Add battery sensor to iCloud (#29818)

* Add battery sensor to iCloud

* Update .coveragerc

* Review: @balloob & @MartinHjelmare

* Review: use f string
pull/29955/head
Quentame 2019-12-14 23:06:00 +01:00 committed by Martin Hjelmare
parent 003658a3f0
commit 820780996a
5 changed files with 104 additions and 20 deletions

View File

@ -321,6 +321,7 @@ omit =
homeassistant/components/iaqualink/switch.py
homeassistant/components/icloud/__init__.py
homeassistant/components/icloud/device_tracker.py
homeassistant/components/icloud/sensor.py
homeassistant/components/izone/climate.py
homeassistant/components/izone/discovery.py
homeassistant/components/izone/__init__.py

View File

@ -560,11 +560,6 @@ class IcloudDevice:
"""Return a unique ID."""
return self._device_id
@property
def dev_id(self) -> str:
"""Return the device ID."""
return self._device_id
@property
def name(self) -> str:
"""Return the Apple device name."""

View File

@ -14,8 +14,7 @@ DEFAULT_GPS_ACCURACY_THRESHOLD = 500 # meters
STORAGE_KEY = DOMAIN
STORAGE_VERSION = 1
# Next PR will add sensor
ICLOUD_COMPONENTS = ["device_tracker"]
ICLOUD_COMPONENTS = ["device_tracker", "sensor"]
# pyicloud.AppleDevice status
DEVICE_BATTERY_LEVEL = "batteryLevel"

View File

@ -1,8 +1,10 @@
"""Support for tracking for iCloud devices."""
import logging
from typing import Dict
from homeassistant.components.device_tracker import SOURCE_TYPE_GPS
from homeassistant.components.device_tracker.config_entry import TrackerEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_USERNAME
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.typing import HomeAssistantType
@ -26,13 +28,15 @@ async def async_setup_scanner(
pass
async def async_setup_entry(hass: HomeAssistantType, entry, async_add_entities):
async def async_setup_entry(
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities
):
"""Configure a dispatcher connection based on a config entry."""
username = entry.data[CONF_USERNAME]
for device in hass.data[DOMAIN][username].devices.values():
if device.location is None:
_LOGGER.debug("No position found for device %s", device.name)
_LOGGER.debug("No position found for %s", device.name)
continue
_LOGGER.debug("Adding device_tracker for %s", device.name)
@ -49,12 +53,12 @@ class IcloudTrackerEntity(TrackerEntity):
self._unsub_dispatcher = None
@property
def unique_id(self):
def unique_id(self) -> str:
"""Return a unique ID."""
return f"{self._device.unique_id}_tracker"
return self._device.unique_id
@property
def name(self):
def name(self) -> str:
"""Return the name of the device."""
return self._device.name
@ -74,36 +78,36 @@ class IcloudTrackerEntity(TrackerEntity):
return self._device.location[DEVICE_LOCATION_LONGITUDE]
@property
def should_poll(self):
def should_poll(self) -> bool:
"""No polling needed."""
return False
@property
def battery_level(self):
def battery_level(self) -> int:
"""Return the battery level of the device."""
return self._device.battery_level
@property
def source_type(self):
def source_type(self) -> str:
"""Return the source type, eg gps or router, of the device."""
return SOURCE_TYPE_GPS
@property
def icon(self):
def icon(self) -> str:
"""Return the icon."""
return icon_for_icloud_device(self._device)
@property
def device_state_attributes(self):
def device_state_attributes(self) -> Dict[str, any]:
"""Return the device state attributes."""
return self._device.state_attributes
@property
def device_info(self):
def device_info(self) -> Dict[str, any]:
"""Return the device information."""
return {
"identifiers": {(DOMAIN, self.unique_id)},
"name": self.name,
"identifiers": {(DOMAIN, self._device.unique_id)},
"name": self._device.name,
"manufacturer": "Apple",
"model": self._device.device_model,
}

View File

@ -0,0 +1,85 @@
"""Support for iCloud sensors."""
import logging
from typing import Dict
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_USERNAME, DEVICE_CLASS_BATTERY
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.icon import icon_for_battery_level
from homeassistant.helpers.typing import HomeAssistantType
from . import IcloudDevice
from .const import DOMAIN
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities
) -> None:
"""Set up iCloud devices sensors based on a config entry."""
username = entry.data[CONF_USERNAME]
entities = []
for device in hass.data[DOMAIN][username].devices.values():
if device.battery_level is not None:
_LOGGER.debug("Adding battery sensor for %s", device.name)
entities.append(IcloudDeviceBatterySensor(device))
async_add_entities(entities, True)
class IcloudDeviceBatterySensor(Entity):
"""Representation of a iCloud device battery sensor."""
def __init__(self, device: IcloudDevice):
"""Initialize the battery sensor."""
self._device = device
@property
def unique_id(self) -> str:
"""Return a unique ID."""
return f"{self._device.unique_id}_battery"
@property
def name(self) -> str:
"""Sensor name."""
return f"{self._device.name} battery state"
@property
def device_class(self) -> str:
"""Return the device class of the sensor."""
return DEVICE_CLASS_BATTERY
@property
def state(self) -> int:
"""Battery state percentage."""
return self._device.battery_level
@property
def unit_of_measurement(self) -> str:
"""Battery state measured in percentage."""
return "%"
@property
def icon(self) -> str:
"""Battery state icon handling."""
return icon_for_battery_level(
battery_level=self._device.battery_level,
charging=self._device.battery_status == "Charging",
)
@property
def device_state_attributes(self) -> Dict[str, any]:
"""Return default attributes for the iCloud device entity."""
return self._device.state_attributes
@property
def device_info(self) -> Dict[str, any]:
"""Return the device information."""
return {
"identifiers": {(DOMAIN, self._device.unique_id)},
"name": self._device.name,
"manufacturer": "Apple",
"model": self._device.device_model,
}