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
}
]

Overview

Featured

Welcome to the W0QL remote station journal. The station was born in 2016 and is located on the plains east of Denver. It’s controlled over the Internet and powered exclusively by a solar system and lithium batteries.

The Flexradio is the heart of the whole station.

Now let’s get going, with the most recent post beginning below.

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.