Universal Thermostat is designed to complete almost all climate control tasks in a certain zone.
Component grew out of Smart Thermostat from hacker-cb, who did the great job I am extremely appreciated for!
- supports multiple heating and cooling entities
- supports various target entity domains:
switch,climate,input_boolean,number,input_number - supports invert logic for any heater or cooler
- supports PID/PWM regulation for supported entities
- supports
automode with adjustable cooling and heating deltas - supports
heat_coolmode with separate temperature cooling and heating setpoints - supports templates for configurable parameters
- supports presets with flexible parameters
- supports multiple windows openings (or other devices that should prevent heater/cooler working) with individual timers and inversions
switch,input_boolean- basic toggling mode or PWM modeclimate- basic toggling mode or PID regulator modenumber+switch,input_number+switch- PID regulator mode with toggleable switch
This is recommended way, which will handle one-click upgrade in HACS.
- Install hacs if it is not installed.
- Open HACS -> Integrations. Click 3 dots in the upper right corner.
- Click Custom repositories.
- Add
vaproloff/universalThermostatrepository. - Find
Universal Thermostatin HACS catalog and clickinstallbutton.
NOTE: This is not recommended way, because you will need to upgrade component manually.
-
Copy
/custom_components/universal_thermostatto your<config_dir>/custom_components/directory.- On HassIO the final location will be
/config/custom_components/universal_thermostat. - On Supervised the final location will be
/usr/share/hassio/homeassistant/custom_components/universal_thermostat. - NOTE: You will need to create the
custom_componentsfolder if it does not exist.
- On HassIO the final location will be
-
Restart Home Assistant Core.
climate:
- platform: universal_thermostat
target_sensor: sensor.kitchen_temperature
cooler: switch.kitchen_cooler_switchclimate:
- platform: universal_thermostat
name: Kitchen Thermostat
unique_id: kitchen_thermostat
object_id: kitchen_thermostat
target_sensor: sensor.kitchen_temperature
min_temp: 18
max_temp: 28
precision: 0.1
target_temp_step: 0.5
target_temp: 24.5
target_temp_low: 24
target_temp_high: 25
auto_cool_delta: "{{ states('input_number.auto_cool_delta') | float }}"
auto_heat_delta: 1.0
heat_cool_disabled: false
initial_hvac_mode: heat_cool
heater:
- entity_id: climate.kitchen_heating_floor_thermostat
kp: 1.3
ki: 0.5
kd: 10
pid_sample_period: 300
min: 16
max: 35
- entity_id: switch.kitchen_heater_switch
inverted: false
cold_tolerance: 0.3
hot_tolerance: 0.3
min_cycle_duration: 600
cooler:
- entity_id: number.kitchen_cooler_regulator
switch_entity_id: switch.kitchen_cooler_regulator_switch
switch_inverted: true
kp: 20
ki: 0.01
kd: 2
min: 0
max: 10
- entity_id: climate.kitchen_cooler_thermostat
cold_tolerance: 0.3
hot_tolerance: 0.3
target_temp_delta: 1.0
ignore_windows: true
windows:
- entity_id: switch.window_1
timeout:
seconds: 2
- entity_id: input_boolean.window_2
inverted: true
timeout: "{{ states('input_number.window_open_timeout') | float }}"
- binary_sensor.window_3
presets:
sleep:
temp_delta: "{{ states('input_number.sleep_temp_delta') | float }}"
away:
heat_delta: -1.0
cool_delta: 2.0
eco:
target_temp: 18.0
heat_target_temp: 18.0
cool_target_temp: 29.0target_temp- Climate target temperature, can be changed in UI. Initial can be set viatarget_tempconfig option.cur_temp- Current sensor temperature. Will be reported bytarget_sensorentity.CONFIG.xxx- Reference to the config option.CONFIG.CONTROLLER.xxx- Reference to the config controller option (heater/cooler).
name(Required) - Climate entity nameunique_id(Optional) - Climate entityunique_idobject_id(Optional) - Climate entity suggestedentity_idcooler(Optional) - String, Array or Map of the coolers.heater(Optional) - String, Array or Map of the heaters.target_sensor(Required) - Target temperature sensormin_temp(Optional, default=7) - Set minimum set point available.max_temp(Optional, default=35) - Set maximum set point available.target_temp(Optional) - Initial target temperature.target_temp_low(Optional) - Initial target low temperature (forheat_coolmode).target_temp_high(Optional) - Initial target high temperature (forheat_coolmode).auto_cool_delta(Optional) - Target temperature delta for Coolers inautomode. Could be a template. Default: 1.0.auto_heat_delta(Optional) - Target temperature delta for Heaters inautomode. Could be a template. Default: 1.0.heat_cool_disabled(Optional) - Disablesheat_coolmode. Default: false.initial_hvac_mode(Optional) - Initial HVAC mode.precision(Optional) - Precision for this device. Supported values are 0.1, 0.5 and 1.0. Default: 0.1 for Celsius and 1.0 for Fahrenheit.target_temp_step(Optional) - Temperature set point step. Supported values are 0.1, 0.5 and 1.0. Default: equals toprecision.windows(Optional) - String, Array or Map of the window entities.presets(Optional) - Map of presets.
NOTE: at least one of heater or cooler is required.
Initial HVAC mode can be set via initial_hvac_mode config option.
Thermostat behavior will depend on active HVAC mode. HVAC mode can be set in UI.
NOTE: available if at least one CONFIG.heater was defined.
- All heater controllers will be turned on. Specific behavior of each heater will depend on the controller type.
- All cooler controllers will be turned off.
NOTE: available if at least one CONFIG.coller was defined.
- All cooler controllers will be turned on. Specific behavior of each cooler will depend on the controller type.
- All heater controllers will be turned off.
NOTE: available if at least one CONFIG.heater and at least one CONFIG.cooler were defined.
- All cooler and heater controllers will be turned on.
- Specific behavior of each heater and cooler will depend on the controller type.
- All cooler controllers will pick
target_temp_highas theirtarget_temp. - All heater controllers will pick
target_temp_lowas theirtarget_temp.
NOTE: available if at least one CONFIG.heater and at least one CONFIG.cooler were defined.
- All cooler and heater controllers will be turned on.
- Specific behavior of each heater and cooler will depend on the controller type.
- All cooler controllers will pick
target_temp + auto_cool_deltaas theirtarget_temp. - All heater controllers will pick
target_temp - auto_heat_deltaas theirtarget_temp.
NOTE: turning on controller DOES NOT MEANS turning on CONFIG.CONTROLLER.enitity_id inside controller.
Controller behavior depends on the specific controller logic and described below for each controller.
Specific controller will be created for each heater/cooler config option based on CONFIG.CONTROLLER.enitity_id domain.
Supported domains: switch,input_boolean
entity_id(Required) - Target entity ID.inverted(Optional, default=false) - Need to invertentity_idlogic.keep_alive(Optional) - Send keep-alive interval. Use with heaters, coolers, A/C units that shut off if they don’t receive a signal from their remote for a while.ignore_windows(Optional, default=false) - Need to ignore windows logic.min_cycle_duration(Optional, default=null) - Minimal cycle duration. Used to protect from on/off cycling.cold_tolerance(Optional, default=0.3) - Cold tolerance.hot_tolerance(Optional, default=0.3) - Hot tolerance.
- Turn on
entity_idifcur_temp <= target_temp - cold_tolerance(heater) orcur_temp >= target_temp + self._hot_tolerance(cooler) - No
entity_idchanges will be performed if configmin_cycle_durationwas set and enough time was not passed since last switch. - Behavior on/off will be inverted if
invertedconfig option was set totrue
Domains: switch,input_boolean.
- Internal PID limits are integers, defined as constants
PWM_SWITCH_MIN_VALUEandPWM_SWITCH_MAX_VALUE(0, 100). So, you must use this limits when tuningpid_paramsterms.
entity_id(Required) - Target entity ID.inverted(Optional, default=false) - Need to invertentity_idlogic.keep_alive(Optional) - Send keep-alive interval. Use with heaters, coolers, A/C units that shut off if they don’t receive a signal from their remote for a while.ignore_windows(Optional, default=false) - Need to ignore windows logic.kp(Required) - PID proportional coefficient, could be a template (Always positive, will be inverted internally for cool mode).ki(Required) - PID integral coefficient, could be a template (Always positive, will be inverted internally for cool mode).kd(Required) - PID derivative coefficient, could be a template (Always positive, will be inverted internally for cool mode).pid_sample_period(Optional) - PID constant sample time period.pwm_period(Required) - PWM period. Switch will be turned on and turned off according internal PID output once in this period.
- PID output will be calculated internally based on provided PID coefficients.
pwm_periodwill be separated to two parts:ONandOFF. Each part duration will depend on PID output.- PWM on/off need will be checked every
pwm_period/100time but not often than each 1 second. (PWM_SWITCH_MAX_VALUEinternal const variable) - Behavior on/off will be inverted if
invertedconfig option was set totrue. - It is keep on/off state duration before Home Assistant restart. Last change time is saved in thermostat state attributes.
NOTE: This mode will be set if entity domain is one of the listed above and pid_params config entry is present.
Domains: climate
entity_id(Required) - Target entity ID.inverted(Optional, default=false) - Need to invertentity_idlogic.keep_alive(Optional) - Send keep-alive interval. Use with heaters, coolers, A/C units that shut off if they don’t receive a signal from their remote for a while.ignore_windows(Optional, default=false) - Need to ignore windows logic.min_cycle_duration(Optional, default=null) - Minimal cycle duration. Used to protect from on/off cycling.cold_tolerance(Optional, default=0.3) - Cold tolerance. Could be a template.hot_tolerance(Optional, default=0.3) - Hot tolerance. Could be a template.target_temp_delta(Optional, default=None) - Delta between Thermostat set point and target climate entity. Could be a template. If not mentioned - temperature control will be disabled.
- Climate
entity_idwill be turned on when controller is active. - Climate
entity_idwill be turned off when controller is not active. - Climate
entity_idtemperature set point will be adjusted takingtarget_temp_deltainto account if it specified:- Thermostat set point +
target_temp_delta- for heaters; - Thermostat set point -
target_temp_delta- for coolers;
- Thermostat set point +
Domains: climate
entity_id(Required) - Target entity ID.inverted(Optional, default=false) - Need to invertentity_idlogic.keep_alive(Optional) - Send keep-alive interval. Use with heaters, coolers, A/C units that shut off if they don’t receive a signal from their remote for a while.ignore_windows(Optional, default=false) - Need to ignore windows logic.kp(Required) - PID proportional coefficient, could be a template (Always positive, will be inverted internally for cool mode).ki(Required) - PID integral coefficient, could be a template (Always positive, will be inverted internally for cool mode).kd(Required) - PID derivative coefficient, could be a template (Always positive, will be inverted internally for cool mode).pid_sample_period(Optional) - PID constant sample time period.min(Optional) - Minimum temperature which can be set. Attributemin_tempfromentity_idwill be used if not specified. Could be a template.max(Optional) - Maximum temperature which can be set. Attributemax_tempfromentity_idwill be used if not specified. Could be a template.
- Climate
entity_idwill be turned on when controller is active. - Climate
entity_idwill be turned off when controller is not active. - Climate
entity_idtemperature will be adjusted everypid_sample_periodit is provided, or on everyCONFIF.target_sensorupdate ifpid_sample_periodis not provided. - PID parameters will be inverted if
invertedwas set totrue
Domains: number,input_number
entity_id(Required) - Target entity ID.inverted(Optional, default=false) - Need to invertentity_idlogic.keep_alive(Optional) - Send keep-alive interval. Use with heaters, coolers, A/C units that shut off if they don’t receive a signal from their remote for a while.ignore_windows(Optional, default=false) - Need to ignore windows logic.pid_params(Required) - PID params comma-separated string or array in the formatKp, Ki, Kd(Always positive, will be inverted internally for cool mode).pid_sample_period(Optional) - PID constant sample time period.min(Optional) - Minimum temperature which can be set. Attributeminfromentity_idwill be used if not specified.max(Optional) - Maximum temperature which can be set. Attributemaxfromentity_idwill be used if not specified.switch_entity_id(Optional) - Switch entity which belongs toswitch,input_booleandomains.switch_inverted(Optional, default=false) - Isswitch_entity_idinverted?
- Switch
switch_entity_idwill be turned on when controller is active if it is set. - Switch
switch_entity_idwill be turned off when controller is not active if it is set. - Number
entity_idtemperature will be adjusted everypid_sample_periodit is provided, or on everyCONFIF.target_sensorupdate ifpid_sample_periodis not provided. pid_paramswill be inverted ifinvertedwas set totrueswitch_entity_idbehavior will be inverted ifswitch_invertedwas set totrue
Windows are optional and their logic will be available if at least one window entity added to the config.
switchinput_booleanbinary_sensor
windows: binary_sensor.my_windowwindows:
- binary_sensor.my_window
- input_boolean.heater_blockwindows:
- entity_id: binary_sensor.my_window
timeout: "{{ states('input_number.window_open_timeout') | float }}"
- entity_id: input_boolean.heater_can_work
inverted: truewindows:
- binary_sensor.my_window_1
- entity_id: binary_sensor.my_window_2
timeout:
minutes: 2
- entity_id: input_boolean.heater_can_work
inverted: trueentity_id(Required) - Target entity ID.inverted(Optional, default=false) - Need to invertentity_idlogic.timeout(Optional, default=none) - time period to wait until stop/start controller after window opening/closing. Can be a template.
- after any window entity turns
on, controller stops working (offifinverted: true) - after all window entities turn
off, controller starts working (onifinverted: true) - if controller has
ignore_windowsconfig option - it doesn't take into account windows states - if window has a
timeoutconfig option - it stops/starts controllers after time period mentioned
Presets are optional and will be available if at least one preset mode added to the config. All preset modes are equal in functionality, their behaviour depends only on used config parameters.
Mapping key will be a preset name. Preset can have any name, but it is recommended to use defaults, that support icons and translations:
ecoawaysleepboostcomforthomeactivity
- if any preset is active, changing
hvac_modemanually resets current preset toNone - if any preset is active, activating
Nonepreset_moderestores thermostat parameters to None-preset state - if any preset is active, activating another delta
preset_modeapplies all changes relatively to None-preset state - preset activation can change
hvac_modeif preset config needs it - if you want to decrease target temperature, use negative float number.
presets:
sleep:
temp_delta: -1.0temp_delta(Required) - single target temperature delta, signed float, can be a template
- changes thermostat target temperatures (both ranged and non-ranged):
target_temp + temp_deltatarget_temp_low + temp_deltatarget_temp_high + temp_delta
presets:
away:
heat_delta: -1.0
cool_delta: 2.0heat_delta(Required) - heating target temperature delta, signed float, can be a templatecool_delta(Required) - heating target temperature delta, signed float, can be a template
- if
hvac_modeisCOOL- changes thermostat target temperature:target_temp + cool_delta
- if
hvac_modeisHEAT- changes thermostat target temperature:target_temp + heat_delta
- if
hvac_modeisHEAT_COOL- changes thermostat target temperature:target_temp_low + heat_deltatarget_temp_high + cool_delta
- if
hvac_modeisAUTO- doesn't change thermostat target temperature, but creates additional deltas toauto_cool_deltaandauto_heat_deltaforcontrollers:- heaters'
target_temps will betarget_temp - auto_heat_delta + heat_delta - coolers'
target_temps will betarget_temp + auto_cool_delta + cool_delta
- heaters'
presets:
eco:
heat_target_temp: 18.0
cool_target_temp: 28.0
comfort:
target_temp: 25.0target_temp(Optional) - single target temperature, signed float, can be a templateheat_target_temp(Optional) - heating target temperature, signed float, can be a templatecool_target_temp(Optional) - cooling target temperature, signed float, can be a template
- if
hvac_modeisCOOL- changes thermostat target temperature tocool_target_tempif available or totarget_temp: - if
hvac_modeisHEAT- changes thermostat target temperature toheat_target_tempif available or totarget_temp: - if
hvac_modeisHEAT_COOL- changes thermostat target temperatures:target_temp_lowwill beheat_target_tempif available ortarget_temptarget_temp_highwill becool_target_tempif available ortarget_temp
- if
hvac_modeisAUTOand onlytarget_tempis available - changes thermostat target temperature totarget_temp: - if
hvac_modeisAUTOandheat_target_tempandcool_target_tempare available - doesn't change thermostat target temperature, but creates additional target temperatures forcontrollers:- heaters'
target_temps will beheat_target_temp - coolers'
target_temps will becool_target_temp
- heaters'
NOTE: Any of these config schemas could be used, but not mixed!
- Adjustable delays for turning heater/cooler on/off.
- Add support templates for
pwm_period.
- Set up your logger to print debug messages for this component using:
logger:
default: info
logs:
custom_components.universal_thermostat: debug- Restart HA
- Verify you're still having the issue
- File an issue in this GitHub Repository containing your HA log (Developer section > Info > Load Full Home Assistant Log)
- You can paste your log file at pastebin https://pastebin.com/ and submit a link.
- Please include details about your setup (Pi, NUC, etc, docker?, HassOS?)
- The log file can also be found at
/<config_dir>/home-assistant.log