mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 00:39:50 +03:00
merged with dev 1.8.1
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,7 +3,9 @@
|
|||||||
.gcc-flags.json
|
.gcc-flags.json
|
||||||
.vscode
|
.vscode
|
||||||
.env
|
.env
|
||||||
|
.DS_Store
|
||||||
platformio.ini
|
platformio.ini
|
||||||
lib/readme.txt
|
lib/readme.txt
|
||||||
.travis.yml
|
.travis.yml
|
||||||
scripts/stackdmp.txt
|
scripts/stackdmp.txt
|
||||||
|
*.bin
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -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.8.1dev] 2019-07-27
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added back -DCRASH in Debug build target for capturing any ESP8266 stack dumps during crashes
|
||||||
|
- Web Interface, for checking stats and setting wifi credentials. See wiki for more details.
|
||||||
|
- reset firmware option. If the reset button on the ESP is pressed during boot up sequence (the LED is flashing very fast) all settings are erased and goes into AP mode.
|
||||||
|
- Added tx_mode back with options 0,1 and 2 until we've fixed option 2 that works for everyone and doesn't reset ESP
|
||||||
|
- More solar module data captured, thanks to @Vuego123
|
||||||
|
- Detect thermostat mode for EMS+ RC300/Moduline 3000
|
||||||
|
- MQTT message to set boiler flowtemp (`boiler_cmd_flowtemp`). See [wiki](https://github.com/proddy/EMS-ESP/wiki/MQTT).
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Detecting unset values in the SPIFFS and setting default values
|
||||||
|
- Bosch Easy Connect wrongly classified as a thermostat
|
||||||
|
- Correctly handle telegrams who's size are exactly 32 bytes (e.g. 0x19 MonitorSlow)
|
||||||
|
- Telnet also available when in AP mode
|
||||||
|
- Handling of thermostat temperatures that were single bytes and couldn't exceed 25.5 (0xFF) degrees!
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improved handling of Solar Modules (thanks @Vuego123)
|
||||||
|
- `publish_wait` renamed to `publish_time`, a value of 0 means disabling all MQTT sending
|
||||||
|
- How signed shorts are handled such as the current and setpoint temps on RC300s
|
||||||
|
- Stopped automatic refresh of web page, which causes crashes/memory loss after a short time
|
||||||
|
- Support HA 0.96 climate component changes
|
||||||
|
- -DDEFAULT_NO_SERIAL changed to -DFORCE_SERIAL
|
||||||
|
- some code cleanups, removing NULLS and moving some things fron heap to stack to prevent memory fragmentation
|
||||||
|
|
||||||
## [1.8.0] 2019-06-15
|
## [1.8.0] 2019-06-15
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
- platform: mqtt
|
- platform: mqtt
|
||||||
name: boiler
|
name: boiler
|
||||||
modes:
|
modes:
|
||||||
- "on"
|
- "auto"
|
||||||
- "off"
|
- "off"
|
||||||
min_temp: 40
|
min_temp: 40
|
||||||
max_temp: 60
|
max_temp: 60
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
temperature_command_topic: "home/ems-esp/boiler_cmd_wwtemp"
|
temperature_command_topic: "home/ems-esp/boiler_cmd_wwtemp"
|
||||||
current_temperature_template: "{{ value_json.wWCurTmp }}"
|
current_temperature_template: "{{ value_json.wWCurTmp }}"
|
||||||
temperature_state_template: "{{ value_json.wWSelTemp }}"
|
temperature_state_template: "{{ value_json.wWSelTemp }}"
|
||||||
mode_state_template: "{{ value_json.wWActivated }}"
|
mode_state_template: "{% if value_json.wWActivated == 'off' %} off {% else %} auto {% endif %}"
|
||||||
mode_state_topic: "home/ems-esp/boiler_data"
|
mode_state_topic: "home/ems-esp/boiler_data"
|
||||||
mode_command_topic: "home/ems-esp/wwactivated"
|
mode_command_topic: "home/ems-esp/wwactivated"
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -6,23 +6,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef MyEMS_h
|
#ifndef MyESP_h
|
||||||
#define MyEMS_h
|
#define MyESP_h
|
||||||
|
|
||||||
#define MYESP_VERSION "1.1.16"
|
#define MYESP_VERSION "1.1.24"
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ArduinoOTA.h>
|
#include <ArduinoOTA.h>
|
||||||
#include <AsyncMqttClient.h> // https://github.com/marvinroger/async-mqtt-client and for ESP32 see https://github.com/marvinroger/async-mqtt-client/issues/127
|
#include <AsyncMqttClient.h> // https://github.com/marvinroger/async-mqtt-client and for ESP32 see https://github.com/marvinroger/async-mqtt-client/issues/127
|
||||||
#include <DNSServer.h>
|
#include <ESP8266WebServer.h>
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include <JustWifi.h> // https://github.com/xoseperez/justwifi
|
#include <JustWifi.h> // https://github.com/xoseperez/justwifi
|
||||||
#include <TelnetSpy.h> // modified from https://github.com/yasheena/telnetspy
|
#include <TelnetSpy.h> // modified from https://github.com/yasheena/telnetspy
|
||||||
|
|
||||||
|
#ifdef CRASH
|
||||||
#include <EEPROM_Rotate.h>
|
#include <EEPROM_Rotate.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "user_interface.h"
|
|
||||||
void custom_crash_callback(struct rst_info *, uint32_t, uint32_t);
|
void custom_crash_callback(struct rst_info *, uint32_t, uint32_t);
|
||||||
|
#include "user_interface.h"
|
||||||
extern struct rst_info resetInfo;
|
extern struct rst_info resetInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,10 +41,10 @@ extern struct rst_info resetInfo;
|
|||||||
|
|
||||||
#define MYEMS_CONFIG_FILE "/config.json"
|
#define MYEMS_CONFIG_FILE "/config.json"
|
||||||
|
|
||||||
#define LOADAVG_INTERVAL 30000 // Interval between calculating load average (in ms)
|
#define LOADAVG_INTERVAL 30000 // Interval between calculating load average (in ms) = 30 seconds
|
||||||
|
|
||||||
// WIFI
|
// WIFI
|
||||||
#define WIFI_CONNECT_TIMEOUT 10000 // Connecting timeout for WIFI in ms
|
#define WIFI_CONNECT_TIMEOUT 10000 // Connecting timeout for WIFI in ms (10 seconds)
|
||||||
#define WIFI_RECONNECT_INTERVAL 600000 // If could not connect to WIFI, retry after this time in ms. 10 minutes
|
#define WIFI_RECONNECT_INTERVAL 600000 // If could not connect to WIFI, retry after this time in ms. 10 minutes
|
||||||
|
|
||||||
// MQTT
|
// MQTT
|
||||||
@@ -65,6 +68,8 @@ extern struct rst_info resetInfo;
|
|||||||
#define TELNET_MAX_COMMAND_LENGTH 80 // length of a command
|
#define TELNET_MAX_COMMAND_LENGTH 80 // length of a command
|
||||||
#define TELNET_EVENT_CONNECT 1
|
#define TELNET_EVENT_CONNECT 1
|
||||||
#define TELNET_EVENT_DISCONNECT 0
|
#define TELNET_EVENT_DISCONNECT 0
|
||||||
|
#define TELNET_EVENT_SHOWCMD 10
|
||||||
|
#define TELNET_EVENT_SHOWSET 20
|
||||||
|
|
||||||
// ANSI Colors
|
// ANSI Colors
|
||||||
#define COLOR_RESET "\x1B[0m"
|
#define COLOR_RESET "\x1B[0m"
|
||||||
@@ -143,12 +148,11 @@ PROGMEM const char * const custom_reset_string[] = {custom_reset_hardware, cus
|
|||||||
#define RTCMEM_OFFSET 32u
|
#define RTCMEM_OFFSET 32u
|
||||||
#define RTCMEM_ADDR (RTCMEM_ADDR_BASE + (RTCMEM_OFFSET * 4u))
|
#define RTCMEM_ADDR (RTCMEM_ADDR_BASE + (RTCMEM_OFFSET * 4u))
|
||||||
#define RTCMEM_BLOCKS 96u
|
#define RTCMEM_BLOCKS 96u
|
||||||
#define RTCMEM_MAGIC 0x45535075
|
#define RTCMEM_MAGIC 0x45535076
|
||||||
|
|
||||||
struct RtcmemData {
|
struct RtcmemData {
|
||||||
uint32_t magic; // RTCMEM_MAGIC
|
uint32_t magic; // RTCMEM_MAGIC
|
||||||
uint32_t sys; // system reset reason (1-4)
|
uint32_t sys; // system details
|
||||||
uint32_t energy; // store energy count
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
|
static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
|
||||||
@@ -165,6 +169,13 @@ typedef struct {
|
|||||||
|
|
||||||
typedef enum { MYESP_FSACTION_SET, MYESP_FSACTION_LIST, MYESP_FSACTION_SAVE, MYESP_FSACTION_LOAD } MYESP_FSACTION;
|
typedef enum { MYESP_FSACTION_SET, MYESP_FSACTION_LIST, MYESP_FSACTION_SAVE, MYESP_FSACTION_LOAD } MYESP_FSACTION;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MYESP_BOOTSTATUS_POWERON = 0,
|
||||||
|
MYESP_BOOTSTATUS_BOOTED = 1,
|
||||||
|
MYESP_BOOTSTATUS_BOOTING = 2,
|
||||||
|
MYESP_BOOTSTATUS_RESETNEEDED = 3
|
||||||
|
} MYESP_BOOTSTATUS; // boot messages
|
||||||
|
|
||||||
typedef std::function<void(unsigned int, const char *, const char *)> mqtt_callback_f;
|
typedef std::function<void(unsigned int, const char *, const char *)> mqtt_callback_f;
|
||||||
typedef std::function<void()> wifi_callback_f;
|
typedef std::function<void()> wifi_callback_f;
|
||||||
typedef std::function<void()> ota_callback_f;
|
typedef std::function<void()> ota_callback_f;
|
||||||
@@ -172,6 +183,7 @@ typedef std::function<void(uint8_t, const char *)>
|
|||||||
typedef std::function<void(uint8_t)> telnet_callback_f;
|
typedef std::function<void(uint8_t)> telnet_callback_f;
|
||||||
typedef std::function<bool(MYESP_FSACTION, const JsonObject json)> fs_callback_f;
|
typedef std::function<bool(MYESP_FSACTION, const JsonObject json)> fs_callback_f;
|
||||||
typedef std::function<bool(MYESP_FSACTION, uint8_t, const char *, const char *)> fs_settings_callback_f;
|
typedef std::function<bool(MYESP_FSACTION, uint8_t, const char *, const char *)> fs_settings_callback_f;
|
||||||
|
typedef std::function<void(char *)> web_callback_f;
|
||||||
|
|
||||||
// calculates size of an 2d array at compile time
|
// calculates size of an 2d array at compile time
|
||||||
template <typename T, size_t N>
|
template <typename T, size_t N>
|
||||||
@@ -179,14 +191,55 @@ constexpr size_t ArraySize(T (&)[N]) {
|
|||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void PROGMEM_readAnything(const T * sce, T & dest) {
|
||||||
|
memcpy_P(&dest, sce, sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
#define UPTIME_OVERFLOW 4294967295 // Uptime overflow value
|
#define UPTIME_OVERFLOW 4294967295 // Uptime overflow value
|
||||||
|
|
||||||
|
// web min and max length of wifi ssid and password
|
||||||
|
#define MAX_SSID_LEN 32
|
||||||
|
#define MAX_PWD_LEN 64
|
||||||
|
|
||||||
|
#define MYESP_BOOTUP_FLASHDELAY 50 // flash duration for LED at bootup sequence
|
||||||
|
#define MYESP_BOOTUP_DELAY 2000 // time before we open the window to reset. This is to stop resetting values when uploading firmware via USB
|
||||||
|
|
||||||
|
// max size of char buffer for storing web page
|
||||||
|
#define MYESP_MAXCHARBUFFER 800
|
||||||
|
|
||||||
|
// Holds the admin webpage in the program memory
|
||||||
|
const char webCommonPage_start[] = "<html>"
|
||||||
|
"<head>"
|
||||||
|
"<style>input {font-size: 1.2em; width: 100%; max-width: 350px; display: block; margin: 5px auto; }"
|
||||||
|
"body {background-color: #FFA500;font: normal 18px Verdana, Arial, sans-serif;} </style>";
|
||||||
|
|
||||||
|
const char webCommonPage_start_body[] = "</head><body>";
|
||||||
|
|
||||||
|
const char webCommonPage_end[] = "</body></html>";
|
||||||
|
|
||||||
|
const char webResetPage_form[] = "<form id='form' action='/reset' method='post'>"
|
||||||
|
"<input name='newssid' type='text' maxlength='32' placeholder='SSID'>"
|
||||||
|
"<input name='newpassword' id='password1' type='password' maxlength='64' placeholder='Password'>"
|
||||||
|
"<input type='submit' value='Save and reboot'>"
|
||||||
|
"</form>";
|
||||||
|
|
||||||
|
const char webResetPage_post[] =
|
||||||
|
"<p>New wifi credentials set. System is now rebooting. Please wait a few seconds and then reconnect via telnet or browser to its new IP given address.</p>";
|
||||||
|
|
||||||
|
const char webResetAllPage_form[] = "<form id='resetform' action='/resetall' method='post'>"
|
||||||
|
"<input name='confirm' type='text' minlength='3' maxlength='16' placeholder='yes'>"
|
||||||
|
"<input type='submit' value='Reset All'>"
|
||||||
|
"</form>";
|
||||||
|
|
||||||
// class definition
|
// class definition
|
||||||
class MyESP {
|
class MyESP {
|
||||||
public:
|
public:
|
||||||
MyESP();
|
MyESP();
|
||||||
~MyESP();
|
~MyESP();
|
||||||
|
|
||||||
|
ESP8266WebServer webServer; // Web server on port 80
|
||||||
|
|
||||||
// wifi
|
// wifi
|
||||||
void setWIFICallback(void (*callback)());
|
void setWIFICallback(void (*callback)());
|
||||||
void setWIFI(const char * wifi_ssid, const char * wifi_password, wifi_callback_f callback);
|
void setWIFI(const char * wifi_ssid, const char * wifi_password, wifi_callback_f callback);
|
||||||
@@ -216,7 +269,7 @@ class MyESP {
|
|||||||
// debug & telnet
|
// debug & telnet
|
||||||
void myDebug(const char * format, ...);
|
void myDebug(const char * format, ...);
|
||||||
void myDebug_P(PGM_P format_P, ...);
|
void myDebug_P(PGM_P format_P, ...);
|
||||||
void setTelnet(command_t * cmds, uint8_t count, telnetcommand_callback_f callback_cmd, telnet_callback_f callback);
|
void setTelnet(telnetcommand_callback_f callback_cmd, telnet_callback_f callback);
|
||||||
bool getUseSerial();
|
bool getUseSerial();
|
||||||
void setUseSerial(bool toggle);
|
void setUseSerial(bool toggle);
|
||||||
|
|
||||||
@@ -224,6 +277,9 @@ class MyESP {
|
|||||||
void setSettings(fs_callback_f callback, fs_settings_callback_f fs_settings_callback);
|
void setSettings(fs_callback_f callback, fs_settings_callback_f fs_settings_callback);
|
||||||
bool fs_saveConfig();
|
bool fs_saveConfig();
|
||||||
|
|
||||||
|
// Web
|
||||||
|
void setWeb(web_callback_f callback_web);
|
||||||
|
|
||||||
// Crash
|
// Crash
|
||||||
void crashClear();
|
void crashClear();
|
||||||
void crashDump();
|
void crashDump();
|
||||||
@@ -239,10 +295,9 @@ class MyESP {
|
|||||||
int getWifiQuality();
|
int getWifiQuality();
|
||||||
void showSystemStats();
|
void showSystemStats();
|
||||||
bool getHeartbeat();
|
bool getHeartbeat();
|
||||||
|
uint32_t getSystemLoadAverage();
|
||||||
// rtcmem and reset reason
|
|
||||||
bool rtcmemStatus();
|
|
||||||
uint32_t getSystemResetReason();
|
uint32_t getSystemResetReason();
|
||||||
|
uint8_t getSystemBootStatus();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// mqtt
|
// mqtt
|
||||||
@@ -271,7 +326,6 @@ class MyESP {
|
|||||||
bool _rtcmem_status;
|
bool _rtcmem_status;
|
||||||
|
|
||||||
// wifi
|
// wifi
|
||||||
DNSServer dnsServer; // For Access Point (AP) support
|
|
||||||
void _wifiCallback(justwifi_messages_t code, char * parameter);
|
void _wifiCallback(justwifi_messages_t code, char * parameter);
|
||||||
void _wifi_setup();
|
void _wifi_setup();
|
||||||
wifi_callback_f _wifi_callback;
|
wifi_callback_f _wifi_callback;
|
||||||
@@ -285,6 +339,7 @@ class MyESP {
|
|||||||
ota_callback_f _ota_post_callback;
|
ota_callback_f _ota_post_callback;
|
||||||
void _ota_setup();
|
void _ota_setup();
|
||||||
void _OTACallback();
|
void _OTACallback();
|
||||||
|
bool _ota_doing_update;
|
||||||
|
|
||||||
// crash
|
// crash
|
||||||
void _eeprom_setup();
|
void _eeprom_setup();
|
||||||
@@ -298,8 +353,6 @@ class MyESP {
|
|||||||
char * _telnet_readWord(bool allow_all_chars);
|
char * _telnet_readWord(bool allow_all_chars);
|
||||||
void _telnet_setup();
|
void _telnet_setup();
|
||||||
char _command[TELNET_MAX_COMMAND_LENGTH]; // the input command from either Serial or Telnet
|
char _command[TELNET_MAX_COMMAND_LENGTH]; // the input command from either Serial or Telnet
|
||||||
command_t * _helpProjectCmds; // Help of commands setted by project
|
|
||||||
uint8_t _helpProjectCmds_count; // # available commands
|
|
||||||
void _consoleShowHelp();
|
void _consoleShowHelp();
|
||||||
telnetcommand_callback_f _telnetcommand_callback; // Callable for projects commands
|
telnetcommand_callback_f _telnetcommand_callback; // Callable for projects commands
|
||||||
telnet_callback_f _telnet_callback; // callback for connect/disconnect
|
telnet_callback_f _telnet_callback; // callback for connect/disconnect
|
||||||
@@ -316,19 +369,25 @@ class MyESP {
|
|||||||
fs_settings_callback_f _fs_settings_callback;
|
fs_settings_callback_f _fs_settings_callback;
|
||||||
void _printSetCommands();
|
void _printSetCommands();
|
||||||
|
|
||||||
|
// web
|
||||||
|
web_callback_f _web_callback;
|
||||||
|
|
||||||
// general
|
// general
|
||||||
char * _app_hostname;
|
char * _app_hostname;
|
||||||
char * _app_name;
|
char * _app_name;
|
||||||
char * _app_version;
|
char * _app_version;
|
||||||
char * _boottime;
|
char * _boottime;
|
||||||
bool _suspendOutput;
|
bool _suspendOutput;
|
||||||
bool _use_serial;
|
bool _serial;
|
||||||
bool _heartbeat;
|
bool _heartbeat;
|
||||||
unsigned long _getUptime();
|
unsigned long _getUptime();
|
||||||
String _buildTime();
|
String _buildTime();
|
||||||
|
bool _firstInstall;
|
||||||
|
|
||||||
// reset reason and rtcmem
|
// reset reason and rtcmem
|
||||||
bool _rtcmemStatus();
|
bool _rtcmemStatus();
|
||||||
|
bool _getRtcmemStatus();
|
||||||
|
|
||||||
void _rtcmemInit();
|
void _rtcmemInit();
|
||||||
void _rtcmemSetup();
|
void _rtcmemSetup();
|
||||||
|
|
||||||
@@ -337,27 +396,33 @@ class MyESP {
|
|||||||
uint8_t _getSystemStabilityCounter();
|
uint8_t _getSystemStabilityCounter();
|
||||||
void _setSystemStabilityCounter(uint8_t counter);
|
void _setSystemStabilityCounter(uint8_t counter);
|
||||||
|
|
||||||
uint8_t _getSystemResetReason();
|
|
||||||
void _setSystemResetReason(uint8_t reason);
|
void _setSystemResetReason(uint8_t reason);
|
||||||
|
uint8_t _getCustomResetReason();
|
||||||
|
void _setCustomResetReason(uint8_t reason);
|
||||||
|
uint8_t _getSystemResetReason();
|
||||||
|
|
||||||
unsigned char _getCustomResetReason();
|
void _setSystemBootStatus(uint8_t status);
|
||||||
void _setCustomResetReason(unsigned char reason);
|
|
||||||
|
|
||||||
bool _systemStable;
|
bool _systemStable;
|
||||||
|
void _bootupSequence();
|
||||||
bool getSystemCheck();
|
bool _getSystemCheck();
|
||||||
void _systemCheckLoop();
|
void _systemCheckLoop();
|
||||||
void _setSystemCheck(bool stable);
|
void _setSystemCheck(bool stable);
|
||||||
|
|
||||||
// load average (0..100) and heap ram
|
// load average (0..100) and heap ram
|
||||||
uint32_t getSystemLoadAverage();
|
|
||||||
void _calculateLoad();
|
void _calculateLoad();
|
||||||
uint32_t _load_average;
|
uint32_t _load_average;
|
||||||
uint32_t getInitialFreeHeap();
|
uint32_t _getInitialFreeHeap();
|
||||||
uint32_t getUsedHeap();
|
uint32_t _getUsedHeap();
|
||||||
|
|
||||||
// heartbeat
|
// heartbeat
|
||||||
void _heartbeatCheck(bool force);
|
void _heartbeatCheck(bool force);
|
||||||
|
|
||||||
|
// webserver
|
||||||
|
void _webserver_setup();
|
||||||
|
void _webRootPage();
|
||||||
|
void _webResetPage();
|
||||||
|
void _webResetAllPage();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MyESP myESP;
|
extern MyESP myESP;
|
||||||
|
|||||||
@@ -573,6 +573,7 @@ void TelnetSpy::handle() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!listening) {
|
if (!listening) {
|
||||||
|
|
||||||
if ((WiFi.status() == WL_DISCONNECTED) && (WiFi.getMode() & WIFI_AP)) {
|
if ((WiFi.status() == WL_DISCONNECTED) && (WiFi.getMode() & WIFI_AP)) {
|
||||||
if (usedSer) {
|
if (usedSer) {
|
||||||
usedSer->println("[TELNET] in AP mode"); // added by Proddy
|
usedSer->println("[TELNET] in AP mode"); // added by Proddy
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
;
|
;
|
||||||
; PlatformIO Project Configuration File for EMS-ESP
|
; PlatformIO Project Configuration File for EMS-ESP
|
||||||
; Uses PlatformIO 4.0
|
|
||||||
;
|
;
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
@@ -8,24 +7,15 @@ default_envs = release
|
|||||||
;default_envs = debug
|
;default_envs = debug
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
debug_flags = -Wall -Wextra -Werror -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -DTESTS
|
; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DFORCE_SERIAL -DNO_GLOBAL_EEPROM -DLOGICANALYZER
|
||||||
general_flags = -g -w -DNO_GLOBAL_EEPROM
|
extra_flags = -DNO_GLOBAL_EEPROM
|
||||||
|
|
||||||
arduino_core_2_3_0 = espressif8266@1.5.0
|
|
||||||
arduino_core_2_4_0 = espressif8266@1.6.0
|
|
||||||
arduino_core_2_4_1 = espressif8266@1.7.3
|
|
||||||
arduino_core_2_4_2 = espressif8266@1.8.0
|
|
||||||
arduino_core_2_5_0 = espressif8266@2.0.4
|
|
||||||
arduino_core_2_5_1 = espressif8266@2.1.1
|
|
||||||
arduino_core_2_5_2 = espressif8266@2.2.1
|
|
||||||
arduino_core_latest = espressif8266
|
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
board = d1_mini
|
board = d1_mini
|
||||||
; board = nodemcuv2
|
; board = nodemcuv2
|
||||||
; board = d1_mini_pro
|
; board = d1_mini_pro
|
||||||
framework = arduino
|
framework = arduino
|
||||||
platform = ${common.arduino_core_latest}
|
platform = espressif8266
|
||||||
lib_deps =
|
lib_deps =
|
||||||
CRC32
|
CRC32
|
||||||
CircularBuffer
|
CircularBuffer
|
||||||
@@ -41,16 +31,17 @@ monitor_speed = 115200
|
|||||||
;upload_port = ems-esp.local
|
;upload_port = ems-esp.local
|
||||||
|
|
||||||
[env:debug]
|
[env:debug]
|
||||||
build_flags = ${common.general_flags} ${common.debug_flags}
|
build_type = debug
|
||||||
|
build_flags = ${common.extra_flags} -DCRASH
|
||||||
extra_scripts = pre:scripts/rename_fw.py
|
extra_scripts = pre:scripts/rename_fw.py
|
||||||
|
|
||||||
[env:clean]
|
[env:clean]
|
||||||
extra_scripts = pre:scripts/clean_fw.py
|
extra_scripts = pre:scripts/clean_fw.py
|
||||||
|
|
||||||
[env:release]
|
[env:release]
|
||||||
build_flags = ${common.general_flags}
|
build_flags = ${common.extra_flags}
|
||||||
extra_scripts = pre:scripts/rename_fw.py
|
extra_scripts = pre:scripts/rename_fw.py
|
||||||
|
|
||||||
[env:checkcode]
|
[env:checkcode]
|
||||||
build_flags = ${common.general_flags}
|
build_flags = ${common.extra_flags}
|
||||||
extra_scripts = scripts/checkcode.py
|
extra_scripts = scripts/checkcode.py
|
||||||
|
|||||||
@@ -17,4 +17,8 @@ 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.elf", 'scripts/stackdmp.txt'])
|
call(['python', 'scripts/decoder.py ', '-s', '-e', os.getcwd()+"/.pio/build/debug/firmware_d1_mini_debug.elf", 'scripts/stackdmp.txt'])
|
||||||
|
|
||||||
|
# example for linux:
|
||||||
|
# % cd EMS-ESP
|
||||||
|
# % python scripts/decoder_linux.py -s -e .pio/build/debug/firmware_d1_mini.elf scripts/stackdmp.txt
|
||||||
|
|||||||
307
scripts/decoder_linux.py
Normal file
307
scripts/decoder_linux.py
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""ESP Exception Decoder
|
||||||
|
|
||||||
|
github: https://github.com/janLo/EspArduinoExceptionDecoder
|
||||||
|
license: GPL v3
|
||||||
|
author: Jan Losinski
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
EXCEPTIONS = [
|
||||||
|
"Illegal instruction",
|
||||||
|
"SYSCALL instruction",
|
||||||
|
"InstructionFetchError: Processor internal physical address or data error during instruction fetch",
|
||||||
|
"LoadStoreError: Processor internal physical address or data error during load or store",
|
||||||
|
"Level1Interrupt: Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register",
|
||||||
|
"Alloca: MOVSP instruction, if caller's registers are not in the register file",
|
||||||
|
"IntegerDivideByZero: QUOS, QUOU, REMS, or REMU divisor operand is zero",
|
||||||
|
"reserved",
|
||||||
|
"Privileged: Attempt to execute a privileged operation when CRING ? 0",
|
||||||
|
"LoadStoreAlignmentCause: Load or store to an unaligned address",
|
||||||
|
"reserved",
|
||||||
|
"reserved",
|
||||||
|
"InstrPIFDataError: PIF data error during instruction fetch",
|
||||||
|
"LoadStorePIFDataError: Synchronous PIF data error during LoadStore access",
|
||||||
|
"InstrPIFAddrError: PIF address error during instruction fetch",
|
||||||
|
"LoadStorePIFAddrError: Synchronous PIF address error during LoadStore access",
|
||||||
|
"InstTLBMiss: Error during Instruction TLB refill",
|
||||||
|
"InstTLBMultiHit: Multiple instruction TLB entries matched",
|
||||||
|
"InstFetchPrivilege: An instruction fetch referenced a virtual address at a ring level less than CRING",
|
||||||
|
"reserved",
|
||||||
|
"InstFetchProhibited: An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch",
|
||||||
|
"reserved",
|
||||||
|
"reserved",
|
||||||
|
"reserved",
|
||||||
|
"LoadStoreTLBMiss: Error during TLB refill for a load or store",
|
||||||
|
"LoadStoreTLBMultiHit: Multiple TLB entries matched for a load or store",
|
||||||
|
"LoadStorePrivilege: A load or store referenced a virtual address at a ring level less than CRING",
|
||||||
|
"reserved",
|
||||||
|
"LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads",
|
||||||
|
"StoreProhibited: A store referenced a page mapped with an attribute that does not permit stores"
|
||||||
|
]
|
||||||
|
|
||||||
|
PLATFORMS = {
|
||||||
|
"ESP8266": "lx106",
|
||||||
|
"ESP32": "esp32"
|
||||||
|
}
|
||||||
|
|
||||||
|
EXCEPTION_REGEX = re.compile("^Exception \\((?P<exc>[0-9]*)\\):$")
|
||||||
|
COUNTER_REGEX = re.compile('^epc1=(?P<epc1>0x[0-9a-f]+) epc2=(?P<epc2>0x[0-9a-f]+) epc3=(?P<epc3>0x[0-9a-f]+) '
|
||||||
|
'excvaddr=(?P<excvaddr>0x[0-9a-f]+) depc=(?P<depc>0x[0-9a-f]+)$')
|
||||||
|
CTX_REGEX = re.compile("^ctx: (?P<ctx>.+)$")
|
||||||
|
POINTER_REGEX = re.compile('^sp: (?P<sp>[0-9a-f]+) end: (?P<end>[0-9a-f]+) offset: (?P<offset>[0-9a-f]+)$')
|
||||||
|
STACK_BEGIN = '>>>stack>>>'
|
||||||
|
STACK_END = '<<<stack<<<'
|
||||||
|
STACK_REGEX = re.compile(
|
||||||
|
'^(?P<off>[0-9a-f]+):\W+(?P<c1>[0-9a-f]+) (?P<c2>[0-9a-f]+) (?P<c3>[0-9a-f]+) (?P<c4>[0-9a-f]+)(\W.*)?$')
|
||||||
|
|
||||||
|
StackLine = namedtuple("StackLine", ["offset", "content"])
|
||||||
|
|
||||||
|
|
||||||
|
class ExceptionDataParser(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.exception = None
|
||||||
|
|
||||||
|
self.epc1 = None
|
||||||
|
self.epc2 = None
|
||||||
|
self.epc3 = None
|
||||||
|
self.excvaddr = None
|
||||||
|
self.depc = None
|
||||||
|
|
||||||
|
self.ctx = None
|
||||||
|
|
||||||
|
self.sp = None
|
||||||
|
self.end = None
|
||||||
|
self.offset = None
|
||||||
|
|
||||||
|
self.stack = []
|
||||||
|
|
||||||
|
def _parse_exception(self, line):
|
||||||
|
match = EXCEPTION_REGEX.match(line)
|
||||||
|
if match is not None:
|
||||||
|
self.exception = int(match.group('exc'))
|
||||||
|
return self._parse_counters
|
||||||
|
return self._parse_exception
|
||||||
|
|
||||||
|
def _parse_counters(self, line):
|
||||||
|
match = COUNTER_REGEX.match(line)
|
||||||
|
if match is not None:
|
||||||
|
self.epc1 = match.group("epc1")
|
||||||
|
self.epc2 = match.group("epc2")
|
||||||
|
self.epc3 = match.group("epc3")
|
||||||
|
self.excvaddr = match.group("excvaddr")
|
||||||
|
self.depc = match.group("depc")
|
||||||
|
return self._parse_ctx
|
||||||
|
return self._parse_counters
|
||||||
|
|
||||||
|
def _parse_ctx(self, line):
|
||||||
|
match = CTX_REGEX.match(line)
|
||||||
|
if match is not None:
|
||||||
|
self.ctx = match.group("ctx")
|
||||||
|
return self._parse_pointers
|
||||||
|
return self._parse_ctx
|
||||||
|
|
||||||
|
def _parse_pointers(self, line):
|
||||||
|
match = POINTER_REGEX.match(line)
|
||||||
|
if match is not None:
|
||||||
|
self.sp = match.group("sp")
|
||||||
|
self.end = match.group("end")
|
||||||
|
self.offset = match.group("offset")
|
||||||
|
return self._parse_stack_begin
|
||||||
|
return self._parse_pointers
|
||||||
|
|
||||||
|
def _parse_stack_begin(self, line):
|
||||||
|
if line == STACK_BEGIN:
|
||||||
|
return self._parse_stack_line
|
||||||
|
return self._parse_stack_begin
|
||||||
|
|
||||||
|
def _parse_stack_line(self, line):
|
||||||
|
if line != STACK_END:
|
||||||
|
match = STACK_REGEX.match(line)
|
||||||
|
if match is not None:
|
||||||
|
self.stack.append(StackLine(offset=match.group("off"),
|
||||||
|
content=(match.group("c1"), match.group("c2"), match.group("c3"),
|
||||||
|
match.group("c4"))))
|
||||||
|
return self._parse_stack_line
|
||||||
|
return None
|
||||||
|
|
||||||
|
def parse_file(self, file, stack_only=False):
|
||||||
|
func = self._parse_exception
|
||||||
|
if stack_only:
|
||||||
|
func = self._parse_stack_begin
|
||||||
|
|
||||||
|
for line in file:
|
||||||
|
func = func(line.strip())
|
||||||
|
if func is None:
|
||||||
|
break
|
||||||
|
|
||||||
|
if func is not None:
|
||||||
|
print("ERROR: Parser not complete!")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
class AddressResolver(object):
|
||||||
|
def __init__(self, tool_path, elf_path):
|
||||||
|
self._tool = tool_path
|
||||||
|
self._elf = elf_path
|
||||||
|
self._address_map = {}
|
||||||
|
|
||||||
|
def _lookup(self, addresses):
|
||||||
|
cmd = [self._tool, "-aipfC", "-e", self._elf] + [addr for addr in addresses if addr is not None]
|
||||||
|
|
||||||
|
if sys.version_info[0] < 3:
|
||||||
|
output = subprocess.check_output(cmd)
|
||||||
|
else:
|
||||||
|
output = subprocess.check_output(cmd, encoding="utf-8")
|
||||||
|
|
||||||
|
line_regex = re.compile("^(?P<addr>[0-9a-fx]+): (?P<result>.+)$")
|
||||||
|
|
||||||
|
last = None
|
||||||
|
for line in output.splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
match = line_regex.match(line)
|
||||||
|
|
||||||
|
if match is None:
|
||||||
|
if last is not None and line.startswith('(inlined by)'):
|
||||||
|
line = line [12:].strip()
|
||||||
|
self._address_map[last] += ("\n \-> inlined by: " + line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if match.group("result") == '?? ??:0':
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._address_map[match.group("addr")] = match.group("result")
|
||||||
|
last = match.group("addr")
|
||||||
|
|
||||||
|
def fill(self, parser):
|
||||||
|
addresses = [parser.epc1, parser.epc2, parser.epc3, parser.excvaddr, parser.sp, parser.end, parser.offset]
|
||||||
|
for line in parser.stack:
|
||||||
|
addresses.extend(line.content)
|
||||||
|
|
||||||
|
self._lookup(addresses)
|
||||||
|
|
||||||
|
def _sanitize_addr(self, addr):
|
||||||
|
if addr.startswith("0x"):
|
||||||
|
addr = addr[2:]
|
||||||
|
|
||||||
|
fill = "0" * (8 - len(addr))
|
||||||
|
return "0x" + fill + addr
|
||||||
|
|
||||||
|
def resolve_addr(self, addr):
|
||||||
|
out = self._sanitize_addr(addr)
|
||||||
|
|
||||||
|
if out in self._address_map:
|
||||||
|
out += ": " + self._address_map[out]
|
||||||
|
|
||||||
|
return out
|
||||||
|
|
||||||
|
def resolve_stack_addr(self, addr, full=True):
|
||||||
|
addr = self._sanitize_addr(addr)
|
||||||
|
if addr in self._address_map:
|
||||||
|
return addr + ": " + self._address_map[addr]
|
||||||
|
|
||||||
|
if full:
|
||||||
|
return "[DATA (0x" + addr + ")]"
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def print_addr(name, value, resolver):
|
||||||
|
print("{}:{} {}".format(name, " " * (8 - len(name)), resolver.resolve_addr(value)))
|
||||||
|
|
||||||
|
|
||||||
|
def print_stack_full(lines, resolver):
|
||||||
|
print("stack:")
|
||||||
|
for line in lines:
|
||||||
|
print(line.offset + ":")
|
||||||
|
for content in line.content:
|
||||||
|
print(" " + resolver.resolve_stack_addr(content))
|
||||||
|
|
||||||
|
|
||||||
|
def print_stack(lines, resolver):
|
||||||
|
print("stack:")
|
||||||
|
for line in lines:
|
||||||
|
for content in line.content:
|
||||||
|
out = resolver.resolve_stack_addr(content, full=False)
|
||||||
|
if out is None:
|
||||||
|
continue
|
||||||
|
print(out)
|
||||||
|
|
||||||
|
|
||||||
|
def print_result(parser, resolver, full=True, stack_only=False):
|
||||||
|
if not stack_only:
|
||||||
|
print('Exception: {} ({})'.format(parser.exception, EXCEPTIONS[parser.exception]))
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print_addr("epc1", parser.epc1, resolver)
|
||||||
|
print_addr("epc2", parser.epc2, resolver)
|
||||||
|
print_addr("epc3", parser.epc3, resolver)
|
||||||
|
print_addr("excvaddr", parser.excvaddr, resolver)
|
||||||
|
print_addr("depc", parser.depc, resolver)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("ctx: " + parser.ctx)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print_addr("sp", parser.sp, resolver)
|
||||||
|
print_addr("end", parser.end, resolver)
|
||||||
|
print_addr("offset", parser.offset, resolver)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
if full:
|
||||||
|
print_stack_full(parser.stack, resolver)
|
||||||
|
else:
|
||||||
|
print_stack(parser.stack, resolver)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = argparse.ArgumentParser(description="decode ESP Stacktraces.")
|
||||||
|
|
||||||
|
parser.add_argument("-p", "--platform", help="The platform to decode from", choices=PLATFORMS.keys(),
|
||||||
|
default="ESP8266")
|
||||||
|
parser.add_argument("-t", "--tool", help="Path to the xtensa toolchain",
|
||||||
|
default="~/.platformio/packages/toolchain-xtensa/")
|
||||||
|
parser.add_argument("-e", "--elf", help="path to elf file", required=True)
|
||||||
|
parser.add_argument("-f", "--full", help="Print full stack dump", action="store_true")
|
||||||
|
parser.add_argument("-s", "--stack_only", help="Decode only a stractrace", action="store_true")
|
||||||
|
parser.add_argument("file", help="The file to read the exception data from ('-' for STDIN)", default="-")
|
||||||
|
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = parse_args()
|
||||||
|
|
||||||
|
if args.file == "-":
|
||||||
|
file = sys.stdin
|
||||||
|
else:
|
||||||
|
if not os.path.exists(args.file):
|
||||||
|
print("ERROR: file " + args.file + " not found")
|
||||||
|
sys.exit(1)
|
||||||
|
file = open(args.file, "r")
|
||||||
|
|
||||||
|
addr2line = os.path.join(os.path.abspath(os.path.expanduser(args.tool)),
|
||||||
|
"bin/xtensa-" + PLATFORMS[args.platform] + "-elf-addr2line")
|
||||||
|
if not os.path.exists(addr2line):
|
||||||
|
print("ERROR: addr2line not found (" + addr2line + ")")
|
||||||
|
|
||||||
|
elf_file = os.path.abspath(os.path.expanduser(args.elf))
|
||||||
|
if not os.path.exists(elf_file):
|
||||||
|
print("ERROR: elf file not found (" + elf_file + ")")
|
||||||
|
|
||||||
|
parser = ExceptionDataParser()
|
||||||
|
resolver = AddressResolver(addr2line, elf_file)
|
||||||
|
|
||||||
|
parser.parse_file(file, args.stack_only)
|
||||||
|
resolver.fill(parser)
|
||||||
|
|
||||||
|
print_result(parser, resolver, args.full, args.stack_only)
|
||||||
@@ -1,8 +1,26 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from subprocess import call
|
import re
|
||||||
import os
|
|
||||||
Import("env")
|
Import("env")
|
||||||
|
|
||||||
# see http://docs.platformio.org/en/latest/projectconf/advanced_scripting.html#before-pre-and-after-post-actions
|
bag = {}
|
||||||
# env.Replace(PROGNAME="firmware_%s" % defines.get("VERSION"))
|
exprs = [
|
||||||
env.Replace(PROGNAME="firmware_%s" % env['BOARD'])
|
(re.compile(r'^#define APP_VERSION\s+"(\S+)"'), 'app_version'),
|
||||||
|
(re.compile(r'^#define APP_NAME\s+"(\S+)"'), 'app_name'),
|
||||||
|
(re.compile(r'^#define APP_HOSTNAME\s+"(\S+)"'), 'app_hostname')
|
||||||
|
]
|
||||||
|
with open('./src/version.h', '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_name = bag.get('app_name')
|
||||||
|
app_hostname = bag.get('app_hostname')
|
||||||
|
|
||||||
|
board = env['BOARD']
|
||||||
|
branch = env['PIOENV']
|
||||||
|
|
||||||
|
# build filename, replacing . with _ for the version
|
||||||
|
env.Replace(PROGNAME="firmware_%s" % branch + "_" + app_version.replace(".", "_"))
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
std::vector<ds_device_t> _devices;
|
std::vector<ds_device_t> _devices;
|
||||||
|
|
||||||
DS18::DS18() {
|
DS18::DS18() {
|
||||||
_wire = NULL;
|
_wire = nullptr;
|
||||||
_count = 0;
|
_count = 0;
|
||||||
_gpio = GPIO_NONE;
|
_gpio = GPIO_NONE;
|
||||||
_parasite = 0;
|
_parasite = 0;
|
||||||
|
|||||||
573
src/ems-esp.cpp
573
src/ems-esp.cpp
File diff suppressed because it is too large
Load Diff
526
src/ems.cpp
526
src/ems.cpp
@@ -63,6 +63,7 @@ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram);
|
|||||||
|
|
||||||
// ISM1
|
// ISM1
|
||||||
void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram);
|
void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram);
|
||||||
|
void _process_ISM1Set(_EMS_RxTelegram * EMS_RxTelegram);
|
||||||
|
|
||||||
// HeatPump HP
|
// HeatPump HP
|
||||||
void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram);
|
void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram);
|
||||||
@@ -116,19 +117,22 @@ const _EMS_Type EMS_Types[] = {
|
|||||||
{EMS_MODEL_UBA, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage},
|
{EMS_MODEL_UBA, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW},
|
{EMS_MODEL_UBA, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", _process_UBATotalUptimeMessage},
|
{EMS_MODEL_UBA, EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", _process_UBATotalUptimeMessage},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", NULL},
|
{EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", nullptr},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", _process_UBAParametersMessage},
|
{EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", _process_UBAParametersMessage},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
|
{EMS_MODEL_UBA, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
|
||||||
|
|
||||||
// Other devices
|
// SM devices
|
||||||
{EMS_MODEL_OTHER, EMS_TYPE_SM10Monitor, "SM10Monitor", _process_SM10Monitor},
|
{EMS_MODEL_SM, EMS_TYPE_SM10Monitor, "SM10Monitor", _process_SM10Monitor},
|
||||||
{EMS_MODEL_OTHER, EMS_TYPE_SM100Monitor, "SM100Monitor", _process_SM100Monitor},
|
{EMS_MODEL_SM, EMS_TYPE_SM100Monitor, "SM100Monitor", _process_SM100Monitor},
|
||||||
{EMS_MODEL_OTHER, EMS_TYPE_SM100Status, "SM100Status", _process_SM100Status},
|
{EMS_MODEL_SM, EMS_TYPE_SM100Status, "SM100Status", _process_SM100Status},
|
||||||
{EMS_MODEL_OTHER, EMS_TYPE_SM100Status2, "SM100Status2", _process_SM100Status2},
|
{EMS_MODEL_SM, EMS_TYPE_SM100Status2, "SM100Status2", _process_SM100Status2},
|
||||||
{EMS_MODEL_OTHER, EMS_TYPE_SM100Energy, "SM100Energy", _process_SM100Energy},
|
{EMS_MODEL_SM, EMS_TYPE_SM100Energy, "SM100Energy", _process_SM100Energy},
|
||||||
{EMS_MODEL_OTHER, EMS_TYPE_HPMonitor1, "HeatPumpMonitor1", _process_HPMonitor1},
|
{EMS_MODEL_SM, EMS_TYPE_ISM1StatusMessage, "ISM1StatusMessage", _process_ISM1StatusMessage},
|
||||||
{EMS_MODEL_OTHER, EMS_TYPE_HPMonitor2, "HeatPumpMonitor2", _process_HPMonitor2},
|
{EMS_MODEL_SM, EMS_TYPE_ISM1Set, "ISM1Set", _process_ISM1Set},
|
||||||
{EMS_MODEL_OTHER, EMS_TYPE_ISM1StatusMessage, "ISM1StatusMessage", _process_ISM1StatusMessage},
|
|
||||||
|
// heatpunps
|
||||||
|
{EMS_MODEL_HP, EMS_TYPE_HPMonitor1, "HeatPumpMonitor1", _process_HPMonitor1},
|
||||||
|
{EMS_MODEL_HP, EMS_TYPE_HPMonitor2, "HeatPumpMonitor2", _process_HPMonitor2},
|
||||||
|
|
||||||
// RC10
|
// RC10
|
||||||
{EMS_MODEL_RC10, EMS_TYPE_RCTime, "RCTime", _process_RCTime},
|
{EMS_MODEL_RC10, EMS_TYPE_RCTime, "RCTime", _process_RCTime},
|
||||||
@@ -184,12 +188,16 @@ const _EMS_Type EMS_Types[] = {
|
|||||||
// calculate sizes of arrays at compile
|
// calculate sizes of arrays at compile
|
||||||
uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types
|
uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types
|
||||||
uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boiler models
|
uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boiler models
|
||||||
|
uint8_t _Solar_Module_Types_max = ArraySize(SolarModule_Types); // number of solar module types
|
||||||
uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices
|
uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices
|
||||||
uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types
|
uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types
|
||||||
|
uint8_t _HeatPump_Types_max = ArraySize(HeatPump_Types); // number of defined heatpuimp types
|
||||||
|
|
||||||
// these structs contain the data we store from the Boiler and Thermostat
|
// these structs contain the data we store from the specific EMS devices
|
||||||
_EMS_Boiler EMS_Boiler; // for boiler
|
_EMS_Boiler EMS_Boiler; // for boiler
|
||||||
_EMS_Thermostat EMS_Thermostat; // for thermostat
|
_EMS_Thermostat EMS_Thermostat; // for thermostat
|
||||||
|
_EMS_SolarModule EMS_SolarModule; // for solar modules
|
||||||
|
_EMS_HeatPump EMS_HeatPump; // for heatpumps
|
||||||
_EMS_Other EMS_Other; // for other known EMS devices
|
_EMS_Other EMS_Other; // for other known EMS devices
|
||||||
|
|
||||||
// CRC lookup table with poly 12 for faster checking
|
// CRC lookup table with poly 12 for faster checking
|
||||||
@@ -212,7 +220,6 @@ const uint32_t EMS_BUS_TIMEOUT = 15000; // timeout in ms before recogni
|
|||||||
const uint32_t EMS_POLL_TIMEOUT = 5000000; // timeout in microseconds before recognizing the ems bus is offline (5 seconds)
|
const uint32_t EMS_POLL_TIMEOUT = 5000000; // timeout in microseconds before recognizing the ems bus is offline (5 seconds)
|
||||||
|
|
||||||
// init stats and counters and buffers
|
// init stats and counters and buffers
|
||||||
// uses -255 or 255 for values that haven't been set yet (EMS_VALUE_INT_NOTSET and EMS_VALUE_FLOAT_NOTSET)
|
|
||||||
void ems_init() {
|
void ems_init() {
|
||||||
// overall status
|
// overall status
|
||||||
EMS_Sys_Status.emsRxPgks = 0;
|
EMS_Sys_Status.emsRxPgks = 0;
|
||||||
@@ -229,6 +236,7 @@ void ems_init() {
|
|||||||
EMS_Sys_Status.emsPollFrequency = 0;
|
EMS_Sys_Status.emsPollFrequency = 0;
|
||||||
EMS_Sys_Status.txRetryCount = 0;
|
EMS_Sys_Status.txRetryCount = 0;
|
||||||
EMS_Sys_Status.emsReverse = false;
|
EMS_Sys_Status.emsReverse = false;
|
||||||
|
EMS_Sys_Status.emsTxMode = 0;
|
||||||
|
|
||||||
// thermostat
|
// thermostat
|
||||||
EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||||
@@ -239,8 +247,8 @@ void ems_init() {
|
|||||||
EMS_Thermostat.day = 0;
|
EMS_Thermostat.day = 0;
|
||||||
EMS_Thermostat.month = 0;
|
EMS_Thermostat.month = 0;
|
||||||
EMS_Thermostat.year = 0;
|
EMS_Thermostat.year = 0;
|
||||||
EMS_Thermostat.mode = 255; // dummy value
|
EMS_Thermostat.mode = EMS_VALUE_INT_NOTSET;
|
||||||
EMS_Thermostat.day_mode = 255; // dummy value
|
EMS_Thermostat.day_mode = EMS_VALUE_INT_NOTSET;
|
||||||
EMS_Thermostat.device_id = EMS_ID_NONE;
|
EMS_Thermostat.device_id = EMS_ID_NONE;
|
||||||
EMS_Thermostat.write_supported = false;
|
EMS_Thermostat.write_supported = false;
|
||||||
EMS_Thermostat.hc = 1; // default heating circuit is 1
|
EMS_Thermostat.hc = 1; // default heating circuit is 1
|
||||||
@@ -260,8 +268,8 @@ void ems_init() {
|
|||||||
|
|
||||||
// UBAMonitorFast
|
// UBAMonitorFast
|
||||||
EMS_Boiler.selFlowTemp = EMS_VALUE_INT_NOTSET; // Selected flow temperature
|
EMS_Boiler.selFlowTemp = EMS_VALUE_INT_NOTSET; // Selected flow temperature
|
||||||
EMS_Boiler.curFlowTemp = EMS_VALUE_SHORT_NOTSET; // Current flow temperature
|
EMS_Boiler.curFlowTemp = EMS_VALUE_USHORT_NOTSET; // Current flow temperature
|
||||||
EMS_Boiler.retTemp = EMS_VALUE_SHORT_NOTSET; // Return temperature
|
EMS_Boiler.retTemp = EMS_VALUE_USHORT_NOTSET; // Return temperature
|
||||||
EMS_Boiler.burnGas = EMS_VALUE_INT_NOTSET; // Gas on/off
|
EMS_Boiler.burnGas = EMS_VALUE_INT_NOTSET; // Gas on/off
|
||||||
EMS_Boiler.fanWork = EMS_VALUE_INT_NOTSET; // Fan on/off
|
EMS_Boiler.fanWork = EMS_VALUE_INT_NOTSET; // Fan on/off
|
||||||
EMS_Boiler.ignWork = EMS_VALUE_INT_NOTSET; // Ignition on/off
|
EMS_Boiler.ignWork = EMS_VALUE_INT_NOTSET; // Ignition on/off
|
||||||
@@ -277,14 +285,14 @@ void ems_init() {
|
|||||||
|
|
||||||
// UBAMonitorSlow
|
// UBAMonitorSlow
|
||||||
EMS_Boiler.extTemp = EMS_VALUE_SHORT_NOTSET; // Outside temperature
|
EMS_Boiler.extTemp = EMS_VALUE_SHORT_NOTSET; // Outside temperature
|
||||||
EMS_Boiler.boilTemp = EMS_VALUE_SHORT_NOTSET; // Boiler temperature
|
EMS_Boiler.boilTemp = EMS_VALUE_USHORT_NOTSET; // Boiler temperature
|
||||||
EMS_Boiler.pumpMod = EMS_VALUE_INT_NOTSET; // Pump modulation
|
EMS_Boiler.pumpMod = EMS_VALUE_INT_NOTSET; // Pump modulation
|
||||||
EMS_Boiler.burnStarts = EMS_VALUE_LONG_NOTSET; // # burner restarts
|
EMS_Boiler.burnStarts = EMS_VALUE_LONG_NOTSET; // # burner restarts
|
||||||
EMS_Boiler.burnWorkMin = EMS_VALUE_LONG_NOTSET; // Total burner operating time
|
EMS_Boiler.burnWorkMin = EMS_VALUE_LONG_NOTSET; // Total burner operating time
|
||||||
EMS_Boiler.heatWorkMin = EMS_VALUE_LONG_NOTSET; // Total heat operating time
|
EMS_Boiler.heatWorkMin = EMS_VALUE_LONG_NOTSET; // Total heat operating time
|
||||||
|
|
||||||
// UBAMonitorWWMessage
|
// UBAMonitorWWMessage
|
||||||
EMS_Boiler.wWCurTmp = EMS_VALUE_SHORT_NOTSET; // Warm Water current temperature
|
EMS_Boiler.wWCurTmp = EMS_VALUE_USHORT_NOTSET; // Warm Water current temperature
|
||||||
EMS_Boiler.wWStarts = EMS_VALUE_LONG_NOTSET; // Warm Water # starts
|
EMS_Boiler.wWStarts = EMS_VALUE_LONG_NOTSET; // Warm Water # starts
|
||||||
EMS_Boiler.wWWorkM = EMS_VALUE_LONG_NOTSET; // Warm Water # minutes
|
EMS_Boiler.wWWorkM = EMS_VALUE_LONG_NOTSET; // Warm Water # minutes
|
||||||
EMS_Boiler.wWOneTime = EMS_VALUE_INT_NOTSET; // Warm Water one time function on/off
|
EMS_Boiler.wWOneTime = EMS_VALUE_INT_NOTSET; // Warm Water one time function on/off
|
||||||
@@ -298,16 +306,26 @@ void ems_init() {
|
|||||||
EMS_Boiler.pump_mod_max = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation max. power
|
EMS_Boiler.pump_mod_max = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation max. power
|
||||||
EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power
|
EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power
|
||||||
|
|
||||||
|
// Solar Module values
|
||||||
|
EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100
|
||||||
|
EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100
|
||||||
|
EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100
|
||||||
|
EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active
|
||||||
|
EMS_SolarModule.EnergyLastHour = EMS_VALUE_USHORT_NOTSET;
|
||||||
|
EMS_SolarModule.EnergyToday = EMS_VALUE_USHORT_NOTSET;
|
||||||
|
EMS_SolarModule.EnergyTotal = EMS_VALUE_USHORT_NOTSET;
|
||||||
|
EMS_SolarModule.device_id = EMS_ID_NONE;
|
||||||
|
EMS_SolarModule.model_id = EMS_MODEL_NONE;
|
||||||
|
EMS_SolarModule.product_id = EMS_ID_NONE;
|
||||||
|
EMS_SolarModule.pumpWorkMin = EMS_VALUE_LONG_NOTSET;
|
||||||
|
EMS_SolarModule.setpoint_maxBottomTemp = EMS_VALUE_SHORT_NOTSET;
|
||||||
|
|
||||||
// Other EMS devices values
|
// Other EMS devices values
|
||||||
EMS_Other.SMcollectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100
|
EMS_HeatPump.HPModulation = EMS_VALUE_INT_NOTSET;
|
||||||
EMS_Other.SMbottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100
|
EMS_HeatPump.HPSpeed = EMS_VALUE_INT_NOTSET;
|
||||||
EMS_Other.SMpumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100
|
EMS_HeatPump.device_id = EMS_ID_NONE;
|
||||||
EMS_Other.SMpump = EMS_VALUE_INT_NOTSET; // pump active
|
EMS_HeatPump.model_id = EMS_MODEL_NONE;
|
||||||
EMS_Other.SMEnergyLastHour = EMS_VALUE_SHORT_NOTSET;
|
EMS_HeatPump.product_id = EMS_ID_NONE;
|
||||||
EMS_Other.SMEnergyToday = EMS_VALUE_SHORT_NOTSET;
|
|
||||||
EMS_Other.SMEnergyTotal = EMS_VALUE_SHORT_NOTSET;
|
|
||||||
EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET;
|
|
||||||
EMS_Other.HPSpeed = EMS_VALUE_INT_NOTSET;
|
|
||||||
|
|
||||||
// calculated values
|
// calculated values
|
||||||
EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off
|
EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off
|
||||||
@@ -322,9 +340,6 @@ void ems_init() {
|
|||||||
EMS_Thermostat.product_id = EMS_ID_NONE;
|
EMS_Thermostat.product_id = EMS_ID_NONE;
|
||||||
strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version));
|
strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version));
|
||||||
|
|
||||||
// set other types
|
|
||||||
EMS_Other.SM = false;
|
|
||||||
EMS_Other.HP = false;
|
|
||||||
|
|
||||||
// default logging is none
|
// default logging is none
|
||||||
ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
|
ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
|
||||||
@@ -340,6 +355,23 @@ bool ems_getPoll() {
|
|||||||
return EMS_Sys_Status.emsPollEnabled;
|
return EMS_Sys_Status.emsPollEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ems_setTxMode(uint8_t mode) {
|
||||||
|
EMS_Sys_Status.emsTxMode = mode;
|
||||||
|
|
||||||
|
// special case for Junkers. If tx_mode is 3 then set the reverse poll flag
|
||||||
|
// https://github.com/proddy/EMS-ESP/issues/103#issuecomment-495945850
|
||||||
|
if (mode == 3) {
|
||||||
|
EMS_Sys_Status.emsReverse = true;
|
||||||
|
myDebug_P(PSTR("Forcing emsReverse for Junkers"));
|
||||||
|
} else {
|
||||||
|
EMS_Sys_Status.emsReverse = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ems_getTxMode() {
|
||||||
|
return EMS_Sys_Status.emsTxMode;
|
||||||
|
}
|
||||||
|
|
||||||
bool ems_getEmsRefreshed() {
|
bool ems_getEmsRefreshed() {
|
||||||
return EMS_Sys_Status.emsRefreshed;
|
return EMS_Sys_Status.emsRefreshed;
|
||||||
}
|
}
|
||||||
@@ -360,14 +392,30 @@ bool ems_getThermostatEnabled() {
|
|||||||
return (EMS_Thermostat.device_id != EMS_ID_NONE);
|
return (EMS_Thermostat.device_id != EMS_ID_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ems_getSolarModuleEnabled() {
|
||||||
|
return (EMS_SolarModule.device_id != EMS_ID_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ems_getHeatPumpEnabled() {
|
||||||
|
return (EMS_HeatPump.device_id != EMS_ID_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t ems_getThermostatModel() {
|
uint8_t ems_getThermostatModel() {
|
||||||
return (EMS_Thermostat.model_id);
|
return (EMS_Thermostat.model_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t ems_getSolarModuleModel() {
|
||||||
|
return (EMS_SolarModule.model_id);
|
||||||
|
}
|
||||||
|
|
||||||
void ems_setTxDisabled(bool b) {
|
void ems_setTxDisabled(bool b) {
|
||||||
EMS_Sys_Status.emsTxDisabled = b;
|
EMS_Sys_Status.emsTxDisabled = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ems_getTxDisabled() {
|
||||||
|
return (EMS_Sys_Status.emsTxDisabled);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ems_getPollFrequency() {
|
uint32_t ems_getPollFrequency() {
|
||||||
return EMS_Sys_Status.emsPollFrequency;
|
return EMS_Sys_Status.emsPollFrequency;
|
||||||
}
|
}
|
||||||
@@ -401,6 +449,8 @@ void ems_setLogging(_EMS_SYS_LOGGING loglevel) {
|
|||||||
myDebug_P(PSTR("System Logging set to Verbose"));
|
myDebug_P(PSTR("System Logging set to Verbose"));
|
||||||
} else if (loglevel == EMS_SYS_LOGGING_THERMOSTAT) {
|
} else if (loglevel == EMS_SYS_LOGGING_THERMOSTAT) {
|
||||||
myDebug_P(PSTR("System Logging set to Thermostat only"));
|
myDebug_P(PSTR("System Logging set to Thermostat only"));
|
||||||
|
} else if (loglevel == EMS_SYS_LOGGING_SOLARMODULE) {
|
||||||
|
myDebug_P(PSTR("System Logging set to Solar Module only"));
|
||||||
} else if (loglevel == EMS_SYS_LOGGING_RAW) {
|
} else if (loglevel == EMS_SYS_LOGGING_RAW) {
|
||||||
myDebug_P(PSTR("System Logging set to Raw mode"));
|
myDebug_P(PSTR("System Logging set to Raw mode"));
|
||||||
}
|
}
|
||||||
@@ -457,7 +507,7 @@ char * _smallitoa3(uint16_t value, char * buffer) {
|
|||||||
* Find the pointer to the EMS_Types array for a given type ID
|
* Find the pointer to the EMS_Types array for a given type ID
|
||||||
* or -1 if not found
|
* or -1 if not found
|
||||||
*/
|
*/
|
||||||
int _ems_findType(uint8_t type) {
|
int _ems_findType(uint16_t type) {
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
bool typeFound = false;
|
bool typeFound = false;
|
||||||
// scan through known ID types
|
// scan through known ID types
|
||||||
@@ -498,7 +548,7 @@ void _debugPrintTelegram(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram,
|
|||||||
strlcat(output_str, prefix, sizeof(output_str));
|
strlcat(output_str, prefix, sizeof(output_str));
|
||||||
|
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
strlcat(output_str, " telegram: ", sizeof(output_str));
|
strlcat(output_str, "telegram: ", sizeof(output_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < (length - 1); i++) {
|
for (int i = 0; i < (length - 1); i++) {
|
||||||
@@ -580,19 +630,27 @@ void _ems_sendTelegram() {
|
|||||||
// for a READ or VALIDATE
|
// for a READ or VALIDATE
|
||||||
EMS_TxTelegram.data[1] = EMS_TxTelegram.dest | 0x80; // read has 8th bit set
|
EMS_TxTelegram.data[1] = EMS_TxTelegram.dest | 0x80; // read has 8th bit set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// complete the rest of the header depending on EMS or EMS+
|
||||||
|
if (EMS_TxTelegram.type > 0xFF) {
|
||||||
|
// EMS 2.0 / emsplus
|
||||||
|
EMS_TxTelegram.data[2] = 0xFF; // fixed value indicating an extended message
|
||||||
|
EMS_TxTelegram.data[3] = EMS_TxTelegram.offset;
|
||||||
|
EMS_TxTelegram.data[4] = EMS_TxTelegram.dataValue; // for read its #bytes to return, for write it the value to set
|
||||||
|
EMS_TxTelegram.data[5] = EMS_TxTelegram.type >> 8; // type, 1st byte
|
||||||
|
EMS_TxTelegram.data[6] = EMS_TxTelegram.type & 0xFF; // type, 2nd byte
|
||||||
|
EMS_TxTelegram.length += 2; // add 2 bytes to length to compensate the extra FF and byte for the type
|
||||||
|
} else {
|
||||||
|
// EMS 1.0
|
||||||
EMS_TxTelegram.data[2] = EMS_TxTelegram.type; // type
|
EMS_TxTelegram.data[2] = EMS_TxTelegram.type; // type
|
||||||
EMS_TxTelegram.data[3] = EMS_TxTelegram.offset; // offset
|
EMS_TxTelegram.data[3] = EMS_TxTelegram.offset; // offset
|
||||||
|
|
||||||
// see if it has data, add the single data value byte
|
|
||||||
// otherwise leave it alone and assume the data has been pre-populated
|
|
||||||
if (EMS_TxTelegram.length == EMS_MIN_TELEGRAM_LENGTH) {
|
if (EMS_TxTelegram.length == EMS_MIN_TELEGRAM_LENGTH) {
|
||||||
// for reading this is #bytes we want to read (the size)
|
EMS_TxTelegram.data[4] = EMS_TxTelegram.dataValue; // for read its #bytes to return, for write it the value to set
|
||||||
// for writing its the value we want to write
|
|
||||||
EMS_TxTelegram.data[4] = EMS_TxTelegram.dataValue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// finally calculate CRC and add it to the end
|
// finally calculate CRC and add it to the end
|
||||||
uint8_t crc = _crcCalculator(EMS_TxTelegram.data, EMS_TxTelegram.length);
|
EMS_TxTelegram.data[EMS_TxTelegram.length - 1] = _crcCalculator(EMS_TxTelegram.data, EMS_TxTelegram.length);
|
||||||
EMS_TxTelegram.data[EMS_TxTelegram.length - 1] = crc;
|
|
||||||
|
|
||||||
// print debug info
|
// print debug info
|
||||||
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) {
|
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) {
|
||||||
@@ -669,17 +727,27 @@ void _createValidate() {
|
|||||||
* When a telegram is processed we forcefully erase it from the stack to prevent overflow
|
* When a telegram is processed we forcefully erase it from the stack to prevent overflow
|
||||||
*/
|
*/
|
||||||
void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
||||||
// create the Rx package
|
|
||||||
static _EMS_RxTelegram EMS_RxTelegram;
|
|
||||||
static uint32_t _last_emsPollFrequency = 0;
|
static uint32_t _last_emsPollFrequency = 0;
|
||||||
|
|
||||||
EMS_RxTelegram.telegram = telegram;
|
/*
|
||||||
EMS_RxTelegram.timestamp = millis();
|
* check if we just received a single byte
|
||||||
EMS_RxTelegram.length = length;
|
* it could well be a Poll request from the boiler for us, which will have a value of 0x8B (0x0B | 0x80)
|
||||||
|
* or either a return code like 0x01 or 0x04 from the last Write command
|
||||||
|
* Roger Wilco: we have different types here:
|
||||||
|
* EMS_ID_ME && length == 1 && EMS_TX_STATUS_IDLE && EMS_RX_STATUS_IDLE: polling request
|
||||||
|
* EMS_ID_ME && length > 1 && EMS_TX_STATUS_IDLE && EMS_RX_STATUS_IDLE: direct telegram
|
||||||
|
* (EMS_TX_SUCCESS || EMS_TX_ERROR) && EMS_TX_STATUS_WAIT: response, free the EMS bus
|
||||||
|
*
|
||||||
|
* In addition, it may happen that we where interrupted (f.e. by WIFI activity) and the
|
||||||
|
* buffer isn't valid anymore, so we must not answer at all...
|
||||||
|
*/
|
||||||
|
if (EMS_Sys_Status.emsRxStatus != EMS_RX_STATUS_IDLE) {
|
||||||
|
if (EMS_Sys_Status.emsLogging > EMS_SYS_LOGGING_NONE) {
|
||||||
|
myDebug_P(PSTR("** [DEBUG MODE] We missed the bus - Rx non-idle!")); //TODO tidy up error logging
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// check if we just received a single byte
|
|
||||||
// it could well be a Poll request from the boiler for us, which will have a value of 0x8B (0x0B | 0x80)
|
|
||||||
// or either a return code like 0x01 or 0x04 from the last Write command
|
|
||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
uint8_t value = telegram[0]; // 1st byte of data package
|
uint8_t value = telegram[0]; // 1st byte of data package
|
||||||
|
|
||||||
@@ -728,7 +796,11 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill in the rest of the telegram
|
static _EMS_RxTelegram EMS_RxTelegram; // create the Rx package
|
||||||
|
EMS_RxTelegram.telegram = telegram;
|
||||||
|
EMS_RxTelegram.timestamp = millis();
|
||||||
|
EMS_RxTelegram.length = length;
|
||||||
|
|
||||||
EMS_RxTelegram.src = telegram[0] & 0x7F; // removing 8th bit as we deal with both reads and writes here
|
EMS_RxTelegram.src = telegram[0] & 0x7F; // removing 8th bit as we deal with both reads and writes here
|
||||||
EMS_RxTelegram.dest = telegram[1] & 0x7F; // remove 8th bit (don't care if read or write)
|
EMS_RxTelegram.dest = telegram[1] & 0x7F; // remove 8th bit (don't care if read or write)
|
||||||
EMS_RxTelegram.offset = telegram[3]; // offset is always 4th byte
|
EMS_RxTelegram.offset = telegram[3]; // offset is always 4th byte
|
||||||
@@ -766,9 +838,16 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
EMS_RxTelegram.data_length = length - 5; // remove 4 bytes header plus CRC
|
EMS_RxTelegram.data_length = length - 5; // remove 4 bytes header plus CRC
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we are in raw logging mode then just print out the telegram as it is
|
||||||
|
// but still continue to process it
|
||||||
|
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_RAW) {
|
||||||
|
_debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Assume at this point we have something that vaguely resembles a telegram in the format [src] [dest] [type] [offset] [data] [crc]
|
// Assume at this point we have something that vaguely resembles a telegram in the format [src] [dest] [type] [offset] [data] [crc]
|
||||||
// validate the CRC, if it's bad ignore it
|
// validate the CRC, if it's bad ignore it
|
||||||
if (telegram[length - 1] != _crcCalculator(telegram, length)) {
|
if (telegram[length - 1] != _crcCalculator(telegram, length)) {
|
||||||
|
LA_PULSE(200);
|
||||||
EMS_Sys_Status.emxCrcErr++;
|
EMS_Sys_Status.emxCrcErr++;
|
||||||
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) {
|
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) {
|
||||||
_debugPrintTelegram("Corrupt telegram: ", &EMS_RxTelegram, COLOR_RED, true);
|
_debugPrintTelegram("Corrupt telegram: ", &EMS_RxTelegram, COLOR_RED, true);
|
||||||
@@ -776,12 +855,6 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are in raw logging mode then just print out the telegram as it is
|
|
||||||
// but still continue to process it
|
|
||||||
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_RAW) {
|
|
||||||
_debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// here we know its a valid incoming telegram of at least 6 bytes
|
// here we know its a valid incoming telegram of at least 6 bytes
|
||||||
// we use this to see if we always have a connection to the boiler, in case of drop outs
|
// we use this to see if we always have a connection to the boiler, in case of drop outs
|
||||||
EMS_Sys_Status.emsRxTimestamp = EMS_RxTelegram.timestamp; // timestamp of last read
|
EMS_Sys_Status.emsRxTimestamp = EMS_RxTelegram.timestamp; // timestamp of last read
|
||||||
@@ -799,6 +872,7 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
uint8_t src = EMS_RxTelegram->src;
|
uint8_t src = EMS_RxTelegram->src;
|
||||||
uint8_t dest = EMS_RxTelegram->dest;
|
uint8_t dest = EMS_RxTelegram->dest;
|
||||||
uint16_t type = EMS_RxTelegram->type;
|
uint16_t type = EMS_RxTelegram->type;
|
||||||
|
uint8_t length = EMS_RxTelegram->data_length;
|
||||||
|
|
||||||
char output_str[200] = {0};
|
char output_str[200] = {0};
|
||||||
char buffer[16] = {0};
|
char buffer[16] = {0};
|
||||||
@@ -850,6 +924,7 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s));
|
strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (length != 0) {
|
||||||
// type
|
// type
|
||||||
strlcat(output_str, ", type 0x", sizeof(output_str));
|
strlcat(output_str, ", type 0x", sizeof(output_str));
|
||||||
|
|
||||||
@@ -859,18 +934,28 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
} else {
|
} else {
|
||||||
strlcat(output_str, _hextoa(type, buffer), sizeof(output_str));
|
strlcat(output_str, _hextoa(type, buffer), sizeof(output_str));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcat(output_str, ", ", sizeof(output_str));
|
||||||
|
|
||||||
|
|
||||||
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_THERMOSTAT) {
|
if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_THERMOSTAT) {
|
||||||
// only print ones to/from thermostat if logging is set to thermostat only
|
// only print ones to/from thermostat if logging is set to thermostat only
|
||||||
if ((src == EMS_Thermostat.device_id) || (dest == EMS_Thermostat.device_id)) {
|
if ((src == EMS_Thermostat.device_id) || (dest == EMS_Thermostat.device_id)) {
|
||||||
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
||||||
}
|
}
|
||||||
|
} else if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_SOLARMODULE) {
|
||||||
|
// only print ones to/from thermostat if logging is set to thermostat only
|
||||||
|
if ((src == EMS_SolarModule.device_id) || (dest == EMS_SolarModule.device_id)) {
|
||||||
|
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// always print
|
// always print
|
||||||
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
_debugPrintTelegram(output_str, EMS_RxTelegram, color_s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* print detailed telegram
|
* print detailed telegram
|
||||||
* and then call its callback if there is one defined
|
* and then call its callback if there is one defined
|
||||||
@@ -909,7 +994,7 @@ void _ems_processTelegram(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
// if it's a common type (across ems devices) or something specifically for us process it.
|
// if it's a common type (across ems devices) or something specifically for us process it.
|
||||||
// dest will be EMS_ID_NONE and offset 0x00 for a broadcast message
|
// dest will be EMS_ID_NONE and offset 0x00 for a broadcast message
|
||||||
if (typeFound) {
|
if (typeFound) {
|
||||||
if ((EMS_Types[i].processType_cb) != (void *)NULL) {
|
if ((EMS_Types[i].processType_cb) != nullptr) {
|
||||||
// print non-verbose message
|
// print non-verbose message
|
||||||
if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_BASIC) || (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE)) {
|
if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_BASIC) || (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE)) {
|
||||||
myDebug_P(PSTR("<--- %s(0x%02X)"), EMS_Types[i].typeString, type);
|
myDebug_P(PSTR("<--- %s(0x%02X)"), EMS_Types[i].typeString, type);
|
||||||
@@ -990,10 +1075,15 @@ void _processType(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
if (((EMS_RxTelegram->src & 0x7F) == (EMS_TxTelegram.dest & 0x7F)) && (EMS_RxTelegram->type == EMS_TxTelegram.type)) {
|
if (((EMS_RxTelegram->src & 0x7F) == (EMS_TxTelegram.dest & 0x7F)) && (EMS_RxTelegram->type == EMS_TxTelegram.type)) {
|
||||||
// all checks out, read was successful, remove tx from queue and continue to process telegram
|
// all checks out, read was successful, remove tx from queue and continue to process telegram
|
||||||
_removeTxQueue();
|
_removeTxQueue();
|
||||||
EMS_Sys_Status.emsRxPgks++; // increment counter
|
EMS_Sys_Status.emsRxPgks++; // increment Rx happy counter
|
||||||
ems_setEmsRefreshed(EMS_TxTelegram.forceRefresh); // does mqtt need refreshing?
|
ems_setEmsRefreshed(EMS_TxTelegram.forceRefresh); // does mqtt need refreshing?
|
||||||
} else {
|
} else {
|
||||||
// read not OK, we didn't get back a telegram we expected
|
// read not OK, we didn't get back a telegram we expected
|
||||||
|
|
||||||
|
// first see if we got a response back from the sender saying its an unknown command
|
||||||
|
if (EMS_RxTelegram->data_length == 0) {
|
||||||
|
_removeTxQueue();
|
||||||
|
} else {
|
||||||
// leave on queue and try again, but continue to process what we received as it may be important
|
// leave on queue and try again, but continue to process what we received as it may be important
|
||||||
EMS_Sys_Status.txRetryCount++;
|
EMS_Sys_Status.txRetryCount++;
|
||||||
// if retried too many times, give up and remove it
|
// if retried too many times, give up and remove it
|
||||||
@@ -1008,12 +1098,13 @@ void _processType(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_ems_processTelegram(EMS_RxTelegram); // process it always
|
_ems_processTelegram(EMS_RxTelegram); // process it always
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) {
|
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) {
|
||||||
// should not get here, since this is handled earlier receiving a 01 or 04
|
// should not get here, since this is handled earlier receiving a 01 or 04
|
||||||
myDebug_P(PSTR("** Error ! Write - should not be here"));
|
myDebug_P(PSTR("** Error! Write - should not be here"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_VALIDATE) {
|
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_VALIDATE) {
|
||||||
@@ -1173,7 +1264,7 @@ void _process_UBAMonitorSlow(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
*/
|
*/
|
||||||
void _process_RC10StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_RC10StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RC10StatusMessage_setpoint); // is * 2
|
EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RC10StatusMessage_setpoint); // is * 2
|
||||||
EMS_Thermostat.curr_roomTemp = _toByte(EMS_OFFSET_RC10StatusMessage_curr); // is * 10
|
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_RC10StatusMessage_curr); // is * 10
|
||||||
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||||
}
|
}
|
||||||
@@ -1247,9 +1338,7 @@ void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
|
|
||||||
EMS_Thermostat.day_mode = _bitRead(EMS_OFFSET_RCPLUSGet_mode_day, 1); // get day mode flag
|
EMS_Thermostat.day_mode = _bitRead(EMS_OFFSET_RCPLUSGet_mode_day, 1); // get day mode flag
|
||||||
|
|
||||||
// room night setpoint is _toByte(2) (value is *2)
|
EMS_Thermostat.mode = _bitRead(EMS_OFFSET_RCPLUSStatusMessage_mode, 0); // bit 1, mode (auto=1 or manual=0)
|
||||||
// boiler set temp is _toByte(4) (value is *2)
|
|
||||||
// day night is byte(8), 0x01 for night, 0x00 for day
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// actual set point
|
// actual set point
|
||||||
@@ -1263,6 +1352,13 @@ void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
if (EMS_RxTelegram->offset == 6) {
|
if (EMS_RxTelegram->offset == 6) {
|
||||||
// to add...
|
// to add...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// thermostat mode auto/manual, examples:
|
||||||
|
// manual : 10 00 FF 0A 01 A5 02 (CRC=16) #data=1
|
||||||
|
// auto : Thermostat -> all, type 0x01A5 telegram: 10 00 FF 0A 01 A5 03 (CRC=17) #data=1
|
||||||
|
if (EMS_RxTelegram->offset == EMS_OFFSET_RCPLUSStatusMessage_mode) {
|
||||||
|
EMS_Thermostat.mode = _bitRead(0, 0); // bit 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1284,10 +1380,12 @@ void _process_RCPLUSStatusMode(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
* FR10 Junkers - type x6F01
|
* FR10 Junkers - type x6F01
|
||||||
*/
|
*/
|
||||||
void _process_JunkersStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_JunkersStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
|
if (EMS_RxTelegram->offset == 0) {
|
||||||
// e.g. for FR10: 90 00 FF 00 00 6F 03 01 00 BE 00 BF
|
// e.g. for FR10: 90 00 FF 00 00 6F 03 01 00 BE 00 BF
|
||||||
// e.g. for FW100: 90 00 FF 00 00 6F 03 02 00 D7 00 DA F3 34 00 C4
|
// e.g. for FW100: 90 00 FF 00 00 6F 03 02 00 D7 00 DA F3 34 00 C4
|
||||||
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_curr); // value is * 10
|
EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_curr); // value is * 10
|
||||||
EMS_Thermostat.setpoint_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_setpoint); // value is * 10
|
EMS_Thermostat.setpoint_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_setpoint); // value is * 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1348,12 +1446,11 @@ void _process_RCOutdoorTempMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
* SM10Monitor - type 0x97
|
* SM10Monitor - type 0x97
|
||||||
*/
|
*/
|
||||||
void _process_SM10Monitor(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_SM10Monitor(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
EMS_Other.SMcollectorTemp = _toShort(2); // collector temp from SM10, is *10
|
EMS_SolarModule.collectorTemp = _toShort(2); // collector temp from SM10, is *10
|
||||||
EMS_Other.SMbottomTemp = _toShort(5); // bottom temp from SM10, is *10
|
EMS_SolarModule.bottomTemp = _toShort(5); // bottom temp from SM10, is *10
|
||||||
EMS_Other.SMpumpModulation = _toByte(4); // modulation solar pump
|
EMS_SolarModule.pumpModulation = _toByte(4); // modulation solar pump
|
||||||
EMS_Other.SMpump = _bitRead(7, 1); // active if bit 1 is set
|
EMS_SolarModule.pump = _bitRead(7, 1); // active if bit 1 is set
|
||||||
|
|
||||||
EMS_Other.SM = true;
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1369,13 +1466,12 @@ void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EMS_Other.SMcollectorTemp = _toShort(0); // collector temp from SM100, is *10
|
EMS_SolarModule.collectorTemp = _toShort(0); // collector temp from SM100, is *10
|
||||||
|
|
||||||
if (EMS_RxTelegram->data_length > 2) {
|
if (EMS_RxTelegram->data_length > 2) {
|
||||||
EMS_Other.SMbottomTemp = _toShort(2); // bottom temp from SM100, is *10
|
EMS_SolarModule.bottomTemp = _toShort(2); // bottom temp from SM100, is *10
|
||||||
}
|
}
|
||||||
|
|
||||||
EMS_Other.SM = true;
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1387,13 +1483,12 @@ void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
// check for complete telegram
|
// check for complete telegram
|
||||||
if (EMS_RxTelegram->offset == 0) {
|
if (EMS_RxTelegram->offset == 0) {
|
||||||
EMS_Other.SMpumpModulation = _toByte(9); // modulation solar pump
|
EMS_SolarModule.pumpModulation = _toByte(9); // modulation solar pump
|
||||||
} else if (EMS_RxTelegram->offset == 0x09) {
|
} else if (EMS_RxTelegram->offset == 0x09) {
|
||||||
// or short telegram with a single byte with offset 09
|
// or short telegram with a single byte with offset 09
|
||||||
EMS_Other.SMpumpModulation = _toByte(0); // modulation solar pump
|
EMS_SolarModule.pumpModulation = _toByte(0); // modulation solar pump
|
||||||
}
|
}
|
||||||
|
|
||||||
EMS_Other.SM = true;
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1403,13 +1498,12 @@ void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
// check for complete telegram
|
// check for complete telegram
|
||||||
if (EMS_RxTelegram->offset == 0) {
|
if (EMS_RxTelegram->offset == 0) {
|
||||||
EMS_Other.SMpump = _bitRead(10, 2); // 03=off 04=on at offset 10 which is byte 10
|
EMS_SolarModule.pump = _bitRead(10, 2); // 03=off 04=on at offset 10 which is byte 10
|
||||||
} else if (EMS_RxTelegram->offset == 0x0A) {
|
} else if (EMS_RxTelegram->offset == 0x0A) {
|
||||||
// or short telegram with a single byte with offset 0A
|
// or short telegram with a single byte with offset 0A
|
||||||
EMS_Other.SMpump = _bitRead(0, 2); // 03=off 04=on
|
EMS_SolarModule.pump = _bitRead(0, 2); // 03=off 04=on
|
||||||
}
|
}
|
||||||
|
|
||||||
EMS_Other.SM = true;
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1418,11 +1512,10 @@ void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
* e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35
|
* e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35
|
||||||
*/
|
*/
|
||||||
void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
EMS_Other.SMEnergyLastHour = _toShort(2); // last hour / 10 in Wh
|
EMS_SolarModule.EnergyLastHour = _toShort(2); // last hour / 10 in Wh
|
||||||
EMS_Other.SMEnergyToday = _toShort(6); // todays in Wh
|
EMS_SolarModule.EnergyToday = _toShort(6); // todays in Wh
|
||||||
EMS_Other.SMEnergyTotal = _toShort(10); // total / 10 in kWh
|
EMS_SolarModule.EnergyTotal = _toShort(10); // total / 10 in kWh
|
||||||
|
|
||||||
EMS_Other.SM = true;
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1430,9 +1523,8 @@ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
* Type 0xE3 - HeatPump Monitor 1
|
* Type 0xE3 - HeatPump Monitor 1
|
||||||
*/
|
*/
|
||||||
void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
EMS_Other.HPModulation = _toByte(14); // modulation %
|
EMS_HeatPump.HPModulation = _toByte(14); // modulation %
|
||||||
|
|
||||||
EMS_Other.HP = true;
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1440,9 +1532,8 @@ void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
* Type 0xE5 - HeatPump Monitor 2
|
* Type 0xE5 - HeatPump Monitor 2
|
||||||
*/
|
*/
|
||||||
void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
EMS_Other.HPSpeed = _toByte(25); // speed %
|
EMS_HeatPump.HPSpeed = _toByte(25); // speed %
|
||||||
|
|
||||||
EMS_Other.HP = true;
|
|
||||||
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1450,10 +1541,31 @@ void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
* Junkers ISM1 Solar Module - type 0x0003 EMS+ for energy readings
|
* Junkers ISM1 Solar Module - type 0x0003 EMS+ for energy readings
|
||||||
*/
|
*/
|
||||||
void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
|
if (EMS_RxTelegram->offset == 0) {
|
||||||
// e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0
|
// e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0
|
||||||
EMS_Other.SMcollectorTemp = _toShort(4); // Collector Temperature
|
EMS_SolarModule.collectorTemp = _toShort(4); // Collector Temperature
|
||||||
EMS_Other.SMbottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler
|
EMS_SolarModule.bottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler
|
||||||
EMS_Other.SM = true;
|
EMS_SolarModule.EnergyLastHour = _toShort(2); // Solar Energy produced in last hour - is * 10 and handled in ems-esp.cpp
|
||||||
|
EMS_SolarModule.pump = _bitRead(8, 0); // Solar pump on (1) or off (0)
|
||||||
|
EMS_SolarModule.pumpWorkMin = _toLong(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EMS_RxTelegram->offset == 4) {
|
||||||
|
// e.g. B0 00 FF 04 00 03 02 E5
|
||||||
|
EMS_SolarModule.collectorTemp = _toShort(0); // Collector Temperature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Junkers ISM1 Solar Module - type 0x0001 EMS+ for setting values
|
||||||
|
*/
|
||||||
|
void _process_ISM1Set(_EMS_RxTelegram * EMS_RxTelegram) {
|
||||||
|
if (EMS_RxTelegram->offset == 6) {
|
||||||
|
// e.g. 90 30 FF 06 00 01 50 (CRC=2C)
|
||||||
|
// to implement: change max solar boiler temperature
|
||||||
|
EMS_SolarModule.setpoint_maxBottomTemp = _toByte(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1508,7 +1620,6 @@ void ems_clearDeviceList() {
|
|||||||
*/
|
*/
|
||||||
void _addDevice(uint8_t product_id, uint8_t device_id, char * version, const char * model_string) {
|
void _addDevice(uint8_t product_id, uint8_t device_id, char * version, const char * model_string) {
|
||||||
_Generic_Type device;
|
_Generic_Type device;
|
||||||
|
|
||||||
// if its a duplicate don't add
|
// if its a duplicate don't add
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (std::list<_Generic_Type>::iterator it = Devices.begin(); it != Devices.end(); it++) {
|
for (std::list<_Generic_Type>::iterator it = Devices.begin(); it != Devices.end(); it++) {
|
||||||
@@ -1516,7 +1627,6 @@ void _addDevice(uint8_t product_id, uint8_t device_id, char * version, const cha
|
|||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
device.product_id = product_id;
|
device.product_id = product_id;
|
||||||
device.device_id = device_id;
|
device.device_id = device_id;
|
||||||
@@ -1631,6 +1741,64 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// look for Solar Modules
|
||||||
|
i = 0;
|
||||||
|
while (i < _Solar_Module_Types_max) {
|
||||||
|
if (SolarModule_Types[i].product_id == product_id) {
|
||||||
|
typeFound = true; // we have a matching product id. i is the index.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeFound) {
|
||||||
|
myDebug_P(PSTR("Solar Module found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"),
|
||||||
|
SolarModule_Types[i].model_string,
|
||||||
|
SolarModule_Types[i].device_id,
|
||||||
|
product_id,
|
||||||
|
version);
|
||||||
|
|
||||||
|
// add to list
|
||||||
|
_addDevice(product_id, SolarModule_Types[i].device_id, version, SolarModule_Types[i].model_string);
|
||||||
|
|
||||||
|
myDebug_P(PSTR("Solar Module support enabled."));
|
||||||
|
EMS_SolarModule.device_id = SolarModule_Types[i].device_id;
|
||||||
|
EMS_SolarModule.product_id = product_id;
|
||||||
|
strlcpy(EMS_SolarModule.version, version, sizeof(EMS_SolarModule.version));
|
||||||
|
|
||||||
|
// fetch Solar Module values
|
||||||
|
ems_getSolarModuleValues();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// look for heatpumps
|
||||||
|
i = 0;
|
||||||
|
while (i < _HeatPump_Types_max) {
|
||||||
|
if (HeatPump_Types[i].product_id == product_id) {
|
||||||
|
typeFound = true; // we have a matching product id. i is the index.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeFound) {
|
||||||
|
myDebug_P(PSTR("Heat Pump found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"),
|
||||||
|
HeatPump_Types[i].model_string,
|
||||||
|
HeatPump_Types[i].device_id,
|
||||||
|
product_id,
|
||||||
|
version);
|
||||||
|
|
||||||
|
// add to list
|
||||||
|
_addDevice(product_id, HeatPump_Types[i].device_id, version, HeatPump_Types[i].model_string);
|
||||||
|
|
||||||
|
myDebug_P(PSTR("Heat Pump support enabled."));
|
||||||
|
EMS_HeatPump.device_id = SolarModule_Types[i].device_id;
|
||||||
|
EMS_HeatPump.product_id = product_id;
|
||||||
|
strlcpy(EMS_HeatPump.version, version, sizeof(EMS_HeatPump.version));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// finally look for the other EMS devices
|
// finally look for the other EMS devices
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < _Other_Types_max) {
|
while (i < _Other_Types_max) {
|
||||||
@@ -1646,26 +1814,9 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) {
|
|||||||
|
|
||||||
// add to list
|
// add to list
|
||||||
_addDevice(product_id, Other_Types[i].device_id, version, Other_Types[i].model_string);
|
_addDevice(product_id, Other_Types[i].device_id, version, Other_Types[i].model_string);
|
||||||
|
|
||||||
// see if this is a Solar Module SM10
|
|
||||||
if (Other_Types[i].device_id == EMS_ID_SM) {
|
|
||||||
EMS_Other.SM = true; // we have detected a SM10
|
|
||||||
myDebug_P(PSTR("SM10 Solar Module support enabled."));
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if this is a HeatPump
|
|
||||||
if (Other_Types[i].device_id == EMS_ID_HP) {
|
|
||||||
EMS_Other.HP = true; // we have detected a HP
|
|
||||||
myDebug_P(PSTR("HeatPump support enabled."));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch other values
|
|
||||||
ems_getOtherValues();
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
myDebug_P(PSTR("Unrecognized device found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"), EMS_RxTelegram->src, product_id, version);
|
myDebug_P(PSTR("Unrecognized device found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"), EMS_RxTelegram->src, product_id, version);
|
||||||
|
|
||||||
// add to list
|
// add to list
|
||||||
_addDevice(product_id, EMS_RxTelegram->src, version, "unknown?");
|
_addDevice(product_id, EMS_RxTelegram->src, version, "unknown?");
|
||||||
}
|
}
|
||||||
@@ -1774,22 +1925,32 @@ void ems_getThermostatValues() {
|
|||||||
uint8_t type = EMS_Thermostat.device_id;
|
uint8_t type = EMS_Thermostat.device_id;
|
||||||
uint8_t hc = EMS_Thermostat.hc;
|
uint8_t hc = EMS_Thermostat.hc;
|
||||||
|
|
||||||
if (model_id == EMS_MODEL_RC20) {
|
switch (model_id) {
|
||||||
ems_doReadCommand(EMS_TYPE_RC20StatusMessage, type); // to get the setpoint temp
|
case EMS_MODEL_RC20:
|
||||||
|
ems_doReadCommand(EMS_TYPE_RC20StatusMessage, type); // to get the temps
|
||||||
ems_doReadCommand(EMS_TYPE_RC20Set, type); // to get the mode
|
ems_doReadCommand(EMS_TYPE_RC20Set, type); // to get the mode
|
||||||
} else if (model_id == EMS_MODEL_RC30) {
|
break;
|
||||||
ems_doReadCommand(EMS_TYPE_RC30StatusMessage, type); // to get the setpoint temp
|
case EMS_MODEL_RC30:
|
||||||
|
ems_doReadCommand(EMS_TYPE_RC30StatusMessage, type); // to get the temps
|
||||||
ems_doReadCommand(EMS_TYPE_RC30Set, type); // to get the mode
|
ems_doReadCommand(EMS_TYPE_RC30Set, type); // to get the mode
|
||||||
} else if ((model_id == EMS_MODEL_RC35) || (model_id == EMS_MODEL_ES73)) {
|
break;
|
||||||
|
case EMS_MODEL_EASY:
|
||||||
|
ems_doReadCommand(EMS_TYPE_EasyStatusMessage, type);
|
||||||
|
break;
|
||||||
|
case EMS_MODEL_RC35:
|
||||||
|
case EMS_MODEL_ES73:
|
||||||
if (hc == 1) {
|
if (hc == 1) {
|
||||||
ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC1, type); // to get the setpoint temp
|
ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC1, type); // to get the temps
|
||||||
ems_doReadCommand(EMS_TYPE_RC35Set_HC1, type); // to get the mode
|
ems_doReadCommand(EMS_TYPE_RC35Set_HC1, type); // to get the mode
|
||||||
} else if (hc == 2) {
|
} else if (hc == 2) {
|
||||||
ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC2, type); // to get the setpoint temp
|
ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC2, type); // to get the temps
|
||||||
ems_doReadCommand(EMS_TYPE_RC35Set_HC2, type); // to get the mode
|
ems_doReadCommand(EMS_TYPE_RC35Set_HC2, type); // to get the mode
|
||||||
}
|
}
|
||||||
} else if ((model_id == EMS_MODEL_EASY)) {
|
break;
|
||||||
ems_doReadCommand(EMS_TYPE_EasyStatusMessage, type);
|
case EMS_MODEL_RC300:
|
||||||
|
ems_doReadCommand(EMS_TYPE_RCPLUSStatusMessage, type);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ems_doReadCommand(EMS_TYPE_RCTime, type); // get Thermostat time
|
ems_doReadCommand(EMS_TYPE_RCTime, type); // get Thermostat time
|
||||||
@@ -1809,14 +1970,21 @@ void ems_getBoilerValues() {
|
|||||||
/*
|
/*
|
||||||
* Get other values from EMS devices
|
* Get other values from EMS devices
|
||||||
*/
|
*/
|
||||||
void ems_getOtherValues() {
|
void ems_getSolarModuleValues() {
|
||||||
if (EMS_Other.SM) {
|
uint8_t product_id = EMS_SolarModule.product_id;
|
||||||
|
|
||||||
|
if (ems_getSolarModuleEnabled()) {
|
||||||
|
if (product_id == EMS_PRODUCTID_SM10) {
|
||||||
ems_doReadCommand(EMS_TYPE_SM10Monitor, EMS_ID_SM); // fetch all from SM10Monitor
|
ems_doReadCommand(EMS_TYPE_SM10Monitor, EMS_ID_SM); // fetch all from SM10Monitor
|
||||||
|
} else if (product_id == EMS_PRODUCTID_SM100) {
|
||||||
|
ems_doReadCommand(EMS_TYPE_SM100Monitor, EMS_ID_SM); // fetch all from SM100Monitor
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns current thermostat type as a string
|
* returns current thermostat type as a string
|
||||||
|
* by looking up the product_id
|
||||||
*/
|
*/
|
||||||
char * ems_getThermostatDescription(char * buffer) {
|
char * ems_getThermostatDescription(char * buffer) {
|
||||||
uint8_t size = 128;
|
uint8_t size = 128;
|
||||||
@@ -1898,6 +2066,88 @@ char * ems_getBoilerDescription(char * buffer) {
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns current Solar Module type as a string
|
||||||
|
*/
|
||||||
|
char * ems_getSolarModuleDescription(char * buffer) {
|
||||||
|
uint8_t size = 128;
|
||||||
|
if (!ems_getSolarModuleEnabled()) {
|
||||||
|
strlcpy(buffer, "<not enabled>", size);
|
||||||
|
} else {
|
||||||
|
int i = 0;
|
||||||
|
bool found = false;
|
||||||
|
char tmp[6] = {0};
|
||||||
|
|
||||||
|
// scan through known ID types
|
||||||
|
while (i < _Solar_Module_Types_max) {
|
||||||
|
if (SolarModule_Types[i].product_id == EMS_SolarModule.product_id) {
|
||||||
|
found = true; // we have a match
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
strlcpy(buffer, SolarModule_Types[i].model_string, size);
|
||||||
|
} else {
|
||||||
|
strlcpy(buffer, "DeviceID: 0x", size);
|
||||||
|
strlcat(buffer, _hextoa(EMS_SolarModule.device_id, tmp), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcat(buffer, " (ProductID:", size);
|
||||||
|
if (EMS_SolarModule.product_id == EMS_ID_NONE) {
|
||||||
|
strlcat(buffer, "?", size);
|
||||||
|
} else {
|
||||||
|
strlcat(buffer, itoa(EMS_SolarModule.product_id, tmp, 10), size);
|
||||||
|
}
|
||||||
|
strlcat(buffer, " Version:", size);
|
||||||
|
strlcat(buffer, EMS_SolarModule.version, size);
|
||||||
|
strlcat(buffer, ")", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns current Heat Pump type as a string
|
||||||
|
*/
|
||||||
|
char * ems_getHeatPumpDescription(char * buffer) {
|
||||||
|
uint8_t size = 128;
|
||||||
|
if (!ems_getHeatPumpEnabled()) {
|
||||||
|
strlcpy(buffer, "<not enabled>", size);
|
||||||
|
} else {
|
||||||
|
int i = 0;
|
||||||
|
bool found = false;
|
||||||
|
char tmp[6] = {0};
|
||||||
|
|
||||||
|
// scan through known ID types
|
||||||
|
while (i < _HeatPump_Types_max) {
|
||||||
|
if (HeatPump_Types[i].product_id == EMS_HeatPump.product_id) {
|
||||||
|
found = true; // we have a match
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
strlcpy(buffer, HeatPump_Types[i].model_string, size);
|
||||||
|
} else {
|
||||||
|
strlcpy(buffer, "DeviceID: 0x", size);
|
||||||
|
strlcat(buffer, _hextoa(EMS_HeatPump.device_id, tmp), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcat(buffer, " (ProductID:", size);
|
||||||
|
if (EMS_HeatPump.product_id == EMS_ID_NONE) {
|
||||||
|
strlcat(buffer, "?", size);
|
||||||
|
} else {
|
||||||
|
strlcat(buffer, itoa(EMS_HeatPump.product_id, tmp, 10), size);
|
||||||
|
}
|
||||||
|
strlcat(buffer, " Version:", size);
|
||||||
|
strlcat(buffer, EMS_HeatPump.version, size);
|
||||||
|
strlcat(buffer, ")", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the versions of our connected devices
|
* Find the versions of our connected devices
|
||||||
*/
|
*/
|
||||||
@@ -1914,6 +2164,11 @@ void ems_scanDevices() {
|
|||||||
Device_Ids.push_back(tt.device_id);
|
Device_Ids.push_back(tt.device_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy over solar modules
|
||||||
|
for (_SolarModule_Type sm : SolarModule_Types) {
|
||||||
|
Device_Ids.push_back(sm.device_id);
|
||||||
|
}
|
||||||
|
|
||||||
// copy over others
|
// copy over others
|
||||||
for (_Other_Type ot : Other_Types) {
|
for (_Other_Type ot : Other_Types) {
|
||||||
Device_Ids.push_back(ot.device_id);
|
Device_Ids.push_back(ot.device_id);
|
||||||
@@ -1949,6 +2204,16 @@ void ems_printAllDevices() {
|
|||||||
Boiler_Types[i].product_id);
|
Boiler_Types[i].product_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myDebug_P(PSTR("\nThese %d devices are supported as solar module devices:"), _Solar_Module_Types_max);
|
||||||
|
for (i = 0; i < _Solar_Module_Types_max; i++) {
|
||||||
|
myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"),
|
||||||
|
COLOR_BOLD_ON,
|
||||||
|
SolarModule_Types[i].model_string,
|
||||||
|
COLOR_BOLD_OFF,
|
||||||
|
SolarModule_Types[i].device_id,
|
||||||
|
SolarModule_Types[i].product_id);
|
||||||
|
}
|
||||||
|
|
||||||
myDebug_P(PSTR("\nThese %d devices are supported as other known EMS devices:"), _Other_Types_max);
|
myDebug_P(PSTR("\nThese %d devices are supported as other known EMS devices:"), _Other_Types_max);
|
||||||
for (i = 0; i < _Other_Types_max; i++) {
|
for (i = 0; i < _Other_Types_max; i++) {
|
||||||
myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"),
|
myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"),
|
||||||
@@ -2004,6 +2269,23 @@ void ems_printDevices() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prints the device list to a string for html parsing
|
||||||
|
*/
|
||||||
|
uint8_t ems_printDevices_s(char * buffer, uint16_t len) {
|
||||||
|
if (Devices.size() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char s[100];
|
||||||
|
for (std::list<_Generic_Type>::iterator it = Devices.begin(); it != Devices.end(); it++) {
|
||||||
|
sprintf(s, "%s (DeviceID:0x%02X ProductID:%d Version:%s)<br>", (it)->model_string, (it)->device_id, (it)->product_id, (it)->version);
|
||||||
|
strlcat(buffer, s, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Devices.size();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a command to UART Tx to Read from another device
|
* Send a command to UART Tx to Read from another device
|
||||||
* Read commands when sent must respond by the destination (target) immediately (or within 10ms)
|
* Read commands when sent must respond by the destination (target) immediately (or within 10ms)
|
||||||
@@ -2039,14 +2321,14 @@ void ems_doReadCommand(uint16_t type, uint8_t dest, bool forceRefresh) {
|
|||||||
EMS_TxTelegram.action = EMS_TX_TELEGRAM_READ; // read command
|
EMS_TxTelegram.action = EMS_TX_TELEGRAM_READ; // read command
|
||||||
EMS_TxTelegram.dest = dest; // 8th bit will be set to indicate a read
|
EMS_TxTelegram.dest = dest; // 8th bit will be set to indicate a read
|
||||||
EMS_TxTelegram.offset = 0; // 0 for all data
|
EMS_TxTelegram.offset = 0; // 0 for all data
|
||||||
EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; // is always 6 bytes long (including CRC at end)
|
|
||||||
EMS_TxTelegram.type = type;
|
EMS_TxTelegram.type = type;
|
||||||
|
EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; // EMS 1.0: 6 bytes long (including CRC at end), EMS+ will add 2 bytes. includes CRC
|
||||||
EMS_TxTelegram.dataValue = EMS_MAX_TELEGRAM_LENGTH; // for a read this is the # bytes we want back
|
EMS_TxTelegram.dataValue = EMS_MAX_TELEGRAM_LENGTH; // for a read this is the # bytes we want back
|
||||||
EMS_TxTelegram.type_validate = EMS_ID_NONE;
|
EMS_TxTelegram.type_validate = EMS_ID_NONE;
|
||||||
EMS_TxTelegram.comparisonValue = 0;
|
EMS_TxTelegram.comparisonValue = 0;
|
||||||
EMS_TxTelegram.comparisonOffset = 0;
|
EMS_TxTelegram.comparisonOffset = 0;
|
||||||
EMS_TxTelegram.comparisonPostRead = EMS_ID_NONE;
|
EMS_TxTelegram.comparisonPostRead = EMS_ID_NONE;
|
||||||
EMS_TxTelegram.forceRefresh = forceRefresh; // should we send to MQTT after a successful read?
|
EMS_TxTelegram.forceRefresh = forceRefresh; // send to MQTT after a successful read
|
||||||
|
|
||||||
EMS_TxQueue.push(EMS_TxTelegram);
|
EMS_TxQueue.push(EMS_TxTelegram);
|
||||||
}
|
}
|
||||||
@@ -2075,7 +2357,7 @@ void ems_sendRawTelegram(char * telegram) {
|
|||||||
}
|
}
|
||||||
// and interate until end
|
// and interate until end
|
||||||
while (p != 0) {
|
while (p != 0) {
|
||||||
if ((p = strtok(NULL, " ,"))) {
|
if ((p = strtok(nullptr, " ,"))) {
|
||||||
strlcpy(value, p, sizeof(value));
|
strlcpy(value, p, sizeof(value));
|
||||||
uint8_t val = (uint8_t)strtol(value, 0, 16);
|
uint8_t val = (uint8_t)strtol(value, 0, 16);
|
||||||
EMS_TxTelegram.data[++count] = val;
|
EMS_TxTelegram.data[++count] = val;
|
||||||
@@ -2454,7 +2736,7 @@ void ems_testTelegram(uint8_t test_num) {
|
|||||||
|
|
||||||
// and interate until end
|
// and interate until end
|
||||||
while (p != 0) {
|
while (p != 0) {
|
||||||
if ((p = strtok(NULL, " ,"))) {
|
if ((p = strtok(nullptr, " ,"))) {
|
||||||
strlcpy(value, p, sizeof(value));
|
strlcpy(value, p, sizeof(value));
|
||||||
uint8_t val = (uint8_t)strtol(value, 0, 16);
|
uint8_t val = (uint8_t)strtol(value, 0, 16);
|
||||||
telegram[++length] = val;
|
telegram[++length] = val;
|
||||||
@@ -2469,6 +2751,6 @@ void ems_testTelegram(uint8_t test_num) {
|
|||||||
// go an parse it
|
// go an parse it
|
||||||
ems_parseTelegram(telegram, length + 1); // include CRC in length
|
ems_parseTelegram(telegram, length + 1); // include CRC in length
|
||||||
#else
|
#else
|
||||||
myDebug_P(PSTR("Firmware not compiled with test data set"));
|
myDebug_P(PSTR("Firmware not compiled with test data. Use -DTESTS"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
156
src/ems.h
156
src/ems.h
@@ -12,27 +12,90 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
/* debug helper for logic analyzer
|
||||||
|
* create marker puls on GPIOx
|
||||||
|
* ° for Rx, we use GPIO14
|
||||||
|
* ° for Tx, we use GPIO12
|
||||||
|
*/
|
||||||
|
// clang-format off
|
||||||
|
#ifdef LOGICANALYZER
|
||||||
|
#define RX_MARK_PIN 14
|
||||||
|
#define TX_MARK_PIN 12
|
||||||
|
|
||||||
|
#define RX_MARK_MASK (1 << RX_MARK_PIN)
|
||||||
|
#define TX_MARK_MASK (1 << TX_MARK_PIN)
|
||||||
|
#define MARKERS_MASK (RX_MARK_PIN | TX_MARK_PIN)
|
||||||
|
|
||||||
|
#define GPIO_H(mask) (GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, (mask)))
|
||||||
|
#define GPIO_L(mask) (GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, (mask)))
|
||||||
|
|
||||||
|
#define RX_PULSE(pulse) \
|
||||||
|
do { \
|
||||||
|
GPIO_H(RX_MARK_MASK); \
|
||||||
|
delayMicroseconds(pulse); \
|
||||||
|
GPIO_L(RX_MARK_MASK); \
|
||||||
|
} while (0)
|
||||||
|
#define TX_PULSE(pulse) \
|
||||||
|
do { \
|
||||||
|
GPIO_H(TX_MARK_MASK); \
|
||||||
|
delayMicroseconds(pulse); \
|
||||||
|
GPIO_L(TX_MARK_MASK); \
|
||||||
|
} while (0)
|
||||||
|
#define LA_PULSE(pulse) \
|
||||||
|
do { \
|
||||||
|
GPIO_H(MARKERS_MASK); \
|
||||||
|
delayMicroseconds(pulse); \
|
||||||
|
GPIO_L(MARKERS_MASK); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define INIT_MARKERS(void) \
|
||||||
|
do { \
|
||||||
|
pinMode(RX_MARK_PIN, OUTPUT); \
|
||||||
|
pinMode(TX_MARK_PIN, OUTPUT); \
|
||||||
|
GPIO_L(MARKERS_MASK); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define RX_PULSE(pulse) \
|
||||||
|
{}
|
||||||
|
#define TX_PULSE(pulse) \
|
||||||
|
{}
|
||||||
|
#define LA_PULSE(pulse) \
|
||||||
|
{}
|
||||||
|
#define INIT_MARKERS(void) \
|
||||||
|
{}
|
||||||
|
#define RX_MARK_MASK
|
||||||
|
#define TX_MARK_MASK
|
||||||
|
#define GPIO_H(mask)
|
||||||
|
#define GPIO_L(mask)
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
#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
|
||||||
#define EMS_ID_ME 0x0B // our device, hardcoded as the "Service Key"
|
#define EMS_ID_ME 0x0B // our device, hardcoded as the "Service Key"
|
||||||
#define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08
|
#define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08
|
||||||
#define EMS_ID_SM 0x30 // Solar Module SM10 and SM100
|
#define EMS_ID_SM 0x30 // Solar Module SM10, SM100 and ISM1
|
||||||
#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
|
#define EMS_PRODUCTID_HEATRONICS 95 // ProductID for a Junkers Heatronic3 device
|
||||||
|
|
||||||
|
#define EMS_PRODUCTID_SM10 73 // ProductID for SM10 solar module
|
||||||
|
#define EMS_PRODUCTID_SM100 163 // ProductID for SM10 solar module
|
||||||
|
#define EMS_PRODUCTID_ISM1 101 // ProductID for SM10 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
|
||||||
|
|
||||||
// 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
|
#define EMS_MAX_TELEGRAM_LENGTH 32
|
||||||
|
|
||||||
// default values
|
// default values for null values
|
||||||
#define EMS_VALUE_INT_ON 1 // boolean true
|
#define EMS_VALUE_INT_ON 1 // boolean true
|
||||||
#define EMS_VALUE_INT_OFF 0 // boolean false
|
#define EMS_VALUE_INT_OFF 0 // boolean false
|
||||||
#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit ints
|
#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit unsigned ints/bytes
|
||||||
#define EMS_VALUE_SHORT_NOTSET 0x8000 // for 2-byte signed shorts
|
#define EMS_VALUE_SHORT_NOTSET -32768 // for 2-byte signed shorts
|
||||||
|
#define EMS_VALUE_USHORT_NOTSET 0x8000 // for 2-byte unsigned shorts
|
||||||
#define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs
|
#define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs
|
||||||
|
|
||||||
#define EMS_THERMOSTAT_WRITE_YES true
|
#define EMS_THERMOSTAT_WRITE_YES true
|
||||||
@@ -57,8 +120,11 @@ typedef enum {
|
|||||||
} _EMS_RX_STATUS;
|
} _EMS_RX_STATUS;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
EMS_TX_STATUS_OK,
|
||||||
EMS_TX_STATUS_IDLE, // ready
|
EMS_TX_STATUS_IDLE, // ready
|
||||||
EMS_TX_STATUS_WAIT // waiting for response from last Tx
|
EMS_TX_STATUS_WAIT, // waiting for response from last Tx
|
||||||
|
EMS_TX_WTD_TIMEOUT, // watchdog timeout during send
|
||||||
|
EMS_TX_BRK_DETECT // incoming BRK during Tx
|
||||||
} _EMS_TX_STATUS;
|
} _EMS_TX_STATUS;
|
||||||
|
|
||||||
#define EMS_TX_SUCCESS 0x01 // EMS single byte after a Tx Write indicating a success
|
#define EMS_TX_SUCCESS 0x01 // EMS single byte after a Tx Write indicating a success
|
||||||
@@ -78,6 +144,7 @@ typedef enum {
|
|||||||
EMS_SYS_LOGGING_RAW, // raw data mode
|
EMS_SYS_LOGGING_RAW, // raw data mode
|
||||||
EMS_SYS_LOGGING_BASIC, // only basic read/write messages
|
EMS_SYS_LOGGING_BASIC, // only basic read/write messages
|
||||||
EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat
|
EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat
|
||||||
|
EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from thermostat
|
||||||
EMS_SYS_LOGGING_VERBOSE // everything
|
EMS_SYS_LOGGING_VERBOSE // everything
|
||||||
} _EMS_SYS_LOGGING;
|
} _EMS_SYS_LOGGING;
|
||||||
|
|
||||||
@@ -98,6 +165,7 @@ typedef struct {
|
|||||||
bool emsTxDisabled; // true to prevent all Tx
|
bool emsTxDisabled; // true to prevent all Tx
|
||||||
uint8_t txRetryCount; // # times the last Tx was re-sent
|
uint8_t txRetryCount; // # times the last Tx was re-sent
|
||||||
bool emsReverse; // if true, poll logic is reversed
|
bool emsReverse; // if true, poll logic is reversed
|
||||||
|
uint8_t emsTxMode; // handles Tx logic
|
||||||
} _EMS_Sys_Status;
|
} _EMS_Sys_Status;
|
||||||
|
|
||||||
// The Tx send package
|
// The Tx send package
|
||||||
@@ -148,20 +216,30 @@ const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = {
|
|||||||
{0x00} // data
|
{0x00} // data
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// where defintions are stored
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t model_id;
|
|
||||||
uint8_t product_id;
|
uint8_t product_id;
|
||||||
char model_string[50];
|
char model_string[50];
|
||||||
} _Boiler_Type;
|
} _Boiler_Type;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t model_id;
|
uint8_t product_id;
|
||||||
|
uint8_t device_id;
|
||||||
|
char model_string[50];
|
||||||
|
} _SolarModule_Type;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
uint8_t product_id;
|
uint8_t product_id;
|
||||||
uint8_t device_id;
|
uint8_t device_id;
|
||||||
char model_string[50];
|
char model_string[50];
|
||||||
} _Other_Type;
|
} _Other_Type;
|
||||||
|
|
||||||
// Definition for thermostat devices
|
typedef struct {
|
||||||
|
uint8_t product_id;
|
||||||
|
uint8_t device_id;
|
||||||
|
char model_string[50];
|
||||||
|
} _HeatPump_Type;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t model_id;
|
uint8_t model_id;
|
||||||
uint8_t product_id;
|
uint8_t product_id;
|
||||||
@@ -170,6 +248,7 @@ typedef struct {
|
|||||||
bool write_supported;
|
bool write_supported;
|
||||||
} _Thermostat_Type;
|
} _Thermostat_Type;
|
||||||
|
|
||||||
|
// for consolidating all types
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t product_id;
|
uint8_t product_id;
|
||||||
uint8_t device_id;
|
uint8_t device_id;
|
||||||
@@ -189,8 +268,8 @@ typedef struct { // UBAParameterWW
|
|||||||
|
|
||||||
// UBAMonitorFast
|
// UBAMonitorFast
|
||||||
uint8_t selFlowTemp; // Selected flow temperature
|
uint8_t selFlowTemp; // Selected flow temperature
|
||||||
int16_t curFlowTemp; // Current flow temperature
|
uint16_t curFlowTemp; // Current flow temperature
|
||||||
int16_t retTemp; // Return temperature
|
uint16_t retTemp; // Return temperature
|
||||||
uint8_t burnGas; // Gas on/off
|
uint8_t burnGas; // Gas on/off
|
||||||
uint8_t fanWork; // Fan on/off
|
uint8_t fanWork; // Fan on/off
|
||||||
uint8_t ignWork; // Ignition on/off
|
uint8_t ignWork; // Ignition on/off
|
||||||
@@ -206,14 +285,14 @@ typedef struct { // UBAParameterWW
|
|||||||
|
|
||||||
// UBAMonitorSlow
|
// UBAMonitorSlow
|
||||||
int16_t extTemp; // Outside temperature
|
int16_t extTemp; // Outside temperature
|
||||||
int16_t boilTemp; // Boiler temperature
|
uint16_t boilTemp; // Boiler temperature
|
||||||
uint8_t pumpMod; // Pump modulation
|
uint8_t pumpMod; // Pump modulation
|
||||||
uint32_t burnStarts; // # burner starts
|
uint32_t burnStarts; // # burner starts
|
||||||
uint32_t burnWorkMin; // Total burner operating time
|
uint32_t burnWorkMin; // Total burner operating time
|
||||||
uint32_t heatWorkMin; // Total heat operating time
|
uint32_t heatWorkMin; // Total heat operating time
|
||||||
|
|
||||||
// UBAMonitorWWMessage
|
// UBAMonitorWWMessage
|
||||||
int16_t wWCurTmp; // Warm Water current temperature:
|
uint16_t wWCurTmp; // Warm Water current temperature
|
||||||
uint32_t wWStarts; // Warm Water # starts
|
uint32_t wWStarts; // Warm Water # starts
|
||||||
uint32_t wWWorkM; // Warm Water # minutes
|
uint32_t wWWorkM; // Warm Water # minutes
|
||||||
uint8_t wWOneTime; // Warm Water one time function on/off
|
uint8_t wWOneTime; // Warm Water one time function on/off
|
||||||
@@ -241,21 +320,39 @@ typedef struct { // UBAParameterWW
|
|||||||
* Telegram package defintions for Other EMS devices
|
* Telegram package defintions for Other EMS devices
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// SM Solar Module - SM10Monitor/SM100Monitor
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool SM; // set true if there is a Solar Module available
|
|
||||||
bool HP; // set true if there is a Heat Pump available
|
|
||||||
int16_t SMcollectorTemp; // collector temp
|
|
||||||
int16_t SMbottomTemp; // bottom temp
|
|
||||||
uint8_t SMpumpModulation; // modulation solar pump
|
|
||||||
uint8_t SMpump; // pump active
|
|
||||||
int16_t SMEnergyLastHour;
|
|
||||||
int16_t SMEnergyToday;
|
|
||||||
int16_t SMEnergyTotal;
|
|
||||||
uint8_t HPModulation; // heatpump modulation in %
|
uint8_t HPModulation; // heatpump modulation in %
|
||||||
uint8_t HPSpeed; // speed 0-100 %
|
uint8_t HPSpeed; // speed 0-100 %
|
||||||
|
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 product_id;
|
||||||
|
char version[10];
|
||||||
|
} _EMS_HeatPump;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t device_id;
|
||||||
|
uint8_t model_id;
|
||||||
|
uint8_t product_id;
|
||||||
|
char version[10];
|
||||||
} _EMS_Other;
|
} _EMS_Other;
|
||||||
|
|
||||||
|
// SM Solar Module - SM10/SM100/ISM1
|
||||||
|
typedef struct {
|
||||||
|
int16_t collectorTemp; // collector temp
|
||||||
|
int16_t bottomTemp; // bottom temp
|
||||||
|
uint8_t pumpModulation; // modulation solar pump
|
||||||
|
uint8_t pump; // pump active
|
||||||
|
int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp
|
||||||
|
uint16_t EnergyLastHour;
|
||||||
|
uint16_t EnergyToday;
|
||||||
|
uint16_t EnergyTotal;
|
||||||
|
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;
|
||||||
|
|
||||||
// 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
|
||||||
@@ -300,11 +397,13 @@ void ems_sendRawTelegram(char * telegram);
|
|||||||
void ems_scanDevices();
|
void ems_scanDevices();
|
||||||
void ems_printAllDevices();
|
void ems_printAllDevices();
|
||||||
void ems_printDevices();
|
void ems_printDevices();
|
||||||
|
uint8_t ems_printDevices_s(char * buffer, uint16_t len);
|
||||||
void ems_printTxQueue();
|
void ems_printTxQueue();
|
||||||
void ems_testTelegram(uint8_t test_num);
|
void ems_testTelegram(uint8_t test_num);
|
||||||
void ems_startupTelegrams();
|
void ems_startupTelegrams();
|
||||||
bool ems_checkEMSBUSAlive();
|
bool ems_checkEMSBUSAlive();
|
||||||
void ems_clearDeviceList();
|
void ems_clearDeviceList();
|
||||||
|
void ems_setTxMode(uint8_t mode);
|
||||||
|
|
||||||
void ems_setThermostatTemp(float temperature, uint8_t temptype = 0);
|
void ems_setThermostatTemp(float temperature, uint8_t temptype = 0);
|
||||||
void ems_setThermostatMode(uint8_t mode);
|
void ems_setThermostatMode(uint8_t mode);
|
||||||
@@ -319,20 +418,27 @@ 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();
|
||||||
|
uint8_t ems_getTxMode();
|
||||||
|
|
||||||
char * ems_getThermostatDescription(char * buffer);
|
char * ems_getThermostatDescription(char * buffer);
|
||||||
char * ems_getBoilerDescription(char * buffer);
|
char * ems_getBoilerDescription(char * buffer);
|
||||||
|
char * ems_getSolarModuleDescription(char * buffer);
|
||||||
|
char * ems_getHeatPumpDescription(char * buffer);
|
||||||
void ems_getThermostatValues();
|
void ems_getThermostatValues();
|
||||||
void ems_getBoilerValues();
|
void ems_getBoilerValues();
|
||||||
void ems_getOtherValues();
|
void ems_getSolarModuleValues();
|
||||||
bool ems_getPoll();
|
bool ems_getPoll();
|
||||||
bool ems_getTxEnabled();
|
bool ems_getTxEnabled();
|
||||||
bool ems_getThermostatEnabled();
|
bool ems_getThermostatEnabled();
|
||||||
bool ems_getBoilerEnabled();
|
bool ems_getBoilerEnabled();
|
||||||
|
bool ems_getSolarModuleEnabled();
|
||||||
|
bool ems_getHeatPumpEnabled();
|
||||||
bool ems_getBusConnected();
|
bool ems_getBusConnected();
|
||||||
_EMS_SYS_LOGGING ems_getLogging();
|
_EMS_SYS_LOGGING ems_getLogging();
|
||||||
bool ems_getEmsRefreshed();
|
bool ems_getEmsRefreshed();
|
||||||
uint8_t ems_getThermostatModel();
|
uint8_t ems_getThermostatModel();
|
||||||
|
uint8_t ems_getSolarModuleModel();
|
||||||
void ems_discoverModels();
|
void ems_discoverModels();
|
||||||
bool ems_getTxCapable();
|
bool ems_getTxCapable();
|
||||||
uint32_t ems_getPollFrequency();
|
uint32_t ems_getPollFrequency();
|
||||||
@@ -342,12 +448,12 @@ uint8_t _crcCalculator(uint8_t * data, uint8_t len);
|
|||||||
void _processType(_EMS_RxTelegram * EMS_RxTelegram);
|
void _processType(_EMS_RxTelegram * EMS_RxTelegram);
|
||||||
void _debugPrintPackage(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram, const char * color);
|
void _debugPrintPackage(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram, const char * color);
|
||||||
void _ems_clearTxData();
|
void _ems_clearTxData();
|
||||||
int _ems_findBoilerModel(uint8_t model_id);
|
|
||||||
bool _ems_setModel(uint8_t model_id);
|
|
||||||
void _removeTxQueue();
|
void _removeTxQueue();
|
||||||
|
|
||||||
// global so can referenced in other classes
|
// global so can referenced in other classes
|
||||||
extern _EMS_Sys_Status EMS_Sys_Status;
|
extern _EMS_Sys_Status EMS_Sys_Status;
|
||||||
extern _EMS_Boiler EMS_Boiler;
|
extern _EMS_Boiler EMS_Boiler;
|
||||||
extern _EMS_Thermostat EMS_Thermostat;
|
extern _EMS_Thermostat EMS_Thermostat;
|
||||||
|
extern _EMS_SolarModule EMS_SolarModule;
|
||||||
|
extern _EMS_HeatPump EMS_HeatPump;
|
||||||
extern _EMS_Other EMS_Other;
|
extern _EMS_Other EMS_Other;
|
||||||
|
|||||||
@@ -48,7 +48,10 @@
|
|||||||
#define EMS_TYPE_SM100Energy 0x028E // SM100Energy
|
#define EMS_TYPE_SM100Energy 0x028E // SM100Energy
|
||||||
#define EMS_TYPE_HPMonitor1 0xE3 // HeatPump Monitor 1
|
#define EMS_TYPE_HPMonitor1 0xE3 // HeatPump Monitor 1
|
||||||
#define EMS_TYPE_HPMonitor2 0xE5 // HeatPump Monitor 2
|
#define EMS_TYPE_HPMonitor2 0xE5 // HeatPump Monitor 2
|
||||||
|
|
||||||
#define EMS_TYPE_ISM1StatusMessage 0x0003 // Solar Module Junkers ISM1 Status
|
#define EMS_TYPE_ISM1StatusMessage 0x0003 // Solar Module Junkers ISM1 Status
|
||||||
|
#define EMS_TYPE_ISM1Set 0x0001 // for setting values of the solar module like max boiler temp
|
||||||
|
#define EMS_OFFSET_ISM1Set_MaxBoilerTemp 6 // position of max boiler temp e.g. 50 in the following example: 90 30 FF 06 00 01 50 (CRC=2C)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Thermostats...
|
* Thermostats...
|
||||||
@@ -63,7 +66,7 @@
|
|||||||
#define EMS_TYPE_RC10Set 0xB0 // for setting values like temp and mode
|
#define EMS_TYPE_RC10Set 0xB0 // for setting values like temp and mode
|
||||||
#define EMS_OFFSET_RC10Set_temp 4 // position of thermostat setpoint temperature
|
#define EMS_OFFSET_RC10Set_temp 4 // position of thermostat setpoint temperature
|
||||||
#define EMS_OFFSET_RC10StatusMessage_setpoint 1 // setpoint temp
|
#define EMS_OFFSET_RC10StatusMessage_setpoint 1 // setpoint temp
|
||||||
#define EMS_OFFSET_RC10StatusMessage_curr 3 // current temp
|
#define EMS_OFFSET_RC10StatusMessage_curr 2 // current temp
|
||||||
|
|
||||||
// RC20 specific
|
// RC20 specific
|
||||||
#define EMS_TYPE_RC20StatusMessage 0x91 // is an automatic thermostat broadcast giving us temps
|
#define EMS_TYPE_RC20StatusMessage 0x91 // is an automatic thermostat broadcast giving us temps
|
||||||
@@ -109,6 +112,7 @@
|
|||||||
#define EMS_OFFSET_RCPLUSStatusMessage_setpoint 3 // setpoint temp
|
#define EMS_OFFSET_RCPLUSStatusMessage_setpoint 3 // setpoint temp
|
||||||
#define EMS_OFFSET_RCPLUSStatusMessage_curr 0 // current temp
|
#define EMS_OFFSET_RCPLUSStatusMessage_curr 0 // current temp
|
||||||
#define EMS_OFFSET_RCPLUSGet_mode_day 8 // day/night mode
|
#define EMS_OFFSET_RCPLUSGet_mode_day 8 // day/night mode
|
||||||
|
#define EMS_OFFSET_RCPLUSStatusMessage_mode 0x0A // thermostat mode (auto, manual)
|
||||||
|
|
||||||
// Junkers FR10, FW100 (EMS Plus)
|
// Junkers FR10, FW100 (EMS Plus)
|
||||||
#define EMS_TYPE_JunkersStatusMessage 0x6F // is an automatic thermostat broadcast giving us temps
|
#define EMS_TYPE_JunkersStatusMessage 0x6F // is an automatic thermostat broadcast giving us temps
|
||||||
@@ -118,16 +122,19 @@
|
|||||||
|
|
||||||
// Known EMS types
|
// Known EMS types
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EMS_MODEL_NONE,
|
EMS_MODEL_NONE, // unset
|
||||||
EMS_MODEL_ALL, // common for all devices
|
EMS_MODEL_ALL, // common for all devices
|
||||||
|
|
||||||
// generic ID for the boiler
|
// heatpump
|
||||||
|
EMS_MODEL_HP,
|
||||||
|
|
||||||
|
// solar module
|
||||||
|
EMS_MODEL_SM,
|
||||||
|
|
||||||
|
// boiler
|
||||||
EMS_MODEL_UBA,
|
EMS_MODEL_UBA,
|
||||||
|
|
||||||
// generic ID for all the other weird devices
|
// and the thermostats
|
||||||
EMS_MODEL_OTHER,
|
|
||||||
|
|
||||||
// and finally the thermostats
|
|
||||||
EMS_MODEL_ES73,
|
EMS_MODEL_ES73,
|
||||||
EMS_MODEL_RC10,
|
EMS_MODEL_RC10,
|
||||||
EMS_MODEL_RC20,
|
EMS_MODEL_RC20,
|
||||||
@@ -135,7 +142,7 @@ typedef enum {
|
|||||||
EMS_MODEL_RC30,
|
EMS_MODEL_RC30,
|
||||||
EMS_MODEL_RC35,
|
EMS_MODEL_RC35,
|
||||||
EMS_MODEL_EASY,
|
EMS_MODEL_EASY,
|
||||||
EMS_MODEL_RC310,
|
EMS_MODEL_RC300,
|
||||||
EMS_MODEL_CW100,
|
EMS_MODEL_CW100,
|
||||||
EMS_MODEL_1010,
|
EMS_MODEL_1010,
|
||||||
EMS_MODEL_OT,
|
EMS_MODEL_OT,
|
||||||
@@ -147,56 +154,71 @@ typedef enum {
|
|||||||
|
|
||||||
} _EMS_MODEL_ID;
|
} _EMS_MODEL_ID;
|
||||||
|
|
||||||
// EMS types for known devices. This list will be extended when new devices are recognized.
|
// EMS types for known boilers. This list will be extended when new devices are recognized.
|
||||||
// The device_id is always 0x08
|
// The device_id is always 0x08
|
||||||
// format is MODEL_ID, PRODUCT ID, DESCRIPTION
|
// format is PRODUCT ID, DESCRIPTION
|
||||||
const _Boiler_Type Boiler_Types[] = {
|
const _Boiler_Type Boiler_Types[] = {
|
||||||
|
|
||||||
{EMS_MODEL_UBA, 72, "MC10 Module"},
|
{72, "MC10 Module"},
|
||||||
{EMS_MODEL_UBA, 123, "Buderus GB172/Nefit Trendline/Junkers Cerapur"},
|
{123, "Buderus GB172/Nefit Trendline/Junkers Cerapur"},
|
||||||
{EMS_MODEL_UBA, 115, "Nefit Topline Compact/Buderus GB162"},
|
{115, "Nefit Topline Compact/Buderus GB162"},
|
||||||
{EMS_MODEL_UBA, 203, "Buderus Logamax U122/Junkers Cerapur"},
|
{203, "Buderus Logamax U122/Junkers Cerapur"},
|
||||||
{EMS_MODEL_UBA, 208, "Buderus Logamax plus/GB192"},
|
{208, "Buderus Logamax plus/GB192"},
|
||||||
{EMS_MODEL_UBA, 64, "Sieger BK15/Nefit Smartline/Buderus GB152"},
|
{64, "Sieger BK15/Nefit Smartline/Buderus GB152"},
|
||||||
{EMS_MODEL_UBA, EMS_PRODUCTID_HEATRONICS, "Bosch Condens 2500/Junkers Heatronics3"}, // Junkers
|
{EMS_PRODUCTID_HEATRONICS, "Bosch Condens 2500/Junkers Heatronics3"},
|
||||||
{EMS_MODEL_UBA, 122, "Nefit Proline"},
|
{122, "Nefit Proline"},
|
||||||
{EMS_MODEL_UBA, 172, "Nefit Enviline"}
|
{172, "Nefit Enviline"}
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Other EMS devices which are not considered boilers or thermostats
|
|
||||||
const _Other_Type Other_Types[] = {
|
|
||||||
|
|
||||||
{EMS_MODEL_OTHER, 69, 0x21, "MM10 Mixer Module"},
|
|
||||||
{EMS_MODEL_OTHER, 71, 0x11, "WM10 Switch Module"},
|
|
||||||
{EMS_MODEL_OTHER, 160, 0x20, "MM100 Mixing Module"},
|
|
||||||
{EMS_MODEL_OTHER, 160, 0x21, "MM100 Mixing Module"},
|
|
||||||
{EMS_MODEL_OTHER, 159, 0x21, "MM50 Mixing Module"},
|
|
||||||
{EMS_MODEL_OTHER, 68, 0x09, "BC10/RFM20 Receiver"},
|
|
||||||
{EMS_MODEL_OTHER, 190, 0x09, "BC10 Base Controller"},
|
|
||||||
{EMS_MODEL_OTHER, 114, 0x09, "BC10 Base Controller"},
|
|
||||||
{EMS_MODEL_OTHER, 125, 0x09, "BC25 Base Controller"},
|
|
||||||
{EMS_MODEL_OTHER, 152, 0x09, "Junkers Controller"},
|
|
||||||
{EMS_MODEL_OTHER, 205, 0x02, "Nefit Moduline Easy Connect"},
|
|
||||||
{EMS_MODEL_OTHER, 73, EMS_ID_SM, "SM10 Solar Module"},
|
|
||||||
{EMS_MODEL_OTHER, 163, EMS_ID_SM, "SM100 Solar Module"},
|
|
||||||
{EMS_MODEL_OTHER, 171, 0x02, "EMS-OT OpenTherm converter"},
|
|
||||||
{EMS_MODEL_OTHER, 252, EMS_ID_HP, "HeatPump Module"}, // warning, fake product id!
|
|
||||||
{EMS_MODEL_OTHER, 101, 0x30, "Junkers ISM1 Solar Controller"},
|
|
||||||
{EMS_MODEL_OTHER, 189, EMS_ID_GATEWAY, "Web Gateway KM200"}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Known Solar Module types
|
||||||
|
* format is PRODUCT ID, DEVICE ID, DESCRIPTION
|
||||||
|
*/
|
||||||
|
const _SolarModule_Type SolarModule_Types[] = {
|
||||||
|
|
||||||
|
{EMS_PRODUCTID_SM10, EMS_ID_SM, "SM10 Solar Module"},
|
||||||
|
{EMS_PRODUCTID_SM100, EMS_ID_SM, "SM100 Solar Module"},
|
||||||
|
{EMS_PRODUCTID_ISM1, EMS_ID_SM, "Junkers ISM1 Solar Module"}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Other EMS devices which are not considered boilers, thermostats or solar modules
|
||||||
|
// format is PRODUCT ID, DEVICE ID, DESCRIPTION
|
||||||
|
const _Other_Type Other_Types[] = {
|
||||||
|
|
||||||
|
{69, 0x21, "MM10 Mixer Module"},
|
||||||
|
{71, 0x11, "WM10 Switch Module"},
|
||||||
|
{160, 0x20, "MM100 Mixing Module"},
|
||||||
|
{160, 0x21, "MM100 Mixing Module"},
|
||||||
|
{159, 0x21, "MM50 Mixing Module"},
|
||||||
|
{68, 0x09, "BC10/RFM20 Receiver"},
|
||||||
|
{190, 0x09, "BC10 Base Controller"},
|
||||||
|
{114, 0x09, "BC10 Base Controller"},
|
||||||
|
{125, 0x09, "BC25 Base Controller"},
|
||||||
|
{152, 0x09, "Junkers Controller"},
|
||||||
|
{205, 0x02, "Nefit Moduline Easy Connect"},
|
||||||
|
{206, 0x02, "Bosch Easy Connect"},
|
||||||
|
{171, 0x02, "EMS-OT OpenTherm converter"},
|
||||||
|
{252, EMS_ID_HP, "HeatPump Module"},
|
||||||
|
{189, EMS_ID_GATEWAY, "Web Gateway KM200"}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// heatpump
|
||||||
|
// format is PRODUCT ID, DEVICE ID, DESCRIPTION
|
||||||
|
const _HeatPump_Type HeatPump_Types[] = {{252, EMS_ID_HP, "HeatPump Module"}};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Known thermostat types and their capabilities
|
* Known thermostat types and their capabilities
|
||||||
|
* format is MODEL_ID, PRODUCT ID, DEVICE ID, DESCRIPTION
|
||||||
*/
|
*/
|
||||||
const _Thermostat_Type Thermostat_Types[] = {
|
const _Thermostat_Type Thermostat_Types[] = {
|
||||||
|
|
||||||
// Easy devices - not currently supporting write operations
|
// Easy devices - not currently supporting write operations
|
||||||
{EMS_MODEL_EASY, 202, 0x18, "TC100/Nefit Easy", EMS_THERMOSTAT_WRITE_NO},
|
{EMS_MODEL_EASY, 202, 0x18, "Logamatic TC100/Nefit Moduline Easy", EMS_THERMOSTAT_WRITE_NO},
|
||||||
{EMS_MODEL_EASY, 203, 0x18, "Bosch EasyControl CT200", EMS_THERMOSTAT_WRITE_NO},
|
{EMS_MODEL_EASY, 203, 0x18, "Bosch EasyControl CT200", EMS_THERMOSTAT_WRITE_NO},
|
||||||
{EMS_MODEL_EASY, 206, 0x02, "Bosch Easy", EMS_THERMOSTAT_WRITE_NO},
|
{EMS_MODEL_CW100, 157, 0x18, "Bosch CW100", EMS_THERMOSTAT_WRITE_NO},
|
||||||
{EMS_MODEL_CW100, 157, 0x18, "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/Nefit Moduline 100", EMS_THERMOSTAT_WRITE_YES},
|
||||||
@@ -204,7 +226,7 @@ const _Thermostat_Type Thermostat_Types[] = {
|
|||||||
{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/Nefit 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_RC310, 158, 0x10, "RC3x0/Nefit Moduline 1010H", EMS_THERMOSTAT_WRITE_NO},
|
{EMS_MODEL_RC300, 158, 0x10, "RC300/RC310/Nefit Moduline 3000", EMS_THERMOSTAT_WRITE_NO},
|
||||||
{EMS_MODEL_1010, 165, 0x18, "Nefit Moduline 1010", EMS_THERMOSTAT_WRITE_NO},
|
{EMS_MODEL_1010, 165, 0x18, "Nefit Moduline 1010", EMS_THERMOSTAT_WRITE_NO},
|
||||||
|
|
||||||
// Sieger
|
// Sieger
|
||||||
@@ -217,5 +239,4 @@ const _Thermostat_Type Thermostat_Types[] = {
|
|||||||
{EMS_MODEL_FR110, 108, 0x18, "Junkers FR110", EMS_THERMOSTAT_WRITE_NO},
|
{EMS_MODEL_FR110, 108, 0x18, "Junkers FR110", EMS_THERMOSTAT_WRITE_NO},
|
||||||
{EMS_MODEL_FW120, 192, 0x10, "Junkers FW120", EMS_THERMOSTAT_WRITE_NO}
|
{EMS_MODEL_FW120, 192, 0x10, "Junkers FW120", EMS_THERMOSTAT_WRITE_NO}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
163
src/emsuart.cpp
163
src/emsuart.cpp
@@ -29,7 +29,7 @@ static void emsuart_rx_intr_handler(void * para) {
|
|||||||
EMS_Sys_Status.emsRxStatus = EMS_RX_STATUS_BUSY; // status set to busy
|
EMS_Sys_Status.emsRxStatus = EMS_RX_STATUS_BUSY; // status set to busy
|
||||||
length = 0;
|
length = 0;
|
||||||
}
|
}
|
||||||
|
GPIO_H(RX_MARK_MASK);
|
||||||
// fill IRQ buffer, by emptying Rx FIFO
|
// fill IRQ buffer, by emptying Rx FIFO
|
||||||
if (USIS(EMSUART_UART) & ((1 << UIFF) | (1 << UITO) | (1 << UIBD))) {
|
if (USIS(EMSUART_UART) & ((1 << UIFF) | (1 << UITO) | (1 << UIBD))) {
|
||||||
while ((USS(EMSUART_UART) >> USRXC) & 0xFF) {
|
while ((USS(EMSUART_UART) >> USRXC) & 0xFF) {
|
||||||
@@ -39,20 +39,20 @@ static void emsuart_rx_intr_handler(void * para) {
|
|||||||
// clear Rx FIFO full and Rx FIFO timeout interrupts
|
// clear Rx FIFO full and Rx FIFO timeout interrupts
|
||||||
USIC(EMSUART_UART) = (1 << UIFF) | (1 << UITO);
|
USIC(EMSUART_UART) = (1 << UIFF) | (1 << UITO);
|
||||||
}
|
}
|
||||||
|
GPIO_L(RX_MARK_MASK);
|
||||||
|
|
||||||
// BREAK detection = End of EMS data block
|
// BREAK detection = End of EMS data block
|
||||||
if (USIS(EMSUART_UART) & ((1 << UIBD))) {
|
if (USIS(EMSUART_UART) & ((1 << UIBD))) {
|
||||||
ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them
|
ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them
|
||||||
|
|
||||||
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
|
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
|
||||||
|
|
||||||
pEMSRxBuf->length = length;
|
pEMSRxBuf->length = length;
|
||||||
os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, length); // copy data into transfer buffer, including the BRK 0x00 at the end
|
os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, length); // copy data into transfer buffer, including the BRK 0x00 at the end
|
||||||
EMS_Sys_Status.emsRxStatus = EMS_RX_STATUS_IDLE; // set the status flag stating BRK has been received and we can start a new package
|
EMS_Sys_Status.emsRxStatus = EMS_RX_STATUS_IDLE; // set the status flag stating BRK has been received and we can start a new package
|
||||||
|
ETS_UART_INTR_ENABLE(); // re-enable UART interrupts
|
||||||
|
|
||||||
system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity
|
system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity
|
||||||
|
RX_PULSE(EMSUART_BIT_TIME / 2);
|
||||||
ETS_UART_INTR_ENABLE(); // re-enable UART interrupts
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,21 +63,22 @@ static void emsuart_rx_intr_handler(void * para) {
|
|||||||
*/
|
*/
|
||||||
static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events) {
|
static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events) {
|
||||||
_EMSRxBuf * pCurrent = pEMSRxBuf;
|
_EMSRxBuf * pCurrent = pEMSRxBuf;
|
||||||
|
pEMSRxBuf = paEMSRxBuf[++emsRxBufIdx % EMS_MAXBUFFERS]; // next free EMS Receive buffer
|
||||||
uint8_t length = pCurrent->length; // number of bytes including the BRK at the end
|
uint8_t length = pCurrent->length; // number of bytes including the BRK at the end
|
||||||
|
pCurrent->length = 0;
|
||||||
|
|
||||||
// validate and transmit the EMS buffer, excluding the BRK
|
// validate and transmit the EMS buffer, excluding the BRK
|
||||||
if (length == 2) {
|
if (length == 2) {
|
||||||
// it's a poll or status code, single byte
|
RX_PULSE(20);
|
||||||
|
// it's a poll or status code, single byte and ok to send on
|
||||||
ems_parseTelegram((uint8_t *)pCurrent->buffer, 1);
|
ems_parseTelegram((uint8_t *)pCurrent->buffer, 1);
|
||||||
} else if ((length > 4) && (pCurrent->buffer[length - 2] != 0x00)) {
|
} else if ((length > 4) && (length <= EMS_MAXBUFFERSIZE + 1) && (pCurrent->buffer[length - 2] != 0x00)) {
|
||||||
// ignore double BRK at the end, possibly from the Tx loopback
|
// ignore double BRK at the end, possibly from the Tx loopback
|
||||||
// also telegrams with no data value
|
// also telegrams with no data value
|
||||||
|
RX_PULSE(40);
|
||||||
ems_parseTelegram((uint8_t *)pCurrent->buffer, length - 1); // transmit EMS buffer, excluding the BRK
|
ems_parseTelegram((uint8_t *)pCurrent->buffer, length - 1); // transmit EMS buffer, excluding the BRK
|
||||||
}
|
}
|
||||||
|
// memset(pCurrent->buffer, 0x00, EMS_MAXBUFFERSIZE); // wipe memory just to be safe
|
||||||
memset(pCurrent->buffer, 0x00, EMS_MAXBUFFERSIZE); // wipe memory just to be safe
|
|
||||||
|
|
||||||
pEMSRxBuf = paEMSRxBuf[++emsRxBufIdx % EMS_MAXBUFFERS]; // next free EMS Receive buffer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -94,7 +95,7 @@ static inline void ICACHE_FLASH_ATTR emsuart_flush_fifos() {
|
|||||||
*/
|
*/
|
||||||
void ICACHE_FLASH_ATTR emsuart_init() {
|
void ICACHE_FLASH_ATTR emsuart_init() {
|
||||||
ETS_UART_INTR_DISABLE();
|
ETS_UART_INTR_DISABLE();
|
||||||
ETS_UART_INTR_ATTACH(NULL, NULL);
|
ETS_UART_INTR_ATTACH(nullptr, nullptr);
|
||||||
|
|
||||||
// allocate and preset EMS Receive buffers
|
// allocate and preset EMS Receive buffers
|
||||||
for (int i = 0; i < EMS_MAXBUFFERS; i++) {
|
for (int i = 0; i < EMS_MAXBUFFERS; i++) {
|
||||||
@@ -117,11 +118,14 @@ void ICACHE_FLASH_ATTR emsuart_init() {
|
|||||||
|
|
||||||
// conf1 params
|
// conf1 params
|
||||||
// UCTOE = RX TimeOut enable (default is 1)
|
// UCTOE = RX TimeOut enable (default is 1)
|
||||||
// UCTOT = RX TimeOut Threshold (7 bit) = want this when no more data after 2 characters (default is 2)
|
// UCTOT = RX TimeOut Threshold (7 bit) = want this when no more data after 1 characters (default is 2)
|
||||||
// UCFFT = RX FIFO Full Threshold (7 bit) = want this to be 31 for 32 bytes of buffer (default was 127)
|
// UCFFT = RX FIFO Full Threshold (7 bit) = want this to be 31 for 32 bytes of buffer (default was 127)
|
||||||
// see https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf
|
// see https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf
|
||||||
|
//
|
||||||
|
// change: we set UCFFT to 1 to get an immediate indicator about incoming trafffic.
|
||||||
|
// Otherwise, we're only noticed by UCTOT or RxBRK!
|
||||||
USC1(EMSUART_UART) = 0; // reset config first
|
USC1(EMSUART_UART) = 0; // reset config first
|
||||||
USC1(EMSUART_UART) = (EMS_MAX_TELEGRAM_LENGTH << UCFFT) | (0x02 << UCTOT) | (1 << UCTOE); // enable interupts
|
USC1(EMSUART_UART) = (0x01 << UCFFT) | (0x01 << UCTOT) | (1 << UCTOE); // enable interupts
|
||||||
|
|
||||||
// set interrupts for triggers
|
// set interrupts for triggers
|
||||||
USIC(EMSUART_UART) = 0xFFFF; // clear all interupts
|
USIC(EMSUART_UART) = 0xFFFF; // clear all interupts
|
||||||
@@ -138,9 +142,9 @@ void ICACHE_FLASH_ATTR emsuart_init() {
|
|||||||
system_set_os_print(0);
|
system_set_os_print(0);
|
||||||
|
|
||||||
// swap Rx and Tx pins to use GPIO13 (D7) and GPIO15 (D8) respectively
|
// swap Rx and Tx pins to use GPIO13 (D7) and GPIO15 (D8) respectively
|
||||||
system_uart_swap();
|
//system_uart_swap();
|
||||||
|
|
||||||
ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, NULL);
|
ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr);
|
||||||
ETS_UART_INTR_ENABLE();
|
ETS_UART_INTR_ENABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,30 +164,99 @@ void ICACHE_FLASH_ATTR emsuart_start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* set loopback mode and clear Tx/Rx FIFO
|
* Send a BRK signal
|
||||||
|
* Which is a 11-bit set of zero's (11 cycles)
|
||||||
*/
|
*/
|
||||||
static inline void ICACHE_FLASH_ATTR emsuart_loopback(bool enable) {
|
void ICACHE_FLASH_ATTR emsuart_tx_brk() {
|
||||||
if (enable)
|
uint32_t tmp;
|
||||||
USC0(EMSUART_UART) |= (1 << UCLBE); // enable loopback
|
|
||||||
else
|
// must make sure Tx FIFO is empty
|
||||||
USC0(EMSUART_UART) &= ~(1 << UCLBE); // disable loopback
|
while (((USS(EMSUART_UART) >> USTXC) & 0xFF) != 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask
|
||||||
|
USC0(EMSUART_UART) |= (tmp); // set bits
|
||||||
|
USC0(EMSUART_UART) &= ~(tmp); // clear bits
|
||||||
|
|
||||||
|
// To create a 11-bit <BRK> we set TXD_BRK bit so the break signal will
|
||||||
|
// automatically be sent when the tx fifo is empty
|
||||||
|
tmp = (1 << UCBRK);
|
||||||
|
GPIO_H(TX_MARK_MASK);
|
||||||
|
USC0(EMSUART_UART) |= (tmp); // set bit
|
||||||
|
|
||||||
|
if (EMS_Sys_Status.emsTxMode <= 1) { // classic mode and ems+ (0, 1)
|
||||||
|
delayMicroseconds(EMSUART_TX_BRK_WAIT);
|
||||||
|
} else if (EMS_Sys_Status.emsTxMode == 3) { // junkers mode
|
||||||
|
delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
USC0(EMSUART_UART) &= ~(tmp); // clear bit
|
||||||
|
GPIO_L(TX_MARK_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send to Tx, ending with a <BRK>
|
* Send to Tx, ending with a <BRK>
|
||||||
*/
|
*/
|
||||||
void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
|
_EMS_TX_STATUS ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
|
||||||
if (len == 0)
|
_EMS_TX_STATUS result = EMS_TX_STATUS_OK;
|
||||||
return;
|
if (len) {
|
||||||
|
LA_PULSE(50);
|
||||||
|
// temp code until we get mode 2 working without resets
|
||||||
|
if (EMS_Sys_Status.emsTxMode == 0) { // classic mode logic
|
||||||
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
|
TX_PULSE(EMSUART_BIT_TIME / 4);
|
||||||
|
USF(EMSUART_UART) = buf[i];
|
||||||
|
}
|
||||||
|
emsuart_tx_brk(); // send <BRK>
|
||||||
|
} else if (EMS_Sys_Status.emsTxMode == 1) { // With extra tx delay for EMS+
|
||||||
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
|
TX_PULSE(EMSUART_BIT_TIME / 4);
|
||||||
|
USF(EMSUART_UART) = buf[i];
|
||||||
|
delayMicroseconds(EMSUART_TX_BRK_WAIT); // https://github.com/proddy/EMS-ESP/issues/23#
|
||||||
|
}
|
||||||
|
emsuart_tx_brk(); // send <BRK>
|
||||||
|
} else if (EMS_Sys_Status.emsTxMode == 3) { // Junkers logic by @philrich
|
||||||
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
|
TX_PULSE(EMSUART_BIT_TIME / 4);
|
||||||
|
USF(EMSUART_UART) = buf[i];
|
||||||
|
|
||||||
|
// just to be safe wait for tx fifo empty (needed?)
|
||||||
|
while (((USS(EMSUART_UART) >> USTXC) & 0xff) != 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
// wait until bits are sent on wire
|
||||||
|
delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP);
|
||||||
|
}
|
||||||
|
emsuart_tx_brk(); // send <BRK>
|
||||||
|
} else if (EMS_Sys_Status.emsTxMode == 2) {
|
||||||
/*
|
/*
|
||||||
|
*
|
||||||
* based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch
|
* based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch
|
||||||
* we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO.
|
* we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO.
|
||||||
* after sending the last char we poll the Rx status until either
|
* after sending the last char we poll the Rx status until either
|
||||||
* - size(Rx FIFO) == size(Tx-Telegram)
|
* - size(Rx FIFO) == size(Tx-Telegram)
|
||||||
* - <BRK> is detected
|
* - <BRK> is detected
|
||||||
* At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode.
|
* At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode.
|
||||||
|
*
|
||||||
|
* EMS-Bus error handling
|
||||||
|
* 1. Busmaster stops echoing on Tx w/o permission
|
||||||
|
* 2. Busmaster cancel telegram by sending a BRK
|
||||||
|
*
|
||||||
|
* Case 1. is handled by a watchdog counter which is reset on each
|
||||||
|
* Tx attempt. The timeout should be 20x EMSUART_BIT_TIME plus
|
||||||
|
* some smart guess for processing time on targeted EMS device.
|
||||||
|
* We set EMS_Sys_Status.emsTxStatus to EMS_TX_WTD_TIMEOUT and return
|
||||||
|
*
|
||||||
|
* Case 2. is handled via a BRK chk during transmission.
|
||||||
|
* We set EMS_Sys_Status.emsTxStatus to EMS_TX_BRK_DETECT and return
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// shorter busy poll...
|
||||||
|
#define EMSUART_BUSY_WAIT (EMSUART_BIT_TIME / 8)
|
||||||
|
#define EMS_TX_TO_COUNT ((20 + 10000 / EMSUART_BIT_TIME) * 8)
|
||||||
|
uint16_t wdc = EMS_TX_TO_COUNT;
|
||||||
|
|
||||||
ETS_UART_INTR_DISABLE(); // disable rx interrupt
|
ETS_UART_INTR_DISABLE(); // disable rx interrupt
|
||||||
|
|
||||||
// clear Rx status register
|
// clear Rx status register
|
||||||
@@ -191,11 +264,25 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
|
|||||||
emsuart_flush_fifos();
|
emsuart_flush_fifos();
|
||||||
|
|
||||||
// throw out the telegram...
|
// throw out the telegram...
|
||||||
for (uint8_t i = 0; i < len;) {
|
for (uint8_t i = 0; i < len && result == EMS_TX_STATUS_OK;) {
|
||||||
|
GPIO_H(TX_MARK_MASK);
|
||||||
|
|
||||||
|
wdc = EMS_TX_TO_COUNT;
|
||||||
|
volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF;
|
||||||
USF(EMSUART_UART) = buf[i++]; // send each Tx byte
|
USF(EMSUART_UART) = buf[i++]; // send each Tx byte
|
||||||
// wait for echo from busmaster
|
// wait for echo from busmaster
|
||||||
while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) < i || (USIS(EMSUART_UART) & (1 << UIBD)))) {
|
GPIO_L(TX_MARK_MASK);
|
||||||
delayMicroseconds(EMSUART_BIT_TIME); // burn CPU cycles...
|
|
||||||
|
while (((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) {
|
||||||
|
delayMicroseconds(EMSUART_BUSY_WAIT); // burn CPU cycles...
|
||||||
|
if (--wdc == 0) {
|
||||||
|
EMS_Sys_Status.emsTxStatus = result = EMS_TX_WTD_TIMEOUT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (USIR(EMSUART_UART) & (1 << UIBD)) {
|
||||||
|
USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ
|
||||||
|
EMS_Sys_Status.emsTxStatus = result = EMS_TX_BRK_DETECT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,23 +290,29 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) {
|
|||||||
// on Rx-BRK (bus collision), we simply enable Rx and leave it
|
// on Rx-BRK (bus collision), we simply enable Rx and leave it
|
||||||
// otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT.
|
// otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT.
|
||||||
// worst case, we'll see an additional Rx-BRK...
|
// worst case, we'll see an additional Rx-BRK...
|
||||||
|
if (result != EMS_TX_STATUS_OK) {
|
||||||
|
LA_PULSE(200); // mark Tx error
|
||||||
|
} else {
|
||||||
|
// neither bus collision nor timeout - send terminating BRK signal
|
||||||
|
GPIO_H(TX_MARK_MASK);
|
||||||
if (!(USIS(EMSUART_UART) & (1 << UIBD))) {
|
if (!(USIS(EMSUART_UART) & (1 << UIBD))) {
|
||||||
// no bus collision - send terminating BRK signal
|
// no bus collision - send terminating BRK signal
|
||||||
emsuart_loopback(true);
|
USC0(EMSUART_UART) |= (1 << UCLBE) | (1 << UCBRK); // enable loopback & set <BRK>
|
||||||
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
|
|
||||||
|
|
||||||
// wait until BRK detected...
|
// wait until BRK detected...
|
||||||
while (!(USIS(EMSUART_UART) & (1 << UIBD))) {
|
while (!(USIR(EMSUART_UART) & (1 << UIBD))) {
|
||||||
delayMicroseconds(EMSUART_BIT_TIME);
|
delayMicroseconds(EMSUART_BUSY_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear <BRK>
|
USC0(EMSUART_UART) &= ~((1 << UCBRK) | (1 << UCLBE)); // disable loopback & clear <BRK>
|
||||||
|
|
||||||
USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ
|
USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ
|
||||||
emsuart_loopback(false); // disable loopback mode
|
|
||||||
}
|
}
|
||||||
|
GPIO_L(TX_MARK_MASK);
|
||||||
|
}
|
||||||
ETS_UART_INTR_ENABLE(); // receive anything from FIFO...
|
ETS_UART_INTR_ENABLE(); // receive anything from FIFO...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -8,16 +8,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <ems.h>
|
||||||
|
|
||||||
#define EMSUART_UART 0 // UART 0
|
#define EMSUART_UART 0 // UART 0
|
||||||
#define EMSUART_CONFIG 0x1C // 8N1 (8 bits, no stop bits, 1 parity)
|
#define EMSUART_CONFIG 0x1C // 8N1 (8 bits, no stop bits, 1 parity)
|
||||||
#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit
|
#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit
|
||||||
|
|
||||||
#define EMS_MAXBUFFERS 10 // buffers for circular filling to avoid collisions
|
#define EMS_MAXBUFFERS 5 // buffers for circular filling to avoid collisions
|
||||||
#define EMS_MAXBUFFERSIZE 32 // max size of the buffer. packets are max 32 bytes to support EMS 1.0
|
#define EMS_MAXBUFFERSIZE (EMS_MAX_TELEGRAM_LENGTH + 2) // max size of the buffer. EMS packets are max 32 bytes, plus extra 2 for BRKs
|
||||||
|
|
||||||
#define EMSUART_BIT_TIME 104 // bit time @9600 baud
|
#define EMSUART_BIT_TIME 104 // bit time @9600 baud
|
||||||
|
|
||||||
|
#define EMSUART_TX_BRK_WAIT 2070 // the BRK from Boiler master is roughly 1.039ms, so accounting for hardware lag using around 2078 (for half-duplex) - 8 (lag)
|
||||||
|
#define EMSUART_TX_WAIT_BYTE EMSUART_BIT_TIME * 10 // Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit)
|
||||||
|
#define EMSUART_TX_WAIT_BRK EMSUART_BIT_TIME * 11 // Time to send a BRK Signal (11 Bit)
|
||||||
|
#define EMSUART_TX_WAIT_GAP EMSUART_BIT_TIME * 7 // Gap between to Bytes
|
||||||
|
#define EMSUART_TX_LAG 8
|
||||||
|
|
||||||
#define EMSUART_recvTaskPrio 1
|
#define EMSUART_recvTaskPrio 1
|
||||||
#define EMSUART_recvTaskQueueLen 64
|
#define EMSUART_recvTaskQueueLen 64
|
||||||
|
|
||||||
@@ -29,5 +36,5 @@ typedef struct {
|
|||||||
void ICACHE_FLASH_ATTR emsuart_init();
|
void ICACHE_FLASH_ATTR emsuart_init();
|
||||||
void ICACHE_FLASH_ATTR emsuart_stop();
|
void ICACHE_FLASH_ATTR emsuart_stop();
|
||||||
void ICACHE_FLASH_ATTR emsuart_start();
|
void ICACHE_FLASH_ATTR emsuart_start();
|
||||||
void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len);
|
_EMS_TX_STATUS ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len);
|
||||||
void ICACHE_FLASH_ATTR emsuart_tx_poll();
|
void ICACHE_FLASH_ATTR emsuart_tx_poll();
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
#define TOPIC_BOILER_WWACTIVATED "wwactivated" // for receiving MQTT message to change water on/off
|
#define TOPIC_BOILER_WWACTIVATED "wwactivated" // for receiving MQTT message to 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" // for received boiler 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" // for received boiler ww comfort setting via MQTT
|
||||||
|
#define TOPIC_BOILER_CMD_FLOWTEMP "boiler_cmd_flowtemp" // for received boiler 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
|
||||||
@@ -57,6 +58,7 @@
|
|||||||
#define SM_ENERGYLASTHOUR "energylasthour" // energy last hour
|
#define SM_ENERGYLASTHOUR "energylasthour" // energy last hour
|
||||||
#define SM_ENERGYTODAY "energytoday" // energy today
|
#define SM_ENERGYTODAY "energytoday" // energy today
|
||||||
#define SM_ENERGYTOTAL "energytotal" // energy total
|
#define SM_ENERGYTOTAL "energytotal" // energy total
|
||||||
|
#define SM_PUMPWORKMIN "pumpWorkMin" // Total minutes
|
||||||
|
|
||||||
// MQTT for HP (HeatPump)
|
// MQTT for HP (HeatPump)
|
||||||
#define TOPIC_HP_DATA "hp_data" // topic name
|
#define TOPIC_HP_DATA "hp_data" // topic name
|
||||||
@@ -83,10 +85,15 @@
|
|||||||
// can be enabled and disabled via the 'set led' command and pin set by 'set led_gpio'
|
// can be enabled and disabled via the 'set led' command and pin set by 'set led_gpio'
|
||||||
#define EMSESP_LED_GPIO LED_BUILTIN
|
#define EMSESP_LED_GPIO LED_BUILTIN
|
||||||
|
|
||||||
|
#ifdef LOGICANALYZER
|
||||||
|
#define EMSESP_DALLAS_GPIO D1
|
||||||
|
#define EMSESP_DALLAS_PARASITE false
|
||||||
|
#else
|
||||||
// set this if using an external temperature sensor like a DS18B20
|
// set this if using an external temperature sensor like a DS18B20
|
||||||
// D5 is the default on a bbqkees board
|
// D5 is the default on a bbqkees board
|
||||||
#define EMSESP_DALLAS_GPIO D5
|
#define EMSESP_DALLAS_GPIO D5
|
||||||
#define EMSESP_DALLAS_PARASITE false
|
#define EMSESP_DALLAS_PARASITE false
|
||||||
|
#endif
|
||||||
|
|
||||||
// By default the EMS bus will be scanned for known devices based on the product ids in ems_devices.h
|
// By default the EMS bus will be scanned for known devices based on the product ids in ems_devices.h
|
||||||
// You can override the Thermostat and Boiler types here
|
// You can override the Thermostat and Boiler types here
|
||||||
|
|||||||
@@ -49,7 +49,10 @@ static const char * TEST_DATA[] = {
|
|||||||
"90 00 FF 00 00 6F 03 01 00 BE 00 BF", // test 44 - FR10
|
"90 00 FF 00 00 6F 03 01 00 BE 00 BF", // test 44 - FR10
|
||||||
"08 00 E3 00 01 00 01 00 00 00 00 00 00 00 00 00 DF 00 64 55", // test 45 - heatpump Enviline
|
"08 00 E3 00 01 00 01 00 00 00 00 00 00 00 00 00 DF 00 64 55", // test 45 - heatpump Enviline
|
||||||
"08 00 E5 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A", // test 46 - heatpump Enviline
|
"08 00 E5 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A", // test 46 - heatpump Enviline
|
||||||
"38 10 FF 00 03 2B 00 C7 07 C3 01" // test 47 - heatpump Enviline
|
"38 10 FF 00 03 2B 00 C7 07 C3 01", // test 47 - heatpump Enviline
|
||||||
|
"08 0B 19 00 00 F7 80 00 80 00 00 00 00 00 03 58 97 0C 7B 1F 00 00 00 06 C4 DF 02 64 48 80 00", // test 48 - outdoor temp check
|
||||||
|
"88 00 19 00 00 DC 80 00 80 00 FF FF 00 00 00 21 9A 06 E1 7C 00 00 00 06 C2 13 00 1E 90 80 00", // test 49 - check max length
|
||||||
|
"30 00 FF 00 02 8E 00 00 41 82 00 00 28 36 00 00 82 21" // test 50 - SM100
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,5 +6,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define APP_NAME "EMS-ESP"
|
#define APP_NAME "EMS-ESP"
|
||||||
#define APP_VERSION "1.8.0"
|
#define APP_VERSION "1.8.1"
|
||||||
#define APP_HOSTNAME "ems-esp"
|
#define APP_HOSTNAME "ems-esp"
|
||||||
|
|||||||
Reference in New Issue
Block a user