Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save charithmadhuranga/1f2ef0e7b869fd9a853b311491c08ffe to your computer and use it in GitHub Desktop.

Select an option

Save charithmadhuranga/1f2ef0e7b869fd9a853b311491c08ffe 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

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://flaviut/esphome@emporia-vue
    components: [ emporia_vue ]

esp32:
  board: esp32dev
  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

# these are called references in YAML. They allow you to reuse
# this configuration in each sensor, while only defining it once
.defaultfilters:
  - &df1
    # adjust these to fit your needs
    # 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
  - &df2
    # filter out any values below 0. You may want to disable
    # this filter while configuring your system to make sure you
    # don't get any consistently negative values.
    # lambda: 'return x;'  // no-op
    lambda: 'return max(x, 0.0f);'

sensor:
  - platform: emporia_vue
    i2c_id: i2c_a
    phases:
      - id: phase_a
        input: BLACK
        voltage:
          name: "Phase A Voltage"
          filters: [*df1, *df2]
      - id: phase_b
        input: RED
        voltage:
          name: "Phase B Voltage"
          filters: [*df1, *df2]
    ct_clamps:
      - phase_id: phase_a
        input: "A"
        power:
          name: "Phase A Power"
          id: phase_a_power
          device_class: power
          filters: [*df1, *df2]
      - phase_id: phase_b
        input: "B"
        power:
          name: "Phase B Power"
          id: phase_b_power
          device_class: power
          filters: [*df1, *df2]
      - { phase_id: phase_a, input:  "1", power: { name:  "Circuit 1 Power", id:  cir1, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_b, input:  "2", power: { name:  "Circuit 2 Power", id:  cir2, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_a, input:  "3", power: { name:  "Circuit 3 Power", id:  cir3, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_a, input:  "4", power: { name:  "Circuit 4 Power", id:  cir4, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_a, input:  "5", power: { name:  "Circuit 5 Power", id:  cir5, filters: [ *df1, *df2, multiply: 2 ] } }
      - { phase_id: phase_a, input:  "6", power: { name:  "Circuit 6 Power", id:  cir6, filters: [ *df1, *df2, multiply: 2 ] } }
      - { phase_id: phase_a, input:  "7", power: { name:  "Circuit 7 Power", id:  cir7, filters: [ *df1, *df2, multiply: 2 ] } }
      - { phase_id: phase_b, input:  "8", power: { name:  "Circuit 8 Power", id:  cir8, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_b, input:  "9", power: { name:  "Circuit 9 Power", id:  cir9, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_b, input: "10", power: { name: "Circuit 10 Power", id: cir10, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_a, input: "11", power: { name: "Circuit 11 Power", id: cir11, filters: [ *df1, *df2, multiply: 2 ] } }
      - { phase_id: phase_a, input: "12", power: { name: "Circuit 12 Power", id: cir12, filters: [ *df1, *df2, multiply: 2 ] } }
      - { phase_id: phase_a, input: "13", power: { name: "Circuit 13 Power", id: cir13, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_a, input: "14", power: { name: "Circuit 14 Power", id: cir14, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_b, input: "15", power: { name: "Circuit 15 Power", id: cir15, filters: [ *df1, *df2 ] } }
      - { phase_id: phase_a, input: "16", power: { name: "Circuit 16 Power", id: cir16, filters: [ *df1, *df2 ] } }
  - 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 You will then need to solder a serial header onto the programming port, so that it looks like this:

closeup of the debug header pinout Plug the USB adapter in. Connect RX to RX, TX to TX, and GND to GND. Do not connect 5V or 3.3V 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 Hold the modified end of the cable in IO0 to the metal shield on the ESP32. While holding it in place, connect 5V on your UART adapter to the VCC_5V0 pin on the board.

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!

FAQ

How do I use this with MQTT?

At this time, it's not possible to use the Vue with MQTT.

Technical background: ESPHome doesn't support MQTT when using the ESP-IDF framework, at least not at the time of writing. However, we can't use the Arduino framework, since we need to this bugfix commit. The bugfix is in the latest version of arduino-esp32, but we access it through platformio/platform-espressif32, which has not yet been updated (please be patent and don't bother the maintainers in the issue!)

I'm getting negative values

  • You may have put that clamp on the wire backwards
  • You may have selected the wrong phase in the configuration

The readings on one or two of my sensors are crazy

Sometimes the CTs aren't fully plugged into the 3.5mm jacks on the Vue. It's often not an issue with the initial install, but with stuff getting jostled around as you put things back together.

This issue will often manifest as jumps between 0W and some other wattage for no reason.

Open up the panel, and make sure every connector is fully inserted into the Vue. Check if the problem is solved before putting the panel cover back on.

My data readings go up and down

If your readings are within ±1W, then they're within the expected margin of error. The filters are designed to smooth out noise like this, and it's expected as no physical system can be perfect.

If the readings are significant outside of that, there may be a problem.


(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