KNX in Eigenregie mit dem Arduino

Mit ** gekennzeichnete Links auf dieser Seite sind Affiliatelinks.

KNX in Eigenregie mit dem Arduino
KNX in Eigenregie mit dem Arduino
  • 19.05.2019
  • Level 2
  • Hardware
  • Grundlagen
  • DIY

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.

Wichtig: Das Projekt ist nur eine Demo - das Projekt kann Fehler enthalten und ist kein fertiges Produkt

Video

Arduino-Kurs

Produkte

Paradisetronic.com Pro Micro Modul mit ATmega32U4, Arduino Leonardo Board ähnlich, 5V, 16MHz **

ICQUANZX MH-Z19 Infrarot-CO2-Sensormodul MH-Z19B Kohlendioxid-Gassensor für CO2-Monitor 0-5000ppm MH Z19B **

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

»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

»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

»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

»KNX-Busankoppler mit CO2-Sensor am Arduino«

Ergebnis

Wichtig: Das Projekt ist nur eine Demo - das Projekt kann Fehler enthalten und ist kein fertiges Produkt

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.

Du willst mehr?

Smart-Home-Trainings von A-Z

Steig' noch tiefer in die Themen ein und meistere Deine Projekte! Über 14.000 Teilnehmer konnten sich schon von der Qualität der Online-Kurse überzeugen.

ioBroker-Master-Kurs

ioBroker-Master-Kurs

Mehr Infos
Hausbau-Kurs

Hausbau mit KNX

Mehr Infos
Lox-Kurs

Lox-Kurs

Mehr Infos
Node-RED-Master-Kurs

Node-RED-Master-Kurs

Mehr Infos