Skip to content

Instantly share code, notes, and snippets.

@CJOWood
Forked from bradsjm/emporia-vue-v3.yaml
Last active November 16, 2024 05:14
Show Gist options
  • Save CJOWood/35b95803246207c2128915b280198336 to your computer and use it in GitHub Desktop.
Save CJOWood/35b95803246207c2128915b280198336 to your computer and use it in GitHub Desktop.
Emporia VUE V3 ESPHome Configuration
substitutions:
name: electrical-panel
friendly_name: Electrical Panel
display_name: "ElecPnl"
area: "Family Room"
# Circuit Labels used for publishing to Home Assistant
circuit_1: "Heat Pump"
circuit_2: "Stove"
circuit_3: "Heat Strip 1"
circuit_4: "Heat Strip 2"
circuit_5: "Sub Panel"
circuit_6: "Circuit 6"
circuit_7: "Circuit 7"
circuit_8: "Solar 1"
circuit_9: "Solar 2"
circuit_10: "Circuit 10"
circuit_11: "Circuit 11"
circuit_12: "Circuit 12"
circuit_13: "Circuit 13"
circuit_14: "Circuit 14"
circuit_15: "Circuit 15"
circuit_16: "Circuit 16"
# Icons for Home Assistant
icon_circuit: "mdi:power-plug"
icon_current: "mdi:current-ac"
icon_meter: "mdi:meter-electric"
icon_phase: "mdi:angle-acute"
icon_power: "mdi:transmission-tower-import"
icon_voltage: "mdi:transmission-tower"
esphome:
name: ${name}
area: ${area}
friendly_name: ${friendly_name}
name_add_mac_suffix: false
external_components:
# - source: github://emporia-vue-local/esphome@vue3
- source: github://digiblur/esphome-vue3@dev
components:
- emporia_vue
esp32:
board: esp32dev
framework:
type: esp-idf
version: recommended
preferences:
# the default of 1min is far too short--flash chip is rated
# for approx 100k writes.
flash_write_interval: "48h"
# Enable logging
logger:
logs:
sensor: INFO
# Enable Home Assistant API
api:
encryption:
key: ""
ota:
- platform: esphome
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
on_connect:
- light.turn_on: wifi_led
on_disconnect:
- light.turn_off: wifi_led
# Optional manual IP
manual_ip:
static_ip:
gateway:
subnet:
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Electrical-Panel"
password: ""
captive_portal:
### START SETUP HERE
i2c:
sda: 5
scl: 18
scan: false
id: i2c_a
# frequency: 200kHz # recommended range is 50-200kHz
frequency: 400kHz # recommended range is 50-200kHz
timeout: 1ms
time:
- platform: homeassistant # Home Assistant Time Platform
id: homeassistant_time # ID for Home Assistant Time Platform
# these are called references in YAML. They allow you to reuse
# this configuration in each sensor, while only defining it once
.defaultfilters:
- &throttle_avg # Average all raw readings together over a 5 second span before publishing
throttle_average: 5s
- &throttle_time # Only send the most recent measurement every 60 seconds
throttle: 60s
- &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: 24
# we push a new value every 1.44 seconds
send_every: 12
- &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);'
- &zero # Use for disconnected circuits to return 0
lambda: "return 0.0f;"
- &double # Use to double the measurement for 240V breakers
multiply: 2
sensor:
- platform: emporia_vue
i2c_id: i2c_a
# Configure the Emporia Vue wire harness phases.
phases:
# Verify that this specific phase/leg is connected to the matching input wire color on device listed below
- id: phase_b
# Vue device wire color (BLACK or RED for split phase)
input: BLACK
# To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
# 0.0194 is used as the default as starting point for Vue 3 but may need adjusted to ensure accuracy
calibration: 0.0194
voltage: { id: phase_b_voltage, name: "Phase B Voltage", icon: $icon_voltage, accuracy_decimals: 0, filters: [ *moving_avg, *pos ] }
frequency: { id: phase_b_freqency, name: "Phase B Frequency", accuracy_decimals: 0, filters: [ *moving_avg, *pos ] }
# Verify that this specific phase/leg is connected to the matching input wire color on device listed below
- id: phase_a
# Vue device wire color (BLACK or RED for split phase)
input: RED
# To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
# 0.0194 is used as the default as starting point for Vue 3 but may need adjusted to ensure accuracy
calibration: 0.0194
voltage: { id: phase_a_voltage, name: "Phase A Voltage", icon: $icon_voltage, accuracy_decimals: 0, filters: [ *moving_avg, *pos ] }
phase_angle: { id: phase_a_angle, name: "Phase A Phase Angle", icon: $icon_phase, accuracy_decimals: 0, filters: [ *moving_avg, *pos ] }
# Verify that this specific phase/leg is connected to the matching input wire color on device listed below
# - id: phase_c
# # Vue device wire color (BLUE for three phase)
# input: BLUE
# # To calculate new calibration value use the formula <in-use calibration value> * <accurate voltage> / <reporting voltage>
# # 0.0194 is used as the default as starting point for Vue 3 but may need adjusted to ensure accuracy
# calibration: 0.0194
# voltage: { id: phase_c_voltage, name: "Phase C Voltage", icon: $icon_voltage, accuracy_decimals: 0, filters: [ *moving_avg, *pos ] }
# phase_angle: { id: phase_c_angle, name: "Phase C Phase Angle", icon: $icon_phase, accuracy_decimals: 0, filters: [ *moving_avg, *pos ] }
# Configure the Emporia Vue CT clamps.
ct_clamps:
# Do not specify a name for any of the power sensors here, only an id. This leaves the power sensors internal to ESPHome.
# These non-throttled power sensors are used for accurately calculating energy.
# Copy sensors defined later will filter and then send power measurements to Home Assistant.
# Main Service CT Clamps (up to 3)
# Verify the correct input on the device is connected to the CT clamp phase defined (Vue 3 inputs are inverted)
- { input: "A", phase_id: phase_a, power: { id: phase_a_power_import, filters: *invert } }
- { input: "B", phase_id: phase_b, power: { id: phase_b_power_import, filters: *invert } }
- { input: "A", phase_id: phase_a, power: { id: phase_a_power_export, filters: *pos } } # This measures energy uploaded to grid on phase A
- { input: "B", phase_id: phase_b, power: { id: phase_b_power_export, filters: *pos } } # This measures energy uploaded to grid on phase B
# - { input: "C", phase_id: phase_c, power: { id: phase_c_power, filters: *invert } }
# Circuit CT Clamps (up to 16)
# Pay close attention to set the phase_id for each breaker by matching it to the phase/leg it connects to in the panel
# Use *invert filter for inverted positive values (Vue 3 inputs are inverted) or *zero for un-used inputs
# Use *double filter for double (240v) breakers (this will assume power is evenly divided between the two legs)
#EG: - { input: "1", phase_id: phase_a, power: { id: c1_pwr, filters: [ *invert, *double ] }, current: { id: c1_cur, filters: [ *double ] } }
#EG: - { input: "1", phase_id: phase_a, power: { id: c1_pwr, filters: [ *invert ] }, current: { id: c1_cur, filters: [ *double ] } }
- { input: "1", phase_id: phase_a, power: { id: c1_pwr, filters: [ *invert, *double ] }, current: { id: c1_cur, filters: [ *double ] } }
- { input: "2", phase_id: phase_a, power: { id: c2_pwr, filters: [ *invert ] }, current: { id: c2_cur } }
- { input: "3", phase_id: phase_a, power: { id: c3_pwr, filters: [ *invert ] }, current: { id: c3_cur } }
- { input: "4", phase_id: phase_a, power: { id: c4_pwr, filters: [ *invert ] }, current: { id: c4_cur } }
- { input: "5", phase_id: phase_b, power: { id: c5_pwr, filters: [ *invert ] }, current: { id: c5_cur } }
- { input: "6", phase_id: phase_b, power: { id: c6_pwr, filters: [ *invert ] }, current: { id: c6_cur } }
- { input: "7", phase_id: phase_b, power: { id: c7_pwr, filters: [ *invert, *double ] }, current: { id: c7_cur, filters: [ *double ] } }
- { input: "8", phase_id: phase_a, power: { id: c8_pwr, filters: [ *pos ] }, current: { id: c8_cur } } # Solar
- { input: "9", phase_id: phase_b, power: { id: c9_pwr, filters: [ *pos ] }, current: { id: c9_cur } } # Solar
# Unused CT clamp inputs are explicitly set to zero (*zero filter) to avoid phantom readings
- { input: "10", phase_id: phase_a, power: { id: c10_pwr, filters: [ *zero ] }, current: { id: c10_cur, filters: [ *zero ] } }
- { input: "11", phase_id: phase_a, power: { id: c11_pwr, filters: [ *zero ] }, current: { id: c11_cur, filters: [ *zero ] } }
- { input: "12", phase_id: phase_a, power: { id: c12_pwr, filters: [ *zero ] }, current: { id: c12_cur, filters: [ *zero ] } }
- { input: "13", phase_id: phase_a, power: { id: c13_pwr, filters: [ *zero ] }, current: { id: c13_cur, filters: [ *zero ] } }
- { input: "14", phase_id: phase_a, power: { id: c14_pwr, filters: [ *zero ] }, current: { id: c14_cur, filters: [ *zero ] } }
- { input: "15", phase_id: phase_a, power: { id: c15_pwr, filters: [ *zero ] }, current: { id: c15_cur, filters: [ *zero ] } }
- { input: "16", phase_id: phase_a, power: { id: c16_pwr, filters: [ *zero ] }, current: { id: c16_cur, filters: [ *zero ] } }
# Update power readings at the same time.
on_update:
then:
- component.update: total_power_export
- component.update: total_power_import
- component.update: balance_power
- component.update: total_solar_power
- component.update: total_power_consumption
# The total sensor will be updated after all power sensors update via on_update trigger.
- platform: template
id: total_solar_power
update_interval: never
device_class: power
state_class: measurement
unit_of_measurement: "W"
lambda: return id(c8_pwr).state + id(c9_pwr).state;
# The total power sensor will be updated after all power sensors update via on_update trigger.
- platform: template
id: total_power_import
update_interval: never
device_class: power
state_class: measurement
unit_of_measurement: "W"
lambda: return id(phase_a_power_import).state + id(phase_b_power_import).state;
# lambda: return id(phase_a_power).state + id(phase_b_power).state + id(phase_c_power).state;
# The sensor will be updated after all power sensors update via on_update trigger.
- platform: template
id: total_power_export
update_interval: never
device_class: power
state_class: measurement
unit_of_measurement: "W"
lambda: return id(phase_a_power_export).state + id(phase_b_power_export).state;
# The sensor will be updated after all power sensors update via on_update trigger
- platform: template
id: total_power_consumption
update_interval: never
device_class: power
state_class: measurement
unit_of_measurement: "W"
lambda: return id(total_power_import).state + id(total_solar_power).state - id(total_power_export).state;
# The balance power sensor will be updated after all power sensors update via on_update trigger.
- platform: template
id: balance_power
update_interval: never
device_class: power
state_class: measurement
unit_of_measurement: "W"
lambda: !lambda |-
return max(0.0f,
id(total_power_import).state
+ id(total_solar_power).state
- id( c1_pwr).state
- id( c2_pwr).state
- id( c3_pwr).state
- id( c4_pwr).state
- id( c5_pwr).state
- id( c6_pwr).state
- id( c7_pwr).state
- id(c10_pwr).state
- id(c11_pwr).state
- id(c12_pwr).state
- id(c13_pwr).state
- id(c14_pwr).state
- id(c15_pwr).state
- id(c16_pwr).state
- id(total_power_export).state
);
# The copy sensors publish the each power state to Home Assistant.
- { platform: copy, name: "Phase B Power Import", source_id: phase_b_power_import, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_power }
- { platform: copy, name: "Phase B Power Export", source_id: phase_b_power_export, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_power }
- { platform: copy, name: "Phase A Power Import", source_id: phase_a_power_import, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_power }
- { platform: copy, name: "Phase A Power Export", source_id: phase_a_power_export, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_power }
- { platform: copy, name: "Total Power Consumption", source_id: total_power_consumption, filters: *throttle_avg }
- { platform: copy, name: "Total Power Import", source_id: total_power_import, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_power }
- { platform: copy, name: "Total Power Export", source_id: total_power_export, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_power }
- { platform: copy, name: "Balance Power", source_id: balance_power, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_power }
- { platform: copy, name: "Total Solar Power", source_id: total_solar_power, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_power }
- { platform: copy, name: "${circuit_1} Power", source_id: c1_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_2} Power", source_id: c2_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_3} Power", source_id: c3_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_4} Power", source_id: c4_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_5} Power", source_id: c5_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_6} Power", source_id: c6_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_7} Power", source_id: c7_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_8} Power", source_id: c8_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_9} Power", source_id: c9_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
# - { platform: copy, name: "${circuit_10} Power", source_id: cir10_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
# - { platform: copy, name: "${circuit_11} Power", source_id: cir11_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
# - { platform: copy, name: "${circuit_12} Power", source_id: cir12_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
# - { platform: copy, name: "${circuit_13} Power", source_id: cir13_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
# - { platform: copy, name: "${circuit_14} Power", source_id: cir14_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
# - { platform: copy, name: "${circuit_15} Power", source_id: cir15_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
# - { platform: copy, name: "${circuit_16} Power", source_id: cir16_pwr, filters: *moving_avg, accuracy_decimals: 0, icon: $icon_circuit }
- { platform: copy, name: "${circuit_1} Current", source_id: c1_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
- { platform: copy, name: "${circuit_2} Current", source_id: c2_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
- { platform: copy, name: "${circuit_3} Current", source_id: c3_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
- { platform: copy, name: "${circuit_4} Current", source_id: c4_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
- { platform: copy, name: "${circuit_5} Current", source_id: c5_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
- { platform: copy, name: "${circuit_6} Current", source_id: c6_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
- { platform: copy, name: "${circuit_7} Current", source_id: c7_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
- { platform: copy, name: "${circuit_8} Current", source_id: c8_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
- { platform: copy, name: "${circuit_9} Current", source_id: c9_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
# - { platform: copy, name: "${circuit_10} Current", source_id: c10_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
# - { platform: copy, name: "${circuit_11} Current", source_id: c11_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
# - { platform: copy, name: "${circuit_12} Current", source_id: c12_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
# - { platform: copy, name: "${circuit_13} Current", source_id: c13_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
# - { platform: copy, name: "${circuit_14} Current", source_id: c14_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
# - { platform: copy, name: "${circuit_15} Current", source_id: c15_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
# - { platform: copy, name: "${circuit_16} Current", source_id: c16_cur, filters: *moving_avg, accuracy_decimals: 1, icon: $icon_current }
# The total daily energy sensors to be published to Home Assistant
- { platform: total_daily_energy, name: "Total Daily Energy Export", power_id: total_power_export, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "Total Daily Energy Import", power_id: total_power_import, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "Total Daily Energy Consumption", power_id: total_power_consumption, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "Balance Daily Energy", power_id: balance_power, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "Solar Daily Energy", power_id: total_solar_power, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_1} Daily Energy", power_id: c1_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_2} Daily Energy", power_id: c2_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_3} Daily Energy", power_id: c3_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_4} Daily Energy", power_id: c4_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_5} Daily Energy", power_id: c5_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_6} Daily Energy", power_id: c6_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_7} Daily Energy", power_id: c7_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_8} Daily Energy", power_id: c8_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- { platform: total_daily_energy, name: "${circuit_9} Daily Energy", power_id: c9_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
# - { platform: total_daily_energy, name: "${circuit_10} Daily Energy", power_id: c10_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
# - { platform: total_daily_energy, name: "${circuit_11} Daily Energy", power_id: c11_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
# - { platform: total_daily_energy, name: "${circuit_12} Daily Energy", power_id: c12_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
# - { platform: total_daily_energy, name: "${circuit_13} Daily Energy", power_id: c13_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
# - { platform: total_daily_energy, name: "${circuit_14} Daily Energy", power_id: c14_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
# - { platform: total_daily_energy, name: "${circuit_15} Daily Energy", power_id: c15_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
# - { platform: total_daily_energy, name: "${circuit_16} Daily Energy", power_id: c16_pwr, filters: *throttle_time, accuracy_decimals: 0, restore: false, icon: $icon_meter }
- platform: wifi_signal
name: "RSSI"
update_interval: 60s
disabled_by_default: true
text_sensor:
- platform: wifi_info
ip_address:
name: "IP Address"
ssid:
name: "Connected SSID"
disabled_by_default: true
mac_address:
name: "MAC Address"
disabled_by_default: true
light:
- platform: status_led
id: wifi_led
pin:
number: 2
ignore_strapping_warning: true
restore_mode: ALWAYS_OFF
- platform: status_led
id: ethernet_led
pin: 4
restore_mode: ALWAYS_OFF
button:
- platform: restart
name: Restart
id: restart_button
icon: mdi:restart
- platform: safe_mode
name: Restart (Safe Mode)
id: safe_mode_button
icon: mdi:restart-alert
switch:
- platform: restart
name: Restart
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment