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()
