From ec5f19ac8d54ed6964269bcf3a8b4f639e44e944 Mon Sep 17 00:00:00 2001 From: Mattallmighty Date: Mon, 15 Nov 2021 07:56:41 +1100 Subject: [PATCH] =?UTF-8?q?Fix=20QLC+=20Integration=20=E2=9C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/tasks.json | 8 +- .../DialogAddEventListener.js | 2 +- ledfx/api/integration_qlc.py | 123 +++++++++--------- ledfx/integrations/qlc.py | 24 ++-- 4 files changed, 78 insertions(+), 79 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b770e77d..c8aefb9a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -24,9 +24,11 @@ { "label": "[3]-[Frontend]:3000-start", "type": "shell", - // "command": "runuser -l vscode -c 'cd /workspaces/${workspaceFolderBasename}/frontend; yarn; yarn start'", "command": "cd /workspaces/${workspaceFolderBasename}/frontend; yarn; yarn start", - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -60,7 +62,7 @@ "type": "shell", "command": "rm -rf /workspaces/${workspaceFolderBasename}/ledfx_frontend/*; runuser -l vscode -c 'cd /workspaces/${workspaceFolderBasename}/frontend; yarn build'", "problemMatcher": [] - }, + } ], "inputs": [ { diff --git a/frontend/src/components/IntegrationComponents/DialogAddEventListener.js b/frontend/src/components/IntegrationComponents/DialogAddEventListener.js index fecaab5e..19e2f0e3 100644 --- a/frontend/src/components/IntegrationComponents/DialogAddEventListener.js +++ b/frontend/src/components/IntegrationComponents/DialogAddEventListener.js @@ -50,7 +50,7 @@ function ConfirmationDialogRaw(props) { // console.log("qlcInfo - Response: ", qlcInfo); const effectNames = qlcInfo && qlcInfo.event_types && qlcInfo.event_types.effect_set.event_filters.effect_name //const effectCleared = qlcInfo && qlcInfo.event_types && qlcInfo.event_types.effect_cleared.event_name - const SceneSet = qlcInfo && qlcInfo.event_types && qlcInfo.event_types.scene_set.event_filters.scene_name + const SceneSet = qlcInfo && qlcInfo.event_types && qlcInfo.event_types.scene_activated.event_filters.scene_name const QLCWidgets = qlcInfo && qlcInfo.qlc_widgets && qlcInfo.qlc_widgets.sort((a,b) => parseInt(a[0]) - parseInt(b[0]) ) const EVENT_TYPES= qlcInfo && qlcInfo.event_types && qlcInfo.event_types // console.log("test3",EVENT_TYPES); diff --git a/ledfx/api/integration_qlc.py b/ledfx/api/integration_qlc.py index 3c5f23d3..f7d469fa 100644 --- a/ledfx/api/integration_qlc.py +++ b/ledfx/api/integration_qlc.py @@ -1,5 +1,4 @@ import logging -from json import JSONDecodeError from aiohttp import web @@ -15,60 +14,70 @@ class QLCEndpoint(RestEndpoint): ENDPOINT_PATH = "/api/integrations/qlc/{integration_id}" - async def get(self, integration_id) -> web.Response: + async def get(self, integration_id, request) -> web.Response: """Get info from QLC+ integration""" integration = self._ledfx.integrations.get(integration_id) if (integration is None) or (integration.type != "qlc"): response = {"not found": 404} return web.json_response(data=response, status=404) - response = {} + data = await request.json() + info = data.get("info") + if info is None: + response = { + "status": "failed", + "reason": 'Required attribute "info" was not provided', + } + return web.json_response(data=response, status=500) - # generate dict of {effect_id: effect_name} - effect_names = [] - for effect_type, effect in self._ledfx.effects.classes().items(): - effect_names.append(effect.NAME) + if info == "event_types": + # generate dict of {effect_id: effect_name} + effect_names = [] + for effect_type, effect in self._ledfx.effects.classes().items(): + effect_names.append(effect.NAME) - scene_names = [] - for scene in self._ledfx.config["scenes"]: - scene_names.append(self._ledfx.config["scenes"][scene]["name"]) + scene_names = [] + for scene in self._ledfx.config["scenes"]: + scene_names.append(self._ledfx.config["scenes"][scene]["name"]) - response["event_types"] = { - Event.EFFECT_SET: { - "event_name": "Effect Set", - "event_filters": {"effect_name": effect_names}, - }, - Event.EFFECT_CLEARED: { - "event_name": "Effect Cleared", - "event_filters": {}, - }, - Event.SCENE_SET: { - "event_name": "Scene Set", - "event_filters": {"scene_name": scene_names}, - }, - } + response = { + Event.EFFECT_SET: { + "event_name": "Effect Set", + "event_filters": {"effect_name": effect_names}, + }, + Event.EFFECT_CLEARED: { + "event_name": "Effect Cleared", + "event_filters": {}, + }, + Event.SCENE_SET: { + "event_name": "Scene Set", + "event_filters": {"scene_name": scene_names}, + }, + } - response["qlc_widgets"] = await integration.get_widgets() + elif info == "qlc_widgets": + response = await integration.get_widgets() - response["qlc_listeners"] = integration.data + elif info == "qlc_listeners": + response = integration.data + + else: + response = { + "status": "failed", + "reason": f'Unknown info parameter "{info}"', + } + return web.json_response(data=response, status=500) return web.json_response(data=response, status=200) async def put(self, integration_id, request) -> web.Response: - """Toggle a QLC event listener""" + """ Toggle a QLC event listener """ integration = self._ledfx.integrations.get(integration_id) if (integration is None) or (integration.type != "qlc"): response = {"not found": 404} return web.json_response(data=response, status=404) - try: - data = await request.json() - except JSONDecodeError: - response = { - "status": "failed", - "reason": "JSON Decoding failed", - } - return web.json_response(data=response, status=400) + data = await request.json() event_type = data.get("event_type") event_filter = data.get("event_filter") @@ -77,21 +86,21 @@ class QLCEndpoint(RestEndpoint): "status": "failed", "reason": 'Required attribute "event_type" was not provided', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) if event_filter is None: response = { "status": "failed", "reason": 'Required attribute "event_filter" was not provided', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) if type(event_filter) is not dict: response = { "status": "failed", "reason": f'Invalid filter "{event_filter}", should be dictionary eg. {{ "scene_name" : "my scene" }} ', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) # toggle the event listener if not integration.toggle_event(event_type, event_filter): @@ -99,7 +108,7 @@ class QLCEndpoint(RestEndpoint): "status": "failed", "reason": f"Could not find event with type {event_type} and filter {event_filter}", } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) # Save the configuration (integration will handle modifying "data") for _integration in self._ledfx.config["integrations"]: @@ -115,20 +124,13 @@ class QLCEndpoint(RestEndpoint): return web.json_response(data=response, status=200) async def post(self, integration_id, request) -> web.Response: - """Add a new QLC event listener or update an existing one""" + """ Add a new QLC event listener or update an existing one """ integration = self._ledfx.integrations.get(integration_id) if (integration is None) or (integration.type != "qlc"): response = {"not found": 404} return web.json_response(data=response, status=404) - try: - data = await request.json() - except JSONDecodeError: - response = { - "status": "failed", - "reason": "JSON Decoding failed", - } - return web.json_response(data=response, status=400) + data = await request.json() event_type = data.get("event_type") event_filter = data.get("event_filter") qlc_payload = data.get("qlc_payload") @@ -138,28 +140,28 @@ class QLCEndpoint(RestEndpoint): "status": "failed", "reason": 'Required attribute "event_type" was not provided', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) if event_filter is None: response = { "status": "failed", "reason": 'Required attribute "event_filter" was not provided', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) if type(event_filter) is not dict: response = { "status": "failed", "reason": f'Invalid filter "{event_filter}", should be dictionary eg. {{ "scene_name" : "my scene" }} ', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) if qlc_payload is None: response = { "status": "failed", "reason": 'Required attribute "qlc_payload" was not provided', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) # Create a link between ledfx event and sending the payload integration.create_event(event_type, event_filter, True, qlc_payload) @@ -178,20 +180,13 @@ class QLCEndpoint(RestEndpoint): return web.json_response(data=response, status=200) async def delete(self, integration_id, request) -> web.Response: - """Delete a QLC event listener""" + """ Delete a QLC event listener """ integration = self._ledfx.integrations.get(integration_id) if (integration is None) or (integration.type != "qlc"): response = {"not found": 404} return web.json_response(data=response, status=404) - try: - data = await request.json() - except JSONDecodeError: - response = { - "status": "failed", - "reason": "JSON Decoding failed", - } - return web.json_response(data=response, status=400) + data = await request.json() event_type = data.get("event_type") event_filter = data.get("event_filter") @@ -200,21 +195,21 @@ class QLCEndpoint(RestEndpoint): "status": "failed", "reason": 'Required attribute "event_type" was not provided', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) if event_filter is None: response = { "status": "failed", "reason": 'Required attribute "event_filter" was not provided', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) if type(event_filter) is not dict: response = { "status": "failed", "reason": f'Invalid filter "{event_filter}", should be dictionary eg. {{ "scene_name" : "my scene" }} ', } - return web.json_response(data=response, status=400) + return web.json_response(data=response, status=500) # Delete the listener and event from data integration.delete_event(event_type, event_filter) diff --git a/ledfx/integrations/qlc.py b/ledfx/integrations/qlc.py index 0fc0a98c..27aaced6 100644 --- a/ledfx/integrations/qlc.py +++ b/ledfx/integrations/qlc.py @@ -62,7 +62,7 @@ class QLC(Integration): self.restore_from_data(data) def restore_from_data(self, data): - """Creates the event listeners from saved data""" + """ Creates the event listeners from saved data """ if data is not None: try: for entry in data: @@ -84,7 +84,7 @@ class QLC(Integration): return self._data def create_event(self, event_type, event_filter, active, qlc_payload): - """Create or update event listener that sends a qlc payload on a specific event""" + """ Create or update event listener that sends a qlc payload on a specific event """ # If it exists, remove the existing listener and update data for idx, entry in enumerate(self._data): _event_type, _event_filter, _active, _qlc_payload = entry @@ -110,7 +110,7 @@ class QLC(Integration): ) def delete_event(self, event_type, event_filter): - """Completely delete event listener and saved payload from data""" + """ Completely delete event listener and saved payload from data """ # remove listener if it exists self._remove_listener(event_type, event_filter) # remove event and payload from data @@ -123,7 +123,7 @@ class QLC(Integration): ) def toggle_event(self, event_type, event_filter): - """Toggle a payload linked to event on or off""" + """ Toggle a payload linked to event on or off """ # Update "active" flag in data for idx, entry in enumerate(self._data): _event_type, _event_filter, _active, _qlc_payload = entry @@ -149,7 +149,7 @@ class QLC(Integration): return False # failed to find event_type with this event_filter def _remove_listener(self, event_type, event_filter): - """Internal function to remove ledfx events listener if it exists""" + """ Internal function to remove ledfx events listener if it exists """ for idx, entry in enumerate(self._listeners): _event_type, _event_filter, listener = entry if (_event_type == event_type) and (_event_filter == event_filter): @@ -159,7 +159,7 @@ class QLC(Integration): break def _add_listener(self, event_type, event_filter, qlc_payload): - """Internal function that links payload to send on the specified event""" + """ Internal function that links payload to send on the specified event """ def make_callback(qlc_payload): def callback(_): @@ -180,7 +180,7 @@ class QLC(Integration): self._listeners.append((event_type, event_filter, listener)) async def get_widgets(self): - """Returns a list of widgets as tuples: [(ID, Type, Name),...]""" + """ Returns a list of widgets as tuples: [(ID, Type, Name),...] """ # First get list of widgets (ID, Name) widgets = [] message = "QLC+API|getWidgetsList" @@ -198,7 +198,7 @@ class QLC(Integration): return widgets async def _send_payload(self, qlc_payload): - """Sends payload of {id:value, ...} pairs to QLC""" + """ Sends payload of {id:value, ...} pairs to QLC""" for widget_id, value in qlc_payload.items(): await self._client.send(f"{int(widget_id)}|{value}") @@ -238,12 +238,14 @@ class QLCWebsocketClient: self.websocket = None self.url = url self.domain = domain + self.session = aiohttp.ClientSession() async def connect(self): """Connect to the WebSocket.""" while True: try: - self.websocket = await aiohttp.ClientSession.ws_connect(self.domain) + self.websocket = await self.session.ws_connect(self.url) + #self.websocket = await self.ws_connect(self.url) return True except aiohttp.client_exceptions.ClientConnectorError: _LOGGER.info( @@ -276,7 +278,7 @@ class QLCWebsocketClient: await self.websocket.send_str(message) # Every call to the logger is a performance hit - # _LOGGER.debug(f"Sent message {message} to {self.domain}") + _LOGGER.debug(f"Sent message {message} to {self.domain}") async def receive(self): """Receive one message from the WebSocket.""" @@ -299,4 +301,4 @@ class QLCWebsocketClient: elif message.type == aiohttp.WSMsgType.CLOSED: break elif message.type == aiohttp.WSMsgType.ERROR: - break + break \ No newline at end of file