#include "RTClib.h"
#include <LiquidCrystal_I2C.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <OneWire.h>
#define SCL 16
#define SDA 17
#define ONE_WIRE_BUS 11

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
static TaskHandle_t xGatewayTask = NULL;    // 网关线程

typedef struct{
  uint8_t type;     // 数据类型 1
  uint16_t year;    // 年
  uint8_t month;    // 月
  uint8_t day;      // 日
  uint8_t hour;     // 时
  uint8_t minute;   // 分
  uint8_t second;   // 秒
  uint8_t week;     // 星期
}Data_Time;

typedef struct{
  uint8_t type;     // 数据类型 2
  float temperature;  //温度
}Data_Temperature;

// 温度传感器获取
void temperature_task(void* param_t){
  OneWire oneWire(ONE_WIRE_BUS);        // 初始化一个OneWire对象来控制1-Wire总线
  DallasTemperature sensors(&oneWire);  // 初始化一个DallasTemperature对象来使用DS18B20
  sensors.begin();

  while(1){
    sensors.requestTemperatures();
    Data_Temperature *temp = (Data_Temperature *)pvPortMalloc(sizeof(Data_Temperature));
    temp->type=2;
    temp->temperature = sensors.getTempCByIndex(0);
    // 发送数据,使用指针作为附件
    if(xTaskNotify(xGatewayTask, (uint32_t)temp, eSetValueWithoutOverwrite)!=pdPASS){
      // 不进行数据覆盖,但如果发送失败,则需要就地释放空间,否则运行时间长了会导致溢出
      vPortFree(temp);
    }
    vTaskDelay(random(200,1000));
  }
}

// 时钟获取线程
void clock_task(void *param_t){
  RTC_DS1307 rtc;         // 定义时钟
  if (rtc.begin()) {
    while(1){
      DateTime now = rtc.now();
      Data_Time *time = (Data_Time *)pvPortMalloc(sizeof(Data_Time));
      time->type=1;
      time->year = now.year();
      time->month = now.month();
      time->day = now.day();
      time->hour = now.hour();
      time->minute = now.minute();
      time->second = now.second();
      time->week = now.dayOfTheWeek();
      // 发送数据,使用指针作为附件
      if(xTaskNotify(xGatewayTask, (uint32_t)time, eSetValueWithoutOverwrite)!=pdPASS){
        // 释放空间
        vPortFree(time);
      }
      vTaskDelay(random(200,1000));   // 每间隔一段时间上报一次时间
    }
  }
  vTaskDelete(NULL);  // 自我终结
}

// 物联网网关
void gateway_task(void *param_t){
  uint32_t annex;   // 附件数据
  void *dp= NULL;   // 接收邮件附件用的指针
  LiquidCrystal_I2C lcd(0x27, 20, 4);
  lcd.init();
  lcd.backlight();
  char line[4][21]; //数据

  while(1){
    if(xTaskNotifyWait(0x00, 0x00, &annex, 0) == pdTRUE){
      dp = (void*)annex;
      char *type = (char *)dp;
      if(*type==1){
        // 时间数据
        Data_Time *time = (Data_Time *)dp;
        int second  = time->second;
        int minute  = time->minute;
        int hour    = time->hour;
        int day     = time->day;
        int month   = time->month;
        int year    = time->year;
        int week    = time->week;
        sprintf(line[0], "   %04d - %02d - %02d", year, month, day);
        sprintf(line[1], "     %s",daysOfTheWeek[time->week]);
        sprintf(line[2], "    %02d : %02d : %02d", hour, minute, second);
        for(int i=0; i<3; i++){
          lcd.setCursor(0, i);
          lcd.print(line[i]);
        }
      }else if(*type==2){
        // 温度数据
        Data_Temperature *temp = (Data_Temperature *)dp;
        sprintf(line[3], " Temperature : %.2f", temp->temperature);
        lcd.setCursor(0, 3);
        lcd.print(line[3]);
      }
      vPortFree(dp);    // 一定要释放附件空间
    }
    vTaskDelay(200);
  }
}

void setup() {
  Serial.begin(115200);
  // Serial.println("Hello, ESP32-S3!");
  Wire.begin(SDA, SCL);   // 初始化I2C总线

  xTaskCreate(gateway_task, "GATEWAY", 10240, NULL, 1, &xGatewayTask);
  xTaskCreate(clock_task, "CLOCK", 10240, NULL, 1, NULL);
  xTaskCreate(temperature_task, "TEMP", 10240, NULL, 1, NULL);

  vTaskDelete(NULL);  // 自宫
}

void loop() {
  delay(3000);
}
esp:0
esp:1
esp:2
esp:3
esp:4
esp:5
esp:6
esp:7
esp:8
esp:9
esp:10
esp:11
esp:12
esp:13
esp:14
esp:15
esp:16
esp:17
esp:18
esp:19
esp:20
esp:21
esp:35
esp:36
esp:37
esp:38
esp:39
esp:40
esp:41
esp:42
esp:45
esp:46
esp:47
esp:48
esp:3V3.1
esp:3V3.2
esp:RST
esp:5V
esp:GND.1
esp:GND.2
esp:TX
esp:RX
esp:GND.3
esp:GND.4
GND5VSDASCLSQWRTCDS1307+
rtc1:GND
rtc1:5V
rtc1:SDA
rtc1:SCL
rtc1:SQW
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL
temp1:GND
temp1:DQ
temp1:VCC