feat: added unit system selection

This commit is contained in:
Yurii
2024-03-20 02:37:20 +03:00
parent 9e3ef7a465
commit 2f4dbcc205
10 changed files with 420 additions and 100 deletions

View File

@@ -62,6 +62,18 @@
<div id="opentherm-settings-busy" aria-busy="true"></div>
<form action="/api/settings" id="opentherm-settings" class="hidden">
<fieldset>
<legend>Unit system</legend>
<label>
<input type="radio" class="opentherm-unit-system" name="opentherm[unitSystem]" value="0" />
Metric (celsius)
</label>
<label>
<input type="radio" class="opentherm-unit-system" name="opentherm[unitSystem]" value="1" />
Imperial (fahrenheit)
</label>
</fieldset>
<div class="grid">
<label for="opentherm-in-gpio">
In GPIO
@@ -298,6 +310,18 @@
<div id="system-settings-busy" aria-busy="true"></div>
<form action="/api/settings" id="system-settings" class="hidden">
<fieldset>
<legend>Unit system</legend>
<label>
<input type="radio" class="system-unit-system" name="system[unitSystem]" value="0" />
Metric (celsius)
</label>
<label>
<input type="radio" class="system-unit-system" name="system[unitSystem]" value="1" />
Imperial (fahrenheit)
</label>
</fieldset>
<fieldset>
<label for="system-debug">
<input type="checkbox" class="system-debug" name="system[debug]" value="true">

View File

@@ -33,6 +33,8 @@ const char HA_AVAILABILITY_MODE[] PROGMEM = "availability_mode";
const char HA_TOPIC[] PROGMEM = "topic";
const char HA_DEVICE_CLASS[] PROGMEM = "device_class";
const char HA_UNIT_OF_MEASUREMENT[] PROGMEM = "unit_of_measurement";
const char HA_UNIT_OF_MEASUREMENT_C[] PROGMEM = "°C";
const char HA_UNIT_OF_MEASUREMENT_F[] PROGMEM = "°F";
const char HA_ICON[] PROGMEM = "icon";
const char HA_MIN[] PROGMEM = "min";
const char HA_MAX[] PROGMEM = "max";

View File

@@ -27,14 +27,21 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("emergency")).c_str(), doc);
}
bool publishNumberEmergencyTarget(bool enabledByDefault = true) {
bool publishNumberEmergencyTarget(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("emergency_target"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("emergency_target"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Emergency target temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-alert");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -142,7 +149,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("heating_turbo")).c_str(), doc);
}
bool publishNumberHeatingTarget(byte minTemp = 20, byte maxTemp = 90, bool enabledByDefault = true) {
bool publishNumberHeatingTarget(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 20, byte maxTemp = 90, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -150,7 +157,14 @@ public:
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_target"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Heating target");
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -167,14 +181,21 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_target")).c_str(), doc);
}
bool publishNumberHeatingHysteresis(bool enabledByDefault = true) {
bool publishNumberHeatingHysteresis(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_hysteresis"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_hysteresis"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Heating hysteresis");
doc[FPSTR(HA_ICON)] = F("mdi:altimeter");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -191,7 +212,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_hysteresis")).c_str(), doc);
}
bool publishSensorHeatingSetpoint(bool enabledByDefault = true) {
bool publishSensorHeatingSetpoint(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -200,7 +221,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Heating setpoint");
doc[FPSTR(HA_ICON)] = F("mdi:coolant-temperature");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -211,7 +239,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("heating_setpoint")).c_str(), doc);
}
bool publishSensorBoilerHeatingMinTemp(bool enabledByDefault = true) {
bool publishSensorBoilerHeatingMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -223,7 +251,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Boiler heating min temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -234,7 +269,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_heating_min_temp")).c_str(), doc);
}
bool publishSensorBoilerHeatingMaxTemp(bool enabledByDefault = true) {
bool publishSensorBoilerHeatingMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -246,7 +281,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Boiler heating max temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -257,14 +299,21 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_heating_max_temp")).c_str(), doc);
}
bool publishNumberHeatingMinTemp(bool enabledByDefault = true) {
bool publishNumberHeatingMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_min_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_min_temp"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Heating min temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -281,14 +330,21 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("heating_min_temp")).c_str(), doc);
}
bool publishNumberHeatingMaxTemp(bool enabledByDefault = true) {
bool publishNumberHeatingMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_max_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_max_temp"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Heating max temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -352,7 +408,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SWITCH), F("dhw")).c_str(), doc);
}
bool publishNumberDhwTarget(byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
bool publishNumberDhwTarget(UnitSystem unit = UnitSystem::METRIC, byte minTemp = 40, byte maxTemp = 60, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -360,7 +416,14 @@ public:
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_target"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("DHW target");
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -377,7 +440,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("dhw_target")).c_str(), doc);
}
bool publishSensorBoilerDhwMinTemp(bool enabledByDefault = true) {
bool publishSensorBoilerDhwMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -389,7 +452,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Boiler DHW min temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -400,7 +470,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_dhw_min_temp")).c_str(), doc);
}
bool publishSensorBoilerDhwMaxTemp(bool enabledByDefault = true) {
bool publishSensorBoilerDhwMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -412,7 +482,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Boiler DHW max temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -423,14 +500,21 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("boiler_dhw_max_temp")).c_str(), doc);
}
bool publishNumberDhwMinTemp(bool enabledByDefault = true) {
bool publishNumberDhwMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_min_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_min_temp"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("DHW min temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -447,14 +531,21 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("dhw_min_temp")).c_str(), doc);
}
bool publishNumberDhwMaxTemp(bool enabledByDefault = true) {
bool publishNumberDhwMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_max_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_max_temp"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("DHW max temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -579,14 +670,21 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("pid_dt")).c_str(), doc);
}
bool publishNumberPidMinTemp(bool enabledByDefault = true) {
bool publishNumberPidMinTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pid_min_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pid_min_temp"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("PID min temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-down");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -603,14 +701,21 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("pid_min_temp")).c_str(), doc);
}
bool publishNumberPidMaxTemp(bool enabledByDefault = true) {
bool publishNumberPidMaxTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pid_max_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pid_max_temp"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("PID max temp");
doc[FPSTR(HA_ICON)] = F("mdi:thermometer-chevron-up");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
@@ -1027,13 +1132,20 @@ public:
}
bool publishNumberIndoorTemp(bool enabledByDefault = true) {
bool publishNumberIndoorTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("indoor_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("indoor_temp"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Indoor temperature");
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -1050,7 +1162,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("indoor_temp")).c_str(), doc);
}
bool publishSensorIndoorTemp(bool enabledByDefault = true) {
bool publishSensorIndoorTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -1059,7 +1171,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Indoor temperature");
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -1070,13 +1189,20 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("indoor_temp")).c_str(), doc);
}
bool publishNumberOutdoorTemp(bool enabledByDefault = true) {
bool publishNumberOutdoorTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("outdoor_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("outdoor_temp"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Outdoor temperature");
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -1093,7 +1219,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("outdoor_temp")).c_str(), doc);
}
bool publishSensorOutdoorTemp(bool enabledByDefault = true) {
bool publishSensorOutdoorTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -1102,7 +1228,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Outdoor temperature");
doc[FPSTR(HA_ICON)] = F("mdi:home-thermometer-outline");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -1113,7 +1246,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("outdoor_temp")).c_str(), doc);
}
bool publishSensorHeatingTemp(bool enabledByDefault = true) {
bool publishSensorHeatingTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -1125,7 +1258,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("Heating temperature");
doc[FPSTR(HA_ICON)] = F("mdi:radiator");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -1136,7 +1276,7 @@ public:
return this->publish(this->getTopic(FPSTR(HA_ENTITY_SENSOR), F("heating_temp")).c_str(), doc);
}
bool publishSensorDhwTemp(bool enabledByDefault = true) {
bool publishSensorDhwTemp(UnitSystem unit = UnitSystem::METRIC, bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
@@ -1148,7 +1288,14 @@ public:
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("diagnostic");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_STATE_CLASS)] = F("measurement");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
if (unit == UnitSystem::METRIC) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_C);
} else if (unit == UnitSystem::IMPERIAL) {
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = FPSTR(HA_UNIT_OF_MEASUREMENT_F);
}
doc[FPSTR(HA_NAME)] = F("DHW temperature");
doc[FPSTR(HA_ICON)] = F("mdi:water-pump");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("state"));

View File

@@ -326,11 +326,11 @@ protected:
this->haHelper->publishSwitchHeating(false);
this->haHelper->publishSwitchHeatingTurbo();
this->haHelper->publishNumberHeatingHysteresis();
this->haHelper->publishSensorHeatingSetpoint(false);
this->haHelper->publishSensorBoilerHeatingMinTemp(false);
this->haHelper->publishSensorBoilerHeatingMaxTemp(false);
this->haHelper->publishNumberHeatingMinTemp(false);
this->haHelper->publishNumberHeatingMaxTemp(false);
this->haHelper->publishSensorHeatingSetpoint(settings.system.unitSystem, false);
this->haHelper->publishSensorBoilerHeatingMinTemp(settings.system.unitSystem, false);
this->haHelper->publishSensorBoilerHeatingMaxTemp(settings.system.unitSystem, false);
this->haHelper->publishNumberHeatingMinTemp(settings.system.unitSystem, false);
this->haHelper->publishNumberHeatingMaxTemp(settings.system.unitSystem, false);
this->haHelper->publishNumberHeatingMaxModulation(false);
// pid
@@ -339,8 +339,8 @@ protected:
this->haHelper->publishNumberPidFactorI();
this->haHelper->publishNumberPidFactorD();
this->haHelper->publishNumberPidDt(false);
this->haHelper->publishNumberPidMinTemp(false);
this->haHelper->publishNumberPidMaxTemp(false);
this->haHelper->publishNumberPidMinTemp(settings.system.unitSystem, false);
this->haHelper->publishNumberPidMaxTemp(settings.system.unitSystem, false);
// equitherm
this->haHelper->publishSwitchEquitherm();
@@ -383,20 +383,33 @@ protected:
bool published = false;
bool isStupidMode = !settings.pid.enable && !settings.equitherm.enable;
byte heatingMinTemp = isStupidMode ? settings.heating.minTemp : 10;
byte heatingMaxTemp = isStupidMode ? settings.heating.maxTemp : 30;
byte heatingMinTemp = 0;
byte heatingMaxTemp = 90;
bool editableOutdoorTemp = settings.sensors.outdoor.type == SensorType::MANUAL;
bool editableIndoorTemp = settings.sensors.indoor.type == SensorType::MANUAL;
if (isStupidMode) {
heatingMinTemp = settings.heating.minTemp;
heatingMaxTemp = settings.heating.maxTemp;
} else if (settings.system.unitSystem == UnitSystem::METRIC) {
heatingMinTemp = 5;
heatingMaxTemp = 30;
} else if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
heatingMinTemp = 41;
heatingMaxTemp = 86;
}
if (force || _dhwPresent != settings.opentherm.dhwPresent) {
_dhwPresent = settings.opentherm.dhwPresent;
if (_dhwPresent) {
this->haHelper->publishSwitchDhw(false);
this->haHelper->publishSensorBoilerDhwMinTemp(false);
this->haHelper->publishSensorBoilerDhwMaxTemp(false);
this->haHelper->publishNumberDhwMinTemp(false);
this->haHelper->publishNumberDhwMaxTemp(false);
this->haHelper->publishSensorBoilerDhwMinTemp(settings.system.unitSystem, false);
this->haHelper->publishSensorBoilerDhwMaxTemp(settings.system.unitSystem, false);
this->haHelper->publishNumberDhwMinTemp(settings.system.unitSystem, false);
this->haHelper->publishNumberDhwMaxTemp(settings.system.unitSystem, false);
this->haHelper->publishBinSensorDhw();
this->haHelper->publishSensorDhwTemp();
this->haHelper->publishSensorDhwFlowRate(false);
@@ -426,7 +439,7 @@ protected:
_heatingMaxTemp = heatingMaxTemp;
_isStupidMode = isStupidMode;
this->haHelper->publishNumberHeatingTarget(heatingMinTemp, heatingMaxTemp, false);
this->haHelper->publishNumberHeatingTarget(settings.system.unitSystem, heatingMinTemp, heatingMaxTemp, false);
this->haHelper->publishClimateHeating(
heatingMinTemp,
heatingMaxTemp,
@@ -450,7 +463,7 @@ protected:
_dhwMinTemp = settings.dhw.minTemp;
_dhwMaxTemp = settings.dhw.maxTemp;
this->haHelper->publishNumberDhwTarget(settings.dhw.minTemp, settings.dhw.maxTemp, false);
this->haHelper->publishNumberDhwTarget(settings.system.unitSystem, settings.dhw.minTemp, settings.dhw.maxTemp, false);
this->haHelper->publishClimateDhw(settings.dhw.minTemp, settings.dhw.maxTemp);
published = true;

View File

@@ -325,7 +325,7 @@ protected:
// Update DHW temp
byte newDhwTemp = settings.dhw.target;
if (settings.opentherm.dhwPresent && settings.dhw.enable && (needSetDhwTemp() || newDhwTemp != currentDhwTemp)) {
if (settings.opentherm.dhwPresent && settings.dhw.enable && (this->needSetDhwTemp() || newDhwTemp != currentDhwTemp)) {
if (newDhwTemp < settings.dhw.minTemp || newDhwTemp > settings.dhw.maxTemp) {
newDhwTemp = constrain(newDhwTemp, settings.dhw.minTemp, settings.dhw.maxTemp);
}
@@ -333,7 +333,7 @@ protected:
Log.sinfoln(FPSTR(L_OT_DHW), F("Set temp = %u"), newDhwTemp);
// Set DHW temp
if (this->instance->setDhwTemp(newDhwTemp)) {
if (this->instance->setDhwTemp(tempTo(newDhwTemp))) {
currentDhwTemp = newDhwTemp;
this->dhwSetTempTime = millis();
@@ -343,7 +343,7 @@ protected:
// Set DHW temp to CH2
if (settings.opentherm.dhwToCh2) {
if (!this->instance->setHeatingCh2Temp(newDhwTemp)) {
if (!this->instance->setHeatingCh2Temp(tempTo(newDhwTemp))) {
Log.swarningln(FPSTR(L_OT_DHW), F("Failed set ch2 temp"));
}
}
@@ -351,11 +351,11 @@ protected:
// Update heating temp
if (heatingEnabled && (needSetHeatingTemp() || fabs(vars.parameters.heatingSetpoint - currentHeatingTemp) > 0.0001)) {
if (heatingEnabled && (this->needSetHeatingTemp() || fabs(vars.parameters.heatingSetpoint - currentHeatingTemp) > 0.0001)) {
Log.sinfoln(FPSTR(L_OT_HEATING), F("Set temp = %u"), vars.parameters.heatingSetpoint);
// Set heating temp
if (this->instance->setHeatingCh1Temp(vars.parameters.heatingSetpoint)) {
if (this->instance->setHeatingCh1Temp(tempTo(vars.parameters.heatingSetpoint))) {
currentHeatingTemp = vars.parameters.heatingSetpoint;
this->heatingSetTempTime = millis();
@@ -365,7 +365,7 @@ protected:
// Set heating temp to CH2
if (settings.opentherm.heatingCh1ToCh2) {
if (!this->instance->setHeatingCh2Temp(vars.parameters.heatingSetpoint)) {
if (!this->instance->setHeatingCh2Temp(tempTo(vars.parameters.heatingSetpoint))) {
Log.swarningln(FPSTR(L_OT_HEATING), F("Failed set ch2 temp"));
}
}
@@ -390,7 +390,7 @@ protected:
void initialize() {
// Not all boilers support these, only try once when the boiler becomes connected
if (updateSlaveVersion()) {
if (this->updateSlaveVersion()) {
Log.straceln(FPSTR(L_OT), F("Slave version: %u, type: %u"), vars.parameters.slaveVersion, vars.parameters.slaveType);
} else {
@@ -398,21 +398,21 @@ protected:
}
// 0x013F
if (setMasterVersion(0x3F, 0x01)) {
if (this->setMasterVersion(0x3F, 0x01)) {
Log.straceln(FPSTR(L_OT), F("Master version: %u, type: %u"), vars.parameters.masterVersion, vars.parameters.masterType);
} else {
Log.swarningln(FPSTR(L_OT), F("Set master version failed"));
}
if (updateSlaveConfig()) {
if (this->updateSlaveConfig()) {
Log.straceln(FPSTR(L_OT), F("Slave member id: %u, flags: %u"), vars.parameters.slaveMemberId, vars.parameters.slaveFlags);
} else {
Log.swarningln(FPSTR(L_OT), F("Get slave config failed"));
}
if (setMasterConfig(settings.opentherm.memberIdCode & 0xFF, (settings.opentherm.memberIdCode & 0xFFFF) >> 8)) {
if (this->setMasterConfig(settings.opentherm.memberIdCode & 0xFF, (settings.opentherm.memberIdCode & 0xFFFF) >> 8)) {
Log.straceln(FPSTR(L_OT), F("Master member id: %u, flags: %u"), vars.parameters.masterMemberId, vars.parameters.masterFlags);
} else {
@@ -598,8 +598,8 @@ protected:
byte maxTemp = (response & 0xFFFF) >> 8;
if (minTemp >= 0 && maxTemp > 0 && maxTemp > minTemp) {
vars.parameters.dhwMinTemp = minTemp;
vars.parameters.dhwMaxTemp = maxTemp;
vars.parameters.dhwMinTemp = tempFrom(minTemp);
vars.parameters.dhwMaxTemp = tempFrom(maxTemp);
return true;
}
@@ -622,8 +622,8 @@ protected:
byte maxTemp = (response & 0xFFFF) >> 8;
if (minTemp >= 0 && maxTemp > 0 && maxTemp > minTemp) {
vars.parameters.heatingMinTemp = minTemp;
vars.parameters.heatingMaxTemp = maxTemp;
vars.parameters.heatingMinTemp = tempFrom(minTemp);
vars.parameters.heatingMaxTemp = tempFrom(maxTemp);
return true;
}
@@ -634,7 +634,7 @@ protected:
unsigned long response = this->instance->sendRequest(CustomOpenTherm::buildRequest(
OpenThermMessageType::WRITE_DATA,
OpenThermMessageID::MaxTSet,
CustomOpenTherm::temperatureToData(value)
CustomOpenTherm::temperatureToData(tempTo(value))
));
return CustomOpenTherm::isValidResponse(response);
@@ -651,7 +651,9 @@ protected:
return false;
}
vars.temperatures.outdoor = CustomOpenTherm::getFloat(response) + settings.sensors.outdoor.offset;
float value = CustomOpenTherm::getFloat(response);
vars.temperatures.outdoor = tempFrom(value) + settings.sensors.outdoor.offset;
return true;
}
@@ -671,7 +673,7 @@ protected:
return false;
}
vars.temperatures.heating = value;
vars.temperatures.heating = tempFrom(value);
return true;
}
@@ -692,7 +694,7 @@ protected:
return false;
}
vars.temperatures.dhw = value;
vars.temperatures.dhw = tempFrom(value);
return true;
}
@@ -771,4 +773,26 @@ protected:
return true;
}
static float tempTo(float value) {
if (settings.system.unitSystem == UnitSystem::METRIC && settings.opentherm.unitSystem == UnitSystem::IMPERIAL) {
value = c2f(value);
} else if (settings.system.unitSystem == UnitSystem::IMPERIAL && settings.opentherm.unitSystem == UnitSystem::METRIC) {
value = f2c(value);
}
return value;
}
static float tempFrom(float value) {
if (settings.system.unitSystem == UnitSystem::METRIC && settings.opentherm.unitSystem == UnitSystem::IMPERIAL) {
value = f2c(value);
} else if (settings.system.unitSystem == UnitSystem::IMPERIAL && settings.opentherm.unitSystem == UnitSystem::METRIC) {
value = c2f(value);
}
return value;
}
};

View File

@@ -69,7 +69,7 @@ protected:
}
}
// Ограничиваем, если до этого не ограничило
// Limits
if (newTemp < settings.heating.minTemp || newTemp > settings.heating.maxTemp) {
newTemp = constrain(newTemp, settings.heating.minTemp, settings.heating.maxTemp);
}
@@ -182,7 +182,6 @@ protected:
}
newTemp = round(newTemp);
newTemp = constrain(newTemp, 0, 100);
return newTemp;
}
@@ -273,16 +272,36 @@ protected:
}
}
/**
* @brief Get the Equitherm Temp
* Calculations in degrees C, conversion occurs when using F
*
* @param minTemp
* @param maxTemp
* @return float
*/
float getEquithermTemp(int minTemp, int maxTemp) {
float targetTemp = vars.states.emergency ? settings.emergency.target : settings.heating.target;
float indoorTemp = vars.temperatures.indoor;
float outdoorTemp = vars.temperatures.outdoor;
if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
minTemp = f2c(minTemp);
maxTemp = f2c(maxTemp);
targetTemp = f2c(targetTemp);
indoorTemp = f2c(indoorTemp);
outdoorTemp = f2c(outdoorTemp);
}
if (vars.states.emergency) {
etRegulator.Kt = 0;
etRegulator.indoorTemp = 0;
etRegulator.outdoorTemp = vars.temperatures.outdoor;
etRegulator.outdoorTemp = outdoorTemp;
} else if (settings.pid.enable) {
etRegulator.Kt = 0;
etRegulator.indoorTemp = round(vars.temperatures.indoor);
etRegulator.outdoorTemp = round(vars.temperatures.outdoor);
etRegulator.indoorTemp = round(indoorTemp);
etRegulator.outdoorTemp = round(outdoorTemp);
} else {
if (settings.heating.turbo) {
@@ -290,17 +309,21 @@ protected:
} else {
etRegulator.Kt = settings.equitherm.t_factor;
}
etRegulator.indoorTemp = vars.temperatures.indoor;
etRegulator.outdoorTemp = vars.temperatures.outdoor;
etRegulator.indoorTemp = indoorTemp;
etRegulator.outdoorTemp = outdoorTemp;
}
etRegulator.setLimits(minTemp, maxTemp);
etRegulator.Kn = settings.equitherm.n_factor;
// etRegulator.Kn = tuneEquithermN(etRegulator.Kn, vars.temperatures.indoor, settings.heating.target, 300, 1800, 0.01, 1);
etRegulator.Kk = settings.equitherm.k_factor;
etRegulator.targetTemp = vars.states.emergency ? settings.emergency.target : settings.heating.target;
etRegulator.targetTemp = targetTemp;
float result = etRegulator.getResult();
return etRegulator.getResult();
if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
result = c2f(result);
}
return result;
}
float getPidTemp(int minTemp, int maxTemp) {

View File

@@ -79,14 +79,34 @@ protected:
}
#endif
if (outdoorTempUpdated && fabs(vars.temperatures.outdoor - this->filteredOutdoorTemp) > 0.099) {
vars.temperatures.outdoor = this->filteredOutdoorTemp + settings.sensors.outdoor.offset;
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("New temp: %f"), vars.temperatures.outdoor);
if (outdoorTempUpdated) {
float newTemp = settings.sensors.outdoor.offset;
if (settings.system.unitSystem == UnitSystem::METRIC) {
newTemp += this->filteredOutdoorTemp;
} else if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
newTemp += c2f(this->filteredOutdoorTemp);
}
if (fabs(vars.temperatures.outdoor - newTemp) > 0.099) {
vars.temperatures.outdoor = newTemp;
Log.sinfoln(FPSTR(L_SENSORS_OUTDOOR), F("New temp: %f"), vars.temperatures.outdoor);
}
}
if (indoorTempUpdated && fabs(vars.temperatures.indoor - this->filteredIndoorTemp) > 0.099) {
vars.temperatures.indoor = this->filteredIndoorTemp + settings.sensors.indoor.offset;
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("New temp: %f"), vars.temperatures.indoor);
if (indoorTempUpdated) {
float newTemp = settings.sensors.indoor.offset;
if (settings.system.unitSystem == UnitSystem::METRIC) {
newTemp += this->filteredIndoorTemp;
} else if (settings.system.unitSystem == UnitSystem::IMPERIAL) {
newTemp += c2f(this->filteredIndoorTemp);
}
if (fabs(vars.temperatures.indoor - newTemp) > 0.099) {
vars.temperatures.indoor = newTemp;
Log.sinfoln(FPSTR(L_SENSORS_INDOOR), F("New temp: %f"), vars.temperatures.indoor);
}
}
}

View File

@@ -27,6 +27,7 @@ struct Settings {
bool debug = DEBUG_BY_DEFAULT;
bool useSerial = USE_SERIAL;
bool useTelnet = USE_TELNET;
UnitSystem unitSystem = UnitSystem::METRIC;
} system;
struct {
@@ -36,6 +37,7 @@ struct Settings {
} portal;
struct {
UnitSystem unitSystem = UnitSystem::METRIC;
byte inGpio = DEFAULT_OT_IN_GPIO;
byte outGpio = DEFAULT_OT_OUT_GPIO;
unsigned int memberIdCode = 0;

View File

@@ -118,4 +118,9 @@ enum class SensorType : byte {
BLUETOOTH
};
enum class UnitSystem : byte {
METRIC,
IMPERIAL
};
char buffer[255];

View File

@@ -1,5 +1,25 @@
#include <Arduino.h>
inline float c2f(float value) {
return (9.0f / 5.0f) * value + 32.0f;
}
inline float f2c(float value) {
return (value - 32.0f) * (5.0f / 9.0f);
}
bool isValidTemp(float value, UnitSystem unit, float min = 0.1f, float max = 99.9f) {
if (unit == UnitSystem::METRIC) {
return value >= min && value <= max;
} else if (unit == UnitSystem::IMPERIAL) {
return value >= c2f(min) && value <= c2f(max);
} else {
return false;
}
}
double roundd(double value, uint8_t decimals = 2) {
if (decimals == 0) {
return (int)(value + 0.5);
@@ -13,7 +33,7 @@ double roundd(double value, uint8_t decimals = 2) {
return (int)(value * multiplier) / multiplier;
}
size_t getTotalHeap() {
inline size_t getTotalHeap() {
#if defined(ARDUINO_ARCH_ESP32)
return ESP.getHeapSize();
#elif defined(ARDUINO_ARCH_ESP8266)
@@ -63,7 +83,7 @@ size_t getMaxFreeBlockHeap(bool getMinValue = false) {
return getMinValue ? minValue : value;
}
uint8_t getHeapFrag() {
inline uint8_t getHeapFrag() {
return 100 - getMaxFreeBlockHeap() * 100.0 / getFreeHeap();
}
@@ -268,11 +288,13 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
dst["system"]["debug"] = src.system.debug;
dst["system"]["useSerial"] = src.system.useSerial;
dst["system"]["useTelnet"] = src.system.useTelnet;
dst["system"]["unitSystem"] = static_cast<byte>(src.system.unitSystem);
dst["portal"]["useAuth"] = src.portal.useAuth;
dst["portal"]["login"] = src.portal.login;
dst["portal"]["password"] = src.portal.password;
dst["opentherm"]["unitSystem"] = static_cast<byte>(src.opentherm.unitSystem);
dst["opentherm"]["inGpio"] = src.opentherm.inGpio;
dst["opentherm"]["outGpio"] = src.opentherm.outGpio;
dst["opentherm"]["memberIdCode"] = src.opentherm.memberIdCode;
@@ -377,6 +399,25 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
changed = true;
}
if (!src["system"]["unitSystem"].isNull()) {
byte value = src["system"]["unitSystem"].as<unsigned char>();
switch (value) {
case static_cast<byte>(UnitSystem::METRIC):
dst.system.unitSystem = UnitSystem::METRIC;
changed = true;
break;
case static_cast<byte>(UnitSystem::IMPERIAL):
dst.system.unitSystem = UnitSystem::IMPERIAL;
changed = true;
break;
default:
break;
}
}
// portal
if (src["portal"]["useAuth"].is<bool>()) {
@@ -404,6 +445,25 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
// opentherm
if (!src["opentherm"]["unitSystem"].isNull()) {
byte value = src["opentherm"]["unitSystem"].as<unsigned char>();
switch (value) {
case static_cast<byte>(UnitSystem::METRIC):
dst.opentherm.unitSystem = UnitSystem::METRIC;
changed = true;
break;
case static_cast<byte>(UnitSystem::IMPERIAL):
dst.opentherm.unitSystem = UnitSystem::IMPERIAL;
changed = true;
break;
default:
break;
}
}
if (!src["opentherm"]["inGpio"].isNull()) {
if (src["opentherm"]["inGpio"].is<JsonString>() && src["opentherm"]["inGpio"].as<JsonString>().size() == 0) {
if (dst.opentherm.inGpio != GPIO_IS_NOT_CONFIGURED) {
@@ -567,7 +627,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
if (!src["emergency"]["target"].isNull()) {
double value = src["emergency"]["target"].as<double>();
if (value > 0 && value < 100) {
if (isValidTemp(value, dst.system.unitSystem)) {
dst.emergency.target = roundd(value, 2);
changed = true;
}
@@ -618,7 +678,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
if (!src["heating"]["target"].isNull()) {
double value = src["heating"]["target"].as<double>();
if (value > 0 && value < 100) {
if (isValidTemp(value, dst.system.unitSystem)) {
dst.heating.target = roundd(value, 2);
changed = true;
}
@@ -670,7 +730,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
if (!src["dhw"]["target"].isNull()) {
unsigned char value = src["dhw"]["target"].as<unsigned char>();
if (value >= 0 && value < 100) {
if (isValidTemp(value, dst.system.unitSystem)) {
dst.dhw.target = value;
changed = true;
}
@@ -740,7 +800,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
if (!src["pid"]["maxTemp"].isNull()) {
unsigned char value = src["pid"]["maxTemp"].as<unsigned char>();
if (value > 0 && value <= 100 && value > dst.pid.minTemp) {
if (isValidTemp(value, dst.system.unitSystem) && value > dst.pid.minTemp) {
dst.pid.maxTemp = value;
changed = true;
}
@@ -749,7 +809,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
if (!src["pid"]["minTemp"].isNull()) {
unsigned char value = src["pid"]["minTemp"].as<unsigned char>();
if (value >= 0 && value < 100 && value < dst.pid.maxTemp) {
if (isValidTemp(value, dst.system.unitSystem) && value < dst.pid.maxTemp) {
dst.pid.minTemp = value;
changed = true;
}
@@ -1031,7 +1091,7 @@ bool jsonToVars(const JsonVariantConst src, Variables& dst) {
if (!src["temperatures"]["indoor"].isNull()) {
double value = src["temperatures"]["indoor"].as<double>();
if (settings.sensors.indoor.type == SensorType::MANUAL && value > -100 && value < 100) {
if (settings.sensors.indoor.type == SensorType::MANUAL && isValidTemp(value, settings.system.unitSystem, -99.9f, 99.9f)) {
dst.temperatures.indoor = roundd(value, 2);
changed = true;
}
@@ -1040,7 +1100,7 @@ bool jsonToVars(const JsonVariantConst src, Variables& dst) {
if (!src["temperatures"]["outdoor"].isNull()) {
double value = src["temperatures"]["outdoor"].as<double>();
if (settings.sensors.outdoor.type == SensorType::MANUAL && value > -100 && value < 100) {
if (settings.sensors.outdoor.type == SensorType::MANUAL && isValidTemp(value, settings.system.unitSystem, -99.9f, 99.9f)) {
dst.temperatures.outdoor = roundd(value, 2);
changed = true;
}