25.10.2023, 06:36
Try this updated library. Let us know if it works so we can update the example on our website.
Code:
local socket = require('socket')
local crc16 = require('encdec').crc16
local ifinfo = require('ifinfo')
HDL = {
-- destination ip
dstip = '192.168.0.2',
-- packet constant data
magic = 'HDLMIRACLE',
lcode = string.char(0xAA, 0xAA),
-- source device settings
srcsubnet = 1,
srcdevice = 254,
devicetype = 0xFFFE,
-- command types
cmd = {
chanreg = 0x0031, -- single channel regulate
chanregreply = 0x0032, -- single channel regulate answerback
chanstat = 0x0033, -- read status of single channel targets
chanstatreply = 0x0034, -- single channel targets status answerback
}
}
HDL.init = function()
local info, chunk, chunks
info = ifinfo()
if not info or not info.eth0 then
error('cannot get interface info')
end
-- ip header
HDL.iphdr = ''
-- broadcast address
HDL.bcast = info.eth0.bcast
-- split ip address into chunks
chunks = info.eth0.inetaddr:split('.')
-- add ip address chunks
for i = 1, 4 do
chunk = tonumber(chunks[ i ])
HDL.iphdr = HDL.iphdr .. string.char(chunk)
end
end
HDL.decode = function(packet)
local len, data, src, crc
-- primary header
if packet:sub(5, 14) ~= HDL.magic then
return nil, 'magic'
end
-- leading code
if packet:sub(15, 16) ~= HDL.lcode then
return nil, 'lcode'
end
-- get data length and check against
len = packet:byte(17)
if len and len + 16 ~= packet:len() then
return nil, 'len'
end
-- get packet data and check crc
data = packet:sub(17, len + 14)
crc = packet:byte(len + 15) * 0x100 + packet:byte(len + 16)
if crc16(data) ~= crc then
return nil, 'crc'
end
-- return parsed packet
return {
srcip = string.format('%d.%d.%d.%d', packet:byte(1, 4)),
srcsubnet = packet:byte(18),
srcdevice = packet:byte(19),
devicetype = (packet:byte(20) * 0x100 + packet:byte(21)),
opcode = (packet:byte(22) * 0x100 + packet:byte(23)),
dstsubnet = packet:byte(24),
dstdevice = packet:byte(25),
additional = packet:sub(26, len + 14)
}
end
HDL.word = function(v)
return string.char(bit.band(bit.rshift(v, 8), 0xFF), bit.band(v, 0xFF))
end
HDL.encode = function(cmd, dstsubnet, dstdevice, extra)
local packet, len, crc, data
-- perform init if required
if not HDL.iphdr then
HDL.init()
end
-- start packet: ip, magic and leading code
packet = { HDL.iphdr, HDL.magic, HDL.lcode }
-- base data
data = string.char(HDL.srcsubnet, HDL.srcdevice) ..
HDL.word(HDL.devicetype) ..
HDL.word(cmd) ..
string.char(dstsubnet, dstdevice)
-- add extra data parameters
if type(extra) == 'string' then
data = data .. extra
end
-- calculate length and crc
len = string.char(data:len() + 3)
crc = crc16(len .. data)
table.insert(packet, len)
table.insert(packet, data)
table.insert(packet, HDL.word(crc))
return table.concat(packet)
end
HDL.send = function(packet)
local client = socket.udp()
client:sendto(packet, HDL.dstip, 6000)
end
HDL.chanreg = function(dstsubnet, dstdevice, chan, value, delay)
local extra, packet
delay = delay or 0
if type(value) == 'boolean' then
value = value and 100 or 0
end
extra = string.char(chan, value) .. HDL.word(delay)
packet = HDL.encode(HDL.cmd.chanreg, dstsubnet, dstdevice, extra)
HDL.send(packet)
end