First ESPHome Custom Sensor ZMPT101B Voltage Sensor

Hi there.

This entire thing is someone else’s brain child, although I set this up so long ago, I can’t recall who I need to give credit to :confused:

The really relevant parts are as follows:

esp8266:
  board: d1_mini

esphome:
  name: "mains-voltage"

  includes:
    - custom_sensor.h

external_components:
  - source:
      type: git
      url: https://github.com/robertklep/esphome-custom-component
    components: [ custom, custom_component ]

logger:
  level: INFO

# The rest of your code for the node

sensor:
# Mains Voltage 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"
      filters:
        - lambda: |
              if (x < 120) return 0;
              else return (x);
        - sliding_window_moving_average:
              window_size: 5
              send_every: 5
      on_value:
        then:
          - if:
              condition:
                - lambda: 'return id(${sen_id}).state > 240;'
              then:
                - switch.turn_on: ${sen_id}_high
              else:
                - switch.turn_off: ${sen_id}_high
          - if:
              condition:
                and:
                  - lambda: 'return id(${sen_id}).state <= 240;'
                  - lambda: 'return id(${sen_id}).state > 210;'
              then:
                - switch.turn_on: ${sen_id}_ok
              else:
                - switch.turn_off: ${sen_id}_ok
          - if:
              condition:
                and:
                  - lambda: 'return id(${sen_id}).state <= 210;'
                  - lambda: 'return id(${sen_id}).state > 180;'
              then:
                - switch.turn_on: ${sen_id}_low
              else:
                - switch.turn_off: ${sen_id}_low
          - if:
              condition:
                - lambda: 'return id(${sen_id}).state <= 180;'
              then:
                - switch.turn_on: ${sen_id}_no_power
                - light.turn_on:
                    id: led_${sen_id}_status
                    brightness: 50%
                    effect: pulse
              else:
                - switch.turn_off: ${sen_id}_no_power
                - light.turn_off: led_${sen_id}_status

binary_sensor:
  - platform: template
    id: mains_status
    name: "Mains Status"
    lambda: |-
      return id(${sen_id}).state > 140.0;

I didn’t know if you’d want to use the “High”, “Ok”, “Low” etc, so I just left that in, and I also added the binary sensor for the sake of having a definitive On/Off state.

And a manually created file named custom_sensor.h, which needs to go in the root of your ESPHome directory with the contents being:

#include "esphome.h"
#include <Arduino.h>

#define VMAX 250
#define FREQUENCY 50
#define CALIBRATE_READ 130
#define CALIBRATE_ACTUAL 225.25
#define ZERO_VAC 796

class ZMPT101BSensor : public PollingComponent, public Sensor {
  public:
    // constructor
    ZMPT101BSensor() : PollingComponent(1000) {}

    float get_setup_priority() const override { return esphome::setup_priority::HARDWARE; }

    void setup() override {
      // This will be called by App.setup()
    }

    void update() override {
    // This will be called every "update_interval" milliseconds.

      uint32_t period = 1000000 / FREQUENCY;
      uint32_t t_start = micros();
      uint32_t Vsum = 0, measurements_count = 0;
      int32_t Vnow;

      while (micros() - t_start < period) {
        Vnow = analogRead(A0) - ZERO_VAC;
        Vsum += Vnow*Vnow;
        measurements_count++;
      }

      float Vrms = sqrt(Vsum / measurements_count) / CALIBRATE_READ * CALIBRATE_ACTUAL;
      publish_state(int(Vrms));

    }
};

For setting up the ZMPT101B you can just watch these 3 videos:

to get a better understanding of the calibration, otherwise, if you do a search for ZMPT101B Calibration, there are a couple of YouTube videos that show you how to calibrate this sensor with Arduino code, which is the way I did it, and then just re-flashed the node in ESPHome afterwards.

As all the videos recommend, Be Very mindful of the fact that you are messing with Mains Voltage! (Thought I’d better include that :man_shrugging: )

There will be some final adjustments you would need to make to the custom_sensor.h in the end, as the measurements at your DB and mine would be considerably different depending if you are being supplied 110v, 220v, 250v etc in this section:

#define VMAX 250
#define FREQUENCY 50
#define CALIBRATE_READ 130
#define CALIBRATE_ACTUAL 225.25
#define ZERO_VAC 796

This article also gives a fair amount of setup and advice:

Hope this helps!

1 Like