Hallo Leute,
ich wollte mal Fragen ob irgendwer Interesse am Programmieren eines ganz banalen ArtNet Controllers in Python hätte.
Alleine werde ich das wahrscheinlich erstmal nicht schaffen, da ich mich noch nie mit Netzwerkprotkollen beschäftigt habe, aber den kompletten Pseudo-Code hab ich schonmal.
Das ArtNet Netzwerkprotokoll dürfte hier eigentlich für so manchen hier ganz interessant sein, da man mit einem ArtNet Controller direkt aus Python heraus einen Großteil der modernen Bühnentechnik, aber auch z.B. einfache LED Lampen steuern könnte.
Tim
ArtNet Controller / Library
hi,
wenn du niemanden finden solltest, empfehle ich dir das hier: http://i2h.de/fQg7
Meines wissens benutzt Artnet als Netzwerkprotokoll UDP. In der anleitung wird gezeigt wie man sowas programmiert!
gruß
wenn du niemanden finden solltest, empfehle ich dir das hier: http://i2h.de/fQg7
Meines wissens benutzt Artnet als Netzwerkprotokoll UDP. In der anleitung wird gezeigt wie man sowas programmiert!
gruß
So, ich habe mich inzwischen selbst dran versucht und habe auch schon ein ganzes Stück geschafft.
An einer Stelle komme ich aber nicht weiter:
Es soll in einem UDP Paket zusammen mit anderen Daten eine Adresse gesendet werden. In der Spezifikation steht:
Bit 15: 0
Bit 14-8: Net (Zahl zwischen 1-128, Usereingabe)
Bit 7-4: Subnet (Zahl zwischen 1-16, Usereingabe)
Bit 3-0: Universe (Zahl zwischen 1-16, Usereingabe)
Dann soll das Low Byte zuerst und dann das High Byte jeweils als Int8 (?) gesendet werden.
Wie mache ich daraus jetzt einen String, den ich in einem UDP Paket senden kann?
Vielen Dnak schonmal im Vorraus für eure Hilfe
An einer Stelle komme ich aber nicht weiter:
Es soll in einem UDP Paket zusammen mit anderen Daten eine Adresse gesendet werden. In der Spezifikation steht:
Bit 15: 0
Bit 14-8: Net (Zahl zwischen 1-128, Usereingabe)
Bit 7-4: Subnet (Zahl zwischen 1-16, Usereingabe)
Bit 3-0: Universe (Zahl zwischen 1-16, Usereingabe)
Dann soll das Low Byte zuerst und dann das High Byte jeweils als Int8 (?) gesendet werden.
Wie mache ich daraus jetzt einen String, den ich in einem UDP Paket senden kann?
Vielen Dnak schonmal im Vorraus für eure Hilfe

