Private GIT

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

Handle oscillation and oscillation_state differently on V2

Thanks to @Scaredycrow for finding this issue. It appears that V2
devices emit two states: oscillation (the configured mode; this is
the intent) and oscillation_state (what the fan is currently doing).
In most cases, these should be equivalent -- though the fan will
report "IDLE" if the fan is intended to oscillate but has met its
air quality/heat target & is thusly turned off.

To make this work: dyson_oscillation_mode now reflects the intended
mode (which is no change for V1 and not a significant change for V2),
and a new metric: dyson_oscillation_state covers the possibility of
IDLE. I also added code for V1 to simulate the V2 behaviour for
consistency between the model generations.
parent bd3d8973
Branches
No related tags found
No related merge requests found
......@@ -55,7 +55,8 @@ dyson_fan_power | enum | all | ON if the fan is powered on, OFF otherwise
dyson_auto_mode | enum | all | ON if the fan is in auto mode, OFF otherwise
dyson_fan_state | enum | all | FAN, OFF (what the fan is actually doing)
dyson_fan_speed_units | gauge | all | 0-10 (or -1 if on AUTO)
dyson_oscillation_mode | enum | all | ON if the fan is oscillating, OFF otherwise
dyson_oscillation_mode | enum | all | ON if the fan in oscillation mode, OFF otherwise
dyson_oscillation_state | enum | all | ON, OFF, IDLE. ON means the fan is currently oscillating, IDLE means the fan is in auto mode and the fan is paused
dyson_oscillation_angle_low_degrees | gauge | V2 fans only | low angle of oscillation in degrees
dyson_oscillation_angle_high_degrees | gauge | V2 fans only | high angle of oscillation in degrees
dyson_night_mode | enum | all | ON if the fan is in night mode, OFF otherwise
......
"""Creates and maintains Prometheus metric values."""
import enum
import logging
from libpurecool import const, dyson_pure_state, dyson_pure_state_v2
......@@ -24,6 +25,13 @@ def update_enum(enum, name: str, serial: str, state):
enum.labels(name=name, serial=serial).state(state)
class _OscillationState(enum.Enum):
"""On V2 devices, oscillation_status can return 'IDLE' in auto mode."""
ON = 'ON'
OFF = 'OFF'
IDLE = 'IDLE'
class Metrics:
"""Registers/exports and updates Prometheus metrics for DysonLink fans."""
......@@ -71,7 +79,9 @@ class Metrics:
self.fan_speed = make_gauge(
'dyson_fan_speed_units', 'Current speed of fan (-1 = AUTO)')
self.oscillation = make_enum(
'dyson_oscillation_mode', 'Current oscillation mode', const.Oscillation)
'dyson_oscillation_mode', 'Current oscillation mode (will the fan move?)', const.Oscillation)
self.oscillation_state = make_enum(
'dyson_oscillation_state', 'Current oscillation state (is the fan moving?)', _OscillationState)
self.night_mode = make_enum(
'dyson_night_mode', 'Night mode', const.NightMode)
self.heat_mode = make_enum(
......@@ -188,7 +198,6 @@ class Metrics:
self.updatePureCoolStateCommon(name, serial, message)
update_enum(self.fan_mode, name, serial, message.fan_mode)
update_enum(self.oscillation, name, serial, message.oscillation)
update_gauge(self.quality_target, name,
serial, message.quality_target)
......@@ -203,6 +212,14 @@ class Metrics:
update_enum(self.auto_mode, name, serial, auto)
update_enum(self.fan_power, name, serial, power)
oscillation_state = message.oscillation
if message.fan_mode == const.FanMode.AUTO.value and message.fan_state == const.FanState.FAN_OFF:
# Compatibility with V2's behaviour for this value.
oscillation_state = _OscillationState.IDLE.value
update_enum(self.oscillation, name, serial, message.oscillation)
update_enum(self.oscillation_state, name, serial, oscillation_state)
# Convert filter_life from hours to seconds.
filter_life = int(message.filter_life) * 60 * 60
update_gauge(self.filter_life, name, serial, filter_life)
......@@ -228,10 +245,26 @@ class Metrics:
update_gauge(self.night_mode_speed, name, serial,
int(message.night_mode_speed))
# V2 provides oscillation_status and oscillation as fields,
# oscillation_status provides values compatible with V1, so we use that.
# oscillation returns as 'OION', 'OIOF.'
update_enum(self.oscillation, name, serial,
# V2 devices differentiate between _current_ oscillation status ('on', 'off', 'idle')
# and configured mode ('on', 'off'). This is roughly the difference between
# "is it oscillating right now" (oscillation_status) and "will it oscillate" (oscillation).
#
# This issue https://github.com/etheralm/libpurecool/issues/4#issuecomment-563358021
# seems to indicate that oscillation can be one of the OscillationV2 values (OION, OIOF)
# or one of the Oscillation values (ON, OFF) -- so support and translate both.
v2_to_v1_map = {
const.OscillationV2.OSCILLATION_ON.value: const.Oscillation.OSCILLATION_ON.value,
const.OscillationV2.OSCILLATION_OFF.value: const.Oscillation.OSCILLATION_OFF.value,
const.Oscillation.OSCILLATION_ON.value: const.Oscillation.OSCILLATION_ON.value,
const.Oscillation.OSCILLATION_OFF.value: const.Oscillation.OSCILLATION_OFF.value
}
oscillation = v2_to_v1_map.get(message.oscillation, None)
if oscillation:
update_enum(self.oscillation, name, serial, oscillation)
else:
logging.warning('Received unknown oscillation setting from "%s" (serial=%s): %s; ignoring',
name, serial, message.oscillation)
update_enum(self.oscillation_state, name, serial,
message.oscillation_status)
update_gauge(self.oscillation_angle_low, name,
serial, int(message.oscillation_angle_low))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment