#include <Adafruit_NeoPixel.h>
#include <RTClib.h>
#include <DHT.h>
#include <Bounce2.h>
#include <elapsedMillis.h>
#define LED_PIN 6
#define LED_COUNT 58
#define BUTTON_PIN 3
RTC_DS1307 rtc;
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
Bounce2::Button button = Bounce2::Button();
const uint32_t clockColor = strip.Color(0, 0, 255);
const byte symbols[14] = {
  // abcdefg
  0B01111110, // 0
  0B01000010, // 1
  0B01101101, // 2
  0B01100111, // 3
  0B01010011, // 4
  0B00110111, // 5
  0B00111111, // 6
  0B01100010, // 7
  0B01111111, // 8
  0B01110111, // 9
  0B01110001, // Deg (°)
  0B00111100, // C
  0B00011111, // b
  0B01110011  // q
};
// Display modes
// 0 - time
// 1 - temperature
// 2 - relative humidity
// 3 - cycle between modes
uint8_t displayMode = 0;
uint8_t cycleMode = 0;
elapsedMillis cycleTimer;
void setup() {
  Serial.begin(9600);
  dht.begin();
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }
  strip.begin();
  strip.show();
  button.attach(BUTTON_PIN, INPUT_PULLUP);
  button.interval(10);
  button.setPressedState(LOW);
}
void loop() {
  button.update();
  if (button.pressed()) {
    displayMode = ++displayMode & 3;
    if (displayMode == 3) {
      cycleMode = 0;
      cycleTimer = 0;
    }
  }
  readDHT();
  switch (displayMode) {
    case 0:
      displayTime();
      break;
    case 1:
      displayTemperature();
      break;
    case 2:
      displayHumidity();
      break;
    case 3:
      cycleModes();
      break;
  }
  delay(400);
}
void displaySymbol(uint8_t digit, uint8_t value) {
  byte symbol = symbols[value];
  uint8_t skip = digit >= 2 ? 2 : 0;
  uint32_t color;
  uint8_t start = (14 * digit) + skip;
  for (uint8_t i = 0; i < 7; i++) {
    if ((symbol >> i) & 1) {
      strip.setPixelColor(start, clockColor);
      strip.setPixelColor(start + 1, clockColor);
    }
    start += 2;
  }
}
void displayTime() {
  DateTime now = rtc.now();
  strip.clear();
  displaySymbol(0, now.hour() / 10);
  displaySymbol(1, now.hour() % 10);
  displaySymbol(2, now.minute() / 10);
  displaySymbol(3, now.minute() % 10);
  displayColon(~now.second() & 1);
  strip.show();
}
void displayColon(bool state) {
  uint32_t color = state ? clockColor : 0;
  strip.setPixelColor(28, color);
  strip.setPixelColor(29, color);
}
void cycleModes() {
  switch (cycleMode) {
    case 0:
      displayTime();
      break;
    case 1:
      displayTemperature();
      break;
    case 2:
      displayHumidity();
      break;
  }
  if (cycleTimer > 5000) {
    cycleTimer = 0;
    cycleMode = (cycleMode + 1) % 3;
  }
}