From f04e544f2e30ec8b2ac66579e2b8892c094f93f8 Mon Sep 17 00:00:00 2001 From: Nmstr Date: Thu, 1 Jan 2026 17:19:20 +0100 Subject: [PATCH 1/4] added ArtNet backend --- .../output/output_backends/artnet_backend.py | 45 +++++++++++++++++++ pyproject.toml | 1 + uv.lock | 27 ++++++++++- 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 LightDrive/output/output_backends/artnet_backend.py diff --git a/LightDrive/output/output_backends/artnet_backend.py b/LightDrive/output/output_backends/artnet_backend.py new file mode 100644 index 0000000..32fc314 --- /dev/null +++ b/LightDrive/output/output_backends/artnet_backend.py @@ -0,0 +1,45 @@ +from output.output_backends.generic_output_backend import GenericOutputBackend +from pyartnet import ArtNetNode +import threading +import asyncio + +class ArtNetBackend(GenericOutputBackend): + def __init__(self, target_ip: str, universe: int, max_fps: int, refresh_every: int) -> None: + super().__init__() + self._target_ip = target_ip + self._universe = universe + self._max_fps = max_fps + self._refresh_every = refresh_every + self._values = [0] * 512 + self._running = False + self._worker_task = None + + self._start_worker() + + def set_values(self, values: list[int]) -> None: + self._values = values + + def stop(self) -> None: + self._running = False + if self._worker_task: + self._worker_task.cancel() + + async def _run_worker(self): + self._running = True + async with ArtNetNode.create(self._target_ip, max_fps=self._max_fps, refresh_every=self._refresh_every) as node: + universe = node.add_universe(self._universe) + channel = universe.add_channel(start=1, width=512) + + while self._running: + channel.set_values(values=self._values) + await asyncio.sleep(1 / self._max_fps) # There is no reason to refresh quicker than the max fps + + def _start_worker(self) -> None: + loop = asyncio.get_event_loop() + self._worker_task = loop.create_task(self._run_worker()) + worker_thread = threading.Thread(target=self._run_loop, args=(loop,)) + worker_thread.start() + + def _run_loop(self, loop: asyncio.AbstractEventLoop) -> None: + asyncio.set_event_loop(loop) + loop.run_forever() diff --git a/pyproject.toml b/pyproject.toml index 7967859..f816530 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ classifiers = [ "Topic :: Home Automation", ] dependencies = [ + "pyartnet>=2.0", "pyside6>=6.10.1", ] [project.urls] diff --git a/uv.lock b/uv.lock index e0211d4..4855d1a 100644 --- a/uv.lock +++ b/uv.lock @@ -7,11 +7,27 @@ name = "lightdrive" version = "0.0.0.dev0" source = { virtual = "." } dependencies = [ + { name = "pyartnet" }, { name = "pyside6" }, ] [package.metadata] -requires-dist = [{ name = "pyside6", specifier = ">=6.10.1" }] +requires-dist = [ + { name = "pyartnet", specifier = ">=2.0" }, + { name = "pyside6", specifier = ">=6.10.1" }, +] + +[[package]] +name = "pyartnet" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/d7/6d75c0bcaab1418e9f378549bca8a73a4c614fb2a051e333bc93b97cbfc1/pyartnet-2.0.tar.gz", hash = "sha256:da88614eae7ed2feeeb741a7a790201668a12f7d5c458730cbe08677d4ad5c71", size = 16296, upload-time = "2025-11-04T05:56:59.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/56/a98750ea692d74ed5c2fe30760c93b4878097a1815c4c9ae3a9877d37292/pyartnet-2.0-py3-none-any.whl", hash = "sha256:f0e181dbdcce30806460685ae1ec45444b8ece446caac8593b5e42f327ac9a3d", size = 26146, upload-time = "2025-11-04T05:56:58.139Z" }, +] [[package]] name = "pyside6" @@ -72,3 +88,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cf/a6/8c65ee0fa5e172ebcca03246b1bc3bd96cdaf1d60537316648536b7072a5/shiboken6-6.10.1-cp39-abi3-win_amd64.whl", hash = "sha256:c1601d3cda1fa32779b141663873741b54e797cb0328458d7466281f117b0a4e", size = 1234704, upload-time = "2025-11-20T10:08:57.417Z" }, { url = "https://files.pythonhosted.org/packages/7b/6a/c0fea2f2ac7d9d96618c98156500683a4d1f93fea0e8c5a2bc39913d7ef1/shiboken6-6.10.1-cp39-abi3-win_arm64.whl", hash = "sha256:5cf800917008587b551005a45add2d485cca66f5f7ecd5b320e9954e40448cc9", size = 1795567, upload-time = "2025-11-20T10:08:59.184Z" }, ] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] From 1622bbefaa1b5aaf3d7b0dc760cbdceb8793058c Mon Sep 17 00:00:00 2001 From: Nmstr Date: Thu, 1 Jan 2026 17:32:17 +0100 Subject: [PATCH 2/4] added qml for ArtNet configuration --- .../Pages/IoPage/ConfigureUniversePopup.qml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml b/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml index 826f93e..b283243 100644 --- a/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml +++ b/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml @@ -99,6 +99,65 @@ Popup { editable: true } } + Row { + CheckBox { + anchors.verticalCenter: parent.verticalCenter + id: artnetBackendCheckbox + } + Text { + anchors.verticalCenter: parent.verticalCenter + text: "Enable ArtNet" + color: "white" + } + } + GridLayout { + id: artnetBackendGrid + columns: 2 + enabled: artnetBackendCheckbox.checkState + + Text { + text: "Target IP:" + color: "white" + } + TextField { + id: artnetTargetIpInput + placeholderText: "127.0.0.1" + text: "127.0.0.1" + } + Text { + text: "Universe:" + color: "white" + } + SpinBox { + id: artnetUniverseSpin + from: 0 + to: 32767 + stepSize: 1 + editable: true + } + Text { + text: "Max FPS" + color: "white" + } + SpinBox { + id: artnetMaxFpsSpin + from: 1 + to: 100 + stepSize: 1 + editable: true + } + Text { + text: "Min Interval:" + color: "white" + } + SpinBox { + id: artnetMinIntervalSpin + from: 100 + to: 100_000 + stepSize: 100 + editable: true + } + } } Row { From f34fea71dde370cef277e184ddb07b5ff126cd8e Mon Sep 17 00:00:00 2001 From: Nmstr Date: Thu, 1 Jan 2026 18:58:56 +0100 Subject: [PATCH 3/4] ArtNet backend can now be configured --- LightDrive/data_structures.py | 8 +++++ .../output/output_backends/artnet_backend.py | 24 ++++++++++----- LightDrive/output/output_universe.py | 21 +++++++++++++ .../Pages/IoPage/ConfigureUniversePopup.qml | 14 +++++++++ LightDrive/universe_handler.py | 30 ++++++++++++++++++- 5 files changed, 89 insertions(+), 8 deletions(-) diff --git a/LightDrive/data_structures.py b/LightDrive/data_structures.py index c4ac961..c0153d1 100644 --- a/LightDrive/data_structures.py +++ b/LightDrive/data_structures.py @@ -11,11 +11,19 @@ class UniverseTcpBackend(UniverseGenericBackend): port: int = field(default=7500, init=False) hz: int = field(default=30, init=False) +@dataclass +class UniverseArtNetBackend(UniverseGenericBackend): + target_ip: str = field(default="127.0.0.1", init=False) + universe: int = field(default=0, init=False) + max_fps: int = field(default=25, init=False) + min_interval: int = field(default=2000, init=False) + @dataclass class Universe: uuid: str = field(default_factory=lambda: str(uuid.uuid4()), init=False) name: str tcp_backend: UniverseTcpBackend = field(default_factory=UniverseTcpBackend, init=False) + artnet_backend: UniverseArtNetBackend = field(default_factory=UniverseArtNetBackend, init=False) @dataclass diff --git a/LightDrive/output/output_backends/artnet_backend.py b/LightDrive/output/output_backends/artnet_backend.py index 32fc314..2120615 100644 --- a/LightDrive/output/output_backends/artnet_backend.py +++ b/LightDrive/output/output_backends/artnet_backend.py @@ -12,6 +12,7 @@ def __init__(self, target_ip: str, universe: int, max_fps: int, refresh_every: i self._refresh_every = refresh_every self._values = [0] * 512 self._running = False + self._config_changed = False self._worker_task = None self._start_worker() @@ -26,16 +27,18 @@ def stop(self) -> None: async def _run_worker(self): self._running = True - async with ArtNetNode.create(self._target_ip, max_fps=self._max_fps, refresh_every=self._refresh_every) as node: - universe = node.add_universe(self._universe) - channel = universe.add_channel(start=1, width=512) + while self._running: + async with ArtNetNode.create(self._target_ip, max_fps=self._max_fps, refresh_every=self._refresh_every) as node: + universe = node.add_universe(self._universe) + channel = universe.add_channel(start=1, width=512) - while self._running: - channel.set_values(values=self._values) - await asyncio.sleep(1 / self._max_fps) # There is no reason to refresh quicker than the max fps + while not self._config_changed: + channel.set_values(values=self._values) + await asyncio.sleep(1 / self._max_fps) # There is no reason to refresh quicker than the max fps + self._config_changed = False def _start_worker(self) -> None: - loop = asyncio.get_event_loop() + loop = asyncio.new_event_loop() self._worker_task = loop.create_task(self._run_worker()) worker_thread = threading.Thread(target=self._run_loop, args=(loop,)) worker_thread.start() @@ -43,3 +46,10 @@ def _start_worker(self) -> None: def _run_loop(self, loop: asyncio.AbstractEventLoop) -> None: asyncio.set_event_loop(loop) loop.run_forever() + + def update_configuration(self, target_ip: str, universe: int, max_fps: int, refresh_every: int) -> None: + self._target_ip = target_ip + self._universe = universe + self._max_fps = max_fps + self._refresh_every = refresh_every + self._config_changed = True diff --git a/LightDrive/output/output_universe.py b/LightDrive/output/output_universe.py index a2fc964..ed9cb0d 100644 --- a/LightDrive/output/output_universe.py +++ b/LightDrive/output/output_universe.py @@ -1,5 +1,6 @@ from data_structures import Universe from output.output_backends.generic_output_backend import GenericOutputBackend +from output.output_backends.artnet_backend import ArtNetBackend from output.output_backends.tcp_backend import TcpBackend class OutputUniverse: @@ -16,6 +17,14 @@ def build_backends(self): tcp_backend = TcpBackend(target_ip, port, hz) self.output_backends.append(tcp_backend) + if self._universe_data.artnet_backend.enabled: + target_ip = self._universe_data.artnet_backend.target_ip + universe = self._universe_data.artnet_backend.universe + max_fps = self._universe_data.artnet_backend.max_fps + min_interval = self._universe_data.artnet_backend.min_interval + artnet_backend = ArtNetBackend(target_ip, universe, max_fps, min_interval) + self.output_backends.append(artnet_backend) + def update_backends(self): def _get_backend(backend_type) -> GenericOutputBackend | None: for backend in self.output_backends: @@ -36,6 +45,18 @@ def _get_backend(backend_type) -> GenericOutputBackend | None: tcp_backend = TcpBackend(tcp_backend_data.target_ip, tcp_backend_data.port, tcp_backend_data.hz) self.output_backends.append(tcp_backend) + artnet_backend = _get_backend(ArtNetBackend) + if artnet_backend and self._universe_data.artnet_backend.enabled: + artnet_backend_data = self._universe_data.artnet_backend + artnet_backend.update_configuration(artnet_backend_data.target_ip, artnet_backend_data.universe, artnet_backend_data.max_fps, artnet_backend_data.min_interval) + elif artnet_backend and not self._universe_data.artnet_backend.enabled: + artnet_backend.stop() + self.output_backends.remove(artnet_backend) + elif not artnet_backend and self._universe_data.artnet_backend.enabled: + artnet_backend_data = self._universe_data.artnet_backend + artnet_backend = ArtNetBackend(artnet_backend_data.target_ip, artnet_backend_data.universe, artnet_backend_data.max_fps, artnet_backend_data.min_interval) + self.output_backends.append(artnet_backend) + def tick_output(self, values: list[int]) -> None: """ Sends data from the snippets to all output backends. diff --git a/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml b/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml index b283243..bb29bbd 100644 --- a/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml +++ b/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml @@ -187,6 +187,7 @@ Popup { onClicked: { universeHandler.configure_universe(currentUuid, universeNameInput.text); universeHandler.configure_tcp_backend(currentUuid, tcpBackendCheckbox.checkState, tcpTargetIpInput.text, tcpPortInput.text, tcpHzSpin.value); + universeHandler.configure_artnet_backend(currentUuid, artnetBackendCheckbox.checkState, artnetTargetIpInput.text, artnetUniverseSpin.value, artnetMaxFpsSpin.value, artnetMinIntervalSpin.value); cleanup(); } } @@ -222,6 +223,13 @@ Popup { tcpTargetIpInput.text = tcpBackendData[1]; tcpPortInput.text = tcpBackendData[2]; tcpHzSpin.value = tcpBackendData[3]; + + let artnetBackendData = universeHandler.get_artnet_backend_configuration(currentUuid); + artnetBackendCheckbox.checkState = artnetBackendData[0]; + artnetTargetIpInput.text = artnetBackendData[1]; + artnetUniverseSpin.value = artnetBackendData[2]; + artnetMaxFpsSpin.value = artnetBackendData[3]; + artnetMinIntervalSpin.value = artnetBackendData[4]; } function cleanup() { @@ -232,6 +240,12 @@ Popup { tcpPortInput.text = "7500"; tcpHzSpin.value = 30 + artnetBackendCheckbox.checkState = false; + artnetTargetIpInput.text = "127.0.0.1"; + artnetUniverseSpin.value = 0; + artnetMaxFpsSpin.value = 25; + artnetMinIntervalSpin.value = 2; + currentUuid = ""; configureUniversePopup.close(); } diff --git a/LightDrive/universe_handler.py b/LightDrive/universe_handler.py index 34e7d9b..a54a6f6 100644 --- a/LightDrive/universe_handler.py +++ b/LightDrive/universe_handler.py @@ -72,4 +72,32 @@ def get_tcp_backend_configuration(self, universe_uuid: str) -> list: if universe.uuid == universe_uuid: return [universe.tcp_backend.enabled, universe.tcp_backend.target_ip, universe.tcp_backend.port, universe.tcp_backend.hz] else: - return [] \ No newline at end of file + return [] + + @Slot(str, bool, str, int, int, int) + def configure_artnet_backend(self, universe_uuid: str, enabled: bool, target_ip: str, universe_num: int, max_fps: int, min_interval: int) -> None: + if not universe_uuid: + return + for universe in self.root.workspace.universes: + if universe.uuid == universe_uuid: + universe_data = universe + break + else: + return + + universe_data.artnet_backend.enabled = enabled + universe_data.artnet_backend.target_ip = target_ip + universe_data.artnet_backend.universe = universe_num + universe_data.artnet_backend.max_fps = max_fps + universe_data.artnet_backend.min_interval = min_interval + self.root.output_manager.build_output_universes() + + @Slot(str, result=list) # See reason for type above + def get_artnet_backend_configuration(self, universe_uuid: str) -> list: + if not universe_uuid: + return [] + for universe in self.root.workspace.universes: + if universe.uuid == universe_uuid: + return [universe.artnet_backend.enabled, universe.artnet_backend.target_ip, universe.artnet_backend.universe, universe.artnet_backend.max_fps, universe.artnet_backend.min_interval] + else: + return [] From 3492d778f22034c0b7b6c29cc03032814fbfc988 Mon Sep 17 00:00:00 2001 From: Nmstr Date: Thu, 1 Jan 2026 19:55:14 +0100 Subject: [PATCH 4/4] switched artnet library --- LightDrive/data_structures.py | 3 +- .../output/output_backends/artnet_backend.py | 59 ++++++------------- LightDrive/output/output_universe.py | 9 ++- .../Pages/IoPage/ConfigureUniversePopup.qml | 21 ++----- LightDrive/universe_handler.py | 9 ++- pyproject.toml | 2 +- uv.lock | 24 ++------ 7 files changed, 38 insertions(+), 89 deletions(-) diff --git a/LightDrive/data_structures.py b/LightDrive/data_structures.py index c0153d1..5b132d5 100644 --- a/LightDrive/data_structures.py +++ b/LightDrive/data_structures.py @@ -15,8 +15,7 @@ class UniverseTcpBackend(UniverseGenericBackend): class UniverseArtNetBackend(UniverseGenericBackend): target_ip: str = field(default="127.0.0.1", init=False) universe: int = field(default=0, init=False) - max_fps: int = field(default=25, init=False) - min_interval: int = field(default=2000, init=False) + fps: int = field(default=30, init=False) @dataclass class Universe: diff --git a/LightDrive/output/output_backends/artnet_backend.py b/LightDrive/output/output_backends/artnet_backend.py index 2120615..777b702 100644 --- a/LightDrive/output/output_backends/artnet_backend.py +++ b/LightDrive/output/output_backends/artnet_backend.py @@ -1,55 +1,32 @@ from output.output_backends.generic_output_backend import GenericOutputBackend -from pyartnet import ArtNetNode -import threading -import asyncio +from stupidArtnet import StupidArtnet class ArtNetBackend(GenericOutputBackend): - def __init__(self, target_ip: str, universe: int, max_fps: int, refresh_every: int) -> None: + def __init__(self, target_ip: str, universe: int, fps: int) -> None: super().__init__() self._target_ip = target_ip self._universe = universe - self._max_fps = max_fps - self._refresh_every = refresh_every - self._values = [0] * 512 - self._running = False - self._config_changed = False - self._worker_task = None + self._fps = fps - self._start_worker() + self._packet_size = 512 + self._device = self.create_device() + + def create_device(self) -> StupidArtnet: + device = StupidArtnet(target_ip=self._target_ip, universe=self._universe, packet_size=self._packet_size, fps=self._fps, broadcast=True) + device.start() + return device def set_values(self, values: list[int]) -> None: - self._values = values + self._device.set(values) def stop(self) -> None: - self._running = False - if self._worker_task: - self._worker_task.cancel() - - async def _run_worker(self): - self._running = True - while self._running: - async with ArtNetNode.create(self._target_ip, max_fps=self._max_fps, refresh_every=self._refresh_every) as node: - universe = node.add_universe(self._universe) - channel = universe.add_channel(start=1, width=512) - - while not self._config_changed: - channel.set_values(values=self._values) - await asyncio.sleep(1 / self._max_fps) # There is no reason to refresh quicker than the max fps - self._config_changed = False + self._device.blackout() + self._device.stop() - def _start_worker(self) -> None: - loop = asyncio.new_event_loop() - self._worker_task = loop.create_task(self._run_worker()) - worker_thread = threading.Thread(target=self._run_loop, args=(loop,)) - worker_thread.start() - - def _run_loop(self, loop: asyncio.AbstractEventLoop) -> None: - asyncio.set_event_loop(loop) - loop.run_forever() - - def update_configuration(self, target_ip: str, universe: int, max_fps: int, refresh_every: int) -> None: + def update_configuration(self, target_ip: str, universe: int, fps: int) -> None: self._target_ip = target_ip self._universe = universe - self._max_fps = max_fps - self._refresh_every = refresh_every - self._config_changed = True + self._fps = fps + + self.stop() + self._device = self.create_device() diff --git a/LightDrive/output/output_universe.py b/LightDrive/output/output_universe.py index ed9cb0d..f0b5bd2 100644 --- a/LightDrive/output/output_universe.py +++ b/LightDrive/output/output_universe.py @@ -20,9 +20,8 @@ def build_backends(self): if self._universe_data.artnet_backend.enabled: target_ip = self._universe_data.artnet_backend.target_ip universe = self._universe_data.artnet_backend.universe - max_fps = self._universe_data.artnet_backend.max_fps - min_interval = self._universe_data.artnet_backend.min_interval - artnet_backend = ArtNetBackend(target_ip, universe, max_fps, min_interval) + fps = self._universe_data.artnet_backend.fps + artnet_backend = ArtNetBackend(target_ip, universe, fps) self.output_backends.append(artnet_backend) def update_backends(self): @@ -48,13 +47,13 @@ def _get_backend(backend_type) -> GenericOutputBackend | None: artnet_backend = _get_backend(ArtNetBackend) if artnet_backend and self._universe_data.artnet_backend.enabled: artnet_backend_data = self._universe_data.artnet_backend - artnet_backend.update_configuration(artnet_backend_data.target_ip, artnet_backend_data.universe, artnet_backend_data.max_fps, artnet_backend_data.min_interval) + artnet_backend.update_configuration(artnet_backend_data.target_ip, artnet_backend_data.universe, artnet_backend_data.fps) elif artnet_backend and not self._universe_data.artnet_backend.enabled: artnet_backend.stop() self.output_backends.remove(artnet_backend) elif not artnet_backend and self._universe_data.artnet_backend.enabled: artnet_backend_data = self._universe_data.artnet_backend - artnet_backend = ArtNetBackend(artnet_backend_data.target_ip, artnet_backend_data.universe, artnet_backend_data.max_fps, artnet_backend_data.min_interval) + artnet_backend = ArtNetBackend(artnet_backend_data.target_ip, artnet_backend_data.universe, artnet_backend_data.fps) self.output_backends.append(artnet_backend) def tick_output(self, values: list[int]) -> None: diff --git a/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml b/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml index bb29bbd..82df379 100644 --- a/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml +++ b/LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml @@ -140,23 +140,12 @@ Popup { color: "white" } SpinBox { - id: artnetMaxFpsSpin + id: artnetFpsSpin from: 1 to: 100 stepSize: 1 editable: true } - Text { - text: "Min Interval:" - color: "white" - } - SpinBox { - id: artnetMinIntervalSpin - from: 100 - to: 100_000 - stepSize: 100 - editable: true - } } } @@ -187,7 +176,7 @@ Popup { onClicked: { universeHandler.configure_universe(currentUuid, universeNameInput.text); universeHandler.configure_tcp_backend(currentUuid, tcpBackendCheckbox.checkState, tcpTargetIpInput.text, tcpPortInput.text, tcpHzSpin.value); - universeHandler.configure_artnet_backend(currentUuid, artnetBackendCheckbox.checkState, artnetTargetIpInput.text, artnetUniverseSpin.value, artnetMaxFpsSpin.value, artnetMinIntervalSpin.value); + universeHandler.configure_artnet_backend(currentUuid, artnetBackendCheckbox.checkState, artnetTargetIpInput.text, artnetUniverseSpin.value, artnetFpsSpin.value); cleanup(); } } @@ -228,8 +217,7 @@ Popup { artnetBackendCheckbox.checkState = artnetBackendData[0]; artnetTargetIpInput.text = artnetBackendData[1]; artnetUniverseSpin.value = artnetBackendData[2]; - artnetMaxFpsSpin.value = artnetBackendData[3]; - artnetMinIntervalSpin.value = artnetBackendData[4]; + artnetFpsSpin.value = artnetBackendData[3]; } function cleanup() { @@ -243,8 +231,7 @@ Popup { artnetBackendCheckbox.checkState = false; artnetTargetIpInput.text = "127.0.0.1"; artnetUniverseSpin.value = 0; - artnetMaxFpsSpin.value = 25; - artnetMinIntervalSpin.value = 2; + artnetFpsSpin.value = 30; currentUuid = ""; configureUniversePopup.close(); diff --git a/LightDrive/universe_handler.py b/LightDrive/universe_handler.py index a54a6f6..d707660 100644 --- a/LightDrive/universe_handler.py +++ b/LightDrive/universe_handler.py @@ -74,8 +74,8 @@ def get_tcp_backend_configuration(self, universe_uuid: str) -> list: else: return [] - @Slot(str, bool, str, int, int, int) - def configure_artnet_backend(self, universe_uuid: str, enabled: bool, target_ip: str, universe_num: int, max_fps: int, min_interval: int) -> None: + @Slot(str, bool, str, int, int) + def configure_artnet_backend(self, universe_uuid: str, enabled: bool, target_ip: str, universe_num: int, fps: int) -> None: if not universe_uuid: return for universe in self.root.workspace.universes: @@ -88,8 +88,7 @@ def configure_artnet_backend(self, universe_uuid: str, enabled: bool, target_ip: universe_data.artnet_backend.enabled = enabled universe_data.artnet_backend.target_ip = target_ip universe_data.artnet_backend.universe = universe_num - universe_data.artnet_backend.max_fps = max_fps - universe_data.artnet_backend.min_interval = min_interval + universe_data.artnet_backend.fps = fps self.root.output_manager.build_output_universes() @Slot(str, result=list) # See reason for type above @@ -98,6 +97,6 @@ def get_artnet_backend_configuration(self, universe_uuid: str) -> list: return [] for universe in self.root.workspace.universes: if universe.uuid == universe_uuid: - return [universe.artnet_backend.enabled, universe.artnet_backend.target_ip, universe.artnet_backend.universe, universe.artnet_backend.max_fps, universe.artnet_backend.min_interval] + return [universe.artnet_backend.enabled, universe.artnet_backend.target_ip, universe.artnet_backend.universe, universe.artnet_backend.fps] else: return [] diff --git a/pyproject.toml b/pyproject.toml index f816530..5ed88e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,8 +17,8 @@ classifiers = [ "Topic :: Home Automation", ] dependencies = [ - "pyartnet>=2.0", "pyside6>=6.10.1", + "stupidartnet>=1.6.0", ] [project.urls] Source = "https://github.com/Nmstr/LightDrive" diff --git a/uv.lock b/uv.lock index 4855d1a..932f4f9 100644 --- a/uv.lock +++ b/uv.lock @@ -7,26 +7,14 @@ name = "lightdrive" version = "0.0.0.dev0" source = { virtual = "." } dependencies = [ - { name = "pyartnet" }, { name = "pyside6" }, + { name = "stupidartnet" }, ] [package.metadata] requires-dist = [ - { name = "pyartnet", specifier = ">=2.0" }, { name = "pyside6", specifier = ">=6.10.1" }, -] - -[[package]] -name = "pyartnet" -version = "2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/19/d7/6d75c0bcaab1418e9f378549bca8a73a4c614fb2a051e333bc93b97cbfc1/pyartnet-2.0.tar.gz", hash = "sha256:da88614eae7ed2feeeb741a7a790201668a12f7d5c458730cbe08677d4ad5c71", size = 16296, upload-time = "2025-11-04T05:56:59.573Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/56/a98750ea692d74ed5c2fe30760c93b4878097a1815c4c9ae3a9877d37292/pyartnet-2.0-py3-none-any.whl", hash = "sha256:f0e181dbdcce30806460685ae1ec45444b8ece446caac8593b5e42f327ac9a3d", size = 26146, upload-time = "2025-11-04T05:56:58.139Z" }, + { name = "stupidartnet", specifier = ">=1.6.0" }, ] [[package]] @@ -90,10 +78,10 @@ wheels = [ ] [[package]] -name = "typing-extensions" -version = "4.15.0" +name = "stupidartnet" +version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/41/ef5ac9d70b6694c41b21d42b2ba7b73772f4713f7b7c2b3c8b5c091ffe7f/stupidartnet-1.6.0.tar.gz", hash = "sha256:0e4c0cd0b662c2663ce0397d6f990dbae91576ad7c10230863e96d8d78c21845", size = 14892, upload-time = "2025-03-12T19:59:17.598Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/85/af/8ec0c05142bd915e9f95b85c238c0ae4a0ff61060c29b3b92a245b78139a/stupidartnet-1.6.0-py3-none-any.whl", hash = "sha256:b9b96fe23e759966b8692d99f0b6111f2b0a1b90b18e10a7bdc8a459ca3fe7c0", size = 12668, upload-time = "2025-03-12T19:59:16.453Z" }, ]