Hey,
I’ve been wondering for a long time how to download the image taken by my crappy video intercom (it’s one of the worst things I bought that was supposed to be smart). I found an option to capture a message containing a picture. It’s the same photo that’s in the official Tuya app. I used Node-RED installed in HA for this, because you can simulate messages and debug the whole process accurately.
In Node-RED I used this plugin ( node-red-contrib-tuya-smart-device (node) - Node-RED ) In Node-RED you can install it by clicking on Settings → Palette → Install → and search for “node-red-contrib-tuya-smart-device”
Import the code that is below:
[{"id":"0f190a2bca60a4be","type":"tuya-smart-device","z":"8ad639860cb6690f","deviceName":"Dorbell parter","disableAutoStart":false,"deviceId":"","deviceKey":"","storeAsCreds":false,"deviceIp":"10.0.1.50","retryTimeout":1000,"findTimeout":10000,"tuyaVersion":"3.3","eventMode":"event-both","credentials":{"secretConfig":"{}"},"x":340,"y":480,"wires":[["5afadc8ea527fdf3","8938329798814a30"],[]]},{"id":"5afadc8ea527fdf3","type":"function","z":"8ad639860cb6690f","name":"Add timestamp to LOG","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\nvar time = yyyy + \"-\" + mm + \"-\" + dd + \" \" + hh + \":\" + mmm + \":\" + ss;\n\nmsg.payload = { Time: time, Message: msg.payload }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":480,"wires":[["a25ea003dfe40c1b"]]},{"id":"a25ea003dfe40c1b","type":"file","z":"8ad639860cb6690f","name":"Save all commands send by dorbell in /share/logs/parter.log","filename":"/share/logs/parter.log","filenameType":"str","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"none","x":960,"y":480,"wires":[[]]},{"id":"1286683668fb701f","type":"base64","z":"8ad639860cb6690f","name":"Decode base64 adress","action":"b64","property":"payload","x":1030,"y":560,"wires":[["0b9c9d503cf1a34a"]]},{"id":"710cf8f19245a997","type":"inject","z":"8ad639860cb6690f","name":"Fake message","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"data\":{\"dps\":{\"154\":\"aHR0cHM6Ly9yZWdpb3dlYmNhbS5kZS9maWxlYWRtaW4vdXNlcl91cGxvYWQvMDFfc3RvcmNoX2tpcmNoemFydGVuMjAyMS5qcGc/dmVyPTE2MzkzMDIyNjYzNDk=\"},\"t\":1664969089},\"deviceId\":\"bfd52cb7f15a171ef3qznk\",\"deviceName\":\"Dorbell pietro\"}","payloadType":"json","x":360,"y":560,"wires":[["8938329798814a30"]]},{"id":"8938329798814a30","type":"switch","z":"8ad639860cb6690f","name":"If contains picture","property":"payload.data.dps","propertyType":"msg","rules":[{"t":"hask","v":"154","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":570,"y":560,"wires":[["49ff43949c4ef580"],[]]},{"id":"49ff43949c4ef580","type":"change","z":"8ad639860cb6690f","name":"Extract base64 adress","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.data.dps[\"154\"]","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":800,"y":560,"wires":[["1286683668fb701f"]]},{"id":"45dc7a80ee0db931","type":"file","z":"8ad639860cb6690f","name":"Write file","filename":"filename","filenameType":"msg","appendNewline":true,"createDir":false,"overwriteFile":"true","encoding":"none","x":840,"y":640,"wires":[["74cae47ba499b0ac"]]},{"id":"b5a8447904c662d5","type":"function","z":"8ad639860cb6690f","name":"Set file name","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// file path with / at the end\nvar path = \"/media/Parter/\"; // This is the path\nvar fileName = \"Dorbell_Parter_\" + yyyy + \"_\" + mm + \"_\" + dd + \"-\" + hh + \"_\" + mmm + \"_\" + ss + \".jpg\"; // file name\nvar pathWithLocal = \"/media/local/Parter/\" // Need to add /local/ to path for notify\n//node.warn(now);\n//msg.filename = `/share/logs/test.jpg`\n\nmsg.filename = path + fileName;\nmsg.filename2 = pathWithLocal + fileName;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":640,"wires":[["45dc7a80ee0db931"]]},{"id":"8049a89b539eb455","type":"http request","z":"8ad639860cb6690f","name":"HTTP request","method":"use","ret":"bin","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":520,"y":640,"wires":[["b5a8447904c662d5"]]},{"id":"0b9c9d503cf1a34a","type":"change","z":"8ad639860cb6690f","name":"Payload to URL","rules":[{"t":"set","p":"url","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"method","pt":"msg","to":"get","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":640,"wires":[["8049a89b539eb455"]]},{"id":"7642b2b6835a4e61","type":"tuya-smart-device","z":"8ad639860cb6690f","deviceName":"Dorbell pietro","disableAutoStart":false,"deviceId":"","deviceKey":"","storeAsCreds":false,"deviceIp":"10.0.1.51","retryTimeout":1000,"findTimeout":10000,"tuyaVersion":"3.3","eventMode":"event-both","credentials":{"secretConfig":"{}"},"x":350,"y":820,"wires":[["7b321904fe0af295","27138d1448befa47"],[]]},{"id":"cc076642764c123e","type":"file","z":"8ad639860cb6690f","name":"Save all commands send by dorbell in /share/logs/pietro.log","filename":"/share/logs/pietro.log","filenameType":"str","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"none","x":960,"y":820,"wires":[[]]},{"id":"7b321904fe0af295","type":"function","z":"8ad639860cb6690f","name":"Add timestamp to LOG","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\nvar time = yyyy + \"-\" + mm + \"-\" + dd + \" \" + hh + \":\" + mmm + \":\" + ss;\n\nmsg.payload = { Time: time, Message: msg.payload }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":820,"wires":[["cc076642764c123e"]]},{"id":"43a86da92e358c4d","type":"base64","z":"8ad639860cb6690f","name":"Decode base64 adress","action":"b64","property":"payload","x":1030,"y":900,"wires":[["ce17f74d19a20be1"]]},{"id":"931fd56e0ecdcad9","type":"inject","z":"8ad639860cb6690f","name":"Fake message","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"data\":{\"dps\":{\"154\":\"aHR0cHM6Ly9yZWdpb3dlYmNhbS5kZS9maWxlYWRtaW4vdXNlcl91cGxvYWQvMDFfc3RvcmNoX2tpcmNoemFydGVuMjAyMS5qcGc/dmVyPTE2MzkzMDIyNjYzNDk=\"},\"t\":1664969089},\"deviceId\":\"bfd52cb7f15a171ef3qznk\",\"deviceName\":\"Dorbell pietro\"}","payloadType":"json","x":360,"y":900,"wires":[["27138d1448befa47"]]},{"id":"27138d1448befa47","type":"switch","z":"8ad639860cb6690f","name":"If contains picture","property":"payload.data.dps","propertyType":"msg","rules":[{"t":"hask","v":"154","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":570,"y":900,"wires":[["1e7bc8ea60e2b55c"],[]]},{"id":"1e7bc8ea60e2b55c","type":"change","z":"8ad639860cb6690f","name":"Extract base64 adress","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.data.dps[\"154\"]","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":800,"y":900,"wires":[["43a86da92e358c4d"]]},{"id":"e372f3b41528dc38","type":"file","z":"8ad639860cb6690f","name":"Write file","filename":"filename","filenameType":"msg","appendNewline":true,"createDir":false,"overwriteFile":"true","encoding":"none","x":840,"y":980,"wires":[["2262904dd9aedfef"]]},{"id":"c8ca7efa2c8f033c","type":"function","z":"8ad639860cb6690f","name":"Set file name","func":"var now = new Date();\n// Create formatted time\nvar yyyy = now.getFullYear();\nvar mm = now.getMonth() < 9 ? \"0\" + (now.getMonth() + 1) : (now.getMonth() + 1); // getMonth() is zero-based\nvar dd = now.getDate() < 10 ? \"0\" + now.getDate() : now.getDate();\nvar hh = now.getHours() < 10 ? \"0\" + now.getHours() : now.getHours();\nvar mmm = now.getMinutes() < 10 ? \"0\" + now.getMinutes() : now.getMinutes();\nvar ss = now.getSeconds() < 10 ? \"0\" + now.getSeconds() : now.getSeconds();\n\n// file path with / at the end\nvar path = \"/media/Pietro/\"; // This is the path\nvar fileName = \"Dorbell_Pietro_\" + yyyy + \"_\" + mm + \"_\" + dd + \"-\" + hh + \"_\" + mmm + \"_\" + ss + \".jpg\"; // file name\nvar pathWithLocal = \"/media/local/Pietro/\" // Need to add /local/ to path for notify\n\nmsg.filename = path + fileName;\nmsg.filename2 = pathWithLocal + fileName;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":980,"wires":[["e372f3b41528dc38"]]},{"id":"ca1df8d17e7e2c27","type":"http request","z":"8ad639860cb6690f","name":"HTTP request","method":"use","ret":"bin","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":520,"y":980,"wires":[["c8ca7efa2c8f033c"]]},{"id":"ce17f74d19a20be1","type":"change","z":"8ad639860cb6690f","name":"Payload to URL","rules":[{"t":"set","p":"url","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"method","pt":"msg","to":"get","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":980,"wires":[["ca1df8d17e7e2c27"]]},{"id":"252fe9520b79ef56","type":"api-call-service","z":"8ad639860cb6690f","name":"Notify","server":"32589209.0c3ffe","version":5,"debugenabled":true,"domain":"notify","service":"mobile_app_telefonadrian","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1290,"y":640,"wires":[[]]},{"id":"74cae47ba499b0ac","type":"delay","z":"8ad639860cb6690f","name":"Delay 1s","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":640,"wires":[["05fa85fd24f29686"]]},{"id":"05fa85fd24f29686","type":"function","z":"8ad639860cb6690f","name":"Build message","func":"msg.payload =\n{\n \"data\":\n {\n \"title\": \"Ktoś dzwoni!\",\n \"message\": \"Ktoś dobija się do domu! (zjęcie z parteru)\",\n \"data\":\n {\n \"ttl\": 0,\n \"priority\": \"high\",\n \"icon_url\": msg.filename2,\n \"color\": \"green\",\n \"image\": msg.filename2,\n \"sticky\": \"true\",\n }\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1140,"y":640,"wires":[["252fe9520b79ef56","f4c7478e2a586590"]]},{"id":"2be6e90b7f5673df","type":"api-call-service","z":"8ad639860cb6690f","name":"Notify","server":"32589209.0c3ffe","version":5,"debugenabled":true,"domain":"notify","service":"mobile_app_telefonadrian","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1290,"y":980,"wires":[[]]},{"id":"2262904dd9aedfef","type":"delay","z":"8ad639860cb6690f","name":"Delay 1s","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":980,"wires":[["56aed77283525840"]]},{"id":"56aed77283525840","type":"function","z":"8ad639860cb6690f","name":"Build message","func":"msg.payload =\n{\n \"data\":\n {\n \"title\": \"Ktoś dzwoni!\",\n \"message\": \"Ktoś dobija się do domu! (zjęcie z piętra)\",\n \"data\":\n {\n \"ttl\": 0,\n \"priority\": \"high\",\n \"icon_url\": msg.filename2,\n \"color\": \"green\",\n \"image\": msg.filename2,\n \"sticky\": \"true\",\n }\n }\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1140,"y":980,"wires":[["2be6e90b7f5673df","23a73e15a77f75ab"]]},{"id":"f4c7478e2a586590","type":"api-call-service","z":"8ad639860cb6690f","name":"Notify","server":"32589209.0c3ffe","version":5,"debugenabled":true,"domain":"notify","service":"mobile_app_sm_a505fn","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1290,"y":700,"wires":[[]]},{"id":"23a73e15a77f75ab","type":"api-call-service","z":"8ad639860cb6690f","name":"Notify","server":"32589209.0c3ffe","version":5,"debugenabled":true,"domain":"notify","service":"mobile_app_sm_a505fn","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"jsonata","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1290,"y":1040,"wires":[[]]},{"id":"32589209.0c3ffe","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"}]
It contains the process of saving all the messages sent by each device (I have two monitors so I created two copies). In addition, the pictures are saved in a folder. And at the very end a notification is sent to the phone.
In order for everything to work you need to enter “Device Virtual ID”, " Device Key" and “IP adress”.
You can easily check the Device Virtual ID in TuyaIOT.
Device Key is also in TuyaIOT but is a little harder to get. You need to go to “Api Explorer” on the TuyaIOT website and search for “Get Device Information”. It should be under “General Device Capabilities” → “General device management” → “Get Device Information”.
Now you need to paste the “Device ID” there and press Submit Request. If your device responds you should get the device information, and in the ““local_key”:” line is your Device Key.
I spent a few hours on it but for about two months now everything has been working properly.
