/*
╔------------------------------------------------------------╗
║ Arduino 64x8 LED Dot Matrix Clock ║
╠------------------------------------------------------------╣
║ A simple LED dot matrix clock project based on Arduino Nano║
║(ATmega328), also using a DS3231RTC module and a LDR sensor,║
║ IR remote, SD card, DTS and Rotary encoder ║
╠------------------------------------------------------------╣
║ Filename: LEDDotMatrixClock.ino ║
║ Last modified: 10 Februar 2022 by Patrik Frida. FINAL 1.8 ║
╚------------------------------------------------------------╝
*/
// #######################################################################################
// # Connect modules to pins ... #
// #######################################################################################
// # SD card : 3V3 !! and GND, MISO to D12, CLK to D13, MOSI to D11, CS to D4 #
// # RTC : + to 5V, - to GND, D to A4 SDA, C to A5 SCL #
// # Rotarry Encoder : RT_GND + RT_BTN_GND to D7, RT_A to D8, RT_B to D6, RT_BTN to D9 #
// # IR decoder : IR_data to D2, - to GND, + to 5V #
// # Matrix LCD : CLK to D13, MA_CS to A3, DIN to D11, VCC to 5V, GND #
// # LDR sensor : - to GND, + to A2 #
// #######################################################################################
// #######################################################################################
// # Build Config ... #
// ################################### MASTER CONFIG #####################################
#define SD_SUPPORT // Support SD card for DT and RT Texts
#define ADV_SUPPORT // Support Light Sensor and Temperature
//#define IR_SUPPORT 2 // Support IR Remote, Set Remote controll TYPE 1 or 2
#define DTS_SUPPORT // DTS (Daylight time saving) Prepina Letny a zimny cas
#define TEXT_TIME // Show TIME before DT and RT Texts
#define LED_BOOST // Allow Switch LED Boost intensity
#define LED_MODULES 8 // Count of LED Modules is Min 4 and Max 8. 4 for small version, 8 for lagre version
// #################################### TEST #############################################
// If needed to using DEBUG for IR scan maybee temporarily disable ADV_SUPPORT if low Flash space
//#define DEBUG // Scan IR codes from remote for using codes in const values (section IR codes ... bellow)
// #######################################################################################
#if LED_MODULES < 4 || LED_MODULES > 8
#error Valid value for LED_MODULES is value between 4 and 8
#endif
////////////////////////////// LGT Flash Size FIX ////////////////////////////////////////
// LGT8F is cheap CPU with lower Flash memmory size
#if defined(__LGT8FX8P__) || defined(__LGT8FX8E__)
// LGT8F386 version
///////////////////
// Too low Flash size to using Rotary Encoder, Fix and LED Flash support
// Use only IR Support with Remote controll
#elif defined(__AVR_ATmega328P__)
// Nano, Uno version
////////////////////
#define QUICK_SENSOR // Refresh light sensor quickly
#define DAY_FIX // Fix day name for 'Štvrtok' : Stv = Št
#define FLASH_SUPPORT // Support for LED Flash
#define RT_ENC_SUPPORT // Support Rotary Encoder
#define RT_ENC_PSEUDO_GND 7 // Use Pseudo GND for Rotary Encoder = D7 otherwise use real GND
#else
#error Use Arduino Nano, Uno or LGT8F board
#endif
//////////////////////////////////////////////////////////////////////////////////////////
// ############################### TEXT LEN CHECK ########################################
#ifdef SD_SUPPORT
// Max text from SD card length check
const byte MAX_TEXT_LEN = 166;
#ifdef TEXT_TIME
const byte MAX_LEN = MAX_TEXT_LEN - 6;
#else
const byte MAX_LEN = MAX_TEXT_LEN;
#endif
#endif
// ###################################### END ############################################
// Minimum needed libraryies
#include <EEPROM.h>
#include "DS3231.h"
#include "Adafruit_GFX.h"
#include "Max72xxPanel.h"
// Other customizabled Libraries
#ifdef RT_ENC_SUPPORT
#include "ClickEncoder.h"
#include "TimerOne.h"
#define RT_EN_A 6
#define RT_EN_B 8
#define RT_BTN 9
ClickEncoder *encoder;
void timerIsr() {
encoder->service();
}
#endif
#ifdef SD_SUPPORT
#include <SD.h>
File myFile;
#define SD_CS 4
#endif
#ifdef IR_SUPPORT
#include <IRLremote.h>
#define IR_data 2
CNec IRLremote;
#endif
DS3231 rtc(SDA, SCL); // A4, A5
int16_t last, value;
bool isClockSetup = false;
// EEPROM Val Address
#ifdef DTS_SUPPORT
const byte dtsVal = 0;
#endif
const byte simpleVal = 1;
const byte nightVal = 2;
const byte nightFromVal = 3;
const byte nightToVal = 4;
#ifdef ADV_SUPPORT
const byte sensorVal = 5;
const byte temperatureVal = 6;
#endif
#ifdef LED_BOOST
const byte ledVal = 7;
#endif
#ifdef ADV_SUPPORT
const byte LDR_PIN = A2; // LDR Sensor pin
#endif
////////////////////////////////// LED Matrix setup ///////////////////////////////////////////////////
const byte LED_CS = A3; // Attach CS to this pin, DIN to D11 MOSI and D13 CLK to SCK
const byte H_DISPLAYS = LED_MODULES; // Horizontal displays number - Min is 4 and Max is 8!
const byte V_DISPLAYS = 1; // Vertical displays number
///////////////////////////////////////////////////////////////////////////////////////////////////////
const byte stupneIcon = 1;
const byte disabledIcon = 2;
const byte enabledIcon = 3;
const byte autoIcon = 4;
const byte planIcon = 5;
const byte NightModeIcon = 7;
const byte DayModeIcon = 8;
const byte SimpleModeIcon = 9;
const byte WideModeIcon = 10;
const byte TemperatureOnIcon = 11;
const byte TemperatureOffIcon = 12;
const byte SensorOnIcon = 13;
const byte SensorOffIcon = 14;
const byte SensorPlanIcon = 15;
#ifdef DTS_SUPPORT
const byte dtsLetoIcon = 16;
const byte dtsZimaIcon = 17;
#endif
const byte resetIcon = 18;
#ifdef SD_SUPPORT
const byte noSDIcon = 19;
const byte SDokIcon = 20;
#endif
const byte SensorOnBoostIcon = 21;
const byte SensorOffBoostIcon = 22;
const byte SensorPlanBoostIcon = 23;
Max72xxPanel matrix = Max72xxPanel(LED_CS, H_DISPLAYS, V_DISPLAYS);
#if LED_MODULES >= 4 && LED_MODULES <= 5
byte WAIT = 25;
#elif LED_MODULES >= 6 && LED_MODULES <= 8
byte WAIT = 20;
#endif
const byte SPACER = 1;
const byte FONT_WIDTH = 5 + SPACER; // The font width is 5 pixels
byte setMode = 0;
byte bits = 0; // Bit 0 = valChanged, Bit 1 = displayOff, Bit 2 = activeNight, Bit 3 - sdExists, Bit 4 - firstVal, Bit 5 = saveVal, Bit 6 and Bit 7 = show (0 None, 1 DT, 2 RT, 3 UserDisplayOff)
// Usage - Functions ...
void setValChanged(bool val) {
bitWrite(bits, 0, val);
}
bool getValChanged() {
return bitRead(bits, 0);
}
bool getSettings() {
return setMode > 0;
}
void setDisplayOff(bool val) {
bitWrite(bits, 1, val);
}
bool getDisplayOff() {
return bitRead(bits, 1);
}
void setActiveNight(bool val) {
bitWrite(bits, 2, val);
}
bool getActiveNight() {
return bitRead(bits, 2);
}
void setSdExists(bool val) {
bitWrite(bits, 3, val);
}
bool getSdExists() {
return bitRead(bits, 3);
}
void setFirstVal(bool val) {
bitWrite(bits, 4, val);
}
bool getFirstVal() {
return bitRead(bits, 4);
}
void setSaveVal(bool val) {
bitWrite(bits, 5, val);
}
bool getSaveVal() {
return bitRead(bits, 5);
}
#ifdef FLASH_SUPPORT
bool flash = false;
#endif
const byte showDT = 1;
const byte showRT = 2;
const byte showCustOff = 3;
void setShowDText() {
bitWrite(bits, 6, 0);
bitWrite(bits, 7, 1);
}
void setShowYText() {
bitWrite(bits, 6, 1);
bitWrite(bits, 7, 0);
}
void setCustOff() {
bitWrite(bits, 6, 1);
bitWrite(bits, 7, 1);
}
void resetShow() {
bitWrite(bits, 6, 0);
bitWrite(bits, 7, 0);
}
byte getShow() {
if (!bitRead(bits, 6) && bitRead(bits, 7)) return showDT;
else if (bitRead(bits, 6) && !bitRead(bits, 7)) return showRT;
else if (bitRead(bits, 6) && bitRead(bits, 7)) return showCustOff;
return 0;
}
// MENU items constants
const byte setNone = 0;
const byte setSimple = 1;
const byte setNight = 2;
const byte setNightFrom = 3;
const byte setNightTo = 4;
const byte setSensor = 5;
const byte setTemp = 6;
#ifdef DTS_SUPPORT
const byte setDTS = 7;
#endif
const byte setHour = 8;
const byte setMinute = 9;
const byte setSecond = 10;
const byte setDay = 11;
const byte setMonth = 12;
const byte setYear = 13;
void resetNightMode()
{
EEPROM.write(nightVal, 1);
resetShow();
}
// IR codes
#ifdef IR_SUPPORT
// To scan codes from new RC enable DEBUG and disable ADV_SUPPORT in define tag at top
// Flash to Arduino Nano and scan codes from RC, then set codes to source code bellow
// Then turn off DEBUG and enable ADV_SUPPORT and flash again final code to Arduino Nano
const int rcAddress = 65280; // RC master address
#if IR_SUPPORT == 1
// ------------------- RC 1 ----------------------
const byte powerBtn = 12; // on-off
const byte menuBtn = 7; //recal
#ifdef SD_SUPPORT
const byte dTextBtn = 17; // 1
const byte yTextBtn = 18; // 2
#endif
const byte plusBtn = 0; //CH +
const byte minusBtn = 1; //CH -
const byte okBtn = 3; // Vol -
const byte resetBtn = 8; //stop
const byte tempBtn = 9; //rec
const byte autoNightBtn = 15; //timeshift
const byte simpleBtn = 26; //zoom
const byte dashboardBtn = 2; // Vol +
const byte clockSetupBtn = 20; // 4
const byte dateSetupBtn = 21; // 5
const byte sensorBtn = 16; // 0
#ifdef DTS_SUPPORT
const byte dtsBtn = 23; // 7
#endif
#ifdef LED_BOOST
const byte ledBoostBtn = 24; // 8
#endif
#ifdef FLASH_SUPPORT
const byte flashBtn = 25; // 9
#endif
// Reserved codes ...
//const byte empty3Btn = 19; // 3
//const byte empty6Btn = 22; // 6
#else
// ------------------- RC 2 ----------------------
const byte powerBtn = 69; // 1
const byte menuBtn = 68; // 4
#ifdef SD_SUPPORT
const byte dTextBtn = 8; // LEFT
const byte yTextBtn = 90; // RIGHT
#endif
const byte plusBtn = 24; // UP
const byte minusBtn = 82; // DOWN
const byte okBtn = 28; // OK
const byte resetBtn = 13; // #
const byte tempBtn = 25; // 0
const byte autoNightBtn = 22; // *
const byte simpleBtn = 7; // 7
const byte dashboardBtn = 70; // 2
const byte clockSetupBtn = 64; // 5
const byte dateSetupBtn = 67; // 6
const byte sensorBtn = 21; // 8
#ifdef DTS_SUPPORT
const byte dtsBtn = 9; // 9
#endif
#ifdef FLASH_SUPPORT
const byte flashBtn = 71; // 3
const byte ledBoostBtn = -1; // N/A
#else
#ifdef LED_BOOST
const byte ledBoostBtn = 71; // 3
#endif
#endif
#endif
#endif
//declaration
void (*resetFunc) (void) = 0; //declare reset function @ address 0
void printToMatrix(String output)
{
matrix.fillScreen(LOW);
for (byte letter = 0; letter < output.length(); letter++) {
byte x = (letter * FONT_WIDTH) + 1;
byte y = (matrix.height() - 8) / 2; // center the text vertically
matrix.drawChar(x, y, output[letter], HIGH, LOW, 1);
}
matrix.write();
}
void setup() {
// pre wokwi vypni simple
EEPROM.write(simpleVal, 0);
#ifdef RT_ENC_SUPPORT
#ifdef RT_ENC_PSEUDO_GND
// Pin as Pseudo GND
pinMode (RT_ENC_PSEUDO_GND, OUTPUT);
digitalWrite(RT_ENC_PSEUDO_GND, LOW);
#endif
// D7, D8, D9 as RT ENC Input
pinMode (RT_EN_A, INPUT_PULLUP);
pinMode (RT_EN_B, INPUT_PULLUP);
pinMode (RT_BTN, INPUT_PULLUP);
#endif
#ifdef ADV_SUPPORT
pinMode(LDR_PIN, INPUT_PULLUP);
#endif
#ifdef IR_SUPPORT
// Start reading the remote
IRLremote.begin(IR_data);
#endif
rtc.begin();
for (byte i = 0; i < H_DISPLAYS; i++)
{
matrix.setPosition(i, i, 0);
matrix.setRotation(i, 3);
}
#ifdef ADV_SUPPORT
matrix.setIntensity(getLedIntensity());
#else
matrix.setIntensity(0);
#endif
matrix.fillScreen(LOW);
#ifdef SD_SUPPORT
if (!SD.begin(SD_CS)) {
matrix.drawChar(10, 0, (char)noSDIcon, HIGH, LOW, 1);
}
else
{
matrix.drawChar(10, 0, (char)SDokIcon, HIGH, LOW, 1);
SD.open("/");
setSdExists(1);
}
delay(1000);
matrix.write();
#endif
//matrix.write();
#ifdef RT_ENC_SUPPORT
encoder = new ClickEncoder(RT_EN_A, RT_EN_B, RT_BTN, 4);
Timer1.initialize(1000);
Timer1.attachInterrupt(timerIsr);
#endif
last = -1;
}
#ifdef QUICK_SENSOR
byte lastSec = 0;
#endif
void ResetArduino()
{
if (getShow() == showCustOff)
{
resetNightMode();
}
printToMatrix(String((char)resetIcon));
delay(1000);
resetFunc();
}
byte GetDTSOrigHour()
{
byte hour = rtc.getTime().hour;
#ifdef DTS_SUPPORT
if (EEPROM.read(dtsVal))
{
hour--;
}
#endif
return hour;
}
void SwitchDisplay() {
matrix.setIntensity(getLedIntensity());
bool displayOff = getDisplayOff();
if (getActiveNight())
{
resetShow();
}
else if (!displayOff && EEPROM.read(nightVal))
{
EEPROM.write(nightVal, 0);
setCustOff();
}
else if (getShow() == showCustOff)
{
resetNightMode();
}
setDisplayOff(!displayOff);
#ifdef FLASH_SUPPORT
if (displayOff)
{
flash = false;
}
#endif
}
/////////////////////////////////////////////////////////////
// Realizacia vstupu cez tlacidlo rotacneho enkodera alebo IR
/////////////////////////////////////////////////////////////
void encoderLoop()
{
bool settings = getSettings();
#ifdef SD_SUPPORT
bool sdExists = getSdExists();
#endif
bool displayOff = getDisplayOff();
byte show = getShow();
String Label = "";
if (setMode == setNone) {
value = WAIT;
}
#ifdef RT_ENC_SUPPORT
if (setMode == setNone)
{
value -= encoder->getValue();
}
else
{
value += encoder->getValue();
}
#endif
#ifdef ADV_SUPPORT
#ifdef QUICK_SENSOR
byte sec = rtc.getTime().sec;
if (lastSec != sec && sec % 2 == 0)
{
matrix.setIntensity(getLedIntensity()); // value between 0 and 15 for brightness
lastSec = sec;
}
#endif
#endif
#ifdef IR_SUPPORT
if (IRLremote.available())
{
// Get the new data from the remote
auto data = IRLremote.read();
#ifdef DEBUG
// Show IR command
scrollToMatrix(String(data.address) + F("-") + String(data.command));
#endif
// IR decode
if (data.address == rcAddress)
{
String Label = "";
byte left = 2;
byte boostIconOffset = 0;
#ifdef LED_BOOST
if (EEPROM.read(ledVal))
{
boostIconOffset = 8;
}
#endif
switch (data.command)
{
case powerBtn: // Power
SwitchDisplay();
break;
#ifdef FLASH_SUPPORT
case flashBtn: // Display full screen
flash = !flash;
break;
#endif
case menuBtn: // Menu
if (show == showCustOff)
{
resetNightMode();
}
if (settings)
{
setMode = setNone;
value = WAIT;
}
else
{
setMode = setSimple;
setFirstVal(1);
setSaveVal(0);
}
break;
#ifdef SD_SUPPORT
case dTextBtn: // DText
if (sdExists && !settings)
{
setShowDText();
setValChanged(1);
}
else
{
matrix.fillScreen(LOW);
matrix.drawChar(10, 0, (char)noSDIcon, HIGH, LOW, 1);
matrix.write();
delay(1000);
}
break;
case yTextBtn: // YText
if (sdExists && !settings)
{
setShowYText();
setValChanged(1);
}
else
{
matrix.fillScreen(LOW);
matrix.drawChar(10, 0, (char)noSDIcon, HIGH, LOW, 1);
matrix.write();
delay(1000);
}
break;
#endif
case plusBtn: // +
if (setMode == setNone)
{
value = value - 5;
}
else
{
value++;
}
break;
case minusBtn: // -
if (setMode == setNone)
value = value + 5;
else
value--;
break;
case okBtn:
if (!getFirstVal() && setMode > 0)
{
setFirstVal(1);
setSaveVal(1);
}
break;
case resetBtn:
if (setMode != setNone)
{
if (setMode == setYear)
{
value = 2022;
}
else if (setMode == setDay || setMode == setMonth)
{
value = 1;
}
else if (setMode == setNightTo)
{
value = 8;
}
else if (setMode == setNightFrom)
{
value = 23;
}
else
{
value = 0;
}
}
else
{
ResetArduino();
}
break;
#ifdef ADV_SUPPORT
case tempBtn:
EEPROM.write(temperatureVal, !EEPROM.read(temperatureVal));
Label = (char)stupneIcon;
Label += F("C:");
if (EEPROM.read(temperatureVal))
Label += (char)enabledIcon;
else
Label += (char)disabledIcon;
printToMatrix(Label);
delay(800);
setValChanged(1);
break;
#endif
case autoNightBtn:
EEPROM.write(nightVal, !EEPROM.read(nightVal));
#if LED_MODULES < 8
Label = F("AtN:");
#else
Label = F("Auto Noc:");
#endif
if (EEPROM.read(nightVal))
{
Label += (char)enabledIcon;
}
else
{
Label += (char)disabledIcon;
}
printToMatrix(Label);
delay(800);
if (getDisplayOff())
{
setActiveNight(0);
setDisplayOff(0);
}
break;
#ifdef ADV_SUPPORT
case sensorBtn:
Label = F("Jas:");
if (!EEPROM.read(sensorVal))
{
EEPROM.write(sensorVal, 1);
Label += (char)(SensorOnIcon + boostIconOffset);
}
else if (EEPROM.read(sensorVal) == 1)
{
EEPROM.write(sensorVal, 2);
Label += (char)(SensorPlanIcon + boostIconOffset);
}
else
{
EEPROM.write(sensorVal, 0);
Label += (char)(SensorOffIcon + boostIconOffset);
}
printToMatrix(Label);
delay(800);
break;
#endif
case simpleBtn:
EEPROM.write(simpleVal, !EEPROM.read(simpleVal));
#if LED_MODULES < 8
Label = F("SMP:");
#else
Label = F("Simple:");
#endif
if (EEPROM.read(simpleVal))
{
Label += (char)enabledIcon;
}
else
{
Label += (char)disabledIcon;
}
printToMatrix(Label);
delay(800);
setValChanged(1);
break;
case dashboardBtn:
#if LED_MODULES == 4
#define ICON_SPACE 6;
#elif LED_MODULES == 5
#define ICON_SPACE 7;
#elif LED_MODULES == 6
#define ICON_SPACE 8;
#elif LED_MODULES == 7
#define ICON_SPACE 9;
#else
#define ICON_SPACE 10;
#endif
matrix.fillScreen(LOW);
// Simple
if (EEPROM.read(simpleVal))
{
matrix.drawChar(left, 0, (char)SimpleModeIcon, HIGH, LOW, 1);
}
else
{
matrix.drawChar(left, 0, (char)WideModeIcon, HIGH, LOW, 1);
}
left = left + ICON_SPACE;
#ifdef ADV_SUPPORT
// Temp
if (EEPROM.read(temperatureVal))
{
matrix.drawChar(left, 0, (char)TemperatureOnIcon, HIGH, LOW, 1);
}
else
{
matrix.drawChar(left, 0, (char)TemperatureOffIcon, HIGH, LOW, 1);
}
left = left + ICON_SPACE;
// LDR Sensor
if (EEPROM.read(sensorVal) == 1)
{
matrix.drawChar(left, 0, (char)(SensorOnIcon + boostIconOffset), HIGH, LOW, 1);
}
else if (EEPROM.read(sensorVal) == 2)
{
matrix.drawChar(left, 0, (char)(SensorPlanIcon + boostIconOffset), HIGH, LOW, 1);
}
else
{
matrix.drawChar(left, 0, (char)(SensorOffIcon + boostIconOffset), HIGH, LOW, 1);
}
left = left + ICON_SPACE;
#endif
// Auto Night
if (EEPROM.read(nightVal) || getShow() == showCustOff)
{
matrix.drawChar(left, 0, (char)NightModeIcon, HIGH, LOW, 1);
}
else
{
matrix.drawChar(left, 0, (char)DayModeIcon, HIGH, LOW, 1);
}
left = left + ICON_SPACE;
#ifdef SD_SUPPORT
// SD exists
if (sdExists)
{
matrix.drawChar(left, 0, (char)SDokIcon, HIGH, LOW, 1);
}
else
{
matrix.drawChar(left, 0, (char)noSDIcon, HIGH, LOW, 1);
}
left = left + ICON_SPACE;
#endif
#ifdef DTS_SUPPORT
// DTS
if (EEPROM.read(dtsVal))
{
matrix.drawChar(left, 0, (char)dtsLetoIcon, HIGH, LOW, 1);
}
else
{
matrix.drawChar(left, 0, (char)dtsZimaIcon, HIGH, LOW, 1);
}
matrix.write();
delay(3000);
#endif
break;
case clockSetupBtn:
if (setMode == setNone)
{
isClockSetup = true;
setFirstVal(1);
setSaveVal(0);
setMode = setHour;
setValChanged(1);
}
else
{
isClockSetup = false;
value = WAIT;
setMode = setNone;
rtc.setDOW();
}
break;
case dateSetupBtn:
if (setMode == setNone)
{
setFirstVal(1);
setSaveVal(0);
setMode = setDay;
setValChanged(1);
}
else
{
value = WAIT;
setMode = setNone;
rtc.setDOW();
}
break;
#ifdef DTS_SUPPORT
case dtsBtn:
EEPROM.write(dtsVal, !EEPROM.read(dtsVal));
Label = F("DTS:");
if (EEPROM.read(dtsVal))
Label += (char)dtsLetoIcon;
else
Label += (char)dtsZimaIcon;
printToMatrix(Label);
delay(800);
setValChanged(1);
break;
#endif
#ifdef LED_BOOST
case ledBoostBtn:
Label = F("LD+:");
if (EEPROM.read(ledVal) > 0)
{
EEPROM.write(ledVal, 0);
Label += (char)disabledIcon;
}
else
{
EEPROM.write(ledVal, 2);
Label += (char)enabledIcon;
}
printToMatrix(Label);
delay(800);
break;
#endif
}
}
}
#endif
//////////////////////////////////////////////////////
// Nasatvenie hranicnych limitov pre konkretne hodnoty
//////////////////////////////////////////////////////
if (setMode == setNight
|| setMode == setSimple
#ifdef ADV_SUPPORT
|| setMode == setTemp
#endif
#ifdef DTS_SUPPORT
|| setMode == setDTS
#endif
)
{
if (value < 0) value = 1;
else if (value > 1) value = 0;
}
// Uprav rychlost textu, ak nie je vypnuty display
else if (setMode == setNone & !displayOff)
{
if (value < 10) value = 10;
#if LED_MODULES < 7
else if (value > 50) value = 50;
#else
else if (value > 40) value = 40;
#endif
WAIT = value;
}
#ifdef ADV_SUPPORT
else if (setMode == setSensor)
{
if (value < 0) value = 2;
else if (value > 2) value = 0;
}
#endif
else if (setMode == setNightFrom)
{
if (value < 20) value = 20;
else if (value > 23) value = 23;
}
else if (setMode == setNightTo)
{
if (value < 4) value = 4;
else if (value > 8) value = 8;
}
else if (setMode == setHour)
{
if (value < 0) value = 23;
else if (value > 23) value = 0;
}
else if (setMode == setMinute || setMode == setSecond)
{
if (value < 0) value = 59;
else if (value > 59) value = 0;
}
else if (setMode == setDay)
{
if (value < 1) value = 31;
else if (value > 31) value = 0;
}
else if (setMode == setMonth)
{
if (value < 1) value = 12;
else if (value > 12) value = 1;
}
else if (setMode == setYear)
{ }
// Ak je vypnuty display a pohnem roray, zapni display
else if (setMode == setNone & displayOff & value != last)
{
setDisplayOff(0);
}
if (value != last) {
last = value;
#ifdef FLASH_SUPPORT
flash = false;
#endif
}
#ifdef RT_ENC_SUPPORT
ClickEncoder::Button b = encoder->getButton();
if (b != ClickEncoder::Open) {
// Button
switch (b) {
case ClickEncoder::Released:
// Release
if (EEPROM.read(ledVal) > 0)
{
EEPROM.write(ledVal, 0);
}
else
{
EEPROM.write(ledVal, 2);
}
//setShowDText();
break;
case ClickEncoder::Clicked:
// Click
if (!getFirstVal() && setMode > 0)
{
// Save
setFirstVal(1);
setSaveVal(1);
}
else
{
// Vypni/zapni display
SwitchDisplay();
}
break;
case ClickEncoder::DoubleClicked:
// Double click
// Prepni rezim nastavenia hodin
if (settings)
{
setMode = setNone;
}
else
{
setMode = setSimple;
}
break;
}
}
#endif
}
void scrollToMatrix(String output)
{
String Label = "";
byte boostIconOffset = 0;
for ( int i = 0 ; i < FONT_WIDTH * output.length() + matrix.width() - 1 - SPACER; i++ ) {
encoderLoop();
if (getShow() == showDT || getShow() == showRT)
{
output = "";
}
if (getSettings())
{
///////////////////////////////////////////////////////////////
if (setMode == setNone)
{
if (getShow() == showCustOff)
{
resetNightMode();
}
setFirstVal(1);
setSaveVal(0);
setDisplayOff(0);
printToMatrix(F("Menu"));
setMode = setSimple;
delay(800);
}
///////////////////////////////////////////////////////////////
else if (setMode == setSimple)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = EEPROM.read(simpleVal);
setFirstVal(0);
}
#if LED_MODULES < 8
Label = F("SMP:");
#else
Label = F("Simple:");
#endif
if (value)
Label += (char)enabledIcon;
else
Label += (char)disabledIcon;
printToMatrix(Label);
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setNight;
EEPROM.write(simpleVal, value);
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setNight)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = EEPROM.read(nightVal);
setFirstVal(0);
}
#if LED_MODULES < 8
Label = F("AtN:");
#else
Label = F("Auto Noc:");
#endif
if (value)
{
Label += (char)enabledIcon;
}
else
{
Label += (char)disabledIcon;
}
printToMatrix(Label);
}
else
{
setFirstVal(1);
setSaveVal(0);
// Ak bol nastaveny nocny rezim, prejdi na nastavenie casu noci
if (value == 1)
{
setMode = setNightFrom;
}
else
{
#ifdef ADV_SUPPORT
setMode = setSensor;
#else
setMode = setHour;
#endif
}
EEPROM.write(nightVal, value);
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setNightFrom)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = EEPROM.read(nightFromVal);
setFirstVal(0);
}
Label = F("Od:");
printToMatrix(Label + String(value));
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setNightTo;
EEPROM.write(nightFromVal, value);
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setNightTo)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = EEPROM.read(nightToVal);
setFirstVal(0);
}
Label = F("Do:");
printToMatrix(Label + String(value));
}
else
{
setFirstVal(1);
setSaveVal(0);
#ifdef ADV_SUPPORT
setMode = setSensor;
#else
setMode = setHour;
#endif
EEPROM.write(nightToVal, value);
}
}
#ifdef ADV_SUPPORT
///////////////////////////////////////////////////////////////
else if (setMode == setSensor)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = EEPROM.read(sensorVal);
setFirstVal(0);
}
#ifdef LED_BOOST
if (EEPROM.read(ledVal))
{
boostIconOffset = 8;
}
#endif
Label = F("Jas:");
if (value == 0)
{
Label += (char)(SensorOffIcon + boostIconOffset);
}
else if (value == 1)
{
Label += (char)(SensorOnIcon + boostIconOffset);
}
else if (value == 2)
{
Label += (char)(SensorPlanIcon + boostIconOffset);
}
printToMatrix(Label);
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setTemp;
EEPROM.write(sensorVal, value);
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setTemp)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = EEPROM.read(temperatureVal);
setFirstVal(0);
}
Label = (char)stupneIcon;
Label += F("C:");
if (value)
Label += (char)enabledIcon;
else
Label += (char)disabledIcon;
printToMatrix(Label);
}
else
{
setFirstVal(1);
setSaveVal(0);
#ifdef DTS_SUPPORT
setMode = setDTS;
#else
setMode = setHour;
#endif
EEPROM.write(temperatureVal, value);
}
}
#endif
#ifdef DTS_SUPPORT
///////////////////////////////////////////////////////////////
else if (setMode == setDTS)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = EEPROM.read(dtsVal);
setFirstVal(0);
}
Label = F("DTS:");
if (value)
Label += (char)dtsLetoIcon;
else
Label += (char)dtsZimaIcon;
printToMatrix(Label);
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setHour;
EEPROM.write(dtsVal, value);
}
}
#endif
///////////////////////////////////////////////////////////////
else if (setMode == setHour)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = rtc.getTime().hour;
setFirstVal(0);
}
#if LED_MODULES < 6
Label = F("Ho:");
#else
Label = F("Hod:");
#endif
printToMatrix(Label + String(value));
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setMinute;
#ifdef DTS_SUPPORT
if (EEPROM.read(dtsVal))
{
value--;
}
#endif
rtc.setTime(value, rtc.getTime().min, rtc.getTime().sec);
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setMinute)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = rtc.getTime().min;
setFirstVal(0);
}
#if LED_MODULES < 6
Label = F("Mi:");
#else
Label = F("Min:");
#endif
printToMatrix(Label + String(value));
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setSecond;
rtc.setTime(GetDTSOrigHour(), value, rtc.getTime().sec);
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setSecond)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = rtc.getTime().sec;
setFirstVal(0);
}
#if LED_MODULES < 6
Label = F("Se:");
#else
Label = F("Sek:");
#endif
printToMatrix(Label + String(value));
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setDay;
if (isClockSetup)
{
isClockSetup = false;
setMode = setNone;
}
rtc.setTime(GetDTSOrigHour(), rtc.getTime().min, value);
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setDay)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = rtc.getTime().date;
setFirstVal(0);
}
#if LED_MODULES < 6
Label = F("De:");
#else
Label = F("Den:");
#endif
printToMatrix(Label + String(value));
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setMonth;
rtc.setDate(value, rtc.getTime().mon, rtc.getTime().year);
rtc.setDOW();
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setMonth)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = rtc.getTime().mon;
setFirstVal(0);
}
#if LED_MODULES < 6
Label = F("Me:");
#else
Label = F("Mes:");
#endif
printToMatrix(Label + String(value));
}
else
{
setFirstVal(1);
setSaveVal(0);
setMode = setYear;
rtc.setDate(rtc.getTime().date, value, rtc.getTime().year);
rtc.setDOW();
setValChanged(1);
}
}
///////////////////////////////////////////////////////////////
else if (setMode == setYear)
{
if (!getSaveVal())
{
if (getFirstVal())
{
value = rtc.getTime().year;
setFirstVal(0);
}
#if LED_MODULES == 8
Label = F("Rok:");
printToMatrix(Label + String(value));
#else
printToMatrix(String(value));
#endif
}
else
{
// Ukonci menu
setMode = setNone;
rtc.setDate(rtc.getTime().date, rtc.getTime().mon, value);
rtc.setDOW();
}
}
}
#ifdef FLASH_SUPPORT
else if (flash)
{
matrix.setIntensity(15);
matrix.fillScreen(HIGH);
matrix.write();
}
#endif
else if (getDisplayOff())
{
matrix.setIntensity(0);
matrix.fillScreen(LOW);
matrix.drawPixel((H_DISPLAYS * 8) - 1, 0 /*(rtc.getTime().min % 6) + 1*/, rtc.getTime().sec % 4 == 0);
matrix.write();
return;
}
else if (!getDisplayOff() && !getSettings())
{
if (getValChanged())
{
setValChanged(0);
return;
}
matrix.fillScreen(LOW);
int letter = i / FONT_WIDTH;
int x = (matrix.width() - 1) - i % FONT_WIDTH;
int y = (matrix.height() - 8) / 2; // center the text vertically
while ( x + FONT_WIDTH - SPACER >= 0 && letter >= 0 ) {
if (getSettings())
{
return;
}
if ( letter < output.length() ) {
matrix.drawChar(x, y, output[letter], HIGH, LOW, 1);
}
letter--;
x -= FONT_WIDTH;
}
matrix.write();
delay(WAIT * 2);
}
}
}
void loop() {
String output = outputStrClock();
#ifndef QUICK_SENSOR
#ifdef ADV_SUPPORT
matrix.setIntensity(getLedIntensity()); // value between 0 and 15 for brightness
#endif
#endif
scrollToMatrix(output);
if ((EEPROM.read(nightVal) == 1 || getShow() == showCustOff)
&& (rtc.getTime().hour >= EEPROM.read(nightFromVal) || rtc.getTime().hour < EEPROM.read(nightToVal))
&& !getSettings())
{
if (getShow() == showCustOff)
{
////
resetNightMode();
}
setDisplayOff(1);
setActiveNight(1);
}
else if (EEPROM.read(nightVal) == 1
&& (rtc.getTime().hour >= EEPROM.read(nightToVal) && rtc.getTime().hour < EEPROM.read(nightFromVal)))
{
setDisplayOff(0);
setActiveNight(0);
}
}
#ifdef SD_SUPPORT
String readTextFromSD(String _output, bool isDT)
{
byte len = 0;
String openFile = "";
String Type = "";
bool displayOff = getDisplayOff();
#ifdef FLASH_SUPPORT
if (!getSettings() && !flash)
#else
if (!getSettings())
#endif
{
int year = rtc.getTime().year;
if (isDT)
{
Type = F("DT ");
openFile = String(year) + F("/") + String(rtc.getTime().mon) + F("-") + String(rtc.getTime().date);
}
else
{
Type = F("RT ");
openFile = String(year) + F("/year");
}
matrix.fillScreen(LOW);
matrix.write();
}
if (!displayOff)
{
_output = Type;
}
else
{
return _output;
}
#ifdef SD_SUPPORT
#ifdef TEXT_TIME
_output.concat(rtc.getTimeStr(FORMAT_SHORT));
_output.concat(F(" "));
#endif
#endif
#ifdef SD_SUPPORT
if (getSdExists() & SD.exists(openFile)) {
// Open file
myFile = SD.open(openFile, FILE_READ);
// read from the file until there's nothing else in it:
while (myFile.available()) {
len++;
if (len < MAX_LEN)
{
_output += char(myFile.read());
}
else
{
_output += (char)6; // .. (2 dots)
break;
}
}
myFile.close();
delay(500);
}
#endif
return _output;
}
#endif
String outputStrClock() {
String _output = "";
String space = F(" ");
bool activeNight = getActiveNight();
bool sdExists = getSdExists();
byte show = getShow();
if (show != showDT && show != showRT)
{
if (EEPROM.read(nightVal) == 1 && activeNight)
{
_output.concat(space);
_output.concat(rtc.getTimeStr(FORMAT_SHORT));
_output.concat(space);
}
else
{
#ifdef DAY_FIX
String _fix = String((char)138);
_fix += (char)116;
#endif
if (!activeNight && EEPROM.read(simpleVal) == 0)
{
_output = rtc.getTimeStr(FORMAT_SHORT);
_output.concat(space);
_output.concat(rtc.getDateStr());
_output.concat(space);
#ifdef DAY_FIX
if (rtc.getDOWStr() == "Stv")
{
_output += _fix;
}
else
#endif
{
_output.concat(rtc.getDOWStr());
}
_output.concat(space);
#ifdef ADV_SUPPORT
if (EEPROM.read(temperatureVal) == 1)
#endif
{
_output.concat(rtc.getTemp());
_output.concat((char)stupneIcon);
_output.concat(F("C"));
}
}
else
{
_output.concat(rtc.getTimeStr(FORMAT_SHORT));
_output.concat(space);
#ifdef DAY_FIX
if (rtc.getDOWStr() == "Stv")
{
_output += _fix;
}
else
#endif
{
_output.concat(rtc.getDOWStr());
}
}
}
}
#ifdef SD_SUPPORT
// Read TEXT
//readingText = false;
setActiveNight(0);
byte min = rtc.getTime().min;
if (sdExists && (show == showRT || min == 0) && !activeNight)
{
//readingText = true;
setActiveNight(1);
_output = readTextFromSD(_output, 0);
resetShow();
}
else if (sdExists && (show == showDT || min % 15 == 0) && !activeNight)
{
//readingText = true;
setActiveNight(1);
_output = readTextFromSD(_output, 1);
resetShow();
}
#endif
return _output;
}
byte getLedIntensity() {
#ifdef LED_BOOST
byte _value = EEPROM.read(ledVal);
#else
byte _value = 0;
#endif
#ifdef ADV_SUPPORT
byte light = analogRead(LDR_PIN);
if (EEPROM.read(sensorVal) == 1)
{
// LDR by range
if (light >= 0 && light <= 80) {
_value = 15;
}
else if (light >= 81 && light <= 200) {
_value += 6;
}
else if (light >= 201 && light <= 400) {
_value += 2;
}
}
else if (EEPROM.read(sensorVal) == 2)
{
#endif
byte hour = rtc.getTime().hour;
if (hour < 7)
{
_value = 0;
}
else if (hour < 11)
{
_value += 3;
}
else if (hour < 15)
{
_value += 7;
}
else if (hour < 21)
{
_value += 3;
}
else if (hour < 23)
{
_value = 0;
}
#ifdef ADV_SUPPORT
}
#endif
return _value;
}