17 Commits

Author SHA1 Message Date
Yurii
7cbc52a8b0 chore: bump version 2024-03-01 00:26:41 +03:00
Laxilef
e090be380c Merge pull request #49 from blitzu/patch-3
fix: fix typo in settings.html
2024-03-01 00:22:32 +03:00
Laxilef
0bf49d2249 Merge pull request #50 from blitzu/patch-2
fix: fix typo in network.html
2024-03-01 00:22:13 +03:00
Laxilef
a83d94d361 Merge pull request #51 from blitzu/patch-1
fix: fix typo in index.html
2024-03-01 00:21:49 +03:00
Laxilef
358980da4c Merge pull request #48 from blitzu/patch-4
fix: fix typo in upgrade.html
2024-03-01 00:21:13 +03:00
blitzu
f91e39d067 Update upgrade.html 2024-02-29 18:52:31 +02:00
blitzu
1d53f21d46 Update settings.html 2024-02-29 18:52:08 +02:00
blitzu
c225e7c2a8 Update network.html 2024-02-29 18:51:25 +02:00
blitzu
6831c4331f Update index.html 2024-02-29 18:50:36 +02:00
Yurii
8fb62ce8ae fix: set temperature for sensors in manual mode fixed 2024-02-23 03:50:30 +03:00
Yurii
e829a00355 chore: bump version 2024-02-20 16:21:20 +03:00
Yurii
bee720386a refactor: changed availability conditions for HA entities 2024-02-20 16:17:03 +03:00
Yurii
c4b6eadb81 refactor: using BLE advertising instead of manual requests 2024-02-20 15:29:14 +03:00
Yurii
a5d2b9fcfa refactor: small fixes 2024-02-20 15:27:51 +03:00
Yurii
1a03117257 chore: bump version 2024-02-05 19:58:11 +03:00
Yurii
b421780f7b fix: change channel to 6 for Wifi AP 2024-02-05 19:57:26 +03:00
Yurii
987c101394 fix: set wifi sleep if use ble 2024-02-05 19:55:40 +03:00
20 changed files with 264 additions and 232 deletions

View File

