Arduino Nano (Umweltdaten im Haus sammeln)

Hallo und Guten Morgen.

Vorab ich starte gerade meine ersten Versuche :slight_smile:

Ich möchte folgendes realisieren.

In jedem Zimmer im Haus, soll folgende Einheit verbaut werden:

Display OLED 128x64 zu Kontrolle LINK ----OK
BME280 für Temperatur und Luftdruck LINK ----OK
Bewegungsmelder LINK ----OK
Luftgütesensor MQ2 ?????
Oberflächentemperatur Sensor (soll die Oberflächentemperatur des Fußboden erfassen) LINK ----OK (erfasst in 3m Höhe die Temperatur der gesamten Oberfläche)
Lichtsensor LINK ----OK
Temperaturfüller direkt in der Betondecke ----OK
Summer für Rückmeldung / Alarm (Optional)
LED für Rückmeldung (Bewegungsmelder) ----OK (Bewegungsmelder)
LED für Rückmeldung (Gegenstelle / Master) (kurze Impulse)

Die Werte sollen im Display alle x Sekunden nacheinander angezeigt werden.
Zudem sollen die Werte per LAN (kein WLan) zur einer PFC200 Codesys 3.5 SPS gesendet werden, evtl. per Modbus oder MTTQ. Dafür möchte ich einen ENC28J60 verwenden.

Das wäre meine Idee oder Vorstellung.

Danke für die Hilfe!

Gruß
hd458

du stellst keine einzige Frage. Daher: ja super! Hopp auf.

Ein Tipp: nimm nicht den ENC28J60 sondern ein Shield mit einem W5100 oder einem W5500. Es gibt auch Boards da kann man direkt den Nano draufstecken (oder drunterstecken, weil die Pins lang genug sind)
hier zum Beispiel auf Aliexpress
oder auf Amazon genauso

So aber nun Step bei Step.

Ich habe erst mal einen BME280 genommen und das OLED Display.

Dann folgenden Codes geschrieben.

Es funktioniert soweit auch. Aber ich denke man kann den Code besser schreiben. Würde gerne Kritik haben haben, wie gesagt ist mein erster CODE :slight_smile:

//Quellen
//Schriftarten für Display OLED: https://github.com/olikraus/u8glib/wiki/fontsize

#include <Wire.h>
#include "U8glib.h"
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define SEALEVELPRESSURE_HPA (1013.25)                                //BME280
Adafruit_BME280 bme;                                                  //BME280 - I2C
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK);                        //Display OLED

//Werte und Wertetypen setzen/declar für BME280
float pressure = 0.0;
float temp = 0.0;
float altitude = 0.0;
float humid = 0.0;
int sensorID;

//wird nur beim ersten Start ausgeführt
void setup(void)
{
bme.begin();                                                          //BME280
}

//wird kontinuierlich ausgeführt (Programmcode)
void loop(void)
{
  DisplayPresTemp(&pressure, &temp, &altitude, &humid, &sensorID);    //BME280 Unterprgramm aufrufen
}

//Unterprogramm DisplayPresTemp
void DisplayPresTemp(float* pressure, float* temp, float* altitude, float* humid, int* sensorID)
{
  *temp           = bme.readTemperature();                  //Temperatur
  *pressure       = bme.readPressure() / 100.0;             //Luftdruck
  *altitude       = bme.readAltitude(SEALEVELPRESSURE_HPA); //Calculate altitude assuming 'standard' barometric pressure of 1013.25 millibar = 101325 Pascal
  *humid          = bme.readHumidity();                     //Luftfeuchtigkeit
  *sensorID       = bme.sensorID(),16;                      //Sensor ID
  
  u8g.firstPage();
  do
  {
    u8g.setFontRefHeightExtendedText();                     
    u8g.setDefaultForegroundColor();
    u8g.setFontPosTop();


    u8g.setFont(u8g_font_timB14);                             //Schriftart setzen

    u8g.firstPage();
    do {
      u8g.drawStr(10, 18, "HomeControl");
    } while( u8g.nextPage() );
    delay(4000);


    u8g.setFont(u8g_font_7x13B);                              //Schriftart setzen
    
    u8g.firstPage();
    do {
      u8g.drawStr(35, 38, "Luftdruck");
      u8g.setPrintPos(30, 55  );
      u8g.print(*pressure);
      u8g.println(" hPa");
    } while( u8g.nextPage() );
    delay(2000);
  
    u8g.firstPage();
    do {
      u8g.drawStr(32, 38, "Temperatur");
      u8g.setPrintPos(45, 55);
      u8g.print(*temp);
      u8g.println(" C");
    } while( u8g.nextPage() );  
    delay(2000);

    u8g.firstPage();
    do {
      u8g.drawStr(35, 38, "Altitude");
      u8g.setPrintPos(40, 55);
      u8g.print(*altitude);
      u8g.println(" m");
    } while( u8g.nextPage() );  
    delay(2000);

    u8g.firstPage();
    do {                   
      u8g.drawStr(12, 38, "Luftfeuchtigkeit");
      u8g.setPrintPos(45, 55);
      u8g.print(*humid);
      u8g.println(" %");
    } while( u8g.nextPage() );  
    delay(2000);

    u8g.firstPage();
    do {
      u8g.drawStr(12, 38, "Sensor ID BME280");
      u8g.setPrintPos(49, 55);
      u8g.print(*sensorID);
      u8g.println(" ID");
    } while( u8g.nextPage() );  
    delay(2000);
    
  }
  while (u8g.nextPage());
}

