Some switch are not visible in the list of radiators #40
This commit is contained in:
@@ -118,3 +118,23 @@ template:
|
|||||||
unique_id: maison_occupee
|
unique_id: maison_occupee
|
||||||
state: "{{is_state('person.jmc', 'home') }}"
|
state: "{{is_state('person.jmc', 'home') }}"
|
||||||
device_class: occupancy
|
device_class: occupancy
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
turn_off:
|
||||||
|
service: select.select_option
|
||||||
|
data:
|
||||||
|
option: comfort-2
|
||||||
|
target:
|
||||||
|
entity_id: select.seche_serviettes_sdb_rdc_cable_outlet_mode
|
||||||
|
|||||||
@@ -1334,6 +1334,10 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
HVACMode.OFF,
|
HVACMode.OFF,
|
||||||
HVACMode.HEAT,
|
HVACMode.HEAT,
|
||||||
HVACMode.COOL,
|
HVACMode.COOL,
|
||||||
|
HVACMode.HEAT_COOL,
|
||||||
|
HVACMode.DRY,
|
||||||
|
HVACMode.AUTO,
|
||||||
|
HVACMode.FAN_ONLY,
|
||||||
]:
|
]:
|
||||||
return
|
return
|
||||||
self._hvac_mode = new_state.state
|
self._hvac_mode = new_state.state
|
||||||
@@ -1979,29 +1983,3 @@ class VersatileThermostat(ClimateEntity, RestoreEntity):
|
|||||||
if self._attr_preset_mode == preset:
|
if self._attr_preset_mode == preset:
|
||||||
await self._async_set_preset_mode_internal(preset, force=True)
|
await self._async_set_preset_mode_internal(preset, force=True)
|
||||||
await self._async_control_heating(force=True)
|
await self._async_control_heating(force=True)
|
||||||
|
|
||||||
# No more needed
|
|
||||||
|
|
||||||
|
|
||||||
# @classmethod
|
|
||||||
# def add_entity(cls, entry_id, entity):
|
|
||||||
# """Adds an entity into the VersatileRegistry entities"""
|
|
||||||
# _LOGGER.debug("Adding entity %s", entry_id)
|
|
||||||
# cls._registry[entry_id] = entity
|
|
||||||
# _LOGGER.debug("Entity registry is now %s", cls._registry)
|
|
||||||
#
|
|
||||||
# @classmethod
|
|
||||||
# async def update_entity(cls, entry_id, infos):
|
|
||||||
# """Updates an existing entity referenced by entry_id with the infos in arguments"""
|
|
||||||
# entity: VersatileThermostat = cls._registry.get(entry_id)
|
|
||||||
# if entity is None:
|
|
||||||
# _LOGGER.warning(
|
|
||||||
# "Tries to update VersatileThermostat entity %s but was not found in thermostat registry",
|
|
||||||
# entry_id,
|
|
||||||
# )
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# _LOGGER.debug("We have found the entity to update")
|
|
||||||
# entity.post_init(infos)
|
|
||||||
#
|
|
||||||
# await entity.async_added_to_hass()
|
|
||||||
|
|||||||
@@ -8,25 +8,20 @@ from collections.abc import Mapping
|
|||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.const import TEMPERATURE, UnitOfPower
|
|
||||||
from homeassistant.util.unit_system import TEMPERATURE_UNITS
|
|
||||||
|
|
||||||
from homeassistant.core import callback, async_get_hass
|
from homeassistant.core import callback
|
||||||
from homeassistant.config_entries import (
|
from homeassistant.config_entries import (
|
||||||
ConfigEntry,
|
ConfigEntry,
|
||||||
ConfigFlow as HAConfigFlow,
|
ConfigFlow as HAConfigFlow,
|
||||||
OptionsFlow,
|
OptionsFlow,
|
||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.data_entry_flow import FlowHandler
|
from homeassistant.data_entry_flow import FlowHandler, FlowResult
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
|
||||||
|
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.helpers.entity_registry import (
|
|
||||||
RegistryEntry,
|
from homeassistant.helpers import selector
|
||||||
async_get,
|
|
||||||
)
|
|
||||||
from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DOMAIN
|
from homeassistant.components.climate import ClimateEntity, DOMAIN as CLIMATE_DOMAIN
|
||||||
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||||
from homeassistant.components.input_boolean import (
|
from homeassistant.components.input_boolean import (
|
||||||
@@ -126,35 +121,33 @@ def add_suggested_values_to_schema(
|
|||||||
return vol.Schema(schema)
|
return vol.Schema(schema)
|
||||||
|
|
||||||
|
|
||||||
def is_temperature_sensor(sensor: RegistryEntry):
|
# def is_temperature_sensor(sensor: RegistryEntry):
|
||||||
"""Check if a registryEntry is a temperature sensor or assimilable to a temperature sensor"""
|
# """Check if a registryEntry is a temperature sensor or assimilable to a temperature sensor"""
|
||||||
if not sensor.entity_id.startswith(
|
# if not sensor.entity_id.startswith(
|
||||||
INPUT_NUMBER_DOMAIN
|
# INPUT_NUMBER_DOMAIN
|
||||||
) and not sensor.entity_id.startswith(SENSOR_DOMAIN):
|
# ) and not sensor.entity_id.startswith(SENSOR_DOMAIN):
|
||||||
return False
|
# return False
|
||||||
return (
|
# return (
|
||||||
sensor.device_class == TEMPERATURE
|
# sensor.device_class == TEMPERATURE
|
||||||
or sensor.original_device_class == TEMPERATURE
|
# or sensor.original_device_class == TEMPERATURE
|
||||||
or sensor.unit_of_measurement in TEMPERATURE_UNITS
|
# or sensor.unit_of_measurement in TEMPERATURE_UNITS
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
|
#
|
||||||
def is_power_sensor(sensor: RegistryEntry):
|
# def is_power_sensor(sensor: RegistryEntry):
|
||||||
"""Check if a registryEntry is a power sensor or assimilable to a temperature sensor"""
|
# """Check if a registryEntry is a power sensor or assimilable to a temperature sensor"""
|
||||||
if not sensor.entity_id.startswith(
|
# if not sensor.entity_id.startswith(
|
||||||
INPUT_NUMBER_DOMAIN
|
# INPUT_NUMBER_DOMAIN
|
||||||
) and not sensor.entity_id.startswith(SENSOR_DOMAIN):
|
# ) and not sensor.entity_id.startswith(SENSOR_DOMAIN):
|
||||||
return False
|
# return False
|
||||||
return (
|
# return (
|
||||||
# sensor.device_class == TEMPERATURE
|
# sensor.unit_of_measurement
|
||||||
# or sensor.original_device_class == TEMPERATURE
|
# in [
|
||||||
sensor.unit_of_measurement
|
# UnitOfPower.KILO_WATT,
|
||||||
in [
|
# UnitOfPower.WATT,
|
||||||
UnitOfPower.KILO_WATT,
|
# UnitOfPower.BTU_PER_HOUR,
|
||||||
UnitOfPower.WATT,
|
# ]
|
||||||
UnitOfPower.BTU_PER_HOUR,
|
# )
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class VersatileThermostatBaseConfigFlow(FlowHandler):
|
class VersatileThermostatBaseConfigFlow(FlowHandler):
|
||||||
@@ -183,46 +176,46 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
is_empty or self._infos.get(CONF_PRESENCE_SENSOR) is not None
|
is_empty or self._infos.get(CONF_PRESENCE_SENSOR) is not None
|
||||||
)
|
)
|
||||||
|
|
||||||
self.hass = async_get_hass()
|
# self.hass = async_get_hass()
|
||||||
ent_reg = async_get(hass=self.hass)
|
# ent_reg = async_get(hass=self.hass)
|
||||||
|
|
||||||
climates = []
|
# climates = []
|
||||||
switches = []
|
# switches = []
|
||||||
temp_sensors = []
|
# temp_sensors = []
|
||||||
power_sensors = []
|
# power_sensors = []
|
||||||
window_sensors = []
|
# window_sensors = []
|
||||||
presence_sensors = []
|
# presence_sensors = []
|
||||||
|
#
|
||||||
k: str
|
# k: str
|
||||||
for k in ent_reg.entities:
|
# for k in ent_reg.entities:
|
||||||
v: RegistryEntry = ent_reg.entities[k]
|
# v: RegistryEntry = ent_reg.entities[k]
|
||||||
_LOGGER.debug("Looking entity: %s", k)
|
# _LOGGER.debug("Looking entity: %s", k)
|
||||||
# if k.startswith(CLIMATE_DOMAIN) and (
|
# # if k.startswith(CLIMATE_DOMAIN) and (
|
||||||
# infos is None or k != infos.get("entity_id")
|
# # infos is None or k != infos.get("entity_id")
|
||||||
# ):
|
# # ):
|
||||||
# _LOGGER.debug("Climate !")
|
# # _LOGGER.debug("Climate !")
|
||||||
# climates.append(k)
|
# # climates.append(k)
|
||||||
if k.startswith(SWITCH_DOMAIN) or k.startswith(INPUT_BOOLEAN_DOMAIN):
|
# if k.startswith(SWITCH_DOMAIN) or k.startswith(INPUT_BOOLEAN_DOMAIN):
|
||||||
_LOGGER.debug("Switch !")
|
# _LOGGER.debug("Switch !")
|
||||||
switches.append(k)
|
# switches.append(k)
|
||||||
elif is_temperature_sensor(v):
|
# elif is_temperature_sensor(v):
|
||||||
_LOGGER.debug("Temperature sensor !")
|
# _LOGGER.debug("Temperature sensor !")
|
||||||
temp_sensors.append(k)
|
# temp_sensors.append(k)
|
||||||
elif is_power_sensor(v):
|
# elif is_power_sensor(v):
|
||||||
_LOGGER.debug("Power sensor !")
|
# _LOGGER.debug("Power sensor !")
|
||||||
power_sensors.append(k)
|
# power_sensors.append(k)
|
||||||
elif k.startswith(PERSON_DOMAIN):
|
# elif k.startswith(PERSON_DOMAIN):
|
||||||
_LOGGER.debug("Presence sensor !")
|
# _LOGGER.debug("Presence sensor !")
|
||||||
presence_sensors.append(k)
|
# presence_sensors.append(k)
|
||||||
|
#
|
||||||
# window sensor and presence
|
# # window sensor and presence
|
||||||
if k.startswith(INPUT_BOOLEAN_DOMAIN) or k.startswith(BINARY_SENSOR_DOMAIN):
|
# if k.startswith(INPUT_BOOLEAN_DOMAIN) or k.startswith(BINARY_SENSOR_DOMAIN):
|
||||||
_LOGGER.debug("Window or presence sensor !")
|
# _LOGGER.debug("Window or presence sensor !")
|
||||||
window_sensors.append(k)
|
# window_sensors.append(k)
|
||||||
presence_sensors.append(k)
|
# presence_sensors.append(k)
|
||||||
|
#
|
||||||
# Special case for climates which are not in EntityRegistry
|
# # Special case for climates which are not in EntityRegistry
|
||||||
climates = self.find_all_climates()
|
# climates = self.find_all_climates()
|
||||||
|
|
||||||
self.STEP_USER_DATA_SCHEMA = vol.Schema(
|
self.STEP_USER_DATA_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
@@ -230,8 +223,17 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
vol.Required(
|
vol.Required(
|
||||||
CONF_THERMOSTAT_TYPE, default=CONF_THERMOSTAT_SWITCH
|
CONF_THERMOSTAT_TYPE, default=CONF_THERMOSTAT_SWITCH
|
||||||
): vol.In(CONF_THERMOSTAT_TYPES),
|
): vol.In(CONF_THERMOSTAT_TYPES),
|
||||||
vol.Required(CONF_TEMP_SENSOR): vol.In(temp_sensors),
|
vol.Required(CONF_TEMP_SENSOR): selector.EntitySelector(
|
||||||
vol.Required(CONF_EXTERNAL_TEMP_SENSOR): vol.In(temp_sensors),
|
selector.EntitySelectorConfig(
|
||||||
|
domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN]
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# vol.In(temp_sensors),
|
||||||
|
vol.Required(CONF_EXTERNAL_TEMP_SENSOR): selector.EntitySelector(
|
||||||
|
selector.EntitySelectorConfig(
|
||||||
|
domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN]
|
||||||
|
),
|
||||||
|
), # vol.In(temp_sensors),
|
||||||
vol.Required(CONF_CYCLE_MIN, default=5): cv.positive_int,
|
vol.Required(CONF_CYCLE_MIN, default=5): cv.positive_int,
|
||||||
vol.Required(CONF_TEMP_MIN, default=7): vol.Coerce(float),
|
vol.Required(CONF_TEMP_MIN, default=7): vol.Coerce(float),
|
||||||
vol.Required(CONF_TEMP_MAX, default=35): vol.Coerce(float),
|
vol.Required(CONF_TEMP_MAX, default=35): vol.Coerce(float),
|
||||||
@@ -244,7 +246,11 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
|
|
||||||
self.STEP_THERMOSTAT_SWITCH = vol.Schema(
|
self.STEP_THERMOSTAT_SWITCH = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_HEATER): vol.In(switches),
|
vol.Required(CONF_HEATER): selector.EntitySelector(
|
||||||
|
selector.EntitySelectorConfig(
|
||||||
|
domain=[SWITCH_DOMAIN, INPUT_BOOLEAN_DOMAIN]
|
||||||
|
),
|
||||||
|
), # vol.In(switches),
|
||||||
vol.Required(
|
vol.Required(
|
||||||
CONF_PROP_FUNCTION, default=PROPORTIONAL_FUNCTION_TPI
|
CONF_PROP_FUNCTION, default=PROPORTIONAL_FUNCTION_TPI
|
||||||
): vol.In(
|
): vol.In(
|
||||||
@@ -257,7 +263,9 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
|
|
||||||
self.STEP_THERMOSTAT_CLIMATE = vol.Schema(
|
self.STEP_THERMOSTAT_CLIMATE = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_CLIMATE): vol.In(climates),
|
vol.Required(CONF_CLIMATE): selector.EntitySelector(
|
||||||
|
selector.EntitySelectorConfig(domain=CLIMATE_DOMAIN),
|
||||||
|
), # vol.In(climates),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -277,14 +285,22 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
|
|
||||||
self.STEP_WINDOW_DATA_SCHEMA = vol.Schema(
|
self.STEP_WINDOW_DATA_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_WINDOW_SENSOR): vol.In(window_sensors),
|
vol.Optional(CONF_WINDOW_SENSOR): selector.EntitySelector(
|
||||||
|
selector.EntitySelectorConfig(
|
||||||
|
domain=[BINARY_SENSOR_DOMAIN, INPUT_BOOLEAN_DOMAIN]
|
||||||
|
),
|
||||||
|
), # vol.In(window_sensors),
|
||||||
vol.Optional(CONF_WINDOW_DELAY, default=30): cv.positive_int,
|
vol.Optional(CONF_WINDOW_DELAY, default=30): cv.positive_int,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
self.STEP_MOTION_DATA_SCHEMA = vol.Schema(
|
self.STEP_MOTION_DATA_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_MOTION_SENSOR): vol.In(window_sensors),
|
vol.Optional(CONF_MOTION_SENSOR): selector.EntitySelector(
|
||||||
|
selector.EntitySelectorConfig(
|
||||||
|
domain=[BINARY_SENSOR_DOMAIN, INPUT_BOOLEAN_DOMAIN]
|
||||||
|
),
|
||||||
|
), # vol.In(window_sensors),
|
||||||
vol.Optional(CONF_MOTION_DELAY, default=30): cv.positive_int,
|
vol.Optional(CONF_MOTION_DELAY, default=30): cv.positive_int,
|
||||||
vol.Optional(CONF_MOTION_PRESET, default="comfort"): vol.In(
|
vol.Optional(CONF_MOTION_PRESET, default="comfort"): vol.In(
|
||||||
CONF_PRESETS_SELECTIONABLE
|
CONF_PRESETS_SELECTIONABLE
|
||||||
@@ -297,8 +313,16 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
|
|
||||||
self.STEP_POWER_DATA_SCHEMA = vol.Schema(
|
self.STEP_POWER_DATA_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_POWER_SENSOR): vol.In(power_sensors),
|
vol.Optional(CONF_POWER_SENSOR): selector.EntitySelector(
|
||||||
vol.Optional(CONF_MAX_POWER_SENSOR): vol.In(power_sensors),
|
selector.EntitySelectorConfig(
|
||||||
|
domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN]
|
||||||
|
),
|
||||||
|
), # vol.In(power_sensors),
|
||||||
|
vol.Optional(CONF_MAX_POWER_SENSOR): selector.EntitySelector(
|
||||||
|
selector.EntitySelectorConfig(
|
||||||
|
domain=[SENSOR_DOMAIN, INPUT_NUMBER_DOMAIN]
|
||||||
|
),
|
||||||
|
), # vol.In(power_sensors),
|
||||||
vol.Optional(CONF_DEVICE_POWER, default="1"): vol.Coerce(float),
|
vol.Optional(CONF_DEVICE_POWER, default="1"): vol.Coerce(float),
|
||||||
vol.Optional(CONF_PRESET_POWER, default="13"): vol.Coerce(float),
|
vol.Optional(CONF_PRESET_POWER, default="13"): vol.Coerce(float),
|
||||||
}
|
}
|
||||||
@@ -306,7 +330,15 @@ class VersatileThermostatBaseConfigFlow(FlowHandler):
|
|||||||
|
|
||||||
self.STEP_PRESENCE_DATA_SCHEMA = vol.Schema(
|
self.STEP_PRESENCE_DATA_SCHEMA = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_PRESENCE_SENSOR): vol.In(presence_sensors),
|
vol.Optional(CONF_PRESENCE_SENSOR): selector.EntitySelector(
|
||||||
|
selector.EntitySelectorConfig(
|
||||||
|
domain=[
|
||||||
|
PERSON_DOMAIN,
|
||||||
|
BINARY_SENSOR_DOMAIN,
|
||||||
|
INPUT_BOOLEAN_DOMAIN,
|
||||||
|
]
|
||||||
|
),
|
||||||
|
), # vol.In(presence_sensors),
|
||||||
}
|
}
|
||||||
).extend(
|
).extend(
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user