Projekt: Raum(-luft)sensor (Temp, Hum, Co2, VOC, LUX)

Begonnen von herrmannj, 21 Januar 2019, 00:24:44

Vorheriges Thema - Nächstes Thema

Papa Romeo

...die richtige Lötspitzentemperatur prüft man zwischen Daumen und Zeigefinger.
...überlasse niemals etwas einer Software, das du hardwaremässig erreichen kannst.
...unvorsichtige Elektriker werden schnell zu leitenden Angestellten.
und...never change a running System...no Updates if not necessary

Starsurfer

Moin,
habe bei mir jetzt folgende Hardware laufen:
- Nodemcu v2
- 1.8 TFT (ST7735)
- BME280
- MAX44009
- MHZ19 (noch nicht im Code eingebaut)

Aktuelle Uhrzeit über NTP, auf dem Display.

Gesendet wird bei meiner Version über MQTT, da ich später noch die Außentemperatur mit auf dem Display anzeigen lassen will.
Der Code ist noch nicht ganz fertig und noch etwas chaotisch, aber vielleicht kann der ein oder andere ja damit schon was anfangen.

Arduino Code:
/*
Based on clock sketch by Gilchrist 6/2/2014 1.0
Updated by Bodmer
A few colour codes:

code  color
0x0000  Black
0xFFFF  White
0xBDF7  Light Gray
0x7BEF  Dark Gray
0xF800  Red
0xFFE0  Yellow
0xFBE0  Orange
0x79E0  Brown
0x7E0 Green
0x7FF Cyan
0x1F  Blue
0xF81F  Pink
*/
#define DEBUG_SERIAL

#ifdef DEBUG_SERIAL
#define DEBUG_BEGIN Serial.begin(115200)
#define DEBUG_PRINT(x) Serial.println(x)
#else
#define DEBUG_PRINT(x)
#define DEBUG_BEGIN
#endif

#define USE_BME280 0x76
#define USE_MHZ19B
#define USE_MAX
#define USE_TFT

#include <ESP8266WiFi.h>          //https://github.com/esp8266/Arduino
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include "WiFiManager.h"          //https://github.com/tzapu/WiFiManager
#include <PubSubClient.h>         // mqtt client
#include <ESP8266WiFi.h>
#include <Wire.h>

//BME280
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
//MAX44009
#include <MAX44009.h> //https://github.com/dantudose/MAX44009
MAX44009 light;
//MHZ19
#include <MHZ.h>                          // MH-Z19b: https://github.com/tobiasschuerg/MH-Z-CO2-Sensors
#include <SoftwareSerial.h> // Software Serial, used by MH-Z19b
//TFT
#include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI();  // Invoke library, pins defined in User_Setup.h

//for LED status
#include <Ticker.h>
Ticker ticker;

#define mqtt_port 1883
char mqtt_server[] = "192.168.178.87";
WiFiClient espClient;
PubSubClient client(espClient);

//NTP
#include <NTPtimeESP.h>
#define DEBUG_ON
NTPtime NTPch("fritz.box");   // Choose server pool as required
strDateTime dateTime;

#define heartbeat_topic "ESP_Sensor/Wohnzimmer/heartbeat/state"
#define wifisignal_topic "ESP_Sensor/Wohnzimmer/wifi/state"
#define abs_dewPoint_topic "/Haus/Wohnzimmer/abs_dewPoint"
#define abs_humidity_topic "/Haus/Wohnzimmer/abs_humidity"
#define humidity_topic "/Haus/Wohnzimmer/humidity"
#define lux_topic "/Haus/Wohnzimmer/lux"
#define pressure_topic "/Haus/Wohnzimmer/pressure"
#define temp_topic "/Haus/Wohnzimmer/temp"
bool heartbeat = 1;

// Interval to report mqtt data in seconds
unsigned long currentMillis = millis();
unsigned long prevLedMillis   = millis(); // counter main loop for signaling led
unsigned long prevBMEMillis   = millis(); // counter main loop for dht
unsigned long prevMhz19Millis = millis(); // counter main loop for MH-Z19
unsigned long prevLUXMillis   = millis(); // counter main loop for LDR
unsigned long prevHearbeatMillis = 15000;    // default
unsigned long intervalHearbeat = 15000;    // default
unsigned long sigLedOn        = 50;       // ms for led on
unsigned long sigLedOff       = 450;      // ms for led off
unsigned long intervalBME     = 50000;    // default
unsigned long intervalMhz19   = 10000;    // default
unsigned long intervalLUX     = 10000;    // default
unsigned long intervalLed     = 0;        //
uint32_t targetTime = 0;       // for next 1 second timeout
unsigned long delayTime;
//////////////////////////////////////////////////////////////////////////////////

