Correctly calculate lux values at Xiaomi Aqara Motion Sensor's illuminance channel

Tags: #<Tag:0x00007f5c9dc0e080>

Dear all,

thanks for the awesome openHAB software and the great and helpful community! Here’s a small contribution I can return.

I’ve played around with the said Aqara devices for a while now and have also seen the very small values for the illuminance channel. I’ve found various threads in the community suggesting to just multiply it by 10.000 to get the lux value. I believe that’s incorrect. You rather need to revert a transformation which is designed in the Zigbee spec but incorrectly implemented in the device.

Just add a custom transformation, e.g. by using a JavaScript Transformation as follows, and you’ll receive the correct value in lux.

function log10(val) {
  return Math.log(val) / Math.log(10);
}

(function(i) {
  var measuredValue = parseFloat(i);
  if(isNaN(measuredValue)) return "- lx";
  var illuminance = 10000*log10(measuredValue+1);
  return illuminance.toFixed(0) + " lx";
})(input)

For details see here: https://github.com/openhab/org.openhab.binding.zigbee/issues/573

Cheers!

1 Like

Thank you for investigation.
I will try to add this to my setup.

I know my question is not related to the correct calculation itself, but more to the Javascript transformation service.
May I ask how your items looks like and how you handle the calculated lux values in rules?

String <itemName> { channel="<channelUID>"[profile="transform:JS", function="<filename>", sourceFormat="<valueFormat>"]}

The given above will give the result of the calculation as string type, but in rules I want to compare numbers which each other.

You may use the transformation in an item like this:

Number MyItem "Illuminance [JS(TransformationScript.js):%s]" {channel="zigbee:device:***:***_1_illuminance"}

In rules I calculate the value separately again because it’s fairly easy to do so.

I wonder if the reason you got a string type was because your item type is a String item type?

In other words, what if instead of:

String <itemname> .....

you use:

Number <itemname>

Would that solve it?

How to you convert the returned value of the transformation to a number? Please could you give an example how you calculate and compare this value in a rule.

@JimT: I’ve tried to do so.
Therefore I’ve changed the script slightly to return a number instead of a string, but I’m even not sure if a number is returned.

function log10(val) {
return Math.log(val) / Math.log(10);
}

(function(i) {
var measuredValue = parseFloat(i);
if(isNaN(measuredValue)) return 1;
var illuminance = 10000*log10(measuredValue+1);
return illuminance;
})(input)

String MyItem “Illuminance” { channel=“zigbee:device:***_1_illuminance”[profile=“transform:JS”, function=“aqaraLuxCalc.js”]}

Number MyItem “Illuminance” { channel=“zigbee:device:***_1_illuminance”[profile=“transform:JS”, function=“aqaraLuxCalc.js”]}

The String Item will have the correct value, but the Number Item has always the value 1.0


Based on that post the JS Transformation always returns a String value.

To expand a bit, all of the Transformation services always return a raw string.

When you use a transform within a binding, the binding is written to parse the string return into whatever form the channel requires.
For example, it is possible to process an incoming MQTT payload in a transform, and the binding deals with converting the transform’s string output into a number for a number channel.
The binding author has to write code to support all this, and so not all bindings support transforms.

The transform profile does not currently implement any conversion on return string, so it really only works with String type Items. That’s a shame, but that’s how it is today.