Author Topic: Can oak get time from the cloud?  (Read 10158 times)

mab299108

  • Newbie
  • *
  • Posts: 6
Can oak get time from the cloud?
« on: July 20, 2016, 11:59:57 pm »
Looking at the particle reference document, I see that devices on the particle cloud should sync time with the server when they connect (https://docs.particle.io/reference/firmware/photon/#time). However, when I add Time.now() to my code I  get: 'Time' was not declared in this scope. I think that other particle devices have a built in RTC, so I am wondering if this this an ability that oak is missing, or is there another version of the firmware that I need to support getting the current time on oak?

PeterF

  • Hero Member
  • *****
  • Posts: 877
Re: Can oak get time from the cloud?
« Reply #1 on: July 22, 2016, 01:39:27 am »
AFAIK, it is unfortunately a missing ability, probably due to the different architecture of the Oaks onboard processor. As you say, boards like the Particle Photon have an onboard RTC. The ESP8266 MCU in the Oak has a RTC as well, but it is for internal timing purposes, rather being used as a time clock.

Best bet is probably to use an external RTC such as the DS1307, and/or NTP time : http://www.esp8266.com/viewtopic.php?f=32&t=2881

t4ce

  • Newbie
  • *
  • Posts: 5
Re: Can oak get time from the cloud?
« Reply #2 on: July 29, 2016, 09:46:39 am »

PeterF

  • Hero Member
  • *****
  • Posts: 877
Re: Can oak get time from the cloud?
« Reply #3 on: July 29, 2016, 08:23:36 pm »
That is indeed the correct call - however, as per the wiki and v1 firmware release notes, 'Particle.syncTime() - though time is not yet connected to anything'.

So the function is available (in as far as compiling without failing, it doesn't sync with anything, as the Oak doesn't have a user accessible RTC to sync the time with. And if you try to access any of the Time functions, it will fail with a 'Time not declared in this scope' error.

You could get the time via a HTTP request from one of the NIST time servers like in the code below.

Code: [Select]
#include <ESP8266WiFi.h>

// const char* host = "utcnist2.colorado.edu";
const char* host = "128.138.141.172";
String TimeDate = "";

void setup()
{
  Particle.begin();
  Particle.println("time test sketch");
}

void loop()
{
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 13;

  if (!client.connect(host, httpPort)) {
    Particle.println("connection failed");
    return;
  }

  // This will send the request to the server
  client.print("HEAD / HTTP/1.1\r\nAccept: */*\r\nUser-Agent: Mozilla/4.0 (compatible; ESP8266 Arduino Oak;)\r\n\r\n");

  delay(100);

  // Read all the lines of the reply from server and print them to Serial
  // expected line is like : Date: Thu, 01 Jan 2015 22:00:14 GMT
  char buffer[12];
  String dateTime = "";

  while (client.available())
  {
    String line = client.readStringUntil('\r');

    if (line.indexOf("Date") != -1)
    {
      Particle.print("=====>");
    }
    else
    {
      //Particle.print(line);

      TimeDate = line.substring(7);
      //Particle.println(TimeDate);

      // date starts at pos 7
      TimeDate = line.substring(7, 15);
      TimeDate.toCharArray(buffer, 10);
      Particle.print("UTC Date/Time: ");
      Particle.print(buffer);

      // time starts at pos 14
      TimeDate = line.substring(16, 24);
      TimeDate.toCharArray(buffer, 10);
      Particle.print(" ");
      Particle.println(buffer);
    }
  }

  delay(10000);

}

With a few modifications to the TimeNTP_ESP8266Wifi examples that come with the Time library, it is also possible to get the time via NTP, and in an easier to manipulate form.

Code: [Select]
/*
 * Time_NTP.pde
 * Example showing time sync to NTP time source
 *
 * This sketch uses the ESP8266WiFi library
 */
 
#include <TimeLib.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

const char ssid[] = "*************";  //  your network SSID (name)
const char pass[] = "********";       // your network password

// NTP Servers:
IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov
// IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov
// IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov


const int timeZone = 1;     // Central European Time
//const int timeZone = -5;  // Eastern Standard Time (USA)
//const int timeZone = -4;  // Eastern Daylight Time (USA)
//const int timeZone = -8;  // Pacific Standard Time (USA)
//const int timeZone = -7;  // Pacific Daylight Time (USA)


WiFiUDP Udp;
unsigned int localPort = 8888;  // local port to listen for UDP packets

void setup()
{
  Particle.begin();
//  while (!Serial) ; // Needed for Leonardo only
  delay(250);
  Particle.println("TimeNTP Example");
//  Particle.print("Connecting to ");
//  Serial.println(ssid);
//  WiFi.begin(ssid, pass);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
//    Serial.print(".");
  }

 
//  Serial.print("IP number assigned by DHCP is ");
//  Serial.println(WiFi.localIP());
//  Serial.println("Starting UDP");
  Udp.begin(localPort);
//  Serial.print("Local port: ");
//  Serial.println(Udp.localPort());
  Particle.println("waiting for sync");
  setSyncProvider(getNtpTime);
}

time_t prevDisplay = 0; // when the digital clock was displayed

void loop()

  if (timeStatus() != timeNotSet) {
    if (now() != prevDisplay) { //update the display only if time has changed
      prevDisplay = now();
      digitalClockDisplay(); 
    }
  }
}

void digitalClockDisplay(){
  // digital clock display of the time
  Particle.print(hour());
  printDigits(minute());
  printDigits(second());
  Particle.print(" ");
  Particle.print(day());
  Particle.print(".");
  Particle.print(month());
  Particle.print(".");
  Particle.print(year());
  Particle.println();
}



void printDigits(int digits){
  // utility for digital clock display: prints preceding colon and leading 0
  Particle.print(":");
  if(digits < 10)
    Particle.print('0');
  Particle.print(digits);
}

/*-------- NTP code ----------*/

const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets

time_t getNtpTime()
{
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  Particle.println("Transmit NTP Request");
  sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      Particle.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR;
    }
  }
  Particle.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}

// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
  // set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  // Initialize values needed to form NTP request
  // (see URL above for details on the packets)
  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); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
}

brohan

  • Jr. Member
  • **
  • Posts: 59
Re: Can oak get time from the cloud?
« Reply #4 on: July 29, 2016, 10:03:12 pm »
I know that personally, I can't get the time from the cloud, but I can when the sun is shining. Perhaps the Oak can get the time if it's taller than the cloud?

PeterF

  • Hero Member
  • *****
  • Posts: 877
Re: Can oak get time from the cloud?
« Reply #5 on: July 29, 2016, 11:54:20 pm »
Oh... you're a tough nut to crack aren't you! :D :D

brohan

  • Jr. Member
  • **
  • Posts: 59
Re: Can oak get time from the cloud?
« Reply #6 on: July 30, 2016, 08:37:20 am »
No, but an Oak is.  8)

emardee

  • Full Member
  • ***
  • Posts: 135
Re: Can oak get time from the cloud?
« Reply #7 on: July 30, 2016, 06:37:59 pm »
Oh... you're a tough nut to crack aren't you! :D :D
No, but an Oak is.  8)

I think you are confusing and an Oak and an Acorn! (Acorns don't have the voltage regulator onboard)

PeterF

  • Hero Member
  • *****
  • Posts: 877
Re: Can oak get time from the cloud?
« Reply #8 on: July 30, 2016, 07:01:51 pm »
lol... I couldn't come up with anything wittier at the time, so hoped no one would notice!  :o Ruin my fun why don't you... !!!  :'( :'(

So... which came first... the acorn or the oak?  ;D ;D ;D

brohan

  • Jr. Member
  • **
  • Posts: 59
Re: Can oak get time from the cloud?
« Reply #9 on: July 30, 2016, 10:17:14 pm »
Sorry mab299108, we now return you to your regularly scheduled q & a.

mab299108

  • Newbie
  • *
  • Posts: 6
Re: Can oak get time from the cloud?
« Reply #10 on: August 23, 2016, 09:17:15 am »
Thanks PeterF. Your sample of pulling the data direct from the NIST server is a big help. Works like a charm and I was able to upload and test the first sample in a matter of seconds.

crambo

  • Jr. Member
  • **
  • Posts: 52
Re: Can oak get time from the cloud?
« Reply #11 on: November 24, 2016, 09:37:37 am »
Hi All,

I love the humor here, but I have an issue when using the above sample NTP code. It works beautifully for a couple of hours and then the Oak seems to freeze up and become unresponsive until reboot. I am running some simple code for a few hours to see if it might be a hardware issue, but if not I am wondering if there might be some kind of memory leak.

Anyone running NTP on an Oak successfully? Just curious if it might be a bigger issue.

(Thank some higher being for these forums!)

-Cam

crambo

  • Jr. Member
  • **
  • Posts: 52
Re: Can oak get time from the cloud?
« Reply #12 on: November 24, 2016, 09:46:48 am »
Huh. Well it already crashed running a simple pixel test. Might be a hardware thing.

Will post here with update.


crambo

  • Jr. Member
  • **
  • Posts: 52
Re: Can oak get time from the cloud?
« Reply #13 on: November 24, 2016, 12:05:37 pm »
Ok, so running a simple neopixel test crashes both oaks I have. How would I begin troubleshooting such a thing? Could it be the neopixels I am using? I will get some more and work that angle as well....


Here is the code that crashes the neopixel:

#include <Adafruit_NeoPixel_Oak.h>

#define PIN      1
#define N_LEDS 21

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_LEDS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();
}

void loop() {
  chaseup(strip.Color(255, 0, 0)); // Red
  chasedown(strip.Color(255, 0, 0)); // Red
  chaseup(strip.Color(0, 255, 0)); // Green
  chasedown(strip.Color(0, 255, 0)); // Green
  chaseup(strip.Color(0, 0, 255)); // Blue
  chasedown(strip.Color(0, 0, 255)); // Blue
}

static void chaseup(uint32_t c) {
  for (uint16_t i = 0; i < strip.numPixels() + 4; i++) {
    strip.setPixelColor(i  , c); // Draw new pixel
    strip.setPixelColor(i - 4, 0); // Erase pixel a few steps back
    strip.show();
    delay(5);
  }
}
static void chasedown(uint32_t c) {
  for (uint16_t i = strip.numPixels(); i > 0 + 4; i--) {
    strip.setPixelColor(i  , c); // Draw new pixel
    strip.setPixelColor(i + 4, 0); // Erase pixel a few steps back
    strip.show();
    delay(5);
  }
}

emardee

  • Full Member
  • ***
  • Posts: 135
Re: Can oak get time from the cloud?
« Reply #14 on: November 24, 2016, 01:01:19 pm »
I'd flick a few "yield()" commands in there, to see if it solves the crashing.

I'd personally start with too many and then see which I could remove later... so would put a "yield ()" before each "delay (5)". Note this might cause glitches in the animation, but at the moment we are troubleshooting to see if that is the problem or not, so that is acceptable for now.... clearly once diagnosed you might want to improve that later.

As I understanding it, yield lets the particle cloud stuff do its thing, but if there are no gaps, then the particle communication code seems to get to a point where it crashes. That was my experience with longer animations, or longer pixel strings. This is based on observation and reading these forums, rather than knowledge of how Oak actually works (especially with regard to the Particle "magic")... so what I think I've observed and what is really happening, might not be the same at all!