Modbus TCP Server / Tecnoalarm panel gateway
This tutorial will guide you in setting up HSYCO as a gateway to enable communication between Modbus TCP and one of the security panels integrated into HSYCO. HSYCO will act as a Modbus TCP server.
To access HSYCO Manager open a browser and type the URL:
https://192.168.1.50/hsycoserver/manager
The IP address and the URLKey written above are the default ones
Add a security control panel I/O Server
Follow these steps of this tutorial:
Add a Modbus Tcp server I/O Server
1. Go back to the Manager splash screen
2. Click on Settings.
3. Add a new I/O server.
4. Click the type input field.
5. Type "mod"
6. Select Modbus TCP Server.
7. Select the name input field.
8. Assign a unique name to the I/O server, for example "mserver"
9. Click the port input field.
10. Type "502", the default Modbus port.
11. Click "Confirm"
12. Click on the Options icon.
13. Add a new option.
14. Click the option field.
15. Select "eventslog".
16. Click the value input field.
17. Select "true".
18. Click "Confirm".
19. Close the Options popup.
20. Click "Save Apply & restart".
21. Confirm by clicking the Save button.
Check the connection status
1. Let’s now check the connection status of the I/O Servers we just added. Go back to the Manager splash screen and click on Status Browser.
2. Click the "Filter" field to search for the connection datapoint.
3. Type " tecno.conn"
4. If the datapoint ‘tecno.connection’ is equal to ‘online,’ this means that the Tecnoalarm I/O server is successfully connected to HSYCO.
EVENTS scripting
1. From the Manager splash screen select Code Editor.
2. Click "New Events File"
3. Give a name to your script, for example: "gateway.txt"
4. Click "New File"
5. Now it's time to write some lines of code.
For further information about the logic of EVENTS programming, read EVENTS programming quickstart
Let's start with some simple functions:
#copy the status of a zone of the security panel to a Modbus register (Holding Register)
io tecno.zone.1.alarm = 1 : io mserver.1.1.hr = "ushort:"1
io tecno.zone.1.alarm = 0 : io mserver.1.1.hr = "ushort:"0
#copy the status of a zone of the security panel to a Modbus register (Coil)
io tecno.zone.2.alarm = 1 : io mserver.1.10.co = "bit:"1
io tecno.zone.2.alarm = 0 : io mserver.1.10.co = "bit:"0
#when a Modbus register is set to 1/0, arm/disarm a security panel program
io mserver.1.20.hr = 1 : io tecno.program.1 = arm
io mserver.1.20.hr = 0 : io tecno.program.1 = disarm
Click ‘Save’ in the upper right corner to activate this script.
The complete list of all the datapoints generated by an I/O Server is available in the Integrations section.
You can use Javascript as well. For example, this code automatically keeps the status of a Tecnoalarm panel aligned with a series of registers in a Modbus TCP Server.
First, a JS code to create and keep updated the Modbus register table:
#********************************************************
# ************** GATEWAY TECNOALARM MODBUS **************
#********************************************************
# Initialization
init: {
// MODBUS GATEWAY ADDRESS
var unitid = "1";
// Also modify in the other events file
}
# For each event
function ioEvent(name, value): {
# If event comes from tecnoalarm
if (name.startsWith("tecno") == true ){
//messageLog("GATEWAY TM - event from central: " + name + " / value: " + value );
var registro = "";
// testing
// name = "tecno.program.6.alarm";
// value = "0";
// tab 1 (program status)
if (name.startsWith("tecno.program.")){
// determine program number
var programma = "";
var splt1 = name.split(".");
programma = splt1[2];
// LSB
// var registro = (programma - 1 ) * 2;
var registro = (programma * 2) - 1 ;
if (name.endsWith("status")){
// tab1.1
var bits1pos03 = "";
switch (value) {
case "off":
bits1pos03 = "000"
break;
case "preout":
bits1pos03 = "001"
break;
case "out":
bits1pos03 = "010"
break;
case "armed":
bits1pos03 = "011"
break;
case "outpartial":
bits1pos03 = "100"
break;
case "armedpartial":
bits1pos03 = "101"
break;
case "endpartial":
bits1pos03 = "110"
break;
default:
bits1pos03 = "---"
}
// write to modbus table
var seq1 = "-------------" + bits1pos03;
// write 32 bits from 1
// LSB
// var registro = (programma - 1 ) * 2;
// MSB
var registro2 = registro + 1;
ioSet("mserver."+unitid+"."+ registro +".hr", "bits:"+seq1 );
ioSet("mserver."+unitid+"."+ registro2 +".hr", "bits:0000000000000000");
messageLog("GATEWAY TM - T1.1 program status " + programma + " : " + value + " / bit value: " + bits1pos03 + "/ register: " + registro + " / sequence: " + seq1);
}
// continue table 1
// program in pre-alarm
else if (name.endsWith("prealarm") ){
// registro = (programma - 1) * 2;
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro +".hr", "bits:------------1---");
messageLog("GATEWAY TM - T1 pre-alarm status program " + programma + " : " + value + " / register: " + registro + " / sequence: bits:------------1---");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro +".hr", "bits:------------0---");
messageLog("GATEWAY TM - T1 pre-alarm status program " + programma + " : " + value + " / register: " + registro + " / sequence: bits:------------0---");
}
// program in alarm
} else if (name.endsWith("alarmmemory") ){
// registro = (programma - 1) * 2;
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro +".hr", "bits:-----------1----");
messageLog("GATEWAY TM - T1 alarm memory status program " + programma + " : " + value + " / register: " + registro + " / sequence: bits:-----------1----");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro +".hr", "bits:-----------0----");
messageLog("GATEWAY TM - T1 alarm memory status program " + programma + " : " + value + " / register: " + registro + " / sequence: bits:-----------0----");
}
// program in alarm memory
} else if (name.endsWith(".alarm") ){
// registro = (programma - 1) * 2;
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro +".hr", "bits:----------1-----");
messageLog("GATEWAY TM - T1 alarm status program " + programma + " : " + value + " / register: " + registro + " / sequence: bits:----------1-----");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro +".hr", "bits:----------0-----");
messageLog("GATEWAY TM - T1 alarm status program " + programma + " : " + value + " / register: " + registro + " / sequence: bits:----------0-----");
}
}
}// end t1
//tab 3 (zone status)
else if (name.startsWith("tecno.zone.")){
// determine the zone number
var zona = "";
var splt3 = name.split(".");
zona = splt3[2];
//var registro4 = ((zona - 1) * 2) + 198;
var registro4 = ((zona * 2) - 1) + 198;
// if zone excluded
if (name.endsWith(".excluded")){
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:---------------1");
messageLog("GATEWAY TM - T3 zone exclusion state " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:---------------1");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:---------------0");
messageLog("GATEWAY TM - T3 zone exclusion state " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:---------------0");
}
// if zone open/closed
} else if (name.endsWith(".alarm")){
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:---------1------");
messageLog("GATEWAY TM - T3 zone open/closed state " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:---------1------");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:---------0------");
messageLog("GATEWAY TM - T3 zone open/closed state " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:---------0------");
}
// if cable cut
} else if (name.endsWith(".cablecutstatus")){
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:-------------1--");
messageLog("GATEWAY TM - T3 cable cut status zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:-------------1--");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:-------------0--");
messageLog("GATEWAY TM - T3 cable cut status zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:-------------0--");
}
// if cable cut alarm
} else if (name.endsWith(".cablecutalarm")){
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:------------1---");
messageLog("GATEWAY TM - T3 cable cut alarm state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:------------1---");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:------------0---");
messageLog("GATEWAY TM - T3 cable cut alarm state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:------------0---");
}
// battery low state
} else if (name.endsWith(".lowbattery")){
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:-----------1----");
messageLog("GATEWAY TM - T3 low battery state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:-----------1----");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:-----------0----");
messageLog("GATEWAY TM - T3 low battery state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:-----------0----");
}
// no radio communication
} else if (name.endsWith(".noradio")){
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:----------1-----");
messageLog("GATEWAY TM - T3 no radio state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:----------1-----");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:----------0-----");
messageLog("GATEWAY TM - T3 no radio state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:----------0-----");
}
// active (armed/disarmed) state
} else if (name.endsWith(".active")){
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:-------1--------");
messageLog("GATEWAY TM - T3 active state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:-------1--------");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:-------0--------");
messageLog("GATEWAY TM - T3 active state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:-------0--------");
}
// learned state
} else if (name.endsWith(".radiolearned")){
if (value == "1"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:--------1-------");
messageLog("GATEWAY TM - T3 learned state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:--------1-------");
} else if (value == "0"){
ioSet("mserver."+unitid+"."+ registro4 +".hr", "bits:--------0-------");
messageLog("GATEWAY TM - T3 learned state zone " + zona + " : " + value + " / register: " + registro4 + " / sequence: bits:--------0-------");
}
}
} // end tab 3
}
}
#gateway writes register 196 = 1 > the gateway is ready
io tecno.connection = online : programtimer startgateway = set 15
io tecno.connection = offline : programtimer startgateway = clear
#programtimer startgateway : io mserver.1.196.hr = int:1, log = "GATEWAY TM - READY"
programtimer startgateway : {
ioSet("mserver."+unitid+".196.hr", "bits:---------------1");
messageLog("GATEWAY TM - READY");
}
#io tecno.connection = offline : io mserver.1.196.hr = int:0, log = "GATEWAY TM - TECNOALARM OFFLINE OR GATEWAY NOT READY"
io tecno.connection = offline : {
ioSet("mserver."+unitid+".196.hr", "bits:---------------0");
messageLog("GATEWAY TM - TECNOALARM OFFLINE OR GATEWAY NOT READY");
}
Then, in another EVENTS file, this code allows sending a command to the Tecnoalarm panel by writing to a Modbus TCP register.
#********************************************************
# ************** GATEWAY TECNOALARM MODBUS **************
#********************************************************
# Initialization
init : {
// MODBUS GATEWAY ADDRESS
var unitid = "1";
// also modify in the other events file
}
# COMMAND TABLE (T2)
# 65 - program state 1 LSB
# 66 - program state 1 MSB
# ---
# 127 - program state 32 LSB
# 128 - program state 32 MSB
# (register / 2) - 31.5
# COMMAND TABLE (T4)
# 1223 - program state 1 LSB
# 1224 - program state 1 MSB
# ---
# 2245 - program state 32 LSB
# 2246 - program state 32 MSB
# (register / 2) - 610
# for each event on the Modbus server
function ioEvent(name,value) : {
if (name.startsWith("mserver")){
var splt = name.split(".");
var uid = splt[1];
var reg = splt[2] * 1;
// if the unit id is correct
if (uid == unitid){
// tab 2 - program insertions
if (reg >= 65 && reg <= 127){
var prog = (reg / 2) - 31.5;
messageLog("GATEWAY TM - T2 - program modification: " + prog + " / new value: " + value);
if (value == "3"){
// then insert program
ioSet("tecno.program." + prog, "arm");
messageLog("GATEWAY TM - T2 - program insertion: " + prog);
} else if (value == "0"){
// then disarm program
ioSet("tecno.program." + prog, "disarm");
messageLog("GATEWAY TM - T2 - program disarming: " + prog);
}
// tab 4 - zone enablement
} else if (reg >= 1223 && reg <= 2245){
var zone = (reg / 2) - 610.5;
messageLog("GATEWAY TM - T4 - zone modification: " + zone + " / new value: " + value);
if (value == "0"){
// then include zone
ioSet("tecno.zone." + zone, "enable");
messageLog("GATEWAY TM - T4 - zone inclusion: " + zone);
} else if (value == "3"){
// then exclude zone
ioSet("tecno.zone." + zone, "disable");
messageLog("GATEWAY TM - T4 - zone exclusion: " + zone);
}
}
}
}
}
#subscribe to registers where modifications are made to control Tecnoalarm
#tab 2
io mserver.connection = online : io mserver.1.65.hr = subscribe:int,
io mserver.1.67.hr = subscribe:int,
io mserver.1.69.hr = subscribe:int,
io mserver.1.71.hr = subscribe:int,
io mserver.1.73.hr = subscribe:int,
io mserver.1.75.hr = subscribe:int,
io mserver.1.77.hr = subscribe:int,
io mserver.1.79.hr = subscribe:int,
io mserver.1.81.hr = subscribe:int,
io mserver.1.83.hr = subscribe:int,
io mserver.1.85.hr = subscribe:int,
io mserver.1.87.hr = subscribe:int,
io mserver.1.89.hr = subscribe:int,
io mserver.1.91.hr = subscribe:int,
io mserver.1.93.hr = subscribe:int,
io mserver.1.95.hr = subscribe:int,
io mserver.1.97.hr = subscribe:int,
io mserver.1.99.hr = subscribe:int,
io mserver.1.101.hr = subscribe:int,
io mserver.1.103.hr = subscribe:int,
io mserver.1.105.hr = subscribe:int,
io mserver.1.107.hr = subscribe:int,
io mserver.1.109.hr = subscribe:int,
io mserver.1.111.hr = subscribe:int,
io mserver.1.113.hr = subscribe:int,
io mserver.1.115.hr = subscribe:int,
io mserver.1.117.hr = subscribe:int,
io mserver.1.119.hr = subscribe:int,
io mserver.1.121.hr = subscribe:int,
io mserver.1.123.hr = subscribe:int,
io mserver.1.125.hr = subscribe:int,
io mserver.1.127.hr = subscribe:int
#tab 4
io mserver.connection = online : {
for (var i = 1223; i < 2246; i++) {
ioSet("mserver."+unitid+"."+i+".hr", "subscribe:int");
i++;
}
}
MODBUS tables
Supported Modbus functions, Modbus TCP/IP
03: Read Holding Registers
06: Write Single Register
Program Status Table
Modbus address | Info |
---|---|
1 | Program status 1 |
3 | Program status 2 |
5 | Program status 3 |
7 | Program status 4 |
9 | Program status 5 |
11 | Program status 6 |
13 | Program status 7 |
15 | Program status 8 |
17 | Program status 9 |
19 | Program status 10 |
21 | Program status 11 |
23 | Program status 12 |
25 | Program status 13 |
27 | Program status 14 |
29 | Program status 15 |
31 | Program status 16 |
33 | Program status 17 |
35 | Program status 18 |
37 | Program status 19 |
39 | Program status 20 |
41 | Program status 21 |
43 | Program status 22 |
45 | Program status 23 |
47 | Program status 24 |
49 | Program status 25 |
51 | Program status 26 |
53 | Program status 27 |
55 | Program status 28 |
57 | Program status 29 |
59 | Program status 30 |
61 | Program status 31 |
63 | Program status 32 |
Possible Values:
bit | Description | note |
---|---|---|
0..3 | sub state | See Table 1.1 |
4 | pre alarm | |
5 | alarm | |
6 | alarm memory | |
7..32 | not used |
Table 1.1
Value | Status |
---|---|
0 | normal status |
1 | pre exit |
2 | exit |
3 | armed |
4 | armed partial |
5 | partial |
6 | end of partialization |
Program Commands Table
Send a command to the Tecnoalarm panel by writing 0 or 3 in one of this registers
Modbus address | Info |
---|---|
65 | Program command 1 |
67 | Program command 2 |
69 | Program command 3 |
71 | Program command 4 |
73 | Program command 5 |
75 | Program command 6 |
77 | Program command 7 |
79 | Program command 8 |
81 | Program command 9 |
83 | Program command 10 |
85 | Program command 11 |
87 | Program command 12 |
89 | Program command 13 |
91 | Program command 14 |
93 | Program command 15 |
95 | Program command 16 |
97 | Program command 17 |
99 | Program command 18 |
101 | Program command 19 |
103 | Program command 20 |
105 | Program command 21 |
107 | Program command 22 |
109 | Program command 23 |
111 | Program command 24 |
113 | Program command 25 |
115 | Program command 26 |
117 | Program command 27 |
119 | Program command 28 |
121 | Program command 29 |
123 | Program command 30 |
125 | Program command 31 |
127 | Program command 32 |
Possible Values:
value | Description |
---|---|
0 | disarm program |
3 | arm program |
Connection Status
Modbus address | Info |
---|---|
196 | 0 : HSYCO not connected with Tecnoalarm panel |
196 | 1 : HSYCO connected |
Zone Status Table
Modbus address | Zone Status |
---|---|
198 | Zone status 1 |
200 | Zone status 2 |
202 | Zone status 3 |
... | ... |
... | ... |
1220 | Zone status 512 |
Possible Values:
bit | Description | note |
---|---|---|
0 | permanent exclusion | |
1 | alarm | |
2 | cable cut | |
3 | alarm cable cut | |
4 | battery status | |
5 | no radio | |
6 | open/close | open = 0, close = 1 |
7 | learned | |
8 | active | 1 = armed, 0 = disarmed |
9 | ||
10 | ||
11 | alarm memory |
Zone Commands Table
Modbus address | Zone Status |
---|---|
1223 | Zone command 1 |
1225 | Zone command 2 |
1227 | Zone command 3 |
... | ... |
... | ... |
2245 | Zone command 512 |
Possible Values:
value | Description |
---|---|
0 | include zone |
3 | exclude zone |