mirror of
https://github.com/Laxilef/OTGateway.git
synced 2026-05-16 14:28:16 +05:00
feat: added a choice of averaging type for indoor and outdoor temperatures
This commit is contained in:
+1
-1
@@ -225,7 +225,7 @@ protected:
|
|||||||
uint8_t availableSensors = 0;
|
uint8_t availableSensors = 0;
|
||||||
|
|
||||||
if (Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::INDOOR_TEMP)) {
|
if (Sensors::existsConnectedSensorsByPurpose(Sensors::Purpose::INDOOR_TEMP)) {
|
||||||
auto value = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY);
|
auto value = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY, settings.heating.indoorTempAvgType);
|
||||||
if (value < lowTemp) {
|
if (value < lowTemp) {
|
||||||
lowTemp = value;
|
lowTemp = value;
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-1
@@ -77,6 +77,12 @@ public:
|
|||||||
RSSI = 3
|
RSSI = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class AverageType : uint8_t {
|
||||||
|
MEAN = 0,
|
||||||
|
MINIMUM = 1,
|
||||||
|
MAXIMUM = 2
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
char name[33];
|
char name[33];
|
||||||
@@ -330,7 +336,7 @@ public:
|
|||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float getMeanValueByPurpose(Purpose purpose, const ValueType valueType, bool onlyConnected = true) {
|
static float getMeanValueByPurpose(Purpose purpose, const ValueType valueType, const AverageType avgType = AverageType::MEAN, bool onlyConnected = true) {
|
||||||
if (settings == nullptr || results == nullptr) {
|
if (settings == nullptr || results == nullptr) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
@@ -340,6 +346,7 @@ public:
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (avgType == AverageType::MEAN) {
|
||||||
float value = 0.0f;
|
float value = 0.0f;
|
||||||
uint8_t amount = 0;
|
uint8_t amount = 0;
|
||||||
|
|
||||||
@@ -362,6 +369,43 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
return value / amount;
|
return value / amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (avgType == AverageType::MINIMUM) {
|
||||||
|
float value = NAN;
|
||||||
|
|
||||||
|
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
|
||||||
|
auto& sSensor = settings[id];
|
||||||
|
auto& rSensor = results[id];
|
||||||
|
|
||||||
|
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
|
||||||
|
if (value == NAN || rSensor.values[valueId] < value) {
|
||||||
|
value = rSensor.values[valueId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value != NAN ? value : 0.0f;
|
||||||
|
|
||||||
|
} else if (avgType == AverageType::MAXIMUM) {
|
||||||
|
float value = NAN;
|
||||||
|
|
||||||
|
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
|
||||||
|
auto& sSensor = settings[id];
|
||||||
|
auto& rSensor = results[id];
|
||||||
|
|
||||||
|
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
|
||||||
|
if (value == NAN || rSensor.values[valueId] > value) {
|
||||||
|
value = rSensor.values[valueId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value != NAN ? value : 0.0f;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// bad mean type
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool existsConnectedSensorsByPurpose(Purpose purpose) {
|
static bool existsConnectedSensorsByPurpose(Purpose purpose) {
|
||||||
|
|||||||
+2
-2
@@ -423,8 +423,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateMasterValues() {
|
void updateMasterValues() {
|
||||||
vars.master.heating.outdoorTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::OUTDOOR_TEMP, Sensors::ValueType::PRIMARY);
|
vars.master.heating.outdoorTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::OUTDOOR_TEMP, Sensors::ValueType::PRIMARY, settings.heating.outdoorTempAvgType);
|
||||||
vars.master.heating.indoorTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY);
|
vars.master.heating.indoorTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::INDOOR_TEMP, Sensors::ValueType::PRIMARY, settings.heating.indoorTempAvgType);
|
||||||
|
|
||||||
vars.master.heating.currentTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::HEATING_TEMP, Sensors::ValueType::PRIMARY);
|
vars.master.heating.currentTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::HEATING_TEMP, Sensors::ValueType::PRIMARY);
|
||||||
vars.master.heating.returnTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::HEATING_RETURN_TEMP, Sensors::ValueType::PRIMARY);
|
vars.master.heating.returnTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::HEATING_RETURN_TEMP, Sensors::ValueType::PRIMARY);
|
||||||
|
|||||||
@@ -107,6 +107,8 @@ struct Settings {
|
|||||||
uint8_t minTemp = DEFAULT_HEATING_MIN_TEMP;
|
uint8_t minTemp = DEFAULT_HEATING_MIN_TEMP;
|
||||||
uint8_t maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
uint8_t maxTemp = DEFAULT_HEATING_MAX_TEMP;
|
||||||
uint8_t maxModulation = 100;
|
uint8_t maxModulation = 100;
|
||||||
|
Sensors::AverageType indoorTempAvgType = Sensors::AverageType::MEAN;
|
||||||
|
Sensors::AverageType outdoorTempAvgType = Sensors::AverageType::MEAN;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ const char S_IGNORE_DIAG_STATE[] PROGMEM = "ignoreDiagState";
|
|||||||
const char S_IMMERGAS_FIX[] PROGMEM = "immergasFix";
|
const char S_IMMERGAS_FIX[] PROGMEM = "immergasFix";
|
||||||
const char S_ALWAYS_SEND_INDOOR_TEMP[] PROGMEM = "alwaysSendIndoorTemp";
|
const char S_ALWAYS_SEND_INDOOR_TEMP[] PROGMEM = "alwaysSendIndoorTemp";
|
||||||
const char S_INDOOR_TEMP[] PROGMEM = "indoorTemp";
|
const char S_INDOOR_TEMP[] PROGMEM = "indoorTemp";
|
||||||
|
const char S_INDOOR_TEMP_AVG_TYPE[] PROGMEM = "indoorTempAvgType";
|
||||||
const char S_INDOOR_TEMP_CONTROL[] PROGMEM = "indoorTempControl";
|
const char S_INDOOR_TEMP_CONTROL[] PROGMEM = "indoorTempControl";
|
||||||
const char S_IN_GPIO[] PROGMEM = "inGpio";
|
const char S_IN_GPIO[] PROGMEM = "inGpio";
|
||||||
const char S_INPUT[] PROGMEM = "input";
|
const char S_INPUT[] PROGMEM = "input";
|
||||||
@@ -155,6 +156,7 @@ const char S_ON_LOSS_CONNECTION[] PROGMEM = "onLossConnection"
|
|||||||
const char S_OPENTHERM[] PROGMEM = "opentherm";
|
const char S_OPENTHERM[] PROGMEM = "opentherm";
|
||||||
const char S_OPTIONS[] PROGMEM = "options";
|
const char S_OPTIONS[] PROGMEM = "options";
|
||||||
const char S_OUTDOOR_TEMP[] PROGMEM = "outdoorTemp";
|
const char S_OUTDOOR_TEMP[] PROGMEM = "outdoorTemp";
|
||||||
|
const char S_OUTDOOR_TEMP_AVG_TYPE[] PROGMEM = "outdoorTempAvgType";
|
||||||
const char S_OUT_GPIO[] PROGMEM = "outGpio";
|
const char S_OUT_GPIO[] PROGMEM = "outGpio";
|
||||||
const char S_OUTPUT[] PROGMEM = "output";
|
const char S_OUTPUT[] PROGMEM = "output";
|
||||||
const char S_OVERHEAT[] PROGMEM = "overheat";
|
const char S_OVERHEAT[] PROGMEM = "overheat";
|
||||||
|
|||||||
+38
@@ -498,6 +498,8 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
|
|||||||
heating[FPSTR(S_MIN_TEMP)] = src.heating.minTemp;
|
heating[FPSTR(S_MIN_TEMP)] = src.heating.minTemp;
|
||||||
heating[FPSTR(S_MAX_TEMP)] = src.heating.maxTemp;
|
heating[FPSTR(S_MAX_TEMP)] = src.heating.maxTemp;
|
||||||
heating[FPSTR(S_MAX_MODULATION)] = src.heating.maxModulation;
|
heating[FPSTR(S_MAX_MODULATION)] = src.heating.maxModulation;
|
||||||
|
heating[FPSTR(S_INDOOR_TEMP_AVG_TYPE)] = static_cast<uint8_t>(src.heating.indoorTempAvgType);
|
||||||
|
heating[FPSTR(S_OUTDOOR_TEMP_AVG_TYPE)] = static_cast<uint8_t>(src.heating.outdoorTempAvgType);
|
||||||
|
|
||||||
auto heatingOverheatProtection = heating[FPSTR(S_OVERHEAT_PROTECTION)].to<JsonObject>();
|
auto heatingOverheatProtection = heating[FPSTR(S_OVERHEAT_PROTECTION)].to<JsonObject>();
|
||||||
heatingOverheatProtection[FPSTR(S_HIGH_TEMP)] = src.heating.overheatProtection.highTemp;
|
heatingOverheatProtection[FPSTR(S_HIGH_TEMP)] = src.heating.overheatProtection.highTemp;
|
||||||
@@ -1393,6 +1395,42 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!src[FPSTR(S_HEATING)][FPSTR(S_INDOOR_TEMP_AVG_TYPE)].isNull()) {
|
||||||
|
uint8_t value = src[FPSTR(S_HEATING)][FPSTR(S_INDOOR_TEMP_AVG_TYPE)].as<uint8_t>();
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case static_cast<uint8_t>(Sensors::AverageType::MEAN):
|
||||||
|
case static_cast<uint8_t>(Sensors::AverageType::MINIMUM):
|
||||||
|
case static_cast<uint8_t>(Sensors::AverageType::MAXIMUM):
|
||||||
|
if (static_cast<uint8_t>(dst.heating.indoorTempAvgType) != value) {
|
||||||
|
dst.heating.indoorTempAvgType = static_cast<Sensors::AverageType>(value);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src[FPSTR(S_HEATING)][FPSTR(S_OUTDOOR_TEMP_AVG_TYPE)].isNull()) {
|
||||||
|
uint8_t value = src[FPSTR(S_HEATING)][FPSTR(S_OUTDOOR_TEMP_AVG_TYPE)].as<uint8_t>();
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case static_cast<uint8_t>(Sensors::AverageType::MEAN):
|
||||||
|
case static_cast<uint8_t>(Sensors::AverageType::MINIMUM):
|
||||||
|
case static_cast<uint8_t>(Sensors::AverageType::MAXIMUM):
|
||||||
|
if (static_cast<uint8_t>(dst.heating.outdoorTempAvgType) != value) {
|
||||||
|
dst.heating.outdoorTempAvgType = static_cast<Sensors::AverageType>(value);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!src[FPSTR(S_HEATING)][FPSTR(S_OVERHEAT_PROTECTION)][FPSTR(S_HIGH_TEMP)].isNull()) {
|
if (!src[FPSTR(S_HEATING)][FPSTR(S_OVERHEAT_PROTECTION)][FPSTR(S_HIGH_TEMP)].isNull()) {
|
||||||
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_OVERHEAT_PROTECTION)][FPSTR(S_HIGH_TEMP)].as<unsigned char>();
|
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_OVERHEAT_PROTECTION)][FPSTR(S_HIGH_TEMP)].as<unsigned char>();
|
||||||
|
|
||||||
|
|||||||
@@ -315,6 +315,11 @@
|
|||||||
"min": "Minimum temperature",
|
"min": "Minimum temperature",
|
||||||
"max": "Maximum temperature"
|
"max": "Maximum temperature"
|
||||||
},
|
},
|
||||||
|
"avgType": {
|
||||||
|
"mean": "Mean temperature",
|
||||||
|
"min": "Minimum temperature",
|
||||||
|
"max": "Maximum temperature"
|
||||||
|
},
|
||||||
"maxModulation": "Max modulation level",
|
"maxModulation": "Max modulation level",
|
||||||
"ohProtection": {
|
"ohProtection": {
|
||||||
"title": "Overheating protection",
|
"title": "Overheating protection",
|
||||||
@@ -379,7 +384,15 @@
|
|||||||
"set0target": "Set null target"
|
"set0target": "Set null target"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"turboFactor": "Turbo mode coeff."
|
"turboFactor": "Turbo mode coeff.",
|
||||||
|
"indoorTempAvgType": {
|
||||||
|
"title": "Indoor temp. averaging type",
|
||||||
|
"desc": "May be useful when using two or more indoor temp. sensors (when using «Equitherm» and/or «PID»)."
|
||||||
|
},
|
||||||
|
"outdoorTempAvgType": {
|
||||||
|
"title": "Outdoor temp. averaging type",
|
||||||
|
"desc": "May be useful when using two or more outdoor temp. sensors (when using «Equitherm»)."
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"emergency": {
|
"emergency": {
|
||||||
|
|||||||
@@ -198,6 +198,28 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="grid">
|
||||||
|
<label>
|
||||||
|
<span data-i18n>settings.heating.indoorTempAvgType.title</span>
|
||||||
|
<select name="heating[indoorTempAvgType]">
|
||||||
|
<option value="0" data-i18n>settings.avgType.mean</option>
|
||||||
|
<option value="1" data-i18n>settings.avgType.min</option>
|
||||||
|
<option value="2" data-i18n>settings.avgType.max</option>
|
||||||
|
</select>
|
||||||
|
<small data-i18n>settings.heating.indoorTempAvgType.desc</small>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<span data-i18n>settings.heating.outdoorTempAvgType.title</span>
|
||||||
|
<select name="heating[outdoorTempAvgType]">
|
||||||
|
<option value="0" data-i18n>settings.avgType.mean</option>
|
||||||
|
<option value="1" data-i18n>settings.avgType.min</option>
|
||||||
|
<option value="2" data-i18n>settings.avgType.max</option>
|
||||||
|
</select>
|
||||||
|
<small data-i18n>settings.heating.outdoorTempAvgType.desc</small>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
@@ -1171,6 +1193,8 @@
|
|||||||
setSelectValue("[name='heating[hysteresis][action]']", data.heating.hysteresis.action);
|
setSelectValue("[name='heating[hysteresis][action]']", data.heating.hysteresis.action);
|
||||||
setInputValue("[name='heating[turboFactor]']", data.heating.turboFactor);
|
setInputValue("[name='heating[turboFactor]']", data.heating.turboFactor);
|
||||||
setInputValue("[name='heating[maxModulation]']", data.heating.maxModulation);
|
setInputValue("[name='heating[maxModulation]']", data.heating.maxModulation);
|
||||||
|
setSelectValue("[name='heating[indoorTempAvgType]']", data.heating.indoorTempAvgType);
|
||||||
|
setSelectValue("[name='heating[outdoorTempAvgType]']", data.heating.outdoorTempAvgType);
|
||||||
setInputValue("[name='heating[overheatProtection][highTemp]']", data.heating.overheatProtection.highTemp, {
|
setInputValue("[name='heating[overheatProtection][highTemp]']", data.heating.overheatProtection.highTemp, {
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": data.system.unitSystem == 0 ? 100 : 212
|
"max": data.system.unitSystem == 0 ? 100 : 212
|
||||||
|
|||||||
Reference in New Issue
Block a user