mirror of
https://github.com/mjg59/python-broadlink.git
synced 2024-11-22 07:00:12 +01:00
Raise exceptions for errors (#356)
* Raise exceptions for errors * Fix lb1 error check * Fix typo * Improve code readability * Fix exception
This commit is contained in:
parent
5e444988e1
commit
3216b069f0
@ -12,6 +12,7 @@ from datetime import datetime
|
|||||||
from cryptography.hazmat.backends import default_backend
|
from cryptography.hazmat.backends import default_backend
|
||||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||||
|
|
||||||
|
from .exceptions import check_error, exception
|
||||||
|
|
||||||
def gendevice(devtype, host, mac, name=None, cloud=None):
|
def gendevice(devtype, host, mac, name=None, cloud=None):
|
||||||
devices = {
|
devices = {
|
||||||
@ -221,10 +222,7 @@ class device:
|
|||||||
payload[0x36] = ord('1')
|
payload[0x36] = ord('1')
|
||||||
|
|
||||||
response = self.send_packet(0x65, payload)
|
response = self.send_packet(0x65, payload)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
if any(response[0x22:0x24]):
|
|
||||||
return False
|
|
||||||
|
|
||||||
payload = self.decrypt(response[0x38:])
|
payload = self.decrypt(response[0x38:])
|
||||||
|
|
||||||
key = payload[0x04:0x14]
|
key = payload[0x04:0x14]
|
||||||
@ -301,7 +299,7 @@ class device:
|
|||||||
break
|
break
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
if (time.time() - start_time) > self.timeout:
|
if (time.time() - start_time) > self.timeout:
|
||||||
raise
|
raise exception(0xfffd)
|
||||||
finally:
|
finally:
|
||||||
cs.close()
|
cs.close()
|
||||||
return bytearray(response[0])
|
return bytearray(response[0])
|
||||||
@ -328,7 +326,8 @@ class mp1(device):
|
|||||||
packet[0x0d] = sid_mask
|
packet[0x0d] = sid_mask
|
||||||
packet[0x0e] = sid_mask if state else 0
|
packet[0x0e] = sid_mask if state else 0
|
||||||
|
|
||||||
self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
|
|
||||||
def set_power(self, sid, state):
|
def set_power(self, sid, state):
|
||||||
"""Sets the power state of the smart power strip."""
|
"""Sets the power state of the smart power strip."""
|
||||||
@ -348,9 +347,7 @@ class mp1(device):
|
|||||||
packet[0x08] = 0x01
|
packet[0x08] = 0x01
|
||||||
|
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if isinstance(payload[0x4], int):
|
if isinstance(payload[0x4], int):
|
||||||
state = payload[0x0e]
|
state = payload[0x0e]
|
||||||
@ -384,6 +381,7 @@ class bg1(device):
|
|||||||
eg. `{"pwr":1,"pwr1":1,"pwr2":0,"maxworktime":60,"maxworktime1":60,"maxworktime2":0,"idcbrightness":50}`"""
|
eg. `{"pwr":1,"pwr1":1,"pwr2":0,"maxworktime":60,"maxworktime1":60,"maxworktime2":0,"idcbrightness":50}`"""
|
||||||
packet = self._encode(1, b'{}')
|
packet = self._encode(1, b'{}')
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
return self._decode(response)
|
return self._decode(response)
|
||||||
|
|
||||||
def set_state(self, pwr=None, pwr1=None, pwr2=None, maxworktime=None, maxworktime1=None, maxworktime2=None, idcbrightness=None):
|
def set_state(self, pwr=None, pwr1=None, pwr2=None, maxworktime=None, maxworktime1=None, maxworktime2=None, idcbrightness=None):
|
||||||
@ -405,6 +403,7 @@ class bg1(device):
|
|||||||
js = json.dumps(data).encode('utf8')
|
js = json.dumps(data).encode('utf8')
|
||||||
packet = self._encode(2, js)
|
packet = self._encode(2, js)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
return self._decode(response)
|
return self._decode(response)
|
||||||
|
|
||||||
def _encode(self, flag, js):
|
def _encode(self, flag, js):
|
||||||
@ -432,10 +431,6 @@ class bg1(device):
|
|||||||
return packet
|
return packet
|
||||||
|
|
||||||
def _decode(self, response):
|
def _decode(self, response):
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
js_len = struct.unpack_from('<I', payload, 0x0a)[0]
|
js_len = struct.unpack_from('<I', payload, 0x0a)[0]
|
||||||
state = json.loads(payload[0x0e:0x0e+js_len])
|
state = json.loads(payload[0x0e:0x0e+js_len])
|
||||||
@ -449,7 +444,8 @@ class sp1(device):
|
|||||||
def set_power(self, state):
|
def set_power(self, state):
|
||||||
packet = bytearray(4)
|
packet = bytearray(4)
|
||||||
packet[0] = state
|
packet[0] = state
|
||||||
self.send_packet(0x66, packet)
|
response = self.send_packet(0x66, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
|
|
||||||
|
|
||||||
class sp2(device):
|
class sp2(device):
|
||||||
@ -465,7 +461,8 @@ class sp2(device):
|
|||||||
packet[4] = 3 if state else 2
|
packet[4] = 3 if state else 2
|
||||||
else:
|
else:
|
||||||
packet[4] = 1 if state else 0
|
packet[4] = 1 if state else 0
|
||||||
self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
|
|
||||||
def set_nightlight(self, state):
|
def set_nightlight(self, state):
|
||||||
"""Sets the night light state of the smart plug"""
|
"""Sets the night light state of the smart plug"""
|
||||||
@ -475,16 +472,15 @@ class sp2(device):
|
|||||||
packet[4] = 3 if state else 1
|
packet[4] = 3 if state else 1
|
||||||
else:
|
else:
|
||||||
packet[4] = 2 if state else 0
|
packet[4] = 2 if state else 0
|
||||||
self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
|
|
||||||
def check_power(self):
|
def check_power(self):
|
||||||
"""Returns the power state of the smart plug."""
|
"""Returns the power state of the smart plug."""
|
||||||
packet = bytearray(16)
|
packet = bytearray(16)
|
||||||
packet[0] = 1
|
packet[0] = 1
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if isinstance(payload[0x4], int):
|
if isinstance(payload[0x4], int):
|
||||||
return bool(payload[0x4] == 1 or payload[0x4] == 3 or payload[0x4] == 0xFD)
|
return bool(payload[0x4] == 1 or payload[0x4] == 3 or payload[0x4] == 0xFD)
|
||||||
@ -495,9 +491,7 @@ class sp2(device):
|
|||||||
packet = bytearray(16)
|
packet = bytearray(16)
|
||||||
packet[0] = 1
|
packet[0] = 1
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if isinstance(payload[0x4], int):
|
if isinstance(payload[0x4], int):
|
||||||
return bool(payload[0x4] == 2 or payload[0x4] == 3 or payload[0x4] == 0xFF)
|
return bool(payload[0x4] == 2 or payload[0x4] == 3 or payload[0x4] == 0xFF)
|
||||||
@ -506,9 +500,7 @@ class sp2(device):
|
|||||||
def get_energy(self):
|
def get_energy(self):
|
||||||
packet = bytearray([8, 0, 254, 1, 5, 1, 0, 0, 0, 45])
|
packet = bytearray([8, 0, 254, 1, 5, 1, 0, 0, 0, 45])
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if isinstance(payload[0x7], int):
|
if isinstance(payload[0x7], int):
|
||||||
energy = int(hex(payload[0x07] * 256 + payload[0x06])[2:]) + int(hex(payload[0x05])[2:]) / 100.0
|
energy = int(hex(payload[0x07] * 256 + payload[0x06])[2:]) + int(hex(payload[0x05])[2:]) / 100.0
|
||||||
@ -527,9 +519,7 @@ class a1(device):
|
|||||||
packet = bytearray(16)
|
packet = bytearray(16)
|
||||||
packet[0] = 1
|
packet[0] = 1
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
data = {}
|
data = {}
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if isinstance(payload[0x4], int):
|
if isinstance(payload[0x4], int):
|
||||||
@ -578,9 +568,7 @@ class a1(device):
|
|||||||
packet = bytearray(16)
|
packet = bytearray(16)
|
||||||
packet[0] = 1
|
packet[0] = 1
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
data = {}
|
data = {}
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if isinstance(payload[0x4], int):
|
if isinstance(payload[0x4], int):
|
||||||
@ -609,9 +597,7 @@ class rm(device):
|
|||||||
packet = bytearray(self._request_header)
|
packet = bytearray(self._request_header)
|
||||||
packet.append(0x04)
|
packet.append(0x04)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
return payload[len(self._request_header) + 4:]
|
return payload[len(self._request_header) + 4:]
|
||||||
|
|
||||||
@ -619,30 +605,32 @@ class rm(device):
|
|||||||
packet = bytearray(self._code_sending_header)
|
packet = bytearray(self._code_sending_header)
|
||||||
packet += bytes([0x02, 0x00, 0x00, 0x00])
|
packet += bytes([0x02, 0x00, 0x00, 0x00])
|
||||||
packet += data
|
packet += data
|
||||||
self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
|
|
||||||
def enter_learning(self):
|
def enter_learning(self):
|
||||||
packet = bytearray(self._request_header)
|
packet = bytearray(self._request_header)
|
||||||
packet.append(0x03)
|
packet.append(0x03)
|
||||||
self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
|
|
||||||
def sweep_frequency(self):
|
def sweep_frequency(self):
|
||||||
packet = bytearray(self._request_header)
|
packet = bytearray(self._request_header)
|
||||||
packet.append(0x19)
|
packet.append(0x19)
|
||||||
self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
|
|
||||||
def cancel_sweep_frequency(self):
|
def cancel_sweep_frequency(self):
|
||||||
packet = bytearray(self._request_header)
|
packet = bytearray(self._request_header)
|
||||||
packet.append(0x1e)
|
packet.append(0x1e)
|
||||||
self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
|
|
||||||
def check_frequency(self):
|
def check_frequency(self):
|
||||||
packet = bytearray(self._request_header)
|
packet = bytearray(self._request_header)
|
||||||
packet.append(0x1a)
|
packet.append(0x1a)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return False
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if payload[len(self._request_header) + 4] == 1:
|
if payload[len(self._request_header) + 4] == 1:
|
||||||
return True
|
return True
|
||||||
@ -652,9 +640,7 @@ class rm(device):
|
|||||||
packet = bytearray(self._request_header)
|
packet = bytearray(self._request_header)
|
||||||
packet.append(0x1b)
|
packet.append(0x1b)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return False
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if payload[len(self._request_header) + 4] == 1:
|
if payload[len(self._request_header) + 4] == 1:
|
||||||
return True
|
return True
|
||||||
@ -664,9 +650,7 @@ class rm(device):
|
|||||||
packet = bytearray(self._request_header)
|
packet = bytearray(self._request_header)
|
||||||
packet.append(type)
|
packet.append(type)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return False
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
value_pos = len(self._request_header) + offset
|
value_pos = len(self._request_header) + offset
|
||||||
if isinstance(payload[value_pos], int):
|
if isinstance(payload[value_pos], int):
|
||||||
@ -767,12 +751,7 @@ class hysen(device):
|
|||||||
|
|
||||||
# send to device
|
# send to device
|
||||||
response = self.send_packet(0x6a, request_payload)
|
response = self.send_packet(0x6a, request_payload)
|
||||||
|
check_error(response[0x22:0x24])
|
||||||
# check for error
|
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
|
||||||
if err:
|
|
||||||
raise ValueError('broadlink_response_error', err)
|
|
||||||
|
|
||||||
response_payload = bytearray(self.decrypt(bytes(response[0x38:])))
|
response_payload = bytearray(self.decrypt(bytes(response[0x38:])))
|
||||||
|
|
||||||
# experimental check on CRC in response (first 2 bytes are len, and trailing bytes are crc)
|
# experimental check on CRC in response (first 2 bytes are len, and trailing bytes are crc)
|
||||||
@ -940,10 +919,7 @@ class S1C(device):
|
|||||||
packet = bytearray(16)
|
packet = bytearray(16)
|
||||||
packet[0] = 0x06 # 0x06 - get sensors info, 0x07 - probably add sensors
|
packet[0] = 0x06 # 0x06 - get sensors info, 0x07 - probably add sensors
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
if not payload:
|
if not payload:
|
||||||
return None
|
return None
|
||||||
@ -991,9 +967,7 @@ class dooya(device):
|
|||||||
packet[9] = 0xfa
|
packet[9] = 0xfa
|
||||||
packet[10] = 0x44
|
packet[10] = 0x44
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
err = response[0x22] | (response[0x23] << 8)
|
check_error(response[0x22:0x24])
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
return ord(payload[4])
|
return ord(payload[4])
|
||||||
|
|
||||||
@ -1059,10 +1033,7 @@ class lb1(device):
|
|||||||
packet[0x07] = checksum >> 8 # Checksum 2 position
|
packet[0x07] = checksum >> 8 # Checksum 2 position
|
||||||
|
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
|
check_error(response[0x36:0x38])
|
||||||
err = response[0x36] | (response[0x37] << 8)
|
|
||||||
if err != 0:
|
|
||||||
return None
|
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(bytes(response[0x38:]))
|
||||||
|
|
||||||
responseLength = int(payload[0x0a]) | (int(payload[0x0b]) << 8)
|
responseLength = int(payload[0x0a]) | (int(payload[0x0b]) << 8)
|
||||||
|
97
broadlink/exceptions.py
Normal file
97
broadlink/exceptions.py
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
"""Exceptions for Broadlink devices."""
|
||||||
|
|
||||||
|
|
||||||
|
class BroadlinkException(Exception):
|
||||||
|
"""Common base class for all Broadlink exceptions."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticationError(BroadlinkException):
|
||||||
|
"""Authentication error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AuthorizationError(BroadlinkException):
|
||||||
|
"""Authorization error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CommandNotSupportedError(BroadlinkException):
|
||||||
|
"""Command not supported error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionClosedError(BroadlinkException):
|
||||||
|
"""Connection closed error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DataValidationError(BroadlinkException):
|
||||||
|
"""Data validation error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceOfflineError(BroadlinkException):
|
||||||
|
"""Device offline error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ReadError(BroadlinkException):
|
||||||
|
"""Read error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SendError(BroadlinkException):
|
||||||
|
"""Send error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SSIDNotFoundError(BroadlinkException):
|
||||||
|
"""SSID not found error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class StorageError(BroadlinkException):
|
||||||
|
"""Storage error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownError(BroadlinkException):
|
||||||
|
"""Unknown error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class WriteError(BroadlinkException):
|
||||||
|
"""Write error."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
FIRMWARE_ERRORS = {
|
||||||
|
0xffff: (AuthenticationError, "Authentication failed"),
|
||||||
|
0xfffe: (ConnectionClosedError, "You have been logged out"),
|
||||||
|
0xfffd: (DeviceOfflineError, "The device is offline"),
|
||||||
|
0xfffc: (CommandNotSupportedError, "Command not supported"),
|
||||||
|
0xfffb: (StorageError, "The device storage is full"),
|
||||||
|
0xfffa: (DataValidationError, "Structure is abnormal"),
|
||||||
|
0xfff9: (AuthorizationError, "Control key is expired"),
|
||||||
|
0xfff8: (SendError, "Send error"),
|
||||||
|
0xfff7: (WriteError, "Write error"),
|
||||||
|
0xfff6: (ReadError, "Read error"),
|
||||||
|
0xfff5: (SSIDNotFoundError, "SSID could not be found in AP configuration"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def exception(error_code):
|
||||||
|
"""Return exception corresponding to an error code."""
|
||||||
|
try:
|
||||||
|
exc, msg = FIRMWARE_ERRORS[error_code]
|
||||||
|
return exc(msg)
|
||||||
|
except KeyError:
|
||||||
|
return UnknownError("Unknown error: " + hex(error_code))
|
||||||
|
|
||||||
|
|
||||||
|
def check_error(error):
|
||||||
|
"""Raise exception if an error occurred."""
|
||||||
|
error_code = error[0] | (error[1] << 8)
|
||||||
|
if error_code:
|
||||||
|
raise exception(error_code)
|
Loading…
Reference in New Issue
Block a user