How do I check that a device is online?

Hello,
To control my outside lights and also monitor my greenhouse and garage temperatures.
I have three ESP32 dev boards which communicate with Node-RED via a Mosquito server running on a Raspberry Pi4B. I have both manual and automated lighting control and I can see the temperatures for the past twenty-four hours on my dashboard. I'm pleased with my progress but I have come up against a problem I can't figure out.
My WiFi is on its range limits and occasionally the one or more of the ESP32 dev boards go off-line. I have programmed a working reconnection for them in their respective C++ code, however I'd like to record the date and time one goes off line, so I can better understand the problem and decide if I need another WiFi range extender.
To check if a controller is online every minute I send each one a message "Offline" on receiving this they reply "Online" using the same topic.
On each controller's status topic I get a pair of messages "Offline" followed rapidly with "Online", provided the device is online. If not I only get the "Offline" message. I use this text on my Dashboard to display their status.
How can I use these messages to trigger writing to a time stamped log file of when an ESP32 device goes off-line or comes on-line?

My approach would be to use the Ping node to check if the device is online / offline and also a Filter to allow messages only when the state has changed - not to flood the log and then write to the log file with the File write node.

Example Flow :

[{"id":"c5a89e79ce9178c0","type":"ping","z":"54efb553244c241f","protocol":"Automatic","mode":"triggered","name":"","host":"","timer":"20","inputs":1,"x":470,"y":580,"wires":[["0333e185f5939315","65298e6fa7db0e87"]]},{"id":"394ab037e5188f3f","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":170,"y":580,"wires":[["bfddde9ced331ae0"]]},{"id":"bfddde9ced331ae0","type":"function","z":"54efb553244c241f","name":"devices","func":"// expected output: 2011-10-05T14:48:00.000Z\nlet now = new Date().toLocaleString();\n\nmsg.payload =\n    [\n        {\n            \"host\": \"192.168.0.66\",\n            \"name\": \"Garden 1\",\n            \"timeout\": 5000,\n            \"datetime\": now\n        },\n        {\n            \"host\": \"192.168.0.7\",\n            \"name\": \"Garden 2\",\n            \"timeout\": 5000,\n            \"datetime\": now\n        },\n        {\n            \"host\": \"192.168.0.17\",\n            \"name\": \"ESP32\",\n            \"timeout\": 5000,\n            \"datetime\": now\n        }\n    ]\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":580,"wires":[["c5a89e79ce9178c0"]]},{"id":"0333e185f5939315","type":"debug","z":"54efb553244c241f","name":"1","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":570,"y":520,"wires":[]},{"id":"b5079b376dea8da4","type":"function","z":"54efb553244c241f","name":"error","func":"// check for failed (false) pings\nif (msg.payload === false) {\n    msg.payload = `${msg.ping.datetime} : Device ${msg.ping.name} Offline`\n}\nelse {\n    msg.payload = `${msg.ping.datetime} : Device ${msg.ping.name} Online`\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":580,"wires":[["205d157d41f0a66c"]]},{"id":"205d157d41f0a66c","type":"file","z":"54efb553244c241f","name":"log","filename":"c:\\users\\user\\desktop\\ping_log.txt","appendNewline":true,"createDir":false,"overwriteFile":"false","encoding":"none","x":1030,"y":580,"wires":[[]]},{"id":"65298e6fa7db0e87","type":"rbe","z":"54efb553244c241f","name":"","func":"rbe","gap":"","start":"","inout":"out","septopics":true,"property":"payload","topi":"topic","x":650,"y":580,"wires":[["67232c5173a81985","b5079b376dea8da4"]]},{"id":"67232c5173a81985","type":"debug","z":"54efb553244c241f","name":"2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":750,"y":520,"wires":[]}]

MQTT has a LWT(last will testament) function. Provides info when MQTT disconnects. Check documentation.

Thank you both for replying,
I'll try both suggestions, just to see if I can get them to work.