/* 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; } }