KNX in Eigenregie mit dem Arduino
Jetzt gibt es für KNX tausende von fertigen Komponenten, welche man einfach kaufen und hinzufügen kann. Wie genau das geht und wie diese mit der ETS verknüpft werden, habe ich bereits in einer mehrteiligen Reihe gezeigt. Leider sind einige Komponenten für KNX extrem teuer, obwohl der Leistungsumfang gar nicht so super mächtig ist. Um mir mal ein Beispiel rauszusuchen, habe ich einen CO2-Sensor gewählt. Von MDT liegt so eine Lösung bei über 180 Euro, Gira ruft sogar über 220 Euro aktuell dafür auf. Das sind natürlich extreme Preise. Und da habe ich mich gefragt (wie schon viele vor mir auch): Geht das nicht in Eigenregie ein wenig günstiger? Und genau da kommt der Arudino ins Spiel.
Die kleinen Mikrocontroller sind perfekt geeignet, um die verschiedensten Sensoren und Aktoren anschließen zu können. Für die meisten Komponenten gibt es fertige Libraries (Bibliotheken), sodass man diese mit wenigen Zeilen Code bereits nutzen kann. I2C, SPI, CAN und andere Systeme können ebenfalls angesprochen werden. Also müsste man doch auch eine Schnittstelle zu KNX schaffen können, oder? Ja! Allerdings nicht einfach so. Wir brauchen noch ein Gerät, welches die Vermittlung zum KNX-Bus für uns übernimmt. Dafür nehmen wir einen Buskoppler von Siemens - soweit ich weiß, muss auch genau dieses Modell sein. Und damit haben wir auch schon alles zusammen, was wir für die ersten eigenen KNX-Komponenten brauchen.
Video
Produkte
- MHZ19 CO2-Sensor: Amazon **, Ali Express **
- Arduino Pro Micro 5V: Amazon **, Ali Express **
- MP1584 DC-DC Converter: Amazon **, Ali Express **
- Kondensator 25V 2200µF: Amazon **, Ali Express **
- Kondensator 6,3V 1000µF: Amazon **, Ali Express **
Busankoppler
Der KNX-Busankoppler ** hat insgesamt 10 Pins (2x5), von welchen insgesamt 7 belegt sind. Die genaue Belegung habe ich hier für Dich aufbereitet:
»KNX-Busankoppler Pinout«
Bitte nicht wundern, dass ich die Pins anders nummeriert habe als in den offiziellen Dokumenten von Siemens. Das war nötig, damit sich diese mit den Pin-Nummern in KiCad auf meinen Platinen decken.
Code und Schaltpläne
Teil 1
»KNX-Busankoppler am Arduino«
Als erstes muss die folgende Library eingebunden werden:
Erster Test: Sende alle 5 Sekunden auf “Ein” auf die Gruppenadresse 31/1/1.
#include <Arduino.h>
#include <KnxTpUart.h>
KnxTpUart knx(&Serial1, "1.1.25");
void setup() {
Serial1.begin(19200, SERIAL_8E1);
knx.uartReset();
}
void loop() {
bool success = knx.groupWriteBool("31/1/1", true);
delay(5000);
}
Teil 2
»KNX-Busankoppler mit CO2-Sensor am Arduino«
Für den zweiten Test brauchen wir die MHZ-19 Library. Hier habe ich den KNX-Teil noch einmal auskommentiert, damit wir uns erstmal auf das Auslesen der Werte vom Sensor konzentrieren können. Sobald beides funktioniert wird die Verknüpfung von Sensor und KNX im Code hergestellt.
Dafür muss zusätzlich noch diese Library eingebunden werden
#include <Arduino.h>
#include <KnxTpUart.h>
#include <MHZ19.h>
//KnxTpUart knx(&Serial1, "1.1.25");
MHZ19 mhz19;
void setup() {
Serial.begin(9600);
// Serial1.begin(19200, SERIAL_8E1);
// knx.uartReset();
mhz19.begin(8, 9);
mhz19.setAutoCalibration(false);
}
void loop() {
int co2ppm = mhz19.getPPM(MHZ19_POTOCOL::UART);
int temp = mhz19.getTemperature();
Serial.print("co2: "); Serial.println(co2ppm);
Serial.print("temp: "); Serial.println(temp);
delay(5000);
}
Teil 3
Jetzt muss das Ganze nur noch miteinander verknüpft werden. Kurz vor weg: So klappt es nicht am KNX-Ankoppler. Über USB läuft alles wunderbar, aber das wars. Warum? Der Sensor zieht zu viel Strom. Teilweise über 100mA an 5V. Laut diversen Angaben im Netz dürfen wir aber nur maximal 50mA über den 5V-Pin ziehen. Nicht gut. Wenn man sich nun ausrechnet, wie groß ein Kondensator sein müsste, um diesen Strom bei der Spannung kurzzeitig bereitstellen zu können, ist das praktisch unmöglich zu erreichen. Also bauen wir die Schaltung auf den 20V-Pin um.
#include <Arduino.h>
#include <KnxTpUart.h>
#include <MHZ19.h>
KnxTpUart knx(&Serial1, "1.1.25");
MHZ19 mhz19;
void setup() {
Serial.begin(9600);
Serial1.begin(19200, SERIAL_8E1);
knx.uartReset();
mhz19.begin(8, 9);
mhz19.setAutoCalibration(false);
}
void loop() {
int co2ppm = mhz19.getPPM(MHZ19_POTOCOL::UART);
knx.groupWrite2ByteInt("31/1/2", co2ppm);
//int temp = mhz19.getTemperature();
//Serial.print("co2: "); Serial.println(co2ppm);
//Serial.print("temp: "); Serial.println(temp);
delay(10000);
}
Damit es auch am Busankoppler funktioniert, muss das Ganze wie folgt umgebaut werden:
»KNX-Busankoppler mit CO2-Sensor am Arduino«
Ergebnis
Das Ganze wurde dann auf eine eigene Platine mit ein paar mehr Funktionen übertragen (Button, 3 LEDs, …). Die restlichen Komponenten wurden genau so übernommen wie bereits im vorigen Schritt gezeigt. Danach wurder der Code natürlich noch so angepasst, dass die verschiedenen LEDs und der Button auch nutzbar werden.
Die Platine habe ich natürlich auf GitHub veröffentlicht (Gerber-Datei direkt unter den Releases).
Da auf der Platine neben dem CO2-Sensor noch drei LEDs und ein Taster platz gefunden haben, wurden diese in den Code natürlich ebenfalls integriert. Dieser Taster muss noch entprellt werden - dafür nutze ich gerne die Bounce2-Lib. Alternativ kann man den Weg natürlich auch “zu Fuß” gehen. Genau wie bei den anderen Bibliotheken muss diese auch im Lib-Verzeichnis des Projektes abgelegt werden.
#include <Arduino.h>
#include <KnxTpUart.h>
#include <MHZ19.h>
#include <Bounce2.h>
#define PHYSICAL_ADDRESS "1.1.25"
#define CO2_REFRESH_INTERVAL 10000
#define CO2_PPM_GROUP_ADDRESS "10/1/2"
#define LED1_GROUP_ADDRESS "10/1/11"
#define LED2_GROUP_ADDRESS "10/1/12"
#define LED3_GROUP_ADDRESS "10/1/13"
#define BUTTON_GROUP_ADDRESS "10/1/3"
#define LED1 10 // Green
#define LED2 16 // Yellow
#define LED3 14 // Red
#define BUTTON1 15 // Test Button and Terminal Block
Bounce debouncer = Bounce();
KnxTpUart knx(&Serial1, PHYSICAL_ADDRESS);
MHZ19 mhz19;
void setup() {
Serial.begin(9600);
// LED config
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
// Button config
pinMode(BUTTON1, INPUT_PULLUP);
debouncer.attach(BUTTON1, INPUT_PULLUP);
debouncer.interval(25);
// KNX config
Serial1.begin(19200, SERIAL_8E1);
knx.uartReset();
knx.addListenGroupAddress(CO2_PPM_GROUP_ADDRESS);
knx.addListenGroupAddress(LED1_GROUP_ADDRESS);
knx.addListenGroupAddress(LED2_GROUP_ADDRESS);
knx.addListenGroupAddress(LED3_GROUP_ADDRESS);
// CO2 sensor config
mhz19.begin(8, 9);
mhz19.setAutoCalibration(false);
}
void maintainCo2Sensor() {
static unsigned long lastRefreshTime = 0;
if (millis() - lastRefreshTime >= CO2_REFRESH_INTERVAL) {
lastRefreshTime += CO2_REFRESH_INTERVAL;
knx.groupWrite2ByteFloat(CO2_PPM_GROUP_ADDRESS, getCo2SensorPpm());
}
}
float getCo2SensorPpm() {
int co2ppm = mhz19.getPPM(MHZ19_POTOCOL::UART);
Serial.println(co2ppm);
return float(co2ppm);
}
void maintainKnxSerial() {
if (Serial1.available() > 0) {
KnxTpUartSerialEventType eType = knx.serialEvent();
if (eType == KNX_TELEGRAM) {
KnxTelegram* telegram = knx.getReceivedTelegram();
String target =
String(0 + telegram->getTargetMainGroup()) + "/" +
String(0 + telegram->getTargetMiddleGroup()) + "/" +
String(0 + telegram->getTargetSubGroup());
if (telegram->getCommand() == KNX_COMMAND_READ) {
// Answer to Read
if (target == CO2_PPM_GROUP_ADDRESS) {
knx.groupAnswer2ByteFloat(CO2_PPM_GROUP_ADDRESS, getCo2SensorPpm());
}
} else if (telegram->getCommand() == KNX_COMMAND_WRITE) {
// Write commands
if (target == LED1_GROUP_ADDRESS) {
digitalWrite(LED1, telegram->getBool() ? HIGH : LOW);
} else if (target == LED2_GROUP_ADDRESS) {
digitalWrite(LED2, telegram->getBool() ? HIGH : LOW);
} else if (target == LED3_GROUP_ADDRESS) {
digitalWrite(LED3, telegram->getBool() ? HIGH : LOW);
}
}
}
}
}
void loop() {
maintainCo2Sensor();
maintainKnxSerial();
// Button Event
debouncer.update();
if (debouncer.fell()) {
knx.groupWriteBool(BUTTON_GROUP_ADDRESS, true);
}
}
Transparenz-Hinweis (Level 2)
Für diesen Beitrag wurden mir Produkte kostenfrei zur Verfügung gestellt! Es wurden keinerlei Bedingungen, Richtlinien oder Vorgaben bezüglich der Inhalte, welche ich in meiner Bewertung äußern darf, auferlegt.
Darüber hinaus habe ich keine zusätzliche Vergütung erhalten.