Private GIT

Skip to content
Snippets Groups Projects
Commit 3ccd67dc authored by Sean Rees's avatar Sean Rees
Browse files

Update metric names to conform more closely to the Prometheus naming scheme[1]

parent 3272dd35
Branches
No related tags found
No related merge requests found
...@@ -4,37 +4,51 @@ Prometheus client for DysonLink fans (e.g; Pure Hot+Cool). ...@@ -4,37 +4,51 @@ Prometheus client for DysonLink fans (e.g; Pure Hot+Cool).
This code only supports Pure Hot+Cool fans at the moment. It should be trivial This code only supports Pure Hot+Cool fans at the moment. It should be trivial
to extend to other fan types (I just don't have one to test). to extend to other fan types (I just don't have one to test).
## Dependencies ## Build
```
% bazel build :main
```
If you'd like a Debian package:
```
% baze build :main-deb
```
### Without Bazel
You'll need these dependencies:
``` ```
pip install libpurecool pip install libpurecool
pip install prometheus_client pip install prometheus_client
``` ```
## Metrics ## Metrics
### Environmental ### Environmental
Name | Type | Description Name | Type | Description
---- | ---- | ----------- ---- | ---- | -----------
humidity | gauge | relative humidity percentage dyson_humidity_percent | gauge | relative humidity percentage
temperature | gauge | ambient temperature in celsius dyson_temperature_celsius | gauge | ambient temperature in celsius
voc | gauge | volatile organic compounds (range 0-10?) dyson_volatile_organic_compounds_units | gauge | volatile organic compounds (range 0-10?)
dust | gauge | dust level (range 0-10?) dyson_dust_units | gauge | dust level (range 0-10?)
### Operational ### Operational
Name | Type | Description Name | Type | Description
---- | ---- | ----------- ---- | ---- | -----------
fan_mode | enum | AUTO, FAN (what the fan is set to) dyson_fan_mode | enum | AUTO, FAN (what the fan is set to)
fan_state | enum | FAN, OFF (what the fan is actually doing) dyson_fan_state | enum | FAN, OFF (what the fan is actually doing)
fan_speed | gauge | 0-10 (or -1 if on AUTO) dyson_fan_speed_units | gauge | 0-10 (or -1 if on AUTO)
oscillation | enum | ON, OFF dyson_oscillation_mode | enum | ON, OFF
focus_mode | enum | ON, OFF dyson_focus_mode | enum | ON, OFF
heat_mode | enum | HEAT, OFF (OFF means "in cooling mode") dyson_heat_mode | enum | HEAT, OFF (OFF means "in cooling mode")
heat_state | enum | HEAT, OFF (what the fan is actually doing) dyson_heat_state | enum | HEAT, OFF (what the fan is actually doing)
heat_target | gauge | target temperature (celsius) dyson_heat_target_celsius | gauge | target temperature (celsius)
quality_target | gauge | air quality target (1, 3, 5?) dyson_quality_target_units | gauge | air quality target (1, 3, 5?)
filter_life | gauge | hours of filter life remaining dyson_filter_life_seconds | gauge | seconds of filter life remaining
## Usage ## Usage
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
"gnetId": null, "gnetId": null,
"graphTooltip": 0, "graphTooltip": 0,
"id": null, "id": null,
"iteration": 1543741240899, "iteration": 1600325678809,
"links": [], "links": [],
"panels": [ "panels": [
{ {
...@@ -129,11 +129,12 @@ ...@@ -129,11 +129,12 @@
"tableColumn": "", "tableColumn": "",
"targets": [ "targets": [
{ {
"expr": "fan_mode{instance=~\"$instance\",name=~\"$name\"}==1", "expr": "dyson_fan_mode{instance=~\"$instance\",name=~\"$name\"}==1",
"format": "time_series", "format": "time_series",
"instant": true, "instant": true,
"interval": "",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "{{fan_mode}}", "legendFormat": "{{dyson_fan_mode}}",
"refId": "A" "refId": "A"
} }
], ],
...@@ -211,11 +212,12 @@ ...@@ -211,11 +212,12 @@
"tableColumn": "", "tableColumn": "",
"targets": [ "targets": [
{ {
"expr": "fan_state{instance=~\"$instance\",name=~\"$name\"}==1", "expr": "dyson_fan_state{instance=~\"$instance\",name=~\"$name\"}==1",
"format": "time_series", "format": "time_series",
"instant": true, "instant": true,
"interval": "",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "{{fan_state}}", "legendFormat": "{{dyson_fan_state}}",
"refId": "A" "refId": "A"
} }
], ],
...@@ -293,11 +295,12 @@ ...@@ -293,11 +295,12 @@
"tableColumn": "", "tableColumn": "",
"targets": [ "targets": [
{ {
"expr": "oscillation{instance=~\"$instance\",name=~\"$name\"}==1", "expr": "dyson_oscillation_mode{instance=~\"$instance\",name=~\"$name\"}==1",
"format": "time_series", "format": "time_series",
"instant": true, "instant": true,
"interval": "",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "{{oscillation}}", "legendFormat": "{{dyson_oscillation_mode}}",
"refId": "A" "refId": "A"
} }
], ],
...@@ -375,12 +378,12 @@ ...@@ -375,12 +378,12 @@
"tableColumn": "", "tableColumn": "",
"targets": [ "targets": [
{ {
"expr": "focus_mode{instance=~\"$instance\",name=~\"$name\"}==1", "expr": "dyson_focus_mode{instance=~\"$instance\",name=~\"$name\"}==1",
"format": "time_series", "format": "time_series",
"instant": true, "instant": true,
"interval": "", "interval": "",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "{{focus_mode}}", "legendFormat": "{{dyson_focus_mode}}",
"refId": "A" "refId": "A"
} }
], ],
...@@ -458,11 +461,11 @@ ...@@ -458,11 +461,11 @@
"tableColumn": "", "tableColumn": "",
"targets": [ "targets": [
{ {
"expr": "heat_mode{instance=~\"$instance\",name=~\"$name\"}==1", "expr": "dyson_heat_mode{instance=~\"$instance\",name=~\"$name\"}==1",
"format": "time_series", "format": "time_series",
"instant": true, "instant": true,
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "{{heat_mode}}", "legendFormat": "{{dyson_heat_mode}}",
"refId": "A" "refId": "A"
} }
], ],
...@@ -571,7 +574,7 @@ ...@@ -571,7 +574,7 @@
"#d44a3a" "#d44a3a"
], ],
"datasource": "${DS_LOCAL}", "datasource": "${DS_LOCAL}",
"format": "h", "format": "s",
"gauge": { "gauge": {
"maxValue": 100, "maxValue": 100,
"minValue": 0, "minValue": 0,
...@@ -622,7 +625,7 @@ ...@@ -622,7 +625,7 @@
"tableColumn": "", "tableColumn": "",
"targets": [ "targets": [
{ {
"expr": "filter_life{instance=~\"$instance\",name=~\"$name\"}", "expr": "dyson_filter_life_seconds{instance=~\"$instance\",name=~\"$name\"}",
"format": "time_series", "format": "time_series",
"intervalFactor": 1, "intervalFactor": 1,
"refId": "A" "refId": "A"
...@@ -694,7 +697,7 @@ ...@@ -694,7 +697,7 @@
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
{ {
"expr": "dust{instance=~\"$instance\",name=~\"$name\"}", "expr": "dyson_dust_units{instance=~\"$instance\",name=~\"$name\"}",
"format": "time_series", "format": "time_series",
"interval": "", "interval": "",
"intervalFactor": 1, "intervalFactor": 1,
...@@ -702,14 +705,14 @@ ...@@ -702,14 +705,14 @@
"refId": "A" "refId": "A"
}, },
{ {
"expr": "voc{instance=~\"$instance\",name=~\"$name\"}", "expr": "dyson_volatile_organic_compounds_units{instance=~\"$instance\",name=~\"$name\"}",
"format": "time_series", "format": "time_series",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "VOC", "legendFormat": "VOC",
"refId": "B" "refId": "B"
}, },
{ {
"expr": "quality_target{instance=~\"$instance\",name=~\"$name\"}", "expr": "dyson_quality_target_units{instance=~\"$instance\",name=~\"$name\"}",
"format": "time_series", "format": "time_series",
"interval": "", "interval": "",
"intervalFactor": 1, "intervalFactor": 1,
...@@ -797,7 +800,7 @@ ...@@ -797,7 +800,7 @@
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
{ {
"expr": "humidity{instance=~\"$instance\",name=~\"$name\"}", "expr": "dyson_humidity_percent{instance=~\"$instance\",name=~\"$name\"}",
"format": "time_series", "format": "time_series",
"intervalFactor": 10, "intervalFactor": 10,
"legendFormat": "Humidity (%age)", "legendFormat": "Humidity (%age)",
...@@ -883,14 +886,14 @@ ...@@ -883,14 +886,14 @@
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
{ {
"expr": "temperature{instance=~\"$instance\",name=~\"$name\"}", "expr": "dyson_temperature_celsius{instance=~\"$instance\",name=~\"$name\"}",
"format": "time_series", "format": "time_series",
"intervalFactor": 10, "intervalFactor": 10,
"legendFormat": "Temperature", "legendFormat": "Temperature",
"refId": "A" "refId": "A"
}, },
{ {
"expr": "heat_target{instance=~\"$instance\",name=~\"$name\"}", "expr": "dyson_heat_target_celsius{instance=~\"$instance\",name=~\"$name\"}",
"format": "time_series", "format": "time_series",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "Heat Target", "legendFormat": "Heat Target",
...@@ -920,7 +923,7 @@ ...@@ -920,7 +923,7 @@
"label": null, "label": null,
"logBase": 1, "logBase": 1,
"max": null, "max": null,
"min": null, "min": "15",
"show": true "show": true
}, },
{ {
...@@ -987,9 +990,10 @@ ...@@ -987,9 +990,10 @@
"steppedLine": false, "steppedLine": false,
"targets": [ "targets": [
{ {
"expr": "filter_life{instance=~\"$instance\",name=~\"$name\"}", "expr": "dyson_filter_life_seconds{instance=~\"$instance\",name=~\"$name\"}",
"format": "time_series", "format": "time_series",
"intervalFactor": 1, "intervalFactor": 1,
"legendFormat": "Remaining Life - {{name}}",
"refId": "A" "refId": "A"
} }
], ],
...@@ -1012,7 +1016,7 @@ ...@@ -1012,7 +1016,7 @@
}, },
"yaxes": [ "yaxes": [
{ {
"format": "h", "format": "s",
"label": null, "label": null,
"logBase": 1, "logBase": 1,
"max": null, "max": null,
...@@ -1116,5 +1120,5 @@ ...@@ -1116,5 +1120,5 @@
"timezone": "", "timezone": "",
"title": "Dyson Fan", "title": "Dyson Fan",
"uid": "wSsTjyYik", "uid": "wSsTjyYik",
"version": 7 "version": 10
} }
\ No newline at end of file
...@@ -35,34 +35,37 @@ class Metrics(): ...@@ -35,34 +35,37 @@ class Metrics():
labels = ['name', 'serial'] labels = ['name', 'serial']
# Environmental Sensors # Environmental Sensors
self.humidity = prometheus_client.Gauge('humidity', 'Relative humidity (percentage)', labels) self.humidity = prometheus_client.Gauge(
'dyson_humidity_percent', 'Relative humidity (percentage)', labels)
self.temperature = prometheus_client.Gauge( self.temperature = prometheus_client.Gauge(
'temperature', 'Ambient temperature (celsius)', labels) 'dyson_temperature_celsius', 'Ambient temperature (celsius)', labels)
self.voc = prometheus_client.Gauge('voc', 'Level of Volatile organic compounds', labels) self.voc = prometheus_client.Gauge(
self.dust = prometheus_client.Gauge('dust', 'Level of Dust', labels) 'dyson_volatile_organic_compounds_units', 'Level of Volatile organic compounds', labels)
self.dust = prometheus_client.Gauge(
'dyson_dust_units', 'Level of Dust', labels)
# Operational State # Operational State
# Ignoring: tilt (known values OK), standby_monitoring. # Ignoring: tilt (known values OK), standby_monitoring.
self.fan_mode = prometheus_client.Enum( self.fan_mode = prometheus_client.Enum(
'fan_mode', 'Current mode of the fan', labels, states=['AUTO', 'FAN']) 'dyson_fan_mode', 'Current mode of the fan', labels, states=['AUTO', 'FAN'])
self.fan_state = prometheus_client.Enum( self.fan_state = prometheus_client.Enum(
'fan_state', 'Current running state of the fan', labels, states=['FAN', 'OFF']) 'dyson_fan_state', 'Current running state of the fan', labels, states=['FAN', 'OFF'])
self.fan_speed = prometheus_client.Gauge( self.fan_speed = prometheus_client.Gauge(
'fan_speed', 'Current speed of fan (-1 = AUTO)', labels) 'dyson_fan_speed_units', 'Current speed of fan (-1 = AUTO)', labels)
self.oscillation = prometheus_client.Enum( self.oscillation = prometheus_client.Enum(
'oscillation', 'Current oscillation mode', labels, states=['ON', 'OFF']) 'dyson_oscillation_mode', 'Current oscillation mode', labels, states=['ON', 'OFF'])
self.focus_mode = prometheus_client.Enum( self.focus_mode = prometheus_client.Enum(
'focus_mode', 'Current focus mode', labels, states=['ON', 'OFF']) 'dyson_focus_mode', 'Current focus mode', labels, states=['ON', 'OFF'])
self.heat_mode = prometheus_client.Enum( self.heat_mode = prometheus_client.Enum(
'heat_mode', 'Current heat mode', labels, states=['HEAT', 'OFF']) 'dyson_heat_mode', 'Current heat mode', labels, states=['HEAT', 'OFF'])
self.heat_state = prometheus_client.Enum( self.heat_state = prometheus_client.Enum(
'heat_state', 'Current heat state', labels, states=['HEAT', 'OFF']) 'dyson_heat_state', 'Current heat state', labels, states=['HEAT', 'OFF'])
self.heat_target = prometheus_client.Gauge( self.heat_target = prometheus_client.Gauge(
'heat_target', 'Heat target temperature (celsius)', labels) 'dyson_heat_target_celsius', 'Heat target temperature (celsius)', labels)
self.quality_target = prometheus_client.Gauge( self.quality_target = prometheus_client.Gauge(
'quality_target', 'Quality target for fan', labels) 'dyson_quality_target_units', 'Quality target for fan', labels)
self.filter_life = prometheus_client.Gauge( self.filter_life = prometheus_client.Gauge(
'filter_life', 'Remaining filter life (hours)', labels) 'dyson_filter_life_seconds', 'Remaining filter life (seconds)', labels)
def update(self, name: str, serial: str, message: object) -> None: def update(self, name: str, serial: str, message: object) -> None:
"""Receives a sensor or device state update and updates Prometheus metrics. """Receives a sensor or device state update and updates Prometheus metrics.
...@@ -94,13 +97,16 @@ class Metrics(): ...@@ -94,13 +97,16 @@ class Metrics():
# Convert from Decicelsius to Kelvin. # Convert from Decicelsius to Kelvin.
heat_target = int(message.heat_target) / 10 - 273.2 heat_target = int(message.heat_target) / 10 - 273.2
# Convert filter_life from hours to seconds
filter_life = int(message.filter_life) * 60 * 60
self.oscillation.labels(name=name, serial=serial).state(message.oscillation) self.oscillation.labels(name=name, serial=serial).state(message.oscillation)
self.focus_mode.labels(name=name, serial=serial).state(message.focus_mode) self.focus_mode.labels(name=name, serial=serial).state(message.focus_mode)
self.heat_mode.labels(name=name, serial=serial).state(message.heat_mode) self.heat_mode.labels(name=name, serial=serial).state(message.heat_mode)
self.heat_state.labels(name=name, serial=serial).state(message.heat_state) self.heat_state.labels(name=name, serial=serial).state(message.heat_state)
self.heat_target.labels(name=name, serial=serial).set(heat_target) self.heat_target.labels(name=name, serial=serial).set(heat_target)
self.quality_target.labels(name=name, serial=serial).set(message.quality_target) self.quality_target.labels(name=name, serial=serial).set(message.quality_target)
self.filter_life.labels(name=name, serial=serial).set(message.filter_life) self.filter_life.labels(name=name, serial=serial).set(filter_life)
else: else:
logging.warning('Received unknown update from "%s" (serial=%s): %s; ignoring', logging.warning('Received unknown update from "%s" (serial=%s): %s; ignoring',
name, serial, type(message)) name, serial, type(message))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment