Added blood pressure sensors

This commit is contained in:
Ron Klinkien
2026-01-03 13:22:25 +01:00
parent 57fb7ecfcd
commit 28ad661ab7
7 changed files with 102 additions and 12 deletions

View File

@@ -93,6 +93,15 @@ Sensor values depend on your Garmin devices and connected apps.
| Hydration Goal | Target intake |
| Sweat Loss | Estimated fluid loss |
### Blood Pressure
| Sensor | Description |
|--------|-------------|
| Systolic | Systolic blood pressure (mmHg) |
| Diastolic | Diastolic blood pressure (mmHg) |
| Pulse | Pulse from blood pressure reading (bpm) |
| Measurement Time | When the BP was measured |
### Health Monitoring
| Sensor | Description |

View File

@@ -99,8 +99,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
# Register integration-level services (only once for first entry)
if len(hass.config_entries.async_entries(DOMAIN)) == 1:
# Register integration-level services (only once)
if not hass.services.has_service(DOMAIN, "add_body_composition"):
await async_setup_services(hass)
return True
@@ -112,8 +112,9 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
# Unload services only if this is the last entry
if unload_ok and len(hass.config_entries.async_entries(DOMAIN)) == 1:
# Unload services only if this is the last entry (no entries remaining after unload)
remaining_entries = len(hass.config_entries.async_entries(DOMAIN))
if unload_ok and remaining_entries == 1: # This entry is being unloaded
await async_unload_services(hass)
return bool(unload_ok)

View File

@@ -253,6 +253,41 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
self.api.get_hydration_data, today.isoformat()
)
# Fetch blood pressure data (last 30 days for latest reading)
blood_pressure_data = {}
try:
bp_response = await self.hass.async_add_executor_job(
self.api.get_blood_pressure,
(today - timedelta(days=30)).isoformat(),
today.isoformat(),
)
_LOGGER.debug(
"Blood pressure API response: type=%s",
type(bp_response).__name__,
)
# API returns dict with measurementSummaries containing measurements
if bp_response and isinstance(bp_response, dict):
summaries = bp_response.get("measurementSummaries", [])
if summaries:
# Get measurements from the most recent day
latest_summary = summaries[-1]
measurements = latest_summary.get("measurements", [])
if measurements:
latest_bp = measurements[-1]
blood_pressure_data = {
"bpSystolic": latest_bp.get("systolic"),
"bpDiastolic": latest_bp.get("diastolic"),
"bpPulse": latest_bp.get("pulse"),
"bpMeasurementTime": latest_bp.get(
"measurementTimestampLocal"
),
}
_LOGGER.debug(
"Blood pressure data parsed: %s", blood_pressure_data
)
except Exception as err:
_LOGGER.debug("Blood pressure data not available: %s", err)
except GarminConnectAuthenticationError as err:
raise ConfigEntryAuthFailed from err
except GarminConnectTooManyRequestsError:
@@ -367,6 +402,7 @@ class GarminConnectDataUpdateCoordinator(DataUpdateCoordinator):
**fitnessage_data,
**hydration_data,
**menstrual_data,
**blood_pressure_data,
}

View File

@@ -1071,6 +1071,38 @@ MENSTRUAL_CYCLE_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
),
)
# Blood Pressure Sensors
BLOOD_PRESSURE_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
GarminConnectSensorEntityDescription(
key="bpSystolic",
translation_key="bp_systolic",
native_unit_of_measurement="mmHg",
state_class=SensorStateClass.MEASUREMENT,
icon="mdi:heart-pulse",
),
GarminConnectSensorEntityDescription(
key="bpDiastolic",
translation_key="bp_diastolic",
native_unit_of_measurement="mmHg",
state_class=SensorStateClass.MEASUREMENT,
icon="mdi:heart-pulse",
),
GarminConnectSensorEntityDescription(
key="bpPulse",
translation_key="bp_pulse",
native_unit_of_measurement="bpm",
state_class=SensorStateClass.MEASUREMENT,
icon="mdi:heart",
),
GarminConnectSensorEntityDescription(
key="bpMeasurementTime",
translation_key="bp_measurement_time",
device_class=SensorDeviceClass.TIMESTAMP,
icon="mdi:clock-outline",
value_fn=lambda data: data.get("bpMeasurementTime"),
),
)
# Diagnostic Sensors
DIAGNOSTIC_SENSORS: tuple[GarminConnectSensorEntityDescription, ...] = (
GarminConnectSensorEntityDescription(
@@ -1103,6 +1135,7 @@ ALL_SENSOR_DESCRIPTIONS: tuple[GarminConnectSensorEntityDescription, ...] = (
*ADDITIONAL_DISTANCE_SENSORS,
*WELLNESS_SENSORS,
*MENSTRUAL_CYCLE_SENSORS,
*BLOOD_PRESSURE_SENSORS,
*DIAGNOSTIC_SENSORS,
)

View File

@@ -36,10 +36,6 @@ set_active_gear:
add_body_composition:
name: Add body composition
description: Add body composition metrics to Garmin Connect.
target:
entity:
integration: garmin_connect
domain: sensor
fields:
weight:
name: Weight
@@ -181,10 +177,6 @@ add_body_composition:
add_blood_pressure:
name: Add blood pressure
description: Add blood pressure measurement to Garmin Connect.
target:
entity:
integration: garmin_connect
domain: sensor
fields:
systolic:
name: Systolic

View File

@@ -379,6 +379,18 @@
"menstrual_period_length": {
"name": "Menstrual period length"
},
"bp_systolic": {
"name": "Blood pressure systolic"
},
"bp_diastolic": {
"name": "Blood pressure diastolic"
},
"bp_pulse": {
"name": "Blood pressure pulse"
},
"bp_measurement_time": {
"name": "Blood pressure measurement time"
},
"device_last_synced": {
"name": "Device last synced"
}

View File

@@ -83,6 +83,13 @@ This integration provides **110+ sensors** covering various health and fitness m
- **Hydration Goal** - Target intake
- **Sweat Loss** - Estimated fluid loss
### Blood Pressure
- **Systolic** - Systolic blood pressure (mmHg)
- **Diastolic** - Diastolic blood pressure (mmHg)
- **Pulse** - Pulse from blood pressure reading (bpm)
- **Measurement Time** - When the BP was measured
### Health Monitoring
- **SpO2** - Blood oxygen levels (average, lowest, latest)