/*
Version 0.1 - septembre 2019
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsClient.h> // https://github.com/kakopappa/sinric/wiki/How-to-add-dependency-libraries
#include <ArduinoJson.h> // https://github.com/kakopappa/sinric/wiki/How-to-add-dependency-libraries
#include <StreamString.h>
#include "DHTesp.h" // https://github.com/beegee-tokyo/DHTesp
#include <AceButton.h> // https://github.com/bxparks/AceButton
using namespace ace_button;
#define DEBUG_WEBSOCKETS true
ESP8266WiFiMulti WiFiMulti;
WebSocketsClient webSocket;
DHTesp dht;
#define MyApiKey "xxxxxxxxxxxxxxxxxxxx" // Changez votre cle API. votre cle API est affiché dans votre compte sur sinric.com
#define MySSID "xxxxxxxx" // Changez votre reseau Wifi
#define MyWifiPassword "xxxxxxxx" // Changez votre mot de passe reseau Wifi
#define Switch1 "xxxxxxxxx" // Changez l'ID par celuis de votre switch crée sur sinric.com
#define HEARTBEAT_INTERVAL 300000 // 3 Minutes
#define TEMPRATURE_INTERVAL 100000 // 1 Minutes
#define SERVER_URL "iot.sinric.com" //"iot.sinric.com"
#define SERVER_PORT 80 // 80
const int LED_PIN = 13;
const int BUTTON_PIN = 0;
const int RELAY_PIN = 12;
float temp;
float setpoint = 18.0;
uint64_t heartbeatTimestamp = 0;
uint64_t tempratureUpdateTimestamp = 0;
bool isConnected, flag = false;
AceButton button(BUTTON_PIN);
void handleEvent(AceButton*, uint8_t, uint8_t);
void setPowerStateOnServer(String deviceId, String value);
void setSetTemperatureSettingOnServer(String deviceId, String value, String scale);
void readTempature();
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
isConnected = false;
Serial.printf("[WSc] Webservice disconnected from sinric.com!\n");
break;
case WStype_CONNECTED: {
isConnected = true;
Serial.printf("[WSc] Service connected to sinric.com at url: %s\n", payload);
Serial.printf("Waiting for commands from sinric.com ...\n");
}
break;
case WStype_TEXT: {
Serial.printf("[WSc] get text: %s\n", payload);
// Example payloads For Thermostat
// {"deviceId": xxxx, "action": "setPowerState", value: "ON"} // https://developer.amazon.com/docs/device-apis/alexa-thermostatcontroller.html
// {"deviceId": xxxx, "action": "SetTargetTemperature", value: "targetSetpoint": { "value": 20.0, "scale": "CELSIUS"}} // https://developer.amazon.com/docs/device-apis/alexa-thermostatcontroller.html#settargettemperature
// {"deviceId": xxxx, "action": "AdjustTargetTemperature", value: "targetSetpointDelta": { "value": 2.0, "scale": "FAHRENHEIT" }} // https://developer.amazon.com/docs/device-apis/alexa-thermostatcontroller.html#adjusttargettemperature
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.parseObject((char*)payload);
String deviceId = json ["deviceId"];
String action = json ["action"];
if (deviceId == Switch1) {// Device ID of first device
if(action == "setPowerState") { // On or Off
String value = json ["value"];
Serial.println("[WSc] setPowerState" + value);
if (value == "ON") {
flag = true;
digitalWrite(LED_PIN, LOW);
digitalWrite(RELAY_PIN, HIGH);
} else {
flag = false;
digitalWrite(LED_PIN, HIGH);
digitalWrite(RELAY_PIN, LOW);
}
}
else if(action == "SetTargetTemperature") {
// Alexa, set thermostat to 20
//String value = json ["value"];
String value = json["value"]["targetSetpoint"]["value"];
String scale = json["value"]["targetSetpoint"]["scale"];
Serial.println("[WSc] SetTargetTemperature value: " + value);
Serial.println("[WSc] SetTargetTemperature scale: " + scale);
setpoint = value.toFloat();
}
else if(action == "AdjustTargetTemperature") {
//Alexa, make it warmer in here
//Alexa, make it cooler in here
String value = json["value"]["targetSetpointDelta"]["value"];
String scale = json["value"]["targetSetpointDelta"]["scale"];
Serial.println("[WSc] AdjustTargetTemperature value: " + value);
Serial.println("[WSc] AdjustTargetTemperature scale: " + scale);
setpoint = setpoint + value.toFloat();
}
else if (action == "test") {
Serial.println("[WSc] received test command from sinric.com");
}
}
}
break;
case WStype_BIN:
Serial.printf("[WSc] get binary length: %u\n", length);
break;
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
WiFiMulti.addAP(MySSID, MyWifiPassword);
Serial.println();
Serial.print("Connecting to Wifi: ");
Serial.println(MySSID);
// Waiting for Wifi connect
while(WiFiMulti.run() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
if(WiFiMulti.run() == WL_CONNECTED) {
Serial.println("");
Serial.print("WiFi connected. ");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
dht.setup(3, DHTesp::DHT22); // Connect DHT sensor to GPIO 3
button.init(BUTTON_PIN);
button.setEventHandler(handleEvent);
digitalWrite(LED_PIN, HIGH);
digitalWrite(RELAY_PIN, LOW);
// server address, port and URL
webSocket.begin(SERVER_URL, SERVER_PORT, "/");
// event handler
webSocket.onEvent(webSocketEvent);
webSocket.setAuthorization("apikey", MyApiKey);
// try again every 5000ms if connection has failed
webSocket.setReconnectInterval(5000); // If you see 'class WebSocketsClient' has no member named 'setReconnectInterval' error update arduinoWebSockets
}
void loop() {
webSocket.loop();
button.check();
if(isConnected) {
uint64_t now = millis();
// Send heartbeat in order to avoid disconnections during ISP resetting IPs over night. Thanks @MacSass
if((now - heartbeatTimestamp) > HEARTBEAT_INTERVAL) {
heartbeatTimestamp = now;
webSocket.sendTXT("H");
}
// Send the tempature settings to server
if((now - tempratureUpdateTimestamp) > TEMPRATURE_INTERVAL) {
tempratureUpdateTimestamp = now;
readTempature();
Serial.println(setpoint);
Serial.println(temp);
Serial.println(flag);
if (temp < setpoint && flag == true) {
Serial.println("en chauffe");
} else {
Serial.println("chauffage coupe");
}
}
}
}
// Read tempratre from DHT Sensor
void readTempature() {
//delay(dht.getMinimumSamplingPeriod());
float humidity = dht.getHumidity();
float temperature = dht.getTemperature();
float temperaturefh = dht.toFahrenheit(temperature);
temp = temperature;
Serial.print(dht.getStatusString());
Serial.print("\t");
Serial.print(humidity, 1);
Serial.print("\t\t");
Serial.print(temperature, 1);
Serial.print("\t\t");
Serial.print(dht.toFahrenheit(temperature), 1);
Serial.print("\t\t");
Serial.print(dht.computeHeatIndex(temperature, humidity, false), 1);
Serial.print("\t\t");
Serial.println(dht.computeHeatIndex(dht.toFahrenheit(temperature), humidity, true), 1);
setSetTemperatureSettingOnServer("<device id>", temperature, "FAHRENHEIT", temperaturefh, humidity);
}
// If you are going to use a push button to on/off the switch manually, use this function to update the status on the server
// so it will reflect on Alexa app.
// eg: setPowerStateOnServer("deviceid", "ON")
// Call ONLY If status changed. DO NOT CALL THIS IN loop() and overload the server.
void setPowerStateOnServer(String deviceId, String value) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["deviceId"] = deviceId;
root["action"] = "setPowerState";
root["value"] = value;
StreamString databuf;
root.printTo(databuf);
webSocket.sendTXT(databuf);
}
// Call ONLY If status changed. DO NOT CALL THIS IN loop() and overload the server.
//eg: setSetTemperatureSettingOnServer("deviceid", 25.0, "CELSIUS" or "FAHRENHEIT", 23.0, 45.3)
// setPoint: Indicates the target temperature to set on the termostat.
void setSetTemperatureSettingOnServer(String deviceId, float setPoint, String scale, float ambientTemperature, float ambientHumidity) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["action"] = "SetTemperatureSetting";
root["deviceId"] = deviceId;
JsonObject& valueObj = root.createNestedObject("value");
JsonObject& temperatureSetting = valueObj.createNestedObject("temperatureSetting");
temperatureSetting["setPoint"] = setPoint;
temperatureSetting["scale"] = scale;
temperatureSetting["ambientTemperature"] = ambientTemperature;
temperatureSetting["ambientHumidity"] = ambientHumidity;
StreamString databuf;
root.printTo(databuf);
webSocket.sendTXT(databuf);
}
// Call ONLY If status changed. DO NOT CALL THIS IN loop() and overload the server.
void setThermostatModeOnServer(String deviceId, String thermostatMode) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
root["deviceId"] = deviceId;
root["action"] = "SetThermostatMode";
root["value"] = thermostatMode;
StreamString databuf;
root.printTo(databuf);
webSocket.sendTXT(databuf);
}
void handleEvent(AceButton*, uint8_t eventType, uint8_t) {
switch (eventType) {
case AceButton::kEventPressed:
Serial.println("kEventPressed");
if (flag == false) {
setPowerStateOnServer(Switch1, "ON");
Serial.println("ON par le bouton");
digitalWrite(LED_PIN, LOW);
flag = true;
break;
} else {
setPowerStateOnServer(Switch1, "OFF");
Serial.println("OFF par le bouton");
digitalWrite(LED_PIN, HIGH);
digitalWrite(RELAY_PIN, LOW);
flag = false;
break;
}
case AceButton::kEventReleased:
Serial.println("kEventReleased");
break;
}
}