Schneider smartlink modbus

Hello i am starting this to document for future reference for others my progress with this and problems.
This is what is done so far:
For the powertags 250Amps create an example.thing file in folder things

Bridge modbus:tcp:Powertag_main [ host="192.168.1.1", port=502, id=162, timeBetweenTransactionsMillis=1, connectMaxTries=3, reconnectAfterMillis=14400000  ] {

    Bridge poller main_1 [ start=2999, length=91, refresh=1000, type="input" ] {
        Thing data phaseL1_A_main [ readStart="2999", readValueType="float32" ]
        Thing data phaseL2_A_main [ readStart="3001", readValueType="float32" ]
        Thing data phaseL3_A_main [ readStart="3003", readValueType="float32" ]
        Thing data phaseL1_L2_V_main [ readStart="3019", readValueType="float32" ]
        Thing data phaseL2_L3_V_main [ readStart="3021", readValueType="float32" ]
        Thing data phaseL3_L1_V_main [ readStart="3023", readValueType="float32" ]
        Thing data phaseL1_N_V_main [ readStart="3027", readValueType="float32" ]
        Thing data phaseL2_N_V_main [ readStart="3029", readValueType="float32" ]
        Thing data phaseL3_N_V_main [ readStart="3031", readValueType="float32" ]
        Thing data active_total_power_main [ readStart="3059",readTransform="JS(active_power.js)", readValueType="float32" ]
        Thing data power_factor_total_power_main [ readStart="3083" , readValueType="float32" ]
         
    }
    Bridge poller main_2 [ start=3075, length=2, refresh=1100, type="input" ] {
        Thing data temperature_main [ readStart="3075",readTransform="JS(temperature_power.js)", readValueType="float32" ]

    }

    Bridge poller main_3 [ start=3109, length=3, refresh=1100, type="input" ] {
        Thing data frequency_main [ readStart="3109", readValueType="float32" ]

    }

    Bridge poller main_4 [ start=3207, length=4, refresh=1100, type="input" ] {
        Thing data total_delivered_active_main [ readStart="3207",readTransform="JS(active_power.js)", readValueType="int64" ]
    }
    Bridge poller main_5 [ start=3211, length=4, refresh=1100, type="input" ] {
        Thing data total_received_active_main [ readStart="3211",readTransform="JS(active_power.js)", readValueType="int64" ]

    }
    Bridge poller main_6 [ start=3263, length=4, refresh=1100, type="input" ] {
        Thing data partial_active_energy_delivered_main [ readStart="3263",readTransform="JS(active_power.js)", readValueType="int64" ]

    }
    Bridge poller main_7 [ start=3271, length=4, refresh=1100, type="input" ] {
        Thing data partial_active_energy_received_main [ readStart="3271",readTransform="JS(active_power.js)", readValueType="int64" ]

    }
}

Then for the normal powertags that go to 63Amps create an example2.thing file in folder things

Bridge modbus:tcp:Powertag_security [ host="192.168.1.1", port=502, id=152, timeBetweenTransactionsMillis=1, connectMaxTries=3, reconnectAfterMillis=14400000  ] {

    Bridge poller security_1 [ start=2999, length=91, refresh=1000, type="input" ] {
        Thing data phaseL1_A_security [ readStart="2999", readValueType="float32" ]
        Thing data phaseL2_A_security [ readStart="3001", readValueType="float32" ]
        Thing data phaseL3_A_security [ readStart="3003", readValueType="float32" ]
        Thing data phaseL1_L2_V_security [ readStart="3019", readValueType="float32" ]
        Thing data phaseL2_L3_V_security [ readStart="3021", readValueType="float32" ]
        Thing data phaseL3_L1_V_security [ readStart="3023", readValueType="float32" ]
        Thing data phaseL1_N_V_security [ readStart="3027", readValueType="float32" ]
        Thing data phaseL2_N_V_security [ readStart="3029", readValueType="float32" ]
        Thing data phaseL3_N_V_security [ readStart="3031", readValueType="float32" ]
        Thing data active_total_power_security [ readStart="3059",readTransform="JS(active_power.js)", readValueType="float32" ]
        Thing data power_factor_total_power_security [ readStart="3083" , readValueType="float32" ]
         
    }
    Bridge poller security_4 [ start=3203, length=4, refresh=1100, type="input" ] {
        Thing data total_delivered_active_security [ readStart="3203",readTransform="JS(active_power.js)", readValueType="int64" ]

    }

}

The scrips used for the powertags create file active_power.js in transformation folder

(function(inputData) {
    return parseFloat(inputData) / 1000;
    })(input)

In order to get the data in the ui i used for the big powertag create an example.items in items folder

//main 
Number Amps_main_L1            "L1 Amps main breaker from ups [%.1f A]"   ( gss_modbus_measure_main_amps ) ["Current"] { channel="modbus:data:Powertag_main:main_1:phaseL1_A_main:number" }
Number Amps_main_L2            "L2 Amps main breaker from ups [%.1f A]"  ( gss_modbus_measure_main_amps)  ["Current"] { channel="modbus:data:Powertag_main:main_1:phaseL2_A_main:number" }
Number Amps_main_L3           "L3 Amps main breaker from ups [%.1f A]"  ( gss_modbus_measure_main_amps)  ["Current"] { channel="modbus:data:Powertag_main:main_1:phaseL3_A_main:number" }
Number Volts_main_L1_L2            "L1-L2 Volts main breaker from ups [%.1f V]"  (gss_modbus_measure_main_voltage) ["Voltage"] { channel="modbus:data:Powertag_main:main_1:phaseL1_L2_V_main:number" }
Number Volts_main_L2_L3            "L2-L3 Volts main breaker from ups [%.1f V]" (gss_modbus_measure_main_voltage)  ["Voltage"] { channel="modbus:data:Powertag_main:main_1:phaseL2_L3_V_main:number" }
Number Volts_main_L3_L1           "L3-L1 Volts main breaker from ups [%.1f V]"  (gss_modbus_measure_main_voltage) ["Voltage"] { channel="modbus:data:Powertag_main:main_1:phaseL3_L1_V_main:number" }
Number Volts_main_L1_N            "L1-N Volts main breaker from ups [%.1f V]"  (gss_modbus_measure_main_voltage) ["Voltage"] { channel="modbus:data:Powertag_main:main_1:phaseL1_N_V_main:number" }
Number Volts_main_L2_N            "L2-N Volts main breaker from ups [%.1f V]" (gss_modbus_measure_main_voltage) ["Voltage"]  { channel="modbus:data:Powertag_main:main_1:phaseL2_N_V_main:number" }
Number Volts_main_L3_N           "L3-N Volts main breaker from ups [%.1f V]"  (gss_modbus_measure_main_voltage) ["Voltage"] { channel="modbus:data:Powertag_main:main_1:phaseL3_N_V_main:number" }
Number Total_active_power_main           "Active power 3phase main breaker from ups [%.4f kW]"  (gss_modbus_measure_main_metrics) ["Energy"] { channel="modbus:data:Powertag_main:main_1:active_total_power_main:number" }
Number Total_power_factor_main           "Power factor total main breaker from ups [%.1f cos]"  (gss_modbus_measure_main_metrics) ["Energy"] { channel="modbus:data:Powertag_main:main_1:power_factor_total_power_main:number" }
Number Frequency_main           "Frequency main breaker from ups  [%.1f Hz]"  (gss_modbus_measure_main_metrics) ["Energy"] { channel="modbus:data:Powertag_main:main_3:frequency_main:number" }
Number Temperature_main           "Temperature main breaker from ups [%.1f °C]"  (gss_modbus_measure_main_metrics) ["Measurement","Temperature"] { channel="modbus:data:Powertag_main:main_2:temperature_main:number" }
Number Total_delivered_active_main           " Total active power delivered main breaker from ups [%.4f kWh]"  (gss_modbus_measure_main_metrics) ["Energy"] { channel="modbus:data:Powertag_main:main_4:total_delivered_active_main:number" }
Number Total_received_active_main           " Total active power received main breaker from ups [%.4f kWh]"  (gss_modbus_measure_main_metrics) ["Energy"] { channel="modbus:data:Powertag_main:main_5:total_received_active_main:number" }
Number Partial_active_energy_delivered_main           " Partial active energy delivered main breaker from ups [%.4f kWh]"  (gss_modbus_measure_main_metrics) ["Energy"] { channel="modbus:data:Powertag_main:main_6:partial_active_energy_delivered_main:number" }
Number Partial_active_energy_received_main           " Partial active energy received main breaker from ups [%.4f kWh]"  (gss_modbus_measure_main_metrics) ["Energy"] { channel="modbus:data:Powertag_main:main_7:partial_active_energy_received_main:number" }

And then for the smaller ones create an example2.items in items folder

//security 
Number Amps_security_L1            "L1 Amps security [%.1f A]"   ( gss_modbus_measure_security_amps ) ["Current"] { channel="modbus:data:Powertag_security:security_1:phaseL1_A_security:number" }
Number Amps_security_L2            "L2 Amps security [%.1f A]"  ( gss_modbus_measure_security_amps)  ["Current"] { channel="modbus:data:Powertag_security:security_1:phaseL2_A_security:number" }
Number Amps_security_L3           "L3 Amps security [%.1f A]"  ( gss_modbus_measure_security_amps)  ["Current"] { channel="modbus:data:Powertag_security:security_1:phaseL3_A_security:number" }
Number Volts_security_L1_L2            "L1-L2 Volts security [%.1f V]"  (gss_modbus_measure_security_voltage) ["Voltage"] { channel="modbus:data:Powertag_security:security_1:phaseL1_L2_V_security:number" }
Number Volts_security_L2_L3            "L2-L3 Volts security [%.1f V]" (gss_modbus_measure_security_voltage)  ["Voltage"] { channel="modbus:data:Powertag_security:security_1:phaseL2_L3_V_security:number" }
Number Volts_security_L3_L1           "L3-L1 Volts security [%.1f V]"  (gss_modbus_measure_security_voltage) ["Voltage"] { channel="modbus:data:Powertag_security:security_1:phaseL3_L1_V_security:number" }
Number Volts_security_L1_N            "L1-N Volts security [%.1f V]"  (gss_modbus_measure_security_voltage) ["Voltage"] { channel="modbus:data:Powertag_security:security_1:phaseL1_N_V_security:number" }
Number Volts_security_L2_N            "L2-N Volts security [%.1f V]" (gss_modbus_measure_security_voltage) ["Voltage"]  { channel="modbus:data:Powertag_security:security_1:phaseL2_N_V_security:number" }
Number Volts_security_L3_N           "L3-N Volts security [%.1f V]"  (gss_modbus_measure_security_voltage) ["Voltage"] { channel="modbus:data:Powertag_security:security_1:phaseL3_N_V_security:number" }
Number Total_active_power_security           "Active power 3phase security [%.4f kW]"  (gss_modbus_measure_security_metrics) ["Energy"] { channel="modbus:data:Powertag_security:security_1:active_total_power_security:number" }
Number Total_power_factor_security           "Power factor total security [%.1f cos]"  (gss_modbus_measure_security_metrics) ["Energy"] { channel="modbus:data:Powertag_security:security_1:power_factor_total_power_security:number" }
Number Total_delivered_active_security           " Total active power delivered security [%.4f kWh]"  (gss_modbus_measure_security_metrics) ["Energy"] { channel="modbus:data:Powertag_security:security_4:total_delivered_active_security:number" }

Now for inputs and outputs thing configuration for example slave 2 slot 2 for an ReflexiC60 i used this for the things file

Bridge modbus:tcp:Smartlink_2 [ host="192.168.1.1", port=502, id=2 , timeBetweenTransactionsMillis=1, connectMaxTries=3, reconnectAfterMillis=14400000 ] {

    Bridge poller breakers_car1 [ start=14240, length=2, refresh=2000, type="holding" ] {
        Thing data car1_breaker_write [ readStart="14240.0", readValueType="bit", writeStart="14241", writeValueType="uint16", writeType="holding", writeTransform="JS:writeorderbit.js"]
        Thing data car1_breaker_read [ readStart="14240.0", readValueType="bit" ]
        Thing data car1_breaker_read1 [ readStart="14240.1", readValueType="bit" ]
        
    
    }
    Bridge poller breakers_car1_data [ start=14252, length=4, refresh=2001, type="holding" ] {
        Thing data car1_breaker_cycle [ readStart="14252", readValueType="uint32" ]
        Thing data car1_breaker_trip [ readStart="14254", readValueType="uint32" ]
    }




}

and this items to represent them for the item file thanks [rossko57] for the guidance on this part

//car charger 1
Switch Car1_breaker_write    "Set relay car"   (gss_modbus_devices_car1)   ["Status"]  { channel="modbus:data:Smartlink_2:breakers_car1:car1_breaker_write:switch" }
Number Car1_breaker_read     "Relay car status [MAP(contact_relay.map):%s] "  (gss_modbus_devices_car1)  ["Alarm"]   { channel="modbus:data:Smartlink_2:breakers_car1:car1_breaker_read:switch" }
Number Car1_breaker_read1     "Breaker car status[MAP(contact_breaker.map):%s] "  (gss_modbus_devices_car1)  ["Alarm"]   { channel="modbus:data:Smartlink_2:breakers_car1:car1_breaker_read1:switch" }
Number Car1_breaker_cycle     "Breaker cycle car "  (gss_modbus_devices_car1)  ["Status"]   { channel="modbus:data:Smartlink_2:breakers_car1_data:car1_breaker_cycle:number", listWidget="oh-label-item" }
Number Car1_breaker_trip     "Breaker trip car "  (gss_modbus_devices_car1)  ["Status"]   { channel="modbus:data:Smartlink_2:breakers_car1_data:car1_breaker_trip:number" , listWidget="oh-label-item"}


And then tranformations
The switch transformation create file writeorderbit.js in transformation folder

(function(inputData) {
    // write transform for smartlink orders
    if (inputData == "OFF") {
       return 1 ; // activate bit 0
    } else {
       return 2 ; // de-activate bit 1
    }        
  })(input)

And then mapping for the status of the relay or the handle breaker create file contact_relay.map in transformation folder

1=Relay CLOSED
0=Relay OPEN

This post will be updated as i go adding more different devices

See the binding docs for OH3

For older versions, see

Hello from what I can see my problem would be solved by the modbus binding if function 22 would be available.

The Schneider text you showed earlier does not describe the use of FC22 at all for “Direct Bit Addressing”. Maybe that’s somewhere else?

Regardless, OH binding does not support FC22 today. What are you going to do now?

I don’t really understand what Schneider docs say. Read/writing a single bit in a holding register is straightforward (see below) but I’m not sure that is what they describe- FC01,2,5,15 are all about single bit registers, not 16-bit holding registers.

    Bridge poller breakers_car1 [ start=14240, length=2, refresh=2000, type="holding" ] {
        Thing data car1_breaker_0 [ readStart="14240.0", readValueType="bit",writeStart="14241.0", writeValueType="bit", writeType="holding"]
        Thing data ...
//note the read and write parts of a data Thing need not be the same in any way


Switch Car1_breaker_0    "r/w relay car" 0   { channel="modbus:data:Smartlink_2:breakers_car1:car1_breaker_0:switch" , autoupdate="false"}

I don’t think you need any expire, Schneider suggests that is taken care of at their end.

I’ve got a feeling this is all getting over-complicated, are you sure you can’t just treat these as modbus ‘coil’ types?

Hello maybe I am going crazy with FC 22 but i tried coil and everything.The first example is the only one that works and also in their interface they have two separate buttons to close and open and also for indication. Now from what I can read in Schneider doc is that they accept FC3,6 and 16 and the register is read and write . But like you said this is getting all to complicated to translate that into a simple switch in openhab. I will keep posted if i find a solution.

Thank you for following :+1:

Well openHAB does not support it, and from looking at a Smartlink manual

neither does Schneider. Don’t waste your time on that…

Anyway,from reading the manual I think I’ve got a better grasp of the BITMAP now. There’s multiple ways to access it, let’s use the easiest.

Smartlink talks about writing “orders” for control.
These could be read back, but you don’t need to do that for any reason I can think of. So treat these “orders” as write-only, and read the “input i1” register for the on/off status.

The twist is that it uses two addresses for “orders”, write 1 to X for OFF, write 1 to Y for ON.
You could manage that using rules and two extra dummy Items and two modbus data Things.

But the two ‘targets’ are bits in the same register. All we have to do is write different values for ON/OFF, using a transformation. We don’t care about the other bits in the register.

writeorderbit.js in your /transform folder

(function(inputData) {
  // write transform for smartlink orders
  if (inputData == "ON") {
     return 1 ; // activate bit 0
  } else {
     return 2 ; // de-activate bit 1
  }        
})(input)

Install JS transformation

Now can make one data Thing

    Bridge poller breakers_car1 [ start=14240, length=1, refresh=2000, type="holding" ] {
        Thing data breaker2 [ readStart="14240.0", readValueType="bit", writeStart="14241", writeValueType="uint16", writeType="holding", writeTransform="JS:writeorderbit.js"]

And link to one Item

Switch Car1_breaker2    "Channel 2 on/off"    { channel="modbus:data:Smartlink_2:breakers_car1:breaker2", autoupdate="false"}

Expire not needed, Schneider box looks after itself.

Thank you for spending time on this i managed to make it work like a simple switch.
This is the things file

Bridge modbus:tcp:Smartlink_2 [ host="192.168.1.1", port=502, id=2 ] {

    Bridge poller breakers_car1 [ start=14240, length=2, refresh=2000, type="holding" ] {
        Thing data car1_breaker_write [ readStart="14240.0", readValueType="bit", writeStart="14241", writeValueType="uint16", writeType="holding", writeTransform="JS:writeorderbit.js"]
        Thing data car1_breaker_read [ readStart="14240.0", readValueType="bit" ]
        Thing data car1_breaker_read1 [ readStart="14240.1", readValueType="bit" ]
        
    
    }
    Bridge poller breakers_car1_data [ start=14252, length=4, refresh=2001, type="holding" ] {
        Thing data car1_breaker_cycle [ readStart="14252", readValueType="uint32" ]
        Thing data car1_breaker_trip [ readStart="14254", readValueType="uint32" ]
    }




}

This is the items file

//car charger 1
Switch Car1_breaker_write    "Set relay car"   (gss_modbus_devices_car1)   ["Status"]  { channel="modbus:data:Smartlink_2:breakers_car1:car1_breaker_write:switch" }
Number Car1_breaker_read     "Relay car status [MAP(contact_relay.map):%s] "  (gss_modbus_devices_car1)  ["Alarm"]   { channel="modbus:data:Smartlink_2:breakers_car1:car1_breaker_read:switch" }
Number Car1_breaker_read1     "Breaker car status[MAP(contact_breaker.map):%s] "  (gss_modbus_devices_car1)  ["Alarm"]   { channel="modbus:data:Smartlink_2:breakers_car1:car1_breaker_read1:switch" }
Number Car1_breaker_cycle     "Breaker cycle car "  (gss_modbus_devices_car1)  ["Status"]   { channel="modbus:data:Smartlink_2:breakers_car1_data:car1_breaker_cycle:number", listWidget="oh-label-item" }
Number Car1_breaker_trip     "Breaker trip car "  (gss_modbus_devices_car1)  ["Status"]   { channel="modbus:data:Smartlink_2:breakers_car1_data:car1_breaker_trip:number" , listWidget="oh-label-item"}


And for the transformation i had to change to off

(function(inputData) {
    // write transform for smartlink orders
    if (inputData == "OFF") {
       return 1 ; // activate bit 0
    } else {
       return 2 ; // de-activate bit 1
    }        
  })(input)

Works like a charm granted takes time to pool the status but otherwise does the job

Hope it helps other aswell

After adding a second gateway to openhab i noticed that i get alot of timeout errors from modbus. I also noticed that on the first gateway openhab shows as an active connection and on the second nothing but packets are being send and received. Now from reading the forums i found this https://community.openhab.org/t/solved-can-not-get-modbus-tcp-to-work/69232/25?page=2
But now curious what is the max limit that i can configure reconnectAfterMillis so that connection always stays open ?

Also found this on Schneider website
Please find the below turnaround time of Smartlink Si B as below:

Modbus: 10ms
Ethernet: 1ms.

Thank you @ssalonen i already read that but was curious about a max limit i guess there is none
Looking at the logs i noticed that every hour it was timing out so i decided to add like 4 hours of open connection and after 1 day of running no more errors or warns so this is what it looks right now

Bridge modbus:tcp:Smartlink2_main "smartlink " [ host="192.168.1.1", port=502, id=255, timeBetweenTransactionsMillis=1, connectMaxTries=3, reconnectAfterMillis=14400000 ]