Good network ping flow - but how to change payload dynamically with msg.topic?

I have the following network ping flow set up that works well:

[{"id":"e8c17b5587f8c344","type":"ping","z":"eb3cbe54.bd558","protocol":"Automatic","mode":"triggered","name":"Ping","host":"","timer":"5","inputs":1,"x":250,"y":840,"wires":[["20ef40f2d7f77dd9","f00eb1c8865e8424"]]},{"id":"20ef40f2d7f77dd9","type":"switch","z":"eb3cbe54.bd558","name":"Pass Ping?","property":"payload","propertyType":"msg","rules":[{"t":"istype","v":"number","vt":"number"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":410,"y":840,"wires":[["6ac1ce40344acbb8"],["8704e1e24b44c5e8","99fb19c3d4ee24ca"]]},{"id":"bc89895a3aee3de4","type":"time-inject","z":"eb3cbe54.bd558","name":"Google","nameInt":"\"www.google.com\"","positionConfig":"580132a8.865a5c","props":[{"p":"","pt":"msgPayload","v":"www.google.com","vt":"str","o":"","oT":"none","oM":"60000","f":0,"fS":0,"fT":"UNIX timestamp (ms)","fI":"0","next":true,"days":"","months":"","onlyOddDays":false,"onlyEvenDays":false},{"p":"target","pt":"msg","v":"www.google.com","vt":"str","o":"","oT":"none","oM":"60000","f":0,"fS":0,"fT":"UNIX timestamp (ms)","fI":"0","next":false,"days":"","months":"","onlyOddDays":false,"onlyEvenDays":false}],"injectTypeSelect":"none","intervalCount":1,"intervalCountType":"num","intervalCountMultiplier":60000,"time":"","timeType":"entered","offset":0,"offsetType":"none","offsetMultiplier":60000,"timeEnd":"","timeEndType":"entered","timeEndOffset":0,"timeEndOffsetType":"none","timeEndOffsetMultiplier":60000,"timeDays":"*","timeOnlyOddDays":false,"timeOnlyEvenDays":false,"timeMonths":"*","timedatestart":"","timedateend":"","property":"","propertyType":"none","propertyCompare":"true","propertyThreshold":"","propertyThresholdType":"num","timeAlt":"","timeAltType":"entered","timeAltDays":"*","timeAltOnlyOddDays":false,"timeAltOnlyEvenDays":false,"timeAltMonths":"*","timeAltOffset":0,"timeAltOffsetType":"none","timeAltOffsetMultiplier":60000,"once":false,"onceDelay":0.1,"recalcTime":2,"x":90,"y":840,"wires":[["e8c17b5587f8c344"]]},{"id":"8704e1e24b44c5e8","type":"trigger","z":"eb3cbe54.bd558","name":"Wait 2 minutes","op1":"","op2":"0","op1type":"nul","op2type":"str","duration":"2","extend":false,"overrideDelay":false,"units":"min","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":840,"y":840,"wires":[["ae17c6d2dc52b5b4","81431809fee394f3"]]},{"id":"6ac1ce40344acbb8","type":"change","z":"eb3cbe54.bd558","name":"Reset Trigger","rules":[{"t":"set","p":"reset","pt":"msg","to":"true","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":620,"y":820,"wires":[["8704e1e24b44c5e8"]]},{"id":"6cde3bf3fd57f2eb","type":"time-inject","z":"eb3cbe54.bd558","name":"Bad Google","nameInt":"\"10.0.0.200\"","positionConfig":"580132a8.865a5c","props":[{"p":"","pt":"msgPayload","v":"10.0.0.200","vt":"str","o":"","oT":"none","oM":"60000","f":0,"fS":0,"fT":"UNIX timestamp (ms)","fI":"0","next":true,"days":"","months":"","onlyOddDays":false,"onlyEvenDays":false},{"p":"target","pt":"msg","v":"www.google.com","vt":"str","o":"","oT":"none","oM":"60000","f":0,"fS":0,"fT":"UNIX timestamp (ms)","fI":"0","next":false,"days":"","months":"","onlyOddDays":false,"onlyEvenDays":false}],"injectTypeSelect":"none","intervalCount":1,"intervalCountType":"num","intervalCountMultiplier":60000,"time":"","timeType":"entered","offset":0,"offsetType":"none","offsetMultiplier":60000,"timeEnd":"","timeEndType":"entered","timeEndOffset":0,"timeEndOffsetType":"none","timeEndOffsetMultiplier":60000,"timeDays":"*","timeOnlyOddDays":false,"timeOnlyEvenDays":false,"timeMonths":"*","timedatestart":"","timedateend":"","property":"","propertyType":"none","propertyCompare":"true","propertyThreshold":"","propertyThresholdType":"num","timeAlt":"","timeAltType":"entered","timeAltDays":"*","timeAltOnlyOddDays":false,"timeAltOnlyEvenDays":false,"timeAltMonths":"*","timeAltOffset":0,"timeAltOffsetType":"none","timeAltOffsetMultiplier":60000,"once":false,"onceDelay":0.1,"recalcTime":2,"x":110,"y":880,"wires":[["e8c17b5587f8c344"]]},{"id":"ae17c6d2dc52b5b4","type":"template","z":"eb3cbe54.bd558","name":"Set Message","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"Pings to {{{topic}}} have failed.","output":"str","x":1050,"y":840,"wires":[["6791d007d6b12a33"]]},{"id":"6791d007d6b12a33","type":"api-call-service","z":"eb3cbe54.bd558","name":"Notify iPhone","server":"296c0678.b5f9ca","version":5,"debugenabled":false,"domain":"notify","service":"mobile_app_iphone","areaId":[],"deviceId":[],"entityId":[],"data":"{\t   \"title\": \"Network Problem\",\t   \"message\": \"{{{payload}}}\"\t}","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1230,"y":840,"wires":[[]]},{"id":"580132a8.865a5c","type":"position-config","name":"Home","isValide":"true","longitude":"0","latitude":"0","angleType":"deg","timeZoneOffset":99,"timeZoneDST":0,"stateTimeFormat":"3","stateDateFormat":"12"},{"id":"296c0678.b5f9ca","type":"server","name":"Home Assistant","version":4,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m"}]

I’m currently testing it with IP addresses (targets) set in the inject nodes. “Google” pings Google, and “Bad Google” pings an IP address that doesn’t exist in my network, so it fails every time. If the first ping fails, I wait for a second failed ping before passing along a notification. If the first ping fails and it’s followed by a successful ping, the trigger node is reset and no notification is sent.

Ultimately, one of my goals is to automatically reboot individual hardware (modem, router, access points) with plug-in modules based on the ping results. I’m pretty sure I can do that with a switch node.

However… for the purposes of notification, I’m wondering how I can dynamically interpret different IP addresses for correct wording in my notifications. I’ve proven that msg.topic containing the target IP makes it all the way through to the notification, and I’ve included the IP in the notification. However, instead of, “Pings to 192.168.1.40 have failed,” I would like the notification to say, “Pings to the router have failed.” I’m not sure how to set unique messages based on different msg.topics. Any help would be great.

EDIT: I believe I can use a switch node with n outputs, and then send each output through a change node… but there has to be a cleaner way of doing it.

I have this flow running.
It starts and ping one host at a time until the list is done and then it starts over.
Host is set dynamically and the sensor creation in HA is done dynamically too, so extra hosts can just be added to the list node.

[{"id":"483ec824ea1b04f5","type":"ping","z":"be03f9025a1f137a","protocol":"IPv4","mode":"triggered","name":"ping","host":"","timer":"20","inputs":1,"x":385,"y":1185,"wires":[["7ed1448475afb9f0"]]},{"id":"f8ae3eaa37ec0085","type":"function","z":"be03f9025a1f137a","name":"init payload","func":"msg.payload = [\n    {\n        \"host\":msg.ping_hosts[flow.get('host_count')].host,\n        \"name\":msg.ping_hosts[flow.get('host_count')].name,\n        \"timeout\":1000\n    }\n]\ndelete msg.ping_hosts\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":235,"y":1185,"wires":[["483ec824ea1b04f5"]]},{"id":"a6931ffd61c70578","type":"ha-api","z":"be03f9025a1f137a","name":"sensor","server":"541ade28.b4a62","version":1,"debugenabled":false,"protocol":"http","method":"post","path":"/api/states/{{entity_id}}","data":"","dataType":"json","responseType":"json","outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"results"}],"x":730,"y":1320,"wires":[["3f532e48695fa37b"]]},{"id":"7ed1448475afb9f0","type":"function","z":"be03f9025a1f137a","name":"rearrange payload","func":"ping = msg.payload\nmsg.payload = [\n    {\n        \"host\":msg.ping.host,\n        \"name\":msg.ping.name,\n        \"timeout\":msg.ping.timeout,\n        \"ping1\":ping\n    }\n]\ndelete msg.ping\ndelete msg.topic\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":1185,"wires":[["c2e35ae3d26c33a6"]]},{"id":"c2e35ae3d26c33a6","type":"ping","z":"be03f9025a1f137a","protocol":"IPv4","mode":"triggered","name":"ping","host":"","timer":"20","inputs":1,"x":385,"y":1230,"wires":[["89915cde6f7d909c"]]},{"id":"89915cde6f7d909c","type":"function","z":"be03f9025a1f137a","name":"rearrange payload","func":"ping = msg.payload\nmsg.payload = [\n    {\n        \"host\":msg.ping.host,\n        \"name\":msg.ping.name,\n        \"timeout\":msg.ping.timeout,\n        \"ping1\":msg.ping.ping1,\n        \"ping2\":ping\n    }\n]\ndelete msg.ping\ndelete msg.topic\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":1230,"wires":[["dc24823239775591"]]},{"id":"7fa87ef4304e6395","type":"function","z":"be03f9025a1f137a","name":"rearrange payload","func":"ping = msg.payload\nmsg.payload = [\n    {\n        \"host\":msg.ping.host,\n        \"name\":msg.ping.name,\n        \"timeout\":msg.ping.timeout,\n        \"ping1\":msg.ping.ping1,\n        \"ping2\":msg.ping.ping2,\n        \"ping3\":ping\n    }\n]\ndelete msg.ping\ndelete msg.topic\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":1275,"wires":[["294c147daaf6df02"]]},{"id":"dc24823239775591","type":"ping","z":"be03f9025a1f137a","protocol":"IPv4","mode":"triggered","name":"ping","host":"","timer":"20","inputs":1,"x":385,"y":1275,"wires":[["7fa87ef4304e6395"]]},{"id":"bc5f05722a270186","type":"function","z":"be03f9025a1f137a","name":"make final payload","func":"ping = msg.payload\nmsg.entity_id = `sensor.ping_${msg.ping.name.toLowerCase().replace(/ /g, '_' )}`;\npacketloss=0;\naverage = 0;\nif (msg.ping.ping1==false)\n{\n    packetloss=1;\n}\nelse\n{\n    average=msg.ping.ping1;\n}\n\nif (msg.ping.ping2==false)\n{\n    packetloss++;\n}\nelse\n{\n    average=average+msg.ping.ping2;\n}\n\nif (msg.ping.ping3==false)\n{\n    packetloss++;\n}\nelse\n{\n    average=average+msg.ping.ping3;\n}\n\nif (ping==false)\n{\n    packetloss++;\n}\nelse\n{\n    average=average+ping;\n}\n\nif (packetloss!=4)\n{\n    average=average/(4-packetloss);\n}\npacketloss=packetloss*25\n\nmsg.payload = {\n    data: {\n        state: Date.now(),\n        attributes: {\n            'name':msg.ping.name,\n            'host':msg.ping.host,\n            'ping1': msg.ping.ping1,\n            'ping2': msg.ping.ping2,\n            'ping3': msg.ping.ping3,\n            'ping4': ping,\n            'average': Math.floor(average),\n            'packetloss': packetloss,\n            friendly_name: 'Ping '+msg.ping.name,\n            icon: 'mdi:pulse'\n        }\n    }\n};\ndelete msg.ping\ndelete msg.topic\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":560,"y":1320,"wires":[["a6931ffd61c70578"]]},{"id":"294c147daaf6df02","type":"ping","z":"be03f9025a1f137a","protocol":"IPv4","mode":"triggered","name":"ping","host":"","timer":"20","inputs":1,"x":385,"y":1320,"wires":[["bc5f05722a270186"]]},{"id":"d064d8bb22462211","type":"function","z":"be03f9025a1f137a","name":"set ping list","func":"msg.ping_hosts = [\n        { \"name\":\"Google 1\", \"host\":\"8.8.8.8\"},\n        { \"name\": \"Google 2\", \"host\": \"8.8.4.4\" },\n        { \"name\": \"Cloudflare\", \"host\": \"1.1.1.1\" }\n    ]\nflow.set('ping_hosts_length',msg.ping_hosts.length)\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":1125,"wires":[["f8ae3eaa37ec0085"]]},{"id":"84f842d2fce7ac39","type":"inject","z":"be03f9025a1f137a","name":"start ping cycle","props":[],"repeat":"120","crontab":"","once":true,"onceDelay":"30","topic":"","x":220,"y":1125,"wires":[["56afe359d07f650f"]]},{"id":"7bfed63949c4ddc6","type":"function","z":"be03f9025a1f137a","name":"initiate counter","func":"flow.set('host_count',0)\nflow.set('running',1)\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":1125,"wires":[["d064d8bb22462211"]]},{"id":"3f532e48695fa37b","type":"function","z":"be03f9025a1f137a","name":"increase counter","func":"var counter=flow.get('host_count')+1\nif (counter==flow.get('ping_hosts_length'))\n{\n    flow.set('running',0)\n}\nflow.set('host_count',counter)\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":885,"y":1320,"wires":[["ead674e4f58171df"]]},{"id":"56afe359d07f650f","type":"switch","z":"be03f9025a1f137a","name":"Check for active session","property":"running","propertyType":"flow","rules":[{"t":"neq","v":"1","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":430,"y":1125,"wires":[["7bfed63949c4ddc6"]]},{"id":"ead674e4f58171df","type":"switch","z":"be03f9025a1f137a","name":"Check for active session","property":"running","propertyType":"flow","rules":[{"t":"neq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":850,"y":1230,"wires":[["d064d8bb22462211"]]},{"id":"541ade28.b4a62","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true}]

Ah, OK - I tried it out. I see the sensors created in HA, and I see my dummy device has attributes of ping1, ping2, ping3, and ping4 all false, whereas the real devices and the Internet IPs all come back with a ping value. Cool.

Now, do you just trigger notifications off the individual sensor attributes? Or do you not do notifications using this flow? I was looking for a one-stop solution to trigger notifications (containing the “name” attribute, probably) and reboot hardware. I’ll play around with it… I don’t code, but my clipboard game is pretty strong.

Thank you.

EDIT: With this very simple flow, I get an output each time one of the device sensors’ “ping4” attribute delivers a false. However, I still don’t know how to get the “name” attribute included as part of the message:

[{"id":"95a7ee9b5a1eb0ee","type":"trigger-state","z":"eb3cbe54.bd558","name":"Ping Failure","server":"296c0678.b5f9ca","version":2,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"sensor.ping_","entityidfiltertype":"regex","debugenabled":false,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"property","propertyValue":"new_state.attributes.ping4","comparatorType":"is","comparatorValueDatatype":"bool","comparatorValue":"false"}],"inputs":1,"outputs":2,"customoutputs":[],"outputinitially":true,"state_type":"str","enableInput":true,"x":250,"y":2220,"wires":[["b7da4a9710d0bb7e"],[]]},{"id":"b7da4a9710d0bb7e","type":"debug","z":"eb3cbe54.bd558","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":640,"y":2220,"wires":[]},{"id":"296c0678.b5f9ca","type":"server","name":"Home Assistant","version":4,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m"}]

Its just a ping sensor.
Notifications are not included.
You can make a message with a function node that fits your preferred notification text.

Try adding a function node to the last ping node and inserst the text below in it.

var new_payload = "ping time to "+msg.topic+" is "+msg.payload;
msg.payload = new_payload.replace("8.8.8.8","Google 1");
msg.payload = new_payload.replace("8.8.4.4","Google 2");
msg.payload = new_payload.replace("1.1.1.1","Cloudflare");
return msg;