[ST Edge] Issue with the powerMeter ST library

The default handler for SimpleMetering - InstantaneousDemand in st\zigbee\defaults\powerMeter_defaults.lua is calculating power as raw_value * multiplier/divisor = W, whereas the Zigbee spec has the calculation as raw_value * multiplier/divisor = kW. As a result, the power values in the events generated by the handler are 1000x too small.

function powerMeter_defaults.instantaneous_demand_handler(driver, device, value, zb_rx)
  local raw_value = value.value
  --- demand = demand received * Multipler/Divisor
  local multiplier = device:get_field(constants.SIMPLE_METERING_MULTIPLIER_KEY) or 1
  local divisor = device:get_field(constants.SIMPLE_METERING_DIVISOR_KEY) or 1
  raw_value = raw_value * multiplier/divisor
  device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, capabilities.powerMeter.power({value = raw_value, unit = "W" }))
end
2 Likes

Thank you for sharing your findings, @philh30. I’ll report it right away!

1 Like

I’m happy to see that the issue regarding powerMeter_defaults.instantaneous_demand_handler has been included in the latest firmware update. I haven’t tested yet, but it appears that the changes will correct the issue that I flagged above.

However, the same changes were also applied to powerMeter_defaults.active_power_meter_handler in the same file. That handler is for the Active Power attribute of the Electrical Measurement cluster. The Zigbee spec for that attribute indicates that it’s reported in Watts, so multiplying by 1,000 is unnecessary and is now causing the default handler to produce erroneous readings.

--- Default handler for ActivePower attribute on ElectricalMeasurement cluster
---
--- This converts the Int16 instantaneous demand into the powerMeter.power capability event.  This will
--- check the device for values set in the constants.ELECTRICAL_MEASUREMENT_MULTIPLIER_KEY and
--- constants.ELECTRICAL_MEASUREMENT_DIVISOR_KEY to convert the raw value to the correctly scaled values.  These
--- fields should be set by reading the values from the same cluster
---
--- @param driver ZigbeeDriver The current driver running containing necessary context for execution
--- @param device st.zigbee.Device The device this message was received from containing identifying information
--- @param value st.zigbee.data_types.Int16 the value of the ActivePower
--- @param zb_rx st.zigbee.ZigbeeMessageRx the full message this report came in
function powerMeter_defaults.active_power_meter_handler(driver, device, value, zb_rx)
  local raw_value = value.value
  -- By default emit raw value
  local multiplier = device:get_field(constants.ELECTRICAL_MEASUREMENT_MULTIPLIER_KEY) or 1
  local divisor = device:get_field(constants.ELECTRICAL_MEASUREMENT_DIVISOR_KEY) or 1

  if divisor == 0 then 
    log.warn("Temperature scale divisor is 0; using 1 to avoid division by zero")
    divisor = 1
  end

  raw_value = raw_value * multiplier/divisor

  local raw_value_watts = raw_value * 1000
  device:emit_event_for_endpoint(zb_rx.address_header.src_endpoint.value, capabilities.powerMeter.power({value = raw_value_watts, unit = "W" }))
end
2 Likes

Ooh, ok, I will mention this to the team, thank you for reviewing the modification and sharing this new issue. :+1:

1 Like