// Draw humidity and temperature traces
// Full trace takes 3.5 minutes at 2 seconds per reading (fastest) with 100 readings
// Increase "timeout" to lengthen DHT history: 30 minutes trace use "timeout = 17000"

#include <DHT.h> // https://github.com/adafruit/DHT-sensor-library
#include <Adafruit_SSD1306.h> // https://github.com/adafruit/Adafruit_SSD1306
// #include "bitmap.h" // local graphic objects

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define I2C_ADDRESS 0x3C
#define DHTTYPE    DHT22 // DHT22, AM2302, AM2321
#define DHTpin        11
DHT dht(DHTpin, DHTTYPE); // create DHT object

float h, c, f;
int oldH = -1, oldC;
int traceStart = 26, traceEnd = 125, trace = traceStart; // line trace
unsigned long timer, timeout = 2000; // time between DHT reading. 17000 takes about 30 minutes

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); // create OLED object

void setup() {
  Serial.begin(115200); // initialize serial communications
  dht.begin(); // initialize DHT

  display.begin(SSD1306_SWITCHCAPVCC, I2C_ADDRESS);
  // checkOLED(); // initialize and verify OLED object
  display.clearDisplay();
  display.display();
  drawDisplay();
}

void loop() {
  if (millis() - timer > timeout) { // time between DHT reading
    timer = millis();
    h = dht.readHumidity();
    c = dht.readTemperature();
    f = dht.readTemperature(true);
    checkDHThcf();

    if (trace > traceEnd) // keep traces inside box
      trace = traceStart; // restart traces

    int hMap = map(h, 100, 0, 2, 29); // DHT humidity HI/LO range to OLED LO/HI range
    int cMap = map(c, 80, -40, 35, 61); // DHT temperature HI/LO range to OLED LO/HI range

    if (oldH != h) // erase oldH, write h
      displayHC(oldH, h, 'h');

    if (oldC != c)
      displayHC(oldC, c, 'c'); // erase oldC, write c

    display.drawLine(trace, 2, trace, 29, 0); // erase h trace
    display.drawLine(trace, 35, trace, 61, 0); // erase c trace
    display.display();

    display.drawPixel(trace, hMap, WHITE); // plot mapped h trace
    display.drawPixel(trace, cMap, WHITE); // plot mapped c trace
    display.display();

    oldH = h; // store current readings
    oldC = c;
    trace++; // move trace right
  }
}

void displayHC (int oldHC, int newHC, char hc) {
  int value; // incoming data
  int row; // OLED row for data

  if (hc == 'h')
    row = 12;
  else
    row = 45;

  for (int color = 0; color < 2; color++) {
    if (color == 0)
      value = oldHC;
    else
      value = newHC;

    display.setTextColor(color);
    display.setCursor(2, row);
    if (value >= -10 && value < 0)  display.print(F(" "));
    if (value >= 0 && value < 10)   display.print(F("  "));
    if (value >= 10 && value < 100) display.print(F(" "));
    display.print(value);
  }
}

void drawDisplay() {
  display.setTextSize(1); // smallest font
  display.setTextColor(WHITE);

  display.drawRect(0, 0, 128, 32, WHITE); // upper box
  display.drawRect(0, 33, 128, 31, WHITE); // lower box

  // int x = 26, ytop = 1, ybot = 63; // verify text alignment only
  // display.drawLine(x, ytop, x, ybot, WHITE); // right-alignment

  display.setCursor(8, 2);   display.print(F("100"));
  display.setCursor(20, 12);  display.print(F("%"));
  display.setCursor(20, 22); display.print(F("0"));
  display.setCursor(14, 35); display.print(F("80"));
  display.setCursor(20, 45);  display.print(F("C"));
  display.setCursor(8, 55);  display.print(F("-40"));
  display.display();
}

void checkDHThcf() {
  if (isnan(h) || isnan(c) || isnan(f)) {
    Serial.println(F("Failed to read DHT."));
    while (1); // hold here after device failure
  }
}

void checkOLED() {
  if (!display.begin(SSD1306_SWITCHCAPVCC, I2C_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    while (1); // hold here after device failure
  }
}

/*
  display.drawLine(StartX, StartY, EndX, EndY, WHITE);
  display.drawRect(StartX, StartY, Width in Pixels, Height in Pixels, WHITE);
  display.drawCircle(CenterX, CenterY, Radius in Pixels, WHITE);
  display.drawTriangle(FirstX , FirstY, SecondX, SecondY, ThirdX, ThirdY, WHITE);
*/