Noob: Turn on/off LED at 8:00AM

I’d like to turn an LED on at 8:00AM. I’m a noobie programmer, so most of the API calls go over my head.
I understand the blinking LED program, and I could adjust it to blink on a longer period, but that would depend on when the spark starts up. Is there any way to check to see what the current time is? I’m thinking I’d elongate the loop to 60 minutes and put the conditional check to see if the hour of the time is between 8 and 10.

Any help making this (what seems to me a very simple) program?

Hi @sweenig,

You're in luck! A bunch of community members ported Network Time syncing code to run on the core, and I recently made a blink an LED example using their code. I posted that here:

This program blinks on every multiple of 5 seconds synced with a time server, it should be a small step to port that to blink at 8am. :slight_smile:

Thanks,
David

Thanks @Dave! That got me pretty much there. I do have a couple questions about it though.
Here’s what I’ve got so far (my OCD required me to remove much of the whitespace):

UDP UDP;
char string[ 17 ] = { "" };
int led = D0;
int hour, minute, second;
unsigned int localPort = 123;
unsigned int timeZone = -6; //tz offset
unsigned int serverNum = 0;
unsigned long timeout;
const char timeServer[] = "pool.ntp.org";
const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
int synced = 0;
int state = 0;
unsigned int offset = 0;
unsigned long secsSince1900 = 0;
void setup()
{
	UDP.begin(localPort);
	pinMode(led, OUTPUT);
}
void loop()
{
    if (!synced) {syncTime();synced = 1;}
    receiveTimeTick();
    if (hour >= 8) {
        digitalWrite(led, HIGH); //go on
        delay(3600 * 3); //stay on for three hours
        digitalWrite(led, LOW); //go off
    }
    delay(60000); //idle for 1 minute (could be much longer really)
}
void syncTime() {sendNTPpacket(timeServer);}  // send an NTP packet to a time server wait to see if a reply is available
void receiveTimeTick() {
    if (synced) {return;}
    if ( UDP.parsePacket() ) {
    	UDP.read(packetBuffer, NTP_PACKET_SIZE);  // read the packet into the buffer
	    //the timestamp starts at byte 40 of the received packet and is four bytes,
	    // or two words, long. First, extract the two words:
	    unsigned long highWord = (packetBuffer[40] << 8) + packetBuffer[41];
	    unsigned long lowWord = (packetBuffer[42] << 8) + packetBuffer[43];
	    // combine the four bytes (two words) into a long integer
	    // this is NTP time (seconds since Jan 1 1900):
        secsSince1900 = highWord << 16 | lowWord;
	    secsSince1900 += timeZone*60*60;
	    offset = millis();
	    synced = 1;
    }
	while ( UDP.parsePacket() ) {               // clean-up buffer
		UDP.read(packetBuffer, NTP_PACKET_SIZE);  // read the packet into the buffer
	}
}
unsigned long sendNTPpacket(const char *address) // function to send an NTP request to the time server at the given address
{
	// set all bytes in the buffer to 0
	memset(packetBuffer, 0, NTP_PACKET_SIZE);
	// Initialize values needed to form NTP request
	packetBuffer[0] = 0b11100011;   // LI, Version, Mode
	packetBuffer[1] = 0;     // Stratum, or type of clock
	packetBuffer[2] = 6;     // Polling Interval
	packetBuffer[3] = 0xEC;  // Peer Clock Precision
	// 8 bytes of zero for Root Delay & Root Dispersion
	packetBuffer[12]  = 49;
	packetBuffer[13]  = 0x4E;
	packetBuffer[14]  = 49;
	packetBuffer[15]  = 52;
	// all NTP fields have been given values, now you can send a packet requesting a timestamp:
	UDP.beginPacket(address, 123);
	UDP.write(packetBuffer, NTP_PACKET_SIZE); //NTP requests are to port 123
	UDP.endPacket();
}

So, a couple questions:

  1. Can the syncTime() and sendNTPpacket() functions be consolidated down to one single function?
  2. Since I don’t have anything other than an LED connected to the spark, I assume I can remove all the parts that involve the serial output, right?

Hey @sweenig,

Sure you can safely drop the serial output, but some serial output can be handy when debugging. Hmm, at the moment in the code “sendNTPpacket” is contained within “syncTime”, do you mean “receiveTimeTick” ?

It’s just really important whenever you write NTP code that touches someone else’s server that you’re careful not to send out too many requests (more than 1 an hour, say). Those servers handle a lot of traffic, and they’re sensitive to overuse. The check to see if you’ve received a packet needs a while (25-1000s) of ms before a response will have come back so checking it this way in the loop is pretty laid back as opposed to blocking or expecting it to happen in a particular time frame.

Thanks,
David

I think a cool feature that the team could implement down the road is a pseudo RTC. Where each time the core connects to the cloud it grabs the time, and just use millis() and some internal calculations to provide Spark.time.hour(), Spark.time.minute() etc…

1 Like

I am working on something just like this.

1 Like

Thanks @Dave. I’ve dropped the serial output. How would I normally get the output seeing as I have nothing but an LED connected to the Spark? I’d need some kind of display connected to receive the serial output, right? Just checking what it takes to make that happen as I don’t have plans to do anything on that level yet.

I mean that syncTime() just makes a call to sendNTPpacket(), and it’s the only thing in the syncTime() function. I was wondering if I could just skip the syncTime() function and just call directly to the sendNTPpacket() function.

Let me see if I understand the flow properly:

  1. initially synced=0, so an NTP request is sent. I’ve added a delay because I really don’t mind holding the execution so that maybe I can get this all done in one loop.
  2. the receiveTimeTick() function would run every time the loop repeats, trying to read in a UDP response, if it’s there. If it is not, the loop repeats and since synced is still 0, another request is sent. This is where I need to be careful to not overload the NTP server with requests. If an NTP response is found by the receiveTimeTick() function, it’ll set secsSince1900 to the proper time and then set synced to 1.
  3. Now that synced is 1, the sending of the NTP packet is skipped and instead, the main portion of the if loop runs, which converts the time (something I removed initially but realized has to be in there even if I’m not outputting serially) and turns on my LED.

Is this how the program is supposed to work? I think the following code does this. (Sorry my very real OCD required me to remove many of the comments and whitespace.) Any reasons you guys can see that this wouldn’t work? (Go ahead and let me have it, but remember I’m a noob and a hobbyist, I’m a network engineer by trade.)

UDP UDP;
char string[ 17 ] = { "" };
int led = D0;
int hour, minute, second;
unsigned int localPort = 123;
unsigned int timeZone = -6; //tz offset
const char timeServer[] = "pool.ntp.org";
const int NTP_PACKET_SIZE= 48;
byte packetBuffer[NTP_PACKET_SIZE];
int synced = 0;
unsigned int offset = 0;
unsigned long secsSince1900 = 0;
void setup()
{
	UDP.begin(localPort);
	pinMode(led, OUTPUT);
	digitalWrite(led, LOW); //set it to be off initially
	RGB.control(true);
}
void loop()
{
	if (!synced) {
		RGB.color(255, 0, 0); //for status output
		sendNTPpacket(timeServer); //send NTP request
		delay(1500); //wait for a response
	}
	receiveTimeTick(); //try to read a packet. if receiveTimeTick() fails, status will still be 0, so loop repeats and another request is sent.
	if (synced) {
		RGB.color(0, 255, 0);
		displayTime(); //convert the time into usable chunks
		if (hour >= 8) {
			RGB.color(0, 0, 255);
			digitalWrite(led, HIGH);
			delay(3600000 * 3);
			digitalWrite(led, LOW);
		}
		delay(60000);
	}
}
void displayTime() {
	if (!synced) {return;}
	const unsigned long seventyYears = 2208988800UL;    
	unsigned long epoch = secsSince1900 - seventyYears;
	epoch += ((millis() - offset) / 1000.0);
	hour = (epoch % 86400L) / 3600;         
	minute = (epoch % 3600) / 60;
	second = (epoch % 60);
}
void receiveTimeTick() {
	if (synced) {return;}
	if ( UDP.parsePacket() ) {
		UDP.read(packetBuffer, NTP_PACKET_SIZE);
		unsigned long highWord = (packetBuffer[40] << 8) + packetBuffer[41];
		unsigned long lowWord = (packetBuffer[42] << 8) + packetBuffer[43];
		secsSince1900 = highWord << 16 | lowWord;
		secsSince1900 += timeZone*60*60;
		offset = millis();
		synced = 1;
	}
	while ( UDP.parsePacket() ) {UDP.read(packetBuffer, NTP_PACKET_SIZE);}
}
unsigned long sendNTPpacket(const char *address)
{
	memset(packetBuffer, 0, NTP_PACKET_SIZE);
	packetBuffer[0] = 0b11100011;	 // LI, Version, Mode
	packetBuffer[1] = 0;		 // Stratum, or type of clock
	packetBuffer[2] = 6;		 // Polling Interval
	packetBuffer[3] = 0xEC;	// Peer Clock Precision
	packetBuffer[12]	= 49;
	packetBuffer[13]	= 0x4E;
	packetBuffer[14]	= 49;
	packetBuffer[15]	= 52;
	UDP.beginPacket(address, 123);
	UDP.write(packetBuffer, NTP_PACKET_SIZE); //NTP requests are to port 123
	UDP.endPacket();
}

Hi @sweenig,

I would add another flag and a delay or something just to make sure you’re not sending out lots and lots of NTP requests before you’ve heard back. Communicating over the Internet via packets means you’re not guaranteed to get a response at all, or exactly when you might prefer, so some flexibility is required. You definitely don’t need the wrapper function “syncTime”, just part of my effort to make the code more readable.

In your loop function you have a 60 second delay. Right now this isn’t going to work because the delays are hard stops, and they prevent the Core from maintaining its connection to the cloud. A delay this long will force your core to reset and try to reconnect. So throw some protections around “sendNTPpacket” so you don’t spam the server, and don’t block as long, and you’re set.

Thanks,
David

I posted my time library today over here:

https://community.spark.io/t/real-time-clock-library-for-spark/2925

Ok, the 60 second delay may have been something I really missed, early on. Aside from downloading the initial program, I don’t need my spark to be connected to the cloud. In fact, unless the power resets (and the ‘clock’ gets out of sync) I don’t see any reason to connect to the cloud except at initialization. Why would a 60 second delay cause the core to lose its connection? Why should I care? If there’s a good reason, I want to understand it. If the only reason is that the core likes to stay connected to the mothership, there should be a way to disable that, right?

I’ve gone back to the drawing board to try and implement your recommended controls and get rid of the stopping delays. This all very helpful and I’m learning a ton by trying to make this code my own. Thanks for all your help!

As a side question: What difference does it make if I declare stuff before the setup() function as opposed to inside the setup function? If there’s no difference, is there a best practice? Should I be declaring all my variables and stuff within the setup() function? Is it a matter of personal preference/readability?

Here’s what I have now

UDP UDP;
int houron = 8;
int houroff = 11;
char string[ 17 ] = { "" };
int hour, minute, second;
int led = D0;
unsigned int localPort = 123;
unsigned int timeZone = -6; //tz offset
const char timeServer[] = "pool.ntp.org";
const int NTP_PACKET_SIZE= 48;
byte packetBuffer[NTP_PACKET_SIZE];
int ntpsent = 0; //number of ntp requests sent
int ntplistened = 0; //number of times we've listened for an ntp response
int synced = 0;
unsigned int offset = 0;
unsigned long secsSince1900 = 0;
void setup()
{
	UDP.begin(localPort);
	RGB.control(true);
	pinMode(led, OUTPUT);digitalWrite(led, LOW); //set it to be off initially
}
void loop()
{
	if (!synced) {
		RGB.color(255, 0, 0); //red indicates not sync'd
		if (!ntpsent || ntplistened >= 3000) {sendNTPpacket(timeServer);} //send request if not yet req'd or if no response in 3000 loops
		receiveTimeTick(); //try to read a response
	}
	if (synced) {
		RGB.color(0, 255, 0); //green indicates sync'd
		const unsigned long seventyYears = 2208988800UL;
		unsigned long epoch = secsSince1900 - seventyYears;
		epoch += ((millis() - offset) / 1000.0);
		hour = (epoch % 86400L) / 3600;minute = (epoch % 3600) / 60;second = (epoch % 60); //calculate h, m, & s
		if (second <= (houron - 1)) {digitalWrite(led, LOW);} //if before 8am, turn off LED
		if (second >= houron && second <= (houroff - 1)) {digitalWrite(led, HIGH);} //if between 8:00am and 10:59am, turn on LED
		if (second >= houroff) {digitalWrite(led, LOW);} //if after 11am, turn of LED
		delay(1000); //in no hurry here since we're waiting for time to pass, but don't stop too long
	}
}
unsigned long sendNTPpacket(const char *address)
{
	memset(packetBuffer, 0, NTP_PACKET_SIZE);
	packetBuffer[0] = 0b11100011;packetBuffer[1] = 0;packetBuffer[2] = 6;
	packetBuffer[3] = 0xEC;packetBuffer[12] = 49;packetBuffer[13] = 0x4E;
	packetBuffer[14] = 49;packetBuffer[15] = 52;UDP.beginPacket(address, 123);
	UDP.write(packetBuffer, NTP_PACKET_SIZE);UDP.endPacket();
	ntpsent += 1;ntplistened = 0;
}
void receiveTimeTick() {
	ntplistened += 1;
	if ( UDP.parsePacket() ) {
		UDP.read(packetBuffer, NTP_PACKET_SIZE);
		unsigned long highWord = (packetBuffer[40] << 8) + packetBuffer[41];
		unsigned long lowWord = (packetBuffer[42] << 8) + packetBuffer[43];
		secsSince1900 = highWord << 16 | lowWord;
		secsSince1900 += timeZone*60*60;
		offset = millis();
		synced = 1;
	}
	while ( UDP.parsePacket() ) {UDP.read(packetBuffer, NTP_PACKET_SIZE);}
	//delay(1000); //do i need a delay here just to make sure all 3000 loops don't happen too quickly?
}

If you plug the Core into your computer it will show up as a serial device, then you can use a serial terminal program like puTTY (Windows) or Terminal + screen (Mac) to connect to it. Anything sent with the Serial.print Serial.println Serial.write commands will show up on the serial console on your computer. :smile:

Also, seriously try to not remove all the white space and comments from the code if you're going to post them for help, it make it hard for the rest of us to read the code and help you. It would be really nice if you could comment your code as well so we know what you think your code should be doing / are trying to do. Don't get me wrong, I'm not angry or anything, these are just good programming practices you should get in the habit of now. Code should be indented, generally one tab per level of loop, this makes it easier to ascertain where you are in nested loops; in general it's a good idea to leave a blank like between blocks of code that do something specific and break large chunks of specific code into functions where possible and each function should be separated by a blank line as well to make it easier to find your way around.

If you're going to be OCD, try to direct it towards best practices and making code easily readable. You're not saving memory by removing white spaces and comments; the compiler does that for you! :wink:

1 Like

Ok, serial output through my PC is completely awesome and I totally missed that. I’ll give it a shot.

I understand about the whitespace comments, I have no problem with that. One of the main reasons i do it is to compress things vertically since i have a 16:9 monitor on my system and I don’t like having to scroll up and down just to see the whole block of code. For that same reason, I find myself zooming out to the smallest readable font (in any editor). In fact, for this project, I’ve been developing the code in Notepad++ instead of the spark editor.

I do want the help and I can overcome my OCD to make the code more readable. Remember, I’m a noob, and I appreciate tips like this that help me interact with the community more easily/productively.

I guess what I would really like to see is a way that I can link to the build section of the spark.io website. Copying and pasting code from there to the message boards seems less than ideal given that the editor already has syntax highlighting, line numbers, etc. I think it would make collaboration easier. It shouldn’t be too hard to link to specific versions so people reading the post later on can see the evolution of a particular block of code.

Back to the problem at hand: I went ahead and flashed my spark with this code and it seems to work for a while. However, eventually, something resets and the whole thing reinitializes, i lose control of the RGB LED, but the led on D0 continues to flash as expected. Since this will eventually be a toddler alarm clock, I want to keep control over all the lights on the system. Any ideas why it freaks out? I’ll have to keep it in front of me (and running on seconds instead of hours to see if there’s any rhyme or reason to it).

Here’s the current version of the code (whitespace added and even more comments added).

Hey @sweenig,

Totally, we've been talking about a way to share code more easily and link into the build site, I think this is in the pipeline. :smile:

On the Core, your code is running alongside a bunch of code that's handling the internet and initializing the hardware for you. We're noticing that when you do your own hardware initialization outside the setup function, it's possible that it can run at the wrong time, causing stuff to not be initialized how you might want. The safest thing is to cause any hardware initialization specific stuff (like pinMode) to be called from setup(). You can declare variables wherever / globally if you want, but it's important to remember your code is running on an embedded platform, so you don't have infinite ram :slight_smile:

Thanks,
David

Totally, we've been talking about a way to share code more easily and link into the build site, I think this is in the pipeline. smile
That's wonderful to hear!

Ok, so the best practice really would be for me to contain all my stuff within the setup function, right? Obviously it doesn't have to be that way, but if I do it that way, I'm being 'safe'. Of course I have to keep in mind the resource limitations, but if the guys at Spark can build a Nest thermostat, I can build a simple blinking LED.

I'm still having problems losing control of the RGB led after an indeterminate amount of time running my code. As you can see on my updated code, I've put the RGB.control(true) call within the loop to try to see if that will retain control.

As as side note (next feature I'll be adding to this thing): Are there any examples of ways to creatively light up the RGB led? I'd like to see if I could make a low pulsing red before the toddler should wake up and then cross fade to green. I could play around with it myself, but I figured there might already be some examples out there (perhaps a couple functions I could drop in).

Hey @sweenig,

Here’s my RGB control test code that I use on my cores, it’s based on @BDub’s NeoPixel code ( https://community.spark.io/t/adafruit-neopixel-library/1143 ) :

int count = 0;
int direction = 1;
int maxcount = 32768;
int steps = 10;
uint32_t delayVal = 25;
  
int red; 
int green;  
int blue;

void setup() { 
    RGB.control(true);
    RGB.color(0, 0, 0); 
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
void Wheel(uint8_t WheelPos) {
  if (WheelPos < 85) {
    setColor(WheelPos * 3, 255 - WheelPos * 3, 0);
  } 
  else if (WheelPos < 170) {
    WheelPos -= 85;
    setColor(255 - WheelPos * 3, 0, WheelPos * 3 );
  } 
  else {
    WheelPos -= 170;
    setColor(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

void setColor(uint8_t r, uint8_t g, uint8_t b) {
  red = r;
  green = g;
  blue = b;
  RGB.color(r, g, b);
}


void stepColors() {
    count += direction;
    if (count > maxcount) {
        direction = -1;
    }
    else if (count == 0) {
        direction = 1;
    }
    
    Wheel(count);
}

void loop() {
    for(int i=0;i<steps;i++) {
        stepColors();
        Delay(delayVal);
    }
}
1 Like