[Solved] MQTT ESPHome color channel integration

Okeydoke, give us a clue? What messages do you need to send for the various actions?
If you command say brightness 0 to a Color Item, that’s exactly what gets passed to the binding, 0. We can use transformations if you need to change that into OFF or off or 0.0.0 for sending to the device, but need to know which is wanted.

1 Like

Ok there are two problems for me…

one is I don’t understand how a color channel in rgb mode should send the brightness to the brightness channel beside sending color to the rgb channel - and while english is not my main language it’s sometimes really hard for me to say exactly what I wan’t - I don’t get what’s the difference of a color channel in rgb vs in hsb mode - I mean technically - If the color item works with hsb and is converted to rgb where is the brightness gone then?? I have One controller but two channels to feed.

on the other hand I don’t want to complicate things I just want a simple solution for my problem. integrate the rgb into a color channel plus a fully working colorpicker… It feels like running in circles to discuss this, because I thought I had explained what I want to achieve, but the only thing I get is explanations about how things basically work. but that don’t brings out a solution for my problem.

To be honest I don’t know how to explain any further what I want in my eyes everything was explained before. But it seems there’s no easy solution to get the colorpicker running.

From OH I can control the effect channel, the brightness, turn the device on and off - only thing that is not working is the color item with the colorpicker.

don’t get me wrong I appreciate the help from you guys, but It’s sometimes hard to communicate

In RGB, brightness isn’t a separate property. If you have and RGB of 100,100,100 (a middling gray color) and want to increase the brightness by 10%, the RGB becomes 110,110,110 (a lighter gray color). That’s it. All brightness possibilities are represented in the RGB values directly.

HSB is a completely different coordinate system to represent color. If you ever took advanced math, think of it like the difference between doing trigonometry in radians versus degrees. Depending on which system you are working in you’ll come up with completely different numbers to represent the same value. Same thing is happening here. Instead of a value for red, green, and blue, a color is chosen using a hue, saturation, and brightness value.

Like you have with radians and degrees, it’s possible to convert one to the other.

So where does the brightness go? It goes into new RGB values. It’s not a separate coordinate in RGB like it is in HSB.

tl;dr: when the brightness goes up, the RGB values uniformly go up. When the brightness goes down, the RGB values uniformly go down. Brightness is encoded in the RGB values, it’s not a separate independent value.

And we want to help you get there. But we don’t have enough information. And when we ask for the information we need to figure out why it’s not working the way it should you say that’s not something you care about right now. You may not care but we do. We need that information to understand where it’s going wrong.

So all we can do is what we have done and explain.

Let’s go back to the original post.

OK, fine and correct. Indeed this won’t work because the MQTT binding expects “75,55,255”, not ‘{“r”: 75,“g”:55,“b”:255}’. It can’t convert the RGB to HSB until you transform that JSON to the right format.

A rule is not required.

You don’t need to transform the RGB to HSB, you need to convert ‘{“r”: 75,“g”:55,“b”:255}’ to “75,55,255”.

REGEX is not required.

Note the word “transform” has shown up again. See my first reply which has a JS transformation that does in fact convert the full incoming message from the JSON to “75,55,255”.

This would in fact be the least complicated path to reach your goal.

This seems to be where things break down.

You don’t need a separate brightness channel. It can all be handled by the Color channel. You could have a separate brightness Channel, but it’s not going to be used from the Color Picker widget. You’ll need a separate widget for that (usually a slider).

When you adjust the brightness from the Color Picker widget, it will change the HSB values (the brightness value) which will in turn be translated to a new RGB value which gets sent to the device. Brightness is not separately and independently represented in the messages sent to the device.

Now, if you do decide to have a separate Channel and Item for each of the brightness and color Channels, the way they stay in sync is through the update messages from the device on the state topic.

Changing the brightness:

Brightness Item -> Brightness Channel -> MQTT Command Message -> Device changes brightness -> MQTT State Message -> Color Channel gets new RGB and translates that to a new HSB -> Color Item

Changing the color:

Color Item -> Color Channel -> MQTT Command Message -> Device changes color -> MQTT State Message  -> Brightness Channel gets new brightness value -> Brightness Item

