First ESPHome Custom Sensor ZMPT101B Voltage Sensor

Installed:

#define VMAX 250
#define FREQUENCY 50
#define CALIBRATE_READ 1
#define CALIBRATE_ACTUAL 1
#define ZERO_VAC 880

log :

[03:26:13][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:14][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:15][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:16][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:17][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:18][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:19][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:20][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:21][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:22][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:23][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:24][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:25][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:26][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:27][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:28][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:29][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:30][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:31][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:32][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:33][D][sensor:093]: 'Mains Voltage': Sending state 2.00000 V with 0 decimals of accuracy
[03:26:34][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:35][D][sensor:093]: 'Mains Voltage': Sending state 3.00000 V with 0 decimals of accuracy
[03:26:36][D][sensor:093]: 'Mains Voltage': Sending state 1.00000 V with 0 decimals of accuracy

the next step would be to understand how to connect all this to ADS1115. To measure on three vases using Wemos d1
I also found an article, maybe using this example it will be possible to achieve greater accuracy (but this is if it is not possible to achieve a positive result here) :
ESP32 + ESPHome Open Source Energy Monitor

but to be honest I experimented a week ago, the ideal option is a transformer, a diode bridge and a divider on resistors with a small capacitor and INA226 , I managed to achieve an accuracy of ±0.3 V, I took the transformer from some old power supply, but the downside is the dimensions ((

this article uses the Arduino library and they were able to get very accurate readings , but is it possible to screw it to ESPHome somehow?

Interfacing ZMPT101B Voltage Sensor with ESP32

or borrow a calculation model

If you look at both code files, you will see that they are both doing essentially the same thing (calculating the RMS voltage) in pretty much the identical way.

Have you tried the Arduino example with your hardware and gotten better results?

Did you follow the instructions to adjust the trimpot?

Note that the ADC in a standard Arduino is generally an order of magnitude better than the one in the esp32. This page has some good data on how to make it better: ESP32 Analog To Digital Conversion Accuracy - IoT Kits

Those techniques would work if you were measuring DC voltages, since they clearly say you need to do averaging to get good results. Doing averaging of a varying input will likely give you worse results.

You haven’t really stated what you are trying to do. If you just want to know there is voltage there, this will work. If you want to measure energy and or get an accurate (how accurate?) measurent you really should use something else.

This post is from someone doing something similar (but somewhat different)
Struggling with a CT and ESP32-Wroom - ESPHome - Home Assistant Community

It has the same issue of the esp32 ADC really isn’t that good, so you have to do a lot of work to get something reasonable out of it. It is likely good enough for many scenarios.

The arduino example does do multiple full cycle measurements and averages those that probably gives slightly more consistent results.

@neel-m linked my post, if you look at my code in there (I put it on github now) you will see I take 1 minute’s worth of sample average with ESPhome. For my purpose I am trying to determine if Washer/Dryer are on. Since they go through cycles (motors/pumps/heaters) the reading will jump up/down, so need to smooth it out and take an average.

Here is a snippet:

update_interval: 7s
    filters:
      - sliding_window_moving_average: 
         window_size: 9 #keep roughly 1 min average
         send_every: 1

If you need smoother more rapid changes you can lower the average to last 3, update more often. Or switch to exponential_moving_average which can give more weight to more recent values, only using older ones to smooth out the curve.

From my experience using ESP32 Wroom board, it has enough precision to be within 0.1A accurate of real readings. It gets less accurate closer you get to 0. So unless you are working with pulling 0.1A or less, it should be accurate enough. Otherwise you may need an ADS1115 which has much higher precision (its an addon board you can use with your ESP32).

Thank you for the clarifications, I read your post too. I will experiment with current transformers, but a little later, but I will use separate coils and maybe I will also try ZMCT103C. But a week earlier (I mentioned this a little higher here) I made what seemed to me a very accurate voltmeter, and the essence of this article lies precisely in the pairing of esp and ZMPT101B.
And earlier, a successful experiment consisted of such a simple solution: 1) transformer (220/12 V), 2) diode bridge, 3) capacitor, 4) resistive divider, 5) INA226 (simply because it is the best). As a result, the accuracy is ± 0.3 V. In theory, this is the same as yours … only voltage and not current)))
And here is part of the code:

  - platform: ina226
    address: 0x40
    shunt_resistance: 0.1 ohm
    max_current: 3.2A
    adc_time: 140us
    adc_averaging: 128
    update_interval: 2s
    bus_voltage:
      name: "INA226 Voltage"
      filters:
        - calibrate_linear:
           method: least_squares
           datapoints:
            - 0.0 -> 0.0
            - 6.96 -> 101
            - 10.87 -> 151
            - 14.85 -> 195
            - 18 -> 238.5

I tested it for a week, it worked perfectly, but the big minus is the dimensions

Why are the dimensions a problem?
Are you sending this on a rocket where ever cc and gram counts?

