xoseperez / espurna

Home automation firmware for ESP8266-based devices
http://tinkerman.cat
GNU General Public License v3.0
2.98k stars 635 forks source link

Openhab 2.4 MQTT: Dimming 0-100% instead of 0 to255 #1460

Closed flashy02 closed 3 years ago

flashy02 commented 5 years ago

Hello everybody, with the new Openhab release 2.4 a new MQTT binding is used, so the workaround of using an transformation for a channel/dimmer before publishing a dimming-value is no longer possible. With this, only values from 0-100% where published from a Dimmer-Item. In the past i thought several times about it, why it is possible to use HSB values for a RGB channel where it is normal to use a value between 0-100% for the brightness-channel, but if I want to use the channel directly, it is neccesary to use a value between 0-255 (8bit). The Feature request would be, to get a switch in the web-interface to change the channels/brightness from 0-255 behavior to 0-100% behaviour for MQTT, so no transformation in Openhab is neccesary.

Best regards Flashy

davebuk commented 4 years ago

Out of interest, I built a version and included

#define LIGHT_MAX_VALUE         100
 #define LIGHT_MAX_BRIGHTNESS   100

Although this works using espurna and openHAB, to get the Google assistant to recognise the device, I had to set the device in the '.items' file to a DIMMER rather than NUMBER type. The problem was, when espurna MQTT received the command from openHAB, espurna seemed to convert it to a decimal number <= 1. This meant at 100%, the channel#0 recevied the value 1, not 100.

mcspr commented 4 years ago

Can you give an example of MQTT interaction?

Lights module stores channel and brightness values in kv storage as ch0 and brightness and in RAM between resets. Old values could be >100 since there are no constrains applied when loading them, both need to be manually changed at least once.

davebuk commented 4 years ago

I have setup another openHAB channel that uses the mqtt brightness rather than channel#0 so as to not effect my current setup too much. Using 'REST API' to send to numerical value to the openHAB item, the openHAB log file shows:

2019-12-04 19:24:30.794 [ome.event.ItemCommandEvent] - Item 'LED001_brt_test' received command 100

2019-12-04 19:24:30.801 [nt.ItemStatePredictedEvent] - LED001_brt_test predicted to become 100

2019-12-04 19:24:30.806 [vent.ItemStateChangedEvent] - LED001_brt_test changed from UNDEF to 100

2019-12-04 19:25:08.168 [ome.event.ItemCommandEvent] - Item 'LED001_brt_test' received command 75

2019-12-04 19:25:08.170 [nt.ItemStatePredictedEvent] - LED001_brt_test predicted to become 75

2019-12-04 19:25:08.178 [vent.ItemStateChangedEvent] - LED001_brt_test changed from 100 to 75

2019-12-04 19:26:45.809 [vent.ItemStateChangedEvent] - LED001_brt_test changed from 75 to 0

espurna's log shows:

[014813] [MQTT] Sending LED001/brightness => 255 (PID 1)
[014820] [MQTT] Sending LED001/vcc => 3494 (PID 1)
[014823] [MQTT] Sending LED001/status => 1 (PID 1)
[014829] [MQTT] Sending LED001/loadavg => 1 (PID 1)
[179867] [MQTT] Received LED001/brightness/set => 1.00000000
[179971] [MQTT] Sending LED001/channel/0 => 0 (PID 1)
[179972] [MQTT] Sending LED001/brightness => 1 (PID 1)
[217238] [MQTT] Received LED001/brightness/set => 0.75000000

Trying to send a number greater than 100 fails, I guess as its a 'Dimmer' item rather than a 'Number' item.

Perhaps although openHAB's log says its sending 100 or 75, it may only be sending the percentage 1 or 0.75 rather than a number.

davebuk commented 4 years ago

I have just tried the app 'MQTT Dash' as a separate MQTT input. That just sends the numerical value to the topic. This works fine. Sending any number between 0 and 255 is received by espurna, shows that value and updates the value on the status screen correctly. It must be an openHAB issue.