Du solltest dir das struct-Modul anschauen. Allerdings sehe ich da nicht, wie man da festlegt, wieviele Bits benötigt werden … Also erkläre ich mal, wie ich es machen würde:T64 hat geschrieben:So, ich habe mich inzwischen selbst dran versucht und habe auch schon ein ganzes Stück geschafft.
An einer Stelle komme ich aber nicht weiter:
Es soll in einem UDP Paket zusammen mit anderen Daten eine Adresse gesendet werden. In der Spezifikation steht:
Bit 15: 0
Bit 14-8: Net (Zahl zwischen 1-128, Usereingabe)
Bit 7-4: Subnet (Zahl zwischen 1-16, Usereingabe)
Bit 3-0: Universe (Zahl zwischen 1-16, Usereingabe)
Dann soll das Low Byte zuerst und dann das High Byte jeweils als Int8 (?) gesendet werden.
Wie mache ich daraus jetzt einen String, den ich in einem UDP Paket senden kann?
Vielen Dnak schonmal im Vorraus für eure Hilfe
- Ich verkette Subnet und Universe als binäre Zahl miteinander, sodass ich einen 8-bit Integer erhalte:
Code: Alles auswählen
>>> subnet = 13 >>> universe = 9 >>> low_byte = "".join([bin(subnet)[2:], bin(universe)[2:]]) >>> low_byte '11011001' >>> int(low_byte, 2) 217
- Für Net und das Nullbit ist es einfacher:
Code: Alles auswählen
>>> net = 123 >>> high_byte = '{:0>8}'.format(bin(net)[2:]) '01111011' >>> int(high_byte, 2) 123
Code: Alles auswählen
chr(217); chr(123)
@nomnom: Über die Zeichenkettendarstellung der Binärzahlen zu gehen ist unnötig umständlich und ausserdem funktioniert das so wie Du es zeigst nicht bei allen Zahlen, sondern nur bei solchen wo sowohl `subnet` als auch `universe` mindestens den Wert 8 haben. Sonst sind das nämlich keine 4 Bit in der Zeichenkettendarstellung.
@T64: Die Zahlen können so nicht stimmen, denn man bekommt in vier Bits nur Zahlen zwischen 0 und 15 (inklusive) und in sieben Bits 0 bis 127 (inklusive).
Man könnte das `struct`-Modul aus der Standardbibliothek verwenden:
Oder wenn es auch etwas externes sein darf, könnte man zum `construct`-Modul greifen.
@T64: Die Zahlen können so nicht stimmen, denn man bekommt in vier Bits nur Zahlen zwischen 0 und 15 (inklusive) und in sieben Bits 0 bis 127 (inklusive).
Man könnte das `struct`-Modul aus der Standardbibliothek verwenden:
Code: Alles auswählen
import struct
def main():
assert struct.calcsize('<H') == 2
net = 123
subnet = 13
universe = 9
data = struct.pack('<H', net << 8 | subnet << 4 | universe)
print repr(data)
if __name__ == '__main__':
main()
Erstmal vielen Dank für die schnelle Hilfe, ich hab es auch gleich mal eingebaut, aber wie sollte es anders sein, es geht noch nicht.
Ein Programm, dass ArtNet empfangen kann (OLA) meldet nur "ArtNet got unknown packet 50".
Der vollständigkeit halber ist hier noch der Code, ich erwarte aber nicht, dass da irgendwer durchblickt, ohne ArtNet zu kennen...
(Da ist natürlich noch nichts optimiert, alles stur nach den Spezifikationen...)
Für den, den es Interessiert, die Spezifiktaionen gibt es hier: http://tinyurl.com/c6649r8
Ein Programm, dass ArtNet empfangen kann (OLA) meldet nur "ArtNet got unknown packet 50".
Der vollständigkeit halber ist hier noch der Code, ich erwarte aber nicht, dass da irgendwer durchblickt, ohne ArtNet zu kennen...
Code: Alles auswählen
import socket
import struct
class ArtNet():
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def ArtDMX_broadcast(self, dmxdata, address):
net, subnet, universe = address
#ip = "2.255.255.255"
ip = "192.168.178.26"
port = 6454
content = []
# Name, 7byte + 0x00
content.append("lumino" + chr(0x00))
# OpCode ArtDMX -> 0x5000, Low Byte first
high, low = self.getByteLength(int(0x5000))
content.append(chr(low) + chr(high))
# Protocol Version 14, High Byte first
high, low = self.getByteLength(14)
content.append(chr(high) + chr(high))
# Order -> nope -> 0x00
content.append(chr(0x00))
# Eternity Port
content.append(chr(1))
# Address
low = "".join([bin(subnet)[2:], bin(universe)[2:]])
low = int(low, 2)
high = '{:0>8}'.format(bin(net)[2:])
high = int(high, 2)
content.append(chr(low) + chr(high))
# Length of DMX Data, High Byte First
high, low = self.getByteLength(len(dmxdata))
content.append(chr(high) + chr(low))
# DMX Data
for d in dmxdata:
content.append(chr(d))
content = "".join(content)
print content
self.s.sendto(content, (ip, port))
def getByteLength(self, length):
temp = struct.pack('!h', length)
byteList = [firstLength, secondLength] = struct.unpack('BB', temp)
return list(byteList)
def close(self):
self.s.close()
dmx_data = [120] * 512
address = [0, 0, 2]
ArtNet().ArtDMX_broadcast(dmx_data, address)
Für den, den es Interessiert, die Spezifiktaionen gibt es hier: http://tinyurl.com/c6649r8
@T64: Stimmt die Byte-Reihenfolge?
Es ist übrigens extrem unsinnig eine Zahl mit `struct.pack()` umzuwandeln, sie danach mit `struct.unpack()` in zwei Bytewerte zu wandeln, und im nächsten Schritt dann wieder mit `chr()` und ``+`` in eine Zeichenkette umzuwandeln. Ähnlich unsinnig ist so etwas wie ``int(0x5000)``. Eine ganze Zahl braucht man nicht in eine ganze Zahl umwandeln, denn es ist ja schon eine ganze Zahl.
Der Name `getByteLength()` ist ungünstig, denn Du verwendest das nicht nur für Längen, sondern grundsätzlich für 16-Bit-Werte. Das ist auch keine echte Methode. Die ganze Klasse erscheint mir ein wenig fragwürdig.
Das mit `bin()` funktioniert so nicht, wie ich in meinem letzten Beitrag schon erwähnte.
Bei der Version hast Du zweimal das High-Byte genommen.
Es ist übrigens extrem unsinnig eine Zahl mit `struct.pack()` umzuwandeln, sie danach mit `struct.unpack()` in zwei Bytewerte zu wandeln, und im nächsten Schritt dann wieder mit `chr()` und ``+`` in eine Zeichenkette umzuwandeln. Ähnlich unsinnig ist so etwas wie ``int(0x5000)``. Eine ganze Zahl braucht man nicht in eine ganze Zahl umwandeln, denn es ist ja schon eine ganze Zahl.
Der Name `getByteLength()` ist ungünstig, denn Du verwendest das nicht nur für Längen, sondern grundsätzlich für 16-Bit-Werte. Das ist auch keine echte Methode. Die ganze Klasse erscheint mir ein wenig fragwürdig.
Das mit `bin()` funktioniert so nicht, wie ich in meinem letzten Beitrag schon erwähnte.
Bei der Version hast Du zweimal das High-Byte genommen.
Ich wusste leider nicht, wie man es sonst hätte machen können. Bin nicht so vertraut mit binären Zahlen …BlackJack hat geschrieben:@nomnom: Über die Zeichenkettendarstellung der Binärzahlen zu gehen ist unnötig umständlich
BlackJack hat geschrieben:und ausserdem funktioniert das so wie Du es zeigst nicht bei allen Zahlen, sondern nur bei solchen wo sowohl `subnet` als auch `universe` mindestens den Wert 8 haben. Sonst sind das nämlich keine 4 Bit in der Zeichenkettendarstellung.

