PZEM-6L24 on esphome

Anybody used PZEM-6L24 on esphome?

Thanks & Regards,

Aslam

Apparently yes according to a search of these forums. Best of luck defining your problem, describing it, and solving it.

Hi @aslu

Very interesting! Can you tell us more? :+1:

We use 6 PZEM… :star2:

I would also like to use a native in yaml input like in the case of pzem-004t

Modbus?

i have the following config.
β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™β€˜β€™
uart:
id: mod_bus
tx_pin: GPIO17 # Adjust to your wiring
rx_pin: GPIO16
baud_rate: 9600
parity: NONE
stop_bits: 1

Modbus RTU

modbus:
id: modbus_hub
uart_id: mod_bus
send_wait_time: 200ms

MODBUS CONTROLLER COMPONENT (THIS WAS MISSING!)

modbus_controller:

  • id: pzem
    modbus_id: modbus_hub
    address: 0x01 # Default slave ID for PZEM
    update_interval: 10s

Sensors using modbus_controller

sensor:

Voltage Phase A

  • platform: modbus_controller
    modbus_controller_id: pzem
    name: β€œVoltage Phase A”
    register_type: holding
    address: 0x0000
    unit_of_measurement: β€œV”
    device_class: voltage
    state_class: measurement
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    • multiply: 0.1

Voltage Phase B

  • platform: modbus_controller
    modbus_controller_id: pzem
    name: β€œVoltage Phase B”
    register_type: holding
    address: 0x0001
    unit_of_measurement: β€œV”
    device_class: voltage
    state_class: measurement
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    • multiply: 0.1

Voltage Phase C

  • platform: modbus_controller
    modbus_controller_id: pzem
    name: β€œVoltage Phase C”
    register_type: holding
    address: 0x0002
    unit_of_measurement: β€œV”
    device_class: voltage
    state_class: measurement
    value_type: U_WORD
    accuracy_decimals: 1
    filters:
    • multiply: 0.1

Current Phase A

  • platform: modbus_controller
    modbus_controller_id: pzem
    name: β€œCurrent Phase A”
    register_type: holding
    address: 0x0003
    unit_of_measurement: β€œA”
    device_class: current
    state_class: measurement
    value_type: U_WORD
    accuracy_decimals: 3
    filters:
    • multiply: 0.001

Current Phase B

  • platform: modbus_controller
    modbus_controller_id: pzem
    name: β€œCurrent Phase B”
    register_type: holding
    address: 0x0004
    unit_of_measurement: β€œA”
    device_class: current
    state_class: measurement
    value_type: U_WORD
    accuracy_decimals: 3
    filters:
    • multiply: 0.001

Current Phase C

  • platform: modbus_controller
    modbus_controller_id: pzem
    name: β€œCurrent Phase C”
    register_type: holding
    address: 0x0005
    unit_of_measurement: β€œA”
    device_class: current
    state_class: measurement
    value_type: U_WORD
    accuracy_decimals: 3
    filters:
    • multiply: 0.001

Total Active Power (32-bit)

  • platform: modbus_controller
    modbus_controller_id: pzem
    name: β€œTotal Active Power”
    register_type: holding
    address: 0x000C
    unit_of_measurement: β€œW”
    device_class: power
    state_class: measurement
    value_type: U_DWORD
    accuracy_decimals: 0

Total Energy (kWh)

  • platform: modbus_controller
    modbus_controller_id: pzem
    name: β€œTotal Energy”
    register_type: holding
    address: 0x0018
    unit_of_measurement: β€œkWh”
    device_class: energy
    state_class: total_increasing
    value_type: U_DWORD
    accuracy_decimals: 3
    filters:
    • multiply: 0.001

and error:

[23:49:50.249][C][mdns:179]: mDNS:
[23:49:50.249][C][mdns:179]: Hostname: pzem-6l24
[23:49:56.665][D][modbus_controller:039]: Modbus command to device=1 register=0x00 no response received - removed from send queue
β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€β€œβ€
Any idea how to fix this?

1 Like

It’s quite problematic; I don’t think it’s possible without lambdas. I’ve reached this stage, but I don’t have the time or energy to refine it. The values are incorrect. A test rig needs to be built to verify this.

uart:
  tx_pin: GPIO3
  rx_pin: GPIO2
  baud_rate: 9600
  data_bits: 8
  parity: NONE
  stop_bits: 1

modbus:
  id: modbus1
  send_wait_time: 200ms

modbus_controller:
  - id: pzem
    address: 0x01
    modbus_id: modbus1
    update_interval: 10s

sensor:
  # Voltage A (register 0x0000) - 1LSB = 0.1V, low byte first - USE FC4 (input registers)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: voltage_A
    name: "Voltage_A"
    address: 0x0000
    register_type: read           # <-- FC4 (input registers)
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "V"
    accuracy_decimals: 1
    lambda: |-
      if (data.size() < 2) return NAN;
      uint16_t raw = (uint8_t)data[0] | ((uint8_t)data[1] << 8); // low byte first
      float volts = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Voltage_A raw=0x%04X (%u) -> %.1f V", raw, raw, volts);
      return volts;

  # Voltage B (register 0x0001)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: voltage_B
    name: "Voltage_B"
    address: 0x0001
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "V"
    accuracy_decimals: 1
    lambda: |-
      if (data.size() < 2) return NAN;
      uint16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float volts = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Voltage_B raw=0x%04X -> %.1f V", raw, volts);
      return volts;

  # Voltage C (register 0x0002)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: voltage_C
    name: "Voltage_C"
    address: 0x0002
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "V"
    accuracy_decimals: 1
    lambda: |-
      if (data.size() < 2) return NAN;
      uint16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float volts = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Voltage_C raw=0x%04X -> %.1f V", raw, volts);
      return volts;

  # Current A (register 0x0003) - 1LSB = 0.01A, low byte first
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: current_A
    name: "Current_A"
    address: 0x0003
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "A"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      uint16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float amps = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Current_A raw=0x%04X -> %.2f A", raw, amps);
      return amps;

  # Current B (register 0x0004)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: current_B
    name: "Current_B"
    address: 0x0004
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "A"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      uint16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float amps = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Current_B raw=0x%04X -> %.2f A", raw, amps);
      return amps;

  # Current C (register 0x0005)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: current_C
    name: "Current_C"
    address: 0x0005
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "A"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      uint16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float amps = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Current_C raw=0x%04X -> %.2f A", raw, amps);
      return amps;

  # Frequency_A (register 0x0006)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: voltage_frequency_A
    name: "Frequency_A"
    address: 0x0006
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "Hz"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float hertz = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Frequency_A raw=0x%04X -> %.2f Hz", raw, hertz);
      return hertz;

  # Frequency_B (register 0x0007)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: voltage_frequency_B
    name: "Frequency_B"
    address: 0x0007
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "Hz"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float hertz = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Frequency_A raw=0x%04X -> %.2f Hz", raw, hertz);
      return hertz;

  # Frequency_C (register 0x0008)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: voltage_frequency_C
    name: "Frequency_C"
    address: 0x0008
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "Hz"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float hertz = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Frequency_A raw=0x%04X -> %.2f Hz", raw, hertz);
      return hertz;

  # Phase_Voltage_B_Relative_to_A (register 0x0009)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: voltage_phase_B
    name: "Voltage_Phase_B"
    address: 0x0009
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "Β°"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float degree = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Phase_B raw=0x%04X -> %.2f Β°", raw, degree);
      return degree;

  # Phase_Voltage_C_Relative_to_A (register 0x000A)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: voltage_phase_C
    name: "Voltage_Phase_C"
    address: 0x000A
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "Β°"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float degree = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Phase_C raw=0x%04X -> %.2f Β°", raw, degree);
      return degree;

  # Phase_Current_A_Relative_to_A_Voltage (register 0x000B)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: current_phase_A
    name: "Current_Phase_A"
    address: 0x000B
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "Β°"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float degree = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Phase_Current_A raw=0x%04X -> %.2f Β°", raw, degree);
      return degree;

# Phase_Current_B_Relative_to_A_Voltage (register 0x000C)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: current_phase_B
    name: "Current_Phase_B"
    address: 0x000C
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "Β°"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float degree = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Phase_Current_B raw=0x%04X -> %.2f Β°", raw, degree);
      return degree;

# Phase_Current_C_Relative_to_A_Voltage (register 0x000D)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: current_phase_C
    name: "Current_Phase_C"
    address: 0x000D
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    unit_of_measurement: "Β°"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int16_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8);
      float degree = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Phase_Current_C raw=0x%04X -> %.2f Β°", raw, degree);
      return degree;

# Active_Power_A (register 0x000E)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: active_power_A
    name: "Active_Power_A"
    address: 0x000E
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "W"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Active_Power_A raw=0x%04X -> %.2f W", raw, power);
      return power;

# Active_Power_B (register 0x0010)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: active_power_B
    name: "Active_Power_B"
    address: 0x0010
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "W"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Active_Power_B raw=0x%04X -> %.2f W", raw, power);
      return power;

# Active_Power_C (register 0x0012)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: active_power_C
    name: "Active_Power_C"
    address: 0x0012
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "W"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Active_Power_C raw=0x%04X -> %.2f W", raw, power);
      return power;

# Reactive_Power_A (register 0x0014)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: reactive_power_A
    name: "Reactive_Power_A"
    address: 0x0014
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "Var"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Reactive_Power_A raw=0x%04X -> %.2f Var", raw, power);
      return power;

# Reactive_Power_B (register 0x0016)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: reactive_power_B
    name: "Reactive_Power_B"
    address: 0x0016
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "Var"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Reactive_Power_B raw=0x%04X -> %.2f Var", raw, power);
      return power;

# Reactive_Power_C (register 0x0018)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: reactive_power_C
    name: "Reactive_Power_C"
    address: 0x0018
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "Var"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Reactive_Power_C raw=0x%04X -> %.2f Var", raw, power);
      return power;

# Apparent_Power_A (register 0x001A)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: apparent_power_A
    name: "Apparent_Power_A"
    address: 0x001A
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "VA"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Apparent_Power_A raw=0x%04X -> %.2f VA", raw, power);
      return power;

# Apparent_Power_B (register 0x001C)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: apparent_power_B
    name: "Apparent_Power_B"
    address: 0x001C
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "VA"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Apparent_Power_B raw=0x%04X -> %.2f VA", raw, power);
      return power;

# Apparent_Power_C (register 0x001E)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: apparent_power_C
    name: "Apparent_Power_C"
    address: 0x001E
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "VA"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Apparent_Power_C raw=0x%04X -> %.2f VA", raw, power);
      return power;

# Combined_Active_power (register 0x0020)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: combined_active_power
    name: "Combined_Active_Power"
    address: 0x0020
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "W"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Combined_Active_Power raw=0x%04X -> %.2f W", raw, power);
      return power;

# Combined_Reactive_power (register 0x0022)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: combined_reactive_power
    name: "Combined_Reactive_Power"
    address: 0x0022
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "Var"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Combined_Reactive_Power raw=0x%04X -> %.2f Var", raw, power);
      return power;

# Combined_Apparent_power (register 0x0024)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: combined_apparent_power
    name: "Combined_Apparent_Power"
    address: 0x0024
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "VA"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float power = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Combined_Apparent_Power raw=0x%04X -> %.2f VA", raw, power);
      return power;

# Power_Factor_A (register 0x0026)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: power_factor_A
    name: "Power_Factor_A"
    address: 0x0026
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      uint8_t raw = (uint8_t)data[0];
      float powerfactor = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Power_Factor_A raw=0x%04X -> %.2f", raw, powerfactor);
      return powerfactor;

# Power_Factor_B (register 0x0026)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: power_factor_B
    name: "Power_Factor_B"
    address: 0x0026
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      uint8_t raw = (uint8_t)data[1];
      float powerfactor = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Power_Factor_B raw=0x%04X -> %.2f", raw, powerfactor);
      return powerfactor;

# Power_Factor_C (register 0x0027)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: power_factor_C
    name: "Power_Factor_C"
    address: 0x0027
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      uint8_t raw = (uint8_t)data[0];
      float powerfactor = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Power_Factor_C raw=0x%04X -> %.2f", raw, powerfactor);
      return powerfactor;

# Power_Factor_Combined (register 0x0027)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: power_factor_combined
    name: "Power_Factor_Combined"
    address: 0x0027
    register_type: read
    value_type: RAW
    register_count: 1
    force_new_range: true
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      uint8_t raw = (uint8_t)data[1];
      float powerfactor = (float)raw * 0.01f;
      ESP_LOGI("pzem_dbg","Power_Factor_Combined raw=0x%04X -> %.2f", raw, powerfactor);
      return powerfactor;

# Active_Energy_A (register 0x0028)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: active_energy_A
    name: "Active_Energy_A"
    address: 0x0028
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kWh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Active_Energy_A raw=0x%04X -> %.2f kWh", raw, energy);
      return energy;

# Active_Energy_B (register 0x002A)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: active_energy_B
    name: "Active_Energy_B"
    address: 0x002A
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kWh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Active_Energy_B raw=0x%04X -> %.2f kWh", raw, energy);
      return energy;

# Active_Energy_C (register 0x002C)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: active_energy_C
    name: "Active_Energy_C"
    address: 0x002C
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kWh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Active_Energy_C raw=0x%04X -> %.2f kWh", raw, energy);
      return energy;

# Reactive_Energy_A (register 0x002E)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: Reactive_energy_A
    name: "Reactive_Energy_A"
    address: 0x002E
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kVarh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Reactive_Energy_A raw=0x%04X -> %.2f kVarh", raw, energy);
      return energy;

# Reactive_Energy_B (register 0x0030)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: Reactive_energy_B
    name: "Reactive_Energy_B"
    address: 0x0030
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kVarh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Reactive_Energy_B raw=0x%04X -> %.2f kVarh", raw, energy);
      return energy;

# Reactive_Energy_C (register 0x0032)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: Reactive_energy_C
    name: "Reactive_Energy_C"
    address: 0x0032
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kVarh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Reactive_Energy_C raw=0x%04X -> %.2f kVarh", raw, energy);
      return energy;

# Apparent_Energy_A (register 0x0034)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: apparent_energy_A
    name: "Apparent_Energy_A"
    address: 0x0034
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kVAh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Apparent_Energy_A raw=0x%04X -> %.2f kVAh", raw, energy);
      return energy;

# Apparent_Energy_B (register 0x0036)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: apparent_energy_B
    name: "Apparent_Energy_B"
    address: 0x0036
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kVAh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Apparent_Energy_B raw=0x%04X -> %.2f kVAh", raw, energy);
      return energy;

# Apparent_Energy_C (register 0x0038)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: apparent_energy_C
    name: "Apparent_Energy_C"
    address: 0x0038
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kVAh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Apparent_Energy_C raw=0x%04X -> %.2f kVAh", raw, energy);
      return energy;

# Combined_Active_Energy (register 0x003A)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: combined_active_energy
    name: "Combined_Active_Energy"
    address: 0x003A
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "KWh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Combined_Active_Energy raw=0x%04X -> %.2f kWh", raw, energy);
      return energy;

# Combined_Reactive_Energy_A (register 0x003C)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: combined_reactive_energy
    name: "Combined_Reactive_Energy"
    address: 0x003C
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kVarh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Combined_Reactive_Energy raw=0x%04X -> %.2f kVarh", raw, energy);
      return energy;

# Combined_Apparent_Energy (register 0x003E)
  - platform: modbus_controller
    modbus_controller_id: pzem
    id: Combined_Apparent_Energy
    name: "Combined_Apparent_Energy"
    address: 0x003E
    register_type: read
    value_type: RAW
    register_count: 2
    force_new_range: true
    unit_of_measurement: "kVAh"
    accuracy_decimals: 2
    lambda: |-
      if (data.size() < 2) return NAN;
      int32_t raw = (uint16_t)data[0] | ((uint16_t)data[1] << 8) | ((uint16_t)data[2] << 16) | ((uint16_t)data[3] << 24);
      float energy = (float)raw * 0.1f;
      ESP_LOGI("pzem_dbg","Combined_Apparent_Energy raw=0x%04X -> %.2f kVAh", raw, energy);
      return energy;