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
7d7fcc9f5e
commit
4688f11252
7 changed files with 366 additions and 112 deletions
111
Resources/ASBridge.py
Normal file
111
Resources/ASBridge.py
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
import os
|
||||||
|
from Foundation import NSAppleScript
|
||||||
|
from ScriptingBridge import SBApplication
|
||||||
|
|
||||||
|
''' Module defining a MusicController class for Apple Music, enables:
|
||||||
|
basic transport control of the player,
|
||||||
|
query of player status,
|
||||||
|
playing existing playlists, and
|
||||||
|
running external appleScripts for more complex control
|
||||||
|
reporting messages in the notification centre'''
|
||||||
|
|
||||||
|
PLAYSTATE = dict([
|
||||||
|
(1800426320, "Play"),
|
||||||
|
(1800426352, "Pause"),
|
||||||
|
(1800426323, "Stop"),
|
||||||
|
(1800426310, "Wind"),
|
||||||
|
(1800426322, "Rewind")
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
class MusicController(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.app = SBApplication.applicationWithBundleIdentifier_("com.apple.Music")
|
||||||
|
|
||||||
|
# Player information
|
||||||
|
def get_current_track_info(self):
|
||||||
|
name = str(self.app.currentTrack().name())
|
||||||
|
album = str(self.app.currentTrack().album())
|
||||||
|
artist = str(self.app.currentTrack().artist())
|
||||||
|
return [name, album, artist]
|
||||||
|
|
||||||
|
def get_current_play_state(self):
|
||||||
|
return PLAYSTATE.get(self.app.playerState())
|
||||||
|
|
||||||
|
def get_current_track_position(self):
|
||||||
|
return self.app.playerPosition()
|
||||||
|
|
||||||
|
# ########################################################################################
|
||||||
|
# Transport Controls
|
||||||
|
def playpause(self):
|
||||||
|
self.app.playpause()
|
||||||
|
|
||||||
|
def play(self):
|
||||||
|
if PLAYSTATE.get(self.app.playerState()) in ['Wind', 'Rewind']:
|
||||||
|
self.app.resume()
|
||||||
|
elif PLAYSTATE.get(self.app.playerState()) == 'Pause':
|
||||||
|
self.app.playpause()
|
||||||
|
elif PLAYSTATE.get(self.app.playerState()) == 'Stop':
|
||||||
|
playlist = self.app.sources().objectWithName_("Library")
|
||||||
|
playlist.playOnce_(None)
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
if PLAYSTATE.get(self.app.playerState()) == 'Play':
|
||||||
|
self.app.pause()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
if PLAYSTATE.get(self.app.playerState()) != 'Stop':
|
||||||
|
self.app.stop()
|
||||||
|
|
||||||
|
def next_track(self):
|
||||||
|
self.app.nextTrack()
|
||||||
|
|
||||||
|
def previous_track(self):
|
||||||
|
self.app.previousTrack()
|
||||||
|
|
||||||
|
def wind(self, time):
|
||||||
|
# Native wind function can be a bit annoying
|
||||||
|
# I provide an alternative below that skips a set number of seconds forwards
|
||||||
|
# self.app.wind()
|
||||||
|
self.set_current_track_position(time)
|
||||||
|
|
||||||
|
def rewind(self, time):
|
||||||
|
# Native rewind function can be a bit annoying
|
||||||
|
# I provide an alternative below that skips a set number of seconds back
|
||||||
|
# self.app.rewind()
|
||||||
|
self.set_current_track_position(time)
|
||||||
|
|
||||||
|
# ########################################################################################
|
||||||
|
# More complex playback control functions
|
||||||
|
def set_current_track_position(self, time, mode='Relative'):
|
||||||
|
if mode == 'Relative':
|
||||||
|
# Set playback position in seconds relative to current position
|
||||||
|
self.app.setPlayerPosition_(self.app.playerPosition() + time)
|
||||||
|
elif mode == 'Absolute':
|
||||||
|
# Set playback position in seconds from the start of the track
|
||||||
|
self.app.setPlayerPosition_(time)
|
||||||
|
|
||||||
|
def play_playlist(self, playlist):
|
||||||
|
self.app.stop()
|
||||||
|
playlist = self.app.sources().objectWithName_("Library").playlists().objectWithName_(playlist)
|
||||||
|
playlist.playOnce_(None)
|
||||||
|
|
||||||
|
# ########################################################################################
|
||||||
|
# Accessory functions
|
||||||
|
@staticmethod
|
||||||
|
def run_script(script):
|
||||||
|
# Run an external applescript file
|
||||||
|
script = 'run script ("' + script + '" as POSIX file)'
|
||||||
|
s = NSAppleScript.alloc().initWithSource_(script)
|
||||||
|
s.executeAndReturnError_(None)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def notify(message):
|
||||||
|
# Post message in notification center
|
||||||
|
path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
script = 'tell application "' + path + '/Notify.app" to notify("BeoGateway", "' + \
|
||||||
|
message + '")'
|
||||||
|
s = NSAppleScript.alloc().initWithSource_(script)
|
||||||
|
s.executeAndReturnError_(None)
|
|
@ -173,7 +173,7 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
self.log.info("\tAttempting to Authenticate...")
|
self.log.info("\tAttempting to Authenticate...")
|
||||||
self.send_cmd(self._user)
|
self.send_cmd(self._user)
|
||||||
self.send_cmd(self._pwd)
|
self.send_cmd(self._pwd)
|
||||||
self.statefiler()
|
self.statefilter()
|
||||||
|
|
||||||
def handle_close(self):
|
def handle_close(self):
|
||||||
self.log.info(self.name + ": Closing socket")
|
self.log.info(self.name + ": Closing socket")
|
||||||
|
@ -219,7 +219,7 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
self.log.info(self.name + ": sending state update request for" + device + dev_type + room + zone)
|
self.log.info(self.name + ": sending state update request for" + device + dev_type + room + zone)
|
||||||
self.send_cmd(query)
|
self.send_cmd(query)
|
||||||
|
|
||||||
def statefiler(self, zone='*', room='*', dev_type='*', device='*'):
|
def statefilter(self, zone='*', room='*', dev_type='*', device='*'):
|
||||||
s_filter = "f " + zone + "/" + room + "/" + dev_type + '/' + device
|
s_filter = "f " + zone + "/" + room + "/" + dev_type + '/' + device
|
||||||
self.send_cmd(s_filter)
|
self.send_cmd(s_filter)
|
||||||
|
|
||||||
|
@ -241,12 +241,16 @@ class BLHIPClient(asynchat.async_chat):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_channel_track(message):
|
def _get_channel_track(message):
|
||||||
|
try:
|
||||||
# Check device list for channel name information
|
# Check device list for channel name information
|
||||||
if CONST.devices:
|
if CONST.devices:
|
||||||
for device in CONST.devices:
|
for device in CONST.devices:
|
||||||
if device['Device'] == message['Device']:
|
if device['Device'] == message['Device']:
|
||||||
if 'channels' in device['Sources'][message["State_Update"]["source"]]:
|
if 'channels' in device['Sources'][message["State_Update"]["source"]]:
|
||||||
for channel in device['Sources'][message["State_Update"]["source"]]['channels']:
|
for channel in device['Sources'][message["State_Update"]["source"]]['channels']:
|
||||||
if channel['number'] == int(message["State_Update"]['nowPlayingDetails']["channel_track"]):
|
if channel['number'] == int(
|
||||||
|
message["State_Update"]['nowPlayingDetails']["channel_track"]):
|
||||||
message["State_Update"]["nowPlaying"] = channel['name']
|
message["State_Update"]["nowPlaying"] = channel['name']
|
||||||
break
|
break
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
|
@ -1,11 +1,31 @@
|
||||||
# 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([("Current Audio Source", ''), ("Current Video Source", '')])
|
||||||
rooms = []
|
rooms = []
|
||||||
devices = []
|
devices = []
|
||||||
available_sources = []
|
available_sources = []
|
||||||
|
|
||||||
|
# ########################################################################################
|
||||||
|
# Source Types
|
||||||
|
|
||||||
|
source_type_dict = dict(
|
||||||
|
[
|
||||||
|
("Video Sources", ("TV", "V.AUX/DTV2", "MEDIA", "V.TAPE/V.MEM/DVD2", "DVD", "CAMERA",
|
||||||
|
"SAT/DTV", "PC", "WEB", "DOORCAM", "PHOTO", "USB2", "WEBMEDIA", "AV.IN",
|
||||||
|
"HOMEMEDIA", "DNLA", "RECORDINGS", "CAMERA", "USB", "DNLA-DMR", "YOUTUBE",
|
||||||
|
"HOME.APP", "HDMI_1", "HDMI_2", "HDMI_3", "HDMI_4", "HDMI_5", "HDMI_6",
|
||||||
|
"HDMI_7", "HDMI_8", "MATRIX_1", "MATRIX_2", "MATRIX_3", "MATRIX_4", "MATRIX_5",
|
||||||
|
"MATRIX_6", "MATRIX_7", "MATRIX_8", "MATRIX_9", "MATRIX_10", "MATRIX_11",
|
||||||
|
"MATRIX_12", "MATRIX_13", "MATRIX_14", "MATRIX_15", "MATRIX_16", "PERSONAL_1",
|
||||||
|
"PERSONAL_2", "PERSONAL_3", "PERSONAL_4", "PERSONAL_5", "PERSONAL_6", "PERSONAL_7",
|
||||||
|
"PERSONAL_8")),
|
||||||
|
("Audio Sources", ("RADIO", "A.AUX", "A.TAPE/A.MEM", "CD", "PHONO/N.RADIO", "A.TAPE2/N.MUSIC",
|
||||||
|
"SERVER", "SPOTIFY", "CD2/JOIN", "TUNEIN", "DVB_RADIO", "LINE.IN", "BLUETOOTH",
|
||||||
|
"MUSIC", "AIRPLAY", "SPOTIFY", "DEEZER", "QPLAY"))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# Beo4 Commands
|
# Beo4 Commands
|
||||||
beo4_commanddict = dict(
|
beo4_commanddict = dict(
|
||||||
|
@ -18,7 +38,7 @@ beo4_commanddict = dict(
|
||||||
(0x82, "V.Aux/DTV2"),
|
(0x82, "V.Aux/DTV2"),
|
||||||
(0x83, "A.Aux"),
|
(0x83, "A.Aux"),
|
||||||
(0x84, "Media"),
|
(0x84, "Media"),
|
||||||
(0x85, "V.Tape/V.Mem/DVD2"),
|
(0x85, "V.Tape/V.Mem"),
|
||||||
(0x86, "DVD"),
|
(0x86, "DVD"),
|
||||||
(0x87, "Camera"),
|
(0x87, "Camera"),
|
||||||
(0x88, "Text"),
|
(0x88, "Text"),
|
||||||
|
@ -350,9 +370,9 @@ ml_selectedsourcedict = dict(
|
||||||
(0x0B, "TV"),
|
(0x0B, "TV"),
|
||||||
(0x15, "V.TAPE/V.MEM"),
|
(0x15, "V.TAPE/V.MEM"),
|
||||||
(0x16, "DVD2"),
|
(0x16, "DVD2"),
|
||||||
(0x1F, "DTV"),
|
(0x1F, "SAT/DTV"),
|
||||||
(0x29, "DVD"),
|
(0x29, "DVD"),
|
||||||
(0x33, "V.AUX"),
|
(0x33, "V.AUX/DTV2"),
|
||||||
(0x3E, "DOORCAM"),
|
(0x3E, "DOORCAM"),
|
||||||
(0x47, "PC"),
|
(0x47, "PC"),
|
||||||
(0x6F, "RADIO"),
|
(0x6F, "RADIO"),
|
||||||
|
@ -369,6 +389,8 @@ 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_sourcekind_dict = dict([(0x01, "audio source"), (0x02, "video source"), (0xFF, "undefined")])
|
||||||
|
|
||||||
ml_selectedsource_type_dict = dict(
|
ml_selectedsource_type_dict = dict(
|
||||||
[
|
[
|
||||||
("VIDEO", (0x0B, 0x1F)),
|
("VIDEO", (0x0B, 0x1F)),
|
||||||
|
|
|
@ -84,7 +84,7 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
for item in items:
|
for item in items:
|
||||||
try:
|
try:
|
||||||
telegram.append(int(item[:-1], base=16))
|
telegram.append(int(item[:-1], base=16))
|
||||||
except TypeError:
|
except (ValueError, TypeError):
|
||||||
# abort if invalid character found
|
# abort if invalid character found
|
||||||
self.log.debug('Invalid character ' + str(item) + ' found in telegram: ' +
|
self.log.debug('Invalid character ' + str(item) + ' found in telegram: ' +
|
||||||
''.join(items) + '\nAborting!')
|
''.join(items) + '\nAborting!')
|
||||||
|
@ -192,37 +192,35 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
def _decode(self, telegram):
|
def _decode(self, telegram):
|
||||||
# Decode header
|
# Decode header
|
||||||
message = OrderedDict()
|
message = OrderedDict()
|
||||||
if CONST.devices:
|
self._get_device_info(message, telegram)
|
||||||
for device in CONST.devices:
|
message["from_device"] = self._get_device_name(self._dictsanitize(CONST.ml_device_dict, telegram[1]))
|
||||||
if device['ML_ID'] == telegram[1]:
|
|
||||||
message["Zone"] = device["Zone"].upper()
|
|
||||||
message["Room"] = device["Room"].uppr()
|
|
||||||
message["Type"] = "AV RENDERER"
|
|
||||||
message["Device"] = device["Device"]
|
|
||||||
break
|
|
||||||
message["from_device"] = self._dictsanitize(CONST.ml_device_dict, telegram[1])
|
|
||||||
message["from_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[5])
|
message["from_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[5])
|
||||||
message["to_device"] = self._dictsanitize(CONST.ml_device_dict, telegram[0])
|
message["to_device"] = self._get_device_name(self._dictsanitize(CONST.ml_device_dict, telegram[0]))
|
||||||
message["to_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[4])
|
message["to_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[4])
|
||||||
message["type"] = self._dictsanitize(CONST.ml_telegram_type_dict, telegram[3])
|
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_type"] = self._dictsanitize(CONST.ml_command_type_dict, telegram[7])
|
||||||
message["payload_len"] = telegram[8] + 1
|
message["payload_len"] = telegram[8] + 1
|
||||||
message["State_Update"] = OrderedDict()
|
message["State_Update"] = OrderedDict()
|
||||||
|
|
||||||
|
# RELEASE command signifies product standby
|
||||||
|
if message.get("payload_type") in ["RELEASE", "STANDBY"]:
|
||||||
|
message["State_Update"]["state"] = 'Standby'
|
||||||
|
|
||||||
# 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["State_Update"]["nowPlaying"] = ''
|
message["State_Update"]["nowPlaying"] = 'Unknown'
|
||||||
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["State_Update"]["nowPlayingDetails"]["local_source"] = telegram[13]
|
message["State_Update"]["nowPlayingDetails"]["local_source"] = telegram[13]
|
||||||
message["State_Update"]["nowPlayingDetails"]["type"] = telegram[22]
|
message["State_Update"]["nowPlayingDetails"]["type"] = \
|
||||||
|
self._dictsanitize(CONST.ml_sourcekind_dict, telegram[22])
|
||||||
if telegram[8] < 27:
|
if telegram[8] < 27:
|
||||||
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[19]
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[19]
|
||||||
else:
|
else:
|
||||||
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[36] * 256 + telegram[37]
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = telegram[36] * 256 + telegram[37]
|
||||||
message["State_Update"]["nowPlayingDetails"]["source_medium_position"] = \
|
message["State_Update"]["nowPlayingDetails"]["source_medium_position"] = \
|
||||||
self._hexword(telegram[18], telegram[17])
|
self._hexword(telegram[18], telegram[17])
|
||||||
message["State_Update"]["nowPlayingDetails"]["picture_identifier"] = \
|
message["State_Update"]["nowPlayingDetails"]["picture_format"] = \
|
||||||
self._dictsanitize(CONST.ml_pictureformatdict, telegram[23])
|
self._dictsanitize(CONST.ml_pictureformatdict, telegram[23])
|
||||||
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[10])
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[10])
|
||||||
self._get_source_name(source, message)
|
self._get_source_name(source, message)
|
||||||
|
@ -257,7 +255,7 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
|
|
||||||
# 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["State_Update"]["nowPlaying"] = ''
|
message["State_Update"]["nowPlaying"] = 'Unknown'
|
||||||
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["State_Update"]["nowPlayingDetails"]["type"] = \
|
message["State_Update"]["nowPlayingDetails"]["type"] = \
|
||||||
self._get_type(CONST.ml_selectedsource_type_dict, telegram[11])
|
self._get_type(CONST.ml_selectedsource_type_dict, telegram[11])
|
||||||
|
@ -271,7 +269,7 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
|
|
||||||
# video track info
|
# video track info
|
||||||
if message.get("payload_type") == "VIDEO_TRACK_INFO":
|
if message.get("payload_type") == "VIDEO_TRACK_INFO":
|
||||||
message["State_Update"]["nowPlaying"] = ''
|
message["State_Update"]["nowPlaying"] = 'Unknown'
|
||||||
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["State_Update"]["nowPlayingDetails"]["source_type"] = \
|
message["State_Update"]["nowPlayingDetails"]["source_type"] = \
|
||||||
self._get_type(CONST.ml_selectedsource_type_dict, telegram[13])
|
self._get_type(CONST.ml_selectedsource_type_dict, telegram[13])
|
||||||
|
@ -286,6 +284,8 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
# track change info
|
# track change info
|
||||||
if message.get("payload_type") == "TRACK_INFO":
|
if message.get("payload_type") == "TRACK_INFO":
|
||||||
message["State_Update"]["subtype"] = self._dictsanitize(CONST.ml_trackinfo_subtype_dict, telegram[9])
|
message["State_Update"]["subtype"] = self._dictsanitize(CONST.ml_trackinfo_subtype_dict, telegram[9])
|
||||||
|
|
||||||
|
# Change source
|
||||||
if message["State_Update"].get("subtype") == "Change Source":
|
if message["State_Update"].get("subtype") == "Change Source":
|
||||||
message["State_Update"]["prev_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
message["State_Update"]["prev_source"] = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
||||||
message["State_Update"]["prev_sourceID"] = telegram[11]
|
message["State_Update"]["prev_sourceID"] = telegram[11]
|
||||||
|
@ -297,6 +297,7 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
message["State_Update"]["source"] = source
|
message["State_Update"]["source"] = source
|
||||||
message["State_Update"]["sourceID"] = telegram[22]
|
message["State_Update"]["sourceID"] = telegram[22]
|
||||||
|
|
||||||
|
# Current Source
|
||||||
if message["State_Update"].get("subtype") == "Current Source":
|
if message["State_Update"].get("subtype") == "Current Source":
|
||||||
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
source = self._dictsanitize(CONST.ml_selectedsourcedict, telegram[11])
|
||||||
self._get_source_name(source, message)
|
self._get_source_name(source, message)
|
||||||
|
@ -308,7 +309,7 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
|
|
||||||
# goto source
|
# goto source
|
||||||
if message.get("payload_type") == "GOTO_SOURCE":
|
if message.get("payload_type") == "GOTO_SOURCE":
|
||||||
message["State_Update"]["nowPlaying"] = ''
|
message["State_Update"]["nowPlaying"] = 'Unknown'
|
||||||
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["State_Update"]["nowPlayingDetails"]["source_type"] = \
|
message["State_Update"]["nowPlayingDetails"]["source_type"] = \
|
||||||
self._get_type(CONST.ml_selectedsource_type_dict, telegram[11])
|
self._get_type(CONST.ml_selectedsource_type_dict, telegram[11])
|
||||||
|
@ -374,6 +375,27 @@ class MLCLIClient(asynchat.async_chat):
|
||||||
message["State_Update"]["nowPlaying"] = channel['name']
|
message["State_Update"]["nowPlaying"] = channel['name']
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _get_device_info(self, message, telegram):
|
||||||
|
if CONST.devices:
|
||||||
|
for device in CONST.devices:
|
||||||
|
if device['ML_ID'] == self._dictsanitize(CONST.ml_device_dict, telegram[1]):
|
||||||
|
try:
|
||||||
|
message["Zone"] = device['Zone'].upper()
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
message["Room"] = device["Room"].upper()
|
||||||
|
message["Type"] = "AV RENDERER"
|
||||||
|
message["Device"] = device["Device"]
|
||||||
|
break
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_device_name(dev):
|
||||||
|
if CONST.devices:
|
||||||
|
for device in CONST.devices:
|
||||||
|
if device['ML_ID'] == dev:
|
||||||
|
return device['Device']
|
||||||
|
return dev
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_source_name(source, message):
|
def _get_source_name(source, message):
|
||||||
if CONST.available_sources:
|
if CONST.available_sources:
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
import requests
|
|
||||||
import asyncore
|
import asyncore
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
from requests.auth import HTTPDigestAuth, HTTPBasicAuth
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import Resources.CONSTANTS as CONST
|
import Resources.CONSTANTS as CONST
|
||||||
|
@ -20,48 +22,95 @@ class MLConfig:
|
||||||
self._download_data()
|
self._download_data()
|
||||||
|
|
||||||
def _download_data(self):
|
def _download_data(self):
|
||||||
|
try:
|
||||||
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)
|
# try Basic Auth next (this is needed for the BLGW)
|
||||||
response = requests.get(url, auth=auth)
|
response = requests.get(url, auth=HTTPBasicAuth(self._user, self._pwd))
|
||||||
|
|
||||||
|
if response.status_code == 401:
|
||||||
|
# try Digest Auth first (this is needed for the MLGW)
|
||||||
|
response = requests.get(url, auth=HTTPDigestAuth(self._user, self._pwd))
|
||||||
|
|
||||||
|
if response.status_code == 401:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# Once logged in successfully download and process the configuration data
|
||||||
configurationdata = json.loads(response.text)
|
configurationdata = json.loads(response.text)
|
||||||
|
self.log.debug(json.dumps(configurationdata, indent=4))
|
||||||
self.configure_mlgw(configurationdata)
|
self.configure_mlgw(configurationdata)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
def configure_mlgw(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']
|
||||||
|
try:
|
||||||
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'])
|
||||||
|
gateway_type = 'blgw'
|
||||||
|
except KeyError:
|
||||||
|
gateway_type = 'mlgw'
|
||||||
|
|
||||||
for zone in data["zones"]:
|
for zone in data["zones"]:
|
||||||
if int(zone['number']) == 240:
|
if int(zone['number']) == 240:
|
||||||
continue
|
continue
|
||||||
room = OrderedDict()
|
room = OrderedDict()
|
||||||
room['Room_Number'] = zone['number']
|
room['Room_Number'] = zone['number']
|
||||||
|
if gateway_type == 'blgw':
|
||||||
|
# BLGW arranges rooms within zones
|
||||||
room['Zone'] = str(zone['name']).split('/')[0]
|
room['Zone'] = str(zone['name']).split('/')[0]
|
||||||
room['Room_Name'] = str(zone['name']).split('/')[1]
|
room['Room_Name'] = str(zone['name']).split('/')[1]
|
||||||
|
elif gateway_type == 'mlgw':
|
||||||
|
# MLGW has no zoning concept - devices are arranged in rooms only
|
||||||
|
room['Room_Name'] = str(zone['name'])
|
||||||
|
|
||||||
room['Products'] = []
|
room['Products'] = []
|
||||||
|
|
||||||
for product in zone["products"]:
|
for product in zone["products"]:
|
||||||
device = OrderedDict()
|
device = OrderedDict()
|
||||||
room['Products'].append(str(product["name"]))
|
room['Products'].append(str(product["name"]))
|
||||||
|
# Device identification
|
||||||
device['Device'] = str(product["name"])
|
device['Device'] = str(product["name"])
|
||||||
device['MLN'] = product["MLN"]
|
device['MLN'] = product["MLN"]
|
||||||
device['ML_ID'] = ''
|
device['ML_ID'] = ''
|
||||||
|
try:
|
||||||
device['Serial_num'] = str(product["sn"])
|
device['Serial_num'] = str(product["sn"])
|
||||||
device['Zone'] = str(zone["name"]).split('/')[0]
|
except KeyError:
|
||||||
device['Room'] = str(zone["name"]).split('/')[1]
|
device['Serial_num'] = ''
|
||||||
|
|
||||||
|
# Physical location
|
||||||
|
if gateway_type == 'blgw':
|
||||||
|
# BLGW arranges rooms within zones
|
||||||
|
device['Zone'] = str(zone['name']).split('/')[0]
|
||||||
|
device['Room'] = str(zone['name']).split('/')[1]
|
||||||
|
elif gateway_type == 'mlgw':
|
||||||
|
# MLGW has no zoning concept - devices are arranged in rooms only
|
||||||
|
device['Room'] = str(zone['name'])
|
||||||
device['Room_Number'] = str(zone["number"])
|
device['Room_Number'] = str(zone["number"])
|
||||||
|
# Source logging parameters for managing notifications
|
||||||
device['Sources'] = OrderedDict()
|
device['Sources'] = OrderedDict()
|
||||||
|
device['Current Source'] = 'None'
|
||||||
|
device['Current Source Type'] = 'None'
|
||||||
|
device['Now Playing'] = 'None'
|
||||||
|
device['Channel/Track'] = '0'
|
||||||
|
device['State'] = 'Standby'
|
||||||
|
device['last update'] = time.time()
|
||||||
|
|
||||||
for source in product["sources"]:
|
for source in product["sources"]:
|
||||||
device['Sources'][str(source["name"])] = OrderedDict()
|
device['Sources'][str(source["name"])] = OrderedDict()
|
||||||
for selectCmd in source["selectCmds"]:
|
for selectCmd in source["selectCmds"]:
|
||||||
|
if gateway_type == 'blgw':
|
||||||
|
# get source information from the BLGW config file
|
||||||
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'])
|
||||||
|
else:
|
||||||
|
# MLGW config file is structured differently
|
||||||
|
source_id = self._srcdictsanitize(CONST.beo4_commanddict, source['selectID']).upper()
|
||||||
|
device['Sources'][str(source["name"])]['source'] = source_id
|
||||||
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
|
||||||
|
@ -70,7 +119,10 @@ class MLConfig:
|
||||||
for channel in source['channels']:
|
for channel in source['channels']:
|
||||||
c = OrderedDict()
|
c = OrderedDict()
|
||||||
c_num = ''
|
c_num = ''
|
||||||
|
if gateway_type == 'blgw':
|
||||||
num = channel['selectSEQ'][::2]
|
num = channel['selectSEQ'][::2]
|
||||||
|
else:
|
||||||
|
num = channel['selectSEQ'][:-1]
|
||||||
for n in num:
|
for n in num:
|
||||||
c_num += str(n)
|
c_num += str(n)
|
||||||
c['number'] = int(c_num)
|
c['number'] = int(c_num)
|
||||||
|
@ -98,7 +150,7 @@ class MLConfig:
|
||||||
|
|
||||||
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 and CONST.devices:
|
||||||
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
|
||||||
|
@ -106,23 +158,33 @@ class MLConfig:
|
||||||
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') in [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 'to_device' not in mlcli.last_message and mlcli.last_message['from_device'] == \
|
test = True
|
||||||
"MLGW" and mlcli.last_message['payload_type'] == \
|
while test:
|
||||||
"MLGW_REMOTE_BEO4" and mlcli.last_message['payload']['command'] == "LIGHT TIMEOUT":
|
try:
|
||||||
asyncore.loop(count=1, timeout=0.2)
|
if mlcli.last_message['from_device'] == "MLGW" and \
|
||||||
|
mlcli.last_message['payload_type'] == "MLGW_REMOTE_BEO4" and \
|
||||||
|
mlcli.last_message['State_Update']['command'] == "Light Timeout":
|
||||||
|
|
||||||
device['ML_ID'] = mlcli.last_message.get('to_device')
|
device['ML_ID'] = mlcli.last_message.get('to_device')
|
||||||
self.log.info("\tMasterLink ID of product " +
|
self.log.info("\tMasterLink ID of product " +
|
||||||
device.get('Device') + " is " + device.get('ML_ID') + ".\n")
|
device.get('Device') + " is " + device.get('ML_ID') + ".\n")
|
||||||
|
test = False
|
||||||
|
except KeyError:
|
||||||
|
asyncore.loop(count=1, timeout=0.2)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# If this is a NetLink product then it has a serial number and no ML_ID
|
# If this is a NetLink product then it has a serial number and no ML_ID
|
||||||
device['ML_ID'] = 'NA'
|
device['ML_ID'] = 'NA'
|
||||||
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")
|
||||||
|
|
||||||
|
self.log.debug(json.dumps(device, indent=4))
|
||||||
|
|
||||||
|
# ########################################################################################
|
||||||
|
# Utility Functions
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _srcdictsanitize(d, s):
|
def _srcdictsanitize(d, s):
|
||||||
result = d.get(s)
|
result = d.get(s)
|
||||||
|
|
|
@ -118,20 +118,11 @@ class MLGWClient(asynchat.async_chat):
|
||||||
message['serial_Num'] = sn
|
message['serial_Num'] = sn
|
||||||
|
|
||||||
elif payload_type == "Source Status":
|
elif payload_type == "Source Status":
|
||||||
if CONST.rooms and CONST.devices:
|
self._get_device_info(message, payload)
|
||||||
for device in CONST.devices:
|
|
||||||
if device['MLN'] == payload[0]:
|
|
||||||
name = device['Device']
|
|
||||||
for room in CONST.rooms:
|
|
||||||
if name in room['Products']:
|
|
||||||
message["Zone"] = room['Zone'].upper()
|
|
||||||
message["Room"] = room['Room_Name'].upper()
|
|
||||||
message["Type"] = 'AV RENDERER'
|
|
||||||
message["Device"] = name
|
|
||||||
message["payload_type"] = payload_type
|
message["payload_type"] = payload_type
|
||||||
message["MLN"] = payload[0]
|
message["MLN"] = payload[0]
|
||||||
message["State_Update"] = OrderedDict()
|
message["State_Update"] = OrderedDict()
|
||||||
message["State_Update"]["nowPlaying"] = ''
|
message["State_Update"]["nowPlaying"] = 'Unknown'
|
||||||
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
message["State_Update"]["nowPlayingDetails"] = OrderedDict()
|
||||||
message["State_Update"]["nowPlayingDetails"]["channel_track"] = \
|
message["State_Update"]["nowPlayingDetails"]["channel_track"] = \
|
||||||
self._hexword(payload[4], payload[5])
|
self._hexword(payload[4], payload[5])
|
||||||
|
@ -146,27 +137,26 @@ class MLGWClient(asynchat.async_chat):
|
||||||
message["State_Update"]["state"] = self._getdictstr(CONST.sourceactivitydict, payload[6])
|
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:
|
self._get_device_info(message, payload)
|
||||||
for device in CONST.devices:
|
|
||||||
if device['MLN'] == payload[0]:
|
|
||||||
name = device['Device']
|
|
||||||
for room in CONST.rooms:
|
|
||||||
if name in room['Products']:
|
|
||||||
message["Zone"] = room['Zone'].upper()
|
|
||||||
message["Room"] = room['Room_Name'].upper()
|
|
||||||
message["Type"] = 'AV RENDERER'
|
|
||||||
message["Device"] = name
|
|
||||||
message["payload_type"] = payload_type
|
message["payload_type"] = payload_type
|
||||||
message["MLN"] = payload[0]
|
message["MLN"] = payload[0]
|
||||||
message["State_Update"] = OrderedDict()
|
message["State_Update"] = OrderedDict([("sound_status", OrderedDict()), ("picture_status", OrderedDict())])
|
||||||
message["State_Update"]["sound_status"] = self._getdictstr(CONST.mlgw_soundstatusdict, payload[1])
|
message["State_Update"]["sound_status"]["mute_status"] = \
|
||||||
message["State_Update"]["speakermode"] = self._getdictstr(CONST.mlgw_speakermodedict, payload[2])
|
self._getdictstr(CONST.mlgw_soundstatusdict, payload[1])
|
||||||
message["State_Update"]["stereo_mode"] = self._getdictstr(CONST.mlgw_stereoindicatordict, payload[9])
|
message["State_Update"]["sound_status"]["speakermode"] = \
|
||||||
message["State_Update"]["screen1_mute"] = self._getdictstr(CONST.mlgw_screenmutedict, payload[4])
|
self._getdictstr(CONST.mlgw_speakermodedict, payload[2])
|
||||||
message["State_Update"]["screen1_active"] = self._getdictstr(CONST.mlgw_screenactivedict, payload[5])
|
message["State_Update"]["sound_status"]["stereo_mode"] = \
|
||||||
message["State_Update"]["screen2_mute"] = self._getdictstr(CONST.mlgw_screenmutedict, payload[6])
|
self._getdictstr(CONST.mlgw_stereoindicatordict, payload[9])
|
||||||
message["State_Update"]["screen2_active"] = self._getdictstr(CONST.mlgw_screenactivedict, payload[7])
|
message["State_Update"]["picture_status"]["screen1_mute"] = \
|
||||||
message["State_Update"]["cinema_mode"] = self._getdictstr(CONST.mlgw_cinemamodedict, payload[8])
|
self._getdictstr(CONST.mlgw_screenmutedict, payload[4])
|
||||||
|
message["State_Update"]["picture_status"]["screen1_active"] = \
|
||||||
|
self._getdictstr(CONST.mlgw_screenactivedict, payload[5])
|
||||||
|
message["State_Update"]["picture_status"]["screen2_mute"] = \
|
||||||
|
self._getdictstr(CONST.mlgw_screenmutedict, payload[6])
|
||||||
|
message["State_Update"]["picture_status"]["screen2_active"] = \
|
||||||
|
self._getdictstr(CONST.mlgw_screenactivedict, payload[7])
|
||||||
|
message["State_Update"]["picture_status"]["cinema_mode"] = \
|
||||||
|
self._getdictstr(CONST.mlgw_cinemamodedict, payload[8])
|
||||||
message["volume"] = int(payload[3])
|
message["volume"] = int(payload[3])
|
||||||
|
|
||||||
elif payload_type == "All standby notification":
|
elif payload_type == "All standby notification":
|
||||||
|
@ -177,7 +167,10 @@ class MLGWClient(asynchat.async_chat):
|
||||||
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]:
|
||||||
|
try:
|
||||||
message["Zone"] = room['Zone'].upper()
|
message["Zone"] = room['Zone'].upper()
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
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'
|
||||||
|
@ -236,7 +229,7 @@ class MLGWClient(asynchat.async_chat):
|
||||||
self.messageCallBack(self.name, str(list(header)), str(list(payload)), message)
|
self.messageCallBack(self.name, str(list(header)), str(list(payload)), message)
|
||||||
|
|
||||||
# ########################################################################################
|
# ########################################################################################
|
||||||
# ##### mlgw send_cmder functions
|
# ##### mlgw send 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):
|
||||||
|
@ -267,6 +260,7 @@ class MLGWClient(asynchat.async_chat):
|
||||||
# Sleep to allow msg to arrive
|
# Sleep to allow msg to arrive
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
|
|
||||||
|
# Ping the gateway
|
||||||
def ping(self):
|
def ping(self):
|
||||||
self._send_cmd(CONST.MLGW_PL.get("PING"), "")
|
self._send_cmd(CONST.MLGW_PL.get("PING"), "")
|
||||||
|
|
||||||
|
@ -343,7 +337,7 @@ class MLGWClient(asynchat.async_chat):
|
||||||
def _getbeo4commandstr(self, command):
|
def _getbeo4commandstr(self, command):
|
||||||
result = CONST.beo4_commanddict.get(command)
|
result = CONST.beo4_commanddict.get(command)
|
||||||
if result is 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):
|
||||||
|
@ -355,7 +349,7 @@ class MLGWClient(asynchat.async_chat):
|
||||||
def _getselectedsourcestr(self, source):
|
def _getselectedsourcestr(self, source):
|
||||||
result = CONST.ml_selectedsourcedict.get(source)
|
result = CONST.ml_selectedsourcedict.get(source)
|
||||||
if result is 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):
|
||||||
|
@ -376,16 +370,40 @@ class MLGWClient(asynchat.async_chat):
|
||||||
for src in CONST.available_sources:
|
for src in CONST.available_sources:
|
||||||
if src[1] == source:
|
if src[1] == source:
|
||||||
message["State_Update"]["sourceName"] = src[0]
|
message["State_Update"]["sourceName"] = src[0]
|
||||||
break
|
return
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_device_info(message, payload):
|
||||||
|
if CONST.rooms and CONST.devices:
|
||||||
|
for device in CONST.devices:
|
||||||
|
try:
|
||||||
|
if device['MLN'] == payload[0]:
|
||||||
|
name = device['Device']
|
||||||
|
for room in CONST.rooms:
|
||||||
|
if name in room['Products']:
|
||||||
|
try:
|
||||||
|
message["Zone"] = room['Zone'].upper()
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
message["Room"] = room['Room_Name'].upper()
|
||||||
|
message["Type"] = 'AV RENDERER'
|
||||||
|
message["Device"] = name
|
||||||
|
return
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_channel_track(message):
|
def _get_channel_track(message):
|
||||||
# Check device list for channel name information
|
# Check device list for channel name information
|
||||||
if CONST.devices:
|
if CONST.devices:
|
||||||
for device in CONST.devices:
|
for device in CONST.devices:
|
||||||
|
try:
|
||||||
if device['Device'] == message['Device']:
|
if device['Device'] == message['Device']:
|
||||||
if 'channels' in device['Sources'][message["State_Update"]["source"]]:
|
if 'channels' in device['Sources'][message["State_Update"]["source"]]:
|
||||||
for channel in device['Sources'][message["State_Update"]["source"]]['channels']:
|
for channel in device['Sources'][message["State_Update"]["source"]]['channels']:
|
||||||
if channel['number'] == int(message["State_Update"]['nowPlayingDetails']["channel_track"]):
|
if channel['number'] == int(
|
||||||
|
message["State_Update"]['nowPlayingDetails']["channel_track"]):
|
||||||
message["State_Update"]["nowPlaying"] = channel['name']
|
message["State_Update"]["nowPlaying"] = channel['name']
|
||||||
break
|
return
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
|
@ -66,13 +66,12 @@ class MLtnClient(asynchat.async_chat):
|
||||||
self.handle_close()
|
self.handle_close()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
try:
|
||||||
self._decode(items)
|
self._decode(items)
|
||||||
|
except IndexError:
|
||||||
|
self.log.debug(str(list(items)))
|
||||||
|
|
||||||
self._received_data = ""
|
self._received_data = ""
|
||||||
self.last_sent = ''
|
|
||||||
self.last_sent_at = 0
|
|
||||||
self.last_received = ''
|
|
||||||
self.last_received_at = 0
|
|
||||||
|
|
||||||
def _decode(self, items):
|
def _decode(self, items):
|
||||||
header = items[3][:-1]
|
header = items[3][:-1]
|
||||||
|
@ -80,6 +79,10 @@ class MLtnClient(asynchat.async_chat):
|
||||||
telegram = self._received_data[telegram_starts:].replace('!', '').split('/')
|
telegram = self._received_data[telegram_starts:].replace('!', '').split('/')
|
||||||
message = OrderedDict()
|
message = OrderedDict()
|
||||||
|
|
||||||
|
if telegram[0] == 'Monitor events ( keys: M, E, C, (spc), Q ) ----':
|
||||||
|
self.toggle_commands()
|
||||||
|
self.toggle_macros()
|
||||||
|
|
||||||
if header == 'integration_protocol':
|
if header == 'integration_protocol':
|
||||||
message = self._decode_ip(telegram, message)
|
message = self._decode_ip(telegram, message)
|
||||||
|
|
||||||
|
@ -322,13 +325,25 @@ class MLtnClient(asynchat.async_chat):
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
|
|
||||||
def toggle_events(self):
|
def toggle_events(self):
|
||||||
self._send_cmd('e')
|
try:
|
||||||
|
self.push('e')
|
||||||
|
except socket.error, e:
|
||||||
|
self.log.info("Error sending data: %s" % e)
|
||||||
|
self.handle_close()
|
||||||
|
|
||||||
def toggle_macros(self):
|
def toggle_macros(self):
|
||||||
self._send_cmd('m')
|
try:
|
||||||
|
self.push('m')
|
||||||
|
except socket.error, e:
|
||||||
|
self.log.info("Error sending data: %s" % e)
|
||||||
|
self.handle_close()
|
||||||
|
|
||||||
def toggle_commands(self):
|
def toggle_commands(self):
|
||||||
self._send_cmd('c')
|
try:
|
||||||
|
self.push('c')
|
||||||
|
except socket.error, e:
|
||||||
|
self.log.info("Error sending data: %s" % e)
|
||||||
|
self.handle_close()
|
||||||
|
|
||||||
def ping(self):
|
def ping(self):
|
||||||
self._send_cmd('')
|
self._send_cmd('')
|
||||||
|
|
Loading…
Reference in a new issue