#include <IRremoteInt.h>
#include <DFRobot_IRremote.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "DFRobot_Iot.h"

IRremote_Receive IReceive;

#define IRSensor A1   //定义红外距离传感器引脚
#define IR_IN  D0  //定义红外接收引脚
#define Relay D1  //定义继电器引脚
#define M1en D2   //定义步进电机enable引脚
#define M1dirpin D3   //定义步进电机dir引脚
#define M1steppin D4    //定义步进电机step引脚
#define STEP_NUM        1000      //步进数

#define DOWN            LOW       //低电平窗帘下降
#define UP              HIGH      //高电平窗帘上升降

#define LOCATION_UPPER_STOP     41300     //定义上升步数

String IR_CODE_DOWN = "FD10EF";   //下降红外指令
String IR_CODE_UP = "FD50AF";     //上升红外指令
String IR_CODE_PAUSE = "FDA05F";  //暂停红外指令
String IR_CODE_CAL = "FD708F";    //校准红外指令
String IRData;

long Stepper_Location = 0;

DFRobot_Iot myIot;
WiFiClient espClient;
PubSubClient client(espClient);

//设置WiFi名称和密码
const char * WIFI_SSID = "DFRobot-guest";
const char * WIFI_PASSWORD = "dfrobot@2017";

//配置证书信息
String ProductKey = "a1Ywimhh30R";
String ClientId = "12345";/*Custom id*/
String DeviceName = "qAzHgdmmkzqhIBbHU8MH";
String DeviceSecret = "EqTYQmJiUH7T8jiW2XMJBbEEpBIVSK9j";

/*Configure the domain name and port number*/
String ALIYUN_SERVER = "iot-as-mqtt.cn-shanghai.aliyuncs.com";
uint16_t PORT = 1883;

//配置产品功能标识符
String Identifier = "Curtain_Control";

//需要发布和订阅的Topic
const char * subTopic = "/sys/a1Ywimhh30R/qAzHgdmmkzqhIBbHU8MH/thing/service/property/set";//****set
const char * pubTopic = "/sys/a1Ywimhh30R/qAzHgdmmkzqhIBbHU8MH/thing/event/property/post";//******post


void setup()
{
  /*Connect to WIFI*/
  connectWiFi();

  /*Initialize the configuration of Aliyun*/
  myIot.init(ALIYUN_SERVER, ProductKey, ClientId, DeviceName, DeviceSecret);

  client.setServer(myIot._mqttServer, PORT);

  /*Set the callback function to execute the callback function when receiving the subscription information*/
  client.setCallback(callback);

  /*Connect to the cloud platform*/
  ConnectCloud();

  /*Publish information about turning off the lights*/
  client.publish(pubTopic, ("{\"id\":" + ClientId + ",\"params\":{\"" + Identifier + "\":0},\"method\":\"thing.event.property.post\"}").c_str());

  pinMode(Relay, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(M1dirpin, OUTPUT);
  pinMode(M1steppin, OUTPUT);
  pinMode(M1en, OUTPUT);
  pinMode(IRSensor, INPUT);
  IReceive.begin(IR_IN);
  //digitalWrite(M1en, LOW); //低电平使能
}

void loop() {
  if (!client.connected()) {
    ConnectCloud();
  }
  client.loop();
  //Serial.println(IRData);
  String demo = IReceive.getIrCommand();
  if (!(demo == "0")) {
    IRData = demo;
  }
  if (Stepper_Location > LOCATION_UPPER_STOP) {
    if (IRData == IR_CODE_DOWN) {
      ;
    }
    else {
      IRData = IR_CODE_PAUSE;
    }
  }

  if (digitalRead(IRSensor) == 0 && IRData == IR_CODE_UP) {
    digitalWrite(Relay, HIGH);
    digitalWrite(M1en, LOW);
    for (int j = 0; j < 2000; j++) {
      MotorUp();
    }
  }

  if (digitalRead(IRSensor) == 0) {
    digitalWrite(Relay, LOW);
    digitalWrite(M1en, HIGH);
    IRData = IR_CODE_PAUSE;
    Stepper_Location = 0;
  }
  else if (IRData == IR_CODE_DOWN)//向下三角,窗帘下降
  {
    MotorDown();
  }
  else if (IRData == IR_CODE_UP)//向上三角，窗帘上升
  {
    MotorUp();
  }
  else if (IRData == IR_CODE_PAUSE) {//暂停键，窗帘停止
    digitalWrite(Relay, LOW);
    digitalWrite(M1en, HIGH);
  }
  else if ( IRData == IR_CODE_CAL){//校准窗帘位置
    while (digitalRead(IRSensor) == 1) {
      MotorDown();
    }
    IRData = IR_CODE_PAUSE;
    Stepper_Location = 0;
  }
  
}

void Motor() {
  digitalWrite(Relay, HIGH);
  digitalWrite(M1en, LOW);
  digitalWrite(M1steppin, LOW);
  delayMicroseconds(2);
  digitalWrite(M1steppin, HIGH);  //上升沿步进
  delay(1);
}

void MotorUp() {
  delayMicroseconds(2);
  digitalWrite(M1dirpin, LOW);
  Motor();
  Stepper_Location++;
}

void MotorDown() {
  delayMicroseconds(2);
  digitalWrite(M1dirpin, HIGH);
  Motor();
  Stepper_Location--;
}

void connectWiFi() {
  Serial.print("Connecting to ");
  Serial.println(WIFI_SSID);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP Adderss: ");
  Serial.println(WiFi.localIP());
}

void callback(char * topic, byte * payload, unsigned int len) {
  Serial.print("Recevice [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < len; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  StaticJsonBuffer<300> jsonBuffer;
  JsonObject& root = jsonBuffer.parseObject((const char *)payload);
  if (!root.success()) {
    Serial.println("parseObject() failed");
    return;
  }
  const uint16_t Curtain_Control = root["params"][Identifier];
  if (Curtain_Control == 0) {
    IRData = IR_CODE_PAUSE;
  }
  else if (Curtain_Control == 1) {
    IRData = IR_CODE_UP;
  }
  else if (Curtain_Control == 2) {
    IRData = IR_CODE_DOWN;
  }
  else {
    IRData = IR_CODE_CAL;
  }
  String tempMseg = "{\"id\":" + ClientId + ",\"params\":{\"" + Identifier + "\":" + (String)Curtain_Control + "},\"method\":\"thing.event.property.post\"}";
  char sendMseg[tempMseg.length()];
  strcpy(sendMseg, tempMseg.c_str());
  client.publish(pubTopic, sendMseg);
}

void ConnectCloud() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    /*A device connected to the cloud platform based on an automatically calculated username and password*/
    if (client.connect(myIot._clientId, myIot._username, myIot._password)) {
      Serial.println("connected");
      client.subscribe(subTopic);
    }
    else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}
