Skip to content

Commit 35c48ae

Browse files
committed
Add support for binary sensors
1 parent 18d43c5 commit 35c48ae

2 files changed

Lines changed: 143 additions & 6 deletions

File tree

README.md

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,47 @@ Tested against Home Asisstant 2025.8.3.
1010

1111
## Options
1212

13+
[Device class (binary sensor)]: https://www.home-assistant.io/integrations/binary_sensor/#device-class
14+
[Device class (sensor)]: https://www.home-assistant.io/integrations/sensor/#device-class
15+
[PromQL]: https://prometheus.io/docs/prometheus/latest/querying/basics/
16+
[State class]: https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes
17+
[Template]: https://www.home-assistant.io/docs/configuration/templating/
18+
[Unique ID]: https://www.home-assistant.io/faq/unique_id/
19+
20+
### Binary Sensor
21+
22+
| Name | Type | Default | Description |
23+
|---------------------|--------|----------|--------------------------------|
24+
| name | string | required | Friendly name |
25+
| expr | string | required | [PromQL] expression |
26+
| value_template | string | optional | [Template] |
27+
| unique_id | string | optional | [Unique ID] |
28+
| device_class | string | optional | [Device class (binary sensor)] |
29+
30+
### Sensor
31+
1332
| Name | Type | Default | Description |
1433
|---------------------|--------|----------|-------------------------|
1534
| name | string | required | Friendly name |
1635
| expr | string | required | [PromQL] expression |
1736
| unique_id | string | optional | [Unique ID] |
1837
| unit_of_measurement | string | optional | Unit of the measurement |
19-
| device_class | string | optional | [Device class] |
38+
| device_class | string | optional | [Device class (sensor)] |
2039
| state_class | string | optional | [State class] |
2140

22-
[PromQL]: https://prometheus.io/docs/prometheus/latest/querying/basics/
23-
[Unique ID]: https://www.home-assistant.io/faq/unique_id/
24-
[Device class]: https://www.home-assistant.io/integrations/sensor/#device-class
25-
[State class]: https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes
26-
2741
## Example usage
2842

2943
```yaml
44+
binary_sensor:
45+
- platform: prometheus_sensor
46+
url: http://localhost:9090
47+
queries:
48+
- name: Front Door
49+
unique_id: front_door_open
50+
expr: front_door_open
51+
value_template: "{{ value == 1 }}"
52+
device_class: door
53+
3054
sensor:
3155
- platform: prometheus_sensor
3256
url: http://localhost:9090
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"""Prometheus Binary Sensor component."""
2+
3+
from typing import TYPE_CHECKING, Final
4+
5+
import voluptuous as vol
6+
7+
from homeassistant.components.binary_sensor import (
8+
PLATFORM_SCHEMA as BINARY_SENSOR_PLATFORM_SCHEMA,
9+
BinarySensorDeviceClass,
10+
BinarySensorEntity,
11+
)
12+
from homeassistant.const import (
13+
CONF_DEVICE_CLASS,
14+
CONF_NAME,
15+
CONF_UNIQUE_ID,
16+
CONF_URL,
17+
CONF_VALUE_TEMPLATE,
18+
)
19+
from homeassistant.helpers.aiohttp_client import async_get_clientsession
20+
import homeassistant.helpers.config_validation as cv
21+
22+
if TYPE_CHECKING:
23+
from homeassistant.core import HomeAssistant
24+
from homeassistant.helpers.entity_platform import AddEntitiesCallback
25+
from homeassistant.helpers.template import Template
26+
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
27+
28+
from . import Prometheus, QueryResult
29+
30+
from .const import CONF_EXPR, CONF_QUERIES, DEFAULT_URL, SCAN_INTERVAL as SCAN_INTERVAL
31+
32+
_QUERY_SCHEMA: Final = vol.Schema(
33+
{
34+
vol.Required(CONF_NAME): cv.string,
35+
vol.Optional(CONF_UNIQUE_ID): cv.string,
36+
vol.Required(CONF_EXPR): cv.string,
37+
vol.Required(CONF_VALUE_TEMPLATE): cv.template,
38+
vol.Optional(CONF_DEVICE_CLASS): vol.Coerce(BinarySensorDeviceClass),
39+
}
40+
)
41+
42+
PLATFORM_SCHEMA: Final = BINARY_SENSOR_PLATFORM_SCHEMA.extend(
43+
{
44+
vol.Optional(CONF_URL, default=DEFAULT_URL): cv.string, # type: ignore
45+
vol.Required(CONF_QUERIES): [_QUERY_SCHEMA],
46+
}
47+
)
48+
49+
50+
async def async_setup_platform(
51+
hass: HomeAssistant,
52+
config: ConfigType,
53+
async_add_entities: AddEntitiesCallback,
54+
discovery_info: DiscoveryInfoType | None = None,
55+
):
56+
"""Set up the sensor platform."""
57+
session = async_get_clientsession(hass)
58+
url = config[CONF_URL]
59+
prometheus = Prometheus(url, session)
60+
61+
async_add_entities(
62+
new_entities=[
63+
PrometheusBinarySensor(
64+
prometheus=prometheus,
65+
unique_id=query.get(CONF_UNIQUE_ID),
66+
device_name=query[CONF_NAME],
67+
expression=query[CONF_EXPR],
68+
value_template=query.get(CONF_VALUE_TEMPLATE),
69+
device_class=query.get(CONF_DEVICE_CLASS),
70+
)
71+
for query in config[CONF_QUERIES]
72+
],
73+
update_before_add=True,
74+
)
75+
76+
77+
class PrometheusBinarySensor(BinarySensorEntity):
78+
"""Sensor entity representing the result of a PromQL expression."""
79+
80+
def __init__(
81+
self,
82+
*,
83+
prometheus: Prometheus,
84+
unique_id: str | None,
85+
device_name: str,
86+
expression: str,
87+
value_template: Template,
88+
device_class: BinarySensorDeviceClass | None,
89+
):
90+
"""Initialize the sensor."""
91+
self._prometheus: Prometheus = prometheus
92+
self._expression = expression
93+
self._value_template = value_template
94+
95+
self._attr_device_class = device_class
96+
self._attr_name = device_name
97+
self._attr_unique_id = unique_id
98+
99+
async def async_update(self) -> None:
100+
"""Update state by executing query."""
101+
result: QueryResult = await self._prometheus.query(self._expression)
102+
self._attr_available = result.error is None
103+
104+
render_result = (
105+
await self._value_template.async_render_with_possible_json_value(
106+
value=result.value, error_value=None
107+
)
108+
)
109+
110+
if render_result is not None:
111+
self._attr_is_on = bool(render_result)
112+
else:
113+
self._attr_is_on = None

0 commit comments

Comments
 (0)