2022-08-25 05:23:48 +02:00
/* -[ClockSketch v7.2]----------------------------------------------------------------------------------------
https : //www.instructables.com/ClockSketch-V7-Part-I/
2022-09-06 19:20:37 +02:00
2022-08-25 05:23:48 +02:00
pre - configured for :
Retro 7 Segment Clock v3 - The Final One ( s ) ( 3 LEDs / Segment )
https : //www.instructables.com/Retro-7-Segment-Clock-the-Final-Ones/
https : //www.thingiverse.com/thing:5001559
2022-09-06 19:20:37 +02:00
2022-08-25 05:23:48 +02:00
Arduino UNO / Nano / Pro Mini ( AtMega328 , 5 V , 16 MHz ) , DS3231 RTC
May 2022 - Daniel Cikic
Serial Baud Rates :
Arduino : 57600
nodeMCU : 74880
2022-09-06 19:20:37 +02:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2022-08-25 05:30:54 +02:00
2022-08-25 05:23:48 +02:00
// comment below to disable serial in-/output and free some RAM
# define DEBUG
2022-08-25 05:30:54 +02:00
// nodeMCU - uncomment to compile this sketch for nodeMCU 1.0 / ESP8266, make sure to select the proper board
// type inside the IDE! This mode is NOT supported and only experimental!
2022-09-06 19:20:37 +02:00
# define NODEMCU
2022-08-25 05:30:54 +02:00
// useWiFi - enable WiFi support, WPS setup only! If no WPS support is available on a router check settings
// further down, set useWPS to false and enter ssid/password there
2022-09-06 19:20:37 +02:00
# define USEWIFI
2022-08-25 05:30:54 +02:00
// useNTP - enable NTPClient, requires NODEMCU and USEWIFI. This will also enforce AUTODST.
// Configure a ntp server further down below!
2022-09-06 19:20:37 +02:00
# define USENTP
2022-08-25 05:30:54 +02:00
// RTC selection - uncomment the one you're using, comment all others and make sure pin assignemts for
// DS1302 are correct in the parameters section further down!
// #define RTC_DS1302
// #define RTC_DS1307
2022-09-06 19:20:37 +02:00
//#define RTC_DS3231
2022-08-25 05:30:54 +02:00
// autoDST - uncomment to enable automatic DST switching, check Time Change Rules below!
2022-09-06 19:20:37 +02:00
# define AUTODST
2022-08-25 05:30:54 +02:00
// FADING - uncomment to enable fading effects for dots/digits, other parameters further down below
2024-02-29 21:42:20 +01:00
# define FADING
2022-08-25 05:30:54 +02:00
// autoBrightness - uncomment to enable automatic brightness adjustments by using a photoresistor/LDR
// #define AUTOBRIGHTNESS
// customDisplay - uncomment this to enable displayMyStuff(). It's an example of how to display values
// at specified times, like temperature readouts
// #define CUSTOMDISPLAY
// FastForward will speed up things and advance time, this is only for testing purposes!
// Disables AUTODST, USENTP and USERTC.
// #define FASTFORWARD
// customHelper will start some kind of assistant when adapting this sketch to other led layouts, this
// tests all the steps neccessary to run it on almost any led strip configuration.
// #define CUSTOMHELPER
2022-08-25 05:23:48 +02:00
/* ----------------------------------------------------------------------------------------------------- */
2022-08-25 05:30:54 +02:00
2022-09-08 06:16:59 +02:00
// Use an accelerometer instead of button functions
# define USEGYRO
2022-08-25 05:30:54 +02:00
2022-09-08 06:16:59 +02:00
# include <TimeLib.h> // "Time" by Michael Margolis, used in all configs
# include <EEPROM.h> // required for reading/saving settings to eeprom
2022-08-25 05:30:54 +02:00
2022-09-06 19:20:37 +02:00
/* Start RTC config/parameters--------------------------------------------------------------------------
Check pin assignments for DS1302 ( SPI ) , others are I2C ( A4 / A5 on Arduino by default )
2022-08-25 05:30:54 +02:00
Currently all types are using the " Rtc by Makuna " library */
# ifdef RTC_DS1302
2022-09-06 19:20:37 +02:00
# include <ThreeWire.h>
# include <RtcDS1302.h>
2022-09-08 06:16:59 +02:00
ThreeWire myWire ( 7 , 6 , 8 ) ; // IO/DAT, SCLK, CE/RST
2022-09-06 19:20:37 +02:00
RtcDS1302 < ThreeWire > Rtc ( myWire ) ;
# define RTCTYPE "DS1302"
# define USERTC
2022-08-25 05:30:54 +02:00
# endif
# ifdef RTC_DS1307
2022-09-06 19:20:37 +02:00
# include <Wire.h>
# include <RtcDS1307.h>
RtcDS1307 < TwoWire > Rtc ( Wire ) ;
# define RTCTYPE "DS1307"
# define USERTC
2022-08-25 05:30:54 +02:00
# endif
# ifdef RTC_DS3231
2022-09-06 19:20:37 +02:00
# include <Wire.h>
# include <RtcDS3231.h>
RtcDS3231 < TwoWire > Rtc ( Wire ) ;
# define RTCTYPE "DS3231"
# define USERTC
2022-08-25 05:30:54 +02:00
# endif
2022-09-08 06:16:59 +02:00
# if !defined(USERTC)
2022-09-06 19:20:37 +02:00
# pragma message "No RTC selected, check definitions on top of the sketch!"
2022-08-25 05:30:54 +02:00
# endif
/* End RTC config/parameters---------------------------------------------------------------------------- */
2022-09-06 19:20:37 +02:00
/* Start WiFi config/parameters------------------------------------------------------------------------- */
2022-08-25 05:30:54 +02:00
# ifdef USEWIFI
2022-09-08 06:16:59 +02:00
const bool useWPS = false ; // set to false to disable WPS and use credentials below
2024-02-29 21:42:20 +01:00
const char * wifiSSID = " unhb.de " ;
const char * wifiPWD = " sagichnicht " ;
2022-08-25 05:30:54 +02:00
# endif
2022-08-25 05:23:48 +02:00
/* End WiFi config/parameters--------------------------------------------------------------------------- */
2022-09-06 19:20:37 +02:00
/* Start NTP config/parameters--------------------------------------------------------------------------
2022-08-25 05:23:48 +02:00
Using NTP will enforce autoDST , so check autoDST / time zone settings below ! */
2022-08-25 05:30:54 +02:00
# ifdef USENTP
2022-09-06 19:20:37 +02:00
/* I recommend using a local ntp service (many routers offer them), don't spam public ones with dozens
of requests a day , get a rtc ! ^ ^ */
# define NTPHOST "pool.ntp.org"
# ifndef AUTODST
# define AUTODST
# endif
2022-08-25 05:30:54 +02:00
# endif
2022-08-25 05:23:48 +02:00
/* End NTP config/parameters---------------------------------------------------------------------------- */
2022-09-06 19:20:37 +02:00
/* Start autoDST config/parameters ----------------------------------------------------------------------
Comment / uncomment / add TimeChangeRules as needed , only use 2 ( tcr1 , tcr2 ) , comment out unused ones !
2022-08-25 05:23:48 +02:00
Enabling / disabling autoDST will require to set time again , clock will be running in UTC time if autoDST
2022-09-06 19:20:37 +02:00
is enabled , only display times are adjusted ( check serial monitor with DEBUG defined ! )
2022-08-25 05:23:48 +02:00
This will also add options for setting the date ( Year / Month / Day ) when setting time on the clock ! */
2022-08-25 05:30:54 +02:00
# ifdef AUTODST
2022-09-08 06:16:59 +02:00
# include <Timezone.h> // "Timezone" by Jack Christensen
2022-09-06 19:20:37 +02:00
TimeChangeRule * tcr ;
//-----------------------------------------------
/* US */
2024-02-29 21:42:20 +01:00
//TimeChangeRule tcr1 = {"tcr1", First, Sun, Nov, 2, -300}; // utc -5h, valid from first sunday of november at 2am
//TimeChangeRule tcr2 = {"tcr2", Second, Sun, Mar, 2, -240}; // utc -4h, valid from second sunday of march at 2am
2022-09-06 19:20:37 +02:00
//-----------------------------------------------
/* Europe */
2024-02-29 21:42:20 +01:00
TimeChangeRule tcr1 = { " tcr1 " , Last , Sun , Oct , 3 , 60 } ; // standard/winter time, valid from last sunday of october at 3am, UTC + 1 hour (+60 minutes) (negative value like -300 for utc -5h)
TimeChangeRule tcr2 = { " tcr2 " , Last , Sun , Mar , 2 , 120 } ; // daylight/summer time, valid from last sunday of march at 2am, UTC + 2 hours (+120 minutes)
2022-09-06 19:20:37 +02:00
//-----------------------------------------------
Timezone myTimeZone ( tcr1 , tcr2 ) ;
2022-08-25 05:30:54 +02:00
# endif
2022-08-25 05:23:48 +02:00
/* End autoDST config/parameters ----------------------------------------------------------------------- */
2022-08-25 05:30:54 +02:00
/* Start autoBrightness config/parameters -------------------------------------------------------------- */
2022-09-08 06:16:59 +02:00
uint8_t upperLimitLDR = 180 ; // everything above this value will cause max brightness (according to current level) to be used (if it's higher than this)
uint8_t lowerLimitLDR = 50 ; // everything below this value will cause minBrightness to be used
uint8_t minBrightness = 30 ; // anything below this avgLDR value will be ignored
const bool nightMode = false ; // nightmode true -> if minBrightness is used, colorizeOutput() will use a single color for everything, using HSV
const uint8_t nightColor [ 2 ] = { 0 , 70 } ; // hue 0 = red, fixed brightness of 70, https://github.com/FastLED/FastLED/wiki/FastLED-HSV-Colors
float factorLDR = 1.0 ; // try 0.5 - 2.0, compensation value for avgLDR. Set dbgLDR true & define DEBUG and watch the serial monitor. Looking...
const bool dbgLDR = false ; // ...for values roughly in the range of 120-160 (medium room light), 40-80 (low light) and 0 - 20 in the dark
2022-08-25 05:30:54 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
uint8_t pinLDR = 0 ; // LDR connected to A0 (nodeMCU only offers this one)
2022-08-25 05:30:54 +02:00
# else
2022-09-08 06:16:59 +02:00
uint8_t pinLDR = 1 ; // LDR connected to A1 (in case somebody flashes this sketch on arduino and already has an ldr connected to A1)
2022-08-25 05:30:54 +02:00
# endif
2022-09-08 06:16:59 +02:00
uint8_t intervalLDR = 75 ; // read value from LDR every 75ms (most LDRs have a minimum of about 30ms - 50ms)
uint16_t avgLDR = 0 ; // we will average this value somehow somewhere in readLDR();
uint16_t lastAvgLDR = 0 ; // last average LDR value we got
2022-08-25 05:30:54 +02:00
/* End autoBrightness config/parameters ---------------------------------------------------------------- */
2022-08-25 05:23:48 +02:00
# define SKETCHNAME "ClockSketch v7.2"
# define CLOCKNAME "Retro 7 Segment Clock v3 - The Final One(s), 3 LEDs / segment"
/* Start button config/pins----------------------------------------------------------------------------- */
2022-08-25 05:30:54 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
const uint8_t buttonA = 13 ; // momentary push button, 1 pin to gnd, 1 pin to d7 / GPIO_13
const uint8_t buttonB = 14 ; // momentary push button, 1 pin to gnd, 1 pin to d5 / GPIO_14
2022-08-25 05:30:54 +02:00
# else
2022-09-08 06:16:59 +02:00
const uint8_t buttonA = 3 ; // momentary push button, 1 pin to gnd, 1 pin to d3
const uint8_t buttonB = 4 ; // momentary push button, 1 pin to gnd, 1 pin to d4
2022-08-25 05:30:54 +02:00
# endif
2022-08-25 05:23:48 +02:00
/* End button config/pins------------------------------------------------------------------------------- */
2022-09-08 06:16:59 +02:00
/* Start Gyro config/pins - ---------------------------------------------------------------------------- */
# ifdef USEGYRO
# include <MPU6050_tockn.h>
# include <Wire.h>
MPU6050 mpu6050 ( Wire ) ;
int ORIENTATION = 0 ;
# endif
/* End button config/pins------------------------------------------------------------------------------- */
2022-08-25 05:30:54 +02:00
2022-08-25 05:23:48 +02:00
/* Start basic appearance config------------------------------------------------------------------------ */
2022-09-08 06:16:59 +02:00
const bool dotsBlinking = false ; // true = only light up dots on even seconds, false = always on
const bool leadingZero = false ; // true = enable a leading zero, 9:00 -> 09:00, 1:30 -> 01:30...
2024-02-29 21:42:20 +01:00
uint8_t displayMode = 0 ; // 0 = 24h mode, 1 = 12h mode ("1" will also override setting that might be written to EEPROM!)
2022-09-08 06:16:59 +02:00
uint8_t colorMode = 0 ; // different color modes, setting this to anything else than zero will overwrite values written to eeprom, as above
uint16_t colorSpeed = 750 ; // controls how fast colors change, smaller = faster (interval in ms at which color moves inside colorizeOutput();)
const bool colorPreview = true ; // true = preview selected palette/colorMode using "8" on all positions for 3 seconds
const uint8_t colorPreviewDuration = 3 ; // duration in seconds for previewing palettes/colorModes if colorPreview is enabled/true
const bool reverseColorCycling = false ; // true = reverse color movements
const uint8_t brightnessLevels [ 3 ] { 80 , 130 , 220 } ; // 0 - 255, brightness Levels (min, med, max) - index (0-2) will be saved to eeprom
uint8_t brightness = brightnessLevels [ 0 ] ; // default brightness if none saved to eeprom yet / first run
2022-08-25 05:30:54 +02:00
# ifdef FADING
2022-09-08 06:16:59 +02:00
uint8_t fadeDigits = 2 ; // fade digit segments, 0 = disabled, 1 = only fade out segments turned off, 2 = fade old out and fade new in
2024-02-29 21:42:20 +01:00
uint8_t fadeDots = 0 ; // fade dots, 0 = disabled, 1 = turn dots off without fading in/out after specidfied time, 2 = fade in and out
uint8_t fadeDelay = 25 ; // milliseconds between each fading step, 5-25 should work okay-ish
2022-08-25 05:30:54 +02:00
# endif
2022-08-25 05:23:48 +02:00
/* End basic appearance config-------------------------------------------------------------------------- */
/* End of basic config/parameters section */
/* End of feature/parameter section, unless changing advanced things/modifying the sketch there's absolutely nothing to do further down! */
/* library, wifi and ntp stuff depending on above config/parameters */
2022-08-25 05:30:54 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
# if defined(USENTP) && !defined(USEWIFI) // enforce USEWIFI when USENTP is defined
2022-09-06 19:20:37 +02:00
# define USEWIFI
# pragma warning "USENTP without USEWIFI, enabling WiFi"
# endif
# ifdef USEWIFI
# include <ESP8266WiFi.h>
# include <WiFiUdp.h>
# endif
2022-08-25 05:30:54 +02:00
# endif
# ifdef USENTP
2022-09-06 19:20:37 +02:00
# include <NTPClient.h>
WiFiUDP ntpUDP ;
NTPClient timeClient ( ntpUDP , NTPHOST , 0 , 60000 ) ;
2022-08-25 05:30:54 +02:00
# endif
2022-08-25 05:23:48 +02:00
/* end library stuff */
2022-08-25 05:30:54 +02:00
/* setting feature combinations/options */
2022-09-08 06:16:59 +02:00
# if defined(FASTFORWARD) || defined(CUSTOMHELPER)
2022-09-06 19:20:37 +02:00
bool firstLoop = true ;
# ifdef USERTC
# undef USERTC
# endif
# ifdef USEWIFI
# undef USEWIFI
# endif
# ifdef USENTP
# undef USENTP
# endif
# ifdef AUTODST
# undef AUTODST
# endif
2022-08-25 05:30:54 +02:00
# endif
/* setting feature combinations/options */
2022-08-25 05:23:48 +02:00
2022-08-25 05:30:54 +02:00
/* Start of FastLED/clock stuff */
# define LEDSTUFF
# ifdef LEDSTUFF
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
# define FASTLED_ESP8266_RAW_PIN_ORDER // this means we'll be using the raw esp8266 pin order -> GPIO_12, which is d6 on nodeMCU
# define LED_PIN 12 // led data in connected to GPIO_12 (d6/nodeMCU)
2022-09-06 19:20:37 +02:00
# else
2022-09-08 06:16:59 +02:00
# define FASTLED_ALLOW_INTERRUPTS 0 // AVR + WS2812 + IRQ = https://github.com/FastLED/FastLED/wiki/Interrupt-problems
# define LED_PIN 6 // led data in connected to d6 (arduino)
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
# define LED_PWR_LIMIT 500 // 500mA - Power limit in mA (voltage is set in setup() to 5v)
# define LED_DIGITS 4 // 4 or 6 digits, HH:MM or HH:MM:SS
# define LED_COUNT 64 // Total number of leds, 103 on Retro 7 Segment Clock v3 - The Final One(s) - 3 LEDs/segment
# if (LED_DIGITS == 6)
# define LED_COUNT 157 // leds on the 6 digit version
2022-09-06 19:20:37 +02:00
# endif
# include <FastLED.h>
2022-09-08 06:16:59 +02:00
uint8_t markerHSV [ 3 ] = { 0 , 127 , 20 } ; // this color will be used to "flag" leds for coloring later on while updating the leds
2022-09-06 19:20:37 +02:00
CRGB leds [ LED_COUNT ] ;
CRGBPalette16 currentPalette ;
2022-08-25 05:30:54 +02:00
# endif
2022-08-25 05:23:48 +02:00
// start clock specific config/parameters
/* Segment order, seen from the front:
< A >
2022-09-06 19:20:37 +02:00
/ \ / \
F B
\ / \ /
2022-08-25 05:23:48 +02:00
< G >
2022-09-06 19:20:37 +02:00
/ \ / \
E C
\ / \ /
2022-08-25 05:23:48 +02:00
< D >
2022-09-06 19:20:37 +02:00
digit positions , seen from the front :
_ _ _ _ _ _
| _ | | _ | | _ | | _ | | _ | | _ |
| _ | | _ | | _ | | _ | | _ | | _ |
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
0 1 2 3 4 5
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
Note : Digit positions for showSegments ( ) depends on the order in which the segments
are defined in segGroups [ ] below . Most of my things / clocks published so far start
from the right side when seen from the front , TFO from the left . Others may have different
orders , like Lazy 7 - QBE , which is using a single strip and has an order of
3 , 0 , 2 , 1 for top left , top right , bottom left , bottom right .
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
" The Final One(s) " is starting from the left when looking at the front , so it ' s
exactly the reverse order of the old / other ones . This doesn ' t really matter , that ' s
what " digitPositions " a few lines below is for . . .
2022-08-25 05:23:48 +02:00
*/
/* Below is the configuration for led <> segment assignments.
LED_ACCESS_MODE 0 will use the two values inside each segment ( led a , led b )
as they are - 2 leds per segment .
LED_ACCESS_MODE 1 will use the two values inside each segment ( led a , led b )
as start and end value to get 2 + leds / segment .
Example :
leds 0 , 3 - > MODE 0 - > led 0 and 3 inside the segment - > 2 leds
leds 0 , 3 - > MODE 1 - > led 0 - 3 inside the segment - > 4 leds
Simply add all the leds into their corresponding segments inside the array .
The order of digits / strip routing doesn ' t really matter there , positions of
HH : MM : SS are assigned using digitPositions .
2022-09-06 19:20:37 +02:00
digitsLAM - > LED_ACCESS_MODE per digit
2022-08-25 05:23:48 +02:00
*/
// defining access modes for each digit individually
2022-09-08 06:16:59 +02:00
uint8_t digitsLAM [ 6 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
# if (LED_DIGITS == 4)
const uint8_t digitPositions [ 4 ] = { 0 , 1 , 2 , 3 } ; // positions of HH:MM (3, 0, 2, 1 on L7-QBE)
2022-09-06 19:20:37 +02:00
const uint16_t segGroups [ 28 ] [ 2 ] PROGMEM = {
2022-08-25 05:30:54 +02:00
# endif
2022-09-08 06:16:59 +02:00
# if (LED_DIGITS == 6)
const uint8_t digitPositions [ 6 ] = { 0 , 1 , 2 , 3 , 4 , 5 } ; // positions of HH:MM:SS
const uint16_t segGroups [ 42 ] [ 2 ] PROGMEM = {
2022-08-25 05:23:48 +02:00
# endif
2022-09-06 19:20:37 +02:00
/* segments 0-27, 4 digits x 7 segments */
/* digit position 0 */
2024-02-29 21:42:20 +01:00
{ 1 , 2 } , // top, a
{ 3 , 11 } , // top right, b
{ 19 , 27 } , // bottom right, c
{ 25 , 26 } , // bottom, d
{ 24 , 16 } , // bottom left, e
{ 0 , 8 } , // top left, f
{ 9 , 10 } , // center, g
2022-09-06 19:20:37 +02:00
/* digit position 1 */
2024-02-29 21:42:20 +01:00
{ 5 , 6 } , // top, a
{ 7 , 15 } , // top right, b
{ 23 , 31 } , // bottom right, c
{ 29 , 30 } , // bottom, d
{ 28 , 20 } , // bottom left, e
{ 04 , 12 } , // top left, f
{ 13 , 14 } , // center, g
2022-09-06 19:20:37 +02:00
/* digit position 2 */
2024-02-29 21:42:20 +01:00
{ 33 , 34 } , // top, a
{ 35 , 43 } , // top right, b
{ 51 , 59 } , // bottom right, c
{ 57 , 58 } , // bottom, d
{ 56 , 48 } , // bottom left, e
{ 32 , 40 } , // top left, f
{ 41 , 42 } , // center, g
2022-09-06 19:20:37 +02:00
/* digit position 3 */
2024-02-29 21:42:20 +01:00
{ 37 , 38 } , // top, a
{ 39 , 47 } , // top right, b
{ 55 , 63 } , // bottom right, c
{ 61 , 62 } , // bottom, d
{ 60 , 52 } , // bottom left, e
{ 36 , 44 } , // top left, f
{ 45 , 46 } , // center, g
2022-09-08 06:16:59 +02:00
# if (LED_DIGITS == 6) // add two digits, 14 segments, only used if LED_DIGITS is 6...
2022-09-06 19:20:37 +02:00
/* segments 28-41, 6 digits x 7 segments */
/* (bogus on some models which don't support 6 digits) */
/* digit position 4 */
2022-09-08 06:16:59 +02:00
,
{ 114 , 116 } , // top, a !! do not remove the "," at the start of this line !!
{ 111 , 113 } , // top right, b
{ 128 , 130 } , // bottom right, c
{ 125 , 127 } , // bottom, d
{ 122 , 124 } , // bottom left, e
{ 117 , 119 } , // top left, f
{ 108 , 110 } , // center, g
2022-09-06 19:20:37 +02:00
/* digit position 5 */
2022-09-08 06:16:59 +02:00
{ 148 , 150 } , // top, a
{ 145 , 147 } , // top right, b
{ 140 , 142 } , // bottom right, c
{ 137 , 139 } , // bottom, d
{ 134 , 136 } , // bottom left, e
{ 151 , 153 } , // top left, f
{ 154 , 156 } // center, g
# endif // ...end of digits 5+6
} ;
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
# if (LED_DIGITS == 4)
2024-02-29 21:42:20 +01:00
const uint16_t upperDots [ 2 ] PROGMEM = { 18 } ; // leds inside the upper dots (right on L7-QBE)
const uint16_t lowerDots [ 2 ] PROGMEM = { 19 } ; // leds inside the lower dots (left on L7-QBE)
2022-08-25 05:30:54 +02:00
# endif
2022-09-08 06:16:59 +02:00
# if (LED_DIGITS == 6)
const uint16_t upperDots [ 4 ] PROGMEM = { 49 , 50 , 103 , 104 } ; // all the leds inside the upper dots (bogus values on some models which don't support 6 digits)
const uint16_t lowerDots [ 4 ] PROGMEM = { 52 , 53 , 106 , 107 } ; // all the leds inside the lower dots (bogus values on some models which don't support 6 digits)
2022-08-25 05:23:48 +02:00
# endif
2024-02-29 21:42:20 +01:00
const uint16_t amLight [ 1 ] PROGMEM = { 21 } ;
const uint16_t pmLight [ 1 ] PROGMEM = { 22 } ;
2022-09-06 19:20:37 +02:00
2022-09-08 06:16:59 +02:00
// Using above arrays it's very easy to "talk" to the segments. Simply use 0-6 for the first 7 segments, add 7 (7-13) for the second one, 14-20 for third....
const uint8_t digits [ 21 ] [ 7 ] PROGMEM = {
2022-09-06 19:20:37 +02:00
/* Lets define 10 numbers (0-9) with 7 segments each, also adding some letters
1 = segment is on , 0 = segment is off */
2022-09-08 06:16:59 +02:00
{ 1 , 1 , 1 , 1 , 1 , 1 , 0 } , // 0 -> Show segments a - f, don't show g (center one)
{ 0 , 1 , 1 , 0 , 0 , 0 , 0 } , // 1 -> Show segments b + c (top right and bottom right), nothing else
{ 1 , 1 , 0 , 1 , 1 , 0 , 1 } , // 2 -> and so on...
{ 1 , 1 , 1 , 1 , 0 , 0 , 1 } , // 3
{ 0 , 1 , 1 , 0 , 0 , 1 , 1 } , // 4
{ 1 , 0 , 1 , 1 , 0 , 1 , 1 } , // 5
{ 1 , 0 , 1 , 1 , 1 , 1 , 1 } , // 6
{ 1 , 1 , 1 , 0 , 0 , 0 , 0 } , // 7
{ 1 , 1 , 1 , 1 , 1 , 1 , 1 } , // 8
{ 1 , 1 , 1 , 1 , 0 , 1 , 1 } , // 9
{ 0 , 0 , 0 , 1 , 1 , 1 , 1 } , // t -> some letters/symbols from here on (index 10-20, so this won't...
{ 0 , 0 , 0 , 0 , 1 , 0 , 1 } , // r -> ...interfere with using digits 0-9 by using index 0-9
{ 0 , 1 , 1 , 1 , 0 , 1 , 1 } , // y
{ 0 , 1 , 1 , 1 , 1 , 0 , 1 } , // d
{ 1 , 0 , 0 , 1 , 1 , 1 , 0 } , // C
{ 1 , 0 , 0 , 0 , 1 , 1 , 1 } , // F
{ 1 , 1 , 0 , 0 , 1 , 1 , 0 } , // some kind of "half letter M" (left half), displayed using two digits
{ 1 , 1 , 1 , 0 , 0 , 1 , 0 } , // some kind of "half letter M" (right half), displayed using two digits
{ 1 , 1 , 0 , 0 , 0 , 1 , 1 } , // °
{ 0 , 1 , 1 , 0 , 1 , 1 , 1 } , // H
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 } // "blank"
} ;
uint8_t clockStatus = 1 ; // Used for various things, don't mess around with it! 1 = startup
// 0 = regular mode, 1 = startup, 9x = setup modes (90, 91, 92, 93...)
/* these values will be saved to EEPROM:
0 = index for selected palette
1 = index for selected brightness level
2 = displayMode , 12 h / 24 h mode
3 = colorMode */
/* End of FastLED/clock stuff */
// End clock specific configs/parameters
/* other variables */
uint8_t btnRepeatCounter = 0 ; // keeps track of how often a button press has been repeated
/* */
// for USEGYRO
int getOrientation ( )
{
int y = mpu6050 . getAngleY ( ) ;
2022-09-09 05:48:03 +02:00
// should be abt 0 if setting upright
// + or - more than 130 when turned over (abt 170)
// so if flipped, y should be less than -130, or greater than 130
return ( y < - 130 | | y > 130 ) ? 0 : 1 ; // 1 indicates right side up, 0 upside down
2022-09-08 06:16:59 +02:00
}
void checkFlip ( )
{
int currentOrientation = getOrientation ( ) ;
// if flipped over, toggle schema
if ( ORIENTATION = = 1 & & currentOrientation = = 0 )
{
Serial . println ( " flipped! " ) ;
// toggle pallet
paletteSwitcher ( ) ;
}
// if flipped back upright, do nothing
// set new orientation to prevent multiple pallet switches per flip
ORIENTATION = currentOrientation ;
}
/* -- this is where the fun parts start -------------------------------------------------------------------------------------------------------- */
void setup ( )
{
# ifdef DEBUG
while ( millis ( ) < 300 )
{ // safety delay for serial output
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
yield ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
Serial . begin ( 74880 ) ;
Serial . println ( F ( " " ) ) ;
2022-09-06 19:20:37 +02:00
# else
2022-09-08 06:16:59 +02:00
Serial . begin ( 57600 ) ;
Serial . println ( F ( " " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef SKETCHNAME
2022-09-08 06:16:59 +02:00
Serial . print ( SKETCHNAME ) ;
Serial . println ( F ( " starting up... " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef CLOCKNAME
2022-09-08 06:16:59 +02:00
Serial . print ( " Clock Type: " ) ;
Serial . println ( CLOCKNAME ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef RTCTYPE
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " Configured RTC: " ) ) ;
Serial . println ( RTCTYPE ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " LED power limit: " ) ) ;
Serial . print ( LED_PWR_LIMIT ) ;
Serial . println ( F ( " mA " ) ) ;
Serial . print ( F ( " Total LED count: " ) ) ;
Serial . println ( LED_COUNT ) ;
Serial . print ( F ( " LED digits: " ) ) ;
Serial . println ( LED_DIGITS ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef AUTODST
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " autoDST enabled " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " Configured for nodeMCU " ) ) ;
2022-09-06 19:20:37 +02:00
# ifdef USEWIFI
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " WiFi enabled " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef USENTP
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " NTP enabled, NTPHOST: " ) ) ;
Serial . println ( NTPHOST ) ;
2022-09-06 19:20:37 +02:00
# endif
# else
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " Configured for Arduino " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef FASTFORWARD
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " !! FASTFORWARD defined !! " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
while ( millis ( ) < 600 )
{ // safety delay for serial output
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
yield ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
2022-09-06 19:20:37 +02:00
# endif
# ifdef AUTOBRIGHTNESS
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " autoBrightness enabled, LDR using pin: " ) ) ;
Serial . println ( pinLDR ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
pinMode ( pinLDR , INPUT ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
pinMode ( buttonA , INPUT_PULLUP ) ;
pinMode ( buttonB , INPUT_PULLUP ) ;
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
if ( digitalRead ( buttonA ) = = LOW | | digitalRead ( buttonB ) = = LOW )
{
if ( digitalRead ( buttonA ) = = LOW )
{
Serial . println ( F ( " buttonA is LOW / pressed - check wiring! " ) ) ;
}
if ( digitalRead ( buttonB ) = = LOW )
{
Serial . println ( F ( " buttonB is LOW / pressed - check wiring! " ) ) ;
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
}
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
FastLED . addLeds < WS2812B , LED_PIN , GRB > ( leds , LED_COUNT ) . setCorrection ( TypicalSMD5050 ) . setTemperature ( DirectSunlight ) . setDither ( 1 ) ;
FastLED . setMaxPowerInVoltsAndMilliamps ( 5 , LED_PWR_LIMIT ) ;
FastLED . clear ( ) ;
FastLED . show ( ) ;
# ifdef CUSTOMHELPER // customHelper() will run in a loop if defined!
while ( 1 > 0 )
{
customHelper ( ) ;
}
2022-09-06 19:20:37 +02:00
# endif
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " setup(): Lighting up some leds... " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
for ( uint8_t i = 0 ; i < LED_DIGITS ; i + + )
{
showSegment ( 6 , i ) ;
}
FastLED . show ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
# ifdef USEGYRO
Serial . println ( F ( " Setting up mpu6050... " ) ) ;
Wire . begin ( ) ;
mpu6050 . begin ( ) ;
mpu6050 . calcGyroOffsets ( true ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
# ifdef NODEMCU // if building for nodeMCU...
# ifdef USEWIFI // ...and if using WiFi.....
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " Starting up WiFi... " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
WiFi . mode ( WIFI_STA ) ; // set WiFi mode to STA...
if ( useWPS )
{
WiFi . begin ( WiFi . SSID ( ) . c_str ( ) , WiFi . psk ( ) . c_str ( ) ) ; // ...and start connecting using saved credentials...
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " Using WPS setup / saved credentials " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
else
{
WiFi . begin ( wifiSSID , wifiPWD ) ; // ...or credentials defined in the USEWIFI config section
# ifdef DEBUG
Serial . println ( F ( " Using credentials from sketch " ) ) ;
# endif
}
unsigned long startTimer = millis ( ) ;
uint8_t wlStatus = 0 ;
uint8_t counter = 6 ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " Waiting for WiFi connection... " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
while ( wlStatus = = 0 )
{
if ( WiFi . status ( ) ! = WL_CONNECTED )
wlStatus = 0 ;
else
wlStatus = 1 ;
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
if ( millis ( ) - startTimer > = 1000 )
{
FastLED . clear ( ) ;
showDigit ( counter , digitPositions [ 3 ] ) ;
FastLED . show ( ) ;
if ( counter > 0 )
counter - - ;
else
wlStatus = 2 ;
startTimer = millis ( ) ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " . " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
2022-09-06 19:20:37 +02:00
# endif
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
yield ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
if ( WiFi . status ( ) = = WL_CONNECTED )
{ // if status is connected...
# ifdef USENTP // ...and USENTP defined...
timeClient . begin ( ) ; // ...start timeClient
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( ) ;
if ( WiFi . status ( ) ! = 0 )
{
Serial . print ( F ( " setup(): Connected to SSID: " ) ) ;
Serial . println ( WiFi . SSID ( ) ) ;
}
else
Serial . println ( F ( " setup(): WiFi connection failed. " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# endif
2022-09-08 06:16:59 +02:00
EEPROM . begin ( 512 ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:30:54 +02:00
2022-09-06 19:20:37 +02:00
# ifdef USERTC
2022-09-08 06:16:59 +02:00
Rtc . Begin ( ) ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " setup(): RTC.begin(), 2 second safety delay before " ) ) ;
Serial . println ( F ( " doing any read/write actions! " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
unsigned long tmp_time = millis ( ) ;
while ( millis ( ) - tmp_time < 2000 )
{
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
yield ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " setup(): RTC initialized " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# else
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " setup(): No RTC defined! " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# endif
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
FastLED . clear ( ) ;
FastLED . show ( ) ;
/* eeprom settings */
2022-09-06 19:20:37 +02:00
# ifdef nodeMCU
2022-09-08 06:16:59 +02:00
EEPROM . begin ( 512 ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
paletteSwitcher ( ) ;
brightnessSwitcher ( ) ;
colorModeSwitcher ( ) ;
displayModeSwitcher ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:30:54 +02:00
2022-09-06 19:20:37 +02:00
# ifdef FASTFORWARD
2022-09-08 06:16:59 +02:00
setTime ( 21 , 59 , 50 , 30 , 6 , 2021 ) ; // h, m, s, d, m, y to set the clock to when using FASTFORWARD
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:30:54 +02:00
2022-09-06 19:20:37 +02:00
# ifdef USENTP
2022-09-08 06:16:59 +02:00
syncHelper ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:30:54 +02:00
2022-09-08 06:16:59 +02:00
clockStatus = 0 ; // change from 1 (startup) to 0 (running mode)
2022-08-25 05:30:54 +02:00
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
printTime ( ) ;
Serial . println ( F ( " setup() done " ) ) ;
Serial . println ( F ( " ------------------------------------------------------ " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
/* MAIN LOOP */
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
void loop ( )
{
static uint8_t lastInput = 0 ; // != 0 if any button press has been detected
static uint8_t lastSecondDisplayed = 0 ; // This keeps track of the last second when the display was updated (HH:MM and HH:MM:SS)
static unsigned long lastCheckRTC = millis ( ) ; // This will be used to read system time in case no RTC is defined (not supported!)
static bool doUpdate = false ; // Update led content whenever something sets this to true. Coloring will always happen at fixed intervals!
# ifdef USEGYRO
mpu6050 . update ( ) ;
checkFlip ( ) ;
# endif
2022-09-06 19:20:37 +02:00
# ifdef USERTC
2022-09-08 06:16:59 +02:00
static RtcDateTime rtcTime = Rtc . GetDateTime ( ) . Epoch32Time ( ) ; // Get time from rtc (epoch)
2022-09-06 19:20:37 +02:00
# else
2022-09-08 06:16:59 +02:00
static time_t sysTime = now ( ) ; // if no rtc is defined, get local system time
2022-09-06 19:20:37 +02:00
# endif
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
static uint8_t refreshDelay = 5 ; // refresh leds every 5ms
static long lastRefresh = millis ( ) ; // Keeps track of the last led update/FastLED.show() inside the loop
2022-09-06 19:20:37 +02:00
# ifdef AUTOBRIGHTNESS
2022-09-08 06:16:59 +02:00
static long lastReadLDR = millis ( ) ;
2022-09-06 19:20:37 +02:00
# endif
# endif
# ifdef FASTFORWARD
2022-09-08 06:16:59 +02:00
static unsigned long lastFFStep = millis ( ) ; // Keeps track of last time increment if FASTFORWARD is defined
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
if ( lastInput ! = 0 )
{ // If any button press is detected...
if ( btnRepeatCounter < 1 )
{ // execute short/single press function(s)
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " loop(): " ) ) ;
Serial . print ( lastInput ) ;
Serial . println ( F ( " (short press) " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
if ( lastInput = = 1 )
{ // short press button A
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
brightnessSwitcher ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
if ( lastInput = = 2 )
{ // short press button B
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
paletteSwitcher ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
if ( lastInput = = 3 )
{ // short press button A + button B
}
}
else if ( btnRepeatCounter > 8 )
{ // execute long press function(s)...
btnRepeatCounter = 1 ; // ..reset btnRepeatCounter to stop this from repeating
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " loop(): " ) ) ;
Serial . print ( lastInput ) ;
Serial . println ( F ( " (long press) " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
if ( lastInput = = 1 )
{ // long press button A
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
colorModeSwitcher ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
if ( lastInput = = 2 )
{ // long press button B
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
displayModeSwitcher ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
if ( lastInput = = 3 )
{ // long press button A + button B
# ifdef USEWIFI // if USEWIFI is defined and...
if ( useWPS )
{ // ...if useWPS is true...
connectWPS ( ) ; // connect WiFi using WPS
2022-09-06 19:20:37 +02:00
}
2022-09-08 06:16:59 +02:00
# else // if USEWIFI is not defined...
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
FastLED . clear ( ) ;
FastLED . show ( ) ;
setupClock ( ) ; // start date/time setup
2022-09-06 19:20:37 +02:00
# endif
# endif
2022-09-08 06:16:59 +02:00
}
while ( digitalRead ( buttonA ) = = LOW | | digitalRead ( buttonB ) = = LOW )
{ // wait until buttons are released again
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
if ( millis ( ) % 50 = = 0 )
{ // Refresh leds every 50ms to give optical feedback
colorizeOutput ( colorMode ) ;
FastLED . show ( ) ;
}
2022-09-06 19:20:37 +02:00
# endif
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
yield ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
}
}
2022-09-08 06:16:59 +02:00
}
2022-09-06 19:20:37 +02:00
2022-09-08 06:16:59 +02:00
# ifdef FASTFORWARD // if FASTFORWARD is defined...
if ( millis ( ) - lastFFStep > = 250 )
{ // ...and 250ms have passed...
adjustTime ( 5 ) ; // ...add 5 seconds to current time
lastFFStep = millis ( ) ;
}
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
if ( millis ( ) - lastCheckRTC > = 50 )
{ // check rtc/system time every 50ms
2022-09-06 19:20:37 +02:00
# ifdef USERTC
2022-09-08 06:16:59 +02:00
rtcTime = Rtc . GetDateTime ( ) . Epoch32Time ( ) ;
if ( lastSecondDisplayed ! = second ( rtcTime ) )
doUpdate = true ;
2022-09-06 19:20:37 +02:00
# else
2022-09-08 06:16:59 +02:00
sysTime = now ( ) ;
if ( lastSecondDisplayed ! = second ( sysTime ) )
doUpdate = true ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
lastCheckRTC = millis ( ) ;
}
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
if ( doUpdate )
{ // this will update the led array if doUpdate is true because of a new second from the rtc
2022-09-06 19:20:37 +02:00
# ifdef USERTC
2022-09-08 06:16:59 +02:00
setTime ( rtcTime ) ; // sync system time to rtc every second
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
FastLED . clear ( ) ; // 1A - clear all leds...
displayTime ( rtcTime ) ; // 2A - output rtcTime to the led array..
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
lastSecondDisplayed = second ( rtcTime ) ;
2022-09-06 19:20:37 +02:00
# else
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
FastLED . clear ( ) ; // 1B - clear all leds...
displayTime ( sysTime ) ; // 2B - output sysTime to the led array...
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
lastSecondDisplayed = second ( sysTime ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef CUSTOMDISPLAY
2022-09-08 06:16:59 +02:00
displayMyStuff ( ) ; // 3AB - if customDisplay is defined this will clear the led array again to display custom values...
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
doUpdate = false ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
if ( second ( ) % 20 = = 0 )
{
printTime ( ) ;
}
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
# ifdef USENTP // if NTP is enabled, resync to ntp server at 0:00:00 utc
if ( hour ( ) = = 0 & & minute ( ) = = 0 and second ( ) = = 0 )
{
syncHelper ( ) ;
2022-09-06 19:20:37 +02:00
}
2022-09-08 06:16:59 +02:00
# endif
}
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
colorizeOutput ( colorMode ) ; // 1C, 2C, 3C...colorize the data inside the led array right now...
2022-09-06 19:20:37 +02:00
# ifdef AUTOBRIGHTNESS
2022-09-08 06:16:59 +02:00
if ( millis ( ) - lastReadLDR > = intervalLDR )
{ // if LDR is enabled and sample interval has been reached...
readLDR ( ) ; // ...call readLDR();
if ( abs ( avgLDR - lastAvgLDR ) > = 5 )
{ // if avgLDR has changed for more than +/- 5 update lastAvgLDR
lastAvgLDR = avgLDR ;
FastLED . setBrightness ( avgLDR ) ;
2022-09-06 19:20:37 +02:00
}
2022-09-08 06:16:59 +02:00
lastReadLDR = millis ( ) ;
}
2022-09-06 19:20:37 +02:00
# endif
# ifdef FADING
2022-09-08 06:16:59 +02:00
digitsFader ( ) ;
dotsFader ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
if ( millis ( ) - lastRefresh > = refreshDelay )
{
FastLED . show ( ) ;
lastRefresh = millis ( ) ;
2022-09-06 19:20:37 +02:00
}
2022-09-08 06:16:59 +02:00
# endif
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
lastInput = inputButtons ( ) ;
}
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
/* */
2022-08-25 05:23:48 +02:00
# ifdef LEDSTUFF
# ifdef CUSTOMDISPLAY
2022-09-08 06:16:59 +02:00
void displayMyStuff ( )
{
/* One way to display custom sensor data/other things. displayMyStuff() is then called inside the doUpdate if statement inside
void loop ( ) - after updating the leds but before calling colorizeOutput ( ) and FastLED . show ( ) */
if ( second ( ) > = 30 & & second ( ) < 40 )
{ // only do something if current second is 30-39
# ifdef RTC_DS3231 // if DS3231 is used we can read the temperature from that for demo purposes here
float rtcTemp = Rtc . GetTemperature ( ) . AsFloatDegC ( ) ; // get temperature in °C as float (25.75°C)....
uint8_t tmp = round ( rtcTemp ) ; // ...and round (26°C)
2022-09-06 19:20:37 +02:00
# else
2022-09-08 06:16:59 +02:00
uint8_t tmp = 99 ; // get whatever value from whatever sensor into tmp
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
FastLED . clear ( ) ;
if ( LED_DIGITS = = 4 )
{ // if 4 digits, display following content:
showDigit ( tmp / 10 , digitPositions [ 0 ] ) ; // tmp (26°C) / 10 = 2 on position 1 of HH
showDigit ( tmp % 10 , digitPositions [ 1 ] ) ; // tmp (26°C) % 10 = 6 on position 2 of HH
showDigit ( 18 , digitPositions [ 2 ] ) ; // ° symbol from array digits[][] on position 1 of MM
showDigit ( 14 , digitPositions [ 3 ] ) ; // C from array digits[][] on position 2 of MM
}
if ( LED_DIGITS = = 6 )
{ // if 6 digits....
showDigit ( tmp / 10 , digitPositions [ 2 ] ) ; // ...do the above using MM:SS positions instead of HH:MM
showDigit ( tmp % 10 , digitPositions [ 3 ] ) ;
showDigit ( 18 , digitPositions [ 4 ] ) ;
showDigit ( 14 , digitPositions [ 5 ] ) ;
2022-08-25 05:23:48 +02:00
}
}
2022-09-08 06:16:59 +02:00
}
2022-08-25 05:23:48 +02:00
# endif
# ifdef FADING
2022-09-08 06:16:59 +02:00
void fadeSegment ( uint8_t pos , uint8_t segment , uint8_t amount , uint8_t fadeType )
{
/* this will check if the first led of a given segment is lit and if it is, will fade by
amount using fadeType . fadeType is important because when fading things in that where
off previously we must avoid setting them black at first - hence fadeLightBy instead
of fadeToBlack . */
uint8_t ledAM = digitsLAM [ pos ] ; // led access mode according to the position
if ( leds [ pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ 0 ] ) ] )
{
if ( ledAM = = 0 )
{
for ( uint8_t i = 0 ; i < 2 ; i + + )
{
if ( fadeType = = 0 )
{
leds [ pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ i ] ) ] . fadeToBlackBy ( amount ) ;
}
else
{
leds [ pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ i ] ) ] . fadeLightBy ( amount ) ;
2022-08-25 05:23:48 +02:00
}
}
2022-09-08 06:16:59 +02:00
}
if ( ledAM = = 1 )
{
uint16_t startLed = pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ 0 ] ) ;
uint16_t endLed = pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ 1 ] ) ;
for ( uint16_t i = startLed ; i < = endLed ; i + + )
{
if ( fadeType = = 0 )
{
leds [ i ] . fadeToBlackBy ( amount ) ;
}
else
{
leds [ i ] . fadeLightBy ( amount ) ;
2022-08-25 05:23:48 +02:00
}
}
}
}
2022-09-08 06:16:59 +02:00
}
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
void digitsFader ( )
{
if ( fadeDigits = = 0 )
return ;
static unsigned long firstRun = 0 ; // time when a change has been detected and fading starts
static unsigned long lastRun = 0 ; // used to store time when this function was executed the last time
static boolean active = false ; // will be used as a flag when to do something / fade segments
static uint8_t previousSegments [ LED_DIGITS ] [ 7 ] = { 0 } ; // all the segments lit after the last run
static uint8_t currentSegments [ LED_DIGITS ] [ 7 ] = { 0 } ; // all the segments lit right now
static uint8_t changedSegments [ LED_DIGITS ] [ 7 ] = { 0 } ; // used to store the differences -> 1 = led has been turned off, fade out, 2 = was off, fade in
static uint8_t fadeSteps = 15 ; // steps used to fade dots in or out
lastRun = millis ( ) ;
if ( ! active )
{ // this will check if....
firstRun = millis ( ) ;
for ( uint8_t digitPos = 0 ; digitPos < LED_DIGITS ; digitPos + + )
{ // ...any of the segments are on....
for ( uint8_t segmentPos = 0 ; segmentPos < 7 ; segmentPos + + )
{
if ( leds [ pgm_read_word_near ( & segGroups [ segmentPos + digitPos * 7 ] [ 0 ] ) ] )
{
currentSegments [ digitPos ] [ segmentPos ] = 1 ;
}
else
{
currentSegments [ digitPos ] [ segmentPos ] = 0 ;
}
if ( currentSegments [ digitPos ] [ segmentPos ] ! = previousSegments [ digitPos ] [ segmentPos ] )
{ // ...and compare them to the previous displayed segments.
active = true ; // if a change has been detected, set active = true so fading gets executed
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " digitPos: " ) ) ;
Serial . print ( digitPos ) ;
Serial . print ( F ( " - segmentPos: " ) ) ;
Serial . print ( segmentPos ) ;
Serial . print ( F ( " was " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
if ( currentSegments [ digitPos ] [ segmentPos ] = = 0 )
{
changedSegments [ digitPos ] [ segmentPos ] = 1 ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " ON, is now OFF " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
else
{
changedSegments [ digitPos ] [ segmentPos ] = 2 ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " OFF, is now ON " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
}
}
}
}
2022-09-08 06:16:59 +02:00
}
if ( active )
{ // this part is executed once a change has been detected....
static uint8_t counter = 1 ;
static unsigned long lastFadeStep = millis ( ) ;
for ( uint8_t digitPos = 0 ; digitPos < LED_DIGITS ; digitPos + + )
{ // redraw segments that have turned off, so we can fade them out...
for ( uint8_t segmentPos = 0 ; segmentPos < 7 ; segmentPos + + )
{
if ( changedSegments [ digitPos ] [ segmentPos ] = = 1 )
{
showSegment ( segmentPos , digitPos ) ;
}
}
}
colorizeOutput ( colorMode ) ; // colorize again after redraw, so colors keep consistent
for ( uint8_t digitPos = 0 ; digitPos < LED_DIGITS ; digitPos + + )
{
for ( uint8_t segmentPos = 0 ; segmentPos < 7 ; segmentPos + + )
{
if ( changedSegments [ digitPos ] [ segmentPos ] = = 1 )
{ // 1 - segment has turned on, this one has to be faded in
fadeSegment ( digitPos , segmentPos , counter * ( 255.0 / fadeSteps ) , 0 ) ; // fadeToBlackBy, segments supposed to be off/fading out
}
if ( changedSegments [ digitPos ] [ segmentPos ] = = 2 )
{ // 2 - segment has turned off, this one has to be faded out
if ( fadeDigits = = 2 )
{
fadeSegment ( digitPos , segmentPos , 255 - counter * ( 255.0 / fadeSteps ) , 1 ) ; // fadeLightBy, segments supposed to be on/fading in
2022-08-25 05:23:48 +02:00
}
}
}
2022-09-08 06:16:59 +02:00
}
if ( millis ( ) - lastFadeStep > = fadeDelay )
{
counter + + ;
lastFadeStep = millis ( ) ;
}
if ( counter > fadeSteps )
{ // done with fading, reset variables...
counter = 1 ;
active = false ;
for ( uint8_t digitPos = 0 ; digitPos < LED_DIGITS ; digitPos + + )
{ // and save current segments to previousSegments
for ( uint8_t segmentPos = 0 ; segmentPos < 7 ; segmentPos + + )
{
if ( leds [ pgm_read_word_near ( & segGroups [ segmentPos + digitPos * 7 ] [ 0 ] ) ] )
{
previousSegments [ digitPos ] [ segmentPos ] = 1 ;
2022-09-06 19:20:37 +02:00
}
2022-09-08 06:16:59 +02:00
else
{
previousSegments [ digitPos ] [ segmentPos ] = 0 ;
2022-08-25 06:03:03 +02:00
}
2022-09-08 06:16:59 +02:00
changedSegments [ digitPos ] [ segmentPos ] = 0 ;
2022-08-25 06:03:03 +02:00
}
2022-09-06 19:17:32 +02:00
}
2022-09-08 06:16:59 +02:00
# ifdef DEBUG
Serial . print ( F ( " digit fading sequence took " ) ) ; // for debugging/checking duration - fading should never take longer than 1000ms!
Serial . print ( millis ( ) - firstRun ) ;
Serial . println ( F ( " ms " ) ) ;
# endif
}
}
}
void dotsFader ( )
{
if ( fadeDots = = 0 )
return ;
static unsigned long firstRun = 0 ;
static unsigned long lastRun = 0 ;
static boolean active = false ;
static uint8_t fadeSteps = 15 ;
lastRun = millis ( ) ;
if ( ! active )
{
if ( leds [ pgm_read_word_near ( & upperDots [ 0 ] ) ] )
{
active = true ;
firstRun = millis ( ) ;
}
}
if ( fadeDots = = 1 & & active )
{ // action = 1, simply turn off specidifc leds after 500ms
if ( lastRun - firstRun > = 500 )
{
for ( uint8_t i = 0 ; i < ( sizeof ( upperDots ) / sizeof ( upperDots [ 0 ] ) ) ; i + + )
{
leds [ pgm_read_word_near ( & upperDots [ i ] ) ] . setHSV ( 0 , 0 , 0 ) ;
}
for ( uint8_t i = 0 ; i < ( sizeof ( lowerDots ) / sizeof ( lowerDots [ 0 ] ) ) ; i + + )
{
leds [ pgm_read_word_near ( & lowerDots [ i ] ) ] . setHSV ( 0 , 0 , 0 ) ;
}
active = false ;
}
}
if ( fadeDots = = 2 & & active )
{ // fade in/out dots
static uint8_t counter = 1 ;
static unsigned long lastFadeStep = millis ( ) ;
static boolean fadeInDone = true ;
if ( ! fadeInDone )
{
for ( uint8_t i = 0 ; i < ( sizeof ( upperDots ) / sizeof ( upperDots [ 0 ] ) ) ; i + + )
{
leds [ pgm_read_word_near ( & upperDots [ i ] ) ] . fadeToBlackBy ( 255 - counter * ( 255.0 / fadeSteps ) ) ;
}
for ( uint8_t i = 0 ; i < ( sizeof ( lowerDots ) / sizeof ( lowerDots [ 0 ] ) ) ; i + + )
{
leds [ pgm_read_word_near ( & lowerDots [ i ] ) ] . fadeToBlackBy ( 255 - counter * ( 255.0 / fadeSteps ) ) ;
}
if ( millis ( ) - lastFadeStep > = fadeDelay )
{
2022-09-06 19:20:37 +02:00
counter + + ;
lastFadeStep = millis ( ) ;
}
2022-09-08 06:16:59 +02:00
if ( counter > fadeSteps )
{
2022-09-06 19:20:37 +02:00
counter = 1 ;
2022-09-08 06:16:59 +02:00
fadeInDone = true ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " dot fade-in sequence took " ) ) ; // for debugging/checking
2022-08-25 05:30:54 +02:00
Serial . print ( millis ( ) - firstRun ) ;
Serial . println ( F ( " ms " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
}
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
if ( lastRun - firstRun > = 950 - fadeDelay * fadeSteps )
{
for ( uint8_t i = 0 ; i < ( sizeof ( upperDots ) / sizeof ( upperDots [ 0 ] ) ) ; i + + )
{
leds [ pgm_read_word_near ( & upperDots [ i ] ) ] . fadeToBlackBy ( counter * ( 255.0 / fadeSteps ) ) ;
2022-09-06 19:17:32 +02:00
}
2022-09-08 06:16:59 +02:00
for ( uint8_t i = 0 ; i < ( sizeof ( lowerDots ) / sizeof ( lowerDots [ 0 ] ) ) ; i + + )
{
leds [ pgm_read_word_near ( & lowerDots [ i ] ) ] . fadeToBlackBy ( counter * ( 255.0 / fadeSteps ) ) ;
2022-09-06 19:17:32 +02:00
}
2022-09-08 06:16:59 +02:00
if ( millis ( ) - lastFadeStep > = fadeDelay )
{
counter + + ;
lastFadeStep = millis ( ) ;
2022-09-06 19:17:32 +02:00
}
2022-09-08 06:16:59 +02:00
if ( counter > fadeSteps )
{
counter = 1 ;
active = false ;
fadeInDone = false ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " dot fading sequence took " ) ) ; // for debugging/checking
Serial . print ( millis ( ) - firstRun ) ;
Serial . println ( F ( " ms " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
}
}
}
2022-09-08 06:16:59 +02:00
}
2022-08-25 05:23:48 +02:00
# endif
# ifdef AUTOBRIGHTNESS
2022-09-08 06:16:59 +02:00
void readLDR ( )
{ // read LDR value 5 times and write average to avgLDR
static uint8_t runCounter = 1 ;
static uint16_t tmp = 0 ;
uint8_t readOut = map ( analogRead ( pinLDR ) , 0 , 1023 , 0 , 250 ) ;
tmp + = readOut ;
if ( runCounter = = 5 )
{
avgLDR = ( tmp / 5 ) * factorLDR ;
tmp = 0 ;
runCounter = 0 ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
if ( dbgLDR )
{
Serial . print ( F ( " readLDR(): avgLDR value: " ) ) ;
Serial . print ( avgLDR ) ;
}
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
if ( avgLDR < minBrightness )
avgLDR = minBrightness ;
if ( avgLDR > brightness )
avgLDR = brightness ;
if ( avgLDR > = upperLimitLDR & & avgLDR < brightness )
avgLDR = brightness ; // if avgLDR is above upperLimitLDR switch to max current brightness
if ( avgLDR < = lowerLimitLDR )
avgLDR = minBrightness ; // if avgLDR is below lowerLimitLDR switch to minBrightness
# ifdef DEBUG
if ( dbgLDR )
{
Serial . print ( F ( " - adjusted to: " ) ) ;
Serial . println ( avgLDR ) ;
2022-09-06 19:20:37 +02:00
}
2022-09-08 06:16:59 +02:00
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
runCounter + + ;
}
2022-08-25 05:23:48 +02:00
# endif
2022-09-08 06:16:59 +02:00
void setupClock ( )
{
/* This sets time and date (if AUTODST is defined) on the clock/rtc */
clockStatus = 90 ; // clockStatus 9x = setup, relevant for other functions/coloring
while ( digitalRead ( buttonA ) = = LOW | | digitalRead ( buttonB ) = = LOW )
{ // do nothing until both buttons are released to avoid accidental inputs right away
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
2022-09-08 06:16:59 +02:00
yield ( ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
}
tmElements_t setupTime ; // Create a time element which will be used. Using the current time would
setupTime . Hour = 12 ; // give some problems (like time still running while setting hours/minutes)
setupTime . Minute = 0 ; // Setup starts at 12 (12 pm) (utc 12 if AUTODST is defined)
setupTime . Second = 0 ; //
setupTime . Day = 8 ; // date settings only used when AUTODST is defined, but will set them anyways
setupTime . Month = 7 ; // see above
setupTime . Year = 21 ; // current year - 2000 (2021 - 2000 = 21)
# ifdef USERTC
RtcDateTime writeTime ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef AUTODST
2022-09-08 06:16:59 +02:00
clockStatus = 91 ; // 91 = y/m/d setup
uint8_t y , m , d ;
y = getUserInput ( 12 , 20 , 21 , 99 ) ; // show Y + blank, get value from 21 - 99 into y
setupTime . Year = y + 30 ; // 2 digit year + 30 (epoch), so we get offset from 1970
m = getUserInput ( 16 , 17 , 1 , 12 ) ; // show M, get value from 1 - 12 into m
setupTime . Month = m ;
if ( m = = 2 )
{
if ( leapYear ( y + 2000 ) )
{ // check for leap year...
# ifdef DEBUG // ...and get according day input ranges for each month
Serial . println ( F ( " setupClock(): Leap year detected " ) ) ;
# endif
d = getUserInput ( 13 , 20 , 1 , 29 ) ;
2022-08-25 05:30:54 +02:00
}
2022-09-08 06:16:59 +02:00
else
{
d = getUserInput ( 13 , 20 , 1 , 28 ) ;
2022-08-25 05:30:54 +02:00
}
2022-09-08 06:16:59 +02:00
}
if ( m = = 1 | | m = = 3 | | m = = 5 | | m = = 7 | | m = = 8 | | m = = 10 | | m = = 12 )
{
d = getUserInput ( 13 , 20 , 1 , 31 ) ;
}
if ( m = = 4 | | m = = 6 | | m = = 9 | | m = = 11 )
{
d = getUserInput ( 13 , 20 , 1 , 30 ) ;
}
setupTime . Day = d ;
2022-09-06 19:20:37 +02:00
# ifdef USERTC
2022-09-08 06:16:59 +02:00
writeTime = { 2000 + y , setupTime . Month , setupTime . Day ,
setupTime . Hour , setupTime . Minute , setupTime . Second } ;
Rtc . SetDateTime ( writeTime ) ;
setTime ( makeTime ( setupTime ) ) ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( now ( ) ) ;
Serial . print ( F ( " setupClock(): RTC time/date set to: " ) ) ;
Serial . println ( writeTime ) ;
2022-09-06 19:20:37 +02:00
# endif
# else
2022-09-08 06:16:59 +02:00
setTime ( makeTime ( setupTime ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# else
2022-09-08 06:16:59 +02:00
setupTime . Year = 51 ;
# endif
uint8_t lastInput = 0 ;
// hours
while ( lastInput ! = 2 )
{
clockStatus = 92 ; // 92 = HH setup
if ( lastInput = = 1 )
{
if ( setupTime . Hour < 23 )
{
setupTime . Hour + + ;
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
else
{
setupTime . Hour = 0 ;
2022-08-25 05:23:48 +02:00
}
}
displayTime ( makeTime ( setupTime ) ) ;
lastInput = inputButtons ( ) ;
}
lastInput = 0 ;
2022-09-08 06:16:59 +02:00
// minutes
while ( lastInput ! = 2 )
{
clockStatus = 93 ; // 93 = MM setup
if ( lastInput = = 1 )
{
if ( setupTime . Minute < 59 )
{
setupTime . Minute + + ;
}
else
{
setupTime . Minute = 0 ;
}
}
displayTime ( makeTime ( setupTime ) ) ;
lastInput = inputButtons ( ) ;
}
lastInput = 0 ;
// seconds
if ( LED_DIGITS = = 6 )
{
while ( lastInput ! = 2 )
{
clockStatus = 94 ; // 94 = SS setup
if ( lastInput = = 1 )
{
if ( setupTime . Second < 59 )
{
setupTime . Second + + ;
}
else
{
setupTime . Second = 0 ;
}
}
displayTime ( makeTime ( setupTime ) ) ;
lastInput = inputButtons ( ) ;
}
lastInput = 0 ;
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
# ifdef AUTODST
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " setupClock(): " ) ) ;
Serial . print ( F ( " Y/M/D -> " ) ) ;
Serial . print ( 1970 + setupTime . Year ) ;
Serial . print ( F ( " / " ) ) ;
Serial . print ( setupTime . Month ) ;
Serial . print ( F ( " / " ) ) ;
Serial . println ( setupTime . Day ) ;
# endif
Serial . print ( F ( " setupClock(): " ) ) ;
Serial . print ( F ( " HH:MM:SS -> " ) ) ;
2022-09-06 19:20:37 +02:00
# ifdef AUTODST
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " AUTODST enabled, setting LOCAL time -> " ) ) ;
# endif
if ( setupTime . Hour < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . print ( setupTime . Hour ) ;
Serial . print ( F ( " : " ) ) ;
if ( setupTime . Minute < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . print ( setupTime . Minute ) ;
Serial . print ( F ( " : " ) ) ;
if ( setupTime . Second < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . println ( setupTime . Second ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef USERTC
2022-09-08 06:16:59 +02:00
writeTime = { 1970 + setupTime . Year , setupTime . Month , setupTime . Day ,
setupTime . Hour , setupTime . Minute , setupTime . Second } ;
2022-09-06 19:20:37 +02:00
# ifdef AUTODST
2022-09-08 06:16:59 +02:00
time_t t = myTimeZone . toUTC ( makeTime ( setupTime ) ) ; // get UTC time from entered time
writeTime = { 1970 + setupTime . Year , month ( t ) , day ( t ) ,
hour ( t ) , minute ( t ) , second ( t ) } ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
Rtc . SetDateTime ( writeTime ) ;
setTime ( makeTime ( setupTime ) ) ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " setupClock(): RTC time set " ) ) ;
Serial . println ( makeTime ( setupTime ) ) ;
printTime ( ) ;
2022-09-06 19:20:37 +02:00
# endif
# else
# ifdef AUTODST
2022-09-08 06:16:59 +02:00
time_t t = myTimeZone . toUTC ( makeTime ( setupTime ) ) ; // get UTC time from entered time
setTime ( t ) ;
2022-09-06 19:20:37 +02:00
# else
2022-09-08 06:16:59 +02:00
setTime ( makeTime ( setupTime ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# endif
2022-09-08 06:16:59 +02:00
clockStatus = 0 ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . println ( F ( " setupClock() done " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
uint16_t getUserInput ( uint8_t sym1 , uint8_t sym2 , uint8_t startVal , uint8_t endVal )
{
2022-09-06 19:20:37 +02:00
/* This will show two symbols on HH and allow to enter a 2 digit value using the buttons
and display the value on MM . */
2022-08-25 05:23:48 +02:00
static uint8_t lastInput = 0 ;
static uint8_t currentVal = startVal ;
static bool newInput = true ;
2022-09-08 06:16:59 +02:00
if ( newInput )
{
2022-08-25 05:23:48 +02:00
currentVal = startVal ;
newInput = false ;
}
2022-09-08 06:16:59 +02:00
while ( lastInput ! = 2 )
{
if ( lastInput = = 1 )
{
if ( currentVal < endVal )
{
2022-08-25 05:23:48 +02:00
currentVal + + ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
currentVal = startVal ;
}
}
FastLED . clear ( ) ;
showDigit ( sym1 , digitPositions [ 0 ] ) ;
showDigit ( sym2 , digitPositions [ 1 ] ) ;
showDigit ( currentVal / 10 , digitPositions [ 2 ] ) ;
showDigit ( currentVal % 10 , digitPositions [ 3 ] ) ;
2022-09-08 06:16:59 +02:00
if ( millis ( ) % 30 = = 0 )
{
2022-08-25 05:23:48 +02:00
colorizeOutput ( colorMode ) ;
FastLED . show ( ) ;
2022-09-06 19:20:37 +02:00
}
2022-08-25 05:23:48 +02:00
lastInput = inputButtons ( ) ;
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " getUserInput(): returned " ) ) ;
Serial . println ( currentVal ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
lastInput = 0 ;
newInput = true ;
return currentVal ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " getUserInput(): returned " ) ) ;
Serial . println ( currentVal ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
void colorizeOutput ( uint8_t mode )
{
2022-09-06 19:20:37 +02:00
/* So far showDigit()/showSegment() only set some leds inside the array to values from "markerHSV" but we haven't updated
the leds yet using FastLED . show ( ) . This function does the coloring of the right now single colored but " insivible "
output . This way color updates / cycles aren ' t tied to updating display contents */
2022-08-25 05:23:48 +02:00
static unsigned long lastRun = 0 ;
static unsigned long lastColorChange = 0 ;
static uint8_t startColor = 0 ;
2022-09-08 06:16:59 +02:00
static uint8_t colorOffset = 0 ; // different offsets result in quite different results, depending on the amount of leds inside each segment...
2022-09-06 19:20:37 +02:00
// ...so it's set inside each color mode if required
2022-08-25 05:23:48 +02:00
/* mode 0 = check every segment if it's lit and assign a color based on position -> different color per digit
Checking the leds like this will not include the dots - they ' ll be colored later on */
2022-09-08 06:16:59 +02:00
if ( mode = = 0 )
{
2022-08-25 05:23:48 +02:00
colorOffset = 256 / LED_DIGITS ;
2022-09-08 06:16:59 +02:00
for ( uint8_t pos = 0 ; pos < LED_DIGITS ; pos + + )
{
for ( uint8_t segment = 0 ; segment < 7 ; segment + + )
{
2022-08-25 05:23:48 +02:00
colorizeSegment ( segment , pos , startColor + colorOffset * pos ) ;
}
}
}
/* mode 1 = simply assign different colors with an offset of "colorOffset" to each led that's not black/off -
This will include the dots if they ' re supposed to be on - but they will be overwritten later for all modes */
2022-09-08 06:16:59 +02:00
if ( mode = = 1 )
{
2022-08-25 05:23:48 +02:00
colorOffset = 32 ;
2022-09-08 06:16:59 +02:00
for ( uint16_t i = 0 ; i < LED_COUNT ; i + + )
{
if ( leds [ i ] )
{
2022-08-25 05:23:48 +02:00
leds [ i ] = ColorFromPalette ( currentPalette , startColor + i * colorOffset , brightness , LINEARBLEND ) ;
}
}
}
/* mode 2 = check every segment if it's lit and assign a color based on segment -> different color per segment,
same across digits . Checking the leds like this will not include the dots - they ' ll be colored later on */
2022-09-08 06:16:59 +02:00
if ( mode = = 2 )
{
2022-08-25 05:23:48 +02:00
colorOffset = 24 ;
2022-09-08 06:16:59 +02:00
for ( uint8_t pos = 0 ; pos < LED_DIGITS ; pos + + )
{
for ( uint8_t segment = 0 ; segment < 7 ; segment + + )
{
2022-08-25 05:23:48 +02:00
colorizeSegment ( segment , digitPositions [ pos ] , startColor + 1 * colorOffset * segment ) ;
}
}
}
/* mode 3 = same as above - but will assign colorOffsets depending on segment in a specific order (top/down effect) */
2022-09-08 06:16:59 +02:00
if ( mode = = 3 )
{
uint8_t colorOffsets [ 7 ] = { 0 , 24 , 72 , 96 , 72 , 24 , 48 } ; // colorOffsets for segments a-g
for ( uint8_t pos = 0 ; pos < LED_DIGITS ; pos + + )
{
for ( uint8_t segment = 0 ; segment < 7 ; segment + + )
{
2022-08-25 05:23:48 +02:00
colorizeSegment ( segment , digitPositions [ pos ] , startColor + 1 * colorOffsets [ segment ] ) ;
}
}
}
/* clockStatus >= 90 is used for coloring output while in setup mode */
2022-09-08 06:16:59 +02:00
if ( clockStatus > = 90 )
{
2022-08-25 05:23:48 +02:00
static boolean blinkFlag = true ;
static unsigned long lastBlink = millis ( ) ;
static uint8_t b = brightnessLevels [ 0 ] ;
2022-09-08 06:16:59 +02:00
if ( millis ( ) - lastBlink > 333 )
{ // blink switch frequency, 3 times a second
if ( blinkFlag )
{
2022-08-25 05:23:48 +02:00
blinkFlag = false ;
b = brightnessLevels [ 1 ] ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
blinkFlag = true ;
b = brightnessLevels [ 0 ] ;
}
lastBlink = millis ( ) ;
2022-09-08 06:16:59 +02:00
} // unset values = red, set value = green, current value = yellow and blinkinkg
for ( uint8_t pos = 0 ; pos < LED_DIGITS ; pos + + )
{
if ( clockStatus = = 91 )
{ // Y/M/D setup
2022-08-25 05:23:48 +02:00
colorHelper ( digitPositions [ 0 ] , 0 , 255 , brightness ) ;
colorHelper ( digitPositions [ 1 ] , 0 , 255 , brightness ) ;
colorHelper ( digitPositions [ 2 ] , 64 , 255 , b ) ;
colorHelper ( digitPositions [ 3 ] , 64 , 255 , b ) ;
}
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 92 )
{ // hours
2022-08-25 05:23:48 +02:00
colorHelper ( digitPositions [ 0 ] , 64 , 255 , b ) ;
colorHelper ( digitPositions [ 1 ] , 64 , 255 , b ) ;
colorHelper ( digitPositions [ 2 ] , 0 , 255 , brightness ) ;
colorHelper ( digitPositions [ 3 ] , 0 , 255 , brightness ) ;
2022-09-08 06:16:59 +02:00
if ( LED_DIGITS = = 6 )
{
2022-08-25 05:23:48 +02:00
colorHelper ( digitPositions [ 4 ] , 0 , 255 , brightness ) ;
colorHelper ( digitPositions [ 5 ] , 0 , 255 , brightness ) ;
}
}
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 93 )
{ // minutes
2022-08-25 05:23:48 +02:00
colorHelper ( digitPositions [ 0 ] , 96 , 255 , brightness ) ;
colorHelper ( digitPositions [ 1 ] , 96 , 255 , brightness ) ;
colorHelper ( digitPositions [ 2 ] , 64 , 255 , b ) ;
colorHelper ( digitPositions [ 3 ] , 64 , 255 , b ) ;
2022-09-08 06:16:59 +02:00
if ( LED_DIGITS = = 6 )
{
2022-08-25 05:23:48 +02:00
colorHelper ( digitPositions [ 4 ] , 0 , 255 , brightness ) ;
colorHelper ( digitPositions [ 5 ] , 0 , 255 , brightness ) ;
}
}
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 94 )
{ // seconds
2022-08-25 05:23:48 +02:00
colorHelper ( digitPositions [ 0 ] , 96 , 255 , brightness ) ;
colorHelper ( digitPositions [ 1 ] , 96 , 255 , brightness ) ;
colorHelper ( digitPositions [ 2 ] , 96 , 255 , brightness ) ;
colorHelper ( digitPositions [ 3 ] , 96 , 255 , brightness ) ;
2022-09-08 06:16:59 +02:00
if ( LED_DIGITS = = 6 )
{
2022-08-25 05:23:48 +02:00
colorHelper ( digitPositions [ 4 ] , 64 , 255 , b ) ;
colorHelper ( digitPositions [ 5 ] , 64 , 255 , b ) ;
}
}
}
}
/* The dots will always be colored in the same way, just using colors from the current palette. Depending on setup/parameters
this can otherwise lead to the dots looking quite different from the digits , so as before they ' re cycling through the
color palette once per minute */
2022-09-08 06:16:59 +02:00
if ( leds [ pgm_read_word_near ( & upperDots [ 0 ] ) ] )
{ // if the first led inside the array upperDot is lit...
for ( uint8_t i = 0 ; i < ( sizeof ( upperDots ) / sizeof ( upperDots [ 0 ] ) ) ; i + + )
{ // ...start applying colors to all leds inside the array
if ( clockStatus = = 0 )
{
2022-08-25 05:23:48 +02:00
leds [ pgm_read_word_near ( & upperDots [ i ] ) ] = ColorFromPalette ( currentPalette , second ( ) * 4.25 , brightness , LINEARBLEND ) ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
leds [ pgm_read_word_near ( & upperDots [ i ] ) ] . setHSV ( 64 , 255 , brightness ) ;
}
}
}
2022-09-08 06:16:59 +02:00
if ( leds [ pgm_read_word_near ( & lowerDots [ 0 ] ) ] )
{ // same as before for the lower dots...
for ( uint8_t i = ( sizeof ( lowerDots ) / sizeof ( lowerDots [ 0 ] ) ) ; i > 0 ; i - - )
{
if ( clockStatus = = 0 )
{
2022-08-25 05:23:48 +02:00
leds [ pgm_read_word_near ( & lowerDots [ i - 1 ] ) ] = ColorFromPalette ( currentPalette , second ( ) * 4.25 , brightness , LINEARBLEND ) ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
leds [ pgm_read_word_near ( & lowerDots [ i - 1 ] ) ] . setHSV ( 64 , 255 , brightness ) ;
}
}
}
2022-09-06 19:20:37 +02:00
# ifdef FASTFORWARD
2022-09-08 06:16:59 +02:00
if ( millis ( ) - lastColorChange > 15 )
{
2022-09-06 19:20:37 +02:00
# else
2022-09-08 06:16:59 +02:00
if ( millis ( ) - lastColorChange > colorSpeed )
{
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
if ( reverseColorCycling )
{
2022-08-25 05:23:48 +02:00
startColor - - ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
startColor + + ;
}
lastColorChange = millis ( ) ;
}
2022-09-06 19:20:37 +02:00
# ifdef AUTOBRIGHTNESS
2022-09-08 06:16:59 +02:00
if ( nightMode & & clockStatus = = 0 )
{ // nightmode will overwrite everything that has happened so far...
for ( uint16_t i = 0 ; i < LED_COUNT ; i + + )
{
if ( leds [ i ] )
{
if ( avgLDR = = minBrightness )
{
leds [ i ] . setHSV ( nightColor [ 0 ] , 255 , nightColor [ 1 ] ) ; // and assign nightColor to all lit leds. Default is a very dark red.
2022-08-25 05:23:48 +02:00
FastLED . setDither ( 0 ) ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
FastLED . setDither ( 1 ) ;
}
}
}
}
2022-09-06 19:20:37 +02:00
# endif
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
/* // example for time based coloring
// for coloring based on current times the following will get local display time into
// checkTime if autoDST is defined as the clock is running in utc time then
# ifdef AUTODST
time_t checkTime = myTimeZone . toLocal ( now ( ) ) ;
# else
time_t checkTime = now ( ) ;
# endif
2022-08-25 05:23:48 +02:00
2022-09-06 19:20:37 +02:00
// below if-loop simply checks for a given time and colors everything in green/blue accordingly
if ( hour ( checkTime ) > 6 & & hour ( checkTime ) < = 22 ) { // if hour > 6 AND hour <= 22 ---> 07:00 - 22:59
for ( uint16_t i = 0 ; i < LED_COUNT ; i + + ) { // for each position...
if ( leds [ i ] ) { // ...check led and if it's lit...
leds [ i ] . setHSV ( 96 , 255 , brightness ) ; // ...redraw with HSV color 96 -> green
}
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
} else { // ---> 23:00 - 06:59
for ( uint16_t i = 0 ; i < LED_COUNT ; i + + ) { // for each position...
if ( leds [ i ] ) { // ...check led and if it's lit...
leds [ i ] . setHSV ( 160 , 255 , brightness ) ; // ...redraw with HSV color 160 -> blue
}
2022-08-25 05:23:48 +02:00
}
}
2022-09-06 19:20:37 +02:00
*/
2022-08-25 05:23:48 +02:00
lastRun = millis ( ) ;
}
2022-09-08 06:16:59 +02:00
void colorizeSegment ( uint8_t segment , uint8_t pos , uint8_t color )
{
2022-09-06 19:20:37 +02:00
/* Checks if segment at position is on - and if it is, assigns color from current palette */
2022-09-08 06:16:59 +02:00
uint8_t ledAM = digitsLAM [ pos ] ; // led access mode according to the position
if ( leds [ pgm_read_word_near ( & segGroups [ segment + digitPositions [ pos ] * 7 ] [ 0 ] ) ] )
{
if ( ledAM = = 0 )
{
for ( uint8_t i = 0 ; i < 2 ; i + + )
{
2022-08-25 05:23:48 +02:00
leds [ pgm_read_word_near ( & segGroups [ segment + digitPositions [ pos ] * 7 ] [ i ] ) ] = ColorFromPalette ( currentPalette , color , brightness , LINEARBLEND ) ;
}
}
2022-09-08 06:16:59 +02:00
if ( ledAM = = 1 )
{
2022-08-25 05:23:48 +02:00
uint16_t startLed = pgm_read_word_near ( & segGroups [ segment + digitPositions [ pos ] * 7 ] [ 0 ] ) ;
uint16_t endLed = pgm_read_word_near ( & segGroups [ segment + digitPositions [ pos ] * 7 ] [ 1 ] ) ;
2022-09-08 06:16:59 +02:00
for ( uint16_t i = startLed ; i < = endLed ; i + + )
{
2022-08-25 05:23:48 +02:00
leds [ i ] = ColorFromPalette ( currentPalette , color , brightness , LINEARBLEND ) ;
}
}
}
}
2022-09-08 06:16:59 +02:00
void colorHelper ( uint8_t pos , uint8_t hue , uint8_t sat , uint8_t bri )
{
2022-09-06 19:20:37 +02:00
/* Used for coloring digits inside setup routines/steps
It will simply set the digit at the given position to the given hsv values */
2022-09-08 06:16:59 +02:00
uint8_t ledAM = digitsLAM [ pos ] ; // led access mode according to the position
for ( uint8_t segment = 0 ; segment < 7 ; segment + + )
{
if ( leds [ pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ 0 ] ) ] )
{ // if first led inside segment is lit...
if ( ledAM = = 0 )
{
for ( uint8_t i = 0 ; i < 2 ; i + + )
{ // assign hue to led 0 + 1 inside segment
2022-08-25 05:23:48 +02:00
leds [ pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ i ] ) ] . setHSV ( hue , sat , bri ) ;
}
}
2022-09-08 06:16:59 +02:00
if ( ledAM = = 1 )
{
2022-08-25 05:23:48 +02:00
uint16_t startLed = pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ 0 ] ) ;
uint16_t endLed = pgm_read_word_near ( & segGroups [ segment + pos * 7 ] [ 1 ] ) ;
2022-09-08 06:16:59 +02:00
for ( uint16_t i = startLed ; i < = endLed ; i + + )
{ // assign hue to led 0 - 1 inside segment
2022-08-25 05:23:48 +02:00
leds [ i ] . setHSV ( hue , sat , bri ) ;
}
}
}
}
}
2022-09-08 06:16:59 +02:00
void displayTime ( time_t t )
{
2022-09-06 19:20:37 +02:00
# ifdef AUTODST
2022-09-08 06:16:59 +02:00
if ( clockStatus < 90 )
{ // display adjusted times only while NOT in setup
t = myTimeZone . toLocal ( t ) ; // convert display time to local time zone according to rules on top of the sketch
2022-09-06 19:20:37 +02:00
}
# endif
2022-09-08 06:16:59 +02:00
if ( clockStatus > = 90 )
{
2022-08-25 05:23:48 +02:00
FastLED . clear ( ) ;
}
/* hours */
2022-09-08 06:16:59 +02:00
if ( displayMode = = 0 )
{
if ( hour ( t ) < 10 )
{
if ( leadingZero )
{
2022-08-25 05:23:48 +02:00
showDigit ( 0 , digitPositions [ 0 ] ) ;
}
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
showDigit ( hour ( t ) / 10 , digitPositions [ 0 ] ) ;
}
showDigit ( hour ( t ) % 10 , digitPositions [ 1 ] ) ;
2022-09-08 06:16:59 +02:00
}
else if ( displayMode = = 1 )
{
if ( hourFormat12 ( t ) < 10 )
{
if ( leadingZero )
{
2022-08-25 05:23:48 +02:00
showDigit ( 0 , digitPositions [ 0 ] ) ;
}
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
showDigit ( hourFormat12 ( t ) / 10 , digitPositions [ 0 ] ) ;
}
showDigit ( hourFormat12 ( t ) % 10 , digitPositions [ 1 ] ) ;
}
/* minutes */
showDigit ( minute ( t ) / 10 , digitPositions [ 2 ] ) ;
showDigit ( minute ( t ) % 10 , digitPositions [ 3 ] ) ;
2022-09-08 06:16:59 +02:00
if ( LED_DIGITS = = 6 )
{
2022-08-25 05:23:48 +02:00
/* seconds */
showDigit ( second ( t ) / 10 , digitPositions [ 4 ] ) ;
showDigit ( second ( t ) % 10 , digitPositions [ 5 ] ) ;
}
2022-09-08 06:16:59 +02:00
if ( clockStatus > = 90 )
{ // in setup modes displayTime will also use colorizeOutput/FastLED.show!
2022-08-25 05:23:48 +02:00
static unsigned long lastRefresh = millis ( ) ;
2022-09-08 06:16:59 +02:00
if ( isAM ( t ) & & displayMode = = 1 )
{ // in 12h mode and if it's AM only light up the upper dots (while setting time)
2022-08-25 05:23:48 +02:00
showDots ( 1 ) ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
showDots ( 2 ) ;
}
2022-09-06 19:20:37 +02:00
showAmPm ( isAM ( t ) ) ;
2022-09-08 06:16:59 +02:00
if ( millis ( ) - lastRefresh > = 25 )
{
2022-08-25 05:23:48 +02:00
colorizeOutput ( colorMode ) ;
FastLED . show ( ) ;
lastRefresh = millis ( ) ;
}
return ;
}
/* dots */
2022-09-08 06:16:59 +02:00
if ( dotsBlinking )
{
if ( second ( t ) % 2 = = 0 )
{
2022-08-25 05:23:48 +02:00
showDots ( 2 ) ;
}
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
showDots ( 2 ) ;
}
}
2022-09-08 06:16:59 +02:00
void showSegment ( uint8_t segment , uint8_t segDisplay )
{
2022-08-25 05:23:48 +02:00
// This shows the segments from top of the sketch on a given position (segDisplay). Order of positions/segDisplay is the order
// of definitions on the top, first one defined is segDisplay 0, second one is segDisplay 1 and so on...
// "firstLoop" is used to display all information only once per test if customHelper is defined
2022-09-08 06:16:59 +02:00
uint8_t ledAM = digitsLAM [ segDisplay ] ; // led access mode according to the position
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
# ifdef CUSTOMHELPER
2022-09-08 06:16:59 +02:00
if ( firstLoop )
{
Serial . print ( F ( " LED_ACCESS_MODE for segment " ) ) ;
Serial . print ( segment ) ;
Serial . print ( F ( " at position " ) ) ;
Serial . print ( segDisplay ) ;
Serial . print ( F ( " is " ) ) ;
Serial . print ( ledAM ) ;
2022-09-06 19:20:37 +02:00
}
# endif
# endif
2022-09-08 06:16:59 +02:00
if ( ledAM = = 0 )
{ // using both values inside the array to light up two leds
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
# ifdef CUSTOMHELPER
2022-09-08 06:16:59 +02:00
if ( firstLoop )
{
2022-09-06 19:20:37 +02:00
Serial . print ( F ( " . Leds " ) ) ;
}
# endif
# endif
2022-08-25 05:23:48 +02:00
segment + = segDisplay * 7 ;
2022-09-08 06:16:59 +02:00
for ( uint8_t i = 0 ; i < 2 ; i + + )
{
2022-08-25 05:23:48 +02:00
leds [ pgm_read_word_near ( & segGroups [ segment ] [ i ] ) ] . setHSV ( markerHSV [ 0 ] , markerHSV [ 1 ] , markerHSV [ 2 ] ) ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
# ifdef CUSTOMHELPER
2022-09-08 06:16:59 +02:00
if ( firstLoop )
{
if ( i = = 0 )
{
Serial . print ( pgm_read_word_near ( & segGroups [ segment ] [ i ] ) ) ;
Serial . print ( F ( " and " ) ) ;
2022-09-06 19:20:37 +02:00
}
2022-09-08 06:16:59 +02:00
if ( i = = 1 )
{
2022-09-06 19:20:37 +02:00
Serial . println ( pgm_read_word_near ( & segGroups [ segment ] [ i ] ) ) ;
}
}
# endif
# endif
2022-08-25 05:23:48 +02:00
}
}
2022-09-08 06:16:59 +02:00
if ( ledAM = = 1 )
{ // using both values inside the array as start and end to light up multiple leds
2022-08-25 05:23:48 +02:00
segment + = segDisplay * 7 ;
uint16_t startLed = pgm_read_word_near ( & segGroups [ segment ] [ 0 ] ) ;
uint16_t endLed = pgm_read_word_near ( & segGroups [ segment ] [ 1 ] ) ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
# ifdef CUSTOMHELPER
2022-09-08 06:16:59 +02:00
if ( firstLoop )
{
Serial . print ( F ( " . Leds " ) ) ;
Serial . print ( startLed ) ;
Serial . print ( F ( " - " ) ) ;
Serial . println ( endLed ) ;
2022-09-06 19:20:37 +02:00
}
# endif
# endif
2022-09-08 06:16:59 +02:00
for ( uint16_t i = startLed ; i < = endLed ; i + + )
{
2022-08-25 05:23:48 +02:00
leds [ i ] . setHSV ( markerHSV [ 0 ] , markerHSV [ 1 ] , markerHSV [ 2 ] ) ;
}
}
}
2022-09-08 06:16:59 +02:00
void showDots ( uint8_t dots )
{
2022-09-06 19:20:37 +02:00
// // dots 0 = upper dots, dots 1 = lower dots, dots 2 = all dots (right/left/both on Lazy 7 - Quick Build Edition)
// if ( dots == 1 || dots == 2 ) {
// for ( uint8_t i = 0; i < ( sizeof(upperDots) / sizeof(upperDots[0]) ); i++ ) {
// leds[pgm_read_word_near(&upperDots[i])].setHSV(markerHSV[0], markerHSV[1], markerHSV[2]);
// }
// }
// if ( dots == 0 || dots == 2 ) {
// for ( uint8_t i = 0; i < ( sizeof(lowerDots) / sizeof(lowerDots[0]) ); i++ ) {
// leds[pgm_read_word_near(&lowerDots[i])].setHSV(markerHSV[0], markerHSV[1], markerHSV[2]);
// }
// }
}
2022-09-08 06:16:59 +02:00
void showAmPm ( bool amFlag )
{
if ( amFlag = = false )
2022-09-06 19:20:37 +02:00
{
leds [ pgm_read_word_near ( & pmLight [ 0 ] ) ] . setHSV ( 160 , 255 , brightness ) ;
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
else
{
leds [ pgm_read_word_near ( & amLight [ 0 ] ) ] . setHSV ( 64 , 255 , brightness ) ;
2022-08-25 05:23:48 +02:00
}
}
2022-09-08 06:16:59 +02:00
void showDigit ( uint8_t digit , uint8_t pos )
{
2022-08-25 05:23:48 +02:00
// This draws numbers using the according segments as defined on top of the sketch (0 - 9) or symbols/characters (index 10+)
2022-09-08 06:16:59 +02:00
for ( uint8_t i = 0 ; i < 7 ; i + + )
{
if ( pgm_read_byte_near ( & digits [ digit ] [ i ] ) ! = 0 )
showSegment ( i , pos ) ;
2022-08-25 05:23:48 +02:00
}
}
2022-09-08 06:16:59 +02:00
void paletteSwitcher ( )
{
2022-09-06 19:20:37 +02:00
/* As the name suggests this takes care of switching palettes. When adding palettes, make sure paletteCount increases
accordingly . A few examples of gradients / solid colors by using RGB values or HTML Color Codes below */
static uint8_t paletteCount = 6 ;
2022-08-25 05:23:48 +02:00
static uint8_t currentIndex = 0 ;
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 1 )
{ // Clock is starting up, so load selected palette from eeprom...
2022-08-25 05:23:48 +02:00
uint8_t tmp = EEPROM . read ( 0 ) ;
2022-09-08 06:16:59 +02:00
if ( tmp > = 0 & & tmp < paletteCount )
{
currentIndex = tmp ; // 255 from eeprom would mean there's nothing been written yet, so checking range...
}
else
{
currentIndex = 0 ; // ...and default to 0 if returned value from eeprom is not 0 - 6
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " paletteSwitcher(): loaded EEPROM value " ) ) ;
Serial . println ( tmp ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
switch ( currentIndex )
{
case 0 :
currentPalette = CRGBPalette16 ( CRGB ( 224 , 0 , 32 ) ,
CRGB ( 0 , 0 , 244 ) ,
CRGB ( 128 , 0 , 128 ) ,
CRGB ( 224 , 0 , 64 ) ) ;
break ;
case 1 :
currentPalette = CRGBPalette16 ( CRGB ( 224 , 16 , 0 ) ,
CRGB ( 192 , 64 , 0 ) ,
CRGB ( 192 , 128 , 0 ) ,
CRGB ( 240 , 40 , 0 ) ) ;
break ;
case 2 :
currentPalette = CRGBPalette16 ( CRGB : : Aquamarine ,
CRGB : : Turquoise ,
CRGB : : Blue ,
CRGB : : DeepSkyBlue ) ;
break ;
case 3 :
currentPalette = RainbowColors_p ;
break ;
case 4 :
currentPalette = PartyColors_p ;
break ;
case 5 :
currentPalette = CRGBPalette16 ( CRGB : : LawnGreen ) ;
break ;
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " paletteSwitcher(): selected palette " ) ) ;
Serial . println ( currentIndex ) ;
# endif
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 0 )
{ // only save selected palette to eeprom if clock is in normal running mode, not while in startup/setup/whatever
2022-08-25 05:23:48 +02:00
EEPROM . put ( 0 , currentIndex ) ;
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
EEPROM . commit ( ) ;
# endif
# ifdef DEBUG
Serial . print ( F ( " paletteSwitcher(): saved index " ) ) ;
Serial . print ( currentIndex ) ;
Serial . println ( F ( " to eeprom " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
if ( currentIndex < paletteCount - 1 )
{
2022-09-06 19:20:37 +02:00
currentIndex + + ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
currentIndex = 0 ;
}
2022-09-08 06:16:59 +02:00
if ( colorPreview )
{
2022-08-25 05:23:48 +02:00
previewMode ( ) ;
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . println ( F ( " paletteSwitcher() done " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
void brightnessSwitcher ( )
{
2022-08-25 05:23:48 +02:00
static uint8_t currentIndex = 0 ;
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 1 )
{ // Clock is starting up, so load selected palette from eeprom...
2022-08-25 05:23:48 +02:00
uint8_t tmp = EEPROM . read ( 1 ) ;
2022-09-08 06:16:59 +02:00
if ( tmp > = 0 & & tmp < 3 )
{
currentIndex = tmp ; // 255 from eeprom would mean there's nothing been written yet, so checking range...
}
else
{
currentIndex = 0 ; // ...and default to 0 if returned value from eeprom is not 0 - 2
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " brightnessSwitcher(): loaded EEPROM value " ) ) ;
Serial . println ( tmp ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
switch ( currentIndex )
{
case 0 :
brightness = brightnessLevels [ currentIndex ] ;
break ;
case 1 :
brightness = brightnessLevels [ currentIndex ] ;
break ;
case 2 :
brightness = brightnessLevels [ currentIndex ] ;
break ;
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " brightnessSwitcher(): selected brightness index " ) ) ;
Serial . println ( currentIndex ) ;
# endif
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 0 )
{ // only save selected brightness to eeprom if clock is in normal running mode, not while in startup/setup/whatever
2022-08-25 05:23:48 +02:00
EEPROM . put ( 1 , currentIndex ) ;
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
EEPROM . commit ( ) ;
# endif
# ifdef DEBUG
Serial . print ( F ( " brightnessSwitcher(): saved index " ) ) ;
Serial . print ( currentIndex ) ;
Serial . println ( F ( " to eeprom " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
if ( currentIndex < 2 )
{
2022-09-06 19:20:37 +02:00
currentIndex + + ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
currentIndex = 0 ;
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG {
Serial . println ( F ( " brightnessSwitcher() done " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
void colorModeSwitcher ( )
{
2022-08-25 05:23:48 +02:00
static uint8_t currentIndex = 0 ;
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 1 )
{ // Clock is starting up, so load selected palette from eeprom...
if ( colorMode ! = 0 )
return ; // 0 is default, if it's different on startup the config is set differently, so exit here
2022-08-25 05:23:48 +02:00
uint8_t tmp = EEPROM . read ( 3 ) ;
2022-09-08 06:16:59 +02:00
if ( tmp > = 0 & & tmp < 4 )
{ // make sure tmp < 3 is increased if color modes are added in colorizeOutput()!
currentIndex = tmp ; // 255 from eeprom would mean there's nothing been written yet, so checking range...
}
else
{
currentIndex = 0 ; // ...and default to 0 if returned value from eeprom is not 0 - 2
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " colorModeSwitcher(): loaded EEPROM value " ) ) ;
Serial . println ( tmp ) ;
# endif
2022-08-25 05:23:48 +02:00
}
colorMode = currentIndex ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " colorModeSwitcher(): selected colorMode " ) ) ;
Serial . println ( currentIndex ) ;
# endif
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 0 )
{ // only save selected colorMode to eeprom if clock is in normal running mode, not while in startup/setup/whatever
2022-08-25 05:23:48 +02:00
EEPROM . put ( 3 , currentIndex ) ;
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
EEPROM . commit ( ) ;
# endif
# ifdef DEBUG
Serial . print ( F ( " colorModeSwitcher(): saved index " ) ) ;
Serial . print ( currentIndex ) ;
Serial . println ( F ( " to eeprom " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
if ( currentIndex < 3 )
{
2022-09-06 19:20:37 +02:00
currentIndex + + ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
currentIndex = 0 ;
}
2022-09-08 06:16:59 +02:00
if ( colorPreview )
{
2022-08-25 05:23:48 +02:00
previewMode ( ) ;
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG {
Serial . println ( F ( " colorModeSwitcher() done " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
void displayModeSwitcher ( )
{
2022-08-25 05:23:48 +02:00
static uint8_t currentIndex = 0 ;
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 1 )
{ // Clock is starting up, so load selected palette from eeprom...
if ( displayMode ! = 0 )
return ; // 0 is default, if it's different on startup the config is set differently, so exit here
2022-08-25 05:23:48 +02:00
uint8_t tmp = EEPROM . read ( 2 ) ;
2022-09-08 06:16:59 +02:00
if ( tmp > = 0 & & tmp < 2 )
{ // make sure tmp < 2 is increased if display modes are added
currentIndex = tmp ; // 255 from eeprom would mean there's nothing been written yet, so checking range...
}
else
{
currentIndex = 0 ; // ...and default to 0 if returned value from eeprom is not 0 - 1 (24h/12h mode)
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " displayModeSwitcher(): loaded EEPROM value " ) ) ;
Serial . println ( tmp ) ;
# endif
2022-08-25 05:23:48 +02:00
}
displayMode = currentIndex ;
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " displayModeSwitcher(): selected displayMode " ) ) ;
Serial . println ( currentIndex ) ;
# endif
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 0 )
{ // only save selected colorMode to eeprom if clock is in normal running mode, not while in startup/setup/whatever
2022-08-25 05:23:48 +02:00
EEPROM . put ( 2 , currentIndex ) ;
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
EEPROM . commit ( ) ;
# endif
# ifdef DEBUG
Serial . print ( F ( " displayModeSwitcher(): saved index " ) ) ;
Serial . print ( currentIndex ) ;
Serial . println ( F ( " to eeprom " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 0 )
{ // show 12h/24h for 2 seconds after selected in normal run mode, don't show this on startup (status 1)
2022-08-25 05:23:48 +02:00
FastLED . clear ( ) ;
unsigned long timer = millis ( ) ;
2022-09-08 06:16:59 +02:00
while ( millis ( ) - timer < = 2000 )
{
if ( currentIndex = = 0 )
{
2022-08-25 05:23:48 +02:00
showDigit ( 2 , digitPositions [ 0 ] ) ;
showDigit ( 4 , digitPositions [ 1 ] ) ;
showDigit ( 19 , digitPositions [ 3 ] ) ;
}
2022-09-08 06:16:59 +02:00
if ( currentIndex = = 1 )
{
2022-08-25 05:23:48 +02:00
showDigit ( 1 , digitPositions [ 0 ] ) ;
showDigit ( 2 , digitPositions [ 1 ] ) ;
showDigit ( 19 , digitPositions [ 3 ] ) ;
}
colorizeOutput ( colorMode ) ;
2022-09-08 06:16:59 +02:00
if ( millis ( ) % 50 = = 0 )
{
2022-08-25 05:23:48 +02:00
FastLED . show ( ) ;
}
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
yield ( ) ;
# endif
2022-08-25 05:23:48 +02:00
}
}
2022-09-08 06:16:59 +02:00
if ( currentIndex < 1 )
{
2022-09-06 19:20:37 +02:00
currentIndex + + ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-08-25 05:23:48 +02:00
currentIndex = 0 ;
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG {
Serial . println ( F ( " displayModeSwitcher() done " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
void previewMode ( )
{
2022-09-06 19:20:37 +02:00
/* This will simply display "8" on all positions, speed up the color cyling and preview the
selected palette or colorMode */
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 1 )
return ; // don't preview when starting up
2022-08-25 05:23:48 +02:00
unsigned long previewStart = millis ( ) ;
uint16_t colorSpeedBak = colorSpeed ;
colorSpeed = 5 ;
2022-09-08 06:16:59 +02:00
while ( millis ( ) - previewStart < = uint16_t ( colorPreviewDuration * 1000L ) )
{
for ( uint8_t i = 0 ; i < LED_DIGITS ; i + + )
{
2022-08-25 05:23:48 +02:00
showDigit ( 8 , i ) ;
}
colorizeOutput ( colorMode ) ;
FastLED . show ( ) ;
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
yield ( ) ;
# endif
2022-08-25 05:23:48 +02:00
}
colorSpeed = colorSpeedBak ;
FastLED . clear ( ) ;
}
# endif /* LEDSTUFF */
2022-09-08 06:16:59 +02:00
bool leapYear ( uint16_t y )
{
2022-08-25 05:23:48 +02:00
boolean isLeapYear = false ;
2022-09-08 06:16:59 +02:00
if ( y % 4 = = 0 )
isLeapYear = true ;
if ( y % 100 = = 0 & & y % 400 ! = 0 )
isLeapYear = false ;
if ( y % 400 = = 0 )
isLeapYear = true ;
if ( isLeapYear )
return true ;
else
return false ;
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
uint8_t inputButtons ( )
{
2022-08-25 05:23:48 +02:00
/* This scans for button presses and keeps track of delay/repeat for user inputs
Short keypresses will only be returned when buttons are released before repeatDelay
is reached . This is to avoid constantly sending 1 or 2 when executing a long button
press and / or multiple buttons .
Note : Buttons are using pinMode INPUT_PULLUP , so HIGH = not pressed , LOW = pressed ! */
2022-09-08 06:16:59 +02:00
static uint8_t scanInterval = 30 ; // only check buttons every 30ms
static uint16_t repeatDelay = 1000 ; // delay in milliseconds before repeating detected keypresses
static uint8_t repeatRate = 1000 / 10 ; // 10 chars per 1000 milliseconds
static uint8_t minTime = scanInterval * 2 ; // minimum time to register a button as pressed
static unsigned long lastReadout = millis ( ) ; // keeps track of when the last readout happened
static unsigned long lastReturn = millis ( ) ; // keeps track of when the last readout value was returned
static uint8_t lastState = 0 ; // button state from previous scan
uint8_t currentState = 0 ; // button state from current scan
uint8_t retVal = 0 ; // return value, will be 0 if no button is pressed
static unsigned long eventStart = millis ( ) ; // keep track of when button states are changing
if ( millis ( ) - lastReadout < scanInterval )
return 0 ; // only scan for button presses every <scanInterval> ms
if ( digitalRead ( buttonA ) = = LOW )
currentState + = 1 ;
if ( digitalRead ( buttonB ) = = LOW )
currentState + = 2 ;
if ( currentState = = 0 & & currentState = = lastState )
{
2022-08-25 05:23:48 +02:00
btnRepeatCounter = 0 ;
}
2022-09-08 06:16:59 +02:00
if ( currentState ! = 0 & & currentState ! = lastState )
{ // if any button is pressed and different from the previous scan...
eventStart = millis ( ) ; // ...reset eventStart to current time
btnRepeatCounter = 0 ; // ...and reset global variable btnRepeatCounter
}
if ( currentState ! = 0 & & currentState = = lastState )
{ // if same input has been detected at least twice (2x scanInterval)...
if ( millis ( ) - eventStart > = repeatDelay )
{ // ...and longer than repeatDelay...
if ( millis ( ) - lastReturn > = repeatRate )
{ // ...check for repeatRate...
retVal = currentState ; // ...and set retVal to currentState
2022-08-25 05:23:48 +02:00
btnRepeatCounter + + ;
lastReturn = millis ( ) ;
2022-09-08 06:16:59 +02:00
}
else
retVal = 0 ; // return 0 if repeatDelay hasn't been reached yet
2022-08-25 05:23:48 +02:00
}
}
2022-09-08 06:16:59 +02:00
if ( currentState = = 0 & & currentState ! = lastState & & millis ( ) - eventStart > = minTime & & btnRepeatCounter = = 0 )
{
retVal = lastState ; // return lastState if all buttons are released after having been pressed for <minTime> ms
2022-08-25 05:23:48 +02:00
btnRepeatCounter = 0 ;
}
lastState = currentState ;
lastReadout = millis ( ) ;
2022-09-08 06:16:59 +02:00
# ifdef DEBUG // output some information and read serial input, if available
2022-09-06 19:20:37 +02:00
uint8_t serialInput = dbgInput ( ) ;
2022-09-08 06:16:59 +02:00
if ( serialInput ! = 0 )
{
Serial . print ( F ( " inputButtons(): Serial input detected: " ) ) ;
Serial . println ( serialInput ) ;
2022-09-06 19:20:37 +02:00
retVal = serialInput ;
}
2022-09-08 06:16:59 +02:00
if ( retVal ! = 0 )
{
Serial . print ( F ( " inputButtons(): Return value is: " ) ) ;
Serial . print ( retVal ) ;
Serial . print ( F ( " - btnRepeatCounter is: " ) ) ;
Serial . println ( btnRepeatCounter ) ;
2022-09-06 19:20:37 +02:00
}
# endif
2022-08-25 05:23:48 +02:00
return retVal ;
}
// following will only be included if USENTP is defined
# ifdef USENTP
/* This syncs system time to the RTC at startup and will periodically do other sync related
things , like syncing rtc to ntp time */
2022-09-08 06:16:59 +02:00
void syncHelper ( )
{
static unsigned long lastSync = millis ( ) ; // keeps track of the last time a sync attempt has been made
if ( millis ( ) - lastSync < 60000 & & clockStatus ! = 1 )
return ; // only allow one ntp request per minute
if ( WiFi . status ( ) ! = WL_CONNECTED )
{
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . println ( F ( " syncHelper(): No WiFi connection " ) ) ;
return ;
# endif
}
# ifndef USERTC
# ifndef USENTP
# ifdef DEBUG
Serial . println ( F ( " syncHelper(): No RTC and no NTP configured, nothing to do... " ) ) ;
return ;
# endif
# endif
# endif
time_t ntpTime = 0 ;
# ifdef USERTC
RtcDateTime ntpTimeConverted = ntpTime ;
# endif
2022-09-08 06:16:59 +02:00
if ( clockStatus = = 1 )
{ // looks like the sketch has just started running...
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . println ( F ( " syncHelper(): Initial sync on power up... " ) ) ;
# endif
ntpTime = getTimeNTP ( ) ;
# ifdef DEBUG
Serial . print ( F ( " syncHelper(): NTP result is " ) ) ;
Serial . println ( ntpTime ) ;
# endif
lastSync = millis ( ) ;
2022-09-08 06:16:59 +02:00
}
else
{
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . println ( F ( " syncHelper(): Resyncing to NTP... " ) ) ;
# endif
ntpTime = getTimeNTP ( ) ;
# ifdef DEBUG
Serial . print ( F ( " syncHelper(): NTP result is " ) ) ;
Serial . println ( ntpTime ) ;
# endif
lastSync = millis ( ) ;
}
# ifdef USERTC
2022-09-08 06:16:59 +02:00
ntpTimeConverted = { year ( ntpTime ) , month ( ntpTime ) , day ( ntpTime ) ,
hour ( ntpTime ) , minute ( ntpTime ) , second ( ntpTime ) } ;
RtcDateTime rtcTime = Rtc . GetDateTime ( ) ; // get current time from the rtc....
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
if ( ntpTime > 100 )
{
2022-09-06 19:20:37 +02:00
Rtc . SetDateTime ( ntpTimeConverted ) ;
2022-08-25 06:03:03 +02:00
}
2022-09-06 19:20:37 +02:00
# endif
# else
2022-09-08 06:16:59 +02:00
time_t sysTime = now ( ) ; // ...or from system
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . println ( F ( " syncHelper(): No RTC configured, using system time " ) ) ;
Serial . print ( F ( " syncHelper(): sysTime was " ) ) ;
Serial . println ( now ( ) ) ;
# endif
2022-09-08 06:16:59 +02:00
if ( ntpTime > 100 )
{
2022-09-06 19:20:37 +02:00
setTime ( ntpTime ) ;
}
# endif
# ifdef DEBUG
Serial . println ( F ( " syncHelper() done " ) ) ;
# endif
}
2022-08-25 05:23:48 +02:00
2022-09-08 06:16:59 +02:00
time_t getTimeNTP ( )
{
2022-09-06 19:20:37 +02:00
unsigned long startTime = millis ( ) ;
time_t timeNTP ;
2022-09-08 06:16:59 +02:00
if ( WiFi . status ( ) ! = WL_CONNECTED )
{
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " getTimeNTP(): Not connected, WiFi.status is " ) ) ;
Serial . println ( WiFi . status ( ) ) ;
# endif
2022-09-08 06:16:59 +02:00
} // Sometimes the connection doesn't work right away although status is WL_CONNECTED...
while ( millis ( ) - startTime < 2000 )
{ // ...so we'll wait a moment before causing network traffic
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
yield ( ) ;
# endif
2022-08-25 06:03:03 +02:00
}
2022-09-06 19:20:37 +02:00
timeClient . update ( ) ;
timeNTP = timeClient . getEpochTime ( ) ;
2022-09-08 06:16:59 +02:00
if ( timeNTP < 100 )
{
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " getTimeNTP(): NTP returned " ) ) ;
Serial . println ( timeNTP ) ;
2022-09-06 19:20:37 +02:00
Serial . print ( F ( " - trying again... " ) ) ;
# endif
}
timeClient . update ( ) ;
timeNTP = timeClient . getEpochTime ( ) ;
2022-09-08 06:16:59 +02:00
if ( timeNTP < 100 )
{
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " getTimeNTP(): NTP returned " ) ) ;
Serial . println ( timeNTP ) ;
2022-09-06 19:20:37 +02:00
Serial . print ( F ( " - giving up " ) ) ;
# endif
}
# ifdef DEBUG
Serial . println ( F ( " getTimeNTP() done " ) ) ;
# endif
return timeNTP ;
}
2022-08-25 05:23:48 +02:00
# endif
// ---
// functions below will only be included if DEBUG is defined on top of the sketch
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
void printTime ( )
{
2022-09-06 19:20:37 +02:00
/* outputs current system and RTC time to the serial monitor, adds autoDST if defined */
time_t tmp = now ( ) ;
# ifdef USERTC
RtcDateTime tmp2 = Rtc . GetDateTime ( ) . Epoch32Time ( ) ;
setTime ( tmp2 ) ;
tmp = now ( ) ;
# endif
Serial . println ( F ( " ----------------------------------- " ) ) ;
Serial . print ( F ( " System time is : " ) ) ;
2022-09-08 06:16:59 +02:00
if ( hour ( tmp ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . print ( hour ( tmp ) ) ;
Serial . print ( F ( " : " ) ) ;
if ( minute ( tmp ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . print ( minute ( tmp ) ) ;
Serial . print ( F ( " : " ) ) ;
if ( second ( tmp ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
2022-09-06 19:20:37 +02:00
Serial . println ( second ( tmp ) ) ;
Serial . print ( F ( " System date is : " ) ) ;
2022-09-08 06:16:59 +02:00
Serial . print ( year ( tmp ) ) ;
Serial . print ( " - " ) ;
Serial . print ( month ( tmp ) ) ;
Serial . print ( " - " ) ;
Serial . print ( day ( tmp ) ) ;
Serial . println ( F ( " (Y/M/D) " ) ) ;
2022-09-06 19:20:37 +02:00
# ifdef USERTC
Serial . print ( F ( " RTC time is : " ) ) ;
2022-09-08 06:16:59 +02:00
if ( hour ( tmp2 ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . print ( hour ( tmp2 ) ) ;
Serial . print ( F ( " : " ) ) ;
if ( minute ( tmp2 ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . print ( minute ( tmp2 ) ) ;
Serial . print ( F ( " : " ) ) ;
if ( second ( tmp2 ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
2022-09-06 19:20:37 +02:00
Serial . println ( second ( tmp2 ) ) ;
Serial . print ( F ( " RTC date is : " ) ) ;
2022-09-08 06:16:59 +02:00
Serial . print ( year ( tmp2 ) ) ;
Serial . print ( " - " ) ;
Serial . print ( month ( tmp2 ) ) ;
Serial . print ( " - " ) ;
Serial . print ( day ( tmp2 ) ) ;
Serial . println ( F ( " (Y/M/D) " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
# ifdef AUTODST
tmp = myTimeZone . toLocal ( tmp ) ;
Serial . print ( F ( " autoDST time is: " ) ) ;
2022-09-08 06:16:59 +02:00
if ( hour ( tmp ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . print ( hour ( tmp ) ) ;
Serial . print ( F ( " : " ) ) ;
if ( minute ( tmp ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
Serial . print ( minute ( tmp ) ) ;
Serial . print ( F ( " : " ) ) ;
if ( second ( tmp ) < 10 )
Serial . print ( F ( " 0 " ) ) ;
2022-09-06 19:20:37 +02:00
Serial . println ( second ( tmp ) ) ;
Serial . print ( F ( " autoDST date is: " ) ) ;
2022-09-08 06:16:59 +02:00
Serial . print ( year ( tmp ) ) ;
Serial . print ( " - " ) ;
Serial . print ( month ( tmp ) ) ;
Serial . print ( " - " ) ;
Serial . print ( day ( tmp ) ) ;
Serial . println ( F ( " (Y/M/D) " ) ) ;
2022-09-06 19:20:37 +02:00
# endif
Serial . println ( F ( " ----------------------------------- " ) ) ;
}
2022-09-08 06:16:59 +02:00
uint8_t dbgInput ( )
{
2022-09-06 19:20:37 +02:00
/* this catches input from the serial console and hands it over to inputButtons() if DEBUG is defined
Serial input " 7 " matches buttonA , " 8 " matches buttonB , " 9 " matches buttonA + buttonB */
2022-09-08 06:16:59 +02:00
if ( Serial . available ( ) > 0 )
{
2022-09-06 19:20:37 +02:00
uint8_t incomingByte = 0 ;
incomingByte = Serial . read ( ) ;
2022-09-08 06:16:59 +02:00
if ( incomingByte = = 52 )
{ // 4 - long press buttonA
2022-09-06 19:20:37 +02:00
btnRepeatCounter = 10 ;
return 1 ;
}
2022-09-08 06:16:59 +02:00
if ( incomingByte = = 53 )
{ // 5 - long press buttonB
2022-09-06 19:20:37 +02:00
btnRepeatCounter = 10 ;
return 2 ;
2022-08-25 06:03:03 +02:00
}
2022-09-08 06:16:59 +02:00
if ( incomingByte = = 54 )
{ // 6 - long press buttonA + buttonB
2022-09-06 19:20:37 +02:00
btnRepeatCounter = 10 ;
return 3 ;
}
2022-09-08 06:16:59 +02:00
if ( incomingByte = = 55 )
return 1 ; // 7 - buttonA
if ( incomingByte = = 56 )
return 2 ; // 8 - buttonB
if ( incomingByte = = 57 )
return 3 ; // 9 - buttonA + buttonB
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
return 0 ;
}
# endif
// ---
2022-08-25 05:23:48 +02:00
# ifdef USEWIFI
2022-09-08 06:16:59 +02:00
void connectWPS ( )
{ // join network using wps. Will try for 3 times before exiting...
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . println ( F ( " connectWPS(): Initializing WPS setup... " ) ) ;
# endif
uint8_t counter = 1 ;
static unsigned long startTimer = millis ( ) ;
# ifdef LEDSTUFF
FastLED . clear ( ) ;
showDigit ( 10 , digitPositions [ 0 ] ) ;
showDigit ( 11 , digitPositions [ 1 ] ) ;
showDigit ( 12 , digitPositions [ 2 ] ) ;
showDigit ( counter , digitPositions [ 3 ] ) ;
colorizeOutput ( colorMode ) ;
FastLED . show ( ) ;
# endif
2022-09-08 06:16:59 +02:00
while ( counter < 4 )
{
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-09-08 06:16:59 +02:00
if ( millis ( ) % 50 = = 0 )
{
2022-08-25 05:23:48 +02:00
FastLED . clear ( ) ;
showDigit ( 10 , digitPositions [ 0 ] ) ;
showDigit ( 11 , digitPositions [ 1 ] ) ;
showDigit ( 12 , digitPositions [ 2 ] ) ;
showDigit ( counter , digitPositions [ 3 ] ) ;
colorizeOutput ( colorMode ) ;
FastLED . show ( ) ;
}
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
if ( millis ( ) - startTimer > 300 )
{
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . print ( F ( " connectWPS(): Waiting for WiFi/WPS, try " ) ) ;
Serial . println ( counter ) ;
# endif
WiFi . beginWPSConfig ( ) ;
2022-09-08 06:16:59 +02:00
if ( WiFi . SSID ( ) . length ( ) < = 0 )
counter + + ;
else
counter = 4 ;
2022-09-06 19:20:37 +02:00
startTimer = millis ( ) ;
}
# ifdef NODEMCU
yield ( ) ;
# endif
}
FastLED . clear ( ) ;
startTimer = millis ( ) ;
2022-09-08 06:16:59 +02:00
if ( WiFi . SSID ( ) . length ( ) > 0 )
{
2022-09-06 19:20:37 +02:00
# ifdef LEDSTUFF
2022-08-25 05:23:48 +02:00
FastLED . clear ( ) ;
2022-09-06 19:20:37 +02:00
showDigit ( 5 , digitPositions [ 0 ] ) ;
showDigit ( 5 , digitPositions [ 1 ] ) ;
showDigit ( 1 , digitPositions [ 2 ] ) ;
showDigit ( 13 , digitPositions [ 3 ] ) ;
colorizeOutput ( colorMode ) ;
FastLED . show ( ) ;
# endif
# ifdef DEBUG
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " connectWPS(): Connected to SSID: " ) ) ;
Serial . println ( WiFi . SSID ( ) ) ;
2022-09-06 19:20:37 +02:00
# endif
2022-09-08 06:16:59 +02:00
while ( millis ( ) - startTimer < 2000 )
{
2022-09-06 19:20:37 +02:00
# ifdef NODEMCU
yield ( ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef USENTP
clockStatus = 1 ;
syncHelper ( ) ;
clockStatus = 0 ;
# endif USENTP
2022-09-08 06:16:59 +02:00
}
else
{
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . println ( F ( " connectWPS(): Failed, no WPS connection established " ) ) ;
# endif
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
# ifdef DEBUG
Serial . println ( F ( " connectWPS() done " ) ) ;
# endif
}
2022-08-25 05:23:48 +02:00
# endif
# ifdef CUSTOMHELPER
/* This assists in troubleshooting and basic configuration. Testing all neccessary steps to get
showSegment ( ) , showDigit ( ) , showDots ( ) to work . Ugly and using delay ( ) but does the job ^ ^ */
2022-09-08 06:16:59 +02:00
void customHelper ( )
{
2022-09-06 19:20:37 +02:00
markerHSV [ 0 ] = 96 ;
markerHSV [ 1 ] = 255 ;
markerHSV [ 2 ] = 60 ;
colorModeSwitcher ( ) ;
paletteSwitcher ( ) ;
brightness = 50 ;
currentPalette = RainbowColors_p ;
uint8_t test = 1 ;
# ifdef DEBUG
Serial . println ( F ( " \n \n \n Some kind of troubleshooting/custom assistant... ^^ " ) ) ;
Serial . println ( F ( " \n Tests will finish before proceeding to the next one. \n " ) ) ;
2022-09-08 06:16:59 +02:00
Serial . print ( F ( " The first step is to check all leds, so this test will \n simply light up all the leds from 0 to " ) ) ;
Serial . println ( LED_COUNT - 1 ) ;
2022-09-06 19:20:37 +02:00
Serial . println ( F ( " Press button A (or send 7 using serial input) to advance to the next step... \n " ) ) ;
# endif
2022-09-08 06:16:59 +02:00
while ( test = = 1 )
{
for ( uint16_t i = 0 ; i < LED_COUNT ; i + + )
{
2022-09-06 19:20:37 +02:00
leds [ i ] . setHSV ( markerHSV [ 0 ] , markerHSV [ 1 ] , markerHSV [ 2 ] ) ;
FastLED . show ( ) ;
delay ( 75 ) ;
2022-09-08 06:16:59 +02:00
if ( inputButtons ( ) ! = 0 )
test + + ;
2022-09-06 19:20:37 +02:00
}
FastLED . clear ( ) ;
delay ( 300 ) ;
}
# ifdef DEBUG
Serial . println ( F ( " \n \n \n Next we will light up segments 0-6 (a-g) at position 0, this " ) ) ;
Serial . println ( F ( " will show if all of the leds inside segArray[][] for position 0 are correct. " ) ) ;
Serial . println ( F ( " Press button A (or send 7 using serial input) to advance to the next step... \n " ) ) ;
# endif
FastLED . clear ( ) ;
2022-09-08 06:16:59 +02:00
while ( test = = 2 )
{
for ( uint8_t i = 0 ; i < 7 ; i + + )
{
2022-09-06 19:20:37 +02:00
showSegment ( i , 0 ) ;
FastLED . show ( ) ;
delay ( 750 ) ;
2022-09-08 06:16:59 +02:00
if ( inputButtons ( ) ! = 0 )
test + + ;
2022-08-25 05:23:48 +02:00
}
FastLED . clear ( ) ;
2022-09-06 19:20:37 +02:00
FastLED . show ( ) ;
delay ( 300 ) ;
firstLoop = false ;
}
# ifdef DEBUG
Serial . println ( F ( " \n \n Now let's check this for all the positions as defined (LED_DIGITS 4 or 6), starting from 0... " ) ) ;
Serial . println ( F ( " Press button A (or send 7 using serial input) to advance to the next step... \n " ) ) ;
# endif
firstLoop = true ;
2022-09-08 06:16:59 +02:00
while ( test = = 3 )
{
for ( uint8_t pos = 0 ; pos < LED_DIGITS ; pos + + )
{
for ( uint8_t i = 0 ; i < 7 ; i + + )
{
2022-09-06 19:20:37 +02:00
showSegment ( i , pos ) ;
2022-08-25 05:23:48 +02:00
FastLED . show ( ) ;
2022-09-06 19:20:37 +02:00
delay ( 400 ) ;
2022-09-08 06:16:59 +02:00
if ( inputButtons ( ) ! = 0 )
test + + ;
2022-08-25 05:23:48 +02:00
}
2022-09-08 06:16:59 +02:00
if ( firstLoop )
Serial . println ( ) ;
2022-08-25 05:23:48 +02:00
}
2022-08-25 05:30:54 +02:00
FastLED . clear ( ) ;
FastLED . show ( ) ;
delay ( 300 ) ;
2022-09-06 19:20:37 +02:00
firstLoop = false ;
}
# ifdef DEBUG
Serial . println ( F ( " \n \n Testing showDigit() on position 0, displaying 0-9 " ) ) ;
Serial . println ( F ( " Press button A (or send 7 using serial input) to advance to the next step... \n " ) ) ;
# endif
2022-09-08 06:16:59 +02:00
while ( test = = 4 )
{
for ( uint8_t i = 0 ; i < 10 ; i + + )
{
2022-09-06 19:20:37 +02:00
FastLED . clear ( ) ;
showDigit ( i , 0 ) ;
2022-09-08 06:16:59 +02:00
if ( inputButtons ( ) ! = 0 )
test + + ;
2022-08-25 06:03:03 +02:00
FastLED . show ( ) ;
2022-09-06 19:20:37 +02:00
delay ( 500 ) ;
2022-08-25 05:30:54 +02:00
}
2022-09-06 19:17:32 +02:00
FastLED . clear ( ) ;
FastLED . show ( ) ;
delay ( 300 ) ;
2022-09-06 19:20:37 +02:00
}
# ifdef DEBUG
Serial . println ( F ( " \n \n Testing showDots() lighting up the upper/lower dots in a repeating pattern... " ) ) ;
Serial . println ( F ( " Press button A (or send 7 using serial input) to advance to the next step... \n " ) ) ;
# endif
2022-09-08 06:16:59 +02:00
while ( test = = 5 )
{
2022-09-06 19:20:37 +02:00
// if ( second() % 2 == 1 ) {
// showDots(0);
// } else {
// showDots(1);
// }
2022-09-08 06:16:59 +02:00
if ( inputButtons ( ) ! = 0 )
test + + ;
2022-09-06 19:20:37 +02:00
FastLED . show ( ) ;
delay ( 20 ) ;
FastLED . clear ( ) ;
}
FastLED . clear ( ) ;
FastLED . show ( ) ;
delay ( 300 ) ;
# ifdef DEBUG
Serial . println ( F ( " \n \n Final test, displaying 0-9 on all positions, using colorizeOutput(); " ) ) ;
Serial . println ( F ( " Press button A (or send 7 using serial input) to start over... \n " ) ) ;
# endif
2022-09-08 06:16:59 +02:00
while ( test = = 6 )
{
for ( uint8_t i = 0 ; i < 10 ; i + + )
{
for ( uint8_t pos = 0 ; pos < LED_DIGITS ; pos + + )
{
2022-09-06 19:20:37 +02:00
showDigit ( i , pos ) ;
2022-09-06 19:17:32 +02:00
}
2022-09-08 06:16:59 +02:00
if ( inputButtons ( ) ! = 0 )
test + + ;
2022-09-06 19:20:37 +02:00
colorizeOutput ( 1 ) ;
FastLED . show ( ) ;
delay ( 500 ) ;
FastLED . clear ( ) ;
2022-09-06 19:17:32 +02:00
}
2022-08-25 05:23:48 +02:00
}
2022-09-06 19:20:37 +02:00
FastLED . clear ( ) ;
FastLED . show ( ) ;
delay ( 500 ) ;
}
2022-08-25 05:23:48 +02:00
# endif
/* Wooohaa... this one took a bit longer than expected... ^^ /daniel cikic - 07/2021 */