OP25 Boatbod Web UI Update

boatbod

Member
Joined
Mar 3, 2007
Messages
3,630
Reaction score
1,025
Location
Talbot Co, MD
Pull request has been merged into "dev" branch and is operational. I've opened a github Issue so we can discuss fixes/tweaks/suggestions.

Note: the new UI will not be merged into master, gr310 or gr38 until it has been given a good workout, so if you want to try it now, you'll need a gnuradio-3.10 environment that can checkout & build the 'dev' branch.
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,630
Reaction score
1,025
Location
Talbot Co, MD
Outerdog's new UI for boatbod op25 has been pushed to the following branches: "gr38", "gr310" and "master".
Note that it is only supported while running multi_rx.py.
If you still run the old rx.py version of the app, the browser page will be redirected to the legacy version of the user interface. I highly encourage you to upgrade!

Here's a screen shot showing a single p25 system with 3 channels being monitored, but no plots turned on.
Screenshot from 2025-04-27 19-20-38.png

The following screen shot is monitoring two separate p25 systems with a total of 3 channels and a couple of plots enabled.
Screenshot from 2025-04-27 19-29-21.png

There's a fair degree of customization possible; e.g. turning on/off the adjacent sites & band plan info, selecting the source for call history, defining custom colors etc.

Awesome effort Trip!
 

Outerdog

T¹ ÆS Ø
Premium Subscriber
Joined
Jul 1, 2016
Messages
688
Reaction score
847
Thanks for assist, @boatbod!

More screenshots:

Logging voice grants from two systems, displaying band plan, channel/receiver info on 3x receivers, presets per defined system (up to 6 per, try more at your own risk).

1745797840962.png

UI Settings & Controls

1745797933489.png

Viewing server-side config:

1745797964776.png

Can save the call history log to csv with the little save icon:

1745798071727.png

Fancy logo!

1745798142618.png

(its a boat)
 

k7dq

Member
Premium Subscriber
Joined
Dec 22, 2016
Messages
32
Reaction score
8
Location
Clinton, Ut
I like this! I did a rebuild on my bookworm OS and this worked. However on my rpi 3 with the bullseye OS, i still get the older web pages. Any suggestions other than upgrading my OS? Thanks
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,630
Reaction score
1,025
Location
Talbot Co, MD
I like this! I did a rebuild on my bookworm OS and this worked. However on my rpi 3 with the bullseye OS, i still get the older web pages. Any suggestions other than upgrading my OS? Thanks
If you are using rx.py you will only ever get the old UI.
If you are using multi_rx.py and still see the old UI, try refreshing the browser cache.
 

ve2vfd

Member
Joined
Nov 10, 2007
Messages
19
Reaction score
4
Location
Montreal, Canada
Wow, amazing work Outerdog and boatbod! I've been running a very old version with rx.py for years (it it ain't broke, don't fix it) to listen in to our P25-II system at work, but this new superb UI convinced my to finally update my version of linux mint and op25 with fresh installs on a new system and move to multi_rx.py.

Huge thanks!

Pat
 

W4KRR

Member
Premium Subscriber
Joined
Apr 1, 2001
Messages
3,616
Reaction score
261
Location
Coconut Creek
Question for Outerdog: How do the presets work? I edited them in the .json file, but clicking on the preset buttons does nothing.
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,630
Reaction score
1,025
Location
Talbot Co, MD
Question for Outerdog: How do the presets work? I edited them in the .json file, but clicking on the preset buttons does nothing.
Here's an example of presets (plus other stuff) that I use on my desktop development system. Once you update the presets (or other settings) you'll need to restart op25 and reload the browser page to trigger the UI to pull the new settings.
Code:
    "trunking": {
        "module": "tk_p25.py",
        "chans": [
            {
                "sysname": "FiRST Talbot",
                "control_channel_list": "773.84375",
                "whitelist": "",
                "tgid_tags_file": "first_talkgroups.tsv",
                "rid_tags_file": "first-rids.tsv",
                "tdma_cc": false,
                "crypt_behavior": 2,
                "band_plan": {
                    "0": { "offset": -45000000, "step":  6250, "frequency": 851006250 },
                    "1": { "offset":  30000000, "step":  6250, "frequency": 762006250 },
                    "2": { "offset": -45000000, "step": 12500, "frequency": 851012500, "tdma": 2 },
                    "3": { "offset":  30000000, "step": 12500, "frequency": 762006250, "tdma": 2 },
                    "4": { "offset": -39000000, "step": 12500, "frequency": 935012500 }
                },
                "presets": [
                    { "id": 1, "tgid": 7616, "label": "7R4 MED1" },
                    { "id": 2, "tgid": 7617, "label": "7R4 MED2" },
                    { "id": 3, "tgid": 11501, "label": "TB FDISP" },
                    { "id": 4, "tgid": 11503, "label": "TB FTAC3" },
                    { "id": 5, "tgid": 12001, "label": "CC FDISP" },
                    { "id": 6, "tgid": 12401, "label": "DC FDISP" }
                ],
                "site_alias": {
                    "3": {
                        "2": { "alias": "Worcester Simulcast" },
                        "3": { "alias": "Wicomico Simulcast" },
                        "4": { "alias": "Smithville ASR" },
                        "5": { "alias": "Dorchester Simulcast" },
                        "6": { "alias": "Talbot Simulcast" },
                        "8": { "alias": "Caroline Simulcast" },
                        "9": { "alias": "Queen Anne Simulcast" },
                        "10": { "alias": "Federalsburg ASR" },
                        "11": { "alias": "Matapeake ASR" },
                        "12": { "alias": "Bozman ASR" },
                        "15": { "alias": "Crisfield ASR" }
                    },
                    "5": {
                        "3": { "alias": "Calvert Simulcast" },
                        "6": { "alias": "St Marys Simulcast" }
                    }
                }
            }
        ]
    }
 

