ich möchte temporär (wobei ja nichts länger hält als ein Provisorium...) ein paar Temperaturen messen und da sich hierfür aus meiner Sicht eine 1-Wire Extension nicht lohnt (und die Kabelverlegung schwierig wäre), habe ich mir ein paar günstige Temperatursensoren (DS18B20) und ein ESP32 DEVKIT besorgt.
Hiermit kann ich nun die Temperaturen auslesen, auf dem ESP32 in ein Modbus-Register schreiben und mit Loxone auslesen (der ESP32 hängt im WLAN).
Falls jemand ähnliches sucht:
1. Den Temperatursensor an 3,3V, Ground und mit dem 1-Wire an PIN4 des DEVKITS anschließen.
2. Folgenden Sketch in ArduinoIDE flashen und ausführen, der zeigt Euch die Seriennummer(n) des(r) angeschlossenen Temperatursensors(en) in der seriellen Konsole (die brauchen wir, damit nach einem Neustart -bei Verwendung mehrerer Sensoren- die IDs nicht durcheinander kommen):
#include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 4 // Pin D4 (GPIO4) OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress tempDeviceAddress; void printAddress(DeviceAddress deviceAddress) { for (uint8_t i = 0; i < 8; i++) { if (deviceAddress[i] < 16) Serial.print("0"); Serial.print(deviceAddress[i], HEX); } } void setup() { Serial.begin(115200); delay(1000); Serial.println("Starte Sensor-Suche..."); sensors.begin(); int sensorCount = sensors.getDeviceCount(); Serial.print("Sensoren gefunden: "); Serial.println(sensorCount); for (int i = 0; i < sensorCount; i++) { if (sensors.getAddress(tempDeviceAddress, i)) { Serial.print("Sensor "); Serial.print(i + 1); Serial.print(": "); printAddress(tempDeviceAddress); Serial.println(); } else { Serial.print("Sensor "); Serial.print(i + 1); Serial.println(": Adresse konnte nicht gelesen werden."); } } } void loop() { // nichts zu tun }
4. Die jeweilige(n) Seriennummer(n) in 2er Blöcke aufteilen; aus 280A039D54220894 wird also 28 0A 03 9D 54 22 08 94. Nun vor diese 2er Blöcke jeweils noch 0x dran hängen, ergibt also: 0x28, 0x0A, 0x03, 0x9D, 0x54, 0x22, 0x08, 0x94 -diese Seriennummer wie unten im Code unter "TempSensor knownSensors[] = {" sichtbar einfügen. Wie auch unten im Code zu sehen, kann davor noch der Name des Sensors angegeben werden und am Ende das Modbus-Register.
5. In den Anführungszeichen hinter ssid und password Eure WLAN-SSID und das dazugehörige Passwort einfügen, nach dem Start und der Verbindung mit dem WLAN wird die zugewiesene IP-Adresse ebenfalls in der seriellen Konsole ausgegeben:
#include <WiFi.h> #include <OneWire.h> #include <DallasTemperature.h> #include <ModbusIP_ESP8266.h> // WLAN-Zugangsdaten const char* ssid = "******"; const char* password = "*********"; // 1-Wire Bus #define ONE_WIRE_BUS 4 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); // Modbus ModbusIP mb; // Sensorstruktur struct TempSensor { const char* name; DeviceAddress address; uint16_t modbusRegister; }; TempSensor knownSensors[] = { { "VL_Nele", { 0x28, 0x0A, 0x03, 0x9D, 0x54, 0x22, 0x08, 0x94 }, 101 }, { "RL_Nele", { 0x28, 0x5C, 0x44, 0x81, 0x54, 0x22, 0x09, 0xC4 }, 102 }, { "VL_SZ", { 0x28, 0xAE, 0x5E, 0x6D, 0x61, 0x22, 0x07, 0xB6 }, 103 }, { "RL_SZ", { 0x28, 0x30, 0xFE, 0x35, 0x61, 0x22, 0x07, 0xE3 }, 104 }, { "VL_Tom", { 0x28, 0xE7, 0x0C, 0x54, 0x61, 0x22, 0x07, 0x98 }, 105 }, { "RL_Tom", { 0x28, 0xCA, 0xCF, 0x38, 0x61, 0x22, 0x07, 0x8A }, 106 }, { "VL_Bad", { 0x28, 0xBB, 0x70, 0x71, 0x61, 0x22, 0x07, 0x76 }, 107 }, { "RL_Bad", { 0x28, 0xFC, 0x93, 0x42, 0x61, 0x22, 0x07, 0xD2 }, 108 }, { "VL_Diele", { 0x28, 0xAD, 0x9A, 0x5F, 0x61, 0x22, 0x07, 0x9D }, 109 }, { "RL_Diele", { 0x28, 0xFE, 0x96, 0xC0, 0x00, 0x00, 0x00, 0x6D }, 110 }, { "VL_WZ_links", { 0x28, 0xCE, 0xB0, 0xBC, 0x00, 0x00, 0x00, 0x5E }, 111 }, { "RL_WZ_links", { 0x28, 0x0B, 0x6E, 0xBB, 0x00, 0x00, 0x00, 0x50 }, 112 }, { "VL_WZ_rechts", { 0x28, 0x6E, 0x8C, 0xC0, 0x00, 0x00, 0x00, 0x1D }, 113 }, { "RL_WZ_rechts", { 0x28, 0x44, 0x82, 0x50, 0x00, 0x00, 0x00, 0x27 }, 114 }, { "VL_Küche", { 0x28, 0x19, 0x17, 0x52, 0x00, 0x00, 0x00, 0x21 }, 115 }, { "RL_Küche", { 0x28, 0x85, 0x6F, 0xBC, 0x00, 0x00, 0x00, 0xE2 }, 116 }, { "VL_Flur", { 0x28, 0x9A, 0x68, 0xBC, 0x00, 0x00, 0x00, 0xCC }, 117 }, { "RL_Flur", { 0x28, 0xFC, 0x49, 0xBB, 0x00, 0x00, 0x00, 0x0E }, 118 }, { "VL_HKV", { 0x28, 0x57, 0x7B, 0xBC, 0x00, 0x00, 0x00, 0x2B }, 119 }, { "RL_HKV", { 0x28, 0x47, 0xC0, 0xBC, 0x00, 0x00, 0x00, 0x4F }, 120 }, }; const int NUM_SENSORS = sizeof(knownSensors) / sizeof(knownSensors[0]); void setup() { Serial.begin(115200); delay(500); WiFi.begin(ssid, password); Serial.print("Verbinde mit WLAN..."); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\n WLAN verbunden!"); Serial.print("IP-Adresse: "); Serial.println(WiFi.localIP()); sensors.begin(); mb.server(); // Modbus TCP Port 502 for (int i = 0; i < NUM_SENSORS; i++) { mb.addHreg(knownSensors[i].modbusRegister, 0); Serial.printf("Sensor '%s' auf Register %d vorbereitet\n", knownSensors[i].name, knownSensors[i].modbusRegister); } } void loop() { mb.task(); static unsigned long lastUpdate = 0; if (millis() - lastUpdate > 60000) { lastUpdate = millis(); sensors.requestTemperatures(); for (int i = 0; i < NUM_SENSORS; i++) { float tempC = sensors.getTempC(knownSensors[i].address); int16_t value; if (tempC != DEVICE_DISCONNECTED_C) { value = (int16_t)(tempC * 10.0); // z. B. 21.3°C → 213 Serial.printf("%s: %.1f °C → Reg %d\n", knownSensors[i].name, tempC, knownSensors[i].modbusRegister); } else { value = 1000; // 1000,0 °C als Fehlerwert Serial.printf("%s: Sensor nicht erreichbar → Reg %d = 1000°C\n", knownSensors[i].name, knownSensors[i].modbusRegister); } mb.Hreg(knownSensors[i].modbusRegister, value); } } }
6. Der ESP32 liest nun also jede 60sek die Temperatursensoren aus und schreibt diesen Wert in das entsprechende Modbus-Register. Sollte ein Wert nicht gelesen werden können, schreibt er 1000°C in das Register (zur Fehlervisualisierung in Loxone)....
7. In Loxone die IP Adresse des ESPs mit dem Port 502 verwenden, und als Geräteadresse die 1.
Viel Spass!
Gruss,
Sebastian
Kommentar