Skip to content

Commit

Permalink
chore(api): async_fetch_status requests specific vars from values2.xml
Browse files Browse the repository at this point in the history
avoids getting back WiFi secrets from Wibeee...
  • Loading branch information
luuuis committed Dec 19, 2023
1 parent 4ebad05 commit 052eca9
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 13 deletions.
6 changes: 4 additions & 2 deletions custom_components/wibeee/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,12 @@ def __init__(self, session: aiohttp.ClientSession, host: str, timeout: timedelta
self.max_wait = min(timedelta(seconds=5), timeout)
_LOGGER.info("Initializing WibeeeAPI with host: %s, timeout %s, max_wait: %s", host, self.timeout, self.max_wait)

async def async_fetch_status(self, device: DeviceInfo, retries: int = 0) -> dict[str, any]:
async def async_fetch_status(self, device: DeviceInfo, var_names: list[str], retries: int = 0) -> dict[str, any]:
"""Fetches the status XML from Wibeee as a dict, optionally retries"""
if device.use_values2:
values2_response = await self.async_fetch_url(f'http://{self.host}/services/user/values2.xml?id={quote_plus(device.id)}', retries)
# request the specific vars we need, otherwise Wibeee will send down everything including WiFi keys.
var_ids = [f"{quote_plus(device.id)}.{name}" for name in var_names]
values2_response = await self.async_fetch_url(f'http://{self.host}/services/user/values2.xml?id={"&".join(var_ids)}', retries)
return values2_response['values']
else:
status_response = await self.async_fetch_url(f'http://{self.host}/en/status.xml', retries)
Expand Down
35 changes: 24 additions & 11 deletions custom_components/wibeee/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
from homeassistant.helpers.typing import StateType
from homeassistant.util import slugify

from .api import WibeeeAPI, DeviceInfo, StatusResponse
from .api import WibeeeAPI, DeviceInfo
from .const import (
DOMAIN,
DEFAULT_SCAN_INTERVAL,
Expand Down Expand Up @@ -138,7 +138,15 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
))


def create_sensors(device, status: StatusResponse) -> list['WibeeeSensor']:
class StatusElement(NamedTuple):
phase: str
xml_name: str
sensor_type: SensorType


def get_status_elements(device: DeviceInfo) -> list[StatusElement]:
"""Returns the expected elements in the status XML response for this device."""

class StatusLookup(NamedTuple):
"""Strategy for handling `status.xml` or `values2.xml` response lookups."""
is_expected: Callable[[SensorType], bool]
Expand All @@ -152,11 +160,11 @@ class StatusLookup(NamedTuple):
lambda s: [(phase, f"fase{phase}_{s.status_xml_suffix}") for phase in ['1', '2', '3', '4']],
)

expected_types = [sensor for sensor in KNOWN_SENSORS if lookup.is_expected(sensor)]
expected = [(phase, xml_name, sensor_type) for sensor_type in expected_types for phase, xml_name in lookup.xml_names(sensor_type)]
available = [(phase, xml_name, sensor_type, status.get(xml_name)) for phase, xml_name, sensor_type in expected if xml_name in status]

return [WibeeeSensor(device, phase, sensor_type, xml_name, initial_value) for (phase, xml_name, sensor_type, initial_value) in available]
return [
StatusElement(phase, xml_name, sensor_type)
for sensor_type in KNOWN_SENSORS if lookup.is_expected(sensor_type)
for phase, xml_name in lookup.xml_names(sensor_type)
]


def update_sensors(sensors, update_source, lookup_key, data):
Expand All @@ -173,8 +181,8 @@ def status_xml_param(sensor: WibeeeSensor) -> str:

async def fetching_data(now=None):
try:
fetched = await api.async_fetch_status(device, retries=3)
update_sensors(sensors, 'status.xml', status_xml_param, fetched)
fetched = await api.async_fetch_status(device, [s.status_xml_param for s in sensors], retries=3)
update_sensors(sensors, 'values2.xml' if device.use_values2 else 'status.xml', status_xml_param, fetched)
except Exception as err:
if now is None:
raise PlatformNotReady from err
Expand Down Expand Up @@ -218,9 +226,14 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e

api = WibeeeAPI(session, host, min(timeout, scan_interval))
device = await api.async_fetch_device_info(retries=5)
initial_status = await api.async_fetch_status(device, retries=10)
status_elements = get_status_elements(device)

initial_status = await api.async_fetch_status(device, [e.xml_name for e in status_elements], retries=10)
sensors = [
WibeeeSensor(device, e.phase, e.sensor_type, e.xml_name, initial_status.get(e.xml_name))
for e in status_elements if e.xml_name in initial_status
]

sensors = create_sensors(device, initial_status)
for sensor in sensors:
_LOGGER.debug("Adding '%s' (unique_id=%s)", sensor, sensor.unique_id)
async_add_entities(sensors, True)
Expand Down

0 comments on commit 052eca9

Please sign in to comment.