feat: added choice of averaging type for indoor and outdoor temperatures (#244)

* feat: added a choice of averaging type for indoor and outdoor temperatures

* refactor: locales updated

* refactor: some changes
This commit is contained in:
Yurii
2026-05-16 17:58:13 +03:00
committed by GitHub
parent bfc1cc1118
commit db99746ee9
12 changed files with 226 additions and 30 deletions
+1 -1
View File
@@ -225,7 +225,7 @@ protected:
uint8_t availableSensors = 0;
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) {
lowTemp = value;
}
+47 -18
View File
@@ -77,6 +77,12 @@ public:
RSSI = 3
};
enum class AverageType : uint8_t {
MEAN = 0,
MINIMUM = 1,
MAXIMUM = 2
};
typedef struct {
bool enabled = false;
char name[33];
@@ -330,38 +336,61 @@ public:
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, const bool onlyConnected = true, const float defaultValue = NAN) {
if (settings == nullptr || results == nullptr) {
return 0.0f;
return defaultValue;
}
uint8_t valueId = (uint8_t) valueType;
if (!isValidValueId(valueId)) {
return 0.0f;
return defaultValue;
}
float value = 0.0f;
uint8_t amount = 0;
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
auto& sSensor = settings[id];
auto& rSensor = results[id];
if (avgType == AverageType::MEAN) {
float sum = 0.0f;
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
auto& sSensor = settings[id];
auto& rSensor = results[id];
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
value += rSensor.values[valueId];
amount++;
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
sum += rSensor.values[valueId];
amount++;
}
}
value = amount == 1 ? sum : (sum / amount);
} else if (avgType == AverageType::MINIMUM) {
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
auto& sSensor = settings[id];
auto& rSensor = results[id];
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
if (amount == 0 || rSensor.values[valueId] < value) {
value = rSensor.values[valueId];
amount++;
}
}
}
} else if (avgType == AverageType::MAXIMUM) {
for (uint8_t id = 0; id <= getMaxSensorId(); id++) {
auto& sSensor = settings[id];
auto& rSensor = results[id];
if (sSensor.purpose == purpose && (!onlyConnected || rSensor.connected)) {
if (amount == 0 || rSensor.values[valueId] > value) {
value = rSensor.values[valueId];
amount++;
}
}
}
}
if (!amount) {
return 0.0f;
} else if (amount == 1) {
return value;
} else {
return value / amount;
}
return amount > 0 ? value : defaultValue;
}
static bool existsConnectedSensorsByPurpose(Purpose purpose) {
+42 -6
View File
@@ -423,14 +423,50 @@ protected:
}
void updateMasterValues() {
vars.master.heating.outdoorTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::OUTDOOR_TEMP, Sensors::ValueType::PRIMARY);
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,
true,
0.0f
);
vars.master.heating.outdoorTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::OUTDOOR_TEMP,
Sensors::ValueType::PRIMARY,
settings.heating.outdoorTempAvgType,
true,
0.0f
);
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.currentTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::HEATING_TEMP,
Sensors::ValueType::PRIMARY,
Sensors::AverageType::MEAN,
true,
0.0f
);
vars.master.heating.returnTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::HEATING_RETURN_TEMP,
Sensors::ValueType::PRIMARY,
Sensors::AverageType::MEAN,
true,
0.0f
);
vars.master.dhw.currentTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::DHW_TEMP, Sensors::ValueType::PRIMARY);
vars.master.dhw.returnTemp = Sensors::getMeanValueByPurpose(Sensors::Purpose::DHW_RETURN_TEMP, Sensors::ValueType::PRIMARY);
vars.master.dhw.currentTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::DHW_TEMP,
Sensors::ValueType::PRIMARY,
Sensors::AverageType::MEAN,
true,
0.0f
);
vars.master.dhw.returnTemp = Sensors::getMeanValueByPurpose(
Sensors::Purpose::DHW_RETURN_TEMP,
Sensors::ValueType::PRIMARY,
Sensors::AverageType::MEAN,
true,
0.0f
);
}
void makeDallasInstances() {
+2
View File
@@ -107,6 +107,8 @@ struct Settings {
uint8_t minTemp = DEFAULT_HEATING_MIN_TEMP;
uint8_t maxTemp = DEFAULT_HEATING_MAX_TEMP;
uint8_t maxModulation = 100;
Sensors::AverageType indoorTempAvgType = Sensors::AverageType::MEAN;
Sensors::AverageType outdoorTempAvgType = Sensors::AverageType::MEAN;
struct {
bool enabled = true;
+2
View File
@@ -115,6 +115,7 @@ const char S_IGNORE_DIAG_STATE[] PROGMEM = "ignoreDiagState";
const char S_IMMERGAS_FIX[] PROGMEM = "immergasFix";
const char S_ALWAYS_SEND_INDOOR_TEMP[] PROGMEM = "alwaysSendIndoorTemp";
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_IN_GPIO[] PROGMEM = "inGpio";
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_OPTIONS[] PROGMEM = "options";
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_OUTPUT[] PROGMEM = "output";
const char S_OVERHEAT[] PROGMEM = "overheat";
+38
View File
@@ -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_MAX_TEMP)] = src.heating.maxTemp;
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>();
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()) {
unsigned char value = src[FPSTR(S_HEATING)][FPSTR(S_OVERHEAT_PROTECTION)][FPSTR(S_HIGH_TEMP)].as<unsigned char>();