Entre otras pequeñas extensiones, me gustaría presentar hoy otro dispositivo remoto que suministra valores medidos de los sensores I2C BMP280 y/o BME280 a nuestra sede de hogar inteligente.
El circuito se basa en un D1 Mini y los sensores BMP280 Y BME280. Dado que estos sensores pueden tener una dirección I2C de 0X77 o 0X76, el programa descubre automáticamente qué sensor se conectó con qué dirección. Sin modificaciones suministradas por AZ Delivery, el BMP280 tiene la dirección 0X77 y la BME 280 la dirección 0X76.
El circuito es muy simple. El reloj I2C está conectado con D1 del D1 Mini y la línea de datos al D2 del D1 Mini. Para el BMP280, la línea Chipselect debe estar conectada a 3.3 V de modo que el BMP280 comience en el modo I2C. En el D1 Mini conectamos la entrada RESET al pin D0 (línea púrpura). El programa pone el ESP8266 en un profundo sueño después de que se haya hecho el trabajo. Esta conexión vuelve a activar el ESP8266 después de la hora establecida. Sin embargo, debe quitar esta conexión para parpadear.
Bosquejo:
/* Sensor de presión WLAN BMP280 y o BME280 ESP ahora a ArduiTouch SmartHome Si el dispositivo no tiene una dirección MAC de servidor válida se realizará una búsqueda para encontrar una WLAN con SSID ATSmartHome La dirección MAC del servidor se guardará siempre y cuando la fuente de alimentación no se interrumpirá. El protocolo ESP Now es casi la corriente más alta para el trabajo de la red consumido por un corto tiempo (nosotros) solamente. Después de enviar los valores, el dispositivo cambia durante cinco minutos a un modo de sueño profundo con un consumo de energía muy bajo. */ biblioteca para WiFi #include <ESP8266WiFi.H> bibliotecas para utilizar BMP280 y BME280 #include <Adafruit_Sensor.H> #include <Adafruit_BME280.H> #include <Adafruit_BMP280.H> biblioteca para el protocolo de mensajes utilizado #include "AT_MessageBuffer.h" biblioteca para ESP Ahora Externos "C" { #include <espnow.H> } SSID para buscar #define GW_SSID "ATSmartHome" indicador para cambiar los mensajes de depuración en #define Depuración Verdad #define SEND_TIMEOUT 2000 Tiempo de espera de 2 segundos definir canales para los dos sensores #define CHANNEL_TEMP_BME 0 #define CHANNEL_PRESS_BME 1 #define CHANNEL_ALT_BME 2 #define CHANNEL_HUM_BME 3 #define CHANNEL_TEMP_BMP 4 #define CHANNEL_PRESS_BMP 5 #define CHANNEL_ALT_BMP 6 #define SEALEVELPRESSURE_HPA (1013.25) Estructura de datos para guardar la dirección MAC del servidor y una suma de comprobación en la memoria RTC Estructura MEMORYDATA { uint32_t crc32; suma de comprobación para la validación uint8_t Mac[6]; }; Variables globales Volátil Bool callbackCalled; Booleana hasBme = 0; Booleana hasBmp = 0; Dirección MAC y canal Wi-Fi MEMORYDATA statinfo; AT_MessageBuffer Msg; Adafruit_BME280 Bme; I2c Adafruit_BMP280 Bmp; I2c función para calcular la suma de comprobación uint32_t calculateCRC32(Const uint8_t *Datos, Size_t Longitud) { uint32_t Crc = 0xffffffff; Mientras (Longitud--) { uint8_t C = *Datos++; Para (uint32_t Ⅰ. = 0x80; Ⅰ. > 0; Ⅰ. >>= 1) { Bool Poco = Crc & 0x80000000; Si (C & Ⅰ.) { Poco = !Poco; } Crc <<= 1; Si (Poco) { Crc ^= 0x04c11db7; } } } devolución Crc; } escribir MAC del servidor y suma de comprobación en la memoria RTC Vacío UpdateRtcMemory() { uint32_t crcOfData = calculateCRC32(((uint8_t*) &statinfo) + 4, Sizeof(statinfo) - 4); statinfo.crc32 = crcOfData; Esp.rtcUserMemoryWrite(0,(uint32_t*) &statinfo, Sizeof(statinfo)); } buscar el punto de acceso Vacío ScanForSlave() { Bool slaveFound = 0; int8_t scanResults = Wifi.scanNetworks(); restablecer en cada escaneo Si (Depuración) Serial.println("Escaneo hecho"); Si (scanResults == 0) { Si (Depuración) Serial.println("No se han encontrado dispositivos WiFi en el modo AP"); } Más { Si (Depuración) Serial.Impresión("Encontrado"); Si (Depuración) Serial.Impresión(scanResults); Si (Depuración) Serial.println(" dispositivos "); Para (Int Ⅰ = 0; Ⅰ < scanResults; ++Ⅰ) { Imprima SSID y RSSI para cada dispositivo encontrado Cadena Ssid = Wifi.Ssid(Ⅰ); int32_t Rssi = Wifi.Rssi(Ⅰ); int32_t Chl = Wifi.Canal(Ⅰ); Cadena BSSIDstr = Wifi.BSSIDstr(Ⅰ); Si (Depuración) { Serial.Impresión(Ⅰ + 1); Serial.Impresión(": "); Serial.Impresión(Ssid); Serial.Impresión(" /"); Serial.Impresión(Chl); Serial.Impresión(" ("); Serial.Impresión(Rssi); Serial.Impresión(")"); Serial.println(""); } Retraso(10); Compruebe si el dispositivo actual comienza con ATSmartHome' Si (Ssid == GW_SSID) { SSID de interés Si (Depuración) { Serial.println("Encontrado un esclavo."); Serial.Impresión(Ⅰ + 1); Serial.Impresión(": "); Serial.Impresión(Ssid); Serial.Impresión(" ["); Serial.Impresión(BSSIDstr); Serial.Impresión("]"); Serial.Impresión(" ("); Serial.Impresión(Rssi); Serial.Impresión(")"); Serial.println(""); } Int Mac[6]; obtener el servidor MAC y guardar en la memoria RTC Si ( 6 == sscanf(BSSIDstr.c_str(), "%x:%x:%x:%x:%x:%x%c", &Mac[0], &Mac[1], &Mac[2], &Mac[3], &Mac[4], &Mac[5] ) ) { Para (Int Ⅱ = 0; Ⅱ < 6; ++Ⅱ ) { statinfo.Mac[Ⅱ] = (uint8_t) Mac[Ⅱ]; } UpdateRtcMemory(); } slaveFound = 1; no más búsqueda después de AP se encontró Romper; } } } Si (Depuración) { Si (slaveFound) { Serial.println("Esclavo encontrado, procesamiento."); } Más { Serial.println("Esclavo no encontrado, lo intenta de nuevo."); } } liberar RAM Wifi.scanDelete(); } función para initilizar el sensor BME probar ambas direcciones válidas 77 o 76 Booleana initBme() { Booleana Estado = Bme.Comenzar(0x77); Si (!Estado) Estado = Bme.Comenzar(0x76); Si (!Estado) { Serial.println("No se pudo encontrar un sensor BME280 válido, comprobar el cableado!"); hasBme = Falso; Mientras (1); } devolución Estado; } función para initilizar el sensor BMP probar ambas direcciones válidas 77 o 76 Booleana initBmp() { Booleana Estado = Bmp.Comenzar(0x77); Si (!Estado) Estado = Bmp.Comenzar(0x76); Si (!Estado) { Serial.println("No se pudo encontrar un sensor BME280 válido, comprobar el cableado!"); hasBme = Falso; Mientras (1); } Si (Estado) { /* Configuración predeterminada de la hoja de datos. */ Bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Modo de funcionamiento. */ Adafruit_BMP280::SAMPLING_X2, /* Temp. sobremuestreo */ Adafruit_BMP280::SAMPLING_X16, /* Sobremuestreo de presión */ Adafruit_BMP280::FILTER_X16, /* Filtrado. */ Adafruit_BMP280::STANDBY_MS_500); /* Tiempo de espera. */ } devolución Estado; } Vacío Configuración() { Si (Depuración) { Serial.Comenzar(115200); Serial.println("Comenzar"); } obtener la dirección MAC local para usarlo como identificador de dispositivo Cadena strmac = Wifi.macAddress(); Si (Depuración) { Serial.Impresión("Mi dirección MAC"); Serial.println(strmac); } Msg.setId(strmac); Msg.Claro(); hasBme = initBme(); Si (hasBme && Depuración) { Serial.println("Sensor encontrado BME"); } hasBmp = initBmp(); Si (hasBmp && Depuración) { Serial.println("Sensor encontrado BMP"); } leer el servidor MAC de la memoria RTC Esp.rtcUserMemoryRead(0, (uint32_t*) &statinfo, Sizeof(statinfo)); Si (Depuración) Serial.println("RTC hecho"); uint32_t crcOfData = calculateCRC32(((uint8_t*) &statinfo) + 4, Sizeof(statinfo) - 4); Wifi.Modo(WIFI_STA); Modo de estación para el nodo del sensor esp-now Si (Depuración) Serial.println("WifiMode"); Si (statinfo.crc32 != crcOfData) { si suma de comprobación diferente no tenemos un servidor MAC válido Si (Depuración) Serial.println("Busca esclavo"); ScanForSlave(); para (uint8_t i a 0; i<6;i++) statinfo.mac[i] á gwmac[i]; Si (Depuración) { Serial.Printf("Este mac: %s,", Wifi.macAddress().c_str()); Serial.Printf("mac objetivo: %02x%02x%02x%02x%02x%02x%02x", statinfo.Mac[0], statinfo.Mac[1], statinfo.Mac[2], statinfo.Mac[3], statinfo.Mac[4], statinfo.Mac[5]); } } Si (esp_now_init() != 0) { Si (Depuración) Serial.println("*** ESP_Now init falló"); Esp.Reiniciar(); } Controlador ESP Now Wifi.setAutoConnect(Falso); esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER); uint8_t Ch = esp_now_get_peer_channel(statinfo.Mac); Si (Depuración) Serial.Printf("Canal á %i'r"n",Ch); inicializar los datos del mismo nivel Int Res = esp_now_add_peer(statinfo.Mac, ESP_NOW_ROLE_CONTROLLER, 1, Null, 0); Si (Res==0) Serial.println("Parejada con éxito"); registrar la devolución de llamada esp_now_register_send_cb([](uint8_t* Mac, uint8_t sendStatus) { Si (Depuración) { Serial.Impresión("send_cb, estado "); Serial.Impresión(sendStatus); Serial.Impresión(", a mac: "); Char macString[50] = {0}; Sprintf(macString,"%02X:%02X:%02x:%02X:%02X:%02X:%02X", statinfo.Mac[0], statinfo.Mac[1], statinfo.Mac[2], statinfo.Mac[3], statinfo.Mac[4], statinfo.Mac[5]); Serial.println(macString); } callbackCalled = Verdad; }); establecer la bandera en false callbackCalled = Falso; iniciar la medición leer los valores y guardar para el envío Si (hasBme) { Si (Depuración){ Serial.Impresión("Temperatura "); Serial.Impresión(Bme.readTemperature()); Serial.println(" *C"); Serial.Impresión("Presión"); Serial.Impresión(Bme.readPressure() / 100.0F); Serial.println(" hPa"); Serial.Impresión("Aprox. Altitud á "); Serial.Impresión(Bme.readAltitude(SEALEVELPRESSURE_HPA)); Serial.println("m"); Serial.Impresión("Humedad"); Serial.Impresión(Bme.readHumidity()); Serial.println(" %"); } Msg.addCelsius(Bme.readTemperature(), CHANNEL_TEMP_BME); Msg.addHektoPascal(Bme.readPressure()/100.0F, CHANNEL_PRESS_BME); Msg.addMeter(Bme.readAltitude(SEALEVELPRESSURE_HPA), CHANNEL_ALT_BME); Msg.addPercent(Bme.readHumidity(), CHANNEL_HUM_BME); } Si (hasBmp) { Si (Depuración) { Serial.Impresión(Q("Temperatura ")); Serial.Impresión(Bmp.readTemperature()); Serial.println(" *C"); Serial.Impresión(Q("Presión")); Serial.Impresión(Bmp.readPressure()); Serial.println("Pa"); Serial.Impresión(Q("Altitud aproximada ")); Serial.Impresión(Bmp.readAltitude(SEALEVELPRESSURE_HPA)); /* Ajustado a la previsión local! */ Serial.println("m"); } Msg.addCelsius(Bmp.readTemperature(), CHANNEL_TEMP_BMP); Msg.addHektoPascal(Bmp.readPressure()/100.0F, CHANNEL_PRESS_BMP); Msg.addMeter(Bmp.readAltitude(SEALEVELPRESSURE_HPA), CHANNEL_ALT_BMP); } copiar la estructura de datos en sendbuffer uint8_t Buf[255]; uint8_t Sz; Sz = 255; Si (Msg.fillBuffer(&Buf[0], &Sz)) esp_now_send(Null, Buf, Sz); NULL significa enviar a todos los pares } Vacío Bucle() { esperar a que se envíen datos Si (callbackCalled || (Millis() > SEND_TIMEOUT)) { Si (Depuración) Serial.println("Dormir"); Retraso(100); ir durante 10 segundos en modo de sueño profundo despertar por restablecer reset no elimina los datos en RTCmemory Esp.deepSleep(10E6); } }
Para que este boceto sea compilado, además de las bibliotecas para los sensores, necesita la última versión de mi ATMessageBuffer Biblioteca.
El código del boceto también se puede encontrar en los ejemplos de la nueva versión de la ATSmartHome Biblioteca.
Después de actualizar la sede de Smart-Home, compilamos el Sketch y lo cargamos en el D1 Mini. Después de un corto tiempo, la dirección MAC del D1 Mini debe aparecer en la barra azul inferior de la sede de Smarthome. Hacemos clic una vez largo (más de 3 s) en esta dirección MAC. Se muestra la página de registro. Podemos dar un nombre al dispositivo y después de hacer clic en Guardar deberíamos ver las nuevas lecturas en la pantalla. Si otros dispositivos ya se han registrado en la sede central de Smarthome, los nuevos canales también pueden aparecer en una de las otras páginas. El registro automático busca lugares gratuitos en la pantalla y muestra los nuevos canales como pequeños widgets.
Un clic largo en los widgets lo lleva a su página de configuración y puede cambiar su apariencia y posición. La siguiente imagen muestra una posible configuración si utilizamos ambos sensores BMx al mismo tiempo.
Finalmente, una pequeña extensión en el sitio web de la sede de Smarthome. Si se muestra un widget de actuador, tiene la opción de encender o apagar el dispositivo remoto, al igual que en la unidad central Smarthome, haciendo clic. Para el widget del actuador, vea también la parte 3 de esta serie
Aquí están los enlaces a todas las partes anteriores:
Diviértete :)
10 comentarios
Franz Patzal
Hi Greg,
look in part 6:
Ein wichtiger Hinweis zu Beginn!
Die ArduiTouch Smarthome Zentrale funktioniert nur mit dem ESP32 stabil. Es zeigte sich, dass auf Grund des deutlich geringeren RAM des ESP8266 kein stabiler Betrieb möglich ist. Ich habe daher die Version für den ESP8266 wieder aus dem Repository entfernt. Die aktuelle Version der ATSmartHome Bibliothek kann nicht mehr mit dem Sketch für ESP8266 kompiliert werden!
Greg
Hi. I am trying to follow the examples fro the SmartHome project, but it refers to the library ESP8266WiFi.H, even for ESP32 examples . Where can I find this library?
Many thanks!
Greg.
Wolfgang Händel
Hallo Herr Lechner….
Bis auf die etwas begrenzte Reichweite der Arduitouch Zentrale funktioniert bei mir alles recht gut.
Was das Herz des Smarthome Einsteigers natürlich höher schlagen lassen würde, wäre ein Sensormodul für ein binäres Signal (Klingeltaster, Bewegungssensor, Dämmerungssensor uvm.)
Das binäre Signal eines solchen Moduls müsste in der Zentrale ausgewertet werden und bestimmte Funktionen (wie z.B. das Relaismodul aus Teil 3) auslösen.
Haben sie so etwas geplant? Meines Erachtens gehört so etwas zu den Standard-Features eines SmartHome-Systems.
Ansonsten vielen Dank für die interessanten Blogs zum Thema SmartHome und für die Mühe, die sie sich damit gegeben haben bzw. noch geben..
Wolfie
Siegl Reinhard
Hallo
Ich bekomme die Smart Home V" nicht zum laufen.Es stoppt schon bei #include “SPIFFS.h”.
Bei der alten Smart Home konnte ich alle Beiträge nachbauen.
Danke für die Unterstützung schon im Vorraus.
Matthias H.
Hallo Herr Lechner,
könnte man die Stimmungslaterne https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/mehrere-feuer-programme-fuer-unsere-stimmungslaterne?pos=3&_sid=3afeceff9&ss=r nicht mit der Smarthome Zenrale steuern?
Reinhard Schneider
Wie das mit den Fehlern so ist, es hat sich auch bei mir einer eingeschlichen.
Richtig muss es für 5 min deep-sleep heißen:
ESP.deepSleep(300*10E6);
Reinhard Schneider
Leider haben sich in das o.g. Programm einige kleine Fehler eingeschlichen:
1. /function to initilize BMP Sensor
….
Richtig:
Serial.println(“Could not find a valid BMP280 sensor, check wiring!”);
hasBmp = false;
2. In der Beschreibung heißt es
Für 5 Minuten müsste es heißen:….
After sending the values, the device switches for five minutes into a deep sleep mode with very low power consumption.
Der Code ist aber in void loop()
….
//go for 10 seconds into deep sleep mode
//wakeup by reset
//reset does not delete data in RTCmemory
ESP.deepSleep(10E6);
ESP.deepSleep(600*10E6);
Reinhard Schneider
Das obige Programm läuft nur mit der Version 0.15.0 von “ESPiLight”.
Die aktuelle Version 0.16.0 erzeugt Fehlermeldungen.
Ist eine Anpassung des ino-Files geplant?
Joe
Bei den Daten der beiden Sensoren kann man sagen das es Roh-Daten sind.
Jetzt muß man nur eine Kalibrierung mit einem Referenz-Meßgerät höherer Genauigkeit durchführen. Und dann die Rohdaten entsprechen mit einem Justage-Wert belegen.
Es wird immer eine geringfügige Abweichung zwischen den Sensoren geben.
(Rauschen, Eigentemperatur etc, Meßfehler).
Die redudante Messung ist in Bereichen bei denen der Ausfall, starker Unterschied der Meßwerte, ermittelt werden muß. Rreinraum, technische zu überwachende Prozeße.
Temperatur-Differenzen werden auch genutzt um Strömungen, in dem Fall Luft, zu ermitteln.
Also nicht vergessen Justage-Wert und Kalibrierung.
Marcus Klein
Beide Sensoren sind offenbar recht nah beieinander untergebracht. Sie messen trotzdem eine Differenz von einem kompletten Grad Celsius. Das ist ein absolutes No-Go, wenn man damit versucht Heimautomatisierung zu betreiben und die Heizung zu steuern. Daraus folgt direkt, dass der Heizkreis am Sensor mit der kleineren Temperatur immer heizt und der Kreis am Sensor mit der größeren Temperatur immer aus ist. Bei einem Grad Unterschied und nicht verschlossenen Türen zwischen den beiden Räumen und gut isolierter Hütte, wandert die Wärme ausreichend zwischen den beiden Räumen. Das trägt nicht wirklich zum Wohnkomfort bei, sondern stört diesen besonders.
Wie gedenken Sie, diesen Fehler zu kompensieren?