Add support for covers in Prometheus metrics (#83763)

fixes undefined
This commit is contained in:
Matt Gerega 2022-12-27 05:25:33 -05:00 committed by GitHub
parent 5990bd7ca3
commit 2215adf5cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 173 additions and 0 deletions

View File

@ -16,6 +16,7 @@ from homeassistant.components.climate import (
ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_LOW,
HVACAction, HVACAction,
) )
from homeassistant.components.cover import ATTR_POSITION, ATTR_TILT_POSITION
from homeassistant.components.http import HomeAssistantView from homeassistant.components.http import HomeAssistantView
from homeassistant.components.humidifier import ATTR_AVAILABLE_MODES, ATTR_HUMIDITY from homeassistant.components.humidifier import ATTR_AVAILABLE_MODES, ATTR_HUMIDITY
from homeassistant.const import ( from homeassistant.const import (
@ -28,7 +29,11 @@ from homeassistant.const import (
CONTENT_TYPE_TEXT_PLAIN, CONTENT_TYPE_TEXT_PLAIN,
EVENT_STATE_CHANGED, EVENT_STATE_CHANGED,
PERCENTAGE, PERCENTAGE,
STATE_CLOSED,
STATE_CLOSING,
STATE_ON, STATE_ON,
STATE_OPEN,
STATE_OPENING,
STATE_UNAVAILABLE, STATE_UNAVAILABLE,
STATE_UNKNOWN, STATE_UNKNOWN,
UnitOfTemperature, UnitOfTemperature,
@ -371,6 +376,38 @@ class PrometheusMetrics:
value = self.state_as_number(state) value = self.state_as_number(state)
metric.labels(**self._labels(state)).set(value) metric.labels(**self._labels(state)).set(value)
def _handle_cover(self, state):
metric = self._metric(
"cover_state",
self.prometheus_cli.Gauge,
"State of the cover (0/1)",
["state"],
)
cover_states = [STATE_CLOSED, STATE_CLOSING, STATE_OPEN, STATE_OPENING]
for cover_state in cover_states:
metric.labels(**dict(self._labels(state), state=cover_state)).set(
float(cover_state == state.state)
)
position = state.attributes.get(ATTR_POSITION)
if position is not None:
position_metric = self._metric(
"cover_position",
self.prometheus_cli.Gauge,
"Position of the cover (0-100)",
)
position_metric.labels(**self._labels(state)).set(float(position))
tilt_position = state.attributes.get(ATTR_TILT_POSITION)
if tilt_position is not None:
tilt_position_metric = self._metric(
"cover_tilt_position",
self.prometheus_cli.Gauge,
"Tilt Position of the cover (0-100)",
)
tilt_position_metric.labels(**self._labels(state)).set(float(tilt_position))
def _handle_light(self, state): def _handle_light(self, state):
metric = self._metric( metric = self._metric(
"light_brightness_percent", "light_brightness_percent",

View File

@ -11,6 +11,7 @@ from homeassistant.components import (
binary_sensor, binary_sensor,
climate, climate,
counter, counter,
cover,
device_tracker, device_tracker,
humidifier, humidifier,
input_boolean, input_boolean,
@ -44,11 +45,15 @@ from homeassistant.const import (
ENERGY_KILO_WATT_HOUR, ENERGY_KILO_WATT_HOUR,
EVENT_STATE_CHANGED, EVENT_STATE_CHANGED,
PERCENTAGE, PERCENTAGE,
STATE_CLOSED,
STATE_CLOSING,
STATE_HOME, STATE_HOME,
STATE_LOCKED, STATE_LOCKED,
STATE_NOT_HOME, STATE_NOT_HOME,
STATE_OFF, STATE_OFF,
STATE_ON, STATE_ON,
STATE_OPEN,
STATE_OPENING,
STATE_UNLOCKED, STATE_UNLOCKED,
TEMP_CELSIUS, TEMP_CELSIUS,
TEMP_FAHRENHEIT, TEMP_FAHRENHEIT,
@ -445,6 +450,65 @@ async def test_lock(client, lock_entities):
) )
@pytest.mark.parametrize("namespace", [""])
async def test_cover(client, cover_entities):
"""Test prometheus metrics for cover."""
data = {**cover_entities}
body = await generate_latest_metrics(client)
open_covers = ["cover_open", "cover_position", "cover_tilt_position"]
for testcover in data:
open_metric = (
f'cover_state{{domain="cover",'
f'entity="{cover_entities[testcover].entity_id}",'
f'friendly_name="{cover_entities[testcover].original_name}",'
f'state="open"}} {1.0 if cover_entities[testcover].unique_id in open_covers else 0.0}'
)
assert open_metric in body
closed_metric = (
f'cover_state{{domain="cover",'
f'entity="{cover_entities[testcover].entity_id}",'
f'friendly_name="{cover_entities[testcover].original_name}",'
f'state="closed"}} {1.0 if cover_entities[testcover].unique_id == "cover_closed" else 0.0}'
)
assert closed_metric in body
opening_metric = (
f'cover_state{{domain="cover",'
f'entity="{cover_entities[testcover].entity_id}",'
f'friendly_name="{cover_entities[testcover].original_name}",'
f'state="opening"}} {1.0 if cover_entities[testcover].unique_id == "cover_opening" else 0.0}'
)
assert opening_metric in body
closing_metric = (
f'cover_state{{domain="cover",'
f'entity="{cover_entities[testcover].entity_id}",'
f'friendly_name="{cover_entities[testcover].original_name}",'
f'state="closing"}} {1.0 if cover_entities[testcover].unique_id == "cover_closing" else 0.0}'
)
assert closing_metric in body
if testcover == "cover_position":
position_metric = (
f'cover_position{{domain="cover",'
f'entity="{cover_entities[testcover].entity_id}",'
f'friendly_name="{cover_entities[testcover].original_name}"'
f"}} 50.0"
)
assert position_metric in body
if testcover == "cover_tilt_position":
tilt_position_metric = (
f'cover_tilt_position{{domain="cover",'
f'entity="{cover_entities[testcover].entity_id}",'
f'friendly_name="{cover_entities[testcover].original_name}"'
f"}} 50.0"
)
assert tilt_position_metric in body
@pytest.mark.parametrize("namespace", [""]) @pytest.mark.parametrize("namespace", [""])
async def test_counter(client, counter_entities): async def test_counter(client, counter_entities):
"""Test prometheus metrics for counter.""" """Test prometheus metrics for counter."""
@ -1110,6 +1174,78 @@ async def lock_fixture(hass, registry):
return data return data
@pytest.fixture(name="cover_entities")
async def cover_fixture(hass, registry):
"""Simulate cover entities."""
data = {}
cover_open = registry.async_get_or_create(
domain=cover.DOMAIN,
platform="test",
unique_id="cover_open",
suggested_object_id="open_shade",
original_name="Open Shade",
)
set_state_with_entry(hass, cover_open, STATE_OPEN)
data["cover_open"] = cover_open
cover_closed = registry.async_get_or_create(
domain=cover.DOMAIN,
platform="test",
unique_id="cover_closed",
suggested_object_id="closed_shade",
original_name="Closed Shade",
)
set_state_with_entry(hass, cover_closed, STATE_CLOSED)
data["cover_closed"] = cover_closed
cover_closing = registry.async_get_or_create(
domain=cover.DOMAIN,
platform="test",
unique_id="cover_closing",
suggested_object_id="closing_shade",
original_name="Closing Shade",
)
set_state_with_entry(hass, cover_closing, STATE_CLOSING)
data["cover_closing"] = cover_closing
cover_opening = registry.async_get_or_create(
domain=cover.DOMAIN,
platform="test",
unique_id="cover_opening",
suggested_object_id="opening_shade",
original_name="Opening Shade",
)
set_state_with_entry(hass, cover_opening, STATE_OPENING)
data["cover_opening"] = cover_opening
cover_position = registry.async_get_or_create(
domain=cover.DOMAIN,
platform="test",
unique_id="cover_position",
suggested_object_id="position_shade",
original_name="Position Shade",
)
cover_position_attributes = {cover.ATTR_POSITION: 50}
set_state_with_entry(hass, cover_position, STATE_OPEN, cover_position_attributes)
data["cover_position"] = cover_position
cover_tilt_position = registry.async_get_or_create(
domain=cover.DOMAIN,
platform="test",
unique_id="cover_tilt_position",
suggested_object_id="tilt_position_shade",
original_name="Tilt Position Shade",
)
cover_tilt_position_attributes = {cover.ATTR_TILT_POSITION: 50}
set_state_with_entry(
hass, cover_tilt_position, STATE_OPEN, cover_tilt_position_attributes
)
data["cover_tilt_position"] = cover_tilt_position
await hass.async_block_till_done()
return data
@pytest.fixture(name="input_number_entities") @pytest.fixture(name="input_number_entities")
async def input_number_fixture(hass, registry): async def input_number_fixture(hass, registry):
"""Simulate input_number entities.""" """Simulate input_number entities."""