No rules. Nothing complicated is involved.

But thats why we are asking about the outgoing messages and what’s going on in MQTTExplorer and such. For this to work, that end-to-end set of messages and conversions need to be correct and work.

What’s the message the device publishes on the state topic after receiving that command?

Which is caused by a problem with either the outgoing messages or the incoming messages from the device. But when we asked for those we only got partial answers that confused us.

Maybe this is the root source of the confusion. As described above, there is no such thing as RGB+Brightness. The brightness is encoded in the RGB. When you are using RGB there isn’t a separate representation for brightness.

That’s a big reason why OH uses HSB. It’s much more intuitive from the human perspective to work with those coordinates than RGB.

But I suspect if we had a few “when I do this in the color picker, this message gets published and this message comes back” examples we could tell you exactly what to do. But we don’t have those so all we can do is peck around the outside of the problem.

1 Like

Hi Rich

Yes you’re right that’s what confused me…

so were do we go from here - I think at first I should correct the outgoing transformation in order to produce something the ESP can read. So I need to convert the RGB to the JSON string

{"r":xx,"g":xx,"b":xx}

maybe this should do the trick

(function(i) {

    var rgb = i.split(",");
    var color = {"r":rgb[0],"g":rgb[1],"b":rgb[2]};
    var strg = JSON.stringify(color);
    return strg;

})(input)

the next step would be to fix the input side where the channel gets the information from mqtt.
maybe I can use your script example there (don’t know why it’s not working right now)

Ill try that now and be back in a minute…

We could make this transformation even smarter and if it sees a 0,0,0 RGB (assuming it gets the RGB values instead of the HSB values which needs to be confirmed) it also sends an OFF as part of the message. Brightness will take some additional calculations I think, maybe not worth it.

Anyway…

That looks reasonable. But you should be able to see exactly what it’s doing by watching the logs and watching the messages themselves.

And just to add my usual rant. IMO devices that force MQTT clients to encode/decode stuff in JSON are doing it wrong. The organization that manages the MQTT standard has a set of guiding statements when it comes to MQTT and one of the more important ones is “A publisher should not impose work on the clients.” ESPHome is imposing a whole ton of work on the client by using a flat MQTT topic hierarchy and JSON formatted messages.

This integration would be so easy if each part of the JSON were broken out into separate topics.

1 Like

Ok I got it working now :see_no_evil: sorry guys - but I definately could have sworn that rgb needs additional brightness control - that’s my fault :weary: that’s why i asked how to combine those channels…

I would have never opened this thread if I would have realized that before - now everything’s a lot clearer.

the color part of thing looks like this now:

  - id: Color
    channelTypeUID: mqtt:colorRGB
    label: Color
    description: ""
    configuration:
      qos: 2
      transformationPatternOut: JS:rgb2string.js
      formatBeforePublish: '{"color":%s}'
      commandTopic: smart-lamp/light/smart-light/command
      colorMode: RGB
      stateTopic: smart-lamp/light/smart-light/state
      transformationPattern: JS:json2rgb.js
      onBrightness: 10

rgb2string.js

(function(i) {
    var rgb = i.split(",");
    var color = {"r":rgb[0],"g":rgb[1],"b":rgb[2]};
    var strg = JSON.stringify(color);
    return strg;
})(input)

json2rgb.js

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

the only stupid thing is if I use the color item to switch between ON and OFF the lightstrip don’t lights up again by the ON signal it remains dark until I use the colorwheel. When using the state channel instead for ON OFF the settings are restored immediately.

mqtt-explorer shows switching between {“r”:0,“g”:0,“b”:0} and previous values, but the strip remains dark.

beside that everything seems to work properly! sorry again for me misunderstanding how rgb works!

thanks a ton for your patience!

Use MQTT Explorer to tell us what message is sent in each case, so we can tell what your device wants.

1 Like

when using the state item switch:
{"state":"OFF"} or {"state":"ON"}
and color remains {"color":{“r”:250,“g”:166,“b”:0}}