@@ -16,7 +16,7 @@
- PID
- Equithermic curves - adjusts the temperature based on indoor and outdoor temperatures
- Hysteresis setting (for accurate maintenance of room temperature)
- Ability to connect an external sensors to monitor outdoor and indoor temperature ([compatible sensors](#compatible-temperature-sensors))
- Ability to connect an external sensors to monitor outdoor and indoor temperature ([compatible sensors](https://github.com/Laxilef/OTGateway/wiki/Compatibility#temperature-sensors))
- Emergency mode. If the Wi-Fi connection is lost or the gateway cannot connect to the MQTT server, the mode will turn on. This mode will automatically maintain the set temperature and prevent your home from freezing. In this mode it is also possible to use equithermal curves (weather-compensated control).
- Automatic error reset (not with all boilers)
- Diagnostics:
@@ -72,7 +72,7 @@ All available information and instructions can be found in the wiki:
- [ESP32Scheduler](https://github.com/laxilef/ESP32Scheduler) (for ESP32)
- [ArduinoJson](https://github.com/bblanchon/ArduinoJson)
- [OpenTherm Library](https://github.com/ihormelnyk/opentherm_library)
- [ArduinoMqttClient](https://github.com/arduino-libraries/ArduinoMqttClient) /
- [ArduinoMqttClient](https://github.com/arduino-libraries/ArduinoMqttClient)
- [ESPTelnet](https://github.com/LennartHennigs/ESPTelnet)
- [FileData](https://github.com/GyverLibs/FileData)
- [GyverPID](https://github.com/GyverLibs/GyverPID)

View File

@@ -210,7 +210,7 @@
<a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
<a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
<a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
<a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
</small>
</footer>
@@ -227,4 +227,4 @@
};
</script>
</body>
</html>
</html>

View File

@@ -145,7 +145,7 @@
<a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
<a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
<a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
<a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
</small>
</footer>
@@ -163,4 +163,4 @@
</script>
</body>
</html>
</html>

View File

@@ -333,7 +333,7 @@
<a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
<a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
<a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
<a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
</small>
</footer>
@@ -354,4 +354,4 @@
</script>
</body>
</html>
</html>

View File

@@ -91,7 +91,7 @@
<a href="https://github.com/Laxilef/OTGateway/blob/master/LICENSE" target="_blank" class="secondary">License</a>
<a href="https://github.com/Laxilef/OTGateway/blob/master/" target="_blank" class="secondary">Source code</a>
<a href="https://github.com/Laxilef/OTGateway/wiki" target="_blank" class="secondary">Help</a>
<a href="https://github.com/Laxilef/OTGateway/issue" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/issues" target="_blank" class="secondary">Issue & questions</a>
<a href="https://github.com/Laxilef/OTGateway/releases" target="_blank" class="secondary">Releases</a>
</small>
</footer>
@@ -105,4 +105,4 @@
</script>
</body>
</html>
</html>

View File

@@ -17,7 +17,7 @@ public:
float Kk = 0.0;
float Kt = 0.0;
Equitherm() {}
Equitherm() = default;
// kn, kk, kt
Equitherm(float new_kn, float new_kk, float new_kt) {

View File

@@ -6,7 +6,7 @@ class HomeAssistantHelper {
public:
typedef std::function<void(const char*, bool)> PublishEventCallback;
HomeAssistantHelper() {}
HomeAssistantHelper() = default;
void setWriter() {
this->writer = nullptr;

View File

@@ -162,7 +162,7 @@ namespace Network {
#ifdef ARDUINO_ARCH_ESP8266
WiFi.setSleepMode(WIFI_NONE_SLEEP);
#elif defined(ARDUINO_ARCH_ESP32)
WiFi.setSleep(WIFI_PS_NONE);
WiFi.setSleep(USE_BLE ? WIFI_PS_MIN_MODEM : WIFI_PS_NONE);
#endif
WiFi.softAPdisconnect();
@@ -309,12 +309,14 @@ namespace Network {
Log.sinfoln(FPSTR(L_NETWORK), F("No STA credentials, start AP"));
WiFi.mode(WIFI_AP_STA);
this->delayCallback(250);
WiFi.softAP(this->apName, this->apPassword, this->apChannel);
} else if (!this->isApEnabled() && millis() - this->disconnectedTime > this->failedConnectTimeout) {
Log.sinfoln(FPSTR(L_NETWORK), F("Disconnected for a long time, start AP"));
WiFi.mode(WIFI_AP_STA);
this->delayCallback(250);
WiFi.softAP(this->apName, this->apPassword, this->apChannel);
} else if (this->isConnecting() && millis() - this->prevReconnectingTime > this->resetConnectionTimeout) {

View File

@@ -177,7 +177,6 @@ public:
} else {
sizeArgName = length - size_t(argStartPos - currentBuf) - 1;
Serial.printf("sizeArgName: %d\r\n", sizeArgName);
// send all content if arg len > space
if (sizeArgName >= sizeof(argName)) {

View File

@@ -15,7 +15,7 @@ extra_configs = secrets.default.ini
[env]
framework = arduino
lib_deps =
bblanchon/ArduinoJson@^7.0.2
bblanchon/ArduinoJson@^7.0.3
;ihormelnyk/OpenTherm Library@^1.1.4
https://github.com/Laxilef/opentherm_library/archive/refs/heads/fix_start_bit.zip
arduino-libraries/ArduinoMqttClient@^0.1.8
@@ -51,7 +51,7 @@ monitor_speed = 115200
monitor_filters = direct
board_build.flash_mode = dio
board_build.filesystem = littlefs
version = 1.4.0-rc.13
version = 1.4.0-rc.16
; Defaults
[esp8266_defaults]
@@ -65,8 +65,6 @@ extra_scripts =
build_flags = ${env.build_flags}
board_build.ldscript = eagle.flash.1m256.ld
;board_build.ldscript = eagle.flash.4m1m.ld
platform_packages =
framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git
[esp32_defaults]
platform = espressif32

View File

@@ -6,59 +6,6 @@ public:
static const byte TEMP_SOURCE_HEATING = 0;
static const byte TEMP_SOURCE_INDOOR = 1;
bool publishNumberOutdoorSensorOffset(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("settings"));
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.outdoor.type != 1, 'online', 'offline') }}");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("outdoor_sensor_offset"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("outdoor_sensor_offset"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
doc[FPSTR(HA_NAME)] = F("Outdoor sensor offset");
doc[FPSTR(HA_ICON)] = F("mdi:altimeter");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.outdoor.offset|float(0)|round(2) }}");
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"sensors\": {\"outdoor\" : {\"offset\" : {{ value }}}}}");
doc[FPSTR(HA_MIN)] = -10;
doc[FPSTR(HA_MAX)] = 10;
doc[FPSTR(HA_STEP)] = 0.1;
doc[FPSTR(HA_MODE)] = "box";
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
doc.shrinkToFit();
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("outdoor_sensor_offset")).c_str(), doc);
}
bool publishNumberIndoorSensorOffset(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("settings"));
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.sensors.indoor.type != 1, 'online', 'offline') }}");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("indoor_sensor_offset"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("indoor_sensor_offset"));
doc[FPSTR(HA_ENTITY_CATEGORY)] = F("config");
doc[FPSTR(HA_DEVICE_CLASS)] = F("temperature");
doc[FPSTR(HA_UNIT_OF_MEASUREMENT)] = F("°C");
doc[FPSTR(HA_NAME)] = F("Indoor sensor offset");
doc[FPSTR(HA_ICON)] = F("mdi:altimeter");
doc[FPSTR(HA_STATE_TOPIC)] = this->getDeviceTopic(F("settings"));
doc[FPSTR(HA_VALUE_TEMPLATE)] = F("{{ value_json.sensors.indoor.offset|float(0)|round(2) }}");
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"sensors\": {\"indoor\" : {\"offset\" : {{ value }}}}}");
doc[FPSTR(HA_MIN)] = -10;
doc[FPSTR(HA_MAX)] = 10;
doc[FPSTR(HA_STEP)] = 0.1;
doc[FPSTR(HA_MODE)] = "box";
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
doc.shrinkToFit();
return this->publish(this->getTopic(FPSTR(HA_ENTITY_NUMBER), F("indoor_sensor_offset")).c_str(), doc);
}
bool publishSwitchEmergency(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -266,7 +213,10 @@ public:
bool publishSensorBoilerHeatingMinTemp(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_heating_min_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("boiler_heating_min_temp"));
@@ -286,7 +236,10 @@ public:
bool publishSensorBoilerHeatingMaxTemp(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_heating_max_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("boiler_heating_max_temp"));
@@ -415,7 +368,7 @@ public:
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("settings/set"));
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
doc[FPSTR(HA_MIN)] = minTemp;
doc[FPSTR(HA_MAX)] = maxTemp <= minTemp ? maxTemp : maxTemp;
doc[FPSTR(HA_MAX)] = maxTemp > minTemp ? maxTemp : minTemp;
doc[FPSTR(HA_STEP)] = 1;
doc[FPSTR(HA_MODE)] = "box";
doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
@@ -426,7 +379,10 @@ public:
bool publishSensorBoilerDhwMinTemp(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_dhw_min_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("boiler_dhw_min_temp"));
@@ -446,7 +402,10 @@ public:
bool publishSensorBoilerDhwMaxTemp(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_dhw_max_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("boiler_dhw_max_temp"));
@@ -780,7 +739,6 @@ public:
bool publishSelectTuningRegulator(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_COMMAND_TOPIC)] = this->getDeviceTopic(F("state/set"));
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"tuning\": {\"regulator\": {% if value == 'Equitherm' %}0{% elif value == 'PID' %}1{% endif %}}}");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -835,7 +793,10 @@ public:
bool publishBinSensorHeating(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating"));
@@ -853,7 +814,10 @@ public:
bool publishBinSensorDhw(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw"));
@@ -871,7 +835,10 @@ public:
bool publishBinSensorFlame(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("flame"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("flame"));
@@ -889,8 +856,10 @@ public:
bool publishBinSensorFault(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("fault"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("fault"));
@@ -908,7 +877,10 @@ public:
bool publishBinSensorDiagnostic(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("diagnostic"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("diagnostic"));
@@ -926,8 +898,10 @@ public:
bool publishSensorFaultCode(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.fault, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus and value_json.states.fault, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("fault_code"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("fault_code"));
@@ -985,7 +959,10 @@ public:
bool publishSensorModulation(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("modulation_level"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("modulation_level"));
@@ -1005,7 +982,10 @@ public:
bool publishSensorPressure(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pressure"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pressure"));
@@ -1025,7 +1005,10 @@ public:
bool publishSensorDhwFlowRate(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_flow_rate"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_flow_rate"));
@@ -1069,8 +1052,7 @@ public:
bool publishSensorIndoorTemp(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("any");
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
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"));
@@ -1113,8 +1095,7 @@ public:
bool publishSensorOutdoorTemp(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("any");
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
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"));
@@ -1134,7 +1115,10 @@ public:
bool publishSensorHeatingTemp(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating_temp"));
@@ -1154,7 +1138,10 @@ public:
bool publishSensorDhwTemp(bool enabledByDefault = true) {
JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state"));
doc[FPSTR(HA_AVAILABILITY)][1][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}");
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("all");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_temp"));

View File

@@ -20,14 +20,11 @@ public:
}
~MainTask() {
if (this->blinker != nullptr) {
delete this->blinker;
}
delete this->blinker;
}
protected:
const static byte REASON_PUMP_START_HEATING = 1;
const static byte REASON_PUMP_START_ANTISTUCK = 2;
enum class PumpStartReason {NONE, HEATING, ANTISTUCK};
Blinker* blinker = nullptr;
bool blinkerInitialized = false;
@@ -38,7 +35,7 @@ protected:
unsigned long restartSignalTime = 0;
bool heatingEnabled = false;
unsigned long heatingDisabledTime = 0;
byte externalPumpStartReason;
PumpStartReason extPumpStartReason = PumpStartReason::NONE;
unsigned long externalPumpStartTime = 0;
bool telnetStarted = false;
@@ -57,12 +54,12 @@ protected:
void setup() {
#ifdef LED_STATUS_PIN
pinMode(LED_STATUS_PIN, OUTPUT);
digitalWrite(LED_STATUS_PIN, false);
digitalWrite(LED_STATUS_PIN, LOW);
#endif
if (settings.externalPump.pin != 0) {
pinMode(settings.externalPump.pin, OUTPUT);
digitalWrite(settings.externalPump.pin, false);
digitalWrite(settings.externalPump.pin, LOW);
}
}
@@ -250,14 +247,14 @@ protected:
if (!this->blinker->running() && millis() - endBlinkTime >= 5000) {
if (errCount == 0) {
if (!ledOn) {
digitalWrite(ledPin, true);
digitalWrite(ledPin, HIGH);
ledOn = true;
}
return;
} else if (ledOn) {
digitalWrite(ledPin, false);
digitalWrite(ledPin, LOW);
ledOn = false;
endBlinkTime = millis();
return;
@@ -289,7 +286,7 @@ protected:
if (!settings.externalPump.use || settings.externalPump.pin == 0) {
if (vars.states.externalPump) {
if (settings.externalPump.pin != 0) {
digitalWrite(settings.externalPump.pin, false);
digitalWrite(settings.externalPump.pin, LOW);
}
vars.states.externalPump = false;
@@ -302,16 +299,16 @@ protected:
}
if (vars.states.externalPump && !this->heatingEnabled) {
if (this->externalPumpStartReason == MainTask::REASON_PUMP_START_HEATING && millis() - this->heatingDisabledTime > (settings.externalPump.postCirculationTime * 1000u)) {
digitalWrite(settings.externalPump.pin, false);
if (this->extPumpStartReason == MainTask::PumpStartReason::HEATING && millis() - this->heatingDisabledTime > (settings.externalPump.postCirculationTime * 1000u)) {
digitalWrite(settings.externalPump.pin, LOW);
vars.states.externalPump = false;
vars.parameters.extPumpLastEnableTime = millis();
Log.sinfoln("EXTPUMP", F("Disabled: expired post circulation time"));
} else if (this->externalPumpStartReason == MainTask::REASON_PUMP_START_ANTISTUCK && millis() - this->externalPumpStartTime >= (settings.externalPump.antiStuckTime * 1000u)) {
digitalWrite(settings.externalPump.pin, false);
} else if (this->extPumpStartReason == MainTask::PumpStartReason::ANTISTUCK && millis() - this->externalPumpStartTime >= (settings.externalPump.antiStuckTime * 1000u)) {
digitalWrite(settings.externalPump.pin, LOW);
vars.states.externalPump = false;
vars.parameters.extPumpLastEnableTime = millis();
@@ -319,24 +316,24 @@ protected:
Log.sinfoln("EXTPUMP", F("Disabled: expired anti stuck time"));
}
} else if (vars.states.externalPump && this->heatingEnabled && this->externalPumpStartReason == MainTask::REASON_PUMP_START_ANTISTUCK) {
this->externalPumpStartReason = MainTask::REASON_PUMP_START_HEATING;
} else if (vars.states.externalPump && this->heatingEnabled && this->extPumpStartReason == MainTask::PumpStartReason::ANTISTUCK) {
this->extPumpStartReason = MainTask::PumpStartReason::HEATING;
} else if (!vars.states.externalPump && this->heatingEnabled) {
vars.states.externalPump = true;
this->externalPumpStartTime = millis();
this->externalPumpStartReason = MainTask::REASON_PUMP_START_HEATING;
this->extPumpStartReason = MainTask::PumpStartReason::HEATING;
digitalWrite(settings.externalPump.pin, true);
digitalWrite(settings.externalPump.pin, HIGH);
Log.sinfoln("EXTPUMP", F("Enabled: heating on"));
} else if (!vars.states.externalPump && (vars.parameters.extPumpLastEnableTime == 0 || millis() - vars.parameters.extPumpLastEnableTime >= (settings.externalPump.antiStuckInterval * 1000ul))) {
vars.states.externalPump = true;
this->externalPumpStartTime = millis();
this->externalPumpStartReason = MainTask::REASON_PUMP_START_ANTISTUCK;
this->extPumpStartReason = MainTask::PumpStartReason::ANTISTUCK;
digitalWrite(settings.externalPump.pin, true);
digitalWrite(settings.externalPump.pin, HIGH);
Log.sinfoln("EXTPUMP", F("Enabled: anti stuck"));
}

View File

@@ -15,9 +15,7 @@ public:
}
~MqttTask() {
if (this->haHelper != nullptr) {
delete this->haHelper;
}
delete this->haHelper;
if (this->client != nullptr) {
if (this->client->connected()) {
@@ -27,13 +25,8 @@ public:
delete this->client;
}
if (this->writer != nullptr) {
delete this->writer;
}
if (this->wifiClient != nullptr) {
delete this->wifiClient;
}
delete this->writer;
delete this->wifiClient;
}
void disable() {
@@ -208,12 +201,7 @@ protected:
// publish variables and status
if (this->newConnection || millis() - this->prevPubVarsTime > (settings.mqtt.interval * 1000u)) {
this->writer->publish(
this->haHelper->getDeviceTopic("status").c_str(),
!vars.states.otStatus ? "offline" : vars.states.fault ? "fault" : "online",
true
);
this->writer->publish(this->haHelper->getDeviceTopic("status").c_str(), "online", false);
this->publishVariables(this->haHelper->getDeviceTopic("state").c_str());
this->prevPubVarsTime = millis();
}
@@ -328,10 +316,6 @@ protected:
}
void publishHaEntities() {
// main
this->haHelper->publishNumberOutdoorSensorOffset(false);
this->haHelper->publishNumberIndoorSensorOffset(false);
// emergency
this->haHelper->publishSwitchEmergency();
this->haHelper->publishNumberEmergencyTarget();

View File

@@ -54,9 +54,9 @@ protected:
#ifdef LED_OT_RX_PIN
{
digitalWrite(LED_OT_RX_PIN, true);
digitalWrite(LED_OT_RX_PIN, HIGH);
delayMicroseconds(2000);
digitalWrite(LED_OT_RX_PIN, false);
digitalWrite(LED_OT_RX_PIN, LOW);
}
#endif
}
@@ -71,7 +71,7 @@ protected:
#ifdef LED_OT_RX_PIN
pinMode(LED_OT_RX_PIN, OUTPUT);
digitalWrite(LED_OT_RX_PIN, false);
digitalWrite(LED_OT_RX_PIN, LOW);
#endif
}

View File

@@ -28,9 +28,7 @@ public:
}
~PortalTask() {
if (this->bufferedWebServer != nullptr) {
delete this->bufferedWebServer;
}
delete this->bufferedWebServer;
if (this->webServer != nullptr) {
this->stopWebServer();

View File

@@ -159,7 +159,7 @@ protected:
if (vars.parameters.heatingEnabled) {
float pidResult = getPidTemp(
settings.equitherm.enable ? (settings.pid.maxTemp * -1) : settings.pid.minTemp,
settings.equitherm.enable ? settings.pid.maxTemp : settings.pid.maxTemp
settings.pid.maxTemp
);
if (fabs(prevPidResult - pidResult) + 0.0001 >= 0.5) {

View File

@@ -3,13 +3,6 @@
#if USE_BLE
#include <NimBLEDevice.h>
// BLE services and characterstics that we are interested in
const uint16_t bleUuidServiceBattery = 0x180F;
const uint16_t bleUuidServiceEnvironment = 0x181AU;
const uint16_t bleUuidCharacteristicBatteryLevel = 0x2A19;
const uint16_t bleUuidCharacteristicTemperature = 0x2A6E;
const uint16_t bleUuidCharacteristicHumidity = 0x2A6F;
#endif
class SensorsTask : public LeanTask {
@@ -25,21 +18,10 @@ public:
}
~SensorsTask() {
if (this->outdoorSensor != nullptr) {
delete this->outdoorSensor;
}
if (this->oneWireOutdoorSensor != nullptr) {
delete this->oneWireOutdoorSensor;
}
if (this->indoorSensor != nullptr) {
delete this->indoorSensor;
}
if (this->oneWireIndoorSensor != nullptr) {
delete this->oneWireIndoorSensor;
}
delete this->outdoorSensor;
delete this->oneWireOutdoorSensor;
delete this->indoorSensor;
delete this->oneWireIndoorSensor;
}
protected:
@@ -61,9 +43,8 @@ protected:
#if USE_BLE
BLEClient* pBleClient = nullptr;
BLERemoteService* pBleServiceBattery = nullptr;
BLERemoteService* pBleServiceEnvironment = nullptr;
bool initBleSensor = false;
bool initBleNotify = false;
#endif
const char* getTaskName() {
@@ -79,67 +60,150 @@ protected:
}
void loop() {
bool needUpdateIndoorTemp = false;
bool needUpdateOutdoorTemp = false;
if (settings.sensors.outdoor.type == 2 && settings.sensors.outdoor.pin) {
outdoorTemperatureSensor();
needUpdateOutdoorTemp = true;
}
if (settings.sensors.indoor.type == 2 && settings.sensors.indoor.pin) {
indoorTemperatureSensor();
needUpdateIndoorTemp = true;
}
#if USE_BLE
if (settings.sensors.indoor.type == 3 && strlen(settings.sensors.indoor.bleAddresss)) {
if (settings.sensors.indoor.type == 3) {
bluetoothSensor();
needUpdateIndoorTemp = true;
}
#endif
if (needUpdateOutdoorTemp && 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 (needUpdateIndoorTemp && 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 USE_BLE
void bluetoothSensor() {
static bool initBleNotify = false;
if (!initBleSensor && millis() > 5000) {
Log.sinfoln(FPSTR(L_SENSORS_BLE), "Init BLE. Free heap %u bytes", ESP.getFreeHeap());
Log.sinfoln(FPSTR(L_SENSORS_BLE), F("Init BLE"));
BLEDevice::init("");
pBleClient = BLEDevice::createClient();
pBleClient = BLEDevice::createClient();
pBleClient->setConnectTimeout(5);
// Connect to the remote BLE Server.
BLEAddress bleServerAddress(std::string(settings.sensors.indoor.bleAddresss));
if (pBleClient->connect(bleServerAddress)) {
Log.sinfoln(FPSTR(L_SENSORS_BLE), "Connected to BLE device at %s", bleServerAddress.toString().c_str());
// Obtain a reference to the services we are interested in
pBleServiceBattery = pBleClient->getService(BLEUUID(bleUuidServiceBattery));
if (pBleServiceBattery == nullptr) {
Log.sinfoln(FPSTR(L_SENSORS_BLE), "Failed to find battery service");
}
pBleServiceEnvironment = pBleClient->getService(BLEUUID(bleUuidServiceEnvironment));
if (pBleServiceEnvironment == nullptr) {
Log.sinfoln(FPSTR(L_SENSORS_BLE), "Failed to find environmental service");
}
} else {
Log.swarningln(FPSTR(L_SENSORS_BLE), "Error connecting to BLE device at %s", bleServerAddress.toString().c_str());
}
initBleSensor = true;
}
if (pBleClient && pBleClient->isConnected()) {
Log.straceln(FPSTR(L_SENSORS_BLE), "Connected. Free heap %u bytes", ESP.getFreeHeap());
if (pBleServiceBattery) {
uint8_t batteryLevel = *reinterpret_cast<const uint8_t *>(pBleServiceBattery->getValue(bleUuidCharacteristicBatteryLevel).data());
Log.straceln(FPSTR(L_SENSORS_BLE), "Battery: %d", batteryLevel);
}
if (!initBleSensor || pBleClient->isConnected()) {
return;
}
// Reset init notify flag
this->initBleNotify = false;
if (pBleServiceEnvironment) {
float temperature = *reinterpret_cast<const int16_t *>(pBleServiceEnvironment->getValue(bleUuidCharacteristicTemperature).data()) / 100.0f;
Log.straceln(FPSTR(L_SENSORS_BLE), "Temperature: %.2f", temperature);
float humidity = *reinterpret_cast<const int16_t *>(pBleServiceEnvironment->getValue(bleUuidCharacteristicHumidity).data()) / 100.0f;
Log.straceln(FPSTR(L_SENSORS_BLE), "Humidity: %.2f", humidity);
// Connect to the remote BLE Server.
BLEAddress bleServerAddress(settings.sensors.indoor.bleAddresss);
if (!pBleClient->connect(bleServerAddress)) {
Log.swarningln(FPSTR(L_SENSORS_BLE), "Failed connecting to device at %s", bleServerAddress.toString().c_str());
return;
}
vars.temperatures.indoor = temperature + settings.sensors.indoor.offset;
Log.sinfoln(FPSTR(L_SENSORS_BLE), "Connected to device at %s", bleServerAddress.toString().c_str());
NimBLEUUID serviceUUID((uint16_t) 0x181AU);
BLERemoteService* pRemoteService = pBleClient->getService(serviceUUID);
if (!pRemoteService) {
Log.straceln(FPSTR(L_SENSORS_BLE), F("Failed to find service UUID: %s"), serviceUUID.toString().c_str());
return;
}
Log.straceln(FPSTR(L_SENSORS_BLE), F("Found service UUID: %s"), serviceUUID.toString().c_str());
// 0x2A6E - Notify temperature x0.01C (pvvx)
if (!this->initBleNotify) {
NimBLEUUID charUUID((uint16_t) 0x2A6E);
BLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic && pRemoteCharacteristic->canNotify()) {
Log.straceln(FPSTR(L_SENSORS_BLE), F("Found characteristic UUID: %s"), charUUID.toString().c_str());
this->initBleNotify = pRemoteCharacteristic->subscribe(true, [this](NimBLERemoteCharacteristic*, uint8_t* pData, size_t length, bool isNotify) {
if (length != 2) {
Log.swarningln(FPSTR(L_SENSORS_BLE), F("Invalid notification data"));
return;
}
float rawTemp = ((pData[0] | (pData[1] << 8)) * 0.01);
Log.straceln(FPSTR(L_SENSORS_INDOOR), F("Raw temp: %f"), rawTemp);
if (this->emptyIndoorTemp) {
this->filteredIndoorTemp = rawTemp;
this->emptyIndoorTemp = false;
} else {
this->filteredIndoorTemp += (rawTemp - this->filteredIndoorTemp) * EXT_SENSORS_FILTER_K;
}
this->filteredIndoorTemp = floor(this->filteredIndoorTemp * 100) / 100;
});
if (this->initBleNotify) {
Log.straceln(FPSTR(L_SENSORS_BLE), F("Subscribed to characteristic UUID: %s"), charUUID.toString().c_str());
} else {
Log.swarningln(FPSTR(L_SENSORS_BLE), F("Failed to subscribe to characteristic UUID: %s"), charUUID.toString().c_str());
}
}
} else {
Log.straceln(FPSTR(L_SENSORS_BLE), "Not connected");
}
// 0x2A1F - Notify temperature x0.1C (atc1441/pvvx)
if (!this->initBleNotify) {
NimBLEUUID charUUID((uint16_t) 0x2A1F);
BLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic && pRemoteCharacteristic->canNotify()) {
Log.straceln(FPSTR(L_SENSORS_BLE), F("Found characteristic UUID: %s"), charUUID.toString().c_str());
this->initBleNotify = pRemoteCharacteristic->subscribe(true, [this](NimBLERemoteCharacteristic*, uint8_t* pData, size_t length, bool isNotify) {
if (length != 2) {
Log.swarningln(FPSTR(L_SENSORS_BLE), F("Invalid notification data"));
return;
}
float rawTemp = ((pData[0] | (pData[1] << 8)) * 0.1);
Log.straceln(FPSTR(L_SENSORS_INDOOR), F("Raw temp: %f"), rawTemp);
if (this->emptyIndoorTemp) {
this->filteredIndoorTemp = rawTemp;
this->emptyIndoorTemp = false;
} else {
this->filteredIndoorTemp += (rawTemp - this->filteredIndoorTemp) * EXT_SENSORS_FILTER_K;
}
this->filteredIndoorTemp = floor(this->filteredIndoorTemp * 100) / 100;
});
if (this->initBleNotify) {
Log.straceln(FPSTR(L_SENSORS_BLE), F("Subscribed to characteristic UUID: %s"), charUUID.toString().c_str());
} else {
Log.swarningln(FPSTR(L_SENSORS_BLE), F("Failed to subscribe to characteristic UUID: %s"), charUUID.toString().c_str());
}
}
}
if (!this->initBleNotify) {
Log.swarningln(FPSTR(L_SENSORS_BLE), F("Not found supported characteristics"));
pBleClient->disconnect();
}
}
#endif
@@ -205,12 +269,6 @@ protected:
}
this->filteredOutdoorTemp = floor(this->filteredOutdoorTemp * 100) / 100;
if (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"), this->filteredOutdoorTemp);
}
this->outdoorSensor->requestTemperatures();
this->startOutdoorConversionTime = millis();
}
@@ -277,12 +335,6 @@ protected:
}
this->filteredIndoorTemp = floor(this->filteredIndoorTemp * 100) / 100;
if (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"), this->filteredIndoorTemp);
}
this->indoorSensor->requestTemperatures();
this->startIndoorConversionTime = millis();
}

View File

@@ -12,7 +12,7 @@ struct NetworkSettings {
struct {
char ssid[33] = AP_SSID_DEFAULT;
char password[65] = AP_PASSWORD_DEFAULT;
byte channel = 1;
byte channel = 6;
} ap;
struct {
@@ -110,7 +110,7 @@ struct Settings {
// 1 - manual, 2 - ds18b20, 3 - ble
byte type = 1;
byte pin = SENSOR_INDOOR_PIN_DEFAULT;
char bleAddresss[18] = "00:00:00:00:00:00";
uint8_t bleAddresss[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
float offset = 0.0f;
} indoor;
} sensors;
@@ -166,17 +166,17 @@ struct Variables {
unsigned long extPumpLastEnableTime = 0;
byte dhwMinTemp = DEFAULT_DHW_MIN_TEMP;
byte dhwMaxTemp = DEFAULT_DHW_MAX_TEMP;
byte maxModulation;
uint8_t slaveMemberId;
uint8_t slaveFlags;
uint8_t slaveType;
uint8_t slaveVersion;
float slaveOtVersion;
uint8_t masterMemberId;
uint8_t masterFlags;
uint8_t masterType;
uint8_t masterVersion;
float masterOtVersion;
byte maxModulation = 0;
uint8_t slaveMemberId = 0;
uint8_t slaveFlags = 0;
uint8_t slaveType = 0;
uint8_t slaveVersion = 0;
float slaveOtVersion = 0.0f;
uint8_t masterMemberId = 0;
uint8_t masterFlags = 0;
uint8_t masterType = 0;
uint8_t masterVersion = 0;
float masterOtVersion = 0;
} parameters;
struct {

View File

@@ -1,5 +1,5 @@
#define PROJECT_NAME "OpenTherm Gateway"
#define PROJECT_VERSION "1.4.0-rc.13"
#define PROJECT_VERSION "1.4.0-rc.16"
#define PROJECT_REPO "https://github.com/Laxilef/OTGateway"
#define EMERGENCY_TIME_TRESHOLD 120000

View File

@@ -232,7 +232,7 @@ bool jsonToNetworkSettings(const JsonVariantConst src, NetworkSettings& dst) {
}
// ap
// sta
if (!src["sta"]["ssid"].isNull()) {
String value = src["sta"]["ssid"].as<String>();
@@ -329,7 +329,19 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
dst["sensors"]["indoor"]["type"] = src.sensors.indoor.type;
dst["sensors"]["indoor"]["pin"] = src.sensors.indoor.pin;
dst["sensors"]["indoor"]["bleAddresss"] = src.sensors.indoor.bleAddresss;
char bleAddress[18];
sprintf(
bleAddress,
"%02x:%02x:%02x:%02x:%02x:%02x",
src.sensors.indoor.bleAddresss[0],
src.sensors.indoor.bleAddresss[1],
src.sensors.indoor.bleAddresss[2],
src.sensors.indoor.bleAddresss[3],
src.sensors.indoor.bleAddresss[4],
src.sensors.indoor.bleAddresss[5]
);
dst["sensors"]["indoor"]["bleAddresss"] = String(bleAddress);
dst["sensors"]["indoor"]["offset"] = roundd(src.sensors.indoor.offset, 2);
if (!safe) {
@@ -486,7 +498,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
if (!src["mqtt"]["port"].isNull()) {
unsigned short value = src["mqtt"]["port"].as<unsigned short>();
if (value >= 0 && value <= 65536) {
if (value > 0 && value <= 65535) {
dst.mqtt.port = value;
changed = true;
}
@@ -821,9 +833,12 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
#if USE_BLE
if (!src["sensors"]["indoor"]["bleAddresss"].isNull()) {
String value = src["sensors"]["indoor"]["bleAddresss"].as<String>();
int tmp[6];
if(sscanf(value.c_str(), "%02x:%02x:%02x:%02x:%02x:%02x", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]) == 6) {
for(uint8_t i = 0; i < 6; i++) {
dst.sensors.indoor.bleAddresss[i] = (uint8_t) tmp[i];
}
if (value.length() < sizeof(dst.sensors.indoor.bleAddresss)) {
strcpy(dst.sensors.indoor.bleAddresss, value.c_str());
changed = true;
}
}