2019-01-25 12:14:52 +00:00
|
|
|
/* Wemos8266RelaysLedDisplay/main.cpp
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define COMPDATE __DATE__ __TIME__
|
2019-01-29 08:49:11 +00:00
|
|
|
#define APP_VERSION "0.2.18"
|
|
|
|
|
2019-01-25 12:14:52 +00:00
|
|
|
#include <Arduino.h>
|
|
|
|
#include <IOTAppStory.h>
|
|
|
|
#include <NTPClient.h>
|
|
|
|
#include <ESP8266WiFi.h>
|
|
|
|
#include <WiFiUdp.h>
|
2019-01-29 08:49:11 +00:00
|
|
|
#include <FS.h>
|
2019-01-29 12:54:34 +00:00
|
|
|
#include "WebServer.h"
|
2019-01-29 10:26:35 +00:00
|
|
|
#include <ESP8266HTTPClient.h>
|
2019-01-29 08:49:11 +00:00
|
|
|
#include "Relays.h"
|
2019-01-29 12:54:34 +00:00
|
|
|
#include "Clock.h"
|
2019-01-29 14:25:27 +00:00
|
|
|
#include "Display.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 2000
|
|
|
|
#define STARTUP2_ANIMATION_DURATION_ms 33000
|
2019-01-25 12:14:52 +00:00
|
|
|
|
|
|
|
IOTAppStory IAS(COMPDATE, MODEBUTTON);
|
|
|
|
String deviceName = "wemosMatrixDisplay";
|
|
|
|
String chipId;
|
|
|
|
|
2019-01-29 12:54:34 +00:00
|
|
|
Clock realTime("real");
|
|
|
|
Clock modelTime("Fremo");
|
2019-01-25 12:14:52 +00:00
|
|
|
|
2019-01-29 08:49:11 +00:00
|
|
|
Relays R;
|
2019-01-29 12:54:34 +00:00
|
|
|
WebServer W(&R, &realTime, &modelTime);
|
2019-01-29 14:25:27 +00:00
|
|
|
Display D(&realTime, &modelTime);
|
2019-01-25 12:14:52 +00:00
|
|
|
|
|
|
|
WiFiUDP ntpUDP;
|
|
|
|
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
|
2019-01-29 12:54:34 +00:00
|
|
|
|
2019-01-29 14:25:27 +00:00
|
|
|
#define mkstring(x) #x
|
2019-01-25 12:14:52 +00:00
|
|
|
|
|
|
|
// Field default values
|
2019-01-25 19:23:10 +00:00
|
|
|
char *clockName = "FREMO";
|
2019-01-25 12:14:52 +00:00
|
|
|
char *clockSpeed_modelMsPerRealSec_String = "250";
|
2019-01-29 14:25:27 +00:00
|
|
|
char *relay1Pin_String = mkstring(RELAY1_PIN);
|
|
|
|
char *relay2Pin_String = mkstring(RELAY2_PIN);
|
|
|
|
int relay1Pin = RELAY1_PIN, relay2Pin = RELAY2_PIN;
|
2019-01-25 12:14:52 +00:00
|
|
|
char *relayHoldTime_ms_String = "200";
|
|
|
|
char *relayMinOffTime_ms_String = "100";
|
|
|
|
|
2019-01-25 19:23:10 +00:00
|
|
|
// Clock Display Config Parameter
|
|
|
|
static char * displayClockNameEvery_ms_String = "16000";
|
|
|
|
static char * displayClockNameDuration_ms_String = "1200";
|
2019-01-25 12:14:52 +00:00
|
|
|
|
|
|
|
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"));
|
2019-01-29 08:49:11 +00:00
|
|
|
IAS.preSetAppVersion(F(APP_VERSION));
|
2019-01-25 12:14:52 +00:00
|
|
|
IAS.preSetAutoUpdate(true);
|
|
|
|
|
|
|
|
// define fields
|
|
|
|
IAS.addField(clockName, "Clock Name", 8, 'T');
|
|
|
|
IAS.addField(clockSpeed_modelMsPerRealSec_String, "Model MilliSec per Real Sec", 8, 'N');
|
2019-01-25 19:23:10 +00:00
|
|
|
IAS.addField(displayClockNameEvery_ms_String, "Display clock name every (ms)", 5, 'N');
|
|
|
|
IAS.addField(displayClockNameDuration_ms_String, "Display clock name duration (ms)", 5, 'N');
|
2019-01-25 12:14:52 +00:00
|
|
|
IAS.addField(relay1Pin_String, "Pin Relay 1", 2, 'P');
|
|
|
|
IAS.addField(relay2Pin_String, "Pin Relay 2", 2, 'P');
|
|
|
|
IAS.addField(relayHoldTime_ms_String, "Relay hold time (ms)", 3, 'N');
|
|
|
|
IAS.addField(relayMinOffTime_ms_String, "Relay min off time (ms)", 3, 'N');
|
|
|
|
|
|
|
|
IAS.onModeButtonShortPress([]() {
|
2019-01-28 11:22:08 +00:00
|
|
|
Serial.println(F(" If mode button is released, I will enter firmware update mode."));
|
|
|
|
Serial.println(F("*----------------------------------------------------------------------*"));
|
2019-01-29 14:25:27 +00:00
|
|
|
D.print("|updt");
|
2019-01-25 12:14:52 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
IAS.onModeButtonLongPress([]() {
|
2019-01-28 11:22:08 +00:00
|
|
|
Serial.println(F(" If mode button is released, I will enter configuration mode."));
|
|
|
|
Serial.println(F("*----------------------------------------------------------------------*"));
|
2019-01-29 14:25:27 +00:00
|
|
|
D.print("|cfg");
|
2019-01-25 12:14:52 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
IAS.onFirstBoot([]() {
|
|
|
|
Serial.println(F(" Manual reset necessary after serial upload!"));
|
2019-01-28 11:22:08 +00:00
|
|
|
Serial.println(F("*----------------------------------------------------------------------*"));
|
2019-01-29 14:25:27 +00:00
|
|
|
D.print("|rst");
|
2019-01-25 12:14:52 +00:00
|
|
|
ESP.reset();
|
|
|
|
});
|
|
|
|
|
|
|
|
IAS.onConfigMode([]() {
|
2019-01-29 14:25:27 +00:00
|
|
|
D.print(" WiFi");
|
2019-01-25 12:14:52 +00:00
|
|
|
delay(400);
|
2019-01-29 14:25:27 +00:00
|
|
|
D.print(":" + chipId);
|
2019-01-25 12:14:52 +00:00
|
|
|
Serial.print(F("Entered config mode for Wifi, device=")); Serial.println(chipId);
|
|
|
|
});
|
|
|
|
|
|
|
|
IAS.onFirmwareUpdateCheck([]() {
|
2019-01-29 14:25:27 +00:00
|
|
|
// D.print("chk upd");
|
2019-01-25 12:14:52 +00:00
|
|
|
Serial.println(F("Firmware update check"));
|
|
|
|
});
|
|
|
|
|
|
|
|
IAS.onFirmwareUpdateDownload([]() {
|
2019-01-29 14:25:27 +00:00
|
|
|
D.print("dl+instl");
|
2019-01-25 12:14:52 +00:00
|
|
|
Serial.println(F("Download and install new firmware"));
|
|
|
|
});
|
|
|
|
|
|
|
|
IAS.onFirmwareUpdateError([]() {
|
2019-01-29 14:25:27 +00:00
|
|
|
// D.print("Err fwu");
|
2019-01-25 12:14:52 +00:00
|
|
|
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);
|
2019-01-29 10:26:35 +00:00
|
|
|
IAS.callHome(true /*SPIFFS-check*/);
|
2019-01-29 14:25:27 +00:00
|
|
|
modelTime.setSpeed_modelMsPerRealSecond(atoi(clockSpeed_modelMsPerRealSec_String));
|
2019-01-25 12:14:52 +00:00
|
|
|
relay1Pin = IAS.dPinConv(relay1Pin_String);
|
|
|
|
relay2Pin = IAS.dPinConv(relay2Pin_String);
|
2019-01-29 08:49:11 +00:00
|
|
|
R.setHoldTime_ms(atoi(relayHoldTime_ms_String));
|
|
|
|
R.setMinOffTime_ms(atoi(relayMinOffTime_ms_String));
|
2019-01-29 14:25:27 +00:00
|
|
|
D.setClockNameDisplayEvery_ms(atoi(displayClockNameEvery_ms_String));
|
|
|
|
D.setClockNameDurationTime_ms(atoi(displayClockNameDuration_ms_String));
|
2019-01-25 12:14:52 +00:00
|
|
|
|
|
|
|
Serial.println(F("Configuration used:"));
|
|
|
|
Serial.print(F("Relay1 Pin: ")); Serial.println(relay1Pin);
|
|
|
|
Serial.print(F("Relay2 Pin: ")); Serial.println(relay2Pin);
|
2019-01-29 08:49:11 +00:00
|
|
|
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);
|
2019-01-29 14:25:27 +00:00
|
|
|
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);
|
2019-01-25 12:14:52 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 11:22:08 +00:00
|
|
|
|
2019-01-29 08:49:11 +00:00
|
|
|
void setupFS() {
|
|
|
|
if(!SPIFFS.begin()){
|
|
|
|
Serial.println(F(" SPIFFS Mount Failed"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-25 12:14:52 +00:00
|
|
|
void setup(void)
|
|
|
|
{
|
|
|
|
Serial.println(F("setup():"));
|
2019-01-29 14:25:27 +00:00
|
|
|
D.begin();
|
2019-01-29 08:49:11 +00:00
|
|
|
setupFS();
|
2019-01-29 10:26:35 +00:00
|
|
|
setupIAS();
|
2019-01-29 12:54:34 +00:00
|
|
|
W.begin();
|
|
|
|
delay(100);
|
2019-01-29 08:49:11 +00:00
|
|
|
R.begin(relay1Pin, relay2Pin);
|
2019-01-25 12:14:52 +00:00
|
|
|
timeClient.begin();
|
|
|
|
Serial.println(F("setup() finished"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool timeClientInitialized = false;
|
|
|
|
static unsigned long lastTimeOutput_ms = 0;
|
2019-01-28 11:22:08 +00:00
|
|
|
#define TIME_BETWEEN_REALTIME_UPDATE_ms 60000
|
2019-01-25 12:14:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
void loop(void)
|
|
|
|
{
|
|
|
|
static int lastMinutes = 0;
|
|
|
|
|
2019-01-28 11:22:08 +00:00
|
|
|
static unsigned long firstLoop_ts = 0;
|
|
|
|
if (firstLoop_ts == 0) firstLoop_ts = millis();
|
|
|
|
|
2019-01-25 12:14:52 +00:00
|
|
|
if (!timeClientInitialized && WiFi.status() == WL_CONNECTED) {
|
|
|
|
timeClient.begin();
|
|
|
|
timeClientInitialized = true;
|
2019-01-28 11:22:08 +00:00
|
|
|
timeClient.update();
|
|
|
|
Serial.println(timeClient.getFormattedTime());
|
|
|
|
lastTimeOutput_ms = millis();
|
2019-01-25 12:14:52 +00:00
|
|
|
}
|
|
|
|
IAS.loop();
|
|
|
|
|
2019-01-28 11:22:08 +00:00
|
|
|
if (timeClientInitialized && millis()-lastTimeOutput_ms > TIME_BETWEEN_REALTIME_UPDATE_ms) {
|
2019-01-25 12:14:52 +00:00
|
|
|
timeClient.update();
|
|
|
|
Serial.println(timeClient.getFormattedTime());
|
|
|
|
lastTimeOutput_ms = millis();
|
|
|
|
}
|
|
|
|
|
2019-01-28 11:22:08 +00:00
|
|
|
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) {
|
2019-01-29 14:25:27 +00:00
|
|
|
D.loopEyeAnimation();
|
2019-01-28 11:22:08 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-25 12:14:52 +00:00
|
|
|
if (timeClientInitialized) {
|
2019-01-29 14:25:27 +00:00
|
|
|
realTime.setTime(timeClient.getHours(), timeClient.getMinutes(), timeClient.getSeconds());
|
2019-01-25 19:23:10 +00:00
|
|
|
} else {
|
2019-01-29 14:25:27 +00:00
|
|
|
realTime.setTime((millis() / 60 * 60 * 1000) % 24, (millis() / 60 * 1000) % 60, (millis() / 1000) % 60);
|
2019-01-25 19:23:10 +00:00
|
|
|
}
|
|
|
|
|
2019-01-29 14:25:27 +00:00
|
|
|
D.loop();
|
|
|
|
|
2019-01-25 12:14:52 +00:00
|
|
|
// toggle relays
|
2019-01-29 14:25:27 +00:00
|
|
|
if (lastMinutes != realTime.getMinutes()) {
|
2019-01-29 08:49:11 +00:00
|
|
|
R.toggle();
|
2019-01-29 14:25:27 +00:00
|
|
|
lastMinutes = realTime.getMinutes();
|
2019-01-25 12:14:52 +00:00
|
|
|
}
|
|
|
|
|
2019-01-29 08:49:11 +00:00
|
|
|
R.loop();
|
2019-01-25 12:14:52 +00:00
|
|
|
}
|