/* Wemos8266RelaysLedDisplay/main.cpp * (C) Dirk Jahnke */ #define COMPDATE __DATE__ __TIME__ // Following defines are set by build environment using -D parameter // #define APP_VERSION "0.2.18" // #define FS_UPDATE_BASE_URL "http://ota.iotjunkie.org/fc_client" // #define FS_UPDATE_AUTH_USER "fcclient" // #define FS_UPDATE_AUTH_PASSWORD "63Gs59PWveT6uQSh" #include #include #include #include #include #include #include "WebServer.h" #include #include "Relays.h" #include "Clock.h" #include "Display.h" #include "FSUpdater.h" // Button pin on the esp for selecting modes. 0 for Generic devices! #define MODEBUTTON D3 //#define RELAY1_PIN D1 //#define RELAY2_PIN D2 #define DEBUG_RELAYS false #define DEBUG_DISPLAY false #define STARTUP1_ANIMATION_DURATION_ms 1000 #define STARTUP2_ANIMATION_DURATION_ms 33000 IOTAppStory IAS(COMPDATE, MODEBUTTON); String deviceName = "wemosMatrixDisplay"; String chipId; Clock realTime("real"); Clock modelTime("Fremo"); Relays R; WebServer W(&R, &realTime, &modelTime); Display D(&realTime, &modelTime); WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000); FSUpdater fsUpdater(FS_UPDATE_BASE_URL, APP_VERSION, FS_UPDATE_AUTH_USER, FS_UPDATE_AUTH_PASSWORD); #define mkstring(x) #x // Field default values #define CLOCK_NAME_LEN 8 #define CLOCK_SPEED_LEN 4 #define RELAY_PIN_LEN 2 #define RELAY_TIMING_LEN 3 #define CLOCK_NAME_DISPLAY_TIMING_LEN 5 static char def_clockName[CLOCK_NAME_LEN+1] = "FREMO"; static char def_clockSpeed_modelMsPerRealSec_String[CLOCK_SPEED_LEN+1] = "250"; static char def_relay1Pin_String[RELAY_PIN_LEN+1] = mkstring(D1); static char def_relay2Pin_String[RELAY_PIN_LEN+1] = mkstring(D2); static int relay1Pin = D1, relay2Pin = D2; static char def_relayHoldTime_ms_String[RELAY_TIMING_LEN+1] = "200"; static char def_relayMinOffTime_ms_String[RELAY_TIMING_LEN+1] = "100"; // Clock Display Config Parameter static char def_displayClockNameEvery_ms_String[CLOCK_NAME_DISPLAY_TIMING_LEN+1] = "16000"; static char def_displayClockNameDuration_ms_String[CLOCK_NAME_DISPLAY_TIMING_LEN+1] = "1200"; static char *clockName = def_clockName; static char *clockSpeed_modelMsPerRealSec_String = def_clockSpeed_modelMsPerRealSec_String; static char *relay1Pin_String = def_relay1Pin_String; static char *relay2Pin_String = def_relay2Pin_String; static char *relayHoldTime_ms_String = def_relayHoldTime_ms_String; static char *relayMinOffTime_ms_String = def_relayMinOffTime_ms_String; static char *displayClockNameEvery_ms_String = def_displayClockNameEvery_ms_String; static char *displayClockNameDuration_ms_String = def_displayClockNameDuration_ms_String; void setupIAS(void) { #if defined ESP8266 // creat a unique deviceName for classroom situations (deviceName-123) chipId = String(ESP.getChipId()); chipId = "-"+chipId.substring(chipId.length()-3); deviceName += chipId; #endif // preset deviceName this is also your MDNS responder: http://deviceName.local IAS.preSetDeviceName(deviceName); IAS.preSetAppName(F("Wemos2RelaysMatrixDisplays")); IAS.preSetAppVersion(F(APP_VERSION)); IAS.preSetAutoUpdate(true); // define fields IAS.addField(clockName, "Clock Name", CLOCK_NAME_LEN, 'T'); IAS.addField(clockSpeed_modelMsPerRealSec_String, "Model MilliSec per Real Sec", CLOCK_SPEED_LEN, 'N'); IAS.addField(displayClockNameEvery_ms_String, "Display clock name every (ms)", CLOCK_NAME_DISPLAY_TIMING_LEN, 'N'); IAS.addField(displayClockNameDuration_ms_String, "Display clock name duration (ms)", CLOCK_NAME_DISPLAY_TIMING_LEN, 'N'); IAS.addField(relay1Pin_String, "Pin Relay 1", RELAY_PIN_LEN, 'P'); IAS.addField(relay2Pin_String, "Pin Relay 2", RELAY_PIN_LEN, 'P'); IAS.addField(relayHoldTime_ms_String, "Relay hold time (ms)", RELAY_TIMING_LEN, 'N'); IAS.addField(relayMinOffTime_ms_String, "Relay min off time (ms)", RELAY_TIMING_LEN, 'N'); IAS.onModeButtonShortPress([]() { Serial.println(F(" If mode button is released, I will enter firmware update mode.")); Serial.println(F("*----------------------------------------------------------------------*")); D.print("|updt"); }); IAS.onModeButtonLongPress([]() { Serial.println(F(" If mode button is released, I will enter configuration mode.")); Serial.println(F("*----------------------------------------------------------------------*")); D.print("|cfg"); }); IAS.onFirstBoot([]() { Serial.println(F(" Manual reset necessary after serial upload!")); Serial.println(F("*----------------------------------------------------------------------*")); D.print("|rst"); ESP.reset(); }); IAS.onConfigMode([]() { D.print(" WiFi"); delay(400); D.print(":" + chipId); Serial.print(F("Entered config mode for Wifi, device=")); Serial.println(chipId); }); IAS.onFirmwareUpdateCheck([]() { // D.print("chk upd"); Serial.println(F("Firmware update check")); }); IAS.onFirmwareUpdateDownload([]() { D.print("dl+instl"); Serial.println(F("Download and install new firmware")); }); IAS.onFirmwareUpdateError([]() { // D.print("Err fwu"); Serial.println(F("Firmware update error")); }); // Optional parameter: What to do with EEPROM on First boot of the app? // 'F' Fully erase | 'P' Partial erase(default) | 'L' Leave intact IAS.begin('L'); delay(500); // Set to true to enable calling home frequently (disabled by default) IAS.setCallHome(true); // Call home interval in seconds, use 60s only for development. // Please change it to at least 2 hours in production IAS.setCallHomeInterval(120); // IAS.callHome(true /*SPIFFS-check*/); modelTime.setSpeed_modelMsPerRealSecond(atoi(clockSpeed_modelMsPerRealSec_String)); relay1Pin = IAS.dPinConv(relay1Pin_String); relay2Pin = IAS.dPinConv(relay2Pin_String); R.setHoldTime_ms(atoi(relayHoldTime_ms_String)); R.setMinOffTime_ms(atoi(relayMinOffTime_ms_String)); D.setClockNameDisplayEvery_ms(atoi(displayClockNameEvery_ms_String)); D.setClockNameDurationTime_ms(atoi(displayClockNameDuration_ms_String)); Serial.println(F("Configuration used:")); Serial.print(F("Relay1 Pin: ")); Serial.println(relay1Pin); Serial.print(F("Relay2 Pin: ")); Serial.println(relay2Pin); Serial.print(F("Relay hold time (ms): ")); Serial.println(relayHoldTime_ms_String); Serial.print(F("Relay min off time (ms): ")); Serial.println(relayMinOffTime_ms_String); Serial.print(F("Clock speed (model ms per real time s): ")); Serial.println(clockSpeed_modelMsPerRealSec_String); Serial.print(F("Show clock name every (ms): ")); Serial.println(displayClockNameEvery_ms_String); Serial.print(F("Show clock name for (ms): ")); Serial.println(displayClockNameDuration_ms_String); } void setupFS() { if(!SPIFFS.begin()){ Serial.println(F(" SPIFFS Mount Failed")); return; } } void setup(void) { Serial.println(F("setup():")); D.begin(); setupFS(); setupIAS(); W.begin(); delay(100); R.begin(relay1Pin, relay2Pin); timeClient.begin(); Serial.println(F("setup() finished")); } static bool timeClientInitialized = false; static unsigned long lastTimeOutput_ms = 0; #define TIME_BETWEEN_REALTIME_UPDATE_ms 60000 void loop(void) { static unsigned int lastMinutes = 0; static unsigned long lastIASLoop_ts = 0; #define CALL_IAS_EVERY_ms 100 static unsigned long firstLoop_ts = 0; if (firstLoop_ts == 0) firstLoop_ts = millis(); if (!timeClientInitialized && WiFi.status() == WL_CONNECTED) { timeClient.begin(); timeClientInitialized = true; timeClient.update(); Serial.println(timeClient.getFormattedTime()); lastTimeOutput_ms = millis(); } if (millis() - lastIASLoop_ts > CALL_IAS_EVERY_ms) { IAS.loop(); lastIASLoop_ts = millis(); } if (timeClientInitialized && millis()-lastTimeOutput_ms > TIME_BETWEEN_REALTIME_UPDATE_ms) { timeClient.update(); Serial.print("t-update: "); Serial.println(timeClient.getFormattedTime()); lastTimeOutput_ms = millis(); } if (millis() < firstLoop_ts + STARTUP1_ANIMATION_DURATION_ms) { // Startup phase 1: Constant display of content, created during setup() return; } if (millis() < firstLoop_ts + STARTUP1_ANIMATION_DURATION_ms + STARTUP2_ANIMATION_DURATION_ms) { D.loopEyeAnimation(); return; } if (timeClientInitialized) { realTime.setTime(timeClient.getHours(), timeClient.getMinutes(), timeClient.getSeconds()); } else { realTime.setTime((millis() / 60 * 60 * 1000) % 24, (millis() / 60 * 1000) % 60, (millis() / 1000) % 60); } D.loop(); // toggle relays on minute change if (lastMinutes != realTime.getMinutes()) { R.toggle(); lastMinutes = realTime.getMinutes(); } R.loop(); }