Skip to content

Instantly share code, notes, and snippets.

@sivar2311
Created January 19, 2021 11:23
Show Gist options
  • Save sivar2311/20bf1feeafeb3f1835ba82dfc2d046bc to your computer and use it in GitHub Desktop.
Save sivar2311/20bf1feeafeb3f1835ba82dfc2d046bc to your computer and use it in GitHub Desktop.
Thermostat_LM75_Relay
#include "credentials.h"
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "lm75.h"
#include "SinricPro.h"
#include "SinricProThermostat.h"
#include "EEPROM.h"
#define PRINT_TIME 1000 // interval for serial print
#define REPORT_TIME 60000 // interval for reporting temperature to SinricPro server
#define RELAY_PIN 2 // pin for relay (here internal LED is used)
TempI2C_LM75 tempSensor(0x48, TempI2C_LM75::nine_bits);
SinricProThermostat &myThermostat = SinricPro[THERMOSTAT_ID];
enum ThermostatMode { AUTO, COOL, HEAT }; // thermostat modes as enum
struct ThermostatCfg { // configuration struct, used to save and load from eeprom
bool powerState = false; // powerstate (device is on or off) | DEFAULT: OFF (false)
float targetTemperature = 25.0f; // target temperature | DEFAULT: 25°C
ThermostatMode mode = AUTO; // thermostat mode (AUTO, COOL, HEAT) | DEFAULT: AUTO
unsigned char check = 0x42; // just a fixed byte value. used to detect if eeprom data is valid or not
};
ThermostatCfg thermostatConfig; // stores the configuration
float temperature; // keep the current temperature
bool relayState = false; // keep the relay state
float tempThreshold = 1.0f; // temperature hysteresis threshold
/**
* printConfig()
* Print current configuration to serial
**/
void printConfig() {
Serial.printf("Device is %s\r\n", thermostatConfig.powerState?"ON":"OFF");
Serial.printf("Mode is %s\r\n", thermostatConfig.mode == AUTO?"AUTO":thermostatConfig.mode==HEAT?"HEAT":"COOL");
Serial.printf("Target temperature is %2.1f\r\n", thermostatConfig.targetTemperature);
}
/**
* saveConfig()
* Save cofnigruation to EEPROM
**/
void saveConfig() { // saves the configuration to eeprom
Serial.printf("Saving config\r\n");
EEPROM.put(0, thermostatConfig);
EEPROM.commit();
}
/**
* loadConfig()
* loads configuration from eeprom
* applies default configuration if eeprom configuration was not valid (first run)
**/
void loadConfig() {
Serial.printf("Loading config\r\n");
ThermostatCfg tempConfig;
EEPROM.get(0, tempConfig);
if (tempConfig.check == 0xAB) {
Serial.printf("Config is valid\r\n");
thermostatConfig = tempConfig;
} else {
Serial.printf("Config is invalid. Saving default config.\r\n");
saveConfig();
}
printConfig();
if (thermostatConfig.powerState == false) return;
if (thermostatConfig.mode == HEAT) { digitalWrite(RELAY_PIN, HIGH); relayState = true; }
if (thermostatConfig.mode == COOL) { digitalWrite(RELAY_PIN, LOW); relayState = false; }
}
/**
* reportTemperature()
* report current temperature to SinricPro in a given interval (waitTime)
**/
void reportTemperature(unsigned long waitTime) {
if (thermostatConfig.powerState == false) return;
static unsigned long lastMillis;
unsigned long currentMillis = millis();
if (currentMillis - lastMillis <= waitTime) return;
lastMillis = currentMillis;
myThermostat.sendTemperatureEvent(temperature);
Serial.printf("Reporting measured temperature to SinricPro server: %2.1f\r\n", temperature);
}
/**
* handleTemperature()
* - get temperature from sensor
* - return if sensor reading failed
* - if device is in AUTO mode and not turned off
* - if temperature is below target temperature and relay is off: turn on relay, report temperature to SinricPro server
* - if temperature is above target temperature and relay is on: turn off relay, report temperature to SinricPro server
**/
void handleTemperature() {
float tempTemperature = tempSensor.getTemp();
if (tempTemperature > 100.0f) return; // reading was wrong..do nothing
temperature = tempTemperature;
if (thermostatConfig.mode != AUTO || thermostatConfig.powerState == false) return;
if (temperature <= thermostatConfig.targetTemperature && relayState == false) {
Serial.printf("Temperature (%2.3f)is below target temperature. Relay turned on.\r\n", temperature);
digitalWrite(RELAY_PIN, HIGH);
relayState = true;
reportTemperature(0);
}
if (temperature >= (thermostatConfig.targetTemperature + tempThreshold) && relayState == true) {
Serial.printf("Temperature (%2.3f) is above target temeprature. Relay turned off\r\n", temperature);
digitalWrite(RELAY_PIN, LOW);
relayState = false;
reportTemperature(0);
}
}
/**
* printTemperature()
* if device is not turned off: print the temperature in given interval (waitTime) to serial
**/
void printTemperature(unsigned long waitTime) {
if (thermostatConfig.powerState == false) return;
static unsigned long lastMillis;
unsigned long currentMillis = millis();
if (currentMillis - lastMillis <= waitTime) return;
lastMillis = currentMillis;
if (thermostatConfig.mode == AUTO) {
Serial.printf("Current temperature: %2.1f C (Target temperature: %2.1f C: %s)\r\n", temperature, thermostatConfig.targetTemperature, relayState?"ON":"OFF");
} else {
Serial.printf("Current temperature: %2.1f C (Mode is %s)\r\n", temperature, thermostatConfig.mode == HEAT ? "HEAT" : "COOL");
}
}
/**
* onPowerState()
* if relayState is on and newState is off: turn off relay
* if relayState is OFF and newState is on and mode is HEAT, turn on relay
* save config to eerpom
**/
bool onPowerState(const String& deviceId, bool &newState) {
Serial.printf("Device turned %s\r\n", newState?"ON":"OFF");
thermostatConfig.powerState = newState;
if (relayState == true && newState == false) {
digitalWrite(RELAY_PIN, LOW);
relayState = newState;
}
if (relayState == false && newState == true && thermostatConfig.mode == HEAT) {
digitalWrite(RELAY_PIN, HIGH);
relayState = newState;
}
saveConfig();
return true;
}
/**
* onTargetTemperature()
* set the new targetTemperature and save to eeprom
**/
bool onTargetTemperature(const String& deviceId, float &newTargetTemperature) {
Serial.printf("Target temperature set to %2.0f\r\n", newTargetTemperature);
thermostatConfig.targetTemperature = newTargetTemperature;
saveConfig();
return true;
}
/**
* onThermostatMode()
* set the new mode
* if mode is HEAT and relay is off: turn on relay
* if mode is COOL and relay is on: turn off relay
* save value to EEPROM
*/
bool onThermostatMode(const String& deviceId, const String& mode) {
Serial.printf("Mode changed to %s\r\n", mode.c_str());
if (mode == "AUTO") {
thermostatConfig.mode = AUTO;
}
if (mode == "HEAT") {
thermostatConfig.mode = HEAT;
if (relayState == false) digitalWrite(RELAY_PIN, HIGH);
relayState = true;
}
if (mode == "COOL") {
thermostatConfig.mode = COOL;
if (relayState == true) digitalWrite(RELAY_PIN, LOW);
relayState = false;
}
saveConfig();
return true;
}
void setupWiFi() {
Serial.printf("Connecting to %s", WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
Serial.printf(".");
delay(250);
}
Serial.printf("connected! IP is %s\r\n", WiFi.localIP().toString().c_str());
}
void setupSinricPro() {
myThermostat.onTargetTemperature(onTargetTemperature);
myThermostat.onPowerState(onPowerState);
myThermostat.onThermostatMode(onThermostatMode);
SinricPro.onConnected([](){ Serial.printf("Connected to SinricPro\r\n"); reportTemperature(0); });
SinricPro.onDisconnected([](){ Serial.printf("Disconnected from SinricPro!\r\n"); });
SinricPro.begin(APPKEY, APPSECRET);
}
void setup() {
Serial.begin(921600);
pinMode(LED_BUILTIN, OUTPUT);
EEPROM.begin(sizeof(ThermostatCfg));
loadConfig();
setupWiFi();
setupSinricPro();
}
void loop() {
SinricPro.handle();
handleTemperature();
printTemperature(PRINT_TIME);
reportTemperature(REPORT_TIME);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment