// - Added serial JSON (optional) monitor
// - Watchdog timeout from 1 minute through 255 minutes - change of state pin WATCHDOG
// In normal operation shows total on time and total off time
+// = new logging graphics - long-press SET button to see 0-5v battery over time
// Use 328-based board similar regulator (pref low loss) and no USB chip. If possible
// Blog has more - as does this video https://www.youtube.com/watch?v=44Lvdf7o4GQ
// Now set up for the 32-pixel displays - got everything down to 4 lines
// Device address for the SSD1306 display
#define SWITCHON 3.7 // defaults for hysteresis voltage
-#define LONGPRESS_UP 60 // 10ths of second before long presson UP triggers shutdown
-#define LONGPRESS_DOWN 60 // 10ths of second before battery fail test
+#define LONGPRESS_UP 20 // 10ths of second before long presson UP triggers shutdown
+#define LONGPRESS_DOWN 20 // 10ths of second before battery fail test
+#define LONGPRESS_SET 20 // 10ths of second before graphics display
+#define SHOWGRAPH 10 // 10 seconds showing graphical info
#define SHUTDOWN_PERIOD 20
-uint16_t longpressedUp = 0 ;
-uint16_t longpressedDown = 0;
uint8_t triggerShutdown = 0;
uint8_t watchdogTimer = 0;
uint8_t watchdogState = 0;
uint8_t secondsCounter = 0;
void LcdP(char *fmt, ...)
- char buf[128]; // resulting string limited to 128 chars
+ char buf[22]; // resulting string limited to 128 chars
vsnprintf(buf, 128, fmt, args);
- char buf[128]; // resulting string limited to 128 chars
- vsnprintf(buf, 128, fmt, args);
void gotoXY(int x, int y)
analogReference(INTERNAL);
- if (eeSave.check != 0x52d5)
+ if (eeSave.check != 0x52d3)
watchdogState = digitalRead(WATCHDOG);
- if (digitalRead(SET) == 0)
+ if (digitalRead(SET) == 1)
+ { if (sKeypressed<LONGPRESS_SET)
+ if (showGraph) { showGraph=0; oled.clear(); instate=255 ; sKeypressed=0; refresh=1; }
+ if (sKeypressed==LONGPRESS_SET) showGraph = SHOWGRAPH;
+ if (sKeypressed>>LONGPRESS_SET) sKeypressed--;
- if (digitalRead(UP) == 0) // special case long press is reset...
+ if (digitalRead(UP) == 1) // special case long press is reset...
- case 1 : if (eeSave.highV < 4.3) eeSave.highV += 0.1; break;
- case 2 : if (eeSave.lowV < 4.2) eeSave.lowV += 0.1; break;
- case 3 : eeSave.startTimeout++; break;
- case 4 : eeSave.goodTimeout++; break;
- case 5 : eeSave.warningTimeout++; break;
- case 6 : eeSave.offTimeout++; break;
- case 7 : eeSave.batteryOffset++; break;
- case 8 : if (eeSave.tone < 5000) eeSave.tone += 500; else eeSave.tone = 0; break;
- case 9 : eeSave.smon = 1; break;
- case 10 : eeSave.watchdog++;
- watchdogTimer = eeSave.watchdog; watchdogTrigger = 0; break;
+ if (uKeypressed<LONGPRESS_UP)
+ case 1 : if (eeSave.highV < 4.3) eeSave.highV += 0.1; break;
+ case 2 : if (eeSave.lowV < 4.2) eeSave.lowV += 0.1; break;
+ case 3 : eeSave.startTimeout++; break;
+ case 4 : eeSave.goodTimeout++; break;
+ case 5 : eeSave.warningTimeout++; break;
+ case 6 : eeSave.offTimeout++; break;
+ case 7 : eeSave.batteryOffset++; break;
+ case 8 : if (eeSave.tone < 5000) eeSave.tone += 500; else eeSave.tone = 0; break;
+ case 9 : eeSave.smon = 1; break;
+ case 10 : eeSave.watchdog++;
+ watchdogTimer = eeSave.watchdog; watchdogTrigger = 0; break;
+ case 11: eeSave.pause++; break;
- if (++longpressedUp == LONGPRESS_UP) triggerShutdown = 1;
+ if (uKeypressed==LONGPRESS_UP) triggerShutdown = 1;
+ if (uKeypressed>LONGPRESS_UP) uKeypressed--;
- if (digitalRead(DOWN) == 0)
+ if (digitalRead(DOWN) == 1)
+ if (dKeypressed<LONGPRESS_DOWN)
- case 1 : if (eeSave.highV > 2.3) eeSave.highV -= 0.1; break;
- case 2 : if (eeSave.lowV > 2.2) eeSave.lowV -= 0.1; break;
- case 3 : eeSave.startTimeout--; break;
- case 4 : eeSave.goodTimeout--; break;
- case 5 : eeSave.warningTimeout--; break;
- case 6 : eeSave.offTimeout--; break;
- case 7 : eeSave.batteryOffset--; break;
- case 8 : if (eeSave.tone >= 500) eeSave.tone -= 500; break;
- case 9 : eeSave.smon = 0; break;
- case 10 : if (eeSave.watchdog) eeSave.watchdog--;
- watchdogTimer = eeSave.watchdog; watchdogTrigger = 0; break;
+ case 1 : if (eeSave.highV > 2.3) eeSave.highV -= 0.1; break;
+ case 2 : if (eeSave.lowV > 2.2) eeSave.lowV -= 0.1; break;
+ case 3 : eeSave.startTimeout--; break;
+ case 4 : eeSave.goodTimeout--; break;
+ case 5 : eeSave.warningTimeout--; break;
+ case 6 : eeSave.offTimeout--; break;
+ case 7 : eeSave.batteryOffset--; break;
+ case 8 : if (eeSave.tone >= 500) eeSave.tone -= 500; break;
+ case 9 : eeSave.smon = 0; break;
+ case 10 : if (eeSave.watchdog) eeSave.watchdog--;
+ watchdogTimer = eeSave.watchdog; watchdogTrigger = 0; break;
+ case 11 : if (eeSave.pause>1) eeSave.pause--; break;
- if (++longpressedDown == LONGPRESS_DOWN) average = 0; // temporarily drop the voltage and hence trigger warning
+ if (dKeypressed==LONGPRESS_DOWN) average=0;
+ if (dKeypressed>LONGPRESS_DOWN) dKeypressed--;
if (eeSave.highV <= eeSave.lowV) eeSave.highV = eeSave.lowV + 0.1;
case 11: if (updated == 0)
+ LcdP("Log period=%d mins"); oled.clearToEOL();
+ case 12: if (updated == 0)
LcdP("Version=%s", VER); oled.clearToEOL();
- case 12: updated = 0; instate = 0; break;
+ case 13: updated = 0; instate = 0; break;
average = ((average * 7) + analogRead(VOLTAGE)) / 8; //i.e. average over 8 seconds 0-1023 = 0-5v - might make testing longer in the end
vol = (((float)average) * 5.0 / 824.0) * (float)eeSave.batteryOffset / 400.0; //10k/2k2
+ if (++logpause>2) // log 128 values 0-30 = 0-5v - 2 secs updating for testing
+ for (int a=0;a<127;a++) logit[a]=logit[a+1];
+ logit[126]=((int)(vol*6.0));
if (eeSave.smon) Serial.println(bString);
+ if (showGraph==SHOWGRAPH)
+ for (int a=0;a<128;a++)
+ uint32_t point=(0x80000000>>logit[a])|0x80000001;
+ if ((a==0)||(a==127)) point=0xffffffff;
+ oled.setCursor(a,0); oled.ssd1306WriteRamBuf((uint8_t)((point)&255));
+ oled.setCursor(a,1); oled.ssd1306WriteRamBuf((uint8_t)((point>>8)&255));;
+ oled.setCursor(a,2); oled.ssd1306WriteRamBuf((uint8_t)((point>>16)&255));
+ oled.setCursor(a,3); oled.ssd1306WriteRamBuf((uint8_t)((point>>24)&255));
+ showGraph--; if (showGraph==0) refresh=1;
case POWERUP_STATE : // powered up everything off
- if (stateCounter == eeSave.startTimeout) {
+ if ((stateCounter == eeSave.startTimeout) || (refresh)) {
+ if (stateCounter) --stateCounter;
gotoXY(0, 1); LcdP("Bat="); showBattery();
gotoXY(0, 2); LcdP("Wait=%03d secs", stateCounter); oled.clearToEOL();
digitalWrite(WARNING, WARNINGON); // no warning
case GOOD_STATE : // battery is above upper threshold
- if (stateCounter == eeSave.goodTimeout) {
+ if ((stateCounter == eeSave.goodTimeout) || (refresh)) {
LcdP("** Pi Power %s **", VER);
watchdogTimer = eeSave.watchdog;
+ if (stateCounter) --stateCounter;
if (++secondsCounter == 60)
case TIMEOUT_STATE : // battery has dropped below upper threshold - ALWAYS timeout to OFF_STATE
- if (stateCounter == eeSave.warningTimeout) oled.clear();
+ if ((stateCounter == eeSave.warningTimeout) || (refresh)) { refresh=0; oled.clear(); }
gotoXY(0, 0); LcdP("Timoutout. Bat="); showBattery();
gotoXY(0, 1); LcdP("Wait=%03d secs", stateCounter); oled.clearToEOL();
digitalWrite(WARNING, WARNINGON); // warning
digitalWrite(POWER, POWERON);
if (eeSave.tone) tone(TONE, eeSave.tone, 100);
+ if (stateCounter) --stateCounter;
if (stateCounter == 0 ) {
stateCounter = eeSave.offTimeout;
case OFF_STATE : // everything off
- if (stateCounter == eeSave.offTimeout) oled.clear();
+ if ((stateCounter == eeSave.offTimeout) || (refresh)) { refresh=0; oled.clear(); }
+ if (stateCounter) --stateCounter;
if (vol <= eeSave.highV) {
stateCounter = eeSave.offTimeout - 1; // avoid clearscreen
- gotoXY(0, 3); oled.clearToEOL();
+ // gotoXY(0, 3); oled.clearToEOL();
case SHUTDOWN_STATE: // everything off and stays off... hold the SET button.... set state to SHUTDOWN_STATE and stateCounter to SHUTDOWN_PERIOD
- if (stateCounter == SHUTDOWN_PERIOD)
+ if ((stateCounter == SHUTDOWN_PERIOD) || (refresh))
gotoXY(0, 2); LcdP("Shutdown commencing.."); oled.clearToEOL();
digitalWrite(WARNING, WARNINGON); // warning
stateCounter = eeSave.startTimeout;