when using the color item switch:
{"color:{“r”:0,“g”:0,“b”:0}} or {"color":{“r”:250,“g”:166,“b”:0}} for example,
and state remains {"state":"ON"}

Okay, so when you command OFF to your Colour Item, you will need a fancier transformation in your color type channel. Probably a JS javascript because it has to make decisions.

Outline -
When the command is OFF, send payload {"state":"OFF"}
Else when the command is ON, send payload {"state":"ON"}
// space here to deal with brightness //
otherwise, send the RGB payload {"color:{“r”:0,“g”:0,“b”:0}}

Would be nice to understand which command is inbetween - does the color item send an OFF or a 0,0,0 or a simple 0?? Just to understand more of what’s happening under the hood…

Is this converted by the channel or on the item side?

Hmmmm, does the transformation see the command? I think it only sees the state so we might have to be sneaker in the transform.

If the state is 0,0,0 send the {"state":"OFF"} as the command.

But what’s going to happen when that state message comes back? Because the RGB values don’t change, will the light turn back on?

It’s converted by the Channel/Binding. The Item gets the OFF command and the binding translates that to 0,0,0. The Item doesn’t have enough information to figure out what to do with those commands so it’s up the binding.

And what the MQTT binding does with it depends on how the Channel is configured.

I see a problem while sending it to the right json value

right now I’m using

'{"color":%s}'

as format before publish. transformation… but if I try to change 0,0,0 to OFF the format before publish should have been changed to

'{"state":%s}'

I think the only way would be to do the whole conversion in the script and remove the format before publish entry completely

what do you think??

maybe something like this:

(function(i) {
    var rgb = i.split(",");
    var color = {"r":rgb[0],"g":rgb[1],"b":rgb[2]};
    var strg = JSON.stringify(color);
    if (i == 0,0,0)
    return {"state":"OFF"};
    else
    return {"color":strg};
})(input)

Yes, you’ll want to do it in the JS transform. The format field won’t be smart enough to have an “if this else that” type of formatting.

Needs to be i == '0,0,0' since i is a String.

I have problems quoting the strg…

(function(i) {
    var rgb = i.split(",");
    var color = {"r":rgb[0],"g":rgb[1],"b":rgb[2]};
    var strg = JSON.stringify(color);
    var off = '{"state":"OFF"}';
    var json = '{"color":strg}';
    if (i == '0,0,0')
    return off;
    else
    return json;
})(input)

this is what I got so far but when I change color or change the color item switch to ON the mqtt command is
{color:strg}

I also tried var json = '{"color":'strg'}';

but this isn’t the right way to quote this…

You want the value of the variable strg, not the literal “strng” so it needs to be outside the quotes.

var json = '{"color":' + strg + '}';

thanks :wink: omg this is weirder than I thought…

now when I switch OFF via color item switch, both switches turn off.
but after switching back to ON via color item switch, the state item switch remains OFF
the color command is received correctly but is ignored by the device because the state is still off :see_no_evil:

So changed everything but same behavior except the fact that now the state item switch turns off instead of a 0,0,0 command

It’s very late here now I think I go to sleep and think about that tomorrow - thanks a lot for now!!

When you come back, post the MQTT messages sent and received in these cases. Just based on the descriptions it’s too hard to follow along.

Probably should have asked this earlier, but does ESPHome only support these messages and MQTT topic structure? Maybe there’s an easier way from OH’s perspective.

I think so… we will see tomorrow :wink:

We need to keep clear which direction we are talking about at each moment.

For outbound commands, it’s the command that arrives at the channel.
So a Color Item may pass commands of form OFF, or 50 (brightness), or 127,56,50 (HSB)
Clearly we can write a transform to analyze the command and deal with each case, bit fiddly.

It’s not clear to me how much the “helpful” features of a color type MQTT channel are going to get in the way here, i.e. attempting to do a rgb conversion of an OFF that we do not want, if our device understands an actual ‘off’.
It might need a string type channel to stop the “helping”.

Also the incoming transform will be completely different - although we need it doing roughly the inverse, e.g. interpreting state=ON into an HSB update for the Item.

Yes.

Well, the other way is to have no MQTT channels at all handling commands (just handling incoming), and instead have a command-triggered rule generate payloads and send by Action from rule. It’s a little easier to develop and debug.