Lighting Reformat in Function Node with Google Home

I'm using the Google Home node called node-red-contrib-nora. Speaking to the Google Home results in an output in Node Red as follows -

'Hey Google...'
'Turn on the Alfresco light' = {"on":true,"brightness":100}
'Turn off the Alfresco light' = {"on":false,"brightness":100}
'Set the Alfresco brightness to 50%' = {"on":false,"brightness":50}
'Turn on the Alfresco light' = {"on":true,"brightness":50}

The light I'm controlling has more capabilities beyond what the nora-light node is able to support (RGB, Cold/Warm white etc.). Notwithstanding, I'd like to map what the nora-light node can do to a limited subset of light features.

Turning off the lamp by voice = "on":false
would map to an input string
hsv(0,0,0)

Turning on the lamp by voice = "on":true
would map to an input string
temp(100,6500)

Setting the brightness by voice = "brightness":50
would map to an input string
temp(50,6500)

The voice commands will therefore only adjust brightness and ON/OFF with the light at a fixed temperature of 6500. I really have no idea where to start with this..?

YOu have to work out what the Google Home Node is sending into Node-Red - put some debugs on it and have a look at what is being spat out once you have spoken to it.

That will give you a start point.

Once you can map the outputs it should be easy enough to work out what fields need to be manipulated.

Craig

Sorry did not read closely enough - looks like you have done the mapping.

Can you not use a change node to grab the various input fields and output them into either a join node or a function node to send on ?

Craig

Also some of those strings you have quoted seem a little dubious ??

'Turn on the Alfresco light' = {"on":true,"brightness":100} - OK that makes sense
'Turn off the Alfresco light' = {"on":false,"brightness":100} - OK that makes sense - guessing you would store the brightness level somewhere so it came on at the same level next time ??

'Set the Alfresco brightness to 50%' = {"on":false,"brightness":50} - that does not make sense - as per the above

'Turn on the Alfresco light' = {"on":true,"brightness":50} - again as per above - assuming you want to store the brightness level somewhere - maybe a global persistent variable ?

Craig

The variable not changed from a given voice command (either ON/OFF or brightness) persists from previous commands. When you read those commands in order from top to bottom, those are the strings that appear.

'Set the Alfresco brightness to 50%' occurred after the light was turned off. When it's next commanded on, it will be at 50%.

As as very new user to Node Red, I'd be very appreciative of any guidance on how to do the things you suggested. Or any reference material that you can direct me to?

Post up your flow please and also add a debug node to the output of the Nora node and then post up the output from that so we can see what is happening - how the messages are formatted etc

Craig

Drag the change node onto your palette and then have a look at the side information bar - depending on the format of the incoming messages (see my last post) you can then change/produce and outgoing valuable from an incoming stream - so incoming could be {"on":false,"brightness":50} and outgoing could change it to hsv(0,0,0) (not quite that simple as you have numbers and a string - but able to be worked around

Craig

Thanks. I've attached the debug node to the Nora node. The voice commands in order are -

  1. Turn on the light
  2. Set the brightness to 50%
  3. Turn off the light
  4. Set the brightness to 100%

I've attached the flow below. The injects work correctly for the Control out node. The private Token has been removed from the Nora node and IP and port details are removed from the Control out node. I don't know what I'm doing in the Function node yet.

[{"id":"2bd39e77.6113a2","type":"nora-light","z":"febb2f85.8f061","devicename":"Alfresco Light","lightcolor":false,"brightnesscontrol":true,"passthru":true,"statepayload":true,"brightnessoverride":"","roomhint":"Alfresco","name":"Alfresco Light","nora":"ca174d3e.f2527","topic":"","onvalue":"true","onvalueType":"bool","offvalue":"false","offvalueType":"bool","x":280,"y":580,"wires":[["5bae499b.a87fa8","8db6a3e8.0bf6b"]]},{"id":"1a90a730.508439","type":"loxone-control-out","z":"febb2f85.8f061","name":"control out","miniserver":"","control":"12e6cd0f-00c8-1932-ffffd989fb12b87b/AI1","x":890,"y":580,"wires":[]},{"id":"8cbcb37c.72685","type":"inject","z":"febb2f85.8f061","name":"","topic":"","payload":"temp(50,6500)","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":600,"y":440,"wires":[["1a90a730.508439"]]},{"id":"5bae499b.a87fa8","type":"function","z":"febb2f85.8f061","name":"Alfresco Light Reformat","func":"m = msg.payload\nreturn {topic:\"temp\",payload:\"temp(\"+m+\")\"};","outputs":1,"noerr":0,"x":590,"y":580,"wires":[["1a90a730.508439"]]},{"id":"25d403e6.67512c","type":"inject","z":"febb2f85.8f061","name":"","topic":"","payload":"hsv(0,0,0)","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":580,"y":500,"wires":[["1a90a730.508439"]]},{"id":"8db6a3e8.0bf6b","type":"debug","z":"febb2f85.8f061","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":550,"y":640,"wires":[]},{"id":"ca174d3e.f2527","type":"nora-config","z":"","name":"nora config","group":"","notify":false}]

So you only want to action something, based on the bit that HAS changed, you are going to need to compare it to the previous value which means storing it. Theres a section in the docs about context values (how to store values between messages).

So can you explain what happens when

  1. Turn on the light - what brightness does it go to ?
  2. Turn off the light - assume it remembers the last brightness ?
  3. Turn up (or down) the brightness whilt the light is OFF - does this do anything ? Turn the light on or just store the brightness for the next time it is turned on i.e. is a brightness change an implicit turn on of the light ?

Craig

In the debug window - can you click on one of the arrow pointing to the right - this will open the object so we can see the full detals of what is being sent out of the node

Craig

Some further explanation -

  1. Turn on the light - it will go to whatever brightness was last set,
  2. Turn off the light - correct, the brightness value is retained for future use,
  3. Turn up (or down) the brightness while the light is OFF - the light remains off but the value is changed for the next time it is turned on.

The full details of the debug are captured below. The structure is the same for all the debug messages.

Full%20debug%20view

Here you go - read up on this - should give you the way to tackle it (and an understanding of JS Objects and JSON at the same time

http://www.steves-internet-guide.com/working-with-json-data-node-red/

Craig

Thanks. That looks like a comprehensive guide.:+1:

There was a recent upgrade to the NORA node (node-red-contrib-nora) that allows colours to be translated into Node-Red with Google voice commands.

I'm successfully using a light that is capable of Cold White/Warm White and HSV. I'm only using it in a 'dumb' sense, being that I've only worked out how to turn it ON/OFF and set brightness through Node-Red. It turns ON and OFF to the previous brightness setting in Cold White with the attached flow -

[{"id":"9387e6ce.4c94a8","type":"nora-light","z":"7d40fce6.931704","devicename":"Alfresco Light","lightcolor":true,"brightnesscontrol":true,"passthru":false,"statepayload":true,"brightnessoverride":"","roomhint":"Alfresco","name":"Alfresco Light","nora":"dc70cfe5.682e7","topic":"","onvalue":"true","onvalueType":"bool","offvalue":"false","offvalueType":"bool","x":100,"y":160,"wires":[["ea7c205b.894bd","63720066.497f7","141a5777.8b5869"]]},{"id":"c223b6f6.474938","type":"loxone-control-out","z":"7d40fce6.931704","name":"control out","miniserver":"","control":"12e6cd0f-00c8-1932-ffffd989fb12b87b/AI1","x":1150,"y":160,"wires":[]},{"id":"63720066.497f7","type":"function","z":"7d40fce6.931704","name":"On/Off Object","func":"m = msg.payload;\nmsg.payload=m.on;\nreturn msg;","outputs":1,"noerr":0,"x":520,"y":120,"wires":[["d9b1452f.1c12f8"]]},{"id":"a4b7a00c.27d4b","type":"inject","z":"7d40fce6.931704","name":"Warm white","topic":"","payload":"hsv(29.60,58.82,100)","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":730,"y":280,"wires":[["c223b6f6.474938"]]},{"id":"ea7c205b.894bd","type":"function","z":"7d40fce6.931704","name":"Brightness Object","func":"m = msg.payload;\nmsg.payload=m.brightness;\nreturn msg;","outputs":1,"noerr":0,"x":510,"y":160,"wires":[["76e4fc8a.dc1b54"]]},{"id":"d9b1452f.1c12f8","type":"change","z":"7d40fce6.931704","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"false","fromt":"bool","to":"hsv(0,0,0)","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":"true","fromt":"bool","to":"on","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":780,"y":120,"wires":[["c223b6f6.474938"]]},{"id":"76e4fc8a.dc1b54","type":"function","z":"7d40fce6.931704","name":"Brightness Reformat","func":"m = msg.payload\nreturn {payload:\"temp(\"+m+\",6500)\"};","outputs":1,"noerr":0,"x":780,"y":160,"wires":[["c223b6f6.474938"]]},{"id":"141a5777.8b5869","type":"debug","z":"7d40fce6.931704","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":350,"y":40,"wires":[]},{"id":"23184884.aa8bb8","type":"inject","z":"7d40fce6.931704","name":"Cool white","topic":"","payload":"hsv(60.00,16.00,98.04)","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":720,"y":320,"wires":[["c223b6f6.474938"]]},{"id":"a3b43929.c8c668","type":"inject","z":"7d40fce6.931704","name":"Purple","topic":"","payload":"hsv(300,100,100)","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":710,"y":240,"wires":[["c223b6f6.474938"]]},{"id":"dc70cfe5.682e7","type":"nora-config","z":"","name":"nora config","group":"","notify":true}]

The node successfully parses colour commands in the format -

(on or off, brightness in percent, hue: x°, sat: y%, val: z%)

The attached image is the feedback from the command "Set the light to blue" -

Set the light to blue

Set the light to blue payload

The injects in the attached flow successfully set the appropriate colour/temp. I just don't know how to link the NORA node appropriately.

The first question is what format does the message need to be sent to your loxone control-out node to tell the Alfresco light to reflect the HSV values to turn it blue? Then you can use a function node, or a change and/or a template node to extract the HSV values from the Nora node and format them correctly for the loxone node. Make sense?

Edit:
I had a few minutes so grabbed your flow to see the formatting. You can use a template node to connect the Nora node to your loxone control-out to extract the H,S,V values from the Nora node and put it into the "hsv ('H','S','V')" format for your loxone node. In the template node just use this mustache template: hsv({{payload.color.spectrumHsv.hue}},{{payload.color.spectrumHsv.saturation}},{{payload.color.spectrumHsv.value}})

A couple of other suggestions:

  • Also, in place of your on/off function nodes, you can just add a step in your change node to move the msg.payload.on to msg.payload.
  • Similarly in your brightness flow, you can just replace the two function nodes with a template node using the following mustache template: temp({{payload.brightness}},6500)

Hope that helps and makes sense

Thankyou! I'm making head-way now. The Template node is very useful.

A problem I'm having is that the .saturation and .value arrive from the NORA node as values in percent. A value of 100% converts to value 1. 50% converts to 0.5.

I need to just drop the percent and have 100% convert to 100, 50% to 50.

I was successful with replacing the nodes you mentioned with Templates, however I can't turn off the light. I move msg.payload.on to msg.payload for ON.

The OFF command is value 'false' for msg.payload.on. How would I manipulate that?

I think I've worked out what's causing the OFF command problem. Because there's three paths to the Loxone node, the Off command gets there first, then very shortly after by the HSV value path. That turns it back ON to whatever the last HSV value was.

You can put in a function node to run the calculations or there is a calculation node - https://flows-new.nodered.org/node/node-red-contrib-calc That you can use.

I wondered about that when I saw your flow. I'd move from running in parallel to running in serial. You can always use Switch nodes to bypass properties that don't change.

Be aware that the default behavior in Google Actions is that you can change brightness levels and/or color irrespective of if the light is on or off. (there is a discussion going here about that - https://github.com/andrei-tatar/node-red-contrib-nora/issues/33#issuecomment-568323095) You can always override this default behavior in your flow by making it turn the light on anytime there is a change to brightness or color.

One other suggestion, is I assume you are going to want to do this for multiple lights. If so, once you have the core flow working you can turn it into a sub-flow so that it's easy to apply to other lights as a single sub-flow node.

Thanks. That link to the discussion was very helpful. I'm starting to appreciate the complexity to this can be even greater than initially anticipated...