| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- #include <Lixie_II.h> // https://github.com/connornishijima/Lixie_II
- #include <ESP8266WiFi.h> // https://github.com/esp8266/Arduino
- #include <DNSServer.h> // |
- #include <ESP8266WebServer.h> // |
- #include <WiFiUdp.h> // |
- #include <FS.h> // <
- #include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
- #include <NTPClient.h> // https://github.com/arduino-libraries/NTPClient
- #include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson
- /*
- * Lixie II NTP Clock Example for ESP8266
- * by Connor Nishijima (November 2nd, 2019)
- *
- * This example relies on an ESP8266/ESP32 controller,
- * which is used to pull UTC time from an NTP server over WiFi.
- *
- * It requires two external buttons to fully function: (defined as HUE_BUTTON and HOUR_BUTTON below)
- * one for changing color/modes, and one for setting the UTC offset (timezone)
- *
- * Upon booting, it will failt to connect to WiFi as it doesn't yet know your
- * credentials. It will then host it's own WiFi access point named "LIXIE CONFIG"
- * that you can connect your phone to.
- *
- * Once connected, go to http://192.168.4.1 in your phone's browser, and you
- * will see a menu that will let you send the WiFi details down to the clock,
- * to be remembered from this point forward. (Even through power cycles!)
- *
- * A short tap of the HUE button will change color modes, and holding it down will
- * start to cycle the displays through the color wheel. Release the HUE button
- * when it gets to a color you like.
- *
- * A short tap of the HOUR button will increase the UTC offset by 1, (wrapping back
- * to -12 after +12) and a long tap toggles between 12 and 24-hour mode.
- *
- * Holding the HOUR button down during power up will let you access the WiFi
- * configuration page again.
- *
- * MAKE SURE SPIFFS IS ENABLED in Tools > Flash Size
- *
- * Enjoy!
- */
- // USER SETTINGS //////////////////////////////////////////////////////////////////
- #define DATA_PIN D7 // Lixie DIN connects to this pin
- #define NUM_DIGITS 4
- #define SIX_DIGIT_CLOCK false // 6 or 4-digit clock? (6 has seconds shown)
- #define HOUR_BUTTON D1 // These are pulled up internally, and should be
- #define HUE_BUTTON D3 // tied to GND through momentary switches
- ///////////////////////////////////////////////////////////////////////////////////
- Lixie_II lix(DATA_PIN, NUM_DIGITS);
- WiFiUDP ntp_UDP;
- NTPClient time_client(ntp_UDP, "pool.ntp.org", 3600, 60000);
- #define SECONDS_PER_HOUR 3600
- int16_t time_zone_shift = 0;
- uint8_t hour_12_mode = false;
- bool time_found = false;
- uint32_t settings_last_update = 0;
- bool settings_changed = false;
- const char* settings_file = "/settings.json";
- uint32_t t_now = 0;
- uint8_t last_seconds = 0;
- #define STABLE 0
- #define RISE 1
- #define FALL 2
- bool hour_button_state = HIGH;
- bool hue_button_state = HIGH;
- bool hour_button_state_last = HIGH;
- bool hue_button_state_last = HIGH;
- uint8_t hour_button_edge = STABLE;
- uint8_t hue_button_edge = STABLE;
- uint32_t hour_button_last_hit = 0;
- uint32_t hue_button_last_hit = 0;
- uint32_t hour_button_start = 0;
- uint16_t hour_button_wait = 1000;
- bool hour_mode_started = false;
- uint32_t hue_button_start = 0;
- uint8_t button_debounce_ms = 100;
- uint8_t base_hue = 0;
- uint16_t hue_countdown = 255;
- uint16_t hue_push_wait = 500;
- uint8_t current_mode = 0;
- #define NUM_MODES 7
- #define MODE_SOLID 0
- #define MODE_GRADIENT 1
- #define MODE_DUAL 2
- #define MODE_NIXIE 3
- #define MODE_INCANDESCENT 4
- #define MODE_VFD 5
- #define MODE_WHITE 6
- void setup() {
- Serial.begin(115200);
- init_fs();
- load_settings();
- init_displays();
- init_buttons();
- init_wifi();
- init_ntp();
- }
- void loop() {
- run_clock();
- yield();
- }
- void run_clock() {
- t_now = millis();
- time_client.update();
- if (time_client.getSeconds() != last_seconds) {
- show_time();
- }
- if (t_now % 20 == 0) { // 50 FPS
- color_for_mode();
- check_buttons();
- lix.run();
- }
- if (t_now - settings_last_update > 5000 && settings_changed == true) {
- settings_changed = false;
- save_settings();
- }
- }
- void save_settings() {
- StaticJsonBuffer<200> jsonBuffer;
- JsonObject& root = jsonBuffer.createObject();
- root["base_hue"] = base_hue;
- root["mode"] = current_mode;
- root["offset"] = time_zone_shift;
- root["hour_mode"] = hour_12_mode;
-
- String settings;
- root.printTo(settings);
- Serial.println(settings);
- File f = SPIFFS.open(settings_file, "w+");
- if (!f) {
- Serial.println("settings file open failed");
- }
- else {
- //Write data to file
- f.print(settings);
- f.close(); //Close file
- }
- }
- void load_settings() {
- String input = "";
- //Read File data
- File f = SPIFFS.open(settings_file, "r");
- if (!f) {
- Serial.println("settings file open failed");
- }
- else {
- for (uint16_t i = 0; i < f.size(); i++) {
- input += (char)f.read();
- }
- f.close(); //Close file
- }
- StaticJsonBuffer<200> jsonBuffer;
- JsonObject& root = jsonBuffer.parseObject(input);
- base_hue = root["base_hue"];
- current_mode = root["mode"];
- time_zone_shift = root["offset"];
- hour_12_mode = root["hour_mode"];
- }
- void show_time() {
- uint8_t hh = time_client.getHours();
- uint8_t mm = time_client.getMinutes();
- uint8_t ss = time_client.getSeconds();
- if (hour_12_mode == true) {
- if (hh > 12) {
- hh -= 12;
- }
- if (hh == 0) {
- hh = 12;
- }
- }
- uint32_t t_lixie = 1000000; // "1000000" is used to get zero-padding on hours digits
- // This turns a time of 22:34:57 into the integer (1)223457, whose leftmost numeral will not be shown
- t_lixie += (hh * 10000);
- t_lixie += (mm * 100);
- t_lixie += ss;
- if (!SIX_DIGIT_CLOCK) {
- t_lixie /= 100; // Eliminate second places
- }
- lix.write(t_lixie);
- if (!time_found) {
- time_found = true;
- lix.fade_in();
- }
- Serial.println(t_lixie);
- last_seconds = ss;
- }
- void color_for_mode() {
- uint8_t temp_hue = base_hue + hue_countdown;
- if (current_mode == MODE_SOLID) {
- lix.color_all(ON, CHSV(temp_hue, 255, 255));
- lix.color_all(OFF, CRGB(0, 0, 0));
- }
- else if (current_mode == MODE_GRADIENT) {
- lix.gradient_rgb(ON, CHSV(temp_hue, 255, 255), CHSV(temp_hue + 90, 255, 255));
- lix.color_all(OFF, CRGB(0, 0, 0));
- }
- else if (current_mode == MODE_DUAL) {
- lix.color_all_dual(ON, CHSV(temp_hue, 255, 255), CHSV(temp_hue + 90, 255, 255));
- lix.color_all(OFF, CRGB(0, 0, 0));
- }
- else if (current_mode == MODE_NIXIE) {
- lix.color_all(ON, CRGB(255, 70, 7));
- CRGB col_off = CRGB(0, 100, 255);
- const uint8_t nixie_aura_level = 8;
- col_off.r *= (nixie_aura_level / 255.0);
- col_off.g *= (nixie_aura_level / 255.0);
- col_off.b *= (nixie_aura_level / 255.0);
- lix.color_all(OFF, col_off);
- }
- else if (current_mode == MODE_INCANDESCENT) {
- lix.color_all(ON, CRGB(255, 100, 25));
- lix.color_all(OFF, CRGB(0, 0, 0));
- }
- else if (current_mode == MODE_VFD) {
- lix.color_all(ON, CRGB(100, 255, 100));
- lix.color_all(OFF, CRGB(0, 0, 0));
- }
- else if (current_mode == MODE_WHITE) {
- lix.color_all(ON, CRGB(255, 255, 255));
- }
- }
- void check_buttons() {
- hour_button_state = digitalRead(HOUR_BUTTON);
- hue_button_state = digitalRead(HUE_BUTTON);
- if (hour_button_state > hour_button_state_last) {
- hour_button_edge = RISE;
- }
- else if (hour_button_state < hour_button_state_last) {
- if (t_now - hour_button_last_hit >= button_debounce_ms) {
- hour_button_last_hit = t_now;
- hour_button_edge = FALL;
- }
- }
- else {
- hour_button_edge = STABLE;
- }
- if (hue_button_state > hue_button_state_last) {
- hue_button_edge = RISE;
- }
- else if (hue_button_state < hue_button_state_last) {
- if (t_now - hue_button_last_hit >= button_debounce_ms) {
- hue_button_last_hit = t_now;
- hue_button_edge = FALL;
- }
- }
- else {
- hue_button_edge = STABLE;
- }
- parse_buttons();
- hour_button_state_last = hour_button_state;
- hue_button_state_last = hue_button_state;
- }
- void parse_buttons() {
- if (hour_button_edge == FALL) { // PRESS STARTED
- hour_button_start = t_now;
- }
- else if (hour_button_edge == RISE) { // PRESS ENDED
- uint16_t hour_button_duration = t_now - hour_button_start;
- if (hour_button_duration < hour_button_wait) { // RELEASED QUICKLY
- Serial.println("UP");
- time_zone_shift += 1;
- if(time_zone_shift >= 12){
- time_zone_shift = -12;
- }
-
- time_client.setTimeOffset(time_zone_shift * SECONDS_PER_HOUR);
- show_time();
- update_settings();
- }
- else { // RELEASED AFTER LONG PRESS
- hour_mode_started = false;
- }
- }
- if (hue_button_edge == FALL) { // PRESS STARTED
- Serial.println("HUE");
- hue_button_start = t_now;
- }
- else if (hue_button_edge == RISE) { // PRESS ENDED
- uint16_t hue_button_duration = t_now - hue_button_start;
- if (hue_button_duration < hue_push_wait) { // RELEASED QUICKLY
- Serial.println("NEXT MODE");
- current_mode++;
- if (current_mode >= NUM_MODES) {
- current_mode = 0;
- }
- hue_countdown = 127;
- update_settings();
- }
- }
- if (hue_button_state == LOW) { // CURRENTLY PRESSING
- uint16_t hue_button_duration = t_now - hue_button_start;
- if (hue_button_duration >= hue_push_wait) {
- base_hue++;
- Serial.print("HUE: ");
- Serial.println(base_hue);
- update_settings();
- }
- }
- if (hour_button_state == LOW) { // CURRENTLY PRESSING
- uint16_t hour_button_duration = t_now - hour_button_start;
- if (hour_button_duration >= hour_button_wait && hour_mode_started == false) {
- hour_mode_started = true;
- Serial.println("CHANGE HOUR MODE");
- hour_12_mode = !hour_12_mode;
- update_settings();
- }
- }
- if (hue_countdown < 255) {
- hue_countdown += 6;
- if (hue_countdown > 255) {
- hue_countdown = 255;
- }
- }
- }
- void update_settings() {
- settings_changed = true;
- settings_last_update = t_now;
- }
- void init_wifi() {
- WiFiManager wifiManager;
- if (digitalRead(HOUR_BUTTON) == LOW) {
- wifiManager.resetSettings();
- lix.write(808080);
- lix.color_all(ON, CRGB(64,0,255));
- }
- wifiManager.autoConnect("LIXIE CONFIG");
- lix.sweep_color(CRGB(0, 255, 127), 20, 3, false);
- lix.clear(); // Removes "8"s before fading in the time
- color_for_mode();
- }
- void init_ntp() {
- time_client.begin();
- time_client.setTimeOffset(time_zone_shift * SECONDS_PER_HOUR);
- }
- void init_fs() {
- Serial.print("SPIFFS Initialize....");
- if (SPIFFS.begin()) {
- Serial.println("ok");
- }
- else {
- Serial.println("failed");
- }
- }
- void init_buttons() {
- pinMode(HOUR_BUTTON, INPUT_PULLUP);
- pinMode(HUE_BUTTON, INPUT_PULLUP);
- }
- void init_displays() {
- lix.begin();
- lix.max_power(5, 1000);
- lix.write(888888);
- }
|