Jun-09-2019, 03:25 PM
I have a Python Script based on
https://www.beardmonkey.eu/tplink/hs110/...hs110.html
https://www.softscheck.com/en/reverse-en...ink-hs110/
It retrieves data from a smart plug. It works perfectly fine, but I am trying to understand every line of code and I am having trouble with a couple of things. Most of it is commented, the lines that are not commented are the ones I do not understand. Better than posting parts of the script, I thought I should post the whole thing and see if someone can help me decipher it. Thanks!
Basically I am having trouble with the first three def:
Any help is truly appreciated!
https://www.beardmonkey.eu/tplink/hs110/...hs110.html
https://www.softscheck.com/en/reverse-en...ink-hs110/
It retrieves data from a smart plug. It works perfectly fine, but I am trying to understand every line of code and I am having trouble with a couple of things. Most of it is commented, the lines that are not commented are the ones I do not understand. Better than posting parts of the script, I thought I should post the whole thing and see if someone can help me decipher it. Thanks!
Basically I am having trouble with the first three def:
int_to_bytes(x)
, encrypt(string)
, decrypt(string)
and with this line decrypted_data = decrypt(data[4:]).decode()
Any help is truly appreciated!
import sys import socket import threading from struct import * import json import datetime def int_to_bytes(x): return x.to_bytes((x.bit_length() + 7) // 8, 'big') def encrypt(string): key = 171 result = pack('>I', len(string)) for i in string: #same as for (int i = 0; i < str.length(); ++i) a = key ^ i #XOR the bits key = a result += int_to_bytes(a) return result def decrypt(string): key = 171 result = b"" #sequence of octets (integers between 0 and 255) for i in string: a = key ^ i key = i result += int_to_bytes(a) return result #Function that connects to SM and returns data def send_hs_command(address, port, cmd): data = b"" #sequence of octets (integers between 0 and 255) tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #CREATING SOCKET: SOCK_STREAM means connection oriented TCP protocol. #AF_INET is an address family that is used to designate the type of addresses #that your socket can communicate with (in this case, Internet Protocol v4 addresses) try: tcp_sock.connect((address, port)) #socket.connect(address)Connect to a remote socket at address. (The format of address #depends on the address family — see above. tcp_sock.send(encrypt(cmd)) #Send data to the socket. The socket must be connected to a remote socket. Returns the number of bytes sent #It encrypts the EMETER cmd and sends it to the socket data = tcp_sock.recv(2048) #Receive data from the socket. The return value is a string representing the data received. #The maximum amount of data to be received at once is specified by bufsize except socket.error: #raise an exception which forces your program to output an error when something in it goes wrong. print(datetime.datetime.utcnow().isoformat(), "Socket closed.", file=sys.stderr) finally: tcp_sock.close() #Close the socket. All future operations on the socket object will fail. #The remote end will receive no more data return data #Function that actually runs the program every 5 seconds def run(): #threading.Timer(5.0, run).start() #retrieve data from function and save it into data data = send_hs_command("192.168.0.106", 9999, b'{"emeter":{"get_realtime":{}}}') print("data", '\n', data,'\n') #if the function does not return anything, send a message if not data: print(datetime.datetime.utcnow().isoformat(), "No data returned on power request.", file=sys.stderr) return #if the function returns data, it will be decrypted because it was encrypted in the function decrypted_data = decrypt(data[4:]).decode() #This method is used to convert from one encoding scheme, #in which argument string is encoded to the desired encoding scheme. print("decrypted_data", '\n',decrypted_data,'\n' ) #decrypted data will be turned into json json_data = json.loads(decrypted_data) print("json_data", '\n',json_data,'\n' ) #json data will be modified again, but not in order? emeter = json_data["emeter"]["get_realtime"] print("emeter", '\n', emeter,'\n') #I think this is only for the order of the data and to print a timestamp finaldata = { "timestamp": datetime.datetime.utcnow().isoformat(), "voltage_mv":emeter["voltage_mv"], "current_ma":emeter["current_ma"], "power_mw":emeter["power_mw"] , "energy_wh": emeter["total_wh"], } print("finaldata", '\n',finaldata,'\n') #I think this is to keep the order, if I print finaldata it is not organized #Writing a JSON object, serializing, DICT into JSON OBJECT print("json.dumps(finaldata)", '\n',json.dumps(finaldata)) #if data was returned but no emeter was returned, then.. if not emeter: print("No emeter data returned on power request.", file=sys.stderr) return run()