merged with 1.9.1b12

This commit is contained in:
Paul
2019-10-05 14:47:56 +02:00
34 changed files with 9564 additions and 1130 deletions

2
.gitignore vendored
View File

@@ -9,9 +9,7 @@
.pio .pio
.clang_complete .clang_complete
.gcc-flags.json .gcc-flags.json
platformio.ini
lib/readme.txt lib/readme.txt
.travis.yml
# web stuff compiled # web stuff compiled
src/websrc/css/required.css src/websrc/css/required.css

View File

@@ -5,6 +5,36 @@ 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.1] 2019-10-05
### Added
- Support for multiple Heating Circuits - https://github.com/proddy/EMS-ESP/issues/162
- new `mqttlog` command also shows which MQTT topics it is subscribed too
- Optimized event log loading in web and added integrity checks on all config and log files during boot
- `autodetect quick`
- `log_events` option, now optional to save the log events to SPIFFS
### Fixed
- fixed zero values (0.0) for setpoint temperature with the RC35 thermostat when in Auto mode - https://github.com/proddy/EMS-ESP/issues/180
- added check for corrupted event log, which could happen due to SPIFFS writing while UART is active
- made Junkers work again (broke in 1.9.0)
### Changed
- Web login password is now mandatory
- Faster detection of EMS devices on bus by using the 0x07 telegram instead of the brute-force scan
- Fixes to the default HA climate component .yaml file to support latest Home Assistance ('heat' added)
- Update documentation in Wiki on MQTT and troubleshooting
- Slowed down firmware upload via the Web to prevent users rebooting too early
- Change way WiFi is intialized to prevent dual AP and Client
### Removed
- Removed `heating_circuit` config setting
- Removed showing the JSON config files when Saving from the Web
## [1.9.0] 2019-09-01 ## [1.9.0] 2019-09-01
### Changed ### Changed
@@ -57,7 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- HeatPump support (e.g. the Nefit Enviline) - HeatPump support (e.g. the Nefit Enviline)
- new device: Buderus MM50 Mixer - new device: Buderus MM50 Mixer
- new devices: Junkers FW100 and ISM1 (thanks Vuego123) - new devices: Junkers FW100 and ISM1 (thanks Vuego123)
- Improved Tx logic to support EMS, EMS+ and Heatronics (thanks kwertie01, susisstrolch, philrich) - Improved Tx logic to support EMS, EMS+ and Heatronic 3 (thanks kwertie01, susisstrolch, philrich)
- MQTT heartbeat - MQTT heartbeat
### Fixed ### Fixed

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -2,7 +2,7 @@
name: Thermostat name: Thermostat
modes: modes:
- "auto" - "auto"
- "manual" - "heat"
- "off" - "off"
mode_state_topic: "home/ems-esp/thermostat_data" mode_state_topic: "home/ems-esp/thermostat_data"

View File

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 134 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -5,25 +5,34 @@
[platformio] [platformio]
default_envs = release default_envs = release
; default_envs = debug ; default_envs = debug
;default_envs = crash
;default_envs = tests
[common] [common]
; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DFORCE_SERIAL -DNO_GLOBAL_EEPROM -DLOGICANALYZER ; build options are:
general_flags = ; -DMYESP_TIMESTAMP
; -DTESTS
; -DCRASH
; -DFORCE_SERIAL
; -DLOGICANALYZER
general_flags = -g -w -DNO_GLOBAL_EEPROM -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH -DBEARSSL_SSL_BASIC
;general_flags =
[env] [env]
board = d1_mini board = d1_mini
framework = arduino framework = arduino
platform = espressif8266 platform = espressif8266
lib_deps = lib_deps =
ESPAsyncTCP
CRC32 CRC32
CircularBuffer CircularBuffer
OneWire OneWire
JustWifi JustWifi
AsyncMqttClient AsyncMqttClient
ArduinoJson ArduinoJson
EEPROM_rotate EEPROM_Rotate
ESP Async WebServer ESP Async WebServer
ESPAsyncTCP
ESPAsyncUDP ESPAsyncUDP
upload_speed = 921600 upload_speed = 921600
monitor_speed = 115200 monitor_speed = 115200
@@ -39,7 +48,7 @@ monitor_speed = 115200
[env:buildweb] [env:buildweb]
extra_scripts = pre:scripts/buildweb.py extra_scripts = pre:scripts/buildweb.py
[env:test] [env:tests]
build_type = debug build_type = debug
build_flags = ${common.general_flags} -DTESTS build_flags = ${common.general_flags} -DTESTS
extra_scripts = extra_scripts =
@@ -48,7 +57,7 @@ extra_scripts =
[env:crash] [env:crash]
build_type = debug build_type = debug
build_flags = ${common.general_flags} -DNO_GLOBAL_EEPROM -DCRASH build_flags = ${common.general_flags} -DCRASH
extra_scripts = extra_scripts =
pre:scripts/rename_fw.py pre:scripts/rename_fw.py
pre:scripts/buildweb.py pre:scripts/buildweb.py

View File

@@ -17,7 +17,7 @@ import os
# 3fffffb0: feefeffe feefeffe 3ffe8558 40100b01 # 3fffffb0: feefeffe feefeffe 3ffe8558 40100b01
# <<<stack<<< # <<<stack<<<
call(['python', 'scripts/decoder.py ', '-s', '-e', os.getcwd()+"/.pio/build/debug/firmware_d1_mini_debug.elf", 'scripts/stackdmp.txt']) call(['python', 'scripts/decoder.py ', '-s', '-e', os.getcwd()+"/.pio/build/debug/firmware_debug_1_9_1b3.elf", 'scripts/stackdmp.txt'])
# example for linux: # example for linux:
# % cd EMS-ESP # % cd EMS-ESP

View File

