mirror of
https://github.com/xoseperez/espurna.git
synced 2026-03-11 10:47:10 +01:00
Thermostat upgrade (#1711)
* Add "Enable Thermostat" switch * Add heater/cooler thermostat mode
This commit is contained in:
committed by
Max Prokhorov
parent
62a2b9e882
commit
bb33dfd102
Binary file not shown.
5287
code/espurna/static/index.thermostat.html.gz.h
generated
5287
code/espurna/static/index.thermostat.html.gz.h
generated
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,11 @@ Copyright (C) 2017 by Dmitry Blinov <dblinov76 at gmail dot com>
|
||||
#include <ArduinoJson.h>
|
||||
#include <float.h>
|
||||
|
||||
bool _thermostat_enabled = true;
|
||||
bool _thermostat_mode_cooler = false;
|
||||
|
||||
const char* NAME_THERMOSTAT_ENABLED = "thermostatEnabled";
|
||||
const char* NAME_THERMOSTAT_MODE = "thermostatMode";
|
||||
const char* NAME_TEMP_RANGE_MIN = "tempRangeMin";
|
||||
const char* NAME_TEMP_RANGE_MAX = "tempRangeMax";
|
||||
const char* NAME_REMOTE_SENSOR_NAME = "remoteSensorName";
|
||||
@@ -89,6 +94,26 @@ enum thermostat_cycle_type {cooling, heating};
|
||||
unsigned int _thermostat_cycle = heating;
|
||||
String thermostat_remote_sensor_topic;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void thermostatEnabled(bool enabled) {
|
||||
_thermostat_enabled = enabled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool thermostatEnabled() {
|
||||
return _thermostat_enabled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void thermostatModeCooler(bool cooler) {
|
||||
_thermostat_mode_cooler = cooler;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool thermostatModeCooler() {
|
||||
return _thermostat_mode_cooler;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
std::vector<thermostat_callback_f> _thermostat_callbacks;
|
||||
|
||||
@@ -223,6 +248,12 @@ void notifyRangeChanged(bool min) {
|
||||
// Setup
|
||||
//------------------------------------------------------------------------------
|
||||
void commonSetup() {
|
||||
_thermostat_enabled = getSetting(NAME_THERMOSTAT_ENABLED).toInt() == 1;
|
||||
DEBUG_MSG_P(PSTR("[THERMOSTAT] _thermostat_enabled = %d\n"), _thermostat_enabled);
|
||||
|
||||
_thermostat_mode_cooler = getSetting(NAME_THERMOSTAT_MODE).toInt() == 1;
|
||||
DEBUG_MSG_P(PSTR("[THERMOSTAT] _thermostat_mode_cooler = %d\n"), _thermostat_mode_cooler);
|
||||
|
||||
_temp_range.min = getSetting(NAME_TEMP_RANGE_MIN, THERMOSTAT_TEMP_RANGE_MIN).toInt();
|
||||
_temp_range.max = getSetting(NAME_TEMP_RANGE_MAX, THERMOSTAT_TEMP_RANGE_MAX).toInt();
|
||||
DEBUG_MSG_P(PSTR("[THERMOSTAT] _temp_range.min = %d\n"), _temp_range.min);
|
||||
@@ -268,6 +299,8 @@ void _thermostatReload() {
|
||||
#if WEB_SUPPORT
|
||||
//------------------------------------------------------------------------------
|
||||
void _thermostatWebSocketOnSend(JsonObject& root) {
|
||||
root["thermostatEnabled"] = thermostatEnabled();
|
||||
root["thermostatMode"] = thermostatModeCooler();
|
||||
root["thermostatVisible"] = 1;
|
||||
root[NAME_TEMP_RANGE_MIN] = _temp_range.min;
|
||||
root[NAME_TEMP_RANGE_MAX] = _temp_range.max;
|
||||
@@ -296,6 +329,8 @@ void _thermostatWebSocketOnSend(JsonObject& root) {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool _thermostatWebSocketOnReceive(const char * key, JsonVariant& value) {
|
||||
if (strncmp(key, NAME_THERMOSTAT_ENABLED, strlen(NAME_THERMOSTAT_ENABLED)) == 0) return true;
|
||||
if (strncmp(key, NAME_THERMOSTAT_MODE, strlen(NAME_THERMOSTAT_MODE)) == 0) return true;
|
||||
if (strncmp(key, NAME_TEMP_RANGE_MIN, strlen(NAME_TEMP_RANGE_MIN)) == 0) return true;
|
||||
if (strncmp(key, NAME_TEMP_RANGE_MAX, strlen(NAME_TEMP_RANGE_MAX)) == 0) return true;
|
||||
if (strncmp(key, NAME_REMOTE_SENSOR_NAME, strlen(NAME_REMOTE_SENSOR_NAME)) == 0) return true;
|
||||
@@ -353,8 +388,8 @@ void setThermostatState(bool state) {
|
||||
void debugPrintSwitch(bool state, double temp) {
|
||||
char tmp_str[6];
|
||||
dtostrf(temp, 1-sizeof(tmp_str), 1, tmp_str);
|
||||
DEBUG_MSG_P(PSTR("[THERMOSTAT] switch %s, temp: %s, min: %d, max: %d, relay: %s, last switch %d\n"),
|
||||
state ? "ON" : "OFF", tmp_str, _temp_range.min, _temp_range.max, relayStatus(THERMOSTAT_RELAY) ? "ON" : "OFF", millis() - _thermostat.last_switch);
|
||||
DEBUG_MSG_P(PSTR("[THERMOSTAT] switch %s, temp: %s, min: %d, max: %d, mode: %s, relay: %s, last switch %d\n"),
|
||||
state ? "ON" : "OFF", tmp_str, _temp_range.min, _temp_range.max, _thermostat_mode_cooler ? "COOLER" : "HEATER", relayStatus(THERMOSTAT_RELAY) ? "ON" : "OFF", millis() - _thermostat.last_switch);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -372,23 +407,44 @@ inline void switchThermostat(bool state, double temp) {
|
||||
//----------- Main function that make decision ---------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
void checkTempAndAdjustRelay(double temp) {
|
||||
// if thermostat switched ON and t > max - switch it OFF and start cooling
|
||||
if (relayStatus(THERMOSTAT_RELAY) && temp > _temp_range.max) {
|
||||
_thermostat_cycle = cooling;
|
||||
switchThermostat(false, temp);
|
||||
// if thermostat switched ON for max time - switch it OFF for rest
|
||||
} else if (relayStatus(THERMOSTAT_RELAY) && lastSwitchEarlierThan(_thermostat_max_on_time)) {
|
||||
switchThermostat(false, temp);
|
||||
// if t < min and thermostat switched OFF for at least minimum time - switch it ON and start
|
||||
} else if (!relayStatus(THERMOSTAT_RELAY) && temp < _temp_range.min
|
||||
&& (_thermostat.last_switch == 0 || lastSwitchEarlierThan(_thermostat_min_off_time))) {
|
||||
_thermostat_cycle = heating;
|
||||
switchThermostat(true, temp);
|
||||
// if heating cycle and thermostat switchaed OFF for more than min time - switch it ON
|
||||
// continue heating cycle
|
||||
} else if (!relayStatus(THERMOSTAT_RELAY) && _thermostat_cycle == heating
|
||||
&& lastSwitchEarlierThan(_thermostat_min_off_time)) {
|
||||
switchThermostat(true, temp);
|
||||
if (_thermostat_mode_cooler == false) { // Main operation mode. Thermostat is HEATER.
|
||||
// if thermostat switched ON and t > max - switch it OFF and start cooling
|
||||
if (relayStatus(THERMOSTAT_RELAY) && temp > _temp_range.max) {
|
||||
_thermostat_cycle = cooling;
|
||||
switchThermostat(false, temp);
|
||||
// if thermostat switched ON for max time - switch it OFF for rest
|
||||
} else if (relayStatus(THERMOSTAT_RELAY) && lastSwitchEarlierThan(_thermostat_max_on_time)) {
|
||||
switchThermostat(false, temp);
|
||||
// if t < min and thermostat switched OFF for at least minimum time - switch it ON and start
|
||||
} else if (!relayStatus(THERMOSTAT_RELAY) && temp < _temp_range.min
|
||||
&& (_thermostat.last_switch == 0 || lastSwitchEarlierThan(_thermostat_min_off_time))) {
|
||||
_thermostat_cycle = heating;
|
||||
switchThermostat(true, temp);
|
||||
// if heating cycle and thermostat switchaed OFF for more than min time - switch it ON
|
||||
// continue heating cycle
|
||||
} else if (!relayStatus(THERMOSTAT_RELAY) && _thermostat_cycle == heating
|
||||
&& lastSwitchEarlierThan(_thermostat_min_off_time)) {
|
||||
switchThermostat(true, temp);
|
||||
}
|
||||
} else { // Thermostat is COOLER. Inverse logic.
|
||||
// if thermostat switched ON and t < min - switch it OFF and start heating
|
||||
if (relayStatus(THERMOSTAT_RELAY) && temp < _temp_range.min) {
|
||||
_thermostat_cycle = heating;
|
||||
switchThermostat(false, temp);
|
||||
// if thermostat switched ON for max time - switch it OFF for rest
|
||||
} else if (relayStatus(THERMOSTAT_RELAY) && lastSwitchEarlierThan(_thermostat_max_on_time)) {
|
||||
switchThermostat(false, temp);
|
||||
// if t > max and thermostat switched OFF for at least minimum time - switch it ON and start
|
||||
} else if (!relayStatus(THERMOSTAT_RELAY) && temp > _temp_range.max
|
||||
&& (_thermostat.last_switch == 0 || lastSwitchEarlierThan(_thermostat_min_off_time))) {
|
||||
_thermostat_cycle = cooling;
|
||||
switchThermostat(true, temp);
|
||||
// if cooling cycle and thermostat switchaed OFF for more than min time - switch it ON
|
||||
// continue cooling cycle
|
||||
} else if (!relayStatus(THERMOSTAT_RELAY) && _thermostat_cycle == cooling
|
||||
&& lastSwitchEarlierThan(_thermostat_min_off_time)) {
|
||||
switchThermostat(true, temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,6 +516,9 @@ double getLocalHumidity() {
|
||||
//------------------------------------------------------------------------------
|
||||
void thermostatLoop(void) {
|
||||
|
||||
if (!thermostatEnabled())
|
||||
return;
|
||||
|
||||
// Update temperature range
|
||||
if (mqttConnected()) {
|
||||
if (millis() - _temp_range.ask_time > _temp_range.ask_interval) {
|
||||
|
||||
@@ -284,6 +284,9 @@ label[for].toggle {
|
||||
input[name="relay"] + .toggle:before {
|
||||
content: "OFF";
|
||||
}
|
||||
input[name="thermostatMode"] + .toggle:before {
|
||||
content: "Heater";
|
||||
}
|
||||
.toggle:after{
|
||||
content: "YES";
|
||||
right: 20px;
|
||||
@@ -291,6 +294,9 @@ input[name="relay"] + .toggle:before {
|
||||
input[name="relay"] + .toggle:after {
|
||||
content: "ON";
|
||||
}
|
||||
input[name="thermostatMode"] + .toggle:after {
|
||||
content: "Cooler";
|
||||
}
|
||||
.toggle__handler {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
@@ -328,6 +334,9 @@ input:checked + .toggle .toggle__handler {
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
input[name="thermostatMode"]:checked + .toggle .toggle__handler {
|
||||
background: #00c0c0;
|
||||
}
|
||||
input[disabled] + .toggle .toggle__handler {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
@@ -1061,6 +1061,16 @@
|
||||
|
||||
<div class="page">
|
||||
|
||||
<div class="pure-g">
|
||||
<label class="pure-u-1 pure-u-lg-1-4">Enable Thermostat</label>
|
||||
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="thermostatEnabled" tabindex="30" /></div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
<label class="pure-u-1 pure-u-lg-1-4">Thermostat Mode</label>
|
||||
<div class="pure-u-1 pure-u-lg-1-4"><input type="checkbox" name="thermostatMode" tabindex="30" /></div>
|
||||
</div>
|
||||
|
||||
<div class="pure-g">
|
||||
<label class="pure-u-1 pure-u-lg-1-4" for="thermostatOperationMode">Operation mode</label>
|
||||
<input class="pure-u-1 pure-u-lg-1-4" name="thermostatOperationMode" type="text" readonly />
|
||||
|
||||
Reference in New Issue
Block a user