IP Camera and Home Hub integration
This flow shows how you can display IP camera image on a Google Home Hub display. I am using https://flows.nodered.org/node/node-red-contrib-castv2 to cast images to my Home Hub. I am getting the image from a Reolink IP camera that returns a still image when I call a simple HTTP URL. I use this flow so my Home Hub says "There is someone at the door" and after shows the picture of the front door when somebody rings my doorbell. You can find more information on this flow in this video: https://youtu.be/_zLfUPf04cA
Also read the comment nodes in the flow, I put more details there.
[{"id":"b425e75.0dade18","type":"function","z":"daafb700.230458","name":"create image message","func":"msg.payload = {chatId: \"xxxxxx\", type:\"photo\", content:\"/home/pi/node-red-static/gate.jpg\", caption:\"Picture from the front camera\"};\nreturn msg;","outputs":1,"noerr":0,"x":960,"y":1520,"wires":[[]]},{"id":"fdb26f8.573cf9","type":"http request","z":"daafb700.230458","name":"Reolink image","method":"GET","ret":"bin","paytoqs":false,"url":"http://192.168.1.xx/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=<your_UID>&user=<your_username>&password=<your_pasword>","tls":"","persist":false,"proxy":"","authType":"basic","x":420,"y":1540,"wires":[["90a59928.e92228"]]},{"id":"90a59928.e92228","type":"file","z":"daafb700.230458","name":"Save image","filename":"/home/pi/node-red-static/gate.jpg","appendNewline":true,"createDir":false,"overwriteFile":"true","encoding":"none","x":590,"y":1540,"wires":[["22ea72eb.f081ce","b425e75.0dade18"]]},{"id":"5f4bfd81.0acf84","type":"inject","z":"daafb700.230458","name":"Test","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":1420,"wires":[["fdb26f8.573cf9","c763074b.24ae38"]]},{"id":"bbac00e8.c85b4","type":"castv2-sender","z":"daafb700.230458","name":"Google Home Hub","host":"192.168.1.185","x":810,"y":1780,"wires":[["9886e7b3.ef9108","e21d5bc6.d88ca8"]]},{"id":"faeecc3c.17974","type":"function","z":"daafb700.230458","name":"Image message","func":"msg = \n{\n host: \"192.168.1.185\",\n payload: {\n type: \"MEDIA\",\n media: {\n url: \"http://192.168.1.90:5000/MyWeb/web/\"+ msg.payload,\n title: \"Front Gate\", // optional unless desired\n }\n }\n};\n\n\nreturn msg;\n\n// url: \"http://192.168.1.90:5000/MyWeb/web/gate.jpg\",","outputs":1,"noerr":0,"x":600,"y":1780,"wires":[["bbac00e8.c85b4"]]},{"id":"9886e7b3.ef9108","type":"debug","z":"daafb700.230458","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1050,"y":1780,"wires":[]},{"id":"99c6e9f7.c41fe8","type":"delay","z":"daafb700.230458","name":"","pauseType":"delay","timeout":"7","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":400,"y":1780,"wires":[["faeecc3c.17974"]]},{"id":"e21d5bc6.d88ca8","type":"delay","z":"daafb700.230458","name":"","pauseType":"delay","timeout":"30","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":400,"y":1900,"wires":[["9667fbdb.e28078"]]},{"id":"9667fbdb.e28078","type":"function","z":"daafb700.230458","name":"Close image","func":"msg = \n{\n host: \"192.168.1.185\",\n payload: {\n type: \"CLOSE\",\n }\n};\n\n\nreturn msg;\n","outputs":1,"noerr":0,"x":590,"y":1900,"wires":[["f472c500.1c4b38"]]},{"id":"f472c500.1c4b38","type":"castv2-sender","z":"daafb700.230458","name":"Google Home Hub","host":"192.168.1.185","x":810,"y":1900,"wires":[[]]},{"id":"c763074b.24ae38","type":"function","z":"daafb700.230458","name":"TTS message","func":"msg = \n{\n host: \"192.168.1.185\",\n payload: {\n type: \"TTS\",\n text: \"There is someone at the door\",\n speed: 1, // optional to adjust TTS speed, defaults to 1\n language: \"en\", // optional to set TTS language, default to en\n title: \"Front gate\", // optional unless desired\n }\n}\n\n\nreturn msg;\n\n","outputs":1,"noerr":0,"x":420,"y":1440,"wires":[["16e5904c.d1b1e"]]},{"id":"16e5904c.d1b1e","type":"castv2-sender","z":"daafb700.230458","name":"Google Home Hub","host":"192.168.1.185","x":630,"y":1440,"wires":[[]]},{"id":"41867f20.bf7b4","type":"exec","z":"daafb700.230458","command":"/home/pi/pic_upload.sh","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Upload to NAS","x":1260,"y":1580,"wires":[[],[],[]]},{"id":"22ea72eb.f081ce","type":"function","z":"daafb700.230458","name":"Random filename","func":"// this function generates a randomized file name as gate_YYYYMMDDHHMMSS.jpg\nvar now = new Date();\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();\nnode.status({fill:\"blue\",shape:\"ring\",text:\"Date: \"+dd + \".\" + mm + \".\" + yyyy + \" \" + hh + \":\" + mmm + \":\" + ss});\n\nmsg.payload = \"gate_\"+yyyy+mm+dd+hh+mm+ss+\".jpg\";\n\nreturn msg;","outputs":1,"noerr":0,"x":870,"y":1600,"wires":[["41867f20.bf7b4","99c6e9f7.c41fe8","417d0138.b603a"]]},{"id":"7ab92bc7.eb0ba4","type":"comment","z":"daafb700.230458","name":"Voice announcement","info":"","x":410,"y":1400,"wires":[]},{"id":"d7a4bd82.426ea","type":"comment","z":"daafb700.230458","name":"Capture the image from IP camera","info":"For Reolink cameras (excluding battery operated cameras) the URL is described here:\nhttps://support.reolink.com/hc/en-us/articles/360007011233-How-to-Capture-Live-JPEG-Image-of-Reolink-Cameras-via-Web-Browsers\n\nSame concept will work with any other IP cameras that return a jpg image.\n\nThe file-out node saves the image to a fixed file name. node-red-static folder is set in my\nsettings.js, so any file in that folder can be accessed as:\nhttp(s)://192.168.1.x:1880/gate.jpg","x":460,"y":1500,"wires":[]},{"id":"147f0197.30766e","type":"comment","z":"daafb700.230458","name":"Optional Telegram image message","info":"Output of this function node should go to the the Telegram sender node","x":1000,"y":1480,"wires":[]},{"id":"5e49ab46.617094","type":"comment","z":"daafb700.230458","name":"Please read the comment nodes for futher documentation","info":"","x":270,"y":1360,"wires":[]},{"id":"3edd3b64.e8da74","type":"comment","z":"daafb700.230458","name":"Upload file to NAS","info":"My PI has a self-signed certificate and Home Hub was not able to load the image from there. So I copy the image to my NAS which also has its own webserver that I can point to Home Hub\n\n\nThis is my pic_upload.sh file:\nftp -inv 192.168.1.x << EOF\n user <username> <password>\n binary\n cd web\n lcd /home/pi/node-red-static\n put grab.jpg\n put gate.jpg $1\nEOF","x":1250,"y":1540,"wires":[]},{"id":"417d0138.b603a","type":"exec","z":"daafb700.230458","command":"cp /home/pi/node-red-static/gate.jpg","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Rename file","x":1250,"y":1680,"wires":[[],[],[]]},{"id":"32b8b4ce.985a3c","type":"comment","z":"daafb700.230458","name":"Copy to a new file","info":"If your PI has no self-signed certificate (or plain http), you can just copy it to a unique filename to make sure Home Hub always reads the image (otherwise it caches the image with the same file name)","x":1250,"y":1640,"wires":[]},{"id":"f3089c0c.c76a2","type":"comment","z":"daafb700.230458","name":"Display image on the Home Hub","info":"Set the delay to a time it takes for the NAS upload or the file copy to complete\nAlso adjust the URL in the function node to point to the correct URL\nCheck the debug node to see errors returned by Home Hub","x":510,"y":1720,"wires":[]},{"id":"48e0d055.f66a2","type":"comment","z":"daafb700.230458","name":"Return to the default screen","info":"Go back to the default screen (image rotator) after some time","x":500,"y":1840,"wires":[]}]