Da Du später noch mehr machen willst, solltest Du Dich gleich von Anfang an von Delay verabschieden, da der Prozessor in dieser Zeit (fast) nichts tut, also die Zeit nutzlos vertrödelt.

Schaue Dir dazu BlinkWithoutDelay in den Beispielen Deiner IDE an und verstehe es. Dabei kann Dir die Nachtwächtererklärung helfen.

Gruß Tommy

du stellst keine einzige Frage. Daher: ja super! Hopp auf.

Wollte den Beitrag direkt schreiben, aber ich bin neu und darf daher nur alle 5 Minuten schreiben :wink:

Ein Tipp: nimm nicht den ENC28J60 sondern ein Shield mit einem W5100 oder einem W5500.

Was ist besser dran? Den ENC28J60 habe ich noch.

BlinkWithoutDelay

Habe ich wohl verstanden, werde ich bei dem Code versuchen umzusetzen und dann wieder zu Kontrolle hier einstellen.

Danke!

hd458:
Was ist besser dran? Den ENC28J60 habe ich noch.

Stark vereinfacht, den ENC muss der Nano verwalten, dann läuft der ganze TCP/IP Stack im Nano. Der W5100 bringt das alles schon mit und der Nano muss weniger tun.

Zum Code:
#define SEALEVELPRESSURE_HPA (1013.25) //BME280

würde ich nicht als define machen sondern ganz normal

const float sealevelpressureHpa = 1013.25; // obs ein float sein muss bezweifle ich sowieso

Mir erschließt sich nicht, warum du einerseits deine Variablen global definierst:

float pressure = 0.0;
float temp = 0.0;
float altitude = 0.0;
float humid = 0.0;
int sensorID;

dann aber einen Aufstand machst mit Refernzen/Pointer um auf diese zuzugreifen.
Außerdem hast jetzt eine Monster Funktion in der du alles reinpackst (Sensor auslesen und Ausgabe), das hättest in der loop auch machen können. Teile das in vernünftige Einheiten auf.
delay ist langfristig böse
Leerzeilen wo es keine braucht.
Drück mal STRG-T und lass die IDE den Code formatieren.

noiasca:
const float = 1013.25; // obs ein float sein muss bezweifle ich sowieso

Da wird Dich der Compiler aber grimmig anschauen :wink:
Der Variablenname fehlt.

Gruß Tommy

hd458:
Was ist besser dran? Den ENC28J60 habe ich noch.

Das Wieso wurde bereits gesagt.
Für den W5100 bzw W5500 gibt es Module mit PoE. So kannst Du den Arduino direkt über Netzwerkkabel versorgen und brauchst keine zusätzlichen Kabel bzw eine Stromversorgung im Zimmer.
Grüße Uwe

Hallo,
noch mal zurück zu Deinem Hardware Konzept.

Display und BME laufen mit IC2 Bus. Der ist eigendlich nur für kurze Strecken. Das wird nicht für mehrere Zimmer gehen. Mal abgesehen davon das sich da meist nur 2-4 Adressen je Typ einstellen lassen.
Du wirst also schon für jeden Raum einen eigene UP vorsehen müssen.

Heinz

Ich hatte schon so verstanden daß jedes Zimmer einen Arduino bekommt.
Uwe

@Alle
Ja, jedes Zimmer bekommt so eine Einheit oder je nach Größe auch zwei.

@uwefed
Die Frage hatte ich davor gestellt :wink:

@Alle
So habe den Code etwas geändert, ja die delay muss noch weg.

//Quellen
//Schriftarten für Display OLED: https://github.com/olikraus/u8glib/wiki/fontsize

#include <Wire.h>
#include "U8glib.h"
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define SEALEVELPRESSURE_HPA (1013.25)                                //BME280
Adafruit_BME280 bme;                                                  //BME280 - I2C
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NO_ACK);                        //Display OLED

//wird nur beim ersten Start ausgeführt
void setup(void)
{
  bme.begin();                                                          //BME280
}

//wird kontinuierlich ausgeführt (Programmcode)
void loop(void)
{  
  DisplayPres("HomeControl", "Temperatur", (bme.readTemperature()), " C");                    
  DisplayPres("HomeControl", "Luftdruck", (bme.readPressure() / 100.0), " hPa");                
  DisplayPres("HomeControl", "Luftfeuchtigkeit", (bme.readHumidity()), " %");
  DisplayPres("HomeControl", "Altitude", (bme.readAltitude(SEALEVELPRESSURE_HPA)), " m");
  DisplayPres("HomeControl", "Senosr ID", (bme.sensorID(), 16), " ID");
}

