- The list of registered devices would last only as long as Node-Red was active. If I needed to restart the Node-Red docker for any reason, I would also need to re-register announcement devices.
- The ONVIF node the flow relies on is a little flaky, and will occasionally just disappear from Node Red.
I've added functionality to store the list of devices in a text file, so it persists between Node-Red restarts. I also added some notes on how to recover from the self-destructing ONVIF nodes, bring this all up to v1.1.1.
The device list saving is managed automatically as part of the voice registration process, but there's also a manual trigger that can be used in testing. If you use this, you might need to adjust the save and read file locations, particularly if you're not running Node-Red in a docker, like me.
The full flow is pasted below;
[{"id": "55793b5be2d1c883","type": "tab","label": "Doorbell","disabled": false,"info": "","env": []},{"id": "d24f7050.8bd5b","type": "inject","z": "55793b5be2d1c883","name": "Start listening","props": [],"repeat": "86400","crontab": "","once": true,"onceDelay": "5","topic": "","x": 220,"y": 100,"wires": [["97d0eb18.a1ee08"]]},{"id": "97d0eb18.a1ee08","type": "change","z": "55793b5be2d1c883","name": "","rules": [{"t": "set","p": "action","pt": "msg","to": "start","tot": "str"}],"action": "","property": "","from": "","to": "","reg": false,"x": 400,"y": 100,"wires": [["545ec2db2f160340"]]},{"id": "55e40eba.19775","type": "inject","z": "55793b5be2d1c883","name": "Stop listening","repeat": "","crontab": "","once": false,"onceDelay": 0.1,"topic": "","payload": "","payloadType": "date","x": 210,"y": 140,"wires": [["3b192f32.da0b"]]},{"id": "3b192f32.da0b","type": "change","z": "55793b5be2d1c883","name": "","rules": [{"p": "action","pt": "msg","t": "set","to": "stop","tot": "str"}],"action": "","property": "","from": "","to": "","reg": false,"x": 400,"y": 140,"wires": [[]]},{"id": "b8a6fb75.d6bc28","type": "switch","z": "55793b5be2d1c883","name": "","property": "topic","propertyType": "msg","rules": [{"t": "eq","v": "RuleEngine/MyRuleDetector/Visitor","vt": "str"}],"checkall": "true","repair": false,"outputs": 1,"x": 730,"y": 100,"wires": [["9526130c.79b8f"]]},{"id": "9526130c.79b8f","type": "switch","z": "55793b5be2d1c883","name": "","property": "data.value","propertyType": "msg","rules": [{"t": "true"}],"checkall": "true","repair": false,"outputs": 1,"x": 850,"y": 100,"wires": [["4cf4791f.5d21d8"]]},{"id": "4cf4791f.5d21d8","type": "delay","z": "55793b5be2d1c883","name": "","pauseType": "rate","timeout": "5","timeoutUnits": "seconds","rate": "1","nbRateUnits": "5","rateUnits": "second","randomFirst": "1","randomLast": "5","randomUnits": "seconds","drop": true,"outputs": 1,"x": 1000,"y": 100,"wires": [["e562683462597b36"]]},{"id": "dec68ffe455db698","type": "alexa-remote-other","z": "55793b5be2d1c883","name": "","account": "b9d166b16d287937","config": {"option": "get","value": {"what": "activities","count": {"type": "num","value": "1"},"offset": {"type": "num","value": "1"}}},"x": 530,"y": 500,"wires": [["454de8f65d88278a"]]},{"id": "454de8f65d88278a","type": "function","z": "55793b5be2d1c883","name": "Get Device Name of most recent Doorbell request","func": "let deviceName = null;\n\n// Iterate through the array of activities\nfor (let i = 0; i < msg.payload.length; i++) {\n const activity = msg.payload[i];\n\n // Check if the activity contains voiceHistoryRecordItems\n if (activity.data && activity.data.voiceHistoryRecordItems) {\n for (const item of activity.data.voiceHistoryRecordItems) {\n // Check if transcriptText exists and contains the substring \"doorbell notification\"\n if (item.transcriptText && item.transcriptText.includes(\"doorbell alert\")) {\n // Found the desired text, get the deviceName\n deviceName = activity.data.device.deviceName;\n break;\n }\n }\n }\n\n // If deviceName is found, exit the loop\n if (deviceName) {\n break;\n }\n}\n\n// Set the deviceName as the result\nmsg.deviceName = deviceName;\n\nreturn msg;","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 830,"y": 500,"wires": [["529424166f5fec67","7536e089c87482f9"]]},{"id": "5e8d6a337df14589","type": "function","z": "55793b5be2d1c883","name": "store switch state","func": "// Check the payload value\nif (msg.payload === \"on\" || msg.payload === \"off\") {\n // Store the payload value in a flow variable called \"switchState\"\n flow.set(\"switchState\", msg.payload);\n return msg;\n} else {\n // If the payload value is not \"on\" or \"off\", you can handle it here if needed\n // For example, you can send an error message or perform other actions\n node.error(\"Invalid payload value: \" + msg.payload);\n}","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 610,"y": 400,"wires": [["9c7e92e0a11cb2d2"]]},{"id": "529424166f5fec67","type": "function","z": "55793b5be2d1c883","name": "save to context variable","func": "// Retrieve the deviceName from the incoming msg object\nconst deviceName = msg.deviceName;\n\n// Retrieve the switchState from a flow variable\nconst switchState = flow.get(\"switchState\");\n\nif (!deviceName || !switchState) {\n // Handle invalid data or missing values\n msg.successStatus = 0; // Unsuccessful\n msg.error = \"Invalid deviceName or switchState.\";\n} else {\n // Prepare the data to be stored in context variables\n // Use the deviceName as the key (unique identifier)\n const deviceStatus = {\n deviceName: deviceName,\n switchState: switchState\n };\n\n // Retrieve the existing device statuses from flow context (assuming it's an object)\n const existingDeviceStatuses = flow.get(\"deviceStatuses\") || {};\n\n // Update the device status data with the deviceName as the key\n existingDeviceStatuses[deviceName] = deviceStatus;\n\n // Store the updated device status data in flow context\n flow.set(\"deviceStatuses\", existingDeviceStatuses);\n\n // Set the successStatus flag to 1 (successful)\n msg.successStatus = 1;\n\n // Include switchState in the msg payload\n msg.switchState = switchState;\n}\n\nreturn msg;\n","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 410,"y": 600,"wires": [["b994947ab60e8c90"]]},{"id": "f7fe5c7996fb6604","type": "function","z": "55793b5be2d1c883","name": "Make Response","func": "\n// Retrieve the switchState from the message payload\nconst switchState = msg.switchState;\n\n// Define a variable to store the result of the branching\nlet branchResult;\n\n// Check the value of switchState and branch accordingly\nif (switchState === \"on\") {\n // If switchState is \"on\", do something (e.g., set a variable or perform an action)\n\n msg.payload = {\n \"text\": \"I will announce doorbells on this device\",\n \"device\": msg.deviceName\n }\n branchResult = \"Switch is ON\";\n} else if (switchState === \"off\") {\n // If switchState is \"off\", do something else (e.g., set a different variable or perform a different action)\n msg.payload = {\n \"text\": \"Doorbells wont announce on this device\",\n \"device\": msg.deviceName\n }\n \n branchResult = \"Switch is OFF\";\n} else {\n // Handle other cases if needed\n msg.payload = {\n \"text\": \"oops. I've lost track of things. Please try that again.\",\n \"device\": msg.deviceName\n }\n\n\n branchResult = \"Switch is in an unknown state\";\n}\n\n// You can use branchResult or set other variables based on the branch\nmsg.branchResult = branchResult;\n\nreturn msg;","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 800,"y": 600,"wires": [["06e0fb3d494c9327"]]},{"id": "ad02a0a0c945f18f","type": "alexa-remote-routine","z": "55793b5be2d1c883","name": "","account": "b9d166b16d287937","routineNode": {"type": "speak","payload": {"type": "regular","text": {"type": "msg","value": "payload.text"},"devices": {"type": "msg","value": "payload.device"}}},"x": 1160,"y": 600,"wires": [[]]},{"id": "b994947ab60e8c90","type": "switch","z": "55793b5be2d1c883","name": "Success?","property": "successStatus","propertyType": "msg","rules": [{"t": "eq","v": "1","vt": "num"}],"checkall": "true","repair": false,"outputs": 1,"x": 620,"y": 600,"wires": [["f7fe5c7996fb6604","067b285c5fee9abe"]]},{"id": "06e0fb3d494c9327","type": "delay","z": "55793b5be2d1c883","name": "","pauseType": "delay","timeout": "1","timeoutUnits": "seconds","rate": "1","nbRateUnits": "1","rateUnits": "second","randomFirst": "1","randomLast": "5","randomUnits": "seconds","drop": false,"allowrate": false,"outputs": 1,"x": 980,"y": 600,"wires": [["ad02a0a0c945f18f"]]},{"id": "c4bd9e0a5d16d339","type": "inject","z": "55793b5be2d1c883","name": "list devices","props": [{"p": "payload"},{"p": "topic","vt": "str"}],"repeat": "","crontab": "","once": false,"onceDelay": 0.1,"topic": "","payload": "","payloadType": "date","x": 220,"y": 780,"wires": [["bed345588330fe4b"]]},{"id": "bed345588330fe4b","type": "function","z": "55793b5be2d1c883","name": "Retrieve Device Statuses","func": "// Retrieve the deviceStatuses from the flow context\nconst deviceStatuses = flow.get(\"deviceStatuses\");\n\nif (deviceStatuses) {\n // Extract all device names and switch states from the deviceStatuses object\n const deviceInfo = Object.keys(deviceStatuses).map((deviceName) => ({\n deviceName: deviceName,\n switchState: deviceStatuses[deviceName].switchState\n }));\n\n if (deviceInfo.length > 0) {\n // Set the list of device names and switch states in the msg.payload\n msg.payload = deviceInfo;\n } else {\n // If no device names are found, set an informative message\n msg.payload = \"No device names found.\";\n }\n} else {\n // If deviceStatuses is not found, set an informative message\n msg.payload = \"No device statuses found.\";\n}\n\nreturn msg;\n","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 430,"y": 780,"wires": [["d9f51aadc666bdfa"]]},{"id": "d9f51aadc666bdfa","type": "debug","z": "55793b5be2d1c883","name": "Doorbell Alerts","active": true,"tosidebar": true,"console": false,"tostatus": false,"complete": "true","targetType": "full","statusVal": "","statusType": "auto","x": 1160,"y": 780,"wires": []},{"id": "d4feba066cce7b62","type": "inject","z": "55793b5be2d1c883","name": "DELETE devices","props": [{"p": "payload"},{"p": "topic","vt": "str"}],"repeat": "","crontab": "","once": false,"onceDelay": 0.1,"topic": "","payload": "","payloadType": "date","x": 200,"y": 840,"wires": [["80f49f79c09a0969"]]},{"id": "80f49f79c09a0969","type": "function","z": "55793b5be2d1c883","name": "Clear Devices & Statuses","func": "\n// Clear the deviceStatuses variable in the flow context\nflow.set(\"deviceStatuses\", {});\n\n// Set a successStatus flag to indicate that the reset was successful (you can customize this as needed)\nmsg.successStatus = 1;\n\nreturn msg;\n","outputs": 1,"noerr": 0,"initialize": "","finalize": "","libs": [],"x": 430,"y": 840,"wires": [["bed345588330fe4b","360975caf15b761a"]]},{"id": "df33c004d8f22261","type": "inject","z": "55793b5be2d1c883","name": "test announce","props": [{"p": "payload"},{"p": "topic","vt": "str"}],"repeat": "","crontab": "","once": false,"onceDelay": 0.1,"topic": "","payload": "","payloadType": "date","x": 350,"y": 200,"wires": [["e562683462597b36"]]},{"id": "e562683462597b36","type": "function","z": "55793b5be2d1c883","name": "config anouncement for 'on' devices","func": "// Retrieve the deviceStatuses from the flow context\nconst deviceStatuses = flow.get(\"deviceStatuses\");\n\nif (deviceStatuses) {\n // Initialize an array to store device names with 'on' status\n const devicesOn = [];\n\n // Iterate through the deviceStatuses\n for (const deviceName in deviceStatuses) {\n if (deviceStatuses.hasOwnProperty(deviceName)) {\n const switchState = deviceStatuses[deviceName].switchState;\n\n // Check if the switch state is 'on' (you can customize this condition)\n if (switchState === 'on') {\n // Add the device name to the list of devices with 'on' status\n devicesOn.push(deviceName);\n }\n }\n }\n\n if (devicesOn.length > 0) {\n // Create the payload in the required format\n const payload = {\n type: 'speak',\n payload: {\n type: 'regular',\n text: \"There's Someody at the door\",\n devices: devicesOn\n }\n };\n\n // Set the payload in the msg object\n msg.payload = payload;\n } else {\n // If no devices are found with 'on' status, set an informative message\n msg.payload = 'No devices are currently switched on.';\n }\n} else {\n // If deviceStatuses is not found, set an informative message\n msg.payload = 'No device statuses found.';\n}\n\nreturn msg;\n","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 620,"y": 200,"wires": [["d8acdcd07b4e928d"]]},{"id": "9c7e92e0a11cb2d2","type": "delay","z": "55793b5be2d1c883","name": "","pauseType": "delay","timeout": "1","timeoutUnits": "seconds","rate": "1","nbRateUnits": "1","rateUnits": "second","randomFirst": "1","randomLast": "5","randomUnits": "seconds","drop": false,"allowrate": false,"outputs": 1,"x": 360,"y": 500,"wires": [["dec68ffe455db698"]]},{"id": "446290af56c8e2f7","type": "alexa-remote-routine","z": "55793b5be2d1c883","name": "","account": "b9d166b16d287937","routineNode": {"type": "speak","payload": {"type": "regular","text": {"type": "msg","value": "payload.payload.text"},"devices": {"type": "msg","value": "payload.payload.devices"}}},"x": 1160,"y": 280,"wires": [[]]},{"id": "d3c4ab189d5ed545","type": "alexa-remote-routine","z": "55793b5be2d1c883","name": "","account": "b9d166b16d287937","routineNode": {"type": "sound","payload": {"sound": {"type": "str","value": "amzn_sfx_doorbell_chime_02"},"devices": {"type": "msg","value": "payload.payload.devices"}}},"x": 1160,"y": 200,"wires": [[]]},{"id": "830b288c32f7bdd2","type": "delay","z": "55793b5be2d1c883","name": "","pauseType": "delay","timeout": "3","timeoutUnits": "seconds","rate": "1","nbRateUnits": "1","rateUnits": "second","randomFirst": "1","randomLast": "5","randomUnits": "seconds","drop": false,"allowrate": false,"outputs": 1,"x": 980,"y": 260,"wires": [["446290af56c8e2f7"]]},{"id": "e5618282456c5d2f","type": "comment","z": "55793b5be2d1c883","name": "Utility Functions =========================","info": "","x": 220,"y": 720,"wires": []},{"id": "8480fc71dcbdcba5","type": "comment","z": "55793b5be2d1c883","name": "Manage Alexa Events ====================","info": "","x": 220,"y": 320,"wires": []},{"id": "11a64ea38762b9fc","type": "comment","z": "55793b5be2d1c883","name": "Manage Reolink Events ===================","info": "","x": 220,"y": 40,"wires": []},{"id": "d8acdcd07b4e928d","type": "switch","z": "55793b5be2d1c883","name": "","property": "payload","propertyType": "msg","rules": [{"t": "cont","v": "No device","vt": "str"},{"t": "else"}],"checkall": "true","repair": false,"outputs": 2,"x": 850,"y": 200,"wires": [["49d6f2fb0b1c1cce"],["830b288c32f7bdd2","d3c4ab189d5ed545"]]},{"id": "9896d0ca01888104","type": "link in","z": "55793b5be2d1c883","name": "doorbell - debug","links": ["49d6f2fb0b1c1cce","7536e089c87482f9"],"x": 965,"y": 720,"wires": [["d9f51aadc666bdfa"]]},{"id": "49d6f2fb0b1c1cce","type": "link out","z": "55793b5be2d1c883","name": "dorbell debug call 1","mode": "link","links": ["9896d0ca01888104"],"x": 1095,"y": 160,"wires": []},{"id": "7536e089c87482f9","type": "link out","z": "55793b5be2d1c883","name": "dorbell debug call 2","mode": "link","links": ["9896d0ca01888104"],"x": 1095,"y": 500,"wires": []},{"id": "11fc376f018a4408","type": "comment","z": "55793b5be2d1c883","name": "ABOUT v1.1.1","info": "This flow is intended to allow Echo devices\nbe configured to announce visitors who\npress on an OnVif compatible doorbell,\nlike a ReoLink.\n\nFor full details about how this all works,\nsee:\nhttps://mediaserver8.blogspot.com/2023/11/announce-reolink-doorbell-on-echo.html\n\nIf you find this interesting or useful,\nplease consider conributig to my coffee\nfund here: \nhttps://ko-fi.com/8d14a771a245ac7\n\nVERSION HISTORY\n1.1.1 - Added notes on how to reover from disappearing ONIV\n1.1 - Added feature to save device list for persistence\n1.0 - Initial Release","x": 1170,"y": 40,"wires": []},{"id": "1d64d5093a5b4d53","type": "link in","z": "55793b5be2d1c883","name": "Doorbell - Notification","links": ["142dfcd31f9a3e88"],"x": 305,"y": 400,"wires": [["5e8d6a337df14589"]]},{"id": "853201bc07157620","type": "function","z": "55793b5be2d1c883","name": "Prep data","func": "// @ts-nocheck\n//based on this GLOBAL var persistence flow\n\n// flow variables separated by semicolon to be saved\nvar varlist = \"deviceStatuses\";\nvar mylist = varlist.split(\";\");\n\nvar outputs = [];\n\nfor (i=0; i<mylist.length; i++) {\n outputs.push({ key : mylist[i], type: typeof flow.get(mylist[i]), value: flow.get(mylist[i])});\n}\n \n \nmsg.payload = outputs;\nreturn msg;\n\n//msg.payload=typeof global.get(\"torrent_keywords\");\n","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 400,"y": 960,"wires": [["4b6ad3994c0cb8e0"]]},{"id": "9132406e5a2c2909","type": "file","z": "55793b5be2d1c883","name": "","filename": "/data/saveVars/global.json","filenameType": "str","appendNewline": true,"createDir": true,"overwriteFile": "true","x": 750,"y": 960,"wires": [[]]},{"id": "4b6ad3994c0cb8e0","type": "json","z": "55793b5be2d1c883","name": "","property": "payload","action": "","pretty": false,"x": 550,"y": 960,"wires": [["9132406e5a2c2909"]]},{"id": "8451d83eb5862c66","type": "inject","z": "55793b5be2d1c883","name": "Save Flow Settings","props": [{"p": "payload"},{"p": "topic","vt": "str"}],"repeat": "","crontab": "","once": false,"onceDelay": 0.1,"topic": "","payload": "","payloadType": "date","x": 210,"y": 920,"wires": [["853201bc07157620"]]},{"id": "f2f3023afa8c4a86","type": "inject","z": "55793b5be2d1c883","name": "Startup","props": [{"p": "payload"},{"p": "topic","vt": "str"}],"repeat": "","crontab": "","once": true,"onceDelay": "4","topic": "","payload": "","payloadType": "date","x": 200,"y": 1060,"wires": [["21f1d1c39ce10c6f"]]},{"id": "21f1d1c39ce10c6f","type": "file in","z": "55793b5be2d1c883","name": "","filename": "/data/saveVars/global.json","filenameType": "str","format": "utf8","allProps": false,"x": 469,"y": 1060,"wires": [["10781edf6a557798"]]},{"id": "1bd710959b413778","type": "function","z": "55793b5be2d1c883","name": "Restore","func": "var output = [];\n\nfor (var i=0; i<msg.payload.length; i++) {\n switch (msg.payload[i].type) {\n case 'undefined': \n // the global variable probably had no value, nothing needs to be restored\n output.push(msg.payload[i].key + \" is undefined.\");\n break;\n case 'number':\n if (msg.payload[i].value===\"NaN\") {\n // there is no valid value to be restored, skip this variable\n output.push(msg.payload[i].key + \" is NaN.\");\n } else {\n if (msg.payload[i].value.toString().indexOf(\".\")>-1) {\n // the value appears to be a float\n flow.set(msg.payload[i].key,parseFloat(msg.payload[i].value));\n output.push(msg.payload[i].key + \" is restored to \" + msg.payload[i].value);\n } else {\n flow.set(msg.payload[i].key,parseInt(msg.payload[i].value));\n output.push(msg.payload[i].key + \" is restored to \" + msg.payload[i].value);\n }\n }\n break;\n case 'string':\n flow.set(msg.payload[i].key,msg.payload[i].value);\n output.push(msg.payload[i].key + \" is restored to \" + msg.payload[i].value);\n break;\n case 'boolean':\n flow.set(msg.payload[i].key,msg.payload[i].value===\"true\");\n output.push(msg.payload[i].key + \" is restored to \" + msg.payload[i].value);\n break;\n case 'object':\n flow.set(msg.payload[i].key,msg.payload[i].value);\n output.push(msg.payload[i].key + \" is restored\" );\n break;\n }\n}\n\nmsg.payload = output;\nreturn msg;","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 210,"y": 1135,"wires": [["bc0ebbe4a14943a8"]]},{"id": "10781edf6a557798","type": "json","z": "55793b5be2d1c883","name": "","property": "payload","action": "","pretty": true,"x": 670,"y": 1060,"wires": [["1bd710959b413778"]]},{"id": "bc0ebbe4a14943a8","type": "function","z": "55793b5be2d1c883","name": "deviceStatuses restore","func": "msg.topic = \"deviceStatuses\";\nmsg.payload = flow.get(\"deviceStatuses\");\nreturn msg;","outputs": 1,"timeout": "","noerr": 0,"initialize": "","finalize": "","libs": [],"x": 458,"y": 1136,"wires": [["095be6c42958ef61"]]},{"id": "095be6c42958ef61","type": "debug","z": "55793b5be2d1c883","name": "FLOW RESTORE","active": true,"tosidebar": true,"console": false,"tostatus": false,"complete": "true","targetType": "full","statusVal": "","statusType": "auto","x": 730,"y": 1140,"wires": []},{"id": "7c8e283ac4499d78","type": "link in","z": "55793b5be2d1c883","name": "Save Flow Data","links": ["067b285c5fee9abe","360975caf15b761a"],"x": 195,"y": 980,"wires": [["853201bc07157620"]]},{"id": "067b285c5fee9abe","type": "link out","z": "55793b5be2d1c883","name": "call save","mode": "link","links": ["7c8e283ac4499d78"],"x": 725,"y": 660,"wires": []},{"id": "360975caf15b761a","type": "link out","z": "55793b5be2d1c883","name": "call save","mode": "link","links": ["7c8e283ac4499d78"],"x": 675,"y": 840,"wires": []},{"id": "595164358acba24e","type": "comment","z": "55793b5be2d1c883","name": "ONVIF Recover","info": "Sometimes ONVIF nodes delete themselves.\n\nHere's how to reinstall (from https://github.com/bartbutenaers/node-red-contrib-onvif-nodes/issues/25)\n\n1. Remove all hanging nodes in Node-Red UI, including config node\n2. In docker console, cd /data\n3. rm -rf node-red-contrib-obvif\n4. npm install node-red-contrib-onvif-nodes@0.0.1-beta.16\n\n(or the latest version from the releases page: https://github.com/bartbutenaers/node-red-contrib-onvif-nodes/releases)\n\nrestart Node-Red docker, then configure for ReoLink;\n\n1. Add back OnVif events node\n2. Configure new device 'Doorbe;;' with the following credentials;\n\nIP: 192.168.1.135\nPort: 8000\nUser: nodered\nPass: surveilanceCMX1984\n\n3. Set the action to 'Start Listeniong'","x": 1340,"y": 40,"wires": []},{"id": "545ec2db2f160340","type": "onvif-events","z": "55793b5be2d1c883","name": "","deviceConfig": "9ec64a314a5218b8","action": "start","x": 590,"y": 100,"wires": [["b8a6fb75.d6bc28"]]},{"id": "b9d166b16d287937","type": "alexa-remote-account","name": "","authMethod": "proxy","proxyOwnIp": "192.168.1.199","proxyPort": "4567","cookieFile": "/usr/cookie.txt","refreshInterval": "3","alexaServiceHost": "alexa.amazon.co.uk","pushDispatchHost": "","amazonPage": "amazon.co.uk","acceptLanguage": "en-UK","onKeywordInLanguage": "on","userAgent": "","autoInit": "on"},{"id": "9ec64a314a5218b8","type": "onvif-config","xaddress": "192.168.1.135","port": "8000","timeout": "10","checkConnectionInterval": "5","name": "Doorbell"}]
No comments:
Post a Comment