Skip to content

Instantly share code, notes, and snippets.

@flaviut
Last active August 22, 2024 18:14
Show Gist options
  • Save flaviut/93a1212c7b165c7674693a45ad52c512 to your computer and use it in GitHub Desktop.
Save flaviut/93a1212c7b165c7674693a45ad52c512 to your computer and use it in GitHub Desktop.
Setting up Emporia Vue 2 with ESPHome
@poblabs
Copy link

poblabs commented Jun 20, 2022

@poblabs re. the time, I don't know.

I live in America/New_York too, my config is

time:
  - platform: sntp
    id: my_time

and everything works perfectly:

2022-06-20-102634_375x299_scrot

Only idea I have here is that maybe you have a router firewall blocking outbound UDP connections on port 123. I don't know anything about the homeassistant time platform. You can try asking the esphome community.

Just curious then - are your esphome logs in UTC with sntp set? Also does your daily power reset at 8pm or midnight? Looks like midnight on that chart

@flaviut
Copy link
Author

flaviut commented Jun 20, 2022

@poblabs

Logs are in local time:

[10:50:35][D][sensor:125]: 'Circuit 8 Daily Energy': Sending state 180.83740 Wh with 0 decimals of accuracy
[10:50:35][D][sensor:125]: 'Circuit 9 Power': Sending state 0.25883 W with 0 decimals of accuracy
[10:50:35][D][sensor:125]: 'Circuit 9 Daily Energy': Sending state 4.03635 Wh with 0 decimals of accuracy
[10:50:35][D][sensor:125]: 'Circuit 10 Power': Sending state 12.47641 W with 0 decimals of accuracy

And the daily reset happens at midnight.

@poblabs
Copy link

poblabs commented Jun 20, 2022

@poblabs

Logs are in local time:

[10:50:35][D][sensor:125]: 'Circuit 8 Daily Energy': Sending state 180.83740 Wh with 0 decimals of accuracy
[10:50:35][D][sensor:125]: 'Circuit 9 Power': Sending state 0.25883 W with 0 decimals of accuracy
[10:50:35][D][sensor:125]: 'Circuit 9 Daily Energy': Sending state 4.03635 Wh with 0 decimals of accuracy
[10:50:35][D][sensor:125]: 'Circuit 10 Power': Sending state 12.47641 W with 0 decimals of accuracy

And the daily reset happens at midnight.

Thanks for confirming, and thanks for all your work with this! I'll have to dig in deeper outside of the emporia firmware 😄

@poblabs
Copy link

poblabs commented Jun 20, 2022

EDIT I've figured it out. I'm running esphome in Docker, and I need to pass the timezone through to the container using environment variables.

Thanks to this link for the insight

example:

    volumes:
      - "./data:/config"
      - /etc/localtime:/etc/localtime
      - /etc/timezone:/etc/timezone

@VivantSenior
Copy link

I think I've figured it out also ;-) My issue what that even when sensor wasn't connected to the port the output was like random noise. When I connected the clamp it looks good:
image

Missing data at 16:06 and later it's my Emporia dropping from the wifi.

@flaviut, is there a smart way to do in ESPHome a sensor that will calculate power from the other circuts not measured by Emporia (by phase)? Something like this:

phase_a_other_circuts_power = id(phase_a_power).state - sum(all measured circurs on phase a)

and the same for daily energy.

@flaviut
Copy link
Author

flaviut commented Jun 21, 2022

@VivantSenior glad to hear you figured it out!

Re. doing math on results, copy "Total Power" in the config and try and modify it for your situation.

@cshields
Copy link

First, thanks for this! Truly epic.

Have you heard of an issue where half of the CTs/ports go dead at the same time after working fine for days? I'm pretty sure something went belly up in the hardware but figure I'd ask. At first I thought it must be a fried multiplexer, but the bad ports span both of them.

@flaviut
Copy link
Author

flaviut commented Jun 22, 2022

@cshields all on the same phase? Check the wiring on the 2x2 connector: that all the wire nuts are tight, screws tight, and connector completely inserted.

@Ofloo
Copy link

Ofloo commented Jun 25, 2022

energy monitor keeps disconnecting, ..

INFO energy-monitor.local: Error while reading incoming messages: Error while reading data: 0 bytes read on a total of 1 expected bytes
INFO Disconnected from ESPHome API for energy-monitor.local
WARNING Disconnected from API
INFO energy-monitor.local: Ping Failed: Error while reading data: 0 bytes read on a total of 1 expected bytes
INFO Successfully connected to energy-monitor.local

Configuration:

Config
substitutions:
  devicename: "energy-monitor"
  upper_devicename: "emporiavue2"

  wifi_ssid: !secret iot_wifi_ssid
  wifi_pass: !secret iot_wifi_password
  fallback_pass: !secret fallback_wifi_password
  api_pass: !secret esp_api_password
  ota_pass: !secret esp_ota_password
  webserver_username: !secret webserver_username
  webserver_password: !secret webserver_password

esphome:
  name: $devicename

external_components:
  - source: github://flaviut/esphome@emporia-vue-2022.4.0
    components: [ emporia_vue ]

esp32:
  board: esp32dev
  framework:
    type: esp-idf
    version: recommended
    
# Enable Home Assistant API
api:
  password: "${api_pass}"

# Enable over the air updates
ota:
  password: "${ota_pass}"

# Enable logging
logger:

wifi:
  ssid: "${wifi_ssid}"
  password: "${wifi_pass}"