byte omm = 99;
boolean initial = 1;
byte xcolon = 0;
unsigned int colour = 0;
uint8_t hh= 0;
uint8_t mm= 0;
uint8_t ss= 0;

static uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}

float absHum(float temp, float hum) {
  double sdd, dd;
  sdd=6.1078 * pow(10,(7.5*temp)/(237.3+temp));
  dd=hum/100.0*sdd;
  return (float)216.687*dd/(273.15+temp);
};

float dewPoint(float temp, float hum) {
  double A = (hum/100) * pow(10, (7.5*temp / (237+temp)));
  return (float) 237*log10(A)/(7.5-log10(A));
};

void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  //if you used auto generated SSID, print it
  Serial.println(myWiFiManager->getConfigPortalSSID());
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BME280
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme280; // I2C
  char str_temp[6];
  char str_hum[6];
  char str_absHum[6];
  char str_dewPoint[6];
  char str_pressure[16];

void getBMEReadings() {
  float t_offset = 0.65F;
  float h_offset = 7.0F;
  float h = bme280.readHumidity() + h_offset;
  float t = bme280.readTemperature() - t_offset;
  float a = absHum(t, h);
  float d = dewPoint(t, h);
  float p = bme280.readPressure() / 100.0F;
  dtostrf(t, 3, 2, str_temp);
  dtostrf(h, 3, 2, str_hum);
  dtostrf(a, 3, 2, str_absHum);
  dtostrf(d, 3, 2, str_dewPoint);
  dtostrf(p, 3, 1, str_pressure);
};

void printTFT_BME_Values(){
  tft.setTextColor(TFT_WHITE, TFT_BLACK);
  tft.drawCentreString(str_temp, 10, 82, 1);
  tft.drawCentreString ("\xF7" "C", 45, 82, 1);
  tft.drawCentreString(str_hum, 10, 93, 1);
  tft.drawCentreString ("%", 45, 93, 1);
  tft.drawCentreString(str_pressure, 10, 105, 1);
  tft.drawCentreString ("hpa", 45, 105, 1);
}

void printBMEValues() {
    Serial.print("Temperature = ");
    Serial.print(bme280.readTemperature());
    Serial.println(" *C");
    Serial.print("Pressure = ");
    Serial.print(bme280.readPressure() / 100.0F);
    Serial.println(" hPa");
    Serial.print("Approx. Altitude = ");
    Serial.print(bme280.readAltitude(SEALEVELPRESSURE_HPA));
    Serial.println(" m");
    Serial.print("Humidity = ");
    Serial.print(bme280.readHumidity());
    Serial.println(" %");
    Serial.println();
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// MAX44009
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define Addr 0x4A
char str_lux[16];
void getLUXReadings() {
  float lux = light.get_lux();
  dtostrf(lux, 3, 2, str_lux);
  Serial.print("Light (lux):    ");
  Serial.println(str_lux);
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void tick(){
  //toggle state
  int state = digitalRead(LED_BUILTIN);  // get the current state of GPIO1 pin
  digitalWrite(LED_BUILTIN, !state);     // set pin to the opposite state
};

void setup() {
  DEBUG_BEGIN; //for terminal debugging
  DEBUG_PRINT();

  // Enable I2C for ESP8266 NodeMCU boards [VDD to 3V3, GND to GND, SDA to D2, SCL to D1]
  Wire.begin(D2, D1);
  //set led pin as output
  pinMode(LED_BUILTIN, OUTPUT);

  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);
  tft.fillCircle(3, 3, 2, TFT_RED); //WLAN keine Verbindung

  setup_wifi();

  tft.setTextColor(TFT_RED, TFT_BLACK); // Note: the new fonts do not draw the background colour
  tft.drawCentreString("Innen:",15,65,2);
  tft.drawCentreString("Aussen:",120,65,2);

  targetTime = millis() + 1000;

#ifdef USE_BME280
  if (! bme280.begin(USE_BME280)) {
    DEBUG_PRINT("Could not find a valid BME280 sensor, check wiring and address!");
  };
#endif

#ifdef USE_MAX //MAX44009
  if(light.begin())
    {
        Serial.println("Could not find a valid MAX44009 sensor, check wiring!");
    while(1);
  }
#endif
}

void loop() {

unsigned long currentMillis = millis();

  // first parameter: Time zone in floating point (for India); second parameter: 1 for European summer time; 2 for US daylight saving time; 0 for no DST adjustment; (contributed by viewwer, not tested by me)
  dateTime = NTPch.getNTPtime(1.0, 1);
  // check dateTime.valid before using the returned time
  // Use "setSendInterval" or "setRecvTimeout" if required
  if(dateTime.valid){
    NTPch.printDateTime(dateTime);
    Serial.println(dateTime.valid);
    byte actualHour = dateTime.hour;
    byte actualMinute = dateTime.minute;
    byte actualsecond = dateTime.second;
    int actualyear = dateTime.year;
    byte actualMonth = dateTime.month;
    byte actualday =dateTime.day;
   // byte actualwday =dateTime.wday;
    byte actualdayofWeek = dateTime.dayofWeek;

   hh= dateTime.hour;
   mm= dateTime.minute;
   ss= dateTime.second;
  }

 
   if (targetTime < millis()) {
     targetTime = millis()+1000;
     ss++;              // Advance second
     if (ss==60) {
       ss=0;
       omm = mm;
       mm++;            // Advance minute
       if(mm>59) {
         mm=0;
         hh++;          // Advance hour
         if (hh>23) {
          hh=0;
         }
       }
     }

    if (ss==0 || initial) {
      initial = 0;
      tft.setTextColor(TFT_WHITE, TFT_BLACK);
      tft.setCursor (8, 52);
      tft.print(dateTime.dayofWeek);
      tft.print("  ");
      tft.print(dateTime.day);
      tft.print(".");
      tft.print(dateTime.month);
      tft.print(".");
      tft.print(dateTime.year);

      //tft.setTextColor(TFT_BLUE, TFT_BLACK);
      //tft.drawCentreString("It is windy",120,48,2); // Next size up font 2

      //tft.setTextColor(0xF81F, TFT_BLACK); // Pink
      //tft.drawCentreString("12.34",80,100,6); // Large font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 . : a p m
    }

    // Update digital time
    byte xpos = 6;
    byte ypos = 0;
   
    if (omm != mm) { // Only redraw every minute to minimise flicker
      tft.setTextColor(0x39C4, TFT_BLACK);  // Leave a 7 segment ghost image, comment out next line!
      tft.drawString("88:88",xpos,ypos,7); // Overwrite the text to clear it
      tft.setTextColor(0xFBE0, TFT_BLACK); // Orange
      omm = mm;

      if (hh<10) xpos+= tft.drawChar('0',xpos,ypos,7);
      xpos+= tft.drawNumber(hh,xpos,ypos,7);
      xcolon=xpos;
      xpos+= tft.drawChar(':',xpos,ypos,7);
      if (mm<10) xpos+= tft.drawChar('0',xpos,ypos,7);
      tft.drawNumber(mm,xpos,ypos,7);
    }


    if (ss%2) { // Flash the colon
      tft.setTextColor(0x39C4, TFT_BLACK);
      xpos+= tft.drawChar(':',xcolon,ypos,7);
      tft.setTextColor(0xFBE0, TFT_BLACK);
    }
   
  }

  // If we are waking up from a sleep, we need to re-establish a connection with
  // the mqtt server.
  if ( !client.connected() ) {
    reconnect();
  }

  client.loop();

if (currentMillis - prevHearbeatMillis > intervalHearbeat) {
  prevHearbeatMillis = currentMillis;
  heartbeat = !heartbeat;
  Serial.println("Send heartbeat");
  client.publish(heartbeat_topic, String(heartbeat).c_str(), true);
  long rssi = WiFi.RSSI();
  Serial.println("Send wifi signal strenght");
  client.publish(wifisignal_topic, String(rssi).c_str(), true);
  };

#ifdef USE_BME280
  if (currentMillis - prevBMEMillis > intervalBME) {
    prevBMEMillis = currentMillis;
    getBMEReadings();
    printBMEValues();
    printTFT_BME_Values();
    client.publish(temp_topic, str_temp);
    client.publish(humidity_topic, str_hum);
    client.publish(abs_humidity_topic, str_absHum);
    client.publish(abs_dewPoint_topic, str_dewPoint);
    client.publish(pressure_topic, str_pressure);
  };
#endif

#ifdef USE_MAX
  if (currentMillis - prevLUXMillis > intervalLUX) {
    prevLUXMillis = currentMillis;
    getLUXReadings();
    client.publish(lux_topic, str_lux);
  };
#endif
}

void setup_wifi(){
  delay(10);
  // start ticker with 0.5 because we start in AP mode and try to connect
  ticker.attach(0.6, tick);
  WiFiManager wifiManager;
  wifiManager.setAPCallback(configModeCallback);
  if (!wifiManager.autoConnect()) {
    DEBUG_PRINT("failed to connect and hit timeout");
    ESP.reset();
    delay(1000);
  }
  DEBUG_PRINT("connected...yeey :)");
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  ticker.detach();
  digitalWrite(LED_BUILTIN, LOW);
  tft.fillCircle(3, 3, 3, TFT_GREEN); //WLAN keine Verbindung
  client.setServer( mqtt_server, mqtt_port );
  client.setCallback(callback);
  WiFi.mode(WIFI_STA);
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Connecting to MQTT Server ...");
    // Attempt to connect (clientId, username, password)
    if ( client.connect("ESP Device") ) {
      Serial.println( "[DONE]" );
      //client.subscribe("/Garten/temp");
      //client.subscribe("/Garten/hum");
    } else {
      Serial.print( "[FAILED] [ rc = " );
      Serial.print( client.state() );
      Serial.println( " : retrying in 5 seconds]" );
      // Wait 5 seconds before retrying
      delay( 5000 );
    }
  }
}

