Opnsense MQTT Alias Control
Here are some examples for how I read my OpnSense firewall alias table to control it.
It also uses MQTT so its easier to tie into other services.
I also track my gateway status with this tool.
I have another flow that pulls in these messages and sends it to influxdb so I can view the info in Grafana.
[{"id":"44357c6461bdac57","type":"debug","z":"5e9e97e4c26bc3b4","name":"Auth","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":550,"y":60,"wires":[]},{"id":"5c30838eac12c2ab","type":"function","z":"5e9e97e4c26bc3b4","name":"Auth Setup","func":"var key = msg.key;\nvar secret = msg.secret;\nvar opn_ip = msg.opn_ip;\nvar site = msg.site;\n\nvar convert = (Buffer.from(\"\"+key+\":\"+secret+\"\").toString('base64'));\nvar auth = {\n opn_auth: convert,\n opn_ip: opn_ip,\n}\n\nglobal.set(\"opnsense.msg.auth\", convert);\nglobal.set(\"opnsense.msg.ip\", opn_ip);\nglobal.set(\"SITE_NAME\", site);\n\nreturn auth;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":60,"wires":[["44357c6461bdac57"]]},{"id":"8b6a4bfa381ecff8","type":"inject","z":"5e9e97e4c26bc3b4","name":"API INFO SETUP","props":[{"p":"key","v":"KEY_HERE","vt":"str"},{"p":"secret","v":"SECRET_HERE","vt":"str"},{"p":"opn_ip","v":"IP_ADDRESS_HERE","vt":"str"},{"p":"site","v":"SITE_NAME","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"10","topic":"","x":180,"y":60,"wires":[["5c30838eac12c2ab"]]},{"id":"78a84b7d0fbcadd3","type":"inject","z":"5e9e97e4c26bc3b4","name":"check","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"10","topic":"","payload":"gateway","payloadType":"str","x":150,"y":200,"wires":[["aee87d43257e67fe"]]},{"id":"ae44d881f0248372","type":"inject","z":"5e9e97e4c26bc3b4","name":"check","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"10","topic":"check","x":150,"y":260,"wires":[["ac56c38bf789b191"]]},{"id":"aee87d43257e67fe","type":"function","z":"5e9e97e4c26bc3b4","name":"Gateway","func":"// I use this to track my gateway status, payload contains and array named items\n\nvar ip = global.get(\"opnsense.msg.ip\");\nvar auth = global.get(\"opnsense.msg.auth\");\n\nvar msg1 = {\n name: msg.topic,\n what: \"gateway\",\n method: \"GET\",\n header: \"Content-Type: application/json\",\n headers: {\n \"Authorization\":\"Basic \"+auth+\"\"\n },\n url: \"http://\"+ip+\"/api/routes/gateway/status\"};\n\nreturn msg1;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":200,"wires":[["0cedba02e626f5c6"]]},{"id":"ac56c38bf789b191","type":"function","z":"5e9e97e4c26bc3b4","name":" Firewall ","func":"// I use this to pull the firewall rule info, it returns a payload array named rows\n\nvar ip = global.get(\"opnsense.msg.ip\");\nvar auth = global.get(\"opnsense.msg.auth\");\n\nvar msg1 = {\n name: msg.topic,\n what: \"firewall\",\n method: \"GET\",\n header: \"Content-Type: application/json\",\n headers: {\n \"Authorization\":\"Basic \"+auth+\"\"\n },\n url: \"http://\"+ip+\"/api/firewall/alias/searchItem\"};\nreturn msg1;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":260,"wires":[["0cedba02e626f5c6"]]},{"id":"0cedba02e626f5c6","type":"http request","z":"5e9e97e4c26bc3b4","name":"opnsense","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"basic","x":460,"y":200,"wires":[["c0255ad0c43e2a5d","79fb6352287ce3cf"]]},{"id":"c0255ad0c43e2a5d","type":"splitter","z":"5e9e97e4c26bc3b4","name":"items","property":"payload.items","x":610,"y":200,"wires":[["c1b5285d11146542"]]},{"id":"79fb6352287ce3cf","type":"splitter","z":"5e9e97e4c26bc3b4","name":"rows","property":"payload.rows","x":610,"y":260,"wires":[["491fdadc7c5e8f7b"]]},{"id":"c1b5285d11146542","type":"function","z":"5e9e97e4c26bc3b4","name":"MQTT","func":"var site = global.get(\"SITE_NAME\");\nvar device = \"opnsense\";\nvar api = \"gateway\"\nvar clock = Date().slice(16,24);\n\nvar name = msg.payload.name;\n name = name.charAt(0) + name.slice(1).toLowerCase()\n \nvar address = msg.payload.address;\nvar loss = msg.payload.loss;\n // loss = loss.replace(/[^0-9.]+/gi, \"\")\n loss = parseFloat(loss);\n \nvar delay = msg.payload.delay;\n// delay = delay.replace(/[^0-9.]+/gi, \"\")\n delay = parseFloat(delay);\n \nvar stddev = msg.payload.stddev;\n// stddev = stddev.replace(/[^0-9.]+/gi, \"\")\n stddev = parseFloat(stddev);\n// stddev = stddev.toFixed(2)\n \nvar status = msg.payload.status_translated;\nvar http_code = msg.statusCode;\n http_code = parseFloat(http_code)\n\n\nif(http_code == 200){\nif(msg.what === \"gateway\"){\n\nmsg.payload = { \n site: \"\"+site+\"\",\n device: \"\"+device+\"\",\n api: \"\"+api+\"\",\n name: \"\"+name+\"\", \n address: \"\"+address+\"\",\n loss: loss,\n delay: delay,\n stddev: stddev,\n status: \"\"+status+\"\",\n http_code: http_code\n };\nmsg.topic = \"\"+site+\"/\"+device+\"/\"+api+\"/\"+name+\"\" \n\nglobal.set(\"\"+device+\".\"+api+\".\"+name+\".status\", status);\nglobal.set(\"\"+device+\".\"+api+\".\"+name+\".time\", clock);\nglobal.set(\"\"+device+\".\"+api+\".\"+name+\".address\", address);\n{node.status({fill:\"green\",shape:\"dot\",text: \"\"+name+\" \"+status+\"\"})}\nreturn [msg];\n}\n\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":200,"wires":[["a850d68d980e37b6","4e3931bcd485cc47"]]},{"id":"491fdadc7c5e8f7b","type":"function","z":"5e9e97e4c26bc3b4","name":"MQTT","func":"var site = global.get(\"SITE_NAME\");\nvar device = \"opnsense\"\nvar api = \"firewall\"\nvar error = {payload: \"http error\"};\nvar clock = Date().slice(16,24);\n\n\nvar name = msg.payload.name;\nvar uuid = msg.payload.uuid;\nvar content = msg.payload.content;\nvar http_code = msg.statusCode;\n http_code = parseFloat(http_code);\n\nvar bool1 = context.set('bool',0);\nif (msg.payload.enabled ==\"1\"){\n context.set('bool',1);\n}\nvar stat1 = context.set('stat',\"on\");\nif (msg.payload.enabled ==\"1\"){\n context.set('stat',\"off\");\n}\nvar stat = context.get('stat');\n\nvar bool = context.get('bool');\n\nmsg.payload = { \n site: \"\"+site+\"\",\n device: \"\"+device+\"\",\n api: \"\"+api+\"\",\n name: \"\"+name+\"\", \n uuid: \"\"+uuid+\"\",\n bool: Boolean(bool),\n status: \"\"+stat+\"\",\n content: \"\"+content+\"\",\n http_code: http_code,\n clock: \"\"+clock+\"\",\n };\nmsg.topic = \"\"+site+\"/\"+device+\"/\"+api+\"/\"+name+\"\";\n\nvar all = {\"uuid\":\"\"+uuid+\"\", \"status\": \"\"+stat+\"\", \"bool\": Boolean(bool), \"clock\": \"\"+clock+\"\"}; \n\nif(http_code == 200){\n} else {\n return [\"error\"]; }\n//CAN COPY-PASTE THE FOLLOWING FOR EVERY ALIAS to track and/or control\nif(name === \"ENTER_FW_ALIAS_NAME\"){\nglobal.set(\"\"+device+\".\"+api+\".\"+name+\"\", all);\n{node.status({fill:\"green\",shape:\"dot\",text: \"\"+name+\" \"+stat+\"\"})}\nreturn [msg];}\n\n\n\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":750,"y":260,"wires":[["a850d68d980e37b6"]]},{"id":"19019f5d438da9ac","type":"comment","z":"5e9e97e4c26bc3b4","name":"Notes","info":"Fill in the 4 things to get started, I inject this at startup\nKey and Secret are from your user API Keys in OpnSense\nIP is for your OpnSense Router\nSITE_NAME is whatever you want\n","x":150,"y":100,"wires":[]},{"id":"ee2356084585266a","type":"delay","z":"5e9e97e4c26bc3b4","name":"refresh","pauseType":"delay","timeout":"4","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":620,"y":440,"wires":[["6cc90c6e04606dbf"]]},{"id":"5629a5bfaeb92576","type":"delay","z":"5e9e97e4c26bc3b4","name":"reload","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":610,"y":380,"wires":[["6cc90c6e04606dbf"]]},{"id":"9ae6fc0ce99c853f","type":"trigger","z":"5e9e97e4c26bc3b4","name":"timer","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"1","extend":false,"overrideDelay":true,"units":"s","reset":"","bytopic":"topic","topic":"topic","outputs":1,"x":610,"y":320,"wires":[["cf1f673a15275e17"]]},{"id":"075898d30acf85f4","type":"function","z":"5e9e97e4c26bc3b4","name":"opnsense","func":"var ip = global.get(\"opnsense.msg.ip\");\nvar auth = global.get(\"opnsense.msg.auth\");\nvar site = global.get(\"SITE_NAME\")\n\nvar who = msg.who;\nvar what = msg.what;\n\nvar array = global.get(\"opnsense.firewall.\"+who+\"\");\nvar uuid = array[\"uuid\"];\nvar bool = array[\"bool\"];\nvar stat = array[\"status\"];\n\nif(what === true){\n context.set('stat', false);\n }\n\nif(what === false){\n context.set('stat', true);\n }\n\nvar stat1 = context.get('stat');\n\nvar timer = msg.timer;\ntimer = parseInt(timer);\nvar sec = timer * 60;\nvar ms = sec * 1000;\n\n{node.status({fill:\"green\",shape:\"dot\",text: sec})}\n\nvar toggle1 = {\n\n method: \"POST\",\n header: \"Content-Type: application/json\",\n headers: {\n \"Authorization\":\"Basic \"+auth+\"\"\n },\n url: \"http://\"+ip+\"/api/firewall/alias/toggleItem/\"+uuid+\"\",\n payload: {\n who: who,\n what: what\n },\n topic: uuid,\n ip: \"\"+ip+\"\"\n };\n\nvar toggle2 = {\n topic: \"\"+site+\"/cmd/opnsense/toggle/\"+uuid+\"\",\n payload: {\n who: who,\n cmd: Boolean(stat1),\n ctrl: \"timer\",\n timer: 1\n },\n delay: ms\n };\n \nvar reload = {\n\n method: \"POST\",\n header: \"Content-Type: application/json\",\n headers: {\n \"Authorization\":\"Basic \"+auth+\"\"\n },\n url: \"http://\" + ip +\"/api/firewall/alias/reconfigure\",\n topic: uuid, \n ip: \"\"+ip+\"\"\n };\n \nif (sec < 120){\n node.send([ toggle1, null, reload ]);\n {node.status({fill:\"green\",shape:\"dot\",text: \"No Delay\"})}\n }\nif (sec >= 120){\n node.send([ toggle1, toggle2, reload ]);\n {node.status({fill:\"green\",shape:\"dot\",text: \"Has Delay\"})}\n} \n \n ","outputs":3,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":360,"wires":[["6cc90c6e04606dbf"],["9ae6fc0ce99c853f"],["ee2356084585266a","5629a5bfaeb92576"]],"outputLabels":["Status","Toggle",""],"icon":"font-awesome/fa-ban"},{"id":"c7d002a2b9b6ad1e","type":"change","z":"5e9e97e4c26bc3b4","name":"fix mqtt","rules":[{"t":"move","p":"payload.timer","pt":"msg","to":"timer","tot":"msg"},{"t":"move","p":"payload.ctrl","pt":"msg","to":"ctrl","tot":"msg"},{"t":"move","p":"payload.who","pt":"msg","to":"who","tot":"msg"},{"t":"move","p":"payload.cmd","pt":"msg","to":"what","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":280,"y":360,"wires":[["075898d30acf85f4"]]},{"id":"cf1f673a15275e17","type":"change","z":"5e9e97e4c26bc3b4","name":"del","rules":[{"t":"delete","p":"delay","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":320,"wires":[["a850d68d980e37b6"]]},{"id":"58aca5b74abed931","type":"switch","z":"5e9e97e4c26bc3b4","name":"topic","property":"topic","propertyType":"msg","rules":[{"t":"cont","v":"SITE_NAME/cmd/opnsense/toggle","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":270,"y":400,"wires":[["c7d002a2b9b6ad1e"]]},{"id":"dc698c7190ce2b8f","type":"comment","z":"5e9e97e4c26bc3b4","name":"TO MQTT","info":"","x":940,"y":240,"wires":[]},{"id":"6cc90c6e04606dbf","type":"link out","z":"5e9e97e4c26bc3b4","name":"link out 2","mode":"link","links":["b8e5dcfd36f9b2c7"],"x":745,"y":360,"wires":[]},{"id":"b8e5dcfd36f9b2c7","type":"link in","z":"5e9e97e4c26bc3b4","name":"link in 1","links":["6cc90c6e04606dbf"],"x":345,"y":160,"wires":[["0cedba02e626f5c6"]]},{"id":"a850d68d980e37b6","type":"link out","z":"5e9e97e4c26bc3b4","name":"TO_MQTT_SERVER","mode":"link","links":[],"x":865,"y":240,"wires":[]},{"id":"3846b46d637473eb","type":"link in","z":"5e9e97e4c26bc3b4","name":"FROM_MQTT_SERVER","links":[],"x":175,"y":400,"wires":[["58aca5b74abed931"]]},{"id":"f51544bbb253a99c","type":"comment","z":"5e9e97e4c26bc3b4","name":"FROM MQTT","info":"","x":130,"y":360,"wires":[]},{"id":"4e3931bcd485cc47","type":"debug","z":"5e9e97e4c26bc3b4","name":"GATEWAY","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":950,"y":200,"wires":[]},{"id":"a41a01089ff8d053","type":"debug","z":"5e9e97e4c26bc3b4","name":"FIREWALL","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":950,"y":280,"wires":[]},{"id":"db787cf6fd9a28f6","type":"change","z":"5e9e97e4c26bc3b4","name":"Xbox","rules":[{"t":"set","p":"who","pt":"msg","to":"xbox","tot":"str"},{"t":"move","p":"payload","pt":"msg","to":"what","tot":"msg"},{"t":"set","p":"topic","pt":"msg","to":"SITE_NAME/cmd/opnsense/toggle/$UUID#","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":560,"wires":[["551b3d12c84435e8"]]},{"id":"551b3d12c84435e8","type":"delay","z":"5e9e97e4c26bc3b4","name":"limit","pauseType":"rate","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":470,"y":560,"wires":[["a3f025becfc22fe0"]]},{"id":"a3f025becfc22fe0","type":"function","z":"5e9e97e4c26bc3b4","name":"timers","func":"var site = global.get(\"SITE_NAME\");\nvar clock = Date().slice(16,24);\n\nvar who = msg.who;\nvar what = msg.what;\nvar txt = \"\"+who+\" \"+what+\"\";\nvar array = global.get(\"opnsense.firewall.\"+who+\"\");\nvar uuid = array[\"uuid\"];\nvar bool = array[\"bool\"];\nvar stat = array[\"status\"];\n\nnode.status({fill:\"green\", shape:\"ring\", text: txt });\n\nvar toggle_on = {\n topic: \"\"+site+\"/cmd/opnsense/toggle/\"+uuid+\"\",\n payload: {\n timer: 1,\n ctrl: \"schedule\",\n cmd: true,\n who: who,\n what: what,\n clock: clock\n },\n reset: true \n }\n\nvar toggle_off = {\n topic: \"\" + site + \"/cmd/opnsense/toggle/\" + uuid + \"\",\n payload: {\n timer: 1,\n ctrl: \"schedule\",\n cmd: false,\n who: who,\n what: what,\n clock: clock \n },\n reset: true \n }\n\nif(what == \"off\"){\n if(array[\"bool\"] === true){\n node.send([ null ]);\n }\n else{\n node.send([ toggle_off ]);\n }}\n\nif(what == \"on\"){\n if(array[\"bool\"] === false){\n node.send([ null ]);\n }\n else{\n node.send([ toggle_on ]);\n }}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":560,"wires":[["58aca5b74abed931"]],"inputLabels":["who"],"outputLabels":["timer"],"icon":"font-awesome/fa-clock-o"},{"id":"59f5d19b8c9cf5d0","type":"comment","z":"5e9e97e4c26bc3b4","name":"Scheduled Timer example","info":"","x":310,"y":520,"wires":[]},{"id":"ca03ac3e176f3eef","type":"change","z":"5e9e97e4c26bc3b4","name":"Xbox","rules":[{"t":"set","p":"who","pt":"msg","to":"xbox","tot":"str"},{"t":"move","p":"payload","pt":"msg","to":"what","tot":"msg"},{"t":"set","p":"timer","pt":"msg","to":"10","tot":"num"},{"t":"set","p":"ctrl","pt":"msg","to":"Mom","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"SITE_NAME/cmd/opnsense/toggle/$UUID#","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":660,"wires":[["041a4ce9034e530d"]]},{"id":"041a4ce9034e530d","type":"delay","z":"5e9e97e4c26bc3b4","name":"limit","pauseType":"rate","timeout":"3","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":470,"y":660,"wires":[["3e64e82e1ebb3c4d"]]},{"id":"3e64e82e1ebb3c4d","type":"function","z":"5e9e97e4c26bc3b4","name":"manual","func":"var site = global.get(\"SITE_NAME\");\nvar clock = Date().slice(16,24);\n\nvar who = msg.who;\nvar what = msg.what;\nvar timer = msg.timer;\nvar ctrl = msg.ctrl;\n\nvar txt = \"\"+who+\" \"+what+\"\";\nvar array = global.get(\"opnsense.firewall.\"+who+\"\");\nvar uuid = array[\"uuid\"];\nvar bool = array[\"bool\"];\nvar stat = array[\"status\"];\n\nnode.status({fill:\"green\", shape:\"ring\", text: txt });\n\nvar toggle_on = {\n topic: \"\" + site + \"/cmd/opnsense/toggle/\" + uuid + \"\",\n payload: {\n timer: \"\" + timer + \"\",\n ctrl: \"\" + ctrl + \"\",\n cmd: true,\n who: who,\n what: what,\n clock: clock\n },\n reset: true \n }\n\nvar toggle_off = {\n topic: \"\" + site + \"/cmd/opnsense/toggle/\" + uuid + \"\",\n payload: {\n timer: \"\" + timer + \"\",\n ctrl: \"\" + ctrl + \"\",\n cmd: false,\n who: who,\n what: what,\n clock: clock \n },\n reset: true \n }\n\nif(what == \"off\"){\n if(array[\"bool\"] === true){\n node.send([ null ]);\n }\n else{\n node.send([ toggle_off ]);\n }}\n\nif(what == \"on\"){\n if(array[\"bool\"] === false){\n node.send([ null ]);\n }\n else{\n node.send([ toggle_on ]);\n }}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":660,"wires":[["58aca5b74abed931"]],"inputLabels":["who"],"outputLabels":["timer"],"icon":"font-awesome/fa-clock-o"},{"id":"962671cd1c9da020","type":"comment","z":"5e9e97e4c26bc3b4","name":"Manual Timer example","info":"","x":300,"y":620,"wires":[]},{"id":"3c25be0b7d70b5b0","type":"inject","z":"5e9e97e4c26bc3b4","name":"on","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"on","payloadType":"str","x":130,"y":640,"wires":[["ca03ac3e176f3eef"]]},{"id":"1a03965a6d891b96","type":"inject","z":"5e9e97e4c26bc3b4","name":"off","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"off","payloadType":"str","x":130,"y":680,"wires":[["ca03ac3e176f3eef"]]},{"id":"a0a788a33cfa7890","type":"inject","z":"5e9e97e4c26bc3b4","name":"on","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"on","payloadType":"str","x":130,"y":540,"wires":[["db787cf6fd9a28f6"]]},{"id":"702a537cb6141a43","type":"inject","z":"5e9e97e4c26bc3b4","name":"off","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"off","payloadType":"str","x":130,"y":580,"wires":[["db787cf6fd9a28f6"]]}]