Zmpt101b Precision Voltage Sensor Module

Anyone used the zmpt101b Precision Voltage Sensor Module with HA? I can find Arduino code but no one in the HA community has any input.
Any information/suggestions would be appreciated.
Thanks

This just has an analogue output voltage. So wire it up to the ADC pin of ESP board of your choice (e.g. D1 mini) loaded with ESPhome. Couple of lines of YAML and it’s done.

Appreciate the response. Using an ESP32, l already did that, but due to the number of calculations necessary and trimming output to correct the sinewave generated by the op-amp, Arduino libraries are needed (Adafruit SSD1306 library, Adafruit GFX library). Without these, the ESPHome output is worthless. So far, I haven’t been able to incorporate these specific libraries into HA.
Thanks again for your response.

@GrumpyDude and @tom_l I have the same problem you are having but after a great deal of searching I found this article and as I had a spare NANO I had this up and running and producing what looks to be extraorinarily good values in less than an hour.

Example Serial Monitor values:

Voltage: 236.58
Voltage: 236.40
Voltage: 236.15
Voltage: 236.17
Voltage: 235.95
Voltage: 236.51
Voltage: 236.92
Voltage: 236.83
Voltage: 237.12
Voltage: 237.18
Voltage: 236.73
Voltage: 236.94
Voltage: 236.80
Voltage: 236.07
Voltage: 236.22
Voltage: 236.52
Voltage: 236.20
Voltage: 236.40
Voltage: 236.24
Voltage: 235.83
Voltage: 235.94
Voltage: 236.25
Voltage: 236.17
Voltage: 236.21
Voltage: 236.05
Voltage: 236.37
Voltage: 236.81
Voltage: 238.13
Voltage: 238.30
Voltage: 237.57
Voltage: 237.34
Voltage: 237.56

Values produced at 1 second intervals.

So next step is to get the NANO connected via serial? or digital? to MQTT via an ESP01? Perhaps? And then…bingo top shelf voltage sensor…perhaps?

Can anyone help with which way I should proceed?

Cheers if you can help me here…as since trying to take this next step I have pretty much wasted two days so far.

It seems to me this is just potentially a digital ouput from the NANO to an ESP8266 right? If we had Tasmota or ESPHOME support for a ZMPT101B sensor then this would be a cinch right? But then it’s most likely not that simple right?

If you want to try it out (setting up the NANO to process the ZMPT101B analog output) then read the comments as well as the article I linked to above for some more clues to getting it up and running.

@wellsy
Did you get your voltage readings in HA?

@gieljnssns unfortunately no I didn’t. I gave up in the end but after I installed a Fronius Smart Power Meter. I now have a very accurate Mains Voltage reading in HA that I am very happy with. I use the single phase model like this one here in conjunction with my Fronius Solar Inverter and the Fronius Sensor found here

Yes. I’m using one and it works very well.

I have the ZMPT101b voltage sensor and a 50A SCT-013-050 current sensor hooked up to nodeMCU 8266 running ESPHome. The sensors connect through an ADS1115 A/D converter.

The node measures the line voltage and house current and calculates the power consumption. I also have a SMA solar inverter giving me the solar power generation and HA calculates the mains power from the two.

The voltage I measure with the node tracks the voltage reported by the SMA inventer pretty well. The only reason I measure it with the node is that the inverter goes to sleep in the dark and then stops reporting the line voltage.

Concerning the voltage measurement;
The ZMPT outputs the attenuated sine wave with a 1/2Vcc offset. The attenuation can be adjusted and you must make sure the voltage does not clip. A scope comes in handy here. Also note that using the NodeMCU ESP8266 ADC is not great solution the range is 0 - 3.3V, with an offset of 2.5V there is not much room for the signal.

From the sine wave you must calculate the RMS value. Here it gets interesting. The ADS1115 is not fast enough to take enough samples over one wave at 50 Hz (20 ms). So I sample the wave over a much longer time to calculate the RMS value. I make sure NOT to sample at a multiple of 20 ms. I ended up sampling 1250 times at 24 ms, i.e. 30 seconds. And report every 5 seconds.

For the RMS calculation I substract the voltage offset, square the result, calculate the rolling average over 1250 samples, report every 208 samples, take the square root and multiply to calibrate.

I increased the i2c bus speed to 400 kHz and reduced the sample interval 24ms, that way I got the expected 42 samples per second in the log (but I do not know if the ADS or the logging is the constraint …).

It is possible to use the ct_clamp platform for the voltage sensor. It just calculates the RMS voltage from the ADC. But I found it to be very nerveus, so I stick with my solution.


# i2C bus
i2c:
  - sda: D2
    scl: D1
    scan: no
    frequency: 400kHz
    id: bus_a

ads1115:
  - address: 0x48
#    continuous_mode: on

sensor:
  - platform: ads1115
    name: "Mains voltage"
    unit_of_measurement: "V"
    icon: "mdi:flash"
    accuracy_decimals: 0
    update_interval: 24ms
    multiplexer: 'A0_GND'
    gain: 6.144
    filters:
      - offset: -2.5485                       # compensate the offset (calbration)
      - lambda: return x * x;
      - sliding_window_moving_average:
          window_size: 1250                   # average over 30 seconds
          send_every: 208                     # report every 05 seconds
      - lambda: return sqrt(x);
      - multiply: 338                         # calculate mains voltage (calibration)     
    id: mains_voltage

Concerning the current measurement;
I was using the ‘ct_clamp’ platform from ESPHome. That seems to work, but I have no idea what it does and that is frustrating. The ESPHome page on this does not explain much. Also, for the ct_clamp platform I’m supposed to enable the continuous mode, but when I do that I only get ‘reading ADS1115 timed out’ messages in the log.

So I ended up using exactly the same logic as for the voltage sensor with different filter settings (same 24 ms sample rate, average over 12 seconds, report every 2 seconds).

Note that the current clamp will give a zero crossing wave output. To measure the positive and the negative part you must connect as a differential to the ADS1115. The average is zero and there is no need for an offset correction.


  - platform: ads1115
    name: "Mains current"
    unit_of_measurement: "A"
    accuracy_decimals: 1
    icon: "mdi:gauge"
    multiplexer: 'A2_A3'
    gain: 1.024
    update_interval: 24ms
    filters:
      - offset: 0                             # compenstate the offset (value measured at 0A)
      - lambda: return x * x;
      - sliding_window_moving_average:
          window_size: 500                    # average over 12 seconds
          send_every: 83                      # report every 02 seconds
      - lambda: return sqrt(x);
      - multiply: 52.743                      # calculate mains current (0.5 V = 25 A)     
    id: mains_current

I hope this helps some people with their ZMPT101B and SCT-013-050 integrations.

very nice … thanks for sharing
You have been explained in detail how you did. but I don’t understand any. If I got any dought while making it i will message you on this page. help me with this.

  1. Is it possible to share the wiring? so that I can do the same
  2. I’m going to use ESP 32s board, So ADS1115 is necessary or not
  1. I do not do wiring diagrams for these modules, sorry.
  2. I’m not sure I have never used the ESP32. Note that you need a differential input for the current measurement.
1 Like

I got every product. i’m going to try this. after checking your code I didn’t know the number that you entered

In Mains voltage
gain: ? offset: ?multiply: ?

then in Mains current
gain: ? offset: ?multiply: ?

how you got those numbers. I have 0 knowledge about these. you are the only hope,…

and sorry to disturb and thanks for helping

I found this article
that using ZMPT101B and Arduino Uno to Measure AC Voltage
the good part about this code is there are no libraries in code only equations for calculation true RMS and other staff to get AC Voltage.
and I try it by myself it is very accurate and stable I used this code that show the result in Serial Monitor
My plan is to use ZMPT101B with ESP32 on ADC pins with of course ESPHome
My question is anyone can help us to convert these filters to use them in ESPHome

   /* 1- AC Voltage Measurement */
        if(micros() >= voltageLastSample + 1000 )                                                                      /* every 0.2 milli second taking 1 reading */
          {
            voltageSampleRead = (analogRead(VoltageAnalogInputPin)- 512)+ voltageOffset1;                             /* read the sample value including offset value*/
            voltageSampleSum = voltageSampleSum + sq(voltageSampleRead) ;                                             /* accumulate total analog values for each sample readings*/
            
            voltageSampleCount = voltageSampleCount + 1;                                                              /* to move on to the next following count */
            voltageLastSample = micros() ;                                                                            /* to reset the time again so that next cycle can start again*/ 
          }
        
        if(voltageSampleCount == 1000)                                                                                /* after 4000 count or 800 milli seconds (0.8 second), do the calculation and display value*/
          {
            voltageMean = voltageSampleSum/voltageSampleCount;                                                        /* calculate average value of all sample readings taken*/
            RMSVoltageMean = (sqrt(voltageMean))*1.5;                                                                 // The value X 1.5 means the ratio towards the module amplification.      
            adjustRMSVoltageMean = RMSVoltageMean + voltageOffset2;                                                   /* square root of the average value including offset value */                                                                                                                                                       /* square root of the average value*/                                                                                                             
            FinalRMSVoltage = RMSVoltageMean + voltageOffset2;                                                        /* this is the final RMS voltage*/
            if(FinalRMSVoltage <= 2.5)                                                                                /* to eliminate any possible ghost value*/
            {FinalRMSVoltage = 0;}
            Serial.print(" The Voltage RMS value is: ");
            Serial.print(FinalRMSVoltage,decimalPrecision);
            Serial.println(" V ");
            voltageSampleSum =0;                                                                                      /* to reset accumulate sample values for the next cycle */
            voltageSampleCount=0;                                                                                     /* to reset number of sample for the next cycle */
          }


}

