4 Commits

Author SHA1 Message Date
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
14 changed files with 243 additions and 217 deletions

View File

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

View File

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

View File

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

View File

@@ -51,7 +51,7 @@ monitor_speed = 115200
monitor_filters = direct monitor_filters = direct
board_build.flash_mode = dio board_build.flash_mode = dio
board_build.filesystem = littlefs board_build.filesystem = littlefs
version = 1.4.0-rc.14 version = 1.4.0-rc.15
; Defaults ; Defaults
[esp8266_defaults] [esp8266_defaults]

View File

@@ -6,59 +6,6 @@ public:
static const byte TEMP_SOURCE_HEATING = 0; static const byte TEMP_SOURCE_HEATING = 0;
static const byte TEMP_SOURCE_INDOOR = 1; 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) { bool publishSwitchEmergency(bool enabledByDefault = true) {
JsonDocument doc; JsonDocument doc;
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -266,7 +213,10 @@ public:
bool publishSensorBoilerHeatingMinTemp(bool enabledByDefault = true) { bool publishSensorBoilerHeatingMinTemp(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_heating_min_temp")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_heating_min_temp"));
doc[FPSTR(HA_OBJECT_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) { bool publishSensorBoilerHeatingMaxTemp(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_heating_max_temp")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_heating_max_temp"));
doc[FPSTR(HA_OBJECT_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_TOPIC)] = this->getDeviceTopic(F("settings/set"));
doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}"); doc[FPSTR(HA_COMMAND_TEMPLATE)] = F("{\"dhw\": {\"target\" : {{ value|int(0) }}}}");
doc[FPSTR(HA_MIN)] = minTemp; 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_STEP)] = 1;
doc[FPSTR(HA_MODE)] = "box"; doc[FPSTR(HA_MODE)] = "box";
doc[FPSTR(HA_EXPIRE_AFTER)] = 120; doc[FPSTR(HA_EXPIRE_AFTER)] = 120;
@@ -426,7 +379,10 @@ public:
bool publishSensorBoilerDhwMinTemp(bool enabledByDefault = true) { bool publishSensorBoilerDhwMinTemp(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_dhw_min_temp")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_dhw_min_temp"));
doc[FPSTR(HA_OBJECT_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) { bool publishSensorBoilerDhwMaxTemp(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_dhw_max_temp")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("boiler_dhw_max_temp"));
doc[FPSTR(HA_OBJECT_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) { bool publishSelectTuningRegulator(bool enabledByDefault = true) {
JsonDocument doc; JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); 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_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_COMMAND_TEMPLATE)] = F("{\"tuning\": {\"regulator\": {% if value == 'Equitherm' %}0{% elif value == 'PID' %}1{% endif %}}}");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
@@ -835,7 +793,10 @@ public:
bool publishBinSensorHeating(bool enabledByDefault = true) { bool publishBinSensorHeating(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating")); doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("heating"));
@@ -853,7 +814,10 @@ public:
bool publishBinSensorDhw(bool enabledByDefault = true) { bool publishBinSensorDhw(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw")); doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw"));
@@ -871,7 +835,10 @@ public:
bool publishBinSensorFlame(bool enabledByDefault = true) { bool publishBinSensorFlame(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("flame")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("flame"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("flame")); doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("flame"));
@@ -889,8 +856,10 @@ public:
bool publishBinSensorFault(bool enabledByDefault = true) { bool publishBinSensorFault(bool enabledByDefault = true) {
JsonDocument doc; JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.otStatus, 'online', 'offline') }}"); 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("fault")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("fault"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("fault")); doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("fault"));
@@ -908,7 +877,10 @@ public:
bool publishBinSensorDiagnostic(bool enabledByDefault = true) { bool publishBinSensorDiagnostic(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("diagnostic")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("diagnostic"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("diagnostic")); doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("diagnostic"));
@@ -926,8 +898,10 @@ public:
bool publishSensorFaultCode(bool enabledByDefault = true) { bool publishSensorFaultCode(bool enabledByDefault = true) {
JsonDocument doc; JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("state")); doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_VALUE_TEMPLATE)] = F("{{ iif(value_json.states.fault, 'online', 'offline') }}"); 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("fault_code")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("fault_code"));
doc[FPSTR(HA_OBJECT_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) { bool publishSensorModulation(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("modulation_level")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("modulation_level"));
doc[FPSTR(HA_OBJECT_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) { bool publishSensorPressure(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pressure")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("pressure"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pressure")); doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("pressure"));
@@ -1025,7 +1005,10 @@ public:
bool publishSensorDhwFlowRate(bool enabledByDefault = true) { bool publishSensorDhwFlowRate(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_flow_rate")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_flow_rate"));
doc[FPSTR(HA_OBJECT_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) { bool publishSensorIndoorTemp(bool enabledByDefault = true) {
JsonDocument doc; JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("any");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("indoor_temp")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("indoor_temp"));
doc[FPSTR(HA_OBJECT_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) { bool publishSensorOutdoorTemp(bool enabledByDefault = true) {
JsonDocument doc; JsonDocument doc;
doc[FPSTR(HA_AVAILABILITY)][0][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status")); doc[FPSTR(HA_AVAILABILITY)][FPSTR(HA_TOPIC)] = this->getDeviceTopic(F("status"));
doc[FPSTR(HA_AVAILABILITY_MODE)] = F("any");
doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault; doc[FPSTR(HA_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("outdoor_temp")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("outdoor_temp"));
doc[FPSTR(HA_OBJECT_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) { bool publishSensorHeatingTemp(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_temp")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("heating_temp"));
doc[FPSTR(HA_OBJECT_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) { bool publishSensorDhwTemp(bool enabledByDefault = true) {
JsonDocument doc; 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_ENABLED_BY_DEFAULT)] = enabledByDefault;
doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_temp")); doc[FPSTR(HA_UNIQUE_ID)] = this->getObjectId(F("dhw_temp"));
doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_temp")); doc[FPSTR(HA_OBJECT_ID)] = this->getObjectId(F("dhw_temp"));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,13 +3,6 @@
#if USE_BLE #if USE_BLE
#include <NimBLEDevice.h> #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 #endif
class SensorsTask : public LeanTask { class SensorsTask : public LeanTask {
@@ -25,22 +18,11 @@ public:
} }
~SensorsTask() { ~SensorsTask() {
if (this->outdoorSensor != nullptr) {
delete this->outdoorSensor; delete this->outdoorSensor;
}
if (this->oneWireOutdoorSensor != nullptr) {
delete this->oneWireOutdoorSensor; delete this->oneWireOutdoorSensor;
}
if (this->indoorSensor != nullptr) {
delete this->indoorSensor; delete this->indoorSensor;
}
if (this->oneWireIndoorSensor != nullptr) {
delete this->oneWireIndoorSensor; delete this->oneWireIndoorSensor;
} }
}
protected: protected:
OneWire* oneWireOutdoorSensor = nullptr; OneWire* oneWireOutdoorSensor = nullptr;
@@ -61,9 +43,8 @@ protected:
#if USE_BLE #if USE_BLE
BLEClient* pBleClient = nullptr; BLEClient* pBleClient = nullptr;
BLERemoteService* pBleServiceBattery = nullptr;
BLERemoteService* pBleServiceEnvironment = nullptr;
bool initBleSensor = false; bool initBleSensor = false;
bool initBleNotify = false;
#endif #endif
const char* getTaskName() { const char* getTaskName() {
@@ -88,58 +69,135 @@ protected:
} }
#if USE_BLE #if USE_BLE
if (settings.sensors.indoor.type == 3 && strlen(settings.sensors.indoor.bleAddresss)) { if (settings.sensors.indoor.type == 3) {
bluetoothSensor(); bluetoothSensor();
} }
#endif #endif
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"), vars.temperatures.outdoor);
}
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"), vars.temperatures.indoor);
}
} }
#if USE_BLE #if USE_BLE
void bluetoothSensor() { void bluetoothSensor() {
static bool initBleNotify = false;
if (!initBleSensor && millis() > 5000) { 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(""); 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; initBleSensor = true;
} }
if (pBleClient && pBleClient->isConnected()) { if (!initBleSensor || pBleClient->isConnected()) {
Log.straceln(FPSTR(L_SENSORS_BLE), "Connected. Free heap %u bytes", ESP.getFreeHeap()); return;
if (pBleServiceBattery) {
uint8_t batteryLevel = *reinterpret_cast<const uint8_t *>(pBleServiceBattery->getValue(bleUuidCharacteristicBatteryLevel).data());
Log.straceln(FPSTR(L_SENSORS_BLE), "Battery: %d", batteryLevel);
} }
if (pBleServiceEnvironment) { // Reset init notify flag
float temperature = *reinterpret_cast<const int16_t *>(pBleServiceEnvironment->getValue(bleUuidCharacteristicTemperature).data()) / 100.0f; this->initBleNotify = false;
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);
vars.temperatures.indoor = temperature + settings.sensors.indoor.offset; // 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;
} }
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 { } else {
Log.straceln(FPSTR(L_SENSORS_BLE), "Not connected"); 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());
}
}
}
// 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 #endif
@@ -205,12 +263,6 @@ protected:
} }
this->filteredOutdoorTemp = floor(this->filteredOutdoorTemp * 100) / 100; 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->outdoorSensor->requestTemperatures();
this->startOutdoorConversionTime = millis(); this->startOutdoorConversionTime = millis();
} }
@@ -277,12 +329,6 @@ protected:
} }
this->filteredIndoorTemp = floor(this->filteredIndoorTemp * 100) / 100; 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->indoorSensor->requestTemperatures();
this->startIndoorConversionTime = millis(); this->startIndoorConversionTime = millis();
} }

View File

@@ -110,7 +110,7 @@ struct Settings {
// 1 - manual, 2 - ds18b20, 3 - ble // 1 - manual, 2 - ds18b20, 3 - ble
byte type = 1; byte type = 1;
byte pin = SENSOR_INDOOR_PIN_DEFAULT; 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; float offset = 0.0f;
} indoor; } indoor;
} sensors; } sensors;
@@ -166,17 +166,17 @@ struct Variables {
unsigned long extPumpLastEnableTime = 0; unsigned long extPumpLastEnableTime = 0;
byte dhwMinTemp = DEFAULT_DHW_MIN_TEMP; byte dhwMinTemp = DEFAULT_DHW_MIN_TEMP;
byte dhwMaxTemp = DEFAULT_DHW_MAX_TEMP; byte dhwMaxTemp = DEFAULT_DHW_MAX_TEMP;
byte maxModulation; byte maxModulation = 0;
uint8_t slaveMemberId; uint8_t slaveMemberId = 0;
uint8_t slaveFlags; uint8_t slaveFlags = 0;
uint8_t slaveType; uint8_t slaveType = 0;
uint8_t slaveVersion; uint8_t slaveVersion = 0;
float slaveOtVersion; float slaveOtVersion = 0.0f;
uint8_t masterMemberId; uint8_t masterMemberId = 0;
uint8_t masterFlags; uint8_t masterFlags = 0;
uint8_t masterType; uint8_t masterType = 0;
uint8_t masterVersion; uint8_t masterVersion = 0;
float masterOtVersion; float masterOtVersion = 0;
} parameters; } parameters;
struct { struct {

View File

@@ -1,5 +1,5 @@
#define PROJECT_NAME "OpenTherm Gateway" #define PROJECT_NAME "OpenTherm Gateway"
#define PROJECT_VERSION "1.4.0-rc.14" #define PROJECT_VERSION "1.4.0-rc.15"
#define PROJECT_REPO "https://github.com/Laxilef/OTGateway" #define PROJECT_REPO "https://github.com/Laxilef/OTGateway"
#define EMERGENCY_TIME_TRESHOLD 120000 #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()) { if (!src["sta"]["ssid"].isNull()) {
String value = src["sta"]["ssid"].as<String>(); 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"]["type"] = src.sensors.indoor.type;
dst["sensors"]["indoor"]["pin"] = src.sensors.indoor.pin; 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); dst["sensors"]["indoor"]["offset"] = roundd(src.sensors.indoor.offset, 2);
if (!safe) { if (!safe) {
@@ -486,7 +498,7 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
if (!src["mqtt"]["port"].isNull()) { if (!src["mqtt"]["port"].isNull()) {
unsigned short value = src["mqtt"]["port"].as<unsigned short>(); unsigned short value = src["mqtt"]["port"].as<unsigned short>();
if (value >= 0 && value <= 65536) { if (value > 0 && value <= 65535) {
dst.mqtt.port = value; dst.mqtt.port = value;
changed = true; changed = true;
} }
@@ -821,9 +833,12 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
#if USE_BLE #if USE_BLE
if (!src["sensors"]["indoor"]["bleAddresss"].isNull()) { if (!src["sensors"]["indoor"]["bleAddresss"].isNull()) {
String value = src["sensors"]["indoor"]["bleAddresss"].as<String>(); 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; changed = true;
} }
} }