#include #include #include #include // 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¤t=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); }