void callback(char* topic, byte* payload, unsigned int length) {
    Serial.print("Received message [");
    Serial.print(topic);
    Serial.print("] ");
    char msg[length+1];
    for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
        msg[i] = (char)payload[i];
    }
    Serial.println();

    msg[length] = '\0';
    Serial.println(msg);

    if(strcmp(msg,"on")==0){
        digitalWrite(13, HIGH);
    }
    else if(strcmp(msg,"off")==0){
        digitalWrite(13, LOW);
    }
}

FHEM Server: Fujitsu Esprimo q920 + LaCrosseGateway + HM-MOD-RPI-PCB WLAN + ConBee
HomeMatic HM-CC-RT-DN - Sonoff Tasmota
LaCrosse TX29DTH - Innr SP120 - Osram Smart+ Plug
Arduino Mega - MQTT - Pluggit 300
https://www.diy-robot-lawn-mower.com

Nicolas

Hallo Zusammen,

Das ist ein sehr spannendes Projekt. Ich gehe davon aus, dass ihr inzwischen einige Sensoren in Betrieb genommen habt. Gibt es erste Erfahrungsberichte? Sachen die ihr ändern würdet? Könnt ihr allenfalls einige Fotos Posten?

Danke und Gruss, Nicolas

herrmannj

Hallo Nicolas,

herzlich Willkommen!

Die bisher einzigen Prototypen laufen vmtl bei mir. Ich war die vergangenen Wochen beruflich sehr stark eingespannt und wollte vor dem Versand der Platinen erst sicherstellen das sie fehlerfrei funktionieren. Seit 2 Tagen arbeite ich wieder am Projekt.

Aktuell habe ich noch 10 Platinen aus der Bestellung übrig die ich (first come, first serve) versenden kann.

Es gibt einige kleine Punkte zu beachten, betreffen die Frontplatine:

- die LEDs laufen am Wemos nicht mit den 5V lassen sich jedoch problemlos mit 3.3V betreiben. Das geht am einfachsten indem
    a) die Diode auf dem Mainboard nicht bestückt wird
    b) kein 5V Leitungen zwischen Main und Front installiert werden.
    c) eine kleine Brücke zwischen 3,3V und 5V auf der Frontplatine gesetzt wird (Anschlüsse liegen direkt nebeneinander)

-  bei Verwendung der PL9823-F5 (nicht SMD): LEDs so weit wie möglich nach Außen einlöten. Zu erst die jeweils äußeren Pins fixieren, danach einpassen. Die Lötaugen sind etwas zu weit innen, deshalb durch passendes Löten ausgleichen. Passprobe.

- der Widerstand für die LDR auf dem Board zwischen VCC und dem LDR, er müsste zwischen LDR und Masse. Das geht problemlos indem man ihn passend einlötet, schräg, und als Masse den freien i2C Port verwendet.

Ein Display habe ich mir zerschossen, die gibt es in zwei Ausführungen wobei VCC und GND vertauscht sind.

Bei meiner Tochter läuft jetzt seit Wochen einer der Prototypen. Da wird nur eine der LEDs vereinfacht angesteuert und kein Display. Sie ist bereits so begeistert und passt ihr Verhalten (lüften) wirklich darauf an. Auf das Display könnte man möglicherweise komplett verzichten.

Software aktualisiere ich im GIT sobald die nächste MVP Stufe erreicht ist.

Meldungen für Platinen gern per pm (+Adresse)

vg
Joerg

PeMue

