Skip to content

Instantly share code, notes, and snippets.

@bogdanr
Last active June 5, 2017 21:39
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save bogdanr/4e94e1d66e94aafd76a395677d022015 to your computer and use it in GitHub Desktop.
Precise LED clock that can only be imprecisely read
/*
FuzzyClock is a precise LED clock that can only be imprecisely read.
Bogdan Radulescu <bogdan@nimblex.net>
License: Apache License v2
*/
#include <ESP8266WiFi.h> // This one comes with the boards manager import
#include <NTPtimeESP.h> // Get it from https://github.com/SensorsIot/NTPtimeESP
#include <Adafruit_NeoPixel.h> // Get it from https://github.com/adafruit/Adafruit_NeoPixel
#include <ArduinoJson.h> // Get it from https://github.com/bblanchon/ArduinoJson
NTPtime NTPch("ro.pool.ntp.org");
const char* ssid = "Radulescu";
const char* password = "replacewithyourown";
#define analogOutPinGREEN 12
#define analogOutPinBLUE 13
#define analogOutPinRED 15
// We use GPIO5 because GPIO0/GPIO2/GPIO15 are used to determine the boot mode that should be executed at reset. Because of this it causes all the LEDS to light up at reset.
#define LED_PIN 5
#define LED_COUNT 30
#define WU_API_KEY "replacewithyourown"
#define WU_LOCATION "Romania/Bucharest"
#define WUNDERGROUND "api.wunderground.com"
// Create an instance of the Adafruit_NeoPixel class called "leds".
Adafruit_NeoPixel leds = Adafruit_NeoPixel(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
/*
* The structure contains following fields:
* struct strDateTime--
{
byte hour;
byte minute;
byte second;
int year;
byte month;
byte day;
byte dayofWeek;
boolean valid;
};
*/
strDateTime dateTime;
int LEDhour;
int LEDpressure;
// HTTP request
const char WUNDERGROUND_REQ[] =
"GET /api/" WU_API_KEY "/conditions/q/" WU_LOCATION ".json HTTP/1.1\r\n"
"User-Agent: ESP8266/0.1\r\n"
"Accept: */*\r\n"
"Host: " WUNDERGROUND "\r\n"
"Connection: close\r\n"
"\r\n";
void setup() {
analogWrite(analogOutPinRED, 200); // Visually indicate that we started to boot.
leds.begin();
//leds.show(); // Initialize all pixels to 'off'. If we do this it would make the light turn off for a little while when it comes back from sleep so it's commented out.
Serial.begin(115200); // We initialize the serial console for debugging purposes.
Serial.println();
Serial.println("Booted");
pinMode(A0, INPUT); // From this pin we read the ambiental light.
Serial.println("Connecting to Wi-Fi");
WiFi.mode(WIFI_STA);
WiFi.begin (ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println("WiFi connected");
analogWrite(analogOutPinRED, 0);
analogWrite(analogOutPinGREEN, 200);
WUAPI(); // Here we connecto the the WU API and get the data
getShowData(); // In this function we get the NTP time and we display the stuff on the LED strip
ESP.deepSleep(60000000, WAKE_RF_DEFAULT); // We are going to seep for 60 seconds
}
// Nothing happens here because we want to sleep most of the time.
void loop() {
}
void getShowData() {
analogWrite(analogOutPinBLUE, 100);
// first parameter: Time zone in floating point (for India); second parameter: 1 for European summer time; 2 for US daylight saving time (not implemented yet)
dateTime = NTPch.getNTPtime(2.0, 0); // +2GMT without summer time.
// NTPch.printDateTime(dateTime);
byte actualHour = dateTime.hour;
byte actualMinute = dateTime.minute;
// We split the day in half to essentially 12H clock so it would be easier to read.
if (actualHour > 11)
LEDhour = map(actualHour, 12, 23, 0, 29);
else
LEDhour = map(actualHour, 0, 11, 0, 29);
int LEDminute = map(actualMinute, 0, 60, 0, 29);
int lightVal = analogRead(0) * 2; // read the input pin and make the LEDs brighter. It depends on placement and personal preference
int LEDintensity = max(lightVal, 10); // The intensity will be at least 10 so the LEDs will always be on
LEDintensity = min(LEDintensity, 255);// The maximum intensity level is 255 because these chips are 8bit
Serial.print("LEDintensity "); Serial.print(LEDintensity); Serial.print(" LightVal "); Serial.println(lightVal);
leds.setPixelColor(LEDhour, LEDintensity, 0, 0); // Red
leds.setPixelColor(LEDminute, 0, LEDintensity, 0); // Green
leds.setPixelColor(LEDpressure, 0, 0, LEDintensity); // Blue
leds.show();
// We make all leds off for the next time when we have to set them.
leds.setPixelColor(LEDhour, 0x000000);
leds.setPixelColor(LEDminute, 0x000000);
leds.setPixelColor(LEDpressure, 0x000000);
analogWrite(analogOutPinBLUE, 0);
}
bool showWeather(char *json) {
StaticJsonBuffer<3*1024> jsonBuffer;
// Skip characters until first '{' found
// Ignore chunked length, if present
char *jsonstart = strchr(json, '{');
//Serial.print(F("jsonstart ")); Serial.println(jsonstart);
if (jsonstart == NULL) {
Serial.println(F("JSON data missing"));
return false;
}
json = jsonstart;
// Parse JSON
JsonObject& root = jsonBuffer.parseObject(json);
if (!root.success()) {
Serial.println(F("jsonBuffer.parseObject() failed"));
return false;
}
// Extract weather info from parsed JSON
JsonObject& current = root["current_observation"];
const float temp_c = current["temp_c"];
Serial.print(temp_c, 1); Serial.print(F(" C, "));
const char *humi = current[F("relative_humidity")];
Serial.print(humi); Serial.println(F(" RH"));
const char *weather = current["weather"];
Serial.println(weather);
const char *pressure_mb = current["pressure_mb"];
Serial.print("Pressure "); Serial.println(pressure_mb);
const char *observation_time = current["observation_time_rfc822"];
Serial.println(observation_time);
int pressureVal = current["pressure_mb"];
pressureVal = min(pressureVal, 1030);
pressureVal = max(pressureVal, 1001);
LEDpressure = map(pressureVal, 1001, 1030, 0, 29);
Serial.print("PressureLED "); Serial.println(LEDpressure);
}
void WUAPI() {
static char respBuf[4096];
// Use WiFiClient class to create TCP connections
WiFiClient httpclient;
const int httpPort = 80;
if (!httpclient.connect(WUNDERGROUND, httpPort)) {
Serial.println(F("connection failed"));
return;
}
// This will send the http request to the server
Serial.print(WUNDERGROUND_REQ);
httpclient.print(WUNDERGROUND_REQ);
httpclient.flush();
// Collect http response headers and content from Weather Underground
// HTTP headers are discarded.
// The content is formatted in JSON and is left in respBuf.
int respLen = 0;
bool skip_headers = true;
while (httpclient.connected() || httpclient.available()) {
if (skip_headers) {
String aLine = httpclient.readStringUntil('\n');
//Serial.println(aLine);
// Blank line denotes end of headers
if (aLine.length() <= 1) {
skip_headers = false;
}
}
else {
int bytesIn;
bytesIn = httpclient.read((uint8_t *)&respBuf[respLen], sizeof(respBuf) - respLen);
Serial.print(F("bytesIn ")); Serial.println(bytesIn);
if (bytesIn > 0) {
respLen += bytesIn;
if (respLen > sizeof(respBuf)) respLen = sizeof(respBuf);
}
else if (bytesIn < 0) {
Serial.print(F("read error "));
Serial.println(bytesIn);
}
}
delay(1);
}
httpclient.stop();
if (respLen >= sizeof(respBuf)) {
Serial.print(F("respBuf overflow "));
Serial.println(respLen);
return;
}
// Terminate the C string
respBuf[respLen++] = '\0';
//Serial.print(F("respLen "));
//Serial.println(respLen);
//Serial.println(respBuf);
showWeather(respBuf);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment