Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions LightDrive/data_structures.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@ 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)
fps: int = field(default=30, 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
Expand Down
32 changes: 32 additions & 0 deletions LightDrive/output/output_backends/artnet_backend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from output.output_backends.generic_output_backend import GenericOutputBackend
from stupidArtnet import StupidArtnet

class ArtNetBackend(GenericOutputBackend):
def __init__(self, target_ip: str, universe: int, fps: int) -> None:
super().__init__()
self._target_ip = target_ip
self._universe = universe
self._fps = fps

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._device.set(values)

def stop(self) -> None:
self._device.blackout()
self._device.stop()

def update_configuration(self, target_ip: str, universe: int, fps: int) -> None:
self._target_ip = target_ip
self._universe = universe
self._fps = fps

self.stop()
self._device = self.create_device()
20 changes: 20 additions & 0 deletions LightDrive/output/output_universe.py
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -16,6 +17,13 @@ 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
fps = self._universe_data.artnet_backend.fps
artnet_backend = ArtNetBackend(target_ip, universe, fps)
self.output_backends.append(artnet_backend)

def update_backends(self):
def _get_backend(backend_type) -> GenericOutputBackend | None:
for backend in self.output_backends:
Expand All @@ -36,6 +44,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.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.fps)
self.output_backends.append(artnet_backend)

def tick_output(self, values: list[int]) -> None:
"""
Sends data from the snippets to all output backends.
Expand Down
60 changes: 60 additions & 0 deletions LightDrive/qml/Pages/IoPage/ConfigureUniversePopup.qml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,54 @@ 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: artnetFpsSpin
from: 1
to: 100
stepSize: 1
editable: true
}
}
}

Row {
Expand Down Expand Up @@ -128,6 +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, artnetFpsSpin.value);
cleanup();
}
}
Expand Down Expand Up @@ -163,6 +212,12 @@ 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];
artnetFpsSpin.value = artnetBackendData[3];
}

function cleanup() {
Expand All @@ -173,6 +228,11 @@ Popup {
tcpPortInput.text = "7500";
tcpHzSpin.value = 30

artnetBackendCheckbox.checkState = false;
artnetTargetIpInput.text = "127.0.0.1";
artnetUniverseSpin.value = 0;
artnetFpsSpin.value = 30;

currentUuid = "";
configureUniversePopup.close();
}
Expand Down
29 changes: 28 additions & 1 deletion LightDrive/universe_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,31 @@ 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 []
return []

@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:
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.fps = fps
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.fps]
else:
return []
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ classifiers = [
]
dependencies = [
"pyside6>=6.10.1",
"stupidartnet>=1.6.0",
]
[project.urls]
Source = "https://github.com/Nmstr/LightDrive"
Expand Down
15 changes: 14 additions & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.