Skip to content

Commit ae1bedd

Browse files
authored
Add uptime ratio and avg. response time sensors to Uptime Kuma (home-assistant#162785)
1 parent 90b67f9 commit ae1bedd

6 files changed

Lines changed: 1351 additions & 231 deletions

File tree

homeassistant/components/uptime_kuma/icons.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
{
22
"entity": {
33
"sensor": {
4+
"avg_response_time_1d": {
5+
"default": "mdi:timeline-clock-outline"
6+
},
7+
"avg_response_time_30d": {
8+
"default": "mdi:timeline-clock-outline"
9+
},
10+
"avg_response_time_365d": {
11+
"default": "mdi:timeline-clock-outline"
12+
},
413
"cert_days_remaining": {
514
"default": "mdi:certificate"
615
},
@@ -24,6 +33,15 @@
2433
"type": {
2534
"default": "mdi:protocol"
2635
},
36+
"uptime_1d": {
37+
"default": "mdi:history"
38+
},
39+
"uptime_30d": {
40+
"default": "mdi:history"
41+
},
42+
"uptime_365d": {
43+
"default": "mdi:history"
44+
},
2745
"url": {
2846
"default": "mdi:web"
2947
}

homeassistant/components/uptime_kuma/sensor.py

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
SensorEntity,
1515
SensorEntityDescription,
1616
)
17-
from homeassistant.const import CONF_URL, EntityCategory, UnitOfTime
17+
from homeassistant.const import CONF_URL, PERCENTAGE, EntityCategory, UnitOfTime
1818
from homeassistant.core import HomeAssistant, callback
1919
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
2020
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
@@ -37,6 +37,12 @@ class UptimeKumaSensor(StrEnum):
3737
URL = "url"
3838
HOSTNAME = "hostname"
3939
PORT = "port"
40+
UPTIME_RATIO_1D = "uptime_1d"
41+
UPTIME_RATIO_30D = "uptime_30d"
42+
UPTIME_RATIO_365D = "uptime_365d"
43+
AVG_RESPONSE_TIME_1D = "avg_response_time_1d"
44+
AVG_RESPONSE_TIME_30D = "avg_response_time_30d"
45+
AVG_RESPONSE_TIME_365D = "avg_response_time_365d"
4046

4147

4248
@dataclass(kw_only=True, frozen=True)
@@ -104,6 +110,76 @@ class UptimeKumaSensorEntityDescription(SensorEntityDescription):
104110
value_fn=lambda m: m.monitor_port,
105111
create_entity=lambda t: t in HAS_PORT,
106112
),
113+
UptimeKumaSensorEntityDescription(
114+
key=UptimeKumaSensor.PORT,
115+
translation_key=UptimeKumaSensor.PORT,
116+
entity_category=EntityCategory.DIAGNOSTIC,
117+
value_fn=lambda m: m.monitor_port,
118+
create_entity=lambda t: t in HAS_PORT,
119+
),
120+
UptimeKumaSensorEntityDescription(
121+
key=UptimeKumaSensor.UPTIME_RATIO_1D,
122+
translation_key=UptimeKumaSensor.UPTIME_RATIO_1D,
123+
value_fn=lambda m: (
124+
m.monitor_uptime_ratio_1d * 100
125+
if m.monitor_uptime_ratio_1d is not None
126+
else None
127+
),
128+
native_unit_of_measurement=PERCENTAGE,
129+
suggested_display_precision=2,
130+
create_entity=lambda t: True,
131+
),
132+
UptimeKumaSensorEntityDescription(
133+
key=UptimeKumaSensor.UPTIME_RATIO_30D,
134+
translation_key=UptimeKumaSensor.UPTIME_RATIO_30D,
135+
value_fn=lambda m: (
136+
m.monitor_uptime_ratio_30d * 100
137+
if m.monitor_uptime_ratio_30d is not None
138+
else None
139+
),
140+
native_unit_of_measurement=PERCENTAGE,
141+
suggested_display_precision=2,
142+
create_entity=lambda t: True,
143+
),
144+
UptimeKumaSensorEntityDescription(
145+
key=UptimeKumaSensor.UPTIME_RATIO_365D,
146+
translation_key=UptimeKumaSensor.UPTIME_RATIO_365D,
147+
value_fn=lambda m: (
148+
m.monitor_uptime_ratio_365d * 100
149+
if m.monitor_uptime_ratio_365d is not None
150+
else None
151+
),
152+
native_unit_of_measurement=PERCENTAGE,
153+
suggested_display_precision=2,
154+
create_entity=lambda t: True,
155+
),
156+
UptimeKumaSensorEntityDescription(
157+
key=UptimeKumaSensor.AVG_RESPONSE_TIME_1D,
158+
translation_key=UptimeKumaSensor.AVG_RESPONSE_TIME_1D,
159+
value_fn=lambda m: m.monitor_response_time_seconds_1d,
160+
device_class=SensorDeviceClass.DURATION,
161+
native_unit_of_measurement=UnitOfTime.SECONDS,
162+
suggested_unit_of_measurement=UnitOfTime.MILLISECONDS,
163+
create_entity=lambda t: True,
164+
),
165+
UptimeKumaSensorEntityDescription(
166+
key=UptimeKumaSensor.AVG_RESPONSE_TIME_30D,
167+
translation_key=UptimeKumaSensor.AVG_RESPONSE_TIME_30D,
168+
value_fn=lambda m: m.monitor_response_time_seconds_30d,
169+
device_class=SensorDeviceClass.DURATION,
170+
native_unit_of_measurement=UnitOfTime.SECONDS,
171+
suggested_unit_of_measurement=UnitOfTime.MILLISECONDS,
172+
create_entity=lambda t: True,
173+
),
174+
UptimeKumaSensorEntityDescription(
175+
key=UptimeKumaSensor.AVG_RESPONSE_TIME_365D,
176+
translation_key=UptimeKumaSensor.AVG_RESPONSE_TIME_365D,
177+
value_fn=lambda m: m.monitor_response_time_seconds_365d,
178+
device_class=SensorDeviceClass.DURATION,
179+
native_unit_of_measurement=UnitOfTime.SECONDS,
180+
suggested_unit_of_measurement=UnitOfTime.MILLISECONDS,
181+
create_entity=lambda t: True,
182+
),
107183
)
108184

109185

homeassistant/components/uptime_kuma/strings.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@
6161
},
6262
"entity": {
6363
"sensor": {
64+
"avg_response_time_1d": {
65+
"name": "Response time Ø (1 day)"
66+
},
67+
"avg_response_time_30d": {
68+
"name": "Response time Ø (30 days)"
69+
},
70+
"avg_response_time_365d": {
71+
"name": "Response time Ø (365 days)"
72+
},
6473
"cert_days_remaining": {
6574
"name": "Certificate expiry"
6675
},
@@ -117,6 +126,15 @@
117126
"websocket_upgrade": "WebSocket-Upgrade"
118127
}
119128
},
129+
"uptime_1d": {
130+
"name": "Uptime (1 day)"
131+
},
132+
"uptime_30d": {
133+
"name": "Uptime (30 days)"
134+
},
135+
"uptime_365d": {
136+
"name": "Uptime (365 days)"
137+
},
120138
"url": {
121139
"name": "Monitored URL"
122140
}

