Last active
April 25, 2020 21:10
-
-
Save MorningZ/637e4c7bd6864e85aba6218f6dd772fa to your computer and use it in GitHub Desktop.
MyQ Flow for Node-RED / MQTT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[{"id":"507826e5.3ffbf8","type":"inject","z":"874c5955.ab41f8","name":"Status: Timer","topic":"garage/status","payload":"","payloadType":"date","repeat":"30","crontab":"","once":true,"onceDelay":"","x":220,"y":720,"wires":[["b1c4af88.5978d"]]},{"id":"23b3616.20e559e","type":"http request","z":"874c5955.ab41f8","name":"Call for token","method":"POST","ret":"obj","paytoqs":false,"url":"https://myqexternal.myqdevice.com/api/v4/User/Validate","tls":"","persist":false,"proxy":"","authType":"","x":875,"y":680,"wires":[["49214e77.d3055"]],"l":false},{"id":"e34ac162.30a6a","type":"debug","z":"874c5955.ab41f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":1015,"y":680,"wires":[],"l":false},{"id":"968bcaf0.5e0e68","type":"function","z":"874c5955.ab41f8","name":"Credentials","func":"\nreturn {\n \"payload\": {\n \"username\" : \"XXXXXXXXX\",\n \"password\" : \"XXXXXXXX\"\n },\n \"headers\": {\n ContentType : \"application/json\",\n Accept : \"application/json\",\n MyQApplicationId : \"Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB/i\",\n Culture : \"en\"\n }\n};","outputs":1,"noerr":0,"x":750,"y":680,"wires":[["23b3616.20e559e"]]},{"id":"b1c4af88.5978d","type":"function","z":"874c5955.ab41f8","name":"","func":"\nif(msg.payload && msg.payload.desired_state) {\n msg.desired_state = msg.payload.desired_state;\n}\n\n\nmsg.payload = {};\n\nvar myq = global.get(\"myq\");\n\nif(myq && myq.SecurityToken) {\n msg.payload.myq = myq; \n}\n\n\nreturn msg;\n","outputs":"1","noerr":0,"x":435,"y":680,"wires":[["1c87a52e.7e439b","6202206f.e7c1a","47d33c73.653994"]],"l":false},{"id":"c36bcbc8.860e78","type":"debug","z":"874c5955.ab41f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":695,"y":640,"wires":[],"l":false},{"id":"49214e77.d3055","type":"function","z":"874c5955.ab41f8","name":"","func":"\nif(msg.statusCode == 200 && msg.payload.SecurityToken) {\n var myq = {\n SecurityToken : msg.payload.SecurityToken\n };\n \n global.set(\"myq\", myq);\n msg.payload.myq = myq;\n return msg;\n} else {\n return null;\n}\n\n\n","outputs":1,"noerr":0,"x":935,"y":680,"wires":[["e34ac162.30a6a","47d33c73.653994"]],"l":false},{"id":"1c87a52e.7e439b","type":"switch","z":"874c5955.ab41f8","name":"","property":"payload.myq","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":575,"y":680,"wires":[["c36bcbc8.860e78"],["968bcaf0.5e0e68","c36bcbc8.860e78"]],"l":false},{"id":"6202206f.e7c1a","type":"debug","z":"874c5955.ab41f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":515,"y":640,"wires":[],"l":false},{"id":"47d33c73.653994","type":"function","z":"874c5955.ab41f8","name":"","func":"\nvar myq;\n\nif(msg.payload.myq) {\n myq = msg.payload.myq;\n} else {\n myq = global.get(\"myq\");\n}\n\nif(!myq) return msg;\n\n\n\n\nmsg.headers = {\n ContentType : \"application/json\",\n Accept : \"application/json\",\n MyQApplicationId : \"Vj8pQggXLhLy0WHahglCD4N1nAkkXQtGYpq2HrHD7H1nvmbT55KqtN6RSF4ILB/i\",\n Culture : \"en\",\n SecurityToken : myq.SecurityToken\n}\n\n\nreturn msg;\n\n","outputs":1,"noerr":0,"x":495,"y":760,"wires":[["da42ce7f.83aff"]],"l":false},{"id":"c788f7c4.ec6948","type":"http request","z":"874c5955.ab41f8","name":"","method":"GET","ret":"obj","paytoqs":false,"url":"https://myqexternal.myqdevice.com/api/v4/UserDeviceDetails/Get","tls":"","persist":false,"proxy":"","authType":"","x":715,"y":760,"wires":[["db2027af.300d08","3486ae37.022192"]],"l":false},{"id":"cb2d4097.22693","type":"function","z":"874c5955.ab41f8","name":"","func":"\nvar myq = global.get(\"myq\");\n\nmyq.devices = msg.payload.Devices;\nmyq.timestamp = new Date();\n\nglobal.set(\"myq\", myq);\n\nmsg.payload.myq = myq;\n\nvar state = \"unknown\";\nfor (var d in myq.devices) {\n var device = myq.devices[d];\n if(device && device.MyQDeviceTypeName && device.MyQDeviceTypeName == \"GarageDoorOpener\" && device.Attributes) {\n myq.garage = device;\n for(var a in device.Attributes) {\n var attribute = device.Attributes[a];\n if(attribute && attribute.AttributeDisplayName == \"doorstate\") {\n state = attribute.Value + \"\";\n myq.garage.state = \"unknown\";\n if(state == \"1\") myq.garage.state = \"open\";\n if(state == \"2\") myq.garage.state = \"closed\";\n if(state == \"3\") myq.garage.state = \"stopped\";\n if(state == \"4\") myq.garage.state = \"opening\";\n if(state == \"5\") myq.garage.state = \"closing\";\n if(state == \"8\") myq.garage.state = \"moving\";\n if(state == \"9\") myq.garage.state = \"open\";\n }\n }\n }\n}\nif(msg.headers) delete msg.headers;\nif(msg.statusCode) delete msg.statusCode;\nif(msg.responseUrl) delete msg.responseUrl;\nif(msg.responseCookies) delete msg.responseCookies;\n\nmsg.payload = msg.payload.myq;\n\nvar last = global.get(\"myq_garage_last_known\")\nmsg.payload.garage.hasChanged = false;\nif(last && last != msg.payload.garage.state) {\n msg.payload.garage.hasChanged = true;\n}\nglobal.set(\"myq_garage_last_known\", msg.payload.garage.state);\n\nreturn msg;","outputs":1,"noerr":0,"x":855,"y":860,"wires":[["782e6a8f.389834","8b4e29c4.a2d5a8","553e7b4d.6744a4"]],"l":false},{"id":"db2027af.300d08","type":"debug","z":"874c5955.ab41f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":915,"y":760,"wires":[],"l":false},{"id":"ddeb43c.99d7ac","type":"switch","z":"874c5955.ab41f8","name":"Path based on error","property":"payload.error","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":775,"y":820,"wires":[["224359ea.58fea6"],["cb2d4097.22693"]],"l":false},{"id":"224359ea.58fea6","type":"function","z":"874c5955.ab41f8","name":"","func":"\nreturn { _msgid : msg._msgid }\n","outputs":1,"noerr":0,"x":855,"y":820,"wires":[["968bcaf0.5e0e68"]],"l":false},{"id":"3486ae37.022192","type":"function","z":"874c5955.ab41f8","name":"Capture error","func":"\n\nif (msg.payload.ErrorMessage && msg.payload.ErrorMessage !== \"\") {\n msg.payload.error = msg.payload.ErrorMessage;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":715,"y":820,"wires":[["ddeb43c.99d7ac"]],"l":false},{"id":"2e017072.5b181","type":"comment","z":"874c5955.ab41f8","name":"MyQ MQTT Interface","info":"https://github.com/jbnunn/Alexa-MyQGarage/blob/master/myq.py\n\nhttps://unofficialliftmastermyq.docs.apiary.io/","x":240,"y":620,"wires":[]},{"id":"11776618.cff2ca","type":"inject","z":"874c5955.ab41f8","name":"Status: Inject","topic":"garage/status","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":"","x":210,"y":680,"wires":[["b1c4af88.5978d"]]},{"id":"782e6a8f.389834","type":"mqtt out","z":"874c5955.ab41f8","name":"","topic":"garage","qos":"","retain":"","broker":"f0bbcb39.fee3a8","x":1010,"y":820,"wires":[]},{"id":"8b4e29c4.a2d5a8","type":"switch","z":"874c5955.ab41f8","name":"","property":"payload.garage.hasChanged","propertyType":"msg","rules":[{"t":"true"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":915,"y":920,"wires":[["3da5cbc8.6e46f4","553e7b4d.6744a4"],["553e7b4d.6744a4"]],"l":false},{"id":"553e7b4d.6744a4","type":"debug","z":"874c5955.ab41f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":975,"y":880,"wires":[],"l":false},{"id":"3da5cbc8.6e46f4","type":"function","z":"874c5955.ab41f8","name":"Message","func":"\nlet txt = msg.payload.garage.state;\n\nswitch (txt) {\n case \"open\": case \"opening\": txt = \"Opening\"; break; \n case \"opened\": txt = \"Opened\"; break; \n case \"close\": case \"closing\": txt = \"Closing\"; break; \n case \"closed\": txt = \"Closed\"; break; \n}\n\nlet pad = function(num) {\n return (num < 10) ? \"0\" + num : \"\" + num;\n}\n\nlet dt = new Date(msg.payload.timestamp); let hrs = dt.getHours();\nif (hrs === 0) { // Midnight hour\n dt = \"12:\" + dt.getMinutes() + \" am\";\n}\nelse if (hrs > 11) { // PM\n hrs = hrs - 12;\n dt = (hrs < 10 ? \"0\" + hrs : \"\" + hrs) + \":\" + dt.getMinutes() + \" pm\";\n}\nelse { // AM \n dt = (hrs < 10 ? \"0\" + hrs : \"\" + hrs) + \":\" + dt.getMinutes() + \" am\";\n}\n\nreturn {\n \"payload\": {\n \"type\": 'pushNotification', \n \"payload\": { \n title: 'Garage Door', \n text: txt + \" at \" + dt \n }\n }\n};\n\n","outputs":1,"noerr":0,"x":1020,"y":920,"wires":[["a5f7c8c4.84d668"]]},{"id":"7cf27829.570748","type":"inject","z":"874c5955.ab41f8","name":"Control: Close","topic":"garage/control","payload":"{\"desired_state\":\"close\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":"","x":210,"y":880,"wires":[["b1c4af88.5978d"]]},{"id":"b63c7c5d.87899","type":"http request","z":"874c5955.ab41f8","name":"","method":"PUT","ret":"obj","paytoqs":false,"url":"https://myqexternal.myqdevice.com/api/v4/DeviceAttribute/PutDeviceAttribute","tls":"","persist":false,"proxy":"","authType":"","x":615,"y":820,"wires":[["91f0102.12453f","d19d1d10.eff6d"]],"l":false},{"id":"53d039a6.2ae7a8","type":"function","z":"874c5955.ab41f8","name":"","func":"var myq;\n\nif (msg.payload.myq) {\n myq = msg.payload.myq;\n} else {\n myq = global.get(\"myq\");\n}\nvar open_close_state = 0; \nif (msg.desired_state && msg.desired_state == \"open\") open_close_state = 1;\n\nmsg.payload = {\n \"attributeName\": \"desireddoorstate\",\n \"myQDeviceId\": myq.garage.MyQDeviceId,\n \"AttributeValue\": open_close_state\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":515,"y":820,"wires":[["b63c7c5d.87899","91f0102.12453f"]],"l":false},{"id":"da42ce7f.83aff","type":"switch","z":"874c5955.ab41f8","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"garage/control","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":555,"y":760,"wires":[["53d039a6.2ae7a8"],["c788f7c4.ec6948"]],"l":false},{"id":"91f0102.12453f","type":"debug","z":"874c5955.ab41f8","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":715,"y":940,"wires":[],"l":false},{"id":"50e2f908.2ddca8","type":"inject","z":"874c5955.ab41f8","name":"Control: Open","topic":"garage/control","payload":"{\"desired_state\":\"open\"}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":"","x":210,"y":840,"wires":[["b1c4af88.5978d"]]},{"id":"d19d1d10.eff6d","type":"mqtt out","z":"874c5955.ab41f8","name":"State","topic":"garage/control/state","qos":"","retain":"false","broker":"f0bbcb39.fee3a8","x":750,"y":880,"wires":[]},{"id":"8bdf3615.b545d8","type":"mqtt in","z":"874c5955.ab41f8","name":"Control: MQTT","topic":"garage/control","qos":"2","datatype":"json","broker":"f0bbcb39.fee3a8","x":220,"y":920,"wires":[["b1c4af88.5978d","7016175e.dfcde8"]]},{"id":"4c3dfa2d.b3ba54","type":"mqtt in","z":"874c5955.ab41f8","name":"Status: MQTT In","topic":"garage/status","qos":"2","datatype":"auto","broker":"f0bbcb39.fee3a8","x":220,"y":760,"wires":[["b1c4af88.5978d"]]},{"id":"a5f7c8c4.84d668","type":"alexa-remote-routine","z":"874c5955.ab41f8","name":"Send push notification","account":"41ad82a9.09a59c","routineNode":{"type":"custom","payload":{"type":"msg","value":"payload"}},"x":1115,"y":920,"wires":[[]],"icon":"font-awesome/fa-mobile-phone","l":false},{"id":"7016175e.dfcde8","type":"debug","z":"874c5955.ab41f8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":375,"y":920,"wires":[],"l":false},{"id":"dd37364a.6c1238","type":"inject","z":"874c5955.ab41f8","name":"Example \"open\" call from outside this flow","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":880,"y":540,"wires":[["64451aa.233cde4"]]},{"id":"64451aa.233cde4","type":"function","z":"874c5955.ab41f8","name":"Example of MQTT message creation","func":"\n// Make sure that \"Retain\" is set to \"true\" on the \"MQTT Out\" node that this flows into! \n\nreturn {\n \"topic\": \"garage/control\", \n \"payload\": { \"desired_state\": msg.payload ? \"open\" : \"close\" } \n};\n","outputs":1,"noerr":0,"x":1081,"y":560,"wires":[["9cc98833.3a2978"]],"inputLabels":["Open"],"outputLabels":["Close"],"icon":"node-red-contrib-sun-position/switch-black.png","l":false},{"id":"9cc98833.3a2978","type":"mqtt out","z":"874c5955.ab41f8","name":"","topic":"","qos":"2","retain":"true","broker":"cba97092.99da5","x":1170,"y":560,"wires":[]},{"id":"e68277b9.8ba748","type":"inject","z":"874c5955.ab41f8","name":"Example \"close\" call from outside this flow","topic":"","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":880,"y":580,"wires":[["64451aa.233cde4"]]},{"id":"f0bbcb39.fee3a8","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"41ad82a9.09a59c","type":"alexa-remote-account","z":"","name":"Alexa Account","authMethod":"proxy","proxyOwnIp":"10.21.0.71","proxyPort":"3456","cookieFile":"authFile","refreshInterval":"3","alexaServiceHost":"pitangui.amazon.com","amazonPage":"amazon.com","acceptLanguage":"en-US","userAgent":"","useWsMqtt":"on","autoInit":"off"},{"id":"cba97092.99da5","type":"mqtt-broker","z":"","name":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Reference:
https://flows.nodered.org/flow/83f263d6f5f23e53e2aed85b96aadb3e
https://unofficialliftmastermyq.docs.apiary.io/
I just cleaned things up a little bit.
Installed on a Raspberry Pi running Node-RED and Mosquito MQTT and this works fantastic
So far the only issue i've seen is that it can send multiple push notifications at the end once for in-process and another when completed (like one notification for "opening" and another for "open"). That could easily be fixed with a flow variable to tame that.