core icon indicating copy to clipboard operation
core copied to clipboard

Device class energy is missing some valid native units of measurement, generating warnings in logs.

Open nkinnan opened this issue 1 year ago • 10 comments

The problem

Edit: made a few changes and ran more tests after noticing additional device classes and measurement types, but the issue persists. Please see the additional comment that follows.

For AC power measurement there are several units of measurement which generate warnings in the logs. HomeAssistant seems to support what ESPHome supports, which varies by device_class. Currently, the "energy" device class supports the following:

['Wh', 'MJ', 'MWh', 'kWh', 'GJ']

This is enough for simple "dumb" devices which do not account for power factor and reactive energy. This is usually enough since in many places around the world, at least for residential service, the customer is charged for the "real" / "active" power they consume, while any reactive power caused by a poor power factor is ignored by the utility's power meter. (Though we all pay for it in increased infrastructure costs, but I digress...)

I am currently running custom firmware on a device which can account for and report these additional measurements. These measurements can be extremely valuable when looking at power consumption on a non-utility source, for example an inverter. In battery powered situations, the unit of consumption is the VA or Volt-Amp. Most inverters "charge" you for any reactive power, in terms of that costing extra draw from the battery bank. In this situation the reactive power isn't "washed out" over many residences and even compensated for by the utility installing massive capacitor banks to balance it out. It wastes real energy and is valuable to report.

This is why I believe these units should be natively supported, mainly for mobile applications or other off-grid situations:

VAh, kVAh, VARh, kVARh

I believe these already are:

VA, kVA, VAR, kVAR

That is for Volt-Amps, which is equivalent to watts, but is total apparent power as opposed to only the real power (in other words, it accounts for a non-unity power factor), and Volt-Amps-Reactive which is Volt-Amps minus Watts (real) and is the amount of power draw "wasted" in reactance (this is what the power factor adds to Watts if it is not equal to '1').

What version of Home Assistant Core has the issue?

core-2024.1.2

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant OS

Integration causing the issue

esphome

Link to integration documentation on our website

https://www.home-assistant.io/integrations/esphome/

Diagnostics information

No response

Example YAML snippet


substitutions:
  name: "**********"
  friendly_name: "**********"
  encryption_key: **********
  area: "**********"

  relay_restore_mode: RESTORE_DEFAULT_ON

  project_name: "Athom Technology.Smart Plug V2"
  project_version: "2.0"

  sensor_poll_interval: 50ms
  push_values_interval: 1s

external_components:
################################ DO NOT USE: this addition to the CSE7766 component should be integrated with 
################################ esphome soon if the PR goes through, better to wait for that:
################################ https://github.com/esphome/esphome/pull/7301 
  - source:
      type: git
      url: https://github.com/nkinnan/esphome
      ref: "add-cse-7766-reactive-power"
    components: [ cse7766 ]
    refresh: 60s

esphome:
  name: ${name}
  friendly_name: ${friendly_name}
  area: ${area}
  name_add_mac_suffix: false
  project:
    name: "${project_name}"
    version: "${project_version}"
  # this board has 2mb flash, but esphome assumes 1mb for the 8285 board id
  platformio_options:
    board_upload.flash_size: 2MB
    board_upload.maximum_size: 2097152
    board_build.ldscript: "eagle.flash.2m256.ld"
  
# Pin numbering info: https://esphome.io/components/esp8266.html#gpio-pin-numbering

# Picture of this board labeling the pins: https://tasmota.github.io/docs/_media/pinouts/ESP-12s_pinout.jpg

# This Board's pin usage
# ----------------------
# GPIO0 
# GPIO1 
# GPIO2 
# GPIO3 HLW8032 UART
# GPIO4 
# GPIO5  Power Button
# GPIO12 Power Relay
# GPIO13 Blue Status LED
# GPIO14 
# GPIO15 
# GPIO16 

esp8266:
  board: esp8285
  # preserve globals and preferences
  restore_from_flash: true
  # prevent toggling the relay on reboot
  early_pin_init: false

preferences:
  flash_write_interval: 30min

api:
  encryption:
    key: ${encryption_key}
  reboot_timeout: 15 min
    
ota:
  platform: esphome
  password: !secret ota_password

logger:
  # disable logging via UART since we're using UART to read the HLW8032
  baud_rate: 0

mdns:
  disabled: false

# enabling this component will take up a lot of memory and may decrease stability, especially on ESP8266
web_server:
  port: 80
  # this would just be annoying every time, so disable ota from the page instead
  #auth:
  #  username: !secret web_server_username
  #  password: !secret web_server_password  
  
  # disable firmware upload via the web server which is currently un-authenticated
  ota: false
  # don't reference external resources hosted on the net in case internet is down
  local: true

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  # In conjunction with captive_portal, this spawns an AP with the device name and mac address if unable to connect
  ap: 
    password: !secret fallback_hotspot_password
  # if can't connect and no one connects to the AP, reboot
  reboot_timeout: 15min
  # don't scan first, would be a problem if you have multiple APs but I only have one
  fast_connect: true

captive_portal:

time:
  - platform: homeassistant

text_sensor:
  - platform: wifi_info
    ip_address:
      name: "IP Address"
    ssid:
      name: "Connected SSID"
    mac_address:
      name: "Mac Address"

# setup UART to read from HLW8032
uart:
  rx_pin: RX
  baud_rate: 4800

