Skip to content
This repository was archived by the owner on Mar 19, 2024. It is now read-only.

Commit 568372f

Browse files
cleaning + perdiodic (re)login (#201)
1 parent 62b64ae commit 568372f

File tree

12 files changed

+97
-35
lines changed

12 files changed

+97
-35
lines changed

custom_components/multimatic/__init__.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
"""The multimatic integration."""
22
import asyncio
3-
from datetime import timedelta
3+
from datetime import datetime, timedelta
44
import logging
55

6+
from pymultimatic.api import ApiError, defaults
7+
68
from homeassistant.config_entries import ConfigEntry
79
from homeassistant.const import CONF_SCAN_INTERVAL, EVENT_HOMEASSISTANT_STOP
810
from homeassistant.core import HomeAssistant
11+
from homeassistant.helpers.event import async_track_time_interval
912
from homeassistant.helpers.typing import ConfigType
10-
from pymultimatic.api import defaults
1113

1214
from .const import (
15+
CONF_APPLICATION,
1316
CONF_SERIAL_NUMBER,
1417
COORDINATOR_LIST,
1518
COORDINATORS,
1619
DEFAULT_SCAN_INTERVAL,
1720
DOMAIN,
21+
FORCE_RELOGIN_TIMEDELTA,
1822
PLATFORMS,
19-
SERVICES_HANDLER, CONF_APPLICATION,
23+
RELOGIN_TASK_CLEAN,
24+
SERVICES_HANDLER,
2025
)
2126
from .coordinator import MultimaticApi, MultimaticCoordinator
2227
from .service import SERVICES, MultimaticServiceHandler
@@ -71,14 +76,26 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
7176
async def logout(event):
7277
await api.logout()
7378

79+
async def force_relogin(time: datetime):
80+
try:
81+
_LOGGER.debug("Periodic relogin")
82+
await api.login(True)
83+
except ApiError:
84+
_LOGGER.debug("Error during periodic login", exc_info=True)
85+
86+
hass.data[DOMAIN][entry.entry_id][RELOGIN_TASK_CLEAN] = async_track_time_interval(
87+
hass, force_relogin, FORCE_RELOGIN_TIMEDELTA
88+
)
7489
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, logout)
7590

7691
await async_setup_service(hass, api, entry)
7792

7893
return True
7994

8095

81-
async def async_setup_service(hass, api: MultimaticApi, entry: ConfigEntry):
96+
async def async_setup_service(
97+
hass: HomeAssistant, api: MultimaticApi, entry: ConfigEntry
98+
):
8299
"""Set up services."""
83100
serial = api.serial if api.fixed_serial else None
84101

@@ -96,7 +113,7 @@ async def async_setup_service(hass, api: MultimaticApi, entry: ConfigEntry):
96113
hass.data[DOMAIN][entry.entry_id][SERVICES_HANDLER] = service_handler
97114

98115

99-
async def async_unload_services(hass, entry: ConfigEntry):
116+
async def async_unload_services(hass: HomeAssistant, entry: ConfigEntry):
100117
"""Remove services when integration is removed."""
101118
service_handler = hass.data[DOMAIN][entry.entry_id].get(SERVICES_HANDLER, None)
102119
if service_handler:
@@ -121,6 +138,11 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
121138
)
122139
)
123140
)
141+
142+
relogin_task_clean = hass.data[DOMAIN][entry.entry_id][RELOGIN_TASK_CLEAN]
143+
if relogin_task_clean:
144+
relogin_task_clean()
145+
124146
if unload_ok:
125147
await async_unload_services(hass, entry)
126148
hass.data[DOMAIN].pop(entry.entry_id)
@@ -130,7 +152,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
130152
return unload_ok
131153

132154

133-
async def async_migrate_entry(hass, config_entry: ConfigEntry):
155+
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
134156
"""Migrate old entry."""
135157
_LOGGER.debug("Migrating from version %s", config_entry.version)
136158
if config_entry.version == 1:

custom_components/multimatic/binary_sensor.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
BinarySensorEntity,
1414
)
1515
from homeassistant.config_entries import ConfigEntry
16+
from homeassistant.const import EntityCategory
1617
from homeassistant.core import HomeAssistant
1718
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
18-
from homeassistant.helpers.entity import DeviceInfo, EntityCategory
19+
from homeassistant.helpers.entity import DeviceInfo
1920
from homeassistant.helpers.entity_platform import AddEntitiesCallback
2021
from homeassistant.util import slugify
2122

@@ -315,7 +316,7 @@ def __init__(
315316
detail_coo: MultimaticCoordinator,
316317
gw_coo: MultimaticCoordinator,
317318
comp_id,
318-
):
319+
) -> None:
319320
"""Initialize entity."""
320321
MultimaticEntity.__init__(self, coord, DOMAIN, comp_id)
321322
self._detail_coo = detail_coo

custom_components/multimatic/climate.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
from . import SERVICES
4040
from .const import (
41+
CONF_APPLICATION,
4142
DEFAULT_QUICK_VETO_DURATION,
4243
DOMAIN as MULTIMATIC,
4344
PRESET_COOLING_FOR_X_DAYS,
@@ -52,7 +53,6 @@
5253
SENSO,
5354
VENTILATION,
5455
ZONES,
55-
CONF_APPLICATION,
5656
)
5757
from .coordinator import MultimaticCoordinator
5858
from .entities import MultimaticEntity
@@ -81,7 +81,11 @@ async def async_setup_entry(
8181
if zones_coo.data:
8282
for zone in zones_coo.data:
8383
if not zone.rbr and zone.enabled:
84-
climates.append(build_zone_climate(zones_coo, zone, ventilation_coo.data, system_application))
84+
climates.append(
85+
build_zone_climate(
86+
zones_coo, zone, ventilation_coo.data, system_application
87+
)
88+
)
8589

8690
if rooms_coo.data:
8791
rbr_zone = next((zone for zone in zones_coo.data if zone.rbr), None)
@@ -113,7 +117,7 @@ def __init__(
113117
self,
114118
coordinator: MultimaticCoordinator,
115119
comp_id,
116-
):
120+
) -> None:
117121
"""Initialize entity."""
118122
super().__init__(coordinator, DOMAIN, comp_id)
119123
self._comp_id = comp_id
@@ -365,14 +369,18 @@ def current_humidity(self) -> int | None:
365369
return int(humidity) if humidity is not None else None
366370

367371

368-
def build_zone_climate(coordinator: MultimaticCoordinator, zone: Zone, ventilation, application) -> AbstractZoneClimate:
372+
def build_zone_climate(
373+
coordinator: MultimaticCoordinator, zone: Zone, ventilation, application
374+
) -> AbstractZoneClimate:
375+
"""Create correct climate entity."""
369376
if application == MULTIMATIC:
370377
return ZoneClimate(coordinator, zone, ventilation)
371378
return ZoneClimateSenso(coordinator, zone, ventilation)
372379

373380

374381
class AbstractZoneClimate(MultimaticClimate, ABC):
375382
"""Abstract class for a climate for a zone."""
383+
376384
def __init__(
377385
self, coordinator: MultimaticCoordinator, zone: Zone, ventilation
378386
) -> None:
@@ -510,6 +518,7 @@ async def async_set_preset_mode(self, preset_mode: str) -> None:
510518
mode = self._ha_preset()[preset_mode]
511519
await self.coordinator.api.set_zone_operating_mode(self, mode)
512520

521+
513522
class ZoneClimate(AbstractZoneClimate):
514523
"""Climate for a MULTIMATIC zone."""
515524

@@ -602,4 +611,4 @@ def _multimatic_mode(self):
602611
return ZoneClimateSenso._SENSO_TO_HA
603612

604613
def _ha_preset(self):
605-
return ZoneClimateSenso._HA_PRESET_TO_SENSO
614+
return ZoneClimateSenso._HA_PRESET_TO_SENSO

custom_components/multimatic/config_flow.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@
88
from homeassistant import config_entries, core, exceptions
99
from homeassistant.config_entries import ConfigEntry, OptionsFlow
1010
from homeassistant.const import CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_USERNAME
11-
from homeassistant.core import callback
11+
from homeassistant.core import HomeAssistant, callback
1212
from homeassistant.data_entry_flow import FlowResult
1313
from homeassistant.helpers.aiohttp_client import async_create_clientsession
1414
import homeassistant.helpers.config_validation as cv
1515