Thanks

@Control ,

I have it done with a other code from Emonlib.
Using the Custom Sensor Component — ESPHome
I get nice readings inside ESPHome.
(I only connect a voltage not current)

You need to put in de EMonlib.h and Emonlib.ccp inside ESPHome Folder,

image


Then creat the file like “powersensor.h” and put there the code created from the Arduino code, but then translated into custom code language.


#include "esphome.h"
#include "EmonLib.h"

class MyPowerSensor : public PollingComponent, public Sensor {
  public:
   EnergyMonitor emon1;
   Sensor *realpower_sensor = new Sensor();
   Sensor *apparentpower_sensor = new Sensor();
   Sensor *powerfactor_sensor = new Sensor();
   Sensor *supplyvoltage_sensor = new Sensor();

   MyPowerSensor() : PollingComponent(1000) { }
  
  void setup() override {
   emon1.voltage(A0, 380.5, 1.7);
   }
  
  void update() override {
   emon1.calcVI(20,2000);
   float realPower = emon1.realPower;
   realpower_sensor->publish_state(realPower);
   float apparentPower = emon1.apparentPower;
   apparentpower_sensor->publish_state(apparentPower);
   float powerFactor = emon1.powerFactor;
   powerfactor_sensor->publish_state(powerFactor);
   float supplyVoltage = emon1.Vrms;
   supplyvoltage_sensor->publish_state(supplyVoltage);
   }
};


//
//
THE 380.5 IS THE CALIBRATION FACTOR!
USE YOUR OWN VALUE :wink:
//
//



Then create a yaml file, like power.yaml


esphome:
  name: power
  platform: your Platform
  board: your board
  includes:
  - powersensor.h
  - EmonLib.h
  - EmonLib.cpp

wifi:
  ssid: "SSID"
  password: "secretpassword"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Power Fallback Hotspot"
    password: "FCV8QTAaFy1K"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: ""

ota:
  password: ""

sensor:
- platform: custom
  lambda: |-
    auto my_sensor = new MyPowerSensor();
    App.register_component(my_sensor);
    return {my_sensor->realpower_sensor, my_sensor->apparentpower_sensor, my_sensor->powerfactor_sensor, my_sensor->supplyvoltage_sensor};
    
  sensors:
  - name: "RealPowerSensor"
    unit_of_measurement: W
    accuracy_decimals: 2
  - name: "ApparentPowerSensor"
    unit_of_measurement: VA
    accuracy_decimals: 2
  - name: "PowerFactor"
    accuracy_decimals: 2
  - name: "supplyVoltageSensor"
    unit_of_measurement: VA
    accuracy_decimals: 2

I’m now busy with a other code, better calibration and better readings.

I used a esp8266 but the esp32 is better! (you need to adjust the PIN from A0 → 34)



Also reminder that you better use a Logic Level Shifter
When you are using the esp8266



And also better to use a power suply directly on the zmpt101b/ESP8266 (or ESP32)
for better stable and acurate readings.


image

Litle update, I noticed that when I shut short the Voltage, the unit goes into a strange error…
Need to fix.

@mupsje
thank you for your advice :smiley:

Really nice work, well done. I’m building my own PVrouter and I’m aiming to use two of your nodes to achieve this.

I’m curious about continuous mode. From my understanding when continuous mode is set to true the sensor is actively reading data at all times. Therefore you can get away with…

  update_interval: 2s
    filters:
      - sliding_window_moving_average:
          window_size: 6
          send_every: 1

Essentially the readings are averaged already each update interval? Please correct me if I’m wrong.

I don’t know because continues mode does not work for me. See my original posting.

this is not a help at all, I’ve realized you are a moderator… that is not an answer, most of the people is aproaching this and most of them google all the posibilities, YAML is a piece of code wich most didnt know about, and esphome page is quite poor on examples, my background is on Arduino IDE, I make this work, but I can not hit the nail on yaml… so please if you are of the kind… can you please be more specific? Hope you understand the “rookie position of many people here” so please teach us. best regards

It was just a suggestion. It was also found not to be suitable due to this post directly after mine:

So no, I will not be expanding upon my suggestion as it is not a suitable solution. Please read the rest of the posts in this topic.

How did you calculate the calibration factor?

Great Thank you !