Skip to content

Instantly share code, notes, and snippets.

@5310H
Forked from flaviut/Setting up Emporia Vue 2 with ESPHome.md
Created January 8, 2022 18:14
Show Gist options
  • Save 5310H/a32ae056233236526af1afe79b90a352 to your computer and use it in GitHub Desktop.
Save 5310H/a32ae056233236526af1afe79b90a352 to your computer and use it in GitHub Desktop.
Setting up Emporia Vue 2 with ESPHome

Setting up Emporia Vue 2 with ESPHome

example of hass setup

What you need

  • USB to serial converter module
    • I tested this with a cheap & generic CH340G adapter
  • 4 male-to-female jumper wires
    • I have a soldering iron & needed something more secure for development, so I added a header & used that in the pictures, but you can get by without that.
  • esptool.py (windows instructions, generic instructions)
  • ESPHome image

Panel installation, part 1

You'll want to install the clamps & wiring harness into your panel following the instructions at https://www.emporiaenergy.com/installation-guides. At this time, place a label on each wire using masking tape & a pen rather than connecting them to the energy monitor.

Next, we need to figure out which circuits are on which phases, and in the case of multi-pole breakers, the multiplier. There should be a label like the following on your panel: panel phase diagram For each clamp, you want to make a note of the following information:

  • clamp number
  • circuit number
  • phase
  • multiplier, if it is a multi-pole breaker

For the wiring harness, you'll want to make a note of which color cable matches which service main clamp (A, B, C).

Writing configuration

Here's a starting point for a configuration:

esphome:
  name: emporiavue2

external_components:
  - source: github://krconv/esphome@remove-freertos-task
    components: [ emporia_vue ]

esp32:
  board: d-duino-32
  framework:
    type: esp-idf
    version: recommended

# Enable Home Assistant API
api: {"password": "<ota password>"}
ota: {"password": "<ota password>"}

# Enable logging
logger:
  logs:
    # Don't log on each sensor reading, that's way too loud. We can see them in
    # Home Assistant anyway, or re-enable them per-device if needed.
    sensor: INFO

wifi:
  ssid: "<wifi ssid>"
  password: "<wifi password>"

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

sensor:
  - platform: emporia_vue
    i2c_id: i2c_a
    phases:
      - id: phase_a
        input: BLACK
        voltage:
          name: "Phase A Voltage"
          filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }
      - id: phase_b
        input: RED
        voltage:
          name: "Phase B Voltage"
          filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }
    ct_clamps:
      - phase_id: phase_a
        input: "A"
        power:
          name: "Phase A Power"
          id: phase_a_power
          device_class: power
          filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }
      - phase_id: phase_b
        input: "B"
        power:
          name: "Phase B Power"
          id: phase_b_power
          device_class: power
          filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }
      - { phase_id: phase_a, input:  "1", power: { name:  "Circuit 1 Power", id:  cir1, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } } } }
      - { phase_id: phase_b, input:  "2", power: { name:  "Circuit 2 Power", id:  cir2, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } } } }
      - { phase_id: phase_a, input:  "3", power: { name:  "Circuit 3 Power", id:  cir3, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } } } }
      - { phase_id: phase_a, input:  "4", power: { name:  "Circuit 4 Power", id:  cir4, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } } } }
      - { phase_id: phase_a, input:  "5", power: { name:  "Circuit 5 Power", id:  cir5, filters: [ multiply: 2, sliding_window_moving_average: { window_size: 6, send_every: 6 } ] } }
      - { phase_id: phase_a, input:  "6", power: { name:  "Circuit 6 Power", id:  cir6, filters: [ multiply: 2, sliding_window_moving_average: { window_size: 6, send_every: 6 } ] } }
      - { phase_id: phase_a, input:  "7", power: { name:  "Circuit 7 Power", id:  cir7, filters: [ multiply: 2, sliding_window_moving_average: { window_size: 6, send_every: 6 } ] } }
      - { phase_id: phase_b, input:  "8", power: { name:  "Circuit 8 Power", id:  cir8, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }} }
      - { phase_id: phase_b, input:  "9", power: { name:  "Circuit 9 Power", id:  cir9, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }} }
      - { phase_id: phase_b, input: "10", power: { name: "Circuit 10 Power", id: cir10, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }} }
      - { phase_id: phase_a, input: "11", power: { name: "Circuit 11 Power", id: cir11, filters: [ multiply: 2, sliding_window_moving_average: { window_size: 6, send_every: 6 } ] } }
      - { phase_id: phase_a, input: "12", power: { name: "Circuit 12 Power", id: cir12, filters: [ multiply: 2, sliding_window_moving_average: { window_size: 6, send_every: 6 } ] } }
      - { phase_id: phase_a, input: "13", power: { name: "Circuit 13 Power", id: cir13, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }} }
      - { phase_id: phase_a, input: "14", power: { name: "Circuit 14 Power", id: cir14, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }} }
      - { phase_id: phase_b, input: "15", power: { name: "Circuit 15 Power", id: cir15, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }} }
      - { phase_id: phase_a, input: "16", power: { name: "Circuit 16 Power", id: cir16, filters: { sliding_window_moving_average: { window_size: 6, send_every: 6 } }} }
  - platform: template
    name: "Total Power"
    lambda: return id(phase_a_power).state + id(phase_b_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:  "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" }

You'll want to replace <ota password>, <wifi ssid>, and <wifi password> with a unique password, and your wifi credentials, respectively.

You'll also want to update the sensor section of the configuration using the information you've collected in Panel installation, part 1.

Note the sliding_window_moving_average. This is optional, but since we get a reading every 240ms, it is helpful to average these readings together so that we don't need to store such dense, noisy, data in Home Assistant.

Note the "Total Power", "Total Daily Energy", and "Circuit x Daily Energy". This is needed for the Home Assistant energy system, which requires daily kWh numbers.

Do not use the web_server since it is not compatible with the esp-idf framework, and you will get odd error messages.

It's not too critical to get this right on the first try, because you can update the board over WiFi using the ESPHome Dashboard.

Backing up & flashing the Vue 2

Pry the lever on one of the jumper cables up using a pencil or a needle or some other sharp thing. If your cables don't have a lever, cut one end of the cable & strip it using scissors or a knife. prying the lever on the jumper cableseparated cable closeup of the debug header pinout Plug the USB adapter in, connecting the jumpers for RX, TX, and GND between the two. Do not connect the power at this time.

Plug in the unmodified end of the cable we modified above into the IO0 pin of the Emporia Vue 2.

Open a console window and test that esptool.py version works.

photo of connected jumpers Remove any jumper from the USB dongle. Connect a jumper to the 5V pin of the dongle. While holding the jumpers in the Vue against the holes, and while holding the modified end of the cable against the shield of the ESP32, insert the other end of the 5V jumper into the Vue in the VCC_5V0 pin.

Some boards have been reported to have "goop" on these pins. You try cleaning the goop off with isopropyl alcohol & a swab or rag, or you can move the pins up and down against the side of the holes to try and rub off the goop so you get good electrical contact.

If you have a soldering iron and a strip of 2.54mm headers, you can solder those on & save yourself the hassle of holding everything in place.

Doing a backup

With your other hand, run the following in the console: esptool.py -b 921600 read_flash 0 0x800000 flash_contents.bin. Successful completion of this step is critical in case something goes wrong later. This file is necessary to restore the device to factory function.

If the above command fails, try again using esptool.py -b 115200 read_flash 0 0x800000 flash_contents.bin.

Flashing new software

With your other hand, run the following in the console: esphome run vue2.yaml. This will take a few minutes, and install the new software on the Vue 2!

You'll see a bunch of errors like Failed to read from sensor due to I2C error 3, but that's fine, since they'll go away when it is installed into into the wall.

Panel installation, part 2

Reassemble to Vue 2, and follow the instructions to plug everything in & started up!


(c) 2021 Flaviu Tamas Licensed under CC-BY-4.0

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