
#include <Arduino_GFX_Library.h>
#include <TouchDrvCSTXXX.hpp>
#include "lv_conf.h"
#include <lvgl.h>
#include <BME280I2C.h>
#include <EnvironmentCalculations.h>
#include <Wire.h>
#include <ui/ui.h>
#include <ui/vars.h>
#include <ui/actions.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <WiFi.h>
#include <WiFiManager.h>
#include <Ticker.h>
#include <PubSubClient.h>
#include "MQTT.h"
#include <esp_task_wdt.h>

#define MEASINT_S 5
#define SCREEN_UPDATE_S 30  //update screen every 30 secs
#define HISTINT_S (5*60)  //make history point every 5 min.
#define WDT_TIMEOUT SCREEN_UPDATE_S*3  //set WDT timeout to 3 times the screen update time

// -- Initial password to connect to the Thing, when it creates an own Access Point.

MQTT mqtt;
Ticker measurementTick;

unsigned char ChipID = 0x00;
volatile bool TouchEventFlag = false;

float barometerAltitude = 730.0;  // meters ... map readings + barometer position
//using namespace MDO;
/*定义ESP32的SPI使用的引脚*/

BME280I2C::Settings settings(
  BME280::OSR_X1,
  BME280::OSR_X1,
  BME280::OSR_X4,
  BME280::Mode_Normal,
  BME280::StandbyTime_1000ms,
  BME280::Filter_Off,
  BME280::SpiEnable_False,
  BME280I2C::I2CAddr_0x76
);

BME280I2C bme(settings);

#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 2 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf[DRAW_BUF_SIZE / 4];
bool newMeasurement=false,newHistory=false;
float temp(NAN), hum(NAN), pres(NAN),seaLevelPress(NAN);
bool presAlarm = false;
bool mutex_locked = false;
static RTC_NOINIT_ATTR float test;

void measure(void){ //update temp every 30secs
  static uint8_t dropCNT=0;
  static float old_pres=0;
  static uint32_t hist_update_cnt;
  static uint32_t screen_update_cnt;
  //settings.mode = BME280::Mode_Forced;
  //bme.setSettings(settings);
  ++hist_update_cnt;
  ++screen_update_cnt;
  if(newMeasurement){  //if flag was not yet handled completely, skip measurement but increase time counter for history timing
    return;
  }
  bme.read(pres, temp, hum, BME280::TempUnit_Celsius, BME280::PresUnit_hPa);
  //settings.mode = BME280::Mode_Sleep;
  //bme.setSettings(settings);
  temp = temp - 1.0;  //adjust temp to compensate head dissipation of ESP
  seaLevelPress = EnvironmentCalculations::EquivalentSeaLevelPressure(barometerAltitude, temp, pres, EnvironmentCalculations::AltitudeUnit_Meters, EnvironmentCalculations::TempUnit_Celsius);
  /*if(history_isInitialized() && old_pres - pres > 0.1){
    if(++dropCNT > 1){  //pressure drop at leaast 2 secs
      old_pres = pres;
      presAlarm = true;
    }
  }else{
    old_pres = pres;
    dropCNT = 0;
    presAlarm = false;
  }*/
  if(screen_update_cnt >= SCREEN_UPDATE_S/MEASINT_S || presAlarm){ //update every 30 secs
    newMeasurement = true;
    screen_update_cnt = 0;
  }
  
  if(hist_update_cnt >= HISTINT_S/MEASINT_S || history_isInitialized() == false){ //add a point to history every 5 mins or init the hist, if no point present yet
    history_append(seaLevelPress,temp,hum);
    hist_update_cnt = 0;
    newHistory = true;
    newMeasurement = true;
  }
}



void setup(void)
{
  DisplayInit();
  Serial.begin(115200);
  lv_init();
  WiFi.setSleep(WIFI_PS_MIN_MODEM);
  lv_log_register_print_cb(log_print);
  TouchInit();
  bme.begin();
  lv_display_t * disp = lv_display_create(SCREEN_WIDTH, SCREEN_HEIGHT);
  lv_display_set_buffers(disp,draw_buf, NULL, sizeof(draw_buf),LV_DISPLAY_RENDER_MODE_PARTIAL);
  lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_0);
  lv_display_set_flush_cb(disp, my_flush_cb);
  lv_indev_t * indev = lv_indev_create();
  lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
  lv_indev_set_read_cb(indev, my_touch_read);
  ui_init();
  ledcAttachPin(PIN_REL, PWM_REL);
  ledcSetup(PWM_REL, 100000, 8);
  ledcWrite(PWM_REL, 0);
  setBacklight(BL_BRIGHTNESS,300);
  measurementTick.attach(MEASINT_S,measure);
  mqtt.begin();
  getLocalTime(&glblData.bootTime);
  lv_label_set_text_fmt(objects.debugTxt, "IP:\n %s\n\nHostname:\n %s\n\nMqtt-Server:\n %s\n\nMqtt-Port:\n %d\n\nMqtt-Topic:\n %s\n\nHeatBuffer:\n %d",glblData.myIP,Settings::prefs.hostname,Settings::prefs.mqtt_server,Settings::prefs.mqtt_port, Settings::prefs.mqtt_topic,glblData.enBuff);
  measure();
  esp_reset_reason_t reason = esp_reset_reason();
  if ((reason != ESP_RST_DEEPSLEEP) && (reason != ESP_RST_SW)) {
    test = glblData.settemp;
  }
  glblData.settemp = test;
  ui_settemp(glblData.settemp);
  esp_task_wdt_deinit();
  esp_task_wdt_init(WDT_TIMEOUT, true);
  esp_task_wdt_add(NULL);
}

unsigned long lastms = millis();
unsigned long secondsTick = 0, minutesTick = 0;
uint8_t statusCnt=0;
void loop()
{
  if(newMeasurement){
    esp_task_wdt_reset();
    update_sensorNstatus(temp, hum, seaLevelPress,presAlarm);
    test = glblData.settemp;
    newMeasurement = false;
    mqtt.sendStatus();
  }
  if(newHistory){
    newHistory=false;
    chart_autoscale();
    lv_chart_refresh(objects.chart);
  }
  if(millis() - minutesTick > 60000){
    minutesTick = millis();
    if(mqtt.wifiConnected){
      update_wifi_strength(glblData.wifiStrength,glblData.wifiMode);
    }
  }
  if(millis() - secondsTick > 1000){
    secondsTick = millis();
    //update_clockdots();
  }
  mqtt.loop();
  ui_tick();
  if(!ui_isSleeping()){
    lv_task_handler();                // let the GUI do its work
    lv_tick_inc(millis() - lastms);   // tell LVGL how much time has passed
  }
  lastms = millis();
}
