/**
 **************************************************
 *
 * @file        Qwiic.ino
 * @brief       Example demonstrating easyC (I2C) communication between Inkplate 2 and 
 *              a Soldered BME280 or BME680 environmental sensor, using the LVGL library 
 *              for display rendering. 
 *
 *              This example reads temperature, humidity, and pressure data from a 
 *              Soldered BME280 sensor connected via the easyC interface and displays 
 *              it on the Inkplate 6 e-paper screen using LVGL elements.
 *
 *              Note: Both BME280 and BME680 sensors are supported by the same 
 *              Soldered BME280/BME680 library. In this example, the BME280 is used, 
 *              as defined in the code. The sensor communicates over easyC (I2C) 
 *              using the default 0x76 address.
 *
 * For setup instructions and more information about Inkplate 2, visit:
 * https://soldered.com/documentation/inkplate/2/overview/
 *
 * @hardware    Inkplate 2 (ESP32-based e-paper display)
 * @sensors     Soldered BME280 (or BME680) via easyC connector
 * @library     Soldered BME280/BME680 Gas Sensor Arduino Library
 *              https://github.com/SolderedElectronics/Soldered-BME280-BME680-Gas-Sensor-Arduino-Library
 *
 * @authors     Soldered
 * @date        November 2025
 **************************************************
 */


#include <Inkplate-LVGL.h>
#include <BME280-SOLDERED.h>   // Soldered BME280/BME680 library

// Inkplate in 1-bit mode (fast partial updates)
Inkplate inkplate;
BME280   bme280;               

// Optional temperature calibration offset
const float TEMPERATURE_OFFSET = 0.0f;

// UI elements
static lv_obj_t *panel_data;
static lv_obj_t *lbl_title;
static lv_obj_t *lbl_temp;
static lv_obj_t *lbl_hum;
static lv_obj_t *lbl_press;
static lv_obj_t *lbl_warn;

// Refresh policy (do a FULL every ~20 partials)
static int partialCount = 0;
static const int FULL_REFRESH_EVERY = 20;

// Helpers
static inline int dispW() { auto *d = lv_display_get_default(); return lv_display_get_horizontal_resolution(d); }
static inline int dispH() { auto *d = lv_display_get_default(); return lv_display_get_vertical_resolution(d); }

static void make_opaque(lv_obj_t *obj) {
  lv_obj_set_style_bg_color(obj, lv_color_hex(0xFFFFFF), 0);
  lv_obj_set_style_bg_opa(obj, LV_OPA_COVER, 0);
  lv_obj_set_style_border_width(obj, 0, 0);
}

static void ui_create() {
  lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0xFFFFFF), LV_PART_MAIN);

  // Title
  lbl_title = lv_label_create(lv_screen_active());
  lv_label_set_text(lbl_title, "BME280");
  lv_obj_set_style_text_color(lbl_title, lv_color_hex(0x000000), 0);
  lv_obj_set_style_text_font(lbl_title, LV_FONT_DEFAULT, 0);    // small font
  lv_obj_set_pos(lbl_title, 4, 1);
  make_opaque(lbl_title);

  // Data Panel 
  panel_data = lv_obj_create(lv_screen_active());
  make_opaque(panel_data);
  lv_obj_set_style_pad_all(panel_data, 0, 0);
  lv_obj_set_style_border_width(panel_data, 0, 0);
  lv_obj_set_pos(panel_data, 0, 14);                     // leave space for title
  lv_obj_set_size(panel_data, dispW(), dispH() - 14);

  // Temperature
  lbl_temp = lv_label_create(panel_data);
  lv_obj_set_style_text_color(lbl_temp, lv_color_hex(0x000000), 0);
  lv_obj_set_pos(lbl_temp, 4, 2);

  // Humidity
  lbl_hum = lv_label_create(panel_data);
  lv_obj_set_style_text_color(lbl_hum, lv_color_hex(0x000000), 0);
  lv_obj_set_pos(lbl_hum, 4, 20);

  // Pressure
  lbl_press = lv_label_create(panel_data);
  lv_obj_set_style_text_color(lbl_press, lv_color_hex(0x000000), 0);
  lv_obj_set_pos(lbl_press, 4, 38);

  // Warning
  lbl_warn = lv_label_create(panel_data);
  lv_obj_set_style_text_color(lbl_warn, lv_color_hex(0x000000), 0);
  lv_obj_set_style_text_font(lbl_warn, LV_FONT_DEFAULT, 0);
  lv_obj_set_pos(lbl_warn, 4, 58);
  lv_obj_set_width(lbl_warn, dispW() - 8);   // keep text inside screen width
  lv_label_set_text(lbl_warn, "");
}


static void update_readings() {
  // Read sensor
  float tC  = bme280.readTemperature() + TEMPERATURE_OFFSET; // °C
  float hum = bme280.readHumidity() / 10.0f;                 // library returns x10
  float hPa = bme280.readPressure() * 10.0f;                 // hPa (original style)

  // Basic sanity check (some libs return 0 or extreme values if not connected)
  bool looks_bad = (hPa <= 0.0f) || (hum < 0.0f || hum > 100.0f) || (tC < -40.0f || tC > 85.0f);

  char bufT[32], bufH[32], bufP[32];
  snprintf(bufT, sizeof(bufT), "Temperature: %.1f *C", tC);
  snprintf(bufH, sizeof(bufH), "Humidity:    %.0f %%", hum);
  snprintf(bufP, sizeof(bufP), "Pressure:    %.0f hPa", hPa);

  lv_label_set_text(lbl_temp,  bufT);
  lv_label_set_text(lbl_hum,   bufH);
  lv_label_set_text(lbl_press, bufP);

  if (looks_bad) {
    lv_label_set_text(lbl_warn, "Warning: sensor readings look invalid.\nCheck Qwiic cable and sensor power.");
  } else {
    lv_label_set_text(lbl_warn, "");
  }
}

void setup() {
  Serial.begin(115200);

  // LVGL + Inkplate in PARTIAL mode
  inkplate.begin(LV_DISP_RENDER_MODE_PARTIAL);

  // Init BME280 (void return in this library)
  bme280.begin();

  ui_create();
  update_readings();

  // Initial FULL refresh
  lv_tick_inc(20);
  lv_timer_handler();
  inkplate.display();
}

void loop() {
  update_readings();

  lv_tick_inc(10);
  lv_timer_handler();
  inkplate.display();   // FULL


  delay(60000); // ~60 s between readings
}