mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
1.9.5 - Merge remote-tracking branch 'origin/dev'
This commit is contained in:
@@ -37,3 +37,5 @@ SpaceAfterCStyleCast: false
|
|||||||
SpaceBeforeAssignmentOperators: true
|
SpaceBeforeAssignmentOperators: true
|
||||||
SpacesInCStyleCastParentheses: false
|
SpacesInCStyleCastParentheses: false
|
||||||
SpacesInParentheses: false
|
SpacesInParentheses: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
SortIncludes: false
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -18,3 +18,6 @@ node_modules
|
|||||||
# project specfic
|
# project specfic
|
||||||
scripts/stackdmp.txt
|
scripts/stackdmp.txt
|
||||||
firmware
|
firmware
|
||||||
|
|
||||||
|
# firmware
|
||||||
|
*.bin
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
os: linux
|
os: linux
|
||||||
|
dist: bionic
|
||||||
language: python
|
language: python
|
||||||
python:
|
python:
|
||||||
- "2.7"
|
- "3.8"
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
@@ -55,6 +56,7 @@ before_deploy:
|
|||||||
deploy:
|
deploy:
|
||||||
provider: releases
|
provider: releases
|
||||||
edge:
|
edge:
|
||||||
|
# source: wenkokke/dpl
|
||||||
branch: master
|
branch: master
|
||||||
token: ${GITHUB_TOKEN}
|
token: ${GITHUB_TOKEN}
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
|||||||
41
CHANGELOG.md
41
CHANGELOG.md
@@ -5,7 +5,46 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [1.9.4] 2019-12-15
|
## [1.9.5] 30-04-2020
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Solar Module SM200 support
|
||||||
|
- Support writing to Junkers FR100 thermostats
|
||||||
|
- Support writing to RC100, Moduline 1000/1010 thermostats
|
||||||
|
- MM10 Mixing module support (thanks @MichaelDvP)
|
||||||
|
- MM200 warm water circuits (https://github.com/proddy/EMS-ESP/pull/315)
|
||||||
|
- Support for Moduline 200 and Sieger ES72 thermostats
|
||||||
|
- First implementation of writing to generic Junker Thermostats (thanks @Neonox31)
|
||||||
|
- Added model type (Buderus, Sieger, Junkers, Nefit, Bosch, Worcester) to device names
|
||||||
|
- `set master_thermostat <product id>` to choose with thermostat is master when there are multiple on the bus
|
||||||
|
- `boiler wwonetime` command from Telnet
|
||||||
|
- `set bus_id <ID>` to support multiple EMS-ESP circuits. Default is 0x0B to mimic a service key.
|
||||||
|
- `mqtt_nestedjson` option to disable multiple data records being nested into a single JSON string
|
||||||
|
- MQTT publish messages are queued and gracefully published every second to avoid TCP blocks
|
||||||
|
- Added features to WW messages (0x33, 0x34) to improve WW monitoring. (PR#338 by @ypaindaveine)
|
||||||
|
- Added mixing log and stub for EMS type 0xAC (PR#338 by @ypaindaveine)
|
||||||
|
- Added Thermostat retrieving settings (0xA5) (validated on RC30N) with MQTT support (thanks Yves @ypaindaveine. See #352)
|
||||||
|
- Merged with PR https://github.com/proddy/EMS-ESP/pull/366 from @MichaelDvP fixing RC20 and MM50
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- set boiler warm water temp on Junkers/Bosch HT3
|
||||||
|
- fixed detection of the Moduline 400 thermostat
|
||||||
|
- RC35 setting temperature also forces the current select temp to change, irrespective of the mode
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- improved MQTT publishing to stop network flooding. `publish_time` of -1 is no publish, 0 is automatic otherwise its a time interval
|
||||||
|
- External sensors (like Dallas DS18*) are sent as a nested MQTT topic including their unqiue identifier
|
||||||
|
- `mqttlog` console command renamed to `mqttqueue` to only show the current publish queue
|
||||||
|
- `status` payload on start-up shows the IP and Version of EMS-ESP
|
||||||
|
- `thermostat mode` takes a string like manual,auto,heat,day,night,eco,comfort,holiday,nofrost
|
||||||
|
- `thermostat temp` also takes a mode string, e.g. `thermostat temp 20 heat`
|
||||||
|
- `queue` renamed to `txqueue`
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- `autodetect scan`. Replaced with `devices scan` and `devices scan+` for deep scanning
|
||||||
|
- `mqttlog all` and showing MQTT log in the web interface - no point showing history of previous mqtt publishes in ESP's precious memory. For debugging I recommend using MQTT Explorer or another external tool.
|
||||||
|
|
||||||
|
## [1.9.4] 15-12-2019
|
||||||
|
|
||||||
There are breaking changes in this release. Make you sure you adjust the MQTT topics as described in the wiki.
|
There are breaking changes in this release. Make you sure you adjust the MQTT topics as described in the wiki.
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ EMS-ESP is a open-source system built for the Espressif ESP8266 microcontroller
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Supporting more than [50 EMS devices](https://emsesp.github.io/docs/#/Supported-EMS-Devices) (EMS 1, EMS+/2.0 and Heatronics 3).
|
* Supporting more than [50 EMS devices](https://emsesp.github.io/docs/#/Supported-EMS-Devices) (EMS 1, EMS 2.0/Plus and Heatronics 3).
|
||||||
* A web interface for easy configuration and real-time monitoring of the EMS bus.
|
* A web interface for easy configuration and real-time monitoring of the EMS bus.
|
||||||
* Telnet for advanced configuration and verbose traffic logging.
|
* Telnet for advanced configuration and verbose traffic logging.
|
||||||
* Configurable MQTT, with templates for Home Assistant and Domoticz.
|
* Configurable MQTT, with templates for Home Assistant and Domoticz.
|
||||||
|
|||||||
@@ -4,16 +4,23 @@
|
|||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
default_envs = release
|
default_envs = release
|
||||||
;default_envs = debug
|
; default_envs = debug
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
|
# From https://github.com/esp8266/Arduino/blob/master/tools/sdk/ld
|
||||||
|
# eagle.flash.4m1m.ld = 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer
|
||||||
|
# eagle.flash.4m2m.ld = same as above but with 2024 KB SPIFFS
|
||||||
|
# eagle.flash.4m.ld = same as above but with no SPIFFS storage
|
||||||
|
ldscript = eagle.flash.4m1m.ld
|
||||||
|
|
||||||
; custom build options are:
|
; custom build options are:
|
||||||
; -DMYESP_TIMESTAMP
|
; -DMYESP_TIMESTAMP
|
||||||
; -DTESTS
|
; -DTESTS
|
||||||
; -DCRASH
|
; -DCRASH
|
||||||
; -DFORCE_SERIAL
|
; -DFORCE_SERIAL
|
||||||
; -DMYESP_DEBUG
|
; -DMYESP_DEBUG
|
||||||
;custom_flags = -DFORCE_SERIAL -DMYESP_DEBUG
|
; -DSENSOR_MQTT_USEID
|
||||||
|
; custom_flags = -DFORCE_SERIAL -DMYESP_DEBUG -DEMSESP_SIMULATE
|
||||||
custom_flags =
|
custom_flags =
|
||||||
|
|
||||||
# Available lwIP variants (macros):
|
# Available lwIP variants (macros):
|
||||||
@@ -26,33 +33,28 @@ custom_flags =
|
|||||||
# -DVTABLES_IN_FLASH
|
# -DVTABLES_IN_FLASH
|
||||||
# -DNO_GLOBAL_EEPROM
|
# -DNO_GLOBAL_EEPROM
|
||||||
# -DBEARSSL_SSL_BASIC
|
# -DBEARSSL_SSL_BASIC
|
||||||
|
# general_flags = -DNO_GLOBAL_EEPROM -DVTABLES_IN_FLASH -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH
|
||||||
general_flags = -DNO_GLOBAL_EEPROM
|
general_flags = -DNO_GLOBAL_EEPROM
|
||||||
|
|
||||||
# From https://github.com/esp8266/Arduino/blob/master/tools/sdk/ld
|
build_flags = ${common.general_flags} -std=c++11 -fno-exceptions
|
||||||
# eagle.flash.4m1m.ld = 1019 KB sketch, 1000 KB SPIFFS. 4KB EEPROM, 4KB RFCAL, 12KB WIFI stack, 2052 KB OTA & buffer
|
|
||||||
# eagle.flash.4m2m.ld = same as above but with 2024 KB SPIFFS
|
|
||||||
# eagle.flash.4m.ld = same as above but with no SPIFFS storage
|
|
||||||
build_flags_4m1m = -Wl,-Teagle.flash.4m1m.ld
|
|
||||||
build_flags = ${common.general_flags} ${common.build_flags_4m1m}
|
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
framework = arduino
|
framework = arduino
|
||||||
;platform = espressif8266@2.2.2 ; arduino core 2.5.2
|
|
||||||
platform = espressif8266
|
platform = espressif8266
|
||||||
;platform = https://github.com/platformio/platform-espressif8266#develop
|
board_build.ldscript = ${common.ldscript}
|
||||||
;platform = https://github.com/platformio/platform-espressif8266#feature/stage
|
lib_compat_mode = strict
|
||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/rlogiacco/CircularBuffer
|
https://github.com/rlogiacco/CircularBuffer
|
||||||
https://github.com/PaulStoffregen/OneWire
|
https://github.com/PaulStoffregen/OneWire
|
||||||
https://github.com/me-no-dev/ESPAsyncWebServer
|
https://github.com/me-no-dev/ESPAsyncWebServer
|
||||||
https://github.com/me-no-dev/ESPAsyncUDP
|
https://github.com/me-no-dev/ESPAsyncUDP
|
||||||
uuid-common@^1.1.0
|
uuid-common@^1.1.0
|
||||||
uuid-log@^2.1.1
|
uuid-log@^2.1.1
|
||||||
uuid-syslog@^2.0.4 ; https://github.com/nomis/mcu-uuid-syslog
|
uuid-syslog@^2.0.4 ; https://github.com/nomis/mcu-uuid-syslog
|
||||||
JustWifi@2.0.2 ; https://github.com/xoseperez/justwifi
|
JustWifi@2.0.2 ; https://github.com/xoseperez/justwifi
|
||||||
AsyncMqttClient@0.8.2 ; https://github.com/marvinroger/async-mqtt-client
|
AsyncMqttClient@0.8.2 ; https://github.com/marvinroger/async-mqtt-client
|
||||||
EEPROM_Rotate@0.9.2 ; https://github.com/xoseperez/eeprom_rotate
|
EEPROM_Rotate@0.9.2 ; https://github.com/xoseperez/eeprom_rotate
|
||||||
ArduinoJson@6.13.0 ; https://github.com/bblanchon/ArduinoJson
|
ArduinoJson
|
||||||
ESPAsyncTCP@1.2.2 ; https://github.com/me-no-dev/ESPAsyncTCP
|
ESPAsyncTCP@1.2.2 ; https://github.com/me-no-dev/ESPAsyncTCP
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
@@ -112,3 +114,4 @@ build_flags = ${common.build_flags} ${common.custom_flags}
|
|||||||
extra_scripts =
|
extra_scripts =
|
||||||
pre:scripts/pre_script.py
|
pre:scripts/pre_script.py
|
||||||
scripts/main_script.py
|
scripts/main_script.py
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ def clr(color, text):
|
|||||||
|
|
||||||
def remove_float_support():
|
def remove_float_support():
|
||||||
flags = " ".join(env['LINKFLAGS'])
|
flags = " ".join(env['LINKFLAGS'])
|
||||||
print(clr(Color.BLUE, "** LINKFLAGS = %ss" % flags))
|
print(clr(Color.BLUE, "LINKFLAGS = %ss" % flags))
|
||||||
flags = flags.replace("-u _printf_float", "")
|
flags = flags.replace("-u _printf_float", "")
|
||||||
flags = flags.replace("-u _scanf_float", "")
|
flags = flags.replace("-u _scanf_float", "")
|
||||||
newflags = flags.split()
|
newflags = flags.split()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Import("env")
|
|||||||
def build_web():
|
def build_web():
|
||||||
print("** Building web...")
|
print("** Building web...")
|
||||||
env.Execute(
|
env.Execute(
|
||||||
"node ./tools/webfilesbuilder/node_modules/gulp/bin/gulp.js --cwd ./tools/webfilesbuilder")
|
"node ./tools/webfilesbuilder/node_modules/gulp/bin/gulp.js --silent --cwd ./tools/webfilesbuilder")
|
||||||
|
|
||||||
def code_check(source, target, env):
|
def code_check(source, target, env):
|
||||||
print("** Starting cppcheck...")
|
print("** Starting cppcheck...")
|
||||||
|
|||||||
639
src/MyESP.cpp
639
src/MyESP.cpp
@@ -23,6 +23,15 @@ union system_rtcmem_t {
|
|||||||
uint32_t value;
|
uint32_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mqtt_message_t {
|
||||||
|
uint16_t packetId = 0;
|
||||||
|
char * topic = nullptr;
|
||||||
|
char * payload = nullptr;
|
||||||
|
bool retain = false;
|
||||||
|
uint8_t retry_count = 0;
|
||||||
|
};
|
||||||
|
std::deque<mqtt_message_t> _mqtt_queue;
|
||||||
|
|
||||||
// nasty global variables that are called from internal ws functions
|
// nasty global variables that are called from internal ws functions
|
||||||
static char * _general_password = nullptr;
|
static char * _general_password = nullptr;
|
||||||
static bool _shouldRestart = false;
|
static bool _shouldRestart = false;
|
||||||
@@ -74,10 +83,12 @@ MyESP::MyESP() {
|
|||||||
_mqtt_heartbeat = false;
|
_mqtt_heartbeat = false;
|
||||||
_mqtt_keepalive = MQTT_KEEPALIVE;
|
_mqtt_keepalive = MQTT_KEEPALIVE;
|
||||||
_mqtt_qos = MQTT_QOS;
|
_mqtt_qos = MQTT_QOS;
|
||||||
|
_mqtt_nestedjson = false;
|
||||||
_mqtt_retain = MQTT_RETAIN;
|
_mqtt_retain = MQTT_RETAIN;
|
||||||
_mqtt_will_topic = strdup(MQTT_WILL_TOPIC);
|
_mqtt_will_topic = strdup(MQTT_WILL_TOPIC);
|
||||||
_mqtt_will_online_payload = strdup(MQTT_WILL_ONLINE_PAYLOAD);
|
_mqtt_will_online_payload = strdup(MQTT_WILL_ONLINE_PAYLOAD);
|
||||||
_mqtt_will_offline_payload = strdup(MQTT_WILL_OFFLINE_PAYLOAD);
|
_mqtt_will_offline_payload = strdup(MQTT_WILL_OFFLINE_PAYLOAD);
|
||||||
|
_mqtt_publish_fails = 0; // count of number of failed MQTT topic publishes
|
||||||
|
|
||||||
// network
|
// network
|
||||||
_network_password = nullptr;
|
_network_password = nullptr;
|
||||||
@@ -110,14 +121,6 @@ MyESP::MyESP() {
|
|||||||
|
|
||||||
// get the build time
|
// get the build time
|
||||||
_buildTime = _getBuildTime();
|
_buildTime = _getBuildTime();
|
||||||
|
|
||||||
// MQTT log
|
|
||||||
for (uint8_t i = 0; i < MYESP_MQTTLOG_MAX; i++) {
|
|
||||||
MQTT_log[i].type = 0;
|
|
||||||
MQTT_log[i].timestamp = 0;
|
|
||||||
MQTT_log[i].topic = nullptr;
|
|
||||||
MQTT_log[i].payload = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MyESP::~MyESP() {
|
MyESP::~MyESP() {
|
||||||
@@ -382,21 +385,17 @@ bool MyESP::mqttSubscribe(const char * topic) {
|
|||||||
if (mqttClient.connected() && (strlen(topic) > 0)) {
|
if (mqttClient.connected() && (strlen(topic) > 0)) {
|
||||||
char * topic_s = _mqttTopic(topic);
|
char * topic_s = _mqttTopic(topic);
|
||||||
|
|
||||||
uint16_t packet_id = mqttClient.subscribe(topic_s, _mqtt_qos);
|
|
||||||
#ifdef MYESP_DEBUG
|
#ifdef MYESP_DEBUG
|
||||||
myDebug_P(PSTR("[MQTT] Subscribing to %s"), topic_s);
|
myDebug_P(PSTR("[MQTT] Subscribing to %s"), topic_s);
|
||||||
#endif
|
#endif
|
||||||
|
uint16_t packet_id = mqttClient.subscribe(topic_s, _mqtt_qos);
|
||||||
if (packet_id) {
|
if (!packet_id) {
|
||||||
// add to mqtt log
|
|
||||||
_addMQTTLog(topic_s, "", MYESP_MQTTLOGTYPE_SUBSCRIBE); // Has an empty payload for now
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
myDebug_P(PSTR("[MQTT] Error subscribing to %s, error %d"), _mqttTopic(topic), packet_id);
|
myDebug_P(PSTR("[MQTT] Error subscribing to %s, error %d"), _mqttTopic(topic), packet_id);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // didn't work
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MQTT unsubscribe
|
// MQTT unsubscribe
|
||||||
@@ -407,30 +406,218 @@ void MyESP::mqttUnsubscribe(const char * topic) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish using the user's custom retain flag
|
// print MQTT log
|
||||||
bool MyESP::mqttPublish(const char * topic, const char * payload) {
|
void MyESP::_printMQTTQueue() {
|
||||||
// use the custom MQTT retain flag
|
myDebug_P(PSTR("MQTT publish queue:"));
|
||||||
return mqttPublish(topic, payload, _mqtt_retain);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MQTT Publish
|
if (_mqtt_queue.empty()) {
|
||||||
// returns true if all good
|
myDebug_P(PSTR(" queue is empty!"));
|
||||||
bool MyESP::mqttPublish(const char * topic, const char * payload, bool retain) {
|
myDebug_P(PSTR("")); // newline
|
||||||
if (mqttClient.connected() && (strlen(topic) > 0)) {
|
return;
|
||||||
#ifdef MYESP_DEBUG
|
}
|
||||||
myDebug_P(PSTR("[MQTT] Sending publish to %s with payload %s"), _mqttTopic(topic), payload);
|
|
||||||
#endif
|
|
||||||
uint16_t packet_id = mqttClient.publish(_mqttTopic(topic), _mqtt_qos, retain, payload);
|
|
||||||
|
|
||||||
if (packet_id) {
|
for (mqtt_message_t it : _mqtt_queue) {
|
||||||
_addMQTTLog(topic, payload, MYESP_MQTTLOGTYPE_PUBLISH); // add to the log
|
if (it.retry_count == 0) {
|
||||||
return true;
|
if (it.packetId == 0) {
|
||||||
|
myDebug_P(PSTR(" topic=%s payload=%s"), it.topic, it.payload);
|
||||||
|
} else {
|
||||||
|
myDebug_P(PSTR(" topic=%s payload=%s (pid %d)"), it.topic, it.payload, it.packetId);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
myDebug_P(PSTR("[MQTT] Error publishing to %s with payload %s [error %d]"), _mqttTopic(topic), payload, packet_id);
|
myDebug_P(PSTR(" topic=%s payload=%s (pid %d, retry #%d)"), it.topic, it.payload, it.packetId, it.retry_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // failed
|
myDebug_P(PSTR("")); // newline
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish using the user's custom retain flag
|
||||||
|
bool MyESP::mqttPublish(const char * topic, const char * payload) {
|
||||||
|
return (_mqttQueue(topic, payload, _mqtt_retain));
|
||||||
|
}
|
||||||
|
bool MyESP::mqttPublish(const char * topic, JsonDocument & payload) {
|
||||||
|
return (_mqttQueue(topic, payload, _mqtt_retain));
|
||||||
|
}
|
||||||
|
|
||||||
|
// MQTT Publish
|
||||||
|
bool MyESP::mqttPublish(const char * topic, const char * payload, bool retain) {
|
||||||
|
return (_mqttQueue(topic, payload, retain));
|
||||||
|
}
|
||||||
|
bool MyESP::mqttPublish(const char * topic, JsonDocument & payload, bool retain) {
|
||||||
|
return (_mqttQueue(topic, payload, retain));
|
||||||
|
}
|
||||||
|
|
||||||
|
// put a payload string into the queue
|
||||||
|
// can't have empty topic
|
||||||
|
// returns false if can't add to queue
|
||||||
|
bool MyESP::_mqttQueue(const char * topic, const char * payload, bool retain) {
|
||||||
|
if (!mqttClient.connected() || _mqtt_queue.size() >= MQTT_QUEUE_MAX_SIZE || !_hasValue(topic)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new message
|
||||||
|
mqtt_message_t element;
|
||||||
|
element.topic = strdup(topic);
|
||||||
|
element.retain = retain;
|
||||||
|
element.packetId = 0;
|
||||||
|
element.retry_count = 0;
|
||||||
|
if (payload != NULL) {
|
||||||
|
element.payload = strdup(payload);
|
||||||
|
}
|
||||||
|
#ifdef MYESP_DEBUG
|
||||||
|
myDebug_P(PSTR("[MQTT] Adding to queue: #%d [%s] %s"), _mqtt_queue.size(), element.topic, element.payload);
|
||||||
|
#endif
|
||||||
|
_mqtt_queue.push_back(element);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert json doc to a string buffer and place on queue
|
||||||
|
// can't have empty payload or topic
|
||||||
|
// returns false if can't add to queue
|
||||||
|
bool MyESP::_mqttQueue(const char * topic, JsonDocument & payload, bool retain) {
|
||||||
|
if (!mqttClient.connected() || _mqtt_queue.size() >= MQTT_QUEUE_MAX_SIZE || !_hasValue(topic)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for empty JSON doc - we don't like those
|
||||||
|
size_t capacity = measureJson(payload);
|
||||||
|
if (!capacity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new message
|
||||||
|
mqtt_message_t element;
|
||||||
|
element.topic = strdup(topic);
|
||||||
|
element.retain = retain;
|
||||||
|
element.packetId = 0;
|
||||||
|
element.retry_count = 0;
|
||||||
|
|
||||||
|
// reserve space for buffer and serialize json into it
|
||||||
|
capacity++; // add one more to cover the EOL
|
||||||
|
element.payload = (char *)malloc(capacity);
|
||||||
|
serializeJson(payload, (char *)element.payload, capacity);
|
||||||
|
|
||||||
|
#ifdef MYESP_DEBUG
|
||||||
|
myDebug_P(PSTR("[MQTT] Adding to queue: #%d [%s] %s"), _mqtt_queue.size(), element.topic, element.payload);
|
||||||
|
#endif
|
||||||
|
_mqtt_queue.push_back(element);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called when an MQTT Publish ACK is received
|
||||||
|
// check if ACK matches the last Publish we sent, if not report an error
|
||||||
|
// and always remove from queue
|
||||||
|
void MyESP::_mqttOnPublish(uint16_t packetId) {
|
||||||
|
#ifdef MYESP_DEBUG
|
||||||
|
myDebug_P(PSTR("[MQTT] Publish ACK for PID %d"), packetId);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// find the MQTT message in the queue and remove it
|
||||||
|
if ((_mqtt_queue.empty()) || (_mqtt_qos == 0)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mqtt_message_t element = _mqtt_queue.front(); // get top of list
|
||||||
|
|
||||||
|
// if the last published failed, don't bother checking it. wait for the re-try
|
||||||
|
if (element.packetId == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (element.packetId == packetId) {
|
||||||
|
#ifdef MYESP_DEBUG
|
||||||
|
myDebug_P(PSTR("[MQTT] Found PID %d. Removing from queue."), packetId);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef MYESP_DEBUG
|
||||||
|
myDebug_P(PSTR("[MQTT] Mismatch, expecting PID %d, got %d."), element.packetId, packetId);
|
||||||
|
_mqtt_publish_fails++; // increment error count
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
_mqttRemoveLastPublish(); // always remove
|
||||||
|
}
|
||||||
|
|
||||||
|
// removes top of queue
|
||||||
|
void MyESP::_mqttRemoveLastPublish() {
|
||||||
|
mqtt_message_t element = _mqtt_queue.front(); // get top of list
|
||||||
|
free(element.topic);
|
||||||
|
if (element.payload) {
|
||||||
|
free(element.payload);
|
||||||
|
}
|
||||||
|
_mqtt_queue.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
// take top from queue and try and publish it
|
||||||
|
void MyESP::_mqttPublishQueue() {
|
||||||
|
if ((!mqttClient.connected()) || (_mqtt_queue.empty())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mqtt_message_t element = _mqtt_queue.front(); // fetch from queue
|
||||||
|
|
||||||
|
// try and publish it
|
||||||
|
uint16_t packet_id = mqttClient.publish(_mqttTopic(element.topic), _mqtt_qos, element.retain, element.payload);
|
||||||
|
#ifdef MYESP_DEBUG
|
||||||
|
myDebug_P(PSTR("[MQTT] Sent publish (attempt #%d, pid %d) [%s] [%s]"), element.retry_count, packet_id, _mqttTopic(element.topic), element.payload);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (packet_id == 0) {
|
||||||
|
// it failed. if we retried n times, give up. remove from queue
|
||||||
|
if (element.retry_count == (MQTT_PUBLISH_MAX_RETRY - 1)) {
|
||||||
|
myDebug_P(PSTR("[MQTT] Failed to publish to %s with payload %s"), _mqttTopic(element.topic), element.payload);
|
||||||
|
_mqtt_publish_fails++; // increment failure counter
|
||||||
|
_mqttRemoveLastPublish();
|
||||||
|
} else {
|
||||||
|
_mqtt_queue[0].retry_count++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have ACK set with QOS 1 or 2, leave on queue and let the ACK process remove it
|
||||||
|
// but add the packet_id so we can check it later
|
||||||
|
if (_mqtt_qos != 0) {
|
||||||
|
_mqtt_queue[0].packetId = packet_id;
|
||||||
|
#ifdef MYESP_DEBUG
|
||||||
|
myDebug_P(PSTR("[MQTT] Setting packetID %d"), packet_id);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete it from queue
|
||||||
|
_mqttRemoveLastPublish();
|
||||||
|
}
|
||||||
|
|
||||||
|
// send online appended with the version information as JSON
|
||||||
|
void MyESP::_sendStartTopic() {
|
||||||
|
StaticJsonDocument<MYESP_JSON_MAXSIZE_SMALL> doc;
|
||||||
|
JsonObject payload = doc.to<JsonObject>();
|
||||||
|
payload["version"] = _app_version;
|
||||||
|
payload["IP"] = WiFi.localIP().toString();
|
||||||
|
// add time if we know it
|
||||||
|
if ((_ntp_enabled) && (NTP.tcr->abbrev != nullptr)) {
|
||||||
|
uint32_t real_time = getSystemTime();
|
||||||
|
// exclude millis() just in case
|
||||||
|
if (real_time > 10000L) {
|
||||||
|
char s[25];
|
||||||
|
// ISO 8601 describes an internationally accepted way to represent dates and times using numbers
|
||||||
|
snprintf_P(s,
|
||||||
|
25,
|
||||||
|
PSTR("%04u-%02u-%02uT%02u:%02u:%02u"),
|
||||||
|
to_year(real_time),
|
||||||
|
to_month(real_time),
|
||||||
|
to_day(real_time),
|
||||||
|
to_hour(real_time),
|
||||||
|
to_minute(real_time),
|
||||||
|
to_second(real_time)
|
||||||
|
|
||||||
|
);
|
||||||
|
payload["boottime"] = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mqttPublish(MQTT_TOPIC_START, doc, true); // send with retain on
|
||||||
}
|
}
|
||||||
|
|
||||||
// MQTT onConnect - when a connect is established
|
// MQTT onConnect - when a connect is established
|
||||||
@@ -440,8 +627,8 @@ void MyESP::_mqttOnConnect() {
|
|||||||
_mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN;
|
_mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN;
|
||||||
_mqtt_last_connection = millis();
|
_mqtt_last_connection = millis();
|
||||||
|
|
||||||
// say we're alive to the Last Will topic
|
// say we're alive to the Last Will topic, with retain on
|
||||||
mqttPublish(_mqtt_will_topic, _mqtt_will_online_payload, true); // force retain on
|
mqttPublish(_mqtt_will_topic, _mqtt_will_online_payload, true);
|
||||||
|
|
||||||
// subscribe to general subs
|
// subscribe to general subs
|
||||||
mqttSubscribe(MQTT_TOPIC_RESTART);
|
mqttSubscribe(MQTT_TOPIC_RESTART);
|
||||||
@@ -449,10 +636,14 @@ void MyESP::_mqttOnConnect() {
|
|||||||
// subscribe to a start message and send the first publish
|
// subscribe to a start message and send the first publish
|
||||||
// forcing retain to off since we only want to send this once
|
// forcing retain to off since we only want to send this once
|
||||||
mqttSubscribe(MQTT_TOPIC_START);
|
mqttSubscribe(MQTT_TOPIC_START);
|
||||||
mqttPublish(MQTT_TOPIC_START, MQTT_TOPIC_START_PAYLOAD, false);
|
|
||||||
|
// send start topic now unless NTP is enabled, otherwise wait for the time
|
||||||
|
if (!_ntp_enabled) {
|
||||||
|
_sendStartTopic();
|
||||||
|
}
|
||||||
|
|
||||||
// send heartbeat if enabled
|
// send heartbeat if enabled
|
||||||
_heartbeatCheck();
|
heartbeatCheck(true);
|
||||||
|
|
||||||
// call custom function to handle mqtt receives
|
// call custom function to handle mqtt receives
|
||||||
(_mqtt_callback_f)(MQTT_CONNECT_EVENT, nullptr, nullptr);
|
(_mqtt_callback_f)(MQTT_CONNECT_EVENT, nullptr, nullptr);
|
||||||
@@ -489,7 +680,8 @@ void MyESP::_mqtt_setup() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
//mqttClient.onSubscribe([this](uint16_t packetId, uint8_t qos) { myDebug_P(PSTR("[MQTT] Subscribe ACK for PID %d"), packetId); });
|
//mqttClient.onSubscribe([this](uint16_t packetId, uint8_t qos) { myDebug_P(PSTR("[MQTT] Subscribe ACK for PID %d"), packetId); });
|
||||||
//mqttClient.onPublish([this](uint16_t packetId) { myDebug_P(PSTR("[MQTT] Publish ACK for PID %d"), packetId); });
|
|
||||||
|
mqttClient.onPublish([this](uint16_t packetId) { _mqttOnPublish(packetId); });
|
||||||
|
|
||||||
mqttClient.onMessage([this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
mqttClient.onMessage([this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
|
||||||
_mqttOnMessage(topic, payload, len);
|
_mqttOnMessage(topic, payload, len);
|
||||||
@@ -502,8 +694,7 @@ void MyESP::_mqtt_setup() {
|
|||||||
|
|
||||||
// last will
|
// last will
|
||||||
if (_hasValue(_mqtt_will_topic)) {
|
if (_hasValue(_mqtt_will_topic)) {
|
||||||
mqttClient.setWill(_mqttTopic(_mqtt_will_topic), 1, true,
|
mqttClient.setWill(_mqttTopic(_mqtt_will_topic), 1, true, _mqtt_will_offline_payload); // retain always true
|
||||||
_mqtt_will_offline_payload); // retain always true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set credentials if we have them
|
// set credentials if we have them
|
||||||
@@ -525,7 +716,7 @@ void MyESP::_wifi_setup() {
|
|||||||
WiFi.setSleepMode(WIFI_NONE_SLEEP); // added to possibly fix wifi dropouts in arduino core 2.5.0
|
WiFi.setSleepMode(WIFI_NONE_SLEEP); // added to possibly fix wifi dropouts in arduino core 2.5.0
|
||||||
// ref: https://github.com/esp8266/Arduino/issues/6471
|
// ref: https://github.com/esp8266/Arduino/issues/6471
|
||||||
// ref: https://github.com/esp8266/Arduino/issues/6366
|
// ref: https://github.com/esp8266/Arduino/issues/6366
|
||||||
// high tx power causing weird behavior, slighly lowering from 20.5 to 20.0 may help stability
|
// high tx power causing weird behavior, slightly lowering from 20.5 to 20.0 may help stability
|
||||||
WiFi.setOutputPower(20.0); // in DBM
|
WiFi.setOutputPower(20.0); // in DBM
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -715,8 +906,8 @@ void MyESP::_consoleShowHelp() {
|
|||||||
|
|
||||||
myDebug_P(PSTR("*"));
|
myDebug_P(PSTR("*"));
|
||||||
myDebug_P(PSTR("* Commands:"));
|
myDebug_P(PSTR("* Commands:"));
|
||||||
myDebug_P(PSTR("* ?/help=show commands, CTRL-D/quit=close telnet session"));
|
myDebug_P(PSTR("* ?/help=show commands, CTRL-D/quit=end telnet session"));
|
||||||
myDebug_P(PSTR("* set, system, restart, mqttlog, kick, save"));
|
myDebug_P(PSTR("* set, system, restart, mqttqueue, kick, save"));
|
||||||
|
|
||||||
#ifdef CRASH
|
#ifdef CRASH
|
||||||
myDebug_P(PSTR("* crash <dump | clear | test [n]>"));
|
myDebug_P(PSTR("* crash <dump | clear | test [n]>"));
|
||||||
@@ -749,16 +940,17 @@ bool MyESP::_hasValue(const char * s) {
|
|||||||
void MyESP::_printSetCommands() {
|
void MyESP::_printSetCommands() {
|
||||||
myDebug_P(PSTR("\nset commands:\n"));
|
myDebug_P(PSTR("\nset commands:\n"));
|
||||||
myDebug_P(PSTR(" set erase"));
|
myDebug_P(PSTR(" set erase"));
|
||||||
myDebug_P(PSTR(" set <wifi_mode <ap | client>"));
|
myDebug_P(PSTR(" set wifi_mode <ap | client>"));
|
||||||
myDebug_P(PSTR(" set <wifi_ssid | wifi_password> [value]"));
|
myDebug_P(PSTR(" set <wifi_ssid | wifi_password> [value]"));
|
||||||
myDebug_P(PSTR(" set mqtt_enabled <on | off>"));
|
myDebug_P(PSTR(" set mqtt_enabled [on | off]"));
|
||||||
myDebug_P(PSTR(" set <mqtt_ip | mqtt_username | mqtt_password> [value]"));
|
myDebug_P(PSTR(" set <mqtt_ip | mqtt_username | mqtt_password> [value]"));
|
||||||
myDebug_P(PSTR(" set mqtt_heartbeat <on | off> (every 2 mins)"));
|
myDebug_P(PSTR(" set mqtt_heartbeat <on | off> (every 2 mins)"));
|
||||||
myDebug_P(PSTR(" set mqtt_base [string]"));
|
myDebug_P(PSTR(" set mqtt_base [prefix]"));
|
||||||
myDebug_P(PSTR(" set mqtt_port [number]"));
|
myDebug_P(PSTR(" set mqtt_port [n]"));
|
||||||
myDebug_P(PSTR(" set mqtt_qos [0-3]"));
|
myDebug_P(PSTR(" set mqtt_qos [0-3]"));
|
||||||
myDebug_P(PSTR(" set mqtt_keepalive [seconds]"));
|
myDebug_P(PSTR(" set mqtt_keepalive [seconds]"));
|
||||||
myDebug_P(PSTR(" set mqtt_retain [on | off]"));
|
myDebug_P(PSTR(" set mqtt_retain [on | off]"));
|
||||||
|
myDebug_P(PSTR(" set mqtt_nestedjson [on | off]"));
|
||||||
myDebug_P(PSTR(" set ntp_enabled <on | off>"));
|
myDebug_P(PSTR(" set ntp_enabled <on | off>"));
|
||||||
myDebug_P(PSTR(" set ntp_interval [minutes]"));
|
myDebug_P(PSTR(" set ntp_interval [minutes]"));
|
||||||
myDebug_P(PSTR(" set ntp_timezone [n]"));
|
myDebug_P(PSTR(" set ntp_timezone [n]"));
|
||||||
@@ -821,6 +1013,7 @@ void MyESP::_printSetCommands() {
|
|||||||
myDebug_P(PSTR(" mqtt_retain=%s"), (_mqtt_retain) ? "on" : "off");
|
myDebug_P(PSTR(" mqtt_retain=%s"), (_mqtt_retain) ? "on" : "off");
|
||||||
myDebug_P(PSTR(" mqtt_qos=%d"), _mqtt_qos);
|
myDebug_P(PSTR(" mqtt_qos=%d"), _mqtt_qos);
|
||||||
myDebug_P(PSTR(" mqtt_heartbeat=%s"), (_mqtt_heartbeat) ? "on" : "off");
|
myDebug_P(PSTR(" mqtt_heartbeat=%s"), (_mqtt_heartbeat) ? "on" : "off");
|
||||||
|
myDebug_P(PSTR(" mqtt_nestedjson=%s"), (_mqtt_nestedjson) ? "on" : "off");
|
||||||
|
|
||||||
#ifdef FORCE_SERIAL
|
#ifdef FORCE_SERIAL
|
||||||
myDebug_P(PSTR(" serial=%s (this is always when compiled with -DFORCE_SERIAL)"), (_general_serial) ? "on" : "off");
|
myDebug_P(PSTR(" serial=%s (this is always when compiled with -DFORCE_SERIAL)"), (_general_serial) ? "on" : "off");
|
||||||
@@ -873,9 +1066,10 @@ char * MyESP::_telnet_readWord(bool allow_all_chars) {
|
|||||||
// messy code but effective since we don't have too many settings
|
// messy code but effective since we don't have too many settings
|
||||||
// wc is word count, number of parameters after the 'set' command
|
// wc is word count, number of parameters after the 'set' command
|
||||||
bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value) {
|
bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value) {
|
||||||
bool save_config = false;
|
bool save_config = false;
|
||||||
bool save_custom_config = false;
|
bool restart = false;
|
||||||
bool restart = false;
|
|
||||||
|
MYESP_FSACTION_t save_custom_config = MYESP_FSACTION_ERR; // default
|
||||||
|
|
||||||
// check for our internal commands first
|
// check for our internal commands first
|
||||||
if (strcmp(setting, "erase") == 0) {
|
if (strcmp(setting, "erase") == 0) {
|
||||||
@@ -924,6 +1118,8 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value)
|
|||||||
restart = save_config;
|
restart = save_config;
|
||||||
} else if (strcmp(setting, "mqtt_heartbeat") == 0) {
|
} else if (strcmp(setting, "mqtt_heartbeat") == 0) {
|
||||||
save_config = fs_setSettingValue(&_mqtt_heartbeat, value, false);
|
save_config = fs_setSettingValue(&_mqtt_heartbeat, value, false);
|
||||||
|
} else if (strcmp(setting, "mqtt_nestedjson") == 0) {
|
||||||
|
save_config = fs_setSettingValue(&_mqtt_nestedjson, value, false);
|
||||||
} else if (strcmp(setting, "ntp_enabled") == 0) {
|
} else if (strcmp(setting, "ntp_enabled") == 0) {
|
||||||
save_config = fs_setSettingValue(&_ntp_enabled, value, false);
|
save_config = fs_setSettingValue(&_ntp_enabled, value, false);
|
||||||
} else if (strcmp(setting, "ntp_interval") == 0) {
|
} else if (strcmp(setting, "ntp_interval") == 0) {
|
||||||
@@ -938,13 +1134,14 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value)
|
|||||||
// finally check for any custom commands
|
// finally check for any custom commands
|
||||||
if (_fs_setlist_callback_f) {
|
if (_fs_setlist_callback_f) {
|
||||||
save_custom_config = (_fs_setlist_callback_f)(MYESP_FSACTION_SET, wc, setting, value);
|
save_custom_config = (_fs_setlist_callback_f)(MYESP_FSACTION_SET, wc, setting, value);
|
||||||
|
restart = (save_custom_config == MYESP_FSACTION_RESTART);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
// if we were able to recognize the set command, continue
|
// if we were able to recognize the set command, continue
|
||||||
if ((save_config || save_custom_config)) {
|
if ((save_config || save_custom_config != MYESP_FSACTION_ERR)) {
|
||||||
// check for 2 params
|
// check for 2 params
|
||||||
if (value == nullptr) {
|
if (value == nullptr) {
|
||||||
myDebug_P(PSTR("%s has been reset to its default value."), setting);
|
myDebug_P(PSTR("%s has been reset to its default value."), setting);
|
||||||
@@ -960,7 +1157,7 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// and see if we need to also save for custom config
|
// and see if we need to also save for custom config
|
||||||
if (save_custom_config) {
|
if (save_custom_config != MYESP_FSACTION_ERR) {
|
||||||
ok = _fs_createCustomConfig();
|
ok = _fs_createCustomConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1042,12 +1239,12 @@ void MyESP::_telnetCommand(char * commandLine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// print mqtt log command
|
// print mqtt log command
|
||||||
if ((strcmp(ptrToCommandName, "mqttlog") == 0) && (wc == 1)) {
|
if (strcmp(ptrToCommandName, "mqttqueue") == 0) {
|
||||||
_printMQTTLog();
|
_printMQTTQueue();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// show system stats
|
// show system status
|
||||||
if ((strcmp(ptrToCommandName, "system") == 0) && (wc == 1)) {
|
if ((strcmp(ptrToCommandName, "system") == 0) && (wc == 1)) {
|
||||||
showSystemStats();
|
showSystemStats();
|
||||||
return;
|
return;
|
||||||
@@ -1055,12 +1252,11 @@ void MyESP::_telnetCommand(char * commandLine) {
|
|||||||
|
|
||||||
// save everything
|
// save everything
|
||||||
if ((strcmp(ptrToCommandName, "save") == 0) && (wc == 1)) {
|
if ((strcmp(ptrToCommandName, "save") == 0) && (wc == 1)) {
|
||||||
_fs_writeConfig();
|
saveSettings();
|
||||||
_fs_createCustomConfig();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// show system stats
|
// quit
|
||||||
if ((strcmp(ptrToCommandName, "quit") == 0) && (wc == 1)) {
|
if ((strcmp(ptrToCommandName, "quit") == 0) && (wc == 1)) {
|
||||||
myDebug_P(PSTR("[TELNET] exiting telnet session"));
|
myDebug_P(PSTR("[TELNET] exiting telnet session"));
|
||||||
SerialAndTelnet.disconnectClient();
|
SerialAndTelnet.disconnectClient();
|
||||||
@@ -1088,6 +1284,12 @@ void MyESP::_telnetCommand(char * commandLine) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// public function so clients can save config
|
||||||
|
void MyESP::saveSettings() {
|
||||||
|
_fs_writeConfig();
|
||||||
|
_fs_createCustomConfig();
|
||||||
|
}
|
||||||
|
|
||||||
// returns WiFi hostname as a String object
|
// returns WiFi hostname as a String object
|
||||||
String MyESP::_getESPhostname() {
|
String MyESP::_getESPhostname() {
|
||||||
String hostname;
|
String hostname;
|
||||||
@@ -1323,13 +1525,13 @@ void MyESP::_systemCheckLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// print out ESP system stats
|
// print out ESP system status
|
||||||
// for battery power is ESP.getVcc()
|
// for battery power is ESP.getVcc()
|
||||||
void MyESP::showSystemStats() {
|
void MyESP::showSystemStats() {
|
||||||
#if defined(ESP8266)
|
#if defined(ESP8266)
|
||||||
myDebug_P(PSTR("%sESP8266 System stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
myDebug_P(PSTR("%sESP8266 System status:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||||
#else
|
#else
|
||||||
myDebug_P(PSTR("ESP32 System stats:"));
|
myDebug_P(PSTR("ESP32 System status:"));
|
||||||
#endif
|
#endif
|
||||||
myDebug_P(PSTR(""));
|
myDebug_P(PSTR(""));
|
||||||
|
|
||||||
@@ -1373,13 +1575,14 @@ void MyESP::showSystemStats() {
|
|||||||
|
|
||||||
if (isMQTTConnected()) {
|
if (isMQTTConnected()) {
|
||||||
myDebug_P(PSTR(" [MQTT] is connected (heartbeat %s)"), getHeartbeat() ? "enabled" : "disabled");
|
myDebug_P(PSTR(" [MQTT] is connected (heartbeat %s)"), getHeartbeat() ? "enabled" : "disabled");
|
||||||
|
myDebug_P(PSTR(" [MQTT] # failed topic publishes: %d"), _mqtt_publish_fails);
|
||||||
} else {
|
} else {
|
||||||
myDebug_P(PSTR(" [MQTT] is disconnected"));
|
myDebug_P(PSTR(" [MQTT] is disconnected"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_have_ntp_time) {
|
if ((_have_ntp_time) && (NTP.tcr->abbrev != nullptr)) {
|
||||||
uint32_t real_time = getSystemTime();
|
uint32_t real_time = getSystemTime();
|
||||||
myDebug_P(PSTR(" [NTP] Local Time is %02d:%02d:%02d %s (%d)"), to_hour(real_time), to_minute(real_time), to_second(real_time), NTP.tcr->abbrev, real_time);
|
myDebug_P(PSTR(" [NTP] Local Time is %02d:%02d:%02d %s"), to_hour(real_time), to_minute(real_time), to_second(real_time), NTP.tcr->abbrev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CRASH
|
#ifdef CRASH
|
||||||
@@ -1450,43 +1653,40 @@ void MyESP::showSystemStats() {
|
|||||||
/*
|
/*
|
||||||
* Send heartbeat via MQTT with all system data
|
* Send heartbeat via MQTT with all system data
|
||||||
*/
|
*/
|
||||||
void MyESP::_heartbeatCheck(bool force) {
|
void MyESP::heartbeatCheck(bool force) {
|
||||||
static uint32_t last_heartbeat = 0;
|
static uint32_t last_heartbeat = 0;
|
||||||
|
|
||||||
if ((millis() - last_heartbeat > MYESP_HEARTBEAT_INTERVAL) || force) {
|
if ((millis() - last_heartbeat > MYESP_HEARTBEAT_INTERVAL) || force) {
|
||||||
last_heartbeat = millis();
|
last_heartbeat = millis();
|
||||||
|
|
||||||
// print to log if force is set, so at bootup
|
|
||||||
if (force) {
|
|
||||||
_printHeap("[SYSTEM]");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MYESP_DEBUG
|
#ifdef MYESP_DEBUG
|
||||||
_printHeap("[HEARTBEAT] ");
|
_printHeap("[HEARTBEAT]");
|
||||||
#endif
|
#endif
|
||||||
if (!isMQTTConnected() || !(_mqtt_heartbeat)) {
|
if (!isMQTTConnected() || !(_mqtt_heartbeat)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// print to log if force is set
|
||||||
|
if (force) {
|
||||||
|
_printHeap("[SYSTEM]");
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t total_memory = _getInitialFreeHeap();
|
uint32_t total_memory = _getInitialFreeHeap();
|
||||||
uint32_t free_memory = ESP.getFreeHeap();
|
uint32_t free_memory = ESP.getFreeHeap();
|
||||||
uint8_t mem_available = 100 * free_memory / total_memory; // as a %
|
uint8_t mem_available = 100 * free_memory / total_memory; // as a %
|
||||||
|
|
||||||
StaticJsonDocument<MYESP_JSON_MAXSIZE_SMALL> doc;
|
const size_t capacity = JSON_OBJECT_SIZE(6);
|
||||||
JsonObject rootHeartbeat = doc.to<JsonObject>();
|
StaticJsonDocument<capacity> doc;
|
||||||
|
JsonObject rootHeartbeat = doc.to<JsonObject>();
|
||||||
|
|
||||||
rootHeartbeat["version"] = _app_version;
|
rootHeartbeat["rssid"] = getWifiQuality();
|
||||||
rootHeartbeat["IP"] = WiFi.localIP().toString();
|
rootHeartbeat["load"] = getSystemLoadAverage();
|
||||||
rootHeartbeat["rssid"] = getWifiQuality();
|
rootHeartbeat["uptime"] = _getUptime();
|
||||||
rootHeartbeat["load"] = getSystemLoadAverage();
|
rootHeartbeat["freemem"] = mem_available;
|
||||||
rootHeartbeat["uptime"] = _getUptime();
|
rootHeartbeat["tcpdrops"] = _getSystemDropoutCounter();
|
||||||
rootHeartbeat["freemem"] = mem_available;
|
rootHeartbeat["mqttpublishfails"] = _mqtt_publish_fails;
|
||||||
rootHeartbeat["MQTTdisconnects"] = _getSystemDropoutCounter();
|
|
||||||
|
|
||||||
char data[300] = {0};
|
mqttPublish(MQTT_TOPIC_HEARTBEAT, doc, false); // send to MQTT with retain off
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
|
|
||||||
(void)mqttPublish(MQTT_TOPIC_HEARTBEAT, data, false); // send to MQTT with retain off
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1499,13 +1699,13 @@ void MyESP::heartbeatPrint() {
|
|||||||
uint32_t total_memory = _getInitialFreeHeap();
|
uint32_t total_memory = _getInitialFreeHeap();
|
||||||
uint32_t free_memory = ESP.getFreeHeap();
|
uint32_t free_memory = ESP.getFreeHeap();
|
||||||
|
|
||||||
myDebug("[%d] uptime:%d bytesfree:%d (%2u%%), load:%d, dropouts:%d",
|
myDebug_P(PSTR("[%d] uptime:%d bytesfree:%d (%2u%%), load:%d, dropouts:%d"),
|
||||||
i++,
|
i++,
|
||||||
_getUptime(),
|
_getUptime(),
|
||||||
free_memory,
|
free_memory,
|
||||||
100 * free_memory / total_memory,
|
100 * free_memory / total_memory,
|
||||||
getSystemLoadAverage(),
|
getSystemLoadAverage(),
|
||||||
_getSystemDropoutCounter()
|
_getSystemDropoutCounter()
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1738,23 +1938,25 @@ bool MyESP::_fs_loadConfig() {
|
|||||||
_general_serial = general["serial"];
|
_general_serial = general["serial"];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JsonObject mqtt = doc["mqtt"];
|
JsonObject mqtt = doc["mqtt"];
|
||||||
_mqtt_enabled = mqtt["enabled"];
|
_mqtt_enabled = mqtt["enabled"];
|
||||||
_mqtt_heartbeat = mqtt["heartbeat"];
|
_mqtt_heartbeat = mqtt["heartbeat"];
|
||||||
_mqtt_ip = strdup(mqtt["ip"] | "");
|
_mqtt_ip = strdup(mqtt["ip"] | "");
|
||||||
_mqtt_user = strdup(mqtt["user"] | "");
|
_mqtt_user = strdup(mqtt["user"] | "");
|
||||||
_mqtt_port = mqtt["port"] | MQTT_PORT;
|
_mqtt_port = mqtt["port"] | MQTT_PORT;
|
||||||
_mqtt_keepalive = mqtt["keepalive"] | MQTT_KEEPALIVE;
|
_mqtt_keepalive = mqtt["keepalive"] | MQTT_KEEPALIVE;
|
||||||
_mqtt_retain = mqtt["retain"];
|
_mqtt_retain = mqtt["retain"];
|
||||||
_mqtt_qos = mqtt["qos"] | MQTT_QOS;
|
_mqtt_qos = mqtt["qos"] | MQTT_QOS;
|
||||||
_mqtt_password = strdup(mqtt["password"] | "");
|
_mqtt_nestedjson = mqtt["nestedjson"] | true; // default to on
|
||||||
_mqtt_base = strdup(mqtt["base"] | MQTT_BASE_DEFAULT);
|
_mqtt_password = strdup(mqtt["password"] | "");
|
||||||
|
_mqtt_base = strdup(mqtt["base"] | MQTT_BASE_DEFAULT);
|
||||||
|
|
||||||
JsonObject ntp = doc["ntp"];
|
JsonObject ntp = doc["ntp"];
|
||||||
_ntp_server = strdup(ntp["server"] | "");
|
_ntp_server = strdup(ntp["server"] | "");
|
||||||
_ntp_interval = ntp["interval"] | 60;
|
_ntp_interval = ntp["interval"] | 60;
|
||||||
if (_ntp_interval < 2)
|
if (_ntp_interval < 2) {
|
||||||
_ntp_interval = NTP_INTERVAL_DEFAULT;
|
_ntp_interval = NTP_INTERVAL_DEFAULT;
|
||||||
|
}
|
||||||
_ntp_enabled = ntp["enabled"];
|
_ntp_enabled = ntp["enabled"];
|
||||||
_ntp_timezone = ntp["timezone"] | NTP_TIMEZONE_DEFAULT;
|
_ntp_timezone = ntp["timezone"] | NTP_TIMEZONE_DEFAULT;
|
||||||
|
|
||||||
@@ -1951,17 +2153,18 @@ bool MyESP::_fs_writeConfig() {
|
|||||||
general["log_ip"] = _general_log_ip;
|
general["log_ip"] = _general_log_ip;
|
||||||
general["version"] = _app_version;
|
general["version"] = _app_version;
|
||||||
|
|
||||||
JsonObject mqtt = doc.createNestedObject("mqtt");
|
JsonObject mqtt = doc.createNestedObject("mqtt");
|
||||||
mqtt["enabled"] = _mqtt_enabled;
|
mqtt["enabled"] = _mqtt_enabled;
|
||||||
mqtt["heartbeat"] = _mqtt_heartbeat;
|
mqtt["heartbeat"] = _mqtt_heartbeat;
|
||||||
mqtt["ip"] = _mqtt_ip;
|
mqtt["ip"] = _mqtt_ip;
|
||||||
mqtt["user"] = _mqtt_user;
|
mqtt["user"] = _mqtt_user;
|
||||||
mqtt["port"] = _mqtt_port;
|
mqtt["port"] = _mqtt_port;
|
||||||
mqtt["qos"] = _mqtt_qos;
|
mqtt["qos"] = _mqtt_qos;
|
||||||
mqtt["keepalive"] = _mqtt_keepalive;
|
mqtt["keepalive"] = _mqtt_keepalive;
|
||||||
mqtt["retain"] = _mqtt_retain;
|
mqtt["retain"] = _mqtt_retain;
|
||||||
mqtt["password"] = _mqtt_password;
|
mqtt["password"] = _mqtt_password;
|
||||||
mqtt["base"] = _mqtt_base;
|
mqtt["base"] = _mqtt_base;
|
||||||
|
mqtt["nestedjson"] = _mqtt_nestedjson;
|
||||||
|
|
||||||
JsonObject ntp = doc.createNestedObject("ntp");
|
JsonObject ntp = doc.createNestedObject("ntp");
|
||||||
ntp["server"] = _ntp_server;
|
ntp["server"] = _ntp_server;
|
||||||
@@ -2063,6 +2266,11 @@ void MyESP::_calculateLoad() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns true if nested JSON setting is enabled
|
||||||
|
bool MyESP::mqttUseNestedJson() {
|
||||||
|
return _mqtt_nestedjson;
|
||||||
|
}
|
||||||
|
|
||||||
// returns true is MQTT is alive
|
// returns true is MQTT is alive
|
||||||
bool MyESP::isMQTTConnected() {
|
bool MyESP::isMQTTConnected() {
|
||||||
return mqttClient.connected();
|
return mqttClient.connected();
|
||||||
@@ -2278,7 +2486,7 @@ void MyESP::writeLogEvent(const uint8_t type, const char * msg) {
|
|||||||
// Handles WebSocket Events
|
// Handles WebSocket Events
|
||||||
void MyESP::_onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len) {
|
void MyESP::_onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len) {
|
||||||
if (type == WS_EVT_ERROR) {
|
if (type == WS_EVT_ERROR) {
|
||||||
myDebug("[WEB] WebSocket[%s][%u] error(%u): %s\r\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data);
|
myDebug_P(PSTR("[WEB] WebSocket[%s][%u] error(%u): %s\r\n"), server->url(), client->id(), *((uint16_t *)arg), (char *)data);
|
||||||
} else if (type == WS_EVT_DATA) {
|
} else if (type == WS_EVT_DATA) {
|
||||||
AwsFrameInfo * info = (AwsFrameInfo *)arg;
|
AwsFrameInfo * info = (AwsFrameInfo *)arg;
|
||||||
uint64_t index = info->index;
|
uint64_t index = info->index;
|
||||||
@@ -2442,13 +2650,13 @@ void MyESP::_sendStatus() {
|
|||||||
uint32_t total_memory = _getInitialFreeHeap();
|
uint32_t total_memory = _getInitialFreeHeap();
|
||||||
uint32_t free_memory = ESP.getFreeHeap();
|
uint32_t free_memory = ESP.getFreeHeap();
|
||||||
|
|
||||||
DynamicJsonDocument doc(MQTT_MAX_PAYLOAD_SIZE_LARGE);
|
DynamicJsonDocument doc(MYESP_JSON_MAXSIZE_MEDIUM);
|
||||||
JsonObject root = doc.to<JsonObject>();
|
JsonObject root = doc.to<JsonObject>();
|
||||||
root["command"] = "status";
|
root["command"] = "status";
|
||||||
|
|
||||||
FSInfo fsinfo;
|
FSInfo fsinfo;
|
||||||
if (!SPIFFS.info(fsinfo)) {
|
if (!SPIFFS.info(fsinfo)) {
|
||||||
myDebug("[SYSTEM] Error getting info on SPIFFS");
|
myDebug_P(PSTR("[SYSTEM] Error getting info on SPIFFS"));
|
||||||
} else {
|
} else {
|
||||||
root["availspiffs"] = (fsinfo.totalBytes - fsinfo.usedBytes) / 1000;
|
root["availspiffs"] = (fsinfo.totalBytes - fsinfo.usedBytes) / 1000;
|
||||||
root["spiffssize"] = (fsinfo.totalBytes / 1000);
|
root["spiffssize"] = (fsinfo.totalBytes / 1000);
|
||||||
@@ -2486,31 +2694,7 @@ void MyESP::_sendStatus() {
|
|||||||
sprintf(uptime, "%d day%s %d hour%s %d minute%s %d second%s", d, (d == 1) ? "" : "s", h, (h == 1) ? "" : "s", m, (m == 1) ? "" : "s", sec, (sec == 1) ? "" : "s");
|
sprintf(uptime, "%d day%s %d hour%s %d minute%s %d second%s", d, (d == 1) ? "" : "s", h, (h == 1) ? "" : "s", m, (m == 1) ? "" : "s", sec, (sec == 1) ? "" : "s");
|
||||||
root["uptime"] = uptime;
|
root["uptime"] = uptime;
|
||||||
|
|
||||||
char topic_s[MQTT_MAX_TOPIC_SIZE] = {0};
|
char buffer[MYESP_JSON_MAXSIZE_MEDIUM];
|
||||||
if (_hasValue(_mqtt_base)) {
|
|
||||||
strlcpy(topic_s, _mqtt_base, sizeof(topic_s));
|
|
||||||
strlcat(topic_s, "/", sizeof(topic_s));
|
|
||||||
strlcat(topic_s, _general_hostname, sizeof(topic_s));
|
|
||||||
} else {
|
|
||||||
strlcpy(topic_s, _general_hostname, sizeof(topic_s));
|
|
||||||
}
|
|
||||||
strlcat(topic_s, "/", sizeof(topic_s));
|
|
||||||
root["mqttloghdr"] = topic_s;
|
|
||||||
|
|
||||||
// create MQTT log
|
|
||||||
JsonArray list = root.createNestedArray("mqttlog");
|
|
||||||
|
|
||||||
// only send Publish
|
|
||||||
for (uint8_t i = 0; i < MYESP_MQTTLOG_MAX; i++) {
|
|
||||||
if ((MQTT_log[i].type == 1) && (MQTT_log[i].topic != nullptr)) {
|
|
||||||
JsonObject item = list.createNestedObject();
|
|
||||||
item["topic"] = MQTT_log[i].topic;
|
|
||||||
item["payload"] = MQTT_log[i].payload;
|
|
||||||
item["time"] = MQTT_log[i].timestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[MQTT_MAX_PAYLOAD_SIZE_LARGE];
|
|
||||||
size_t len = serializeJson(root, buffer);
|
size_t len = serializeJson(root, buffer);
|
||||||
|
|
||||||
_ws->textAll(buffer, len);
|
_ws->textAll(buffer, len);
|
||||||
@@ -2569,48 +2753,49 @@ void MyESP::_webserver_setup() {
|
|||||||
request->send(response);
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
_webServer->on("/update",
|
_webServer->on(
|
||||||
HTTP_POST,
|
"/update",
|
||||||
[](AsyncWebServerRequest * request) {
|
HTTP_POST,
|
||||||
AsyncWebServerResponse * response = request->beginResponse(200, "text/plain", _shouldRestart ? "OK" : "FAIL");
|
[](AsyncWebServerRequest * request) {
|
||||||
response->addHeader("Connection", "close");
|
AsyncWebServerResponse * response = request->beginResponse(200, "text/plain", _shouldRestart ? "OK" : "FAIL");
|
||||||
request->send(response);
|
response->addHeader("Connection", "close");
|
||||||
},
|
request->send(response);
|
||||||
[](AsyncWebServerRequest * request, String filename, size_t index, uint8_t * data, size_t len, bool final) {
|
},
|
||||||
if (!request->authenticate(MYESP_HTTP_USERNAME, _general_password)) {
|
[](AsyncWebServerRequest * request, String filename, size_t index, uint8_t * data, size_t len, bool final) {
|
||||||
return;
|
if (!request->authenticate(MYESP_HTTP_USERNAME, _general_password)) {
|
||||||
}
|
return;
|
||||||
if (!index) {
|
}
|
||||||
ETS_UART_INTR_DISABLE(); // disable all UART interrupts to be safe
|
if (!index) {
|
||||||
//_writeLogEvent(MYESP_SYSLOG_INFO, "Firmware update started");
|
ETS_UART_INTR_DISABLE(); // disable all UART interrupts to be safe
|
||||||
Update.runAsync(true);
|
//_writeLogEvent(MYESP_SYSLOG_INFO, "Firmware update started");
|
||||||
if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) {
|
Update.runAsync(true);
|
||||||
|
if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) {
|
||||||
//_writeLogEvent(MYESP_SYSLOG_ERROR, "Not enough space to update");
|
//_writeLogEvent(MYESP_SYSLOG_ERROR, "Not enough space to update");
|
||||||
#ifdef MYESP_DEBUG
|
#ifdef MYESP_DEBUG
|
||||||
Update.printError(Serial);
|
Update.printError(Serial);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!Update.hasError()) {
|
if (!Update.hasError()) {
|
||||||
if (Update.write(data, len) != len) {
|
if (Update.write(data, len) != len) {
|
||||||
//_writeLogEvent(MYESP_SYSLOG_ERROR, "Writing to flash failed");
|
//_writeLogEvent(MYESP_SYSLOG_ERROR, "Writing to flash failed");
|
||||||
#ifdef MYESP_DEBUG
|
#ifdef MYESP_DEBUG
|
||||||
Update.printError(Serial);
|
Update.printError(Serial);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (final) {
|
if (final) {
|
||||||
if (Update.end(true)) {
|
if (Update.end(true)) {
|
||||||
//_writeLogEvent(MYESP_SYSLOG_INFO, "Firmware update finished");
|
//_writeLogEvent(MYESP_SYSLOG_INFO, "Firmware update finished");
|
||||||
_shouldRestart = !Update.hasError();
|
_shouldRestart = !Update.hasError();
|
||||||
} else {
|
} else {
|
||||||
//_writeLogEvent(MYESP_SYSLOG_ERROR, "Firmware update failed");
|
//_writeLogEvent(MYESP_SYSLOG_ERROR, "Firmware update failed");
|
||||||
#ifdef MYESP_DEBUG
|
#ifdef MYESP_DEBUG
|
||||||
Update.printError(Serial);
|
Update.printError(Serial);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_webServer->on("/fonts/glyphicons-halflings-regular.woff", HTTP_GET, [](AsyncWebServerRequest * request) {
|
_webServer->on("/fonts/glyphicons-halflings-regular.woff", HTTP_GET, [](AsyncWebServerRequest * request) {
|
||||||
AsyncWebServerResponse * response =
|
AsyncWebServerResponse * response =
|
||||||
@@ -2667,84 +2852,13 @@ void MyESP::_printHeap(const char * prefix) {
|
|||||||
uint32_t total_memory = _getInitialFreeHeap();
|
uint32_t total_memory = _getInitialFreeHeap();
|
||||||
uint32_t free_memory = ESP.getFreeHeap();
|
uint32_t free_memory = ESP.getFreeHeap();
|
||||||
|
|
||||||
myDebug("%s Free Heap: %d bytes initially | %d bytes used (%2u%%) | %d bytes free (%2u%%)",
|
myDebug_P(PSTR("%s Free Heap: %d bytes initially | %d bytes used (%2u%%) | %d bytes free (%2u%%)"),
|
||||||
prefix,
|
prefix,
|
||||||
total_memory,
|
total_memory,
|
||||||
total_memory - free_memory,
|
total_memory - free_memory,
|
||||||
100 * (total_memory - free_memory) / total_memory,
|
100 * (total_memory - free_memory) / total_memory,
|
||||||
free_memory,
|
free_memory,
|
||||||
100 * free_memory / total_memory);
|
100 * free_memory / total_memory);
|
||||||
}
|
|
||||||
|
|
||||||
// print MQTT log - everything that was published last per topic
|
|
||||||
void MyESP::_printMQTTLog() {
|
|
||||||
myDebug_P(PSTR("MQTT publish log:"));
|
|
||||||
uint8_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < MYESP_MQTTLOG_MAX; i++) {
|
|
||||||
if ((MQTT_log[i].topic != nullptr) && (MQTT_log[i].type == MYESP_MQTTLOGTYPE_PUBLISH)) {
|
|
||||||
myDebug_P(PSTR(" Timestamp:%02d:%02d:%02d Topic:%s Payload:%s"),
|
|
||||||
to_hour(MQTT_log[i].timestamp),
|
|
||||||
to_minute(MQTT_log[i].timestamp),
|
|
||||||
to_second(MQTT_log[i].timestamp),
|
|
||||||
MQTT_log[i].topic,
|
|
||||||
MQTT_log[i].payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
myDebug_P(PSTR("")); // newline
|
|
||||||
myDebug_P(PSTR("MQTT subscriptions:"));
|
|
||||||
|
|
||||||
for (i = 0; i < MYESP_MQTTLOG_MAX; i++) {
|
|
||||||
if ((MQTT_log[i].topic != nullptr) && (MQTT_log[i].type == MYESP_MQTTLOGTYPE_SUBSCRIBE)) {
|
|
||||||
myDebug_P(PSTR(" Topic:%s"), MQTT_log[i].topic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
myDebug_P(PSTR("")); // newline
|
|
||||||
}
|
|
||||||
|
|
||||||
// add an MQTT log entry to our buffer
|
|
||||||
void MyESP::_addMQTTLog(const char * topic, const char * payload, const MYESP_MQTTLOGTYPE_t type) {
|
|
||||||
static uint8_t logCount = 0;
|
|
||||||
uint8_t logPointer = 0;
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
#ifdef MYESP_DEBUG
|
|
||||||
myDebug("_addMQTTLog [#%d] %s (%d) [%s] (%d)", logCount, topic, strlen(topic), payload, strlen(payload));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// find the topic
|
|
||||||
// topics must be unique for either publish or subscribe
|
|
||||||
while ((logPointer < MYESP_MQTTLOG_MAX) && (_hasValue(MQTT_log[logPointer].topic))) {
|
|
||||||
if ((strcmp(MQTT_log[logPointer].topic, topic) == 0) && (MQTT_log[logPointer].type == type)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
logPointer++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not found add it and increment next free space pointer
|
|
||||||
if (!found) {
|
|
||||||
logPointer = logCount;
|
|
||||||
if (++logCount == MYESP_MQTTLOG_MAX) {
|
|
||||||
logCount = 0; // rotate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete old record
|
|
||||||
if (MQTT_log[logPointer].topic) {
|
|
||||||
free(MQTT_log[logPointer].topic);
|
|
||||||
}
|
|
||||||
if (MQTT_log[logPointer].payload) {
|
|
||||||
free(MQTT_log[logPointer].payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
// and add new record
|
|
||||||
MQTT_log[logPointer].type = type;
|
|
||||||
MQTT_log[logPointer].topic = strdup(topic);
|
|
||||||
MQTT_log[logPointer].payload = strdup(payload);
|
|
||||||
MQTT_log[logPointer].timestamp = now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send UTC time via ws
|
// send UTC time via ws
|
||||||
@@ -2776,9 +2890,11 @@ void MyESP::_bootupSequence() {
|
|||||||
|
|
||||||
// check if its booted
|
// check if its booted
|
||||||
if (boot_status == MYESP_BOOTSTATUS_BOOTED) {
|
if (boot_status == MYESP_BOOTSTATUS_BOOTED) {
|
||||||
if ((_ntp_enabled) && (now() > 10000) && !_have_ntp_time) {
|
if ((_ntp_enabled) && (now() > 10000L) && !_have_ntp_time) {
|
||||||
_have_ntp_time = true;
|
_have_ntp_time = true;
|
||||||
writeLogEvent(MYESP_SYSLOG_INFO, "System booted");
|
writeLogEvent(MYESP_SYSLOG_INFO, "System booted");
|
||||||
|
// send start topic
|
||||||
|
_sendStartTopic();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2871,7 +2987,6 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char *
|
|||||||
_webserver_setup(); // init web server
|
_webserver_setup(); // init web server
|
||||||
|
|
||||||
_setSystemCheck(false); // reset system check
|
_setSystemCheck(false); // reset system check
|
||||||
_heartbeatCheck(true); // force heartbeat, will send out message to log too
|
|
||||||
|
|
||||||
_setSystemDropoutCounter(0); // reset # TCP dropouts
|
_setSystemDropoutCounter(0); // reset # TCP dropouts
|
||||||
|
|
||||||
@@ -2884,7 +2999,7 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char *
|
|||||||
void MyESP::loop() {
|
void MyESP::loop() {
|
||||||
_calculateLoad();
|
_calculateLoad();
|
||||||
_systemCheckLoop();
|
_systemCheckLoop();
|
||||||
_heartbeatCheck();
|
heartbeatCheck();
|
||||||
_bootupSequence(); // see if a reset was pressed during bootup
|
_bootupSequence(); // see if a reset was pressed during bootup
|
||||||
|
|
||||||
jw.loop(); // WiFi
|
jw.loop(); // WiFi
|
||||||
@@ -2897,6 +3012,14 @@ void MyESP::loop() {
|
|||||||
|
|
||||||
_mqttConnect(); // MQTT
|
_mqttConnect(); // MQTT
|
||||||
|
|
||||||
|
// every second check MQTT queue for publishing
|
||||||
|
static unsigned long lastMqttPoll = 0;
|
||||||
|
unsigned long currentMillis = millis();
|
||||||
|
if ((unsigned long)(currentMillis - lastMqttPoll) >= MQTT_PUBLISH_WAIT) {
|
||||||
|
_mqttPublishQueue();
|
||||||
|
lastMqttPoll = currentMillis;
|
||||||
|
}
|
||||||
|
|
||||||
// SysLog
|
// SysLog
|
||||||
uuid::loop();
|
uuid::loop();
|
||||||
syslog.loop();
|
syslog.loop();
|
||||||
@@ -2907,7 +3030,7 @@ void MyESP::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_formatreq) {
|
if (_formatreq) {
|
||||||
myDebug("[SYSTEM] Factory reset initiated. Please wait. System will automatically restart when complete...");
|
myDebug_P(PSTR("[SYSTEM] Factory reset initiated. Please wait. System will automatically restart when complete..."));
|
||||||
SPIFFS.end();
|
SPIFFS.end();
|
||||||
_ws->enable(false);
|
_ws->enable(false);
|
||||||
SPIFFS.format();
|
SPIFFS.format();
|
||||||
@@ -2917,7 +3040,7 @@ void MyESP::loop() {
|
|||||||
|
|
||||||
if (_shouldRestart) {
|
if (_shouldRestart) {
|
||||||
writeLogEvent(MYESP_SYSLOG_INFO, "System is restarting");
|
writeLogEvent(MYESP_SYSLOG_INFO, "System is restarting");
|
||||||
myDebug("[SYSTEM] Restarting...");
|
myDebug_P(PSTR("[SYSTEM] Restarting..."));
|
||||||
_deferredReset(500, CUSTOM_RESET_TERMINAL);
|
_deferredReset(500, CUSTOM_RESET_TERMINAL);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
|
|||||||
157
src/MyESP.h
157
src/MyESP.h
@@ -9,7 +9,7 @@
|
|||||||
#ifndef MyESP_h
|
#ifndef MyESP_h
|
||||||
#define MyESP_h
|
#define MyESP_h
|
||||||
|
|
||||||
#define MYESP_VERSION "1.2.22"
|
#define MYESP_VERSION "1.2.37"
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ArduinoOTA.h>
|
#include <ArduinoOTA.h>
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include <JustWifi.h>
|
#include <JustWifi.h>
|
||||||
|
#include <deque> // for MQTT publish queue
|
||||||
|
|
||||||
// SysLog
|
// SysLog
|
||||||
#include <uuid/common.h>
|
#include <uuid/common.h>
|
||||||
@@ -85,7 +86,6 @@ extern struct rst_info resetInfo;
|
|||||||
#define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most
|
#define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most
|
||||||
#define MQTT_TOPIC_START "start"
|
#define MQTT_TOPIC_START "start"
|
||||||
#define MQTT_TOPIC_HEARTBEAT "heartbeat"
|
#define MQTT_TOPIC_HEARTBEAT "heartbeat"
|
||||||
#define MQTT_TOPIC_START_PAYLOAD "start"
|
|
||||||
#define MQTT_TOPIC_RESTART "restart"
|
#define MQTT_TOPIC_RESTART "restart"
|
||||||
#define MQTT_WILL_ONLINE_PAYLOAD "online" // for last will & testament payload
|
#define MQTT_WILL_ONLINE_PAYLOAD "online" // for last will & testament payload
|
||||||
#define MQTT_WILL_OFFLINE_PAYLOAD "offline" // for last will & testament payload
|
#define MQTT_WILL_OFFLINE_PAYLOAD "offline" // for last will & testament payload
|
||||||
@@ -95,20 +95,18 @@ extern struct rst_info resetInfo;
|
|||||||
#define MQTT_QOS 0 // default qos 0
|
#define MQTT_QOS 0 // default qos 0
|
||||||
#define MQTT_WILL_TOPIC "status" // for last will & testament topic name
|
#define MQTT_WILL_TOPIC "status" // for last will & testament topic name
|
||||||
#define MQTT_MAX_TOPIC_SIZE 50 // max length of MQTT topic
|
#define MQTT_MAX_TOPIC_SIZE 50 // max length of MQTT topic
|
||||||
#define MQTT_MAX_PAYLOAD_SIZE 700 // max size of a JSON object. See https://arduinojson.org/v6/assistant/
|
#define MQTT_QUEUE_MAX_SIZE 50 // Size of the MQTT queue
|
||||||
#define MQTT_MAX_PAYLOAD_SIZE_LARGE 2000 // max size of a large JSON object, like for sending MQTT log
|
#define MQTT_PUBLISH_WAIT 750 // time in ms before sending MQTT messages
|
||||||
|
#define MQTT_PUBLISH_MAX_RETRY 4 // max retries for giving up on publishing
|
||||||
|
#define MYESP_JSON_MAXSIZE_LARGE 2000 // for large Dynamic json files - https://arduinojson.org/v6/assistant/
|
||||||
|
#define MYESP_JSON_MAXSIZE_MEDIUM 800 // for medium Dynamic json files - https://arduinojson.org/v6/assistant/
|
||||||
|
#define MYESP_JSON_MAXSIZE_SMALL 200 // for smaller Static json documents - https://arduinojson.org/v6/assistant/
|
||||||
|
|
||||||
// Internal MQTT events
|
// Internal MQTT events
|
||||||
#define MQTT_CONNECT_EVENT 0
|
#define MQTT_CONNECT_EVENT 0
|
||||||
#define MQTT_DISCONNECT_EVENT 1
|
#define MQTT_DISCONNECT_EVENT 1
|
||||||
#define MQTT_MESSAGE_EVENT 2
|
#define MQTT_MESSAGE_EVENT 2
|
||||||
|
|
||||||
#define MYESP_JSON_MAXSIZE_LARGE 2000 // for large Dynamic json files
|
|
||||||
#define MYESP_JSON_MAXSIZE_MEDIUM 800 // for medium Dynamic json files
|
|
||||||
#define MYESP_JSON_MAXSIZE_SMALL 200 // for smaller Static json documents
|
|
||||||
|
|
||||||
#define MYESP_MQTTLOG_MAX 60 // max number of log entries for MQTT publishes and subscribes
|
|
||||||
|
|
||||||
#define MYESP_MQTT_PAYLOAD_ON '1' // for MQTT switch on
|
#define MYESP_MQTT_PAYLOAD_ON '1' // for MQTT switch on
|
||||||
#define MYESP_MQTT_PAYLOAD_OFF '0' // for MQTT switch off
|
#define MYESP_MQTT_PAYLOAD_OFF '0' // for MQTT switch off
|
||||||
|
|
||||||
@@ -210,17 +208,25 @@ struct RtcmemData {
|
|||||||
|
|
||||||
static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
|
static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
|
||||||
|
|
||||||
#define MYESP_SYSTEM_CHECK_TIME 60000 // The system is considered stable after these many millis (1 minute)
|
#define MYESP_SYSTEM_CHECK_TIME 60000 // The system is considered stable after these many millis (1 min)
|
||||||
#define MYESP_SYSTEM_CHECK_MAX 10 // After this many crashes on boot
|
#define MYESP_SYSTEM_CHECK_MAX 10 // After this many crashes on boot
|
||||||
#define MYESP_HEARTBEAT_INTERVAL 120000 // in milliseconds, how often the MQTT heartbeat is sent (2 mins)
|
#define MYESP_HEARTBEAT_INTERVAL 60000 // in milliseconds, how often the MQTT heartbeat is sent (1 min)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool set; // is it a set command
|
bool set; // is it a set command?
|
||||||
char key[50];
|
char key[60];
|
||||||
char description[100];
|
char description[110];
|
||||||
} command_t;
|
} command_t;
|
||||||
|
|
||||||
typedef enum { MYESP_FSACTION_SET, MYESP_FSACTION_LIST, MYESP_FSACTION_SAVE, MYESP_FSACTION_LOAD } MYESP_FSACTION_t;
|
typedef enum {
|
||||||
|
MYESP_FSACTION_SET,
|
||||||
|
MYESP_FSACTION_LIST,
|
||||||
|
MYESP_FSACTION_SAVE,
|
||||||
|
MYESP_FSACTION_LOAD,
|
||||||
|
MYESP_FSACTION_ERR,
|
||||||
|
MYESP_FSACTION_OK,
|
||||||
|
MYESP_FSACTION_RESTART
|
||||||
|
} MYESP_FSACTION_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MYESP_BOOTSTATUS_POWERON = 0,
|
MYESP_BOOTSTATUS_POWERON = 0,
|
||||||
@@ -229,24 +235,14 @@ typedef enum {
|
|||||||
MYESP_BOOTSTATUS_RESETNEEDED = 3
|
MYESP_BOOTSTATUS_RESETNEEDED = 3
|
||||||
} MYESP_BOOTSTATUS_t; // boot messages
|
} MYESP_BOOTSTATUS_t; // boot messages
|
||||||
|
|
||||||
typedef enum { MYESP_MQTTLOGTYPE_NONE, MYESP_MQTTLOGTYPE_PUBLISH, MYESP_MQTTLOGTYPE_SUBSCRIBE } MYESP_MQTTLOGTYPE_t;
|
typedef std::function<void(unsigned int, const char *, const char *)> mqtt_callback_f;
|
||||||
|
typedef std::function<void()> wifi_callback_f;
|
||||||
// for storing all MQTT publish messages
|
typedef std::function<void()> ota_callback_f;
|
||||||
typedef struct {
|
typedef std::function<void(uint8_t, const char *)> telnetcommand_callback_f;
|
||||||
uint8_t type; // 0=none, 1=publish, 2=subscribe
|
typedef std::function<void(uint8_t)> telnet_callback_f;
|
||||||
char * topic;
|
typedef std::function<bool(MYESP_FSACTION_t, JsonObject json)> fs_loadsave_callback_f;
|
||||||
char * payload;
|
typedef std::function<MYESP_FSACTION_t(MYESP_FSACTION_t, uint8_t, const char *, const char *)> fs_setlist_callback_f;
|
||||||
time_t timestamp;
|
typedef std::function<void(JsonObject root)> web_callback_f;
|
||||||
} _MQTT_Log_t;
|
|
||||||
|
|
||||||
typedef std::function<void(unsigned int, const char *, const char *)> mqtt_callback_f;
|
|
||||||
typedef std::function<void()> wifi_callback_f;
|
|
||||||
typedef std::function<void()> ota_callback_f;
|
|
||||||
typedef std::function<void(uint8_t, const char *)> telnetcommand_callback_f;
|
|
||||||
typedef std::function<void(uint8_t)> telnet_callback_f;
|
|
||||||
typedef std::function<bool(MYESP_FSACTION_t, JsonObject json)> fs_loadsave_callback_f;
|
|
||||||
typedef std::function<bool(MYESP_FSACTION_t, uint8_t, const char *, const char *)> fs_setlist_callback_f;
|
|
||||||
typedef std::function<void(JsonObject root)> web_callback_f;
|
|
||||||
|
|
||||||
// calculates size of an 2d array at compile time
|
// calculates size of an 2d array at compile time
|
||||||
template <typename T, size_t N>
|
template <typename T, size_t N>
|
||||||
@@ -285,7 +281,10 @@ class MyESP {
|
|||||||
void mqttUnsubscribe(const char * topic);
|
void mqttUnsubscribe(const char * topic);
|
||||||
bool mqttPublish(const char * topic, const char * payload);
|
bool mqttPublish(const char * topic, const char * payload);
|
||||||
bool mqttPublish(const char * topic, const char * payload, bool retain);
|
bool mqttPublish(const char * topic, const char * payload, bool retain);
|
||||||
|
bool mqttPublish(const char * topic, JsonDocument & payload);
|
||||||
|
bool mqttPublish(const char * topic, JsonDocument & payload, bool retain);
|
||||||
void setMQTT(mqtt_callback_f callback);
|
void setMQTT(mqtt_callback_f callback);
|
||||||
|
bool mqttUseNestedJson();
|
||||||
|
|
||||||
// OTA
|
// OTA
|
||||||
void setOTA(ota_callback_f OTACallback_pre, ota_callback_f OTACallback_post);
|
void setOTA(ota_callback_f OTACallback_pre, ota_callback_f OTACallback_post);
|
||||||
@@ -302,6 +301,7 @@ class MyESP {
|
|||||||
|
|
||||||
// FS
|
// FS
|
||||||
void setSettings(fs_loadsave_callback_f loadsave, fs_setlist_callback_f setlist, bool useSerial = true);
|
void setSettings(fs_loadsave_callback_f loadsave, fs_setlist_callback_f setlist, bool useSerial = true);
|
||||||
|
void saveSettings();
|
||||||
bool fs_saveConfig(JsonObject root);
|
bool fs_saveConfig(JsonObject root);
|
||||||
bool fs_saveCustomConfig(JsonObject root);
|
bool fs_saveCustomConfig(JsonObject root);
|
||||||
bool fs_setSettingValue(char ** setting, const char * value, const char * value_default);
|
bool fs_setSettingValue(char ** setting, const char * value, const char * value_default);
|
||||||
@@ -329,25 +329,25 @@ class MyESP {
|
|||||||
uint32_t getSystemLoadAverage();
|
uint32_t getSystemLoadAverage();
|
||||||
uint32_t getSystemResetReason();
|
uint32_t getSystemResetReason();
|
||||||
uint8_t getSystemBootStatus();
|
uint8_t getSystemBootStatus();
|
||||||
bool _have_ntp_time;
|
|
||||||
unsigned long getSystemTime();
|
unsigned long getSystemTime();
|
||||||
void heartbeatPrint();
|
void heartbeatPrint();
|
||||||
|
void heartbeatCheck(bool force = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// mqtt
|
// mqtt
|
||||||
void _mqttOnMessage(char * topic, char * payload, size_t len);
|
void _mqttOnMessage(char * topic, char * payload, size_t len);
|
||||||
void _mqttConnect();
|
void _mqttOnPublish(uint16_t packetId);
|
||||||
void _mqtt_setup();
|
void _mqttConnect();
|
||||||
void _mqttOnConnect();
|
void _mqtt_setup();
|
||||||
void _sendStart();
|
void _mqttOnConnect();
|
||||||
char * _mqttTopic(const char * topic);
|
void _sendStart();
|
||||||
|
char * _mqttTopic(const char * topic);
|
||||||
// mqtt log
|
bool _mqttQueue(const char * topic, const char * payload, bool retain);
|
||||||
_MQTT_Log_t MQTT_log[MYESP_MQTTLOG_MAX]; // log for publish and subscribe messages
|
bool _mqttQueue(const char * topic, JsonDocument & payload, bool retain);
|
||||||
|
void _printMQTTQueue();
|
||||||
void _printMQTTLog();
|
void _mqttPublishQueue();
|
||||||
void _addMQTTLog(const char * topic, const char * payload, const MYESP_MQTTLOGTYPE_t type);
|
void _mqttRemoveLastPublish();
|
||||||
|
void _sendStartTopic();
|
||||||
AsyncMqttClient mqttClient; // the MQTT class
|
AsyncMqttClient mqttClient; // the MQTT class
|
||||||
uint32_t _mqtt_reconnect_delay;
|
uint32_t _mqtt_reconnect_delay;
|
||||||
mqtt_callback_f _mqtt_callback_f;
|
mqtt_callback_f _mqtt_callback_f;
|
||||||
@@ -366,6 +366,8 @@ class MyESP {
|
|||||||
uint32_t _mqtt_last_connection;
|
uint32_t _mqtt_last_connection;
|
||||||
bool _mqtt_connecting;
|
bool _mqtt_connecting;
|
||||||
bool _mqtt_heartbeat;
|
bool _mqtt_heartbeat;
|
||||||
|
bool _mqtt_nestedjson;
|
||||||
|
uint16_t _mqtt_publish_fails;
|
||||||
|
|
||||||
// wifi
|
// wifi
|
||||||
void _wifiCallback(justwifi_messages_t code, char * parameter);
|
void _wifiCallback(justwifi_messages_t code, char * parameter);
|
||||||
@@ -408,20 +410,18 @@ class MyESP {
|
|||||||
void _syslog_setup();
|
void _syslog_setup();
|
||||||
|
|
||||||
// fs and settings
|
// fs and settings
|
||||||
void _fs_setup();
|
void _fs_setup();
|
||||||
bool _fs_loadConfig();
|
bool _fs_loadConfig();
|
||||||
bool _fs_loadCustomConfig();
|
bool _fs_loadCustomConfig();
|
||||||
void _fs_eraseConfig();
|
void _fs_eraseConfig();
|
||||||
bool _fs_writeConfig();
|
bool _fs_writeConfig();
|
||||||
bool _fs_createCustomConfig();
|
bool _fs_createCustomConfig();
|
||||||
bool _fs_sendConfig();
|
bool _fs_sendConfig();
|
||||||
size_t _fs_validateConfigFile(const char * filename, size_t maxsize, JsonDocument & doc);
|
size_t _fs_validateConfigFile(const char * filename, size_t maxsize, JsonDocument & doc);
|
||||||
size_t _fs_validateLogFile(const char * filename);
|
size_t _fs_validateLogFile(const char * filename);
|
||||||
|
|
||||||
fs_loadsave_callback_f _fs_loadsave_callback_f;
|
fs_loadsave_callback_f _fs_loadsave_callback_f;
|
||||||
fs_setlist_callback_f _fs_setlist_callback_f;
|
fs_setlist_callback_f _fs_setlist_callback_f;
|
||||||
|
void _printSetCommands();
|
||||||
void _printSetCommands();
|
|
||||||
|
|
||||||
// general
|
// general
|
||||||
char * _general_hostname;
|
char * _general_hostname;
|
||||||
@@ -444,34 +444,27 @@ class MyESP {
|
|||||||
void _kick();
|
void _kick();
|
||||||
|
|
||||||
// reset reason and rtcmem
|
// reset reason and rtcmem
|
||||||
bool _rtcmem_status;
|
bool _rtcmem_status;
|
||||||
bool _rtcmemStatus();
|
bool _rtcmemStatus();
|
||||||
bool _getRtcmemStatus();
|
bool _getRtcmemStatus();
|
||||||
|
void _rtcmemInit();
|
||||||
void _rtcmemInit();
|
void _rtcmemSetup();
|
||||||
void _rtcmemSetup();
|
void _deferredReset(unsigned long delay, uint8_t reason);
|
||||||
|
|
||||||
void _deferredReset(unsigned long delay, uint8_t reason);
|
|
||||||
|
|
||||||
uint8_t _getSystemStabilityCounter();
|
uint8_t _getSystemStabilityCounter();
|
||||||
void _setSystemStabilityCounter(uint8_t counter);
|
void _setSystemStabilityCounter(uint8_t counter);
|
||||||
|
|
||||||
uint8_t _getSystemDropoutCounter();
|
uint8_t _getSystemDropoutCounter();
|
||||||
void _setSystemDropoutCounter(uint8_t counter);
|
void _setSystemDropoutCounter(uint8_t counter);
|
||||||
void _increaseSystemDropoutCounter();
|
void _increaseSystemDropoutCounter();
|
||||||
|
|
||||||
void _setSystemResetReason(uint8_t reason);
|
void _setSystemResetReason(uint8_t reason);
|
||||||
uint8_t _getCustomResetReason();
|
uint8_t _getCustomResetReason();
|
||||||
void _setCustomResetReason(uint8_t reason);
|
void _setCustomResetReason(uint8_t reason);
|
||||||
uint8_t _getSystemResetReason();
|
uint8_t _getSystemResetReason();
|
||||||
|
void _setSystemBootStatus(uint8_t status);
|
||||||
void _setSystemBootStatus(uint8_t status);
|
bool _systemStable;
|
||||||
|
void _bootupSequence();
|
||||||
bool _systemStable;
|
bool _getSystemCheck();
|
||||||
void _bootupSequence();
|
void _systemCheckLoop();
|
||||||
bool _getSystemCheck();
|
void _setSystemCheck(bool stable);
|
||||||
void _systemCheckLoop();
|
|
||||||
void _setSystemCheck(bool stable);
|
|
||||||
|
|
||||||
// load average (0..100) and heap ram
|
// load average (0..100) and heap ram
|
||||||
void _calculateLoad();
|
void _calculateLoad();
|
||||||
@@ -479,9 +472,6 @@ class MyESP {
|
|||||||
uint32_t _getInitialFreeHeap();
|
uint32_t _getInitialFreeHeap();
|
||||||
uint32_t _getUsedHeap();
|
uint32_t _getUsedHeap();
|
||||||
|
|
||||||
// heartbeat
|
|
||||||
void _heartbeatCheck(bool force = false);
|
|
||||||
|
|
||||||
// web
|
// web
|
||||||
web_callback_f _web_callback_f;
|
web_callback_f _web_callback_f;
|
||||||
const char * _http_username;
|
const char * _http_username;
|
||||||
@@ -500,6 +490,7 @@ class MyESP {
|
|||||||
uint16_t _ntp_interval;
|
uint16_t _ntp_interval;
|
||||||
bool _ntp_enabled;
|
bool _ntp_enabled;
|
||||||
uint8_t _ntp_timezone;
|
uint8_t _ntp_timezone;
|
||||||
|
bool _have_ntp_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MyESP myESP;
|
extern MyESP myESP;
|
||||||
|
|||||||
20
src/Ntp.cpp
20
src/Ntp.cpp
@@ -110,16 +110,16 @@ time_t ICACHE_FLASH_ATTR NtpClient::getNtpTime() {
|
|||||||
time_t UnixUTCtime = (highWord << 16 | lowWord) - 2208988800UL;
|
time_t UnixUTCtime = (highWord << 16 | lowWord) - 2208988800UL;
|
||||||
time_t adjustedtime = (*tz).toLocal(UnixUTCtime, &tcr);
|
time_t adjustedtime = (*tz).toLocal(UnixUTCtime, &tcr);
|
||||||
|
|
||||||
myESP.myDebug("[NTP] Internet time: %02d:%02d:%02d UTC on %d/%d. Local time: %02d:%02d:%02d %s",
|
myESP.myDebug_P(PSTR("[NTP] Internet time: %02d:%02d:%02d UTC on %d/%d. Local time: %02d:%02d:%02d %s"),
|
||||||
to_hour(UnixUTCtime),
|
to_hour(UnixUTCtime),
|
||||||
to_minute(UnixUTCtime),
|
to_minute(UnixUTCtime),
|
||||||
to_second(UnixUTCtime),
|
to_second(UnixUTCtime),
|
||||||
to_day(UnixUTCtime),
|
to_day(UnixUTCtime),
|
||||||
to_month(UnixUTCtime),
|
to_month(UnixUTCtime),
|
||||||
to_hour(adjustedtime),
|
to_hour(adjustedtime),
|
||||||
to_minute(adjustedtime),
|
to_minute(adjustedtime),
|
||||||
to_second(adjustedtime),
|
to_second(adjustedtime),
|
||||||
tcr->abbrev);
|
tcr->abbrev);
|
||||||
|
|
||||||
setTime(adjustedtime);
|
setTime(adjustedtime);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -114,7 +114,7 @@
|
|||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<label class="col-xs-3">Publish Time<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
<label class="col-xs-3">Publish Time<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
||||||
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
||||||
data-content="How often to send MQTT topics with stats. 0 is automatic. (in seconds)"></i></label>
|
data-content="How often to send the MQTT topics in seconds. Must be at least 1"></i></label>
|
||||||
<span class="col-xs-9">
|
<span class="col-xs-9">
|
||||||
<input class="form-control input-sm" placeholder="0" value="" style="display:inline;max-width:185px"
|
<input class="form-control input-sm" placeholder="0" value="" style="display:inline;max-width:185px"
|
||||||
id="publish_time" type="text">
|
id="publish_time" type="text">
|
||||||
@@ -192,10 +192,8 @@
|
|||||||
<td id="b4"></td>
|
<td id="b4"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Boiler Temperature:</th>
|
<th>DHW Temperature:</th>
|
||||||
<td id="b5"></td>
|
<td id="b5"></td>
|
||||||
<th>Return Temperature:</th>
|
|
||||||
<td id="b6"></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ var custom_config = {
|
|||||||
"listen_mode": false,
|
"listen_mode": false,
|
||||||
"shower_timer": false,
|
"shower_timer": false,
|
||||||
"shower_alert": false,
|
"shower_alert": false,
|
||||||
"publish_time": 0,
|
"publish_time": 10,
|
||||||
"tx_mode": 1
|
"tx_mode": 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -99,7 +99,7 @@ function listCustomStats() {
|
|||||||
var l = document.createElement("li");
|
var l = document.createElement("li");
|
||||||
var type = obj[i].type;
|
var type = obj[i].type;
|
||||||
var color = "";
|
var color = "";
|
||||||
if (type === "UBAMaster") {
|
if (type === "Boiler") {
|
||||||
color = "list-group-item-success";
|
color = "list-group-item-success";
|
||||||
} else if (type === "Thermostat") {
|
} else if (type === "Thermostat") {
|
||||||
color = "list-group-item-info";
|
color = "list-group-item-info";
|
||||||
@@ -108,7 +108,7 @@ function listCustomStats() {
|
|||||||
} else if (type === "Heat Pump") {
|
} else if (type === "Heat Pump") {
|
||||||
color = "list-group-item-success";
|
color = "list-group-item-success";
|
||||||
}
|
}
|
||||||
l.innerHTML = obj[i].model + " (Version:" + obj[i].version + " ProductID:" + obj[i].productid + " DeviceID:0x" + obj[i].deviceid + ")";
|
l.innerHTML = obj[i].model + " (DeviceID: 0x" + obj[i].deviceid + ", ProductID: " + obj[i].productid + ", Version: " + obj[i].version + ")";
|
||||||
l.className = "list-group-item " + color;
|
l.className = "list-group-item " + color;
|
||||||
list.appendChild(l);
|
list.appendChild(l);
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,6 @@ function listCustomStats() {
|
|||||||
document.getElementById("b3").innerHTML = ajaxobj.boiler.b3 + " ℃";
|
document.getElementById("b3").innerHTML = ajaxobj.boiler.b3 + " ℃";
|
||||||
document.getElementById("b4").innerHTML = ajaxobj.boiler.b4 + " ℃";
|
document.getElementById("b4").innerHTML = ajaxobj.boiler.b4 + " ℃";
|
||||||
document.getElementById("b5").innerHTML = ajaxobj.boiler.b5 + " ℃";
|
document.getElementById("b5").innerHTML = ajaxobj.boiler.b5 + " ℃";
|
||||||
document.getElementById("b6").innerHTML = ajaxobj.boiler.b6 + " ℃";
|
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("boiler_show").style.display = "none";
|
document.getElementById("boiler_show").style.display = "none";
|
||||||
}
|
}
|
||||||
|
|||||||
99
src/ds18.cpp
99
src/ds18.cpp
@@ -18,24 +18,28 @@ DS18::DS18() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DS18::~DS18() {
|
DS18::~DS18() {
|
||||||
if (_wire)
|
if (_wire) {
|
||||||
delete _wire;
|
delete _wire;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
uint8_t DS18::setup(uint8_t gpio, bool parasite) {
|
void DS18::setup(uint8_t gpio, bool parasite) {
|
||||||
uint8_t count;
|
|
||||||
|
|
||||||
_gpio = gpio;
|
_gpio = gpio;
|
||||||
_parasite = (parasite ? 1 : 0);
|
_parasite = (parasite ? 1 : 0);
|
||||||
|
|
||||||
// OneWire
|
// OneWire
|
||||||
if (_wire)
|
if (_wire) {
|
||||||
delete _wire;
|
delete _wire;
|
||||||
|
}
|
||||||
_wire = new OneWire(_gpio);
|
_wire = new OneWire(_gpio);
|
||||||
|
}
|
||||||
|
|
||||||
// Search devices
|
// clear list and scan for devices
|
||||||
count = loadDevices();
|
uint8_t DS18::scan() {
|
||||||
|
_devices.clear();
|
||||||
|
|
||||||
|
uint8_t count = loadDevices(); // start the search
|
||||||
|
|
||||||
// If no devices found check again pulling up the line
|
// If no devices found check again pulling up the line
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
@@ -48,30 +52,22 @@ uint8_t DS18::setup(uint8_t gpio, bool parasite) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// scan every 2 seconds
|
|
||||||
void DS18::loop() {
|
void DS18::loop() {
|
||||||
static uint32_t last = 0;
|
// we either start a conversion or read the scratchpad
|
||||||
if (millis() - last < DS18_READ_INTERVAL)
|
|
||||||
return;
|
|
||||||
last = millis();
|
|
||||||
|
|
||||||
// Every second we either start a conversion or read the scratchpad
|
|
||||||
static bool conversion = true;
|
static bool conversion = true;
|
||||||
if (conversion) {
|
if (conversion) {
|
||||||
// Start conversion
|
|
||||||
_wire->reset();
|
_wire->reset();
|
||||||
_wire->skip();
|
_wire->skip();
|
||||||
_wire->write(DS18_CMD_START_CONVERSION, _parasite);
|
_wire->write(DS18_CMD_START_CONVERSION, _parasite);
|
||||||
} else {
|
} else {
|
||||||
// Read scratchpads
|
// Read scratchpads
|
||||||
for (unsigned char index = 0; index < _devices.size(); index++) {
|
for (unsigned char index = 0; index < _devices.size(); index++) {
|
||||||
// Read scratchpad
|
|
||||||
if (_wire->reset() == 0) {
|
if (_wire->reset() == 0) {
|
||||||
// Force a CRC check error
|
_devices[index].data[0] = _devices[index].data[0] + 1; // Force a CRC check error
|
||||||
_devices[index].data[0] = _devices[index].data[0] + 1;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read each scratchpad
|
||||||
_wire->select(_devices[index].address);
|
_wire->select(_devices[index].address);
|
||||||
_wire->write(DS18_CMD_READ_SCRATCHPAD);
|
_wire->write(DS18_CMD_READ_SCRATCHPAD);
|
||||||
|
|
||||||
@@ -81,8 +77,7 @@ void DS18::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_wire->reset() != 1) {
|
if (_wire->reset() != 1) {
|
||||||
// Force a CRC check error
|
_devices[index].data[0] = _devices[index].data[0] + 1; // Force a CRC check error
|
||||||
_devices[index].data[0] = _devices[index].data[0] + 1;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +89,7 @@ void DS18::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return string of the device, with name and address
|
// return string of the device, with name and address
|
||||||
char * DS18::getDeviceString(char * buffer, unsigned char index) {
|
char * DS18::getDeviceType(char * buffer, unsigned char index) {
|
||||||
uint8_t size = 128;
|
uint8_t size = 128;
|
||||||
if (index < _count) {
|
if (index < _count) {
|
||||||
unsigned char chip_id = chip(index);
|
unsigned char chip_id = chip(index);
|
||||||
@@ -109,25 +104,22 @@ char * DS18::getDeviceString(char * buffer, unsigned char index) {
|
|||||||
} else {
|
} else {
|
||||||
strlcpy(buffer, "Unknown", size);
|
strlcpy(buffer, "Unknown", size);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
strlcpy(buffer, "invalid", size);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return string of the device, with name and address
|
||||||
|
char * DS18::getDeviceID(char * buffer, unsigned char index) {
|
||||||
|
uint8_t size = 128;
|
||||||
|
if (index < _count) {
|
||||||
uint8_t * address = _devices[index].address;
|
uint8_t * address = _devices[index].address;
|
||||||
char a[30] = {0};
|
char a[30] = {0};
|
||||||
snprintf(a,
|
snprintf(a, sizeof(a), "%02X%02X%02X%02X%02X%02X%02X%02X", address[0], address[1], address[2], address[3], address[4], address[5], address[6], address[7]);
|
||||||
sizeof(a),
|
|
||||||
" (%02X%02X%02X%02X%02X%02X%02X%02X) @ GPIO%d",
|
|
||||||
address[0],
|
|
||||||
address[1],
|
|
||||||
address[2],
|
|
||||||
address[3],
|
|
||||||
address[4],
|
|
||||||
address[5],
|
|
||||||
address[6],
|
|
||||||
address[7],
|
|
||||||
_gpio);
|
|
||||||
|
|
||||||
strlcat(buffer, a, size);
|
strlcpy(buffer, a, size);
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
strlcpy(buffer, "invalid", size);
|
strlcpy(buffer, "invalid", size);
|
||||||
}
|
}
|
||||||
@@ -153,8 +145,9 @@ char * DS18::getDeviceString(char * buffer, unsigned char index) {
|
|||||||
byte 8: SCRATCHPAD_CRC
|
byte 8: SCRATCHPAD_CRC
|
||||||
*/
|
*/
|
||||||
int16_t DS18::getRawValue(unsigned char index) {
|
int16_t DS18::getRawValue(unsigned char index) {
|
||||||
if (index >= _count)
|
if (index >= _count) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t * data = _devices[index].data;
|
uint8_t * data = _devices[index].data;
|
||||||
|
|
||||||
@@ -170,23 +163,35 @@ int16_t DS18::getRawValue(unsigned char index) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
byte cfg = (data[4] & 0x60);
|
byte cfg = (data[4] & 0x60);
|
||||||
if (cfg == 0x00)
|
if (cfg == 0x00) {
|
||||||
raw = raw & ~7; // 9 bit res, 93.75 ms
|
raw = raw & ~7; // 9 bit res, 93.75 ms
|
||||||
else if (cfg == 0x20)
|
} else if (cfg == 0x20) {
|
||||||
raw = raw & ~3; // 10 bit res, 187.5 ms
|
raw = raw & ~3; // 10 bit res, 187.5 ms
|
||||||
else if (cfg == 0x40)
|
} else if (cfg == 0x40) {
|
||||||
raw = raw & ~1; // 11 bit res, 375 ms
|
raw = raw & ~1; // 11 bit res, 375 ms
|
||||||
// 12 bit res, 750 ms
|
// 12 bit res, 750 ms
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return real value as a float
|
// return real value as a float, rounded to 2 decimal places
|
||||||
// The raw temperature data is in units of sixteenths of a degree, so the value must be divided by 16 in order to convert it to degrees.
|
|
||||||
float DS18::getValue(unsigned char index) {
|
float DS18::getValue(unsigned char index) {
|
||||||
float value = (float)getRawValue(index) / 16.0;
|
int16_t raw_value = getRawValue(index);
|
||||||
return value;
|
|
||||||
|
// check if valid
|
||||||
|
if ((raw_value == DS18_CRC_ERROR) || (raw_value == DS18_DISCONNECTED)) {
|
||||||
|
return (float)DS18_DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The raw temperature data is in units of sixteenths of a degree,
|
||||||
|
// so the value must first be divided by 16 in order to convert it to degrees.
|
||||||
|
float new_value = (float)(raw_value / 16.0);
|
||||||
|
|
||||||
|
// round to 2 decimal places
|
||||||
|
// https://arduinojson.org/v6/faq/how-to-configure-the-serialization-of-floats/
|
||||||
|
return (int)(new_value * 100 + 0.5) / 100.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for a supported DS chip version
|
// check for a supported DS chip version
|
||||||
@@ -196,8 +201,9 @@ bool DS18::validateID(unsigned char id) {
|
|||||||
|
|
||||||
// return the type
|
// return the type
|
||||||
unsigned char DS18::chip(unsigned char index) {
|
unsigned char DS18::chip(unsigned char index) {
|
||||||
if (index < _count)
|
if (index < _count) {
|
||||||
return _devices[index].address[0];
|
return _devices[index].address[0];
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,6 +212,7 @@ uint8_t DS18::loadDevices() {
|
|||||||
uint8_t address[8];
|
uint8_t address[8];
|
||||||
_wire->reset();
|
_wire->reset();
|
||||||
_wire->reset_search();
|
_wire->reset_search();
|
||||||
|
|
||||||
while (_wire->search(address)) {
|
while (_wire->search(address)) {
|
||||||
// Check CRC
|
// Check CRC
|
||||||
if (_wire->crc8(address, 7) == address[7]) {
|
if (_wire->crc8(address, 7) == address[7]) {
|
||||||
|
|||||||
@@ -36,9 +36,11 @@ class DS18 {
|
|||||||
DS18();
|
DS18();
|
||||||
~DS18();
|
~DS18();
|
||||||
|
|
||||||
uint8_t setup(uint8_t gpio, bool parasite);
|
void setup(uint8_t gpio, bool parasite);
|
||||||
|
uint8_t scan();
|
||||||
void loop();
|
void loop();
|
||||||
char * getDeviceString(char * s, unsigned char index);
|
char * getDeviceType(char * s, unsigned char index);
|
||||||
|
char * getDeviceID(char * buffer, unsigned char index);
|
||||||
float getValue(unsigned char index);
|
float getValue(unsigned char index);
|
||||||
int16_t getRawValue(unsigned char index); // raw values, needs / 16
|
int16_t getRawValue(unsigned char index); // raw values, needs / 16
|
||||||
|
|
||||||
|
|||||||
2021
src/ems-esp.cpp
2021
src/ems-esp.cpp
File diff suppressed because it is too large
Load Diff
2028
src/ems.cpp
2028
src/ems.cpp
File diff suppressed because it is too large
Load Diff
433
src/ems.h
433
src/ems.h
@@ -12,6 +12,9 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <list> // std::list
|
#include <list> // std::list
|
||||||
|
|
||||||
|
// EMS bus IDs
|
||||||
|
#define EMS_BUSID_DEFAULT 0x0B // Default 0x0B (Service Key)
|
||||||
|
|
||||||
// EMS tx_mode types
|
// EMS tx_mode types
|
||||||
#define EMS_TXMODE_DEFAULT 1 // Default (was previously known as tx_mode 2 in v1.8.x)
|
#define EMS_TXMODE_DEFAULT 1 // Default (was previously known as tx_mode 2 in v1.8.x)
|
||||||
#define EMS_TXMODE_EMSPLUS 2 // EMS+
|
#define EMS_TXMODE_EMSPLUS 2 // EMS+
|
||||||
@@ -26,11 +29,12 @@
|
|||||||
#define EMS_VALUE_BOOL_ON 0x01 // boolean true
|
#define EMS_VALUE_BOOL_ON 0x01 // boolean true
|
||||||
#define EMS_VALUE_BOOL_ON2 0xFF // boolean true, EMS sometimes uses 0xFF for TRUE
|
#define EMS_VALUE_BOOL_ON2 0xFF // boolean true, EMS sometimes uses 0xFF for TRUE
|
||||||
#define EMS_VALUE_BOOL_OFF 0x00 // boolean false
|
#define EMS_VALUE_BOOL_OFF 0x00 // boolean false
|
||||||
#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit unsigned ints/bytes
|
|
||||||
#define EMS_VALUE_SHORT_NOTSET -32768 // for 2-byte signed shorts
|
|
||||||
#define EMS_VALUE_USHORT_NOTSET 0x8000 // for 2-byte unsigned shorts
|
|
||||||
#define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs
|
|
||||||
#define EMS_VALUE_BOOL_NOTSET 0xFE // random number that's not 0, 1 or FF
|
#define EMS_VALUE_BOOL_NOTSET 0xFE // random number that's not 0, 1 or FF
|
||||||
|
#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit unsigned ints/bytes
|
||||||
|
#define EMS_VALUE_SHORT_NOTSET -32000 // 0x8300 for 2-byte signed shorts
|
||||||
|
#define EMS_VALUE_USHORT_NOTSET 32000 // 0x7D00 (was 0x8000) for 2-byte unsigned shorts
|
||||||
|
#define EMS_VALUE_USHORT_NOTVALID 0x8000 // 0x8000 for 2-byte unsigned shorts
|
||||||
|
#define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs
|
||||||
|
|
||||||
// thermostat specific
|
// thermostat specific
|
||||||
#define EMS_THERMOSTAT_MAXHC 4 // max number of heating circuits
|
#define EMS_THERMOSTAT_MAXHC 4 // max number of heating circuits
|
||||||
@@ -38,36 +42,40 @@
|
|||||||
#define EMS_THERMOSTAT_WRITE_YES true
|
#define EMS_THERMOSTAT_WRITE_YES true
|
||||||
#define EMS_THERMOSTAT_WRITE_NO false
|
#define EMS_THERMOSTAT_WRITE_NO false
|
||||||
|
|
||||||
|
// mixing specific
|
||||||
|
#define EMS_MIXING_MAXHC 4 // max number of heating circuits
|
||||||
|
#define EMS_MIXING_MAXWWC 2 // max number of warm water circuits
|
||||||
|
|
||||||
// Device Flags
|
// Device Flags
|
||||||
#define EMS_DEVICE_FLAG_NONE 0 // no flags set
|
// They are unique to the model type (mixing, solar, thermostat etc)
|
||||||
#define EMS_DEVICE_FLAG_SM10 10 // solar module1
|
enum EMS_DEVICE_FLAG_TYPES : uint8_t {
|
||||||
#define EMS_DEVICE_FLAG_SM100 11 // solar module2
|
EMS_DEVICE_FLAG_NONE = 0,
|
||||||
|
EMS_DEVICE_FLAG_MMPLUS = 20, // mixing EMS+
|
||||||
// group flags specific for thermostats
|
EMS_DEVICE_FLAG_MM10 = 21, // mixing MM10
|
||||||
#define EMS_DEVICE_FLAG_NO_WRITE 0x80 // top bit set if write not supported
|
EMS_DEVICE_FLAG_SM10 = 10,
|
||||||
#define EMS_DEVICE_FLAG_EASY 1
|
EMS_DEVICE_FLAG_SM100 = 11, // for SM100 and SM200
|
||||||
#define EMS_DEVICE_FLAG_RC10 2
|
EMS_DEVICE_FLAG_EASY = 1,
|
||||||
#define EMS_DEVICE_FLAG_RC20 3
|
EMS_DEVICE_FLAG_RC10 = 2,
|
||||||
#define EMS_DEVICE_FLAG_RC30 4
|
EMS_DEVICE_FLAG_RC20 = 3,
|
||||||
#define EMS_DEVICE_FLAG_RC35 5
|
EMS_DEVICE_FLAG_RC30 = 4,
|
||||||
#define EMS_DEVICE_FLAG_RC300 6
|
EMS_DEVICE_FLAG_RC30N = 5, // newer type of RC30 with RC35 circuit
|
||||||
#define EMS_DEVICE_FLAG_JUNKERS 7
|
EMS_DEVICE_FLAG_RC35 = 6,
|
||||||
|
EMS_DEVICE_FLAG_RC100 = 7,
|
||||||
typedef enum {
|
EMS_DEVICE_FLAG_RC300 = 8,
|
||||||
EMS_THERMOSTAT_MODE_UNKNOWN,
|
EMS_DEVICE_FLAG_RC20N = 9,
|
||||||
EMS_THERMOSTAT_MODE_OFF,
|
EMS_DEVICE_FLAG_JUNKERS1 = 31, // use 0x65 for HC
|
||||||
EMS_THERMOSTAT_MODE_MANUAL,
|
EMS_DEVICE_FLAG_JUNKERS2 = 32, // use 0x79 for HC, older models
|
||||||
EMS_THERMOSTAT_MODE_AUTO,
|
EMS_DEVICE_FLAG_JUNKERS = (1 << 6), // 6th bit set if its junkers HT3
|
||||||
EMS_THERMOSTAT_MODE_NIGHT,
|
EMS_DEVICE_FLAG_NO_WRITE = (1 << 7) // top bit set if thermostat write not supported
|
||||||
EMS_THERMOSTAT_MODE_DAY
|
};
|
||||||
} _EMS_THERMOSTAT_MODE;
|
|
||||||
|
|
||||||
// trigger settings to determine if hot tap water or the heating is active
|
// trigger settings to determine if hot tap water or the heating is active
|
||||||
#define EMS_BOILER_BURNPOWER_TAPWATER 100
|
#define EMS_BOILER_BURNPOWER_TAPWATER 100
|
||||||
#define EMS_BOILER_SELFLOWTEMP_HEATING 30 // was 70, changed to 30 for https://github.com/proddy/EMS-ESP/issues/193
|
#define EMS_BOILER_SELFLOWTEMP_HEATING 20 // was originally 70, changed to 30 for issue #193, then to 20 with issue #344
|
||||||
|
|
||||||
// define maximum setable tapwater temperature
|
// define min & maximum setable tapwater temperatures
|
||||||
#define EMS_BOILER_TAPWATER_TEMPERATURE_MAX 60
|
#define EMS_BOILER_TAPWATER_TEMPERATURE_MAX 60
|
||||||
|
#define EMS_BOILER_TAPWATER_TEMPERATURE_MIN 30
|
||||||
|
|
||||||
#define EMS_TX_TELEGRAM_QUEUE_MAX 50 // max size of Tx FIFO queue. Number of Tx records to send.
|
#define EMS_TX_TELEGRAM_QUEUE_MAX 50 // max size of Tx FIFO queue. Number of Tx records to send.
|
||||||
|
|
||||||
@@ -106,55 +114,42 @@ typedef enum {
|
|||||||
|
|
||||||
/* EMS logging */
|
/* EMS logging */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EMS_SYS_LOGGING_NONE, // no messages
|
EMS_SYS_LOGGING_NONE, // no messages
|
||||||
EMS_SYS_LOGGING_RAW, // raw data mode
|
EMS_SYS_LOGGING_RAW, // raw data mode
|
||||||
EMS_SYS_LOGGING_WATCH, // watch a specific type ID
|
EMS_SYS_LOGGING_WATCH, // watch a specific type ID
|
||||||
EMS_SYS_LOGGING_BASIC, // only basic read/write messages
|
EMS_SYS_LOGGING_BASIC, // only basic read/write messages
|
||||||
EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat
|
EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat
|
||||||
EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from thermostat
|
EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from solar module
|
||||||
EMS_SYS_LOGGING_VERBOSE, // everything
|
EMS_SYS_LOGGING_MIXINGMODULE, // only telegrams sent from mixing module
|
||||||
EMS_SYS_LOGGING_JABBER // lots of debug output...
|
EMS_SYS_LOGGING_VERBOSE, // everything
|
||||||
|
EMS_SYS_LOGGING_JABBER, // lots of debug output...
|
||||||
|
EMS_SYS_LOGGING_DEVICE // watch the device ID
|
||||||
} _EMS_SYS_LOGGING;
|
} _EMS_SYS_LOGGING;
|
||||||
|
|
||||||
// status/counters since last power on
|
// status/counters since last power on
|
||||||
typedef struct {
|
typedef struct {
|
||||||
_EMS_RX_STATUS emsRxStatus;
|
_EMS_RX_STATUS emsRxStatus;
|
||||||
_EMS_TX_STATUS emsTxStatus;
|
_EMS_TX_STATUS emsTxStatus;
|
||||||
uint16_t emsRxPgks; // # successfull received
|
uint16_t emsRxPgks; // # successfull received
|
||||||
uint16_t emsTxPkgs; // # successfull sent
|
uint16_t emsTxPkgs; // # successfull sent
|
||||||
uint16_t emxCrcErr; // CRC errors
|
uint16_t emxCrcErr; // CRC errors
|
||||||
bool emsPollEnabled; // flag enable the response to poll messages
|
bool emsPollEnabled; // flag enable the response to poll messages
|
||||||
_EMS_SYS_LOGGING emsLogging; // logging
|
_EMS_SYS_LOGGING emsLogging; // logging
|
||||||
uint16_t emsLogging_typeID; // the typeID to watch
|
uint16_t emsLogging_ID; // the type or device ID to watch
|
||||||
uint8_t emsRefreshedFlags; // fresh data, needs to be pushed out to MQTT
|
uint8_t emsRefreshedFlags; // fresh data, needs to be pushed out to MQTT
|
||||||
bool emsBusConnected; // is there an active bus
|
bool emsBusConnected; // is there an active bus
|
||||||
uint32_t emsRxTimestamp; // timestamp of last EMS message received
|
uint32_t emsRxTimestamp; // timestamp of last EMS message received
|
||||||
uint32_t emsPollFrequency; // time between EMS polls
|
uint32_t emsPollFrequency; // time between EMS polls
|
||||||
bool emsTxCapable; // able to send via Tx
|
bool emsTxCapable; // able to send via Tx
|
||||||
bool emsTxDisabled; // true to prevent all Tx
|
bool emsTxDisabled; // true to prevent all Tx
|
||||||
uint8_t txRetryCount; // # times the last Tx was re-sent
|
uint8_t txRetryCount; // # times the last Tx was re-sent
|
||||||
uint8_t emsIDMask; // Buderus: 0x00, Junkers: 0x80
|
uint8_t emsIDMask; // Buderus: 0x00, Junkers: 0x80
|
||||||
uint8_t emsPollAck[1]; // acknowledge buffer for Poll
|
uint8_t emsPollAck[1]; // acknowledge buffer for Poll
|
||||||
uint8_t emsTxMode; // Tx mode 1, 2 or 3
|
uint8_t emsTxMode; // Tx mode 1, 2 or 3
|
||||||
char emsDeviceMap[EMS_SYS_DEVICEMAP_LENGTH]; // contents of 0x07 telegram with bitmasks for all active EMS devices
|
uint8_t emsbusid; // EMS bus ID, default 0x0B for Service Key
|
||||||
|
uint8_t emsMasterThermostat; // product ID for the default thermostat to use
|
||||||
} _EMS_Sys_Status;
|
} _EMS_Sys_Status;
|
||||||
|
|
||||||
// The Tx send package
|
|
||||||
typedef struct {
|
|
||||||
_EMS_TX_TELEGRAM_ACTION action; // read, write, validate, init
|
|
||||||
uint8_t dest;
|
|
||||||
uint16_t type;
|
|
||||||
uint8_t offset;
|
|
||||||
uint8_t length; // full length of complete telegram, including CRC
|
|
||||||
uint8_t dataValue; // value to validate against
|
|
||||||
uint16_t type_validate; // type to call after a successful Write command
|
|
||||||
uint8_t comparisonValue; // value to compare against during a validate command
|
|
||||||
uint8_t comparisonOffset; // offset of where the byte is we want to compare too during validation
|
|
||||||
uint16_t comparisonPostRead; // after a successful write, do a read from this type ID
|
|
||||||
unsigned long timestamp; // when created
|
|
||||||
uint8_t data[EMS_MAX_TELEGRAM_LENGTH];
|
|
||||||
} _EMS_TxTelegram;
|
|
||||||
|
|
||||||
// The Rx receive package
|
// The Rx receive package
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned long timestamp; // timestamp from millis()
|
unsigned long timestamp; // timestamp from millis()
|
||||||
@@ -170,6 +165,23 @@ typedef struct {
|
|||||||
uint8_t emsplus_type; // FF, F7 or F9
|
uint8_t emsplus_type; // FF, F7 or F9
|
||||||
} _EMS_RxTelegram;
|
} _EMS_RxTelegram;
|
||||||
|
|
||||||
|
// The Tx send package
|
||||||
|
typedef struct {
|
||||||
|
_EMS_TX_TELEGRAM_ACTION action; // read, write, validate, init
|
||||||
|
uint8_t dest;
|
||||||
|
uint16_t type;
|
||||||
|
uint8_t offset;
|
||||||
|
uint8_t length; // full length of complete telegram, including CRC
|
||||||
|
bool emsplus; // true if ems+/ems 2.0
|
||||||
|
uint8_t dataValue; // value to validate against
|
||||||
|
uint16_t type_validate; // type to call after a successful Write command
|
||||||
|
uint8_t comparisonValue; // value to compare against during a validate command
|
||||||
|
uint8_t comparisonOffset; // offset of where the byte is we want to compare too during validation
|
||||||
|
uint16_t comparisonPostRead; // after a successful write, do a read from this type ID
|
||||||
|
unsigned long timestamp; // when created
|
||||||
|
uint8_t data[EMS_MAX_TELEGRAM_LENGTH];
|
||||||
|
} _EMS_TxTelegram;
|
||||||
|
|
||||||
// default empty Tx, must match struct
|
// default empty Tx, must match struct
|
||||||
const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = {
|
const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = {
|
||||||
EMS_TX_TELEGRAM_INIT, // action
|
EMS_TX_TELEGRAM_INIT, // action
|
||||||
@@ -177,7 +189,8 @@ const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = {
|
|||||||
EMS_ID_NONE, // type
|
EMS_ID_NONE, // type
|
||||||
0, // offset
|
0, // offset
|
||||||
0, // length
|
0, // length
|
||||||
0, // data value
|
false, // emsplus (no)
|
||||||
|
0, // dataValue
|
||||||
EMS_ID_NONE, // type_validate
|
EMS_ID_NONE, // type_validate
|
||||||
0, // comparisonValue
|
0, // comparisonValue
|
||||||
0, // comparisonOffset
|
0, // comparisonOffset
|
||||||
@@ -193,7 +206,8 @@ typedef enum : uint8_t {
|
|||||||
EMS_DEVICE_UPDATE_FLAG_THERMOSTAT = (1 << 1),
|
EMS_DEVICE_UPDATE_FLAG_THERMOSTAT = (1 << 1),
|
||||||
EMS_DEVICE_UPDATE_FLAG_MIXING = (1 << 2),
|
EMS_DEVICE_UPDATE_FLAG_MIXING = (1 << 2),
|
||||||
EMS_DEVICE_UPDATE_FLAG_SOLAR = (1 << 3),
|
EMS_DEVICE_UPDATE_FLAG_SOLAR = (1 << 3),
|
||||||
EMS_DEVICE_UPDATE_FLAG_HEATPUMP = (1 << 4)
|
EMS_DEVICE_UPDATE_FLAG_HEATPUMP = (1 << 4),
|
||||||
|
EMS_DEVICE_UPDATE_FLAG_SETTINGS = (1 << 5)
|
||||||
} _EMS_DEVICE_UPDATE_FLAG;
|
} _EMS_DEVICE_UPDATE_FLAG;
|
||||||
|
|
||||||
typedef enum : uint8_t {
|
typedef enum : uint8_t {
|
||||||
@@ -205,13 +219,36 @@ typedef enum : uint8_t {
|
|||||||
EMS_DEVICE_TYPE_SOLAR,
|
EMS_DEVICE_TYPE_SOLAR,
|
||||||
EMS_DEVICE_TYPE_HEATPUMP,
|
EMS_DEVICE_TYPE_HEATPUMP,
|
||||||
EMS_DEVICE_TYPE_GATEWAY,
|
EMS_DEVICE_TYPE_GATEWAY,
|
||||||
EMS_DEVICE_TYPE_OTHER,
|
|
||||||
EMS_DEVICE_TYPE_SWITCH,
|
EMS_DEVICE_TYPE_SWITCH,
|
||||||
EMS_DEVICE_TYPE_CONTROLLER,
|
EMS_DEVICE_TYPE_CONTROLLER,
|
||||||
EMS_DEVICE_TYPE_CONNECT,
|
EMS_DEVICE_TYPE_CONNECT,
|
||||||
EMS_DEVICE_TYPE_UNKNOWN
|
EMS_DEVICE_TYPE_UNKNOWN
|
||||||
} _EMS_DEVICE_TYPE;
|
} _EMS_DEVICE_TYPE;
|
||||||
|
|
||||||
|
// to store mapping of device_ids to their string name
|
||||||
|
typedef struct {
|
||||||
|
_EMS_DEVICE_TYPE device_type;
|
||||||
|
char device_type_string[30];
|
||||||
|
} _EMS_Device_Types;
|
||||||
|
|
||||||
|
// mapping for EMS_Devices_Type
|
||||||
|
const _EMS_Device_Types EMS_Devices_Types[] = {
|
||||||
|
|
||||||
|
{EMS_DEVICE_TYPE_UNKNOWN, EMS_MODELTYPE_UNKNOWN_STRING}, // the first, at index 0 is reserved for "unknown"
|
||||||
|
{EMS_DEVICE_TYPE_NONE, "All"},
|
||||||
|
{EMS_DEVICE_TYPE_SERVICEKEY, "Me"},
|
||||||
|
{EMS_DEVICE_TYPE_BOILER, "Boiler"},
|
||||||
|
{EMS_DEVICE_TYPE_THERMOSTAT, "Thermostat"},
|
||||||
|
{EMS_DEVICE_TYPE_MIXING, "Mixing Module"},
|
||||||
|
{EMS_DEVICE_TYPE_SOLAR, "Solar Module"},
|
||||||
|
{EMS_DEVICE_TYPE_HEATPUMP, "Heat Pump"},
|
||||||
|
{EMS_DEVICE_TYPE_GATEWAY, "Gateway"},
|
||||||
|
{EMS_DEVICE_TYPE_SWITCH, "Switching Module"},
|
||||||
|
{EMS_DEVICE_TYPE_CONTROLLER, "Controller"},
|
||||||
|
{EMS_DEVICE_TYPE_CONNECT, "Connect Module"}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
// to store all known EMS devices to date
|
// to store all known EMS devices to date
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t product_id;
|
uint8_t product_id;
|
||||||
@@ -220,13 +257,6 @@ typedef struct {
|
|||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
} _EMS_Device;
|
} _EMS_Device;
|
||||||
|
|
||||||
// to store mapping of device_ids to their string name
|
|
||||||
typedef struct {
|
|
||||||
uint8_t device_id;
|
|
||||||
_EMS_DEVICE_TYPE device_type;
|
|
||||||
char device_type_string[30];
|
|
||||||
} _EMS_Device_Types;
|
|
||||||
|
|
||||||
// for storing all recognised EMS devices
|
// for storing all recognised EMS devices
|
||||||
typedef struct {
|
typedef struct {
|
||||||
_EMS_DEVICE_TYPE device_type; // type (see above)
|
_EMS_DEVICE_TYPE device_type; // type (see above)
|
||||||
@@ -248,18 +278,25 @@ typedef struct {
|
|||||||
uint8_t product_id;
|
uint8_t product_id;
|
||||||
char version[10];
|
char version[10];
|
||||||
|
|
||||||
|
uint8_t brand; // 0=unknown, 1=bosch, 2=junkers, 3=buderus, 4=nefit, 5=sieger, 11=worcester
|
||||||
|
|
||||||
// UBAParameterWW
|
// UBAParameterWW
|
||||||
uint8_t wWActivated; // Warm Water activated
|
uint8_t wWActivated; // Warm Water activated
|
||||||
uint8_t wWSelTemp; // Warm Water selected temperature
|
uint8_t wWSelTemp; // Warm Water selected temperature
|
||||||
uint8_t wWCircPump; // Warm Water circulation pump Available
|
uint8_t wWCircPump; // Warm Water circulation pump Available
|
||||||
uint8_t wWDesiredTemp; // Warm Water desired temperature
|
uint8_t wWCircPumpMode; // Warm Water circulation pump mode (1 = 1x3min, ..., 6=6x3min, 7 continuous)
|
||||||
uint8_t wWComfort; // Warm water comfort or ECO mode
|
uint8_t wWCircPumpType; // Warm Water circulation pump type (0 = charge pump, 0xff = 3-way pump)
|
||||||
|
uint8_t wWDesinfectTemp; // Warm Water desinfection temperature
|
||||||
|
uint8_t wWComfort; // Warm water comfort or ECO mode
|
||||||
|
|
||||||
// UBAMonitorFast
|
// UBAMonitorFast
|
||||||
uint8_t selFlowTemp; // Selected flow temperature
|
uint8_t selFlowTemp; // Selected flow temperature
|
||||||
uint16_t curFlowTemp; // Current flow temperature
|
uint16_t curFlowTemp; // Current flow temperature
|
||||||
|
uint16_t wwStorageTemp1; // warm water storage temp 1
|
||||||
|
uint16_t wwStorageTemp2; // warm water storage temp 2
|
||||||
uint16_t retTemp; // Return temperature
|
uint16_t retTemp; // Return temperature
|
||||||
uint8_t burnGas; // Gas on/off
|
uint8_t burnGas; // Gas on/off
|
||||||
|
uint8_t wWMode; // warm water mode
|
||||||
uint8_t fanWork; // Fan on/off
|
uint8_t fanWork; // Fan on/off
|
||||||
uint8_t ignWork; // Ignition on/off
|
uint8_t ignWork; // Ignition on/off
|
||||||
uint8_t heatPmp; // Circulating pump on/off
|
uint8_t heatPmp; // Circulating pump on/off
|
||||||
@@ -275,6 +312,7 @@ typedef struct {
|
|||||||
// UBAMonitorSlow
|
// UBAMonitorSlow
|
||||||
int16_t extTemp; // Outside temperature
|
int16_t extTemp; // Outside temperature
|
||||||
uint16_t boilTemp; // Boiler temperature
|
uint16_t boilTemp; // Boiler temperature
|
||||||
|
uint16_t exhaustTemp; // Exhaust temperature
|
||||||
uint8_t pumpMod; // Pump modulation
|
uint8_t pumpMod; // Pump modulation
|
||||||
uint32_t burnStarts; // # burner starts
|
uint32_t burnStarts; // # burner starts
|
||||||
uint32_t burnWorkMin; // Total burner operating time
|
uint32_t burnWorkMin; // Total burner operating time
|
||||||
@@ -282,11 +320,17 @@ typedef struct {
|
|||||||
uint16_t switchTemp; // Switch temperature
|
uint16_t switchTemp; // Switch temperature
|
||||||
|
|
||||||
// UBAMonitorWWMessage
|
// UBAMonitorWWMessage
|
||||||
uint16_t wWCurTmp; // Warm Water current temperature
|
uint8_t wWSetTmp; // set temp WW (DHW)
|
||||||
uint32_t wWStarts; // Warm Water # starts
|
uint16_t wWCurTmp; // Warm Water current temperature
|
||||||
uint32_t wWWorkM; // Warm Water # minutes
|
uint16_t wWCurTmp2; // Warm Water current temperature storage
|
||||||
uint8_t wWOneTime; // Warm Water one time function on/off
|
uint32_t wWStarts; // Warm Water # starts
|
||||||
uint8_t wWCurFlow; // Warm Water current flow in l/min
|
uint32_t wWWorkM; // Warm Water # minutes
|
||||||
|
uint8_t wWOneTime; // Warm Water one time function on/off
|
||||||
|
uint8_t wWDesinfecting; // Warm Water desinfection on/off
|
||||||
|
uint8_t wWReadiness; // Warm Water readiness on/off
|
||||||
|
uint8_t wWRecharging; // Warm Water recharge on/off
|
||||||
|
uint8_t wWTemperatureOK; // Warm Water temperature ok on/off
|
||||||
|
uint8_t wWCurFlow; // Warm Water current flow in l/min
|
||||||
|
|
||||||
// UBATotalUptimeMessage
|
// UBATotalUptimeMessage
|
||||||
uint32_t UBAuptime; // Total UBA working hours
|
uint32_t UBAuptime; // Total UBA working hours
|
||||||
@@ -299,7 +343,6 @@ typedef struct {
|
|||||||
// calculated values
|
// calculated values
|
||||||
uint8_t tapwaterActive; // Hot tap water is on/off
|
uint8_t tapwaterActive; // Hot tap water is on/off
|
||||||
uint8_t heatingActive; // Central heating is on/off
|
uint8_t heatingActive; // Central heating is on/off
|
||||||
|
|
||||||
} _EMS_Boiler;
|
} _EMS_Boiler;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -322,34 +365,46 @@ typedef struct {
|
|||||||
uint16_t flowTemp;
|
uint16_t flowTemp;
|
||||||
uint8_t pumpMod;
|
uint8_t pumpMod;
|
||||||
uint8_t valveStatus;
|
uint8_t valveStatus;
|
||||||
} _EMS_Mixing_HC;
|
uint8_t flowSetTemp;
|
||||||
|
} _EMS_MixingModule_HC;
|
||||||
|
|
||||||
// Mixer data
|
// Mixing Module per WWC
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t device_id;
|
uint8_t wwc; // warm water circuit 1, 2
|
||||||
uint8_t device_flags;
|
bool active; // true if there is data for this WWC
|
||||||
const char * device_desc_p;
|
uint16_t flowTemp;
|
||||||
uint8_t product_id;
|
uint8_t pumpMod;
|
||||||
char version[10];
|
uint8_t tempStatus;
|
||||||
bool detected;
|
} _EMS_MixingModule_WWC;
|
||||||
_EMS_Mixing_HC hc[EMS_THERMOSTAT_MAXHC]; // array for the 4 heating circuits
|
|
||||||
} _EMS_Mixing;
|
|
||||||
|
|
||||||
// Solar Module - SM10/SM100/ISM1
|
// Mixing data
|
||||||
|
typedef struct {
|
||||||
|
uint8_t device_id;
|
||||||
|
uint8_t device_flags;
|
||||||
|
const char * device_desc_p;
|
||||||
|
uint8_t product_id;
|
||||||
|
char version[10];
|
||||||
|
_EMS_MixingModule_HC hc[EMS_MIXING_MAXHC]; // array for the 4 heating circuits
|
||||||
|
_EMS_MixingModule_WWC wwc[EMS_MIXING_MAXWWC]; // array for the 2 ww circuits
|
||||||
|
} _EMS_MixingModule;
|
||||||
|
|
||||||
|
// Solar Module - SM10/SM100/SM200/ISM1
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t device_id; // the device ID of the Solar Module
|
uint8_t device_id; // the device ID of the Solar Module
|
||||||
uint8_t device_flags; // Solar Module flags
|
uint8_t device_flags; // Solar Module flags
|
||||||
const char * device_desc_p;
|
const char * device_desc_p;
|
||||||
uint8_t product_id;
|
uint8_t product_id;
|
||||||
char version[10];
|
char version[10];
|
||||||
int16_t collectorTemp; // collector temp
|
int16_t collectorTemp; // collector temp (TS1)
|
||||||
int16_t bottomTemp; // bottom temp
|
int16_t bottomTemp; // bottom temp (TS2)
|
||||||
|
int16_t bottomTemp2; // bottom temp cylinder 2 (TS5)
|
||||||
uint8_t pumpModulation; // modulation solar pump
|
uint8_t pumpModulation; // modulation solar pump
|
||||||
uint8_t pump; // pump active
|
uint8_t pump; // pump active
|
||||||
|
uint8_t valveStatus; // valve status (VS2)
|
||||||
int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp
|
int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp
|
||||||
uint16_t EnergyLastHour;
|
uint32_t EnergyLastHour;
|
||||||
uint16_t EnergyToday;
|
uint32_t EnergyToday;
|
||||||
uint16_t EnergyTotal;
|
uint32_t EnergyTotal;
|
||||||
uint32_t pumpWorkMin; // Total solar pump operating time
|
uint32_t pumpWorkMin; // Total solar pump operating time
|
||||||
} _EMS_SolarModule;
|
} _EMS_SolarModule;
|
||||||
|
|
||||||
@@ -360,7 +415,7 @@ typedef struct {
|
|||||||
int16_t setpoint_roomTemp; // current set temp
|
int16_t setpoint_roomTemp; // current set temp
|
||||||
int16_t curr_roomTemp; // current room temp
|
int16_t curr_roomTemp; // current room temp
|
||||||
uint8_t mode; // 0=low, 1=manual, 2=auto (or night, day on RC35s)
|
uint8_t mode; // 0=low, 1=manual, 2=auto (or night, day on RC35s)
|
||||||
uint8_t day_mode; // 0=night, 1=day
|
uint8_t mode_type; // 0=night/eco, 1=day/comfort
|
||||||
uint8_t summer_mode;
|
uint8_t summer_mode;
|
||||||
uint8_t holiday_mode;
|
uint8_t holiday_mode;
|
||||||
uint8_t daytemp;
|
uint8_t daytemp;
|
||||||
@@ -372,13 +427,22 @@ typedef struct {
|
|||||||
|
|
||||||
// Thermostat data
|
// Thermostat data
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t device_id; // the device ID of the thermostat
|
uint8_t device_id; // the device ID of the thermostat
|
||||||
uint8_t device_flags; // thermostat model flags
|
uint8_t device_flags; // thermostat model flags
|
||||||
const char * device_desc_p;
|
const char * device_desc_p;
|
||||||
uint8_t product_id;
|
uint8_t product_id;
|
||||||
char version[10];
|
char version[10];
|
||||||
char datetime[25]; // HH:MM:SS DD/MM/YYYY
|
char datetime[25]; // HH:MM:SS DD/MM/YYYY
|
||||||
bool write_supported;
|
bool write_supported;
|
||||||
|
|
||||||
|
// Installation parameters (tested on RC30)
|
||||||
|
uint8_t ibaMainDisplay; // 00, display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp
|
||||||
|
uint8_t ibaLanguage; // 01, language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian
|
||||||
|
uint8_t ibaCalIntTemperature; // 02, offset int. temperature sensor, by * 0.1 Kelvin
|
||||||
|
int16_t ibaMinExtTemperature; // 05, min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 (actually a int8_t, coded as int16_t to benefit from negative value rendering)
|
||||||
|
uint8_t ibaBuildingType; // 06, building type: 0 = light, 1 = medium, 2 = heavy
|
||||||
|
uint8_t ibaClockOffset; // 12, offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
||||||
|
|
||||||
_EMS_Thermostat_HC hc[EMS_THERMOSTAT_MAXHC]; // array for the 4 heating circuits
|
_EMS_Thermostat_HC hc[EMS_THERMOSTAT_MAXHC]; // array for the 4 heating circuits
|
||||||
} _EMS_Thermostat;
|
} _EMS_Thermostat;
|
||||||
|
|
||||||
@@ -393,49 +457,93 @@ typedef struct {
|
|||||||
EMS_processType_cb processType_cb;
|
EMS_processType_cb processType_cb;
|
||||||
} _EMS_Type;
|
} _EMS_Type;
|
||||||
|
|
||||||
|
typedef enum : uint8_t {
|
||||||
|
EMS_THERMOSTAT_MODE_UNKNOWN = 0,
|
||||||
|
EMS_THERMOSTAT_MODE_OFF,
|
||||||
|
EMS_THERMOSTAT_MODE_MANUAL,
|
||||||
|
EMS_THERMOSTAT_MODE_AUTO,
|
||||||
|
EMS_THERMOSTAT_MODE_HEAT, // 'heizen'
|
||||||
|
EMS_THERMOSTAT_MODE_NIGHT,
|
||||||
|
EMS_THERMOSTAT_MODE_DAY,
|
||||||
|
EMS_THERMOSTAT_MODE_ECO, // 'sparen'
|
||||||
|
EMS_THERMOSTAT_MODE_COMFORT,
|
||||||
|
EMS_THERMOSTAT_MODE_HOLIDAY,
|
||||||
|
EMS_THERMOSTAT_MODE_NOFROST
|
||||||
|
} _EMS_THERMOSTAT_MODE;
|
||||||
|
|
||||||
|
#define EMS_THERMOSTAT_MODE_UNKNOWN_STR "unknown"
|
||||||
|
#define EMS_THERMOSTAT_MODE_OFF_STR "off"
|
||||||
|
#define EMS_THERMOSTAT_MODE_MANUAL_STR "manual"
|
||||||
|
#define EMS_THERMOSTAT_MODE_AUTO_STR "auto"
|
||||||
|
#define EMS_THERMOSTAT_MODE_HEAT_STR "heat"
|
||||||
|
#define EMS_THERMOSTAT_MODE_NIGHT_STR "night"
|
||||||
|
#define EMS_THERMOSTAT_MODE_DAY_STR "day"
|
||||||
|
#define EMS_THERMOSTAT_MODE_ECO_STR "eco"
|
||||||
|
#define EMS_THERMOSTAT_MODE_COMFORT_STR "comfort"
|
||||||
|
#define EMS_THERMOSTAT_MODE_HOLIDAY_STR "holiday"
|
||||||
|
#define EMS_THERMOSTAT_MODE_NOFROST_STR "nofrost"
|
||||||
|
|
||||||
// function definitions
|
// function definitions
|
||||||
void ems_dumpBuffer(const char * prefix, uint8_t * telegram, uint8_t length);
|
void ems_dumpBuffer(const char * prefix, uint8_t * telegram, uint8_t length);
|
||||||
void ems_parseTelegram(uint8_t * telegram, uint8_t len);
|
void ems_parseTelegram(uint8_t * telegram, uint8_t len);
|
||||||
void ems_init();
|
void ems_init();
|
||||||
void ems_doReadCommand(uint16_t type, uint8_t dest);
|
void ems_doReadCommand(uint16_t type, uint8_t dest, uint8_t offset = 0);
|
||||||
void ems_sendRawTelegram(char * telegram);
|
void ems_sendRawTelegram(char * telegram);
|
||||||
void ems_scanDevices();
|
void ems_printDevices();
|
||||||
void ems_printDevices();
|
uint8_t ems_printDevices_s(char * buffer, uint16_t len);
|
||||||
uint8_t ems_printDevices_s(char * buffer, uint16_t len);
|
void ems_printTxQueue();
|
||||||
void ems_printTxQueue();
|
void ems_testTelegram(uint8_t test_num);
|
||||||
void ems_testTelegram(uint8_t test_num);
|
void ems_startupTelegrams();
|
||||||
void ems_startupTelegrams();
|
bool ems_checkEMSBUSAlive();
|
||||||
bool ems_checkEMSBUSAlive();
|
|
||||||
void ems_clearDeviceList();
|
void ems_setSettingsLanguage(uint8_t lg);
|
||||||
void ems_setThermostatTemp(float temperature, uint8_t hc, uint8_t temptype = 0);
|
void ems_setSettingsBuilding(uint8_t bg);
|
||||||
void ems_setThermostatMode(uint8_t mode, uint8_t hc);
|
void ems_setSettingsDisplay(uint8_t ds);
|
||||||
void ems_setWarmWaterTemp(uint8_t temperature);
|
|
||||||
void ems_setFlowTemp(uint8_t temperature);
|
void ems_setThermostatTemp(float temperature, uint8_t hc, _EMS_THERMOSTAT_MODE temptype);
|
||||||
void ems_setWarmWaterActivated(bool activated);
|
void ems_setThermostatTemp(float temperature, uint8_t hc, const char * mode_s);
|
||||||
void ems_setWarmWaterOnetime(bool activated);
|
void ems_setThermostatMode(_EMS_THERMOSTAT_MODE mode, uint8_t hc);
|
||||||
void ems_setWarmTapWaterActivated(bool activated);
|
void ems_setThermostatMode(const char * mode_s, uint8_t hc);
|
||||||
void ems_setPoll(bool b);
|
void ems_setWarmWaterTemp(uint8_t temperature);
|
||||||
void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t type_id = 0);
|
void ems_setFlowTemp(uint8_t temperature);
|
||||||
void ems_setWarmWaterModeComfort(uint8_t comfort);
|
void ems_setWarmWaterActivated(bool activated);
|
||||||
void ems_setModels();
|
void ems_setWarmWaterOnetime(bool activated);
|
||||||
void ems_setTxDisabled(bool b);
|
void ems_setWarmWaterCirculation(bool activated);
|
||||||
void ems_setTxMode(uint8_t mode);
|
void ems_setWarmTapWaterActivated(bool activated);
|
||||||
char * ems_getDeviceDescription(_EMS_DEVICE_TYPE device_type, char * buffer, bool name_only = false);
|
void ems_setPoll(bool b);
|
||||||
bool ems_getDeviceTypeDescription(uint8_t device_id, char * buffer);
|
void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t type_id);
|
||||||
void ems_getThermostatValues();
|
void ems_setLogging(_EMS_SYS_LOGGING loglevel, bool quiet = false);
|
||||||
void ems_getBoilerValues();
|
void ems_setWarmWaterModeComfort(uint8_t comfort);
|
||||||
void ems_getSolarModuleValues();
|
void ems_setModels();
|
||||||
bool ems_getPoll();
|
void ems_setTxDisabled(bool b);
|
||||||
bool ems_getTxEnabled();
|
void ems_setTxMode(uint8_t mode);
|
||||||
bool ems_getThermostatEnabled();
|
void ems_setEMSbusid(uint8_t id);
|
||||||
bool ems_getMixingDeviceEnabled();
|
void ems_setMasterThermostat(uint8_t product_id);
|
||||||
bool ems_getBoilerEnabled();
|
|
||||||
bool ems_getSolarModuleEnabled();
|
char * ems_getDeviceDescription(_EMS_DEVICE_TYPE device_type, char * buffer, bool name_only = false);
|
||||||
bool ems_getHeatPumpEnabled();
|
bool ems_getDeviceTypeDescription(uint8_t device_id, char * buffer);
|
||||||
|
char * ems_getDeviceTypeName(_EMS_DEVICE_TYPE device_type, char * buffer);
|
||||||
|
_EMS_THERMOSTAT_MODE ems_getThermostatMode(const char * mode_s);
|
||||||
|
void ems_getThermostatValues();
|
||||||
|
void ems_getBoilerValues();
|
||||||
|
void ems_getSettingsValues();
|
||||||
|
void ems_getSolarModuleValues();
|
||||||
|
void ems_getMixingModuleValues();
|
||||||
|
char * ems_getThermostatModeString(_EMS_THERMOSTAT_MODE mode, char * mode_str);
|
||||||
|
|
||||||
|
bool ems_getPoll();
|
||||||
|
bool ems_getTxEnabled();
|
||||||
|
|
||||||
|
bool ems_getThermostatEnabled();
|
||||||
|
bool ems_getMixingModuleEnabled();
|
||||||
|
bool ems_getBoilerEnabled();
|
||||||
|
bool ems_getSolarModuleEnabled();
|
||||||
|
bool ems_getHeatPumpEnabled();
|
||||||
|
|
||||||
bool ems_getBusConnected();
|
bool ems_getBusConnected();
|
||||||
_EMS_SYS_LOGGING ems_getLogging();
|
_EMS_SYS_LOGGING ems_getLogging();
|
||||||
uint8_t ems_getThermostatModel();
|
uint8_t ems_getThermostatFlags();
|
||||||
uint8_t ems_getSolarModuleModel();
|
uint8_t ems_getSolarModuleFlags();
|
||||||
void ems_discoverModels();
|
void ems_discoverModels();
|
||||||
bool ems_getTxCapable();
|
bool ems_getTxCapable();
|
||||||
uint32_t ems_getPollFrequency();
|
uint32_t ems_getPollFrequency();
|
||||||
@@ -443,6 +551,8 @@ bool ems_getTxDisabled();
|
|||||||
void ems_Device_add_flags(unsigned int flags);
|
void ems_Device_add_flags(unsigned int flags);
|
||||||
bool ems_Device_has_flags(unsigned int flags);
|
bool ems_Device_has_flags(unsigned int flags);
|
||||||
void ems_Device_remove_flags(unsigned int flags);
|
void ems_Device_remove_flags(unsigned int flags);
|
||||||
|
bool ems_isHT3();
|
||||||
|
void ems_scanDevices();
|
||||||
|
|
||||||
// private functions
|
// private functions
|
||||||
uint8_t _crcCalculator(uint8_t * data, uint8_t len);
|
uint8_t _crcCalculator(uint8_t * data, uint8_t len);
|
||||||
@@ -450,14 +560,15 @@ void _processType(_EMS_RxTelegram * EMS_RxTelegram);
|
|||||||
void _debugPrintPackage(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram, const char * color);
|
void _debugPrintPackage(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram, const char * color);
|
||||||
void _ems_clearTxData();
|
void _ems_clearTxData();
|
||||||
void _removeTxQueue();
|
void _removeTxQueue();
|
||||||
uint8_t _getHeatingCircuit(_EMS_RxTelegram * EMS_RxTelegram);
|
int8_t _getHeatingCircuit(_EMS_RxTelegram * EMS_RxTelegram);
|
||||||
|
void _printMessage(_EMS_RxTelegram * EMS_RxTelegram, const int show_type = -1);
|
||||||
|
|
||||||
// global so can referenced in other classes
|
// global so can referenced in other classes
|
||||||
extern _EMS_Sys_Status EMS_Sys_Status;
|
extern _EMS_Sys_Status EMS_Sys_Status;
|
||||||
extern _EMS_Boiler EMS_Boiler;
|
extern _EMS_Boiler EMS_Boiler;
|
||||||
extern _EMS_Thermostat EMS_Thermostat;
|
extern _EMS_Thermostat EMS_Thermostat;
|
||||||
extern _EMS_SolarModule EMS_SolarModule;
|
extern _EMS_SolarModule EMS_SolarModule;
|
||||||
extern _EMS_HeatPump EMS_HeatPump;
|
extern _EMS_HeatPump EMS_HeatPump;
|
||||||
extern _EMS_Mixing EMS_Mixing;
|
extern _EMS_MixingModule EMS_MixingModule;
|
||||||
|
|
||||||
extern std::list<_Detected_Device> Devices;
|
extern std::list<_Detected_Device> Devices;
|
||||||
|
|||||||
@@ -12,41 +12,7 @@
|
|||||||
#include "ems.h"
|
#include "ems.h"
|
||||||
|
|
||||||
// Fixed EMS Device IDs
|
// Fixed EMS Device IDs
|
||||||
#define EMS_ID_ME 0x0B // our device, hardcoded as the "Service Key"
|
#define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08
|
||||||
#define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08
|
|
||||||
#define EMS_ID_SM 0x30 // Solar Module SM10, SM100 and ISM1
|
|
||||||
#define EMS_ID_HP 0x38 // HeatPump
|
|
||||||
#define EMS_ID_GATEWAY 0x48 // Gateway e.g. KM200 Web Gateway
|
|
||||||
#define EMS_ID_MIXING1 0x20 // Mixing
|
|
||||||
#define EMS_ID_MIXING2 0x21 // Mixing
|
|
||||||
#define EMS_ID_SWITCH 0x11 // Switch
|
|
||||||
#define EMS_ID_CONTROLLER 0x09 // Controller
|
|
||||||
#define EMS_ID_CONNECT1 0x02 // Connect
|
|
||||||
#define EMS_ID_CONNECT2 0x50 // Connect
|
|
||||||
#define EMS_ID_THERMOSTAT1 0x10 // Thermostat
|
|
||||||
#define EMS_ID_THERMOSTAT2 0x17 // Thermostat
|
|
||||||
#define EMS_ID_THERMOSTAT3 0x18 // Thermostat
|
|
||||||
|
|
||||||
// mapping for EMS_Devices_Type
|
|
||||||
const _EMS_Device_Types EMS_Devices_Types[] = {
|
|
||||||
|
|
||||||
{EMS_ID_BOILER, EMS_DEVICE_TYPE_BOILER, "UBAMaster"},
|
|
||||||
{EMS_ID_THERMOSTAT1, EMS_DEVICE_TYPE_THERMOSTAT, "Thermostat"},
|
|
||||||
{EMS_ID_THERMOSTAT2, EMS_DEVICE_TYPE_THERMOSTAT, "Thermostat"},
|
|
||||||
{EMS_ID_THERMOSTAT3, EMS_DEVICE_TYPE_THERMOSTAT, "Thermostat"},
|
|
||||||
{EMS_ID_SM, EMS_DEVICE_TYPE_SOLAR, "Solar Module"},
|
|
||||||
{EMS_ID_HP, EMS_DEVICE_TYPE_HEATPUMP, "Heat Pump"},
|
|
||||||
{EMS_ID_GATEWAY, EMS_DEVICE_TYPE_GATEWAY, "Gateway"},
|
|
||||||
{EMS_ID_ME, EMS_DEVICE_TYPE_SERVICEKEY, "Me"},
|
|
||||||
{EMS_ID_NONE, EMS_DEVICE_TYPE_NONE, "All"},
|
|
||||||
{EMS_ID_MIXING1, EMS_DEVICE_TYPE_MIXING, "Mixing Module"},
|
|
||||||
{EMS_ID_MIXING2, EMS_DEVICE_TYPE_MIXING, "Mixing Module"},
|
|
||||||
{EMS_ID_SWITCH, EMS_DEVICE_TYPE_SWITCH, "Switching Module"},
|
|
||||||
{EMS_ID_CONTROLLER, EMS_DEVICE_TYPE_CONTROLLER, "Controller"},
|
|
||||||
{EMS_ID_CONNECT1, EMS_DEVICE_TYPE_CONNECT, "Connect"},
|
|
||||||
{EMS_ID_CONNECT2, EMS_DEVICE_TYPE_CONNECT, "Connect"}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Common Type
|
* Common Type
|
||||||
@@ -61,6 +27,7 @@ const _EMS_Device_Types EMS_Devices_Types[] = {
|
|||||||
#define EMS_TYPE_UBAMonitorSlow 0x19 // is an automatic monitor broadcast
|
#define EMS_TYPE_UBAMonitorSlow 0x19 // is an automatic monitor broadcast
|
||||||
#define EMS_TYPE_UBAMonitorWWMessage 0x34 // is an automatic monitor broadcast
|
#define EMS_TYPE_UBAMonitorWWMessage 0x34 // is an automatic monitor broadcast
|
||||||
#define EMS_TYPE_UBAMaintenanceStatusMessage 0x1C // is an automatic monitor broadcast
|
#define EMS_TYPE_UBAMaintenanceStatusMessage 0x1C // is an automatic monitor broadcast
|
||||||
|
#define EMS_TYPE_MC10Status 0x2A
|
||||||
#define EMS_TYPE_UBAParameterWW 0x33
|
#define EMS_TYPE_UBAParameterWW 0x33
|
||||||
#define EMS_TYPE_UBATotalUptimeMessage 0x14
|
#define EMS_TYPE_UBATotalUptimeMessage 0x14
|
||||||
#define EMS_TYPE_UBAFlags 0x35
|
#define EMS_TYPE_UBAFlags 0x35
|
||||||
@@ -77,6 +44,7 @@ const _EMS_Device_Types EMS_Devices_Types[] = {
|
|||||||
#define EMS_OFFSET_UBAParameterWW_wwtemp 2 // WW Temperature
|
#define EMS_OFFSET_UBAParameterWW_wwtemp 2 // WW Temperature
|
||||||
#define EMS_OFFSET_UBAParameterWW_wwactivated 1 // WW Activated
|
#define EMS_OFFSET_UBAParameterWW_wwactivated 1 // WW Activated
|
||||||
#define EMS_OFFSET_UBAParameterWW_wwOneTime 0x00 // WW OneTime loading
|
#define EMS_OFFSET_UBAParameterWW_wwOneTime 0x00 // WW OneTime loading
|
||||||
|
#define EMS_OFFSET_UBAParameterWW_wwCirulation 1 // WW circulation
|
||||||
#define EMS_OFFSET_UBAParameterWW_wwComfort 9 // WW is in comfort or eco mode
|
#define EMS_OFFSET_UBAParameterWW_wwComfort 9 // WW is in comfort or eco mode
|
||||||
#define EMS_VALUE_UBAParameterWW_wwComfort_Hot 0x00 // the value for hot
|
#define EMS_VALUE_UBAParameterWW_wwComfort_Hot 0x00 // the value for hot
|
||||||
#define EMS_VALUE_UBAParameterWW_wwComfort_Eco 0xD8 // the value for eco
|
#define EMS_VALUE_UBAParameterWW_wwComfort_Eco 0xD8 // the value for eco
|
||||||
@@ -84,19 +52,73 @@ const _EMS_Device_Types EMS_Devices_Types[] = {
|
|||||||
|
|
||||||
#define EMS_OFFSET_UBASetPoints_flowtemp 0 // flow temp
|
#define EMS_OFFSET_UBASetPoints_flowtemp 0 // flow temp
|
||||||
|
|
||||||
// SM and HP Types
|
// Installation settings
|
||||||
|
#define EMS_TYPE_IBASettingsMessage 0xA5 // installation settings
|
||||||
|
#define EMS_OFFSET_IBASettings_Display 0 // display
|
||||||
|
#define EMS_OFFSET_IBASettings_Language 1 // language
|
||||||
|
#define EMS_OFFSET_IBASettings_MinExtTemp 5 // min. ext. temperature
|
||||||
|
#define EMS_OFFSET_IBASettings_Building 6 // building
|
||||||
|
#define EMS_OFFSET_IBASettings_CalIntTemp 2 // cal. int. temperature
|
||||||
|
#define EMS_OFFSET_IBASettings_ClockOffset 12 // clock offset
|
||||||
|
|
||||||
|
#define EMS_VALUE_IBASettings_LANG_GERMAN 0
|
||||||
|
#define EMS_VALUE_IBASettings_LANG_DUTCH 1
|
||||||
|
#define EMS_VALUE_IBASettings_LANG_FRENCH 2
|
||||||
|
#define EMS_VALUE_IBASettings_LANG_ITALIAN 3
|
||||||
|
|
||||||
|
#define EMS_VALUE_IBASettings_BUILDING_LIGHT 0
|
||||||
|
#define EMS_VALUE_IBASettings_BUILDING_MEDIUM 1
|
||||||
|
#define EMS_VALUE_IBASettings_BUILDING_HEAVY 2
|
||||||
|
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_INTTEMP 0
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_INTSETPOINT 1
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_EXTTEMP 2
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_BURNERTEMP 3
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_WWTEMP 4
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_FUNCMODE 5
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_TIME 6
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_DATE 7
|
||||||
|
#define EMS_VALUE_IBASettings_DISPLAY_SMOKETEMP 9
|
||||||
|
|
||||||
|
// Mixing Modules
|
||||||
|
// MM100/MM200 (EMS Plus)
|
||||||
|
#define EMS_TYPE_MMPLUSStatusMessage_HC1 0x01D7 // mixing status HC1
|
||||||
|
#define EMS_TYPE_MMPLUSStatusMessage_HC2 0x01D8 // mixing status HC2
|
||||||
|
#define EMS_TYPE_MMPLUSStatusMessage_HC3 0x01D9 // mixing status HC3
|
||||||
|
#define EMS_TYPE_MMPLUSStatusMessage_HC4 0x01DA // mixing status HC4
|
||||||
|
#define EMS_TYPE_MMPLUSStatusMessage_WWC1 0x0231 // mixing status WWC1
|
||||||
|
#define EMS_TYPE_MMPLUSStatusMessage_WWC2 0x0232 // mixing status WWC2
|
||||||
|
#define EMS_OFFSET_MMPLUSStatusMessage_flow_temp 3 // flow temperature
|
||||||
|
#define EMS_OFFSET_MMPLUSStatusMessage_pump_mod 5 // pump modulation
|
||||||
|
#define EMS_OFFSET_MMPLUSStatusMessage_valve_status 2 // valve in percent
|
||||||
|
#define EMS_OFFSET_MMPLUSStatusMessage_WW_flow_temp 0 // flow temperature
|
||||||
|
#define EMS_OFFSET_MMPLUSStatusMessage_WW_pump_mod 2 // pump on 6, off 0
|
||||||
|
#define EMS_OFFSET_MMPLUSStatusMessage_WW_temp_status 11 // 0,1,2
|
||||||
|
|
||||||
|
// MM10
|
||||||
|
#define EMS_TYPE_MMStatusMessage 0xAB // mixing status
|
||||||
|
#define EMS_OFFSET_MMStatusMessage_flow_set 0 // flow setpoint
|
||||||
|
#define EMS_OFFSET_MMStatusMessage_flow_temp 1 // flow temperature
|
||||||
|
#define EMS_OFFSET_MMStatusMessage_pump_mod 3 // pump modulation in percent
|
||||||
|
#define EMS_OFFSET_MMStatusMessage_valve_status 4 // valve 0..255
|
||||||
|
#define EMS_TYPE_MM10ParameterMessage 0xAC // mixing parameters
|
||||||
|
|
||||||
|
// Solar Module
|
||||||
|
// Assuming here that the SM200 behaves like SM100
|
||||||
#define EMS_TYPE_SM10Monitor 0x97 // SM10Monitor
|
#define EMS_TYPE_SM10Monitor 0x97 // SM10Monitor
|
||||||
#define EMS_TYPE_SM100Monitor 0x0262 // SM100Monitor
|
#define EMS_TYPE_SM100Monitor 0x0262 // SM100Monitor
|
||||||
#define EMS_TYPE_SM100Status 0x0264 // SM100Status
|
#define EMS_TYPE_SM100Status 0x0264 // SM100Status
|
||||||
#define EMS_TYPE_SM100Status2 0x026A // SM100Status2
|
#define EMS_TYPE_SM100Status2 0x026A // SM100Status2
|
||||||
#define EMS_TYPE_SM100Energy 0x028E // SM100Energy
|
#define EMS_TYPE_SM100Energy 0x028E // SM100Energy
|
||||||
#define EMS_TYPE_HPMonitor1 0xE3 // HeatPump Monitor 1
|
// ISPM solar module
|
||||||
#define EMS_TYPE_HPMonitor2 0xE5 // HeatPump Monitor 2
|
|
||||||
|
|
||||||
#define EMS_TYPE_ISM1StatusMessage 0x0003 // Solar Module Junkers ISM1 Status
|
#define EMS_TYPE_ISM1StatusMessage 0x0003 // Solar Module Junkers ISM1 Status
|
||||||
#define EMS_TYPE_ISM1Set 0x0001 // for setting values of the solar module like max boiler temp
|
#define EMS_TYPE_ISM1Set 0x0001 // for setting values of the solar module like max boiler temp
|
||||||
#define EMS_OFFSET_ISM1Set_MaxBoilerTemp 6 // position of max boiler temp e.g. 50 in the following example: 90 30 FF 06 00 01 50 (CRC=2C)
|
#define EMS_OFFSET_ISM1Set_MaxBoilerTemp 6 // position of max boiler temp e.g. 50 in the following example: 90 30 FF 06 00 01 50 (CRC=2C)
|
||||||
|
|
||||||
|
// Heat Pump
|
||||||
|
#define EMS_TYPE_HPMonitor1 0xE3 // HeatPump Monitor 1
|
||||||
|
#define EMS_TYPE_HPMonitor2 0xE5 // HeatPump Monitor 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Thermostat Types
|
* Thermostat Types
|
||||||
*/
|
*/
|
||||||
@@ -118,6 +140,16 @@ const _EMS_Device_Types EMS_Devices_Types[] = {
|
|||||||
#define EMS_OFFSET_RC20StatusMessage_setpoint 1 // setpoint temp
|
#define EMS_OFFSET_RC20StatusMessage_setpoint 1 // setpoint temp
|
||||||
#define EMS_OFFSET_RC20StatusMessage_curr 2 // current temp
|
#define EMS_OFFSET_RC20StatusMessage_curr 2 // current temp
|
||||||
|
|
||||||
|
#define EMS_TYPE_RC20NStatusMessage 0xAE
|
||||||
|
#define EMS_OFFSET_RC20NStatusMessage_setpoint 2 // setpoint temp in AE
|
||||||
|
#define EMS_OFFSET_RC20NStatusMessage_curr 3 // current temp in AE
|
||||||
|
|
||||||
|
#define EMS_TYPE_RC20NSet 0xAD
|
||||||
|
#define EMS_OFFSET_RC20NSet_temp_day 2 // position of thermostat setpoint temperature for day time
|
||||||
|
#define EMS_OFFSET_RC20NSet_temp_night 1 // position of thermostat setpoint temperature for night time
|
||||||
|
#define EMS_OFFSET_RC20NSet_mode 3 // position mode
|
||||||
|
#define EMS_OFFSET_RC20NSet_heatingtype 0
|
||||||
|
|
||||||
#define EMS_TYPE_RC20Set 0xA8 // for setting values like temp and mode
|
#define EMS_TYPE_RC20Set 0xA8 // for setting values like temp and mode
|
||||||
#define EMS_OFFSET_RC20Set_mode 23 // position of thermostat mode
|
#define EMS_OFFSET_RC20Set_mode 23 // position of thermostat mode
|
||||||
#define EMS_OFFSET_RC20Set_temp 28 // position of thermostat setpoint temperature
|
#define EMS_OFFSET_RC20Set_temp 28 // position of thermostat setpoint temperature
|
||||||
@@ -142,7 +174,6 @@ const _EMS_Device_Types EMS_Devices_Types[] = {
|
|||||||
#define EMS_OFFSET_RC35StatusMessage_mode 1 // day mode, also summer on RC3's
|
#define EMS_OFFSET_RC35StatusMessage_mode 1 // day mode, also summer on RC3's
|
||||||
#define EMS_OFFSET_RC35StatusMessage_mode1 0 // for holiday mode
|
#define EMS_OFFSET_RC35StatusMessage_mode1 0 // for holiday mode
|
||||||
|
|
||||||
|
|
||||||
#define EMS_TYPE_RC35Set_HC1 0x3D // for setting values like temp and mode (Working mode HC1)
|
#define EMS_TYPE_RC35Set_HC1 0x3D // for setting values like temp and mode (Working mode HC1)
|
||||||
#define EMS_TYPE_RC35Set_HC2 0x47 // for setting values like temp and mode (Working mode HC2)
|
#define EMS_TYPE_RC35Set_HC2 0x47 // for setting values like temp and mode (Working mode HC2)
|
||||||
#define EMS_TYPE_RC35Set_HC3 0x51 // for setting values like temp and mode (Working mode HC3)
|
#define EMS_TYPE_RC35Set_HC3 0x51 // for setting values like temp and mode (Working mode HC3)
|
||||||
@@ -151,9 +182,10 @@ const _EMS_Device_Types EMS_Devices_Types[] = {
|
|||||||
#define EMS_OFFSET_RC35Set_mode 7 // position of thermostat mode
|
#define EMS_OFFSET_RC35Set_mode 7 // position of thermostat mode
|
||||||
#define EMS_OFFSET_RC35Set_temp_day 2 // position of thermostat setpoint temperature for day time
|
#define EMS_OFFSET_RC35Set_temp_day 2 // position of thermostat setpoint temperature for day time
|
||||||
#define EMS_OFFSET_RC35Set_temp_night 1 // position of thermostat setpoint temperature for night time
|
#define EMS_OFFSET_RC35Set_temp_night 1 // position of thermostat setpoint temperature for night time
|
||||||
#define EMS_OFFSET_RC35Set_temp_holiday 3 // temp during holiday 0x47
|
#define EMS_OFFSET_RC35Set_temp_holiday 3 // temp during holiday mode
|
||||||
#define EMS_OFFSET_RC35Set_heatingtype 0 // floor heating = 3 0x47
|
#define EMS_OFFSET_RC35Set_heatingtype 0 // e.g. floor heating = 3
|
||||||
#define EMS_OFFSET_RC35Set_circuitcalctemp 14 // calculated circuit temperature 0x48
|
#define EMS_OFFSET_RC35Set_circuitcalctemp 14 // calculated circuit temperature
|
||||||
|
#define EMS_OFFSET_RC35Set_seltemp 37 // selected temp
|
||||||
|
|
||||||
// Easy specific
|
// Easy specific
|
||||||
#define EMS_TYPE_EasyStatusMessage 0x0A // reading values on an Easy Thermostat
|
#define EMS_TYPE_EasyStatusMessage 0x0A // reading values on an Easy Thermostat
|
||||||
@@ -180,21 +212,38 @@ const _EMS_Device_Types EMS_Devices_Types[] = {
|
|||||||
#define EMS_OFFSET_RCPLUSSet_temp_setpoint 8 // temp setpoint, when changing of templevel (in auto) value is reset and set to FF
|
#define EMS_OFFSET_RCPLUSSet_temp_setpoint 8 // temp setpoint, when changing of templevel (in auto) value is reset and set to FF
|
||||||
#define EMS_OFFSET_RCPLUSSet_manual_setpoint 10 // manual setpoint
|
#define EMS_OFFSET_RCPLUSSet_manual_setpoint 10 // manual setpoint
|
||||||
|
|
||||||
// Junkers FR10, FR50, FW100 (EMS Plus)
|
// Junkers FR10, FR50, FW100, FW120 (EMS Plus)
|
||||||
#define EMS_TYPE_JunkersStatusMessage 0x6F // is an automatic thermostat broadcast giving us temps
|
// HC1 = 0x6F-0x72
|
||||||
|
#define EMS_TYPE_JunkersStatusMessage_HC1 0x6F
|
||||||
|
#define EMS_TYPE_JunkersStatusMessage_HC2 0x70
|
||||||
|
#define EMS_TYPE_JunkersStatusMessage_HC3 0x71
|
||||||
|
#define EMS_TYPE_JunkersStatusMessage_HC4 0x72
|
||||||
|
|
||||||
#define EMS_OFFSET_JunkersStatusMessage_daymode 0 // 3 = day, 2 = night
|
#define EMS_OFFSET_JunkersStatusMessage_daymode 0 // 3 = day, 2 = night
|
||||||
#define EMS_OFFSET_JunkersStatusMessage_mode 1 // current mode, 1 = manual, 2 = auto
|
#define EMS_OFFSET_JunkersStatusMessage_mode 1 // current mode, 1 = manual, 2 = auto
|
||||||
#define EMS_OFFSET_JunkersStatusMessage_setpoint 2 // setpoint temp
|
#define EMS_OFFSET_JunkersStatusMessage_setpoint 2 // setpoint temp
|
||||||
#define EMS_OFFSET_JunkersStatusMessage_curr 4 // current temp
|
#define EMS_OFFSET_JunkersStatusMessage_curr 4 // current temp
|
||||||
|
|
||||||
// MM100 (EMS Plus)
|
// HC1-4 0x65-0x68 - EMS_DEVICE_FLAG_JUNKERS1
|
||||||
#define EMS_TYPE_MMPLUSStatusMessage_HC1 0x01D7 // mixer status HC1
|
// Junkers FR10, FR50, FW100, FW120
|
||||||
#define EMS_TYPE_MMPLUSStatusMessage_HC2 0x01D8 // mixer status HC2
|
#define EMS_TYPE_JunkersSetMessage1_HC1 0x65
|
||||||
#define EMS_TYPE_MMPLUSStatusMessage_HC3 0x01D9 // mixer status HC3
|
#define EMS_TYPE_JunkersSetMessage1_HC2 0x66
|
||||||
#define EMS_TYPE_MMPLUSStatusMessage_HC4 0x01DA // mixer status HC4
|
#define EMS_TYPE_JunkersSetMessage1_HC3 0x67
|
||||||
#define EMS_OFFSET_MMPLUSStatusMessage_flow_temp 3 // flow temperature
|
#define EMS_TYPE_JunkersSetMessage1_HC4 0x68
|
||||||
#define EMS_OFFSET_MMPLUSStatusMessage_pump_mod 5 // pump modulation
|
#define EMS_OFFSET_JunkersSetMessage_day_temp 0x11 // EMS offset to set temperature on thermostat for day mode
|
||||||
#define EMS_OFFSET_MMPLUSStatusMessage_valve_status 2 // valve in percent
|
#define EMS_OFFSET_JunkersSetMessage_night_temp 0x10 // EMS offset to set temperature on thermostat for night mode
|
||||||
|
#define EMS_OFFSET_JunkersSetMessage_no_frost_temp 0x0F // EMS offset to set temperature on thermostat for no frost mode
|
||||||
|
#define EMS_OFFSET_JunkersSetMessage_set_mode 0x0E // EMS offset to set mode on thermostat
|
||||||
|
|
||||||
|
// HC1-4 0x79-0x7C - EMS_DEVICE_FLAG_JUNKERS2
|
||||||
|
// Junkers FR100
|
||||||
|
#define EMS_TYPE_JunkersSetMessage2_HC1 0x79
|
||||||
|
#define EMS_TYPE_JunkersSetMessage2_HC2 0x7A
|
||||||
|
#define EMS_TYPE_JunkersSetMessage2_HC3 0x7B
|
||||||
|
#define EMS_TYPE_JunkersSetMessage2_HC4 0x7C
|
||||||
|
#define EMS_OFFSET_JunkersSetMessage2_no_frost_temp 0x05
|
||||||
|
#define EMS_OFFSET_JunkersSetMessage2_eco_temp 0x06
|
||||||
|
#define EMS_OFFSET_JunkersSetMessage3_heat 0x07
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Table of all known EMS Devices
|
* Table of all known EMS Devices
|
||||||
@@ -203,7 +252,7 @@ const _EMS_Device_Types EMS_Devices_Types[] = {
|
|||||||
static const _EMS_Device EMS_Devices[] = {
|
static const _EMS_Device EMS_Devices[] = {
|
||||||
|
|
||||||
//
|
//
|
||||||
// UBA Masters - typically with device_id of 0x08
|
// UBA Masters - must have device_id of 0x08
|
||||||
//
|
//
|
||||||
{72, EMS_DEVICE_TYPE_BOILER, "MC10 Module", EMS_DEVICE_FLAG_NONE},
|
{72, EMS_DEVICE_TYPE_BOILER, "MC10 Module", EMS_DEVICE_FLAG_NONE},
|
||||||
{123, EMS_DEVICE_TYPE_BOILER, "Buderus GBx72/Nefit Trendline/Junkers Cerapur/Worcester Greenstar Si/27i", EMS_DEVICE_FLAG_NONE},
|
{123, EMS_DEVICE_TYPE_BOILER, "Buderus GBx72/Nefit Trendline/Junkers Cerapur/Worcester Greenstar Si/27i", EMS_DEVICE_FLAG_NONE},
|
||||||
@@ -213,7 +262,8 @@ static const _EMS_Device EMS_Devices[] = {
|
|||||||
{208, EMS_DEVICE_TYPE_BOILER, "Buderus Logamax plus/GB192/Bosch Condens GC9000", EMS_DEVICE_FLAG_NONE},
|
{208, EMS_DEVICE_TYPE_BOILER, "Buderus Logamax plus/GB192/Bosch Condens GC9000", EMS_DEVICE_FLAG_NONE},
|
||||||
{64, EMS_DEVICE_TYPE_BOILER, "Sieger BK13,BK15/Nefit Smartline/Buderus GB1x2", EMS_DEVICE_FLAG_NONE},
|
{64, EMS_DEVICE_TYPE_BOILER, "Sieger BK13,BK15/Nefit Smartline/Buderus GB1x2", EMS_DEVICE_FLAG_NONE},
|
||||||
{234, EMS_DEVICE_TYPE_BOILER, "Buderus Logamax Plus GB122", EMS_DEVICE_FLAG_NONE},
|
{234, EMS_DEVICE_TYPE_BOILER, "Buderus Logamax Plus GB122", EMS_DEVICE_FLAG_NONE},
|
||||||
{95, EMS_DEVICE_TYPE_BOILER, "Bosch Condens 2500/Buderus Logamax GB062/Junkers Cerapur Top/Worcester Greenstar i/Generic HT3", EMS_DEVICE_FLAG_NONE},
|
{84, EMS_DEVICE_TYPE_BOILER, "Buderus Logamax Plus GB022", EMS_DEVICE_FLAG_NONE},
|
||||||
|
{95, EMS_DEVICE_TYPE_BOILER, "Bosch Condens 2500/Buderus Logamax,Logomatic/Junkers Cerapur Top/Worcester Greenstar i/Generic HT3", EMS_DEVICE_FLAG_NONE},
|
||||||
{122, EMS_DEVICE_TYPE_BOILER, "Nefit Proline", EMS_DEVICE_FLAG_NONE},
|
{122, EMS_DEVICE_TYPE_BOILER, "Nefit Proline", EMS_DEVICE_FLAG_NONE},
|
||||||
{170, EMS_DEVICE_TYPE_BOILER, "Buderus Logano GB212", EMS_DEVICE_FLAG_NONE},
|
{170, EMS_DEVICE_TYPE_BOILER, "Buderus Logano GB212", EMS_DEVICE_FLAG_NONE},
|
||||||
{172, EMS_DEVICE_TYPE_BOILER, "Nefit Enviline", EMS_DEVICE_FLAG_NONE},
|
{172, EMS_DEVICE_TYPE_BOILER, "Nefit Enviline", EMS_DEVICE_FLAG_NONE},
|
||||||
@@ -223,19 +273,17 @@ static const _EMS_Device EMS_Devices[] = {
|
|||||||
//
|
//
|
||||||
{73, EMS_DEVICE_TYPE_SOLAR, "SM10 Solar Module", EMS_DEVICE_FLAG_SM10},
|
{73, EMS_DEVICE_TYPE_SOLAR, "SM10 Solar Module", EMS_DEVICE_FLAG_SM10},
|
||||||
{163, EMS_DEVICE_TYPE_SOLAR, "SM100 Solar Module", EMS_DEVICE_FLAG_SM100},
|
{163, EMS_DEVICE_TYPE_SOLAR, "SM100 Solar Module", EMS_DEVICE_FLAG_SM100},
|
||||||
|
{164, EMS_DEVICE_TYPE_SOLAR, "SM200 Solar Module", EMS_DEVICE_FLAG_SM100},
|
||||||
{101, EMS_DEVICE_TYPE_SOLAR, "Junkers ISM1 Solar Module", EMS_DEVICE_FLAG_SM100},
|
{101, EMS_DEVICE_TYPE_SOLAR, "Junkers ISM1 Solar Module", EMS_DEVICE_FLAG_SM100},
|
||||||
{162, EMS_DEVICE_TYPE_SOLAR, "SM50 Solar Module", EMS_DEVICE_FLAG_SM100},
|
{162, EMS_DEVICE_TYPE_SOLAR, "SM50 Solar Module", EMS_DEVICE_FLAG_SM100},
|
||||||
|
|
||||||
//
|
//
|
||||||
// Mixing Devices - type 0x20 or 0x21
|
// Mixing Devices - type 0x20 or 0x21
|
||||||
//
|
//
|
||||||
{160, EMS_DEVICE_TYPE_MIXING, "MM100 Mixing Module", EMS_DEVICE_FLAG_NONE},
|
{160, EMS_DEVICE_TYPE_MIXING, "MM100 Mixing Module", EMS_DEVICE_FLAG_MMPLUS},
|
||||||
{161, EMS_DEVICE_TYPE_MIXING, "MM200 Mixing Module", EMS_DEVICE_FLAG_NONE},
|
{161, EMS_DEVICE_TYPE_MIXING, "MM200 Mixing Module", EMS_DEVICE_FLAG_MMPLUS},
|
||||||
{69, EMS_DEVICE_TYPE_MIXING, "MM10 Mixer Module", EMS_DEVICE_FLAG_NONE},
|
{69, EMS_DEVICE_TYPE_MIXING, "MM10 Mixing Module", EMS_DEVICE_FLAG_MM10},
|
||||||
{159, EMS_DEVICE_TYPE_MIXING, "MM50 Mixing Module", EMS_DEVICE_FLAG_NONE},
|
{159, EMS_DEVICE_TYPE_MIXING, "MM50 Mixing Module", EMS_DEVICE_FLAG_MMPLUS},
|
||||||
{79, EMS_DEVICE_TYPE_MIXING, "MM100 Mixer Module", EMS_DEVICE_FLAG_NONE},
|
|
||||||
{80, EMS_DEVICE_TYPE_MIXING, "MM200 Mixer Module", EMS_DEVICE_FLAG_NONE},
|
|
||||||
{78, EMS_DEVICE_TYPE_MIXING, "MM400 Mixer Module", EMS_DEVICE_FLAG_NONE},
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// HeatPump - type 0x38
|
// HeatPump - type 0x38
|
||||||
@@ -244,25 +292,29 @@ static const _EMS_Device EMS_Devices[] = {
|
|||||||
{200, EMS_DEVICE_TYPE_HEATPUMP, "HeatPump Module", EMS_DEVICE_FLAG_NONE},
|
{200, EMS_DEVICE_TYPE_HEATPUMP, "HeatPump Module", EMS_DEVICE_FLAG_NONE},
|
||||||
|
|
||||||
//
|
//
|
||||||
// Other devices, like 0x11 for Switching, 0x09 for controllers, 0x02 for Connect, 0x48 for Gateway
|
// Other devices like controllers and modems
|
||||||
|
// such as 0x11 for Switching, 0x09 for controllers, 0x02 for Connect, 0x48 for Gateway
|
||||||
//
|
//
|
||||||
{71, EMS_DEVICE_TYPE_SWITCH, "WM10 Switch Module", EMS_DEVICE_FLAG_NONE}, // 0x11
|
{71, EMS_DEVICE_TYPE_SWITCH, "WM10 Switch Module", EMS_DEVICE_FLAG_NONE}, // 0x11
|
||||||
{68, EMS_DEVICE_TYPE_CONTROLLER, "BC10/RFM20 Receiver", EMS_DEVICE_FLAG_NONE}, // 0x09
|
{68, EMS_DEVICE_TYPE_CONTROLLER, "BC10/RFM20 Receiver", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{218, EMS_DEVICE_TYPE_CONTROLLER, "Junkers M200/Buderus RFM200 Receiver", EMS_DEVICE_FLAG_NONE}, // 0x50
|
{218, EMS_DEVICE_TYPE_CONTROLLER, "Junkers M200/Buderus RFM200 Receiver", EMS_DEVICE_FLAG_NONE}, // 0x50
|
||||||
{190, EMS_DEVICE_TYPE_CONTROLLER, "BC10 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
{190, EMS_DEVICE_TYPE_CONTROLLER, "BC10 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{114, EMS_DEVICE_TYPE_CONTROLLER, "BC10 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
{114, EMS_DEVICE_TYPE_CONTROLLER, "BC10 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{125, EMS_DEVICE_TYPE_CONTROLLER, "BC25 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
{125, EMS_DEVICE_TYPE_CONTROLLER, "BC25 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{169, EMS_DEVICE_TYPE_CONTROLLER, "BC40 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
{169, EMS_DEVICE_TYPE_CONTROLLER, "BC40 Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{152, EMS_DEVICE_TYPE_CONTROLLER, "Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
{152, EMS_DEVICE_TYPE_CONTROLLER, "Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{95, EMS_DEVICE_TYPE_CONTROLLER, "HT3 Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
{95, EMS_DEVICE_TYPE_CONTROLLER, "HT3 Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{230, EMS_DEVICE_TYPE_CONTROLLER, "BC Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
{209, EMS_DEVICE_TYPE_CONTROLLER, "W-B ErP Boiler Control Panel", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{205, EMS_DEVICE_TYPE_CONNECT, "Nefit Moduline Easy Connect", EMS_DEVICE_FLAG_NONE}, // 0x02
|
{230, EMS_DEVICE_TYPE_CONTROLLER, "BC Base Controller", EMS_DEVICE_FLAG_NONE}, // 0x09
|
||||||
{206, EMS_DEVICE_TYPE_CONNECT, "Bosch Easy Connect", EMS_DEVICE_FLAG_NONE}, // 0x02
|
{205, EMS_DEVICE_TYPE_CONNECT, "Nefit Moduline Easy Connect", EMS_DEVICE_FLAG_NONE}, // 0x02
|
||||||
{171, EMS_DEVICE_TYPE_CONNECT, "EMS-OT OpenTherm converter", EMS_DEVICE_FLAG_NONE}, // 0x02
|
{206, EMS_DEVICE_TYPE_CONNECT, "Bosch Easy Connect", EMS_DEVICE_FLAG_NONE}, // 0x02
|
||||||
{189, EMS_DEVICE_TYPE_GATEWAY, "Web Gateway KM200", EMS_DEVICE_FLAG_NONE}, // 0x48
|
{171, EMS_DEVICE_TYPE_CONNECT, "EMS-OT OpenTherm converter", EMS_DEVICE_FLAG_NONE}, // 0x02
|
||||||
|
{189, EMS_DEVICE_TYPE_GATEWAY, "Web Gateway KM200", EMS_DEVICE_FLAG_NONE}, // 0x48
|
||||||
|
{94, EMS_DEVICE_TYPE_GATEWAY, "RC Remote Device", EMS_DEVICE_FLAG_NONE}, // 0x18
|
||||||
|
{207, EMS_DEVICE_TYPE_CONTROLLER, "Worcester Sense II/Bosch CS200 Solar Controller", EMS_DEVICE_FLAG_NONE}, // 0x10
|
||||||
|
|
||||||
//
|
//
|
||||||
// Thermostats, typically device id of 0x10, 0x17 and 0x18
|
// Thermostats, typically device id of 0x10, 0x17, 0x18, 0x38 (RC100), 0x39 (Easy)
|
||||||
//
|
//
|
||||||
|
|
||||||
// Easy devices - not currently supporting write operations
|
// Easy devices - not currently supporting write operations
|
||||||
@@ -270,28 +322,30 @@ static const _EMS_Device EMS_Devices[] = {
|
|||||||
{203, EMS_DEVICE_TYPE_THERMOSTAT, "Bosch EasyControl CT200", EMS_DEVICE_FLAG_EASY | EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
|
{203, EMS_DEVICE_TYPE_THERMOSTAT, "Bosch EasyControl CT200", EMS_DEVICE_FLAG_EASY | EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
|
||||||
{157, EMS_DEVICE_TYPE_THERMOSTAT, "Buderus RC200/Bosch CW100/Junkers CW100", EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
|
{157, EMS_DEVICE_TYPE_THERMOSTAT, "Buderus RC200/Bosch CW100/Junkers CW100", EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
|
||||||
|
|
||||||
// Buderus/Nefit
|
// Buderus/Nefit specific
|
||||||
{79, EMS_DEVICE_TYPE_THERMOSTAT, "RC10/Moduline 100", EMS_DEVICE_FLAG_RC10}, // 0x17
|
{79, EMS_DEVICE_TYPE_THERMOSTAT, "RC10/Moduline 100", EMS_DEVICE_FLAG_RC10}, // 0x17
|
||||||
|
{80, EMS_DEVICE_TYPE_THERMOSTAT, "Moduline 200", EMS_DEVICE_FLAG_RC10}, // 0x17
|
||||||
{77, EMS_DEVICE_TYPE_THERMOSTAT, "RC20/Moduline 300", EMS_DEVICE_FLAG_RC20}, // 0x17
|
{77, EMS_DEVICE_TYPE_THERMOSTAT, "RC20/Moduline 300", EMS_DEVICE_FLAG_RC20}, // 0x17
|
||||||
{93, EMS_DEVICE_TYPE_THERMOSTAT, "RC20RF", EMS_DEVICE_FLAG_RC20}, // 0x18
|
{67, EMS_DEVICE_TYPE_THERMOSTAT, "RC30", EMS_DEVICE_FLAG_RC30N}, // 0x10 - based on RC35
|
||||||
{67, EMS_DEVICE_TYPE_THERMOSTAT, "RC30", EMS_DEVICE_FLAG_RC30}, // 0x10
|
{78, EMS_DEVICE_TYPE_THERMOSTAT, "Moduline 400", EMS_DEVICE_FLAG_RC30}, // 0x10
|
||||||
{78, EMS_DEVICE_TYPE_THERMOSTAT, "RC30/Moduline 400", EMS_DEVICE_FLAG_RC30}, // 0x10
|
|
||||||
{86, EMS_DEVICE_TYPE_THERMOSTAT, "RC35", EMS_DEVICE_FLAG_RC35}, // 0x10
|
{86, EMS_DEVICE_TYPE_THERMOSTAT, "RC35", EMS_DEVICE_FLAG_RC35}, // 0x10
|
||||||
|
{93, EMS_DEVICE_TYPE_THERMOSTAT, "RC20RF", EMS_DEVICE_FLAG_RC20}, // 0x19
|
||||||
{158, EMS_DEVICE_TYPE_THERMOSTAT, "RC300/RC310/Moduline 3000/Bosch CW400/W-B Sense II", EMS_DEVICE_FLAG_RC300}, // 0x10
|
{158, EMS_DEVICE_TYPE_THERMOSTAT, "RC300/RC310/Moduline 3000/Bosch CW400/W-B Sense II", EMS_DEVICE_FLAG_RC300}, // 0x10
|
||||||
{165, EMS_DEVICE_TYPE_THERMOSTAT, "RC100/Moduline 1010", EMS_DEVICE_FLAG_RC300 | EMS_DEVICE_FLAG_NO_WRITE}, // 0x18, cannot write
|
{165, EMS_DEVICE_TYPE_THERMOSTAT, "RC100/Moduline 1000/1010", EMS_DEVICE_FLAG_RC100}, // 0x18, 0x38
|
||||||
|
|
||||||
// Sieger
|
// Sieger
|
||||||
{076, EMS_DEVICE_TYPE_THERMOSTAT, "Sieger ES73", EMS_DEVICE_FLAG_RC35}, // 0x10
|
{76, EMS_DEVICE_TYPE_THERMOSTAT, "Sieger ES73", EMS_DEVICE_FLAG_RC35}, // 0x10
|
||||||
|
{113, EMS_DEVICE_TYPE_THERMOSTAT, "Sieger ES72/Buderus RC20", EMS_DEVICE_FLAG_RC20N}, // 0x17
|
||||||
|
|
||||||
// Junkers
|
// Junkers - all 0x10
|
||||||
{105, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW100", EMS_DEVICE_FLAG_JUNKERS | EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write
|
{105, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW100", EMS_DEVICE_FLAG_JUNKERS1}, // 0x10
|
||||||
{106, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW200", EMS_DEVICE_FLAG_JUNKERS | EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write
|
{106, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW200", EMS_DEVICE_FLAG_JUNKERS1}, // 0x10
|
||||||
{107, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR100", EMS_DEVICE_FLAG_JUNKERS | EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write
|
{107, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR100", EMS_DEVICE_FLAG_JUNKERS2}, // 0x10
|
||||||
{108, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR110", EMS_DEVICE_FLAG_JUNKERS | EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write
|
{108, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR110", EMS_DEVICE_FLAG_JUNKERS2}, // 0x10
|
||||||
{111, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR10", EMS_DEVICE_FLAG_JUNKERS | EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write
|
{111, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR10", EMS_DEVICE_FLAG_JUNKERS1}, // 0x10
|
||||||
{191, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR120", EMS_DEVICE_FLAG_JUNKERS | EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write
|
{147, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR50", EMS_DEVICE_FLAG_JUNKERS1}, // 0x10
|
||||||
{192, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW120", EMS_DEVICE_FLAG_JUNKERS | EMS_DEVICE_FLAG_NO_WRITE}, // 0x10, cannot write
|
{191, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR120", EMS_DEVICE_FLAG_JUNKERS1}, // 0x10
|
||||||
{147, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FR50", EMS_DEVICE_FLAG_JUNKERS | EMS_DEVICE_FLAG_NO_WRITE} // 0x10, cannot write
|
{192, EMS_DEVICE_TYPE_THERMOSTAT, "Junkers FW120", EMS_DEVICE_FLAG_JUNKERS1} // 0x10
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -76,11 +76,11 @@ char * _short_to_char(char * s, int16_t value, uint8_t decimals) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert short (two bytes) to text string and prints it
|
// convert unsigned short (two bytes) to text string and prints it
|
||||||
// decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100
|
// decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100
|
||||||
char * _ushort_to_char(char * s, uint16_t value, uint8_t decimals) {
|
char * _ushort_to_char(char * s, uint16_t value, uint8_t decimals) {
|
||||||
// remove errors or invalid values
|
// remove errors or invalid values
|
||||||
if (value == EMS_VALUE_USHORT_NOTSET) {
|
if (value == EMS_VALUE_USHORT_NOTSET) { // 0x7D00
|
||||||
strlcpy(s, "?", 10);
|
strlcpy(s, "?", 10);
|
||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
@@ -149,6 +149,7 @@ void _renderUShortValue(const char * prefix, const char * postfix, uint16_t valu
|
|||||||
|
|
||||||
// convert int (single byte) to text value and returns it
|
// convert int (single byte) to text value and returns it
|
||||||
char * _int_to_char(char * s, uint8_t value, uint8_t div) {
|
char * _int_to_char(char * s, uint8_t value, uint8_t div) {
|
||||||
|
s[0] = '\0'; // reset
|
||||||
if (value == EMS_VALUE_INT_NOTSET) {
|
if (value == EMS_VALUE_INT_NOTSET) {
|
||||||
strlcpy(s, "?", sizeof(s));
|
strlcpy(s, "?", sizeof(s));
|
||||||
return (s);
|
return (s);
|
||||||
@@ -200,7 +201,7 @@ void _renderIntValue(const char * prefix, const char * postfix, uint8_t value, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
// takes a long value at prints it to debug log and prints
|
// takes a long value at prints it to debug log and prints
|
||||||
void _renderLongValue(const char * prefix, const char * postfix, uint32_t value) {
|
void _renderLongValue(const char * prefix, const char * postfix, uint32_t value, uint8_t div) {
|
||||||
static char buffer[200] = {0};
|
static char buffer[200] = {0};
|
||||||
strlcpy(buffer, " ", sizeof(buffer));
|
strlcpy(buffer, " ", sizeof(buffer));
|
||||||
strlcat(buffer, prefix, sizeof(buffer));
|
strlcat(buffer, prefix, sizeof(buffer));
|
||||||
@@ -210,7 +211,13 @@ void _renderLongValue(const char * prefix, const char * postfix, uint32_t value)
|
|||||||
strlcat(buffer, "?", sizeof(buffer));
|
strlcat(buffer, "?", sizeof(buffer));
|
||||||
} else {
|
} else {
|
||||||
char s[20] = {0};
|
char s[20] = {0};
|
||||||
strlcat(buffer, ltoa(value, s, 10), sizeof(buffer));
|
if (div == 0) {
|
||||||
|
strlcat(buffer, ltoa(value, s, 10), sizeof(buffer));
|
||||||
|
} else {
|
||||||
|
strlcat(buffer, ltoa(value / 10, s, 10), sizeof(buffer));
|
||||||
|
strlcat(buffer, ".", sizeof(buffer));
|
||||||
|
strlcat(buffer, ltoa(value % 10, s, 10), sizeof(buffer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (postfix != nullptr) {
|
if (postfix != nullptr) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ void _renderShortValue(const char * prefix, const char * postfix, int16_t va
|
|||||||
void _renderUShortValue(const char * prefix, const char * postfix, uint16_t value, uint8_t decimals = 1);
|
void _renderUShortValue(const char * prefix, const char * postfix, uint16_t value, uint8_t decimals = 1);
|
||||||
char * _int_to_char(char * s, uint8_t value, uint8_t div = 1);
|
char * _int_to_char(char * s, uint8_t value, uint8_t div = 1);
|
||||||
void _renderIntValue(const char * prefix, const char * postfix, uint8_t value, uint8_t div = 1);
|
void _renderIntValue(const char * prefix, const char * postfix, uint8_t value, uint8_t div = 1);
|
||||||
void _renderLongValue(const char * prefix, const char * postfix, uint32_t value);
|
void _renderLongValue(const char * prefix, const char * postfix, uint32_t value, uint8_t div = 0);
|
||||||
void _renderBoolValue(const char * prefix, uint8_t value);
|
void _renderBoolValue(const char * prefix, uint8_t value);
|
||||||
char * _hextoa(uint8_t value, char * buffer);
|
char * _hextoa(uint8_t value, char * buffer);
|
||||||
char * _smallitoa(uint8_t value, char * buffer);
|
char * _smallitoa(uint8_t value, char * buffer);
|
||||||
|
|||||||
@@ -225,26 +225,26 @@ _EMS_TX_STATUS ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
|
|||||||
emsuart_tx_brk(); // send <BRK>
|
emsuart_tx_brk(); // send <BRK>
|
||||||
} else if (EMS_Sys_Status.emsTxMode == EMS_TXMODE_DEFAULT) {
|
} else if (EMS_Sys_Status.emsTxMode == EMS_TXMODE_DEFAULT) {
|
||||||
/*
|
/*
|
||||||
* based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch
|
* based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch
|
||||||
* we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO.
|
* we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO.
|
||||||
* after sending the last char we poll the Rx status until either
|
* after sending the last char we poll the Rx status until either
|
||||||
* - size(Rx FIFO) == size(Tx-Telegram)
|
* - size(Rx FIFO) == size(Tx-Telegram)
|
||||||
* - <BRK> is detected
|
* - <BRK> is detected
|
||||||
* At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode.
|
* At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode.
|
||||||
*
|
*
|
||||||
* EMS-Bus error handling
|
* EMS-Bus error handling
|
||||||
* 1. Busmaster stops echoing on Tx w/o permission
|
* 1. Busmaster stops echoing on Tx w/o permission
|
||||||
* 2. Busmaster cancel telegram by sending a BRK
|
* 2. Busmaster cancel telegram by sending a BRK
|
||||||
*
|
*
|
||||||
* Case 1. is handled by a watchdog counter which is reset on each
|
* Case 1. is handled by a watchdog counter which is reset on each
|
||||||
* Tx attempt. The timeout should be 20x EMSUART_BIT_TIME plus
|
* Tx attempt. The timeout should be 20x EMSUART_BIT_TIME plus
|
||||||
* some smart guess for processing time on targeted EMS device.
|
* some smart guess for processing time on targeted EMS device.
|
||||||
* We set EMS_Sys_Status.emsTxStatus to EMS_TX_WTD_TIMEOUT and return
|
* We set EMS_Sys_Status.emsTxStatus to EMS_TX_WTD_TIMEOUT and return
|
||||||
*
|
*
|
||||||
* Case 2. is handled via a BRK chk during transmission.
|
* Case 2. is handled via a BRK chk during transmission.
|
||||||
* We set EMS_Sys_Status.emsTxStatus to EMS_TX_BRK_DETECT and return
|
* We set EMS_Sys_Status.emsTxStatus to EMS_TX_BRK_DETECT and return
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
uint16_t wdc = EMS_TX_TO_COUNT;
|
uint16_t wdc = EMS_TX_TO_COUNT;
|
||||||
ETS_UART_INTR_DISABLE(); // disable rx interrupt
|
ETS_UART_INTR_DISABLE(); // disable rx interrupt
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
|
|
||||||
#include "ems.h"
|
#include "ems.h"
|
||||||
|
|
||||||
// TOPICS with _CMD_ are used for receiving commands from an MQTT Broker
|
// TOPICS with *_CMD_* are used for receiving commands from an MQTT Broker
|
||||||
// EMS-ESP will subscribe to these topics
|
// EMS-ESP will subscribe to these topics
|
||||||
|
|
||||||
#define TOPIC_GENERIC_CMD "generic_cmd" // for receiving generic system commands via MQTT
|
#define TOPIC_GENERIC_CMD "generic_cmd" // for receiving generic system commands via MQTT
|
||||||
|
|
||||||
// MQTT for thermostat
|
// MQTT for thermostat
|
||||||
@@ -26,38 +27,57 @@
|
|||||||
#define TOPIC_THERMOSTAT_CMD_DAYTEMP "daytemp" // day temp (RC35 specific)
|
#define TOPIC_THERMOSTAT_CMD_DAYTEMP "daytemp" // day temp (RC35 specific)
|
||||||
#define TOPIC_THERMOSTAT_CMD_NIGHTTEMP "nighttemp" // night temp (RC35 specific)
|
#define TOPIC_THERMOSTAT_CMD_NIGHTTEMP "nighttemp" // night temp (RC35 specific)
|
||||||
#define TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP "holidayttemp" // holiday temp (RC35 specific)
|
#define TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP "holidayttemp" // holiday temp (RC35 specific)
|
||||||
|
#define TOPIC_THERMOSTAT_CMD_NOFROSTTEMP "nofrosttemp" // frost temp (Junkers specific)
|
||||||
|
#define TOPIC_THERMOSTAT_CMD_ECOTEMP "ecotemp" // eco temp (Junkers specific)
|
||||||
|
#define TOPIC_THERMOSTAT_CMD_HEATTEMP "heattemp" // heat temp (Junkers specific)
|
||||||
|
|
||||||
#define THERMOSTAT_CURRTEMP "currtemp" // current temperature
|
#define THERMOSTAT_CURRTEMP "currtemp" // current temperature
|
||||||
#define THERMOSTAT_SELTEMP "seltemp" // selected temperature
|
#define THERMOSTAT_SELTEMP "seltemp" // selected temperature
|
||||||
#define THERMOSTAT_HC "hc" // which heating circuit number
|
#define THERMOSTAT_HC "hc" // which heating circuit number
|
||||||
#define THERMOSTAT_MODE "mode" // mode
|
#define THERMOSTAT_MODE "mode" // mode
|
||||||
|
#define THERMOSTAT_MODETYPE "modetype" // mode type
|
||||||
#define THERMOSTAT_DAYTEMP "daytemp" // RC35 specific
|
#define THERMOSTAT_DAYTEMP "daytemp" // RC35 specific
|
||||||
#define THERMOSTAT_NIGHTTEMP "nighttemp" // RC35 specific
|
#define THERMOSTAT_NIGHTTEMP "nighttemp" // RC35 specific
|
||||||
#define THERMOSTAT_HOLIDAYTEMP "holidayttemp" // RC35 specific
|
#define THERMOSTAT_HOLIDAYTEMP "holidayttemp" // RC35 specific
|
||||||
#define THERMOSTAT_HEATINGTYPE "heatingtype" // RC35 specific (3=floorheating)
|
#define THERMOSTAT_HEATINGTYPE "heatingtype" // RC35 specific (3=floorheating)
|
||||||
#define THERMOSTAT_CIRCUITCALCTEMP "circuitcalctemp" // RC35 specific
|
#define THERMOSTAT_CIRCUITCALCTEMP "circuitcalctemp" // RC35 specific
|
||||||
|
|
||||||
|
// mixing module
|
||||||
|
#define MIXING_HC "hc" // which heating circuit number
|
||||||
|
#define MIXING_WWC "wwc" // which warm water circuit number
|
||||||
|
|
||||||
// MQTT for boiler
|
// MQTT for boiler
|
||||||
#define TOPIC_BOILER_DATA "boiler_data" // for sending boiler values to MQTT
|
#define TOPIC_BOILER_DATA "boiler_data" // for sending boiler values to MQTT
|
||||||
#define TOPIC_BOILER_TAPWATER_ACTIVE "tapwater_active" // if hot tap water is running
|
#define TOPIC_BOILER_TAPWATER_ACTIVE "tapwater_active" // if hot tap water is running
|
||||||
#define TOPIC_BOILER_HEATING_ACTIVE "heating_active" // if heating is on
|
#define TOPIC_BOILER_HEATING_ACTIVE "heating_active" // if heating is on
|
||||||
|
|
||||||
#define TOPIC_BOILER_CMD "boiler_cmd" // for receiving boiler commands via MQTT
|
#define TOPIC_BOILER_CMD "boiler_cmd" // for receiving boiler commands via MQTT
|
||||||
#define TOPIC_BOILER_CMD_WWACTIVATED "boiler_cmd_wwactivated" // change water on/off
|
#define TOPIC_BOILER_CMD_WWACTIVATED "boiler_cmd_wwactivated" // change water on/off
|
||||||
#define TOPIC_BOILER_CMD_WWONETIME "boiler_cmd_wwonetime" // warm warter one time loading
|
#define TOPIC_BOILER_CMD_WWONETIME "boiler_cmd_wwonetime" // warm warter one time loading
|
||||||
#define TOPIC_BOILER_CMD_WWTEMP "boiler_cmd_wwtemp" // wwtemp changes via MQTT
|
#define TOPIC_BOILER_CMD_WWCIRCULATION "boiler_cmd_wwcirculation" // start warm warter circulation
|
||||||
#define TOPIC_BOILER_CMD_COMFORT "comfort" // ww comfort setting via MQTT
|
#define TOPIC_BOILER_CMD_WWTEMP "boiler_cmd_wwtemp" // wwtemp changes via MQTT
|
||||||
#define TOPIC_BOILER_CMD_FLOWTEMP "flowtemp" // flowtemp value via MQTT
|
#define TOPIC_BOILER_CMD_COMFORT "comfort" // ww comfort setting via MQTT
|
||||||
|
#define TOPIC_BOILER_CMD_FLOWTEMP "flowtemp" // flowtemp value via MQTT
|
||||||
|
|
||||||
|
// MQTT for settings
|
||||||
|
#define TOPIC_SETTINGS_DATA "settings_data" // for sending settings values to MQTT
|
||||||
|
#define TOPIC_SETTINGS_CMD "settings_cmd" // for receiving settings commands via MQTT
|
||||||
|
#define TOPIC_SETTINGS_CMD_DISPLAY "display" // change display
|
||||||
|
#define TOPIC_SETTINGS_CMD_LANGUAGE "language" // change language
|
||||||
|
#define TOPIC_SETTINGS_CMD_BUILDING "building" // change building
|
||||||
|
#define TOPIC_SETTINGS_CMD_MINEXTTEMP "minextTemp" // change min. ext. temp.
|
||||||
|
|
||||||
// MQTT for mixing device
|
// MQTT for mixing device
|
||||||
#define TOPIC_MIXING_DATA "mixing_data" // for sending mixing device values to MQTT
|
#define TOPIC_MIXING_DATA "mixing_data" // for sending mixing device values to MQTT
|
||||||
|
|
||||||
// MQTT for SM10/SM100 Solar Module
|
// MQTT for SM10/SM100/SM200 Solar Module
|
||||||
#define TOPIC_SM_DATA "sm_data" // topic name
|
#define TOPIC_SM_DATA "sm_data" // topic name
|
||||||
#define SM_COLLECTORTEMP "collectortemp" // collector temp
|
#define SM_COLLECTORTEMP "collectortemp" // collector temp
|
||||||
#define SM_BOTTOMTEMP "bottomtemp" // bottom temp
|
#define SM_BOTTOMTEMP "bottomtemp" // bottom temp1
|
||||||
|
#define SM_BOTTOMTEMP2 "bottomtemp2" // bottom temp2
|
||||||
#define SM_PUMPMODULATION "pumpmodulation" // pump modulation
|
#define SM_PUMPMODULATION "pumpmodulation" // pump modulation
|
||||||
#define SM_PUMP "pump" // pump active
|
#define SM_PUMP "pump" // pump active
|
||||||
|
#define SM_VALVESTATUS "valvestatus" // valve status
|
||||||
#define SM_ENERGYLASTHOUR "energylasthour" // energy last hour
|
#define SM_ENERGYLASTHOUR "energylasthour" // energy last hour
|
||||||
#define SM_ENERGYTODAY "energytoday" // energy today
|
#define SM_ENERGYTODAY "energytoday" // energy today
|
||||||
#define SM_ENERGYTOTAL "energytotal" // energy total
|
#define SM_ENERGYTOTAL "energytotal" // energy total
|
||||||
@@ -76,5 +96,7 @@
|
|||||||
#define TOPIC_SHOWER_DURATION "duration" // duration of the last shower
|
#define TOPIC_SHOWER_DURATION "duration" // duration of the last shower
|
||||||
|
|
||||||
// MQTT for External Sensors
|
// MQTT for External Sensors
|
||||||
#define TOPIC_EXTERNAL_SENSORS "sensors" // for sending sensor values to MQTT
|
#define TOPIC_EXTERNAL_SENSORS "sensors" // topic for sending sensor values to MQTT
|
||||||
#define PAYLOAD_EXTERNAL_SENSORS "temp_%d" // for formatting the payload for each external dallas sensor
|
#define PAYLOAD_EXTERNAL_SENSOR_NUM "sensor" // which sensor #
|
||||||
|
#define PAYLOAD_EXTERNAL_SENSOR_ID "id"
|
||||||
|
#define PAYLOAD_EXTERNAL_SENSOR_TEMP "temp"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define APP_VERSION "1.9.4"
|
#define APP_VERSION "1.9.5"
|
||||||
|
|||||||
@@ -181,9 +181,9 @@
|
|||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<label class="col-xs-3">Port<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
<label class="col-xs-3">Port<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
||||||
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
||||||
data-content="MQTT Server port number"></i></label>
|
data-content="MQTT Server port number (default 1883)"></i></label>
|
||||||
<span class="col-xs-9">
|
<span class="col-xs-9">
|
||||||
<input class="form-control input-sm" placeholder="1883" value="" style="display:inline;max-width:185px"
|
<input class="form-control input-sm" placeholder="" value="" style="display:inline;max-width:185px"
|
||||||
id="mqttport" type="text">
|
id="mqttport" type="text">
|
||||||
</span>
|
</span>
|
||||||
<br>
|
<br>
|
||||||
@@ -191,9 +191,9 @@
|
|||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<label class="col-xs-3">QOS<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
<label class="col-xs-3">QOS<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
||||||
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
||||||
data-content="MQTT QOS 0,1 or 2"></i></label>
|
data-content="MQTT QOS 0, 1 or 2 (default 0)"></i></label>
|
||||||
<span class="col-xs-9">
|
<span class="col-xs-9">
|
||||||
<input class="form-control input-sm" placeholder="1" value="" style="display:inline;max-width:185px"
|
<input class="form-control input-sm" placeholder="" value="" style="display:inline;max-width:185px"
|
||||||
id="mqttqos" type="text">
|
id="mqttqos" type="text">
|
||||||
</span>
|
</span>
|
||||||
<br>
|
<br>
|
||||||
@@ -201,9 +201,9 @@
|
|||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<label class="col-xs-3">Keep Alive<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
<label class="col-xs-3">Keep Alive<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
||||||
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
||||||
data-content="MQTT Keep Alive time in seconds"></i></label>
|
data-content="MQTT Keep Alive time in seconds (default 60)"></i></label>
|
||||||
<span class="col-xs-9">
|
<span class="col-xs-9">
|
||||||
<input class="form-control input-sm" placeholder="60" value="" style="display:inline;max-width:185px"
|
<input class="form-control input-sm" placeholder="" value="" style="display:inline;max-width:185px"
|
||||||
id="mqttkeepalive" type="text">
|
id="mqttkeepalive" type="text">
|
||||||
</span>
|
</span>
|
||||||
<br>
|
<br>
|
||||||
@@ -246,14 +246,14 @@
|
|||||||
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
||||||
data-content="MQTT topic prefix (<mqtt base>/<host name>/)"></i></label>
|
data-content="MQTT topic prefix (<mqtt base>/<host name>/)"></i></label>
|
||||||
<span class="col-xs-9">
|
<span class="col-xs-9">
|
||||||
<input class="form-control input-sm" placeholder="home" value="" style="display:inline;max-width:185px"
|
<input class="form-control input-sm" placeholder="" value="" style="display:inline;max-width:185px"
|
||||||
id="mqttbase" type="text">
|
id="mqttbase" type="text">
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row form-group">
|
<div class="row form-group">
|
||||||
<label class="col-xs-3">Heartbeat<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
<label class="col-xs-3">Heartbeat<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
||||||
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
||||||
data-content="Enable or Disable an automatic MQTT topic publish with system stats"></i></label>
|
data-content="Enable or Disable an automatic MQTT topic publish with system status"></i></label>
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-9">
|
||||||
<form>
|
<form>
|
||||||
<label class="radio-inline">
|
<label class="radio-inline">
|
||||||
@@ -508,16 +508,6 @@
|
|||||||
<table class="table table-hover table-striped table-condensed" border=1>
|
<table class="table table-hover table-striped table-condensed" border=1>
|
||||||
<caption>MQTT <div id="mqttconnected"></div> <div id="mqttheartbeat"></div>
|
<caption>MQTT <div id="mqttconnected"></div> <div id="mqttheartbeat"></div>
|
||||||
</caption>
|
</caption>
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Time</th>
|
|
||||||
<th>Topic<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
|
|
||||||
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
|
|
||||||
id="mqttloghdr"></i></th>
|
|
||||||
<th>Payload</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="mqttlog"></tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -391,40 +391,6 @@ function listStats() {
|
|||||||
document.getElementById("mqttheartbeat").className = "label label-primary";
|
document.getElementById("mqttheartbeat").className = "label label-primary";
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("mqttloghdr").setAttribute('data-content', "Topics are prefixed with " + ajaxobj.mqttloghdr);
|
|
||||||
|
|
||||||
var mtable = document.getElementById("mqttlog");
|
|
||||||
var obj = ajaxobj.mqttlog;
|
|
||||||
var tr, td;
|
|
||||||
|
|
||||||
for (var i = 0; i < obj.length; i++) {
|
|
||||||
tr = document.createElement("tr");
|
|
||||||
|
|
||||||
td = document.createElement("td");
|
|
||||||
|
|
||||||
if (obj[i].time < 1563300000) {
|
|
||||||
td.innerHTML = "(" + obj[i].time + ")";
|
|
||||||
} else {
|
|
||||||
var vuepoch = new Date(obj[i].time * 1000);
|
|
||||||
td.innerHTML = vuepoch.getUTCFullYear() +
|
|
||||||
"-" + twoDigits(vuepoch.getUTCMonth() + 1) +
|
|
||||||
"-" + twoDigits(vuepoch.getUTCDate()) +
|
|
||||||
" " + twoDigits(vuepoch.getUTCHours()) +
|
|
||||||
":" + twoDigits(vuepoch.getUTCMinutes()) +
|
|
||||||
":" + twoDigits(vuepoch.getUTCSeconds());
|
|
||||||
}
|
|
||||||
tr.appendChild(td);
|
|
||||||
|
|
||||||
td = document.createElement("td");
|
|
||||||
td.innerHTML = obj[i].topic
|
|
||||||
tr.appendChild(td);
|
|
||||||
|
|
||||||
td = document.createElement("td");
|
|
||||||
td.innerHTML = obj[i].payload
|
|
||||||
tr.appendChild(td);
|
|
||||||
|
|
||||||
mtable.appendChild(tr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getContent(contentname) {
|
function getContent(contentname) {
|
||||||
|
|||||||
@@ -97,8 +97,9 @@ var custom_configfile = {
|
|||||||
"listen_mode": false,
|
"listen_mode": false,
|
||||||
"shower_timer": true,
|
"shower_timer": true,
|
||||||
"shower_alert": false,
|
"shower_alert": false,
|
||||||
"publish_time": 0,
|
"publish_time": 10,
|
||||||
"tx_mode": 1
|
"tx_mode": 1,
|
||||||
|
"bus_id": 11
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -118,17 +119,7 @@ function sendStatus() {
|
|||||||
"systemload": 0,
|
"systemload": 0,
|
||||||
"mqttconnected": true,
|
"mqttconnected": true,
|
||||||
"mqttheartbeat": false,
|
"mqttheartbeat": false,
|
||||||
"uptime": "0 days 0 hours 1 minute 45 seconds",
|
"uptime": "0 days 0 hours 1 minute 45 seconds"
|
||||||
"mqttloghdr": "home/ems-esp/",
|
|
||||||
"mqttlog": [
|
|
||||||
{ "topic": "start", "payload": "start", "time": 1565956388 },
|
|
||||||
{ "topic": "shower_timer", "payload": "1", "time": 1565956388 },
|
|
||||||
{ "topic": "shower_alert", "payload": "0", "time": 1565956388 },
|
|
||||||
{ "topic": "boiler_data", "payload": "{\"wWComfort\":\"Hot\",\"wWSelTemp\":60,\"selFlowTemp\":5,\"selBurnPow\":0,\"curBurnPow\":0,\"pumpMod\":0,\"wWCurTmp\":48.4,\"wWCurFlow\":0,\"curFlowTemp\":49.3,\"retTemp\":49.3,\"sysPress\":1.8,\"boilTemp\":50.5,\"wWActivated\":\"on\",\"burnGas\":\"off\",\"heatPmp\":\"off\",\"fanWork\":\"off\",\"ignWork\":\"off\",\"wWCirc\":\"off\",\"wWHeat\":\"on\",\"burnStarts\":223397,\"burnWorkMin\":366019,\"heatWorkMin\":294036,\"ServiceCode\":\"0H\",\"ServiceCodeNumber\":203}", "time": 1565956463 },
|
|
||||||
{ "topic": "tapwater_active", "payload": "0", "time": 1565956408 },
|
|
||||||
{ "topic": "heating_active", "payload": "0", "time": 1565956408 },
|
|
||||||
{ "topic": "thermostat_data", "payload": "{\"thermostat_hc\":\"1\",\"thermostat_seltemp\":15,\"thermostat_currtemp\":23,\"thermostat_mode\":\"auto\"}", "time": 1565956444 }
|
|
||||||
]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
wss.broadcast(stats);
|
wss.broadcast(stats);
|
||||||
@@ -170,8 +161,7 @@ function sendCustomStatus() {
|
|||||||
"b2": "off",
|
"b2": "off",
|
||||||
"b3": 0,
|
"b3": 0,
|
||||||
"b4": 53,
|
"b4": 53,
|
||||||
"b5": 54.4,
|
"b5": 54.4
|
||||||
"b6": 53.3
|
|
||||||
},
|
},
|
||||||
|
|
||||||
"sm": {
|
"sm": {
|
||||||
|
|||||||
Reference in New Issue
Block a user