Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ omit =
homeassistant/components/hue/light.py
homeassistant/components/hunterdouglas_powerview/__init__.py
homeassistant/components/hunterdouglas_powerview/scene.py
homeassistant/components/hunterdouglas_powerview/sensor.py
homeassistant/components/hunterdouglas_powerview/cover.py
homeassistant/components/hunterdouglas_powerview/entity.py
homeassistant/components/hydrawise/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def _has_all_unique_hosts(value):
)


PLATFORMS = ["cover", "scene"]
PLATFORMS = ["cover", "scene", "sensor"]
_LOGGER = logging.getLogger(__name__)


Expand Down
2 changes: 2 additions & 0 deletions homeassistant/components/hunterdouglas_powerview/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
ROOM_ID = "id"

SHADE_RESPONSE = "shade"
SHADE_BATTERY_LEVEL = "batteryStrength"
SHADE_BATTERY_LEVEL_MAX = 200

STATE_ATTRIBUTE_ROOM_NAME = "roomName"

Expand Down
37 changes: 4 additions & 33 deletions homeassistant/components/hunterdouglas_powerview/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from aiopvapi.helpers.constants import ATTR_POSITION1, ATTR_POSITION_DATA
from aiopvapi.resources.shade import (
ATTR_POSKIND1,
ATTR_TYPE,
MAX_POSITION,
MIN_POSITION,
factory as PvShade,
Expand All @@ -28,13 +27,7 @@
COORDINATOR,
DEVICE_INFO,
DEVICE_MODEL,
DEVICE_SERIAL_NUMBER,
DOMAIN,
FIRMWARE_BUILD,
FIRMWARE_IN_SHADE,
FIRMWARE_REVISION,
FIRMWARE_SUB_REVISION,
MANUFACTURER,
PV_API,
PV_ROOM_DATA,
PV_SHADE_DATA,
Expand All @@ -43,7 +36,7 @@
SHADE_RESPONSE,
STATE_ATTRIBUTE_ROOM_NAME,
)
from .entity import HDEntity
from .entity import ShadeEntity

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -93,21 +86,19 @@ def hass_position_to_hd(hass_positon):
return int(hass_positon / 100 * MAX_POSITION)


class PowerViewShade(HDEntity, CoverEntity):
class PowerViewShade(ShadeEntity, CoverEntity):
"""Representation of a powerview shade."""

def __init__(self, shade, name, room_data, coordinator, device_info):
"""Initialize the 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._device_info = device_info
self._is_opening = False
self._is_closing = False
self._room_name = None
self._last_action_timestamp = 0
self._scheduled_transition_update = None
self._name = name
self._room_name = room_data.get(room_id, {}).get(ROOM_NAME_UNICODE, "")
self._current_cover_position = MIN_POSITION
self._coordinator = coordinator
Expand Down Expand Up @@ -153,7 +144,7 @@ def device_class(self):
@property
def name(self):
"""Return the name of the shade."""
return self._name
return self._shade_name

async def async_close_cover(self, **kwargs):
"""Close the cover."""
Expand Down Expand Up @@ -268,26 +259,6 @@ async def _async_force_refresh_state(self):
self._async_update_current_cover_position()
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):
"""When entity is added to hass."""
self._async_update_current_cover_position()
Expand Down
33 changes: 33 additions & 0 deletions homeassistant/components/hunterdouglas_powerview/entity.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""The nexia integration base entity."""

from aiopvapi.resources.shade import ATTR_TYPE

import homeassistant.helpers.device_registry as dr
from homeassistant.helpers.entity import Entity

Expand All @@ -11,6 +13,7 @@
DEVICE_SERIAL_NUMBER,
DOMAIN,
FIRMWARE_BUILD,
FIRMWARE_IN_SHADE,
FIRMWARE_REVISION,
FIRMWARE_SUB_REVISION,
MANUFACTURER,
Expand Down Expand Up @@ -57,3 +60,33 @@ def device_info(self):
"sw_version": sw_version,
"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 changes: 86 additions & 0 deletions homeassistant/components/hunterdouglas_powerview/sensor.py
Original file line number Diff line number Diff line change
@@ -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()