|
[{"id":"41819097.56452","type":"debug","z":"46839377.4d6c0c","name":"","active":false,"console":"false","complete":"true","x":470,"y":420,"wires":[]},{"id":"62a080b1.65f88","type":"http in","z":"46839377.4d6c0c","name":"","url":"/google/home","method":"post","swaggerDoc":"","x":290,"y":460,"wires":[["41819097.56452","97181f8b.08539"]]},{"id":"fd3b0cd7.2f07a","type":"switch","z":"46839377.4d6c0c","name":"Sort by Intent Type","property":"payload.inputs[0].intent","propertyType":"msg","rules":[{"t":"eq","v":"action.devices.SYNC","vt":"str"},{"t":"eq","v":"action.devices.QUERY","vt":"str"},{"t":"eq","v":"action.devices.EXECUTE","vt":"str"},{"t":"else"}],"checkall":"false","outputs":4,"x":790,"y":600,"wires":[["48964de7.af0da4"],["be74c96a.f70178"],["8c5e6842.b912a8"],["4b28322c.99bb2c"]]},{"id":"8f49fcb9.99dbd","type":"switch","z":"46839377.4d6c0c","name":"Check inputs","property":"payload.inputs","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","outputs":2,"x":570,"y":540,"wires":[["6258647e.516dac"],["fd3b0cd7.2f07a"]]},{"id":"6258647e.516dac","type":"function","z":"46839377.4d6c0c","name":"Error: Missing Inputs","func":"msg.statusCode = 400;\nmsg.payload = { \n requestId: msg.req.body.requestId,\n payload: {\n errorCode: \"protocolError\"\n }\n};\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":500,"wires":[["1ec86c58.938694"]]},{"id":"1ec86c58.938694","type":"link out","z":"46839377.4d6c0c","name":"","links":["dfa15993.ece3d8","c7959523.ec2808"],"x":1255,"y":500,"wires":[]},{"id":"8c5e6842.b912a8","type":"function","z":"46839377.4d6c0c","name":"action.devices.EXECUTE","func":"msg.requestId = msg.payload.requestId;\nmsg.payload = msg.payload.inputs[0].payload;\n\nreturn msg;","outputs":"1","noerr":0,"x":1070,"y":620,"wires":[["1332d581.826c8a"]]},{"id":"13f2f440.702bfc","type":"inject","z":"46839377.4d6c0c","name":"Test","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":90,"y":760,"wires":[["d1b5a190.3d73a"]]},{"id":"d1b5a190.3d73a","type":"function","z":"46839377.4d6c0c","name":"Inject test payload","func":"return {\n requestId: \"ff36a3cc-ec34-11e6-b1a0-64510650abcf\",\n payload: {\n \"commands\": [{\n \"devices\": [{\n \"id\": \"zway/familyRoom/familyRoomLight\",\n \"customData\": {\n \"fooValue\": 74,\n \"barValue\": false\n }\n }, {\n \"id\": \"zway/kitchen/kitchenLight\",\n \"customData\": {\n \"fooValue\": 12,\n \"barValue\": true\n }\n }, {\n \"id\": \"zway/diningRoom/diningRoomLight\",\n \"customData\": {\n \"fooValue\": 35,\n \"barValue\": false,\n \"bazValue\": \"sheep dip\"\n }\n }],\n \"execution\": [{\n \"command\": \"action.devices.commands.OnOff\",\n \"params\": {\n \"on\": true\n }\n }]\n }]\n }\n};","outputs":1,"noerr":0,"x":270,"y":760,"wires":[["492089c0.bf8898"]]},{"id":"cd98ce34.d79af","type":"link in","z":"46839377.4d6c0c","name":"Google Home EXECUTE","links":["1332d581.826c8a"],"x":55,"y":820,"wires":[["492089c0.bf8898"]]},{"id":"7b107473.9f68fc","type":"comment","z":"46839377.4d6c0c","name":"Process Google Home EXECUTE","info":"","x":180,"y":720,"wires":[]},{"id":"38ef9781.fbddd8","type":"comment","z":"46839377.4d6c0c","name":"Google Home Endpoint","info":"","x":140,"y":420,"wires":[]},{"id":"5d0362f3.f667bc","type":"http response","z":"46839377.4d6c0c","name":"","x":330,"y":940,"wires":[]},{"id":"938b6a26.1045a8","type":"function","z":"46839377.4d6c0c","name":"Add Headers","func":"msg.headers = {\n 'Access-Control-Allow-Origin': '*',\n 'Access-Control-Allow-Headers': 'Content-Type, Authorization'\n};\nreturn msg;","outputs":1,"noerr":0,"x":170,"y":940,"wires":[["5d0362f3.f667bc","17093049.5a43b"]]},{"id":"c7959523.ec2808","type":"link in","z":"46839377.4d6c0c","name":"Google Home Smart Home Response","links":["1ec86c58.938694","8601c640.0382d8"],"x":55,"y":940,"wires":[["938b6a26.1045a8"]]},{"id":"bdb53516.9356f8","type":"comment","z":"46839377.4d6c0c","name":"Google Home Response","info":"","x":150,"y":900,"wires":[]},{"id":"1332d581.826c8a","type":"link out","z":"46839377.4d6c0c","name":"","links":["cd98ce34.d79af"],"x":1255,"y":620,"wires":[]},{"id":"23fc38ec.a0e948","type":"link out","z":"46839377.4d6c0c","name":"","links":["dfa15993.ece3d8","c7959523.ec2808"],"x":1255,"y":540,"wires":[]},{"id":"2cead14a.b0da7e","type":"link out","z":"46839377.4d6c0c","name":"","links":["dfa15993.ece3d8","c7959523.ec2808"],"x":1255,"y":580,"wires":[]},{"id":"4b28322c.99bb2c","type":"function","z":"46839377.4d6c0c","name":"Error: Unknown intent","func":"msg.statusCode = 400;\nmsg.payload = { \n requestId: msg.req.body.requestId,\n payload: {\n errorCode: \"protocolError\"\n }\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":660,"wires":[["5955a067.309f1"]]},{"id":"5955a067.309f1","type":"link out","z":"46839377.4d6c0c","name":"","links":["dfa15993.ece3d8","c7959523.ec2808"],"x":1255,"y":660,"wires":[]},{"id":"17093049.5a43b","type":"debug","z":"46839377.4d6c0c","name":"","active":false,"console":"false","complete":"true","x":330,"y":980,"wires":[]},{"id":"8601c640.0382d8","type":"link out","z":"46839377.4d6c0c","name":"","links":["c7959523.ec2808"],"x":1135,"y":800,"wires":[]},{"id":"469336eb.5eb988","type":"comment","z":"46839377.4d6c0c","name":"Google Device States","info":"","x":140,"y":100,"wires":[]},{"id":"e83f150b.b81c08","type":"inject","z":"46839377.4d6c0c","name":"Print","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":90,"y":180,"wires":[["a93049d8.fb24f8"]]},{"id":"a93049d8.fb24f8","type":"function","z":"46839377.4d6c0c","name":"Get current device state","func":"let devices = flow.get(\"googleDevices\") || {};\n\nif (devices[\"undefined\"])\n delete devices[\"undefined\"];\n\nreturn { payload: devices };","outputs":1,"noerr":0,"x":290,"y":180,"wires":[["632a92a4.31c5ec"]]},{"id":"632a92a4.31c5ec","type":"debug","z":"46839377.4d6c0c","name":"","active":true,"console":"false","complete":"false","x":1030,"y":180,"wires":[]},{"id":"e538faf8.ed4f68","type":"inject","z":"46839377.4d6c0c","name":"SYNC","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":90,"y":500,"wires":[["b40cf88e.440898"]]},{"id":"5ed8eade.6f5d94","type":"inject","z":"46839377.4d6c0c","name":"QUERY","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":90,"y":540,"wires":[["267c6952.970496"]]},{"id":"99692839.a4f958","type":"inject","z":"46839377.4d6c0c","name":"EXECUTE","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":100,"y":580,"wires":[["a65b8270.08bbe"]]},{"id":"b40cf88e.440898","type":"function","z":"46839377.4d6c0c","name":"Inject test payload","func":"return {\n payload: {\n \"requestId\": \"ff36a3cc-ec34-11e6-b1a0-64510650abcf\",\n \"inputs\": [{\n \"intent\": \"action.devices.SYNC\",\n }]\n }\n};","outputs":1,"noerr":0,"x":290,"y":500,"wires":[["8f49fcb9.99dbd"]]},{"id":"267c6952.970496","type":"function","z":"46839377.4d6c0c","name":"Inject test payload","func":"return {\n payload: {\n \"requestId\": \"ff36a3cc-ec34-11e6-b1a0-64510650abcf\",\n \"inputs\": [{\n \"intent\": \"action.devices.QUERY\",\n \"payload\": {\n \"devices\": [{\n \"id\": \"zway/familyRoom/familyRoomLight\",\n \"customData\": {\n \"fooValue\": 12,\n \"barValue\": true,\n \"bazValue\": \"alpaca sauce\"\n }\n }, {\n \"id\": \"zway/kitchen/kitchenLight\",\n \"customData\": {\n \"fooValue\": 74,\n \"barValue\": false,\n \"bazValue\": \"sheep dip\"\n }\n }]\n }\n }]\n }\n};","outputs":1,"noerr":0,"x":290,"y":540,"wires":[["8f49fcb9.99dbd"]]},{"id":"a65b8270.08bbe","type":"function","z":"46839377.4d6c0c","name":"Inject test payload","func":"return {\n payload: {\n \"requestId\": \"ff36a3cc-ec34-11e6-b1a0-64510650abcf\",\n \"uid\": \"213456\",\n \"auth\": \"bearer xxx\",\n \"inputs\": [{\n \"intent\": \"action.devices.EXECUTE\",\n \"payload\": {\n \"commands\": [{\n \"devices\": [{\n \"id\": \"zway/familyRoom/familyRoomLight\",\n \"customData\": {\n \"fooValue\": 74,\n \"barValue\": false\n }\n }, {\n \"id\": \"zway/kitchen/kitchenLight\",\n \"customData\": {\n \"fooValue\": 12,\n \"barValue\": true\n }\n }, {\n \"id\": \"zway/diningRoom/diningRoomLight\",\n \"customData\": {\n \"fooValue\": 35,\n \"barValue\": false,\n \"bazValue\": \"sheep dip\"\n }\n }],\n \"execution\": [{\n \"command\": \"action.devices.commands.OnOff\",\n \"params\": {\n \"on\": true\n }\n }]\n }]\n }\n }]\n }\n};","outputs":1,"noerr":0,"x":290,"y":580,"wires":[["8f49fcb9.99dbd"]]},{"id":"1a651aa0.0bf6a5","type":"inject","z":"46839377.4d6c0c","name":"Reset","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":90,"y":140,"wires":[["63ea1dc5.939784"]]},{"id":"63ea1dc5.939784","type":"function","z":"46839377.4d6c0c","name":"Reset current device state","func":"let devices = flow.get(\"googleDevices\") || {};\nflow.set(\"googleDevices\", {});\nreturn { payload: devices };","outputs":1,"noerr":0,"x":290,"y":140,"wires":[[]]},{"id":"b3799825.8b6e48","type":"http request","z":"46839377.4d6c0c","name":"REQUEST_SYNC ","method":"POST","ret":"obj","url":"","tls":"","x":630,"y":360,"wires":[["f6c424d2.e72a08"]]},{"id":"f6c424d2.e72a08","type":"debug","z":"46839377.4d6c0c","name":"","active":false,"console":"false","complete":"true","x":1010,"y":360,"wires":[]},{"id":"97181f8b.08539","type":"function","z":"46839377.4d6c0c","name":"Get bearer token","func":"let accessTokenStore = global.get(\"googleAccessTokenStore\") || {};\nlet accessTokenId = msg.req.headers.authorization ? msg.req.headers.authorization.split(' ')[1] : null;\nlet accessToken = accessTokenStore[accessTokenId];\n\nif (accessToken !== undefined) {\n if (new Date(accessToken.expiresAt) < Date.now()) {\n delete accessTokenStore[accessTokenId];\n msg.accessToken = \"EXPIRED\";\n } else {\n msg.accessToken = accessToken;\n }\n} else {\n msg.accessToken = null;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":510,"y":460,"wires":[["9faf29d2.cc8468"]]},{"id":"9faf29d2.cc8468","type":"switch","z":"46839377.4d6c0c","name":"Check bearer token","property":"accessToken","propertyType":"msg","rules":[{"t":"null"},{"t":"eq","v":"EXPIRED","vt":"str"},{"t":"else"}],"checkall":"false","outputs":3,"x":740,"y":460,"wires":[["cd90e7eb.b1a048"],["729ff13d.024c2"],["8f49fcb9.99dbd"]]},{"id":"cd90e7eb.b1a048","type":"function","z":"46839377.4d6c0c","name":"Error: Bearer token incorrect","func":"msg.statusCode = 401;\nmsg.payload = { \n requestId: msg.req.body.requestId,\n payload: {\n errorCode: \"authFailure\"\n }\n};\nreturn msg;","outputs":1,"noerr":0,"x":1080,"y":420,"wires":[["741ac462.48099c"]]},{"id":"729ff13d.024c2","type":"function","z":"46839377.4d6c0c","name":"Error: Bearer token expired","func":"msg.statusCode = 401;\nmsg.payload = { \n requestId: msg.req.body.requestId,\n payload: {\n errorCode: \"authExpired\"\n }\n};\nreturn msg;","outputs":1,"noerr":0,"x":1080,"y":460,"wires":[["1306ca8f.11a835"]]},{"id":"1306ca8f.11a835","type":"link out","z":"46839377.4d6c0c","name":"","links":["dfa15993.ece3d8","c7959523.ec2808"],"x":1255,"y":460,"wires":[]},{"id":"741ac462.48099c","type":"link out","z":"46839377.4d6c0c","name":"","links":["dfa15993.ece3d8","c7959523.ec2808"],"x":1255,"y":420,"wires":[]},{"id":"109b127e.38625e","type":"inject","z":"46839377.4d6c0c","name":"On Startup","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"x":110,"y":220,"wires":[["6b16ca61.a48174","679a40cc.51a2a"]]},{"id":"a90446b0.5cf458","type":"function","z":"46839377.4d6c0c","name":"Build request","func":"let agentUserId = flow.get(\"agentUserId\");\nlet homeGraphApiKey = flow.get(\"homeGraphApiKey\");\n\nmsg.url = 'https://homegraph.googleapis.com/v1/devices:requestSync?key=' + homeGraphApiKey;\nmsg.headers = {\n 'Content-Type': 'application/json'\n};\n\nmsg.payload = {\n 'agent_user_id': agentUserId\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":430,"y":360,"wires":[["b3799825.8b6e48"]]},{"id":"825f14df.c0cd28","type":"inject","z":"46839377.4d6c0c","name":"Trigger Google REQUEST_SYNC","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":180,"y":360,"wires":[["a90446b0.5cf458"]]},{"id":"487515ef.bfa52c","type":"comment","z":"46839377.4d6c0c","name":"Google Device Sync Request","info":"","x":160,"y":320,"wires":[]},{"id":"6b16ca61.a48174","type":"credentials","z":"46839377.4d6c0c","name":"","props":[{"value":"agentUserId","type":"flow"},{"value":"homeGraphApiKey","type":"flow"}],"x":290,"y":220,"wires":[[]]},{"id":"48964de7.af0da4","type":"function","z":"46839377.4d6c0c","name":"action.devices.SYNC","func":"let allDevices = flow.get(\"googleDevices\");\nlet devices = [];\nfor (let device in allDevices) {\n var traits = allDevices[device].traits.map(x => x.trait);\n devices.push(Object.assign({}, allDevices[device], { traits: traits }));\n}\n\nlet requestId = msg.payload.requestId;\nlet agentUserId = flow.get(\"agentUserId\");\nmsg.payload = {\n requestId: requestId,\n payload: {\n agentUserId: agentUserId,\n devices: devices\n }\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":540,"wires":[["23fc38ec.a0e948"]]},{"id":"be74c96a.f70178","type":"function","z":"46839377.4d6c0c","name":"action.devices.QUERY","func":"let allDevices = flow.get(\"googleDevices\");\nlet deviceStates = global.get(\"deviceStates\");\nlet devices = {};\nfor (let device in msg.payload.inputs[0].payload.devices) {\n let deviceId = msg.payload.inputs[0].payload.devices[device].id;\n\n let queryDeviceBase = { \"online\": true, \"on\": true };\n \n let currentStates = [];\n for (let trait in allDevices[deviceId].traits) {\n let stateObj = JSON.parse(JSON.stringify(allDevices[deviceId].traits[trait].state));\n \n // Set states according to trait type definition\n switch (allDevices[deviceId].traits[trait].trait) {\n case \"action.devices.traits.OnOff\":\n // Translate on and off to true and false\n if (\"on\" in stateObj && stateObj[\"on\"] in deviceStates) {\n if (isNaN(deviceStates[stateObj[\"on\"]])) {\n stateObj[\"on\"] = deviceStates[stateObj[\"on\"]] === \"on\";\n } else {\n stateObj[\"on\"] = deviceStates[stateObj[\"on\"]] > 0;\n }\n }\n break;\n default:\n // Direct pass through of value\n for (let state in stateObj) {\n if (stateObj[state] in deviceStates) {\n stateObj[state] = deviceStates[stateObj[state]];\n }\n }\n break;\n }\n \n currentStates.push(stateObj);\n }\n \n devices[deviceId] = Object.assign({}, queryDeviceBase, ...currentStates);\n}\n\nlet requestId = msg.payload.requestId;\nmsg.payload = {\n requestId: requestId,\n payload: {\n devices: devices\n }\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":580,"wires":[["2cead14a.b0da7e"]]},{"id":"492089c0.bf8898","type":"function","z":"46839377.4d6c0c","name":"Split command and response","func":"return [ \n msg, \n msg.payload.commands.map(x => { \n return { \"payload\": x };\n })\n];","outputs":2,"noerr":0,"x":240,"y":820,"wires":[["26e176d0.96326a"],["786573c2.7fb3bc"]]},{"id":"26e176d0.96326a","type":"function","z":"46839377.4d6c0c","name":"Build response","func":"let defaultState = { on: true, online: true };\nlet commandResponses = msg.payload.commands.map(x => {\n let translatedParams = Object.assign({}, defaultState, x.execution.params);\n \n if (translatedParams[\"updateModeSettings\"]) {\n translatedParams[\"currentModeSettings\"] = translatedParams[\"updateModeSettings\"];\n delete translatedParams[\"updateModeSettings\"];\n }\n\n if (translatedParams[\"updateToggleSettings\"]) {\n translatedParams[\"currentToggleSettings\"] = translatedParams[\"updateToggleSettings\"];\n delete translatedParams[\"updateToggleSettings\"];\n }\n \n return {\n ids: x.devices.map(y => y.id),\n status: true ? \"SUCCESS\" : \"OFFLINE\",\n states: translatedParams\n };\n});\n\nmsg.payload = {\n requestId: msg.requestId,\n payload: {\n commands: commandResponses\n }\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":480,"y":800,"wires":[["8601c640.0382d8"]]},{"id":"786573c2.7fb3bc","type":"function","z":"46839377.4d6c0c","name":"Parse commands","func":"let commands = [];\nfor (let execution in msg.payload.execution) {\n for (let device in msg.payload.devices) {\n commands.push({\n topic: msg.payload.devices[device].id,\n payload: msg.payload.execution[execution]\n });\n }\n}\n\nreturn [ commands ];","outputs":1,"noerr":0,"x":490,"y":840,"wires":[["b6e1614b.b30d2"]]},{"id":"b6e1614b.b30d2","type":"function","z":"46839377.4d6c0c","name":"Generate MQTT messages","func":"let allDevices = flow.get(\"googleDevices\");\n\n// { topic: device id, payload: execution }\n\nlet commandMsgs = [];\nif (msg.topic in allDevices) {\n // Find traits matching the requested command\n let applicableTraits = allDevices[msg.topic].traits\n .filter(x => msg.payload.command in x.commands);\n\n // A device should have only one handler for a given command\n if (applicableTraits.length == 1) {\n let commandParamToMqttTopicMap = applicableTraits[0].commands[msg.payload.command];\n for (let param in msg.payload.params) {\n if (typeof msg.payload.params[param] === 'object') {\n let commandTopic = \"\";\n // Support one level drill down\n for (let subParam in msg.payload.params[param]) {\n commandMsgs.push({\n topic: commandParamToMqttTopicMap[param][subParam],\n payload: msg.payload.params[param][subParam]\n });\n }\n } else {\n // Set translate states according to trait type\n let payload = \"\";\n switch (applicableTraits[0].trait) {\n case \"action.devices.traits.OnOff\":\n // Translate true and false to on and off\n payload = msg.payload.params[param] === true ? \"on\" : \"off\";\n break;\n default:\n payload = msg.payload.params[param]\n break;\n }\n\n commandMsgs.push({\n topic: commandParamToMqttTopicMap[param],\n payload: payload\n });\n }\n }\n }\n}\n\nreturn [ commandMsgs] ;","outputs":1,"noerr":0,"x":740,"y":840,"wires":[["8d5ba57c.d5d658"]]},{"id":"d8212114.3d38e","type":"link out","z":"46839377.4d6c0c","name":"","links":["d0d9d6b7.697a88"],"x":1255,"y":960,"wires":[]},{"id":"679a40cc.51a2a","type":"file in","z":"46839377.4d6c0c","name":"Read file","filename":"/data/projects/HomeAutio/config/googleDevices.json","format":"utf8","sendError":true,"x":280,"y":260,"wires":[["42e373a7.84018c"]]},{"id":"42e373a7.84018c","type":"json","z":"46839377.4d6c0c","name":"","x":430,"y":260,"wires":[["56b3abb.7086554"]]},{"id":"56b3abb.7086554","type":"function","z":"46839377.4d6c0c","name":"Update googleDevices","func":"if (msg.payload !== null) {\n flow.set(\"googleDevices\", msg.payload);\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":260,"wires":[["fded4397.e7b94"]]},{"id":"fded4397.e7b94","type":"debug","z":"46839377.4d6c0c","name":"","active":false,"console":"false","complete":"true","x":1010,"y":260,"wires":[]},{"id":"8d5ba57c.d5d658","type":"switch","z":"46839377.4d6c0c","name":"Custom handlers","property":"topic","propertyType":"msg","rules":[{"t":"regex","v":"^denon.*$","vt":"str","case":false},{"t":"eq","v":"harmony/default/activity/set","vt":"str"},{"t":"eq","v":"harmony/bedroom/activity/set","vt":"str"},{"t":"regex","v":"^([\\w\\/]+)\\(([\\w\\s]+)\\)(\\/set)$","vt":"str","case":false},{"t":"else"}],"checkall":"false","repair":false,"outputs":5,"x":710,"y":960,"wires":[["664cb048.8e0d9"],["3e162284.55a47e"],["84d1695.bec2098"],["681570b7.b2ad8"],["12541066.18708"]]},{"id":"664cb048.8e0d9","type":"function","z":"46839377.4d6c0c","name":"Denon","func":"msg.payload = msg.payload.toString().toUpperCase();\nreturn msg;","outputs":1,"noerr":0,"x":1090,"y":880,"wires":[["d8212114.3d38e"]]},{"id":"3e162284.55a47e","type":"function","z":"46839377.4d6c0c","name":"Family Room Harmony","func":"switch (msg.payload) {\n case \"on\":\n case \"tv\":\n msg.payload = \"Watch TV\";\n break;\n case \"off\":\n msg.payload = \"PowerOff\";\n break;\n case \"media player\":\n case \"chromecast\":\n msg.payload = \"Watch Shield TV\";\n break;\n case \"game console\":\n msg.payload = \"Play PS4\";\n break;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":1040,"y":920,"wires":[["d8212114.3d38e"]]},{"id":"84d1695.bec2098","type":"function","z":"46839377.4d6c0c","name":"Bedroom Harmony","func":"switch (msg.payload) {\n case \"on\":\n case \"tv\":\n msg.payload = \"Watch TV\";\n break;\n case \"off\":\n msg.payload = \"PowerOff\";\n break;\n case \"media player\":\n case \"chromecast\":\n msg.payload = \"Watch Chromecast\";\n break;\n case \"game console\":\n msg.payload = \"Watch Roku\";\n break;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":1050,"y":960,"wires":[["d8212114.3d38e"]]},{"id":"681570b7.b2ad8","type":"function","z":"46839377.4d6c0c","name":"Value topic","func":"let regex = /([\\w\\/]+)\\(([\\w\\s]+)\\)(\\/set)/g\nlet topicParts = regex.exec(msg.topic);\n\nmsg.topic = topicParts[1] + topicParts[3];\nmsg.payload = msg.payload === \"on\" ? topicParts[2] : \"PowerOff\";\n\nreturn msg;","outputs":1,"noerr":0,"x":1070,"y":1000,"wires":[["d8212114.3d38e"]]},{"id":"12541066.18708","type":"function","z":"46839377.4d6c0c","name":"Default","func":"return msg;","outputs":1,"noerr":0,"x":1080,"y":1040,"wires":[["d8212114.3d38e"]]}] |
Great write up, struggled with the deviceStates variable to begin with but found how to get it working, only thing I haven't been able to achieve is the states that get pulled when running the QUERY. Always seem to get "TypeError: Cannot read property 'states' of undefined"
Using the below JSON for the deviceStates, any help would be appreciated.
[ { "id": "123", "type": "action.devices.types.LIGHT", "traits": [ "action.devices.traits.OnOff" ], "name": { "defaultNames": [ "device123" ], "name": "123", "nicknames": [ "Christmas Tree" ] }, "willReportState": true, "states": { "on": true }, "roomHint": "living room", "deviceInfo": { "manufacturer": "Foo", "model": "Bar", "hwVersion": "1.0", "swVersion": "1.0" }, "customData": { "fooValue": 12, "barValue": false, "bazValue": "dancing alpaca" } } ]