Skip to content

Instantly share code, notes, and snippets.

@IOIO72

IOIO72/README.md Secret

Created April 4, 2018 21:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IOIO72/0e1f6dab22f60c13b90bede25276e16e to your computer and use it in GitHub Desktop.
Save IOIO72/0e1f6dab22f60c13b90bede25276e16e to your computer and use it in GitHub Desktop.
Philips Hue Log File

Description

This flow logs Philips Hue light switch changes. Please follow the instructions to set up this flow to your environment.

Motivation

I use some rules for my light system and some motion detectors. As I arrive at home, my light switches are automatically triggered by my smartphones WiFi logon. Sometimes I ask myself, if the lights were really off during the day or always on, caused by a potential misconfiguration. So I set up my Raspberry Pi to create a log file of light changes.

Maybe it's usefull for you as well... ;)

Setup Instructions

  1. Follow the instructions on https://www.developers.meethue.com/documentation/getting-started to get your Philips Hue API URL.
  2. Inject the api url to the global variable global.settings.hue.url
  3. Set your desired log file name in the node named Write to Lights States Log File
  4. Now you can check when the lights were switched on and off

_ Note: The format of the timestamp is UTC in ISO 8601 compatible format and may not represent your local timezone. _

[{"id":"596ec16a.2048d","type":"subflow","name":"Array Of Booleans to String","info":"","in":[{"x":40,"y":40,"wires":[{"id":"af39cdd0.144f9"}]}],"out":[{"x":440,"y":40,"wires":[{"id":"af39cdd0.144f9","port":0}]}]},{"id":"af39cdd0.144f9","type":"function","z":"596ec16a.2048d","name":"Array Of Booleans to String","func":"let ret = \"\";\n\nfor (const b of msg.payload) {\n ret += (b === true) ? \"1\" : \"0\";\n}\nmsg.payload = ret;\nreturn msg;","outputs":1,"noerr":0,"x":240,"y":40,"wires":[[]]},{"id":"fdccb947.3480f8","type":"subflow","name":"Get Lights State","info":"","in":[{"x":40,"y":40,"wires":[{"id":"5a751ab7.8f3514"}]}],"out":[{"x":300,"y":40,"wires":[{"id":"5a751ab7.8f3514","port":0}]}]},{"id":"5a751ab7.8f3514","type":"function","z":"fdccb947.3480f8","name":"Get Lights States","func":"let ret = [];\n\nfor (const light in msg.payload) {\n ret.push(msg.payload[light].state.on);\n}\n\nmsg.payload = ret;\nreturn msg;\n","outputs":1,"noerr":0,"x":170,"y":40,"wires":[[]]},{"id":"ff0ee1c6.69484","type":"tab","label":"Report Home State","disabled":false,"info":"# Report Home State\n\n## Description\n\nThis flow logs Philips Hue light switch changes.\nPlease follow the instructions to set up this flow to your environment.\n\n## Motivation\n\nI use some rules for my light system and some motion detectors.\nAs I arrive at home, my light switches are automatically triggered by my smartphones WiFi logon.\nSometimes I ask myself, if the lights were really off during the day or always on, caused by a potential misconfiguration.\nSo I set up my Raspberry Pi to create a log file of light changes.\n\nMaybe it's usefull for you as well... ;)\n\n## Setup Instructions\n\n1. Follow the instructions on https://www.developers.meethue.com/documentation/getting-started to get your Philips Hue API URL.\n2. Inject the api url to the global variable `global.settings.hue.url`\n3. Set your desired log file name in the node named `Write to Lights States Log File`\n4. Now you can check when the lights were switched on and off\n \n_\n__Note:__\nThe format of the timestamp is UTC in ISO 8601 compatible format and may not represent your local timezone.\n_"},{"id":"43b7079.0cad1f8","type":"inject","z":"ff0ee1c6.69484","name":"","topic":"","payload":"","payloadType":"date","repeat":"5","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":180,"wires":[["a646fed9.c4707"]]},{"id":"72f0c35c.c0d9ac","type":"http request","z":"ff0ee1c6.69484","name":"Get Lights","method":"GET","ret":"obj","url":"","tls":"","x":330,"y":380,"wires":[["44540150.c3bd9"]]},{"id":"5a78994b.8884f8","type":"change","z":"ff0ee1c6.69484","name":"Set Lights URL","rules":[{"t":"set","p":"url","pt":"msg","to":"$globalContext(\"settings.hue.url\") & \"/lights\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":160,"y":380,"wires":[["72f0c35c.c0d9ac"]]},{"id":"a9958d2a.8a77e","type":"change","z":"ff0ee1c6.69484","name":"Save Last State","rules":[{"t":"set","p":"lastLightsState","pt":"flow","to":"lightsState","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":160,"y":280,"wires":[["aa099e57.239"]]},{"id":"aa73ebd6.d0e128","type":"change","z":"ff0ee1c6.69484","name":"Set Current State","rules":[{"t":"set","p":"lightsState","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":170,"y":480,"wires":[["1a8479df.871036"]]},{"id":"d7c05f9.56629a","type":"switch","z":"ff0ee1c6.69484","name":"Lights State Changed?","property":"lightsState","propertyType":"flow","rules":[{"t":"neq","v":"lastLightsState","vt":"flow"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":190,"y":580,"wires":[["45d7d2c0.8a203c"],["4f3ce9e2.673078"]],"outputLabels":["yes","no"]},{"id":"feda1399.e1a9b","type":"debug","z":"ff0ee1c6.69484","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1030,"y":660,"wires":[]},{"id":"5cbc9fd3.489b","type":"change","z":"ff0ee1c6.69484","name":"off text","rules":[{"t":"set","p":"payload","pt":"msg","to":"ALL LIGHTS OFF","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":580,"wires":[["a93d0be5.e98928"]]},{"id":"4f3ce9e2.673078","type":"change","z":"ff0ee1c6.69484","name":"unchanged text","rules":[{"t":"set","p":"payload","pt":"msg","to":"lights unchanged","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":620,"y":660,"wires":[["feda1399.e1a9b"]]},{"id":"9053e561.d4eeb8","type":"debug","z":"ff0ee1c6.69484","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":870,"y":420,"wires":[]},{"id":"44540150.c3bd9","type":"subflow:fdccb947.3480f8","z":"ff0ee1c6.69484","x":500,"y":380,"wires":[["f4b1114.a61d6f"]]},{"id":"f4b1114.a61d6f","type":"subflow:596ec16a.2048d","z":"ff0ee1c6.69484","name":"Convert to String","x":690,"y":380,"wires":[["9053e561.d4eeb8","6b1950db.6aaa1"]]},{"id":"45d7d2c0.8a203c","type":"switch","z":"ff0ee1c6.69484","name":"Are All Lights Off?","property":"$contains($flowContext(\"lightsState\"), \"1\")","propertyType":"jsonata","rules":[{"t":"false"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":430,"y":580,"wires":[["5cbc9fd3.489b"],["69162fa8.7249d"]],"outputLabels":["yes","no"]},{"id":"69162fa8.7249d","type":"change","z":"ff0ee1c6.69484","name":"changed text","rules":[{"t":"set","p":"payload","pt":"msg","to":"LIGHTS CHANGED","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":620,"wires":[["a93d0be5.e98928"]]},{"id":"39631a9d.7dbb46","type":"file","z":"ff0ee1c6.69484","name":"Write to Lights States Log File","filename":"/home/pi/.node-red/logs/lightsstates.log","appendNewline":true,"createDir":true,"overwriteFile":"false","x":1090,"y":580,"wires":[]},{"id":"a93d0be5.e98928","type":"change","z":"ff0ee1c6.69484","name":"Prepend Timestamp","rules":[{"t":"set","p":"payload","pt":"msg","to":"$now() & \" - \" & $flowContext(\"lightsState\") & \" - \" & msg.payload","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":820,"y":580,"wires":[["feda1399.e1a9b","39631a9d.7dbb46"]]},{"id":"89aa4dbb.f9aa","type":"comment","z":"ff0ee1c6.69484","name":"Set `global.settings.hue.url` to your Philips Hue api url: https://www.developers.meethue.com/documentation/getting-started","info":"> To get detailed step by step instructions, open the flow description.","x":440,"y":40,"wires":[],"icon":"node-red/alert.png"},{"id":"5315b9cc.738bd8","type":"comment","z":"ff0ee1c6.69484","name":"Check for changes every ... seconds","info":"","x":170,"y":140,"wires":[]},{"id":"9dcf6fef.1b09f","type":"comment","z":"ff0ee1c6.69484","name":"Save previous light state","info":"","x":130,"y":240,"wires":[]},{"id":"47f0a7ce.a5fec8","type":"comment","z":"ff0ee1c6.69484","name":"Get the current light state","info":"","x":130,"y":340,"wires":[]},{"id":"18a4fbe7.e23ea4","type":"comment","z":"ff0ee1c6.69484","name":"Save current light state","info":"","x":120,"y":440,"wires":[]},{"id":"f0dc5ba3.683aa8","type":"comment","z":"ff0ee1c6.69484","name":"Log light state changes","info":"","x":120,"y":540,"wires":[]},{"id":"f5d529a9.469eb8","type":"comment","z":"ff0ee1c6.69484","name":"⬇ SET FILENAME HERE","info":"> To get detailed step by step instructions, open the flow description.","x":1070,"y":540,"wires":[],"icon":"node-red/node-changed.png"},{"id":"9f60f3be.8913e","type":"change","z":"ff0ee1c6.69484","name":"Set Philips Hue API URL","rules":[],"action":"","property":"","from":"","to":"","reg":false,"x":370,"y":80,"wires":[[]]},{"id":"18d30974.dd7e17","type":"inject","z":"ff0ee1c6.69484","name":"Set Initial Variables","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":150,"y":80,"wires":[["9f60f3be.8913e"]]},{"id":"4b6ae102.ac9d9","type":"comment","z":"ff0ee1c6.69484","name":"⬅ SET VARIABLE HERE","info":"> To get detailed step by step instructions, open the flow description.","x":590,"y":80,"wires":[],"icon":"node-red/node-changed.png"},{"id":"ca52298c.be1508","type":"link in","z":"ff0ee1c6.69484","name":"Save previous light state","links":["a646fed9.c4707"],"x":55,"y":280,"wires":[["a9958d2a.8a77e"]]},{"id":"ecf7b9a1.4ca168","type":"link in","z":"ff0ee1c6.69484","name":"Get the current light state","links":["aa099e57.239"],"x":55,"y":380,"wires":[["5a78994b.8884f8"]]},{"id":"6e1da50d.f53c4c","type":"link in","z":"ff0ee1c6.69484","name":"Save current light state","links":["6b1950db.6aaa1"],"x":55,"y":480,"wires":[["aa73ebd6.d0e128"]]},{"id":"9a9334da.405dd8","type":"link in","z":"ff0ee1c6.69484","name":"Log light state changes","links":["1a8479df.871036"],"x":55,"y":580,"wires":[["d7c05f9.56629a"]]},{"id":"a646fed9.c4707","type":"link out","z":"ff0ee1c6.69484","name":"","links":["ca52298c.be1508"],"x":235,"y":180,"wires":[]},{"id":"aa099e57.239","type":"link out","z":"ff0ee1c6.69484","name":"","links":["ecf7b9a1.4ca168"],"x":275,"y":280,"wires":[]},{"id":"6b1950db.6aaa1","type":"link out","z":"ff0ee1c6.69484","name":"","links":["6e1da50d.f53c4c"],"x":815,"y":380,"wires":[]},{"id":"1a8479df.871036","type":"link out","z":"ff0ee1c6.69484","name":"","links":["9a9334da.405dd8"],"x":295,"y":480,"wires":[]}]
@mengelsen
Copy link

mengelsen commented Dec 18, 2020

I have a question about the contents of the "Log File".
Here is an example of a line that is written to the "lightsstates.log" file:

2020-12-18T21:31:52.434Z - 100000 - LIGHTS CHANGED

  • The first part is the timestamp.
  • The last part is the "change node" text (appended to the message.payload).
  • I don't understand what the middle part represents. (In my example, this is the "100000".)

@IOIO72
Copy link
Author

IOIO72 commented Dec 18, 2020

I have a question about the contents of the "Log File".
Here is an example of a line that is written to the "lightsstates.log" file:

2020-12-18T21:31:52.434Z - 100000 - LIGHTS CHANGED

  • The first part is the timestamp.
  • The last part is the "change node" text (appended to the message.payload).
  • I don't understand what the middle part represents. (In my example, this is the "100000".)

The binary number represent the on/off state of the light bulbs.

@mengelsen
Copy link

mengelsen commented Dec 18, 2020

@IOIO72 I understand that 0 would imply "off" and 1 equals "on". However, I fail to understand how this 6-digit number should be interpreted.

For example, here are the results that I have captured thus far:

Light1  ON   100000
Light2  ON   110000
Light1  OFF  010000
Light1  ON   110000
Light1  OFF  010000
Light6  ON   010001
Light6  OFF  010000
Light6  ON   010001
Light6  OFF  010000
Light2  OFF  000000 (All Lights Off)
Light2  ON   010000

According to this data, the same binary number (010000) was used when:

  • Light 1 was turned OFF
  • Light 6 was turned OFF
  • Light 2 was turned ON

Any idea how this binary number is meant to be interpreted?
Thanks!

@mengelsen
Copy link

Haha. I (finally) understand what is happening. Each digit represents a single lightbulb.
The first digit = status of light1
The second digit = status of light2

@IOIO72
Copy link
Author

IOIO72 commented Jan 5, 2021

Haha. I (finally) understand what is happening. Each digit represents a single lightbulb.
The first digit = status of light1
The second digit = status of light2

Yeah, right! Sorry for my delayed answer. Due to holiday, I wasn't active on GitHub. Glad, that you found out what happened and I'm happy that you use my NodeRED flow :-)

@mengelsen
Copy link

@IOIO72 Your code works! 💯%

However, I was curious to know what device is responsible for the state change. I was able to achieve this (kinda) with the help of your Node-RED project. Here is an export of the revised code base:

[{"id":"ff0ee1c6.69484","type":"tab","label":"Report Home State","disabled":false,"info":"# Report Home State\n\n## Description\n\nThis flow logs Philips Hue light switch changes.\nPlease follow the instructions to set up this flow to your environment.\n\n## Motivation\n\nI use some rules for my light system and some motion detectors.\nAs I arrive at home, my light switches are automatically triggered by my smartphones WiFi logon.\nSometimes I ask myself, if the lights were really off during the day or always on, caused by a potential misconfiguration.\nSo I set up my Raspberry Pi to create a log file of light changes.\n\nMaybe it's usefull for you as well... ;)\n\n## Setup Instructions\n\n1. Follow the instructions on https://www.developers.meethue.com/documentation/getting-started to get your Philips Hue API URL.\n2. Inject the api url to the global variable `global.settings.hue.url`\n3. Set your desired log file name in the node named `Write to Lights States Log File`\n4. Now you can check when the lights were switched on and off\n \n_\n__Note:__\nThe format of the timestamp is UTC in ISO 8601 compatible format and may not represent your local timezone.\n_"},{"id":"288f64f2.622c9c","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"596ec16a.2048d","type":"subflow","name":"Array Of Booleans to String","info":"","in":[{"x":40,"y":40,"wires":[{"id":"af39cdd0.144f9"}]}],"out":[{"x":440,"y":40,"wires":[{"id":"af39cdd0.144f9","port":0}]}]},{"id":"fdccb947.3480f8","type":"subflow","name":"Get Lights State","info":"","in":[{"x":40,"y":40,"wires":[{"id":"5a751ab7.8f3514"}]}],"out":[{"x":300,"y":40,"wires":[{"id":"5a751ab7.8f3514","port":0}]}]},{"id":"a1719e16.dc588","type":"subflow","name":"Device Responsible for BulbStateChange","info":"","category":"","in":[{"x":20,"y":100,"wires":[{"id":"454db0b1.48969"}]}],"out":[{"x":980,"y":100,"wires":[{"id":"24a93773.36593","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"af39cdd0.144f9","type":"function","z":"596ec16a.2048d","name":"Array Of Booleans to String","func":"let ret = \"\";\n\nfor (const b of msg.payload) {\n    ret += (b === true) ? \"1\" : \"0\";\n}\nmsg.payload = ret;\nreturn msg;","outputs":1,"noerr":0,"x":240,"y":40,"wires":[[]]},{"id":"5a751ab7.8f3514","type":"function","z":"fdccb947.3480f8","name":"Get Lights States","func":"let ret = [];\n\nfor (const light in msg.payload) {\n    ret.push(msg.payload[light].state.on);\n}\n\nmsg.payload = ret;\nreturn msg;\n","outputs":1,"noerr":0,"x":170,"y":40,"wires":[[]]},{"id":"43b7079.0cad1f8","type":"inject","z":"ff0ee1c6.69484","name":"","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"string"}],"repeat":"5","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":180,"wires":[["a646fed9.c4707"]]},{"id":"72f0c35c.c0d9ac","type":"http request","z":"ff0ee1c6.69484","name":"Get Lights","method":"GET","ret":"obj","url":"","tls":"","x":330,"y":380,"wires":[["44540150.c3bd9"]]},{"id":"5a78994b.8884f8","type":"change","z":"ff0ee1c6.69484","name":"Set Lights URL","rules":[{"t":"set","p":"url","pt":"msg","to":"$globalContext(\"settings.hue.url\") & \"/lights\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":160,"y":380,"wires":[["72f0c35c.c0d9ac"]]},{"id":"a9958d2a.8a77e","type":"change","z":"ff0ee1c6.69484","name":"Save Last State","rules":[{"t":"set","p":"lastLightsState","pt":"flow","to":"lightsState","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":160,"y":280,"wires":[["aa099e57.239"]]},{"id":"aa73ebd6.d0e128","type":"change","z":"ff0ee1c6.69484","name":"Set Current State","rules":[{"t":"set","p":"lightsState","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":170,"y":480,"wires":[["1a8479df.871036"]]},{"id":"d7c05f9.56629a","type":"switch","z":"ff0ee1c6.69484","name":"Lights State Changed?","property":"lightsState","propertyType":"flow","rules":[{"t":"else"},{"t":"neq","v":"lastLightsState","vt":"flow"}],"checkall":"true","repair":false,"outputs":2,"x":190,"y":580,"wires":[["4f3ce9e2.673078"],["45d7d2c0.8a203c"]],"outputLabels":["no","yes"]},{"id":"feda1399.e1a9b","type":"debug","z":"ff0ee1c6.69484","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":690,"y":580,"wires":[]},{"id":"5cbc9fd3.489b","type":"change","z":"ff0ee1c6.69484","name":"off text","rules":[{"t":"set","p":"payload","pt":"msg","to":"ALL LIGHTS OFF","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":660,"y":640,"wires":[["a93d0be5.e98928"]]},{"id":"4f3ce9e2.673078","type":"change","z":"ff0ee1c6.69484","name":"unchanged text","rules":[{"t":"set","p":"payload","pt":"msg","to":"lights unchanged","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":580,"wires":[[]]},{"id":"9053e561.d4eeb8","type":"debug","z":"ff0ee1c6.69484","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":870,"y":420,"wires":[]},{"id":"44540150.c3bd9","type":"subflow:fdccb947.3480f8","z":"ff0ee1c6.69484","x":500,"y":380,"wires":[["f4b1114.a61d6f","a2b2c731.b87918"]]},{"id":"f4b1114.a61d6f","type":"subflow:596ec16a.2048d","z":"ff0ee1c6.69484","name":"Convert to String","x":690,"y":380,"wires":[["9053e561.d4eeb8","6b1950db.6aaa1"]]},{"id":"45d7d2c0.8a203c","type":"switch","z":"ff0ee1c6.69484","name":"Are All Lights Off?","property":"$contains($flowContext(\"lightsState\"), \"1\")","propertyType":"jsonata","rules":[{"t":"false"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":450,"y":640,"wires":[["5cbc9fd3.489b"],["c1112385.476cf"]],"outputLabels":["yes","no"]},{"id":"69162fa8.7249d","type":"change","z":"ff0ee1c6.69484","name":"changed text","rules":[{"t":"set","p":"payload","pt":"msg","to":"\"LIGHTS CHANGED BY: \" & msg.lightChangedBy","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":970,"y":700,"wires":[["a93d0be5.e98928"]]},{"id":"39631a9d.7dbb46","type":"file","z":"ff0ee1c6.69484","name":"Write to Lights States Log File","filename":"/usr/local/bin/PhilipsHue/logs/lightsstates.log","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"utf8","x":1150,"y":640,"wires":[[]]},{"id":"a93d0be5.e98928","type":"change","z":"ff0ee1c6.69484","name":"Prepend Timestamp","rules":[{"t":"set","p":"payload","pt":"msg","to":"$now() & \" - \" & $flowContext(\"lightsState\") & \" - \" & msg.payload","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":640,"wires":[["feda1399.e1a9b","39631a9d.7dbb46"]]},{"id":"89aa4dbb.f9aa","type":"comment","z":"ff0ee1c6.69484","name":"Set `global.settings.hue.url` to your Philips Hue api url: https://www.developers.meethue.com/documentation/getting-started","info":"> To get detailed step by step instructions, open the flow description.","x":440,"y":40,"wires":[],"icon":"node-red/alert.png"},{"id":"5315b9cc.738bd8","type":"comment","z":"ff0ee1c6.69484","name":"Check for changes every ... seconds","info":"","x":170,"y":140,"wires":[]},{"id":"9dcf6fef.1b09f","type":"comment","z":"ff0ee1c6.69484","name":"Save previous light state","info":"","x":130,"y":240,"wires":[]},{"id":"47f0a7ce.a5fec8","type":"comment","z":"ff0ee1c6.69484","name":"Get the current light state","info":"","x":130,"y":340,"wires":[]},{"id":"18a4fbe7.e23ea4","type":"comment","z":"ff0ee1c6.69484","name":"Save current light state","info":"","x":120,"y":440,"wires":[]},{"id":"f0dc5ba3.683aa8","type":"comment","z":"ff0ee1c6.69484","name":"Log light state changes","info":"","x":120,"y":540,"wires":[]},{"id":"f5d529a9.469eb8","type":"comment","z":"ff0ee1c6.69484","name":"⬇ SET FILENAME HERE","info":"> To get detailed step by step instructions, open the flow description.","x":1130,"y":600,"wires":[],"icon":"node-red/node-changed.png"},{"id":"9f60f3be.8913e","type":"change","z":"ff0ee1c6.69484","name":"OPEN ME!","rules":[{"t":"set","p":"settings.hue.url","pt":"global","to":"http://ip_address_here/api/api_token_here","tot":"str"},{"t":"set","p":"pi.apiName","pt":"global","to":"Use \"Flow1\" to identify the API name to omit.","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":80,"wires":[[]]},{"id":"18d30974.dd7e17","type":"inject","z":"ff0ee1c6.69484","name":"Set Initial Variables","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"string"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":80,"wires":[["9f60f3be.8913e"]]},{"id":"4b6ae102.ac9d9","type":"comment","z":"ff0ee1c6.69484","name":"⬅ SET VARIABLES HERE","info":"> To get detailed step by step instructions, open the flow description.","x":530,"y":80,"wires":[],"icon":"node-red/node-changed.png"},{"id":"ca52298c.be1508","type":"link in","z":"ff0ee1c6.69484","name":"Save previous light state","links":["a646fed9.c4707"],"x":55,"y":280,"wires":[["a9958d2a.8a77e"]]},{"id":"ecf7b9a1.4ca168","type":"link in","z":"ff0ee1c6.69484","name":"Get the current light state","links":["aa099e57.239"],"x":55,"y":380,"wires":[["5a78994b.8884f8"]]},{"id":"6e1da50d.f53c4c","type":"link in","z":"ff0ee1c6.69484","name":"Save current light state","links":["6b1950db.6aaa1"],"x":55,"y":480,"wires":[["aa73ebd6.d0e128"]]},{"id":"9a9334da.405dd8","type":"link in","z":"ff0ee1c6.69484","name":"Log light state changes","links":["1a8479df.871036"],"x":55,"y":580,"wires":[["d7c05f9.56629a"]]},{"id":"a646fed9.c4707","type":"link out","z":"ff0ee1c6.69484","name":"","links":["ca52298c.be1508"],"x":235,"y":180,"wires":[]},{"id":"aa099e57.239","type":"link out","z":"ff0ee1c6.69484","name":"","links":["ecf7b9a1.4ca168"],"x":275,"y":280,"wires":[]},{"id":"6b1950db.6aaa1","type":"link out","z":"ff0ee1c6.69484","name":"","links":["6e1da50d.f53c4c"],"x":815,"y":380,"wires":[]},{"id":"1a8479df.871036","type":"link out","z":"ff0ee1c6.69484","name":"","links":["9a9334da.405dd8"],"x":295,"y":480,"wires":[]},{"id":"a2b2c731.b87918","type":"debug","z":"ff0ee1c6.69484","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":670,"y":440,"wires":[]},{"id":"6a688d8c.62eab4","type":"comment","z":"a1719e16.dc588","name":"Capture the Philips Hue config","info":"","x":410,"y":60,"wires":[]},{"id":"f3e9749d.059148","type":"http request","z":"a1719e16.dc588","name":"GetConfig","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":350,"y":100,"wires":[["2a54e795.ae9248"]]},{"id":"454db0b1.48969","type":"change","z":"a1719e16.dc588","name":"Set hueConfig URL","rules":[{"t":"set","p":"url","pt":"msg","to":"$globalContext(\"settings.hue.url\") & \"/config\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":170,"y":100,"wires":[["f3e9749d.059148"]]},{"id":"24a93773.36593","type":"function","z":"a1719e16.dc588","name":"Identify Device Last Used","func":" let hueConfig = msg.payload.whitelist;\n let keys = Object.keys(hueConfig);\n let asArray = [];\n \n //Populates the array using JSON from the hue config\n for (let i = 0; i < keys.length; i++) {\n     let key = keys[i];\n     let item = hueConfig[key]; //get item\n     asArray.push(hueConfig[key]);\n }\n \n //Removes the Raspberry Pi from the array\n let omitFromArray = msg.deviceToOmit;\n for (let i = 0; i < asArray.length; i++) {\n    if ( asArray[i].name === omitFromArray) { \n        asArray.splice(i, 1); \n    }\n }\n \n //Sorts the array by \"last use date\"\n //Newest to Oldest\n let sorted = asArray.sort(function compare(a,b) {\n     let aDate = new Date(a[\"last use date\"]), bDate = new Date(b[\"last use date\"]);\n     if (aDate > bDate) return -1;\n     if (aDate < bDate) return 1;\n })\n\nmsg.lightChangedBy = sorted[0].name; //get 1st element\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":810,"y":100,"wires":[[]]},{"id":"c1112385.476cf","type":"subflow:a1719e16.dc588","z":"ff0ee1c6.69484","name":"","x":720,"y":700,"wires":[["69162fa8.7249d"]]},{"id":"2a54e795.ae9248","type":"change","z":"a1719e16.dc588","name":"Identify Device to Omit","rules":[{"t":"set","p":"deviceToOmit","pt":"msg","to":"pi.apiName","tot":"global"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":100,"wires":[["24a93773.36593"]]},{"id":"d72db09f.468d48","type":"http request","z":"288f64f2.622c9c","name":"GetConfig","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":490,"y":140,"wires":[["f5871ca4.7f4048"]]},{"id":"7da858a6.99f3c","type":"change","z":"288f64f2.622c9c","name":"Set hueConfig URL","rules":[{"t":"set","p":"url","pt":"msg","to":"$globalContext(\"settings.hue.url\") & \"/config\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":140,"wires":[["d72db09f.468d48"]]},{"id":"f5871ca4.7f4048","type":"function","z":"288f64f2.622c9c","name":"Identify Device Last Used","func":" let hueConfig = msg.payload.whitelist;\n let keys = Object.keys(hueConfig);\n let asArray = [];\n \n //Populates the array using JSON from the hue config\n for (let i = 0; i < keys.length; i++) {\n    let key = keys[i];\n    let item = hueConfig[key].name; //get item\n    asArray.push(hueConfig[key].name);\n }\n\nmsg.payload = asArray;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":690,"y":140,"wires":[["1a491f1c.8368a1"]]},{"id":"3f64c318.0af854","type":"inject","z":"288f64f2.622c9c","name":"","props":[],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payloadType":"str","x":130,"y":140,"wires":[["7da858a6.99f3c"]]},{"id":"1a491f1c.8368a1","type":"debug","z":"288f64f2.622c9c","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":910,"y":140,"wires":[]},{"id":"630e0608.888b28","type":"comment","z":"288f64f2.622c9c","name":"READ ME!","info":"1) Open the [Debug Sidebar](https://nodered.org/docs/user-guide/editor/sidebar/debug).\n2) Activate the (green) debug node.\n(Click the green box to the right of the node.)\n2) Click the blue \"Inject\" button.\n3) Click on the debug output.\n4) _Copy_ the name used by the raspberry pi.\n5) Go back to the \"Report Home State\" flow.\n6) Double click on the \"OPEN ME\" node.\n7) _Paste_ the name into 2nd global variable. (Called: global.pi.apiName)","x":120,"y":100,"wires":[]},{"id":"baf6f5c2.083cb","type":"comment","z":"288f64f2.622c9c","name":"⬇️ Activate debug node","info":"","x":1050,"y":100,"wires":[]}]

Except from .log file:

2021-01-04T22:15:33.408Z - 000000 - ALL LIGHTS OFF
2021-01-04T22:44:04.913Z - 010001 - LIGHTS CHANGED BY: amazon_dash_button_user
2021-01-05T00:21:18.257Z - 110100 - LIGHTS CHANGED BY: hue-alexa-smarthome-skill-v1
2021-01-05T00:53:49.908Z - 110110 - LIGHTS CHANGED BY: Hue 3#iPHONE

There is one major issue with my (revised) Node-RED project.

Currently, I am chronologically sorting the list of whitelisted devices by "last use date" to determine who toggled the lights. However, Philips HUE motion sensors and light switches can (also) be used to turn lights on/off.

As such, I would need to combine sensor data with the list of whitelisted devices. However, this doesn't guarantee a foolproof solution because "motion" doesn't guarantee a light state change. Additionally, someone could use their smartphone to toggle a light at the same moment that a motion sensor gets tripped.

Anyway...assuming you remove HUE accessories from the equation, this revised workflow will tell you when and what triggered the lightbulb state change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment