mirror of
https://github.com/mjg59/python-broadlink.git
synced 2024-11-22 07:00:12 +01:00
Remove legacy byte conversions
This commit is contained in:
parent
de38e237ca
commit
5ef4124491
@ -1,5 +1,3 @@
|
|||||||
import codecs
|
|
||||||
|
|
||||||
from .device import device
|
from .device import device
|
||||||
from .exceptions import check_error
|
from .exceptions import check_error
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ class S1C(device):
|
|||||||
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)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
if not payload:
|
if not payload:
|
||||||
return None
|
return None
|
||||||
count = payload[0x4]
|
count = payload[0x4]
|
||||||
@ -34,11 +32,11 @@ class S1C(device):
|
|||||||
|
|
||||||
sens_res = []
|
sens_res = []
|
||||||
for sens in sensors_a:
|
for sens in sensors_a:
|
||||||
status = ord(chr(sens[0]))
|
status = sens[0]
|
||||||
_name = str(bytes(sens[4:26]).decode())
|
_name = sens[4:26].decode()
|
||||||
_order = ord(chr(sens[1]))
|
_order = sens[1]
|
||||||
_type = ord(chr(sens[3]))
|
_type = sens[3]
|
||||||
_serial = bytes(codecs.encode(sens[26:30], "hex")).decode()
|
_serial = sens[26:30].hex()
|
||||||
|
|
||||||
type_str = S1C_SENSORS_TYPES.get(_type, 'Unknown')
|
type_str = S1C_SENSORS_TYPES.get(_type, 'Unknown')
|
||||||
|
|
||||||
|
@ -19,9 +19,9 @@ class hysen(device):
|
|||||||
# New behaviour: raises a ValueError if the device response indicates an error or CRC check fails
|
# New behaviour: raises a ValueError if the device response indicates an error or CRC check fails
|
||||||
# The function prepends length (2 bytes) and appends CRC
|
# The function prepends length (2 bytes) and appends CRC
|
||||||
|
|
||||||
def send_request(self, input_payload: bytearray) -> bytes:
|
def send_request(self, input_payload: bytes) -> bytes:
|
||||||
"""Send a request to the device."""
|
"""Send a request to the device."""
|
||||||
crc = calculate_crc16(bytes(input_payload))
|
crc = calculate_crc16(input_payload)
|
||||||
|
|
||||||
# first byte is length, +2 for CRC16
|
# first byte is length, +2 for CRC16
|
||||||
request_payload = bytearray([len(input_payload) + 2, 0x00])
|
request_payload = bytearray([len(input_payload) + 2, 0x00])
|
||||||
@ -34,13 +34,13 @@ 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_error(response[0x22:0x24])
|
||||||
response_payload = bytearray(self.decrypt(bytes(response[0x38:])))
|
response_payload = self.decrypt(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)
|
||||||
response_payload_len = response_payload[0]
|
response_payload_len = response_payload[0]
|
||||||
if response_payload_len + 2 > len(response_payload):
|
if response_payload_len + 2 > len(response_payload):
|
||||||
raise ValueError('hysen_response_error', 'first byte of response is not length')
|
raise ValueError('hysen_response_error', 'first byte of response is not length')
|
||||||
crc = calculate_crc16(bytes(response_payload[2:response_payload_len]))
|
crc = calculate_crc16(response_payload[2:response_payload_len])
|
||||||
if (response_payload[response_payload_len] == crc & 0xFF) and (
|
if (response_payload[response_payload_len] == crc & 0xFF) and (
|
||||||
response_payload[response_payload_len + 1] == (crc >> 8) & 0xFF):
|
response_payload[response_payload_len + 1] == (crc >> 8) & 0xFF):
|
||||||
return response_payload[2:response_payload_len]
|
return response_payload[2:response_payload_len]
|
||||||
|
@ -23,8 +23,8 @@ class dooya(device):
|
|||||||
packet[10] = 0x44
|
packet[10] = 0x44
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
return ord(payload[4])
|
return payload[4]
|
||||||
|
|
||||||
def open(self) -> int:
|
def open(self) -> int:
|
||||||
"""Open the curtain."""
|
"""Open the curtain."""
|
||||||
|
@ -34,14 +34,14 @@ class device:
|
|||||||
self.manufacturer = manufacturer
|
self.manufacturer = manufacturer
|
||||||
self.is_locked = is_locked
|
self.is_locked = is_locked
|
||||||
self.count = random.randrange(0xffff)
|
self.count = random.randrange(0xffff)
|
||||||
self.iv = bytearray(
|
self.iv = bytes(
|
||||||
[0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58])
|
[0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58])
|
||||||
self.id = bytearray([0, 0, 0, 0])
|
self.id = bytes(4)
|
||||||
self.type = "Unknown"
|
self.type = "Unknown"
|
||||||
self.lock = threading.Lock()
|
self.lock = threading.Lock()
|
||||||
|
|
||||||
self.aes = None
|
self.aes = None
|
||||||
key = bytearray(
|
key = bytes(
|
||||||
[0x09, 0x76, 0x28, 0x34, 0x3f, 0xe9, 0x9e, 0x23, 0x76, 0x5c, 0x15, 0x13, 0xac, 0xcf, 0x8b, 0x02])
|
[0x09, 0x76, 0x28, 0x34, 0x3f, 0xe9, 0x9e, 0x23, 0x76, 0x5c, 0x15, 0x13, 0xac, 0xcf, 0x8b, 0x02])
|
||||||
self.update_aes(key)
|
self.update_aes(key)
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ class device:
|
|||||||
"""Return device type."""
|
"""Return device type."""
|
||||||
return self.type
|
return self.type
|
||||||
|
|
||||||
def send_packet(self, command: int, payload: bytearray) -> bytearray:
|
def send_packet(self, command: int, payload: bytes) -> bytes:
|
||||||
"""Send a packet to the device."""
|
"""Send a packet to the device."""
|
||||||
self.count = (self.count + 1) & 0xffff
|
self.count = (self.count + 1) & 0xffff
|
||||||
packet = bytearray(0x38)
|
packet = bytearray(0x38)
|
||||||
@ -162,8 +162,10 @@ class device:
|
|||||||
packet[0x33] = self.id[0]
|
packet[0x33] = self.id[0]
|
||||||
|
|
||||||
# pad the payload for AES encryption
|
# pad the payload for AES encryption
|
||||||
if payload:
|
padding = (16 - len(payload)) % 16
|
||||||
payload += bytearray((16 - len(payload)) % 16)
|
if padding:
|
||||||
|
payload = bytearray(payload)
|
||||||
|
payload += bytearray(padding)
|
||||||
|
|
||||||
checksum = sum(payload, 0xbeaf) & 0xffff
|
checksum = sum(payload, 0xbeaf) & 0xffff
|
||||||
packet[0x34] = checksum & 0xff
|
packet[0x34] = checksum & 0xff
|
||||||
@ -187,7 +189,6 @@ class device:
|
|||||||
cs.sendto(packet, self.host)
|
cs.sendto(packet, self.host)
|
||||||
cs.settimeout(1)
|
cs.settimeout(1)
|
||||||
resp, _ = cs.recvfrom(2048)
|
resp, _ = cs.recvfrom(2048)
|
||||||
resp = bytearray(resp)
|
|
||||||
break
|
break
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
if (time.time() - start_time) > self.timeout:
|
if (time.time() - start_time) > self.timeout:
|
||||||
|
@ -21,8 +21,8 @@ def get_local_ip() -> str:
|
|||||||
return s.getsockname()[0]
|
return s.getsockname()[0]
|
||||||
|
|
||||||
|
|
||||||
def calculate_crc16(input_data) -> int:
|
def calculate_crc16(input_data: bytes) -> int:
|
||||||
"""Calculate CRC-16."""
|
"""Calculate the CRC-16 of a byte string."""
|
||||||
crc16_tab = []
|
crc16_tab = []
|
||||||
crc16_constant = 0xA001
|
crc16_constant = 0xA001
|
||||||
|
|
||||||
@ -35,24 +35,11 @@ def calculate_crc16(input_data) -> int:
|
|||||||
crc = c_ushort(crc >> 1).value
|
crc = c_ushort(crc >> 1).value
|
||||||
crc16_tab.append(hex(crc))
|
crc16_tab.append(hex(crc))
|
||||||
|
|
||||||
try:
|
crcValue = 0xFFFF
|
||||||
is_string = isinstance(input_data, str)
|
|
||||||
is_bytes = isinstance(input_data, bytes)
|
|
||||||
|
|
||||||
if not is_string and not is_bytes:
|
for c in input_data:
|
||||||
raise Exception(
|
tmp = crcValue ^ c
|
||||||
"Please provide a string or a byte sequence "
|
rotated = c_ushort(crcValue >> 8).value
|
||||||
"as argument for calculation."
|
crcValue = rotated ^ int(crc16_tab[(tmp & 0x00FF)], 0)
|
||||||
)
|
|
||||||
|
|
||||||
crcValue = 0xFFFF
|
return crcValue
|
||||||
|
|
||||||
for c in input_data:
|
|
||||||
d = ord(c) if is_string else c
|
|
||||||
tmp = crcValue ^ d
|
|
||||||
rotated = c_ushort(crcValue >> 8).value
|
|
||||||
crcValue = rotated ^ int(crc16_tab[(tmp & 0x00FF)], 0)
|
|
||||||
|
|
||||||
return crcValue
|
|
||||||
except Exception as e:
|
|
||||||
print("EXCEPTION(calculate): {}".format(e))
|
|
||||||
|
@ -44,7 +44,7 @@ class lb1(device):
|
|||||||
|
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x36:0x38])
|
check_error(response[0x36:0x38])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
|
|
||||||
responseLength = int(payload[0x0a]) | (int(payload[0x0b]) << 8)
|
responseLength = int(payload[0x0a]) | (int(payload[0x0b]) << 8)
|
||||||
if responseLength > 0:
|
if responseLength > 0:
|
||||||
|
@ -18,7 +18,7 @@ class rm(device):
|
|||||||
packet.append(0x04)
|
packet.append(0x04)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
return payload[len(self._request_header) + 4:]
|
return payload[len(self._request_header) + 4:]
|
||||||
|
|
||||||
def send_data(self, data: bytes) -> None:
|
def send_data(self, data: bytes) -> None:
|
||||||
@ -56,7 +56,7 @@ class rm(device):
|
|||||||
packet.append(0x1a)
|
packet.append(0x1a)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
if payload[len(self._request_header) + 4] == 1:
|
if payload[len(self._request_header) + 4] == 1:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -67,7 +67,7 @@ class rm(device):
|
|||||||
packet.append(0x1b)
|
packet.append(0x1b)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
if payload[len(self._request_header) + 4] == 1:
|
if payload[len(self._request_header) + 4] == 1:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -78,7 +78,7 @@ class rm(device):
|
|||||||
packet.append(command)
|
packet.append(command)
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
return bytearray(payload[len(self._request_header) + 4:])
|
return bytearray(payload[len(self._request_header) + 4:])
|
||||||
|
|
||||||
def check_temperature(self) -> int:
|
def check_temperature(self) -> int:
|
||||||
|
@ -31,7 +31,7 @@ class a1(device):
|
|||||||
packet = bytearray([0x1])
|
packet = bytearray([0x1])
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
data = bytearray(payload[0x4:])
|
data = bytearray(payload[0x4:])
|
||||||
return {
|
return {
|
||||||
'temperature': data[0x0] + data[0x1] / 10.0,
|
'temperature': data[0x0] + data[0x1] / 10.0,
|
||||||
|
@ -50,7 +50,7 @@ class mp1(device):
|
|||||||
|
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
return payload[0x0e]
|
return payload[0x0e]
|
||||||
|
|
||||||
def check_power(self) -> dict:
|
def check_power(self) -> dict:
|
||||||
@ -116,7 +116,7 @@ class bg1(device):
|
|||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
return self._decode(response)
|
return self._decode(response)
|
||||||
|
|
||||||
def _encode(self, flag: int, js: str) -> bytearray:
|
def _encode(self, flag: int, js: str) -> bytes:
|
||||||
"""Encode a message."""
|
"""Encode a message."""
|
||||||
# The packet format is:
|
# The packet format is:
|
||||||
# 0x00-0x01 length
|
# 0x00-0x01 length
|
||||||
@ -139,7 +139,7 @@ class bg1(device):
|
|||||||
|
|
||||||
def _decode(self, response: bytes) -> dict:
|
def _decode(self, response: bytes) -> dict:
|
||||||
"""Decode a message."""
|
"""Decode a message."""
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(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])
|
||||||
return state
|
return state
|
||||||
@ -197,10 +197,8 @@ class sp2(device):
|
|||||||
packet[0] = 1
|
packet[0] = 1
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
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)
|
|
||||||
return bool(ord(payload[0x4]) == 1 or ord(payload[0x4]) == 3 or ord(payload[0x4]) == 0xFD)
|
|
||||||
|
|
||||||
def check_nightlight(self) -> bool:
|
def check_nightlight(self) -> bool:
|
||||||
"""Return the state of the night light."""
|
"""Return the state of the night light."""
|
||||||
@ -208,20 +206,13 @@ class sp2(device):
|
|||||||
packet[0] = 1
|
packet[0] = 1
|
||||||
response = self.send_packet(0x6a, packet)
|
response = self.send_packet(0x6a, packet)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
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)
|
|
||||||
return bool(ord(payload[0x4]) == 2 or ord(payload[0x4]) == 3 or ord(payload[0x4]) == 0xFF)
|
|
||||||
|
|
||||||
def get_energy(self) -> int:
|
def get_energy(self) -> int:
|
||||||
"""Return the energy state of the device."""
|
"""Return the energy state of the device."""
|
||||||
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)
|
||||||
check_error(response[0x22:0x24])
|
check_error(response[0x22:0x24])
|
||||||
payload = self.decrypt(bytes(response[0x38:]))
|
payload = self.decrypt(response[0x38:])
|
||||||
if isinstance(payload[0x7], int):
|
return 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
|
|
||||||
else:
|
|
||||||
energy = int(hex(ord(payload[0x07]) * 256 + ord(payload[0x06]))[2:]) + int(
|
|
||||||
hex(ord(payload[0x05]))[2:]) / 100.0
|
|
||||||
return energy
|
|
||||||
|
Loading…
Reference in New Issue
Block a user