W4KRR

Member
Premium Subscriber
Joined
Apr 1, 2001
Messages
3,616
Reaction score
261
Location
Coconut Creek
I did edit the .json file for the UI presets. The new tags show up on the UI. What I'm saying is how do you use them? Clicking on the UI preset buttons does nothing.
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,630
Reaction score
1,025
Location
Talbot Co, MD
I did edit the .json file for the UI presets. The new tags show up on the UI. What I'm saying is how do you use them? Clicking on the UI preset buttons does nothing.
The buttons are supposed to lock the receiver onto the designated tgid.
 

Outerdog

T¹ ÆS Ø
Premium Subscriber
Joined
Jul 1, 2016
Messages
688
Reaction score
847
The presets send the hold command along with a tgid value back to multi_rx.py for processing, as seen in the javascript below. Since a talkgroup that is not whitelisted cannot be 'held', it also sends a whitelist command just before the hold command.

Honestly, I have noticed that op25/boatbod behaves a little weird with this implantation. It seems to work, but it's flakey. I haven't taken the time to mess with it really. Maybe I'll look at it closer this weekend. @boatbod - any thoughts why this method might be screwy?

There's a little unneeded if/then here, but that isn't the problem at all.

JavaScript:
function f_preset(i) {

    const preset = newPresets.find(p => p.id === i);
    
    if (!preset) {
        console.warn(`No preset found for ID ${i}`);
        return;
    }

    const command = "hold";

    _tgid = preset.tgid;

    if (isNaN(_tgid) || (_tgid < 0) || (_tgid > 65535))
        _tgid = 0;

    if (channel_list.length == 0) {
    
           if (command == "hold")
            send_command("whitelist", _tgid);
    
        send_command(command, _tgid);

        
    } else {
    
        if (command == "hold")
            send_command("whitelist", _tgid, Number(channel_list[channel_index]));

        send_command(command, _tgid, Number(channel_list[channel_index]));
    }
}
 

W4KRR

Member
Premium Subscriber
Joined
Apr 1, 2001
Messages
3,616
Reaction score
261
Location
Coconut Creek
I was able to edit the needed talkgroup ID's and aliases in the .json file, and then correct text will appear on the buttons, but clicking on them doesn't do anything, as far as I can tell. Not a big deal, I can just use the "GO TO" or "HOLD" function.
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,630
Reaction score
1,025
Location
Talbot Co, MD
The presets send the hold command along with a tgid value back to multi_rx.py for processing, as seen in the javascript below. Since a talkgroup that is not whitelisted cannot be 'held', it also sends a whitelist command just before the hold command.

Honestly, I have noticed that op25/boatbod behaves a little weird with this implantation. It seems to work, but it's flakey. I haven't taken the time to mess with it really. Maybe I'll look at it closer this weekend. @boatbod - any thoughts why this method might be screwy?

There's a little unneeded if/then here, but that isn't the problem at all.

JavaScript:
function f_preset(i) {

    const preset = newPresets.find(p => p.id === i);
  
    if (!preset) {
        console.warn(`No preset found for ID ${i}`);
        return;
    }

    const command = "hold";

    _tgid = preset.tgid;

    if (isNaN(_tgid) || (_tgid < 0) || (_tgid > 65535))
        _tgid = 0;

    if (channel_list.length == 0) {
  
           if (command == "hold")
            send_command("whitelist", _tgid);
  
        send_command(command, _tgid);

      
    } else {
  
        if (command == "hold")
            send_command("whitelist", _tgid, Number(channel_list[channel_index]));

        send_command(command, _tgid, Number(channel_list[channel_index]));
    }
}
I was looking at it a bit last night too. For some reason multi_rx is not seeing the requests (either a whitelist or a hold), but I haven't yet tried running the javascript code in a debugger to see what's going on. It does appear to initiate a hold if there is active traffic, but not when inactive.
 

boatbod

Member
Joined
Mar 3, 2007
Messages
3,630
Reaction score
1,025
Location
Talbot Co, MD
I was looking at it a bit last night too. For some reason multi_rx is not seeing the requests (either a whitelist or a hold), but I haven't yet tried running the javascript code in a debugger to see what's going on. It does appear to initiate a hold if there is active traffic, but not when inactive.
It's failing at line 1371 in main.js; preset = newPresets.find() with i=3 is not returning the preset object

ETA: a fix has been pushed to all branches.
Note: Once you activate a preset, use the HOLD button to clear it.
 
Last edited:

W4KRR

Member
Premium Subscriber
Joined
Apr 1, 2001
Messages
3,616
Reaction score
261
Location
Coconut Creek
It's failing at line 1371 in main.js; preset = newPresets.find() with i=3 is not returning the preset object

ETA: a fix has been pushed to all branches.
Note: Once you activate a preset, use the HOLD button to clear it.
What's the command line to update this?
 

KeetsNomad

Newbie
Joined
Jul 8, 2025
Messages
1
Reaction score
0
Is it possible to stream audio over the new web ui without having to have a separate window open for icecast?
 
Top