add basic gear sensors

This commit is contained in:
Raimund Huber
2022-12-04 12:03:10 +01:00
parent 6a1b5240d7
commit cc6e0af4e5
3 changed files with 139 additions and 1 deletions

View File

@@ -1,6 +1,8 @@
"""The Garmin Connect integration."""
from datetime import date
import logging
import asyncio
from collections.abc import Awaitable
from garminconnect import (
Garmin,
@@ -97,6 +99,16 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
self._api.get_body_composition, date.today().isoformat()
)
alarms = await self.hass.async_add_executor_job(self._api.get_device_alarms)
gear = await self.hass.async_add_executor_job(
self._api.get_gear, summary["userProfileId"]
)
tasks: list[Awaitable] = [
self.hass.async_add_executor_job(
self._api.get_gear_stats, gear_item["uuid"]
)
for gear_item in gear
]
gear_stats = await asyncio.gather(*tasks)
except (
GarminConnectAuthenticationError,
GarminConnectTooManyRequestsError,
@@ -111,4 +123,6 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
**summary,
**body["totalAverage"],
"nextAlarm": alarms,
"gear": gear,
"gear_stats": gear_stats,
}

View File

@@ -354,3 +354,10 @@ GARMIN_ENTITY_LIST = {
"metabolicAge": ["Metabolic Age", TIME_YEARS, "mdi:calendar-heart", None, False],
"nextAlarm": ["Next Alarm Time", None, "mdi:alarm", None, True],
}
GEAR_ICONS = {
"Shoes": "mdi:shoe-sneaker",
"Bike": "mdi:bike",
"Other": "mdi:basketball",
"Golf Clubs": "mdi:golf",
}

View File

@@ -2,10 +2,16 @@
from __future__ import annotations
import logging
from operator import itemgetter
from homeassistant.components.sensor import SensorEntity, SensorStateClass
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_ATTRIBUTION, CONF_ID, DEVICE_CLASS_TIMESTAMP
from homeassistant.const import (
ATTR_ATTRIBUTION,
CONF_ID,
DEVICE_CLASS_TIMESTAMP,
LENGTH_KILOMETERS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import (
@@ -18,6 +24,7 @@ from .const import (
DATA_COORDINATOR,
DOMAIN as GARMIN_DOMAIN,
GARMIN_ENTITY_LIST,
GEAR_ICONS,
)
_LOGGER = logging.getLogger(__name__)
@@ -60,6 +67,19 @@ async def async_setup_entry(
)
)
for gear_item in coordinator.data["gear"]:
entities.append(
GarminConnectGearSensor(
coordinator,
unique_id,
gear_item["uuid"],
gear_item["gearTypeName"],
gear_item["displayName"],
None,
True,
)
)
async_add_entities(entities)
@@ -155,3 +175,100 @@ class GarminConnectSensor(CoordinatorEntity, SensorEntity):
and self.coordinator.data
and self._type in self.coordinator.data
)
class GarminConnectGearSensor(CoordinatorEntity, SensorEntity):
"""Representation of a Garmin Connect Sensor."""
def __init__(
self,
coordinator,
unique_id,
uuid,
sensor_type,
name,
device_class: None,
enabled_default: bool = True,
):
"""Initialize a Garmin Connect sensor."""
super().__init__(coordinator)
self._unique_id = unique_id
self._type = sensor_type
self._uuid = uuid
self._device_class = device_class
self._enabled_default = enabled_default
self._attr_name = name
self._attr_device_class = self._device_class
self._attr_icon = GEAR_ICONS[sensor_type]
self._attr_native_unit_of_measurement = LENGTH_KILOMETERS
self._attr_unique_id = f"{self._unique_id}_{self._uuid}"
self._attr_state_class = SensorStateClass.TOTAL
@property
def native_value(self):
"""Return the state of the sensor."""
if not self.coordinator.data or not self.get_stats():
return None
value = self.get_stats()["totalDistance"]
return round(value / 1000, 2)
@property
def extra_state_attributes(self):
"""Return attributes for sensor."""
gear = self.get_gear()
stats = self.get_stats()
if not self.coordinator.data or not gear or not stats:
return {}
attributes = {
"last_synced": self.coordinator.data["lastSyncTimestampGMT"],
"total_activities": stats["totalActivities"],
"create_date": stats["createDate"],
"update_date": stats["updateDate"],
"date_begin": gear["dateBegin"],
"date_end": gear["dateEnd"],
"gear_make_name": gear["gearMakeName"],
"gear_model_name": gear["gearModelName"],
"gear_status_name": gear["gearStatusName"],
"custom_make_model": gear["customMakeModel"],
"maximum_meters": gear["maximumMeters"],
}
return attributes
@property
def device_info(self) -> DeviceInfo:
"""Return device information."""
return {
"identifiers": {(GARMIN_DOMAIN, self._unique_id)},
"name": "Garmin Connect",
"manufacturer": "Garmin Connect",
}
@property
def entity_registry_enabled_default(self) -> bool:
"""Return if the entity should be enabled when first added to the entity registry."""
return self._enabled_default
@property
def available(self) -> bool:
"""Return True if entity is available."""
return (
super().available
and self.coordinator.data
and self.get_gear()
# and any(g["uuid"] == self._uuid for g in self.coordinator.data["gear"])
)
def get_stats(self):
for gear_stats_item in self.coordinator.data["gear_stats"]:
if gear_stats_item["uuid"] == self._uuid:
return gear_stats_item
def get_gear(self):
for gear_item in self.coordinator.data["gear"]:
if gear_item["uuid"] == self._uuid:
return gear_item