void DisplayPres(String a, String b, float c, String d)
{
  u8g.firstPage();
  do
  {
    u8g.setFontRefHeightExtendedText();
    u8g.setDefaultForegroundColor();
    u8g.setFontPosTop();
    u8g.firstPage();
    do {

      u8g.setFont(u8g_font_timB14);                             //Schriftart setzen
      u8g.setPrintPos(7, 14  );
      u8g.print(a);

      u8g.setFont(u8g_font_7x13B);                              //Schriftart setzen
      u8g.setPrintPos(7, 32  );
      u8g.print(b);
      u8g.setPrintPos(7, 48  );
      u8g.print(c);
      u8g.println(d);
      
    } while ( u8g.nextPage() );
    
    delay(2000);                                                //muss noch weg
  }
  while (u8g.nextPage());
}

Hallo,

Nano und ENC28J60: TCP-Stack, PubSubClient für MQTT und Lib für den BME280 hatte ich mal in Betrieb.
Ist absolute Obergrenze, da ist der Ram-Verbrauch am Ende.

Der Rest ist ein Abwägen der Kosten wenn man mehrere Einheiten bauen will.
Da WLAN raus ist, fällt zumindest meine Lieblingsversion mit einem ESP8266 (D1 mini) schon mal weg.
Hier tummeln sich 10...15 ESPs im WLAN ohne irgendwelche Probleme.

Gruß aus Berlin
Michael

Hi

Mein Bauchgefühl sagt: Das passt nicht Alles auf einen Nano.
Kämpfe hier gerade mit einem Uno (gleicher µC) - allerdings habe ich 'ein paar' globale Variablen, Die etwas Speicher verbraten.
Da das oLED mit Seinem Puffer auch nicht gerade geizig damit umgeht, befürchte ich, daß das Alles an den Speichergrenzen des Nano/Uno scheitert.

MfG

Hi,

falls das OLED zu viel Speicher frisst, könnte man sich die SSD1306Ascii anschauen, wenn ASCII reicht ...

Gruß André

Hi

Danke für den Link - Das könnte mir schon gefallen - muß schauen, ob ich Das nicht um ein PLOT/PSET (einzelnen Pixel setzen) erweitert bekomme ... so ein SSD1306 ist ja auch nur ein Mensch und will nur freundlich angeschwätzt werden :slight_smile:
(ich hätte gerne eine Temperatur-Kurve auf dem Display ... Extrawurst und so)

MfG

Ich werde erst mal so weiter machen, muss ja auch noch das Programmieren lernen :slight_smile:

Das Display ist nicht unbedingt notwendig, da ich dieses eigentlich nur zu Kontrolle wollte.
Würde ein SPI sparsamer sein?

Die Kosten sind wichtig, aber dennoch nicht so entscheidend. Wichtig, das es stabil später läuft.

amithlon:
Da WLAN raus ist, fällt zumindest meine Lieblingsversion mit einem ESP8266 (D1 mini) schon mal weg.
Hier tummeln sich 10...15 ESPs im WLAN ohne irgendwelche Probleme.

Das ist in meinen Augen auch die beste und effektivste Lösung. Ich war auch mal Fan von "Leitung ist Leitung".
Dann lernte ich den Wemos D1 mini kennen ...

Gruß Tommy

Hi

Der letzte Punkt liegt eher an Dir, als am gewählten Protokoll - Welches Dir wohl keinen Speicherplatz sparen wird.
Einzig, wenn Du überall das gleiche Protokoll benutzt - dann muß natürlich nur Eines davon auch im Code abgefrühstückt werden.

Bei mir werden an Nano's (und mindestens zwei Uno) DS18B20 ausgelesen und per CAN (Kabel wurde beim 'Neu-machen' dafür vorgesehen) verschickt.
Neben mehreren Versionen der Nachrichten (von den DS18B20 schwirren hier zwei Typen an Nachrichten rum, eine Alte und eine Aktuelle), gibt's noch BME280 und einen US-Sensor, Dessen Abstand ich so erfahre.
Aktuell möchte ich die Daten loggen (Datenlogger-Shield AZDelivery in meinem Fall) UND als Kurve auf einem Display ausgeben - Letzteres beißt sich akut mit dem Logger-Shield auf einem Uno (neben dem Kram, Den ich eh für die CAN-Nachrichten brauche) - Das wird wohl ein Mega übernehmen dürfen.
Alleine ohne das oLED (dafür mit einem 2004 LCD) werden mir Laufzeitprobleme vorausgesagt

Globale Variablen verwenden 1643 Bytes (80%) des dynamischen Speichers, 405 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.
Wenig Arbeitsspeicher verfügbar, es können Stabilitätsprobleme auftreten.

Bisher aber Keine aufgetreten.

MfG

Gibt es keinen Arduino mit mehr Speicher /Ram und evtl. schon mit LAN onbard?
Wichtig ist halt auch der Stromverbrauch.

Evtl. muss ich mich nur an WLan gewöhnen :slight_smile: