Hallo zusammen,
Vielleicht hat ja hier auch jemand eine Lüftungsanlage WAC350 oder 351 von Westaflex.
Hier nun mein Projekt:
"KWL WAC350/351 Westaflex via ModBus in OpenHab"
Benötigte Hardware:
Raspberry b3+
RS485 Shield: https://www.hwhardsoft.de/deutsch/pr.../rs485-shield/
Rj11-RJ45 Adapter: https://www.kab24.de/kommunikation/k...che=1553093850
image_80993.png
Ein großes Dankeschön geht in erste Linie an rossko57 vom Englischen OpenHab Forum. Er hat hier als "Ghostwriter" für mich fungiert.
Da ich zunächst alles über die PaperUI erstellt hatte, habe ich rossko57 meine Files aus der RestAPI zur Verfügung gestellt.
Den Original Thread findet Ihr übrigens hier: https://community.openhab.org/t/setu...lex-hvac/70573
Des weiteren möchte ich Udo, Madmike, und PeterPan für die Unterstützung an vielen Stellen Danken!
Here we describe how to use Modbus binding 2.x to allow openHAB to interact with a Westaflex WAC350 aircon, other models are probably similar.
WAC350 provides a serial port, so you’d probably use an RS485 USB dongle on your OH host, or an RS485 shield, then connect with twisted pair cable and RJ45 connector. For a long cable run, you may need to arrange a terminator resistor for your RS485 cable.
RJ45 Port 1 on the unit is reserved for the ‘FLEX’ controller panel, Port 2 is the one for external systems like openHAB, these are separate serial buses.
Follow the WAC manual to set up Port 2 serial parameters – typically 19200 baud, no parity, slave ID 1
We’ll also need to know the Modbus register map for this device, as found in the manual.
Screenshot_p19.jpeg
Here the complete ModBus Adresslist: https://drive.google.com/open?id=1iU...pYsr50DvMpvutZ
The WAC350 has several read-only ‘coils’ for binary signals, some writeable coils for control,
read-only ‘input’ registers for numeric sensing, and writeable ‘holding’ registers for control.
That’s all we need to know to set up Modbus binding.
In this example we only use a few of the available registers.
We need to set up Things for the Modbus binding. A serial Bridge thing to define the basic slave, and poller Bridge things for each group of registers we want to access. Finally data Things that describe how to interpret each register.
You have a choice; you may add Things using PaperUI and edit parameters onscreen, for the OH system to save in its database.
Or you may add Things via a text file with your editor, say wac350.things. (You can also view these, but not edit, in PaperUI.)
Don’t try to mix these methods.
I’m going to list settings in the xxx.things style, as it’s more compact than providing a lot of PaperUI screenshots.
westaflex.things:
Notice that some of the data Things use a read transform: some Westaflex registers contain e.g. 195 representing 19.5 degrees, so we tell the binding to use a little javascript to do the division as the binding updates the Item.
You will need to make sure the transformation service is installed in OH, and then create this file and put it in/conf/transform/
divide10.js:
Creating the data Things automatically makes various channels available for your Items.
At this stage, you should be polling your Westaflex over Modbus error free.
To make the data available to openHAB rules and Uis, you must link Items to the Modbus channels.
westaflex.items:
The following Items are not linked to Modbus, may be useful in rules
westaflexplus.items:
Some rule samples, to control your HVAC
westaflex.rules:
Here comes a another rule for having a reminder to change the filters inside the unit:
filtertimer.rules:
Und hier ein Auszug aus meiner Sitemap:
Screenshots der Sitemap:
Sitemap1.png
Sitemap2.png
Sitemap3.png
Viel Spass damit!
Vielleicht hat ja hier auch jemand eine Lüftungsanlage WAC350 oder 351 von Westaflex.
Hier nun mein Projekt:
"KWL WAC350/351 Westaflex via ModBus in OpenHab"
Benötigte Hardware:
Raspberry b3+
RS485 Shield: https://www.hwhardsoft.de/deutsch/pr.../rs485-shield/
Rj11-RJ45 Adapter: https://www.kab24.de/kommunikation/k...che=1553093850
image_80993.png
Ein großes Dankeschön geht in erste Linie an rossko57 vom Englischen OpenHab Forum. Er hat hier als "Ghostwriter" für mich fungiert.
Da ich zunächst alles über die PaperUI erstellt hatte, habe ich rossko57 meine Files aus der RestAPI zur Verfügung gestellt.
Den Original Thread findet Ihr übrigens hier: https://community.openhab.org/t/setu...lex-hvac/70573
Des weiteren möchte ich Udo, Madmike, und PeterPan für die Unterstützung an vielen Stellen Danken!
Here we describe how to use Modbus binding 2.x to allow openHAB to interact with a Westaflex WAC350 aircon, other models are probably similar.
WAC350 provides a serial port, so you’d probably use an RS485 USB dongle on your OH host, or an RS485 shield, then connect with twisted pair cable and RJ45 connector. For a long cable run, you may need to arrange a terminator resistor for your RS485 cable.
RJ45 Port 1 on the unit is reserved for the ‘FLEX’ controller panel, Port 2 is the one for external systems like openHAB, these are separate serial buses.
Follow the WAC manual to set up Port 2 serial parameters – typically 19200 baud, no parity, slave ID 1
We’ll also need to know the Modbus register map for this device, as found in the manual.
Screenshot_p19.jpeg
Here the complete ModBus Adresslist: https://drive.google.com/open?id=1iU...pYsr50DvMpvutZ
The WAC350 has several read-only ‘coils’ for binary signals, some writeable coils for control,
read-only ‘input’ registers for numeric sensing, and writeable ‘holding’ registers for control.
That’s all we need to know to set up Modbus binding.
In this example we only use a few of the available registers.
We need to set up Things for the Modbus binding. A serial Bridge thing to define the basic slave, and poller Bridge things for each group of registers we want to access. Finally data Things that describe how to interpret each register.
You have a choice; you may add Things using PaperUI and edit parameters onscreen, for the OH system to save in its database.
Or you may add Things via a text file with your editor, say wac350.things. (You can also view these, but not edit, in PaperUI.)
Don’t try to mix these methods.
I’m going to list settings in the xxx.things style, as it’s more compact than providing a lot of PaperUI screenshots.
westaflex.things:
Code:
// define the serial path to Westaflex Bridge modbus:serial:wac350 [ port="/dev/ttyS0", baud=19200, stopBits="1.0", parity="none", dataBits=8, encoding="rtu" ] { // define a block of coils to read Bridge poller wcoil [ start=17 length=1 refresh=10000 type="coil" ] { // selected coils of interest Thing data wc17 [ readStart="17", readValueType="bit", writeStart="17", writeType="coil" ] } // define block of inputs to read Bridge poller winputA [ start=0 length=10 refresh=5000 type="input" ] { // selected input reg Thing data wi00 [ readStart="0", readValueType="int16", readTransform="JS(divide10.js)" ] Thing data wi03 [ readStart="3", readValueType="int16", readTransform="JS(divide10.js)" ] Thing data wi06 [ readStart="6", readValueType="int16", readTransform="JS(divide10.js)" ] Thing data wi09 [ readStart="9", readValueType="int16", readTransform="JS(divide10.js)" ] } // define another block of inputs to read Bridge poller winputB [ start=12 length=5 refresh=5000 type="input" ] { Thing data wi13 [ readStart="13", readValueType="int16" ] Thing data wi14 [ readStart="14", readValueType="int16" ] Thing data wi15 [ readStart="15", readValueType="int16" ] Thing data wi16 [ readStart="16", readValueType="int16" ] } // define block of holdings to read/write Bridge poller wholdA [ start=0 length=2 refresh=10000 type="holding" ] { Thing data wh00 [ readStart="0", readValueType="int16", writeStart="0", writeValueType="int16", writeType="holding" ] Thing data wh01 [ readStart="1", readValueType="int16", writeStart="1", writeValueType="int16", writeType="holding" ] } // define another block of holdings to read/write Bridge poller wholdB [ start=300 length=10 refresh=10000 type="holding" ] { Thing data wh305 [ readStart="305", readValueType="uint16" ] } }
You will need to make sure the transformation service is installed in OH, and then create this file and put it in/conf/transform/
divide10.js:
Code:
// Wrap everything in a function (no global variable pollution) (function(inputData) { // on read: the polled number as string return parseFloat(inputData) / 10; })(input)
At this stage, you should be polling your Westaflex over Modbus error free.
To make the data available to openHAB rules and Uis, you must link Items to the Modbus channels.
westaflex.items:
Code:
Group WAC350_Sensors "Westaflex sensors" Number Zuluft "Zuluft [%.0f]" (WAC350_Sensors) { channel="modbus:data:winputA:wi00:number" } Number Abluft "Abluft [%.0f]" (WAC350_Sensors) { channel="modbus:data:winputA:wi03:number" } Number Fort_Luft "Fortluft [%.0f]" (WAC350_Sensors) { channel="modbus:data:winputA:wi06:number" } Number Aussenluft "Aussenluft [%.0f]" (WAC350_Sensors) { channel="modbus:data:winputA:wi09:number" } Number Abluftfeuchte "Abluftfeuchte [%.0f]" (WAC350_Sensors) { channel="modbus:data:winputB:wi13:number" } Number Bypassklappe "Bypassklappe [%.0f]" (WAC350_Sensors) { channel="modbus:data:winputB:wi14:number" } Number Luefter1 "Luefter1 [%.0f]" (WAC350_Sensors) { channel="modbus:data:winputB:wi15:number" } Number Luefter2 "Luefter2 [%.0f]" (WAC350_Sensors) { channel="modbus:data:winputB:wi16:number" } Number LuefterStufe "LuefterStufe [%.0f]" (WAC350_Sensors) { channel="modbus:data:wholdA:wh00:number" } Number ZuluftTempSet "Solltemperatur [%.0f]" (WAC350_Sensors) { channel="modbus:data:wholdA:wh01:number" } Number FilterTimer "Filter Timer [%.0f]" { channel="modbus:data:wholdB:wh305:number" } Switch FanStandby_Switch "FanStandby_Switch" { channel="modbus:data:wcoil:wc17:switch" }
westaflexplus.items:
Code:
// additional Items for rules // for calculated efficiency Number Wirkungsgrad "Wirkungsgrad" (WAC350_Sensors) // set your outdoor temp limits and a control Switch Lueftung_min_max_Temp "Lueftung_min_max_Temp" Number:Temperature AussenGrenzMax_Set "AussenGrenzMax_Set" Number:Temperature AussenGrenzMin_Set "AussenGrenzMin_Set" // set your timer controls Switch WAC350_Zeitschaltung_01 Switch WAC350_Zeitschaltung_02 // timer hours and mins controls Number Deko_WECKER_H "Start Stunde [%s]" Number Deko_WECKER_M "Start Minute [%s]" Number Deko_WECKER_Ho "Start Stunde [%s]" Number Deko_WECKER_Mo "Start Minute [%s]"
westaflex.rules:
Code:
// Beginn der Datei // globale Variablen var Long lLStufe var Timer Deko = null rule "Aussenluft manuell" when Item AussenTemp changed // your outdoor temp sensor then if(Lueftung_min_max_Temp.state != ON) return; // wenn Schalter aus(nicht an) , keine Aktionen if(!(AussenTemp.state instanceof Number)) { logWarn("Lüftung manuell", "AussenTemp.state not a Number: {}",AussenTemp.state) // numerisch ? return; } if (AussenTemp.state >= AussenGrenzMax_Set.state && FanStandby_Switch.state != OFF) { // above max limit FanStandby_Switch.sendCommand(ON) logInfo("Lüftung manuell", "LuefterStufe ist jetzt: {} AussenTemp beträgt {}",LuefterStufe.state,AussenTemp.state ) } else if (AussenTemp.state <= AussenGrenzMin_Set.state && FanStandby_Switch.state != ON) { // below min limit FanStandby_Switch.sendCommand(OFF) logInfo("Lüftung manuell", "LuefterStufe ist jetzt: {} AussenTemp beträgt {}",LuefterStufe.state,AussenTemp.state) } end rule "luefter geändert" when Item LuefterStufe changed then lLStufe = now.millis end rule "berechne Wirkungsgrad" // calculate efficiency when Item Abluft changed or Item Zuluft changed or Item Aussenluft changed then if(lLStufe + 15*60*1000 < now.millis && LuefterStufe.state.toString != "0"){ //Lüfter läuft bereits mindestens 15 Minuten auf der aktuellen Stufe if(!(Abluft.state instanceof Number)) { logWarn("Wirkungsgrad", "Abluft.state not a Number: {}",Abluft.state) return; } if(!(Zuluft.state instanceof Number)) { logWarn("Wirkungsgrad", "Zuluft.state not a Number: {}",Zuluft.state) return; } if(!(Aussenluft.state instanceof Number)) { logWarn("Wirkungsgrad", "Aussenluft.state not a Number: {}", Aussenluft.state) return; } val Number Aussenluft = (Aussenluft.state as Number) val Number nDivisor = (Abluft.state as Number) - Aussenluft //Wert fuer Berechung gem. Westaflex val Number nFaktor = (Zuluft.state as Number) - Aussenluft //Wert fuer Berechung gem. Westaflex if(nDivisor == 0) { logWarn("Wirkungsgrad", "Aussentemperatur = Ablufttemperatur, Division durch 0!") Wirkungsgrad.postUpdate(NULL) } else Wirkungsgrad.postUpdate((100*nFaktor/nDivisor).intValue) //Berechung gem. Westaflex } end rule "Wecker Deko" when Time cron "0 * * * * ?" //Abfrage jede Minute then if(WAC350_Zeitschaltung_01.state == ON) { var sollMinute = (Deko_WECKER_M.state as DecimalType).intValue var sollStunde = (Deko_WECKER_H.state as DecimalType).intValue var sollMinuteo = (Deko_WECKER_Mo.state as DecimalType).intValue var sollStundeo = (Deko_WECKER_Ho.state as DecimalType).intValue if (sollMinute == now.getMinuteOfHour && sollStunde == now.getHourOfDay) { LuefterStufe.sendCommand(1) } else if (sollMinuteo == now.getMinuteOfHour && sollStundeo == now.getHourOfDay) { LuefterStufe.sendCommand(0) } } if(WAC350_Zeitschaltung_02.state == ON) { var sollMinute = (Deko_WECKER_Ma.state as DecimalType).intValue var sollStunde = (Deko_WECKER_Ha.state as DecimalType).intValue var sollMinuteo = (Deko_WECKER_Maa.state as DecimalType).intValue var sollStundeo = (Deko_WECKER_Haa.state as DecimalType).intValue if (sollMinute == now.getMinuteOfHour && sollStunde == now.getHourOfDay) { LuefterStufe.sendCommand(2) } else if (sollMinuteo == now.getMinuteOfHour && sollStundeo == now.getHourOfDay) { LuefterStufe.sendCommand(1) } } end
filtertimer.rules:
Code:
// globale Variablen müssen zu Beginn der rules Datei deklariert werden! var Timer tFilter = null rule "Filterwarnung" when Item FilterTimer changed then if(tFilter === null && (FilterTimer.state >2000 )) { tFilter = createTimer(now.plusHours(12), [ | tFilter = null ]) sendBroadcastNotification("Erinnerung !! Filterwechsel bei 2160h! Aktueller Wert "+FilterTimer.state.toString+"h") //Allgemeine Warnung an alle } end
Code:
Switch item=FanStandby_Switch label="Lüftung Standby" icon="switch" Text label="Lüftung manuell" icon="flow" { Switch item=Lueftung_min_max_Temp label="Lüftung manuell" icon="switch" Text item=AussenTemp label="AussenTemp aktuell [%.1f °C]" icon="temperature" valuecolor=[>27="red",>20="orange",>10="purple",>5="green",<=5="blue"] Setpoint item=AussenGrenzMax_Set label="AussenTemp Lüftung Stop [%.1f °C]" icon="temperature" minValue=15 maxValue=24 step=0.5 Setpoint item=AussenGrenzMin_Set label="AussenTemp Lüftung Start [%.1f °C]" icon="temperature" minValue=13 maxValue=20 step=0.5 } Text item=Lueftung_min_max_Temp label="Lüftung manuell ist Aktiv" icon="switch" visibility=[Lueftung_min_max_Temp==ON] Text label="Zeitschaltuhr" icon="time" { Switch item=WAC350_Zeitschaltung_01 label="Stufe: Stop/Klein" icon="time" mappings=[ON="Timer an", OFF="Timer aus"] Setpoint item=Deko_WECKER_H minValue=0 maxValue=23 step=1 Setpoint item=Deko_WECKER_M minValue=0 maxValue=59 step=1 Setpoint item=Deko_WECKER_Ho minValue=0 maxValue=23 step=1 Setpoint item=Deko_WECKER_Mo minValue=0 maxValue=59 step=1 Selection item=LuefterStufe label="Lüfterstufe" icon="fan" mappings=[0="Stopp", 1="Klein", 2="Mittel", 3="Hoch"] Switch item=WAC350_Zeitschaltung_02 label="Stufe: Mittel/Klein" icon="time" mappings=[ON="Timer an", OFF="Timer aus"] Setpoint item=Deko_WECKER_Ha minValue=0 maxValue=23 step=1 Setpoint item=Deko_WECKER_Ma minValue=0 maxValue=59 step=1 Setpoint item=Deko_WECKER_Haa minValue=0 maxValue=23 step=1 Setpoint item=Deko_WECKER_Maa minValue=0 maxValue=59 step=1 } Text item=WAC350_Zeitschaltung_01 label="Zeitschaltuhr Stop-Klein ist AKTIV" icon="time" visibility=[WAC350_Zeitschaltung_01==ON] Text item=WAC350_Zeitschaltung_02 label="Zeitschaltuhr Mittel-Klein ist AKTIV" icon="time" visibility=[WAC350_Zeitschaltung_02==ON] Selection item=LuefterStufe label="Lüfterstufe" icon="fan" mappings=[0="Stopp", 1="Klein", 2="Mittel", 3="Hoch"] Setpoint item=ZuluftTempSet label="Solltemperatur [%.1f °C]" icon="temperature" minValue=15 maxValue=25 step=1 Text item=Luefter1 label="Lüfter 1 Drehzahl [%s %%]" icon="fan" Text item=Luefter2 label="Lüfter 2 Drehzahl [%s %%]" icon="fan" Text item=Abluft label="Abluft aktuell [%.1f °C]" icon="temperature" valuecolor=[>27="red",>20="orange",>10="purple",>5="green",<=5="blue"] Text item=Zuluft label="Zuluft aktuell [%.1f °C]" icon="temperature" valuecolor=[>27="red",>20="orange",>10="purple",>5="green",<=5="blue"] Text item=Aussenluft label="Aussenluft aktuell [%.1f °C]" icon="temperature" valuecolor=[>27="red",>20="orange",>10="purple",>5="green",<=5="blue"] Text item=Fort_Luft label="Fortluft aktuell [%.1f °C]" icon="temperature" valuecolor=[>27="red",>20="orange",>10="purple",>5="green",<=5="blue"] Text item=Abluftfeuchte label="Abluftfeuchte aktuell [%s %%]" icon="humidity" valuecolor=[>70="red",>60="orange",>50="purple",>35="green",<=25="blue"] Text item=Wirkungsgrad label="Wirkungsgrad aktuell [%s %%]" icon="qualityofservice" Text item=Bypassklappe label="Bypass: [MAP(de.map):%s]" icon="switch" Text item=FilterTimer label="Filtertimer [%s h]" icon="time" valuecolor=[>2159="red",>2000="orange",>0="green"] Text label="Filter tauschen bei 2160h!" icon="error" visibility=[FilterTimer>=2000] Switch item=FiltertimerReset label="Reset Filtertimer" icon="error" visibility=[FilterTimer>=2000,FilterTimer==0]
Sitemap1.png
Sitemap2.png
Sitemap3.png
Viel Spass damit!