16-
from .const import CONF_SERIAL_NUMBER, DEFAULT_SCAN_INTERVAL, DOMAIN, CONF_APPLICATION
16+
from .const import (
17+
CONF_APPLICATION,
18+
CONF_SERIAL_NUMBER,
19+
DEFAULT_SCAN_INTERVAL,
20+
DOMAIN,
21+
MULTIMATIC,
22+
SENSO,
23+
)
1724

1825
_LOGGER = logging.getLogger(__name__)
1926

@@ -22,7 +29,7 @@
2229
vol.Required(CONF_USERNAME): str,
2330
vol.Required(CONF_PASSWORD): str,
2431
vol.Optional(CONF_SERIAL_NUMBER): str,
25-
vol.Required(CONF_APPLICATION, default="MULTIMATIC"): vol.In(["MULTIMATIC", "SENSO"]),
32+
vol.Required(CONF_APPLICATION, default=MULTIMATIC): vol.In([MULTIMATIC, SENSO]),
2633
}
2734
)
2835

@@ -33,20 +40,24 @@ async def validate_input(hass: core.HomeAssistant, data):
3340
Data has the keys from DATA_SCHEMA with values provided by the user.
3441
"""
3542

36-
await validate_authentication(hass, data[CONF_USERNAME], data[CONF_PASSWORD], data[CONF_APPLICATION])
43+
await validate_authentication(
44+
hass, data[CONF_USERNAME], data[CONF_PASSWORD], data[CONF_APPLICATION]
45+
)
3746

3847
return {"title": "Multimatic"}
3948

4049

41-
async def validate_authentication(hass, username, password, application):
50+
async def validate_authentication(
51+
hass: HomeAssistant, username: str, password: str, application: str
52+
):
4253
"""Ensure provided credentials are working."""
4354
try:
44-
systemApplication = defaults.SENSO if application == "SENSO" else defaults.MULTIMATIC
55+
system_app = defaults.SENSO if application == SENSO else defaults.MULTIMATIC
4556
if not await SystemManager(
4657
user=username,
4758
password=password,
4859
session=async_create_clientsession(hass),
49-
application=systemApplication,
60+
application=system_app,
5061
).login(True):
5162
raise InvalidAuth
5263
except ApiError as err:

custom_components/multimatic/const.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
DOMAIN = "multimatic"
88
SENSO = "SENSO"
9+
MULTIMATIC = "MULTIMATIC"
910
ENTITIES = "entities"
1011

1112
# list of platforms into entity are created
@@ -79,3 +80,6 @@
7980
GATEWAY: timedelta(days=1),
8081
EMF_REPORTS: None,
8182
}
83+
84+
FORCE_RELOGIN_TIMEDELTA = timedelta(hours=1)
85+
RELOGIN_TASK_CLEAN = "relogin_task_clean"

custom_components/multimatic/coordinator.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,19 @@
2626

2727
from homeassistant.config_entries import ConfigEntry
2828
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
29+
from homeassistant.core import HomeAssistant
2930
from homeassistant.helpers.aiohttp_client import async_create_clientsession
3031
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
3132

3233
from .const import (
3334
CONF_APPLICATION,
3435
CONF_SERIAL_NUMBER,
3536
DEFAULT_QUICK_VETO_DURATION,
37+
DEFAULT_QUICK_VETO_DURATION_HOURS,
3638
HOLIDAY_MODE,
3739
QUICK_MODE,
3840
REFRESH_EVENT,
39-
SENSO, DEFAULT_QUICK_VETO_DURATION_HOURS,
41+
SENSO,
4042
)
4143
from .utils import (
4244
holiday_mode_from_json,
@@ -51,22 +53,26 @@
5153
class MultimaticApi:
5254
"""Utility to interact with multimatic API."""
5355

54-
def __init__(self, hass, entry: ConfigEntry):
56+
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
5557
"""Init."""
5658

5759
self.serial = entry.data.get(CONF_SERIAL_NUMBER)
5860
self.fixed_serial = self.serial is not None
5961

6062
username = entry.data[CONF_USERNAME]
6163
password = entry.data[CONF_PASSWORD]
62-
systemApplication = defaults.SENSO if entry.data[CONF_APPLICATION] == SENSO else defaults.MULTIMATIC
64+
self._application = (
65+
defaults.SENSO
66+
if entry.data[CONF_APPLICATION] == SENSO
67+
else defaults.MULTIMATIC
68+
)
6369

6470
self._manager = pymultimatic.systemmanager.SystemManager(
6571
user=username,
6672
password=password,
6773
session=async_create_clientsession(hass),
6874
serial=self.serial,
69-
application=systemApplication,
75+
application=self._application,
7076
)
7177

7278
self._quick_mode: QuickMode | None = None
@@ -115,7 +121,7 @@ async def get_ventilation(self):
115121
async def get_dhw(self):
116122
"""Get domestic hot water.
117123
118-
There is a 2 queries here, one to ge the dhw and a second one to get the current temperature if
124+
There are 2 queries here, one to ge the dhw and a second one to get the current temperature if
119125
there is a water tank.
120126
"""
121127
_LOGGER.debug("Will get dhw")
@@ -352,7 +358,7 @@ async def set_quick_veto(self, entity, temperature, duration=None):
352358

353359
q_duration = duration if duration else DEFAULT_QUICK_VETO_DURATION
354360
# For senso, the duration is in hours
355-
if self._manager._application == defaults.SENSO:
361+
if self._application == defaults.SENSO:
356362
q_duration = round(q_duration / 60 / 0.5) * 0.5
357363
qveto = QuickVeto(q_duration, temperature)
358364

@@ -471,20 +477,24 @@ async def _refresh(self, touch_system, entity):
471477
entity.async_schedule_update_ha_state(True)
472478

473479
def _default_quick_veto_duration(self):
474-
return DEFAULT_QUICK_VETO_DURATION_HOURS if self._manager._application == defaults.SENSO else DEFAULT_QUICK_VETO_DURATION
480+
return (
481+
DEFAULT_QUICK_VETO_DURATION_HOURS
482+
if self._application == defaults.SENSO
483+
else DEFAULT_QUICK_VETO_DURATION
484+
)
475485

476486

477487
class MultimaticCoordinator(DataUpdateCoordinator):
478488
"""Multimatic coordinator."""
479489

480490
def __init__(
481491
self,
482-
hass,
492+
hass: HomeAssistant,
483493
name,
484494
api: MultimaticApi,
485495
method: str,
486496
update_interval: timedelta | None,
487-
):
497+
) -> None:
488498
"""Init."""
489499

490500
self._api_listeners: set = set()

custom_components/multimatic/entities.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class MultimaticEntity(CoordinatorEntity, ABC):
1818

1919
coordinator: MultimaticCoordinator
2020

21-
def __init__(self, coordinator: MultimaticCoordinator, domain, device_id):
21+
def __init__(self, coordinator: MultimaticCoordinator, domain, device_id) -> None:
2222
"""Initialize entity."""
2323
super().__init__(coordinator)
2424

custom_components/multimatic/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"homekit": {},
1313
"dependencies": [],
1414
"codeowners": ["@thomasgermain"],
15-
"version": "1.14.0b2",
15+
"version": "1.14.0b3",
1616
"iot_class": "cloud_polling",
1717
"integration_type": "hub"
1818
}

custom_components/multimatic/sensor.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ class ReportSensor(MultimaticEntity, SensorEntity):
107107

108108
def __init__(self, coordinator: MultimaticCoordinator, report: Report) -> None:
109109
"""Init entity."""
110-
MultimaticEntity.__init__(self, coordinator, DOMAIN, f"{report.device_id}_{report.id}")
110+
MultimaticEntity.__init__(
111+
self, coordinator, DOMAIN, f"{report.device_id}_{report.id}"
112+
)
111113
self._report_id = report.id
112114
self._unit = report.unit
113115
self._name = report.name

0 commit comments

Comments
 (0)