tests/components/uptime_kuma/conftest.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,38 +56,56 @@ def mock_pythonkuma() -> Generator[AsyncMock]:
5656
monitor_1 = UptimeKumaMonitor(
5757
monitor_id=1,
5858
monitor_cert_days_remaining=90,
59-
monitor_cert_is_valid=1,
59+
monitor_cert_is_valid=True,
6060
monitor_hostname=None,
6161
monitor_name="Monitor 1",
6262
monitor_port=None,
6363
monitor_response_time=120,
6464
monitor_status=MonitorStatus.UP,
6565
monitor_type=MonitorType.HTTP,
6666
monitor_url="https://example.org",
67+
monitor_uptime_ratio_1d=1,
68+
monitor_uptime_ratio_30d=0.9993369956431142,
69+
monitor_uptime_ratio_365d=0.9941977428851816,
70+
monitor_response_time_seconds_1d=0.10920649819494585,
71+
monitor_response_time_seconds_30d=0.0993296843901052,
72+
monitor_response_time_seconds_365d=0.1043971646081903,
6773
)
6874
monitor_2 = UptimeKumaMonitor(
6975
monitor_id=2,
7076
monitor_cert_days_remaining=0,
71-
monitor_cert_is_valid=0,
77+
monitor_cert_is_valid=False,
7278
monitor_hostname=None,
7379
monitor_name="Monitor 2",
7480
monitor_port=None,
7581
monitor_response_time=28,
7682
monitor_status=MonitorStatus.UP,
7783
monitor_type=MonitorType.PORT,
7884
monitor_url=None,
85+
monitor_uptime_ratio_1d=0.9992223950233281,
86+
monitor_uptime_ratio_30d=0.9990979870869731,
87+
monitor_uptime_ratio_365d=0.9994612200915926,
88+
monitor_response_time_seconds_1d=0.16390272373540857,
89+
monitor_response_time_seconds_30d=0.3371273224043715,
90+
monitor_response_time_seconds_365d=0.34270098747886596,
7991
)
8092
monitor_3 = UptimeKumaMonitor(
8193
monitor_id=3,
8294
monitor_cert_days_remaining=90,
83-
monitor_cert_is_valid=1,
95+
monitor_cert_is_valid=True,
8496
monitor_hostname=None,
8597
monitor_name="Monitor 3",
8698
monitor_port=None,
8799
monitor_response_time=120,
88100
monitor_status=MonitorStatus.DOWN,
89101
monitor_type=MonitorType.JSON_QUERY,
90102
monitor_url="https://down.example.org",
103+
monitor_uptime_ratio_1d=None,
104+
monitor_uptime_ratio_30d=None,
105+
monitor_uptime_ratio_365d=None,
106+
monitor_response_time_seconds_1d=None,
107+
monitor_response_time_seconds_30d=None,
108+
monitor_response_time_seconds_365d=None,
91109
)
92110

93111
with (

tests/components/uptime_kuma/snapshots/test_diagnostics.ambr

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,43 @@
33
dict({
44
'1': dict({
55
'monitor_cert_days_remaining': 90,
6-
'monitor_cert_is_valid': 1,
6+
'monitor_cert_is_valid': True,
77
'monitor_hostname': None,
88
'monitor_id': 1,
99
'monitor_name': 'Monitor 1',
1010
'monitor_port': None,
1111
'monitor_response_time': 120,
12-
'monitor_response_time_seconds_1d': None,
13-
'monitor_response_time_seconds_30d': None,
14-
'monitor_response_time_seconds_365d': None,
12+
'monitor_response_time_seconds_1d': 0.10920649819494585,
13+
'monitor_response_time_seconds_30d': 0.0993296843901052,
14+
'monitor_response_time_seconds_365d': 0.1043971646081903,
1515
'monitor_status': 1,
1616
'monitor_type': 'http',
17-
'monitor_uptime_ratio_1d': None,
18-
'monitor_uptime_ratio_30d': None,
19-
'monitor_uptime_ratio_365d': None,
17+
'monitor_uptime_ratio_1d': 1,
18+
'monitor_uptime_ratio_30d': 0.9993369956431142,
19+
'monitor_uptime_ratio_365d': 0.9941977428851816,
2020
'monitor_url': '**REDACTED**',
2121
}),
2222
'2': dict({
2323
'monitor_cert_days_remaining': 0,
24-
'monitor_cert_is_valid': 0,
24+
'monitor_cert_is_valid': False,
2525
'monitor_hostname': None,
2626
'monitor_id': 2,
2727
'monitor_name': 'Monitor 2',
2828
'monitor_port': None,
2929
'monitor_response_time': 28,
30-
'monitor_response_time_seconds_1d': None,
31-
'monitor_response_time_seconds_30d': None,
32-
'monitor_response_time_seconds_365d': None,
30+
'monitor_response_time_seconds_1d': 0.16390272373540857,
31+
'monitor_response_time_seconds_30d': 0.3371273224043715,
32+
'monitor_response_time_seconds_365d': 0.34270098747886596,
3333
'monitor_status': 1,
3434
'monitor_type': 'port',
35-
'monitor_uptime_ratio_1d': None,
36-
'monitor_uptime_ratio_30d': None,
37-
'monitor_uptime_ratio_365d': None,
35+
'monitor_uptime_ratio_1d': 0.9992223950233281,
36+
'monitor_uptime_ratio_30d': 0.9990979870869731,
37+
'monitor_uptime_ratio_365d': 0.9994612200915926,
3838
'monitor_url': None,
3939
}),
4040
'3': dict({
4141
'monitor_cert_days_remaining': 90,
42-
'monitor_cert_is_valid': 1,
42+
'monitor_cert_is_valid': True,
4343
'monitor_hostname': None,
4444
'monitor_id': 3,
4545
'monitor_name': 'Monitor 3',

0 commit comments

Comments
 (0)