├── esphome ├── sonoff-1.yaml ├── sonoff-2.yaml ├── sonoff-3.yaml ├── izzy-fan.yaml ├── elijah-fan.yaml ├── glowforge-power.yaml ├── sonoff-4.yaml ├── .gitignore ├── secrets.yaml.example ├── basement-fan.yaml ├── common │ ├── common.yaml │ ├── sonoff-s31-fan.yaml │ └── sonoff-s31.yaml ├── basement-atom-echo.yaml ├── camera.yaml ├── izzy-desk.yaml ├── air-sensor-2.yaml ├── backyard-step-lights.yaml ├── sprinkler.yaml ├── elijah-desk-lights.yaml ├── master-bathroom-fan.yaml ├── garage-door.yaml ├── izzy-lamp.yaml ├── air-sensor.yaml ├── README.md ├── ir-blaster.yaml ├── basement-stereo.yaml └── shelly-em1.yaml ├── scripts ├── turn_off_interior_lights.yaml ├── movie_scene.yaml ├── set_homeseer_dim_level.yaml ├── tech_time_over.yaml ├── water_backyard.yaml └── inovelli_led.yaml ├── group.yaml ├── .gitignore ├── secrets.yaml.example ├── python_scripts └── configure_zwave.py ├── customize.yaml ├── Makefile ├── sensor.yaml ├── README.md ├── configuration.yaml ├── automations.yaml └── panels └── zwavegraph2.html /esphome/sonoff-1.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | device_name: sonoff-1 3 | friendly_name: Sonoff 1 4 | 5 | packages: 6 | common: !include common/sonoff-s31.yaml 7 | -------------------------------------------------------------------------------- /esphome/sonoff-2.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | device_name: sonoff-2 3 | friendly_name: Sonoff 2 4 | 5 | packages: 6 | common: !include common/sonoff-s31.yaml 7 | -------------------------------------------------------------------------------- /esphome/sonoff-3.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | device_name: sonoff-3 3 | friendly_name: Sonoff 3 4 | 5 | packages: 6 | common: !include common/sonoff-s31.yaml 7 | -------------------------------------------------------------------------------- /esphome/izzy-fan.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | device_name: izzy-fan 3 | friendly_name: Izzy's Fan 4 | 5 | packages: 6 | common: !include common/sonoff-s31-fan.yaml 7 | -------------------------------------------------------------------------------- /esphome/elijah-fan.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | device_name: elijah-fan 3 | friendly_name: Elijah's Fan 4 | 5 | packages: 6 | common: !include common/sonoff-s31-fan.yaml 7 | -------------------------------------------------------------------------------- /esphome/glowforge-power.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | device_name: glowforge-power 3 | friendly_name: Glowforge Power 4 | 5 | packages: 6 | common: !include common/sonoff-s31.yaml 7 | -------------------------------------------------------------------------------- /esphome/sonoff-4.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | device_name: sonoff-4 3 | friendly_name: Sonoff 4 4 | 5 | packages: 6 | common: !include common/sonoff-s31.yaml 7 | 8 | switch: 9 | - id: !extend relay 10 | restore_mode: ALWAYS_ON 11 | -------------------------------------------------------------------------------- /esphome/.gitignore: -------------------------------------------------------------------------------- 1 | # Gitignore settings for ESPHome 2 | # This is an example and may include too much for your use-case. 3 | # You can modify this file to suit your needs. 4 | /.esphome/ 5 | **/.pioenvs/ 6 | **/.piolibdeps/ 7 | **/lib/ 8 | **/src/ 9 | **/platformio.ini 10 | /secrets.yaml 11 | -------------------------------------------------------------------------------- /scripts/turn_off_interior_lights.yaml: -------------------------------------------------------------------------------- 1 | turn_off_interior_lights: 2 | alias: Turn off interior lights 3 | sequence: 4 | - service: light.turn_off 5 | data: 6 | entity_id: all 7 | - service: switch.turn_off 8 | data: 9 | entity_id: switch.bedroom_lamp 10 | -------------------------------------------------------------------------------- /esphome/secrets.yaml.example: -------------------------------------------------------------------------------- 1 | wifi_ssid: MyCoolWifiNetwork 2 | wifi_password: "mysecurepassword" 3 | wifi_ap_password: "fallbackappassword" 4 | ota_password: "otainstallpassword" 5 | # Key can be generated here: https://esphome.io/components/api.html?highlight=randomly%20generated 6 | esphome_encryption_key: "" 7 | -------------------------------------------------------------------------------- /esphome/basement-fan.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: basement-fan 3 | 4 | esp8266: 5 | board: d1_mini 6 | 7 | packages: 8 | common: !include common/common.yaml 9 | 10 | output: 11 | - platform: gpio 12 | pin: D1 13 | id: gpio_d1 14 | 15 | fan: 16 | - platform: binary 17 | output: gpio_d1 18 | name: "Basement Fan" 19 | -------------------------------------------------------------------------------- /esphome/common/common.yaml: -------------------------------------------------------------------------------- 1 | wifi: 2 | ssid: !secret wifi_ssid 3 | password: !secret wifi_password 4 | fast_connect: true 5 | min_auth_mode: WPA2 6 | 7 | # Enable logging 8 | logger: 9 | 10 | # Enable Home Assistant API 11 | api: 12 | encryption: 13 | key: !secret esphome_encryption_key 14 | 15 | ota: 16 | - platform: esphome 17 | password: !secret ota_password 18 | id: common_ota 19 | -------------------------------------------------------------------------------- /group.yaml: -------------------------------------------------------------------------------- 1 | all_people: 2 | entities: 3 | - person.john_boiles 4 | - person.christina_boiles 5 | 6 | batteries: 7 | entities: 8 | - sensor.lock_battery_level 9 | - sensor.motion_battery_level 10 | - sensor.backdoor_battery_level 11 | - sensor.sidedoor_battery_level 12 | - sensor.frontdoor_battery_level 13 | - sensor.smokealarm_battery_level 14 | - sensor.smokealarms_battery_level 15 | -------------------------------------------------------------------------------- /esphome/basement-atom-echo.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | name: basement-atom-echo 3 | friendly_name: basement-atom-echo 4 | 5 | packages: 6 | m5stack-atom-echo: github://esphome/firmware/wake-word-voice-assistant/m5stack-atom-echo.adopted.yaml@main 7 | common: !include common/common.yaml 8 | 9 | ota: 10 | - id: !remove ota_esphome 11 | 12 | esphome: 13 | name: ${name} 14 | name_add_mac_suffix: false 15 | friendly_name: ${friendly_name} 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !*.yaml 3 | !scenes 4 | !.gitignore 5 | !Makefile 6 | secrets.yaml 7 | known_devices.yaml 8 | entity_registry.yaml 9 | !README.md 10 | !secrets.yaml.example 11 | !custom_components 12 | !python_scripts 13 | !python_scripts/* 14 | !scripts 15 | !scripts/* 16 | !esphome 17 | !esphome/* 18 | /esphome/secrets.yaml 19 | /esphome/air_sensor 20 | /esphome/garage_door 21 | /esphome/ir_blaster 22 | /esphome/scratch 23 | !panels 24 | !panels/*.html 25 | .DS_Store 26 | -------------------------------------------------------------------------------- /esphome/camera.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: camera 3 | 4 | esp32: 5 | board: esp32dev 6 | 7 | packages: 8 | common: !include common/common.yaml 9 | 10 | esp32_camera: 11 | external_clock: 12 | pin: GPIO0 13 | frequency: 20MHz 14 | i2c_pins: 15 | sda: GPIO26 16 | scl: GPIO27 17 | data_pins: [GPIO5, GPIO18, GPIO19, GPIO21, GPIO36, GPIO39, GPIO34, GPIO35] 18 | vsync_pin: GPIO25 19 | href_pin: GPIO23 20 | pixel_clock_pin: GPIO22 21 | power_down_pin: GPIO32 22 | name: ESP Camera 23 | -------------------------------------------------------------------------------- /esphome/common/sonoff-s31-fan.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | common: !include sonoff-s31.yaml 3 | 4 | binary_sensor: 5 | - id: !extend side_button 6 | on_press: 7 | - switch.turn_off: relay 8 | - delay: 1s 9 | - switch.turn_on: relay 10 | 11 | switch: 12 | - id: !extend relay 13 | internal: true 14 | restore_mode: ALWAYS_ON 15 | 16 | button: 17 | - platform: template 18 | name: "Turn Off" 19 | on_press: 20 | then: 21 | - switch.turn_off: relay 22 | - delay: 1s 23 | - switch.turn_on: relay 24 | -------------------------------------------------------------------------------- /secrets.yaml.example: -------------------------------------------------------------------------------- 1 | home_latitude: 30.0000 2 | home_longitude: -122.0000 3 | home_elevation: 0 4 | 5 | mysql_db_url: mysql://homeassistant:PASSWORDHERE@core-mariadb/homeassistant?charset=utf8 6 | 7 | # Used for the Jupyter HASS addon config 8 | github_token: GITHUBTOKENHERE 9 | 10 | # Follow the instructions here: https://www.home-assistant.io/integrations/route53 11 | route53_access_key_id: ACCESSKEYID 12 | route53_secret_access_key: ACCESSSECRET 13 | route53_zone: ROUTE53ZONE 14 | route53_domain: ROUTE53 DOMAIN 15 | 16 | unifi_username: UNIFIUSERNAME 17 | unifi_password: UNIFIPASSWORD 18 | 19 | aqicn_api_token: SECRETAQICNTOKEN 20 | -------------------------------------------------------------------------------- /python_scripts/configure_zwave.py: -------------------------------------------------------------------------------- 1 | wd100_entities = [ 2 | 'light.living_room_light', 3 | 'light.dining_room_light', 4 | 'light.kitchen_island_light', 5 | 'light.kitchen_light', 6 | 'light.kitchen_hallway_light', 7 | 'light.bedroom_light', 8 | ] 9 | parameters = { 10 | 7: 1, 11 | 8: 10, 12 | 9: 1, 13 | 10: 10, 14 | } 15 | 16 | for entity in wd100_entities: 17 | for parameter in parameters: 18 | service_data = {'entity_id': entity, 'parameter': parameter, 'value': parameters[parameter]} 19 | hass.services.call('zwave_js', 'set_config_parameter', service_data, True) 20 | time.sleep(.2) 21 | -------------------------------------------------------------------------------- /esphome/izzy-desk.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: izzy-desk 3 | 4 | esp32: 5 | board: esp32dev 6 | framework: 7 | type: esp-idf 8 | # type: arduino 9 | 10 | packages: 11 | common: !include common/common.yaml 12 | 13 | light: 14 | # - platform: neopixelbus 15 | # type: GRBW 16 | # color_correct: [60%, 60%, 60%, 100%] 17 | # variant: SK6812 18 | # pin: GPIO14 19 | # num_leds: 140 20 | # name: "Izzy's Desk Lights" 21 | # restore_mode: RESTORE_DEFAULT_OFF 22 | - platform: esp32_rmt_led_strip 23 | pin: GPIO14 24 | num_leds: 169 25 | chipset: SK6812 26 | rgb_order: GRB 27 | is_rgbw: true 28 | name: "Izzy's Desk Lights" 29 | restore_mode: RESTORE_DEFAULT_OFF -------------------------------------------------------------------------------- /scripts/movie_scene.yaml: -------------------------------------------------------------------------------- 1 | # Turns on the bedroom lights and then the living room lights 1 minute later 2 | movie_scene: 3 | alias: Activate the movie scene 4 | sequence: 5 | # This is Home Assistant Script Syntax 6 | - alias: Kitchen Island light to dim 7 | service: light.turn_on 8 | data: 9 | entity_id: light.kitchen_island_light 10 | brightness_pct: 2 11 | - alias: Living room light off 12 | service: light.turn_off 13 | data: 14 | entity_id: light.living_room_light 15 | - alias: Dining room light off 16 | service: light.turn_off 17 | data: 18 | entity_id: light.dining_room_light 19 | - alias: Kitchen light off 20 | service: light.turn_off 21 | data: 22 | entity_id: light.kitchen_light 23 | -------------------------------------------------------------------------------- /customize.yaml: -------------------------------------------------------------------------------- 1 | cover.garage_door: 2 | icon: mdi:garage 3 | device_class: garage 4 | binary_sensor.front_door: 5 | device_class: door 6 | binary_sensor.back_door: 7 | device_class: door 8 | binary_sensor.upstairs_smoke_alarms: 9 | device_class: smoke 10 | sensor.pm25_particles: 11 | device_class: pm25 12 | sensor.bedroom_humidity: 13 | device_class: humidity 14 | sensor.kitchen_humidity: 15 | device_class: humidity 16 | sensor.basement_humidity: 17 | device_class: humidity 18 | sensor.outside_humidity: 19 | device_class: humidity 20 | sensor.izzy_room_humidity: 21 | device_class: humidity 22 | media_player.soundbar: 23 | # Required to make this show up in HomeKit 24 | device_class: tv 25 | source_list: 26 | - Optical 27 | - Aux 1 28 | - USB 29 | - Bluetooth 30 | - Aux 2 31 | - Digital 32 | -------------------------------------------------------------------------------- /scripts/set_homeseer_dim_level.yaml: -------------------------------------------------------------------------------- 1 | set_homeseer_dim_level: 2 | alias: Set HomeSeer switch default dim level 3 | description: Automatically set dim level for HomeSeer WD100/WD200 switches (by turning them on to the desired brightness then immediately back off) 4 | fields: 5 | entity_id: 6 | description: The light that will configured. 7 | example: light.bedroom_light 8 | brightness: 9 | description: The default brightness as char from 1-255. 10 | example: 10 11 | sequence: 12 | - condition: template 13 | value_template: "{{ states(entity_id) == 'off' }}" 14 | - service: light.turn_on 15 | data_template: 16 | entity_id: "{{ entity_id }}" 17 | brightness: "{{ brightness }}" 18 | - service: light.turn_off 19 | data_template: 20 | entity_id: "{{ entity_id }}" 21 | -------------------------------------------------------------------------------- /esphome/air-sensor-2.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: air-sensor-2 3 | 4 | esp32: 5 | board: esp32dev 6 | 7 | packages: 8 | common: !include common/common.yaml 9 | 10 | i2c: 11 | sda: 12 12 | scl: 27 13 | scan: true 14 | id: bus_a 15 | 16 | sensor: 17 | - platform: sen5x 18 | id: sen54 19 | pm_1_0: 20 | name: PM <1µm Weight concentration 21 | pm_2_5: 22 | name: PM <2.5µm Weight concentration 23 | pm_4_0: 24 | name: PM <4µm Weight concentration 25 | pm_10_0: 26 | name: PM <10µm Weight concentration 27 | temperature: 28 | name: Temperature 29 | humidity: 30 | name: Humidity 31 | voc: 32 | name: VOC 33 | nox: 34 | name: NOX 35 | - platform: scd4x 36 | co2: 37 | name: "CO2" 38 | temperature: 39 | name: "SCD Temperature" 40 | humidity: 41 | name: "SCD Humidity" 42 | -------------------------------------------------------------------------------- /scripts/tech_time_over.yaml: -------------------------------------------------------------------------------- 1 | tech_time_over: 2 | alias: "Tech time is over" 3 | fields: 4 | message: 5 | description: The message said by Alexa after tech time is over. 6 | example: Time to go have breakfast 7 | variables: 8 | message: "Tech time is over" 9 | sequence: 10 | - service: media_player.turn_off 11 | target: 12 | entity_id: media_player.55_tcl_roku_tv 13 | - service: media_player.select_source 14 | target: 15 | entity_id: media_player.soundbar 16 | data: 17 | source: Aux 1 18 | - delay: 19 | hours: 0 20 | minutes: 0 21 | seconds: 12 22 | milliseconds: 0 23 | - service: notify.alexa_media_living_room 24 | data: 25 | data: 26 | type: tts 27 | message: "{{ message }}" 28 | - service: media_player.select_source 29 | target: 30 | entity_id: media_player.soundbar 31 | data: 32 | source: Optical 33 | -------------------------------------------------------------------------------- /scripts/water_backyard.yaml: -------------------------------------------------------------------------------- 1 | sprinkler_water_backyard: 2 | alias: "Sprinkler Water Backyard" 3 | sequence: 4 | - service: switch.turn_off 5 | entity_id: switch.maple_sprinkler 6 | - service: switch.turn_off 7 | entity_id: switch.apple_and_lemon_sprinkler 8 | - service: switch.turn_off 9 | entity_id: switch.vegetable_box_sprinkler 10 | - service: switch.turn_off 11 | entity_id: switch.lime_tree_sprinkler 12 | - service: switch.turn_off 13 | entity_id: switch.curb_sprinkler 14 | - service: switch.turn_off 15 | entity_id: switch.orange_tree_sprinkler 16 | - condition: time 17 | weekday: 18 | - mon 19 | - wed 20 | - fri 21 | - delay: '00:01' 22 | - service: switch.turn_on 23 | entity_id: switch.vegetable_box_sprinkler 24 | - delay: '00:25' 25 | - service: switch.turn_off 26 | entity_id: switch.vegetable_box_sprinkler 27 | - delay: '00:01' 28 | - service: switch.turn_on 29 | entity_id: switch.maple_sprinkler 30 | - delay: '00:25' 31 | - service: switch.turn_off 32 | entity_id: switch.maple_sprinkler 33 | - delay: '00:01' 34 | - service: switch.turn_on 35 | entity_id: switch.apple_and_lemon_sprinkler 36 | - delay: '00:25' 37 | - service: switch.turn_off 38 | entity_id: switch.apple_and_lemon_sprinkler 39 | -------------------------------------------------------------------------------- /esphome/backyard-step-lights.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: backyard-step-lights 3 | 4 | esp8266: 5 | board: d1_mini 6 | 7 | packages: 8 | common: !include common/common.yaml 9 | 10 | light: 11 | - platform: neopixelbus 12 | type: GRBW 13 | variant: SK6812 14 | pin: GPIO3 15 | num_leds: 86 16 | name: "Backyard Step Lights" 17 | effects: 18 | - addressable_fireworks: 19 | - addressable_flicker: 20 | - addressable_rainbow: 21 | - addressable_color_wipe: 22 | - addressable_scan: 23 | - addressable_random_twinkle: 24 | - addressable_twinkle: 25 | - addressable_twinkle: 26 | name: Custom Twinkle Effect 27 | twinkle_probability: 30% 28 | progress_interval: 4ms 29 | - addressable_lambda: 30 | name: Front Step Only 31 | lambda: |- 32 | it.all().fade_to_black(0); 33 | it.range(22, 66) = current_color; 34 | - addressable_lambda: 35 | name: Fake Front Louvres 36 | lambda: |- 37 | it.all().fade_to_black(0); 38 | it.range(32, 40) = current_color; 39 | it.range(48, 56) = current_color; 40 | - addressable_lambda: 41 | name: Fake Surround Louvres 42 | lambda: |- 43 | it.all().fade_to_black(0); 44 | it.range(7, 15) = current_color; 45 | it.range(32, 40) = current_color; 46 | it.range(48, 56) = current_color; 47 | it.range(75, 82) = current_color; 48 | -------------------------------------------------------------------------------- /esphome/sprinkler.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: sprinkler 3 | on_boot: 4 | priority: -100 5 | # Send a push notification on reboot in case something went wonky when running sprinkers 6 | then: 7 | - delay: 30s 8 | - homeassistant.service: 9 | service: notify.all_devices 10 | data: 11 | message: "Sprinkler controller rebooted." 12 | - homeassistant.service: 13 | service: persistent_notification.create 14 | data: 15 | message: "Sprinkler controller rebooted. If this was expected, disregard." 16 | title: "Sprinkler restart" 17 | 18 | esp8266: 19 | board: d1_mini_lite 20 | 21 | packages: 22 | common: !include common/common.yaml 23 | 24 | switch: 25 | - platform: gpio 26 | pin: 27 | number: D0 28 | inverted: yes 29 | name: "Maple Sprinkler" 30 | icon: "mdi:sprinkler-variant" 31 | - platform: gpio 32 | pin: 33 | number: D5 34 | inverted: yes 35 | name: "Apple and Lemon Sprinkler" 36 | icon: "mdi:sprinkler-variant" 37 | - platform: gpio 38 | pin: 39 | number: D2 40 | inverted: yes 41 | name: "Vegetable Box Sprinkler" 42 | icon: "mdi:sprinkler-variant" 43 | - platform: gpio 44 | pin: 45 | number: D1 46 | inverted: yes 47 | name: "Lime Tree Sprinkler" 48 | icon: "mdi:sprinkler-variant" 49 | - platform: gpio 50 | pin: 51 | number: D7 52 | inverted: yes 53 | name: "Curb Sprinkler" 54 | icon: "mdi:sprinkler-variant" 55 | - platform: gpio 56 | pin: 57 | number: D6 58 | inverted: yes 59 | name: "Orange Tree Sprinkler" 60 | icon: "mdi:sprinkler-variant" 61 | 62 | sensor: 63 | # Uptime sensor. 64 | - platform: uptime 65 | name: Sprinkler Controller Uptime 66 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BASE_DIR="$(shell pwd)" 2 | REMOTE_HOST=hassio@10.0.0.2 3 | REMOTE_CONFIG_DIR=/config 4 | 5 | .PHONY: test 6 | test: 7 | sh $(BASE_DIR)/venv/bin/activate && hass -c . --script check_config 8 | 9 | .PHONY: remote-test 10 | remote-test: 11 | ssh $(REMOTE_HOST) 'sudo -u homeassistant /bin/bash -c "source /srv/homeassistant/homeassistant_venv/bin/activate && hass --script check_config"' 12 | 13 | .PHONY: deploy 14 | deploy: 15 | $(info Deploying HA config to $(REMOTE_HOST).) 16 | rsync -av --rsync-path="sudo rsync" $(BASE_DIR)/*.yaml $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/ 17 | rsync -av --rsync-path="sudo rsync" $(BASE_DIR)/scripts/*.yaml $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/scripts/ 18 | rsync -av --rsync-path="sudo rsync" $(BASE_DIR)/esphome/*.yaml $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/esphome/ 19 | rsync -av --rsync-path="sudo rsync" $(BASE_DIR)/esphome/common/*.yaml $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/esphome/common/ 20 | rsync -av --rsync-path="sudo rsync" $(BASE_DIR)/panels/*.html $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/panels/ 21 | 22 | .PHONY: deploy-zwave 23 | deploy-zwave: 24 | $(info Deploying HA config to $(REMOTE_HOST).) 25 | rsync -av --rsync-path="sudo rsync" $(BASE_DIR)/*.xml $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/ 26 | 27 | .PHONY: pull-remote 28 | pull-remote: 29 | rsync -av --include='*yaml' --include='esphome' --include='scripts' --include='panels' --include='zwavegraph2.html' --include='scenes' --include='zwcfg*.xml' --exclude='*' $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/ ./ 30 | 31 | .PHONY: deploy-scripts 32 | deploy-scripts: 33 | rsync -av --delete --rsync-path="sudo rsync" $(BASE_DIR)/python_scripts $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/ 34 | 35 | .PHONY: deploy-custom-components 36 | deploy-custom-components: 37 | rsync -av --rsync-path="sudo rsync" $(BASE_DIR)/custom_components $(REMOTE_HOST):$(REMOTE_CONFIG_DIR)/ 38 | -------------------------------------------------------------------------------- /esphome/elijah-desk-lights.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: elijah-desk-lights 3 | 4 | esp8266: 5 | board: d1_mini 6 | 7 | packages: 8 | common: !include common/common.yaml 9 | 10 | output: 11 | - platform: esp8266_pwm 12 | pin: 13 | number: D3 14 | inverted: true 15 | mode: OUTPUT_OPEN_DRAIN 16 | frequency: 1000 Hz 17 | id: pwm_output 18 | 19 | binary_sensor: 20 | - platform: gpio 21 | internal: true 22 | pin: 23 | number: D4 24 | inverted: true 25 | mode: INPUT_PULLUP 26 | name: "Elijah Button" 27 | on_double_click: 28 | then: 29 | - homeassistant.service: 30 | service: light.toggle 31 | data: 32 | entity_id: light.elijahs_room_light 33 | - homeassistant.service: 34 | service: light.turn_off 35 | data: 36 | entity_id: light.elijah_desk_lights 37 | - homeassistant.service: 38 | service: light.turn_off 39 | data: 40 | entity_id: light.elijah_button_light 41 | 42 | # Example usage in a light 43 | light: 44 | - platform: monochromatic 45 | output: pwm_output 46 | name: "Elijah Button Light" 47 | effects: 48 | - pulse: 49 | - platform: neopixelbus 50 | type: GRBW 51 | color_correct: [60%, 60%, 60%, 100%] 52 | variant: SK6812 53 | pin: GPIO3 # RX pin 54 | num_leds: 83 55 | name: "Elijah Desk Lights" 56 | restore_mode: RESTORE_DEFAULT_OFF 57 | effects: 58 | - addressable_fireworks: 59 | - addressable_flicker: 60 | - addressable_rainbow: 61 | - addressable_color_wipe: 62 | - addressable_scan: 63 | - addressable_random_twinkle: 64 | - addressable_twinkle: 65 | - addressable_twinkle: 66 | name: Custom Twinkle Effect 67 | twinkle_probability: 30% 68 | progress_interval: 4ms 69 | -------------------------------------------------------------------------------- /esphome/master-bathroom-fan.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: master-bathroom-fan 3 | comment: Panasonic WhisperGreen FV-0511VKSL3 fan 4 | 5 | esp32: 6 | board: nodemcu-32s 7 | framework: 8 | type: arduino 9 | 10 | packages: 11 | common: !include common/common.yaml 12 | 13 | logger: 14 | level: VERBOSE 15 | 16 | external_components: 17 | - source: 18 | type: git 19 | url: https://github.com/johnboiles/panasonic-whispergreen-esphome 20 | components: [panasonic_whispergreen] 21 | # - source: 22 | # type: local 23 | # path: |- 24 | # /Users/johnboiles/Developer/repos/johnboiles/panasonic-whispergreen-uart/esphome/components 25 | # components: [panasonic_whispergreen] 26 | 27 | uart: 28 | id: whispergreen_uart 29 | baud_rate: 4800 30 | data_bits: 8 31 | parity: EVEN 32 | stop_bits: 1 33 | tx_pin: 34 | number: 19 35 | inverted: true 36 | rx_pin: 37 | number: 18 38 | inverted: true 39 | 40 | panasonic_whispergreen: 41 | id: whispergreen_bus 42 | uart_id: whispergreen_uart 43 | 44 | fan: 45 | - platform: panasonic_whispergreen 46 | name: "Master Bathroom Fan" 47 | panasonic_whispergreen_id: whispergreen_bus 48 | 49 | light: 50 | - platform: panasonic_whispergreen 51 | name: "Master Bathroom Fan Light" 52 | panasonic_whispergreen_id: whispergreen_bus 53 | 54 | binary_sensor: 55 | - platform: panasonic_whispergreen 56 | name: "WhisperGreen Occupancy" 57 | panasonic_whispergreen_id: whispergreen_bus 58 | device_class: occupancy 59 | 60 | sensor: 61 | - platform: panasonic_whispergreen 62 | name: "Master Bathroom Fan Power" 63 | panasonic_whispergreen_id: whispergreen_bus 64 | power_multiplier: 0.04 65 | power_offset: 4.0 66 | - platform: panasonic_whispergreen 67 | name: "Master Bathroom Fan Speed" 68 | panasonic_whispergreen_id: whispergreen_bus 69 | kind: speed 70 | -------------------------------------------------------------------------------- /esphome/garage-door.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: garage-door 3 | 4 | esp32: 5 | board: esp32dev 6 | 7 | packages: 8 | common: !include common/common.yaml 9 | 10 | sensor: 11 | - platform: ct_clamp 12 | internal: true 13 | sensor: adc_sensor 14 | name: "Measured Current" 15 | id: "sump_current" 16 | filters: 17 | - calibrate_linear: 18 | - 0 -> 0 19 | # Based on my Bonavita 1000w kettle 20 | - 0.2 -> 8.33333333 21 | - or: 22 | - throttle: 60s 23 | - delta: 0.1 24 | - platform: adc 25 | internal: true 26 | pin: 34 27 | id: adc_sensor 28 | 29 | switch: 30 | - platform: gpio 31 | internal: true 32 | pin: 12 33 | id: garage_door_relay 34 | - platform: gpio 35 | internal: true 36 | pin: 13 37 | id: debug_led 38 | 39 | binary_sensor: 40 | - id: garage_door_sensor 41 | internal: true 42 | platform: gpio 43 | pin: 44 | number: 27 45 | mode: INPUT_PULLUP 46 | inverted: False 47 | device_class: garage_door 48 | filters: 49 | - delayed_on_off: 20ms 50 | - platform: template 51 | name: "Sump Pump" 52 | lambda: |- 53 | if (id(sump_current).state > 2) { 54 | return true; 55 | } else { 56 | return false; 57 | } 58 | 59 | cover: 60 | - platform: template 61 | name: "Garage Door" 62 | lambda: |- 63 | if (id(garage_door_sensor).state) { 64 | return COVER_OPEN; 65 | } else { 66 | return COVER_CLOSED; 67 | } 68 | open_action: 69 | - switch.turn_on: garage_door_relay 70 | - delay: 1s 71 | - switch.turn_off: garage_door_relay 72 | close_action: 73 | - switch.turn_on: garage_door_relay 74 | - delay: 1s 75 | - switch.turn_off: garage_door_relay 76 | stop_action: 77 | - switch.turn_on: garage_door_relay 78 | - delay: 1s 79 | - switch.turn_off: garage_door_relay 80 | -------------------------------------------------------------------------------- /esphome/common/sonoff-s31.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: ${device_name} 3 | friendly_name: ${friendly_name} 4 | 5 | esp8266: 6 | board: esp01_1m 7 | 8 | packages: 9 | common: !include common.yaml 10 | 11 | logger: 12 | baud_rate: 0 # (UART logging interferes with cse7766) 13 | 14 | uart: 15 | rx_pin: RX 16 | baud_rate: 4800 17 | parity: EVEN 18 | 19 | binary_sensor: 20 | - platform: gpio 21 | id: side_button 22 | name: "Button" 23 | pin: 24 | number: GPIO0 25 | mode: INPUT_PULLUP 26 | inverted: True 27 | on_press: 28 | - switch.toggle: relay 29 | 30 | sensor: 31 | - platform: wifi_signal 32 | name: "WiFi Signal" 33 | update_interval: 60s 34 | - platform: cse7766 35 | id: power 36 | current: 37 | name: "Current" 38 | accuracy_decimals: 1 39 | filters: 40 | - or: 41 | - throttle: 60s 42 | - delta: 0.1 43 | voltage: 44 | name: "Input Voltage" 45 | accuracy_decimals: 1 46 | filters: 47 | - or: 48 | - throttle: 60s 49 | - delta: 5.0 50 | power: 51 | name: "Power Consumption" 52 | device_class: power 53 | unit_of_measurement: "W" 54 | accuracy_decimals: 1 55 | id: cse_power 56 | filters: 57 | - or: 58 | - throttle: 60s 59 | - delta: 5.0 60 | energy: 61 | name: "Energy" 62 | accuracy_decimals: 2 63 | filters: 64 | - throttle: 60s 65 | apparent_power: 66 | name: "Apparent Power" 67 | filters: 68 | - throttle_average: 60s 69 | power_factor: 70 | name: "Power Factor" 71 | accuracy_decimals: 2 72 | filters: 73 | - throttle_average: 60s 74 | - platform: total_daily_energy 75 | name: "Daily Energy" 76 | power_id: cse_power 77 | accuracy_decimals: 2 78 | 79 | switch: 80 | - platform: gpio 81 | id: relay 82 | pin: GPIO12 83 | name: "Power" 84 | 85 | time: 86 | - platform: sntp 87 | id: common_time 88 | 89 | status_led: 90 | pin: 91 | number: GPIO13 92 | inverted: True 93 | -------------------------------------------------------------------------------- /esphome/izzy-lamp.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: izzy-lamp 3 | 4 | esp8266: 5 | board: d1_mini 6 | 7 | packages: 8 | common: !include common/common.yaml 9 | 10 | output: 11 | - platform: esp8266_pwm 12 | pin: 13 | number: D3 14 | inverted: true 15 | mode: OUTPUT_OPEN_DRAIN 16 | frequency: 1000 Hz 17 | id: pwm_output 18 | 19 | binary_sensor: 20 | - platform: gpio 21 | internal: true 22 | pin: 23 | number: D4 24 | inverted: true 25 | mode: INPUT_PULLUP 26 | name: "Button" 27 | on_multi_click: 28 | - timing: 29 | - ON for at most 1s 30 | - OFF for at most 1s 31 | - ON for at most 1s 32 | - OFF for at least 0.2s 33 | then: 34 | - logger.log: "Double Clicked" 35 | - homeassistant.action: 36 | action: light.toggle 37 | data: 38 | entity_id: light.izzy_desk_lights 39 | - timing: 40 | - ON for 1s to 2s 41 | - OFF for at least 0.5s 42 | then: 43 | - logger.log: "Single Long Clicked" 44 | - timing: 45 | - ON for at most 1s 46 | - OFF for at least 0.5s 47 | then: 48 | - logger.log: "Single Short Clicked" 49 | - light.toggle: leds 50 | 51 | # Example usage in a light 52 | light: 53 | - platform: monochromatic 54 | output: pwm_output 55 | name: "Button Light" 56 | effects: 57 | - pulse: 58 | - id: leds 59 | platform: neopixelbus 60 | type: GRBW 61 | color_correct: [60%, 60%, 60%, 100%] 62 | variant: SK6812 63 | pin: GPIO3 # RX pin 64 | num_leds: 14 65 | name: "LEDs" 66 | restore_mode: RESTORE_DEFAULT_OFF 67 | effects: 68 | - addressable_fireworks: 69 | - addressable_flicker: 70 | - addressable_rainbow: 71 | - addressable_color_wipe: 72 | - addressable_scan: 73 | - addressable_random_twinkle: 74 | - addressable_twinkle: 75 | - addressable_twinkle: 76 | name: Custom Twinkle Effect 77 | twinkle_probability: 30% 78 | progress_interval: 4ms 79 | -------------------------------------------------------------------------------- /esphome/air-sensor.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: air-sensor 3 | 4 | esp32: 5 | board: esp32dev 6 | 7 | packages: 8 | common: !include common/common.yaml 9 | 10 | api: 11 | services: 12 | - service: mhz19_calibrate_zero 13 | then: 14 | - mhz19.calibrate_zero: mhz19_sensor 15 | 16 | uart: 17 | - id: "mhz19_uart" 18 | tx_pin: 17 19 | rx_pin: 16 20 | baud_rate: 9600 21 | - id: "pms5003_uart" 22 | tx_pin: 18 23 | rx_pin: 5 24 | baud_rate: 9600 25 | 26 | i2c: 27 | sda: 21 28 | scl: 22 29 | 30 | sensor: 31 | - platform: mhz19 32 | id: mhz19_sensor 33 | co2: 34 | name: "MH-Z19 CO2 Value" 35 | filters: 36 | - sliding_window_moving_average: 37 | window_size: 24 38 | send_every: 6 39 | temperature: 40 | name: "MH-Z19 Temperature" 41 | filters: 42 | - sliding_window_moving_average: 43 | window_size: 24 44 | send_every: 6 45 | update_interval: 10s 46 | automatic_baseline_calibration: true 47 | uart_id: "mhz19_uart" 48 | - platform: pmsx003 49 | type: PMSX003 50 | uart_id: "pms5003_uart" 51 | pm_1_0: 52 | name: "PM <1.0µm µg/m³" 53 | filters: 54 | - throttle_average: 60s 55 | pm_2_5: 56 | name: "PM <2.5µm µg/m³" 57 | filters: 58 | - throttle_average: 60s 59 | pm_10_0: 60 | name: "PM <10.0µm µg/m³" 61 | filters: 62 | - throttle_average: 60s 63 | - platform: dht 64 | model: DHT22 65 | pin: 19 66 | temperature: 67 | name: "DHT22 Temperature" 68 | filters: 69 | - throttle_average: 60s 70 | humidity: 71 | name: "DHT22 Humidity" 72 | filters: 73 | - throttle_average: 60s 74 | update_interval: 5s 75 | - platform: ccs811 76 | eco2: 77 | name: "CCS811 eCO2 Value" 78 | filters: 79 | - throttle_average: 60s 80 | tvoc: 81 | name: "CCS811 Total Volatile Organic Compound" 82 | filters: 83 | - throttle_average: 60s 84 | address: 0x5A 85 | update_interval: 5s 86 | baseline: 0x2FC2 87 | - platform: adc 88 | pin: 34 89 | id: no2 90 | name: "NO2" 91 | attenuation: 11db 92 | update_interval: 5s 93 | filters: 94 | - throttle_average: 60s 95 | # - lambda: return 0.05f + ((10-0.05)/(2.2-0.2444444)) * (x - 0.2444444f); -------------------------------------------------------------------------------- /sensor.yaml: -------------------------------------------------------------------------------- 1 | # - platform: miflora 2 | # mac: 'C4:7C:8D:62:73:AC' 3 | # name: Peace Lily 4 | # monitored_conditions: 5 | # - moisture 6 | # - temperature 7 | # - light 8 | # - conductivity 9 | # - battery 10 | 11 | # - platform: miflora 12 | # mac: 'C4:7C:8D:62:6C:D2' 13 | # name: Dracaena 14 | # monitored_conditions: 15 | # - moisture 16 | # - temperature 17 | # - light 18 | # - conductivity 19 | # - battery 20 | 21 | # - platform: thermal_comfort 22 | # sensors: 23 | # basement: 24 | # friendly_name: Basement 25 | # temperature_sensor: sensor.basement_temperature 26 | # humidity_sensor: sensor.basement_humidity 27 | # inside: 28 | # friendly_name: Inside 29 | # temperature_sensor: sensor.thermostat_temperature 30 | # humidity_sensor: sensor.thermostat_humidity 31 | # outside: 32 | # friendly_name: Outside 33 | # temperature_sensor: sensor.outside_temperature 34 | # humidity_sensor: sensor.outside_humidity 35 | # dht22: 36 | # friendly_name: DHT22 37 | # temperature_sensor: sensor.dht22_temperature 38 | # humidity_sensor: sensor.dht22_humidity 39 | 40 | - platform: history_stats 41 | name: Maple Sprinkler Runtime Today 42 | entity_id: switch.maple_sprinkler 43 | state: 'on' 44 | type: time 45 | start: '{{ now().replace(hour=0, minute=0, second=0) }}' 46 | end: '{{ now() }}' 47 | 48 | - platform: history_stats 49 | name: Apple and Lemon Sprinkler Runtime Today 50 | entity_id: switch.apple_and_lemon_sprinkler 51 | state: 'on' 52 | type: time 53 | start: '{{ now().replace(hour=0, minute=0, second=0) }}' 54 | end: '{{ now() }}' 55 | 56 | - platform: history_stats 57 | name: Vegetable Box Sprinkler Runtime Today 58 | entity_id: switch.vegetable_box_sprinkler 59 | state: 'on' 60 | type: time 61 | start: '{{ now().replace(hour=0, minute=0, second=0) }}' 62 | end: '{{ now() }}' 63 | 64 | - platform: history_stats 65 | name: Lime Tree Sprinkler Runtime Today 66 | entity_id: switch.lime_tree_sprinkler 67 | state: 'on' 68 | type: time 69 | start: '{{ now().replace(hour=0, minute=0, second=0) }}' 70 | end: '{{ now() }}' 71 | 72 | - platform: history_stats 73 | name: Curb Sprinkler Runtime Today 74 | entity_id: switch.curb_sprinkler 75 | state: 'on' 76 | type: time 77 | start: '{{ now().replace(hour=0, minute=0, second=0) }}' 78 | end: '{{ now() }}' 79 | 80 | - platform: history_stats 81 | name: Orange Tree Sprinkler Runtime Today 82 | entity_id: switch.orange_tree_sprinkler 83 | state: 'on' 84 | type: time 85 | start: '{{ now().replace(hour=0, minute=0, second=0) }}' 86 | end: '{{ now() }}' 87 | 88 | - platform: filter 89 | name: "Filtered TVOC" 90 | entity_id: sensor.ccs811_total_volatile_organic_compound 91 | filters: 92 | - filter: lowpass 93 | time_constant: 10 94 | - filter: time_simple_moving_average 95 | window_size: "00:05" 96 | precision: 0 97 | 98 | - platform: history_stats 99 | name: TV on Today 100 | entity_id: media_player.55_tcl_roku_tv 101 | state: 102 | - "on" 103 | - "playing" 104 | type: time 105 | start: "{{ now().replace(hour=4, minute=0, second=0) }}" 106 | end: "{{ now() }}" 107 | 108 | - platform: history_stats 109 | name: Sump Activated Count 110 | entity_id: binary_sensor.sump_pump 111 | type: count 112 | state: 113 | - "on" 114 | start: "{{ as_timestamp( now().replace(hour=0, minute=0, second=0) ) - now().weekday() * 86400 }}" 115 | end: "{{ now() }}" 116 | 117 | - platform: history_stats 118 | name: Sump Pump Runtime This Week 119 | entity_id: binary_sensor.sump_pump 120 | type: time 121 | state: 'on' 122 | # Since Monday morning at midnight 123 | start: "{{ as_timestamp( now().replace(hour=0, minute=0, second=0, microsecond=0) ) - now().weekday() * 86400 }}" 124 | end: "{{ now() }}" 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Home Assistant Configs 2 | 3 | This is my [Home Assistant](https://home-assistant.io) configuration. This also includes my [ESPHome](https://esphome.io) device configurations. 4 | 5 | ## Core Hardware 6 | 7 | I run [Home Assistant Operating System](https://github.com/home-assistant/operating-system) on a Raspberry Pi 4 (2GB model) with a USB SSD. I also use the Pi PoE hat so I can power cycle the Pi remotely if necessary (via Unifi controller). 8 | 9 | * [Raspberry Pi 4 Model B (2GB Ram)](https://www.adafruit.com/product/4292) 10 | * [StarTech.com SATA to USB Cable](https://www.amazon.com/gp/product/B00HJZJI84) 11 | * [Kingston 120GB SATA SSD](https://www.amazon.com/gp/product/B01N6JQS8C) 12 | * Note: If starting fresh I might consider a NVMe drive so that there's an easy upgrade path someday when/if there's a Pi with PCIe. 13 | * [Z-Wave.Me USB Stick](https://www.amazon.com/gp/product/B00QJEY6OC) 14 | * Note: If starting fresh I'd get [this GoControl Zigbee + Z-Wave stick](https://www.amazon.com/GoControl-CECOMINOD016164-HUSBZB-1-USB-Hub/dp/B01GJ826F8) so that I could use both Z-Wave and Zigbee. 15 | * [Raspberry Pi PoE Hat](https://www.adafruit.com/product/3953) 16 | 17 | ## Core Software 18 | 19 | I run [Home Assistant Operating System](https://github.com/home-assistant/operating-system). Installation is super easy (just use [balenaEtcher](https://www.balena.io/etcher/) to flash the OS image to your SSD from your computer) and it supports easy 1-click OS updates in the Home Assistant UI via [RAUC](https://rauc.io/). 20 | 21 | ## Integrations 22 | 23 | Off-the-shelf stuff I've integrated with: 24 | * Z-Wave (for wall switches, outlets, smoke alarms, door sensors, Yale Assure smart lock) 25 | * Ecobee 26 | * OctoPrint (3d-printer controller) 27 | * Yeelight 28 | * Apple HomeKit (for Siri and easy access from Apple devices) 29 | * Amazon Alexa 30 | * Unifi Controller 31 | * Unifi Gateway (custom component) 32 | * Network UPS Tools (NUT) 33 | * TPLink outlet 34 | * Route53 (for updating my DNS record) 35 | 36 | Stuff I've built: 37 | * [RTL433 MQTT](https://github.com/johnboiles/rtl-433-docker-pi) Temperature Sensors 38 | * [ESPHome IR Blaster](https://github.com/johnboiles/homeassistant-config/blob/master/esphome/ir_blaster.yaml) (controls my sound bar) 39 | * [ESPHome Fan Controller](https://github.com/johnboiles/homeassistant-config/blob/master/esphome/basement_fan.yaml) (controls an exhaust fan in my basement) 40 | * [ESPHome Air Sensor](https://github.com/johnboiles/homeassistant-config/blob/master/esphome/air_sensor.yaml) (reads CO2, temperature, humidity, particulates, and TVOCs in the air) 41 | * [ESPHome Garage Controller](https://github.com/johnboiles/homeassistant-config/blob/master/esphome/garage_door.yaml) (opens/closes my garage and reports open/closed status) 42 | * [ESPHome Sprinkler Controller](https://github.com/johnboiles/homeassistant-config/blob/master/esphome/sprinkler.yaml) (controls valves for my sprinklers) 43 | * [ESPHome RGB Lights Controller](https://github.com/johnboiles/homeassistant-config/blob/master/esphome/backyard_step_lights.yaml) (controls an RGB LED light strip under my patio step) 44 | 45 | ## Automations 46 | 47 | * Push notify when the 3d printer finishes (and attach a pic) 48 | * Activate scenes when I double tap or triple tap my HomeSeer Z-Wave light switches 49 | * Send an iOS critical notification if my garage is left open for 30 minutes 50 | * Change an LED color on my HomeSeer WD200 light switch when the garage is open 51 | * Set the default dim level for lights to dim at 9pm; set default level to full brightness at 7am 52 | * Push notify when the power goes out (my Pi and network gear have a battery backup) 53 | * Push notify when the smoke alarm is trigerred 54 | * Push notify when a Home Assistant update is available 55 | * Push notify when new firmware for one of my Unifi devices is available 56 | * Push notify when my Unifi Controller has new alerts 57 | * Recalibrate the CO2 sensor 4 hours after everyone leaves the house 58 | * Switch the soundbar to AUX input when Alexa is playing music; switch the soundbar to OPTICAL (for the TV) when Alexa is not playing music 59 | -------------------------------------------------------------------------------- /esphome/README.md: -------------------------------------------------------------------------------- 1 | # ESPHome Configs 2 | 3 | Home for my ESPHome config files that power various pieces of DIY hardware around my house. 4 | 5 | ## Air Sensor 6 | 7 | Air-quality sensor to monitor temperature, humidity, particulate count, CO2, and TVOCs with an ESP32 and some cheap-ish sensors. 8 | 9 | * ESP32 10 | * [PMS5003 High Precision Laser Dust Sensor](https://www.ebay.com/itm/PMS5003-High-Precision-Laser-Dust-Sensor-Module-PM1-0-PM2-5-PM10-Built-in-Fan-N-/263421941788?hash=item3d552bd81c) 11 | * [MHZ-19 Intelligent Infrared CO2 Module](http://www.winsen-sensor.com/products/ndir-co2-sensor/mh-z19.html) 12 | * [DHT22 Temperature & Humidity Sensor](https://www.adafruit.com/product/385) 13 | * CCS811 eCO2 and TVOC sensor 14 | 15 | This project also exposes a service to run the calibration on the MHZ19, so I can automate calibration to happen after the house has been unoccupied for a period. 16 | 17 | ## Garage Door 18 | 19 | Garage door controller that uses a relay and a magnetic reed switch. 20 | 21 | Hardware: 22 | * [NodeMCU 1.0](https://www.amazon.com/HiLetgo-Version-NodeMCU-Internet-Development/dp/B010O1G1ES) ESP8266 Wifi microcontroller (though I'd probably use a [Wemos D1 Mini](https://www.amazon.com/Makerfocus-NodeMcu-Development-ESP8266-ESP-12F/dp/B01N3P763C) if I started over.) 23 | * [5V relay](https://www.amazon.com/Tolako-Arduino-Indicator-Channel-Official/dp/B00VRUAHLE) to trigger the door 24 | * [Magnetic reed switch](https://www.amazon.com/uxcell-Window-Sensor-Magnetic-Recessed/dp/B00HR8CT8E) to detect whether the door is open or closed. 25 | 26 | The electronics are very simple. The relay is switched by a digital output from the microcontroller (the relay board linked above has a transistor to supply the necessary current to the relay). The reed switch is connected to ground and one of the digital inputs (because the ESP8266 has internal pullups, no extra resistor is necessary). Just connect to the normally disconnected side of your relay to the same two wires running to your existing garage door button. 27 | 28 | ![Fritzing diagram](https://raw.githubusercontent.com/johnboiles/esp-garage-opener/assets/images/fritzing.png) 29 | 30 | ## IR Blaster 31 | 32 | IR blaster for sending IR remote codes to my TV and soundbar. Electronics consist of two IR LEDs and a PN2222 transistor to switch the LEDs (since the ESP8266 can't source enough current to drive those LEDs). 33 | 34 | Hardware: 35 | * [Wemos D1 Mini](https://www.amazon.com/gp/product/B01N3P763C) 36 | * IR LED (from my parts box) 37 | * PN2222 transistor (from my parts box) 38 | 39 | ## Basement Fan 40 | 41 | Small DC exhaust blower fan to exhaust fumes from my basement. I use this to extract fumes from my solder station and other burn-y tools. 42 | 43 | Hardware: 44 | * [Wemos D1 Mini](https://www.amazon.com/gp/product/B01N3P763C) 45 | * [Attwood Quiet Blower](https://www.amazon.com/Attwood-1749-4-Blower-Resistant-4-Inch/dp/B003EX02DA) 46 | * [MOSFET board](https://www.amazon.com/gp/product/B01J78FX9S) 47 | * [4 inch aluminum duct](https://www.amazon.com/gp/product/B01N6DV33G) 48 | * [12V Power Supply](https://www.amazon.com/gp/product/B00MBBOWAU) 49 | * [Adjustable Regulator](https://www.amazon.com/gp/product/B01MQGMOKI) to power the Wemos D1 Mini. 50 | 51 | ## ESP32 Camera 52 | 53 | Simplest (and cheapest) security camera out there. Just an [ESP32 with a camera module](https://www.amazon.com/gp/product/B07QYTVZL6) in a [3d-printed box](https://www.thingiverse.com/thing:3463679). 54 | 55 | # Installing / Running 56 | 57 | ESPHome makes it very simple to install the software for this project. 58 | 59 | ## First time installation 60 | 61 | Install the `esphome` tool 62 | 63 | sudo pip install esphome 64 | 65 | Make a `secrets.yaml` with your WiFi credentials 66 | 67 | cp secrets.yaml.example secrets.yaml 68 | 69 | If you don't have it already, you probably need a driver for the CH340 USB->Serial chip. [This janky looking website](http://www.wch.cn/download/CH341SER_MAC_ZIP.html) is the chip manufacturer's official download page. 70 | 71 | ## To upload the firmware 72 | 73 | Replace `air_sensor.yaml` with the desired config and compile and upload the generated firmware. The first time you do this you'll need to connect over USB, but subsequent uploads can happen over wifi. 74 | 75 | esphome air_sensor.yaml run 76 | 77 | ## To read the logs while running 78 | 79 | esphome air_sensor.yaml logs 80 | -------------------------------------------------------------------------------- /esphome/ir-blaster.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: ir-blaster 3 | platformio_options: 4 | board_build.f_cpu: 160000000L 5 | 6 | esp8266: 7 | board: d1_mini 8 | 9 | packages: 10 | common: !include common/common.yaml 11 | 12 | # Enable Home Assistant API 13 | api: 14 | services: 15 | - service: transmit_nec 16 | variables: 17 | address: int 18 | command: int 19 | then: 20 | - remote_transmitter.transmit_nec: 21 | address: !lambda 'return address;' 22 | command: !lambda 'return command;' 23 | # I'm not sure how to use jinja {% if %} statements and return an int, 24 | # So instead I'm using an alternate method that accepts a string for command 25 | - service: transmit_nec_string 26 | variables: 27 | address: int 28 | command: string 29 | then: 30 | - remote_transmitter.transmit_nec: 31 | address: !lambda 'return address;' 32 | command: !lambda 'return (int)strtol(command.c_str(), NULL, 16);' 33 | - service: transmit_raw 34 | variables: 35 | code: int[] 36 | carrier_frequency: float 37 | then: 38 | - remote_transmitter.transmit_raw: 39 | code: !lambda 'return code;' 40 | carrier_frequency: !lambda 'return carrier_frequency;' 41 | - service: transmit_raw_repeat 42 | variables: 43 | code: int[] 44 | carrier_frequency: float 45 | repeat_times: int 46 | repeat_wait_time_us: int 47 | then: 48 | - remote_transmitter.transmit_raw: 49 | code: !lambda 'return code;' 50 | carrier_frequency: !lambda 'return carrier_frequency;' 51 | repeat: 52 | times: !lambda 'return repeat_times;' 53 | wait_time: !lambda 'return repeat_wait_time_us;' 54 | 55 | remote_transmitter: 56 | pin: D0 57 | carrier_duty_percent: 50% 58 | 59 | # Useful for debugging or investigating new IR codes 60 | # remote_receiver: 61 | # pin: 62 | # number: D2 63 | # inverted: True 64 | # dump: all 65 | # # Settings to optimize recognition of RF devices (only uncomment for RF) 66 | # tolerance: 50% 67 | # filter: 250us 68 | # idle: 4ms 69 | # buffer_size: 2kb 70 | 71 | external_components: 72 | - source: github://Palakis/esphome-hdmi-cec 73 | 74 | hdmi_cec: 75 | address: 0x05 # Audio system 76 | physical_address: 0x4000 77 | pin: D1 # GPIO5 78 | osd_name: "IR" 79 | on_message: 80 | - opcode: 0xC3 # Request ARC start 81 | then: 82 | - hdmi_cec.send: # Report ARC started 83 | destination: 0x0 84 | data: [ 0xC1 ] 85 | - opcode: 0x70 # System audio mode request 86 | then: 87 | - hdmi_cec.send: 88 | destination: 0xF 89 | data: [ 0x72, 0x01 ] 90 | # We can provide mute status and volume here but we don't know 91 | # What it is, so instead provide nothing 92 | # - opcode: 0x71 # Give audio status 93 | # then: 94 | # - hdmi_cec.send: 95 | # destination: 0x0 96 | # # data: [ 0x7A, 0x7F ] 97 | # data: [ 0x00, 0x00, 0x00 ] 98 | - opcode: 0x7D # Give audio system mode status 99 | then: 100 | - hdmi_cec.send: 101 | destination: 0x0 102 | data: [ 0x7E, 0x01 ] 103 | - opcode: 0x46 # Give OSD name 104 | then: 105 | - hdmi_cec.send: 106 | destination: 0x0 107 | data: [0x47, 0x65, 0x73, 0x70, 0x68, 0x6F, 0x6D, 0x65] # esphome 108 | - opcode: 0x8C # Give device Vendor ID 109 | then: 110 | - hdmi_cec.send: 111 | destination: 0xF 112 | data: [0x87, 0x00, 0x15, 0x82] 113 | - data: [0x44, 0x41] # User control pressed: volume up 114 | then: 115 | - logger.log: "Volume up" 116 | - remote_transmitter.transmit_nec: 117 | address: 0xFF00 118 | command: 0xBE41 119 | - data: [0x44, 0x42] # User control pressed: volume down 120 | then: 121 | - logger.log: "Volume down" 122 | - remote_transmitter.transmit_nec: 123 | address: 0xFF00 124 | command: 0xBA45 125 | - data: [0x44, 0x43] # User control pressed: volume mute 126 | then: 127 | - logger.log: "Volume mute" 128 | - remote_transmitter.transmit_nec: 129 | address: 0xFF00 130 | command: 0xB748 131 | -------------------------------------------------------------------------------- /esphome/basement-stereo.yaml: -------------------------------------------------------------------------------- 1 | esphome: 2 | name: basement-stereo-2 3 | friendly_name: Basement Stereo 4 | 5 | esp32: 6 | board: esp32-s3-devkitc-1 7 | variant: esp32s3 8 | flash_size: 16MB 9 | framework: 10 | type: esp-idf 11 | version: recommended 12 | sdkconfig_options: 13 | CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y" 14 | CONFIG_ESP32S3_DATA_CACHE_64KB: "y" 15 | CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y" 16 | CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB: "y" 17 | CONFIG_ESP32_S3_BOX_BOARD: "y" 18 | CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY: "y" 19 | 20 | CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP: "y" 21 | 22 | # Settings based on https://github.com/espressif/esp-adf/issues/297#issuecomment-783811702 23 | CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM: "16" 24 | CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM: "512" 25 | CONFIG_ESP32_WIFI_STATIC_TX_BUFFER: "y" 26 | CONFIG_ESP32_WIFI_TX_BUFFER_TYPE: "0" 27 | CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM: "8" 28 | CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM: "32" 29 | CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED: "y" 30 | CONFIG_ESP32_WIFI_TX_BA_WIN: "16" 31 | CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED: "y" 32 | CONFIG_ESP32_WIFI_RX_BA_WIN: "32" 33 | CONFIG_LWIP_MAX_ACTIVE_TCP: "16" 34 | CONFIG_LWIP_MAX_LISTENING_TCP: "16" 35 | CONFIG_TCP_MAXRTX: "12" 36 | CONFIG_TCP_SYNMAXRTX: "6" 37 | CONFIG_TCP_MSS: "1436" 38 | CONFIG_TCP_MSL: "60000" 39 | CONFIG_TCP_SND_BUF_DEFAULT: "65535" 40 | CONFIG_TCP_WND_DEFAULT: "65535" # Adjusted from linked settings to avoid compilation error 41 | CONFIG_TCP_RECVMBOX_SIZE: "512" 42 | CONFIG_TCP_QUEUE_OOSEQ: "y" 43 | CONFIG_TCP_OVERSIZE_MSS: "y" 44 | CONFIG_LWIP_WND_SCALE: "y" 45 | CONFIG_TCP_RCV_SCALE: "3" 46 | CONFIG_LWIP_TCPIP_RECVMBOX_SIZE: "512" 47 | 48 | CONFIG_BT_ALLOCATION_FROM_SPIRAM_FIRST: "y" 49 | CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY: "y" 50 | 51 | CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC: "y" 52 | CONFIG_MBEDTLS_SSL_PROTO_TLS1_3: "y" # TLS1.3 support isn't enabled by default in IDF 5.1.5 53 | 54 | psram: 55 | mode: quad 56 | speed: 80MHz 57 | 58 | packages: 59 | common: !include common/common.yaml 60 | 61 | wifi: 62 | power_save_mode: none 63 | 64 | # external_components: 65 | # - source: 66 | # type: git 67 | # url: https://github.com/esphome/home-assistant-voice-pe 68 | # ref: dev 69 | # components: 70 | # - media_player 71 | # - nabu 72 | # refresh: 0s 73 | 74 | i2s_audio: 75 | - id: i2s_output 76 | i2s_lrclk_pin: GPIO39 77 | i2s_bclk_pin: GPIO41 78 | # i2s_mclk_pin: GPIO40 79 | 80 | speaker: 81 | # - platform: i2s_audio 82 | # id: i2s_audio_speaker 83 | # sample_rate: 48000 84 | # i2s_dout_pin: GPIO38 85 | # bits_per_sample: 32bit 86 | # i2s_audio_id: i2s_output 87 | # dac_type: external 88 | # channel: stereo 89 | # timeout: never 90 | # buffer_duration: 100ms 91 | # Config for PCM5102A 92 | - platform: i2s_audio 93 | id: i2s_audio_speaker 94 | sample_rate: 48000 95 | i2s_dout_pin: GPIO38 96 | i2s_audio_id: i2s_output 97 | # i2s_comm_fmt: pcm 98 | dac_type: external 99 | channel: stereo 100 | timeout: never 101 | buffer_duration: 100ms 102 | - platform: mixer 103 | id: mixing_speaker 104 | output_speaker: i2s_audio_speaker 105 | num_channels: 2 106 | source_speakers: 107 | - id: announcement_mixing_input 108 | timeout: never 109 | - id: media_mixing_input 110 | timeout: never 111 | - platform: resampler 112 | id: announcement_resampling_speaker 113 | output_speaker: announcement_mixing_input 114 | sample_rate: 48000 115 | bits_per_sample: 16 116 | - platform: resampler 117 | id: media_resampling_speaker 118 | output_speaker: media_mixing_input 119 | sample_rate: 48000 120 | bits_per_sample: 16 121 | 122 | media_player: 123 | - platform: speaker 124 | name: Media Player 125 | announcement_pipeline: 126 | speaker: announcement_resampling_speaker 127 | format: FLAC # FLAC is the least processor intensive codec 128 | num_channels: 1 # Stereo audio is unnecessary for announcements 129 | sample_rate: 48000 130 | media_pipeline: 131 | speaker: media_resampling_speaker 132 | format: FLAC # FLAC is the least processor intensive codec 133 | num_channels: 2 134 | sample_rate: 48000 -------------------------------------------------------------------------------- /esphome/shelly-em1.yaml: -------------------------------------------------------------------------------- 1 | substitutions: 2 | # 120A clamp (3000:1): 1.143207411 3 | # 50A clamp (2400:1): 1.156612516 4 | # 50A Victron clamp (2000:1): 0.76 5 | scale_a_power: '1.143207411' 6 | scale_b_power: '-1.143207411' 7 | # Consider calibrating CT clamps, measurements were closer to the stock Shelly EM firmware for me without calibration 8 | # See: https://community.home-assistant.io/t/anyone-using-shelly-em/149867 9 | 10 | esphome: 11 | name: shelly-em1 12 | 13 | esp8266: 14 | board: esp01_1m 15 | 16 | packages: 17 | common: !include common/common.yaml 18 | 19 | time: 20 | - platform: homeassistant 21 | timezone: America/Chicago 22 | 23 | i2c: 24 | sda: GPIO12 25 | scl: GPIO14 26 | 27 | sensor: 28 | - platform: ade7953_i2c 29 | # WARNING: Prevent overheating by setting this IRQ pin! - See https://esphome.io/components/sensor/ade7953.html 30 | irq_pin: GPIO13 31 | voltage: 32 | name: Voltage 33 | id: voltage 34 | filters: 35 | - or: 36 | - delta: 1% 37 | - throttle_average: 60s 38 | frequency: 39 | name: Frequency 40 | id: frequency 41 | filters: 42 | - throttle: 60s 43 | current_a: 44 | name: Phase 1 Current 45 | id: current_phase_1 46 | filters: 47 | - or: 48 | - delta: 10% 49 | - throttle_average: 15s 50 | current_b: 51 | name: Phase 2 Current 52 | id: current_phase_2 53 | filters: 54 | - or: 55 | - delta: 10% 56 | - throttle_average: 15s 57 | active_power_a: 58 | name: Phase 1 Power 59 | id: power_phase_1 60 | filters: 61 | - multiply: $scale_a_power 62 | - or: 63 | - delta: 10% 64 | - throttle_average: 15s 65 | # In case you don't want negative power values. I don't see why you wouldn't - this allows to measure returned power, for instance by PV panels. 66 | # Regarding the energy calculation with both forward and return energy, this may need further consideration. 67 | #- lambda: if (x <= 0.0) return 0; else return x * $scale_a_power; 68 | active_power_b: 69 | name: Phase 2 Power 70 | id: power_phase_2 71 | filters: 72 | - multiply: $scale_b_power 73 | - or: 74 | - delta: 10% 75 | - throttle_average: 15s 76 | #- lambda: if (x <= 0.0) return 0; else return x * $scale_b_power; 77 | apparent_power_a: 78 | name: Phase 1 Apparent Power 79 | id: apparent_power_phase_1 80 | filters: 81 | - multiply: $scale_a_power 82 | - or: 83 | - delta: 10% 84 | - throttle_average: 15s 85 | apparent_power_b: 86 | name: Phase 2 Apparent Power 87 | id: apparent_power_phase_2 88 | filters: 89 | - multiply: $scale_b_power 90 | - or: 91 | - delta: 10% 92 | - throttle_average: 15s 93 | power_factor_a: 94 | name: Phase 1 Power Factor 95 | id: power_factor_phase_1 96 | filters: 97 | - throttle_average: 15s 98 | power_factor_b: 99 | name: Phase 2 Power Factor 100 | id: power_factor_phase_2 101 | filters: 102 | - throttle_average: 15s 103 | reactive_power_a: 104 | name: Phase 1 Reactive Power 105 | id: reactive_power_phase_1 106 | filters: 107 | - multiply: $scale_a_power 108 | - or: 109 | - delta: 10% 110 | - throttle_average: 15s 111 | reactive_power_b: 112 | name: Phase 2 Reactive Power 113 | id: reactive_power_phase_2 114 | filters: 115 | - multiply: $scale_b_power 116 | - or: 117 | - delta: 10% 118 | - throttle_average: 15s 119 | # Short (internal) update interval while using the throttling settings in all sensors above (provides results close to the native Shellys) 120 | update_interval: 1s 121 | 122 | - platform: total_daily_energy 123 | name: Phase 1 Energy 124 | id: energy_phase_1 125 | power_id: power_phase_1 126 | filters: 127 | # Multiplication factor from W to kWh is 0.001 128 | - multiply: 0.001 129 | - throttle: 60s 130 | unit_of_measurement: kWh 131 | 132 | - platform: total_daily_energy 133 | name: Phase 2 Energy 134 | id: energy_phase_2 135 | power_id: power_phase_2 136 | filters: 137 | # Multiplication factor from W to kWh is 0.001 138 | - multiply: 0.001 139 | - throttle: 60s 140 | unit_of_measurement: kWh 141 | 142 | # NTC Temperature 143 | - platform: ntc 144 | sensor: temp_resistance_reading 145 | name: "Temperature" 146 | unit_of_measurement: "°C" 147 | calibration: 148 | b_constant: 3350 149 | reference_resistance: 10kOhm 150 | reference_temperature: 298.15K 151 | - platform: resistance 152 | id: temp_resistance_reading 153 | sensor: temp_analog_reading 154 | configuration: DOWNSTREAM 155 | # This value is a guess, based on the temperature values compared to native Shelly EM devices 156 | resistor: 100kOhm 157 | - platform: adc 158 | id: temp_analog_reading 159 | pin: A0 160 | 161 | status_led: 162 | pin: 163 | number: GPIO0 164 | inverted: yes 165 | 166 | switch: 167 | - platform: gpio 168 | name: Shelly EM Switch 169 | pin: GPIO15 170 | id: relay 171 | -------------------------------------------------------------------------------- /configuration.yaml: -------------------------------------------------------------------------------- 1 | ## Section: Core config 2 | homeassistant: 3 | # Name of the location where Home Assistant is running 4 | name: Boiles Home 5 | # Location required to calculate the time the sun rises and sets 6 | latitude: !secret home_latitude 7 | longitude: !secret home_longitude 8 | # Impacts weather/sunrise data (altitude above sea level in meters) 9 | elevation: !secret home_elevation 10 | unit_system: us_customary 11 | # Pick yours from here: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones 12 | time_zone: America/Los_Angeles 13 | customize: !include customize.yaml 14 | country: US 15 | packages: !include_dir_named packages 16 | 17 | recorder: 18 | db_url: !secret mysql_db_url 19 | 20 | logger: 21 | default: warning 22 | 23 | http: 24 | 25 | ## Section: Default config 26 | 27 | # See https://www.home-assistant.io/integrations/default_config/ 28 | # `default_config` is a meta-component and configures a default set of 29 | # integrations for Home Assistant to load. The integrations that will be 30 | # loaded are: automation, cloud, config, frontend, history, logbook, map, 31 | # mobile_app, person, script, ssdp, sun, system_health, zeroconf 32 | 33 | # default_config: 34 | energy: 35 | 36 | automation: !include automations.yaml 37 | 38 | # Nabu Casa cloud settings 39 | cloud: 40 | 41 | # Enables configuration UI 42 | config: 43 | 44 | # Enables the frontend 45 | frontend: 46 | 47 | # Enables support for tracking state changes over time. 48 | history: 49 | 50 | input_text: 51 | 52 | # View all events in a logbook 53 | logbook: 54 | 55 | mobile_app: 56 | 57 | person: 58 | 59 | script: !include_dir_merge_named scripts 60 | 61 | # Simple Service Discovery Protocol 62 | ssdp: 63 | 64 | # Track the sun 65 | sun: 66 | 67 | system_health: 68 | 69 | zeroconf: 70 | 71 | media_source: 72 | 73 | ## Section: Integration Config 74 | 75 | ios: 76 | 77 | # Allows you to issue voice commands from the frontend in enabled browsers 78 | conversation: 79 | 80 | homekit: 81 | entity_config: 82 | # switch.maple_sprinkler: 83 | # type: sprinkler 84 | # switch.apple_and_lemon_sprinkler: 85 | # type: sprinkler 86 | # switch.vegetable_box_sprinkler: 87 | # type: sprinkler 88 | # switch.orange_tree_sprinkler: 89 | # type: sprinkler 90 | # switch.lime_tree_sprinkler: 91 | # type: sprinkler 92 | # switch.curb_sprinkler: 93 | # type: sprinkler 94 | binary_sensor.front_door: 95 | linked_battery_sensor: sensor.front_door_battery_level 96 | binary_sensor.back_door: 97 | linked_battery_sensor: sensor.back_door_battery_level 98 | # camera.octoprint_camera: 99 | # stream_source: http://10.0.2.17/webcam/?action=stream 100 | filter: 101 | include_entities: 102 | - binary_sensor.front_door 103 | - binary_sensor.back_door 104 | - binary_sensor.basement_side_door 105 | - binary_sensor.basement_motion_detected 106 | exclude_domains: 107 | # Accessory mode entities as per https://www.home-assistant.io/integrations/homekit/#accessory-mode 108 | - media_player 109 | - remote 110 | - lock 111 | - camera 112 | - cover 113 | # Others 114 | - group 115 | - automation 116 | - script 117 | - device_tracker 118 | - binary_sensor 119 | - person 120 | - alarm_control_panel 121 | - input_boolean 122 | - input_text 123 | exclude_entity_globs: 124 | - switch.schedule_* 125 | - '*.octoprint_*' 126 | - switch.heat_pump_* 127 | - '*basement_stereo_*' 128 | - sensor.pg_e_* 129 | - switch.*_sprinkler 130 | exclude_entities: 131 | - switch.3d_printer 132 | - switch.shutoff_valve 133 | - button.elijah_fan_turn_off 134 | - button.izzy_fan_turn_off 135 | - switch.john_s_eight_sleep_side_next_alarm 136 | - switch.christina_s_eight_sleep_side_next_alarm 137 | - switch.shelly_em1_shelly_em_switch 138 | - switch.heat_pump_power 139 | 140 | route53: 141 | aws_access_key_id: !secret route53_access_key_id 142 | aws_secret_access_key: !secret route53_secret_access_key 143 | zone: !secret route53_zone 144 | domain: !secret route53_domain 145 | records: 146 | - house 147 | 148 | ## Section: Component configuration 149 | 150 | group: !include group.yaml 151 | 152 | python_script: 153 | 154 | sensor: !include sensor.yaml 155 | 156 | template: 157 | - sensor: 158 | - default_entity_id: sensor.basement_smoke_alarm_state 159 | icon: hass:smoke-detector 160 | name: Basement Smoke Alarm 161 | state: >- 162 | {%- if is_state("sensor.basement_smoke_alarm_alarm_level", "0") -%}Clear 163 | {%- elif is_state("sensor.basement_smoke_alarm_alarm_type", "1") -%}Fire 164 | {%- elif is_state("sensor.basement_smoke_alarm_alarm_type", "2") -%}CO 165 | {%- elif is_state("sensor.basement_smoke_alarm_alarm_type", "12") -%}Testing 166 | {%- elif is_state("sensor.basement_smoke_alarm_alarm_type", "13") -%}Clear 167 | {% else -%}Unknown{%- endif -%} 168 | - switch: 169 | - turn_on: 170 | - data: 171 | entity_id: climate.heat_pump 172 | fan_mode: high 173 | action: climate.set_fan_mode 174 | turn_off: 175 | - data: 176 | entity_id: climate.heat_pump 177 | fan_mode: auto 178 | action: climate.set_fan_mode 179 | default_entity_id: switch.hvac_fan 180 | name: Fan 181 | state: '{{ is_state_attr(''climate.heat_pump'', ''fan_mode'', ''high'') }}' 182 | 183 | # From https://gist.github.com/AdamNaj/cbf4d792a22f443fe9d354e4dca4de00 184 | panel_custom: 185 | - name: zwavegraph2 186 | sidebar_title: Z-Wave Graph 187 | sidebar_icon: mdi:access-point-network 188 | url_path: zwave 189 | 190 | # Used for the automation that notifies every 30 min when the garage is open. 191 | timer: 192 | garage_door: 193 | duration: '00:30:00' 194 | 195 | media_player: 196 | - platform: universal 197 | name: Soundbar 198 | state_template: 'on' 199 | children: 200 | - media_player.living_room 201 | - media_player.everywhere 202 | commands: 203 | turn_on: 204 | service: esphome.ir_blaster_transmit_nec 205 | data: 206 | address: 0xFF00 207 | # The following command is the correct command for on/off, but HomeKit 208 | # has a quirk where it tries to make sure the soundbar is on before sending 209 | # volume commands. But since the on/off IR codes are the same this ends 210 | # up turning the sound bar off. I'm working around this by just sending the 211 | # volume up command since it also will turn on the sound bar. 212 | # command: 0x02FD 213 | command: 0xBE41 214 | turn_off: 215 | service: esphome.ir_blaster_transmit_nec 216 | data: 217 | address: 0xFF00 218 | command: 0xBF40 219 | volume_up: 220 | service: esphome.ir_blaster_transmit_nec 221 | data: 222 | address: 0xFF00 223 | command: 0xBE41 224 | volume_down: 225 | service: esphome.ir_blaster_transmit_nec 226 | data: 227 | address: 0xFF00 228 | command: 0xBA45 229 | volume_mute: 230 | service: esphome.ir_blaster_transmit_nec 231 | data: 232 | address: 0xFF00 233 | command: 0xB748 234 | select_source: 235 | service: esphome.ir_blaster_transmit_nec_string 236 | data_template: 237 | address: 0xFF00 238 | command: >- 239 | {%- if source == 'Optical' -%} 240 | 0x37C8 241 | {%- elif source == 'Aux 1' -%} 242 | 0x4EB1 243 | {%- elif source == 'USB' -%} 244 | 0x5EA1 245 | {%- elif source == 'Bluetooth' -%} 246 | 0xDD22 247 | {%- elif source == 'Aux 2' -%} 248 | 0x4DB2 249 | {%- elif source == 'Digital' -%} 250 | 0x36C9 251 | {%- endif -%} 252 | 253 | notify: 254 | - name: all_devices 255 | platform: group 256 | services: 257 | - service: mobile_app_iphone_15_pro 258 | -------------------------------------------------------------------------------- /scripts/inovelli_led.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Calculation References: 3 | # https://nathanfiscus.github.io/inovelli-notification-calc/ 4 | # https://community.inovelli.com/t/home-assistant-2nd-gen-switch-rgb-working/168/62 5 | # https://docs.google.com/spreadsheets/d/1bEpujdvBPZY9Fl61PZLUWuHanD2VAkRORFZ5D9xjLzA/edit?usp=sharing 6 | # 7 | # Changes: 8 | # July 22, 2020: Incorporating changes from Kevin Schlichter. 9 | # https://github.com/kschlichter/Home-Assistant-Inovelli-Red-Dimmer-Switch 10 | # 11 | # September 17, 2020: There are some massive improvements to my version of this code. Here are the highlights: 12 | # 1. Choose - using the recently added choose: feature a separate call has been created for the Z-wave and OZW 13 | # versions of the service call. 14 | # 2. Variables - using 0.115’s new variables: feature the variables sent each service call only have to be 15 | # calculated once. 16 | # 3. Supported Features - I realized that I could probably tell the difference between modules using the 17 | # “supported_features” attribute of each switch. For example my dimmer’s supported features is “33”. 18 | # 19 | # September 18, 2020: Added "model" parameter with options of dimmer, switch, combo_light, combo_fan. This replaces 20 | # supported_features as the combo fan/light switch also had the same supported_features value. 21 | # 22 | # February 24, 2021: Added support for Z-Wave JS in place of OpenZwave (ozw). 23 | # The ozw code is remarked out for those that still need it. 24 | # 25 | # February 27, 2021: 26 | # 1. Added zwave_integration at top of "variables:" section to allow users to define which integration is 27 | # installed ("zwave", "ozw", "zwave_js"). I just don't see a simple way to auto-detect this. 28 | # 2. Added a comment describing the "model" variable. 29 | # 3. Replaced personal "script.debug" service call with universal "persistent_notification.create". 30 | # Unremarking these lines could help you troubleshoot why something isn't working as expected. 31 | # 4. Updated broken spreadsheet link with public copy stored in my Google Docs account. 32 | # Thanks for the heads up Kevin Schlichter! 33 | # 34 | # March 26, 2021 35 | # 1. Added fields to help users experimenting in the Services Developer Tool. 36 | # 37 | # April 3, 2021 38 | # Incorporated @firstof9's changes: 39 | # 1. Set execution mode to "parallel" to all this script to potentially run on more than one devices simultaneously. 40 | # 2. Implement ZWave JS's new zwave_js.bulk_set_partial_config_parameters command. 41 | # Source: https://gist.github.com/firstof9/b88d072a81c54b314fe7ddb901fc5c29 42 | # 43 | # May 10, 2021 44 | # Incorporated @koconut's corrected "Off code". 45 | # Source: https://community.home-assistant.io/t/inovelli-z-wave-red-series-notification-led/165483/146 46 | # 47 | inovelli_led: 48 | mode: parallel 49 | variables: 50 | # REQUIRED to be one of these options: "zwave", "ozw", "zwave_js" 51 | # Advanced: If you'd like to have your device list filtered in the Services Developer Tool, 52 | # then unremark out "integration: zwave_js" under the fields section, and change the integration 53 | # name to match. 54 | zwave_integration: "zwave_js" 55 | 56 | # * Strongly recommended -> Use the passed model type ("dimmer", "switch", "combo_light") when present. 57 | # * If not present, then attempt to identify the type using the "product_name" attribute (which is only 58 | # unfortunately only available in the original zwave integration). 59 | # * Finally, assume the model type is "dimmer". 60 | model: | 61 | {% if model is string %} 62 | {{ model }} 63 | {%- elif state_attr(entity_id, 'product_name') is string %} 64 | {%- if 'LZW31' in state_attr(entity_id, 'product_name') %} 65 | dimmer 66 | {%- elif 'LZW36' in state_attr(entity_id, 'product_name') %} 67 | combo_light 68 | {%- else %} 69 | switch 70 | {%- endif %} 71 | {%- else %} 72 | dimmer 73 | {%- endif %} 74 | parameters: 75 | dimmer: 16 76 | combo_light: 24 77 | combo_fan: 25 78 | switch: 8 79 | node_id: '{{ state_attr(entity_id,"node_id") }}' 80 | color: | 81 | {%- if color is not number %} 82 | {{ color|default("Yellow")|title }} 83 | {%- else %} 84 | {{ color|int }} 85 | {% endif %} 86 | # 1-10 87 | level: "{{ level|default(4)|int }}" 88 | duration: '{{ duration|default("Indefinitely")|title }}' 89 | effect: '{{ effect|default("Blink")|title }}' 90 | colors: 91 | "Off": 0 92 | "Red": 1 93 | "Orange": 21 94 | "Yellow": 42 95 | "Green": 85 96 | "Cyan": 127 97 | "Teal": 145 98 | "Blue": 170 99 | "Purple": 195 100 | "Light Pink": 220 101 | "Pink": 234 102 | durations: 103 | "Off": 0 104 | "1 Second": 1 105 | "2 Seconds": 2 106 | "3 Seconds": 3 107 | "4 Seconds": 4 108 | "5 Seconds": 5 109 | "6 Seconds": 6 110 | "7 Seconds": 7 111 | "8 Seconds": 8 112 | "9 Seconds": 9 113 | "10 Seconds": 10 114 | "15 Seconds": 15 115 | "20 Seconds": 20 116 | "25 Seconds": 25 117 | "30 Seconds": 30 118 | "35 Seconds": 35 119 | "40 Seconds": 40 120 | "45 Seconds": 45 121 | "50 Seconds": 50 122 | "55 Seconds": 55 123 | "60 Seconds": 60 124 | "2 Minutes": 62 125 | "3 Minutes": 63 126 | "4 Minutes": 64 127 | "10 Minutes": 70 128 | "15 Minutes": 75 129 | "30 Minutes": 90 130 | "45 Minutes": 105 131 | "1 Hour": 120 132 | "2 Hours": 122 133 | "Indefinitely": 255 134 | effects_dimmer: 135 | "Off": 0 136 | "Solid": 1 137 | "Chase": 2 138 | "Fast Blink": 3 139 | "Slow Blink": 4 140 | "Blink": 4 141 | "Pulse": 5 142 | "Breath": 5 143 | effects_switch: 144 | "Off": 0 145 | "Solid": 1 146 | "Fast Blink": 2 147 | "Slow Blink": 3 148 | "Blink": 3 149 | "Pulse": 4 150 | "Breath": 4 151 | sequence: 152 | # Preform the Inovelli math. 153 | - variables: 154 | parameter: "{{ parameters[model|lower] }}" 155 | color: "{{ colors[color|title]|int }}" 156 | duration: "{{ durations[duration|title] }}" 157 | effect: | 158 | {% if model == "switch" %} 159 | {{- effects_switch[effect|title] }} 160 | {%- else %} 161 | {{- effects_dimmer[effect|title] }} 162 | {% endif %} 163 | inovelli_math: | 164 | {%- if effect|int > 0 %} 165 | {{ color|int + (level|int * 256) + (duration|int * 65536) + (effect|int * 16777216) }} 166 | {%- else %} 167 | 0 168 | {% endif %} 169 | # Unremark to provide an notification with troubleshooting information. 170 | # - service: persistent_notification.create 171 | # data: 172 | # title: "DEBUG: script.inovelli_led" 173 | # notification_id: "inovelli_led" 174 | # message: | 175 | # zwave_integration: {{ zwave_integration }} 176 | # model: {{ model }} 177 | # color: '{{ color|title }}' 178 | # level: '{{ level }}' 179 | # duration: '{{ duration|title }}' 180 | # effect: '{{ effect|title }}' 181 | # node_id: '{{ node_id }}' 182 | # parameter: '{{ parameter }}' 183 | # value: '{{ inovelli_math }}' 184 | 185 | - choose: 186 | # The Z-Wave JS integration requires this service call. 187 | - conditions: 188 | - '{{ zwave_integration == "zwave_js" }}' 189 | sequence: 190 | # Clear the previous effect. 191 | - service: zwave_js.bulk_set_partial_config_parameters 192 | target: 193 | entity_id: "{{ entity_id }}" 194 | data: 195 | parameter: "{{ parameter }}" 196 | value: '16714410' 197 | 198 | # Start the new effect, unless we were just turning it off. 199 | - choose: 200 | - conditions: 201 | - '{{ inovelli_math > 0 }}' 202 | sequence: 203 | - service: zwave_js.bulk_set_partial_config_parameters 204 | target: 205 | entity_id: "{{ entity_id }}" 206 | data: 207 | parameter: "{{ parameter }}" 208 | value: "{{ inovelli_math }}" 209 | 210 | # The OZW integration requires this service call. 211 | - conditions: 212 | - '{{ zwave_integration == "ozw" }}' 213 | sequence: 214 | # Clear the previous effect. 215 | - service: ozw.set_config_parameter 216 | data: 217 | node_id: "{{ node_id }}" 218 | parameter: "{{ parameter }}" 219 | value: 0 220 | 221 | # Start the new effect. 222 | - service: ozw.set_config_parameter 223 | data: 224 | node_id: "{{ node_id }}" 225 | parameter: "{{ parameter }}" 226 | value: "{{ inovelli_math }}" 227 | 228 | # The Z-wave integration requires this service call. 229 | default: 230 | # Clear the previous effect. 231 | - service: zwave.set_config_parameter 232 | data: 233 | node_id: "{{ node_id }}" 234 | parameter: "{{ parameter }}" 235 | size: 4 236 | value: 0 237 | 238 | # Start the new effect. 239 | - service: zwave.set_config_parameter 240 | data: 241 | node_id: "{{ node_id }}" 242 | parameter: "{{ parameter }}" 243 | size: 4 244 | value: "{{ inovelli_math }}" 245 | 246 | fields: 247 | entity_id: 248 | description: Light or switch which represents 249 | example: light.family_room 250 | selector: 251 | entity: 252 | #integration: zwave_js 253 | model: 254 | description: 'Device type: dimmer (default), switch, combo_light' 255 | example: dimmer 256 | selector: 257 | select: 258 | options: 259 | - dimmer 260 | - switch 261 | - combo_light 262 | color: 263 | description: 'Choose a color.' 264 | example: purple 265 | selector: 266 | select: 267 | options: 268 | - "Off" 269 | - Red 270 | - Orange 271 | - Yellow 272 | - Green 273 | - Cyan 274 | - Teal 275 | - Blue 276 | - Purple 277 | - Light Pink 278 | - Pink 279 | effect: 280 | description: 'Choose an effect.' 281 | example: blink 282 | selector: 283 | select: 284 | options: 285 | - "Off" 286 | - Solid 287 | - Chase 288 | - Fast Blink 289 | - Slow Blink 290 | - Blink 291 | - Pulse 292 | - Breath 293 | duration: 294 | description: 'How long should the effect run?' 295 | example: 10 seconds 296 | selector: 297 | select: 298 | options: 299 | - "Off" 300 | - 1 Second 301 | - 2 Seconds 302 | - 3 Seconds 303 | - 4 Seconds 304 | - 5 Seconds 305 | - 6 Seconds 306 | - 7 Seconds 307 | - 8 Seconds 308 | - 9 Seconds 309 | - 10 Seconds 310 | - 15 Seconds 311 | - 20 Seconds 312 | - 25 Seconds 313 | - 30 Seconds 314 | - 35 Seconds 315 | - 40 Seconds 316 | - 45 Seconds 317 | - 50 Seconds 318 | - 55 Seconds 319 | - 60 Seconds 320 | - 2 Minutes 321 | - 3 Minutes 322 | - 4 Minutes 323 | - 10 Minutes 324 | - 15 Minutes 325 | - 30 Minutes 326 | - 45 Minutes 327 | - 1 Hour 328 | - 2 Hours 329 | - Indefinitely -------------------------------------------------------------------------------- /automations.yaml: -------------------------------------------------------------------------------- 1 | - id: 282d7e1b370b46bfa5aa73521d93d8d2 2 | alias: 'Notification: 3d print finished' 3 | trigger: 4 | - platform: state 5 | entity_id: binary_sensor.octoprint_printing 6 | from: 'on' 7 | to: 'off' 8 | action: 9 | - service: camera.snapshot 10 | data: 11 | entity_id: camera.octoprint_camera 12 | filename: /config/www/camera/3d-print.jpg 13 | - service: notify.all_devices 14 | data: 15 | message: 3D print has finished 16 | data: 17 | image: /local/camera/3d-print.jpg 18 | mode: single 19 | - id: d585d760542f4186a44679bece1487d3 20 | alias: 'Bedroom: Play Roll Over Easy' 21 | description: Plays Roll Over Easy on BFF.fm on the bedroom Echo via TuneIn 22 | trigger: 23 | - platform: time 24 | at: 07:31:00 25 | condition: 26 | - condition: time 27 | weekday: 28 | - thu 29 | action: 30 | - service: media_player.volume_set 31 | data: 32 | entity_id: media_player.bedroom 33 | volume_level: 0.3 34 | - service: media_player.play_media 35 | data: 36 | entity_id: media_player.bedroom 37 | media_content_id: BFF.fm 38 | media_content_type: TUNEIN 39 | mode: single 40 | - id: 1342127157ed4f988e2dfc5de60cfc69 41 | alias: 'Dining Room: Turn off all lights with a triple tap down' 42 | trigger: 43 | - event_type: zwave_js_value_notification 44 | event_data: 45 | node_id: 8 46 | property_key: '002' 47 | value: KeyPressed3x 48 | platform: event 49 | action: 50 | - service: script.turn_off_interior_lights 51 | mode: single 52 | - id: 7f5929753d294d9596efe2446d9abf02 53 | alias: 'Kitchen/Bedroom: Turn off common space lights with a triple tap down' 54 | trigger: 55 | - platform: event 56 | event_type: zwave_js_value_notification 57 | event_data: 58 | node_id: 10 59 | property_key: '002' 60 | value: KeyPressed3x 61 | - platform: event 62 | event_type: zwave_js_value_notification 63 | event_data: 64 | node_id: 30 65 | property_key: '002' 66 | value: KeyPressed3x 67 | action: 68 | - service: light.turn_off 69 | data: {} 70 | target: 71 | entity_id: 72 | - light.kitchen_light 73 | - light.kitchen_island_light 74 | - light.dining_room_light 75 | - light.dining_room_chandelier 76 | - light.living_room_light 77 | - light.kitchen_hallway_light 78 | - service: lock.lock 79 | data: {} 80 | target: 81 | entity_id: lock.front_door_lock 82 | mode: single 83 | - id: 08182ba3f3554d85a534a5b658d40104 84 | alias: 'Bedroom: Turn on lamp with double tap up' 85 | trigger: 86 | - platform: event 87 | event_type: zwave_js_value_notification 88 | event_data: 89 | node_id: 30 90 | property_key: '001' 91 | value: KeyPressed2x 92 | action: 93 | - service: switch.turn_on 94 | data: 95 | entity_id: switch.bedroom_lamp 96 | mode: single 97 | - id: 2c181ae14b514e0d9a520d8ab7fea07d 98 | alias: 'Bedroom: Turn off lamp with double tap down' 99 | trigger: 100 | - platform: event 101 | event_type: zwave_js_value_notification 102 | event_data: 103 | node_id: 30 104 | property_key: '002' 105 | value: KeyPressed2x 106 | action: 107 | - service: switch.turn_off 108 | data: 109 | entity_id: switch.bedroom_lamp 110 | mode: single 111 | - id: 33e78170ee6f40cbb028622f9a501a66 112 | alias: 'Notification: Garage Door Open' 113 | description: Send a critical notification if the garage door is left open for 30 114 | minutes. 115 | triggers: 116 | - entity_id: cover.garage_door 117 | to: open 118 | for: 0:30:00 119 | trigger: state 120 | - event_type: timer.finished 121 | event_data: 122 | entity_id: timer.garage_door 123 | trigger: event 124 | conditions: 125 | - condition: state 126 | entity_id: cover.garage_door 127 | state: open 128 | actions: 129 | - entity_id: timer.garage_door 130 | action: timer.start 131 | - condition: state 132 | state: 133 | - 'off' 134 | entity_id: binary_sensor.basement_motion_detected 135 | for: 136 | hours: 0 137 | minutes: 30 138 | seconds: 0 139 | - data: 140 | message: Garage Door is Open 141 | data: 142 | push: 143 | sound: 144 | name: default 145 | critical: 1 146 | volume: 1 147 | action: notify.all_devices 148 | mode: single 149 | - id: c72b1caa51424d049a2f144c1160d7c7 150 | alias: 'Notification: Sprinklers left on' 151 | description: Push notify if the sprinklers have been left on for 30 minutes. 152 | trigger: 153 | - platform: state 154 | entity_id: 155 | - switch.maple_sprinkler 156 | - switch.apple_and_lemon_sprinkler 157 | - switch.vegetable_box_sprinkler 158 | - switch.lime_tree_sprinkler 159 | - switch.curb_sprinkler 160 | - switch.orange_tree_sprinkler 161 | to: 'on' 162 | for: 0:50:00 163 | action: 164 | - service: notify.all_devices 165 | data: 166 | message: Sprinkler has been running for > 30 min 167 | data: 168 | push: 169 | sound: 170 | name: default 171 | critical: 1 172 | volume: 1 173 | mode: single 174 | - id: 61edd68a44424f01b011a64b2ac45ec1 175 | alias: 'Kitchen: WD200 Status LED for Garage Door' 176 | trigger: 177 | - platform: state 178 | entity_id: cover.garage_door 179 | to: open 180 | - platform: state 181 | entity_id: cover.garage_door 182 | to: closed 183 | action: 184 | - service: zwave_js.set_config_parameter 185 | data_template: 186 | entity_id: light.dining_room_chandelier 187 | parameter: 13 188 | value: "{%- if trigger.to_state.state == 'open' -%}\n Enable\n{%- else -%}\n 189 | \ Disable\n{%- endif -%}" 190 | - service: zwave_js.set_config_parameter 191 | data_template: 192 | entity_id: light.dining_room_chandelier 193 | parameter: 21 194 | value: "{%- if trigger.to_state.state == 'open' -%}\n Red\n{%- else -%}\n White\n{%- 195 | endif -%}" 196 | mode: single 197 | - id: 02ac6c6160e74ce2b91d7cd142cd4eda 198 | alias: Set default level for WD100 when turned off after hours 199 | description: '' 200 | trigger: 201 | - platform: state 202 | entity_id: 203 | - light.living_room_light 204 | - light.dining_room_light 205 | - light.kitchen_island_light 206 | - light.kitchen_light 207 | - light.kitchen_hallway_light 208 | - light.bedroom_light 209 | to: 'off' 210 | for: 0:05:00 211 | condition: 212 | - condition: time 213 | after: '21:00:00' 214 | before: 06:00:00 215 | action: 216 | - service: script.set_homeseer_dim_level 217 | data_template: 218 | entity_id: '{{ trigger.entity_id }}' 219 | brightness: "{%- if trigger.entity_id == \"light.kitchen_island_light\" -%}\n 220 | \ 50\n{%- else -%}\n 3\n{%- endif -%}" 221 | mode: single 222 | - id: fbd91d4f47f44fc4964c7b38d3a0b9a2 223 | alias: Set default level at night 224 | description: '' 225 | trigger: 226 | - platform: time 227 | at: '21:00:00' 228 | action: 229 | - service: script.set_homeseer_dim_level 230 | data: 231 | entity_id: light.living_room_light 232 | brightness: 3 233 | - service: script.set_homeseer_dim_level 234 | data: 235 | entity_id: light.dining_room_light 236 | brightness: 3 237 | - service: script.set_homeseer_dim_level 238 | data: 239 | entity_id: light.kitchen_island_light 240 | brightness: 50 241 | - service: script.set_homeseer_dim_level 242 | data: 243 | entity_id: light.kitchen_light 244 | brightness: 3 245 | - service: script.set_homeseer_dim_level 246 | data: 247 | entity_id: light.kitchen_hallway_light 248 | brightness: 3 249 | - service: script.set_homeseer_dim_level 250 | data: 251 | entity_id: light.bedroom_light 252 | brightness: 3 253 | - service: zwave_js.set_config_parameter 254 | data_template: 255 | entity_id: light.master_bathroom_light 256 | parameter: 17 257 | value: 15 258 | mode: single 259 | - id: 82d04dd7c79e4972834845b48035f831 260 | alias: Set default level for Elijah & Izzys rooms 261 | description: '' 262 | trigger: 263 | - platform: time 264 | at: '19:00:00' 265 | action: 266 | - service: zwave_js.set_config_parameter 267 | data: 268 | parameter: '9' 269 | value: '20' 270 | target: 271 | entity_id: light.elijahs_room_light 272 | - service: zwave_js.set_config_parameter 273 | target: 274 | entity_id: light.izzys_room_light 275 | data: 276 | parameter: '9' 277 | value: '20' 278 | - delay: 279 | hours: 0 280 | minutes: 0 281 | seconds: 5 282 | milliseconds: 0 283 | - service: zwave_js.set_config_parameter 284 | data: 285 | parameter: '10' 286 | value: '20' 287 | target: 288 | entity_id: light.elijahs_room_light 289 | - service: zwave_js.set_config_parameter 290 | target: 291 | entity_id: light.izzys_room_light 292 | data: 293 | parameter: '10' 294 | value: '20' 295 | mode: single 296 | - id: 5414ebf2b25c4a0a88bb4115c6a2758d 297 | alias: Set default level in the morning 298 | description: '' 299 | trigger: 300 | - platform: time 301 | at: 07:00:00 302 | action: 303 | - service: script.set_homeseer_dim_level 304 | data: 305 | entity_id: light.living_room_light 306 | brightness: 255 307 | - service: script.set_homeseer_dim_level 308 | data: 309 | entity_id: light.dining_room_light 310 | brightness: 255 311 | - service: script.set_homeseer_dim_level 312 | data: 313 | entity_id: light.dining_room_chandelier 314 | brightness: 255 315 | - service: script.set_homeseer_dim_level 316 | data: 317 | entity_id: light.kitchen_island_light 318 | brightness: 255 319 | - service: script.set_homeseer_dim_level 320 | data: 321 | entity_id: light.kitchen_light 322 | brightness: 255 323 | - service: script.set_homeseer_dim_level 324 | data: 325 | entity_id: light.kitchen_hallway_light 326 | brightness: 255 327 | - service: zwave_js.set_config_parameter 328 | target: 329 | entity_id: light.master_bathroom_light 330 | data: 331 | parameter: '17' 332 | value: '99' 333 | - service: zwave_js.set_config_parameter 334 | target: 335 | entity_id: light.elijahs_room_light 336 | data: 337 | parameter: '9' 338 | value: '99' 339 | - service: zwave_js.set_config_parameter 340 | target: 341 | entity_id: light.izzys_room_light 342 | data: 343 | parameter: '9' 344 | value: '99' 345 | - delay: 346 | hours: 0 347 | minutes: 0 348 | seconds: 5 349 | milliseconds: 0 350 | - service: zwave_js.set_config_parameter 351 | target: 352 | entity_id: light.elijahs_room_light 353 | data: 354 | parameter: '10' 355 | value: '99' 356 | - service: zwave_js.set_config_parameter 357 | target: 358 | entity_id: light.izzys_room_light 359 | data: 360 | parameter: '10' 361 | value: '99' 362 | mode: single 363 | - id: d986a9e1de204037a6ea78c183f07fde 364 | alias: 'Notification: power is out' 365 | description: Sends a critical notification when the power goes out. 366 | trigger: 367 | - platform: numeric_state 368 | entity_id: sensor.nut_ups_input_voltage 369 | below: '60' 370 | action: 371 | - service: notify.all_devices 372 | data: 373 | message: Power is out 374 | data: 375 | push: 376 | sound: 377 | name: default 378 | critical: 1 379 | volume: 1 380 | - service: persistent_notification.create 381 | data: 382 | message: Power went out 383 | title: Power outage 384 | mode: single 385 | - id: 906bd5f51b04474d85bfe5404251d03f 386 | alias: 'Notification: Smoke alarm is triggered in the Basement' 387 | trigger: 388 | - platform: state 389 | entity_id: sensor.basement_smoke_alarm_state 390 | from: Unknown 391 | - platform: state 392 | entity_id: sensor.basement_smoke_alarm_state 393 | from: Clear 394 | condition: 395 | - condition: template 396 | value_template: '{{ not is_state("sensor.basement_smoke_alarm_state", "Clear") 397 | }}' 398 | - condition: template 399 | value_template: '{{ not is_state("sensor.basement_smoke_alarm_state", "Unknown") 400 | }}' 401 | action: 402 | - service: notify.all_devices 403 | data: 404 | title: Smoke alarm 405 | message: Basement smoke alarm is triggered! 406 | data: 407 | push: 408 | sound: 409 | name: default 410 | critical: 1 411 | volume: 1 412 | - service: persistent_notification.create 413 | data: 414 | message: Basement smoke alarm is triggered! 415 | title: Smoke alarm 416 | mode: single 417 | - id: 37ac75c3bcd64822b24cf7d3c29c6ea4 418 | alias: 'Notification: Smoke alarms are triggered upstairs' 419 | trigger: 420 | - platform: state 421 | entity_id: binary_sensor.upstairs_smoke_alarms 422 | to: 'on' 423 | action: 424 | - service: notify.all_devices 425 | data: 426 | title: Smoke alarm 427 | message: Upstairs smoke alarm is triggered! 428 | data: 429 | push: 430 | sound: 431 | name: default 432 | critical: 1 433 | volume: 1 434 | - service: persistent_notification.create 435 | data: 436 | message: Upstairs smoke alarm is triggered! 437 | title: Smoke alarm 438 | mode: single 439 | - id: 230724d25e4c428d9370c15e120ebbf9 440 | alias: 'Living Room: Soundbar to Aux when Alexa is playing music' 441 | trigger: 442 | - platform: state 443 | entity_id: media_player.everywhere 444 | to: playing 445 | - platform: state 446 | entity_id: media_player.everywhere 447 | from: playing 448 | - platform: state 449 | entity_id: media_player.living_room 450 | to: playing 451 | - platform: state 452 | entity_id: media_player.living_room 453 | from: playing 454 | action: 455 | - service: esphome.ir_blaster_transmit_nec_string 456 | data_template: 457 | address: 65280 458 | command: "{%- if trigger.to_state.state == 'playing' -%}\n 0x4EB1\n{%- else 459 | -%}\n 0x37C8\n{%- endif -%}" 460 | mode: single 461 | - id: '1609728044097' 462 | alias: 'Basement: Light with Garage Door' 463 | description: Turn on the Basement Light when the Garage Door opens. 464 | trigger: 465 | - platform: state 466 | entity_id: cover.garage_door 467 | from: closed 468 | to: open 469 | condition: [] 470 | action: 471 | - service: switch.turn_on 472 | data: {} 473 | entity_id: switch.basement_light 474 | mode: single 475 | - id: '1610226412253' 476 | alias: 'Basement: Lights and heater off when no motion' 477 | description: '' 478 | triggers: 479 | - entity_id: binary_sensor.basement_motion_detected 480 | to: 'off' 481 | for: 00:15:00 482 | trigger: state 483 | - trigger: state 484 | entity_id: 485 | - cover.garage_door 486 | to: 487 | - closed 488 | conditions: 489 | - condition: state 490 | entity_id: binary_sensor.basement_motion_detected 491 | state: 492 | - 'off' 493 | for: 494 | hours: 0 495 | minutes: 15 496 | seconds: 0 497 | actions: 498 | - metadata: {} 499 | data: {} 500 | target: 501 | entity_id: switch.basement_light 502 | action: switch.turn_off 503 | - metadata: {} 504 | data: {} 505 | target: 506 | entity_id: switch.basement_heater 507 | action: switch.turn_off 508 | mode: single 509 | - id: '1614914257006' 510 | alias: 'Outside: Lock Door at Sunset' 511 | description: '' 512 | trigger: 513 | - platform: sun 514 | event: sunset 515 | condition: [] 516 | action: 517 | - service: lock.lock 518 | metadata: {} 519 | data: {} 520 | target: 521 | device_id: 85a08776dab4ed63a75d09d78521ddc7 522 | mode: single 523 | - id: '1614914289466' 524 | alias: 'Outside: Turn on Porch Light at Sunset' 525 | description: '' 526 | trigger: 527 | - platform: sun 528 | event: sunset 529 | condition: [] 530 | action: 531 | - service: switch.turn_on 532 | metadata: {} 533 | data: {} 534 | target: 535 | entity_id: switch.porch_light 536 | mode: single 537 | - id: '1614914335846' 538 | alias: 'Outside: Turn Off Porch Light At Sunrise' 539 | description: '' 540 | trigger: 541 | - platform: sun 542 | event: sunrise 543 | condition: [] 544 | action: 545 | - service: switch.turn_off 546 | metadata: {} 547 | data: {} 548 | target: 549 | entity_id: switch.porch_light 550 | mode: single 551 | - id: '1615076634661' 552 | alias: 'Basement: Set Splitflap From Input' 553 | description: '' 554 | trigger: 555 | - platform: state 556 | entity_id: input_text.splitflap 557 | condition: [] 558 | action: 559 | - service: mqtt.publish 560 | data: 561 | topic: splitflap 562 | payload: '{{ states(''input_text.splitflap'') }}' 563 | mode: single 564 | - id: '1615618583223' 565 | alias: 'System: Turn off lights and lock doors when everyone leaves' 566 | description: '' 567 | trigger: 568 | - platform: state 569 | entity_id: group.all_people 570 | to: not_home 571 | for: 00:05:00 572 | condition: [] 573 | action: 574 | - service: script.turn_off_interior_lights 575 | - device_id: 85a08776dab4ed63a75d09d78521ddc7 576 | domain: lock 577 | entity_id: lock.front_door_lock 578 | type: lock 579 | mode: single 580 | - id: '1629572434173' 581 | alias: 'Living Room: Turn down the Soundbar Daily' 582 | description: '' 583 | trigger: 584 | - platform: time 585 | at: 03:00:00 586 | condition: [] 587 | action: 588 | - repeat: 589 | count: '20' 590 | sequence: 591 | - service: media_player.volume_down 592 | target: 593 | entity_id: media_player.soundbar 594 | - delay: 595 | hours: 0 596 | minutes: 0 597 | seconds: 0 598 | milliseconds: 500 599 | - repeat: 600 | count: '5' 601 | sequence: 602 | - service: media_player.volume_up 603 | target: 604 | entity_id: media_player.soundbar 605 | - delay: 606 | hours: 0 607 | minutes: 0 608 | seconds: 0 609 | milliseconds: 500 610 | mode: single 611 | - id: '1630473928636' 612 | alias: Turn off kids lights after 10pm 613 | description: '' 614 | triggers: 615 | - at: '22:00:00' 616 | trigger: time 617 | - at: '22:30:00' 618 | trigger: time 619 | - at: '23:00:00' 620 | trigger: time 621 | - at: '23:30:00' 622 | trigger: time 623 | - at: 00:00:00 624 | trigger: time 625 | - at: '22:15:00' 626 | trigger: time 627 | - at: '22:45:00' 628 | trigger: time 629 | - trigger: time 630 | at: 00:00:00 631 | conditions: [] 632 | actions: 633 | - target: 634 | entity_id: 635 | - light.izzys_room_light 636 | - light.elijahs_room_light 637 | - light.izzy_desk_lights 638 | data: 639 | transition: 300 640 | action: light.turn_off 641 | mode: single 642 | - id: '1635877623449' 643 | alias: 'System: Notify when internet comes back' 644 | description: '' 645 | trigger: 646 | - platform: state 647 | entity_id: binary_sensor.remote_ui 648 | from: 'off' 649 | to: 'on' 650 | for: 651 | hours: 0 652 | minutes: 0 653 | seconds: 10 654 | milliseconds: 0 655 | condition: [] 656 | action: 657 | - service: notify.all_devices 658 | data: 659 | message: Home Assistant reconnected to cloud! 660 | title: Internet is back! 661 | mode: single 662 | - id: '1639551963233' 663 | alias: Turn on christmas tree 664 | description: '' 665 | trigger: 666 | - platform: time 667 | at: 08:00:00 668 | condition: [] 669 | action: 670 | - service: switch.turn_on 671 | target: 672 | entity_id: switch.christmas_tree_lights 673 | data: {} 674 | mode: single 675 | - id: '1641674852044' 676 | alias: 'Notification: Critical notification for leak sensors' 677 | description: '' 678 | triggers: 679 | - type: turned_on 680 | device_id: f2240ba5b3a586a5fa3cdce7415cf5e4 681 | entity_id: binary_sensor.dishwasher_leak_sensor_water 682 | domain: binary_sensor 683 | trigger: device 684 | - type: turned_on 685 | device_id: 434292cbb0748b0427bf8840c7a5cab6 686 | entity_id: binary_sensor.washing_machine_leak_sensor_water 687 | domain: binary_sensor 688 | trigger: device 689 | - type: turned_on 690 | device_id: 405743db70972b84745d0d1c6c2cf804 691 | entity_id: f1473eb1b20da8a1b7293cff4a43d414 692 | domain: binary_sensor 693 | trigger: device 694 | - type: turned_on 695 | device_id: d4d430b97d8ddf49266596c6446d9efc 696 | entity_id: 660ed5dc4638269dd5f6c38123e37d11 697 | domain: binary_sensor 698 | trigger: device 699 | conditions: [] 700 | actions: 701 | - data: 702 | title: Leak detected! 703 | message: '{{ trigger.from_state.attributes.friendly_name }} triggered' 704 | data: 705 | push: 706 | sound: 707 | name: default 708 | critical: 1 709 | volume: 1 710 | action: notify.all_devices 711 | mode: single 712 | - id: '1676703714440' 713 | alias: 'Basement: Fan on when Glowforge Running' 714 | description: '' 715 | trigger: 716 | - platform: numeric_state 717 | entity_id: sensor.glowforge_power_consumption 718 | above: 50 719 | for: 720 | hours: 0 721 | minutes: 0 722 | seconds: 5 723 | condition: [] 724 | action: 725 | - service: fan.turn_on 726 | data: {} 727 | target: 728 | entity_id: fan.basement_fan 729 | mode: single 730 | - id: '1676703799745' 731 | alias: 'Basement: Fan off 1min after Glowforge is finished' 732 | description: '' 733 | trigger: 734 | - platform: numeric_state 735 | entity_id: sensor.glowforge_power_consumption 736 | for: 737 | hours: 0 738 | minutes: 1 739 | seconds: 0 740 | below: 50 741 | condition: [] 742 | action: 743 | - service: fan.turn_off 744 | data: {} 745 | target: 746 | entity_id: fan.basement_fan 747 | mode: single 748 | - id: '1693690036157' 749 | alias: 'Notification: 3d Print Paused' 750 | description: Notify when the print has paused for a minute. This could indicate 751 | out of filament. 752 | trigger: 753 | - platform: state 754 | entity_id: 755 | - sensor.octoprint_current_state 756 | to: Paused 757 | for: 758 | hours: 0 759 | minutes: 1 760 | seconds: 0 761 | condition: [] 762 | action: 763 | - service: camera.snapshot 764 | data: 765 | entity_id: camera.octoprint_camera 766 | filename: /config/www/camera/3d-print.jpg 767 | - service: notify.all_devices 768 | data: 769 | message: 3D print paused (possibly out of filament?) 770 | data: 771 | image: /local/camera/3d-print.jpg 772 | mode: single 773 | - id: '1706157750755' 774 | alias: Turn off Elijah's lights slowly at bedtime 775 | description: '' 776 | trigger: 777 | - platform: time 778 | at: '21:15:00' 779 | - platform: time 780 | at: '21:30:00' 781 | condition: 782 | - condition: or 783 | conditions: 784 | - condition: time 785 | weekday: 786 | - sun 787 | - mon 788 | - tue 789 | - wed 790 | - thu 791 | after: 09:15:00 792 | - condition: time 793 | after: 09:30:00 794 | weekday: 795 | - sat 796 | - fri 797 | action: 798 | - service: light.turn_off 799 | metadata: {} 800 | data: 801 | transition: 300 802 | target: 803 | entity_id: 804 | - light.elijahs_room_light 805 | mode: single 806 | - id: '1706158315722' 807 | alias: Dim Elijah's light at 8:30 808 | description: '' 809 | trigger: 810 | - platform: time 811 | at: '20:30:00' 812 | condition: 813 | - condition: state 814 | entity_id: light.elijahs_room_light 815 | state: 'on' 816 | - condition: numeric_state 817 | entity_id: light.elijahs_room_light 818 | attribute: brightness 819 | above: 40 820 | action: 821 | - service: light.turn_on 822 | target: 823 | entity_id: light.elijahs_room_light 824 | data: 825 | transition: 300 826 | brightness_pct: 40 827 | mode: single 828 | - id: '1706158389767' 829 | alias: Dim Izzy's Light at 8:30 830 | description: '' 831 | trigger: 832 | - platform: time 833 | at: '20:30:00' 834 | condition: 835 | - condition: state 836 | state: 'on' 837 | entity_id: light.izzys_room_light 838 | - condition: numeric_state 839 | entity_id: light.izzys_room_light 840 | attribute: brightness 841 | above: 40 842 | action: 843 | - service: light.turn_on 844 | target: 845 | entity_id: 846 | - light.izzys_room_light 847 | data: 848 | transition: 300 849 | brightness_pct: 40 850 | mode: single 851 | - id: '1706159811658' 852 | alias: Dim Izzy Light at 9:15 853 | description: '' 854 | trigger: 855 | - platform: time 856 | at: '21:15:00' 857 | condition: 858 | - condition: state 859 | state: 'on' 860 | entity_id: light.izzys_room_light 861 | - condition: numeric_state 862 | entity_id: light.izzys_room_light 863 | attribute: brightness 864 | above: 10 865 | action: 866 | - service: light.turn_on 867 | target: 868 | entity_id: 869 | - light.izzys_room_light 870 | data: 871 | transition: 300 872 | brightness_pct: 10 873 | mode: single 874 | - id: '1710307660366' 875 | alias: Hallway light off after 10 876 | description: '' 877 | trigger: 878 | - platform: state 879 | entity_id: 880 | - light.kitchen_hallway_light 881 | to: 'on' 882 | for: 883 | hours: 0 884 | minutes: 20 885 | seconds: 0 886 | condition: 887 | - condition: time 888 | after: '22:00:00' 889 | action: 890 | - service: light.turn_off 891 | metadata: {} 892 | data: 893 | transition: 300 894 | target: 895 | entity_id: light.kitchen_hallway_light 896 | mode: single 897 | - id: '1737248486404' 898 | alias: Turn off Kids' fans at 9a 899 | description: '' 900 | triggers: 901 | - trigger: time 902 | at: 09:00:00 903 | conditions: [] 904 | actions: 905 | - action: button.press 906 | metadata: {} 907 | data: {} 908 | target: 909 | entity_id: 910 | - button.elijah_fan_turn_off 911 | - button.izzy_fan_turn_off 912 | mode: single 913 | - id: '1752337303932' 914 | alias: 'Notification: Fridge Temp High' 915 | description: '' 916 | triggers: 917 | - trigger: numeric_state 918 | entity_id: 919 | - sensor.sonoff_snzb_02d_temperature 920 | for: 921 | hours: 0 922 | minutes: 20 923 | seconds: 0 924 | above: 41 925 | conditions: [] 926 | actions: 927 | - action: notify.notify 928 | metadata: {} 929 | data: 930 | message: Fridge Temp Above 40 931 | mode: single 932 | - id: '1752338448236' 933 | alias: 'Notification: Fridge Temp Low' 934 | description: '' 935 | triggers: 936 | - trigger: numeric_state 937 | entity_id: 938 | - sensor.sonoff_snzb_02d_temperature 939 | for: 940 | hours: 0 941 | minutes: 20 942 | seconds: 0 943 | below: 32 944 | conditions: [] 945 | actions: 946 | - action: notify.notify 947 | metadata: {} 948 | data: 949 | message: Fridge Temp Below 32ºF for 20 mins 950 | mode: single 951 | - id: '1761846428112' 952 | alias: 'Basement: Dehumidifier on when garage door closed' 953 | description: '' 954 | triggers: 955 | - trigger: state 956 | entity_id: 957 | - cover.garage_door 958 | to: closed 959 | conditions: [] 960 | actions: 961 | - action: switch.turn_on 962 | metadata: {} 963 | data: {} 964 | target: 965 | entity_id: switch.basement_dehumidifier_power 966 | mode: single 967 | - id: '1761846487611' 968 | alias: 'Basement: Dehumidifier off when garage door open' 969 | description: '' 970 | triggers: 971 | - trigger: state 972 | entity_id: 973 | - cover.garage_door 974 | to: open 975 | conditions: [] 976 | actions: 977 | - action: switch.turn_off 978 | metadata: {} 979 | data: {} 980 | target: 981 | entity_id: switch.basement_dehumidifier_power 982 | mode: single 983 | - id: '1763664736881' 984 | alias: 'Master Bathroom: Turn on fan light with double tap' 985 | description: '' 986 | triggers: 987 | - trigger: event 988 | event_type: zwave_js_value_notification 989 | event_data: 990 | node_id: 38 991 | property_key: '002' 992 | value: KeyPressed2x 993 | conditions: [] 994 | actions: 995 | - action: light.turn_on 996 | metadata: {} 997 | data: {} 998 | target: 999 | entity_id: light.master_bathroom_fan_master_bathroom_fan_light 1000 | mode: single 1001 | - id: '1763664807693' 1002 | alias: 'Master Bathroom: Turn off fan light with double tap down' 1003 | description: '' 1004 | triggers: 1005 | - trigger: event 1006 | event_type: zwave_js_value_notification 1007 | event_data: 1008 | node_id: 38 1009 | property_key: '001' 1010 | value: KeyPressed2x 1011 | conditions: [] 1012 | actions: 1013 | - action: light.turn_off 1014 | metadata: {} 1015 | data: {} 1016 | target: 1017 | entity_id: light.master_bathroom_fan_master_bathroom_fan_light 1018 | mode: single 1019 | - id: '1763665342959' 1020 | alias: 'Master Bathroom: Turn off fan with tap down' 1021 | description: '' 1022 | triggers: 1023 | - trigger: event 1024 | event_type: zwave_js_value_notification 1025 | event_data: 1026 | node_id: 38 1027 | property_key: '001' 1028 | value: KeyPressed 1029 | conditions: [] 1030 | actions: 1031 | - action: fan.turn_off 1032 | metadata: {} 1033 | data: {} 1034 | target: 1035 | entity_id: fan.master_bathroom_fan 1036 | mode: single 1037 | - id: '1763665372517' 1038 | alias: 'Master Bathroom: Turn on fan with tap up' 1039 | description: '' 1040 | triggers: 1041 | - trigger: event 1042 | event_type: zwave_js_value_notification 1043 | event_data: 1044 | node_id: 38 1045 | property_key: '002' 1046 | value: KeyPressed 1047 | conditions: [] 1048 | actions: 1049 | - action: fan.set_percentage 1050 | metadata: {} 1051 | data: 1052 | percentage: 60 1053 | target: 1054 | device_id: 516dc912426cd01b60537ddf825cd64a 1055 | mode: single 1056 | - id: '1764391469249' 1057 | alias: 'Master Bathroom: Off with no motion' 1058 | description: '' 1059 | triggers: 1060 | - trigger: state 1061 | entity_id: 1062 | - binary_sensor.master_bathroom_motion_detected 1063 | to: 1064 | - 'off' 1065 | from: 1066 | - 'on' 1067 | for: 1068 | hours: 0 1069 | minutes: 20 1070 | seconds: 0 1071 | conditions: [] 1072 | actions: 1073 | - action: light.turn_off 1074 | metadata: {} 1075 | data: {} 1076 | target: 1077 | entity_id: 1078 | - light.master_bathroom_light 1079 | - light.master_bathroom_fan_master_bathroom_fan_light 1080 | - action: fan.turn_off 1081 | metadata: {} 1082 | data: {} 1083 | target: 1084 | entity_id: fan.master_bathroom_fan 1085 | mode: single 1086 | - id: '1764440161109' 1087 | alias: 'Master Bathroom: Fan LED On' 1088 | description: '' 1089 | triggers: 1090 | - trigger: state 1091 | entity_id: 1092 | - fan.master_bathroom_fan 1093 | to: 1094 | - 'on' 1095 | conditions: [] 1096 | actions: 1097 | - action: script.inovelli_led 1098 | metadata: {} 1099 | data: 1100 | entity_id: sensor.fan_electric_kwh 1101 | model: switch 1102 | color: Cyan 1103 | effect: Solid 1104 | mode: single 1105 | - id: '1764440217608' 1106 | alias: 'Master Bathroom: Fan LED Off' 1107 | description: '' 1108 | triggers: 1109 | - trigger: state 1110 | entity_id: 1111 | - fan.master_bathroom_fan 1112 | to: 1113 | - 'off' 1114 | conditions: [] 1115 | actions: 1116 | - action: script.inovelli_led 1117 | metadata: {} 1118 | data: 1119 | entity_id: sensor.fan_electric_kwh 1120 | model: switch 1121 | effect: 'Off' 1122 | mode: single 1123 | -------------------------------------------------------------------------------- /panels/zwavegraph2.html: -------------------------------------------------------------------------------- 1 | 29 | 30 | 31 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 1097 | --------------------------------------------------------------------------------