Tracking User Activity with Node Red

(Preliminary – needs more testing ) Observations after 3 months in operation: Log file has grown too big to print out. The Pi bogs down. New idea is to process the client logon and logoff before making a log entry. One entry per visit. Shorter log.

As more clubs get remote bases a new demand has surfaced and that is tracking users’ activity. Luckily, tracking is a well matched skill of a recent programming language called Node Red. Node Red needs little actual coding skills, developed by IBM, targeting home automation and Internet of Things devices. Recently hams have adapted Node Red to automate ham radio equipment, especially Flexradio 6XXX series. In the last three years many dashboards have been written to automate radio control for contesters and remote bases, thank to Node Red. An excellent example comes from WO2X.

A local club has offered to it’s members the use of a Flexradio remotely since July, 2022 and and now wants to track it’s activity. Searching the Web for a tracking application has proved fruitless, as has networking with other clubs. The response has always been, “We’re looking for the same thing. If you find one, let us know.” Or, “Why don’t you develop one and give us a copy”.

So, we did. This project was developed with a lot of help from YouTubers like Steven Houser, Kyle Klein, Michael Walker, Dave de Coons, and many others, and the Web in general. Currently the project is deployed at a local club station and is being field tested for improvements or for bugs. Features include the following.

  1. Free open source software that resides on a Raspberry Pi.
  2. Dashboard that is accessible from the Internet to show if someone is connected to a radio in real time, with details.
  3. A log file showing who the users have been, including user details, what time the connections were made and what time they were disconnected.
  4. The log file uses the Comma Separated Values (CSV) format so it can be uploaded to an Excel spreadsheet for detailed analysis.
  5. All features are accessible from the Internet by anyone with the correct privileges.
  6. Simple to use.

Steps to recreate this project for your own club’s use are below:

  1. Install an image of “Raspberry Pi OS (32-bit)” on a Raspberry Pi, Model 4 if available. Use Raspberry Pi Imager. Go through the steps of setting location, time zone, keyboard layout, and do the updates.
  2. Use >sudo raspi-config to enable ssh and vnc.
  3. Install Node Red by following the instructions on this link: https://nodered.org/docs/getting-started/raspberrypi
  4. Using Palette Manager, install the following node: node-red-contrib-flexradio written by Stephen Hauser and explained here: https://nodered.org/docs/getting-started/raspberrypi
  5. Connect the Raspberry Pi to the same router the Flexradio is connected to. Configure port forwarding on the router to direct the following ports to the Pi’s I.P. address: 22, to allow online access to the log file; 1880, which is the Node Red application; and 5700, which is the VNC port.

Here is a copy of the Flow used in this project. Import it to your Node Red. Open an import window and copy and paste everything below. Node Red Version 2.2.2 was used as the development platform. Feel free to modify the flow, of course.

[
{
“id”: “fa203948d0e6d9d0”,
“type”: “tab”,
“label”: “Flow 1”,
“disabled”: false,
“info”: “”,
“env”: []
},
{
“id”: “251fb659293c42f1”,
“type”: “flexradio-discovery”,
“z”: “fa203948d0e6d9d0”,
“name”: “”,
“port”: “4992”,
“x”: 330,
“y”: 240,
“wires”: [
[
“8287e170289d500a”
]
]
},
{
“id”: “3f09eb82379ac711”,
“type”: “ui_text”,
“z”: “fa203948d0e6d9d0”,
“group”: “b09e9ca25cf6b31d”,
“order”: 0,
“width”: 0,
“height”: 0,
“name”: “”,
“label”: “Radio”,
“format”: “{{msg.payload.nickname}}”,
“layout”: “row-spread”,
“className”: “”,
“x”: 910,
“y”: 200,
“wires”: []
},
{
“id”: “db9955fa27cf75d0”,
“type”: “ui_text”,
“z”: “fa203948d0e6d9d0”,
“group”: “b09e9ca25cf6b31d”,
“order”: 1,
“width”: 0,
“height”: 0,
“name”: “”,
“label”: “Status”,
“format”: “{{msg.payload.status}}”,
“layout”: “row-spread”,
“className”: “”,
“x”: 910,
“y”: 260,
“wires”: []
},
{
“id”: “e7be831eddfaae4b”,
“type”: “ui_text”,
“z”: “fa203948d0e6d9d0”,
“group”: “b09e9ca25cf6b31d”,
“order”: 2,
“width”: 0,
“height”: 0,
“name”: “”,
“label”: “Client I.P.”,
“format”: “{{msg.payload.gui_client_ips}}”,
“layout”: “row-spread”,
“className”: “”,
“x”: 900,
“y”: 320,
“wires”: []
},
{
“id”: “fa301f57cad7d937”,
“type”: “ui_text”,
“z”: “fa203948d0e6d9d0”,
“group”: “b09e9ca25cf6b31d”,
“order”: 3,
“width”: 0,
“height”: 0,
“name”: “”,
“label”: “Client Station”,
“format”: “{{msg.payload.gui_client_stations}}”,
“layout”: “row-spread”,
“className”: “”,
“x”: 890,
“y”: 360,
“wires”: []
},
{
“id”: “ed6cd3458551a577”,
“type”: “ui_text”,
“z”: “fa203948d0e6d9d0”,
“group”: “b09e9ca25cf6b31d”,
“order”: 4,
“width”: 0,
“height”: 0,
“name”: “”,
“label”: “Client Host”,
“format”: “{{msg.payload.gui_client_hosts}}”,
“layout”: “row-spread”,
“className”: “”,
“x”: 890,
“y”: 420,
“wires”: []
},
{
“id”: “92f266ba0fe72027”,
“type”: “ui_text”,
“z”: “fa203948d0e6d9d0”,
“group”: “b09e9ca25cf6b31d”,
“order”: 5,
“width”: 0,
“height”: 0,
“name”: “”,
“label”: “Client Program”,
“format”: “{{msg.payload.gui_client_programs}}”,
“layout”: “row-spread”,
“className”: “”,
“x”: 880,
“y”: 460,
“wires”: []
},
{
“id”: “e16b56205f6185a9”,
“type”: “ui_text”,
“z”: “fa203948d0e6d9d0”,
“group”: “b09e9ca25cf6b31d”,
“order”: 6,
“width”: 0,
“height”: 0,
“name”: “”,
“label”: “Client Handles”,
“format”: “{{msg.payload.gui_client_handles}}”,
“layout”: “row-spread”,
“className”: “”,
“x”: 880,
“y”: 500,
“wires”: []
},
{
“id”: “8287e170289d500a”,
“type”: “trigger”,
“z”: “fa203948d0e6d9d0”,
“name”: “”,
“op1”: “”,
“op2”: “”,
“op1type”: “pay”,
“op2type”: “pay”,
“duration”: “10”,
“extend”: false,
“overrideDelay”: false,
“units”: “s”,
“reset”: “”,
“bytopic”: “all”,
“topic”: “topic”,
“outputs”: 1,
“x”: 330,
“y”: 340,
“wires”: [
[
“59718a62747b10aa”
]
]
},
{
“id”: “59718a62747b10aa”,
“type”: “rbe”,
“z”: “fa203948d0e6d9d0”,
“name”: “Filter: block all but changes”,
“func”: “rbe”,
“gap”: “”,
“start”: “”,
“inout”: “out”,
“septopics”: false,
“property”: “payload”,
“topi”: “topic”,
“x”: 400,
“y”: 420,
“wires”: [
[
“a2d9d4f4aa370116”,
“5ef3f2abc0776143”,
“d6d6658a8cc20e0f”,
“3f09eb82379ac711”,
“db9955fa27cf75d0”,
“e7be831eddfaae4b”,
“fa301f57cad7d937”,
“ed6cd3458551a577”,
“92f266ba0fe72027”,
“e16b56205f6185a9”,
“dca3db48af21a307”
]
]
},
{
“id”: “1d2574fc485d623f”,
“type”: “change”,
“z”: “fa203948d0e6d9d0”,
“name”: “Stations”,
“rules”: [
{
“t”: “set”,
“p”: “payload”,
“pt”: “msg”,
“to”: “payload.gui_client_stations”,
“tot”: “msg”
}
],
“action”: “”,
“property”: “”,
“from”: “”,
“to”: “”,
“reg”: false,
“x”: 720,
“y”: 580,
“wires”: [
[
“9c48e2830ef9d446”
]
]
},
{
“id”: “76a6532bc40dc4a6”,
“type”: “file”,
“z”: “fa203948d0e6d9d0”,
“name”: “”,
“filename”: “/var/www/html/test.log”,
“appendNewline”: true,
“createDir”: false,
“overwriteFile”: “false”,
“encoding”: “none”,
“x”: 700,
“y”: 1020,
“wires”: [
[]
]
},
{
“id”: “6b1041bab320ca67”,
“type”: “moment”,
“z”: “fa203948d0e6d9d0”,
“name”: “”,
“topic”: “”,
“input”: “”,
“inputType”: “msg”,
“inTz”: “America/Denver”,
“adjAmount”: 0,
“adjType”: “days”,
“adjDir”: “add”,
“format”: “”,
“locale”: “en-US”,
“output”: “”,
“outputType”: “msg”,
“outTz”: “America/Denver”,
“x”: 180,
“y”: 700,
“wires”: [
[
“bf431a5acd90b832”
]
]
},
{
“id”: “bdb049085cc97475”,
“type”: “change”,
“z”: “fa203948d0e6d9d0”,
“name”: “Timestamp”,
“rules”: [
{
“t”: “set”,
“p”: “payload”,
“pt”: “msg”,
“to”: “”,
“tot”: “date”
}
],
“action”: “”,
“property”: “”,
“from”: “”,
“to”: “”,
“reg”: false,
“x”: 170,
“y”: 640,
“wires”: [
[
“6b1041bab320ca67”
]
]
},
{
“id”: “a2d9d4f4aa370116”,
“type”: “delay”,
“z”: “fa203948d0e6d9d0”,
“name”: “”,
“pauseType”: “delay”,
“timeout”: “50”,
“timeoutUnits”: “milliseconds”,
“rate”: “1”,
“nbRateUnits”: “1”,
“rateUnits”: “second”,
“randomFirst”: “1”,
“randomLast”: “5”,
“randomUnits”: “seconds”,
“drop”: false,
“allowrate”: false,
“outputs”: 1,
“x”: 530,
“y”: 660,
“wires”: [
[
“1d2574fc485d623f”,
“8cd903664f096da0”,
“cfab0638431b3f19”,
“8cabe28af2d37e8c”,
“b6eccdc3bda00895”
]
]
},
{
“id”: “8cd903664f096da0”,
“type”: “change”,
“z”: “fa203948d0e6d9d0”,
“name”: “Client I.P.”,
“rules”: [
{
“t”: “set”,
“p”: “payload”,
“pt”: “msg”,
“to”: “payload.gui_client_ips”,
“tot”: “msg”
}
],
“action”: “”,
“property”: “”,
“from”: “”,
“to”: “”,
“reg”: false,
“x”: 720,
“y”: 620,
“wires”: [
[
“f46629eecd4972e9”
]
]
},
{
“id”: “cfab0638431b3f19”,
“type”: “change”,
“z”: “fa203948d0e6d9d0”,
“name”: “Program”,
“rules”: [
{
“t”: “set”,
“p”: “payload”,
“pt”: “msg”,
“to”: “payload.gui_client_programs”,
“tot”: “msg”
}
],
“action”: “”,
“property”: “”,
“from”: “”,
“to”: “”,
“reg”: false,
“x”: 720,
“y”: 700,
“wires”: [
[
“3b931ee1682dd15f”
]
]
},
{
“id”: “8cabe28af2d37e8c”,
“type”: “change”,
“z”: “fa203948d0e6d9d0”,
“name”: “Handles”,
“rules”: [
{
“t”: “set”,
“p”: “payload”,
“pt”: “msg”,
“to”: “payload.gui_client_handles”,
“tot”: “msg”
}
],
“action”: “”,
“property”: “”,
“from”: “”,
“to”: “”,
“reg”: false,
“x”: 720,
“y”: 740,
“wires”: [
[
“0f4f8fc63bf77a90”
]
]
},
{
“id”: “0f4f8fc63bf77a90”,
“type”: “rbe”,
“z”: “fa203948d0e6d9d0”,
“name”: “Filter: nulls”,
“func”: “rbe”,
“gap”: “”,
“start”: “”,
“inout”: “out”,
“septopics”: false,
“property”: “payload”,
“topi”: “topic”,
“x”: 1170,
“y”: 720,
“wires”: [
[
“dbfa56fdd624c7e4”
]
]
},
{
“id”: “d6d6658a8cc20e0f”,
“type”: “function”,
“z”: “fa203948d0e6d9d0”,
“name”: “New line”,
“func”: “msg.payload = msg.payload + \”\n\”;\nreturn msg;”,
“outputs”: 1,
“noerr”: 0,
“initialize”: “”,
“finalize”: “”,
“libs”: [],
“x”: 420,
“y”: 700,
“wires”: [
[
“dbfa56fdd624c7e4”
]
]
},
{
“id”: “5ef3f2abc0776143”,
“type”: “delay”,
“z”: “fa203948d0e6d9d0”,
“name”: “”,
“pauseType”: “delay”,
“timeout”: “25”,
“timeoutUnits”: “milliseconds”,
“rate”: “1”,
“nbRateUnits”: “1”,
“rateUnits”: “second”,
“randomFirst”: “1”,
“randomLast”: “5”,
“randomUnits”: “seconds”,
“drop”: false,
“allowrate”: false,
“outputs”: 1,
“x”: 190,
“y”: 580,
“wires”: [
[
“bdb049085cc97475”
]
]
},
{
“id”: “b6eccdc3bda00895”,
“type”: “change”,
“z”: “fa203948d0e6d9d0”,
“name”: “Host”,
“rules”: [
{
“t”: “set”,
“p”: “payload”,
“pt”: “msg”,
“to”: “payload.gui_client_hosts”,
“tot”: “msg”
}
],
“action”: “”,
“property”: “”,
“from”: “”,
“to”: “”,
“reg”: false,
“x”: 710,
“y”: 660,
“wires”: [
[
“accffad613c92103”
]
]
},
{
“id”: “f46629eecd4972e9”,
“type”: “function”,
“z”: “fa203948d0e6d9d0”,
“name”: “Append comma”,
“func”: “msg.payload = msg.payload + \”,\”;\nreturn msg;”,
“outputs”: 1,
“noerr”: 0,
“initialize”: “”,
“finalize”: “”,
“libs”: [],
“x”: 880,
“y”: 620,
“wires”: [
[
“0f4f8fc63bf77a90”
]
]
},
{
“id”: “accffad613c92103”,
“type”: “function”,
“z”: “fa203948d0e6d9d0”,
“name”: “Append comma”,
“func”: “msg.payload = msg.payload + \”,\”;\nreturn msg;”,
“outputs”: 1,
“noerr”: 0,
“initialize”: “”,
“finalize”: “”,
“libs”: [],
“x”: 880,
“y”: 660,
“wires”: [
[
“0f4f8fc63bf77a90”
]
]
},
{
“id”: “3b931ee1682dd15f”,
“type”: “function”,
“z”: “fa203948d0e6d9d0”,
“name”: “Append comma”,
“func”: “msg.payload = msg.payload + \”,\”;\nreturn msg;”,
“outputs”: 1,
“noerr”: 0,
“initialize”: “”,
“finalize”: “”,
“libs”: [],
“x”: 880,
“y”: 700,
“wires”: [
[
“0f4f8fc63bf77a90”
]
]
},
{
“id”: “dbfa56fdd624c7e4”,
“type”: “csv”,
“z”: “fa203948d0e6d9d0”,
“name”: “”,
“sep”: “,”,
“hdrin”: “”,
“hdrout”: “none”,
“multi”: “one”,
“ret”: “\n”,
“temp”: “”,
“skip”: “0”,
“strings”: true,
“include_empty_strings”: “”,
“include_null_values”: “”,
“x”: 690,
“y”: 960,
“wires”: [
[
“76a6532bc40dc4a6”
]
]
},
{
“id”: “9c48e2830ef9d446”,
“type”: “function”,
“z”: “fa203948d0e6d9d0”,
“name”: “Append comma”,
“func”: “msg.payload = msg.payload + \”,\”;\nreturn msg;”,
“outputs”: 1,
“noerr”: 0,
“initialize”: “”,
“finalize”: “”,
“libs”: [],
“x”: 880,
“y”: 580,
“wires”: [
[
“0f4f8fc63bf77a90”
]
]
},
{
“id”: “bf431a5acd90b832”,
“type”: “function”,
“z”: “fa203948d0e6d9d0”,
“name”: “Append comma”,
“func”: “msg.payload = msg.payload + \”,\”;\nreturn msg;”,
“outputs”: 1,
“noerr”: 0,
“initialize”: “”,
“finalize”: “”,
“libs”: [],
“x”: 440,
“y”: 820,
“wires”: [
[
“dbfa56fdd624c7e4”
]
]
},
{
“id”: “dca3db48af21a307”,
“type”: “debug”,
“z”: “fa203948d0e6d9d0”,
“name”: “”,
“active”: true,
“tosidebar”: true,
“console”: false,
“tostatus”: false,
“complete”: “false”,
“statusVal”: “”,
“statusType”: “auto”,
“x”: 1070,
“y”: 400,
“wires”: []
},
{
“id”: “b09e9ca25cf6b31d”,
“type”: “ui_group”,
“name”: “Discovery”,
“tab”: “0613cce6f287631c”,
“order”: 1,
“disp”: true,
“width”: “6”,
“collapse”: false,
“className”: “”
},
{
“id”: “0613cce6f287631c”,
“type”: “ui_tab”,
“name”: “FlexRadio Dashboard”,
“icon”: “dashboard”,
“disabled”: false,
“hidden”: false
}
]

MTU Workarounds

The maximum transmission unit (MTU) is the largest size frame or packet — in bytes or octets (eight-bit bytes) — that can be transmitted across a data link. It is most used in reference to packet size on an Ethernet network using the Internet Protocol (IP). A deprecated term is “window size”. Default is 1500 which is too big for the remote station network. Symptoms are the radio shows up in the Smartlink window but a connection attempt times out.

At least two workarounds are possible which will have no effect on any other applications or users on the router. Which one you use is up to you. Either one works equally well. The first workaround is to change the settings in the main router for the home. Find the settings for MTU in the network configuration and change the MTU to 1438.

The second workaround uses the command line in the pc to do network shell routines. This routine can change the MTU on the PC. Open cmd with administrator permissions (run as administrator by right-clicking on cmd and clicking on “run as administrator”).

Enter these commands:

>netsh

>interface

>ipv4

>show int

Look for the line that shows the connection to the Internet and write down it’s name. An example is “Ethernet”. If you’re using wifi, it might say “Wi-Fi”. Observe the value in the MTU column. Is it 1500?

Enter the following command:

>set subinterface “Ethernet” mtu=1438 store=persistent

where “Ethernet” is the name obtained in one of the steps above.

An “ok” will be returned if these steps worked. To test, enter the following command:

>show int

The results returned will show the current MTU which should now be 1438.

Note that the magic number may be lower or higher than 1438. Experiment if 1438 doesn’t work.

To return to normal, close the cmd window.

Backdoor Access Project

Abstract: It has always been a goal to have “backdoor” remote access for troubleshooting. There are times when the primary Internet connection is down and normal access is not possible. It is those times when backdoor remote access saves the day. It could prevent a site visit, a trip to the site. These are the specific essential building blocks:

AT&T Mobile Hotspot

Raspberry Pi running ZeroTier, ipforward and iptables

Same subnet but separate ranges of i.p. addresses

Let’s get started: First, an explanatory overview. The hotspot provides Internet access over a different path by using the cellular data network. This specific hotspot costs $35 a month for unlimited data. T-Mobile’s $50 service would probably also work. Up and down bandwidth is 30 Mbps, even in the rural location. Luckily there is an AT&T cell tower not too far from the remote site. Not so lucky is the fact that the hotspot provides only a private i.p. address and not a public address so it cannot be reached from the outside world. Called “carrier grade NAT” or CGNAT, it is a heavy duty impenetrable firewall. Not to fear, however.

A great solution to the CGNAT problem is a product call ZeroTier which becomes the second detail of this project. ZeroTier is an application that runs on a computer behind a firewall and reaches out over the Internet to a software defined LAN. A software defined LAN is similar to the user side of a home router. Instead of the hardware connections like a home router uses, a software defined LAN does it all with algorithms and the Internet. Other computers running the same application and same credentials can reach the same software defined LAN and communicate as if they were all in the same office. For backdoor access one instance of the application is running on a computer at the remote site (a Raspberry Pi) and another instance is running on a computer (Windows 11 pc ) at the home location. Competing products exist and might also work, like Tailsscale, reverse TCP tunnelling, SoftEther, WireGuard and possibly others that do NAT traversal. ZeroTier has been the most comfortable and successful of the ones tried at this remote station.

