First Commit

This commit is contained in:
MindCreeper03
2025-02-27 19:31:50 +01:00
parent bcbb6aff9a
commit e490df1715
2470 changed files with 1479965 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
]
}

View File

@@ -0,0 +1,549 @@
#include <Arduino.h>
#include <Adafruit_SCD30.h>
#include <Adafruit_BME280.h>
#include "RTClib.h"
#include <Wire.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <TFT_eSPI.h>
#include <SD.h>
#include <ESP32Time.h>
#include <WiFi.h>
#include <time.h>
#define INTERNAL_RTC_OFFSET 3600
#define X_OFFSET 3
#define BAUDRATE 57600
#define DATAPOINTS_ON_SCREEN 288
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define FONT_SIZE 2
#define FONT_SIZE_LEGEND 1
#define CS_SD 5
#define CO2_COLOR TFT_BLUE
#define TEMP_COLOR TFT_RED
#define HUM_COLOR TFT_GREEN
#define CENTER_X SCREEN_WIDTH / 2 + 20
#define MODE_SWITCH 35 // 8
#define FORCE_REDRAW 34 // 11
#define SET_RTC 32 // 10
RTC_DS3231 rtc;
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);
Adafruit_SCD30 scd30; //I2C
Adafruit_BME280 bme; // I2C
TFT_eSPI tft = TFT_eSPI();
File g_myFile;
ESP32Time rtc_internal(INTERNAL_RTC_OFFSET);
struct datapoint {
String time;
float temperature;
float humidity;
int co2;
};
String g_fileName = "";
const char* ssid = "Obi W(L)an Kenobi";
const char* password = "YTI2YWJjMjk3ZTUx";
const char* ntpServer = "de.pool.ntp.org";
const long gmtOffset_sec = 3600;
const int dayLightOffset_sec = 0;
datapoint ga_graphed_data[DATAPOINTS_ON_SCREEN];
int g_graphedIndex = 0;
String g_timeYear, g_timeMonth, g_timeDay, g_timeHour, g_timeMinute, g_timeSecond, g_timeStamp, g_date, g_time_hms, g_co2Data, g_humidData, g_tempData, g_timeDow, g_path, g_DataPoint;
datapoint g_currentData = { "", 0, 0, 0 };
int g_screenSelect = 0;
bool g_screenChangeFlag, g_modeSwitchActive, g_triggeredLogging, g_debounceSerialOut, g_debounceForceReDraw, g_debounceRTCSet, g_rtcError, g_debounceRtcError, g_IndexMisMatchReDraw, g_WiFiConnected;
int theoreticalIndex(datapoint point) {
return point.time.substring(11, 13).toInt() * 12 + floor(point.time.substring(14, 16).toInt() / 5);
}
void setRTC() {
bool gotString = false;
char inChar;
u8g2.clearDisplay();
u8g2.clearBuffer();
u8g2.drawStr(X_OFFSET, 10, "Setting Time via Serial");
u8g2.sendBuffer();
int year, month, day, hour, minute, second;
int j = 0;
int data[20];
while (!gotString) {
if (Serial.available()) {
inChar = Serial.read();
data[j] = char(inChar) - '0';
j += 1;
if (inChar == 'x') {
gotString = true;
}
}
}
Serial.println();
for (int i = 0; i < 20; i++) Serial.print(data[i]);
year = data[0] * 10 + data[1] + 2000;
// now month
month = data[2] * 10 + data[3];
// now date
day = data[4] * 10 + data[5];
// now hour
hour = data[6] * 10 + data[7];
// now minute
minute = data[8] * 10 + data[9];
// now second
second = data[10] * 10 + data[11];
rtc.adjust(DateTime(year, month, day, hour, minute, second));
Serial.println("Current Time: " + String(rtc.now().year()) + "-" + String(rtc.now().month()) + "-" + String(rtc.now().day()) + "--" + String(rtc.now().hour()) + ":" + String(rtc.now().minute()) + ":" + String(rtc.now().second()));
g_IndexMisMatchReDraw = true;
}
datapoint StrToDataPoint(String text) {
int StringCount = 0;
String strs[5];
while (text.length() > 0) {
int index = text.indexOf(';');
if (index == -1) {
strs[StringCount++] = text;
break;
} else {
strs[StringCount++] = text.substring(0, index);
text = text.substring(index + 1);
}
}
datapoint data = { strs[0], strs[1].toFloat(), strs[2].toFloat(), strs[3].toInt() };
return data;
}
void drawGraph(float data[288], int points, int type) {
float offset = 0;
int color = 0;
float scale = 0;
int max_y = 220;
int min_y = 20;
int last_y;
float raw_y;
int y;
points = min(points, 288);
switch (type) {
case 0: //co2
color = CO2_COLOR;
offset = -300;
scale = 0.22;
break;
case 1: //temp
color = TEMP_COLOR;
offset = -15;
scale = 10;
break;
case 2: //humidity
color = HUM_COLOR;
offset = 0;
scale = 2;
break;
}
for (int i = 0; i < points; i++) {
raw_y = floor((float(data[i]) + offset) * scale);
y = min(float(max_y), max_y - max(float(min_y), raw_y));
if (i) {
last_y = min(float(max_y), max_y - max(float(min_y), floor((float(data[i - 1]) + offset) * scale)));
} else {
last_y = y;
}
int x = i + 30;
if (i % 5 == 0) {
//Serial.println("Printed Pixel to X: "+String(x)+"; Y: "+String(y));
//Serial.println("Debug Data: Data Value: "+String(data[i]+offset)+"; Y-Raw: "+String(raw_y)+"; Scale: "+String(scale));
}
last_y = max(last_y, 20);
if (y < 20) {
tft.drawLine(x, 20, x, last_y, TFT_RED);
} else {
tft.drawLine(x, y, x, last_y, color);
}
}
}
void checkforData() {
int data;
g_graphedIndex = 0;
String dataString = "";
int StringCount = 0;
String strs[288];
datapoint point;
int new_index;
getTime();
g_myFile = SD.open(g_fileName.c_str());
if (!g_myFile) {
Serial.println("File read of " + g_fileName + " failed. returning to normal program routine");
return;
}
while (g_myFile.available()) {
data = g_myFile.read();
dataString += char(data);
//Serial.print(char(data));
if (dataString.endsWith("\n")) {
strs[StringCount++] = dataString;
//Serial.println(dataString);
dataString = "";
}
//ga_graphed_data[g_graphedIndex] = StrToDataPoint(data);
//g_graphedIndex++;
}
for (int i = 0; i < StringCount; i++) {
point = StrToDataPoint(strs[i]);
new_index = theoreticalIndex(point);
if (new_index > 288) {
Serial.println("Clock error ig");
new_index = 288;
}
if (new_index != g_graphedIndex) {
Serial.println("New Index: " + String(new_index) + " Graphed Index was: " + String(g_graphedIndex));
Serial.println("Indexing Error: Correcting Index");
g_graphedIndex = new_index;
}
//Serial.println(g_graphedIndex);
ga_graphed_data[g_graphedIndex] = point;
//Serial.println(strs[i]);
g_graphedIndex++;
}
g_myFile.close();
new_index = theoreticalIndex(g_currentData);
if (new_index > g_graphedIndex) {
g_graphedIndex = new_index;
Serial.println("Corrected Index");
}
Serial.println("Imported " + String(max(StringCount - 1, 0)) + " of " + String(new_index) + " Datapoints");
}
void synchTime(bool WiFiConnected) {
DateTime now = rtc.now();
if (WiFiConnected) {
configTime(gmtOffset_sec, dayLightOffset_sec, ntpServer);
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("failed to get current time! Updating internal rtc from DS3231");
synchTime(false);
return;
}
Serial.println("Current time:");
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
if (getLocalTime(&timeinfo)) {
rtc_internal.setTimeStruct(timeinfo);
int now_hour;
if(rtc_internal.getHour(true)>0){
now_hour = rtc_internal.getHour(true)-1;
}
else{
now_hour = 23;
}
rtc.adjust(DateTime(rtc_internal.getYear(), rtc_internal.getMonth()+1, rtc_internal.getDay()-1, now_hour, rtc_internal.getMinute(), rtc_internal.getSecond()));
}
} else {
Serial.println("Updating internal rtc from DS3231");
int now_hour;
if(now.hour()>0){
now_hour = now.hour()-1;
}
else{
now_hour = 23;
}
rtc_internal.setTime(now.second(), now.minute(), now_hour, now.day(), now.month(), now.year()); //potential issue here
Serial.println(rtc_internal.getDateTime());
}
Serial.println("Synchronised Clocks");
}
void setup() {
// put your setup code here, to run once:
Serial.begin(BAUDRATE);
delay(5000);
while (!Serial) { ; };
Serial.flush();
if (!SD.begin(CS_SD)) {
Serial.println("Init of SD failed");
}
else{
Serial.println("SD Card initialised");
}
pinMode(MODE_SWITCH, INPUT);
pinMode(FORCE_REDRAW, INPUT);
pinMode(SET_RTC, INPUT);
Wire.begin();
tft.init();
tft.setRotation(1);
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
u8g2.begin();
u8g2.clearDisplay();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_courR08_tf);
g_screenChangeFlag = true;
if (!rtc.begin()) {
Serial.println("Could not find RTC! Check circuit.");
}
Wire.beginTransmission(0x68); // address DS3231
Wire.write(0x0E); // select CONTROL register
Wire.write(0b000011100); // write register (bit 7 is EOSC)
Wire.endTransmission();
Wire.beginTransmission(0x68);
Wire.write(0x0F); // select STATUS register
Wire.write(0b00001000); // write register (bit 7 is OSF)
Wire.endTransmission();
//rtc.adjust(DateTime(__DATE__, __TIME__));
scd30.begin();
bme.begin(0x76); //bme Sensor
if (!scd30.setMeasurementInterval(2)) {
Serial.println("Failed to Set Interval");
}
Serial.print("Measurement Interval: ");
Serial.print(scd30.getMeasurementInterval());
Serial.println(" seconds");
int wificheck = 10;
Serial.println("Connecting to WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED && wificheck) {
delay(1000);
wificheck--;
Serial.println("Connecting to WiFi...");
}
if (WiFi.status() == WL_CONNECTED) {
g_WiFiConnected = true;
Serial.println("Connected to WiFi");
} else {
g_WiFiConnected = false;
Serial.println("Not Connected to WiFi, synchronising with RTC");
}
delay(2000);
synchTime(g_WiFiConnected);
checkforData();
}
void fixRTCError() {
int t = 0;
Serial.println("RTC Error detected, Please reset over Serial or continue");
while (1) {
if (digitalRead(SET_RTC) == HIGH) {
setRTC();
break;
}
if (digitalRead(MODE_SWITCH) == HIGH || t == 60) break;
sleep(1);
t++;
}
Serial.println();
}
void getTime() {
DateTime now = rtc.now();
g_timeYear = String(now.year(), DEC);
g_timeMonth = String(now.month(), DEC);
g_timeDay = String(now.day(), DEC);
g_timeHour = String(now.hour(), DEC);
g_timeMinute = String(now.minute(), DEC);
g_timeSecond = String(now.second(), DEC);
if ((g_timeMonth.length()) == 1) { g_timeMonth = "0" + g_timeMonth; } // eine null voranstellen
if ((g_timeDay.length()) == 1) { g_timeDay = "0" + g_timeDay; }
if ((g_timeHour.length()) == 1) { g_timeHour = "0" + g_timeHour; }
if ((g_timeMinute.length()) == 1) { g_timeMinute = "0" + g_timeMinute; }
if ((g_timeSecond.length()) == 1) { g_timeSecond = "0" + g_timeSecond; }
if (g_date != g_timeDay + "." + g_timeMonth + "." + g_timeYear) {
g_date = g_timeDay + "." + g_timeMonth + "." + g_timeYear;
g_graphedIndex = 0;
g_screenChangeFlag = true;
}
g_time_hms = g_timeHour + ":" + g_timeMinute + ":" + g_timeSecond;
g_timeStamp = g_date + "-" + g_time_hms;
g_fileName = "/data_" + g_timeDay + "_" + g_timeMonth + "_" + g_timeYear + ".csv";
g_currentData.time = g_timeStamp;
}
void getSensorData() {
if (scd30.dataReady()) {
scd30.read();
g_currentData.co2 = scd30.CO2;
g_currentData.temperature = bme.readTemperature();
//pressure = bme.readPressure() / 100.0F;
g_currentData.humidity = bme.readHumidity();
//Serial.println(g_timeStamp+","+String(g_currentData.temperature)+","+String(g_currentData.humidity)+","+String(g_currentData.co2));
}
}
void drawOnScreen() {
if (g_screenChangeFlag) {
tft.fillScreen(TFT_BLACK);
tft.drawLine(29, 20, 29, 220, TFT_WHITE);
tft.drawLine(29, 220, 320, 220, TFT_WHITE);
for (int i = 0; i < 13; i++) {
if (i != 12) tft.drawCentreString(String(i * 2), 30 + i * 24, 227, FONT_SIZE_LEGEND);
tft.drawLine(30 + i * 24, 220, 30 + i * 24, 225, TFT_WHITE);
}
}
float data[288];
//small screen
u8g2.clearBuffer();
u8g2.drawStr(X_OFFSET, 10, (g_date + "-" + g_time_hms).c_str());
g_tempData = "Temp: " + String(g_currentData.temperature) + "C";
g_humidData = "Humid: " + String(g_currentData.humidity) + "%";
g_co2Data = "CO2: " + String(g_currentData.co2) + "ppm";
u8g2.drawStr(X_OFFSET, 19, g_tempData.c_str());
u8g2.drawStr(X_OFFSET, 28, g_humidData.c_str());
u8g2.drawStr(X_OFFSET, 37, g_co2Data.c_str());
u8g2.sendBuffer();
//big screen
switch (g_screenSelect) {
case 0: //co2
if (g_screenChangeFlag) {
Serial.println("showing CO2 Graph");
tft.drawCentreString("CO2 Concentration Statistics for today", CENTER_X, 5, FONT_SIZE);
tft.drawCentreString("ppm", 29, 10, FONT_SIZE_LEGEND);
g_screenChangeFlag = false;
tft.drawCentreString("500", 16, 197, FONT_SIZE_LEGEND);
tft.drawLine(24, 197, 29, 197, TFT_WHITE); //500
tft.drawCentreString("750", 16, 142, FONT_SIZE_LEGEND);
tft.drawLine(24, 142, 29, 142, TFT_WHITE); //1000
tft.drawCentreString("1000", 16, 86, FONT_SIZE_LEGEND);
tft.drawLine(29, 86, 320, 86, TFT_YELLOW); //Ab hier lüften
tft.drawLine(24, 86, 29, 86, TFT_WHITE); //1500
}
for (int i = 0; i < 288; i++) {
data[i] = ga_graphed_data[i].co2;
}
break;
case 1: //temp
if (g_screenChangeFlag) {
Serial.println("showing Temperature Graph");
tft.drawCentreString("Temperature Statistics for today", CENTER_X, 5, FONT_SIZE);
tft.drawCentreString("°C", 29, 10, FONT_SIZE_LEGEND);
g_screenChangeFlag = false;
tft.drawCentreString("20", 16, 170, FONT_SIZE_LEGEND);
tft.drawLine(24, 170, 29, 170, TFT_WHITE); //20
tft.drawCentreString("25", 16, 120, FONT_SIZE_LEGEND);
tft.drawLine(24, 120, 29, 120, TFT_WHITE); //25
tft.drawCentreString("30", 16, 70, FONT_SIZE_LEGEND);
tft.drawLine(24, 70, 29, 70, TFT_WHITE); //30
}
for (int i = 0; i < 288; i++) {
data[i] = ga_graphed_data[i].temperature;
}
break;
case 2: //humidity
if (g_screenChangeFlag) {
Serial.println("Showing Humidity Graph");
tft.drawCentreString("Humidity Statistics for today", CENTER_X, 5, FONT_SIZE);
tft.drawCentreString("%", 29, 10, FONT_SIZE_LEGEND);
g_screenChangeFlag = false;
}
for (int i = 0; i < 288; i++) {
data[i] = ga_graphed_data[i].humidity;
}
break;
//
default:
break;
}
drawGraph(data, g_graphedIndex, g_screenSelect);
}
void combineData() {
g_DataPoint = g_timeStamp + ";" + String(g_currentData.temperature) + ";" + String(g_currentData.humidity) + ";" + String(g_currentData.co2) + "\n";
Serial.print(g_DataPoint);
g_path = g_fileName;
int data;
String dataString = "";
g_myFile = SD.open(g_path.c_str());
while (g_myFile.available()) {
data = g_myFile.read();
dataString += char(data);
}
g_myFile.close();
g_myFile = SD.open(g_path.c_str(), FILE_WRITE);
if (!g_myFile) {
Serial.println("opening Log File for write failed - - - " + g_timeStamp);
}
g_myFile.print(dataString + g_DataPoint);
g_myFile.close();
Serial.println("Logging complete");
Serial.println("Current graphed index: " + String(g_graphedIndex));
}
void loop() {
if (rtc.lostPower()) {
Serial.println("RTC lost power at some point...");
}
if (digitalRead(MODE_SWITCH) == HIGH) { //LOW
if (!g_modeSwitchActive) {
g_screenSelect++;
g_screenChangeFlag = true;
if (g_screenSelect > 1) {
g_screenSelect = 0;
}
g_modeSwitchActive = true;
}
} else {
g_modeSwitchActive = false;
}
if (digitalRead(FORCE_REDRAW) == HIGH || g_IndexMisMatchReDraw) {
g_IndexMisMatchReDraw = false;
if (!g_debounceForceReDraw) {
checkforData();
g_screenChangeFlag = true;
drawOnScreen();
g_debounceForceReDraw = true;
}
} else {
g_debounceForceReDraw = false;
}
if (digitalRead(SET_RTC) == HIGH) {
if (!g_debounceRTCSet) {
setRTC();
g_debounceRTCSet = true;
}
} else {
g_debounceRTCSet = false;
}
getTime();
getSensorData();
g_rtcError = g_timeHour.toInt() > 23 || g_timeMinute.toInt() > 60 || g_timeSecond.toInt() > 60 || g_timeDay.toInt() > 31 || g_timeMonth.toInt() > 12;
if (g_rtcError) {
if (!g_debounceRtcError) {
g_debounceRtcError = true;
fixRTCError();
}
} else {
g_debounceRtcError = false;
}
if ((g_timeMinute.toInt() % 5 == 0) && g_timeSecond.toInt() == 0) {
if (!g_triggeredLogging) {
Serial.println("Logging current Data...");
combineData();
ga_graphed_data[g_graphedIndex] = { g_timeStamp, g_currentData.temperature, g_currentData.humidity, g_currentData.co2 };
if (g_graphedIndex + 2 < g_timeStamp.substring(11, 13).toInt() * 12 + floor(g_timeStamp.substring(14, 16).toInt() / 5)) {
g_IndexMisMatchReDraw = true;
Serial.println("Detected Mismatch in Indeces");
}
g_graphedIndex++;
if (g_graphedIndex > 287) {
for (int i = 1; i < 288; i++) {
ga_graphed_data[i - 1] = ga_graphed_data[i];
}
g_graphedIndex = 286;
g_screenChangeFlag = true;
}
g_triggeredLogging = true;
}
} else {
g_triggeredLogging = false;
}
if (g_timeSecond.toInt() % 2 == 0) {
if (!g_debounceSerialOut) {
drawOnScreen();
g_debounceSerialOut = true;
}
} else {
g_debounceSerialOut = false;
}
delay(20);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,29 @@
from serial import Serial
import time
ser = Serial()
def getPortName() -> str:
return "COM"+input("Enter the number of the connected Port: ")
def getBaudRate() -> int:
return int(input("Enter the Baudrate you are using"))
def getTimeStamp() -> str:
current_time = time.strftime("%y%m%d%w%H%M%S")+"x" #YYMMDDwHHMMSS
print("Getting current Time")
return current_time
def main():
ser.port = getPortName()
if input("Are you using 57600 as baud rate ? (y/N)").lower() == "y":
ser.baudrate = 57600
else:
ser.baudrate = getBaudRate()
timestamp =getTimeStamp()
print(f"Opening port {ser.port} at baudrate {ser.baudrate}")
ser.open()
print("Sending current time to Port")
print(timestamp)
ser.write(timestamp.encode())
print("Closing Port")
ser.close()
if __name__ == "__main__":
main()