#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <LiquidCrystal_I2C.h>
#include "DHT.h"

#define DHTPIN 2
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);

LiquidCrystal_I2C lcd(0x27,16,2); 

#define lag_tela 128  
#define alt_tela 64  
#define OLED_RESET     -1 
Adafruit_SSD1306 display(lag_tela, alt_tela, &Wire, OLED_RESET);

unsigned long mill_receb = 0;
unsigned long mill_resul = 0;
unsigned long lastDisplayUpdate = 0;

const long inter_receb = 20;
const long inter_resul = 7000;

int sig_pul;
const int wire_pul = 0; 
const int led = 3; 

int limsup = 550;
int liminf = 500;

int cntHB = 0;
boolean statlim = true;
int val_bpm = 0;

int x = 0;
int y = 0;
int lastx = 0;
int lasty = 0;

const unsigned char Heart_Icon [] PROGMEM = {
  0x00, 0x00, 0x18, 0x30, 0x3c, 0x78, 0x7e, 0xfc, 0xff, 0xfe, 0xff, 0xfe, 0xee, 0xee, 0xd5, 0x56,
  0x7b, 0xbc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00, 0x00
};

void setup() {
  pinMode(led, OUTPUT);
  Serial.begin(9600);      
  Serial.println(F("DHTxx test!"));

  dht.begin();

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }

  lcd.init();  
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("BPM:");
  lcd.setCursor(0,1);
  lcd.print("Temp:");
  display.clearDisplay();

  display.setTextColor(WHITE);
  display.setCursor(22, 20);
  display.setTextSize(1);
  display.println("  Heart Beat");
  display.setTextColor(BLACK, WHITE); 
  display.setCursor(40, 37);
  display.println("Sentinel");
  display.display();
  delay(1000);

  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0, 22);
  display.print("       Loading...");
  display.display();
  delay(1000);

  display.clearDisplay();
  display.drawBitmap(0, 47, Heart_Icon, 16, 16, WHITE);
  display.drawLine(0, 43, 127, 43, WHITE);
  display.setTextSize(2);
  display.setTextColor(WHITE);
  display.setCursor(20, 48);
  display.print(": 0 BPM");
  display.display();

  Serial.println();
  Serial.println("Aguarde um pouco...");
}

void loop() {
  batimentos();
  TemperaturaEHumidade();
}

void TemperaturaEHumidade() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();
  float f = dht.readTemperature(true);

  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  float hif = dht.computeHeatIndex(f, h);
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("°C "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hic);
  Serial.print(F("°C "));
  Serial.print(hif);
  Serial.println(F("°F"));

  lcd.setCursor(5,0);
  lcd.print(val_bpm);
  lcd.setCursor(6,1);
  lcd.print(t);
}

void batimentos() {
  unsigned long mill_at_rec = millis();

  if (mill_at_rec - mill_receb >= inter_receb) {
    mill_receb = mill_at_rec;
    sig_pul = analogRead(wire_pul);

    if (sig_pul > limsup && statlim == true) {
      cntHB++;
      statlim = false;
      digitalWrite(led, HIGH);
    }

    if (sig_pul < liminf) {
      statlim = true;
      digitalWrite(led, LOW);
    }

    grafico(); 
  }

  unsigned long mill_at_resul = millis();

  if (mill_at_resul - mill_resul >= inter_resul) {
    mill_resul = mill_at_resul;
    val_bpm = cntHB * 6;
    Serial.print("BPM : ");
    Serial.println(val_bpm);
    cntHB = 0;
  }
}

void grafico() {
  if (x > 127) {
    display.fillRect(0, 0, 128, 42, BLACK);
    x = 0;
    lastx = 0;
  }

  int ySignal = sig_pul;
  if (ySignal > 850) ySignal = 850;
  if (ySignal < 350) ySignal = 350;
  int ySignalMap = map(ySignal, 350, 850, 0, 40);
  y = 40 - ySignalMap;
  display.writeLine(lastx, lasty, x, y, WHITE);
  lastx = x;
  lasty = y;
  x++;
}