i2c:
  sda: 21
  scl: 22
  scan: false
  frequency: 200kHz  # recommended range is 50-200kHz
  id: i2c_a
  
time:
  - platform: sntp
    timezone: 'CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00'
    id: my_time
    servers: 
      - 162.159.200.123
      - 195.13.23.5
      - 195.13.1.153
    on_time_sync:
      then:
        - logger.log: "Synchronized system clock"

# these are called references in YAML. They allow you to reuse
# this configuration in each sensor, while only defining it once
.defaultfilters:
  - &moving_avg
    # we capture a new sample every 0.24 seconds, so the time can
    # be calculated from the number of samples as n * 0.24.
    sliding_window_moving_average:
      # we average over the past 2.88 seconds
      window_size: 12
      # we push a new value every 1.44 seconds
      send_every: 6
  - &invert
    # invert and filter out any values below 0.
    lambda: 'return max(-x, 0.0f);'
  - &pos
    # filter out any values below 0.
    lambda: 'return max(x, 0.0f);'
  - &abs
    # take the absolute value of the value
    lambda: 'return abs(x);'

sensor:
  - platform: emporia_vue
    i2c_id: i2c_a
    phases:
      - id: phase_a  # Verify that this specific phase/leg is connected to correct input wire color on device listed below
        input: BLACK  # Vue device wire color
        calibration: 0.02260  # 0.022 is used as the default as starting point but may need adjusted to ensure accuracy
        # To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
        voltage:
          name: "Grid Voltage"
          filters: [*moving_avg, *pos]
      - id: phase_b  # Verify that this specific phase/leg is connected to correct input wire color on device listed below
        input: RED  # Vue device wire color
        calibration: 0.02260  # 0.022 is used as the default as starting point but may need adjusted to ensure accuracy
        # To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
        voltage:
          name: "Neutral Voltage"
          filters: [*moving_avg, *pos]
      - id: phase_c  # Verify that this specific phase/leg is connected to correct input wire color on device listed below
        input: BLUE  # Vue device wire color
        calibration: 0.02260  # 0.022 is used as the default as starting point but may need adjusted to ensure accuracy
        # To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
        voltage:
          name: "PE Voltage"
          filters: [*moving_avg, *pos]
    ct_clamps:
      - phase_id: phase_a
        input: "A"  # Verify the CT going to this device input also matches the phase/leg
        power:
          name: "Grid Power"
          id: phase_a_power
          device_class: power
          filters: [*moving_avg, *pos]
      - phase_id: phase_b
        input: "B"  # Verify the CT going to this device input also matches the phase/leg
        power:
          name: "Neutral Power"
          id: phase_b_power
          device_class: power
          filters: [*moving_avg, *pos]
      - phase_id: phase_c
        input: "C"  # Verify the CT going to this device input also matches the phase/leg
        power:
          name: "PE Power"
          id: phase_c_power
          device_class: power
          filters: [*moving_avg, *pos]
      # Pay close attention to set the phase_id for each breaker by matching it to the phase/leg it connects to in the panel
      - { phase_id: phase_a, input:  "1", power: { name:  "Circuit 1 Power", id:  cir1, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "2", power: { name:  "Circuit 2 Power", id:  cir2, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "3", power: { name:  "Circuit 3 Power", id:  cir3, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "4", power: { name:  "Circuit 4 Power", id:  cir4, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "5", power: { name:  "Circuit 5 Power", id:  cir5, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "6", power: { name:  "Circuit 6 Power", id:  cir6, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "7", power: { name:  "Circuit 7 Power", id:  cir7, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "8", power: { name:  "Circuit 8 Power", id:  cir8, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "9", power: { name:  "Circuit 9 Power", id:  cir9, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "10", power: { name: "Circuit 10 Power", id: cir10, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "11", power: { name: "Circuit 11 Power", id: cir11, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "12", power: { name: "Circuit 12 Power", id: cir12, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "13", power: { name: "Circuit 13 Power", id: cir13, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "14", power: { name: "Circuit 14 Power", id: cir14, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "15", power: { name: "Circuit 15 Power", id: cir15, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "16", power: { name: "Circuit 16 Power", id: cir16, filters: [ *moving_avg, *pos ] } }
  # phase A L1
  - platform: template
    name: "Total Power Grid"
    lambda: return id(phase_a_power).state;
    update_interval: 1s
    id: total_power_a
    unit_of_measurement: "W"
  - platform: total_daily_energy
    name: "Total Daily Energy Grid"
    power_id: total_power_a
    accuracy_decimals: 0
  # phase B Neutral
  - platform: template
    name: "Total Power Neutral"
    lambda: return id(phase_b_power).state;
    update_interval: 5s
    id: total_power_b
    unit_of_measurement: "W"
  - platform: total_daily_energy
    name: "Total Daily Energy Neutral"
    power_id: total_power_b
    accuracy_decimals: 0
  # phase C to Earth
  - platform: template
    name: "Total Power PE"
    lambda: return id(phase_c_power).state;
    update_interval: 5s
    id: total_power_c
    unit_of_measurement: "W"
  - platform: total_daily_energy
    name: "Total Daily Energy PE"
    power_id: total_power_c
    accuracy_decimals: 0

  - { power_id:  cir1, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 1 Daily Energy" }
  - { power_id:  cir2, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 2 Daily Energy" }
  - { power_id:  cir3, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 3 Daily Energy" }
  - { power_id:  cir4, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 4 Daily Energy" }
  - { power_id:  cir5, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 5 Daily Energy" }
  - { power_id:  cir6, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 6 Daily Energy" }
  - { power_id:  cir7, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 7 Daily Energy" }
  - { power_id:  cir8, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 8 Daily Energy" }
  - { power_id:  cir9, platform: total_daily_energy, accuracy_decimals: 0, name:  "Circuit 9 Daily Energy" }
  - { power_id: cir10, platform: total_daily_energy, accuracy_decimals: 0, name: "Circuit 10 Daily Energy" }
  - { power_id: cir11, platform: total_daily_energy, accuracy_decimals: 0, name: "Circuit 11 Daily Energy" }
  - { power_id: cir12, platform: total_daily_energy, accuracy_decimals: 0, name: "Circuit 12 Daily Energy" }
  - { power_id: cir13, platform: total_daily_energy, accuracy_decimals: 0, name: "Circuit 13 Daily Energy" }
  - { power_id: cir14, platform: total_daily_energy, accuracy_decimals: 0, name: "Circuit 14 Daily Energy" }
  - { power_id: cir15, platform: total_daily_energy, accuracy_decimals: 0, name: "Circuit 15 Daily Energy" }
  - { power_id: cir16, platform: total_daily_energy, accuracy_decimals: 0, name: "Circuit 16 Daily Energy" }

@flaviut
Copy link
Author

flaviut commented Jun 26, 2022

@Ofloo I'm not sure; are you able to get any logs over the serial adapter, ideally while not connected to mains?

If not, I'd suggest reaching out to general ESPHome community and asking them. Please remember to let us know how you solved this!

@Ofloo
Copy link

Ofloo commented Jun 26, 2022 via email

@devWaves
Copy link

devWaves commented Jun 27, 2022

@flaviut just wanted to say thanks for this (also thanks to ESPhome devs). Works awesome. I am now using the MQTT integration at it is exactly what I wanted. So you can update your documentation to say MQTT is working

The main reason I wanted it was to monitor things like the electric stove/oven if it was accidentaly left on while we are away or when everyone is asleep etc. I could only trust a local solution for that

@tappyson
Copy link

Hi. Thank you so much for the brilliant work on this. I managed to flash my Emporia Vue and it seems to be working perfectly. I ran it with the Emporia software and the cloud prior to make sure it all worked fine before I went ahead an flashed it. My issue (Due to lack of templating knowledge) now is that I have a solar system and in order to pull in the right data to home assistant I need to be able to create Current/Total energy exported to the grid (All negative values of the Total Power) and All the Energy imported from the Grid (Positive numbers on total power) I removed the filter so my total power or phase power shows negative and positive depending on if my house is producing more than it uses or not. I've found ways to do this in HA but I'd prefer that it was done locally on the device before being pushed to HA.

@maegibbons
Copy link

Hi. Thank you so much for the brilliant work on this. I managed to flash my Emporia Vue and it seems to be working perfectly. I ran it with the Emporia software and the cloud prior to make sure it all worked fine before I went ahead an flashed it. My issue (Due to lack of templating knowledge) now is that I have a solar system and in order to pull in the right data to home assistant I need to be able to create Current/Total energy exported to the grid (All negative values of the Total Power) and All the Energy imported from the Grid (Positive numbers on total power) I removed the filter so my total power or phase power shows negative and positive depending on if my house is producing more than it uses or not. I've found ways to do this in HA but I'd prefer that it was done locally on the device before being pushed to HA.

Can you share what you have done so far so we can see where you are at?

@tappyson
Copy link

tappyson commented Jun 29, 2022

i2c:
  sda: 21
  scl: 22
  scan: false
  frequency: 200kHz  # recommended range is 50-200kHz
  id: i2c_a
time:
  - platform: sntp
    id: my_time

# these are called references in YAML. They allow you to reuse
# this configuration in each sensor, while only defining it once
.defaultfilters:
  - &moving_avg
    # we capture a new sample every 0.24 seconds, so the time can
    # be calculated from the number of samples as n * 0.24.
    sliding_window_moving_average:
      # we average over the past 2.88 seconds
      window_size: 12
      # we push a new value every 1.44 seconds
      send_every: 6
  - &invert
    # invert and filter out any values below 0.
    lambda: 'return max(-x, 0.0f);'
  - &pos
    # filter out any values below 0.
    lambda: 'return max(x, 0.0f);'
  - &abs
    # take the absolute value of the value
    lambda: 'return abs(x);'

sensor:
  - platform: emporia_vue
    i2c_id: i2c_a
    phases:
      - id: phase_a  # Verify that this specific phase/leg is connected to correct input wire color on device listed below
        input: BLACK  # Vue device wire color
        calibration: 0.022  # 0.022 is used as the default as starting point but may need adjusted to ensure accuracy
        # To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
        voltage:
          name: "Phase A Voltage"
          filters: [*moving_avg, *pos]

    ct_clamps:
      - phase_id: phase_a
        input: "C"  # Verify the CT going to this device input also matches the phase/leg
        power:
          name: "Phase A Power"
          id: phase_a_power
          device_class: power
          filters: [*moving_avg]

      # Pay close attention to set the phase_id for each breaker by matching it to the phase/leg it connects to in the panel
      - { phase_id: phase_a, input:  "1", power: { name:  "Lights N9 Power", id:  cir1, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "2", power: { name:  "Lights N8 Power", id:  cir2, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "3", power: { name:  "Plugs N7 Power", id:  cir3, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "4", power: { name:  "Plugs N6 Power", id:  cir4, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "5", power: { name:  "Plugs N5 Power", id:  cir5, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "6", power: { name:  "Solar Power", id:  cir6, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "7", power: { name:  "Aircon N3 Power", id:  cir7, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "8", power: { name:  "Stove N2 Power", id:  cir8, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "9", power: { name:  "Hot Water N1", id:  cir9, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "10", power: { name: "Plugs N4 Power", id: cir10, filters: [ *moving_avg, *pos ] } }


  - platform: template
    name: "Total Power"
    lambda: return id(phase_a_power).state ;
    update_interval: 1s
    id: total_power
    unit_of_measurement: "W"
  - platform: total_daily_energy
    name: "Total Daily Energy"
    power_id: total_power
    accuracy_decimals: 0
  - { power_id:  cir1, platform: total_daily_energy, accuracy_decimals: 0, name:  "Lights N9 Daily Energy", id: total_daily_cir1 }
  - { power_id:  cir2, platform: total_daily_energy, accuracy_decimals: 0, name:  "Lights N8 Daily Energy", id: total_daily_cir2 }
  - { power_id:  cir3, platform: total_daily_energy, accuracy_decimals: 0, name:  "Plugs N7 Daily Energy", id: total_daily_cir3 }
  - { power_id:  cir4, platform: total_daily_energy, accuracy_decimals: 0, name:  "Plugs N6 Daily Energy", id: total_daily_cir4 }
  - { power_id:  cir5, platform: total_daily_energy, accuracy_decimals: 0, name:  "Plugs N5 Daily Energy", id: total_daily_cir5 }
  - { power_id:  cir6, platform: total_daily_energy, accuracy_decimals: 0, name:  "Solar Power Daily Energy", id: total_daily_cir6 }
  - { power_id:  cir7, platform: total_daily_energy, accuracy_decimals: 0, name:  "Aircon N3 Daily Energy", id: total_daily_cir7 }
  - { power_id:  cir8, platform: total_daily_energy, accuracy_decimals: 0, name:  "Stove N2 Daily Energy", id: total_daily_cir8 }
  - { power_id:  cir9, platform: total_daily_energy, accuracy_decimals: 0, name:  "Hot Water N1 Daily Energy", id: total_daily_cir9 }
  - { power_id: cir10, platform: total_daily_energy, accuracy_decimals: 0, name: "Plugs N4 Daily Energy", id: total_daily_cir10 }
  
  
  - platform: template
    name: "Total Usage Power"
    lambda: return id(total_daily_cir1).state + id(total_daily_cir2).state + id(total_daily_cir3).state + id(total_daily_cir4).state + id(total_daily_cir5).state
      + id(total_daily_cir7).state + id(total_daily_cir8).state + id(total_daily_cir9).state + id(total_daily_cir10).state ; 
    update_interval: 1s
    id: total_power_usage
    unit_of_measurement: "W"
    internal: true 

 #Total House Watts Positive
  - platform: template
    name: Total Import
    id: totalconsumed
    lambda: |-
      if (id(total_power).state < 0) {
        return 0;
      } else {
        return id(total_power).state ;
      }
    accuracy_decimals: 1
    unit_of_measurement: "W"
    icon: "mdi:flash-circle"
    update_interval: 1s
    filters: [*moving_avg]
    
#Total House Watts Negative
  - platform: template
    name: Total Export
    id: totalexported
    lambda: |-
      if (id(total_power).state > 0) {
        return 0;
      } else {
        return abs(id(total_power).state) ;
      }
    accuracy_decimals: 1
    unit_of_measurement: "W"
    icon: "mdi:flash-circle"
    update_interval: 1s
    filters: [*moving_avg]

Kinda works but doesn't work in the HA dashboard and the data doesn't look like it's a running total but more like some sort of average?

@tappyson
Copy link

Basically I want two Total Daily's. One that is for all the Grid Import (When the total is positive) and one for Grid Export (When the total is positive) Also please excuse the horrendous editing on the code above. No idea why Github kept editing it that way. I used the insert code tool.

@flaviut
Copy link
Author

flaviut commented Jun 29, 2022

@tappyson you're on the right track. You have the instantaneous power imported and exported. But you need to add that up over time.

Try adding two more sensors like the existing total daily energy:

  - platform: total_daily_energy
    name: "Total Daily Energy"
    power_id: total_power
    accuracy_decimals: 0

Details on how it works: https://esphome.io/components/sensor/total_daily_energy.html

You'll want to replace the thing it's summing over with your totalexported, etc.

PS: I fixed the formatting, here's an explanation of how it works

@Ofloo
Copy link

Ofloo commented Jun 30, 2022

I didn't fix the problem, however I've established how to circumvent it. Seems like the culprit is ESPHome, not sure as to why this specific firmware is having issues with it. Since none of my other clients do but it does.

I've changed my config to mqtt and set all internal to true and now I have no packets going to ESPHome and so no more disconnects and no more packet loss.

Downside I have to configure all my sensors in mqtt: - sensors ..

substitutions:
  devicename: "energy-monitor"
  upper_devicename: "emporiavue2"

  wifi_ssid: !secret iot_wifi_ssid
  wifi_pass: !secret iot_wifi_password
  fallback_pass: !secret fallback_wifi_password
  api_pass: !secret esp_api_password
  ota_pass: !secret esp_ota_password

  # phase a connected to main leat L1 load closet
  name_a_power: "Grid Power"
  name_a_voltage: "Grid Voltage"
  name_total_a_power: "Total Power Grid"
  name_total_a_energy: "Total Daily Energy Grid"
  # phase b connected to main lead N direction load N
  name_b_power: "Neutral Power"
  name_b_voltage: "Neutral Voltage"
  name_total_b_power: "Total Power Neutral"
  name_total_b_energy: "Total Daily Energy Neutral"
  # phase c connected main lead to earth direction load earth
  name_c_power: "PE Power"
  name_c_voltage: "PE Voltage"
  name_total_c_power: "Total Power PE"
  name_total_c_energy: "Total Daily Energy PE"
  # individual circuits
  # individual circuits
  name_circuit01: "Circuit 1"
  name_circuit02: "Circuit 2"
  name_circuit03: "Circuit 3"
  name_circuit04: "Circuit 4"
  name_circuit05: "Circuit 5"
  name_circuit06: "Circuit 6"
  name_circuit07: "Circuit 7"
  name_circuit08: "Circuit 8"
  name_circuit09: "Circuit 9"
  name_circuit10: "Circuit 10"
  name_circuit11: "Circuit 11"
  name_circuit12: "Circuit 12"
  name_circuit13: "Circuit 13"
  name_circuit14: "Circuit 14"
  name_circuit15: "Circuit 15"
  name_circuit16: "Circuit 16"
  name_timezone: 'CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00'


esphome:
  name: $devicename

external_components:
  - source: github://flaviut/esphome@emporia-vue-2022.4.0
    components: [ emporia_vue ]

esp32:
  board: esp32dev
  framework:
    type: esp-idf
    version: recommended

# Enable Home Assistant API
api:
  password: "${api_pass}"

# Enable over the air updates
ota:
  password: "${ota_pass}"

# Enable logging
logger:
  level: error

wifi:
  ssid: "${wifi_ssid}"
  password: "${wifi_pass}"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "${devicename} Fallback Hotspot"
    password: "${fallback_pass}"

i2c:
  sda: 21
  scl: 22
  scan: false
  frequency: 200kHz  # recommended range is 50-200kHz
  id: i2c_a

# these are called references in YAML. They allow you to reuse
# this configuration in each sensor, while only defining it once
.defaultfilters:
  - &moving_avg
    # we capture a new sample every 0.24 seconds, so the time can
    # be calculated from the number of samples as n * 0.24.
    sliding_window_moving_average:
      # we average over the past 2.88 seconds
      window_size: 12
      # we push a new value every 1.44 seconds
      send_every: 6
  - &invert
    # invert and filter out any values below 0.
    lambda: 'return max(-x, 0.0f);'
  - &pos
    # filter out any values below 0.
    lambda: 'return max(x, 0.0f);'
  - &abs
    # take the absolute value of the value
    lambda: 'return abs(x);'

mqtt:
  broker: !secret mqtt_hostname
  username: !secret mqtt_username
  password: !secret mqtt_password
  client_id: vue2
  port: 1883
  topic_prefix: vue2
  discovery: false
  log_topic: null

sensor:
  - platform: emporia_vue
    i2c_id: i2c_a
    phases:
      - id: phase_a  # Verify that this specific phase/leg is connected to correct input wire color on device listed below
        input: BLACK  # Vue device wire color
        calibration: 0.02260  # 0.022 is used as the default as starting point but may need adjusted to ensure accuracy
        # To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
        voltage:
          name: $name_a_voltage
          internal: true
          id: phase_a_voltage
          filters: [*moving_avg, *pos]
      - id: phase_b  # Verify that this specific phase/leg is connected to correct input wire color on device listed below
        input: RED  # Vue device wire color
        calibration: 0.02260  # 0.022 is used as the default as starting point but may need adjusted to ensure accuracy
        # To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
        voltage:
          name: $name_b_voltage
          internal: true
          id: phase_b_voltage
          filters: [*moving_avg, *pos]
      - id: phase_c  # Verify that this specific phase/leg is connected to correct input wire color on device listed below
        input: BLUE  # Vue device wire color
        calibration: 0.02260  # 0.022 is used as the default as starting point but may need adjusted to ensure accuracy
        # To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
        voltage:
          name: $name_c_voltage
          internal: true
          id: phase_c_voltage
          filters: [*moving_avg, *pos]
    ct_clamps:
      - phase_id: phase_a
        input: "A"  # Verify the CT going to this device input also matches the phase/leg
        power:
          name: $name_a_power
          internal: true
          id: phase_a_power
          device_class: power
          filters: [*moving_avg, *pos]
      - phase_id: phase_b
        input: "B"  # Verify the CT going to this device input also matches the phase/leg
        power:
          name: $name_b_power
          internal: true
          id: phase_b_power
          device_class: power
          filters: [*moving_avg, *pos]
      - phase_id: phase_c
        input: "C"  # Verify the CT going to this device input also matches the phase/leg
        power:
          name: $name_c_power
          internal: true
          id: phase_c_power
          device_class: power
          filters: [*moving_avg, *pos]
      # Pay close attention to set the phase_id for each breaker by matching it to the phase/leg it connects to in the panel
      - { phase_id: phase_a, input:  "1", power: { name: $name_circuit01, internal: true, id: power_cir01, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "2", power: { name: $name_circuit02, internal: true, id: power_cir02, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "3", power: { name: $name_circuit03, internal: true, id: power_cir03, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "4", power: { name: $name_circuit04, internal: true, id: power_cir04, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "5", power: { name: $name_circuit05, internal: true, id: power_cir05, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "6", power: { name: $name_circuit06, internal: true, id: power_cir06, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "7", power: { name: $name_circuit07, internal: true, id: power_cir07, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "8", power: { name: $name_circuit08, internal: true, id: power_cir08, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input:  "9", power: { name: $name_circuit09, internal: true, id: power_cir09, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "10", power: { name: $name_circuit10, internal: true, id: power_cir10, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "11", power: { name: $name_circuit11, internal: true, id: power_cir11, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "12", power: { name: $name_circuit12, internal: true, id: power_cir12, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "13", power: { name: $name_circuit13, internal: true, id: power_cir13, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "14", power: { name: $name_circuit14, internal: true, id: power_cir14, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "15", power: { name: $name_circuit15, internal: true, id: power_cir15, device_class: power, filters: [ *moving_avg, *pos ] } }
      - { phase_id: phase_a, input: "16", power: { name: $name_circuit16, internal: true, id: power_cir16, device_class: power, filters: [ *moving_avg, *pos ] } }

  - platform: template
    name: "${name_circuit01} in W"
    lambda: return id(power_cir01).state;
    id: total_cir01
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit02} in W"
    lambda: return id(power_cir02).state;
    id: total_cir02
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit03} in W"
    lambda: return id(power_cir03).state;
    id: total_cir03
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit04} in W"
    lambda: return id(power_cir04).state;
    id: total_cir04
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit05} in W"
    lambda: return id(power_cir05).state;
    id: total_cir05
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit06} in W"
    lambda: return id(power_cir06).state;
    id: total_cir06
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit07} in W"
    lambda: return id(power_cir07).state;
    id: total_cir07
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit08} in W"
    lambda: return id(power_cir08).state;
    id: total_cir08
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit09} in W"
    lambda: return id(power_cir09).state;
    id: total_cir09
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit10} in W"
    lambda: return id(power_cir10).state;
    id: total_cir10
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit11} in W"
    lambda: return id(power_cir11).state;
    id: total_cir11
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit12} in W"
    lambda: return id(power_cir12).state;
    id: total_cir12
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit13} in W"
    lambda: return id(power_cir13).state;
    id: total_cir13
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit14} in W"
    lambda: return id(power_cir14).state;
    id: total_cir14
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit15} in W"
    lambda: return id(power_cir15).state;
    id: total_cir15
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge
  - platform: template
    name: "${name_circuit16} in W"
    lambda: return id(power_cir16).state;
    id: total_cir16
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    update_interval: 1s
    icon: mdi:gauge

    # phase A
  - platform: template
    name: $name_total_a_power
    lambda: return id(phase_a_power).state;
    update_interval: 1s
    id: total_power_a
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    icon: mdi:gauge
  - platform: total_daily_energy
    name: $name_total_a_energy
    power_id: total_power_a
    id: total_power_a_wh
    accuracy_decimals: 0
    unit_of_measurement: "Wh"
    internal: true
    icon: mdi:gauge
  - platform: total_daily_energy
    name: $name_total_a_energy
    power_id: total_power_a
    id: total_power_a_kwh
    accuracy_decimals: 3
    filters: [multiply: 0.001]
    unit_of_measurement: "kWh"
    internal: true
    icon: mdi:gauge
    # phase B
  - platform: template
    name: $name_total_b_power
    lambda: return id(phase_b_power).state;
    update_interval: 1s
    id: total_power_b
    accuracy_decimals: 0
    unit_of_measurement: "W"
    internal: true
    icon: mdi:gauge
  - platform: total_daily_energy
    name: $name_total_b_energy
    power_id: total_power_b
    id: total_power_b_wh
    accuracy_decimals: 0
    internal: true
    icon: mdi:gauge
  - platform: total_daily_energy
    name: $name_total_b_energy
    power_id: total_power_b
    id: total_power_b_kwh
    accuracy_decimals: 3
    filters: [multiply: 0.001]
    unit_of_measurement: "kWh"
    internal: true
    icon: mdi:gauge
    # phase C
  - platform: template
    name: $name_total_c_power
    lambda: return id(phase_c_power).state;
    update_interval: 1s
    id: total_power_c
    unit_of_measurement: "W"
    internal: true
    icon: mdi:gauge
  - platform: total_daily_energy
    name: $name_total_c_energy
    power_id: total_power_c
    id: total_power_c_wh
    accuracy_decimals: 0
    unit_of_measurement: "Wh"
    internal: true
    icon: mdi:gauge
  - platform: total_daily_energy
    name: $name_total_c_energy
    power_id: total_power_c
    id: total_power_c_kwh
    accuracy_decimals: 3
    filters: [multiply: 0.001]
    unit_of_measurement: "kWh"
    internal: true
    icon: mdi:gauge


  - { power_id: total_cir01, id: total_cir01_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit01} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir02, id: total_cir02_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit02} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir03, id: total_cir03_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit03} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir04, id: total_cir04_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit04} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir05, id: total_cir05_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit05} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir06, id: total_cir06_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit06} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir07, id: total_cir07_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit07} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir08, id: total_cir08_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit08} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir09, id: total_cir09_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit09} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir10, id: total_cir10_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit10} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir11, id: total_cir11_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit11} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir12, id: total_cir12_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit12} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir13, id: total_cir13_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit13} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir14, id: total_cir14_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit14} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir15, id: total_cir15_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit15} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }
  - { power_id: total_cir16, id: total_cir16_wh, platform: total_daily_energy, accuracy_decimals: 1, name: "${name_circuit16} in Wh", unit_of_measurement: "Wh", internal: true, icon: mdi:calendar-clock }

  - { power_id: total_cir01, id: total_cir01_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit01} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir02, id: total_cir02_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit02} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir03, id: total_cir03_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit03} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir04, id: total_cir04_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit04} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir05, id: total_cir05_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit05} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir06, id: total_cir06_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit06} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir07, id: total_cir07_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit07} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir08, id: total_cir08_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit08} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir09, id: total_cir09_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit09} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir10, id: total_cir10_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit10} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir11, id: total_cir11_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit11} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir12, id: total_cir12_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit12} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir13, id: total_cir13_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit13} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir14, id: total_cir14_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit14} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir15, id: total_cir15_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit15} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }
  - { power_id: total_cir16, id: total_cir16_kwh, platform: total_daily_energy, accuracy_decimals: 3, name: "${name_circuit16} in kWh", unit_of_measurement: "kWh", internal: true, filters: [multiply: 0.001], icon: mdi:calendar-clock }



time:
  - platform: sntp
    id: my_time
    timezone: $name_timezone
    servers:
      - 10.13.35.1
    on_time_sync:
      then:
        - logger.log: "Synchronized system clock"

    on_time:
      - seconds: /3
        then:
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/1/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir01).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/2/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir02).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/3/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir03).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/4/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir04).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/5/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir05).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/6/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir06).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/7/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir07).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/8/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir08).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/9/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir09).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/10/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir10).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/11/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir11).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/12/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir12).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/13/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir13).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/14/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir14).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/15/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir15).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/16/watt/state");
              payload: !lambda |-
                return to_string(id(total_cir16).state);
      - seconds: /3
        then:
          - mqtt.publish:
              topic: "vue2/mains/A/watt/state"
              payload: !lambda |-
                return to_string(id(phase_a_power).state);
          - mqtt.publish:
              topic: "vue2/mains/B/watt/state"
              payload: !lambda |-
                return to_string(id(phase_b_power).state);
          - mqtt.publish:
              topic: "vue2/mains/C/watt/state"
              payload: !lambda |-
                return to_string(id(phase_c_power).state);
          - mqtt.publish:
              topic: "vue2/mains/A/voltage/state"
              payload: !lambda |-
                return to_string(id(phase_a_voltage).state);
          - mqtt.publish:
              topic: "vue2/mains/B/voltage/state"
              payload: !lambda |-
                return to_string(id(phase_b_voltage).state);
          - mqtt.publish:
              topic: "vue2/mains/C/voltage/state"
              payload: !lambda |-
                return to_string(id(phase_c_voltage).state);
      - seconds: /5
        then:
          - mqtt.publish:
              topic: "vue2/mains/A/wh/state"
              payload: !lambda |-
                return to_string(id(total_power_a_wh).state);
          - mqtt.publish:
              topic: "vue2/mains/B/wh/state"
              payload: !lambda |-
                return to_string(id(total_power_b_wh).state);
          - mqtt.publish:
              topic: "vue2/mains/C/wh/state"
              payload: !lambda |-
                return to_string(id(total_power_c_wh).state);

          - mqtt.publish:
              topic: "vue2/mains/A/kwh/state"
              payload: !lambda |-
                return to_string(id(total_power_a_kwh).state);
          - mqtt.publish:
              topic: "vue2/mains/B/kwh/state"
              payload: !lambda |-
                return to_string(id(total_power_b_kwh).state);
          - mqtt.publish:
              topic: "vue2/mains/C/kwh/state"
              payload: !lambda |-
                return to_string(id(total_power_c_kwh).state);
      - seconds: /10
        then:
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/1/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir01_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/2/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir02_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/3/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir03_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/4/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir04_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/5/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir05_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/6/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir06_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/7/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir07_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/8/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir08_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/9/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir09_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/10/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir10_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/11/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir11_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/12/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir12_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/13/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir13_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/14/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir14_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/15/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir15_wh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/16/wh/state");
              payload: !lambda |-
                return to_string(id(total_cir16_wh).state);
      - seconds: /20
        then:
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/1/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir01_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/2/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir02_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/3/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir03_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/4/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir04_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/5/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir05_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/6/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir06_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/7/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir07_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/8/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir08_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/9/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir09_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/10/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir10_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/11/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir11_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/12/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir12_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/13/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir13_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/14/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir14_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/15/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir15_kwh).state);
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/16/kwh/state");
              payload: !lambda |-
                return to_string(id(total_cir16_kwh).state);
      - seconds: 0
        minutes: /5
        then:
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/mains/A/name/state");
              payload: !lambda |-
                return id(phase_a_power).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/mains/B/name/state");
              payload: !lambda |-
                return id(phase_b_power).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/mains/C/name/state");
              payload: !lambda |-
                return id(phase_c_power).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/1/name/state");
              payload: !lambda |-
                return id(power_cir01).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/2/name/state");
              payload: !lambda |-
                return id(power_cir02).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/3/name/state");
              payload: !lambda |-
                return id(power_cir03).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/4/name/state");
              payload: !lambda |-
                return id(power_cir04).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/5/name/state");
              payload: !lambda |-
                return id(power_cir05).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/6/name/state");
              payload: !lambda |-
                return id(power_cir06).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/7/name/state");
              payload: !lambda |-
                return id(power_cir07).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/8/name/state");
              payload: !lambda |-
                return id(power_cir08).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/9/name/state");
              payload: !lambda |-
                return id(power_cir09).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/10/name/state");
              payload: !lambda |-
                return id(power_cir10).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/11/name/state");
              payload: !lambda |-
                return id(power_cir11).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/12/name/state");
              payload: !lambda |-
                return id(power_cir12).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/13/name/state");
              payload: !lambda |-
                return id(power_cir13).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/14/name/state");
              payload: !lambda |-
                return id(power_cir14).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/15/name/state");
              payload: !lambda |-
                return id(power_cir15).get_name();
          - mqtt.publish:
              topic: !lambda |-
                return std::string("vue2/circuits/16/name/state");
              payload: !lambda |-
                return id(power_cir16).get_name();

@tappyson
Copy link

tappyson commented Jul 1, 2022

@tappyson you're on the right track. You have the instantaneous power imported and exported. But you need to add that up over time.

Try adding two more sensors like the existing total daily energy:

  - platform: total_daily_energy
    name: "Total Daily Energy"
    power_id: total_power
    accuracy_decimals: 0

Details on how it works: https://esphome.io/components/sensor/total_daily_energy.html

You'll want to replace the thing it's summing over with your totalexported, etc.

PS: I fixed the formatting, here's an explanation of how it works

Thanks so much. Got to working a treat.

@tappyson
Copy link

tappyson commented Jul 1, 2022

What would good practice be for creating a 1 or 5 min sensor. Create a new sensor with more datapoints using the rolling moving average?

Also does anyone know of a good way to send only say 5min data but then activate a 1s sensor for live viewing with some form of button click?

@flaviut
Copy link
Author

flaviut commented Jul 2, 2022

@tappyson

What would good practice be for creating a 1 or 5 min sensor. Create a new sensor with more datapoints using the rolling moving average?

Yup, exactly. Moving averages are way more complicated than you'd expect, but the sliding_window_moving_average is likely what you're looking for.

Also does anyone know of a good way to send only say 5min data but then activate a 1s sensor for live viewing with some form of button click?

Sorry, I can't help here.


@devWaves Thanks for the reminder! I've updated the guide.

@cosmicosmo4
Copy link

cosmicosmo4 commented Jul 4, 2022

I am having an issue, my total_daily_energy sensors are not resetting at all. I am running esphome and homeassistant in docker containers, with configs nearly identical to the example. I do see the accurate local time in my esphome logs.

In the device's config I have:

time:
  - platform: sntp
    id: my_time

In docker-compose.yaml I have:

    environment:
      ESPHOME_DASHBOARD_USE_PING: 'true'
      TZ: 'America/Chicago'
    volumes:
      - './esphomeconfig/:/config:rw'
      - /etc/localtime:/etc/localtime
      - /etc/timezone:/etc/timezone

(possibly redundant?)

And in the logs I see:

[10:14:17][C][sntp:050]: SNTP Time:
[10:14:17][C][sntp:051]:   Server 1: '0.pool.ntp.org'
[10:14:17][C][sntp:052]:   Server 2: '1.pool.ntp.org'
[10:14:17][C][sntp:053]:   Server 3: '2.pool.ntp.org'
[10:14:17][C][sntp:054]:   Timezone: 'CST6CDT,M3.2.0,M11.1.0'
[10:14:19][D][sensor:125]: 'Total Power': Sending state 236.83893 W with 1 decimals of accuracy
[10:14:19][D][sensor:125]: 'Total Daily Energy': Sending state 283491.21875 Wh with 0 decimals of accuracy

which is the correct local time.

The device is in a VLAN that's firewalled off from the internet, but I opened a rule to allow it to send packets to port 123:

image

But the data just keeps going up:

image

Thanks for any help!

@Ofloo
Copy link

Ofloo commented Jul 4, 2022

you need cycle: daily inside your energy total`

  - platform: total_daily_energy
    name: "Total Daily Energy"
    power_id: total_power
    accuracy_decimals: 0
    cycle: daily

@cosmicosmo4
Copy link

That gives me:
image

@flaviut
Copy link
Author

flaviut commented Jul 4, 2022

I don't see a cycle parameter documented: https://esphome.io/components/sensor/total_daily_energy.html

Anyway @cosmicosmo4, are you sure the time is getting synchronized? You should see a log message: esphome/issues#449 (comment)

@cosmicosmo4
Copy link

I haven't noticed the "Synchronizing..." message. How often is it supposed to synchronize? Also, I do have the correct time in the logs, so it must have synchronized at some point.

@Ofloo
Copy link

Ofloo commented Jul 4, 2022

oh that's inside the emporia config

I have

time:
  - platform: sntp
    id: my_time
    timezone: $name_timezone
    servers:
      - 10.13.35.1
    on_time_sync:
      then:
        - logger.log: "Synchronized system clock"

However keep in mind that I have setup ntp on my gateway don't like my iot clients going to the internet so ...

@stephenjamieson
Copy link

You could try syncing with homeassistant:

time:
  - platform: homeassistant
    id: homeassistant_time
    timezone: America/New_York

@Ofloo
Copy link

Ofloo commented Jul 4, 2022

for name_timezone I have name_timezone: 'CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00'

@flaviut
Copy link
Author

flaviut commented Jul 4, 2022

I'm out of ideas :)

I'd suggest asking the ESPHome community directly. Please let us know what you find out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment