10
Apr2022
Automating Your Home Climate Control With Home Assistant
About a year or so ago, I moved away from HomeKit and starting using Home Assistant. HomeKit was just too unreliable when it came to automating things, not to mention that Siri is very moody about when it wants to work or not.
My Home Assistant setup now controls all my HomeKit, Zigbee, and Z-Wave devices and they are all exposed back to HomeKit so I can use Siri for voice control. I must say, that I am pretty impressed with the setup and its reliability.
But, we are here to talk about your home’s climate control, so let’s begin.
I live in Montreal and the weather here gets pretty darn cold in the Winter which means high electricity bills. To that end our utility company, Hydro Quebec, has started new programs for peak hours to let folks lower their electricity bills and I am participating in that. The way it works is that they send an email the day before to tell you that tomorrow there may be a peak event during the morning, evening or both. So, I wanted a way to automate it all so I don’t have to adjust things manually.
The Setup
My home heating is with forced air, but I do have a few baseboard heaters around and floor heaters in the bathrooms, so they all have to work in concert.
- Main HVAC: Ecobee3
- Baseboard heaters (mix of Z-Wave, and HomeKit)
- Floor heaters (Zigbee)
- Gmail for peak event notifications
The Goal
Below is what I set out to achieve:
- Climate settings should have Home, Away, Sleep settings
- Climate settings should take into account peak events
- Climate settings should differentiate between workdays and weekends/holidays
- Climate settings should be aware of Summer/Winter temperatures
- All of the above should be easily adjustable.
How it works
In order to do all the goals I had set, the first thing was to take away the Ecobee’s programming, so I changed a few settings:
- Everyday of the week is only set to have 1 comfort setting which is the temperature range that I use for both Winter/Summer
- The hold setting is set to not change automatically, so if I change the temperature, it will keep that until I manually change it again.
Side Note: As much as I love the Ecobee, there is no way to have it resume unless you use it with HomeKit directly (i.e. only the Ecobee itself can add the resume to HomeKit, there is no HomeKit command for it). Also, I don’t like that it communicates with home base so much but I want the wether so I don’t like to let it know if I am home/away/on holiday.
One other item I should point out is that the way I prep for a peak time is that I preheat my house prior to peak time and then turn everything down for the duration so heating is used less and hopefully the house can stay somewhat warm during the event.
From this point on, I am going to refer to the file attached here and explain how it works. I think that would be best.
Adjustable Settings
The following is a list of inputs I used to achieve gaol #5:
- input_datetime
- peak_morning_start_time: The time that a morning peak event starts
- peak_morning_end_time: The time that a morning peak event ends
- peak_evening_start_time: The time that a evening peak event starts
- peak_evening_end_time: The time that a evening peak event ends
- input_number
- peak_pre_time (range 0-180 min): The time needed to preheat the home prior to a peak event
- winter_summer_threshold (range (-10 to 10 ºC): The temperature above which summer settings should be used.
- input_boolean
- peak_demand_morning_today: Whether today has a morning peak event
- peak_demand_evening_today: Whether today has a evening peak event
- peak_demand_morning_tomorrow: Whether tomorrow has a morning peak event
- peak_demand_evening_tomorrow: Whether tomorrow has a evening peak event
Besides the above, there are a few other things that are also leveraged:
- work_wakeup_time: The time that the house wakes up for a work day
- work_quiet_time: The time that the house is in sleep mode for a work day
- holiday_wakeup_time: The time that the house wakes up for a holiday (or weekend)
- holiday_quiet_time: The time that the house is in sleep mode for a holiday (or weekend)
- workday
- workday_today: Whether it is a work day today
- workday_tomorrow: Whether it is a work day tomorrow.
- IMAP Email Content: To check email for peak time (Note: I get this in English)
- peak_demand_morning_notification: a sensor that is set when a peak time email is received containing peak time for tomorrow morning.
- peak_demand_evening_notification: a sensor that is set when a peak time email is received containing peak time for tomorrow evening.
- household: This is a group of household members that indicates if we are home or not using sensors for each person.
- peak_time_now: A sensor indicating whether we are in a peak time at this moment.
- house_mode: A sensor indicating whether the house is in Home, Sleep, or Away mode. This is dependent on whether household is home or away and whether tomorrow and today are workdays or not (if tomorrow is not a workday, then the house goes to sleep mode at holiday_quiet_time instead of workday_quiet_time).
Implementation
The climate settings are controlled via scenes:
- Climate: Main Thermostat Away: This scene sets the temperature range for the Ecobee when we are away. The Ecobee is set to auto cool/heat and the range is such that it is the same for Summer and Winter.
- Climate: Main Thermostat Home: This scene sets the temperature range for the Ecobee when we are home.
- Climate: Main Thermostat Sleep: This scene sets the temperature range for the Ecobee when we are asleep.
- Climate: Other Thermostats Summer: This scene sets the temperature for each of the baseboard and floor heaters for the Summer time. Basically, turns them off.
- Climate: Other Thermostats Away – Winter: This scene sets the temperature for each of the baseboard and floor heaters for the Winter when the household is away.
- Climate: Other Thermostats Home – Winter: This scene sets the temperature for each of the baseboard and floor heaters for the Winter when the household is home.
- Climate: Other Thermostats Sleep – Winter: This scene sets the temperature for each of the baseboard and floor heaters for the Winter when the household is asleep.
- Climate: All Thermostats Peak Time: This scene sets the temperature for all (including Ecobee) heaters while we are in peak time.
Since the email for peak time comes the day before, the email sensor checks and set tomorrow’s peak inputs first (hydro_email). Then at 1AM, an automation copies the values to today’s peak input and resets tomorrow’s peak inputs back to off (Peak Time: Copy tomorrows values).
Then depending on whether it is a workday, holiday, or peak time automations control the heaters:
- Climate: Preheat at morning peak start time: This automation triggers at preheat time (peak start time – preheat time) only if there is a morning peak event, and household is home to make sure the house is heated and ready to use less heating during the morning peak time.
- Scene: Climate: Main Thermostat Home
- Scene: Climate: Other Thermostats Home – Winter
- Climate: Preheat at evening peak start time: Same as the morning automation but for the evening peak time
- Scene: Climate: Main Thermostat Home
- Scene: Climate: Other Thermostats Home – Winter
- Climate: Set peak mode at peak start time: This automation is triggered when the peak_time_now sensor is turned on and household is home
- Scene: Climate: All Thermostats Peak Time
- Climate: Reset peak mode at peak end time: This automation reset the climate settings to what they should be once peak time is over (i.e. if house_mode is set to sleep, then set the sleep time settings , etc).
- If home:
- Scene: Climate: Main Thermostat Home
- Scene: Climate: Other Thermostats Home – Winter
- If asleep:
- Scene: Climate: Main Thermostat Sleep
- Scene: Climate: Other Thermostats Sleep – Winter
- Otherwise:
- Scene: Climate: Main Thermostat Away
- Scene: Climate: Other Thermostats Away – Winter
- If home:
- Climate: Preheat before morning wake time or at wake time: This automation sets the climate settings to home at preheat time or at wakeup time if household is home and it is not a peak_time_now.
- Scene: Climate: Main Thermostat Home
- If temperature is below threshold (winter_summer_threshold):
- Scene: Climate: Other Thermostats Home – Winter
- Otherwise:
- Scene: Climate: Other Thermostats Summer
- Climate: Pre Cool or stop heating before sleep time or at sleep time: This automation sets the climate settings to sleep at preheat time or at sleep time if household is home and it is not a peak_time_now.
- Scene: Climate: Main Thermostat Sleep
- If temperature is below threshold (winter_summer_threshold):
- Scene: Climate: Other Thermostats Sleep – Winter
- Otherwise:
- Scene: Climate: Other Thermostats Summer
- Climate: Household leaves: This automation sets the climate settings to away when household is not home.
- Scene: Climate: Main Thermostat Away
- If temperature is below threshold (winter_summer_threshold):
- Scene: Climate: Other Thermostats Away – Winter
- Otherwise:
- Scene: Climate: Other Thermostats Summer
- Climate: Household arrives: This automation sets the climate settings to home when household comes home (i.e. first person arrives home).
- If house_mode is set to sleep:
- Scene: Climate: Main Thermostat Sleep
- If temperature is below threshold (winter_summer_threshold):
- Scene: Climate: Other Thermostats Sleep – Winter
- Otherwise:
- Scene: Climate: Main Thermostat Home
- If temperature is below threshold (winter_summer_threshold):
- Scene: Climate: Other Thermostats Home – Winter
- Otherwise:
- Scene: Climate: Other Thermostats Summer
- If house_mode is set to sleep:
YAML
here is the Yaml for the above so you can see how it is implemented exactly. Note that some inputs/sensors are external to this file but they are explained in here so you know what they do.
input_datetime:
# This indicates the start time of peak demand time in the morning
peak_morning_start_time:
name: Peak Demand Morning Start
has_date: false
has_time: true
icon: mdi:clock-time-six
# This indicates the end time of peak demand time in the morning
peak_morning_end_time:
name: Peak Demand Morning End
has_date: false
has_time: true
icon: mdi:clock-time-nine
# This indicates the start time of peak demand time in the evening
peak_evening_start_time:
name: Peak Demand Evening Start
has_date: false
has_time: true
icon: mdi:clock-time-four-outline
# This indicates the end time of peak demand time in the evening
peak_evening_end_time:
name: Peak Demand Evening End
has_date: false
has_time: true
icon: mdi:clock-time-eight-outline
input_number:
# This input sets the time needed to cool/heat the house prior to Peak time
peak_pre_time:
name: Peak Pre Time
min: 0
max: 180
step: 5
mode: slider
icon: mdi:timelapse
winter_summer_threshold:
name: Winter/Summer Threshold
min: -10
max: 10
step: 1
mode: slider
icon: mdi:car-speed-limiter
input_boolean:
# This input determines whether peak demand morning time is enabled for today or not
peak_demand_morning_today:
name: Peak Demand Morning Today
icon: mdi:summit
# This input determines whether peak demand evening time is enabled for today or not
peak_demand_evening_today:
name: Peak Demand Evening Today
icon: mdi:summit
# This input determines whether peak demand morning time is enabled for tomorrow or not
peak_demand_morning_tomorrow:
name: Peak Demand Morning Tomorrow
icon: mdi:summit
# This input determines whether peak demand evening time is enabled for tomorrow or not
peak_demand_evening_tomorrow:
name: Peak Demand Evening Tomorrow
icon: mdi:summit
sensor:
# https://www.home-assistant.io/integrations/imap_email_content/
- platform: imap_email_content
name: hydro_email
server: imap.gmail.com
port: 993
username: !secret peak_email_username
password: !secret peak_email_password
senders:
- hydroquebec@communication.hydroquebec.com
value_template: >-
{% if ( 'Peak demand event notification' in subject) %}
peak
{% else %}
off
{% endif %}
- platform: template
sensors:
peak_demand_morning_notification:
friendly_name: "Peak Demand Morning Notification" #Thu, 20 Jan 2022 12:52:16 -0500
value_template: >-
{% if ( states('sensor.hydro_email') == 'peak' and strptime(state_attr('sensor.hydro_email','date'), '%a, %d %b %Y %H:%M:%S %z').strftime('%d%m%Y') == now().strftime('%d%m%Y') and state_attr('sensor.hydro_email','body') is search('from 6 to 9 a.m.', ignorecase=True) ) %}
on
{% else %}
off
{% endif %}
peak_demand_evening_notification:
friendly_name: "Peak Demand Evening Notification"
value_template: >-
{% if ( states('sensor.hydro_email') == 'peak' and strptime(state_attr('sensor.hydro_email','date'), '%a, %d %b %Y %H:%M:%S %z').strftime('%d%m%Y') == now().strftime('%d%m%Y') and state_attr('sensor.hydro_email','body') is search('from 4 to 8 p.m.', ignorecase=True) ) %}
on
{% else %}
off
{% endif %}
peak_time_now:
friendly_name: "Peak Time Now"
value_template: >-
{% if ( is_state('input_boolean.peak_demand_morning_today', 'on') and
now().strftime('%H:%M') >= (state_attr('input_datetime.peak_morning_start_time', 'timestamp') | timestamp_custom('%H:%M', False)) and
now().strftime('%H:%M') <= (state_attr('input_datetime.peak_morning_end_time', 'timestamp') | timestamp_custom('%H:%M', False)) ) or
( is_state('input_boolean.peak_demand_evening_today', 'on') and
now().strftime('%H:%M') >= (state_attr('input_datetime.peak_evening_start_time', 'timestamp') | timestamp_custom('%H:%M', False)) and
now().strftime('%H:%M') <= (state_attr('input_datetime.peak_evening_end_time', 'timestamp') | timestamp_custom('%H:%M', False)) ) %}
on
{% else %}
off
{% endif %}
scene:
######
# Climate: Main Thermostat Away
- name: "Climate: Main Thermostat Away"
id: bb18cf20-57ae-47e3-a80e-c9896745673f
entities:
climate.sedhvac:
state: "heat_cool"
target_temp_high: 29
target_temp_low: 14
#####
# Climate: Main Thermostat Home
- name: "Climate: Main Thermostat Home"
id: bab27c18-3237-4a0b-83f9-6606865e0ec9
entities:
climate.sedhvac:
state: "heat_cool"
target_temp_high: 25
target_temp_low: 19.5
#####
# Climate: Main Thermostat Sleep
- name: "Climate: Main Thermostat Sleep"
id: b0d722cc-8480-4229-a07c-7ae21309945a
entities:
climate.sedhvac:
state: "heat_cool"
target_temp_high: 23.5
target_temp_low: 17.5
######
# Climate: Other Thermostats Summer
- name: "Climate: Other Thermostats Summer"
id: 68cb636e-b76d-4148-93cf-cc65e8d6f45c
entities:
climate.bedroom3_thermostat:
state: "heat"
temperature: 6
climate.guest_bedroom_thermostat:
state: "heat"
temperature: 6
climate.family_room_thermostat:
state: "off"
climate.garage_thermostat:
state: "off"
climate.downstairs_bathroom_thermostat:
state: "off"
climate.master_bathroom_thermostat:
state: "off"
climate.upstairs_bathroom_thermostat:
state: "off"
######
# Climate: Other Thermostats Away - Winter
- name: "Climate: Other Thermostats Away - Winter"
id: d86d5909-8eb2-4dd2-a51f-8aae0599a0c6
entities:
climate.bedroom3_thermostat:
state: "heat"
temperature: 12
climate.guest_bedroom_thermostat:
state: "heat"
temperature: 12
climate.family_room_thermostat:
state: "heat"
temperature: 12
climate.garage_thermostat:
state: "heat"
temperature: 8
climate.downstairs_bathroom_thermostat:
state: "heat"
temperature: 12
climate.master_bathroom_thermostat:
state: "heat"
temperature: 12
climate.upstairs_bathroom_thermostat:
state: "heat"
temperature: 12
#####
# Climate: Other Thermostats Home - Winter
- name: "Climate: Other Thermostats Home - Winter"
id: 411533f6-ef26-450b-9acb-2e44a4c5cd50
entities:
climate.bedroom3_thermostat:
state: "heat"
temperature: 18
climate.family_room_thermostat:
state: "heat"
temperature: 18
climate.guest_bedroom_thermostat:
state: "heat"
temperature: 18
climate.garage_thermostat:
state: "heat"
temperature: 14
climate.downstairs_bathroom_thermostat:
state: "heat"
temperature: 20
climate.master_bathroom_thermostat:
state: "heat"
temperature: 20
climate.upstairs_bathroom_thermostat:
state: "heat"
temperature: 20
#####
# Climate: Other Thermostats Sleep - Winter
- name: "Climate: Other Thermostats Sleep - Winter"
id: 4b8b86c5-035a-4b8b-a934-f31571cd71e6
entities:
climate.bedroom3_thermostat:
state: "heat"
temperature: 17
climate.family_room_thermostat:
state: "heat"
temperature: 17
climate.guest_bedroom_thermostat:
state: "heat"
temperature: 17
climate.garage_thermostat:
state: "heat"
temperature: 12
climate.downstairs_bathroom_thermostat:
state: "heat"
temperature: 18
climate.master_bathroom_thermostat:
state: "heat"
temperature: 18
climate.upstairs_bathroom_thermostat:
state: "heat"
temperature: 18
#####
# Climate: All Thermostats Peak Time
- name: "Climate: All Thermostats Peak Time"
id: 794a89e7-1ecc-4e02-977b-21a0e8260b0f
entities:
climate.sedhvac:
state: "heat_cool"
target_temp_high: 25
target_temp_low: 18
climate.bedroom3_thermostat:
state: "heat"
temperature: 17
climate.family_room_thermostat:
state: "heat"
temperature: 17
climate.guest_bedroom_thermostat:
state: "heat"
temperature: 15
climate.garage_thermostat:
state: "heat"
temperature: 10
climate.downstairs_bathroom_thermostat:
state: "heat"
temperature: 17
climate.master_bathroom_thermostat:
state: "heat"
temperature: 17
climate.upstairs_bathroom_thermostat:
state: "heat"
temperature: 17
automation:
######
# Climate: Preheat at morning peak start time
- alias: "Climate: Preheat at morning peak start time"
id: "7e432873-c8b7-4d75-9ff4-cfb3c6753bc6"
description: ""
mode: single
trigger:
- platform: template
value_template: "{{ states('sensor.time') == ((state_attr('input_datetime.peak_morning_start_time', 'timestamp') - (states('input_number.peak_pre_time')|float * 60) ) | timestamp_custom('%H:%M', False)) }}"
condition:
alias: Household is home and today is peak time
condition: and
conditions:
- condition: state
entity_id: input_boolean.peak_demand_morning_today
state: "on"
- condition: state
entity_id: group.household
state: "home"
- condition: template
value_template: "{{ state_attr('weather.home', 'temperature') < (states('input_number.winter_summer_threshold')|float) }}"
action:
- scene: scene.climate_main_thermostat_home
- scene: scene.climate_other_thermostats_home_winter
######
# limate: Preheat at evening peak start time
- alias: "Climate: Preheat at evening peak start time"
id: "5310be81-0d3d-4a82-baf6-e4c455e5beb5"
description: ""
mode: single
trigger:
- platform: template
value_template: "{{ states('sensor.time') == ((state_attr('input_datetime.peak_evening_start_time', 'timestamp') - (states('input_number.peak_pre_time')|float * 60) ) | timestamp_custom('%H:%M', False)) }}"
condition:
alias: Household is home and today is peak time
condition: and
conditions:
- condition: state
entity_id: input_boolean.peak_demand_evening_today
state: "on"
- condition: state
entity_id: group.household
state: "home"
- condition: template
value_template: "{{ state_attr('weather.home', 'temperature') < (states('input_number.winter_summer_threshold')|float) }}"
action:
- scene: scene.climate_main_thermostat_home
- scene: scene.climate_other_thermostats_home_winter
######
# Climate: Set peak mode at peak start time
- alias: "Climate: Set peak mode at peak start time"
id: "f2a9c6d3-6e3c-46bd-a72f-843c48e6ba80"
description: ""
mode: single
trigger:
- platform: state
entity_id: sensor.peak_time_now
from: "off"
to: "on"
condition:
# if it is peak time then the temp must be below threshold, but we check anyways
alias: Only do this if the temperature is below threshold and household is home
condition: and
conditions:
- condition: state
entity_id: group.household
state: "home"
- condition: template
value_template: "{{ state_attr('weather.home', 'temperature') < (states('input_number.winter_summer_threshold')|float) }}"
action:
- scene: scene.climate_all_thermostats_peak_time
######
# Climate: Reset peak mode at evening peak end time
- alias: "Climate: Reset peak mode at peak end time"
id: "957f2036-23a9-42c2-92e5-bb03cf7445eb"
description: ""
mode: single
trigger:
- platform: state
entity_id: sensor.peak_time_now
from: "on"
to: "off"
condition: []
action:
- alias: Set home/sleep/away mode appropriately
choose:
- conditions:
- condition: state
entity_id: sensor.house_mode
state: "Home"
sequence:
- scene: scene.climate_main_thermostat_home
- scene: scene.climate_other_thermostats_home_winter
- conditions:
- condition: state
entity_id: sensor.house_mode
state: "Sleep"
sequence:
- scene: scene.climate_main_thermostat_sleep_2
- scene: scene.climate_other_thermostats_sleep_winter
default:
- scene: scene.climate_main_thermostat_away
- scene: scene.climate_other_thermostats_away_winter
######
# Climate: Preheat before morning wake time or at wake time
- alias: "Climate: Preheat before morning wake time or at wake time"
id: "e950b43b-0314-4f9b-9092-08cfd87e9b74"
description: ""
mode: single
trigger:
- platform: template
value_template: "{{ states('binary_sensor.workday_today') == 'off' and states('sensor.time') == ((state_attr('input_datetime.holiday_wakeup_time', 'timestamp') - (states('input_number.peak_pre_time')|float * 60) ) | timestamp_custom('%H:%M', False)) }}"
- platform: template
value_template: "{{ states('binary_sensor.workday_today') == 'on' and states('sensor.time') == ((state_attr('input_datetime.work_wakeup_time', 'timestamp') - (states('input_number.peak_pre_time')|float * 60) ) | timestamp_custom('%H:%M', False)) }}"
- platform: template
value_template: "{{ states('binary_sensor.workday_today') == 'off' and states('sensor.time') == ( state_attr('input_datetime.holiday_wakeup_time', 'timestamp') | timestamp_custom('%H:%M', False) ) }}"
- platform: template
value_template: "{{ states('binary_sensor.workday_today') == 'on' and states('sensor.time') == ( state_attr('input_datetime.work_wakeup_time', 'timestamp') | timestamp_custom('%H:%M', False) ) }}"
condition:
alias: Household is home and NOT peak time now
condition: and
conditions:
- condition: state
entity_id: sensor.peak_time_now
state: "off"
- condition: state
entity_id: group.household
state: "home"
action:
- scene: scene.climate_main_thermostat_home
- alias: Also set the other thermostats if temp is below threshold
choose:
- conditions:
- condition: template
value_template: "{{ state_attr('weather.home', 'temperature') < (states('input_number.winter_summer_threshold')|float) }}"
sequence:
- scene: scene.climate_other_thermostats_home_winter
default:
- scene: scene.climate_other_thermostats_summer
######
# Climate: Pre Cool or stop heating before sleep time or at sleep time
- alias: "Climate: Pre Cool or stop heating before sleep time or at sleep time"
id: "9684f644-4b38-4782-8de5-3d81c3448622"
description: ""
mode: single
trigger:
- platform: template
value_template: "{{ states('binary_sensor.workday_tomorrow') == 'off' and states('sensor.time') == ((state_attr('input_datetime.holiday_quiet_time', 'timestamp') - (states('input_number.peak_pre_time')|float * 60) ) | timestamp_custom('%H:%M', False)) }}"
- platform: template
value_template: "{{ states('binary_sensor.workday_tomorrow') == 'on' and states('sensor.time') == ((state_attr('input_datetime.work_quiet_time', 'timestamp') - (states('input_number.peak_pre_time')|float * 60) ) | timestamp_custom('%H:%M', False)) }}"
- platform: template
value_template: "{{ states('binary_sensor.workday_tomorrow') == 'off' and states('sensor.time') == ( state_attr('input_datetime.holiday_quiet_time', 'timestamp') | timestamp_custom('%H:%M', False) ) }}"
- platform: template
value_template: "{{ states('binary_sensor.workday_tomorrow') == 'on' and states('sensor.time') == ( state_attr('input_datetime.work_quiet_time', 'timestamp') | timestamp_custom('%H:%M', False) ) }}"
condition:
alias: Household is home and NOT peak time now
condition: and
conditions:
- condition: state
entity_id: sensor.peak_time_now
state: "off"
- condition: state
entity_id: group.household
state: "home"
action:
- scene: scene.climate_main_thermostat_sleep_2
- alias: Also set the other thermostats if temp is below threshold
choose:
- conditions:
- condition: template
value_template: "{{ state_attr('weather.home', 'temperature') < (states('input_number.winter_summer_threshold')|float) }}"
sequence:
- scene: scene.climate_other_thermostats_sleep_winter
default:
- scene: scene.climate_other_thermostats_summer
######
# Peak Time: Set tomorrow's morning values
- alias: "Peak Time: Set tomorrows morning value"
id: "ebf235ee-74cf-45d4-8eec-054eb3c03e6a"
description: ""
mode: single
trigger:
- platform: state
entity_id: sensor.peak_demand_morning_notification
from: "off"
to: "on"
condition: []
action:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.peak_demand_morning_tomorrow
######
# Peak Time: Set tomorrow's evening values
- alias: "Peak Time: Set tomorrows evening value"
id: "73f52595-c64e-41ea-b437-aa13272ffb31"
description: ""
mode: single
trigger:
- platform: state
entity_id: sensor.peak_demand_evening_notification
from: "off"
to: "on"
condition: []
action:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.peak_demand_evening_tomorrow
######
# Peak Time: Copy tomorrow's values
- alias: "Peak Time: Copy tomorrows values"
id: "0dd12a22-7418-426a-9439-402cce7bb7e5"
description: ""
mode: single
trigger:
- platform: time
at: 00:01:00
condition: []
action:
- alias: Copy morning value and set tomorrow to off
choose:
- conditions:
- condition: state
entity_id: input_boolean.peak_demand_morning_tomorrow
state: "on"
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.peak_demand_morning_today
default:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.peak_demand_morning_today
- alias: Copy evening value and set tomorrow to off
choose:
- conditions:
- condition: state
entity_id: input_boolean.peak_demand_evening_tomorrow
state: "on"
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.peak_demand_evening_today
default:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.peak_demand_evening_today
- service: input_boolean.turn_off
target:
entity_id: input_boolean.peak_demand_morning_tomorrow
- service: input_boolean.turn_off
target:
entity_id: input_boolean.peak_demand_evening_tomorrow
######
# Climate: Household leaves
- alias: "Climate: Household leaves"
id: 0e666717-db83-4d67-b784-eca6edc92431
description: When everyone leaves
mode: single
trigger:
- platform: state
entity_id: group.household
from: home
to: not_home
condition: []
action:
- scene: scene.climate_main_thermostat_away
- alias: Also set the other thermostats if temp is below threshold
choose:
- conditions:
- condition: template
value_template: "{{ state_attr('weather.home', 'temperature') < (states('input_number.winter_summer_threshold')|float) }}"
sequence:
- scene: scene.climate_other_thermostats_away_winter
default:
- scene: scene.climate_other_thermostats_summer
######
# Climate: Household Arrives
- alias: "Climate: Household Arrives"
id: 0c6be006-26e6-4d15-b6d4-0615c3aca80f
description: When first person arrives
mode: single
trigger:
- platform: state
entity_id: group.household
from: not_home
to: home
condition: []
action:
- alias: For the main thermostat, if it is past sleep time, then set to sleep, otherwise home
choose:
- conditions:
- condition: state
entity_id: sensor.house_mode
state: "Sleep"
sequence:
- scene: scene.climate_main_thermostat_sleep_2
default:
- scene: scene.climate_main_thermostat_home
- scene: scene.mm_monitor_on
- alias: Also set the other thermostats depending on sleep mode and current temperature
choose:
- conditions:
- condition: state
entity_id: sensor.house_mode
state: "Sleep"
- condition: template
value_template: "{{ state_attr('weather.home', 'temperature') < (states('input_number.winter_summer_threshold')|float) }}"
sequence:
- scene: scene.climate_other_thermostats_sleep_winter
- conditions:
- condition: state
entity_id: sensor.house_mode
state: "Home"
- condition: template
value_template: "{{ state_attr('weather.home', 'temperature') < (states('input_number.winter_summer_threshold')|float) }}"
sequence:
- scene: scene.climate_other_thermostats_home_winter
default:
- scene: scene.climate_other_thermostats_summer
read more
19
Jul2019
Fixing a bricked EdgeRouter Lite
Last week the EdgeRouter I use for my office did not come back after a reboot or perhaps I was too impatient, so I tried to reset it and that is when things went wrong.
Long story short, somehow I got the router into a state where it would not boot up anymore and the only way into it was the console port, for which I did not have a cable. Then I managed to find an old article which messed up my the routers USB drive so things took a turn for the worst. But fear not, it all worked out in the end, even though the only help I got from UBNT support was absolute zilch.
Here I outline some useful links for anyone else that may run into this issue, but mostly so I have it documented for next time ;). Before I get started here, the credit on everything here goes to others who documented this well on various locations.
Connecting to the console
In order to connect to the console, you will need a USB to RJ45 cable. I bought one off of Amazon which worked great right out of the box for me.
In order to connect (on a Mac), all you need to do is run:
> ls -ltr /dev/*usb*
crw-rw-rw- 1 root wheel 21, 3 Jul 17 15:48 /dev/cu.usbserial-AI038TPF
crw-rw-rw- 1 root wheel 21, 2 Jul 17 08:56 /dev/tty.usbserial-AI038TPF
> screen /dev/tty.usbserial-AI038TPF 115200
Useful links
There are a few links that were helpful here and I have them listed here, but I am going to outline what I had to do ultimately since I followed the first one and it messed me up more.
(ARCHIVED) EdgeRouter – Last Resort Recovery – DO NOT USE, Only as reference.
Recovering an unresponsive Ubiquiti EdgeRouter Lite router – DO NOT USE, Only as reference
EdgeRouter – Manual TFTP Recovery – Try this link first.
mkeosfs – easily generate USB image for EdgeRouter
The third link above is perhaps the first thing you should try if you have not messed up your router bad enough, but I had to use the 4th and 5th links.
The EdgeRouter’s USB Drive
I kept reading about this, and could not believe that there was a usb drive in the edge router, but I guess ultimately that was a good design for when it goes bad and these routers used to have a history of the drives going bad.
There are three screws on the back of the router that you can open and the router comes apart (Note: you may void your warranty by doing this). Then the flash drive is right in your face.

Recovering the file system
Once the USB drive is unplugged, connect it to your PC/Mac and run the commands to recreate the drive. I found the easiest way was to use the mkeosdrive script provided in the last link above.
I ran the commands below, but if you read the GitHub site properly, there is a way to recreate the drive and include your backup in there as well.
# Get the path to the USB drive
> sudo disk -l
# Then run the command to create the drive
> sudo ./mkeosdrive /dev/sdb ER-e100.v2.0.4.5199165.tar
Rebooting the router
Once the USB drive is ready, plug it back into your router, close things up. Then just wire it up and wait for it to boot. It should be back to normal.
I also found other links where folks talk about creating a backup of the USB drive in case something like this happens again, but what are the chances of that……right? 😉
read more15
Apr2018
Dealing with SQLite files in mobile apps
Recently I found myself wanting to inspect what was in the application database outside of the mobile application I was working on, which as usual lead me to search for a solution on DuckDuckGo.
I found a great link here, which basically says:
- Download and install SQLite command line tools if necessary (OSX comes with one).
- Find the SQLite file you want to inspect
- Run the command to open the database and inspect it:
sqlite3 /Users/<username>/Library/Developer/CoreSimulator/Devices/<Simulator device ID>/data/Containers/Data/Application/<App id>/Library/Private\ Documents/_alloy_.sql
sqlite> .tables
user order item
sqlite> .schema user
CREATE TABLE user (id INETGER PRIMARY KEY, uname TEXT, fname TEXT, lname TEXT);
sqlite>select * from user;
1|jsmith|John|Smith
read more
11
Apr2018
How to determine and set your default java version on OSX
[korey@localhost ~]$ cd /Library/Java/JavaVirtualMachines
[korey@localhost /Library/Java/JavaVirtualMachines]$ ls -al
This will give you a list of JDKs that you have installed.
To set the default java version to 1.8.0_131 for example, use the following command:
[korey@localhost ~]$ /usr/libexec/java_home -v 1.8.0_131 --exec javac -version
Related link read more
17
Jan2018
IoT Devices and Network Security

Image credits: isBuzzNews
Consumer grade hardware and custom firmware
This is the first option that we talked about. Here you could go with a router like the Asus AC-RT66U or the Linksys WRT series, but make sure to do your due diligence and confirm that the router you have or you want to get is supported. This includes reading the forums on other users that have setup these routers to see if they have run into issues or not. Here are some of your options for custom firmware:- DD-WRT – This is perhaps the most popular option and the one with the widest support for consumer grade routers. Its UI layout is smart enough that basic setup should be a breeze, but it is capable of so much more if you spend the time to dig into it.
- Tomato – This one has a few versions, but I’ve linked to the more popular version of it. This is like DD-WRT on Steriods since it also provides you live refresh and better statistics tracking right out of the box.
- Advanced Tomato – This is the same as Tomato but with much nicer UI. I really enjoyed using this briefly. If you like Tomato, you’e gonna love this.
- OpenWRT / LEDE – LEDE was a fork of OpenWRT, but they have recently announced that they are merging again. This has the least number of supported devices and relieves are less frequent, but if you know your networking, its the best option. This is the only one that includes a package manager UI to you can add other packages easily through the UI. This also makes it easier to add functionality that the other firmwares may not provide out of the box.
Business grade hardware
As a stepping stone, I recommend you play around by installing one of the custom firmwares mentioned previously on the router that you have so you get familiar with the concepts, and once you get fed up of fighting to get things working, you move up to business grade hardware. I am assuming that you are not reading this far unless you’re a noob. The options here are endless and so are the expenses, so I’ll stick to the option that I’ve had experience with (installing at costomer locations), which gives you a big bang for the buck. Ubiquiti! They provide a range of wired and wireless products that are pretty much in line with high end consumer devices in price, but from a stability and functionality perspective, they are flawless (as much as can be). For example, an Edge Router Lite 3 plus a Unifi AC Pro model can cost less than a Linksys Max-Stream AC4000 MU-MIMO Wi-Fi Tri-Band Router and provide way more functionality and most probably better performance. Setting up a network in a 2700sq.ft. space, I ended up replacing two wireless routers, with just the one Unifi AC Pro. Of course had to use the Edge Router Lite as well since the Unifi by itself does not have everything you need, and you may need a (managed) switch as well if setting up a more complex VLAN. The one downside to the Unifi line of products is that they require a controller software be running on a PC or the cloud key so you can control them (i.e. there is no web interface without the controller software), but still this is a great setup.The Network
Now the real part. As Spiderman’s wise uncle Ben said, “With great power comes great responsibility.” So the more smart devices you have (more power), the more you need to be careful (responsible). There have been numerous articles about many smart devices that have been either communicating in the open (intentionally or otherwise) or are left open to hacking, so it only makes sense to separate these devices from the rest of your network. We’ll start with the base setup and then make things more complicated optionally.
- VLAN 10 is the business/home network. Computers and devices on this network have full internet access, as well as full access to the IoT network (VLAN 20).
- VLAN 20 is the IoT network. This network is isolated from both the business/home network and the guest network. You could provide full internet access to this network or optionally limit access here as well to well known protocols like HTTP/S, DNS, NTP, etc.
- VLAN 30 is the guest network which should not have access to either of the other networks; just Internet. Again, internet access here could be limited to just a few protocols as well. You could further protect yourself and your guests by using the AP isolation feature of your Wireless Access Point if it has it.
16
Apr2017
Solving Appcelerator Compile Issue – Invalid Request
result from /build-verify=> {"success":false,"error":"invalid request","code":"com.appcelerator.security.invalid.session"}, err=null
The answer, perform the following
[korey@localhost ~]$î‚°Â appc logout
Appcelerator Command-Line Interface, version 6.2.0
Copyright (c) 2014-2017, Appcelerator, Inc. All Rights Reserved.
*** Logged Out ***
[korey@localhost ~]$î‚°Â appc login
Appcelerator Command-Line Interface, version 6.2.0
Copyright (c) 2014-2017, Appcelerator, Inc. All Rights Reserved.
Appcelerator Login required to continue ...
? Appcelerator ID: me@company.com
? Password: *********
Generating Developer Certificate and Private/Public Keys...
me@company.com logged into organization company.com [100011118]
read more
28
Jun2015
Manage Apache on OSX (Updated or Yosemite)
- Apache is installed at: /etc/apache2
- Apache config is at: /etc/apach2/httpd.conf
- Apache user config is at: /etc/apach2/users/<username>.conf
- Apache extra config is at: /etc/apach2/extra/*.conf
- You can customize your own virtual server by modifying: /etc/apach2/users/<username>.conf
- You can start/stop Apache by:
- Enabling/disabling Web Sharing in System Preferences
- running the following in terminal:
sudo apachectl
- Create folder to host your files (e.g. /Users/<my_username>/Sites/)
- Create an index file in the above folder with a message so you know when it is working.
- In /etc/apach2/httpd.conf, make sure:
- userdir_module is loaded (i.e. not commented out).
LoadModule userdir_module libexec/apache2/mod_userdir.so - httpd-userdir.conf is included.
Include /etc/apache2/extra/httpd-userdir.conf
- userdir_module is loaded (i.e. not commented out).
- In /etc/apache2/extra/httpd-userdir.conf, make sure that user configuration files are included.
Include /private/etc/apache2/users/*.conf - In /etc/apache2/users, make sure to create a user file for yourself (note: you will have to use sudo to make sure permissions on the file are set to 644 and owned by root:wheel).
/etc/apache2/users/<my_username>.conf
Contents:<Directory "/Users/<my_username>/Sites/"> Options Indexes MultiViews AllowOverride All Require all granted DirectoryIndex index.html </Directory>
10
Apr2015
Have you ordered your Apple Watch?

18
Mar2015
Getting Fancy with Terminal
[korey@localhost ~]$ brew install fish
Now that fish is installed, you will have a few options in making it your default shell. Homebrew provides instructions already, but I just wanted it on my account for Terminal, so I changed the shell command in Terminal’s preferences.

[korey@localhost ~]$ brew install python
[korey@localhost ~]$ pip install powerline-status
The next step is to install the patched fonts so your prompt will not have strange characters on it. For this part, you need to download the patched fonts zip from github, and then run the install.sh script included there. The last step here is equally important; you should change the font used by your selected terminal profile to one of the fonts for Powerline.

[korey@localhost ~]$ vi ~/.config/fish/config.fish
# source autojump
[ -f /usr/local/share/autojump/autojump.fish ]; and . /usr/local/share/autojump/autojump.fish
#source powerline
set fish_function_path $fish_function_path "/usr/local/lib/python2.7/site-packages/powerline/bindings/fish"
powerline-setup
My last step was to install auto jump, which is another great tool and you can see that it has also been included in the above listing in my Fish config.
[korey@localhost ~]$ brew install autojump
You should now end up with a autocomplete terminal similar to this:

17
Mar2015
Installing MongoDB on OSX (Yosemite)

[korey@localhost ~]$ brew install mongodb
At this point MongoDB is installed. To start it manually, first create the location where the DB will be stored (default is /data/db):
[korey@localhost ~]$ mkdir /data/db
[korey@localhost ~]$ mongd
Note that the user running mongod needs to have write access to the DB folder. The downside here is that the DB needs to be started manually each time and it will run as your userid.
In order to automatically start the service, it is necessary to create a LaunchDaemon which will allow the service to start as soon as the computer starts.
-
1. The first step is to create a service account so the service does not run as root.
2. Next, is to create a proper location for the log and database location:
[korey@localhost ~]$ sudo mkdir -p /var/lib/mongodb
[korey@localhost ~]$ sudo mkdir -p /var/log/mongo
[korey@localhost ~]$ sudo chown -R _mongo:_mongo /var/lib/mongodb
[korey@localhost ~]$ sudo chown -R _mongo:_mongo /var/log/mongo
3. Now that we have an account and location, it is time to create the daemon plist file:
Label
org.mongo.mongod
ProgramArguments
/usr/local/bin/mongod
--dbpath
/var/lib/mongodb/
--logpath
/var/log/mongo/mongodb.log
KeepAlive
UserName
_mongo
GroupName
_mongo
Store this file at: /Library/LaunchDaemons and name it: org.mongo.mongod.plist.
[korey@localhost ~]$ sudo launchctl load /Library/LaunchDaemons/org.mongo.mongod.plist
[korey@localhost ~]$ sudo launchctl unload /Library/LaunchDaemons/org.mongo.mongod.plist
read more