Skip to content

Commit bb2b42c

Browse files
committed
Added BITS, INTEGERS, LWT
1 parent b20c355 commit bb2b42c

File tree

7 files changed

+138
-11
lines changed

7 files changed

+138
-11
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pip-delete-this-directory.txt
3939

4040
# Unit test / coverage reports
4141
htmlcov/
42+
.tests/
4243
.tox/
4344
.nox/
4445
.coverage
@@ -131,3 +132,6 @@ dmypy.json
131132
# Pypirc for deploying new package to PyPI server
132133
.pypirc
133134
.vscode/settings.json
135+
136+
# IDE metadata
137+
.idea/

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,7 @@ Supported bus devices
8787
- JA3-018M (163)
8888
- Virtual heating regulator (167)
8989
- Virtual cooling regulator (168)
90+
- SA3_014M (169)
91+
- JA3_014M (170)
92+
- BITS (bits)
93+
- INTEGETS (integers)

inelsmqtt/__init__.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,10 @@ def __on_discover(
411411
device_type = fragments[TOPIC_FRAGMENTS[FRAGMENT_DEVICE_TYPE]]
412412
action = fragments[TOPIC_FRAGMENTS[FRAGMENT_STATE]]
413413

414-
if device_type in DEVICE_TYPE_DICT:
415-
topic = msg.topic.split("/")[2:]
416-
topic = "/".join(topic)
414+
topic = msg.topic.split("/")[2:]
415+
topic = "/".join(topic)
417416

417+
if device_type in DEVICE_TYPE_DICT:
418418
if action == "status":
419419
self.__discovered[topic] = msg.payload
420420
self.__last_values[msg.topic] = msg.payload
@@ -426,6 +426,14 @@ def __on_discover(
426426
self.__last_values[msg.topic] = msg.payload
427427
self.__is_subscribed_list[msg.topic] = True
428428
_LOGGER.info("Device of type %s found [connected].\n", device_type)
429+
else:
430+
if device_type == "gw" and action == "connected":
431+
if msg.topic not in self.__is_subscribed_list:
432+
client.subscribe(msg.topic, 0, None, None)
433+
self.__messages[msg.topic] = msg.payload
434+
self.__last_values[msg.topic] = copy.copy(msg.topic)
435+
self.__is_subscribed_list[msg.topic] = True
436+
_LOGGER.info("Device of type %s found [gw].\n", device_type)
429437

430438
def __on_message(
431439
self,
@@ -446,7 +454,7 @@ def __on_message(
446454

447455
message_type = message_parts[TOPIC_FRAGMENTS[FRAGMENT_STATE]]
448456

449-
if device_type in DEVICE_TYPE_DICT:
457+
if device_type in DEVICE_TYPE_DICT or device_type == "gw":
450458
# keep last value
451459
self.__last_values[msg.topic] = (
452460
copy.copy(self.__messages[msg.topic])

inelsmqtt/const.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
CLIMATE = "climate"
1515
BUTTON = "button"
1616
BINARY_SENSOR = "binary_sensor"
17+
NUMBER = "number"
1718

1819
# RF
1920
RF_SINGLE_SWITCH = "Single switching unit" # 01
@@ -88,6 +89,8 @@
8889
JA3_014M = "JA3-014M"
8990
DALI_DMX_UNIT = "DALI-DMX-Unit"
9091
DALI_DMX_UNIT_2 = "DALI-DMX-Unit-2"
92+
INTEGERS = "INTEGERS"
93+
BITS = "BITS"
9194

9295
#Virtual bus
9396
VIRT_CONTR = "Virtual controller"
@@ -177,6 +180,9 @@
177180
"168": VIRT_COOL_REG,
178181

179182
"170": JA3_014M,
183+
184+
"bits": BITS,
185+
"integers": INTEGERS,
180186
}
181187

182188
#TODO retire this system
@@ -257,6 +263,9 @@
257263
"168": CLIMATE, # VIRT_COOL_REG
258264

259265
"170": COVER, # JA3_014M
266+
267+
"bits": SWITCH,
268+
"integers": NUMBER,
260269
}
261270

262271

@@ -843,9 +852,16 @@ class Climate_presets(IntEnum):
843852
FRAGMENT_UNIQUE_ID: 4,
844853
}
845854

855+
GW_CONNECTED = {
856+
b"{\"status\": true}": True,
857+
b"{\"status\": false}": False,
858+
}
859+
846860
DEVICE_CONNECTED = {
847861
"on\n": True,
848862
"off\n": False,
863+
"{\"status\": true}": True,
864+
"{\"status\": false}": False,
849865
}
850866

851867
# SWITCH CONSTANTS

inelsmqtt/devices/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
FRAGMENT_DEVICE_TYPE,
1919
FRAGMENT_SERIAL_NUMBER,
2020
FRAGMENT_UNIQUE_ID,
21+
GW_CONNECTED,
2122
DEVICE_CONNECTED,
2223
VERSION,
2324
)
@@ -66,6 +67,7 @@ def __init__(
6667
self.__set_topic = f"{fragments[TOPIC_FRAGMENTS[FRAGMENT_DOMAIN]]}/set/{fragments[TOPIC_FRAGMENTS[FRAGMENT_SERIAL_NUMBER]]}/{fragments[TOPIC_FRAGMENTS[FRAGMENT_DEVICE_TYPE]]}/{fragments[TOPIC_FRAGMENTS[FRAGMENT_UNIQUE_ID]]}" # noqa: E501
6768

6869
self.__connected_topic = f"{fragments[TOPIC_FRAGMENTS[FRAGMENT_DOMAIN]]}/connected/{fragments[TOPIC_FRAGMENTS[FRAGMENT_SERIAL_NUMBER]]}/{fragments[TOPIC_FRAGMENTS[FRAGMENT_DEVICE_TYPE]]}/{fragments[TOPIC_FRAGMENTS[FRAGMENT_UNIQUE_ID]]}" # noqa: E501
70+
self.__gw_connected_topic = f"{fragments[TOPIC_FRAGMENTS[FRAGMENT_DOMAIN]]}/connected/{fragments[TOPIC_FRAGMENTS[FRAGMENT_SERIAL_NUMBER]]}/gw" # noqa: E501
6971
self.__title = title if title is not None else self.__unique_id
7072
self.__domain = fragments[TOPIC_FRAGMENTS[FRAGMENT_DOMAIN]]
7173
self.__state: Any = None
@@ -137,7 +139,11 @@ def is_available(self) -> bool:
137139
Returns:
138140
bool: True/False
139141
"""
140-
val = self.__mqtt.messages()[self._Device__connected_topic]
142+
gw = self.__mqtt.messages().get(self._Device__gw_connected_topic)
143+
if not GW_CONNECTED.get(gw):
144+
return False
145+
146+
val = self.__mqtt.messages().get(self._Device__connected_topic)
141147
if isinstance(val, (bytes, bytearray)):
142148
val = val.decode()
143149

inelsmqtt/util.py

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""Utility classes."""
22
from dataclasses import dataclass
33
import logging
4+
import json
5+
import re
46

57
from operator import itemgetter
68
from typing import Any, Dict, Optional
@@ -205,8 +207,24 @@
205207
Shutter_state,
206208
Climate_action,
207209
Climate_modes,
210+
211+
BITS,
212+
INTEGERS,
213+
NUMBER,
208214
)
209215

216+
#bit
217+
@dataclass
218+
class Bit():
219+
is_on: bool
220+
addr: str
221+
222+
#number
223+
@dataclass
224+
class Number():
225+
value: int
226+
addr: str
227+
210228
#relay
211229
@dataclass
212230
class SimpleRelay():
@@ -278,6 +296,29 @@ def break_into_bytes(line: str):
278296
return [line[i:i+2] for i in range(0, len(line), 2)]
279297
return []
280298

299+
def xparse_formated_json(data):
300+
regex = r"state\":\{(.*)\}\}"
301+
match = re.search(regex, data)
302+
addr_val_list = []
303+
if match != None:
304+
states = match.group(1)
305+
addr_value_pair_list = states.split(',')
306+
for item in addr_value_pair_list:
307+
addr, val = item.split(':')
308+
addr_val_list.append(
309+
(addr, int(val))
310+
)
311+
return addr_val_list
312+
313+
def parse_formated_json(data):
314+
addr_val_list = []
315+
data = json.loads(data)
316+
for addr, val in data['state'].items():
317+
addr_val_list.append(
318+
(addr, val)
319+
)
320+
return addr_val_list
321+
281322
class DeviceValue(object):
282323
"""Device value interpretation object."""
283324

@@ -842,6 +883,42 @@ def __find_ha_value(self) -> None:
842883
card_present=card_present,
843884
card_id=card_id,
844885
)
886+
elif self.__inels_type is BITS:
887+
bit: list[Bit] = []
888+
for addr, val in parse_formated_json(self.__inels_status_value):
889+
bit.append(
890+
Bit(
891+
is_on=val, addr=addr
892+
)
893+
)
894+
895+
self.__ha_value = new_object(
896+
bit=bit,
897+
)
898+
899+
set_val = {}
900+
for bit in self.ha_value.bit:
901+
set_val[bit.addr] = bit.is_on
902+
903+
self.__inels_set_value = json.dumps({"cmd": set_val})
904+
elif self.__device_type is NUMBER:
905+
number: list[Number] = []
906+
for addr, val in parse_formated_json(self.__inels_status_value):
907+
number.append(
908+
Number(
909+
value=val, addr=addr
910+
)
911+
)
912+
913+
self.__ha_value = new_object(
914+
number=number,
915+
)
916+
917+
set_val = {}
918+
for number in self.ha_value.number:
919+
set_val[number.addr] = number.value
920+
921+
self.__inels_set_value = json.dumps({"cmd": set_val})
845922
elif self.__device_type is SENSOR: # temperature sensor
846923
if self.__inels_type is RF_TEMPERATURE_INPUT:
847924
battery = int(self.__trim_inels_status_values(DEVICE_TYPE_10_DATA, BATTERY, ""), 16)
@@ -1193,8 +1270,8 @@ def __find_ha_value(self) -> None:
11931270
self.__inels_set_value = DEVICE_TYPE_13_COMM_TEST
11941271
self.__ha_value = None
11951272
else:
1196-
simple_light = []
1197-
simple_light.append(
1273+
warm_light = []
1274+
warm_light.append(
11981275
WarmLight(
11991276
brightness=round(
12001277
int(self.__trim_inels_status_values(DEVICE_TYPE_13_DATA, OUT, ""), 16) * 100.0/255.0
@@ -1205,7 +1282,7 @@ def __find_ha_value(self) -> None:
12051282
),
12061283
)
12071284

1208-
self.__ha_value=new_object(simple_light=simple_light)
1285+
self.__ha_value=new_object(warm_light=warm_light)
12091286
elif self.__inels_type is DA3_22M:
12101287
temp = self.__trim_inels_status_values(DA3_22M_DATA, TEMP_IN, "")
12111288

@@ -2181,7 +2258,19 @@ def __find_inels_value(self) -> None:
21812258
elif self.__inels_type in [GCR3_11, GCH3_31]:
21822259
set_val = "04\n" if self.ha_value.simple_relay[0].is_on else "00\n"
21832260
set_val += "00\n" * 9
2184-
self.__inels_set_value = set_val
2261+
self.__inels_set_value = set_val
2262+
elif self.__inels_type is BITS:
2263+
set_val = {}
2264+
for bit in self.ha_value.bit:
2265+
set_val[bit.addr] = int(bit.is_on)
2266+
2267+
self.__inels_set_value = json.dumps({"cmd": set_val})
2268+
elif self.__device_type is NUMBER:
2269+
set_val = {}
2270+
for number in self.ha_value.number:
2271+
set_val[number.addr] = int(number.value)
2272+
2273+
self.__inels_set_value = json.dumps({"cmd": set_val})
21852274
elif self.__device_type is LIGHT:
21862275
if self.__inels_type in [RF_SINGLE_DIMMER, RF_DIMMER]:
21872276
if self.__ha_value is None:
@@ -2204,7 +2293,7 @@ def __find_inels_value(self) -> None:
22042293
if self.__ha_value is None:
22052294
self.__inels_set_value = DEVICE_TYPE_13_COMM_TEST
22062295
else:
2207-
self.__inels_set_value = f"0F\n00\n00\n00\n{round(self.ha_value.simple_light[0].brightness*2.55):02X}\n{round(self.ha_value.simple_light[0].relative_ct*2.55):02X}\n"
2296+
self.__inels_set_value = f"0F\n00\n00\n00\n{round(self.ha_value.warm_light[0].brightness*2.55):02X}\n{round(self.ha_value.warm_light[0].relative_ct*2.55):02X}\n"
22082297
elif self.__inels_type is DA3_22M:
22092298
# correct the values
22102299
out1 = round(self.__ha_value.light_coa_toa[0].brightness, -1)

setup.py

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

44
setup(
55
name="elkoep-mqtt",
6-
version="0.2.26",
6+
version="0.2.27",
77
url="https://github.com/epdevlab/elkoep-mqtt",
88
license="MIT",
99
author="Elko EP s.r.o.",

0 commit comments

Comments
 (0)