So this code does what I want it to, but it feels very "hardwired" and I don't know the best way to make it better.
I put the code on Github, I don't think a snippet will suffice here.
So this code does what I want it to, but it feels very "hardwired" and I don't know the best way to make it better.
I put the code on Github, I don't think a snippet will suffice here.
Code looks clean, not sure what you mean by "hardwired". What do you not like about the code.
#include <Wire.h>
#include "RTClib.h"
#include <IRremote.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"
#define TODBUTTON 4
#define OVERRIDEBUTTON 5
SSD1306AsciiWire oled;
IRsend irsend;
RTC_DS3231 rtc;
//sets the different options for time events
enum class TimeOfDay : uint8_t
{
Night, Dawn, Day, Dusk, Evening, Storm
};
//initializes the time keeper variables
TimeOfDay tod = TimeOfDay::Night;
TimeOfDay newTod = TimeOfDay :: Storm;
boolean powerWhite = true;
boolean powerRGB = false;
boolean todSent = false;
boolean overrideTod = false;
boolean forceTod = false;
void setup()
{
Serial.begin(9600);
Wire.begin();
oled.begin(&Adafruit128x64, 0x3C);
pinMode(TODBUTTON,INPUT_PULLUP);
pinMode(OVERRIDEBUTTON,INPUT_PULLUP);
//updates the time and date to the time and date the sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
void loop() {
//turns override mode on and off
if(digitalRead(OVERRIDEBUTTON) == LOW)
{
overrideTod = !overrideTod;
}
//force next tod;
if (digitalRead(TODBUTTON) == LOW)
{
newTod = nextEnum();
}
DateTime now = rtc.now();
scheduler(now);
updateDisplay(now);
delay(3000);
}
void scheduler(DateTime now)
{
if (overrideTod)
{
if (newTod == TimeOfDay::Day && tod != newTod) {
tod = TimeOfDay::Day;
Day();
}
else if (newTod == TimeOfDay::Dawn && tod != newTod) {
tod = TimeOfDay::Dawn;
dawn();
}
else if (newTod == TimeOfDay::Dusk && tod != newTod){
tod = TimeOfDay::Dusk;
dusk();
}
else if (newTod == TimeOfDay::Evening && tod != newTod){
tod = TimeOfDay::Evening;
evening();
}
else if (newTod == TimeOfDay::Night && tod != newTod){
tod = TimeOfDay::Night;
night();
}
}
else
{
forceTod = false;
if(now.hour() >= 6 && now.hour() < 7 && tod !=TimeOfDay::Dawn){
newTod = TimeOfDay::Dawn;
tod = TimeOfDay::Dawn;
dawn();
}
else if(now.hour() >= 7 && now.hour() < 18 && tod !=TimeOfDay::Day){
newTod = TimeOfDay::Day;
tod = TimeOfDay::Day;
Day();
}
else if(now.hour() >= 18 && now.hour() < 19 && tod !=TimeOfDay::Dusk){
newTod = TimeOfDay::Dusk;
tod = TimeOfDay::Dusk;
dusk();
}
else if(now.hour() >= 19 && now.hour() < 22 && tod !=TimeOfDay::Evening){
newTod = TimeOfDay::Evening;
tod = TimeOfDay::Evening;
evening();
}
else if(now.hour() >= 22 || now.hour() < 6 && tod !=TimeOfDay::Night){
newTod = TimeOfDay::Night;
tod = TimeOfDay::Night;
night();
}
}
}
void updateDisplay(DateTime now)
{
oled.set1X();
oled.setFont(ZevvPeep8x16);
oled.clear();
//prints current time
oled.print(now.hour(), DEC);
oled.print(':');
if(now.minute() < 10) oled.print('0');
oled.println(now.minute(), DEC);
//prints Override status
if(overrideTod == true) oled.println("Override");
else oled.println();
//prints tod
oled.set2X();
if(tod == TimeOfDay::Night) oled.println("Night");
else if(tod == TimeOfDay::Dawn) oled.println("Dawn");
else if(tod == TimeOfDay::Day) oled.println("Day");
else if(tod == TimeOfDay::Dusk) oled.println("Dusk");
else if(tod == TimeOfDay::Evening) oled.println("Evening");
}
TimeOfDay nextEnum()
{
if(tod == TimeOfDay::Night) return TimeOfDay::Dawn;
else if(tod == TimeOfDay::Dawn) return TimeOfDay::Day;
else if(tod == TimeOfDay::Day) return TimeOfDay::Dusk;
else if(tod == TimeOfDay::Dusk) return TimeOfDay::Evening;
else if(tod == TimeOfDay::Evening) return TimeOfDay::Night;
else return TimeOfDay::Day;
}
/////////////////////////////
// Events
//whPower = 0xF7C03F;
//whPlus = 0xF7E01F;
//whMinus = 0xF7D02F;
//storm = 0xF7C837;
//rgbPower = 0xF740BF;
//blue = 0xF750AF;
//amber = 0xF708F7;
//pink = 0xF76897;
////////////////////////////////////
void night()
{
if (powerWhite) {
irsend.sendNEC(0xF7C03F,32);
powerWhite = !powerWhite;
}
if (powerRGB)
{
irsend.sendNEC(0xF740BF,32);
powerRGB = !powerRGB;
}
}
void dawn()
{
if (powerWhite) {
irsend.sendNEC(0xF7C03F,32);
powerWhite = !powerWhite;
}
if (!powerRGB)
{
irsend.sendNEC(0xF740BF,32);
powerRGB = !powerRGB;
}
irsend.sendNEC(0xF708F7,32);
}
void Day()
{
if (!powerWhite) {
irsend.sendNEC(0xF7C03F,32);
powerWhite = !powerWhite;
}
if (powerRGB)
{
irsend.sendNEC(0xF740BF,32);
powerRGB = !powerRGB;
}
}
void dusk()
{
if (powerWhite) {
irsend.sendNEC(0xF7C03F,32);
powerWhite = !powerWhite;
}
if (!powerRGB)
{
irsend.sendNEC(0xF740BF,32);
powerRGB = !powerRGB;
}
irsend.sendNEC(0xF76897,32);
}
void evening()
{
if (powerWhite) {
irsend.sendNEC(0xF7C03F,32);
powerWhite = !powerWhite;
}
if (!powerRGB)
{
irsend.sendNEC(0xF740BF,32);
powerRGB = !powerRGB;
}
irsend.sendNEC(0xF750AF,32);
}
If I want to add another time of day I have to add it in several places. Or if I want to change the time, again I have to go hunting and change a couple different things.
You could wrap your times together with a pointer to the function to be called into an entry in a list of structures.
Set an index into the structures based on the hour and call whatever function is at that index.
This method would allow you to add or remove times at will. It will not, however, handle the special case of night where the comparison is different from the others.
// time of day functions
void dawn() {
Serial.println("Dawn");
}
void day() {
Serial.println("Day");
}
void dusk() {
Serial.println("Dusk");
}
void evening() {
Serial.println("Evening");
}
// storage for one time of day
typedef struct {
byte hourLow;
byte hourHigh;
void (*fn)();
} tod;
/* Dawn, Day, Dusk, Evening */
tod todList[] = {6, 7, dawn,
7, 18, day,
18, 19, dusk,
19, 22, evening
};
byte todIdx; // index into todList
const byte LIST_SIZE = sizeof(todList) / sizeof(todList[0]);
void setup() {
Serial.begin(9600);
// dawn
setIndex(6);
(*todList[todIdx].fn)();
// day
setIndex(10);
(*todList[todIdx].fn)();
// dusk
setIndex(18);
(*todList[todIdx].fn)();
// evening
setIndex(19);
(*todList[todIdx].fn)();
}
// set index into time of day list
void setIndex(byte hour)
{
for (byte idx = 0; idx < LIST_SIZE; idx++)
{
// if passed hour is between high and low
if ( (hour >= todList[idx].hourLow) && (hour < todList[idx].hourHigh) )
{
// set index, stop looking
todIdx = idx;
break;
} // if
} // for
}
void loop() {}
Unrelated to you question, but there’s no need to go out to your RTC every time you want to get the current time. Add in the TimeLib.h library. It keeps time using internal millis() so retrieval of time is very efficient, no I2C transactions. The millis()-based time is plenty accurate over the short term.
The library has the ability to hook in a callback function that’s called at an interval of your choice. In that callback you go to the RTC and get the current time. The library then uses that to true-up its internal time. You don’t need to do that very often - every 5 or 10 minutes is fine.
It looks like you are sending the same IR code to turn the lights ON and OFF so all you need for each is to send the code when the state changes. This can simplify your "Time Of Day" functions quite a bit. It would be good to give the IR codes names
unsigned long IRCodeBlue = 0xF750AFUL;
unsigned long IRCodeAmber = 0xF708F7UL;
void evening()
{
SetWhite(false);
SetRGB(true);
irsend.sendNEC(IRCodeBlue, 32);
}
void SetWhite(boolean newState)
{
if (powerWhite != newState)
{
// Time to toggle
irsend.sendNEC(0xF7C03F, 32);
}
powerWhite = newState;
}
void SetRGB(boolean newState)
{
if (powerRGB != newState)
{
// Time to toggle
irsend.sendNEC(0xF7C03F, 32);
}
powerRGB = newState;
}
I tried to name the colors, but it wasn't working because I didn't add the UL at the end!