Hallo Jörg,
Zitat von: PeMue am 03 Februar 2019, 19:49:24
Ich nehme dann mal 2 Platinen, aber nur wenn es einen Schaltplan gibt und ich mein breakout verbauen kann  8) 8) 8)
Ist das noch auf Deinem Schirm? Breakouts sind auch noch da, falls ihr sie braucht. Details zur Bezahlung per PM?

Gruß Peter
RPi3Bv1.2 rpiaddon 1.66 6.0 1xHM-CC-RT-DN 1.4 1xHM-TC-IT-WM 1.1 2xHB-UW-Sen-THPL-O 0.15 1x-I 0.14OTAU  1xCUNO2 1.67 2xEM1000WZ 2xUniroll 1xASH2200 3xHMS100T(F) 1xRFXtrx 90 1xWT440H 3xTFA30.3150 5xFA21
RPi1Bv2 LCDCSM 1.63 5.8 2xMAX HKT 1xMAX RT V200KW1 Heizung Wasser

herrmannj

Zitat von: PeMue am 25 April 2019, 22:01:05
Hallo Jörg,Ist das noch auf Deinem Schirm? Breakouts sind auch noch da, falls ihr sie braucht. Details zur Bezahlung per PM?

Gruß Peter
Schick mal Deine Adresse bitte.

Papa Romeo

...die richtige Lötspitzentemperatur prüft man zwischen Daumen und Zeigefinger.
...überlasse niemals etwas einer Software, das du hardwaremässig erreichen kannst.
...unvorsichtige Elektriker werden schnell zu leitenden Angestellten.
und...never change a running System...no Updates if not necessary

herrmannj


Papa Romeo

...hätte eigentlich auch alles da....müsste es nur noch zusammenlöten und den Sketch aufspielen....stecke aber im Moment zu tief und zu viel ("zu viel" --> Aussage meiner Frau) in meinen eigenen Projekten drin. ::)
...die richtige Lötspitzentemperatur prüft man zwischen Daumen und Zeigefinger.
...überlasse niemals etwas einer Software, das du hardwaremässig erreichen kannst.
...unvorsichtige Elektriker werden schnell zu leitenden Angestellten.
und...never change a running System...no Updates if not necessary

herrmannj


Starsurfer

Bei mir läuft jetzt die mqtt Version seid knapp einer Woche, allerdings auf dem Steckbrett mit 1.44 " TFT. Ist mir aber definitiv zu klein, das Display.
FHEM Server: Fujitsu Esprimo q920 + LaCrosseGateway + HM-MOD-RPI-PCB WLAN + ConBee
HomeMatic HM-CC-RT-DN - Sonoff Tasmota
LaCrosse TX29DTH - Innr SP120 - Osram Smart+ Plug
Arduino Mega - MQTT - Pluggit 300
https://www.diy-robot-lawn-mower.com

herrmannj


Starsurfer

FHEM Server: Fujitsu Esprimo q920 + LaCrosseGateway + HM-MOD-RPI-PCB WLAN + ConBee
HomeMatic HM-CC-RT-DN - Sonoff Tasmota
LaCrosse TX29DTH - Innr SP120 - Osram Smart+ Plug
Arduino Mega - MQTT - Pluggit 300
https://www.diy-robot-lawn-mower.com

juergs

#328
Hallo Zusammen,
freut mich, dass hier auch wieder Aktivität aufgenommen wird.

Meine Idee ist es, die Erkenntnisse aus dem Projekt Wetterstation auch mit dem BME-Sensor zu verschmelzen bzw. zu erweitern.

Ich benutze hierzu dieses Display TFT-2-4-Touch-Shield-V1-0-0-for-LOLIN-WEMOS-D1-mini-2-4-inch mit dem ESP8266-Wemos D1.
Das Display hat den Vorteil, dass man den ESP auf die Displayplatine mit aufstecken kann.
Da die Steckerleiste doppelt ausgeführt ist, kann man Erweiterungen sehr leicht aufstecken.  Der Aufbau fällt dadurch auch sehr kompakt aus.
Hierbei bin  ich gerade am Ausarbeiten einer passenden Platine und am Einarbeiten in KiCAD.  ::)

Außerdem bin ich dabei, die Sensordaten zusätzlich in die IOT-Cloud  zu versenden.

Zitat..gut Ding, will Weile haben... ;)

//--- settings for LOLIN TFT2.4 with Wemos D1 mini-pinout
//---
#define TFT_DC      D8     //D2
#define TFT_CS      D0     //D1
#define TFT_LED     D4     //D8

/* #define HAVE_TOUCHPAD */
#define TOUCH_CS    D3
#define TOUCH_IRQ   255


Grüße,
Jürgen

juergs