Skip to main content

Modbus TCP Server / Security 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

note

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 Tecnoalarm I/O Server

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 addressInfo
1Program status 1
3Program status 2
5Program status 3
7Program status 4
9Program status 5
11Program status 6
13Program status 7
15Program status 8
17Program status 9
19Program status 10
21Program status 11
23Program status 12
25Program status 13
27Program status 14
29Program status 15
31Program status 16
33Program status 17
35Program status 18
37Program status 19
39Program status 20
41Program status 21
43Program status 22
45Program status 23
47Program status 24
49Program status 25
51Program status 26
53Program status 27
55Program status 28
57Program status 29
59Program status 30
61Program status 31
63Program status 32

Possible Values:

bitDescriptionnote
0..3sub stateSee Table 1.1
4pre alarm
5alarm
6alarm memory
7..32not used

Table 1.1

ValueStatus
0normal status
1pre exit
2exit
3armed
4armed partial
5partial
6end of partialization

Program Commands Table

Send a command to the Tecnoalarm panel by writing 0 or 3 in one of this registers

Modbus addressInfo
65Program command 1
67Program command 2
69Program command 3
71Program command 4
73Program command 5
75Program command 6
77Program command 7
79Program command 8
81Program command 9
83Program command 10
85Program command 11
87Program command 12
89Program command 13
91Program command 14
93Program command 15
95Program command 16
97Program command 17
99Program command 18
101Program command 19
103Program command 20
105Program command 21
107Program command 22
109Program command 23
111Program command 24
113Program command 25
115Program command 26
117Program command 27
119Program command 28
121Program command 29
123Program command 30
125Program command 31
127Program command 32

Possible Values:

valueDescription
0disarm program
3arm program

Connection Status

Modbus addressInfo
1960 : HSYCO not connected with Tecnoalarm panel
1961 : HSYCO connected

Zone Status Table

Modbus addressZone Status
198Zone status 1
200Zone status 2
202Zone status 3
......
......
1220Zone status 512

Possible Values:

bitDescriptionnote
0permanent exclusion
1alarm
2cable cut
3alarm cable cut
4battery status
5no radio
6open/closeopen = 0, close = 1
7learned
8active1 = armed, 0 = disarmed
9
10
11alarm memory

Zone Commands Table

Modbus addressZone Status
1223Zone command 1
1225Zone command 2
1227Zone command 3
......
......
2245Zone command 512

Possible Values:

valueDescription
0include zone
3exclude zone