@@ -21,6 +21,13 @@ with open('./src/version.h', 'r') as f:
if m and len(m.groups()) > 0: if m and len(m.groups()) > 0:
bag[var] = m.group(1) bag[var] = m.group(1)
with open('./src/ems-esp.cpp', 'r') as f:
for l in f.readlines():
for expr, var in exprs:
m = expr.match(l)
if m and len(m.groups()) > 0:
bag[var] = m.group(1)
app_version = bag.get('app_version') app_version = bag.get('app_version')
app_name = bag.get('app_name') app_name = bag.get('app_name')
app_hostname = bag.get('app_hostname') app_hostname = bag.get('app_hostname')
@@ -32,5 +39,8 @@ branch = env['PIOENV']
env.AddPreAction("buildprog", build_web) env.AddPreAction("buildprog", build_web)
# build filename, replacing . with _ for the version # build filename, replacing . with _ for the version
env.Replace(PROGNAME="firmware_%s" % branch + "_" + app_version.replace(".", "_")) #env.Replace(PROGNAME="firmware_%s" % branch + "_" + app_version.replace(".", "_"))
env.Replace(PROGNAME=app_name + "-" + app_version.replace(".", "_") + "-" + board + "-" + branch)
#env.Replace(PROGNAME=app_name + "-" + app_version)

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
#ifndef MyESP_h #ifndef MyESP_h
#define MyESP_h #define MyESP_h
#define MYESP_VERSION "1.2.0" #define MYESP_VERSION "1.2.6"
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
@@ -87,7 +87,7 @@ extern struct rst_info resetInfo;
#define MQTT_MAX_PAYLOAD_SIZE 500 // max size of a JSON object. See https://arduinojson.org/v6/assistant/ #define MQTT_MAX_PAYLOAD_SIZE 500 // max size of a JSON object. See https://arduinojson.org/v6/assistant/
#define MQTT_MAX_PAYLOAD_SIZE_LARGE 2000 // max size of a large JSON object, like for sending MQTT log #define MQTT_MAX_PAYLOAD_SIZE_LARGE 2000 // max size of a large JSON object, like for sending MQTT log
#define MYESP_JSON_MAXSIZE 2000 // for large Dynamic json files #define MYESP_JSON_MAXSIZE 2000 // for large Dynamic json files
#define MYESP_MQTTLOG_MAX 20 // max number of log entries for MQTT publishes #define MYESP_MQTTLOG_MAX 40 // max number of log entries for MQTT publishes and subscribes
#define MYESP_JSON_LOG_MAXSIZE 300 // max size of an JSON log entry #define MYESP_JSON_LOG_MAXSIZE 300 // max size of an JSON log entry
// Internal MQTT events // Internal MQTT events
@@ -139,7 +139,9 @@ PROGMEM const char * const custom_reset_string[] = {custom_reset_hardware, cus
#define CUSTOM_RESET_MAX 5 #define CUSTOM_RESET_MAX 5
// SPIFFS // SPIFFS
#define MYESP_SPIFFS_MAXSIZE 800 // https://arduinojson.org/v6/assistant/ // https://arduinojson.org/v6/assistant/
#define MYESP_SPIFFS_MAXSIZE_CONFIG 800 // max size for a config file
#define MYESP_SPIFFS_MAXSIZE_EVENTLOG 20000 // max size for the eventlog in bytes
// CRASH // CRASH
/** /**
@@ -212,6 +214,7 @@ typedef enum {
// for storing all MQTT publish messages // for storing all MQTT publish messages
typedef struct { typedef struct {
uint8_t type; // 0=none, 1=publish, 2=subscribe
char * topic; char * topic;
char * payload; char * payload;
time_t timestamp; time_t timestamp;
@@ -291,7 +294,6 @@ class MyESP {
// Crash // Crash
void crashClear(); void crashClear();
void crashDump(); void crashDump();
void crashTest(uint8_t t);
void crashInfo(); void crashInfo();
// general // general
@@ -317,9 +319,10 @@ class MyESP {
char * _mqttTopic(const char * topic); char * _mqttTopic(const char * topic);
// mqtt log // mqtt log
_MQTT_Log MQTT_log[MYESP_MQTTLOG_MAX]; // log for publish messages _MQTT_Log MQTT_log[MYESP_MQTTLOG_MAX]; // log for publish and subscribe messages
void _printMQTTLog(); void _printMQTTLog();
void _addMQTTLog(const char * topic, const char * payload); void _addMQTTLog(const char * topic, const char * payload, const uint8_t type);
AsyncMqttClient mqttClient; // the MQTT class AsyncMqttClient mqttClient; // the MQTT class
uint32_t _mqtt_reconnect_delay; uint32_t _mqtt_reconnect_delay;
@@ -377,11 +380,13 @@ class MyESP {
void _fs_setup(); void _fs_setup();
bool _fs_loadConfig(); bool _fs_loadConfig();
bool _fs_loadCustomConfig(); bool _fs_loadCustomConfig();
void _fs_printFile(const char * file);
void _fs_eraseConfig(); void _fs_eraseConfig();
bool _fs_writeConfig(); bool _fs_writeConfig();
bool _fs_createCustomConfig(); bool _fs_createCustomConfig();
bool _fs_sendConfig(); bool _fs_sendConfig();
bool _fs_validateConfigFile(const char * filename, size_t maxsize, JsonDocument & doc);
bool _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;
@@ -395,11 +400,12 @@ class MyESP {
char * _app_updateurl; char * _app_updateurl;
bool _suspendOutput; bool _suspendOutput;
bool _general_serial; bool _general_serial;
unsigned long _getUptime(); bool _general_log_events;
char * _getBuildTime();
char * _buildTime; char * _buildTime;
bool _timerequest; bool _timerequest;
bool _formatreq; bool _formatreq;
unsigned long _getUptime();
char * _getBuildTime();
bool _hasValue(char * s); bool _hasValue(char * s);
void _printHeap(const char * s); void _printHeap(const char * s);

View File

@@ -122,19 +122,6 @@
<br> <br>
</div> </div>
<div class="row form-group">
<label class="col-xs-3">Heating Circuit<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
data-content="Select the main heating circuit to use. Default is HC1."></i></label>
<span class="col-xs-9 col-md-5">
<select class="form-control input-sm" id="heating_circuit">
<option selected="selected" value="1">HC1</option>
<option value="2">HC2</option>
<option value="3">HC3</option>
</select>
</span>
</div>
<div class="row form-group"> <div class="row form-group">
<label class="col-xs-3">Tx mode<i style="margin-left: 10px;" <label class="col-xs-3">Tx mode<i style="margin-left: 10px;"
class="glyphicon glyphicon-exclamation-sign text-danger" aria-hidden="true" data-toggle="popover" class="glyphicon glyphicon-exclamation-sign text-danger" aria-hidden="true" data-toggle="popover"
@@ -143,8 +130,8 @@
<span class="col-xs-9 col-md-5"> <span class="col-xs-9 col-md-5">
<select class="form-control input-sm" id="tx_mode"> <select class="form-control input-sm" id="tx_mode">
<option selected="selected" value="1">1 (EMS generic)</option> <option selected="selected" value="1">1 (EMS generic)</option>
<option value="2">2 (EMS+/EMS2.0)</option> <option value="2">2 (EMS+)</option>
<option value="3">3 (Junkers Heatronics)</option> <option value="3">3 (Junkers Heatronic)</option>
</select> </select>
</span> </span>
</div> </div>

View File

@@ -9,20 +9,15 @@ var custom_config = {
"shower_timer": false, "shower_timer": false,
"shower_alert": false, "shower_alert": false,
"publish_time": 120, "publish_time": 120,
"heating_circuit": 1 "tx_mode": 1
}
}
function custom_commit() {
websock.send(JSON.stringify(custom_config));
} }
};
function listcustom() { function listcustom() {
document.getElementById("led_gpio").value = custom_config.settings.led_gpio; document.getElementById("led_gpio").value = custom_config.settings.led_gpio;
document.getElementById("dallas_gpio").value = custom_config.settings.dallas_gpio; document.getElementById("dallas_gpio").value = custom_config.settings.dallas_gpio;
document.getElementById("publish_time").value = custom_config.settings.publish_time; document.getElementById("publish_time").value = custom_config.settings.publish_time;
document.getElementById("heating_circuit").value = custom_config.settings.heating_circuit;
document.getElementById("tx_mode").value = custom_config.settings.tx_mode; document.getElementById("tx_mode").value = custom_config.settings.tx_mode;
if (custom_config.settings.led) { if (custom_config.settings.led) {
@@ -72,10 +67,9 @@ function savecustom() {
} }
custom_config.settings.publish_time = parseInt(document.getElementById("publish_time").value); custom_config.settings.publish_time = parseInt(document.getElementById("publish_time").value);
custom_config.settings.heating_circuit = parseInt(document.getElementById("heating_circuit").value);
custom_config.settings.tx_mode = parseInt(document.getElementById("tx_mode").value); custom_config.settings.tx_mode = parseInt(document.getElementById("tx_mode").value);
custom_uncommited(); custom_saveconfig();
} }
function listCustomStats() { function listCustomStats() {
@@ -87,6 +81,8 @@ function listCustomStats() {
document.getElementById("devicesshow").style.display = "none"; document.getElementById("devicesshow").style.display = "none";
document.getElementById("thermostat_show").style.display = "none"; document.getElementById("thermostat_show").style.display = "none";
document.getElementById("boiler_show").style.display = "none"; document.getElementById("boiler_show").style.display = "none";
document.getElementById("sm_show").style.display = "none";
document.getElementById("hp_show").style.display = "none";
return; return;
} }
@@ -98,16 +94,15 @@ function listCustomStats() {
for (var i = 0; i < obj.length; i++) { for (var i = 0; i < obj.length; i++) {
var l = document.createElement("li"); var l = document.createElement("li");
var type = obj[i].type; var type = obj[i].type;
if (type == 1) {
var color = "list-group-item-success";
} else if (type == 2) {
var color = "list-group-item-info";
} else if (type == 3) {
var color = "list-group-item-warning";
} else if (type == 4) {
var color = "list-group-item-success";
} else {
var color = ""; var color = "";
if (type === 1) {
color = "list-group-item-success";
} else if (type === 2) {
color = "list-group-item-info";
} else if (type === 3) {
color = "list-group-item-warning";
} else if (type === 4) {
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 + " (Version:" + obj[i].version + " ProductID:" + obj[i].productid + " DeviceID:0x" + obj[i].deviceid + ")";
l.className = "list-group-item " + color; l.className = "list-group-item " + color;

View File

@@ -39,8 +39,6 @@ DS18 ds18;
// set to value >0 if the ESP is overheating or there are timing issues. Recommend a value of 1. // set to value >0 if the ESP is overheating or there are timing issues. Recommend a value of 1.
#define EMSESP_DELAY 0 // initially set to 0 for no delay. Change to 1 if getting WDT resets from wifi #define EMSESP_DELAY 0 // initially set to 0 for no delay. Change to 1 if getting WDT resets from wifi
#define DEFAULT_HEATINGCIRCUIT 1 // default to HC1 for thermostats that support multiple heating circuits like the RC35
// timers, all values are in seconds // timers, all values are in seconds
#define DEFAULT_PUBLISHTIME 120 // every 2 minutes publish MQTT values, including Dallas sensors #define DEFAULT_PUBLISHTIME 120 // every 2 minutes publish MQTT values, including Dallas sensors
Ticker publishValuesTimer; Ticker publishValuesTimer;
@@ -102,7 +100,6 @@ typedef struct {
uint8_t led_gpio; // pin for LED uint8_t led_gpio; // pin for LED
uint8_t dallas_gpio; // pin for attaching external dallas temperature sensors uint8_t dallas_gpio; // pin for attaching external dallas temperature sensors
bool dallas_parasite; // on/off is using parasite bool dallas_parasite; // on/off is using parasite
uint8_t heating_circuit; // number of heating circuit, 1 or 2
uint8_t tx_mode; // TX mode 1,2 or 3 uint8_t tx_mode; // TX mode 1,2 or 3
} _EMSESP_Settings; } _EMSESP_Settings;
@@ -124,11 +121,10 @@ static const command_t project_cmds[] PROGMEM = {
{true, "shower_timer <on | off>", "send MQTT notification on all shower durations"}, {true, "shower_timer <on | off>", "send MQTT notification on all shower durations"},
{true, "shower_alert <on | off>", "stop hot water to send 3 cold burst warnings after max shower time is exceeded"}, {true, "shower_alert <on | off>", "stop hot water to send 3 cold burst warnings after max shower time is exceeded"},
{true, "publish_time <seconds>", "set frequency for publishing data to MQTT (0=off)"}, {true, "publish_time <seconds>", "set frequency for publishing data to MQTT (0=off)"},
{true, "heating_circuit <1 | 2>", "set the main thermostat HC to work with (if using multiple heating circuits)"},
{true, "tx_mode <n>", "changes Tx logic. 1=ems generic, 2=ems+, 3=Junkers HT3"}, {true, "tx_mode <n>", "changes Tx logic. 1=ems generic, 2=ems+, 3=Junkers HT3"},
{false, "info", "show current captured on the devices"}, {false, "info", "show current captured on the devices"},
{false, "log <n | b | t | r | v>", "set logging mode to none, basic, thermostat only, raw or verbose"}, {false, "log <n | b | t | s | r | j | v>", "set logging mode to none, basic, thermostat only, solar module only, raw, jabber or verbose"},
#ifdef TESTS #ifdef TESTS
{false, "test <n>", "insert a test telegram on to the EMS bus"}, {false, "test <n>", "insert a test telegram on to the EMS bus"},
@@ -136,14 +132,14 @@ static const command_t project_cmds[] PROGMEM = {
{false, "publish", "publish all values to MQTT"}, {false, "publish", "publish all values to MQTT"},
{false, "refresh", "fetch values from the EMS devices"}, {false, "refresh", "fetch values from the EMS devices"},
{false, "devices", "list all supported and detected EMS devices and types IDs"}, {false, "devices [all]", "list all supported and detected EMS devices"},
{false, "queue", "show current Tx queue"}, {false, "queue", "show current Tx queue"},
{false, "autodetect [deep]", "detect EMS devices and attempt to automatically set boiler and thermostat types"}, {false, "autodetect [quick | deep]", "detect EMS devices and attempt to automatically set boiler and thermostat types"},
{false, "shower <timer | alert>", "toggle either timer or alert on/off"}, {false, "shower <timer | alert>", "toggle either timer or alert on/off"},
{false, "send XX ...", "send raw telegram data as hex to EMS bus"}, {false, "send XX ...", "send raw telegram data to EMS bus (XX are hex values)"},
{false, "thermostat read <type ID>", "send read request to the thermostat"}, {false, "thermostat read <type ID>", "send read request to the thermostat for heating circuit hc 1-4"},
{false, "thermostat temp <degrees>", "set current thermostat temperature"}, {false, "thermostat temp [hc] <degrees>", "set current thermostat temperature"},
{false, "thermostat mode <mode>", "set mode (0=low/night, 1=manual/day, 2=auto)"}, {false, "thermostat mode [hc] <mode>", "set mode (0=low/night, 1=manual/day, 2=auto) for heating circuit hc 1-4"},
{false, "thermostat scan <type ID>", "probe thermostat on all type id responses"}, {false, "thermostat scan <type ID>", "probe thermostat on all type id responses"},
{false, "boiler read <type ID>", "send read request to boiler"}, {false, "boiler read <type ID>", "send read request to boiler"},
{false, "boiler wwtemp <degrees>", "set boiler warm water temperature"}, {false, "boiler wwtemp <degrees>", "set boiler warm water temperature"},
@@ -392,29 +388,33 @@ void _renderBoolValue(const char * prefix, uint8_t value) {
// figures out the thermostat mode // figures out the thermostat mode
// returns 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day // returns 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
uint8_t _getThermostatMode() { // hc_num is 1 to 4
uint8_t _getThermostatMode(uint8_t hc_num) {
int thermoMode = EMS_VALUE_INT_NOTSET; int thermoMode = EMS_VALUE_INT_NOTSET;
uint8_t model = ems_getThermostatModel();
if (ems_getThermostatModel() == EMS_MODEL_RC20) { uint8_t mode = EMS_Thermostat.hc[hc_num - 1].mode;
if (EMS_Thermostat.mode == 0) {
if (model == EMS_MODEL_RC20) {
if (mode == 0) {
thermoMode = 0; // low thermoMode = 0; // low
} else if (EMS_Thermostat.mode == 1) { } else if (mode == 1) {
thermoMode = 1; // manual thermoMode = 1; // manual
} else if (EMS_Thermostat.mode == 2) { } else if (mode == 2) {
thermoMode = 2; // auto thermoMode = 2; // auto
} }
} else if (ems_getThermostatModel() == EMS_MODEL_RC300) { } else if (model == EMS_MODEL_RC300) {
if (EMS_Thermostat.mode == 0) { if (mode == 0) {
thermoMode = 1; // manual thermoMode = 1; // manual
} else if (EMS_Thermostat.mode == 1) { } else if (mode == 1) {
thermoMode = 2; // auto thermoMode = 2; // auto
} }
} else { // default for all thermostats } else { // default for all other thermostats
if (EMS_Thermostat.mode == 0) { if (mode == 0) {
thermoMode = 3; // night thermoMode = 3; // night
} else if (EMS_Thermostat.mode == 1) { } else if (mode == 1) {
thermoMode = 4; // day thermoMode = 4; // day
} else if (EMS_Thermostat.mode == 2) { } else if (mode == 2) {
thermoMode = 2; // auto thermoMode = 2; // auto
} }
} }
@@ -459,7 +459,7 @@ void showInfo() {
myDebug_P(PSTR("\n%sEMS Bus stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); myDebug_P(PSTR("\n%sEMS Bus stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
if (ems_getBusConnected()) { if (ems_getBusConnected()) {
myDebug_P(PSTR(" Bus is connected")); myDebug_P(PSTR(" Bus is connected, protocol: %s"), ((EMS_Sys_Status.emsIDMask == 0x80) ? "Junkers HT3" : "Buderus"));
myDebug_P(PSTR(" Rx: # successful read requests=%d, # CRC errors=%d"), EMS_Sys_Status.emsRxPgks, EMS_Sys_Status.emxCrcErr); myDebug_P(PSTR(" Rx: # successful read requests=%d, # CRC errors=%d"), EMS_Sys_Status.emsRxPgks, EMS_Sys_Status.emxCrcErr);
if (ems_getTxCapable()) { if (ems_getTxCapable()) {
@@ -602,44 +602,54 @@ void showInfo() {
myDebug_P(PSTR("%sThermostat stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); myDebug_P(PSTR("%sThermostat stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
myDebug_P(PSTR(" Thermostat: %s"), ems_getThermostatDescription(buffer_type, false)); myDebug_P(PSTR(" Thermostat: %s"), ems_getThermostatDescription(buffer_type, false));
// Render Current & Setpoint Room Temperature
if (ems_getThermostatModel() == EMS_MODEL_EASY) {
// Temperatures are *100
_renderShortValue("Set room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 10); // *100
_renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 10); // *100
} else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)
|| (ems_getThermostatModel() == EMS_MODEL_FW120)) {
// Temperatures are *10
_renderShortValue("Set room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 1); // *10
_renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 1); // *10
} else {
// because we store in 2 bytes short, when converting to a single byte we'll loose the negative value if its unset
_renderShortValue("Setpoint room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 2); // convert to a single byte * 2
_renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 1); // is *10
}
// Render Day/Night/Holiday Temperature
if ((EMS_Thermostat.holidaytemp > 0) && (EMSESP_Settings.heating_circuit == 2)) { // only if we are on a RC35 we show more info
_renderIntValue("Day temperature", "C", EMS_Thermostat.daytemp, 2); // convert to a single byte * 2
_renderIntValue("Night temperature", "C", EMS_Thermostat.nighttemp, 2); // convert to a single byte * 2
_renderIntValue("Vacation temperature", "C", EMS_Thermostat.holidaytemp, 2); // convert to a single byte * 2
}
// Render Thermostat Date & Time // Render Thermostat Date & Time
// not for EASY uint8_t model = ems_getThermostatModel();
if ((ems_getThermostatModel() != EMS_MODEL_EASY)) { if ((model != EMS_MODEL_EASY)) {
myDebug_P(PSTR(" Thermostat time is %02d:%02d:%02d %d/%d/%d"), myDebug_P(PSTR(" Thermostat time is %s"), EMS_Thermostat.datetime);
EMS_Thermostat.hour, }
EMS_Thermostat.minute,
EMS_Thermostat.second, uint8_t _m_setpoint, _m_curr;
EMS_Thermostat.day, switch (model) {
EMS_Thermostat.month, case EMS_MODEL_EASY:
EMS_Thermostat.year + 2000); _m_setpoint = 10; // *100
_m_curr = 10; // *100
break;
case EMS_MODEL_FR10:
case EMS_MODEL_FW100:
case EMS_MODEL_FW120:
_m_setpoint = 1; // *10
_m_curr = 1; // *10
break;
default: // RC30, RC35 etc...
_m_setpoint = 2; // *2
_m_curr = 1; // *10
break;
}
// go through all Heating Circuits
for (uint8_t hc_num = 1; hc_num <= EMS_THERMOSTAT_MAXHC; hc_num++) {
// only show if we have data for the Heating Circuit
if (EMS_Thermostat.hc[hc_num - 1].active) {
myDebug_P(PSTR(" Heating Circuit %d"), hc_num);
_renderShortValue(" Current room temperature", "C", EMS_Thermostat.hc[hc_num - 1].curr_roomTemp, _m_curr);
_renderShortValue(" Setpoint room temperature", "C", EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp, _m_setpoint);
// Render Day/Night/Holiday Temperature on RC35s
// there is no single setpoint temp, but one for day, night and vacation
if (model == EMS_MODEL_RC35) {
if (EMS_Thermostat.hc[hc_num - 1].summer_mode) {
myDebug_P(PSTR(" Program is set to Summer mode"));
} else if (EMS_Thermostat.hc[hc_num - 1].holiday_mode) {
myDebug_P(PSTR(" Program is set to Holiday mode"));
}
_renderIntValue(" Day temperature", "C", EMS_Thermostat.hc[hc_num - 1].daytemp, 2); // convert to a single byte * 2
_renderIntValue(" Night temperature", "C", EMS_Thermostat.hc[hc_num - 1].nighttemp, 2); // convert to a single byte * 2
_renderIntValue(" Vacation temperature", "C", EMS_Thermostat.hc[hc_num - 1].holidaytemp, 2); // convert to a single byte * 2
} }
// Render Termostat Mode, if we have a mode // Render Termostat Mode, if we have a mode
uint8_t thermoMode = _getThermostatMode(); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day uint8_t thermoMode = _getThermostatMode(hc_num); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
if (thermoMode == 0) { if (thermoMode == 0) {
myDebug_P(PSTR(" Mode is set to low")); myDebug_P(PSTR(" Mode is set to low"));
} else if (thermoMode == 1) { } else if (thermoMode == 1) {
@@ -652,8 +662,10 @@ void showInfo() {
myDebug_P(PSTR(" Mode is set to day")); myDebug_P(PSTR(" Mode is set to day"));
} }
} }
}
}
// Dallas // Dallas external temp sensors
if (EMSESP_Settings.dallas_sensors != 0) { if (EMSESP_Settings.dallas_sensors != 0) {
myDebug_P(PSTR("")); // newline myDebug_P(PSTR("")); // newline
char buffer[128] = {0}; char buffer[128] = {0};
@@ -715,6 +727,11 @@ void publishValues(bool force) {
return; return;
} }
// don't publish is publish time is set to 0
if (EMSESP_Settings.publish_time == 0) {
return;
}
char s[20] = {0}; // for formatting strings char s[20] = {0}; // for formatting strings
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc; StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
char data[MQTT_MAX_PAYLOAD_SIZE] = {0}; char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
@@ -826,48 +843,56 @@ void publishValues(bool force) {
last_boilerActive = ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive); // remember last state last_boilerActive = ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive); // remember last state
} }
// handle the thermostat values separately // handle the thermostat values
// only send thermostat values if we actually have them if (ems_getThermostatEnabled()) {
if (ems_getThermostatEnabled() && ((EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) && (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET))) { uint8_t total_active_hc = 0; // number of HCs
bool hc_1_active = EMS_Thermostat.hc[EMS_THERMOSTAT_DEFAULTHC - 1].active; // do we have HC1 active?
for (uint8_t hc_v = 1; hc_v <= EMS_THERMOSTAT_MAXHC; hc_v++) {
_EMS_Thermostat_HC * thermostat = &EMS_Thermostat.hc[hc_v - 1];
// only send if we have an active Heating Circuit with real data
if (thermostat->active) {
total_active_hc++; // increase count for #HCs we encounter
// build new json object // build new json object
doc.clear(); doc.clear();
JsonObject rootThermostat = doc.to<JsonObject>(); JsonObject rootThermostat = doc.to<JsonObject>();
rootThermostat[THERMOSTAT_HC] = _int_to_char(s, EMSESP_Settings.heating_circuit); rootThermostat[THERMOSTAT_HC] = _int_to_char(s, thermostat->hc); // heating circuit 1..4
// different logic depending on thermostat types // different logic depending on thermostat types
if (ems_getThermostatModel() == EMS_MODEL_EASY) { if (ems_getThermostatModel() == EMS_MODEL_EASY) {
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 100; rootThermostat[THERMOSTAT_SELTEMP] = (double)thermostat->setpoint_roomTemp / 100;
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 100; rootThermostat[THERMOSTAT_CURRTEMP] = (double)thermostat->curr_roomTemp / 100;
} else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100) } else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)
|| (ems_getThermostatModel() == EMS_MODEL_FW120)) { || (ems_getThermostatModel() == EMS_MODEL_FW120)) {
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 10; rootThermostat[THERMOSTAT_SELTEMP] = (double)thermostat->setpoint_roomTemp / 10;
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 10; rootThermostat[THERMOSTAT_CURRTEMP] = (double)thermostat->curr_roomTemp / 10;
} else { } else {
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) if (thermostat->setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 2; rootThermostat[THERMOSTAT_SELTEMP] = (double)thermostat->setpoint_roomTemp / 2;
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) if (thermostat->curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 10; rootThermostat[THERMOSTAT_CURRTEMP] = (double)thermostat->curr_roomTemp / 10;
if (EMS_Thermostat.daytemp != EMS_VALUE_INT_NOTSET) if (thermostat->daytemp != EMS_VALUE_INT_NOTSET)
rootThermostat[THERMOSTAT_DAYTEMP] = (double)EMS_Thermostat.daytemp / 2; rootThermostat[THERMOSTAT_DAYTEMP] = (double)thermostat->daytemp / 2;
if (EMS_Thermostat.nighttemp != EMS_VALUE_INT_NOTSET) if (thermostat->nighttemp != EMS_VALUE_INT_NOTSET)
rootThermostat[THERMOSTAT_NIGHTTEMP] = (double)EMS_Thermostat.nighttemp / 2; rootThermostat[THERMOSTAT_NIGHTTEMP] = (double)thermostat->nighttemp / 2;
if (EMS_Thermostat.holidaytemp != EMS_VALUE_INT_NOTSET) if (thermostat->holidaytemp != EMS_VALUE_INT_NOTSET)
rootThermostat[THERMOSTAT_HOLIDAYTEMP] = (double)EMS_Thermostat.holidaytemp / 2; rootThermostat[THERMOSTAT_HOLIDAYTEMP] = (double)thermostat->holidaytemp / 2;
if (EMS_Thermostat.heatingtype != EMS_VALUE_INT_NOTSET) if (thermostat->heatingtype != EMS_VALUE_INT_NOTSET)
rootThermostat[THERMOSTAT_HEATINGTYPE] = EMS_Thermostat.heatingtype; rootThermostat[THERMOSTAT_HEATINGTYPE] = thermostat->heatingtype;
if (EMS_Thermostat.circuitcalctemp != EMS_VALUE_INT_NOTSET) if (thermostat->circuitcalctemp != EMS_VALUE_INT_NOTSET)
rootThermostat[THERMOSTAT_CIRCUITCALCTEMP] = EMS_Thermostat.circuitcalctemp; rootThermostat[THERMOSTAT_CIRCUITCALCTEMP] = thermostat->circuitcalctemp;
} }
uint8_t thermoMode = _getThermostatMode(); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day uint8_t thermoMode = _getThermostatMode(hc_v); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
// Termostat Mode // Termostat Mode
if (thermoMode == 0) { if (thermoMode == 0) {
@@ -896,10 +921,19 @@ void publishValues(bool force) {
fchecksum = crc.finalize(); fchecksum = crc.finalize();
if ((previousThermostatPublishCRC != fchecksum) || force) { if ((previousThermostatPublishCRC != fchecksum) || force) {
previousThermostatPublishCRC = fchecksum; previousThermostatPublishCRC = fchecksum;
char thermostat_topicname[20];
strlcpy(thermostat_topicname, TOPIC_THERMOSTAT_DATA, sizeof(thermostat_topicname)); // "thermostat_data"
// if we have more than 1 active Heating Circuit
// or this is single HC and its not HC1
// append topic name with the HC number
if ((total_active_hc > 1) || ((total_active_hc == 1) && (!hc_1_active))) {
char buffer[4];
strlcat(thermostat_topicname, itoa(total_active_hc, buffer, 10), sizeof(thermostat_topicname));
}
myDebugLog("Publishing thermostat data via MQTT"); myDebugLog("Publishing thermostat data via MQTT");
myESP.mqttPublish(thermostat_topicname, data);
// send values via MQTT }
myESP.mqttPublish(TOPIC_THERMOSTAT_DATA, data); }
} }
} }
} }
@@ -1029,7 +1063,7 @@ char * _readWord() {
// publish external dallas sensor temperature values to MQTT // publish external dallas sensor temperature values to MQTT
void do_publishSensorValues() { void do_publishSensorValues() {
if (EMSESP_Settings.dallas_sensors != 0) { if ((EMSESP_Settings.dallas_sensors != 0) && (EMSESP_Settings.publish_time != 0)) {
publishSensorValues(); publishSensorValues();
} }
} }
@@ -1066,7 +1100,7 @@ void do_scanThermostat() {
// do a system health check every now and then to see if we all connections // do a system health check every now and then to see if we all connections
void do_systemCheck() { void do_systemCheck() {
if (!ems_getBusConnected()) { if (!ems_getBusConnected() && !myESP.getUseSerial()) {
myDebug_P(PSTR("Error! Unable to read the EMS bus.")); myDebug_P(PSTR("Error! Unable to read the EMS bus."));
} }
} }
@@ -1075,7 +1109,7 @@ void do_systemCheck() {
// only if we have a EMS connection // only if we have a EMS connection
void do_regularUpdates() { void do_regularUpdates() {
if (ems_getBusConnected() && !ems_getTxDisabled()) { if (ems_getBusConnected() && !ems_getTxDisabled()) {
myDebugLog("Requesting scheduled EMS device data"); myDebugLog("Starting scheduled query from EMS devices");
ems_getThermostatValues(); ems_getThermostatValues();
ems_getBoilerValues(); ems_getBoilerValues();
ems_getSolarModuleValues(); ems_getSolarModuleValues();
@@ -1165,9 +1199,15 @@ void runUnitTest(uint8_t test_num) {
} }
// callback for loading/saving settings to the file system (SPIFFS) // callback for loading/saving settings to the file system (SPIFFS)
bool LoadSaveCallback(MYESP_FSACTION action, JsonObject json) { bool LoadSaveCallback(MYESP_FSACTION action, JsonObject settings) {
if (action == MYESP_FSACTION_LOAD) { if (action == MYESP_FSACTION_LOAD) {
const JsonObject & settings = json["settings"]; // check for valid json
if (settings.isNull()) {
myDebug_P(PSTR("Error processing json settings"));
return false;
}
// serializeJsonPretty(settings, Serial); // for debugging
EMSESP_Settings.led = settings["led"]; EMSESP_Settings.led = settings["led"];
EMSESP_Settings.led_gpio = settings["led_gpio"] | EMSESP_LED_GPIO; EMSESP_Settings.led_gpio = settings["led_gpio"] | EMSESP_LED_GPIO;
@@ -1180,18 +1220,13 @@ bool LoadSaveCallback(MYESP_FSACTION action, JsonObject json) {
EMSESP_Settings.listen_mode = settings["listen_mode"]; EMSESP_Settings.listen_mode = settings["listen_mode"];
ems_setTxDisabled(EMSESP_Settings.listen_mode); ems_setTxDisabled(EMSESP_Settings.listen_mode);
EMSESP_Settings.heating_circuit = settings["heating_circuit"] | DEFAULT_HEATINGCIRCUIT; EMSESP_Settings.tx_mode = settings["tx_mode"] | EMS_TXMODE_DEFAULT; // default to 1 (generic)
ems_setThermostatHC(EMSESP_Settings.heating_circuit);
EMSESP_Settings.tx_mode = settings["tx_mode"] | 1; // default to 1 (generic)
ems_setTxMode(EMSESP_Settings.tx_mode); ems_setTxMode(EMSESP_Settings.tx_mode);
return true; return true;
} }
if (action == MYESP_FSACTION_SAVE) { if (action == MYESP_FSACTION_SAVE) {
JsonObject settings = json.createNestedObject("settings");
settings["led"] = EMSESP_Settings.led; settings["led"] = EMSESP_Settings.led;
settings["led_gpio"] = EMSESP_Settings.led_gpio; settings["led_gpio"] = EMSESP_Settings.led_gpio;
settings["dallas_gpio"] = EMSESP_Settings.dallas_gpio; settings["dallas_gpio"] = EMSESP_Settings.dallas_gpio;
@@ -1200,7 +1235,6 @@ bool LoadSaveCallback(MYESP_FSACTION action, JsonObject json) {
settings["shower_timer"] = EMSESP_Settings.shower_timer; settings["shower_timer"] = EMSESP_Settings.shower_timer;
settings["shower_alert"] = EMSESP_Settings.shower_alert; settings["shower_alert"] = EMSESP_Settings.shower_alert;
settings["publish_time"] = EMSESP_Settings.publish_time; settings["publish_time"] = EMSESP_Settings.publish_time;
settings["heating_circuit"] = EMSESP_Settings.heating_circuit;
settings["tx_mode"] = EMSESP_Settings.tx_mode; settings["tx_mode"] = EMSESP_Settings.tx_mode;
return true; return true;
@@ -1308,22 +1342,10 @@ bool SetListCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, co
ok = true; ok = true;
} }
// heating_circuit
if ((strcmp(setting, "heating_circuit") == 0) && (wc == 2)) {
uint8_t hc = atoi(value);
if ((hc >= 1) && (hc <= 2)) {
EMSESP_Settings.heating_circuit = hc;
ems_setThermostatHC(hc);
ok = true;
} else {
myDebug_P(PSTR("Error. Usage: set heating_circuit <1 | 2>"));
}
}
// tx_mode // tx_mode
if ((strcmp(setting, "tx_mode") == 0) && (wc == 2)) { if ((strcmp(setting, "tx_mode") == 0) && (wc == 2)) {
uint8_t mode = atoi(value); uint8_t mode = atoi(value);
if ((mode >= 1) && (mode <= 3)) { if ((mode >= 1) && (mode <= 3)) { // see ems.h for definitions
EMSESP_Settings.tx_mode = mode; EMSESP_Settings.tx_mode = mode;
ems_setTxMode(mode); ems_setTxMode(mode);
ok = true; ok = true;
@@ -1338,7 +1360,6 @@ bool SetListCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, co
myDebug_P(PSTR(" led_gpio=%d"), EMSESP_Settings.led_gpio); myDebug_P(PSTR(" led_gpio=%d"), EMSESP_Settings.led_gpio);
myDebug_P(PSTR(" dallas_gpio=%d"), EMSESP_Settings.dallas_gpio); myDebug_P(PSTR(" dallas_gpio=%d"), EMSESP_Settings.dallas_gpio);
myDebug_P(PSTR(" dallas_parasite=%s"), EMSESP_Settings.dallas_parasite ? "on" : "off"); myDebug_P(PSTR(" dallas_parasite=%s"), EMSESP_Settings.dallas_parasite ? "on" : "off");
myDebug_P(PSTR(" heating_circuit=%d"), EMSESP_Settings.heating_circuit);
myDebug_P(PSTR(" tx_mode=%d"), EMSESP_Settings.tx_mode); myDebug_P(PSTR(" tx_mode=%d"), EMSESP_Settings.tx_mode);
myDebug_P(PSTR(" listen_mode=%s"), EMSESP_Settings.listen_mode ? "on" : "off"); myDebug_P(PSTR(" listen_mode=%s"), EMSESP_Settings.listen_mode ? "on" : "off");
myDebug_P(PSTR(" shower_timer=%s"), EMSESP_Settings.shower_timer ? "on" : "off"); myDebug_P(PSTR(" shower_timer=%s"), EMSESP_Settings.shower_timer ? "on" : "off");
@@ -1418,7 +1439,14 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
} }
if (strcmp(first_cmd, "devices") == 0) { if (strcmp(first_cmd, "devices") == 0) {
ems_printAllDevices(); if (wc == 2) {
char * second_cmd = _readWord();
if (strcmp(second_cmd, "all") == 0) {
ems_printAllDevices(); // verbose
}
} else {
ems_printDevices();
}
ok = true; ok = true;
} }
@@ -1433,17 +1461,17 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
if (strcmp(second_cmd, "deep") == 0) { if (strcmp(second_cmd, "deep") == 0) {
startDeviceScan(); startDeviceScan();
ok = true; ok = true;
} else if (strcmp(second_cmd, "quick") == 0) {
ems_clearDeviceList();
ems_doReadCommand(EMS_TYPE_UBADevices, EMS_Boiler.device_id);
ok = true;
} }
} else { } else {
ems_scanDevices(); ems_scanDevices(); // normal known device scan
ok = true; ok = true;
} }
} }
if (strcmp(first_cmd, "startup") == 0) {
ems_startupTelegrams();
ok = true;
}
// shower settings // shower settings
if ((strcmp(first_cmd, "shower") == 0) && (wc == 2)) { if ((strcmp(first_cmd, "shower") == 0) && (wc == 2)) {
@@ -1487,13 +1515,21 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
} }
// thermostat commands // thermostat commands
if ((strcmp(first_cmd, "thermostat") == 0) && (wc == 3)) { if ((strcmp(first_cmd, "thermostat") == 0) && (wc >= 3)) {
char * second_cmd = _readWord(); char * second_cmd = _readWord();
uint8_t hc = EMS_THERMOSTAT_DEFAULTHC;
if (strcmp(second_cmd, "temp") == 0) { if (strcmp(second_cmd, "temp") == 0) {
ems_setThermostatTemp(_readFloatNumber()); if (wc == 4) {
hc = _readIntNumber(); // next parameter is the heating circuit
}
ems_setThermostatTemp(_readFloatNumber(), hc);
ok = true; ok = true;
} else if (strcmp(second_cmd, "mode") == 0) { } else if (strcmp(second_cmd, "mode") == 0) {
ems_setThermostatMode(_readIntNumber()); if (wc == 4) {
hc = _readIntNumber(); // next parameter is the heating circuit
}
ems_setThermostatMode(_readIntNumber(), hc);
ok = true; ok = true;
} else if (strcmp(second_cmd, "read") == 0) { } else if (strcmp(second_cmd, "read") == 0) {
ems_doReadCommand(_readHexNumber(), EMS_Thermostat.device_id); ems_doReadCommand(_readHexNumber(), EMS_Thermostat.device_id);
@@ -1541,7 +1577,7 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
} }
// send raw // send raw
if (strcmp(first_cmd, "send") == 0) { if ((strcmp(first_cmd, "send") == 0) && (wc > 1)) {
ems_sendRawTelegram((char *)&commandLine[5]); ems_sendRawTelegram((char *)&commandLine[5]);
ok = true; ok = true;
} }
@@ -1554,7 +1590,7 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
// check for invalid command // check for invalid command
if (!ok) { if (!ok) {
myDebug_P(PSTR("Unknown command. Use ? for help.")); myDebug_P(PSTR("Unknown command or wrong number of arguments. Use ? for help."));
} }
} }
@@ -1570,17 +1606,69 @@ void OTACallback_post() {
emsuart_start(); emsuart_start();
} }
// see's if a topic is appended with an interger value
// used to identify a heating circuit
// returns HC number
uint8_t _hasHCspecified(const char * topic, const char * input) {
int orig_len = strlen(topic); // original length of the topic we're comparing too
// check if the strings match ignoring any suffix
if (strncmp(input, topic, orig_len) == 0) {
// see if we have additional chars at the end, we want none or 1
uint8_t diff = (strlen(input) - orig_len);
if (diff > 1) {
return 0; // invalid
}
if (diff == 0) {
return EMS_THERMOSTAT_DEFAULTHC; // identical, use default
}
// return the value of the last char, 0-9
return input[orig_len] - '0';
}
return 0; // invalid
}
// MQTT Callback to handle incoming/outgoing changes // MQTT Callback to handle incoming/outgoing changes
void MQTTCallback(unsigned int type, const char * topic, const char * message) { void MQTTCallback(unsigned int type, const char * topic, const char * message) {
// we're connected. lets subscribe to some topics // we're connected. lets subscribe to some topics
if (type == MQTT_CONNECT_EVENT) { if (type == MQTT_CONNECT_EVENT) {
// subscribe to the 4 heating circuits
char topic_s[50];
char buffer[4];
// subscribe to the normal batch to be backwards compatible
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_TEMP); myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_TEMP);
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_MODE); myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_MODE);
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_HC);
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_DAYTEMP); myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_DAYTEMP);
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_NIGHTTEMP); myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_NIGHTTEMP);
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP); myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP);
for (uint8_t hc = 1; hc <= EMS_THERMOSTAT_MAXHC; hc++) {
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_TEMP, sizeof(topic_s));
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end
myESP.mqttSubscribe(topic_s);
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_MODE, sizeof(topic_s));
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end
myESP.mqttSubscribe(topic_s);
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_DAYTEMP, sizeof(topic_s));
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end
myESP.mqttSubscribe(topic_s);
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_NIGHTTEMP, sizeof(topic_s));
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end
myESP.mqttSubscribe(topic_s);
strlcpy(topic_s, TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP, sizeof(topic_s));
strlcat(topic_s, itoa(hc, buffer, 10), sizeof(topic_s)); // add 1-4 at the end
myESP.mqttSubscribe(topic_s);
}
myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWACTIVATED); myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWACTIVATED);
myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWTEMP); myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWTEMP);
myESP.mqttSubscribe(TOPIC_BOILER_CMD_COMFORT); myESP.mqttSubscribe(TOPIC_BOILER_CMD_COMFORT);
@@ -1597,59 +1685,60 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
// handle incoming MQTT publish events // handle incoming MQTT publish events
if (type == MQTT_MESSAGE_EVENT) { if (type == MQTT_MESSAGE_EVENT) {
uint8_t hc;
// thermostat temp changes // thermostat temp changes
if (strcmp(topic, TOPIC_THERMOSTAT_CMD_TEMP) == 0) { hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_TEMP, topic);
if (hc) {
float f = strtof((char *)message, 0); float f = strtof((char *)message, 0);
char s[10] = {0}; char s[10] = {0};
myDebug_P(PSTR("MQTT topic: thermostat temperature value %s"), _float_to_char(s, f)); myDebug_P(PSTR("MQTT topic: thermostat HC%d temperature value %s"), hc, _float_to_char(s, f));
ems_setThermostatTemp(f); ems_setThermostatTemp(f, hc);
publishValues(true); // publish back immediately, can't remember why I do this?! publishValues(true); // publish back immediately
return;
} }
// thermostat mode changes // thermostat mode changes
if (strcmp(topic, TOPIC_THERMOSTAT_CMD_MODE) == 0) { hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_MODE, topic);
myDebug_P(PSTR("MQTT topic: thermostat mode value %s"), message); if (hc) {
myDebug_P(PSTR("MQTT topic: thermostat HC%d mode value %s"), hc, message);
if (strcmp((char *)message, "auto") == 0) { if (strcmp((char *)message, "auto") == 0) {
ems_setThermostatMode(2); ems_setThermostatMode(2, hc);
} else if (strcmp((char *)message, "day") == 0 || strcmp((char *)message, "manual") == 0) { } else if (strcmp((char *)message, "day") == 0 || (strcmp((char *)message, "manual") == 0) || (strcmp((char *)message, "heat") == 0)) {
ems_setThermostatMode(1); ems_setThermostatMode(1, hc);
} else if (strcmp((char *)message, "night") == 0 || strcmp((char *)message, "off") == 0) { } else if (strcmp((char *)message, "night") == 0 || strcmp((char *)message, "off") == 0) {
ems_setThermostatMode(0); ems_setThermostatMode(0, hc);
}
}
// thermostat heating circuit change
if (strcmp(topic, TOPIC_THERMOSTAT_CMD_HC) == 0) {
myDebug_P(PSTR("MQTT topic: thermostat heating circuit value %s"), message);
uint8_t hc = atoi((char *)message);
if ((hc >= 1) && (hc <= 2)) {
EMSESP_Settings.heating_circuit = hc;
ems_setThermostatHC(hc);
} }
return;
} }
// set night temp value // set night temp value
if (strcmp(topic, TOPIC_THERMOSTAT_CMD_NIGHTTEMP) == 0) { hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_NIGHTTEMP, topic);
if (hc) {
float f = strtof((char *)message, 0); float f = strtof((char *)message, 0);
char s[10] = {0}; char s[10] = {0};
myDebug_P(PSTR("MQTT topic: new thermostat night temperature value %s"), _float_to_char(s, f)); myDebug_P(PSTR("MQTT topic: new thermostat HC%d night temperature value %s"), hc, _float_to_char(s, f));
ems_setThermostatTemp(f, 1); ems_setThermostatTemp(f, hc, 1); // night
return;
} }
// set daytemp value // set daytemp value
if (strcmp(topic, TOPIC_THERMOSTAT_CMD_DAYTEMP) == 0) { hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_DAYTEMP, topic);
if (hc) {
float f = strtof((char *)message, 0); float f = strtof((char *)message, 0);
char s[10] = {0}; char s[10] = {0};
myDebug_P(PSTR("MQTT topic: new thermostat day temperature value %s"), _float_to_char(s, f)); myDebug_P(PSTR("MQTT topic: new thermostat HC%d day temperature value %s"), hc, _float_to_char(s, f));
ems_setThermostatTemp(f, 2); ems_setThermostatTemp(f, hc, 2); // day
return;
} }
// set holiday value // set holiday value
if (strcmp(topic, TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP) == 0) { hc = _hasHCspecified(TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP, topic);
if (hc) {
float f = strtof((char *)message, 0); float f = strtof((char *)message, 0);
char s[10] = {0}; char s[10] = {0};
myDebug_P(PSTR("MQTT topic: new thermostat holiday temperature value %s"), _float_to_char(s, f)); myDebug_P(PSTR("MQTT topic: new thermostat HC%d holiday temperature value %s"), hc, _float_to_char(s, f));
ems_setThermostatTemp(f, 3); ems_setThermostatTemp(f, hc, 3); // holiday
return;
} }
// wwActivated // wwActivated
@@ -1659,6 +1748,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
} else if (message[0] == '0' || strcmp(message, "off") == 0) { } else if (message[0] == '0' || strcmp(message, "off") == 0) {
ems_setWarmWaterActivated(false); ems_setWarmWaterActivated(false);
} }
return;
} }
// boiler wwtemp changes // boiler wwtemp changes
@@ -1667,6 +1757,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
myDebug_P(PSTR("MQTT topic: boiler warm water temperature value %d"), t); myDebug_P(PSTR("MQTT topic: boiler warm water temperature value %d"), t);
ems_setWarmWaterTemp(t); ems_setWarmWaterTemp(t);
publishValues(true); // publish back immediately, can't remember why I do this?! publishValues(true); // publish back immediately, can't remember why I do this?!
return;
} }
// boiler ww comfort setting // boiler ww comfort setting
@@ -1679,6 +1770,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
} else if (strcmp((char *)message, "intelligent") == 0) { } else if (strcmp((char *)message, "intelligent") == 0) {
ems_setWarmWaterModeComfort(3); ems_setWarmWaterModeComfort(3);
} }
return;
} }
// boiler flowtemp setting // boiler flowtemp setting
@@ -1686,6 +1778,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
uint8_t t = atoi((char *)message); uint8_t t = atoi((char *)message);
myDebug_P(PSTR("MQTT topic: boiler flowtemp value %d"), t); myDebug_P(PSTR("MQTT topic: boiler flowtemp value %d"), t);
ems_setFlowTemp(t); ems_setFlowTemp(t);
return;
} }
// shower timer // shower timer
@@ -1696,6 +1789,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
EMSESP_Settings.shower_timer = false; EMSESP_Settings.shower_timer = false;
} }
set_showerTimer(); set_showerTimer();
return;
} }
// shower alert // shower alert
@@ -1706,11 +1800,13 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
EMSESP_Settings.shower_alert = false; EMSESP_Settings.shower_alert = false;
} }
set_showerAlert(); set_showerAlert();
return;
} }
// shower cold shot // shower cold shot
if (strcmp(topic, TOPIC_SHOWER_COLDSHOT) == 0) { if (strcmp(topic, TOPIC_SHOWER_COLDSHOT) == 0) {
_showerColdShotStart(); _showerColdShotStart();
return;
} }
} }
} }
@@ -1719,7 +1815,6 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
void WIFICallback() { void WIFICallback() {
// This is where we enable the UART service to scan the incoming serial Tx/Rx bus signals // This is where we enable the UART service to scan the incoming serial Tx/Rx bus signals
// This is done after we have a WiFi signal to avoid any resource conflicts // This is done after we have a WiFi signal to avoid any resource conflicts
// TODO see if EMS bus is blocked during startup and whether we still need to delay the UART with the swap below?
// system_uart_swap(); // system_uart_swap();
} }
@@ -1748,20 +1843,28 @@ void WebCallback(JsonObject root) {
} }
} }
// send over EMS devices
JsonArray list = emsbus.createNestedArray("devices"); JsonArray list = emsbus.createNestedArray("devices");
for (std::list<_Generic_Device>::iterator it = Devices.begin(); it != Devices.end(); it++) { for (std::list<_Generic_Device>::iterator it = Devices.begin(); it != Devices.end(); ++it) {
JsonObject item = list.createNestedObject(); JsonObject item = list.createNestedObject();
item["type"] = (it)->model_type; item["type"] = (it)->model_type;
item["model"] = (it)->model_string; item["model"] = (it)->model_string;
item["version"] = (it)->version; item["version"] = (it)->version;
item["productid"] = (it)->product_id; item["productid"] = (it)->product_id;
char s[10]; char buffer[10];
itoa((it)->device_id, s, 16); // copy of my _hextoa() function from ems.cpp, to convert device_id into a 0xNN hex value string
item["deviceid"] = s; // convert to hex char * p = buffer;
byte nib1 = ((it)->device_id >> 4) & 0x0F;
byte nib2 = ((it)->device_id >> 0) & 0x0F;
*p++ = nib1 < 0xA ? '0' + nib1 : 'A' + nib1 - 0xA;
*p++ = nib2 < 0xA ? '0' + nib2 : 'A' + nib2 - 0xA;
*p = '\0'; // null terminate just in case
item["deviceid"] = buffer;
} }
// send over Thermostat data
JsonObject thermostat = root.createNestedObject("thermostat"); JsonObject thermostat = root.createNestedObject("thermostat");
if (ems_getThermostatEnabled()) { if (ems_getThermostatEnabled()) {
@@ -1770,27 +1873,29 @@ void WebCallback(JsonObject root) {
char buffer[200]; char buffer[200];
thermostat["tm"] = ems_getThermostatDescription(buffer, true); thermostat["tm"] = ems_getThermostatDescription(buffer, true);
uint8_t hc_num = EMS_THERMOSTAT_DEFAULTHC; // default to HC1
// Render Current & Setpoint Room Temperature // Render Current & Setpoint Room Temperature
if (ems_getThermostatModel() == EMS_MODEL_EASY) { if (ems_getThermostatModel() == EMS_MODEL_EASY) {
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
thermostat["ts"] = (double)EMS_Thermostat.setpoint_roomTemp / 100; thermostat["ts"] = (double)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 100;
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
thermostat["tc"] = (double)EMS_Thermostat.curr_roomTemp / 100; thermostat["tc"] = (double)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 100;
} else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100) } else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)
|| (ems_getThermostatModel() == EMS_MODEL_FW120)) { || (ems_getThermostatModel() == EMS_MODEL_FW120)) {
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
thermostat["ts"] = (double)EMS_Thermostat.setpoint_roomTemp / 10; thermostat["ts"] = (double)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 10;
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
thermostat["tc"] = (double)EMS_Thermostat.curr_roomTemp / 10; thermostat["tc"] = (double)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 10;
} else { } else {
if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) if (EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET)
thermostat["ts"] = (double)EMS_Thermostat.setpoint_roomTemp / 2; thermostat["ts"] = (double)EMS_Thermostat.hc[hc_num - 1].setpoint_roomTemp / 2;
if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) if (EMS_Thermostat.hc[hc_num - 1].curr_roomTemp != EMS_VALUE_SHORT_NOTSET)
thermostat["tc"] = (double)EMS_Thermostat.curr_roomTemp / 10; thermostat["tc"] = (double)EMS_Thermostat.hc[hc_num - 1].curr_roomTemp / 10;
} }
// Render Termostat Mode, if we have a mode // Render Termostat Mode, if we have a mode
uint8_t thermoMode = _getThermostatMode(); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day uint8_t thermoMode = _getThermostatMode(hc_num); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day
if (thermoMode == 0) { if (thermoMode == 0) {
thermostat["tmode"] = "low"; thermostat["tmode"] = "low";
} else if (thermoMode == 1) { } else if (thermoMode == 1) {
@@ -1899,8 +2004,7 @@ void initEMSESP() {
EMSESP_Settings.dallas_sensors = 0; EMSESP_Settings.dallas_sensors = 0;
EMSESP_Settings.led_gpio = EMSESP_LED_GPIO; EMSESP_Settings.led_gpio = EMSESP_LED_GPIO;
EMSESP_Settings.dallas_gpio = EMSESP_DALLAS_GPIO; EMSESP_Settings.dallas_gpio = EMSESP_DALLAS_GPIO;
EMSESP_Settings.heating_circuit = 1; // default heating circuit to HC1 EMSESP_Settings.tx_mode = EMS_TXMODE_DEFAULT; // default tx mode
EMSESP_Settings.tx_mode = 1; // default tx mode
// shower settings // shower settings
EMSESP_Shower.timerStart = 0; EMSESP_Shower.timerStart = 0;
@@ -2023,13 +2127,17 @@ void setup() {
} }
} }
// enable regular checks if not in test mode // enable regular checks
if (!EMSESP_Settings.listen_mode) { if (!EMSESP_Settings.listen_mode) {
publishValuesTimer.attach(EMSESP_Settings.publish_time, do_publishValues); // post MQTT EMS values
publishSensorValuesTimer.attach(EMSESP_Settings.publish_time, do_publishSensorValues); // post MQTT sensor values
regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS
} }
// set timers for MQTT publish
if (EMSESP_Settings.publish_time != 0) {
publishValuesTimer.attach(EMSESP_Settings.publish_time, do_publishValues); // post MQTT EMS values
publishSensorValuesTimer.attach(EMSESP_Settings.publish_time, do_publishSensorValues); // post MQTT dallas sensor values
}
// set pin for LED // set pin for LED
if (EMSESP_Settings.led_gpio != EMS_VALUE_INT_NOTSET) { if (EMSESP_Settings.led_gpio != EMS_VALUE_INT_NOTSET) {
pinMode(EMSESP_Settings.led_gpio, OUTPUT); pinMode(EMSESP_Settings.led_gpio, OUTPUT);
@@ -2060,7 +2168,7 @@ void loop() {
// publish the values to MQTT, only if the values have changed // publish the values to MQTT, only if the values have changed
// although we don't want to publish when doing a deep scan of the thermostat // although we don't want to publish when doing a deep scan of the thermostat
if (ems_getEmsRefreshed() && (scanThermostat_count == 0) && (!EMSESP_Settings.listen_mode)) { if (ems_getEmsRefreshed() && (scanThermostat_count == 0)) {
publishValues(false); publishValues(false);
ems_setEmsRefreshed(false); // reset ems_setEmsRefreshed(false); // reset
} }

File diff suppressed because it is too large Load Diff

116
src/ems.h
View File

@@ -72,6 +72,11 @@
#endif #endif
// clang-format on // clang-format on
// EMS tx_mode types
#define EMS_TXMODE_DEFAULT 1 // Default (was previously known as tx_mode 2)
#define EMS_TXMODE_EMSPLUS 2 // EMS+
#define EMS_TXMODE_HT3 3 // Junkers HT3
#define EMS_ID_NONE 0x00 // used as a dest in broadcast messages and empty device IDs #define EMS_ID_NONE 0x00 // used as a dest in broadcast messages and empty device IDs
// Fixed EMS IDs // Fixed EMS IDs
@@ -81,16 +86,15 @@
#define EMS_ID_HP 0x38 // HeatPump #define EMS_ID_HP 0x38 // HeatPump
#define EMS_ID_GATEWAY 0x48 // KM200 Web Gateway #define EMS_ID_GATEWAY 0x48 // KM200 Web Gateway
#define EMS_PRODUCTID_HEATRONICS 95 // ProductID for a Junkers Heatronic3 device // Product IDs
#define EMS_PRODUCTID_HEATRONIC 95 // Junkers Heatronic 3 device
#define EMS_PRODUCTID_SM10 73 // ProductID for SM10 solar module #define EMS_PRODUCTID_SM10 73 // SM10 solar module
#define EMS_PRODUCTID_SM100 163 // ProductID for SM10 solar module #define EMS_PRODUCTID_SM50 162 // SM50 solar module
#define EMS_PRODUCTID_ISM1 101 // ProductID for SM10 solar module #define EMS_PRODUCTID_SM100 163 // SM100 solar module
#define EMS_PRODUCTID_ISM1 101 // Junkers ISM1 solar module
#define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC #define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC
#define EMS_MAX_TELEGRAM_LENGTH 32 // max length of a telegram, including CRC, for Rx and Tx.
// max length of a telegram, including CRC, for Rx and Tx.
#define EMS_MAX_TELEGRAM_LENGTH 32
// default values for null values // default values for null values
#define EMS_VALUE_INT_ON 1 // boolean true #define EMS_VALUE_INT_ON 1 // boolean true
@@ -100,6 +104,9 @@
#define EMS_VALUE_USHORT_NOTSET 0x8000 // for 2-byte unsigned 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_LONG_NOTSET 0xFFFFFF // for 3-byte longs
// thermostat specific
#define EMS_THERMOSTAT_MAXHC 4 // max number of heating circuits
#define EMS_THERMOSTAT_DEFAULTHC 1 // default heating circuit is 1
#define EMS_THERMOSTAT_WRITE_YES true #define EMS_THERMOSTAT_WRITE_YES true
#define EMS_THERMOSTAT_WRITE_NO false #define EMS_THERMOSTAT_WRITE_NO false
@@ -107,20 +114,26 @@
#define EMS_BOILER_BURNPOWER_TAPWATER 100 #define EMS_BOILER_BURNPOWER_TAPWATER 100
#define EMS_BOILER_SELFLOWTEMP_HEATING 70 #define EMS_BOILER_SELFLOWTEMP_HEATING 70
// define maximum settable tapwater temperature // define maximum setable tapwater temperature
#define EMS_BOILER_TAPWATER_TEMPERATURE_MAX 60 #define EMS_BOILER_TAPWATER_TEMPERATURE_MAX 60
#define EMS_TX_TELEGRAM_QUEUE_MAX 100 // max size of Tx FIFO queue #define EMS_TX_TELEGRAM_QUEUE_MAX 50 // max size of Tx FIFO queue. Number of Tx records to send.
//#define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_VERBOSE //#define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_VERBOSE // turn on for debugging
#define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_NONE #define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_NONE
// define the model types which get rendered to html colors in the web interface #define EMS_SYS_DEVICEMAP_LENGTH 15 // size of the 0x07 telegram data part which stores all active EMS devices
// define the model types
// which get rendered to html colors in the web interface in file custom.js in function listCustomStats()
#define EMS_MODELTYPE_BOILER 1 // success color #define EMS_MODELTYPE_BOILER 1 // success color
#define EMS_MODELTYPE_THERMOSTAT 2 // info color #define EMS_MODELTYPE_THERMOSTAT 2 // info color
#define EMS_MODELTYPE_SM 3 // warning color #define EMS_MODELTYPE_SM 3 // warning color
#define EMS_MODELTYPE_HP 4 // success color #define EMS_MODELTYPE_HP 4 // success color
#define EMS_MODELTYPE_OTHER 5 // no color #define EMS_MODELTYPE_OTHER 5 // no color
#define EMS_MODELTYPE_UNKNOWN 6 // no color
#define EMS_MODELTYPE_UNKNOWN_STRING "unknown?" // model type text to use when discovering an unknown device
/* EMS UART transfer status */ /* EMS UART transfer status */
typedef enum { typedef enum {
@@ -178,6 +191,7 @@ typedef struct {
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
} _EMS_Sys_Status; } _EMS_Sys_Status;
// The Tx send package // The Tx send package
@@ -237,7 +251,6 @@ typedef struct {
typedef struct { typedef struct {
uint8_t product_id; uint8_t product_id;
uint8_t device_id;
char model_string[50]; char model_string[50];
} _SolarModule_Device; } _SolarModule_Device;
@@ -249,7 +262,6 @@ typedef struct {
typedef struct { typedef struct {
uint8_t product_id; uint8_t product_id;
uint8_t device_id;
char model_string[50]; char model_string[50];
} _HeatPump_Device; } _HeatPump_Device;
@@ -273,7 +285,13 @@ typedef struct {
/* /*
* Telegram package defintions * Telegram package defintions
*/ */
typedef struct { // UBAParameterWW typedef struct {
// settings
uint8_t device_id; // this is typically always 0x08
uint8_t product_id;
char version[10];
// 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
@@ -324,23 +342,19 @@ typedef struct { // UBAParameterWW
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
// settings
char version[10];
uint8_t device_id; // this is typically always 0x08
uint8_t product_id;
} _EMS_Boiler; } _EMS_Boiler;
/* /*
* Telegram package defintions for Other EMS devices * Telegram package defintions for Other EMS devices
*/ */
typedef struct { typedef struct {
uint8_t HPModulation; // heatpump modulation in %
uint8_t HPSpeed; // speed 0-100 %
uint8_t device_id; // the device ID of the Heat Pump (e.g. 0x30) uint8_t device_id; // the device ID of the Heat Pump (e.g. 0x30)
uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) uint8_t model_id; // Solar Module / Heat Pump model
uint8_t product_id; uint8_t product_id;
char version[10]; char version[10];
uint8_t HPModulation; // heatpump modulation in %
uint8_t HPSpeed; // speed 0-100 %
} _EMS_HeatPump; } _EMS_HeatPump;
typedef struct { typedef struct {
@@ -352,6 +366,11 @@ typedef struct {
// SM Solar Module - SM10/SM100/ISM1 // SM Solar Module - SM10/SM100/ISM1
typedef struct { typedef struct {
uint8_t device_id; // the device ID of the Solar Module
uint8_t model_id; // Solar Module
uint8_t product_id;
char version[10];
int16_t collectorTemp; // collector temp int16_t collectorTemp; // collector temp
int16_t bottomTemp; // bottom temp int16_t bottomTemp; // bottom temp
uint8_t pumpModulation; // modulation solar pump uint8_t pumpModulation; // modulation solar pump
@@ -361,35 +380,34 @@ typedef struct {
uint16_t EnergyToday; uint16_t EnergyToday;
uint16_t EnergyTotal; uint16_t EnergyTotal;
uint32_t pumpWorkMin; // Total solar pump operating time uint32_t pumpWorkMin; // Total solar pump operating time
uint8_t device_id; // the device ID of the Solar Module
uint8_t model_id; // Solar Module
uint8_t product_id;
char version[10];
} _EMS_SolarModule; } _EMS_SolarModule;
// heating circuit
typedef struct {
uint8_t hc; // heating circuit 1,2, 3 or 4
bool active; // true if there is data for this HC
int16_t setpoint_roomTemp; // current set temp
int16_t curr_roomTemp; // current room temp
uint8_t mode; // 0=low, 1=manual, 2=auto (or night, day on RC35s)
uint8_t day_mode; // 0=night, 1=day
uint8_t summer_mode;
uint8_t holiday_mode;
uint8_t daytemp;
uint8_t nighttemp;
uint8_t holidaytemp;
uint8_t heatingtype; // type of heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
uint8_t circuitcalctemp; // calculated setpoint flow temperature
} _EMS_Thermostat_HC;
// 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 model_id; // thermostat model uint8_t model_id; // thermostat model
uint8_t product_id; uint8_t product_id;
bool write_supported;
uint8_t hc; // heating circuit 1 or 2
char version[10]; char version[10];
int16_t setpoint_roomTemp; // current set temp char datetime[25]; // HH:MM:SS DD/MM/YYYY
int16_t curr_roomTemp; // current room temp bool write_supported;
uint8_t mode; // 0=low, 1=manual, 2=auto _EMS_Thermostat_HC hc[EMS_THERMOSTAT_MAXHC]; // array for the 4 heating circuits
bool day_mode; // 0=night, 1=day
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t day;
uint8_t month;
uint8_t year;
uint8_t daytemp;
uint8_t nighttemp;
uint8_t holidaytemp;
uint8_t heatingtype;
uint8_t circuitcalctemp;
} _EMS_Thermostat; } _EMS_Thermostat;
// call back function signature for processing telegram types // call back function signature for processing telegram types
@@ -419,9 +437,8 @@ void ems_startupTelegrams();
bool ems_checkEMSBUSAlive(); bool ems_checkEMSBUSAlive();
void ems_clearDeviceList(); void ems_clearDeviceList();
void ems_setThermostatTemp(float temperature, uint8_t temptype = 0); void ems_setThermostatTemp(float temperature, uint8_t hc, uint8_t temptype = 0);
void ems_setThermostatMode(uint8_t mode); void ems_setThermostatMode(uint8_t mode, uint8_t hc);
void ems_setThermostatHC(uint8_t hc);
void ems_setWarmWaterTemp(uint8_t temperature); void ems_setWarmWaterTemp(uint8_t temperature);
void ems_setFlowTemp(uint8_t temperature); void ems_setFlowTemp(uint8_t temperature);
void ems_setWarmWaterActivated(bool activated); void ems_setWarmWaterActivated(bool activated);
@@ -432,9 +449,10 @@ void ems_setEmsRefreshed(bool b);
void ems_setWarmWaterModeComfort(uint8_t comfort); void ems_setWarmWaterModeComfort(uint8_t comfort);
void ems_setModels(); void ems_setModels();
void ems_setTxDisabled(bool b); void ems_setTxDisabled(bool b);
bool ems_getTxDisabled();
void ems_setTxMode(uint8_t mode); void ems_setTxMode(uint8_t mode);
uint8_t _getHeatingCircuit(_EMS_RxTelegram * EMS_RxTelegram);
char * ems_getThermostatDescription(char * buffer, bool name_only = false); char * ems_getThermostatDescription(char * buffer, bool name_only = false);
char * ems_getBoilerDescription(char * buffer, bool name_only = false); char * ems_getBoilerDescription(char * buffer, bool name_only = false);
char * ems_getSolarModuleDescription(char * buffer, bool name_only = false); char * ems_getSolarModuleDescription(char * buffer, bool name_only = false);
@@ -456,6 +474,8 @@ uint8_t ems_getSolarModuleModel();
void ems_discoverModels(); void ems_discoverModels();
bool ems_getTxCapable(); bool ems_getTxCapable();
uint32_t ems_getPollFrequency(); uint32_t ems_getPollFrequency();
bool ems_getTxDisabled();
// private functions // private functions
uint8_t _crcCalculator(uint8_t * data, uint8_t len); uint8_t _crcCalculator(uint8_t * data, uint8_t len);

View File

@@ -16,6 +16,7 @@
* Common Type * Common Type
*/ */
#define EMS_TYPE_Version 0x02 #define EMS_TYPE_Version 0x02
#define EMS_TYPE_UBADevices 0x07 // EMS connected devices
/* /*
* Boiler Telegram Types... * Boiler Telegram Types...
@@ -91,12 +92,20 @@
// RC35 specific // RC35 specific
#define EMS_TYPE_RC35StatusMessage_HC1 0x3E // is an automatic thermostat broadcast giving us temps on HC1 #define EMS_TYPE_RC35StatusMessage_HC1 0x3E // is an automatic thermostat broadcast giving us temps on HC1
#define EMS_TYPE_RC35StatusMessage_HC2 0x48 // is an automatic thermostat broadcast giving us temps on HC2 #define EMS_TYPE_RC35StatusMessage_HC2 0x48 // is an automatic thermostat broadcast giving us temps on HC2
#define EMS_TYPE_RC35StatusMessage_HC3 0x52 // is an automatic thermostat broadcast giving us temps on HC3
#define EMS_TYPE_RC35StatusMessage_HC4 0x5C // is an automatic thermostat broadcast giving us temps on HC4
#define EMS_OFFSET_RC35StatusMessage_setpoint 2 // desired temp #define EMS_OFFSET_RC35StatusMessage_setpoint 2 // desired temp
#define EMS_OFFSET_RC35StatusMessage_curr 3 // current temp #define EMS_OFFSET_RC35StatusMessage_curr 3 // current temp
#define EMS_OFFSET_RC35StatusMessage_mode 1 //day mode #define EMS_OFFSET_RC35StatusMessage_mode 1 // day mode, also summer on RC3's
#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_HC4 0x5B // for setting values like temp and mode (Working mode HC4)
#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
@@ -110,7 +119,10 @@
#define EMS_OFFSET_EasyStatusMessage_curr 8 // current temp #define EMS_OFFSET_EasyStatusMessage_curr 8 // current temp
// RC1010, RC310 and RC300 specific (EMS Plus) // RC1010, RC310 and RC300 specific (EMS Plus)
#define EMS_TYPE_RCPLUSStatusMessage 0x01A5 // is an automatic thermostat broadcast giving us temps, also reading #define EMS_TYPE_RCPLUSStatusMessage_HC1 0x01A5 // is an automatic thermostat broadcast giving us temps for HC1
#define EMS_TYPE_RCPLUSStatusMessage_HC2 0x01A6 // is an automatic thermostat broadcast giving us temps for HC2
#define EMS_TYPE_RCPLUSStatusMessage_HC3 0x01A7 // is an automatic thermostat broadcast giving us temps for HC3
#define EMS_TYPE_RCPLUSStatusMessage_HC4 0x01A8 // is an automatic thermostat broadcast giving us temps for HC4
#define EMS_TYPE_RCPLUSStatusMode 0x1AF // summer/winter mode #define EMS_TYPE_RCPLUSStatusMode 0x1AF // summer/winter mode
#define EMS_OFFSET_RCPLUSStatusMessage_mode 10 // thermostat mode (auto, manual) #define EMS_OFFSET_RCPLUSStatusMessage_mode 10 // thermostat mode (auto, manual)
#define EMS_OFFSET_RCPLUSStatusMessage_setpoint 3 // setpoint temp #define EMS_OFFSET_RCPLUSStatusMessage_setpoint 3 // setpoint temp
@@ -172,26 +184,28 @@ typedef enum {
const _Boiler_Device Boiler_Devices[] = { const _Boiler_Device Boiler_Devices[] = {
{72, "MC10 Module"}, {72, "MC10 Module"},
{123, "Buderus GB172/Nefit Trendline/Junkers Cerapur"}, {123, "Buderus GBx72/Nefit Trendline/Junkers Cerapur"},
{115, "Nefit Topline Compact/Buderus GB162"}, {115, "Nefit Topline Compact/Buderus GB162"},
{203, "Buderus Logamax U122/Junkers Cerapur"}, {203, "Buderus Logamax U122/Junkers Cerapur"},
{208, "Buderus Logamax plus/GB192"}, {208, "Buderus Logamax plus/GB192"},
{64, "Sieger BK15/Nefit Smartline/Buderus GB152"}, {64, "Sieger BK15/Nefit Smartline/Buderus GB152"},
{EMS_PRODUCTID_HEATRONICS, "Bosch Condens 2500/Junkers Heatronics3"}, {EMS_PRODUCTID_HEATRONIC, "Bosch Condens 2500/Junkers Heatronic 3"},
{122, "Nefit Proline"}, {122, "Nefit Proline"},
{170, "Buderus Logano GB212"},
{172, "Nefit Enviline"} {172, "Nefit Enviline"}
}; };
/* /*
* Known Solar Module types * Known Solar Module types, device type 0x30
* format is PRODUCT ID, DEVICE ID, DESCRIPTION * format is PRODUCT ID, DESCRIPTION
*/ */
const _SolarModule_Device SolarModule_Devices[] = { const _SolarModule_Device SolarModule_Devices[] = {
{EMS_PRODUCTID_SM10, EMS_ID_SM, "SM10 Solar Module"}, {EMS_PRODUCTID_SM10, "SM10 Solar Module"},
{EMS_PRODUCTID_SM100, EMS_ID_SM, "SM100 Solar Module"}, {EMS_PRODUCTID_SM100, "SM100 Solar Module"},
{EMS_PRODUCTID_ISM1, EMS_ID_SM, "Junkers ISM1 Solar Module"} {EMS_PRODUCTID_ISM1, "Junkers ISM1 Solar Module"},
{EMS_PRODUCTID_SM50, "SM50 Solar Module"}
}; };
@@ -199,27 +213,31 @@ const _SolarModule_Device SolarModule_Devices[] = {
// format is PRODUCT ID, DEVICE ID, DESCRIPTION // format is PRODUCT ID, DEVICE ID, DESCRIPTION
const _Other_Device Other_Devices[] = { const _Other_Device Other_Devices[] = {
{69, 0x21, "MM10 Mixer Module"},
{71, 0x11, "WM10 Switch Module"}, {71, 0x11, "WM10 Switch Module"},
{69, 0x21, "MM10 Mixer Module"},
{160, 0x20, "MM100 Mixing Module"}, {160, 0x20, "MM100 Mixing Module"},
{160, 0x21, "MM100 Mixing Module"}, {160, 0x21, "MM100 Mixing Module"},
{159, 0x21, "MM50 Mixing Module"}, {159, 0x21, "MM50 Mixing Module"},
{68, 0x09, "BC10/RFM20 Receiver"}, {68, 0x09, "BC10/RFM20 Receiver"},
{190, 0x09, "BC10 Base Controller"}, {190, 0x09, "BC10 Base Controller"},
{114, 0x09, "BC10 Base Controller"}, {114, 0x09, "BC10 Base Controller"},
{125, 0x09, "BC25 Base Controller"}, {125, 0x09, "BC25 Base Controller"},
{169, 0x09, "BC40 Base Controller"},
{152, 0x09, "Junkers Controller"}, {152, 0x09, "Junkers Controller"},
{205, 0x02, "Nefit Moduline Easy Connect"}, {205, 0x02, "Nefit Moduline Easy Connect"},
{206, 0x02, "Bosch Easy Connect"}, {206, 0x02, "Bosch Easy Connect"},
{171, 0x02, "EMS-OT OpenTherm converter"}, {171, 0x02, "EMS-OT OpenTherm converter"},
{252, EMS_ID_HP, "HeatPump Module"},
{189, EMS_ID_GATEWAY, "Web Gateway KM200"} {189, EMS_ID_GATEWAY, "Web Gateway KM200"}
}; };
// heatpump // heatpump, device ID 0x38
// format is PRODUCT ID, DEVICE ID, DESCRIPTION // format is PRODUCT ID, DEVICE ID, DESCRIPTION
const _HeatPump_Device HeatPump_Devices[] = {{252, EMS_ID_HP, "HeatPump Module"}}; const _HeatPump_Device HeatPump_Devices[] = {{252, "HeatPump Module"}};
/* /*
* Known thermostat types and their capabilities * Known thermostat types and their capabilities
@@ -233,13 +251,13 @@ const _Thermostat_Device Thermostat_Devices[] = {
{EMS_MODEL_CW100, 157, 0x18, "Bosch CW100", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_CW100, 157, 0x18, "Bosch CW100", EMS_THERMOSTAT_WRITE_NO},
// Buderus/Nefit // Buderus/Nefit
{EMS_MODEL_RC10, 79, 0x17, "RC10/Nefit Moduline 100", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC10, 79, 0x17, "RC10/Moduline 100", EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC20, 77, 0x17, "RC20/Nefit Moduline 300", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC20, 77, 0x17, "RC20/Moduline 300", EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC20F, 93, 0x18, "RC20F", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC20F, 93, 0x18, "RC20F", EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC30, 78, 0x10, "RC30/Nefit Moduline 400", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC30, 78, 0x10, "RC30/Moduline 400", EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC35, 86, 0x10, "RC35", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC35, 86, 0x10, "RC35", EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_RC300, 158, 0x10, "RC300/RC310/Nefit Moduline 3000", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC300, 158, 0x10, "RC300/RC310/Moduline 3000", EMS_THERMOSTAT_WRITE_YES},
{EMS_MODEL_1010, 165, 0x18, "Nefit Moduline 1010", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_1010, 165, 0x18, "RC100/Moduline 1010", EMS_THERMOSTAT_WRITE_NO},
// Sieger // Sieger
{EMS_MODEL_ES73, 76, 0x10, "Sieger ES73", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_ES73, 76, 0x10, "Sieger ES73", EMS_THERMOSTAT_WRITE_YES},

View File

@@ -191,9 +191,9 @@ void ICACHE_FLASH_ATTR emsuart_tx_brk() {
GPIO_H(TX_MARK_MASK); GPIO_H(TX_MARK_MASK);
USC0(EMSUART_UART) |= (tmp); // set bit USC0(EMSUART_UART) |= (tmp); // set bit
if (EMS_Sys_Status.emsTxMode <= 1) { // classic mode and ems+ (0, 1) if (EMS_Sys_Status.emsTxMode == EMS_TXMODE_EMSPLUS) { // EMS+ mode
delayMicroseconds(EMSUART_TX_BRK_WAIT); delayMicroseconds(EMSUART_TX_BRK_WAIT);
} else if (EMS_Sys_Status.emsTxMode == 3) { // junkers mode } else if (EMS_Sys_Status.emsTxMode == EMS_TXMODE_HT3) { // junkers mode
delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits) delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits)
} }
@@ -214,14 +214,14 @@ _EMS_TX_STATUS ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
if (len) { if (len) {
LA_PULSE(50); LA_PULSE(50);
if (EMS_Sys_Status.emsTxMode == 2) { // With extra tx delay for EMS+ if (EMS_Sys_Status.emsTxMode == EMS_TXMODE_EMSPLUS) { // With extra tx delay for EMS+
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
TX_PULSE(EMSUART_BIT_TIME / 4); TX_PULSE(EMSUART_BIT_TIME / 4);
USF(EMSUART_UART) = buf[i]; USF(EMSUART_UART) = buf[i];
delayMicroseconds(EMSUART_TX_BRK_WAIT); // https://github.com/proddy/EMS-ESP/issues/23# delayMicroseconds(EMSUART_TX_BRK_WAIT); // https://github.com/proddy/EMS-ESP/issues/23#
} }
emsuart_tx_brk(); // send <BRK> emsuart_tx_brk(); // send <BRK>
} else if (EMS_Sys_Status.emsTxMode == 3) { // Junkers logic by @philrich } else if (EMS_Sys_Status.emsTxMode == EMS_TXMODE_HT3) { // Junkers logic by @philrich
for (uint8_t i = 0; i < len; i++) { for (uint8_t i = 0; i < len; i++) {
TX_PULSE(EMSUART_BIT_TIME / 4); TX_PULSE(EMSUART_BIT_TIME / 4);
USF(EMSUART_UART) = buf[i]; USF(EMSUART_UART) = buf[i];
@@ -234,7 +234,7 @@ _EMS_TX_STATUS ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP); delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP);
} }
emsuart_tx_brk(); // send <BRK> emsuart_tx_brk(); // send <BRK>
} else if (EMS_Sys_Status.emsTxMode == 1) { } 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.

View File

@@ -10,14 +10,17 @@
#include "ems.h" #include "ems.h"
// TOPICS with _CMD_ are used for receiving commands from an MQTT Broker
// EMS-ESP will subscribe to these topics
// MQTT for thermostat // MQTT for thermostat
// these topics can be suffixed with a Heating Circuit number, e.g. thermostat_cmd_temp1 and thermostat_data1
#define TOPIC_THERMOSTAT_DATA "thermostat_data" // for sending thermostat values to MQTT #define TOPIC_THERMOSTAT_DATA "thermostat_data" // for sending thermostat values to MQTT
#define TOPIC_THERMOSTAT_CMD_TEMP "thermostat_cmd_temp" // for received thermostat temp changes via MQTT #define TOPIC_THERMOSTAT_CMD_TEMP "thermostat_cmd_temp" // temp changes via MQTT
#define TOPIC_THERMOSTAT_CMD_MODE "thermostat_cmd_mode" // for received thermostat mode changes via MQTT #define TOPIC_THERMOSTAT_CMD_MODE "thermostat_cmd_mode" // mode changes via MQTT
#define TOPIC_THERMOSTAT_CMD_HC "thermostat_cmd_hc" // for received thermostat hc number changes via MQTT #define TOPIC_THERMOSTAT_CMD_DAYTEMP "thermostat_daytemp" // day temp (RC35 specific)
#define TOPIC_THERMOSTAT_CMD_DAYTEMP "thermostat_daytemp" // for received thermostat day temp (RC35 specific) #define TOPIC_THERMOSTAT_CMD_NIGHTTEMP "thermostat_nighttemp" // night temp (RC35 specific)
#define TOPIC_THERMOSTAT_CMD_NIGHTTEMP "thermostat_nighttemp" // for received thermostat night temp (RC35 specific) #define TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP "thermostat_holidayttemp" // holiday temp (RC35 specific)
#define TOPIC_THERMOSTAT_CMD_HOLIDAYTEMP "thermostat_holidayttemp" // for received thermostat holiday temp (RC35 specific)
#define THERMOSTAT_CURRTEMP "thermostat_currtemp" // current temperature #define THERMOSTAT_CURRTEMP "thermostat_currtemp" // current temperature
#define THERMOSTAT_SELTEMP "thermostat_seltemp" // selected temperature #define THERMOSTAT_SELTEMP "thermostat_seltemp" // selected temperature
#define THERMOSTAT_HC "thermostat_hc" // which heating circuit number #define THERMOSTAT_HC "thermostat_hc" // which heating circuit number
@@ -32,10 +35,10 @@
#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_WWACTIVATED "boiler_cmd_wwactivated" // for received message to change water on/off #define TOPIC_BOILER_CMD_WWACTIVATED "boiler_cmd_wwactivated" // change water on/off
#define TOPIC_BOILER_CMD_WWTEMP "boiler_cmd_wwtemp" // for received boiler wwtemp changes via MQTT #define TOPIC_BOILER_CMD_WWTEMP "boiler_cmd_wwtemp" // wwtemp changes via MQTT
#define TOPIC_BOILER_CMD_COMFORT "boiler_cmd_comfort" // for received boiler ww comfort setting via MQTT #define TOPIC_BOILER_CMD_COMFORT "boiler_cmd_comfort" // ww comfort setting via MQTT
#define TOPIC_BOILER_CMD_FLOWTEMP "boiler_cmd_flowtemp" // for received boiler flowtemp value via MQTT #define TOPIC_BOILER_CMD_FLOWTEMP "boiler_cmd_flowtemp" // flowtemp value via MQTT
// MQTT for SM10/SM100 Solar Module // MQTT for SM10/SM100 Solar Module
#define TOPIC_SM_DATA "sm_data" // topic name #define TOPIC_SM_DATA "sm_data" // topic name

View File

@@ -1 +1 @@
#define APP_VERSION "1.9.0" #define APP_VERSION "1.9.1"

View File

@@ -11,19 +11,17 @@
<meta name="description" content=""> <meta name="description" content="">
<meta name="author" content=""> <meta name="author" content="">
<title id="customname"></title> <title id="customname"></title>
<!-- Bootstrap core CSS -->
<link href="css/required.css" rel="stylesheet"> <link href="css/required.css" rel="stylesheet">
</head> </head>
<body> <body>
<div class="wrapper"> <div class="wrapper">
<!-- Sidebar Holder -->
<nav id="sidebar"> <nav id="sidebar">
<div id="dismiss"> <div id="dismiss">
<i class="glyphicon glyphicon-arrow-left"></i> <i class="glyphicon glyphicon-arrow-left"></i>
</div> </div>
<div class="sidebar-header"> <div class="sidebar-header">
<h1 id="customname2" class="text-center"></h1> <h1 id="customname2" class="text-center" onclick="home();"></h1>
<h6 id="mainver" class="text-center"></h6> <h6 id="mainver" class="text-center"></h6>
</div> </div>
<ul class="list-unstyled components"> <ul class="list-unstyled components">
@@ -72,7 +70,7 @@
</ul> </ul>
<ul class="list-unstyled CTAs"> <ul class="list-unstyled CTAs">
<li> <li>
<a id="helpurl" target="_blank" class="download">Help</a> <a id="helpurl" target="_blank" class="article">Help</a>
</li> </li>
<li> <li>
<a href="#" class="article" onclick="logout();">Logout</a> <a href="#" class="article" onclick="logout();">Logout</a>
@@ -96,7 +94,6 @@
</nav> </nav>
<!-- Page Content Holder -->
<div id="content"> <div id="content">
<button type="button" id="sidebarCollapse" class="btn btn-info navbar-btn"> <button type="button" id="sidebarCollapse" class="btn btn-info navbar-btn">
<i class="glyphicon glyphicon-menu-hamburger"></i> <i class="glyphicon glyphicon-menu-hamburger"></i>
@@ -105,51 +102,8 @@
<div id="ajaxcontent"> <div id="ajaxcontent">
</div> </div>
<div id="revcommit" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Please review your system changes</h4>
</div>
<div class="modal-body">
<pre id="jsonholder"></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" onclick="commit();" class="btn btn-success" data-dismiss="modal">Save
& Restart</button>
</div>
</div>
</div>
</div>
<div id="custom_revcommit" class="modal fade" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Please review your custom changes</h4>
</div>
<div class="modal-body">
<pre id="jsonholder2"></pre>
Note: some settings my require a <b>Restart System</b> first to take effect.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" onclick="custom_commit();" class="btn btn-success"
data-dismiss="modal">Save
</button>
</div>
</div>
</div>
</div>
<div id="destroy" class="modal fade" role="dialog"> <div id="destroy" class="modal fade" role="dialog">
<div class="modal-dialog"> <div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button> <button type="button" class="close" data-dismiss="modal">&times;</button>
@@ -181,7 +135,6 @@
<div id="reboot" class="modal fade" role="dialog"> <div id="reboot" class="modal fade" role="dialog">
<div class="modal-dialog"> <div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button> <button type="button" class="close" data-dismiss="modal">&times;</button>
@@ -198,13 +151,12 @@
</div> </div>
</div> </div>
<div id="signin" class="modal fade" role="dialog"> <div id="signin" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button> <h4 class="modal-title">Please enter password to login to the system</h4>
<h4 class="modal-title">Please log in</h4>
</div> </div>
<div class="row"> <div class="row">
<br> <br>
@@ -216,7 +168,7 @@
<div class="form-group"> <div class="form-group">
<input id="password" class="form-control" placeholder="Password" <input id="password" class="form-control" placeholder="Password"
name="password" type="password" value="" required="" name="password" type="password" value="" required=""
title="Please enter your password"> title="Please enter the password">
</div> </div>
<button type="submit" <button type="submit"
class="btn btn-success btn-md pull-right">Login</button> class="btn btn-success btn-md pull-right">Login</button>
@@ -232,7 +184,6 @@
<div id="update" class="modal fade" role="dialog"> <div id="update" class="modal fade" role="dialog">
<div class="modal-dialog"> <div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button> <button type="button" class="close" data-dismiss="modal">&times;</button>

View File

@@ -22,26 +22,6 @@
style="display:none;"> style="display:none;">
</div> </div>
<br> <br>
<div id="restoremodal" class="modal fade" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Please wait while data is restoring...</h4>
</div>
<div class="modal-body">
<div id="pbar" class="progress">
<div id="dynamic" class="progress-bar progress-bar-primary progress-bar-striped active">
Restoring...</div>
</div>
</div>
<div class="modal-footer">
<button type="button" id="restoreclose" style="display:none;" class="btn btn-default"
data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
<br> <br>
@@ -57,7 +37,7 @@
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<h3 class="panel-title">Please wait a few seconds while the system restarts...</h3> <h3 class="panel-title">Please wait for about 10 seconds while the system restarts...</h3>
</div> </div>
<div class="panel-body"> <div class="panel-body">
<div class="progress"> <div class="progress">
@@ -73,6 +53,30 @@
</div> </div>
</div> </div>
<div id="progressupload">
<br>
<br>
<div class="container">
<div class="row">
<br>
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Please wait for about a minute while the firmware uploads...</h3>
</div>
<div class="panel-body">
<div class="progress">
<div id="updateprog" class="progress-bar progress-bar-striped active" role="progressbar"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%">0%
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="generalcontent"> <div id="generalcontent">
<br> <br>
<legend>General Settings</legend> <legend>General Settings</legend>
@@ -110,6 +114,21 @@
</form> </form>
</div> </div>
<br> <br>
</div>
<div class="row form-group">
<label class="col-xs-3">Event Logging<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
data-content="Enabling logging of all events to the device's storage"></i></label>
<div class="col-xs-9">
<form>
<label class="radio-inline">
<input type="radio" value="1" name="logeventsenabled">Enabled</label>
<label class="radio-inline">
<input type="radio" value="0" name="logeventsenabled" checked>Disabled</label>
</form>
</div>
<br>
<br> <br>
<div class="col-xs-9 col-md-8"> <div class="col-xs-9 col-md-8">
<button onclick="savegeneral()" class="btn btn-primary btn-sm pull-right">Save</button> <button onclick="savegeneral()" class="btn btn-primary btn-sm pull-right">Save</button>
@@ -125,13 +144,15 @@
<div id="eventcontent"> <div id="eventcontent">
<div class="text-center" id="loading-img"> <div class="text-center" id="loading-img">
<h5>Please wait while processing the log data...<span id="loadpages"></span></h5> <h5>Loading Logs. Please wait...<span id="loadpages"></span></h5>
<br> <br>
</div> </div>
<div> <div>
<br> <br>
<legend>Event Log</legend> <legend>Event Log</legend>
<h6 class="text-muted">Dates shown in () represent elapsed time in seconds when NTP Time is disabled</h6> <h6 class="text-muted">Dates shown in () represent elapsed time in seconds when NTP Time is disabled</h6>
<div id="logevents" class="label label-danger">Event Logging has been disabled. See Settings->General Settings.
</div>
<br> <br>
<div class="panel panel-default"> <div class="panel panel-default">
<div> <div>
@@ -236,7 +257,8 @@
<div id="networkcontent"> <div id="networkcontent">
<br> <br>
<legend>Wireless Settings</legend> <legend>Wireless Settings</legend>
<h6 class="text-muted">Enter the wireless network settings here, or use Scan to find nearby networks to join</h6> <h6 class="text-muted">Enter the wireless network settings here, or use Scan to find nearby networks to join
</h6>
<br> <br>
<div class="row form-group"> <div class="row form-group">
<label class="col-xs-3">Mode<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign" <label class="col-xs-3">Mode<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
@@ -245,7 +267,8 @@
<div class="col-xs-9"> <div class="col-xs-9">
<form> <form>
<label class="radio-inline"> <label class="radio-inline">
<input type="radio" value="1" name="wmode" id="wmodeap" onclick="handleAP();" checked>Access Point <input type="radio" value="1" name="wmode" id="wmodeap" onclick="handleAP();" checked>Access
Point
</label> </label>
<label class="radio-inline"> <label class="radio-inline">
<input type="radio" value="0" name="wmode" id="wmodesta" onclick="handleSTA();">Client</label> <input type="radio" value="0" name="wmode" id="wmodesta" onclick="handleSTA();">Client</label>
@@ -282,7 +305,8 @@
<div id="ntpcontent"> <div id="ntpcontent">
<br> <br>
<legend>Time Settings</legend> <legend>Time Settings</legend>
<h6 class="text-muted">With Network Time Protocol (NTP) enabled, all times are adjusted to the local timezone and <h6 class="text-muted">With Network Time Protocol (NTP) enabled, all times are adjusted to the local timezone
and
respect daylight saving respect daylight saving
time (DST)</h6> time (DST)</h6>
<br> <br>

View File

@@ -6,6 +6,8 @@ var utcSeconds;
var data = []; var data = [];
var ajaxobj; var ajaxobj;
var custom_config = {};
var config = { var config = {
"command": "configfile", "command": "configfile",
"network": { "network": {
@@ -16,7 +18,8 @@ var config = {
"general": { "general": {
"hostname": "", "hostname": "",
"serial": false, "serial": false,
"password": "admin" "password": "admin",
"log_events": true
}, },
"mqtt": { "mqtt": {
"enabled": false, "enabled": false,
@@ -68,6 +71,14 @@ function syncBrowserTime() {
$("#ntp").click(); $("#ntp").click();
} }
function handleNTPON() {
document.getElementById("forcentp").style.display = "block";
}
function handleNTPOFF() {
document.getElementById("forcentp").style.display = "none";
}
function listntp() { function listntp() {
websock.send("{\"command\":\"gettime\"}"); websock.send("{\"command\":\"gettime\"}");
@@ -85,25 +96,30 @@ function listntp() {
deviceTime(); deviceTime();
} }
function revcommit() { function home() {
document.getElementById("jsonholder").innerText = JSON.stringify(config, null, 2); window.location = '/';
$("#revcommit").modal("show");
} }
function uncommited() { function restart_alert() {
$("#commit").fadeOut(200, function () { $("#commit").fadeOut(200, function () {
$(this).css("background", "gold").fadeIn(1000); $(this).css("background", "gold").fadeIn(1000);
}); });
document.getElementById("commit").innerHTML = "<h6>Settings have changed. Click here to review and save.</h6>"; document.getElementById("commit").innerHTML = "<h6>Settings have changed. It's recommended to reboot the system. Click here to restart.</h6>";
$("#commit").click(function () { $("#commit").click(function () {
revcommit(); $("#reboot").modal("show");
return false; return false;
}); });
} }
function custom_uncommited() { function saveconfig() {
document.getElementById("jsonholder2").innerText = JSON.stringify(custom_config.settings, null, 2); websock.send(JSON.stringify(config));
$("#custom_revcommit").modal("show"); restart_alert();
}
function custom_saveconfig() {
websock.send(JSON.stringify(custom_config));
restart_alert();
} }
function saventp() { function saventp() {
@@ -115,14 +131,13 @@ function saventp() {
config.ntp.enabled = true; config.ntp.enabled = true;
} }
uncommited(); saveconfig();
} }
function forcentp() { function forcentp() {
websock.send("{\"command\":\"forcentp\"}"); websock.send("{\"command\":\"forcentp\"}");
} }
function savegeneral() { function savegeneral() {
var a = document.getElementById("adminpwd").value; var a = document.getElementById("adminpwd").value;
if (a === null || a === "") { if (a === null || a === "") {
@@ -137,7 +152,12 @@ function savegeneral() {
config.general.serial = true; config.general.serial = true;
} }
uncommited(); config.general.log_events = false;
if (parseInt($("input[name=\"logeventsenabled\"]:checked").val()) === 1) {
config.general.log_events = true;
}
saveconfig();
} }
function savemqtt() { function savemqtt() {
@@ -157,7 +177,7 @@ function savemqtt() {
config.mqtt.user = document.getElementById("mqttuser").value; config.mqtt.user = document.getElementById("mqttuser").value;
config.mqtt.password = document.getElementById("mqttpwd").value; config.mqtt.password = document.getElementById("mqttpwd").value;
uncommited(); saveconfig();
} }
function savenetwork() { function savenetwork() {
@@ -176,7 +196,7 @@ function savenetwork() {
config.network.wmode = wmode; config.network.wmode = wmode;
config.network.password = document.getElementById("wifipass").value; config.network.password = document.getElementById("wifipass").value;
uncommited(); saveconfig();
} }
var formData = new FormData(); var formData = new FormData();
@@ -189,8 +209,8 @@ function inProgress(callback) {
var i = 0; var i = 0;
var prg = setInterval(function () { var prg = setInterval(function () {
$(".progress-bar").css("width", i + "%").attr("aria-valuenow", i).html(i + "%"); $(".progress-bar").css("width", i + "%").attr("aria-valuenow", i).html(i + "%");
i++; i = i + 5;
if (i === 101) { if (i === 105) {
clearInterval(prg); clearInterval(prg);
var a = document.createElement("a"); var a = document.createElement("a");
a.href = "http://" + config.general.hostname + ".local"; a.href = "http://" + config.general.hostname + ".local";
@@ -211,9 +231,6 @@ function inProgress(callback) {
contentType: false contentType: false
}); });
break; break;
case "commit":
websock.send(JSON.stringify(config));
break;
case "destroy": case "destroy":
websock.send("{\"command\":\"destroy\"}"); websock.send("{\"command\":\"destroy\"}");
break; break;
@@ -228,8 +245,30 @@ function inProgress(callback) {
}).hide().fadeIn(); }).hide().fadeIn();
} }
function commit() { function inProgressUpload() {
inProgress("commit"); $("body").load("myesp.html #progressupload", function (responseTxt, statusTxt, xhr) {
if (statusTxt === "success") {
$(".progress").css("height", "40");
$(".progress").css("font-size", "xx-large");
var i = 0;
var prg = setInterval(function () {
$(".progress-bar").css("width", i + "%").attr("aria-valuenow", i).html(i + "%");
i = i + 1;
if (i === 101) {
clearInterval(prg);
document.getElementById("updateprog").className = "progress-bar progress-bar-success";
document.getElementById("updateprog").innerHTML = "Completed";
}
}, 500);
$.ajax({
url: "/update",
type: "POST",
data: formData,
processData: false,
contentType: false
});
}
}).hide().fadeIn();
} }
function handleSTA() { function handleSTA() {
@@ -247,14 +286,6 @@ function handleAP() {
document.getElementById("inputtohide").style.display = "block"; document.getElementById("inputtohide").style.display = "block";
} }
function handleNTPON() {
document.getElementById("forcentp").style.display = "block";
}
function handleNTPOFF() {
document.getElementById("forcentp").style.display = "none";
}
function listnetwork() { function listnetwork() {
document.getElementById("inputtohide").value = config.network.ssid; document.getElementById("inputtohide").value = config.network.ssid;
document.getElementById("wifipass").value = config.network.password; document.getElementById("wifipass").value = config.network.password;
@@ -275,6 +306,10 @@ function listgeneral() {
if (config.general.serial) { if (config.general.serial) {
$("input[name=\"serialenabled\"][value=\"1\"]").prop("checked", true); $("input[name=\"serialenabled\"][value=\"1\"]").prop("checked", true);
} }
if (config.general.log_events) {
$("input[name=\"logeventsenabled\"][value=\"1\"]").prop("checked", true);
}
} }
function listmqtt() { function listmqtt() {
@@ -424,7 +459,15 @@ function getContent(contentname) {
page = 1; page = 1;
data = []; data = [];
getEvents(); getEvents();
if (config.general.log_events) {
document.getElementById("logevents").style.display = "none";
} else {
document.getElementById("logevents").style.display = "block";
}
break; break;
case "#customcontent": case "#customcontent":
listcustom(); listcustom();
break; break;
@@ -435,16 +478,18 @@ function getContent(contentname) {
var customname2 = " " + ajaxobj.customname; var customname2 = " " + ajaxobj.customname;
$("#customname2").text(customname2); $("#customname2").text(customname2);
var elem;
if (config.network.wmode === 0) { if (config.network.wmode === 0) {
var elem = document.getElementById("helpurl"); elem = document.getElementById("helpurl");
var helpurl = ajaxobj.appurl + "/wiki" var helpurl = ajaxobj.appurl + "/wiki";
elem.setAttribute("href", helpurl); elem.setAttribute("href", helpurl);
document.getElementById("helpurl").style.display = "block"; document.getElementById("helpurl").style.display = "block";
} else { } else {
document.getElementById("helpurl").style.display = "none"; document.getElementById("helpurl").style.display = "none";
} }
var elem = document.getElementById("appurl"); elem = document.getElementById("appurl");
elem.setAttribute("href", ajaxobj.appurl); elem.setAttribute("href", ajaxobj.appurl);
$("#appurl2").text(ajaxobj.appurl); $("#appurl2").text(ajaxobj.appurl);
@@ -494,10 +539,10 @@ function restoreSet() {
return; return;
} }
if (json.command === "configfile") { if (json.command === "configfile") {
var x = confirm("File seems to be valid, do you wish to continue?"); var x = confirm("System Config file seems to be valid, do you wish to continue?");
if (x) { if (x) {
config = json; config = json;
uncommited(); saveconfig();
} }
} }
}; };
@@ -522,10 +567,10 @@ function restoreCustomSet() {
return; return;
} }
if (json.command === "custom_configfile") { if (json.command === "custom_configfile") {
var x = confirm("File seems to be valid, do you wish to continue?"); var x = confirm("Custom Config file seems to be valid, do you wish to continue?");
if (x) { if (x) {
custom_config = json; custom_config = json;
custom_uncommited(); custom_saveconfig();
} }
} }
}; };
@@ -544,12 +589,17 @@ function twoDigits(value) {
function initEventTable() { function initEventTable() {
var newlist = []; var newlist = [];
for (var i = 0; i < data.length; i++) { for (var i = 0; i < data.length; i++) {
var dup = JSON.parse(data[i]);
dup.uid = i;
newlist[i] = {}; newlist[i] = {};
newlist[i].options = {}; newlist[i].options = {};
newlist[i].value = {}; newlist[i].value = {};
try {
var dup = JSON.parse(data[i]);
dup.uid = i + 1;
} catch (e) {
var dup = { "uid": i + 1, "type": "ERRO", "src": "SYS", "desc": "Error in log file", "data": data[i], "time": 1 }
}
newlist[i].value = dup; newlist[i].value = dup;
var c = dup.type; var c = dup.type;
switch (c) { switch (c) {
case "WARN": case "WARN":
@@ -564,7 +614,6 @@ function initEventTable() {
default: default:
break; break;
} }
} }
jQuery(function ($) { jQuery(function ($) {
window.FooTable.init("#eventtable", { window.FooTable.init("#eventtable", {
@@ -669,10 +718,6 @@ function initMQTTLogTable() {
}); });
} }
function restartESP() {
inProgress("restart");
}
var nextIsNotJson = false; var nextIsNotJson = false;
function socketMessageListener(evt) { function socketMessageListener(evt) {
@@ -790,62 +835,6 @@ $(".noimp").on("click", function () {
$("#noimp").modal("show"); $("#noimp").modal("show");
}); });
window.FooTable.MyFiltering = window.FooTable.Filtering.extend({
construct: function (instance) {
this._super(instance);
this.acctypes = ["1", "99", "0"];
this.acctypesstr = ["Always", "Admin", "Disabled"];
this.def = "Access Type";
this.$acctype = null;
},
$create: function () {
this._super();
var self = this,
$formgrp = $("<div/>", {
"class": "form-group"
})
.append($("<label/>", {
"class": "sr-only",
text: "Status"
}))
.prependTo(self.$form);
self.$acctype = $("<select/>", {
"class": "form-control"
})
.on("change", {
self: self
}, self._onStatusDropdownChanged)
.append($("<option/>", {
text: self.def
}))
.appendTo($formgrp);
$.each(self.acctypes, function (i, acctype) {
self.$acctype.append($("<option/>").text(self.acctypesstr[i]).val(self.acctypes[i]));
});
},
_onStatusDropdownChanged: function (e) {
var self = e.data.self,
selected = $(this).val();
if (selected !== self.def) {
self.addFilter("acctype", selected, ["acctype"]);
} else {
self.removeFilter("acctype");
}
self.filter();
},
draw: function () {
this._super();
var acctype = this.find("acctype");
if (acctype instanceof window.FooTable.Filter) {
this.$acctype.val(acctype.query.val());
} else {
this.$acctype.val(this.def);
}
}
});
var xDown = null; var xDown = null;
var yDown = null; var yDown = null;
@@ -921,7 +910,7 @@ function connectWS() {
function upload() { function upload() {
formData.append("bin", $("#binform")[0].files[0]); formData.append("bin", $("#binform")[0].files[0]);
inProgress("upload"); inProgressUpload();
} }
function login() { function login() {

View File

@@ -1,4 +1,4 @@
'use strict'; "use strict";
module.exports = function () { module.exports = function () {
return { return {

View File

@@ -52,17 +52,10 @@ var eventlog = {
"page": 1, "page": 1,
"haspages": 1, "haspages": 1,
"list": [ "list": [
"{ \"type\": \"WARN\", \"src\": \"sys\", \"desc\": \"Event log cleared!\", \"data\": \"\", \"time\": 1563371160 }", "{\"type\":\"WARN\",\"src\":\"system\",\"desc\":\"test data\",\"data\":\"Record #1\",\"time\": 1563371160}",
"{ \"type\": \"WARN\", \"src\": \"sys\", \"desc\": \"Event log cleared!\", \"data\": \"\", \"time\": 1563371160 }", "{\"type\":\"WARN\",\"src\":\"system\",\"desc\":\"test data\",\"data\":\"Record #2\",\"time\":0}",
"{ \"type\": \"INFO\", \"src\": \"wifi\", \"desc\": \"WiFi is connected\", \"data\": \"SMC\", \"time\": 13 }", "{\"type\":\"INFO\",\"src\":\"system\",\"desc\":\"System booted\",\"data\":\"\",\"time\":1568660479}",
"{ \"type\": \"INFO\", \"src\": \"sys\", \"desc\": \"System setup completed, running\", \"data\": \"\", \"time\": 13 }", "{\"type\":\"WARN\",\"src\":\"system\",\"desc\":\"test data\",\"data\":\"Record #3\",\"time\":0}"
"{ \"type\": \"INFO\", \"src\": \"wifi\", \"desc\": \"WiFi is connected\", \"data\": \"SMC\", \"time\": 13 }",
"{ \"type\": \"INFO\", \"src\": \"sys\", \"desc\": \"System setup completed, running\", \"data\": \"\", \"time\": 13 }",
"{ \"type\": \"WARN\", \"src\": \"websrv\", \"desc\": \"New login attempt\", \"data\": \"\", \"time\": 1563371160 }",
"{ \"type\": \"INFO\", \"src\": \"websrv\", \"desc\": \"Login success!\", \"data\": \"\", \"time\": 1563371160 }",
"{ \"type\": \"INFO\", \"src\": \"wifi\", \"desc\": \"WiFi is connected\", \"data\": \"SMC\", \"time\": 13 }",
"{ \"type\": \"INFO\", \"src\": \"sys\", \"desc\": \"System setup completed, running\", \"data\": \"\", \"time\": 13 }",
"{ \"type\": \"WARN\", \"src\": \"websrv\", \"desc\": \"New login attempt\", \"data\": \"\", \"time\": 1563371160 }"
] ]
} }
@@ -76,7 +69,8 @@ var configfile = {
"general": { "general": {
"hostname": "myesp", "hostname": "myesp",
"password": "admin", "password": "admin",
"serial": true "serial": true,
"log_events": true
}, },
"mqtt": { "mqtt": {
"enabled": false, "enabled": false,
@@ -105,7 +99,6 @@ var custom_configfile = {
"shower_timer": true, "shower_timer": true,
"shower_alert": false, "shower_alert": false,
"publish_time": 120, "publish_time": 120,
"heating_circuit": 1,
"tx_mode": 1 "tx_mode": 1
} }
}; };
@@ -155,7 +148,7 @@ function sendStatus() {
function sendCustomStatus() { function sendCustomStatus() {
var stats = { var stats = {
"command": "custom_status", "command": "custom_status",
"version": "1.9.0", "version": "1.9.1",
"customname": "EMS-ESP", "customname": "EMS-ESP",
"appurl": "https://github.com/proddy/EMS-ESP", "appurl": "https://github.com/proddy/EMS-ESP",
"updateurl": "https://api.github.com/repos/proddy/EMS-ESP/releases/latest", "updateurl": "https://api.github.com/repos/proddy/EMS-ESP/releases/latest",
@@ -222,7 +215,7 @@ wss.on('connection', function connection(ws) {
console.log("[INFO] Got Command: " + obj.command); console.log("[INFO] Got Command: " + obj.command);
switch (obj.command) { switch (obj.command) {
case "configfile": case "configfile":
console.log("[INFO] New system settings file received"); console.log("[INFO] New system config received");
configfile = obj; configfile = obj;
break; break;
case "custom_configfile": case "custom_configfile":