Add battery sensors to hunterdouglas_powerview (#34917)
This commit is contained in:
parent
cfc0edff6b
commit
a2efc079f1
6 changed files with 127 additions and 34 deletions
|
@ -313,6 +313,7 @@ omit =
|
||||||
homeassistant/components/hue/light.py
|
homeassistant/components/hue/light.py
|
||||||
homeassistant/components/hunterdouglas_powerview/__init__.py
|
homeassistant/components/hunterdouglas_powerview/__init__.py
|
||||||
homeassistant/components/hunterdouglas_powerview/scene.py
|
homeassistant/components/hunterdouglas_powerview/scene.py
|
||||||
|
homeassistant/components/hunterdouglas_powerview/sensor.py
|
||||||
homeassistant/components/hunterdouglas_powerview/cover.py
|
homeassistant/components/hunterdouglas_powerview/cover.py
|
||||||
homeassistant/components/hunterdouglas_powerview/entity.py
|
homeassistant/components/hunterdouglas_powerview/entity.py
|
||||||
homeassistant/components/hydrawise/*
|
homeassistant/components/hydrawise/*
|
||||||
|
|
|
@ -69,7 +69,7 @@ CONFIG_SCHEMA = vol.Schema(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
PLATFORMS = ["cover", "scene"]
|
PLATFORMS = ["cover", "scene", "sensor"]
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,8 @@ ROOM_NAME_UNICODE = "name_unicode"
|
||||||
ROOM_ID = "id"
|
ROOM_ID = "id"
|
||||||
|
|
||||||
SHADE_RESPONSE = "shade"
|
SHADE_RESPONSE = "shade"
|
||||||
|
SHADE_BATTERY_LEVEL = "batteryStrength"
|
||||||
|
SHADE_BATTERY_LEVEL_MAX = 200
|
||||||
|
|
||||||
STATE_ATTRIBUTE_ROOM_NAME = "roomName"
|
STATE_ATTRIBUTE_ROOM_NAME = "roomName"
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import logging
|
||||||
from aiopvapi.helpers.constants import ATTR_POSITION1, ATTR_POSITION_DATA
|
from aiopvapi.helpers.constants import ATTR_POSITION1, ATTR_POSITION_DATA
|
||||||
from aiopvapi.resources.shade import (
|
from aiopvapi.resources.shade import (
|
||||||
ATTR_POSKIND1,
|
ATTR_POSKIND1,
|
||||||
ATTR_TYPE,
|
|
||||||
MAX_POSITION,
|
MAX_POSITION,
|
||||||
MIN_POSITION,
|
MIN_POSITION,
|
||||||
factory as PvShade,
|
factory as PvShade,
|
||||||
|
@ -28,13 +27,7 @@ from .const import (
|
||||||
COORDINATOR,
|
COORDINATOR,
|
||||||
DEVICE_INFO,
|
DEVICE_INFO,
|
||||||
DEVICE_MODEL,
|
DEVICE_MODEL,
|
||||||
DEVICE_SERIAL_NUMBER,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
FIRMWARE_BUILD,
|
|
||||||
FIRMWARE_IN_SHADE,
|
|
||||||
FIRMWARE_REVISION,
|
|
||||||
FIRMWARE_SUB_REVISION,
|
|
||||||
MANUFACTURER,
|
|
||||||
PV_API,
|
PV_API,
|
||||||
PV_ROOM_DATA,
|
PV_ROOM_DATA,
|
||||||
PV_SHADE_DATA,
|
PV_SHADE_DATA,
|
||||||
|
@ -43,7 +36,7 @@ from .const import (
|
||||||
SHADE_RESPONSE,
|
SHADE_RESPONSE,
|
||||||
STATE_ATTRIBUTE_ROOM_NAME,
|
STATE_ATTRIBUTE_ROOM_NAME,
|
||||||
)
|
)
|
||||||
from .entity import HDEntity
|
from .entity import ShadeEntity
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -93,21 +86,19 @@ def hass_position_to_hd(hass_positon):
|
||||||
return int(hass_positon / 100 * MAX_POSITION)
|
return int(hass_positon / 100 * MAX_POSITION)
|
||||||
|
|
||||||
|
|
||||||
class PowerViewShade(HDEntity, CoverEntity):
|
class PowerViewShade(ShadeEntity, CoverEntity):
|
||||||
"""Representation of a powerview shade."""
|
"""Representation of a powerview shade."""
|
||||||
|
|
||||||
def __init__(self, shade, name, room_data, coordinator, device_info):
|
def __init__(self, shade, name, room_data, coordinator, device_info):
|
||||||
"""Initialize the shade."""
|
"""Initialize the shade."""
|
||||||
room_id = shade.raw_data.get(ROOM_ID_IN_SHADE)
|
room_id = shade.raw_data.get(ROOM_ID_IN_SHADE)
|
||||||
super().__init__(coordinator, device_info, shade.id)
|
super().__init__(coordinator, device_info, shade, name)
|
||||||
self._shade = shade
|
self._shade = shade
|
||||||
self._device_info = device_info
|
self._device_info = device_info
|
||||||
self._is_opening = False
|
self._is_opening = False
|
||||||
self._is_closing = False
|
self._is_closing = False
|
||||||
self._room_name = None
|
|
||||||
self._last_action_timestamp = 0
|
self._last_action_timestamp = 0
|
||||||
self._scheduled_transition_update = None
|
self._scheduled_transition_update = None
|
||||||
self._name = name
|
|
||||||
self._room_name = room_data.get(room_id, {}).get(ROOM_NAME_UNICODE, "")
|
self._room_name = room_data.get(room_id, {}).get(ROOM_NAME_UNICODE, "")
|
||||||
self._current_cover_position = MIN_POSITION
|
self._current_cover_position = MIN_POSITION
|
||||||
self._coordinator = coordinator
|
self._coordinator = coordinator
|
||||||
|
@ -153,7 +144,7 @@ class PowerViewShade(HDEntity, CoverEntity):
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name of the shade."""
|
"""Return the name of the shade."""
|
||||||
return self._name
|
return self._shade_name
|
||||||
|
|
||||||
async def async_close_cover(self, **kwargs):
|
async def async_close_cover(self, **kwargs):
|
||||||
"""Close the cover."""
|
"""Close the cover."""
|
||||||
|
@ -268,26 +259,6 @@ class PowerViewShade(HDEntity, CoverEntity):
|
||||||
self._async_update_current_cover_position()
|
self._async_update_current_cover_position()
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
@property
|
|
||||||
def device_info(self):
|
|
||||||
"""Return the device_info of the device."""
|
|
||||||
firmware = self._shade.raw_data[FIRMWARE_IN_SHADE]
|
|
||||||
sw_version = f"{firmware[FIRMWARE_REVISION]}.{firmware[FIRMWARE_SUB_REVISION]}.{firmware[FIRMWARE_BUILD]}"
|
|
||||||
model = self._shade.raw_data[ATTR_TYPE]
|
|
||||||
for shade in self._shade.shade_types:
|
|
||||||
if shade.shade_type == model:
|
|
||||||
model = shade.description
|
|
||||||
break
|
|
||||||
|
|
||||||
return {
|
|
||||||
"identifiers": {(DOMAIN, self.unique_id)},
|
|
||||||
"name": self.name,
|
|
||||||
"model": str(model),
|
|
||||||
"sw_version": sw_version,
|
|
||||||
"manufacturer": MANUFACTURER,
|
|
||||||
"via_device": (DOMAIN, self._device_info[DEVICE_SERIAL_NUMBER]),
|
|
||||||
}
|
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""When entity is added to hass."""
|
"""When entity is added to hass."""
|
||||||
self._async_update_current_cover_position()
|
self._async_update_current_cover_position()
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
"""The nexia integration base entity."""
|
"""The nexia integration base entity."""
|
||||||
|
|
||||||
|
from aiopvapi.resources.shade import ATTR_TYPE
|
||||||
|
|
||||||
import homeassistant.helpers.device_registry as dr
|
import homeassistant.helpers.device_registry as dr
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
|
@ -11,6 +13,7 @@ from .const import (
|
||||||
DEVICE_SERIAL_NUMBER,
|
DEVICE_SERIAL_NUMBER,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
FIRMWARE_BUILD,
|
FIRMWARE_BUILD,
|
||||||
|
FIRMWARE_IN_SHADE,
|
||||||
FIRMWARE_REVISION,
|
FIRMWARE_REVISION,
|
||||||
FIRMWARE_SUB_REVISION,
|
FIRMWARE_SUB_REVISION,
|
||||||
MANUFACTURER,
|
MANUFACTURER,
|
||||||
|
@ -57,3 +60,33 @@ class HDEntity(Entity):
|
||||||
"sw_version": sw_version,
|
"sw_version": sw_version,
|
||||||
"manufacturer": MANUFACTURER,
|
"manufacturer": MANUFACTURER,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ShadeEntity(HDEntity):
|
||||||
|
"""Base class for hunter douglas shade entities."""
|
||||||
|
|
||||||
|
def __init__(self, coordinator, device_info, shade, shade_name):
|
||||||
|
"""Initialize the shade."""
|
||||||
|
super().__init__(coordinator, device_info, shade.id)
|
||||||
|
self._shade_name = shade_name
|
||||||
|
self._shade = shade
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Return the device_info of the device."""
|
||||||
|
firmware = self._shade.raw_data[FIRMWARE_IN_SHADE]
|
||||||
|
sw_version = f"{firmware[FIRMWARE_REVISION]}.{firmware[FIRMWARE_SUB_REVISION]}.{firmware[FIRMWARE_BUILD]}"
|
||||||
|
model = self._shade.raw_data[ATTR_TYPE]
|
||||||
|
for shade in self._shade.shade_types:
|
||||||
|
if shade.shade_type == model:
|
||||||
|
model = shade.description
|
||||||
|
break
|
||||||
|
|
||||||
|
return {
|
||||||
|
"identifiers": {(DOMAIN, self._shade.id)},
|
||||||
|
"name": self._shade_name,
|
||||||
|
"model": str(model),
|
||||||
|
"sw_version": sw_version,
|
||||||
|
"manufacturer": MANUFACTURER,
|
||||||
|
"via_device": (DOMAIN, self._device_info[DEVICE_SERIAL_NUMBER]),
|
||||||
|
}
|
||||||
|
|
86
homeassistant/components/hunterdouglas_powerview/sensor.py
Normal file
86
homeassistant/components/hunterdouglas_powerview/sensor.py
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
"""Support for hunterdouglass_powerview sensors."""
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from aiopvapi.resources.shade import factory as PvShade
|
||||||
|
|
||||||
|
from homeassistant.const import DEVICE_CLASS_BATTERY, UNIT_PERCENTAGE
|
||||||
|
from homeassistant.core import callback
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
COORDINATOR,
|
||||||
|
DEVICE_INFO,
|
||||||
|
DOMAIN,
|
||||||
|
PV_API,
|
||||||
|
PV_SHADE_DATA,
|
||||||
|
SHADE_BATTERY_LEVEL,
|
||||||
|
SHADE_BATTERY_LEVEL_MAX,
|
||||||
|
)
|
||||||
|
from .entity import ShadeEntity
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass, entry, async_add_entities):
|
||||||
|
"""Set up the hunter douglas shades sensors."""
|
||||||
|
|
||||||
|
pv_data = hass.data[DOMAIN][entry.entry_id]
|
||||||
|
shade_data = pv_data[PV_SHADE_DATA]
|
||||||
|
pv_request = pv_data[PV_API]
|
||||||
|
coordinator = pv_data[COORDINATOR]
|
||||||
|
device_info = pv_data[DEVICE_INFO]
|
||||||
|
|
||||||
|
entities = []
|
||||||
|
for raw_shade in shade_data.values():
|
||||||
|
shade = PvShade(raw_shade, pv_request)
|
||||||
|
if SHADE_BATTERY_LEVEL not in shade.raw_data:
|
||||||
|
continue
|
||||||
|
name_before_refresh = shade.name
|
||||||
|
entities.append(
|
||||||
|
PowerViewShadeBatterySensor(
|
||||||
|
coordinator, device_info, shade, name_before_refresh
|
||||||
|
)
|
||||||
|
)
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
||||||
|
|
||||||
|
class PowerViewShadeBatterySensor(ShadeEntity):
|
||||||
|
"""Representation of an shade battery charge sensor."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Return the unit of measurement."""
|
||||||
|
return UNIT_PERCENTAGE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Name of the shade battery."""
|
||||||
|
return f"{self._shade_name} Battery"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_class(self):
|
||||||
|
"""Shade battery Class."""
|
||||||
|
return DEVICE_CLASS_BATTERY
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self):
|
||||||
|
"""Shade battery Uniqueid."""
|
||||||
|
return f"{self._unique_id}_charge"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Get the current value in percentage."""
|
||||||
|
return round(
|
||||||
|
self._shade.raw_data[SHADE_BATTERY_LEVEL] / SHADE_BATTERY_LEVEL_MAX * 100
|
||||||
|
)
|
||||||
|
|
||||||
|
async def async_added_to_hass(self):
|
||||||
|
"""When entity is added to hass."""
|
||||||
|
self.async_on_remove(
|
||||||
|
self._coordinator.async_add_listener(self._async_update_shade_from_group)
|
||||||
|
)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _async_update_shade_from_group(self):
|
||||||
|
"""Update with new data from the coordinator."""
|
||||||
|
self._shade.raw_data = self._coordinator.data[self._shade.id]
|
||||||
|
self.async_write_ha_state()
|
Loading…
Add table
Add a link
Reference in a new issue