mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 16:29:51 +03:00
michael's updates
This commit is contained in:
@@ -228,7 +228,7 @@ std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegr
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const auto & tf : telegram_functions_) {
|
for (const auto & tf : telegram_functions_) {
|
||||||
if ((tf.telegram_type_id_ & 0x7F) == (telegram->type_id & 0x7F)) {
|
if (tf.telegram_type_id_ == (telegram->type_id && ((telegram->type_id & 0xF0) != 0xF0))) {
|
||||||
return uuid::read_flash_string(tf.telegram_type_name_);
|
return uuid::read_flash_string(tf.telegram_type_name_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,11 +66,6 @@ uint32_t EMSESP::last_fetch_ = 0;
|
|||||||
#include "test/test_data.h" // used with the 'test' command, under su/admin
|
#include "test/test_data.h" // used with the 'test' command, under su/admin
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// for each associated EMS device go and request its data values
|
|
||||||
void EMSESP::fetch_device_values() {
|
|
||||||
fetch_device_values(0); // 0 = fetch all
|
|
||||||
}
|
|
||||||
|
|
||||||
// for a specific EMS device go and request data values
|
// for a specific EMS device go and request data values
|
||||||
// or if device_id is 0 it will fetch from all known devices
|
// or if device_id is 0 it will fetch from all known devices
|
||||||
void EMSESP::fetch_device_values(const uint8_t device_id) {
|
void EMSESP::fetch_device_values(const uint8_t device_id) {
|
||||||
@@ -422,7 +417,7 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
|
|||||||
if (emsdevice) {
|
if (emsdevice) {
|
||||||
if (emsdevice->is_device_id(telegram->src)) {
|
if (emsdevice->is_device_id(telegram->src)) {
|
||||||
found = emsdevice->handle_telegram(telegram);
|
found = emsdevice->handle_telegram(telegram);
|
||||||
// check to see if we need to force an MQTT publish
|
// check to see if we need to follow up after the telegram has been processed
|
||||||
if (found) {
|
if (found) {
|
||||||
if (emsdevice->updated_values()) {
|
if (emsdevice->updated_values()) {
|
||||||
emsdevice->publish_values(); // publish to MQTT if we explicitly have too
|
emsdevice->publish_values(); // publish to MQTT if we explicitly have too
|
||||||
|
|||||||
@@ -123,8 +123,7 @@ class EMSESP {
|
|||||||
|
|
||||||
static void console_commands(Shell & shell, unsigned int context);
|
static void console_commands(Shell & shell, unsigned int context);
|
||||||
|
|
||||||
static void fetch_device_values(const uint8_t device_id);
|
static void fetch_device_values(const uint8_t device_id = 0);
|
||||||
static void fetch_device_values();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EMSESP() = delete;
|
EMSESP() = delete;
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ class Settings {
|
|||||||
uint8_t master_thermostat() const;
|
uint8_t master_thermostat() const;
|
||||||
void master_thermostat(const uint8_t & master_thermostat);
|
void master_thermostat(const uint8_t & master_thermostat);
|
||||||
|
|
||||||
enum MQTT_format : uint8_t { SINGLE = 1, NESTED, HA };
|
enum MQTT_format : uint8_t { SINGLE = 1, NESTED, HA, CUSTOM };
|
||||||
uint8_t mqtt_format() const;
|
uint8_t mqtt_format() const;
|
||||||
void mqtt_format(const uint8_t & mqtt_format);
|
void mqtt_format(const uint8_t & mqtt_format);
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,16 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i
|
|||||||
} else {
|
} else {
|
||||||
LOG_DEBUG(F("Registering new thermostat with device ID 0x%02X"), device_id);
|
LOG_DEBUG(F("Registering new thermostat with device ID 0x%02X"), device_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// for the thermostat, go a query all the heating circuits. This is only done once. The automatic fetch will from now on
|
||||||
|
// only update the active heating circuits
|
||||||
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
|
EMSESP::send_read_request(set_typeids[i], device_id);
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < monitor_typeids.size(); i++) {
|
||||||
|
EMSESP::send_read_request(monitor_typeids[i], device_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// for the master thermostat initialize the MQTT subscribes
|
// for the master thermostat initialize the MQTT subscribes
|
||||||
@@ -222,6 +232,48 @@ void Thermostat::thermostat_cmd(const char * message) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto & hc : heating_circuits_) {
|
||||||
|
char hc_name[6], s[3]; // hc{1-4}
|
||||||
|
strlcpy(hc_name, "hc", 6);
|
||||||
|
uint8_t hc_num = hc->hc_num();
|
||||||
|
strlcat(hc_name, Helpers::itoa(s, hc_num), 6);
|
||||||
|
if (nullptr != doc[hc_name]["mode"]) {
|
||||||
|
std::string mode = doc[hc_name]["mode"]; // first check mode
|
||||||
|
set_mode(mode, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["temp"]) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::AUTO, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["nighttemp"]) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::NIGHT, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["daytemp"]) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::DAY, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["nofrosttemp"]) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::NOFROST, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["summertemp"]) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::SUMMER, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["designtemp"]) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::DESIGN, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["offsettemp"]) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["holidaytemp"]) { //
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::HOLIDAY, hc_num);
|
||||||
|
}
|
||||||
|
if (float f = doc[hc_name]["remotetemp"]) {
|
||||||
|
if (f > 100 || f < 0) {
|
||||||
|
hc->remotetemp = EMS_VALUE_SHORT_NOTSET;
|
||||||
|
} else {
|
||||||
|
hc->remotetemp = (uint16_t)(f * 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char * command = doc["cmd"];
|
const char * command = doc["cmd"];
|
||||||
if (command == nullptr) {
|
if (command == nullptr) {
|
||||||
return;
|
return;
|
||||||
@@ -301,6 +353,27 @@ void Thermostat::thermostat_cmd(const char * message) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (strcmp(command, "summertemp") == 0) {
|
||||||
|
float f = doc["data"];
|
||||||
|
if (f) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::SUMMER, hc_num);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcmp(command, "designtemp") == 0) {
|
||||||
|
float f = doc["data"];
|
||||||
|
if (f) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::DESIGN, hc_num);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strcmp(command, "offettemp") == 0) {
|
||||||
|
float f = doc["data"];
|
||||||
|
if (f) {
|
||||||
|
set_temperature(f, HeatingCircuit::Mode::OFFSET, hc_num);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::thermostat_cmd_temp(const char * message) {
|
void Thermostat::thermostat_cmd_temp(const char * message) {
|
||||||
@@ -314,7 +387,7 @@ void Thermostat::thermostat_cmd_mode(const char * message) {
|
|||||||
set_mode(s, DEFAULT_HEATING_CIRCUIT);
|
set_mode(s, DEFAULT_HEATING_CIRCUIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function is called post and telegram process call
|
// this function is called post the telegram handler function has been executed
|
||||||
// we check if any of the thermostat values have changed and then republish if necessary
|
// we check if any of the thermostat values have changed and then republish if necessary
|
||||||
bool Thermostat::updated_values() {
|
bool Thermostat::updated_values() {
|
||||||
// only publish on the master thermostat
|
// only publish on the master thermostat
|
||||||
@@ -357,16 +430,43 @@ void Thermostat::publish_values() {
|
|||||||
JsonObject rootThermostat = doc.to<JsonObject>();
|
JsonObject rootThermostat = doc.to<JsonObject>();
|
||||||
JsonObject dataThermostat;
|
JsonObject dataThermostat;
|
||||||
|
|
||||||
// optional, add external temp. I don't think anyone actually is interested in this
|
// add external temp
|
||||||
if ((flags == EMS_DEVICE_FLAG_RC35) && (mqtt_format_ == Settings::MQTT_format::SINGLE)) {
|
if ((flags == EMS_DEVICE_FLAG_RC35 || flags == EMS_DEVICE_FLAG_RC30_1)
|
||||||
|
&& (mqtt_format_ == Settings::MQTT_format::SINGLE || mqtt_format_ == Settings::MQTT_format::CUSTOM)) {
|
||||||
|
if (datetime_.size()) {
|
||||||
|
rootThermostat["time"] = datetime_.c_str();
|
||||||
|
}
|
||||||
if (dampedoutdoortemp != EMS_VALUE_INT_NOTSET) {
|
if (dampedoutdoortemp != EMS_VALUE_INT_NOTSET) {
|
||||||
doc["dampedtemp"] = dampedoutdoortemp;
|
rootThermostat["dampedtemp"] = dampedoutdoortemp;
|
||||||
}
|
}
|
||||||
if (tempsensor1 != EMS_VALUE_USHORT_NOTSET) {
|
if (tempsensor1 != EMS_VALUE_USHORT_NOTSET) {
|
||||||
doc["tempsensor1"] = (float)tempsensor1 / 10;
|
rootThermostat["inttemp1"] = (float)tempsensor1 / 10;
|
||||||
}
|
}
|
||||||
if (tempsensor2 != EMS_VALUE_USHORT_NOTSET) {
|
if (tempsensor2 != EMS_VALUE_USHORT_NOTSET) {
|
||||||
doc["tempsensor1"] = (float)tempsensor2 / 10;
|
rootThermostat["inttemp2"] = (float)tempsensor2 / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ibaCalIntTemperature != EMS_VALUE_INT_NOTSET) {
|
||||||
|
rootThermostat["intoffset"] = (float)ibaCalIntTemperature / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ibaMinExtTemperature != EMS_VALUE_INT_NOTSET) {
|
||||||
|
rootThermostat["minexttemp"] = (float)ibaMinExtTemperature; // min ext temp for heating curve, in deg.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ibaBuildingType != EMS_VALUE_UINT_NOTSET) {
|
||||||
|
if (ibaBuildingType == 0) {
|
||||||
|
rootThermostat["building"] = "light";
|
||||||
|
} else if (ibaBuildingType == 1) {
|
||||||
|
rootThermostat["building"] = "medium";
|
||||||
|
} else if (ibaBuildingType == 2) {
|
||||||
|
rootThermostat["building"] = "heavy";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mqtt_format_ == Settings::MQTT_format::SINGLE) {
|
||||||
|
Mqtt::publish("thermostat_data", doc);
|
||||||
|
rootThermostat = doc.to<JsonObject>(); // clear object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +536,8 @@ void Thermostat::publish_values() {
|
|||||||
dataThermostat["designtemp"] = hc->designtemp;
|
dataThermostat["designtemp"] = hc->designtemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hc->mode != EMS_VALUE_UINT_NOTSET) {
|
// when using HA always send the mode otherwise it'll break the component/widget and report an error
|
||||||
|
if ((hc->mode != EMS_VALUE_UINT_NOTSET) || (mqtt_format_ == Settings::MQTT_format::HA)) {
|
||||||
uint8_t hc_mode = hc->get_mode(flags);
|
uint8_t hc_mode = hc->get_mode(flags);
|
||||||
// if we're sending to HA the only valid mode types are heat, auto and off
|
// if we're sending to HA the only valid mode types are heat, auto and off
|
||||||
if (mqtt_format_ == Settings::MQTT_format::HA) {
|
if (mqtt_format_ == Settings::MQTT_format::HA) {
|
||||||
@@ -465,14 +566,14 @@ void Thermostat::publish_values() {
|
|||||||
dataThermostat["modetype"] = mode_tostring(hc->get_mode_type(flags));
|
dataThermostat["modetype"] = mode_tostring(hc->get_mode_type(flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if format is single, send immediately and quit
|
// if format is single, send immediately and clear object for next hc
|
||||||
if (mqtt_format_ == Settings::MQTT_format::SINGLE) {
|
if (mqtt_format_ == Settings::MQTT_format::SINGLE) {
|
||||||
char topic[30];
|
char topic[30];
|
||||||
char s[3]; // for formatting strings
|
char s[3]; // for formatting strings
|
||||||
strlcpy(topic, "thermostat_data", 30);
|
strlcpy(topic, "thermostat_data", 30);
|
||||||
strlcat(topic, Helpers::itoa(s, hc->hc_num()), 30); // append hc to topic
|
strlcat(topic, Helpers::itoa(s, hc->hc_num()), 30); // append hc to topic
|
||||||
Mqtt::publish(topic, doc);
|
Mqtt::publish(topic, doc);
|
||||||
return;
|
rootThermostat = doc.to<JsonObject>(); // clear object
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -654,6 +755,15 @@ std::string Thermostat::mode_tostring(uint8_t mode) const {
|
|||||||
case HeatingCircuit::Mode::AUTO:
|
case HeatingCircuit::Mode::AUTO:
|
||||||
return read_flash_string(F("auto"));
|
return read_flash_string(F("auto"));
|
||||||
break;
|
break;
|
||||||
|
case HeatingCircuit::Mode::SUMMER:
|
||||||
|
return read_flash_string(F("summer"));
|
||||||
|
break;
|
||||||
|
case HeatingCircuit::Mode::OFFSET:
|
||||||
|
return read_flash_string(F("offset"));
|
||||||
|
break;
|
||||||
|
case HeatingCircuit::Mode::DESIGN:
|
||||||
|
return read_flash_string(F("design"));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
case HeatingCircuit::Mode::UNKNOWN:
|
case HeatingCircuit::Mode::UNKNOWN:
|
||||||
return read_flash_string(F("unknown"));
|
return read_flash_string(F("unknown"));
|
||||||
@@ -860,19 +970,14 @@ void Thermostat::process_EasyMonitor(std::shared_ptr<const Telegram> telegram) {
|
|||||||
|
|
||||||
// Settings Parameters - 0xA5 - RC30_1
|
// Settings Parameters - 0xA5 - RC30_1
|
||||||
void Thermostat::process_IBASettings(std::shared_ptr<const Telegram> telegram) {
|
void Thermostat::process_IBASettings(std::shared_ptr<const Telegram> telegram) {
|
||||||
uint8_t extTemp = 100; // Min. ext temperature is coded as int8, 0xF6=-10, 0x0 = 0, 0xFF=-1. 100 is out of permissible range
|
// 22 - display line on RC35
|
||||||
|
|
||||||
telegram->read_value(ibaMainDisplay,
|
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, 9 smoke temp
|
||||||
telegram->read_value(ibaLanguage, 6); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian
|
telegram->read_value(ibaLanguage, 1); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian
|
||||||
telegram->read_value(ibaBuildingType, 2); // building type: 0 = light, 1 = medium, 2 = heavy
|
|
||||||
telegram->read_value(ibaCalIntTemperature, 2); // offset int. temperature sensor, by * 0.1 Kelvin
|
telegram->read_value(ibaCalIntTemperature, 2); // offset int. temperature sensor, by * 0.1 Kelvin
|
||||||
telegram->read_value(extTemp, 5); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1
|
telegram->read_value(ibaBuildingType, 6); // building type: 0 = light, 1 = medium, 2 = heavy
|
||||||
if (extTemp != 100) {
|
telegram->read_value(ibaMinExtTemperature, 5); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1
|
||||||
// code as signed short, to benefit from negative value rendering
|
telegram->read_value(ibaClockOffset, 12); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
||||||
ibaMinExtTemperature = (int16_t)(extTemp > 127) ? (extTemp - 256) : extTemp;
|
|
||||||
}
|
|
||||||
telegram->read_value(ibaClockOffset, 12); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// type 0x6F - FR10/FR50/FR100 Junkers
|
// type 0x6F - FR10/FR50/FR100 Junkers
|
||||||
@@ -936,7 +1041,7 @@ void Thermostat::process_RC30Set(std::shared_ptr<const Telegram> telegram) {
|
|||||||
// type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes
|
// type 0x3E (HC1), 0x48 (HC2), 0x52 (HC3), 0x5C (HC4) - data from the RC35 thermostat (0x10) - 16 bytes
|
||||||
void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
|
void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
|
||||||
// exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature
|
// exit if the 15th byte (second from last) is 0x00, which I think is calculated flow setpoint temperature
|
||||||
// with weather controlled RC35s this value can be zero and our setpoint temps will be incorrect
|
// with weather controlled RC35s this value is >=5, otherwise can be zero and our setpoint temps will be incorrect
|
||||||
// see https://github.com/proddy/EMS-ESP/issues/373#issuecomment-627907301
|
// see https://github.com/proddy/EMS-ESP/issues/373#issuecomment-627907301
|
||||||
if (telegram->message_data[14] == 0x00) {
|
if (telegram->message_data[14] == 0x00) {
|
||||||
return;
|
return;
|
||||||
@@ -944,11 +1049,7 @@ void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> telegram) {
|
|||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||||
|
|
||||||
// ignore if the value is 0 (see https://github.com/proddy/EMS-ESP/commit/ccc30738c00f12ae6c89177113bd15af9826b836)
|
telegram->read_value8(hc->setpoint_roomTemp, 2); // is * 2, force to single byte, is 0 in summermode
|
||||||
if (telegram->message_data[2] != 0x00) {
|
|
||||||
telegram->read_value8(hc->setpoint_roomTemp, 2); // is * 2, force to single byte
|
|
||||||
}
|
|
||||||
|
|
||||||
telegram->read_value(hc->curr_roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler
|
telegram->read_value(hc->curr_roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler
|
||||||
telegram->read_value(hc->mode_type, 1, 1);
|
telegram->read_value(hc->mode_type, 1, 1);
|
||||||
telegram->read_value(hc->summer_mode, 1, 0);
|
telegram->read_value(hc->summer_mode, 1, 0);
|
||||||
@@ -970,10 +1071,12 @@ void Thermostat::process_RC35Set(std::shared_ptr<const Telegram> telegram) {
|
|||||||
telegram->read_value(hc->daytemp, 2); // is * 2
|
telegram->read_value(hc->daytemp, 2); // is * 2
|
||||||
telegram->read_value(hc->nighttemp, 1); // is * 2
|
telegram->read_value(hc->nighttemp, 1); // is * 2
|
||||||
telegram->read_value(hc->holidaytemp, 3); // is * 2
|
telegram->read_value(hc->holidaytemp, 3); // is * 2
|
||||||
telegram->read_value(hc->heatingtype, 0); // byte 0 bit floor heating = 3
|
telegram->read_value(hc->heatingtype, 0); // 0- off, 1-radiator, 2-convector, 3-floor
|
||||||
|
|
||||||
telegram->read_value(hc->designtemp, 17);
|
telegram->read_value(hc->summertemp, 22); // is * 1
|
||||||
telegram->read_value(hc->offsettemp, 6);
|
telegram->read_value(hc->nofrosttemp, 23); // is * 1
|
||||||
|
telegram->read_value(hc->designtemp, 17); // is * 1
|
||||||
|
telegram->read_value(hc->offsettemp, 6); // is * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// process_RCTime - type 0x06 - date and time from a thermostat - 14 bytes long
|
// process_RCTime - type 0x06 - date and time from a thermostat - 14 bytes long
|
||||||
@@ -1144,7 +1247,6 @@ void Thermostat::set_mode(const uint8_t mode, const uint8_t hc_num) {
|
|||||||
write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid);
|
write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Set the temperature of the thermostat
|
// Set the temperature of the thermostat
|
||||||
void Thermostat::set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num) {
|
void Thermostat::set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num) {
|
||||||
if (can_write()) {
|
if (can_write()) {
|
||||||
@@ -1201,10 +1303,29 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
|
|||||||
case HeatingCircuit::Mode::HOLIDAY: // change the holiday temp
|
case HeatingCircuit::Mode::HOLIDAY: // change the holiday temp
|
||||||
offset = EMS_OFFSET_RC35Set_temp_holiday;
|
offset = EMS_OFFSET_RC35Set_temp_holiday;
|
||||||
break;
|
break;
|
||||||
|
case HeatingCircuit::Mode::OFFSET: // change the offset temp
|
||||||
|
offset = EMS_OFFSET_RC35Set_temp_offset;
|
||||||
|
break;
|
||||||
|
case HeatingCircuit::Mode::DESIGN:
|
||||||
|
offset = EMS_OFFSET_RC35Set_temp_design;
|
||||||
|
break;
|
||||||
|
case HeatingCircuit::Mode::SUMMER:
|
||||||
|
offset = EMS_OFFSET_RC35Set_temp_summer;
|
||||||
|
break;
|
||||||
|
case HeatingCircuit::Mode::NOFROST:
|
||||||
|
offset = EMS_OFFSET_RC35Set_temp_nofrost;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code
|
case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code
|
||||||
if (model == EMS_DEVICE_FLAG_RC35) {
|
if (model == EMS_DEVICE_FLAG_RC35) {
|
||||||
offset = EMS_OFFSET_RC35Set_seltemp; // https://github.com/proddy/EMS-ESP/issues/310
|
uint8_t mode_ = hc->get_mode(flags());
|
||||||
|
if (mode_ == HeatingCircuit::Mode::NIGHT) {
|
||||||
|
offset = EMS_OFFSET_RC35Set_temp_night;
|
||||||
|
} else if (mode_ == HeatingCircuit::Mode::DAY) {
|
||||||
|
offset = EMS_OFFSET_RC35Set_temp_day;
|
||||||
|
} else {
|
||||||
|
offset = EMS_OFFSET_RC35Set_seltemp; // https://github.com/proddy/EMS-ESP/issues/310
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uint8_t mode_type = hc->get_mode_type(flags());
|
uint8_t mode_type = hc->get_mode_type(flags());
|
||||||
offset = (mode_type == HeatingCircuit::Mode::NIGHT) ? EMS_OFFSET_RC35Set_temp_night : EMS_OFFSET_RC35Set_temp_day;
|
offset = (mode_type == HeatingCircuit::Mode::NIGHT) ? EMS_OFFSET_RC35Set_temp_night : EMS_OFFSET_RC35Set_temp_day;
|
||||||
|
|||||||
@@ -57,9 +57,12 @@ class Thermostat : public EMSdevice {
|
|||||||
uint8_t holidaytemp = EMS_VALUE_UINT_NOTSET;
|
uint8_t holidaytemp = EMS_VALUE_UINT_NOTSET;
|
||||||
uint8_t heatingtype = EMS_VALUE_UINT_NOTSET; // type of heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
|
uint8_t heatingtype = EMS_VALUE_UINT_NOTSET; // type of heating: 1 radiator, 2 convectors, 3 floors, 4 room supply
|
||||||
uint8_t circuitcalctemp = EMS_VALUE_UINT_NOTSET;
|
uint8_t circuitcalctemp = EMS_VALUE_UINT_NOTSET;
|
||||||
|
uint8_t summertemp = EMS_VALUE_UINT_NOTSET;
|
||||||
|
uint8_t nofrosttemp = EMS_VALUE_UINT_NOTSET;
|
||||||
|
uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heatingcurve design temp at MinExtTemp
|
||||||
|
uint8_t offsettemp = 100; // heatingcurve offest temp at roomtemp signed!
|
||||||
|
uint16_t remotetemp = EMS_VALUE_SHORT_NOTSET; // for simulating a RC20 remote
|
||||||
|
|
||||||
uint8_t designtemp = EMS_VALUE_UINT_NOTSET; // heatingcurve design temp at MinExtTemp
|
|
||||||
uint8_t offsettemp = 100; // heatingcurve offest temp at roomtemp signed!
|
|
||||||
|
|
||||||
uint8_t hc_num() const {
|
uint8_t hc_num() const {
|
||||||
return hc_num_;
|
return hc_num_;
|
||||||
@@ -76,7 +79,7 @@ class Thermostat : public EMSdevice {
|
|||||||
return set_typeid_;
|
return set_typeid_;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Mode : uint8_t { UNKNOWN, OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN };
|
enum Mode : uint8_t { UNKNOWN, OFF, MANUAL, AUTO, DAY, NIGHT, HEAT, NOFROST, ECO, HOLIDAY, COMFORT, OFFSET, DESIGN, SUMMER };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t hc_num_;
|
uint8_t hc_num_;
|
||||||
@@ -159,6 +162,10 @@ class Thermostat : public EMSdevice {
|
|||||||
static constexpr uint8_t EMS_OFFSET_RC35Set_heatingtype = 0; // e.g. floor heating = 3
|
static constexpr uint8_t EMS_OFFSET_RC35Set_heatingtype = 0; // e.g. floor heating = 3
|
||||||
static constexpr uint8_t EMS_OFFSET_RC35Set_circuitcalctemp = 14; // calculated circuit temperature
|
static constexpr uint8_t EMS_OFFSET_RC35Set_circuitcalctemp = 14; // calculated circuit temperature
|
||||||
static constexpr uint8_t EMS_OFFSET_RC35Set_seltemp = 37; // selected temp
|
static constexpr uint8_t EMS_OFFSET_RC35Set_seltemp = 37; // selected temp
|
||||||
|
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_offset = 6;
|
||||||
|
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_design = 17;
|
||||||
|
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_summer = 22;
|
||||||
|
static constexpr uint8_t EMS_OFFSET_RC35Set_temp_nofrost = 23;
|
||||||
|
|
||||||
static constexpr uint8_t EMS_OFFSET_EasyStatusMessage_setpoint = 10; // setpoint temp
|
static constexpr uint8_t EMS_OFFSET_EasyStatusMessage_setpoint = 10; // setpoint temp
|
||||||
static constexpr uint8_t EMS_OFFSET_EasyStatusMessage_curr = 8; // current temp
|
static constexpr uint8_t EMS_OFFSET_EasyStatusMessage_curr = 8; // current temp
|
||||||
|
|||||||
@@ -29,14 +29,14 @@
|
|||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
static intr_handle_t uart_handle;
|
static intr_handle_t uart_handle;
|
||||||
static RingbufHandle_t buf_handle = NULL;
|
static RingbufHandle_t buf_handle = NULL;
|
||||||
static uint8_t rxbuf[UART_FIFO_LEN];
|
static bool drop_first_rx = true;
|
||||||
static uint8_t rxlen;
|
static uint8_t tx_mode_ = 0xFF;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Task to handle the incoming data
|
* Task to handle the incoming data
|
||||||
*/
|
*/
|
||||||
void EMSuart::emsuart_recvTask(void * param) {
|
void EMSuart::emsuart_recvTask(void * para) {
|
||||||
while (1) {
|
while (1) {
|
||||||
size_t item_size;
|
size_t item_size;
|
||||||
uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, portMAX_DELAY);
|
uint8_t * telegram = (uint8_t *)xRingbufferReceive(buf_handle, &item_size, portMAX_DELAY);
|
||||||
@@ -48,29 +48,41 @@ void EMSuart::emsuart_recvTask(void * param) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UART interrupt, on break read the fifo and put the whole telegram to ringbuffer
|
* UART interrupt, on break read the fifo and put the whole telegram to ringbuffer
|
||||||
*/
|
*/
|
||||||
static void IRAM_ATTR uart_intr_handle(void * arg) {
|
void IRAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
|
||||||
|
static uint8_t rxbuf[EMS_MAXBUFFERSIZE];
|
||||||
|
static uint8_t length;
|
||||||
|
|
||||||
if (EMS_UART.int_st.brk_det) {
|
if (EMS_UART.int_st.brk_det) {
|
||||||
uint8_t rx_fifo_len = EMS_UART.status.rxfifo_cnt;
|
|
||||||
for (rxlen = 0; rxlen < rx_fifo_len; rxlen++) {
|
|
||||||
rxbuf[rxlen] = EMS_UART.fifo.rw_byte; // read all bytes into buffer
|
|
||||||
}
|
|
||||||
if ((rxlen == 2) || ((rxlen > 4) && (rxlen <= EMS_MAXBUFFERSIZE))) {
|
|
||||||
int baseType = 0;
|
|
||||||
xRingbufferSendFromISR(buf_handle, rxbuf, rxlen - 1, &baseType);
|
|
||||||
}
|
|
||||||
EMS_UART.int_clr.brk_det = 1; // clear flag
|
EMS_UART.int_clr.brk_det = 1; // clear flag
|
||||||
EMS_UART.conf0.txd_brk = 0; // if it was break from sending, clear bit
|
EMS_UART.conf0.txd_brk = 0; // if it was break from sending, clear bit
|
||||||
|
length = 0;
|
||||||
|
while (EMS_UART.status.rxfifo_cnt) {
|
||||||
|
uint8_t rx = EMS_UART.fifo.rw_byte; // read all bytes into buffer
|
||||||
|
if (length < EMS_MAXBUFFERSIZE) {
|
||||||
|
rxbuf[length++] = rx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((!drop_first_rx) && ((length == 2) || ((length > 4)))) {
|
||||||
|
int baseType = 0;
|
||||||
|
xRingbufferSendFromISR(buf_handle, rxbuf, length - 1, &baseType);
|
||||||
|
}
|
||||||
|
drop_first_rx = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* init UART driver
|
* init UART driver
|
||||||
*/
|
*/
|
||||||
void EMSuart::start(uint8_t tx_mode) {
|
void EMSuart::start(uint8_t tx_mode) {
|
||||||
|
if (tx_mode_ != 0xFF) { // uart already initialized
|
||||||
|
restart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_mode_ = tx_mode;
|
||||||
|
|
||||||
uart_config_t uart_config = {
|
uart_config_t uart_config = {
|
||||||
.baud_rate = EMSUART_BAUD,
|
.baud_rate = EMSUART_BAUD,
|
||||||
.data_bits = UART_DATA_8_BITS,
|
.data_bits = UART_DATA_8_BITS,
|
||||||
@@ -81,14 +93,18 @@ void EMSuart::start(uint8_t tx_mode) {
|
|||||||
|
|
||||||
ESP_ERROR_CHECK(uart_param_config(EMSUART_UART, &uart_config));
|
ESP_ERROR_CHECK(uart_param_config(EMSUART_UART, &uart_config));
|
||||||
ESP_ERROR_CHECK(uart_set_pin(EMSUART_UART, EMSUART_TXPIN, EMSUART_RXPIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
ESP_ERROR_CHECK(uart_set_pin(EMSUART_UART, EMSUART_TXPIN, EMSUART_RXPIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
|
||||||
//EMS_UART.conf1.rxfifo_full_thrhd = 127; // enough to hold the incoming telegram, should never reached
|
EMS_UART.int_ena.val = 0; // disable all intr.
|
||||||
//EMS_UART.idle_conf.tx_brk_num = 12; // breaklength 12 bit
|
EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags
|
||||||
EMS_UART.int_ena.val = 0; // disable all intr.
|
EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit
|
||||||
EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags
|
EMS_UART.idle_conf.rx_idle_thrhd = 12;
|
||||||
EMS_UART.int_ena.brk_det = 1; // activate only break
|
|
||||||
buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT);
|
drop_first_rx = true;
|
||||||
ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART, uart_intr_handle, NULL, ESP_INTR_FLAG_IRAM, &uart_handle));
|
|
||||||
|
buf_handle = xRingbufferCreate(128, RINGBUF_TYPE_NOSPLIT);
|
||||||
|
ESP_ERROR_CHECK(uart_isr_register(EMSUART_UART, emsuart_rx_intr_handler, NULL, ESP_INTR_FLAG_IRAM, &uart_handle));
|
||||||
xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, 12, NULL);
|
xTaskCreate(emsuart_recvTask, "emsuart_recvTask", 2048, NULL, 12, NULL);
|
||||||
|
|
||||||
|
EMS_UART.int_ena.brk_det = 1; // activate only break
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -102,18 +118,21 @@ void EMSuart::stop() {
|
|||||||
* Restart Interrupt
|
* Restart Interrupt
|
||||||
*/
|
*/
|
||||||
void EMSuart::restart() {
|
void EMSuart::restart() {
|
||||||
EMS_UART.int_clr.val = 0xFFFFFFFF; // clear all intr. flags
|
if (EMS_UART.int_raw.brk_det) {
|
||||||
EMS_UART.int_ena.brk_det = 1; // activate only break
|
EMS_UART.int_clr.brk_det = 1; // clear flag
|
||||||
|
drop_first_rx = true; // and drop first frame
|
||||||
|
}
|
||||||
|
EMS_UART.int_ena.brk_det = 1; // activate only break
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sends a 1-byte poll, ending with a <BRK>
|
* Sends a 1-byte poll, ending with a <BRK>
|
||||||
*/
|
*/
|
||||||
void EMSuart::send_poll(uint8_t data) {
|
void EMSuart::send_poll(uint8_t data) {
|
||||||
EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared
|
EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared
|
||||||
EMS_UART.fifo.rw_byte = data;
|
EMS_UART.fifo.rw_byte = data;
|
||||||
EMS_UART.idle_conf.tx_brk_num = 12; // breaklength 12 bit
|
//EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit
|
||||||
EMS_UART.conf0.txd_brk = 1; // sending ends in a break
|
EMS_UART.conf0.txd_brk = 1; // sending ends in a break
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -123,16 +142,13 @@ void EMSuart::send_poll(uint8_t data) {
|
|||||||
*/
|
*/
|
||||||
EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) {
|
EMSUART_STATUS EMSuart::transmit(uint8_t * buf, uint8_t len) {
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
if (EMS_UART.status.txfifo_cnt > 0) { // fifo not empty
|
|
||||||
return EMS_TX_WTD_TIMEOUT;
|
|
||||||
}
|
|
||||||
EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared
|
EMS_UART.conf0.txd_brk = 0; // just to make sure the bit is cleared
|
||||||
for (uint8_t i = 0; i < len; i++) {
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
EMS_UART.fifo.rw_byte = buf[i];
|
EMS_UART.fifo.rw_byte = buf[i];
|
||||||
}
|
}
|
||||||
//uart_tx_chars(EMSUART_UART, (const char *)buf, len);
|
//uart_tx_chars(EMSUART_UART, (const char *)buf, len);
|
||||||
EMS_UART.idle_conf.tx_brk_num = 12; // breaklength 12 bit
|
//EMS_UART.idle_conf.tx_brk_num = 11; // breaklength 11 bit
|
||||||
EMS_UART.conf0.txd_brk = 1; // sending ends in a break
|
EMS_UART.conf0.txd_brk = 1; // sending ends in a break
|
||||||
}
|
}
|
||||||
return EMS_TX_STATUS_OK;
|
return EMS_TX_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ESP32 UART port by @ArwedL and improved by @MichaelDvP. See https://github.com/proddy/EMS-ESP/issues/380
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef EMSESP_EMSUART_H
|
#ifndef EMSESP_EMSUART_H
|
||||||
#define EMSESP_EMSUART_H
|
#define EMSESP_EMSUART_H
|
||||||
|
|
||||||
@@ -27,15 +32,15 @@
|
|||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
#include <driver/uart.h>
|
#include <driver/uart.h>
|
||||||
|
|
||||||
#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra 2 for BRKs
|
#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus extra for BRK
|
||||||
|
|
||||||
#define EMSUART_UART UART_NUM_2 // on the ESP32 we're using UART2
|
#define EMSUART_UART UART_NUM_2 // on the ESP32 we're using UART2
|
||||||
#define EMS_UART UART2 // for intr setting
|
#define EMS_UART UART2 // for intr setting
|
||||||
#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit
|
#define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit
|
||||||
|
|
||||||
// customize the GPIO pins for RX and TX here
|
// customize the GPIO pins for RX and TX here
|
||||||
#define EMSUART_RXPIN 17 // 17 is UART2 RX. Use 23 for D7 on a Wemos D1-32 mini for backwards compatabilty
|
#define EMSUART_RXPIN 23 // 17 is UART2 RX. Use 23 for D7 on a Wemos D1-32 mini for backwards compatabilty
|
||||||
#define EMSUART_TXPIN 16 // 16 is UART2 TX. Use 5 for D8 on a Wemos D1-32 mini for backwards compatabilty
|
#define EMSUART_TXPIN 5 // 16 is UART2 TX. Use 5 for D8 on a Wemos D1-32 mini for backwards compatabilty
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
@@ -57,7 +62,8 @@ class EMSuart {
|
|||||||
static EMSUART_STATUS transmit(uint8_t * buf, uint8_t len);
|
static EMSUART_STATUS transmit(uint8_t * buf, uint8_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void emsuart_recvTask(void * param);
|
static void emsuart_recvTask(void * para);
|
||||||
|
static void IRAM_ATTR emsuart_rx_intr_handler(void * para);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -28,25 +28,26 @@ os_event_t recvTaskQueue[EMSUART_recvTaskQueueLen]; // our Rx queue
|
|||||||
|
|
||||||
EMSuart::EMSRxBuf_t * pEMSRxBuf;
|
EMSuart::EMSRxBuf_t * pEMSRxBuf;
|
||||||
EMSuart::EMSRxBuf_t * paEMSRxBuf[EMS_MAXBUFFERS];
|
EMSuart::EMSRxBuf_t * paEMSRxBuf[EMS_MAXBUFFERS];
|
||||||
uint8_t emsRxBufIdx = 0;
|
uint8_t emsRxBufIdx = 0;
|
||||||
uint8_t phantomBreak = 0;
|
uint8_t phantomBreak = 0;
|
||||||
uint8_t tx_mode_ = EMS_TXMODE_DEFAULT;
|
uint8_t tx_mode_ = 0xFF;
|
||||||
|
bool drop_first_rx = true;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Main interrupt handler
|
// Main interrupt handler
|
||||||
// Important: must not use ICACHE_FLASH_ATTR
|
// Important: must not use ICACHE_FLASH_ATTR
|
||||||
//
|
//
|
||||||
void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
|
void ICACHE_RAM_ATTR EMSuart::emsuart_rx_intr_handler(void * para) {
|
||||||
static uint8_t length = 0;
|
static uint8_t length = 0;
|
||||||
static bool rx_idle_ = true;
|
// static bool rx_idle_ = true;
|
||||||
static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2];
|
static uint8_t uart_buffer[EMS_MAXBUFFERSIZE + 2];
|
||||||
|
|
||||||
|
/*
|
||||||
// is a new buffer? if so init the thing for a new telegram
|
// is a new buffer? if so init the thing for a new telegram
|
||||||
if (rx_idle_) {
|
if (rx_idle_) {
|
||||||
rx_idle_ = false; // status set to busy
|
rx_idle_ = false; // status set to busy
|
||||||
length = 0;
|
length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
@@ -58,15 +59,25 @@ void ICACHE_RAM_ATTR EMSuart::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);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// 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
|
length = 0;
|
||||||
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
|
while ((USS(EMSUART_UART) >> USRXC) & 0xFF) {
|
||||||
|
uint8_t rx = USF(EMSUART_UART);
|
||||||
pEMSRxBuf->length = (length > EMS_MAXBUFFERSIZE) ? EMS_MAXBUFFERSIZE : length;
|
if (length < EMS_MAXBUFFERSIZE) {
|
||||||
os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end
|
uart_buffer[length++] = rx;
|
||||||
rx_idle_ = true; // check set the status flag stating BRK has been received and we can start a new package
|
}
|
||||||
|
}
|
||||||
|
USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear <BRK> bit
|
||||||
|
ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them
|
||||||
|
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
|
||||||
|
if (!drop_first_rx) {
|
||||||
|
pEMSRxBuf->length = length;
|
||||||
|
os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, pEMSRxBuf->length); // copy data into transfer buffer, including the BRK 0x00 at the end
|
||||||
|
// rx_idle_ = true; // check set the status flag stating BRK has been received and we can start a new package
|
||||||
|
}
|
||||||
|
drop_first_rx = false;
|
||||||
ETS_UART_INTR_ENABLE(); // re-enable UART interrupts
|
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
|
||||||
@@ -116,8 +127,12 @@ void ICACHE_FLASH_ATTR EMSuart::emsuart_flush_fifos() {
|
|||||||
* init UART0 driver
|
* init UART0 driver
|
||||||
*/
|
*/
|
||||||
void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
|
void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
|
||||||
|
if (tx_mode_ != 0xFF) { // it's a restart no need to configure rx
|
||||||
|
tx_mode_ = tx_mode;
|
||||||
|
restart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
tx_mode_ = tx_mode;
|
tx_mode_ = tx_mode;
|
||||||
|
|
||||||
// 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++) {
|
||||||
EMSRxBuf_t * p = (EMSRxBuf_t *)malloc(sizeof(EMSRxBuf_t));
|
EMSRxBuf_t * p = (EMSRxBuf_t *)malloc(sizeof(EMSRxBuf_t));
|
||||||
@@ -148,8 +163,9 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
|
|||||||
//
|
//
|
||||||
// change: we set UCFFT to 1 to get an immediate indicator about incoming traffic.
|
// change: we set UCFFT to 1 to get an immediate indicator about incoming traffic.
|
||||||
// Otherwise, we're only noticed by UCTOT or RxBRK!
|
// Otherwise, we're only noticed by UCTOT or RxBRK!
|
||||||
USC1(EMSUART_UART) = 0; // reset config first
|
// change: don't care, we do not use these interrupts
|
||||||
USC1(EMSUART_UART) = (0x01 << UCFFT) | (0x01 << UCTOT) | (0 << UCTOE); // enable interupts
|
//USC1(EMSUART_UART) = 0; // reset config first
|
||||||
|
//USC1(EMSUART_UART) = (0x01 << UCFFT) | (0x01 << UCTOT) | (0 << 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
|
||||||
@@ -158,7 +174,8 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
|
|||||||
// enable rx break, fifo full and timeout.
|
// 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
|
// 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 Rx Timeout - it may lead to wrong readouts
|
||||||
USIE(EMSUART_UART) = (1 << UIBD) | (1 << UIFF) | (0 << UITO);
|
// 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
|
// set up interrupt callbacks for Rx
|
||||||
system_os_task(emsuart_recvTask, EMSUART_recvTaskPrio, recvTaskQueue, EMSUART_recvTaskQueueLen);
|
system_os_task(emsuart_recvTask, EMSUART_recvTaskPrio, recvTaskQueue, EMSUART_recvTaskQueueLen);
|
||||||
@@ -171,7 +188,7 @@ void ICACHE_FLASH_ATTR EMSuart::start(uint8_t tx_mode) {
|
|||||||
|
|
||||||
ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr);
|
ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr);
|
||||||
ETS_UART_INTR_ENABLE();
|
ETS_UART_INTR_ENABLE();
|
||||||
|
drop_first_rx = true;
|
||||||
// LOG_INFO(F("UART service for Rx/Tx started"));
|
// LOG_INFO(F("UART service for Rx/Tx started"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,6 +204,10 @@ void ICACHE_FLASH_ATTR EMSuart::stop() {
|
|||||||
* re-start UART0 driver
|
* re-start UART0 driver
|
||||||
*/
|
*/
|
||||||
void ICACHE_FLASH_ATTR EMSuart::restart() {
|
void ICACHE_FLASH_ATTR EMSuart::restart() {
|
||||||
|
if (USIS(EMSUART_UART) & ((1 << UIBD))) {
|
||||||
|
USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt
|
||||||
|
drop_first_rx = true;
|
||||||
|
}
|
||||||
ETS_UART_INTR_ENABLE();
|
ETS_UART_INTR_ENABLE();
|
||||||
// emsuart_flush_fifos();
|
// emsuart_flush_fifos();
|
||||||
}
|
}
|
||||||
@@ -211,7 +232,7 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() {
|
|||||||
tmp = (1 << UCBRK);
|
tmp = (1 << UCBRK);
|
||||||
USC0(EMSUART_UART) |= (tmp); // set bit
|
USC0(EMSUART_UART) |= (tmp); // set bit
|
||||||
|
|
||||||
if (tx_mode_ == EMS_TX_WTD_TIMEOUT) { // EMS+ mode
|
if (tx_mode_ == EMS_TXMODE_EMSPLUS) { // EMS+ mode
|
||||||
delayMicroseconds(EMSUART_TX_BRK_WAIT);
|
delayMicroseconds(EMSUART_TX_BRK_WAIT);
|
||||||
} else if (tx_mode_ == EMS_TXMODE_HT3) { // junkers mode
|
} else if (tx_mode_ == EMS_TXMODE_HT3) { // junkers mode
|
||||||
delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits)
|
delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits)
|
||||||
@@ -225,9 +246,15 @@ void ICACHE_FLASH_ATTR EMSuart::tx_brk() {
|
|||||||
* It's a bit dirty. there is no special wait logic per tx_mode type, fifo flushes or error checking
|
* 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) {
|
void EMSuart::send_poll(uint8_t data) {
|
||||||
USF(EMSUART_UART) = data;
|
if (tx_mode_ == EMS_TXMODE_NEW) {
|
||||||
delayMicroseconds(EMSUART_TX_BRK_WAIT);
|
USC0(EMSUART_UART) &= ~(1 << UCBRK); // make sure <BRK> bit is cleared
|
||||||
tx_brk(); // send <BRK>
|
USF(EMSUART_UART) = data;
|
||||||
|
USC0(EMSUART_UART) |= (1 << UCBRK); // send <BRK> at the end
|
||||||
|
} else {
|
||||||
|
USF(EMSUART_UART) = data;
|
||||||
|
delayMicroseconds(EMSUART_TX_BRK_WAIT);
|
||||||
|
tx_brk(); // send <BRK>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -242,12 +269,11 @@ EMSUART_STATUS ICACHE_FLASH_ATTR EMSuart::transmit(uint8_t * buf, uint8_t len) {
|
|||||||
|
|
||||||
// new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380
|
// new code from Michael. See https://github.com/proddy/EMS-ESP/issues/380
|
||||||
if (tx_mode_ == EMS_TXMODE_NEW) {
|
if (tx_mode_ == EMS_TXMODE_NEW) {
|
||||||
USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear <BRK> bit
|
USC0(EMSUART_UART) &= ~(1 << UCBRK); // make sure <BRK> bit is cleared
|
||||||
for (uint8_t i = 0; i < len; i++) {
|
for (uint8_t i = 0; i < len; i++) {
|
||||||
USF(EMSUART_UART) = buf[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
|
||||||
|
|
||||||
return EMS_TX_STATUS_OK;
|
return EMS_TX_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#define EMS_TXMODE_DEFAULT 1
|
#define EMS_TXMODE_DEFAULT 1
|
||||||
#define EMS_TXMODE_EMSPLUS 2
|
#define EMS_TXMODE_EMSPLUS 2
|
||||||
#define EMS_TXMODE_HT3 3
|
#define EMS_TXMODE_HT3 3
|
||||||
#define EMS_TXMODE_NEW 4 // for michael
|
#define EMS_TXMODE_NEW 4 // for michael's testing
|
||||||
|
|
||||||
// LEGACY
|
// LEGACY
|
||||||
#define EMSUART_BIT_TIME 104 // bit time @9600 baud
|
#define EMSUART_BIT_TIME 104 // bit time @9600 baud
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
#define EMSUART_TX_LAG 8
|
#define EMSUART_TX_LAG 8
|
||||||
#define EMSUART_BUSY_WAIT (EMSUART_BIT_TIME / 8)
|
#define EMSUART_BUSY_WAIT (EMSUART_BIT_TIME / 8)
|
||||||
#define EMS_TX_TO_CHARS (2 + 20)
|
#define EMS_TX_TO_CHARS (2 + 20)
|
||||||
#define EMS_TX_TO_COUNT ((EMS_TX_TO_CHARS)*10 * 8)
|
#define EMS_TX_TO_COUNT ((EMS_TX_TO_CHARS)*8)
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "2.0.0a10"
|
#define EMSESP_APP_VERSION "2.0.0a11"
|
||||||
|
|||||||
Reference in New Issue
Block a user