UCPS_WS26-27/UCPSMain/UCPSMain.ino

204 lines
5.3 KiB
C++

#include <LiquidCrystal.h>
#include <dht_nonblocking.h>
#include <SoftwareSerial.h>
#include <WiFiEsp.h>
// Wifi (Hotspot)
const char wifiSSID[] = "FreeWifi";
const char wifiPASS[] = "temppassword";
// ESP8266 (Wifi module, AT firmware)
SoftwareSerial wifiSerial(2, 3); // RX = 2, TX = 3
WiFiEspClient client;
// LCD Display
#define DHT_SENSOR_TYPE DHT_TYPE_11
static const int DHT_SENSOR_PIN = A1;
DHT_nonblocking dht_sensor(DHT_SENSOR_PIN, DHT_SENSOR_TYPE);
LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // RS, EN, D4, D5, D6, D7
// Light sensor and LEDs
int lightPin = A0; // LDR
int dataPin = 4; // DS
int latchPin = 5; // ST_CP
int clockPin = 6; // SH_CP
int leds = 0;
// API
const float NO_TEMP = -999.0;
const unsigned long API_INTERVAL = 60000UL; // 60s
const unsigned long RETRY_INTERVAL = 30000UL; // 30s
unsigned long lastApiFetch = 0;
unsigned long fetchInterval = API_INTERVAL;
float outdoorTemp = NO_TEMP;
// MOSFET module (heating elements)
const int mosfetPin = 13;
unsigned long previousMosfetMillis = 0;
bool mosfetState = true;
const unsigned long mosfetOnTime = 60000UL; // 60 seconds ON
const unsigned long mosfetOffTime = 60000UL; // 60 seconds OFF
// Store the indoor temp
float lastIndoorTemp = NO_TEMP;
// Connect to hotspot if not connected, then fetch the current temperature
float fetchOutdoorTemp() {
if (WiFi.status() != WL_CONNECTED) {
WiFi.begin(wifiSSID, wifiPASS);
if (WiFi.status() != WL_CONNECTED) return NO_TEMP;
}
client.setTimeout(5000);
if (!client.connect("api.open-meteo.com", 80)) return NO_TEMP;
client.print(F("GET /v1/forecast?latitude=49.46998&longitude=8.4819&current=temperature_2m HTTP/1.1\r\n"
"Host: api.open-meteo.com\r\n"
"Connection: close\r\n"
"\r\n"));
float t = NO_TEMP;
if (client.find("\"current\":") && client.find("\"temperature_2m\":")) {
t = client.parseFloat();
}
client.stop();
return t;
}
// Write to LCD display
void lcdLine(uint8_t row, const char *text) {
lcd.setCursor(0, row);
uint8_t i = 0;
for (; text[i] != '\0' && i < 16; i++) lcd.write(text[i]);
for (; i < 16; i++) lcd.write(' ');
}
// LEDs for light sensor
void updateShiftRegister() {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, leds);
digitalWrite(latchPin, HIGH);
}
// Measure temperature
static bool measure_environment(float *temp, float *hum) {
static unsigned long timestamp = millis();
// FIXED syntax error below
if (millis() - timestamp > 3000ul) {
if (dht_sensor.measure(temp, hum) == true) {
timestamp = millis();
return true;
}
}
return false;
}
void setup() {
pinMode(latchPin, OUTPUT);
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(mosfetPin, OUTPUT);
Serial.begin(115200);
lcd.begin(16, 2);
lcdLine(0, "Connecting WiFi");
lcdLine(1, "");
wifiSerial.begin(9600);
WiFi.init(&wifiSerial);
if (WiFi.status() == WL_NO_SHIELD) {
lcdLine(0, "ESP not found");
delay(2000);
}
outdoorTemp = fetchOutdoorTemp();
lastApiFetch = millis();
fetchInterval = (outdoorTemp == NO_TEMP) ? RETRY_INTERVAL : API_INTERVAL;
lcd.clear();
digitalWrite(mosfetPin, HIGH);
mosfetState = true;
previousMosfetMillis = millis();
}
void loop() {
unsigned long currentMillis = millis();
// MOSFET timer
if (mosfetState) {
if (currentMillis - previousMosfetMillis >= mosfetOnTime) {
mosfetState = false;
previousMosfetMillis = currentMillis;
digitalWrite(mosfetPin, LOW);
}
} else {
if (currentMillis - previousMosfetMillis >= mosfetOffTime) {
mosfetState = true;
previousMosfetMillis = currentMillis;
digitalWrite(mosfetPin, HIGH);
}
}
unsigned long remainingSeconds = 0;
if (mosfetState) {
remainingSeconds = (mosfetOnTime - (currentMillis - previousMosfetMillis)) / 1000;
} else {
remainingSeconds = (mosfetOffTime - (currentMillis - previousMosfetMillis)) / 1000;
}
// Indoor temp
float indoorTemp, indoorHum;
if (measure_environment(&indoorTemp, &indoorHum) == true) {
lastIndoorTemp = indoorTemp;
}
// LCD row 0 (Temp + Countdown)
char line0[20];
if (lastIndoorTemp != NO_TEMP) {
char tempStr[6];
dtostrf(lastIndoorTemp, 4, 1, tempStr);
// Formats into exactly 16 chars: "In:22.5C ON 10"
snprintf(line0, sizeof(line0), "In:%sC %s %2lu", tempStr, mosfetState ? "ON " : "OFF", remainingSeconds);
} else {
snprintf(line0, sizeof(line0), "In:--- C %s %2lu", mosfetState ? "ON " : "OFF", remainingSeconds);
}
lcdLine(0, line0);
// API outdoor temp
if (currentMillis - lastApiFetch >= fetchInterval) {
float t = fetchOutdoorTemp();
lastApiFetch = currentMillis;
if (t != NO_TEMP) {
outdoorTemp = t;
fetchInterval = API_INTERVAL;
} else {
fetchInterval = RETRY_INTERVAL;
}
}
// LCD row 1
if (outdoorTemp != NO_TEMP) {
char outStr[10];
dtostrf(outdoorTemp, 4, 1, outStr);
char line1[20];
snprintf(line1, sizeof(line1), "Out: %s C", outStr);
lcdLine(1, line1);
} else {
lcdLine(1, "Out: API Error");
}
// Light sensor LEDs
int reading = analogRead(lightPin);
int numLEDSLit = reading / 57;
if (numLEDSLit > 8) numLEDSLit = 8;
leds = 0;
for (int i = 0; i < numLEDSLit; i++) {
leds = leds + (1 << i);
}
updateShiftRegister();
delay(100);
}