Merge pull request #446 from MichaelDvP/v2

V2
This commit is contained in:
Proddy
2020-08-02 08:07:29 +02:00
committed by GitHub
13 changed files with 349 additions and 244 deletions

View File

@@ -100,7 +100,6 @@ boiler
wwonetime <on | off>
wwtemp <degrees>
read <type ID>
temp <degrees>
maxpower <%>
minpower <%>
@@ -113,6 +112,61 @@ thermostat
```
----------
### **mqtt commands**
commands can be written as `{"cmd": ,"data": }` or direct.
To set thermostat commands depending on heatingcircuits add `"hc": ` or nest the command. Without `"hc":` the first ative heatingcircuit is set.
These commands are equivalent:
`{"hc":2,"cmd":"daytemp","data":21}` or `{"hc":2,"daytemp":21}`or `{"hc2"{"daytemp":21}}`
In direct commands it's possible to combine commands, i.e. `{"hc1":{"daytemp":21,"nighttemp":17},"hc2":{"daytemp":20}}`
```
*boiler_cmd*
comfort <hot, eco, intelligent>
flowtemp <degrees>
wwtemp <degrees>
boilhyston <degrees> (negative value)
boilhystoff <degrees> (positive value)
burnperiod <minutes>
burnminpower <%>
burnmaxpower <%>
pumpdelay <minutes>
*thermostat_cmd*
--- without hc ---
wwmode <off | on | auto>
calinttemp <degrees>
minexttemp <degrees>
building <light | medium | heavy>
language <n> (0=de, 1=nl, 2=fr, 3=it) only RC30
display <n> (0=int temp, 1= int set, 2=ext. temp, 3=burner, 4=ww, 5=mode, 6=time, 7=date, 8=smoke) only RC30
clockoffset <seconds> (only RC30)
--- with hc ---
mode <auto | night | day | nofrost | heat | eco>
temp <degrees>
nighttemp <degrees>
daytemp <degrees>
nofrosttemp <degrees>
ecotemp <degrees>
heattemp <degrees>
summertemp <degrees>
designtemp <degrees>
offsettemp <degrees>
holidaytemp <degrees>
remotetemp <degrees>
control <0 | 1 | 2>
pause <hours>
party <hours>
holiday <dd.mm.yyyy-dd.mm.yyyy>
date <NTP | hh:mm:ss-dd.mm.yyyy-dw-dst>
*cmd*
send <"0B XX XX ..">
D0 <0 | 1>
D1 <0 | 1>
D2 <0 | 1>
D3 <0 | 1>
```
### **Basic Design Principles**

View File

@@ -44,7 +44,7 @@ void EMSESPDevicesService::scan_devices(AsyncWebServerRequest * request) {
}
void EMSESPDevicesService::all_devices(AsyncWebServerRequest * request) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_EMSESP_STATUS_SIZE);
AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_EMSESP_DEVICE_SIZE);
JsonObject root = response->getRoot();
JsonArray devices = root.createNestedArray("devices");
@@ -78,7 +78,7 @@ void EMSESPDevicesService::device_data(AsyncWebServerRequest * request, JsonVari
if (json.is<JsonObject>()) {
uint8_t id = json["id"]; // get id from selected table row
AsyncJsonResponse * response = new AsyncJsonResponse(false, 1024);
AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_EMSESP_DEVICE_SIZE);
#ifndef EMSESP_STANDALONE
EMSESP::device_info(id, (JsonObject &)response->getRoot());
#endif

View File

@@ -24,7 +24,8 @@
#include <ESPAsyncWebServer.h>
#include <SecurityManager.h>
#define MAX_EMSESP_STATUS_SIZE 1024
// #define MAX_EMSESP_STATUS_SIZE 1024
#define MAX_EMSESP_DEVICE_SIZE 1280
#define EMSESP_DEVICES_SERVICE_PATH "/rest/allDevices"
#define SCAN_DEVICES_SERVICE_PATH "/rest/scanDevices"

View File

@@ -30,7 +30,6 @@ MAKE_PSTR_WORD(intelligent)
MAKE_PSTR_WORD(hot)
MAKE_PSTR_WORD(maxpower)
MAKE_PSTR_WORD(minpower)
MAKE_PSTR_WORD(temp)
MAKE_PSTR(comfort_mandatory, "<hot | eco | intelligent>")
@@ -106,18 +105,50 @@ void Boiler::boiler_cmd(const char * message) {
uint8_t t = doc["wwtemp"];
set_warmwater_temp(t);
}
if (nullptr != doc["boilhyston"]) {
int8_t t = doc["boilhyston"];
set_hyst_on(t);
}
if (nullptr != doc["boilhystoff"]) {
uint8_t t = doc["boilhystoff"];
set_hyst_off(t);
}
if (nullptr != doc["burnperiod"]) {
uint8_t t = doc["burnperiod"];
set_burn_period(t);
}
if (nullptr != doc["burnminpower"]) {
uint8_t p = doc["burnminpower"];
set_min_power(p);
}
if (nullptr != doc["burnmaxpower"]) {
uint8_t p = doc["burnmaxpower"];
set_max_power(p);
}
if (nullptr != doc["pumpdelay"]) {
uint8_t t = doc["pumpdelay"];
set_pump_delay(t);
}
if (nullptr != doc["comfort"]) {
const char * data = doc["comfort"];
if (strcmp((char *)data, "hot") == 0) {
set_warmwater_mode(1);
} else if (strcmp((char *)data, "eco") == 0) {
set_warmwater_mode(2);
} else if (strcmp((char *)data, "intelligent") == 0) {
set_warmwater_mode(3);
}
}
const char * command = doc["cmd"];
if (command == nullptr) {
if (command == nullptr || doc["data"] == nullptr) {
return;
}
// boiler ww comfort setting
if (strcmp(command, "comfort") == 0) {
const char * data = doc["data"];
if (data == nullptr) {
return;
}
if (strcmp((char *)data, "hot") == 0) {
set_warmwater_mode(1);
} else if (strcmp((char *)data, "eco") == 0) {
@@ -131,36 +162,45 @@ void Boiler::boiler_cmd(const char * message) {
// boiler flowtemp setting
if (strcmp(command, "flowtemp") == 0) {
uint8_t t = doc["data"];
if (t) {
set_flow_temp(t);
}
set_flow_temp(t);
return;
}
// boiler temp setting
if (strcmp(command, "temp") == 0) {
if (strcmp(command, "wwtemp") == 0) {
uint8_t t = doc["data"];
if (t) {
set_temp(t);
}
set_warmwater_temp(t);
return;
}
// boiler max power setting
if (strcmp(command, "maxpower") == 0) {
if (strcmp(command, "burnmaxpower") == 0) {
uint8_t p = doc["data"];
if (p) {
set_max_power(p);
}
set_max_power(p);
return;
}
// boiler min power setting
if (strcmp(command, "minpower") == 0) {
if (strcmp(command, "burnminpower") == 0) {
uint8_t p = doc["data"];
if (p) {
set_min_power(p);
}
set_min_power(p);
return;
}
if (strcmp(command, "boilhyston") == 0) {
int8_t t = doc["data"];
set_hyst_on(t);
return;
}
if (strcmp(command, "boilhystoff") == 0) {
uint8_t t = doc["data"];
set_hyst_off(t);
return;
}
if (strcmp(command, "burnperiod") == 0) {
uint8_t t = doc["data"];
set_burn_period(t);
return;
}
if (strcmp(command, "pumpdelay") == 0) {
uint8_t t = doc["data"];
set_pump_delay(t);
return;
}
}
@@ -216,7 +256,7 @@ void Boiler::device_info(JsonArray & root) {
// publish values via MQTT
void Boiler::publish_values() {
const size_t capacity = JSON_OBJECT_SIZE(50); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/
const size_t capacity = JSON_OBJECT_SIZE(56); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/
DynamicJsonDocument doc(capacity);
char s[10]; // for formatting strings
@@ -328,7 +368,7 @@ void Boiler::publish_values() {
doc["flameCurr"] = (float)(int16_t)flameCurr_ / 10;
}
if (Helpers::hasValue(heatPmp_, VALUE_BOOL)) {
doc["heatPmp"] = Helpers::render_value(s, heatPmp_, EMS_VALUE_BOOL);
doc["heatPump"] = Helpers::render_value(s, heatPmp_, EMS_VALUE_BOOL);
}
if (Helpers::hasValue(fanWork_, VALUE_BOOL)) {
doc["fanWork"] = Helpers::render_value(s, fanWork_, EMS_VALUE_BOOL);
@@ -340,13 +380,37 @@ void Boiler::publish_values() {
doc["wWHeat"] = Helpers::render_value(s, wWHeat_, EMS_VALUE_BOOL);
}
if (Helpers::hasValue(heating_temp_)) {
doc["heating_temp"] = heating_temp_;
doc["heatingTemp"] = heating_temp_;
}
if (Helpers::hasValue(pump_mod_max_)) {
doc["pump_mod_max"] = pump_mod_max_;
doc["pumpModMax"] = pump_mod_max_;
}
if (Helpers::hasValue(pump_mod_min_)) {
doc["pump_mod_min"] = pump_mod_min_;
doc["pumpModMin"] = pump_mod_min_;
}
if (Helpers::hasValue(pumpDelay_)) {
doc["pumpDelay"] = pumpDelay_;
}
if (Helpers::hasValue(burnPeriod_)) {
doc["burnMinPeriod"] = burnPeriod_;
}
if (Helpers::hasValue(burnPowermin_)) {
doc["burnMinPower"] = burnPowermin_;
}
if (Helpers::hasValue(burnPowermax_)) {
doc["burnMaxPower"] = burnPowermax_;
}
if (Helpers::hasValue(boilTemp_on_)) {
doc["boilHystOn"] = boilTemp_on_;
}
if (Helpers::hasValue(boilTemp_off_)) {
doc["boilHystOff"] = boilTemp_off_;
}
if (Helpers::hasValue(setFlowTemp_)) {
doc["setFlowTemp"] = setFlowTemp_;
}
if (Helpers::hasValue(setWWPumpPow_)) {
doc["wWSetPumpPower"] = setWWPumpPow_;
}
if (Helpers::hasValue(wWStarts_)) {
doc["wWStarts"] = wWStarts_;
@@ -366,17 +430,6 @@ void Boiler::publish_values() {
if (Helpers::hasValue(heatWorkMin_)) {
doc["heatWorkMin"] = heatWorkMin_;
}
if (Helpers::hasValue(temp_)) {
doc["heatWorkMin"] = temp_;
}
if (Helpers::hasValue(maxpower_)) {
doc["heatWorkMin"] = maxpower_;
}
if (Helpers::hasValue(setpointpower_)) {
doc["heatWorkMin"] = setpointpower_;
}
if (Helpers::hasValue(serviceCode_)) {
doc["serviceCode"] = serviceCodeChar_;
doc["serviceCodeNumber"] = serviceCode_;
@@ -474,11 +527,17 @@ void Boiler::show_values(uuid::console::Shell & shell) {
print_value(shell, 2, F("Heating temperature setting on the boiler"), heating_temp_, F_(degrees));
print_value(shell, 2, F("Boiler circuit pump modulation max power"), pump_mod_max_, F_(percent));
print_value(shell, 2, F("Boiler circuit pump modulation min power"), pump_mod_min_, F_(percent));
print_value(shell, 2, F("Boiler circuit pump delay time"), pumpDelay_, F("min"));
print_value(shell, 2, F("Boiler temp hysteresis on"), boilTemp_on_, F_(degrees));
print_value(shell, 2, F("Boiler temp hysteresis off"), boilTemp_off_, F_(degrees));
print_value(shell, 2, F("Boiler burner min period"), burnPeriod_, F("min"));
print_value(shell, 2, F("Boiler burner min power"), burnPowermin_, F_(percent));
print_value(shell, 2, F("Boiler burner max power"), burnPowermax_, F_(percent));
// UBASetPoint - these may differ from the above
print_value(shell, 2, F("Boiler temp"), temp_, F_(degrees));
print_value(shell, 2, F("Max output power"), maxpower_, F_(percent));
print_value(shell, 2, F("Set power"), setpointpower_, F_(percent));
print_value(shell, 2, F("Set Flow temperature"), setFlowTemp_, F_(degrees));
print_value(shell, 2, F("Boiler burner set power"), setBurnPow_, F_(percent));
print_value(shell, 2, F("Warm Water pump set power"), setWWPumpPow_, F_(percent));
// UBAMonitorSlow
if (Helpers::hasValue(extTemp_)) {
@@ -591,6 +650,12 @@ void Boiler::process_UBATotalUptime(std::shared_ptr<const Telegram> telegram) {
*/
void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(heating_temp_, 1);
telegram->read_value(burnPowermax_,2);
telegram->read_value(burnPowermin_,3);
telegram->read_value(boilTemp_off_,4);
telegram->read_value(boilTemp_on_,5);
telegram->read_value(burnPeriod_,6);
telegram->read_value(pumpDelay_,8);
telegram->read_value(pump_mod_max_, 9);
telegram->read_value(pump_mod_min_, 10);
}
@@ -717,9 +782,9 @@ void Boiler::process_UBAOutdoorTemp(std::shared_ptr<const Telegram> telegram) {
// UBASetPoint 0x1A
void Boiler::process_UBASetPoints(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(temp_, 0); // boiler flow temp
telegram->read_value(maxpower_, 1); // max output power in %
telegram->read_value(setpointpower_, 14); // ww pump speed/power?
telegram->read_value(setFlowTemp_, 0); // boiler set temp from thermostat
telegram->read_value(setBurnPow_, 1); // max output power in %
telegram->read_value(setWWPumpPow_, 2); // ww pump speed/power?
}
#pragma GCC diagnostic push
@@ -766,12 +831,6 @@ void Boiler::set_flow_temp(const uint8_t temperature) {
write_command(EMS_TYPE_UBASetPoints, 0, temperature);
}
// set heating temp
void Boiler::set_temp(const uint8_t temperature) {
LOG_INFO(F("Setting boiler temperature to %d C"), temperature);
write_command(EMS_TYPE_UBAParameters, 1, temperature);
}
// set min boiler output
void Boiler::set_min_power(const uint8_t power) {
LOG_INFO(F("Setting boiler min power to "), power);
@@ -784,6 +843,30 @@ void Boiler::set_max_power(const uint8_t power) {
write_command(EMS_TYPE_UBAParameters, 2, power);
}
// set oiler on hysteresis
void Boiler::set_hyst_on(const uint8_t temp) {
LOG_INFO(F("Setting boiler hysteresis on to %d C"), temp);
write_command(EMS_TYPE_UBAParameters, 5, temp);
}
// set boiler off hysteresis
void Boiler::set_hyst_off(const uint8_t temp) {
LOG_INFO(F("Setting boiler hysteresis off to %d C"), temp);
write_command(EMS_TYPE_UBAParameters, 4, temp);
}
// set min burner period
void Boiler::set_burn_period(const uint8_t t) {
LOG_INFO(F("Setting burner min. period to %d min"), t);
write_command(EMS_TYPE_UBAParameters, 6, t);
}
// set pump delay
void Boiler::set_pump_delay(const uint8_t t) {
LOG_INFO(F("Setting boiler pump delay to %d min"), t);
write_command(EMS_TYPE_UBAParameters, 8, t);
}
// 1=hot, 2=eco, 3=intelligent
// note some boilers do not have this setting, than it's done by thermostat
// on a RC35 it's by EMSESP::send_write_request(0x37, 0x10, 2, &set, 1, 0); (set is 1,2,3)
@@ -888,14 +971,6 @@ void Boiler::console_commands(Shell & shell, unsigned int context) {
set_flow_temp(Helpers::atoint(arguments.front().c_str()));
});
EMSESPShell::commands->add_command(ShellContext::BOILER,
CommandFlags::ADMIN,
flash_string_vector{F_(temp)},
flash_string_vector{F_(degrees_mandatory)},
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
set_temp(Helpers::atoint(arguments.front().c_str()));
});
EMSESPShell::commands->add_command(ShellContext::BOILER,
CommandFlags::ADMIN,
flash_string_vector{F_(maxpower)},

View File

@@ -121,11 +121,17 @@ class Boiler : public EMSdevice {
uint8_t heating_temp_ = EMS_VALUE_UINT_NOTSET; // Heating temperature setting on the boiler
uint8_t pump_mod_max_ = EMS_VALUE_UINT_NOTSET; // Boiler circuit pump modulation max. power %
uint8_t pump_mod_min_ = EMS_VALUE_UINT_NOTSET; // Boiler circuit pump modulation min. power
uint8_t burnPowermin_ = EMS_VALUE_UINT_NOTSET;
uint8_t burnPowermax_ = EMS_VALUE_UINT_NOTSET;
int8_t boilTemp_off_ = EMS_VALUE_INT_NOTSET;
int8_t boilTemp_on_ = EMS_VALUE_UINT_NOTSET;
uint8_t burnPeriod_ = EMS_VALUE_UINT_NOTSET;
uint8_t pumpDelay_ = EMS_VALUE_UINT_NOTSET;
// UBASetPoint
uint8_t temp_ = EMS_VALUE_UINT_NOTSET; // boiler flow temp
uint8_t maxpower_ = EMS_VALUE_UINT_NOTSET; // max output power in %
uint8_t setpointpower_ = EMS_VALUE_UINT_NOTSET; // ww pump speed/power?
uint8_t setFlowTemp_ = EMS_VALUE_UINT_NOTSET; // boiler setpoint temp
uint8_t setBurnPow_ = EMS_VALUE_UINT_NOTSET; // max output power in %
uint8_t setWWPumpPow_ = EMS_VALUE_UINT_NOTSET; // ww pump speed/power?
// other internal calculated params
uint8_t tap_water_active_ = EMS_VALUE_BOOL_NOTSET; // Hot tap water is on/off
@@ -161,9 +167,12 @@ class Boiler : public EMSdevice {
void set_tapwarmwater_activated(const bool activated);
void set_warmwater_onetime(const bool activated);
void set_warmwater_circulation(const bool activated);
void set_temp(const uint8_t temperature);
void set_min_power(const uint8_t power);
void set_max_power(const uint8_t power);
void set_hyst_on(const uint8_t temp);
void set_hyst_off(const uint8_t temp);
void set_burn_period(const uint8_t t);
void set_pump_delay(const uint8_t t);
// mqtt callbacks

View File

@@ -266,11 +266,14 @@ void Solar::process_ISM1StatusMessage(std::shared_ptr<const Telegram> telegram)
if (Wh != 0xFFFF) {
energyLastHour_ = Wh * 10; // set to *10
}
telegram->read_bitvalue(pump_, 8, 0); // Solar pump on (1) or off (0)
telegram->read_value(pumpWorkMin_, 10, 3); // force to 3 bytes
telegram->read_bitvalue(collectorOnOff_, 9, 0); // collector shutdown on/off
telegram->read_bitvalue(tankHeated_, 9, 2); // tank full
}
/*
* Junkers ISM1 Solar Module - type 0x0101 EMS+ for setting values
* e.g. 90 30 FF 06 00 01 50
*/
void Solar::process_ISM1Set(std::shared_ptr<const Telegram> telegram) {

View File

@@ -207,7 +207,17 @@ void Thermostat::device_info(JsonArray & root) {
std::string mode_str(15, '\0');
snprintf_P(&mode_str[0], mode_str.capacity() + 1, PSTR("%sMode"), hc_str.c_str());
dataElement["name"] = mode_str;
dataElement["value"] = mode_tostring(hc->get_mode(flags));
std::string modetype_str(20, '\0');
if (Helpers::hasValue(hc->summer_mode) && hc->summer_mode) {
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - summer"), mode_tostring(hc->get_mode(flags)).c_str());
} else if (Helpers::hasValue(hc->holiday_mode) && hc->holiday_mode) {
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - holiday"), mode_tostring(hc->get_mode(flags)).c_str());
} else if (Helpers::hasValue(hc->mode_type)) {
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, PSTR("%s - %s"), mode_tostring(hc->get_mode(flags)).c_str(), mode_tostring(hc->get_mode_type(flags)).c_str());
} else {
snprintf_P(&modetype_str[0], modetype_str.capacity() + 1, mode_tostring(hc->get_mode(flags)).c_str());
}
dataElement["value"] = modetype_str;
}
}
}
@@ -301,7 +311,7 @@ void Thermostat::thermostat_cmd(const char * message) {
set_holiday(holiday.c_str(), hc_num);
}
}
// commands without heatingcircuit
if (nullptr != doc["wwmode"]) {
std::string mode = doc["wwmode"];
set_ww_mode(mode);
@@ -406,10 +416,10 @@ void Thermostat::thermostat_cmd(const char * message) {
// check for commands like {"hc":2,"cmd":"temp","data":21}
const char * command = doc["cmd"];
if (command == nullptr) {
if (command == nullptr || doc["data"] == nullptr) {
return;
}
// ok, we have command and data
if (strcmp(command, "temp") == 0) {
float f = doc["data"];
if (f) {
@@ -595,7 +605,8 @@ void Thermostat::publish_values() {
}
// send this specific data using the thermostat_data topic
if ((mqtt_format_ == MQTT_format::SINGLE) || (mqtt_format_ == MQTT_format::HA)) {
// if ((mqtt_format_ == MQTT_format::SINGLE) || (mqtt_format_ == MQTT_format::HA)) {
if (mqtt_format_ != MQTT_format::NESTED) {
Mqtt::publish("thermostat_data", doc);
rootThermostat = doc.to<JsonObject>(); // clear object
}
@@ -609,7 +620,8 @@ void Thermostat::publish_values() {
has_data = true;
// if the MQTT format is 'nested' or 'ha' then create the parent object hc<n>
if (mqtt_format_ != MQTT_format::SINGLE) {
// if (mqtt_format_ != MQTT_format::SINGLE) {
if ((mqtt_format_ == MQTT_format::NESTED) || (mqtt_format_ == MQTT_format::HA)) {
char hc_name[10]; // hc{1-4}
strlcpy(hc_name, "hc", 10);
char s[3];
@@ -698,7 +710,8 @@ void Thermostat::publish_values() {
// if format is single, send immediately and clear object for next hc
// the topic will have the hc number appended
if (mqtt_format_ == MQTT_format::SINGLE) {
// if (mqtt_format_ == MQTT_format::SINGLE) {
if ((mqtt_format_ == MQTT_format::SINGLE) || (mqtt_format_ == MQTT_format::CUSTOM)) {
char topic[30];
char s[3];
strlcpy(topic, "thermostat_data", 30);
@@ -717,10 +730,9 @@ void Thermostat::publish_values() {
}
// if we're using nested json, send all in one go under one topic called thermostat_data
// if ((mqtt_format_ == MQTT_format::NESTED) || (mqtt_format_ == MQTT_format::CUSTOM)) {
if (mqtt_format_ == MQTT_format::NESTED) {
Mqtt::publish("thermostat_data", doc);
} else if (mqtt_format_ == MQTT_format::CUSTOM) {
Mqtt::publish("thermostat_data", doc);
}
}
@@ -1030,7 +1042,7 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
shell.printfln(F(" Display: time"));
} else if (ibaMainDisplay_ == 7) {
shell.printfln(F(" Display: date"));
} else if (ibaMainDisplay_ == 9) {
} else if (ibaMainDisplay_ == 8) {
shell.printfln(F(" Display: smoke temperature"));
}
}
@@ -1209,7 +1221,7 @@ void Thermostat::process_EasyMonitor(std::shared_ptr<const Telegram> telegram) {
void Thermostat::process_IBASettings(std::shared_ptr<const Telegram> telegram) {
// 22 - display line on RC35
telegram->read_value(ibaMainDisplay_,
0); // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 9 smoke temp
0); // display on Thermostat: 0 int. temp, 1 int. setpoint, 2 ext. temp., 3 burner temp., 4 ww temp, 5 functioning mode, 6 time, 7 data, 8 smoke temp
telegram->read_value(ibaLanguage_, 1); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian
telegram->read_value(ibaCalIntTemperature_, 2); // offset int. temperature sensor, by * 0.1 Kelvin
telegram->read_value(ibaBuildingType_, 6); // building type: 0 = light, 1 = medium, 2 = heavy
@@ -1351,11 +1363,16 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
if (flags() == EMS_DEVICE_FLAG_EASY) {
return; // not supported
}
if (telegram->message_length < 7) {
return;
}
if (telegram->message_data[7] & 0x0C) { // date and time not valid
set_datetime("NTP"); // set from NTP
return;
}
if (datetime_.empty()) {
datetime_.resize(25, '\0');
}
// render time to HH:MM:SS DD/MM/YYYY
// had to create separate buffers because of how printf works
char buf1[6];
@@ -1510,18 +1527,38 @@ void Thermostat::set_party(const uint8_t hrs, const uint8_t hc_num) {
}
}
// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst
// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst or "NTP" for setting to internet-time
// dw - day of week (0..6), dst- summertime (0/1)
void Thermostat::set_datetime(const char * dt) {
uint8_t data[9];
data[0] = (dt[16] - '0') * 100 + (dt[17] - '0') * 10 + (dt[18] - '0'); // year
data[1] = (dt[12] - '0') * 10 + (dt[13] - '0'); // month
data[2] = (dt[0] - '0') * 10 + (dt[1] - '0'); // hour
data[3] = (dt[9] - '0') * 10 + (dt[10] - '0'); // day
data[4] = (dt[3] - '0') * 10 + (dt[4] - '0'); // min
data[5] = (dt[6] - '0') * 10 + (dt[7] - '0'); // sec
data[6] = (dt[20] - '0'); // day of week
data[7] = (dt[22] - '0'); // summerime
if (strcmp(dt,"NTP") == 0) {
time_t now = time(nullptr);
tm * tm_ = localtime(&now);
if (tm_->tm_year < 110) { // no NTP time
LOG_WARNING(F("No NTP time. Cannot set RCtime"));
return;
}
data[0] = tm_->tm_year - 100; // Bosch counts from 2000
data[1] = tm_->tm_mon;
data[2] = tm_->tm_hour;
data[3] = tm_->tm_mday;
data[4] = tm_->tm_min;
data[5] = tm_->tm_sec;
data[6] = (tm_->tm_wday + 6) % 7; // Bosch counts from Mo, time from Su
data[7] = tm_->tm_isdst + 2; // set DST and flag for ext. clock
char time_string[25];
strftime(time_string, 25, "%FT%T%z", tm_);
LOG_INFO(F("Date and time: %s"), time_string);
} else {
data[0] = (dt[16] - '0') * 100 + (dt[17] - '0') * 10 + (dt[18] - '0'); // year
data[1] = (dt[12] - '0') * 10 + (dt[13] - '0'); // month
data[2] = (dt[0] - '0') * 10 + (dt[1] - '0'); // hour
data[3] = (dt[9] - '0') * 10 + (dt[10] - '0'); // day
data[4] = (dt[3] - '0') * 10 + (dt[4] - '0'); // min
data[5] = (dt[6] - '0') * 10 + (dt[7] - '0'); // sec
data[6] = (dt[20] - '0'); // day of week
data[7] = (dt[22] - '0') + 2; // DST and flag
}
if ((flags() & 0x0F) == EMS_DEVICE_FLAG_RC35 || (flags() & 0x0F) == EMS_DEVICE_FLAG_RC30_1) {
LOG_INFO(F("Setting date and time"));
write_command(6, 0, data, 8, 0);

View File

@@ -31,6 +31,7 @@
#include "mqtt.h"
#include <vector>
#include <time.h>
namespace emsesp {

View File

@@ -23,6 +23,12 @@
MAKE_PSTR(logger_name, "sensors")
#ifdef ESP32
#define YIELD
#else
#define YIELD yield()
#endif
namespace emsesp {
uuid::log::Logger Sensors::logger_{F_(logger_name), uuid::log::Facility::DAEMON};
@@ -63,7 +69,7 @@ void Sensors::loop() {
if (time_now - last_activity_ >= READ_INTERVAL_MS) {
// LOG_DEBUG(F("Read sensor temperature")); // uncomment for debug
if (bus_.reset()) {
yield();
YIELD;
bus_.skip();
bus_.write(CMD_CONVERT_TEMP);
@@ -155,17 +161,17 @@ float Sensors::get_temperature_c(const uint8_t addr[]) {
LOG_ERROR(F("Bus reset failed before reading scratchpad from %s"), Device(addr).to_string().c_str());
return NAN;
}
yield();
YIELD;
uint8_t scratchpad[SCRATCHPAD_LEN] = {0};
bus_.select(addr);
bus_.write(CMD_READ_SCRATCHPAD);
bus_.read_bytes(scratchpad, SCRATCHPAD_LEN);
yield();
YIELD;
if (!bus_.reset()) {
LOG_ERROR(F("Bus reset failed after reading scratchpad from %s"), Device(addr).to_string().c_str());
return NAN;
}
yield();
YIELD;
if (bus_.crc8(scratchpad, SCRATCHPAD_LEN - 1) != scratchpad[SCRATCHPAD_LEN - 1]) {
LOG_WARNING(F("Invalid scratchpad CRC: %02X%02X%02X%02X%02X%02X%02X%02X%02X from device %s"),
scratchpad[0],
@@ -202,7 +208,8 @@ float Sensors::get_temperature_c(const uint8_t addr[]) {
break;
}
return (float)raw_value / 16;
uint32_t raw = (raw_value *625) / 100; // round to 0.01
return (float)raw / 100;
#else
return NAN;
#endif

View File

@@ -34,8 +34,8 @@ static hw_timer_t * timer = NULL;
bool drop_next_rx = true;
uint8_t tx_mode_ = 0xFF;
uint8_t emsTxBuf[EMS_MAXBUFFERSIZE];
uint8_t emsTxBufIdx;
uint8_t emsTxBufLen;
uint8_t emsTxBufIdx = 0;
uint8_t emsTxBufLen = 0;
uint32_t emsTxWait;
/*
@@ -88,12 +88,15 @@ void IRAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
portENTER_CRITICAL(&mux);
if (emsTxBufIdx < emsTxBufLen) {
EMS_UART.fifo.rw_byte = emsTxBuf[emsTxBufIdx];
timerAlarmWrite(timer, emsTxWait, true);
if (emsTxBufIdx == 1) {
timerAlarmWrite(timer, emsTxWait, true);
}
} else if (emsTxBufIdx == emsTxBufLen) {
EMS_UART.conf0.txd_inv = 1;
timerAlarmWrite(timer, EMSUART_TX_WAIT_BRK, true);
timerAlarmWrite(timer, EMSUART_TX_BRK_TIMER, true);
} else if (emsTxBufIdx == emsTxBufLen + 1) {
EMS_UART.conf0.txd_inv = 0;
emsTxBufLen = 0;
timerAlarmDisable(timer);
}
emsTxBufIdx++;
@@ -130,7 +133,7 @@ void EMSuart::start(const uint8_t tx_mode) {
xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, configMAX_PRIORITIES - 1, NULL);
timer = timerBegin(0, 80, true); // timer prescale to 1 us, countup
timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, false); // Timer with level interrupt
timerAttachInterrupt(timer, &emsuart_tx_timer_intr_handler, true); // Timer with edge interrupt
restart();
}
@@ -140,6 +143,9 @@ void EMSuart::start(const uint8_t tx_mode) {
void EMSuart::stop() {
EMS_UART.int_ena.val = 0; // disable all intr.
EMS_UART.conf0.txd_inv = 0; // stop break
if (emsTxBufLen > 0) {
timerAlarmDisable(timer);
}
};
/*
@@ -165,44 +171,11 @@ void EMSuart::restart() {
}
}
/*
* Sends a 11-bit break by inverting the tx-port
*/
void EMSuart::tx_brk() {
EMS_UART.conf0.txd_inv = 1;
delayMicroseconds(EMSUART_TX_WAIT_BRK);
EMS_UART.conf0.txd_inv = 0;
}
/*
* Sends a 1-byte poll, ending with a <BRK>
*/
void EMSuart::send_poll(const uint8_t data) {
if (tx_mode_ > 5) { // timer controlled modes
emsTxBuf[0] = data;
emsTxBufIdx = 0;
emsTxBufLen = 1;
timerAlarmWrite(timer, emsTxWait, true); // start timer with autoreload
timerAlarmEnable(timer); // first interrupt comes immediately
} else if (tx_mode_ == EMS_TXMODE_DEFAULT) {
volatile uint8_t _usrxc = EMS_UART.status.rxfifo_cnt;
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
EMS_UART.fifo.rw_byte = data;
while ((EMS_UART.status.rxfifo_cnt == _usrxc) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT);
}
tx_brk();
} else if (tx_mode_ == EMS_TXMODE_EMSPLUS) {
EMS_UART.fifo.rw_byte = data;
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
tx_brk();
} else if (tx_mode_ == EMS_TXMODE_HT3) {
EMS_UART.fifo.rw_byte = data;
delayMicroseconds(EMSUART_TX_WAIT_HT3);
tx_brk();
} else {
EMS_UART.fifo.rw_byte = data;
}
transmit(&data, 1);
}
/*
@@ -221,7 +194,7 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
}
emsTxBufIdx = 0;
emsTxBufLen = len;
if (tx_mode_ > 100) {
if (tx_mode_ > 100 && len > 1) {
timerAlarmWrite(timer, EMSUART_TX_WAIT_REPLY, true);
} else {
timerAlarmWrite(timer, emsTxWait, true); // start with autoreload
@@ -242,7 +215,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
EMS_UART.fifo.rw_byte = buf[i];
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
}
tx_brk();
EMS_UART.conf0.txd_inv = 1; // send <brk>
delayMicroseconds(EMSUART_TX_BRK_PLUS);
EMS_UART.conf0.txd_inv = 0;
return EMS_TX_STATUS_OK;
}
@@ -251,11 +226,13 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
EMS_UART.fifo.rw_byte = buf[i];
delayMicroseconds(EMSUART_TX_WAIT_HT3);
}
tx_brk();
EMS_UART.conf0.txd_inv = 1; // send <brk>
delayMicroseconds(EMSUART_TX_BRK_HT3);
EMS_UART.conf0.txd_inv = 0;
return EMS_TX_STATUS_OK;
}
// mode 1
// mode 1: wait for echo after each byte
// flush fifos -- not supported in ESP32 uart #2!
// EMS_UART.conf0.rxfifo_rst = 1;
// EMS_UART.conf0.txfifo_rst = 1;
@@ -267,7 +244,9 @@ uint16_t EMSuart::transmit(const uint8_t * buf, const uint8_t len) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
}
}
tx_brk();
EMS_UART.conf0.txd_inv = 1;
delayMicroseconds(EMSUART_TX_BRK_EMS);
EMS_UART.conf0.txd_inv = 0;
return EMS_TX_STATUS_OK;
}

View File

@@ -46,20 +46,25 @@
#define EMS_TXMODE_NEW 4 // for michael's testing
// LEGACY
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud
#define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 10) // 10 bt
#define EMSUART_TX_WAIT_REPLY 100000 // delay 100ms after first byte
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud
// Timer controlled modes
#define EMSUART_TX_BRK_TIMER (EMSUART_TX_BIT_TIME * 10 + 28) // 10.25 bit times
#define EMSUART_TX_WAIT_REPLY 100000 // delay 100ms after first byte
// EMS 1.0
#define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13
#define EMSUART_TX_TIMEOUT (32 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 256
#define EMSUART_TX_TIMEOUT (20 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT)
#define EMSUART_TX_BRK_EMS (EMSUART_TX_BIT_TIME * 10)
// HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation.
// since we use a faster processor the lag is negligible
#define EMSUART_TX_WAIT_HT3 (EMSUART_TX_BIT_TIME * 17) // 1768
#define EMSUART_TX_BRK_HT3 (EMSUART_TX_BIT_TIME * 11)
// EMS+ - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) and delay of another Bytetime.
#define EMSUART_TX_WAIT_PLUS (EMSUART_TX_BIT_TIME * 20) // 2080
#define EMSUART_TX_BRK_PLUS (EMSUART_TX_BIT_TIME * 11)
// customize the GPIO pins for RX and TX here
@@ -91,7 +96,6 @@ class EMSuart {
static void emsuart_recvTask(void * para);
static void IRAM_ATTR emsuart_rx_intr_handler(void * para);
static void IRAM_ATTR emsuart_tx_timer_intr_handler();
static void tx_brk();
};
} // namespace emsesp

View File

@@ -95,10 +95,10 @@ void ICACHE_RAM_ATTR EMSuart::emsuart_tx_timer_intr_handler() {
timer1_write(emsTxWait);
} else if (emsTxBufIdx == emsTxBufLen) {
USC0(EMSUART_UART) |= (1 << UCBRK); // set <BRK>
timer1_write(EMSUART_TX_WAIT_BRK * 5);
timer1_write(EMSUART_TX_BRK_TIMER);
} else {
USC0(EMSUART_UART) &= ~(1 << UCBRK); // reset <BRK>
sending_ = false;
sending_ = false;
}
}
@@ -114,11 +114,6 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() {
* init UART0 driver
*/
void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
if (tx_mode_ > 100) {
emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode - 90);
} else {
emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode + 10); // bittimes wait to next bytes
}
if (tx_mode_ != 0xFF) { // it's a restart no need to configure uart
tx_mode_ = tx_mode;
restart();
@@ -133,7 +128,6 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
}
pEMSRxBuf = paEMSRxBuf[0]; // reset EMS Rx Buffer
ETS_UART_INTR_DISABLE();
ETS_UART_INTR_ATTACH(nullptr, nullptr);
// pin settings
@@ -153,22 +147,14 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
// 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
//
// change: we set UCFFT to 1 to get an immediate indicator about incoming traffic.
// Otherwise, we're only noticed by UCTOT or RxBRK!
// change: don't care, we do not use these interrupts
USC1(EMSUART_UART) = 0; // reset config first
USC1(EMSUART_UART) = 0; // reset config
// USC1(EMSUART_UART) = (0x7F << UCFFT) | (0x01 << UCTOT) | (1 << UCTOE); // enable interupts
// set interrupts for triggers
USIC(EMSUART_UART) = 0xFFFF; // clear all interupts
USIE(EMSUART_UART) = 0; // disable all interrupts
// enable rx break, fifo full and timeout.
// but not frame error UIFR (because they are too frequent) or overflow UIOF because our buffer is only max 32 bytes
// change: we don't care about Rx Timeout - it may lead to wrong readouts
// change:we don't care about Fifo full and read only on break-detect
USIE(EMSUART_UART) = (1 << UIBD) | (0 << UIFF) | (0 << UITO);
// set up interrupt callbacks for Rx
system_os_task(emsuart_recvTask, EMSUART_recvTaskPrio, recvTaskQueue, EMSUART_recvTaskQueueLen);
@@ -182,10 +168,9 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
drop_next_rx = true;
// for sending with large delay in EMS+ mode we use a timer interrupt
timer1_attachInterrupt(emsuart_tx_timer_intr_handler); // Add ISR Function
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE); // 5 MHz timer
ETS_UART_INTR_ENABLE();
USIE(EMSUART_UART) = (1 << UIBD);
timer1_attachInterrupt(emsuart_tx_timer_intr_handler);
restart();
}
/*
@@ -204,67 +189,25 @@ void ICACHE_FLASH_ATTR EMSuart::stop() {
*/
void ICACHE_FLASH_ATTR EMSuart::restart() {
if (USIR(EMSUART_UART) & ((1 << UIBD))) {
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the <brk> detect interrupt
drop_next_rx = true;
}
if (tx_mode_ > 100) {
emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode_ - 90);
} else {
emsTxWait = 5 * EMSUART_TX_BIT_TIME * (tx_mode_ + 10); // bittimes wait to next bytes
}
emsTxBufIdx = 0;
emsTxBufLen = 0;
timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);
USIE(EMSUART_UART) = (1 << UIBD);
}
/*
* Send a BRK signal
* Which is a 11-bit set of zero's (11 cycles)
*/
void ICACHE_FLASH_ATTR EMSuart::tx_brk() {
// make sure Tx FIFO is empty
while (((USS(EMSUART_UART) >> USTXC) & 0xFF)) {
}
USC0(EMSUART_UART) |= (1 << UCBRK); // set bit
// also for EMS+ there is no need to wait longer, we are finished and can free the bus.
delayMicroseconds(EMSUART_TX_WAIT_BRK); // 1144
USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear BRK bit
USIE(EMSUART_UART) = (1 << UIBD); // enable <brk> interrupt
}
/*
* Sends a 1-byte poll, ending with a <BRK>
* It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking
*/
void EMSuart::send_poll(uint8_t data) {
// reset tx-brk, just in case it is accidentally set
USC0(EMSUART_UART) &= ~(1 << UCBRK);
sending_ = true;
if (tx_mode_ >= 5) { // timer controlled modes
emsTxBuf[0] = data;
emsTxBufIdx = 0;
emsTxBufLen = 1;
timer1_write(emsTxWait);
} else if (tx_mode_ == EMS_TXMODE_NEW) { // hardware controlled modes
USF(EMSUART_UART) = data;
USC0(EMSUART_UART) |= (1 << UCBRK);
} else if (tx_mode_ == EMS_TXMODE_HT3) {
USF(EMSUART_UART) = data;
delayMicroseconds(EMSUART_TX_WAIT_HT3);
tx_brk(); // send <BRK>
sending_ = false;
} else if (tx_mode_ == EMS_TXMODE_EMSPLUS) {
USF(EMSUART_UART) = data;
delayMicroseconds(EMSUART_TX_WAIT_PLUS);
tx_brk(); // send <BRK>
sending_ = false;
} else {
// tx_mode 1
volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF;
USF(EMSUART_UART) = data;
uint16_t timeoutcnt = EMSUART_TX_TIMEOUT;
while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) && (--timeoutcnt > 0)) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
}
tx_brk(); // send <BRK>
sending_ = false;
}
void ICACHE_FLASH_ATTR EMSuart::send_poll(uint8_t data) {
transmit(&data, 1);
}
/*
@@ -276,20 +219,18 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
if (len == 0 || len >= EMS_MAXBUFFERSIZE) {
return EMS_TX_STATUS_ERR; // nothing or to much to send
}
// reset tx-brk, just in case it is accidentally set
USC0(EMSUART_UART) &= ~(1 << UCBRK);
sending_ = true;
// timer controlled modes with extra delay
if (tx_mode_ >= 5) {
sending_ = true;
for (uint8_t i = 0; i < len; i++) {
emsTxBuf[i] = buf[i];
}
USF(EMSUART_UART) = buf[0]; // send first byte
emsTxBufIdx = 0;
emsTxBufLen = len;
if (tx_mode_ > 100) {
timer1_write(EMSUART_TX_WAIT_REPLY);
if (tx_mode_ > 100 && len > 1) {
timer1_write(EMSUART_TX_WAIT_REPLY); // large delay after first byte
} else {
timer1_write(emsTxWait);
}
@@ -301,7 +242,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
for (uint8_t i = 0; i < len; i++) {
USF(EMSUART_UART) = buf[i];
}
USC0(EMSUART_UART) |= (1 << UCBRK); // send <BRK> at the end
USC0(EMSUART_UART) |= (1 << UCBRK); // send <BRK> at the end, clear by interrupt
return EMS_TX_STATUS_OK;
}
@@ -311,8 +252,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
USF(EMSUART_UART) = buf[i];
delayMicroseconds(EMSUART_TX_WAIT_PLUS); // 2070
}
tx_brk(); // send <BRK>
sending_ = false;
USC0(EMSUART_UART) |= (1 << UCBRK); // set break
delayMicroseconds(EMSUART_TX_BRK_PLUS);
USC0(EMSUART_UART) &= ~(1 << UCBRK);
return EMS_TX_STATUS_OK;
}
@@ -326,8 +268,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
// wait until bits are sent on wire
delayMicroseconds(EMSUART_TX_WAIT_HT3);
}
tx_brk(); // send <BRK>
sending_ = false;
USC0(EMSUART_UART) |= (1 << UCBRK); // set break bit
delayMicroseconds(EMSUART_TX_BRK_HT3);
USC0(EMSUART_UART) &= ~(1 << UCBRK);
return EMS_TX_STATUS_OK;
}
@@ -356,9 +299,7 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
*
*/
// disable rx interrupt
// clear Rx status register, resetting the Rx FIFO and flush it
// ETS_UART_INTR_DISABLE();
emsuart_flush_fifos();
// send the bytes along the serial line
@@ -371,18 +312,9 @@ uint16_t ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
delayMicroseconds(EMSUART_TX_BUSY_WAIT); // burn CPU cycles...
}
}
// we got the whole telegram in the Rx buffer
// on Rx-BRK (bus collision), we simply enable Rx and leave it
// otherwise we send the final Tx-BRK
// worst case, we'll see an additional Rx-BRK...
// neither bus collision nor timeout - send terminating BRK signal
if (!(USIS(EMSUART_UART) & (1 << UIBD))) {
// no bus collision - send terminating BRK signal
tx_brk();
}
// ETS_UART_INTR_ENABLE(); // open up the FIFO again to start receiving
sending_ = false;
USC0(EMSUART_UART) |= (1 << UCBRK); // snd break
delayMicroseconds(EMSUART_TX_BRK_EMS);
USC0(EMSUART_UART) &= ~(1 << UCBRK);
return EMS_TX_STATUS_OK; // send the Tx ok status back
}

View File

@@ -40,22 +40,26 @@
#define EMS_TXMODE_NEW 4 // for michael's testing
// LEGACY
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud
#define EMSUART_TX_WAIT_BRK (EMSUART_TX_BIT_TIME * 10)
#define EMSUART_TX_WAIT_REPLY 500000 // delay 100ms after first byte
#define EMSUART_TX_BIT_TIME 104 // bit time @9600 baud
// TIMER modes
#define EMSUART_TX_BRK_TIMER (EMSUART_TX_BIT_TIME * 52) // > 10 bittimes for timer modes
#define EMSUART_TX_WAIT_REPLY 500000 // delay 100ms after first byte
// EMS 1.0
#define EMSUART_TX_BUSY_WAIT (EMSUART_TX_BIT_TIME / 8) // 13
// #define EMSUART_TX_TIMEOUT (22 * EMSUART_TX_BIT_TIME / EMSUART_TX_BUSY_WAIT) // 176
// #define EMSUART_TX_TIMEOUT (32 * 8) // 256 for tx_mode 1 - see https://github.com/proddy/EMS-ESP/issues/398#issuecomment-645886277
#define EMSUART_TX_TIMEOUT (220 * 8) // 1760 as in v1.9 (180 ms)
#define EMSUART_TX_BRK_EMS (EMSUART_TX_BIT_TIME * 10)
// HT3/Junkers - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) plus 7 bit delay. The -8 is for lag compensation.
// since we use a faster processor the lag is negligible
#define EMSUART_TX_WAIT_HT3 (EMSUART_TX_BIT_TIME * 17) // 1768
#define EMSUART_TX_BRK_HT3 (EMSUART_TX_BIT_TIME * 11)
// EMS+ - Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) and delay of another Bytetime.
#define EMSUART_TX_WAIT_PLUS (EMSUART_TX_BIT_TIME * 20) // 2080
#define EMSUART_TX_BRK_PLUS (EMSUART_TX_BIT_TIME * 11)
namespace emsesp {
@@ -85,7 +89,6 @@ class EMSuart {
static void ICACHE_RAM_ATTR emsuart_rx_intr_handler(void * para);
static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events);
static void ICACHE_FLASH_ATTR emsuart_flush_fifos();
static void ICACHE_FLASH_ATTR tx_brk();
static void ICACHE_RAM_ATTR emsuart_tx_timer_intr_handler();
static bool sending_;
};