Exemple #1
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"
Exemple #2
0
def send_manual_command(method, params, connection):
    cmdid = send_manual_command.commandcounter
    send_manual_command.commandcounter += 1

    print("---------Send message to client {} {}".format(
        connection.dname, connection.client_address))
    cmd = {"id": cmdid, "method": '%s' % method, "params": params, "from": '4'}

    # add to blocklist to not forward results from my cmds to the cloud
    connection.blocked_from_client_list.append(cmdid)

    # build message
    send_ts = datetime.datetime.utcnow() + datetime.timedelta(seconds=1)
    header = {
        'length': 0,
        'unknown': 0x00000000,
        'device_id': connection.device_id,
        'ts': send_ts
    }
    msg = {'data': {'value': cmd}, 'header': {'value': header}, 'checksum': 0}
    connection.Cloudi.do_log(connection.ddid, cmd,
                             MessageDirection.ToClient + "(cmd)")
    print("Sendtime %s " % send_ts)
    print("Localtime %s " % datetime.datetime.utcnow())
    c = Message.build(msg, **connection.ctx)
    print("%s : prepare command" % connection.dname)
    print("%s : Value: %s" % (connection.dname, msg))

    # print("< RAW: %s" % binascii.hexlify(c))

    if connection.send_data_to_client_and_wait_for_result(c, cmdid):
        return cmdid
    else:
        return None
Exemple #3
0
	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
Exemple #4
0
 def handle(self):
     # self.request is the client connection
     thread_id = threading.get_ident()
     print(" --------------- Thread-id: %s" % thread_id)
     self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     if self.cloudstate != "online":
         self.cloudstate = "offline"
     self.Cloudi = CloudClient()
     while True:
         if self.request.fileno() < 0:
             break
         if self.cloudstate == "online":
             if self.sock.fileno() < 0:
                 print("Cloud connection disconnected")
                 self.sock.close()
                 self.cloudstate = "offline"
                 break
             r, w, x = select.select([self.request, self.sock], [], [], 1)
         else:
             r, w, x = select.select([self.request], [], [], 1)
         for s in r:
             if s == self.request:
                 self.on_read()
             if s == self.sock:
                 self.on_read_cloud()
         if self.ddid != 0:
             if self.sended == 0:
                 queue_return = self.Cloudi.get_commands(self.ddid)
                 # print("Queue:")
                 # print(queue_return["id"])
                 # print(self.commandcounter)
                 # if queue_return["id"] >= self.commandcounter:
                 if queue_return["id"] >= 0:
                     self.commandcounter = queue_return["id"]
                     self.Cloudi.mark_command_as_processed(self.ddid, queue_return["id"])
                     cmd = queue_return
                     cmd["id"] = self.commandcounter
                     self.blocked_from_client_list.append(cmd["id"])  # add to blocklist to not forward results from my cmds to the cloud
                     send_ts = datetime.datetime.utcnow() + datetime.timedelta(seconds=1)
                     header = {'length': 0, 'unknown': 0x00000000,
                               'device_id': self.device_id,
                               'ts': send_ts}
                     msg = {'data': {'value': cmd},
                            'header': {'value': header},
                            'checksum': 0}
                     self.Cloudi.do_log(self.ddid, cmd, "client << dustcloud (cmd)")
                     print("Sendtime %s " % send_ts)
                     print("Localtime %s " % datetime.datetime.utcnow())
                     c = Message.build(msg, **self.ctx)
                     print("%s : prepare response (command)" % self.dname)
                     print("%s : Value: %s" % (self.dname, msg))
                     # print("< RAW: %s" % binascii.hexlify(c))
                     self.sendmydata(c)
     print("Close Request")
     self.sock.close()
     self.request.close()
     print(" --------------- Thread-id: %s closed" % thread_id)
Exemple #5
0
def send_pending_commands(connection):
    if not connection.ddid:
        # if there is no device id it doesn't make sense to send any commands
        return

    queue_return = connection.Cloudi.get_commands(connection.ddid)
    if queue_return["id"] >= 0:
        print("---------Send message to client {}".format(connection.dname))
        connection.commandcounter = queue_return["id"]
        connection.Cloudi.mark_command_as_processed(connection.ddid,
                                                    queue_return["id"])
        cmd = queue_return
        cmd["id"] = connection.commandcounter
        connection.blocked_from_client_list.append(
            cmd["id"]
        )  # add to blocklist to not forward results from my cmds to the cloud
        send_ts = datetime.datetime.utcnow() + datetime.timedelta(seconds=1)
        header = {
            'length': 0,
            'unknown': 0x00000000,
            'device_id': connection.device_id,
            'ts': send_ts
        }
        msg = {
            'data': {
                'value': cmd
            },
            'header': {
                'value': header
            },
            'checksum': 0
        }
        connection.Cloudi.do_log(connection.ddid, cmd,
                                 MessageDirection.ToClient + "(cmd)")
        print("Sendtime %s " % send_ts)
        print("Localtime %s " % datetime.datetime.utcnow())
        c = Message.build(msg, **connection.ctx)
        print("%s : prepare command" % connection.dname)
        print("%s : Value: %s" % (connection.dname, msg))
        # print("< RAW: %s" % binascii.hexlify(c))
        connection.sendmydata(c)
Exemple #6
0
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
Exemple #7
0
def send_manual_command(method, params, connection):
    cmdid = send_manual_command.commandcounter
    send_manual_command.commandcounter += 1

    print("---------Send message to client {} {}".format(connection.dname, connection.client_address))
    cmd = {
        "id": cmdid,
        "method": '%s' % method,
        "params": params,
        "from": '4'
    }

    # add to blocklist to not forward results from my cmds to the cloud
    connection.blocked_from_client_list.append(cmdid)

    # build message
    send_ts = datetime.datetime.utcnow() + datetime.timedelta(seconds=1)
    header = {'length': 0, 'unknown': 0x00000000,
              'device_id': connection.device_id,
              'ts': send_ts}
    msg = {'data': {'value': cmd},
           'header': {'value': header},
           'checksum': 0}
    connection.Cloudi.do_log(connection.ddid, cmd, MessageDirection.ToClient + "(cmd)")
    print("Sendtime %s " % send_ts)
    print("Localtime %s " % datetime.datetime.utcnow())
    c = Message.build(msg, **connection.ctx)
    print("%s : prepare command" % connection.dname)
    print("%s : Value: %s" % (connection.dname, msg))

    # print("< RAW: %s" % binascii.hexlify(c))

    if connection.send_data_to_client_and_wait_for_result(c, cmdid):
        return cmdid
    else:
        return None
Exemple #8
0
    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
Exemple #9
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
Exemple #10
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)
Exemple #11
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
        """
        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)