How to use PZEM004T Energy Monitor with esphome

I think the difference is that it talks to all of them at the same time.
I have change the “update_interval:” on one to be 1s, the other to be 1.02s
I get periodic CRCs when they align, but overall 95% of reads are good.
I used to have a delay in the code for the second one, but since an update that shows as a yaml error, so I can’t have it in the code now.
Hope this helps.

And they can be wired in parallel, since on Tx, each is just an LED and resistor on the PZEM board, and on the Rx, any one of them that is replying (- assuming you only addressed one!) can pull the input to the ESP down to ground.
If you want to talk to many, you’d need to change the drive strength of the ESP (ESP32 only feature), or the current it can output will be too low, when divided between all the PZEM bards, to drive the optocouplers and be able to signal to the PZEM electronics.
Otherwise 1 transistor could buffer the current if needed.
Drop me an Email if you want a diagram etc. [email protected] remove the 1’s

I have the same issue with the
Modbus CRC Check failed!

Have you found a solution?

Steeve wrote about reporting issue of several devices. But I have one only to test it.

Appears there was a bug introduced around 2022.11.3 that causes issues with modbus.

Some are having success with changing the arduino framework version as below.

  board: nodemcu-32s
    type: arduino
    version: 2.0.6

Here are a couple related GitHub issues

In my case, I had an issue at about the same version that caused the Quinled-ESP32 ABE boards to not boot and switching to esp-idf resolved it.

I try to change address my PZEM004T to 0x003 to this code:

but it always has the old address: 0x01 what am I doing wrong?


  name: ac-mero-01


    ## configure controller settings at setup

    ## make sure priority is lower than setup_priority of modbus_controller

    priority: -100


      - lambda: |-

          auto new_address = 0x03;

          if(new_address < 0x01 || new_address > 0xF7) // sanity check


            ESP_LOGE("ModbusLambda", "Address needs to be between 0x01 and 0xF7");



          esphome::modbus_controller::ModbusController *controller = id(pzem);

          auto set_addr_cmd = esphome::modbus_controller::ModbusCommandItem::create_write_single_command(

            controller, 0x0003, new_address);

          delay(200) ;


          ESP_LOGI("ModbusLambda", "PZEM Addr set");


  send_wait_time: 200ms

  id: mod_bus_pzem


  - id: pzem

    # The current device address.

    address: 0x01

    # The special address 0xF8 is a broadcast address accepted by any pzem device,

    # so if you use this address, make sure there is only one pzem device connected

    # to the uart bus.

    # address: 0xF8

    modbus_id: mod_bus_pzem

    command_throttle: 0ms

    setup_priority: -10

    update_interval: 30s

Not providing any logs?

I think you wrongly changed this part

auto set_addr_cmd = esphome::modbus_controller::ModbusCommandItem::create_write_single_command(

            controller, 0x0003, new_address)

the 0x0003 should be left as 0x0002, it’s register number for the address, not the address itself.

I made and emulator for pzem-004t v3 module. See here. Could be used to troubleshoot issues

1 Like

I got wrong low power incoming value, and also very low power factor. Trying to count my main AC power, energy consumption that connected to AC in of solar inverter.
I hope that some one can help to resolve issue with incorrect values? Much appreciated

Did you calibrate it? Here you can find a lot of information. It is for Tasmota but also works for ESPHOME:
PZEM-0xx power monitor - Tasmota

Unfortunately, I can’t use Tasmota. Because I have one esp32dev board that is already attached 2 more devices, so one device is attached to UART1, another with Bluetooth module, and Pzem 004t with UART2. Very strange when I chose any other appliances to measure, cattle, electric boiler, oven etc, it’s works correctly and power factor close to 1, but if I use for measure solar inverter AC IN it shows me very wrong value of power factor and Active Power. Do you know the correct way how to calibrate it?

i am only found this function in ESPhome like an example bellow:

    - calibrate_linear:
        # Map 0.0 (from sensor) to 0.0 (true value)
        - 0.0 -> 0.0
        - 0.131 -> 0.1442
        - 0.418 -> 0.42035
        - 0.603 -> 0.5981
        - 3.054 -> 3.03078
        - 4.035 -> 3.9948
        - 6.085 -> 6.02167
        - 7.346 -> 7.2887
        - 13.093 -> 13.05151

is it possible to use button instead of switch?

Can someone explain me how to use button component instead of switch for reset?

  - platform: uart
    uart_id: PZem
    id: reset_PZem
    name: "PZem Reset"
    data: [0x01, 0x42, 0x80, 0x11]

opening the site you linked shows this as first sentence:

PZEM is a dedicated separate energy monitor, device calibration in Tasmota is not supported.

this fact is repeated under the headline calibration

As the PZEM is a dedicated energy monitor, device calibration in TASMOTA is currently not supported.

What is AC in of solar inverter? :thinking: Might wanna draft your wiring here? :memo:

But you might anyway need a bi-directional power meter (something the old pzem004t v1+v2 could be hacked to support but the pzem004t v3 isn’t capable of afaik) :man_shrugging:

By using a template button: :control_knobs:

and make use of the uart.write action for the on_press trigger :raised_hands:

or even easier by utilizing the pzemac.reset_energy action :point_down:

winner winner chicken dinner :baby_chick:

1 Like

This is my code, it works fine but I can’t get yesterday’s energy, the sensor is unknown. Where is the error?


  name: pzemac

  friendly_name: Wemos D1


  board: esp01_1m

# Enable logging


# Enable Home Assistant API



    key: "XXXX"


  password: "xxxxxxx"


  ssid: !secret wifi_ssid

  password: !secret wifi_password







  # Enable fallback hotspot (captive portal) in case wifi connection fails


    ssid: "Wemos-D1 Fallback Hotspot"

    password: "xxx"



  id: PZem

  rx_pin: 14

  tx_pin: 12

  baud_rate: 9600


  - platform: wifi_signal

    name: "WiFi Sensor"

    update_interval: 60s

  - platform: pzemac


      name: Home Current

      unit_of_measurement: A

      accuracy_decimals: 1

      icon: mdi:flash-circle


      name: Home Voltage

      unit_of_measurement: V

      icon: mdi:flash-circle


      name: Home Power

      unit_of_measurement: W

      accuracy_decimals: 1        

      icon: mdi:flash-circle

      id: home_power


      name: Home Power Factor

      id: pow_factor



      name: Home Energy

      unit_of_measurement: Wh

      accuracy_decimals: 0


      #  - multiply: 0.001

      icon: mdi:flash-circle

      id: home_energy

    update_interval: 5s

  - platform: total_daily_energy

    name: "Total Daily Energy"

    unit_of_measurement: Wh

    accuracy_decimals: 0

    power_id: home_power    


  - platform: template

    name: Energy Yesterday

    id: set_yesterday

    unit_of_measurement: Wh

    accuracy_decimals: 0

    icon: mdi:lightning-bolt


  - platform: template

    name: Reset


      uart.write: [0x01, 0x42, 0x80, 0x11]


  - platform: homeassistant


      - seconds: 59

        minutes: 59

        hours: 23


          - sensor.template.publish:

              id: set_yesterday

              state: !lambda |-

                return id(home_energy).state;

I’m using this module to monitor my home consumption and it works quite nice. Even idle consumption is accurate. However my main breaker is only 40A, so I wanted to increase resolution, by using 50A transformer. Bought SCT016S 50A-100mA transformer, however it turned out to be very inaccurate at low currents, standard transformer is much better.
Now I’m thinking I could connect two 100A transformers in parallel, to increase accuracy. Would that work, or it’s not possible to connect multiple transformers?

Because the pzem004t (pcb) module is calibrated for the coil/clamp it is shipped with :bulb: As I know 10A and 100A versions are sold but the coils/clamp are likely not interchangable :warning:

How comes that?

PZEM-004T v3


  • Measuring range:80~260V

  • Resolution: 0.1V

  • Measurement accuracy: 0.5%

Power factor

  • Measuring range: 0.00~1.00

  • Resolution: 0.01

  • Measurement accuracy: 1%


  • Measuring range: 45Hz~65Hz

  • Resolution: 0.1Hz

  • Measurement accuracy: 0.5%


  • Measuring range: 0~10A(PZEM-004T-10A); 0~100A(PZEM-004T-100A)

  • Starting measure current: 0.01A(PZEM-004T-10A); 0.02A(PZEM-004T-100A)

  • Resolution: 0.001A

  • Measurement accuracy: 0.5%

Active power

  • Measuring range: 0~2.3kW(PZEM-004T-10A); 0~23kW(PZEM-004T-100A)

  • Starting measure power: 0.4W

  • Resolution: 0.1W

  • Display format:

<1000W, it displays one decimal, such as: 999.9W

≥1000W, it display only integer, such as: 1000W

  • Measurement accuracy: 0.5%

Active Energy

  • Measuring range: 0~9999.99kWh

  • Resolution: 1Wh

  • Measurement accuracy: 0.5%

  • Display format:

<10kWh, the display unit is Wh(1kWh=1000Wh), such as: 9999Wh

≥10kWh, the display unit is kWh, such as: 9999.99kWh

Which resolution is the one not sufficient for you? The current of 0.001A steps? :thinking:

No, nothing to with calibration, I tested actual current transformer produces, and it’s badly nonlinear with low currents.

Also, resolution and accuracy do increase if more turns in the transformer, for example see this, It’s 10 times here, but the principle is would be the here using two transformers for 2 time increase.

Your solar inverter actually produces very high frequency pulses into the mains, the average of which is a reasonable approximation to the mains waveform.
However it has a great deal of electrical noise on it (like loads of spikes).
These can really confuse things expecting a fairly nice sine wave.
If you can put ferrites around the conductors, they will limit the high frequency noise.
Also keeping your clamp as far away from the inverter as you can may help reduce how much of the high frequency noise is seen but the PZEM module.

1 Like