diff --git a/custom_components/wibeee/api.py b/custom_components/wibeee/api.py index 306041eba8..7705206219 100644 --- a/custom_components/wibeee/api.py +++ b/custom_components/wibeee/api.py @@ -31,11 +31,18 @@ async def async_fetch_device_info(self, retries: int): devices = await self.async_fetch_url(f'http://{self.host}/services/user/devices.xml', retries) device_id = devices['devices']['id'] + var_names = ['macAddr', 'softVersion', 'model', 'ipAddr'] + var_ids = [f"{quote_plus(device_id)}.{name}" for name in var_names] + values = await self.async_fetch_url(f'http://{self.host}/services/user/values.xml?var={"&".join(var_ids)}', retries) + # macAddr11:11:11:11:11:11 - values = await self.async_fetch_url(f'http://{self.host}/services/user/values.xml?var={quote_plus(device_id)}.macAddr', retries) - mac_addr = values['values']['variable']['value'] + device_vars = {var['id']: var['value'] for var in values['values']['variable']} - return dict(id=device_id, mac_addr=mac_addr.replace(":", "").lower()) if device_id and mac_addr else None + return { + **device_vars, + 'macAddr': device_vars['macAddr'].replace(':', ''), + 'id': device_id, + } if len(device_vars) == len(var_names) else None async def async_fetch_url(self, url, retries: int = 0): async def fetch_with_retries(try_n): diff --git a/custom_components/wibeee/config_flow.py b/custom_components/wibeee/config_flow.py index 862970e38c..bfa7cd806f 100644 --- a/custom_components/wibeee/config_flow.py +++ b/custom_components/wibeee/config_flow.py @@ -13,6 +13,7 @@ from .api import WibeeeAPI from .const import (DOMAIN, DEFAULT_SCAN_INTERVAL) +from .util import short_mac _LOGGER = logging.getLogger(__name__) @@ -26,9 +27,9 @@ async def validate_input(hass: HomeAssistant, user_input: dict) -> [str, str, di except Exception as e: raise NoDeviceInfo from e - mac_addr = format_mac(device['mac_addr']) + mac_addr = format_mac(device['macAddr']) unique_id = mac_addr - name = f"Wibeee {mac_addr.replace(':', '')[-6:].upper()}" + name = f"Wibeee {short_mac(mac_addr)}" return name, unique_id, {CONF_HOST: user_input[CONF_HOST], } diff --git a/custom_components/wibeee/sensor.py b/custom_components/wibeee/sensor.py index d8bd27dd1d..1b1ba101f0 100755 --- a/custom_components/wibeee/sensor.py +++ b/custom_components/wibeee/sensor.py @@ -40,12 +40,14 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import PlatformNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_track_time_interval from homeassistant.util import slugify from .api import WibeeeAPI from .const import (DOMAIN, DEFAULT_SCAN_INTERVAL, DEFAULT_TIMEOUT) +from .util import short_mac _LOGGER = logging.getLogger(__name__) @@ -72,6 +74,20 @@ 'energia_reactiva_cap': ['Capacitive_Reactive_Energy', 'Capacitive Reactive Energy', 'VArCh', DEVICE_CLASS_ENERGY] } +KNOWN_MODELS = { + 'WBM': 'Wibeee 1Ph', + 'WBT': 'Wibeee 3Ph', + 'WTD': 'Wibeee 3Ph RN', + 'WX2': 'Wibeee MAX 2S', + 'WX3': 'Wibeee MAX 3S', + 'WXX': 'Wibeee MAX MS', + 'WBB': 'Wibeee BOX', + 'WB3': 'Wibeee BOX S3P', + 'W3P': 'Wibeee 3Ph 3W', + 'WGD': 'Wibeee GND', + 'WBP': 'Wibeee PLUG', +} + async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Import existing configuration from YAML.""" @@ -126,7 +142,7 @@ class WibeeeSensor(SensorEntity): def __init__(self, device, xml_name: str, sensor_phase: str, sensor_type: str, sensor_value): """Initialize the sensor.""" ha_name, friendly_name, unit, device_class = SENSOR_TYPES[sensor_type] - [device_name, mac_addr] = [device['id'], device['mac_addr']] + [device_name, mac_addr] = [device['id'], device['macAddr']] entity_id = slugify(f"{DOMAIN} {mac_addr} {friendly_name} L{sensor_phase}") self._xml_name = xml_name self._attr_native_unit_of_measurement = unit @@ -137,6 +153,7 @@ def __init__(self, device, xml_name: str, sensor_phase: str, sensor_type: str, s self._attr_unique_id = f"_{mac_addr}_{ha_name.lower()}_{sensor_phase}" self._attr_name = f"{device_name} {friendly_name} L{sensor_phase}" self._attr_should_poll = False + self._attr_device_info = _make_device_info(device, sensor_phase) self.entity_id = f"sensor.{entity_id}" # we don't want this derived from the name @callback @@ -154,3 +171,24 @@ def make_device_sensors(device, status) -> list['WibeeeSensor']: phase_values = [(key, value, key[4:].split("_", 1)) for key, value in status.items() if key.startswith('fase')] known_values = [(key, phase, stype, value) for (key, value, (phase, stype)) in phase_values] return [WibeeeSensor(device, key, phase, stype, value) for (key, phase, stype, value) in known_values if stype in SENSOR_TYPES] + + +def _make_device_info(device, sensor_phase) -> DeviceInfo: + mac_addr = device['macAddr'] + is_clamp = sensor_phase != '4' + + device_name = f'Wibeee {short_mac(mac_addr)}' + device_model = KNOWN_MODELS.get(device['model'], 'Wibeee Energy Meter') + + return DeviceInfo( + # identifiers and links + identifiers={(DOMAIN, f'{mac_addr}_L{sensor_phase}' if is_clamp else mac_addr)}, + via_device=(DOMAIN, f'{mac_addr}') if is_clamp else None, + + # and now for the humans :) + name=device_name if not is_clamp else f"{device_name} Line {sensor_phase}", + model=device_model if not is_clamp else f'{device_model} Clamp', + manufacturer='Smilics', + configuration_url=f"http://{device['ipAddr']}/" if not is_clamp else None, + sw_version=f"{device['softVersion']}" if not is_clamp else None, + ) diff --git a/custom_components/wibeee/util.py b/custom_components/wibeee/util.py new file mode 100644 index 0000000000..de7167b1a0 --- /dev/null +++ b/custom_components/wibeee/util.py @@ -0,0 +1,3 @@ +def short_mac(mac_addr): + """Returns the last 6 chars of the MAC address for showing in UI.""" + return mac_addr.replace(':', '')[-6:].upper()