Programmierung
Manchmal muss beim Hochladen des Programms auf den des ESP32 der Reset-Knopf des ESP gedrückt gehalten werden.
Downloads:
Software
Um die Uhrzeit des RTC-Moduls zu setzen muss das Programm "DS3231_set" aus dem Software Ordner benutzt werden.
Downloads:
Software
Um die Uhrzeit des RTC-Moduls zu setzen muss das Programm "DS3231_set" aus dem Software Ordner benutzt werden.
Anleitung:
1. Climate Cube per Kabel mit dem PC verbinden und dieses Programm hochladen
2. Seriellen Monitor mit der Baud-Rate 57600 öffnen
3. Über die Kommandozeile folgenden Text an den ESP schicken:
Im Format YYMMDDwHHMMSS mit einem "x" am Ende die aktuelle Uhrzeit senden
z.B. 28.02.2024 07:52:00 entspricht 2402283075200x
Die Zeichen setzen sich zusammen aus:
YY -> Jahr -> 24
MM -> Monat -> 02
DD -> Tag -> 28
w -> Wochentag -> 3 (1=Montag, 2=Dienstag, 3=Mittwoch, 4=Donnerstag, 5=Freitag, 6=Samstag, 0=Sonntag)
HH -> Stunde -> 07
MM -> Minute -> 52
SS -> Sekunde -> 00
Hier als Beispiel der Code zum loggen der Daten auf einer SD-Karte
// Climate Cube V2 Code by Luca Ermentraut - lufraerm@gmail.com
#include "Wire.h" //I2C library
#include "SHT2x.h" //URL: https://github.com/RobTillaart/SHT2x
#include "SparkFunCCS811.h" //Click here to get the library: http://librarymanager/All#SparkFun_CCS811
#include "RTClib.h" //libraray for real time clock (RTC)
#include "FS.h"
#include "SD.h" //https://RandomNerdTutorials.com/esp32-microsd-card-arduino/
#include "SPI.h" //SPI lib to communicate with SD-card module
#include <Adafruit_NeoPixel.h> //Bibliothek zum Ansteuern der LEDs
#include <BH1750.h> //Lichtsensor library
#define LED_PIN 2 // Pin zum ansteuern der LEDs
#define LED_COUNT 2 // Anzahl der anzusteuernden LEDs
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_RGB + NEO_KHZ800); // zum Ansteuern der LEDs
RTC_DS3231 rtc; //rtc Objekt erstellen
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; //Array zum Speichern der Wochentage, werden im seriellen Monitor ausgegeben
String ErrorCodes[10] = {"kein Fehler","schreiben auf SD-Karte Fehler","CO2 Sensor Fehler","schreiben auf SD-Karte Fehler","CO2 Sensor Init Fehler","RTC Fehler","SD Init Fehler","SD-Karte nicht gefunden","RTC Connection lost",""}; //Array für Fehlercodes, werden im seriellen Monitor ausgegeben
const int PIR1_PIN = 4; //Pin für Bewegungssensor
bool movement = false; //speichert Bewegung (0 oder 1) bis zum nächsten loggen
float temperatureVariable = 25.0; //in degrees C
float humidityVariable = 65.0; //in % relative
#define CCS811_ADDR 0x5A //I2C Address for gas sensor
int CO2, CO2_1max, CO2_1min, CO2_2max, CO2_2min, CO2_state; //CO2 = Speicher CO2 Wert, Genzwerte für CO2 Ampel, CO2_state = aktuelle Farbe der Ampel (0 oder 1 oder 2)
int prevTime = 0; //Millisekundenspeicher für main loop
int duration = 5000; //Intervall zum loggen in ms
SHT2x sht; // sht Objekt erstellen
CCS811 myCCS811(CCS811_ADDR); //CCS811 Objekt erstellen
extern int ErrorCode = 0; //Speicher für ErrorCodes
bool LedState = false; //zum Blinken der LEDs im Fehlerfall
BH1750 lightMeter; //lightMeter Objekt erstellen
float lux = 0;
void setup()
{
Serial.begin(115200); //Beginn des seriellen Monitors mit Baudrate
pinMode(PIR1_PIN, INPUT); //pinMode Definition für Bewegungssensor
Wire.begin(); //I2C Initialisierung
sht.begin(); //SHT Initialisierung
CCS811_Init(); //CCS811 Initialisierung, siehe unten
RTC_Init(); //RTC Initialisierung, siehe unten
SD_Init(); //SD Initialisierung, siehe unten
strip.begin(); //LED Initialisierung
lightMeter.begin(); //Lichtsensor Initialisierung
strip.clear(); // LEDs standardmäßig auf "aus" setzten
strip.show(); // eingestellte LED-Farbe freigeben
CO2_1max = 900; //Grenzwerte für CO2 Ampel
CO2_1min = 750;
CO2_2max = 1500;
CO2_2min = 1350;
CO2_state = 0;
}
void loop()
{
if (digitalRead(PIR1_PIN) == 1){ //wird dauerhaft überprüft
movement = true;
}
if ((millis() - prevTime) > duration) { //alles in Klammer wird im Intervall von duration ausgeführt, siehe https://docs.arduino.cc/built-in-examples/digital/BlinkWithoutDelay/
prevTime = millis();
if (ErrorCode == 0){ //wird nur ausgeführt wenn kein Error Code vorhanden ist
DateTime now = readSensors(); //Sensoren auslesen und aktuelle Uhrzeit zurückgeben
SerialDebug(now); //Funtion zur Ausgabe aller Daten auf dem seriellen Monitor, siehe unten
logData(now); //Funktion zum loggen auf SD-Karte
movement = false; //nach dem loggen wieder auf false setzen
if ((now.month() > 12) || (now.day() > 31) || (now.hour() > 24) || (now.minute() > 60)){
ErrorCode = 8;
}
}
LedControl(); // Funktion zum Ansteuern der LEDs
}
}
DateTime readSensors(){
sht.read();
temperatureVariable = sht.getTemperature(); //in degrees C
humidityVariable = sht.getHumidity(); //in % relative
myCCS811.setEnvironmentalData(humidityVariable, temperatureVariable); //für genauere Mesuung werden Werte an Gas Sensor übergeben
myCCS811.readAlgorithmResults(); //Dump a reading and wait
delay(1000);
//temperatureVariable = temperatureVariable - (temperatureVariable * 0.15);
if (myCCS811.dataAvailable()) {
myCCS811.readAlgorithmResults(); //Calling readAlgorithmResults() function updates the global tVOC and CO2 variables
}
else {
Serial.println("CCS811 Error");
ErrorCode=2;
}
lux = lightMeter.readLightLevel(); //Lichtsensor auslesen
return rtc.now();
}
void LedControl(){
if (ErrorCode == 0){
CO2 = myCCS811.getCO2();
if ((CO2 > CO2_1max) && (CO2_state == 0)){ //wenn CO2 größer als erster Maximalwert ist -> Ampel von grün auf gelb
CO2_state = 1;
}
if ((CO2 > CO2_2max) && (CO2_state == 1)){ //wenn CO2 größer als zweiter Maximalwert ist -> Ampel von gelb auf rot
CO2_state = 2;
}
if ((CO2 < CO2_1min) && (CO2_state == 1)){ //wenn CO2 kleiner als erster Minimalwert ist -> Ampel von gelb auf grün
CO2_state = 0;
}
if ((CO2 < CO2_2min) && (CO2_state == 2)){ //wenn CO2 kleiner als zwiter Minimalwert ist -> Ampel von rot auf gelb
CO2_state = 1;
}
if (CO2_state == 0){
strip.setPixelColor(0, strip.Color(0, 10, 0)); // LED_1 soll dauerhaft grün leuchten
strip.setPixelColor(1, strip.Color(0, 10, 0)); // LED_2 soll dauerhaft grün leuchten
strip.show(); // Freigabe der LEDs
}
if (CO2_state == 1){
strip.setPixelColor(0, strip.Color(10, 8, 0)); // LED_1 soll dauerhaft gelb leuchten
strip.setPixelColor(1, strip.Color(10, 8, 0)); // LED_2 soll dauerhaft gelb leuchten
strip.show();
}
if (CO2_state == 2){
strip.setPixelColor(0, strip.Color(10, 0, 0)); // LED_1 soll dauerhaft rot leuchten
strip.setPixelColor(1, strip.Color(10, 0, 0)); // LED_2 soll dauerhaft rot leuchten
strip.show();
}
}
else if (ErrorCode > 0){
duration = 500; //Blinkintervall
Serial.print("Error Code: ");
Serial.println(ErrorCode); //Error Code aufgeben
Serial.println(ErrorCodes[ErrorCode]); //Fehler ausgeben
if (LedState){ //LEDs sollen rot blinken
strip.setPixelColor(0, strip.Color(255, 0, 0)); //LEDs an
strip.setPixelColor(1, strip.Color(255, 0, 0));
strip.show();
LedState = !LedState;
}
else {
strip.setPixelColor(0, strip.Color(0, 0, 0)); //LEDs aus
strip.setPixelColor(1, strip.Color(0, 0, 0));
strip.show();
LedState = !LedState;
}
}
}
void SerialDebug(DateTime now){
Serial.println("---------------------------------------");
Serial.print("Humidity: ");
Serial.print(humidityVariable);
Serial.println("% relative");
Serial.print("Temperature: ");
Serial.print(temperatureVariable);
Serial.println(" degrees C");
Serial.print("CO2[");
Serial.print(myCCS811.getCO2());
Serial.print("] tVOC[");
Serial.print(myCCS811.getTVOC());
Serial.print("]");
Serial.println();
Serial.print("Movement: ");
Serial.println(movement);
Serial.print("light intensity: ");
Serial.print(lux);
Serial.println(" lux");
Serial.print(now.year(), DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(" ");
Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
Serial.print(" ");
Serial.print(now.hour(), DEC);
Serial.print(':');
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.print(now.second(), DEC);
Serial.println();
/*Serial.print(" since midnight 1/1/1970 = ");
Serial.print(now.unixtime());
Serial.print("s = ");
Serial.print(now.unixtime() / 86400L);
Serial.println("d");*/
}
void logData(DateTime now){
String dataString = ""; // String zum Speichern der Daten
dataString += String(now.unixtime()); //Daten anhängen
dataString += ","; //durch Komma getrennt -> als CSV importierbar
dataString += String(myCCS811.getCO2());
dataString += ",";
dataString += String(myCCS811.getTVOC());
dataString += ",";
dataString += String(movement);
dataString += ",";
dataString += String(temperatureVariable);
dataString += ",";
dataString += String(humidityVariable);
dataString += ",";
dataString += String(lux);
dataString += "\r\n"; //nächste Zeile
appendFile(SD, "/datalog.txt", dataString.c_str()); //zu Datei auf SD-Karte hinzufügen
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
ErrorCode=3;
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
ErrorCode=1;
}
file.close();
}
void CCS811_Init(){
if (myCCS811.begin() == false)
{
Serial.print("CCS811 error. Please check wiring. Freezing...");
ErrorCode=4;
}
}
void RTC_Init(){
if (! rtc.begin()) {
Serial.println("Couldn't find RTC");
Serial.flush();
ErrorCode=5;
}
}
void SD_Init(){
if(!SD.begin(5)){
Serial.println("Card Mount Failed");
ErrorCode=6;
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
ErrorCode=7;
return;
}
}
// -- END OF FILE --
Last modified: Thursday, 29 February 2024, 9:57 AM