mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 19:27:45 +00:00
Rewrite Atag (#35496)
* rewrite library * Update strings.json * fix updated with empty reply * dont use entity_id * atag_id * use super init instead * original ids to prevent breaking change
This commit is contained in:
parent
86b984b0bd
commit
4099815a08
@ -3,24 +3,12 @@ from datetime import timedelta
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import async_timeout
|
import async_timeout
|
||||||
from pyatag import AtagDataStore, AtagException
|
from pyatag import AtagException, AtagOne
|
||||||
|
|
||||||
from homeassistant.components.climate import DOMAIN as CLIMATE
|
from homeassistant.components.climate import DOMAIN as CLIMATE
|
||||||
from homeassistant.components.sensor import DOMAIN as SENSOR
|
from homeassistant.components.sensor import DOMAIN as SENSOR
|
||||||
from homeassistant.components.water_heater import DOMAIN as WATER_HEATER
|
from homeassistant.components.water_heater import DOMAIN as WATER_HEATER
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
|
||||||
ATTR_DEVICE_CLASS,
|
|
||||||
ATTR_ICON,
|
|
||||||
ATTR_ID,
|
|
||||||
ATTR_MODE,
|
|
||||||
ATTR_NAME,
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT,
|
|
||||||
DEVICE_CLASS_PRESSURE,
|
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
|
||||||
PRESSURE_BAR,
|
|
||||||
TEMP_CELSIUS,
|
|
||||||
)
|
|
||||||
from homeassistant.core import HomeAssistant, asyncio
|
from homeassistant.core import HomeAssistant, asyncio
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
@ -30,94 +18,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda
|
|||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOMAIN = "atag"
|
DOMAIN = "atag"
|
||||||
DATA_LISTENER = f"{DOMAIN}_listener"
|
|
||||||
SIGNAL_UPDATE_ATAG = f"{DOMAIN}_update"
|
|
||||||
PLATFORMS = [CLIMATE, WATER_HEATER, SENSOR]
|
PLATFORMS = [CLIMATE, WATER_HEATER, SENSOR]
|
||||||
HOUR = "h"
|
|
||||||
FIRE = "fire"
|
|
||||||
PERCENTAGE = "%"
|
|
||||||
|
|
||||||
ICONS = {
|
|
||||||
TEMP_CELSIUS: "mdi:thermometer",
|
|
||||||
PRESSURE_BAR: "mdi:gauge",
|
|
||||||
FIRE: "mdi:fire",
|
|
||||||
ATTR_MODE: "mdi:settings",
|
|
||||||
}
|
|
||||||
|
|
||||||
ENTITY_TYPES = {
|
|
||||||
SENSOR: [
|
|
||||||
{
|
|
||||||
ATTR_NAME: "Outside Temperature",
|
|
||||||
ATTR_ID: "outside_temp",
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
|
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
|
|
||||||
ATTR_ICON: ICONS[TEMP_CELSIUS],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ATTR_NAME: "Average Outside Temperature",
|
|
||||||
ATTR_ID: "tout_avg",
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
|
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
|
|
||||||
ATTR_ICON: ICONS[TEMP_CELSIUS],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ATTR_NAME: "Weather Status",
|
|
||||||
ATTR_ID: "weather_status",
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: None,
|
|
||||||
ATTR_DEVICE_CLASS: None,
|
|
||||||
ATTR_ICON: None,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ATTR_NAME: "CH Water Pressure",
|
|
||||||
ATTR_ID: "ch_water_pres",
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: PRESSURE_BAR,
|
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_PRESSURE,
|
|
||||||
ATTR_ICON: ICONS[PRESSURE_BAR],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ATTR_NAME: "CH Water Temperature",
|
|
||||||
ATTR_ID: "ch_water_temp",
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
|
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
|
|
||||||
ATTR_ICON: ICONS[TEMP_CELSIUS],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ATTR_NAME: "CH Return Temperature",
|
|
||||||
ATTR_ID: "ch_return_temp",
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
|
|
||||||
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
|
|
||||||
ATTR_ICON: ICONS[TEMP_CELSIUS],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ATTR_NAME: "Burning Hours",
|
|
||||||
ATTR_ID: "burning_hours",
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: HOUR,
|
|
||||||
ATTR_DEVICE_CLASS: None,
|
|
||||||
ATTR_ICON: ICONS[FIRE],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ATTR_NAME: "Flame",
|
|
||||||
ATTR_ID: "rel_mod_level",
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
|
|
||||||
ATTR_DEVICE_CLASS: None,
|
|
||||||
ATTR_ICON: ICONS[FIRE],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
CLIMATE: {
|
|
||||||
ATTR_NAME: DOMAIN.title(),
|
|
||||||
ATTR_ID: CLIMATE,
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: None,
|
|
||||||
ATTR_DEVICE_CLASS: None,
|
|
||||||
ATTR_ICON: None,
|
|
||||||
},
|
|
||||||
WATER_HEATER: {
|
|
||||||
ATTR_NAME: DOMAIN.title(),
|
|
||||||
ATTR_ID: WATER_HEATER,
|
|
||||||
ATTR_UNIT_OF_MEASUREMENT: None,
|
|
||||||
ATTR_DEVICE_CLASS: None,
|
|
||||||
ATTR_ICON: None,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup(hass: HomeAssistant, config):
|
async def async_setup(hass: HomeAssistant, config):
|
||||||
@ -130,8 +31,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
session = async_get_clientsession(hass)
|
session = async_get_clientsession(hass)
|
||||||
|
|
||||||
coordinator = AtagDataUpdateCoordinator(hass, session, entry)
|
coordinator = AtagDataUpdateCoordinator(hass, session, entry)
|
||||||
|
try:
|
||||||
await coordinator.async_refresh()
|
await coordinator.async_refresh()
|
||||||
|
except AtagException:
|
||||||
|
raise ConfigEntryNotReady
|
||||||
|
|
||||||
if not coordinator.last_update_success:
|
if not coordinator.last_update_success:
|
||||||
raise ConfigEntryNotReady
|
raise ConfigEntryNotReady
|
||||||
@ -152,7 +55,7 @@ class AtagDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
|
|
||||||
def __init__(self, hass, session, entry):
|
def __init__(self, hass, session, entry):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
self.atag = AtagDataStore(session, paired=True, **entry.data)
|
self.atag = AtagOne(session=session, **entry.data)
|
||||||
|
|
||||||
super().__init__(
|
super().__init__(
|
||||||
hass, _LOGGER, name=DOMAIN, update_interval=timedelta(seconds=30)
|
hass, _LOGGER, name=DOMAIN, update_interval=timedelta(seconds=30)
|
||||||
@ -162,12 +65,12 @@ class AtagDataUpdateCoordinator(DataUpdateCoordinator):
|
|||||||
"""Update data via library."""
|
"""Update data via library."""
|
||||||
with async_timeout.timeout(20):
|
with async_timeout.timeout(20):
|
||||||
try:
|
try:
|
||||||
await self.atag.async_update()
|
await self.atag.update()
|
||||||
if not self.atag.sensordata:
|
if not self.atag.report:
|
||||||
raise UpdateFailed("No data")
|
raise UpdateFailed("No data")
|
||||||
except (AtagException) as error:
|
except AtagException as error:
|
||||||
raise UpdateFailed(error)
|
raise UpdateFailed(error)
|
||||||
return self.atag.sensordata
|
return self.atag.report
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass, entry):
|
async def async_unload_entry(hass, entry):
|
||||||
@ -188,24 +91,21 @@ async def async_unload_entry(hass, entry):
|
|||||||
class AtagEntity(Entity):
|
class AtagEntity(Entity):
|
||||||
"""Defines a base Atag entity."""
|
"""Defines a base Atag entity."""
|
||||||
|
|
||||||
def __init__(self, coordinator: AtagDataUpdateCoordinator, atag_type: dict) -> None:
|
def __init__(self, coordinator: AtagDataUpdateCoordinator, atag_id: str) -> None:
|
||||||
"""Initialize the Atag entity."""
|
"""Initialize the Atag entity."""
|
||||||
self.coordinator = coordinator
|
self.coordinator = coordinator
|
||||||
|
|
||||||
self._id = atag_type[ATTR_ID]
|
self._id = atag_id
|
||||||
self._name = atag_type[ATTR_NAME]
|
self._name = DOMAIN.title()
|
||||||
self._icon = atag_type[ATTR_ICON]
|
|
||||||
self._unit = atag_type[ATTR_UNIT_OF_MEASUREMENT]
|
|
||||||
self._class = atag_type[ATTR_DEVICE_CLASS]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_info(self) -> dict:
|
def device_info(self) -> dict:
|
||||||
"""Return info for device registry."""
|
"""Return info for device registry."""
|
||||||
device = self.coordinator.atag.device
|
device = self.coordinator.atag.id
|
||||||
version = self.coordinator.atag.apiversion
|
version = self.coordinator.atag.apiversion
|
||||||
return {
|
return {
|
||||||
"identifiers": {(DOMAIN, device)},
|
"identifiers": {(DOMAIN, device)},
|
||||||
ATTR_NAME: "Atag Thermostat",
|
"name": "Atag Thermostat",
|
||||||
"model": "Atag One",
|
"model": "Atag One",
|
||||||
"sw_version": version,
|
"sw_version": version,
|
||||||
"manufacturer": "Atag",
|
"manufacturer": "Atag",
|
||||||
@ -216,14 +116,6 @@ class AtagEntity(Entity):
|
|||||||
"""Return the name of the entity."""
|
"""Return the name of the entity."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
@property
|
|
||||||
def icon(self) -> str:
|
|
||||||
"""Return the mdi icon of the entity."""
|
|
||||||
self._icon = (
|
|
||||||
self.coordinator.data.get(self._id, {}).get(ATTR_ICON) or self._icon
|
|
||||||
)
|
|
||||||
return self._icon
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def should_poll(self) -> bool:
|
def should_poll(self) -> bool:
|
||||||
"""Return the polling requirement of the entity."""
|
"""Return the polling requirement of the entity."""
|
||||||
@ -232,12 +124,7 @@ class AtagEntity(Entity):
|
|||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
"""Return the unit of measurement of this entity, if any."""
|
"""Return the unit of measurement of this entity, if any."""
|
||||||
return self._unit
|
return self.coordinator.atag.climate.temp_unit
|
||||||
|
|
||||||
@property
|
|
||||||
def device_class(self):
|
|
||||||
"""Return the device class."""
|
|
||||||
return self._class
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
@ -247,7 +134,7 @@ class AtagEntity(Entity):
|
|||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
"""Return a unique ID to use for this entity."""
|
"""Return a unique ID to use for this entity."""
|
||||||
return f"{self.coordinator.atag.device}-{self._id}"
|
return f"{self.coordinator.atag.id}-{self._id}"
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Connect to dispatcher listening for entity data notifications."""
|
"""Connect to dispatcher listening for entity data notifications."""
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Initialization of ATAG One climate platform."""
|
"""Initialization of ATAG One climate platform."""
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from homeassistant.components.climate import ClimateDevice
|
from homeassistant.components.climate import ClimateEntity
|
||||||
from homeassistant.components.climate.const import (
|
from homeassistant.components.climate.const import (
|
||||||
CURRENT_HVAC_HEAT,
|
CURRENT_HVAC_HEAT,
|
||||||
CURRENT_HVAC_IDLE,
|
CURRENT_HVAC_IDLE,
|
||||||
@ -14,7 +14,7 @@ from homeassistant.components.climate.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
|
||||||
|
|
||||||
from . import CLIMATE, DOMAIN, ENTITY_TYPES, AtagEntity
|
from . import CLIMATE, DOMAIN, AtagEntity
|
||||||
|
|
||||||
PRESET_SCHEDULE = "Auto"
|
PRESET_SCHEDULE = "Auto"
|
||||||
PRESET_MANUAL = "Manual"
|
PRESET_MANUAL = "Manual"
|
||||||
@ -33,10 +33,10 @@ HVAC_MODES = [HVAC_MODE_AUTO, HVAC_MODE_HEAT]
|
|||||||
async def async_setup_entry(hass, entry, async_add_entities):
|
async def async_setup_entry(hass, entry, async_add_entities):
|
||||||
"""Load a config entry."""
|
"""Load a config entry."""
|
||||||
coordinator = hass.data[DOMAIN][entry.entry_id]
|
coordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
async_add_entities([AtagThermostat(coordinator, ENTITY_TYPES[CLIMATE])])
|
async_add_entities([AtagThermostat(coordinator, CLIMATE)])
|
||||||
|
|
||||||
|
|
||||||
class AtagThermostat(AtagEntity, ClimateDevice):
|
class AtagThermostat(AtagEntity, ClimateEntity):
|
||||||
"""Atag climate device."""
|
"""Atag climate device."""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -47,8 +47,8 @@ class AtagThermostat(AtagEntity, ClimateDevice):
|
|||||||
@property
|
@property
|
||||||
def hvac_mode(self) -> Optional[str]:
|
def hvac_mode(self) -> Optional[str]:
|
||||||
"""Return hvac operation ie. heat, cool mode."""
|
"""Return hvac operation ie. heat, cool mode."""
|
||||||
if self.coordinator.atag.hvac_mode in HVAC_MODES:
|
if self.coordinator.atag.climate.hvac_mode in HVAC_MODES:
|
||||||
return self.coordinator.atag.hvac_mode
|
return self.coordinator.atag.climate.hvac_mode
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -59,31 +59,31 @@ class AtagThermostat(AtagEntity, ClimateDevice):
|
|||||||
@property
|
@property
|
||||||
def hvac_action(self) -> Optional[str]:
|
def hvac_action(self) -> Optional[str]:
|
||||||
"""Return the current running hvac operation."""
|
"""Return the current running hvac operation."""
|
||||||
if self.coordinator.atag.cv_status:
|
if self.coordinator.atag.climate.status:
|
||||||
return CURRENT_HVAC_HEAT
|
return CURRENT_HVAC_HEAT
|
||||||
return CURRENT_HVAC_IDLE
|
return CURRENT_HVAC_IDLE
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def temperature_unit(self):
|
def temperature_unit(self):
|
||||||
"""Return the unit of measurement."""
|
"""Return the unit of measurement."""
|
||||||
if self.coordinator.atag.temp_unit in [TEMP_CELSIUS, TEMP_FAHRENHEIT]:
|
if self.coordinator.atag.climate.temp_unit in [TEMP_CELSIUS, TEMP_FAHRENHEIT]:
|
||||||
return self.coordinator.atag.temp_unit
|
return self.coordinator.atag.climate.temp_unit
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_temperature(self) -> Optional[float]:
|
def current_temperature(self) -> Optional[float]:
|
||||||
"""Return the current temperature."""
|
"""Return the current temperature."""
|
||||||
return self.coordinator.atag.temperature
|
return self.coordinator.atag.climate.temperature
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature(self) -> Optional[float]:
|
def target_temperature(self) -> Optional[float]:
|
||||||
"""Return the temperature we try to reach."""
|
"""Return the temperature we try to reach."""
|
||||||
return self.coordinator.atag.target_temperature
|
return self.coordinator.atag.climate.target_temperature
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preset_mode(self) -> Optional[str]:
|
def preset_mode(self) -> Optional[str]:
|
||||||
"""Return the current preset mode, e.g., auto, manual, fireplace, extend, etc."""
|
"""Return the current preset mode, e.g., auto, manual, fireplace, extend, etc."""
|
||||||
return self.coordinator.atag.hold_mode
|
return self.coordinator.atag.climate.preset_mode
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preset_modes(self) -> Optional[List[str]]:
|
def preset_modes(self) -> Optional[List[str]]:
|
||||||
@ -92,15 +92,15 @@ class AtagThermostat(AtagEntity, ClimateDevice):
|
|||||||
|
|
||||||
async def async_set_temperature(self, **kwargs) -> None:
|
async def async_set_temperature(self, **kwargs) -> None:
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
await self.coordinator.atag.set_temp(kwargs.get(ATTR_TEMPERATURE))
|
await self.coordinator.atag.climate.set_temp(kwargs.get(ATTR_TEMPERATURE))
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
|
async def async_set_hvac_mode(self, hvac_mode: str) -> None:
|
||||||
"""Set new target hvac mode."""
|
"""Set new target hvac mode."""
|
||||||
await self.coordinator.atag.set_hvac_mode(hvac_mode)
|
await self.coordinator.atag.climate.set_hvac_mode(hvac_mode)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||||
"""Set new preset mode."""
|
"""Set new preset mode."""
|
||||||
await self.coordinator.atag.set_hold_mode(preset_mode)
|
await self.coordinator.atag.climate.set_preset_mode(preset_mode)
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
"""Config flow for the Atag component."""
|
"""Config flow for the Atag component."""
|
||||||
from pyatag import DEFAULT_PORT, AtagDataStore, AtagException
|
from pyatag import DEFAULT_PORT, AtagException, AtagOne
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import CONF_DEVICE, CONF_HOST, CONF_PORT
|
from homeassistant.const import CONF_DEVICE, CONF_EMAIL, CONF_HOST, CONF_PORT
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
|
|
||||||
@ -11,6 +11,7 @@ from . import DOMAIN # pylint: disable=unused-import
|
|||||||
|
|
||||||
DATA_SCHEMA = {
|
DATA_SCHEMA = {
|
||||||
vol.Required(CONF_HOST): str,
|
vol.Required(CONF_HOST): str,
|
||||||
|
vol.Optional(CONF_EMAIL): str,
|
||||||
vol.Required(CONF_PORT, default=DEFAULT_PORT): vol.Coerce(int),
|
vol.Required(CONF_PORT, default=DEFAULT_PORT): vol.Coerce(int),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,14 +32,15 @@ class AtagConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
return await self._show_form()
|
return await self._show_form()
|
||||||
session = async_get_clientsession(self.hass)
|
session = async_get_clientsession(self.hass)
|
||||||
try:
|
try:
|
||||||
atag = AtagDataStore(session, **user_input)
|
atag = AtagOne(session=session, **user_input)
|
||||||
await atag.async_check_pair_status()
|
await atag.authorize()
|
||||||
|
await atag.update(force=True)
|
||||||
|
|
||||||
except AtagException:
|
except AtagException:
|
||||||
return await self._show_form({"base": "connection_error"})
|
return await self._show_form({"base": "connection_error"})
|
||||||
|
|
||||||
user_input.update({CONF_DEVICE: atag.device})
|
user_input.update({CONF_DEVICE: atag.id})
|
||||||
return self.async_create_entry(title=atag.device, data=user_input)
|
return self.async_create_entry(title=atag.id, data=user_input)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
async def _show_form(self, errors=None):
|
async def _show_form(self, errors=None):
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
"name": "Atag",
|
"name": "Atag",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/atag/",
|
"documentation": "https://www.home-assistant.io/integrations/atag/",
|
||||||
"requirements": ["pyatag==0.2.19"],
|
"requirements": ["pyatag==0.3.1.1"],
|
||||||
"codeowners": ["@MatsNL"]
|
"codeowners": ["@MatsNL"]
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,31 @@
|
|||||||
"""Initialization of ATAG One sensor platform."""
|
"""Initialization of ATAG One sensor platform."""
|
||||||
from homeassistant.const import ATTR_STATE
|
from homeassistant.const import (
|
||||||
|
DEVICE_CLASS_PRESSURE,
|
||||||
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
PRESSURE_BAR,
|
||||||
|
TEMP_CELSIUS,
|
||||||
|
TEMP_FAHRENHEIT,
|
||||||
|
)
|
||||||
|
|
||||||
from . import DOMAIN, ENTITY_TYPES, SENSOR, AtagEntity
|
from . import DOMAIN, AtagEntity
|
||||||
|
|
||||||
|
SENSORS = {
|
||||||
|
"Outside Temperature": "outside_temp",
|
||||||
|
"Average Outside Temperature": "tout_avg",
|
||||||
|
"Weather Status": "weather_status",
|
||||||
|
"CH Water Pressure": "ch_water_pres",
|
||||||
|
"CH Water Temperature": "ch_water_temp",
|
||||||
|
"CH Return Temperature": "ch_return_temp",
|
||||||
|
"Burning Hours": "burning_hours",
|
||||||
|
"Flame": "rel_mod_level",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
"""Initialize sensor platform from config entry."""
|
"""Initialize sensor platform from config entry."""
|
||||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
entities = []
|
entities = []
|
||||||
for sensor in ENTITY_TYPES[SENSOR]:
|
for sensor in SENSORS:
|
||||||
entities.append(AtagSensor(coordinator, sensor))
|
entities.append(AtagSensor(coordinator, sensor))
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
@ -16,7 +33,38 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
class AtagSensor(AtagEntity):
|
class AtagSensor(AtagEntity):
|
||||||
"""Representation of a AtagOne Sensor."""
|
"""Representation of a AtagOne Sensor."""
|
||||||
|
|
||||||
|
def __init__(self, coordinator, sensor):
|
||||||
|
"""Initialize Atag sensor."""
|
||||||
|
super().__init__(coordinator, SENSORS[sensor])
|
||||||
|
self._name = sensor
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state of the sensor."""
|
"""Return the state of the sensor."""
|
||||||
return self.coordinator.data[self._id][ATTR_STATE]
|
return self.coordinator.data[self._id].state
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
"""Return icon."""
|
||||||
|
return self.coordinator.data[self._id].icon
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_class(self):
|
||||||
|
"""Return deviceclass."""
|
||||||
|
if self.coordinator.data[self._id].sensorclass in [
|
||||||
|
DEVICE_CLASS_PRESSURE,
|
||||||
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
]:
|
||||||
|
return self.coordinator.data[self._id].sensorclass
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Return measure."""
|
||||||
|
if self.coordinator.data[self._id].measure in [
|
||||||
|
PRESSURE_BAR,
|
||||||
|
TEMP_CELSIUS,
|
||||||
|
TEMP_FAHRENHEIT,
|
||||||
|
]:
|
||||||
|
return self.coordinator.data[self._id].measure
|
||||||
|
return None
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"title": "Connect to the device",
|
"title": "Connect to the device",
|
||||||
"data": {
|
"data": {
|
||||||
"host": "Host",
|
"host": "Host",
|
||||||
|
"email": "Email (Optional)",
|
||||||
"port": "Port (10000)"
|
"port": "Port (10000)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,11 @@ from homeassistant.components.water_heater import (
|
|||||||
ATTR_TEMPERATURE,
|
ATTR_TEMPERATURE,
|
||||||
STATE_ECO,
|
STATE_ECO,
|
||||||
STATE_PERFORMANCE,
|
STATE_PERFORMANCE,
|
||||||
WaterHeaterDevice,
|
WaterHeaterEntity,
|
||||||
)
|
)
|
||||||
from homeassistant.const import STATE_OFF, TEMP_CELSIUS
|
from homeassistant.const import STATE_OFF, TEMP_CELSIUS
|
||||||
|
|
||||||
from . import DOMAIN, ENTITY_TYPES, WATER_HEATER, AtagEntity
|
from . import DOMAIN, WATER_HEATER, AtagEntity
|
||||||
|
|
||||||
SUPPORT_FLAGS_HEATER = 0
|
SUPPORT_FLAGS_HEATER = 0
|
||||||
OPERATION_LIST = [STATE_OFF, STATE_ECO, STATE_PERFORMANCE]
|
OPERATION_LIST = [STATE_OFF, STATE_ECO, STATE_PERFORMANCE]
|
||||||
@ -16,10 +16,10 @@ OPERATION_LIST = [STATE_OFF, STATE_ECO, STATE_PERFORMANCE]
|
|||||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
"""Initialize DHW device from config entry."""
|
"""Initialize DHW device from config entry."""
|
||||||
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
||||||
async_add_entities([AtagWaterHeater(coordinator, ENTITY_TYPES[WATER_HEATER])])
|
async_add_entities([AtagWaterHeater(coordinator, WATER_HEATER)])
|
||||||
|
|
||||||
|
|
||||||
class AtagWaterHeater(AtagEntity, WaterHeaterDevice):
|
class AtagWaterHeater(AtagEntity, WaterHeaterEntity):
|
||||||
"""Representation of an ATAG water heater."""
|
"""Representation of an ATAG water heater."""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -35,12 +35,12 @@ class AtagWaterHeater(AtagEntity, WaterHeaterDevice):
|
|||||||
@property
|
@property
|
||||||
def current_temperature(self):
|
def current_temperature(self):
|
||||||
"""Return the current temperature."""
|
"""Return the current temperature."""
|
||||||
return self.coordinator.atag.dhw_temperature
|
return self.coordinator.atag.dhw.temperature
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current_operation(self):
|
def current_operation(self):
|
||||||
"""Return current operation."""
|
"""Return current operation."""
|
||||||
if self.coordinator.atag.dhw_status:
|
if self.coordinator.atag.dhw.status:
|
||||||
return STATE_PERFORMANCE
|
return STATE_PERFORMANCE
|
||||||
return STATE_OFF
|
return STATE_OFF
|
||||||
|
|
||||||
@ -51,20 +51,20 @@ class AtagWaterHeater(AtagEntity, WaterHeaterDevice):
|
|||||||
|
|
||||||
async def async_set_temperature(self, **kwargs):
|
async def async_set_temperature(self, **kwargs):
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
if await self.coordinator.atag.dhw_set_temp(kwargs.get(ATTR_TEMPERATURE)):
|
if await self.coordinator.atag.dhw.set_temp(kwargs.get(ATTR_TEMPERATURE)):
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature(self):
|
def target_temperature(self):
|
||||||
"""Return the setpoint if water demand, otherwise return base temp (comfort level)."""
|
"""Return the setpoint if water demand, otherwise return base temp (comfort level)."""
|
||||||
return self.coordinator.atag.dhw_target_temperature
|
return self.coordinator.atag.dhw.target_temperature
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max_temp(self):
|
def max_temp(self):
|
||||||
"""Return the maximum temperature."""
|
"""Return the maximum temperature."""
|
||||||
return self.coordinator.atag.dhw_max_temp
|
return self.coordinator.atag.dhw.max_temp
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_temp(self):
|
def min_temp(self):
|
||||||
"""Return the minimum temperature."""
|
"""Return the minimum temperature."""
|
||||||
return self.coordinator.atag.dhw_min_temp
|
return self.coordinator.atag.dhw.min_temp
|
||||||
|
@ -1212,7 +1212,7 @@ pyalmond==0.0.2
|
|||||||
pyarlo==0.2.3
|
pyarlo==0.2.3
|
||||||
|
|
||||||
# homeassistant.components.atag
|
# homeassistant.components.atag
|
||||||
pyatag==0.2.19
|
pyatag==0.3.1.1
|
||||||
|
|
||||||
# homeassistant.components.netatmo
|
# homeassistant.components.netatmo
|
||||||
pyatmo==3.3.1
|
pyatmo==3.3.1
|
||||||
|
@ -515,7 +515,7 @@ pyalmond==0.0.2
|
|||||||
pyarlo==0.2.3
|
pyarlo==0.2.3
|
||||||
|
|
||||||
# homeassistant.components.atag
|
# homeassistant.components.atag
|
||||||
pyatag==0.2.19
|
pyatag==0.3.1.1
|
||||||
|
|
||||||
# homeassistant.components.netatmo
|
# homeassistant.components.netatmo
|
||||||
pyatmo==3.3.1
|
pyatmo==3.3.1
|
||||||
|
@ -3,13 +3,14 @@ from pyatag import AtagException
|
|||||||
|
|
||||||
from homeassistant import config_entries, data_entry_flow
|
from homeassistant import config_entries, data_entry_flow
|
||||||
from homeassistant.components.atag import DOMAIN
|
from homeassistant.components.atag import DOMAIN
|
||||||
from homeassistant.const import CONF_DEVICE, CONF_HOST, CONF_PORT
|
from homeassistant.const import CONF_DEVICE, CONF_EMAIL, CONF_HOST, CONF_PORT
|
||||||
|
|
||||||
from tests.async_mock import PropertyMock, patch
|
from tests.async_mock import PropertyMock, patch
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
FIXTURE_USER_INPUT = {
|
FIXTURE_USER_INPUT = {
|
||||||
CONF_HOST: "127.0.0.1",
|
CONF_HOST: "127.0.0.1",
|
||||||
|
CONF_EMAIL: "test@domain.com",
|
||||||
CONF_PORT: 10000,
|
CONF_PORT: 10000,
|
||||||
}
|
}
|
||||||
FIXTURE_COMPLETE_ENTRY = FIXTURE_USER_INPUT.copy()
|
FIXTURE_COMPLETE_ENTRY = FIXTURE_USER_INPUT.copy()
|
||||||
@ -42,7 +43,7 @@ async def test_connection_error(hass):
|
|||||||
"""Test we show user form on Atag connection error."""
|
"""Test we show user form on Atag connection error."""
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.atag.config_flow.AtagDataStore.async_check_pair_status",
|
"homeassistant.components.atag.config_flow.AtagOne.authorize",
|
||||||
side_effect=AtagException(),
|
side_effect=AtagException(),
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
@ -58,10 +59,10 @@ async def test_connection_error(hass):
|
|||||||
|
|
||||||
async def test_full_flow_implementation(hass):
|
async def test_full_flow_implementation(hass):
|
||||||
"""Test registering an integration and finishing flow works."""
|
"""Test registering an integration and finishing flow works."""
|
||||||
with patch(
|
with patch("homeassistant.components.atag.AtagOne.authorize",), patch(
|
||||||
"homeassistant.components.atag.AtagDataStore.async_check_pair_status",
|
"homeassistant.components.atag.AtagOne.update",
|
||||||
), patch(
|
), patch(
|
||||||
"homeassistant.components.atag.AtagDataStore.device",
|
"homeassistant.components.atag.AtagOne.id",
|
||||||
new_callable=PropertyMock(return_value="device_identifier"),
|
new_callable=PropertyMock(return_value="device_identifier"),
|
||||||
):
|
):
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user