forked from openlp/openlp
-- Renamed test_projector_clss to clss_one
-- Added test_projector_clss_two -- Updated PJLink non-standard class check -- Added process_snum -- Added tests for process_snum -- Renamed tests/functional/openlp_core_lib/test_projectordb.py to test_projector_db.py -- Added filter model command (rfil) -- Added lamp model command (rlmp) -- Added tests for filter/model commands -- Fix typo in projector status window -- Cleanups from commit notes -- Added invalid data buffer cleanups -- Added calls ... bzr-revno: 2753
This commit is contained in:
commit
b60a8b5a3e
@ -303,7 +303,7 @@ class ProjectorDB(Manager):
|
||||
:param ip: Host IP/Name
|
||||
:returns: Projector() instance
|
||||
"""
|
||||
log.debug('get_projector_by_ip(ip="%s")' % ip)
|
||||
log.debug('get_projector_by_ip(ip="{ip}")'.format(ip=ip))
|
||||
projector = self.get_object_filtered(Projector, Projector.ip == ip)
|
||||
if projector is None:
|
||||
# Not found
|
||||
|
@ -44,6 +44,7 @@ log.debug('pjlink1 loaded')
|
||||
|
||||
__all__ = ['PJLink']
|
||||
|
||||
import re
|
||||
from codecs import decode
|
||||
|
||||
from PyQt5 import QtCore, QtNetwork
|
||||
@ -53,7 +54,7 @@ from openlp.core.lib.projector.constants import CONNECTION_ERRORS, CR, ERROR_MSG
|
||||
E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, \
|
||||
E_PARAMETER, E_PROJECTOR, E_SOCKET_TIMEOUT, E_UNAVAILABLE, E_UNDEFINED, PJLINK_ERRORS, \
|
||||
PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_POWR_STATUS, PJLINK_VALID_CMD, \
|
||||
PJLINK_DEFAULT_CODES, STATUS_STRING, S_CONNECTED, S_CONNECTING, S_NETWORK_RECEIVED, S_NETWORK_SENDING, \
|
||||
STATUS_STRING, S_CONNECTED, S_CONNECTING, S_NETWORK_RECEIVED, S_NETWORK_SENDING, \
|
||||
S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_STATUS
|
||||
|
||||
# Shortcuts
|
||||
@ -113,8 +114,13 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
self.port = port
|
||||
self.pin = pin
|
||||
super().__init__()
|
||||
self.model_lamp = None
|
||||
self.model_filter = None
|
||||
self.mac_adx = kwargs.get('mac_adx')
|
||||
self.serial_no = None
|
||||
self.serial_no_received = None # Used only if saved serial number is different than received serial number
|
||||
self.dbid = None
|
||||
self.db_update = False # Use to check if db needs to be updated prior to exiting
|
||||
self.location = None
|
||||
self.notes = None
|
||||
self.dbid = kwargs.get('dbid')
|
||||
@ -158,7 +164,11 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
'LAMP': self.process_lamp,
|
||||
'NAME': self.process_name,
|
||||
'PJLINK': self.check_login,
|
||||
'POWR': self.process_powr
|
||||
'POWR': self.process_powr,
|
||||
'SNUM': self.process_snum,
|
||||
'SVER': self.process_sver,
|
||||
'RFIL': self.process_rfil,
|
||||
'RLMP': self.process_rlmp
|
||||
}
|
||||
|
||||
def reset_information(self):
|
||||
@ -166,12 +176,16 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
Reset projector-specific information to default
|
||||
"""
|
||||
log.debug('({ip}) reset_information() connect status is {state}'.format(ip=self.ip, state=self.state()))
|
||||
self.send_queue = []
|
||||
self.power = S_OFF
|
||||
self.pjlink_name = None
|
||||
self.manufacturer = None
|
||||
self.model = None
|
||||
self.serial_no = None
|
||||
self.serial_no_received = None
|
||||
self.sw_version = None
|
||||
self.sw_version_received = None
|
||||
self.mac_adx = None
|
||||
self.shutter = None
|
||||
self.mute = None
|
||||
self.lamp = None
|
||||
@ -188,7 +202,6 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
if hasattr(self, 'socket_timer'):
|
||||
log.debug('({ip}): Calling socket_timer.stop()'.format(ip=self.ip))
|
||||
self.socket_timer.stop()
|
||||
self.send_queue = []
|
||||
self.send_busy = False
|
||||
|
||||
def thread_started(self):
|
||||
@ -240,6 +253,7 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
Normally called by timer().
|
||||
"""
|
||||
if self.state() != self.ConnectedState:
|
||||
log.warn("({ip}) poll_loop(): Not connected - returning".format(ip=self.ip))
|
||||
return
|
||||
log.debug('({ip}) Updating projector status'.format(ip=self.ip))
|
||||
# Reset timer in case we were called from a set command
|
||||
@ -248,8 +262,11 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
self.timer.setInterval(self.poll_time)
|
||||
# Restart timer
|
||||
self.timer.start()
|
||||
# These commands may change during connetion
|
||||
for command in ['POWR', 'ERST', 'LAMP', 'AVMT', 'INPT']:
|
||||
# These commands may change during connection
|
||||
check_list = ['POWR', 'ERST', 'LAMP', 'AVMT', 'INPT']
|
||||
if self.pjlink_class == '2':
|
||||
check_list.extend(['FILT', 'FREZ'])
|
||||
for command in check_list:
|
||||
self.send_command(command, queue=True)
|
||||
# The following commands do not change, so only check them once
|
||||
if self.power == S_ON and self.source_available is None:
|
||||
@ -262,6 +279,38 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
self.send_command('INF2', queue=True)
|
||||
if self.pjlink_name is None:
|
||||
self.send_command('NAME', queue=True)
|
||||
if self.pjlink_class == '2':
|
||||
# Class 2 specific checks
|
||||
if self.serial_no is None:
|
||||
self.send_command('SNUM', queue=True)
|
||||
if self.sw_version is None:
|
||||
self.send_command('SVER', queue=True)
|
||||
if self.model_filter is None:
|
||||
self.send_command('RFIL', queue=True)
|
||||
if self.model_lamp is None:
|
||||
self.send_command('RLMP', queue=True)
|
||||
|
||||
def process_rfil(self, data):
|
||||
"""
|
||||
Process replacement filter type
|
||||
"""
|
||||
if self.model_filter is None:
|
||||
self.model_filter = data
|
||||
else:
|
||||
log.warn("({ip}) Filter model already set".format(ip=self.ip))
|
||||
log.warn("({ip}) Saved model: '{old}'".format(ip=self.ip, old=self.model_filter))
|
||||
log.warn("({ip}) New model: '{new}'".format(ip=self.ip, new=data))
|
||||
|
||||
def process_rlmp(self, data):
|
||||
"""
|
||||
Process replacement lamp type
|
||||
"""
|
||||
if self.model_lamp is None:
|
||||
self.model_lamp = data
|
||||
else:
|
||||
log.warn("({ip}) Lamp model already set".format(ip=self.ip))
|
||||
log.warn("({ip}) Saved lamp: '{old}'".format(ip=self.ip, old=self.model_lamp))
|
||||
log.warn("({ip}) New lamp: '{new}'".format(ip=self.ip, new=data))
|
||||
|
||||
def _get_status(self, status):
|
||||
"""
|
||||
@ -331,7 +380,7 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
self.change_status(E_SOCKET_TIMEOUT)
|
||||
return
|
||||
read = self.readLine(self.max_size)
|
||||
dontcare = self.readLine(self.max_size) # Clean out the trailing \r\n
|
||||
self.readLine(self.max_size) # Clean out the trailing \r\n
|
||||
if read is None:
|
||||
log.warning('({ip}) read is None - socket error?'.format(ip=self.ip))
|
||||
return
|
||||
@ -341,7 +390,7 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
data = decode(read, 'utf-8')
|
||||
# Possibility of extraneous data on input when reading.
|
||||
# Clean out extraneous characters in buffer.
|
||||
dontcare = self.readLine(self.max_size)
|
||||
self.readLine(self.max_size)
|
||||
log.debug('({ip}) check_login() read "{data}"'.format(ip=self.ip, data=data.strip()))
|
||||
# At this point, we should only have the initial login prompt with
|
||||
# possible authentication
|
||||
@ -363,24 +412,24 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
# Authentication error
|
||||
self.disconnect_from_host()
|
||||
self.change_status(E_AUTHENTICATION)
|
||||
log.debug('({ip}) emitting projectorAuthentication() signal'.format(ip=self.name))
|
||||
log.debug('({ip}) emitting projectorAuthentication() signal'.format(ip=self.ip))
|
||||
return
|
||||
elif data_check[1] == '0' and self.pin is not None:
|
||||
# Pin set and no authentication needed
|
||||
log.warning('({ip}) Regular connection but PIN set'.format(ip=self.name))
|
||||
self.disconnect_from_host()
|
||||
self.change_status(E_AUTHENTICATION)
|
||||
log.debug('({ip}) Emitting projectorNoAuthentication() signal'.format(ip=self.name))
|
||||
log.debug('({ip}) Emitting projectorNoAuthentication() signal'.format(ip=self.ip))
|
||||
self.projectorNoAuthentication.emit(self.name)
|
||||
return
|
||||
elif data_check[1] == '1':
|
||||
# Authenticated login with salt
|
||||
if self.pin is None:
|
||||
log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.name))
|
||||
log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.ip))
|
||||
self.disconnect_from_host()
|
||||
self.change_status(E_AUTHENTICATION)
|
||||
log.debug('({ip}) Emitting projectorAuthentication() signal'.format(ip=self.name))
|
||||
self.projectorAuthentication.emit(self.name)
|
||||
log.debug('({ip}) Emitting projectorAuthentication() signal'.format(ip=self.ip))
|
||||
self.projectorAuthentication.emit(self.ip)
|
||||
return
|
||||
else:
|
||||
log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2]))
|
||||
@ -400,6 +449,20 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
self.timer.setInterval(2000) # Set 2 seconds for initial information
|
||||
self.timer.start()
|
||||
|
||||
def _trash_buffer(self, msg=None):
|
||||
"""
|
||||
Clean out extraneous stuff in the buffer.
|
||||
"""
|
||||
log.warning("({ip}) {message}".format(ip=self.ip, message='Invalid packet' if msg is None else msg))
|
||||
self.send_busy = False
|
||||
trash_count = 0
|
||||
while self.bytesAvailable() > 0:
|
||||
trash = self.read(self.max_size)
|
||||
trash_count += len(trash)
|
||||
log.debug("({ip}) Finished cleaning buffer - {count} bytes dropped".format(ip=self.ip,
|
||||
count=trash_count))
|
||||
return
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def get_data(self):
|
||||
"""
|
||||
@ -414,43 +477,27 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
if read == -1:
|
||||
# No data available
|
||||
log.debug('({ip}) get_data(): No data available (-1)'.format(ip=self.ip))
|
||||
self.send_busy = False
|
||||
self.projectorReceivedData.emit()
|
||||
return
|
||||
return self.receive_data_signal()
|
||||
self.socket_timer.stop()
|
||||
self.projectorNetwork.emit(S_NETWORK_RECEIVED)
|
||||
# NOTE: Class2 has changed to some values being UTF-8
|
||||
data_in = decode(read, 'utf-8')
|
||||
data = data_in.strip()
|
||||
if len(data) < 7:
|
||||
# Not enough data for a packet
|
||||
log.debug('({ip}) get_data(): Packet length < 7: "{data}"'.format(ip=self.ip, data=data))
|
||||
self.receive_data_signal()
|
||||
return
|
||||
if (len(data) < 7) or (not data.startswith(PJLINK_PREFIX)):
|
||||
return self._trash_buffer(msg='get_data(): Invalid packet - length or prefix')
|
||||
elif '=' not in data:
|
||||
log.warning('({ip}) get_data(): Invalid packet received'.format(ip=self.ip))
|
||||
self.receive_data_signal()
|
||||
return
|
||||
return self._trash_buffer(msg='get_data(): Invalid packet does not have equal')
|
||||
log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.ip, data=data))
|
||||
# At this point, we should have something to work with
|
||||
if data.upper().startswith('PJLINK'):
|
||||
# Reconnected from remote host disconnect ?
|
||||
self.check_login(data)
|
||||
self.receive_data_signal()
|
||||
return
|
||||
data_split = data.split('=')
|
||||
header, data = data.split('=')
|
||||
try:
|
||||
(prefix, version, cmd, data) = (data_split[0][0], data_split[0][1], data_split[0][2:], data_split[1])
|
||||
version, cmd = header[1], header[2:]
|
||||
except ValueError as e:
|
||||
log.warning('({ip}) get_data(): Invalid packet - expected header + command + data'.format(ip=self.ip))
|
||||
log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip()))
|
||||
self.change_status(E_INVALID_DATA)
|
||||
self.receive_data_signal()
|
||||
return
|
||||
log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip()))
|
||||
return self._trash_buffer('get_data(): Expected header + command + data')
|
||||
if cmd not in PJLINK_VALID_CMD:
|
||||
log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
|
||||
self.receive_data_signal()
|
||||
return
|
||||
return self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))
|
||||
if int(self.pjlink_class) < int(version):
|
||||
log.warn('({ip}) get_data(): Projector returned class reply higher '
|
||||
'than projector stated class'.format(ip=self.ip))
|
||||
@ -506,7 +553,7 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
salt='' if salt is None
|
||||
else ' with hash'))
|
||||
cmd_ver = PJLINK_VALID_CMD[cmd]['version']
|
||||
if self.pjlink_class in cmd_ver:
|
||||
if self.pjlink_class in PJLINK_VALID_CMD[cmd]['version']:
|
||||
header = PJLINK_HEADER.format(linkclass=self.pjlink_class)
|
||||
elif len(cmd_ver) == 1 and (int(cmd_ver[0]) < int(self.pjlink_class)):
|
||||
# Typically a class 1 only command
|
||||
@ -575,6 +622,7 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
self.waitForBytesWritten(2000) # 2 seconds should be enough
|
||||
if sent == -1:
|
||||
# Network error?
|
||||
log.warning("({ip}) _send_command(): -1 received".format(ip=self.ip))
|
||||
self.change_status(E_NETWORK,
|
||||
translate('OpenLP.PJLink', 'Error while sending data to projector'))
|
||||
|
||||
@ -617,20 +665,17 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
elif data.upper() == 'ERR4':
|
||||
# Projector/display error
|
||||
self.change_status(E_PROJECTOR)
|
||||
self.send_busy = False
|
||||
self.projectorReceivedData.emit()
|
||||
self.receive_data_signal()
|
||||
return
|
||||
# Command succeeded - no extra information
|
||||
elif data.upper() == 'OK':
|
||||
log.debug('({ip}) Command returned OK'.format(ip=self.ip))
|
||||
# A command returned successfully, recheck data
|
||||
self.send_busy = False
|
||||
self.projectorReceivedData.emit()
|
||||
# A command returned successfully
|
||||
self.receive_data_signal()
|
||||
return
|
||||
# Command checks already passed
|
||||
log.debug('({ip}) Calling function for {cmd}'.format(ip=self.ip, cmd=cmd))
|
||||
self.send_busy = False
|
||||
self.projectorReceivedData.emit()
|
||||
self.receive_data_signal()
|
||||
self.pjlink_functions[cmd](data)
|
||||
|
||||
def process_lamp(self, data):
|
||||
@ -729,11 +774,22 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
:param data: Class that projector supports.
|
||||
"""
|
||||
# bug 1550891: Projector returns non-standard class response:
|
||||
# : Expected: %1CLSS=1
|
||||
# : Received: %1CLSS=Class 1
|
||||
# : Expected: '%1CLSS=1'
|
||||
# : Received: '%1CLSS=Class 1' (Optoma)
|
||||
# : Received: '%1CLSS=Version1' (BenQ)
|
||||
if len(data) > 1:
|
||||
# Split non-standard information from response
|
||||
clss = data.split()[-1]
|
||||
log.warn("({ip}) Non-standard CLSS reply: '{data}'".format(ip=self.ip, 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.
|
||||
try:
|
||||
clss = re.findall('\d', data)[0] # Should only be the first match
|
||||
except IndexError:
|
||||
log.error("({ip}) No numbers found in class version reply - defaulting to class '1'".format(ip=self.ip))
|
||||
clss = '1'
|
||||
elif not data.isdigit():
|
||||
log.error("({ip}) NAN class version reply - defaulting to class '1'".format(ip=self.ip))
|
||||
clss = '1'
|
||||
else:
|
||||
clss = data
|
||||
self.pjlink_class = clss
|
||||
@ -845,6 +901,42 @@ class PJLink(QtNetwork.QTcpSocket):
|
||||
PJLINK_ERST_STATUS[data[5]]
|
||||
return
|
||||
|
||||
def process_snum(self, data):
|
||||
"""
|
||||
Serial number of projector.
|
||||
|
||||
:param data: Serial number from projector.
|
||||
"""
|
||||
if self.serial_no is None:
|
||||
log.debug("({ip}) Setting projector serial number to '{data}'".format(ip=self.ip, data=data))
|
||||
self.serial_no = data
|
||||
self.db_update = False
|
||||
else:
|
||||
# Compare serial numbers and see if we got the same projector
|
||||
if self.serial_no != data:
|
||||
log.warn("({ip}) Projector serial number does not match saved serial number".format(ip=self.ip))
|
||||
log.warn("({ip}) Saved: '{old}'".format(ip=self.ip, old=self.serial_no))
|
||||
log.warn("({ip}) Received: '{new}'".format(ip=self.ip, new=data))
|
||||
log.warn("({ip}) NOT saving serial number".format(ip=self.ip))
|
||||
self.serial_no_received = data
|
||||
|
||||
def process_sver(self, data):
|
||||
"""
|
||||
Software version of projector
|
||||
"""
|
||||
if self.sw_version is None:
|
||||
log.debug("({ip}) Setting projector software version to '{data}'".format(ip=self.ip, data=data))
|
||||
self.sw_version = data
|
||||
self.db_update = True
|
||||
else:
|
||||
# Compare software version and see if we got the same projector
|
||||
if self.serial_no != data:
|
||||
log.warn("({ip}) Projector software version does not match saved software version".format(ip=self.ip))
|
||||
log.warn("({ip}) Saved: '{old}'".format(ip=self.ip, old=self.sw_version))
|
||||
log.warn("({ip}) Received: '{new}'".format(ip=self.ip, new=data))
|
||||
log.warn("({ip}) NOT saving serial number".format(ip=self.ip))
|
||||
self.sw_version_received = data
|
||||
|
||||
def connect_to_host(self):
|
||||
"""
|
||||
Initiate connection to projector.
|
||||
|
@ -71,10 +71,10 @@ log = logging.getLogger(__name__)
|
||||
|
||||
log.debug('pjlink2 loaded')
|
||||
|
||||
from PyQt5 import QtCore, QtNetwork
|
||||
from PyQt5 import QtNetwork
|
||||
|
||||
|
||||
class PJLinkUDP(QtNetwork.QTcpSocket):
|
||||
class PJLinkUDP(QtNetwork.QUdpSocket):
|
||||
"""
|
||||
Socket service for handling datagram (UDP) sockets.
|
||||
"""
|
||||
|
@ -25,12 +25,9 @@ backend for the projector setup.
|
||||
"""
|
||||
import logging
|
||||
|
||||
# Not all imports used at this time, but keep for future upgrades
|
||||
from sqlalchemy import Table, Column, types, inspect
|
||||
from sqlalchemy.exc import NoSuchTableError
|
||||
from sqlalchemy import Table, Column, types
|
||||
from sqlalchemy.sql.expression import null
|
||||
|
||||
from openlp.core.common.db import drop_columns
|
||||
from openlp.core.lib.db import get_upgrade_op
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
@ -420,9 +420,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
:param opt: Needed by PyQt5
|
||||
"""
|
||||
try:
|
||||
ip = opt.link.ip
|
||||
projector = opt
|
||||
projector.link.set_shutter_closed()
|
||||
opt.link.set_shutter_closed()
|
||||
except AttributeError:
|
||||
for list_item in self.projector_list_widget.selectedItems():
|
||||
if list_item is None:
|
||||
@ -455,9 +453,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
:param opt: Needed by PyQt5
|
||||
"""
|
||||
try:
|
||||
ip = opt.link.ip
|
||||
projector = opt
|
||||
projector.link.connect_to_host()
|
||||
opt.link.connect_to_host()
|
||||
except AttributeError:
|
||||
for list_item in self.projector_list_widget.selectedItems():
|
||||
if list_item is None:
|
||||
@ -527,7 +523,8 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
self.projector_list = new_list
|
||||
list_item = self.projector_list_widget.takeItem(self.projector_list_widget.currentRow())
|
||||
list_item = None
|
||||
deleted = self.projectordb.delete_projector(projector.db_item)
|
||||
if not self.projectordb.delete_projector(projector.db_item):
|
||||
log.warning('Delete projector {item} failed'.format(item=projector.db_item))
|
||||
for item in self.projector_list:
|
||||
log.debug('New projector list - item: {ip} {name}'.format(ip=item.link.ip, name=item.link.name))
|
||||
|
||||
@ -538,9 +535,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
:param opt: Needed by PyQt5
|
||||
"""
|
||||
try:
|
||||
ip = opt.link.ip
|
||||
projector = opt
|
||||
projector.link.disconnect_from_host()
|
||||
opt.link.disconnect_from_host()
|
||||
except AttributeError:
|
||||
for list_item in self.projector_list_widget.selectedItems():
|
||||
if list_item is None:
|
||||
@ -573,9 +568,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
:param opt: Needed by PyQt5
|
||||
"""
|
||||
try:
|
||||
ip = opt.link.ip
|
||||
projector = opt
|
||||
projector.link.set_power_off()
|
||||
opt.link.set_power_off()
|
||||
except AttributeError:
|
||||
for list_item in self.projector_list_widget.selectedItems():
|
||||
if list_item is None:
|
||||
@ -593,9 +586,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
:param opt: Needed by PyQt5
|
||||
"""
|
||||
try:
|
||||
ip = opt.link.ip
|
||||
projector = opt
|
||||
projector.link.set_power_on()
|
||||
opt.link.set_power_on()
|
||||
except AttributeError:
|
||||
for list_item in self.projector_list_widget.selectedItems():
|
||||
if list_item is None:
|
||||
@ -613,9 +604,7 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
:param opt: Needed by PyQt5
|
||||
"""
|
||||
try:
|
||||
ip = opt.link.ip
|
||||
projector = opt
|
||||
projector.link.set_shutter_open()
|
||||
opt.link.set_shutter_open()
|
||||
except AttributeError:
|
||||
for list_item in self.projector_list_widget.selectedItems():
|
||||
if list_item is None:
|
||||
@ -662,9 +651,10 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
data=translate('OpenLP.ProjectorManager', 'Closed')
|
||||
if projector.link.shutter
|
||||
else translate('OpenLP', 'Open'))
|
||||
message = '%s<b>%s</b>: %s<br />' % (message,
|
||||
translate('OpenLP.ProjectorManager', 'Current source input is'),
|
||||
projector.link.source)
|
||||
message = '{msg}<b>{source}</b>: {selected}<br />'.format(msg=message,
|
||||
source=translate('OpenLP.ProjectorManager',
|
||||
'Current source input is'),
|
||||
selected=projector.link.source)
|
||||
if projector.link.pjlink_class == '2':
|
||||
# Information only available for PJLink Class 2 projectors
|
||||
message += '<b>{title}</b>: {data}<br /><br />'.format(title=translate('OpenLP.ProjectorManager',
|
||||
@ -685,10 +675,10 @@ class ProjectorManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, UiProjecto
|
||||
'Lamp'),
|
||||
count=count,
|
||||
status=translate('OpenLP.ProjectorManager',
|
||||
' is on')
|
||||
'ON')
|
||||
if item['On']
|
||||
else translate('OpenLP.ProjectorManager',
|
||||
'is off'))
|
||||
'OFF'))
|
||||
|
||||
message += '<b>{title}</b>: {hours}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Hours'),
|
||||
hours=item['Hours'])
|
||||
|
@ -393,9 +393,9 @@ class SourceSelectSingle(QtWidgets.QDialog):
|
||||
QtCore.Qt.WindowCloseButtonHint)
|
||||
self.edit = edit
|
||||
if self.edit:
|
||||
title = translate('OpenLP.SourceSelectForm', 'Edit Projector Source Text')
|
||||
self.title = translate('OpenLP.SourceSelectForm', 'Edit Projector Source Text')
|
||||
else:
|
||||
title = translate('OpenLP.SourceSelectForm', 'Select Projector Source')
|
||||
self.title = translate('OpenLP.SourceSelectForm', 'Select Projector Source')
|
||||
self.setObjectName('source_select_single')
|
||||
self.setWindowIcon(build_icon(':/icon/openlp-log.svg'))
|
||||
self.setModal(True)
|
||||
|
12
setup.cfg
12
setup.cfg
@ -1,4 +1,14 @@
|
||||
# E402 module level import not at top of file
|
||||
# E722 do not use bare except, specify exception instead
|
||||
# F841 local variable '<variable>' is assigned to but never used
|
||||
|
||||
[pep8]
|
||||
exclude=resources.py,vlc.py
|
||||
max-line-length = 120
|
||||
ignore = E402,E722
|
||||
ignore = E402
|
||||
|
||||
[flake8]
|
||||
exclude=resources.py,vlc.py
|
||||
max-line-length = 120
|
||||
ignore = E402
|
||||
|
||||
|
@ -59,9 +59,101 @@ class TestPJLink(TestCase):
|
||||
self.assertTrue(mock_qmd5_hash.called_with(TEST_PIN,
|
||||
"Connection request should have been called with TEST_PIN"))
|
||||
|
||||
def test_projector_class(self):
|
||||
def test_projector_process_rfil_save(self):
|
||||
"""
|
||||
Test class version from projector
|
||||
Test saving filter type
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
pjlink.model_filter = None
|
||||
filter_model = 'Filter Type Test'
|
||||
|
||||
# WHEN: Filter model is received
|
||||
pjlink.process_rfil(data=filter_model)
|
||||
|
||||
# THEN: Filter model number should be saved
|
||||
self.assertEqual(pjlink.model_filter, filter_model, 'Filter type should have been saved')
|
||||
|
||||
def test_projector_process_rfil_nosave(self):
|
||||
"""
|
||||
Test saving filter type previously saved
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
pjlink.model_filter = 'Old filter type'
|
||||
filter_model = 'Filter Type Test'
|
||||
|
||||
# WHEN: Filter model is received
|
||||
pjlink.process_rfil(data=filter_model)
|
||||
|
||||
# THEN: Filter model number should be saved
|
||||
self.assertNotEquals(pjlink.model_filter, filter_model, 'Filter type should NOT have been saved')
|
||||
|
||||
def test_projector_process_rlmp_save(self):
|
||||
"""
|
||||
Test saving lamp type
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
pjlink.model_lamp = None
|
||||
lamp_model = 'Lamp Type Test'
|
||||
|
||||
# WHEN: Filter model is received
|
||||
pjlink.process_rlmp(data=lamp_model)
|
||||
|
||||
# THEN: Filter model number should be saved
|
||||
self.assertEqual(pjlink.model_lamp, lamp_model, 'Lamp type should have been saved')
|
||||
|
||||
def test_projector_process_rlmp_nosave(self):
|
||||
"""
|
||||
Test saving lamp type previously saved
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
pjlink.model_lamp = 'Old lamp type'
|
||||
lamp_model = 'Filter Type Test'
|
||||
|
||||
# WHEN: Filter model is received
|
||||
pjlink.process_rlmp(data=lamp_model)
|
||||
|
||||
# THEN: Filter model number should be saved
|
||||
self.assertNotEquals(pjlink.model_lamp, lamp_model, 'Lamp type should NOT have been saved')
|
||||
|
||||
def test_projector_process_snum_set(self):
|
||||
"""
|
||||
Test saving serial number from projector
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
pjlink.serial_no = None
|
||||
test_number = 'Test Serial Number'
|
||||
|
||||
# WHEN: No serial number is set and we receive serial number command
|
||||
pjlink.process_snum(data=test_number)
|
||||
|
||||
# THEN: Serial number should be set
|
||||
self.assertEqual(pjlink.serial_no, test_number,
|
||||
'Projector serial number should have been set')
|
||||
|
||||
def test_projector_process_snum_different(self):
|
||||
"""
|
||||
Test projector serial number different than saved serial number
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
pjlink.serial_no = 'Previous serial number'
|
||||
test_number = 'Test Serial Number'
|
||||
|
||||
# WHEN: No serial number is set and we receive serial number command
|
||||
pjlink.process_snum(data=test_number)
|
||||
|
||||
# THEN: Serial number should be set
|
||||
self.assertNotEquals(pjlink.serial_no, test_number,
|
||||
'Projector serial number should NOT have been set')
|
||||
|
||||
def test_projector_clss_one(self):
|
||||
"""
|
||||
Test class 1 sent from projector
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
@ -70,12 +162,26 @@ class TestPJLink(TestCase):
|
||||
pjlink.process_clss('1')
|
||||
|
||||
# THEN: Projector class should be set to 1
|
||||
self.assertEquals(pjlink.pjlink_class, '1',
|
||||
'Projector should have returned class=1')
|
||||
self.assertEqual(pjlink.pjlink_class, '1',
|
||||
'Projector should have returned class=1')
|
||||
|
||||
def test_non_standard_class_reply(self):
|
||||
def test_projector_clss_two(self):
|
||||
"""
|
||||
Bugfix 1550891: CLSS request returns non-standard 'Class N' reply
|
||||
Test class 2 sent from projector
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
|
||||
# WHEN: Process class response
|
||||
pjlink.process_clss('2')
|
||||
|
||||
# THEN: Projector class should be set to 1
|
||||
self.assertEqual(pjlink.pjlink_class, '2',
|
||||
'Projector should have returned class=2')
|
||||
|
||||
def test_bug_1550891_non_standard_class_reply(self):
|
||||
"""
|
||||
Bugfix 1550891: CLSS request returns non-standard reply
|
||||
"""
|
||||
# GIVEN: Test object
|
||||
pjlink = pjlink_test
|
||||
@ -84,8 +190,8 @@ class TestPJLink(TestCase):
|
||||
pjlink.process_clss('Class 1')
|
||||
|
||||
# THEN: Projector class should be set with proper value
|
||||
self.assertEquals(pjlink.pjlink_class, '1',
|
||||
'Non-standard class reply should have set proper class')
|
||||
self.assertEqual(pjlink.pjlink_class, '1',
|
||||
'Non-standard class reply should have set class=1')
|
||||
|
||||
@patch.object(pjlink_test, 'change_status')
|
||||
def test_status_change(self, mock_change_status):
|
||||
@ -131,10 +237,10 @@ class TestPJLink(TestCase):
|
||||
pjlink.process_command('LAMP', '22222 1')
|
||||
|
||||
# THEN: Lamp should have been set with status=ON and hours=22222
|
||||
self.assertEquals(pjlink.lamp[0]['On'], True,
|
||||
'Lamp power status should have been set to TRUE')
|
||||
self.assertEquals(pjlink.lamp[0]['Hours'], 22222,
|
||||
'Lamp hours should have been set to 22222')
|
||||
self.assertEqual(pjlink.lamp[0]['On'], True,
|
||||
'Lamp power status should have been set to TRUE')
|
||||
self.assertEqual(pjlink.lamp[0]['Hours'], 22222,
|
||||
'Lamp hours should have been set to 22222')
|
||||
|
||||
@patch.object(pjlink_test, 'projectorReceivedData')
|
||||
def test_projector_process_multiple_lamp(self, mock_projectorReceivedData):
|
||||
@ -148,20 +254,20 @@ class TestPJLink(TestCase):
|
||||
pjlink.process_command('LAMP', '11111 1 22222 0 33333 1')
|
||||
|
||||
# THEN: Lamp should have been set with proper lamp status
|
||||
self.assertEquals(len(pjlink.lamp), 3,
|
||||
'Projector should have 3 lamps specified')
|
||||
self.assertEquals(pjlink.lamp[0]['On'], True,
|
||||
'Lamp 1 power status should have been set to TRUE')
|
||||
self.assertEquals(pjlink.lamp[0]['Hours'], 11111,
|
||||
'Lamp 1 hours should have been set to 11111')
|
||||
self.assertEquals(pjlink.lamp[1]['On'], False,
|
||||
'Lamp 2 power status should have been set to FALSE')
|
||||
self.assertEquals(pjlink.lamp[1]['Hours'], 22222,
|
||||
'Lamp 2 hours should have been set to 22222')
|
||||
self.assertEquals(pjlink.lamp[2]['On'], True,
|
||||
'Lamp 3 power status should have been set to TRUE')
|
||||
self.assertEquals(pjlink.lamp[2]['Hours'], 33333,
|
||||
'Lamp 3 hours should have been set to 33333')
|
||||
self.assertEqual(len(pjlink.lamp), 3,
|
||||
'Projector should have 3 lamps specified')
|
||||
self.assertEqual(pjlink.lamp[0]['On'], True,
|
||||
'Lamp 1 power status should have been set to TRUE')
|
||||
self.assertEqual(pjlink.lamp[0]['Hours'], 11111,
|
||||
'Lamp 1 hours should have been set to 11111')
|
||||
self.assertEqual(pjlink.lamp[1]['On'], False,
|
||||
'Lamp 2 power status should have been set to FALSE')
|
||||
self.assertEqual(pjlink.lamp[1]['Hours'], 22222,
|
||||
'Lamp 2 hours should have been set to 22222')
|
||||
self.assertEqual(pjlink.lamp[2]['On'], True,
|
||||
'Lamp 3 power status should have been set to TRUE')
|
||||
self.assertEqual(pjlink.lamp[2]['Hours'], 33333,
|
||||
'Lamp 3 hours should have been set to 33333')
|
||||
|
||||
@patch.object(pjlink_test, 'projectorReceivedData')
|
||||
@patch.object(pjlink_test, 'projectorUpdateIcons')
|
||||
@ -182,9 +288,9 @@ class TestPJLink(TestCase):
|
||||
pjlink.process_command('POWR', PJLINK_POWR_STATUS[S_ON])
|
||||
|
||||
# THEN: Power should be set to ON
|
||||
self.assertEquals(pjlink.power, S_ON, 'Power should have been set to ON')
|
||||
self.assertEqual(pjlink.power, S_ON, 'Power should have been set to ON')
|
||||
mock_send_command.assert_called_once_with('INST')
|
||||
self.assertEquals(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')
|
||||
self.assertEqual(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')
|
||||
|
||||
@patch.object(pjlink_test, 'projectorReceivedData')
|
||||
@patch.object(pjlink_test, 'projectorUpdateIcons')
|
||||
@ -205,9 +311,9 @@ class TestPJLink(TestCase):
|
||||
pjlink.process_command('POWR', PJLINK_POWR_STATUS[S_STANDBY])
|
||||
|
||||
# THEN: Power should be set to STANDBY
|
||||
self.assertEquals(pjlink.power, S_STANDBY, 'Power should have been set to STANDBY')
|
||||
self.assertEquals(mock_send_command.called, False, 'send_command should not have been called')
|
||||
self.assertEquals(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')
|
||||
self.assertEqual(pjlink.power, S_STANDBY, 'Power should have been set to STANDBY')
|
||||
self.assertEqual(mock_send_command.called, False, 'send_command should not have been called')
|
||||
self.assertEqual(mock_UpdateIcons.emit.called, True, 'projectorUpdateIcons should have been called')
|
||||
|
||||
@patch.object(pjlink_test, 'projectorUpdateIcons')
|
||||
def test_projector_process_avmt_closed_unmuted(self, mock_projectorReceivedData):
|
||||
@ -289,7 +395,7 @@ class TestPJLink(TestCase):
|
||||
pjlink.process_inpt('1')
|
||||
|
||||
# THEN: Input selected should reflect current input
|
||||
self.assertEquals(pjlink.source, '1', 'Input source should be set to "1"')
|
||||
self.assertEqual(pjlink.source, '1', 'Input source should be set to "1"')
|
||||
|
||||
def test_projector_reset_information(self):
|
||||
"""
|
||||
@ -318,7 +424,7 @@ class TestPJLink(TestCase):
|
||||
pjlink.reset_information()
|
||||
|
||||
# THEN: All information should be reset and timers stopped
|
||||
self.assertEquals(pjlink.power, S_OFF, 'Projector power should be OFF')
|
||||
self.assertEqual(pjlink.power, S_OFF, 'Projector power should be OFF')
|
||||
self.assertIsNone(pjlink.pjlink_name, 'Projector pjlink_name should be None')
|
||||
self.assertIsNone(pjlink.manufacturer, 'Projector manufacturer should be None')
|
||||
self.assertIsNone(pjlink.model, 'Projector model should be None')
|
||||
@ -329,7 +435,7 @@ class TestPJLink(TestCase):
|
||||
self.assertIsNone(pjlink.source_available, 'Projector source_available should be None')
|
||||
self.assertIsNone(pjlink.source, 'Projector source should be None')
|
||||
self.assertIsNone(pjlink.other_info, 'Projector other_info should be None')
|
||||
self.assertEquals(pjlink.send_queue, [], 'Projector send_queue should be an empty list')
|
||||
self.assertEqual(pjlink.send_queue, [], 'Projector send_queue should be an empty list')
|
||||
self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False')
|
||||
self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called')
|
||||
self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called')
|
||||
@ -355,8 +461,8 @@ class TestPJLink(TestCase):
|
||||
# WHEN: call with authentication request and pin not set
|
||||
pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE)
|
||||
|
||||
# THEN: No Authentication signal should have been sent
|
||||
mock_authentication.emit.assert_called_with(pjlink.name)
|
||||
# THEN: 'No Authentication' signal should have been sent
|
||||
mock_authentication.emit.assert_called_with(pjlink.ip)
|
||||
|
||||
@patch.object(pjlink_test, 'waitForReadyRead')
|
||||
@patch.object(pjlink_test, 'state')
|
||||
@ -381,8 +487,8 @@ class TestPJLink(TestCase):
|
||||
pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE)
|
||||
|
||||
# THEN: send_command should have the proper authentication
|
||||
self.assertEquals("{test}".format(test=mock_send_command.call_args),
|
||||
"call(data='{hash}%1CLSS ?\\r')".format(hash=TEST_HASH))
|
||||
self.assertEqual("{test}".format(test=mock_send_command.call_args),
|
||||
"call(data='{hash}%1CLSS ?\\r')".format(hash=TEST_HASH))
|
||||
|
||||
@patch.object(pjlink_test, 'disconnect_from_host')
|
||||
def socket_abort_test(self, mock_disconnect):
|
||||
|
Loading…
Reference in New Issue
Block a user