mirror of
https://github.com/LukeSpad/BeoGateway.git
synced 2024-12-23 21:51:51 +00:00
Add files via upload
This commit is contained in:
parent
82af7d348c
commit
338287f477
7 changed files with 490 additions and 355 deletions
|
@ -6,7 +6,8 @@ import json
|
||||||
import urllib
|
import urllib
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import Resources.CONSTANTS as const
|
import Resources.CONSTANTS as CONST
|
||||||
|
|
||||||
|
|
||||||
class BLHIPClient(asynchat.async_chat):
|
class BLHIPClient(asynchat.async_chat):
|
||||||
"""Client to interact with a Beolink Gateway via the Home Integration Protocol
|
"""Client to interact with a Beolink Gateway via the Home Integration Protocol
|
||||||
|
@ -99,11 +100,11 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
|
|
||||||
for s in state:
|
for s in state:
|
||||||
if s.split('=')[0] == "nowPlayingDetails":
|
if s.split('=')[0] == "nowPlayingDetails":
|
||||||
playDetails = s.split('=')
|
play_details = s.split('=')
|
||||||
if len(playDetails[1]) >0:
|
if len(play_details[1]) > 0:
|
||||||
playDetails = playDetails[1].split('; ')
|
play_details = play_details[1].split('; ')
|
||||||
message['State_Update']["nowPlayingDetails"] = OrderedDict()
|
message['State_Update']["nowPlayingDetails"] = OrderedDict()
|
||||||
for p in playDetails:
|
for p in play_details:
|
||||||
if p.split(': ')[0] in ['track number', 'channel number']:
|
if p.split(': ')[0] in ['track number', 'channel number']:
|
||||||
message['State_Update']["nowPlayingDetails"]['channel_track'] = p.split(': ')[1]
|
message['State_Update']["nowPlayingDetails"]['channel_track'] = p.split(': ')[1]
|
||||||
else:
|
else:
|
||||||
|
@ -111,11 +112,16 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
|
|
||||||
elif s.split('=')[0] == "sourceUniqueId":
|
elif s.split('=')[0] == "sourceUniqueId":
|
||||||
src = s.split('=')[1].split(':')[0].upper()
|
src = s.split('=')[1].split(':')[0].upper()
|
||||||
message['State_Update']['source'] = self._srcdictsanitize(const._blgw_srcdict, src)
|
message['State_Update']['source'] = self._srcdictsanitize(CONST.blgw_srcdict, src)
|
||||||
message['State_Update'][s.split('=')[0]] = s.split('=')[1]
|
message['State_Update'][s.split('=')[0]] = s.split('=')[1]
|
||||||
else:
|
else:
|
||||||
message['State_Update'][s.split('=')[0]] = s.split('=')[1]
|
message['State_Update'][s.split('=')[0]] = s.split('=')[1]
|
||||||
|
|
||||||
|
# call function to find channel details if type = Legacy
|
||||||
|
if 'nowPlayingDetails' in message['State_Update'] \
|
||||||
|
and message['State_Update']['nowPlayingDetails']['type'] == 'Legacy':
|
||||||
|
self._get_channel_track(message)
|
||||||
|
|
||||||
if message.get('Type') == 'BUTTON':
|
if message.get('Type') == 'BUTTON':
|
||||||
if message['State_Update'].get('STATE') == '0':
|
if message['State_Update'].get('STATE') == '0':
|
||||||
message['State_Update']['Status'] = 'Off'
|
message['State_Update']['Status'] = 'Off'
|
||||||
|
@ -143,7 +149,6 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
self.set_terminator(b'\r\n')
|
self.set_terminator(b'\r\n')
|
||||||
# Create the socket
|
# Create the socket
|
||||||
try:
|
try:
|
||||||
socket.setdefaulttimeout(3)
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
self.log.info("Error creating socket: %s" % e)
|
self.log.info("Error creating socket: %s" % e)
|
||||||
|
@ -154,12 +159,12 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
except socket.gaierror, e:
|
except socket.gaierror, e:
|
||||||
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
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()
|
|
||||||
except socket.timeout, e:
|
except socket.timeout, e:
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
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:
|
else:
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
self.log.info("\tConnected to B&O Gateway")
|
self.log.info("\tConnected to B&O Gateway")
|
||||||
|
@ -178,12 +183,12 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
def send_cmd(self, telegram):
|
def send_cmd(self, telegram):
|
||||||
try:
|
try:
|
||||||
self.push(telegram.encode("ascii") + "\r\n")
|
self.push(telegram.encode("ascii") + "\r\n")
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error sending data: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
except socket.timeout, e:
|
except socket.timeout, e:
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
self.handle_close()
|
||||||
|
except socket.error, e:
|
||||||
|
self.log.info("Error sending data: %s" % e)
|
||||||
|
self.handle_close()
|
||||||
else:
|
else:
|
||||||
self.last_sent = telegram
|
self.last_sent = telegram
|
||||||
self.last_sent_at = time.time()
|
self.last_sent_at = time.time()
|
||||||
|
@ -226,9 +231,22 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
def ping(self):
|
def ping(self):
|
||||||
self.query('Main', 'global', 'SYSTEM', 'BeoLink')
|
self.query('Main', 'global', 'SYSTEM', 'BeoLink')
|
||||||
|
|
||||||
def _srcdictsanitize(self, d, s):
|
# Utility Functions
|
||||||
|
@staticmethod
|
||||||
|
def _srcdictsanitize(d, s):
|
||||||
result = d.get(s)
|
result = d.get(s)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = s
|
result = s
|
||||||
return str(result)
|
return str(result)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_channel_track(message):
|
||||||
|
# Check device list for channel name information
|
||||||
|
if CONST.devices:
|
||||||
|
for device in CONST.devices:
|
||||||
|
if device['Device'] == message['Device']:
|
||||||
|
if 'channels' in device['Sources'][message["State_Update"]["source"]]:
|
||||||
|
for channel in device['Sources'][message["State_Update"]["source"]]['channels']:
|
||||||
|
if channel['number'] == int(message["State_Update"]['nowPlayingDetails']["channel_track"]):
|
||||||
|
message["State_Update"]["nowPlaying"] = channel['name']
|
||||||
|
break
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
# Constants for B&O telegram protocols
|
# Constants for B&O telegram protocols
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
### Config data (set on initialisation)
|
# Config data (set on initialisation)
|
||||||
gateway = dict()
|
gateway = dict()
|
||||||
rooms = []
|
rooms = []
|
||||||
devices = []
|
devices = []
|
||||||
available_sources = []
|
available_sources = []
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
### Beo4 Commands
|
# Beo4 Commands
|
||||||
beo4_commanddict = dict(
|
beo4_commanddict = dict(
|
||||||
[
|
[
|
||||||
# Source selection:
|
# Source selection:
|
||||||
|
@ -124,7 +124,7 @@ beo4_commanddict = dict(
|
||||||
)
|
)
|
||||||
BEO4_CMDS = {v.upper(): k for k, v in beo4_commanddict.items()}
|
BEO4_CMDS = {v.upper(): k for k, v in beo4_commanddict.items()}
|
||||||
|
|
||||||
### BeoRemote One Commands
|
# BeoRemote One Commands
|
||||||
beoremoteone_commanddict = dict(
|
beoremoteone_commanddict = dict(
|
||||||
[
|
[
|
||||||
# Source, (Cmd, Unit)
|
# Source, (Cmd, Unit)
|
||||||
|
@ -195,7 +195,7 @@ beoremoteone_commanddict = dict(
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# Source Activity
|
# Source Activity
|
||||||
_sourceactivitydict = dict(
|
sourceactivitydict = dict(
|
||||||
[
|
[
|
||||||
(0x00, "Unknown"),
|
(0x00, "Unknown"),
|
||||||
(0x01, "Stop"),
|
(0x01, "Stop"),
|
||||||
|
@ -214,7 +214,7 @@ _sourceactivitydict = dict(
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### MasterLink (not MLGW) Protocol packet constants
|
# ##### MasterLink (not MLGW) Protocol packet constants
|
||||||
_ml_telegram_type_dict = dict(
|
ml_telegram_type_dict = dict(
|
||||||
[
|
[
|
||||||
(0x0A, "COMMAND"),
|
(0x0A, "COMMAND"),
|
||||||
(0x0B, "REQUEST"),
|
(0x0B, "REQUEST"),
|
||||||
|
@ -224,7 +224,7 @@ _ml_telegram_type_dict = dict(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
_ml_command_type_dict = dict(
|
ml_command_type_dict = dict(
|
||||||
[
|
[
|
||||||
(0x04, "MASTER_PRESENT"),
|
(0x04, "MASTER_PRESENT"),
|
||||||
# REQUEST_DISTRIBUTED_SOURCE: seen when a device asks what source is being distributed
|
# REQUEST_DISTRIBUTED_SOURCE: seen when a device asks what source is being distributed
|
||||||
|
@ -242,7 +242,7 @@ _ml_command_type_dict = dict(
|
||||||
(0x3C, "TIMER"),
|
(0x3C, "TIMER"),
|
||||||
(0x40, "CLOCK"),
|
(0x40, "CLOCK"),
|
||||||
(0x44, "TRACK_INFO"),
|
(0x44, "TRACK_INFO"),
|
||||||
# LOCK_MANAGER_COMMAND: Lock to Determine what device issues source commands
|
# LOCKmANAGER_COMMAND: Lock to Determine what device issues source commands
|
||||||
# reference: https://tidsskrift.dk/daimipb/article/download/7043/6004/0
|
# reference: https://tidsskrift.dk/daimipb/article/download/7043/6004/0
|
||||||
(0x45, "GOTO_SOURCE"),
|
(0x45, "GOTO_SOURCE"),
|
||||||
(0x5C, "LOCK_MANAGER_COMMAND"),
|
(0x5C, "LOCK_MANAGER_COMMAND"),
|
||||||
|
@ -280,13 +280,13 @@ _ml_command_type_dict = dict(
|
||||||
#########################################################
|
#########################################################
|
||||||
# On power up all devices send out a request key telegram. If
|
# 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
|
# 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_LOCK_MANAGER telegram and assumes responsibility
|
# Master in older implementations) then asserts a NEW_LOCKmANAGER telegram and assumes responsibility
|
||||||
# for LOCK_MANAGER_COMMAND telegrams until a key transfer occurs.
|
# for LOCKmANAGER_COMMAND telegrams until a key transfer occurs.
|
||||||
(0x12, "KEY_LOST"), # ?
|
(0x12, "KEY_LOST"), # ?
|
||||||
# Unknown command with payload of length 1.
|
# Unknown command with payload of length 1.
|
||||||
# bit 0: unknown
|
# bit 0: unknown
|
||||||
# bit 1: unknown
|
# bit 1: unknown
|
||||||
(0xA0, "NEW_LOCK_MANAGER"), #?
|
(0xA0, "NEW_LOCKMANAGER"), # ?
|
||||||
# Unknown command with payload of length 2
|
# Unknown command with payload of length 2
|
||||||
# bit 0: unknown
|
# bit 0: unknown
|
||||||
# bit 1: unknown
|
# bit 1: unknown
|
||||||
|
@ -294,7 +294,7 @@ _ml_command_type_dict = dict(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
_ml_command_type_request_key_subtype_dict = dict(
|
ml_command_type_request_key_subtype_dict = dict(
|
||||||
[
|
[
|
||||||
(0x01, "Request Key"),
|
(0x01, "Request Key"),
|
||||||
(0x02, "Transfer Key"),
|
(0x02, "Transfer Key"),
|
||||||
|
@ -305,7 +305,7 @@ _ml_command_type_request_key_subtype_dict = dict(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
_ml_activity_dict = dict(
|
ml_activity_dict = dict(
|
||||||
[
|
[
|
||||||
(0x01, "Request Source"),
|
(0x01, "Request Source"),
|
||||||
(0x02, "Request Source"),
|
(0x02, "Request Source"),
|
||||||
|
@ -314,24 +314,24 @@ _ml_activity_dict = dict(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
_ml_device_dict = dict(
|
ml_device_dict = dict(
|
||||||
[
|
[
|
||||||
(0xC0, "VIDEO_MASTER"),
|
(0xC0, "VIDEO MASTER"),
|
||||||
(0xC1, "AUDIO_MASTER"),
|
(0xC1, "AUDIO MASTER"),
|
||||||
(0xC2, "SOURCE_CENTER"),
|
(0xC2, "SOURCE CENTER/SLAVE DEVICE"),
|
||||||
(0x81, "ALL_AUDIO_LINK_DEVICES"),
|
(0x81, "ALL AUDIO LINK DEVICES"),
|
||||||
(0x82, "ALL_VIDEO_LINK_DEVICES"),
|
(0x82, "ALL VIDEO LINK DEVICES"),
|
||||||
(0x83, "ALL_LINK_DEVICES"),
|
(0x83, "ALL LINK DEVICES"),
|
||||||
(0x80, "ALL"),
|
(0x80, "ALL"),
|
||||||
(0xF0, "MLGW"),
|
(0xF0, "MLGW"),
|
||||||
# Power Master exists in older (pre 1996?) ML implementations. Later revisions enforced the Video Master
|
# Power Master exists in older (pre 1996?) ML implementations. Later revisions enforced the Video Master
|
||||||
# as lock key manager for the system and the concept was phased out. If your system is older than 2000
|
# as lock key manager for the system and the concept was phased out. If your system is older than 2000
|
||||||
# you may see this device type on the network.
|
# you may see this device type on the network.
|
||||||
(0xFF, "POWER_MASTER"), #?
|
(0xFF, "POWER MASTER"), # ?
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
_ml_pictureformatdict = dict(
|
ml_pictureformatdict = dict(
|
||||||
[
|
[
|
||||||
(0x00, "Not known"),
|
(0x00, "Not known"),
|
||||||
(0x01, "Known by decoder"),
|
(0x01, "Known by decoder"),
|
||||||
|
@ -344,7 +344,7 @@ _ml_pictureformatdict = dict(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
_ml_selectedsourcedict = dict(
|
ml_selectedsourcedict = dict(
|
||||||
[
|
[
|
||||||
(0x00, "NONE"),
|
(0x00, "NONE"),
|
||||||
(0x0B, "TV"),
|
(0x0B, "TV"),
|
||||||
|
@ -367,9 +367,9 @@ _ml_selectedsourcedict = dict(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
_ml_trackinfo_subtype_dict = dict([(0x05, "Current Source"),(0x07, "Change Source"),])
|
ml_trackinfo_subtype_dict = dict([(0x05, "Current Source"), (0x07, "Change Source"), ])
|
||||||
|
|
||||||
_ml_selectedsource_type_dict = dict(
|
ml_selectedsource_type_dict = dict(
|
||||||
[
|
[
|
||||||
("VIDEO", (0x0B, 0x1F)),
|
("VIDEO", (0x0B, 0x1F)),
|
||||||
("VIDEO_PAUSABLE", (0x15, 0x16, 0x29, 0x33)),
|
("VIDEO_PAUSABLE", (0x15, 0x16, 0x29, 0x33)),
|
||||||
|
@ -382,7 +382,7 @@ _ml_selectedsource_type_dict = dict(
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### MLGW Protocol packet constants
|
# ##### MLGW Protocol packet constants
|
||||||
_mlgw_payloadtypedict = dict(
|
mlgw_payloadtypedict = dict(
|
||||||
[
|
[
|
||||||
(0x01, "Beo4 Command"),
|
(0x01, "Beo4 Command"),
|
||||||
(0x02, "Source Status"),
|
(0x02, "Source Status"),
|
||||||
|
@ -405,9 +405,9 @@ _mlgw_payloadtypedict = dict(
|
||||||
(0x40, "Location based event"),
|
(0x40, "Location based event"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
MLGW_PL = {v.upper(): k for k, v in _mlgw_payloadtypedict.items()}
|
MLGW_PL = {v.upper(): k for k, v in mlgw_payloadtypedict.items()}
|
||||||
|
|
||||||
_destselectordict = dict(
|
destselectordict = dict(
|
||||||
[
|
[
|
||||||
(0x00, "Video Source"),
|
(0x00, "Video Source"),
|
||||||
(0x01, "Audio Source"),
|
(0x01, "Audio Source"),
|
||||||
|
@ -416,17 +416,17 @@ _destselectordict = dict(
|
||||||
(0x1B, "MLGW"),
|
(0x1B, "MLGW"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
CMDS_DEST = {v.upper(): k for k, v in _destselectordict.items()}
|
CMDS_DEST = {v.upper(): k for k, v in destselectordict.items()}
|
||||||
|
|
||||||
_mlgw_secsourcedict = dict([(0x00, "V.TAPE/V.MEM"),(0x01, "V.TAPE2/DVD2/V.MEM2"),])
|
mlgw_secsourcedict = dict([(0x00, "V.TAPE/V.MEM"), (0x01, "V.TAPE2/DVD2/V.MEM2")])
|
||||||
_mlgw_linkdict = dict([(0x00, "Local/Default Source"),(0x01, "Remote Source/Option 4 Product"),])
|
mlgw_linkdict = dict([(0x00, "Local/Default Source"), (0x01, "Remote Source/Option 4 Product")])
|
||||||
|
|
||||||
_mlgw_virtualactiondict = dict([(0x01, "PRESS"), (0x02, "HOLD"), (0x03, "RELEASE")])
|
mlgw_virtualactiondict = dict([(0x01, "PRESS"), (0x02, "HOLD"), (0x03, "RELEASE")])
|
||||||
|
|
||||||
### for '0x03: Picture and Sound Status'
|
# for '0x03: Picture and Sound Status'
|
||||||
_mlgw_soundstatusdict = dict([(0x00, "Not muted"), (0x01, "Muted")])
|
mlgw_soundstatusdict = dict([(0x00, "Not muted"), (0x01, "Muted")])
|
||||||
|
|
||||||
_mlgw_speakermodedict = dict(
|
mlgw_speakermodedict = dict(
|
||||||
[
|
[
|
||||||
(0x01, "Center channel"),
|
(0x01, "Center channel"),
|
||||||
(0x02, "2ch stereo"),
|
(0x02, "2ch stereo"),
|
||||||
|
@ -437,20 +437,20 @@ _mlgw_speakermodedict = dict(
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
_mlgw_screenmutedict = dict([(0x00, "not muted"), (0x01, "muted")])
|
mlgw_screenmutedict = dict([(0x00, "not muted"), (0x01, "muted")])
|
||||||
_mlgw_screenactivedict = dict([(0x00, "not active"), (0x01, "active")])
|
mlgw_screenactivedict = dict([(0x00, "not active"), (0x01, "active")])
|
||||||
_mlgw_cinemamodedict = dict([(0x00, "Cinemamode=off"), (0x01, "Cinemamode=on")])
|
mlgw_cinemamodedict = dict([(0x00, "Cinema mode off"), (0x01, "Cinema mode on")])
|
||||||
_mlgw_stereoindicatordict = dict([(0x00, "Mono"), (0x01, "Stereo")])
|
mlgw_stereoindicatordict = dict([(0x00, "Mono"), (0x01, "Stereo")])
|
||||||
|
|
||||||
### for '0x04: Light and Control command'
|
# for '0x04: Light and Control command'
|
||||||
_mlgw_lctypedict = dict([(0x01, "LIGHT"), (0x02, "CONTROL")])
|
mlgw_lctypedict = dict([(0x01, "LIGHT"), (0x02, "CONTROL")])
|
||||||
|
|
||||||
### for '0x31: Login Status
|
# for '0x31: Login Status
|
||||||
_mlgw_loginstatusdict = dict([(0x00, "OK"), (0x01, "FAIL")])
|
mlgw_loginstatusdict = dict([(0x00, "OK"), (0x01, "FAIL")])
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### BeoLink Gateway Protocol packet constants
|
# ##### BeoLink Gateway Protocol packet constants
|
||||||
_blgw_srcdict = dict(
|
blgw_srcdict = dict(
|
||||||
[
|
[
|
||||||
("TV", "TV"),
|
("TV", "TV"),
|
||||||
("DVD", "DVD"),
|
("DVD", "DVD"),
|
||||||
|
|
|
@ -5,7 +5,8 @@ import time
|
||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import Resources.CONSTANTS as const
|
import Resources.CONSTANTS as CONST
|
||||||
|
|
||||||
|
|
||||||
class MLCLIClient(asynchat.async_chat):
|
class MLCLIClient(asynchat.async_chat):
|
||||||
"""Client to monitor raw packet traffic on the Masterlink network via the undocumented command line interface
|
"""Client to monitor raw packet traffic on the Masterlink network via the undocumented command line interface
|
||||||
|
@ -57,7 +58,7 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
telegram = self._received_data
|
telegram = self._received_data
|
||||||
self._received_data = ""
|
self._received_data = ""
|
||||||
|
|
||||||
#clear login process lines before processing telegrams
|
# Clear login process lines before processing telegrams
|
||||||
if self._i <= self._header_lines:
|
if self._i <= self._header_lines:
|
||||||
self._i += 1
|
self._i += 1
|
||||||
if self._i == self._header_lines - 1:
|
if self._i == self._header_lines - 1:
|
||||||
|
@ -67,6 +68,16 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
|
|
||||||
# Process telegrams and return json data in human readable format
|
# Process telegrams and return json data in human readable format
|
||||||
if self._i > self._header_lines:
|
if self._i > self._header_lines:
|
||||||
|
if "---- Logging" in telegram:
|
||||||
|
# Pong telegram
|
||||||
|
header = telegram
|
||||||
|
payload = []
|
||||||
|
message = OrderedDict([('payload_type', 'Pong'), ('CONNECTION', 'Online')])
|
||||||
|
self.is_connected = True
|
||||||
|
if self.messageCallBack:
|
||||||
|
self.messageCallBack(self.name, header, str(list(payload)), message)
|
||||||
|
else:
|
||||||
|
# ML protocol message detected
|
||||||
items = telegram.split()[1:]
|
items = telegram.split()[1:]
|
||||||
if len(items):
|
if len(items):
|
||||||
telegram = bytearray()
|
telegram = bytearray()
|
||||||
|
@ -75,6 +86,8 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
telegram.append(int(item[:-1], base=16))
|
telegram.append(int(item[:-1], base=16))
|
||||||
except:
|
except:
|
||||||
# abort if invalid character found
|
# abort if invalid character found
|
||||||
|
self.log.debug('Invalid character ' + str(item) + ' found in telegram: ' +
|
||||||
|
''.join(items) + '\nAborting!')
|
||||||
break
|
break
|
||||||
|
|
||||||
# Decode any telegram with a valid 9 byte header, excluding typy 0x14 (regular clock sync pings)
|
# Decode any telegram with a valid 9 byte header, excluding typy 0x14 (regular clock sync pings)
|
||||||
|
@ -90,7 +103,6 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
self.set_terminator(b'\r\n')
|
self.set_terminator(b'\r\n')
|
||||||
# Create the socket
|
# Create the socket
|
||||||
try:
|
try:
|
||||||
socket.setdefaulttimeout(3)
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
self.log.info("Error creating socket: %s" % e)
|
self.log.info("Error creating socket: %s" % e)
|
||||||
|
@ -101,12 +113,12 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
except socket.gaierror, e:
|
except socket.gaierror, e:
|
||||||
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
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()
|
|
||||||
except socket.timeout, e:
|
except socket.timeout, e:
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
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:
|
else:
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
self.log.info("\tConnected to B&O Gateway")
|
self.log.info("\tConnected to B&O Gateway")
|
||||||
|
@ -124,12 +136,12 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
def send_cmd(self, telegram):
|
def send_cmd(self, telegram):
|
||||||
try:
|
try:
|
||||||
self.push(telegram + "\r\n")
|
self.push(telegram + "\r\n")
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error sending data: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
except socket.timeout, e:
|
except socket.timeout, e:
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
self.handle_close()
|
||||||
|
except socket.error, e:
|
||||||
|
self.log.info("Error sending data: %s" % e)
|
||||||
|
self.handle_close()
|
||||||
else:
|
else:
|
||||||
self.last_sent = telegram
|
self.last_sent = telegram
|
||||||
self.last_sent_at = time.time()
|
self.last_sent_at = time.time()
|
||||||
|
@ -149,7 +161,8 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### Utility functions
|
# ##### Utility functions
|
||||||
def _hexbyte(self, byte):
|
@staticmethod
|
||||||
|
def _hexbyte(byte):
|
||||||
resultstr = hex(byte)
|
resultstr = hex(byte)
|
||||||
if byte < 16:
|
if byte < 16:
|
||||||
resultstr = resultstr[:2] + "0" + resultstr[2]
|
resultstr = resultstr[:2] + "0" + resultstr[2]
|
||||||
|
@ -162,12 +175,13 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
|
|
||||||
def _dictsanitize(self, d, s):
|
def _dictsanitize(self, d, s):
|
||||||
result = d.get(s)
|
result = d.get(s)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = self._hexbyte(s)
|
result = self._hexbyte(s)
|
||||||
self.log.debug("UNKNOWN (type=" + result + ")")
|
self.log.debug("UNKNOWN (type=" + result + ")")
|
||||||
return str(result)
|
return str(result)
|
||||||
|
|
||||||
def _get_type(self, d, s):
|
@staticmethod
|
||||||
|
def _get_type(d, s):
|
||||||
rev_dict = {value: key for key, value in d.items()}
|
rev_dict = {value: key for key, value in d.items()}
|
||||||
for i in range(len(list(rev_dict))):
|
for i in range(len(list(rev_dict))):
|
||||||
if s in list(rev_dict)[i]:
|
if s in list(rev_dict)[i]:
|
||||||
|
@ -175,127 +189,195 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### Decode Masterlink Protocol packet to a serializable dict
|
# ##### Decode Masterlink Protocol packet to a serializable dict
|
||||||
|
|
||||||
def _decode(self, telegram):
|
def _decode(self, telegram):
|
||||||
# Decode header
|
# Decode header
|
||||||
message = OrderedDict()
|
message = OrderedDict()
|
||||||
if const.devices:
|
if CONST.devices:
|
||||||
for device in const.devices:
|
for device in CONST.devices:
|
||||||
if device['ML_ID'] == telegram[1]:
|
if device['ML_ID'] == telegram[1]:
|
||||||
message["Zone"] = device["Zone"].upper()
|
message["Zone"] = device["Zone"].upper()
|
||||||
message["Room"] = device["Room"].uppr()
|
message["Room"] = device["Room"].uppr()
|
||||||
message["Type"] = "AV RENDERER"
|
message["Type"] = "AV RENDERER"
|
||||||
message["Device"] = device["Device"]
|
message["Device"] = device["Device"]
|
||||||
message["from_device"] = self._dictsanitize(const._ml_device_dict, telegram[1])
|
break
|
||||||
message["from_source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[5])
|
message["from_device"] = self._dictsanitize(CONST.ml_device_dict, telegram[1])
|
||||||
message["to_device"] = self._dictsanitize(const._ml_device_dict, telegram[0])
|
message["from_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[5])
|
||||||
message["to_source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[4])
|
message["to_device"] = self._dictsanitize(CONST.ml_device_dict, telegram[0])
|
||||||
message["type"] = self._dictsanitize(const._ml_telegram_type_dict, telegram[3])
|
message["to_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[4])
|
||||||
message["payload_type"] = self._dictsanitize(const._ml_command_type_dict, telegram[7])
|
message["type"] = self._dictsanitize(CONST.ml_telegram_type_dict, telegram[3])
|
||||||
|
message["payload_type"] = self._dictsanitize(CONST.ml_command_type_dict, telegram[7])
|
||||||
message["payload_len"] = telegram[8] + 1
|
message["payload_len"] = telegram[8] + 1
|
||||||
message["payload"] = OrderedDict()
|
message["State_Update"] = OrderedDict()
|
||||||
|
|
||||||
# source status info
|
# source status info
|
||||||
# TTFF__TYDSOS__PTLLPS SR____LS______SLSHTR__ACSTPI________________________TRTR______
|
# TTFF__TYDSOS__PTLLPS SR____LS______SLSHTR__ACSTPI________________________TRTR______
|
||||||
if message.get("payload_type") == "STATUS_INFO":
|
if message.get("payload_type") == "STATUS_INFO":
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[10])
|
message["State_Update"]["nowPlaying"] = ''
|
||||||
message["payload"]["sourceID"] = telegram[10]
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["payload"]["source_type"] = telegram[22]
|
message["State_Update"]["nowPlayingDetails"]["local_source"] = telegram[13]
|
||||||
message["payload"]["local_source"] = telegram[13]
|
message["State_Update"]["nowPlayingDetails"]["type"] = telegram[22]
|
||||||
message["payload"]["source_medium"] = self._hexword(telegram[18], telegram[17])
|
if telegram[8] < 27:
|
||||||
message["payload"]["channel_track"] = (
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[19]
|
||||||
telegram[19] if telegram[8] < 27 else (telegram[36] * 256 + telegram[37])
|
else:
|
||||||
)
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[36] * 256 + telegram[37]
|
||||||
message["payload"]["picture_identifier"] = self._dictsanitize(const._ml_pictureformatdict, telegram[23])
|
message["State_Update"]["nowPlayingDetails"]["source_medium_position"] = \
|
||||||
message["payload"]["state"] = self._dictsanitize(const._sourceactivitydict, telegram[21])
|
self._hexword(telegram[18], telegram[17])
|
||||||
|
message["State_Update"]["nowPlayingDetails"]["picture_identifier"] = \
|
||||||
|
self._dictsanitize(CONST.ml_pictureformatdict, telegram[23])
|
||||||
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[10])
|
||||||
|
self._get_source_name(source, message)
|
||||||
|
message["State_Update"]["source"] = source
|
||||||
|
message["State_Update"]["sourceID"] = telegram[10]
|
||||||
|
self._get_channel_track(telegram, message)
|
||||||
|
message["State_Update"]["state"] = self._dictsanitize(CONST.sourceactivitydict, telegram[21])
|
||||||
|
|
||||||
# display source information
|
# display source information
|
||||||
if message.get("payload_type") == "DISPLAY_SOURCE":
|
if message.get("payload_type") == "DISPLAY_SOURCE":
|
||||||
_s = ""
|
_s = ""
|
||||||
for i in range(0, telegram[8] - 5):
|
for i in range(0, telegram[8] - 5):
|
||||||
_s = _s + chr(telegram[i + 15])
|
_s = _s + chr(telegram[i + 15])
|
||||||
message["payload"]["display_source"] = _s.rstrip()
|
message["State_Update"]["display_source"] = _s.rstrip()
|
||||||
|
|
||||||
# extended source information
|
# extended source information
|
||||||
if message.get("payload_type") == "EXTENDED_SOURCE_INFORMATION":
|
if message.get("payload_type") == "EXTENDED_SOURCE_INFORMATION":
|
||||||
message["payload"]["info_type"] = telegram[10]
|
message["State_Update"]["info_type"] = telegram[10]
|
||||||
_s = ""
|
_s = ""
|
||||||
for i in range(0, telegram[8] - 14):
|
for i in range(0, telegram[8] - 14):
|
||||||
_s = _s + chr(telegram[i + 24])
|
_s = _s + chr(telegram[i + 24])
|
||||||
message["payload"]["info_value"] = _s
|
message["State_Update"]["info_value"] = _s
|
||||||
|
|
||||||
# beo4 command
|
# beo4 command
|
||||||
if message.get("payload_type") == "BEO4_KEY":
|
if message.get("payload_type") == "BEO4_KEY":
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[10])
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[10])
|
||||||
message["payload"]["sourceID"] = telegram[10]
|
self._get_source_name(source, message)
|
||||||
message["payload"]["source_type"] = self._get_type(const._ml_selectedsource_type_dict, telegram[10])
|
message["State_Update"]["source"] = source
|
||||||
message["payload"]["command"] = self._dictsanitize(const.beo4_commanddict, telegram[11])
|
message["State_Update"]["sourceID"] = telegram[10]
|
||||||
|
message["State_Update"]["source_type"] = self._get_type(CONST.ml_selectedsource_type_dict, telegram[10])
|
||||||
|
message["State_Update"]["command"] = self._dictsanitize(CONST.beo4_commanddict, telegram[11])
|
||||||
|
|
||||||
# audio track info long
|
# audio track info long
|
||||||
if message.get("payload_type") == "TRACK_INFO_LONG":
|
if message.get("payload_type") == "TRACK_INFO_LONG":
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[11])
|
message["State_Update"]["nowPlaying"] = ''
|
||||||
message["payload"]["sourceID"] = telegram[11]
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["payload"]["source_type"] = self._get_type(const._ml_selectedsource_type_dict, telegram[11])
|
message["State_Update"]["nowPlayingDetails"]["type"] = \
|
||||||
message["payload"]["channel_track"] = telegram[12]
|
self._get_type(CONST.ml_selectedsource_type_dict, telegram[11])
|
||||||
message["payload"]["state"] = self._dictsanitize(const._sourceactivitydict, telegram[13])
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[12]
|
||||||
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
||||||
|
self._get_source_name(source, message)
|
||||||
|
message["State_Update"]["source"] = source
|
||||||
|
message["State_Update"]["sourceID"] = telegram[11]
|
||||||
|
self._get_channel_track(telegram, message)
|
||||||
|
message["State_Update"]["state"] = self._dictsanitize(CONST.sourceactivitydict, telegram[13])
|
||||||
|
|
||||||
# video track info
|
# video track info
|
||||||
if message.get("payload_type") == "VIDEO_TRACK_INFO":
|
if message.get("payload_type") == "VIDEO_TRACK_INFO":
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[13])
|
message["State_Update"]["nowPlaying"] = ''
|
||||||
message["payload"]["sourceID"] = telegram[13]
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["payload"]["source_type"] = self._get_type(const._ml_selectedsource_type_dict, telegram[13])
|
message["State_Update"]["nowPlayingDetails"]["source_type"] = \
|
||||||
message["payload"]["channel_track"] = telegram[11] * 256 + telegram[12]
|
self._get_type(CONST.ml_selectedsource_type_dict, telegram[13])
|
||||||
message["payload"]["state"] = self._dictsanitize(const._sourceactivitydict, telegram[14])
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[11] * 256 + telegram[12]
|
||||||
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[13])
|
||||||
|
self._get_source_name(source, message)
|
||||||
|
message["State_Update"]["source"] = source
|
||||||
|
message["State_Update"]["sourceID"] = telegram[13]
|
||||||
|
self._get_channel_track(telegram, message)
|
||||||
|
message["State_Update"]["state"] = self._dictsanitize(CONST.sourceactivitydict, telegram[14])
|
||||||
|
|
||||||
# track change info
|
# track change info
|
||||||
if message.get("payload_type") == "TRACK_INFO":
|
if message.get("payload_type") == "TRACK_INFO":
|
||||||
message["payload"]["subtype"] = self._dictsanitize(const._ml_trackinfo_subtype_dict, telegram[9])
|
message["State_Update"]["subtype"] = self._dictsanitize(CONST.ml_trackinfo_subtype_dict, telegram[9])
|
||||||
if message["payload"].get("subtype") == "Change Source":
|
if message["State_Update"].get("subtype") == "Change Source":
|
||||||
message["payload"]["prev_source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[11])
|
message["State_Update"]["prev_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
||||||
message["payload"]["prev_sourceID"] = telegram[11]
|
message["State_Update"]["prev_sourceID"] = telegram[11]
|
||||||
message["payload"]["prev_source_type"] = self._get_type(
|
message["State_Update"]["prev_source_type"] = self._get_type(
|
||||||
const._ml_selectedsource_type_dict, telegram[11])
|
CONST.ml_selectedsource_type_dict, telegram[11])
|
||||||
if len(telegram) > 18:
|
if len(telegram) > 18:
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[22])
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[22])
|
||||||
message["payload"]["sourceID"] = telegram[22]
|
self._get_source_name(source, message)
|
||||||
if message["payload"].get("subtype") == "Current Source":
|
message["State_Update"]["source"] = source
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[11])
|
message["State_Update"]["sourceID"] = telegram[22]
|
||||||
message["payload"]["sourceID"] = telegram[11]
|
|
||||||
message["payload"]["source_type"] = self._get_type(const._ml_selectedsource_type_dict, telegram[11])
|
if message["State_Update"].get("subtype") == "Current Source":
|
||||||
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
||||||
|
self._get_source_name(source, message)
|
||||||
|
message["State_Update"]["source"] = source
|
||||||
|
message["State_Update"]["sourceID"] = telegram[11]
|
||||||
|
message["State_Update"]["source_type"] = self._get_type(CONST.ml_selectedsource_type_dict, telegram[11])
|
||||||
else:
|
else:
|
||||||
message["payload"]["subtype"] = "Undefined: " + self._hexbyte(telegram[9])
|
message["State_Update"]["subtype"] = "Undefined: " + self._hexbyte(telegram[9])
|
||||||
|
|
||||||
# goto source
|
# goto source
|
||||||
if message.get("payload_type") == "GOTO_SOURCE":
|
if message.get("payload_type") == "GOTO_SOURCE":
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[11])
|
message["State_Update"]["nowPlaying"] = ''
|
||||||
message["payload"]["sourceID"] = telegram[11]
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["payload"]["source_type"] = self._get_type(const._ml_selectedsource_type_dict, telegram[11])
|
message["State_Update"]["nowPlayingDetails"]["source_type"] = \
|
||||||
message["payload"]["channel_track"] = telegram[12]
|
self._get_type(CONST.ml_selectedsource_type_dict, telegram[11])
|
||||||
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[12]
|
||||||
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
||||||
|
self._get_source_name(source, message)
|
||||||
|
message["State_Update"]["source"] = source
|
||||||
|
message["State_Update"]["sourceID"] = telegram[11]
|
||||||
|
self._get_channel_track(telegram, message)
|
||||||
|
|
||||||
# remote request
|
# remote request
|
||||||
if message.get("payload_type") == "MLGW_REMOTE_BEO4":
|
if message.get("payload_type") == "MLGW_REMOTE_BEO4":
|
||||||
message["payload"]["command"] = self._dictsanitize(const.beo4_commanddict, telegram[14])
|
message["State_Update"]["command"] = self._dictsanitize(CONST.beo4_commanddict, telegram[14])
|
||||||
message["payload"]["destination"] = self._dictsanitize(const._destselectordict, telegram[11])
|
message["State_Update"]["destination"] = self._dictsanitize(CONST.destselectordict, telegram[11])
|
||||||
|
|
||||||
# request_key
|
# request_key
|
||||||
if message.get("payload_type") == "LOCK_MANAGER_COMMAND":
|
if message.get("payload_type") == "LOCK_MANAGER_COMMAND":
|
||||||
message["payload"]["subtype"] = self._dictsanitize(
|
message["State_Update"]["subtype"] = self._dictsanitize(
|
||||||
const._ml_command_type_request_key_subtype_dict, telegram[9])
|
CONST.ml_command_type_request_key_subtype_dict, telegram[9])
|
||||||
|
|
||||||
# request distributed audio source
|
# request distributed audio source
|
||||||
if message.get("payload_type") == "REQUEST_DISTRIBUTED_SOURCE":
|
if message.get("payload_type") == "REQUEST_DISTRIBUTED_SOURCE":
|
||||||
message["payload"]["subtype"] = self._dictsanitize(const._ml_activity_dict, telegram[9])
|
message["State_Update"]["subtype"] = self._dictsanitize(CONST.ml_activity_dict, telegram[9])
|
||||||
if message["payload"].get('subtype') == "Source Active":
|
if message["State_Update"].get('subtype') == "Source Active":
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[13])
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[13])
|
||||||
message["payload"]["sourceID"] = telegram[13]
|
self._get_source_name(source, message)
|
||||||
message["payload"]["source_type"] = self._get_type(const._ml_selectedsource_type_dict, telegram[13])
|
message["State_Update"]["source"] = source
|
||||||
|
message["State_Update"]["sourceID"] = telegram[13]
|
||||||
|
message["State_Update"]["source_type"] = self._get_type(CONST.ml_selectedsource_type_dict, telegram[13])
|
||||||
|
|
||||||
# request local audio source
|
# request local audio source
|
||||||
if message.get("payload_type") == "REQUEST_LOCAL_SOURCE":
|
if message.get("payload_type") == "REQUEST_LOCAL_SOURCE":
|
||||||
message["payload"]["subtype"] = self._dictsanitize(const._ml_activity_dict, telegram[9])
|
message["State_Update"]["subtype"] = self._dictsanitize(CONST.ml_activity_dict, telegram[9])
|
||||||
if message["payload"].get('subtype') == "Source Active":
|
if message["State_Update"].get('subtype') == "Source Active":
|
||||||
message["payload"]["source"] = self._dictsanitize(const._ml_selectedsourcedict, telegram[11])
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
||||||
message["payload"]["sourceID"] = telegram[11]
|
self._get_source_name(source, message)
|
||||||
message["payload"]["source_type"] = self._get_type(const._ml_selectedsource_type_dict, telegram[11])
|
message["State_Update"]["source"] = source
|
||||||
|
message["State_Update"]["sourceID"] = telegram[11]
|
||||||
|
message["State_Update"]["source_type"] = self._get_type(CONST.ml_selectedsource_type_dict, telegram[11])
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_channel_track(telegram, message):
|
||||||
|
# Check device list for channel name information
|
||||||
|
if CONST.devices:
|
||||||
|
for device in CONST.devices:
|
||||||
|
# Loop over devices to find source list for this specific device
|
||||||
|
if device['ML_ID'] == telegram[1]:
|
||||||
|
if 'channels' in device['Sources'][message["State_Update"]["source"]]:
|
||||||
|
for channel in device['Sources'][message["State_Update"]["source"]]['channels']:
|
||||||
|
if channel['number'] == message["State_Update"]["nowPlayingDetails"]["channel_track"]:
|
||||||
|
message["State_Update"]["nowPlaying"] = channel['name']
|
||||||
|
break
|
||||||
|
# If device is a NetLink device and has no ML_ID, seek a generic solution from the first device that has
|
||||||
|
# this source available: This could give an incorrect response if a link room device has a different
|
||||||
|
# favorites list to the Audio Master!
|
||||||
|
for device in CONST.devices:
|
||||||
|
if message["State_Update"]["source"] in device['Sources']:
|
||||||
|
if 'channels' in device['Sources'][message["State_Update"]["source"]]:
|
||||||
|
for channel in device['Sources'][message["State_Update"]["source"]]['channels']:
|
||||||
|
if channel['number'] == message["State_Update"]["nowPlayingDetails"]["channel_track"]:
|
||||||
|
message["State_Update"]["nowPlaying"] = channel['name']
|
||||||
|
break
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_source_name(source, message):
|
||||||
|
if CONST.available_sources:
|
||||||
|
for src in CONST.available_sources:
|
||||||
|
if src[1] == source:
|
||||||
|
message["State_Update"]["sourceName"] = src[0]
|
||||||
|
break
|
||||||
|
|
|
@ -4,34 +4,35 @@ import asyncore
|
||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import Resources.CONSTANTS as const
|
import Resources.CONSTANTS as CONST
|
||||||
|
|
||||||
|
|
||||||
class MLConfig:
|
class MLConfig:
|
||||||
|
|
||||||
def __init__(self, host_address='blgw.local', user='admin', pwd='admin'):
|
def __init__(self, host_address='blgw.local', user='admin', pwd='admin'):
|
||||||
self.log = logging.getLogger('Config:')
|
self.log = logging.getLogger('Config')
|
||||||
self.log.setLevel('INFO')
|
self.log.setLevel('INFO')
|
||||||
|
|
||||||
self._host = host_address
|
self._host = host_address
|
||||||
self._user = user
|
self._user = user
|
||||||
self._pwd = pwd
|
self._pwd = pwd
|
||||||
|
|
||||||
self._downloadData()
|
self._download_data()
|
||||||
|
|
||||||
def _downloadData(self):
|
def _download_data(self):
|
||||||
self.log.info('Downloading configuration data from Gateway...')
|
self.log.info('Downloading configuration data from Gateway...')
|
||||||
url = 'http://' + self._host + '/mlgwpservices.json'
|
url = 'http://' + self._host + '/mlgwpservices.json'
|
||||||
auth = (self._user, self._pwd)
|
auth = (self._user, self._pwd)
|
||||||
response = requests.get(url, auth=auth)
|
response = requests.get(url, auth=auth)
|
||||||
configurationdata = json.loads(response.text)
|
configurationdata = json.loads(response.text)
|
||||||
self.configureMLGW((configurationdata))
|
self.configure_mlgw(configurationdata)
|
||||||
|
|
||||||
def configureMLGW(self, data):
|
def configure_mlgw(self, data):
|
||||||
self.log.info('Processing Gateway configuration data...\n')
|
self.log.info('Processing Gateway configuration data...\n')
|
||||||
const.gateway['Serial_Number'] = data['sn']
|
CONST.gateway['Serial_Number'] = data['sn']
|
||||||
const.gateway['Project'] = data['project']
|
CONST.gateway['Project'] = data['project']
|
||||||
const.gateway['Installer'] = str(data['installer']['name'])
|
CONST.gateway['Installer'] = str(data['installer']['name'])
|
||||||
const.gateway['Contact'] = str(data['installer']['contact'])
|
CONST.gateway['Contact'] = str(data['installer']['contact'])
|
||||||
|
|
||||||
for zone in data["zones"]:
|
for zone in data["zones"]:
|
||||||
if int(zone['number']) == 240:
|
if int(zone['number']) == 240:
|
||||||
|
@ -58,59 +59,59 @@ class MLConfig:
|
||||||
device['Sources'][str(source["name"])] = OrderedDict()
|
device['Sources'][str(source["name"])] = OrderedDict()
|
||||||
for selectCmd in source["selectCmds"]:
|
for selectCmd in source["selectCmds"]:
|
||||||
source_id = str(source['sourceId'].split(':')[0])
|
source_id = str(source['sourceId'].split(':')[0])
|
||||||
source_id = self._srcdictsanitize(const._blgw_srcdict, source_id).upper()
|
source_id = self._srcdictsanitize(CONST.blgw_srcdict, source_id).upper()
|
||||||
device['Sources'][str(source["name"])]['source'] = source_id
|
device['Sources'][str(source["name"])]['source'] = source_id
|
||||||
device['Sources'][str(source["name"])]['uniqueID'] = str(source['sourceId'])
|
device['Sources'][str(source["name"])]['uniqueID'] = str(source['sourceId'])
|
||||||
source_tuple = (str(source["name"]), source_id)
|
source_tuple = (str(source["name"]), source_id)
|
||||||
cmd_tuple = (source_id, (int(selectCmd["cmd"]), int(selectCmd["unit"])))
|
cmd_tuple = (source_id, (int(selectCmd["cmd"]), int(selectCmd["unit"])))
|
||||||
device['Sources'][str(source["name"])]['BR1_cmd'] = cmd_tuple
|
device['Sources'][str(source["name"])]['BR1_cmd'] = cmd_tuple
|
||||||
if source.has_key('channels'):
|
if 'channels' in source:
|
||||||
device['Sources'][str(source["name"])][
|
device['Sources'][str(source["name"])]['channels'] = []
|
||||||
'channel_track'] = OrderedDict()
|
|
||||||
for channel in source['channels']:
|
for channel in source['channels']:
|
||||||
|
c = OrderedDict()
|
||||||
c_num = ''
|
c_num = ''
|
||||||
num = channel['selectSEQ'][::2]
|
num = channel['selectSEQ'][::2]
|
||||||
for n in num:
|
for n in num:
|
||||||
c_num += str(n)
|
c_num += str(n)
|
||||||
device['Sources'][str(source["name"])]['channel_track'][c_num] = OrderedDict()
|
c['number'] = int(c_num)
|
||||||
device['Sources'][str(source["name"])]['channel_track'][c_num]['name'] = channel['name']
|
c['name'] = channel['name']
|
||||||
device['Sources'][str(source["name"])]['channel_track'][c_num]['icon'] = channel['icon']
|
c['icon'] = channel['icon']
|
||||||
|
device['Sources'][str(source["name"])]['channels'].append(c)
|
||||||
|
|
||||||
if source_tuple not in const.available_sources:
|
if source_tuple not in CONST.available_sources:
|
||||||
const.available_sources.append(source_tuple)
|
CONST.available_sources.append(source_tuple)
|
||||||
|
|
||||||
const.devices.append(device)
|
CONST.devices.append(device)
|
||||||
const.rooms.append(room)
|
CONST.rooms.append(room)
|
||||||
|
|
||||||
self.log.info('Found ' + str(len(const.devices)) + ' AV Renderers!')
|
self.log.info('Found ' + str(len(CONST.devices)) + ' AV Renderers!')
|
||||||
for i in range(len(const.devices)):
|
for i in range(len(CONST.devices)):
|
||||||
self.log.info('\tMLN ' + str(const.devices[i].get('MLN')) + ': ' + str(const.devices[i].get('Device')))
|
self.log.info('\tMLN ' + str(CONST.devices[i].get('MLN')) + ': ' + str(CONST.devices[i].get('Device')))
|
||||||
self.log.info('\tFound ' + str(len(const.available_sources)) + ' Available Sources [Name, Type]:')
|
self.log.info('\tFound ' + str(len(CONST.available_sources)) + ' Available Sources [Name, Type]:')
|
||||||
for i in range(len(const.available_sources)):
|
for i in range(len(CONST.available_sources)):
|
||||||
self.log.info('\t\t' + str(list(const.available_sources[i])))
|
self.log.info('\t\t' + str(list(CONST.available_sources[i])))
|
||||||
self.log.info('Done!\n')
|
self.log.info('Done!\n')
|
||||||
|
|
||||||
self.log.debug(json.dumps(const.gateway, indent=4))
|
self.log.debug(json.dumps(CONST.gateway, indent=4))
|
||||||
self.log.debug(json.dumps(const.rooms, indent=4))
|
self.log.debug(json.dumps(CONST.rooms, indent=4))
|
||||||
self.log.debug(json.dumps(const.devices, indent=4))
|
self.log.debug(json.dumps(CONST.devices, indent=4))
|
||||||
|
|
||||||
def get_masterlink_id(self, mlgw, mlcli):
|
def get_masterlink_id(self, mlgw, mlcli):
|
||||||
self.log.info("Finding MasterLink ID of products:")
|
self.log.info("Finding MasterLink ID of products:")
|
||||||
if mlgw.is_connected and mlcli.is_connected:
|
if mlgw.is_connected and mlcli.is_connected:
|
||||||
for device in const.devices:
|
for device in CONST.devices:
|
||||||
self.log.info("Finding MasterLink ID of product " + device.get('Device'))
|
self.log.info("Finding MasterLink ID of product " + device.get('Device'))
|
||||||
# Ping the device with a light timeout to elicit a ML telegram containing its ML_ID
|
# Ping the device with a light timeout to elicit a ML telegram containing its ML_ID
|
||||||
mlgw.send_beo4_cmd(int(device.get('MLN')),
|
mlgw.send_beo4_cmd(int(device.get('MLN')),
|
||||||
const.CMDS_DEST.get("AUDIO SOURCE"),
|
CONST.CMDS_DEST.get("AUDIO SOURCE"),
|
||||||
const.BEO4_CMDS.get("LIGHT TIMEOUT"))
|
CONST.BEO4_CMDS.get("LIGHT TIMEOUT"))
|
||||||
|
|
||||||
if device.get('Serial_num') is None:
|
if device.get('Serial_num') is None:
|
||||||
# If this is a MasterLink product it has no serial number...
|
# If this is a MasterLink product it has no serial number...
|
||||||
# loop to until expected response received from ML Command Line Interface
|
# loop to until expected response received from ML Command Line Interface
|
||||||
while not mlcli.last_message.has_key('to_device') and mlcli.last_message[
|
while 'to_device' not in mlcli.last_message and mlcli.last_message['from_device'] == \
|
||||||
'from_device'] == "MLGW" and mlcli.last_message[
|
"MLGW" and mlcli.last_message['payload_type'] == \
|
||||||
'payload_type'] == "MLGW_REMOTE_BEO4" and mlcli.last_message[
|
"MLGW_REMOTE_BEO4" and mlcli.last_message['payload']['command'] == "LIGHT TIMEOUT":
|
||||||
'payload']['command'] == "LIGHT TIMEOUT":
|
|
||||||
asyncore.loop(count=1, timeout=0.2)
|
asyncore.loop(count=1, timeout=0.2)
|
||||||
|
|
||||||
device['ML_ID'] = mlcli.last_message.get('to_device')
|
device['ML_ID'] = mlcli.last_message.get('to_device')
|
||||||
|
@ -122,8 +123,9 @@ class MLConfig:
|
||||||
self.log.info("\tNetworkLink ID of product " + device.get('Device') + " is " +
|
self.log.info("\tNetworkLink ID of product " + device.get('Device') + " is " +
|
||||||
device.get('Serial_num') + ". No MasterLink ID assigned.\n")
|
device.get('Serial_num') + ". No MasterLink ID assigned.\n")
|
||||||
|
|
||||||
def _srcdictsanitize(self, d, s):
|
@staticmethod
|
||||||
|
def _srcdictsanitize(d, s):
|
||||||
result = d.get(s)
|
result = d.get(s)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = s
|
result = s
|
||||||
return str(result)
|
return str(result)
|
||||||
|
|
|
@ -5,7 +5,8 @@ import time
|
||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import Resources.CONSTANTS as const
|
import Resources.CONSTANTS as CONST
|
||||||
|
|
||||||
|
|
||||||
class MLGWClient(asynchat.async_chat):
|
class MLGWClient(asynchat.async_chat):
|
||||||
"""Client to interact with a B&O Gateway via the MasterLink Gateway Protocol
|
"""Client to interact with a B&O Gateway via the MasterLink Gateway Protocol
|
||||||
|
@ -37,9 +38,10 @@ class MLGWClient(asynchat.async_chat):
|
||||||
self.messageCallBack = None
|
self.messageCallBack = None
|
||||||
|
|
||||||
# Expose dictionaries via API
|
# Expose dictionaries via API
|
||||||
self.BEO4_CMDS = const.BEO4_CMDS
|
self.BEO4_CMDS = CONST.BEO4_CMDS
|
||||||
self.CMDS_DEST = const.CMDS_DEST
|
self.BEORMT1_CMDS = CONST.beoremoteone_commanddict
|
||||||
self.MLGW_PL = const.MLGW_PL
|
self.CMDS_DEST = CONST.CMDS_DEST
|
||||||
|
self.MLGW_PL = CONST.MLGW_PL
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### Open Socket and connect to B&O Gateway
|
# ##### Open Socket and connect to B&O Gateway
|
||||||
|
@ -77,8 +79,7 @@ class MLGWClient(asynchat.async_chat):
|
||||||
|
|
||||||
def _decode(self, msg_type, header, payload):
|
def _decode(self, msg_type, header, payload):
|
||||||
message = OrderedDict()
|
message = OrderedDict()
|
||||||
payload_type = self._dictsanitize(const._mlgw_payloadtypedict, msg_type)
|
payload_type = self._dictsanitize(CONST.mlgw_payloadtypedict, msg_type)
|
||||||
message["Payload_type"] = payload_type
|
|
||||||
|
|
||||||
if payload_type == "MLGW virtual button event":
|
if payload_type == "MLGW virtual button event":
|
||||||
virtual_btn = payload[0]
|
virtual_btn = payload[0]
|
||||||
|
@ -87,6 +88,7 @@ class MLGWClient(asynchat.async_chat):
|
||||||
else:
|
else:
|
||||||
virtual_action = self._getvirtualactionstr(payload[1])
|
virtual_action = self._getvirtualactionstr(payload[1])
|
||||||
|
|
||||||
|
message["payload_type"] = payload_type
|
||||||
message["button"] = virtual_btn
|
message["button"] = virtual_btn
|
||||||
message["action"] = virtual_action
|
message["action"] = virtual_action
|
||||||
|
|
||||||
|
@ -99,75 +101,89 @@ class MLGWClient(asynchat.async_chat):
|
||||||
else:
|
else:
|
||||||
self.log.info("\tLogin successful to %s", self._host)
|
self.log.info("\tLogin successful to %s", self._host)
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
|
message["payload_type"] = payload_type
|
||||||
message['Connected'] = "True"
|
message['Connected'] = "True"
|
||||||
self.get_serial()
|
self.get_serial()
|
||||||
|
|
||||||
elif payload_type == "Pong":
|
elif payload_type == "Pong":
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
|
message["payload_type"] = payload_type
|
||||||
message['CONNECTION'] = 'Online'
|
message['CONNECTION'] = 'Online'
|
||||||
|
|
||||||
elif payload_type == "Serial Number":
|
elif payload_type == "Serial Number":
|
||||||
sn = ''
|
sn = ''
|
||||||
for c in payload:
|
for c in payload:
|
||||||
sn += chr(c)
|
sn += chr(c)
|
||||||
message['Serial_Num'] = sn
|
message["payload_type"] = payload_type
|
||||||
|
message['serial_Num'] = sn
|
||||||
|
|
||||||
elif payload_type == "Source Status":
|
elif payload_type == "Source Status":
|
||||||
if const.rooms and const.devices:
|
if CONST.rooms and CONST.devices:
|
||||||
for device in const.devices:
|
for device in CONST.devices:
|
||||||
if device['MLN'] == payload[0]:
|
if device['MLN'] == payload[0]:
|
||||||
name = device['Device']
|
name = device['Device']
|
||||||
for room in const.rooms:
|
for room in CONST.rooms:
|
||||||
if name in room['Products']:
|
if name in room['Products']:
|
||||||
message["Zone"] = room['Zone'].upper()
|
message["Zone"] = room['Zone'].upper()
|
||||||
message["Room"] = room['Room_Name'].upper()
|
message["Room"] = room['Room_Name'].upper()
|
||||||
message["Type"] = 'AV RENDERER'
|
message["Type"] = 'AV RENDERER'
|
||||||
message["Device"] = name
|
message["Device"] = name
|
||||||
|
message["payload_type"] = payload_type
|
||||||
message["MLN"] = payload[0]
|
message["MLN"] = payload[0]
|
||||||
message["Source"] = self._getselectedsourcestr(payload[1]).upper()
|
message["State_Update"] = OrderedDict()
|
||||||
message["Source_medium_position"] = self._hexword(payload[2], payload[3])
|
message["State_Update"]["nowPlaying"] = ''
|
||||||
message["Source_position"] = self._hexword(payload[4], payload[5])
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["Picture_format"] = self._getdictstr(const.ml_pictureformatdict, payload[7])
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = \
|
||||||
message["State"] = self._getdictstr(const._sourceactivitydict, payload[6])
|
self._hexword(payload[4], payload[5])
|
||||||
|
message["State_Update"]["nowPlayingDetails"]["source_medium_position"] = \
|
||||||
|
self._hexword(payload[2], payload[3])
|
||||||
|
message["State_Update"]["nowPlayingDetails"]["picture_format"] = \
|
||||||
|
self._getdictstr(CONST.ml_pictureformatdict, payload[7])
|
||||||
|
source = self._getselectedsourcestr(payload[1]).upper()
|
||||||
|
self._get_source_name(source, message)
|
||||||
|
message["State_Update"]["source"] = source
|
||||||
|
self._get_channel_track(message)
|
||||||
|
message["State_Update"]["state"] = self._getdictstr(CONST.sourceactivitydict, payload[6])
|
||||||
|
|
||||||
elif payload_type == "Picture and Sound Status":
|
elif payload_type == "Picture and Sound Status":
|
||||||
if const.rooms and const.devices:
|
if CONST.rooms and CONST.devices:
|
||||||
for device in const.devices:
|
for device in CONST.devices:
|
||||||
if device['MLN'] == payload[0]:
|
if device['MLN'] == payload[0]:
|
||||||
name = device['Device']
|
name = device['Device']
|
||||||
for room in const.rooms:
|
for room in CONST.rooms:
|
||||||
if name in room['Products']:
|
if name in room['Products']:
|
||||||
message["Zone"] = room['Zone'].upper()
|
message["Zone"] = room['Zone'].upper()
|
||||||
message["Room"] = room['Room_Name'].upper()
|
message["Room"] = room['Room_Name'].upper()
|
||||||
message["Type"] = 'AV RENDERER'
|
message["Type"] = 'AV RENDERER'
|
||||||
message["Device"] = name
|
message["Device"] = name
|
||||||
|
message["payload_type"] = payload_type
|
||||||
message["MLN"] = payload[0]
|
message["MLN"] = payload[0]
|
||||||
message["Sound_status"] = self._getdictstr(const.mlgw_soundstatusdict, payload[1])
|
message["State_Update"] = OrderedDict()
|
||||||
message["Speaker_mode"] = self._getdictstr(const._mlgw_speakermodedict, payload[2])
|
message["State_Update"]["sound_status"] = self._getdictstr(CONST.mlgw_soundstatusdict, payload[1])
|
||||||
message["Stereo_mode"] = self._getdictstr(const._mlgw_stereoindicatordict, payload[9])
|
message["State_Update"]["speakermode"] = self._getdictstr(CONST.mlgw_speakermodedict, payload[2])
|
||||||
message["Volume"] = int(payload[3])
|
message["State_Update"]["stereo_mode"] = self._getdictstr(CONST.mlgw_stereoindicatordict, payload[9])
|
||||||
message["Screen1_mute"] = self._getdictstr(const._mlgw_screenmutedict, payload[4])
|
message["State_Update"]["screen1_mute"] = self._getdictstr(CONST.mlgw_screenmutedict, payload[4])
|
||||||
message["Screen1_active"] = self._getdictstr(const._mlgw_screenactivedict, payload[5])
|
message["State_Update"]["screen1_active"] = self._getdictstr(CONST.mlgw_screenactivedict, payload[5])
|
||||||
message["Screen2_mute"] = self._getdictstr(const._mlgw_screenmutedict, payload[6])
|
message["State_Update"]["screen2_mute"] = self._getdictstr(CONST.mlgw_screenmutedict, payload[6])
|
||||||
message["Screen2_active"] = self._getdictstr(const._mlgw_screenactivedict, payload[7])
|
message["State_Update"]["screen2_active"] = self._getdictstr(CONST.mlgw_screenactivedict, payload[7])
|
||||||
message["Cinema_mode"] = self._getdictstr(const._mlgw_cinemamodedict, payload[8])
|
message["State_Update"]["cinema_mode"] = self._getdictstr(CONST.mlgw_cinemamodedict, payload[8])
|
||||||
|
message["volume"] = int(payload[3])
|
||||||
|
|
||||||
elif payload_type == "All standby notification":
|
elif payload_type == "All standby notification":
|
||||||
message["Command"] = "All Standby"
|
message["payload_type"] = payload_type
|
||||||
|
message["command"] = "All Standby"
|
||||||
|
|
||||||
elif payload_type == "Light and Control command":
|
elif payload_type == "Light and Control command":
|
||||||
if const.rooms:
|
if CONST.rooms:
|
||||||
for room in const.rooms:
|
for room in CONST.rooms:
|
||||||
if room['Room_Number'] == payload[0]:
|
if room['Room_Number'] == payload[0]:
|
||||||
message["Zone"] = room['Zone'].upper()
|
message["Zone"] = room['Zone'].upper()
|
||||||
message["Room"] = room['Room_Name'].upper()
|
message["Room"] = room['Room_Name'].upper()
|
||||||
message["Type"] = self._getdictstr(const._mlgw_lctypedict, payload[1]).upper() + " COMMAND"
|
message["Type"] = self._getdictstr(CONST.mlgw_lctypedict, payload[1]).upper() + " COMMAND"
|
||||||
message["Device"] = 'Beo4/BeoRemote One'
|
message["Device"] = 'Beo4/BeoRemote One'
|
||||||
message["Room number"] = str(payload[0])
|
message["payload_type"] = payload_type
|
||||||
message["Command"] = self._getbeo4commandstr(payload[2])
|
message["room_number"] = str(payload[0])
|
||||||
|
message["command"] = self._getbeo4commandstr(payload[2])
|
||||||
|
|
||||||
if message != '':
|
if message != '':
|
||||||
self._report(header, payload, message)
|
self._report(header, payload, message)
|
||||||
|
@ -177,7 +193,6 @@ class MLGWClient(asynchat.async_chat):
|
||||||
self.set_terminator(b'\r\n')
|
self.set_terminator(b'\r\n')
|
||||||
# Create the socket
|
# Create the socket
|
||||||
try:
|
try:
|
||||||
socket.setdefaulttimeout(3)
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
self.log.info("Error creating socket: %s" % e)
|
self.log.info("Error creating socket: %s" % e)
|
||||||
|
@ -188,12 +203,12 @@ class MLGWClient(asynchat.async_chat):
|
||||||
except socket.gaierror, e:
|
except socket.gaierror, e:
|
||||||
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
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()
|
|
||||||
except socket.timeout, e:
|
except socket.timeout, e:
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
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:
|
else:
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
self.log.info("\tConnected to B&O Gateway")
|
self.log.info("\tConnected to B&O Gateway")
|
||||||
|
@ -207,7 +222,7 @@ class MLGWClient(asynchat.async_chat):
|
||||||
login.append(c)
|
login.append(c)
|
||||||
|
|
||||||
self.log.info("\tAttempting to Authenticate...")
|
self.log.info("\tAttempting to Authenticate...")
|
||||||
self._send_cmd(const.MLGW_PL.get("LOGIN REQUEST"), login)
|
self._send_cmd(CONST.MLGW_PL.get("LOGIN REQUEST"), login)
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
self.log.info(self.name + ": Closing socket")
|
self.log.info(self.name + ": Closing socket")
|
||||||
|
@ -223,9 +238,9 @@ class MLGWClient(asynchat.async_chat):
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### mlgw send_cmder functions
|
# ##### mlgw send_cmder functions
|
||||||
|
|
||||||
## send_cmd command to mlgw
|
# send_cmd command to mlgw
|
||||||
def _send_cmd(self, msg_type, payload):
|
def _send_cmd(self, msg_type, payload):
|
||||||
#construct header
|
# Construct header
|
||||||
telegram = [1, msg_type, len(payload), 0]
|
telegram = [1, msg_type, len(payload), 0]
|
||||||
# append payload
|
# append payload
|
||||||
for p in payload:
|
for p in payload:
|
||||||
|
@ -233,12 +248,12 @@ class MLGWClient(asynchat.async_chat):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.push(str(bytearray(telegram)))
|
self.push(str(bytearray(telegram)))
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error sending data: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
except socket.timeout, e:
|
except socket.timeout, e:
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
self.handle_close()
|
||||||
|
except socket.error, e:
|
||||||
|
self.log.info("Error sending data: %s" % e)
|
||||||
|
self.handle_close()
|
||||||
else:
|
else:
|
||||||
self.last_sent = str(bytearray(telegram))
|
self.last_sent = str(bytearray(telegram))
|
||||||
self.last_sent_at = time.time()
|
self.last_sent_at = time.time()
|
||||||
|
@ -253,53 +268,52 @@ class MLGWClient(asynchat.async_chat):
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
|
|
||||||
def ping(self):
|
def ping(self):
|
||||||
self._send_cmd(const.MLGW_PL.get("PING"), "")
|
self._send_cmd(CONST.MLGW_PL.get("PING"), "")
|
||||||
|
|
||||||
## Get serial number of mlgw
|
# Get serial number of mlgw
|
||||||
def get_serial(self):
|
def get_serial(self):
|
||||||
if self.is_connected:
|
if self.is_connected:
|
||||||
# Request serial number
|
# Request serial number
|
||||||
self._send_cmd(const.MLGW_PL.get("REQUEST SERIAL NUMBER"), "")
|
self._send_cmd(CONST.MLGW_PL.get("REQUEST SERIAL NUMBER"), "")
|
||||||
|
|
||||||
## send_cmd Beo4 command to mlgw
|
# send_cmd Beo4 command to mlgw
|
||||||
def send_beo4_cmd(self, mln, dest, cmd, sec_source=0x00, link=0x00):
|
def send_beo4_cmd(self, mln, dest, cmd, sec_source=0x00, link=0x00):
|
||||||
payload = []
|
payload = [
|
||||||
payload.append(mln) # byte[0] MLN
|
mln, # byte[0] MLN
|
||||||
payload.append(dest) # byte[1] Dest-Sel (0x00, 0x01, 0x05, 0x0f)
|
dest, # byte[1] Dest-Sel (0x00, 0x01, 0x05, 0x0f)
|
||||||
payload.append(cmd) # byte[2] Beo4 Command
|
cmd, # byte[2] Beo4 Command
|
||||||
payload.append(sec_source) # byte[3] Sec-Source
|
sec_source, # byte[3] Sec-Source
|
||||||
payload.append(link) # byte[4] Link
|
link] # byte[4] Link
|
||||||
self._send_cmd(const.MLGW_PL.get("BEO4 COMMAND"), payload)
|
self._send_cmd(CONST.MLGW_PL.get("BEO4 COMMAND"), payload)
|
||||||
|
|
||||||
## send_cmd BeoRemote One command to mlgw
|
# send_cmd BeoRemote One command to mlgw
|
||||||
def send_beoremoteone_cmd(self, mln, cmd, network_bit=0x00):
|
def send_beoremoteone_cmd(self, mln, cmd, network_bit=0x00):
|
||||||
payload = []
|
payload = [
|
||||||
payload.append(mln) # byte[0] MLN
|
mln, # byte[0] MLN
|
||||||
payload.append(cmd) # byte[1] Beo4 Command
|
cmd, # byte[1] Beo4 Command
|
||||||
payload.append(0x00) # byte[2] AV (needs to be 0)
|
0x00, # byte[2] AV (needs to be 0)
|
||||||
payload.append(network_bit) # byte[3] Network_bit (0 = local source, 1 = network source)
|
network_bit] # byte[3] Network_bit (0 = local source, 1 = network source)
|
||||||
self._send_cmd(const.MLGW_PL.get("BEOREMOTE ONE CONTROL COMMAND"), payload)
|
self._send_cmd(CONST.MLGW_PL.get("BEOREMOTE ONE CONTROL COMMAND"), payload)
|
||||||
|
|
||||||
## send_cmd BeoRemote One Source Select to mlgw
|
# send_cmd BeoRemote One Source Select to mlgw
|
||||||
def send_beoremoteone_select_source(self, mln, cmd, unit, network_bit=0x00):
|
def send_beoremoteone_select_source(self, mln, cmd, unit, network_bit=0x00):
|
||||||
payload = []
|
payload = [
|
||||||
payload.append(mln) # byte[0] MLN
|
mln, # byte[0] MLN
|
||||||
payload.append(cmd) # byte[1] Beormyone Command
|
cmd, # byte[1] Beoremote One Command self.BEORMT1_CMD.get('cmd')[0]
|
||||||
payload.append(unit) # byte[2] Unit
|
unit, # byte[2] Unit self.BEORMT1_CMD.get('cmd')[1]
|
||||||
payload.append(0x00) # byte[3] AV (needs to be 0)
|
0x00, # byte[3] AV (needs to be 0)
|
||||||
payload.append(network_bit) # byte[4] Network_bit (0 = local source, 1 = network source)
|
network_bit] # byte[4] Network_bit (0 = local source, 1 = network source)
|
||||||
self._send_cmd(const.MLGW_PL.get("BEOREMOTE ONE SOURCE SELECTION"), payload)
|
self._send_cmd(CONST.MLGW_PL.get("BEOREMOTE ONE SOURCE SELECTION"), payload)
|
||||||
|
|
||||||
## send_cmd Beo4 commmand and store the source name
|
# send_cmd Beo4 commmand and store the source name
|
||||||
def send_beo4_select_source(self, mln, dest, source, sec_source=0x00, link=0x00):
|
def send_beo4_select_source(self, mln, dest, source, sec_source=0x00, link=0x00):
|
||||||
beolink_source = self._dictsanitize(const.beo4_commanddict, source).upper()
|
|
||||||
self.send_beo4_cmd(mln, dest, source, sec_source, link)
|
self.send_beo4_cmd(mln, dest, source, sec_source, link)
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### Utility functions
|
# ##### Utility functions
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def _hexbyte(self, byte):
|
def _hexbyte(byte):
|
||||||
resultstr = hex(byte)
|
resultstr = hex(byte)
|
||||||
if byte < 16:
|
if byte < 16:
|
||||||
resultstr = resultstr[:2] + "0" + resultstr[2]
|
resultstr = resultstr[:2] + "0" + resultstr[2]
|
||||||
|
@ -312,51 +326,66 @@ class MLGWClient(asynchat.async_chat):
|
||||||
|
|
||||||
def _dictsanitize(self, d, s):
|
def _dictsanitize(self, d, s):
|
||||||
result = d.get(s)
|
result = d.get(s)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = "UNKNOWN (type=" + self._hexbyte(s) + ")"
|
result = "UNKNOWN (type=" + self._hexbyte(s) + ")"
|
||||||
return str(result)
|
return str(result)
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### Decode MLGW Protocol packet to readable string
|
# ##### Decode MLGW Protocol packet to readable string
|
||||||
|
|
||||||
## Get message string for mlgw packet's payload type
|
# Get message string for mlgw packet's payload type
|
||||||
#
|
|
||||||
def _getpayloadtypestr(self, payloadtype):
|
def _getpayloadtypestr(self, payloadtype):
|
||||||
result = const._mlgw_payloadtypedict.get(payloadtype)
|
result = CONST.mlgw_payloadtypedict.get(payloadtype)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = "UNKNOWN (type=" + self._hexbyte(payloadtype) + ")"
|
result = "UNKNOWN (type=" + self._hexbyte(payloadtype) + ")"
|
||||||
return str(result)
|
return str(result)
|
||||||
|
|
||||||
def _getmlnstr(self, mln):
|
|
||||||
result = "MLN=" + str(mln)
|
|
||||||
return result
|
|
||||||
|
|
||||||
def _getbeo4commandstr(self, command):
|
def _getbeo4commandstr(self, command):
|
||||||
result = const.beo4_commanddict.get(command)
|
result = CONST.beo4_commanddict.get(command)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = "Cmd=" + self._hexbyte(command)
|
result = "Cmd=" + self._hexbyte(command)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _getvirtualactionstr(self, action):
|
def _getvirtualactionstr(self, action):
|
||||||
result = const._mlgw_virtualactiondict.get(action)
|
result = CONST.mlgw_virtualactiondict.get(action)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = "Action=" + self._hexbyte(action)
|
result = "Action=" + self._hexbyte(action)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _getselectedsourcestr(self, source):
|
def _getselectedsourcestr(self, source):
|
||||||
result = const.ml_selectedsourcedict.get(source)
|
result = CONST.ml_selectedsourcedict.get(source)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = "Src=" + self._hexbyte(source)
|
result = "Src=" + self._hexbyte(source)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _getspeakermodestr(self, source):
|
def _getspeakermodestr(self, source):
|
||||||
result = const._mlgw_speakermodedict.get(source)
|
result = CONST.mlgw_speakermodedict.get(source)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = "mode=" + self._hexbyte(source)
|
result = "mode=" + self._hexbyte(source)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _getdictstr(self, mydict, mykey):
|
def _getdictstr(self, mydict, mykey):
|
||||||
result = mydict.get(mykey)
|
result = mydict.get(mykey)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = self._hexbyte(mykey)
|
result = self._hexbyte(mykey)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_source_name(source, message):
|
||||||
|
if CONST.available_sources:
|
||||||
|
for src in CONST.available_sources:
|
||||||
|
if src[1] == source:
|
||||||
|
message["State_Update"]["sourceName"] = src[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_channel_track(message):
|
||||||
|
# Check device list for channel name information
|
||||||
|
if CONST.devices:
|
||||||
|
for device in CONST.devices:
|
||||||
|
if device['Device'] == message['Device']:
|
||||||
|
if 'channels' in device['Sources'][message["State_Update"]["source"]]:
|
||||||
|
for channel in device['Sources'][message["State_Update"]["source"]]['channels']:
|
||||||
|
if channel['number'] == int(message["State_Update"]['nowPlayingDetails']["channel_track"]):
|
||||||
|
message["State_Update"]["nowPlaying"] = channel['name']
|
||||||
|
break
|
||||||
|
|
|
@ -5,7 +5,8 @@ import time
|
||||||
import json
|
import json
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import Resources.CONSTANTS as const
|
import Resources.CONSTANTS as CONST
|
||||||
|
|
||||||
|
|
||||||
class MLtnClient(asynchat.async_chat):
|
class MLtnClient(asynchat.async_chat):
|
||||||
"""Client to monitor network activity on a Masterlink Gateway via the telnet monitor"""
|
"""Client to monitor network activity on a Masterlink Gateway via the telnet monitor"""
|
||||||
|
@ -74,10 +75,9 @@ class MLtnClient(asynchat.async_chat):
|
||||||
self.last_received_at = 0
|
self.last_received_at = 0
|
||||||
|
|
||||||
def _decode(self, items):
|
def _decode(self, items):
|
||||||
time_stamp = ''.join([items[1],' at ',items[0]])
|
|
||||||
header = items[3][:-1]
|
header = items[3][:-1]
|
||||||
telegramStarts = len(''.join(items[:4])) + 4
|
telegram_starts = len(''.join(items[:4])) + 4
|
||||||
telegram = self._received_data[telegramStarts:].replace('!','').split('/')
|
telegram = self._received_data[telegram_starts:].replace('!', '').split('/')
|
||||||
message = OrderedDict()
|
message = OrderedDict()
|
||||||
|
|
||||||
if header == 'integration_protocol':
|
if header == 'integration_protocol':
|
||||||
|
@ -125,22 +125,23 @@ class MLtnClient(asynchat.async_chat):
|
||||||
message['Payload']['to_MLN'] = int(s[k], base=16)
|
message['Payload']['to_MLN'] = int(s[k], base=16)
|
||||||
if k == 11:
|
if k == 11:
|
||||||
message['Payload']['Destination'] = self._dictsanitize(
|
message['Payload']['Destination'] = self._dictsanitize(
|
||||||
const._mlgw_payloaddestdict, int(s[k], base=16))
|
CONST.destselectordict, int(s[k], base=16))
|
||||||
if k == 12:
|
if k == 12:
|
||||||
message['Payload']['Command'] = self._dictsanitize(
|
message['Payload']['Command'] = self._dictsanitize(
|
||||||
const.beo4_commanddict, int(s[k], base=16)).upper()
|
CONST.beo4_commanddict, int(s[k], base=16)).upper()
|
||||||
if k == 13:
|
if k == 13:
|
||||||
message['Payload']['Sec-Source'] = self._dictsanitize(
|
message['Payload']['Sec-Source'] = self._dictsanitize(
|
||||||
const._mlgw_secsourcedict, int(s[k], base=16))
|
CONST.mlgw_secsourcedict, int(s[k], base=16))
|
||||||
if k == 14:
|
if k == 14:
|
||||||
message['Payload']['Link'] = self._dictsanitize(
|
message['Payload']['Link'] = self._dictsanitize(
|
||||||
const._mlgw_linkdict, int(s[k], base=16))
|
CONST.mlgw_linkdict, int(s[k], base=16))
|
||||||
if k > 14:
|
if k > 14:
|
||||||
message['Payload']['cmd' + str(k - 9)] = self._dictsanitize(
|
message['Payload']['cmd' + str(k - 9)] = self._dictsanitize(
|
||||||
const.beo4_commanddict, int(s[k], base=16))
|
CONST.beo4_commanddict, int(s[k], base=16))
|
||||||
return message
|
return message
|
||||||
|
|
||||||
def _decode_action(self, telegram, message):
|
@staticmethod
|
||||||
|
def _decode_action(telegram, message):
|
||||||
message['Zone'] = telegram[0].upper()
|
message['Zone'] = telegram[0].upper()
|
||||||
message['Room'] = telegram[1].upper()
|
message['Room'] = telegram[1].upper()
|
||||||
message['Type'] = telegram[2].upper()
|
message['Type'] = telegram[2].upper()
|
||||||
|
@ -167,7 +168,8 @@ class MLtnClient(asynchat.async_chat):
|
||||||
message['State_Update']['STATE'] = telegram[4]
|
message['State_Update']['STATE'] = telegram[4]
|
||||||
return message
|
return message
|
||||||
|
|
||||||
def _decode_command(self, telegram, message):
|
@staticmethod
|
||||||
|
def _decode_command(telegram, message):
|
||||||
message['Zone'] = telegram[0].upper()
|
message['Zone'] = telegram[0].upper()
|
||||||
message['Room'] = telegram[1].upper()
|
message['Room'] = telegram[1].upper()
|
||||||
message['Type'] = telegram[2].upper()
|
message['Type'] = telegram[2].upper()
|
||||||
|
@ -228,7 +230,7 @@ class MLtnClient(asynchat.async_chat):
|
||||||
for s in state:
|
for s in state:
|
||||||
message['State_Update'][s.split('=')[0].lower()] = s.split('=')[1].title()
|
message['State_Update'][s.split('=')[0].lower()] = s.split('=')[1].title()
|
||||||
if message['State_Update'].get('command') == ' Cmd':
|
if message['State_Update'].get('command') == ' Cmd':
|
||||||
message['State_Update']['command'] = self._dictsanitize(const.beo4_commanddict,
|
message['State_Update']['command'] = self._dictsanitize(CONST.beo4_commanddict,
|
||||||
int(s[13:].strip())).title()
|
int(s[13:].strip())).title()
|
||||||
elif telegram[4][:7] == 'Control':
|
elif telegram[4][:7] == 'Control':
|
||||||
state = telegram[4][6:].split('&')
|
state = telegram[4][6:].split('&')
|
||||||
|
@ -236,7 +238,7 @@ class MLtnClient(asynchat.async_chat):
|
||||||
for s in state:
|
for s in state:
|
||||||
message['State_Update'][s.split('=')[0].lower()] = s.split('=')[1]
|
message['State_Update'][s.split('=')[0].lower()] = s.split('=')[1]
|
||||||
if message['State_Update'].get('command') == ' cmd':
|
if message['State_Update'].get('command') == ' cmd':
|
||||||
message['State_Update']['command'] = self._dictsanitize(const.beo4_commanddict,
|
message['State_Update']['command'] = self._dictsanitize(CONST.beo4_commanddict,
|
||||||
int(s[13:].strip())).title()
|
int(s[13:].strip())).title()
|
||||||
elif telegram[4] == 'All standby':
|
elif telegram[4] == 'All standby':
|
||||||
message['State_Update']['command'] = telegram[4]
|
message['State_Update']['command'] = telegram[4]
|
||||||
|
@ -246,7 +248,7 @@ class MLtnClient(asynchat.async_chat):
|
||||||
for s in state:
|
for s in state:
|
||||||
if s.split('=')[0] == 'sourceUniqueId':
|
if s.split('=')[0] == 'sourceUniqueId':
|
||||||
src = s.split('=')[1].split(':')[0].upper()
|
src = s.split('=')[1].split(':')[0].upper()
|
||||||
message['State_Update']['source'] = self._srcdictsanitize(const._blgw_srcdict, src)
|
message['State_Update']['source'] = self._srcdictsanitize(CONST.blgw_srcdict, src)
|
||||||
message['State_Update'][s.split('=')[0]] = s.split('=')[1]
|
message['State_Update'][s.split('=')[0]] = s.split('=')[1]
|
||||||
elif s.split('=')[0] == 'nowPlayingDetails':
|
elif s.split('=')[0] == 'nowPlayingDetails':
|
||||||
message['State_Update']['nowPlayingDetails'] = OrderedDict()
|
message['State_Update']['nowPlayingDetails'] = OrderedDict()
|
||||||
|
@ -274,7 +276,6 @@ class MLtnClient(asynchat.async_chat):
|
||||||
self.set_terminator(b'\r\n')
|
self.set_terminator(b'\r\n')
|
||||||
# Create the socket
|
# Create the socket
|
||||||
try:
|
try:
|
||||||
socket.setdefaulttimeout(3)
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
self.log.info("Error creating socket: %s" % e)
|
self.log.info("Error creating socket: %s" % e)
|
||||||
|
@ -285,12 +286,12 @@ class MLtnClient(asynchat.async_chat):
|
||||||
except socket.gaierror, e:
|
except socket.gaierror, e:
|
||||||
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
self.log.info("\tError with address %s:%i - %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
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()
|
|
||||||
except socket.timeout, e:
|
except socket.timeout, e:
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
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:
|
else:
|
||||||
self.is_connected = True
|
self.is_connected = True
|
||||||
self.log.info("\tConnected to B&O Gateway")
|
self.log.info("\tConnected to B&O Gateway")
|
||||||
|
@ -308,25 +309,25 @@ class MLtnClient(asynchat.async_chat):
|
||||||
def _send_cmd(self, telegram):
|
def _send_cmd(self, telegram):
|
||||||
try:
|
try:
|
||||||
self.push(telegram + "\r\n")
|
self.push(telegram + "\r\n")
|
||||||
except socket.error, e:
|
|
||||||
self.log.info("Error sending data: %s" % e)
|
|
||||||
self.handle_close()
|
|
||||||
except socket.timeout, e:
|
except socket.timeout, e:
|
||||||
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
self.log.info("\tSocket connection to %s:%i timed out- %s" % (self._host, self._port, e))
|
||||||
self.handle_close()
|
self.handle_close()
|
||||||
|
except socket.error, e:
|
||||||
|
self.log.info("Error sending data: %s" % e)
|
||||||
|
self.handle_close()
|
||||||
else:
|
else:
|
||||||
self.last_sent = telegram
|
self.last_sent = telegram
|
||||||
self.last_sent_at = time.time()
|
self.last_sent_at = time.time()
|
||||||
self.log.info(self.name + " >>-SENT--> : " + telegram)
|
self.log.info(self.name + " >>-SENT--> : " + telegram)
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
|
|
||||||
def toggleEvents(self):
|
def toggle_events(self):
|
||||||
self._send_cmd('e')
|
self._send_cmd('e')
|
||||||
|
|
||||||
def toggleMacros(self):
|
def toggle_macros(self):
|
||||||
self._send_cmd('m')
|
self._send_cmd('m')
|
||||||
|
|
||||||
def toggleCommands(self):
|
def toggle_commands(self):
|
||||||
self._send_cmd('c')
|
self._send_cmd('c')
|
||||||
|
|
||||||
def ping(self):
|
def ping(self):
|
||||||
|
@ -334,7 +335,8 @@ class MLtnClient(asynchat.async_chat):
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### Utility functions
|
# ##### Utility functions
|
||||||
def _hexbyte(self, byte):
|
@staticmethod
|
||||||
|
def _hexbyte(byte):
|
||||||
resultstr = hex(byte)
|
resultstr = hex(byte)
|
||||||
if byte < 16:
|
if byte < 16:
|
||||||
resultstr = resultstr[:2] + "0" + resultstr[2]
|
resultstr = resultstr[:2] + "0" + resultstr[2]
|
||||||
|
@ -342,12 +344,13 @@ class MLtnClient(asynchat.async_chat):
|
||||||
|
|
||||||
def _dictsanitize(self, d, s):
|
def _dictsanitize(self, d, s):
|
||||||
result = d.get(s)
|
result = d.get(s)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = "UNKNOWN (type=" + self._hexbyte(s) + ")"
|
result = "UNKNOWN (type=" + self._hexbyte(s) + ")"
|
||||||
return str(result)
|
return str(result)
|
||||||
|
|
||||||
def _srcdictsanitize(self, d, s):
|
@staticmethod
|
||||||
|
def _srcdictsanitize(d, s):
|
||||||
result = d.get(s)
|
result = d.get(s)
|
||||||
if result == None:
|
if result is None:
|
||||||
result = s
|
result = s
|
||||||
return str(result)
|
return str(result)
|
1
Resources/__init__.py
Normal file
1
Resources/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# init
|
Loading…
Reference in a new issue