1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-15 07:36:16 +00:00

Add uptime ratio and avg. response time sensors to Uptime Kuma (#162785)

This commit is contained in:
Manu
2026-02-11 22:09:21 +01:00
committed by GitHub
parent 90b67f90fa
commit ae1bedd94a
6 changed files with 1139 additions and 19 deletions

View File

@@ -1,6 +1,15 @@
{
"entity": {
"sensor": {
"avg_response_time_1d": {
"default": "mdi:timeline-clock-outline"
},
"avg_response_time_30d": {
"default": "mdi:timeline-clock-outline"
},
"avg_response_time_365d": {
"default": "mdi:timeline-clock-outline"
},
"cert_days_remaining": {
"default": "mdi:certificate"
},
@@ -24,6 +33,15 @@
"type": {
"default": "mdi:protocol"
},
"uptime_1d": {
"default": "mdi:history"
},
"uptime_30d": {
"default": "mdi:history"
},
"uptime_365d": {
"default": "mdi:history"
},
"url": {
"default": "mdi:web"
}

View File

@@ -14,7 +14,7 @@ from homeassistant.components.sensor import (
SensorEntity,
SensorEntityDescription,
)
from homeassistant.const import CONF_URL, EntityCategory, UnitOfTime
from homeassistant.const import CONF_URL, PERCENTAGE, EntityCategory, UnitOfTime
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
@@ -37,6 +37,12 @@ class UptimeKumaSensor(StrEnum):
URL = "url"
HOSTNAME = "hostname"
PORT = "port"
UPTIME_RATIO_1D = "uptime_1d"
UPTIME_RATIO_30D = "uptime_30d"
UPTIME_RATIO_365D = "uptime_365d"
AVG_RESPONSE_TIME_1D = "avg_response_time_1d"
AVG_RESPONSE_TIME_30D = "avg_response_time_30d"
AVG_RESPONSE_TIME_365D = "avg_response_time_365d"
@dataclass(kw_only=True, frozen=True)
@@ -104,6 +110,76 @@ SENSOR_DESCRIPTIONS: tuple[UptimeKumaSensorEntityDescription, ...] = (
value_fn=lambda m: m.monitor_port,
create_entity=lambda t: t in HAS_PORT,
),
UptimeKumaSensorEntityDescription(
key=UptimeKumaSensor.PORT,
translation_key=UptimeKumaSensor.PORT,
entity_category=EntityCategory.DIAGNOSTIC,
value_fn=lambda m: m.monitor_port,
create_entity=lambda t: t in HAS_PORT,
),
UptimeKumaSensorEntityDescription(
key=UptimeKumaSensor.UPTIME_RATIO_1D,
translation_key=UptimeKumaSensor.UPTIME_RATIO_1D,
value_fn=lambda m: (
m.monitor_uptime_ratio_1d * 100
if m.monitor_uptime_ratio_1d is not None
else None
),
native_unit_of_measurement=PERCENTAGE,
suggested_display_precision=2,
create_entity=lambda t: True,
),
UptimeKumaSensorEntityDescription(
key=UptimeKumaSensor.UPTIME_RATIO_30D,
translation_key=UptimeKumaSensor.UPTIME_RATIO_30D,
value_fn=lambda m: (
m.monitor_uptime_ratio_30d * 100
if m.monitor_uptime_ratio_30d is not None
else None
),
native_unit_of_measurement=PERCENTAGE,
suggested_display_precision=2,
create_entity=lambda t: True,
),
UptimeKumaSensorEntityDescription(
key=UptimeKumaSensor.UPTIME_RATIO_365D,
translation_key=UptimeKumaSensor.UPTIME_RATIO_365D,
value_fn=lambda m: (
m.monitor_uptime_ratio_365d * 100
if m.monitor_uptime_ratio_365d is not None
else None
),
native_unit_of_measurement=PERCENTAGE,
suggested_display_precision=2,
create_entity=lambda t: True,
),
UptimeKumaSensorEntityDescription(
key=UptimeKumaSensor.AVG_RESPONSE_TIME_1D,
translation_key=UptimeKumaSensor.AVG_RESPONSE_TIME_1D,
value_fn=lambda m: m.monitor_response_time_seconds_1d,
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.MILLISECONDS,
create_entity=lambda t: True,
),
UptimeKumaSensorEntityDescription(
key=UptimeKumaSensor.AVG_RESPONSE_TIME_30D,
translation_key=UptimeKumaSensor.AVG_RESPONSE_TIME_30D,
value_fn=lambda m: m.monitor_response_time_seconds_30d,
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.MILLISECONDS,
create_entity=lambda t: True,
),
UptimeKumaSensorEntityDescription(
key=UptimeKumaSensor.AVG_RESPONSE_TIME_365D,
translation_key=UptimeKumaSensor.AVG_RESPONSE_TIME_365D,
value_fn=lambda m: m.monitor_response_time_seconds_365d,
device_class=SensorDeviceClass.DURATION,
native_unit_of_measurement=UnitOfTime.SECONDS,
suggested_unit_of_measurement=UnitOfTime.MILLISECONDS,
create_entity=lambda t: True,
),
)

View File

@@ -61,6 +61,15 @@
},
"entity": {
"sensor": {
"avg_response_time_1d": {
"name": "Response time Ø (1 day)"
},
"avg_response_time_30d": {
"name": "Response time Ø (30 days)"
},
"avg_response_time_365d": {
"name": "Response time Ø (365 days)"
},
"cert_days_remaining": {
"name": "Certificate expiry"
},
@@ -117,6 +126,15 @@
"websocket_upgrade": "WebSocket-Upgrade"
}
},
"uptime_1d": {
"name": "Uptime (1 day)"
},
"uptime_30d": {
"name": "Uptime (30 days)"
},
"uptime_365d": {
"name": "Uptime (365 days)"
},
"url": {
"name": "Monitored URL"
}

View File

@@ -56,7 +56,7 @@ def mock_pythonkuma() -> Generator[AsyncMock]:
monitor_1 = UptimeKumaMonitor(
monitor_id=1,
monitor_cert_days_remaining=90,
monitor_cert_is_valid=1,
monitor_cert_is_valid=True,
monitor_hostname=None,
monitor_name="Monitor 1",
monitor_port=None,
@@ -64,11 +64,17 @@ def mock_pythonkuma() -> Generator[AsyncMock]:
monitor_status=MonitorStatus.UP,
monitor_type=MonitorType.HTTP,
monitor_url="https://example.org",
monitor_uptime_ratio_1d=1,
monitor_uptime_ratio_30d=0.9993369956431142,
monitor_uptime_ratio_365d=0.9941977428851816,
monitor_response_time_seconds_1d=0.10920649819494585,
monitor_response_time_seconds_30d=0.0993296843901052,
monitor_response_time_seconds_365d=0.1043971646081903,
)
monitor_2 = UptimeKumaMonitor(
monitor_id=2,
monitor_cert_days_remaining=0,
monitor_cert_is_valid=0,
monitor_cert_is_valid=False,
monitor_hostname=None,
monitor_name="Monitor 2",
monitor_port=None,
@@ -76,11 +82,17 @@ def mock_pythonkuma() -> Generator[AsyncMock]:
monitor_status=MonitorStatus.UP,
monitor_type=MonitorType.PORT,
monitor_url=None,
monitor_uptime_ratio_1d=0.9992223950233281,
monitor_uptime_ratio_30d=0.9990979870869731,
monitor_uptime_ratio_365d=0.9994612200915926,
monitor_response_time_seconds_1d=0.16390272373540857,
monitor_response_time_seconds_30d=0.3371273224043715,
monitor_response_time_seconds_365d=0.34270098747886596,
)
monitor_3 = UptimeKumaMonitor(
monitor_id=3,
monitor_cert_days_remaining=90,
monitor_cert_is_valid=1,
monitor_cert_is_valid=True,
monitor_hostname=None,
monitor_name="Monitor 3",
monitor_port=None,
@@ -88,6 +100,12 @@ def mock_pythonkuma() -> Generator[AsyncMock]:
monitor_status=MonitorStatus.DOWN,
monitor_type=MonitorType.JSON_QUERY,
monitor_url="https://down.example.org",
monitor_uptime_ratio_1d=None,
monitor_uptime_ratio_30d=None,
monitor_uptime_ratio_365d=None,
monitor_response_time_seconds_1d=None,
monitor_response_time_seconds_30d=None,
monitor_response_time_seconds_365d=None,
)
with (

View File

@@ -3,43 +3,43 @@
dict({
'1': dict({
'monitor_cert_days_remaining': 90,
'monitor_cert_is_valid': 1,
'monitor_cert_is_valid': True,
'monitor_hostname': None,
'monitor_id': 1,
'monitor_name': 'Monitor 1',
'monitor_port': None,
'monitor_response_time': 120,
'monitor_response_time_seconds_1d': None,
'monitor_response_time_seconds_30d': None,
'monitor_response_time_seconds_365d': None,
'monitor_response_time_seconds_1d': 0.10920649819494585,
'monitor_response_time_seconds_30d': 0.0993296843901052,
'monitor_response_time_seconds_365d': 0.1043971646081903,
'monitor_status': 1,
'monitor_type': 'http',
'monitor_uptime_ratio_1d': None,
'monitor_uptime_ratio_30d': None,
'monitor_uptime_ratio_365d': None,
'monitor_uptime_ratio_1d': 1,
'monitor_uptime_ratio_30d': 0.9993369956431142,
'monitor_uptime_ratio_365d': 0.9941977428851816,
'monitor_url': '**REDACTED**',
}),
'2': dict({
'monitor_cert_days_remaining': 0,
'monitor_cert_is_valid': 0,
'monitor_cert_is_valid': False,
'monitor_hostname': None,
'monitor_id': 2,
'monitor_name': 'Monitor 2',
'monitor_port': None,
'monitor_response_time': 28,
'monitor_response_time_seconds_1d': None,
'monitor_response_time_seconds_30d': None,
'monitor_response_time_seconds_365d': None,
'monitor_response_time_seconds_1d': 0.16390272373540857,
'monitor_response_time_seconds_30d': 0.3371273224043715,
'monitor_response_time_seconds_365d': 0.34270098747886596,
'monitor_status': 1,
'monitor_type': 'port',
'monitor_uptime_ratio_1d': None,
'monitor_uptime_ratio_30d': None,
'monitor_uptime_ratio_365d': None,
'monitor_uptime_ratio_1d': 0.9992223950233281,
'monitor_uptime_ratio_30d': 0.9990979870869731,
'monitor_uptime_ratio_365d': 0.9994612200915926,
'monitor_url': None,
}),
'3': dict({
'monitor_cert_days_remaining': 90,
'monitor_cert_is_valid': 1,
'monitor_cert_is_valid': True,
'monitor_hostname': None,
'monitor_id': 3,
'monitor_name': 'Monitor 3',

File diff suppressed because it is too large Load Diff