Recently I connected a Solarfocus Biomass Boiler “therminator II” with openHAB. These products use the “Solarfocus ecomanager-touch” controller, which has a 7” touch display. With this tutorial I share my working configuration and experiences on the Modbus TCP connection.
openHAB environment | |
---|---|
Tested OH versions | 2.5.12 - Release Build, 3.0.1 - Release Build |
Needed Bindings | Modbus |
Needed Transformations | Javascript Transformation, Map Transformation |
1. Check software version and MODBUS TCP option on Solarfocus controller
The Modbus TCP Feature requires a minimum software version. If you don’t have the Modbus TCP Status menu, ask your dealer to activate this feature on your device.
Product | Software version |
---|---|
Wood Boiler therminator II touch | from V 19.072 |
Wood Boiler pelletelegance, octoplus, pellettop touch | from V 19.050 |
Control module ecomanager-touch | from V 19.050 |
Air Source Heat Pump vampair |
Make sure your Solarfocus is connected to a network. The IP settings can be managed in the IP VNC menu.
2. Textual configurations
solarfocus.things
Bridge modbus:tcp:solarfocus [ host="192.168.0.85", port=502, id=1 ] {
// Input registers: Functioncode FC04 (0x04)
// +++++ NOTE: readTransform="JS(conv_divide10.js)" working - readTransform="JS:conv_divide10.js" not working +++++
Bridge poller sf_heizkreis [ start=1100, length=8, refresh=5000, type="input" ] {
Thing data SF1100 [ readStart="1100", readValueType="int16", readTransform="JS(conv_divide10.js)" ] // Vorlauftemperatur
Thing data SF1103 [ readStart="1103", readValueType="uint16", readTransform="JS(conv_binary2.js)" ] // Begrenzungsthermostat offen/geschlossen
Thing data SF1105 [ readStart="1105", readValueType="uint16", readTransform="JS(conv_binary1.js)" ] // Heizkreispumpe Ein/Aus
Thing data SF1106 [ readStart="1106", readValueType="uint16" ] // Mischerstellung
Thing data SF1107 [ readStart="1107", readValueType="uint16" ] // Status Heizkreis
}
Bridge poller sf_puffer [ start=1900, length=5, refresh=10000, type="input" ] {
Thing data SF1900 [ readStart="1900", readValueType="int16", readTransform="JS(conv_divide10.js)" ] // Puffertemperatur oben
Thing data SF1901 [ readStart="1901", readValueType="int16", readTransform="JS(conv_divide10.js)" ] // Puffertemperatur unten
Thing data SF1902 [ readStart="1902", readValueType="int16", readTransform="JS(conv_divide10.js)" ] // Puffertemperatur X35
Thing data SF1903 [ readStart="1903", readValueType="int16", readTransform="JS(conv_binary1.js)" ] // Puffer Ladepumpe
Thing data SF1904 [ readStart="1904", readValueType="uint16" ] // Pufferstatus
}
Bridge poller sf_boiler [ start=500, length=2, refresh=10000, type="input" ] {
Thing data SF500 [ readStart="500", readValueType="int16", readTransform="JS(conv_divide10.js)" ] // Boiler Temperatur
Thing data SF501 [ readStart="501", readValueType="uint16" ] // Boiler Status
}
Bridge poller sf_kessel [ start=2400, length=10, refresh=5000, type="input" ] {
Thing data SF2400 [ readStart="2400", readValueType="int16", readTransform="JS(conv_divide10.js)" ] // Kesseltemperatur
Thing data SF2401 [ readStart="2401", readValueType="uint16" ] // Statuszeile Kessel
Thing data SF2404 [ readStart="2404", readValueType="int16" ] // Nachrichtennummer
Thing data SF2405 [ readStart="2405", readValueType="int16", readTransform="JS(conv_binary3.js)" ] // Türkontakt offen/geschlossen
Thing data SF2406 [ readStart="2406", readValueType="int16" ] // Kesselreinigung %
Thing data SF2407 [ readStart="2407", readValueType="int16" ] // Ascheboxfüllstand
Thing data SF2408 [ readStart="2408", readValueType="int16", readTransform="JS(conv_divide10.js)" ] // Außentemperatur
Thing data SF2409 [ readStart="2409", readValueType="int16" ] // Kesselbetriebsart
}
// Holding registers: Read with Functioncode FC3 (0x03); Write with Functioncode FC16 (0x10)
// +++++ NOTE: writeMultipleEvenWithSingleRegisterOrCoil="true" (FC16); By default, or when 'false, FC06 ("Write single holding register")
Bridge poller sf_holdingreg1 [ start=32600, length=8, refresh=20000, type="holding" ] {
Thing data SF32600 [ readStart="32600", readValueType="int16", readTransform="JS(conv_divide10.js)", writeStart="32600", writeValueType="int16", writeTransform="JS(conv_multiply10.js)", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ] // Vorlaufsolltemperatur
Thing data SF32603 [ readStart="32603", readValueType="int16", writeStart="32603", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ] // Heizkreisbetriebsart
Thing data SF32605 [ readStart="32605", readValueType="int16", readTransform="JS(conv_divide10.js)", writeStart="32605", writeValueType="int16", writeTransform="JS(conv_multiply10.js)", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ] // Raumtemperatur Soll
Thing data SF32606 [ readStart="32606", readValueType="int16", readTransform="JS(conv_divide10.js)", writeStart="32606", writeValueType="int16", writeTransform="JS(conv_multiply10.js)", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ] // Raumtemperatur Ist extern
Thing data SF32607 [ readStart="32607", readValueType="int16", writeStart="32607", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ] // Raumfeuchte Ist extern
}
Bridge poller sf_holdingreg2 [ start=32000, length=3, refresh=30000, type="holding" ] {
Thing data SF32000 [ readStart="32000", readValueType="int16", readTransform="JS(conv_divide10.js)", writeStart="32000", writeValueType="int16", writeTransform="JS(conv_multiply10.js)", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ] // Boiler – Solltemperatur
Thing data SF32001 [ readStart="32001", readValueType="int16", readTransform="JS(conv_binary1.js)", writeStart="32001", writeValueType="int16", writeTransform="JS(conv_binary6.js)", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ] // Boiler – Einmalladung
Thing data SF32002 [ readStart="32002", readValueType="int16", writeStart="32002", writeValueType="int16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil="true" ] // Boiler – Freigabeart
}
}
solarfocus.items
Group gSolarfocus "Group Solarfocus" <text>
Group gSFPuffer "Group Buffer tank" <text>
Group gSFHeizkreis "Group Heating circuit" <text>
Group gSFBoiler "Group Hot water" <text>
// ########## Heating circuit ##########
Number MODBUS_SF1100 "Flow pipe temperature [%.1f °C]" <flowpipe> (gSolarfocus, gSFHeizkreis) { channel="modbus:data:solarfocus:sf_heizkreis:SF1100:number" } // Vorlauftemperatur
Contact MODBUS_SF1103 "Limit thermostat []" <lock> (gSolarfocus) { channel="modbus:data:solarfocus:sf_heizkreis:SF1103:contact" } // Begrenzungsthermostat offen/geschlossen
Switch MODBUS_SF1105 "Heating circuit pump []" <pump> (gSolarfocus, gBhCount, gSwCount) { channel="modbus:data:solarfocus:sf_heizkreis:SF1105:switch" } // Heizkreispumpe Ein/Aus
Number MODBUS_SF1106 "Mixer position [%d %%]" <text> (gSolarfocus) { channel="modbus:data:solarfocus:sf_heizkreis:SF1106:number" } // Mischerstellung
Number MODBUS_SF1107 "Status Heating circuit [MAP(sf-heizkreis1.map):%s]" <radiator> (gSolarfocus) { channel="modbus:data:solarfocus:sf_heizkreis:SF1107:number" } // Status Heizkreis
// ########## Buffer tank ##########
Number MODBUS_SF1900 "Buffer temperature top [%.1f °C]" <temperature> (gSolarfocus, gSFPuffer) { channel="modbus:data:solarfocus:sf_puffer:SF1900:number" } // Puffertemperatur oben
Number MODBUS_SF1901 "Buffer temperature bottom [%.1f °C]" <temperature> (gSolarfocus, gSFPuffer) { channel="modbus:data:solarfocus:sf_puffer:SF1901:number" } // Puffertemperatur unten
Number MODBUS_SF1902 "Buffer temperature X35 [%.1f °C]" <temperature> (gSolarfocus, gSFPuffer) { channel="modbus:data:solarfocus:sf_puffer:SF1902:number" } // Puffertemperatur X35
Switch MODBUS_SF1903 "Buffer charging pump []" <pump> (gSolarfocus, gBhCount, gSwCount) { channel="modbus:data:solarfocus:sf_puffer:SF1903:switch" } // Puffer Ladepumpe
Number MODBUS_SF1904 "Status Buffer [MAP(sf-puffer.map):%s]" <text> (gSolarfocus) { channel="modbus:data:solarfocus:sf_puffer:SF1904:number" } // Pufferstatus
// ########## Hot water ##########
Number MODBUS_SF500 "Hot water temperature [%.1f °C]" <faucet> (gSolarfocus, gSFBoiler) { channel="modbus:data:solarfocus:sf_boiler:SF500:number" } // Boiler Temperatur
Number MODBUS_SF501 "Status Hot water [MAP(sf-boiler.map):%s]" <text> (gSolarfocus) { channel="modbus:data:solarfocus:sf_boiler:SF501:number" } // Boiler Status
// ########## Biomass Boiler ##########
Number MODBUS_SF2400 "Boiler temperature [%.1f °C]" <fire> (gSolarfocus) { channel="modbus:data:solarfocus:sf_kessel:SF2400:number" } // Kesseltemperatur
Number MODBUS_SF2401 "Status Boiler [MAP(sf-kessel1.map):%s]" <text> (gSolarfocus) { channel="modbus:data:solarfocus:sf_kessel:SF2401:number" } // Statuszeile Kessel
Number MODBUS_SF2404 "Message [MAP(sf-meldungen1.map):%s]" <error> (gSolarfocus) { channel="modbus:data:solarfocus:sf_kessel:SF2404:number" } // Nachrichtennummer
Contact MODBUS_SF2405 "Front door []" <frontdoor> (gSolarfocus) { channel="modbus:data:solarfocus:sf_kessel:SF2405:contact" } // Türkontakt offen/geschlossen
Number MODBUS_SF2406 "Boiler cleaning [%d %%]" <settings> (gSolarfocus) { channel="modbus:data:solarfocus:sf_kessel:SF2406:number" } // Kesselreinigung %
Number MODBUS_SF2407 "Ash box level [%d %%]" <settings> (gSolarfocus) { channel="modbus:data:solarfocus:sf_kessel:SF2407:number" } // Ascheboxfüllstand
Number MODBUS_SF2408 "Temperature outside [%.1f °C]" <temperature> (gSolarfocus) { channel="modbus:data:solarfocus:sf_kessel:SF2408:number" } // Außentemperatur
Number MODBUS_SF2409 "Boiler operating mode [MAP(sf-kessel2.map):%s]" <text> (gSolarfocus) { channel="modbus:data:solarfocus:sf_kessel:SF2409:number" } // Kesselbetriebsart
// ########## Holding registers heating circuit ##########
Number MODBUS_SF32600 "Flow pipe set-point temperature [%.1f °C]" <flowpipe> (gSolarfocus) { channel="modbus:data:solarfocus:sf_holdingreg1:SF32600:number" } // Vorlaufsolltemperatur
Number MODBUS_SF32603 "Heating circuit operating mode [MAP(sf-heizkreis2.map):%s]" <radiator> (gSolarfocus) { channel="modbus:data:solarfocus:sf_holdingreg1:SF32603:number" } // Heizkreisbetriebsart
Number MODBUS_SF32605 "Room set-point temperature [%.1f °C]" <temperature> (gSolarfocus) { channel="modbus:data:solarfocus:sf_holdingreg1:SF32605:number" } // Vorlaufsolltemperatur
Number MODBUS_SF32606 "Room temperatur external [%.1f °C]" <temperature> (gSolarfocus) { channel="modbus:data:solarfocus:sf_holdingreg1:SF32606B:number" } // Raumtemperatur Ist extern
Number MODBUS_SF32607 "Room humidity external [%.0f %%]" <humidity> (gSolarfocus) { channel="modbus:data:solarfocus:sf_holdingreg1:SF32607B:number" } // Raumfeuchte Ist extern
// ########## Holding registers hot water ##########
Number MODBUS_SF32000 "Hot water set-point temperature [%.1f °C]" <temperature> (gSolarfocus) { channel="modbus:data:solarfocus:sf_holdingreg2:SF32000:number" } // Boiler – Solltemperatur
Switch MODBUS_SF32001 "Hot water one-time charge []" <switch> (gSolarfocus) { channel="modbus:data:solarfocus:sf_holdingreg2:SF32001:switch" } // Boiler – Einmalladung
Number MODBUS_SF32002 "Hot water operating mode [MAP(sf-boiler2.map):%s]" <text> (gSolarfocus) { channel="modbus:data:solarfocus:sf_holdingreg2:SF32002:number" } // Boiler – Freigabeart
3. Transformation files
Following you can see the content of the used transformation files. Please note: Most of the map files don’t show all lines. The complete information can be found in the specification document provided by Solarfocus (see References). Please excuse the German language I used here. Please ask Solarfocus for specifications in other languages.
sf-heizkreis1.map
200=Heizkreis ist ausgeschaltet
201=Dauerheizbetrieb
202=Trinkwasserspeichervorrang ist aktiv
203=Dauerabsenkbetrieb
204=Außenfühler Unterbrechung oder Kurzschluss
205…
NULL=undefined
UNDEF=UNDEF
-=no data
=?
sf-puffer.map
200=Puffer ist nicht freigeschaltet
201=Bereitschaft
202=Puffer wird beladen
203=Frostschutzbetrieb
204=Kaminkehrer
205…
NULL=undefined
UNDEF=UNDEF
-=no data
=?
sf-boiler.map
200=Trinkwasserspeicher ist nicht freigeschaltet
201=Bereitschaft
202=Trinkwasserspeicher wird beladen
203=Frostschutzbetrieb
204=Kaminkehrer
205…
NULL=undefined
UNDEF=UNDEF
-=no data
=?
sf-kessel1.map
200=Bereitschaft
201=Zündphase
202=Pelletsbetrieb
203=Kesselsolltemperatur erreicht, Nachlauf
204=Nachlauf
205…
NULL=undefined
UNDEF=UNDEF
-=no data
=?
sf-meldungen1.map
200=OK
201=(1) Bus Unterbrechung
202=(2) Netzsicherung defekt
203=(3) Triac-Sicherung defekt
204=(4) Fehler 24 V DC Versorgung
205…
NULL=undefined
UNDEF=UNDEF
-=no data
=?
sf-kessel2.map
0=Stückholz
1=Stückholz Automatik
2=Stückholz + Pellets
3=Stückholz Automatik + Pellets
4=Pellets
5=Hackgut
NULL=undefined
UNDEF=UNDEF
-=no data
=?
sf-heizkreis2.map
0=Dauerbetrieb
1=Absenkbetrieb
2=Automatik
3=Heizkreis aus (Frostwache)
NULL=undefined
UNDEF=UNDEF
-=no data
=?
sf-boiler2.map
0=Immer Aus
1=Immer Ein
2=Montag – Sonntag
3=Blockweise (Mo-Fr, Sa-So)
4=Tagweise
NULL=undefined
UNDEF=UNDEF
-=no data
=?
Onoff.map
OFF=Off □
ON=On ■
OPEN=open ▯
CLOSED=closed ▮
NULL=undefined
UNDEF=UNDEF
-=no data
=?
conv_divide10.js
(function(inputData) {
// on read: the polled number as string
// on write: openHAB command as string
var DIVIDE_BY = 10;
return parseFloat(inputData) / DIVIDE_BY;
})(input)
conv_multiply10.js
(function(inputData) {
// on read: the polled number as string
// on write: openHAB command as string
var MULTIPLY_BY = 10;
return Math.round(parseFloat(inputData, 10) * MULTIPLY_BY);
})(input)
conv_binary1.js
(function(inputData) {
var out = inputData ; // allow UNDEF to pass through
if (inputData == '1' || inputData == 'ON' || inputData == 'OPEN') {
out = 'ON' ; // change to OFF or OPEN depending on your Item type
} else if (inputData == '0' || inputData == 'OFF' || inputData == 'CLOSED') {
out = 'OFF' ; // in Anführungszeichen!
}
return out ; // return a string
})(input)
conv_binary3.js
(function(inputData) {
var out = inputData ; // allow UNDEF to pass through
if (inputData == '1' || inputData == 'ON' || inputData == 'OPEN') {
out = 'OPEN' ; // change to OFF or OPEN depending on your Item type
} else if (inputData == '0' || inputData == 'OFF' || inputData == 'CLOSED') {
out = 'CLOSED' ; // in Anführungszeichen!
}
return out ; // return a string
})(input)
conv_binary6.js
(function(inputData) {
var out = "" //inputData ; // allow UNDEF to pass through
if (inputData == 'ON' || inputData == '1' || inputData == 'CLOSED') {
out = '1' ; // change to OFF or OPEN depending on your Item type
} else if (inputData == 'OFF' || inputData == '0' || inputData == 'OPEN') {
out = '0' ; // in Anführungszeichen!
}
return out ; // return a string
})(input)
solarfocus.sitemap
sitemap solarfocus label="Solarfocus Biomass Boiler" {
Frame label="Heating circuit" {
Default item=MODBUS_SF1100 // Vorlauftemperatur
Default item=MODBUS_SFHZKURVBERVL // Heizkurve berechn. Vorlauf
Default item=MODBUS_SF1106 // Mischerstellung
Text item=MODBUS_SF1105 label="Heating circuit pump [MAP(onoff.map):%s]" valuecolor=[==OFF="#A4A4A4", ==ON="#A900DB"] labelcolor=[==ON="green"]
Text item=MODBUS_SF1103 label="Limit thermostat [MAP(onoff.map):%s]" valuecolor=[==CLOSED="#A4A4A4", ==OPEN="#A900DB"] labelcolor=[==OPEN="fuchsia"] //visibility=[MODBUS_SF1103 == OPEN]
Default item=MODBUS_SF1107 // Status Heizkreis
}
Frame label="Buffer tank" {
Default item=MODBUS_SF1900 valuecolor=[>=82="red", <40="#1d8dfd"] // Puffertemperatur oben
Default item=MODBUS_SF1901 valuecolor=[>=82="red", <40="#1d8dfd"] // Puffertemperatur unten
Default item=MODBUS_SF1902 valuecolor=[>=82="red", <40="#1d8dfd"] // Puffertemperatur X35
Text item=MODBUS_SF1903 label="Buffer charging pump [MAP(onoff.map):%s]" valuecolor=[==OFF="#A4A4A4", ==ON="#A900DB"] labelcolor=[==ON="green"]
Default item=MODBUS_SF1904 // Pufferstatus
}
Frame label="Hot water" {
Default item=MODBUS_SF500 valuecolor=[>=65="red", <40="#1d8dfd"] // Boiler Temperatur
Default item=MODBUS_SF501 // Boiler Status
}
Frame label="Biomass Boiler" {
Default item=MODBUS_SF2400 valuecolor=[>=82="red", <60="#1d8dfd"] // Kesseltemperatur
Default item=MODBUS_SF2409 // Kesselbetriebsart
Text item=MODBUS_SF2405 label="Front door [MAP(onoff.map):%s]" valuecolor=[==CLOSED="#A4A4A4", ==OPEN="#A900DB"] labelcolor=[==OPEN="green"]
Default item=MODBUS_SF2406 valuecolor=[>=95="red", >=90="orange"] // Kesselreinigung %
Default item=MODBUS_SF2407 valuecolor=[>=95="red", >=90="orange"] // Ascheboxfüllstand
Default item=MODBUS_SF2408 valuecolor=[>=0="red", <0="#1d8dfd"] // Außentemperatur
Default item=MODBUS_SF2404 valuecolor=[==0="green", ==200="green", >=1="red"] // Nachrichtennummer
Default item=MODBUS_SF2401 // Statuszeile Kessel
}
Frame label="Control" {
Setpoint item=MODBUS_SF32603 minValue=0 maxValue=3 step=1 // Heizkreisbetriebsart
Setpoint item=MODBUS_SF32600 minValue=22 maxValue=70 step=1 // Vorlaufsolltemperatur
Setpoint item=MODBUS_SF32605 minValue=5 maxValue=45 step=1 // Raumtemperatur Soll
Setpoint item=MODBUS_SF32002 minValue=0 maxValue=4 step=1 // Boiler – Freigabeart
Setpoint item=MODBUS_SF32000 minValue=20 maxValue=65 step=0.5 // Boiler – Solltemperatur
Default item=MODBUS_SF32001 // Boiler – Einmalladung
}
Frame label="External Room sensor" {
Default item=MODBUS_SF32606 // Raumtemperatur Ist extern
Default item=MODBUS_SF32607 //Raumfeuchte Ist extern
}
}
4. The result (basicui)
5. References