[Solved] MQTT ESPHome color channel integration

Hi guys,

I’m actually using openHAB 3.3.0 with MainUI configuration
I’m trying to integrate an ws2812b led strip driven by an ESP32 with an ESPHome firmware…

I’ve read a lot of threads about rgb conversion, but I’m struggeling with my integration.

from the ESP’s MQTT i get this string:

{"effect":"None","color_mode":"rgb","state":"OFF","brightness":85,"color":{"r":75,"g":55,"b":255}}

I already managed to bind:

  • effect → text channel
  • state → switch channel
  • brightness → dimmer channel

this is working so far… but now it get’s a little complicated

I want to get brightness and color to work with a colorwheel.

so I added:

  • color → RGB color channel

and used this JSONPATH:

JSONPATH:$.color

but this returns the whole unformatted json string

{"r":75,"g":55,"b":255}

which is not usable in this format…
or should I split the color to three different channels?

  • colorR → number channel
  • colorG → number channel
  • colorB → number channel

anyway… I think I have to create a rule to convert RGB to HSB after all, but I’m unsure what’s the best way to go from here. But before writing a rule there are some conversions possible on channel side or am I mistaking?? I’m not good in using REGEX at all but maybe there a way to convert the color string without splitting it to R,G,B first.

Maybe someone done something similar before and saves me from reinventing the wheel :wink:

I hope to get some help where and how I should convert the values.

After that my plan is to bring the values to a rule which send the converted data to a dummy color item and additionally converts the HSB values from the color item to return it to the channels.

I’m unsure which way is the most uncomplicated in OH3 to reach my goal

There is a color_mode attribute for the Color Channel that you can set to RGB and it will handle the conversion between RGB and HSB. But it’s going to expect the format of the message to “R,G,B”.

I’m not wholly certain the order of operations but you might be able to use a JS Transformation to parse out the RGB values and format them as a comma separated string. Then, if my hunch is correct, if you set the color_mode to “RGB” it will convert that to HSB automatically for you.

The JS Transformation would look something like

function(i) {
    var parsed = JSON.parse(i);
    return parsed.color.r+','+parsed.color.g+','+parsed.color.b;
}(input)
2 Likes

Thanks Rich :wink:

If I get this right, you mean to add the JS to the channel config at Transform Values/Input Value Transformations like JS:splitrgb.jswith your function in it, right?

What I dont get is how to control the brightness channel simultaniously with the color item, that’s why I thought about a conversion rule… maybe my thoughts are way to complicated :smirk: because you didn’t mention the use of a rule and a dummy item additionally…

For now I’ll try to get a pure RGB string and see how far I get

Yes.

If you send a single integer to the Color Item, it will interpret that as a brightness command and adjust the HSB as appropriate. That in turn will be converted to RGB before the command goes back out.

So in short, you shouldn’t need a separate Dimmer Item to control the brightness. Same goes for ON/OFF commands to a Color Item, so you shouldn’t need a Switch either.

However, this largely depends on how these dimmer and ON/OFF commands need to be sent to the device. If the messages are different (e.g. you can’t use 0,0,0 for OFF) you might need separate Channels.

Ok I think I have to use a rule instead…

when I use MQTT-Explorer app to send {"r":0,"g":0,"b":0} to the color channel
light turns off but state remains “ON” and brightness percentage is also not touched.

your script acts very strange I don’t get the r,g,b but the value from the HSB color items brightness ?!??
that’s really weird :flushed:

(json2rgb.js is your function)
see here:

no matter which rgb values I send to the color channel via mqtt explorer, the linked item isn’t updated!??
I added single channels for r,g and b and these are updated like expected

I also tried to change the transformation back to "JSONPATH:$.color and changed the item’s Profile to JS and linked your script

color item profile


same behavior…

seems like your script is completely ignored…

can you imagine why this real strange behavior occurs?

What would be interesting is what your bulb responds with, the other channels are not going to do anything unless there is an incoming message.

That cannot work as a color type MQTT channel cannot parse the string that you extracted {"r":0,"g":0,"b":0}, quite apart from the JS script not expecting that format anyway.

I just configured my esphome lights to publish RGB values in as “r,g,b” and this gets picked up by openhab easily.

Something like this:

      - mqtt.publish:
          topic: ${device_name}/rgb/state
          retain: true
          payload: !lambda |-
            return
              to_string((int)(id(light1)->remote_values.get_red()*255)) + "," +
              to_string((int)(id(light1)->remote_values.get_green()*255)) + "," +
              to_string((int)(id(light1)->remote_values.get_blue()*255))
              ;

and for the setting:

    - topic: ${device_name}/rgb/set
      then:
        - lambda: |-
            std::vector<std::string> colors = split(x, ',');

            if (colors.size() != 3) {
              return;
            }

            auto r = parse_number<float>(colors[0]);
            auto g = parse_number<float>(colors[1]);
            auto b = parse_number<float>(colors[2]);

            if (r.has_value() && g.has_value() && b.has_value()) {
              id(light1).turn_on()
                .set_color_mode(ColorMode::RGB)
                .set_red(r.value()/255)
                .set_green(g.value()/255)
                .set_blue(b.value()/255)
                .perform();
            }

Also can you post your full items / things definition? Although I haven’t tested it, Rich’s JS transformation should work.

However, it doesn’t seem like your Outgoing value format is going to work though. Most likely your esphome expects {"color": {"r": xx, "g": xx, "b": xx}} in the same format that it published the color data. You’ll get “255,255,255” from a color item assuming you’ve set your channel to rgb mode.

I don’t really like using a single “color” item to control power / color / brightness. I prefer having a separate item for each of those + color temperature. This way I can turn the light on/off and it retains its previous color / colortemp / brightness.

Hi rossko,

the light strip turns off… but I also wan’t to use the state (switch) channel and one channel should react to the other in my opinion. Best way for me would be the ability to use all channels, that’s why I think I should use a rule and an additional “dummy” color item.

You’re right JimT,
for this part I definately need an additional rule to convert the rgb into the json string… but this part is ignored by me for now, because I first want to focus on the incoming values and how to pass them to the color item via channel transformations.

I don’t really understand from where you copied the definitions you posted above - would be nice if you could explain exactly what you did and where…

the thing:

UID: mqtt:topic:MosquittoMqttBroker:SmartLamp
label: MQTT - SmartLamp
thingTypeUID: mqtt:topic
configuration: {}
bridgeUID: mqtt:broker:MosquittoMqttBroker
channels:
  - id: Brightness
    channelTypeUID: mqtt:dimmer
    label: Brightness
    description: ""
    configuration:
      postCommand: true
      min: 0
      qos: 2
      formatBeforePublish: '{"brightness":%.0f}'
      max: 255
      commandTopic: smart-lamp/light/smart-light/command
      stateTopic: smart-lamp/light/smart-light/state
      transformationPattern: JSONPATH:$.brightness
  - id: Switch
    channelTypeUID: mqtt:switch
    label: Switch
    description: ""
    configuration:
      commandTopic: smart-lamp/light/smart-light/command
      qos: 2
      formatBeforePublish: '{"state":"%s"}'
      transformationPattern: JSONPATH:$.state
      stateTopic: smart-lamp/light/smart-light/state
  - id: Effect
    channelTypeUID: mqtt:string
    label: Effect
    description: ""
    configuration:
      commandTopic: smart-lamp/light/smart-light/command
      allowedStates: None,Fast Pulse,Slow Pulse,Random,Flicker,Rainbow Full,Rainbow
        Double,Color Wipe,Scan,Twinkle,Random Twinkle,Fireworks
      qos: 2
      formatBeforePublish: '{"effect":"%s"}'
      stateTopic: smart-lamp/light/smart-light/state
      transformationPattern: JSONPATH:$.effect
  - id: Color
    channelTypeUID: mqtt:colorRGB
    label: Color
    description: ""
    configuration:
      qos: 2
      formatBeforePublish: '{"color":{%s}}'
      commandTopic: smart-lamp/light/smart-light/command
      colorMode: RGB
      stateTopic: smart-lamp/light/smart-light/state
      transformationPattern: JSONPATH:$.color
      onBrightness: 10
  - id: ColorR
    channelTypeUID: mqtt:number
    label: ColorR
    description: ""
    configuration:
      min: 0
      qos: 2
      formatBeforePublish: '{"color":{"r":%s}}'
      max: 255
      commandTopic: smart-lamp/light/smart-light/command
      stateTopic: smart-lamp/light/smart-light/state
      transformationPattern: JSONPATH:$.color.r
  - id: ColorG
    channelTypeUID: mqtt:number
    label: ColorG
    description: ""
    configuration:
      min: 0
      qos: 2
      formatBeforePublish: '{"color":{"g":%s}}'
      max: 255
      commandTopic: smart-lamp/light/smart-light/command
      stateTopic: smart-lamp/light/smart-light/state
      transformationPattern: JSONPATH:$.color.g
  - id: ColorB
    channelTypeUID: mqtt:number
    label: ColorB
    description: ""
    configuration:
      min: 0
      qos: 2
      formatBeforePublish: '{"color":{"b":%s}}'
      max: 255
      commandTopic: smart-lamp/light/smart-light/command
      stateTopic: smart-lamp/light/smart-light/state
      transformationPattern: JSONPATH:$.color.b

I dont know how to get to the items yaml??

Well, let’s try again. What messages does your light strip send over MQTT when it turns off? Are those going to update your ‘switch’ channel? (Why would you expect openHAB to do that, unless you code it to do it)
When we know what the actual message is that you’d like to affect multiple channels, then there’ll be advise about the way to do it.

only the channel that was changed - I don’t know how to describe that… when I change the state channel from OFF to ON only the state changes and if I change brightness only brightness changes…

all channels are in the same mqtt topic
{"effect":"None","color_mode":"rgb","state":"OFF","brightness":85,"color":{"r":75,"g":55,"b":255}}

but when changes are made by a colorpicker brightness and color should change
when I change the rgb to 0,0,0 the state is still ON but should be OFF.

Alright. This about understanding the behaviour of your device and mapping that to your openHAB Item(s).

So for example -

you would want this message to extract the OFF part, and use to update whatever Item(s) you have in openHAB.
If you’ve got a Color, you’ll want the brightness updated to 0
If you’ve got a Dimmer, same
And of course a Switch to OFF.
If you’ve chosen to have the same device linked to all three Items, you’ll need extra channels to do this work.
Notably you can link multiple channels to one Item.
So for your one Switch Item, you can “listen” for state=OFF and separately “listen” for brightness=0 (with a suitable transformation) on two channels.

I think first perhaps decide if you really want multiple Items - I’d be trying with just one Color Item myself.

For outbound commands, you would need to transform OFF into a 0,0,0 rgb etc. if your device cannot handle OFF. Again this about understanding what your device can do.

According to the docs for the MQTT binding, it should retain at least the color and saturation. The brightness though is a fixed value when you command it from OFF to ON.

color and saturation are preserved from the last state, but the brightness will be set to this configured initial brightness (default: 10%).

How’s it supposed to know? There’s nothing inherent about MQTT Channels that tied them together. If the device doesn’t send the OFF message when you turn it OFF through the Color Channel, how’s the MQTT binding supposed to know? The Channel is tied to a specific message on a specific topic.

Not necessarily. The outgoing format and/or an outgoing JS transform should be able to build the proper JSON for the outgoing message. However, if you want to keep the Items tied to these separate Channels in sync and your device doesn’t publish a message with its new states after responding to a command, you will have to use a rule.

But I can’t believe that ESPHome doesn’t publish a new state message after changing state from any source, including an MQTT message.

Unfortunately there isn’t one. Items consist of multiple records from multiple sources and there is no easy way yet to consolidate an Item into a single YAML representation.

What message do you get back when you change the RGB to 0,0,0? How are you changing the RGB to 0,0,0? What is the actual message that gets published for formatBeforePublish: '{"color":{%s}}'? Is it valid?

There is an order of operations involved in Generic MQTT Things for outgoing messages and it’s not well documented. It seems possible that you’ll still be getting the HSB values for the %s. At a minimum it will definitely be R,G,B format as opposed to the JSON format ESPHome expects.

So I strongly suspect, like @JimT pointed out, that the command you are sending to the ESPHome through the color Channel is bogus and since the ESPHome can’t interpret it, it doesn’t change state and there’s no message back to OH to tell the other channels to change since the light never changed in the first place.

The only reason the Item linked to the Color channel changed is because of autoupdate.

You need to have MQTTExplorer (or something like it) to monitor the actual MQTT messages being sent back and forth. If those are not right, it’s not going to work.

hmm I think that’s not what should happen - in my understanding brightness is a part of HSB colorpicker so the HSB e.g. 78,100,68 should be converted to RGB+Brightness or am I wrong??

If I get this right I’m able to bind color, brightness and state channel to one color item?
and the colorpicker decides what to do`?

Sure, I don’t blame the device or openhab I just want to find a solution to properly configure the thing to act like I think it should work e.g. a rule or something that does these changes to avoid inconsistencies.

I only want to get the colorpicker working (HSB to RGB) and that the power switch is also working.
Can I achieve this by binding multiple channels to the colorpicker and use channel transformations?

I don’t do this with openhab I use mqtt-explorer to do so for testing purposes… as I wrote above I didn’t come so far for now to check the outgoing part…

I think you need to adopt a mental approach here.

The colorpicker is the interface between GUI and a standard Color Item.
It neither knows nor cares one jot about MQTT or rgb. Not at all. Just standard Color Item.

Channels and transforms is all about interfacing some more or less weird rgb device to a standard openHAB Color Item. It neither knows nor cares if you are going to use that with a colorpicker or elaborate rules or keep the whole thing a secret.

It’s two separate areas, each can be approached separately.

What features of your standard Color Item would you like to see in your GUI? The Color Item itself can handle colour controls; or just brightness controls; or just on/off controls.
I’d assume you want at least the possibility of all three.

So then we can focus on interfacing a standard Color Item to your MQTT device.

Not quite.
You can have three color type channels that extract different bits of your JSON, and each can send hsv updates to your one Item.

It’s more obvious if you look at the simpler case, have three switch channels for one Switch Item, one looks for state=OFF, one looks for brightness=0, one looks for rgb=0,0,0, all pass OFF to the Item.

I think you should avoid all that by using just one Color Item, not multiple Items.

Yes, assuming the device publishes messages when it changes state and the commands sent by the Color Channel are valid and the device actually changes state in response to them. I’m pretty certain, as currently configured above, the messages being sent by the Color channel is not something the ESPHome can interpret.

Until you get the outgoing part working, the synchronization between the Channels will never work because the ESPHome will not be publishing that message with its new state.

You’re probably right Rossko,

That’s why I asked for the best solution in OH3 to get the colorpicker working that I can switch ON OFF change color and brightness…

Yes but I can see what happens in mqtt-explorer when sending commands to the subtopics