Power usage reading on Shelly RGBW2

Hello,

I managed to flash RGBW2 with ESPHome and so far it works as expected.

The only problem I have is getting power usage measurements. I have added A0 GPIO pin as ADC and it’s changing value as I increase the power, but it’s not linear.

I took measurements at different percentage and this is how the graph looks like:

Values:

Brightness in % A0 readout
poweroff 0,41602
0% 0,41602
10% 0,41602
20% 0,41699
30% 0,41699
40% 0,41797
50% 0,41992
60% 0,4248
70% 0,42871
80% 0,43555
90% 0,44141
100% 0,45117

It looks like exponential growth, but I can’t seem to get the correct function for proper calculation. Also it would be great to make it more linear as one changes the brightness.

Did anyone solve this?

My config if anyone needs it:

substitutions:
  devicename: shelly_rgbw2_generic
  friendly_name: Generic firmware for shelly
  device_description: Shelly LED dimmer

esphome:
  name: ${devicename}
  platform: ESP8266
  # Set modwifi on shelly devices since they have 2MB of flash
  board: modwifi

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  # Should make wifi signal better (https://www.die-welt.net/2020/04/controlling-roller-shutters-using-a-shelly-25-esphome-and-home-assistant/)
  power_save_mode: none
  manual_ip:
    static_ip: 192.168.50.69
    gateway: !secret ip_gateway
    subnet: !secret ip_subnet
    dns1: !secret ip_dns1

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: ${friendly_name}
    password: !secret ap_password

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:

time:
  # Sync RTC time with HA
  - platform: homeassistant
    id: homeassistant_time

text_sensor:
  # Sensor with esphome version and fw build time
  - platform: version
    name: ${friendly_name} version
  # Extra wifi info from device
  - platform: wifi_info
    ip_address:
      name: ${friendly_name} IP
    ssid:
      name: ${friendly_name} SSID
    bssid:
      name: ${friendly_name} BSSID

sensor:
  # Reports the WiFi signal strength
  - platform: wifi_signal
    name: ${friendly_name} RSSI
    update_interval: 60s
  # Reports how long the device has been powered (in hours) since last reboot
  - platform: uptime
    name: ${friendly_name} uptime
    update_interval: 60s
    filters:
      - lambda: return x / 3600;
    unit_of_measurement: "h"
  # Analog input (power usage)
  - platform: adc
    pin: A0
    name: "${friendly_name} power"
    update_interval: 1s
switch:
  - platform: restart
    name: ${friendly_name} restart

# Pins for output are found on
# https://translate.google.com/translate?sl=auto&tl=en&u=https%3A%2F%2Fbitekmindenhol.blog.hu%2F2019%2F03%2F30%2Fshelly_rgbw2

binary_sensor:
  # HA sensor showing if device is connected
  - platform: status
    name: ${friendly_name} status
  # Switch button
  - platform: gpio
    pin:
      number: GPIO5
      #mode: INPUT_PULLUP
      #inverted: True
    name: ${friendly_name} button
    on_click:
      then:
        - light.toggle: 
            id: lightid
    #internal: true
    id: switchid

output:
  - id: pwm_r
    platform: esp8266_pwm
    pin: 12
    frequency: 1000 Hz
    # min_power: 0.06
  - id: pwm_g
    platform: esp8266_pwm
    pin: 15
    frequency: 1000 Hz
    # min_power: 0.06
  - id: pwm_b
    platform: esp8266_pwm
    pin: 14
    frequency: 1000 Hz
    # min_power: 0.06
  - id: pwm_w
    platform: esp8266_pwm
    pin: 4
    frequency: 1000 Hz
    # min_power: 0.06

light:
  - platform: rgbw
    name: ${friendly_name} light
    default_transition_length: 0.3s
    red: pwm_r
    green: pwm_g
    blue: pwm_b
    white: pwm_w
    id: lightid
1 Like

The ADC is quite non-linear at the extreme ends of it’s range.

You have a table of measurements, use the linear calibration transform map: Sensor Component — ESPHome

1 Like

Yes, I just found out about calibrate-linear yesterday. I will try this option tomorrow.

Hey @mmz did you finally calibrate your rgbw2 power consumption.

Hi, did you have any success?

