Looks good. Cool use for Node-RED by the way. 
First question. I get that you probably want to write to a SQL table as a log. However, I'm guessing that you don't have so many rides that you can't keep the current data in memory? If that is the case, I would absolutely maintain the current live data in a global context variable.
Sure, write the copy to the DB but use the live data for the dashboard.
Personally, I would also simplify your data because a lot of what you have in the data table should actually be done by the front-end, all of the highlighting for example. Simpler is better. Trust the process - what I mean is that we will make the highlighting follow the data. So data something like:
[
{
"Ride": "1",
"Mode": "OFF",
"Status": "PLC",
"RTC": "10/15/2025 15:13"
},
{
"Ride": "2",
"Mode": "OFF",
"Status": "Cycles this Year: 26595 (Today: 0) / PLC",
"RTC": "10/15/2025 15:13"
},
{
"Ride": "3",
"Mode": "OFFLINE",
"Status": ""
},
{
"Ride": "4",
"Mode": "OFFLINE",
"Status": ""
},
{
"Ride": "4",
"Mode": "OFFLINE",
"Status": "Cycles this Year: 16895 (Today: 264) (Train 1: 5686, Train 2: 8650, Train 3: 0) / PLC",
"RTC": "8/17/2025 23:23"
},
{
"Ride": "5",
"Mode": "OFFLINE",
"Status": ""
},
{
"Ride": "6",
"Mode": "OFF",
"Status": "Cycles this Year: 17445 / PLC RTC: 10/15/2025 15:00"
},
{
"Ride": "7",
"Mode": "OFFLINE",
"Status": "Cycles this Year: 53717 (SECTION 1: 14837, SECTION 2: 14968, SECTION 3: 14337, SECTION 4: 0, SECTION 5: 4610, SECTION 6: 4965)"
},
{
"Ride": "8",
"Mode": "OFF",
"Status": "Cycles this Year: 28269 (Today: 15) (Train 1: 14158, Train 2: 14111) / PLC RTC: 10/15/2023 15:09"
},
{
"Ride": "9",
"Mode": "OFF",
"Status": "Cycles this Year: 50543 (Cart 1: 0, Cart 2: 12858, Cart 3: 12870, Cart 4: 12866, Cart 5: 11949) / PLC RTC: 10/15/2025 15:01"
},
{
"Ride": "10",
"Mode": "",
"Status": " Alarm 0420 RV04 Watchdog Failure (High), Alarm 0520 RV05 Watchdog Failure (High), Alarm 0720 RV07 Watchdog Failure (High), Alarm 0001 ESTOP Went Active Alarm (High), Alarm 0013 OCC-100 Panel Enable Off (High), Alarm 0220 RV02 Watchdog Failure (High), Alarm 0320 RV03 Watchdog Failure (High)"
},
{
"Ride": "11",
"Mode": "OFF",
"Status": "Cycles this Year: 17323 / PLC RTC: 10/15/2025 15:08"
},
{
"Ride": "12",
"Mode": "OFFLINE",
"Status": ""
},
{
"Ride": "13",
"Mode": "OFF",
"Status": "035.09 ESTOP! Block B Slowdown Friction Brake 2 Press. Trans. detected pressure too low when brake off (engage). {I_BKB_FBR_02_PT}, 012.28 RideS! Block S Station Train Detect Sensor 7 Prox Switch (Exit) not flagged when expected. {BKS_TDT_7_PX_NC}, 014.06 RideS! Block B Slowdown Train Detect Sensor 8 Prox Switch (Exit) not flagged when expected. {BKB_TDT_8_PX_NC}, 014.26 RideS! Block S Station Train Detect Sensor 6 Prox Switch (Fwd Stop) not flagged when expected. {BKS_TDT_6_PX_NC}, 035.10 ESTOP! Block B Slowdown Friction Brake 3 Press. Trans. detected pressure too low when brake off (engage). {I_BKB_FBR_03_PT}, 004.03 ESTOP! Main Oper Cons (MOC) System Enable is off. {MOC1_SYS_SW}, 012.06 RideS! Block B Slowdown Train Detect Sensor 7 Prox Switch (Exit) not flagged when expected. {BKB_TDT_7_PX_NC}, 014.28 RideS! Block S Station Train Detect Sensor 8 Prox Switch (Exit) not flagged when expected. {BKS_TDT_8_PX_NC}, 020.30 ESTOP! Tow-Cart Retract Clutch Left Close/Op..."
},
...
]
Note that I've shortened the data as well as removed any formatting. The ride data could also be numeric rather than a string which would probably be more useful. I assume that you have a lookup table that converts the numbers into names?
Also note that I've split out the rtc
to its own field - not sure whether you can do that but it is always easier to start with structured data, that gives you far more flexibility with the display. You might also consider making the rtc
data yyyy-mm-dd hh:mm
which is more easily sorted (and is actually more easily read by humans).
How many entries are we talking about? Is it just the 24? Because if so, this will be super easy. If it were >1000 or so, we'd probably have to do things differently.
One of the nice things about Node-RED is how easy it is to create a new, parallel flow. That means that you should be able to create and maintain the new global without having any impact on your existing flows and dashboard.
One final thing about the data, I note that you aren't really differentiating in the data between a machine that is simply off and one that is off because of an issue. It would actually be better to have additional modes. Maybe OFF-ERROR
?
Anyway, this is the first stage - getting the most flexible and usable data. When we have that, it will be trivial to use a uibuilder node and a uib-element
node configured to output a table from your global context variable. On each data update, you will need to (a) update the variable, (b) pass that updated variable to the uib-element
node who's output is passed to the uibuilder node which updates the browser. We will worry about restarts and other finessing later on.
<existing flow that updates your SQL> -> ...
+->New node to update the new global
+->uib-element node (set to output a table)
+->uibuilder node
Hope that makes sense?
Late here, will catch up with you tomorrow.