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 @@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Comment thread
Quentame marked this conversation as resolved.

@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
Original file line number Diff line number Diff line change
@@ -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,
}