From 03ec77fb6263285c57313ce25ea6b4ec7fe59d5d Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Sat, 12 Mar 2022 05:13:46 +0100 Subject: [PATCH] Motion blinds support direct wifi blinds (#67372) * bump motionblinds to 0.6.0 * fix unknown type * fix name for wifi direct blinds * push motionblinds to 0.6.1 * fix RSSI sensor * Do not add singnal sensor twice for direct WiFi blinds * fix device registry * fix typo * missing import * fix styling * fix spelling --- .../components/motion_blinds/__init__.py | 35 ++++----- .../components/motion_blinds/const.py | 1 + .../components/motion_blinds/cover.py | 71 +++++++++++++++---- .../components/motion_blinds/manifest.json | 2 +- .../components/motion_blinds/sensor.py | 41 +++++++---- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 7 files changed, 109 insertions(+), 45 deletions(-) diff --git a/homeassistant/components/motion_blinds/__init__.py b/homeassistant/components/motion_blinds/__init__.py index b3712e6e832..b60de49044d 100644 --- a/homeassistant/components/motion_blinds/__init__.py +++ b/homeassistant/components/motion_blinds/__init__.py @@ -4,7 +4,7 @@ import logging from socket import timeout from typing import TYPE_CHECKING -from motionblinds import AsyncMotionMulticast, ParseException +from motionblinds import DEVICE_TYPES_WIFI, AsyncMotionMulticast, ParseException from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY, CONF_HOST, EVENT_HOMEASSISTANT_STOP @@ -23,6 +23,7 @@ from .const import ( KEY_COORDINATOR, KEY_GATEWAY, KEY_MULTICAST_LISTENER, + KEY_VERSION, MANUFACTURER, PLATFORMS, UPDATE_INTERVAL, @@ -147,29 +148,31 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # Fetch initial data so we have data when entities subscribe await coordinator.async_config_entry_first_refresh() - hass.data[DOMAIN][entry.entry_id] = { - KEY_GATEWAY: motion_gateway, - KEY_COORDINATOR: coordinator, - } - if motion_gateway.firmware is not None: version = f"{motion_gateway.firmware}, protocol: {motion_gateway.protocol}" else: version = f"Protocol: {motion_gateway.protocol}" + hass.data[DOMAIN][entry.entry_id] = { + KEY_GATEWAY: motion_gateway, + KEY_COORDINATOR: coordinator, + KEY_VERSION: version, + } + if TYPE_CHECKING: assert entry.unique_id is not None - device_registry = dr.async_get(hass) - device_registry.async_get_or_create( - config_entry_id=entry.entry_id, - connections={(dr.CONNECTION_NETWORK_MAC, motion_gateway.mac)}, - identifiers={(DOMAIN, motion_gateway.mac)}, - manufacturer=MANUFACTURER, - name=entry.title, - model="Wi-Fi bridge", - sw_version=version, - ) + if motion_gateway.device_type not in DEVICE_TYPES_WIFI: + device_registry = dr.async_get(hass) + device_registry.async_get_or_create( + config_entry_id=entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, motion_gateway.mac)}, + identifiers={(DOMAIN, motion_gateway.mac)}, + manufacturer=MANUFACTURER, + name=entry.title, + model="Wi-Fi bridge", + sw_version=version, + ) hass.config_entries.async_setup_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/motion_blinds/const.py b/homeassistant/components/motion_blinds/const.py index 01f74c4ef4d..696a00ff79e 100644 --- a/homeassistant/components/motion_blinds/const.py +++ b/homeassistant/components/motion_blinds/const.py @@ -15,6 +15,7 @@ DEFAULT_INTERFACE = "any" KEY_GATEWAY = "gateway" KEY_COORDINATOR = "coordinator" KEY_MULTICAST_LISTENER = "multicast_listener" +KEY_VERSION = "version" ATTR_WIDTH = "width" ATTR_ABSOLUTE_POSITION = "absolute_position" diff --git a/homeassistant/components/motion_blinds/cover.py b/homeassistant/components/motion_blinds/cover.py index 9bc952a21ea..ffb2a03ddc6 100644 --- a/homeassistant/components/motion_blinds/cover.py +++ b/homeassistant/components/motion_blinds/cover.py @@ -1,7 +1,7 @@ """Support for Motion Blinds using their WLAN API.""" import logging -from motionblinds import BlindType +from motionblinds import DEVICE_TYPES_WIFI, BlindType import voluptuous as vol from homeassistant.components.cover import ( @@ -12,7 +12,11 @@ from homeassistant.components.cover import ( ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from homeassistant.helpers import config_validation as cv, entity_platform +from homeassistant.helpers import ( + config_validation as cv, + device_registry as dr, + entity_platform, +) from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity @@ -24,6 +28,7 @@ from .const import ( DOMAIN, KEY_COORDINATOR, KEY_GATEWAY, + KEY_VERSION, MANUFACTURER, SERVICE_SET_ABSOLUTE_POSITION, ) @@ -74,26 +79,40 @@ async def async_setup_entry( entities = [] motion_gateway = hass.data[DOMAIN][config_entry.entry_id][KEY_GATEWAY] coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR] + sw_version = hass.data[DOMAIN][config_entry.entry_id][KEY_VERSION] for blind in motion_gateway.device_list.values(): if blind.type in POSITION_DEVICE_MAP: entities.append( MotionPositionDevice( - coordinator, blind, POSITION_DEVICE_MAP[blind.type], config_entry + coordinator, + blind, + POSITION_DEVICE_MAP[blind.type], + config_entry, + sw_version, ) ) elif blind.type in TILT_DEVICE_MAP: entities.append( MotionTiltDevice( - coordinator, blind, TILT_DEVICE_MAP[blind.type], config_entry + coordinator, + blind, + TILT_DEVICE_MAP[blind.type], + config_entry, + sw_version, ) ) elif blind.type in TDBU_DEVICE_MAP: entities.append( MotionTDBUDevice( - coordinator, blind, TDBU_DEVICE_MAP[blind.type], config_entry, "Top" + coordinator, + blind, + TDBU_DEVICE_MAP[blind.type], + config_entry, + sw_version, + "Top", ) ) entities.append( @@ -102,6 +121,7 @@ async def async_setup_entry( blind, TDBU_DEVICE_MAP[blind.type], config_entry, + sw_version, "Bottom", ) ) @@ -111,12 +131,25 @@ async def async_setup_entry( blind, TDBU_DEVICE_MAP[blind.type], config_entry, + sw_version, "Combined", ) ) else: - _LOGGER.warning("Blind type '%s' not yet supported", blind.blind_type) + _LOGGER.warning( + "Blind type '%s' not yet supported, " "assuming RollerBlind", + blind.blind_type, + ) + entities.append( + MotionPositionDevice( + coordinator, + blind, + POSITION_DEVICE_MAP[BlindType.RollerBlind], + config_entry, + sw_version, + ) + ) async_add_entities(entities) @@ -131,22 +164,34 @@ async def async_setup_entry( class MotionPositionDevice(CoordinatorEntity, CoverEntity): """Representation of a Motion Blind Device.""" - def __init__(self, coordinator, blind, device_class, config_entry): + def __init__(self, coordinator, blind, device_class, config_entry, sw_version): """Initialize the blind.""" super().__init__(coordinator) self._blind = blind self._config_entry = config_entry + if blind.device_type in DEVICE_TYPES_WIFI: + via_device = () + connections = {(dr.CONNECTION_NETWORK_MAC, blind.mac)} + name = blind.blind_type + else: + via_device = (DOMAIN, blind._gateway.mac) + connections = {} + name = f"{blind.blind_type}-{blind.mac[12:]}" + sw_version = None + self._attr_device_class = device_class - self._attr_name = f"{blind.blind_type}-{blind.mac[12:]}" + self._attr_name = name self._attr_unique_id = blind.mac self._attr_device_info = DeviceInfo( + connections=connections, identifiers={(DOMAIN, blind.mac)}, manufacturer=MANUFACTURER, model=blind.blind_type, - name=f"{blind.blind_type}-{blind.mac[12:]}", - via_device=(DOMAIN, blind._gateway.mac), + name=name, + via_device=via_device, + sw_version=sw_version, hw_version=blind.wireless_name, ) @@ -247,9 +292,11 @@ class MotionTiltDevice(MotionPositionDevice): class MotionTDBUDevice(MotionPositionDevice): """Representation of a Motion Top Down Bottom Up blind Device.""" - def __init__(self, coordinator, blind, device_class, config_entry, motor): + def __init__( + self, coordinator, blind, device_class, config_entry, sw_version, motor + ): """Initialize the blind.""" - super().__init__(coordinator, blind, device_class, config_entry) + super().__init__(coordinator, blind, device_class, config_entry, sw_version) self._motor = motor self._motor_key = motor[0] self._attr_name = f"{blind.blind_type}-{motor}-{blind.mac[12:]}" diff --git a/homeassistant/components/motion_blinds/manifest.json b/homeassistant/components/motion_blinds/manifest.json index c904320d9af..40fd9cafad4 100644 --- a/homeassistant/components/motion_blinds/manifest.json +++ b/homeassistant/components/motion_blinds/manifest.json @@ -3,7 +3,7 @@ "name": "Motion Blinds", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/motion_blinds", - "requirements": ["motionblinds==0.5.13"], + "requirements": ["motionblinds==0.6.1"], "dependencies": ["network"], "codeowners": ["@starkillerOG"], "iot_class": "local_push", diff --git a/homeassistant/components/motion_blinds/sensor.py b/homeassistant/components/motion_blinds/sensor.py index 4c0b4251bf2..03e3a6e7618 100644 --- a/homeassistant/components/motion_blinds/sensor.py +++ b/homeassistant/components/motion_blinds/sensor.py @@ -1,5 +1,5 @@ """Support for Motion Blinds sensors.""" -from motionblinds import BlindType +from motionblinds import DEVICE_TYPES_WIFI, BlindType from homeassistant.components.sensor import SensorDeviceClass, SensorEntity from homeassistant.config_entries import ConfigEntry @@ -31,13 +31,15 @@ async def async_setup_entry( if blind.type == BlindType.TopDownBottomUp: entities.append(MotionTDBUBatterySensor(coordinator, blind, "Bottom")) entities.append(MotionTDBUBatterySensor(coordinator, blind, "Top")) - elif blind.battery_voltage > 0: + elif blind.battery_voltage is not None and blind.battery_voltage > 0: # Only add battery powered blinds entities.append(MotionBatterySensor(coordinator, blind)) - entities.append( - MotionSignalStrengthSensor(coordinator, motion_gateway, TYPE_GATEWAY) - ) + # Do not add signal sensor twice for direct WiFi blinds + if motion_gateway.device_type not in DEVICE_TYPES_WIFI: + entities.append( + MotionSignalStrengthSensor(coordinator, motion_gateway, TYPE_GATEWAY) + ) async_add_entities(entities) @@ -52,9 +54,14 @@ class MotionBatterySensor(CoordinatorEntity, SensorEntity): """Initialize the Motion Battery Sensor.""" super().__init__(coordinator) + if blind.device_type in DEVICE_TYPES_WIFI: + name = f"{blind.blind_type}-battery" + else: + name = f"{blind.blind_type}-battery-{blind.mac[12:]}" + self._blind = blind self._attr_device_info = DeviceInfo(identifiers={(DOMAIN, blind.mac)}) - self._attr_name = f"{blind.blind_type}-battery-{blind.mac[12:]}" + self._attr_name = name self._attr_unique_id = f"{blind.mac}-battery" @property @@ -96,9 +103,14 @@ class MotionTDBUBatterySensor(MotionBatterySensor): """Initialize the Motion Battery Sensor.""" super().__init__(coordinator, blind) + if blind.device_type in DEVICE_TYPES_WIFI: + name = f"{blind.blind_type}-{motor}-battery" + else: + name = f"{blind.blind_type}-{motor}-battery-{blind.mac[12:]}" + self._motor = motor self._attr_unique_id = f"{blind.mac}-{motor}-battery" - self._attr_name = f"{blind.blind_type}-{motor}-battery-{blind.mac[12:]}" + self._attr_name = name @property def native_value(self): @@ -130,17 +142,18 @@ class MotionSignalStrengthSensor(CoordinatorEntity, SensorEntity): """Initialize the Motion Signal Strength Sensor.""" super().__init__(coordinator) + if device_type == TYPE_GATEWAY: + name = "Motion gateway signal strength" + elif device.device_type in DEVICE_TYPES_WIFI: + name = f"{device.blind_type} signal strength" + else: + name = f"{device.blind_type} signal strength - {device.mac[12:]}" + self._device = device self._device_type = device_type self._attr_device_info = DeviceInfo(identifiers={(DOMAIN, device.mac)}) self._attr_unique_id = f"{device.mac}-RSSI" - - @property - def name(self): - """Return the name of the blind signal strength sensor.""" - if self._device_type == TYPE_GATEWAY: - return "Motion gateway signal strength" - return f"{self._device.blind_type} signal strength - {self._device.mac[12:]}" + self._attr_name = name @property def available(self): diff --git a/requirements_all.txt b/requirements_all.txt index 744a1973215..fa3e8e745c9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1011,7 +1011,7 @@ mitemp_bt==0.0.5 moehlenhoff-alpha2==1.1.2 # homeassistant.components.motion_blinds -motionblinds==0.5.13 +motionblinds==0.6.1 # homeassistant.components.motioneye motioneye-client==0.3.12 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 893530eab42..f67bac50270 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -671,7 +671,7 @@ minio==5.0.10 moehlenhoff-alpha2==1.1.2 # homeassistant.components.motion_blinds -motionblinds==0.5.13 +motionblinds==0.6.1 # homeassistant.components.motioneye motioneye-client==0.3.12