mirror of
https://github.com/cyberjunky/home-assistant-garmin_connect.git
synced 2026-01-06 19:43:52 -05:00
Added User Points, User Level and Last Activity sensors
This commit is contained in:
@@ -90,6 +90,8 @@ Disabled by default:
|
||||
|
||||
```text
|
||||
Badges
|
||||
User Points
|
||||
User Level
|
||||
Consumed KiloCalories
|
||||
Remaining KiloCalories
|
||||
Net Remaining KiloCalories
|
||||
@@ -134,6 +136,8 @@ Muscle Mass
|
||||
Physique Rating
|
||||
Visceral Fat
|
||||
Metabolic Age
|
||||
Last Activities
|
||||
Last Activity
|
||||
```
|
||||
|
||||
## Screenshots
|
||||
|
||||
@@ -23,6 +23,7 @@ from .const import (
|
||||
DAY_TO_NUMBER,
|
||||
DEFAULT_UPDATE_INTERVAL,
|
||||
DOMAIN,
|
||||
LEVEL_POINTS,
|
||||
Gear,
|
||||
)
|
||||
|
||||
@@ -106,6 +107,7 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
gear_stats = {}
|
||||
gear_defaults = {}
|
||||
activity_types = {}
|
||||
last_activities = []
|
||||
sleep_data = {}
|
||||
sleep_score = None
|
||||
sleep_time_seconds = None
|
||||
@@ -116,41 +118,64 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
today = datetime.now(ZoneInfo(self.time_zone)).date()
|
||||
|
||||
try:
|
||||
# User summary
|
||||
summary = await self.hass.async_add_executor_job(
|
||||
self.api.get_user_summary, today.isoformat()
|
||||
)
|
||||
_LOGGER.debug("Summary data fetched: %s", summary)
|
||||
|
||||
# Body composition
|
||||
body = await self.hass.async_add_executor_job(
|
||||
self.api.get_body_composition, today.isoformat()
|
||||
)
|
||||
_LOGGER.debug("Body data fetched: %s", body)
|
||||
|
||||
activities = await self.hass.async_add_executor_job(
|
||||
# Last activities
|
||||
last_activities = await self.hass.async_add_executor_job(
|
||||
self.api.get_activities_by_date,
|
||||
(today - timedelta(days=7)).isoformat(),
|
||||
(today + timedelta(days=1)).isoformat(),
|
||||
)
|
||||
_LOGGER.debug("Activities data fetched: %s", activities)
|
||||
summary["lastActivities"] = activities
|
||||
_LOGGER.debug("Activities data fetched: %s", last_activities)
|
||||
summary["lastActivities"] = last_activities
|
||||
summary["lastActivity"] = last_activities[0] if last_activities else {}
|
||||
|
||||
# Badges
|
||||
badges = await self.hass.async_add_executor_job(self.api.get_earned_badges)
|
||||
_LOGGER.debug("Badges data fetched: %s", badges)
|
||||
summary["badges"] = badges
|
||||
|
||||
# Calculate user points and user level
|
||||
user_points = 0
|
||||
for badge in badges:
|
||||
user_points += badge["badgePoints"] * badge["badgeEarnedNumber"]
|
||||
|
||||
summary["userPoints"] = user_points
|
||||
|
||||
user_level = 0
|
||||
for level, points in LEVEL_POINTS.items():
|
||||
if user_points >= points:
|
||||
user_level = level
|
||||
|
||||
summary["userLevel"] = user_level
|
||||
|
||||
# Alarms
|
||||
alarms = await self.hass.async_add_executor_job(self.api.get_device_alarms)
|
||||
_LOGGER.debug("Alarms data fetched: %s", alarms)
|
||||
|
||||
next_alarms = calculate_next_active_alarms(alarms, self.time_zone)
|
||||
|
||||
# Activity types
|
||||
activity_types = await self.hass.async_add_executor_job(self.api.get_activity_types)
|
||||
_LOGGER.debug("Activity types data fetched: %s", activity_types)
|
||||
|
||||
# Sleep data
|
||||
sleep_data = await self.hass.async_add_executor_job(
|
||||
self.api.get_sleep_data, today.isoformat()
|
||||
)
|
||||
_LOGGER.debug("Sleep data fetched: %s", sleep_data)
|
||||
|
||||
# HRV data
|
||||
hrv_data = await self.hass.async_add_executor_job(
|
||||
self.api.get_hrv_data, today.isoformat()
|
||||
)
|
||||
@@ -164,6 +189,7 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
if not await self.async_login():
|
||||
raise UpdateFailed(error) from error
|
||||
|
||||
# Gear data
|
||||
try:
|
||||
gear = await self.hass.async_add_executor_job(
|
||||
self.api.get_gear, summary[Gear.USERPROFILE_ID]
|
||||
@@ -184,18 +210,21 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
except (KeyError, TypeError, ValueError, ConnectionError) as err:
|
||||
_LOGGER.debug("Gear data is not available: %s", err)
|
||||
|
||||
# Sleep score data
|
||||
try:
|
||||
sleep_score = sleep_data["dailySleepDTO"]["sleepScores"]["overall"]["value"]
|
||||
_LOGGER.debug("Sleep score data: %s", sleep_score)
|
||||
except KeyError:
|
||||
_LOGGER.debug("Sleep score data is not available")
|
||||
|
||||
# Sleep time seconds data
|
||||
try:
|
||||
sleep_time_seconds = sleep_data["dailySleepDTO"]["sleepTimeSeconds"]
|
||||
_LOGGER.debug("Sleep time seconds data: %s", sleep_time_seconds)
|
||||
except KeyError:
|
||||
_LOGGER.debug("Sleep time seconds data is not available")
|
||||
|
||||
# HRV data
|
||||
try:
|
||||
if hrv_data and "hrvSummary" in hrv_data:
|
||||
hrv_status = hrv_data["hrvSummary"]
|
||||
@@ -208,9 +237,9 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
|
||||
**body["totalAverage"],
|
||||
"nextAlarm": next_alarms,
|
||||
"gear": gear,
|
||||
"gear_stats": gear_stats,
|
||||
"activity_types": activity_types,
|
||||
"gear_defaults": gear_defaults,
|
||||
"gearStats": gear_stats,
|
||||
"activityTypes": activity_types,
|
||||
"gearDefaults": gear_defaults,
|
||||
"sleepScore": sleep_score,
|
||||
"sleepTimeSeconds": sleep_time_seconds,
|
||||
"hrvStatus": hrv_status,
|
||||
|
||||
@@ -622,7 +622,17 @@ GARMIN_ENTITY_LIST = {
|
||||
],
|
||||
"nextAlarm": ["Next Alarm Time", None, "mdi:alarm", SensorDeviceClass.TIMESTAMP, None, True],
|
||||
"lastActivities": ["Last Activities", None, "mdi:numeric", None, SensorStateClass.TOTAL, False],
|
||||
"lastActivity": ["Last Activity", None, "mdi:walk", None, None, False],
|
||||
"badges": ["Badges", None, "mdi:medal", None, SensorStateClass.TOTAL, False],
|
||||
"userPoints": ["User Points", None, "mdi:counter", None, SensorStateClass.TOTAL, False],
|
||||
"userLevel": [
|
||||
"User Level",
|
||||
None,
|
||||
"mdi:star-four-points-circle",
|
||||
None,
|
||||
SensorStateClass.TOTAL,
|
||||
False,
|
||||
],
|
||||
"sleepScore": [
|
||||
"Sleep Score",
|
||||
None,
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
"iot_class": "cloud_polling",
|
||||
"issue_tracker": "https://github.com/cyberjunky/home-assistant-garmin_connect/issues",
|
||||
"requirements": ["garminconnect>=0.2.24"],
|
||||
"version": "0.2.28"
|
||||
"version": "0.2.29"
|
||||
}
|
||||
|
||||
@@ -198,6 +198,9 @@ class GarminConnectSensor(CoordinatorEntity, SensorEntity):
|
||||
if self._type == "lastActivities" or self._type == "badges":
|
||||
value = len(self.coordinator.data[self._type])
|
||||
|
||||
if self._type == "lastActivity":
|
||||
value = self.coordinator.data[self._type]["activityName"]
|
||||
|
||||
elif self._type == "hrvStatus":
|
||||
value = self.coordinator.data[self._type]["status"].capitalize()
|
||||
|
||||
@@ -237,12 +240,15 @@ class GarminConnectSensor(CoordinatorEntity, SensorEntity):
|
||||
}
|
||||
|
||||
if self._type == "lastActivities":
|
||||
attributes["last_Activities"] = self.coordinator.data[self._type]
|
||||
attributes["last_activities"] = self.coordinator.data[self._type]
|
||||
|
||||
if self._type == "lastActivity":
|
||||
attributes = {**attributes, **self.coordinator.data[self._type]}
|
||||
|
||||
# Only show the last 10 badges for performance reasons
|
||||
if self._type == "badges":
|
||||
badges = self.coordinator.data.get(self._type, [])
|
||||
sorted_badges = sorted(badges, key=lambda x: x['badgeEarnedDate'])
|
||||
sorted_badges = sorted(badges, key=lambda x: x["badgeEarnedDate"])
|
||||
attributes["badges"] = sorted_badges[-10:]
|
||||
|
||||
if self._type == "nextAlarm":
|
||||
@@ -291,8 +297,7 @@ class GarminConnectSensor(CoordinatorEntity, SensorEntity):
|
||||
|
||||
"""Check for login."""
|
||||
if not await self.coordinator.async_login():
|
||||
raise IntegrationError(
|
||||
"Failed to login to Garmin Connect, unable to update")
|
||||
raise IntegrationError("Failed to login to Garmin Connect, unable to update")
|
||||
|
||||
"""Record a weigh in/body composition."""
|
||||
await self.hass.async_add_executor_job(
|
||||
@@ -322,8 +327,7 @@ class GarminConnectSensor(CoordinatorEntity, SensorEntity):
|
||||
|
||||
"""Check for login."""
|
||||
if not await self.coordinator.async_login():
|
||||
raise IntegrationError(
|
||||
"Failed to login to Garmin Connect, unable to update")
|
||||
raise IntegrationError("Failed to login to Garmin Connect, unable to update")
|
||||
|
||||
"""Record a blood pressure measurement."""
|
||||
await self.hass.async_add_executor_job(
|
||||
@@ -384,9 +388,8 @@ class GarminConnectGearSensor(CoordinatorEntity, SensorEntity):
|
||||
gear = self._gear()
|
||||
stats = self._stats()
|
||||
gear_defaults = self._gear_defaults()
|
||||
activity_types = self.coordinator.data["activity_types"]
|
||||
default_for_activity = self._activity_names_for_gear_defaults(
|
||||
gear_defaults, activity_types)
|
||||
activity_types = self.coordinator.data["activityTypes"]
|
||||
default_for_activity = self._activity_names_for_gear_defaults(gear_defaults, activity_types)
|
||||
|
||||
if not self.coordinator.data or not gear or not stats:
|
||||
return {}
|
||||
@@ -437,7 +440,7 @@ class GarminConnectGearSensor(CoordinatorEntity, SensorEntity):
|
||||
|
||||
def _stats(self):
|
||||
"""Get gear statistics from garmin"""
|
||||
for gear_stats_item in self.coordinator.data["gear_stats"]:
|
||||
for gear_stats_item in self.coordinator.data["gearStats"]:
|
||||
if gear_stats_item[Gear.UUID] == self._uuid:
|
||||
return gear_stats_item
|
||||
|
||||
@@ -452,7 +455,7 @@ class GarminConnectGearSensor(CoordinatorEntity, SensorEntity):
|
||||
return list(
|
||||
filter(
|
||||
lambda d: d[Gear.UUID] == self.uuid and d["defaultGear"] is True,
|
||||
self.coordinator.data["gear_defaults"],
|
||||
self.coordinator.data["gearDefaults"],
|
||||
)
|
||||
)
|
||||
|
||||
@@ -463,14 +466,13 @@ class GarminConnectGearSensor(CoordinatorEntity, SensorEntity):
|
||||
|
||||
"""Check for login."""
|
||||
if not await self.coordinator.async_login():
|
||||
raise IntegrationError(
|
||||
"Failed to login to Garmin Connect, unable to update")
|
||||
raise IntegrationError("Failed to login to Garmin Connect, unable to update")
|
||||
|
||||
"""Update Garmin Gear settings."""
|
||||
activity_type_id = next(
|
||||
filter(
|
||||
lambda a: a[Gear.TYPE_KEY] == activity_type,
|
||||
self.coordinator.data["activity_types"],
|
||||
self.coordinator.data["activityTypes"],
|
||||
)
|
||||
)[Gear.TYPE_ID]
|
||||
if setting != ServiceSetting.ONLY_THIS_AS_DEFAULT:
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
colorlog==6.9.0
|
||||
setuptools==75.8.0
|
||||
setuptools==75.8.0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# homeassistant==2024.4.1
|
||||
homeassistant==2025.1.2
|
||||
homeassistant==2025.1.2
|
||||
|
||||
Reference in New Issue
Block a user