Here are my sketches:
The TimeMaster:
#define CHILD_ID_TIME 1
#define CHILD_ID_SIGNAL 2
#define TARGET 27
// #define TARGET 26
MyMessage msgTime(CHILD_ID_TIME, V_CUSTOM);
MyMessage msgSignal(CHILD_ID_SIGNAL, V_STATUS);
#include "DCF77.h"
#include "Time.h"
#define DCF_PIN 2 // Connection pin to DCF 77 device
#define DCF_INTERRUPT digitalPinToInterrupt(DCF_PIN) // Interrupt number associated with pin
time_t time;
bool bPresented = false;
DCF77 DCF = DCF77(DCF_PIN, DCF_INTERRUPT);
void startDCF()
{
static bool bDCFStarted = false;
if (!bDCFStarted) {
DCF.Start();
pinMode(DCF_PIN, INPUT_PULLUP);
Serial.println("Waiting for DCF77 time ... ");
Serial.println("It will take at least 2 minutes until a first update can be processed.");
bDCFStarted = true;
}
}
void preHwInit()
{
Serial.begin(MY_BAUD_RATE);
Serial.println();
startDCF();
}
void setup()
{
msgSignal.setDestination(TARGET);
msgTime.setDestination(TARGET);
}
void presentation()
{
present(CHILD_ID_TIME, S_CUSTOM);
present(CHILD_ID_SIGNAL, S_BINARY);
}
bool bHaveTime = false;
unsigned long lastSentTime = 0;
void loop()
{
time_t DCFtime = DCF.getTime(); // Check if new DCF77 time is available
if (DCFtime != 0)
{
Serial.println("Time is updated");
setTime(DCFtime);
bHaveTime = true;
lastSentTime = minute();
}
if (bHaveTime) {
if (DCFtime != 0) {
Serial.println("Just obtained time. Send a message!");
msgTime.set(DCFtime);
send(msgTime);
}
if (minute() != lastSentTime) {
Serial.println("A minute has passed. Send a message!");
msgTime.set(now());
send(msgTime);
lastSentTime = minute();
}
}
}
The night light:
#define MY_RADIO_NRF24
#define MY_DEBUG
// #define MY_NODE_ID 27
// #define MY_GATEWAY_SERIAL
#include <MySensors.h>
#include <SPI.h>
#include <Adafruit_NeoPixel.h>
#include <avr/power.h>
#include <EEPROM.h>
#include <Time.h>
#define colorNight(s) (s.Color(255, 20, 147)) // Purple
#define colorDay(s) (s.Color( 0, 0, 0)) // Black
#define colorMorn(s) (s.Color( 44, 201, 13)) // Green
#define colorError(s) (s.Color(255, 0, 0))
#define colorUp(s) (s.Color( 0, 255, 0))
#define colorDown(s) (s.Color( 0, 0, 255))
#define PIN 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, PIN, NEO_GRB + NEO_KHZ800);
unsigned long colorPixel = 0;
unsigned long colorOld = 0xffff;
bool bHaveTime = false;
bool bEmergencyMode = false;
bool bEmergencyModeChecked = false;
void setPixelColor(unsigned long color)
{
colorPixel = color;
}
void doSetPixelColor(long color)
{
if (!bEmergencyMode || color == colorMorn(strip) || color == colorNight(strip)) {
strip.setPixelColor(0, color);
strip.show();
}
}
void doSetPixelColor()
{
if (colorOld != colorPixel) {
doSetPixelColor(colorPixel);
colorOld = colorPixel;
}
}
void receive(const MyMessage &message)
{
if (!bHaveTime && message.type == V_STATUS) {
setPixelColor(message.getBool() ? colorUp(strip) : colorDown(strip));
} else if (message.type == V_CUSTOM) {
time_t timeNow = message.getULong();
setTime(timeNow);
bHaveTime = true;
}
}
void presentation()
{
setPixelColor(colorUp(strip));
present(0, S_LIGHT);
}
void before()
{
strip.begin();
doSetPixelColor(colorDown(strip));
strip.show(); // Initialize all pixels to 'off'
}
void setup() {
// This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket
#if defined (__AVR_ATtiny85__)
if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif
// End of trinket special code
Serial.begin(115200);
EEPROM.write(300 + 2, EEPROM.read(300 + 1));
EEPROM.write(300 + 1, EEPROM.read(300 + 0));
EEPROM.write(300 + 0, 0xff);
}
void loop() {
static unsigned long int lastLoop = -1;
if (lastLoop == -1 || millis() < lastLoop || millis() - lastLoop > 60000) {
// request(0, V_CUSTOM, 42);
lastLoop = millis();
}
if (!bEmergencyModeChecked && millis() < 5000) {
bEmergencyMode = false;
bEmergencyModeChecked = true;
bool bNeedEmergencyMode = true;
for (int t = 0; t <= 2; ++t) {
if (EEPROM.read(300 + t) != 0xff) {
bNeedEmergencyMode = false;
}
}
bEmergencyMode = bNeedEmergencyMode;
if (bEmergencyMode) {
setPixelColor(colorNight(strip));
}
}
if (bEmergencyModeChecked && millis() >= 10000) {
EEPROM.write(300 + 0, 0);
bEmergencyModeChecked = false;
}
if (bEmergencyMode && millis() > 12L * 60 * 60 * 1000) {
setPixelColor(colorMorn(strip));
}
if (bHaveTime) {
if (hour() >= 19 || hour() < 7) {
setPixelColor(colorNight(strip));
} else if (hour() >= 8) {
setPixelColor(colorDay(strip));
} else if (hour() >= 7) {
setPixelColor(colorMorn(strip));
}
}
doSetPixelColor();
}
Emergency mode on the night light is triggered by starting and stopping it three times within 10 seconds each time, so that if it can't find a time source, you can still get 12 hours of 'night light' followed by 'day light'.
In the night light, I commented out the request() call (and I took out the receive() implementation in the TimeMaster) because I ran into the DCF time receiver starting again every time.
Any more info you need right now? Just shout!