forked from openlp/openlp
PJLink Updates N
This commit is contained in:
parent
6e2bc427a7
commit
598a373929
@ -32,9 +32,128 @@ log.debug('projector_constants loaded')
|
|||||||
# Set common constants.
|
# Set common constants.
|
||||||
CR = chr(0x0D) # \r
|
CR = chr(0x0D) # \r
|
||||||
LF = chr(0x0A) # \n
|
LF = chr(0x0A) # \n
|
||||||
PJLINK_PORT = 4352
|
PJLINK_CLASS = '1' # Default to class 1 until we query the projector
|
||||||
TIMEOUT = 30.0
|
|
||||||
PJLINK_MAX_PACKET = 136
|
PJLINK_MAX_PACKET = 136
|
||||||
|
PJLINK_PREFIX = '%'
|
||||||
|
PJLINK_PORT = 4352
|
||||||
|
PJLINK_SUFFIX = CR
|
||||||
|
PJLINK_TIMEOUT = 30.0
|
||||||
|
|
||||||
|
# Error and status codes
|
||||||
|
S_OK = E_OK = 0 # E_OK included since I sometimes forget
|
||||||
|
|
||||||
|
# Error codes. Start at 200 so we don't duplicate system error codes.
|
||||||
|
E_GENERAL = 200 # Unknown error
|
||||||
|
E_NOT_CONNECTED = 201
|
||||||
|
E_UNDEFINED = 202 # PJLink ERR1
|
||||||
|
E_PARAMETER = 203 # PJLink ERR2
|
||||||
|
E_UNAVAILABLE = 204 # PJLink ERR3
|
||||||
|
E_PROJECTOR = 205 # PJLink ERR4
|
||||||
|
E_AUTHENTICATION = 206 # PJLink ERRA
|
||||||
|
E_NO_AUTHENTICATION = 207 # PJLink authentication mismatch between projector and program
|
||||||
|
E_PREFIX = 208 # PJLink invalid prefix for packet
|
||||||
|
E_CLASS = 209 # PJLink class version mismatch
|
||||||
|
E_INVALID_DATA = 210
|
||||||
|
E_WARN = 211
|
||||||
|
E_ERROR = 212
|
||||||
|
E_FAN = 213
|
||||||
|
E_LAMP = 214
|
||||||
|
E_TEMP = 215
|
||||||
|
E_COVER = 216
|
||||||
|
E_FILTER = 217
|
||||||
|
E_UNKNOWN = 218
|
||||||
|
|
||||||
|
# Remap Qt socket error codes to local error codes
|
||||||
|
E_CONNECTION_REFUSED = 230
|
||||||
|
E_REMOTE_HOST_CLOSED_CONNECTION = 231
|
||||||
|
E_HOST_NOT_FOUND = 232
|
||||||
|
E_SOCKET_ACCESS = 233
|
||||||
|
E_SOCKET_RESOURCE = 234
|
||||||
|
E_SOCKET_TIMEOUT = 235
|
||||||
|
E_DATAGRAM_TOO_LARGE = 236
|
||||||
|
E_NETWORK = 237
|
||||||
|
E_ADDRESS_IN_USE = 238
|
||||||
|
E_SOCKET_ADDRESS_NOT_AVAILABLE = 239
|
||||||
|
E_UNSUPPORTED_SOCKET_OPERATION = 240
|
||||||
|
E_PROXY_AUTHENTICATION_REQUIRED = 241
|
||||||
|
E_SLS_HANDSHAKE_FAILED = 242
|
||||||
|
E_UNFINISHED_SOCKET_OPERATION = 243
|
||||||
|
E_PROXY_CONNECTION_REFUSED = 244
|
||||||
|
E_PROXY_CONNECTION_CLOSED = 245
|
||||||
|
E_PROXY_CONNECTION_TIMEOUT = 246
|
||||||
|
E_PROXY_NOT_FOUND = 247
|
||||||
|
E_PROXY_PROTOCOL = 248
|
||||||
|
E_UNKNOWN_SOCKET_ERROR = 249
|
||||||
|
|
||||||
|
# Status codes start at 300
|
||||||
|
|
||||||
|
# Remap Qt socket states to local status codes
|
||||||
|
S_NOT_CONNECTED = 300
|
||||||
|
S_HOST_LOOKUP = 301
|
||||||
|
S_CONNECTING = 302
|
||||||
|
S_CONNECTED = 303
|
||||||
|
S_BOUND = 304
|
||||||
|
S_LISTENING = 305 # Listed as internal use only in QAbstractSocket
|
||||||
|
S_CLOSING = 306
|
||||||
|
|
||||||
|
# Projector states
|
||||||
|
S_INITIALIZE = 310
|
||||||
|
S_STATUS = 311
|
||||||
|
S_OFF = 312
|
||||||
|
S_STANDBY = 313
|
||||||
|
S_WARMUP = 314
|
||||||
|
S_ON = 315
|
||||||
|
S_COOLDOWN = 316
|
||||||
|
S_INFO = 317
|
||||||
|
|
||||||
|
# Information that does not affect status
|
||||||
|
S_NETWORK_IDLE = 400
|
||||||
|
S_NETWORK_SENDING = 401
|
||||||
|
S_NETWORK_RECEIVING = 402
|
||||||
|
|
||||||
|
# Map PJlink errors to local status
|
||||||
|
PJLINK_ERRORS = {
|
||||||
|
'ERRA': E_AUTHENTICATION, # Authentication error
|
||||||
|
'ERR1': E_UNDEFINED, # Undefined command error
|
||||||
|
'ERR2': E_PARAMETER, # Invalid parameter error
|
||||||
|
'ERR3': E_UNAVAILABLE, # Projector busy
|
||||||
|
'ERR4': E_PROJECTOR, # Projector or display failure
|
||||||
|
E_AUTHENTICATION: 'ERRA',
|
||||||
|
E_UNDEFINED: 'ERR1',
|
||||||
|
E_PARAMETER: 'ERR2',
|
||||||
|
E_UNAVAILABLE: 'ERR3',
|
||||||
|
E_PROJECTOR: 'ERR4'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Map QAbstractSocketState enums to local status
|
||||||
|
QSOCKET_STATE = {
|
||||||
|
0: S_NOT_CONNECTED, # 'UnconnectedState',
|
||||||
|
1: S_HOST_LOOKUP, # 'HostLookupState',
|
||||||
|
2: S_CONNECTING, # 'ConnectingState',
|
||||||
|
3: S_CONNECTED, # 'ConnectedState',
|
||||||
|
4: S_BOUND, # 'BoundState',
|
||||||
|
5: S_LISTENING, # 'ListeningState' - Noted as "Internal Use Only" on Qt website
|
||||||
|
6: S_CLOSING, # 'ClosingState',
|
||||||
|
S_NOT_CONNECTED: 0,
|
||||||
|
S_HOST_LOOKUP: 1,
|
||||||
|
S_CONNECTING: 2,
|
||||||
|
S_CONNECTED: 3,
|
||||||
|
S_BOUND: 4,
|
||||||
|
S_LISTENING: 5,
|
||||||
|
S_CLOSING: 6
|
||||||
|
}
|
||||||
|
|
||||||
|
PROJECTOR_STATE = [
|
||||||
|
S_INITIALIZE,
|
||||||
|
S_STATUS,
|
||||||
|
S_OFF,
|
||||||
|
S_STANDBY,
|
||||||
|
S_WARMUP,
|
||||||
|
S_ON,
|
||||||
|
S_COOLDOWN,
|
||||||
|
S_INFO
|
||||||
|
]
|
||||||
|
|
||||||
# NOTE: Changed format to account for some commands are both class 1 and 2
|
# NOTE: Changed format to account for some commands are both class 1 and 2
|
||||||
PJLINK_VALID_CMD = {
|
PJLINK_VALID_CMD = {
|
||||||
'ACKN': {'version': ['2', ],
|
'ACKN': {'version': ['2', ],
|
||||||
@ -144,227 +263,140 @@ PJLINK_VALID_CMD = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# QAbstractSocketState enums converted to string
|
CONNECTION_ERRORS = [
|
||||||
S_QSOCKET_STATE = {
|
E_ADDRESS_IN_USE,
|
||||||
0: 'QSocketState - UnconnectedState',
|
E_CONNECTION_REFUSED,
|
||||||
1: 'QSocketState - HostLookupState',
|
E_DATAGRAM_TOO_LARGE,
|
||||||
2: 'QSocketState - ConnectingState',
|
E_HOST_NOT_FOUND,
|
||||||
3: 'QSocketState - ConnectedState',
|
E_NETWORK,
|
||||||
4: 'QSocketState - BoundState',
|
E_NOT_CONNECTED,
|
||||||
5: 'QSocketState - ListeningState (internal use only)',
|
E_PROXY_AUTHENTICATION_REQUIRED,
|
||||||
6: 'QSocketState - ClosingState',
|
E_PROXY_CONNECTION_CLOSED,
|
||||||
'UnconnectedState': 0,
|
E_PROXY_CONNECTION_REFUSED,
|
||||||
'HostLookupState': 1,
|
E_PROXY_CONNECTION_TIMEOUT,
|
||||||
'ConnectingState': 2,
|
E_PROXY_NOT_FOUND,
|
||||||
'ConnectedState': 3,
|
E_PROXY_PROTOCOL,
|
||||||
'BoundState': 4,
|
E_REMOTE_HOST_CLOSED_CONNECTION,
|
||||||
'ListeningState': 5,
|
E_SLS_HANDSHAKE_FAILED,
|
||||||
'ClosingState': 6
|
E_SOCKET_ACCESS,
|
||||||
}
|
E_SOCKET_ADDRESS_NOT_AVAILABLE,
|
||||||
|
E_SOCKET_RESOURCE,
|
||||||
|
E_SOCKET_TIMEOUT,
|
||||||
|
E_UNFINISHED_SOCKET_OPERATION,
|
||||||
|
E_UNKNOWN_SOCKET_ERROR,
|
||||||
|
E_UNSUPPORTED_SOCKET_OPERATION
|
||||||
|
]
|
||||||
|
|
||||||
# Error and status codes
|
PROJECTOR_ERRORS = [
|
||||||
S_OK = E_OK = 0 # E_OK included since I sometimes forget
|
E_AUTHENTICATION,
|
||||||
# Error codes. Start at 200 so we don't duplicate system error codes.
|
E_CLASS,
|
||||||
E_GENERAL = 200 # Unknown error
|
E_INVALID_DATA,
|
||||||
E_NOT_CONNECTED = 201
|
E_NO_AUTHENTICATION,
|
||||||
E_FAN = 202
|
E_PARAMETER,
|
||||||
E_LAMP = 203
|
E_PREFIX,
|
||||||
E_TEMP = 204
|
E_PROJECTOR,
|
||||||
E_COVER = 205
|
E_UNAVAILABLE,
|
||||||
E_FILTER = 206
|
E_UNDEFINED,
|
||||||
E_NO_AUTHENTICATION = 207 # PIN set and no authentication set on projector
|
E_UNKNOWN
|
||||||
E_UNDEFINED = 208 # ERR1
|
]
|
||||||
E_PARAMETER = 209 # ERR2
|
|
||||||
E_UNAVAILABLE = 210 # ERR3
|
|
||||||
E_PROJECTOR = 211 # ERR4
|
|
||||||
E_INVALID_DATA = 212
|
|
||||||
E_WARN = 213
|
|
||||||
E_ERROR = 214
|
|
||||||
E_AUTHENTICATION = 215 # ERRA
|
|
||||||
E_CLASS = 216
|
|
||||||
E_PREFIX = 217
|
|
||||||
|
|
||||||
# Remap Qt socket error codes to projector error codes
|
# Show status code as string
|
||||||
E_CONNECTION_REFUSED = 230
|
STATUS_CODE = {
|
||||||
E_REMOTE_HOST_CLOSED_CONNECTION = 231
|
|
||||||
E_HOST_NOT_FOUND = 232
|
|
||||||
E_SOCKET_ACCESS = 233
|
|
||||||
E_SOCKET_RESOURCE = 234
|
|
||||||
E_SOCKET_TIMEOUT = 235
|
|
||||||
E_DATAGRAM_TOO_LARGE = 236
|
|
||||||
E_NETWORK = 237
|
|
||||||
E_ADDRESS_IN_USE = 238
|
|
||||||
E_SOCKET_ADDRESS_NOT_AVAILABLE = 239
|
|
||||||
E_UNSUPPORTED_SOCKET_OPERATION = 240
|
|
||||||
E_PROXY_AUTHENTICATION_REQUIRED = 241
|
|
||||||
E_SLS_HANDSHAKE_FAILED = 242
|
|
||||||
E_UNFINISHED_SOCKET_OPERATION = 243
|
|
||||||
E_PROXY_CONNECTION_REFUSED = 244
|
|
||||||
E_PROXY_CONNECTION_CLOSED = 245
|
|
||||||
E_PROXY_CONNECTION_TIMEOUT = 246
|
|
||||||
E_PROXY_NOT_FOUND = 247
|
|
||||||
E_PROXY_PROTOCOL = 248
|
|
||||||
E_UNKNOWN_SOCKET_ERROR = -1
|
|
||||||
|
|
||||||
# Status codes start at 300
|
|
||||||
S_NOT_CONNECTED = 300
|
|
||||||
S_CONNECTING = 301
|
|
||||||
S_CONNECTED = 302
|
|
||||||
S_INITIALIZE = 303
|
|
||||||
S_STATUS = 304
|
|
||||||
S_OFF = 305
|
|
||||||
S_STANDBY = 306
|
|
||||||
S_WARMUP = 307
|
|
||||||
S_ON = 308
|
|
||||||
S_COOLDOWN = 309
|
|
||||||
S_INFO = 310
|
|
||||||
|
|
||||||
# Information that does not affect status
|
|
||||||
S_NETWORK_SENDING = 400
|
|
||||||
S_NETWORK_RECEIVED = 401
|
|
||||||
|
|
||||||
CONNECTION_ERRORS = {
|
|
||||||
E_NOT_CONNECTED, E_NO_AUTHENTICATION, E_AUTHENTICATION, E_CLASS,
|
|
||||||
E_PREFIX, E_CONNECTION_REFUSED, E_REMOTE_HOST_CLOSED_CONNECTION,
|
|
||||||
E_HOST_NOT_FOUND, E_SOCKET_ACCESS, E_SOCKET_RESOURCE, E_SOCKET_TIMEOUT,
|
|
||||||
E_DATAGRAM_TOO_LARGE, E_NETWORK, E_ADDRESS_IN_USE, E_SOCKET_ADDRESS_NOT_AVAILABLE,
|
|
||||||
E_UNSUPPORTED_SOCKET_OPERATION, E_PROXY_AUTHENTICATION_REQUIRED,
|
|
||||||
E_SLS_HANDSHAKE_FAILED, E_UNFINISHED_SOCKET_OPERATION, E_PROXY_CONNECTION_REFUSED,
|
|
||||||
E_PROXY_CONNECTION_CLOSED, E_PROXY_CONNECTION_TIMEOUT, E_PROXY_NOT_FOUND,
|
|
||||||
E_PROXY_PROTOCOL, E_UNKNOWN_SOCKET_ERROR
|
|
||||||
}
|
|
||||||
|
|
||||||
PJLINK_ERRORS = {
|
|
||||||
'ERRA': E_AUTHENTICATION, # Authentication error
|
|
||||||
'ERR1': E_UNDEFINED, # Undefined command error
|
|
||||||
'ERR2': E_PARAMETER, # Invalid parameter error
|
|
||||||
'ERR3': E_UNAVAILABLE, # Projector busy
|
|
||||||
'ERR4': E_PROJECTOR, # Projector or display failure
|
|
||||||
E_AUTHENTICATION: 'ERRA',
|
|
||||||
E_UNDEFINED: 'ERR1',
|
|
||||||
E_PARAMETER: 'ERR2',
|
|
||||||
E_UNAVAILABLE: 'ERR3',
|
|
||||||
E_PROJECTOR: 'ERR4'
|
|
||||||
}
|
|
||||||
|
|
||||||
# Map error/status codes to string
|
|
||||||
ERROR_STRING = {
|
|
||||||
0: 'S_OK',
|
|
||||||
E_GENERAL: 'E_GENERAL',
|
|
||||||
E_NOT_CONNECTED: 'E_NOT_CONNECTED',
|
|
||||||
E_FAN: 'E_FAN',
|
|
||||||
E_LAMP: 'E_LAMP',
|
|
||||||
E_TEMP: 'E_TEMP',
|
|
||||||
E_COVER: 'E_COVER',
|
|
||||||
E_FILTER: 'E_FILTER',
|
|
||||||
E_AUTHENTICATION: 'E_AUTHENTICATION',
|
|
||||||
E_NO_AUTHENTICATION: 'E_NO_AUTHENTICATION',
|
|
||||||
E_UNDEFINED: 'E_UNDEFINED',
|
|
||||||
E_PARAMETER: 'E_PARAMETER',
|
|
||||||
E_UNAVAILABLE: 'E_UNAVAILABLE',
|
|
||||||
E_PROJECTOR: 'E_PROJECTOR',
|
|
||||||
E_INVALID_DATA: 'E_INVALID_DATA',
|
|
||||||
E_WARN: 'E_WARN',
|
|
||||||
E_ERROR: 'E_ERROR',
|
|
||||||
E_CLASS: 'E_CLASS',
|
|
||||||
E_PREFIX: 'E_PREFIX', # Last projector error
|
|
||||||
E_CONNECTION_REFUSED: 'E_CONNECTION_REFUSED', # First QtSocket error
|
|
||||||
E_REMOTE_HOST_CLOSED_CONNECTION: 'E_REMOTE_HOST_CLOSED_CONNECTION',
|
|
||||||
E_HOST_NOT_FOUND: 'E_HOST_NOT_FOUND',
|
|
||||||
E_SOCKET_ACCESS: 'E_SOCKET_ACCESS',
|
|
||||||
E_SOCKET_RESOURCE: 'E_SOCKET_RESOURCE',
|
|
||||||
E_SOCKET_TIMEOUT: 'E_SOCKET_TIMEOUT',
|
|
||||||
E_DATAGRAM_TOO_LARGE: 'E_DATAGRAM_TOO_LARGE',
|
|
||||||
E_NETWORK: 'E_NETWORK',
|
|
||||||
E_ADDRESS_IN_USE: 'E_ADDRESS_IN_USE',
|
E_ADDRESS_IN_USE: 'E_ADDRESS_IN_USE',
|
||||||
E_SOCKET_ADDRESS_NOT_AVAILABLE: 'E_SOCKET_ADDRESS_NOT_AVAILABLE',
|
E_AUTHENTICATION: 'E_AUTHENTICATION',
|
||||||
E_UNSUPPORTED_SOCKET_OPERATION: 'E_UNSUPPORTED_SOCKET_OPERATION',
|
E_CLASS: 'E_CLASS',
|
||||||
|
E_CONNECTION_REFUSED: 'E_CONNECTION_REFUSED',
|
||||||
|
E_COVER: 'E_COVER',
|
||||||
|
E_DATAGRAM_TOO_LARGE: 'E_DATAGRAM_TOO_LARGE',
|
||||||
|
E_ERROR: 'E_ERROR',
|
||||||
|
E_FAN: 'E_FAN',
|
||||||
|
E_FILTER: 'E_FILTER',
|
||||||
|
E_GENERAL: 'E_GENERAL',
|
||||||
|
E_HOST_NOT_FOUND: 'E_HOST_NOT_FOUND',
|
||||||
|
E_INVALID_DATA: 'E_INVALID_DATA',
|
||||||
|
E_LAMP: 'E_LAMP',
|
||||||
|
E_NETWORK: 'E_NETWORK',
|
||||||
|
E_NO_AUTHENTICATION: 'E_NO_AUTHENTICATION',
|
||||||
|
E_NOT_CONNECTED: 'E_NOT_CONNECTED',
|
||||||
|
E_PARAMETER: 'E_PARAMETER',
|
||||||
|
E_PREFIX: 'E_PREFIX',
|
||||||
|
E_PROJECTOR: 'E_PROJECTOR',
|
||||||
E_PROXY_AUTHENTICATION_REQUIRED: 'E_PROXY_AUTHENTICATION_REQUIRED',
|
E_PROXY_AUTHENTICATION_REQUIRED: 'E_PROXY_AUTHENTICATION_REQUIRED',
|
||||||
E_SLS_HANDSHAKE_FAILED: 'E_SLS_HANDSHAKE_FAILED',
|
|
||||||
E_UNFINISHED_SOCKET_OPERATION: 'E_UNFINISHED_SOCKET_OPERATION',
|
|
||||||
E_PROXY_CONNECTION_REFUSED: 'E_PROXY_CONNECTION_REFUSED',
|
|
||||||
E_PROXY_CONNECTION_CLOSED: 'E_PROXY_CONNECTION_CLOSED',
|
E_PROXY_CONNECTION_CLOSED: 'E_PROXY_CONNECTION_CLOSED',
|
||||||
|
E_PROXY_CONNECTION_REFUSED: 'E_PROXY_CONNECTION_REFUSED',
|
||||||
E_PROXY_CONNECTION_TIMEOUT: 'E_PROXY_CONNECTION_TIMEOUT',
|
E_PROXY_CONNECTION_TIMEOUT: 'E_PROXY_CONNECTION_TIMEOUT',
|
||||||
E_PROXY_NOT_FOUND: 'E_PROXY_NOT_FOUND',
|
E_PROXY_NOT_FOUND: 'E_PROXY_NOT_FOUND',
|
||||||
E_PROXY_PROTOCOL: 'E_PROXY_PROTOCOL',
|
E_PROXY_PROTOCOL: 'E_PROXY_PROTOCOL',
|
||||||
E_UNKNOWN_SOCKET_ERROR: 'E_UNKNOWN_SOCKET_ERROR'
|
E_REMOTE_HOST_CLOSED_CONNECTION: 'E_REMOTE_HOST_CLOSED_CONNECTION',
|
||||||
}
|
E_SLS_HANDSHAKE_FAILED: 'E_SLS_HANDSHAKE_FAILED',
|
||||||
|
E_SOCKET_ACCESS: 'E_SOCKET_ACCESS',
|
||||||
STATUS_STRING = {
|
E_SOCKET_ADDRESS_NOT_AVAILABLE: 'E_SOCKET_ADDRESS_NOT_AVAILABLE',
|
||||||
S_NOT_CONNECTED: 'S_NOT_CONNECTED',
|
E_SOCKET_RESOURCE: 'E_SOCKET_RESOURCE',
|
||||||
S_CONNECTING: 'S_CONNECTING',
|
E_SOCKET_TIMEOUT: 'E_SOCKET_TIMEOUT',
|
||||||
S_CONNECTED: 'S_CONNECTED',
|
E_TEMP: 'E_TEMP',
|
||||||
S_STATUS: 'S_STATUS',
|
E_UNAVAILABLE: 'E_UNAVAILABLE',
|
||||||
S_OFF: 'S_OFF',
|
E_UNDEFINED: 'E_UNDEFINED',
|
||||||
S_INITIALIZE: 'S_INITIALIZE',
|
E_UNFINISHED_SOCKET_OPERATION: 'E_UNFINISHED_SOCKET_OPERATION',
|
||||||
S_STANDBY: 'S_STANDBY',
|
E_UNKNOWN: 'E_UNKNOWN',
|
||||||
S_WARMUP: 'S_WARMUP',
|
E_UNKNOWN_SOCKET_ERROR: 'E_UNKNOWN_SOCKET_ERROR',
|
||||||
S_ON: 'S_ON',
|
E_UNSUPPORTED_SOCKET_OPERATION: 'E_UNSUPPORTED_SOCKET_OPERATION',
|
||||||
|
E_WARN: 'E_WARN',
|
||||||
|
S_BOUND: 'S_BOUND',
|
||||||
S_COOLDOWN: 'S_COOLDOWN',
|
S_COOLDOWN: 'S_COOLDOWN',
|
||||||
|
S_CLOSING: 'S_CLOSING',
|
||||||
|
S_CONNECTED: 'S_CONNECTED',
|
||||||
|
S_CONNECTING: 'S_CONNECTING',
|
||||||
|
S_HOST_LOOKUP: 'S_HOST_LOOKUP',
|
||||||
S_INFO: 'S_INFO',
|
S_INFO: 'S_INFO',
|
||||||
|
S_INITIALIZE: 'S_INITIALIZE',
|
||||||
|
S_LISTENING: 'S_LISTENING',
|
||||||
|
S_NETWORK_RECEIVING: 'S_NETWORK_RECEIVING',
|
||||||
S_NETWORK_SENDING: 'S_NETWORK_SENDING',
|
S_NETWORK_SENDING: 'S_NETWORK_SENDING',
|
||||||
S_NETWORK_RECEIVED: 'S_NETWORK_RECEIVED'
|
S_NETWORK_IDLE: 'S_NETWORK_IDLE',
|
||||||
|
S_NOT_CONNECTED: 'S_NOT_CONNECTED',
|
||||||
|
S_OFF: 'S_OFF',
|
||||||
|
S_OK: 'S_OK', # S_OK or E_OK
|
||||||
|
S_ON: 'S_ON',
|
||||||
|
S_STANDBY: 'S_STANDBY',
|
||||||
|
S_STATUS: 'S_STATUS',
|
||||||
|
S_WARMUP: 'S_WARMUP',
|
||||||
}
|
}
|
||||||
|
|
||||||
# Map error/status codes to message strings
|
# Map status codes to message strings
|
||||||
ERROR_MSG = {
|
STATUS_MSG = {
|
||||||
E_OK: translate('OpenLP.ProjectorConstants', 'OK'), # E_OK | S_OK
|
|
||||||
E_GENERAL: translate('OpenLP.ProjectorConstants', 'General projector error'),
|
|
||||||
E_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not connected error'),
|
|
||||||
E_LAMP: translate('OpenLP.ProjectorConstants', 'Lamp error'),
|
|
||||||
E_FAN: translate('OpenLP.ProjectorConstants', 'Fan error'),
|
|
||||||
E_TEMP: translate('OpenLP.ProjectorConstants', 'High temperature detected'),
|
|
||||||
E_COVER: translate('OpenLP.ProjectorConstants', 'Cover open detected'),
|
|
||||||
E_FILTER: translate('OpenLP.ProjectorConstants', 'Check filter'),
|
|
||||||
E_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'Authentication Error'),
|
|
||||||
E_UNDEFINED: translate('OpenLP.ProjectorConstants', 'Undefined Command'),
|
|
||||||
E_PARAMETER: translate('OpenLP.ProjectorConstants', 'Invalid Parameter'),
|
|
||||||
E_UNAVAILABLE: translate('OpenLP.ProjectorConstants', 'Projector Busy'),
|
|
||||||
E_PROJECTOR: translate('OpenLP.ProjectorConstants', 'Projector/Display Error'),
|
|
||||||
E_INVALID_DATA: translate('OpenLP.ProjectorConstants', 'Invalid packet received'),
|
|
||||||
E_WARN: translate('OpenLP.ProjectorConstants', 'Warning condition detected'),
|
|
||||||
E_ERROR: translate('OpenLP.ProjectorConstants', 'Error condition detected'),
|
|
||||||
E_CLASS: translate('OpenLP.ProjectorConstants', 'PJLink class not supported'),
|
|
||||||
E_PREFIX: translate('OpenLP.ProjectorConstants', 'Invalid prefix character'),
|
|
||||||
E_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',
|
|
||||||
'The connection was refused by the peer (or timed out)'),
|
|
||||||
E_REMOTE_HOST_CLOSED_CONNECTION: translate('OpenLP.ProjectorConstants',
|
|
||||||
'The remote host closed the connection'),
|
|
||||||
E_HOST_NOT_FOUND: translate('OpenLP.ProjectorConstants', 'The host address was not found'),
|
|
||||||
E_SOCKET_ACCESS: translate('OpenLP.ProjectorConstants',
|
|
||||||
'The socket operation failed because the application '
|
|
||||||
'lacked the required privileges'),
|
|
||||||
E_SOCKET_RESOURCE: translate('OpenLP.ProjectorConstants',
|
|
||||||
'The local system ran out of resources (e.g., too many sockets)'),
|
|
||||||
E_SOCKET_TIMEOUT: translate('OpenLP.ProjectorConstants',
|
|
||||||
'The socket operation timed out'),
|
|
||||||
E_DATAGRAM_TOO_LARGE: translate('OpenLP.ProjectorConstants',
|
|
||||||
'The datagram was larger than the operating system\'s limit'),
|
|
||||||
E_NETWORK: translate('OpenLP.ProjectorConstants',
|
|
||||||
'An error occurred with the network (Possibly someone pulled the plug?)'),
|
|
||||||
E_ADDRESS_IN_USE: translate('OpenLP.ProjectorConstants',
|
E_ADDRESS_IN_USE: translate('OpenLP.ProjectorConstants',
|
||||||
'The address specified with socket.bind() '
|
'The address specified with socket.bind() '
|
||||||
'is already in use and was set to be exclusive'),
|
'is already in use and was set to be exclusive'),
|
||||||
E_SOCKET_ADDRESS_NOT_AVAILABLE: translate('OpenLP.ProjectorConstants',
|
E_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERRA: Authentication Error"'),
|
||||||
'The address specified to socket.bind() '
|
E_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',
|
||||||
'does not belong to the host'),
|
'The connection was refused by the peer (or timed out)'),
|
||||||
E_UNSUPPORTED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
|
E_COVER: translate('OpenLP.ProjectorConstants', 'Projector cover open detected'),
|
||||||
'The requested socket operation is not supported by the local '
|
E_CLASS: translate('OpenLP.ProjectorConstants', 'PJLink class not supported'),
|
||||||
'operating system (e.g., lack of IPv6 support)'),
|
E_DATAGRAM_TOO_LARGE: translate('OpenLP.ProjectorConstants',
|
||||||
|
"The datagram was larger than the operating system's limit"),
|
||||||
|
E_ERROR: translate('OpenLP.ProjectorConstants', 'Error condition detected'),
|
||||||
|
E_FAN: translate('OpenLP.ProjectorConstants', 'Projector fan error'),
|
||||||
|
E_FILTER: translate('OpenLP.ProjectorConstants', 'Projector check filter'),
|
||||||
|
E_GENERAL: translate('OpenLP.ProjectorConstants', 'General projector error'),
|
||||||
|
E_HOST_NOT_FOUND: translate('OpenLP.ProjectorConstants', 'The host address was not found'),
|
||||||
|
E_INVALID_DATA: translate('OpenLP.ProjectorConstants', 'PJLink invalid packet received'),
|
||||||
|
E_LAMP: translate('OpenLP.ProjectorConstants', 'Projector lamp error'),
|
||||||
|
E_NETWORK: translate('OpenLP.ProjectorConstants',
|
||||||
|
'An error occurred with the network (Possibly someone pulled the plug?)'),
|
||||||
|
E_NO_AUTHENTICATION: translate('OpenLP.ProjectorConstants', 'PJlink authentication Mismatch Error'),
|
||||||
|
E_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Projector not connected error'),
|
||||||
|
E_PARAMETER: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR2: Invalid Parameter"'),
|
||||||
|
E_PREFIX: translate('OpenLP.ProjectorConstants', 'PJLink Invalid prefix character'),
|
||||||
|
E_PROJECTOR: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR4: Projector/Display Error"'),
|
||||||
E_PROXY_AUTHENTICATION_REQUIRED: translate('OpenLP.ProjectorConstants',
|
E_PROXY_AUTHENTICATION_REQUIRED: translate('OpenLP.ProjectorConstants',
|
||||||
'The socket is using a proxy, '
|
'The socket is using a proxy, '
|
||||||
'and the proxy requires authentication'),
|
'and the proxy requires authentication'),
|
||||||
E_SLS_HANDSHAKE_FAILED: translate('OpenLP.ProjectorConstants',
|
|
||||||
'The SSL/TLS handshake failed'),
|
|
||||||
E_UNFINISHED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
|
|
||||||
'The last operation attempted has not finished yet '
|
|
||||||
'(still in progress in the background)'),
|
|
||||||
E_PROXY_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',
|
|
||||||
'Could not contact the proxy server because the connection '
|
|
||||||
'to that server was denied'),
|
|
||||||
E_PROXY_CONNECTION_CLOSED: translate('OpenLP.ProjectorConstants',
|
E_PROXY_CONNECTION_CLOSED: translate('OpenLP.ProjectorConstants',
|
||||||
'The connection to the proxy server was closed unexpectedly '
|
'The connection to the proxy server was closed unexpectedly '
|
||||||
'(before the connection to the final peer was established)'),
|
'(before the connection to the final peer was established)'),
|
||||||
|
E_PROXY_CONNECTION_REFUSED: translate('OpenLP.ProjectorConstants',
|
||||||
|
'Could not contact the proxy server because the connection '
|
||||||
|
'to that server was denied'),
|
||||||
E_PROXY_CONNECTION_TIMEOUT: translate('OpenLP.ProjectorConstants',
|
E_PROXY_CONNECTION_TIMEOUT: translate('OpenLP.ProjectorConstants',
|
||||||
'The connection to the proxy server timed out or the proxy '
|
'The connection to the proxy server timed out or the proxy '
|
||||||
'server stopped responding in the authentication phase.'),
|
'server stopped responding in the authentication phase.'),
|
||||||
@ -373,51 +405,91 @@ ERROR_MSG = {
|
|||||||
E_PROXY_PROTOCOL: translate('OpenLP.ProjectorConstants',
|
E_PROXY_PROTOCOL: translate('OpenLP.ProjectorConstants',
|
||||||
'The connection negotiation with the proxy server failed because the '
|
'The connection negotiation with the proxy server failed because the '
|
||||||
'response from the proxy server could not be understood'),
|
'response from the proxy server could not be understood'),
|
||||||
E_UNKNOWN_SOCKET_ERROR: translate('OpenLP.ProjectorConstants', 'An unidentified error occurred'),
|
E_REMOTE_HOST_CLOSED_CONNECTION: translate('OpenLP.ProjectorConstants',
|
||||||
S_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not connected'),
|
'The remote host closed the connection'),
|
||||||
S_CONNECTING: translate('OpenLP.ProjectorConstants', 'Connecting'),
|
E_SLS_HANDSHAKE_FAILED: translate('OpenLP.ProjectorConstants',
|
||||||
|
'The SSL/TLS handshake failed'),
|
||||||
|
E_SOCKET_ADDRESS_NOT_AVAILABLE: translate('OpenLP.ProjectorConstants',
|
||||||
|
'The address specified to socket.bind() '
|
||||||
|
'does not belong to the host'),
|
||||||
|
E_SOCKET_ACCESS: translate('OpenLP.ProjectorConstants',
|
||||||
|
'The socket operation failed because the application '
|
||||||
|
'lacked the required privileges'),
|
||||||
|
E_SOCKET_RESOURCE: translate('OpenLP.ProjectorConstants',
|
||||||
|
'The local system ran out of resources (e.g., too many sockets)'),
|
||||||
|
E_SOCKET_TIMEOUT: translate('OpenLP.ProjectorConstants',
|
||||||
|
'The socket operation timed out'),
|
||||||
|
E_TEMP: translate('OpenLP.ProjectorConstants', 'Projector high temperature detected'),
|
||||||
|
E_UNAVAILABLE: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR3: Busy"'),
|
||||||
|
E_UNDEFINED: translate('OpenLP.ProjectorConstants', 'PJLink returned "ERR1: Undefined Command"'),
|
||||||
|
E_UNFINISHED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
|
||||||
|
'The last operation attempted has not finished yet '
|
||||||
|
'(still in progress in the background)'),
|
||||||
|
E_UNKNOWN: translate('OpenLP.ProjectorConstants', 'Unknown condiction detected'),
|
||||||
|
E_UNKNOWN_SOCKET_ERROR: translate('OpenLP.ProjectorConstants', 'An unidentified socket error occurred'),
|
||||||
|
E_UNSUPPORTED_SOCKET_OPERATION: translate('OpenLP.ProjectorConstants',
|
||||||
|
'The requested socket operation is not supported by the local '
|
||||||
|
'operating system (e.g., lack of IPv6 support)'),
|
||||||
|
E_WARN: translate('OpenLP.ProjectorConstants', 'Warning condition detected'),
|
||||||
|
S_BOUND: translate('OpenLP.ProjectorConstants', 'Socket is bount to an address or port'),
|
||||||
|
S_CLOSING: translate('OpenLP.ProjectorConstants', 'Socket is about to close'),
|
||||||
S_CONNECTED: translate('OpenLP.ProjectorConstants', 'Connected'),
|
S_CONNECTED: translate('OpenLP.ProjectorConstants', 'Connected'),
|
||||||
S_STATUS: translate('OpenLP.ProjectorConstants', 'Getting status'),
|
S_CONNECTING: translate('OpenLP.ProjectorConstants', 'Connecting'),
|
||||||
S_OFF: translate('OpenLP.ProjectorConstants', 'Off'),
|
|
||||||
S_INITIALIZE: translate('OpenLP.ProjectorConstants', 'Initialize in progress'),
|
|
||||||
S_STANDBY: translate('OpenLP.ProjectorConstants', 'Power in standby'),
|
|
||||||
S_WARMUP: translate('OpenLP.ProjectorConstants', 'Warmup in progress'),
|
|
||||||
S_ON: translate('OpenLP.ProjectorConstants', 'Power is on'),
|
|
||||||
S_COOLDOWN: translate('OpenLP.ProjectorConstants', 'Cooldown in progress'),
|
S_COOLDOWN: translate('OpenLP.ProjectorConstants', 'Cooldown in progress'),
|
||||||
|
S_HOST_LOOKUP: translate('OpenLP.ProjectorConstants', 'Performing a host name lookup'),
|
||||||
S_INFO: translate('OpenLP.ProjectorConstants', 'Projector Information available'),
|
S_INFO: translate('OpenLP.ProjectorConstants', 'Projector Information available'),
|
||||||
|
S_INITIALIZE: translate('OpenLP.ProjectorConstants', 'Initialize in progress'),
|
||||||
|
S_LISTENING: translate('OpenLP.ProjectorConstants', 'Socket it listening (internal use only)'),
|
||||||
|
S_NETWORK_IDLE: translate('OpenLP.ProjectorConstants', 'No network activity at this time'),
|
||||||
|
S_NETWORK_RECEIVING: translate('OpenLP.ProjectorConstants', 'Received data'),
|
||||||
S_NETWORK_SENDING: translate('OpenLP.ProjectorConstants', 'Sending data'),
|
S_NETWORK_SENDING: translate('OpenLP.ProjectorConstants', 'Sending data'),
|
||||||
S_NETWORK_RECEIVED: translate('OpenLP.ProjectorConstants', 'Received data')
|
S_NOT_CONNECTED: translate('OpenLP.ProjectorConstants', 'Not Connected'),
|
||||||
|
S_OFF: translate('OpenLP.ProjectorConstants', 'Off'),
|
||||||
|
S_OK: translate('OpenLP.ProjectorConstants', 'OK'),
|
||||||
|
S_ON: translate('OpenLP.ProjectorConstants', 'Power is on'),
|
||||||
|
S_STANDBY: translate('OpenLP.ProjectorConstants', 'Power in standby'),
|
||||||
|
S_STATUS: translate('OpenLP.ProjectorConstants', 'Getting status'),
|
||||||
|
S_WARMUP: translate('OpenLP.ProjectorConstants', 'Warmup in progress'),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Map ERST return code positions to equipment
|
# Map ERST reply positions to equipment
|
||||||
|
PJLINK_ERST_LIST = {
|
||||||
|
"FAN": translate('OpenLP.PJLink', 'Fan'),
|
||||||
|
"LAMP": translate('OpenLP.PJLink', 'Lamp'),
|
||||||
|
"TEMP": translate('OpenLP.PJLink', 'Temperature'),
|
||||||
|
"COVER": translate('OpenLP.PJLink', 'Cover'),
|
||||||
|
"FILTER": translate('OpenLP.PJLink', 'Filter'),
|
||||||
|
"OTHER": translate('OpenPL.PJLink', 'Other')
|
||||||
|
}
|
||||||
|
|
||||||
|
# Map projector item to ERST data position
|
||||||
PJLINK_ERST_DATA = {
|
PJLINK_ERST_DATA = {
|
||||||
'DATA_LENGTH': 6,
|
'DATA_LENGTH': 6, # Zero based so enums are 0-5
|
||||||
0: 'FAN',
|
|
||||||
1: 'LAMP',
|
|
||||||
2: 'TEMP',
|
|
||||||
3: 'COVER',
|
|
||||||
4: 'FILTER',
|
|
||||||
5: 'OTHER',
|
|
||||||
'FAN': 0,
|
'FAN': 0,
|
||||||
'LAMP': 1,
|
'LAMP': 1,
|
||||||
'TEMP': 2,
|
'TEMP': 2,
|
||||||
'COVER': 3,
|
'COVER': 3,
|
||||||
'FILTER': 4,
|
'FILTER': 4,
|
||||||
'OTHER': 5
|
'OTHER': 5,
|
||||||
|
0: 'FAN',
|
||||||
|
1: 'LAMP',
|
||||||
|
2: 'TEMP',
|
||||||
|
3: 'COVER',
|
||||||
|
4: 'FILTER',
|
||||||
|
5: 'OTHER'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Map for ERST return codes to string
|
# Map ERST reply codes to string
|
||||||
PJLINK_ERST_STATUS = {
|
PJLINK_ERST_STATUS = {
|
||||||
'0': 'OK',
|
'0': S_OK,
|
||||||
'1': ERROR_STRING[E_WARN],
|
'1': E_WARN,
|
||||||
'2': ERROR_STRING[E_ERROR],
|
'2': E_ERROR,
|
||||||
'OK': '0',
|
S_OK: '0',
|
||||||
E_OK: '0',
|
|
||||||
E_WARN: '1',
|
E_WARN: '1',
|
||||||
E_ERROR: '2'
|
E_ERROR: '2'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Map for POWR return codes to status code
|
# Map POWR return codes to status code
|
||||||
PJLINK_POWR_STATUS = {
|
PJLINK_POWR_STATUS = {
|
||||||
'0': S_STANDBY,
|
'0': S_STANDBY,
|
||||||
'1': S_ON,
|
'1': S_ON,
|
||||||
@ -485,3 +557,7 @@ for source in PJLINK_DEFAULT_SOURCES:
|
|||||||
label = "{source}{item}".format(source=source, item=item)
|
label = "{source}{item}".format(source=source, item=item)
|
||||||
PJLINK_DEFAULT_CODES[label] = "{source} {item}".format(source=PJLINK_DEFAULT_SOURCES[source],
|
PJLINK_DEFAULT_CODES[label] = "{source} {item}".format(source=PJLINK_DEFAULT_SOURCES[source],
|
||||||
item=PJLINK_DEFAULT_ITEMS[item])
|
item=PJLINK_DEFAULT_ITEMS[item])
|
||||||
|
# Remove temp variables so they don't become part of the module dict
|
||||||
|
del(source)
|
||||||
|
del(item)
|
||||||
|
del(label)
|
||||||
|
@ -35,9 +35,25 @@ from openlp.core.common.registry import RegistryBase
|
|||||||
from openlp.core.common.settings import Settings
|
from openlp.core.common.settings import Settings
|
||||||
from openlp.core.lib.ui import create_widget_action
|
from openlp.core.lib.ui import create_widget_action
|
||||||
from openlp.core.projectors import DialogSourceStyle
|
from openlp.core.projectors import DialogSourceStyle
|
||||||
from openlp.core.projectors.constants import ERROR_MSG, ERROR_STRING, E_AUTHENTICATION, E_ERROR, \
|
from openlp.core.projectors.constants import \
|
||||||
E_NETWORK, E_NOT_CONNECTED, E_UNKNOWN_SOCKET_ERROR, STATUS_STRING, S_CONNECTED, S_CONNECTING, S_COOLDOWN, \
|
E_AUTHENTICATION, \
|
||||||
S_INITIALIZE, S_NOT_CONNECTED, S_OFF, S_ON, S_STANDBY, S_WARMUP
|
E_ERROR, \
|
||||||
|
E_NETWORK, \
|
||||||
|
E_NOT_CONNECTED, \
|
||||||
|
E_UNKNOWN_SOCKET_ERROR, \
|
||||||
|
S_CONNECTED, \
|
||||||
|
S_CONNECTING, \
|
||||||
|
S_COOLDOWN, \
|
||||||
|
S_INITIALIZE, \
|
||||||
|
S_NOT_CONNECTED, \
|
||||||
|
S_OFF, \
|
||||||
|
S_ON, \
|
||||||
|
S_STANDBY, \
|
||||||
|
S_WARMUP, \
|
||||||
|
STATUS_CODE, \
|
||||||
|
STATUS_MSG, \
|
||||||
|
QSOCKET_STATE
|
||||||
|
|
||||||
from openlp.core.projectors.db import ProjectorDB
|
from openlp.core.projectors.db import ProjectorDB
|
||||||
from openlp.core.projectors.pjlink import PJLink, PJLinkUDP
|
from openlp.core.projectors.pjlink import PJLink, PJLinkUDP
|
||||||
from openlp.core.projectors.editform import ProjectorEditForm
|
from openlp.core.projectors.editform import ProjectorEditForm
|
||||||
@ -440,11 +456,12 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
:param opt: Needed by PyQt5
|
:param opt: Needed by PyQt5
|
||||||
"""
|
"""
|
||||||
projector = item.data(QtCore.Qt.UserRole)
|
projector = item.data(QtCore.Qt.UserRole)
|
||||||
if projector.link.state() != projector.link.ConnectedState:
|
if QSOCKET_STATE[projector.link.state()] != S_CONNECTED:
|
||||||
try:
|
try:
|
||||||
|
log.debug('ProjectorManager: Calling connect_to_host() on "{ip}"'.format(ip=projector.link.ip))
|
||||||
projector.link.connect_to_host()
|
projector.link.connect_to_host()
|
||||||
except:
|
except:
|
||||||
pass
|
log.debug('ProjectorManager: "{ip}" already connected - skipping'.format(ip=projector.link.ip))
|
||||||
return
|
return
|
||||||
|
|
||||||
def on_connect_projector(self, opt=None):
|
def on_connect_projector(self, opt=None):
|
||||||
@ -647,7 +664,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
'Other info'),
|
'Other info'),
|
||||||
data=projector.link.other_info)
|
data=projector.link.other_info)
|
||||||
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Power status'),
|
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Power status'),
|
||||||
data=ERROR_MSG[projector.link.power])
|
data=STATUS_MSG[projector.link.power])
|
||||||
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Shutter is'),
|
message += '<b>{title}</b>: {data}<br />'.format(title=translate('OpenLP.ProjectorManager', 'Shutter is'),
|
||||||
data=translate('OpenLP.ProjectorManager', 'Closed')
|
data=translate('OpenLP.ProjectorManager', 'Closed')
|
||||||
if projector.link.shutter
|
if projector.link.shutter
|
||||||
@ -692,7 +709,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
else:
|
else:
|
||||||
message += '<b>{data}</b>'.format(data=translate('OpenLP.ProjectorManager', 'Current errors/warnings'))
|
message += '<b>{data}</b>'.format(data=translate('OpenLP.ProjectorManager', 'Current errors/warnings'))
|
||||||
for (key, val) in projector.link.projector_errors.items():
|
for (key, val) in projector.link.projector_errors.items():
|
||||||
message += '<b>{key}</b>: {data}<br />'.format(key=key, data=ERROR_MSG[val])
|
message += '<b>{key}</b>: {data}<br />'.format(key=key, data=STATUS_MSG[val])
|
||||||
QtWidgets.QMessageBox.information(self, translate('OpenLP.ProjectorManager', 'Projector Information'), message)
|
QtWidgets.QMessageBox.information(self, translate('OpenLP.ProjectorManager', 'Projector Information'), message)
|
||||||
|
|
||||||
def _add_projector(self, projector):
|
def _add_projector(self, projector):
|
||||||
@ -817,31 +834,18 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
if ip == list_item.link.ip:
|
if ip == list_item.link.ip:
|
||||||
item = list_item
|
item = list_item
|
||||||
break
|
break
|
||||||
message = translate('OpenLP.ProjectorManager', 'No message') if msg is None else msg
|
if item is None:
|
||||||
if status in STATUS_STRING:
|
log.error('ProjectorManager: Unknown item "{ip}" - not updating status'.format(ip=ip))
|
||||||
status_code = STATUS_STRING[status]
|
return
|
||||||
message = ERROR_MSG[status] if msg is None else msg
|
elif item.status == status:
|
||||||
elif status in ERROR_STRING:
|
log.debug('ProjectorManager: No status change for "{ip}" - not updating status'.format(ip=ip))
|
||||||
status_code = ERROR_STRING[status]
|
return
|
||||||
message = ERROR_MSG[status] if msg is None else msg
|
|
||||||
else:
|
item.status = status
|
||||||
status_code = status
|
item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
|
||||||
message = ERROR_MSG[status] if msg is None else msg
|
log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=STATUS_CODE[status]))
|
||||||
log.debug('({name}) updateStatus(status={status}) message: "{message}"'.format(name=item.link.name,
|
item.widget.setIcon(item.icon)
|
||||||
status=status_code,
|
return self.update_icons()
|
||||||
message=message))
|
|
||||||
if status in STATUS_ICONS:
|
|
||||||
if item.status == status:
|
|
||||||
return
|
|
||||||
item.status = status
|
|
||||||
item.icon = QtGui.QIcon(QtGui.QPixmap(STATUS_ICONS[status]))
|
|
||||||
if status in ERROR_STRING:
|
|
||||||
status_code = ERROR_STRING[status]
|
|
||||||
elif status in STATUS_STRING:
|
|
||||||
status_code = STATUS_STRING[status]
|
|
||||||
log.debug('({name}) Updating icon with {code}'.format(name=item.link.name, code=status_code))
|
|
||||||
item.widget.setIcon(item.icon)
|
|
||||||
self.update_icons()
|
|
||||||
|
|
||||||
def get_toolbar_item(self, name, enabled=False, hidden=False):
|
def get_toolbar_item(self, name, enabled=False, hidden=False):
|
||||||
item = self.one_toolbar.findChild(QtWidgets.QAction, name)
|
item = self.one_toolbar.findChild(QtWidgets.QAction, name)
|
||||||
@ -877,7 +881,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM
|
|||||||
self.get_toolbar_item('show_projector_multiple', hidden=True)
|
self.get_toolbar_item('show_projector_multiple', hidden=True)
|
||||||
elif count == 1:
|
elif count == 1:
|
||||||
projector = self.projector_list_widget.selectedItems()[0].data(QtCore.Qt.UserRole)
|
projector = self.projector_list_widget.selectedItems()[0].data(QtCore.Qt.UserRole)
|
||||||
connected = projector.link.state() == projector.link.ConnectedState
|
connected = QSOCKET_STATE[projector.link.state()] == S_CONNECTED
|
||||||
power = projector.link.power == S_ON
|
power = projector.link.power == S_ON
|
||||||
self.get_toolbar_item('connect_projector_multiple', hidden=True)
|
self.get_toolbar_item('connect_projector_multiple', hidden=True)
|
||||||
self.get_toolbar_item('disconnect_projector_multiple', hidden=True)
|
self.get_toolbar_item('disconnect_projector_multiple', hidden=True)
|
||||||
|
@ -54,11 +54,12 @@ from PyQt5 import QtCore, QtNetwork
|
|||||||
|
|
||||||
from openlp.core.common import qmd5_hash
|
from openlp.core.common import qmd5_hash
|
||||||
from openlp.core.common.i18n import translate
|
from openlp.core.common.i18n import translate
|
||||||
from openlp.core.projectors.constants import CONNECTION_ERRORS, CR, ERROR_MSG, ERROR_STRING, \
|
from openlp.core.projectors.constants import CONNECTION_ERRORS, PJLINK_CLASS, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \
|
||||||
E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, E_OK, \
|
PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PREFIX, PJLINK_PORT, PJLINK_POWR_STATUS, \
|
||||||
E_PARAMETER, E_PROJECTOR, E_SOCKET_TIMEOUT, E_UNAVAILABLE, E_UNDEFINED, PJLINK_ERRORS, PJLINK_ERST_DATA, \
|
PJLINK_SUFFIX, PJLINK_VALID_CMD, PROJECTOR_STATE, STATUS_CODE, STATUS_MSG, QSOCKET_STATE, \
|
||||||
PJLINK_ERST_STATUS, PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_POWR_STATUS, PJLINK_VALID_CMD, \
|
E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, E_INVALID_DATA, E_NETWORK, E_NOT_CONNECTED, \
|
||||||
STATUS_STRING, S_CONNECTED, S_CONNECTING, S_INFO, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_QSOCKET_STATE, S_STATUS
|
E_OK, E_SOCKET_TIMEOUT, \
|
||||||
|
S_CONNECTED, S_CONNECTING, S_INFO, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, S_STATUS
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
log.debug('pjlink loaded')
|
log.debug('pjlink loaded')
|
||||||
@ -69,12 +70,9 @@ __all__ = ['PJLink']
|
|||||||
SocketError = QtNetwork.QAbstractSocket.SocketError
|
SocketError = QtNetwork.QAbstractSocket.SocketError
|
||||||
SocketSTate = QtNetwork.QAbstractSocket.SocketState
|
SocketSTate = QtNetwork.QAbstractSocket.SocketState
|
||||||
|
|
||||||
PJLINK_PREFIX = '%'
|
|
||||||
PJLINK_CLASS = '1' # Default to class 1 until we query the projector
|
|
||||||
# Add prefix here, but defer linkclass expansion until later when we have the actual
|
# Add prefix here, but defer linkclass expansion until later when we have the actual
|
||||||
# PJLink class for the command
|
# PJLink class for the command
|
||||||
PJLINK_HEADER = '{prefix}{{linkclass}}'.format(prefix=PJLINK_PREFIX)
|
PJLINK_HEADER = '{prefix}{{linkclass}}'.format(prefix=PJLINK_PREFIX)
|
||||||
PJLINK_SUFFIX = CR
|
|
||||||
|
|
||||||
|
|
||||||
class PJLinkUDP(QtNetwork.QUdpSocket):
|
class PJLinkUDP(QtNetwork.QUdpSocket):
|
||||||
@ -136,8 +134,9 @@ class PJLinkCommands(object):
|
|||||||
"""
|
"""
|
||||||
Initialize instance variables. Also used to reset projector-specific information to default.
|
Initialize instance variables. Also used to reset projector-specific information to default.
|
||||||
"""
|
"""
|
||||||
|
conn_state = STATUS_CODE[QSOCKET_STATE[self.state()]]
|
||||||
log.debug('({ip}) reset_information() connect status is {state}'.format(ip=self.ip,
|
log.debug('({ip}) reset_information() connect status is {state}'.format(ip=self.ip,
|
||||||
state=S_QSOCKET_STATE[self.state()]))
|
state=conn_state))
|
||||||
self.fan = None # ERST
|
self.fan = None # ERST
|
||||||
self.filter_time = None # FILT
|
self.filter_time = None # FILT
|
||||||
self.lamp = None # LAMP
|
self.lamp = None # LAMP
|
||||||
@ -183,42 +182,25 @@ class PJLinkCommands(object):
|
|||||||
# Due to some replies should stay as mixed-case, validate using separate uppercase check
|
# Due to some replies should stay as mixed-case, validate using separate uppercase check
|
||||||
_data = data.upper()
|
_data = data.upper()
|
||||||
# Check if we have a future command not available yet
|
# Check if we have a future command not available yet
|
||||||
if cmd not in PJLINK_VALID_CMD:
|
if cmd not in self.pjlink_functions:
|
||||||
log.error('({ip}) Ignoring command="{cmd}" (Invalid/Unknown)'.format(ip=self.ip, cmd=cmd))
|
log.warning('({ip}) Unable to process command="{cmd}" (Future option?)'.format(ip=self.ip, cmd=cmd))
|
||||||
return
|
return
|
||||||
elif _data == 'OK':
|
elif _data == 'OK':
|
||||||
log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=self.ip, cmd=cmd))
|
log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=self.ip, cmd=cmd))
|
||||||
# A command returned successfully, so do a query on command to verify status
|
# A command returned successfully, so do a query on command to verify status
|
||||||
return self.send_command(cmd=cmd)
|
return self.send_command(cmd=cmd)
|
||||||
elif cmd not in self.pjlink_functions:
|
|
||||||
log.warning('({ip}) Unable to process command="{cmd}" (Future option?)'.format(ip=self.ip, cmd=cmd))
|
|
||||||
return
|
|
||||||
elif _data in PJLINK_ERRORS:
|
elif _data in PJLINK_ERRORS:
|
||||||
# Oops - projector error
|
# Oops - projector error
|
||||||
log.error('({ip}) Projector returned error "{data}"'.format(ip=self.ip, data=data))
|
log.error('({ip}) {cmd}: {err}'.format(ip=self.ip,
|
||||||
if _data == PJLINK_ERRORS[E_AUTHENTICATION]:
|
cmd=cmd,
|
||||||
# Authentication error
|
err=STATUS_MSG[PJLINK_ERRORS[_data]]))
|
||||||
|
if PJLINK_ERRORS[_data] == E_AUTHENTICATION:
|
||||||
self.disconnect_from_host()
|
self.disconnect_from_host()
|
||||||
self.change_status(E_AUTHENTICATION)
|
|
||||||
log.debug('({ip}) emitting projectorAuthentication() signal'.format(ip=self.ip))
|
|
||||||
self.projectorAuthentication.emit(self.name)
|
self.projectorAuthentication.emit(self.name)
|
||||||
elif _data == PJLINK_ERRORS[E_UNDEFINED]:
|
return self.change_status(status=E_AUTHENTICATION)
|
||||||
# Projector does not recognize command
|
|
||||||
self.change_status(E_UNDEFINED, '{error}: "{data}"'.format(error=ERROR_MSG[E_UNDEFINED],
|
|
||||||
data=cmd))
|
|
||||||
elif _data == PJLINK_ERRORS[E_PARAMETER]:
|
|
||||||
# Invalid parameter
|
|
||||||
self.change_status(E_PARAMETER)
|
|
||||||
elif _data == PJLINK_ERRORS[E_UNAVAILABLE]:
|
|
||||||
# Projector busy
|
|
||||||
self.change_status(E_UNAVAILABLE)
|
|
||||||
elif _data == PJLINK_ERRORS[E_PROJECTOR]:
|
|
||||||
# Projector/display error
|
|
||||||
self.change_status(E_PROJECTOR)
|
|
||||||
return
|
|
||||||
# Command checks already passed
|
# Command checks already passed
|
||||||
log.debug('({ip}) Calling function for {cmd}'.format(ip=self.ip, cmd=cmd))
|
log.debug('({ip}) Calling function for {cmd}'.format(ip=self.ip, cmd=cmd))
|
||||||
self.pjlink_functions[cmd](data)
|
self.pjlink_functions[cmd](data=data)
|
||||||
|
|
||||||
def process_avmt(self, data):
|
def process_avmt(self, data):
|
||||||
"""
|
"""
|
||||||
@ -313,22 +295,22 @@ class PJLinkCommands(object):
|
|||||||
data[PJLINK_ERST_DATA['COVER']],
|
data[PJLINK_ERST_DATA['COVER']],
|
||||||
data[PJLINK_ERST_DATA['FILTER']],
|
data[PJLINK_ERST_DATA['FILTER']],
|
||||||
data[PJLINK_ERST_DATA['OTHER']])
|
data[PJLINK_ERST_DATA['OTHER']])
|
||||||
if fan != PJLINK_ERST_STATUS[E_OK]:
|
if fan != PJLINK_ERST_STATUS[S_OK]:
|
||||||
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Fan')] = \
|
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Fan')] = \
|
||||||
PJLINK_ERST_STATUS[fan]
|
PJLINK_ERST_STATUS[fan]
|
||||||
if lamp != PJLINK_ERST_STATUS[E_OK]:
|
if lamp != PJLINK_ERST_STATUS[S_OK]:
|
||||||
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Lamp')] = \
|
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Lamp')] = \
|
||||||
PJLINK_ERST_STATUS[lamp]
|
PJLINK_ERST_STATUS[lamp]
|
||||||
if temp != PJLINK_ERST_STATUS[E_OK]:
|
if temp != PJLINK_ERST_STATUS[S_OK]:
|
||||||
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Temperature')] = \
|
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Temperature')] = \
|
||||||
PJLINK_ERST_STATUS[temp]
|
PJLINK_ERST_STATUS[temp]
|
||||||
if cover != PJLINK_ERST_STATUS[E_OK]:
|
if cover != PJLINK_ERST_STATUS[S_OK]:
|
||||||
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Cover')] = \
|
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Cover')] = \
|
||||||
PJLINK_ERST_STATUS[cover]
|
PJLINK_ERST_STATUS[cover]
|
||||||
if filt != PJLINK_ERST_STATUS[E_OK]:
|
if filt != PJLINK_ERST_STATUS[S_OK]:
|
||||||
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Filter')] = \
|
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Filter')] = \
|
||||||
PJLINK_ERST_STATUS[filt]
|
PJLINK_ERST_STATUS[filt]
|
||||||
if other != PJLINK_ERST_STATUS[E_OK]:
|
if other != PJLINK_ERST_STATUS[S_OK]:
|
||||||
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Other')] = \
|
self.projector_errors[translate('OpenLP.ProjectorPJLink', 'Other')] = \
|
||||||
PJLINK_ERST_STATUS[other]
|
PJLINK_ERST_STATUS[other]
|
||||||
return
|
return
|
||||||
@ -373,8 +355,18 @@ class PJLinkCommands(object):
|
|||||||
|
|
||||||
:param data: Currently selected source
|
:param data: Currently selected source
|
||||||
"""
|
"""
|
||||||
|
# First, see if we have a valid input based on what is installed (if available)
|
||||||
|
if self.source_available is not None:
|
||||||
|
# We have available inputs, so verify it's in the list
|
||||||
|
if data not in self.source_available:
|
||||||
|
log.warn('({ip}) Input source not listed in available sources - ignoring'.format(ip=self.ip))
|
||||||
|
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=self.ip))
|
||||||
|
return
|
||||||
self.source = data
|
self.source = data
|
||||||
log.info('({ip}) Setting data source to "{data}"'.format(ip=self.ip, data=self.source))
|
log.debug('({ip}) Setting data source to "{data}"'.format(ip=self.ip, data=self.source))
|
||||||
return
|
return
|
||||||
|
|
||||||
def process_inst(self, data):
|
def process_inst(self, data):
|
||||||
@ -390,7 +382,6 @@ class PJLinkCommands(object):
|
|||||||
sources.append(source)
|
sources.append(source)
|
||||||
sources.sort()
|
sources.sort()
|
||||||
self.source_available = sources
|
self.source_available = sources
|
||||||
self.projectorUpdateIcons.emit()
|
|
||||||
log.debug('({ip}) Setting projector sources_available to "{data}"'.format(ip=self.ip,
|
log.debug('({ip}) Setting projector sources_available to "{data}"'.format(ip=self.ip,
|
||||||
data=self.source_available))
|
data=self.source_available))
|
||||||
return
|
return
|
||||||
@ -551,17 +542,15 @@ class PJLinkCommands(object):
|
|||||||
return
|
return
|
||||||
elif self.sw_version is None:
|
elif self.sw_version is None:
|
||||||
log.debug('({ip}) Setting projector software version to "{data}"'.format(ip=self.ip, data=data))
|
log.debug('({ip}) Setting projector software version to "{data}"'.format(ip=self.ip, data=data))
|
||||||
self.sw_version = data
|
|
||||||
self.db_update = True
|
|
||||||
else:
|
else:
|
||||||
# Compare software version and see if we got the same projector
|
if self.sw_version != data:
|
||||||
if self.serial_no != data:
|
|
||||||
log.warning('({ip}) Projector software version does not match saved '
|
log.warning('({ip}) Projector software version does not match saved '
|
||||||
'software version'.format(ip=self.ip))
|
'software version'.format(ip=self.ip))
|
||||||
log.warning('({ip}) Saved: "{old}"'.format(ip=self.ip, old=self.sw_version))
|
log.warning('({ip}) Saved: "{old}"'.format(ip=self.ip, old=self.sw_version))
|
||||||
log.warning('({ip}) Received: "{new}"'.format(ip=self.ip, new=data))
|
log.warning('({ip}) Received: "{new}"'.format(ip=self.ip, new=data))
|
||||||
log.warning('({ip}) Saving new serial number as sw_version_received'.format(ip=self.ip))
|
log.warning('({ip}) Updating software version'.format(ip=self.ip))
|
||||||
self.sw_version_received = data
|
self.sw_version = data
|
||||||
|
self.db_update = True
|
||||||
|
|
||||||
|
|
||||||
class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
||||||
@ -678,7 +667,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
Retrieve information from projector that changes.
|
Retrieve information from projector that changes.
|
||||||
Normally called by timer().
|
Normally called by timer().
|
||||||
"""
|
"""
|
||||||
if self.state() != S_QSOCKET_STATE['ConnectedState']:
|
if QSOCKET_STATE[self.state()] != S_CONNECTED:
|
||||||
log.warning('({ip}) poll_loop(): Not connected - returning'.format(ip=self.ip))
|
log.warning('({ip}) poll_loop(): Not connected - returning'.format(ip=self.ip))
|
||||||
return
|
return
|
||||||
log.debug('({ip}) poll_loop(): Updating projector status'.format(ip=self.ip))
|
log.debug('({ip}) poll_loop(): Updating projector status'.format(ip=self.ip))
|
||||||
@ -688,13 +677,8 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
self.timer.setInterval(self.poll_time)
|
self.timer.setInterval(self.poll_time)
|
||||||
# Restart timer
|
# Restart timer
|
||||||
self.timer.start()
|
self.timer.start()
|
||||||
# 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)
|
|
||||||
# The following commands do not change, so only check them once
|
# The following commands do not change, so only check them once
|
||||||
|
# Call them first in case other functions rely on something here
|
||||||
if self.power == S_ON and self.source_available is None:
|
if self.power == S_ON and self.source_available is None:
|
||||||
self.send_command('INST')
|
self.send_command('INST')
|
||||||
if self.other_info is None:
|
if self.other_info is None:
|
||||||
@ -715,22 +699,28 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
self.send_command('RFIL')
|
self.send_command('RFIL')
|
||||||
if self.model_lamp is None:
|
if self.model_lamp is None:
|
||||||
self.send_command('RLMP')
|
self.send_command('RLMP')
|
||||||
|
# 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)
|
||||||
|
|
||||||
def _get_status(self, status):
|
def _get_status(self, status):
|
||||||
"""
|
"""
|
||||||
Helper to retrieve status/error codes and convert to strings.
|
Helper to retrieve status/error codes and convert to strings.
|
||||||
|
|
||||||
:param status: Status/Error code
|
:param status: Status/Error code
|
||||||
:returns: (Status/Error code, String)
|
:returns: tuple (-1 if code not INT, None)
|
||||||
|
:returns: tuple (string: code as string, None if no description)
|
||||||
|
:returns: tuple (string: code as string, string: Status/Error description)
|
||||||
"""
|
"""
|
||||||
if not isinstance(status, int):
|
if not isinstance(status, int):
|
||||||
return -1, 'Invalid status code'
|
return -1, None
|
||||||
elif status in ERROR_STRING:
|
elif status not in STATUS_MSG:
|
||||||
return ERROR_STRING[status], ERROR_MSG[status]
|
return None, None
|
||||||
elif status in STATUS_STRING:
|
|
||||||
return STATUS_STRING[status], ERROR_MSG[status]
|
|
||||||
else:
|
else:
|
||||||
return status, translate('OpenLP.PJLink', 'Unknown status')
|
return STATUS_CODE[status], STATUS_MSG[status]
|
||||||
|
|
||||||
def change_status(self, status, msg=None):
|
def change_status(self, status, msg=None):
|
||||||
"""
|
"""
|
||||||
@ -740,19 +730,27 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
:param status: Status code
|
:param status: Status code
|
||||||
:param msg: Optional message
|
:param msg: Optional message
|
||||||
"""
|
"""
|
||||||
message = translate('OpenLP.PJLink', 'No message') if msg is None else msg
|
if status in STATUS_CODE:
|
||||||
(code, message) = self._get_status(status)
|
log.debug('({ip}) Changing status to {status} '
|
||||||
if msg is not None:
|
'"{msg}"'.format(ip=self.ip,
|
||||||
message = msg
|
status=STATUS_CODE[status],
|
||||||
|
msg=msg if msg is not None else STATUS_MSG[status]))
|
||||||
|
else:
|
||||||
|
log.warning('({ip}) Unknown status change code: {code}'.format(ip=self.ip,
|
||||||
|
code=status))
|
||||||
|
return
|
||||||
if status in CONNECTION_ERRORS:
|
if status in CONNECTION_ERRORS:
|
||||||
# Projector, connection state
|
# Connection state error affects both socket and projector
|
||||||
self.projector_status = self.error_status = self.status_connect = E_NOT_CONNECTED
|
self.error_status = status
|
||||||
elif status >= S_NOT_CONNECTED and status < S_STATUS:
|
self.status_connect = E_NOT_CONNECTED
|
||||||
|
elif status >= S_NOT_CONNECTED and status in QSOCKET_STATE:
|
||||||
|
# Socket connection status update
|
||||||
self.status_connect = status
|
self.status_connect = status
|
||||||
self.projector_status = S_NOT_CONNECTED
|
elif status >= S_NOT_CONNECTED and status in PROJECTOR_STATE:
|
||||||
elif status <= S_INFO:
|
# Only affects the projector status
|
||||||
self.status_connect = S_CONNECTED
|
|
||||||
self.projector_status = status
|
self.projector_status = status
|
||||||
|
|
||||||
|
# These log entries are for troubleshooting only
|
||||||
(status_code, status_message) = self._get_status(self.status_connect)
|
(status_code, status_message) = self._get_status(self.status_connect)
|
||||||
log.debug('({ip}) status_connect: {code}: "{message}"'.format(ip=self.ip,
|
log.debug('({ip}) status_connect: {code}: "{message}"'.format(ip=self.ip,
|
||||||
code=status_code,
|
code=status_code,
|
||||||
@ -765,6 +763,15 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
log.debug('({ip}) error_status: {code}: "{message}"'.format(ip=self.ip,
|
log.debug('({ip}) error_status: {code}: "{message}"'.format(ip=self.ip,
|
||||||
code=status_code,
|
code=status_code,
|
||||||
message=status_message if msg is None else msg))
|
message=status_message if msg is None else msg))
|
||||||
|
|
||||||
|
# Now that we logged extra information for debugging, broadcast the original change/message
|
||||||
|
(code, message) = self._get_status(status)
|
||||||
|
if msg is not None:
|
||||||
|
message = msg
|
||||||
|
elif message is None:
|
||||||
|
# No message for status code
|
||||||
|
message = translate('OpenLP.PJLink', 'No message') if msg is None else msg
|
||||||
|
|
||||||
self.changeStatus.emit(self.ip, status, message)
|
self.changeStatus.emit(self.ip, status, message)
|
||||||
self.projectorUpdateIcons.emit()
|
self.projectorUpdateIcons.emit()
|
||||||
|
|
||||||
@ -794,7 +801,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
data = decode(read, 'utf-8')
|
data = decode(read, 'utf-8')
|
||||||
# Possibility of extraneous data on input when reading.
|
# Possibility of extraneous data on input when reading.
|
||||||
# Clean out extraneous characters in buffer.
|
# Clean out extraneous characters in buffer.
|
||||||
self.readLine(self.max_size)
|
self.read(2048)
|
||||||
log.debug('({ip}) check_login() read "{data}"'.format(ip=self.ip, data=data.strip()))
|
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
|
# At this point, we should only have the initial login prompt with
|
||||||
# possible authentication
|
# possible authentication
|
||||||
@ -805,6 +812,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
# Invalid initial packet - close socket
|
# Invalid initial packet - close socket
|
||||||
log.error('({ip}) Invalid initial packet received - closing socket'.format(ip=self.ip))
|
log.error('({ip}) Invalid initial packet received - closing socket'.format(ip=self.ip))
|
||||||
return self.disconnect_from_host()
|
return self.disconnect_from_host()
|
||||||
|
# Convert the initial login prompt with the expected PJLink normal command format for processing
|
||||||
log.debug('({ip}) check_login(): Formatting initial connection prompt to PJLink packet'.format(ip=self.ip))
|
log.debug('({ip}) check_login(): Formatting initial connection prompt to PJLink packet'.format(ip=self.ip))
|
||||||
return self.get_data('{start}{clss}{data}'.format(start=PJLINK_PREFIX,
|
return self.get_data('{start}{clss}{data}'.format(start=PJLINK_PREFIX,
|
||||||
clss='1',
|
clss='1',
|
||||||
@ -895,7 +903,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
Get data from TCP socket.
|
Get data from TCP socket.
|
||||||
"""
|
"""
|
||||||
log.debug('({ip}) get_socket(): Reading data'.format(ip=self.ip))
|
log.debug('({ip}) get_socket(): Reading data'.format(ip=self.ip))
|
||||||
if self.state() != self.ConnectedState:
|
if QSOCKET_STATE[self.state()] != S_CONNECTED:
|
||||||
log.debug('({ip}) get_socket(): Not connected - returning'.format(ip=self.ip))
|
log.debug('({ip}) get_socket(): Not connected - returning'.format(ip=self.ip))
|
||||||
self.send_busy = False
|
self.send_busy = False
|
||||||
return
|
return
|
||||||
@ -907,8 +915,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
log.debug('({ip}) get_socket(): 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()
|
return self.receive_data_signal()
|
||||||
self.socket_timer.stop()
|
self.socket_timer.stop()
|
||||||
self.get_data(buff=read, ip=self.ip)
|
return self.get_data(buff=read, ip=self.ip)
|
||||||
return self.receive_data_signal()
|
|
||||||
|
|
||||||
def get_data(self, buff, ip=None):
|
def get_data(self, buff, ip=None):
|
||||||
"""
|
"""
|
||||||
@ -927,13 +934,17 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
data = data_in.strip()
|
data = data_in.strip()
|
||||||
# Initial packet checks
|
# Initial packet checks
|
||||||
if (len(data) < 7):
|
if (len(data) < 7):
|
||||||
return self._trash_buffer(msg='get_data(): Invalid packet - length')
|
self._trash_buffer(msg='get_data(): Invalid packet - length')
|
||||||
|
return self.receive_data_signal()
|
||||||
elif len(data) > self.max_size:
|
elif len(data) > self.max_size:
|
||||||
return self._trash_buffer(msg='get_data(): Invalid packet - too long')
|
self._trash_buffer(msg='get_data(): Invalid packet - too long')
|
||||||
|
return self.receive_data_signal()
|
||||||
elif not data.startswith(PJLINK_PREFIX):
|
elif not data.startswith(PJLINK_PREFIX):
|
||||||
return self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing')
|
self._trash_buffer(msg='get_data(): Invalid packet - PJLink prefix missing')
|
||||||
|
return self.receive_data_signal()
|
||||||
elif '=' not in data:
|
elif '=' not in data:
|
||||||
return self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="')
|
self._trash_buffer(msg='get_data(): Invalid reply - Does not have "="')
|
||||||
|
return self.receive_data_signal()
|
||||||
log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.ip, data=data))
|
log.debug('({ip}) get_data(): Checking new data "{data}"'.format(ip=self.ip, data=data))
|
||||||
header, data = data.split('=')
|
header, data = data.split('=')
|
||||||
# At this point, the header should contain:
|
# At this point, the header should contain:
|
||||||
@ -947,15 +958,17 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
self.change_status(E_INVALID_DATA)
|
self.change_status(E_INVALID_DATA)
|
||||||
log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in))
|
log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in))
|
||||||
return self._trash_buffer('get_data(): Expected header + command + data')
|
self._trash_buffer('get_data(): Expected header + command + data')
|
||||||
|
return self.receive_data_signal()
|
||||||
if cmd not in PJLINK_VALID_CMD:
|
if cmd not in PJLINK_VALID_CMD:
|
||||||
log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
|
log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd))
|
||||||
return self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))
|
self._trash_buffer(msg='get_data(): Unknown command "{data}"'.format(data=cmd))
|
||||||
|
return self.receive_data_signal()
|
||||||
if int(self.pjlink_class) < int(version):
|
if int(self.pjlink_class) < int(version):
|
||||||
log.warning('({ip}) get_data(): Projector returned class reply higher '
|
log.warning('({ip}) get_data(): Projector returned class reply higher '
|
||||||
'than projector stated class'.format(ip=self.ip))
|
'than projector stated class'.format(ip=self.ip))
|
||||||
self.send_busy = False
|
self.process_command(cmd, data)
|
||||||
return self.process_command(cmd, data)
|
return self.receive_data_signal()
|
||||||
|
|
||||||
@QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)
|
@QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)
|
||||||
def get_error(self, err):
|
def get_error(self, err):
|
||||||
@ -993,7 +1006,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
:param salt: Optional salt for md5 hash initial authentication
|
:param salt: Optional salt for md5 hash initial authentication
|
||||||
:param priority: Option to send packet now rather than queue it up
|
:param priority: Option to send packet now rather than queue it up
|
||||||
"""
|
"""
|
||||||
if self.state() != self.ConnectedState:
|
if QSOCKET_STATE[self.state()] != S_CONNECTED:
|
||||||
log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip))
|
log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip))
|
||||||
return self.reset_information()
|
return self.reset_information()
|
||||||
if cmd not in PJLINK_VALID_CMD:
|
if cmd not in PJLINK_VALID_CMD:
|
||||||
@ -1018,7 +1031,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
header=header,
|
header=header,
|
||||||
command=cmd,
|
command=cmd,
|
||||||
options=opts,
|
options=opts,
|
||||||
suffix=CR)
|
suffix=PJLINK_SUFFIX)
|
||||||
if out in self.priority_queue:
|
if out in self.priority_queue:
|
||||||
log.debug('({ip}) send_command(): Already in priority queue - skipping'.format(ip=self.ip))
|
log.debug('({ip}) send_command(): Already in priority queue - skipping'.format(ip=self.ip))
|
||||||
elif out in self.send_queue:
|
elif out in self.send_queue:
|
||||||
@ -1044,9 +1057,10 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
"""
|
"""
|
||||||
# Funny looking data check, but it's a quick check for data=None
|
# Funny looking data check, but it's a quick check for data=None
|
||||||
log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.ip, data=data.strip() if data else data))
|
log.debug('({ip}) _send_command(data="{data}")'.format(ip=self.ip, data=data.strip() if data else data))
|
||||||
|
conn_state = STATUS_CODE[QSOCKET_STATE[self.state()]]
|
||||||
log.debug('({ip}) _send_command(): Connection status: {data}'.format(ip=self.ip,
|
log.debug('({ip}) _send_command(): Connection status: {data}'.format(ip=self.ip,
|
||||||
data=S_QSOCKET_STATE[self.state()]))
|
data=conn_state))
|
||||||
if self.state() != self.ConnectedState:
|
if QSOCKET_STATE[self.state()] != S_CONNECTED:
|
||||||
log.debug('({ip}) _send_command() Not connected - abort'.format(ip=self.ip))
|
log.debug('({ip}) _send_command() Not connected - abort'.format(ip=self.ip))
|
||||||
self.send_busy = False
|
self.send_busy = False
|
||||||
return self.disconnect_from_host()
|
return self.disconnect_from_host()
|
||||||
@ -1088,10 +1102,11 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
"""
|
"""
|
||||||
Initiate connection to projector.
|
Initiate connection to projector.
|
||||||
"""
|
"""
|
||||||
log.debug('{ip}) connect_to_host(): Starting connection'.format(ip=self.ip))
|
log.debug('({ip}) connect_to_host(): Starting connection'.format(ip=self.ip))
|
||||||
if self.state() == self.ConnectedState:
|
if QSOCKET_STATE[self.state()] == S_CONNECTED:
|
||||||
log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip))
|
log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip))
|
||||||
return
|
return
|
||||||
|
self.error_status = S_OK
|
||||||
self.change_status(S_CONNECTING)
|
self.change_status(S_CONNECTING)
|
||||||
self.connectToHost(self.ip, self.port if isinstance(self.port, int) else int(self.port))
|
self.connectToHost(self.ip, self.port if isinstance(self.port, int) else int(self.port))
|
||||||
|
|
||||||
@ -1100,12 +1115,13 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
"""
|
"""
|
||||||
Close socket and cleanup.
|
Close socket and cleanup.
|
||||||
"""
|
"""
|
||||||
if abort or self.state() != self.ConnectedState:
|
if abort or QSOCKET_STATE[self.state()] != S_NOT_CONNECTED:
|
||||||
if abort:
|
if abort:
|
||||||
log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip))
|
log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip))
|
||||||
|
self.abort()
|
||||||
else:
|
else:
|
||||||
log.warning('({ip}) disconnect_from_host(): Not connected'.format(ip=self.ip))
|
log.warning('({ip}) disconnect_from_host(): Not connected'.format(ip=self.ip))
|
||||||
self.disconnectFromHost()
|
self.disconnectFromHost()
|
||||||
try:
|
try:
|
||||||
self.readyRead.disconnect(self.get_socket)
|
self.readyRead.disconnect(self.get_socket)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
@ -1201,7 +1217,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
elif src not in self.source_available:
|
elif src not in self.source_available:
|
||||||
return
|
return
|
||||||
log.debug('({ip}) Setting input source to "{data}"'.format(ip=self.ip, data=src))
|
log.debug('({ip}) Setting input source to "{data}"'.format(ip=self.ip, data=src))
|
||||||
self.send_command(cmd='INPT', opts=src)
|
self.send_command(cmd='INPT', opts=src, priority=True)
|
||||||
self.poll_loop()
|
self.poll_loop()
|
||||||
|
|
||||||
def set_power_on(self):
|
def set_power_on(self):
|
||||||
@ -1209,7 +1225,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
Send command to turn power to on.
|
Send command to turn power to on.
|
||||||
"""
|
"""
|
||||||
log.debug('({ip}) Setting POWR to 1 (on)'.format(ip=self.ip))
|
log.debug('({ip}) Setting POWR to 1 (on)'.format(ip=self.ip))
|
||||||
self.send_command(cmd='POWR', opts='1')
|
self.send_command(cmd='POWR', opts='1', priority=True)
|
||||||
self.poll_loop()
|
self.poll_loop()
|
||||||
|
|
||||||
def set_power_off(self):
|
def set_power_off(self):
|
||||||
@ -1217,7 +1233,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
Send command to turn power to standby.
|
Send command to turn power to standby.
|
||||||
"""
|
"""
|
||||||
log.debug('({ip}) Setting POWR to 0 (standby)'.format(ip=self.ip))
|
log.debug('({ip}) Setting POWR to 0 (standby)'.format(ip=self.ip))
|
||||||
self.send_command(cmd='POWR', opts='0')
|
self.send_command(cmd='POWR', opts='0', priority=True)
|
||||||
self.poll_loop()
|
self.poll_loop()
|
||||||
|
|
||||||
def set_shutter_closed(self):
|
def set_shutter_closed(self):
|
||||||
@ -1225,7 +1241,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
Send command to set shutter to closed position.
|
Send command to set shutter to closed position.
|
||||||
"""
|
"""
|
||||||
log.debug('({ip}) Setting AVMT to 11 (shutter closed)'.format(ip=self.ip))
|
log.debug('({ip}) Setting AVMT to 11 (shutter closed)'.format(ip=self.ip))
|
||||||
self.send_command(cmd='AVMT', opts='11')
|
self.send_command(cmd='AVMT', opts='11', priority=True)
|
||||||
self.poll_loop()
|
self.poll_loop()
|
||||||
|
|
||||||
def set_shutter_open(self):
|
def set_shutter_open(self):
|
||||||
@ -1233,8 +1249,9 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands):
|
|||||||
Send command to set shutter to open position.
|
Send command to set shutter to open position.
|
||||||
"""
|
"""
|
||||||
log.debug('({ip}) Setting AVMT to "10" (shutter open)'.format(ip=self.ip))
|
log.debug('({ip}) Setting AVMT to "10" (shutter open)'.format(ip=self.ip))
|
||||||
self.send_command(cmd='AVMT', opts='10')
|
self.send_command(cmd='AVMT', opts='10', priority=True)
|
||||||
self.poll_loop()
|
self.poll_loop()
|
||||||
|
self.projectorUpdateIcons.emit()
|
||||||
|
|
||||||
def receive_data_signal(self):
|
def receive_data_signal(self):
|
||||||
"""
|
"""
|
||||||
|
@ -23,12 +23,51 @@
|
|||||||
Package to test the openlp.core.projectors.constants module.
|
Package to test the openlp.core.projectors.constants module.
|
||||||
"""
|
"""
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
from openlp.core.projectors import constants
|
||||||
|
from openlp.core.projectors.constants import STATUS_CODE, STATUS_MSG
|
||||||
|
|
||||||
|
|
||||||
class TestProjectorConstants(TestCase):
|
class TestProjectorConstants(TestCase):
|
||||||
"""
|
"""
|
||||||
Test specific functions in the projector constants module.
|
Test specific functions in the projector constants module.
|
||||||
"""
|
"""
|
||||||
|
def test_defined_codes_in_status_code(self):
|
||||||
|
"""
|
||||||
|
Test defined status/error codes have equivalent strings
|
||||||
|
"""
|
||||||
|
check = []
|
||||||
|
missing_str = []
|
||||||
|
|
||||||
|
# GIVEN: List of defined E_* and S_* items defined in constants
|
||||||
|
for item in constants.__dict__:
|
||||||
|
if item.startswith('E_') or item.startswith('S_'):
|
||||||
|
check.append(item)
|
||||||
|
|
||||||
|
# WHEN: Verify defined list against STATUS_STR
|
||||||
|
for item in check:
|
||||||
|
if constants.__dict__[item] not in STATUS_CODE:
|
||||||
|
missing_str.append(item)
|
||||||
|
|
||||||
|
# THEN: There should be no missing items
|
||||||
|
assert 0 == len(missing_str), 'Status string missing: {msg}'.format(msg=missing_str)
|
||||||
|
|
||||||
|
def test_status_code_in_status_message(self):
|
||||||
|
"""
|
||||||
|
Test if entries in STATUS_CODE have equivalent descriptions in STATUS_MSG
|
||||||
|
"""
|
||||||
|
missing_msg = []
|
||||||
|
|
||||||
|
# GIVEN: Test items
|
||||||
|
check = STATUS_CODE
|
||||||
|
|
||||||
|
# WHEN: Verify each entry in STATUS_MSG against STATUS_CODE
|
||||||
|
for item in check:
|
||||||
|
if item not in STATUS_MSG:
|
||||||
|
missing_msg.append(item)
|
||||||
|
|
||||||
|
# THEN: There should be no missing items
|
||||||
|
assert 0 == len(missing_msg), 'Status message missing: {msg}'.format(msg=missing_msg)
|
||||||
|
|
||||||
def test_build_pjlink_video_label(self):
|
def test_build_pjlink_video_label(self):
|
||||||
"""
|
"""
|
||||||
Test building PJLINK_DEFAULT_CODES dictionary
|
Test building PJLINK_DEFAULT_CODES dictionary
|
||||||
|
@ -25,7 +25,7 @@ Package to test the openlp.core.projectors.pjlink base package.
|
|||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import call, patch, MagicMock
|
from unittest.mock import call, patch, MagicMock
|
||||||
|
|
||||||
from openlp.core.projectors.constants import E_PARAMETER, ERROR_STRING, S_ON, S_CONNECTED, S_QSOCKET_STATE
|
from openlp.core.projectors.constants import E_PARAMETER, STATUS_CODE, S_ON, S_CONNECTED, QSOCKET_STATE
|
||||||
from openlp.core.projectors.db import Projector
|
from openlp.core.projectors.db import Projector
|
||||||
from openlp.core.projectors.pjlink import PJLink
|
from openlp.core.projectors.pjlink import PJLink
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ class TestPJLinkBase(TestCase):
|
|||||||
# as first parameter
|
# as first parameter
|
||||||
mock_change_status.called_with(E_PARAMETER,
|
mock_change_status.called_with(E_PARAMETER,
|
||||||
'change_status should have been called with "{}"'.format(
|
'change_status should have been called with "{}"'.format(
|
||||||
ERROR_STRING[E_PARAMETER]))
|
STATUS_CODE[E_PARAMETER]))
|
||||||
|
|
||||||
@patch.object(pjlink_test, 'disconnect_from_host')
|
@patch.object(pjlink_test, 'disconnect_from_host')
|
||||||
def test_socket_abort(self, mock_disconnect):
|
def test_socket_abort(self, mock_disconnect):
|
||||||
@ -104,7 +104,7 @@ class TestPJLinkBase(TestCase):
|
|||||||
"""
|
"""
|
||||||
# GIVEN: Mocks and test data
|
# GIVEN: Mocks and test data
|
||||||
mock_state = patch.object(self.pjlink_test, 'state').start()
|
mock_state = patch.object(self.pjlink_test, 'state').start()
|
||||||
mock_state.return_value = S_QSOCKET_STATE['ConnectedState']
|
mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
|
||||||
mock_timer = patch.object(self.pjlink_test, 'timer').start()
|
mock_timer = patch.object(self.pjlink_test, 'timer').start()
|
||||||
mock_timer.interval.return_value = 10
|
mock_timer.interval.return_value = 10
|
||||||
mock_send_command = patch.object(self.pjlink_test, 'send_command').start()
|
mock_send_command = patch.object(self.pjlink_test, 'send_command').start()
|
||||||
@ -117,7 +117,6 @@ class TestPJLinkBase(TestCase):
|
|||||||
pjlink.manufacturer = None
|
pjlink.manufacturer = None
|
||||||
pjlink.model = None
|
pjlink.model = None
|
||||||
pjlink.pjlink_name = None
|
pjlink.pjlink_name = None
|
||||||
pjlink.ConnectedState = S_CONNECTED
|
|
||||||
call_list = [
|
call_list = [
|
||||||
call('POWR'),
|
call('POWR'),
|
||||||
call('ERST'),
|
call('ERST'),
|
||||||
|
@ -24,209 +24,222 @@ Package to test the openlp.core.projectors.pjlink command routing.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from unittest.mock import patch, MagicMock
|
from unittest.mock import MagicMock, call, patch
|
||||||
|
|
||||||
import openlp.core.projectors.pjlink
|
import openlp.core.projectors.pjlink
|
||||||
from openlp.core.projectors.constants import PJLINK_ERRORS, \
|
from openlp.core.projectors.constants import PJLINK_ERRORS, PJLINK_PREFIX, STATUS_MSG, \
|
||||||
E_AUTHENTICATION, E_PARAMETER, E_PROJECTOR, E_UNAVAILABLE, E_UNDEFINED
|
E_AUTHENTICATION, E_PARAMETER, E_PROJECTOR, E_UNAVAILABLE, E_UNDEFINED
|
||||||
from openlp.core.projectors.db import Projector
|
from openlp.core.projectors.db import Projector
|
||||||
from openlp.core.projectors.pjlink import PJLink
|
from openlp.core.projectors.pjlink import PJLink
|
||||||
|
|
||||||
'''
|
from tests.resources.projector.data import TEST1_DATA
|
||||||
from openlp.core.projectors.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, TEST1_DATA
|
|
||||||
|
|
||||||
pjlink_test = PJLink(Projector(**TEST1_DATA), pin=TEST_PIN, no_poll=True)
|
|
||||||
pjlink_test.ip = '127.0.0.1'
|
|
||||||
|
|
||||||
|
|
||||||
class TestPJLinkRouting(TestCase):
|
class TestPJLinkRouting(TestCase):
|
||||||
"""
|
"""
|
||||||
Tests for the PJLink module command routing
|
Tests for the PJLink module command routing
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def test_get_data_unknown_command(self):
|
||||||
'''
|
"""
|
||||||
TestPJLinkCommands part 2 initialization
|
Test not a valid command
|
||||||
'''
|
"""
|
||||||
self.pjlink_test = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
# GIVEN: Test object
|
||||||
|
log_warning_text = [call('(111.111.111.111) get_data(): Invalid packet - unknown command "UNK"')]
|
||||||
|
log_debug_text = [call('(111.111.111.111) get_data(ip="111.111.111.111" buffer="b\'%1UNK=Huh?\'"'),
|
||||||
|
call('(111.111.111.111) get_data(): Checking new data "%1UNK=Huh?"')]
|
||||||
|
|
||||||
def tearDown(self):
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
'''
|
patch.object(openlp.core.projectors.pjlink.PJLink, '_trash_buffer') as mock_buffer:
|
||||||
TestPJLinkCommands part 2 cleanups
|
|
||||||
'''
|
|
||||||
self.pjlink_test = None
|
|
||||||
|
|
||||||
@patch.object(openlp.core.projectors.pjlink, 'log')
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
def test_process_command_call_clss(self, mock_log):
|
pjlink.pjlink_functions = MagicMock()
|
||||||
|
|
||||||
|
# WHEN: get_data called with an unknown command
|
||||||
|
pjlink.get_data(buff='{prefix}1UNK=Huh?'.format(prefix=PJLINK_PREFIX).encode('utf-8'))
|
||||||
|
|
||||||
|
# THEN: Appropriate log entries should have been made and methods called/not called
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_text)
|
||||||
|
mock_log.warning.assert_has_calls(log_warning_text)
|
||||||
|
self.assertFalse(pjlink.pjlink_functions.called, 'Should not have accessed pjlink_functions')
|
||||||
|
self.assertTrue(mock_buffer.called, 'Should have called _trash_buffer')
|
||||||
|
|
||||||
|
def test_process_command_call_clss(self):
|
||||||
"""
|
"""
|
||||||
Test process_command calls proper function
|
Test process_command calls proper function
|
||||||
"""
|
"""
|
||||||
# GIVEN: Test object
|
# GIVEN: Test object and mocks
|
||||||
pjlink = pjlink_test
|
log_debug_calls = [call('(111.111.111.111) Processing command "CLSS" with data "1"'),
|
||||||
log_text = '(127.0.0.1) Calling function for CLSS'
|
call('(111.111.111.111) Calling function for CLSS')]
|
||||||
mock_log.reset_mock()
|
|
||||||
mock_process_clss = MagicMock()
|
|
||||||
pjlink.pjlink_functions['CLSS'] = mock_process_clss
|
|
||||||
|
|
||||||
# WHEN: process_command is called with valid function and data
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
pjlink.process_command(cmd='CLSS', data='1')
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
|
||||||
|
|
||||||
# THEN: Process method should have been called properly
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
mock_log.debug.assert_called_with(log_text)
|
|
||||||
mock_process_clss.assert_called_with('1')
|
|
||||||
|
|
||||||
@patch.object(pjlink_test, 'change_status')
|
# WHEN: process_command is called with valid function and data
|
||||||
@patch.object(openlp.core.projectors.pjlink, 'log')
|
pjlink.process_command(cmd='CLSS', data='1')
|
||||||
def test_process_command_err1(self, mock_log, mock_change_status):
|
|
||||||
"""
|
|
||||||
Test ERR1 - Undefined projector function
|
|
||||||
"""
|
|
||||||
# GIVEN: Test object
|
|
||||||
pjlink = pjlink_test
|
|
||||||
log_text = '(127.0.0.1) Projector returned error "ERR1"'
|
|
||||||
mock_change_status.reset_mock()
|
|
||||||
mock_log.reset_mock()
|
|
||||||
|
|
||||||
# WHEN: process_command called with ERR1
|
# THEN: Appropriate log entries should have been made and methods called
|
||||||
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNDEFINED])
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
mock_process_clss.assert_called_once_with(data='1')
|
||||||
|
|
||||||
# THEN: Error should be logged and status_change should be called
|
def test_process_command_erra(self):
|
||||||
mock_change_status.assert_called_once_with(E_UNDEFINED, 'Undefined Command: "CLSS"')
|
|
||||||
mock_log.error.assert_called_with(log_text)
|
|
||||||
|
|
||||||
@patch.object(pjlink_test, 'change_status')
|
|
||||||
@patch.object(openlp.core.projectors.pjlink, 'log')
|
|
||||||
def test_process_command_err2(self, mock_log, mock_change_status):
|
|
||||||
"""
|
|
||||||
Test ERR2 - Parameter Error
|
|
||||||
"""
|
|
||||||
# GIVEN: Test object
|
|
||||||
pjlink = pjlink_test
|
|
||||||
log_text = '(127.0.0.1) Projector returned error "ERR2"'
|
|
||||||
mock_change_status.reset_mock()
|
|
||||||
mock_log.reset_mock()
|
|
||||||
|
|
||||||
# WHEN: process_command called with ERR2
|
|
||||||
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PARAMETER])
|
|
||||||
|
|
||||||
# THEN: Error should be logged and status_change should be called
|
|
||||||
mock_change_status.assert_called_once_with(E_PARAMETER)
|
|
||||||
mock_log.error.assert_called_with(log_text)
|
|
||||||
|
|
||||||
@patch.object(pjlink_test, 'change_status')
|
|
||||||
@patch.object(openlp.core.projectors.pjlink, 'log')
|
|
||||||
def test_process_command_err3(self, mock_log, mock_change_status):
|
|
||||||
"""
|
|
||||||
Test ERR3 - Unavailable error
|
|
||||||
"""
|
|
||||||
# GIVEN: Test object
|
|
||||||
pjlink = pjlink_test
|
|
||||||
log_text = '(127.0.0.1) Projector returned error "ERR3"'
|
|
||||||
mock_change_status.reset_mock()
|
|
||||||
mock_log.reset_mock()
|
|
||||||
|
|
||||||
# WHEN: process_command called with ERR3
|
|
||||||
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNAVAILABLE])
|
|
||||||
|
|
||||||
# THEN: Error should be logged and status_change should be called
|
|
||||||
mock_change_status.assert_called_once_with(E_UNAVAILABLE)
|
|
||||||
mock_log.error.assert_called_with(log_text)
|
|
||||||
|
|
||||||
@patch.object(pjlink_test, 'change_status')
|
|
||||||
@patch.object(openlp.core.projectors.pjlink, 'log')
|
|
||||||
def test_process_command_err4(self, mock_log, mock_change_status):
|
|
||||||
"""
|
|
||||||
Test ERR3 - Unavailable error
|
|
||||||
"""
|
|
||||||
# GIVEN: Test object
|
|
||||||
pjlink = pjlink_test
|
|
||||||
log_text = '(127.0.0.1) Projector returned error "ERR4"'
|
|
||||||
mock_change_status.reset_mock()
|
|
||||||
mock_log.reset_mock()
|
|
||||||
|
|
||||||
# WHEN: process_command called with ERR3
|
|
||||||
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PROJECTOR])
|
|
||||||
|
|
||||||
# THEN: Error should be logged and status_change should be called
|
|
||||||
mock_change_status.assert_called_once_with(E_PROJECTOR)
|
|
||||||
mock_log.error.assert_called_with(log_text)
|
|
||||||
|
|
||||||
@patch.object(pjlink_test, 'projectorAuthentication')
|
|
||||||
@patch.object(pjlink_test, 'change_status')
|
|
||||||
@patch.object(pjlink_test, 'disconnect_from_host')
|
|
||||||
@patch.object(openlp.core.projectors.pjlink, 'log')
|
|
||||||
def test_process_command_erra(self, mock_log, mock_disconnect, mock_change_status, mock_err_authenticate):
|
|
||||||
"""
|
"""
|
||||||
Test ERRA - Authentication Error
|
Test ERRA - Authentication Error
|
||||||
"""
|
"""
|
||||||
# GIVEN: Test object
|
# GIVEN: Test object
|
||||||
pjlink = pjlink_test
|
log_error_calls = [call('(111.111.111.111) PJLINK: {msg}'.format(msg=STATUS_MSG[E_AUTHENTICATION]))]
|
||||||
log_text = '(127.0.0.1) Projector returned error "ERRA"'
|
log_debug_calls = [call('(111.111.111.111) Processing command "PJLINK" with data "ERRA"')]
|
||||||
mock_change_status.reset_mock()
|
|
||||||
mock_log.reset_mock()
|
|
||||||
|
|
||||||
# WHEN: process_command called with ERRA
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_AUTHENTICATION])
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_pjlink') as mock_process_pjlink, \
|
||||||
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'change_status') as mock_change_status, \
|
||||||
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'disconnect_from_host') as mock_disconnect, \
|
||||||
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'projectorAuthentication') as mock_authentication:
|
||||||
|
|
||||||
# THEN: Error should be logged and several methods should be called
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
self.assertTrue(mock_disconnect.called, 'disconnect_from_host should have been called')
|
|
||||||
mock_change_status.assert_called_once_with(E_AUTHENTICATION)
|
# WHEN: process_command called with ERRA
|
||||||
mock_log.error.assert_called_with(log_text)
|
pjlink.process_command(cmd='PJLINK', data=PJLINK_ERRORS[E_AUTHENTICATION])
|
||||||
|
|
||||||
|
# THEN: Appropriate log entries should have been made and methods called/not called
|
||||||
|
mock_log.error.assert_has_calls(log_error_calls)
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
self.assertTrue(mock_disconnect.called, 'disconnect_from_host should have been called')
|
||||||
|
mock_change_status.assert_called_once_with(status=E_AUTHENTICATION)
|
||||||
|
mock_authentication.emit.assert_called_once_with(pjlink.name)
|
||||||
|
mock_process_pjlink.assert_not_called()
|
||||||
|
|
||||||
|
def test_process_command_err1(self):
|
||||||
|
"""
|
||||||
|
Test ERR1 - Undefined projector function
|
||||||
|
"""
|
||||||
|
# GIVEN: Test object
|
||||||
|
log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_UNDEFINED]))]
|
||||||
|
log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR1"'),
|
||||||
|
call('(111.111.111.111) Calling function for CLSS')]
|
||||||
|
|
||||||
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
|
||||||
|
|
||||||
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
|
|
||||||
|
# WHEN: process_command called with ERR1
|
||||||
|
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNDEFINED])
|
||||||
|
|
||||||
|
# THEN: Appropriate log entries should have been made and methods called
|
||||||
|
mock_log.error.assert_has_calls(log_error_text)
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_text)
|
||||||
|
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNDEFINED])
|
||||||
|
|
||||||
|
def test_process_command_err2(self):
|
||||||
|
"""
|
||||||
|
Test ERR2 - Parameter Error
|
||||||
|
"""
|
||||||
|
# GIVEN: Test object
|
||||||
|
log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_PARAMETER]))]
|
||||||
|
log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR2"'),
|
||||||
|
call('(111.111.111.111) Calling function for CLSS')]
|
||||||
|
|
||||||
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
|
||||||
|
|
||||||
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
|
|
||||||
|
# WHEN: process_command called with ERR2
|
||||||
|
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PARAMETER])
|
||||||
|
|
||||||
|
# THEN: Appropriate log entries should have been made and methods called/not called
|
||||||
|
mock_log.error.assert_has_calls(log_error_text)
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_text)
|
||||||
|
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PARAMETER])
|
||||||
|
|
||||||
|
def test_process_command_err3(self):
|
||||||
|
"""
|
||||||
|
Test ERR3 - Unavailable error
|
||||||
|
"""
|
||||||
|
# GIVEN: Test object
|
||||||
|
log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_UNAVAILABLE]))]
|
||||||
|
log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR3"'),
|
||||||
|
call('(111.111.111.111) Calling function for CLSS')]
|
||||||
|
|
||||||
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
|
||||||
|
|
||||||
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
|
|
||||||
|
# WHEN: process_command called with ERR3
|
||||||
|
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNAVAILABLE])
|
||||||
|
|
||||||
|
# THEN: Appropriate log entries should have been made and methods called
|
||||||
|
mock_log.error.assert_has_calls(log_error_text)
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_text)
|
||||||
|
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNAVAILABLE])
|
||||||
|
|
||||||
|
def test_process_command_err4(self):
|
||||||
|
"""
|
||||||
|
Test ERR3 - Unavailable error
|
||||||
|
"""
|
||||||
|
# GIVEN: Test object
|
||||||
|
log_error_text = [call('(111.111.111.111) CLSS: {msg}'.format(msg=STATUS_MSG[E_PROJECTOR]))]
|
||||||
|
log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "ERR4"'),
|
||||||
|
call('(111.111.111.111) Calling function for CLSS')]
|
||||||
|
|
||||||
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
|
||||||
|
|
||||||
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
|
|
||||||
|
# WHEN: process_command called with ERR4
|
||||||
|
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PROJECTOR])
|
||||||
|
|
||||||
|
# THEN: Appropriate log entries should have been made and methods called
|
||||||
|
mock_log.error.assert_has_calls(log_error_text)
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_text)
|
||||||
|
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PROJECTOR])
|
||||||
|
|
||||||
def test_process_command_future(self):
|
def test_process_command_future(self):
|
||||||
"""
|
"""
|
||||||
Test command valid but no method to process yet
|
Test command valid but no method to process yet
|
||||||
"""
|
"""
|
||||||
# GIVEN: Initial mocks and data
|
|
||||||
mock_log = patch.object(openlp.core.projectors.pjlink, 'log').start()
|
|
||||||
mock_functions = patch.object(self.pjlink_test, 'pjlink_functions').start()
|
|
||||||
mock_functions.return_value = []
|
|
||||||
|
|
||||||
pjlink = self.pjlink_test
|
|
||||||
log_text = '(111.111.111.111) Unable to process command="CLSS" (Future option?)'
|
|
||||||
|
|
||||||
# WHEN: process_command called with an unknown command
|
|
||||||
pjlink.process_command(cmd='CLSS', data='DONT CARE')
|
|
||||||
|
|
||||||
# THEN: Error should be logged and no command called
|
|
||||||
self.assertFalse(mock_functions.called, 'Should not have gotten to the end of the method')
|
|
||||||
mock_log.warning.assert_called_once_with(log_text)
|
|
||||||
|
|
||||||
@patch.object(pjlink_test, 'pjlink_functions')
|
|
||||||
@patch.object(openlp.core.projectors.pjlink, 'log')
|
|
||||||
def test_process_command_invalid(self, mock_log, mock_functions):
|
|
||||||
"""
|
|
||||||
Test not a valid command
|
|
||||||
"""
|
|
||||||
# GIVEN: Test object
|
# GIVEN: Test object
|
||||||
pjlink = pjlink_test
|
log_warning_text = [call('(111.111.111.111) Unable to process command="CLSS" (Future option?)')]
|
||||||
mock_functions.reset_mock()
|
log_debug_text = [call('(111.111.111.111) Processing command "CLSS" with data "Huh?"')]
|
||||||
mock_log.reset_mock()
|
|
||||||
|
|
||||||
# WHEN: process_command called with an unknown command
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
pjlink.process_command(cmd='Unknown', data='Dont Care')
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
|
||||||
log_text = '(127.0.0.1) Ignoring command="Unknown" (Invalid/Unknown)'
|
|
||||||
|
|
||||||
# THEN: Error should be logged and no command called
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
self.assertFalse(mock_functions.called, 'Should not have gotten to the end of the method')
|
pjlink.pjlink_functions = MagicMock()
|
||||||
mock_log.error.assert_called_once_with(log_text)
|
|
||||||
|
# WHEN: Processing a possible future command
|
||||||
|
pjlink.process_command(cmd='CLSS', data="Huh?")
|
||||||
|
|
||||||
|
# THEN: Appropriate log entries should have been made and methods called/not called
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_text)
|
||||||
|
mock_log.warning.assert_has_calls(log_warning_text)
|
||||||
|
self.assertFalse(pjlink.pjlink_functions.called, 'Should not have accessed pjlink_functions')
|
||||||
|
self.assertFalse(mock_process_clss.called, 'Should not have called process_clss')
|
||||||
|
|
||||||
def test_process_command_ok(self):
|
def test_process_command_ok(self):
|
||||||
"""
|
"""
|
||||||
Test command returned success
|
Test command returned success
|
||||||
"""
|
"""
|
||||||
# GIVEN: Initial mocks and data
|
# GIVEN: Initial mocks and data
|
||||||
mock_log = patch.object(openlp.core.projectors.pjlink, 'log').start()
|
# GIVEN: Test object and mocks
|
||||||
mock_send_command = patch.object(self.pjlink_test, 'send_command').start()
|
log_debug_calls = [call('(111.111.111.111) Processing command "CLSS" with data "OK"'),
|
||||||
|
call('(111.111.111.111) Command "CLSS" returned OK')]
|
||||||
|
|
||||||
pjlink = self.pjlink_test
|
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
|
||||||
log_text = '(111.111.111.111) Command "POWR" returned OK'
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
|
||||||
|
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
|
||||||
|
|
||||||
# WHEN: process_command called with a command that returns OK
|
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
|
||||||
pjlink.process_command(cmd='POWR', data='OK')
|
|
||||||
|
|
||||||
# THEN: Appropriate calls should have been made
|
# WHEN: process_command is called with valid function and data
|
||||||
mock_log.debug.assert_called_with(log_text)
|
pjlink.process_command(cmd='CLSS', data='OK')
|
||||||
mock_send_command.assert_called_once_with(cmd='POWR')
|
|
||||||
|
# THEN: Appropriate log entries should have been made and methods called
|
||||||
|
mock_log.debug.assert_has_calls(log_debug_calls)
|
||||||
|
mock_send_command.assert_called_once_with(cmd='CLSS')
|
||||||
|
mock_process_clss.assert_not_called()
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user