sensor: 
  - platform: uptime
    name: "Uptime"

  - platform: wifi_signal
    name: "WiFi Signal"
    update_interval: 60s
    
  # "unified driver" which works well enough, though looking at the code, it's not checking 
  # for some error and overflow conditions, and it might do some funky stuff near zero (looks 
  # like it's dropping small values entirely since that's a limitation of the cse7766, I 
  # should really look into de-unifying this if I can verify I can obtain better behavior)
  - platform: cse7766
#    update_interval: ${sensor_poll_interval}

    voltage:
      name: "Voltage"
      id: voltage_sensor
      accuracy_decimals: 1
      unit_of_measurement: "V"
      device_class: voltage
      filters:
        - throttle_average: ${push_values_interval}
#        - round: 2
#        - delta: 0.1

    current:
      name: "Current"
      id: current_sensor
      accuracy_decimals: 3
      unit_of_measurement: "A"
      device_class: current
      filters:
        - throttle_average: ${push_values_interval}
#        - round: 5
#        - delta: 0.0001

    power_factor:
      name: "Power Factor"
      id: power_factor_sensor
      accuracy_decimals: 2
      device_class: power_factor
      filters:
        #div0 when no power draw
        - lambda: if (isnan(x) || isinf(x)) return 1.0; else return x;
        - throttle_average: ${push_values_interval}
  #      - round: 3
  #      - delta: 0.01

    power:
      name: "Active Power"
      id: active_power_sensor
      accuracy_decimals: 1
      unit_of_measurement: "W"
      device_class: power
      filters:
        - throttle_average: ${push_values_interval}
#        - round: 2
#        - delta: 0.1

    apparent_power:
      name: "Apparent Power"
      id: apparent_power_sensor
      accuracy_decimals: 1
      unit_of_measurement: VA
      device_class: apparent_power
      filters:
        - throttle_average: ${push_values_interval}
#        - round: 2
#        - delta: 0.1

    reactive_power:
      name: "Reactive Power"
      id: reactive_power_sensor
      accuracy_decimals: 1
      unit_of_measurement: VAR
      device_class: reactive_power
      filters:
        - throttle_average: ${push_values_interval}
#        - round: 2
#        - delta: 0.1

    energy:
      name: "Active Energy (chip)"
#      restore: true
#      mode: lifetime
      id: active_energy_sensor
      accuracy_decimals: 3
      unit_of_measurement: kWh
      device_class: energy
      state_class: "total_increasing"
      filters:
        - multiply: 0.001
        - delta: 0.001
 
  - platform: integration
    name: "Active Energy"
    sensor: active_power_sensor
    time_unit: h
    restore: true
    accuracy_decimals: 3
    unit_of_measurement: kWh
    device_class: "energy"
    state_class: "total_increasing"
    filters:
      - multiply: 0.001
      - delta: 0.001

  - platform: integration
    name: "Apparent Energy"
    sensor: apparent_power_sensor
    time_unit: h
    restore: true
    accuracy_decimals: 3
    unit_of_measurement: kVAh
    device_class: "energy"
    state_class: "total_increasing"
    filters:
      - multiply: 0.001
      - delta: 0.001

  - platform: integration
    name: "Reactive Energy"
    sensor: reactive_power_sensor
    time_unit: h
    restore: true
    accuracy_decimals: 3
    unit_of_measurement: kVARh
    device_class: "energy"
    state_class: "total_increasing"
    filters:
      - multiply: 0.001
      - delta: 0.001

light:
  - platform: status_led
    name: "Status LED"
    id: blue_led
    disabled_by_default: true
    pin:
      inverted: true
      number: GPIO13

switch:
  - platform: gpio
    name: "Power Relay"
    pin: GPIO12
    id: relay
    restore_mode: ${relay_restore_mode}

binary_sensor:
  - platform: gpio
    pin:
      number: 5
      mode: INPUT_PULLUP
      inverted: true
    name: "Power Button"
    filters:
      - delayed_on_off: 100ms
    disabled_by_default: true
#    on_multi_click:
#      - timing:
#          - ON for at most 1s
#          - OFF for at least 0.2s
#        then:
#          - switch.toggle: relay
#      - timing:
#          - ON for at least 4s
#        then:
#          - button.press: Reset

Anything in the logs that might be useful for us?

2024-01-08 11:55:53.623 WARNING (MainThread) [homeassistant.components.sensor] Entity sensor.socket_television_total_apparent_energy (<class 'homeassistant.components.esphome.sensor.EsphomeSensor'>) is using native unit of measurement 'kVAh' which is not a valid unit for the device class ('energy') it is using; expected one of ['Wh', 'MJ', 'MWh', 'kWh', 'GJ']; Please update your configuration if your entity is manually configured, otherwise create a bug report at https://github.com/home-assistant/core/issues?q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+esphome%22
2024-01-08 11:55:53.631 WARNING (MainThread) [homeassistant.components.sensor] Entity sensor.socket_television_total_reactive_energy (<class 'homeassistant.components.esphome.sensor.EsphomeSensor'>) is using native unit of measurement 'kVARh' which is not a valid unit for the device class ('energy') it is using; expected one of ['Wh', 'MJ', 'MWh', 'kWh', 'GJ']; Please update your configuration if your entity is manually configured, otherwise create a bug report at https://github.com/home-assistant/core/issues?q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+esphome%22

Additional information

No response

nkinnan avatar Jan 09 '24 23:01 nkinnan