changeset 1974:9a81855ec766

new artnet output module Ignore-this: b86cd8e651b5848cf03c247123647505
author drewp@bigasterisk.com
date Sat, 08 Jun 2019 07:43:46 +0000
parents aebe823b2414
children f66dbe512025
files bin/collector light9/collector/output.py
diffstat 2 files changed, 53 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/bin/collector	Sat Jun 08 07:37:43 2019 +0000
+++ b/bin/collector	Sat Jun 08 07:43:46 2019 +0000
@@ -27,7 +27,7 @@
 from rdfdb.syncedgraph import SyncedGraph
 from standardservice.scalessetup import gatherProcessStats
 
-from light9.collector.output import Udmx, DummyOutput  # noqa
+from light9.collector.output import Udmx, ArtnetDmx, DummyOutput  # noqa
 
 
 class Updates(cyclone.websocket.WebSocketHandler):
@@ -66,13 +66,13 @@
 def launch(graph, doLoadTest=False):
     try:
         # todo: drive outputs with config files
-        rate = 20 # On udmx, 22 breaks. 28 breaks. 30 breaks.
+        rate = 20  # On udmx, 22 breaks. 28 breaks. 30 breaks.
         outputs = [
-            
-            Udmx(L9['output/dmxA/'], bus=3, address=None, lastDmxChannel=221, rate=rate),
-            Udmx(L9['output/dmxB/'], bus=1, address=None, lastDmxChannel=221, rate=rate),
+
+            #Udmx(L9['output/dmxB/'], bus=1, address=None, lastDmxChannel=221, rate=rate),
             #DummyOutput(L9['output/dmxA/']),
-            DummyOutput(L9['output/dmxB/']),
+            DummyOutput(L9['output/dmxA/']),
+            ArtnetDmx(L9['output/dmxB/'], rate=rate),
         ]
     except Exception:
         log.error("setting up outputs:")
--- a/light9/collector/output.py	Sat Jun 08 07:37:43 2019 +0000
+++ b/light9/collector/output.py	Sat Jun 08 07:43:46 2019 +0000
@@ -1,4 +1,6 @@
 from rdflib import URIRef
+import socket
+import struct
 import time
 import usb.core
 import logging
@@ -131,6 +133,51 @@
             self.dmx.send_dmx(buf)
 
 
+class ArtnetDmx(BackgroundLoopOutput):
+    # adapted from https://github.com/spacemanspiff2007/PyArtNet/blob/master/pyartnet/artnet_node.py (gpl3)
+    def __init__(self, uri, host, port, rate):
+        """sends UDP messages to the given host/port"""
+        super().__init__(uri, rate)
+        packet = bytearray()
+        packet.extend(map(ord, "Art-Net"))
+        packet.append(0x00)  # Null terminate Art-Net
+        packet.extend([0x00, 0x50])  # Opcode ArtDMX 0x5000 (Little endian)
+        packet.extend([0x00, 0x0e])  # Protocol version 14
+        self.base_packet = packet
+        self.sequence_counter = 255
+        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+    def _write(self, buf):
+        self._writeStats.fps.mark()
+        with self._writeStats.call.time():
+
+            if not buf:
+                logAllDmx.debug('%s: empty buf- no output', self.shortId())
+                return
+
+            if logAllDmx.isEnabledFor(logging.DEBUG):
+                # for testing fps, smooth fades, etc
+                logAllDmx.debug('%s: %s...' %
+                                (self.shortId(), ' '.join(map(str, buf[:32]))))
+
+            if self.sequence_counter:
+                self.sequence_counter += 1
+                if self.sequence_counter > 255:
+                    self.sequence_counter = 1
+            packet = self.base_packet[:]
+            packet.append(self.sequence_counter)  # Sequence,
+            packet.append(0x00)  # Physical
+            universe_nr = 0
+            packet.append(universe_nr & 0xFF)  # Universe LowByte
+            packet.append(universe_nr >> 8 & 0xFF)  # Universe HighByte
+
+            packet.extend(struct.pack(
+                '>h', len(buf)))  # Pack the number of channels Big endian
+            packet.extend(buf)
+
+            self._socket.sendto(packet, ('127.0.0.1', 6454))
+
+
 class Udmx(BackgroundLoopOutput):
     _reconnections = scales.IntStat('reconnections')
     _connected = scales.IntStat('connected')