Skip to content

Commit

Permalink
Add battery sensor to iCloud (#29818)
Browse files Browse the repository at this point in the history
* Add battery sensor to iCloud

* Update .coveragerc

* Review: @balloob & @MartinHjelmare

* Review: use f string
  • Loading branch information
Quentame authored and MartinHjelmare committed Dec 14, 2019
1 parent 003658a commit 8207809
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 20 deletions.
1 change: 1 addition & 0 deletions .coveragerc
Expand Up @@ -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
Expand Down
5 changes: 0 additions & 5 deletions homeassistant/components/icloud/__init__.py
Expand Up @@ -560,11 +560,6 @@ def unique_id(self) -> str:
"""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."""
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/icloud/const.py
Expand Up @@ -14,8 +14,7 @@
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"
Expand Down
30 changes: 17 additions & 13 deletions homeassistant/components/icloud/device_tracker.py
@@ -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
Expand All @@ -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)
Expand All @@ -49,12 +53,12 @@ def __init__(self, device: IcloudDevice):
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

Expand All @@ -74,36 +78,36 @@ def longitude(self):
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,
}
Expand Down
85 changes: 85 additions & 0 deletions homeassistant/components/icloud/sensor.py
@@ -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,
}

0 comments on commit 8207809

Please sign in to comment.