Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f970c18eaf | ||
|
|
af51ef62e0 | ||
|
|
b38fbd9d78 | ||
|
|
6e8e72e343 | ||
|
|
2bebe3e210 | ||
|
|
aa3b87762d | ||
|
|
f4cabbf2c0 | ||
|
|
24b59e545b | ||
|
|
5997a26c73 | ||
|
|
fe4b9ced81 | ||
|
|
c4fc976007 | ||
|
|
31d862acab | ||
|
|
9709a9eed0 | ||
|
|
61eae8c066 | ||
|
|
e16daa3d53 | ||
|
|
90a6c926e3 |
@@ -1,196 +1,196 @@
|
||||
default_config:
|
||||
|
||||
logger:
|
||||
default: info
|
||||
logs:
|
||||
custom_components.versatile_thermostat: info
|
||||
custom_components.versatile_thermostat.underlyings: debug
|
||||
custom_components.versatile_thermostat.climate: debug
|
||||
default: info
|
||||
logs:
|
||||
custom_components.versatile_thermostat: info
|
||||
custom_components.versatile_thermostat.underlyings: debug
|
||||
custom_components.versatile_thermostat.climate: debug
|
||||
|
||||
# If you need to debug uncommment the line below (doc: https://www.home-assistant.io/integrations/debugpy/)
|
||||
debugpy:
|
||||
start: true
|
||||
wait: false
|
||||
port: 5678
|
||||
start: true
|
||||
wait: false
|
||||
port: 5678
|
||||
|
||||
input_number:
|
||||
fake_temperature_sensor1:
|
||||
name: Temperature
|
||||
min: 0
|
||||
max: 35
|
||||
step: .1
|
||||
icon: mdi:thermometer
|
||||
unit_of_measurement: °C
|
||||
mode: box
|
||||
fake_external_temperature_sensor1:
|
||||
name: Ext Temperature
|
||||
min: -10
|
||||
max: 35
|
||||
step: .1
|
||||
icon: mdi:home-thermometer
|
||||
unit_of_measurement: °C
|
||||
mode: box
|
||||
fake_current_power:
|
||||
name: Current power
|
||||
min: 0
|
||||
max: 1000
|
||||
step: 10
|
||||
icon: mdi:flash
|
||||
unit_of_measurement: kW
|
||||
fake_current_power_max:
|
||||
name: Current power max threshold
|
||||
min: 0
|
||||
max: 1000
|
||||
step: 10
|
||||
icon: mdi:flash
|
||||
unit_of_measurement: kW
|
||||
fake_temperature_sensor1:
|
||||
name: Temperature
|
||||
min: 0
|
||||
max: 35
|
||||
step: .1
|
||||
icon: mdi:thermometer
|
||||
unit_of_measurement: °C
|
||||
mode: box
|
||||
fake_external_temperature_sensor1:
|
||||
name: Ext Temperature
|
||||
min: -10
|
||||
max: 35
|
||||
step: .1
|
||||
icon: mdi:home-thermometer
|
||||
unit_of_measurement: °C
|
||||
mode: box
|
||||
fake_current_power:
|
||||
name: Current power
|
||||
min: 0
|
||||
max: 1000
|
||||
step: 10
|
||||
icon: mdi:flash
|
||||
unit_of_measurement: kW
|
||||
fake_current_power_max:
|
||||
name: Current power max threshold
|
||||
min: 0
|
||||
max: 1000
|
||||
step: 10
|
||||
icon: mdi:flash
|
||||
unit_of_measurement: kW
|
||||
|
||||
input_boolean:
|
||||
# input_boolean to simulate the windows entity. Only for development environment.
|
||||
fake_window_sensor1:
|
||||
name: Window 1
|
||||
icon: mdi:window-closed-variant
|
||||
# input_boolean to simulate the heater entity switch. Only for development environment.
|
||||
fake_heater_switch3:
|
||||
name: Heater 3
|
||||
icon: mdi:radiator
|
||||
fake_heater_switch2:
|
||||
name: Heater 2
|
||||
icon: mdi:radiator
|
||||
fake_heater_switch1:
|
||||
name: Heater 1
|
||||
icon: mdi:radiator
|
||||
fake_heater_4switch1:
|
||||
name: Heater (multiswitch1)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4switch2:
|
||||
name: Heater (multiswitch2)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4switch3:
|
||||
name: Heater (multiswitch3)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4switch4:
|
||||
name: Heater (multiswitch4)
|
||||
icon: mdi:radiator
|
||||
# input_boolean to simulate the motion sensor entity. Only for development environment.
|
||||
fake_motion_sensor1:
|
||||
name: Motion Sensor 1
|
||||
icon: mdi:run
|
||||
# input_boolean to simulate the presence sensor entity. Only for development environment.
|
||||
fake_presence_sensor1:
|
||||
name: Presence Sensor 1
|
||||
icon: mdi:home
|
||||
# input_boolean to simulate the windows entity. Only for development environment.
|
||||
fake_window_sensor1:
|
||||
name: Window 1
|
||||
icon: mdi:window-closed-variant
|
||||
# input_boolean to simulate the heater entity switch. Only for development environment.
|
||||
fake_heater_switch3:
|
||||
name: Heater 3
|
||||
icon: mdi:radiator
|
||||
fake_heater_switch2:
|
||||
name: Heater 2
|
||||
icon: mdi:radiator
|
||||
fake_heater_switch1:
|
||||
name: Heater 1
|
||||
icon: mdi:radiator
|
||||
fake_heater_4switch1:
|
||||
name: Heater (multiswitch1)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4switch2:
|
||||
name: Heater (multiswitch2)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4switch3:
|
||||
name: Heater (multiswitch3)
|
||||
icon: mdi:radiator
|
||||
fake_heater_4switch4:
|
||||
name: Heater (multiswitch4)
|
||||
icon: mdi:radiator
|
||||
# input_boolean to simulate the motion sensor entity. Only for development environment.
|
||||
fake_motion_sensor1:
|
||||
name: Motion Sensor 1
|
||||
icon: mdi:run
|
||||
# input_boolean to simulate the presence sensor entity. Only for development environment.
|
||||
fake_presence_sensor1:
|
||||
name: Presence Sensor 1
|
||||
icon: mdi:home
|
||||
|
||||
climate:
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat1
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat2
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat3
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat4
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat5
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat6
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat7
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat8
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat9
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat1
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat2
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat3
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat4
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat5
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat6
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat7
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat8
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
- platform: generic_thermostat
|
||||
name: Underlying thermostat9
|
||||
heater: input_boolean.fake_heater_switch3
|
||||
target_sensor: input_number.fake_temperature_sensor1
|
||||
|
||||
recorder:
|
||||
include:
|
||||
domains:
|
||||
- input_boolean
|
||||
- input_number
|
||||
- switch
|
||||
- climate
|
||||
- sensor
|
||||
include:
|
||||
domains:
|
||||
- input_boolean
|
||||
- input_number
|
||||
- switch
|
||||
- climate
|
||||
- sensor
|
||||
|
||||
template:
|
||||
- binary_sensor:
|
||||
- name: maison_occupee
|
||||
unique_id: maison_occupee
|
||||
state: "{{is_state('person.jmc', 'home') }}"
|
||||
device_class: occupancy
|
||||
- sensor:
|
||||
- name: "Total énergie switch1"
|
||||
unique_id: total_energie_switch1
|
||||
unit_of_measurement: "kWh"
|
||||
device_class: energy
|
||||
state_class: total_increasing
|
||||
state: >
|
||||
{% set energy = state_attr('climate.thermostat_switch_1', 'total_energy') %}
|
||||
{% if energy == 'unavailable' or energy is none%}unavailable{% else %}
|
||||
{{ ((energy | float) / 1.0) | round(2, default=0) }}
|
||||
{% endif %}
|
||||
- name: "Total énergie climate 2"
|
||||
unique_id: total_energie_climate2
|
||||
unit_of_measurement: "kWh"
|
||||
device_class: energy
|
||||
state_class: total_increasing
|
||||
state: >
|
||||
{% set energy = state_attr('climate.thermostat_climate_2', 'total_energy') %}
|
||||
{% if energy == 'unavailable' or energy is none%}unavailable{% else %}
|
||||
{{ ((energy | float) / 1.0) | round(2, default=0) }}
|
||||
{% endif %}
|
||||
- name: "Total énergie chambre"
|
||||
unique_id: total_energie_chambre
|
||||
unit_of_measurement: "kWh"
|
||||
device_class: energy
|
||||
state_class: total_increasing
|
||||
state: >
|
||||
{% set energy = state_attr('climate.thermostat_chambre', 'total_energy') %}
|
||||
{% if energy == 'unavailable' or energy is none%}unavailable{% else %}
|
||||
{{ ((energy | float) / 1.0) | round(2, default=0) }}
|
||||
{% endif %}
|
||||
- binary_sensor:
|
||||
- name: maison_occupee
|
||||
unique_id: maison_occupee
|
||||
state: "{{is_state('person.jmc', 'home') }}"
|
||||
device_class: occupancy
|
||||
- sensor:
|
||||
- name: "Total énergie switch1"
|
||||
unique_id: total_energie_switch1
|
||||
unit_of_measurement: "kWh"
|
||||
device_class: energy
|
||||
state_class: total_increasing
|
||||
state: >
|
||||
{% set energy = state_attr('climate.thermostat_switch_1', 'total_energy') | float(default=-1) %}
|
||||
{% if energy < 0 %}{{none}}{% else %}
|
||||
{{ energy | round(2, default=0) }}
|
||||
{% endif %}
|
||||
- name: "Total énergie climate 2"
|
||||
unique_id: total_energie_climate2
|
||||
unit_of_measurement: "kWh"
|
||||
device_class: energy
|
||||
state_class: total_increasing
|
||||
state: >
|
||||
{% set energy = state_attr('climate.thermostat_climate_2', 'total_energy') | float(default=-1) %}
|
||||
{% if energy < 0 %}{{none}}{% else %}
|
||||
{{ energy | round(2, default=0) }}
|
||||
{% endif %}
|
||||
- name: "Total énergie chambre"
|
||||
unique_id: total_energie_chambre
|
||||
unit_of_measurement: "kWh"
|
||||
device_class: energy
|
||||
state_class: total_increasing
|
||||
state: >
|
||||
{% set energy = state_attr('climate.thermostat_chambre', 'total_energy') | float(default=-1) %}
|
||||
{% if energy < 0 %}{{none}}{% else %}
|
||||
{{ energy | round(2, default=0) }}
|
||||
{% endif %}
|
||||
|
||||
switch:
|
||||
- platform: template
|
||||
switches:
|
||||
pilote_sdb_rdc:
|
||||
friendly_name: "Pilote chauffage SDB RDC"
|
||||
value_template: "{{ is_state_attr('switch_seche_serviettes_sdb_rdc', 'sensor_state', 'on') }}"
|
||||
turn_on:
|
||||
service: select.select_option
|
||||
data:
|
||||
option: comfort
|
||||
target:
|
||||
entity_id: select.seche_serviettes_sdb_rdc_cable_outlet_mode
|
||||
- platform: template
|
||||
switches:
|
||||
pilote_sdb_rdc:
|
||||
friendly_name: "Pilote chauffage SDB RDC"
|
||||
value_template: "{{ is_state_attr('switch_seche_serviettes_sdb_rdc', 'sensor_state', 'on') }}"
|
||||
turn_on:
|
||||
service: select.select_option
|
||||
data:
|
||||
option: comfort
|
||||
target:
|
||||
entity_id: select.seche_serviettes_sdb_rdc_cable_outlet_mode
|
||||
|
||||
turn_off:
|
||||
service: select.select_option
|
||||
data:
|
||||
option: comfort-2
|
||||
target:
|
||||
entity_id: select.seche_serviettes_sdb_rdc_cable_outlet_mode
|
||||
turn_off:
|
||||
service: select.select_option
|
||||
data:
|
||||
option: comfort-2
|
||||
target:
|
||||
entity_id: select.seche_serviettes_sdb_rdc_cable_outlet_mode
|
||||
|
||||
frontend:
|
||||
themes:
|
||||
versatile_thermostat_theme:
|
||||
state-binary_sensor-safety-on-color: "#FF0B0B"
|
||||
state-binary_sensor-power-on-color: "#FF0B0B"
|
||||
state-binary_sensor-window-on-color: "rgb(156, 39, 176)"
|
||||
state-binary_sensor-motion-on-color: "rgb(156, 39, 176)"
|
||||
state-binary_sensor-presence-on-color: "lightgreen"
|
||||
themes:
|
||||
versatile_thermostat_theme:
|
||||
state-binary_sensor-safety-on-color: "#FF0B0B"
|
||||
state-binary_sensor-power-on-color: "#FF0B0B"
|
||||
state-binary_sensor-window-on-color: "rgb(156, 39, 176)"
|
||||
state-binary_sensor-motion-on-color: "rgb(156, 39, 176)"
|
||||
state-binary_sensor-presence-on-color: "lightgreen"
|
||||
|
||||
2
.github/workflows/cron.yaml
vendored
2
.github/workflows/cron.yaml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: Validate
|
||||
steps:
|
||||
- uses: "actions/checkout@v2"
|
||||
- uses: "actions/checkout@v3.5.2"
|
||||
|
||||
- name: HACS validation
|
||||
uses: "hacs/action@main"
|
||||
|
||||
17
.github/workflows/hacs.yml
vendored
Normal file
17
.github/workflows/hacs.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: HACS Action
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
jobs:
|
||||
hacs:
|
||||
name: HACS Action
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: HACS Action
|
||||
uses: "hacs/action@main"
|
||||
with:
|
||||
category: "integration"
|
||||
10
.github/workflows/pull.yml
vendored
10
.github/workflows/pull.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: Validate
|
||||
steps:
|
||||
- uses: "actions/checkout@v2"
|
||||
- uses: "actions/checkout@v3.5.2"
|
||||
|
||||
- name: HACS validation
|
||||
uses: "hacs/action@main"
|
||||
@@ -23,8 +23,8 @@ jobs:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: Check style formatting
|
||||
steps:
|
||||
- uses: "actions/checkout@v2"
|
||||
- uses: "actions/setup-python@v1"
|
||||
- uses: "actions/checkout@v3.5.2"
|
||||
- uses: "actions/setup-python@v4.6.0"
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- run: python3 -m pip install black
|
||||
@@ -35,9 +35,9 @@ jobs:
|
||||
name: Run tests
|
||||
steps:
|
||||
- name: Check out code from GitHub
|
||||
uses: "actions/checkout@v2"
|
||||
uses: "actions/checkout@v3.5.2"
|
||||
- name: Setup Python
|
||||
uses: "actions/setup-python@v1"
|
||||
uses: "actions/setup-python@v4.6.0"
|
||||
with:
|
||||
python-version: "3.8"
|
||||
- name: Install requirements
|
||||
|
||||
6
.github/workflows/push.yml
vendored
6
.github/workflows/push.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: Validate
|
||||
steps:
|
||||
- uses: "actions/checkout@v2"
|
||||
- uses: "actions/checkout@v3.5.2"
|
||||
|
||||
- name: HACS validation
|
||||
uses: "hacs/action@main"
|
||||
@@ -26,8 +26,8 @@ jobs:
|
||||
runs-on: "ubuntu-latest"
|
||||
name: Check style formatting
|
||||
steps:
|
||||
- uses: "actions/checkout@v2"
|
||||
- uses: "actions/setup-python@v1"
|
||||
- uses: "actions/checkout@v3.5.2"
|
||||
- uses: "actions/setup-python@v4.6.0"
|
||||
with:
|
||||
python-version: "3.x"
|
||||
- run: python3 -m pip install black
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
>  Cette intégration de thermostat vise à simplifier considérablement vos automatisations autour de la gestion du chauffage. Parce que tous les événements autour du chauffage classiques sont gérés nativement par le thermostat (personne à la maison ?, activité détectée dans une pièce ?, fenêtre ouverte ?, délestage de courant ?), vous n'avez pas à vous encombrer de scripts et d'automatismes compliqués pour gérer vos climats. ;-).
|
||||
|
||||
- [Merci pour la bière buymecoffee: https://www.buymeacoffee.com/jmcollin78](#merci-pour-la-bière-buymecoffee-httpswwwbuymeacoffeecomjmcollin78)
|
||||
- [Merci pour la bière buymecoffee](#merci-pour-la-bière-buymecoffee)
|
||||
- [Quand l'utiliser et ne pas l'utiliser](#quand-lutiliser-et-ne-pas-lutiliser)
|
||||
- [Pourquoi une nouvelle implémentation du thermostat ?](#pourquoi-une-nouvelle-implémentation-du-thermostat-)
|
||||
- [Comment installer cet incroyable Thermostat Versatile ?](#comment-installer-cet-incroyable-thermostat-versatile-)
|
||||
@@ -54,6 +54,7 @@ Ce composant personnalisé pour Home Assistant est une mise à niveau et est une
|
||||
|
||||
|
||||
>  _*Nouveautés*_
|
||||
> > * **Release 3.3**: ajout du mode Air Conditionné (AC). Cette fonction vous permet d'utiliser le mode AC de votre thermostat sous-jacent. Pour l'utiliser, vous devez cocher l'option "Uitliser le mode AC" et définir les valeurs de température pour les presets et pour les presets en cas d'absence
|
||||
> * **Release 3.2** : ajout de la possibilité de commander plusieurs switch à partir du même thermostat. Dans ce mode, les switchs sont déclenchés avec un délai pour minimiser la puissance nécessaire à un instant (on minimise les périodes de recouvrement). Voir [Configuration](#sélectionnez-des-entités-pilotées)
|
||||
> * **Release 3.1** : ajout d'une détection de fenêtres/portes ouvertes par chute de température. Cette nouvelle fonction permet de stopper automatiquement un radiateur lorsque la température chute brutalement. Voir [Le mode auto](#le-mode-auto)
|
||||
> * **Release majeure 3.0** : ajout d'un équipement thermostat et de capteurs (binaires et non binaires) associés. Beaucoup plus proche de la philosphie Home Assistant, vous avez maintenant un accès direct à l'énergie consommée par le radiateur piloté par le thermostat et à plein d'autres capteurs qui seront utiles dans vos automatisations et dashboard.
|
||||
|
||||
@@ -53,7 +53,8 @@
|
||||
This custom component for Home Assistant is an upgrade and is a complete rewrite of the component "Awesome thermostat" (see [Github](https://github.com/dadge/awesome_thermostat)) with addition of features.
|
||||
|
||||
> _*News*_
|
||||
> * **Release 3.2**: added the ability to control multiple switches from the same thermostat. In this mode, the switches are triggered with a delay to minimize the power required at one time (we minimize the recovery periods). See [Configuration](#select-the-driven-entity)
|
||||
> * **Release 3.3**: add the Air Conditionned mode (AC). This feature allow to use the eventual AC mode of your underlying climate entity. You have to check the "Use AC mode" checkbox in configuration and give preset temperature value for AC mode and AC mode when absent if absence is configured
|
||||
> * **Release 3.2**: add the ability to control multiple switches from the same thermostat. In this mode, the switches are triggered with a delay to minimize the power required at one time (we minimize the recovery periods). See [Configuration](#select-the-driven-entity)
|
||||
> * **Release 3.1**: added detection of open windows/doors by temperature drop. This new function makes it possible to automatically stop a radiator when the temperature drops suddenly. See [Auto mode](#auto-mode)
|
||||
> * **Major release 3.0**: addition of thermostat equipment and associated sensors (binary and non-binary). Much closer to the Home Assistant philosophy, you now have direct access to the energy consumed by the radiator controlled by the thermostat and many other sensors that will be useful in your automations and dashboard.
|
||||
> * **release 2.3**: addition of the power and energy measurement of the radiator controlled by the thermostat.
|
||||
|
||||
@@ -27,6 +27,7 @@ fi
|
||||
if [ "$command" == "hassfest" ]; then
|
||||
echo "Running container start"
|
||||
python3 -m script.hassfest
|
||||
# python -m script.hassfest --requirements --action validate --integration-path config/custom_components/versatile_thermostat/
|
||||
fi
|
||||
|
||||
if [ "$command" == "restart" ]; then
|
||||
|
||||
@@ -18,7 +18,7 @@ from homeassistant.core import (
|
||||
from homeassistant.components.climate import ClimateEntity
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.helpers.entity import DeviceInfo, DeviceEntryType
|
||||
from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.reload import async_setup_reload_service
|
||||
@@ -100,6 +100,8 @@ from .const import (
|
||||
CONF_DEVICE_POWER,
|
||||
CONF_PRESETS,
|
||||
CONF_PRESETS_AWAY,
|
||||
CONF_PRESETS_WITH_AC,
|
||||
CONF_PRESETS_AWAY_WITH_AC,
|
||||
CONF_CYCLE_MIN,
|
||||
CONF_PROP_FUNCTION,
|
||||
CONF_TPI_COEF_INT,
|
||||
@@ -127,10 +129,12 @@ from .const import (
|
||||
# CONF_THERMOSTAT_SWITCH,
|
||||
CONF_THERMOSTAT_CLIMATE,
|
||||
CONF_CLIMATE,
|
||||
CONF_AC_MODE,
|
||||
UnknownEntity,
|
||||
EventType,
|
||||
ATTR_MEAN_POWER_CYCLE,
|
||||
ATTR_TOTAL_ENERGY,
|
||||
PRESET_AC_SUFFIX,
|
||||
)
|
||||
|
||||
from .underlyings import UnderlyingSwitch, UnderlyingClimate, UnderlyingEntity
|
||||
@@ -289,9 +293,12 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
self,
|
||||
entry_infos,
|
||||
)
|
||||
|
||||
self._ac_mode = entry_infos.get(CONF_AC_MODE) == True
|
||||
# convert entry_infos into usable attributes
|
||||
presets = {}
|
||||
for key, value in CONF_PRESETS.items():
|
||||
items = CONF_PRESETS_WITH_AC.items() if self._ac_mode else CONF_PRESETS.items()
|
||||
for key, value in items:
|
||||
_LOGGER.debug("looking for key=%s, value=%s", key, value)
|
||||
if value in entry_infos:
|
||||
presets[key] = entry_infos.get(value)
|
||||
@@ -299,7 +306,12 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
_LOGGER.debug("value %s not found in Entry", value)
|
||||
|
||||
presets_away = {}
|
||||
for key, value in CONF_PRESETS_AWAY.items():
|
||||
items = (
|
||||
CONF_PRESETS_AWAY_WITH_AC.items()
|
||||
if self._ac_mode
|
||||
else CONF_PRESETS_AWAY.items()
|
||||
)
|
||||
for key, value in items:
|
||||
_LOGGER.debug("looking for key=%s, value=%s", key, value)
|
||||
if value in entry_infos:
|
||||
presets_away[key] = entry_infos.get(value)
|
||||
@@ -394,10 +406,10 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
|
||||
self._presence_on = self._presence_sensor_entity_id is not None
|
||||
|
||||
# if self.ac_mode: -> MODE_COOL should be better to use thermostat_over_climate type
|
||||
# self.hvac_list = [HVAC_MODE_COOL, HVAC_MODE_OFF]
|
||||
# else:
|
||||
self._hvac_list = [HVACMode.HEAT, HVACMode.OFF]
|
||||
if self._ac_mode:
|
||||
self._hvac_list = [HVACMode.HEAT, HVACMode.COOL, HVACMode.OFF]
|
||||
else:
|
||||
self._hvac_list = [HVACMode.HEAT, HVACMode.OFF]
|
||||
|
||||
self._unit = self._hass.config.units.temperature_unit
|
||||
# Will be restored if possible
|
||||
@@ -437,7 +449,6 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
self._target_temp = None
|
||||
self._saved_target_temp = PRESET_NONE
|
||||
self._humidity = None
|
||||
self._ac_mode = False
|
||||
self._fan_mode = None
|
||||
self._swing_mode = None
|
||||
self._cur_temp = None
|
||||
@@ -494,13 +505,10 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
if len(presets):
|
||||
self._support_flags = SUPPORT_FLAGS | ClimateEntityFeature.PRESET_MODE
|
||||
|
||||
for key, val in presets.items():
|
||||
for key, val in CONF_PRESETS.items():
|
||||
if val != 0.0:
|
||||
self._attr_preset_modes.append(key)
|
||||
|
||||
# self._attr_preset_modes = (
|
||||
# [PRESET_NONE] + list(presets.keys()) + [PRESET_ACTIVITY]
|
||||
# )
|
||||
_LOGGER.debug(
|
||||
"After adding presets, preset_modes to %s", self._attr_preset_modes
|
||||
)
|
||||
@@ -609,11 +617,11 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
# Ingore this error which is possible if underlying climate is not found temporary
|
||||
pass
|
||||
|
||||
async def remove_thermostat(self):
|
||||
def remove_thermostat(self):
|
||||
"""Called when the thermostat will be removed"""
|
||||
_LOGGER.info("%s - Removing thermostat", self)
|
||||
for under in self._underlyings:
|
||||
await under.remove_entity()
|
||||
under.remove_entity()
|
||||
|
||||
async def async_startup(self):
|
||||
"""Triggered on startup, used to get old state and set internal states accordingly"""
|
||||
@@ -1207,6 +1215,10 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
await under.set_hvac_mode(hvac_mode) or need_control_heating
|
||||
)
|
||||
|
||||
# If AC is on maybe we have to change the temperature in force mode
|
||||
if self._ac_mode:
|
||||
await self._async_set_preset_mode_internal(self._attr_preset_mode, True)
|
||||
|
||||
if need_control_heating and sub_need_control_heating:
|
||||
await self._async_control_heating(force=True)
|
||||
|
||||
@@ -1286,13 +1298,18 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
) # in security just keep the current target temperature, the thermostat should be off
|
||||
if preset_mode == PRESET_POWER:
|
||||
return self._power_temp
|
||||
elif self._presence_on is False or self._presence_state in [
|
||||
STATE_ON,
|
||||
STATE_HOME,
|
||||
]:
|
||||
return self._presets[preset_mode]
|
||||
else:
|
||||
return self._presets_away[self.get_preset_away_name(preset_mode)]
|
||||
# Select _ac presets if in COOL Mode
|
||||
if self._ac_mode and self._hvac_mode == HVACMode.COOL:
|
||||
preset_mode = preset_mode + PRESET_AC_SUFFIX
|
||||
|
||||
if self._presence_on is False or self._presence_state in [
|
||||
STATE_ON,
|
||||
STATE_HOME,
|
||||
]:
|
||||
return self._presets[preset_mode]
|
||||
else:
|
||||
return self._presets_away[self.get_preset_away_name(preset_mode)]
|
||||
|
||||
def get_preset_away_name(self, preset_mode):
|
||||
"""Get the preset name in away mode (when presence is off)"""
|
||||
@@ -1565,6 +1582,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
if not new_state:
|
||||
return
|
||||
|
||||
new_hvac_mode = new_state.state
|
||||
|
||||
old_state = event.data.get("old_state")
|
||||
old_hvac_action = (
|
||||
old_state.attributes.get("hvac_action")
|
||||
@@ -1577,16 +1596,21 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
else None
|
||||
)
|
||||
|
||||
# Issue 99 - some AC turn hvac_mode=cool and hvac_action=idle when sending a HVACMode_OFF command
|
||||
if self._hvac_mode == HVACMode.OFF and new_hvac_action == HVACAction.IDLE:
|
||||
_LOGGER.debug("The underlying switch to idle instead of OFF. We will consider it as OFF")
|
||||
new_hvac_mode = HVACMode.OFF
|
||||
|
||||
_LOGGER.info(
|
||||
"%s - Underlying climate changed. Event.new_state is %s, current_hvac_mode=%s, new_hvac_action=%s, old_hvac_action=%s",
|
||||
"%s - Underlying climate changed. Event.new_hvac_mode is %s, current_hvac_mode=%s, new_hvac_action=%s, old_hvac_action=%s",
|
||||
self,
|
||||
new_state,
|
||||
new_hvac_mode,
|
||||
self._hvac_mode,
|
||||
new_hvac_action,
|
||||
old_hvac_action,
|
||||
)
|
||||
|
||||
if new_state.state in [
|
||||
if new_hvac_mode in [
|
||||
HVACMode.OFF,
|
||||
HVACMode.HEAT,
|
||||
HVACMode.COOL,
|
||||
@@ -1594,8 +1618,9 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
HVACMode.DRY,
|
||||
HVACMode.AUTO,
|
||||
HVACMode.FAN_ONLY,
|
||||
None
|
||||
]:
|
||||
self._hvac_mode = new_state.state
|
||||
self._hvac_mode = new_hvac_mode
|
||||
|
||||
# Interpretation of hvac
|
||||
HVAC_ACTION_ON = [ # pylint: disable=invalid-name
|
||||
@@ -2050,7 +2075,10 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
now - self._last_ext_temperature_mesure.replace(tzinfo=self._current_tz)
|
||||
).total_seconds() / 60.0
|
||||
|
||||
mode_cond = self._is_over_climate or self._hvac_mode != HVACMode.OFF
|
||||
# TODO before change:
|
||||
# mode_cond = self._is_over_climate or self._hvac_mode != HVACMode.OFF
|
||||
# fixed into this. Why if _is_over_climate we could into security even if HVACMode is OFF ?
|
||||
mode_cond = self._hvac_mode != HVACMode.OFF
|
||||
|
||||
temp_cond: bool = (
|
||||
delta_temp > self._security_delay_min
|
||||
@@ -2078,9 +2106,18 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
switch_cond,
|
||||
)
|
||||
|
||||
ret = False
|
||||
if mode_cond and temp_cond and climate_cond:
|
||||
if not self._security_state:
|
||||
# Issue 99 - a climate is regulated by the device itself and not by VTherm. So a VTherm should never be in security !
|
||||
shouldClimateBeInSecurity = False # temp_cond and climate_cond
|
||||
shouldSwitchBeInSecurity = temp_cond and switch_cond
|
||||
shouldBeInSecurity = shouldClimateBeInSecurity or shouldSwitchBeInSecurity
|
||||
|
||||
shouldStartSecurity = mode_cond and not self._security_state and shouldBeInSecurity
|
||||
# attr_preset_mode is not necessary normaly. It is just here to be sure
|
||||
shouldStopSecurity = self._security_state and not shouldBeInSecurity and self._attr_preset_mode == PRESET_SECURITY
|
||||
|
||||
# Logging and event
|
||||
if shouldStartSecurity:
|
||||
if shouldClimateBeInSecurity:
|
||||
_LOGGER.warning(
|
||||
"%s - No temperature received for more than %.1f minutes (dt=%.1f, dext=%.1f) and underlying climate is %s. Set it into security mode",
|
||||
self,
|
||||
@@ -2089,10 +2126,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
delta_ext_temp,
|
||||
self.hvac_action,
|
||||
)
|
||||
ret = True
|
||||
|
||||
if mode_cond and temp_cond and switch_cond:
|
||||
if not self._security_state:
|
||||
elif shouldSwitchBeInSecurity:
|
||||
_LOGGER.warning(
|
||||
"%s - No temperature received for more than %.1f minutes (dt=%.1f, dext=%.1f) and on_percent (%.2f) is over defined value (%.2f). Set it into security mode",
|
||||
self,
|
||||
@@ -2102,9 +2136,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
self._prop_algorithm.on_percent,
|
||||
self._security_min_on_percent,
|
||||
)
|
||||
ret = True
|
||||
|
||||
if mode_cond and temp_cond and not self._security_state:
|
||||
self.send_event(
|
||||
EventType.TEMPERATURE_EVENT,
|
||||
{
|
||||
@@ -2120,8 +2152,8 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
},
|
||||
)
|
||||
|
||||
if not self._security_state and ret:
|
||||
self._security_state = ret
|
||||
if shouldStartSecurity:
|
||||
self._security_state = True
|
||||
self.save_hvac_mode()
|
||||
self.save_preset_mode()
|
||||
await self._async_set_preset_mode_internal(PRESET_SECURITY)
|
||||
@@ -2147,18 +2179,14 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
},
|
||||
)
|
||||
|
||||
if (
|
||||
self._security_state
|
||||
and self._attr_preset_mode == PRESET_SECURITY
|
||||
and not ret
|
||||
):
|
||||
if shouldStopSecurity:
|
||||
_LOGGER.warning(
|
||||
"%s - End of security mode. restoring hvac_mode to %s and preset_mode to %s",
|
||||
self,
|
||||
self._saved_hvac_mode,
|
||||
self._saved_preset_mode,
|
||||
)
|
||||
self._security_state = ret
|
||||
self._security_state = False
|
||||
# Restore hvac_mode if previously saved
|
||||
if self._is_over_climate or self._security_default_on_percent <= 0.0:
|
||||
await self.restore_hvac_mode(False)
|
||||
@@ -2181,7 +2209,7 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
||||
},
|
||||
)
|
||||
|
||||
return ret
|
||||
return shouldBeInSecurity
|
||||
|
||||
async def _async_control_heating(self, force=False, _=None):
|
||||
"""The main function used to run the calculation at each cycle"""
|
||||
|
||||
@@ -4,7 +4,8 @@ from datetime import timedelta
|
||||
from homeassistant.core import HomeAssistant, callback, Event
|
||||
from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DOMAIN
|
||||
from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.helpers.entity import Entity, DeviceInfo, DeviceEntryType
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.device_registry import DeviceInfo, DeviceEntryType
|
||||
from homeassistant.helpers.event import async_track_state_change_event, async_call_later
|
||||
|
||||
from .climate import VersatileThermostat
|
||||
|
||||
@@ -61,7 +61,9 @@ from .const import (
|
||||
CONF_CYCLE_MIN,
|
||||
CONF_PRESET_POWER,
|
||||
CONF_PRESETS,
|
||||
CONF_PRESETS_WITH_AC,
|
||||
CONF_PRESETS_AWAY,
|
||||
CONF_PRESETS_AWAY_WITH_AC,
|
||||
CONF_PRESETS_SELECTIONABLE,
|
||||
CONF_PROP_FUNCTION,
|
||||
CONF_TPI_COEF_EXT,
|
||||
@@ -83,6 +85,7 @@ from .const import (
|
||||
CONF_USE_MOTION_FEATURE,
|
||||
CONF_USE_PRESENCE_FEATURE,
|
||||
CONF_USE_POWER_FEATURE,
|
||||
CONF_AC_MODE,
|
||||
CONF_THERMOSTAT_TYPES,
|
||||
UnknownEntity,
|
||||
WindowOpenDetectionMethod,
|
||||
@@ -132,35 +135,6 @@ def add_suggested_values_to_schema(
|
||||
return vol.Schema(schema)
|
||||
|
||||
|
||||
# def is_temperature_sensor(sensor: RegistryEntry):
|
||||
# """Check if a registryEntry is a temperature sensor or assimilable to a temperature sensor"""
|
||||
# if not sensor.entity_id.startswith(
|
||||
# INPUT_NUMBER_DOMAIN
|
||||
# ) and not sensor.entity_id.startswith(SENSOR_DOMAIN):
|
||||
# return False
|
||||
# return (
|
||||
# sensor.device_class == TEMPERATURE
|
||||
# or sensor.original_device_class == TEMPERATURE
|
||||
# or sensor.unit_of_measurement in TEMPERATURE_UNITS
|
||||
# )
|
||||
#
|
||||
#
|
||||
# def is_power_sensor(sensor: RegistryEntry):
|
||||
# """Check if a registryEntry is a power sensor or assimilable to a temperature sensor"""
|
||||
# if not sensor.entity_id.startswith(
|
||||
# INPUT_NUMBER_DOMAIN
|
||||
# ) and not sensor.entity_id.startswith(SENSOR_DOMAIN):
|
||||
# return False
|
||||
# return (
|
||||
# sensor.unit_of_measurement
|
||||
# in [
|
||||
# UnitOfPower.KILO_WATT,
|
||||
# UnitOfPower.WATT,
|
||||
# UnitOfPower.BTU_PER_HOUR,
|
||||
# ]
|
||||
# )
|
||||
|
||||
|
||||
class VersatileThermostatBaseConfigFlow(FlowHandler):
|
||||
"""The base Config flow class. Used to put some code in commons."""
|
||||
|
||||
@@ -257,6 +231,7 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
||||
vol.Required(CONF_CLIMATE): selector.EntitySelector(
|
||||
selector.EntitySelectorConfig(domain=CLIMATE_DOMAIN),
|
||||
),
|
||||
vol.Optional(CONF_AC_MODE, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -274,6 +249,15 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
||||
}
|
||||
)
|
||||
|
||||
self.STEP_PRESETS_WITH_AC_DATA_SCHEMA = ( # pylint: disable=invalid-name
|
||||
vol.Schema( # pylint: disable=invalid-name
|
||||
{
|
||||
vol.Optional(v, default=0.0): vol.Coerce(float)
|
||||
for (k, v) in CONF_PRESETS_WITH_AC.items()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
self.STEP_WINDOW_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name
|
||||
{
|
||||
vol.Optional(CONF_WINDOW_SENSOR): selector.EntitySelector(
|
||||
@@ -340,6 +324,27 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
||||
}
|
||||
)
|
||||
|
||||
self.STEP_PRESENCE_WITH_AC_DATA_SCHEMA = ( # pylint: disable=invalid-name
|
||||
vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_PRESENCE_SENSOR): selector.EntitySelector(
|
||||
selector.EntitySelectorConfig(
|
||||
domain=[
|
||||
PERSON_DOMAIN,
|
||||
BINARY_SENSOR_DOMAIN,
|
||||
INPUT_BOOLEAN_DOMAIN,
|
||||
]
|
||||
),
|
||||
),
|
||||
}
|
||||
).extend(
|
||||
{
|
||||
vol.Optional(v, default=17): vol.Coerce(float)
|
||||
for (k, v) in CONF_PRESETS_AWAY_WITH_AC.items()
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
self.STEP_ADVANCED_DATA_SCHEMA = vol.Schema( # pylint: disable=invalid-name
|
||||
{
|
||||
vol.Required(
|
||||
@@ -489,9 +494,12 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
||||
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
|
||||
next_step = self.async_step_presence
|
||||
|
||||
return await self.generic_step(
|
||||
"presets", self.STEP_PRESETS_DATA_SCHEMA, user_input, next_step
|
||||
)
|
||||
if self._infos.get(CONF_AC_MODE) == True:
|
||||
schema = self.STEP_PRESETS_WITH_AC_DATA_SCHEMA
|
||||
else:
|
||||
schema = self.STEP_PRESETS_DATA_SCHEMA
|
||||
|
||||
return await self.generic_step("presets", schema, user_input, next_step)
|
||||
|
||||
async def async_step_window(self, user_input: dict | None = None) -> FlowResult:
|
||||
"""Handle the window sensor flow steps"""
|
||||
@@ -542,9 +550,14 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
||||
"""Handle the presence management flow steps"""
|
||||
_LOGGER.debug("Into ConfigFlow.async_step_presence user_input=%s", user_input)
|
||||
|
||||
if self._infos.get(CONF_AC_MODE) == True:
|
||||
schema = self.STEP_PRESENCE_WITH_AC_DATA_SCHEMA
|
||||
else:
|
||||
schema = self.STEP_PRESENCE_DATA_SCHEMA
|
||||
|
||||
return await self.generic_step(
|
||||
"presence",
|
||||
self.STEP_PRESENCE_DATA_SCHEMA,
|
||||
schema,
|
||||
user_input,
|
||||
self.async_step_advanced,
|
||||
)
|
||||
@@ -676,9 +689,12 @@ class VersatileThermostatOptionsFlowHandler(
|
||||
elif self._infos[CONF_USE_PRESENCE_FEATURE]:
|
||||
next_step = self.async_step_presence
|
||||
|
||||
return await self.generic_step(
|
||||
"presets", self.STEP_PRESETS_DATA_SCHEMA, user_input, next_step
|
||||
)
|
||||
if self._infos.get(CONF_AC_MODE) == True:
|
||||
schema = self.STEP_PRESETS_WITH_AC_DATA_SCHEMA
|
||||
else:
|
||||
schema = self.STEP_PRESETS_DATA_SCHEMA
|
||||
|
||||
return await self.generic_step("presets", schema, user_input, next_step)
|
||||
|
||||
async def async_step_window(self, user_input: dict | None = None) -> FlowResult:
|
||||
"""Handle the window sensor flow steps"""
|
||||
@@ -736,9 +752,14 @@ class VersatileThermostatOptionsFlowHandler(
|
||||
"Into OptionsFlowHandler.async_step_presence user_input=%s", user_input
|
||||
)
|
||||
|
||||
if self._infos.get(CONF_AC_MODE) == True:
|
||||
schema = self.STEP_PRESENCE_WITH_AC_DATA_SCHEMA
|
||||
else:
|
||||
schema = self.STEP_PRESENCE_DATA_SCHEMA
|
||||
|
||||
return await self.generic_step(
|
||||
"presence",
|
||||
self.STEP_PRESENCE_DATA_SCHEMA,
|
||||
schema,
|
||||
user_input,
|
||||
self.async_step_advanced,
|
||||
)
|
||||
|
||||
@@ -11,6 +11,11 @@ from homeassistant.components.climate import (
|
||||
ClimateEntityFeature,
|
||||
)
|
||||
|
||||
PRESET_AC_SUFFIX = "_ac"
|
||||
PRESET_ECO_AC = PRESET_ECO + PRESET_AC_SUFFIX
|
||||
PRESET_COMFORT_AC = PRESET_COMFORT + PRESET_AC_SUFFIX
|
||||
PRESET_BOOST_AC = PRESET_BOOST + PRESET_AC_SUFFIX
|
||||
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from .prop_algorithm import (
|
||||
@@ -64,6 +69,7 @@ CONF_USE_WINDOW_FEATURE = "use_window_feature"
|
||||
CONF_USE_MOTION_FEATURE = "use_motion_feature"
|
||||
CONF_USE_PRESENCE_FEATURE = "use_presence_feature"
|
||||
CONF_USE_POWER_FEATURE = "use_power_feature"
|
||||
CONF_AC_MODE = "ac_mode"
|
||||
CONF_WINDOW_AUTO_OPEN_THRESHOLD = "window_auto_open_threshold"
|
||||
CONF_WINDOW_AUTO_CLOSE_THRESHOLD = "window_auto_close_threshold"
|
||||
CONF_WINDOW_AUTO_MAX_DURATION = "window_auto_max_duration"
|
||||
@@ -77,14 +83,39 @@ CONF_PRESETS = {
|
||||
)
|
||||
}
|
||||
|
||||
CONF_PRESETS_WITH_AC = {
|
||||
p: f"{p}_temp"
|
||||
for p in (
|
||||
PRESET_ECO,
|
||||
PRESET_COMFORT,
|
||||
PRESET_BOOST,
|
||||
PRESET_ECO_AC,
|
||||
PRESET_COMFORT_AC,
|
||||
PRESET_BOOST_AC,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
PRESET_AWAY_SUFFIX = "_away"
|
||||
|
||||
CONF_PRESETS_AWAY = {
|
||||
p: f"{p}_temp"
|
||||
for p in (
|
||||
PRESET_ECO + PRESET_AWAY_SUFFIX,
|
||||
PRESET_BOOST + PRESET_AWAY_SUFFIX,
|
||||
PRESET_COMFORT + PRESET_AWAY_SUFFIX,
|
||||
PRESET_BOOST + PRESET_AWAY_SUFFIX,
|
||||
)
|
||||
}
|
||||
|
||||
CONF_PRESETS_AWAY_WITH_AC = {
|
||||
p: f"{p}_temp"
|
||||
for p in (
|
||||
PRESET_ECO + PRESET_AWAY_SUFFIX,
|
||||
PRESET_COMFORT + PRESET_AWAY_SUFFIX,
|
||||
PRESET_BOOST + PRESET_AWAY_SUFFIX,
|
||||
PRESET_ECO_AC + PRESET_AWAY_SUFFIX,
|
||||
PRESET_COMFORT_AC + PRESET_AWAY_SUFFIX,
|
||||
PRESET_BOOST_AC + PRESET_AWAY_SUFFIX,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -92,6 +123,8 @@ CONF_PRESETS_SELECTIONABLE = [PRESET_ECO, PRESET_COMFORT, PRESET_BOOST]
|
||||
|
||||
CONF_PRESETS_VALUES = list(CONF_PRESETS.values())
|
||||
CONF_PRESETS_AWAY_VALUES = list(CONF_PRESETS_AWAY.values())
|
||||
CONF_PRESETS_WITH_AC_VALUES = list(CONF_PRESETS_WITH_AC.values())
|
||||
CONF_PRESETS_AWAY_WITH_AC_VALUES = list(CONF_PRESETS_AWAY_WITH_AC.values())
|
||||
|
||||
ALL_CONF = (
|
||||
[
|
||||
@@ -130,9 +163,12 @@ ALL_CONF = (
|
||||
CONF_USE_MOTION_FEATURE,
|
||||
CONF_USE_PRESENCE_FEATURE,
|
||||
CONF_USE_POWER_FEATURE,
|
||||
CONF_AC_MODE,
|
||||
]
|
||||
+ CONF_PRESETS_VALUES
|
||||
+ CONF_PRESETS_AWAY_VALUES,
|
||||
+ CONF_PRESETS_AWAY_VALUES
|
||||
+ CONF_PRESETS_WITH_AC_VALUES
|
||||
+ CONF_PRESETS_AWAY_WITH_AC_VALUES,
|
||||
)
|
||||
|
||||
CONF_FUNCTIONS = [
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
homeassistant
|
||||
homeassistant==2023.9.0
|
||||
ffmpeg
|
||||
@@ -1,4 +1,4 @@
|
||||
# -r requirements_dev.txt
|
||||
-r requirements_dev.txt
|
||||
# aiodiscover
|
||||
ulid_transform
|
||||
pytest-homeassistant-custom-component
|
||||
@@ -1,120 +1,121 @@
|
||||
reload:
|
||||
description: Reload all Versatile Thermostat entities.
|
||||
name: Reload
|
||||
description: Reload all Versatile Thermostat entities.
|
||||
|
||||
set_presence:
|
||||
name: Set presence
|
||||
description: Force the presence mode in thermostat
|
||||
target:
|
||||
entity:
|
||||
integration: versatile_thermostat
|
||||
fields:
|
||||
presence:
|
||||
name: Presence
|
||||
description: Presence setting
|
||||
required: true
|
||||
advanced: false
|
||||
example: "on"
|
||||
default: "on"
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "on"
|
||||
- "off"
|
||||
- "home"
|
||||
- "not_home"
|
||||
name: Set presence
|
||||
description: Force the presence mode in thermostat
|
||||
target:
|
||||
entity:
|
||||
integration: versatile_thermostat
|
||||
fields:
|
||||
presence:
|
||||
name: Presence
|
||||
description: Presence setting
|
||||
required: true
|
||||
advanced: false
|
||||
example: "on"
|
||||
default: "on"
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "on"
|
||||
- "off"
|
||||
- "home"
|
||||
- "not_home"
|
||||
|
||||
set_preset_temperature:
|
||||
name: Set temperature preset
|
||||
description: Change the target temperature of a preset
|
||||
target:
|
||||
entity:
|
||||
integration: versatile_thermostat
|
||||
fields:
|
||||
preset:
|
||||
name: Preset
|
||||
description: Preset name
|
||||
required: true
|
||||
advanced: false
|
||||
example: "comfort"
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "eco"
|
||||
- "comfort"
|
||||
- "boost"
|
||||
temperature:
|
||||
name: Temperature when present
|
||||
description: Target temperature for the preset when present
|
||||
required: false
|
||||
advanced: false
|
||||
example: "19.5"
|
||||
default: "17"
|
||||
selector:
|
||||
number:
|
||||
min: 7
|
||||
max: 35
|
||||
step: 0.1
|
||||
unit_of_measurement: °
|
||||
mode: slider
|
||||
temperature_away:
|
||||
name: Temperature when not present
|
||||
description: Target temperature for the preset when not present
|
||||
required: false
|
||||
advanced: false
|
||||
example: "17"
|
||||
default: "15"
|
||||
selector:
|
||||
number:
|
||||
min: 7
|
||||
max: 35
|
||||
step: 0.1
|
||||
unit_of_measurement: °
|
||||
mode: slider
|
||||
name: Set temperature preset
|
||||
description: Change the target temperature of a preset
|
||||
target:
|
||||
entity:
|
||||
integration: versatile_thermostat
|
||||
fields:
|
||||
preset:
|
||||
name: Preset
|
||||
description: Preset name
|
||||
required: true
|
||||
advanced: false
|
||||
example: "comfort"
|
||||
selector:
|
||||
select:
|
||||
options:
|
||||
- "eco"
|
||||
- "comfort"
|
||||
- "boost"
|
||||
temperature:
|
||||
name: Temperature when present
|
||||
description: Target temperature for the preset when present
|
||||
required: false
|
||||
advanced: false
|
||||
example: "19.5"
|
||||
default: "17"
|
||||
selector:
|
||||
number:
|
||||
min: 7
|
||||
max: 35
|
||||
step: 0.1
|
||||
unit_of_measurement: °
|
||||
mode: slider
|
||||
temperature_away:
|
||||
name: Temperature when not present
|
||||
description: Target temperature for the preset when not present
|
||||
required: false
|
||||
advanced: false
|
||||
example: "17"
|
||||
default: "15"
|
||||
selector:
|
||||
number:
|
||||
min: 7
|
||||
max: 35
|
||||
step: 0.1
|
||||
unit_of_measurement: °
|
||||
mode: slider
|
||||
|
||||
set_security:
|
||||
name: Set security
|
||||
description: Change the security parameters
|
||||
target:
|
||||
entity:
|
||||
integration: versatile_thermostat
|
||||
fields:
|
||||
delay_min:
|
||||
name: Delay in minutes
|
||||
description: Maximum allowed delay in minutes between two temperature mesures
|
||||
required: false
|
||||
advanced: false
|
||||
example: "30"
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 9999
|
||||
unit_of_measurement: "min"
|
||||
mode: box
|
||||
min_on_percent:
|
||||
name: Minimal on_percent
|
||||
description: Minimal heating percent value for security preset activation
|
||||
required: false
|
||||
advanced: false
|
||||
example: "0.5"
|
||||
default: "0.5"
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 1
|
||||
step: 0.05
|
||||
unit_of_measurement: "%"
|
||||
mode: slider
|
||||
default_on_percent:
|
||||
name: on_percent used in security mode
|
||||
description: The default heating percent value in security preset
|
||||
required: false
|
||||
advanced: false
|
||||
example: "0.1"
|
||||
default: "0.1"
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 1
|
||||
step: 0.05
|
||||
unit_of_measurement: "%"
|
||||
mode: slider
|
||||
name: Set security
|
||||
description: Change the security parameters
|
||||
target:
|
||||
entity:
|
||||
integration: versatile_thermostat
|
||||
fields:
|
||||
delay_min:
|
||||
name: Delay in minutes
|
||||
description: Maximum allowed delay in minutes between two temperature mesures
|
||||
required: false
|
||||
advanced: false
|
||||
example: "30"
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 9999
|
||||
unit_of_measurement: "min"
|
||||
mode: box
|
||||
min_on_percent:
|
||||
name: Minimal on_percent
|
||||
description: Minimal heating percent value for security preset activation
|
||||
required: false
|
||||
advanced: false
|
||||
example: "0.5"
|
||||
default: "0.5"
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 1
|
||||
step: 0.05
|
||||
unit_of_measurement: "%"
|
||||
mode: slider
|
||||
default_on_percent:
|
||||
name: on_percent used in security mode
|
||||
description: The default heating percent value in security preset
|
||||
required: false
|
||||
advanced: false
|
||||
example: "0.1"
|
||||
default: "0.1"
|
||||
selector:
|
||||
number:
|
||||
min: 0
|
||||
max: 1
|
||||
step: 0.05
|
||||
unit_of_measurement: "%"
|
||||
mode: slider
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
"heater_entity3_id": "3rd Heater switch",
|
||||
"heater_entity4_id": "4th Heater switch",
|
||||
"proportional_function": "Algorithm",
|
||||
"climate_entity_id": "Underlying thermostat"
|
||||
"climate_entity_id": "Underlying thermostat",
|
||||
"ac_mode": "AC mode"
|
||||
},
|
||||
"data_description": {
|
||||
"heater_entity_id": "Mandatory heater entity id",
|
||||
@@ -38,7 +39,8 @@
|
||||
"heater_entity3_id": "Optional 3rd Heater entity id. Leave empty if not used",
|
||||
"heater_entity4_id": "Optional 4th Heater entity id. Leave empty if not used",
|
||||
"proportional_function": "Algorithm to use (TPI is the only one for now)",
|
||||
"climate_entity_id": "Underlying climate entity id"
|
||||
"climate_entity_id": "Underlying climate entity id",
|
||||
"ac_mode": "Use the Air Conditioning (AC) mode"
|
||||
}
|
||||
},
|
||||
"tpi": {
|
||||
@@ -55,7 +57,10 @@
|
||||
"data": {
|
||||
"eco_temp": "Temperature in Eco preset",
|
||||
"comfort_temp": "Temperature in Comfort preset",
|
||||
"boost_temp": "Temperature in Boost preset"
|
||||
"boost_temp": "Temperature in Boost preset",
|
||||
"eco_ac_temp": "Temperature in Eco preset for AC mode",
|
||||
"comfort_ac_temp": "Temperature in Comfort preset for AC mode",
|
||||
"boost_ac_temp": "Temperature in Boost preset for AC mode"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
@@ -102,7 +107,10 @@
|
||||
"presence_sensor_entity_id": "Presence sensor entity id (true is present)",
|
||||
"eco_away_temp": "Temperature in Eco preset when no presence",
|
||||
"comfort_away_temp": "Temperature in Comfort preset when no presence",
|
||||
"boost_away_temp": "Temperature in Boost preset when no presence"
|
||||
"boost_away_temp": "Temperature in Boost preset when no presence",
|
||||
"eco_ac_away_temp": "Temperature in Eco preset when no presence in AC mode",
|
||||
"comfort_ac_away_temp": "Temperature in Comfort preset when no presence in AC mode",
|
||||
"boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
@@ -161,7 +169,8 @@
|
||||
"heater_entity3_id": "3rd Heater switch",
|
||||
"heater_entity4_id": "4th Heater switch",
|
||||
"proportional_function": "Algorithm",
|
||||
"climate_entity_id": "Underlying thermostat"
|
||||
"climate_entity_id": "Underlying thermostat",
|
||||
"ac_mode": "AC mode"
|
||||
},
|
||||
"data_description": {
|
||||
"heater_entity_id": "Mandatory heater entity id",
|
||||
@@ -169,7 +178,8 @@
|
||||
"heater_entity3_id": "Optional 3rd Heater entity id. Leave empty if not used",
|
||||
"heater_entity4_id": "Optional 4th Heater entity id. Leave empty if not used",
|
||||
"proportional_function": "Algorithm to use (TPI is the only one for now)",
|
||||
"climate_entity_id": "Underlying climate entity id"
|
||||
"climate_entity_id": "Underlying climate entity id",
|
||||
"ac_mode": "Use the Air Conditioning (AC) mode"
|
||||
}
|
||||
},
|
||||
"tpi": {
|
||||
@@ -186,7 +196,10 @@
|
||||
"data": {
|
||||
"eco_temp": "Temperature in Eco preset",
|
||||
"comfort_temp": "Temperature in Comfort preset",
|
||||
"boost_temp": "Temperature in Boost preset"
|
||||
"boost_temp": "Temperature in Boost preset",
|
||||
"eco_ac_temp": "Temperature in Eco preset for AC mode",
|
||||
"comfort_ac_temp": "Temperature in Comfort preset for AC mode",
|
||||
"boost_ac_temp": "Temperature in Boost preset for AC mode"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
@@ -233,7 +246,10 @@
|
||||
"presence_sensor_entity_id": "Presence sensor entity id (true is present)",
|
||||
"eco_away_temp": "Temperature in Eco preset when no presence",
|
||||
"comfort_away_temp": "Temperature in Comfort preset when no presence",
|
||||
"boost_away_temp": "Temperature in Boost preset when no presence"
|
||||
"boost_away_temp": "Temperature in Boost preset when no presence",
|
||||
"eco_ac_away_temp": "Temperature in Eco preset when no presence in AC mode",
|
||||
"comfort_ac_away_temp": "Temperature in Comfort preset when no presence in AC mode",
|
||||
"boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
|
||||
@@ -15,6 +15,7 @@ from custom_components.versatile_thermostat.const import (
|
||||
CONF_THERMOSTAT_CLIMATE,
|
||||
CONF_THERMOSTAT_SWITCH,
|
||||
CONF_THERMOSTAT_TYPE,
|
||||
CONF_AC_MODE,
|
||||
CONF_TEMP_SENSOR,
|
||||
CONF_EXTERNAL_TEMP_SENSOR,
|
||||
CONF_CYCLE_MIN,
|
||||
@@ -112,6 +113,7 @@ MOCK_TH_OVER_SWITCH_TPI_CONFIG = {
|
||||
|
||||
MOCK_TH_OVER_CLIMATE_TYPE_CONFIG = {
|
||||
CONF_CLIMATE: "climate.mock_climate",
|
||||
CONF_AC_MODE: False,
|
||||
}
|
||||
|
||||
MOCK_PRESETS_CONFIG = {
|
||||
|
||||
@@ -94,7 +94,7 @@ async def test_window_management_time_not_enough(
|
||||
await try_window_condition(None)
|
||||
assert entity.window_state == STATE_OFF
|
||||
|
||||
await entity.remove_thermostat()
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@@ -234,7 +234,7 @@ async def test_window_management_time_enough(
|
||||
assert entity.preset_mode is PRESET_BOOST
|
||||
|
||||
# Clean the entity
|
||||
await entity.remove_thermostat()
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@@ -418,7 +418,7 @@ async def test_window_auto_fast(hass: HomeAssistant, skip_hass_states_is_state):
|
||||
assert entity.hvac_mode is HVACMode.HEAT
|
||||
|
||||
# Clean the entity
|
||||
await entity.remove_thermostat()
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@@ -561,7 +561,7 @@ async def test_window_auto_auto_stop(hass: HomeAssistant, skip_hass_states_is_st
|
||||
assert entity.preset_mode is PRESET_BOOST
|
||||
|
||||
# Clean the entity
|
||||
await entity.remove_thermostat()
|
||||
entity.remove_thermostat()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||
@@ -670,4 +670,4 @@ async def test_window_auto_no_on_percent(
|
||||
assert entity.hvac_mode is HVACMode.HEAT
|
||||
|
||||
# Clean the entity
|
||||
await entity.remove_thermostat()
|
||||
entity.remove_thermostat()
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
"heater_entity3_id": "3rd Heater switch",
|
||||
"heater_entity4_id": "4th Heater switch",
|
||||
"proportional_function": "Algorithm",
|
||||
"climate_entity_id": "Underlying thermostat"
|
||||
"climate_entity_id": "Underlying thermostat",
|
||||
"ac_mode": "AC mode"
|
||||
},
|
||||
"data_description": {
|
||||
"heater_entity_id": "Mandatory heater entity id",
|
||||
@@ -38,7 +39,8 @@
|
||||
"heater_entity3_id": "Optional 3rd Heater entity id. Leave empty if not used",
|
||||
"heater_entity4_id": "Optional 4th Heater entity id. Leave empty if not used",
|
||||
"proportional_function": "Algorithm to use (TPI is the only one for now)",
|
||||
"climate_entity_id": "Underlying climate entity id"
|
||||
"climate_entity_id": "Underlying climate entity id",
|
||||
"ac_mode": "Use the Air Conditioning (AC) mode"
|
||||
}
|
||||
},
|
||||
"tpi": {
|
||||
@@ -55,7 +57,10 @@
|
||||
"data": {
|
||||
"eco_temp": "Temperature in Eco preset",
|
||||
"comfort_temp": "Temperature in Comfort preset",
|
||||
"boost_temp": "Temperature in Boost preset"
|
||||
"boost_temp": "Temperature in Boost preset",
|
||||
"eco_ac_temp": "Temperature in Eco preset for AC mode",
|
||||
"comfort_ac_temp": "Temperature in Comfort preset for AC mode",
|
||||
"boost_ac_temp": "Temperature in Boost preset for AC mode"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
@@ -102,7 +107,10 @@
|
||||
"presence_sensor_entity_id": "Presence sensor entity id (true is present)",
|
||||
"eco_away_temp": "Temperature in Eco preset when no presence",
|
||||
"comfort_away_temp": "Temperature in Comfort preset when no presence",
|
||||
"boost_away_temp": "Temperature in Boost preset when no presence"
|
||||
"boost_away_temp": "Temperature in Boost preset when no presence",
|
||||
"eco_ac_away_temp": "Temperature in Eco preset when no presence in AC mode",
|
||||
"comfort_ac_away_temp": "Temperature in Comfort preset when no presence in AC mode",
|
||||
"boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
@@ -161,7 +169,8 @@
|
||||
"heater_entity3_id": "3rd Heater switch",
|
||||
"heater_entity4_id": "4th Heater switch",
|
||||
"proportional_function": "Algorithm",
|
||||
"climate_entity_id": "Underlying thermostat"
|
||||
"climate_entity_id": "Underlying thermostat",
|
||||
"ac_mode": "AC mode"
|
||||
},
|
||||
"data_description": {
|
||||
"heater_entity_id": "Mandatory heater entity id",
|
||||
@@ -169,7 +178,8 @@
|
||||
"heater_entity3_id": "Optional 3rd Heater entity id. Leave empty if not used",
|
||||
"heater_entity4_id": "Optional 4th Heater entity id. Leave empty if not used",
|
||||
"proportional_function": "Algorithm to use (TPI is the only one for now)",
|
||||
"climate_entity_id": "Underlying climate entity id"
|
||||
"climate_entity_id": "Underlying climate entity id",
|
||||
"ac_mode": "Use the Air Conditioning (AC) mode"
|
||||
}
|
||||
},
|
||||
"tpi": {
|
||||
@@ -186,7 +196,10 @@
|
||||
"data": {
|
||||
"eco_temp": "Temperature in Eco preset",
|
||||
"comfort_temp": "Temperature in Comfort preset",
|
||||
"boost_temp": "Temperature in Boost preset"
|
||||
"boost_temp": "Temperature in Boost preset",
|
||||
"eco_ac_temp": "Temperature in Eco preset for AC mode",
|
||||
"comfort_ac_temp": "Temperature in Comfort preset for AC mode",
|
||||
"boost_ac_temp": "Temperature in Boost preset for AC mode"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
@@ -233,7 +246,10 @@
|
||||
"presence_sensor_entity_id": "Presence sensor entity id (true is present)",
|
||||
"eco_away_temp": "Temperature in Eco preset when no presence",
|
||||
"comfort_away_temp": "Temperature in Comfort preset when no presence",
|
||||
"boost_away_temp": "Temperature in Boost preset when no presence"
|
||||
"boost_away_temp": "Temperature in Boost preset when no presence",
|
||||
"eco_ac_away_temp": "Temperature in Eco preset when no presence in AC mode",
|
||||
"comfort_ac_away_temp": "Temperature in Comfort preset when no presence in AC mode",
|
||||
"boost_ac_away_temp": "Temperature in Boost preset when no presence in AC mode"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
"heater_entity3_id": "3ème radiateur",
|
||||
"heater_entity4_id": "4ème radiateur",
|
||||
"proportional_function": "Algorithme",
|
||||
"climate_entity_id": "Thermostat sous-jacent"
|
||||
"climate_entity_id": "Thermostat sous-jacent",
|
||||
"ac_mode": "AC mode ?"
|
||||
},
|
||||
"data_description": {
|
||||
"heater_entity_id": "Entity id du 1er radiateur obligatoire",
|
||||
@@ -37,7 +38,8 @@
|
||||
"heater_entity3_id": "Optionnel entity id du 3ème radiateur",
|
||||
"heater_entity4_id": "Optionnel entity id du 4ème radiateur",
|
||||
"proportional_function": "Algorithme à utiliser (Seul TPI est disponible pour l'instant)",
|
||||
"climate_entity_id": "Entity id du thermostat sous-jacent"
|
||||
"climate_entity_id": "Entity id du thermostat sous-jacent",
|
||||
"ac_mode": "Utilisation du mode Air Conditionné (AC)"
|
||||
}
|
||||
},
|
||||
"tpi": {
|
||||
@@ -54,7 +56,10 @@
|
||||
"data": {
|
||||
"eco_temp": "Température en preset Eco",
|
||||
"comfort_temp": "Température en preset Comfort",
|
||||
"boost_temp": "Température en preset Boost"
|
||||
"boost_temp": "Température en preset Boost",
|
||||
"eco_ac_temp": "Température en preset Eco en mode AC",
|
||||
"comfort_ac_temp": "Température en preset Comfort en mode AC",
|
||||
"boost_ac_temp": "Température en preset Boost en mode AC"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
@@ -101,7 +106,10 @@
|
||||
"presence_sensor_entity_id": "Capteur de présence entity id (true si quelqu'un est présent)",
|
||||
"eco_away_temp": "Température en preset Eco en cas d'absence",
|
||||
"comfort_away_temp": "Température en preset Comfort en cas d'absence",
|
||||
"boost_away_temp": "Température en preset Boost en cas d'absence"
|
||||
"boost_away_temp": "Température en preset Boost en cas d'absence",
|
||||
"eco_ac_away_temp": "Température en preset Eco en cas d'absence en mode AC",
|
||||
"comfort_ac_away_temp": "Température en preset Comfort en cas d'absence en mode AC",
|
||||
"boost_ac_away_temp": "Température en preset Boost en cas d'absence en mode AC"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
@@ -161,7 +169,8 @@
|
||||
"heater_entity3_id": "3ème radiateur",
|
||||
"heater_entity4_id": "4ème radiateur",
|
||||
"proportional_function": "Algorithme",
|
||||
"climate_entity_id": "Thermostat sous-jacent"
|
||||
"climate_entity_id": "Thermostat sous-jacent",
|
||||
"ac_mode": "AC mode ?"
|
||||
},
|
||||
"data_description": {
|
||||
"heater_entity_id": "Entity id du 1er radiateur obligatoire",
|
||||
@@ -169,7 +178,8 @@
|
||||
"heater_entity3_id": "Optionnel entity id du 3ème radiateur",
|
||||
"heater_entity4_id": "Optionnel entity id du 4ème radiateur",
|
||||
"proportional_function": "Algorithme à utiliser (Seul TPI est disponible pour l'instant)",
|
||||
"climate_entity_id": "Entity id du thermostat sous-jacent"
|
||||
"climate_entity_id": "Entity id du thermostat sous-jacent",
|
||||
"ac_mode": "Utilisation du mode Air Conditionné (AC)"
|
||||
}
|
||||
},
|
||||
"tpi": {
|
||||
@@ -186,7 +196,10 @@
|
||||
"data": {
|
||||
"eco_temp": "Température en preset Eco",
|
||||
"comfort_temp": "Température en preset Comfort",
|
||||
"boost_temp": "Température en preset Boost"
|
||||
"boost_temp": "Température en preset Boost",
|
||||
"eco_ac_temp": "Température en preset Eco en mode AC",
|
||||
"comfort_ac_temp": "Température en preset Comfort en mode AC",
|
||||
"boost_ac_temp": "Température en preset Boost en mode AC"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
@@ -233,7 +246,10 @@
|
||||
"presence_sensor_entity_id": "Capteur de présence entity id (true si quelqu'un est présent)",
|
||||
"eco_away_temp": "Température en preset Eco en cas d'absence",
|
||||
"comfort_away_temp": "Température en preset Comfort en cas d'absence",
|
||||
"boost_away_temp": "Température en preset Boost en cas d'absence"
|
||||
"boost_away_temp": "Température en preset Boost en cas d'absence",
|
||||
"eco_ac_away_temp": "Température en preset Eco en cas d'absence en mode AC",
|
||||
"comfort_ac_away_temp": "Température en preset Comfort en cas d'absence en mode AC",
|
||||
"boost_ac_away_temp": "Température en preset Boost en cas d'absence en mode AC"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
"heater_entity3_id": "Terzo riscaldatore",
|
||||
"heater_entity4_id": "Quarto riscaldatore",
|
||||
"proportional_function": "Algoritmo",
|
||||
"climate_entity_id": "Termostato sottostante"
|
||||
"climate_entity_id": "Termostato sottostante",
|
||||
"ac_mode": "AC mode ?"
|
||||
},
|
||||
"data_description": {
|
||||
"heater_entity_id": "Entity id obbligatoria del primo riscaldatore",
|
||||
@@ -38,7 +39,8 @@
|
||||
"heater_entity3_id": "Entity id del terzo riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||
"heater_entity4_id": "Entity id del quarto riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||
"proportional_function": "Algoritmo da utilizzare (il TPI per adesso è l'unico)",
|
||||
"climate_entity_id": "Entity id del termostato sottostante"
|
||||
"climate_entity_id": "Entity id del termostato sottostante",
|
||||
"ac_mode": "Utilizzare la modalità AC (Air Conditioned) ?"
|
||||
}
|
||||
},
|
||||
"tpi": {
|
||||
@@ -55,7 +57,10 @@
|
||||
"data": {
|
||||
"eco_temp": "Temperatura nel preset Eco",
|
||||
"comfort_temp": "Temperatura nel preset Comfort",
|
||||
"boost_temp": "Temperatura nel preset Boost"
|
||||
"boost_temp": "Temperatura nel preset Boost",
|
||||
"eco_ac_temp": "Temperatura nel preset Eco (AC mode)",
|
||||
"comfort_ac_temp": "Temperatura nel preset Comfort (AC mode)",
|
||||
"boost_ac_temp": "Temperatura nel preset Boost (AC mode)"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
@@ -102,7 +107,10 @@
|
||||
"presence_sensor_entity_id": "Entity id sensore presenza (true se è presente qualcuno)",
|
||||
"eco_away_temp": "Temperatura al preset Eco in caso d'assenza",
|
||||
"comfort_away_temp": "Temperatura al preset Comfort in caso d'assenza",
|
||||
"boost_away_temp": "Temperatura al preset Boost in caso d'assenza"
|
||||
"boost_away_temp": "Temperatura al preset Boost in caso d'assenza",
|
||||
"eco_ac_away_temp": "Temperatura al preset Eco in caso d'assenza (AC mode)",
|
||||
"comfort_ac_away_temp": "Temperatura al preset Comfort in caso d'assenza (AC mode)",
|
||||
"boost_ac_away_temp": "Temperatura al preset Boost in caso d'assenza (AC mode)"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
@@ -161,7 +169,8 @@
|
||||
"heater_entity3_id": "Terzo interruttore riscaldatore",
|
||||
"heater_entity4_id": "Quarto interruttore riscaldatore",
|
||||
"proportional_function": "Algoritmo",
|
||||
"climate_entity_id": "Termostato sottostante"
|
||||
"climate_entity_id": "Termostato sottostante",
|
||||
"ac_mode": "AC mode ?"
|
||||
},
|
||||
"data_description": {
|
||||
"heater_entity_id": "Entity id obbligatoria del primo riscaldatore",
|
||||
@@ -169,7 +178,8 @@
|
||||
"heater_entity3_id": "Entity id del terzo riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||
"heater_entity4_id": "Entity id del quarto riscaldatore facoltativo. Lasciare vuoto se non utilizzato",
|
||||
"proportional_function": "Algoritmo da utilizzare (il TPI per adesso è l'unico)",
|
||||
"climate_entity_id": "Entity id del termostato sottostante"
|
||||
"climate_entity_id": "Entity id del termostato sottostante",
|
||||
"ac_mode": "Utilizzare la modalità AC (Air Conditioned) ?"
|
||||
}
|
||||
},
|
||||
"tpi": {
|
||||
@@ -186,7 +196,10 @@
|
||||
"data": {
|
||||
"eco_temp": "Temperatura nel preset Eco",
|
||||
"comfort_temp": "Temperatura nel preset Comfort",
|
||||
"boost_temp": "Temperatura nel preset Boost"
|
||||
"boost_temp": "Temperatura nel preset Boost",
|
||||
"eco_ac_temp": "Temperatura nel preset Eco (AC mode)",
|
||||
"comfort_ac_temp": "Temperatura nel preset Comfort (AC mode)",
|
||||
"boost_ac_temp": "Temperatura nel preset Boost (AC mode)"
|
||||
}
|
||||
},
|
||||
"window": {
|
||||
@@ -233,7 +246,10 @@
|
||||
"presence_sensor_entity_id": "Entity id sensore presenza (true se è presente qualcuno)",
|
||||
"eco_away_temp": "Temperatura al preset Eco in caso d'assenza",
|
||||
"comfort_away_temp": "Temperatura al preset Comfort in caso d'assenza",
|
||||
"boost_away_temp": "Temperatura al preset Boost in caso d'assenza"
|
||||
"boost_away_temp": "Temperatura al preset Boost in caso d'assenza",
|
||||
"eco_ac_away_temp": "Temperatura al preset Eco in caso d'assenza (AC mode)",
|
||||
"comfort_ac_away_temp": "Temperatura al preset Comfort in caso d'assenza (AC mode)",
|
||||
"boost_ac_away_temp": "Temperatura al preset Boost in caso d'assenza (AC mode)"
|
||||
}
|
||||
},
|
||||
"advanced": {
|
||||
|
||||
@@ -127,7 +127,7 @@ class UnderlyingEntity:
|
||||
"""Set the target temperature"""
|
||||
return
|
||||
|
||||
async def remove_entity(self):
|
||||
def remove_entity(self):
|
||||
"""Remove the underlying entity"""
|
||||
return
|
||||
|
||||
@@ -180,7 +180,7 @@ class UnderlyingSwitch(UnderlyingEntity):
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
if self.is_device_active:
|
||||
await self.turn_off()
|
||||
await self._cancel_cycle()
|
||||
self._cancel_cycle()
|
||||
|
||||
if self._hvac_mode != hvac_mode:
|
||||
self._hvac_mode = hvac_mode
|
||||
@@ -228,7 +228,7 @@ class UnderlyingSwitch(UnderlyingEntity):
|
||||
if self._async_cancel_cycle is not None:
|
||||
if force:
|
||||
_LOGGER.debug("%s - we force a new cycle", self)
|
||||
await self._cancel_cycle()
|
||||
self._cancel_cycle()
|
||||
else:
|
||||
_LOGGER.debug(
|
||||
"%s - A previous cycle is alredy running and no force -> waits for its end",
|
||||
@@ -258,7 +258,7 @@ class UnderlyingSwitch(UnderlyingEntity):
|
||||
else:
|
||||
_LOGGER.debug("%s - nothing to do", self)
|
||||
|
||||
async def _cancel_cycle(self):
|
||||
def _cancel_cycle(self):
|
||||
"""Cancel the cycle"""
|
||||
if self._async_cancel_cycle:
|
||||
self._async_cancel_cycle()
|
||||
@@ -275,7 +275,7 @@ class UnderlyingSwitch(UnderlyingEntity):
|
||||
self._on_time_sec,
|
||||
)
|
||||
|
||||
await self._cancel_cycle()
|
||||
self._cancel_cycle()
|
||||
|
||||
if self._hvac_mode == HVACMode.OFF:
|
||||
_LOGGER.debug("%s - End of cycle (HVAC_MODE_OFF - 2)", self)
|
||||
@@ -327,7 +327,7 @@ class UnderlyingSwitch(UnderlyingEntity):
|
||||
self._should_relaunch_control_heating,
|
||||
self._off_time_sec,
|
||||
)
|
||||
await self._cancel_cycle()
|
||||
self._cancel_cycle()
|
||||
|
||||
if self._hvac_mode == HVACMode.OFF:
|
||||
_LOGGER.debug("%s - End of cycle (HVAC_MODE_OFF - 2)", self)
|
||||
@@ -368,9 +368,9 @@ class UnderlyingSwitch(UnderlyingEntity):
|
||||
# increment energy at the end of the cycle
|
||||
self._thermostat.incremente_energy()
|
||||
|
||||
async def remove_entity(self):
|
||||
"""Remove the entity"""
|
||||
await self._cancel_cycle()
|
||||
def remove_entity(self):
|
||||
"""Remove the entity after stopping its cycle"""
|
||||
self._cancel_cycle()
|
||||
|
||||
|
||||
class UnderlyingClimate(UnderlyingEntity):
|
||||
@@ -446,7 +446,7 @@ class UnderlyingClimate(UnderlyingEntity):
|
||||
def is_device_active(self):
|
||||
"""If the toggleable device is currently active."""
|
||||
if self.is_initialized:
|
||||
return self._underlying_climate.hvac_action not in [
|
||||
return self._underlying_climate.hvac_mode != HVACMode.OFF and self._underlying_climate.hvac_action not in [
|
||||
HVACAction.IDLE,
|
||||
HVACAction.OFF,
|
||||
]
|
||||
@@ -581,8 +581,41 @@ class UnderlyingClimate(UnderlyingEntity):
|
||||
return self._underlying_climate.temperature_unit
|
||||
|
||||
@property
|
||||
def target_temperature_step(self) -> str:
|
||||
def target_temperature_step(self) -> float:
|
||||
"""Get the target_temperature_step"""
|
||||
if not self.is_initialized:
|
||||
return 1
|
||||
return self._underlying_climate.target_temperature_step
|
||||
|
||||
@property
|
||||
def target_temperature_high(self) -> float:
|
||||
"""Get the target_temperature_high"""
|
||||
if not self.is_initialized:
|
||||
return 30
|
||||
return self._underlying_climate.target_temperature_high
|
||||
|
||||
@property
|
||||
def target_temperature_low(self) -> float:
|
||||
"""Get the target_temperature_low"""
|
||||
if not self.is_initialized:
|
||||
return 15
|
||||
return self._underlying_climate.target_temperature_low
|
||||
|
||||
@property
|
||||
def is_aux_heat(self) -> bool:
|
||||
"""Get the is_aux_heat"""
|
||||
if not self.is_initialized:
|
||||
return False
|
||||
return self._underlying_climate.is_aux_heat
|
||||
|
||||
def turn_aux_heat_on(self) -> None:
|
||||
"""Turn auxiliary heater on."""
|
||||
if not self.is_initialized:
|
||||
return None
|
||||
return self._underlying_climate.turn_aux_heat_on()
|
||||
|
||||
def turn_aux_heat_off(self) -> None:
|
||||
"""Turn auxiliary heater on."""
|
||||
if not self.is_initialized:
|
||||
return None
|
||||
return self._underlying_climate.turn_aux_heat_off()
|
||||
|
||||
Reference in New Issue
Block a user