Skip to content

Commit 54e6477

Browse files
committed
Fix climate controller issues:
- Only use last known temperature values when heat/cool values are non-zero - Add support for negative temperature values
1 parent 7857a75 commit 54e6477

File tree

4 files changed

+80
-25
lines changed

4 files changed

+80
-25
lines changed

inelsmqtt/protocols/cu3.py

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
parse_formated_json,
134134
trim_inels_status_bytes,
135135
trim_inels_status_values,
136+
twos_comp_4B,
136137
)
137138

138139

@@ -2044,25 +2045,22 @@ def create_ha_value_object(cls, device_value: DeviceValue) -> Any:
20442045
last_known_required = None
20452046
last_known_required_cool = None
20462047

2047-
temp_current: float = int(
2048-
trim_inels_status_values(device_value.inels_status_value, cls.DATA, CURRENT_TEMP, ""), 16
2048+
temp_current: float = twos_comp_4B(
2049+
int(trim_inels_status_values(device_value.inels_status_value, cls.DATA, CURRENT_TEMP, ""), 16)
20492050
)
20502051
if temp_current == 0x7FFFFFFB:
20512052
temp_current = 0
20522053
else:
20532054
temp_current /= 100
20542055

20552056
temp_critical_max = (
2056-
int(
2057-
trim_inels_status_values( # check if 0x7F FF FF FB -> make it 50
2058-
device_value.inels_status_value, cls.DATA, CRITICAL_MAX_TEMP, ""
2059-
),
2060-
16,
2057+
twos_comp_4B(
2058+
int(trim_inels_status_values(device_value.inels_status_value, cls.DATA, CRITICAL_MAX_TEMP, ""), 16)
20612059
)
20622060
/ 100
20632061
)
2064-
temp_required_heat: float = int(
2065-
trim_inels_status_values(device_value.inels_status_value, cls.DATA, REQUIRED_HEAT_TEMP, ""), 16
2062+
temp_required_heat: float = twos_comp_4B(
2063+
int(trim_inels_status_values(device_value.inels_status_value, cls.DATA, REQUIRED_HEAT_TEMP, ""), 16)
20662064
)
20672065
if temp_required_heat == 0x7FFFFFFB:
20682066
temp_required_heat = 0
@@ -2076,17 +2074,8 @@ def create_ha_value_object(cls, device_value: DeviceValue) -> Any:
20762074
if temp_required_heat != 0:
20772075
last_known_required = temp_required_heat
20782076

2079-
temp_critical_min = (
2080-
int(
2081-
trim_inels_status_values( # check if 0x7F FF FF FB -> make it -50
2082-
device_value.inels_status_value, cls.DATA, CRITICAL_MIN_TEMP, ""
2083-
),
2084-
16,
2085-
)
2086-
/ 100
2087-
)
2088-
temp_required_cool: float = int(
2089-
trim_inels_status_values(device_value.inels_status_value, cls.DATA, REQUIRED_COOL_TEMP, ""), 16
2077+
temp_required_cool: float = twos_comp_4B(
2078+
int(trim_inels_status_values(device_value.inels_status_value, cls.DATA, REQUIRED_COOL_TEMP, ""), 16)
20902079
)
20912080
if temp_required_cool == 0x7FFFFFFB:
20922081
temp_required_cool = 0
@@ -2101,7 +2090,10 @@ def create_ha_value_object(cls, device_value: DeviceValue) -> Any:
21012090
last_known_required_cool = temp_required_cool
21022091

21032092
temp_correction = (
2104-
int(trim_inels_status_values(device_value.inels_status_value, cls.DATA, TEMP_CORRECTION, ""), 16) / 100
2093+
twos_comp_4B(
2094+
int(trim_inels_status_values(device_value.inels_status_value, cls.DATA, TEMP_CORRECTION, ""), 16)
2095+
)
2096+
/ 100
21052097
)
21062098
holiday_mode = int(trim_inels_status_values(device_value.inels_status_value, cls.DATA, PUBLIC_HOLIDAY, ""), 16)
21072099
control_mode = int(trim_inels_status_values(device_value.inels_status_value, cls.DATA, CONTROL_MODE, ""))
@@ -2213,11 +2205,13 @@ def create_inels_set_value(cls, device_value: DeviceValue) -> str:
22132205

22142206
required_heat = cc.required
22152207
required_cool = cc.required_cool
2216-
if (required_heat == 0 or required_cool == 0) and manual_in == 7 and (byte18 == 1 or byte18 == 3):
2208+
if manual_in == 7 and byte18 in [1, 3]:
22172209
try:
22182210
climate_controller = device_value.last_value.ha_value.climate_controller
2219-
required_heat = climate_controller.last_known_required or required_heat
2220-
required_cool = climate_controller.last_known_required_cool or required_cool
2211+
if required_heat == 0 and climate_controller.last_known_required:
2212+
required_heat = climate_controller.last_known_required
2213+
if required_cool == 0 and climate_controller.last_known_required_cool:
2214+
required_cool = climate_controller.last_known_required_cool
22212215
except AttributeError:
22222216
pass
22232217

inelsmqtt/utils/common.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ def new_object(**kwargs: Any) -> Any:
108108
return cls
109109

110110

111+
def twos_comp_4B(i):
112+
return -(i & 0b10000000000000000000000000000000) | (i & 0b01111111111111111111111111111111)
113+
114+
111115
def break_into_bytes(line: str) -> List[str]:
112116
if len(line) % 2 == 0:
113117
return [line[i : i + 2] for i in range(0, len(line), 2)]

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setup(
66
name="elkoep-mqtt",
7-
version="0.2.33.beta.16",
7+
version="0.2.33.beta.17",
88
url="https://github.com/epdevlab/elkoep-mqtt",
99
license="MIT",
1010
author="Elko EP s.r.o.",

tests/test_device_value.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,24 @@ def device_value(self):
20062006
inels_value="DD\n0A\n00\n00\nFB\nFF\nFF\n7F\n80\n0C\n00\n00\n88\n13\n00\n00\nBC\n02\n00\n00\n00\n00\n00\n00\n00\n00\n00\n00\n00\n00\n05\n"
20072007
)
20082008

2009+
@pytest.fixture
2010+
def device_value_all_negative(self):
2011+
return self.create_device_value(
2012+
inels_value="9C\nFF\nFF\nFF\n38\nFF\nFF\nFF\nD4\nFE\nFF\nFF\n70\nFE\nFF\nFF\n0C\nFE\nFF\nFF\nA8\nFD\nFF\nFF\n44\nFD\nFF\nFF\n00\n00\n00\n"
2013+
)
2014+
2015+
@pytest.fixture
2016+
def device_value_all_positive(self):
2017+
return self.create_device_value(
2018+
inels_value="64\n00\n00\n00\nC8\n00\n00\n00\n2C\n01\n00\n00\n90\n01\n00\n00\nF4\n01\n00\n00\n58\n02\n00\n00\nBC\n02\n00\n00\n00\n00\n00\n"
2019+
)
2020+
2021+
@pytest.fixture
2022+
def device_value_7FFFFFFB(self):
2023+
return self.create_device_value(
2024+
inels_value="FB\nFF\nFF\n7F\nC8\n00\n00\n00\nFB\nFF\nFF\n7F\n90\n01\n00\n00\nF4\n01\n00\n00\nFB\nFF\nFF\n7F\nBC\n02\n00\n00\n00\n00\n00\n"
2025+
)
2026+
20092027
def test_create_ha_value_object(self, device_value):
20102028
assert device_value.ha_value.climate_controller.current == 27.81
20112029
assert device_value.ha_value.climate_controller.required == 32.0
@@ -2052,6 +2070,45 @@ def test_create_ha_value_required_temp_after_hca_turned_off(self, device_value):
20522070
== "DD\n0A\n00\n00\nFB\nFF\nFF\n7F\n80\n0C\n00\n00\n00\n00\n00\n00\n00\n07\n01\n"
20532071
)
20542072

2073+
def test_last_value_does_not_overwrite_current_value(self, device_value):
2074+
assert device_value.ha_value.climate_controller.required == 32.0
2075+
assert device_value.ha_value.climate_controller.last_known_required == 32.0
2076+
2077+
dev_value_current = self.create_device_value(
2078+
inels_value="DD\n0A\n00\n00\nFB\nFF\nFF\n7F\n80\n0C\n00\n00\n88\n13\n00\n00\nBC\n02\n00\n00\n00\n00\n00\n00\n00\n00\n00\n00\n00\n00\n05\n"
2079+
)
2080+
dev_value_current.ha_value.climate_controller.required = 16.0
2081+
2082+
hca_device_value = self.create_device_value(
2083+
ha_value=dev_value_current.ha_value,
2084+
last_value=device_value,
2085+
)
2086+
2087+
# the required value is 16.0, but the last known value is 32.0, so the set value must be 16.0
2088+
assert (
2089+
hca_device_value.inels_set_value
2090+
== "DD\n0A\n00\n00\nFB\nFF\nFF\n7F\n40\n06\n00\n00\n00\n00\n00\n00\n00\n07\n01\n"
2091+
)
2092+
2093+
def test_all_negative_temp(self, device_value_all_negative):
2094+
assert device_value_all_negative.ha_value.climate_controller.current == -1.0
2095+
assert device_value_all_negative.ha_value.climate_controller.critical_temp == -2.0
2096+
assert device_value_all_negative.ha_value.climate_controller.required == -3.0
2097+
assert device_value_all_negative.ha_value.climate_controller.required_cool == -6.0
2098+
assert device_value_all_negative.ha_value.climate_controller.correction_temp == -7.0
2099+
2100+
def test_all_positive_temp(self, device_value_all_positive):
2101+
assert device_value_all_positive.ha_value.climate_controller.current == 1.0
2102+
assert device_value_all_positive.ha_value.climate_controller.critical_temp == 2.0
2103+
assert device_value_all_positive.ha_value.climate_controller.required == 3.0
2104+
assert device_value_all_positive.ha_value.climate_controller.required_cool == 6.0
2105+
assert device_value_all_positive.ha_value.climate_controller.correction_temp == 7.0
2106+
2107+
def test_7FFFFFFB(self, device_value_7FFFFFFB):
2108+
assert device_value_7FFFFFFB.ha_value.climate_controller.current == 0
2109+
assert device_value_7FFFFFFB.ha_value.climate_controller.required == 0
2110+
assert device_value_7FFFFFFB.ha_value.climate_controller.required_cool == 0
2111+
20552112

20562113
class Test_CU_DEVICE_TYPE_167(BaseDeviceTestClass):
20572114
DEVICE_TYPE_ID = "167"

0 commit comments

Comments
 (0)