Got mine for 1 LED fo 12V 2W:

  - platform: adc
    pin: A0
    name: "${device_name} adc"
    update_interval: 5s
    accuracy_decimals: 4
    id: current_raw
    internal: true
  - platform: template
    name: "${device_name} power"
    unit_of_measurement: W
    accuracy_decimals: 1
    device_class: power
    lambda: return id(current_raw).state;
    filters:
      - calibrate_linear:
        - 0.4000 -> 0.0
        - 0.4043 -> 0.14
        - 0.4053 -> 0.20
      - multiply: 12 # 12V lamp

Did you find out how to do it without having to calibrate it? I am using the config below and even though it “works”, it still feels hackish and it’s only thanks to the fact I have a multimeter and get the values. Shelly is able to do it on stock firmware, so do you know what’s the limitation of getting it right from the beginning as well?

substitutions:
  device_name: bottommirror

esphome:
  name: ${device_name}
  platform: ESP8266
  board: esp01_1m

logger:
api:
ota:

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

  manual_ip:
    static_ip: 192.168.0.29
    gateway: 192.168.0.1
    subnet: 255.255.255.0


light:
  - platform: cwww
    name: "Bottom Bathroom Mirror"
    cold_white: ${device_name}_out_ch3
    warm_white: ${device_name}_out_ch4
    cold_white_color_temperature: 6536 K
    warm_white_color_temperature: 2650 K
    constant_brightness: false


# Example output entry
output:
  - platform: esp8266_pwm
    id: ${device_name}_out_ch1
    pin: GPIO12
    frequency: 1000 Hz
  - platform: esp8266_pwm
    id: ${device_name}_out_ch2
    pin: GPIO15
    frequency: 1000 Hz
  - platform: esp8266_pwm
    id: ${device_name}_out_ch3
    pin: GPIO14
    frequency: 1000 Hz
  - platform: esp8266_pwm
    id: ${device_name}_out_ch4
    pin: GPIO4
    frequency: 1000 Hz

sensor:
  - platform: wifi_signal
    name: "${device_name} - WiFi Signal"
    update_interval: 60s
  - platform: uptime
    name: "${device_name} - Uptime"
    icon: mdi:clock-outline
    update_interval: 60s
  - platform: uptime
    name: "${device_name} - Uptime Seconds"
    id: uptime_sensor
    update_interval: 60s
    on_raw_value:
      then:
        - text_sensor.template.publish:
            id: uptime_human
            state: !lambda |-
              int seconds = round(id(uptime_sensor).raw_state);
              int days = seconds / (24 * 3600);
              seconds = seconds % (24 * 3600);
              int hours = seconds / 3600;
              seconds = seconds % 3600;
              int minutes = seconds /  60;
              seconds = seconds % 60;
              return (
                (days ? String(days) + "d " : "") +
                (hours ? String(hours) + "h " : "") +
                (minutes ? String(minutes) + "m " : "") +
                (String(seconds) + "s")
              ).c_str();
  - platform: adc
    pin: A0
    name: "${device_name} - adc"
    update_interval: 5s
    accuracy_decimals: 4
    id: current_raw
    internal: true
  - platform: template
    name: "${device_name} - Power"
    unit_of_measurement: W
    accuracy_decimals: 1
    device_class: power
    update_interval: 5s
    id: my_power
    lambda: return id(current_raw).state;
    filters:
      - calibrate_linear:
        - 0.39551 -> 0.0
        - 0.43750 -> 1.5834
      - multiply: 24 # 24V strips
  - platform: total_daily_energy
    name: "${device_name} - Total Daily Energy"
    power_id: my_power
    filters:
        - multiply: 0.001
    unit_of_measurement: kW

# Enable time component to reset energy at midnight
time:
  - platform: sntp
    id: my_time

text_sensor:
  - platform: template
    name: "${device_name} - Uptime"
    id: uptime_human
    icon: mdi:clock-start
    update_interval: 60s

switch:
  - platform: restart
    name: "${device_name} - Restart"

Can I ask where you measured the value 1.5834? Is this a current from measuring in series?

The ADC on an ESP8266 is reporting a voltage (not current) from 0-1V (assuming its a bare chip), so 0.39551V and 0.43750V. If one were to open up an RGBW2 to look at where A0 is wired (resistors , etc) one could calculate the current (I think).

In any case, a measurement like yours should be fine and isn’t really a hack at all.

PS Note the ADC is has 1024 levels so 0.0009765625V steps (assuming its linear).

1 Like