Merge pull request #1226 from proddy/dev2

dev2 - minor changes
This commit is contained in:
Proddy
2023-07-14 17:25:37 +02:00
committed by GitHub
29 changed files with 1180 additions and 442 deletions

21
.vscode/tasks.json vendored
View File

@@ -4,20 +4,15 @@
"version": "2.0.0",
"tasks": [
{
"label": "PlatformIO: Execute EMS-ESP (standalone)",
"type": "shell",
"command": "./.pio/build/standalone/program",
"linux": {
"options": {
"env": {
// Workaround for sdl2 `-m32` crash
// https://bugs.launchpad.net/ubuntu/+source/libsdl2/+bug/1775067/comments/7
"DBUS_FATAL_WARNINGS": "0"
}
}
},
"dependsOn": ["PlatformIO: Build EMS-ESP (standalone)"],
"problemMatcher": []
"label": "build standalone emsesp",
"command": "make",
"args": [],
"problemMatcher": ["$gcc"],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@@ -17,13 +17,13 @@ MAKEFLAGS+="j "
#TARGET := $(notdir $(CURDIR))
TARGET := emsesp
BUILD := build
SOURCES := src src/* lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src src/devices lib/ArduinoJson/src lib/PButton lib/semver
INCLUDES := src lib_standalone lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src lib/semver lib/* src/devices
LIBRARIES :=
SOURCES := src src/* lib_standalone lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src src/devices lib/ArduinoJson/src lib/PButton lib/semver lib/espMqttClient/src lib/espMqttClient/src/*
INCLUDES := src lib_standalone lib/espMqttClient/src lib/espMqttClient/src/Transport lib/ArduinoJson/src lib/uuid-common/src lib/uuid-console/src lib/uuid-log/src lib/uuid-telnet/src lib/uuid-syslog/src lib/semver lib/* src/devices
LIBRARIES :=
CPPCHECK = cppcheck
# CHECKFLAGS = -q --force --std=c++17
CHECKFLAGS = -q --force --std=c++11
CHECKFLAGS = -q --force --std=c++11 -pthread
#----------------------------------------------------------------------
# Languages Standard
@@ -36,8 +36,8 @@ CXX_STANDARD := -std=c++11
#----------------------------------------------------------------------
# Defined Symbols
#----------------------------------------------------------------------
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0 -DARDUINO
DEFINES += -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST
DEFINES += -DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
DEFINES += -DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST -D__linux__ -DEMC_RX_BUFFER_SIZE=1500
DEFINES += $(ARGS)
DEFAULTS = -DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.6.0-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
@@ -52,7 +52,7 @@ CSOURCES := $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.c))
CXXSOURCES := $(foreach dir,$(SOURCES),$(wildcard $(dir)/*.cpp))
OBJS := $(patsubst %,$(BUILD)/%.o,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)) )
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)) )
DEPS := $(patsubst %,$(BUILD)/%.d,$(basename $(CSOURCES)) $(basename $(CXXSOURCES)) )
INCLUDE += $(addprefix -I,$(foreach dir,$(INCLUDES), $(wildcard $(dir))))
INCLUDE += $(addprefix -I,$(foreach dir,$(LIBRARIES),$(wildcard $(dir)/include)))
@@ -79,7 +79,7 @@ CPPFLAGS += -g3
CPPFLAGS += -Os
CFLAGS += $(CPPFLAGS)
CFLAGS += -Wall -Wextra -Werror -Wswitch-enum -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-unused-lambda-capture
CFLAGS += -Wall -Wextra -Werror -Wswitch-enum -Wno-unused-parameter
CXXFLAGS += $(CFLAGS) -MMD

View File

@@ -26,10 +26,10 @@
"@mui/material": "^5.14.0",
"@preact/compat": "^17.1.2",
"@table-library/react-table-library": "4.1.4",
"@types/lodash-es": "^4.17.7",
"@types/node": "^20.4.1",
"@types/react": "^18.2.14",
"@types/react-dom": "^18.2.6",
"@types/lodash-es": "^4.17.8",
"@types/node": "^20.4.2",
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@types/react-router-dom": "^5.3.3",
"alova": "^2.9.2",
"async-validator": "^4.2.5",
@@ -52,9 +52,10 @@
"@preact/preset-vite": "^2.5.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"cspell": "^6.31.1",
"eslint": "^8.44.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-airbnb-typescript": "^17.1.0",
"eslint-config-prettier": "^8.8.0",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-autofix": "^1.1.0",
@@ -68,7 +69,7 @@
"prettier": "^3.0.0",
"rollup-plugin-visualizer": "^5.9.2",
"terser": "^5.19.0",
"vite": "^4.4.3",
"vite": "^4.4.4",
"vite-plugin-svgr": "^3.2.0",
"vite-tsconfig-paths": "^4.2.0"
},

View File

@@ -1,5 +1,5 @@
/*
* Uses font-size 400 (normal) only and Latin (plus extra unicode chars) to keep flash memory to a minimun
* Uses font-size 400 (normal) only and Latin (plus extra unicode chars) to keep flash memory to a minimum
* View fonts on https://fonts.google.com/
* Download woff2 using e.g. https://fonts.googleapis.com/css2?family=Lato or https://fonts.googleapis.com/css2?family=Roboto
*/

View File

@@ -21,22 +21,22 @@ export const fetchLog = () => alovaInstance.Post('/rest/fetchLog');
// Get versions from github
export const getStableVersion = () =>
alovaInstanceGH.Get<Version>('releases/latest', {
transformData(reponse: any) {
transformData(response: any) {
return {
version: reponse.data.name,
url: reponse.data.assets[1].browser_download_url,
changelog: reponse.data.assets[0].browser_download_url
version: response.data.name,
url: response.data.assets[1].browser_download_url,
changelog: response.data.assets[0].browser_download_url
};
}
});
export const getDevVersion = () =>
alovaInstanceGH.Get<Version>('releases/tags/latest', {
transformData(reponse: any) {
transformData(response: any) {
return {
version: reponse.data.name.split(/\s+/).splice(-1),
url: reponse.data.assets[1].browser_download_url,
changelog: reponse.data.assets[0].browser_download_url
version: response.data.name.split(/\s+/).splice(-1),
url: response.data.assets[1].browser_download_url,
changelog: response.data.assets[0].browser_download_url
};
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -24,167 +24,171 @@ the LICENSE file.
#include "Transport/Transport.h"
class MqttClient {
public:
virtual ~MqttClient();
bool connected() const;
bool disconnected() const;
bool connect();
bool disconnect(bool force = false);
template <typename... Args>
uint16_t subscribe(const char* topic, uint8_t qos, Args&&... args) {
uint16_t packetId = _getNextPacketId();
if (_state != State::connected) {
packetId = 0;
} else {
EMC_SEMAPHORE_TAKE();
if (!_addPacket(packetId, topic, qos, std::forward<Args>(args) ...)) {
emc_log_e("Could not create SUBSCRIBE packet");
packetId = 0;
}
EMC_SEMAPHORE_GIVE();
public:
virtual ~MqttClient();
bool connected() const;
bool disconnected() const;
bool connect();
bool disconnect(bool force = false);
template <typename... Args>
uint16_t subscribe(const char * topic, uint8_t qos, Args &&... args) {
uint16_t packetId = _getNextPacketId();
if (_state != State::connected) {
packetId = 0;
} else {
EMC_SEMAPHORE_TAKE();
if (!_addPacket(packetId, topic, qos, std::forward<Args>(args)...)) {
emc_log_e("Could not create SUBSCRIBE packet");
packetId = 0;
}
EMC_SEMAPHORE_GIVE();
}
return packetId;
}
return packetId;
}
template <typename... Args>
uint16_t unsubscribe(const char* topic, Args&&... args) {
uint16_t packetId = _getNextPacketId();
if (_state != State::connected) {
packetId = 0;
} else {
EMC_SEMAPHORE_TAKE();
if (!_addPacket(packetId, topic, std::forward<Args>(args) ...)) {
emc_log_e("Could not create UNSUBSCRIBE packet");
packetId = 0;
}
EMC_SEMAPHORE_GIVE();
template <typename... Args>
uint16_t unsubscribe(const char * topic, Args &&... args) {
uint16_t packetId = _getNextPacketId();
if (_state != State::connected) {
packetId = 0;
} else {
EMC_SEMAPHORE_TAKE();
if (!_addPacket(packetId, topic, std::forward<Args>(args)...)) {
emc_log_e("Could not create UNSUBSCRIBE packet");
packetId = 0;
}
EMC_SEMAPHORE_GIVE();
}
return packetId;
}
return packetId;
}
uint16_t publish(const char* topic, uint8_t qos, bool retain, const uint8_t* payload, size_t length);
uint16_t publish(const char* topic, uint8_t qos, bool retain, const char* payload);
uint16_t publish(const char* topic, uint8_t qos, bool retain, espMqttClientTypes::PayloadCallback callback, size_t length);
void clearQueue(bool deleteSessionData = false); // Not MQTT compliant and may cause unpredictable results when `deleteSessionData` = true!
const char* getClientId() const;
uint16_t getQueue() const;
void loop();
uint16_t publish(const char * topic, uint8_t qos, bool retain, const uint8_t * payload, size_t length);
uint16_t publish(const char * topic, uint8_t qos, bool retain, const char * payload);
uint16_t publish(const char * topic, uint8_t qos, bool retain, espMqttClientTypes::PayloadCallback callback, size_t length);
void clearQueue(bool deleteSessionData = false); // Not MQTT compliant and may cause unpredictable results when `deleteSessionData` = true!
const char * getClientId() const;
uint16_t getQueue() const;
void loop();
protected:
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1);
espMqttClientTypes::UseInternalTask _useInternalTask;
espMqttClientInternals::Transport* _transport;
protected:
explicit MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority = 1, uint8_t core = 1);
espMqttClientTypes::UseInternalTask _useInternalTask;
espMqttClientInternals::Transport * _transport;
espMqttClientTypes::OnConnectCallback _onConnectCallback;
espMqttClientTypes::OnDisconnectCallback _onDisconnectCallback;
espMqttClientTypes::OnSubscribeCallback _onSubscribeCallback;
espMqttClientTypes::OnUnsubscribeCallback _onUnsubscribeCallback;
espMqttClientTypes::OnMessageCallback _onMessageCallback;
espMqttClientTypes::OnPublishCallback _onPublishCallback;
espMqttClientTypes::OnErrorCallback _onErrorCallback;
typedef void(*mqttClientHook)(void*);
const char* _clientId;
IPAddress _ip;
const char* _host;
uint16_t _port;
bool _useIp;
uint32_t _keepAlive;
bool _cleanSession;
const char* _username;
const char* _password;
const char* _willTopic;
const uint8_t* _willPayload;
uint16_t _willPayloadLength;
uint8_t _willQos;
bool _willRetain;
uint32_t _timeout;
espMqttClientTypes::OnConnectCallback _onConnectCallback;
espMqttClientTypes::OnDisconnectCallback _onDisconnectCallback;
espMqttClientTypes::OnSubscribeCallback _onSubscribeCallback;
espMqttClientTypes::OnUnsubscribeCallback _onUnsubscribeCallback;
espMqttClientTypes::OnMessageCallback _onMessageCallback;
espMqttClientTypes::OnPublishCallback _onPublishCallback;
espMqttClientTypes::OnErrorCallback _onErrorCallback;
typedef void (*mqttClientHook)(void *);
const char * _clientId;
IPAddress _ip;
const char * _host;
uint16_t _port;
bool _useIp;
uint32_t _keepAlive;
bool _cleanSession;
const char * _username;
const char * _password;
const char * _willTopic;
const uint8_t * _willPayload;
uint16_t _willPayloadLength;
uint8_t _willQos;
bool _willRetain;
uint32_t _timeout;
// state is protected to allow state changes by the transport system, defined in child classes
// eg. to allow AsyncTCP
enum class State {
disconnected = 0,
connectingTcp1 = 1,
connectingTcp2 = 2,
connectingMqtt = 3,
connected = 4,
disconnectingMqtt1 = 5,
disconnectingMqtt2 = 6,
disconnectingTcp1 = 7,
disconnectingTcp2 = 8
};
std::atomic<State> _state;
// state is protected to allow state changes by the transport system, defined in child classes
// eg. to allow AsyncTCP
enum class State {
disconnected = 0,
connectingTcp1 = 1,
connectingTcp2 = 2,
connectingMqtt = 3,
connected = 4,
disconnectingMqtt1 = 5,
disconnectingMqtt2 = 6,
disconnectingTcp1 = 7,
disconnectingTcp2 = 8
};
std::atomic<State> _state;
private:
char _generatedClientId[EMC_CLIENTID_LENGTH];
uint16_t _packetId;
private:
char _generatedClientId[EMC_CLIENTID_LENGTH];
uint16_t _packetId;
#if defined(ARDUINO_ARCH_ESP32)
SemaphoreHandle_t _xSemaphore;
TaskHandle_t _taskHandle;
static void _loop(MqttClient* c);
SemaphoreHandle_t _xSemaphore;
TaskHandle_t _taskHandle;
static void _loop(MqttClient * c);
#elif defined(ARDUINO_ARCH_ESP8266) && EMC_ESP8266_MULTITHREADING
std::atomic<bool> _xSemaphore = false;
std::atomic<bool> _xSemaphore = false;
#elif defined(__linux__)
std::mutex mtx;
// added mutable to compile EMS-ESP standalone
mutable std::mutex mtx;
#endif
uint8_t _rxBuffer[EMC_RX_BUFFER_SIZE];
struct OutgoingPacket {
uint32_t timeSent;
espMqttClientInternals::Packet packet;
uint8_t _rxBuffer[EMC_RX_BUFFER_SIZE];
struct OutgoingPacket {
uint32_t timeSent;
espMqttClientInternals::Packet packet;
template <typename... Args>
OutgoingPacket(uint32_t t, espMqttClientTypes::Error error, Args &&... args)
: timeSent(t)
, packet(error, std::forward<Args>(args)...) {
}
};
espMqttClientInternals::Outbox<OutgoingPacket> _outbox;
size_t _bytesSent;
espMqttClientInternals::Parser _parser;
uint32_t _lastClientActivity;
uint32_t _lastServerActivity;
bool _pingSent;
espMqttClientTypes::DisconnectReason _disconnectReason;
uint16_t _getNextPacketId();
template <typename... Args>
OutgoingPacket(uint32_t t, espMqttClientTypes::Error error, Args&&... args) :
timeSent(t),
packet(error, std::forward<Args>(args) ...) {}
};
espMqttClientInternals::Outbox<OutgoingPacket> _outbox;
size_t _bytesSent;
espMqttClientInternals::Parser _parser;
uint32_t _lastClientActivity;
uint32_t _lastServerActivity;
bool _pingSent;
espMqttClientTypes::DisconnectReason _disconnectReason;
bool _addPacket(Args &&... args) {
espMqttClientTypes::Error error(espMqttClientTypes::Error::SUCCESS);
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.emplace(0, error, std::forward<Args>(args)...);
if (it && error == espMqttClientTypes::Error::SUCCESS)
return true;
return false;
}
uint16_t _getNextPacketId();
template <typename... Args>
bool _addPacketFront(Args &&... args) {
espMqttClientTypes::Error error(espMqttClientTypes::Error::SUCCESS);
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.emplaceFront(0, error, std::forward<Args>(args)...);
if (it && error == espMqttClientTypes::Error::SUCCESS)
return true;
return false;
}
template <typename... Args>
bool _addPacket(Args&&... args) {
espMqttClientTypes::Error error(espMqttClientTypes::Error::SUCCESS);
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.emplace(0, error, std::forward<Args>(args) ...);
if (it && error == espMqttClientTypes::Error::SUCCESS) return true;
return false;
}
void _checkOutbox();
int _sendPacket();
bool _advanceOutbox();
void _checkIncoming();
void _checkPing();
void _checkTimeout();
template <typename... Args>
bool _addPacketFront(Args&&... args) {
espMqttClientTypes::Error error(espMqttClientTypes::Error::SUCCESS);
espMqttClientInternals::Outbox<OutgoingPacket>::Iterator it = _outbox.emplaceFront(0, error, std::forward<Args>(args) ...);
if (it && error == espMqttClientTypes::Error::SUCCESS) return true;
return false;
}
void _onConnack();
void _onPublish();
void _onPuback();
void _onPubrec();
void _onPubrel();
void _onPubcomp();
void _onSuback();
void _onUnsuback();
void _checkOutbox();
int _sendPacket();
bool _advanceOutbox();
void _checkIncoming();
void _checkPing();
void _checkTimeout();
void _clearQueue(int clearData); // 0: keep session,
// 1: keep only PUBLISH qos > 0
// 2: delete all
void _onError(uint16_t packetId, espMqttClientTypes::Error error);
void _onConnack();
void _onPublish();
void _onPuback();
void _onPubrec();
void _onPubrel();
void _onPubcomp();
void _onSuback();
void _onUnsuback();
void _clearQueue(int clearData); // 0: keep session,
// 1: keep only PUBLISH qos > 0
// 2: delete all
void _onError(uint16_t packetId, espMqttClientTypes::Error error);
#if defined(ARDUINO_ARCH_ESP32)
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
size_t _highWaterMark;
#endif
#endif
#if defined(ARDUINO_ARCH_ESP32)
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_INFO
size_t _highWaterMark;
#endif
#endif
};

View File

@@ -172,14 +172,14 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
}
bool MqttSettingsService::configureMqtt() {
// disconnect if connected
// disconnect if already connected
if (_mqttClient->connected()) {
emsesp::EMSESP::logger().info("Disconneting to configure");
emsesp::EMSESP::logger().info("Disconnecting to configure");
_mqttClient->disconnect(true);
}
// only connect if WiFi is connected and MQTT is enabled
if (_state.enabled && emsesp::EMSESP::system_.network_connected() && !_state.host.isEmpty()) {
// if (_state.enabled && !_state.host.isEmpty()) {
_reconfigureMqtt = false;
#if CONFIG_IDF_TARGET_ESP32S3
if (_state.rootCA.length() > 0) {
@@ -212,6 +212,7 @@ bool MqttSettingsService::configureMqtt() {
static_cast<espMqttClient *>(_mqttClient)->setCleanSession(_state.cleanSession);
return _mqttClient->connect();
}
return false;
}

View File

@@ -21,6 +21,10 @@
#include <stdio.h>
#include <stdarg.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <string>
#include <Network.h>
@@ -43,18 +47,34 @@ static unsigned long __millis = 0;
static bool __output_pins[256];
static int __output_level[256];
int main(int argc __attribute__((unused)), char * argv[] __attribute__((unused))) {
setup();
while (millis() <= 10 * 1000) {
std::atomic_bool exitProgram(false);
void ClientLoop(void * arg) {
(void)arg;
for (;;) {
loop();
if (exitProgram)
break;
}
return 0;
}
unsigned long millis() {
return __millis;
int main(int argc __attribute__((unused)), char * argv[] __attribute__((unused))) {
setup();
std::thread t = std::thread(ClientLoop, nullptr);
// while (millis() <= 10 * 1000) {
while (1) {
if (exitProgram)
break;
std::this_thread::yield();
}
t.join();
return EXIT_SUCCESS;
}
// unsigned long millis() {
// return __millis;
// }
int64_t esp_timer_get_time() {
return __millis;
}
@@ -64,6 +84,7 @@ void delay(unsigned long millis) {
}
void yield(void) {
std::this_thread::yield();
}
int snprintf_P(char * str, size_t size, const char * format, ...) {

View File

@@ -35,7 +35,7 @@
#include <iostream>
// #define IPAddress std::string
#define IPAddress String
// #define IPAddress String
#define ICACHE_FLASH_ATTR
#define ICACHE_RAM_ATTR
@@ -171,7 +171,13 @@ extern NativeConsole Serial;
extern ETHClass ETH;
extern WiFiClass WiFi;
unsigned long millis();
// unsigned long millis();
#if defined(__linux__)
#include <chrono> // NOLINT [build/c++11]
#include <thread> // NOLINT [build/c++11] for yield()
#define millis() std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count()
#endif
int64_t esp_timer_get_time();

View File

@@ -101,7 +101,10 @@ class ESP8266React {
: _settings(server, fs, nullptr)
, _securitySettingsService(server, fs){};
void begin(){};
void begin() {
// initialize mqtt
_mqttClient = new espMqttClient();
};
void loop(){};
SecurityManager * getSecurityManager() {
@@ -112,6 +115,11 @@ class ESP8266React {
return _mqttClient;
}
void setWill(const char * will_topic) {
}
void onMessage(espMqttClientTypes::OnMessageCallback callback) {
}
StatefulService<DummySettings> * getNetworkSettingsService() {
return &_settings;
}

View File

@@ -3,6 +3,7 @@
#include <Arduino.h>
#include <functional>
#include <IPAddress.h>
#define WiFiMode_t wifi_mode_t
#define WIFI_OFF WIFI_MODE_NULL

View File

View File

@@ -1,130 +0,0 @@
#ifndef ESPMQTTCLIENT_H_
#define ESPMQTTCLIENT_H_
#include "Arduino.h"
#include <functional>
namespace espMqttClientTypes {
enum class DisconnectReason : uint8_t {
USER_OK = 0,
MQTT_UNACCEPTABLE_PROTOCOL_VERSION = 1,
MQTT_IDENTIFIER_REJECTED = 2,
MQTT_SERVER_UNAVAILABLE = 3,
MQTT_MALFORMED_CREDENTIALS = 4,
MQTT_NOT_AUTHORIZED = 5,
TLS_BAD_FINGERPRINT = 6,
TCP_DISCONNECTED = 7
};
const char * disconnectReasonToString(DisconnectReason reason);
enum class SubscribeReturncode : uint8_t { QOS0 = 0x00, QOS1 = 0x01, QOS2 = 0x02, FAIL = 0X80 };
const char * subscribeReturncodeToString(SubscribeReturncode returnCode);
enum class Error : uint8_t { SUCCESS = 0, OUT_OF_MEMORY = 1, MAX_RETRIES = 2, MALFORMED_PARAMETER = 3, MISC_ERROR = 4 };
const char * errorToString(Error error);
struct MessageProperties {
uint8_t qos;
bool dup;
bool retain;
uint16_t packetId;
};
typedef std::function<void(bool sessionPresent)> OnConnectCallback;
typedef std::function<void(DisconnectReason reason)> OnDisconnectCallback;
typedef std::function<void(uint16_t packetId, const SubscribeReturncode * returncodes, size_t len)> OnSubscribeCallback;
typedef std::function<void(uint16_t packetId)> OnUnsubscribeCallback;
typedef std::function<void(const MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total)> OnMessageCallback;
typedef std::function<void(uint16_t packetId)> OnPublishCallback;
typedef std::function<size_t(uint8_t * data, size_t maxSize, size_t index)> PayloadCallback;
typedef std::function<void(uint16_t packetId, Error error)> OnErrorCallback;
} // namespace espMqttClientTypes
class espMqttClient {
public:
espMqttClient();
~espMqttClient();
espMqttClient & setKeepAlive(uint16_t keepAlive);
espMqttClient & setClientId(const char * clientId);
espMqttClient & setCleanSession(bool cleanSession);
espMqttClient & setMaxTopicLength(uint16_t maxTopicLength);
espMqttClient & setCredentials(const char * username, const char * password = nullptr);
espMqttClient & setWill(const char * topic, uint8_t qos, bool retain, const char * payload = nullptr, size_t length = 0) {
return *this;
}
espMqttClient & setServer(IPAddress ip, uint16_t port);
espMqttClient & setServer(const char * host, uint16_t port);
espMqttClient & onConnect(espMqttClientTypes::OnConnectCallback callback) {
return *this;
}
espMqttClient & onDisconnect(espMqttClientTypes::OnDisconnectCallback callback) {
return *this;
}
espMqttClient & onSubscribe(espMqttClientTypes::OnSubscribeCallback callback) {
return *this;
}
espMqttClient & onUnsubscribe(espMqttClientTypes::OnUnsubscribeCallback callback) {
return *this;
}
espMqttClient & onMessage(espMqttClientTypes::OnMessageCallback callback) {
return *this;
}
espMqttClient & onPublish(espMqttClientTypes::OnPublishCallback callback) {
return *this;
}
bool connected() const {
return false;
}
void connect() {
}
void disconnect(bool force = false) {
}
uint16_t subscribe(const char * topic, uint8_t qos) {
return 1;
}
uint16_t unsubscribe(const char * topic) {
return 1;
}
uint16_t publish(const char * topic, uint8_t qos, bool retain, const char * payload = nullptr, size_t length = 0, bool dup = false, uint16_t message_id = 0) {
return 1;
}
const char * getClientId() {
return "12";
}
uint16_t getQueue() const {
return 0;
}
private:
bool _connected;
bool _connectPacketNotEnoughSpace;
bool _disconnectOnPoll;
bool _tlsBadFingerprint;
uint32_t _lastClientActivity;
uint32_t _lastServerActivity;
uint32_t _lastPingRequestTime;
char _generatedClientId[18 + 1]; // esp8266-abc123 and esp32-abcdef123456
IPAddress _ip;
const char * _host;
bool _useIp;
uint16_t _port;
uint16_t _keepAlive;
bool _cleanSession;
const char * _clientId;
const char * _username;
const char * _password;
const char * _willTopic;
const char * _willPayload;
uint16_t _willPayloadLength;
uint8_t _willQos;
bool _willRetain;
};
#endif

View File

@@ -13,10 +13,16 @@
; -DEMSESP_EN_ONLY ; only EN translated entity names
; my_build_flags = -DEMSESP_DEBUG
[platformio]
default_envs = esp32_4M
; default_envs = esp32_16M
; default_envs = lolin_s3
; default_envs = standalone
[env:esp32_4M]
; if using OTA enter your details below
; upload_protocol = espota
; upload_flags =
; upload_flags =
; --port=8266
; --auth=ems-esp-neo
; upload_port = ems-esp.local
@@ -25,19 +31,20 @@ upload_port = /dev/ttyUSB*
; upload_port = COM5
; override arduino espressif core
; platform = espressif32 ; take latest
; platform = espressif32@5.2.0
platform = espressif32 ; take latest
; platform = espressif32@5.3.0
extra_scripts =
pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time
scripts/rename_fw.py
; post:scripts/app-tls-size.py
[env:esp32_16M]
upload_port = /dev/ttyUSB*
; upload_port = COM3
[env:lolin_s3]
upload_port = /dev/ttyACM0
extra_scripts =
; pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time
pre:scripts/build_interface.py ; comment out if you don't want to re-build the WebUI each time
scripts/rename_fw.py
; pio run -e debug

View File

@@ -20,7 +20,6 @@ core_build_flags =
; -std=gnu++17
; core_unbuild_flags = -std=gnu++11
; core_unbuild_flags = -std=gnu++17
core_unbuild_flags =
; my_build_flags is set in pio_local.ini
@@ -41,9 +40,12 @@ unbuild_flags =
[espressi32_base]
platform = espressif32
; platform = espressif32@5.3.0
; platform = espressif32@5.2.0
framework = arduino
build_flags = ${common.build_flags}
build_unflags = ${common.unbuild_flags}
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
[env]
monitor_speed = 115200
@@ -62,7 +64,7 @@ check_flags =
; build for GitHub Actions CI
; the Web interface is built seperately
[env:ci]
platform = espressif32@5.2.0
platform = espressif32
framework = arduino
extra_scripts = scripts/rename_fw.py
board = esp32dev
@@ -84,99 +86,69 @@ build_flags = ${common.build_flags} -O2
build_unflags = ${common.unbuild_flags}
[env:esp32_4M]
platform = espressif32@5.2.0
framework = arduino
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
extends = espressi32_base
board = esp32dev
board_upload.flash_size = 4MB
board_build.partitions = esp32_partition_4M.csv
build_flags = ${common.build_flags} -Os
build_unflags = ${common.unbuild_flags}
[env:esp32_4Mplus]
extends = espressi32_base
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
board = esp32dev
board_upload.flash_size = 4MB
board_build.partitions = esp32_asym_partition_4M.csv
build_flags = ${common.build_flags}
build_unflags = ${common.unbuild_flags}
[env:esp32_16M]
extends = espressi32_base
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
board = esp32dev
board_upload.flash_size = 16MB
board_build.partitions = esp32_partition_16M.csv
build_flags = ${common.build_flags}
build_unflags = ${common.unbuild_flags}
[env:lolin_c3_mini]
extends = espressi32_base
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
board = lolin_c3_mini
board_upload.flash_size = 4MB
board_build.partitions = esp32_asym_partition_4M.csv
build_flags = ${common.build_flags}
build_unflags = ${common.unbuild_flags}
; lolin C3 mini v1 needs special wifi init.
; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
[env:lolin_c3_mini_v1]
extends = espressi32_base
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
board = lolin_c3_mini
board_upload.flash_size = 4MB
board_build.partitions = esp32_asym_partition_4M.csv
build_flags = ${common.build_flags} -DBOARD_C3_MINI_V1
build_unflags = ${common.unbuild_flags}
[env:lolin_s2_mini]
extends = espressi32_base
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
board = lolin_s2_mini
board_upload.flash_size = 4MB
board_build.partitions = esp32_asym_partition_4M.csv
build_flags = ${common.build_flags}
build_unflags = ${common.unbuild_flags}
[env:lolin_s3]
extends = espressi32_base
extra_scripts =
pre:scripts/build_interface.py
scripts/rename_fw.py
board = lolin_s3
board_build.f_cpu = 240000000L
board_upload.flash_size = 16MB
board_build.partitions = esp32_partition_16M.csv
build_flags = ${common.build_flags} -O2
build_unflags = ${common.unbuild_flags}
board_upload.use_1200bps_touch = false
board_upload.wait_for_upload_port = false
build_flags = ${common.build_flags} -O2
; to build and run: pio run -e standalone -t exec
[env:standalone]
platform = native
build_flags =
-DARDUINO
-DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
-DARDUINOJSON_ENABLE_STD_STRING=1 -DARDUINOJSON_ENABLE_PROGMEM=1 -DARDUINOJSON_ENABLE_ARDUINO_STRING -DARDUINOJSON_USE_DOUBLE=0
-DEMSESP_DEBUG -DEMSESP_STANDALONE -DEMSESP_TEST
-DEMSESP_DEFAULT_LOCALE=\"en\" -DEMSESP_DEFAULT_TX_MODE=8 -DEMSESP_DEFAULT_VERSION=\"3.6.0-dev\" -DEMSESP_DEFAULT_BOARD_PROFILE=\"S32\"
-lpthread
-std=gnu++11 -Og -ggdb
build_src_flags =
build_src_flags =
-Wall -Wextra -Werror -Wswitch-enum -Wno-unused-parameter -Wno-inconsistent-missing-override -Wno-unused-lambda-capture
-I./lib_standalone
-I./lib/ArduinoJson/src
@@ -185,6 +157,8 @@ build_src_flags =
-I./lib/uuid-log/src
-I./lib/semver
-I./lib/PButton
-I./lib/espMqttClient/src
-I./lib/espMqttClient/src/Transport
build_src_filter =
+<*>
-<.git/>
@@ -194,5 +168,7 @@ build_src_filter =
+<../lib/uuid-log>
+<../lib/semver>
+<../lib/PButton>
+<../lib/espMqttClient/src>
+<../lib/espMqttClient/src/Transport>
lib_compat_mode = off
lib_ldf_mode = off

View File

@@ -498,7 +498,7 @@ void AnalogSensor::publish_values(const bool force) {
config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + " else " + sample_val + "}}";
char uniq_s[70];
if (Mqtt::entity_format() == Mqtt::entitiyFormat::MULTI_SHORT) {
if (Mqtt::entity_format() == Mqtt::entityFormat::MULTI_SHORT) {
snprintf(uniq_s, sizeof(uniq_s), "%s_analogsensor_%02d", Mqtt::basename().c_str(), sensor.gpio());
} else {
snprintf(uniq_s, sizeof(uniq_s), "analogsensor_%02d", sensor.gpio());

View File

@@ -1139,8 +1139,8 @@ void Thermostat::process_RC300Settings(std::shared_ptr<const Telegram> telegram)
// 0x2CC - e.g. wwprio for RC310 hcx parameter
void Thermostat::process_RC300Set2(std::shared_ptr<const Telegram> telegram) {
// typeids are not in a raw. hc:0x2CC, hc2: 0x2CE for RC310
// telegram is either offset 3 with data lenght of 1 and values 0/1 (radiators) - 10 0B FF 03 01 CC 01 F6
// or offset 0 with data lenght of 6 bytes - offset 3 values are 0x00 or 0xFF - 10 0B FF 00 01 CE FF 13 0A FF 1E 00 20
// telegram is either offset 3 with data length of 1 and values 0/1 (radiators) - 10 0B FF 03 01 CC 01 F6
// or offset 0 with data length of 6 bytes - offset 3 values are 0x00 or 0xFF - 10 0B FF 00 01 CE FF 13 0A FF 1E 00 20
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
if (hc == nullptr) {
@@ -2727,7 +2727,7 @@ bool Thermostat::set_controlmode(const char * value, const int8_t id) {
return false;
}
// sets the thermostat time for nightmode for RC10, telegrm 0xB0
// sets the thermostat time for nightmode for RC10, telegram 0xB0
bool Thermostat::set_reducehours(const char * value, const int8_t id) {
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);

View File

@@ -28,7 +28,7 @@
#include <uuid/log.h>
// forward declarators
// forward declarator
// used to bind EMS-ESP functions to external frameworks
namespace emsesp {
class EMSESP {

View File

@@ -315,7 +315,7 @@ void Mqtt::show_topic_handlers(uuid::console::Shell & shell, const uint8_t devic
// called when an MQTT Publish ACK is received
void Mqtt::on_publish(uint16_t packetId) const {
LOG_DEBUG("Packet %d sent successfull", packetId);
LOG_DEBUG("Packet %d sent successful", packetId);
}
// called when MQTT settings have changed via the Web forms
@@ -393,12 +393,6 @@ void Mqtt::start() {
[this](const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total) {
on_message(topic, (const char *)payload, len); // receiving mqtt
});
/*
mqttClient_->onPublish([this](uint16_t packetId) {
on_publish(packetId); // publish
});
*/
}
void Mqtt::set_publish_time_boiler(uint16_t publish_time) {
@@ -527,7 +521,7 @@ void Mqtt::ha_status() {
StaticJsonDocument<EMSESP_JSON_SIZE_LARGE> doc;
char uniq[70];
if (Mqtt::entity_format() == entitiyFormat::MULTI_SHORT) {
if (Mqtt::entity_format() == entityFormat::MULTI_SHORT) {
snprintf(uniq, sizeof(uniq), "%s_system_status", mqtt_basename_.c_str());
} else {
strcpy(uniq, "system_status");
@@ -588,9 +582,10 @@ void Mqtt::ha_status() {
// add sub or pub task to the queue.
// the base is not included in the topic
bool Mqtt::queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain) {
if (topic.empty()) {
return false;
if (!mqtt_enabled_ || topic.empty()) {
return false; // quit, not using MQTT
}
uint16_t packet_id = 0;
char fulltopic[MQTT_TOPIC_MAX_SIZE];
@@ -804,10 +799,10 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev
// build unique identifier also used as object_id which also becomes the Entity ID in HA
char uniq_id[80];
if (Mqtt::entity_format() == entitiyFormat::MULTI_SHORT) {
if (Mqtt::entity_format() == entityFormat::MULTI_SHORT) {
// prefix base name to each uniq_id and use the shortname
snprintf(uniq_id, sizeof(uniq_id), "%s_%s_%s", mqtt_basename_.c_str(), device_name, entity_with_tag);
} else if (Mqtt::entity_format() == entitiyFormat::SINGLE_SHORT) {
} else if (Mqtt::entity_format() == entityFormat::SINGLE_SHORT) {
// shortname, no mqtt base. This is the default version.
snprintf(uniq_id, sizeof(uniq_id), "%s_%s", device_name, entity_with_tag);
} else {
@@ -1171,7 +1166,7 @@ bool Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp,
snprintf(name_s, sizeof(name_s), "Hc%d", hc_num);
if (Mqtt::entity_format() == entitiyFormat::MULTI_SHORT) {
if (Mqtt::entity_format() == entityFormat::MULTI_SHORT) {
snprintf(uniq_id_s, sizeof(uniq_id_s), "%s_thermostat_hc%d", mqtt_basename_.c_str(), hc_num); // add basename
} else {
snprintf(uniq_id_s, sizeof(uniq_id_s), "thermostat_hc%d", hc_num); // backward compatible with v3.4

View File

@@ -36,7 +36,7 @@ using mqtt_sub_function_p = std::function<bool(const char * message)>;
class Mqtt {
public:
enum discoveryType : uint8_t { HOMEASSISTANT, DOMOTICZ };
enum entitiyFormat : uint8_t { SINGLE_LONG, SINGLE_SHORT, MULTI_SHORT };
enum entityFormat : uint8_t { SINGLE_LONG, SINGLE_SHORT, MULTI_SHORT };
void loop();
void start();
@@ -104,11 +104,7 @@ class Mqtt {
#endif
static bool connected() {
#if defined(EMSESP_STANDALONE)
return true;
#else
return mqttClient_->connected();
#endif
}
static MqttClient * client() {

View File

@@ -155,7 +155,7 @@ void Shower::set_shower_state(bool state, bool force) {
doc["name"] = "Shower Active";
char str[70];
if (Mqtt::entity_format() == Mqtt::entitiyFormat::MULTI_SHORT) {
if (Mqtt::entity_format() == Mqtt::entityFormat::MULTI_SHORT) {
snprintf(str, sizeof(str), "%s_shower_active", Mqtt::basename().c_str());
} else {
snprintf(str, sizeof(str), "shower_active"); // v3.4 compatible

View File

@@ -536,7 +536,7 @@ void System::loop() {
// send MQTT info topic appended with the version information as JSON, as a retained flag
void System::send_info_mqtt(const char * event_str, bool send_ntp) {
// use dynamic json becaues it is called from NTP-callback from lwip task with small stack
// use dynamic json because it is called from NTP-callback from lwip task with small stack
DynamicJsonDocument doc = DynamicJsonDocument(EMSESP_JSON_SIZE_MEDIUM);
doc["event"] = event_str;
doc["version"] = EMSESP_APP_VERSION;
@@ -1503,7 +1503,7 @@ std::string System::reset_reason(uint8_t cpu) const {
break;
}
#endif
return ("Unkonwn");
return ("Unknown");
}
#pragma GCC diagnostic pop

View File

@@ -528,7 +528,7 @@ void TemperatureSensor::publish_values(const bool force) {
config["val_tpl"] = (std::string) "{{" + val_obj + " if " + val_cond + " else -55}}";
char uniq_s[70];
if (Mqtt::entity_format() == Mqtt::entitiyFormat::MULTI_SHORT) {
if (Mqtt::entity_format() == Mqtt::entityFormat::MULTI_SHORT) {
snprintf(uniq_s, sizeof(uniq_s), "%s_temperaturesensor_%s", Mqtt::basename().c_str(), sensor.id().c_str());
} else {
snprintf(uniq_s, sizeof(uniq_s), "temperaturesensor_%s", sensor.id().c_str());

View File

@@ -1001,14 +1001,14 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
EMSESP::mqtt_.incoming("ems-esp/thermostat/hc2/mode", "auto");
EMSESP::mqtt_.incoming("ems-esp/thermostat/wwc3/mode", "auto");
EMSESP::mqtt_.incoming("ems-esp/boiler/wwcircpump", "off");
EMSESP::mqtt_.incoming("ems-esp/thermostat/seltemp"); // empty payload, sends reponse
EMSESP::mqtt_.incoming("ems-esp/thermostat/seltemp"); // empty payload
EMSESP::mqtt_.incoming("ems-esp/thermostat_hc1", "22"); // HA only
EMSESP::mqtt_.incoming("ems-esp/thermostat_hc1", "off"); // HA only
EMSESP::mqtt_.incoming("ems-esp/system/send", "11 12 13");
EMSESP::mqtt_.incoming("ems-esp/boiler/syspress"); // empty payload, sends reponse
EMSESP::mqtt_.incoming("ems-esp/thermostat/mode"); // empty payload, sends reponse
EMSESP::mqtt_.incoming("ems-esp/boiler/syspress"); // empty payload
EMSESP::mqtt_.incoming("ems-esp/thermostat/mode"); // empty payload
EMSESP::mqtt_.incoming("ems-esp/system/publish");
EMSESP::mqtt_.incoming("ems-esp/thermostat/seltemp"); // empty payload, sends reponse
EMSESP::mqtt_.incoming("ems-esp/thermostat/seltemp"); // empty payload
EMSESP::mqtt_.incoming("ems-esp/boiler/wwseltemp", "59");
EMSESP::mqtt_.incoming("ems-esp/boiler/wwseltemp");
@@ -1022,7 +1022,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// check extended MQTT base
Mqtt::base("home/cellar/heating");
EMSESP::mqtt_.incoming("home/cellar/heating/thermostat/mode"); // empty payload, sends reponse
EMSESP::mqtt_.incoming("home/cellar/heating/thermostat/mode"); // empty payload
// Web API TESTS
AsyncWebServerRequest request;

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.6.0-dev.13c"
#define EMSESP_APP_VERSION "3.6.0-dev.13d"

View File

@@ -30,7 +30,7 @@ WebEntityService::WebEntityService(AsyncWebServer * server, FS * fs, SecurityMan
// load the settings when the service starts
void WebEntityService::begin() {
_fsPersistence.readFromFS();
EMSESP::logger().info("Starting custom entity service");
EMSESP::logger().info("Starting Custom entity service");
}
// this creates the entity file, saving it to the FS

View File

@@ -50,7 +50,7 @@ void WebScheduler::read(WebScheduler & webScheduler, JsonObject & root) {
}
}
// call on initialization and also when the Scheduile web page is saved
// call on initialization and also when the Schedule web page is saved
// this loads the data into the internal class
StateUpdateResult WebScheduler::update(JsonObject & root, WebScheduler & webScheduler) {
#ifdef EMSESP_STANDALONE

View File

@@ -229,7 +229,7 @@ const char * WebStatusService::disconnectReason(uint8_t code) {
#ifndef EMSESP_STANDALONE
switch (code) {
case WIFI_REASON_UNSPECIFIED: // = 1,
return "unspecifiied";
return "unspecified";
case WIFI_REASON_AUTH_EXPIRE: // = 2,
return "auth expire";
case WIFI_REASON_AUTH_LEAVE: // = 3,
@@ -239,9 +239,9 @@ const char * WebStatusService::disconnectReason(uint8_t code) {
case WIFI_REASON_ASSOC_TOOMANY: // = 5,
return "assoc too many";
case WIFI_REASON_NOT_AUTHED: // = 6,
return "not authed";
return "not authenticated";
case WIFI_REASON_NOT_ASSOCED: // = 7,
return "not assoced";
return "not assoc";
case WIFI_REASON_ASSOC_LEAVE: // = 8,
return "assoc leave";
case WIFI_REASON_ASSOC_NOT_AUTHED: // = 9,