From 566ebbeeda93200f1c6579a7657ec42781047ef2 Mon Sep 17 00:00:00 2001 From: LukeSpad <64772822+LukeSpad@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:00:48 +0000 Subject: [PATCH] Add files via upload --- .../Server Plugin/Resources/ASBridge.py | 10 +++-- .../Server Plugin/Resources/BLHIP_CLIENT.py | 43 ++++++++++-------- .../Server Plugin/Resources/CONSTANTS.py | 2 +- .../Server Plugin/Resources/MLCLI_CLIENT.py | 44 +++++++++++++------ .../Server Plugin/Resources/MLCONFIG.py | 10 +++-- .../Server Plugin/Resources/MLGW_CLIENT.py | 40 +++++++++-------- .../Server Plugin/Resources/MLtn_CLIENT.py | 26 +++++++---- 7 files changed, 110 insertions(+), 65 deletions(-) diff --git a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/ASBridge.py b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/ASBridge.py index ec843ab..b8ebc6b 100644 --- a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/ASBridge.py +++ b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/ASBridge.py @@ -1,5 +1,8 @@ #!/usr/bin/python -import indigo +try: + import indigo +except ImportError: + pass import logging import os import unicodedata @@ -30,7 +33,6 @@ class MusicController(object): def __init__(self): self.app = SBApplication.applicationWithBundleIdentifier_("com.apple.Music") - # ######################################################################################## # Player information def get_current_track_info(self): @@ -134,9 +136,11 @@ class MusicController(object): self.app.currentTrack().setValue_forKey_('true', 'loved') self.app.currentTrack().setValue_forKey_('true', 'enabled') elif int(rate) == 0: - # If rated 0% then set to disliked and disable the track so it will not be played in shuffle + # If rated 0% then set to disliked and disable the track, so it will not be played in shuffle self.app.currentTrack().setValue_forKey_('true', 'disliked') self.app.currentTrack().setValue_forKey_('false', 'enabled') + # It's obviously a stinker, so let's skip to the next track + self.app.nextTrack() else: # else remove disliked/loved flags and check the track is enabled for playback self.app.currentTrack().setValue_forKey_('false', 'disliked') diff --git a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/BLHIP_CLIENT.py b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/BLHIP_CLIENT.py index 238e7fb..9ad3ae5 100644 --- a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/BLHIP_CLIENT.py +++ b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/BLHIP_CLIENT.py @@ -1,4 +1,7 @@ -import indigo +try: + import indigo +except ImportError: + pass import asynchat import socket import time @@ -48,10 +51,11 @@ class BLHIPClient(asynchat.async_chat): # ##### Client functions def collect_incoming_data(self, data): self.is_connected = True - self._received_data += data + self._received_data += str(data) def found_terminator(self): - # indigo.server.log("Raw Data: " + self._received_data) + if self.debug: + indigo.server.log("Raw Data: " + self._received_data) self.last_received = self._received_data self.last_received_at = time.time() @@ -62,7 +66,7 @@ class BLHIPClient(asynchat.async_chat): indigo.server.log('\tAuthentication Successful!', level=logging.DEBUG) self.query(dev_type="AV renderer") - self._received_data = urllib.unquote(self._received_data) + self._received_data = urllib.parse.unquote(self._received_data) telegram = self._received_data.replace("%201", "") telegram = telegram.split('/') header = telegram[0:4] @@ -73,24 +77,20 @@ class BLHIPClient(asynchat.async_chat): e_string = str(header[0]) if e_string[0] == 'e': if e_string[2:4] == 'OK' and self.debug: - indigo.server.log('Command Successfully Processed: ' + str(urllib.unquote(self._received_data)), - level=logging.DEBUG) + indigo.server.log('Command Successfully Processed: ' + str(self._received_data), level=logging.DEBUG) elif e_string[2:5] == 'CMD': - indigo.server.log('Wrong or Unrecognised Command: ' + str(urllib.unquote(self._received_data)), - level=logging.WARNING) + indigo.server.log('Wrong or Unrecognised Command: ' + str(self._received_data), level=logging.WARNING) elif e_string[2:5] == 'SYN': - indigo.server.log('Bad Syntax, or Wrong Character Encoding: ' + - str(urllib.unquote(self._received_data)), level=logging.WARNING) + indigo.server.log('Bad Syntax, or Wrong Character Encoding: ' + str(self._received_data), + level=logging.WARNING) elif e_string[2:5] == 'ACC': - indigo.server.log('Zone Access Violation: ' + str(urllib.unquote(self._received_data)), - level=logging.WARNING) + indigo.server.log('Zone Access Violation: ' + str(self._received_data), level=logging.WARNING) elif e_string[2:5] == 'LEN': - indigo.server.log('Received Message Too Long: ' + str(urllib.unquote(self._received_data)), - level=logging.WARNING) + indigo.server.log('Received Message Too Long: ' + str(self._received_data), level=logging.WARNING) self._received_data = "" return @@ -190,9 +190,16 @@ class BLHIPClient(asynchat.async_chat): self.is_connected = False self.close() - def send_cmd(self, telegram): + def send_cmd(self, payload): + payload = payload + "\r\n" + payload = payload.encode('UTF8') + telegram = bytearray() + # append payload + for p in payload: + telegram.append(p) + try: - self.push(str(telegram + "\r\n")) + self.push(telegram) except socket.timeout as e: indigo.server.log("\tSocket connection timed out: " + str(e), level=logging.ERROR) self.handle_close() @@ -204,9 +211,9 @@ class BLHIPClient(asynchat.async_chat): self.last_sent_at = time.time() if telegram == 'q Main/global/SYSTEM/BeoLink': if self.debug: - indigo.server.log(self.name + " >>-SENT--> : " + telegram, level=logging.DEBUG) + indigo.server.log(self.name + " >>-SENT--> : " + payload.decode('UTF8'), level=logging.DEBUG) else: - indigo.server.log(self.name + " >>-SENT--> : " + telegram, level=logging.INFO) + indigo.server.log(self.name + " >>-SENT--> : " + payload.decode('UTF8'), level=logging.INFO) time.sleep(0.2) def query(self, zone='*', room='*', dev_type='*', device='*'): diff --git a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/CONSTANTS.py b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/CONSTANTS.py index 0eec4ce..80ed3ef 100644 --- a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/CONSTANTS.py +++ b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/CONSTANTS.py @@ -485,7 +485,7 @@ ml_command_type_dict = dict( ######################################################### # On power up all devices send out a request key telegram. If # no lock manager is allocated the devices send out a key_lost telegram. The Video Master (or Power - # Master in older implementations) then asserts a NEW_LOCKmANAGER telegram and assumes responsibility + # Master in older implementations) then asserts a NEW_LOCKMANAGER telegram and assumes responsibility # for LOCKMANAGER_COMMAND telegrams until a key transfer occurs. # reference: https://tidsskrift.dk/daimipb/article/download/7043/6004/0 (0x12, "KEY_LOST"), # ? diff --git a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLCLI_CLIENT.py b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLCLI_CLIENT.py index 2e0346d..e2aa405 100644 --- a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLCLI_CLIENT.py +++ b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLCLI_CLIENT.py @@ -1,4 +1,7 @@ -import indigo +try: + import indigo +except ImportError: + pass import asynchat import socket import time @@ -26,7 +29,7 @@ class MLCLIClient(asynchat.async_chat): self._i = 0 self._header_lines = 6 - self._received_data = "" + self._received_data = '' self.last_sent = '' self.last_sent_at = time.time() self.last_received = '' @@ -48,7 +51,7 @@ class MLCLIClient(asynchat.async_chat): # ######################################################################################## # ##### Client functions def collect_incoming_data(self, data): - self._received_data += data + self._received_data += str(data) def found_terminator(self): self.last_received = self._received_data @@ -61,8 +64,10 @@ class MLCLIClient(asynchat.async_chat): if self._i <= self._header_lines: self._i += 1 if self._i == self._header_lines - 1: - indigo.server.log("\tAuthenticated! Gateway type is " + telegram[0:4] + "\n", level=logging.DEBUG) - if telegram[0:4] != "MLGW": + if "MLGW" in telegram: + indigo.server.log("\tAuthenticated! Gateway type is MLGW\n", level=logging.DEBUG) + else: + indigo.server.log("\tAuthenticated! Gateway type is BLGW\n", level=logging.DEBUG) self.isBLGW = True # Process telegrams and return json data in human readable format @@ -79,10 +84,15 @@ class MLCLIClient(asynchat.async_chat): # ML protocol message detected items = telegram.split()[1:] if len(items): - telegram = bytearray() + telegram = [] for item in items: + if len(item) == 3: + item = '0x' + item[:-1] + elif len(item) == 4: + item = '0x' + item[:-2] + try: - telegram.append(int(item[:-1], base=16)) + telegram.append(int(item, base=16)) except (ValueError, TypeError): # abort if invalid character found if self.debug: @@ -90,9 +100,8 @@ class MLCLIClient(asynchat.async_chat): ''.join(items) + '\nAborting!', level=logging.ERROR) break - # Decode any telegram with a valid 9 byte header, excluding typy 0x14 (regular clock sync pings) - if len(telegram) >= 9: - # Header: To_Device/From_Device/1/Type/To_Source/From_Source/0/Payload_Type/Length + # Decode any telegram with a valid 9 byte header, excluding type 0x14 (regular clock sync pings) + if len(telegram) > 9: header = telegram[:9] payload = telegram[9:] message = self._decode(telegram) @@ -133,9 +142,16 @@ class MLCLIClient(asynchat.async_chat): self.is_connected = False self.close() - def send_cmd(self, telegram): + def send_cmd(self, payload): + payload = payload + "\r\n" + payload = payload.encode('UTF8') + telegram = bytearray() + # append payload + for p in payload: + telegram.append(p) + try: - self.push(str(telegram + "\r\n")) + self.push(telegram) except socket.timeout as e: indigo.server.log("\tSocket connection timed out: " + str(e), level=logging.ERROR) self.handle_close() @@ -145,7 +161,7 @@ class MLCLIClient(asynchat.async_chat): else: self.last_sent = telegram self.last_sent_at = time.time() - indigo.server.log(self.name + " >>-SENT--> : " + telegram, level=logging.INFO) + indigo.server.log(self.name + " >>-SENT--> : " + payload.decode('UTF8'), level=logging.INFO) time.sleep(0.2) def _report(self, header, payload, message): @@ -156,7 +172,7 @@ class MLCLIClient(asynchat.async_chat): def ping(self): if self.debug: indigo.server.log(self.name + " >>-SENT--> : Ping", level=logging.DEBUG) - self.push('\n') + self.push(b'\n') # ######################################################################################## # ##### Utility functions diff --git a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLCONFIG.py b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLCONFIG.py index 7202499..392b276 100644 --- a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLCONFIG.py +++ b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLCONFIG.py @@ -1,4 +1,7 @@ -import indigo +try: + import indigo +except ImportError: + pass import asyncore import json import requests @@ -22,6 +25,8 @@ class MLConfig: def _download_data(self): try: + indigo.debugger() + indigo.server.log('Downloading configuration data from Gateway...', level=logging.WARNING) url = 'http://' + str(self._host) + '/mlgwpservices.json' # try Basic Auth next (this is needed for the BLGW) @@ -239,7 +244,7 @@ class MLConfig: CONST.rooms.append(room) # Report details of the configuration - n_devices = indigo.devices.len(filter="uk.co.lukes_plugins.BeoGateway.plugin.AVrenderer") - 1 + n_devices = indigo.devices.len(filter="uk.co.lukes_plugins.BeoGateway.plugin.AVrenderer") indigo.server.log('Found ' + str(n_devices) + ' AV Renderers!', level=logging.DEBUG) for node in indigo.devices.iter('uk.co.lukes_plugins.BeoGateway.plugin.AVrenderer'): indigo.server.log('\tMLN ' + str(node.address) + ': ' + str(node.name), level=logging.INFO) @@ -282,7 +287,6 @@ class MLConfig: test = False except KeyError: asyncore.loop(count=1, timeout=0.2) - else: # If this is a NetLink product then it has a serial number and no ML_ID indigo.server.log("\tNetworkLink ID of product " + node.name + " is " + diff --git a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLGW_CLIENT.py b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLGW_CLIENT.py index 5e83bd4..ed12065 100644 --- a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLGW_CLIENT.py +++ b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLGW_CLIENT.py @@ -1,4 +1,7 @@ -import indigo +try: + import indigo +except ImportError: + pass import asynchat import socket import time @@ -20,15 +23,15 @@ class MLGWClient(asynchat.async_chat): self._host = host_address self._port = int(port) - self._user = user - self._pwd = pwd + self._user = user.encode('UTF8') + self._pwd = pwd.encode('UTF8') self.name = name self.is_connected = False self._received_data = bytearray() - self.last_sent = '' + self.last_sent = bytearray() self.last_sent_at = time.time() - self.last_received = '' + self.last_received = bytearray() self.last_received_at = time.time() self.last_message = {} @@ -72,11 +75,11 @@ class MLGWClient(asynchat.async_chat): self._received_data = "" def found_terminator(self, msg_type, payload): - self.last_received = str(list(self._received_data)) + self.last_received = self._received_data self.last_received_at = time.time() header = self._received_data[0:4] - self._received_data = "" + self._received_data = bytearray() self._decode(msg_type, header, payload) def _decode(self, msg_type, header, payload): @@ -184,6 +187,8 @@ class MLGWClient(asynchat.async_chat): self._report(header, payload, message) def client_connect(self): + indigo.debugger() + indigo.server.log('Connecting to host at ' + self._host + ', port ' + str(self._port), level=logging.WARNING) self.set_terminator(b'\r\n') # Create the socket @@ -209,7 +214,7 @@ class MLGWClient(asynchat.async_chat): indigo.server.log("\tConnected to B&O Gateway", level=logging.DEBUG) def handle_connect(self): - login = [] + login = bytearray() for c in self._user: login.append(c) login.append(0x00) @@ -217,6 +222,7 @@ class MLGWClient(asynchat.async_chat): login.append(c) indigo.server.log("\tAttempting to Authenticate...", level=logging.WARNING) + indigo.server.log("\tLogin: " + str(login), level=logging.DEBUG) self._send_cmd(CONST.MLGW_PL.get("LOGIN REQUEST"), login) def handle_close(self): @@ -235,21 +241,19 @@ class MLGWClient(asynchat.async_chat): # send_cmd command to mlgw def _send_cmd(self, msg_type, payload): # Construct header - telegram = [1, msg_type, len(payload), 0] + telegram = bytearray() + telegram.append(1) + telegram.append(msg_type) + telegram.append(len(payload)) + telegram.append(0) + indigo.debugger() + # append payload for p in payload: telegram.append(p) - # Convert telegram to byte string - # b_telegram = b'' - # for t in telegram: - # if type(t) == int: - # b_telegram += (t).to_bytes(1, byteorder='little') - # else: - # b_telegram += bytes(t, 'ascii') - try: - self.push(str(bytearray(telegram))) + self.push(telegram) except socket.timeout as e: indigo.server.log("\tSocket connection to timed out: " + str(e), level=logging.ERROR) self.handle_close() diff --git a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLtn_CLIENT.py b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLtn_CLIENT.py index 6a873b7..ea021b2 100644 --- a/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLtn_CLIENT.py +++ b/BeoGateway.indigoPlugin/Contents/Server Plugin/Resources/MLtn_CLIENT.py @@ -1,4 +1,7 @@ -import indigo +try: + import indigo +except ImportError: + pass import asynchat import socket import time @@ -47,7 +50,7 @@ class MLtnClient(asynchat.async_chat): # ######################################################################################## # ##### Client functions def collect_incoming_data(self, data): - self._received_data += data + self._received_data += str(data) def found_terminator(self): self.last_received = self._received_data @@ -300,17 +303,24 @@ class MLtnClient(asynchat.async_chat): def handle_connect(self): indigo.server.log("\tAttempting to Authenticate...", level=logging.WARNING) - self._send_cmd(self._pwd) - self._send_cmd("MONITOR") + self.send_cmd(self._pwd) + self.send_cmd("MONITOR") def handle_close(self): indigo.server.log(self.name + ": Closing socket", level=logging.ERROR) self.is_connected = False self.close() - def _send_cmd(self, telegram): + def send_cmd(self, payload): + payload = payload + "\r\n" + payload = payload.encode('UTF8') + telegram = bytearray() + # append payload + for p in payload: + telegram.append(p) + try: - self.push(str(telegram + "\r\n")) + self.push(telegram) except socket.timeout as e: indigo.server.log("\tSocket connection timed out: " + str(e), level=logging.ERROR) self.handle_close() @@ -320,7 +330,7 @@ class MLtnClient(asynchat.async_chat): else: self.last_sent = telegram self.last_sent_at = time.time() - indigo.server.log(self.name + " >>-SENT--> : " + telegram, level=logging.INFO) + indigo.server.log(self.name + " >>-SENT--> : " + payload.decode('UTF8'), level=logging.INFO) time.sleep(0.2) def toggle_events(self): @@ -345,7 +355,7 @@ class MLtnClient(asynchat.async_chat): self.handle_close() def ping(self): - self._send_cmd('') + self.send_cmd('') # ######################################################################################## # ##### Utility functions