Merge remote-tracking branch 'upstream/dev' into MM10

This commit is contained in:
MichaelDvP
2020-01-12 09:59:51 +01:00
58 changed files with 161 additions and 8346 deletions

View File

@@ -1474,13 +1474,13 @@ void MyESP::_heartbeatCheck(bool force) {
StaticJsonDocument<MYESP_JSON_MAXSIZE_SMALL> doc;
JsonObject rootHeartbeat = doc.to<JsonObject>();
rootHeartbeat["version"] = _app_version;
rootHeartbeat["IP"] = WiFi.localIP().toString();
rootHeartbeat["rssid"] = getWifiQuality();
rootHeartbeat["load"] = getSystemLoadAverage();
rootHeartbeat["uptime"] = _getUptime();
rootHeartbeat["freemem"] = mem_available;
rootHeartbeat["MQTTdisconnects"] = _getSystemDropoutCounter();
//rootHeartbeat["version"] = _app_version;
//rootHeartbeat["IP"] = WiFi.localIP().toString();
rootHeartbeat["rssid"] = getWifiQuality();
rootHeartbeat["load"] = getSystemLoadAverage();
rootHeartbeat["uptime"] = _getUptime();
rootHeartbeat["freemem"] = mem_available;
//rootHeartbeat["MQTTdisconnects"] = _getSystemDropoutCounter();
char data[300] = {0};
serializeJson(doc, data, sizeof(data));

View File

@@ -9,7 +9,7 @@
#ifndef MyESP_h
#define MyESP_h
#define MYESP_VERSION "1.2.22"
#define MYESP_VERSION "1.2.23"
#include <ArduinoJson.h>
#include <ArduinoOTA.h>

View File

@@ -114,7 +114,7 @@
<div class="row form-group">
<label class="col-xs-3">Publish Time<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
data-content="How often to send MQTT topics with stats. 0 is automatic. (in seconds)"></i></label>
data-content="How often to send the MQTT topics in seconds. Must be at least 1"></i></label>
<span class="col-xs-9">
<input class="form-control input-sm" placeholder="0" value="" style="display:inline;max-width:185px"
id="publish_time" type="text">

View File

@@ -8,7 +8,7 @@ var custom_config = {
"listen_mode": false,
"shower_timer": false,
"shower_alert": false,
"publish_time": 0,
"publish_time": 10,
"tx_mode": 1
}
};

View File

@@ -18,24 +18,28 @@ DS18::DS18() {
}
DS18::~DS18() {
if (_wire)
if (_wire) {
delete _wire;
}
}
// init
uint8_t DS18::setup(uint8_t gpio, bool parasite) {
uint8_t count;
void DS18::setup(uint8_t gpio, bool parasite) {
_gpio = gpio;
_parasite = (parasite ? 1 : 0);
// OneWire
if (_wire)
if (_wire) {
delete _wire;
}
_wire = new OneWire(_gpio);
}
// Search devices
count = loadDevices();
// clear list and scan for devices
uint8_t DS18::scan() {
_devices.clear();
uint8_t count = loadDevices(); // start the search
// If no devices found check again pulling up the line
if (count == 0) {
@@ -48,30 +52,30 @@ uint8_t DS18::setup(uint8_t gpio, bool parasite) {
return count;
}
// scan every 2 seconds
void DS18::loop() {
static uint32_t last = 0;
if (millis() - last < DS18_READ_INTERVAL)
if (millis() - last < DS18_READ_INTERVAL) {
return;
}
last = millis();
// Every second we either start a conversion or read the scratchpad
static bool conversion = true;
if (conversion) {
// Start conversion
_wire->reset();
_wire->skip();
_wire->write(DS18_CMD_START_CONVERSION, _parasite);
} else {
// Read scratchpads
for (unsigned char index = 0; index < _devices.size(); index++) {
// Read scratchpad
if (_wire->reset() == 0) {
// Force a CRC check error
_devices[index].data[0] = _devices[index].data[0] + 1;
_devices[index].data[0] = _devices[index].data[0] + 1; // Force a CRC check error
return;
}
// Read each scratchpad
_wire->select(_devices[index].address);
_wire->write(DS18_CMD_READ_SCRATCHPAD);
@@ -81,8 +85,7 @@ void DS18::loop() {
}
if (_wire->reset() != 1) {
// Force a CRC check error
_devices[index].data[0] = _devices[index].data[0] + 1;
_devices[index].data[0] = _devices[index].data[0] + 1; // Force a CRC check error
return;
}
@@ -153,8 +156,9 @@ char * DS18::getDeviceString(char * buffer, unsigned char index) {
byte 8: SCRATCHPAD_CRC
*/
int16_t DS18::getRawValue(unsigned char index) {
if (index >= _count)
if (index >= _count) {
return 0;
}
uint8_t * data = _devices[index].data;
@@ -170,23 +174,35 @@ int16_t DS18::getRawValue(unsigned char index) {
}
} else {
byte cfg = (data[4] & 0x60);
if (cfg == 0x00)
if (cfg == 0x00) {
raw = raw & ~7; // 9 bit res, 93.75 ms
else if (cfg == 0x20)
} else if (cfg == 0x20) {
raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40)
} else if (cfg == 0x40) {
raw = raw & ~1; // 11 bit res, 375 ms
// 12 bit res, 750 ms
}
}
return raw;
}
// return real value as a float
// The raw temperature data is in units of sixteenths of a degree, so the value must be divided by 16 in order to convert it to degrees.
// return real value as a float, rounded to 2 decimal places
float DS18::getValue(unsigned char index) {
float value = (float)getRawValue(index) / 16.0;
return value;
int16_t raw_value = getRawValue(index);
// check if valid
if ((raw_value == DS18_CRC_ERROR) || (raw_value == DS18_DISCONNECTED)) {
return (float)DS18_DISCONNECTED;
}
// The raw temperature data is in units of sixteenths of a degree,
// so the value must first be divided by 16 in order to convert it to degrees.
float new_value = (float)(raw_value / 16.0);
// round to 2 decimal places
// https://arduinojson.org/v6/faq/how-to-configure-the-serialization-of-floats/
return (int)(new_value * 100 + 0.5) / 100.0;
}
// check for a supported DS chip version
@@ -196,8 +212,9 @@ bool DS18::validateID(unsigned char id) {
// return the type
unsigned char DS18::chip(unsigned char index) {
if (index < _count)
if (index < _count) {
return _devices[index].address[0];
}
return 0;
}
@@ -206,6 +223,7 @@ uint8_t DS18::loadDevices() {
uint8_t address[8];
_wire->reset();
_wire->reset_search();
while (_wire->search(address)) {
// Check CRC
if (_wire->crc8(address, 7) == address[7]) {

View File

@@ -36,7 +36,8 @@ class DS18 {
DS18();
~DS18();
uint8_t setup(uint8_t gpio, bool parasite);
void setup(uint8_t gpio, bool parasite);
uint8_t scan();
void loop();
char * getDeviceString(char * s, unsigned char index);
float getValue(unsigned char index);

View File

@@ -98,9 +98,9 @@ static const command_t project_cmds[] PROGMEM = {
{true, "listen_mode <on | off>", "when set to on all automatic Tx are disabled"},
{true, "shower_timer <on | off>", "send MQTT notification on all shower durations"},
{true, "shower_alert <on | off>", "stop hot water to send 3 cold burst warnings after max shower time is exceeded"},
{true, "publish_time <seconds>", "set frequency for publishing data to MQTT (0=automatic)"},
{true, "publish_time <seconds>", "set frequency for publishing data to MQTT"},
{true, "tx_mode <n>", "changes Tx logic. 1=EMS generic, 2=EMS+, 3=HT3"},
{true, "master_thermostat [product id]", "product id to use as the master thermostat. Use no args for list."},
{true, "master_thermostat [product id]", "set default thermostat to use. Omit [product id] to show options."},
{false, "info", "show current values deciphered from the EMS messages"},
{false, "log <n | b | t | s | r | j | v | w [type ID]", "set logging to none, basic, thermostat, solar module, raw, jabber, verbose or watch a specific type"},
@@ -113,7 +113,7 @@ static const command_t project_cmds[] PROGMEM = {
{false, "refresh", "fetch values from the EMS devices"},
{false, "devices", "list detected EMS devices"},
{false, "queue", "show current Tx queue"},
{false, "autodetect", "detect EMS devices and attempt to automatically set boiler and thermostat types"},
{false, "autodetect", "scan for EMS devices and external sensors"},
{false, "send XX ...", "send raw telegram data to EMS bus (XX are hex values)"},
{false, "thermostat read <type ID>", "send read request to the thermostat for heating circuit hc 1-4"},
{false, "thermostat temp [hc] <degrees>", "set current thermostat temperature"},
@@ -505,13 +505,27 @@ void showInfo() {
char valuestr[8] = {0}; // for formatting temp
myDebug_P(PSTR("%sExternal temperature sensors:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF);
for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) {
myDebug_P(PSTR(" Sensor #%d %s: %s C"), i + 1, ds18.getDeviceString(buffer, i), _float_to_char(valuestr, ds18.getValue(i)));
float sensorValue = ds18.getValue(i);
if (sensorValue != DS18_DISCONNECTED) {
myDebug_P(PSTR(" Sensor #%d %s: %s C"), i + 1, ds18.getDeviceString(buffer, i), _float_to_char(valuestr, sensorValue));
}
}
}
myDebug_P(PSTR("")); // newline
}
// scan for external Dallas sensors and display
void scanDallas() {
EMSESP_Settings.dallas_sensors = ds18.scan();
if (EMSESP_Settings.dallas_sensors) {
char buffer[128] = {0};
for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) {
myDebug_P(PSTR("External temperature sensor %s found"), ds18.getDeviceString(buffer, i));
}
}
}
// send all dallas sensor values as a JSON package to MQTT
void publishSensorValues() {
// don't send if MQTT is connected
@@ -531,9 +545,8 @@ void publishSensorValues() {
// see if the sensor values have changed, if so send it on
for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) {
// round to 2 decimal places. from https://arduinojson.org/v6/faq/how-to-configure-the-serialization-of-floats/
float sensorValue = (int)(ds18.getValue(i) * 100 + 0.5) / 100.0;
if (sensorValue != DS18_DISCONNECTED && sensorValue != DS18_CRC_ERROR) {
float sensorValue = ds18.getValue(i);
if (sensorValue != DS18_DISCONNECTED) {
sprintf(label, PAYLOAD_EXTERNAL_SENSORS, (i + 1));
sensors[label] = sensorValue;
hasdata = true;
@@ -1083,8 +1096,13 @@ bool SetListCallback(MYESP_FSACTION_t action, uint8_t wc, const char * setting,
// publish_time
if ((strcmp(setting, "publish_time") == 0) && (wc == 2)) {
EMSESP_Settings.publish_time = atoi(value);
ok = true;
int16_t val = atoi(value);
if (val > 0) {
EMSESP_Settings.publish_time = atoi(value);
ok = true;
} else {
myDebug_P(PSTR("Error. time must be at least 1 second"));
}
}
// tx_mode
@@ -1133,12 +1151,7 @@ bool SetListCallback(MYESP_FSACTION_t action, uint8_t wc, const char * setting,
myDebug_P(PSTR(" listen_mode=%s"), EMSESP_Settings.listen_mode ? "on" : "off");
myDebug_P(PSTR(" shower_timer=%s"), EMSESP_Settings.shower_timer ? "on" : "off");
myDebug_P(PSTR(" shower_alert=%s"), EMSESP_Settings.shower_alert ? "on" : "off");
if (EMSESP_Settings.publish_time) {
myDebug_P(PSTR(" publish_time=%d"), EMSESP_Settings.publish_time);
} else {
myDebug_P(PSTR(" publish_time=0 (always publish on data received)"), EMSESP_Settings.publish_time);
}
myDebug_P(PSTR(" publish_time=%d"), EMSESP_Settings.publish_time);
if (EMSESP_Settings.master_thermostat) {
myDebug_P(PSTR(" master_thermostat=%d"), EMSESP_Settings.master_thermostat);
@@ -1188,9 +1201,9 @@ void _showCommands(uint8_t event) {
// we set the logging here
void TelnetCallback(uint8_t event) {
if (event == TELNET_EVENT_CONNECT) {
ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
ems_setLogging(EMS_SYS_LOGGING_DEFAULT, true);
} else if (event == TELNET_EVENT_DISCONNECT) {
ems_setLogging(EMS_SYS_LOGGING_NONE);
ems_setLogging(EMS_SYS_LOGGING_NONE, true);
} else if ((event == TELNET_EVENT_SHOWCMD) || (event == TELNET_EVENT_SHOWSET)) {
_showCommands(event);
}
@@ -1229,6 +1242,8 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) {
}
if (strcmp(first_cmd, "autodetect") == 0) {
myDebug("Scanning for new EMS devices and attached external sensors...");
scanDallas();
ems_clearDeviceList();
ems_doReadCommand(EMS_TYPE_UBADevices, EMS_Boiler.device_id);
ok = true;
@@ -1464,14 +1479,18 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
const char * shower_alert = doc[TOPIC_SHOWER_ALERT];
if (shower_alert) {
EMSESP_Settings.shower_alert = ((shower_alert[0] - MYESP_MQTT_PAYLOAD_OFF) == 1);
myDebug_P(PSTR("Shower alert has been set to %s"), EMSESP_Settings.shower_alert ? "enabled" : "disabled");
if (ems_getLogging() != EMS_SYS_LOGGING_NONE) {
myDebug_P(PSTR("Shower alert has been set to %s"), EMSESP_Settings.shower_alert ? "enabled" : "disabled");
}
}
// assumes payload is "1" or "0"
const char * shower_timer = doc[TOPIC_SHOWER_TIMER];
if (shower_timer) {
EMSESP_Settings.shower_timer = ((shower_timer[0] - MYESP_MQTT_PAYLOAD_OFF) == 1);
myDebug_P(PSTR("Shower timer has been set to %s"), EMSESP_Settings.shower_timer ? "enabled" : "disabled");
if (ems_getLogging() != EMS_SYS_LOGGING_NONE) {
myDebug_P(PSTR("Shower timer has been set to %s"), EMSESP_Settings.shower_timer ? "enabled" : "disabled");
}
}
return;
@@ -1940,7 +1959,7 @@ void setup() {
regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS
}
// set timers for MQTT publish, only if publish_time is not 0 (automatic mode)
// set timers for MQTT publish
if (EMSESP_Settings.publish_time) {
publishValuesTimer.attach(EMSESP_Settings.publish_time, do_publishValues); // post MQTT EMS values
}
@@ -1956,7 +1975,8 @@ void setup() {
systemCheckTimer.attach(SYSTEMCHECK_TIME, do_systemCheck); // check if EMS is reachable
// check for Dallas sensors
EMSESP_Settings.dallas_sensors = ds18.setup(EMSESP_Settings.dallas_gpio, EMSESP_Settings.dallas_parasite); // returns #sensors
ds18.setup(EMSESP_Settings.dallas_gpio, EMSESP_Settings.dallas_parasite);
scanDallas();
}
//
@@ -1970,11 +1990,6 @@ void loop() {
ds18.loop();
}
// publish EMS data to MQTT, only if in automatic mode (publish_time=0) otherwise it'll use the timer
if (EMSESP_Settings.publish_time == 0) {
publishEMSValues(false);
}
// if we have an EMS connect go and fetch some data and MQTT publish it
if (_need_first_publish) {
publishEMSValues(false);

View File

@@ -210,7 +210,7 @@ void ems_init() {
strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version));
// default logging is none
ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
ems_setLogging(EMS_SYS_LOGGING_DEFAULT, true);
}
// Getters and Setters for parameters
@@ -282,27 +282,33 @@ _EMS_SYS_LOGGING ems_getLogging() {
}
void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t type_id) {
if (loglevel <= EMS_SYS_LOGGING_JABBER) {
EMS_Sys_Status.emsLogging = loglevel;
EMS_Sys_Status.emsLogging_typeID = type_id;
ems_setLogging(EMS_SYS_LOGGING_WATCH, false);
}
if (loglevel == EMS_SYS_LOGGING_NONE) {
myDebug_P(PSTR("System Logging set to None"));
} else if (loglevel == EMS_SYS_LOGGING_BASIC) {
myDebug_P(PSTR("System Logging set to Basic"));
} else if (loglevel == EMS_SYS_LOGGING_VERBOSE) {
myDebug_P(PSTR("System Logging set to Verbose"));
} else if (loglevel == EMS_SYS_LOGGING_THERMOSTAT) {
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) {
myDebug_P(PSTR("System Logging set to Raw mode"));
} else if (loglevel == EMS_SYS_LOGGING_JABBER) {
myDebug_P(PSTR("System Logging set to Jabber mode"));
} else if (loglevel == EMS_SYS_LOGGING_WATCH) {
EMS_Sys_Status.emsLogging_typeID = type_id;
myDebug_P(PSTR("System Logging set to Watch mode"));
}
void ems_setLogging(_EMS_SYS_LOGGING loglevel, bool quiet) {
EMS_Sys_Status.emsLogging = loglevel;
if (quiet) {
return; // no reporting to console
}
if (loglevel == EMS_SYS_LOGGING_NONE) {
myDebug_P(PSTR("System Logging set to None"));
} else if (loglevel == EMS_SYS_LOGGING_BASIC) {
myDebug_P(PSTR("System Logging set to Basic"));
} else if (loglevel == EMS_SYS_LOGGING_VERBOSE) {
myDebug_P(PSTR("System Logging set to Verbose"));
} else if (loglevel == EMS_SYS_LOGGING_THERMOSTAT) {
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) {
myDebug_P(PSTR("System Logging set to Raw mode"));
} else if (loglevel == EMS_SYS_LOGGING_JABBER) {
myDebug_P(PSTR("System Logging set to Jabber mode"));
} else if (loglevel == EMS_SYS_LOGGING_WATCH) {
myDebug_P(PSTR("System Logging set to Watch mode"));
}
}
@@ -2135,21 +2141,31 @@ void ems_printDevices() {
have_unknowns = true;
}
myDebug_P(PSTR(" %s: %s%s%s (DeviceID:0x%02X ProductID:%d Version:%s)"),
device_type,
COLOR_BOLD_ON,
device_string,
COLOR_BOLD_OFF,
it->device_id,
it->product_id,
it->version);
}
if ((it->device_type == EMS_DEVICE_TYPE_THERMOSTAT) && (EMS_Sys_Status.emsMasterThermostat == it->product_id)) {
myDebug_P(PSTR(" %s: %s%s%s (DeviceID:0x%02X ProductID:%d Version:%s) [master]"),
device_type,
COLOR_BOLD_ON,
device_string,
COLOR_BOLD_OFF,
it->device_id,
it->product_id,
it->version);
} else {
myDebug_P(PSTR(" %s: %s%s%s (DeviceID:0x%02X ProductID:%d Version:%s)"),
device_type,
COLOR_BOLD_ON,
device_string,
COLOR_BOLD_OFF,
it->device_id,
it->product_id,
it->version);
}
}
myDebug_P(PSTR("")); // newline
if (have_unknowns) {
myDebug_P(
PSTR("You have a device is that is not yet known by EMS-ESP. Please report this as a GitHub issue so we can expand the EMS device library."));
myDebug_P(PSTR("One or more devices are not recognized by EMS-ESP. Please report this in GitHub."));
}
} else {
myDebug_P(PSTR("No were devices recognized. This may be because Tx is disabled or failing."));

View File

@@ -434,7 +434,8 @@ void ems_setWarmWaterActivated(bool activated);
void ems_setWarmWaterOnetime(bool activated);
void ems_setWarmTapWaterActivated(bool activated);
void ems_setPoll(bool b);
void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t type_id = 0);
void ems_setLogging(_EMS_SYS_LOGGING loglevel, uint16_t type_id);
void ems_setLogging(_EMS_SYS_LOGGING loglevel, bool quiet = false);
void ems_setWarmWaterModeComfort(uint8_t comfort);
void ems_setModels();
void ems_setTxDisabled(bool b);

View File

@@ -1 +1 @@
#define APP_VERSION "1.9.5b16"
#define APP_VERSION "1.9.5b17"