Calibrating the voltage of an ESPhome Smart Plug

Hello everyone,

I have multiple smart plugs from Athom some of them are V1 and the others are V2 and all of them flashed with ESPhome.

I live in Germany and the Voltage here is 230V and the V2s are reading the right value, but the V1s are showing the voltage as 220V, which is wrong.

Furthermore, I have found online that I can calibrate the plug using the option:

  filters:
    - calibrate_linear:
        # Map 0.0 (from sensor) to 0.0 (true value)
        - 0.0 -> 0.0

The problem is when I try to edit the configuration file from ESPHome dashboard to override some values from the original configuration file, the plug starts to read the voltage as 0.

My question is, where/how can I add my celebration values to my config file to be able to update/overwrite the original one?
This is my current config file:

substitutions:
  device_name: "plug-kitchen"
  name: plug-kitchen
  friendly_name: "Plug Kitchen"
packages:
  athom.smart-plug-v2: github://athom-tech/athom-configs/athom-smart-plug.yaml
esphome:
  name: ${name}
  name_add_mac_suffix: false

wifi:
  use_address: 192.168.8.115
  ssid: !secret wifi_ssid
  password: !secret wifi_password

and this is the original config file I’m using as a base https://github.com/athom-tech/athom-configs/blob/6502aa9b33ce4a841e20dd55c80cf813fa71f404/athom-smart-plug.yaml

Oher links that might be helpful:
Page of the product: https://www.athom.tech/blank-1/esphome-eu-plug

My best
Mash

Here is the way I apply the filter to calibrate my Sonoff S31 devices (only pertinent code snippet):

in my common file:

sensor:
  - platform: cse7766
    update_interval: 3s
    voltage:
      name: "${friendly_name} Voltage"
      unit_of_measurement: V
      accuracy_decimals: 1
      filters:
        # Map from sensor -> measured value
        - calibrate_linear:
          - ${cal_volt_lower}
          - ${cal_volt_mid_lower}
          - ${cal_volt_mid_upper}
          - ${cal_volt_upper}

then in my substitution file:

substitutions:
# sensor value in ESPHome -> real measured value
  cal_volt_lower: 116.2 -> 117.6
  cal_volt_mid_lower: 120.2 -> 121.5
  cal_volt_mid_upper: 121.4 -> 122.6
  cal_volt_upper: 121.5 -> 122.7
  
<<: !include common_sonoff_s31.yaml
2 Likes

okay okay okay.
Please… i need some reality check help.

I got the Athom V1 and the yaml from their Github page.

so i tried to Modify the power to suite my needs…
But i fail at empty Load values in Watt.

[13:35:03][D][hlw8012:082]: Got power=3.4W, voltage=202.1V
[13:35:03][D][sensor:093]: ‘Power’: Sending state 11.09113 W with 1 decimals of accuracy

there is currently NO load connected. so it should send 0W even though it gets 3.4W

But if i modify that

    power:
      name: "Power"
      id: socket_my_power
      unit_of_measurement: W
      filters:
          - calibrate_linear:
            - 0.0000 -> 0.5900 # Relay off no load
            - 0.0000 -> 4.5600 # Relay on no load
            - 783.4000 -> 369.0000
            - 794.8000 -> 371.0000 #cali eierkocher
            - 2043.0282 -> 885.0000
          # Normalize for plug load
          - lambda: if (x < 4.56000) return 0; else return (x - 4.56000);
    change_mode_every: 1
    update_interval: 5s

|13:38:11|[D]|[hlw8012:076]|Got power=3.4W, current=0.1A|
|13:38:11|[D]|[sensor:093]|‘Power’: Sending state 9.25112 W with 1 decimals of accuracy|

So i changed it the other way around:

    power:
      name: "Power"
      id: socket_my_power
      unit_of_measurement: W
      filters:
          - calibrate_linear:
            - 0.0000 -> 0.0900 # Relay off no load
            - 3.4000 -> 0.4000 # Relay on no load
            - 783.4000 -> 369.0000
            - 794.8000 -> 371.0000 #cali eierkocher
            - 2043.0282 -> 885.0000
          # Normalize for plug load
          - lambda: if (x < 0.4000) return 0; else return (x - 0.4000);
    change_mode_every: 1
    update_interval: 5s

|13:43:44|[D]|[hlw8012:082]|Got power=3.4W, voltage=201.0V|
|13:43:44|[D]|[sensor:093]|‘Power’: Sending state 11.04743 W with 1 decimals of accuracy|

Honestly… i don’t get it anymore.

If you uses calibrate_linear, ESPhome will fit a linear model with an intercept. Depending on how well your calibration readings fit a line with zero-intercept, you will get better or worse performance in the low range. So it is preferable to enforce zero-intercept. Your data looks like this:

You can see the discrepancy near the origin of the graph.

I have evaluated the linearity of my smart plug and found that the response is pretty perfectly linear. So I use a careful single-point calibration with a zero intercept. Something along those lines:

voltage:
      name: "${devicename} - Voltage"
      unit_of_measurement: V
      accuracy_decimals: 1
      icon: mdi:flash-outline
      filters:
        - multiply: 0.8658

Or just give two value pairs to calibrate_linear (one at zero, one at a high load). I don’t handle the correction for power consumption by the smart plug in the config, but simple subtract it from the true-reading value before using it. That way, ESPhome will only report the power consumption of the load but not that of the plug which is what I want. If you want to have that included, you would have to correct it by adding it and handling the state of the relay there as well.

I have written a blog post about my findings. Sorry, German only, but the comments in your config file suggest you speak German…

1 Like

luckily i do speak german.
Found your blogpost before when i was searching the web for soultions.

but my issue here is something else.
This cheap plugs are known to have “ghosting” issues below 5W. And that seems to be my problem.
Thats why i tried to modify the linear calibration to be Stuck to 0W until the ghosting is gone and then scale up.

Something like that (fictional values)
image

Ah – ok. There may be a way to get that: calibrate_linear has a method parameter. If you set that to exact it will not fit a linear model but use a line connecting the actual data points. See https://esphome.io/components/sensor/index.html#calibrate-linear

now thats one of the better written help pages from esphome!

Lambda should actualy do that.
- lambda: if (x < 0.4000) return 0; else return (x - 0.4000);
Is just… whatever…
If X is bigger than 4.5W return 0, else retun (x)
no clue whe they subtract 0.4 from X there. Is that supposed to be the powerdrain the unit itself has?