mirror of
https://github.com/Laxilef/OTGateway.git
synced 2025-12-12 03:04:27 +05:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd53d1ef3e | ||
|
|
3bd8010b74 | ||
|
|
6a26e27d39 | ||
|
|
8fa440810c | ||
|
|
95b18385ba | ||
|
|
4457e16a8f | ||
|
|
1965ca671e | ||
|
|
0d1873ec77 | ||
|
|
38ec56fb33 | ||
|
|
bb7c3eeba3 | ||
|
|
0c778d4c7f | ||
|
|
2e5e5e59a8 | ||
|
|
e1623e7b63 | ||
|
|
80b91d9a01 | ||
|
|
25b70e4db5 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,8 +1,13 @@
|
|||||||
.pio
|
.pio
|
||||||
.vscode
|
.vscode
|
||||||
build/*.bin
|
build/*
|
||||||
data/*
|
data/*
|
||||||
|
managed_components/*
|
||||||
|
node_modules/*
|
||||||
secrets.ini
|
secrets.ini
|
||||||
node_modules
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
*.lock
|
||||||
|
sdkconfig.*
|
||||||
|
CMakeLists.txt
|
||||||
|
!sdkconfig.defaults
|
||||||
!.gitkeep
|
!.gitkeep
|
||||||
@@ -48,6 +48,10 @@ let paths = {
|
|||||||
{
|
{
|
||||||
src: 'src_data/images/*.*',
|
src: 'src_data/images/*.*',
|
||||||
dest: 'data/static/images/'
|
dest: 'data/static/images/'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: 'src_data/*.txt',
|
||||||
|
dest: 'data/static/'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
pages: {
|
pages: {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ extra_configs = secrets.default.ini
|
|||||||
core_dir = .pio
|
core_dir = .pio
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
version = 1.5.3
|
version = 1.5.4
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
bblanchon/ArduinoJson@^7.3.0
|
bblanchon/ArduinoJson@^7.3.0
|
||||||
@@ -84,7 +84,7 @@ board_build.ldscript = eagle.flash.4m1m.ld
|
|||||||
;platform_packages =
|
;platform_packages =
|
||||||
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
|
; framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.5
|
||||||
; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip
|
; framework-arduinoespressif32-libs @ https://github.com/espressif/esp32-arduino-lib-builder/releases/download/idf-release_v5.1/esp32-arduino-libs-idf-release_v5.1-33fbade6.zip
|
||||||
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.11/platform-espressif32.zip
|
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip
|
||||||
platform_packages =
|
platform_packages =
|
||||||
board_build.partitions = esp32_partitions.csv
|
board_build.partitions = esp32_partitions.csv
|
||||||
lib_deps =
|
lib_deps =
|
||||||
@@ -287,21 +287,26 @@ build_flags =
|
|||||||
|
|
||||||
[env:esp32_c6]
|
[env:esp32_c6]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
framework = arduino, espidf
|
||||||
platform_packages = ${esp32_defaults.platform_packages}
|
platform_packages = ${esp32_defaults.platform_packages}
|
||||||
board = esp32-c6-devkitm-1
|
board = esp32-c6-devkitm-1
|
||||||
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
board_build.partitions = ${esp32_defaults.board_build.partitions}
|
||||||
lib_deps =
|
lib_deps = ${esp32_defaults.lib_deps}
|
||||||
${esp32_defaults.lib_deps}
|
lib_ignore =
|
||||||
;${esp32_defaults.nimble_lib}
|
${esp32_defaults.lib_ignore}
|
||||||
lib_ignore = ${esp32_defaults.lib_ignore}
|
|
||||||
extra_scripts = ${esp32_defaults.extra_scripts}
|
extra_scripts = ${esp32_defaults.extra_scripts}
|
||||||
build_unflags =
|
build_unflags =
|
||||||
-mtext-section-literals
|
-mtext-section-literals
|
||||||
build_type = ${esp32_defaults.build_type}
|
build_type = ${esp32_defaults.build_type}
|
||||||
build_flags =
|
build_flags =
|
||||||
${esp32_defaults.build_flags}
|
${esp32_defaults.build_flags}
|
||||||
; Currently the NimBLE library is incompatible with ESP32 C6
|
-D USE_BLE=1
|
||||||
;-D USE_BLE=1
|
-D DEFAULT_OT_IN_GPIO=15
|
||||||
|
-D DEFAULT_OT_OUT_GPIO=23
|
||||||
|
-D DEFAULT_SENSOR_OUTDOOR_GPIO=0
|
||||||
|
-D DEFAULT_SENSOR_INDOOR_GPIO=0
|
||||||
|
-D DEFAULT_STATUS_LED_GPIO=11
|
||||||
|
-D DEFAULT_OT_RX_LED_GPIO=10
|
||||||
|
|
||||||
[env:otthing]
|
[env:otthing]
|
||||||
platform = ${esp32_defaults.platform}
|
platform = ${esp32_defaults.platform}
|
||||||
|
|||||||
33
sdkconfig.defaults
Normal file
33
sdkconfig.defaults
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# Source:
|
||||||
|
# https://github.com/pioarduino/platform-espressif32/tree/main/examples/espidf-arduino-h2zero-BLE_scan
|
||||||
|
|
||||||
|
CONFIG_FREERTOS_HZ=1000
|
||||||
|
CONFIG_MBEDTLS_PSK_MODES=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
|
||||||
|
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||||
|
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||||
|
CONFIG_ESPTOOLPY_HEADER_FLASHSIZE_UPDATE=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# BT config
|
||||||
|
CONFIG_BT_ENABLED=y
|
||||||
|
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||||
|
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||||
|
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||||
|
CONFIG_BT_BLUEDROID_ENABLED=n
|
||||||
|
CONFIG_BT_NIMBLE_ENABLED=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Arduino Configuration
|
||||||
|
CONFIG_AUTOSTART_ARDUINO=y
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_COMPILATION=y
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_Zigbee=n
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_Matter=n
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_WiFiProv=n
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_BLE=n
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_BluetoothSerial=n
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_SimpleBLE=n
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_RainMaker=n
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_OpenThread=n
|
||||||
|
CONFIG_ARDUINO_SELECTIVE_Insights=n
|
||||||
@@ -1215,7 +1215,7 @@ public:
|
|||||||
|
|
||||||
doc[FPSTR(HA_MIN_TEMP)] = minTemp;
|
doc[FPSTR(HA_MIN_TEMP)] = minTemp;
|
||||||
doc[FPSTR(HA_MAX_TEMP)] = maxTemp;
|
doc[FPSTR(HA_MAX_TEMP)] = maxTemp;
|
||||||
doc[FPSTR(HA_TEMP_STEP)] = 0.5f;
|
doc[FPSTR(HA_TEMP_STEP)] = 0.1f;
|
||||||
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
doc[FPSTR(HA_EXPIRE_AFTER)] = this->expireAfter;
|
||||||
doc.shrinkToFit();
|
doc.shrinkToFit();
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ public:
|
|||||||
this->prevPubVarsTime = 0;
|
this->prevPubVarsTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void rebuildHaEntity(uint8_t sensorId, Sensors::Settings& prevSettings) {
|
inline void reconfigureSensor(uint8_t sensorId, Sensors::Settings& prevSettings) {
|
||||||
this->queueRebuildingHaEntities[sensorId] = prevSettings;
|
this->queueReconfigureSensors[sensorId] = prevSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -81,7 +81,7 @@ protected:
|
|||||||
MqttWriter* writer = nullptr;
|
MqttWriter* writer = nullptr;
|
||||||
UnitSystem currentUnitSystem = UnitSystem::METRIC;
|
UnitSystem currentUnitSystem = UnitSystem::METRIC;
|
||||||
bool currentHomeAssistantDiscovery = false;
|
bool currentHomeAssistantDiscovery = false;
|
||||||
std::unordered_map<uint8_t, Sensors::Settings> queueRebuildingHaEntities;
|
std::unordered_map<uint8_t, Sensors::Settings> queueReconfigureSensors;
|
||||||
unsigned short readyForSendTime = 30000;
|
unsigned short readyForSendTime = 30000;
|
||||||
unsigned long lastReconnectTime = 0;
|
unsigned long lastReconnectTime = 0;
|
||||||
unsigned long connectedTime = 0;
|
unsigned long connectedTime = 0;
|
||||||
@@ -276,8 +276,8 @@ protected:
|
|||||||
this->publishNonStaticHaEntities();
|
this->publishNonStaticHaEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rebuilding ha configs
|
||||||
for (auto& [sensorId, prevSettings] : this->queueRebuildingHaEntities) {
|
for (auto& [sensorId, prevSettings] : this->queueReconfigureSensors) {
|
||||||
Log.sinfoln(FPSTR(L_MQTT_HA), F("Rebuilding config for sensor #%hhu '%s'"), sensorId, prevSettings.name);
|
Log.sinfoln(FPSTR(L_MQTT_HA), F("Rebuilding config for sensor #%hhu '%s'"), sensorId, prevSettings.name);
|
||||||
|
|
||||||
// delete old config
|
// delete old config
|
||||||
@@ -298,15 +298,6 @@ protected:
|
|||||||
this->haHelper->deleteDynamicSensor(prevSettings, Sensors::ValueType::TEMPERATURE);
|
this->haHelper->deleteDynamicSensor(prevSettings, Sensors::ValueType::TEMPERATURE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Sensors::Type::MANUAL:
|
|
||||||
this->client->unsubscribe(
|
|
||||||
this->haHelper->getDeviceTopic(
|
|
||||||
F("sensors"),
|
|
||||||
Sensors::makeObjectId(prevSettings.name).c_str(),
|
|
||||||
F("set")
|
|
||||||
).c_str()
|
|
||||||
);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this->haHelper->deleteDynamicSensor(prevSettings, Sensors::ValueType::PRIMARY);
|
this->haHelper->deleteDynamicSensor(prevSettings, Sensors::ValueType::PRIMARY);
|
||||||
}
|
}
|
||||||
@@ -334,24 +325,49 @@ protected:
|
|||||||
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::TEMPERATURE, settings.system.unitSystem);
|
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::TEMPERATURE, settings.system.unitSystem);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Sensors::Type::MANUAL:
|
default:
|
||||||
this->client->subscribe(
|
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::PRIMARY, settings.system.unitSystem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (this->currentHomeAssistantDiscovery) {
|
||||||
|
this->currentHomeAssistantDiscovery = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reconfigure manual sensors
|
||||||
|
for (auto& [sensorId, prevSettings] : this->queueReconfigureSensors) {
|
||||||
|
// unsubscribe from old topic
|
||||||
|
if (strlen(prevSettings.name) && prevSettings.enabled) {
|
||||||
|
if (prevSettings.type == Sensors::Type::MANUAL) {
|
||||||
|
this->client->unsubscribe(
|
||||||
this->haHelper->getDeviceTopic(
|
this->haHelper->getDeviceTopic(
|
||||||
F("sensors"),
|
F("sensors"),
|
||||||
Sensors::makeObjectId(prevSettings.name).c_str(),
|
Sensors::makeObjectId(prevSettings.name).c_str(),
|
||||||
F("set")
|
F("set")
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
if (!Sensors::hasEnabledAndValid(sensorId)) {
|
||||||
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::PRIMARY, settings.system.unitSystem);
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
this->queueRebuildingHaEntities.clear();
|
|
||||||
|
|
||||||
} else if (this->currentHomeAssistantDiscovery) {
|
// subscribe to new topic
|
||||||
this->currentHomeAssistantDiscovery = false;
|
auto& sSettings = Sensors::settings[sensorId];
|
||||||
|
if (sSettings.type == Sensors::Type::MANUAL) {
|
||||||
|
this->client->subscribe(
|
||||||
|
this->haHelper->getDeviceTopic(
|
||||||
|
F("sensors"),
|
||||||
|
Sensors::makeObjectId(sSettings.name).c_str(),
|
||||||
|
F("set")
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear queue
|
||||||
|
this->queueReconfigureSensors.clear();
|
||||||
|
|
||||||
if (this->newConnection) {
|
if (this->newConnection) {
|
||||||
this->newConnection = false;
|
this->newConnection = false;
|
||||||
@@ -366,6 +382,26 @@ protected:
|
|||||||
|
|
||||||
this->client->subscribe(this->haHelper->getDeviceTopic(F("settings/set")).c_str());
|
this->client->subscribe(this->haHelper->getDeviceTopic(F("settings/set")).c_str());
|
||||||
this->client->subscribe(this->haHelper->getDeviceTopic(F("state/set")).c_str());
|
this->client->subscribe(this->haHelper->getDeviceTopic(F("state/set")).c_str());
|
||||||
|
|
||||||
|
// subscribe to manual sensors
|
||||||
|
for (uint8_t sensorId = 0; sensorId <= Sensors::getMaxSensorId(); sensorId++) {
|
||||||
|
if (!Sensors::hasEnabledAndValid(sensorId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& sSettings = Sensors::settings[sensorId];
|
||||||
|
if (sSettings.type != Sensors::Type::MANUAL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->client->subscribe(
|
||||||
|
this->haHelper->getDeviceTopic(
|
||||||
|
F("sensors"),
|
||||||
|
Sensors::makeObjectId(sSettings.name).c_str(),
|
||||||
|
F("set")
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDisconnect() {
|
void onDisconnect() {
|
||||||
@@ -514,15 +550,6 @@ protected:
|
|||||||
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::TEMPERATURE, settings.system.unitSystem);
|
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::TEMPERATURE, settings.system.unitSystem);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Sensors::Type::MANUAL:
|
|
||||||
this->client->subscribe(
|
|
||||||
this->haHelper->getDeviceTopic(
|
|
||||||
F("sensors"),
|
|
||||||
Sensors::makeObjectId(sSettings.name).c_str(),
|
|
||||||
F("set")
|
|
||||||
).c_str()
|
|
||||||
);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::PRIMARY, settings.system.unitSystem);
|
this->haHelper->publishDynamicSensor(sSettings, Sensors::ValueType::PRIMARY, settings.system.unitSystem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -214,7 +214,12 @@ protected:
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vars.slave.connected && millis() - this->lastSuccessResponse < 1325) {
|
// 5 request retries
|
||||||
|
// 1000ms maximum response waiting time
|
||||||
|
// 100ms delay between requests
|
||||||
|
// +15%
|
||||||
|
// 5 * (1000 + 100) * 1.15 = 6325 ms
|
||||||
|
if (!vars.slave.connected && millis() - this->lastSuccessResponse < 6325) {
|
||||||
Log.sinfoln(
|
Log.sinfoln(
|
||||||
FPSTR(L_OT),
|
FPSTR(L_OT),
|
||||||
F("Connected, downtime: %lu s."),
|
F("Connected, downtime: %lu s."),
|
||||||
@@ -224,7 +229,7 @@ protected:
|
|||||||
this->connectedTime = millis();
|
this->connectedTime = millis();
|
||||||
vars.slave.connected = true;
|
vars.slave.connected = true;
|
||||||
|
|
||||||
} else if (vars.slave.connected && millis() - this->lastSuccessResponse > 1325) {
|
} else if (vars.slave.connected && millis() - this->lastSuccessResponse > 6325) {
|
||||||
Log.swarningln(
|
Log.swarningln(
|
||||||
FPSTR(L_OT),
|
FPSTR(L_OT),
|
||||||
F("Disconnected, uptime: %lu s."),
|
F("Disconnected, uptime: %lu s."),
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
//#define PORTAL_CACHE "max-age=86400"
|
//#define PORTAL_CACHE "max-age=86400"
|
||||||
#define PORTAL_CACHE nullptr
|
#define PORTAL_CACHE nullptr
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
#include <ESP8266mDNS.h>
|
||||||
#include <ESP8266WebServer.h>
|
#include <ESP8266WebServer.h>
|
||||||
#include <Updater.h>
|
#include <Updater.h>
|
||||||
using WebServer = ESP8266WebServer;
|
using WebServer = ESP8266WebServer;
|
||||||
#else
|
#else
|
||||||
|
#include <ESPmDNS.h>
|
||||||
#include <WebServer.h>
|
#include <WebServer.h>
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -53,7 +55,7 @@ protected:
|
|||||||
bool webServerEnabled = false;
|
bool webServerEnabled = false;
|
||||||
bool dnsServerEnabled = false;
|
bool dnsServerEnabled = false;
|
||||||
unsigned long webServerChangeState = 0;
|
unsigned long webServerChangeState = 0;
|
||||||
unsigned long dnsServerChangeState = 0;
|
bool mDnsState = false;
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32)
|
#if defined(ARDUINO_ARCH_ESP32)
|
||||||
const char* getTaskName() override {
|
const char* getTaskName() override {
|
||||||
@@ -616,7 +618,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
tMqtt->rebuildHaEntity(sensorId, prevSettings);
|
tMqtt->reconfigureSensor(sensorId, prevSettings);
|
||||||
fsSensorsSettings.update();
|
fsSensorsSettings.update();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -858,6 +860,7 @@ protected:
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this->webServer->serveStatic("/robots.txt", LittleFS, "/static/robots.txt", PORTAL_CACHE);
|
||||||
this->webServer->serveStatic("/favicon.ico", LittleFS, "/static/images/favicon.ico", PORTAL_CACHE);
|
this->webServer->serveStatic("/favicon.ico", LittleFS, "/static/images/favicon.ico", PORTAL_CACHE);
|
||||||
this->webServer->serveStatic("/static", LittleFS, "/static", PORTAL_CACHE);
|
this->webServer->serveStatic("/static", LittleFS, "/static", PORTAL_CACHE);
|
||||||
}
|
}
|
||||||
@@ -872,6 +875,16 @@ protected:
|
|||||||
this->startWebServer();
|
this->startWebServer();
|
||||||
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("Started: AP up or STA connected"));
|
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("Started: AP up or STA connected"));
|
||||||
|
|
||||||
|
// Enabling mDNS
|
||||||
|
if (!this->mDnsState && settings.portal.mdns) {
|
||||||
|
if (MDNS.begin(networkSettings.hostname)) {
|
||||||
|
MDNS.addService("http", "tcp", 80);
|
||||||
|
this->mDnsState = true;
|
||||||
|
|
||||||
|
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("mDNS enabled and service added"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
::optimistic_yield(1000);
|
::optimistic_yield(1000);
|
||||||
#endif
|
#endif
|
||||||
@@ -880,13 +893,29 @@ protected:
|
|||||||
this->stopWebServer();
|
this->stopWebServer();
|
||||||
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("Stopped: AP and STA down"));
|
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("Stopped: AP and STA down"));
|
||||||
|
|
||||||
|
// Disabling mDNS
|
||||||
|
if (this->mDnsState) {
|
||||||
|
MDNS.end();
|
||||||
|
this->mDnsState = false;
|
||||||
|
|
||||||
|
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("mDNS disabled"));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
::optimistic_yield(1000);
|
::optimistic_yield(1000);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disabling mDNS if disabled in settings
|
||||||
|
if (this->mDnsState && !settings.portal.mdns) {
|
||||||
|
MDNS.end();
|
||||||
|
this->mDnsState = false;
|
||||||
|
|
||||||
|
Log.straceln(FPSTR(L_PORTAL_WEBSERVER), F("mDNS disabled"));
|
||||||
|
}
|
||||||
|
|
||||||
// dns server
|
// dns server
|
||||||
if (!this->stateDnsServer() && this->stateWebServer() && network->isApEnabled() && network->hasApClients() && millis() - this->dnsServerChangeState >= this->changeStateInterval) {
|
if (!this->stateDnsServer() && !network->isConnected() && network->isApEnabled() && this->stateWebServer()) {
|
||||||
this->startDnsServer();
|
this->startDnsServer();
|
||||||
Log.straceln(FPSTR(L_PORTAL_DNSSERVER), F("Started: AP up"));
|
Log.straceln(FPSTR(L_PORTAL_DNSSERVER), F("Started: AP up"));
|
||||||
|
|
||||||
@@ -894,9 +923,9 @@ protected:
|
|||||||
::optimistic_yield(1000);
|
::optimistic_yield(1000);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else if (this->stateDnsServer() && (!network->isApEnabled() || !this->stateWebServer())) {
|
} else if (this->stateDnsServer() && (network->isConnected() || !network->isApEnabled() || !this->stateWebServer())) {
|
||||||
this->stopDnsServer();
|
this->stopDnsServer();
|
||||||
Log.straceln(FPSTR(L_PORTAL_DNSSERVER), F("Stopped: AP down"));
|
Log.straceln(FPSTR(L_PORTAL_DNSSERVER), F("Stopped: AP down/STA connected"));
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP8266
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
::optimistic_yield(1000);
|
::optimistic_yield(1000);
|
||||||
@@ -1006,7 +1035,6 @@ protected:
|
|||||||
|
|
||||||
this->dnsServer->start(53, "*", network->getApIp());
|
this->dnsServer->start(53, "*", network->getApIp());
|
||||||
this->dnsServerEnabled = true;
|
this->dnsServerEnabled = true;
|
||||||
this->dnsServerChangeState = millis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopDnsServer() {
|
void stopDnsServer() {
|
||||||
@@ -1017,6 +1045,5 @@ protected:
|
|||||||
//this->dnsServer->processNextRequest();
|
//this->dnsServer->processNextRequest();
|
||||||
this->dnsServer->stop();
|
this->dnsServer->stop();
|
||||||
this->dnsServerEnabled = false;
|
this->dnsServerEnabled = false;
|
||||||
this->dnsServerChangeState = millis();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -496,9 +496,8 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rSensor.connected) {
|
// Mark connected
|
||||||
rSensor.connected = true;
|
Sensors::setConnectionStatusById(sensorId, true, true);
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->bleLastSetDtTime[sensorId] || millis() - this->bleLastSetDtTime[sensorId] > this->bleSetDtInterval) {
|
if (!this->bleLastSetDtTime[sensorId] || millis() - this->bleLastSetDtTime[sensorId] > this->bleSetDtInterval) {
|
||||||
struct tm ti;
|
struct tm ti;
|
||||||
@@ -521,7 +520,6 @@ protected:
|
|||||||
|
|
||||||
this->bleLastSetDtTime[sensorId] = millis();
|
this->bleLastSetDtTime[sensorId] = millis();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -981,16 +979,16 @@ protected:
|
|||||||
auto& rSensor = Sensors::results[sensorId];
|
auto& rSensor = Sensors::results[sensorId];
|
||||||
|
|
||||||
if (rSensor.connected && !sSensor.enabled) {
|
if (rSensor.connected && !sSensor.enabled) {
|
||||||
rSensor.connected = false;
|
Sensors::setConnectionStatusById(sensorId, false, false);
|
||||||
|
|
||||||
} else if (rSensor.connected && sSensor.type == Sensors::Type::NOT_CONFIGURED) {
|
} else if (rSensor.connected && sSensor.type == Sensors::Type::NOT_CONFIGURED) {
|
||||||
rSensor.connected = false;
|
Sensors::setConnectionStatusById(sensorId, false, false);
|
||||||
|
|
||||||
} else if (rSensor.connected && sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
} else if (rSensor.connected && sSensor.purpose == Sensors::Purpose::NOT_CONFIGURED) {
|
||||||
rSensor.connected = false;
|
Sensors::setConnectionStatusById(sensorId, false, false);
|
||||||
|
|
||||||
} else if (sSensor.type != Sensors::Type::MANUAL && rSensor.connected && (millis() - rSensor.activityTime) > this->disconnectedTimeout) {
|
} else if (sSensor.type != Sensors::Type::MANUAL && rSensor.connected && (millis() - rSensor.activityTime) > this->disconnectedTimeout) {
|
||||||
rSensor.connected = false;
|
Sensors::setConnectionStatusById(sensorId, false, false);
|
||||||
|
|
||||||
}/* else if (!rSensor.connected) {
|
}/* else if (!rSensor.connected) {
|
||||||
rSensor.connected = true;
|
rSensor.connected = true;
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ struct Settings {
|
|||||||
bool auth = false;
|
bool auth = false;
|
||||||
char login[13] = DEFAULT_PORTAL_LOGIN;
|
char login[13] = DEFAULT_PORTAL_LOGIN;
|
||||||
char password[33] = DEFAULT_PORTAL_PASSWORD;
|
char password[33] = DEFAULT_PORTAL_PASSWORD;
|
||||||
|
bool mdns = true;
|
||||||
} portal;
|
} portal;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DEFAULT_HOSTNAME
|
#ifndef DEFAULT_HOSTNAME
|
||||||
#define DEFAULT_HOSTNAME "opentherm"
|
#define DEFAULT_HOSTNAME ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DEFAULT_AP_SSID
|
#ifndef DEFAULT_AP_SSID
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DEFAULT_MQTT_PREFIX
|
#ifndef DEFAULT_MQTT_PREFIX
|
||||||
#define DEFAULT_MQTT_PREFIX "opentherm"
|
#define DEFAULT_MQTT_PREFIX ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef DEFAULT_OT_IN_GPIO
|
#ifndef DEFAULT_OT_IN_GPIO
|
||||||
|
|||||||
3
src/idf_component.yml
Normal file
3
src/idf_component.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
dependencies:
|
||||||
|
idf: ">=5.3.2"
|
||||||
|
h2zero/esp-nimble-cpp: ">=2.2.1"
|
||||||
12
src/main.cpp
12
src/main.cpp
@@ -102,6 +102,12 @@ void setup() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate hostname if it is empty
|
||||||
|
if (!strlen(networkSettings.hostname)) {
|
||||||
|
strcpy(networkSettings.hostname, getChipId("otgateway-").c_str());
|
||||||
|
fsNetworkSettings.update();
|
||||||
|
}
|
||||||
|
|
||||||
network = (new NetworkMgr)
|
network = (new NetworkMgr)
|
||||||
->setHostname(networkSettings.hostname)
|
->setHostname(networkSettings.hostname)
|
||||||
->setStaCredentials(
|
->setStaCredentials(
|
||||||
@@ -148,6 +154,12 @@ void setup() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate mqtt prefix if it is empty
|
||||||
|
if (!strlen(settings.mqtt.prefix)) {
|
||||||
|
strcpy(settings.mqtt.prefix, getChipId("otgateway_").c_str());
|
||||||
|
fsSettings.update();
|
||||||
|
}
|
||||||
|
|
||||||
// Logs settings
|
// Logs settings
|
||||||
if (!settings.system.serial.enabled) {
|
if (!settings.system.serial.enabled) {
|
||||||
Serial.end();
|
Serial.end();
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ const char S_MAX_MODULATION[] PROGMEM = "maxModulation";
|
|||||||
const char S_MAX_POWER[] PROGMEM = "maxPower";
|
const char S_MAX_POWER[] PROGMEM = "maxPower";
|
||||||
const char S_MAX_TEMP[] PROGMEM = "maxTemp";
|
const char S_MAX_TEMP[] PROGMEM = "maxTemp";
|
||||||
const char S_MAX_TEMP_SYNC_WITH_TARGET_TEMP[] PROGMEM = "maxTempSyncWithTargetTemp";
|
const char S_MAX_TEMP_SYNC_WITH_TARGET_TEMP[] PROGMEM = "maxTempSyncWithTargetTemp";
|
||||||
|
const char S_MDNS[] PROGMEM = "mdns";
|
||||||
const char S_MEMBER_ID[] PROGMEM = "memberId";
|
const char S_MEMBER_ID[] PROGMEM = "memberId";
|
||||||
const char S_MIN[] PROGMEM = "min";
|
const char S_MIN[] PROGMEM = "min";
|
||||||
const char S_MIN_FREE[] PROGMEM = "minFree";
|
const char S_MIN_FREE[] PROGMEM = "minFree";
|
||||||
|
|||||||
44
src/utils.h
44
src/utils.h
@@ -1,5 +1,37 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
String getChipId(const char* prefix = nullptr, const char* suffix = nullptr) {
|
||||||
|
String chipId;
|
||||||
|
chipId.reserve(
|
||||||
|
6
|
||||||
|
+ (prefix != nullptr ? strlen(prefix) : 0)
|
||||||
|
+ (suffix != nullptr ? strlen(suffix) : 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (prefix != nullptr) {
|
||||||
|
chipId.concat(prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cid = 0;
|
||||||
|
#if defined(ARDUINO_ARCH_ESP8266)
|
||||||
|
cid = ESP.getChipId();
|
||||||
|
#elif defined(ARDUINO_ARCH_ESP32)
|
||||||
|
// https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/ChipID/GetChipID/GetChipID.ino
|
||||||
|
for (uint8_t i = 0; i < 17; i = i + 8) {
|
||||||
|
cid |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
chipId += String(cid, HEX);
|
||||||
|
|
||||||
|
if (suffix != nullptr) {
|
||||||
|
chipId.concat(suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
chipId.trim();
|
||||||
|
return chipId;
|
||||||
|
}
|
||||||
|
|
||||||
bool isLeapYear(short year) {
|
bool isLeapYear(short year) {
|
||||||
if (year % 4 != 0) {
|
if (year % 4 != 0) {
|
||||||
return false;
|
return false;
|
||||||
@@ -408,6 +440,7 @@ void settingsToJson(const Settings& src, JsonVariant dst, bool safe = false) {
|
|||||||
portal[FPSTR(S_AUTH)] = src.portal.auth;
|
portal[FPSTR(S_AUTH)] = src.portal.auth;
|
||||||
portal[FPSTR(S_LOGIN)] = src.portal.login;
|
portal[FPSTR(S_LOGIN)] = src.portal.login;
|
||||||
portal[FPSTR(S_PASSWORD)] = src.portal.password;
|
portal[FPSTR(S_PASSWORD)] = src.portal.password;
|
||||||
|
portal[FPSTR(S_MDNS)] = src.portal.mdns;
|
||||||
|
|
||||||
auto opentherm = dst[FPSTR(S_OPENTHERM)].to<JsonObject>();
|
auto opentherm = dst[FPSTR(S_OPENTHERM)].to<JsonObject>();
|
||||||
opentherm[FPSTR(S_UNIT_SYSTEM)] = static_cast<uint8_t>(src.opentherm.unitSystem);
|
opentherm[FPSTR(S_UNIT_SYSTEM)] = static_cast<uint8_t>(src.opentherm.unitSystem);
|
||||||
@@ -675,6 +708,15 @@ bool jsonToSettings(const JsonVariantConst src, Settings& dst, bool safe = false
|
|||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (src[FPSTR(S_PORTAL)][FPSTR(S_MDNS)].is<bool>()) {
|
||||||
|
bool value = src[FPSTR(S_PORTAL)][FPSTR(S_MDNS)].as<bool>();
|
||||||
|
|
||||||
|
if (value != dst.portal.mdns) {
|
||||||
|
dst.portal.mdns = value;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// opentherm
|
// opentherm
|
||||||
if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_UNIT_SYSTEM)].isNull()) {
|
if (!src[FPSTR(S_OPENTHERM)][FPSTR(S_UNIT_SYSTEM)].isNull()) {
|
||||||
@@ -1791,7 +1833,7 @@ bool jsonToSensorSettings(const uint8_t sensorId, const JsonVariantConst src, Se
|
|||||||
if (!src[FPSTR(S_FACTOR)].isNull()) {
|
if (!src[FPSTR(S_FACTOR)].isNull()) {
|
||||||
float value = src[FPSTR(S_FACTOR)].as<float>();
|
float value = src[FPSTR(S_FACTOR)].as<float>();
|
||||||
|
|
||||||
if (value > 0.09f && value <= 10.0f && fabsf(value - dst.factor) > 0.0001f) {
|
if (value > 0.09f && value <= 100.0f && fabsf(value - dst.factor) > 0.0001f) {
|
||||||
dst.factor = roundf(value, 3);
|
dst.factor = roundf(value, 3);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -296,7 +296,8 @@
|
|||||||
"portal": {
|
"portal": {
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"auth": "Require authentication"
|
"auth": "Require authentication",
|
||||||
|
"mdns": "Use mDNS"
|
||||||
},
|
},
|
||||||
|
|
||||||
"system": {
|
"system": {
|
||||||
|
|||||||
@@ -296,7 +296,8 @@
|
|||||||
"portal": {
|
"portal": {
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"auth": "Richiede autenticazione"
|
"auth": "Richiede autenticazione",
|
||||||
|
"mdns": "Usa mDNS"
|
||||||
},
|
},
|
||||||
|
|
||||||
"system": {
|
"system": {
|
||||||
|
|||||||
@@ -296,7 +296,8 @@
|
|||||||
"portal": {
|
"portal": {
|
||||||
"login": "Логин",
|
"login": "Логин",
|
||||||
"password": "Пароль",
|
"password": "Пароль",
|
||||||
"auth": "Требовать аутентификацию"
|
"auth": "Требовать аутентификацию",
|
||||||
|
"mdns": "Использовать mDNS"
|
||||||
},
|
},
|
||||||
|
|
||||||
"system": {
|
"system": {
|
||||||
|
|||||||
@@ -41,14 +41,18 @@
|
|||||||
<details open>
|
<details open>
|
||||||
<summary><b data-i18n>dashboard.section.control</b></summary>
|
<summary><b data-i18n>dashboard.section.control</b></summary>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="thermostat" id="thermostat-heating">
|
<div class="thermostat tHeat" data-purpose="heating" data-min="0" data-max="100" data-step="0.1" data-big-step="1">
|
||||||
<div class="thermostat-header" data-i18n>dashboard.thermostat.heating</div>
|
<div class="thermostat-header" data-i18n>dashboard.thermostat.heating</div>
|
||||||
<div class="thermostat-temp">
|
<div class="thermostat-temp">
|
||||||
<div class="thermostat-temp-target"><span id="tHeatTargetTemp"></span> <span class="tempUnit"></span></div>
|
<div class="thermostat-temp-target"><span class="targetTemp"></span> <span class="tempUnit"></span></div>
|
||||||
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tHeatCurrentTemp"></span> <span class="tempUnit"></span></div>
|
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tHeatCurrentTemp"></span> <span class="tempUnit"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="thermostat-minus"><button id="tHeatActionMinus" class="outline"><i class="icons-down"></i></button></div>
|
<div class="thermostat-minus">
|
||||||
<div class="thermostat-plus"><button id="tHeatActionPlus" class="outline"><i class="icons-up"></i></button></div>
|
<button class="tAction outline" data-action="decrement"><i class="icons-down"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="thermostat-plus">
|
||||||
|
<button class="tAction outline" data-action="increment"><i class="icons-up"></i></button>
|
||||||
|
</div>
|
||||||
<div class="thermostat-control">
|
<div class="thermostat-control">
|
||||||
<input type="checkbox" role="switch" id="tHeatEnabled" value="true">
|
<input type="checkbox" role="switch" id="tHeatEnabled" value="true">
|
||||||
<label htmlFor="tHeatEnabled" data-i18n>dashboard.thermostat.enable</label>
|
<label htmlFor="tHeatEnabled" data-i18n>dashboard.thermostat.enable</label>
|
||||||
@@ -58,14 +62,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="thermostat" id="thermostat-dhw">
|
<div class="thermostat tDhw" data-purpose="dhw" data-min="0" data-max="100" data-step="1" data-big-step="5">
|
||||||
<div class="thermostat-header" data-i18n>dashboard.thermostat.dhw</div>
|
<div class="thermostat-header" data-i18n>dashboard.thermostat.dhw</div>
|
||||||
<div class="thermostat-temp">
|
<div class="thermostat-temp">
|
||||||
<div class="thermostat-temp-target"><span id="tDhwTargetTemp"></span> <span class="tempUnit"></span></div>
|
<div class="thermostat-temp-target"><span class="targetTemp"></span> <span class="tempUnit"></span></div>
|
||||||
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tDhwCurrentTemp"></span> <span class="tempUnit"></span></div>
|
<div class="thermostat-temp-current"><span data-i18n>dashboard.thermostat.temp.current</span>: <span id="tDhwCurrentTemp"></span> <span class="tempUnit"></span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="thermostat-minus"><button class="outline" id="tDhwActionMinus"><i class="icons-down"></i></button></div>
|
<div class="thermostat-minus">
|
||||||
<div class="thermostat-plus"><button class="outline" id="tDhwActionPlus"><i class="icons-up"></i></button></div>
|
<button class="tAction outline" data-action="decrement"><i class="icons-down"></i></button>
|
||||||
|
</div>
|
||||||
|
<div class="thermostat-plus">
|
||||||
|
<button class="tAction outline" data-action="increment"><i class="icons-up"></i></button>
|
||||||
|
</div>
|
||||||
<div class="thermostat-control">
|
<div class="thermostat-control">
|
||||||
<input type="checkbox" role="switch" id="tDhwEnabled" value="true">
|
<input type="checkbox" role="switch" id="tDhwEnabled" value="true">
|
||||||
<label htmlFor="tDhwEnabled" data-i18n>dashboard.thermostat.enable</label>
|
<label htmlFor="tDhwEnabled" data-i18n>dashboard.thermostat.enable</label>
|
||||||
@@ -282,7 +290,6 @@
|
|||||||
<script src="/static/app.js?{BUILD_TIME}"></script>
|
<script src="/static/app.js?{BUILD_TIME}"></script>
|
||||||
<script>
|
<script>
|
||||||
let modifiedTime = null;
|
let modifiedTime = null;
|
||||||
let noRegulators;
|
|
||||||
let prevSettings;
|
let prevSettings;
|
||||||
let newSettings = {
|
let newSettings = {
|
||||||
heating: {
|
heating: {
|
||||||
@@ -300,78 +307,69 @@
|
|||||||
const lang = new Lang(document.getElementById('lang'));
|
const lang = new Lang(document.getElementById('lang'));
|
||||||
lang.build();
|
lang.build();
|
||||||
|
|
||||||
document.querySelector('#tHeatActionMinus').addEventListener('click', (event) => {
|
let actionTimer = null;
|
||||||
if (!prevSettings) {
|
let actionLongPress = false;
|
||||||
return;
|
document.querySelectorAll('.tAction').forEach((item) => {
|
||||||
|
const action = item.dataset.action;
|
||||||
|
const tContainer = item.parentNode.parentNode;
|
||||||
|
|
||||||
|
for (const eName of ['pointerup', 'pointercancel']) {
|
||||||
|
item.addEventListener(eName, (event) => {
|
||||||
|
clearInterval(actionTimer);
|
||||||
|
|
||||||
|
const purpose = tContainer.dataset.purpose;
|
||||||
|
const minTemp = parseFloat(tContainer.dataset.min);
|
||||||
|
const maxTemp = parseFloat(tContainer.dataset.max);
|
||||||
|
const step = parseFloat(tContainer.dataset.step);
|
||||||
|
const bigStep = parseFloat(tContainer.dataset.bigStep);
|
||||||
|
|
||||||
|
if (!actionLongPress && prevSettings) {
|
||||||
|
let value = 0;
|
||||||
|
if (action == 'increment') {
|
||||||
|
value = step;
|
||||||
|
|
||||||
|
} else if (action == 'decrement') {
|
||||||
|
value = -(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
newSettings.heating.target -= 0.5;
|
newSettings[purpose].target = parseFloat(constrain(newSettings[purpose].target + value, minTemp, maxTemp).toFixed(2));
|
||||||
modifiedTime = Date.now();
|
modifiedTime = Date.now();
|
||||||
|
setValue('.targetTemp', newSettings[purpose].target, tContainer);
|
||||||
let minTemp;
|
|
||||||
if (noRegulators) {
|
|
||||||
minTemp = prevSettings.heating.minTemp;
|
|
||||||
} else {
|
|
||||||
minTemp = prevSettings.system.unitSystem == 0 ? 5 : 41;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevSettings && newSettings.heating.target < minTemp) {
|
|
||||||
newSettings.heating.target = minTemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue('#tHeatTargetTemp', newSettings.heating.target);
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
document.querySelector('#tHeatActionPlus').addEventListener('click', (event) => {
|
item.addEventListener('pointerdown', (event) => {
|
||||||
if (!prevSettings) {
|
if (!prevSettings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
newSettings.heating.target += 0.5;
|
const purpose = tContainer.dataset.purpose;
|
||||||
|
const minTemp = parseFloat(tContainer.dataset.min);
|
||||||
|
const maxTemp = parseFloat(tContainer.dataset.max);
|
||||||
|
const step = parseFloat(tContainer.dataset.step);
|
||||||
|
const bigStep = parseFloat(tContainer.dataset.bigStep);
|
||||||
|
|
||||||
|
actionLongPress = false;
|
||||||
|
actionTimer = setInterval(() => {
|
||||||
|
if (!actionLongPress) {
|
||||||
|
actionLongPress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = 0;
|
||||||
|
if (action == 'increment') {
|
||||||
|
value = bigStep;
|
||||||
|
|
||||||
|
} else if (action == 'decrement') {
|
||||||
|
value = -(bigStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
newSettings[purpose].target = parseFloat(constrain(newSettings[purpose].target + value, minTemp, maxTemp).toFixed(2));
|
||||||
modifiedTime = Date.now();
|
modifiedTime = Date.now();
|
||||||
|
|
||||||
let maxTemp;
|
setValue('.targetTemp', newSettings[purpose].target, tContainer);
|
||||||
if (noRegulators) {
|
}, 500);
|
||||||
maxTemp = prevSettings.heating.maxTemp;
|
|
||||||
} else {
|
|
||||||
maxTemp = prevSettings.system.unitSystem == 0 ? 30 : 86;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prevSettings && newSettings.heating.target > maxTemp) {
|
|
||||||
newSettings.heating.target = maxTemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue('#tHeatTargetTemp', newSettings.heating.target);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('#tDhwActionMinus').addEventListener('click', (event) => {
|
|
||||||
if (!prevSettings) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
newSettings.dhw.target -= 1.0;
|
|
||||||
modifiedTime = Date.now();
|
|
||||||
|
|
||||||
if (newSettings.dhw.target < prevSettings.dhw.minTemp) {
|
|
||||||
newSettings.dhw.target = prevSettings.dhw.minTemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue('#tDhwTargetTemp', newSettings.dhw.target);
|
|
||||||
});
|
|
||||||
|
|
||||||
document.querySelector('#tDhwActionPlus').addEventListener('click', (event) => {
|
|
||||||
if (!prevSettings) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
newSettings.dhw.target += 1.0;
|
|
||||||
modifiedTime = Date.now();
|
|
||||||
|
|
||||||
if (newSettings.dhw.target > prevSettings.dhw.maxTemp) {
|
|
||||||
newSettings.dhw.target = prevSettings.dhw.maxTemp;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue('#tDhwTargetTemp', newSettings.dhw.target);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector('#tHeatEnabled').addEventListener('change', (event) => {
|
document.querySelector('#tHeatEnabled').addEventListener('change', (event) => {
|
||||||
@@ -486,7 +484,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
noRegulators = !result.opentherm.options.nativeHeatingControl && !result.equitherm.enabled && !result.pid.enabled;
|
|
||||||
prevSettings = result;
|
prevSettings = result;
|
||||||
unitSystem = result.system.unitSystem;
|
unitSystem = result.system.unitSystem;
|
||||||
newSettings.heating.enabled = result.heating.enabled;
|
newSettings.heating.enabled = result.heating.enabled;
|
||||||
@@ -496,17 +493,17 @@
|
|||||||
newSettings.dhw.target = result.dhw.target;
|
newSettings.dhw.target = result.dhw.target;
|
||||||
|
|
||||||
if (result.opentherm.options.dhwSupport) {
|
if (result.opentherm.options.dhwSupport) {
|
||||||
show('#thermostat-dhw');
|
show('.tDhw');
|
||||||
} else {
|
} else {
|
||||||
hide('#thermostat-dhw');
|
hide('.tDhw');
|
||||||
}
|
}
|
||||||
|
|
||||||
setCheckboxValue('#tHeatEnabled', result.heating.enabled);
|
setCheckboxValue('#tHeatEnabled', result.heating.enabled);
|
||||||
setCheckboxValue('#tHeatTurbo', result.heating.turbo);
|
setCheckboxValue('#tHeatTurbo', result.heating.turbo);
|
||||||
setValue('#tHeatTargetTemp', result.heating.target);
|
setValue('.tHeat .targetTemp', result.heating.target);
|
||||||
|
|
||||||
setCheckboxValue('#tDhwEnabled', result.dhw.enabled);
|
setCheckboxValue('#tDhwEnabled', result.dhw.enabled);
|
||||||
setValue('#tDhwTargetTemp', result.dhw.target);
|
setValue('.tDhw .targetTemp', result.dhw.target);
|
||||||
|
|
||||||
setValue('.tempUnit', temperatureUnit(unitSystem));
|
setValue('.tempUnit', temperatureUnit(unitSystem));
|
||||||
setValue('.pressureUnit', pressureUnit(unitSystem));
|
setValue('.pressureUnit', pressureUnit(unitSystem));
|
||||||
@@ -646,6 +643,14 @@
|
|||||||
setState('.mCascadeControlInput', result.master.cascadeControl.input);
|
setState('.mCascadeControlInput', result.master.cascadeControl.input);
|
||||||
setState('.mCascadeControlOutput', result.master.cascadeControl.output);
|
setState('.mCascadeControlOutput', result.master.cascadeControl.output);
|
||||||
|
|
||||||
|
const tHeat = document.querySelector('.tHeat');
|
||||||
|
tHeat.dataset.min = result.master.heating.minTemp;
|
||||||
|
tHeat.dataset.max = result.master.heating.maxTemp;
|
||||||
|
|
||||||
|
const tDhw = document.querySelector('.tDhw');
|
||||||
|
tDhw.dataset.min = result.master.dhw.minTemp;
|
||||||
|
tDhw.dataset.max = result.master.dhw.maxTemp;
|
||||||
|
|
||||||
setBusy('#dashboard-busy', '#dashboard-container', false);
|
setBusy('#dashboard-busy', '#dashboard-container', false);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -140,7 +140,7 @@
|
|||||||
|
|
||||||
<label>
|
<label>
|
||||||
<span data-i18n>sensors.correction.factor</span>
|
<span data-i18n>sensors.correction.factor</span>
|
||||||
<input type="number" inputmode="decimal" name="factor" min="0.01" max="10" step="0.01" required>
|
<input type="number" inputmode="decimal" name="factor" min="0.01" max="100" step="0.01" required>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -57,6 +57,11 @@
|
|||||||
<input type="checkbox" name="portal[auth]" value="true">
|
<input type="checkbox" name="portal[auth]" value="true">
|
||||||
<span data-i18n>settings.portal.auth</span>
|
<span data-i18n>settings.portal.auth</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="portal[mdns]" value="true">
|
||||||
|
<span data-i18n>settings.portal.mdns</span>
|
||||||
|
</label>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<button type="submit" data-i18n>button.save</button>
|
<button type="submit" data-i18n>button.save</button>
|
||||||
@@ -773,6 +778,7 @@
|
|||||||
setCheckboxValue("[name='portal[auth]']", data.portal.auth);
|
setCheckboxValue("[name='portal[auth]']", data.portal.auth);
|
||||||
setInputValue("[name='portal[login]']", data.portal.login);
|
setInputValue("[name='portal[login]']", data.portal.login);
|
||||||
setInputValue("[name='portal[password]']", data.portal.password);
|
setInputValue("[name='portal[password]']", data.portal.password);
|
||||||
|
setCheckboxValue("[name='portal[mdns]']", data.portal.mdns);
|
||||||
setBusy('#portal-settings-busy', '#portal-settings', false);
|
setBusy('#portal-settings-busy', '#portal-settings', false);
|
||||||
|
|
||||||
// Opentherm
|
// Opentherm
|
||||||
|
|||||||
2
src_data/robots.txt
Normal file
2
src_data/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
User-agent: *
|
||||||
|
Disallow: /
|
||||||
@@ -132,10 +132,14 @@ const setupNetworkScanForm = (formSelector, tableSelector) => {
|
|||||||
for (let i = 0; i < result.length; i++) {
|
for (let i = 0; i < result.length; i++) {
|
||||||
let row = tbody.insertRow(-1);
|
let row = tbody.insertRow(-1);
|
||||||
row.classList.add("network");
|
row.classList.add("network");
|
||||||
row.setAttribute('data-ssid', result[i].hidden ? '' : result[i].ssid);
|
row.dataset.ssid = result[i].hidden ? '' : result[i].ssid;
|
||||||
row.onclick = () => {
|
row.insertCell().textContent = `#${i + 1}`;
|
||||||
const input = document.querySelector('input#sta-ssid');
|
|
||||||
const ssid = this.getAttribute('data-ssid');
|
const nameCell = row.insertCell();
|
||||||
|
nameCell.innerHTML = result[i].hidden ? `<i>${result[i].bssid}</i>` : result[i].ssid;
|
||||||
|
nameCell.onclick = (event) => {
|
||||||
|
const input = document.querySelector("[name='sta[ssid]']");
|
||||||
|
const ssid = event.target.parentNode.dataset.ssid;
|
||||||
if (!input || !ssid) {
|
if (!input || !ssid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -144,9 +148,6 @@ const setupNetworkScanForm = (formSelector, tableSelector) => {
|
|||||||
input.focus();
|
input.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
row.insertCell().textContent = `#${i + 1}`;
|
|
||||||
row.insertCell().innerHTML = result[i].hidden ? `<i>${result[i].bssid}</i>` : result[i].ssid;
|
|
||||||
|
|
||||||
// info cell
|
// info cell
|
||||||
let infoCell = row.insertCell();
|
let infoCell = row.insertCell();
|
||||||
|
|
||||||
@@ -165,7 +166,7 @@ const setupNetworkScanForm = (formSelector, tableSelector) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let signalQualityContainer = document.createElement("span");
|
let signalQualityContainer = document.createElement("span");
|
||||||
signalQualityContainer.setAttribute('data-tooltip', `${result[i].signalQuality}%`);
|
signalQualityContainer.dataset.tooltip = `${result[i].signalQuality}%`;
|
||||||
signalQualityContainer.appendChild(signalQualityIcon);
|
signalQualityContainer.appendChild(signalQualityIcon);
|
||||||
infoCell.appendChild(signalQualityContainer);
|
infoCell.appendChild(signalQualityContainer);
|
||||||
|
|
||||||
@@ -192,7 +193,7 @@ const setupNetworkScanForm = (formSelector, tableSelector) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let authContainer = document.createElement("span");
|
let authContainer = document.createElement("span");
|
||||||
authContainer.setAttribute('data-tooltip', (result[i].auth in authList) ? authList[result[i].auth] : "unknown");
|
authContainer.dataset.tooltip = (result[i].auth in authList) ? authList[result[i].auth] : "unknown";
|
||||||
authContainer.appendChild(authIcon);
|
authContainer.appendChild(authIcon);
|
||||||
infoCell.appendChild(authContainer);
|
infoCell.appendChild(authContainer);
|
||||||
}
|
}
|
||||||
@@ -849,3 +850,7 @@ function dec2hex(i) {
|
|||||||
|
|
||||||
return hex.toUpperCase();
|
return hex.toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function constrain(amt, low, high) {
|
||||||
|
return ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user