This is a full setup and how to connecting a Nilan ventilation or heatpump using the Nilan CTS602 modbus interface to openhab 2.4 using a RS485 USB dongle.
This example applies to Nilan Comfort 300LR (Ventilation) without pre- or after- heating, and no CO2 either. It´s a HVAC without heater or cooler. The three devices are optional addons for the Nilan Comfort 300LR. All data will be available through Modbus, if they´re applied. In this turtorial, they are not applied.
First you´ll need a RS485 USB device. The one I use is from In-Circuit and bought on Amazon.de.
https://www.amazon.de/In-Circuit-901-274-USB-RS485-Adapter/dp/B00I9H0998/ref=sr_1_6?keywords=In-Circuit&qid=1553725671&s=gateway&sr=8-6
Its available with a housing as well.
Second you´ll need to know the modbus wiring for the Nilan CTS602 interface. On my Nilan Comfort 300LR, the modbus interface is located on the right side of the agregate.
My device is from before November 2017. Nilan has changed the modbus interface to a grey plug since then, but it´s still located on the right side of the agregate. The wiring is almost the same for both the green and the grey models, but to make sure, you should look into your setup manual.
The wiring in use for my specific device are:
A1 (yellow) B1 (brown) and GND (blue). (The other wires are used for the display which came with the Nilan Comfort 300LR).
At the other end (RS485 USB dongle), the same three wires will have to be connected like this:
In following order from left to right of the picture: Blue, Yellow and Brown.
The dip switches is set to, 1 = OFF, 2 = ON, 3 = ON and 4 = ON.
Setting up Openhab.
Go to PaperUI -> Addons -> Bindings and install the Modbus 2.4 (or later) binding.
Thats basicly it.
From here, all thats needed is a things, and items and sitemap. I have created a basic (full) setup ready to use, by just copying the files into their respective folders, covering the Nilan Comfort 300LR (without heater and CO2 addon If your agregate got heater and/or CO2, you should add the extra registers as well as the items).
.things:
Bridge modbus:serial:myNilan [ port="/dev/ttyUSB0", id=30, baud=19200, stopBits="1.0", parity="even", dataBits=8, encoding="rtu" ] {
Bridge poller appRegisters [ start=000, length=4, refresh=6000, type="input" ] {
Thing data inp000 [ readStart="000", readValueType="int16" ]
Thing data inp001 [ readStart="001", readValueType="int16" ]
Thing data inp002 [ readStart="002", readValueType="int16" ]
Thing data inp003 [ readStart="003", readValueType="int16" ]
}
Bridge poller 100Registers [ start=100, length=16, refresh=6000, type="input" ] {
Thing data inp100 [ readStart="100", readValueType="int16" ]
Thing data inp101 [ readStart="101", readValueType="int16" ]
Thing data inp103 [ readStart="103", readValueType="int16" ]
Thing data inp105 [ readStart="105", readValueType="int16" ]
Thing data inp106 [ readStart="106", readValueType="int16" ]
Thing data inp107 [ readStart="107", readValueType="int16" ]
Thing data inp114 [ readStart="114", readValueType="int16" ]
Thing data inp115 [ readStart="115", readValueType="int16" ]
}
Bridge poller inputRegisters [ start=200, length=23, refresh=6000, type="input" ] {
Thing data inp200 [ readStart="200", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp202 [ readStart="202", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp203 [ readStart="203", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp204 [ readStart="204", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp207 [ readStart="207", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp208 [ readStart="208", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp209 [ readStart="209", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp210 [ readStart="210", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp215 [ readStart="215", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp221 [ readStart="221", readValueType="int16", readTransform="JS(divide100.js)" ]
}
Bridge poller 400Registers [ start=400, length=10, refresh=6000, type="input" ] {
Thing data inp400 [ readStart="400", readValueType="int16" ]
Thing data inp401 [ readStart="401", readValueType="int16" ]
Thing data inp402 [ readStart="402", readValueType="int16", readTransform="JS(nilan_alarmdate.js)" ]
Thing data inp403 [ readStart="403", readValueType="int16", readTransform="JS(nilan_alarmdate.js)" ]
Thing data inp404 [ readStart="404", readValueType="int16" ]
Thing data inp405 [ readStart="405", readValueType="int16", readTransform="JS(nilan_alarmdate.js)" ]
Thing data inp406 [ readStart="406", readValueType="int16", readTransform="JS(nilan_alarmdate.js)" ]
Thing data inp407 [ readStart="407", readValueType="int16" ]
Thing data inp408 [ readStart="408", readValueType="int16", readTransform="JS(nilan_alarmdate.js)" ]
Thing data inp409 [ readStart="409", readValueType="int16", readTransform="JS(nilan_alarmdate.js)" ]
}
Bridge poller statusRegisters [ start=1000, length=4, refresh=6000, type="input" ] {
Thing data inp1000 [ readStart="1000", readValueType="int16" ]
Thing data inp1001 [ readStart="1001", readValueType="int16" ]
Thing data inp1002 [ readStart="1002", readValueType="int16" ]
Thing data inp1003 [ readStart="1003", readValueType="int16" ]
}
Bridge poller airflowRegisters [ start=1100, length=5, refresh=6000, type="input" ] {
Thing data inp1100 [ readStart="1100", readValueType="int16" ]
Thing data inp1101 [ readStart="1101", readValueType="int16" ]
Thing data inp1102 [ readStart="1102", readValueType="int16" ]
Thing data inp1103 [ readStart="1103", readValueType="int16" ]
Thing data inp1104 [ readStart="1104", readValueType="int16" ]
}
Bridge poller airRegisters [ start=1200, length=7, refresh=6000, type="input" ] {
Thing data inp1200 [ readStart="1200", readValueType="int16" ]
Thing data inp1201 [ readStart="1201", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp1202 [ readStart="1202", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp1203 [ readStart="1203", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp1204 [ readStart="1204", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp1205 [ readStart="1205", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data inp1206 [ readStart="1206", readValueType="int16", readTransform="JS(divide100.js)" ]
}
Bridge poller displayRegisters [ start=2000, length=12, refresh=6000, type="input" ] {
Thing data inp2000 [ readStart="2000", readValueType="int16" ]
Thing data inp2000 [ readStart="2002", readValueType="int16" ]
Thing data inp2000 [ readStart="2003", readValueType="int16" ]
Thing data inp2000 [ readStart="2004", readValueType="int16" ]
Thing data inp2000 [ readStart="2005", readValueType="int16" ]
Thing data inp2000 [ readStart="2006", readValueType="int16" ]
Thing data inp2000 [ readStart="2007", readValueType="int16" ]
Thing data inp2000 [ readStart="2008", readValueType="int16" ]
Thing data inp2000 [ readStart="2009", readValueType="int16" ]
Thing data inp2000 [ readStart="2010", readValueType="int16" ]
Thing data inp2000 [ readStart="2011", readValueType="int16" ]
}
Bridge poller holdingRegisters [ start=100, length=28, refresh=6000, type="holding" ] {
Thing data hold100 [ readStart="100", readValueType="int16" ]
Thing data hold102 [ readStart="102", readValueType="int16" ]
Thing data hold103 [ readStart="103", readValueType="int16" ]
Thing data hold123 [ readStart="123", readValueType="int16", writeStart="123", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold125 [ readStart="125", readValueType="int16", writeStart="125", writeValueType="int16", writeType="holding" ]
Thing data hold126 [ readStart="126", readValueType="int16", writeStart="126", writeValueType="int16", writeType="holding" ]
}
Bridge poller fanRegisters [ start=200, length=3, refresh=6000, type="holding" ] {
Thing data hold200 [ readStart="200", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data hold201 [ readStart="201", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data hold202 [ readStart="202", readValueType="int16", readTransform="JS(divide100.js)" ]
}
Bridge poller timeRegisters [ start=300, length=6, refresh=6000, type="holding" ] {
Thing data hold300 [ readStart="300", readValueType="int16" ]
Thing data hold301 [ readStart="301", readValueType="int16" ]
Thing data hold302 [ readStart="302", readValueType="int16" ]
Thing data hold303 [ readStart="303", readValueType="int16" ]
Thing data hold304 [ readStart="304", readValueType="int16" ]
Thing data hold305 [ readStart="305", readValueType="int16" ]
}
Bridge poller ProgSelRegisters [ start=500, length=2, refresh=6000, type="holding" ] {
Thing data hold500 [ readStart="500", readValueType="int16", writeStart="500", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
}
Bridge poller ProgUserFuncActRegisters [ start=600, length=7, refresh=6000, type="holding" ] {
Thing data hold600 [ readStart="600", readValueType="int16", writeStart="600", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold601 [ readStart="601", readValueType="int16", writeStart="601", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold602 [ readStart="602", readValueType="int16", writeStart="602", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold603 [ readStart="603", readValueType="int16", writeStart="603", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold604 [ readStart="604", readValueType="int16", writeStart="604", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
Thing data hold605 [ readStart="605", readValueType="int16", writeStart="605", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
}
Bridge poller controlRegisters [ start=1001, length=7, refresh=6000, type="holding" ] {
Thing data hold1001 [ readStart="1001", readValueType="int16", writeStart="1001", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold1002 [ readStart="1002", readValueType="int16", writeStart="1002", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold1003 [ readStart="1003", readValueType="int16", writeStart="1003", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold1004 [ readStart="1004", readValueType="int16", writeStart="1004", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
Thing data hold1005 [ readStart="1005", readValueType="int16" ]
Thing data hold1006 [ readStart="1006", readValueType="int16", readTransform="JS(divide100.js)" ]
Thing data hold1007 [ readStart="1007", readValueType="int16" ]
}
Bridge poller AirFlowExhMoRegisters [ start=1100, length=2, refresh=6000, type="holding" ] {
Thing data hold1100 [ readStart="1100", readValueType="int16" ]
Thing data hold1101 [ readStart="1101", readValueType="int16", writeStart="1101", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
}
Bridge poller AirTempRegisters [ start=1200, length=8, refresh=6000, type="holding" ] {
Thing data hold1200 [ readStart="1200", readValueType="int16", writeStart="1200", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
Thing data hold1201 [ readStart="1201", readValueType="int16", writeStart="1201", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
Thing data hold1202 [ readStart="1202", readValueType="int16", writeStart="1202", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
Thing data hold1203 [ readStart="1203", readValueType="int16", writeStart="1203", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
Thing data hold1204 [ readStart="1204", readValueType="int16", writeStart="1204", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
Thing data hold1205 [ readStart="1205", readValueType="int16", writeStart="1205", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
}
Bridge poller AirQuaRhRegisters [ start=1910, length=4, refresh=6000, type="holding" ] {
Thing data hold1910 [ readStart="1910", readValueType="int16", writeStart="1910", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold1911 [ readStart="1911", readValueType="int16", writeStart="1911", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
Thing data hold1912 [ readStart="1912", readValueType="int16", writeStart="1912", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true", readTransform="JS(divide100.js)", writeTransform="JS(multiply100.js)" ]
Thing data hold1913 [ readStart="1913", readValueType="int16", writeStart="1913", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ]
}
}
items:
/* Nilan */
String nilan_generated_time "Systemtime [%s]" <time> (gNilan)
Number nilan_generated_chartperiod "Chart period [%d]" <line> (gNilan)
Group gNilan "All Modbus attributes (input + holding)"
Group gNilanProgram "User program settings"
Group gAirSensor "Air temperature and quality sensors"
Number nilan_BusVersion "Bus version [%s]" {channel="modbus:data:myNilan:appRegisters:inp000:number"}
String nilan_AppVersionMajor "App Version Major [%s]" {channel="modbus:data:myNilan:appRegisters:inp001:string"}
String nilan_AppversionMinor "App Version Minor [%s]" {channel="modbus:data:myNilan:appRegisters:inp002:string"}
String nilan_AppVersionRelease "App Version Release [%s]" {channel="modbus:data:myNilan:appRegisters:inp003:string"}
Switch nilan_Input_UserFunc "User function [%s]" <boy_2> (gNilan) {channel="modbus:data:myNilan:100Registers:inp100:switch"}
Switch nilan_Input_AirFilter "Air filter alarm [%s]" <siren> (gNilan) {channel="modbus:data:myNilan:100Registers:inp101:switch"}
Switch nilan_Input_Smoke "Fire/Smoke alarm [%s]" <smoke> (gNilan) {channel="modbus:data:myNilan:100Registers:inp103:switch"}
Switch nilan_Input_Frost_Overht "Heating surface frost / overheat [%s]" <climate> (gNilan) {channel="modbus:data:myNilan:100Registers:inp105:switch"}
Switch nilan_Input_AirFlow "Airflow monitor (guard) [%s]" <flow> (gNilan) {channel="modbus:data:myNilan:100Registers:inp106:switch"}
Switch nilan_Input_P_HI "High pressure switch [%s]" <pressure> (gNilan) {channel="modbus:data:myNilan:100Registers:inp107:switch"}
Switch nilan_Input_DamperClosed "Air Damper Closed position [%s]" <flow> (gNilan) {channel="modbus:data:myNilan:100Registers:inp114:switch"}
Switch nilan_Input_DamperOpen "Air Damper Open position [%s]" <flow> (gNilan) {channel="modbus:data:myNilan:100Registers:inp115:switch"}
Number nilan_Input_T0_Controller "T0 Controller Board Temperature [%.1f °C]" <temperature> (gNilan,heat_nilan) {channel="modbus:data:myNilan:inputRegisters:inp200:number"}
// Number nilan_Input_T2_Inlet "Inlet Temperature (before heater) [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:inputRegisters:inp202:number"}
Number nilan_Input_T3_Exhaust "T3 Room Exhaust Temperature [%.1f °C]" <temperature> (gNilan,gAirSensor,gChart,heat_nilan) {channel="modbus:data:myNilan:inputRegisters:inp203:number"}
Number nilan_Input_T4_Outlet "T4 Outlet Temperature [%.1f °C]" <temperature> (gNilan,heat_nilan) {channel="modbus:data:myNilan:inputRegisters:inp204:number"}
Number nilan_Input_T7_Inlet "T7 Inlet Temperature (after heater) [%.1f °C]" <temperature> (gNilan,gAirSensor,gChart,heat_nilan) {channel="modbus:data:myNilan:inputRegisters:inp207:number"}
Number nilan_Input_T8_Outdoor "T8 Outdoor temperatur [%.1f °C]" <temperature> (gNilan,gAirSensor,gChart,heat_nilan) {channel="modbus:data:myNilan:inputRegisters:inp208:number"}
Number nilan_Input_T9_Heater "T9 Heating Surface Temperature T9 [%.1f °C]" <temperature> (gNilan,heat_nilan) {channel="modbus:data:myNilan:inputRegisters:inp209:number"}
Number nilan_Input_T10_Extem "T10 External room temperature T10 [%.1f °C]" <temperature> (gNilan,heat_nilan) {channel="modbus:data:myNilan:inputRegisters:inp210:number"}
Number nilan_Input_T15_Room "T15 Userpanel Room Temperatur [%.1f °C]" <temperature> (gNilan,gAirSensor,heat_nilan) {channel="modbus:data:myNilan:inputRegisters:inp215:number"}
Number nilan_Input_RH "Humidity [%.0f %%]" <humidity> (gNilan,gAirSensor,Fugtighed) {channel="modbus:data:myNilan:inputRegisters:inp221:number"}
Number Nilan_Alarm_Status "Alarm state bit mask [%d]" <keyring> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp400:number"}
Number Nilan_Alarm_List_1_ID "Alarm 1 - Code [MAP(nilan_alarmcode_to_string.map):%s]" <keyring> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp401:number"}
String Nilan_Alarm_List_1_Date "Alarm 1 - Date [%s]" <calendar> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp402:string"}
String Nilan_Alarm_List_1_Time "Alarm 1 - Time [%s]" <clock> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp403:string"}
Number Nilan_Alarm_List_2_ID "Alarm 2 - Code [%s]" <keyring> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp404:number"}
String Nilan_Alarm_List_2_Date "Alarm 2 - Date [%s]" <calendar> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp405:string"}
String Nilan_Alarm_List_2_Time "Alarm 2 - Time [%s]" <clock> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp406:string"}
Number Nilan_Alarm_List_3_ID "Alarm 3 - Code [%s]" <keyring> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp407:number"}
String Nilan_Alarm_List_3_Date "Alarm 3 - Date [%s]" <calendar> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp408:string"}
String Nilan_Alarm_List_3_Time "Alarm 3 - Time [%s]" <clock> (gNilanAlarm) {channel="modbus:data:myNilan:400Registers:inp409:string"}
Switch nilan_Control_RunAct "Actual on/off state [%s]" <switch> (gNilan) {channel="modbus:data:myNilan:statusRegisters:inp1000:switch"}
Number nilan_Control_ModeAct "Actual operation mode [MAP(nilan_control_modeact.map):%s]" <settings> (gNilan) {channel="modbus:data:myNilan:statusRegisters:inp1001:number"}
Number nilan_Control_State "Actual control state [MAP(nilan_control_state.map):%s]" <settings> {channel="modbus:data:myNilan:statusRegisters:inp1002:number"}
Number nilan_Control_SeclnState "Actual time in state [%d s]" <time> {channel="modbus:data:myNilan:statusRegisters:inp1003:number"}
Number nilan_AirFlow_VentSet "Actual ventilation step set point [MAP(nilan_ventset.map):%s]" <fan> {channel="modbus:data:myNilan:airflowRegisters:inp1100:number"}
Number nilan_AirFlow_InletAct "Actual Inlet step set point [MAP(nilan_ventset.map):%s]" <fan> {channel="modbus:data:myNilan:airflowRegisters:inp1101:number"}
Number nilan_AirFlow_ExhaustAct "Actual Exhaust step set point [MAP(nilan_ventset.map):%s]" <fan> {channel="modbus:data:myNilan:airflowRegisters:inp1102:number"}
Number nilan_AirFlow_SinceFiltDay "Days since last airfilter change alarm [%s]" <calendar> {channel="modbus:data:myNilan:airflowRegisters:inp1103:number"}
Number nilan_AirFlow_ToFiltDay "Days to next airfilter change alarm [%s]" <calendar> {channel="modbus:data:myNilan:airflowRegisters:inp1104:number"}
Number Nilan_AirTemp_IsSummer "Summer state [MAP(nilan_summer_on_off.map):%s]" <sun> (gNilan) {channel="modbus:data:myNilan:airRegisters:inp1200:number"}
Number Nilan_AirTemp_TempinletSet "Inlet temperature request (T7 setpoint) [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:airRegisters:inp1201:number"}
Number Nilan_AirTemp_TempControl "Actual value for controlled temperature [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:airRegisters:inp1202:number"}
Number Nilan_AirTemp_TempRoom "Actual room temperature (T15 or T10) [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:airRegisters:inp1203:number"}
Number Nilan_AirTemp_EffPct "Passive Heat exchanger efficiency [%.1f %%]" <line> (gNilan) {channel="modbus:data:myNilan:airRegisters:inp1204:number"}
Number Nilan_AirTemp_CapSet "Requested capacity [%.1f %%]" {channel="modbus:data:myNilan:airRegisters:inp1205:number"}
Number Nilan_AirTemp_CapAct "Actual capacity [%.1f %%]" {channel="modbus:data:myNilan:airRegisters:inp1206:number"}
Number Nilan_Display_LED_1 "LED 1 [MAP(nilan_on_off.map):%s]" <cu_light> (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2000:number"}
String Nilan_Display_Text_1_2 "Text line 1 character 1-2 [%s]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2002:string"}
String Nilan_Display_Text_3_4 "Text line 1 character 3-4 [%s]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2003:string"}
String Nilan_Display_Text_5_6 "Text line 1 character 5-6 [%s]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2004:string"}
String Nilan_Display_Text_7_8 "Text line 1 character 7-8 [%s]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2005:string"}
Number Nilan_Display_Attr_1_8 "Text line 1 flags [%d]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2006:number"}
String Nilan_Display_Text_9_10 "Text line 2 character 9-10 [%s]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2007:string"}
String Nilan_Display_Text_11_12 "Text line 2 character 11-12 [%s]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2008:string"}
String Nilan_Display_Text_13_14 "Text line 2 character 13-14 [%s]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2009:string"}
String Nilan_Display_Text_15_16 "Text line 2 character 15-16 [%s]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2010:string"}
Number Nilan_Display_Attr_9_16 "Text line 2 flags [%d]" (gNilan) {channel="modbus:data:myNilan:displayRegisters:inp2011:number"}
Contact nilan_Output_AirFlap "Air flap [%s]" <contact> (gNilan) {channel="modbus:data:myNilan:holdingRegisters:hold100:contact"}
Contact nilan_Output_BypassOpen "Bypass flap open [%s]" <contact> (gNilan) {channel="modbus:data:myNilan:holdingRegisters:hold102:contact"}
Contact nilan_Output_BypassClose "Bypass flap close [%s]" <contact> (gNilan) {channel="modbus:data:myNilan:holdingRegisters:hold103:contact"}
Switch nilan_Output_UserFunc "User function active [%s]" <boy_2> (gNilan) {channel="modbus:data:myNilan:holdingRegisters:hold123:switch"}
Switch nilan_Output_Defrosting "Defrost function active [%s]" <climate> (gNilan) {channel="modbus:data:myNilan:holdingRegisters:hold125:switch"}
Switch nilan_AlarmRelayState "Alarm Relay state [%s]" <switch> (gNilan) {channel="modbus:data:myNilan:holdingRegisters:hold126:switch"}
Number nilan_Output_ExhaustSpeed "Exhaust fan speed [%.0f %%]" <fan> (gNilan) {channel="modbus:data:myNilan:fanRegisters:hold200:number"}
Number nilan_Output_InletSpeed "Inlet fan speed [%.0f %%]" <fan> (gNilan) {channel="modbus:data:myNilan:fanRegisters:hold201:number"}
Number nilan_Output_AirHeatCap "Air heater capacity [%.1f %%]" <line> {channel="modbus:data:myNilan:fanRegisters:hold202:number"}
Number Nilan_Time_Second "Second [%d]" <time> (gNilan) {channel="modbus:data:myNilan:timeRegisters:hold300:number"}
Number Nilan_Time_Minute "Minute [%d]" <time> (gNilan) {channel="modbus:data:myNilan:timeRegisters:hold301:number"}
Number Nilan_Time_Hour "Hour [%d]" <time> (gNilan) {channel="modbus:data:myNilan:timeRegisters:hold302:number"}
Number Nilan_Time_Day "Day [%d]" <calendar> (gNilan) {channel="modbus:data:myNilan:timeRegisters:hold303:number"}
Number Nilan_Time_Month "Month [%d]" <calendar> (gNilan) {channel="modbus:data:myNilan:timeRegisters:hold304:number"}
Number Nilan_Time_Year "Year [%d]" <calendar> (gNilan) {channel="modbus:data:myNilan:timeRegisters:hold305:number"}
Number Nilan_Program_Select "Week program nb. select [MAP(nilan_program_select.map):%s]" <calendar> (gNilan,gNilanProgram) {channel="modbus:data:myNilan:ProgSelRegisters:hold500:number"}
Switch Nilan_Program_UserFuncAct "User function active [%s]" <boy_2> (gNilan,gNilanProgram) {channel="modbus:data:myNilan:ProgUserFuncActRegisters:hold600:switch"}
Number Nilan_Program_UserFuncSet "User function select [MAP(nilan_program_userfuncset.map):%s]" <settings> (gNilan,gNilanProgram) {channel="modbus:data:myNilan:ProgUserFuncActRegisters:hold601:number"}
Number Nilan_Program_UserTimeSet "Min User function period [%d min.]" <clock> (gNilan,gNilanProgram) {channel="modbus:data:myNilan:ProgUserFuncActRegisters:hold602:number"}
Number Nilan_Program_UserVentSet "Step User function ventilation [MAP(nilan_ventset.map):%s]" <fan_ceiling> (gNilan,gNilanProgram) {channel="modbus:data:myNilan:ProgUserFuncActRegisters:hold603:number"}
Number Nilan_Program_UserTempSet "User function temperature (Extend function only) [%.1f °C]" <temperature> (gNilan,gNilanProgram) {channel="modbus:data:myNilan:ProgUserFuncActRegisters:hold604:number"}
Number Nilan_Program_UserOffsSet "User function temperature(Offset function only) [%.1f °C]" <temperature> (gNilan,gNilanProgram) {channel="modbus:data:myNilan:ProgUserFuncActRegisters:hold605:number"}
Switch Nilan_Control_RunSet "User on / off select" <switch> (gNilan) {channel="modbus:data:myNilan:controlRegisters:hold1001:switch"}
Number Nilan_Control_ModeSet "User operation mode select [MAP(nilan_control_modeact.map):%s]" <settings> (gNilan) {channel="modbus:data:myNilan:controlRegisters:hold1002:number"}
Number Nilan_Control_VentSet "User ventilation step select [MAP(nilan_ventset.map):%s]" <fan_ceiling> (gNilan) {channel="modbus:data:myNilan:controlRegisters:hold1003:number", autoupdate="false"}
Number Nilan_Control_TempSet "User temperature setpoint [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:controlRegisters:hold1004:number"}
Number Nilan_Control_ServiceMode "Service mode select [MAP(nilan_control_servicemode.map):%s]" <lock> (gNilan) {channel="modbus:data:myNilan:controlRegisters:hold1005:number"}
Number Nilan_Control_ServicePct "Service mode capacity [%.1f %%]" (gNilan) {channel="modbus:data:myNilan:controlRegisters:hold1006:number"}
Number Nilan_Control_Preset "Request preset to factory [%d]" (gNilan) {channel="modbus:data:myNilan:controlRegisters:hold1007:number"}
Number Nilan_AirFlow_AirExchMode "Air exchange mode [MAP(nilan_airflow_airexchmode.map):%s]" <flow> (gNilan) {channel="modbus:data:myNilan:AirFlowExhMoRegisters:hold1100:number"}
Number Nilan_AirFlow_CoolVent "Cooling high ventilation step [MAP(nilan_ventset.map):%s]" <fan_ceiling> (gNilan) {channel="modbus:data:myNilan:AirFlowExhMoRegisters:hold1101:number"}
Number Nilan_AirTemp_CoolSet "Cooling temperature setpoint select [%d]" <temperature> (gNilan) {channel="modbus:data:myNilan:AirTempRegisters:hold1200:number"}
Number Nilan_AirTemp_TempMinSum "Inlet temp. min. summer [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:AirTempRegisters:hold1201:number"}
Number Nilan_AirTemp_TempMinWin "Inlet temp. min. winter [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:AirTempRegisters:hold1202:number"}
Number Nilan_AirTemp_TempMax "Inlet temp. max. summer [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:AirTempRegisters:hold1203:number"}
Number Nilan_AirTemp_TempMaxWin "Inlet temp. max. winter [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:AirTempRegisters:hold1204:number"}
Number Nilan_AirTemp_TempSummer "Summer/winter limit [%.1f °C]" <temperature> (gNilan) {channel="modbus:data:myNilan:AirTempRegisters:hold1205:number"}
Number Nilan_AirQual_RH_VentLo "Humidity low winter step select [MAP(nilan_ventset.map):%s]" <fan_ceiling> (gNilan) {channel="modbus:data:myNilan:AirQuaRhRegisters:hold1910:number"}
Number Nilan_AirQual_RH_VentHi "Humidity high step select [MAP(nilan_ventset.map):%s]" <fan_ceiling> (gNilan) {channel="modbus:data:myNilan:AirQuaRhRegisters:hold1911:number"}
Number Nilan_AirQual_RH_LimLo "Humidity limit for low ventilation [%.0f %%]" <humidity> (gNilan) {channel="modbus:data:myNilan:AirQuaRhRegisters:hold1912:number"}
Number Nilan_AirQual_RH_TimeOut "Humidity max. time on high ventilation [%d min.]" <clock> (gNilan) {channel="modbus:data:myNilan:AirQuaRhRegisters:hold1913:number"}
sitemap:
sitemap nilan label="Nilan" {
Frame label="Inputs100" {
Text item=nilan_Input_UserFunc
Text item=nilan_Input_AirFilter
Text item=nilan_Input_Smoke
Text item=nilan_Input_Frost_Overht
Text item=nilan_Input_AirFlow
Text item=nilan_Input_P_HI
Text item=nilan_Input_DamperClosed
Text item=nilan_Input_DamperOpen
}
Frame label="Inputs200" {
Text item=nilan_Input_T0_Controller
// Text item=nilan_Input_T2_Inlet // If No heating feature, inlet temperature reports from T7
Text item=nilan_Input_T3_Exhaust
Text item=nilan_Input_T4_Outlet
Text item=nilan_Input_T7_Inlet
Text item=nilan_Input_T8_Outdoor
// Text item=nilan_Input_T9_Heater // Requires a heater
// Text item=nilan_Input_T10_Extem // Requires external room thermostat
Text item=nilan_Input_T15_Room
Text item=nilan_Input_RH
}
Frame label="Inputs400 Alarm" {
Text item=Nilan_Alarm_Status
Text item=Nilan_Alarm_List_1_ID
Text item=Nilan_Alarm_List_1_Date
Text item=Nilan_Alarm_List_1_Time
Text item=Nilan_Alarm_List_2_ID
Text item=Nilan_Alarm_List_2_Date
Text item=Nilan_Alarm_List_2_Time
Text item=Nilan_Alarm_List_3_ID
Text item=Nilan_Alarm_List_3_Date
Text item=Nilan_Alarm_List_3_Time
}
Frame label="Inputs1000" {
Text item=nilan_Control_RunAct
Text item=nilan_Control_ModeAct
Text item=nilan_Control_State
Text item=nilan_Control_SeclnState
}
Frame label="Inputs1100" {
Text item=nilan_AirFlow_VentSet
Text item=nilan_AirFlow_InletAct
Text item=nilan_AirFlow_ExhaustAct
Text item=nilan_AirFlow_SinceFiltDay
}
Frame label="Inputs1200" {
Text item=Nilan_AirTemp_IsSummer
Text item=Nilan_AirTemp_TempinletSet
Text item=Nilan_AirTemp_TempControl
Text item=Nilan_AirTemp_TempRoom
Text item=Nilan_AirTemp_EffPct
Text item=Nilan_AirTemp_CapSet
Text item=Nilan_AirTemp_CapAct
}
Frame label="Inputs2000 Panel Display " {
Text item=Nilan_Display_LED_1
Text item=Nilan_Display_Text_1_2
Text item=Nilan_Display_Text_3_4
Text item=Nilan_Display_Text_5_6
Text item=Nilan_Display_Text_7_8
Text item=Nilan_Display_Attr_1_8
Text item=Nilan_Display_Text_9_10
Text item=Nilan_Display_Text_11_12
Text item=Nilan_Display_Text_13_14
Text item=Nilan_Display_Text_15_16
Text item=Nilan_Display_Attr_9_16
}
Frame label="Holding 100" {
Text item=nilan_Output_AirFlap
Text item=nilan_Output_BypassOpen
Text item=nilan_Output_BypassClose
Text item=nilan_Output_UserFunc
Text item=nilan_Output_Defrosting
Text item=nilan_AlarmRelayState
}
Frame label="Holding 200" {
Text item=nilan_Output_ExhaustSpeed
Text item=nilan_Output_InletSpeed
Text item=nilan_Output_AirHeatCap
}
Frame label="Holding 300" {
Text item=Nilan_Time_Second
Text item=Nilan_Time_Minute
Text item=Nilan_Time_Hour
Text item=Nilan_Time_Day
Text item=Nilan_Time_Month
Text item=Nilan_Time_Year
}
Frame label="Holding 500" {
Selection item=Nilan_Program_Select label="Weekprogram" mappings=[0="None", 1="Program 1", 2="Program 2", 3="Program 3", 4="Erase"]
}
Frame label="Holding 600" {
Selection item=Nilan_Program_UserFuncAct label="Activate User Function" mappings=[OFF="ikke aktiv", ON="aktiv"] icon="fire"
Selection item=Nilan_Program_UserFuncSet label="User Function" mappings=[0="None", 1="Extend", 2="Inlet", 3="Exhaust", 4="External heater offset", 5="Ventilate"]
Setpoint item=Nilan_Program_UserTimeSet label="Ventilation time [%d min.]" minValue=0 maxValue=65000 step=1
Selection item=Nilan_Program_UserVentSet label="Ventilation speed" mappings=[0="Off", 1="1", 2="2", 3="3", 4="4"]
Setpoint item=Nilan_Program_UserTempSet label="Set temperatur" minValue=0 maxValue=65 step=1 visibility=[Nilan_Program_UserFuncSet==1]
Setpoint item=Nilan_Program_UserOffsSet label="Temperatur-Offset" minValue=0 maxValue=65000 step=1 visibility=[Nilan_Program_UserFuncSet==4]
}
Frame label="Holding 1000" {
Switch item=Nilan_Control_RunSet
Selection item=Nilan_Control_ModeSet mappings=[0="Off", 1="Heat", 2="Cool", 3="AUTO", 4="Service"]
Switch item=Nilan_Control_VentSet mappings=[0="0", 1="1", 2="2", 3="3", 4="4"]
Setpoint item=Nilan_Control_TempSet minValue=0 maxValue=65 step=1
Text item=Nilan_Control_ServiceMode
Text item=Nilan_Control_ServicePct
Text item=Nilan_Control_Preset
Text item=nilan_generated_time
}
Frame label="Holding 1100" {
Selection item=Nilan_AirFlow_AirExchMode label="Air Echange Mode (mode)" mappings=[0="Energy", 1="Comfort", 2="ComfortWater"] //only suitable when having a heater.
Selection item=Nilan_AirFlow_CoolVent label="Ventilation speed for cooling" mappings=[0="Off", 1="1", 2="2", 3="3", 4="4"]
}
Frame label="AirTemp 1200 Holding" {
Selection item=Nilan_AirTemp_CoolSet label="Cooling set temperature" mappings=[0="Off (No cooling allowed)", 1="Set + 0 °C (User setpoint plus 0 degrees)", 2="Set + 1 °C", 3="Set + 2 °C", 4="Set + 3 °C", 5="Set + 4 °C", 6="Set + 5 °C", 7="Set + 7 °C", 8="Set + 10 °C"]
Setpoint item=Nilan_AirTemp_TempMinSum label="Temperaturminimum (Summer)" minValue=0 maxValue=65 step=1
Setpoint item=Nilan_AirTemp_TempMinWin label="Temperaturminimum (Winter)" minValue=0 maxValue=65 step=1
Setpoint item=Nilan_AirTemp_TempMax label="Temperaturmaximum (Summer)" minValue=0 maxValue=65 step=1
Setpoint item=Nilan_AirTemp_TempMaxWin label="Temperaturmaximum (Winter)" minValue=0 maxValue=65 step=1
Setpoint item=Nilan_AirTemp_TempSummer label="Limit Summer / Winter" minValue=0 maxValue=65 step=1
}
Frame label="AirQualRH 1910 Holding" {
Selection item=Nilan_AirQual_RH_VentLo label="Ventilation speed, if humidity is too low (Winter)" mappings=[0="Off", 1="1", 2="2", 3="3", 4="4"]
Selection item=Nilan_AirQual_RH_VentHi label="Ventilation speed, if humidity is too high" mappings=[0="Off", 1="1", 2="2", 3="3", 4="4"]
Setpoint item=Nilan_AirQual_RH_LimLo label="Low humidity limit " minValue=0 maxValue=100 step=5
Setpoint item=Nilan_AirQual_RH_TimeOut label="Ventilation time, when humidity is too high [%d min.]" minValue=0 maxValue=65000 step=1
}
Frame label="app" {
Text item=nilan_BusVersion
Text item=nilan_AppVersionMajor
Text item=nilan_AppversionMinor
Text item=nilan_AppVersionRelease
}
}
Thats it. Please notice, the modbus ID in the things file is set for 30. This is the default modbus ID. If you for some reason have changed it, then you´ll have to change the things file as well.
Issues:
There are a few issues in the above setup.
Alarm dates are not transformed correctly or there is an issue with the modbus readings. I havn´t yet figure how to deal with this. The value returns date 0.0.1980, which is wrong. But I believe its possible to get the correct readings somehow. The problem with testing the alarm values, is to create an alarm issue. Filter exchanged is reported fine though.
The Display Text (LCD) values as well as the app registers needs to be translated in some way. I believe they uses the same scheme, but I havn´t yet understood fully. @nickma82 probably knows how to.
Whats missing is the transformations. There are quite a few in use, so I have compressed them into an RAR archive file for you to download insted. They are mostly self-explained I would say.
transform.rar.txt (3.0 KB)
Hopefully I covered all or most of it.
If anyone can apply with the rest of the registers for heating, CO2 as well as other missing informations about the alarm dates LCD Text and App data, feel free to contribute to this thread.