-->
Page 1 of 3

The Light Clock

PostPosted: Thu Oct 08, 2015 4:11 am
by Chris Carter
Hey guys,

I've been working on an ESP8266 based project for kickstarter for the past few months. I thought some people might want the code. I've mostly expanded on what others have done, but there are some nice menus etc that people could want?

Key codes you might want:

Open WiFi hotspot to connect and enter local wifi network details
MDNS network location (iOS/OSX)
SSDP network location (Windows)
Access NTS time server
Update automatically from DST server (removed from live code-base)
Drive WS8212B LEDs
Multiple Menus with lots of settings processing.

https://github.com/chrismelba/thelightclockwifi

You can see the pitch for the finished product at http://www.thelightclock.com/explained

We're aiming to be on Kickstarter on the 2nd of Nov, or if you want to build your own I'm developing an instructable.

Thanks so much to the community for helping me get this far :)

Image

Re: The Light Clock

PostPosted: Fri Oct 09, 2015 5:22 am
by schufti
did something similar with arduino mini pro (one button to control all features) and swithed over to ESP8266 for full WiFi controll (button as fallback if no WiFi).

see here: https://vid.me/GIWJ

Re: The Light Clock

PostPosted: Fri Dec 04, 2015 7:33 am
by ger
I am curious about the code used by Schufti

Re: The Light Clock

PostPosted: Sat Dec 05, 2015 2:54 pm
by schufti
Hi,
can't give you a more recent version (with web ui) but this should be a good start.
you have to modify the code for your WiFi. If no connection can be made manual setup ist started.
first single clicks set hour, then double click switsche to minutes in 5min steps, next doule click sets single minutes, last double click starts clock.
Single click in clock mode starts/stops rainbow mode, double click enters setup ... (as far as I remember)
Haven't checked compilability of the code for month ...

Hw is simple:
60 WS2812 powerd with 3.3V data on GPIO2
pushbutton on GPIO0 to gnd, pullup on PD



Code: Select all#include <Adafruit_NeoPixel.h>
#include <OneButton.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

#define PIN 2
#define BTN 0
#define HUE 60
#define mySSID "yourSSID"
#define myPASS "yourPASS"

unsigned long sek, ma;
unsigned int hz, mz, sz, adj = 0, cc = 0;
byte hb = 0x0F, bb = 1, wl = 0;

// setup neopixel
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);

// Setup button
OneButton button(BTN, true);

// setup WiFi
char ssid[] = mySSID;                // your network SSID (name)
char pass[] = myPASS;                // your network password
unsigned int localPort = 2390;       // local port to listen for UDP packets
IPAddress timeServer(86,59,13,46);   // at.pool.ntp.org NTP server
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
// A UDP instance to let us send and receive packets over UDP
WiFiUDP udp;

void setup() {
  // init serial
  Serial.begin(115200);
  Serial.println();
  // init Neopixels
  strip.begin();
  // strip.setBrightness(0x10);
  strip.clear();
  strip.show();

  // link the button functions to be called on a button events
  button.attachDoubleClick(dclk);
  button.attachClick(sclk);

  // init WiFi
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);
  delay(500);
  while ((WiFi.status() != WL_CONNECTED) && (cc < 15)) {
    Serial.print(WiFi.status());
    delay(500);
    ++cc;
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi connected");
    udp.begin(localPort);
    sendNTPpacket(timeServer); // send an NTP packet to a time server
    // wait to see if a reply is available
    delay(200);

    while (!udp.parsePacket()) {
      Serial.print(".");
      sendNTPpacket(timeServer); // send an NTP packet to a time server
      delay(200);
    }

    Serial.println("ntp received");
    setTimefromUdp();
    WiFi.mode(WIFI_OFF);
  }
  else {
    Serial.println("manual setup");
    WiFi.mode(WIFI_OFF);
    dclk();
  }
} //setup

void loop() {
  if (millis() % 1000 <= 10)
  { sek++;
    PrintTime();
    delay(10);
  }

  button.tick();
  delay(5);

  if (millis() % 125 > 110)
  { if (adj == 0)
    { sz = sek % 60;
      if (sz == 0)
      { mz = (sek / 60) % 60;
        hz = (sek / 720) % 60;
      }
    }
    strip.clear();
    if (adj == 5)
    {
      for (byte i = 0; i < 60; i++)
        strip.setPixelColor(i, hsi_rgb((360 / HUE) * ((i + cc) % HUE), 0.93, 0.93));
      cc = (cc + 1) % HUE;
    }
    else
    { for (byte i = 0; i < 60; i += 5)
        strip.setPixelColor(i, hb, hb, hb);
      strip.setPixelColor(hz, 0x00, 0x00, 0x1F);
      strip.setPixelColor(mz, 0x00, 0x1F, 0x00);
      strip.setPixelColor(sz, 0x1F, 0x00, 0x00);
      hb = hb + bb;
      if (hb >= 0x17 || hb <= 0x5) bb = bb * -1;
    }
    strip.show();
    delay(10);
  }

  if ((sek % 14400) == 14370 && wl == 0)
  { WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, pass);
    wl = 1;
    Serial.println("WiFi_started");
  }

  if (wl == 1 && WiFi.status() == WL_CONNECTED)
  { udp.begin(localPort);
    sendNTPpacket(timeServer);
    wl = 2;
    Serial.println("ntp_request");
  }

  if (wl == 2 && udp.parsePacket())
  { setTimefromUdp();
    WiFi.mode(WIFI_OFF);
    wl = 0;
    Serial.println("ntp_received");
  }

  if ((sek % 14400) == 14390 && wl > 0)
  { WiFi.mode(WIFI_OFF);
    wl = 0;
    Serial.println("wlan_stopped");
  }


} //loop

