Art-Net DMX - sjfp - 11.05.2018
Hi Just asking if anyone has any information using Art-Net DMX IP.
We are looking to use the C-Bus NAC, (Similar to LM)
Art-Net is a protocol to control DMX lighting over IP Networks.
Any example on how to implement would be grateful, say like send channel 1 to 255 or channel 2 to 125 on Module IP 192.168.2.43
RE: Art-Net DMX - edgars - 11.05.2018
here is the Artnet integration script:
Code: require("socket")
artnet_id = "Art-net" .. string.char(0) --8 byte
op_codes = {
ARTNET_POLL = 0x2000,
ARTNET_REPLY = 0x2100,
ARTNET_DMX = 0x5000,
ARTNET_ADDRESS = 0x6000,
ARTNET_INPUT = 0x7000,
ARTNET_TODREQUEST = 0x8000,
ARTNET_TODDATA = 0x8100,
ARTNET_TODCONTROL = 0x8200,
ARTNET_RDM = 0x8300,
ARTNET_VIDEOSTEUP = 0xa010,
ARTNET_VIDEOPALETTE = 0xa020,
ARTNET_VIDEODATA = 0xa040,
ARTNET_MACMASTER = 0xf000,
ARTNET_MACSLAVE = 0xf100,
ARTNET_FIRMWAREMASTER = 0xf200,
ARTNET_FIRMWAREREPLY = 0xf300,
ARTNET_IPPROG = 0xf800,
ARTNET_IPREPLY = 0xf900,
ARTNET_MEDIA = 0x9000,
ARTNET_MEDIAPATCH = 0x9200,
ARTNET_MEDIACONTROLREPLY = 0x9300
}
protocol_version = {
high = 0,
low = 14
}
priority_codes = {
DpLow = 0x10,
DpMed = 0x40,
DpHigh = 0x80,
DpCritical = 0xE0,
DpVolatile = 0xF0
}
function op_code(name)
local code = op_codes[name]
local low = bit.band(code, 0x00FF)
local high = bit.rshift(code, 8)
return low, high
end
function artnet_poll(address, port, talk_to_me, priority)
local command = {}
local opCodeLow, opCodeHigh = op_code("ARTNET_POLL")
table.insert(command, opCodeLow)
table.insert(command, opCodeHigh)
table.insert(command, protocol_version.low)
table.insert(command, protocol_version.high)
table.insert(command, talk_to_me)
table.insert(command, priority_codes[priority])
command = artnet_id .. string.char(unpack(command))
local s = socket.udp()
s:sendto(command, address, port)
s:close()
end
function artnet_dmx(address, port, sequence, in_port_physical, in_port_address, data)
local command = {}
local opCodeLow, opCodeHigh = op_code("ARTNET_DMX")
table.insert(command, opCodeLow)
table.insert(command, opCodeHigh)
table.insert(command, protocol_version.low)
table.insert(command, protocol_version.high)
--[[
The sequence number is used to ensure that ArtDmx packets are used in the correct order.
When Art-Net is carried over a medium such as the Internet, it is possible that ArtDmx packets will reach the receiver out of order.
This field is incremented in the range 0x01 to 0xff to allow the receiving node to resequence packets.
The Sequence field is set to 0x00 to disable this feature
]]
sequence = bit.band(sequence, 0xFF)
table.insert(command, sequence)
--[[
The physical input port from which DMX512 data was input.
This field is for information only. Use Universe for data routing.
]]
table.insert(command, in_port_physical)
--15 bit Port-Address (universe)
local address_hi = bit.rshift(in_port_address, 8)
local address_low = bit.band(in_port_address, 0x00FF)
table.insert(command, address_hi)
table.insert(command, address_low)
--Length
local l = #data --2 byte
local LengthHi = bit.rshift(l, 8)
local LengthLow = bit.band(l, 0x00FF)
table.insert(command, LengthHi)
table.insert(command, LengthLow)
command = artnet_id .. string.char(unpack(command)) .. string.char(unpack(data))
local s = socket.udp()
s:sendto(command, address, port)
s:close()
end
artnet_dmx(ip, port, 0, 0x12, 0x93, {0xA, 0x12, 0xFF})
RE: Art-Net DMX - sjfp - 11.05.2018
WOW
Thank you, will give it go now.
Sorry for my ignorance, new to LUA, could you explain how to deploy this.
I have a group 0/56/0 to control channel 1 on DMX at 192.168.2.43
Where do I put the script, I assume it goes in the User Library and is then called from an event based script.
Where do I put the DMX Channel No, IP Address, and Port Number.
Again, Sorry if I am being completely stupid.
RE: Art-Net DMX - admin - 14.05.2018
Here's a simplified function. Change universe number as needed, sequence and physical parameters can probably be zero. Value is the output channel value ranging from 0 to 255.
Code: function artnet_dmx(ip, sequence, physical, universe, data)
local cmd = string.char(
-- null byte
0,
-- ARTNET_DMX opcope
0, 0x50,
-- protocol version 14
0, 14,
-- sequence number is used to ensure that ArtDmx packets are used in the correct order
bit.band(sequence, 0xFF),
-- physical input port from which DMX512 data was input.
bit.band(physical, 0xFF),
-- 15 bit Port-Address (universe)
bit.band(universe, 0xFF), bit.rshift(universe, 8),
-- Length
bit.rshift(#data, 8), bit.band(#data, 0xFF)
)
local req = "Art-Net" .. cmd .. string.char(unpack(data))
local sck = require("socket").udp()
sck:sendto(req, ip, 0x1936)
sck:close()
end
ip = '192.168.2.43'
universe = 123
value = 255
artnet_dmx(ip, 0, 0, universe, { value })
RE: Art-Net DMX - Erwin van der Zwart - 14.05.2018
Hi,
Nice (:
Is there also a handler script so we can use it as a server?
BR,
Erwin
RE: Art-Net DMX - sjfp - 14.05.2018
(14.05.2018, 06:28)admin Wrote: Here's a simplified function. Change universe number as needed, sequence and physical parameters can probably be zero. Value is the output channel value ranging from 0 to 255.
Code: function artnet_dmx(ip, sequence, physical, universe, data)
local cmd = string.char(
-- null byte
0,
-- ARTNET_DMX opcope
0, 0x50,
-- protocol version 14
0, 14,
-- sequence number is used to ensure that ArtDmx packets are used in the correct order
bit.band(sequence, 0xFF),
-- physical input port from which DMX512 data was input.
bit.band(physical, 0xFF),
-- 15 bit Port-Address (universe)
bit.band(universe, 0xFF), bit.rshift(universe, 8),
-- Length
bit.rshift(#data, 8), bit.band(#data, 0xFF)
)
local req = "Art-Net" .. cmd .. string.char(unpack(data))
local sck = require("socket").udp()
sck:sendto(req, ip, 0x1936)
sck:close()
end
ip = '192.168.2.43'
universe = 123
value = 255
artnet_dmx(ip, 0, 0, universe, { value })
Many thanks for the details. Works great. What do I need to change to control each DMX 512 Channels
(14.05.2018, 10:26)sjfp Wrote: (14.05.2018, 06:28)admin Wrote: Here's a simplified function. Change universe number as needed, sequence and physical parameters can probably be zero. Value is the output channel value ranging from 0 to 255.
Code: function artnet_dmx(ip, sequence, physical, universe, data)
local cmd = string.char(
-- null byte
0,
-- ARTNET_DMX opcope
0, 0x50,
-- protocol version 14
0, 14,
-- sequence number is used to ensure that ArtDmx packets are used in the correct order
bit.band(sequence, 0xFF),
-- physical input port from which DMX512 data was input.
bit.band(physical, 0xFF),
-- 15 bit Port-Address (universe)
bit.band(universe, 0xFF), bit.rshift(universe, 8),
-- Length
bit.rshift(#data, 8), bit.band(#data, 0xFF)
)
local req = "Art-Net" .. cmd .. string.char(unpack(data))
local sck = require("socket").udp()
sck:sendto(req, ip, 0x1936)
sck:close()
end
ip = '192.168.2.43'
universe = 123
value = 255
artnet_dmx(ip, 0, 0, universe, { value })
Many thanks for the details. Works great. What do I need to change to control each DMX 512 Channels Found how. {value1,value2,value3) 1= Ch1 2=Ch2 3=Ch3 etc etc.
But how can I can change channels independently without affecting other channels that may of been set
RE: Art-Net DMX - admin - 14.05.2018
You can only write full dmx-512 value array starting with the first address. So for several channels you need a script attached to all controlling groups which will write all required values.
@Erwin, it's possible to implement a simple server which only handles DMX commands. Do you have real use cases for that?
RE: Art-Net DMX - Erwin van der Zwart - 14.05.2018
Hi Admin,
We get the request for Art-Net a few times a year, often for theather and cinema projects.
In most cases there is a main DMX control in the area where they want to control the KNX lights from there main system. In theater it’s mostly the stage cleaning and blue lights and backstage area ligths and often screens for windows between public area and stage. They want to control it often from the control room’s dmx panels.
At this moment we refer to dedicated bidirectional DMX IP gateways to do this task but if we can do it by scripting i would like to run some tests to see how it performs.
PS: All new Dolby Atmos theathers in the NL are controlled by Wiser for KNX at this moment and they control quite some DMX loops for user experience in coridors (:
BR,
Erwin
RE: Art-Net DMX - admin - 15.05.2018
Here's a rudimentary server example (resident script, sleep time = 0). Only DMX command is supported, sequences are not supported, universe number is ignored.
Code: if not server then
mapping = { '32/1/1', '32/1/2', '32/1/3' }
cache = {}
header = 'Art-Net' .. string.char(0, 0, 0x50, 0, 14)
function parse(data)
if #data < 19 then
return
end
if data:sub(1, #header) ~= header then
return
end
local values = data:sub(19)
for i = 1, #values do
local value = values:byte(i)
if mapping[ i ] and cache[ i ] ~= value then
cache[ i ] = value
grp.write(mapping[ i ], value, dt.uint8)
end
end
end
server = require('socket').udp()
server:settimeout(3)
server:setsockname('*', 0x1936)
end
data, err = server:receive()
if data then
parse(data)
end
RE: Art-Net DMX - sjfp - 21.05.2018
(14.05.2018, 11:02)admin Wrote: You can only write full dmx-512 value array starting with the first address. So for several channels you need a script attached to all controlling groups which will write all required values.
@Erwin, it's possible to implement a simple server which only handles DMX commands. Do you have real use cases for that?
Thanks for the advise.
I have been looking on how to write that script you mentioned, I have it working in a fashion, but would appreciate to some advise on the best way to achieve logging all the groups.
I have started off by creating a table to store each groups current val, but wondering how to extract all the data that's contained in the table.
I have it working by bring back individual stored values, but cant find the correct way to bring back all stored in a format like
{200,50,0,255,127,100,255,0,0,0,255,0} etc. etc.
any help would be appreciated.
RE: Art-Net DMX - admin - 22.05.2018
If you have many groups to control you should use a resident script which monitors all bus traffic and sends update once any group changes. I'll provide an example later on.
RE: Art-Net DMX - sjfp - 22.05.2018
(22.05.2018, 06:00)admin Wrote: If you have many groups to control you should use a resident script which monitors all bus traffic and sends update once any group changes. I'll provide an example later on.
Thank you. Looking forward to seeing your example. Really appreciate your help.
RE: Art-Net DMX - admin - 23.05.2018
Resident script, sleep time = 0. Might require some change to work with C-BUS objects.
Code: if not client then
ip = '192.168.2.43'
mapping = { '1/1/1', '1/1/2', '1/1/3', '2/1/1', '2/1/2', '2/1/3' }
universe = 1
physical = 0
udpsock = require('socket').udp()
addrtoid = {}
values = {}
for id, addr in ipairs(mapping) do
obj = grp.find(addr)
addrtoid[ addr ] = id
if obj then
value = obj.value or 0
if obj.datatype == dt.scale then
value = math.floor(value * 2.55)
end
else
value = 0
end
values[ id ] = value
end
function send()
local cmd = string.char(
-- null byte; ARTNET_DMX opcope; protocol version 14, sequence not defined
0, 0, 0x50, 0, 14, 0,
-- physical input port from which DMX512 data was input
bit.band(physical, 0xFF),
-- 15 bit Port-Address (universe)
bit.band(universe, 0xFF), bit.rshift(universe, 8),
-- Length
bit.rshift(#values, 8), bit.band(#values, 0xFF)
)
local req = 'Art-Net' .. cmd .. string.char(unpack(values))
udpsock:sendto(req, ip, 0x1936)
end
function eventhandler(event)
local id = addrtoid[ event.dst ]
if id then
values[ id ] = busdatatype.decode(event.datahex, dt.uint8, event.dstraw)
send()
end
end
client = require('localbus').new()
client:sethandler('groupwrite', eventhandler)
send()
end
client:step()
RE: Art-Net DMX - sjfp - 23.05.2018
(23.05.2018, 08:35)admin Wrote: Resident script, sleep time = 0. Might require some change to work with C-BUS objects.
Code: if not client then
ip = '192.168.2.43'
mapping = { '1/1/1', '1/1/2', '1/1/3', '2/1/1', '2/1/2', '2/1/3' }
universe = 1
physical = 0
udpsock = require('socket').udp()
addrtoid = {}
values = {}
for id, addr in ipairs(mapping) do
obj = grp.find(addr)
addrtoid[ addr ] = id
if obj then
value = obj.value or 0
if obj.datatype == dt.scale then
value = math.floor(value * 2.55)
end
else
value = 0
end
values[ id ] = value
end
function send()
local cmd = string.char(
-- null byte; ARTNET_DMX opcope; protocol version 14, sequence not defined
0, 0, 0x50, 0, 14, 0,
-- physical input port from which DMX512 data was input
bit.band(physical, 0xFF),
-- 15 bit Port-Address (universe)
bit.band(universe, 0xFF), bit.rshift(universe, 8),
-- Length
bit.rshift(#values, 8), bit.band(#values, 0xFF)
)
local req = 'Art-Net' .. cmd .. string.char(unpack(values))
udpsock:sendto(req, ip, 0x1936)
end
function eventhandler(event)
local id = addrtoid[ event.dst ]
if id then
values[ id ] = busdatatype.decode(event.datahex, dt.uint8, event.dstraw)
send()
end
end
client = require('localbus').new()
client:sethandler('groupwrite', eventhandler)
send()
end
client:step()
Thank you for your assistance. Will have a go when i get back to the office tomorrow evening.
RE: Art-Net DMX - lcrowhurst - 03.02.2020
(23.05.2018, 09:49)sjfp Wrote: (23.05.2018, 08:35)admin Wrote: Resident script, sleep time = 0. Might require some change to work with C-BUS objects.
Code: if not client then
ip = '192.168.2.43'
mapping = { '1/1/1', '1/1/2', '1/1/3', '2/1/1', '2/1/2', '2/1/3' }
universe = 1
physical = 0
udpsock = require('socket').udp()
addrtoid = {}
values = {}
for id, addr in ipairs(mapping) do
obj = grp.find(addr)
addrtoid[ addr ] = id
if obj then
value = obj.value or 0
if obj.datatype == dt.scale then
value = math.floor(value * 2.55)
end
else
value = 0
end
values[ id ] = value
end
function send()
local cmd = string.char(
-- null byte; ARTNET_DMX opcope; protocol version 14, sequence not defined
0, 0, 0x50, 0, 14, 0,
-- physical input port from which DMX512 data was input
bit.band(physical, 0xFF),
-- 15 bit Port-Address (universe)
bit.band(universe, 0xFF), bit.rshift(universe, 8),
-- Length
bit.rshift(#values, 8), bit.band(#values, 0xFF)
)
local req = 'Art-Net' .. cmd .. string.char(unpack(values))
udpsock:sendto(req, ip, 0x1936)
end
function eventhandler(event)
local id = addrtoid[ event.dst ]
if id then
values[ id ] = busdatatype.decode(event.datahex, dt.uint8, event.dstraw)
send()
end
end
client = require('localbus').new()
client:sethandler('groupwrite', eventhandler)
send()
end
client:step()
Thank you for your assistance. Will have a go when i get back to the office tomorrow evening.
Did you get this solution to work. I have a similar requirement. I have a client with a DMX slider controller that they want to control Cbus controlled lights with. Where did you purchase a art-net interface from?
thanks
RE: Art-Net DMX - admin - 03.02.2020
This script sends Art-Net commands but you need a different script which receives Art-Net commands. This is doable but first you need a DMX > Art-Net converter. I think something like this should work: https://dmxking.com/artnetsacn/edmx1-pro
RE: Art-Net DMX - lcrowhurst - 03.02.2020
(03.02.2020, 11:41)admin Wrote: This script sends Art-Net commands but you need a different script which receives Art-Net commands. This is doable but first you need a DMX > Art-Net converter. I think something like this should work: https://dmxking.com/artnetsacn/edmx1-pro
thanks for the info I will get intouch with them, how hard is it to write an art-net receiver ?
RE: Art-Net DMX - admin - 03.02.2020
An example of Art-Net receiver. It ignores sequence and universe numbers which are not needed for general use. Edit mapping table to select which groups addresses are mapped to DMX channel numbers starting from 1. Output value for each channel is 1 byte (0..255).
Code: if not server then
mapping = {
[1] = '32/1/1',
[2] = '32/1/2',
[3] = '32/1/3',
}
server = require('socket').udp()
server:settimeout(1)
server:setsockname('*', 0x1936)
header = 'Art-Net' .. string.char(0, 0, 0x50)
values = {}
function parse(data)
local count, value
if data:sub(1, #header) ~= header then
return
end
count = #data - 18
for i = 1, count do
value = data:byte(i + 18)
if value ~= values[ i ] then
values[ i ] = value
if mapping[ i ] then
grp.update(mapping[ i ], value)
end
end
end
end
end
data = server:receive()
if data then
parse(data)
end
RE: Art-Net DMX - lcrowhurst - 04.02.2020
(03.02.2020, 12:51)admin Wrote: An example of Art-Net receiver. It ignores sequence and universe numbers which are not needed for general use. Edit mapping table to select which groups addresses are mapped to DMX channel numbers starting from 1. Output value for each channel is 1 byte (0..255).
Code: if not server then
mapping = {
[1] = '32/1/1',
[2] = '32/1/2',
[3] = '32/1/3',
}
server = require('socket').udp()
server:settimeout(1)
server:setsockname('*', 0x1936)
header = 'Art-Net' .. string.char(0, 0, 0x50)
values = {}
function parse(data)
local count, value
if data:sub(1, #header) ~= header then
return
end
count = #data - 18
for i = 1, count do
value = data:byte(i + 18)
if value ~= values[ i ] then
values[ i ] = value
if mapping[ i ] then
grp.update(mapping[ i ], value)
end
end
end
end
end
data = server:receive()
if data then
parse(data)
end
Thanks for the info, I’ve tried testing it with a couple of software controller, as I’m not on site, but the wiser only shows a connection to the controller (eg when I log server it shows art-net) but the data is alway nil.
can I put the art-net transmit on the wiser and test that way?
RE: Art-Net DMX - admin - 04.02.2020
You can run the sending script on the same device. Just set IP to 127.0.0.1
|