Skip to content

Commit d3fb2d6

Browse files
Clean up error handling, make sure disconnect is called
* Issue #4 - Clean up error handling, make sure disconnect is called correctly after write. Improve retry logic to also include retrying if the connection attempt fails. Finally logging has been improved. * Fix import style * Add support for user configurable retry count * Set reasonable retry wait * Fix up PR comments from @Danielhiversen * Update readme * Switchbot readme pic * Switchbot readme pic * fix pr
1 parent 86e6af4 commit d3fb2d6

File tree

2 files changed

+59
-34
lines changed

2 files changed

+59
-34
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# pySwitchbot [![Build Status](https://travis-ci.org/Danielhiversen/pySwitchbot.svg?branch=master)](https://travis-ci.org/Danielhiversen/pySwitchbot)
2-
Library to control Switchbot
2+
Library to control Switchbot IoT devices https://www.switch-bot.com/bot
33

44
[Buy me a coffee :)](http://paypal.me/dahoiv)

switchbot/__init__.py

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
"""Library to handle connection with Switchbot"""
2+
import time
23

34
import binascii
45
import logging
56

67
import bluepy
78

9+
DEFAULT_RETRY_COUNT = 3
10+
DEFAULT_RETRY_TIMEOUT = .2
11+
812
UUID = "cba20d00-224d-11e6-9fb8-0002a5d5c51b"
913
HANDLE = "cba20002-224d-11e6-9fb8-0002a5d5c51b"
1014

@@ -18,53 +22,74 @@
1822
class Switchbot:
1923
"""Representation of a Switchbot."""
2024

21-
def __init__(self, mac) -> None:
25+
def __init__(self, mac, retry_count=DEFAULT_RETRY_COUNT) -> None:
2226
self._mac = mac
2327
self._device = None
28+
self._retry_count = retry_count
2429

25-
def _connect(self) -> bool:
30+
def _connect(self) -> None:
2631
if self._device is not None:
27-
_LOGGER.debug("Disconnecting")
28-
try:
29-
self._device.disconnect()
30-
except bluepy.btle.BTLEException:
31-
pass
32+
return
3233
try:
33-
_LOGGER.debug("Connecting")
34+
_LOGGER.debug("Connecting to Switchbot...")
3435
self._device = bluepy.btle.Peripheral(self._mac,
3536
bluepy.btle.ADDR_TYPE_RANDOM)
37+
_LOGGER.debug("Connected to Switchbot.")
3638
except bluepy.btle.BTLEException:
37-
_LOGGER.warning("Failed to connect to Switchbot", exc_info=True)
38-
return False
39-
return True
39+
_LOGGER.debug("Failed connecting to Switchbot.", exc_info=True)
40+
self._device = None
41+
raise
4042

41-
def _sendpacket(self, key, retry=2) -> bool:
42-
if self._device is None and not self._connect():
43-
_LOGGER.error("Can not connect to switchbot.")
44-
return False
43+
def _disconnect(self) -> None:
44+
if self._device is None:
45+
return
46+
_LOGGER.debug("Disconnecting")
47+
try:
48+
self._device.disconnect()
49+
except bluepy.btle.BTLEException:
50+
_LOGGER.warning("Error disconnecting from Switchbot.", exc_info=True)
51+
finally:
52+
self._device = None
53+
54+
def _writekey(self, key) -> bool:
55+
_LOGGER.debug("Prepare to send")
56+
hand_service = self._device.getServiceByUUID(UUID)
57+
hand = hand_service.getCharacteristics(HANDLE)[0]
58+
_LOGGER.debug("Sending command, %s", key)
59+
write_result = hand.write(binascii.a2b_hex(key), withResponse=True)
60+
if not write_result:
61+
_LOGGER.error("Sent command but didn't get a response from Switchbot confirming command was sent. "
62+
"Please check the Switchbot.")
63+
else:
64+
_LOGGER.info("Successfully sent command to Switchbot (MAC: %s).", self._mac)
65+
return write_result
4566

67+
def _sendcommand(self, key, retry) -> bool:
68+
send_success = False
4669
try:
47-
_LOGGER.debug("Prepare to send")
48-
hand_service = self._device.getServiceByUUID(UUID)
49-
hand = hand_service.getCharacteristics(HANDLE)[0]
50-
_LOGGER.debug("Sending command, %s", key)
51-
hand.write(binascii.a2b_hex(key))
70+
self._connect()
71+
send_success = self._writekey(key)
5272
except bluepy.btle.BTLEException:
53-
if retry < 1 or not self._connect():
54-
_LOGGER.error("Can not connect to switchbot.", exc_info=True)
55-
return False
56-
_LOGGER.warning("Can not connect to switchbot. Retrying")
57-
return self._sendpacket(key, retry-1)
58-
return True
59-
60-
def turn_on(self) -> None:
73+
_LOGGER.warning("Error talking to Switchbot.", exc_info=True)
74+
finally:
75+
self._disconnect()
76+
if send_success:
77+
return send_success
78+
if retry < 1:
79+
_LOGGER.error("Switchbot communication failed. Stopping trying.", exc_info=True)
80+
return False
81+
_LOGGER.warning("Cannot connect to Switchbot. Retrying (remaining: %d)...", retry)
82+
time.sleep(DEFAULT_RETRY_TIMEOUT)
83+
return self._sendcommand(key, retry - 1)
84+
85+
def turn_on(self) -> bool:
6186
"""Turn device on."""
62-
return self._sendpacket(ON_KEY)
87+
return self._sendcommand(ON_KEY, self._retry_count)
6388

64-
def turn_off(self) -> None:
89+
def turn_off(self) -> bool:
6590
"""Turn device off."""
66-
return self._sendpacket(OFF_KEY)
91+
return self._sendcommand(OFF_KEY, self._retry_count)
6792

68-
def press(self) -> None:
93+
def press(self) -> bool:
6994
"""Press command to device."""
70-
return self._sendpacket(PRESS_KEY)
95+
return self._sendcommand(PRESS_KEY, self._retry_count)

0 commit comments

Comments
 (0)