This is an alternative solution to the ComfoAir binding which uses a serial port.
I preferred to have the ComoAir directly controlled via the KNX bus and thus I bought the Zehnder ComfoConnect KNX C.
I am sharing my items and sitemap configuration, maybe its useful to other openHABeners:
Sitemap integration:
Text item=Lueftung_Airflow_Msg icon="fan" label="Lüftung "{
Frame label="Control" {
Switch item=Lueftung_Auto_Mode label="Automatik"
Setpoint item=Lueftung_Fan_Level step=1 minValue=0 maxValue=4
Switch item=Lueftung_Temperature_profile_mode label="temperature profile mode" mappings=[0=adaptiv, 1=fest, 2=setpoint]
Switch item=Lueftung_Temperature_profile label="temperature profile" mappings=[0=normal, 1=cool, 2=warm]
Setpoint item=Lueftung_Temperature_set_point minValue=16 maxValue=24 step=0.5
Switch item=Lueftung_Chart_Period label="Chart Period" icon="chart" mappings=[0="Hour", 1="Day", 2="Week"]
}
Frame label="Status" {
Text item=Lueftung_Filterwechsel_Msg
Text item=Lueftung_Airflow_Msg
Text item=Lueftung_Status_Msg
Text item=Lueftung_StatusErr_Msg
Chart item=gLueftung_Chart_Airflow period=h refresh=600 visibility=[Lueftung_Chart_Period==0, Lueftung_Chart_Period=="NULL"]
Chart item=gLueftung_Chart_Airflow period=D refresh=3600 visibility=[Lueftung_Chart_Period==1]
Chart item=gLueftung_Chart_Airflow period=W refresh=3600 visibility=[Lueftung_Chart_Period==2]
}
Frame label="Temperature" {
Text item=Lueftung_Temperatur_Extract_Msg
Text item=Lueftung_Temperatur_Exhaust_Msg
Text item=Lueftung_Temperatur_Outdoor_Msg
Text item=Lueftung_Temperatur_Supply_Msg
}
Frame label="Humidity" {
Text item=Lueftung_Humidity_Extract_Msg
Text item=Lueftung_Humidity_Exhaust_Msg
Text item=Lueftung_Humidity_Outdoor_Msg
Text item=Lueftung_Humidity_Supply_Msg
Chart item=gLueftung_Chart_Humidity period=h refresh=600 visibility=[Lueftung_Chart_Period==0, Lueftung_Chart_Period=="NULL"]
Chart item=gLueftung_Chart_Humidity period=D refresh=3600 visibility=[Lueftung_Chart_Period==1]
Chart item=gLueftung_Chart_Humidity period=W refresh=3600 visibility=[Lueftung_Chart_Period==2]
}
}
Items:
Group gLueftung "Lüftungsanlage" <pie>
Group gLueftung_Chart_Airflow
Group gLueftung_Chart_Humidity
Number Lueftung_Chart_Period "Chart Period"
Switch Lueftung_Auto_Mode "Auto Modus" (gLueftung) { knx="1.003:30/1/0+<1.003:30/1/1" }
String Lueftung_Filterwechsel_Msg "Filtertausch [%s]" <clock> (gLueftung)
String Lueftung_Airflow_Msg "Airflow [%s]" <fan> (gLueftung)
String Lueftung_Status_Msg "Status [%s]" <settings> (gLueftung)
String Lueftung_StatusErr_Msg "Error Status [%s]" <settings> (gLueftung)
String Lueftung_Temperatur_Room_Msg "Room [%s]" <temperature> (gLueftung)
String Lueftung_Temperatur_Extract_Msg "Extract [%s]" <temperature> (gLueftung)
String Lueftung_Temperatur_Exhaust_Msg "Exhaust [%s]" <temperature> (gLueftung)
String Lueftung_Temperatur_Outdoor_Msg "Outdoor [%s]" <temperature> (gLueftung)
String Lueftung_Temperatur_Supply_Msg "Supply [%s]" <temperature> (gLueftung)
String Lueftung_Humidity_Room_Msg "Room [%s]" <humidity> (gLueftung)
String Lueftung_Humidity_Extract_Msg "Extract [%s]" <humidity> (gLueftung)
String Lueftung_Humidity_Exhaust_Msg "Exhaust [%s]" <humidity> (gLueftung)
String Lueftung_Humidity_Outdoor_Msg "Outdoor [%s]" <humidity> (gLueftung)
String Lueftung_Humidity_Supply_Msg "Supply [%s]" <humidity> (gLueftung)
//Number Lueftung_Control "Steuerung" <settings> (gLueftung) {comfoair="activate"}
//Number Lueftung_Komfortemperatur "Zieltemperatur [%.1f °C]" <temperature> (gLueftung) {comfoair="target_temperatur"}
//Number Lueftung_Bypass "Bypass [MAP(bypass_de.map):%s]" <selfBypass> (gLueftung) {comfoair="bypass_mode"}
Number Lueftung_Fan_Level "Stufe [%d]" <fan> (gLueftung) { knx="5.010:30/1/2+<5.010:30/1/3"}
Number Lueftung_Airflow "Airflow [%d h]" (gLueftung, gLueftung_Chart_Airflow) { autoupdate="true", knx="<(10)13.002:30/1/4" }
Number Lueftung_Filterwechsel "Filterwechsel [%d h]" (gLueftung) { autoupdate="true", knx="<(300)7.007:30/1/5" }
Number Lueftung_Status "Status [%d]" (gLueftung) { autoupdate="true", knx="<(300)5.001:30/1/7" }
Number Lueftung_Temperature_profile_mode "Temperatur profile mode" <settings> (gLueftung) { knx="5.010:30/1/8+<5.010:30/1/9" }
Number Lueftung_Temperature_profile "Temperatur profile" <settings> (gLueftung) { knx="5.010:30/1/10+<5.010:30/1/11" }
Number Lueftung_Temperature_set_point "Temperatur [%.1f]" <temperature> (gLueftung) { knx="30/1/12+<30/1/13" }
//Switch Lueftung_StatusErr "Error Status [%d]" (gLueftung) { autoupdate="true", knx="<(30)1.003:30/1/6" }
Number Lueftung_Temperatur_Room "Room [%.1f °C]" (gLueftung) { autoupdate="true", knx="<(100)30/1/20" }
Number Lueftung_Temperatur_Extract "Extract [%.1f °C]" (gLueftung) { autoupdate="true", knx="<(100)30/1/21" }
Number Lueftung_Temperatur_Exhaust "Exhaust [%.1f °C]" (gLueftung) { autoupdate="true", knx="<(100)30/1/22" }
Number Lueftung_Temperatur_Outdoor "Outdoor [%.1f °C]" (gLueftung) { autoupdate="true", knx="<(100)30/1/23" }
Number Lueftung_Temperatur_Supply "Supply [%.1f °C]" (gLueftung) { autoupdate="true", knx="<(100)30/1/24" }
Number Lueftung_Humidity_Room "Room [%d %%]" (gLueftung) { autoupdate="true", knx="<(100)5.001:30/1/30" }
Number Lueftung_Humidity_Extract "Extract [%d %%]" (gLueftung, gLueftung_Chart_Humidity) { autoupdate="true", knx="<(100)5.001:30/1/31" }
Number Lueftung_Humidity_Exhaust "Exhaust [%d %%]" (gLueftung) { autoupdate="true", knx="<(100)5.001:30/1/32" }
Number Lueftung_Humidity_Outdoor "Outdoor [%d %%]" (gLueftung) { autoupdate="true", knx="<(100)5.001:30/1/33" }
Number Lueftung_Humidity_Supply "Supply [%d %%]" (gLueftung, gLueftung_Chart_Humidity) { autoupdate="true", knx="<(100)5.001:30/1/34" }
rules:
import org.openhab.core.library.types.*
import org.openhab.core.persistence.*
import org.openhab.model.script.actions.*
import java.lang.Math
var boolean autoChangeInProgress = false
rule "Airflow Message"
when
System started
or
Item Lueftung_Airflow changed
then
if( (Lueftung_Airflow.state instanceof DecimalType) ){
var String msg = Lueftung_Airflow.state.format("%d") + " m" + "\u00b3" +"/h"
postUpdate(Lueftung_Airflow_Msg,msg)
}
end
rule "Filterwechsel Message"
when
System started
or
Item Lueftung_Filterwechsel changed
then
if( (Lueftung_Filterwechsel.state instanceof DecimalType) ){
var Number Filterwechsel = Lueftung_Filterwechsel.state as DecimalType
var Number days = Filterwechsel/24
var String msg = days.intValue + " Tage"
postUpdate(Lueftung_Filterwechsel_Msg, msg)
}
end
rule "Status and Error Status Message"
when
System started
or
Item Lueftung_Status changed
or
Item Lueftung_StatusErr received update
then
if( (Lueftung_Status.state instanceof DecimalType) ){
var Number Status = Lueftung_Status.state as DecimalType
if (Status.intValue == 0) {
postUpdate(Lueftung_Status_Msg, "ok, Status: " + Status.intValue)
} else {
postUpdate(Lueftung_Status_Msg, "Not ok check ComfoConnect KNX C manual, status val: " + Status.intValue)
}
}
// if ( (Lueftung_StatusErr.state instanceof DecimalType) ){
// var Number StatusErr = Lueftung_StatusErr.state as DecimalType
// if (StatusErr.intValue == 0) {
// postUpdate(Lueftung_StatusErr_Msg, "no Error")
// } else {
// postUpdate(Lueftung_StatusErr_Msg, "Error: check ComfoConnect KNX C manual, status val: " + StatusErr.intValue )
// }
// }
end
rule "Temperature Message"
when
System started
or
Item Lueftung_Temperatur_Room changed
or
Item Lueftung_Temperatur_Extract changed
or
Item Lueftung_Temperatur_Exhaust changed
or
Item Lueftung_Temperatur_Outdoor changed
or
Item Lueftung_Temperatur_Supply changed
then
if( (Lueftung_Temperatur_Room.state instanceof DecimalType) ){
postUpdate(Lueftung_Temperatur_Room_Msg, Lueftung_Temperatur_Room.state.format("%.1f") + "°C")
}
if( (Lueftung_Temperatur_Extract.state instanceof DecimalType) ){
postUpdate(Lueftung_Temperatur_Extract_Msg, Lueftung_Temperatur_Extract.state.format("%.1f") + "°C")
}
if( (Lueftung_Temperatur_Exhaust.state instanceof DecimalType) ){
postUpdate(Lueftung_Temperatur_Exhaust_Msg, Lueftung_Temperatur_Exhaust.state.format("%.1f") + "°C")
}
if( (Lueftung_Temperatur_Outdoor.state instanceof DecimalType) ){
postUpdate(Lueftung_Temperatur_Outdoor_Msg, Lueftung_Temperatur_Outdoor.state.format("%.1f") + "°C")
}
if( (Lueftung_Temperatur_Supply.state instanceof DecimalType) ){
postUpdate(Lueftung_Temperatur_Supply_Msg, Lueftung_Temperatur_Supply.state.format("%.1f") + "°C")
}
end
rule "Humidity Message"
when
System started
or
Item Lueftung_Humidity_Room changed
or
Item Lueftung_Humidity_Extract changed
or
Item Lueftung_Humidity_Exhaust changed
or
Item Lueftung_Humidity_Outdoor changed
or
Item Lueftung_Humidity_Supply changed
then
if( (Lueftung_Humidity_Room.state instanceof DecimalType) ){
postUpdate(Lueftung_Humidity_Room_Msg, Lueftung_Humidity_Room.state.format("%d") + "%")
}
if( (Lueftung_Humidity_Extract.state instanceof DecimalType) ){
postUpdate(Lueftung_Humidity_Extract_Msg, Lueftung_Humidity_Extract.state.format("%d") + "%")
}
if( (Lueftung_Humidity_Exhaust.state instanceof DecimalType) ){
postUpdate(Lueftung_Humidity_Exhaust_Msg, Lueftung_Humidity_Exhaust.state.format("%d") + "%")
}
if( (Lueftung_Humidity_Outdoor.state instanceof DecimalType) ){
postUpdate(Lueftung_Humidity_Outdoor_Msg, Lueftung_Humidity_Outdoor.state.format("%d") + "%")
}
if( (Lueftung_Humidity_Supply.state instanceof DecimalType) ){
postUpdate(Lueftung_Humidity_Supply_Msg, Lueftung_Humidity_Supply.state.format("%d") + "%")
}
end
/*
rule "Filterlaufzeit"
when
System started
or
Item Lueftung_Filterlaufzeit changed
then
if( Lueftung_Filterlaufzeit.state instanceof DecimalType ){
var Number laufzeit = Lueftung_Filterlaufzeit.state as DecimalType
var Number weeks = Math::floor( (laufzeit/168).doubleValue )
var Number days = Math::floor( ((laufzeit-(weeks*168))/24).doubleValue)
var String msg = ""
if( weeks > 0 ){
if( weeks == 1 ) msg = weeks.intValue + " Woche"
else msg = weeks.intValue + " Wochen"
}
if( days > 0 ){
if( msg.length > 0 ) msg = msg + ", "
if( days == 1 ) msg = msg + days.intValue + " Tag"
else msg = msg + days.intValue + " Tage"
}
postUpdate(Lueftung_Filterlaufzeit_Message,msg)
}
end
persistence config:
Strategies {
// for rrd charts, we need a cron strategy
everyMinute : "0 * * * * ?"
}
Items {
DemoSwitch,NoOfLights,Window_GF_Toilet,Heating* : strategy = everyChange, everyMinute, restoreOnStartup
// let's only store temperature values in rrd
Temperature*,Weather_Chart* : strategy = everyMinute, restoreOnStartup
Heizung_Chart* : strategy = everyMinute, restoreOnStartup
Lueftung_Airflow, Lueftung_Humidity_Extract, Lueftung_Humidity_Supply: strategy = everyMinute, restoreOnStartup
gLueftung_Chart_Airflow, gLueftung_Chart_Humidity : strategy = everyMinute, restoreOnStartup
SMA_TotalPac : strategy = everyMinute, restoreOnStartup
gSMA_Chart : strategy = everyMinute, restoreOnStartup
}
Hints or ideas to improve the setup are very welcome.