Is there any method of creating a modbus client with a script?
Scenario:
I have 100 preloaded profiles on a SL. Via VISU, I can input a IP adress scope. With a "number" object, I can determine how many clients that should be created based on IP address.
18.02.2017, 00:03 (This post was last modified: 18.02.2017, 18:42 by Erwin van der Zwart.)
Hi,
Yes this is possible, this script simulates the form you normal fill in manually, basicly any user form can be simulated and automated (;
Try this script:
Code:
-- Batch adding modbus devices - Created by Erwin van der Zwart - Schneider Electric Netherlands -----------
-- For spaceLYnk FW 1.2.1 or higher and homeLYnk FW 1.5.1 or higher ----------------------------------------
--------------------------------------------- Start Parameters ---------------------------------------------
-- Set username and password for access to SL/HL
username = 'admin'
password = 'admin'
---------------------------------------------- End Parameters ----------------------------------------------
---------------------------------- DON'T CHANGE ANYTHING UNDER THIS LINE -----------------------------------
-- Load modules
require('json')
require('socket.url')
require('socket.http')
-- Get current HL/SL ip address
data = io.readproc('if-json')
data = json.decode(data)
ip = data.eth0.inetaddr
-- Set counters for creation log
number_of_devices = 0
number_failed = 0
-- Function to send request to create modbus device
function url_send(device_proto, device_name, device_profile, device_ip, device_port, device_slave, device_pollinterval, device_id)
local device = {
proto = device_proto,
name = device_name,
profile = device_profile,
ip = device_ip,
port = device_port,
slave = device_slave,
pollinterval = device_pollinterval,
id = device_id,
}
data = json.encode(device)
form_data = 'data=' .. socket.url.escape(data)
socket.http.TIMEOUT = 15
local res, code, response_header = socket.http.request(url, form_data)
return res, code, response_header
end
-- Create devices
for i = 1, 10, 1 do
-- used fields to send: protocol,name,profile,ip,port,slave,pollinterval,id
result, code, response_header = url_send("tcp", "Device " .. i, "iEM-iEM3155", "192.168.10." .. i, "502", i, "5", "")
-- Calculate results for creation devices log
if result == '{"success":true}' then
number_of_devices = number_of_devices + 1
else
number_failed = number_failed + 1
end
end
-- Create result log
if number_failed == 0 then
log ("Created " .. number_of_devices .. " devices succesfully")
else
log ("Created " .. number_of_devices .. " devices succesfully and creation of " .. number_failed .. " devices failed")
end
-- Disable script when done automaticly
script.disable(_SCRIPTNAME)
I assume your next question will be: How do i automate the mappings (:
Here is a sample to automaticly create new objects and map them to your modbus device. Objects are created with correct type by info of modbus mapping data points.
Only un-mapped objects are processed, if a object is mapped already it's skipped.
If you don't want to map all points you need to add some conditions or create a new modbus profile with only points to be auto mapped.
Code:
query = 'SELECT * FROM modbus_mapping'
counter = 0
for _, mapping in ipairs(db:getall(query)) do
if mapping.bus_address == "" or mapping.bus_address == nil then
grp_address = '1/1/' .. counter
if counter < 256 then
dec_grp_address = knxlib.encodega(grp_address)
address = grp.create({
datatype = mapping.datatype,
address = grp_address,
name = mapping.name,
comment = 'Auto mapped by script',
units = mapping.units,
tags = {},
})
counter = counter + 1
db:update('modbus_mapping', { bus_address = dec_grp_address, bus_write = 1, value_delta = 0.1, value_custom = 'Auto mapped by script' }, { id = mapping.id })
end
end
end
Please make a back-up before running both of these scripts to be sure the result is what you expect as this script will and can add a lot of objects and create a lot of links automaticly.
This auto mapping script is limited to 256 objects, when you need more auto mappings there needs to be a extra step to move to next address scope. That is not included now.
You can now goto next step to add plans automaticly, add these objects automatic to the plan including images and have a full visu page with your metering device in just 1 mouse click (;
28.09.2017, 20:22 (This post was last modified: 28.09.2017, 20:33 by Erwin van der Zwart.)
Hi,
Yes i could, but i don't see the point (:
You can change grp.address = '1/1/' .. counter to grp.address = '1/2/' .. counter and run it again, the script checks already if a object is already mapped and skips it then, so it will resume on the unmapped objects.
If you have 900 objects just run it 4 times and change the grp.address range between each run.
also add script.disable(_SCRIPTNAME) at the end of the above script to avoid it from running multiple times when using it from a resident script
29.09.2017, 07:56 (This post was last modified: 29.09.2017, 07:59 by AEK.)
(28.09.2017, 20:22)Erwin van der Zwart Wrote: Hi,
Yes i could, but i don't see the point (:
You can change grp.address = '1/1/' .. counter to grp.address = '1/2/' .. counter and run it again, the script checks already if a object is already mapped and skips it then, so it will resume on the unmapped objects.
If you have 900 objects just run it 4 times and change the grp.address range between each run.
also add script.disable(_SCRIPTNAME) at the end of the above script to avoid it from running multiple times when using it from a resident script
BR,
Erwin
I've tried to modify and seems it works
Code:
-- Select all entrys from DB inside table 'modbus_mapping'
-- "id", "internal_id", "device", "name", "active", "bus_write", "bus_address", "bus_datatype", "internal", "type", "value_delta","value_base","value_multiplier","value_bitmask","value_nan","value_conv","value_custom","units","address","address_scale","read_count","read_offset","read_swap","datatype","writable","write_only","write_multiple"
query = 'SELECT * FROM modbus_mapping'
counter = 0
for _, mapping in ipairs(db:getall(query)) do
if mapping.bus_address == "" or mapping.bus_address == nil then
mid_group = math.floor(counter/256)
grp_address = '32/'..mid_group..'/' .. (counter - 256*mid_group)
log(grp_address)
if counter < 2047 then
dec_grp_address = knxlib.encodega(grp_address)
address = grp.create({
datatype = mapping.datatype,
address = grp_address,
name = mapping.name,
comment = 'Auto mapped by script',
units = mapping.units,
tags = {},
})
counter = counter + 1
db:update('modbus_mapping', { bus_address = dec_grp_address, bus_write = 1, value_delta = 0.1, value_custom = 'Auto mapped by script' }, { id = mapping.id })
end
end
end
log('done')
script.disable(_SCRIPTNAME)
but few times this script did not fill full modbus table. it stops on 32/0/225, but all GA was created (the last was 32/3/***)
this script worked about 1 minute
(29.09.2017, 07:37)toujour Wrote: Hi to Everybody,
I like your scripts !!
I have a problem with only one object in modbus mapping profile, please see the image in the attachment.
I want change the COIL 192 to COIL 191 ( I forgot it in the profile )
Can I use a script to change only this point ? I have more then 500 point in this modbus device.
Thanks in Advance !
Alberto
I think there is another simple way
You can create additional profile for your modbus device only with coil 191.
25.05.2018, 12:14 (This post was last modified: 25.05.2018, 12:15 by FatMax.)
(18.02.2017, 00:03)Erwin van der Zwart Wrote: Hi,
Yes this is possible, this script simulates the form you normal fill in manually, basicly any user form can be simulated and automated (;
Try this script:
Code:
-- Batch adding modbus devices - Created by Erwin van der Zwart - Schneider Electric Netherlands -----------
-- For spaceLYnk FW 1.2.1 or higher and homeLYnk FW 1.5.1 or higher ----------------------------------------
--------------------------------------------- Start Parameters ---------------------------------------------
-- Set username and password for access to SL/HL
username = 'admin'
password = 'admin'
---------------------------------------------- End Parameters ----------------------------------------------
---------------------------------- DON'T CHANGE ANYTHING UNDER THIS LINE -----------------------------------
-- Load modules
require('json')
require('socket.url')
require('socket.http')
-- Get current HL/SL ip address
data = io.readproc('if-json')
data = json.decode(data)
ip = data.eth0.inetaddr
-- Set counters for creation log
number_of_devices = 0
number_failed = 0
-- Function to send request to create modbus device
function url_send(device_proto, device_name, device_profile, device_ip, device_port, device_slave, device_pollinterval, device_id)
local device = {
proto = device_proto,
name = device_name,
profile = device_profile,
ip = device_ip,
port = device_port,
slave = device_slave,
pollinterval = device_pollinterval,
id = device_id,
}
data = json.encode(device)
form_data = 'data=' .. socket.url.escape(data)
socket.http.TIMEOUT = 15
local res, code, response_header = socket.http.request(url, form_data)
return res, code, response_header
end
-- Create devices
for i = 1, 10, 1 do
-- used fields to send: protocol,name,profile,ip,port,slave,pollinterval,id
result, code, response_header = url_send("tcp", "Device " .. i, "iEM-iEM3155", "192.168.10." .. i, "502", i, "5", "")
-- Calculate results for creation devices log
if result == '{"success":true}' then
number_of_devices = number_of_devices + 1
else
number_failed = number_failed + 1
end
end
-- Create result log
if number_failed == 0 then
log ("Created " .. number_of_devices .. " devices succesfully")
else
log ("Created " .. number_of_devices .. " devices succesfully and creation of " .. number_failed .. " devices failed")
end
-- Disable script when done automaticly
script.disable(_SCRIPTNAME)
Erwin;
This functionality (which is utterly brilliant by the way) seems to be broken i FW 2.1.1. I´ve tried on all FW up to 2.1.0 and it works as a charm. I suspect there's some parameters missing. When I log the response i get a 404. Do you have any idea what might have changed (I don't like undocumented changes!!!) in FW 2.1.1?
28.05.2018, 08:16 (This post was last modified: 28.05.2018, 08:19 by Erwin van der Zwart.)
Hi,
The new FW requires a extra parameter 'timeout' that old FW didn't use, and also new browsers are blocking credentials in URL so i changed the script in a new methode for web requests.
Thanks to Admin for that (:
Here is the new script:
Code:
-- Batch adding modbus devices v1.1 - Created by Erwin van der Zwart - Schneider Electric Netherlands -----------
-- For spaceLYnk FW 2.1.1 or higher and Wiser for KNX FW 2.1.1 or higher ----------------------------------------
----------------------------------------------- Start Parameters ------------------------------------------------
------------------------------------------------ End Parameters -------------------------------------------------
------------------------------------ DON'T CHANGE ANYTHING UNDER THIS LINE --------------------------------------
-- Set counters for creation log
number_of_devices = 0
number_failed = 0
-- Function to send request (in this case to create a modbus device)
function webrequest(mod, act, vars, data)
require('json')
require('dbenv')
local path
vars = vars or {}
function getvar(v)
return vars[ v ]
end
json.data = function()
return data or {}
end
if mod == 'plugin' then
path = 'plugins/' .. act .. '/web.lua'
else
path = 'web/' .. mod .. '/' .. act .. '.lua'
end
return dofile('/lib/genohm-scada/' .. path)
end
-- Create devices
for i = 0, Number_of_devices - 1, 1 do
requestdata = {
id = "",
timeout = "" .. Device_timeout,
pollinterval = "" .. Device_pollinterval,
slave = "" .. Device_slave_start + i,
port = "" .. Device_port,
ip = Device_ip_range .. "." .. Device_ip_start + i,
profile = Device_profile,
name = Device_name_prefix .. " " .. i + 1,
proto = Device_protocol,
}
result = webrequest('plugin', 'modbus', {request = 'device-save'}, requestdata)
-- Calculate results for creation devices log
if result == '{"success":true}' then
number_of_devices = number_of_devices + 1
else
number_failed = number_failed + 1
end
end
-- Create result log
if number_failed == 0 then
log ("Created " .. number_of_devices .. " devices succesfully")
else
log ("Created " .. number_of_devices .. " devices succesfully and creation of " .. number_failed .. " devices failed")
end
-- Disable script when done automaticly
script.disable(_SCRIPTNAME)
14.09.2018, 08:41 (This post was last modified: 14.09.2018, 08:42 by FatMax.)
(28.05.2018, 08:16)Erwin van der Zwart Wrote: Hi,
The new FW requires a extra parameter 'timeout' that old FW didn't use, and also new browsers are blocking credentials in URL so i changed the script in a new methode for web requests.
Thanks to Admin for that (:
Here is the new script:
-- SNIP --
BR,
Erwin
I´m trying to rewrite the script you posted Erwin, in order to enable RTU and change the settings. However, I'm getting a error when calling the web request function:
Code:
/lib/genohm-scada/plugins/modbus/web:0: attempt to index global 'uci' (a nil value)
stack traceback:
/lib/genohm-scada/plugins/modbus/web: in function </lib/genohm-scada/plugins/modbus/web:0>
/lib/genohm-scada/plugins/modbus/web: in function </lib/genohm-scada/plugins/modbus/web:0>
[C]: in function 'webrequest'
User script:46: in main chunk
I´m guessing this has something to do with the libraries we are calling at the top, so I'm not sure what it is trying to index
15.03.2019, 11:58 (This post was last modified: 15.03.2019, 12:15 by pillbox.)
Hello. I have some strange thing with mapping script. All mappings do successfull, but no one mapping read data from ModBus until one of them is opened and save manually.
HomeLynk 2.3.0
I have been implementing this code in a project with modbus RTU.
I have it running well but I cant seem to find a way to use this to set the Modbus Device Address.
I assume this is the Mapping.ID? inspecting the SQL it appears to me a locked entity? does this mean it is not possible?
Hi Erwin,
Do you know if there is an equivalent library/function that does the same job for the C-bus SHAC/NAC variant made by Schneider Electric? I'm trying to automate the mappings process but not for a KNX device.