How To Use

Any device anywhere worldwide on the same ZeroTier network can reach the LAN at the remote site. As this is written the network id ends in ee4. To reach the i3 NUC: Power is on the ‘Station’ circuit on the 4005i using port 82. The NUC i.p. on the LAN is 192.168.1.100. It can be reached using Remote Desktop Protocol. The Pi is at 192.168.1.204 and it can be reached with Putty. The KMTronic is at 192.168.1.204 and it can be reached with a browser. If the main LAN is down the only device that can be reached is the Pi. Other well known ports:

Pi .201

86 .205

88 .206

82 .207

83 .208

90 .209

89 .210

84 .211

85 .212

How To Set Up

Click on the Home Main link to visit ZeroTier.

Home Main

Follow the instructions on the ZeroTier web page to make an account and to create a network. Their free plan has all the features needed.

This brings us to the third detail, the Raspberry Pi computer.

A Raspberry Pi is fully capable of running the ZeroTier application and then some.

Shown above is a Raspberry Pi model 3 which is the model being used in this project. Follow the instructions on the ZeroTier web page to join the network created above. With a hotspot and a Pi running ZeroTier the hardware and some of the software to get into the site is complete but no connection has been made to the main LAN yet.

Each detail has involved challenges but probably the biggest challenge of all has been how to connect to and how to communicate with the existing LAN at the remote site. At this point there are two LAN’s, one providing a data link between the hotspot and the Pi and the other LAN providing communication for all the existing equipment. Connecting any two LAN’s requires a router, but not just any router. An ordinary home router will not do. Turns out the solution is simple and elegant thanks to the Linux operating system running on the Raspberry Pi. It can run a few built-in processes and perform the necessary router functions. A nice writeup of how to configure this routing function is published by the ZeroTier developers: “Route between ZeroTier and Physical Networks

https://zerotier.atlassian.net/wiki/spaces/SD/pages/224395274/Route+between+ZeroTier+and+Physical+Networks

One of the essential processes is iptables:

sudo iptables -t nat -A POSTROUTING -o $PHY_IFACE -j MASQUERADE
sudo iptables -A FORWARD -i $PHY_IFACE -o $ZT_IFACE -m state –state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i $ZT_IFACE -o $PHY_IFACE -j ACCEPT

Another essential process is ipforwarding:

sudo sysctl -w net.ipv4.ip_forward=1

Edit /etc/sysctl.conf to uncomment net.ipv4.ip_forward. This enables forwarding at boot.

Next, take steps to avoid two devices having the same addresses on the combined LAN: On the hotspot, set the dhcp i.p. address range to the highest 50 addresses in the subnet, and make the subnet identical to the main LAN subnet. Turnoff DHCP on the hotspot. On the main LAN, set the router dhcp range to exclude the top 50 addresses and leave DHCP on.

A few items remain to polish the backdoor project. The whole idea is to be able to access the remote network at all times. There is no way to know what the source of the failure might be. It could be power down inside the remote station. In that case the backdoor needs to have it’s own power. For that reason, the hotspot and Pi have their own battery and solar panel separate from the rest. Considering the main LAN goes through a big ethernet switch and that switch could be down, the hotspot and Pi have their own switch. That small switch is also powered by the separate battery. Rebooting devices remotely is invaluable. Some devices, like computers, can be rebooted with software commands or they might need a hardware reset. Other devices, like BMS’s and EMC’s require a hardware reset. Relays wired to provide the hardware reset, controlled over the Internet through the backdoor can save a trip to the site. At this site relays are wired to short out the BMS’s (which is how they are reset if they have tripped). Another bank of relays is installed to reset the EMC’s if they lock up ( like they have been prone to do ). Almost all equipment has a method of being rebooted or reset remotely.

A successful backdoor access project provides a lot of comfort knowing the every day remote operation has tools for a better chance of recovery when something goes wrong.

Thoughts for future improvements – One improvement could be to move all the non-radio equipment to the secondary Internet connection, leaving the entire bandwidth of the main connection to the radio. That would be easy because the hardware connections are already in place. It would just be a matter of changing the i.p. settings on each piece of equipment to static with the gateway address of the secondary connection. A second idea is to combine the two Internet connections into what is called “dual-WAN” service. A product exists to do this easily (according to the sales literature). It is called Speedify and is worth checking out someday.

One additional thought. Use bridging instead of routing to see if bridging would pass the broadcast packets. What this means is the packets that advertise a service are being blocked (by the hotspot??) when using routing. It is possible bridging would fix this. The hotspot would not see the packet headers and thus not know any particular packet was a broadcast packet.

One more additional thought. Use iptables “mangle” to create a mangle table which will be a MSS filter. Set the filter size to, in turn, create an MTU size that will pass through the PPPoE Internet connection at the radio end.

Here is an example of a line of code to create the mangle table:

iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1452

Credit for this example goes to serverfault.com

https://serverfault.com/questions/467756/what-is-the-mangle-table-in-iptables