MultiChannel ADS1115 ESPHome Energy Monitor with CT_CLAMPS

Hi, First post so please be gentle - Just really getting into Home Assistant and playing with sensors, trying to setup a energy monitor and whilst I have this working on 1 channel I want to get all four working.

Setup - Home Assistant on Docker (Raspberry Pi), D1 Mini flashed with ESPHOME, MottramLabs 4 channel ADS1115 and 4x CT013 Clamps

My code as per below … Any pointers on getting the other 3 sensors working would be appreciated as I’ve hit a brick wall trying to search for something to help…

# energy.yaml
# 2022-11-15 -

# Standard YAML Stuff
esphome:
  name: housepowermonitor
  platform: ESP8266
  board: d1_mini

# Enable Logger
logger:

# Enable Home Assistant API
api:

# Over the Air Password
ota:
  password: ""

# Network Configuration
wifi:
  networks:
  - ssid: "xxxxxxx"
    password: "xxxxxxx"

  # Fallback hotspot in case Wifi connection fails
  ap:
    ssid: "espfallback"
    password: ""

# Config
captive_portal:

# Web Server
web_server:
  port: 80
  auth:
    username: xxxxxxx
    password: xxxxxxx

# Time Services
time:
  platform: sntp
  id: my_time

# Hardware Control
i2c:
  sda: 4
  scl: 5
  scan: true
  id: bus_a

# Module
ads1115:
  - address: 0x48
    id: ads1115_48

# Sensors
sensor:
  # Input Sensor (Clamp)
  - platform: ads1115
    multiplexer: "A0_GND"
    gain: 6.144
    name: "ADS1115 Channel A0-GND"
    id: adc_sensor0

  # Read a known voltage from Home Assistant to get a more accurate running position
  - platform: homeassistant
    name: "Known Voltage"
    entity_id: sensor.g_dc1_energy_voltage
    id: known_volts

  # Daily Totals Sensor
  - platform: total_daily_energy
    name: "Total Daily Energy CH0"
    power_id: my_power0
    unit_of_measurement: "kWh"
    id: import_ct_total

  # Clamp Sensor
  - platform: ct_clamp
    sensor: adc_sensor0
    name: "Home Current CH0"
    id: livesensor0
    update_interval: 5s
    filters:
    -  calibrate_linear:
       - 0 -> 0
       - 0.02345 -> 4.646

  # Return Sensor
  - platform: template
    id: my_power0
    name: "Home Power CH1"
    lambda: return id(livesensor0).state * id(known_volts).state / 1000;
    update_interval: 5s

Just theory. Have you tried adding another (for channel A1->GND)

- platform: ads1115
    multiplexer: "A1_GND"
    gain: 6.144
    name: "ADS1115 Channel A1-GND"
    id: adc_sensor1

 # Clamp Sensor
  - platform: ct_clamp
    sensor: adc_sensor1
    name: "Home Current CH0"
    id: livesensor1 // changed
    update_interval: 5s
    filters:
    -  calibrate_linear:
       - 0 -> 0
       - 0.02345 -> 4.646

etc.

replacing every 0 in name or id with 1?

How did you get on with this?

This is the code I am running that is working …

ads1115:

1st ADS1115 (ADDR → Grnd)

  • address: 0x48
    id: ads1115_1

sensor:

Channel 1

  • platform: ct_clamp
    sensor: ads1115_1_a0
    id: current_ch1
    name: “NRG-ESP-1 House Current”
    update_interval: 15s
    filters:

    • calibrate_linear:
      • 0 → 0
      • 0.00049 → 0.017
      • 0.01984 → 3.842
      • 0.02096 → 3.931
      • 0.02421 → 4.656
      • 0.04293 → 8.475
      • 0.05668 → 11.16

    When Current updates, update Watts

    on_value:
    then:
    - sensor.template.publish:
    id: watts_ch1
    # home_voltage is taken from a TasMota Plug in G_DC1
    state: !lambda ‘return id(current_ch1).state * id(home_voltage).state;’

  • platform: ads1115
    ads1115_id: ads1115_1
    multiplexer: ‘A0_GND’
    gain: 6.144
    name: “ADS1115-1-A0”
    id: ads1115_1_a0
    update_interval: 15s
    internal: true

Channel 2

  • platform: ct_clamp
    sensor: ads1115_1_a1
    id: current_ch2
    name: “NRG-ESP-2 Kitchen Current”
    update_interval: 15s
    filters:

    • calibrate_linear:

      Sensor map 0.0 (from sensor) → 0.0 (true value)

      • 0 → 0
      • 0.00049 → 0.017
      • 0.01984 → 3.842
      • 0.02096 → 3.931
      • 0.02421 → 4.656
      • 0.04293 → 8.475
      • 0.05668 → 11.16

    When Current updates, update Watts

    on_value:
    then:
    - sensor.template.publish:
    id: watts_ch2
    # home_voltage is taken from a TasMota Plug in G_DC1
    state: !lambda ‘return id(current_ch2).state * id(home_voltage).state;’

  • platform: ads1115
    ads1115_id: ads1115_1
    multiplexer: ‘A1_GND’
    gain: 6.144
    name: “ADS1115-1-A1”
    id: ads1115_1_a1
    update_interval: 15s
    internal: true

Channel 3

  • platform: ct_clamp
    sensor: ads1115_1_a2
    id: current_ch3
    name: “NRG-ESP-3 Exterior Current”
    update_interval: 15s
    filters:

    • calibrate_linear:
      • 0 → 0
      • 0.00049 → 0.017
      • 0.01984 → 3.842
      • 0.02096 → 3.931
      • 0.02421 → 4.656
      • 0.04293 → 8.475
      • 0.05668 → 11.16

    When Current updates, update Watts

    on_value:
    then:
    - sensor.template.publish:
    id: watts_ch3
    # home_voltage is taken from a TasMota Plug in G_DC1
    state: !lambda ‘return id(current_ch3).state * id(home_voltage).state;’

  • platform: ads1115
    ads1115_id: ads1115_1
    multiplexer: ‘A2_GND’
    gain: 6.144
    name: “ADS1115-1-A2”
    id: ads1115_1_a2
    update_interval: 15s
    internal: true

Channel 4

  • platform: ct_clamp
    sensor: ads1115_1_a3
    id: current_ch4
    name: "NRG-ESP-4 "
    update_interval: 15s
    #filters:

    - calibrate_linear:

    - 0 → 0

    - 0.02344 → 4.648

    When Current updates, update Watts

    on_value:
    then:
    - sensor.template.publish:
    id: watts_ch4
    # home_voltage is taken from a TasMota Plug in G_DC1
    state: !lambda ‘return id(current_ch4).state * id(home_voltage).state;’

  • platform: ads1115
    ads1115_id: ads1115_1
    multiplexer: ‘A3_GND’
    gain: 6.144
    name: “ADS1115-1-A3”
    id: ads1115_1_a3
    update_interval: 15s
    internal: true

Template Sensors for Watts

  • platform: template
    id: watts_ch1
    name: “NRG-ESP-1 House Watts”
    lambda: return {};
    unit_of_measurement: W
    accuracy_decimals: 0
    device_class: power

  • platform: template
    id: watts_ch2
    name: “NRG-ESP-2 Kitchen Watts”
    lambda: return {};
    unit_of_measurement: W
    accuracy_decimals: 0
    device_class: power

  • platform: template
    id: watts_ch3
    name: “NRG-ESP-3 Exterior Watts”
    lambda: return {};
    unit_of_measurement: W
    accuracy_decimals: 0
    device_class: power

  • platform: template
    id: watts_ch4
    name: “NRG-ESP-4 Watts”
    lambda: return {};
    unit_of_measurement: W
    accuracy_decimals: 0
    device_class: power

Total

  • platform: template
    id: combo_watts
    name: “NRG-ESP Total Watts”
    lambda: |-
    return (id(watts_ch1).state + id(watts_ch2).state + id(watts_ch3).state + id(watts_ch4).state);
    unit_of_measurement: W
    accuracy_decimals: 0
    device_class: power
    update_interval: 30s

Energy Sensors (kWh) for HA Dashboard

  • platform: total_daily_energy
    name: “NRG-ESP-1 House Total kWh”
    power_id: watts_ch1
    filters:

    • multiply: 0.001
      unit_of_measurement: kWh
  • platform: total_daily_energy
    name: “NRG-ESP-2 Kitchen Total kWh”
    power_id: watts_ch2
    filters:

    • multiply: 0.001
      unit_of_measurement: kWh
  • platform: total_daily_energy
    name: “NRG-ESP-3 Exterior Total kWh”
    power_id: watts_ch3
    filters:

    • multiply: 0.001
      unit_of_measurement: kWh
  • platform: total_daily_energy
    name: “NRG-ESP-4 Total kWh”
    power_id: watts_ch4
    filters:

    • multiply: 0.001
      unit_of_measurement: kWh

Voltage from HA

  • platform: homeassistant
    name: “Voltage From Home Assistant”

entity_id: sensor.s_desk_energy_voltage

entity_id: sensor.average_voltage
id: home_voltage
  • platform: wifi_signal
    name: “NRG-ESP WiFi Signal Sensor”
    id: espwifi
    update_interval: 60s

  • platform: uptime
    name: “NRG-ESP Uptime”
    id: espuptime
    update_interval: 60s
    filters:

    • lambda: return x / 3600.0;
      unit_of_measurement: “hrs”
      accuracy_decimals: 2

Hello,

I’m trying to do similar thing, but I’m not sure how to connect the CT clamp with the ADS1115 and the Weemos D1 mini.

I have try to directly connect the CT clamp between A0 and GND and I retreive some small negative values from ADS1115 input voltage. I also try with this schema and I retreive positive values arround 1.64V without real changes when I change the current.

Could you explain my how you connect your CT clamps in your case and if it works well now ?

Thanks !

I also get a few negative values when I’ve tried, since using these I’ve finally got my energy supplier to replace my smart meters to SMET2 and I’ve treated myself to a Glow device to send MQTT data from the meters to HA. The clamps are still in place as it does give me some other data (I.e. a couple of specific rooms have their own clamp)

Nice ! Could you share with me some details of your CT clamps connections with the ADS1115 and finally the ESP devices ? Do you have some extra components between the ADS and the CT clamps (resistors, capacitors, …) ? May be a photo or a quick & dirty schema could really hep me! Thanks !

help here?

Hi @brenard ,

Did you manage to do it? Do you have any schema?

It’s depending on your ct clamp style. If it’s a mA version, you’ll need a burden resistor to convert to volts for the ads to read.

Then, because the CT clamp will swing 1v to -1v and the ads only reads positive voltage, you’ll need to bias the 3.3v input in half using 2x 10k resistors to 1.65 ish volts (basically 1.65 will be 0 so the ads can read the full ac voltage wave). A cap is used to decouple and stabilize the reference 1.65 voltage.

Here is a diagram with a volt style CT clamp (has a burden resistor added internally). If your ct clamp is amp style, it will need a burden resistor between the CT clamp wires, close to the clamp.

The ADS1115 is wired to the esp using 4 pins; the i2c pins (SDA, SCL), 3.3v and ground. One leg of the CT clamp goes to ADS1115 A0, the other leg gets the 3.3v biased input (0-1.65 is negative, 1.65xx = 0, 1.65-3.3 is positive).

substitutions:
  friendly_name: esp32-dryer

i2c:
  id: adc_ext
  scl: 9
  sda: 8
   
ads1115:
  address: 0x48
  # Needed for CT clamp
  continuous_mode: on
  id: ads0

sensor:
# pull in data from a hass sensor, in this case, voltage pulled from my washing machine ZigBee power monitoring plug.
  - platform: homeassistant
    entity_id: sensor.0x70b3d52b600114bb_voltage
    id: voltage

  - platform: ads1115
    multiplexer: 'A0_GND'
    gain: 6.144
    name: "${friendly_name} - A0 - Voltage"
    accuracy_decimals: 5
    internal: True
    id: ads_a0
    ads1115_id: ads0
    update_interval: 500ms

  - platform: ct_clamp
    # 1V/30A clamp
    sensor: ads_a0
    id: raw0
    name: "${friendly_name} - A0 - Raw"
    sample_duration: 300ms
    update_interval: 1000ms
    accuracy_decimals: 5

  - platform: ct_clamp
    # 1V/30A clamp
    sensor: ads_a0
    id: current0
    name: "${friendly_name} - A0 - Calibrated"
    sample_duration: 300ms
    update_interval: 1000ms
    accuracy_decimals: 5
    # calibrate with a multimeter
    filters: 
      # RAW A -> Calibrated A
      - calibrate_linear: 
        - 0 -> 0
        - 0.15146 -> 4.00
        - 0.88471 -> 25.90
      - clamp:
          min_value: 0
          max_value: 30
          ignore_out_of_range: false

  - platform: template
    name: "${friendly_name} - Watts"
    id: watts0
    device_class: power
    state_class: measurement
    unit_of_measurement: W
    # Change int volts = xxx; to whatever your house voltage *should* be.
    # If the hass sensor pulling voltage ever fails, it will default to this value.
    lambda: |-
      int volts = 120;
      if (!(isnan(id(voltage).state))) {
        volts = id(voltage).state;
      }
      return (id(current0).state * volts);
    update_interval: 1s
    # if you have no hass sensor for voltage, remove the hass sensor from above and have this lambda return xxx V 
#    lambda: |-
#      int volts = 120;
#      return (id(current0).state * volts);

To convert to watts you’ll need to know the voltage of your house, or you can base it off of whatever your mains voltage is supposed to be (120V AC here in Canada). Change the watts template lambda base voltage to what yours is, or you can use a hass sensor (id: voltage in the above example) if you already have some device pulling in voltage.

To calibrate

The pertinent part is here:

    # calibrate with a multimeter
    filters: 
      # RAW A -> Calibrated A
      - calibrate_linear: 
        - 0 -> 0
        - 0.15146 -> 4.00
        - 0.88471 -> 25.90
      - clamp:
          min_value: 0
          max_value: 30
          ignore_out_of_range: false
  • calibrate_linear: 0.15146 -> 4.00 means, when the raw sensor (raw reading from the clamp) is reporting 0.15146 A, a calibrated measuring device is reporting 4.00 A. esphome will take care of the heavy lifting. Notice how I used 3 calibration points for finer tuned results (AFAIK).

  • clamp (naming is a coincidence) will not report values outside of the ct clamps reported range (due to sllght calibration issues). In my case I have a 30 Amp clamp that outputs 1V, so I dont want negative results below 0 or higher readings above 30.

You can use a cheap aliexpress amp clamp style multimeter to calibrate your CT clamps to output acceptable data. In my case I was calibrating using an electric dryer, which isn’t easy because it is not a constant load.

If you can, calibrate using a constant load for a more dialed in output.


Adding a roughly 3 cm wire to the esp32-c3 supermini antenna pad has increased the sign al quite a bit. This PCB has the crystal pretty close to the cap antenna so I used a wire instead. Make sure to put the wire on the correct pad