Skip to content

Commit

Permalink
Add event firing for device deactivation from errors and error recovery
Browse files Browse the repository at this point in the history
  • Loading branch information
shauneccles committed Feb 19, 2024
1 parent 3a7e156 commit d8372b8
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 49 deletions.
13 changes: 10 additions & 3 deletions ledfx/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@
import voluptuous as vol

from ledfx.config import save_config
from ledfx.events import DeviceCreatedEvent, DeviceUpdateEvent, Event
from ledfx.events import (
DeviceCreatedEvent,
DevicesUpdatedEvent,
DeviceUpdateEvent,
Event,
)
from ledfx.utils import (
AVAILABLE_FPS,
WLED,
Expand Down Expand Up @@ -557,13 +562,15 @@ def activate(self):
self.serial = serial.Serial(self.com_port, self.baudrate)
if self.serial.isOpen:
super().activate()
self._online = True

except serial.SerialException:
_LOGGER.critical(
_LOGGER.warning(
"Serial Error: Please ensure your device is connected, functioning and the correct COM port is selected."
)
# Todo: Trigger the UI to refresh after the clear effect call. Currently it still shows as active.
self._online = False
self.deactivate()
self._ledfx.events.fire_event(DevicesUpdatedEvent(self.id))

def deactivate(self):
super().deactivate()
Expand Down
5 changes: 4 additions & 1 deletion ledfx/devices/adalight.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import voluptuous as vol

from ledfx.devices import SerialDevice, packets
from ledfx.events import DevicesUpdatedEvent

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -48,7 +49,9 @@ def flush(self, data):
)

except serial.SerialException:
_LOGGER.critical(
# If we have lost connection, log it, go offline, and fire an event to the frontend
_LOGGER.warning(
"Serial Connection Interrupted. Please check connections and ensure your device is functioning correctly."
)
self.deactivate()
self._ledfx.events.fire_event(DevicesUpdatedEvent(self.id))
19 changes: 13 additions & 6 deletions ledfx/devices/ddp.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import voluptuous as vol

from ledfx.devices import UDPDevice
from ledfx.events import DevicesUpdatedEvent

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -56,6 +57,7 @@ def __init__(self, ledfx, config):
def flush(self, data):
self.frame_count += 1
try:

DDPDevice.send_out(
self._sock,
self.destination,
Expand All @@ -64,19 +66,24 @@ def flush(self, data):
self.frame_count,
)
if self.connection_warning:
_LOGGER.info(
f"DDP connection reestablished to {self.config['name']}"
)
# If we have reconnected, log it, come back online, and fire an event to the frontend
_LOGGER.info(f"DDP connection reestablished to {self.name}")
self.connection_warning = False
self._online = True
self._ledfx.events.fire_event(
DevicesUpdatedEvent(self.id, online=True)
)
except AttributeError:
self.activate()
except OSError as e:
# print warning only once until it clears

if not self.connection_warning:
_LOGGER.warning(
f"Error in DDP connection to {self.config['name']}: {e}"
)
# If we have lost connection, log it, go offline, and fire an event to the frontend
_LOGGER.warning(f"Error in DDP connection to {self.name}: {e}")
self.connection_warning = True
self._online = False
self._ledfx.events.fire_event(DevicesUpdatedEvent(self.id))

@staticmethod
def send_out(sock, dest, port, data, frame_count):
Expand Down
2 changes: 1 addition & 1 deletion ledfx/devices/hue.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def activate(self):
)

if not handshake_success:
raise Exception(
_LOGGER.warning(
"Could not connect to the Bridge. Disconnect and reconnect it from power."
)

Expand Down
63 changes: 28 additions & 35 deletions ledfx/devices/openrgb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import numpy as np
import voluptuous as vol
from openrgb import OpenRGBClient

from ledfx.devices import NetworkedDevice, packets
from ledfx.events import DevicesUpdatedEvent
Expand Down Expand Up @@ -45,56 +46,46 @@ def __init__(self, ledfx, config):
self.ip_address = self._config["ip_address"]
self.port = self._config["port"]
self.openrgb_device_id = self._config["openrgb_id"]
self._online = True

def activate(self):
try:
from openrgb import OpenRGBClient

try:
self.openrgb_device = OpenRGBClient(
self.ip_address,
self.port,
self.name,
3, # protocol_version
)
self.openrgb_device = self.openrgb_device.devices[
self.openrgb_device_id
]
self._online = True
except (ConnectionRefusedError, TimeoutError):
_LOGGER.warning(
f"{self.openrgb_device_id} not reachable. Is the api server running?"
)
self._online = False
return
# check for eedevice

device_supports_direct = False
for mode in self.openrgb_device.modes:
if mode.name.lower() == "direct":
device_supports_direct = True
if not device_supports_direct:
raise ValueError()
except ImportError:
_LOGGER.critical("Unable to load openrgb library")
self.openrgb_device = OpenRGBClient(
self.ip_address,
self.port,
self.name,
3, # protocol_version
)
self.openrgb_device = self.openrgb_device.devices[
self.openrgb_device_id
]

except (ConnectionRefusedError, TimeoutError):
_LOGGER.warning(
f"{self.openrgb_device_id} not reachable. Is OpenRGB server running?"
)
self.deactivate()
except IndexError:
_LOGGER.critical(
_LOGGER.warning(
f"Couldn't find OpenRGB device ID: {self.openrgb_device_id}"
)
self._online = False

self.deactivate()
except ValueError:
_LOGGER.critical(
f"{self.openrgb_device_id} doesn't support direct mode, and isn't suitable for streamed effects from LedFx"

device_supports_direct = False
for mode in self.openrgb_device.modes:
if mode.name.lower() == "direct":
device_supports_direct = True
if not device_supports_direct:
_LOGGER.warning(
f"{self.openrgb_device_id} doesn't support direct mode - not supported by LedFx"
)
self.deactivate()
else:
self._online = True
super().activate()

def deactivate(self):

super().deactivate()

def flush(self, data):
Expand All @@ -108,7 +99,9 @@ def flush(self, data):
except AttributeError:
self.activate()
except ConnectionAbortedError:
# Unexpected device disconnect - deactivate and tell the frontend
_LOGGER.warning(f"Device disconnected: {self.openrgb_device_id}")

self._ledfx.events.fire_event(DevicesUpdatedEvent(self.id))
self._online = False
self.deactivate()
Expand Down
2 changes: 1 addition & 1 deletion ledfx/devices/rpi_ws281x.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def activate(self):
try:
from rpi_ws281x import PixelStrip
except ImportError:
_LOGGER.critical(
_LOGGER.warning(
"Unable to load ws281x module - are you on a Raspberry Pi?"
)
self.deactivate()
Expand Down
5 changes: 3 additions & 2 deletions ledfx/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ def __init__(self, device_name):


class DevicesUpdatedEvent(Event):
"""Weird event emitted when OpenRGB device fails to connect"""
"""
Event emitted when a device changes status due to something outside the users control - this is used to update the frontend
"""

def __init__(self, device_id: str):
super().__init__(Event.DEVICES_UPDATED)
Expand All @@ -66,7 +68,6 @@ class VirtualUpdateEvent(Event):
def __init__(self, virtual_id: str, pixels: np.ndarray):
super().__init__(Event.VIRTUAL_UPDATE)
self.virtual_id = virtual_id
# self.pixels = pixels.astype(np.uint8).T.tolist()
self.pixels = pixels


Expand Down

0 comments on commit d8372b8

Please sign in to comment.