Skip to content

Commit

Permalink
feature: periodic send query packet
Browse files Browse the repository at this point in the history
  • Loading branch information
YOGYUI committed Mar 22, 2024
1 parent 1c77e2d commit cd2a6e8
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Hillstate-Gwanggyosan/Include/Define/AirConditioner.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def updateState(self, state: int, **kwargs):

def makePacketQueryState(self) -> bytearray:
# F7 0B 01 1C 01 40 XX 00 00 YY EE
# XX: 상위 4비트=공간 인덱스, 하위 4비트=디바이스 인덱스 (1-based
# XX: 상위 4비트=공간 인덱스, 하위 4비트=디바이스 인덱스 (1-based)
# YY: Checksum (XOR SUM)
packet = bytearray([0xF7, 0x0B, 0x01, 0x1C, 0x01, 0x40])
packet.append((self.room_index << 4) + (self.index + 1))
Expand Down
7 changes: 6 additions & 1 deletion Hillstate-Gwanggyosan/Include/Define/GasValve.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,12 @@ def configMQTT(self, retain: bool = False):

def makePacketQueryState(self) -> bytearray:
# F7 0B 01 1B 01 43 11 00 00 B5 EE
return bytearray([0xF7, 0x0B, 0x01, 0x1B, 0x01, 0x43, 0x11, 0x00, 0x00, 0xB5, 0xEE])
packet = bytearray([0xF7, 0x0B, 0x01, 0x1B, 0x01, 0x43])
packet.append(0x11)
packet.extend([0x00, 0x00])
packet.append(self.calcXORChecksum(packet))
packet.append(0xEE)
return packet

def makePacketSetState(self, state: bool) -> bytearray:
# F7 0B 01 1B 02 43 11 XX 00 YY EE
Expand Down
3 changes: 2 additions & 1 deletion Hillstate-Gwanggyosan/Include/Define/Light.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def makePacketQueryState(self) -> bytearray:
# XX: 상위 4비트 = Room Index, 하위 4비트 = 0
# YY: Checksum (XOR SUM)
packet = bytearray([0xF7, 0x0B, 0x01, 0x19, 0x01, 0x40])
packet.append(self.room_index << 4)
# packet.append(self.room_index << 4)
packet.append((self.room_index << 4) + (self.index + 1))
packet.extend([0x00, 0x00])
packet.append(self.calcXORChecksum(packet))
packet.append(0xEE)
Expand Down
3 changes: 2 additions & 1 deletion Hillstate-Gwanggyosan/Include/Define/Outlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ def makePacketQueryState(self) -> bytearray:
# XX: 상위 4비트 = Room Index, 하위 4비트 = 0
# YY: Checksum (XOR SUM)
packet = bytearray([0xF7, 0x0B, 0x01, 0x1F, 0x01, 0x40])
packet.append(self.room_index << 4)
# packet.append(self.room_index << 4)
packet.append((self.room_index << 4) + (self.index + 1))
packet.extend([0x00, 0x00])
packet.append(self.calcXORChecksum(packet))
packet.append(0xEE)
Expand Down
3 changes: 2 additions & 1 deletion Hillstate-Gwanggyosan/Include/Define/Thermostat.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ def makePacketQueryState(self) -> bytearray:
# F7 0B 01 18 01 46 10 00 00 XX EE
# XX: Checksum (XOR SUM)
packet = bytearray([0xF7, 0x0B, 0x01, 0x18, 0x01, 0x46])
packet.extend([0x10, 0x00, 0x00])
packet.append(0x10 + self.room_index)
packet.extend([0x00, 0x00])
packet.append(self.calcXORChecksum(packet))
packet.append(0xEE)
return packet
Expand Down
3 changes: 2 additions & 1 deletion Hillstate-Gwanggyosan/Include/Define/Ventilator.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ def makePacketQueryState(self) -> bytearray:
# F7 0B 01 2B 01 40 11 00 00 XX EE
# XX: Checksum (XOR SUM)
packet = bytearray([0xF7, 0x0B, 0x01, 0x2B, 0x01, 0x40])
packet.extend([0x11, 0x00, 0x00])
packet.append(0x11)
packet.extend([0x00, 0x00])
packet.append(self.calcXORChecksum(packet))
packet.append(0xEE)
return packet
Expand Down
101 changes: 79 additions & 22 deletions Hillstate-Gwanggyosan/Include/Home.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class Home:
thread_timer: Union[ThreadTimer, None] = None
thread_energy_monitor: Union[ThreadEnergyMonitor, None] = None
thread_discovery: Union[ThreadDiscovery, None] = None
thread_query_state: Union[ThreadQueryState, None] = None
queue_command: queue.Queue
queue_parse_result: queue.Queue

Expand Down Expand Up @@ -88,6 +89,10 @@ class Home:

verbose_unreg_dev_packet: bool = False

enable_periodic_query_state: bool = False
query_state_period: int = 1000
verbose_periodic_query_state: bool = False

def __init__(self, name: str = 'Home', init_service: bool = True, config_file_path: str = None):
self.name = name
self.device_list = list()
Expand Down Expand Up @@ -121,6 +126,8 @@ def initialize(self, init_service: bool, connect_rs485: bool):
self.startThreadCommandQueue()
self.startThreadParseResultQueue()
self.startThreadTimer()
if self.enable_periodic_query_state:
self.startThreadQueryState()
try:
self.mqtt_client.connect(self.mqtt_host, self.mqtt_port)
except Exception as e:
Expand Down Expand Up @@ -172,6 +179,7 @@ def release(self):
self.stopThreadCommandQueue()
self.stopThreadParseResultQueue()
self.stopThreadTimer()
self.stopThreadQueryState()

for elem in self.rs485_info_list:
elem.release()
Expand Down Expand Up @@ -469,6 +477,24 @@ def loadDeviceConfig(self, node: ET.Element):
if enable_discovery:
self.startDiscoverDevice()

periodic_query_state_node = node.find('periodic_query_state')
if periodic_query_state_node is not None:
try:
enable_node = periodic_query_state_node.find('enable')
self.enable_periodic_query_state = bool(int(enable_node.text))
except Exception as e:
writeLog(f"Failed to read <periodic_query_state> - <enable> node ({e})", self)
try:
period_node = periodic_query_state_node.find('period')
self.query_state_period = int(period_node.text)
except Exception as e:
writeLog(f"Failed to read <periodic_query_state> - <period> node ({e})", self)
try:
verbose_node = periodic_query_state_node.find('verbose')
self.verbose_periodic_query_state = bool(int(verbose_node.text))
except Exception as e:
writeLog(f"Failed to read <periodic_query_state> - <verbose> node ({e})", self)

entry_node = node.find('entry')
dev_entry_cnt = len(list(entry_node))
for dev_node in list(entry_node):
Expand Down Expand Up @@ -645,6 +671,8 @@ def onRS485SubPhoneConnected(self):
def startThreadCommandQueue(self):
if self.thread_cmd_queue is None:
self.thread_cmd_queue = ThreadCommandQueue(self.queue_command)
self.thread_cmd_queue.sig_start_seq.connect(self.onThreadCommandQueueStartSequence)
self.thread_cmd_queue.sig_finish_seq.connect(self.onThreadCommandQueueFinishSequence)
self.thread_cmd_queue.sig_terminated.connect(self.onThreadCommandQueueTerminated)
self.thread_cmd_queue.setDaemon(True)
self.thread_cmd_queue.start()
Expand All @@ -657,6 +685,14 @@ def onThreadCommandQueueTerminated(self):
del self.thread_cmd_queue
self.thread_cmd_queue = None

def onThreadCommandQueueStartSequence(self):
if self.thread_query_state is not None:
self.thread_query_state.setAvailable(False)

def onThreadCommandQueueFinishSequence(self):
if self.thread_query_state is not None:
self.thread_query_state.setAvailable(True)

def startThreadParseResultQueue(self):
if self.thread_parse_result_queue is None:
self.thread_parse_result_queue = ThreadParseResultQueue(self.queue_parse_result)
Expand Down Expand Up @@ -723,6 +759,27 @@ def onThreadEnergyMonitorTerminated(self):
del self.thread_energy_monitor
self.thread_energy_monitor = None

def startThreadQueryState(self):
if self.thread_query_state is None:
self.thread_query_state = ThreadQueryState(
self.device_list,
self.parser_mapping,
self.rs485_info_list,
self.query_state_period,
self.verbose_periodic_query_state
)
self.thread_query_state.sig_terminated.connect(self.onThreadQueryStateTerminated)
self.thread_query_state.setDaemon(True)
self.thread_query_state.start()

def stopThreadQueryState(self):
if self.thread_query_state is not None:
self.thread_query_state.stop()

def onThreadQueryStateTerminated(self):
del self.thread_query_state
self.thread_query_state = None

def publish_all(self):
for dev in self.device_list:
try:
Expand Down Expand Up @@ -829,26 +886,26 @@ def isSubphoneActivated(self) -> bool:
def isHEMSActivated(self) -> bool:
return self.findDevice(DeviceType.HEMS, 0, 0) is not None

def command(self, **kwargs):
def send_command(self, **kwargs):
try:
dev: Device = kwargs['device']
dev_type: DeviceType = dev.getType()
index = self.parser_mapping.get(dev_type)
info: RS485Info = self.rs485_info_list[index]
kwargs['parser'] = info.parser
except Exception as e:
writeLog('command Exception::{}'.format(e), self)
writeLog('send_command Exception::{}'.format(e), self)
self.queue_command.put(kwargs)

def onDeviceSetState(self, dev: Device, state: int):
if isinstance(dev, AirConditioner):
self.command(
self.send_command(
device=dev,
category='active',
target=state
)
elif isinstance(dev, Thermostat):
self.command(
self.send_command(
device=dev,
category='state',
target='HEAT' if state else 'OFF'
Expand Down Expand Up @@ -989,7 +1046,7 @@ def onMqttCommandLight(self, topic: str, message: dict):
device = self.findDevice(DeviceType.LIGHT, dev_idx, room_idx)
if device is not None:
if 'state' in message.keys():
self.command(
self.send_command(
device=device,
category='state',
target=message['state']
Expand All @@ -1006,7 +1063,7 @@ def onMqttCommandOutlet(self, topic: str, message: dict):
device = self.findDevice(DeviceType.OUTLET, dev_idx, room_idx)
if device is not None:
if 'state' in message.keys():
self.command(
self.send_command(
device=device,
category='state',
target=message['state']
Expand All @@ -1023,7 +1080,7 @@ def onMqttCommandGasvalve(self, topic: str, message: dict):
device = self.findDevice(DeviceType.GASVALVE, dev_idx, room_idx)
if device is not None:
if 'state' in message.keys():
self.command(
self.send_command(
device=device,
category='state',
target=message['state']
Expand All @@ -1040,13 +1097,13 @@ def onMqttCommandThermostat(self, topic: str, message: dict):
device = self.findDevice(DeviceType.THERMOSTAT, dev_idx, room_idx)
if device is not None:
if 'state' in message.keys():
self.command(
self.send_command(
device=device,
category='state',
target=message['state']
)
if 'targetTemperature' in message.keys():
self.command(
self.send_command(
device=device,
category='temperature',
target=message['targetTemperature']
Expand All @@ -1068,7 +1125,7 @@ def onMqttCommandVentilator(self, topic: str, message: dict):
device = self.findDevice(DeviceType.VENTILATOR, dev_idx, room_idx)
if device is not None:
if 'state' in message.keys():
self.command(
self.send_command(
device=device,
category='state',
target=message['state']
Expand All @@ -1077,7 +1134,7 @@ def onMqttCommandVentilator(self, topic: str, message: dict):
if device.state == 1:
# 전원이 켜져있을 경우에만 풍량설정 가능하도록..
# 최초 전원 ON시 풍량 '약'으로 설정!
self.command(
self.send_command(
device=device,
category='rotationspeed',
target=message['rotationspeed']
Expand All @@ -1094,27 +1151,27 @@ def onMqttCommandAirconditioner(self, topic: str, message: dict):
device = self.findDevice(DeviceType.AIRCONDITIONER, dev_idx, room_idx)
if device is not None:
if 'active' in message.keys():
self.command(
self.send_command(
device=device,
category='active',
target=message['active']
)
if 'targetTemperature' in message.keys():
self.command(
self.send_command(
device=device,
category='temperature',
target=message['targetTemperature']
)
if 'rotationspeed' in message.keys():
self.command(
self.send_command(
device=device,
category='rotationspeed',
target=message['rotationspeed']
)
if 'rotationspeed_name' in message.keys(): # for HA
speed_dict = {'Max': 100, 'Medium': 75, 'Min': 50, 'Auto': 25}
target = speed_dict[message['rotationspeed_name']]
self.command(
self.send_command(
device=device,
category='rotationspeed',
target=target
Expand All @@ -1136,7 +1193,7 @@ def onMqttCommandElevator(self, topic: str, message: dict):
device = self.findDevice(DeviceType.ELEVATOR, dev_idx, room_idx)
if device is not None:
if 'state' in message.keys():
self.command(
self.send_command(
device=device,
category='state',
target=message['state']
Expand All @@ -1153,26 +1210,26 @@ def onMqttCommandSubPhone(self, topic: str, message: dict):
device = self.findDevice(DeviceType.SUBPHONE, dev_idx, room_idx)
if device is not None:
if 'streaming_state' in message.keys():
self.command(
self.send_command(
device=device,
category='streaming',
target=message['streaming_state']
)
if 'doorlock_state' in message.keys():
self.command(
self.send_command(
device=device,
category='doorlock',
target=message['doorlock_state']
)
# 세대현관문, 공동현관문 분리
if 'lock_front_state' in message.keys():
self.command(
self.send_command(
device=device,
category='lock_front',
target=message['lock_front_state']
)
if 'lock_communal_state' in message.keys():
self.command(
self.send_command(
device=device,
category='lock_communal',
target=message['lock_communal_state']
Expand All @@ -1198,7 +1255,7 @@ def onMqttCommandBatchOffSwitch(self, topic: str, message: dict):
device = self.findDevice(DeviceType.BATCHOFFSWITCH, dev_idx, room_idx)
if device is not None:
if 'state' in message.keys():
self.command(
self.send_command(
device=device,
category='state',
target=message['state']
Expand Down Expand Up @@ -1281,7 +1338,7 @@ def stopFFMpeg(self):
"""
def onMqttCommandDookLock(self, topic: str, message: dict):
if 'state' in message.keys():
self.command(
self.send_command(
device=self.doorlock,
category='state',
target=message['state']
Expand Down
4 changes: 4 additions & 0 deletions Hillstate-Gwanggyosan/Include/Threads/ThreadCommandQueue.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def __init__(self, queue_: queue.Queue):
self._queue = queue_
self._retry_cnt = 10
self._delay_response = 0.4
self.sig_start_seq = Callback()
self.sig_finish_seq = Callback()
self.sig_terminated = Callback()

def run(self):
Expand All @@ -46,6 +48,7 @@ def run(self):
writeLog('parser is not designated', self)
continue

self.sig_start_seq.emit()
if isinstance(dev, Light):
if category == 'state':
self.set_state_common(dev, target, parser)
Expand Down Expand Up @@ -109,6 +112,7 @@ def run(self):
if target == 'Unsecured':
self.set_doorlock_open(dev, parser)
"""
self.sig_finish_seq.emit()
except Exception as e:
writeLog(str(e), self)
else:
Expand Down

0 comments on commit cd2a6e8

Please sign in to comment.