Skip to content

Instantly share code, notes, and snippets.

@ddrager
Created April 18, 2019 01:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ddrager/fecb65d2999cc197801292699a993696 to your computer and use it in GitHub Desktop.
Save ddrager/fecb65d2999cc197801292699a993696 to your computer and use it in GitHub Desktop.
Wired up a neopixel "ring" LED light to a esp8266 with oled readout. This code grabs data from my local HomeAssistant server, and displays it on the oled display, as well as changing the ring's color depending on home energy usage. It was a cool little project to hack together!
// ring_power_display.ino
//
// Libraries needed:
// Time.h & TimeLib.h: https://github.com/PaulStoffregen/Time
// Timezone.h: https://github.com/JChristensen/Timezone
// SSD1306.h & SSD1306Wire.h: https://github.com/squix78/esp8266-oled-ssd1306
// NTPClient.h: https://github.com/arduino-libraries/NTPClient
// ESP8266WiFi.h & WifiUDP.h: https://github.com/ekstrand/ESP8266wifi
//
// 128x64 OLED pinout:
// GND goes to ground
// Vin goes to 3.3V
// Data to I2C SDA (GPIO 0)
// Clk to I2C SCL (GPIO 2)
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <SSD1306.h>
#include <SSD1306Wire.h>
#include <NTPClient.h>
#include <Time.h>
#include <TimeLib.h>
#include <Timezone.h>
#include <ArduinoJson.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 15
Adafruit_NeoPixel strip = Adafruit_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800);
// Define NTP properties
#define NTP_OFFSET 60 * 60 // In seconds
#define NTP_INTERVAL 300 * 1000 // In miliseconds
#define NTP_ADDRESS "pool.ntp.org" // change this to whatever pool is closest (see ntp.org)
// Set up the NTP UDP client
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, NTP_ADDRESS, NTP_OFFSET, NTP_INTERVAL);
// Create a display objectpool.ntp.org
// SSD1306 display(0x3d, 0, 2); //0x3d for the Adafruit 1.3" OLED, 0x3C being the usual address of the OLED
#define DISPLAY_HEIGHT 32
#define DISPLAY_WIDTH 128
SSD1306 display(0x3c, SDA, SCL, OLED_RST, GEOMETRY_128_32);
const char* ssid = ""; // insert your own ssid
const char* password = ""; // and password
String date;
String t;
const char * days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"} ;
const char * months[] = {"Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"} ;
const char * ampm[] = {"AM", "PM"} ;
const char* host = "";
const int httpsPort = 8124;
String url = "/influx/query?db=home_assistant&q=SELECT%20last(%22value%22)%20FROM%20%22W%22%20WHERE%20(%22entity_id%22%20%3D~%20%2Faeotec_dsb09104_home_energy_meter_power_*%2F)%20AND%20time%20%3E%3D%20now()%20-%201h&epoch=ms";
// Use web browser to view and copy
// SHA1 fingerprint of the certificate
const char* fingerprint = "9E 57 66 08 CB 8D 61 1C D4 90 C5 2E 74 1B 61 BB 87 BD EA 91";
void setup ()
{
Serial.begin(115200); // most ESP-01's use 115200 but this could vary
timeClient.begin(); // Start the NTP UDP client
// reset leds
strip.begin();
strip.show(); // Initialize all pixels to 'off'
// reset oled
display.init();
display.flipScreenVertically();
// Connect to wifi
Serial.println("");
Serial.print("Connecting to ");
Serial.print(ssid);
display.drawString(0, 10, "Connecting to Wifi...");
display.display();
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi at ");
Serial.print(WiFi.localIP());
Serial.println("");
display.drawString(0, 24, "Connected.");
display.display();
delay(1000);
}
void loop()
{
if (WiFi.status() == WL_CONNECTED) //Check WiFi connection status
{
date = ""; // clear the variables
t = "";
// update the NTP client and get the UNIX UTC timestamp
timeClient.update();
unsigned long epochTime = timeClient.getEpochTime();
// convert received time stamp to time_t object
time_t local, utc;
utc = epochTime;
// Then convert the UTC UNIX timestamp to local time
TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -300}; //UTC - 5 hours - change this as needed
TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -360}; //UTC - 6 hours - change this as needed
Timezone usEastern(usEDT, usEST);
local = usEastern.toLocal(utc);
// now format the Time variables into strings with proper names for month, day etc
date += days[weekday(local)-1];
date += ", ";
date += months[month(local)-1];
date += " ";
date += day(local);
date += ", ";
date += year(local);
// format the time to 12-hour format with AM/PM and no seconds
t += hourFormat12(local);
t += ":";
if(minute(local) < 10) // add a zero if minute is under 10
t += "0";
t += minute(local);
t += " ";
t += ampm[isPM(local)];
// Display the date and time
Serial.println("");
Serial.print("Local date: ");
Serial.print(date);
Serial.println("");
Serial.print("Local time: ");
Serial.print(t);
// print the date and time on the OLED
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setFont(ArialMT_Plain_16);
display.drawStringMaxWidth(64, 0, 128, t);
display.setFont(ArialMT_Plain_10);
display.drawStringMaxWidth(64, 20, 128, date);
display.display();
delay(5000);
WiFiClientSecure client;
if (!client.connect(host, httpsPort)) {
Serial.println("connection failed");
}
if (client.verify(fingerprint, host)) {
Serial.println("certificate matches");
} else {
Serial.println("certificate doesn't match");
}
Serial.print(F("Requesting URL: "));
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
delay(10);
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
Serial.println("headers received");
break;
}
}
String something = client.readStringUntil('\n');
String json_raw = client.readStringUntil('\n');
int json_len = json_raw.length()+1;
char json[json_len];
json_raw.toCharArray(json, json_len);
const size_t bufferSize = 3*JSON_ARRAY_SIZE(1) + 2*JSON_ARRAY_SIZE(2) + JSON_OBJECT_SIZE(1) + JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(3) + 100;
DynamicJsonBuffer jsonBuffer(bufferSize);
JsonObject& root = jsonBuffer.parseObject(json);
int results0_statement_id = root["results"][0]["statement_id"]; // 0
JsonObject& results0_series0 = root["results"][0]["series"][0];
const char* results0_series0_name = results0_series0["name"]; // "W"
const char* results0_series0_columns0 = results0_series0["columns"][0]; // "time"
const char* results0_series0_columns1 = results0_series0["columns"][1]; // "last"
int results0_series0_values00 = int(results0_series0["values"][0][0]); // 1543458088845
float results0_series0_values01 = results0_series0["values"][0][1]; // 1625.91
int watts;
watts = (int)results0_series0_values01;
// convert char for display with unit
char eusage[8];
sprintf(eusage,"%i W",watts);
display.clear();
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.setFont(ArialMT_Plain_24); // 24, 18, 10
display.drawStringMaxWidth(64, 6, 128, eusage);
//display.setFont(ArialMT_Plain_10);
//display.drawStringMaxWidth(64, 20, 128, "Watts");
display.display();
//Serial.println(results0_series0_values00);
// set LED based on current energy usage
if (watts < 600) {
colorFade(0, 10, 0, 50); // Green 10 total
} else if (watts < 800) {
colorFade(5, 10, 0, 50); // Yellow 15 total
} else if (watts < 1000) {
colorFade(15, 15, 0, 50); // Yellow 30 total
} else if (watts < 1200) {
colorFade(20, 25, 0, 50); // Yellow 45 total
} else if (watts < 1500) {
colorFade(25, 20, 0, 50); // Yellow 45 total
} else if (watts < 2000) {
colorFade(30, 15, 0, 50); // Yellow 50 total
} else {
colorFade(50, 0, 0, 50); // Red 50 total
}
delay(5000);
}
else // attempt to connect to wifi again if disconnected
{
display.clear();
display.drawString(0, 2, "Connecting to Wifi...");
display.display();
WiFi.begin(ssid, password);
display.drawString(0, 12, "Connected.");
display.display();
delay(1000);
}
//delay(5000); //Send a request to update every 10 sec (= 10,000 ms)
}
void colorFade(uint8_t r, uint8_t g, uint8_t b, uint8_t wait) {
for(uint16_t i = 0; i < strip.numPixels(); i++) {
uint8_t curr_r, curr_g, curr_b;
uint32_t curr_col = strip.getPixelColor(i); // get the current colour
curr_b = curr_col & 0xFF; curr_g = (curr_col >> 8) & 0xFF; curr_r = (curr_col >> 16) & 0xFF; // separate into RGB components
while ((curr_r != r) || (curr_g != g) || (curr_b != b)){ // while the curr color is not yet the target color
if (curr_r < r) curr_r++; else if (curr_r > r) curr_r--; // increment or decrement the old color values
if (curr_g < g) curr_g++; else if (curr_g > g) curr_g--;
if (curr_b < b) curr_b++; else if (curr_b > b) curr_b--;
strip.setPixelColor(i, curr_r, curr_g, curr_b); // set the color
strip.show();
//delay(wait); // add a delay if its too fast
}
delay(50);
}
}
// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment