#include #include #include #include #include // Hardware configuration #define STOP_RAIN_PIN D6 #define LED_PIN D4 #define NUM_LEDS 3 #define BRIGHTNESS 64 #define LED_TYPE WS2812B #define COLOR_ORDER GRB // Define raindrop parameters #define MAX_DROPS 1 #define DROP_FADE 20 #define DROP_SPEED 1 // Display time per message (in milliseconds) #define DISPLAY_TIME 10000 // Wifi connection parameters const char *ssid = "My.Network2.4G"; const char *password = "026322113"; const char *mqtt_server = "91.121.93.94"; // test.mosquitto.org // MQTT client WiFiClient espClient; PubSubClient client(espClient); unsigned long lastMsg = 0; #define MSG_BUFFER_SIZE (50) char msg[MSG_BUFFER_SIZE]; // Message queue const int MAX_QUEUE_SIZE = 10; String messageQueue[MAX_QUEUE_SIZE]; int queueSize = 0; unsigned long previousDisplayTime = 0; // Effects modes enum EffectMode { GREEN_STATIC, RED_STATIC, BLUE_STATIC, RAINBOW }; // Current effect mode EffectMode currentEffectMode = GREEN_STATIC; // LCD display LiquidCrystal_I2C lcd(0x27, 16, 2); // Global variables required for rain effect (do not modify) struct Raindrop { int position; int intensity; }; Raindrop drops[MAX_DROPS]; int dropTs = 0; int rainingCountdown = 0; CRGB leds[NUM_LEDS]; void enqueueMessage(String message) { if (queueSize < MAX_QUEUE_SIZE) { messageQueue[queueSize++] = message; } } String dequeueMessage() { String dequeuedMessage = ""; if (queueSize > 0) { dequeuedMessage = messageQueue[0]; for (int i = 0; i < queueSize - 1; i++) { messageQueue[i] = messageQueue[i + 1]; } queueSize--; } return dequeuedMessage; } void normalModeEffects() { FastLED.clear(); if (currentEffectMode == GREEN_STATIC) { fill_solid(leds, NUM_LEDS, CRGB(0, 255, 0)); // Green } if (currentEffectMode == RED_STATIC) { fill_solid(leds, NUM_LEDS, CRGB(255, 0, 0)); // Red } if (currentEffectMode == BLUE_STATIC) { fill_solid(leds, NUM_LEDS, CRGB(0, 0, 255)); // Blue } if (currentEffectMode == RAINBOW) { static uint8_t hue = 0; fill_rainbow(leds, NUM_LEDS, hue, 255 / NUM_LEDS); hue+=3; } FastLED.show(); } void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void callback(char *topic, byte *payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); if ((char)payload[0] == 'r') { rainingCountdown = millis() + DISPLAY_TIME; enqueueMessage("It gonna rain!"); } } bool isRaining() { return millis() < rainingCountdown; } void reconnect() { while (!client.connected()) { Serial.print("Attempting MQTT connection..."); String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); if (client.connect(clientId.c_str())) { client.subscribe("weather-project/data"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); delay(5000); } } } void IRAM_ATTR stopButtonPressed() { if (isRaining()) { Serial.println("Stop button pressed"); rainingCountdown = 0; previousDisplayTime = 0; } else { currentEffectMode = static_cast((currentEffectMode + 1) % 4); } } void displayNextMessage() { if (millis() - previousDisplayTime < DISPLAY_TIME) { return; } // lcd.clear(); if (queueSize > 0) { lcd.clear(); String currentMessage = dequeueMessage(); lcd.setCursor(0, 0); lcd.print(currentMessage); previousDisplayTime = millis(); } else { lcd.setCursor(0, 0); lcd.print("Have a nice day!"); } } void setup() { pinMode(STOP_RAIN_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(STOP_RAIN_PIN), stopButtonPressed, FALLING); pinMode(BUILTIN_LED, OUTPUT); Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); FastLED.addLeds(leds, NUM_LEDS); FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); FastLED.clear(); randomSeed(analogRead(0)); for (int i = 0; i < MAX_DROPS; i++) { drops[i].position = random(NUM_LEDS); drops[i].intensity = random(200, 255); } FastLED.show(); pinMode(LED_BUILTIN, OUTPUT); lcd.begin(); lcd.backlight(); lcd.print("Hello, world!"); currentEffectMode = GREEN_STATIC; } void rainEffect() { if (millis() - dropTs > 100) { for (int i = 0; i < MAX_DROPS; i++) { drops[i].position += DROP_SPEED; if (drops[i].position >= NUM_LEDS) { drops[i].position = random(-10, -1); drops[i].intensity = random(200, 255); } drops[i].intensity -= DROP_FADE; if (drops[i].intensity <= 0) { drops[i].position = random(-10, -1); drops[i].intensity = random(200, 255); } } dropTs = millis(); } FastLED.clear(); for (int i = 0; i < MAX_DROPS; i++) { if (drops[i].position >= 0 && drops[i].position < NUM_LEDS) { leds[drops[i].position] = CRGB::Blue; leds[drops[i].position].fadeToBlackBy(drops[i].intensity); } } FastLED.show(); } void loop() { displayNextMessage(); if (isRaining()) { rainEffect(); } else { normalModeEffects(); } if (!client.connected()) { reconnect(); } client.loop(); }