unsigned long hsi_rgb(float H, float S, float I) {
  unsigned int r, g, b;
  //  H = fmod(H,360); // cycle H around to 0-360 degrees
  H = 3.14159 * H / (float)180; // Convert to radians.
  S = S > 0 ? (S < 1 ? S : 1) : 0; // clamp S and I to interval [0,1]
  I = I > 0 ? (I < 1 ? I : 1) : 0;

  // Math! Thanks in part to Kyle Miller.
  if (H < 2.09439) {
    r = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
    g = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
    b = 255 * I / 3 * (1 - S);
  } else if (H < 4.188787) {
    H = H - 2.09439;
    g = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
    b = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
    r = 255 * I / 3 * (1 - S);
  } else {
    H = H - 4.188787;
    b = 255 * I / 3 * (1 + S * cos(H) / cos(1.047196667 - H));
    r = 255 * I / 3 * (1 + S * (1 - cos(H) / cos(1.047196667 - H)));
    g = 255 * I / 3 * (1 - S);
  }
  return (long(r) << 16) | (g << 8) | (b & 0xFF);
} //hsi_rgb


void dclk() {
  Serial.print("dbl_click ");
  Serial.println(adj);
  switch (++adj) {
    case 1: {
        strip.clear();
        sz = -1; mz = -1; hz = 0; sek = 0lu;
        strip.setPixelColor(hz, 0x00, 0x00, 0x1F);
        break;
      }
    case 2: {
        mz = 0;
        strip.setPixelColor(mz, 0x00, 0x1F, 0x00);
        break;
      }
    case 3: {
        strip.setPixelColor(mz, 0x00, 0x1F, 0x00);
        break;
      }
    case 4: {
        sek = (hz * 720) + (mz * 60);
      }
    default: {
        mz = (sek / 60) % 60;
        hz = (sek / 720) % 60;
        strip.setBrightness(0xFF);
        strip.clear();
        adj = 0;
      }
  }
} //dblclick

void sclk() {
  Serial.print("sgl_click ");
  Serial.println(adj);
  switch (adj) {
    case 0: {
        strip.setBrightness(0x10);
        adj = 5;
        cc = 0;
        break;
      }
    case 1: {
        strip.setPixelColor(hz, 0, 0, 0);
        hz = (hz + 5) % 60;
        strip.setPixelColor(hz, 0, 0, 0x1F);
        break;
      }
    case 2: {
        strip.setPixelColor(mz, 0, 0, 0);
        mz = (mz + 5) % 60;
        strip.setPixelColor(mz, 0, 0x1F, 0);
        break;
      }
    case 3: {
        strip.setPixelColor(mz, 0, 0, 0);
        mz = (mz + 1) % 60;
        strip.setPixelColor(mz, 0, 0x1F, 0);
        break;
      }
    case 5: {
        WiFi.mode(WIFI_STA);
        WiFi.begin(ssid, pass);
        strip.setBrightness(0xFF);
        wl = 1; adj = 0;
        Serial.println("wlan_started");
        break;
      }
    default:
      ;
  }
} //click

// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(IPAddress& 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); //NTP requests are to port 123
  udp.write(packetBuffer, NTP_PACKET_SIZE);
  udp.endPacket();
} //sendNTPpacket

void setTimefromUdp() {
  // We've received a packet, read the data from it
  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 = word(packetBuffer[40], packetBuffer[41]);
  unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  // combine the four bytes (two words) into a long integer
  // this is NTP time (seconds since Jan 1 1900):
  unsigned long secsSince1900 = highWord << 16 | lowWord;
  // now convert NTP time into UTC+2 time:
  unsigned long utc = (secsSince1900 % 86400L) + 7201L;
  if (utc != sek) {
    sek = utc;
    hz = (sek / 720) % 60;
    mz = (sek / 60) % 60;
    sz = (sek % 60);
    Serial.println("time_adjust");
    PrintTime();
  }
} // set TimefromUdp

void PrintTime() {
  Serial.print(millis()); Serial.print("ms\t");
  Serial.print(sek); Serial.print("s\ttime is:  ");
  Serial.print(int(hz/5)); Serial.print(":");
  Serial.print(mz); Serial.print(":");
  Serial.print(sz);Serial.print(" \t");
  Serial.println(adj);
}