mcspr commented 4 years ago

So does that mean transformation on openhab side is possible after-all? Re:

workaround of using an transformation for a channel/dimmer before publishing a dimming-value is no longer possible.

Log is confusing, why it is a 0...1 suddenly. MQTT only handles the integer part of the number, so anything after the dot is silently dropped (at least it is how I remember String::toInt() aka strtol error handling works for partially parsed strings).

davebuk commented 4 years ago

I think I read once about transformation issues directly with the mqtt add-on binding, but I guess by using proxy items openHAB will use those values via the proxy item to the mqtt binding.

I'll try and get some more espurna logs if that helps?

ColinShorts commented 4 years ago

If it helps, I've been using openhab and mqtt (mosquito) with espurna for a while now... This is how I handle the dimmers:

colin@openhab2:/etc/openhab2$ grep big items/light.items
Dimmer Light_FF_Living_BigLight_dimmer "Big Light [%s]" <light> (Living,Lights,LightDimmers) [ "Lighting" ]  {mqtt=">[mosquitto:light/ff/livingroom/big/channel/0/set:command:*:JS(espurna-dimmer.js)]"}

colin@openhab2:/etc/openhab2$ cat transform/espurna-dimmer.js
(function(i) {
        if(i >= 0) {
                return i / 100 * 255;
        } else if (i == "ON") {
                return 80;
        } else if (i =="OFF") {
                return 0;
        } else {
                return null;
        }
})(input)

It's probably not all that pretty, but it seems to work ok for me with either Alexa or Google Assistant.

Edit: trimming some spaces

davebuk commented 4 years ago

Thanks @ColinShorts . Using the .js transform code above, would that require me to use the JSON payload function of espurna mqtt instead of the standard single mqtt entries? I'm unfamiliar with the :command:*:JS part. Will that just use the code in the .js file to produce a number that gets passed to the binding?

mcspr commented 4 years ago

Judging from the light/ff/livingroom/big/channel/0/set:command part, it is only scaling values sent from openhab to espurna? If the user wants to avoid transform hook, which scale should we use for percentage? 0 to 1 or 0 to 100? Would it be a DIMMER device?

ColinShorts commented 4 years ago

I could have provided a bit of context, and a different example. The device is an intermitech quinled esp-01 based 2 channel dimmer. I'm only using a single channel in ceiling lights although that doesn't really matter in this context.

Here is an example showing two way communication:

Dimmer Light_SF_UpperGuest_dimmer  "Upper Guest Dimmer [%s]" <light> (UpperGuest,Lights,LightDimmers)  [ "Lighting" ]  {mqtt=">[mosquitto:light/sf/upper-guest/channel/0/set:command:*:JS(espurna-dimmer.js)],<[mosquitto:lig
ht/sf/upper-guest/channel/0:state:JS(espurna-dimmer.js)]"}

As everything had been going through openhab, and I have no physical controls that talk to the devices directly*, openhab keeps track of the values.

davebuk commented 4 years ago

Log is confusing, why it is a 0...1 suddenly. MQTT only handles the integer part of the number, so anything after the dot is silently dropped (at least it is how I remember String::toInt() aka strtol error handling works for partially parsed strings).

I think that may have been due to the light being turned off at the time. See output below:

[703915] [MQTT] Received LED001/brightness/set => 39
[704019] [MQTT] Sending LED001/channel/0 => 0 (PID 1)
[704020] [MQTT] Sending LED001/brightness => 39 (PID 1)
[709225] [WEBSOCKET] Requested action: relay
[709226] [RELAY] #0 scheduled ON in 0 ms
[709230] [RELAY] #0 set to ON
[709233] [MQTT] Sending LED001/relay/0 => 1 (PID 1)
[709334] [MQTT] Sending LED001/channel/0 => 39 (PID 1)
[709335] [MQTT] Sending LED001/brightness => 39 (PID 1)
[710235] [RELAY] Setting relay mask: 0b1
[717477] [MQTT] Received LED001/brightness/set => 49
[717581] [MQTT] Sending LED001/channel/0 => 49 (PID 1)
[717582] [MQTT] Sending LED001/brightness => 49 (PID 1)

