def process_cloud_data(self, mysocket,data): if len(data) == int.from_bytes(data[2:4],byteorder='big'): # Check correct lenght of packet again print(threading.get_ident()) did = int.from_bytes(data[8:12],byteorder='big') self.do_log_raw(did,binascii.hexlify(data), "from_cloud") if did == mysocket.ddid: m = Message.parse(data, mysocket.ctx) print("Headertime %s " %m.header.value["ts"]) print("Localtime %s " %datetime.datetime.utcnow() ) if m.data["length"] > 0: method = m.data.value.get("method", "NONE") device_result = m.data.value.get("result", "NONE") device_error = m.data.value.get("error", "NONE") packetid = m.data.value.get("id", 0) print("Cloud->%s : messageID: %s Method: %s " % (mysocket.dname,packetid,method)) print("Cloud->%s : Value: %s" % (mysocket.dname,m.data.value)) self.do_log(did, m.data.value, "from_cloud") if (mysocket.full_cloud_forward == 1 and (method not in mysocket.blocked_methods_from_cloud_list) and (packetid not in mysocket.blocked_from_cloud_list)): mysocket.sendmydata(data) # forward data to client if (packetid in mysocket.blocked_from_client_list): mysocket.blocked_from_cloud_list.remove(packetid) else: print("Cloud->%s : Ping-Pong" % mysocket.dname) if ((mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1)): #self.do_log(did,"PING-PONG (len=32)","from_cloud(ping)") mysocket.sendmydata(data) # forward data to client else: print("Wrong packet size %s %s " % (len(data),int.from_bytes(data[2:4],byteorder='big'))) return 1 return 0
def switchoff(): helobytes = bytes.fromhex( '21310020ffffffffffffffffffffffffffffffffffffffffffffffffffffffff') s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(helobytes, ('192.168.31.201', 54321)) # 插座ip,端口54321 data, addr = s.recvfrom(1024) print("data信息") print(data) m = Message.parse(data) tok = codecs.encode(m.checksum, 'hex') print(m) print(tok) # 控制脚本 ts = m.header.value.ts + datetime.timedelta(seconds=1) device_id = m.header.value.device_id cmd = {'id': 1, 'method': 'set_power', 'params': ['off']} header = { 'length': 0, 'unknown': 0x00000000, 'device_id': device_id, 'ts': ts } msg = {'data': {'value': cmd}, 'header': {'value': header}, 'checksum': 0} m0 = Message.build(msg, token=m.checksum) print("m0的信息") print(m0) s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s2.sendto(m0, ('192.168.31.201', 54321)) return "off success"
def mirobo_discover(): """ Scan for devices in the network. Code taken from /usr/local/lib/python3.5/dist-packages/miio/device.py:def discover() """ timeout = 5 seen_addrs = [] # type: List[str] seen_tokens = [] # type: List[str] addr = '192.168.8.1' # '<broadcast>' # magic, length 32 helobytes = bytes.fromhex( '21310020ffffffffffffffffffffffffffffffffffffffffffffffffffffffff') s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) s.settimeout(timeout) for _i in range(3): s.sendto(helobytes, (addr, 54321)) while True: try: data, addr = s.recvfrom(1024) m = Message.parse(data) # type: Message # print("Got a response: %s" % m) if addr[0] not in seen_addrs: token = codecs.encode(m.checksum, 'hex') if type(token) is bytes: token = token.decode() # tostring print(" IP %s: %s - token: %s" % (addr[0], m.header.value.devtype, token)) seen_addrs.append(addr[0]) seen_tokens.append([addr[0], token]) except socket.timeout: print("Discovery done") return seen_tokens except Exception as ex: print("error while reading discover results: %s", ex) break return None
def process_cloud_data(self, mysocket, data): if len(data) == int.from_bytes(data[2:4], byteorder='big'): # Check correct lenght of packet again did = int.from_bytes(data[8:12], byteorder='big') self.do_log_raw(did, binascii.hexlify(data), MessageDirection.FromCloud) if did == mysocket.ddid: m = Message.parse(data, **mysocket.ctx) print("Headertime %s " % m.header.value["ts"]) print("Localtime %s " % datetime.datetime.utcnow()) if m.data["length"] > 0: if m.data.value: method = m.data.value.get("method", "NONE") device_result = m.data.value.get("result", "NONE") device_error = m.data.value.get("error", "NONE") packetid = m.data.value.get("id", 0) print("%s<-cloud : messageID: %s Method: %s " % (mysocket.dname, packetid, method)) print("%s<-cloud : Value: %s" % (mysocket.dname, m.data.value)) self.do_log(did, m.data.value, MessageDirection.FromCloud) if mysocket.full_cloud_forward == 1 \ and method not in blocked_methods_from_cloud_list \ and packetid not in mysocket.blocked_from_cloud_list: mysocket.send_data_to_client(data) # forward data to client if packetid in mysocket.blocked_from_client_list: mysocket.blocked_from_cloud_list.remove(packetid) else: print("%s<-cloud : Couldn't parse message!" % mysocket.dname) else: print("%s<-cloud : Ping-Pong" % mysocket.dname) if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): # self.do_log(did,"PING-PONG (len=32)", MessageDirection.FromCloud + "(ping)") mysocket.send_data_to_client(data) # forward data to client else: print("Wrong packet size %s %s " % (len(data), int.from_bytes(data[2:4], byteorder='big'))) return 1 return 0
def process_data(self, mysocket, data): """ Parse message in data :param mysocket: connection handler instance :param data: message as bytes :return: 1 on failure, 0 on success """ clienthello = bytes.fromhex( "21310020ffffffffffffffff0000000000000000000000000000000000000000") timestamp = binascii.hexlify(struct.pack('>I', round( time.time()))).decode("utf-8") serverhello = bytes.fromhex("21310020ffffffffffffffff" + timestamp + "00000000000000000000000000000000") if len(data) == int.from_bytes( data[2:4], byteorder='big'): # Check correct lenght of packet again self.do_log_raw(threading.get_ident(), binascii.hexlify(data), MessageDirection.FromClient) if data == clienthello: print("{} thats a client hello") # print("< RAW: %s" % binascii.hexlify(serverhello)) mysocket.clienthello = data mysocket.send_data_to_client(serverhello) elif data[0:12] == clienthello[0:12]: print("{} thats a long client hello") serverhello = bytes.fromhex("21310020ffffffffffffffff" + timestamp) + data[16:32] # print("< RAW: %s" % binascii.hexlify(serverhello)) mysocket.clienthello = data mysocket.send_data_to_client(serverhello) else: did = int.from_bytes(data[8:12], byteorder='big') # register socket connection for device to allow sending custom commands outside # the request handler device = get_device(did) if device: device[1] = mysocket try: if self.cursor.execute( "SELECT did,name,enckey,forward_to_cloud,full_cloud_forward FROM devices WHERE did = %s", did) == 1: # Fetch all the rows in a list of lists. results = self.cursor.fetchall() if not results: print( "Error: unable to fetch data for did %s. Device unknown?" % did) return 1 for row in results: ddid = row[0] dname = row[1] denckey = row[2] forward_to_cloud = row[3] full_cloud_forward = row[4] # Now print fetched result print( "ddid = %s, dname = %s, denckey = %s, forward_to_cloud = %d, full_cloud_forward = %d" % (ddid, dname, denckey, forward_to_cloud, full_cloud_forward)) else: print( "Error: unable to fetch data for did %s. Device unknown?" % did) return 1 except Exception: print("Error: unable to fetch data for did %s" % did) raise enckey = denckey enckey = enckey + ( 16 - len(enckey) ) * "\x00" # extend key if its shorter than 16 bytes ctx = {'token': enckey.encode()} m = Message.parse(data, **ctx) # a ddid of 0 is ok for the first time if mysocket.ddid != 0 and mysocket.ddid != ddid: print("(!!!) Warning, did missmatch: %d != %d" % (mysocket.ddid, ddid)) mysocket.ddid = ddid mysocket.ctx = ctx mysocket.dname = dname mysocket.device_id = m.header.value["device_id"] mysocket.forward_to_cloud = forward_to_cloud mysocket.full_cloud_forward = full_cloud_forward self.set_last_contact(ddid, mysocket.client_address[0], mysocket.connmode) print("Headertime %s " % m.header.value["ts"]) print("Localtime %s " % datetime.datetime.utcnow()) if m.data["length"] > 0: method = m.data.value.get("method", "NONE") device_result = m.data.value.get("result", "NONE") device_error = m.data.value.get("error", "NONE") packetid = m.data.value.get("id", 0) print("%s : messageID: %s Method: %s " % (dname, packetid, method)) print("%s : Value: %s" % (dname, m.data.value)) if method == "_otc.info": params = m.data.value["params"] try: self.cursor.execute( "UPDATE devices SET token = %s, fw = %s, mac = %s, ssid = %s, model = %s, netinfo = %s WHERE did = %s", (params["token"], params["fw_ver"], params["mac"], params["ap"]["ssid"], params["model"], params["netif"]["localIp"], did)) self.db.commit() except Exception as e: # Rollback in case there is any error print("!!! (eee) SQL rollback : %s" % str(e)) self.db.rollback() self.do_log(did, m.data.value, MessageDirection.FromClient) cmd = { "id": packetid, "result": { "otc_list": [{ "ip": my_cloudserver_ip, "port": 80 }], "otc_test": { "list": [{ "ip": my_cloudserver_ip, "port": 8053 }], "interval": 1800, "firsttest": 769 } } } if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): self.do_log( did, m.data.value, MessageDirection.ToCloud + "(blck_resp)") mysocket.blocked_from_cloud_list.append( packetid ) # block real otc_info response from cloud mysocket.send_data_to_cloud(data) elif method in status_methods: self.do_log(did, m.data.value, MessageDirection.FromClient) cmd = {"id": packetid, "result": "ok"} if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): self.do_log(did, m.data.value, MessageDirection.ToCloud + "(status)") mysocket.send_data_to_cloud(data) return 0 elif method == "NONE" and (device_result != "NONE" or device_error != "NONE"): # client sent a result for a request self.do_log(did, m.data.value, MessageDirection.FromClient) if packetid in self.expected_messages: self.expected_messages.pop(packetid).set() if (mysocket.full_cloud_forward == 1) and ( packetid not in mysocket.blocked_from_client_list): self.do_log(did, m.data.value, MessageDirection.ToCloud + "(result)") mysocket.send_data_to_cloud(data) if packetid in mysocket.blocked_from_client_list: mysocket.blocked_from_client_list.remove(packetid) return 0 elif method == "_sync.batch_gen_room_up_url": self.do_log(did, m.data.value, MessageDirection.FromClient) # cmd = { # "id": packetid, # "result": ["https://xxx/index.php?id=1", # "https://xxx/index.php?id=2", # "https://xxx/index.php?id=3", # "https://xxx/index.php?id=4"] # } if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): self.do_log(did, m.data.value, MessageDirection.ToCloud) # mysocket.blocked_from_cloud_list.append(packetid) # block real response from cloud mysocket.send_data_to_cloud(data) return 0 else: print("%s : unknown method" % dname) self.do_log(did, m.data.value, MessageDirection.FromClient) cmd = {"id": packetid, "result": "ok"} # send response to client self.do_log(did, cmd, MessageDirection.ToClient) send_ts = m.header.value["ts"] + datetime.timedelta( seconds=1) header = { 'length': 0, 'unknown': 0x00000000, 'device_id': m.header.value["device_id"], 'ts': send_ts } msg = { 'data': { 'value': cmd }, 'header': { 'value': header }, 'checksum': 0 } c = Message.build(msg, **ctx) print("%s : prepare response" % dname) print("%s : Value: %s" % (dname, cmd)) # print("< RAW: %s" % binascii.hexlify(c)) mysocket.send_data_to_client(c) else: print("%s : Ping-Pong" % dname) if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): # self.do_log(did,"PING (len=32)", MessageDirection.ToCloud + "(ping)") mysocket.send_data_to_cloud(data) else: # print("< RAW: %s" % binascii.hexlify(data)) mysocket.send_data_to_client(data) # Ping-Pong else: print("Wrong packet size %s %s " % (len(data), int.from_bytes(data[2:4], byteorder='big'))) return 1 return 0
# -*- coding: utf-8 -*- """ TODO description @author: hch @date : 2021/3/27 """ import codecs import socket from miio.protocol import Message if __name__ == '__main__': helobytes = bytes.fromhex( '21310020ffffffffffffffffffffffffffffffffffffffffffffffffffffffff') s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(helobytes, ('192.168.3.23', 54321)) # 插座ip,端口54321 data, addr = s.recvfrom(1024) print(data, addr) m = Message.parse(data) tok = codecs.encode(m.checksum, 'hex') print(m) print(tok)
def process_data(self, mysocket, data): """ Parse message in data :param mysocket: connection handler instance :param data: message as bytes :return: 1 on failure, 0 on success """ my_cloudserver_i_p = "10.0.0.1" clienthello = bytes.fromhex("21310020ffffffffffffffff0000000000000000000000000000000000000000") timestamp = binascii.hexlify(struct.pack('>I', round(time.time()))).decode("utf-8") serverhello = bytes.fromhex("21310020ffffffffffffffff" + timestamp + "00000000000000000000000000000000") if len(data) == int.from_bytes(data[2:4], byteorder='big'): # Check correct lenght of packet again self.do_log_raw(threading.get_ident(), binascii.hexlify(data), MessageDirection.FromClient) if data == clienthello: print("{} thats a client hello") # print("< RAW: %s" % binascii.hexlify(serverhello)) mysocket.clienthello = data mysocket.send_data_to_client(serverhello) elif data[0:12] == clienthello[0:12]: print("{} thats a long client hello") serverhello = bytes.fromhex("21310020ffffffffffffffff" + timestamp) + data[16:32] # print("< RAW: %s" % binascii.hexlify(serverhello)) mysocket.clienthello = data mysocket.send_data_to_client(serverhello) else: did = int.from_bytes(data[8:12], byteorder='big') # register socket connection for device to allow sending custom commands outside # the request handler device = get_device(did) if device: device[1] = mysocket try: if self.cursor.execute("SELECT did,name,enckey,forward_to_cloud,full_cloud_forward FROM devices WHERE did = %s", did) == 1: # Fetch all the rows in a list of lists. results = self.cursor.fetchall() if not results: print("Error: unable to fetch data for did %s. Device unknown?" % did) return 1 for row in results: ddid = row[0] dname = row[1] denckey = row[2] forward_to_cloud = row[3] full_cloud_forward = row[4] # Now print fetched result print("ddid = %s, dname = %s, denckey = %s, full_cloud_forward = %d, forward_to_cloud = %d" % (ddid, dname, denckey, forward_to_cloud, full_cloud_forward)) else: print("Error: unable to fetch data for did %s. Device unknown?" % did) return 1 except Exception: print("Error: unable to fetch data for did %s" % did) raise enckey = denckey enckey = enckey + (16 - len(enckey)) * "\x00" # extend key if its shorter than 16 bytes ctx = {'token': enckey.encode()} m = Message.parse(data, **ctx) # a ddid of 0 is ok for the first time if mysocket.ddid != 0 and mysocket.ddid != ddid: print("(!!!) Warning, did missmatch: %d != %d" % (mysocket.ddid, ddid)) mysocket.ddid = ddid mysocket.ctx = ctx mysocket.dname = dname mysocket.device_id = m.header.value["device_id"] mysocket.forward_to_cloud = forward_to_cloud mysocket.full_cloud_forward = full_cloud_forward self.set_last_contact(ddid, mysocket.client_address[0], mysocket.connmode) print("Headertime %s " % m.header.value["ts"]) print("Localtime %s " % datetime.datetime.utcnow()) if m.data["length"] > 0: method = m.data.value.get("method", "NONE") device_result = m.data.value.get("result", "NONE") device_error = m.data.value.get("error", "NONE") packetid = m.data.value.get("id", 0) print("%s : messageID: %s Method: %s " % (dname, packetid, method)) print("%s : Value: %s" % (dname, m.data.value)) if method == "_otc.info": params = m.data.value["params"] try: self.cursor.execute( "UPDATE devices SET token = %s, fw = %s, mac = %s, ssid = %s, model = %s, netinfo = %s WHERE did = %s", (params["token"], params["fw_ver"], params["mac"], params["ap"]["ssid"], params["model"], params["netif"]["localIp"], did)) self.db.commit() except Exception as e: # Rollback in case there is any error print("!!! (eee) SQL rollback : %s" % str(e)) self.db.rollback() self.do_log(did, m.data.value, MessageDirection.FromClient) cmd = { "id": packetid, "result": {"otc_list": [{"ip": my_cloudserver_i_p, "port": 80}], "otc_test": {"list": [{"ip": my_cloudserver_i_p, "port": 8053}], "interval": 1800, "firsttest": 769}} } if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): self.do_log(did, m.data.value, MessageDirection.ToCloud + "(blck_resp)") mysocket.blocked_from_cloud_list.append(packetid) # block real otc_info response from cloud mysocket.send_data_to_cloud(data) elif method in status_methods: self.do_log(did, m.data.value, MessageDirection.FromClient) cmd = { "id": packetid, "result": "ok" } if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): self.do_log(did, m.data.value, MessageDirection.ToCloud + "(status)") mysocket.send_data_to_cloud(data) return 0 elif method == "NONE" and (device_result != "NONE" or device_error != "NONE"): # client sent a result for a request self.do_log(did, m.data.value, MessageDirection.FromClient) if packetid in self.expected_messages: self.expected_messages.pop(packetid).set() if (mysocket.full_cloud_forward == 1) and (packetid not in mysocket.blocked_from_client_list): self.do_log(did, m.data.value, MessageDirection.ToCloud + "(result)") mysocket.send_data_to_cloud(data) if packetid in mysocket.blocked_from_client_list: mysocket.blocked_from_client_list.remove(packetid) return 0 elif method == "_sync.batch_gen_room_up_url": self.do_log(did, m.data.value, MessageDirection.FromClient) # cmd = { # "id": packetid, # "result": ["https://xxx/index.php?id=1", # "https://xxx/index.php?id=2", # "https://xxx/index.php?id=3", # "https://xxx/index.php?id=4"] # } if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): self.do_log(did, m.data.value, MessageDirection.ToCloud) # mysocket.blocked_from_cloud_list.append(packetid) # block real response from cloud mysocket.send_data_to_cloud(data) return 0 else: print("%s : unknown method" % dname) self.do_log(did, m.data.value, MessageDirection.FromClient) cmd = { "id": packetid, "result": "ok" } # send response to client self.do_log(did, cmd, MessageDirection.ToClient) send_ts = m.header.value["ts"] + datetime.timedelta(seconds=1) header = {'length': 0, 'unknown': 0x00000000, 'device_id': m.header.value["device_id"], 'ts': send_ts} msg = {'data': {'value': cmd}, 'header': {'value': header}, 'checksum': 0} c = Message.build(msg, **ctx) print("%s : prepare response" % dname) print("%s : Value: %s" % (dname, cmd)) # print("< RAW: %s" % binascii.hexlify(c)) mysocket.send_data_to_client(c) else: print("%s : Ping-Pong" % dname) if (mysocket.forward_to_cloud == 1) or (mysocket.full_cloud_forward == 1): # self.do_log(did,"PING (len=32)", MessageDirection.ToCloud + "(ping)") mysocket.send_data_to_cloud(data) else: # print("< RAW: %s" % binascii.hexlify(data)) mysocket.send_data_to_client(data) # Ping-Pong else: print("Wrong packet size %s %s " % (len(data), int.from_bytes(data[2:4], byteorder='big'))) return 1 return 0
import codecs import socket import datetime from miio.protocol import Message helobytes = bytes.fromhex('21310020ffffffffffffffffffffffffffffffffffffffffffffffffffffffff') s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(helobytes, ('192.168.31.201', 54321)) # 插座ip,端口54321 data, addr = s.recvfrom(1024) print("data信息") print(data) m = Message.parse(data) tok = codecs.encode(m.checksum, 'hex') print(m) print(tok) # 控制脚本 ts = m.header.value.ts + datetime.timedelta(seconds=1) device_id = m.header.value.device_id cmd = {'id': 1, 'method': 'set_power', 'params': ['off']} header = {'length': 0, 'unknown': 0x00000000, 'device_id': device_id, 'ts': ts} msg = {'data': {'value': cmd}, 'header': {'value': header}, 'checksum': 0} m0 = Message.build(msg, token=m.checksum) print("m0的信息") print(m0) s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s2.sendto(m0, ('192.168.31.201', 54321)) data2, addr2 = s2.recvfrom(1024)