Using python to communicate with Xiaomi gateway

Three parts of communication between python and Xiaomi gateway:

The understanding of the following content needs to be used in conjunction with the green meter gateway LAN communication protocol

1. Monitor the multicast information sent by the gateway: (there are life signals and event information of the gateway and connected equipment)

2. Read the required information

3. Control connection device (involving token encryption part)

 

1. upd broadcast monitors the multicast information of Xiaomi gateway

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 import socket
 5 
 6 def get_gateway_heart():
 7     SENDERIP = "0.0.0.0"
 8     MYPORT = 9898
 9     MYGROUP = '224.0.0.50'
10 
11     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
12     #allow multiple sockets to use the same PORT number
13     sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
14     #Bind to the port that we know will receive multicast data
15     sock.bind((SENDERIP,MYPORT))
16     #tell the kernel that we are a multicast socket
17     #sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
18     #Tell the kernel that we want to add ourselves to a multicast group
19     #The address for the multicast group is the third param
20     status = sock.setsockopt(socket.IPPROTO_IP,
21         socket.IP_ADD_MEMBERSHIP,
22         socket.inet_aton(MYGROUP) + socket.inet_aton(SENDERIP));
23 
24     #sock.setblocking(0)
25     #ts = time.time()
26     data, addr = sock.recvfrom(1024)
27     data_str=str(data,encoding='utf-8')
28 #    sock.close()
29     return data_str
30 
31 
32 if __name__=='__main__':
33     while True:
34         tmp=get_gateway_heart()
35         print(tmp)

2. The calculation method of converting the initial password vector of Xiaomi gateway to string

1 from binascii import b2a_hex, a2b_hex
2 import sys
3 
4 s='17996d093d28ddb3ba695a2e6f58562e'    #Initial vector
5 m=a2b_hex(s)    
6 print(m)
7 
8 #Initial vector after conversion
9 #b'\x17\x99m\t=(\xdd\xb3\xbaiZ.oXV.'

3. The method of encrypting token

 1 from Crypto.Cipher import AES
 2 from binascii import b2a_hex, a2b_hex
 3 
 4 class prpcrypt():
 5     def __init__(self, key='cy5zmrpqws05vsqj'):
 6         self.key = key              #
 7         self.mode = AES.MODE_CBC
 8 
 9     # Encryption function, if the text is less than 16 bits, use space to complement it to 16 bits,
10     # If more than 16 is not a multiple of 16 at that time, then make up for the multiple of 16.
11     def encrypt(self, text):        #text is the content to encrypt
12         cryptor = AES.new(self.key, self.mode,b'\x17\x99m\t=(\xdd\xb3\xbaiZ.oXV.')
13         # Here key key Length must be 16( AES-128),
14         # 24(AES-192),Or 32. AES-256)Bytes length
15         # at present AES-128 Enough for current use
16         length = 16
17         count = len(text)
18         if count < length:
19             add = (length - count)
20             # \0 backspace
21             text = text + ('\0' * add)
22         elif count > length:
23             add = (length - (count % length))
24             text = text + ('\0' * add)
25         self.ciphertext = cryptor.encrypt(text)
26         # Because the strings obtained during AES encryption are not necessarily ascii character sets, there may be problems when they are output to the terminal or saved
27         # Therefore, the encrypted string is converted into hexadecimal string
28         return str(b2a_hex(self.ciphertext),encoding='utf-8')
29         #return self.ciphertext
30 
31     # After decryption, remove the complemented space strip() Remove b'0000000000000000'
32     def decrypt(self, text):
33         cryptor = AES.new(self.key, self.mode, b'\x17\x99m\t=(\xdd\xb3\xbaiZ.oXV.')
34         plain_text = cryptor.decrypt(a2b_hex(text))
35         return plain_text.rstrip('\0')
36 
37 
38 if __name__ == '__main__':
39     pc = prpcrypt('0987654321qwerty')  # Initialization key
40     e = pc.encrypt('1234567890abcdef')  # encryption
41    # d = pc.decrypt(e)  # Decrypt
42     print("encryption:", e)
43     #print("Decrypt:", d)

4. Obtain the token and encrypt the acquired token

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import socket
import json
from xm_gw.encrypty import prpcrypt

def get_token():    #adopt get_id_list Get token
    ip_port_single = ("192.168.31.150", 9898)
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
    comd = {'cmd': 'get_id_list'}
    order = json.dumps(comd)
    s.sendto(bytes(order, encoding="utf-8"), ip_port_single)
    data,addr=s.recvfrom(1024)
    data_str=str(data,encoding='utf-8')
    token=json.loads(data_str).get('token')
    s.close()
    return token

def get_token_encrypty():
    tok = get_token()  # Get the present token,What to encrypt
    k = prpcrypt()
    key_encrypt = k.encrypt(tok)
    return key_encrypt

if __name__=='__main__':
    tok=get_token()
    tok_encry=get_token_encrypty()
    print(tok)
    print(tok_encry)

5. Establish gateway communication and execute control command

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 import socket
 4 import json
 5 from xm_gw import udp_token_key
 6 
 7 
 8 class udp_gw():
 9     def __init__(self, ip_gateway='192.168.8.100'):
10         self.ip_port_zu43 = ('224.0.0.50', 4321)
11         self.ip_port_single = (ip_gateway, 9898)
12         self.ip_port_zu9898=('224.0.0.50', 9898)
13 
14     def whois(self):
15         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
16         comd = {'cmd': 'whois'}
17         order = json.dumps(comd)
18         s.sendto(bytes(order, encoding="utf-8"), self.ip_port_zu43)
19         data_bytes, addr = s.recvfrom(1024)
20         data_dic = json.loads(str(data_bytes, encoding='utf-8'))
21         s.close()
22         return data_dic
23 
24     def get_id_list(self):
25         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
26         comd = {'cmd': 'get_id_list'}
27         order = json.dumps(comd)
28         s.sendto(bytes(order, encoding="utf-8"), self.ip_port_single)
29         data_bytes, addr = s.recvfrom(1024)
30         data_dic = json.loads(str(data_bytes, encoding='utf-8'))
31         s.close()
32         return data_dic
33 
34     def read_sid(self, sid):
35         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
36         comd = {'cmd': 'read', 'sid': sid}
37         order = json.dumps(comd)
38         s.sendto(bytes(order, encoding="utf-8"), self.ip_port_single)
39         data_bytes, addr = s.recvfrom(1024)
40         data_dic = json.loads(str(data_bytes, encoding='utf-8'))
41         s.close()
42         return data_dic
43 
44     def write_plug(self, status):
45         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
46         key_encrypt = udp_token_key.get_token_encrypty()
47         comd = {"cmd": "write", "model": "plug", "sid": "158d0001b84d9a", "short_id": 46384,
48                 "data": {"status": status, 'key': key_encrypt}}
49         order = json.dumps(comd)
50         s.sendto(bytes(order, encoding="utf-8"), self.ip_port_single)
51         data_bytes, addr = s.recvfrom(1024)
52         data_dic = json.loads(str(data_bytes, encoding='utf-8'))
53         s.close()
54         return data_dic
55 
56     def read_all_sid(self):
57         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
58         ls = json.loads(self.get_id_list().get('data'))
59         ls_sensor_state = []
60         for sid in ls:
61             comd = {'cmd': 'read', 'sid': sid}
62             order = json.dumps(comd)
63             s.sendto(bytes(order, encoding="utf-8"), self.ip_port_single)
64             data_bytes, addr = s.recvfrom(1024)
65             data_dic = json.loads(str(data_bytes, encoding='utf-8'))
66             #            print(data_dic)
67             ls_sensor_state.append(data_dic)
68         s.close()
69         return ls_sensor_state
70 
71     def get_dict_model_sid(self):
72         dic_gw=self.whois()
73         ls=self.read_all_sid()
74         dic_model_sid = {}
75         for dic in ls:
76             model = dic.get('model')
77             sid = dic.get('sid')
78             dic_model_sid[model] = sid
79         dic_model_sid['gateway'] = dic_gw.get('sid')
80         return dic_model_sid
81 
82 
83 if __name__=='__main__':
84     import time
85     #{'plug': '158d0001b84d9a', 'switch': '158d0001c10bd7', 'sensor_ht': '158d0001e87bd9',
86     # 'magnet': '158d0001bb3daf', 'motion': '158d0001c2f110', 'gateway': '7811dcb38599'}
87     gw=udp_gw('192.168.31.150')
88     tmp = gw.read_sid('158d0001b84d9a')
89 #    print(tmp1)
90 #    time.sleep(5)
91 #    gw.write_plug('off')
92 #    time.sleep(5)
93 #    tmp=gw.read_sid('158d0001b84d9a')
94 
95     print(tmp)

Keywords: Python socket JSON encoding

Added by immobilarity on Sat, 04 Apr 2020 00:44:26 +0300