From 578edbc7dc6fb2f953ccd268e6a3a07fd3bf677c Mon Sep 17 00:00:00 2001 From: CeeWeasel Date: Tue, 9 Dec 2025 16:59:38 -0500 Subject: [PATCH] stop hating myself --- .gitignore | 3 + automations/things/dishwasher_done.yaml | 176 ++-- automations/things/tumble_dryer_done.yaml | 111 --- automations/things/washing_machine_done.yaml | 111 --- components/packages/announcements.yaml | 74 +- .../packages/appliances/dishwasher.yaml | 296 +++--- .../packages/appliances/dishwasher_mqtt.yaml | 259 ++++++ components/packages/google_assistant.yaml | 60 -- esphome/archive/power-monitor-cs.yaml | 282 ++++++ esphome/archive/power-monitor.yaml | 847 ++++++++++++++++++ esphome/circuit-setup/6chan_common.yaml | 68 ++ .../circuit-setup/6chan_common_ethernet.yaml | 65 ++ .../6chan_common_ethernet_ws.yaml | 67 ++ .../6chan_energy_meter_1-addon.yaml | 220 +++++ .../6chan_energy_meter_1-addon_ethernet.yaml | 217 +++++ .../6chan_energy_meter_2-addons.yaml | 250 ++++++ .../6chan_energy_meter_2-addons_ethernet.yaml | 250 ++++++ .../6chan_energy_meter_3-addons.yaml | 276 ++++++ ...chan_energy_meter_3-addons_2-voltages.yaml | 320 +++++++ .../6chan_energy_meter_3-addons_ethernet.yaml | 279 ++++++ .../6chan_energy_meter_4-addons.yaml | 303 +++++++ .../6chan_energy_meter_4-addons_ethernet.yaml | 310 +++++++ .../6chan_energy_meter_5-addons.yaml | 330 +++++++ .../6chan_energy_meter_5-addons_ethernet.yaml | 341 +++++++ .../6chan_energy_meter_6-addons.yaml | 357 ++++++++ .../6chan_energy_meter_6-addons_ethernet.yaml | 372 ++++++++ .../6chan_energy_meter_main_board.yaml | 162 ++++ .../6chan_energy_meter_main_ethernet.yaml | 155 ++++ .../6chan_energy_meter_main_ethernet_ws.yaml | 155 ++++ esphome/circuit-setup/README.md | 153 ++++ .../calibration/6chan_addon1_calibration.yaml | 65 ++ .../6chan_addon1_offset_calibrations.yaml | 39 + .../calibration/6chan_addon2_calibration.yaml | 65 ++ .../6chan_addon2_offset_calibrations.yaml | 39 + .../calibration/6chan_addon3_calibration.yaml | 65 ++ .../6chan_addon3_offset_calibrations.yaml | 39 + .../calibration/6chan_addon4_calibration.yaml | 65 ++ .../6chan_addon4_offset_calibrations.yaml | 39 + .../calibration/6chan_addon5_calibration.yaml | 65 ++ .../6chan_addon5_offset_calibrations.yaml | 39 + .../calibration/6chan_addon6_calibration.yaml | 65 ++ .../6chan_addon6_offset_calibrations.yaml | 39 + .../calibration/6chan_main_calibration.yaml | 65 ++ .../6chan_main_offset_calibrations.yaml | 39 + .../6chan_energy_meter_3-phase_ethernet.yaml | 223 +++++ ...han_energy_meter_6-addons_42-channels.yaml | 459 ++++++++++ .../6chan_energy_meter_6-addons_ethernet.yaml | 481 ++++++++++ ...6chan_energy_meter_house_solar_ha_kwh.yaml | 272 ++++++ .../examples/6chan_energy_meter_v1.2.yaml | 205 +++++ .../examples/6chan_main_calibration_beta.yaml | 420 +++++++++ .../meter_sensors/6chan_addon1.yaml | 100 +++ .../meter_sensors/6chan_addon2.yaml | 100 +++ .../meter_sensors/6chan_addon3.yaml | 101 +++ .../meter_sensors/6chan_addon4.yaml | 100 +++ .../meter_sensors/6chan_addon5.yaml | 100 +++ .../meter_sensors/6chan_addon6.yaml | 100 +++ .../meter_sensors/6chan_main_sensor.yaml | 123 +++ .../6chan_addon1_power_quality.yaml | 123 +++ .../6chan_addon2_power_quality.yaml | 123 +++ .../6chan_addon3_power_quality.yaml | 123 +++ .../6chan_addon4_power_quality.yaml | 123 +++ .../6chan_addon5_power_quality.yaml | 123 +++ .../6chan_addon6_power_quality.yaml | 123 +++ .../6chan_main_power_quality.yaml | 123 +++ .../status_fields/6chan_addon1_status.yaml | 25 + .../status_fields/6chan_addon2_status.yaml | 25 + .../status_fields/6chan_addon3_status.yaml | 25 + .../status_fields/6chan_addon4_status.yaml | 25 + .../status_fields/6chan_addon5_status.yaml | 25 + .../status_fields/6chan_addon6_status.yaml | 25 + .../status_fields/6chan_main_status.yaml | 30 + esphome/common/media_player.yaml | 14 + esphome/common/mqtt_all.yaml | 30 + esphome/common/mqtt_null.yaml | 26 + esphome/garage-cleversensor.yaml | 6 + esphome/home-assistant-voice-097b44.yaml | 40 +- esphome/power-monitor.yaml | 15 + lovelace/appliances/dishwasher.yaml | 64 +- lovelace/appliances/keurig.yaml | 17 - lovelace/frigate/view-ai-cam03.yaml | 4 - lovelace/frigate/view-ai-cam04.yaml | 5 +- lovelace/frigate/view-ai-cam06.yaml | 5 +- lovelace/frigate/view-ai-cam07.yaml | 5 +- lovelace/frigate/view-ai-cam08.yaml | 5 +- lovelace/frigate/view-ai-cam12.yaml | 5 +- lovelace/frigate/view-ai-cam13.yaml | 165 ---- lovelace/frigate/view-ai-cam14.yaml | 127 --- lovelace/frigate/view-ai-cam18.yaml | 7 +- lovelace/frigate/view-ai-cam19.yaml | 7 +- lovelace/phone/home.yaml | 36 +- lovelace/phone/kitchen.yaml | 2 +- lovelace/resources.yaml | 3 + lovelace/view-ha-floorplan.yaml | 14 +- lovelace/view-overview.yaml | 26 +- www/floorplan/floorplan.css | 14 +- .../6c84a73d-d5a3-4fad-8bc2-3c6d663eff40.gif | Bin 0 -> 41094 bytes .../b7353e92-f701-4f3d-a3d9-0673f7d8d05f.jpg | Bin 0 -> 35660 bytes www/mail_and_packages/overlay.png | Bin 0 -> 8764 bytes www/mail_and_packages/vignette.png | Bin 0 -> 38527 bytes www/mail_and_packages/white.png | Bin 0 -> 171 bytes 100 files changed, 11098 insertions(+), 966 deletions(-) delete mode 100644 automations/things/tumble_dryer_done.yaml delete mode 100644 automations/things/washing_machine_done.yaml create mode 100644 components/packages/appliances/dishwasher_mqtt.yaml create mode 100644 esphome/archive/power-monitor-cs.yaml create mode 100644 esphome/archive/power-monitor.yaml create mode 100644 esphome/circuit-setup/6chan_common.yaml create mode 100644 esphome/circuit-setup/6chan_common_ethernet.yaml create mode 100644 esphome/circuit-setup/6chan_common_ethernet_ws.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_1-addon.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_1-addon_ethernet.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_2-addons.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_2-addons_ethernet.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_3-addons.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_3-addons_2-voltages.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_3-addons_ethernet.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_4-addons.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_4-addons_ethernet.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_5-addons.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_5-addons_ethernet.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_6-addons.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_6-addons_ethernet.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_main_board.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_main_ethernet.yaml create mode 100644 esphome/circuit-setup/6chan_energy_meter_main_ethernet_ws.yaml create mode 100644 esphome/circuit-setup/README.md create mode 100644 esphome/circuit-setup/calibration/6chan_addon1_calibration.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon1_offset_calibrations.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon2_calibration.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon2_offset_calibrations.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon3_calibration.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon3_offset_calibrations.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon4_calibration.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon4_offset_calibrations.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon5_calibration.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon5_offset_calibrations.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon6_calibration.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_addon6_offset_calibrations.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_main_calibration.yaml create mode 100644 esphome/circuit-setup/calibration/6chan_main_offset_calibrations.yaml create mode 100644 esphome/circuit-setup/examples/6chan_energy_meter_3-phase_ethernet.yaml create mode 100644 esphome/circuit-setup/examples/6chan_energy_meter_6-addons_42-channels.yaml create mode 100644 esphome/circuit-setup/examples/6chan_energy_meter_6-addons_ethernet.yaml create mode 100644 esphome/circuit-setup/examples/6chan_energy_meter_house_solar_ha_kwh.yaml create mode 100644 esphome/circuit-setup/examples/6chan_energy_meter_v1.2.yaml create mode 100644 esphome/circuit-setup/examples/6chan_main_calibration_beta.yaml create mode 100644 esphome/circuit-setup/meter_sensors/6chan_addon1.yaml create mode 100644 esphome/circuit-setup/meter_sensors/6chan_addon2.yaml create mode 100644 esphome/circuit-setup/meter_sensors/6chan_addon3.yaml create mode 100644 esphome/circuit-setup/meter_sensors/6chan_addon4.yaml create mode 100644 esphome/circuit-setup/meter_sensors/6chan_addon5.yaml create mode 100644 esphome/circuit-setup/meter_sensors/6chan_addon6.yaml create mode 100644 esphome/circuit-setup/meter_sensors/6chan_main_sensor.yaml create mode 100644 esphome/circuit-setup/power_quality/6chan_addon1_power_quality.yaml create mode 100644 esphome/circuit-setup/power_quality/6chan_addon2_power_quality.yaml create mode 100644 esphome/circuit-setup/power_quality/6chan_addon3_power_quality.yaml create mode 100644 esphome/circuit-setup/power_quality/6chan_addon4_power_quality.yaml create mode 100644 esphome/circuit-setup/power_quality/6chan_addon5_power_quality.yaml create mode 100644 esphome/circuit-setup/power_quality/6chan_addon6_power_quality.yaml create mode 100644 esphome/circuit-setup/power_quality/6chan_main_power_quality.yaml create mode 100644 esphome/circuit-setup/status_fields/6chan_addon1_status.yaml create mode 100644 esphome/circuit-setup/status_fields/6chan_addon2_status.yaml create mode 100644 esphome/circuit-setup/status_fields/6chan_addon3_status.yaml create mode 100644 esphome/circuit-setup/status_fields/6chan_addon4_status.yaml create mode 100644 esphome/circuit-setup/status_fields/6chan_addon5_status.yaml create mode 100644 esphome/circuit-setup/status_fields/6chan_addon6_status.yaml create mode 100644 esphome/circuit-setup/status_fields/6chan_main_status.yaml create mode 100644 esphome/common/media_player.yaml create mode 100644 esphome/common/mqtt_all.yaml create mode 100644 esphome/common/mqtt_null.yaml delete mode 100644 lovelace/frigate/view-ai-cam13.yaml delete mode 100644 lovelace/frigate/view-ai-cam14.yaml create mode 100644 www/mail_and_packages/6c84a73d-d5a3-4fad-8bc2-3c6d663eff40.gif create mode 100644 www/mail_and_packages/amazon/b7353e92-f701-4f3d-a3d9-0673f7d8d05f.jpg create mode 100644 www/mail_and_packages/overlay.png create mode 100644 www/mail_and_packages/vignette.png create mode 100644 www/mail_and_packages/white.png diff --git a/.gitignore b/.gitignore index 0bd58ed..cbbb60b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,8 @@ backup_config.yaml glances/ .tts.token* *.tts.token +.secrets/ +secrets/ customize.yaml image/ open-zwave/ @@ -63,6 +65,7 @@ rtl_433.conf *.conf.template* go2rtc-1.0.0 go2rtc.yaml +mqtt_dump.txt nest.conf harmony_harmony_hub.conf diff --git a/automations/things/dishwasher_done.yaml b/automations/things/dishwasher_done.yaml index c53f3d2..38bfbb9 100644 --- a/automations/things/dishwasher_done.yaml +++ b/automations/things/dishwasher_done.yaml @@ -1,102 +1,102 @@ -alias: Dishwasher Done -id: dishwashwer_done -description: "Dishwasher just finished" -trigger: - - platform: state - entity_id: input_boolean.empty_dishwasher - from: "off" - to: "on" +# alias: Dishwasher Done +# id: dishwashwer_done +# description: "Dishwasher just finished" +# trigger: +# - platform: state +# entity_id: input_boolean.empty_dishwasher +# from: "off" +# to: "on" - - platform: homeassistant - event: start +# - platform: homeassistant +# event: start -condition: - - alias: "The home is occupied" - condition: state - entity_id: input_boolean.home_occupied - state: "on" +# condition: +# - alias: "The home is occupied" +# condition: state +# entity_id: input_boolean.home_occupied +# state: "on" - - alias: "Its not bedtime" - condition: state - entity_id: input_boolean.bedtime - state: "off" +# - alias: "Its not bedtime" +# condition: state +# entity_id: input_boolean.bedtime +# state: "off" -action: - - repeat: - while: "{{ is_state('input_boolean.empty_dishwasher','on') }}" - sequence: - - choose: - - conditions: - - condition: state - entity_id: input_boolean.allow_announcements - state: "on" +# action: +# - repeat: +# while: "{{ is_state('input_boolean.empty_dishwasher','on') }}" +# sequence: +# - choose: +# - conditions: +# - condition: state +# entity_id: input_boolean.allow_announcements +# state: "on" - - condition: not - conditions: - - condition: state - entity_id: sensor.pixel_7_audio_mode - state: in_communication - - condition: state - entity_id: sensor.pixel_7_audio_mode - state: in_call - - condition: state - entity_id: input_boolean.kids_bedtime - state: "on" - # - condition: state - # entity_id: input_boolean.announcement_pending - # state: 'on' +# - condition: not +# conditions: +# - condition: state +# entity_id: sensor.pixel_7_audio_mode +# state: in_communication +# - condition: state +# entity_id: sensor.pixel_7_audio_mode +# state: in_call +# - condition: state +# entity_id: input_boolean.kids_bedtime +# state: "on" +# # - condition: state +# # entity_id: input_boolean.announcement_pending +# # state: 'on' - sequence: - - action: input_boolean.turn_off - data: {} - target: - entity_id: - - input_boolean.announce_dishwasher_done - - action: input_boolean.turn_on - data: {} - target: - entity_id: - - input_boolean.announce_dishwasher_done - # - input_boolean.announcement_pending +# sequence: +# - action: input_boolean.turn_off +# data: {} +# target: +# entity_id: +# - input_boolean.announce_dishwasher_done +# - action: input_boolean.turn_on +# data: {} +# target: +# entity_id: +# - input_boolean.announce_dishwasher_done +# # - input_boolean.announcement_pending - - choose: - - conditions: - - "{{is_state('binary_sensor.dreambox_recently_active','on') }}" +# - choose: +# - conditions: +# - "{{is_state('binary_sensor.dreambox_recently_active','on') }}" - sequence: - - action: notify.dreambox - data: - message: The dishwasher is done +# sequence: +# - action: notify.dreambox +# data: +# message: The dishwasher is done - - choose: - - conditions: - - "{{is_state('binary_sensor.dreamsurface_recently_active','on') }}" +# - choose: +# - conditions: +# - "{{is_state('binary_sensor.dreamsurface_recently_active','on') }}" - sequence: - - action: notify.dreamsurface - data: - message: The dishwasher is done +# sequence: +# - action: notify.dreamsurface +# data: +# message: The dishwasher is done - - choose: - - conditions: - - condition: state - entity_id: input_boolean.clint_home - state: "off" +# - choose: +# - conditions: +# - condition: state +# entity_id: input_boolean.clint_home +# state: "off" - sequence: - - action: notify.mobile_app_pixel_7 - data: - message: The dishwasher is done - data: - tag: "dishwasher-complete" - notification_icon: mdi:dishwasher-alert - channel: Appliance +# sequence: +# - action: notify.mobile_app_pixel_7 +# data: +# message: The dishwasher is done +# data: +# tag: "dishwasher-complete" +# notification_icon: mdi:dishwasher-alert +# channel: Appliance - - delay: - minutes: 30 +# - delay: +# minutes: 30 - - action: input_boolean.turn_off - data: {} - target: - entity_id: - - input_boolean.announce_dishwasher_done +# - action: input_boolean.turn_off +# data: {} +# target: +# entity_id: +# - input_boolean.announce_dishwasher_done diff --git a/automations/things/tumble_dryer_done.yaml b/automations/things/tumble_dryer_done.yaml deleted file mode 100644 index cb7315f..0000000 --- a/automations/things/tumble_dryer_done.yaml +++ /dev/null @@ -1,111 +0,0 @@ -alias: Tumble Dryer Done -id: tumble_dryer_done -description: "Dryer just finished" -trigger: - - platform: state - entity_id: input_boolean.fold_clothes - from: "off" - to: "on" - - - platform: homeassistant - event: start - -condition: - - alias: "The home is occupied" - condition: state - entity_id: input_boolean.home_occupied - state: "on" - - - alias: "Its not bedtime" - condition: state - entity_id: input_boolean.bedtime - state: "off" - - - condition: state - entity_id: input_boolean.allow_announcements - state: "on" - -action: - - repeat: - while: "{{ is_state('input_boolean.fold_clothes','on') }}" - sequence: - - choose: - - conditions: - - condition: state - entity_id: input_boolean.clint_home - state: "on" - - condition: state - entity_id: binary_sensor.utility_room_occupied - state: "off" - - condition: not - conditions: - - condition: state - entity_id: sensor.pixel_7_audio_mode - state: in_communication - - condition: state - entity_id: sensor.pixel_7_audio_mode - state: in_call - - condition: state - entity_id: input_boolean.kids_bedtime - state: "on" - - condition: state - entity_id: input_boolean.bedtime - state: "on" - # - condition: state - # entity_id: input_boolean.announcement_pending - # state: 'on' - - sequence: - - action: input_boolean.turn_off - data: {} - target: - entity_id: - - input_boolean.announce_dryer_done - - action: input_boolean.turn_on - data: {} - target: - entity_id: - - input_boolean.announce_dryer_done - # - input_boolean.announcement_pending - - - choose: - - conditions: - - "{{ is_state('binary_sensor.dreambox_recently_active','on') }}" - - sequence: - - action: notify.dreambox - data: - message: The dryer is done - - - choose: - - conditions: - - "{{ is_state('binary_sensor.dreamsurface_recently_active','on') }}" - - sequence: - - action: notify.dreamsurface - data: - message: The dryer is done - - - choose: - - conditions: - - condition: state - entity_id: input_boolean.clint_home - state: "off" - - sequence: - - action: notify.mobile_app_pixel_7 - data: - message: The dryer is done - data: - tag: "dryer-complete" - notification_icon: mdi:tumble-dryer-alert - channel: Appliance - - - delay: - minutes: 15 - - - action: input_boolean.turn_off - data: {} - target: - entity_id: - - input_boolean.announce_dryer_done diff --git a/automations/things/washing_machine_done.yaml b/automations/things/washing_machine_done.yaml deleted file mode 100644 index ba85122..0000000 --- a/automations/things/washing_machine_done.yaml +++ /dev/null @@ -1,111 +0,0 @@ -alias: Washing Machine Done -id: washing_machine_done -description: "Washing machine just finished" -trigger: - - platform: state - entity_id: input_boolean.swap_laundry - from: "off" - to: "on" - - - platform: homeassistant - event: start - -condition: - - alias: "The home is occupied" - condition: state - entity_id: input_boolean.home_occupied - state: "on" - - - alias: "Its not bedtime" - condition: state - entity_id: input_boolean.bedtime - state: "off" - - - condition: state - entity_id: input_boolean.allow_announcements - state: "on" - -action: - - repeat: - while: "{{ is_state('input_boolean.swap_laundry','on') }}" - sequence: - - choose: - - conditions: - - condition: state - entity_id: input_boolean.clint_home - state: "on" - - condition: state - entity_id: binary_sensor.utility_room_occupied - state: "off" - - condition: not - conditions: - - condition: state - entity_id: sensor.pixel_7_audio_mode - state: in_communication - - condition: state - entity_id: sensor.pixel_7_audio_mode - state: in_call - - condition: state - entity_id: input_boolean.kids_bedtime - state: "on" - - condition: state - entity_id: input_boolean.bedtime - state: "on" - # - condition: state - # entity_id: input_boolean.announcement_pending - # state: 'on' - - sequence: - - action: input_boolean.turn_off - data: {} - target: - entity_id: - - input_boolean.announce_washing_machine_done - - action: input_boolean.turn_on - data: {} - target: - entity_id: - - input_boolean.announce_washing_machine_done - # - input_boolean.announcement_pending - - - choose: - - conditions: - - "{{is_state('binary_sensor.dreambox_recently_active','on') }}" - - sequence: - - action: notify.dreambox - data: - message: The washing machine is done - - - choose: - - conditions: - - "{{is_state('binary_sensor.dreamsurface_recently_active','on') }}" - - sequence: - - action: notify.dreamsurface - data: - message: The washing machine is done - - - choose: - - conditions: - - condition: state - entity_id: input_boolean.clint_home - state: "off" - - sequence: - - action: notify.mobile_app_pixel_7 - data: - message: The washing machine is done - data: - tag: "washing-machine-complete" - notification_icon: mdi:washing-machine-alert - channel: Appliance - - - delay: - minutes: 15 - - - action: input_boolean.turn_off - data: {} - target: - entity_id: - - input_boolean.announce_washing_machine_done diff --git a/components/packages/announcements.yaml b/components/packages/announcements.yaml index 02a60e3..8955728 100644 --- a/components/packages/announcements.yaml +++ b/components/packages/announcements.yaml @@ -1,48 +1,48 @@ -input_boolean: - announcement_pending: - name: Announcement Pending - icon: mdi:bullhorn +# input_boolean: +# announcement_pending: +# name: Announcement Pending +# icon: mdi:bullhorn - announce_washing_machine_done: - name: Announce Washing Machine Done - icon: mdi:washing-machine +# announce_washing_machine_done: +# name: Announce Washing Machine Done +# icon: mdi:washing-machine - announce_dryer_done: - name: Announce Dryer Done - icon: mdi:tumble-dryer +# announce_dryer_done: +# name: Announce Dryer Done +# icon: mdi:tumble-dryer - announce_dishwasher_done: - name: Announce Dishwasher Done - icon: mdi:dishwasher +# announce_dishwasher_done: +# name: Announce Dishwasher Done +# icon: mdi:dishwasher - announce_almost_bedtime: - name: Announce Almost Bedtime - icon: mdi:sleep +# announce_almost_bedtime: +# name: Announce Almost Bedtime +# icon: mdi:sleep - announce_goodnight_emmett: - name: Announce Goodnight Emmett - icon: mdi:sleep +# announce_goodnight_emmett: +# name: Announce Goodnight Emmett +# icon: mdi:sleep - announce_goodnight_bridget: - name: Announce Goodnight Bridget - icon: mdi:sleep +# announce_goodnight_bridget: +# name: Announce Goodnight Bridget +# icon: mdi:sleep - announce_goodnight_ebin: - name: Announce Goodnight Ebin - icon: mdi:sleep +# announce_goodnight_ebin: +# name: Announce Goodnight Ebin +# icon: mdi:sleep - announce_goodnight_emmett_bridget: - name: Announce Goodnight Emmett Bridget - icon: mdi:sleep +# announce_goodnight_emmett_bridget: +# name: Announce Goodnight Emmett Bridget +# icon: mdi:sleep - announce_goodnight_emmett_ebin: - name: Announce Goodnight Emmett Ebin - icon: mdi:sleep +# announce_goodnight_emmett_ebin: +# name: Announce Goodnight Emmett Ebin +# icon: mdi:sleep - announce_goodnight_bridget_ebin: - name: Announce Goodnight Bridget Ebin - icon: mdi:sleep +# announce_goodnight_bridget_ebin: +# name: Announce Goodnight Bridget Ebin +# icon: mdi:sleep - announce_goodnight_emmett_bridget_ebin: - name: Announce Goodnight Emmett Bridget Ebin - icon: mdi:sleep \ No newline at end of file +# announce_goodnight_emmett_bridget_ebin: +# name: Announce Goodnight Emmett Bridget Ebin +# icon: mdi:sleep \ No newline at end of file diff --git a/components/packages/appliances/dishwasher.yaml b/components/packages/appliances/dishwasher.yaml index 3e50ccd..7ca590e 100644 --- a/components/packages/appliances/dishwasher.yaml +++ b/components/packages/appliances/dishwasher.yaml @@ -1,170 +1,170 @@ -template: - - binary_sensor: - - name: Dishwasher - unique_id: templatebinarysensor.dishwasher - icon: mdi:dishwasher - delay_on: "{{states('input_number.dishwasher_delay_on') | float(default=0) }}" - delay_off: "{{states('input_number.dishwasher_delay_off') | float(default=0) }}" - availability: "{{ states('sensor.pm_dishwasher_w') not in ['unknown', 'unavailable'] }}" - attributes: - model_number: "MDB6769PAS1" - serial_number: "F24407234" - power: "{{ states('sensor.pm_dishwasher_w') | float(default=0)}}" - target: "{{ states('input_number.dishwasher_on') | float(default=0)}}" - state: "{{ states('sensor.pm_dishwasher_w')|float(default=0) >= states('input_number.dishwasher_on')|float(default=0) }}" +# template: +# - binary_sensor: +# - name: Dishwasher +# unique_id: templatebinarysensor.dishwasher +# icon: mdi:dishwasher +# delay_on: "{{states('input_number.dishwasher_delay_on') | float(default=0) }}" +# delay_off: "{{states('input_number.dishwasher_delay_off') | float(default=0) }}" +# availability: "{{ states('sensor.pm_dishwasher_w') not in ['unknown', 'unavailable'] }}" +# attributes: +# model_number: "MDB6769PAS1" +# serial_number: "F24407234" +# power: "{{ states('sensor.pm_dishwasher_w') | float(default=0)}}" +# target: "{{ states('input_number.dishwasher_on') | float(default=0)}}" +# state: "{{ states('sensor.pm_dishwasher_w')|float(default=0) >= states('input_number.dishwasher_on')|float(default=0) }}" - - sensor: - - name: Dishwasher - unique_id: templatesensor_dishwasher - state: > - {% if is_state('binary_sensor.dishwasher','on')%} - running - {% elif is_state('binary_sensor.dishwasher','off') and is_state('input_boolean.empty_dishwasher','on') %} - pending - {% else %} - idle - {% endif %} - icon: > - {% if is_state('sensor.dishwasher','idle') %} - mdi:dishwasher-off - {% elif is_state('sensor.dishwasher','pending') %} - mdi:dishwasher-alert - {% else %} - mdi:dishwasher - {% endif %} - attributes: - model_number: "MDB6769PAS1" - serial_number: "F24407234" - power: "{{ states('sensor.pm_dishwasher_w') | float(default=0)}}" - target: "{{ states('input_number.dishwasher_on') | float(default=0)}}" +# - sensor: +# - name: Dishwasher +# unique_id: templatesensor_dishwasher +# state: > +# {% if is_state('binary_sensor.dishwasher','on')%} +# running +# {% elif is_state('binary_sensor.dishwasher','off') and is_state('input_boolean.empty_dishwasher','on') %} +# pending +# {% else %} +# idle +# {% endif %} +# icon: > +# {% if is_state('sensor.dishwasher','idle') %} +# mdi:dishwasher-off +# {% elif is_state('sensor.dishwasher','pending') %} +# mdi:dishwasher-alert +# {% else %} +# mdi:dishwasher +# {% endif %} +# attributes: +# model_number: "MDB6769PAS1" +# serial_number: "F24407234" +# power: "{{ states('sensor.pm_dishwasher_w') | float(default=0)}}" +# target: "{{ states('input_number.dishwasher_on') | float(default=0)}}" -input_boolean: - empty_dishwasher: - name: Empty Dishwasher - icon: mdi:cupboard +# input_boolean: +# empty_dishwasher: +# name: Empty Dishwasher +# icon: mdi:cupboard -input_number: - dishwasher_on: - # was 4 - name: "Dishwasher On" - icon: mdi:dishwasher - min: 0 - max: 1000 - step: 0.1 - mode: box - unit_of_measurement: W +# input_number: +# dishwasher_on: +# # was 4 +# name: "Dishwasher On" +# icon: mdi:dishwasher +# min: 0 +# max: 1000 +# step: 0.1 +# mode: box +# unit_of_measurement: W - dishwasher_off: - name: "Dishwasher Off" - icon: mdi:dishwasher-off - min: 0 - max: 1000 - step: 0.1 - mode: box - unit_of_measurement: W +# dishwasher_off: +# name: "Dishwasher Off" +# icon: mdi:dishwasher-off +# min: 0 +# max: 1000 +# step: 0.1 +# mode: box +# unit_of_measurement: W - dishwasher_delay_on: - name: "Dishwasher Delay On" - icon: mdi:clock - min: 0 - max: 900 - step: 10 - mode: box +# dishwasher_delay_on: +# name: "Dishwasher Delay On" +# icon: mdi:clock +# min: 0 +# max: 900 +# step: 10 +# mode: box - dishwasher_delay_off: - # was 600 - name: "Dishwasher Delay Off" - icon: mdi:clock-alert - min: 0 - max: 900 - step: 10 - mode: box +# dishwasher_delay_off: +# # was 600 +# name: "Dishwasher Delay Off" +# icon: mdi:clock-alert +# min: 0 +# max: 900 +# step: 10 +# mode: box -automation: - - id: automation_empty_dishwasher_state - alias: Empty Dishwasher - trigger: - - id: dishwasher_off - platform: state - entity_id: binary_sensor.dishwasher - from: "on" - to: "off" +# automation: +# - id: automation_empty_dishwasher_state +# alias: Empty Dishwasher +# trigger: +# - id: dishwasher_off +# platform: state +# entity_id: binary_sensor.dishwasher +# from: "on" +# to: "off" - - id: dishwasher_on - platform: state - entity_id: binary_sensor.dishwasher - from: "off" - to: "on" +# - id: dishwasher_on +# platform: state +# entity_id: binary_sensor.dishwasher +# from: "off" +# to: "on" - - id: door_open - platform: state - entity_id: binary_sensor.dishwasher_door_contact - from: "off" - to: "on" - for: - seconds: 5 +# - id: door_open +# platform: state +# entity_id: binary_sensor.dishwasher_door_contact +# from: "off" +# to: "on" +# for: +# seconds: 5 - condition: [] - action: - - choose: - - alias: "Dishwasher is running. No need to empty it yet" - conditions: - - condition: trigger - id: dishwasher_on +# condition: [] +# action: +# - choose: +# - alias: "Dishwasher is running. No need to empty it yet" +# conditions: +# - condition: trigger +# id: dishwasher_on - - condition: state - entity_id: input_boolean.empty_dishwasher - state: "on" +# - condition: state +# entity_id: input_boolean.empty_dishwasher +# state: "on" - sequence: - - action: logbook.log - data_template: - name: Empty Dishwasher - Load Started - entity_id: automation.empty_dishwasher - message: Dishwasher just turned on. Turning off input_boolean in case it got left on +# sequence: +# - action: logbook.log +# data_template: +# name: Empty Dishwasher - Load Started +# entity_id: automation.empty_dishwasher +# message: Dishwasher just turned on. Turning off input_boolean in case it got left on - - action: homeassistant.turn_off - target: - entity_id: input_boolean.empty_dishwasher +# - action: homeassistant.turn_off +# target: +# entity_id: input_boolean.empty_dishwasher - - alias: "Dishwasher finished while door was shut" - conditions: - - condition: trigger - id: dishwasher_off +# - alias: "Dishwasher finished while door was shut" +# conditions: +# - condition: trigger +# id: dishwasher_off - - condition: state - entity_id: binary_sensor.dishwasher_door_contact - state: "off" +# - condition: state +# entity_id: binary_sensor.dishwasher_door_contact +# state: "off" - sequence: - - action: logbook.log - data_template: - name: Empty Dishwasher - Load finished - entity_id: automation.empty_dishwasher - message: Dishwasher just turned off while the door was shut. Assuming dishes need to be put away +# sequence: +# - action: logbook.log +# data_template: +# name: Empty Dishwasher - Load finished +# entity_id: automation.empty_dishwasher +# message: Dishwasher just turned off while the door was shut. Assuming dishes need to be put away - - action: homeassistant.turn_on - target: - entity_id: input_boolean.empty_dishwasher +# - action: homeassistant.turn_on +# target: +# entity_id: input_boolean.empty_dishwasher - - alias: "Door was opened for 30 seconds while dishwasher was off" - conditions: - - condition: trigger - id: door_open +# - alias: "Door was opened for 30 seconds while dishwasher was off" +# conditions: +# - condition: trigger +# id: door_open - - condition: state - entity_id: binary_sensor.dishwasher - state: "off" +# - condition: state +# entity_id: binary_sensor.dishwasher +# state: "off" - sequence: - - action: logbook.log - data_template: - name: Empty Dishwasher - Dishes put away - entity_id: automation.empty_dishwasher - message: Dishwasher door was opened while the dishwasher was off. Assuming dishes don't need to be put away. +# sequence: +# - action: logbook.log +# data_template: +# name: Empty Dishwasher - Dishes put away +# entity_id: automation.empty_dishwasher +# message: Dishwasher door was opened while the dishwasher was off. Assuming dishes don't need to be put away. - - action: homeassistant.turn_off - target: - entity_id: input_boolean.empty_dishwasher +# - action: homeassistant.turn_off +# target: +# entity_id: input_boolean.empty_dishwasher - mode: single +# mode: single diff --git a/components/packages/appliances/dishwasher_mqtt.yaml b/components/packages/appliances/dishwasher_mqtt.yaml new file mode 100644 index 0000000..fb3c1f5 --- /dev/null +++ b/components/packages/appliances/dishwasher_mqtt.yaml @@ -0,0 +1,259 @@ +# mqtt: +# - sensor: +# # This is the root sensor that tracks the state of the dishwasher +# - unique_id: mqtt_dishwasher_status # supposedly has to be set to associate with device +# default_entity_id: status # IDK if this will work with unique_id set but we need unique_id set to associate with a device + +# # # This sensor will always be available, since is it just a combination of other sensors +# # availability: +# # topic: "cleverdevices/dishwasher" +# device: +# name: "Dishwasher" +# model: "MDB6769PAS1" +# serial_number: "F24407234" +# suggested_area: "Kitchen" +# identifiers: +# - "MDB6769PAS1 - F24407234" +# device_class: enum +# entity_category: diagnostic +# icon: > +# {% if is_state('sensor.dishwasher','idle') %} +# mdi:dishwasher-off +# {% elif is_state('sensor.dishwasher','pending') %} +# mdi:dishwasher-alert +# {% else %} +# mdi:dishwasher +# {% endif %} +# options: +# - "Idle" # Dishwasher is not doing anything +# - "Running" # Dishwasher is running +# - "Pending" # Dishwasher ran, stopped running, and the door hasn't been opened. Basically, the dishes need to be unloaded +# - "Problem" # The dishwasher has been running for too long, indicating a possible issue +# availability_topic: "cleverdevices/dishwasher/availability" +# payload_available: online +# payload_not_available: offline +# state_topic: "cleverdevices/dishwasher" +# state: >- +# {% set mapper = { +# 'idle': 'Idle', +# 'running': 'Running', +# 'Pending': 'Pending', +# 'Problem': 'Problem', +# } %} +# {% set state = states('binary_sensor.work_day') %} +# {{ mapper[state] if state in mapper else 'Unknown' }} +# # attributes: +# # model_number: "MDB6769PAS1" +# # serial_number: "F24407234" +# # power: "{{ states('sensor.pm_dishwasher_w') | float(default=0)}}" +# # target: "{{ states('input_number.dishwasher_on') | float(default=0)}}" + +# - binary_sensor: +# - unique_id: mqtt_dishwasher +# default_entity_id: dishwasher +# name: Dishwasher +# device_class: running + +# - unique_id: mqtt_dishwasher_door +# default_entity_id: door +# name: Door +# device_class: opening + + +# - number: +# - unique_id: mqtt_dishwasher_running_watts +# name: "Dishwasher On" +# device: +# name: "Dishwasher" +# model: "MDB6769PAS1" +# serial_number: "F24407234" +# suggested_area: "Kitchen" +# identifiers: +# - "MDB6769PAS1 - F24407234" +# icon: mdi:dishwasher +# min: 0 +# max: 1000 +# step: 0.1 +# mode: box +# unit_of_measurement: W + +# - unique_id: mqtt_dishwasher_idle_watts +# name: "Dishwasher Off" +# icon: mdi:dishwasher-off +# min: 0 +# max: 1000 +# step: 0.1 +# mode: box +# unit_of_measurement: W + +# - unique_id: mqtt_dishwasher_delay_on +# name: "Dishwasher Delay On" +# icon: mdi:clock-start +# min: 0 +# max: 900 +# step: 10 +# mode: box + +# - unique_id: mqtt_dishwasher_delay_off +# # was 600 +# name: "Dishwasher Delay Off" +# icon: mdi:clock-end +# min: 0 +# max: 900 +# step: 10 +# mode: box + +# - unique_id: mqtt_dishwasher_delay_problem +# # was 600 +# name: "Dishwasher Delay Off" +# icon: mdi:clock-alert +# min: 0 +# max: 900 +# step: 10 +# mode: box + +# template: +# - binary_sensor: +# - name: Dishwasher +# unique_id: templatebinarysensor.dishwasher +# icon: mdi:dishwasher +# delay_on: "{{states('input_number.dishwasher_delay_on') | float(default=0) }}" +# delay_off: "{{states('input_number.dishwasher_delay_off') | float(default=0) }}" +# availability: "{{ states('sensor.pm_dishwasher_w') not in ['unknown', 'unavailable'] }}" +# attributes: +# model_number: "MDB6769PAS1" +# serial_number: "F24407234" +# power: "{{ states('sensor.pm_dishwasher_w') | float(default=0)}}" +# target: "{{ states('input_number.dishwasher_on') | float(default=0)}}" +# state: "{{ states('sensor.pm_dishwasher_w')|float(default=0) >= states('input_number.dishwasher_on')|float(default=0) }}" + +# input_boolean: +# empty_dishwasher: +# name: Empty Dishwasher +# icon: mdi:cupboard + +# input_number: +# dishwasher_on: +# # was 4 +# name: "Dishwasher On" +# icon: mdi:dishwasher +# min: 0 +# max: 1000 +# step: 0.1 +# mode: box +# unit_of_measurement: W + +# dishwasher_off: +# name: "Dishwasher Off" +# icon: mdi:dishwasher-off +# min: 0 +# max: 1000 +# step: 0.1 +# mode: box +# unit_of_measurement: W + +# dishwasher_delay_on: +# name: "Dishwasher Delay On" +# icon: mdi:clock +# min: 0 +# max: 900 +# step: 10 +# mode: box + +# dishwasher_delay_off: +# # was 600 +# name: "Dishwasher Delay Off" +# icon: mdi:clock-alert +# min: 0 +# max: 900 +# step: 10 +# mode: box + +# # automation: +# # - id: automation_empty_dishwasher_state +# # alias: Empty Dishwasher +# # trigger: +# # - id: dishwasher_off +# # platform: state +# # entity_id: binary_sensor.dishwasher +# # from: "on" +# # to: "off" + +# # - id: dishwasher_on +# # platform: state +# # entity_id: binary_sensor.dishwasher +# # from: "off" +# # to: "on" + +# # - id: door_open +# # platform: state +# # entity_id: binary_sensor.dishwasher_door_contact +# # from: "off" +# # to: "on" +# # for: +# # seconds: 5 + +# # condition: [] +# # action: +# # - choose: +# # - alias: "Dishwasher is running. No need to empty it yet" +# # conditions: +# # - condition: trigger +# # id: dishwasher_on + +# # - condition: state +# # entity_id: input_boolean.empty_dishwasher +# # state: "on" + +# # sequence: +# # - action: logbook.log +# # data_template: +# # name: Empty Dishwasher - Load Started +# # entity_id: automation.empty_dishwasher +# # message: Dishwasher just turned on. Turning off input_boolean in case it got left on + +# # - action: homeassistant.turn_off +# # target: +# # entity_id: input_boolean.empty_dishwasher + +# # - alias: "Dishwasher finished while door was shut" +# # conditions: +# # - condition: trigger +# # id: dishwasher_off + +# # - condition: state +# # entity_id: binary_sensor.dishwasher_door_contact +# # state: "off" + +# # sequence: +# # - action: logbook.log +# # data_template: +# # name: Empty Dishwasher - Load finished +# # entity_id: automation.empty_dishwasher +# # message: Dishwasher just turned off while the door was shut. Assuming dishes need to be put away + +# # - action: homeassistant.turn_on +# # target: +# # entity_id: input_boolean.empty_dishwasher + +# # - alias: "Door was opened for 30 seconds while dishwasher was off" +# # conditions: +# # - condition: trigger +# # id: door_open + +# # - condition: state +# # entity_id: binary_sensor.dishwasher +# # state: "off" + +# # sequence: +# # - action: logbook.log +# # data_template: +# # name: Empty Dishwasher - Dishes put away +# # entity_id: automation.empty_dishwasher +# # message: Dishwasher door was opened while the dishwasher was off. Assuming dishes don't need to be put away. + +# # - action: homeassistant.turn_off +# # target: +# # entity_id: input_boolean.empty_dishwasher + +# # mode: single diff --git a/components/packages/google_assistant.yaml b/components/packages/google_assistant.yaml index 714c1d9..9c9a522 100644 --- a/components/packages/google_assistant.yaml +++ b/components/packages/google_assistant.yaml @@ -84,66 +84,6 @@ google_assistant: - Out Front Cam room: Front Yard - input_boolean.announcement_pending: - name: Announcement Pending - expose: true - room: Furnace Room - - input_boolean.announce_washing_machine_done: - name: Announce Washing Machine Done - expose: true - room: Utility Room - - input_boolean.announce_dryer_done: - name: Announce Dryer Done - expose: true - room: Utility Room - - input_boolean.announce_dishwasher_done: - name: Announce Dishwasher Done - expose: true - room: Kitchen - - input_boolean.announce_almost_bedtime: - name: Announce Almost Bedtime - expose: true - room: Girls Room - - input_boolean.announce_goodnight_emmett: - name: Announce Goodnight Emmett - expose: true - room: Boys Room - - input_boolean.announce_goodnight_bridget: - name: Announce Goodnight Bridget - expose: true - room: Girls Room - - input_boolean.announce_goodnight_ebin: - name: Announce Goodnight Ebin - expose: true - room: Girls Room - - input_boolean.announce_goodnight_emmett_bridget: - name: Announce Goodnight Emmett Bridget - expose: true - room: Girls Room - - input_boolean.announce_goodnight_emmett_ebin: - name: Announce Goodnight Emmett Ebin - expose: true - room: Boys Room - - input_boolean.announce_goodnight_bridget_ebin: - name: Announce Goodnight Bridget Ebin - expose: true - room: Girls Room - - input_boolean.announce_goodnight_emmett_bridget_ebin: - name: Announce Goodnight Emmett Bridget Ebin - expose: true - room: Girls Room - input_boolean.kids_bedtime: name: Kids Bedtime expose: true diff --git a/esphome/archive/power-monitor-cs.yaml b/esphome/archive/power-monitor-cs.yaml new file mode 100644 index 0000000..443d169 --- /dev/null +++ b/esphome/archive/power-monitor-cs.yaml @@ -0,0 +1,282 @@ +# CT01 - A - Grid Phase A +# CT02 - G - Dryer +# CT03 - D - Furnace +# CT04 - B - Grid Phase B +# CT05 - E - Basement Plugs (Computer is on this circuit) +# CT06 - F - Nursery, Kitchen, and Dining Room Lights +# CT07 - C - Sump Pump Plug +# CT08 - H - Microwave Plug +# CT09 - I - Stove/Oven +# CT10 - J - Front Room Plugs +# CT11 - M - Heat Pump +# CT12 - L - Kitchen Circuit 1 (Fridge is on this circuit) + +substitutions: + devicename: power-monitor + disp_name: power-monitor + friendly_name: 'PM:' + entity_name: power_monitor + comment: Clever Power Monitor + static_ip: !secret power-monitor-ip + platform: ESP32 + board: nodemcu-32s + update_time: 500ms + kwh_report_interval: 60s + watt_heartbeat: 60s + throttle_time: 60s + watt_delta: "50.0" + #watt_delta: "5.0" + #grid_watt_delta: "10.0" + grid_watt_delta: "200.0" + #fast_update_time: 10s + #medium_update_time: 30s + #slow_update_time: 60s + + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + + ct1_name: 'Grid Phase A' + ct4_name: 'Grid Phase B' + + ct22_name: 'Well' # 1, 3 # sct010 - O + ct12_name: 'Kitchen 1' # 5 # sct006 - L + ct16_name: 'Kitchen 2' # 7 # sct006 - S + ct18_name: 'Laundry Plug' # 9 # sct006 - N + ct8_name: 'Microwave Plug' # 11 # sct006 - H + ct17_name: 'Bathroom Plug' # 13 # sct006 - R + ct11_name: 'Heat Pump' # 15, 17 - M + ct24_name: 'Basement Bedroom and Furnace Room Lights' # 19 # sct006 - K + ct5_name: 'Basement Plugs' # 21a # sct006 - E + ct23_name: 'Basement and Laundry Lights and Plugs' # 21b # sct006 - W + ct7_name: 'Sump Pump Plug' # 23 # sct006 - C + + ct6_name: 'Nursery, Dining, Kitchen Lights' # 2 # sct006 - F + ct20_name: 'Master Suite' # 4 # sct006 - T + ct3_name: 'Furnace' # 6 # sct006 - D + ct15_name: 'Basement Stairs and Lights' # 8 # sct006 - P + ct21_name: 'Dishwasher' # 10 # sct006 - V + ct13_name: 'Garage Outside and Front Garage Lights' # 12 # sct006 - U + ct10_name: 'Front Room Plugs' # 14 # sct006 - J + ct14_name: 'Garage and Outside Plugs' # 16 # sct006 - Q + ct9_name: 'Stove' # 18, 20 # sct016 - I + ct2_name: 'Dryer' # 22, 24 # sct010 - G + + ct19_name: 'Unused' + + +# Current Transformers: +# 20A/25mA SCT-006: 11143 + sct006: '11143' +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 80A/26.6mA SCT-010: 41660 + sct010: '41660' +# 100A/50ma SCT-013-000: 27518 + sct013: '27518' +# 120A/40mA: SCT-016: 41787 + sct016: '41787' +# 200A/100mA SCT-024: 27518 + #current_cal: '27518' +# Jameco 9VAC Transformer: +# For meter versions: +# >= v1.3: 7305 + #voltage_cal: '7305' + +## Main Board + current_cal_ct1: '41787' + current_cal_ct2: '41660' + current_cal_ct3: '11143' + current_cal_ct4: '41787' + current_cal_ct5: '11143' + current_cal_ct6: '11143' +## Addon1 + current_cal_ct7: '11143' + current_cal_ct8: '11143' + current_cal_ct9: '27518' + current_cal_ct10: '11143' + current_cal_ct11: '41660' + current_cal_ct12: '11143' +## Addon2 + current_cal_ct13: '11143' + current_cal_ct14: '11143' + current_cal_ct15: '11143' + current_cal_ct16: '11143' + current_cal_ct17: '11143' + current_cal_ct18: '11143' +## Addon3 + current_cal_ct19: '11143' + current_cal_ct20: '11143' + current_cal_ct21: '11143' + current_cal_ct22: '41660' + current_cal_ct23: '11143' + current_cal_ct24: '11143' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + + electric_freq: "60Hz" + + offset_calibration: "true" + gain_calibration: "true" + + + # spi_clk: 18 + # spi_miso: 19 + # spi_mosi: 23 + # ic1_main: 5 + # ic1_addon1: 0 + # ic1_addon2: 27 + # ic1_addon3: 2 + # ic2_main: 4 + # ic2_addon1: 16 + # ic2_addon2: 17 + # ic2_addon3: 21 + +# ethernet: +# id: eth +# type: W5500 +# clk_pin: GPIO13 +# mosi_pin: GPIO11 +# miso_pin: GPIO12 +# cs_pin: GPIO14 +# interrupt_pin: GPIO10 +# reset_pin: GPIO9 +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.7.0' + project: + name: circuitsetup.6c-energy-meter-3-addons + version: "1.7" + +packages: + wifi: !include common/wifi.yaml + # device_base: !include common/complex_esp32_base.yaml + common: !include circuit-setup/6chan_common.yaml + main: !include circuit-setup/meter_sensors/6chan_main_sensor.yaml + main_status: !include circuit-setup/status_fields/6chan_main_status.yaml + main_cal: !include circuit-setup/calibration/6chan_main_calibration.yaml + addon_1: !include circuit-setup/meter_sensors/6chan_addon1.yaml + addon_2: !include circuit-setup/meter_sensors/6chan_addon2.yaml + addon_3: !include circuit-setup/meter_sensors/6chan_addon3.yaml + + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing \ No newline at end of file diff --git a/esphome/archive/power-monitor.yaml b/esphome/archive/power-monitor.yaml new file mode 100644 index 0000000..556a5d5 --- /dev/null +++ b/esphome/archive/power-monitor.yaml @@ -0,0 +1,847 @@ +# CT01 - A - Grid Phase A +# CT02 - G - Dryer +# CT03 - D - Furnace +# CT04 - B - Grid Phase B +# CT05 - E - Basement Plugs (Computer is on this circuit) +# CT06 - F - Nursery, Kitchen, and Dining Room Lights +# CT07 - C - Sump Pump Plug +# CT08 - H - Microwave Plug +# CT09 - I - Stove/Oven +# CT10 - J - Front Room Plugs +# CT11 - M - Heat Pump +# CT12 - L - Kitchen Circuit 1 (Fridge is on this circuit) + +substitutions: + devicename: power-monitor + friendly_name: 'PM:' + entity_name: power_monitor + comment: Clever Power Monitor + static_ip: !secret power-monitor-ip + platform: ESP32 + board: nodemcu-32s + update_time: 500ms + kwh_report_interval: 60s + watt_heartbeat: 60s + throttle_time: 60s + watt_delta: "50.0" + #watt_delta: "5.0" + #grid_watt_delta: "10.0" + grid_watt_delta: "200.0" + #fast_update_time: 10s + #medium_update_time: 30s + #slow_update_time: 60s + + ct01Name: 'Grid Phase A' + ct04Name: 'Grid Phase B' + + ct22Name: 'Well' # 1, 3 # sct010 - O + ct12Name: 'Kitchen 1' # 5 # sct006 - L + ct16Name: 'Kitchen 2' # 7 # sct006 - S + ct18Name: 'Laundry Plug' # 9 # sct006 - N + ct08Name: 'Microwave Plug' # 11 # sct006 - H + ct17Name: 'Bathroom Plug' # 13 # sct006 - R + ct11Name: 'Heat Pump' # 15, 17 - M + ct24Name: 'Basement Bedroom and Furnace Room Lights' # 19 # sct006 - K + ct05Name: 'Basement Plugs' # 21a # sct006 - E + ct23Name: 'Basement and Laundry Lights and Plugs' # 21b # sct006 - W + ct07Name: 'Sump Pump Plug' # 23 # sct006 - C + + ct06Name: 'Nursery, Dining, Kitchen Lights' # 2 # sct006 - F + ct20Name: 'Master Suite' # 4 # sct006 - T + ct03Name: 'Furnace' # 6 # sct006 - D + ct15Name: 'Basement Stairs and Lights' # 8 # sct006 - P + ct21Name: 'Dishwasher' # 10 # sct006 - V + ct13Name: 'Garage Outside and Front Garage Lights' # 12 # sct006 - U + ct10Name: 'Front Room Plugs' # 14 # sct006 - J + ct14Name: 'Garage and Outside Plugs' # 16 # sct006 - Q + ct09Name: 'Stove' # 18, 20 # sct016 - I + ct02Name: 'Dryer' # 22, 24 # sct010 - G + + ct19Name: 'Unused' + + +# Current Transformers: +# 20A/25mA SCT-006: 11143 + sct006: '11143' +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 80A/26.6mA SCT-010: 41660 + sct010: '41660' +# 100A/50ma SCT-013-000: 27518 + sct013: '27518' +# 120A/40mA: SCT-016: 41787 + sct016: '41787' +# 200A/100mA SCT-024: 27518 + #current_cal: '27518' +# Jameco 9VAC Transformer: +# For meter versions: +# >= v1.3: 7305 + voltage_cal: '7305' + + + spi_clk: 18 + spi_miso: 19 + spi_mosi: 23 + ic1_main: 5 + ic1_addon1: 0 + ic1_addon2: 27 + ic1_addon3: 2 + ic2_main: 4 + ic2_addon1: 16 + ic2_addon2: 17 + ic2_addon3: 21 + +# ethernet: +# id: eth +# type: W5500 +# clk_pin: GPIO13 +# mosi_pin: GPIO11 +# miso_pin: GPIO12 +# cs_pin: GPIO14 +# interrupt_pin: GPIO10 +# reset_pin: GPIO9 + + +packages: + wifi: !include common/wifi.yaml + # device_base: !include common/complex_esp32_base.yaml + device_base: !include common/device_base.yaml + mqtt: !include common/mqtt_null.yaml + +esp32: + board: nodemcu-32s + +# web_server: +# port: 80 + +time: + - platform: sntp + id: sntp_time + timezone: America/Detroit + +logger: + # level: DEBUG + # logs: + # sensor: DEBUG + +spi: + clk_pin: ${spi_clk} + miso_pin: ${spi_miso} + mosi_pin: ${spi_mosi} + +sensor: +#IC1 Main + - platform: atm90e32 + cs_pin: ${ic1_main} + phase_a: + voltage: + name: ${friendly_name} [V] + id: ic1Volts + filters: + - throttle_average: 60s + accuracy_decimals: 1 + current: + name: ${friendly_name} ${ct01Name} [A] + id: ct1Amps + filters: + - or: + - delta: 2 + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + power: + name: ${friendly_name} ${ct01Name} [W] + id: ct1Watts + filters: + - or: + - delta: ${grid_watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct016} + phase_b: + power: + name: ${friendly_name} ${ct02Name} [W] + id: ct2Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct010} + phase_c: + power: + name: ${friendly_name} ${ct03Name} [W] + id: ct3Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + frequency: + name: ${friendly_name} Freq A + filters: + - or: + - delta: 0.05 + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + +#IC2 Main + - platform: atm90e32 + cs_pin: ${ic2_main} + phase_a: + current: + name: ${friendly_name} ${ct04Name} [A] + id: ct4Amps + filters: + - or: + - delta: ${grid_watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + power: + name: ${friendly_name} ${ct04Name} [W] + id: ct4Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + gain_voltage: ${voltage_cal} + gain_ct: ${sct016} + phase_b: + power: + name: ${friendly_name} ${ct05Name} [W] + id: ct5Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_c: + power: + name: ${friendly_name} ${ct06Name} [W] + id: ct6Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + frequency: + name: ${friendly_name} Freq B + filters: + - or: + - delta: 0.05 + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + + +#IC1 AddOn 1 + - platform: atm90e32 + cs_pin: ${ic1_addon1} + phase_a: + power: + name: ${friendly_name} ${ct07Name} [W] + id: ct7Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_b: + power: + name: ${friendly_name} ${ct08Name} [W] + id: ct8Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_c: + power: + name: ${friendly_name} ${ct09Name} [W] + id: ct9Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct013} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 1 + - platform: atm90e32 + cs_pin: ${ic2_addon1} + phase_a: + power: + name: ${friendly_name} ${ct10Name} [W] + id: ct10Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_b: + power: + name: ${friendly_name} ${ct11Name} [W] + id: ct11Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct010} + phase_c: + power: + name: ${friendly_name} ${ct12Name} [W] + id: ct12Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + +#IC1 AddOn 2 + - platform: atm90e32 + cs_pin: ${ic1_addon2} + phase_a: + power: + name: ${friendly_name} ${ct13Name} [W] + id: ct13Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_b: + power: + name: ${friendly_name} ${ct14Name} [W] + id: ct14Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_c: + power: + name: ${friendly_name} ${ct15Name} [W] + id: ct15Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 2 + - platform: atm90e32 + cs_pin: ${ic2_addon2} + phase_a: + power: + name: ${friendly_name} ${ct16Name} [W] + id: ct16Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_b: + power: + name: ${friendly_name} ${ct17Name} [W] + id: ct17Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_c: + power: + name: ${friendly_name} ${ct18Name} [W] + id: ct18Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 3 + - platform: atm90e32 +#do not use GPIO2 if ESP32 has an on-board LED assigned to it + cs_pin: ${ic1_addon3} + phase_a: + power: + name: ${friendly_name} ${ct19Name} [W] + id: ct19Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_b: + power: + name: ${friendly_name} ${ct20Name} [W] + id: ct20Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_c: + power: + name: ${friendly_name} ${ct21Name} [W] + id: ct21Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + qos: 1 + retain: true + availability: + topic: ${mqtt_root_topic}/${devicename}/${ct21Name}_w/status + payload_available: online + payload_not_available: offline + state_topic: ${mqtt_root_topic}/${devicename}/${ct21Name}_w + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 3 + - platform: atm90e32 + cs_pin: ${ic2_addon3} + phase_a: + power: + #name: ${friendly_name} ${ct22Name} [W] + internal: true + id: ct22Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct010} + phase_b: + power: + name: ${friendly_name} ${ct23Name} [W] + id: ct23Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + phase_c: + power: + name: ${friendly_name} ${ct24Name} [W] + id: ct24Watts + filters: + - or: + - delta: ${watt_delta} + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + - multiply: -1 + accuracy_decimals: 1 + gain_voltage: ${voltage_cal} + gain_ct: ${sct006} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + +#Total Amps From Grid + - platform: template + name: ${friendly_name} Grid Total [A] + id: totalAmpsFromGrid + lambda: return id(ct1Amps).state + id(ct4Amps).state ; + accuracy_decimals: 1 + unit_of_measurement: A + device_class: current + state_class: measurement + update_interval: ${update_time} + filters: + - or: + - delta: 2.0 + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + +#Total Watts From Grid + - platform: template + name: ${friendly_name} Grid Total [W] + id: totalWattsFromGrid + lambda: return id(ct1Watts).state + id(ct4Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + state_class: measurement + update_interval: ${update_time} + filters: + - or: + - delta: 5.0 + - throttle_average: ${throttle_time} + # - heartbeat: ${watt_heartbeat} + +#kWh From Grid + - platform: total_daily_energy + name: ${friendly_name} Grid [kWh] + power_id: totalWattsFromGrid + filters: + - multiply: 0.001 + # - heartbeat: ${kwh_report_interval} + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +# The CT for the Well needs to be calibrated. +# In the interim, I'm using this lambda + - platform: template + name: ${friendly_name} ${ct22Name} [W] + id: ct22WattsPositive + state_class: measurement + lambda: |- + if (id(ct22Watts).state < 0){ + return 0; + } else { + return id(ct22Watts).state ; + } + accuracy_decimals: 1 + unit_of_measurement: W + icon: mdi:lightning-bolt-circle + update_interval: ${update_time} + filters: + - delta: 5.0 + # - heartbeat: ${watt_heartbeat} + +# kWh from CT1 +# This is included in the grid calculation + +# kWh from CT2 (the dryer) + - platform: total_daily_energy + name: ${friendly_name} ${ct02Name} [kWh] + power_id: ct2Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 3 + - platform: total_daily_energy + name: ${friendly_name} ${ct03Name} [kWh] + power_id: ct3Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +# kWh From CT 4 +# This is included in the Grid calculation area + +#kWh From CT 5 + - platform: total_daily_energy + name: ${friendly_name} ${ct05Name} [kWh] + power_id: ct5Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 6 + - platform: total_daily_energy + name: ${friendly_name} ${ct06Name} [kWh] + power_id: ct6Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 7 + - platform: total_daily_energy + name: ${friendly_name} ${ct07Name} [kWh] + power_id: ct7Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 8 + - platform: total_daily_energy + name: ${friendly_name} ${ct08Name} [kWh] + power_id: ct8Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 9 + - platform: total_daily_energy + name: ${friendly_name} ${ct09Name} [kWh] + power_id: ct9Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 10 + - platform: total_daily_energy + name: ${friendly_name} ${ct10Name} [kWh] + power_id: ct10Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 11 (Heat Pump) + - platform: total_daily_energy + name: ${friendly_name} ${ct11Name} [kWh] + power_id: ct11Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 12 + - platform: total_daily_energy + name: ${friendly_name} ${ct12Name} [kWh] + power_id: ct12Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 13 + - platform: total_daily_energy + name: ${friendly_name} ${ct13Name} [kWh] + power_id: ct13Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 14 + - platform: total_daily_energy + name: ${friendly_name} ${ct14Name} [kWh] + power_id: ct14Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 15 + - platform: total_daily_energy + name: ${friendly_name} ${ct15Name} [kWh] + power_id: ct15Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 16 + - platform: total_daily_energy + name: ${friendly_name} ${ct16Name} [kWh] + power_id: ct16Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 17 + - platform: total_daily_energy + name: ${friendly_name} ${ct17Name} [kWh] + power_id: ct17Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 18 + - platform: total_daily_energy + name: ${friendly_name} ${ct18Name} [kWh] + power_id: ct18Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 19 +# this is not used + # - platform: total_daily_energy + # name: ${friendly_name} ${ct19Name} [kWh] + # power_id: ct19Watts + # filters: + # - multiply: 0.001 + # - throttle_average: ${kwh_report_interval} + # unit_of_measurement: kWh + # device_class: energy + # state_class: total_increasing + # # min_save_interval: ${update_time} + +#kWh From CT 20 + - platform: total_daily_energy + name: ${friendly_name} ${ct20Name} [kWh] + power_id: ct20Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 21 + - platform: total_daily_energy + name: ${friendly_name} ${ct21Name} [kWh] + power_id: ct21Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + qos: 1 + retain: true + availability: + topic: ${mqtt_root_topic}/${devicename}/${ct21Name}_kwh/status + payload_available: online + payload_not_available: offline + state_topic: ${mqtt_root_topic}/${devicename}/${ct21Name}_kwh + # min_save_interval: ${update_time} + +#kWh From CT 22 + - platform: total_daily_energy + name: ${friendly_name} ${ct22Name} [kWh] + power_id: ct22WattsPositive + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 23 + - platform: total_daily_energy + name: ${friendly_name} ${ct23Name} [kWh] + power_id: ct23Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} + +#kWh From CT 24 + - platform: total_daily_energy + name: ${friendly_name} ${ct24Name} [kWh] + power_id: ct24Watts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + # min_save_interval: ${update_time} diff --git a/esphome/circuit-setup/6chan_common.yaml b/esphome/circuit-setup/6chan_common.yaml new file mode 100644 index 0000000..0ea80d7 --- /dev/null +++ b/esphome/circuit-setup/6chan_common.yaml @@ -0,0 +1,68 @@ +# CircuitSetup 6 Channel Energy Meter ESPHome common variables + +esp32: + board: nodemcu-32s + cpu_frequency: 240MHz + framework: + # ESPHome v2025.7.0 update to allow more than 6 SPI hardware devices on ESP-IDF + type: esp-idf + +# Enable logging +logger: + +debug: + update_interval: 10s + +spi: + clk_pin: 18 + miso_pin: 19 + mosi_pin: 23 + +#Wifi signal +sensor: + - platform: wifi_signal + name: ${disp_name} WiFi + id: wifi_signal_db + entity_category: diagnostic + update_interval: 60s + + - platform: copy + source_id: wifi_signal_db + id: wifi_signal_pct + name: ${friendly_name} WiFi % + filters: + - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0); + unit_of_measurement: "%" + entity_category: diagnostic + + - platform: debug + free: + name: "Heap Free" + id: heap_free_sensor + entity_category: diagnostic + loop_time: + name: "Loop Time" + id: loop_time_sensor + entity_category: diagnostic + + - platform: uptime + name: Uptime + id: uptime_sensor + entity_category: diagnostic + +text_sensor: + - platform: debug + reset_reason: + name: "Reset Reason" + id: reset_reason_sensor + entity_category: diagnostic + +button: + - platform: restart + name: Restart + id: restart_button + entity_category: config + +time: + - platform: homeassistant + id: homeassistant_time diff --git a/esphome/circuit-setup/6chan_common_ethernet.yaml b/esphome/circuit-setup/6chan_common_ethernet.yaml new file mode 100644 index 0000000..36c08d7 --- /dev/null +++ b/esphome/circuit-setup/6chan_common_ethernet.yaml @@ -0,0 +1,65 @@ +# CircuitSetup 6 Channel Energy Meter ESPHome common variables +# using the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter + +esp32: + board: esp32-s3-devkitc-1 + cpu_frequency: 240MHz + framework: + type: esp-idf + +# Enable logging +logger: + hardware_uart: UART0 + level: DEBUG + +debug: + update_interval: 5s + +ethernet: + type: W5500 + clk_pin: 10 + mosi_pin: 12 + miso_pin: 11 + cs_pin: 9 + interrupt_pin: 13 + reset_pin: 14 + clock_speed: 30Mhz + +spi: + interface: software + clk_pin: 7 + miso_pin: 5 + mosi_pin: 6 + +sensor: + - platform: debug + free: + name: "Heap Free" + id: heap_free_sensor + entity_category: diagnostic + loop_time: + name: "Loop Time" + id: loop_time_sensor + entity_category: diagnostic + + - platform: uptime + name: Uptime + id: uptime_sensor + entity_category: diagnostic + +text_sensor: + - platform: debug + reset_reason: + name: "Reset Reason" + id: reset_reason_sensor + entity_category: diagnostic + +button: + - platform: restart + name: Restart + id: restart_button + entity_category: config + +time: + - platform: homeassistant + id: homeassistant_time diff --git a/esphome/circuit-setup/6chan_common_ethernet_ws.yaml b/esphome/circuit-setup/6chan_common_ethernet_ws.yaml new file mode 100644 index 0000000..af7c2e2 --- /dev/null +++ b/esphome/circuit-setup/6chan_common_ethernet_ws.yaml @@ -0,0 +1,67 @@ +# CircuitSetup 6 Channel Energy Meter ESPHome common variables +# using the Waveshare ESP32-S3-ETH and the CircuitSetup 6 Channel Energy Meter Ethernet WS Adapter + +esp32: + board: esp32-s3-devkitc-1 + variant: esp32s3 + flash_size: 16MB + cpu_frequency: 240MHz + framework: + type: esp-idf + +# Enable logging +logger: + hardware_uart: UART0 + level: DEBUG + +debug: + update_interval: 5s + +ethernet: + type: W5500 + clk_pin: 13 + mosi_pin: 11 + miso_pin: 12 + cs_pin: 14 + interrupt_pin: 10 + reset_pin: 9 + clock_speed: 30Mhz + +spi: + interface: software + clk_pin: 44 + miso_pin: 45 + mosi_pin: 43 + +sensor: + - platform: debug + free: + name: "Heap Free" + id: heap_free_sensor + entity_category: diagnostic + loop_time: + name: "Loop Time" + id: loop_time_sensor + entity_category: diagnostic + + - platform: uptime + name: Uptime + id: uptime_sensor + entity_category: diagnostic + +text_sensor: + - platform: debug + reset_reason: + name: "Reset Reason" + id: reset_reason_sensor + entity_category: diagnostic + +button: + - platform: restart + name: Restart + id: restart_button + entity_category: config + +time: + - platform: homeassistant + id: homeassistant_time diff --git a/esphome/circuit-setup/6chan_energy_meter_1-addon.yaml b/esphome/circuit-setup/6chan_energy_meter_1-addon.yaml new file mode 100644 index 0000000..d977edb --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_1-addon.yaml @@ -0,0 +1,220 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 1 Add-on Board config +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: "CircuitSetup Energy Meter 12x" +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.7.0' + project: + name: circuitsetup.6c-energy-meter-1-addon + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_1-addon.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_1-addon_ethernet.yaml b/esphome/circuit-setup/6chan_energy_meter_1-addon_ethernet.yaml new file mode 100644 index 0000000..3cabe04 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_1-addon_ethernet.yaml @@ -0,0 +1,217 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 1 Add-on Board config +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: "CircuitSetup Energy Meter 12x" +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + platformio_options: + board_build.flash_mode: dio + project: + name: circuitsetup.6c-energy-meter-1-addon-ethernet + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common_ethernet.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_1-addon_ethernet.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +# CS Pin mappings for Lilygo T-ETH-Lite ESP32S3 +- id: !extend ${main_meter_id1} + cs_pin: 8 +#- id: !extend ${main_meter_id2} +# cs_pin: 4 +#- id: !extend ${addon1_id1} +# cs_pin: 0 +#- id: !extend ${addon1_id2} +# cs_pin: 16 + +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_2-addons.yaml b/esphome/circuit-setup/6chan_energy_meter_2-addons.yaml new file mode 100644 index 0000000..4b2466d --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_2-addons.yaml @@ -0,0 +1,250 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 2 Add-on Boards config +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: "CircuitSetup Energy Meter 18x" +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.7.0' + project: + name: circuitsetup.6c-energy-meter-2-addons + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_2-addons.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_2-addons_ethernet.yaml b/esphome/circuit-setup/6chan_energy_meter_2-addons_ethernet.yaml new file mode 100644 index 0000000..c417201 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_2-addons_ethernet.yaml @@ -0,0 +1,250 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 2 Add-on Boards config +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: "CircuitSetup Energy Meter 18x" +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + platformio_options: + board_build.flash_mode: dio + project: + name: circuitsetup.6c-energy-meter-2-addons-ethernet + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common_ethernet.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_2-addons_ethernet.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +# CS Pin mappings for Lilygo T-ETH-Lite ESP32S3 +- id: !extend ${main_meter_id1} + cs_pin: 8 +#- id: !extend ${main_meter_id2} +# cs_pin: 4 +#- id: !extend ${addon1_id1} +# cs_pin: 0 +#- id: !extend ${addon1_id2} +# cs_pin: 16 +- id: !extend ${addon2_id1} + cs_pin: 18 +#- id: !extend ${addon2_id2} +# cs_pin: 17 + +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_3-addons.yaml b/esphome/circuit-setup/6chan_energy_meter_3-addons.yaml new file mode 100644 index 0000000..161f559 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_3-addons.yaml @@ -0,0 +1,276 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 3 Add-on Boards config +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: CircuitSetup Energy Meter 24x +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.7.0' + project: + name: circuitsetup.6c-energy-meter-3-addons + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_3-addons.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_3-addons_2-voltages.yaml b/esphome/circuit-setup/6chan_energy_meter_3-addons_2-voltages.yaml new file mode 100644 index 0000000..28a2c8f --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_3-addons_2-voltages.yaml @@ -0,0 +1,320 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 3 Add-on Boards config +# See all options at https://esphome.io/components/sensor/atm90e32.html +# +# Assumes 1st voltage is on main & add-on 1, 2nd voltage is on add-on 2 & 3 +# This is done by cutting the 2 bottom most pins, and attaching a 2nd +# voltage transformer to add-on 2 VA2 + + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: CircuitSetup Energy Meter 24x +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.7.0' + project: + name: circuitsetup.6c-energy-meter-3-addons-2-voltages + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1min + files: + - Software/ESPHome/6chan_common.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_3-addons_2-voltages.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +## Status field for 2nd voltage +text_sensor: + - platform: atm90e32 + id: ${addon2_id1} + frequency_status: + name: "Frequency Status 2" + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# + +## assigns voltage_cal according to how hardware is set up to accept 2 voltage transformers +# gain_voltage can be set independently if needed +- id: !extend ${main_meter_id2} + phase_a: + gain_voltage: ${voltage_cal1} + phase_b: + gain_voltage: ${voltage_cal1} + phase_c: + gain_voltage: ${voltage_cal1} + +- id: !extend ${addon1_id2} + phase_a: + gain_voltage: ${voltage_cal1} + phase_b: + gain_voltage: ${voltage_cal1} + phase_c: + gain_voltage: ${voltage_cal1} + +## adds Voltage 2 to addon 2 +- id: !extend ${addon2_id1} + phase_a: + voltage: + name: Voltage 2 + id: ic2Volts + accuracy_decimals: 1 + gain_voltage: ${voltage_cal2} + phase_b: + gain_voltage: ${voltage_cal2} + phase_c: + gain_voltage: ${voltage_cal2} + frequency: + name: Frequency 2 + +- id: !extend ${addon3_id1} + phase_a: + gain_voltage: ${voltage_cal2} + phase_b: + gain_voltage: ${voltage_cal2} + phase_c: + gain_voltage: ${voltage_cal2} + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing \ No newline at end of file diff --git a/esphome/circuit-setup/6chan_energy_meter_3-addons_ethernet.yaml b/esphome/circuit-setup/6chan_energy_meter_3-addons_ethernet.yaml new file mode 100644 index 0000000..bd51f6b --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_3-addons_ethernet.yaml @@ -0,0 +1,279 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 3 Add-on Boards config +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: "CircuitSetup Energy Meter 24x" +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + project: + name: circuitsetup.6c-energy-meter-3-addons-ethernet + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common_ethernet.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_3-addons_ethernet.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +# CS Pin mappings for Lilygo T-ETH-Lite ESP32S3 +- id: !extend ${main_meter_id1} + cs_pin: 8 +#- id: !extend ${main_meter_id2} +# cs_pin: 4 +#- id: !extend ${addon1_id1} +# cs_pin: 0 +#- id: !extend ${addon1_id2} +# cs_pin: 16 +- id: !extend ${addon2_id1} + cs_pin: 18 +#- id: !extend ${addon2_id2} +# cs_pin: 17 +#- id: !extend ${addon3_id1} +# cs_pin: 2 +#- id: !extend ${addon3_id2} +# cs_pin: 21 + +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_4-addons.yaml b/esphome/circuit-setup/6chan_energy_meter_4-addons.yaml new file mode 100644 index 0000000..3b73d97 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_4-addons.yaml @@ -0,0 +1,303 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 4 Add-on Boards config +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: CircuitSetup Energy Meter 30x +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 +## Addon4 + addon4_name1: Addon4 25-27 + addon4_name2: Addon4 28-30 + addon4_id1: addon4_1 + addon4_id2: addon4_2 + ct25_name: CT25 + ct26_name: CT26 + ct27_name: CT27 + ct28_name: CT28 + ct29_name: CT29 + ct30_name: CT30 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +## Addon4 + current_cal_ct25: '27518' + current_cal_ct26: '27518' + current_cal_ct27: '27518' + current_cal_ct28: '27518' + current_cal_ct29: '27518' + current_cal_ct30: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.7.0' + project: + name: circuitsetup.6c-energy-meter-4-addons + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + - Software/ESPHome/meter_sensors/6chan_addon4.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon4_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + #- Software/ESPHome/status_fields/6chan_addon4_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon4_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon4_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_4-addons.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true +- id: !extend totalAmpsAddOn4 + internal: true +- id: !extend totalWattsAddOn4 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state + id(totalAmpsAddOn4).state; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state + id(totalWattsAddOn4).state; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_4-addons_ethernet.yaml b/esphome/circuit-setup/6chan_energy_meter_4-addons_ethernet.yaml new file mode 100644 index 0000000..471e0a8 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_4-addons_ethernet.yaml @@ -0,0 +1,310 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 4 Add-on Boards config +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: CircuitSetup Energy Meter 30x +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 +## Addon4 + addon4_name1: Addon4 25-27 + addon4_name2: Addon4 28-30 + addon4_id1: addon4_1 + addon4_id2: addon4_2 + ct25_name: CT25 + ct26_name: CT26 + ct27_name: CT27 + ct28_name: CT28 + ct29_name: CT29 + ct30_name: CT30 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +## Addon4 + current_cal_ct25: '27518' + current_cal_ct26: '27518' + current_cal_ct27: '27518' + current_cal_ct28: '27518' + current_cal_ct29: '27518' + current_cal_ct30: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + project: + name: circuitsetup.6c-energy-meter-4-addons-ethernet + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common_ethernet.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + - Software/ESPHome/meter_sensors/6chan_addon4.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon4_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + #- Software/ESPHome/status_fields/6chan_addon4_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon4_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon4_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_4-addons_ethernet.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +# CS Pin mappings for Lilygo T-ETH-Lite ESP32S3 +- id: !extend ${main_meter_id1} + cs_pin: 8 +#- id: !extend ${main_meter_id2} +# cs_pin: 4 +#- id: !extend ${addon1_id1} +# cs_pin: 0 +#- id: !extend ${addon1_id2} +# cs_pin: 16 +- id: !extend ${addon2_id1} + cs_pin: 18 +#- id: !extend ${addon2_id2} +# cs_pin: 17 +#- id: !extend ${addon3_id1} +# cs_pin: 2 +#- id: !extend ${addon3_id2} +# cs_pin: 21 +- id: !extend ${addon4_id1} + cs_pin: 3 +- id: !extend ${addon4_id2} + cs_pin: 20 + +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true +- id: !extend totalAmpsAddOn4 + internal: true +- id: !extend totalWattsAddOn4 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state + id(totalAmpsAddOn4).state; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state + id(totalWattsAddOn4).state; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_5-addons.yaml b/esphome/circuit-setup/6chan_energy_meter_5-addons.yaml new file mode 100644 index 0000000..8ed2711 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_5-addons.yaml @@ -0,0 +1,330 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 5 Add-on Boards config +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: CircuitSetup Energy Meter 36x +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 +## Addon4 + addon4_name1: Addon4 25-27 + addon4_name2: Addon4 28-30 + addon4_id1: addon4_1 + addon4_id2: addon4_2 + ct25_name: CT25 + ct26_name: CT26 + ct27_name: CT27 + ct28_name: CT28 + ct29_name: CT29 + ct30_name: CT30 +## Addon5 + addon5_name1: Addon5 31-33 + addon5_name2: Addon5 34-36 + addon5_id1: addon5_1 + addon5_id2: addon5_2 + ct31_name: CT31 + ct32_name: CT32 + ct33_name: CT33 + ct34_name: CT34 + ct35_name: CT35 + ct36_name: CT36 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +## Addon4 + current_cal_ct25: '27518' + current_cal_ct26: '27518' + current_cal_ct27: '27518' + current_cal_ct28: '27518' + current_cal_ct29: '27518' + current_cal_ct30: '27518' +## Addon4 + current_cal_ct31: '27518' + current_cal_ct32: '27518' + current_cal_ct33: '27518' + current_cal_ct34: '27518' + current_cal_ct35: '27518' + current_cal_ct36: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.7.0' + project: + name: circuitsetup.6c-energy-meter-5-addons + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + - Software/ESPHome/meter_sensors/6chan_addon4.yaml + - Software/ESPHome/meter_sensors/6chan_addon5.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon4_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon5_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + #- Software/ESPHome/status_fields/6chan_addon4_status.yaml + #- Software/ESPHome/status_fields/6chan_addon5_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon4_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon5_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon4_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon5_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_5-addons.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true +- id: !extend totalAmpsAddOn4 + internal: true +- id: !extend totalWattsAddOn4 + internal: true +- id: !extend totalAmpsAddOn5 + internal: true +- id: !extend totalWattsAddOn5 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state + id(totalAmpsAddOn4).state + id(totalAmpsAddOn5).state; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state + id(totalWattsAddOn4).state + id(totalWattsAddOn5).state; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_5-addons_ethernet.yaml b/esphome/circuit-setup/6chan_energy_meter_5-addons_ethernet.yaml new file mode 100644 index 0000000..472797e --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_5-addons_ethernet.yaml @@ -0,0 +1,341 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 5 Add-on Boards config +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: CircuitSetup Energy Meter 36x +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 +## Addon4 + addon4_name1: Addon4 25-27 + addon4_name2: Addon4 28-30 + addon4_id1: addon4_1 + addon4_id2: addon4_2 + ct25_name: CT25 + ct26_name: CT26 + ct27_name: CT27 + ct28_name: CT28 + ct29_name: CT29 + ct30_name: CT30 +## Addon5 + addon5_name1: Addon5 31-33 + addon5_name2: Addon5 34-36 + addon5_id1: addon5_1 + addon5_id2: addon5_2 + ct31_name: CT31 + ct32_name: CT32 + ct33_name: CT33 + ct34_name: CT34 + ct35_name: CT35 + ct36_name: CT36 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +## Addon4 + current_cal_ct25: '27518' + current_cal_ct26: '27518' + current_cal_ct27: '27518' + current_cal_ct28: '27518' + current_cal_ct29: '27518' + current_cal_ct30: '27518' +## Addon4 + current_cal_ct31: '27518' + current_cal_ct32: '27518' + current_cal_ct33: '27518' + current_cal_ct34: '27518' + current_cal_ct35: '27518' + current_cal_ct36: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + project: + name: circuitsetup.6c-energy-meter-5-addons-ethernet + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common_ethernet.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + - Software/ESPHome/meter_sensors/6chan_addon4.yaml + - Software/ESPHome/meter_sensors/6chan_addon5.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon4_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon5_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + #- Software/ESPHome/status_fields/6chan_addon4_status.yaml + #- Software/ESPHome/status_fields/6chan_addon5_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon4_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon5_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon4_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon5_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_5-addons_ethernet.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +# CS Pin mappings for Lilygo T-ETH-Lite ESP32S3 +- id: !extend ${main_meter_id1} + cs_pin: 8 +#- id: !extend ${main_meter_id2} +# cs_pin: 4 +#- id: !extend ${addon1_id1} +# cs_pin: 0 +#- id: !extend ${addon1_id2} +# cs_pin: 16 +- id: !extend ${addon2_id1} + cs_pin: 18 +#- id: !extend ${addon2_id2} +# cs_pin: 17 +#- id: !extend ${addon3_id1} +# cs_pin: 2 +#- id: !extend ${addon3_id2} +# cs_pin: 21 +- id: !extend ${addon4_id1} + cs_pin: 3 +- id: !extend ${addon4_id2} + cs_pin: 20 +- id: !extend ${addon5_id1} + cs_pin: 41 +- id: !extend ${addon5_id2} + cs_pin: 39 + +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true +- id: !extend totalAmpsAddOn4 + internal: true +- id: !extend totalWattsAddOn4 + internal: true +- id: !extend totalAmpsAddOn5 + internal: true +- id: !extend totalWattsAddOn5 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state + id(totalAmpsAddOn4).state + id(totalAmpsAddOn5).state; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state + id(totalWattsAddOn4).state + id(totalWattsAddOn5).state; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_6-addons.yaml b/esphome/circuit-setup/6chan_energy_meter_6-addons.yaml new file mode 100644 index 0000000..4806fa1 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_6-addons.yaml @@ -0,0 +1,357 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 6 Add-on Boards config +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: CircuitSetup Energy Meter 42x +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 +## Addon4 + addon4_name1: Addon4 25-27 + addon4_name2: Addon4 28-30 + addon4_id1: addon4_1 + addon4_id2: addon4_2 + ct25_name: CT25 + ct26_name: CT26 + ct27_name: CT27 + ct28_name: CT28 + ct29_name: CT29 + ct30_name: CT30 +## Addon5 + addon5_name1: Addon5 31-33 + addon5_name2: Addon5 34-36 + addon5_id1: addon5_1 + addon5_id2: addon5_2 + ct31_name: CT31 + ct32_name: CT32 + ct33_name: CT33 + ct34_name: CT34 + ct35_name: CT35 + ct36_name: CT36 +## Addon6 + addon6_name1: Addon6 37-39 + addon6_name2: Addon6 40-42 + addon6_id1: addon6_1 + addon6_id2: addon6_2 + ct37_name: CT37 + ct38_name: CT38 + ct39_name: CT39 + ct40_name: CT40 + ct41_name: CT41 + ct42_name: CT42 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +## Addon4 + current_cal_ct25: '27518' + current_cal_ct26: '27518' + current_cal_ct27: '27518' + current_cal_ct28: '27518' + current_cal_ct29: '27518' + current_cal_ct30: '27518' +## Addon5 + current_cal_ct31: '27518' + current_cal_ct32: '27518' + current_cal_ct33: '27518' + current_cal_ct34: '27518' + current_cal_ct35: '27518' + current_cal_ct36: '27518' +## Addon6 + current_cal_ct37: '27518' + current_cal_ct38: '27518' + current_cal_ct39: '27518' + current_cal_ct40: '27518' + current_cal_ct41: '27518' + current_cal_ct42: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.7.0' + project: + name: circuitsetup.6c-energy-meter-6-addons + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + - Software/ESPHome/meter_sensors/6chan_addon4.yaml + - Software/ESPHome/meter_sensors/6chan_addon5.yaml + - Software/ESPHome/meter_sensors/6chan_addon6.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon4_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon5_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon6_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + #- Software/ESPHome/status_fields/6chan_addon4_status.yaml + #- Software/ESPHome/status_fields/6chan_addon5_status.yaml + #- Software/ESPHome/status_fields/6chan_addon6_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon4_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon5_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon6_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon4_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon5_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon6_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_6-addons.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true +- id: !extend totalAmpsAddOn4 + internal: true +- id: !extend totalWattsAddOn4 + internal: true +- id: !extend totalAmpsAddOn5 + internal: true +- id: !extend totalWattsAddOn5 + internal: true +- id: !extend totalAmpsAddOn6 + internal: true +- id: !extend totalWattsAddOn6 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state + id(totalAmpsAddOn4).state + id(totalAmpsAddOn5).state + id(totalAmpsAddOn6).state; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state + id(totalWattsAddOn4).state + id(totalWattsAddOn5).state + id(totalWattsAddOn6).state; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_6-addons_ethernet.yaml b/esphome/circuit-setup/6chan_energy_meter_6-addons_ethernet.yaml new file mode 100644 index 0000000..46b1962 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_6-addons_ethernet.yaml @@ -0,0 +1,372 @@ +# CircuitSetup 6 Channel Energy Meter Main Board + 6 Add-on Boards config +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: CircuitSetup Energy Meter 42x +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces +## Main board + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 +## Addon1 + addon1_name1: Addon1 7-9 + addon1_name2: Addon1 10-12 + addon1_id1: addon1_1 + addon1_id2: addon1_2 + ct7_name: CT7 + ct8_name: CT8 + ct9_name: CT9 + ct10_name: CT10 + ct11_name: CT11 + ct12_name: CT12 +## Addon2 + addon2_name1: Addon2 13-15 + addon2_name2: Addon2 16-18 + addon2_id1: addon2_1 + addon2_id2: addon2_2 + ct13_name: CT13 + ct14_name: CT14 + ct15_name: CT15 + ct16_name: CT16 + ct17_name: CT17 + ct18_name: CT18 +## Addon3 + addon3_name1: Addon3 19-21 + addon3_name2: Addon3 22-24 + addon3_id1: addon3_1 + addon3_id2: addon3_2 + ct19_name: CT19 + ct20_name: CT20 + ct21_name: CT21 + ct22_name: CT22 + ct23_name: CT23 + ct24_name: CT24 +## Addon4 + addon4_name1: Addon4 25-27 + addon4_name2: Addon4 28-30 + addon4_id1: addon4_1 + addon4_id2: addon4_2 + ct25_name: CT25 + ct26_name: CT26 + ct27_name: CT27 + ct28_name: CT28 + ct29_name: CT29 + ct30_name: CT30 +## Addon5 + addon5_name1: Addon5 31-33 + addon5_name2: Addon5 34-36 + addon5_id1: addon5_1 + addon5_id2: addon5_2 + ct31_name: CT31 + ct32_name: CT32 + ct33_name: CT33 + ct34_name: CT34 + ct35_name: CT35 + ct36_name: CT36 +## Addon6 + addon6_name1: Addon6 37-39 + addon6_name2: Addon6 40-42 + addon6_id1: addon6_1 + addon6_id2: addon6_2 + ct37_name: CT37 + ct38_name: CT38 + ct39_name: CT39 + ct40_name: CT40 + ct41_name: CT41 + ct42_name: CT42 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + +## Main Board + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +## Addon1 + current_cal_ct7: '27518' + current_cal_ct8: '27518' + current_cal_ct9: '27518' + current_cal_ct10: '27518' + current_cal_ct11: '27518' + current_cal_ct12: '27518' +## Addon2 + current_cal_ct13: '27518' + current_cal_ct14: '27518' + current_cal_ct15: '27518' + current_cal_ct16: '27518' + current_cal_ct17: '27518' + current_cal_ct18: '27518' +## Addon3 + current_cal_ct19: '27518' + current_cal_ct20: '27518' + current_cal_ct21: '27518' + current_cal_ct22: '27518' + current_cal_ct23: '27518' + current_cal_ct24: '27518' +## Addon4 + current_cal_ct25: '27518' + current_cal_ct26: '27518' + current_cal_ct27: '27518' + current_cal_ct28: '27518' + current_cal_ct29: '27518' + current_cal_ct30: '27518' +## Addon5 + current_cal_ct31: '27518' + current_cal_ct32: '27518' + current_cal_ct33: '27518' + current_cal_ct34: '27518' + current_cal_ct35: '27518' + current_cal_ct36: '27518' +## Addon6 + current_cal_ct37: '27518' + current_cal_ct38: '27518' + current_cal_ct39: '27518' + current_cal_ct40: '27518' + current_cal_ct41: '27518' + current_cal_ct42: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + project: + name: circuitsetup.6c-energy-meter-6-addons-ethernet + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common_ethernet.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + - Software/ESPHome/meter_sensors/6chan_addon1.yaml + - Software/ESPHome/meter_sensors/6chan_addon2.yaml + - Software/ESPHome/meter_sensors/6chan_addon3.yaml + - Software/ESPHome/meter_sensors/6chan_addon4.yaml + - Software/ESPHome/meter_sensors/6chan_addon5.yaml + - Software/ESPHome/meter_sensors/6chan_addon6.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon1_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon2_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon3_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon4_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon5_power_quality.yaml + #- Software/ESPHome/power_quality/6chan_addon6_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + #- Software/ESPHome/status_fields/6chan_addon1_status.yaml + #- Software/ESPHome/status_fields/6chan_addon2_status.yaml + #- Software/ESPHome/status_fields/6chan_addon3_status.yaml + #- Software/ESPHome/status_fields/6chan_addon4_status.yaml + #- Software/ESPHome/status_fields/6chan_addon5_status.yaml + #- Software/ESPHome/status_fields/6chan_addon6_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## Uncomment to enable + ## Details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon1_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon2_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon3_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon4_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon5_calibration.yaml + #- Software/ESPHome/calibration/6chan_addon6_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon1_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon2_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon3_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon4_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon5_offset_calibrations.yaml + #- Software/ESPHome/calibration/6chan_addon6_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_6-addons_ethernet.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +# CS Pin mappings for Lilygo T-ETH-Lite ESP32S3 +- id: !extend ${main_meter_id1} + cs_pin: 8 +#- id: !extend ${main_meter_id2} +# cs_pin: 4 +#- id: !extend ${addon1_id1} +# cs_pin: 0 +#- id: !extend ${addon1_id2} +# cs_pin: 16 +- id: !extend ${addon2_id1} + cs_pin: 18 +#- id: !extend ${addon2_id2} +# cs_pin: 17 +#- id: !extend ${addon3_id1} +# cs_pin: 2 +#- id: !extend ${addon3_id2} +# cs_pin: 21 +- id: !extend ${addon4_id1} + cs_pin: 3 +- id: !extend ${addon4_id2} + cs_pin: 20 +- id: !extend ${addon5_id1} + cs_pin: 41 +- id: !extend ${addon5_id2} + cs_pin: 39 +#- id: !extend ${addon6_id1} +# cs_pin: 15 +- id: !extend ${addon6_id2} + cs_pin: 38 + +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +## Comment out to show amps and watts per meter board in Home Assistant +- id: !extend totalAmpsMain + internal: true +- id: !extend totalWattsMain + internal: true +- id: !extend totalAmpsAddOn1 + internal: true +- id: !extend totalWattsAddOn1 + internal: true +- id: !extend totalAmpsAddOn2 + internal: true +- id: !extend totalWattsAddOn2 + internal: true +- id: !extend totalAmpsAddOn3 + internal: true +- id: !extend totalWattsAddOn3 + internal: true +- id: !extend totalAmpsAddOn4 + internal: true +- id: !extend totalWattsAddOn4 + internal: true +- id: !extend totalAmpsAddOn5 + internal: true +- id: !extend totalWattsAddOn5 + internal: true +- id: !extend totalAmpsAddOn6 + internal: true +- id: !extend totalWattsAddOn6 + internal: true + +#Total Amps +########### +- platform: template + name: ${friendly_name} Total Amps + id: totalAmps + lambda: return id(totalAmpsMain).state + id(totalAmpsAddOn1).state + id(totalAmpsAddOn2).state + id(totalAmpsAddOn3).state + id(totalAmpsAddOn4).state + id(totalAmpsAddOn5).state + id(totalAmpsAddOn6).state; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts +############ +- platform: template + name: ${friendly_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state + id(totalWattsAddOn4).state + id(totalWattsAddOn5).state + id(totalWattsAddOn6).state; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_main_board.yaml b/esphome/circuit-setup/6chan_energy_meter_main_board.yaml new file mode 100644 index 0000000..57c46c2 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_main_board.yaml @@ -0,0 +1,162 @@ +# CircuitSetup 6 Channel Energy Meter Main Board config +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: "CircuitSetup Energy Meter" +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: '60Hz' + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + project: + name: circuitsetup.6c-energy-meter + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_main_board.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWattsMain + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_main_ethernet.yaml b/esphome/circuit-setup/6chan_energy_meter_main_ethernet.yaml new file mode 100644 index 0000000..add1894 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_main_ethernet.yaml @@ -0,0 +1,155 @@ +# CircuitSetup 6 Channel Energy Meter Main Board config +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter + friendly_name: "CircuitSetup Energy Meter" +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: "${disp_name}" + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + platformio_options: + board_build.flash_mode: dio + project: + name: circuitsetup.6c-energy-meter-ethernet + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1d + files: + - Software/ESPHome/6chan_common_ethernet.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_main_ethernet.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +# CS Pin mappings for Lilygo T-ETH-Lite ESP32S3 +- id: !extend ${main_meter_id1} + cs_pin: 8 +#- id: !extend ${main_meter_id2} +# cs_pin: 4 + +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWattsMain + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/6chan_energy_meter_main_ethernet_ws.yaml b/esphome/circuit-setup/6chan_energy_meter_main_ethernet_ws.yaml new file mode 100644 index 0000000..cfd25c4 --- /dev/null +++ b/esphome/circuit-setup/6chan_energy_meter_main_ethernet_ws.yaml @@ -0,0 +1,155 @@ +# CircuitSetup 6 Channel Energy Meter Main Board config +# Uses the Waveshare ESP32-S3-ETH and the CircuitSetup 6 Channel Energy Meter Ethernet WS Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: energy-meter-eth-ws + friendly_name: "CircuitSetup Energy Meter" +# Interval of how often the power data is updated + update_time: 10s +# Frequency of your electrical grid - 60Hz in North America, 50Hz otherwise + electric_freq: "60Hz" + +## The below names and IDs can be changed to whatever you want. IDs should not have spaces + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 + +## Semi-Automatic Calibration ## +# See https://esphome.io/components/sensor/atm90e32.html#calibration +# WHEN CALIBRATION IS ENABLED, calculated values for offset and gain stored in memory take priority over config values +# To save calculated calibration values, copy them from the logs to your config +# then use the clear buttons to clear the calibration values from memory +# Values are stored in the variables for gain below and offsets in their corresponding files +# under /calibration/6chan_xxxx_offset_calibrations.yaml + offset_calibration: "true" + gain_calibration: "true" + +## Gain Calibration Values ## +# Change current_cal_ctX value to the corresponding CT's that you're using +# For more precise calibration, see documentation for Semi-Auto calibration +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + +esphome: + name: "${disp_name}" + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + platformio_options: + board_build.flash_mode: dio + project: + name: circuitsetup.6c-energy-meter-ethernet-ws + version: "1.7" + +packages: + remote_package: + url: https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter + ref: master + refresh: 1min + files: + - Software/ESPHome/6chan_common_ethernet_ws.yaml + - Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + + ## Additional power quality sensors per CT/Phase + ## Uncomment to enable + ## details: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + #- Software/ESPHome/power_quality/6chan_main_power_quality.yaml + + ## Enables text status fields for each CT/Phase + ## details: https://esphome.io/components/sensor/atm90e32.html#text-sensor + - Software/ESPHome/status_fields/6chan_main_status.yaml + + ## Adds semi-automatic calibration buttons and reference fields + ## If enabled, make sure offset & gain calibration are set to "true" above + ## details: https://esphome.io/components/sensor/atm90e32.html#calibration + - Software/ESPHome/calibration/6chan_main_calibration.yaml + + ## Additional offset calibration fields that should be copied per CT/Phase from the ESPHome logs + ## These do not need to be set unless you are seeing non-zero values when CTs or Voltage + ## should not be registering anything. + #- Software/ESPHome/calibration/6chan_main_offset_calibrations.yaml + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_energy_meter_main_ethernet_ws.yaml@master + import_full_config: true + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +# CS Pin mappings for Waveshare ESP32-S3-ETH +- id: !extend ${main_meter_id1} + cs_pin: 34 +- id: !extend ${main_meter_id2} + cs_pin: 40 + +## The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +## divide the current_cal_ctx (above) by 2 (120A CT) or 4 (200A CT) and multiply the current and power values +## by 2 or 4, uncommenting the below and changing the id and phase_x accordingly +#- id: !extend ${main_meter_id1} # CTs 1-3 +# phase_a: # CT1 +# current: +# filters: +# - multiply: 2 +# power: +# filters: +# - multiply: 2 +# +## uncomment if monitoring 2 voltages +#- id: !extend ${main_meter_id2} +# phase_a: +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 +# frequency: +# name: Frequency 2 + +#kWh +#### +- platform: total_daily_energy + name: ${friendly_name} Total kWh + power_id: totalWattsMain + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/README.md b/esphome/circuit-setup/README.md new file mode 100644 index 0000000..946c2f1 --- /dev/null +++ b/esphome/circuit-setup/README.md @@ -0,0 +1,153 @@ +# ESPHome Configuration for Expandable 6-Channel ESP32 Energy Meter + +This folder contains [ESPHome](https://esphome.io) configuration files used to monitor power and energy via the CircuitSetup Expandable 6-Channel Energy Meter. These configurations support flexible deployments - with or without add-on boards - as well as Wi-Fi or Ethernet connections. Many files use `!include` statements to modularize calibration, sensor definitions, power quality metrics, and device status. + +--- + +## 📁 Base Config Files + +| File | Description | +|------|-------------| +| `6chan_common.yaml` | Base shared configuration: sets platform (`esp32`), SPI, includes time and API components. Meant to be included in Wi-Fi-based setups. | +| `6chan_common_ethernet.yaml` | Same as `6chan_common.yaml`, but for the [Lilygo T-ETH-Lite ESP32S3](https://lilygo.cc/products/t-eth-lite) and the [CircuitSetup 6 Channel Energy Meter Ethernet Adapter](https://circuitsetup.us/product/6-channel-energy-meter-to-lilygo-t-eth-lite-esp32s3-ethernet-adapter/) . | +| `6chan_energy_meter_main_board.yaml` | Full configuration for monitoring only the main board's 6 channels via Wi-Fi. | +| `6chan_energy_meter_main_ethernet.yaml` | Ethernet-based variant of `6chan_energy_meter_main_board.yaml`. | +| `6chan_energy_meter_1-addon.yaml` | Main board + 1 add-on board (12 channels). | +| `6chan_energy_meter_2-addons.yaml` | Main board + 2 add-ons (18 channels). | +| `6chan_energy_meter_3-addons.yaml` | Main board + 3 add-ons (24 channels). | + +--- + +## 📂 calibration/ + +When these files are included, and calibration is enabled, semi-automatic calibration can be done for each current and voltage channel by providing a current and voltage reference. Calculated values for offset and gain stored in memory take priority over config values. +To save calculated calibration values, copy them from the ESPHome logs to your config then use the clear buttons to clear the calibration values from memory + +[See details on semi-automatic calibrations here](https://esphome.io/components/sensor/atm90e32.html#calibration) + +| File | Description | +|------|-------------| +| `6chan_xxxx_calibration.yaml` | Enables calibration buttons for gain, power offset, current/voltage offset, and clear buttons for each | +| `6chan_xxxx_offset_calibrations.yaml` | Offset calibration values fine tuned via the output of the semi-automatic calibrations. Values should be copied in from the meter's ESPHome log | + +--- + +## 📂 meter_sensors/ + +Default current, power (watts), and voltage sensor entities per meter board +[More details on each sensor here](https://esphome.io/components/sensor/atm90e32.html#configuration-variables) + +--- + +## 📂 status_fields/ + +These fields display the status of each CT, or phase, with a short text description. [See more details here](https://esphome.io/components/sensor/atm90e32.html#text-sensor) + +--- + +## 📂 power_quality/ + +Contains power quality values that are available for each phase, and can be enabled per meter board. Enabling these on every current channel is possible, but will produce a lot of data and sensors that are likely not needed. They include reactive_power, apparent_power, harmonic_power, power_factor, phase_angle, peak_current +[More details on each sensor here](https://esphome.io/components/sensor/atm90e32.html#configuration-variables) + +--- + +## 📂 examples/ + +Pre-configured use cases to jumpstart your setup. + +| File | Description | +|------|-------------| +| `6chan_energy_meter_3-phase_ethernet.yaml` | Configuration for 3-phase measurement with Ethernet. Uses main board + 1 add-on. | +| `6chan_energy_meter_6-addons_ethernet.yaml` | Max configuration: main board + 6 add-ons over Ethernet (42 channels). | +| `6chan_energy_meter_house_solar_ha_kwh.yaml` | Real-world example measuring house + solar circuits. | +| `6chan_main_calibration_beta.yaml` | Beta calibration test — for experimentation only, not recommended for production. | + +--- + +## Measuring More Than 65A on a Current Channel +The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, divide `current_cal_ctx` by 2 (120A CT) or 4 (200A CT) and multiply the current and power values by 2 or 4, uncommenting the below and changing the `id` and `phase_x` accordingly. + +Under `sensor:` add: +``` +- id: !extend ${main_meter_id1} # CTs 1-3 + phase_a: # CT1 + current: + filters: + - multiply: 2 + power: + filters: + - multiply: 2 +``` +--- + +## Monitoring More Than 1 Voltage +By default, all voltage channels are connected, and set up to monitor a single phase. [See here on what needs to be done with hardware if monitoring more than 1 voltage.](https://github.com/CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/tree/master?tab=readme-ov-file#measuring-a-second-voltage) + +In the config, under `sensor:` add: +``` +- id: !extend ${main_meter_id2} + phase_a: + voltage: + name: Voltage 2 + id: ic2Volts + accuracy_decimals: 1 + frequency: + name: Frequency 2 +``` +--- + +## Excluding/Removing Sensors +If you, for example, want to see power quality sensors on only 2 out of the 4 CT channels of the main board, you could add something like this in your base config file. This is assuming you are including `Software/ESPHome/power_quality/6chan_main_power_quality.yaml` and you want to exclude power quality sensors for the last 4 CTs: + +Under `sensor:` add: +``` +- id: !extend ${main_meter_id1} + phase_c: # CT3 + reactive_power: !remove + apparent_power: !remove + harmonic_power: !remove + power_factor: !remove + phase_angle: !remove + peak_current: !remove + +- id: !extend ${main_meter_id2} + phase_a: # CT4 + reactive_power: !remove + apparent_power: !remove + harmonic_power: !remove + power_factor: !remove + phase_angle: !remove + peak_current: !remove + phase_b: #CT5 + reactive_power: !remove + apparent_power: !remove + harmonic_power: !remove + power_factor: !remove + phase_angle: !remove + peak_current: !remove + phase_c: #CT6 + reactive_power: !remove + apparent_power: !remove + harmonic_power: !remove + power_factor: !remove + phase_angle: !remove + peak_current: !remove +``` +--- + +## Including Files Locally + +You can copy config files to your local directories and change the `packages:` part of your config to something like this: +``` +packages: + common: !include Software/ESPHome/6chan_common.yaml + main: !include Software/ESPHome/meter_sensors/6chan_main_sensor.yaml + main_status: !include Software/ESPHome/status_fields/6chan_main_status.yaml + main_cal: !include Software/ESPHome/calibration/6chan_main_calibration.yaml +``` +--- + +## Compiled Firmware + +[See here to flash your ESP32](https://circuitsetup.github.io/ESPWebInstaller/) diff --git a/esphome/circuit-setup/calibration/6chan_addon1_calibration.yaml b/esphome/circuit-setup/calibration/6chan_addon1_calibration.yaml new file mode 100644 index 0000000..9b44c70 --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon1_calibration.yaml @@ -0,0 +1,65 @@ +# Details: https://esphome.io/components/sensor/atm90e32.html#calibration +# Semi-automatic Calibration Buttons +#################################### +button: + - platform: atm90e32 + id: ${addon1_id1} + run_offset_calibration: + name: "1. Run ${addon1_name1} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon1_name1} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon1_name1} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon1_name1} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon1_name1} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon1_name1} Gain Cal" + + - platform: atm90e32 + id: ${addon1_id2} + run_offset_calibration: + name: "1. Run ${addon1_name2} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon1_name2} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon1_name2} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon1_name2} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon1_name2} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon1_name2} Gain Cal" + +# V & I Calibration Reference Fields +#################################### +# Use these to input a known value being measured by a CT or voltage transformer +number: + - platform: atm90e32 + id: ${addon1_id1} + reference_voltage: + # will copy to phase_b/c for calibration reference + phase_a: + name: "${addon1_name1} Ref V 1" + reference_current: + phase_a: + name: "${ct7_name} Ref Current" + phase_b: + name: "${ct8_name} Ref Current" + phase_c: + name: "${ct9_name} Ref Current" + + - platform: atm90e32 + id: ${addon1_id2} + reference_voltage: + # needed to calibrate voltage registers even if not output + phase_a: + name: "${addon1_name2} Ref V 2" + reference_current: + phase_a: + name: "${ct10_name} Ref Current" + phase_b: + name: "${ct11_name} Ref Current" + phase_c: + name: "${ct12_name} Ref Current" diff --git a/esphome/circuit-setup/calibration/6chan_addon1_offset_calibrations.yaml b/esphome/circuit-setup/calibration/6chan_addon1_offset_calibrations.yaml new file mode 100644 index 0000000..bd3c32b --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon1_offset_calibrations.yaml @@ -0,0 +1,39 @@ +# Offset calibration values fine tuned via the output of the semi-automatic calibrations +# Values should be copied in from the meter's ESPHome log +# See details on semi-automatic calibrations here: +# https://esphome.io/components/sensor/atm90e32.html#calibration + +sensor: +- id: !extend ${addon1_id1} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + +- id: !extend ${addon1_id2} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 diff --git a/esphome/circuit-setup/calibration/6chan_addon2_calibration.yaml b/esphome/circuit-setup/calibration/6chan_addon2_calibration.yaml new file mode 100644 index 0000000..b7af761 --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon2_calibration.yaml @@ -0,0 +1,65 @@ +# Details: https://esphome.io/components/sensor/atm90e32.html#calibration +# Semi-automatic Calibration Buttons +#################################### +button: + - platform: atm90e32 + id: ${addon2_id1} + run_offset_calibration: + name: "1. Run ${addon2_name1} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon2_name1} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon2_name1} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon2_name1} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon2_name1} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon2_name1} Gain Cal" + + - platform: atm90e32 + id: ${addon2_id2} + run_offset_calibration: + name: "1. Run ${addon2_name2} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon2_name2} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon2_name2} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon2_name2} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon2_name2} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon2_name2} Gain Cal" + +# V & I Calibration Reference Fields +#################################### +# Use these to input a known value being measured by a CT or voltage transformer +number: + - platform: atm90e32 + id: ${addon2_id1} + reference_voltage: + # will copy to phase_b/c for calibration reference + phase_a: + name: "${addon2_name1} Ref V 1" + reference_current: + phase_a: + name: "${ct13_name} Ref Current" + phase_b: + name: "${ct14_name} Ref Current" + phase_c: + name: "${ct15_name} Ref Current" + + - platform: atm90e32 + id: ${addon2_id2} + reference_voltage: + # needed to calibrate voltage registers even if not output + phase_a: + name: "${addon2_name2} Ref V 2" + reference_current: + phase_a: + name: "${ct16_name} Ref Current" + phase_b: + name: "${ct17_name} Ref Current" + phase_c: + name: "${ct18_name} Ref Current" diff --git a/esphome/circuit-setup/calibration/6chan_addon2_offset_calibrations.yaml b/esphome/circuit-setup/calibration/6chan_addon2_offset_calibrations.yaml new file mode 100644 index 0000000..98fb553 --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon2_offset_calibrations.yaml @@ -0,0 +1,39 @@ +# Offset calibration values fine tuned via the output of the semi-automatic calibrations +# Values should be copied in from the meter's ESPHome log +# See details on semi-automatic calibrations here: +# https://esphome.io/components/sensor/atm90e32.html#calibration + +sensor: +- id: !extend ${addon2_id1} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + +- id: !extend ${addon2_id2} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 diff --git a/esphome/circuit-setup/calibration/6chan_addon3_calibration.yaml b/esphome/circuit-setup/calibration/6chan_addon3_calibration.yaml new file mode 100644 index 0000000..52b297b --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon3_calibration.yaml @@ -0,0 +1,65 @@ +# Details: https://esphome.io/components/sensor/atm90e32.html#calibration +# Semi-automatic Calibration Buttons +#################################### +button: + - platform: atm90e32 + id: ${addon3_id1} + run_offset_calibration: + name: "1. Run ${addon3_name1} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon3_name1} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon3_name1} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon3_name1} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon3_name1} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon3_name1} Gain Cal" + + - platform: atm90e32 + id: ${addon3_id2} + run_offset_calibration: + name: "1. Run ${addon3_name2} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon3_name2} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon3_name2} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon3_name2} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon3_name2} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon3_name2} Gain Cal" + +# V & I Calibration Reference Fields +#################################### +# Use these to input a known value being measured by a CT or voltage transformer +number: + - platform: atm90e32 + id: ${addon3_id1} + reference_voltage: + # will copy to phase_b/c for calibration reference + phase_a: + name: "${addon3_name1} Ref V 1" + reference_current: + phase_a: + name: "${ct19_name} Ref Current" + phase_b: + name: "${ct20_name} Ref Current" + phase_c: + name: "${ct21_name} Ref Current" + + - platform: atm90e32 + id: ${addon3_id2} + reference_voltage: + # needed to calibrate voltage registers even if not output + phase_a: + name: "${addon3_name2} Ref V 2" + reference_current: + phase_a: + name: "${ct22_name} Ref Current" + phase_b: + name: "${ct23_name} Ref Current" + phase_c: + name: "${ct24_name} Ref Current" diff --git a/esphome/circuit-setup/calibration/6chan_addon3_offset_calibrations.yaml b/esphome/circuit-setup/calibration/6chan_addon3_offset_calibrations.yaml new file mode 100644 index 0000000..e337f60 --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon3_offset_calibrations.yaml @@ -0,0 +1,39 @@ +# Offset calibration values fine tuned via the output of the semi-automatic calibrations +# Values should be copied in from the meter's ESPHome log +# See details on semi-automatic calibrations here: +# https://esphome.io/components/sensor/atm90e32.html#calibration + +sensor: +- id: !extend ${addon3_id1} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + +- id: !extend ${addon3_id2} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 diff --git a/esphome/circuit-setup/calibration/6chan_addon4_calibration.yaml b/esphome/circuit-setup/calibration/6chan_addon4_calibration.yaml new file mode 100644 index 0000000..1fa6547 --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon4_calibration.yaml @@ -0,0 +1,65 @@ +# Details: https://esphome.io/components/sensor/atm90e32.html#calibration +# Semi-automatic Calibration Buttons +#################################### +button: + - platform: atm90e32 + id: ${addon4_id1} + run_offset_calibration: + name: "1. Run ${addon4_name1} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon4_name1} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon4_name1} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon4_name1} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon4_name1} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon4_name1} Gain Cal" + + - platform: atm90e32 + id: ${addon4_id2} + run_offset_calibration: + name: "1. Run ${addon4_name2} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon4_name2} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon4_name2} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon4_name2} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon4_name2} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon4_name2} Gain Cal" + +# V & I Calibration Reference Fields +#################################### +# Use these to input a known value being measured by a CT or voltage transformer +number: + - platform: atm90e32 + id: ${addon4_id1} + reference_voltage: + # will copy to phase_b/c for calibration reference + phase_a: + name: "${addon4_name1} Ref V 1" + reference_current: + phase_a: + name: "${ct25_name} Ref Current" + phase_b: + name: "${ct26_name} Ref Current" + phase_c: + name: "${ct27_name} Ref Current" + + - platform: atm90e32 + id: ${addon4_id2} + reference_voltage: + # needed to calibrate voltage registers even if not output + phase_a: + name: "${addon4_name2} Ref V 2" + reference_current: + phase_a: + name: "${ct28_name} Ref Current" + phase_b: + name: "${ct29_name} Ref Current" + phase_c: + name: "${ct30_name} Ref Current" diff --git a/esphome/circuit-setup/calibration/6chan_addon4_offset_calibrations.yaml b/esphome/circuit-setup/calibration/6chan_addon4_offset_calibrations.yaml new file mode 100644 index 0000000..e15f7ef --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon4_offset_calibrations.yaml @@ -0,0 +1,39 @@ +# Offset calibration values fine tuned via the output of the semi-automatic calibrations +# Values should be copied in from the meter's ESPHome log +# See details on semi-automatic calibrations here: +# https://esphome.io/components/sensor/atm90e32.html#calibration + +sensor: +- id: !extend ${addon4_id1} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + +- id: !extend ${addon4_id2} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 diff --git a/esphome/circuit-setup/calibration/6chan_addon5_calibration.yaml b/esphome/circuit-setup/calibration/6chan_addon5_calibration.yaml new file mode 100644 index 0000000..ae869af --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon5_calibration.yaml @@ -0,0 +1,65 @@ +# Details: https://esphome.io/components/sensor/atm90e32.html#calibration +# Semi-automatic Calibration Buttons +#################################### +button: + - platform: atm90e32 + id: ${addon5_id1} + run_offset_calibration: + name: "1. Run ${addon5_name1} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon5_name1} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon5_name1} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon5_name1} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon5_name1} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon5_name1} Gain Cal" + + - platform: atm90e32 + id: ${addon5_id2} + run_offset_calibration: + name: "1. Run ${addon5_name2} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon5_name2} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon5_name2} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon5_name2} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon5_name2} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon5_name2} Gain Cal" + +# V & I Calibration Reference Fields +#################################### +# Use these to input a known value being measured by a CT or voltage transformer +number: + - platform: atm90e32 + id: ${addon5_id1} + reference_voltage: + # will copy to phase_b/c for calibration reference + phase_a: + name: "${addon5_name1} Ref V 1" + reference_current: + phase_a: + name: "${ct31_name} Ref Current" + phase_b: + name: "${ct32_name} Ref Current" + phase_c: + name: "${ct33_name} Ref Current" + + - platform: atm90e32 + id: ${addon5_id2} + reference_voltage: + # needed to calibrate voltage registers even if not output + phase_a: + name: "${addon5_name2} Ref V 2" + reference_current: + phase_a: + name: "${ct34_name} Ref Current" + phase_b: + name: "${ct35_name} Ref Current" + phase_c: + name: "${ct36_name} Ref Current" diff --git a/esphome/circuit-setup/calibration/6chan_addon5_offset_calibrations.yaml b/esphome/circuit-setup/calibration/6chan_addon5_offset_calibrations.yaml new file mode 100644 index 0000000..b81912d --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon5_offset_calibrations.yaml @@ -0,0 +1,39 @@ +# Offset calibration values fine tuned via the output of the semi-automatic calibrations +# Values should be copied in from the meter's ESPHome log +# See details on semi-automatic calibrations here: +# https://esphome.io/components/sensor/atm90e32.html#calibration + +sensor: +- id: !extend ${addon5_id1} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + +- id: !extend ${addon5_id2} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 diff --git a/esphome/circuit-setup/calibration/6chan_addon6_calibration.yaml b/esphome/circuit-setup/calibration/6chan_addon6_calibration.yaml new file mode 100644 index 0000000..5b13fd8 --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon6_calibration.yaml @@ -0,0 +1,65 @@ +# Details: https://esphome.io/components/sensor/atm90e32.html#calibration +# Semi-automatic Calibration Buttons +#################################### +button: + - platform: atm90e32 + id: ${addon6_id1} + run_offset_calibration: + name: "1. Run ${addon6_name1} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon6_name1} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon6_name1} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon6_name1} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon6_name1} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon6_name1} Gain Cal" + + - platform: atm90e32 + id: ${addon6_id2} + run_offset_calibration: + name: "1. Run ${addon6_name2} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${addon6_name2} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${addon6_name2} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${addon6_name2} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${addon6_name2} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${addon6_name2} Gain Cal" + +# V & I Calibration Reference Fields +#################################### +# Use these to input a known value being measured by a CT or voltage transformer +number: + - platform: atm90e32 + id: ${addon6_id1} + reference_voltage: + # will copy to phase_b/c for calibration reference + phase_a: + name: "${addon6_name1} Ref V 1" + reference_current: + phase_a: + name: "${ct37_name} Ref Current" + phase_b: + name: "${ct38_name} Ref Current" + phase_c: + name: "${ct39_name} Ref Current" + + - platform: atm90e32 + id: ${addon6_id2} + reference_voltage: + # needed to calibrate voltage registers even if not output + phase_a: + name: "${addon6_name2} Ref V 2" + reference_current: + phase_a: + name: "${ct40_name} Ref Current" + phase_b: + name: "${ct41_name} Ref Current" + phase_c: + name: "${ct42_name} Ref Current" diff --git a/esphome/circuit-setup/calibration/6chan_addon6_offset_calibrations.yaml b/esphome/circuit-setup/calibration/6chan_addon6_offset_calibrations.yaml new file mode 100644 index 0000000..6b9f309 --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_addon6_offset_calibrations.yaml @@ -0,0 +1,39 @@ +# Offset calibration values fine tuned via the output of the semi-automatic calibrations +# Values should be copied in from the meter's ESPHome log +# See details on semi-automatic calibrations here: +# https://esphome.io/components/sensor/atm90e32.html#calibration + +sensor: +- id: !extend ${addon6_id1} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + +- id: !extend ${addon6_id2} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 diff --git a/esphome/circuit-setup/calibration/6chan_main_calibration.yaml b/esphome/circuit-setup/calibration/6chan_main_calibration.yaml new file mode 100644 index 0000000..8525f12 --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_main_calibration.yaml @@ -0,0 +1,65 @@ +# Details: https://esphome.io/components/sensor/atm90e32.html#calibration +# Main Board Semi-automatic Calibration Buttons +############################################### +button: + - platform: atm90e32 + id: ${main_meter_id1} + run_offset_calibration: + name: "1. Run ${main_meter_name1} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${main_meter_name1} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${main_meter_name1} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${main_meter_name1} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${main_meter_name1} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${main_meter_name1} Gain Cal" + + - platform: atm90e32 + id: ${main_meter_id2} + run_offset_calibration: + name: "1. Run ${main_meter_name2} Offset Cal" + clear_offset_calibration: + name: "z1. Clear ${main_meter_name2} Offset Cal" + run_power_offset_calibration: + name: "2. Run ${main_meter_name2} Power Offset Cal" + clear_power_offset_calibration: + name: "z2. Clear ${main_meter_name2} Power Offset Cal" + run_gain_calibration: + name: "3. Run ${main_meter_name2} Gain Cal" + clear_gain_calibration: + name: "z3. Clear ${main_meter_name2} Gain Cal" + +# Main Board V & I Calibration Reference Fields +############################################### +# Use these to input a known value being measured by a CT or voltage transformer +number: + - platform: atm90e32 + id: ${main_meter_id1} + reference_voltage: + # will copy to phase_b/c for calibration reference + phase_a: + name: "${main_meter_name1} Ref V 1" + reference_current: + phase_a: + name: "${ct1_name} Ref Current" + phase_b: + name: "${ct2_name} Ref Current" + phase_c: + name: "${ct3_name} Ref Current" + + - platform: atm90e32 + id: ${main_meter_id2} + reference_voltage: + # needed to calibrate voltage registers even if not output + phase_a: + name: "${main_meter_name2} Ref V 2" + reference_current: + phase_a: + name: "${ct4_name} Ref Current" + phase_b: + name: "${ct5_name} Ref Current" + phase_c: + name: "${ct6_name} Ref Current" diff --git a/esphome/circuit-setup/calibration/6chan_main_offset_calibrations.yaml b/esphome/circuit-setup/calibration/6chan_main_offset_calibrations.yaml new file mode 100644 index 0000000..0c72d2e --- /dev/null +++ b/esphome/circuit-setup/calibration/6chan_main_offset_calibrations.yaml @@ -0,0 +1,39 @@ +# Offset calibration values fine tuned via the output of the semi-automatic calibrations +# Values should be copied in from the meter's ESPHome log +# See details on semi-automatic calibrations here: +# https://esphome.io/components/sensor/atm90e32.html#calibration + +sensor: +- id: !extend ${main_meter_id1} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + +- id: !extend ${main_meter_id2} + phase_a: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 diff --git a/esphome/circuit-setup/examples/6chan_energy_meter_3-phase_ethernet.yaml b/esphome/circuit-setup/examples/6chan_energy_meter_3-phase_ethernet.yaml new file mode 100644 index 0000000..4ed8d70 --- /dev/null +++ b/esphome/circuit-setup/examples/6chan_energy_meter_3-phase_ethernet.yaml @@ -0,0 +1,223 @@ +# CircuitSetup 6 Channel Energy Meter Main Board with 1 add-on board, 3-Phase over ethernet - 12 current channels +# +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter. +# Setup asumes JP12 and JP13 have been severed on the main and add-on board, and each phase has its +# own voltage transformer hooked up to the main board jack, and VA2 on each meter. +# +# Current Trasnformers must be in phase with their respective voltage: +# Phase 1: CT1-CT6 (main board, add-on board left side) +# Phase 2: CT7-CT9 (main board right) +# Phase 3: CT10-CT12 (add-on board right) + +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: Energy Meter + friendly_name: CircuitSetup Energy Meter +# Interval of how often the power data is updated + update_time: 10s + +# Change current_cal to the corresponding CT's that you're using +# If different CTs per current channel, remove or change "${current_cal}" from +# "gain_ct" below and replace with the CT calibration number respectively +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + current_cal: '27518' + +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal: '7305' + +esphome: + name: "${disp_name}" + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + platformio_options: + board_build.flash_mode: dio + project: + name: circuitsetup.6c-energy-meter-ethernet + version: "1.6" + +packages: + common: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_common_ethernet.yaml + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +sensor: +#IC1 Main + - platform: atm90e32 + cs_pin: 8 + phase_a: + voltage: + name: ${disp_name} Volts Phase 1 + id: voltsPhase1 + accuracy_decimals: 1 + power: + name: ${disp_name} CT1 Watts + id: ct1Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT2 Watts + id: ct2Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT3 Watts + id: ct3Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + frequency: + name: ${disp_name} Freq Phase 1 + line_frequency: 50Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 Main + - platform: atm90e32 + cs_pin: 4 + phase_a: + voltage: + name: ${disp_name} Volts Phase 2 + id: voltsPhase2 + accuracy_decimals: 1 + power: + name: ${disp_name} CT7 Watts + id: ct7Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT8 Watts + id: ct8Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT9 Watts + id: ct9Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 50Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 1 + - platform: atm90e32 + cs_pin: 0 + phase_a: + power: + name: ${disp_name} CT4 Watts + id: ct4Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT5 Watts + id: ct5Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT6 Watts + id: ct6Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 50Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 1 + - platform: atm90e32 + cs_pin: 16 + phase_a: + voltage: + name: ${disp_name} Volts Phase 3 + id: voltsPhase3 + accuracy_decimals: 1 + power: + name: ${disp_name} CT10 Watts + id: ct10Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT11 Watts + id: ct11Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT12 Watts + id: ct12Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 50Hz + gain_pga: 1X + update_interval: ${update_time} + +#Total Watts Phase 1 + - platform: template + name: ${disp_name} Total Watts Phase 1 + id: totalWattsPhase1 + lambda: return id(ct1Watts).state + id(ct2Watts).state + id(ct3Watts).state + id(ct4Watts).state + id(ct5Watts).state + id(ct6Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts Phase 2 + - platform: template + name: ${disp_name} Total Watts Phase 2 + id: totalWattsPhase2 + lambda: return id(ct7Watts).state + id(ct8Watts).state + id(ct9Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts Phase 3 + - platform: template + name: ${disp_name} Total Watts Phase 3 + id: totalWattsPhase3 + lambda: return id(ct10Watts).state + id(ct11Watts).state + id(ct12Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts + - platform: template + name: ${disp_name} Total Watts + id: totalWatts + lambda: return id(totalWattsPhase1).state + id(totalWattsPhase2).state + id(totalWattsPhase3).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#kWh + - platform: total_daily_energy + name: ${disp_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/examples/6chan_energy_meter_6-addons_42-channels.yaml b/esphome/circuit-setup/examples/6chan_energy_meter_6-addons_42-channels.yaml new file mode 100644 index 0000000..0ae13b0 --- /dev/null +++ b/esphome/circuit-setup/examples/6chan_energy_meter_6-addons_42-channels.yaml @@ -0,0 +1,459 @@ +# CircuitSetup 6 Channel Energy Meter Main Board with 6 add-on boards - 42 current channels +# To reduce the number of sensors, only the power sensor for each current channel is output. +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: Energy Meter + friendly_name: CircuitSetup Energy Meter +# Interval of how often the power data is updated + update_time: 10s + +# Change current_cal to the corresponding CT's that you're using +# If different CTs per current channel, remove or change "${current_cal}" from +# "gain_ct" below and replace with the CT calibration number respectively +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + current_cal: '11143' # 20A/25mA + +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal: '7305' + +packages: + common: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_common.yaml + +sensor: +#IC1 Main + - platform: atm90e32 + cs_pin: 5 + phase_a: + voltage: + name: ${disp_name} Volts A Main + id: ic1Volts + accuracy_decimals: 1 + power: + name: ${disp_name} CT1 Watts + id: ct1Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT2 Watts + id: ct2Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT3 Watts + id: ct3Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + frequency: + name: ${disp_name} Freq A Main + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 Main + - platform: atm90e32 + cs_pin: 4 + phase_a: + power: + name: ${disp_name} CT4 Watts + id: ct4Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT5 Watts + id: ct5Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT6 Watts + id: ct6Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 1 + - platform: atm90e32 + cs_pin: 0 + phase_a: + power: + name: ${disp_name} CT7 Watts + id: ct7Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT8 Watts + id: ct8Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT9 Watts + id: ct9Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 1 + - platform: atm90e32 + cs_pin: 16 + phase_a: + power: + name: ${disp_name} CT10 Watts + id: ct10Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT11 Watts + id: ct11Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT12 Watts + id: ct12Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 2 + - platform: atm90e32 + cs_pin: 27 + phase_a: + power: + name: ${disp_name} CT13 Watts + id: ct13Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT14 Watts + id: ct14Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT15 Watts + id: ct15Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 2 + - platform: atm90e32 + cs_pin: 17 + phase_a: + power: + name: ${disp_name} CT16 Watts + id: ct16Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT17 Watts + id: ct17Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT18 Watts + id: ct18Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 3 + - platform: atm90e32 +#do not use GPIO2 if ESP32 has an on-board LED assigned to it + cs_pin: 2 + phase_a: + power: + name: ${disp_name} CT19 Watts + id: ct19Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT20 Watts + id: ct20Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT21 Watts + id: ct21Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 3 + - platform: atm90e32 + cs_pin: 21 + phase_a: + power: + name: ${disp_name} CT22 Watts + id: ct22Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT23 Watts + id: ct23Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT24 Watts + id: ct24Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 4 + - platform: atm90e32 + cs_pin: 13 + phase_a: + power: + name: ${disp_name} CT25 Watts + id: ct25Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT26 Watts + id: ct26Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT27 Watts + id: ct27Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 4 + - platform: atm90e32 + cs_pin: 22 + phase_a: + power: + name: ${disp_name} CT28 Watts + id: ct28Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT29 Watts + id: ct29Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT30 Watts + id: ct30Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 5 + - platform: atm90e32 + cs_pin: 14 + phase_a: + power: + name: ${disp_name} CT31 Watts + id: ct31Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT32 Watts + id: ct32Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT33 Watts + id: ct33Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 5 + - platform: atm90e32 + cs_pin: 25 + phase_a: + power: + name: ${disp_name} CT34 Watts + id: ct34Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT35 Watts + id: ct35Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT36 Watts + id: ct36Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 6 + - platform: atm90e32 + cs_pin: 15 + phase_a: + power: + name: ${disp_name} CT37 Watts + id: ct37Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT38 Watts + id: ct38Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT39 Watts + id: ct39Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 6 + - platform: atm90e32 + cs_pin: 26 + phase_a: + power: + name: ${disp_name} CT40 Watts + id: ct40Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT41 Watts + id: ct41Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT42 Watts + id: ct42Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + +#Total Watts Main + - platform: template + name: ${disp_name} Total Watts Main + id: totalWattsMain + lambda: return id(ct1Watts).state + id(ct2Watts).state + id(ct3Watts).state + id(ct4Watts).state + id(ct5Watts).state + id(ct6Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn1 + - platform: template + name: ${disp_name} Total Watts Add-on1 + id: totalWattsAddOn1 + lambda: return id(ct7Watts).state + id(ct8Watts).state + id(ct9Watts).state + id(ct10Watts).state + id(ct11Watts).state + id(ct12Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn2 + - platform: template + name: ${disp_name} Total Watts Add-on2 + id: totalWattsAddOn2 + lambda: return id(ct13Watts).state + id(ct14Watts).state + id(ct15Watts).state + id(ct16Watts).state + id(ct17Watts).state + id(ct18Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn3 + - platform: template + name: ${disp_name} Total Watts Add-on3 + id: totalWattsAddOn3 + lambda: return id(ct19Watts).state + id(ct20Watts).state + id(ct21Watts).state + id(ct22Watts).state + id(ct23Watts).state + id(ct24Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn4 + - platform: template + name: ${disp_name} Total Watts Add-on4 + id: totalWattsAddOn4 + lambda: return id(ct25Watts).state + id(ct26Watts).state + id(ct27Watts).state + id(ct28Watts).state + id(ct29Watts).state + id(ct30Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn5 + - platform: template + name: ${disp_name} Total Watts Add-on5 + id: totalWattsAddOn5 + lambda: return id(ct31Watts).state + id(ct32Watts).state + id(ct33Watts).state + id(ct34Watts).state + id(ct35Watts).state + id(ct36Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn6 + - platform: template + name: ${disp_name} Total Watts Add-on6 + id: totalWattsAddOn6 + lambda: return id(ct37Watts).state + id(ct38Watts).state + id(ct39Watts).state + id(ct40Watts).state + id(ct41Watts).state + id(ct42Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts + - platform: template + name: ${disp_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state + id(totalWattsAddOn4).state + id(totalWattsAddOn5).state + id(totalWattsAddOn6).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#kWh + - platform: total_daily_energy + name: ${disp_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/examples/6chan_energy_meter_6-addons_ethernet.yaml b/esphome/circuit-setup/examples/6chan_energy_meter_6-addons_ethernet.yaml new file mode 100644 index 0000000..4eaa32d --- /dev/null +++ b/esphome/circuit-setup/examples/6chan_energy_meter_6-addons_ethernet.yaml @@ -0,0 +1,481 @@ +# CircuitSetup 6 Channel Energy Meter Main Board with 6 add-on boards over ethernet - 42 current channels +# +# To reduce the number of sensors, only the power sensor for each current channel is output. +# +# Uses the Lilygo T-ETH-Lite ESP32S3 and the CircuitSetup 6 Channel Energy Meter Ethernet Adapter +# See all options at https://esphome.io/components/sensor/atm90e32.html +# +# CS pins for the ESP32-S3 are different, and must be changed if previously using a WiFi ESP32: +#Main board: +# 5 -> 8 +# 4 -> 4 (stays the same) +#Add-on boards: +#CS (CT1-3): +# 0 -> 0 +# 27 -> 18 +# 2 -> 2 +# 13 -> 3 +# 14 -> 41 +# 15 -> 15 +#CS2 (CT3-6): +# 16 -> 16 +# 17 -> 17 +# 21 -> 21 +# 22 -> 20 +# 25 -> 39 +# 26 -> 38 + +substitutions: +# Change the disp_name to something you want + disp_name: Energy Meter + friendly_name: CircuitSetup Energy Meter +# Interval of how often the power data is updated + update_time: 10s + +# Change current_cal to the corresponding CT's that you're using +# If different CTs per current channel, remove or change "${current_cal}" from +# "gain_ct" below and replace with the CT calibration number respectively +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + current_cal: '11143' # 20A/25mA + +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal: '7305' + +packages: + common: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_common_ethernet.yaml + +sensor: +#IC1 Main + - platform: atm90e32 + cs_pin: 8 + phase_a: + voltage: + name: ${disp_name} Volts A Main + id: ic1Volts + accuracy_decimals: 1 + power: + name: ${disp_name} CT1 Watts + id: ct1Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT2 Watts + id: ct2Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT3 Watts + id: ct3Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + frequency: + name: ${disp_name} Freq A Main + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 Main + - platform: atm90e32 + cs_pin: 4 + phase_a: + power: + name: ${disp_name} CT4 Watts + id: ct4Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT5 Watts + id: ct5Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT6 Watts + id: ct6Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 1 + - platform: atm90e32 + cs_pin: 0 + phase_a: + power: + name: ${disp_name} CT7 Watts + id: ct7Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT8 Watts + id: ct8Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT9 Watts + id: ct9Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 1 + - platform: atm90e32 + cs_pin: 16 + phase_a: + power: + name: ${disp_name} CT10 Watts + id: ct10Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT11 Watts + id: ct11Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT12 Watts + id: ct12Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 2 + - platform: atm90e32 + cs_pin: 18 + phase_a: + power: + name: ${disp_name} CT13 Watts + id: ct13Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT14 Watts + id: ct14Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT15 Watts + id: ct15Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 2 + - platform: atm90e32 + cs_pin: 17 + phase_a: + power: + name: ${disp_name} CT16 Watts + id: ct16Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT17 Watts + id: ct17Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT18 Watts + id: ct18Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 3 + - platform: atm90e32 + cs_pin: 2 + phase_a: + power: + name: ${disp_name} CT19 Watts + id: ct19Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT20 Watts + id: ct20Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT21 Watts + id: ct21Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 3 + - platform: atm90e32 + cs_pin: 21 + phase_a: + power: + name: ${disp_name} CT22 Watts + id: ct22Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT23 Watts + id: ct23Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT24 Watts + id: ct24Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 4 + - platform: atm90e32 + cs_pin: 3 + phase_a: + power: + name: ${disp_name} CT25 Watts + id: ct25Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT26 Watts + id: ct26Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT27 Watts + id: ct27Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 4 + - platform: atm90e32 + cs_pin: 20 + phase_a: + power: + name: ${disp_name} CT28 Watts + id: ct28Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT29 Watts + id: ct29Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT30 Watts + id: ct30Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 5 + - platform: atm90e32 + cs_pin: 41 + phase_a: + power: + name: ${disp_name} CT31 Watts + id: ct31Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT32 Watts + id: ct32Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT33 Watts + id: ct33Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 5 + - platform: atm90e32 + cs_pin: 39 + phase_a: + power: + name: ${disp_name} CT34 Watts + id: ct34Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT35 Watts + id: ct35Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT36 Watts + id: ct36Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC1 AddOn 6 + - platform: atm90e32 + cs_pin: 15 + phase_a: + power: + name: ${disp_name} CT37 Watts + id: ct37Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT38 Watts + id: ct38Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT39 Watts + id: ct39Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 AddOn 6 + - platform: atm90e32 + cs_pin: 38 + phase_a: + power: + name: ${disp_name} CT40 Watts + id: ct40Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + power: + name: ${disp_name} CT41 Watts + id: ct41Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_c: + power: + name: ${disp_name} CT42 Watts + id: ct42Watts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + +#Total Watts Main + - platform: template + name: ${disp_name} Total Watts Main + id: totalWattsMain + lambda: return id(ct1Watts).state + id(ct2Watts).state + id(ct3Watts).state + id(ct4Watts).state + id(ct5Watts).state + id(ct6Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn1 + - platform: template + name: ${disp_name} Total Watts Add-on1 + id: totalWattsAddOn1 + lambda: return id(ct7Watts).state + id(ct8Watts).state + id(ct9Watts).state + id(ct10Watts).state + id(ct11Watts).state + id(ct12Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn2 + - platform: template + name: ${disp_name} Total Watts Add-on2 + id: totalWattsAddOn2 + lambda: return id(ct13Watts).state + id(ct14Watts).state + id(ct15Watts).state + id(ct16Watts).state + id(ct17Watts).state + id(ct18Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn3 + - platform: template + name: ${disp_name} Total Watts Add-on3 + id: totalWattsAddOn3 + lambda: return id(ct19Watts).state + id(ct20Watts).state + id(ct21Watts).state + id(ct22Watts).state + id(ct23Watts).state + id(ct24Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn4 + - platform: template + name: ${disp_name} Total Watts Add-on4 + id: totalWattsAddOn4 + lambda: return id(ct25Watts).state + id(ct26Watts).state + id(ct27Watts).state + id(ct28Watts).state + id(ct29Watts).state + id(ct30Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn5 + - platform: template + name: ${disp_name} Total Watts Add-on5 + id: totalWattsAddOn5 + lambda: return id(ct31Watts).state + id(ct32Watts).state + id(ct33Watts).state + id(ct34Watts).state + id(ct35Watts).state + id(ct36Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts AddOn6 + - platform: template + name: ${disp_name} Total Watts Add-on6 + id: totalWattsAddOn6 + lambda: return id(ct37Watts).state + id(ct38Watts).state + id(ct39Watts).state + id(ct40Watts).state + id(ct41Watts).state + id(ct42Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Watts + - platform: template + name: ${disp_name} Total Watts + id: totalWatts + lambda: return id(totalWattsMain).state + id(totalWattsAddOn1).state + id(totalWattsAddOn2).state + id(totalWattsAddOn3).state + id(totalWattsAddOn4).state + id(totalWattsAddOn5).state + id(totalWattsAddOn6).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#kWh + - platform: total_daily_energy + name: ${disp_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/examples/6chan_energy_meter_house_solar_ha_kwh.yaml b/esphome/circuit-setup/examples/6chan_energy_meter_house_solar_ha_kwh.yaml new file mode 100644 index 0000000..a2578f2 --- /dev/null +++ b/esphome/circuit-setup/examples/6chan_energy_meter_house_solar_ha_kwh.yaml @@ -0,0 +1,272 @@ +# 6 Channel Example Config for Split Single Phase whole house, solar, and 2 other circuits +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: Energy Meter + friendly_name: CircuitSetup Energy Meter +# Interval of how often the power data is updated + update_time: 10s + +# Change current_cal to the corresponding CT's that you're using +# If different CTs per current channel, remove or change "${current_cal}" from +# "gain_ct" below and replace with the CT calibration number respectively +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + house_current_cal: '27518' + solar_current_cal: '27518' + current_cal: '27518' + +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal: '7305' + +esphome: + name: ${disp_name} + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + project: + name: circuitsetup.6c-energy-meter + version: "1.6" + +packages: + common: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_common.yaml + +# Enable Home Assistant API +# An encryption key is recommended and can be generated here: +# https://esphome.io/components/api.html#configuration-variables +api: +# encryption: +# key: "YOUR_ENCRYPTION_KEY_HERE" + +# Enable OTA updating +ota: + - platform: esphome + +# Set up a wifi access point +wifi: + ap: + +# In combination with the `ap` this allows +# provisioning wifi credentials to the device. +captive_portal: + +# Sets up Bluetooth LE to provision wifi credentials +# to the device. +esp32_improv: + authorizer: none + +# Sets up the improv via serial client for wifi provisioning +improv_serial: + +web_server: + port: 80 + +sensor: +#IC1 + - platform: atm90e32 + cs_pin: 5 + #CT1 + phase_a: + voltage: + name: ${disp_name} Volts + id: HouseL1Volts + accuracy_decimals: 1 + current: + name: ${disp_name} House L1 Amps + id: HouseL1Amps + power: + name: ${disp_name} House L1 Watts + id: HouseL1Watts + gain_voltage: ${voltage_cal} + gain_ct: ${house_current_cal} + #CT2 + phase_b: + current: + name: ${disp_name} Solar L1 Amps + id: SolarL1Amps + power: + name: ${disp_name} Solar L1 Watts + id: SolarL1Watts + gain_voltage: ${voltage_cal} + gain_ct: ${solar_current_cal} + #CT3 + phase_c: + current: + name: ${disp_name} Hot Water Amps + id: HotWaterAmps + power: + name: ${disp_name} Hot Water Watts + id: HotWaterWatts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + frequency: + name: ${disp_name} Freq + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 + - platform: atm90e32 + cs_pin: 4 + #CT4 + phase_a: + current: + name: ${disp_name} Dryer Amps + id: DryerAmps + power: + name: ${disp_name} Dryer Watts + id: DryerWatts + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + #CT5 + phase_b: + current: + name: ${disp_name} Solar L2 Amps + id: SolarL2Amps + power: + name: ${disp_name} CT5 Watts + id: SolarL2Watts + gain_voltage: ${voltage_cal} + gain_ct: ${solar_current_cal} + #CT6 + phase_c: + current: + name: ${disp_name} House L2 Amps + id: HouseL2Amps + power: + name: ${disp_name} House L2 Watts + id: HouseL2Watts + gain_voltage: ${voltage_cal} + gain_ct: ${house_current_cal} + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + +#Total House Amps + - platform: template + name: ${disp_name} Total House Amps + id: totalHouseAmps + lambda: return id(HouseL1Amps).state + id(HouseL2Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total House Watts + - platform: template + name: ${disp_name} Total House Watts + id: totalHouseWatts + lambda: return id(HouseL1Watts).state + id(HouseL2Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#Total House Watts Negative + - platform: template + name: ${disp_name} Total House Return To Grid Watts + id: returnToGridWatts + lambda: |- + if (id(totalHouseWatts).state > 0) { + return 0; + } else { + return abs(id(totalHouseWatts).state) ; + } + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#House Negative kWh (HA Return to Grid) + - platform: total_daily_energy + name: ${disp_name} House Return To Grid kWh + power_id: returnToGridWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + + #Total House Watts Positive + - platform: template + name: ${disp_name} Total House Positive Watts + id: totalHousePositiveWatts + lambda: |- + if (id(totalHouseWatts).state < 0) { + return 0; + } else { + return id(totalHouseWatts).state ; + } + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#House positive kWh + - platform: total_daily_energy + name: ${disp_name} House kWh + power_id: totalHousePositiveWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + +#Total Solar Amps + - platform: template + name: ${disp_name} Total Solar Amps + id: totalSolarAmps + lambda: return id(SolarL1Amps).state + id(SolarL2Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Solar Watts + - platform: template + name: ${disp_name} Total Solar Watts + id: totalSolarWatts + lambda: return id(SolarL1Watts).state + id(SolarL2Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + +#Solar kWh + - platform: total_daily_energy + name: ${disp_name} Solar kWh + power_id: totalSolarWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + +#Individual Hot Water kWh + - platform: total_daily_energy + name: ${disp_name} Hot Water kWh + power_id: HotWaterWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + +#Individual Dryer kWh + - platform: total_daily_energy + name: ${disp_name} Dryer kWh + power_id: DryerWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing diff --git a/esphome/circuit-setup/examples/6chan_energy_meter_v1.2.yaml b/esphome/circuit-setup/examples/6chan_energy_meter_v1.2.yaml new file mode 100644 index 0000000..0ee83b6 --- /dev/null +++ b/esphome/circuit-setup/examples/6chan_energy_meter_v1.2.yaml @@ -0,0 +1,205 @@ +substitutions: +# Change the disp_name to something you want + disp_name: 6C +# Interval of how often the power is updated + update_time: 10s +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + current_cal: '27518' +# Jameco 9VAC Transformer: 42620 + voltage_cal: '42620' + +esphome: + name: 6chan_energy_meter + platform: ESP32 + board: nodemcu-32s + +wifi: + ssid: !secret wifi_ssid + password: !secret wifi_pass + manual_ip: + static_ip: !secret ip_eh_nrgnode + gateway: !secret ip_gateway + subnet: !secret ip_subnet + dns1: !secret ip_dns1 + +# mqtt: +# broker: !secret mqtt_broker +# username: !secret mqtt_user +# password: !secret mqtt_pass + +# Enable logging +logger: + +# Enable Home Assistant API +api: + +ota: + +web_server: + port: 80 + +spi: + clk_pin: 18 + miso_pin: 19 + mosi_pin: 23 + +sensor: + - platform: wifi_signal + name: ${disp_name} WiFi + update_interval: 60s +#IC1 + - platform: atm90e32 + cs_pin: 5 + phase_a: + voltage: + name: ${disp_name} Volts A + id: ic1Volts + accuracy_decimals: 1 +# filters: +# - multiply: 2.0 + current: + name: ${disp_name} CT1 Amps + id: ct1Amps +# The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +# divide the gain_ct by 2 (120A CT) or 4 (200A CT) and multiply the current value by 2 or 4 by uncommenting the filter below +# filters: +# - multiply: 2.0 + gain_voltage: ${voltage_cal} +# Voltage using a 9VAC power transformer +# Note: If you can not get the voltage correct with the highest gain of 65535, uncomment the 2.0 multiply filter above and lower the gain as needed + gain_ct: ${current_cal} + phase_b: + current: + name: ${disp_name} CT2 Amps + id: ct2Amps + gain_ct: ${current_cal} + phase_c: + current: + name: ${disp_name} CT3 Amps + id: ct3Amps + gain_ct: ${current_cal} + frequency: + name: ${disp_name} Freq A + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} +#IC2 + - platform: atm90e32 + cs_pin: 4 + phase_a: + voltage: + name: ${disp_name} Volts B + id: ic2Volts + accuracy_decimals: 1 + current: + name: ${disp_name} CT4 Amps + id: ct4Amps + gain_voltage: ${voltage_cal} + gain_ct: ${current_cal} + phase_b: + current: + name: ${disp_name} CT5 Amps + id: ct5Amps + gain_ct: ${current_cal} + phase_c: + current: + name: ${disp_name} CT6 Amps + id: ct6Amps + gain_ct: ${current_cal} + frequency: + name: ${disp_name} Freq B + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + +#Watts per channel + - platform: template + name: ${disp_name} CT1 Watts + id: ct1Watts + lambda: return id(ct1Amps).state * id(ic1Volts).state; + accuracy_decimals: 0 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + - platform: template + name: ${disp_name} CT2 Watts + id: ct2Watts + lambda: return id(ct2Amps).state * id(ic1Volts).state; + accuracy_decimals: 0 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + - platform: template + name: ${disp_name} CT3 Watts + id: ct3Watts + lambda: return id(ct3Amps).state * id(ic1Volts).state; + accuracy_decimals: 0 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + - platform: template + name: ${disp_name} CT4 Watts + id: ct4Watts + lambda: return id(ct4Amps).state * id(ic2Volts).state; + accuracy_decimals: 0 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + - platform: template + name: ${disp_name} CT5 Watts + id: ct5Watts + lambda: return id(ct5Amps).state * id(ic2Volts).state; + accuracy_decimals: 0 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} + - platform: template + name: ${disp_name} CT6 Watts + id: ct6Watts + lambda: return id(ct6Amps).state * id(ic2Volts).state; + accuracy_decimals: 0 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#Total Amps + - platform: template + name: ${disp_name} Total Amps + id: totalAmps + lambda: return id(ct1Amps).state + id(ct2Amps).state + id(ct3Amps).state + id(ct4Amps).state + id(ct5Amps).state + id(ct6Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} +#Total Watts + - platform: template + name: ${disp_name} Total Watts + id: totalWatts + lambda: return id(totalAmps).state * id(ic1Volts).state; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#kWh + - platform: total_daily_energy + name: ${disp_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing +switch: + - platform: restart + name: ${disp_name} Restart +time: + - platform: sntp + id: sntp_time diff --git a/esphome/circuit-setup/examples/6chan_main_calibration_beta.yaml b/esphome/circuit-setup/examples/6chan_main_calibration_beta.yaml new file mode 100644 index 0000000..5f239bb --- /dev/null +++ b/esphome/circuit-setup/examples/6chan_main_calibration_beta.yaml @@ -0,0 +1,420 @@ +# CircuitSetup 6 Channel Energy Meter Main Board example config +# See all options at https://esphome.io/components/sensor/atm90e32.html + +substitutions: +# Change the disp_name to something you want + disp_name: Energy-Meter + friendly_name: CircuitSetup Energy Meter Wifi +# Interval of how often the power data is updated + update_time: 60s + +# Change current_cal to the corresponding CT's that you're using +# If different CTs per current channel, remove or change "${current_cal}" from +# "gain_ct" below and replace with the CT calibration number respectively +# Current Transformers: +# 20A/25mA SCT-006: 11143 +# 30A/1V SCT-013-030: 8650 +# 50A/1V SCT-013-050: 15420 +# 50A/16.6mA SCT-010: 41334 +# 80A/26.6mA SCT-010: 41660 +# 100A/50ma SCT-013-000: 27518 +# 120A/40mA: SCT-016: 41787 +# 200A/100mA SCT-024: 27518 +# 200A/50mA SCT-024: 55036 + current_cal_ct1: '27518' + current_cal_ct2: '27518' + current_cal_ct3: '27518' + current_cal_ct4: '27518' + current_cal_ct5: '27518' + current_cal_ct6: '27518' +# This only needs to be changed if you're using something other than the +# Jameco 9VAC Transformer: + voltage_cal1: '7305' + voltage_cal2: '7305' + + main_meter_name1: Meter 1-3 + main_meter_name2: Meter 4-6 + main_meter_id1: meter_main1 + main_meter_id2: meter_main2 + ct1_name: CT1 + ct2_name: CT2 + ct3_name: CT3 + ct4_name: CT4 + ct5_name: CT5 + ct6_name: CT6 + +#packages: +# common: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_common.yaml +esphome: + name: energy-meter + friendly_name: "${friendly_name}" + name_add_mac_suffix: true + min_version: '2025.5.0' + project: + name: circuitsetup.6c-energy-meter + version: "1.5" + +esp32: + board: nodemcu-32s + +captive_portal: + +improv_serial: + +logger: + level: DEBUG + +# Enable OTA updating +ota: + - platform: esphome + +web_server: + port: 80 + +spi: + interface: software + clk_pin: 18 + miso_pin: 19 + mosi_pin: 23 + +time: + - platform: homeassistant + id: homeassistant_time + +dashboard_import: + package_import_url: github://CircuitSetup/Expandable-6-Channel-ESP32-Energy-Meter/Software/ESPHome/6chan_main_calibration_beta.yaml + import_full_config: false + +api: + +wifi: + # Set up a wifi access point + ap: + +sensor: +#IC1 + - platform: atm90e32 + cs_pin: 5 + id: ${main_meter_id1} + phase_a: + voltage: + name: Voltage 1 + id: ic1Volts + accuracy_decimals: 1 + current: + name: ${ct1_name} Amps + id: ct1Amps +# The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +# divide the gain_ct by 2 (120A CT) or 4 (200A CT) and multiply the current and power values by 2 or 4 by uncommenting the filter below +# filters: +# - multiply: 2 + power: + name: ${ct1_name} Watts + id: ct1Watts +# filters: +# - multiply: 2 + reactive_power: + name: ${ct1_name} VAR + apparent_power: + name: ${ct1_name} VA + harmonic_power: + name: ${ct1_name} Harmonic Power + power_factor: + name: ${ct1_name} PF + phase_angle: + name: ${ct1_name} Phase Angle + peak_current: + name: ${ct1_name} Peak Current + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct1} + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + current: + name: ${ct2_name} Amps + id: ct2Amps + power: + name: ${ct2_name} Watts + id: ct2Watts + reactive_power: + name: ${ct2_name} VAR + apparent_power: + name: ${ct2_name} VA + harmonic_power: + name: ${ct2_name} Harmonic Power + power_factor: + name: ${ct2_name} PF + phase_angle: + name: ${ct2_name} Phase Angle + peak_current: + name: ${ct2_name} Peak Current + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct2} + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + current: + name: ${ct3_name} Amps + id: ct3Amps + power: + name: ${ct3_name} Watts + id: ct3Watts + reactive_power: + name: ${ct3_name} VAR + apparent_power: + name: ${ct3_name} VA + harmonic_power: + name: ${ct3_name} Harmonic Power + power_factor: + name: ${ct3_name} PF + phase_angle: + name: ${ct3_name} Phase Angle + peak_current: + name: ${ct3_name} Peak Current + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct3} + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + frequency: + name: Frequency 1 + chip_temperature: + name: ${main_meter_name1} Chip Temp + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: true + enable_gain_calibration: true +#IC2 + - platform: atm90e32 + cs_pin: 4 + id: ${main_meter_id2} + phase_a: +#this voltage is only needed if monitoring 2 voltages +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 + current: + name: ${ct4_name} Amps + id: ct4Amps + power: + name: ${ct4_name} Watts + id: ct4Watts + reactive_power: + name: ${ct4_name} VAR + apparent_power: + name: ${ct4_name} VA + harmonic_power: + name: ${ct4_name} Harmonic Power + power_factor: + name: ${ct4_name} PF + phase_angle: + name: ${ct4_name} Phase Angle + peak_current: + name: ${ct4_name} Peak Current + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct4} + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_b: + current: + name: ${ct5_name} Amps + id: ct5Amps + power: + name: ${ct5_name} Watts + id: ct5Watts + reactive_power: + name: ${ct5_name} VAR + apparent_power: + name: ${ct5_name} VA + harmonic_power: + name: ${ct5_name} Harmonic Power + power_factor: + name: ${ct5_name} PF + phase_angle: + name: ${ct5_name} Phase Angle + peak_current: + name: ${ct5_name} Peak Current + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct5} + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 + phase_c: + current: + name: ${ct6_name} Amps + id: ct6Amps + power: + name: ${ct6_name} Watts + id: ct6Watts + reactive_power: + name: ${ct6_name} VAR + apparent_power: + name: ${ct6_name} VA + harmonic_power: + name: ${ct6_name} Harmonic Power + power_factor: + name: ${ct6_name} PF + phase_angle: + name: ${ct6_name} Phase Angle + peak_current: + name: ${ct6_name} Peak Current + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct6} + offset_voltage: 0 + offset_current: 0 + offset_active_power: 0 + offset_reactive_power: 0 +#this is only needed if monitoring 2 voltages +# frequency: +# name: Frequency 2 + chip_temperature: + name: ${main_meter_name2} Chip Temp + line_frequency: 60Hz + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: true + enable_gain_calibration: true + +#Total Amps + - platform: template + name: ${disp_name} Total Amps + id: totalAmps + lambda: return id(ct1Amps).state + id(ct2Amps).state + id(ct3Amps).state + id(ct4Amps).state + id(ct5Amps).state + id(ct6Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} +#Total Watts + - platform: template + name: ${disp_name} Total Watts + id: totalWatts + lambda: return id(ct1Watts).state + id(ct2Watts).state + id(ct3Watts).state + id(ct4Watts).state + id(ct5Watts).state + id(ct6Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} +#kWh + - platform: total_daily_energy + name: ${disp_name} Total kWh + power_id: totalWatts + filters: + - multiply: 0.001 + unit_of_measurement: kWh + device_class: energy + state_class: total_increasing + +#wifi diagnostic + - platform: wifi_signal + name: ${disp_name} WiFi + id: wifi_signal_db + entity_category: diagnostic + + - platform: copy + source_id: wifi_signal_db + id: wifi_signal_pct + name: ${disp_name} WiFi % + filters: + - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0); + unit_of_measurement: "%" + entity_category: diagnostic + +switch: + - platform: restart + name: ${disp_name} Restart + entity_category: diagnostic + +text_sensor: + - platform: atm90e32 + id: ${main_meter_id1} + phase_status: + phase_a: + name: "${ct1_name} Status" + phase_b: + name: "${ct2_name} Status" + phase_c: + name: "${ct3_name} Status" + frequency_status: + name: "Frequency Status 1" + + - platform: atm90e32 + id: ${main_meter_id2} + phase_status: + phase_a: + name: "${ct4_name} Status" + phase_b: + name: "${ct5_name} Status" + phase_c: + name: "${ct6_name} Status" +#this is only needed if monitoring 2 voltages +# freq_status: +# name: "Frequency Status 2" + +button: + - platform: atm90e32 + id: ${main_meter_id1} + run_gain_calibration: + name: "Run ${main_meter_name1} Gain Calibration" + clear_gain_calibration: + name: "Clear ${main_meter_name1} Gain Calibration" + run_offset_calibration: + name: "Run ${main_meter_name1} Offset Calibration" + clear_offset_calibration: + name: "Clear ${main_meter_name1} Offset Calibration" + run_power_offset_calibration: + name: "Run ${main_meter_name1} Power Offset Calibration" + clear_power_offset_calibration: + name: "Clear ${main_meter_name1} Power Offset Calibration" + + - platform: atm90e32 + id: ${main_meter_id2} + run_gain_calibration: + name: "Run ${main_meter_name2} Gain Calibration" + clear_gain_calibration: + name: "Clear ${main_meter_name2} Gain Calibration" + run_offset_calibration: + name: "Run ${main_meter_name2} Offset Calibration" + clear_offset_calibration: + name: "Clear ${main_meter_name2} Offset Calibration" + run_power_offset_calibration: + name: "Run ${main_meter_name2} Power Offset Calibration" + clear_power_offset_calibration: + name: "Clear ${main_meter_name2} Power Offset Calibration" + +number: + - platform: atm90e32 + id: ${main_meter_id1} + reference_voltage: + # will copy to phase_b/c for calibration reference + phase_a: + name: "Ref Voltage 1" + reference_current: + phase_a: + name: "${ct1_name} Ref Current" + phase_b: + name: "${ct2_name} Ref Current" + phase_c: + name: "${ct3_name} Ref Current" + + - platform: atm90e32 + id: ${main_meter_id2} + reference_voltage: + # needed to calibrate voltage registers even if not output + phase_a: + name: "Ref Voltage 2" + reference_current: + phase_a: + name: "${ct4_name} Ref Current" + phase_b: + name: "${ct5_name} Ref Current" + phase_c: + name: "${ct6_name} Ref Current" diff --git a/esphome/circuit-setup/meter_sensors/6chan_addon1.yaml b/esphome/circuit-setup/meter_sensors/6chan_addon1.yaml new file mode 100644 index 0000000..6523e41 --- /dev/null +++ b/esphome/circuit-setup/meter_sensors/6chan_addon1.yaml @@ -0,0 +1,100 @@ +# CircuitSetup 6 Channel Energy Meter 1st Add-on board config +# Assumes jumpers are both in the 1st position + +sensor: +#IC1 AddOn 1 +############ + - platform: atm90e32 + release_device: true + cs_pin: 0 + id: ${addon1_id1} + phase_a: + current: + name: ${ct7_name} Amps + id: ct7Amps + power: + name: ${ct7_name} Watts + id: ct7Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct7} + phase_b: + current: + name: ${ct8_name} Amps + id: ct8Amps + power: + name: ${ct8_name} Watts + id: ct8Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct8} + phase_c: + current: + name: ${ct9_name} Amps + id: ct9Amps + power: + name: ${ct9_name} Watts + id: ct9Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct9} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} +#IC2 AddOn 1 +############ + - platform: atm90e32 + release_device: true + cs_pin: 16 + id: ${addon1_id2} + phase_a: + current: + name: ${ct10_name} Amps + id: ct10Amps + power: + name: ${ct10_name} Watts + id: ct10Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct10} + phase_b: + current: + name: ${ct11_name} Amps + id: ct11Amps + power: + name: ${ct11_name} Watts + id: ct11Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct11} + phase_c: + current: + name: ${ct12_name} Amps + id: ct12Amps + power: + name: ${ct12_name} Watts + id: ct12Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct12} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} + +#Total Amps AddOn1 + - platform: template + name: ${friendly_name} Total Amps Add-on1 + id: totalAmpsAddOn1 + lambda: return id(ct7Amps).state + id(ct8Amps).state + id(ct9Amps).state + id(ct10Amps).state + id(ct11Amps).state + id(ct12Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts AddOn1 + - platform: template + name: ${friendly_name} Total Watts Add-on1 + id: totalWattsAddOn1 + lambda: return id(ct7Watts).state + id(ct8Watts).state + id(ct9Watts).state + id(ct10Watts).state + id(ct11Watts).state + id(ct12Watts).state ; + accuracy_decimals: 2 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} diff --git a/esphome/circuit-setup/meter_sensors/6chan_addon2.yaml b/esphome/circuit-setup/meter_sensors/6chan_addon2.yaml new file mode 100644 index 0000000..6c50c4b --- /dev/null +++ b/esphome/circuit-setup/meter_sensors/6chan_addon2.yaml @@ -0,0 +1,100 @@ +# CircuitSetup 6 Channel Energy Meter 2nd Add-on board config +# Assumes jumpers are both in the 2nd position + +sensor: +#IC1 AddOn 2 +############ + - platform: atm90e32 + cs_pin: 27 + release_device: true + id: ${addon2_id1} + phase_a: + current: + name: ${ct13_name} Amps + id: ct13Amps + power: + name: ${ct13_name} Watts + id: ct13Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct13} + phase_b: + current: + name: ${ct14_name} Amps + id: ct14Amps + power: + name: ${ct14_name} Watts + id: ct14Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct14} + phase_c: + current: + name: ${ct15_name} Amps + id: ct15Amps + power: + name: ${ct15_name} Watts + id: ct15Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct15} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} +#IC2 AddOn 2 +############ + - platform: atm90e32 + release_device: true + cs_pin: 17 + id: ${addon2_id2} + phase_a: + current: + name: ${ct16_name} Amps + id: ct16Amps + power: + name: ${ct16_name} Watts + id: ct16Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct16} + phase_b: + current: + name: ${ct17_name} Amps + id: ct17Amps + power: + name: ${ct17_name} Watts + id: ct17Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct17} + phase_c: + current: + name: ${ct18_name} Amps + id: ct18Amps + power: + name: ${ct18_name} Watts + id: ct18Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct18} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} + +#Total Amps AddOn2 + - platform: template + name: ${friendly_name} Total Amps Add-on2 + id: totalAmpsAddOn2 + lambda: return id(ct13Amps).state + id(ct14Amps).state + id(ct15Amps).state + id(ct16Amps).state + id(ct17Amps).state + id(ct18Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts AddOn2 + - platform: template + name: ${friendly_name} Total Watts Add-on2 + id: totalWattsAddOn2 + lambda: return id(ct13Watts).state + id(ct14Watts).state + id(ct15Watts).state + id(ct16Watts).state + id(ct17Watts).state + id(ct18Watts).state ; + accuracy_decimals: 2 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} diff --git a/esphome/circuit-setup/meter_sensors/6chan_addon3.yaml b/esphome/circuit-setup/meter_sensors/6chan_addon3.yaml new file mode 100644 index 0000000..f69d18b --- /dev/null +++ b/esphome/circuit-setup/meter_sensors/6chan_addon3.yaml @@ -0,0 +1,101 @@ +# CircuitSetup 6 Channel Energy Meter 3rd Add-on board config +# Assumes jumpers are both in the 3rd position + +sensor: +#IC1 AddOn 3 +############ + - platform: atm90e32 + release_device: true + #if ESP32 has an LED for GPIO2, remove jumper or ESP32 from meter stack before programming via serial + cs_pin: 2 + id: ${addon3_id1} + phase_a: + current: + name: ${ct19_name} Amps + id: ct19Amps + power: + name: ${ct19_name} Watts + id: ct19Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct19} + phase_b: + current: + name: ${ct20_name} Amps + id: ct20Amps + power: + name: ${ct20_name} Watts + id: ct20Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct20} + phase_c: + current: + name: ${ct21_name} Amps + id: ct21Amps + power: + name: ${ct21_name} Watts + id: ct21Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct21} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} +#IC2 AddOn 3 +############ + - platform: atm90e32 + release_device: true + cs_pin: 21 + id: ${addon3_id2} + phase_a: + current: + name: ${ct22_name} Amps + id: ct22Amps + power: + name: ${ct22_name} Watts + id: ct22Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct22} + phase_b: + current: + name: ${ct23_name} Amps + id: ct23Amps + power: + name: ${ct23_name} Watts + id: ct23Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct23} + phase_c: + current: + name: ${ct24_name} Amps + id: ct24Amps + power: + name: ${ct24_name} Watts + id: ct24Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct24} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} + +#Total Amps AddOn3 + - platform: template + name: ${friendly_name} Total Amps Add-on3 + id: totalAmpsAddOn3 + lambda: return id(ct19Amps).state + id(ct20Amps).state + id(ct21Amps).state + id(ct22Amps).state + id(ct23Amps).state + id(ct24Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts AddOn3 + - platform: template + name: ${friendly_name} Total Watts Add-on3 + id: totalWattsAddOn3 + lambda: return id(ct19Watts).state + id(ct20Watts).state + id(ct21Watts).state + id(ct22Watts).state + id(ct23Watts).state + id(ct24Watts).state ; + accuracy_decimals: 2 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} diff --git a/esphome/circuit-setup/meter_sensors/6chan_addon4.yaml b/esphome/circuit-setup/meter_sensors/6chan_addon4.yaml new file mode 100644 index 0000000..a47af86 --- /dev/null +++ b/esphome/circuit-setup/meter_sensors/6chan_addon4.yaml @@ -0,0 +1,100 @@ +# CircuitSetup 6 Channel Energy Meter 4th Add-on board config +# Assumes jumpers are both in the 4th position + +sensor: +#IC1 AddOn 4 +############ + - platform: atm90e32 + release_device: true + cs_pin: 13 + id: ${addon4_id1} + phase_a: + current: + name: ${ct25_name} Amps + id: ct25Amps + power: + name: ${ct25_name} Watts + id: ct25Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct25} + phase_b: + current: + name: ${ct26_name} Amps + id: ct26Amps + power: + name: ${ct26_name} Watts + id: ct26Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct26} + phase_c: + current: + name: ${ct27_name} Amps + id: ct27Amps + power: + name: ${ct27_name} Watts + id: ct27Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct27} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} +#IC2 AddOn 4 +############ + - platform: atm90e32 + release_device: true + cs_pin: 22 + id: ${addon4_id2} + phase_a: + current: + name: ${ct28_name} Amps + id: ct28Amps + power: + name: ${ct28_name} Watts + id: ct28Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct28} + phase_b: + current: + name: ${ct29_name} Amps + id: ct29Amps + power: + name: ${ct29_name} Watts + id: ct29Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct29} + phase_c: + current: + name: ${ct30_name} Amps + id: ct30Amps + power: + name: ${ct30_name} Watts + id: ct30Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct30} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} + +#Total Amps AddOn4 + - platform: template + name: ${friendly_name} Total Amps Add-on4 + id: totalAmpsAddOn4 + lambda: return id(ct25Amps).state + id(ct26Amps).state + id(ct27Amps).state + id(ct28Amps).state + id(ct29Amps).state + id(ct30Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts AddOn4 + - platform: template + name: ${friendly_name} Total Watts Add-on4 + id: totalWattsAddOn4 + lambda: return id(ct25Watts).state + id(ct26Watts).state + id(ct27Watts).state + id(ct28Watts).state + id(ct29Watts).state + id(ct30Watts).state ; + accuracy_decimals: 2 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} diff --git a/esphome/circuit-setup/meter_sensors/6chan_addon5.yaml b/esphome/circuit-setup/meter_sensors/6chan_addon5.yaml new file mode 100644 index 0000000..2c8502c --- /dev/null +++ b/esphome/circuit-setup/meter_sensors/6chan_addon5.yaml @@ -0,0 +1,100 @@ +# CircuitSetup 6 Channel Energy Meter 5th Add-on board config +# Assumes jumpers are both in the 5th position + +sensor: +#IC1 AddOn 5 +############ + - platform: atm90e32 + release_device: true + cs_pin: 14 + id: ${addon5_id1} + phase_a: + current: + name: ${ct31_name} Amps + id: ct31Amps + power: + name: ${ct31_name} Watts + id: ct31Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct31} + phase_b: + current: + name: ${ct32_name} Amps + id: ct32Amps + power: + name: ${ct32_name} Watts + id: ct32Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct32} + phase_c: + current: + name: ${ct33_name} Amps + id: ct33Amps + power: + name: ${ct33_name} Watts + id: ct33Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct33} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} +#IC2 AddOn 5 +############ + - platform: atm90e32 + release_device: true + cs_pin: 25 + id: ${addon5_id2} + phase_a: + current: + name: ${ct34_name} Amps + id: ct34Amps + power: + name: ${ct34_name} Watts + id: ct34Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct34} + phase_b: + current: + name: ${ct35_name} Amps + id: ct35Amps + power: + name: ${ct35_name} Watts + id: ct35Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct35} + phase_c: + current: + name: ${ct36_name} Amps + id: ct36Amps + power: + name: ${ct36_name} Watts + id: ct36Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct36} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} + +#Total Amps AddOn5 + - platform: template + name: ${friendly_name} Total Amps Add-on5 + id: totalAmpsAddOn5 + lambda: return id(ct31Amps).state + id(ct32Amps).state + id(ct33Amps).state + id(ct34Amps).state + id(ct35Amps).state + id(ct36Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts AddOn5 + - platform: template + name: ${friendly_name} Total Watts Add-on5 + id: totalWattsAddOn5 + lambda: return id(ct31Watts).state + id(ct32Watts).state + id(ct33Watts).state + id(ct34Watts).state + id(ct35Watts).state + id(ct36Watts).state ; + accuracy_decimals: 2 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} diff --git a/esphome/circuit-setup/meter_sensors/6chan_addon6.yaml b/esphome/circuit-setup/meter_sensors/6chan_addon6.yaml new file mode 100644 index 0000000..7fe0e22 --- /dev/null +++ b/esphome/circuit-setup/meter_sensors/6chan_addon6.yaml @@ -0,0 +1,100 @@ +# CircuitSetup 6 Channel Energy Meter 6th Add-on board config +# Assumes jumpers are both in the 6th position + +sensor: +#IC1 AddOn 6 +############ + - platform: atm90e32 + release_device: true + cs_pin: 15 + id: ${addon6_id1} + phase_a: + current: + name: ${ct37_name} Amps + id: ct37Amps + power: + name: ${ct37_name} Watts + id: ct37Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct37} + phase_b: + current: + name: ${ct38_name} Amps + id: ct38Amps + power: + name: ${ct38_name} Watts + id: ct38Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct38} + phase_c: + current: + name: ${ct39_name} Amps + id: ct39Amps + power: + name: ${ct39_name} Watts + id: ct39Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct39} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} +#IC2 AddOn 6 +############ + - platform: atm90e32 + release_device: true + cs_pin: 26 + id: ${addon6_id2} + phase_a: + current: + name: ${ct40_name} Amps + id: ct40Amps + power: + name: ${ct40_name} Watts + id: ct40Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct40} + phase_b: + current: + name: ${ct41_name} Amps + id: ct41Amps + power: + name: ${ct41_name} Watts + id: ct41Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct41} + phase_c: + current: + name: ${ct42_name} Amps + id: ct42Amps + power: + name: ${ct42_name} Watts + id: ct42Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct42} + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} + +#Total Amps AddOn6 + - platform: template + name: ${friendly_name} Total Amps Add-on6 + id: totalAmpsAddOn6 + lambda: return id(ct37Amps).state + id(ct38Amps).state + id(ct39Amps).state + id(ct40Amps).state + id(ct41Amps).state + id(ct42Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts AddOn6 + - platform: template + name: ${friendly_name} Total Watts Add-on6 + id: totalWattsAddOn6 + lambda: return id(ct37Watts).state + id(ct38Watts).state + id(ct39Watts).state + id(ct40Watts).state + id(ct41Watts).state + id(ct42Watts).state ; + accuracy_decimals: 2 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} diff --git a/esphome/circuit-setup/meter_sensors/6chan_main_sensor.yaml b/esphome/circuit-setup/meter_sensors/6chan_main_sensor.yaml new file mode 100644 index 0000000..258660d --- /dev/null +++ b/esphome/circuit-setup/meter_sensors/6chan_main_sensor.yaml @@ -0,0 +1,123 @@ +sensor: +# Main IC1 +######### + - platform: atm90e32 + release_device: true + cs_pin: 5 + id: ${main_meter_id1} + phase_a: + voltage: + name: Voltage 1 + id: ic1Volts + accuracy_decimals: 1 + current: + name: ${ct1_name} Amps + id: ct1Amps +# The max value for current that the meter can output is 65.535. If you expect to measure current over 65A, +# divide the gain_ct by 2 (120A CT) or 4 (200A CT) and multiply the current and power values by 2 or 4 by uncommenting the filter below +# filters: +# - multiply: 2 + power: + name: ${ct1_name} Watts + id: ct1Watts +# filters: +# - multiply: 2 + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct1} + phase_b: + current: + name: ${ct2_name} Amps + id: ct2Amps + power: + name: ${ct2_name} Watts + id: ct2Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct2} + phase_c: + current: + name: ${ct3_name} Amps + id: ct3Amps + power: + name: ${ct3_name} Watts + id: ct3Watts + gain_voltage: ${voltage_cal1} + gain_ct: ${current_cal_ct3} + frequency: + name: Frequency 1 + chip_temperature: + name: ${main_meter_name1} Chip Temp + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} +# Main IC2 +########## + - platform: atm90e32 + release_device: true + cs_pin: 4 + id: ${main_meter_id2} + phase_a: +#this voltage is only needed if monitoring 2 voltages +# voltage: +# name: Voltage 2 +# id: ic2Volts +# accuracy_decimals: 1 + current: + name: ${ct4_name} Amps + id: ct4Amps + power: + name: ${ct4_name} Watts + id: ct4Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct4} + phase_b: + current: + name: ${ct5_name} Amps + id: ct5Amps + power: + name: ${ct5_name} Watts + id: ct5Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct5} + phase_c: + current: + name: ${ct6_name} Amps + id: ct6Amps + power: + name: ${ct6_name} Watts + id: ct6Watts + gain_voltage: ${voltage_cal2} + gain_ct: ${current_cal_ct6} +#this is only needed if monitoring 2 voltages +# frequency: +# name: Frequency 2 + chip_temperature: + name: ${main_meter_name2} Chip Temp + line_frequency: ${electric_freq} + gain_pga: 1X + update_interval: ${update_time} + enable_offset_calibration: ${offset_calibration} + enable_gain_calibration: ${gain_calibration} + +#Total Amps Main +################ + - platform: template + name: ${friendly_name} Total Amps Main + id: totalAmpsMain + lambda: return id(ct1Amps).state + id(ct2Amps).state + id(ct3Amps).state + id(ct4Amps).state + id(ct5Amps).state + id(ct6Amps).state ; + accuracy_decimals: 2 + unit_of_measurement: A + device_class: current + update_interval: ${update_time} + +#Total Watts Main +################# + - platform: template + name: ${friendly_name} Total Watts Main + id: totalWattsMain + lambda: return id(ct1Watts).state + id(ct2Watts).state + id(ct3Watts).state + id(ct4Watts).state + id(ct5Watts).state + id(ct6Watts).state ; + accuracy_decimals: 1 + unit_of_measurement: W + device_class: power + update_interval: ${update_time} diff --git a/esphome/circuit-setup/power_quality/6chan_addon1_power_quality.yaml b/esphome/circuit-setup/power_quality/6chan_addon1_power_quality.yaml new file mode 100644 index 0000000..d202799 --- /dev/null +++ b/esphome/circuit-setup/power_quality/6chan_addon1_power_quality.yaml @@ -0,0 +1,123 @@ +# This file contains power quality values that are available for each phase +# Enabling these on every current channel is possible, but will produce a lot of data +# and sensors that are likely not needed. +# More details on each sensor here: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + +sensor: +- id: !extend ${addon1_id1} + phase_a: + reactive_power: + name: ${ct7_name} VAR + id: ct7VAR + apparent_power: + name: ${ct7_name} VA + id: ct7VA + harmonic_power: + name: ${ct7_name} Harmonic + id: ct7Har + power_factor: + name: ${ct7_name} Power Factor + id: ct7PF + phase_angle: + name: ${ct7_name} Phase Angle + id: ct7Angle + peak_current: + name: ${ct7_name} Peak A + id: ct7Peak + phase_b: + reactive_power: + name: ${ct8_name} VAR + id: ct8VAR + apparent_power: + name: ${ct8_name} VA + id: ct8VA + harmonic_power: + name: ${ct8_name} Harmonic + id: ct8Har + power_factor: + name: ${ct8_name} Power Factor + id: ct8PF + phase_angle: + name: ${ct8_name} Phase Angle + id: ct8Angle + peak_current: + name: ${ct8_name} Peak A + id: ct8Peak + phase_c: + reactive_power: + name: ${ct9_name} VAR + id: ct9VAR + apparent_power: + name: ${ct9_name} VA + id: ct9VA + harmonic_power: + name: ${ct9_name} Harmonic + id: ct9Har + power_factor: + name: ${ct9_name} Power Factor + id: ct9PF + phase_angle: + name: ${ct9_name} Phase Angle + id: ct9Angle + peak_current: + name: ${ct9_name} Peak A + id: ct9Peak + +- id: !extend ${addon1_id2} + phase_a: + reactive_power: + name: ${ct10_name} VAR + id: ct10VAR + apparent_power: + name: ${ct10_name} VA + id: ct10VA + harmonic_power: + name: ${ct10_name} Harmonic + id: ct10Har + power_factor: + name: ${ct10_name} Power Factor + id: ct10PF + phase_angle: + name: ${ct10_name} Phase Angle + id: ct10Angle + peak_current: + name: ${ct10_name} Peak A + id: ct10Peak + phase_b: + reactive_power: + name: ${ct11_name} VAR + id: ct11VAR + apparent_power: + name: ${ct11_name} VA + id: ct11VA + harmonic_power: + name: ${ct11_name} Harmonic + id: ct11Har + power_factor: + name: ${ct11_name} Power Factor + id: ct11PF + phase_angle: + name: ${ct11_name} Phase Angle + id: ct11Angle + peak_current: + name: ${ct11_name} Peak A + id: ct11Peak + phase_c: + reactive_power: + name: ${ct12_name} VAR + id: ct12VAR + apparent_power: + name: ${ct12_name} VA + id: ct12VA + harmonic_power: + name: ${ct12_name} Harmonic + id: ct12Har + power_factor: + name: ${ct12_name} Power Factor + id: ct12PF + phase_angle: + name: ${ct12_name} Phase Angle + id: ct12Angle + peak_current: + name: ${ct12_name} Peak A + id: ct12Peak diff --git a/esphome/circuit-setup/power_quality/6chan_addon2_power_quality.yaml b/esphome/circuit-setup/power_quality/6chan_addon2_power_quality.yaml new file mode 100644 index 0000000..7e4f9a9 --- /dev/null +++ b/esphome/circuit-setup/power_quality/6chan_addon2_power_quality.yaml @@ -0,0 +1,123 @@ +# This file contains power quality values that are available for each phase +# Enabling these on every current channel is possible, but will produce a lot of data +# and sensors that are likely not needed. +# More details on each sensor here: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + +sensor: +- id: !extend ${addon2_id1} + phase_a: + reactive_power: + name: ${ct13_name} VAR + id: ct13VAR + apparent_power: + name: ${ct13_name} VA + id: ct13VA + harmonic_power: + name: ${ct13_name} Harmonic + id: ct13Har + power_factor: + name: ${ct13_name} Power Factor + id: ct13PF + phase_angle: + name: ${ct13_name} Phase Angle + id: ct13Angle + peak_current: + name: ${ct13_name} Peak A + id: ct13Peak + phase_b: + reactive_power: + name: ${ct14_name} VAR + id: ct14VAR + apparent_power: + name: ${ct14_name} VA + id: ct14VA + harmonic_power: + name: ${ct14_name} Harmonic + id: ct14Har + power_factor: + name: ${ct14_name} Power Factor + id: ct14PF + phase_angle: + name: ${ct14_name} Phase Angle + id: ct14Angle + peak_current: + name: ${ct14_name} Peak A + id: ct14Peak + phase_c: + reactive_power: + name: ${ct15_name} VAR + id: ct15VAR + apparent_power: + name: ${ct15_name} VA + id: ct15VA + harmonic_power: + name: ${ct15_name} Harmonic + id: ct15Har + power_factor: + name: ${ct15_name} Power Factor + id: ct15PF + phase_angle: + name: ${ct15_name} Phase Angle + id: ct15Angle + peak_current: + name: ${ct15_name} Peak A + id: ct15Peak + +- id: !extend ${addon2_id2} + phase_a: + reactive_power: + name: ${ct16_name} VAR + id: ct16VAR + apparent_power: + name: ${ct16_name} VA + id: ct16VA + harmonic_power: + name: ${ct16_name} Harmonic + id: ct16Har + power_factor: + name: ${ct16_name} Power Factor + id: ct16PF + phase_angle: + name: ${ct16_name} Phase Angle + id: ct16Angle + peak_current: + name: ${ct16_name} Peak A + id: ct16Peak + phase_b: + reactive_power: + name: ${ct17_name} VAR + id: ct17VAR + apparent_power: + name: ${ct17_name} VA + id: ct17VA + harmonic_power: + name: ${ct17_name} Harmonic + id: ct17Har + power_factor: + name: ${ct17_name} Power Factor + id: ct17PF + phase_angle: + name: ${ct17_name} Phase Angle + id: ct17Angle + peak_current: + name: ${ct17_name} Peak A + id: ct17Peak + phase_c: + reactive_power: + name: ${ct18_name} VAR + id: ct18VAR + apparent_power: + name: ${ct18_name} VA + id: ct18VA + harmonic_power: + name: ${ct18_name} Harmonic + id: ct18Har + power_factor: + name: ${ct18_name} Power Factor + id: ct18PF + phase_angle: + name: ${ct18_name} Phase Angle + id: ct18Angle + peak_current: + name: ${ct18_name} Peak A + id: ct18Peak diff --git a/esphome/circuit-setup/power_quality/6chan_addon3_power_quality.yaml b/esphome/circuit-setup/power_quality/6chan_addon3_power_quality.yaml new file mode 100644 index 0000000..7046c28 --- /dev/null +++ b/esphome/circuit-setup/power_quality/6chan_addon3_power_quality.yaml @@ -0,0 +1,123 @@ +# This file contains power quality values that are available for each phase +# Enabling these on every current channel is possible, but will produce a lot of data +# and sensors that are likely not needed. +# More details on each sensor here: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + +sensor: +- id: !extend ${addon3_id1} + phase_a: + reactive_power: + name: ${ct19_name} VAR + id: ct19VAR + apparent_power: + name: ${ct19_name} VA + id: ct19VA + harmonic_power: + name: ${ct19_name} Harmonic + id: ct19Har + power_factor: + name: ${ct19_name} Power Factor + id: ct19PF + phase_angle: + name: ${ct19_name} Phase Angle + id: ct19Angle + peak_current: + name: ${ct19_name} Peak A + id: ct19Peak + phase_b: + reactive_power: + name: ${ct20_name} VAR + id: ct20VAR + apparent_power: + name: ${ct20_name} VA + id: ct20VA + harmonic_power: + name: ${ct20_name} Harmonic + id: ct20Har + power_factor: + name: ${ct20_name} Power Factor + id: ct20PF + phase_angle: + name: ${ct20_name} Phase Angle + id: ct20Angle + peak_current: + name: ${ct20_name} Peak A + id: ct20Peak + phase_c: + reactive_power: + name: ${ct21_name} VAR + id: ct21VAR + apparent_power: + name: ${ct21_name} VA + id: ct21VA + harmonic_power: + name: ${ct21_name} Harmonic + id: ct21Har + power_factor: + name: ${ct21_name} Power Factor + id: ct21PF + phase_angle: + name: ${ct21_name} Phase Angle + id: ct21Angle + peak_current: + name: ${ct21_name} Peak A + id: ct21Peak + +- id: !extend ${addon3_id2} + phase_a: + reactive_power: + name: ${ct22_name} VAR + id: ct22VAR + apparent_power: + name: ${ct22_name} VA + id: ct22VA + harmonic_power: + name: ${ct22_name} Harmonic + id: ct22Har + power_factor: + name: ${ct22_name} Power Factor + id: ct22PF + phase_angle: + name: ${ct22_name} Phase Angle + id: ct22Angle + peak_current: + name: ${ct22_name} Peak A + id: ct22Peak + phase_b: + reactive_power: + name: ${ct23_name} VAR + id: ct23VAR + apparent_power: + name: ${ct23_name} VA + id: ct23VA + harmonic_power: + name: ${ct23_name} Harmonic + id: ct23Har + power_factor: + name: ${ct23_name} Power Factor + id: ct23PF + phase_angle: + name: ${ct23_name} Phase Angle + id: ct23Angle + peak_current: + name: ${ct23_name} Peak A + id: ct23Peak + phase_c: + reactive_power: + name: ${ct24_name} VAR + id: ct24VAR + apparent_power: + name: ${ct24_name} VA + id: ct24VA + harmonic_power: + name: ${ct24_name} Harmonic + id: ct24Har + power_factor: + name: ${ct24_name} Power Factor + id: ct24PF + phase_angle: + name: ${ct24_name} Phase Angle + id: ct24Angle + peak_current: + name: ${ct24_name} Peak A + id: ct24Peak diff --git a/esphome/circuit-setup/power_quality/6chan_addon4_power_quality.yaml b/esphome/circuit-setup/power_quality/6chan_addon4_power_quality.yaml new file mode 100644 index 0000000..6ecfc05 --- /dev/null +++ b/esphome/circuit-setup/power_quality/6chan_addon4_power_quality.yaml @@ -0,0 +1,123 @@ +# This file contains power quality values that are available for each phase +# Enabling these on every current channel is possible, but will produce a lot of data +# and sensors that are likely not needed. +# More details on each sensor here: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + +sensor: +- id: !extend ${addon4_id1} + phase_a: + reactive_power: + name: ${ct25_name} VAR + id: ct25VAR + apparent_power: + name: ${ct25_name} VA + id: ct25VA + harmonic_power: + name: ${ct25_name} Harmonic + id: ct25Har + power_factor: + name: ${ct25_name} Power Factor + id: ct25PF + phase_angle: + name: ${ct25_name} Phase Angle + id: ct25Angle + peak_current: + name: ${ct25_name} Peak A + id: ct25Peak + phase_b: + reactive_power: + name: ${ct26_name} VAR + id: ct26VAR + apparent_power: + name: ${ct26_name} VA + id: ct26VA + harmonic_power: + name: ${ct26_name} Harmonic + id: ct26Har + power_factor: + name: ${ct26_name} Power Factor + id: ct26PF + phase_angle: + name: ${ct26_name} Phase Angle + id: ct26Angle + peak_current: + name: ${ct26_name} Peak A + id: ct26Peak + phase_c: + reactive_power: + name: ${ct27_name} VAR + id: ct27VAR + apparent_power: + name: ${ct27_name} VA + id: ct27VA + harmonic_power: + name: ${ct27_name} Harmonic + id: ct27Har + power_factor: + name: ${ct27_name} Power Factor + id: ct27PF + phase_angle: + name: ${ct27_name} Phase Angle + id: ct27Angle + peak_current: + name: ${ct27_name} Peak A + id: ct27Peak + +- id: !extend ${addon4_id2} + phase_a: + reactive_power: + name: ${ct28_name} VAR + id: ct28VAR + apparent_power: + name: ${ct28_name} VA + id: ct28VA + harmonic_power: + name: ${ct28_name} Harmonic + id: ct28Har + power_factor: + name: ${ct28_name} Power Factor + id: ct28PF + phase_angle: + name: ${ct28_name} Phase Angle + id: ct28Angle + peak_current: + name: ${ct28_name} Peak A + id: ct28Peak + phase_b: + reactive_power: + name: ${ct29_name} VAR + id: ct29VAR + apparent_power: + name: ${ct29_name} VA + id: ct29VA + harmonic_power: + name: ${ct29_name} Harmonic + id: ct29Har + power_factor: + name: ${ct29_name} Power Factor + id: ct29PF + phase_angle: + name: ${ct29_name} Phase Angle + id: ct29Angle + peak_current: + name: ${ct29_name} Peak A + id: ct29Peak + phase_c: + reactive_power: + name: ${ct30_name} VAR + id: ct30VAR + apparent_power: + name: ${ct30_name} VA + id: ct30VA + harmonic_power: + name: ${ct30_name} Harmonic + id: ct30Har + power_factor: + name: ${ct30_name} Power Factor + id: ct30PF + phase_angle: + name: ${ct30_name} Phase Angle + id: ct30Angle + peak_current: + name: ${ct30_name} Peak A + id: ct30Peak diff --git a/esphome/circuit-setup/power_quality/6chan_addon5_power_quality.yaml b/esphome/circuit-setup/power_quality/6chan_addon5_power_quality.yaml new file mode 100644 index 0000000..e32cb47 --- /dev/null +++ b/esphome/circuit-setup/power_quality/6chan_addon5_power_quality.yaml @@ -0,0 +1,123 @@ +# This file contains power quality values that are available for each phase +# Enabling these on every current channel is possible, but will produce a lot of data +# and sensors that are likely not needed. +# More details on each sensor here: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + +sensor: +- id: !extend ${addon5_id1} + phase_a: + reactive_power: + name: ${ct31_name} VAR + id: ct31VAR + apparent_power: + name: ${ct31_name} VA + id: ct31VA + harmonic_power: + name: ${ct31_name} Harmonic + id: ct31Har + power_factor: + name: ${ct31_name} Power Factor + id: ct31PF + phase_angle: + name: ${ct31_name} Phase Angle + id: ct31Angle + peak_current: + name: ${ct31_name} Peak A + id: ct31Peak + phase_b: + reactive_power: + name: ${ct32_name} VAR + id: ct32VAR + apparent_power: + name: ${ct32_name} VA + id: ct32VA + harmonic_power: + name: ${ct32_name} Harmonic + id: ct32Har + power_factor: + name: ${ct32_name} Power Factor + id: ct32PF + phase_angle: + name: ${ct32_name} Phase Angle + id: ct32Angle + peak_current: + name: ${ct32_name} Peak A + id: ct32Peak + phase_c: + reactive_power: + name: ${ct33_name} VAR + id: ct33VAR + apparent_power: + name: ${ct33_name} VA + id: ct33VA + harmonic_power: + name: ${ct33_name} Harmonic + id: ct33Har + power_factor: + name: ${ct33_name} Power Factor + id: ct33PF + phase_angle: + name: ${ct33_name} Phase Angle + id: ct33Angle + peak_current: + name: ${ct33_name} Peak A + id: ct33Peak + +- id: !extend ${addon5_id2} + phase_a: + reactive_power: + name: ${ct34_name} VAR + id: ct34VAR + apparent_power: + name: ${ct34_name} VA + id: ct34VA + harmonic_power: + name: ${ct34_name} Harmonic + id: ct34Har + power_factor: + name: ${ct34_name} Power Factor + id: ct34PF + phase_angle: + name: ${ct34_name} Phase Angle + id: ct34Angle + peak_current: + name: ${ct34_name} Peak A + id: ct34Peak + phase_b: + reactive_power: + name: ${ct35_name} VAR + id: ct35VAR + apparent_power: + name: ${ct35_name} VA + id: ct35VA + harmonic_power: + name: ${ct35_name} Harmonic + id: ct35Har + power_factor: + name: ${ct35_name} Power Factor + id: ct35PF + phase_angle: + name: ${ct35_name} Phase Angle + id: ct35Angle + peak_current: + name: ${ct35_name} Peak A + id: ct35Peak + phase_c: + reactive_power: + name: ${ct36_name} VAR + id: ct36VAR + apparent_power: + name: ${ct36_name} VA + id: ct36VA + harmonic_power: + name: ${ct36_name} Harmonic + id: ct36Har + power_factor: + name: ${ct36_name} Power Factor + id: ct36PF + phase_angle: + name: ${ct36_name} Phase Angle + id: ct36Angle + peak_current: + name: ${ct36_name} Peak A + id: ct36Peak diff --git a/esphome/circuit-setup/power_quality/6chan_addon6_power_quality.yaml b/esphome/circuit-setup/power_quality/6chan_addon6_power_quality.yaml new file mode 100644 index 0000000..93cfdba --- /dev/null +++ b/esphome/circuit-setup/power_quality/6chan_addon6_power_quality.yaml @@ -0,0 +1,123 @@ +# This file contains power quality values that are available for each phase +# Enabling these on every current channel is possible, but will produce a lot of data +# and sensors that are likely not needed. +# More details on each sensor here: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + +sensor: +- id: !extend ${addon6_id1} + phase_a: + reactive_power: + name: ${ct37_name} VAR + id: ct37VAR + apparent_power: + name: ${ct37_name} VA + id: ct37VA + harmonic_power: + name: ${ct37_name} Harmonic + id: ct37Har + power_factor: + name: ${ct37_name} Power Factor + id: ct37PF + phase_angle: + name: ${ct37_name} Phase Angle + id: ct37Angle + peak_current: + name: ${ct37_name} Peak A + id: ct37Peak + phase_b: + reactive_power: + name: ${ct38_name} VAR + id: ct38VAR + apparent_power: + name: ${ct38_name} VA + id: ct38VA + harmonic_power: + name: ${ct38_name} Harmonic + id: ct38Har + power_factor: + name: ${ct38_name} Power Factor + id: ct38PF + phase_angle: + name: ${ct38_name} Phase Angle + id: ct38Angle + peak_current: + name: ${ct38_name} Peak A + id: ct38Peak + phase_c: + reactive_power: + name: ${ct39_name} VAR + id: ct39VAR + apparent_power: + name: ${ct39_name} VA + id: ct39VA + harmonic_power: + name: ${ct39_name} Harmonic + id: ct39Har + power_factor: + name: ${ct39_name} Power Factor + id: ct39PF + phase_angle: + name: ${ct39_name} Phase Angle + id: ct39Angle + peak_current: + name: ${ct39_name} Peak A + id: ct39Peak + +- id: !extend ${addon6_id2} + phase_a: + reactive_power: + name: ${ct40_name} VAR + id: ct40VAR + apparent_power: + name: ${ct40_name} VA + id: ct40VA + harmonic_power: + name: ${ct40_name} Harmonic + id: ct40Har + power_factor: + name: ${ct40_name} Power Factor + id: ct40PF + phase_angle: + name: ${ct40_name} Phase Angle + id: ct40Angle + peak_current: + name: ${ct40_name} Peak A + id: ct40Peak + phase_b: + reactive_power: + name: ${ct41_name} VAR + id: ct41VAR + apparent_power: + name: ${ct41_name} VA + id: ct41VA + harmonic_power: + name: ${ct41_name} Harmonic + id: ct41Har + power_factor: + name: ${ct41_name} Power Factor + id: ct41PF + phase_angle: + name: ${ct41_name} Phase Angle + id: ct41Angle + peak_current: + name: ${ct41_name} Peak A + id: ct41Peak + phase_c: + reactive_power: + name: ${ct42_name} VAR + id: ct42VAR + apparent_power: + name: ${ct42_name} VA + id: ct42VA + harmonic_power: + name: ${ct42_name} Harmonic + id: ct42Har + power_factor: + name: ${ct42_name} Power Factor + id: ct42PF + phase_angle: + name: ${ct42_name} Phase Angle + id: ct42Angle + peak_current: + name: ${ct42_name} Peak A + id: ct42Peak diff --git a/esphome/circuit-setup/power_quality/6chan_main_power_quality.yaml b/esphome/circuit-setup/power_quality/6chan_main_power_quality.yaml new file mode 100644 index 0000000..e4a66de --- /dev/null +++ b/esphome/circuit-setup/power_quality/6chan_main_power_quality.yaml @@ -0,0 +1,123 @@ +# This file contains power quality values that are available for each phase +# Enabling these on every current channel is possible, but will produce a lot of data +# and sensors that are likely not needed. +# More details on each sensor here: https://esphome.io/components/sensor/atm90e32.html#configuration-variables + +sensor: +- id: !extend ${main_meter_id1} + phase_a: + reactive_power: + name: ${ct1_name} VAR + id: ct1VAR + apparent_power: + name: ${ct1_name} VA + id: ct1VA + harmonic_power: + name: ${ct1_name} Harmonic + id: ct1Har + power_factor: + name: ${ct1_name} Power Factor + id: ct1PF + phase_angle: + name: ${ct1_name} Phase Angle + id: ct1Angle + peak_current: + name: ${ct1_name} Peak A + id: ct1Peak + phase_b: + reactive_power: + name: ${ct2_name} VAR + id: ct2VAR + apparent_power: + name: ${ct2_name} VA + id: ct2VA + harmonic_power: + name: ${ct2_name} Harmonic + id: ct2Har + power_factor: + name: ${ct2_name} Power Factor + id: ct2PF + phase_angle: + name: ${ct2_name} Phase Angle + id: ct2Angle + peak_current: + name: ${ct2_name} Peak A + id: ct2Peak + phase_c: + reactive_power: + name: ${ct3_name} VAR + id: ct3VAR + apparent_power: + name: ${ct3_name} VA + id: ct3VA + harmonic_power: + name: ${ct3_name} Harmonic + id: ct3Har + power_factor: + name: ${ct3_name} Power Factor + id: ct3PF + phase_angle: + name: ${ct3_name} Phase Angle + id: ct3Angle + peak_current: + name: ${ct3_name} Peak A + id: ct3Peak + +- id: !extend ${main_meter_id2} + phase_a: + reactive_power: + name: ${ct4_name} VAR + id: ct4VAR + apparent_power: + name: ${ct4_name} VA + id: ct4VA + harmonic_power: + name: ${ct4_name} Harmonic + id: ct4Har + power_factor: + name: ${ct4_name} Power Factor + id: ct4PF + phase_angle: + name: ${ct4_name} Phase Angle + id: ct4Angle + peak_current: + name: ${ct4_name} Peak A + id: ct4Peak + phase_b: + reactive_power: + name: ${ct5_name} VAR + id: ct5VAR + apparent_power: + name: ${ct5_name} VA + id: ct5VA + harmonic_power: + name: ${ct5_name} Harmonic + id: ct5Har + power_factor: + name: ${ct5_name} Power Factor + id: ct5PF + phase_angle: + name: ${ct5_name} Phase Angle + id: ct5Angle + peak_current: + name: ${ct5_name} Peak A + id: ct5Peak + phase_c: + reactive_power: + name: ${ct6_name} VAR + id: ct6VAR + apparent_power: + name: ${ct6_name} VA + id: ct6VA + harmonic_power: + name: ${ct6_name} Harmonic + id: ct6Har + power_factor: + name: ${ct6_name} Power Factor + id: ct6PF + phase_angle: + name: ${ct6_name} Phase Angle + id: ct6Angle + peak_current: + name: ${ct6_name} Peak A + id: ct6Peak diff --git a/esphome/circuit-setup/status_fields/6chan_addon1_status.yaml b/esphome/circuit-setup/status_fields/6chan_addon1_status.yaml new file mode 100644 index 0000000..1217e3a --- /dev/null +++ b/esphome/circuit-setup/status_fields/6chan_addon1_status.yaml @@ -0,0 +1,25 @@ +# These fields display the status of each CT, or phase, with a short text description +# See more details here: https://esphome.io/components/sensor/atm90e32.html#text-sensor + +# Status Fields +############### +text_sensor: + - platform: atm90e32 + id: ${addon1_id1} + phase_status: + phase_a: + name: "${ct7_name} Status" + phase_b: + name: "${ct8_name} Status" + phase_c: + name: "${ct9_name} Status" + + - platform: atm90e32 + id: ${addon1_id2} + phase_status: + phase_a: + name: "${ct10_name} Status" + phase_b: + name: "${ct11_name} Status" + phase_c: + name: "${ct12_name} Status" diff --git a/esphome/circuit-setup/status_fields/6chan_addon2_status.yaml b/esphome/circuit-setup/status_fields/6chan_addon2_status.yaml new file mode 100644 index 0000000..2d3d3be --- /dev/null +++ b/esphome/circuit-setup/status_fields/6chan_addon2_status.yaml @@ -0,0 +1,25 @@ +# These fields display the status of each CT, or phase, with a short text description +# See more details here: https://esphome.io/components/sensor/atm90e32.html#text-sensor + +# Status Fields +############### +text_sensor: + - platform: atm90e32 + id: ${addon2_id1} + phase_status: + phase_a: + name: "${ct13_name} Status" + phase_b: + name: "${ct14_name} Status" + phase_c: + name: "${ct15_name} Status" + + - platform: atm90e32 + id: ${addon2_id2} + phase_status: + phase_a: + name: "${ct16_name} Status" + phase_b: + name: "${ct17_name} Status" + phase_c: + name: "${ct18_name} Status" diff --git a/esphome/circuit-setup/status_fields/6chan_addon3_status.yaml b/esphome/circuit-setup/status_fields/6chan_addon3_status.yaml new file mode 100644 index 0000000..525774d --- /dev/null +++ b/esphome/circuit-setup/status_fields/6chan_addon3_status.yaml @@ -0,0 +1,25 @@ +# These fields display the status of each CT, or phase, with a short text description +# See more details here: https://esphome.io/components/sensor/atm90e32.html#text-sensor + +# Status Fields +############### +text_sensor: + - platform: atm90e32 + id: ${addon3_id1} + phase_status: + phase_a: + name: "${ct19_name} Status" + phase_b: + name: "${ct20_name} Status" + phase_c: + name: "${ct21_name} Status" + + - platform: atm90e32 + id: ${addon3_id2} + phase_status: + phase_a: + name: "${ct22_name} Status" + phase_b: + name: "${ct23_name} Status" + phase_c: + name: "${ct24_name} Status" diff --git a/esphome/circuit-setup/status_fields/6chan_addon4_status.yaml b/esphome/circuit-setup/status_fields/6chan_addon4_status.yaml new file mode 100644 index 0000000..44b07e3 --- /dev/null +++ b/esphome/circuit-setup/status_fields/6chan_addon4_status.yaml @@ -0,0 +1,25 @@ +# These fields display the status of each CT, or phase, with a short text description +# See more details here: https://esphome.io/components/sensor/atm90e32.html#text-sensor + +# Status Fields +############### +text_sensor: + - platform: atm90e32 + id: ${addon4_id1} + phase_status: + phase_a: + name: "${ct25_name} Status" + phase_b: + name: "${ct26_name} Status" + phase_c: + name: "${ct27_name} Status" + + - platform: atm90e32 + id: ${addon4_id2} + phase_status: + phase_a: + name: "${ct28_name} Status" + phase_b: + name: "${ct29_name} Status" + phase_c: + name: "${ct30_name} Status" diff --git a/esphome/circuit-setup/status_fields/6chan_addon5_status.yaml b/esphome/circuit-setup/status_fields/6chan_addon5_status.yaml new file mode 100644 index 0000000..b8e05f1 --- /dev/null +++ b/esphome/circuit-setup/status_fields/6chan_addon5_status.yaml @@ -0,0 +1,25 @@ +# These fields display the status of each CT, or phase, with a short text description +# See more details here: https://esphome.io/components/sensor/atm90e32.html#text-sensor + +# Status Fields +############### +text_sensor: + - platform: atm90e32 + id: ${addon5_id1} + phase_status: + phase_a: + name: "${ct31_name} Status" + phase_b: + name: "${ct32_name} Status" + phase_c: + name: "${ct33_name} Status" + + - platform: atm90e32 + id: ${addon5_id2} + phase_status: + phase_a: + name: "${ct34_name} Status" + phase_b: + name: "${ct35_name} Status" + phase_c: + name: "${ct36_name} Status" diff --git a/esphome/circuit-setup/status_fields/6chan_addon6_status.yaml b/esphome/circuit-setup/status_fields/6chan_addon6_status.yaml new file mode 100644 index 0000000..6e92a00 --- /dev/null +++ b/esphome/circuit-setup/status_fields/6chan_addon6_status.yaml @@ -0,0 +1,25 @@ +# These fields display the status of each CT, or phase, with a short text description +# See more details here: https://esphome.io/components/sensor/atm90e32.html#text-sensor + +# Status Fields +############### +text_sensor: + - platform: atm90e32 + id: ${addon6_id1} + phase_status: + phase_a: + name: "${ct37_name} Status" + phase_b: + name: "${ct38_name} Status" + phase_c: + name: "${ct39_name} Status" + + - platform: atm90e32 + id: ${addon6_id2} + phase_status: + phase_a: + name: "${ct40_name} Status" + phase_b: + name: "${ct41_name} Status" + phase_c: + name: "${ct42_name} Status" diff --git a/esphome/circuit-setup/status_fields/6chan_main_status.yaml b/esphome/circuit-setup/status_fields/6chan_main_status.yaml new file mode 100644 index 0000000..fe23653 --- /dev/null +++ b/esphome/circuit-setup/status_fields/6chan_main_status.yaml @@ -0,0 +1,30 @@ +# These fields display the status of each CT, or phase, with a short text description +# See more details here: https://esphome.io/components/sensor/atm90e32.html#text-sensor + +# Main Board Status Fields +########################## +text_sensor: + - platform: atm90e32 + id: ${main_meter_id1} + phase_status: + phase_a: + name: "${ct1_name} Status" + phase_b: + name: "${ct2_name} Status" + phase_c: + name: "${ct3_name} Status" + frequency_status: + name: "Frequency Status 1" + + - platform: atm90e32 + id: ${main_meter_id2} + phase_status: + phase_a: + name: "${ct4_name} Status" + phase_b: + name: "${ct5_name} Status" + phase_c: + name: "${ct6_name} Status" +#this is only needed if monitoring 2 voltages +# freq_status: +# name: "Frequency Status 2" diff --git a/esphome/common/media_player.yaml b/esphome/common/media_player.yaml new file mode 100644 index 0000000..c29bebb --- /dev/null +++ b/esphome/common/media_player.yaml @@ -0,0 +1,14 @@ +media_player: + - id: external_media_player + platform: speaker + + # Define the actions Home Assistant will call + on_turn_on: + - lambda: |- + // No action needed, Home Assistant can call this service + return; + + on_turn_off: + - lambda: |- + // No action needed, Home Assistant can call this service + return; \ No newline at end of file diff --git a/esphome/common/mqtt_all.yaml b/esphome/common/mqtt_all.yaml new file mode 100644 index 0000000..0308f24 --- /dev/null +++ b/esphome/common/mqtt_all.yaml @@ -0,0 +1,30 @@ +esphome: + +api: + reboot_timeout: 0s + +substitutions: + mqtt_root_topic: !secret mqtt_root_topic + +mqtt: + broker: !secret mqtt_broker + port: !secret mqtt_port + username: !secret mqtt_username + password: !secret mqtt_password + discover_ip: False + discovery: false + discovery_retain: false + log_topic: null + + topic_prefix: ${mqtt_root_topic}/${devicename} + + # birth_message: + # topic: ${mqtt_root_topic}/${devicename}/availability + # payload: online + # will_message: + # topic: ${mqtt_root_topic}/${devicename}/availability + # payload: offline + + # shutdown_message: + # topic: ${mqtt_root_topic}/${devicename}/availability + # payload: shutdown diff --git a/esphome/common/mqtt_null.yaml b/esphome/common/mqtt_null.yaml new file mode 100644 index 0000000..62bcd51 --- /dev/null +++ b/esphome/common/mqtt_null.yaml @@ -0,0 +1,26 @@ +esphome: + +api: + reboot_timeout: 0s + +substitutions: + mqtt_root_topic: !secret mqtt_root_topic + +mqtt: + broker: !secret mqtt_broker + port: !secret mqtt_port + username: !secret mqtt_username + password: !secret mqtt_password + discover_ip: False + discovery: false + discovery_retain: false + topic_prefix: null + birth_message: + topic: ${mqtt_root_topic}/${devicename}/availability + payload: online + will_message: + topic: ${mqtt_root_topic}/${devicename}/availability + payload: offline + shutdown_message: + topic: ${mqtt_root_topic}/${devicename}/availability + payload: offline \ No newline at end of file diff --git a/esphome/garage-cleversensor.yaml b/esphome/garage-cleversensor.yaml index 6dcb2f7..8b4ebc4 100644 --- a/esphome/garage-cleversensor.yaml +++ b/esphome/garage-cleversensor.yaml @@ -9,6 +9,7 @@ substitutions: network: wifi static_ip: !secret garage-cleversensor-ip i2c_id: bus_a + mqtt_root_topic: !secret mqtt_root_topic # For the ultrasonic sensors trigger1: 16 @@ -54,6 +55,7 @@ packages: device_base: !include common/device_base.yaml web_server: !include common/web_server.yaml bme680: !include common/bme68x_bsec2_i2c.yaml + mqtt: !include common/mqtt_all.yaml # remote_receiver: # pin: ${ir_rx} @@ -115,6 +117,10 @@ binary_sensor: - platform: gpio name: "ESP32-EVB button" pin: ${button1} + # on_press: + # - mqtt.publish: + # topic: "${mqtt_root_topic}/${devicename}/button" + # payload: "pressed" - platform: gpio name: "Garage Door" diff --git a/esphome/home-assistant-voice-097b44.yaml b/esphome/home-assistant-voice-097b44.yaml index c983666..6f72272 100644 --- a/esphome/home-assistant-voice-097b44.yaml +++ b/esphome/home-assistant-voice-097b44.yaml @@ -4,14 +4,52 @@ substitutions: friendly_name: Home Assistant Voice 097b44 comment: Clever Voice static_ip: !secret clints-home-assistant-voice + power_switch_pin: GPIO3 + packages: base: !include common/device_base.yaml network: !include common/wifi.yaml Nabu Casa.Home Assistant Voice PE: github://esphome/home-assistant-voice-pe/home-assistant-voice.yaml + #power_buttons: !include common/media_player.yaml esphome: name: ${name} name_add_mac_suffix: false friendly_name: ${friendly_name} button: - - id: !remove local_restart_button \ No newline at end of file + - id: !remove local_restart_button + + +# forget all of this extending bullshit and implement this: +# https://www.home-assistant.io/integrations/universal/ + +switch: + - platform: template + name: "External Power Switch" + id: external_power_switch + turn_on_action: + - logger.log: "External Power Switch turned on" + - media_player.turn_on: + id: external_media_player + # - lambda: return; + turn_off_action: + - logger.log: "External Power Switch turned off" + - media_player.turn_off: + id: external_media_player + # - lambda: return; + +media_player: + - id: !extend external_media_player + + # Define the actions Home Assistant will call + on_turn_on: + - logger.log: "Media Player Turned On via on_turn_on action" + # - lambda: |- + # // No action needed, Home Assistant can call this service + # return; + + on_turn_off: + - logger.log: "Media Player Turned Off via on_turn_off action" + # - lambda: |- + # // No action needed, Home Assistant can call this service + # return; \ No newline at end of file diff --git a/esphome/power-monitor.yaml b/esphome/power-monitor.yaml index 0775728..e3d8c16 100644 --- a/esphome/power-monitor.yaml +++ b/esphome/power-monitor.yaml @@ -106,6 +106,7 @@ packages: wifi: !include common/wifi.yaml # device_base: !include common/complex_esp32_base.yaml device_base: !include common/device_base.yaml + mqtt: !include common/mqtt_null.yaml esp32: board: nodemcu-32s @@ -466,6 +467,13 @@ sensor: - throttle_average: ${throttle_time} # - heartbeat: ${watt_heartbeat} accuracy_decimals: 1 + qos: 1 + retain: true + availability: + topic: ${mqtt_root_topic}/${devicename}/${ct21Name}_w/status + payload_available: online + payload_not_available: offline + state_topic: ${mqtt_root_topic}/${devicename}/${ct21Name}_w gain_voltage: ${voltage_cal} gain_ct: ${sct006} line_frequency: 60Hz @@ -796,6 +804,13 @@ sensor: unit_of_measurement: kWh device_class: energy state_class: total_increasing + qos: 1 + retain: true + availability: + topic: ${mqtt_root_topic}/${devicename}/${ct21Name}_kwh/status + payload_available: online + payload_not_available: offline + state_topic: ${mqtt_root_topic}/${devicename}/${ct21Name}_kwh # min_save_interval: ${update_time} #kWh From CT 22 diff --git a/lovelace/appliances/dishwasher.yaml b/lovelace/appliances/dishwasher.yaml index f52e321..59ccfbb 100644 --- a/lovelace/appliances/dishwasher.yaml +++ b/lovelace/appliances/dishwasher.yaml @@ -20,36 +20,6 @@ cards: cards: - type: tile entity: sensor.dishwasher - icon_tap_action: - action: navigate - navigation_path: /phone-yaml/dishwasher - tap_action: - action: navigate - navigation_path: /phone-yaml/dishwasher - show_entity_picture: true - vertical: true - - type: tile - entity: binary_sensor.keurig - icon_tap_action: - action: navigate - navigation_path: /phone-yaml/keurig - tap_action: - action: navigate - navigation_path: /phone-yaml/keurig - show_entity_picture: true - vertical: true - - type: tile - entity: binary_sensor.stove - icon_tap_action: - action: navigate - navigation_path: /phone-yaml/stove - tap_action: - action: navigate - navigation_path: /phone-yaml/stove - show_entity_picture: true - vertical: true - - type: tile - entity: input_select.dishwasher_fun_status name: Dishwasher icon_tap_action: action: navigate @@ -81,16 +51,32 @@ cards: navigation_path: /phone-yaml/tumble-dryer show_entity_picture: true vertical: true + - type: tile + entity: binary_sensor.keurig + icon_tap_action: + action: navigate + navigation_path: /phone-yaml/keurig + tap_action: + action: navigate + navigation_path: /phone-yaml/keurig + show_entity_picture: true + vertical: true + - type: tile + entity: binary_sensor.stove + icon_tap_action: + action: navigate + navigation_path: /phone-yaml/stove + tap_action: + action: navigate + navigation_path: /phone-yaml/stove + show_entity_picture: true + vertical: true - type: glance entities: - - entity: input_boolean.empty_dishwasher - tap_action: - action: toggle - entity: sensor.pm_dishwasher_w - - entity: input_number.dishwasher_delay_on - - entity: input_number.dishwasher_on - - entity: input_number.dishwasher_delay_off - - entity: sensor.dishwasher - - entity: binary_sensor.dishwasher + name: Watts - entity: binary_sensor.dishwasher_door_contact - - entity: sensor.dishwasher_door_device_temperature \ No newline at end of file + - entity: input_text.dishwasher_runtime + name: Runtime + - entity: counter.dishwasher + name: Cycles \ No newline at end of file diff --git a/lovelace/appliances/keurig.yaml b/lovelace/appliances/keurig.yaml index e79be5f..385f779 100644 --- a/lovelace/appliances/keurig.yaml +++ b/lovelace/appliances/keurig.yaml @@ -18,16 +18,6 @@ cards: cards: - type: grid cards: - - type: tile - entity: sensor.dishwasher - icon_tap_action: - action: navigate - navigation_path: /phone-yaml/dishwasher - tap_action: - action: navigate - navigation_path: /phone-yaml/dishwasher - show_entity_picture: true - vertical: true - type: tile entity: binary_sensor.keurig icon_tap_action: @@ -70,14 +60,7 @@ cards: vertical: true - type: glance entities: - - entity: input_boolean.empty_dishwasher - tap_action: - action: toggle - entity: sensor.pm_dishwasher_w - - entity: input_number.dishwasher_delay_on - - entity: input_number.dishwasher_on - - entity: input_number.dishwasher_delay_off - - entity: sensor.dishwasher - entity: binary_sensor.dishwasher - entity: binary_sensor.dishwasher_door_contact - entity: sensor.dishwasher_door_device_temperature diff --git a/lovelace/frigate/view-ai-cam03.yaml b/lovelace/frigate/view-ai-cam03.yaml index 88be1c2..462ceb9 100644 --- a/lovelace/frigate/view-ai-cam03.yaml +++ b/lovelace/frigate/view-ai-cam03.yaml @@ -7,10 +7,6 @@ visible: - user: cad46dedf86f454ebbd7f697a58730f2 cards: - !include /config/lovelace/cameras/view-camera-03.yaml - # - type: horizontal-stack - # cards: - #- !include /config/lovelace/cameras/view-camera-03.yaml - #- !include /config/lovelace/raw-cameras/computer-area-card.yaml - type: vertical-stack view_layout: diff --git a/lovelace/frigate/view-ai-cam04.yaml b/lovelace/frigate/view-ai-cam04.yaml index f067f9a..47deba2 100644 --- a/lovelace/frigate/view-ai-cam04.yaml +++ b/lovelace/frigate/view-ai-cam04.yaml @@ -6,9 +6,8 @@ visible: - user: 24a4bd075e7f41a497dd0390a1dd4a9f - user: cad46dedf86f454ebbd7f697a58730f2 cards: - - type: horizontal-stack - cards: - - !include /config/lovelace/cameras/view-camera-04.yaml + - !include /config/lovelace/cameras/view-camera-04.yaml + - type: vertical-stack view_layout: position: sidebar diff --git a/lovelace/frigate/view-ai-cam06.yaml b/lovelace/frigate/view-ai-cam06.yaml index 8dbfb2a..bf9ce60 100644 --- a/lovelace/frigate/view-ai-cam06.yaml +++ b/lovelace/frigate/view-ai-cam06.yaml @@ -6,9 +6,8 @@ visible: - user: 24a4bd075e7f41a497dd0390a1dd4a9f - user: cad46dedf86f454ebbd7f697a58730f2 cards: - - type: horizontal-stack - cards: - - !include /config/lovelace/cameras/view-camera-06.yaml + - !include /config/lovelace/cameras/view-camera-06.yaml + - type: vertical-stack view_layout: position: sidebar diff --git a/lovelace/frigate/view-ai-cam07.yaml b/lovelace/frigate/view-ai-cam07.yaml index 085f4e6..d4a159b 100644 --- a/lovelace/frigate/view-ai-cam07.yaml +++ b/lovelace/frigate/view-ai-cam07.yaml @@ -6,9 +6,8 @@ visible: - user: 24a4bd075e7f41a497dd0390a1dd4a9f - user: cad46dedf86f454ebbd7f697a58730f2 cards: - - type: horizontal-stack - cards: - - !include /config/lovelace/cameras/view-camera-07.yaml + - !include /config/lovelace/cameras/view-camera-07.yaml + - type: vertical-stack view_layout: position: sidebar diff --git a/lovelace/frigate/view-ai-cam08.yaml b/lovelace/frigate/view-ai-cam08.yaml index df689fe..46fb68e 100644 --- a/lovelace/frigate/view-ai-cam08.yaml +++ b/lovelace/frigate/view-ai-cam08.yaml @@ -6,9 +6,8 @@ visible: - user: 24a4bd075e7f41a497dd0390a1dd4a9f - user: cad46dedf86f454ebbd7f697a58730f2 cards: - - type: horizontal-stack - cards: - - !include /config/lovelace/cameras/view-camera-08.yaml + - !include /config/lovelace/cameras/view-camera-08.yaml + - type: vertical-stack view_layout: position: sidebar diff --git a/lovelace/frigate/view-ai-cam12.yaml b/lovelace/frigate/view-ai-cam12.yaml index 076a2b2..53a44a3 100644 --- a/lovelace/frigate/view-ai-cam12.yaml +++ b/lovelace/frigate/view-ai-cam12.yaml @@ -6,9 +6,8 @@ visible: - user: 24a4bd075e7f41a497dd0390a1dd4a9f - user: cad46dedf86f454ebbd7f697a58730f2 cards: - - type: horizontal-stack - cards: - - !include /config/lovelace/cameras/view-camera-12.yaml + - !include /config/lovelace/cameras/view-camera-12.yaml + - type: vertical-stack view_layout: position: sidebar diff --git a/lovelace/frigate/view-ai-cam13.yaml b/lovelace/frigate/view-ai-cam13.yaml deleted file mode 100644 index c18ebb6..0000000 --- a/lovelace/frigate/view-ai-cam13.yaml +++ /dev/null @@ -1,165 +0,0 @@ -title: AI Cam13 -path: ai-cam13 -icon: mdi:television -type: sidebar -visible: - - user: 24a4bd075e7f41a497dd0390a1dd4a9f - - user: cad46dedf86f454ebbd7f697a58730f2 -cards: - - type: horizontal-stack - cards: - - !include /config/lovelace/cameras/view-camera-13.yaml - - type: vertical-stack - view_layout: - position: sidebar - cards: - - type: glance - title: Front Room - entities: [] - # - type: glance - # show_state: false - # columns: 4 - # entities: - # - name: Contrast - # entity: switch.frigate_cam13_improve_contrast - # tap_action: - # action: toggle - # - name: Snapshots - # entity: switch.frigate_cam13_snapshots - # tap_action: - # action: toggle - # - name: Detect - # entity: switch.frigate_cam13_detect - # tap_action: - # action: toggle - # - name: Occupancy - # entity: binary_sensor.frigate_cam13_all_occupancy - - type: entities - title: Kitchen - show_header_toggle: false - entities: - - name: Kitchen - entity: sensor.kitchen_person_count - - name: Kitchen - entity: binary_sensor.kitchen_person_occupancy - - type: custom:advanced-camera-card - cameras: - - camera_entity: camera.frigate_cam12 - title: Kitchen - icon: mdi:fridge - live_provider: ha - frigate: - camera_name: frigate_cam12 - zone: kitchen - label: person - url: http://192.168.1.7:5000 - view: - default: snapshots - event_gallery: - controls: - thumbnails: - size: 75 - menu: - style: overlay - position: top - buttons: - clips: - enabled: false - download: - enabled: false - frigate_ui: - enabled: false - frigate: - enabled: false - live: - enabled: false - media_viewer: - controls: - next_previous: - style: chevrons - - type: entities - title: Dining Room - show_header_toggle: false - entities: - - name: Dining Room - entity: sensor.dining_room_person_count - - name: Dining Room - entity: binary_sensor.dining_room_person_occupancy - - type: custom:advanced-camera-card - cameras: - - camera_entity: camera.frigate_cam12 - title: Dining Room - icon: mdi:table-chair - live_provider: ha - frigate: - camera_name: frigate_cam12 - zone: dining_room - label: person - url: http://192.168.1.7:5000 - view: - default: snapshots - event_gallery: - controls: - thumbnails: - size: 75 - menu: - style: overlay - position: top - buttons: - clips: - enabled: false - download: - enabled: false - frigate_ui: - enabled: false - frigate: - enabled: false - live: - enabled: false - media_viewer: - controls: - next_previous: - style: chevrons - - type: entities - title: Front Room - show_header_toggle: false - entities: - - name: Front Room - entity: sensor.front_room_person_count - - name: Front Room - entity: binary_sensor.front_room_person_occupancy - - type: custom:advanced-camera-card - cameras: - - camera_entity: camera.frigate_cam12 - title: Front Room - icon: mdi:television - live_provider: ha - frigate: - camera_name: frigate_cam13 - zone: front_room - label: person - url: http://192.168.1.7:5000 - view: - default: snapshots - event_gallery: - controls: - thumbnails: - size: 75 - menu: - style: overlay - position: top - buttons: - clips: - enabled: false - download: - enabled: false - frigate_ui: - enabled: false - frigate: - enabled: false - live: - enabled: false - media_viewer: - controls: - next_previous: - style: chevrons diff --git a/lovelace/frigate/view-ai-cam14.yaml b/lovelace/frigate/view-ai-cam14.yaml deleted file mode 100644 index a01affd..0000000 --- a/lovelace/frigate/view-ai-cam14.yaml +++ /dev/null @@ -1,127 +0,0 @@ -title: AI Cam14 -path: ai-cam14 -icon: mdi:slide -type: sidebar -visible: - - user: 24a4bd075e7f41a497dd0390a1dd4a9f - - user: cad46dedf86f454ebbd7f697a58730f2 -cards: - - type: horizontal-stack - cards: - - !include /config/lovelace/cameras/view-camera-14.yaml - - type: vertical-stack - view_layout: - position: sidebar - cards: - - type: glance - title: Back Yard - entities: [] - - type: glance - show_state: true - columns: 5 - entities: - # - name: Contrast - # entity: switch.frigate_cam14_improve_contrast - # tap_action: - # action: toggle - # - name: Snapshots - # entity: switch.frigate_cam14_snapshots - # tap_action: - # action: toggle - # - name: Detect - # entity: switch.frigate_cam14_detect - # tap_action: - # action: toggle - # - name: Occupancy - # entity: binary_sensor.frigate_cam14_all_occupancy - - type: horizontal-stack - cards: - # - type: glance - # title: People - # show_icon: false - # columns: 1 - # entities: - # - name: Count - # entity: sensor.frigate_cam14_person_count - # - name: Occupancy - # entity: binary_sensor.frigate_cam14_person_occupancy - - type: custom:advanced-camera-card - cameras: - - camera_entity: camera.frigate_cam12 - # - camera_entity: camera.frigate_cam14 - title: Person - icon: mdi:slide - live_provider: ha - frigate: - camera_name: frigate_cam14 - label: person - url: http://192.168.1.7:5000 - view: - default: snapshots - event_gallery: - controls: - thumbnails: - size: 100 - menu: - style: overlay - position: top - buttons: - clips: - enabled: false - download: - enabled: false - frigate_ui: - enabled: false - frigate: - enabled: false - live: - enabled: false - media_viewer: - controls: - next_previous: - style: chevrons - # - type: horizontal-stack - # cards: - # - type: glance - # title: Animals - # show_icon: false - # columns: 1 - # entities: - # - name: Count - # entity: sensor.frigate_cam14_animal_count - # - name: Occupancy - # entity: binary_sensor.frigate_cam14_animal_occupancy - # - type: custom:advanced-camera-card - # cameras: - # - camera_entity: camera.frigate_cam14 - # title: Back Yard - # icon: mdi:bird - # live_provider: ha - # frigate: - # camera_name: frigate_cam14 - # label: animal - # url: http://192.168.1.7:5000 - # view: - # default: snapshots - # event_gallery: - # controls: - # thumbnails: - # size: 100 - # menu: - # style: overlay - # position: top - # buttons: - # clips: - # enabled: false - # download: - # enabled: false - # frigate_ui: - # enabled: false - # frigate: - # enabled: false - # live: - # enabled: false - # media_viewer: - # controls: - # next_previous: - # style: chevrons diff --git a/lovelace/frigate/view-ai-cam18.yaml b/lovelace/frigate/view-ai-cam18.yaml index bca4856..863ef23 100644 --- a/lovelace/frigate/view-ai-cam18.yaml +++ b/lovelace/frigate/view-ai-cam18.yaml @@ -6,11 +6,8 @@ visible: - user: 24a4bd075e7f41a497dd0390a1dd4a9f - user: cad46dedf86f454ebbd7f697a58730f2 cards: - - type: horizontal-stack - cards: - - type: vertical-stack - cards: - - !include /config/lovelace/cameras/view-camera-18.yaml + - !include /config/lovelace/cameras/view-camera-18.yaml + - type: vertical-stack view_layout: position: sidebar diff --git a/lovelace/frigate/view-ai-cam19.yaml b/lovelace/frigate/view-ai-cam19.yaml index ed69791..6bc90bf 100644 --- a/lovelace/frigate/view-ai-cam19.yaml +++ b/lovelace/frigate/view-ai-cam19.yaml @@ -6,11 +6,8 @@ visible: - user: 24a4bd075e7f41a497dd0390a1dd4a9f - user: cad46dedf86f454ebbd7f697a58730f2 cards: - - type: horizontal-stack - cards: - - type: vertical-stack - cards: - - !include /config/lovelace/cameras/view-camera-19.yaml + - !include /config/lovelace/cameras/view-camera-19.yaml + - type: vertical-stack view_layout: position: sidebar diff --git a/lovelace/phone/home.yaml b/lovelace/phone/home.yaml index 1cb14f5..1f752ee 100644 --- a/lovelace/phone/home.yaml +++ b/lovelace/phone/home.yaml @@ -98,7 +98,7 @@ cards: state_not: "idle" chip: type: template - entity: input_boolean.empty_dishwasher + entity: sensor.dishwasher icon: > {% if is_state('sensor.dishwasher','running')-%} mdi:dishwasher @@ -181,25 +181,25 @@ cards: alignment: center - - type: markdown - content: > - {% set time = now().hour -%} - - {% if (time >= 18) -%} - Good evening, {{user}}! - {% elif (time >=12) -%} - Good afternoon, {{user}}! - {% else -%} - Good morning, {{user}}! - {%endif-%} - Today should be {{states('sensor.home_weather_condition')}}, with a high of - {{states('sensor.temphigh_today')|float(0)|round(0)}} and a low of - {{states('sensor.templow_today')|float(0)|round(0)}}. - tap_action: - action: navigate - navigation_path: /details-yml/weather - type: vertical-stack cards: + - type: markdown + content: > + {% set time = now().hour -%} + {% if (time >= 18) -%} + Good evening, {{user}}! + {% elif (time >=12) -%} + Good afternoon, {{user}}! + {% else -%} + Good morning, {{user}}! + {% endif %} + {% if states('sensor.home_weather_condition') not in ['unknown', 'unavailable'] -%} + Today should be {{states('sensor.home_weather_condition') | lower}}, with a high of {{states('sensor.temphigh_today')|float(0)|round(0)}} and a low of {{states('sensor.templow_today')|float(0)|round(0)}}. + {% endif %} + tap_action: + action: navigate + navigation_path: /details-yml/weather + - type: horizontal-stack cards: - type: custom:mushroom-template-card diff --git a/lovelace/phone/kitchen.yaml b/lovelace/phone/kitchen.yaml index a766154..be514e9 100644 --- a/lovelace/phone/kitchen.yaml +++ b/lovelace/phone/kitchen.yaml @@ -85,7 +85,7 @@ cards: action: navigate navigation_path: /phone-yaml/stove - type: custom:mushroom-entity-card - entity: binary_sensor.dishwasher + entity: input_select.dishwasher_fun_status layout: vertical primary_info: none secondary_info: none diff --git a/lovelace/resources.yaml b/lovelace/resources.yaml index e1c14fa..921a606 100644 --- a/lovelace/resources.yaml +++ b/lovelace/resources.yaml @@ -1,3 +1,6 @@ +- url: /hacsfiles/mass-player-card/mass-player-card.js + type: module + - url: /webrtc/webrtc-camera.js type: module diff --git a/lovelace/view-ha-floorplan.yaml b/lovelace/view-ha-floorplan.yaml index 1f0818f..fe733e2 100644 --- a/lovelace/view-ha-floorplan.yaml +++ b/lovelace/view-ha-floorplan.yaml @@ -758,10 +758,22 @@ cards: - state: "on" class: "door-open" + + - entities: + - sensor.dishwasher + states: + - state: "Idle" + class: "appliance-off" + - state: "Problem" + class: "appliance-problem" + - state: "Running" + class: "appliance-on" + - state: "Pending" + class: "appliance-pending" + - entities: - sensor.washing_machine - sensor.tumble_dryer - - sensor.dishwasher - binary_sensor.keurig - binary_sensor.microwave - binary_sensor.stove diff --git a/lovelace/view-overview.yaml b/lovelace/view-overview.yaml index 23cd2dc..62656b5 100644 --- a/lovelace/view-overview.yaml +++ b/lovelace/view-overview.yaml @@ -565,24 +565,30 @@ badges: - type: conditional conditions: - - entity: sensor.dishwasher - state_not: "idle" + - entity: input_select.dishwasher_fun_status + state_not: "Hungry for more" chip: type: template - entity: input_boolean.empty_dishwasher + entity: input_select.dishwasher_fun_status icon: > - {% if is_state('sensor.dishwasher','running')-%} + {% if is_state('input_select.dishwasher_fun_status','Scrubbing')-%} mdi:dishwasher - {% elif is_state('sensor.dishwasher','pending')-%} + {% elif is_state('input_select.dishwasher_fun_status','Water spots and mildew!')-%} mdi:dishwasher-alert + {% elif is_state('input_select.dishwasher_fun_status','Trouble')-%} + mdi:alert + {% elif is_state('input_select.dishwasher_fun_status','Hungry for more')-%} + mdi:dishwasher-off {%- endif %} icon_color: > - {% if is_state('sensor.dishwasher','running')-%} - amber - {% elif is_state('sensor.dishwasher','pending')-%} - blue - {% else -%} + {% if is_state('input_select.dishwasher_fun_status','Scrubbing')-%} + green + {% elif is_state('input_select.dishwasher_fun_status','Water spots and mildew!')-%} + orange + {% elif is_state('input_select.dishwasher_fun_status','Trouble')-%} red + {% elif is_state('input_select.dishwasher_fun_status','Hungry for more')-%} + disabled {%- endif %} tap_action: action: navigate diff --git a/www/floorplan/floorplan.css b/www/floorplan/floorplan.css index f8a89d4..607f93f 100644 --- a/www/floorplan/floorplan.css +++ b/www/floorplan/floorplan.css @@ -136,7 +136,7 @@ g.svg-long-click> :not(text):hover, .appliance-off { /* fill: var(--green-color) !important; */ /* fill: #81c9a7 !important; */ - fill: #81D9a7 !important; + fill: var(--disabled-color) !important; fill-opacity: 1 !important; /* stroke: #82caa8 !important; stroke-width: 1px !important; @@ -145,14 +145,14 @@ g.svg-long-click> :not(text):hover, } .appliance-on { - fill: #ff8800 !important; + fill: var(--primary-color) !important; fill-opacity: 1 !important; /* animation-duration: 4s; animation-name: rotate90; animation-fill-mode: forwards; */ } -.appliance-pending { +.appliance-problem { fill: var(--error-color) !important; fill-opacity: 1 !important; /* animation-duration: 4s; @@ -160,6 +160,14 @@ g.svg-long-click> :not(text):hover, animation-fill-mode: forwards; */ } +.appliance-pending { + fill: var(--warning-color) !important; + fill-opacity: 1 !important; + /* animation-duration: 4s; + animation-name: rotate90; + animation-fill-mode: forwards; */ +} + .window-closed { /* fill: var(--green-color) !important; */ /* fill: #81c9a7 !important; */ diff --git a/www/mail_and_packages/6c84a73d-d5a3-4fad-8bc2-3c6d663eff40.gif b/www/mail_and_packages/6c84a73d-d5a3-4fad-8bc2-3c6d663eff40.gif new file mode 100644 index 0000000000000000000000000000000000000000..94e230cdfb2bcd7498dd26115bca0d27e615ec4a GIT binary patch literal 41094 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�p6pDo-TcsYYTmWnN}UsOm)mZTmc1Jj$#Nl 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ΠklJ4rA-Y+UH3d8RD*{&s~bR@AT!UM=o%9 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 XHtp2D6#oC=Kl`j~EptCVc;f#6hRkuo literal 0 HcmV?d00001 diff --git a/www/mail_and_packages/white.png b/www/mail_and_packages/white.png new file mode 100644 index 0000000000000000000000000000000000000000..a12ccffbcb5a56f87278b7dac5f20ab0f8539517 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0y~yV4A_ez-Yn93=}!aE%*~iF%}28J29*~C-V}>VM%xN zb!1@J*w6hZkrl{i4)6(a{r~^}@*~nGfLzW3kH}&M2EM}}%y>M1MG8>R(9^{+q~g}w qgNBSi-k}9w{d0Nw6@X0afbS|pS^@*(xs}c8AO)VTelF{r5}E*RI48^i literal 0 HcmV?d00001