Your transformer solution converts the AC to DC, which makes it easier to use averaging AND it used a decent ADC, do not surprised it worked better.

I don’t believe I have heard what you are really trying to do so really hard to provide good advice on how to achieve it.

As a result, I need to make a device for precise measurements on three phases and in a DIN rail housing, in an electrical panel, to implement various possibilities in the future, for example, if in the summer the mains voltage drops significantly, turn off the inverter split system until the mains voltage is normalized (as one of the options), or notify about this in the audio speaker, and then decide for yourself what to do with this information

I have several ZMPT101B, and I had an idea: maybe try to remake one of them, namely: use an isolating transformer and unsolder the operational amplifier with the strapping, and assemble a step-down divider instead, then also rectify the voltage, put in an SMD capacitor and connect to the ADS1115 (why ADS1115 x2 - I need to read voltage from three phases and current from three phases with one wemos, that is, I need 6 inputs)

Get three of them, one for each phase, only hook up the inputs. This does the measurement properly and cheaply in a very small size.

If you are interested in actually measuring energy usage look here:

https://openenergymonitor.org/

I have seen these solutions and there is support for tuya, here the question is to solve this so-called problem. And if my buy ready-made solutions at the first difficulties, then why do you need ESP. :rofl:

Unless you have orders of magnitude more time than money, I would suggest one of the choices I listed above. They are the Easy Button where very knowledgeable people have done the work to figure out to do the job well and made it easy to follow. I have 2 IotaWatts and they work great. For about a decade I had a pack of power measurement ICs in a drawer that I was going to use to measure energy. I still have them, but it will still be a lot of work to get them to a point where they will be usable.

If your goal is learning, go read the open energy monitor site. They also have a forum with people that know all about measuring power. I know enough to say you are choosing a very difficult path with low chance of success for your main goal, but might provide lots of opportunities for learning (and bashing your head against the wall, when things don’t make sense).

1 Like

Perhaps this is the best application of ZMPT101B that solves my problems. I will stop here, I will only make my own PCB Board :rofl:

This part of the question can be said to be completely closed. I found two solutions:

  1. A separate transformer ZMPT101B. You can achieve accurate readings in the range of 150-260 V. You need to very carefully select components such as a current-limiting resistor, diodes in the rectifier, a bipolar capacitor and a smoothing capacitor with load resistors. And make sure that the transformer does not go into saturation. And the accuracy is ±0.4 V.
  2. A more obvious solution for obtaining relatively accurate values ​​with a small delay (acceptable if you do not need to catch voltage drops from starting currents). Accuracy ± 1.5 V
    Code:
i2c:

ads1115:
  - address: 0x48

sensor:
  - platform: ads1115
    multiplexer: 'A0_GND'
    gain: 4.096
    sample_rate: 475
    name: "ADS1115 Channel A0-GND"
    id: ads_a0
    resolution: 16_BITS

  - platform: ct_clamp
    sensor: ads_a0
    name: "Volt"
    unit_of_measurement: "V"
    id: dryer_volt
    update_interval: 2s
    sample_duration: 1000ms      
    filters:
      - sliding_window_moving_average: 
         window_size: 4 
         send_every: 1
      - calibrate_linear:
          method: exact
          datapoints:
          - 0.01155  -> 0.0
          - 0.31828 -> 100
          - 0.47214 -> 150
          - 0.63152 -> 200
          - 0.77275 -> 245

Many thanks to everyone who responded, especially Neel Malik))))

Glad you found something that works for you and thanks for sharing what it was. This might help someone in the future.

1 Like

Apologies for hijacking the thread, but since the latest ESPHome update, you can not use the custom platform any more

The "custom" component has been removed. Consider conversion to an external component.
https://esphome.io/guides/contributing#a-note-about-custom-components.

So none of this works any more, and unfortunately I have zero clue as to where it is now supposed to go or the format

I did give it an attempt on ChatGPT, but eventually it was just sending me around in circles, so this node has missed a Good couple of udates due to this.

Is there anyone that can guide me through the process of how this needs to be correctly amended in ESPHome?

I currently have the following code on the node:

esphome:
  name: "mains-voltage"

  includes:
    - zmpt101b_custom_sensor.h

esp8266:
  board: d1_mini

sensor:
  - platform: custom
    lambda: |-
      auto my_sensor = new ZMPT101BSensor();
      App.register_component(my_sensor);
      return {my_sensor};

    sensors:
      id: ${sen_id}
      name: "${sen_name}"
      unit_of_measurement: V
      state_class: "measurement"
      accuracy_decimals: 2
      icon: "mdi:current-ac"

Everything from “sensor:” is currently highlighted in red :confused:

Any help would be most appreciated

Thanks in advance for the replies

look here:

it is an external component (supported by esphome) that brings back the recently removed capability of custom components

1 Like

Thank you worked a treat after a bit of finagling