Added robot eye animation. Made some cleanups.
This commit is contained in:
193
src/main.cpp
193
src/main.cpp
@@ -4,7 +4,6 @@
|
||||
#define COMPDATE __DATE__ __TIME__
|
||||
// Button pin on the esp for selecting modes. 0 for Generic devices!
|
||||
#define MODEBUTTON D3
|
||||
|
||||
#define RELAY1_PIN D1
|
||||
#define RELAY2_PIN D2
|
||||
#define DISPLAY_CLK_PIN D5
|
||||
@@ -13,7 +12,8 @@
|
||||
#define VERTICAL_BAR_STARTS_TOP false
|
||||
#define DEBUG_RELAYS false
|
||||
#define DEBUG_DISPLAY false
|
||||
#define DEBUG_LVL 0
|
||||
#define STARTUP1_ANIMATION_DURATION_ms 15000
|
||||
#define STARTUP2_ANIMATION_DURATION_ms 45000
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <IOTAppStory.h>
|
||||
@@ -23,12 +23,11 @@
|
||||
#include <NTPClient.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
#include "MD_RobotEyes.h"
|
||||
|
||||
IOTAppStory IAS(COMPDATE, MODEBUTTON);
|
||||
String deviceName = "wemosMatrixDisplay";
|
||||
String chipId;
|
||||
const uint16_t WAIT_TIME = 1000;
|
||||
|
||||
// Define the number of devices we have in the chain and the hardware interface
|
||||
// NOTE: These pin numbers will probably not work with your hardware and may
|
||||
@@ -47,14 +46,12 @@ Your hardware matches the setting for FC-16 modules. Please set FC16_HW.
|
||||
|
||||
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
|
||||
#define MAX_DEVICES 4
|
||||
#define CLK_PIN DISPLAY_CLK_PIN
|
||||
#define DATA_PIN DISPLAY_DATA_PIN
|
||||
#define CS_PIN DISPLAY_CS_PIN
|
||||
|
||||
// Hardware SPI connection
|
||||
// MD_Parola P = MD_Parola(HARDWARE_TYPE, DISPLAY_CS_PIN, MAX_DEVICES);
|
||||
// Arbitrary output pins
|
||||
MD_Parola P = MD_Parola(HARDWARE_TYPE, DISPLAY_DATA_PIN, DISPLAY_CLK_PIN, DISPLAY_CS_PIN, MAX_DEVICES);
|
||||
MD_RobotEyes E;
|
||||
|
||||
WiFiUDP ntpUDP;
|
||||
NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", 3600, 60000);
|
||||
@@ -67,10 +64,10 @@ char *relay1Pin_String = "D1";
|
||||
char *relay2Pin_String = "D2";
|
||||
int relay1Pin = D1, relay2Pin = D2;
|
||||
char *relayHoldTime_ms_String = "200";
|
||||
int relayHoldTime_ms = 200;
|
||||
unsigned int relayHoldTime_ms = 200;
|
||||
char *relayMinOffTime_ms_String = "100";
|
||||
int relayMinOffTime_ms = 100;
|
||||
int displayRefresh_ms = 200;
|
||||
unsigned int relayMinOffTime_ms = 100;
|
||||
unsigned int displayRefresh_ms = 200;
|
||||
|
||||
// Clock Display Config Parameter
|
||||
static char * displayClockNameEvery_ms_String = "16000";
|
||||
@@ -90,7 +87,7 @@ void setupIAS(void) {
|
||||
// preset deviceName this is also your MDNS responder: http://deviceName.local
|
||||
IAS.preSetDeviceName(deviceName);
|
||||
IAS.preSetAppName(F("Wemos2RelaysMatrixDisplays"));
|
||||
IAS.preSetAppVersion(F("0.0.1"));
|
||||
IAS.preSetAppVersion(F("0.2.1"));
|
||||
IAS.preSetAutoUpdate(true);
|
||||
|
||||
// define fields
|
||||
@@ -104,43 +101,43 @@ void setupIAS(void) {
|
||||
IAS.addField(relayMinOffTime_ms_String, "Relay min off time (ms)", 3, 'N');
|
||||
|
||||
IAS.onModeButtonShortPress([]() {
|
||||
Serial.println(F(" If mode button is released, I will enter in firmware update mode."));
|
||||
Serial.println(F("*-------------------------------------------------------------------------*"));
|
||||
Serial.println(F(" If mode button is released, I will enter firmware update mode."));
|
||||
Serial.println(F("*----------------------------------------------------------------------*"));
|
||||
P.print("|updt");
|
||||
});
|
||||
|
||||
IAS.onModeButtonLongPress([]() {
|
||||
Serial.println(F(" If mode button is released, I will enter in configuration mode."));
|
||||
Serial.println(F("*-------------------------------------------------------------------------*"));
|
||||
Serial.println(F(" If mode button is released, I will enter configuration mode."));
|
||||
Serial.println(F("*----------------------------------------------------------------------*"));
|
||||
P.print("|cfg");
|
||||
});
|
||||
|
||||
IAS.onFirstBoot([]() {
|
||||
Serial.println(F(" Manual reset necessary after serial upload!"));
|
||||
Serial.println(F("*-------------------------------------------------------------------------*"));
|
||||
Serial.println(F("*----------------------------------------------------------------------*"));
|
||||
P.print("|rst");
|
||||
ESP.reset();
|
||||
});
|
||||
|
||||
IAS.onConfigMode([]() {
|
||||
P.print("WiFi");
|
||||
P.print(" WiFi");
|
||||
delay(400);
|
||||
P.print("*" + chipId);
|
||||
P.print(":" + chipId);
|
||||
Serial.print(F("Entered config mode for Wifi, device=")); Serial.println(chipId);
|
||||
});
|
||||
|
||||
IAS.onFirmwareUpdateCheck([]() {
|
||||
P.print("chk upd");
|
||||
// P.print("chk upd");
|
||||
Serial.println(F("Firmware update check"));
|
||||
});
|
||||
|
||||
IAS.onFirmwareUpdateDownload([]() {
|
||||
P.print("dl&instl");
|
||||
P.print("dl+instl");
|
||||
Serial.println(F("Download and install new firmware"));
|
||||
});
|
||||
|
||||
IAS.onFirmwareUpdateError([]() {
|
||||
P.print("Err fwu");
|
||||
// P.print("Err fwu");
|
||||
Serial.println(F("Firmware update error"));
|
||||
});
|
||||
|
||||
@@ -180,6 +177,8 @@ void setupRelays(int relay1Pin, int relay2Pin) {
|
||||
digitalWrite(relay2Pin, LOW);
|
||||
}
|
||||
|
||||
static MD_MAX72XX *graphicDisplay = NULL;
|
||||
|
||||
void setupDisplay() {
|
||||
int charCode;
|
||||
#if VERTICAL_BAR_STARTS_TOP
|
||||
@@ -211,6 +210,9 @@ void setupDisplay() {
|
||||
|
||||
P.begin();
|
||||
// P.setZoneEffect(0, true, PA_FLIP_LR);
|
||||
graphicDisplay = P.getGraphicObject();
|
||||
E.begin(graphicDisplay);
|
||||
|
||||
P.setIntensity(1);
|
||||
for (charCode=1; charCode<=9; ++charCode) {
|
||||
P.addChar(charCode, verticalBarFont+2*(charCode-1));
|
||||
@@ -221,14 +223,15 @@ void setupDisplay() {
|
||||
P.addChar('0', newZero);
|
||||
P.print(intro);
|
||||
}
|
||||
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
Serial.println(F("setup():"));
|
||||
setupDisplay();
|
||||
setupIAS();
|
||||
delay(500);
|
||||
delay(200);
|
||||
setupRelays(relay1Pin, relay2Pin);
|
||||
delay(500);
|
||||
|
||||
timeClient.begin();
|
||||
Serial.println(F("setup() finished"));
|
||||
@@ -237,7 +240,7 @@ void setup(void)
|
||||
|
||||
static bool timeClientInitialized = false;
|
||||
static unsigned long lastTimeOutput_ms = 0;
|
||||
#define TIME_BETWEEN_TIME_REPORTS_ms 60000
|
||||
#define TIME_BETWEEN_REALTIME_UPDATE_ms 60000
|
||||
|
||||
static unsigned long last_relay_off_ts=0, last_relay_hold_ts=0;
|
||||
enum RelayState { RELAY_STATE_OFF=0, RELAY_STATE_ON_EVEN_MINUTE, RELAY_STATE_ON_ODD_MINUTE };
|
||||
@@ -285,6 +288,80 @@ void loopRelays(void) {
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[7];
|
||||
MD_RobotEyes::emotion_t e;
|
||||
uint16_t timePause; // in milliseconds
|
||||
} sampleItem_t;
|
||||
|
||||
static const sampleItem_t eSeq[] =
|
||||
{
|
||||
{ "Nutral", MD_RobotEyes::E_NEUTRAL, 1000 },
|
||||
{ "Blink" , MD_RobotEyes::E_BLINK, 1000 },
|
||||
{ "Wink" , MD_RobotEyes::E_WINK, 1000 },
|
||||
{ "Left" , MD_RobotEyes::E_LOOK_L, 1000 },
|
||||
{ "Right" , MD_RobotEyes::E_LOOK_R, 1000 },
|
||||
{ "Up" , MD_RobotEyes::E_LOOK_U, 1000 },
|
||||
{ "Down" , MD_RobotEyes::E_LOOK_D, 1000 },
|
||||
{ "Angry" , MD_RobotEyes::E_ANGRY, 1000 },
|
||||
{ "Sad" , MD_RobotEyes::E_SAD, 1000 },
|
||||
{ "Evil" , MD_RobotEyes::E_EVIL, 1000 },
|
||||
{ "Evil2" , MD_RobotEyes::E_EVIL2, 1000 },
|
||||
{ "Squint", MD_RobotEyes::E_SQUINT, 1000 },
|
||||
{ "Dead" , MD_RobotEyes::E_DEAD, 1000 },
|
||||
{ "ScanV" , MD_RobotEyes::E_SCAN_UD, 1000 },
|
||||
{ "ScanH" , MD_RobotEyes::E_SCAN_LR, 1000 },
|
||||
};
|
||||
#define DISPLAY_ANIM_NAME false
|
||||
|
||||
void loopStartupAnimation() {
|
||||
// show startup animation
|
||||
boolean animationFinished = false;
|
||||
static uint32_t timeStartDelay;
|
||||
static uint8_t index = ARRAY_SIZE(eSeq);
|
||||
static enum { S_IDLE, S_TEXT, S_ANIM, S_PAUSE } state = S_IDLE;
|
||||
|
||||
animationFinished = E.runAnimation();
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case S_IDLE:
|
||||
index++;
|
||||
if (index >= ARRAY_SIZE(eSeq))
|
||||
index = 0;
|
||||
#if DISPLAY_ANIM_NAME
|
||||
E.setText(eSeq[index].name);
|
||||
#endif
|
||||
state = S_TEXT;
|
||||
break;
|
||||
|
||||
case S_TEXT: // wait for the text to finish
|
||||
if (animationFinished) // text animation is finished
|
||||
{
|
||||
E.setAnimation(eSeq[index].e, true);
|
||||
state = S_ANIM;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_ANIM: // checking animation is completed
|
||||
if (animationFinished) // animation is finished
|
||||
{
|
||||
timeStartDelay = millis();
|
||||
state = S_PAUSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_PAUSE: // non blocking waiting for a period between animations
|
||||
if (millis() - timeStartDelay >= eSeq[index].timePause)
|
||||
state = S_IDLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
state = S_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void loop(void)
|
||||
{
|
||||
@@ -298,17 +375,32 @@ void loop(void)
|
||||
static char debugMsg[MsgSize+1];
|
||||
static int recentDisplayState = -1;
|
||||
|
||||
static unsigned long firstLoop_ts = 0;
|
||||
if (firstLoop_ts == 0) firstLoop_ts = millis();
|
||||
|
||||
if (!timeClientInitialized && WiFi.status() == WL_CONNECTED) {
|
||||
timeClient.begin();
|
||||
timeClientInitialized = true;
|
||||
}
|
||||
IAS.loop();
|
||||
|
||||
if (timeClientInitialized && millis()-lastTimeOutput_ms > TIME_BETWEEN_TIME_REPORTS_ms) {
|
||||
timeClient.update();
|
||||
Serial.println(timeClient.getFormattedTime());
|
||||
lastTimeOutput_ms = millis();
|
||||
}
|
||||
IAS.loop();
|
||||
|
||||
if (timeClientInitialized && millis()-lastTimeOutput_ms > TIME_BETWEEN_REALTIME_UPDATE_ms) {
|
||||
timeClient.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) {
|
||||
loopStartupAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeClientInitialized) {
|
||||
hours = timeClient.getHours();
|
||||
@@ -323,6 +415,8 @@ void loop(void)
|
||||
if (minuteProgressIndicator > 9) minuteProgressIndicator = 9;
|
||||
snprintf(timeBuffer, 10, "%c %2d:%02d", minuteProgressIndicator, hours, minutes);
|
||||
|
||||
//P.displayAnimate();
|
||||
//P.displayClear();
|
||||
/* DEBUG */
|
||||
#if DEBUG_RELAYS
|
||||
if (seconds != lastSeconds) {
|
||||
@@ -346,44 +440,7 @@ void loop(void)
|
||||
#endif
|
||||
/* END DEBUG */
|
||||
|
||||
currentDisplayState = seconds / 5; // Value 0..11
|
||||
|
||||
#if DEBUG_DISPLAY
|
||||
static bool executed = false;
|
||||
if (recentDisplayState != currentDisplayState) executed = false;
|
||||
|
||||
#define ExecOnce(p) {if (!executed) {executed=true; p;}}
|
||||
|
||||
switch (currentDisplayState) {
|
||||
case 0: ExecOnce(P.print(timeBuffer)); break;
|
||||
case 1:
|
||||
snprintf(debugMsg, MsgSize, "%c t%cr%c", minuteProgressIndicator, timeClientInitialized ? 'x':'-', (relaysState == RELAY_STATE_OFF)?'-':(relaysState == RELAY_STATE_ON_EVEN_MINUTE?'e':'o'));
|
||||
ExecOnce(P.print(debugMsg));
|
||||
break;
|
||||
case 2: ExecOnce(P.print(timeBuffer)); break;
|
||||
case 3: // if (lastSeconds != seconds) P.print(seconds); break;
|
||||
case 4: ExecOnce(P.print(timeBuffer)); break;
|
||||
case 5: ExecOnce(P.print(timeBuffer)); break;
|
||||
case 6:
|
||||
switch (minutes % 3) {
|
||||
case 0: snprintf(debugMsg, MsgSize, "%c s%d", minuteProgressIndicator, clockSpeed_modelMsPerRealSec); break;
|
||||
case 1: snprintf(debugMsg, MsgSize, "%c h%d", minuteProgressIndicator, relayHoldTime_ms); break;
|
||||
case 2: snprintf(debugMsg, MsgSize, "%c o%d", minuteProgressIndicator, relayMinOffTime_ms); break;
|
||||
}
|
||||
ExecOnce(P.print(debugMsg));
|
||||
break;
|
||||
case 7: ExecOnce(P.print(timeBuffer)); break;
|
||||
case 8:
|
||||
snprintf(debugMsg, MsgSize, "t%cr%c", timeClientInitialized ? 'x':'-', (relaysState == RELAY_STATE_OFF)?'-':(relaysState == RELAY_STATE_ON_EVEN_MINUTE?'e':'o'));
|
||||
ExecOnce(P.print(debugMsg));
|
||||
break;
|
||||
case 9: ExecOnce(P.print(timeBuffer)); break;
|
||||
case 10: if (lastSeconds != seconds) P.printf("%c %d", minuteProgressIndicator, seconds); break;
|
||||
case 11: ExecOnce(P.print(timeBuffer)); break;
|
||||
default: ExecOnce(P.print("default")); break;
|
||||
}
|
||||
recentDisplayState = currentDisplayState;
|
||||
#else
|
||||
// standard procedure to display
|
||||
static uint32_t last_clock_refresh = 0;
|
||||
static uint32_t lastTimeClockNameShown = 0;
|
||||
@@ -398,20 +455,22 @@ void loop(void)
|
||||
if ((millis() - lastTimeClockNameShown > displayClockNameEvery_ms)
|
||||
&& (seconds < 60-doNotShowClockNameBeforeAndAfterMinuteChange_s)
|
||||
&& (seconds > doNotShowClockNameBeforeAndAfterMinuteChange_s)) {
|
||||
P.begin(); // re-initialize, that fixes display problems due to electrical relais feedbacks
|
||||
P.setIntensity(2);
|
||||
P.print(clockName);
|
||||
lastTimeClockNameShown = millis();
|
||||
showingClockName = true;
|
||||
} else {
|
||||
// showing clock
|
||||
if (millis() - last_clock_refresh > displayRefresh_ms) {
|
||||
//P.displayClear();
|
||||
P.setIntensity(1);
|
||||
P.print(timeBuffer);
|
||||
last_clock_refresh = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// toggle relays
|
||||
if (lastMinutes != minutes) {
|
||||
toggleRelays();
|
||||
|
||||
Reference in New Issue
Block a user