Integrating Nora Light to Home Assistant Light [HowTo / Solved]

Tags: #<Tag:0x00007f7397b4cca8> #<Tag:0x00007f7397b4cb68> #<Tag:0x00007f7397b4caa0>

Hi There,

As I couldn’t find a succinct article on this below are a few considerations on how to control a Tasmota Light via Google Assistant through Nora and Home Assistant.

Prequel / Architecture
I have a number of Tasmotized (Sonoff) devices to control switches and lights around the house. The lights are controlled by Home Assistant and communicate via MQTT through Mosquitto Server. I further use NodeRed as an automation platform which also implements Nora as a means of controlling my devices through Google Assistant.

In my setup I decided for NodeRed to only communicate to Home Assistant to automate any behaviors (i.e. no direct comms to of NodeRed to devices via MQTT nodes). That way I know that I only need to worry about HA integration and can then automate any integrated device through the HA integration in NodeRed.

The problem
In this setup one of the challenges is the payloads received from Google Assistant commands interpreted by Nora for light controls. When you say “Hey Google, turn light x on.” or “Hey G, turn the light to 50% brightness” or “Hey G, make my light red” you get back a structure that isn’t immediately compatible with the HA Light_on Service inputs. It’s actually easy once done, but took a while to figure out…

The solution
The simple NodeRed flow below covers the conversion from NORA payload to HA Light.turn_on.
What it does:

  1. An Event_State monitors the Light state in HA and sends back the status to Google via the NORA Light Node. That way Google stays in sync with the current light state if changed in HA and not Google.
  2. The NORA Light node takes care of the Google Assistant commands and sends a payload back with state, brightness and color. I provide the HA light entity id as the topic in this node.
  3. A switch node splits the msg path based on the ‘on’ value from Nora:
    False is just passed through to the turn_off node.
    True is further processed as below.
  4. A scaling node scales the saturation value from 0-1 to 0-100 to be compatible with HA’s Light.turn_on expected value range.
  5. The ‘call service’ node Light.turn_on node contains the tiny bit of magic to pull out the relevant values from the incoming msg. Set the data field to a Jest expression and use:
{
  "entity_id": msg.topic, 
  "brightness": msg.payload.brightness,
  "hs_color": [
    msg.payload.color.spectrumHsv.hue, 
    msg.payload.color.spectrumHsv.saturation
  ]
}

This seems to work fine despite not using the V in HSV. (Happy for anyone to advise what to do with the V…).

The setup allows for Google Assistant control of:
a. on/off
b. brightness
c. colours
…in addition to having the light as a normal HA Light which allows full control from your phone.

Hope this helps

The full flow is here:

[
    {
        "id": "8b22f878.8bbf58",
        "type": "server-state-changed",
        "z": "f1ec0fc6.32285",
        "name": "Scarlett's Night Light State",
        "server": "9b3e0f74.a13fc",
        "version": 1,
        "exposeToHomeAssistant": false,
        "haConfig": [
            {
                "property": "name",
                "value": ""
            },
            {
                "property": "icon",
                "value": ""
            }
        ],
        "entityidfilter": "light.lamp_rgbw_scarlett",
        "entityidfiltertype": "exact",
        "outputinitially": false,
        "state_type": "habool",
        "haltifstate": "",
        "halt_if_type": "str",
        "halt_if_compare": "is",
        "outputs": 1,
        "output_only_on_state_change": true,
        "x": 250,
        "y": 1120,
        "wires": [
            [
                "7185d00d.5f86b"
            ]
        ]
    },
    {
        "id": "7185d00d.5f86b",
        "type": "nora-light",
        "z": "f1ec0fc6.32285",
        "devicename": "Scarlett's Night Light",
        "lightcolor": true,
        "brightnesscontrol": true,
        "turnonwhenbrightnesschanges": false,
        "passthru": false,
        "statepayload": true,
        "brightnessoverride": "",
        "roomhint": "Scarlett's Room",
        "name": "",
        "nora": "c97818ee.f9ae48",
        "topic": "light.lamp_rgbw_scarlett",
        "onvalue": "true",
        "onvalueType": "bool",
        "offvalue": "false",
        "offvalueType": "bool",
        "x": 480,
        "y": 1120,
        "wires": [
            [
                "e89d71d4.48981"
            ]
        ]
    },
    {
        "id": "e89d71d4.48981",
        "type": "switch",
        "z": "f1ec0fc6.32285",
        "name": "",
        "property": "payload.on",
        "propertyType": "msg",
        "rules": [
            {
                "t": "true"
            },
            {
                "t": "false"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 2,
        "x": 650,
        "y": 1120,
        "wires": [
            [
                "45207d5f.9ffa44"
            ],
            [
                "2cff4c8.e87f7b4"
            ]
        ]
    },
    {
        "id": "45207d5f.9ffa44",
        "type": "range",
        "z": "f1ec0fc6.32285",
        "minin": "0",
        "maxin": "1",
        "minout": "0",
        "maxout": "100",
        "action": "scale",
        "round": false,
        "property": "payload.color.spectrumHsv.saturation",
        "name": "Scale Saturation",
        "x": 800,
        "y": 1100,
        "wires": [
            [
                "89a7120b.6df35"
            ]
        ]
    },
    {
        "id": "2cff4c8.e87f7b4",
        "type": "api-call-service",
        "z": "f1ec0fc6.32285",
        "name": "Light OFF",
        "server": "9b3e0f74.a13fc",
        "version": 1,
        "debugenabled": false,
        "service_domain": "light",
        "service": "turn_off",
        "entityId": "",
        "data": "{\"entity_id\": msg.topic}",
        "dataType": "jsonata",
        "mergecontext": "",
        "output_location": "",
        "output_location_type": "none",
        "mustacheAltTags": false,
        "x": 960,
        "y": 1180,
        "wires": [
            []
        ]
    },
    {
        "id": "89a7120b.6df35",
        "type": "api-call-service",
        "z": "f1ec0fc6.32285",
        "name": "Light ON",
        "server": "9b3e0f74.a13fc",
        "version": 1,
        "debugenabled": false,
        "service_domain": "light",
        "service": "turn_on",
        "entityId": "",
        "data": "{\"entity_id\": msg.topic, \"brightness\": msg.payload.brightness,\t\"hs_color\": [\tmsg.payload.color.spectrumHsv.hue, \tmsg.payload.color.spectrumHsv.saturation]\t}",
        "dataType": "jsonata",
        "mergecontext": "",
        "output_location": "",
        "output_location_type": "none",
        "mustacheAltTags": false,
        "x": 960,
        "y": 1100,
        "wires": [
            []
        ]
    },
    {
        "id": "9b3e0f74.a13fc",
        "type": "server",
        "z": "",
        "name": "Home Assistant",
        "legacy": false,
        "addon": false,
        "rejectUnauthorizedCerts": true,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": false,
        "cacheJson": true
    },
    {
        "id": "c97818ee.f9ae48",
        "type": "nora-config",
        "z": "",
        "name": "nora config",
        "group": "",
        "notify": false
    }
]