mirror of
https://github.com/LukeSpad/BeoGateway.git
synced 2024-12-23 21:51:51 +00:00
Delete MLtn_CLIENT.py
This commit is contained in:
parent
88f9e14a22
commit
30abe19219
1 changed files with 0 additions and 371 deletions
|
@ -1,371 +0,0 @@
|
||||||
import asynchat
|
|
||||||
import logging
|
|
||||||
import socket
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
import Resources.CONSTANTS as CONST
|
|
||||||
|
|
||||||
|
|
||||||
class MLtnClient(asynchat.async_chat):
|
|
||||||
"""Client to monitor network activity on a Masterlink Gateway via the telnet monitor"""
|
|
||||||
def __init__(self, host_address='mlgw.local', port=23, user='admin', pwd='admin', name='MLGW_HIP', cb=None):
|
|
||||||
asynchat.async_chat.__init__(self)
|
|
||||||
self.log = logging.getLogger('Client (%7s)' % name)
|
|
||||||
self.log.setLevel('INFO')
|
|
||||||
|
|
||||||
self._host = host_address
|
|
||||||
self._port = int(port)
|
|
||||||
self._user = user
|
|
||||||
self._pwd = pwd
|
|
||||||
self.name = name
|
|
||||||
self.is_connected = False
|
|
||||||
|
|
||||||
self._i = 0
|
|
||||||
self._header_lines = 4
|
|
||||||
self._received_data = ''
|
|
||||||
self.last_sent = ''
|
|
||||||
self.last_sent_at = time.time()
|
|
||||||
self.last_received = ''
|
|
||||||
self.last_received_at = time.time()
|
|
||||||
self.last_message = {}
|
|
||||||
|
|
||||||
self.isBLGW = False
|
|
||||||
|
|
||||||
# Optional callback function
|
|
||||||
if cb:
|
|
||||||
self.messageCallBack = cb
|
|
||||||
else:
|
|
||||||
self.messageCallBack = None
|
|
||||||
|
|
||||||
# ########################################################################################
|
|
||||||
# ##### Open Socket and connect to B&O Gateway
|
|
||||||
self.client_connect()
|
|
||||||
|
|
||||||
# ########################################################################################
|
|
||||||
# ##### Client functions
|
|
||||||
def collect_incoming_data(self, data):
|
|
||||||
self.log.debug(data)
|
|
||||||
self._received_data += data
|
|
||||||
|
|
||||||
def found_terminator(self):
|
|
||||||
self.last_received = self._received_data
|
|
||||||
self.last_received_at = time.time()
|
|
||||||
self.log.debug(self._received_data)
|
|
||||||
|
|
||||||
items = self._received_data.split(' ')
|
|
||||||
|
|
||||||
if self._i <= self._header_lines:
|
|
||||||
self._i += 1
|
|
||||||
if self._received_data[0:4] != "MLGW":
|
|
||||||
self.isBLGW = True
|
|
||||||
if self._i == self._header_lines - 1:
|
|
||||||
self.log.info("\t" + self._received_data)
|
|
||||||
if self._received_data == 'incorrect password':
|
|
||||||
self.handle_close()
|
|
||||||
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
self._decode(items)
|
|
||||||
except IndexError:
|
|
||||||
self.log.debug(str(list(items)))
|
|
||||||
|
|
||||||
self._received_data = ""
|
|
||||||
|
|
||||||
def _decode(self, items):
|
|
||||||
header = items[3][:-1]
|
|
||||||
telegram_starts = len(''.join(items[:4])) + 4
|
|
||||||
telegram = self._received_data[telegram_starts:].replace('!', '').split('/')
|
|
||||||
message = OrderedDict()
|
|
||||||
|
|
||||||
if telegram[0] == 'Monitor events ( keys: M, E, C, (spc), Q ) ----':
|
|
||||||
self.toggle_commands()
|
|
||||||
self.toggle_macros()
|
|
||||||
|
|
||||||
if header == 'integration_protocol':
|
|
||||||
message = self._decode_ip(telegram, message)
|
|
||||||
|
|
||||||
if header == 'resource_found':
|
|
||||||
message['State_Update'] = telegram[0]
|
|
||||||
|
|
||||||
if header == 'action_executed':
|
|
||||||
message = self._decode_action(telegram, message)
|
|
||||||
|
|
||||||
if header == 'command_executed':
|
|
||||||
message = self._decode_command(telegram, message)
|
|
||||||
|
|
||||||
if header == 'macro_fired':
|
|
||||||
message['Zone'] = telegram[0].upper()
|
|
||||||
message['Room'] = telegram[1].upper()
|
|
||||||
message['Macro_Name'] = telegram[3]
|
|
||||||
|
|
||||||
if header == 'trigger_fired':
|
|
||||||
message = self._decode_trigger(telegram, message)
|
|
||||||
|
|
||||||
self._report(header, telegram, message)
|
|
||||||
|
|
||||||
def _decode_ip(self, telegram, message):
|
|
||||||
if ''.join(telegram).split(':')[0] == 'Integration Protocol login':
|
|
||||||
chars = ''.join(telegram).split(':')[1][2:].split(' ')
|
|
||||||
message['Payload'] = ''
|
|
||||||
for c in chars:
|
|
||||||
if c == '0x0':
|
|
||||||
message['Payload'] += '0'
|
|
||||||
else:
|
|
||||||
message['Payload'] += chr(int(c, base=16))
|
|
||||||
|
|
||||||
if ''.join(telegram).split(':')[0] == 'Integration Protocol':
|
|
||||||
if ''.join(telegram).split(':')[1] == ' processed serial number request':
|
|
||||||
message['Payload'] = 'processed serial number request'
|
|
||||||
else:
|
|
||||||
s = ''.join(telegram).split(' ')
|
|
||||||
message['Type'] = 'Send Beo4 Command'
|
|
||||||
message[s[5]] = s[6]
|
|
||||||
message['Payload'] = OrderedDict()
|
|
||||||
for k in range(10, len(s)):
|
|
||||||
if k == 10:
|
|
||||||
message['Payload']['to_MLN'] = int(s[k], base=16)
|
|
||||||
if k == 11:
|
|
||||||
message['Payload']['Destination'] = self._dictsanitize(
|
|
||||||
CONST.destselectordict, int(s[k], base=16))
|
|
||||||
if k == 12:
|
|
||||||
message['Payload']['Command'] = self._dictsanitize(
|
|
||||||
CONST.beo4_commanddict, int(s[k], base=16)).upper()
|
|
||||||
if k == 13:
|
|
||||||
message['Payload']['Sec-Source'] = self._dictsanitize(
|
|
||||||
CONST.mlgw_secsourcedict, int(s[k], base=16))
|
|
||||||
if k == 14:
|
|
||||||
message['Payload']['Link'] = self._dictsanitize(
|
|
||||||
CONST.mlgw_linkdict, int(s[k], base=16))
|
|
||||||
if k > 14:
|
|
||||||
message['Payload']['cmd' + str(k - 9)] = self._dictsanitize(
|
|
||||||
CONST.beo4_commanddict, int(s[k], base=16))
|
|
||||||
return message
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _decode_action(telegram, message):
|
|
||||||
message['Zone'] = telegram[0].upper()
|
|
||||||
message['Room'] = telegram[1].upper()
|
|
||||||
message['Type'] = telegram[2].upper()
|
|
||||||
message['Device'] = telegram[3]
|
|
||||||
message['State_Update'] = OrderedDict()
|
|
||||||
if message.get('Type') == 'BUTTON':
|
|
||||||
if telegram[4].split('=')[0] == '_SET STATE?STATE':
|
|
||||||
message['State_Update']['STATE'] = telegram[4].split('=')[1]
|
|
||||||
if message['State_Update'].get('STATE') == '0':
|
|
||||||
message['State_Update']['Status'] = "Off"
|
|
||||||
else:
|
|
||||||
message['State_Update']['Status'] = "On"
|
|
||||||
else:
|
|
||||||
message['State_Update']['STATE'] = telegram[4]
|
|
||||||
|
|
||||||
if message.get('Type') == 'DIMMER': # e.g. DownstairsHallwayDIMMERWall LightSTATE_UPDATE?LEVEL=5
|
|
||||||
if telegram[4].split('=')[0] == '_SET STATE?LEVEL':
|
|
||||||
message['State_Update']['LEVEL'] = telegram[4].split('=')[1]
|
|
||||||
if message['State_Update'].get('LEVEL') == '0':
|
|
||||||
message['State_Update']['Status'] = "Off"
|
|
||||||
else:
|
|
||||||
message['State_Update']['Status'] = "On"
|
|
||||||
else:
|
|
||||||
message['State_Update']['STATE'] = telegram[4]
|
|
||||||
return message
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _decode_command(telegram, message):
|
|
||||||
message['Zone'] = telegram[0].upper()
|
|
||||||
message['Room'] = telegram[1].upper()
|
|
||||||
message['Type'] = telegram[2].upper()
|
|
||||||
message['Device'] = telegram[3]
|
|
||||||
message['State_Update'] = OrderedDict()
|
|
||||||
if message.get('Type') == 'BUTTON':
|
|
||||||
if telegram[4].split('=')[0] == '_SET STATE?STATE':
|
|
||||||
message['State_Update']['STATE'] = telegram[4].split('=')[1]
|
|
||||||
if message['State_Update'].get('STATE') == '0':
|
|
||||||
message['State_Update']['Status'] = "Off"
|
|
||||||
else:
|
|
||||||
message['State_Update']['Status'] = "On"
|
|
||||||
else:
|
|
||||||
message['State_Update']['STATE'] = telegram[4]
|
|
||||||
|
|
||||||
if message.get('Type') == 'DIMMER':
|
|
||||||
if telegram[4].split('=')[0] == '_SET STATE?LEVEL':
|
|
||||||
message['State_Update']['LEVEL'] = telegram[4].split('=')[1]
|
|
||||||
if message['State_Update'].get('LEVEL') == '0':
|
|
||||||
message['State_Update']['Status'] = "Off"
|
|
||||||
else:
|
|
||||||
message['State_Update']['Status'] = "On"
|
|
||||||
else:
|
|
||||||
message['State_Update']['STATE'] = telegram[4]
|
|
||||||
return message
|
|
||||||
|
|
||||||
def _decode_trigger(self, telegram, message):
|
|
||||||
message['Zone'] = telegram[0].upper()
|
|
||||||
message['Room'] = telegram[1].upper()
|
|
||||||
message['Type'] = telegram[2].upper()
|
|
||||||
message['Device'] = telegram[3]
|
|
||||||
message['State_Update'] = OrderedDict()
|
|
||||||
|
|
||||||
if message.get('Type') == 'BUTTON':
|
|
||||||
if telegram[4].split('=')[0] == 'STATE_UPDATE?STATE':
|
|
||||||
message['State_Update']['STATE'] = telegram[4].split('=')[1]
|
|
||||||
if message['State_Update'].get('STATE') == '0':
|
|
||||||
message['State_Update']['Status'] = "Off"
|
|
||||||
else:
|
|
||||||
message['State_Update']['Status'] = "On"
|
|
||||||
else:
|
|
||||||
message['State_Update']['STATE'] = telegram[4]
|
|
||||||
|
|
||||||
if message.get('Type') == 'DIMMER':
|
|
||||||
if telegram[4].split('=')[0] == 'STATE_UPDATE?LEVEL':
|
|
||||||
message['State_Update']['LEVEL'] = telegram[4].split('=')[1]
|
|
||||||
if message['State_Update'].get('LEVEL') == '0':
|
|
||||||
message['State_Update']['Status'] = "Off"
|
|
||||||
else:
|
|
||||||
message['State_Update']['Status'] = "On"
|
|
||||||
else:
|
|
||||||
message['State_Update']['STATE'] = telegram[4]
|
|
||||||
|
|
||||||
if message.get('Type') == 'AV RENDERER':
|
|
||||||
if telegram[4][:5] == 'Light':
|
|
||||||
state = telegram[4][6:].split('&')
|
|
||||||
message['State_Update']['type'] = 'Light Command'
|
|
||||||
for s in state:
|
|
||||||
message['State_Update'][s.split('=')[0].lower()] = s.split('=')[1].title()
|
|
||||||
if message['State_Update'].get('command') == ' Cmd':
|
|
||||||
message['State_Update']['command'] = self._dictsanitize(CONST.beo4_commanddict,
|
|
||||||
int(s[13:].strip())).title()
|
|
||||||
elif telegram[4][:7] == 'Control':
|
|
||||||
state = telegram[4][6:].split('&')
|
|
||||||
message['State_Update']['type'] = 'Control Command'
|
|
||||||
for s in state:
|
|
||||||
message['State_Update'][s.split('=')[0].lower()] = s.split('=')[1]
|
|
||||||
if message['State_Update'].get('command') == ' cmd':
|
|
||||||
message['State_Update']['command'] = self._dictsanitize(CONST.beo4_commanddict,
|
|
||||||
int(s[13:].strip())).title()
|
|
||||||
elif telegram[4] == 'All standby':
|
|
||||||
message['State_Update']['command'] = telegram[4]
|
|
||||||
|
|
||||||
else:
|
|
||||||
state = telegram[4][13:].split('&')
|
|
||||||
for s in state:
|
|
||||||
if s.split('=')[0] == 'sourceUniqueId':
|
|
||||||
src = s.split('=')[1].split(':')[0].upper()
|
|
||||||
message['State_Update']['source'] = self._srcdictsanitize(CONST.blgw_srcdict, src)
|
|
||||||
message['State_Update'][s.split('=')[0]] = s.split('=')[1]
|
|
||||||
elif s.split('=')[0] == 'nowPlayingDetails':
|
|
||||||
message['State_Update']['nowPlayingDetails'] = OrderedDict()
|
|
||||||
details = s.split('=')[1].split(';')
|
|
||||||
if len(details) > 1:
|
|
||||||
for d in details:
|
|
||||||
if d.split(':')[0].strip() in ['track number', 'channel number']:
|
|
||||||
message['State_Update']['nowPlayingDetails']['channel_track'] \
|
|
||||||
= d.split(':')[1].strip()
|
|
||||||
else:
|
|
||||||
message['State_Update']['nowPlayingDetails'][d.split(':')[0].strip()] \
|
|
||||||
= d.split(':')[1].strip()
|
|
||||||
else:
|
|
||||||
message['State_Update'][s.split('=')[0]] = s.split('=')[1]
|
|
||||||
return message
|
|
||||||
|
|
||||||
def _report(self, header, telegram, message):
|
|
||||||
self.last_message = message
|
|
||||||
self.log.debug(self.name + "\n" + str(json.dumps(message, indent=4)))
|
|
||||||
if self.messageCallBack:
|
|
||||||
self.messageCallBack(self.name, ''.join(header).upper(), ''.join(telegram), message)
|
|
||||||
|
|
||||||
def client_connect(self):
|
|
||||||
self.log.info('Connecting to host at %s, port %i', self._host, self._port)
|
|
||||||
self.set_terminator(b'\r\n')
|
|
||||||
# Create the socket
|
|
||||||
try:
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error creating socket: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
# Now connect
|
|
||||||
try:
|
|
||||||
self.connect((self._host, self._port))
|
|
||||||
except socket.gaierror, e:
|
|
||||||
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
|
||||||
self.handle_close()
|
|
||||||
except socket.timeout, e:
|
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
|
||||||
self.handle_close()
|
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("\tError opening connection to %s:%i - %s" % (self._host, self._port, e))
|
|
||||||
self.handle_close()
|
|
||||||
else:
|
|
||||||
self.is_connected = True
|
|
||||||
self.log.info("\tConnected to B&O Gateway")
|
|
||||||
|
|
||||||
def handle_connect(self):
|
|
||||||
self.log.info("\tAttempting to Authenticate...")
|
|
||||||
self._send_cmd(self._pwd)
|
|
||||||
self._send_cmd("MONITOR")
|
|
||||||
|
|
||||||
def handle_close(self):
|
|
||||||
self.log.info(self.name + ": Closing socket")
|
|
||||||
self.is_connected = False
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def _send_cmd(self, telegram):
|
|
||||||
try:
|
|
||||||
self.push(telegram + "\r\n")
|
|
||||||
except socket.timeout, e:
|
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
|
||||||
self.handle_close()
|
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error sending data: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
else:
|
|
||||||
self.last_sent = telegram
|
|
||||||
self.last_sent_at = time.time()
|
|
||||||
self.log.info(self.name + " >>-SENT--> : " + telegram)
|
|
||||||
time.sleep(0.2)
|
|
||||||
|
|
||||||
def toggle_events(self):
|
|
||||||
try:
|
|
||||||
self.push('e')
|
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error sending data: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
|
|
||||||
def toggle_macros(self):
|
|
||||||
try:
|
|
||||||
self.push('m')
|
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error sending data: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
|
|
||||||
def toggle_commands(self):
|
|
||||||
try:
|
|
||||||
self.push('c')
|
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error sending data: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
|
|
||||||
def ping(self):
|
|
||||||
self._send_cmd('')
|
|
||||||
|
|
||||||
# ########################################################################################
|
|
||||||
# ##### Utility functions
|
|
||||||
@staticmethod
|
|
||||||
def _hexbyte(byte):
|
|
||||||
resultstr = hex(byte)
|
|
||||||
if byte < 16:
|
|
||||||
resultstr = resultstr[:2] + "0" + resultstr[2]
|
|
||||||
return resultstr
|
|
||||||
|
|
||||||
def _dictsanitize(self, d, s):
|
|
||||||
result = d.get(s)
|
|
||||||
if result is None:
|
|
||||||
result = "UNKNOWN (type=" + self._hexbyte(s) + ")"
|
|
||||||
return str(result)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _srcdictsanitize(d, s):
|
|
||||||
result = d.get(s)
|
|
||||||
if result is None:
|
|
||||||
result = s
|
|
||||||
return str(result)
|
|
Loading…
Reference in a new issue