← Back to team overview

openlp-core team mailing list archive

[Merge] lp:~alisonken1/openlp/pjlink2-k into lp:openlp

 

Ken Roberts has proposed merging lp:~alisonken1/openlp/pjlink2-k into lp:openlp.

Commit message:
PJLink2 update K

Requested reviews:
  OpenLP Core (openlp-core)

For more details, see:
https://code.launchpad.net/~alisonken1/openlp/pjlink2-k/+merge/331191

PJlink2 update K

- Update notes in PJLink-Notes.odt/update PDF
- Add PJLink.get_socket() (process socket data)
- Add PJLink.get_buffer() (process non-socket data)
- Update PJLink.get_data() to work with get_socket/get_buffer
- Cleanup ProjectorManager code
- Fix incorrect note reference to song db in test_projector_db
- Fix projector tests for change to PJLink() creation
- Start PJLinkUDP class
- Remove unused pjlink2.py module
- Code oops cleanups

[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2199/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/2102/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1989/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Code_Analysis/1359/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Test_Coverage/1192/
[SUCCESS] https://ci.openlp.io/job/Branch-04c-Code_Analysis2/322/
[FAILURE] https://ci.openlp.io/job/Branch-05-AppVeyor-Tests/162/

-- 
Your team OpenLP Core is requested to review the proposed merge of lp:~alisonken1/openlp/pjlink2-k into lp:openlp.
=== modified file 'documentation/PJLink_Notes.odt'
Binary files documentation/PJLink_Notes.odt	2017-09-09 06:57:21 +0000 and documentation/PJLink_Notes.odt	2017-09-22 12:12:22 +0000 differ
=== modified file 'documentation/PJLink_Notes.pdf'
Binary files documentation/PJLink_Notes.pdf	2017-09-09 06:57:21 +0000 and documentation/PJLink_Notes.pdf	2017-09-22 12:12:22 +0000 differ
=== modified file 'openlp/core/lib/projector/db.py'
--- openlp/core/lib/projector/db.py	2017-06-25 02:21:07 +0000
+++ openlp/core/lib/projector/db.py	2017-09-22 12:12:22 +0000
@@ -341,9 +341,9 @@
         """
         old_projector = self.get_object_filtered(Projector, Projector.ip == projector.ip)
         if old_projector is not None:
-            log.warning('add_new() skipping entry ip="{ip}" (Already saved)'.format(ip=old_projector.ip))
+            log.warning('add_projector() skipping entry ip="{ip}" (Already saved)'.format(ip=old_projector.ip))
             return False
-        log.debug('add_new() saving new entry')
+        log.debug('add_projector() saving new entry')
         log.debug('ip="{ip}", name="{name}", location="{location}"'.format(ip=projector.ip,
                                                                            name=projector.name,
                                                                            location=projector.location))

=== modified file 'openlp/core/lib/projector/pjlink.py'
--- openlp/core/lib/projector/pjlink.py	2017-08-23 19:46:30 +0000
+++ openlp/core/lib/projector/pjlink.py	2017-09-22 12:12:22 +0000
@@ -72,6 +72,28 @@
 PJLINK_SUFFIX = CR
 
 
+class PJLinkUDP(QtNetwork.QUdpSocket):
+    """
+    Socket service for PJLink UDP socket.
+    """
+    # New commands available in PJLink Class 2
+    pjlink_udp_commands = [
+        'ACKN',  # Class 2  (cmd is SRCH)
+        'ERST',  # Class 1/2
+        'INPT',  # Class 1/2
+        'LKUP',  # Class 2  (reply only - no cmd)
+        'POWR',  # Class 1/2
+        'SRCH'   # Class 2  (reply is ACKN)
+    ]
+
+    def __init__(self, port=PJLINK_PORT):
+        """
+        Initialize socket
+        """
+
+        self.port = port
+
+
 class PJLinkCommands(object):
     """
     Process replies from PJLink projector.
@@ -488,7 +510,7 @@
 
 class PJLink(PJLinkCommands, QtNetwork.QTcpSocket):
     """
-    Socket service for connecting to a PJLink-capable projector.
+    Socket service for PJLink TCP socket.
     """
     # Signals sent by this module
     changeStatus = QtCore.pyqtSignal(str, int, str)
@@ -499,43 +521,29 @@
     projectorReceivedData = QtCore.pyqtSignal()  # Notify when received data finished processing
     projectorUpdateIcons = QtCore.pyqtSignal()  # Update the status icons on toolbar
 
-    # New commands available in PJLink Class 2
-    pjlink_udp_commands = [
-        'ACKN',  # Class 2
-        'ERST',  # Class 1 or 2
-        'INPT',  # Class 1 or 2
-        'LKUP',  # Class 2
-        'POWR',  # Class 1 or 2
-        'SRCH'   # Class 2
-    ]
-
-    def __init__(self, port=PJLINK_PORT, *args, **kwargs):
+    def __init__(self, projector, *args, **kwargs):
         """
         Setup for instance.
         Options should be in kwargs except for port which does have a default.
 
-        :param name: Display name
-        :param ip: IP address to connect to
-        :param port: Port to use. Default to PJLINK_PORT
-        :param pin: Access pin (if needed)
+        :param projector: Database record of projector
 
         Optional parameters
-        :param dbid: Database ID number
-        :param location: Location where projector is physically located
-        :param notes: Extra notes about the projector
         :param poll_time: Time (in seconds) to poll connected projector
         :param socket_timeout: Time (in seconds) to abort the connection if no response
         """
-        log.debug('PJlink(args={args} kwargs={kwargs})'.format(args=args, kwargs=kwargs))
+        log.debug('PJlink(projector={projector}, args={args} kwargs={kwargs})'.format(projector=projector,
+                                                                                      args=args,
+                                                                                      kwargs=kwargs))
         super().__init__()
-        self.dbid = kwargs.get('dbid')
-        self.ip = kwargs.get('ip')
-        self.location = kwargs.get('location')
-        self.mac_adx = kwargs.get('mac_adx')
-        self.name = kwargs.get('name')
-        self.notes = kwargs.get('notes')
-        self.pin = kwargs.get('pin')
-        self.port = port
+        self.entry = projector
+        self.ip = self.entry.ip
+        self.location = self.entry.location
+        self.mac_adx = self.entry.mac_adx
+        self.name = self.entry.name
+        self.notes = self.entry.notes
+        self.pin = self.entry.pin
+        self.port = self.entry.port
         self.db_update = False  # Use to check if db needs to be updated prior to exiting
         # Poll time 20 seconds unless called with something else
         self.poll_time = 20000 if 'poll_time' not in kwargs else kwargs['poll_time'] * 1000
@@ -751,7 +759,7 @@
             self.change_status(E_AUTHENTICATION)
             log.debug('({ip}) emitting projectorAuthentication() signal'.format(ip=self.ip))
             return
-        elif data_check[1] == '0' and self.pin is not None:
+        elif (data_check[1] == '0') and (self.pin):
             # Pin set and no authentication needed
             log.warning('({ip}) Regular connection but PIN set'.format(ip=self.name))
             self.disconnect_from_host()
@@ -761,7 +769,7 @@
             return
         elif data_check[1] == '1':
             # Authenticated login with salt
-            if self.pin is None:
+            if not self.pin:
                 log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.ip))
                 self.disconnect_from_host()
                 self.change_status(E_AUTHENTICATION)
@@ -776,7 +784,7 @@
         else:
             data_hash = None
         # We're connected at this point, so go ahead and setup regular I/O
-        self.readyRead.connect(self.get_data)
+        self.readyRead.connect(self.get_socket)
         self.projectorReceivedData.connect(self._send_command)
         # Initial data we should know about
         self.send_command(cmd='CLSS', salt=data_hash)
@@ -800,27 +808,51 @@
                                                                                    count=trash_count))
         return
 
+    @QtCore.pyqtSlot(str, str)
+    def get_buffer(self, data, ip):
+        """
+        Get data from somewhere other than TCP socket
+
+        :param data:  Data to process. buffer must be formatted as a proper PJLink packet.
+        :param ip:      Destination IP for buffer.
+        """
+        log.debug("({ip}) get_buffer(data='{buff}' ip='{ip_in}'".format(ip=self.ip, buff=data, ip_in=ip))
+        if ip is None:
+            log.debug("({ip}) get_buffer() Don't know who data is for - exiting".format(ip=self.ip))
+            return
+        return self.get_data(buff=data, ip=ip)
+
     @QtCore.pyqtSlot()
-    def get_data(self):
-        """
-        Socket interface to retrieve data.
-        """
-        log.debug('({ip}) get_data(): Reading data'.format(ip=self.ip))
+    def get_socket(self):
+        """
+        Get data from TCP socket.
+        """
+        log.debug('({ip}) get_socket(): Reading data'.format(ip=self.ip))
         if self.state() != self.ConnectedState:
-            log.debug('({ip}) get_data(): Not connected - returning'.format(ip=self.ip))
+            log.debug('({ip}) get_socket(): Not connected - returning'.format(ip=self.ip))
             self.send_busy = False
             return
         # Although we have a packet length limit, go ahead and use a larger buffer
         read = self.readLine(1024)
-        log.debug("({ip}) get_data(): '{buff}'".format(ip=self.ip, buff=read))
+        log.debug("({ip}) get_socket(): '{buff}'".format(ip=self.ip, buff=read))
         if read == -1:
             # No data available
-            log.debug('({ip}) get_data(): No data available (-1)'.format(ip=self.ip))
+            log.debug('({ip}) get_socket(): No data available (-1)'.format(ip=self.ip))
             return self.receive_data_signal()
         self.socket_timer.stop()
         self.projectorNetwork.emit(S_NETWORK_RECEIVED)
+        return self.get_data(buff=read, ip=self.ip)
+
+    def get_data(self, buff, ip):
+        """
+        Process received data
+
+        :param buff:    Data to process.
+        :param ip:      (optional) Destination IP.
+        """
+        log.debug("({ip}) get_data(ip='{ip_in}' buffer='{buff}'".format(ip=self.ip, ip_in=ip, buff=buff))
         # NOTE: Class2 has changed to some values being UTF-8
-        data_in = decode(read, 'utf-8')
+        data_in = decode(buff, 'utf-8')
         data = data_in.strip()
         if (len(data) < 7) or (not data.startswith(PJLINK_PREFIX)):
             return self._trash_buffer(msg='get_data(): Invalid packet - length or prefix')
@@ -990,7 +1022,7 @@
             self.reset_information()
         self.disconnectFromHost()
         try:
-            self.readyRead.disconnect(self.get_data)
+            self.readyRead.disconnect(self.get_socket)
         except TypeError:
             pass
         if abort:

=== removed file 'openlp/core/lib/projector/pjlink2.py'
--- openlp/core/lib/projector/pjlink2.py	2017-07-07 23:43:50 +0000
+++ openlp/core/lib/projector/pjlink2.py	1970-01-01 00:00:00 +0000
@@ -1,85 +0,0 @@
-# -*- coding: utf-8 -*-
-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
-
-###############################################################################
-# OpenLP - Open Source Lyrics Projection                                      #
-# --------------------------------------------------------------------------- #
-# Copyright (c) 2008-2017 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                          #
-###############################################################################
-"""
-    :mod:`openlp.core.lib.projector.pjlink2` module provides the PJLink Class 2
-    updates from PJLink Class 1.
-
-    This module only handles the UDP socket functionality. Command/query/status
-    change messages will still be processed by the PJLink 1 module.
-
-    Currently, the only variance is the addition of a UDP "search" command to
-    query the local network for Class 2 capable projectors,
-    and UDP "notify" messages from projectors to connected software of status
-    changes (i.e., power change, input change, error changes).
-
-    Differences between Class 1 and Class 2 PJLink specifications are as follows.
-
-    New Functionality:
-        * Search - UDP Query local network for Class 2 capabable projector(s).
-        * Status - UDP Status change with connected projector(s). Status change
-            messages consist of:
-            * Initial projector power up when network communication becomes available
-            * Lamp off/standby to warmup or on
-            * Lamp on to cooldown or off/standby
-            * Input source select change completed
-            * Error status change (i.e., fan/lamp/temp/cover open/filter/other error(s))
-
-    New Commands:
-        * Query serial number of projector
-        * Query version number of projector software
-        * Query model number of replacement lamp
-        * Query model number of replacement air filter
-        * Query current projector screen resolution
-        * Query recommended screen resolution
-        * Query name of specific input terminal (video source)
-        * Adjust projector microphone in 1-step increments
-        * Adjust projector speacker in 1-step increments
-
-    Extended Commands:
-        * Addition of INTERNAL terminal (video source) for a total of 6 types of terminals.
-        * Number of terminals (video source) has been expanded from [1-9]
-            to [1-9a-z] (Addition of 26 terminals for each type of input).
-
-    See PJLink Class 2 Specifications for details.
-    http://pjlink.jbmia.or.jp/english/dl_class2.html
-
-        Section 5-1 PJLink Specifications
-
-        Section 5-5 Guidelines for Input Terminals
-"""
-import logging
-log = logging.getLogger(__name__)
-
-log.debug('pjlink2 loaded')
-
-from PyQt5 import QtNetwork
-
-
-class PJLinkUDP(QtNetwork.QUdpSocket):
-    """
-    Socket service for handling datagram (UDP) sockets.
-    """
-    log.debug('PJLinkUDP loaded')
-    # Class varialbe for projector list. Should be replaced by ProjectorManager's
-    # projector list after being loaded there.
-    projector_list = None
-    projectors_found = None  # UDP search found list

=== modified file 'openlp/core/ui/projector/manager.py'
--- openlp/core/ui/projector/manager.py	2017-08-06 07:23:26 +0000
+++ openlp/core/ui/projector/manager.py	2017-09-22 12:12:22 +0000
@@ -38,8 +38,7 @@
     E_NETWORK, E_NOT_CONNECTED, E_UNKNOWN_SOCKET_ERROR, STATUS_STRING, S_CONNECTED, S_CONNECTING, S_COOLDOWN, \
     S_INITIALIZE, S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP
 from openlp.core.lib.projector.db import ProjectorDB
-from openlp.core.lib.projector.pjlink import PJLink
-from openlp.core.lib.projector.pjlink2 import PJLinkUDP
+from openlp.core.lib.projector.pjlink import PJLink, PJLinkUDP
 from openlp.core.ui.projector.editform import ProjectorEditForm
 from openlp.core.ui.projector.sourceselectform import SourceSelectTabs, SourceSelectSingle
 
@@ -700,16 +699,9 @@
         :returns: PJLink() instance
         """
         log.debug('_add_projector()')
-        return PJLink(dbid=projector.id,
-                      ip=projector.ip,
-                      port=int(projector.port),
-                      name=projector.name,
-                      location=projector.location,
-                      notes=projector.notes,
-                      pin=None if projector.pin == '' else projector.pin,
+        return PJLink(projector=projector,
                       poll_time=self.poll_time,
-                      socket_timeout=self.socket_timeout
-                      )
+                      socket_timeout=self.socket_timeout)
 
     def add_projector(self, projector, start=False):
         """

=== modified file 'tests/functional/openlp_core_lib/test_projector_db.py'
--- tests/functional/openlp_core_lib/test_projector_db.py	2017-08-06 07:23:26 +0000
+++ tests/functional/openlp_core_lib/test_projector_db.py	2017-09-22 12:12:22 +0000
@@ -111,7 +111,7 @@
         """
         Test that we can upgrade an old song db to the current schema
         """
-        # GIVEN: An old song db
+        # GIVEN: An old prjector db
         old_db = os.path.join(TEST_RESOURCES_PATH, "projector", TEST_DB_PJLINK1)
         tmp_db = os.path.join(self.tmp_folder, TEST_DB)
         shutil.copyfile(old_db, tmp_db)

=== modified file 'tests/functional/openlp_core_lib/test_projector_pjlink_base.py'
--- tests/functional/openlp_core_lib/test_projector_pjlink_base.py	2017-08-06 07:23:26 +0000
+++ tests/functional/openlp_core_lib/test_projector_pjlink_base.py	2017-09-22 12:12:22 +0000
@@ -25,12 +25,13 @@
 from unittest import TestCase
 from unittest.mock import call, patch, MagicMock
 
+from openlp.core.lib.projector.db import Projector
 from openlp.core.lib.projector.pjlink import PJLink
 from openlp.core.lib.projector.constants import E_PARAMETER, ERROR_STRING, S_ON, S_CONNECTED
 
-from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE, TEST_HASH
+from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE, TEST_HASH, TEST1_DATA
 
-pjlink_test = PJLink(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True)
+pjlink_test = PJLink(Projector(**TEST1_DATA), no_poll=True)
 
 
 class TestPJLinkBase(TestCase):

=== modified file 'tests/functional/openlp_core_lib/test_projector_pjlink_cmd_routing.py'
--- tests/functional/openlp_core_lib/test_projector_pjlink_cmd_routing.py	2017-08-12 20:38:50 +0000
+++ tests/functional/openlp_core_lib/test_projector_pjlink_cmd_routing.py	2017-09-22 12:12:22 +0000
@@ -27,6 +27,7 @@
 from unittest.mock import patch, MagicMock
 
 import openlp.core.lib.projector.pjlink
+from openlp.core.lib.projector.db import Projector
 from openlp.core.lib.projector.pjlink import PJLink
 from openlp.core.lib.projector.constants import PJLINK_ERRORS, \
     E_AUTHENTICATION, E_PARAMETER, E_PROJECTOR, E_UNAVAILABLE, E_UNDEFINED
@@ -35,9 +36,10 @@
 from openlp.core.lib.projector.constants import ERROR_STRING, PJLINK_ERST_DATA, PJLINK_ERST_STATUS, \
     PJLINK_POWR_STATUS, PJLINK_VALID_CMD, E_WARN, E_ERROR, S_OFF, S_STANDBY, S_ON
 '''
-from tests.resources.projector.data import TEST_PIN
+from tests.resources.projector.data import TEST_PIN, TEST1_DATA
 
-pjlink_test = PJLink(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True)
+pjlink_test = PJLink(Projector(**TEST1_DATA), pin=TEST_PIN, no_poll=True)
+pjlink_test.ip = '127.0.0.1'
 
 
 class TestPJLinkRouting(TestCase):

=== modified file 'tests/functional/openlp_core_lib/test_projector_pjlink_commands.py'
--- tests/functional/openlp_core_lib/test_projector_pjlink_commands.py	2017-08-12 20:38:50 +0000
+++ tests/functional/openlp_core_lib/test_projector_pjlink_commands.py	2017-09-22 12:12:22 +0000
@@ -26,15 +26,17 @@
 from unittest.mock import patch
 
 import openlp.core.lib.projector.pjlink
+from openlp.core.lib.projector.db import Projector
 from openlp.core.lib.projector.pjlink import PJLink
 from openlp.core.lib.projector.constants import ERROR_STRING, PJLINK_ERST_DATA, PJLINK_ERST_STATUS, \
     PJLINK_POWR_STATUS, \
     E_ERROR, E_NOT_CONNECTED, E_SOCKET_ADDRESS_NOT_AVAILABLE, E_UNKNOWN_SOCKET_ERROR, E_WARN, \
     S_CONNECTED, S_OFF, S_ON, S_NOT_CONNECTED, S_CONNECTING, S_STANDBY
 
-from tests.resources.projector.data import TEST_PIN
+from tests.resources.projector.data import TEST_PIN, TEST1_DATA
 
-pjlink_test = PJLink(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True)
+pjlink_test = PJLink(Projector(**TEST1_DATA), pin=TEST_PIN, no_poll=True)
+pjlink_test.ip = '127.0.0.1'
 
 # Create a list of ERST positional data so we don't have to redo the same buildup multiple times
 PJLINK_ERST_POSITIONS = []


Follow ups