To get the DMX control of the Logic Machine one needs to get two scripts running. The first is a “handler” that needs to be added as a resident script:

-- This software may be used and distributed according to the terms of the
-- GNU General Public License version 3, incorporated herein by reference.
if not d then
d = DMX:init({
channels = 16,
transition = 1,
})
log('DMX initialized')
-- reset custom DMX RGB color settings to "off" (0), comment out if not needed
storage.set('DMXrgbred', 0)
storage.set('DMXrgbgreen', 0)
storage.set('DMXrgbblue', 0)
log('Reset RGB colors')
end
d:run()
and the second are the common functions, that you can just add to the end of the current common functions.
-- This code is copyright of openrb.com
-- Open Source but != free
DMX = {
-- default params
defaults = {
-- storage key
skey = 'dmx_chan_',
-- RS-485 port
port = '/dev/ttyAPP2',
-- number of calls per second
resolution = 20,
-- total number of channels to use
channels = 16,
-- transition time in seconds, does not include DMX transfer time
transition = 2,
},
-- value setter
set = function(i, v)
-- validate channel number
if type(i) == 'number' and i >= 1 and i < = 512 then
-- validate channel value
if type(v) == 'number' and v >= 0 and v < = 255 then
storage.set(DMX.defaults.skey .. i, v)
end
end
end
}
-- DMX init, returns new DMX object
function DMX:init(params)
log('starting DMX')
require('luadmx')
local n = setmetatable({}, { __index = DMX })
local k, v
-- set user parameters
n.params = params
-- copy parameters that are set by user
for k, v in pairs(DMX.defaults) do
if n.params[ k ] == nil then
n.params[ k ] = v
end
end
n:reset()
return n
end
function DMX:reset()
local err, chan
log('resetting DMX')
self.dm, err = luadmx.open(self.params.port)
-- error while opening
if err then
os.sleep(1)
error(err)
end
-- set channel count
self.dm:setcount(self.params.channels)
-- number of transaction ticks
self.ticks = math.max(1, self.params.transition * self.params.resolution)
-- calculate sleep time
self.sleep = 1 / self.params.resolution
-- reset channel map
self.channels = {}
-- fill channel map
for chan = 1, self.params.channels do
self.channels[ chan ] = { current = 0, target = 0, ticks = 0 }
-- turn off by default
storage.set(self.params.skey .. chan, 0)
self.dm:setchannel(chan, 0)
end
end
-- get new values
function DMX:getvalues()
local chan, val
--log('getting DMX values')
-- check for new values for each channel
for chan = 1, self.params.channels do
val = storage.get(self.params.skey .. chan)
-- target value differs, set transcation
if val ~= self.channels[ chan ].target then
self.channels[ chan ].target = val
self.channels[ chan ].delta = (self.channels[ chan ].target - self.channels[ chan ].current) / self.ticks
self.channels[ chan ].ticks = self.ticks
end
end
end
-- main loop handler
function DMX:run()
local i, bs, bm, as, am, delta
local res = self.params.resolution
if not self.calibrated then
bs, bm = os.microtime()
end
self:getvalues()
-- transition loop
for i = 1, res do
self:step()
self.dm:send()
-- wait until next step
os.sleep(self.sleep)
end
-- calibrate delay loop to match 1 second
if not self.calibrated then
as, am = os.microtime()
delta = (as - bs) + (am - bm) / 1000000
if delta > 1.05 then
self.sleep = self.sleep - math.max(10, self.sleep / res)
else
self.calibrated = true
end
end
end
-- single transition step
function DMX:step()
local chan, t
-- transition for each channel
for chan = 1, self.params.channels do
t = self.channels[ chan ].ticks
-- transition is active
if t > 0 then
t = t - 1
self.channels[ chan ].current = self.channels[ chan ].target - self.channels[ chan ].delta * t
self.channels[ chan ].ticks = t
self.dm:setchannel(chan, self.channels[ chan ].current)
end
end
end