openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #31834
[Merge] lp:~alisonken1/openlp/pjlink2-f into lp:openlp
Ken Roberts has proposed merging lp:~alisonken1/openlp/pjlink2-f into lp:openlp.
Commit message:
PJLink class 2 update F
Requested reviews:
OpenLP Core (openlp-core)
For more details, see:
https://code.launchpad.net/~alisonken1/openlp/pjlink2-f/+merge/326265
-- Added '# noqa' for flake8 to ignore specific line errors
-- Renamed test_projector_clssto 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
-- Added lamp model command
-- Added tests for filter/model commands
--------------------------------
lp:~alisonken1/openlp/pjlink2-f (revision 2752)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2096/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/2006/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1919/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Code_Analysis/1296/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Test_Coverage/1142/
[SUCCESS] https://ci.openlp.io/job/Branch-04c-Code_Analysis2/271/
[SUCCESS] https://ci.openlp.io/job/Branch-05-AppVeyor-Tests/116/
--
Your team OpenLP Core is requested to review the proposed merge of lp:~alisonken1/openlp/pjlink2-f into lp:openlp.
=== modified file 'openlp/core/lib/projector/db.py'
--- openlp/core/lib/projector/db.py 2017-06-01 22:35:57 +0000
+++ openlp/core/lib/projector/db.py 2017-06-25 02:30:08 +0000
@@ -303,7 +303,7 @@
: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
=== modified file 'openlp/core/lib/projector/pjlink1.py'
--- openlp/core/lib/projector/pjlink1.py 2017-06-17 00:25:06 +0000
+++ openlp/core/lib/projector/pjlink1.py 2017-06-25 02:30:08 +0000
@@ -44,6 +44,8 @@
__all__ = ['PJLink']
+import re
+
from codecs import decode
from PyQt5 import QtCore, QtNetwork
@@ -53,9 +55,12 @@
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
+# Possible future imports
+# from openlp.core.lib.projector.constants import PJLINK_DEFAULT_CODES
+
# Shortcuts
SocketError = QtNetwork.QAbstractSocket.SocketError
SocketSTate = QtNetwork.QAbstractSocket.SocketState
@@ -113,8 +118,13 @@
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 +168,9 @@
'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
}
def reset_information(self):
@@ -166,12 +178,16 @@
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 +204,6 @@
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):
@@ -249,7 +264,10 @@
# Restart timer
self.timer.start()
# These commands may change during connetion
- for command in ['POWR', 'ERST', 'LAMP', 'AVMT', 'INPT']:
+ 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 +280,38 @@
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):
"""
@@ -341,7 +391,7 @@
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)
+ dontcare = self.readLine(self.max_size) # noqa: F841
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
@@ -440,7 +490,8 @@
return
data_split = data.split('=')
try:
- (prefix, version, cmd, data) = (data_split[0][0], data_split[0][1], data_split[0][2:], data_split[1])
+ (prefix, version, cmd, data) = (data_split[0][0], data_split[0][1], # noqa: F841
+ data_split[0][2:], data_split[1])
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()))
@@ -729,11 +780,22 @@
: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 +907,42 @@
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.
=== modified file 'openlp/core/lib/projector/upgrade.py'
--- openlp/core/lib/projector/upgrade.py 2017-06-09 12:12:39 +0000
+++ openlp/core/lib/projector/upgrade.py 2017-06-25 02:30:08 +0000
@@ -25,16 +25,18 @@
"""
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__)
+# Possible future imports
+# from sqlalchemy.exc import NoSuchTableError
+# from sqlalchemy import inspect
+# from openlp.core.common.db import drop_columns
+
# Initial projector DB was unversioned
__version__ = 2
=== modified file 'setup.cfg'
--- setup.cfg 2017-02-26 21:14:49 +0000
+++ setup.cfg 2017-06-25 02:30:08 +0000
@@ -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
+
+[flake8]
+exclude=resources.py,vlc.py
+max-line-length = 120
+ignore = E402,E722
+
=== modified file 'tests/functional/openlp_core_lib/test_projector_constants.py'
--- tests/functional/openlp_core_lib/test_projector_constants.py 2017-06-01 22:35:57 +0000
+++ tests/functional/openlp_core_lib/test_projector_constants.py 2017-06-25 02:30:08 +0000
@@ -22,7 +22,7 @@
"""
Package to test the openlp.core.lib.projector.constants package.
"""
-from unittest import TestCase, skip
+from unittest import TestCase, skip # noqa: F401
class TestProjectorConstants(TestCase):
=== renamed file 'tests/functional/openlp_core_lib/test_projectordb.py' => 'tests/functional/openlp_core_lib/test_projector_db.py'
--- tests/functional/openlp_core_lib/test_projectordb.py 2017-06-01 22:35:57 +0000
+++ tests/functional/openlp_core_lib/test_projector_db.py 2017-06-25 02:30:08 +0000
@@ -29,8 +29,8 @@
import shutil
from tempfile import mkdtemp
-from unittest import TestCase, skip
-from unittest.mock import MagicMock, patch
+from unittest import TestCase, skip # noqa: F401
+from unittest.mock import MagicMock, patch # noqa: F401
from openlp.core.lib.projector import upgrade
from openlp.core.lib.db import upgrade_db
@@ -413,7 +413,7 @@
Test add_projector() fail
"""
# GIVEN: Test entry in the database
- ignore_result = self.projector.add_projector(Projector(**TEST1_DATA))
+ ignore_result = self.projector.add_projector(Projector(**TEST1_DATA)) # noqa: F841
# WHEN: Attempt to add same projector entry
results = self.projector.add_projector(Projector(**TEST1_DATA))
@@ -439,7 +439,7 @@
Test update_projector() when entry not in database
"""
# GIVEN: Projector entry in database
- ignore_result = self.projector.add_projector(Projector(**TEST1_DATA))
+ ignore_result = self.projector.add_projector(Projector(**TEST1_DATA)) # noqa: F841
projector = Projector(**TEST2_DATA)
# WHEN: Attempt to update data with a different ID
=== modified file 'tests/functional/openlp_core_lib/test_projector_pjlink1.py'
--- tests/functional/openlp_core_lib/test_projector_pjlink1.py 2017-05-27 18:21:24 +0000
+++ tests/functional/openlp_core_lib/test_projector_pjlink1.py 2017-06-25 02:30:08 +0000
@@ -59,9 +59,101 @@
self.assertTrue(mock_qmd5_hash.called_with(TEST_PIN,
"Connection request should have been called with TEST_PIN"))
- def test_projector_class(self):
- """
- Test class version from projector
+ def test_projector_process_rfil_save(self):
+ """
+ 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.assertEquals(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.assertEquals(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.assertEquals(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
@@ -73,9 +165,23 @@
self.assertEquals(pjlink.pjlink_class, '1',
'Projector should have returned class=1')
- def test_non_standard_class_reply(self):
- """
- Bugfix 1550891: CLSS request returns non-standard 'Class N' reply
+ def test_projector_clss_two(self):
+ """
+ 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.assertEquals(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
@@ -85,7 +191,7 @@
# THEN: Projector class should be set with proper value
self.assertEquals(pjlink.pjlink_class, '1',
- 'Non-standard class reply should have set proper class')
+ 'Non-standard class reply should have set class=1')
@patch.object(pjlink_test, 'change_status')
def test_status_change(self, mock_change_status):
Follow ups