code clean up (#243)
This commit is contained in:
		
							parent
							
								
									c9a1c106a7
								
							
						
					
					
						commit
						a75f98720e
					
				
					 1 changed files with 774 additions and 770 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| #!/usr/bin/python | #!/usr/bin/python | ||||||
| 
 | 
 | ||||||
| from datetime import datetime | from datetime import datetime | ||||||
|  | 
 | ||||||
| try: | try: | ||||||
|     from Crypto.Cipher import AES |     from Crypto.Cipher import AES | ||||||
| except ImportError as e: | except ImportError as e: | ||||||
|  | @ -9,7 +10,6 @@ except ImportError as e: | ||||||
| import time | import time | ||||||
| import random | import random | ||||||
| import socket | import socket | ||||||
| import sys |  | ||||||
| import threading | import threading | ||||||
| import codecs | import codecs | ||||||
| 
 | 
 | ||||||
|  | @ -60,6 +60,7 @@ def gendevice(devtype, host, mac): | ||||||
|         return device(host=host, mac=mac, devtype=devtype) |         return device(host=host, mac=mac, devtype=devtype) | ||||||
|     return deviceClass(host=host, mac=mac, devtype=devtype) |     return deviceClass(host=host, mac=mac, devtype=devtype) | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| def discover(timeout=None, local_ip_address=None): | def discover(timeout=None, local_ip_address=None): | ||||||
|     if local_ip_address is None: |     if local_ip_address is None: | ||||||
|         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||||||
|  | @ -69,13 +70,13 @@ def discover(timeout=None, local_ip_address=None): | ||||||
|     cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |     cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||||||
|     cs.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |     cs.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | ||||||
|     cs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) |     cs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) | ||||||
|   cs.bind((local_ip_address,0)) |     cs.bind((local_ip_address, 0)) | ||||||
|     port = cs.getsockname()[1] |     port = cs.getsockname()[1] | ||||||
|     starttime = time.time() |     starttime = time.time() | ||||||
| 
 | 
 | ||||||
|     devices = [] |     devices = [] | ||||||
| 
 | 
 | ||||||
|   timezone = int(time.timezone/-3600) |     timezone = int(time.timezone / -3600) | ||||||
|     packet = bytearray(0x30) |     packet = bytearray(0x30) | ||||||
| 
 | 
 | ||||||
|     year = datetime.now().year |     year = datetime.now().year | ||||||
|  | @ -122,9 +123,8 @@ def discover(timeout=None, local_ip_address=None): | ||||||
|         mac = responsepacket[0x3a:0x40] |         mac = responsepacket[0x3a:0x40] | ||||||
|         devtype = responsepacket[0x34] | responsepacket[0x35] << 8 |         devtype = responsepacket[0x34] | responsepacket[0x35] << 8 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|         return gendevice(devtype, host, mac) |         return gendevice(devtype, host, mac) | ||||||
|   else: | 
 | ||||||
|     while (time.time() - starttime) < timeout: |     while (time.time() - starttime) < timeout: | ||||||
|         cs.settimeout(timeout - (time.time() - starttime)) |         cs.settimeout(timeout - (time.time() - starttime)) | ||||||
|         try: |         try: | ||||||
|  | @ -140,7 +140,6 @@ def discover(timeout=None, local_ip_address=None): | ||||||
|     return devices |     return devices | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| class device: | class device: | ||||||
|     def __init__(self, host, mac, devtype, timeout=10): |     def __init__(self, host, mac, devtype, timeout=10): | ||||||
|         self.host = host |         self.host = host | ||||||
|  | @ -148,13 +147,15 @@ class device: | ||||||
|         self.devtype = devtype |         self.devtype = devtype | ||||||
|         self.timeout = timeout |         self.timeout = timeout | ||||||
|         self.count = random.randrange(0xffff) |         self.count = random.randrange(0xffff) | ||||||
|     self.key = bytearray([0x09, 0x76, 0x28, 0x34, 0x3f, 0xe9, 0x9e, 0x23, 0x76, 0x5c, 0x15, 0x13, 0xac, 0xcf, 0x8b, 0x02]) |         self.key = bytearray( | ||||||
|     self.iv = bytearray([0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28, 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58]) |             [0x09, 0x76, 0x28, 0x34, 0x3f, 0xe9, 0x9e, 0x23, 0x76, 0x5c, 0x15, 0x13, 0xac, 0xcf, 0x8b, 0x02]) | ||||||
|  |         self.iv = bytearray( | ||||||
|  |             [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 = bytearray([0, 0, 0, 0]) | ||||||
|         self.cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |         self.cs = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||||||
|         self.cs.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |         self.cs.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | ||||||
|         self.cs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) |         self.cs.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) | ||||||
|     self.cs.bind(('',0)) |         self.cs.bind(('', 0)) | ||||||
|         self.type = "Unknown" |         self.type = "Unknown" | ||||||
|         self.lock = threading.Lock() |         self.lock = threading.Lock() | ||||||
| 
 | 
 | ||||||
|  | @ -166,12 +167,12 @@ class device: | ||||||
|             self.decrypt = self.decrypt_pycrypto |             self.decrypt = self.decrypt_pycrypto | ||||||
| 
 | 
 | ||||||
|     def encrypt_pyaes(self, payload): |     def encrypt_pyaes(self, payload): | ||||||
|     aes = pyaes.AESModeOfOperationCBC(self.key, iv = bytes(self.iv)) |         aes = pyaes.AESModeOfOperationCBC(self.key, iv=bytes(self.iv)) | ||||||
|     return b"".join([aes.encrypt(bytes(payload[i:i+16])) for i in range(0, len(payload), 16)]) |         return b"".join([aes.encrypt(bytes(payload[i:i + 16])) for i in range(0, len(payload), 16)]) | ||||||
| 
 | 
 | ||||||
|     def decrypt_pyaes(self, payload): |     def decrypt_pyaes(self, payload): | ||||||
|     aes = pyaes.AESModeOfOperationCBC(self.key, iv = bytes(self.iv)) |         aes = pyaes.AESModeOfOperationCBC(self.key, iv=bytes(self.iv)) | ||||||
|     return b"".join([aes.decrypt(bytes(payload[i:i+16])) for i in range(0, len(payload), 16)]) |         return b"".join([aes.decrypt(bytes(payload[i:i + 16])) for i in range(0, len(payload), 16)]) | ||||||
| 
 | 
 | ||||||
|     def encrypt_pycrypto(self, payload): |     def encrypt_pycrypto(self, payload): | ||||||
|         aes = AES.new(bytes(self.key), AES.MODE_CBC, bytes(self.iv)) |         aes = AES.new(bytes(self.key), AES.MODE_CBC, bytes(self.iv)) | ||||||
|  | @ -255,9 +256,9 @@ class device: | ||||||
|         packet[0x33] = self.id[3] |         packet[0x33] = self.id[3] | ||||||
| 
 | 
 | ||||||
|         # pad the payload for AES encryption |         # pad the payload for AES encryption | ||||||
|     if len(payload)>0: |         if payload: | ||||||
|       numpad=(len(payload)//16+1)*16 |             numpad = (len(payload) // 16 + 1) * 16 | ||||||
|       payload=payload.ljust(numpad, b"\x00") |             payload = payload.ljust(numpad, b"\x00") | ||||||
| 
 | 
 | ||||||
|         checksum = 0xbeaf |         checksum = 0xbeaf | ||||||
|         for i in range(len(payload)): |         for i in range(len(payload)): | ||||||
|  | @ -294,7 +295,7 @@ class device: | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class mp1(device): | class mp1(device): | ||||||
|   def __init__ (self, host, mac, devtype): |     def __init__(self, host, mac, devtype): | ||||||
|         device.__init__(self, host, mac, devtype) |         device.__init__(self, host, mac, devtype) | ||||||
|         self.type = "MP1" |         self.type = "MP1" | ||||||
| 
 | 
 | ||||||
|  | @ -307,16 +308,14 @@ class mp1(device): | ||||||
|         packet[0x03] = 0xa5 |         packet[0x03] = 0xa5 | ||||||
|         packet[0x04] = 0x5a |         packet[0x04] = 0x5a | ||||||
|         packet[0x05] = 0x5a |         packet[0x05] = 0x5a | ||||||
|     packet[0x06] = 0xb2 + ((sid_mask<<1) if state else sid_mask) |         packet[0x06] = 0xb2 + ((sid_mask << 1) if state else sid_mask) | ||||||
|         packet[0x07] = 0xc0 |         packet[0x07] = 0xc0 | ||||||
|         packet[0x08] = 0x02 |         packet[0x08] = 0x02 | ||||||
|         packet[0x0a] = 0x03 |         packet[0x0a] = 0x03 | ||||||
|         packet[0x0d] = sid_mask |         packet[0x0d] = sid_mask | ||||||
|         packet[0x0e] = sid_mask if state else 0 |         packet[0x0e] = sid_mask if state else 0 | ||||||
| 
 | 
 | ||||||
|     response = self.send_packet(0x6a, packet) |         self.send_packet(0x6a, packet) | ||||||
| 
 |  | ||||||
|     err = response[0x22] | (response[0x23] << 8) |  | ||||||
| 
 | 
 | ||||||
|     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.""" | ||||||
|  | @ -337,9 +336,10 @@ class mp1(device): | ||||||
| 
 | 
 | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return None | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|       if type(payload[0x4]) == int: |         if isinstance(payload[0x4], int): | ||||||
|             state = payload[0x0e] |             state = payload[0x0e] | ||||||
|         else: |         else: | ||||||
|             state = ord(payload[0x0e]) |             state = ord(payload[0x0e]) | ||||||
|  | @ -357,7 +357,7 @@ class mp1(device): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class sp1(device): | class sp1(device): | ||||||
|   def __init__ (self, host, mac, devtype): |     def __init__(self, host, mac, devtype): | ||||||
|         device.__init__(self, host, mac, devtype) |         device.__init__(self, host, mac, devtype) | ||||||
|         self.type = "SP1" |         self.type = "SP1" | ||||||
| 
 | 
 | ||||||
|  | @ -368,7 +368,7 @@ class sp1(device): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class sp2(device): | class sp2(device): | ||||||
|   def __init__ (self, host, mac, devtype): |     def __init__(self, host, mac, devtype): | ||||||
|         device.__init__(self, host, mac, devtype) |         device.__init__(self, host, mac, devtype) | ||||||
|         self.type = "SP2" |         self.type = "SP2" | ||||||
| 
 | 
 | ||||||
|  | @ -398,19 +398,12 @@ class sp2(device): | ||||||
|         packet[0] = 1 |         packet[0] = 1 | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return None | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|       if type(payload[0x4]) == int: |         if isinstance(payload[0x4], int): | ||||||
|         if payload[0x4] == 1 or payload[0x4] == 3 or payload[0x4] == 0xFD: |             return bool(payload[0x4] == 1 or payload[0x4] == 3 or payload[0x4] == 0xFD) | ||||||
|           state = True |         return bool(ord(payload[0x4]) == 1 or ord(payload[0x4]) == 3 or ord(payload[0x4]) == 0xFD) | ||||||
|         else: |  | ||||||
|           state = False |  | ||||||
|       else: |  | ||||||
|         if ord(payload[0x4]) == 1 or ord(payload[0x4]) == 3 or ord(payload[0x4]) == 0xFD: |  | ||||||
|           state = True |  | ||||||
|         else: |  | ||||||
|           state = False |  | ||||||
|       return state |  | ||||||
| 
 | 
 | ||||||
|     def check_nightlight(self): |     def check_nightlight(self): | ||||||
|         """Returns the power state of the smart plug.""" |         """Returns the power state of the smart plug.""" | ||||||
|  | @ -418,35 +411,30 @@ class sp2(device): | ||||||
|         packet[0] = 1 |         packet[0] = 1 | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return None | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|       if type(payload[0x4]) == int: |         if isinstance(payload[0x4], int): | ||||||
|         if payload[0x4] == 2 or payload[0x4] == 3 or payload[0x4] == 0xFF: |             return bool(payload[0x4] == 2 or payload[0x4] == 3 or payload[0x4] == 0xFF) | ||||||
|           state = True |         return bool(ord(payload[0x4]) == 2 or ord(payload[0x4]) == 3 or ord(payload[0x4]) == 0xFF) | ||||||
|         else: |  | ||||||
|           state = False |  | ||||||
|       else: |  | ||||||
|         if ord(payload[0x4]) == 2 or ord(payload[0x4]) == 3 or ord(payload[0x4]) == 0xFF: |  | ||||||
|           state = True |  | ||||||
|         else: |  | ||||||
|           state = False |  | ||||||
|       return state |  | ||||||
| 
 | 
 | ||||||
|     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) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return None | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|       if type(payload[0x07]) == 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 | ||||||
|         else: |         else: | ||||||
|         energy = int(hex(ord(payload[0x07]) * 256 + ord(payload[0x06]))[2:]) + int(hex(ord(payload[0x05]))[2:])/100.0 |             energy = int(hex(ord(payload[0x07]) * 256 + ord(payload[0x06]))[2:]) + int( | ||||||
|  |                 hex(ord(payload[0x05]))[2:]) / 100.0 | ||||||
|         return energy |         return energy | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class a1(device): | class a1(device): | ||||||
|   def __init__ (self, host, mac, devtype): |     def __init__(self, host, mac, devtype): | ||||||
|         device.__init__(self, host, mac, devtype) |         device.__init__(self, host, mac, devtype) | ||||||
|         self.type = "A1" |         self.type = "A1" | ||||||
| 
 | 
 | ||||||
|  | @ -455,10 +443,11 @@ class a1(device): | ||||||
|         packet[0] = 1 |         packet[0] = 1 | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return None | ||||||
|         data = {} |         data = {} | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|       if type(payload[0x4]) == int: |         if isinstance(payload[0x4], int): | ||||||
|             data['temperature'] = (payload[0x4] * 10 + payload[0x5]) / 10.0 |             data['temperature'] = (payload[0x4] * 10 + payload[0x5]) / 10.0 | ||||||
|             data['humidity'] = (payload[0x6] * 10 + payload[0x7]) / 10.0 |             data['humidity'] = (payload[0x6] * 10 + payload[0x7]) / 10.0 | ||||||
|             light = payload[0x8] |             light = payload[0x8] | ||||||
|  | @ -505,10 +494,11 @@ class a1(device): | ||||||
|         packet[0] = 1 |         packet[0] = 1 | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return None | ||||||
|         data = {} |         data = {} | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|       if type(payload[0x4]) == int: |         if isinstance(payload[0x4], int): | ||||||
|             data['temperature'] = (payload[0x4] * 10 + payload[0x5]) / 10.0 |             data['temperature'] = (payload[0x4] * 10 + payload[0x5]) / 10.0 | ||||||
|             data['humidity'] = (payload[0x6] * 10 + payload[0x7]) / 10.0 |             data['humidity'] = (payload[0x6] * 10 + payload[0x7]) / 10.0 | ||||||
|             data['light'] = payload[0x8] |             data['light'] = payload[0x8] | ||||||
|  | @ -524,7 +514,7 @@ class a1(device): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class rm(device): | class rm(device): | ||||||
|   def __init__ (self, host, mac, devtype): |     def __init__(self, host, mac, devtype): | ||||||
|         device.__init__(self, host, mac, devtype) |         device.__init__(self, host, mac, devtype) | ||||||
|         self.type = "RM2" |         self.type = "RM2" | ||||||
| 
 | 
 | ||||||
|  | @ -533,7 +523,8 @@ class rm(device): | ||||||
|         packet[0] = 4 |         packet[0] = 4 | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return None | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|         return payload[0x04:] |         return payload[0x04:] | ||||||
| 
 | 
 | ||||||
|  | @ -562,7 +553,8 @@ class rm(device): | ||||||
|         packet[0] = 0x1a |         packet[0] = 0x1a | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return False | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|         if payload[0x04] == 1: |         if payload[0x04] == 1: | ||||||
|             return True |             return True | ||||||
|  | @ -573,7 +565,8 @@ class rm(device): | ||||||
|         packet[0] = 0x1b |         packet[0] = 0x1b | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return False | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|         if payload[0x04] == 1: |         if payload[0x04] == 1: | ||||||
|             return True |             return True | ||||||
|  | @ -584,9 +577,10 @@ class rm(device): | ||||||
|         packet[0] = 1 |         packet[0] = 1 | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return False | ||||||
|         payload = self.decrypt(bytes(response[0x38:])) |         payload = self.decrypt(bytes(response[0x38:])) | ||||||
|       if type(payload[0x4]) == int: |         if isinstance(payload[0x4], int): | ||||||
|             temp = (payload[0x4] * 10 + payload[0x5]) / 10.0 |             temp = (payload[0x4] * 10 + payload[0x5]) / 10.0 | ||||||
|         else: |         else: | ||||||
|             temp = (ord(payload[0x4]) * 10 + ord(payload[0x5])) / 10.0 |             temp = (ord(payload[0x4]) * 10 + ord(payload[0x5])) / 10.0 | ||||||
|  | @ -595,7 +589,7 @@ class rm(device): | ||||||
| 
 | 
 | ||||||
| # For legacy compatibility - don't use this | # For legacy compatibility - don't use this | ||||||
| class rm2(rm): | class rm2(rm): | ||||||
|   def __init__ (self): |     def __init__(self): | ||||||
|         device.__init__(self, None, None, None) |         device.__init__(self, None, None, None) | ||||||
| 
 | 
 | ||||||
|     def discover(self): |     def discover(self): | ||||||
|  | @ -605,7 +599,7 @@ class rm2(rm): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class hysen(device): | class hysen(device): | ||||||
|   def __init__ (self, host, mac, devtype): |     def __init__(self, host, mac, devtype): | ||||||
|         device.__init__(self, host, mac, devtype) |         device.__init__(self, host, mac, devtype) | ||||||
|         self.type = "Hysen heating controller" |         self.type = "Hysen heating controller" | ||||||
| 
 | 
 | ||||||
|  | @ -614,13 +608,13 @@ class hysen(device): | ||||||
|     # Returns decrypted payload |     # Returns decrypted payload | ||||||
|     # 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): |     def send_request(self, input_payload): | ||||||
| 
 | 
 | ||||||
|         from PyCRC.CRC16 import CRC16 |         from PyCRC.CRC16 import CRC16 | ||||||
|         crc = CRC16(modbus_flag=True).calculate(bytes(input_payload)) |         crc = CRC16(modbus_flag=True).calculate(bytes(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]) | ||||||
|         request_payload.extend(input_payload) |         request_payload.extend(input_payload) | ||||||
| 
 | 
 | ||||||
|         # append CRC |         # append CRC | ||||||
|  | @ -633,41 +627,40 @@ class hysen(device): | ||||||
|         # check for error |         # check for error | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|         if err: |         if err: | ||||||
|       raise ValueError('broadlink_response_error',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) | ||||||
|         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 = CRC16(modbus_flag=True).calculate(bytes(response_payload[2:response_payload_len])) |         crc = CRC16(modbus_flag=True).calculate(bytes(response_payload[2:response_payload_len])) | ||||||
|     if (response_payload[response_payload_len] == crc & 0xFF) and (response_payload[response_payload_len+1] == (crc >> 8) & 0xFF): |         if (response_payload[response_payload_len] == crc & 0xFF) and ( | ||||||
|  |                 response_payload[response_payload_len + 1] == (crc >> 8) & 0xFF): | ||||||
|             return response_payload[2:response_payload_len] |             return response_payload[2:response_payload_len] | ||||||
|     else: |         raise ValueError('hysen_response_error', 'CRC check on response failed') | ||||||
|       raise ValueError('hysen_response_error','CRC check on response failed') |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|     # Get current room temperature in degrees celsius |     # Get current room temperature in degrees celsius | ||||||
|     def get_temp(self): |     def get_temp(self): | ||||||
|     payload = self.send_request(bytearray([0x01,0x03,0x00,0x00,0x00,0x08])) |         payload = self.send_request(bytearray([0x01, 0x03, 0x00, 0x00, 0x00, 0x08])) | ||||||
|         return payload[0x05] / 2.0 |         return payload[0x05] / 2.0 | ||||||
| 
 | 
 | ||||||
|     # Get current external temperature in degrees celsius |     # Get current external temperature in degrees celsius | ||||||
|     def get_external_temp(self): |     def get_external_temp(self): | ||||||
|     payload = self.send_request(bytearray([0x01,0x03,0x00,0x00,0x00,0x08])) |         payload = self.send_request(bytearray([0x01, 0x03, 0x00, 0x00, 0x00, 0x08])) | ||||||
|         return payload[18] / 2.0 |         return payload[18] / 2.0 | ||||||
| 
 | 
 | ||||||
|     # Get full status (including timer schedule) |     # Get full status (including timer schedule) | ||||||
|     def get_full_status(self): |     def get_full_status(self): | ||||||
|     payload = self.send_request(bytearray([0x01,0x03,0x00,0x00,0x00,0x16])) |         payload = self.send_request(bytearray([0x01, 0x03, 0x00, 0x00, 0x00, 0x16])) | ||||||
|         data = {} |         data = {} | ||||||
|         data['remote_lock'] = payload[3] & 1 |         data['remote_lock'] = payload[3] & 1 | ||||||
|         data['power'] = payload[4] & 1 |         data['power'] = payload[4] & 1 | ||||||
|         data['active'] = (payload[4] >> 4) & 1 |         data['active'] = (payload[4] >> 4) & 1 | ||||||
|         data['temp_manual'] = (payload[4] >> 6) & 1 |         data['temp_manual'] = (payload[4] >> 6) & 1 | ||||||
|     data['room_temp'] =  (payload[5] & 255)/2.0 |         data['room_temp'] = (payload[5] & 255) / 2.0 | ||||||
|     data['thermostat_temp'] =  (payload[6] & 255)/2.0 |         data['thermostat_temp'] = (payload[6] & 255) / 2.0 | ||||||
|         data['auto_mode'] = payload[7] & 15 |         data['auto_mode'] = payload[7] & 15 | ||||||
|         data['loop_mode'] = (payload[7] >> 4) & 15 |         data['loop_mode'] = (payload[7] >> 4) & 15 | ||||||
|         data['sensor'] = payload[8] |         data['sensor'] = payload[8] | ||||||
|  | @ -675,13 +668,13 @@ class hysen(device): | ||||||
|         data['dif'] = payload[10] |         data['dif'] = payload[10] | ||||||
|         data['svh'] = payload[11] |         data['svh'] = payload[11] | ||||||
|         data['svl'] = payload[12] |         data['svl'] = payload[12] | ||||||
|     data['room_temp_adj'] = ((payload[13] << 8) + payload[14])/2.0 |         data['room_temp_adj'] = ((payload[13] << 8) + payload[14]) / 2.0 | ||||||
|         if data['room_temp_adj'] > 32767: |         if data['room_temp_adj'] > 32767: | ||||||
|             data['room_temp_adj'] = 32767 - data['room_temp_adj'] |             data['room_temp_adj'] = 32767 - data['room_temp_adj'] | ||||||
|         data['fre'] = payload[15] |         data['fre'] = payload[15] | ||||||
|         data['poweron'] = payload[16] |         data['poweron'] = payload[16] | ||||||
|         data['unknown'] = payload[17] |         data['unknown'] = payload[17] | ||||||
|     data['external_temp'] = (payload[18] & 255)/2.0 |         data['external_temp'] = (payload[18] & 255) / 2.0 | ||||||
|         data['hour'] = payload[19] |         data['hour'] = payload[19] | ||||||
|         data['min'] = payload[20] |         data['min'] = payload[20] | ||||||
|         data['sec'] = payload[21] |         data['sec'] = payload[21] | ||||||
|  | @ -689,42 +682,49 @@ class hysen(device): | ||||||
| 
 | 
 | ||||||
|         weekday = [] |         weekday = [] | ||||||
|         for i in range(0, 6): |         for i in range(0, 6): | ||||||
|       weekday.append({'start_hour':payload[2*i + 23], 'start_minute':payload[2*i + 24],'temp':payload[i + 39]/2.0}) |             weekday.append( | ||||||
|  |                 {'start_hour': payload[2 * i + 23], 'start_minute': payload[2 * i + 24], 'temp': payload[i + 39] / 2.0}) | ||||||
| 
 | 
 | ||||||
|         data['weekday'] = weekday |         data['weekday'] = weekday | ||||||
|         weekend = [] |         weekend = [] | ||||||
|         for i in range(6, 8): |         for i in range(6, 8): | ||||||
|       weekend.append({'start_hour':payload[2*i + 23], 'start_minute':payload[2*i + 24],'temp':payload[i + 39]/2.0}) |             weekend.append( | ||||||
|  |                 {'start_hour': payload[2 * i + 23], 'start_minute': payload[2 * i + 24], 'temp': payload[i + 39] / 2.0}) | ||||||
| 
 | 
 | ||||||
|         data['weekend'] = weekend |         data['weekend'] = weekend | ||||||
|         return data |         return data | ||||||
| 
 | 
 | ||||||
|     # Change controller mode |     # Change controller mode | ||||||
|     # auto_mode = 1 for auto (scheduled/timed) mode, 0 for manual mode. |     # auto_mode = 1 for auto (scheduled/timed) mode, 0 for manual mode. | ||||||
|   # Manual mode will activate last used temperature.  In typical usage call set_temp to activate manual control and set temp. |     # Manual mode will activate last used temperature. | ||||||
|  |     # In typical usage call set_temp to activate manual control and set temp. | ||||||
|     # loop_mode refers to index in [ "12345,67", "123456,7", "1234567" ] |     # loop_mode refers to index in [ "12345,67", "123456,7", "1234567" ] | ||||||
|     # E.g. loop_mode = 0 ("12345,67") means Saturday and Sunday follow the "weekend" schedule |     # E.g. loop_mode = 0 ("12345,67") means Saturday and Sunday follow the "weekend" schedule | ||||||
|     # loop_mode = 2 ("1234567") means every day (including Saturday and Sunday) follows the "weekday" schedule |     # loop_mode = 2 ("1234567") means every day (including Saturday and Sunday) follows the "weekday" schedule | ||||||
|     # The sensor command is currently experimental |     # The sensor command is currently experimental | ||||||
|   def set_mode(self, auto_mode, loop_mode,sensor=0): |     def set_mode(self, auto_mode, loop_mode, sensor=0): | ||||||
|     mode_byte = ( (loop_mode + 1) << 4) + auto_mode |         mode_byte = ((loop_mode + 1) << 4) + auto_mode | ||||||
|         # print 'Mode byte: 0x'+ format(mode_byte, '02x') |         # print 'Mode byte: 0x'+ format(mode_byte, '02x') | ||||||
|     self.send_request(bytearray([0x01,0x06,0x00,0x02,mode_byte,sensor])) |         self.send_request(bytearray([0x01, 0x06, 0x00, 0x02, mode_byte, sensor])) | ||||||
| 
 | 
 | ||||||
|     # Advanced settings |     # Advanced settings | ||||||
|   # Sensor mode (SEN) sensor = 0 for internal sensor, 1 for external sensor, 2 for internal control temperature, external limit temperature. Factory default: 0. |     # Sensor mode (SEN) sensor = 0 for internal sensor, 1 for external sensor, | ||||||
|  |     # 2 for internal control temperature, external limit temperature. Factory default: 0. | ||||||
|     # Set temperature range for external sensor (OSV) osv = 5..99. Factory default: 42C |     # Set temperature range for external sensor (OSV) osv = 5..99. Factory default: 42C | ||||||
|     # Deadzone for floor temprature (dIF) dif = 1..9. Factory default: 2C |     # Deadzone for floor temprature (dIF) dif = 1..9. Factory default: 2C | ||||||
|     # Upper temperature limit for internal sensor (SVH) svh = 5..99. Factory default: 35C |     # Upper temperature limit for internal sensor (SVH) svh = 5..99. Factory default: 35C | ||||||
|     # Lower temperature limit for internal sensor (SVL) svl = 5..99. Factory default: 5C |     # Lower temperature limit for internal sensor (SVL) svl = 5..99. Factory default: 5C | ||||||
|     # Actual temperature calibration (AdJ) adj = -0.5. Prescision 0.1C |     # Actual temperature calibration (AdJ) adj = -0.5. Prescision 0.1C | ||||||
|   # Anti-freezing function (FrE) fre = 0 for anti-freezing function shut down, 1 for anti-freezing function open. Factory default: 0 |     # Anti-freezing function (FrE) fre = 0 for anti-freezing function shut down, | ||||||
|  |     #  1 for anti-freezing function open. Factory default: 0 | ||||||
|     # Power on memory (POn) poweron = 0 for power on memory off, 1 for power on memory on. Factory default: 0 |     # Power on memory (POn) poweron = 0 for power on memory off, 1 for power on memory on. Factory default: 0 | ||||||
|     def set_advanced(self, loop_mode, sensor, osv, dif, svh, svl, adj, fre, poweron): |     def set_advanced(self, loop_mode, sensor, osv, dif, svh, svl, adj, fre, poweron): | ||||||
|     input_payload = bytearray([0x01,0x10,0x00,0x02,0x00,0x05,0x0a, loop_mode, sensor, osv, dif, svh, svl, (int(adj*2)>>8 & 0xff), (int(adj*2) & 0xff), fre, poweron]) |         input_payload = bytearray([0x01, 0x10, 0x00, 0x02, 0x00, 0x05, 0x0a, loop_mode, sensor, osv, dif, svh, svl, | ||||||
|  |                                    (int(adj * 2) >> 8 & 0xff), (int(adj * 2) & 0xff), fre, poweron]) | ||||||
|         self.send_request(input_payload) |         self.send_request(input_payload) | ||||||
| 
 | 
 | ||||||
|   # For backwards compatibility only.  Prefer calling set_mode directly.  Note this function invokes loop_mode=0 and sensor=0. |     # For backwards compatibility only.  Prefer calling set_mode directly. | ||||||
|  |     # Note this function invokes loop_mode=0 and sensor=0. | ||||||
|     def switch_to_auto(self): |     def switch_to_auto(self): | ||||||
|         self.set_mode(auto_mode=1, loop_mode=0) |         self.set_mode(auto_mode=1, loop_mode=0) | ||||||
| 
 | 
 | ||||||
|  | @ -733,16 +733,17 @@ class hysen(device): | ||||||
| 
 | 
 | ||||||
|     # Set temperature for manual mode (also activates manual mode if currently in automatic) |     # Set temperature for manual mode (also activates manual mode if currently in automatic) | ||||||
|     def set_temp(self, temp): |     def set_temp(self, temp): | ||||||
|     self.send_request(bytearray([0x01,0x06,0x00,0x01,0x00,int(temp * 2)]) ) |         self.send_request(bytearray([0x01, 0x06, 0x00, 0x01, 0x00, int(temp * 2)])) | ||||||
| 
 | 
 | ||||||
|   # Set device on(1) or off(0), does not deactivate Wifi connectivity.  Remote lock disables control by buttons on thermostat. |     # Set device on(1) or off(0), does not deactivate Wifi connectivity. | ||||||
|  |     # Remote lock disables control by buttons on thermostat. | ||||||
|     def set_power(self, power=1, remote_lock=0): |     def set_power(self, power=1, remote_lock=0): | ||||||
|     self.send_request(bytearray([0x01,0x06,0x00,0x00,remote_lock,power]) ) |         self.send_request(bytearray([0x01, 0x06, 0x00, 0x00, remote_lock, power])) | ||||||
| 
 | 
 | ||||||
|     # set time on device |     # set time on device | ||||||
|     # n.b. day=1 is Monday, ..., day=7 is Sunday |     # n.b. day=1 is Monday, ..., day=7 is Sunday | ||||||
|     def set_time(self, hour, minute, second, day): |     def set_time(self, hour, minute, second, day): | ||||||
|     self.send_request(bytearray([0x01,0x10,0x00,0x08,0x00,0x02,0x04, hour, minute, second, day ])) |         self.send_request(bytearray([0x01, 0x10, 0x00, 0x08, 0x00, 0x02, 0x04, hour, minute, second, day])) | ||||||
| 
 | 
 | ||||||
|     # Set timer schedule |     # Set timer schedule | ||||||
|     # Format is the same as you get from get_full_status. |     # Format is the same as you get from get_full_status. | ||||||
|  | @ -750,28 +751,28 @@ class hysen(device): | ||||||
|     # {'start_hour':17, 'start_minute':30, 'temp': 22 } |     # {'start_hour':17, 'start_minute':30, 'temp': 22 } | ||||||
|     # Each one specifies the thermostat temp that will become effective at start_hour:start_minute |     # Each one specifies the thermostat temp that will become effective at start_hour:start_minute | ||||||
|     # weekend is similar but only has 2 (e.g. switch on in morning and off in afternoon) |     # weekend is similar but only has 2 (e.g. switch on in morning and off in afternoon) | ||||||
|   def set_schedule(self,weekday,weekend): |     def set_schedule(self, weekday, weekend): | ||||||
|         # Begin with some magic values ... |         # Begin with some magic values ... | ||||||
|     input_payload = bytearray([0x01,0x10,0x00,0x0a,0x00,0x0c,0x18]) |         input_payload = bytearray([0x01, 0x10, 0x00, 0x0a, 0x00, 0x0c, 0x18]) | ||||||
| 
 | 
 | ||||||
|         # Now simply append times/temps |         # Now simply append times/temps | ||||||
|         # weekday times |         # weekday times | ||||||
|         for i in range(0, 6): |         for i in range(0, 6): | ||||||
|       input_payload.append( weekday[i]['start_hour'] ) |             input_payload.append(weekday[i]['start_hour']) | ||||||
|       input_payload.append( weekday[i]['start_minute'] ) |             input_payload.append(weekday[i]['start_minute']) | ||||||
| 
 | 
 | ||||||
|         # weekend times |         # weekend times | ||||||
|         for i in range(0, 2): |         for i in range(0, 2): | ||||||
|       input_payload.append( weekend[i]['start_hour'] ) |             input_payload.append(weekend[i]['start_hour']) | ||||||
|       input_payload.append( weekend[i]['start_minute'] ) |             input_payload.append(weekend[i]['start_minute']) | ||||||
| 
 | 
 | ||||||
|         # weekday temperatures |         # weekday temperatures | ||||||
|         for i in range(0, 6): |         for i in range(0, 6): | ||||||
|       input_payload.append( int(weekday[i]['temp'] * 2) ) |             input_payload.append(int(weekday[i]['temp'] * 2)) | ||||||
| 
 | 
 | ||||||
|         # weekend temperatures |         # weekend temperatures | ||||||
|         for i in range(0, 2): |         for i in range(0, 2): | ||||||
|       input_payload.append( int(weekend[i]['temp'] * 2) ) |             input_payload.append(int(weekend[i]['temp'] * 2)) | ||||||
| 
 | 
 | ||||||
|         self.send_request(input_payload) |         self.send_request(input_payload) | ||||||
| 
 | 
 | ||||||
|  | @ -787,6 +788,7 @@ class S1C(device): | ||||||
|     """ |     """ | ||||||
|     Its VERY VERY VERY DIRTY IMPLEMENTATION of S1C |     Its VERY VERY VERY DIRTY IMPLEMENTATION of S1C | ||||||
|     """ |     """ | ||||||
|  | 
 | ||||||
|     def __init__(self, *a, **kw): |     def __init__(self, *a, **kw): | ||||||
|         device.__init__(self, *a, **kw) |         device.__init__(self, *a, **kw) | ||||||
|         self.type = 'S1C' |         self.type = 'S1C' | ||||||
|  | @ -796,13 +798,14 @@ 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) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         if err != 0: | ||||||
|  |             return None | ||||||
|         aes = AES.new(bytes(self.key), AES.MODE_CBC, bytes(self.iv)) |         aes = AES.new(bytes(self.key), AES.MODE_CBC, bytes(self.iv)) | ||||||
| 
 | 
 | ||||||
|         payload = aes.decrypt(bytes(response[0x38:])) |         payload = aes.decrypt(bytes(response[0x38:])) | ||||||
|       if payload: |         if not payload: | ||||||
|         head = payload[:4] |             return None | ||||||
|         count = payload[0x4] #need to fix for python 2.x |         count = payload[0x4] | ||||||
|         sensors = payload[0x6:] |         sensors = payload[0x6:] | ||||||
|         sensors_a = [bytearray(sensors[i * 83:(i + 1) * 83]) for i in range(len(sensors) // 83)] |         sensors_a = [bytearray(sensors[i * 83:(i + 1) * 83]) for i in range(len(sensors) // 83)] | ||||||
| 
 | 
 | ||||||
|  | @ -812,7 +815,7 @@ class S1C(device): | ||||||
|             _name = str(bytes(sens[4:26]).decode()) |             _name = str(bytes(sens[4:26]).decode()) | ||||||
|             _order = ord(chr(sens[1])) |             _order = ord(chr(sens[1])) | ||||||
|             _type = ord(chr(sens[3])) |             _type = ord(chr(sens[3])) | ||||||
|           _serial = bytes(codecs.encode(sens[26:30],"hex")).decode() |             _serial = bytes(codecs.encode(sens[26:30], "hex")).decode() | ||||||
| 
 | 
 | ||||||
|             type_str = S1C_SENSORS_TYPES.get(_type, 'Unknown') |             type_str = S1C_SENSORS_TYPES.get(_type, 'Unknown') | ||||||
| 
 | 
 | ||||||
|  | @ -833,7 +836,7 @@ class S1C(device): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class dooya(device): | class dooya(device): | ||||||
|   def __init__ (self, host, mac, devtype): |     def __init__(self, host, mac, devtype): | ||||||
|         device.__init__(self, host, mac, devtype) |         device.__init__(self, host, mac, devtype) | ||||||
|         self.type = "Dooya DT360E" |         self.type = "Dooya DT360E" | ||||||
| 
 | 
 | ||||||
|  | @ -847,7 +850,8 @@ class dooya(device): | ||||||
|         packet[10] = 0x44 |         packet[10] = 0x44 | ||||||
|         response = self.send_packet(0x6a, packet) |         response = self.send_packet(0x6a, packet) | ||||||
|         err = response[0x22] | (response[0x23] << 8) |         err = response[0x22] | (response[0x23] << 8) | ||||||
|     if err == 0: |         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]) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue