/*
   ESP8266 通过HTTP方式连接到OneNet物联网平台
   实现对数据的上传和读取
   实例为上传DHT11采集到的温度和湿度数据，读取平台LIGHT数据流的数值
   By: Dr.Z
   2018/12/17
*/
#include <ESP8266WiFi.h>
#include <Arduino_JSON.h>
#include <SoftwareSerial.h>

#define DEBUG 1
#define LED 2 
#define DHTPIN 3                         // 传感器连接到D3 -- Sensor to D3
#define DHTTYPE DHT11                     // DHT 11 

WiFiClient client; 
SoftwareSerial dbgSerial(4,12); // 对应ModeMCU班上的 RX(D5), TX(D6)


const char ssid[]     = "PivnsSuPai";         // 使用时请修改为当前你的 wifi 名称 -- Please use your own wifi ssid
const char password[] = "24251052";     //  使用时请修改为当前你的 wifi 密码 -- Please use your own wifi password
const char OneNetServer[] = "api.heclouds.com";
const int tcpPort = 80;

int32_t DeviceId = 1170140006;         // 使用时请修改为你的设备ID -- Please use your own device ID
const char APIKEY[] = "ZJh312lYEl=Gj7a2jtNAl8xr1b8=";    // 使用时请修改为你的API KEY -- Please use your own API KEY

const char DS_ang[] = "ANG";   
const char DS_Temp[] = "TEMP";                        // 数据流 温度TEMP -- Stream "TEMP"
const char DS_Hum[] = "HUMI";                          // 数据流 湿度HUMI -- Stream "HUMI"
char DataStreams[] = "LIGHT";                // 数据流 LIGHT -- Stream "LIGHT"


float temp;              //用于存放传感器温度的数值 -- Saving the temperature value of DH11
float humi;              //用于存放传感器湿度的数值 -- Saving the humidity value of DH11
int ang;                 //用于存放传感器风速的数值

void postData(int dId, float val_t, float val_h,float val_a) 
{
    // 创建发送请求的URL -- We now create a URI for the request
    String url = "/devices/";
    url += String(dId);
    url += "/datapoints";  

    String data = "{\"datastreams\":[";
    data+="{\"id\":\""+String(DS_Temp)+"\",\"datapoints\":[{\"value\":+1.234}]},"; //例子
    data+="{\"id\":\""+String(DS_Hum)+"\",\"datapoints\":[{\"value\":5.789}]},"; //例子
    data+="{\"id\":\""+String(DS_ang)+"\",\"datapoints\":[{\"value\":"+String(val_a)+"}]}"; //风速数据
    data+="]}";  
           
    // 创建发送指令 -- We now combine the request to the server
    String post_data = "POST " + url + " HTTP/1.1\r\n" +
                       "api-key:" + APIKEY + "\r\n" +
                       "Host:" + OneNetServer + "\r\n" +
                       "Content-Length: " + String(data.length()) + "\r\n" + "\r\n" +data;                     //发送数据长度

                        
    // 发送指令 -- This will send the request to server
    client.print(post_data);
    // 调试模式串口打印发送的指令 -- The request will be printed if we choose the DEBUG mode
    if (DEBUG)
    {
        Serial.println(post_data);  
    }
    unsigned long timeout = millis();
    while (client.available() == 0) 
    {
      if (millis() - timeout > 2000) 
      {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return;
      }      
    }
    delay(200);
    Serial.println(client.readString());
    
}

byte serReadArray[24];
int ReadIndex = 0;
byte dataAvailiable=0;
byte timeoutCount=0;


void setup() 
{

   dbgSerial.begin(9600);
   //dbgSerial.println("Hello, world?");
   
    WiFi.mode(WIFI_AP_STA);   //设置工作模式 -- set work mode:  WIFI_AP /WIFI_STA /WIFI_AP_STA
    Serial.begin(115200);
    
    Serial.println("");
    Serial.print("Trying to connect to ");
    Serial.println(ssid);
    // 连接到wifi -- We start by connecting to a wifi network
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) 
    {
      delay(500);
      Serial.print(".");
    }  
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());  
}
const char txArray[]={0x02,0x03,0x00,0x00,0x00,0x01,0x84,0x39};//传感器发送的查询寄存器指令
int modbusRead()
{
   int timeMsCount=0;
   //发送传感器查询指令   
   dbgSerial.write(txArray,sizeof(txArray));
   Serial.println("modbus read register....");
   //读取传感器数据
   while(1)
   {
    
    delay(1);
    if(dbgSerial.available()>0)
    {
      byte b = dbgSerial.read();
      serReadArray[ReadIndex++] = b;
      timeoutCount=10;
    }
    else 
    {
       delay(1);
       if(timeoutCount>0)timeoutCount--;
    }
    
    if(timeoutCount==0) //timeout
    {
      
      if(ReadIndex>=7)
      {
        ang = (float)((serReadArray[3]<<8)+serReadArray[4]);//根据计算公式:计算风速
        temp=serReadArray[2]+(float)serReadArray[3]/100;//根据计算公式：计算温湿度值等
        humi=serReadArray[4]+(float)serReadArray[5]/100;  

        Serial.write(serReadArray,ReadIndex);        
        Serial.println(" succ: get response!");
        ReadIndex=0;
        break;
      }
    }
    timeMsCount++;
    if(timeMsCount>2000)
    {
       Serial.println("err: sensor is no response!");  
      return 0; //错误：传感器超时
    }
  }
  return 1;

}


void loop() 
{
    
     //周期读取modbus     
     delay(3000);
     int ret=modbusRead();
     if(ret>0)//有传感器数据返回
     {
          //1.建立连接并判断 -- Connecting to server
          if (!client.connect(OneNetServer, tcpPort)) 
          {
            Serial.println("connection failed");
            return;
          }
          //2.上传数据 -- post value
          postData(DeviceId, temp, humi,ang);       
          
          Serial.println("closing connection");
      }
    
}
