Skip to content

Commit

Permalink
Merge pull request #63 from yozik04/resolve_alarm
Browse files Browse the repository at this point in the history
Alarm resolve
  • Loading branch information
yozik04 authored Feb 13, 2024
2 parents e35f335 + 821485f commit d71bf61
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 65 deletions.
19 changes: 19 additions & 0 deletions tests/test_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,22 @@ def test_log_read_response(messages: Messages):
result = messages.log_read_response1.parse(response)

assert 6 == result.fields.value.pages


def test_alarm_resolve(messages: Messages, data_model: DataModel):
expected = binascii.unhexlify("0400 f900 0790 0200 0691".replace(" ", ""))

assert expected == messages.write_request.build(
{
"fields": {
"value": {
"items": [
{
"address": data_model.addresses["A_CYC_FAULT_ACTIVITY"],
"value": 2,
}
]
}
}
}
)
28 changes: 27 additions & 1 deletion tests/test_vallox_alarm.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import datetime
from unittest import mock

import pytest

from vallox_websocket_api.vallox import Alarm, MetricData
from vallox_websocket_api.vallox import Alarm, MetricData, Vallox


@pytest.fixture
def vallox():
client = Vallox("127.0.0.1")
client.set_values = mock.AsyncMock()

return client


@pytest.fixture
Expand Down Expand Up @@ -217,10 +226,27 @@ async def test_get_info(metrics: dict):
assert len(alarms) == 1

alarm = alarms[0]
assert alarm.nr == 1
assert alarm.code == 23
assert alarm.severity == Alarm.Severity.SEVERE
assert alarm.activity == Alarm.Activity.SOLVED
assert alarm.count == 0
assert alarm.first_date == datetime.date(2024, 1, 2)
assert alarm.last_date == datetime.date(2024, 1, 7)
assert alarm.message == "Low supply air temperature"


async def test_resolve_alarm(vallox: Vallox):
alarm = Alarm(
nr=1,
code=23,
severity=Alarm.Severity.SEVERE,
first_date=datetime.date(2024, 1, 2),
last_date=datetime.date(2024, 1, 7),
count=0,
activity=Alarm.Activity.ACTIVE,
)

await vallox.resolve_alarm(alarm)

vallox.set_values.assert_called_once_with({"A_CYC_FAULT_ACTIVITY": 2})
34 changes: 17 additions & 17 deletions tests/test_vallox_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ async def test_set_profile_home(vallox: Vallox):

vallox.set_values.assert_called_once_with(
{
"A_CYC_STATE": "0",
"A_CYC_BOOST_TIMER": "0",
"A_CYC_FIREPLACE_TIMER": "0",
"A_CYC_EXTRA_TIMER": "0",
"A_CYC_STATE": 0,
"A_CYC_BOOST_TIMER": 0,
"A_CYC_FIREPLACE_TIMER": 0,
"A_CYC_EXTRA_TIMER": 0,
}
)

Expand All @@ -25,10 +25,10 @@ async def test_set_profile_away(vallox: Vallox):

vallox.set_values.assert_called_once_with(
{
"A_CYC_STATE": "1",
"A_CYC_BOOST_TIMER": "0",
"A_CYC_FIREPLACE_TIMER": "0",
"A_CYC_EXTRA_TIMER": "0",
"A_CYC_STATE": 1,
"A_CYC_BOOST_TIMER": 0,
"A_CYC_FIREPLACE_TIMER": 0,
"A_CYC_EXTRA_TIMER": 0,
}
)

Expand All @@ -41,9 +41,9 @@ async def test_set_profile_boost(vallox: Vallox):

vallox.set_values.assert_called_once_with(
{
"A_CYC_BOOST_TIMER": "30",
"A_CYC_FIREPLACE_TIMER": "0",
"A_CYC_EXTRA_TIMER": "0",
"A_CYC_BOOST_TIMER": 30,
"A_CYC_FIREPLACE_TIMER": 0,
"A_CYC_EXTRA_TIMER": 0,
}
)

Expand All @@ -58,9 +58,9 @@ async def test_set_profile_fireplace(vallox: Vallox):

vallox.set_values.assert_called_once_with(
{
"A_CYC_BOOST_TIMER": "0",
"A_CYC_FIREPLACE_TIMER": "30",
"A_CYC_EXTRA_TIMER": "0",
"A_CYC_BOOST_TIMER": 0,
"A_CYC_FIREPLACE_TIMER": 30,
"A_CYC_EXTRA_TIMER": 0,
}
)

Expand All @@ -75,9 +75,9 @@ async def test_set_profile_extra(vallox: Vallox):

vallox.set_values.assert_called_once_with(
{
"A_CYC_BOOST_TIMER": "0",
"A_CYC_FIREPLACE_TIMER": "0",
"A_CYC_EXTRA_TIMER": "30",
"A_CYC_BOOST_TIMER": 0,
"A_CYC_FIREPLACE_TIMER": 0,
"A_CYC_EXTRA_TIMER": 30,
}
)

Expand Down
17 changes: 9 additions & 8 deletions vallox_websocket_api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,17 @@ class Client:
"""Client for Vallox Websocket API"""

SETTABLE_INT_VALS = {
re.compile("^A_CYC_MODE$"),
re.compile("^A_CYC_STATE$"),
re.compile("^A_CYC_(?:HOME|AWAY|BOOST|EXTRA)_AIR_TEMP_TARGET$"),
re.compile("^A_CYC_(?:HOME|AWAY|BOOST)_SPEED_SETTING$"),
re.compile("^A_CYC_(?:BOOST|FIREPLACE|EXTRA)_TIMER$"),
re.compile("^A_CYC_(?:FIREPLACE|EXTRA)_(?:EXTR|SUPP)_FAN$"),
re.compile("^A_CYC_(?:EXTR|SUPP)_FAN_BALANCE_BASE$"),
re.compile(r"^A_CYC_MODE$"),
re.compile(r"^A_CYC_STATE$"),
re.compile(r"^A_CYC_(?:HOME|AWAY|BOOST|EXTRA)_AIR_TEMP_TARGET$"),
re.compile(r"^A_CYC_(?:HOME|AWAY|BOOST)_SPEED_SETTING$"),
re.compile(r"^A_CYC_(?:BOOST|FIREPLACE|EXTRA)_TIMER$"),
re.compile(r"^A_CYC_(?:FIREPLACE|EXTRA)_(?:EXTR|SUPP)_FAN$"),
re.compile(r"^A_CYC_(?:EXTR|SUPP)_FAN_BALANCE_BASE$"),
re.compile(
"^A_CYC_FILTER_CHANGED_(?:DAY|MONTH|YEAR)|A_CYC_FILTER_CHANGE_INTERVAL$"
r"^A_CYC_FILTER_CHANGED_(?:DAY|MONTH|YEAR)|A_CYC_FILTER_CHANGE_INTERVAL$"
),
re.compile(r"^A_CYC_FAULT_ACTIVITY(?:_\d{1,2})?$"),
}

_settable_addresses: Dict[int, type]
Expand Down
76 changes: 37 additions & 39 deletions vallox_websocket_api/vallox.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def swap16(val: int) -> int:
return ((val & 0xFF) << 8) | ((val >> 8) & 0xFF)


def _get_alarm_date(raw: int) -> Optional[date]:
def _get_alarm_date(raw: Optional[int]) -> Optional[date]:
if raw is None:
return None

Expand Down Expand Up @@ -212,6 +212,7 @@ def get_alarms(self, skip_solved=True) -> list["Alarm"]:
if fault_count is None:
return []

fault_count = int(fault_count)
alarms = []
for i in range(1, fault_count + 1):
suffix = "" if i == 1 else f"_{i}"
Expand All @@ -222,9 +223,7 @@ def get_alarms(self, skip_solved=True) -> list["Alarm"]:
if code == 0:
continue

activity = self.data.get(f"A_CYC_FAULT_ACTIVITY{suffix}")
if activity is None:
activity = Alarm.Severity.UNKNOWN
activity = Alarm.Activity(self.data.get(f"A_CYC_FAULT_ACTIVITY{suffix}"))

if skip_solved and activity == 2:
continue
Expand All @@ -234,14 +233,13 @@ def get_alarms(self, skip_solved=True) -> list["Alarm"]:
)
last_date = _get_alarm_date(self.data.get(f"A_CYC_FAULT_LAST_DATE{suffix}"))

severity = self.data.get(f"A_CYC_FAULT_SEVERITY{suffix}")
if severity is None:
severity = Alarm.Severity.UNKNOWN
severity = Alarm.Severity(self.data.get(f"A_CYC_FAULT_SEVERITY{suffix}"))

alarms.append(
Alarm(
code=code,
severity=Alarm.Severity(severity),
nr=i,
code=int(code),
severity=severity,
first_date=first_date,
last_date=last_date,
count=self.data.get(f"A_CYC_FAULT_COUNT{suffix}", None),
Expand All @@ -256,10 +254,11 @@ def get_alarms(self, skip_solved=True) -> list["Alarm"]:
class Alarm:
"""Alarm dataclass"""

nr: int
code: int
severity: "Severity"
first_date: datetime.date
last_date: datetime.date
first_date: Optional[datetime.date]
last_date: Optional[datetime.date]
count: int
activity: "Activity"

Expand Down Expand Up @@ -287,7 +286,7 @@ def message(self) -> str:

def __repr__(self):
return (
f"Alarm(code={self.code}, severity={self.severity}, first_date={self.first_date}, "
f"Alarm(nr={self.nr}, code={self.code}, severity={self.severity}, first_date={self.first_date}, "
f"last_date={self.last_date}, count={self.count}, activity={self.activity}, "
f"message='{self.message}')"
)
Expand Down Expand Up @@ -325,58 +324,49 @@ async def set_profile(
logger.info("Setting unit to HOME profile")
await self.set_values(
{
"A_CYC_STATE": "0",
"A_CYC_BOOST_TIMER": "0",
"A_CYC_FIREPLACE_TIMER": "0",
"A_CYC_EXTRA_TIMER": "0",
"A_CYC_STATE": 0,
"A_CYC_BOOST_TIMER": 0,
"A_CYC_FIREPLACE_TIMER": 0,
"A_CYC_EXTRA_TIMER": 0,
}
)
elif profile == PROFILE.AWAY:
logger.info("Setting unit to AWAY profile")
await self.set_values(
{
"A_CYC_STATE": "1",
"A_CYC_BOOST_TIMER": "0",
"A_CYC_FIREPLACE_TIMER": "0",
"A_CYC_EXTRA_TIMER": "0",
"A_CYC_STATE": 1,
"A_CYC_BOOST_TIMER": 0,
"A_CYC_FIREPLACE_TIMER": 0,
"A_CYC_EXTRA_TIMER": 0,
}
)
elif profile == PROFILE.FIREPLACE:
if set_duration is not None:
dur = str(set_duration)
else:
dur = str(await self.fetch_metric("A_CYC_FIREPLACE_TIME"))
dur = set_duration or await self.fetch_metric("A_CYC_FIREPLACE_TIME")
logger.info(f"Setting unit to FIREPLACE profile for {dur} minutes")
await self.set_values(
{
"A_CYC_BOOST_TIMER": "0",
"A_CYC_BOOST_TIMER": 0,
"A_CYC_FIREPLACE_TIMER": dur,
"A_CYC_EXTRA_TIMER": "0",
"A_CYC_EXTRA_TIMER": 0,
}
)
elif profile == PROFILE.BOOST:
if set_duration is not None:
dur = str(set_duration)
else:
dur = str(await self.fetch_metric("A_CYC_BOOST_TIME"))
dur = set_duration or await self.fetch_metric("A_CYC_BOOST_TIME")
logger.info(f"Setting unit to BOOST profile for {dur} minutes")
await self.set_values(
{
"A_CYC_BOOST_TIMER": dur,
"A_CYC_FIREPLACE_TIMER": "0",
"A_CYC_EXTRA_TIMER": "0",
"A_CYC_FIREPLACE_TIMER": 0,
"A_CYC_EXTRA_TIMER": 0,
}
)
elif profile == PROFILE.EXTRA:
if set_duration is not None:
dur = str(set_duration)
else:
dur = str(await self.fetch_metric("A_CYC_EXTRA_TIME"))
logger.info(f"Setting unit to EXTRA profile for {dur} minutes")
dur = set_duration or await self.fetch_metric("A_CYC_EXTRA_TIME")
logger.info(f"Setting unit to EXTRA profile for {dur} minutes")
await self.set_values(
{
"A_CYC_BOOST_TIMER": "0",
"A_CYC_FIREPLACE_TIMER": "0",
"A_CYC_BOOST_TIMER": 0,
"A_CYC_FIREPLACE_TIMER": 0,
"A_CYC_EXTRA_TIMER": dur,
}
)
Expand Down Expand Up @@ -437,3 +427,11 @@ async def set_filter_change_date(self, _date: date) -> None:
"A_CYC_FILTER_CHANGED_YEAR": _date.year - 2000,
}
)

async def resolve_alarm(self, alarm: Alarm) -> None:
"""Resolve an alarm"""

suffix = "" if alarm.nr == 1 else f"_{alarm.nr}"
await self.set_values(
{f"A_CYC_FAULT_ACTIVITY{suffix}": Alarm.Activity.SOLVED.value}
)

0 comments on commit d71bf61

Please sign in to comment.