The strange thing is, by changing brightness via mqtt both brightness and channel#0 values get updated and that can be seen in the output:

[013902] [MQTT] Sending LED001/channel/0 => 255 (PID 1)
[013903] [MQTT] Sending LED001/brightness => 255 (PID 1)
[025660] [MQTT] Received LED001/brightness/set => 52
[025764] [MQTT] Sending LED001/channel/0 => 52 (PID 1)
[025765] [MQTT] Sending LED001/brightness => 52 (PID 1)

But the webUI still shows the original 255 value for channel#0, even after refreshing the page. I then changed the webUI slider from 255 to 136 (just a random position) and the output gives:

[296902] [WEBSOCKET] Requested action: channel
[297005] [MQTT] Sending LED001/channel/0 => 27 (PID 1)
[297006] [MQTT] Sending LED001/brightness => 52 (PID 1)

Changing channel#0 slider back to 255 sets channel#0 back to 52:

[405269] [WEBSOCKET] Requested action: channel
[405372] [MQTT] Sending LED001/channel/0 => 52 (PID 1)
[405373] [MQTT] Sending LED001/brightness => 52 (PID 1)

Should channel#0 follow brightness? Should channel#0 not be used at all and just use brightness control for a single dimmer?

davebuk commented 4 years ago

From a openHAB and espurna integration point of view, by setting the definitions #define LIGHT_MAX_VALUE 100 #define LIGHT_MAX_BRIGHTNESS 100 espurna can act as a percentage dimmer working with values between 0-100%. I think openHAB should output the whole number value rather than the decimal 0.0-1.0. Using the transformation code, it should be as simple as taking that openHAB number and /100 or *100 depending on if its an in/out, stateTopic/commandTopic command.

davebuk commented 4 years ago

I should add to this thread, using openHAB rules and proxy items my dimmer works fine. Percent is converted to number (0-255) and sent to channel#0, and channel#0 (0-255) changes are converted to percent. With Google I can request a percent change and the corresponding 0-255 value is sent to the device via openHAB and mqtt.

What I was looking for (so was @flashy02) was a direct interaction with openHAB and espurna when the item is of type 'DIMMER'. openHAB item type 'COLOR' uses percentage HSB values to send a value between 0-100 without having to use rules or transformations but a single channel dimmer only uses the 0-255 values.

davebuk commented 4 years ago

If the user wants to avoid transform hook, which scale should we use for percentage? 0 to 1 or 0 to 100? Would it be a DIMMER device?

I have setup a rule to output the value of the 'DIMMER' item to a log entry. Regardless of whether its set to log as 'string' or 'number' changing the value to 50 logs 50, 75 logs 75 and 100 logs 100 etc. In espurna's logs it shows 0.50000000, 0.75000000 and 1.00000000. Disabling mqtt on espurna (to stop the value being set to 0 by the stateTopic update) and then querying the openHAB items state value using REST API, it reports the 50, 75, 100 etc values. I don't know how the percent value of 50 from openHAB gets interpreted as 0.5 by espurna?

mcspr commented 4 years ago

Hm. So looking at the mqtt.generic readme: https://github.com/openhab/openhab2-addons/tree/master/bundles/org.openhab.binding.mqtt.generic

dimmer: This channel handles numeric values as percentages. It can have min, max and step values.

https://community.openhab.org/t/mqtt-homie-dimmer-item-value-scale/77362/38

The range can be configured. 0-1 could be the default depending on your version.

So the dimmer should probably work even with 0...255 when setting min= max= and step= attributes


colorRGB / colorHSB is another matter, but does it not work like that already? https://github.com/xoseperez/espurna/blob/a2599de4d11481ba9f9712087472ee63bc7e9a7f/code/espurna/light.ino#L267-L270 HSB(V) matches with the 360,100,100 syntax mentioned in the readme of the mqtt.generic RGB is inherently 0...255

davebuk commented 4 years ago

All working!! Read on and thanks for your assistance. :-) WRT HSB(V) yes, using item type 'COLOR' works fine when sending/receiving the 360,100,100 string, but a single channel dimmer in espurna, I guess, wouldn't know what to do with that number format if sent to channel#0. Is that correct?

I upgraded from 2.4.0 to 2.5.0M6 but that made no difference. Although the openHAB item is set as a dimmer, I had the thing/channel defined as a 'NUMBER' type. I have changed it to a 'DIMMER' type and espurna now sees the correct numerical value: https://www.openhab.org/addons/bindings/mqtt.generic/

[013833] [WEBSOCKET] Requested action: brightness
[013936] [MQTT] Sending LED001/channel/0 => 255 (PID 1)
[013937] [MQTT] Sending LED001/brightness => 255 (PID 1)
[045221] [MQTT] Received LED001/brightness/set => 26.0
[045325] [MQTT] Sending LED001/channel/0 => 26 (PID 1)
[045326] [MQTT] Sending LED001/brightness => 26 (PID 1)

dimmer: This channel handles numeric values as percentages. It can have min, max and step values. So the dimmer should probably work even with 0...255 when setting min= max= and step= attributes

This works correctly now I have set the 'thing' type to 'DIMMER' instead of 'NUMBER'. I set the min/max to 0/255 with a step of 1. Using the 'SLIDER' item within the sitemap (which is a 0-100% slider), espurna receives the 0-100% value between 0-255.

mcspr commented 4 years ago

WRT HSB(V) yes, using item type 'COLOR' works fine when sending/receiving the 360,100,100 string, but a single channel dimmer in espurna, I guess, wouldn't know what to do with that number format if sent to channel#0. Is that correct?

Yeah, that would not work with a single channel device.

But do we still want to have configurable min= and max= from ESPurna side? Maybe even combining brightness and value max into one setting. fwiw scaling already happens whenever light module wants to output something, just a matter of making sure nothing internally tries to use hardcoded 255 and adjust it to a proper limit

WebUI can receive the same changes as #1941, adjusting input type=range limits

davebuk commented 4 years ago

Personally, with the knowledge I now have, it doesn't probably matter. I read multiple times about DIMMERS in the openHAB setup, but it took a while to sink in what the actual configuration does setting up min/max/step values in the openHAB 'THING' to match the hardware configuration.

I guess from a new user point of view 0-100 makes more sense than 0-255. Is it something that can be added to the espurna v2 code and adjusted in the webUI rather than re-compiling using #defines? Could 'Light' offset type values for colour and brightness be adjusted similar to the calibration settings used when setting up a power monitoring device? That way, if someone really wanted to, they could force their light to, dim to or brighten to a fixed value while their home automation software would still use the 0-100% range.

CrappyTan commented 3 years ago

This can be closed as there is a native way of doing this:

Type dimmer : dimmer "Dimmer" [stateTopic = "home/lights/bathroom/led/LED_BATHROOM_BASIN/brightness", commandTopic = "home/lights/bathroom/led/LED_BATHROOM_BASIN/brightness/set", min=0, max=255 ] The min/max will cause the binding to scale the OH value of 0-100 to match that of the min-max. This happens on both publish and received.

mcspr commented 3 years ago

Closing via https://github.com/xoseperez/espurna/issues/1460#issuecomment-703143927 & https://github.com/xoseperez/espurna/wiki/MQTT#openhab (In case there are more things to be aware of, perhaps a separate page + sidebar link would be more discoverable)