mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-01-30 02:29:12 +03:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d37267f57 | ||
|
|
cca6f87500 | ||
|
|
758d76051f | ||
|
|
95f7e66cff | ||
|
|
5ec068409f | ||
|
|
8796b6d340 | ||
|
|
bfbb18655d | ||
|
|
9088651e53 | ||
|
|
3e8f379502 | ||
|
|
265c2c4231 | ||
|
|
f671d79280 | ||
|
|
97c89d1d13 | ||
|
|
e0a26a38fa | ||
|
|
038f06e59f | ||
|
|
f4d2bae04f | ||
|
|
d443e275ea | ||
|
|
30d2057e01 | ||
|
|
d952b9aaae | ||
|
|
3402215e8d | ||
|
|
f01031dc26 | ||
|
|
01d4d116b9 | ||
|
|
bc7f82eef1 | ||
|
|
efdb355033 | ||
|
|
87c9fd010f |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -22,7 +22,7 @@ _Make sure your have performed every step and checked the applicable boxes befor
|
||||
- [ ] Searched the issue in [issues](https://github.com/emsesp/EMS-ESP32/issues)
|
||||
- [ ] Searched the issue in [discussions](https://github.com/emsesp/EMS-ESP32/discussions)
|
||||
- [ ] Searched the issue in the [docs](https://emsesp.org/Troubleshooting/)
|
||||
- [ ] Searched the issue in the [chat](https://discord.gg/3J3GgnzpyT)
|
||||
- [ ] Searched the issue in the [chat](https://discord.gg/GP9DPSgeJq)
|
||||
- [ ] Provide the System information in the area below, taken from `http://<IP>/api/system`
|
||||
|
||||
```json
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -7,5 +7,5 @@ contact_links:
|
||||
url: https://github.com/emsesp/EMS-ESP32/discussions
|
||||
about: EMS-ESP usage Questions, Feature Requests and Projects.
|
||||
- name: EMS-ESP Users Chat
|
||||
url: https://discord.gg/3J3GgnzpyT
|
||||
url: https://discord.gg/GP9DPSgeJq
|
||||
about: Chat for feedback, questions and troubleshooting.
|
||||
|
||||
@@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- board profile `CUSTOM` can only be selected in developer mode
|
||||
- mqtt sends round values without decimals (`28` instead of `28.0`)
|
||||
|
||||
|
||||
## [3.8.0] 31 December 2025
|
||||
|
||||
## Added
|
||||
|
||||
17
README.md
17
README.md
@@ -18,7 +18,7 @@
|
||||
<a href="https://emsesp.org">
|
||||
<img src="https://img.shields.io/badge/Documentation-0077b5?style=for-the-badge&logo=googledocs&logoColor=white" alt="Guides" />
|
||||
</a>
|
||||
<a href="https://discord.gg/3J3GgnzpyT">
|
||||
<a href="https://discord.gg/GP9DPSgeJq">
|
||||
<img src="https://img.shields.io/badge/Discord-7289da?style=for-the-badge&logo=discord&logoColor=white" alt="Discord" />
|
||||
</a>
|
||||
<a href="https://github.com/emsesp/EMS-ESP32/blob/main/CHANGELOG.md">
|
||||
@@ -32,7 +32,7 @@
|
||||
[](https://sonarcloud.io/summary/new_code?id=emsesp_EMS-ESP32)
|
||||
[](https://app.codacy.com/gh/emsesp/EMS-ESP32/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
||||
[](https://github.com/emsesp/EMS-ESP32/releases)
|
||||
[](https://discord.gg/3J3GgnzpyT)
|
||||
[](https://discord.gg/GP9DPSgeJq)
|
||||
|
||||
[](https://github.com/emsesp/EMS-ESP32/stargazers)
|
||||
[](https://github.com/emsesp/EMS-ESP32/network)
|
||||
@@ -40,7 +40,8 @@
|
||||
|
||||
**EMS-ESP** is an open-source firmware for the Espressif ESP32 microcontroller to communicate with **EMS** (Energy Management System) compatible equipment from manufacturers such as Bosch, Buderus, Nefit, Junkers, Worcester, Sieger, elm.leblanc and iVT.
|
||||
|
||||
It requires a small circuit to interface with the EMS bus which can be purchased from <https://bbqkees-electronics.nl> or custom built.
|
||||
It requires a small circuit to interface with the EMS bus which can be purchased from <https://bbqkees-electronics.nl>. These gateways are tested thoroughly and certified to work with EMS-ESP.
|
||||
|
||||
|
||||
## 📦 **Key Features**
|
||||
|
||||
@@ -64,17 +65,17 @@ Head over to the [Installation Guide](https://emsesp.org/Installing) section of
|
||||
|
||||
## 📋 **Documentation**
|
||||
|
||||
Visit [emsesp.org](https://emsesp.org) for more details on how to install and configure EMS-ESP. There is also a collection of Frequently Asked Questions and Troubleshooting tips with example customizations from the community.
|
||||
Visit [emsesp.org](https://emsesp.org) for more details on how to setup and configure EMS-ESP. You'll also find more a collection of example configuarations, Frequently Asked Questions and Troubleshooting tips.
|
||||
|
||||
## 💬 **Getting Support**
|
||||
|
||||
To chat with the community reach out on our [Discord Server](https://discord.gg/3J3GgnzpyT).
|
||||
To chat with the community reach out on our [Discord Server](https://discord.gg/GP9DPSgeJq).
|
||||
|
||||
If you find an issue or have a request, see [how to request support](https://emsesp.org/Support/) on how to submit a bug report or feature request.
|
||||
If you find an issue or have a request, see the [Getting Support](https://emsesp.org/Support/) section of the documentation. Note if you are using a non-BBQKees EMS gateway, you may need to contact the manufacturer for support.
|
||||
|
||||
## 🎥 **Live Demo**
|
||||
|
||||
For a live demo go to [demo.emsesp.org](https://demo.emsesp.org). Pick a language from the sign on page and log in with any username or password. Note not all features are operational as it's based on static data.
|
||||
To see a live demo go to [demo.emsesp.org](https://demo.emsesp.org). Pick a language and use any username and password to log in. Note whast you're seeing is static example data so not all features are operational.
|
||||
|
||||
## 💖 **Contributors**
|
||||
|
||||
@@ -84,7 +85,7 @@ If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it
|
||||
|
||||
## 📦 **Building**
|
||||
|
||||
See the [Building Guide](https://emsesp.org/Building) section of the documentation for instructions on how to build EMS-ESP.
|
||||
See the [Building the firmware](https://emsesp.org/Building) guide in the documentation for instructions on how to build EMS-ESP from this source code.
|
||||
|
||||
## 📢 **Libraries used**
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
}
|
||||
],
|
||||
"dictionaries": ["project-words"],
|
||||
"caseSensitive": false,
|
||||
"ignorePaths": [
|
||||
"node_modules",
|
||||
"compile_commands.json",
|
||||
@@ -36,6 +37,7 @@
|
||||
"pnpm-*.yaml",
|
||||
"vite.config.ts",
|
||||
"lib/esp32-psram/**",
|
||||
"test/test_api/test_api.h"
|
||||
"test/test_api/test_api.h",
|
||||
"lib_standalone/**"
|
||||
]
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
"@mui/material": "^7.3.7",
|
||||
"@preact/compat": "^18.3.1",
|
||||
"@table-library/react-table-library": "4.1.15",
|
||||
"alova": "3.4.1",
|
||||
"alova": "3.5.0",
|
||||
"async-validator": "^4.2.5",
|
||||
"etag": "^1.8.1",
|
||||
"formidable": "^3.5.4",
|
||||
@@ -38,34 +38,34 @@
|
||||
"magic-string": "^0.30.21",
|
||||
"mime-types": "^3.0.2",
|
||||
"preact": "^10.28.2",
|
||||
"react": "^19.2.3",
|
||||
"react-dom": "^19.2.3",
|
||||
"react": "^19.2.4",
|
||||
"react-dom": "^19.2.4",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router": "^7.12.0",
|
||||
"react-router": "^7.13.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"typesafe-i18n": "^5.26.2",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.28.5",
|
||||
"@babel/core": "^7.28.6",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@preact/compat": "^18.3.1",
|
||||
"@preact/preset-vite": "^2.10.2",
|
||||
"@preact/preset-vite": "^2.10.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"@types/node": "^25.0.6",
|
||||
"@types/react": "^19.2.8",
|
||||
"@types/node": "^25.1.0",
|
||||
"@types/react": "^19.2.10",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"axe-core": "^4.11.1",
|
||||
"concurrently": "^9.2.1",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"prettier": "^3.7.4",
|
||||
"prettier": "^3.8.1",
|
||||
"rollup-plugin-visualizer": "^6.0.5",
|
||||
"terser": "^5.44.1",
|
||||
"typescript-eslint": "^8.52.0",
|
||||
"terser": "^5.46.0",
|
||||
"typescript-eslint": "^8.54.0",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-imagemin": "^0.6.1",
|
||||
"vite-tsconfig-paths": "^6.0.4"
|
||||
"vite-tsconfig-paths": "^6.0.5"
|
||||
},
|
||||
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48"
|
||||
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264"
|
||||
}
|
||||
|
||||
983
interface/pnpm-lock.yaml
generated
983
interface/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -120,7 +120,7 @@ const HelpComponent = () => {
|
||||
label: () => LL.HELP_INFORMATION_1()
|
||||
},
|
||||
{
|
||||
href: 'https://discord.gg/3J3GgnzpyT',
|
||||
href: 'https://discord.gg/GP9DPSgeJq',
|
||||
icon: <CommentIcon />,
|
||||
label: () => LL.HELP_INFORMATION_2()
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ const nl: Translation = {
|
||||
REFRESH: 'Ververs',
|
||||
EXPORT: 'Export',
|
||||
FAVORITES: "Favorieten",
|
||||
DEVICE_DETAILS: 'Device Gegevens',
|
||||
DEVICE_DETAILS: 'Apparaat Gegevens',
|
||||
ID_OF: '{0} ID',
|
||||
DEVICE: 'Apparaat',
|
||||
PRODUCT: 'Product',
|
||||
@@ -65,7 +65,7 @@ const nl: Translation = {
|
||||
TEMP_SENSOR: 'Temperatuur sensor',
|
||||
TEMP_SENSORS: 'Temperatuur Sensoren',
|
||||
WRITE_CMD_SENT: 'Schrijf commando gestuurd',
|
||||
EMS_BUS_WARNING: 'EMS bus niet gevonden. Als deze waarschuwing blijft staan na een paar seconden dan loop de instellingen na en in het bijzonder het apparaat type profiel na.',
|
||||
EMS_BUS_WARNING: 'EMS bus niet gevonden. Als deze waarschuwing blijft staan na een paar seconden loop dan de instellingen na en in het bijzonder het apparaat type profiel.',
|
||||
EMS_BUS_SCANNING: 'Scannen naar EMS apparaten...',
|
||||
CONNECTED: 'Verbonden',
|
||||
TX_ISSUES: 'Tx bus probleem. Probeer een andere Tx verzendmodus',
|
||||
@@ -75,7 +75,7 @@ const nl: Translation = {
|
||||
EMS_DEVICE: 'EMS Apparaat',
|
||||
SUCCESS: 'SUCCESS',
|
||||
FAIL: 'MISLUKT',
|
||||
QUALITY: 'QUALITEIT',
|
||||
QUALITY: 'KWALITEIT',
|
||||
SCAN: 'Scan',
|
||||
STATUS_NAMES: [
|
||||
'EMS Telegrammen ontvangen (Rx)',
|
||||
@@ -120,7 +120,7 @@ const nl: Translation = {
|
||||
ENABLE_SHOWER_TIMER: 'Activeer Douche Timer (tijdmeting)',
|
||||
ENABLE_SHOWER_ALERT: 'Activeer Douchemelding',
|
||||
TRIGGER_TIME: 'Trigger tijd',
|
||||
COLD_SHOT_DURATION: 'Tijd Shot koud water',
|
||||
COLD_SHOT_DURATION: 'Lengte koud water puls',
|
||||
FORMATTING_OPTIONS: 'Formatteringsopties',
|
||||
BOOLEAN_FORMAT_DASHBOARD: 'Boolean formaat web',
|
||||
BOOLEAN_FORMAT_API: 'Boolean formaat API/MQTT',
|
||||
@@ -143,7 +143,7 @@ const nl: Translation = {
|
||||
CUSTOMIZATIONS_FULL: 'Te veel entiteiten geselecteerd. Sla op in delen aub',
|
||||
CUSTOMIZATIONS_SAVED: 'Custom aanpassingen opgeslagen',
|
||||
CUSTOMIZATIONS_HELP_1: 'Selecteer een apparaat en pas de entiteiten aan door middel van de opties',
|
||||
CUSTOMIZATIONS_HELP_2: 'Markeer as favoriet',
|
||||
CUSTOMIZATIONS_HELP_2: 'Markeer als favoriet',
|
||||
CUSTOMIZATIONS_HELP_3: 'Zet schrijfacties uit',
|
||||
CUSTOMIZATIONS_HELP_4: 'Uitsluiten van MQTT en API',
|
||||
CUSTOMIZATIONS_HELP_5: 'verbergen voor apparaten',
|
||||
@@ -191,7 +191,7 @@ const nl: Translation = {
|
||||
UPLOAD_DROP_TEXT: 'Sleep en firmware .bin bestand hierheen of klik hier',
|
||||
ERROR: 'Onverwachte fout, probeer opnieuw',
|
||||
TIME_SET: 'Tijd ingesteld',
|
||||
MANAGE_USERS: 'Beheer Gebruikers',
|
||||
MANAGE_USERS: 'Gebruikersbeheer',
|
||||
IS_ADMIN: 'is Admin',
|
||||
USER_WARNING: 'U dient tenminste 1 admin gebruiker te configureren',
|
||||
ADD: 'Toevoegen',
|
||||
@@ -200,7 +200,7 @@ const nl: Translation = {
|
||||
GENERATING_TOKEN: 'Token aan het genereren',
|
||||
USER: 'Gebruiker',
|
||||
MODIFY: 'Aanpassen',
|
||||
SU_TEXT: 'Het su (super user) wachtwoord wordt gebruikt om authorisatie tokens te signeren en ook om admin privileges te activeren in de console.',
|
||||
SU_TEXT: 'Het su (super user) wachtwoord wordt gebruikt om authorisatie tokens te ondertekenen en ook om admin privileges te activeren in de console.',
|
||||
NOT_ENABLED: 'Niet geactiveerd',
|
||||
ERRORS_OF: '{0} Foutmeldingen',
|
||||
DISCONNECT_REASON: 'Verbinding verbroken vanwege',
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <esp32-psram.h>
|
||||
#include <uuid/common.h>
|
||||
#include <uuid/log.h>
|
||||
|
||||
@@ -1647,13 +1648,13 @@ class Shell : public std::enable_shared_from_this<Shell>, public uuid::log::Hand
|
||||
|
||||
Stream & stream_; /*!< Stream used for the input/output of this shell. @since 3.0.0 */
|
||||
std::shared_ptr<Commands> commands_; /*!< Commands available for execution in this shell. @since 0.1.0 */
|
||||
std::deque<unsigned int> context_; /*!< Context stack for this shell. Affects which commands are available. Should never be empty. @since 0.1.0 */
|
||||
std::deque<unsigned int, AllocatorPSRAM<unsigned int>> context_; /*!< Context stack for this shell. Affects which commands are available. Should never be empty. @since 0.1.0 */
|
||||
unsigned int flags_ = 0; /*!< Current flags for this shell. Affects which commands are available. @since 0.1.0 */
|
||||
#if UUID_CONSOLE_THREAD_SAFE
|
||||
mutable std::mutex mutex_; /*!< Mutex for queued log messages. @since 1.0.0 */
|
||||
#endif
|
||||
unsigned long log_message_id_ = 0; /*!< The next identifier to use for queued log messages. @since 0.1.0 */
|
||||
std::list<QueuedLogMessage> log_messages_; /*!< Queued log messages, in the order they were received. @since 0.1.0 */
|
||||
std::list<QueuedLogMessage, AllocatorPSRAM<QueuedLogMessage>> log_messages_; /*!< Queued log messages, in the order they were received. @since 0.1.0 */
|
||||
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum command line length in bytes. @since 0.6.0 */
|
||||
std::string line_buffer_; /*!< Command line buffer. Limited to maximum_command_line_length() bytes. @since 0.1.0 */
|
||||
size_t maximum_command_line_length_ = MAX_COMMAND_LINE_LENGTH; /*!< Maximum command line length in bytes. @since 0.6.0 */
|
||||
@@ -1786,7 +1787,7 @@ class CommandLine {
|
||||
* @return A reference to the parameters.
|
||||
* @since 0.6.0
|
||||
*/
|
||||
inline std::vector<std::string> & operator*() {
|
||||
inline std::vector<std::string, AllocatorPSRAM<std::string>> & operator*() {
|
||||
return parameters_;
|
||||
}
|
||||
/**
|
||||
@@ -1795,7 +1796,7 @@ class CommandLine {
|
||||
* @return A reference to the parameters.
|
||||
* @since 0.6.0
|
||||
*/
|
||||
inline const std::vector<std::string> & operator*() const {
|
||||
inline const std::vector<std::string, AllocatorPSRAM<std::string>> & operator*() const {
|
||||
return parameters_;
|
||||
}
|
||||
/**
|
||||
@@ -1804,7 +1805,7 @@ class CommandLine {
|
||||
* @return A pointer to the parameters.
|
||||
* @since 0.4.0
|
||||
*/
|
||||
inline std::vector<std::string> * operator->() {
|
||||
inline std::vector<std::string, AllocatorPSRAM<std::string>> * operator->() {
|
||||
return ¶meters_;
|
||||
}
|
||||
/**
|
||||
@@ -1813,7 +1814,7 @@ class CommandLine {
|
||||
* @return A pointer to the parameters.
|
||||
* @since 0.4.0
|
||||
*/
|
||||
inline const std::vector<std::string> * operator->() const {
|
||||
inline const std::vector<std::string, AllocatorPSRAM<std::string>> * operator->() const {
|
||||
return ¶meters_;
|
||||
}
|
||||
|
||||
@@ -1843,7 +1844,7 @@ class CommandLine {
|
||||
bool trailing_space = false; /*!< Command line has a trailing space. @since 0.4.0 */
|
||||
|
||||
private:
|
||||
std::vector<std::string> parameters_; /*!< Separate command line parameters. @since 0.4.0 */
|
||||
std::vector<std::string, AllocatorPSRAM<std::string>> parameters_; /*!< Separate command line parameters. @since 0.4.0 */
|
||||
size_t escape_parameters_ = std::numeric_limits<size_t>::max(); /*!< Number of initial arguments to escape in output. @since 0.5.0 */
|
||||
};
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ void Logger::vlog(Level level, const char * format, va_list ap) const {
|
||||
}
|
||||
|
||||
void Logger::vlog(Level level, Facility facility, const char * format, va_list ap) const {
|
||||
std::vector<char> text(MAX_LOG_LENGTH + 1);
|
||||
std::vector<char, AllocatorPSRAM<char>> text(MAX_LOG_LENGTH + 1);
|
||||
|
||||
if (vsnprintf(text.data(), text.size(), format, ap) <= 0) {
|
||||
return;
|
||||
@@ -241,7 +241,7 @@ void Logger::vlog(Level level, Facility facility, const char * format, va_list a
|
||||
dispatch(level, facility, text);
|
||||
}
|
||||
|
||||
void Logger::dispatch(Level level, Facility facility, std::vector<char> & text) const {
|
||||
void Logger::dispatch(Level level, Facility facility, std::vector<char, AllocatorPSRAM<char>> & text) const {
|
||||
std::shared_ptr<Message> message = std::make_shared<Message>(get_uptime_ms(), level, facility, name_, text.data());
|
||||
text.resize(0);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <esp32-psram.h>
|
||||
#include <uuid/common.h>
|
||||
|
||||
#ifndef UUID_COMMON_THREAD_SAFE
|
||||
@@ -645,7 +646,7 @@ class Logger {
|
||||
* @param[in] text Log message text.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
void dispatch(Level level, Facility facility, std::vector<char> & text) const;
|
||||
void dispatch(Level level, Facility facility, std::vector<char, AllocatorPSRAM<char>> & text) const;
|
||||
|
||||
static std::atomic<Level> global_level_; /*!< Minimum global log level across all handlers. @since 3.0.0 */
|
||||
#if UUID_LOG_THREAD_SAFE
|
||||
@@ -723,7 +724,7 @@ class PrintHandler : public uuid::log::Handler {
|
||||
mutable std::mutex mutex_; /*!< Mutex for configuration, state and queued log messages. @since 2.3.0 */
|
||||
#endif
|
||||
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum number of log messages to buffer before they are output. @since 2.2.0 */
|
||||
std::list<std::shared_ptr<Message>> log_messages_; /*!< Queued log messages, in the order they were received. @since 2.2.0 */
|
||||
std::list<std::shared_ptr<Message>, AllocatorPSRAM<std::shared_ptr<Message>>> log_messages_; /*!< Queued log messages, in the order they were received. @since 2.2.0 */
|
||||
};
|
||||
|
||||
} // namespace log
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <esp32-psram.h>
|
||||
#include <uuid/log.h>
|
||||
|
||||
#ifndef UUID_LOG_THREAD_SAFE
|
||||
@@ -321,7 +322,7 @@ class SyslogService : public uuid::log::Handler {
|
||||
#endif
|
||||
size_t maximum_log_messages_ = MAX_LOG_MESSAGES; /*!< Maximum number of log messages to buffer before they are output. @since 1.0.0 */
|
||||
unsigned long log_message_id_ = 0; /*!< The next identifier to use for queued log messages. @since 1.0.0 */
|
||||
std::list<QueuedLogMessage> log_messages_; /*!< Queued log messages, in the order they were received. @since 1.0.0 */
|
||||
std::list<QueuedLogMessage, AllocatorPSRAM<QueuedLogMessage>> log_messages_; /*!< Queued log messages, in the order they were received. @since 1.0.0 */
|
||||
uint64_t mark_interval_ = 0; /*!< Mark interval in milliseconds. @since 2.0.0 */
|
||||
uint64_t last_message_ = 0; /*!< Last message/mark time. @since 2.0.0 */
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ size_t TelnetStream::write(uint8_t data) {
|
||||
}
|
||||
|
||||
size_t TelnetStream::write(const uint8_t * buffer, size_t size) {
|
||||
std::vector<unsigned char> data;
|
||||
std::vector<unsigned char, AllocatorPSRAM<unsigned char>> data;
|
||||
data.reserve(size);
|
||||
|
||||
while (size-- > 0) {
|
||||
@@ -310,7 +310,7 @@ size_t TelnetStream::raw_write(unsigned char data) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t TelnetStream::raw_write(const std::vector<unsigned char> & data) {
|
||||
size_t TelnetStream::raw_write(const std::vector<unsigned char, AllocatorPSRAM<unsigned char>> & data) {
|
||||
return raw_write(reinterpret_cast<const unsigned char *>(data.data()), data.size());
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <esp32-psram.h>
|
||||
#include <uuid/console.h>
|
||||
|
||||
namespace uuid {
|
||||
@@ -203,7 +204,7 @@ class TelnetStream : public ::Stream {
|
||||
* @return The number of bytes that were output.
|
||||
* @since 0.1.0
|
||||
*/
|
||||
size_t raw_write(const std::vector<unsigned char> & data);
|
||||
size_t raw_write(const std::vector<unsigned char, AllocatorPSRAM<unsigned char>> & data);
|
||||
/**
|
||||
* Write an array of bytes directly to the output stream.
|
||||
*
|
||||
@@ -222,7 +223,7 @@ class TelnetStream : public ::Stream {
|
||||
unsigned char previous_in_ = 0; /*!< Previous character that was received. Used to detect CR NUL. @since 0.1.0 */
|
||||
unsigned char previous_out_ = 0; /*!< Previous character that was sent. Used to insert NUL after CR without LF. @since 0.1.0 */
|
||||
int peek_ = -1; /*!< Previously read data cached by peek(). @since 0.1.0 */
|
||||
std::vector<char> output_buffer_; /*!< Buffer data to be output until a read function is called. @since 0.1.0 */
|
||||
std::vector<char, AllocatorPSRAM<char>> output_buffer_; /*!< Buffer data to be output until a read function is called. @since 0.1.0 */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -425,7 +426,7 @@ class TelnetService {
|
||||
|
||||
WiFiServer server_; /*!< TCP server. @since 0.1.0 */
|
||||
size_t maximum_connections_ = MAX_CONNECTIONS; /*!< Maximum number of concurrent open connections. @since 0.1.0 */
|
||||
std::list<Connection> connections_; /*!< Open connections. @since 0.1.0 */
|
||||
std::list<Connection, AllocatorPSRAM<Connection>> connections_; /*!< Open connections. @since 0.1.0 */
|
||||
shell_factory_function shell_factory_; /*!< Function to create a shell. @since 0.1.0 */
|
||||
unsigned long initial_idle_timeout_ = DEFAULT_IDLE_TIMEOUT; /*!< Initial idle timeout (in seconds). @since 0.1.0 */
|
||||
unsigned long write_timeout_ = DEFAULT_WRITE_TIMEOUT; /*!< Write timeout (in milliseconds). @since 0.1.0 */
|
||||
|
||||
@@ -19,12 +19,164 @@ class AsyncClient {
|
||||
class AsyncServer {
|
||||
public:
|
||||
AsyncServer(uint16_t port)
|
||||
: _port(port){};
|
||||
~AsyncServer(){};
|
||||
: _port(port) {};
|
||||
~AsyncServer() {};
|
||||
|
||||
protected:
|
||||
uint16_t _port;
|
||||
};
|
||||
|
||||
namespace asyncsrv {
|
||||
|
||||
static constexpr const char empty[] = "";
|
||||
|
||||
static constexpr const char T__opaque[] = "\", opaque=\"";
|
||||
static constexpr const char T_100_CONTINUE[] = "100-continue";
|
||||
static constexpr const char T_13[] = "13";
|
||||
static constexpr const char T_ACCEPT[] = "Accept";
|
||||
static constexpr const char T_Accept_Ranges[] = "Accept-Ranges";
|
||||
static constexpr const char T_attachment[] = "attachment; filename=\"";
|
||||
static constexpr const char T_AUTH[] = "Authorization";
|
||||
static constexpr const char T_auth_nonce[] = "\", qop=\"auth\", nonce=\"";
|
||||
static constexpr const char T_BASIC[] = "Basic";
|
||||
static constexpr const char T_BASIC_REALM[] = "Basic realm=\"";
|
||||
static constexpr const char T_BEARER[] = "Bearer";
|
||||
static constexpr const char T_BODY[] = "body";
|
||||
static constexpr const char T_Cache_Control[] = "Cache-Control";
|
||||
static constexpr const char T_chunked[] = "chunked";
|
||||
static constexpr const char T_close[] = "close";
|
||||
static constexpr const char T_cnonce[] = "cnonce";
|
||||
static constexpr const char T_Connection[] = "Connection";
|
||||
static constexpr const char T_Content_Disposition[] = "Content-Disposition";
|
||||
static constexpr const char T_Content_Encoding[] = "Content-Encoding";
|
||||
static constexpr const char T_Content_Length[] = "Content-Length";
|
||||
static constexpr const char T_Content_Type[] = "Content-Type";
|
||||
static constexpr const char T_Content_Location[] = "Content-Location";
|
||||
static constexpr const char T_Cookie[] = "Cookie";
|
||||
static constexpr const char T_CORS_ACAC[] = "Access-Control-Allow-Credentials";
|
||||
static constexpr const char T_CORS_ACAH[] = "Access-Control-Allow-Headers";
|
||||
static constexpr const char T_CORS_ACAM[] = "Access-Control-Allow-Methods";
|
||||
static constexpr const char T_CORS_ACAO[] = "Access-Control-Allow-Origin";
|
||||
static constexpr const char T_CORS_ACMA[] = "Access-Control-Max-Age";
|
||||
static constexpr const char T_CORS_O[] = "Origin";
|
||||
static constexpr const char T_data_[] = "data: ";
|
||||
static constexpr const char T_Date[] = "Date";
|
||||
static constexpr const char T_DIGEST[] = "Digest";
|
||||
static constexpr const char T_DIGEST_[] = "Digest ";
|
||||
static constexpr const char T_ETag[] = "ETag";
|
||||
static constexpr const char T_event_[] = "event: ";
|
||||
static constexpr const char T_EXPECT[] = "Expect";
|
||||
static constexpr const char T_FALSE[] = "false";
|
||||
static constexpr const char T_filename[] = "filename";
|
||||
static constexpr const char T_gzip[] = "gzip";
|
||||
static constexpr const char T_Host[] = "host";
|
||||
static constexpr const char T_HTTP_1_0[] = "HTTP/1.0";
|
||||
static constexpr const char T_HTTP_100_CONT[] = "HTTP/1.1 100 Continue\r\n\r\n";
|
||||
static constexpr const char T_id__[] = "id: ";
|
||||
static constexpr const char T_IMS[] = "If-Modified-Since";
|
||||
static constexpr const char T_INM[] = "If-None-Match";
|
||||
static constexpr const char T_inline[] = "inline";
|
||||
static constexpr const char T_keep_alive[] = "keep-alive";
|
||||
static constexpr const char T_Last_Event_ID[] = "Last-Event-ID";
|
||||
static constexpr const char T_Last_Modified[] = "Last-Modified";
|
||||
static constexpr const char T_LOCATION[] = "Location";
|
||||
static constexpr const char T_LOGIN_REQ[] = "Login Required";
|
||||
static constexpr const char T_MULTIPART_[] = "multipart/";
|
||||
static constexpr const char T_name[] = "name";
|
||||
static constexpr const char T_nc[] = "nc";
|
||||
static constexpr const char T_no_cache[] = "no-cache";
|
||||
static constexpr const char T_nonce[] = "nonce";
|
||||
static constexpr const char T_none[] = "none";
|
||||
static constexpr const char T_opaque[] = "opaque";
|
||||
static constexpr const char T_qop[] = "qop";
|
||||
static constexpr const char T_realm[] = "realm";
|
||||
static constexpr const char T_realm__[] = "realm=\"";
|
||||
static constexpr const char T_response[] = "response";
|
||||
static constexpr const char T_retry_[] = "retry: ";
|
||||
static constexpr const char T_retry_after[] = "Retry-After";
|
||||
static constexpr const char T_nn[] = "\n\n";
|
||||
static constexpr const char T_rn[] = "\r\n";
|
||||
static constexpr const char T_rnrn[] = "\r\n\r\n";
|
||||
static constexpr const char T_Server[] = "Server";
|
||||
static constexpr const char T_Transfer_Encoding[] = "Transfer-Encoding";
|
||||
static constexpr const char T_TRUE[] = "true";
|
||||
static constexpr const char T_UPGRADE[] = "Upgrade";
|
||||
static constexpr const char T_uri[] = "uri";
|
||||
static constexpr const char T_username[] = "username";
|
||||
static constexpr const char T_WS[] = "websocket";
|
||||
static constexpr const char T_WWW_AUTH[] = "WWW-Authenticate";
|
||||
|
||||
// HTTP Methods
|
||||
static constexpr const char T_ANY[] = "ANY";
|
||||
static constexpr const char T_GET[] = "GET";
|
||||
static constexpr const char T_POST[] = "POST";
|
||||
static constexpr const char T_PUT[] = "PUT";
|
||||
static constexpr const char T_DELETE[] = "DELETE";
|
||||
static constexpr const char T_PATCH[] = "PATCH";
|
||||
static constexpr const char T_HEAD[] = "HEAD";
|
||||
static constexpr const char T_OPTIONS[] = "OPTIONS";
|
||||
static constexpr const char T_UNKNOWN[] = "UNKNOWN";
|
||||
|
||||
// Req content types
|
||||
static constexpr const char T_RCT_NOT_USED[] = "RCT_NOT_USED";
|
||||
static constexpr const char T_RCT_DEFAULT[] = "RCT_DEFAULT";
|
||||
static constexpr const char T_RCT_HTTP[] = "RCT_HTTP";
|
||||
static constexpr const char T_RCT_WS[] = "RCT_WS";
|
||||
static constexpr const char T_RCT_EVENT[] = "RCT_EVENT";
|
||||
static constexpr const char T_ERROR[] = "ERROR";
|
||||
|
||||
// extensions & MIME-Types
|
||||
static constexpr const char T__avif[] = ".avif"; // AVIF: Highly compressed images. Compatible with all modern browsers.
|
||||
static constexpr const char T__csv[] = ".csv"; // CSV: Data logging and configuration
|
||||
static constexpr const char T__css[] = ".css"; // CSS: Styling for web interfaces
|
||||
static constexpr const char T__gif[] = ".gif"; // GIF: Simple animations. Legacy support
|
||||
static constexpr const char T__gz[] = ".gz"; // GZ: compressed files
|
||||
static constexpr const char T__htm[] = ".htm"; // HTM: Web interface files
|
||||
static constexpr const char T__html[] = ".html"; // HTML: Web interface files
|
||||
static constexpr const char T__ico[] = ".ico"; // ICO: Favicons, system icons. Legacy support
|
||||
static constexpr const char T__jpg[] = ".jpg"; // JPEG/JPG: Photos. Legacy support
|
||||
static constexpr const char T__js[] = ".js"; // JavaScript: Interactive functionality
|
||||
static constexpr const char T__json[] = ".json"; // JSON: Data exchange format
|
||||
static constexpr const char T__mp4[] = ".mp4"; // MP4: Proprietary format. Worse compression than WEBM.
|
||||
static constexpr const char T__mjs[] = ".mjs"; // MJS: JavaScript module format
|
||||
static constexpr const char T__opus[] = ".opus"; // OPUS: High compression audio format
|
||||
static constexpr const char T__pdf[] = ".pdf"; // PDF: Universal document format
|
||||
static constexpr const char T__png[] = ".png"; // PNG: Icons, logos, transparency. Legacy support
|
||||
static constexpr const char T__svg[] = ".svg"; // SVG: Vector graphics, icons (scalable, tiny file sizes)
|
||||
static constexpr const char T__ttf[] = ".ttf"; // TTF: Font file. Legacy support
|
||||
static constexpr const char T__txt[] = ".txt"; // TXT: Plain text files
|
||||
static constexpr const char T__webm[] = ".webm"; // WebM: Video. Open source, optimized for web. Compatible with all modern browsers.
|
||||
static constexpr const char T__webp[] = ".webp"; // WebP: Highly compressed images. Compatible with all modern browsers.
|
||||
static constexpr const char T__woff[] = ".woff"; // WOFF: Font file. Legacy support
|
||||
static constexpr const char T__woff2[] = ".woff2"; // WOFF2: Better compression. Compatible with all modern browsers.
|
||||
static constexpr const char T__xml[] = ".xml"; // XML: Configuration and data files
|
||||
static constexpr const char T_application_javascript[] = "application/javascript"; // Obsolete type for JavaScript
|
||||
static constexpr const char T_application_json[] = "application/json";
|
||||
static constexpr const char T_application_msgpack[] = "application/msgpack";
|
||||
static constexpr const char T_application_octet_stream[] = "application/octet-stream";
|
||||
static constexpr const char T_application_pdf[] = "application/pdf";
|
||||
static constexpr const char T_app_xform_urlencoded[] = "application/x-www-form-urlencoded";
|
||||
static constexpr const char T_audio_opus[] = "audio/opus";
|
||||
static constexpr const char T_font_ttf[] = "font/ttf";
|
||||
static constexpr const char T_font_woff[] = "font/woff";
|
||||
static constexpr const char T_font_woff2[] = "font/woff2";
|
||||
static constexpr const char T_image_avif[] = "image/avif";
|
||||
static constexpr const char T_image_gif[] = "image/gif";
|
||||
static constexpr const char T_image_jpeg[] = "image/jpeg";
|
||||
static constexpr const char T_image_png[] = "image/png";
|
||||
static constexpr const char T_image_svg_xml[] = "image/svg+xml";
|
||||
static constexpr const char T_image_webp[] = "image/webp";
|
||||
static constexpr const char T_image_x_icon[] = "image/x-icon";
|
||||
static constexpr const char T_text_css[] = "text/css";
|
||||
static constexpr const char T_text_csv[] = "text/csv";
|
||||
static constexpr const char T_text_event_stream[] = "text/event-stream";
|
||||
static constexpr const char T_text_html[] = "text/html";
|
||||
static constexpr const char T_text_javascript[] = "text/javascript";
|
||||
static constexpr const char T_text_plain[] = "text/plain";
|
||||
static constexpr const char T_text_xml[] = "text/xml";
|
||||
static constexpr const char T_video_mp4[] = "video/mp4";
|
||||
static constexpr const char T_video_webm[] = "video/webm";
|
||||
} // namespace asyncsrv
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"@trivago/prettier-plugin-sort-imports": "^6.0.2",
|
||||
"formidable": "^3.5.4",
|
||||
"itty-router": "^5.0.22",
|
||||
"prettier": "^3.7.4"
|
||||
"prettier": "^3.8.1"
|
||||
},
|
||||
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48"
|
||||
"packageManager": "pnpm@10.28.2+sha512.41872f037ad22f7348e3b1debbaf7e867cfd448f2726d9cf74c08f19507c31d2c8e7a11525b983febc2df640b5438dee6023ebb1f84ed43cc2d654d2bc326264"
|
||||
}
|
||||
|
||||
90
mock-api/pnpm-lock.yaml
generated
90
mock-api/pnpm-lock.yaml
generated
@@ -13,7 +13,7 @@ importers:
|
||||
version: 3.1.3
|
||||
'@trivago/prettier-plugin-sort-imports':
|
||||
specifier: ^6.0.2
|
||||
version: 6.0.2(prettier@3.7.4)
|
||||
version: 6.0.2(prettier@3.8.1)
|
||||
formidable:
|
||||
specifier: ^3.5.4
|
||||
version: 3.5.4
|
||||
@@ -21,17 +21,17 @@ importers:
|
||||
specifier: ^5.0.22
|
||||
version: 5.0.22
|
||||
prettier:
|
||||
specifier: ^3.7.4
|
||||
version: 3.7.4
|
||||
specifier: ^3.8.1
|
||||
version: 3.8.1
|
||||
|
||||
packages:
|
||||
|
||||
'@babel/code-frame@7.27.1':
|
||||
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
|
||||
'@babel/code-frame@7.28.6':
|
||||
resolution: {integrity: sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/generator@7.28.5':
|
||||
resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==}
|
||||
'@babel/generator@7.28.6':
|
||||
resolution: {integrity: sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/helper-globals@7.28.0':
|
||||
@@ -46,21 +46,21 @@ packages:
|
||||
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/parser@7.28.5':
|
||||
resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==}
|
||||
'@babel/parser@7.28.6':
|
||||
resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
|
||||
'@babel/template@7.28.6':
|
||||
resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/traverse@7.28.5':
|
||||
resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==}
|
||||
'@babel/traverse@7.28.6':
|
||||
resolution: {integrity: sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@babel/types@7.28.5':
|
||||
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
|
||||
'@babel/types@7.28.6':
|
||||
resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.13':
|
||||
@@ -145,8 +145,8 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
hasBin: true
|
||||
|
||||
lodash-es@4.17.22:
|
||||
resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==}
|
||||
lodash-es@4.17.23:
|
||||
resolution: {integrity: sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
@@ -167,8 +167,8 @@ packages:
|
||||
picocolors@1.1.1:
|
||||
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
|
||||
|
||||
prettier@3.7.4:
|
||||
resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==}
|
||||
prettier@3.8.1:
|
||||
resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
@@ -177,16 +177,16 @@ packages:
|
||||
|
||||
snapshots:
|
||||
|
||||
'@babel/code-frame@7.27.1':
|
||||
'@babel/code-frame@7.28.6':
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
js-tokens: 4.0.0
|
||||
picocolors: 1.1.1
|
||||
|
||||
'@babel/generator@7.28.5':
|
||||
'@babel/generator@7.28.6':
|
||||
dependencies:
|
||||
'@babel/parser': 7.28.5
|
||||
'@babel/types': 7.28.5
|
||||
'@babel/parser': 7.28.6
|
||||
'@babel/types': 7.28.6
|
||||
'@jridgewell/gen-mapping': 0.3.13
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
jsesc: 3.1.0
|
||||
@@ -197,29 +197,29 @@ snapshots:
|
||||
|
||||
'@babel/helper-validator-identifier@7.28.5': {}
|
||||
|
||||
'@babel/parser@7.28.5':
|
||||
'@babel/parser@7.28.6':
|
||||
dependencies:
|
||||
'@babel/types': 7.28.5
|
||||
'@babel/types': 7.28.6
|
||||
|
||||
'@babel/template@7.27.2':
|
||||
'@babel/template@7.28.6':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
'@babel/parser': 7.28.5
|
||||
'@babel/types': 7.28.5
|
||||
'@babel/code-frame': 7.28.6
|
||||
'@babel/parser': 7.28.6
|
||||
'@babel/types': 7.28.6
|
||||
|
||||
'@babel/traverse@7.28.5':
|
||||
'@babel/traverse@7.28.6':
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.27.1
|
||||
'@babel/generator': 7.28.5
|
||||
'@babel/code-frame': 7.28.6
|
||||
'@babel/generator': 7.28.6
|
||||
'@babel/helper-globals': 7.28.0
|
||||
'@babel/parser': 7.28.5
|
||||
'@babel/template': 7.27.2
|
||||
'@babel/types': 7.28.5
|
||||
'@babel/parser': 7.28.6
|
||||
'@babel/template': 7.28.6
|
||||
'@babel/types': 7.28.6
|
||||
debug: 4.4.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@babel/types@7.28.5':
|
||||
'@babel/types@7.28.6':
|
||||
dependencies:
|
||||
'@babel/helper-string-parser': 7.27.1
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
@@ -246,17 +246,17 @@ snapshots:
|
||||
dependencies:
|
||||
'@noble/hashes': 1.8.0
|
||||
|
||||
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.7.4)':
|
||||
'@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.8.1)':
|
||||
dependencies:
|
||||
'@babel/generator': 7.28.5
|
||||
'@babel/parser': 7.28.5
|
||||
'@babel/traverse': 7.28.5
|
||||
'@babel/types': 7.28.5
|
||||
'@babel/generator': 7.28.6
|
||||
'@babel/parser': 7.28.6
|
||||
'@babel/traverse': 7.28.6
|
||||
'@babel/types': 7.28.6
|
||||
javascript-natural-sort: 0.7.1
|
||||
lodash-es: 4.17.22
|
||||
lodash-es: 4.17.23
|
||||
minimatch: 9.0.5
|
||||
parse-imports-exports: 0.2.4
|
||||
prettier: 3.7.4
|
||||
prettier: 3.8.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
@@ -291,7 +291,7 @@ snapshots:
|
||||
|
||||
jsesc@3.1.0: {}
|
||||
|
||||
lodash-es@4.17.22: {}
|
||||
lodash-es@4.17.23: {}
|
||||
|
||||
minimatch@9.0.5:
|
||||
dependencies:
|
||||
@@ -311,6 +311,6 @@ snapshots:
|
||||
|
||||
picocolors@1.1.1: {}
|
||||
|
||||
prettier@3.7.4: {}
|
||||
prettier@3.8.1: {}
|
||||
|
||||
wrappy@1.0.2: {}
|
||||
|
||||
@@ -106,7 +106,7 @@ board_build.filesystem = littlefs
|
||||
lib_deps =
|
||||
bblanchon/ArduinoJson @ 7.4.2
|
||||
ESP32Async/AsyncTCP @ 3.4.10
|
||||
ESP32Async/ESPAsyncWebServer @ 3.9.4
|
||||
ESP32Async/ESPAsyncWebServer @ 3.9.5
|
||||
https://github.com/emsesp/EMS-ESP-Modules.git @ 1.0.8
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,24 +21,24 @@ void APSettingsService::begin() {
|
||||
|
||||
// wait 10 sec on STA disconnect before starting AP
|
||||
void APSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||
uint8_t was_connected = _connected;
|
||||
const uint8_t was_connected = _connected;
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
_connected &= ~1;
|
||||
_connected &= ~1U;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
_connected &= ~2;
|
||||
_connected &= ~2U;
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
_connected |= 1;
|
||||
_connected |= 1U;
|
||||
break;
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP6:
|
||||
_connected |= 2;
|
||||
_connected |= 2U;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return;
|
||||
}
|
||||
// wait 10 sec before starting AP
|
||||
if (was_connected && !_connected) {
|
||||
@@ -52,18 +52,19 @@ void APSettingsService::reconfigureAP() {
|
||||
}
|
||||
|
||||
void APSettingsService::loop() {
|
||||
unsigned long currentMillis = uuid::get_uptime();
|
||||
unsigned long manageElapsed = static_cast<uint32_t>(currentMillis - _lastManaged);
|
||||
if (manageElapsed >= MANAGE_NETWORK_DELAY) {
|
||||
const unsigned long currentMillis = uuid::get_uptime();
|
||||
if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) {
|
||||
_lastManaged = currentMillis;
|
||||
manageAP();
|
||||
}
|
||||
|
||||
if (_dnsServer) {
|
||||
handleDNS();
|
||||
}
|
||||
}
|
||||
|
||||
void APSettingsService::manageAP() {
|
||||
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
const WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
if (_state.provisionMode == AP_MODE_ALWAYS || (_state.provisionMode == AP_MODE_DISCONNECTED && !_connected)) {
|
||||
if (_reconfigureAp || currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) {
|
||||
startAP();
|
||||
@@ -87,8 +88,10 @@ void APSettingsService::startAP() {
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||
#endif
|
||||
if (!_dnsServer) {
|
||||
IPAddress apIp = WiFi.softAPIP();
|
||||
emsesp::EMSESP::logger().info("Starting Access Point with captive portal on %s", apIp.toString().c_str());
|
||||
const IPAddress apIp = WiFi.softAPIP();
|
||||
char ipStr[16];
|
||||
snprintf(ipStr, sizeof(ipStr), "%u.%u.%u.%u", apIp[0], apIp[1], apIp[2], apIp[3]);
|
||||
emsesp::EMSESP::logger().info("Starting Access Point with captive portal on %s", ipStr);
|
||||
_dnsServer = new DNSServer;
|
||||
_dnsServer->start(DNS_PORT, "*", apIp);
|
||||
}
|
||||
@@ -111,8 +114,8 @@ void APSettingsService::handleDNS() {
|
||||
}
|
||||
|
||||
APNetworkStatus APSettingsService::getAPNetworkStatus() {
|
||||
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
bool apActive = currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA;
|
||||
const WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
const bool apActive = (currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA);
|
||||
|
||||
if (apActive && _state.provisionMode != AP_MODE_ALWAYS && WiFi.status() == WL_CONNECTED) {
|
||||
return APNetworkStatus::LINGERING;
|
||||
@@ -135,7 +138,7 @@ void APSettings::read(const APSettings & settings, JsonObject root) {
|
||||
}
|
||||
|
||||
StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
||||
APSettings newSettings = {};
|
||||
APSettings newSettings{};
|
||||
newSettings.provisionMode = static_cast<uint8_t>(root["provision_mode"] | FACTORY_AP_PROVISION_MODE);
|
||||
|
||||
switch (settings.provisionMode) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef APSettingsConfig_h
|
||||
#define APSettingsConfig_h
|
||||
#ifndef APSettingsService_h
|
||||
#define APSettingsService_h
|
||||
|
||||
#include "HttpEndpoint.h"
|
||||
#include "FSPersistence.h"
|
||||
@@ -70,9 +70,9 @@ class APSettings {
|
||||
IPAddress subnetMask;
|
||||
|
||||
bool operator==(const APSettings & settings) const {
|
||||
return provisionMode == settings.provisionMode && ssid == settings.ssid && password == settings.password && channel == settings.channel
|
||||
&& ssidHidden == settings.ssidHidden && maxClients == settings.maxClients && localIP == settings.localIP && gatewayIP == settings.gatewayIP
|
||||
&& subnetMask == settings.subnetMask;
|
||||
return provisionMode == settings.provisionMode && channel == settings.channel && ssidHidden == settings.ssidHidden
|
||||
&& maxClients == settings.maxClients && localIP == settings.localIP && gatewayIP == settings.gatewayIP
|
||||
&& subnetMask == settings.subnetMask && ssid == settings.ssid && password == settings.password;
|
||||
}
|
||||
|
||||
static void read(const APSettings & settings, JsonObject root);
|
||||
@@ -96,8 +96,8 @@ class APSettingsService : public StatefulService<APSettings> {
|
||||
|
||||
// for the management delay loop
|
||||
volatile unsigned long _lastManaged;
|
||||
volatile boolean _reconfigureAp;
|
||||
uint8_t _connected;
|
||||
volatile bool _reconfigureAp;
|
||||
volatile uint8_t _connected;
|
||||
|
||||
void reconfigureAP();
|
||||
void manageAP();
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "WWWData.h" // include auto-generated static web resources
|
||||
|
||||
static constexpr const char CACHE_CONTROL[] = "public,max-age=60";
|
||||
|
||||
ESP32React::ESP32React(AsyncWebServer * server, FS * fs)
|
||||
: _securitySettingsService(server, fs)
|
||||
, _networkSettingsService(server, fs, &_securitySettingsService)
|
||||
@@ -22,21 +24,18 @@ ESP32React::ESP32React(AsyncWebServer * server, FS * fs)
|
||||
ArRequestHandlerFunction indexHtmlHandler = nullptr;
|
||||
|
||||
WWWData::registerRoutes([server, &indexHtmlHandler](const char * uri, const String & contentType, const uint8_t * content, size_t len, const String & hash) {
|
||||
ArRequestHandlerFunction requestHandler = [contentType, content, len, hash](AsyncWebServerRequest * request) {
|
||||
AsyncWebServerResponse * response;
|
||||
String etag = "\"" + hash + "\""; // RFC9110: ETag must be enclosed in double quotes
|
||||
|
||||
// Check if the client already has the same version and respond with a 304 (Not modified)
|
||||
if (request->header("If-None-Match").equals(hash)) {
|
||||
response = request->beginResponse(304);
|
||||
} else {
|
||||
response = request->beginResponse(200, contentType, content, len);
|
||||
response->addHeader("Content-Encoding", "gzip"); // not br for brotlin only works over HTTPS
|
||||
ArRequestHandlerFunction requestHandler = [contentType, content, len, etag](AsyncWebServerRequest * request) {
|
||||
if (request->header(asyncsrv::T_INM) == etag) {
|
||||
request->send(304);
|
||||
return;
|
||||
}
|
||||
|
||||
// always send these headers - see https://datatracker.ietf.org/doc/html/rfc7232#section-4.1
|
||||
response->addHeader("ETag", hash);
|
||||
response->addHeader("Cache-Control", "no-cache"); // Requires revalidation before using cached content (ETags enable 304 responses)
|
||||
|
||||
AsyncWebServerResponse * response = request->beginResponse(200, contentType, content, len);
|
||||
response->addHeader(asyncsrv::T_Content_Encoding, asyncsrv::T_gzip, false);
|
||||
response->addHeader(asyncsrv::T_ETag, etag, false);
|
||||
response->addHeader(asyncsrv::T_Cache_Control, CACHE_CONTROL, false);
|
||||
request->send(response);
|
||||
};
|
||||
|
||||
@@ -69,11 +68,11 @@ void ESP32React::begin() {
|
||||
_networkSettingsService.read([&](NetworkSettings & networkSettings) {
|
||||
DefaultHeaders & defaultHeaders = DefaultHeaders::Instance();
|
||||
if (networkSettings.enableCORS) {
|
||||
defaultHeaders.addHeader("Access-Control-Allow-Origin", networkSettings.CORSOrigin);
|
||||
defaultHeaders.addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
|
||||
defaultHeaders.addHeader("Access-Control-Allow-Credentials", "true");
|
||||
defaultHeaders.addHeader(asyncsrv::T_CORS_ACAO, networkSettings.CORSOrigin);
|
||||
defaultHeaders.addHeader(asyncsrv::T_CORS_ACAH, "Accept, Content-Type, Authorization");
|
||||
defaultHeaders.addHeader(asyncsrv::T_CORS_ACAC, "true");
|
||||
}
|
||||
defaultHeaders.addHeader("Server", networkSettings.hostname);
|
||||
defaultHeaders.addHeader(asyncsrv::T_Server, networkSettings.hostname);
|
||||
});
|
||||
_apSettingsService.begin();
|
||||
_ntpSettingsService.begin();
|
||||
|
||||
@@ -10,20 +10,23 @@
|
||||
class JsonUtils {
|
||||
public:
|
||||
static void readIP(JsonObject root, const String & key, IPAddress & ip, const String & def) {
|
||||
IPAddress defaultIp = {};
|
||||
IPAddress defaultIp{};
|
||||
if (!defaultIp.fromString(def)) {
|
||||
defaultIp = INADDR_NONE;
|
||||
}
|
||||
readIP(root, key, ip, defaultIp);
|
||||
}
|
||||
static void readIP(JsonObject root, const String & key, IPAddress & ip, const IPAddress & defaultIp = INADDR_NONE) {
|
||||
if (!root[key].is<String>() || !ip.fromString(root[key].as<String>())) {
|
||||
const JsonVariant value = root[key];
|
||||
if (!value.is<String>() || !ip.fromString(value.as<const char *>())) {
|
||||
ip = defaultIp;
|
||||
}
|
||||
}
|
||||
static void writeIP(JsonObject root, const String & key, const IPAddress & ip) {
|
||||
if (IPUtils::isSet(ip)) {
|
||||
root[key] = ip.toString();
|
||||
char ipStr[16];
|
||||
snprintf(ipStr, sizeof(ipStr), "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
|
||||
root[key] = ipStr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -255,7 +255,7 @@ void MqttSettings::read(MqttSettings & settings, JsonObject root) {
|
||||
}
|
||||
|
||||
StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings) {
|
||||
MqttSettings newSettings = {};
|
||||
MqttSettings newSettings;
|
||||
bool changed = false;
|
||||
|
||||
#ifndef TASMOTA_SDK
|
||||
|
||||
@@ -125,11 +125,11 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
||||
FSPersistence<MqttSettings> _fsPersistence;
|
||||
|
||||
// variable to help manage connection
|
||||
bool _reconfigureMqtt;
|
||||
unsigned long _disconnectedAt;
|
||||
volatile bool _reconfigureMqtt;
|
||||
volatile unsigned long _disconnectedAt;
|
||||
|
||||
// connection status
|
||||
espMqttClientTypes::DisconnectReason _disconnectReason;
|
||||
volatile espMqttClientTypes::DisconnectReason _disconnectReason;
|
||||
|
||||
// the MQTT client instance
|
||||
MqttClient * _mqttClient;
|
||||
|
||||
@@ -49,7 +49,7 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
|
||||
private:
|
||||
HttpEndpoint<NTPSettings> _httpEndpoint;
|
||||
FSPersistence<NTPSettings> _fsPersistence;
|
||||
bool _connected;
|
||||
volatile bool _connected;
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
void configureNTP();
|
||||
|
||||
@@ -102,10 +102,10 @@ class NetworkSettingsService : public StatefulService<NetworkSettings> {
|
||||
HttpEndpoint<NetworkSettings> _httpEndpoint;
|
||||
FSPersistence<NetworkSettings> _fsPersistence;
|
||||
|
||||
unsigned long _lastConnectionAttempt;
|
||||
bool _stopping;
|
||||
volatile unsigned long _lastConnectionAttempt;
|
||||
volatile bool _stopping;
|
||||
|
||||
uint16_t connectcount_ = 0; // number of wifi reconnects
|
||||
volatile uint16_t connectcount_ = 0; // number of wifi reconnects
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||
void mDNS_start() const;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#ifndef EMSESP_COMMAND_H_
|
||||
#define EMSESP_COMMAND_H_
|
||||
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
#include "console.h"
|
||||
#include <esp32-psram.h>
|
||||
@@ -153,7 +153,7 @@ class Command {
|
||||
|
||||
class SUrlParser {
|
||||
private:
|
||||
std::unordered_map<std::string, std::string> m_keysvalues;
|
||||
std::map<std::string, std::string> m_keysvalues;
|
||||
std::vector<std::string> m_folders;
|
||||
|
||||
public:
|
||||
@@ -166,7 +166,7 @@ class SUrlParser {
|
||||
return m_folders;
|
||||
};
|
||||
|
||||
std::unordered_map<std::string, std::string> & params() {
|
||||
std::map<std::string, std::string> & params() {
|
||||
return m_keysvalues;
|
||||
};
|
||||
|
||||
|
||||
@@ -1721,7 +1721,7 @@ void EMSdevice::get_value_json(JsonObject json, DeviceValue & dv) {
|
||||
// generate Prometheus metrics format from device values
|
||||
std::string EMSdevice::get_metrics_prometheus(const int8_t tag) {
|
||||
std::string result;
|
||||
std::unordered_map<std::string, bool> seen_metrics;
|
||||
std::map<std::string, bool> seen_metrics;
|
||||
|
||||
// Helper function to check if a device value type is supported for Prometheus metrics
|
||||
auto is_supported_type = [](uint8_t type) -> bool {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "emsdevicevalue.h"
|
||||
|
||||
#include <esp32-psram.h>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
@@ -19,14 +19,15 @@
|
||||
#ifndef EMSESP_EMSFACTORY_H_
|
||||
#define EMSESP_EMSFACTORY_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory> // for unique_ptr
|
||||
#include <map>
|
||||
|
||||
#include "emsdevice.h"
|
||||
// Forward declaration
|
||||
namespace emsesp {
|
||||
class EMSdevice;
|
||||
}
|
||||
|
||||
// Macro for class registration
|
||||
// Anonymous namespace is used to make the definitions here private to the current
|
||||
// compilation unit (current file). It is equivalent to the old C static keyword.
|
||||
#define REGISTER_FACTORY(derivedClass, device_type) \
|
||||
namespace { \
|
||||
auto registry_##derivedClass = ConcreteEMSFactory<derivedClass>(device_type); \
|
||||
@@ -34,30 +35,29 @@
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
class EMSdevice; // forward declaration, for gcc linking
|
||||
|
||||
class EMSFactory {
|
||||
public:
|
||||
virtual ~EMSFactory() = default;
|
||||
|
||||
// Register factory object of derived class
|
||||
// using the device_type as the unique identifier
|
||||
static auto registerFactory(const uint8_t device_type, EMSFactory * factory) -> void {
|
||||
auto & reg = EMSFactory::getRegister();
|
||||
reg[device_type] = factory;
|
||||
}
|
||||
|
||||
using FactoryMap = std::map<uint8_t, EMSFactory *>;
|
||||
|
||||
// Register factory object of derived class using the device_type as the unique identifier
|
||||
static inline auto registerFactory(const uint8_t device_type, EMSFactory * factory) -> void {
|
||||
getRegister()[device_type] = factory;
|
||||
}
|
||||
|
||||
// returns all registered classes (really only for debugging)
|
||||
static auto device_handlers() -> FactoryMap {
|
||||
return EMSFactory::getRegister();
|
||||
static inline auto device_handlers() -> const FactoryMap & {
|
||||
return getRegister();
|
||||
}
|
||||
|
||||
// Construct derived class returning an unique ptr
|
||||
static auto add(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * default_name, uint8_t flags, uint8_t brand)
|
||||
-> std::unique_ptr<EMSdevice> {
|
||||
return std::unique_ptr<EMSdevice>(EMSFactory::makeRaw(device_type, device_id, product_id, version, default_name, flags, brand));
|
||||
if (auto * ptr = makeRaw(device_type, device_id, product_id, version, default_name, flags, brand)) {
|
||||
return std::unique_ptr<EMSdevice>(ptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual auto construct(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand) const
|
||||
@@ -65,7 +65,7 @@ class EMSFactory {
|
||||
|
||||
private:
|
||||
// Force global variable to be initialized, thus it avoids the "initialization order fiasco"
|
||||
static auto getRegister() -> FactoryMap & {
|
||||
static inline auto getRegister() -> FactoryMap & {
|
||||
static FactoryMap classRegister{};
|
||||
return classRegister;
|
||||
}
|
||||
@@ -74,11 +74,9 @@ class EMSFactory {
|
||||
// find which EMS device it is and use that class
|
||||
static auto makeRaw(const uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const char * name, uint8_t flags, uint8_t brand)
|
||||
-> EMSdevice * {
|
||||
auto it = EMSFactory::getRegister().find(device_type);
|
||||
if (it != EMSFactory::getRegister().end()) {
|
||||
return it->second->construct(device_type, device_id, product_id, version, name, flags, brand);
|
||||
}
|
||||
return nullptr;
|
||||
const auto & reg = getRegister();
|
||||
const auto it = reg.find(device_type);
|
||||
return (it != reg.end()) ? it->second->construct(device_type, device_id, product_id, version, name, flags, brand) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -86,7 +84,7 @@ template <typename DerivedClass>
|
||||
class ConcreteEMSFactory : EMSFactory {
|
||||
public:
|
||||
// Register this global object on the EMSFactory register
|
||||
ConcreteEMSFactory(const uint8_t device_type) {
|
||||
explicit ConcreteEMSFactory(const uint8_t device_type) {
|
||||
EMSFactory::registerFactory(device_type, this);
|
||||
}
|
||||
|
||||
|
||||
@@ -344,7 +344,11 @@ bool isnum(const std::string & s) {
|
||||
std::string commands(std::string & expr, bool quotes) {
|
||||
auto expr_new = Helpers::toLower(expr);
|
||||
for (uint8_t device = 0; device < EMSdevice::DeviceType::UNKNOWN; device++) {
|
||||
std::string d = (std::string)EMSdevice::device_type_2_device_name(device) + "/";
|
||||
// Optimized: build string with reserve to avoid temporary allocations
|
||||
std::string d;
|
||||
d.reserve(32); // typical device name length + "/"
|
||||
d = EMSdevice::device_type_2_device_name(device);
|
||||
d += "/";
|
||||
auto f = expr_new.find(d);
|
||||
while (f != std::string::npos) {
|
||||
// entity names are alphanumeric or _
|
||||
@@ -367,9 +371,11 @@ std::string commands(std::string & expr, bool quotes) {
|
||||
JsonDocument doc_in;
|
||||
JsonObject output = doc_out.to<JsonObject>();
|
||||
JsonObject input = doc_in.to<JsonObject>();
|
||||
std::string cmd_s = "api/" + std::string(cmd);
|
||||
// Optimized: use stack buffer for small strings to avoid heap allocation
|
||||
char cmd_s[COMMAND_MAX_LENGTH + 5]; // "api/" prefix + cmd
|
||||
snprintf(cmd_s, sizeof(cmd_s), "api/%s", cmd);
|
||||
|
||||
auto return_code = Command::process(cmd_s.c_str(), true, input, output);
|
||||
auto return_code = Command::process(cmd_s, true, input, output);
|
||||
// check for no value (entity is valid but has no value set)
|
||||
if (return_code != CommandRet::OK && return_code != CommandRet::NO_VALUE) {
|
||||
return expr = "";
|
||||
@@ -725,7 +731,7 @@ std::string compute(const std::string & expr) {
|
||||
// if there is data, force a POST
|
||||
if (value.length() || Helpers::toLower(method) == "post") {
|
||||
if (value.find_first_of('{') != std::string::npos) {
|
||||
http.addHeader("Content-Type", "application/json"); // auto-set to JSON
|
||||
http.addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON
|
||||
}
|
||||
httpResult = http.POST(value.c_str());
|
||||
} else {
|
||||
|
||||
@@ -1762,7 +1762,7 @@ void System::get_value_json(JsonObject output, const std::string & circuit, cons
|
||||
// generate Prometheus metrics format from system values
|
||||
std::string System::get_metrics_prometheus() {
|
||||
std::string result;
|
||||
std::unordered_map<std::string, bool> seen_metrics;
|
||||
std::map<std::string, bool> seen_metrics;
|
||||
|
||||
result.reserve(16000);
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class Connect : public EMSdevice {
|
||||
bool set_childlock(const char * value, const int8_t id);
|
||||
bool set_icon(const char * value, const int8_t id);
|
||||
|
||||
std::vector<std::shared_ptr<Connect::RoomCircuit>> room_circuits_;
|
||||
std::vector<std::shared_ptr<Connect::RoomCircuit>, AllocatorPSRAM<std::shared_ptr<Connect::RoomCircuit>>> room_circuits_;
|
||||
|
||||
void process_OutdoorTemp(std::shared_ptr<const Telegram> telegram);
|
||||
void process_RCTime(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
@@ -59,7 +59,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
if (model == EMSdevice::EMS_DEVICE_FLAG_RC10) {
|
||||
monitor_typeids = {0xB1};
|
||||
set_typeids = {0xB0};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "RC10Monitor", false, MAKE_PF_CB(process_RC10Monitor));
|
||||
register_telegram_type(set_typeids[i], "RC10Set", false, MAKE_PF_CB(process_RC10Set));
|
||||
}
|
||||
@@ -70,7 +71,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
set_typeids = {0x3D, 0x47, 0x51, 0x5B};
|
||||
timer_typeids = {0x3F, 0x49, 0x53, 0x5D};
|
||||
timer2_typeids = {0x42, 0x4C, 0x56, 0x60};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "RC35Monitor", false, MAKE_PF_CB(process_RC35Monitor));
|
||||
register_telegram_type(set_typeids[i], "RC35Set", false, MAKE_PF_CB(process_RC35Set));
|
||||
register_telegram_type(timer_typeids[i], "RC35Timer", false, MAKE_PF_CB(process_RC35Timer));
|
||||
@@ -88,7 +90,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
set_typeids = {0xA8};
|
||||
curve_typeids = {0x90};
|
||||
timer_typeids = {0x8F};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor));
|
||||
register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set));
|
||||
register_telegram_type(curve_typeids[i], "RC20Temp", false, MAKE_PF_CB(process_RC20Temp));
|
||||
@@ -103,7 +106,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
if (device_id == 0x17) { // master
|
||||
monitor_typeids = {0xAE};
|
||||
set_typeids = {0xAD};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor_2));
|
||||
register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set_2));
|
||||
}
|
||||
@@ -117,7 +121,8 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
set_typeids = {0xA7};
|
||||
curve_typeids = {0x40};
|
||||
timer_typeids = {0x3F};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "RC30Monitor", false, MAKE_PF_CB(process_RC30Monitor));
|
||||
register_telegram_type(set_typeids[i], "RC30Set", false, MAKE_PF_CB(process_RC30Set));
|
||||
register_telegram_type(curve_typeids[i], "RC30Temp", false, MAKE_PF_CB(process_RC30Temp));
|
||||
@@ -131,15 +136,16 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
// EASY
|
||||
} else if (model == EMSdevice::EMS_DEVICE_FLAG_EASY) {
|
||||
monitor_typeids = {0x0A};
|
||||
set_typeids = {};
|
||||
set_typeids.clear();
|
||||
register_telegram_type(monitor_typeids[0], "EasyMonitor", true, MAKE_PF_CB(process_EasyMonitor));
|
||||
register_telegram_type(0x02A5, "EasyMonitor", false, MAKE_PF_CB(process_EasyMonitor));
|
||||
|
||||
// CRF
|
||||
} else if (model == EMSdevice::EMS_DEVICE_FLAG_CRF) {
|
||||
monitor_typeids = {0x02A5, 0x02A6, 0x02A7, 0x02A8};
|
||||
set_typeids = {};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
set_typeids.clear();
|
||||
const size_t size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "CRFMonitor", false, MAKE_PF_CB(process_CRFMonitor));
|
||||
}
|
||||
|
||||
@@ -163,14 +169,16 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
summer2_typeids = {0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0476, 0x0477, 0x0478};
|
||||
hp_typeids = {0x0467, 0x0468, 0x0469, 0x046A};
|
||||
hpmode_typeids = {0x0291, 0x0292, 0x0293, 0x0294};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t monitor_size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < monitor_size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "RC300Monitor", false, MAKE_PF_CB(process_RC300Monitor));
|
||||
register_telegram_type(set_typeids[i], "RC300Set", false, MAKE_PF_CB(process_RC300Set));
|
||||
register_telegram_type(summer_typeids[i], "RC300Summer", false, MAKE_PF_CB(process_RC300Summer));
|
||||
register_telegram_type(curve_typeids[i], "RC300Curves", false, MAKE_PF_CB(process_RC300Curve));
|
||||
register_telegram_type(summer2_typeids[i], "RC300Summer2", false, MAKE_PF_CB(process_RC300Summer2));
|
||||
}
|
||||
for (uint8_t i = 0; i < set2_typeids.size(); i++) {
|
||||
const size_t set2_size = set2_typeids.size();
|
||||
for (uint8_t i = 0; i < set2_size; i++) {
|
||||
// register_telegram_type(set2_typeids[i], "RC300Set2", false, MAKE_PF_CB(process_RC300Set2));
|
||||
register_telegram_type(set2_typeids[i], "RC300Set2", false, MAKE_PF_CB(process_PID));
|
||||
register_telegram_type(hp_typeids[i], "HPSet", false, MAKE_PF_CB(process_HPSet));
|
||||
@@ -210,19 +218,20 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
}
|
||||
|
||||
monitor_typeids = {0x016F, 0x0170, 0x0171, 0x0172};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t junkers_size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < junkers_size; i++) {
|
||||
register_telegram_type(monitor_typeids[i], "JunkersMonitor", false, MAKE_PF_CB(process_JunkersMonitor));
|
||||
}
|
||||
|
||||
if (has_flags(EMSdevice::EMS_DEVICE_FLAG_JUNKERS_OLD)) {
|
||||
// FR120, FR100
|
||||
set_typeids = {0x0179, 0x017A, 0x017B, 0x017C};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
for (uint8_t i = 0; i < junkers_size; i++) {
|
||||
register_telegram_type(set_typeids[i], "JunkersSet", false, MAKE_PF_CB(process_JunkersSet2));
|
||||
}
|
||||
} else {
|
||||
set_typeids = {0x0165, 0x0166, 0x0167, 0x0168};
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
for (uint8_t i = 0; i < junkers_size; i++) {
|
||||
register_telegram_type(set_typeids[i], "JunkersSet", false, MAKE_PF_CB(process_JunkersSet));
|
||||
}
|
||||
}
|
||||
@@ -237,10 +246,12 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
||||
|
||||
// query all the heating circuits. This is only done once.
|
||||
// The automatic fetch will from now on only update the active heating circuits
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t monitor_size_final = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < monitor_size_final; i++) {
|
||||
EMSESP::send_read_request(monitor_typeids[i], device_id);
|
||||
}
|
||||
for (uint8_t i = 0; i < set_typeids.size(); i++) {
|
||||
const size_t set_size = set_typeids.size();
|
||||
for (uint8_t i = 0; i < set_size; i++) {
|
||||
EMSESP::send_read_request(set_typeids[i], device_id);
|
||||
}
|
||||
|
||||
@@ -293,7 +304,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search monitor message types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||
const size_t monitor_size = monitor_typeids.size();
|
||||
for (uint8_t i = 0; i < monitor_size; i++) {
|
||||
if (monitor_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
toggle_ = true;
|
||||
@@ -304,7 +316,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search status message/set types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < set_typeids.size(); i++) {
|
||||
const size_t set_size = set_typeids.size();
|
||||
for (uint8_t i = 0; i < set_size; i++) {
|
||||
if (set_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
@@ -314,7 +327,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search set2 types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < set2_typeids.size(); i++) {
|
||||
const size_t set2_size = set2_typeids.size();
|
||||
for (uint8_t i = 0; i < set2_size; i++) {
|
||||
if (set2_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
@@ -324,7 +338,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search summer message types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < summer_typeids.size(); i++) {
|
||||
const size_t summer_size = summer_typeids.size();
|
||||
for (uint8_t i = 0; i < summer_size; i++) {
|
||||
if (summer_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
@@ -334,7 +349,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search summer message types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < summer2_typeids.size(); i++) {
|
||||
const size_t summer2_size = summer2_typeids.size();
|
||||
for (uint8_t i = 0; i < summer2_size; i++) {
|
||||
if (summer2_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
@@ -344,7 +360,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search heating_curve message types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < curve_typeids.size(); i++) {
|
||||
const size_t curve_size = curve_typeids.size();
|
||||
for (uint8_t i = 0; i < curve_size; i++) {
|
||||
if (curve_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
@@ -354,7 +371,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search timer message types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < timer_typeids.size(); i++) {
|
||||
const size_t timer_size = timer_typeids.size();
|
||||
for (uint8_t i = 0; i < timer_size; i++) {
|
||||
if (timer_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
@@ -364,7 +382,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search timer message types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < timer2_typeids.size(); i++) {
|
||||
const size_t timer2_size = timer2_typeids.size();
|
||||
for (uint8_t i = 0; i < timer2_size; i++) {
|
||||
if (timer2_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
@@ -374,7 +393,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
|
||||
// not found, search heatpump message types
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < hp_typeids.size(); i++) {
|
||||
const size_t hp_size = hp_typeids.size();
|
||||
for (uint8_t i = 0; i < hp_size; i++) {
|
||||
if (hp_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
@@ -383,7 +403,8 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
||||
}
|
||||
|
||||
if (hc_num == 0) {
|
||||
for (uint8_t i = 0; i < hpmode_typeids.size(); i++) {
|
||||
const size_t hpmode_size = hpmode_typeids.size();
|
||||
for (uint8_t i = 0; i < hpmode_size; i++) {
|
||||
if (hpmode_typeids[i] == telegram->type_id) {
|
||||
hc_num = i + 1;
|
||||
break;
|
||||
|
||||
@@ -244,16 +244,16 @@ class Thermostat : public EMSdevice {
|
||||
}
|
||||
|
||||
// each thermostat has a list of heating controller type IDs for reading and writing
|
||||
std::vector<uint16_t> monitor_typeids;
|
||||
std::vector<uint16_t> set_typeids;
|
||||
std::vector<uint16_t> set2_typeids;
|
||||
std::vector<uint16_t> timer_typeids;
|
||||
std::vector<uint16_t> timer2_typeids;
|
||||
std::vector<uint16_t> summer_typeids;
|
||||
std::vector<uint16_t> summer2_typeids;
|
||||
std::vector<uint16_t> curve_typeids;
|
||||
std::vector<uint16_t> hp_typeids;
|
||||
std::vector<uint16_t> hpmode_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> monitor_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> set_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> set2_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> timer_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> timer2_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> summer_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> summer2_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> curve_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> hp_typeids;
|
||||
std::vector<uint16_t, AllocatorPSRAM<uint16_t>> hpmode_typeids;
|
||||
|
||||
// standard for all thermostats
|
||||
char status_[20]; // online or offline
|
||||
@@ -305,8 +305,8 @@ class Thermostat : public EMSdevice {
|
||||
uint8_t pvRaiseHeat_;
|
||||
uint8_t pvLowerCool_;
|
||||
|
||||
std::vector<std::shared_ptr<HeatingCircuit>> heating_circuits_; // each thermostat can have multiple heating circuits
|
||||
std::vector<std::shared_ptr<DhwCircuit>> dhw_circuits_; // each thermostat can have multiple dhw circuits
|
||||
std::vector<std::shared_ptr<HeatingCircuit>, AllocatorPSRAM<std::shared_ptr<HeatingCircuit>>> heating_circuits_; // each thermostat can have multiple heating circuits
|
||||
std::vector<std::shared_ptr<DhwCircuit>, AllocatorPSRAM<std::shared_ptr<DhwCircuit>>> dhw_circuits_; // each thermostat can have multiple dhw circuits
|
||||
|
||||
// Generic Types
|
||||
static constexpr uint16_t EMS_TYPE_RCTime = 0x06; // time
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define EMSESP_APP_VERSION "3.8.1"
|
||||
#define EMSESP_APP_VERSION "3.8.2-dev.1"
|
||||
|
||||
@@ -248,18 +248,24 @@ void WebSchedulerService::publish(const bool force) {
|
||||
snprintf(val_obj, sizeof(val_obj), "value_json['%s']", scheduleItem.name);
|
||||
snprintf(val_cond, sizeof(val_cond), "%s is defined", val_obj);
|
||||
|
||||
// Optimized: use stack buffer instead of string concatenation to avoid heap allocations
|
||||
char val_tpl[150];
|
||||
if (Mqtt::discovery_type() == Mqtt::discoveryType::HOMEASSISTANT) {
|
||||
config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + "}}";
|
||||
snprintf(val_tpl, sizeof(val_tpl), "{{%s if %s}}", val_obj, val_cond);
|
||||
} else {
|
||||
config["val_tpl"] = (std::string) "{{" + val_obj + "}}"; // omit value conditional Jinja2 template code
|
||||
snprintf(val_tpl, sizeof(val_tpl), "{{%s}}", val_obj); // omit value conditional Jinja2 template code
|
||||
}
|
||||
config["val_tpl"] = val_tpl;
|
||||
|
||||
char uniq_s[70];
|
||||
snprintf(uniq_s, sizeof(uniq_s), "%s_%s", F_(scheduler), scheduleItem.name);
|
||||
|
||||
config["uniq_id"] = uniq_s;
|
||||
config["name"] = (const char *)scheduleItem.name;
|
||||
config["def_ent_id"] = std::string("switch.") + uniq_s;
|
||||
// Optimized: use stack buffer instead of string concatenation
|
||||
char def_ent_id[80];
|
||||
snprintf(def_ent_id, sizeof(def_ent_id), "switch.%s", uniq_s);
|
||||
config["def_ent_id"] = def_ent_id;
|
||||
|
||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||
char command_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||
@@ -331,7 +337,7 @@ bool WebSchedulerService::command(const char * name, const std::string & command
|
||||
int httpResult = 0;
|
||||
if (value.length() || method == "post") { // we have all lowercase
|
||||
if (value.find_first_of('{') != std::string::npos) {
|
||||
http.addHeader("Content-Type", "application/json"); // auto-set to JSON
|
||||
http.addHeader(asyncsrv::T_Content_Type, asyncsrv::T_application_json, false); // auto-set to JSON
|
||||
}
|
||||
httpResult = http.POST(value.c_str());
|
||||
} else {
|
||||
|
||||
@@ -496,7 +496,15 @@ void WebSettings::set_board_profile(WebSettings & settings) {
|
||||
System::load_board_profile(data, settings.board_profile.c_str());
|
||||
}
|
||||
|
||||
EMSESP::logger().info("Loaded board profile %s", settings.board_profile.c_str());
|
||||
// log board profile and PSRAM info
|
||||
#ifndef EMSESP_STANDALONE
|
||||
uint32_t psram_size = ESP.getPsramSize() / 1024; // in KB
|
||||
if (psram_size > 0) {
|
||||
EMSESP::logger().info("Loaded board profile %s, PSRAM: %lu KB", settings.board_profile.c_str(), psram_size);
|
||||
} else {
|
||||
EMSESP::logger().info("Loaded board profile %s, PSRAM: not available", settings.board_profile.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
// apply the new board profile settings
|
||||
// 0=led, 1=dallas, 2=rx, 3=tx, 4=button, 5=phy_type, 6=eth_power, 7=eth_phy_addr, 8=eth_clock_mode, 9=led_type
|
||||
|
||||
Reference in New Issue
Block a user