Skip to content

Commit 7e17925

Browse files
authored
Merge pull request #78 from raetha/devel
Various fixes from HclX and nabahr
2 parents 8e9b566 + 6f543ed commit 7e17925

File tree

5 files changed

+92
-40
lines changed

5 files changed

+92
-40
lines changed

.github/workflows/build.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ name: Publish to container registries
33
on:
44
release:
55
types: [ "published" ]
6+
push:
7+
branches:
8+
- devel
9+
pull_request:
10+
branches:
11+
- devel
612

713
jobs:
814
ghcr-io:
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
on:
2+
pull_request:
3+
4+
jobs:
5+
update_pr_description:
6+
name: Update Pull Request Description
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v4
10+
11+
# https://github.com/octue/generate-pull-request-description
12+
# Use the lines below in the PR description to trigger
13+
# <!--- START AUTOGENERATED NOTES --->
14+
# <!--- END AUTOGENERATED NOTES ---
15+
- uses: octue/generate-pull-request-description@1.0.0.beta-2
16+
id: pr-description
17+
with:
18+
pull_request_url: ${{ github.event.pull_request.url }}
19+
api_token: ${{ secrets.GITHUB_TOKEN }}
20+
21+
- name: Update pull request body
22+
uses: riskledger/update-pr-description@v2
23+
with:
24+
body: ${{ steps.pr-description.outputs.pull_request_description }}
25+
token: ${{ secrets.GITHUB_TOKEN }}

readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
Configurable WyzeSense to MQTT Gateway intended for use with Home Assistant or other platforms that use MQTT discovery mechanisms. The gateway allows direct local access to [Wyze Sense](https://wyze.com/wyze-sense.html) products without the need for a Wyze Cam or cloud services. This project and its dependencies have no relation to Wyze Labs Inc.
1111

12+
Please submit pull requests against the devel branch.
13+
1214
## Special Thanks
1315
* [HcLX](https://hclxing.wordpress.com) for [WyzeSensePy](https://github.com/HclX/WyzeSensePy), the core library this project uses.
1416
* [Kevin Vincent](http://kevinvincent.me) for [HA-WyzeSense](https://github.com/kevinvincent/ha-wyzesense), the reference code I used to get things working right with the calls to WyzeSensePy.

wyzesense2mqtt/wyzesense.py

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -282,17 +282,20 @@ def _OnSensorAlarm(self, pkt):
282282
sensor_type = sensor[type]
283283
sensor_state = sensor["states"][state2]
284284
else:
285-
sensor_type = "unknown (" + type + ")"
286-
sensor_state = "unknown (" + state2 + ")"
285+
sensor_type = f"unknown({type:02X})"
286+
sensor_state = f"unknown({state2:02X})"
287287
e = SensorEvent(mac, timestamp, ("alarm" if event == 0xA2 else "status"), (sensor_type, sensor_state, battery, signal))
288288
elif event == 0xE8:
289289
type, b1, battery, b2, state1, state2, counter, signal = struct.unpack_from(">BBBBBBHB", data)
290290
if type == 0x03:
291291
sensor_type = "leak:temperature"
292292
sensor_state = "%d.%d" % (state1, state2)
293-
e = SensorEvent(mac, timestamp, "state", (sensor_type, sensor_state, battery, signal))
293+
else:
294+
sensor_type = f"unknown({type:02X})"
295+
sensor_state = f"unknown({state2:02X})"
296+
e = SensorEvent(mac, timestamp, "status", (sensor_type, sensor_state, battery, signal))
294297
else:
295-
e = SensorEvent(mac, timestamp, "%02X" % event, data)
298+
e = SensorEvent(mac, timestamp, f"{event:02X}", data)
296299

297300
self.__on_event(self, e)
298301

@@ -322,6 +325,7 @@ def __init__(self, device, event_handler):
322325
self.__exit_event = threading.Event()
323326
self.__thread = threading.Thread(target=self._Worker)
324327
self.__on_event = event_handler
328+
self.__last_exception = None
325329

326330
self.__handlers = {
327331
Packet.NOTIFY_SYNC_TIME: self._OnSyncTime,
@@ -377,42 +381,46 @@ def _HandlePacket(self, pkt):
377381
handler(pkt)
378382

379383
def _Worker(self):
380-
s = b""
381-
while True:
382-
if self.__exit_event.isSet():
383-
break
384-
385-
s += self._ReadRawHID()
386-
# if s:
387-
# LOGGER.info("Incoming buffer: %s", bytes_to_hex(s))
388-
389-
# Look for the start of the next message, indicated by the magic bytes 0x55AA
390-
start = s.find(b"\x55\xAA")
391-
if start == -1:
392-
time.sleep(0.1)
393-
continue
394-
395-
# Found the start of the next message, ideally this would be at the beginning of the buffer
396-
# but we could be tossing some bad data if a previous parse failed
397-
s = s[start:]
398-
LOGGER.debug("Trying to parse: %s", bytes_to_hex(s))
399-
try:
400-
pkt = Packet.Parse(s)
401-
if not pkt:
402-
# Packet was invalid and couldn't be processed, remove the magic bytes and continue
403-
# looking for another start of message. This essentially tosses the bad message.
404-
LOGGER.error("Unable to parse message")
405-
s = s[2:]
384+
try:
385+
s = b""
386+
while True:
387+
if self.__exit_event.isSet():
388+
break
389+
390+
s += self._ReadRawHID()
391+
# if s:
392+
# LOGGER.info("Incoming buffer: %s", bytes_to_hex(s))
393+
394+
# Look for the start of the next message, indicated by the magic bytes 0x55AA
395+
start = s.find(b"\x55\xAA")
396+
if start == -1:
397+
time.sleep(0.1)
398+
continue
399+
400+
# Found the start of the next message, ideally this would be at the beginning of the buffer
401+
# but we could be tossing some bad data if a previous parse failed
402+
s = s[start:]
403+
LOGGER.debug("Trying to parse: %s", bytes_to_hex(s))
404+
try:
405+
pkt = Packet.Parse(s)
406+
if not pkt:
407+
# Packet was invalid and couldn't be processed, remove the magic bytes and continue
408+
# looking for another start of message. This essentially tosses the bad message.
409+
LOGGER.error("Unable to parse message")
410+
s = s[2:]
411+
time.sleep(0.1)
412+
continue
413+
except EOFError:
414+
# Not enough data to parse a packet, keep the partial packet for now
406415
time.sleep(0.1)
407416
continue
408-
except EOFError:
409-
# Not enough data to parse a packet, keep the partial packet for now
410-
time.sleep(0.1)
411-
continue
412417

413-
LOGGER.debug("Received: %s", bytes_to_hex(s[:pkt.Length]))
414-
s = s[pkt.Length:]
415-
self._HandlePacket(pkt)
418+
LOGGER.debug("Received: %s", bytes_to_hex(s[:pkt.Length]))
419+
s = s[pkt.Length:]
420+
self._HandlePacket(pkt)
421+
except Exception as e:
422+
LOGGER.error("Error occured in dongle worker thread", exc_info=True)
423+
self.__last_exception = e
416424

417425
def _DoCommand(self, pkt, handler, timeout=_CMD_TIMEOUT):
418426
e = threading.Event()
@@ -547,6 +555,10 @@ def _Start(self):
547555
def List(self):
548556
sensors = self._GetSensors()
549557
return sensors
558+
559+
def CheckError(self):
560+
if self.__last_exception:
561+
raise self.__last_exception
550562

551563
def Stop(self, timeout=_CMD_TIMEOUT):
552564
self.__exit_event.set()

wyzesense2mqtt/wyzesense2mqtt.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ def init_config():
117117
CONFIG = read_yaml_file(os.path.join(SAMPLES_PATH, MAIN_CONFIG_FILE))
118118

119119
# load user config over base
120+
user_config = None
120121
if (os.path.isfile(os.path.join(CONFIG_PATH, MAIN_CONFIG_FILE))):
121122
user_config = read_yaml_file(os.path.join(CONFIG_PATH, MAIN_CONFIG_FILE))
122123
CONFIG.update(user_config)
@@ -127,7 +128,7 @@ def init_config():
127128
exit(1)
128129

129130
# write updated config file if needed
130-
if (CONFIG != user_config):
131+
if (user_config is None or CONFIG != user_config):
131132
LOGGER.info("Writing updated config file")
132133
write_yaml_file(os.path.join(CONFIG_PATH, MAIN_CONFIG_FILE), CONFIG)
133134

@@ -344,9 +345,11 @@ def delete_sensor_from_config(sensor_mac):
344345
# Publish MQTT topic
345346
def mqtt_publish(mqtt_topic, mqtt_payload, is_json=True, wait=True):
346347
global MQTT_CLIENT, CONFIG
348+
payload = json.dumps(mqtt_payload) if is_json else mqtt_payload
349+
LOGGER.debug(f"Publishing, {mqtt_topic=}, {payload=}")
347350
mqtt_message_info = MQTT_CLIENT.publish(
348351
mqtt_topic,
349-
payload=(json.dumps(mqtt_payload) if is_json else mqtt_payload),
352+
payload=payload,
350353
qos=CONFIG['mqtt_qos'],
351354
retain=CONFIG['mqtt_retain']
352355
)
@@ -670,6 +673,8 @@ def Stop():
670673
loop_counter = 0
671674
while True:
672675
time.sleep(5)
676+
# Check if there is any exceptions in the dongle thread
677+
WYZESENSE_DONGLE.CheckError()
673678

674679
# Skip everything while dongle is offline, service needs to be restarted
675680
if dongle_offline:
@@ -715,6 +720,8 @@ def Stop():
715720
LOGGER.warning(f"{mac} has gone offline!")
716721
SENSORS_STATE[mac]['online'] = False
717722
except KeyboardInterrupt:
718-
pass
723+
LOGGER.warning("User interrupted")
724+
except Exception as e:
725+
LOGGER.error("An error occurred", exc_info=True)
719726
finally:
720727
Stop()

0 commit comments

Comments
 (0)