forked from openlp/openlp
551 lines
22 KiB
Python
551 lines
22 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||
|
|
||
|
###############################################################################
|
||
|
# OpenLP - Open Source Lyrics Projection #
|
||
|
# --------------------------------------------------------------------------- #
|
||
|
# Copyright (c) 2008-2019 OpenLP Developers #
|
||
|
# --------------------------------------------------------------------------- #
|
||
|
# This program is free software; you can redistribute it and/or modify it #
|
||
|
# under the terms of the GNU General Public License as published by the Free #
|
||
|
# Software Foundation; version 2 of the License. #
|
||
|
# #
|
||
|
# This program is distributed in the hope that it will be useful, but WITHOUT #
|
||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
|
||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
|
||
|
# more details. #
|
||
|
# #
|
||
|
# You should have received a copy of the GNU General Public License along #
|
||
|
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||
|
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||
|
###############################################################################
|
||
|
"""
|
||
|
The :mod:`openlp.core.lib.projector.pjlinkcmmands` module provides the necessary functions for
|
||
|
processing projector replies.
|
||
|
|
||
|
NOTE: PJLink Class (version) checks are handled in the respective PJLink/PJLinkUDP classes.
|
||
|
process_clss is the only exception.
|
||
|
"""
|
||
|
|
||
|
import logging
|
||
|
import re
|
||
|
|
||
|
from openlp.core.common import qmd5_hash
|
||
|
|
||
|
from openlp.core.common.i18n import translate
|
||
|
from openlp.core.common.settings import Settings
|
||
|
|
||
|
from openlp.core.projectors.constants import E_AUTHENTICATION, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \
|
||
|
PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_POWR_STATUS, S_CONNECTED, S_OFF, S_OK, S_ON, S_STANDBY, \
|
||
|
STATUS_MSG
|
||
|
|
||
|
log = logging.getLogger(__name__)
|
||
|
log.debug('Loading pjlinkcommands')
|
||
|
|
||
|
__all__ = ['process_command']
|
||
|
|
||
|
|
||
|
# This should be the only function that's imported.
|
||
|
def process_command(projector, cmd, data):
|
||
|
"""
|
||
|
Verifies any return error code. Calls the appropriate command handler.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param cmd: Command to process
|
||
|
:param data: Data being processed
|
||
|
"""
|
||
|
log.debug('({ip}) Processing command "{cmd}" with data "{data}"'.format(ip=projector.entry.name,
|
||
|
cmd=cmd,
|
||
|
data=data))
|
||
|
# cmd should already be in uppercase, but data may be in mixed-case.
|
||
|
# Due to some replies should stay as mixed-case, validate using separate uppercase check
|
||
|
_data = data.upper()
|
||
|
# Check if we have a future command not available yet
|
||
|
if cmd not in pjlink_functions:
|
||
|
log.warning('({ip}) Unable to process command="{cmd}" (Future option?)'.format(ip=projector.entry.name,
|
||
|
cmd=cmd))
|
||
|
return
|
||
|
elif _data == 'OK':
|
||
|
log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=projector.entry.name, cmd=cmd))
|
||
|
# A command returned successfully, so do a query on command to verify status
|
||
|
return projector.send_command(cmd=cmd, priority=True)
|
||
|
elif _data in PJLINK_ERRORS:
|
||
|
# Oops - projector error
|
||
|
log.error('({ip}) {cmd}: {err}'.format(ip=projector.entry.name,
|
||
|
cmd=cmd,
|
||
|
err=STATUS_MSG[PJLINK_ERRORS[_data]]))
|
||
|
if PJLINK_ERRORS[_data] == E_AUTHENTICATION:
|
||
|
projector.disconnect_from_host()
|
||
|
projector.projectorAuthentication.emit(projector.name)
|
||
|
return projector.change_status(status=E_AUTHENTICATION)
|
||
|
# Command checks already passed
|
||
|
log.debug('({ip}) Calling function for {cmd}'.format(ip=projector.entry.name, cmd=cmd))
|
||
|
pjlink_functions[cmd](projector=projector, data=data)
|
||
|
|
||
|
|
||
|
def process_ackn(projector, data):
|
||
|
"""
|
||
|
Process the ACKN command.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Data in packet
|
||
|
"""
|
||
|
# TODO: Have to rethink this one
|
||
|
pass
|
||
|
|
||
|
|
||
|
def process_avmt(projector, data):
|
||
|
"""
|
||
|
Process shutter and speaker status. See PJLink specification for format.
|
||
|
Update projector.mute (audio) and projector.shutter (video shutter).
|
||
|
10 = Shutter open, audio unchanged
|
||
|
11 = Shutter closed, audio unchanged
|
||
|
20 = Shutter unchanged, Audio normal
|
||
|
21 = Shutter unchanged, Audio muted
|
||
|
30 = Shutter open, audio muted
|
||
|
31 = Shutter closed, audio normal
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Shutter and audio status
|
||
|
"""
|
||
|
settings = {'10': {'shutter': False, 'mute': projector.mute},
|
||
|
'11': {'shutter': True, 'mute': projector.mute},
|
||
|
'20': {'shutter': projector.shutter, 'mute': False},
|
||
|
'21': {'shutter': projector.shutter, 'mute': True},
|
||
|
'30': {'shutter': False, 'mute': False},
|
||
|
'31': {'shutter': True, 'mute': True}
|
||
|
}
|
||
|
if data not in settings:
|
||
|
log.warning('({ip}) Invalid shutter response: {data}'.format(ip=projector.entry.name, data=data))
|
||
|
return
|
||
|
shutter = settings[data]['shutter']
|
||
|
mute = settings[data]['mute']
|
||
|
# Check if we need to update the icons
|
||
|
update_icons = (shutter != projector.shutter) or (mute != projector.mute)
|
||
|
projector.shutter = shutter
|
||
|
projector.mute = mute
|
||
|
if update_icons:
|
||
|
if 'AVMT' in projector.status_timer_checks:
|
||
|
projector.status_timer_delete('AVMT')
|
||
|
projector.projectorUpdateIcons.emit()
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_clss(projector, data):
|
||
|
"""
|
||
|
PJLink class that this projector supports. See PJLink specification for format.
|
||
|
Updates projector.class.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Class that projector supports.
|
||
|
"""
|
||
|
# bug 1550891: Projector returns non-standard class response:
|
||
|
# : Expected: '%1CLSS=1'
|
||
|
# : Received: '%1CLSS=Class 1' (Optoma)
|
||
|
# : Received: '%1CLSS=Version1' (BenQ)
|
||
|
if len(data) > 1:
|
||
|
log.warning('({ip}) Non-standard CLSS reply: "{data}"'.format(ip=projector.entry.name, data=data))
|
||
|
# Due to stupid projectors not following standards (Optoma, BenQ comes to mind),
|
||
|
# AND the different responses that can be received, the semi-permanent way to
|
||
|
# fix the class reply is to just remove all non-digit characters.
|
||
|
chk = re.findall(r'\d', data)
|
||
|
if len(chk) < 1:
|
||
|
log.error('({ip}) No numbers found in class version reply "{data}" - '
|
||
|
'defaulting to class "1"'.format(ip=projector.entry.name, data=data))
|
||
|
clss = '1'
|
||
|
else:
|
||
|
clss = chk[0] # Should only be the first match
|
||
|
elif not data.isdigit():
|
||
|
log.error('({ip}) NAN CLSS version reply "{data}" - '
|
||
|
'defaulting to class "1"'.format(ip=projector.entry.name, data=data))
|
||
|
clss = '1'
|
||
|
else:
|
||
|
clss = data
|
||
|
projector.pjlink_class = clss
|
||
|
log.debug('({ip}) Setting pjlink_class for this projector to "{data}"'.format(ip=projector.entry.name,
|
||
|
data=projector.pjlink_class))
|
||
|
if projector.no_poll:
|
||
|
return
|
||
|
|
||
|
# Since we call this one on first connect, setup polling from here
|
||
|
log.debug('({ip}) process_pjlink(): Starting timer'.format(ip=projector.entry.name))
|
||
|
projector.poll_timer.setInterval(1000) # Set 1 second for initial information
|
||
|
projector.poll_timer.start()
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_erst(projector, data):
|
||
|
"""
|
||
|
Error status. See PJLink Specifications for format.
|
||
|
Updates projector.projector_errors
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Error status
|
||
|
"""
|
||
|
if len(data) != PJLINK_ERST_DATA['DATA_LENGTH']:
|
||
|
count = PJLINK_ERST_DATA['DATA_LENGTH']
|
||
|
log.warning('({ip}) Invalid error status response "{data}": length != {count}'.format(ip=projector.entry.name,
|
||
|
data=data,
|
||
|
count=count))
|
||
|
return
|
||
|
if not data.isnumeric():
|
||
|
# Bad data - ignore
|
||
|
log.warning('({ip}) Invalid error status response "{data}"'.format(ip=projector.entry.name, data=data))
|
||
|
return
|
||
|
datacheck = int(data)
|
||
|
if datacheck == 0:
|
||
|
projector.projector_errors = None
|
||
|
# No errors
|
||
|
return
|
||
|
# We have some sort of status error, so check out what it/they are
|
||
|
projector.projector_errors = {}
|
||
|
fan, lamp, temp, cover, filt, other = (data[PJLINK_ERST_DATA['FAN']],
|
||
|
data[PJLINK_ERST_DATA['LAMP']],
|
||
|
data[PJLINK_ERST_DATA['TEMP']],
|
||
|
data[PJLINK_ERST_DATA['COVER']],
|
||
|
data[PJLINK_ERST_DATA['FILTER']],
|
||
|
data[PJLINK_ERST_DATA['OTHER']])
|
||
|
if fan != PJLINK_ERST_STATUS[S_OK]:
|
||
|
projector.projector_errors[translate('OpenLP.ProjectorPJLink', 'Fan')] = \
|
||
|
PJLINK_ERST_STATUS[fan]
|
||
|
if lamp != PJLINK_ERST_STATUS[S_OK]:
|
||
|
projector.projector_errors[translate('OpenLP.ProjectorPJLink', 'Lamp')] = \
|
||
|
PJLINK_ERST_STATUS[lamp]
|
||
|
if temp != PJLINK_ERST_STATUS[S_OK]:
|
||
|
projector.projector_errors[translate('OpenLP.ProjectorPJLink', 'Temperature')] = \
|
||
|
PJLINK_ERST_STATUS[temp]
|
||
|
if cover != PJLINK_ERST_STATUS[S_OK]:
|
||
|
projector.projector_errors[translate('OpenLP.ProjectorPJLink', 'Cover')] = \
|
||
|
PJLINK_ERST_STATUS[cover]
|
||
|
if filt != PJLINK_ERST_STATUS[S_OK]:
|
||
|
projector.projector_errors[translate('OpenLP.ProjectorPJLink', 'Filter')] = \
|
||
|
PJLINK_ERST_STATUS[filt]
|
||
|
if other != PJLINK_ERST_STATUS[S_OK]:
|
||
|
projector.projector_errors[translate('OpenLP.ProjectorPJLink', 'Other')] = \
|
||
|
PJLINK_ERST_STATUS[other]
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_inf1(projector, data):
|
||
|
"""
|
||
|
Manufacturer name set in projector.
|
||
|
Updates projector.manufacturer
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Projector manufacturer
|
||
|
"""
|
||
|
projector.manufacturer = data
|
||
|
log.debug('({ip}) Setting projector manufacturer data to "{data}"'.format(ip=projector.entry.name,
|
||
|
data=projector.manufacturer))
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_inf2(projector, data):
|
||
|
"""
|
||
|
Projector Model set in projector.
|
||
|
Updates projector.model.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Model name
|
||
|
"""
|
||
|
projector.model = data
|
||
|
log.debug('({ip}) Setting projector model to "{data}"'.format(ip=projector.entry.name, data=projector.model))
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_info(projector, data):
|
||
|
"""
|
||
|
Any extra info set in projector.
|
||
|
Updates projector.other_info.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Projector other info
|
||
|
"""
|
||
|
projector.other_info = data
|
||
|
log.debug('({ip}) Setting projector other_info to "{data}"'.format(ip=projector.entry.name,
|
||
|
data=projector.other_info))
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_inpt(projector, data):
|
||
|
"""
|
||
|
Current source input selected. See PJLink specification for format.
|
||
|
Update projector.source
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Currently selected source
|
||
|
"""
|
||
|
# First, see if we have a valid input based on what is installed (if available)
|
||
|
if projector.source_available is not None:
|
||
|
# We have available inputs, so verify it's in the list
|
||
|
if data not in projector.source_available:
|
||
|
log.warn('({ip}) Input source not listed in available sources - ignoring'.format(ip=projector.entry.name))
|
||
|
return
|
||
|
elif data not in PJLINK_DEFAULT_CODES:
|
||
|
# Hmm - no sources available yet, so check with PJLink defaults
|
||
|
log.warn('({ip}) Input source not listed as a PJLink available source '
|
||
|
'- ignoring'.format(ip=projector.entry.name))
|
||
|
return
|
||
|
projector.source = data
|
||
|
log.debug('({ip}) Setting current source to "{data}"'.format(ip=projector.entry.name, data=projector.source))
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_inst(projector, data):
|
||
|
"""
|
||
|
Available source inputs. See PJLink specification for format.
|
||
|
Updates projector.source_available
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Sources list
|
||
|
"""
|
||
|
sources = []
|
||
|
check = data.split()
|
||
|
for source in check:
|
||
|
sources.append(source)
|
||
|
sources.sort()
|
||
|
projector.source_available = sources
|
||
|
log.debug('({ip}) Setting projector source_available to "{data}"'.format(ip=projector.entry.name,
|
||
|
data=projector.source_available))
|
||
|
projector.projectorUpdateIcons.emit()
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_lamp(projector, data):
|
||
|
"""
|
||
|
Lamp(s) status. See PJLink Specifications for format.
|
||
|
Data may have more than 1 lamp to process.
|
||
|
Update projector.lamp dictionary with lamp status.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Lamp(s) status.
|
||
|
"""
|
||
|
lamps = []
|
||
|
lamp_list = data.split()
|
||
|
if len(lamp_list) < 2:
|
||
|
lamps.append({'Hours': int(lamp_list[0]), 'On': None})
|
||
|
else:
|
||
|
while lamp_list:
|
||
|
if not lamp_list[0].isnumeric() or not lamp_list[1].isnumeric():
|
||
|
# Invalid data - we'll ignore the rest for now
|
||
|
log.warning('({ip}) process_lamp(): Invalid data "{data}"'.format(ip=projector.entry.name, data=data))
|
||
|
return
|
||
|
fill = {'Hours': int(lamp_list[0]), 'On': False if lamp_list[1] == '0' else True}
|
||
|
lamps.append(fill)
|
||
|
lamp_list.pop(0) # Remove lamp hours
|
||
|
lamp_list.pop(0) # Remove lamp on/off
|
||
|
projector.lamp = lamps
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_lkup(projector, data):
|
||
|
"""
|
||
|
Process reply indicating remote is available for connection
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Data packet from remote
|
||
|
"""
|
||
|
log.debug('({ip}) Processing LKUP command'.format(ip=projector.entry.name))
|
||
|
if Settings().value('projector/connect when LKUP received'):
|
||
|
projector.connect_to_host()
|
||
|
|
||
|
|
||
|
def process_name(projector, data):
|
||
|
"""
|
||
|
Projector name set in projector.
|
||
|
Updates projector.pjlink_name
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Projector name
|
||
|
"""
|
||
|
projector.pjlink_name = data
|
||
|
log.debug('({ip}) Setting projector PJLink name to "{data}"'.format(ip=projector.entry.name,
|
||
|
data=projector.pjlink_name))
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_pjlink(projector, data):
|
||
|
"""
|
||
|
Process initial socket connection to terminal.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Initial packet with authentication scheme
|
||
|
"""
|
||
|
log.debug('({ip}) Processing PJLINK command'.format(ip=projector.entry.name))
|
||
|
chk = data.split(' ')
|
||
|
if len(chk[0]) != 1:
|
||
|
# Invalid - after splitting, first field should be 1 character, either '0' or '1' only
|
||
|
log.error('({ip}) Invalid initial authentication scheme - aborting'.format(ip=projector.entry.name))
|
||
|
return projector.disconnect_from_host()
|
||
|
elif chk[0] == '0':
|
||
|
# Normal connection no authentication
|
||
|
if len(chk) > 1:
|
||
|
# Invalid data - there should be nothing after a normal authentication scheme
|
||
|
log.error('({ip}) Normal connection with extra information - aborting'.format(ip=projector.entry.name))
|
||
|
return projector.disconnect_from_host()
|
||
|
elif projector.pin:
|
||
|
log.error('({ip}) Normal connection but PIN set - aborting'.format(ip=projector.entry.name))
|
||
|
return projector.disconnect_from_host()
|
||
|
else:
|
||
|
data_hash = None
|
||
|
elif chk[0] == '1':
|
||
|
if len(chk) < 2:
|
||
|
# Not enough information for authenticated connection
|
||
|
log.error('({ip}) Authenticated connection but not enough info - aborting'.format(ip=projector.entry.name))
|
||
|
return projector.disconnect_from_host()
|
||
|
elif not projector.pin:
|
||
|
log.error('({ip}) Authenticate connection but no PIN - aborting'.format(ip=projector.entry.name))
|
||
|
return projector.disconnect_from_host()
|
||
|
else:
|
||
|
data_hash = str(qmd5_hash(salt=chk[1].encode('utf-8'), data=projector.pin.encode('utf-8')),
|
||
|
encoding='ascii')
|
||
|
# Passed basic checks, so start connection
|
||
|
projector.readyRead.connect(projector.get_socket)
|
||
|
projector.change_status(S_CONNECTED)
|
||
|
log.debug('({ip}) process_pjlink(): Sending "CLSS" initial command'.format(ip=projector.entry.name))
|
||
|
# Since this is an initial connection, make it a priority just in case
|
||
|
return projector.send_command(cmd="CLSS", salt=data_hash, priority=True)
|
||
|
|
||
|
|
||
|
def process_powr(projector, data):
|
||
|
"""
|
||
|
Power status. See PJLink specification for format.
|
||
|
Update projector.power with status. Update icons if change from previous setting.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Power status
|
||
|
"""
|
||
|
log.debug('({ip}: Processing POWR command'.format(ip=projector.entry.name))
|
||
|
if data in PJLINK_POWR_STATUS:
|
||
|
power = PJLINK_POWR_STATUS[data]
|
||
|
update_icons = projector.power != power
|
||
|
projector.power = power
|
||
|
projector.change_status(PJLINK_POWR_STATUS[data])
|
||
|
if update_icons:
|
||
|
projector.projectorUpdateIcons.emit()
|
||
|
# Update the input sources available
|
||
|
if power == S_ON:
|
||
|
projector.send_command('INST')
|
||
|
else:
|
||
|
# Log unknown status response
|
||
|
log.warning('({ip}) Unknown power response: "{data}"'.format(ip=projector.entry.name, data=data))
|
||
|
if projector.power in [S_ON, S_STANDBY, S_OFF] and 'POWR' in projector.status_timer_checks:
|
||
|
projector.status_timer_delete(cmd='POWR')
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_rfil(projector, data):
|
||
|
"""
|
||
|
Process replacement filter type
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Filter replacement model number
|
||
|
"""
|
||
|
if projector.model_filter is None:
|
||
|
projector.model_filter = data
|
||
|
else:
|
||
|
log.warning('({ip}) Filter model already set'.format(ip=projector.entry.name))
|
||
|
log.warning('({ip}) Saved model: "{old}"'.format(ip=projector.entry.name, old=projector.model_filter))
|
||
|
log.warning('({ip}) New model: "{new}"'.format(ip=projector.entry.name, new=data))
|
||
|
|
||
|
|
||
|
def process_rlmp(projector, data):
|
||
|
"""
|
||
|
Process replacement lamp type
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Lamp replacement model number
|
||
|
"""
|
||
|
if projector.model_lamp is None:
|
||
|
projector.model_lamp = data
|
||
|
else:
|
||
|
log.warning('({ip}) Lamp model already set'.format(ip=projector.entry.name))
|
||
|
log.warning('({ip}) Saved lamp: "{old}"'.format(ip=projector.entry.name, old=projector.model_lamp))
|
||
|
log.warning('({ip}) New lamp: "{new}"'.format(ip=projector.entry.name, new=data))
|
||
|
|
||
|
|
||
|
def process_snum(projector, data):
|
||
|
"""
|
||
|
Serial number of projector.
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Serial number from projector.
|
||
|
"""
|
||
|
if projector.serial_no is None:
|
||
|
log.debug('({ip}) Setting projector serial number to "{data}"'.format(ip=projector.entry.name, data=data))
|
||
|
projector.serial_no = data
|
||
|
projector.db_update = False
|
||
|
return
|
||
|
|
||
|
# Compare serial numbers and see if we got the same projector
|
||
|
if projector.serial_no != data:
|
||
|
log.warning('({ip}) Projector serial number does not match saved serial '
|
||
|
'number'.format(ip=projector.entry.name))
|
||
|
log.warning('({ip}) Saved: "{old}"'.format(ip=projector.entry.name, old=projector.serial_no))
|
||
|
log.warning('({ip}) Received: "{new}"'.format(ip=projector.entry.name, new=data))
|
||
|
log.warning('({ip}) NOT saving serial number'.format(ip=projector.entry.name))
|
||
|
projector.serial_no_received = data
|
||
|
|
||
|
|
||
|
def process_srch(projector=None, data=None):
|
||
|
"""
|
||
|
Process the SRCH command.
|
||
|
|
||
|
SRCH is processed by terminals so we ignore any packet.
|
||
|
|
||
|
:param projector: Projector instance (actually ignored for this command)
|
||
|
:param data: Data in packet
|
||
|
"""
|
||
|
log.warning("({ip}) SRCH packet detected - ignoring".format(ip=projector.entry.ip))
|
||
|
return
|
||
|
|
||
|
|
||
|
def process_sver(projector, data):
|
||
|
"""
|
||
|
Software version of projector
|
||
|
|
||
|
:param projector: Projector instance
|
||
|
:param data: Software version of projector
|
||
|
"""
|
||
|
if len(data) > 32:
|
||
|
# Defined in specs max version is 32 characters
|
||
|
log.warning('Invalid software version - too long')
|
||
|
return
|
||
|
if projector.sw_version is not None:
|
||
|
if projector.sw_version == data:
|
||
|
log.debug('({ip}) Software version same as saved version - returning'.format(ip=projector.entry.name))
|
||
|
return
|
||
|
log.warning('({ip}) Projector software version does not match saved '
|
||
|
'software version'.format(ip=projector.entry.name))
|
||
|
log.warning('({ip}) Saved: "{old}"'.format(ip=projector.entry.name, old=projector.sw_version))
|
||
|
log.warning('({ip}) Received: "{new}"'.format(ip=projector.entry.name, new=data))
|
||
|
log.warning('({ip}) Updating software version'.format(ip=projector.entry.name))
|
||
|
|
||
|
log.debug('({ip}) Setting projector software version to "{data}"'.format(ip=projector.entry.name, data=data))
|
||
|
projector.sw_version = data
|
||
|
projector.db_update = True
|
||
|
|
||
|
|
||
|
# Map command to function.
|
||
|
pjlink_functions = {
|
||
|
'ACKN': process_ackn, # Class 2 (command is SRCH)
|
||
|
'AVMT': process_avmt,
|
||
|
'CLSS': process_clss,
|
||
|
'ERST': process_erst,
|
||
|
'INFO': process_info,
|
||
|
'INF1': process_inf1,
|
||
|
'INF2': process_inf2,
|
||
|
'INPT': process_inpt,
|
||
|
'INST': process_inst,
|
||
|
'LAMP': process_lamp,
|
||
|
'LKUP': process_lkup, # Class 2 (reply only - no cmd)
|
||
|
'NAME': process_name,
|
||
|
'PJLINK': process_pjlink,
|
||
|
'POWR': process_powr,
|
||
|
'SNUM': process_snum,
|
||
|
'SRCH': process_srch, # Class 2 (reply is ACKN)
|
||
|
'SVER': process_sver,
|
||
|
'RFIL': process_rfil,
|
||
|
'RLMP': process_rlmp
|
||
|
}
|