From de35ddae7e40b027b93a11c7bbdc9e86c7f1f365 Mon Sep 17 00:00:00 2001 From: Yann FLEUTOT Date: Sun, 17 Mar 2024 23:27:27 +0100 Subject: [PATCH 1/3] Python 3 --- server.py | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) diff --git a/server.py b/server.py index 3bf32f9..2933732 100644 --- a/server.py +++ b/server.py @@ -1,8 +1,9 @@ -from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer +#!/usr/bin/env python3 + +from http.server import BaseHTTPRequestHandler, HTTPServer import broadlink, configparser -import sys, getopt -import time, binascii -import netaddr +import sys +import time import settings import signal import socket @@ -10,7 +11,6 @@ import json import shutil from os import path -from Crypto.Cipher import AES class Server(HTTPServer): def get_request(self): @@ -73,19 +73,19 @@ def do_POST(self): print ("TRY %s != %s" % (GlobalPassword, password)) except NameError: return self.password_required() - print ("LSE %s != %s" % (GlobalPassword, parameters['password'])) + print ("LSE %s != %s" % (GlobalPassword, password)) self.password_required() def password_required(self): response = "Password required from %s" % self.client_address[0] - self.wfile.write('''{ "error": "%s" }''' % response) + self.wfile.write(bytes('''{ "error": "%s" }''' % response, encoding='utf8')) print (response) self.close_connection = 1 return False def access_denied(self): response = "Client %s is not allowed!" % self.client_address[0] - self.wfile.write('''{ "error": "%s" }''' % response) + self.wfile.write(bytes('''{ "error": "%s" }''' % response, encoding='utf8')) print (response) self.close_connection = 1 return False @@ -204,11 +204,11 @@ def messageHandler(self): else: response = "Failed" if "Failed" in response: - self.wfile.write('''{ "error": "%s" }''' % response) + self.wfile.write(bytes('''{ "error": "%s" }''' % response, encoding='utf8')) elif "Sent" in response: - self.wfile.write('''{ "ok": "%s" }''' % response) + self.wfile.write(bytes('''{ "ok": "%s" }''' % response, encoding='utf8')) else: - self.wfile.write (response); + self.wfile.write (bytes(response, encoding='utf8')); print ("\t"+response) def listCommand(): @@ -235,9 +235,6 @@ def sendCommand(commandName,deviceName): device = DeviceByName[deviceName]; serviceName = deviceName + ' Commands' - deviceKey = device.key - deviceIV = device.iv - if settingsFile.has_option(serviceName, commandName): commandFromSettings = settingsFile.get(serviceName, commandName) elif settingsFile.has_option('Commands', commandName): @@ -272,11 +269,9 @@ def sendCommand(commandName,deviceName): sendCommand(command,deviceName) return True - decodedCommand = binascii.unhexlify(commandFromSettings) - AESEncryption = AES.new(str(deviceKey), AES.MODE_CBC, str(deviceIV)) - encodedCommand = AESEncryption.encrypt(str(decodedCommand)) + decodedCommand = bytes.fromhex(commandFromSettings) - finalCommand = encodedCommand[0x04:] + finalCommand = decodedCommand[0x04:] try: device.send_data(finalCommand) @@ -299,9 +294,6 @@ def learnCommand(commandName, deviceName=None): print ("Waiting %d seconds to capture command" % GlobalTimeout) - deviceKey = device.key - deviceIV = device.iv - device.enter_learning() time.sleep(GlobalTimeout) LearnedCommand = device.check_data() @@ -313,8 +305,7 @@ def learnCommand(commandName, deviceName=None): AdditionalData = bytearray([0x00, 0x00, 0x00, 0x00]) finalCommand = AdditionalData + LearnedCommand - AESEncryption = AES.new(str(deviceKey), AES.MODE_CBC, str(deviceIV)) - decodedCommand = binascii.hexlify(AESEncryption.decrypt(str(finalCommand))) + decodedCommand = finalCommand.hex() backupSettings() try: @@ -325,7 +316,7 @@ def learnCommand(commandName, deviceName=None): settingsFile.write(broadlinkControlIniFile) broadlinkControlIniFile.close() return True - except StandardError as e: + except Exception as e: print("Error writing settings file: %s" % e) restoreSettings() return False @@ -345,7 +336,7 @@ def setStatus(commandName, status, deviceName=None): settingsFile.write(broadlinkControlIniFile) broadlinkControlIniFile.close() return True - except StandardError as e: + except Exception as e: print ("Error writing settings file: %s" % e) restoreSettings() return False @@ -390,7 +381,7 @@ def backupSettings(): shutil.copy2(settings.settingsINI,settings.settingsINI+".bak") def restoreSettings(): - if os.path.isfile(settings.settingsINI+".bak"): + if path.isfile(settings.settingsINI+".bak"): shutil.copy2(settings.settingsINI+".bak",settings.settingsINI) else: print ("Can't find backup to restore! Refusing to make this worse!") @@ -462,6 +453,7 @@ def readSettingsFile(): if Autodetect == True: print ("Beginning device auto-detection ... ") + # Try to support multi-homed broadcast better try: devices = broadlink.discover(DiscoverTimeout,listen_address,broadcast_address) @@ -493,7 +485,7 @@ def readSettingsFile(): print ("%s: Found %s on %s (%s) type: %s" % (device.hostname, device.type, device.host, hexmac, hex(device.devtype))) settingsFile.write(broadlinkControlIniFile) broadlinkControlIniFile.close() - except StandardError as e: + except Exception as e: print ("Error writing settings file: %s" % e) restoreSettings() else: From f3053de77fdbd4583410637663aca6b85c4b3229 Mon Sep 17 00:00:00 2001 From: Yann FLEUTOT Date: Sun, 17 Mar 2024 23:28:39 +0100 Subject: [PATCH 2/3] Added support for RM4 family devices --- server.py | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/server.py b/server.py index 2933732..f5cedf7 100644 --- a/server.py +++ b/server.py @@ -492,21 +492,33 @@ def readSettingsFile(): devices = [] if settings.DevList: for devname in settings.DevList: - if Dev[devname,'Type'] == 'RM' or Dev[devname,'Type'] == 'RM2': + if Dev[devname,'Type'] == 'RM4MINI': + device = broadlink.rm4mini((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) + elif Dev[devname,'Type'] == 'RM4MINIB': + device = broadlink.rm4minib((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) + elif Dev[devname,'Type'] == 'RM4PRO': + device = broadlink.rm4pro((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) + elif Dev[devname,'Type'] == 'RM4': + device = broadlink.rm4((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) + elif Dev[devname,'Type'] == 'RMMINI': + device = broadlink.rmmini((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) + elif Dev[devname,'Type'] == 'RMPRO': + device = broadlink.rmpro((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) + elif Dev[devname,'Type'] == 'RM' or Dev[devname,'Type'] == 'RM2': device = broadlink.rm((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) - if Dev[devname,'Type'] == 'MP1': + elif Dev[devname,'Type'] == 'MP1': device = broadlink.mp1((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) - if Dev[devname,'Type'] == 'SP1': + elif Dev[devname,'Type'] == 'SP1': device = broadlink.sp1((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) - if Dev[devname,'Type'] == 'SP2': + elif Dev[devname,'Type'] == 'SP2': device = broadlink.sp2((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) - if Dev[devname,'Type'] == 'A1': + elif Dev[devname,'Type'] == 'A1': device = broadlink.a1((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) - if Dev[devname,'Type'] == 'HYSEN': + elif Dev[devname,'Type'] == 'HYSEN': device = broadlink.hysen((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) - if Dev[devname,'Type'] == 'S1C': + elif Dev[devname,'Type'] == 'S1C': device = broadlink.S1C((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) - if Dev[devname,'Type'] == 'DOOYA': + elif Dev[devname,'Type'] == 'DOOYA': device = broadlink.dooya((Dev[devname,'IPAddress'], 80), Dev[devname,'MACAddress'], Dev[devname,'Device']) device.timeout = Dev[devname,'Timeout'] if not devname in DeviceByName: From 6fbe43e20824a2d7b04e7cf0a4eda4897fd5cfb9 Mon Sep 17 00:00:00 2001 From: Yann FLEUTOT Date: Sun, 17 Mar 2024 23:29:58 +0100 Subject: [PATCH 3/3] Fixed call to non-existent function --- server.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/server.py b/server.py index f5cedf7..f8f6aef 100644 --- a/server.py +++ b/server.py @@ -551,5 +551,3 @@ def SigInt(signum, frame): serverParams = readSettingsFile() InterruptRequested = False start(**serverParams) - if not ShutdownRequested: - reload(settings)