Danke für die ganzen Tips, der Code müsste jetzt schon um einiges schöner aussehen, funktionieren tut er trotzem nicht 
Vielleicht kann jemand doch mal in die Spezifiktation gucken, ob ich vielleicht was total falsch verstanden habe, es geht um http://tinyurl.com/c6649r8 Seite 22-23.
Tim

Code: Alles auswählen
import socket
import struct
class ArtNet():
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def ArtDMX_broadcast(self, dmxdata, address):
# broadcast ip
ip = "2.255.255.255"
# UDP ArtNet Port
port = 6454
content = []
# Name, 7byte + 0x00
content.append("lumino" + "\x00")
# OpCode ArtDMX -> 0x5000, Low Byte first
content.append(struct.pack('<H', 0x5000))
# Protocol Version 14, High Byte first
content.append(struct.pack('>H', 14))
# Order -> nope -> 0x00
content.append("\x00")
# Eternity Port
content.append(chr(1))
# Address
net, subnet, universe = address
content.append(struct.pack('<H', net << 8 | subnet << 4 | universe))
# Length of DMX Data, High Byte First
content.append(struct.pack('>H', len(dmxdata)))
# DMX Data
for d in dmxdata:
content.append(chr(d))
# stitch together
content = "".join(content)
# debug
print content
# send
self.s.sendto(content, (ip, port))
def close(self):
self.s.close()
# Test
dmx_data = [120] * 512
address = [0, 0, 2]
ArtNet().ArtDMX_broadcast(dmx_data, address)
Tim
Es geht! Halleluja! Murphy hat recht, es war das falsch, woran ich am wenigsten gedacht habe: der Name muss aus 7 Buchstaben bestehen, "lumino" hat aber nur 6!
Jetzt muss es nur noch in mein Programm eingebaut werden und ich bin glücklich
Funktionierender Code:
(ist noch nicht vollständig getestet, aber für mich reichts erstmal...)
Danke an alle!
Jetzt muss es nur noch in mein Programm eingebaut werden und ich bin glücklich

Funktionierender Code:
Code: Alles auswählen
import socket
import struct
class ArtNet():
def __init__(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def ArtDMX_broadcast(self, dmxdata, address):
# broadcast ip
ip = "2.255.255.255"
# UDP ArtNet Port
port = 6454
content = []
# Name, 7byte + 0x00
content.append("luminos" + "\x00")
# OpCode ArtDMX -> 0x5000, Low Byte first
content.append(struct.pack('<H', 0x5000))
# Protocol Version 14, High Byte first
content.append(struct.pack('>H', 14))
# Order -> nope -> 0x00
content.append("\x00")
# Eternity Port
content.append(chr(1))
# Address
net, subnet, universe = address
content.append(struct.pack('<H', net << 8 | subnet << 4 | universe))
# Length of DMX Data, High Byte First
content.append(struct.pack('>H', len(dmxdata)))
# DMX Data
for d in dmxdata:
content.append(chr(d))
# stitch together
content = "".join(content)
# debug
print content
# send
self.s.sendto(content, (ip, port))
def close(self):
self.s.close()
Danke an alle!
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Code: Alles auswählen
"luminos" + "\x00"
Code: Alles auswählen
"l" + "u" + "m" + "i" + "n" + "o" + "s" + "\x00"
Code: Alles auswählen
"luminos\x00"
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Da der komplette erste Teil des Pakets statisch ist, muss ich den auch nicht jedes mal neu berechnen, dass wird später nur in der __init__ gemacht. Das lustige ist aber, dass in der Spezifikatioen wirklich "l" + "u" + "m" + "i" + "n" + "o" + "s" + "\x00" steht
.

@T64: In der Spezifikation steht vom Inhalt her eigentlich 'Art-Net\x00' und es sah mir nicht so aus als wenn das variabel wäre.
Nur der Vollständigkeit halber:
Unter http://code.google.com/p/luminosus/downloads/list gibt es ab sofort eine Art ArtNet Python Library (naja, eher Skript, es entspricht wo gaar nicht den Standarts einer Library :-S ...) falls irgendwer in dem Bereich mal was suchen sollte.
Es besteht aus einem Sender (Lichtmischpult z.B., oder auch Android Handy) und einem Empfänger (also ein echter ArtNet Node, der alle Universen eines Subnets in ein Array schreibt).
Viel Spaß
Unter http://code.google.com/p/luminosus/downloads/list gibt es ab sofort eine Art ArtNet Python Library (naja, eher Skript, es entspricht wo gaar nicht den Standarts einer Library :-S ...) falls irgendwer in dem Bereich mal was suchen sollte.
Es besteht aus einem Sender (Lichtmischpult z.B., oder auch Android Handy) und einem Empfänger (also ein echter ArtNet Node, der alle Universen eines Subnets in ein Array schreibt).
Viel Spaß
