mqtt publish peiod per device, publish on change, ADC

This commit is contained in:
MichaelDvP
2020-09-05 16:50:21 +02:00
parent 1636059823
commit 18421d3d1e
22 changed files with 531 additions and 286 deletions

View File

@@ -150,15 +150,75 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
<MenuItem value={2}>2</MenuItem> <MenuItem value={2}>2</MenuItem>
</SelectValidator> </SelectValidator>
<TextValidator <TextValidator
validators={['required', 'isNumber', 'minNumber:1', 'maxNumber:65535']} validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Publish time is required', "Must be a number", "Must be greater than 0", "Max value is 65535"]} errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]}
name="publish_time" name="publish_time_boiler"
label="MQTT Publish Time (seconds)" label="MQTT Boiler Publish Period (seconds, 0=on change)"
fullWidth fullWidth
variant="outlined" variant="outlined"
value={data.publish_time} value={data.publish_time_boiler}
type="number" type="number"
onChange={handleValueChange('publish_time')} onChange={handleValueChange('publish_time_boiler')}
margin="normal"
/>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]}
name="publish_time_thermostat"
label="MQTT Thermostat Publish Period (seconds, 0=on change)"
fullWidth
variant="outlined"
value={data.publish_time_thermostat}
type="number"
onChange={handleValueChange('publish_time_thermostat')}
margin="normal"
/>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]}
name="publish_time_solar"
label="MQTT Solar Publish Period (seconds, 0=on change)"
fullWidth
variant="outlined"
value={data.publish_time_solar}
type="number"
onChange={handleValueChange('publish_time_solar')}
margin="normal"
/>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]}
name="publish_time_mixing"
label="MQTT Mixer Publish Period (seconds, 0=on change)"
fullWidth
variant="outlined"
value={data.publish_time_mixing}
type="number"
onChange={handleValueChange('publish_time_mixing')}
margin="normal"
/>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]}
name="publish_time_other"
label="MQTT other Modules Publish Period (seconds, 0=on change)"
fullWidth
variant="outlined"
value={data.publish_time_other}
type="number"
onChange={handleValueChange('publish_time_other')}
margin="normal"
/>
<TextValidator
validators={['required', 'isNumber', 'minNumber:0', 'maxNumber:65535']}
errorMessages={['Publish time is required', "Must be a number", "Must be 0 or greater", "Max value is 65535"]}
name="publish_time_sensor"
label="MQTT Sensors Publish Period (seconds, 0=on change)"
fullWidth
variant="outlined"
value={data.publish_time_sensor}
type="number"
onChange={handleValueChange('publish_time_sensor')}
margin="normal" margin="normal"
/> />
<FormActions> <FormActions>

View File

@@ -27,7 +27,12 @@ export interface MqttSettings {
keep_alive: number; keep_alive: number;
clean_session: boolean; clean_session: boolean;
max_topic_length: number; max_topic_length: number;
publish_time: number; publish_time_boiler: number;
publish_time_thermostat: number;
publish_time_solar: number;
publish_time_mixing: number;
publish_time_other: number;
publish_time_sensor: number;
mqtt_format: number; mqtt_format: number;
mqtt_qos: number; mqtt_qos: number;
system_heartbeat: boolean; system_heartbeat: boolean;

View File

@@ -184,10 +184,15 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
root["max_topic_length"] = settings.maxTopicLength; root["max_topic_length"] = settings.maxTopicLength;
// added by proddy for EMS-ESP // added by proddy for EMS-ESP
root["system_heartbeat"] = settings.system_heartbeat; root["system_heartbeat"] = settings.system_heartbeat;
root["publish_time"] = settings.publish_time; root["publish_time_boiler"] = settings.publish_time_boiler;
root["mqtt_format"] = settings.mqtt_format; root["publish_time_thermostat"] = settings.publish_time_thermostat;
root["mqtt_qos"] = settings.mqtt_qos; root["publish_time_solar"] = settings.publish_time_solar;
root["publish_time_mixing"] = settings.publish_time_mixing;
root["publish_time_other"] = settings.publish_time_other;
root["publish_time_sensor"] = settings.publish_time_sensor;
root["mqtt_format"] = settings.mqtt_format;
root["mqtt_qos"] = settings.mqtt_qos;
} }
StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & settings) { StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & settings) {
@@ -203,10 +208,15 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
newSettings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION; newSettings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION;
newSettings.maxTopicLength = root["max_topic_length"] | FACTORY_MQTT_MAX_TOPIC_LENGTH; newSettings.maxTopicLength = root["max_topic_length"] | FACTORY_MQTT_MAX_TOPIC_LENGTH;
newSettings.system_heartbeat = root["system_heartbeat"] | EMSESP_DEFAULT_SYSTEM_HEARTBEAT; newSettings.system_heartbeat = root["system_heartbeat"] | EMSESP_DEFAULT_SYSTEM_HEARTBEAT;
newSettings.publish_time = root["publish_time"] | EMSESP_DEFAULT_PUBLISH_TIME; newSettings.publish_time_boiler = root["publish_time_boiler"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.mqtt_format = root["mqtt_format"] | EMSESP_DEFAULT_MQTT_FORMAT; newSettings.publish_time_thermostat = root["publish_time_thermostat"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.mqtt_qos = root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS; newSettings.publish_time_solar = root["publish_time_solar"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.publish_time_mixing = root["publish_time_mixing"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.publish_time_other = root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.publish_time_sensor = root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME;
newSettings.mqtt_format = root["mqtt_format"] | EMSESP_DEFAULT_MQTT_FORMAT;
newSettings.mqtt_qos = root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS;
if (newSettings.system_heartbeat != settings.system_heartbeat) { if (newSettings.system_heartbeat != settings.system_heartbeat) {
emsesp::EMSESP::system_.set_heartbeat(newSettings.system_heartbeat); emsesp::EMSESP::system_.set_heartbeat(newSettings.system_heartbeat);
@@ -216,8 +226,23 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos); emsesp::EMSESP::mqtt_.set_qos(newSettings.mqtt_qos);
} }
if (newSettings.publish_time != settings.publish_time) { if (newSettings.publish_time_boiler != settings.publish_time_boiler) {
emsesp::EMSESP::mqtt_.set_publish_time(newSettings.publish_time); emsesp::EMSESP::mqtt_.set_publish_time_boiler(newSettings.publish_time_boiler);
}
if (newSettings.publish_time_thermostat != settings.publish_time_thermostat) {
emsesp::EMSESP::mqtt_.set_publish_time_thermostat(newSettings.publish_time_thermostat);
}
if (newSettings.publish_time_solar != settings.publish_time_solar) {
emsesp::EMSESP::mqtt_.set_publish_time_solar(newSettings.publish_time_solar);
}
if (newSettings.publish_time_mixing != settings.publish_time_mixing) {
emsesp::EMSESP::mqtt_.set_publish_time_mixing(newSettings.publish_time_mixing);
}
if (newSettings.publish_time_other != settings.publish_time_other) {
emsesp::EMSESP::mqtt_.set_publish_time_other(newSettings.publish_time_other);
}
if (newSettings.publish_time_sensor != settings.publish_time_sensor) {
emsesp::EMSESP::mqtt_.set_publish_time_sensor(newSettings.publish_time_sensor);
} }
emsesp::EMSESP::mqtt_.reset_publish_fails(); // reset fail counter back to 0 emsesp::EMSESP::mqtt_.reset_publish_fails(); // reset fail counter back to 0

View File

@@ -86,7 +86,12 @@ class MqttSettings {
uint16_t maxTopicLength; uint16_t maxTopicLength;
// proddy EMS-ESP specific // proddy EMS-ESP specific
uint16_t publish_time; // seconds uint16_t publish_time_boiler;
uint16_t publish_time_thermostat;
uint16_t publish_time_solar;
uint16_t publish_time_mixing;
uint16_t publish_time_other;
uint16_t publish_time_sensor;
uint8_t mqtt_format; // 1=single, 2=nested, 3=ha, 4=custom uint8_t mqtt_format; // 1=single, 2=nested, 3=ha, 4=custom
uint8_t mqtt_qos; uint8_t mqtt_qos;
bool system_heartbeat; bool system_heartbeat;

View File

@@ -318,6 +318,10 @@ void Boiler::publish_values() {
// called after a process command is called, to check values and see if we need to force an MQTT publish // called after a process command is called, to check values and see if we need to force an MQTT publish
bool Boiler::updated_values() { bool Boiler::updated_values() {
if (changed_) {
changed_ = false;
return true;
}
return false; return false;
} }
@@ -468,40 +472,40 @@ void Boiler::check_active() {
// 0x33 // 0x33
void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(wWActivated_, 1); // 0xFF means on changed_ |= telegram->read_value(wWActivated_, 1); // 0xFF means on
telegram->read_value(wWCircPump_, 6); // 0xFF means on changed_ |= telegram->read_value(wWCircPump_, 6); // 0xFF means on
telegram->read_value(wWCircPumpMode_, 7); // 1=1x3min... 6=6x3min, 7=continuous changed_ |= telegram->read_value(wWCircPumpMode_, 7); // 1=1x3min... 6=6x3min, 7=continuous
telegram->read_value(wWCircPumpType_, 10); // 0 = charge pump, 0xff = 3-way valve changed_ |= telegram->read_value(wWCircPumpType_, 10); // 0 = charge pump, 0xff = 3-way valve
telegram->read_value(wWSelTemp_, 2); changed_ |= telegram->read_value(wWSelTemp_, 2);
telegram->read_value(wWDisinfectTemp_, 8); changed_ |= telegram->read_value(wWDisinfectTemp_, 8);
telegram->read_value(wWComfort_, 9); changed_ |= telegram->read_value(wWComfort_, 9);
} }
// 0x18 // 0x18
void Boiler::process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(selFlowTemp_, 0); changed_ |= telegram->read_value(selFlowTemp_, 0);
telegram->read_value(curFlowTemp_, 1); changed_ |= telegram->read_value(curFlowTemp_, 1);
telegram->read_value(selBurnPow_, 3); // burn power max setting changed_ |= telegram->read_value(selBurnPow_, 3); // burn power max setting
telegram->read_value(curBurnPow_, 4); changed_ |= telegram->read_value(curBurnPow_, 4);
telegram->read_bitvalue(burnGas_, 7, 0); changed_ |= telegram->read_bitvalue(burnGas_, 7, 0);
telegram->read_bitvalue(fanWork_, 7, 2); changed_ |= telegram->read_bitvalue(fanWork_, 7, 2);
telegram->read_bitvalue(ignWork_, 7, 3); changed_ |= telegram->read_bitvalue(ignWork_, 7, 3);
telegram->read_bitvalue(heatPmp_, 7, 5); changed_ |= telegram->read_bitvalue(heatPmp_, 7, 5);
telegram->read_bitvalue(wWHeat_, 7, 6); changed_ |= telegram->read_bitvalue(wWHeat_, 7, 6);
telegram->read_bitvalue(wWCirc_, 7, 7); changed_ |= telegram->read_bitvalue(wWCirc_, 7, 7);
// warm water storage sensors (if present) // warm water storage sensors (if present)
// wwStorageTemp2 is also used by some brands as the boiler temperature - see https://github.com/proddy/EMS-ESP/issues/206 // wwStorageTemp2 is also used by some brands as the boiler temperature - see https://github.com/proddy/EMS-ESP/issues/206
telegram->read_value(wwStorageTemp1_, 9); // 0x8300 if not available changed_ |= telegram->read_value(wwStorageTemp1_, 9); // 0x8300 if not available
telegram->read_value(wwStorageTemp2_, 11); // 0x8000 if not available - this is boiler temp changed_ |= telegram->read_value(wwStorageTemp2_, 11); // 0x8000 if not available - this is boiler temp
telegram->read_value(retTemp_, 13); changed_ |= telegram->read_value(retTemp_, 13);
telegram->read_value(flameCurr_, 15); changed_ |= telegram->read_value(flameCurr_, 15);
telegram->read_value(serviceCode_, 20); changed_ |= telegram->read_value(serviceCode_, 20);
// system pressure. FF means missing // system pressure. FF means missing
telegram->read_value(sysPress_, 17); // is *10 changed_ |= telegram->read_value(sysPress_, 17); // is *10
// read the service code / installation status as appears on the display // read the service code / installation status as appears on the display
if ((telegram->message_length > 18) && (telegram->offset == 0)) { if ((telegram->message_length > 18) && (telegram->offset == 0)) {
@@ -519,22 +523,22 @@ void Boiler::process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram) {
* received only after requested (not broadcasted) * received only after requested (not broadcasted)
*/ */
void Boiler::process_UBATotalUptime(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBATotalUptime(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(UBAuptime_, 0, 3); // force to 3 bytes changed_ |= telegram->read_value(UBAuptime_, 0, 3); // force to 3 bytes
} }
/* /*
* UBAParameters - type 0x16 * UBAParameters - type 0x16
*/ */
void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(heating_temp_, 1); changed_ |= telegram->read_value(heating_temp_, 1);
telegram->read_value(burnPowermax_, 2); changed_ |= telegram->read_value(burnPowermax_, 2);
telegram->read_value(burnPowermin_, 3); changed_ |= telegram->read_value(burnPowermin_, 3);
telegram->read_value(boilTemp_off_, 4); changed_ |= telegram->read_value(boilTemp_off_, 4);
telegram->read_value(boilTemp_on_, 5); changed_ |= telegram->read_value(boilTemp_on_, 5);
telegram->read_value(burnPeriod_, 6); changed_ |= telegram->read_value(burnPeriod_, 6);
telegram->read_value(pumpDelay_, 8); changed_ |= telegram->read_value(pumpDelay_, 8);
telegram->read_value(pump_mod_max_, 9); changed_ |= telegram->read_value(pump_mod_max_, 9);
telegram->read_value(pump_mod_min_, 10); changed_ |= telegram->read_value(pump_mod_min_, 10);
} }
/* /*
@@ -542,19 +546,19 @@ void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) {
* received every 10 seconds * received every 10 seconds
*/ */
void Boiler::process_UBAMonitorWW(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAMonitorWW(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(wWSetTmp_, 0); changed_ |= telegram->read_value(wWSetTmp_, 0);
telegram->read_value(wWCurTmp_, 1); changed_ |= telegram->read_value(wWCurTmp_, 1);
telegram->read_value(wWCurTmp2_, 3); changed_ |= telegram->read_value(wWCurTmp2_, 3);
telegram->read_value(wWCurFlow_, 9); changed_ |= telegram->read_value(wWCurFlow_, 9);
telegram->read_value(wWWorkM_, 10, 3); // force to 3 bytes changed_ |= telegram->read_value(wWWorkM_, 10, 3); // force to 3 bytes
telegram->read_value(wWStarts_, 13, 3); // force to 3 bytes changed_ |= telegram->read_value(wWStarts_, 13, 3); // force to 3 bytes
telegram->read_bitvalue(wWOneTime_, 5, 1); changed_ |= telegram->read_bitvalue(wWOneTime_, 5, 1);
telegram->read_bitvalue(wWDisinfecting_, 5, 2); changed_ |= telegram->read_bitvalue(wWDisinfecting_, 5, 2);
telegram->read_bitvalue(wWReadiness_, 5, 3); changed_ |= telegram->read_bitvalue(wWReadiness_, 5, 3);
telegram->read_bitvalue(wWRecharging_, 5, 4); changed_ |= telegram->read_bitvalue(wWRecharging_, 5, 4);
telegram->read_bitvalue(wWTemperatureOK_, 5, 5); changed_ |= telegram->read_bitvalue(wWTemperatureOK_, 5, 5);
} }
/* /*
@@ -562,13 +566,13 @@ void Boiler::process_UBAMonitorWW(std::shared_ptr<const Telegram> telegram) {
* Still to figure out are: serviceCode, retTemp, sysPress * Still to figure out are: serviceCode, retTemp, sysPress
*/ */
void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(selFlowTemp_, 6); changed_ |= telegram->read_value(selFlowTemp_, 6);
telegram->read_bitvalue(burnGas_, 11, 0); changed_ |= telegram->read_bitvalue(burnGas_, 11, 0);
telegram->read_bitvalue(wWHeat_, 11, 2); changed_ |= telegram->read_bitvalue(wWHeat_, 11, 2);
telegram->read_value(curBurnPow_, 10); changed_ |= telegram->read_value(curBurnPow_, 10);
telegram->read_value(selBurnPow_, 9); changed_ |= telegram->read_value(selBurnPow_, 9);
telegram->read_value(curFlowTemp_, 7); changed_ |= telegram->read_value(curFlowTemp_, 7);
telegram->read_value(flameCurr_, 19); changed_ |= telegram->read_value(flameCurr_, 19);
// read the service code / installation status as appears on the display // read the service code / installation status as appears on the display
if ((telegram->message_length > 4) && (telegram->offset == 0)) { if ((telegram->message_length > 4) && (telegram->offset == 0)) {
@@ -589,79 +593,79 @@ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram
* 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 17 19 20 21 22 23 24 * 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 17 19 20 21 22 23 24
*/ */
void Boiler::process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(extTemp_, 0); changed_ |= telegram->read_value(extTemp_, 0);
telegram->read_value(boilTemp_, 2); changed_ |= telegram->read_value(boilTemp_, 2);
telegram->read_value(exhaustTemp_, 4); changed_ |= telegram->read_value(exhaustTemp_, 4);
telegram->read_value(switchTemp_, 25); // only if there is a mixing module present changed_ |= telegram->read_value(switchTemp_, 25); // only if there is a mixing module present
telegram->read_value(pumpMod_, 9); changed_ |= telegram->read_value(pumpMod_, 9);
telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes changed_ |= telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes
telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes changed_ |= telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes
telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes changed_ |= telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes
} }
/* /*
* UBAMonitorSlowPlus2 - type 0xE3 * UBAMonitorSlowPlus2 - type 0xE3
*/ */
void Boiler::process_UBAMonitorSlowPlus2(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAMonitorSlowPlus2(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(pumpMod2_, 13); changed_ |= telegram->read_value(pumpMod2_, 13);
} }
/* /*
* UBAMonitorSlowPlus - type 0xE5 - central heating monitor EMS+ * UBAMonitorSlowPlus - type 0xE5 - central heating monitor EMS+
*/ */
void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram) {
telegram->read_bitvalue(fanWork_, 2, 2); changed_ |= telegram->read_bitvalue(fanWork_, 2, 2);
telegram->read_bitvalue(ignWork_, 2, 3); changed_ |= telegram->read_bitvalue(ignWork_, 2, 3);
telegram->read_bitvalue(heatPmp_, 2, 5); changed_ |= telegram->read_bitvalue(heatPmp_, 2, 5);
telegram->read_bitvalue(wWCirc_, 2, 7); changed_ |= telegram->read_bitvalue(wWCirc_, 2, 7);
telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes changed_ |= telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes
telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes changed_ |= telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes
telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes changed_ |= telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes
telegram->read_value(pumpMod_, 25); changed_ |= telegram->read_value(pumpMod_, 25);
} }
// 0xE9 - DHW Status // 0xE9 - DHW Status
// e.g. 08 00 E9 00 37 01 F6 01 ED 00 00 00 00 41 3C 00 00 00 00 00 00 00 00 00 00 00 00 37 00 00 00 (CRC=77) #data=27 // e.g. 08 00 E9 00 37 01 F6 01 ED 00 00 00 00 41 3C 00 00 00 00 00 00 00 00 00 00 00 00 37 00 00 00 (CRC=77) #data=27
void Boiler::process_UBADHWStatus(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBADHWStatus(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(wWSetTmp_, 0); changed_ |= telegram->read_value(wWSetTmp_, 0);
telegram->read_value(wWCurTmp_, 1); changed_ |= telegram->read_value(wWCurTmp_, 1);
telegram->read_value(wWCurTmp2_, 3); changed_ |= telegram->read_value(wWCurTmp2_, 3);
telegram->read_value(wWWorkM_, 17, 3); // force to 3 bytes changed_ |= telegram->read_value(wWWorkM_, 17, 3); // force to 3 bytes
telegram->read_value(wWStarts_, 14, 3); // force to 3 bytes changed_ |= telegram->read_value(wWStarts_, 14, 3); // force to 3 bytes
telegram->read_bitvalue(wWOneTime_, 12, 2); changed_ |= telegram->read_bitvalue(wWOneTime_, 12, 2);
telegram->read_bitvalue(wWDisinfecting_, 12, 3); changed_ |= telegram->read_bitvalue(wWDisinfecting_, 12, 3);
telegram->read_bitvalue(wWReadiness_, 12, 4); changed_ |= telegram->read_bitvalue(wWReadiness_, 12, 4);
telegram->read_bitvalue(wWRecharging_, 13, 4); changed_ |= telegram->read_bitvalue(wWRecharging_, 13, 4);
telegram->read_bitvalue(wWTemperatureOK_, 13, 5); changed_ |= telegram->read_bitvalue(wWTemperatureOK_, 13, 5);
telegram->read_bitvalue(wWCircPump_, 13, 2); changed_ |= telegram->read_bitvalue(wWCircPump_, 13, 2);
telegram->read_value(wWActivated_, 20); changed_ |= telegram->read_value(wWActivated_, 20);
telegram->read_value(wWSelTemp_, 10); changed_ |= telegram->read_value(wWSelTemp_, 10);
telegram->read_value(wWDisinfectTemp_, 9); changed_ |= telegram->read_value(wWDisinfectTemp_, 9);
} }
// 0x2A - MC10Status // 0x2A - MC10Status
// e.g. 88 00 2A 00 00 00 00 00 00 00 00 00 D2 00 00 80 00 00 01 08 80 00 02 47 00 // e.g. 88 00 2A 00 00 00 00 00 00 00 00 00 D2 00 00 80 00 00 01 08 80 00 02 47 00
// see https://github.com/proddy/EMS-ESP/issues/397 // see https://github.com/proddy/EMS-ESP/issues/397
void Boiler::process_MC10Status(std::shared_ptr<const Telegram> telegram) { void Boiler::process_MC10Status(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(wwMixTemperature_, 14); changed_ |= telegram->read_value(wwMixTemperature_, 14);
telegram->read_value(wwBufferBoilerTemperature_, 18); changed_ |= telegram->read_value(wwBufferBoilerTemperature_, 18);
} }
/* /*
* UBAOutdoorTemp - type 0xD1 - external temperature EMS+ * UBAOutdoorTemp - type 0xD1 - external temperature EMS+
*/ */
void Boiler::process_UBAOutdoorTemp(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBAOutdoorTemp(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(extTemp_, 0); changed_ |= telegram->read_value(extTemp_, 0);
} }
// UBASetPoint 0x1A // UBASetPoint 0x1A
void Boiler::process_UBASetPoints(std::shared_ptr<const Telegram> telegram) { void Boiler::process_UBASetPoints(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(setFlowTemp_, 0); // boiler set temp from thermostat changed_ |= telegram->read_value(setFlowTemp_, 0); // boiler set temp from thermostat
telegram->read_value(setBurnPow_, 1); // max output power in % changed_ |= telegram->read_value(setBurnPow_, 1); // max output power in %
telegram->read_value(setWWPumpPow_, 2); // ww pump speed/power? changed_ |= telegram->read_value(setWWPumpPow_, 2); // ww pump speed/power?
} }
#pragma GCC diagnostic push #pragma GCC diagnostic push

View File

@@ -53,6 +53,7 @@ class Boiler : public EMSdevice {
uint8_t last_boilerState = 0xFF; // remember last state of heating and warm water on/off uint8_t last_boilerState = 0xFF; // remember last state of heating and warm water on/off
uint8_t mqtt_format_; // single, nested or ha uint8_t mqtt_format_; // single, nested or ha
bool changed_ = false;;
static constexpr uint8_t EMS_TYPE_UBAParameterWW = 0x33; static constexpr uint8_t EMS_TYPE_UBAParameterWW = 0x33;
static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D; static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D;

View File

@@ -82,6 +82,10 @@ void Mixing::device_info(JsonArray & root) {
// check to see if values have been updated // check to see if values have been updated
bool Mixing::updated_values() { bool Mixing::updated_values() {
if (changed_) {
changed_ = false;
return true;
}
return false; return false;
} }
@@ -165,10 +169,10 @@ void Mixing::publish_values() {
void Mixing::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram) { void Mixing::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram) {
type_ = Type::HC; type_ = Type::HC;
hc_ = telegram->type_id - 0x02D7 + 1; // determine which circuit this is hc_ = telegram->type_id - 0x02D7 + 1; // determine which circuit this is
telegram->read_value(flowTemp_, 3); // is * 10 changed_ |= telegram->read_value(flowTemp_, 3); // is * 10
telegram->read_value(flowSetTemp_, 5); changed_ |= telegram->read_value(flowSetTemp_, 5);
telegram->read_value(pumpMod_, 2); changed_ |= telegram->read_value(pumpMod_, 2);
telegram->read_value(status_, 1); // valve status changed_ |= telegram->read_value(status_, 1); // valve status
} }
// Mixing module warm water loading/DHW - 0x0331, 0x0332 // Mixing module warm water loading/DHW - 0x0331, 0x0332
@@ -177,9 +181,9 @@ void Mixing::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> tele
void Mixing::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram) { void Mixing::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> telegram) {
type_ = Type::WWC; type_ = Type::WWC;
hc_ = telegram->type_id - 0x0331 + 1; // determine which circuit this is. There are max 2. hc_ = telegram->type_id - 0x0331 + 1; // determine which circuit this is. There are max 2.
telegram->read_value(flowTemp_, 0); // is * 10 changed_ |= telegram->read_value(flowTemp_, 0); // is * 10
telegram->read_value(pumpMod_, 2); changed_ |= telegram->read_value(pumpMod_, 2);
telegram->read_value(status_, 11); // temp status changed_ |= telegram->read_value(status_, 11); // temp status
} }
// Mixing IMP - 0x010C // Mixing IMP - 0x010C
@@ -189,17 +193,17 @@ void Mixing::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram)
type_ = Type::HC; type_ = Type::HC;
hc_ = get_device_id() - 0x20 + 1; hc_ = get_device_id() - 0x20 + 1;
uint8_t ismixed = 0; uint8_t ismixed = 0;
telegram->read_value(ismixed, 0); // check if circuit is active, 0-off, 1-unmixed, 2-mixed changed_ |= telegram->read_value(ismixed, 0); // check if circuit is active, 0-off, 1-unmixed, 2-mixed
if (ismixed == 0) { if (ismixed == 0) {
return; return;
} }
if (ismixed == 2) { // we have a mixed circuit if (ismixed == 2) { // we have a mixed circuit
telegram->read_value(flowTemp_, 3); // is * 10 changed_ |= telegram->read_value(flowTemp_, 3); // is * 10
telegram->read_value(flowSetTemp_, 5); changed_ |= telegram->read_value(flowSetTemp_, 5);
telegram->read_value(status_, 2); // valve status changed_ |= telegram->read_value(status_, 2); // valve status
} }
uint8_t pump = 0xFF; uint8_t pump = 0xFF;
telegram->read_bitvalue(pump, 1, 0); // pump is also in unmixed circuits changed_ |= telegram->read_bitvalue(pump, 1, 0); // pump is also in unmixed circuits
if (pump != 0xFF) { if (pump != 0xFF) {
pumpMod_ = 100 * pump; pumpMod_ = 100 * pump;
} }
@@ -215,9 +219,9 @@ void Mixing::process_MMStatusMessage(std::shared_ptr<const Telegram> telegram) {
// 0x21 is position 2. 0x20 is typically reserved for the WM10 switch module // 0x21 is position 2. 0x20 is typically reserved for the WM10 switch module
// see https://github.com/proddy/EMS-ESP/issues/270 and https://github.com/proddy/EMS-ESP/issues/386#issuecomment-629610918 // see https://github.com/proddy/EMS-ESP/issues/270 and https://github.com/proddy/EMS-ESP/issues/386#issuecomment-629610918
hc_ = get_device_id() - 0x20 + 1; hc_ = get_device_id() - 0x20 + 1;
telegram->read_value(flowTemp_, 1); // is * 10 changed_ |= telegram->read_value(flowTemp_, 1); // is * 10
telegram->read_value(pumpMod_, 3); changed_ |= telegram->read_value(pumpMod_, 3);
telegram->read_value(flowSetTemp_, 0); changed_ |= telegram->read_value(flowSetTemp_, 0);
} }
#pragma GCC diagnostic push #pragma GCC diagnostic push

View File

@@ -66,6 +66,7 @@ class Mixing : public EMSdevice {
uint8_t status_ = EMS_VALUE_UINT_NOTSET; uint8_t status_ = EMS_VALUE_UINT_NOTSET;
uint8_t flowSetTemp_ = EMS_VALUE_UINT_NOTSET; uint8_t flowSetTemp_ = EMS_VALUE_UINT_NOTSET;
Type type_ = Type::NONE; Type type_ = Type::NONE;
bool changed_ = false;
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -168,11 +168,18 @@ void Solar::publish_values() {
doc["energyTotal"] = (float)energyTotal_ / 10; doc["energyTotal"] = (float)energyTotal_ / 10;
} }
Mqtt::publish("sm_data", doc); // if we have data, publish it
if (!doc.isNull()) {
Mqtt::publish("sm_data", doc);
}
} }
// check to see if values have been updated // check to see if values have been updated
bool Solar::updated_values() { bool Solar::updated_values() {
if (changed_) {
changed_ = false;
return true;
}
return false; return false;
} }
@@ -182,11 +189,11 @@ void Solar::console_commands() {
// SM10Monitor - type 0x97 // SM10Monitor - type 0x97
void Solar::process_SM10Monitor(std::shared_ptr<const Telegram> telegram) { void Solar::process_SM10Monitor(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(collectorTemp_, 2); // collector temp from SM10, is *10 changed_ |= telegram->read_value(collectorTemp_, 2); // collector temp from SM10, is *10
telegram->read_value(tankBottomTemp_, 5); // bottom temp from SM10, is *10 changed_ |= telegram->read_value(tankBottomTemp_, 5); // bottom temp from SM10, is *10
telegram->read_value(solarPumpModulation_, 4); // modulation solar pump changed_ |= telegram->read_value(solarPumpModulation_, 4); // modulation solar pump
telegram->read_bitvalue(solarPump_, 7, 1); changed_ |= telegram->read_bitvalue(solarPump_, 7, 1);
telegram->read_value(pumpWorkMin_, 8); changed_ |= telegram->read_value(pumpWorkMin_, 8);
} }
/* /*
@@ -201,10 +208,10 @@ void Solar::process_SM10Monitor(std::shared_ptr<const Telegram> telegram) {
* bytes 20+21 = TS6 Temperature sensor external heat exchanger * bytes 20+21 = TS6 Temperature sensor external heat exchanger
*/ */
void Solar::process_SM100Monitor(std::shared_ptr<const Telegram> telegram) { void Solar::process_SM100Monitor(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(collectorTemp_, 0); // is *10 - TS1: Temperature sensor for collector array 1 changed_ |= telegram->read_value(collectorTemp_, 0); // is *10 - TS1: Temperature sensor for collector array 1
telegram->read_value(tankBottomTemp_, 2); // is *10 - TS2: Temperature sensor 1 cylinder, bottom changed_ |= telegram->read_value(tankBottomTemp_, 2); // is *10 - TS2: Temperature sensor 1 cylinder, bottom
telegram->read_value(tankBottomTemp2_, 16); // is *10 - TS5: Temperature sensor 2 cylinder, bottom, or swimming pool changed_ |= telegram->read_value(tankBottomTemp2_, 16); // is *10 - TS5: Temperature sensor 2 cylinder, bottom, or swimming pool
telegram->read_value(heatExchangerTemp_, 20); // is *10 - TS6: Heat exchanger temperature sensor changed_ |= telegram->read_value(heatExchangerTemp_, 20); // is *10 - TS6: Heat exchanger temperature sensor
} }
#pragma GCC diagnostic push #pragma GCC diagnostic push
@@ -221,9 +228,9 @@ void Solar::process_SM100Monitor2(std::shared_ptr<const Telegram> telegram) {
// SM100Config - 0x0366 // SM100Config - 0x0366
// e.g. B0 00 FF 00 02 66 01 62 00 13 40 14 // e.g. B0 00 FF 00 02 66 01 62 00 13 40 14
void Solar::process_SM100Config(std::shared_ptr<const Telegram> telegram) { void Solar::process_SM100Config(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(availabilityFlag_, 0); changed_ |= telegram->read_value(availabilityFlag_, 0);
telegram->read_value(configFlag_, 1); changed_ |= telegram->read_value(configFlag_, 1);
telegram->read_value(userFlag_, 2); changed_ |= telegram->read_value(userFlag_, 2);
} }
/* /*
@@ -235,8 +242,8 @@ void Solar::process_SM100Config(std::shared_ptr<const Telegram> telegram) {
void Solar::process_SM100Status(std::shared_ptr<const Telegram> telegram) { void Solar::process_SM100Status(std::shared_ptr<const Telegram> telegram) {
uint8_t solarpumpmod = solarPumpModulation_; uint8_t solarpumpmod = solarPumpModulation_;
uint8_t cylinderpumpmod = cylinderPumpModulation_; uint8_t cylinderpumpmod = cylinderPumpModulation_;
telegram->read_value(cylinderPumpModulation_, 8); changed_ |= telegram->read_value(cylinderPumpModulation_, 8);
telegram->read_value(solarPumpModulation_, 9); changed_ |= telegram->read_value(solarPumpModulation_, 9);
if (solarpumpmod == 0 && solarPumpModulation_ == 100) { // mask out boosts if (solarpumpmod == 0 && solarPumpModulation_ == 100) { // mask out boosts
solarPumpModulation_ = 15; // set to minimum solarPumpModulation_ = 15; // set to minimum
@@ -245,8 +252,8 @@ void Solar::process_SM100Status(std::shared_ptr<const Telegram> telegram) {
if (cylinderpumpmod == 0 && cylinderPumpModulation_ == 100) { // mask out boosts if (cylinderpumpmod == 0 && cylinderPumpModulation_ == 100) { // mask out boosts
cylinderPumpModulation_ = 15; // set to minimum cylinderPumpModulation_ = 15; // set to minimum
} }
telegram->read_bitvalue(tankHeated_, 3, 1); // issue #422 changed_ |= telegram->read_bitvalue(tankHeated_, 3, 1); // issue #422
telegram->read_bitvalue(collectorShutdown_, 3, 0); // collector shutdown changed_ |= telegram->read_bitvalue(collectorShutdown_, 3, 0); // collector shutdown
} }
/* /*
@@ -256,8 +263,8 @@ void Solar::process_SM100Status(std::shared_ptr<const Telegram> telegram) {
* byte 10 = PS1 Solar circuit pump for collector array 1: test=b0001(1), on=b0100(4) and off=b0011(3) * byte 10 = PS1 Solar circuit pump for collector array 1: test=b0001(1), on=b0100(4) and off=b0011(3)
*/ */
void Solar::process_SM100Status2(std::shared_ptr<const Telegram> telegram) { void Solar::process_SM100Status2(std::shared_ptr<const Telegram> telegram) {
telegram->read_bitvalue(valveStatus_, 4, 2); // on if bit 2 set changed_ |= telegram->read_bitvalue(valveStatus_, 4, 2); // on if bit 2 set
telegram->read_bitvalue(solarPump_, 10, 2); // on if bit 2 set changed_ |= telegram->read_bitvalue(solarPump_, 10, 2); // on if bit 2 set
} }
/* /*
@@ -265,9 +272,9 @@ void Solar::process_SM100Status2(std::shared_ptr<const Telegram> telegram) {
* e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35 * e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35
*/ */
void Solar::process_SM100Energy(std::shared_ptr<const Telegram> telegram) { void Solar::process_SM100Energy(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(energyLastHour_, 0); // last hour / 10 in Wh changed_ |= telegram->read_value(energyLastHour_, 0); // last hour / 10 in Wh
telegram->read_value(energyToday_, 4); // todays in Wh changed_ |= telegram->read_value(energyToday_, 4); // todays in Wh
telegram->read_value(energyTotal_, 8); // total / 10 in kWh changed_ |= telegram->read_value(energyTotal_, 8); // total / 10 in kWh
} }
/* /*
@@ -275,26 +282,26 @@ void Solar::process_SM100Energy(std::shared_ptr<const Telegram> telegram) {
* e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 * e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0
*/ */
void Solar::process_ISM1StatusMessage(std::shared_ptr<const Telegram> telegram) { void Solar::process_ISM1StatusMessage(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(collectorTemp_, 4); // Collector Temperature changed_ |= telegram->read_value(collectorTemp_, 4); // Collector Temperature
telegram->read_value(tankBottomTemp_, 6); // Temperature Bottom of Solar Boiler changed_ |= telegram->read_value(tankBottomTemp_, 6); // Temperature Bottom of Solar Boiler
uint16_t Wh = 0xFFFF; uint16_t Wh = 0xFFFF;
telegram->read_value(Wh, 2); // Solar Energy produced in last hour only ushort, is not * 10 changed_ |= telegram->read_value(Wh, 2); // Solar Energy produced in last hour only ushort, is not * 10
if (Wh != 0xFFFF) { if (Wh != 0xFFFF) {
energyLastHour_ = Wh * 10; // set to *10 energyLastHour_ = Wh * 10; // set to *10
} }
telegram->read_bitvalue(solarPump_, 8, 0); // PS1 Solar pump on (1) or off (0) changed_ |= telegram->read_bitvalue(solarPump_, 8, 0); // PS1 Solar pump on (1) or off (0)
telegram->read_value(pumpWorkMin_, 10, 3); // force to 3 bytes changed_ |= telegram->read_value(pumpWorkMin_, 10, 3); // force to 3 bytes
telegram->read_bitvalue(collectorShutdown_, 9, 0); // collector shutdown on/off changed_ |= telegram->read_bitvalue(collectorShutdown_, 9, 0); // collector shutdown on/off
telegram->read_bitvalue(tankHeated_, 9, 2); // tank full changed_ |= telegram->read_bitvalue(tankHeated_, 9, 2); // tank full
} }
/* /*
* Junkers ISM1 Solar Module - type 0x0101 EMS+ for setting values * Junkers ISM1 Solar Module - type 0x0101 EMS+ for setting values
*/ */
void Solar::process_ISM1Set(std::shared_ptr<const Telegram> telegram) { void Solar::process_ISM1Set(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(setpoint_maxBottomTemp_, 6); changed_ |= telegram->read_value(setpoint_maxBottomTemp_, 6);
} }
} // namespace emsesp } // namespace emsesp

View File

@@ -65,6 +65,7 @@ class Solar : public EMSdevice {
uint8_t availabilityFlag_ = EMS_VALUE_BOOL_NOTSET; uint8_t availabilityFlag_ = EMS_VALUE_BOOL_NOTSET;
uint8_t configFlag_ = EMS_VALUE_BOOL_NOTSET; uint8_t configFlag_ = EMS_VALUE_BOOL_NOTSET;
uint8_t userFlag_ = EMS_VALUE_BOOL_NOTSET; uint8_t userFlag_ = EMS_VALUE_BOOL_NOTSET;
bool changed_ = false;
void process_SM10Monitor(std::shared_ptr<const Telegram> telegram); void process_SM10Monitor(std::shared_ptr<const Telegram> telegram);
void process_SM100Monitor(std::shared_ptr<const Telegram> telegram); void process_SM100Monitor(std::shared_ptr<const Telegram> telegram);

View File

@@ -242,23 +242,10 @@ bool Thermostat::updated_values() {
if (EMSESP::actual_master_thermostat() != this->get_device_id()) { if (EMSESP::actual_master_thermostat() != this->get_device_id()) {
return false; return false;
} }
if (changed_) {
// quick hack to see if it changed. We simply just add up all the raw values changed_ = false;
uint16_t new_value = 0;
static uint16_t current_value_ = 0;
for (const auto & hc : heating_circuits_) {
// don't publish if we haven't yet received some data
if (!Helpers::hasValue(hc->setpoint_roomTemp)) {
return false;
}
new_value += hc->setpoint_roomTemp + hc->curr_roomTemp + hc->mode;
}
if (new_value != current_value_) {
current_value_ = new_value;
return true; return true;
} }
return false; return false;
} }
@@ -902,16 +889,16 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
void Thermostat::process_RC20Set(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC20Set(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->mode, 23); changed_ |= telegram->read_value(hc->mode, 23);
} }
// type 0xAE - data from the RC20 thermostat (0x17) // type 0xAE - data from the RC20 thermostat (0x17)
void Thermostat::process_RC20Monitor_2(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC20Monitor_2(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_bitvalue(hc->mode_type, 0, 7); // day/night MSB 7th bit is day changed_ |= telegram->read_bitvalue(hc->mode_type, 0, 7); // day/night MSB 7th bit is day
telegram->read_value(hc->setpoint_roomTemp, 2, 1); // is * 2, force as single byte changed_ |= telegram->read_value(hc->setpoint_roomTemp, 2, 1); // is * 2, force as single byte
telegram->read_value(hc->curr_roomTemp, 3); // is * 10 changed_ |= telegram->read_value(hc->curr_roomTemp, 3); // is * 10
} }
// 0xAD - for reading the mode from the RC20/ES72 thermostat (0x17) // 0xAD - for reading the mode from the RC20/ES72 thermostat (0x17)
@@ -919,21 +906,21 @@ void Thermostat::process_RC20Monitor_2(std::shared_ptr<const Telegram> telegram)
void Thermostat::process_RC20Set_2(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC20Set_2(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->mode, 3); changed_ |= telegram->read_value(hc->mode, 3);
} }
// 0xAF - for reading the roomtemperature from the RC20/ES72 thermostat (0x18, 0x19, ..) // 0xAF - for reading the roomtemperature from the RC20/ES72 thermostat (0x18, 0x19, ..)
void Thermostat::process_RC20Remote(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC20Remote(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->curr_roomTemp, 0); changed_ |= telegram->read_value(hc->curr_roomTemp, 0);
} }
// type 0xB1 - data from the RC10 thermostat (0x17) // type 0xB1 - data from the RC10 thermostat (0x17)
void Thermostat::process_RC10Monitor(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC10Monitor(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte changed_ |= telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte
telegram->read_value(hc->curr_roomTemp, 2); // is * 10 changed_ |= telegram->read_value(hc->curr_roomTemp, 2); // is * 10
} }
#pragma GCC diagnostic push #pragma GCC diagnostic push
@@ -948,56 +935,56 @@ void Thermostat::process_RC10Set(std::shared_ptr<const Telegram> telegram) {
// type 0x0165, ff // type 0x0165, ff
void Thermostat::process_JunkersSet(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_JunkersSet(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->daytemp, 17); // is * 2 changed_ |= telegram->read_value(hc->daytemp, 17); // is * 2
telegram->read_value(hc->nighttemp, 16); // is * 2 changed_ |= telegram->read_value(hc->nighttemp, 16); // is * 2
telegram->read_value(hc->nofrosttemp, 15); // is * 2 changed_ |= telegram->read_value(hc->nofrosttemp, 15); // is * 2
} }
// type 0x0179, ff // type 0x0179, ff
void Thermostat::process_JunkersSet2(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_JunkersSet2(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->daytemp, 7); // is * 2 changed_ |= telegram->read_value(hc->daytemp, 7); // is * 2
telegram->read_value(hc->nighttemp, 6); // is * 2 changed_ |= telegram->read_value(hc->nighttemp, 6); // is * 2
telegram->read_value(hc->nofrosttemp, 5); // is * 2 changed_ |= telegram->read_value(hc->nofrosttemp, 5); // is * 2
} }
// type 0xA3 - for external temp settings from the the RC* thermostats (e.g. RC35) // type 0xA3 - for external temp settings from the the RC* thermostats (e.g. RC35)
void Thermostat::process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(dampedoutdoortemp_, 0); changed_ |= telegram->read_value(dampedoutdoortemp_, 0);
telegram->read_value(tempsensor1_, 3); // sensor 1 - is * 10 changed_ |= telegram->read_value(tempsensor1_, 3); // sensor 1 - is * 10
telegram->read_value(tempsensor2_, 5); // sensor 2 - is * 10 changed_ |= telegram->read_value(tempsensor2_, 5); // sensor 2 - is * 10
} }
// 0x91 - data from the RC20 thermostat (0x17) - 15 bytes long // 0x91 - data from the RC20 thermostat (0x17) - 15 bytes long
void Thermostat::process_RC20Monitor(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC20Monitor(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte changed_ |= telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte
telegram->read_value(hc->curr_roomTemp, 2); // is * 10 changed_ |= telegram->read_value(hc->curr_roomTemp, 2); // is * 10
} }
// type 0x0A - data from the Nefit Easy/TC100 thermostat (0x18) - 31 bytes long // type 0x0A - data from the Nefit Easy/TC100 thermostat (0x18) - 31 bytes long
void Thermostat::process_EasyMonitor(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_EasyMonitor(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->curr_roomTemp, 8); // is * 100 changed_ |= telegram->read_value(hc->curr_roomTemp, 8); // is * 100
telegram->read_value(hc->setpoint_roomTemp, 10); // is * 100 changed_ |= telegram->read_value(hc->setpoint_roomTemp, 10); // is * 100
} }
// 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) {
// 22 - display line on RC35 // 22 - display line on RC35
telegram->read_value(ibaMainDisplay_, changed_ |= 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, 8 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 changed_ |= 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 changed_ |= 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 changed_ |= telegram->read_value(ibaBuildingType_, 6); // building type: 0 = light, 1 = medium, 2 = heavy
telegram->read_value(ibaMinExtTemperature_, 5); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1 changed_ |= telegram->read_value(ibaMinExtTemperature_, 5); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1
telegram->read_value(ibaClockOffset_, 12); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s changed_ |= telegram->read_value(ibaClockOffset_, 12); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
} }
// Settings WW 0x37 - RC35 // Settings WW 0x37 - RC35
void Thermostat::process_RC35wwSettings(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC35wwSettings(std::shared_ptr<const Telegram> telegram) {
telegram->read_value(wwMode_, 2); // 0 off, 1-on, 2-auto changed_ |= telegram->read_value(wwMode_, 2); // 0 off, 1-on, 2-auto
} }
// type 0x6F - FR10/FR50/FR100 Junkers // type 0x6F - FR10/FR50/FR100 Junkers
@@ -1009,21 +996,21 @@ void Thermostat::process_JunkersMonitor(std::shared_ptr<const Telegram> telegram
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->curr_roomTemp, 4); // value is * 10 changed_ |= telegram->read_value(hc->curr_roomTemp, 4); // value is * 10
telegram->read_value(hc->setpoint_roomTemp, 2); // value is * 10 changed_ |= telegram->read_value(hc->setpoint_roomTemp, 2); // value is * 10
telegram->read_value(hc->mode_type, 0); // 1 = nofrost, 2 = eco, 3 = heat changed_ |= telegram->read_value(hc->mode_type, 0); // 1 = nofrost, 2 = eco, 3 = heat
telegram->read_value(hc->mode, 1); // 1 = manual, 2 = auto changed_ |= telegram->read_value(hc->mode, 1); // 1 = manual, 2 = auto
} }
// type 0x02A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10 // type 0x02A5 - data from the Nefit RC1010/3000 thermostat (0x18) and RC300/310s on 0x10
void Thermostat::process_RC300Monitor(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC300Monitor(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->curr_roomTemp, 0); // is * 10 changed_ |= telegram->read_value(hc->curr_roomTemp, 0); // is * 10
telegram->read_bitvalue(hc->mode_type, 10, 1); changed_ |= telegram->read_bitvalue(hc->mode_type, 10, 1);
telegram->read_bitvalue(hc->mode, 10, 0); // bit 1, mode (auto=1 or manual=0) changed_ |= telegram->read_bitvalue(hc->mode, 10, 0); // bit 1, mode (auto=1 or manual=0)
// if manual, take the current setpoint temp at pos 6 // if manual, take the current setpoint temp at pos 6
// if auto, take the next setpoint temp at pos 7 // if auto, take the next setpoint temp at pos 7
@@ -1032,9 +1019,9 @@ void Thermostat::process_RC300Monitor(std::shared_ptr<const Telegram> telegram)
// pos 3 actual setpoint (optimized), i.e. changes with temporary change, summer/holiday-modes // pos 3 actual setpoint (optimized), i.e. changes with temporary change, summer/holiday-modes
// pos 6 actual setpoint according to programmed changes eco/comfort // pos 6 actual setpoint according to programmed changes eco/comfort
// pos 7 next setpoint in the future, time to next setpoint in pos 8/9 // pos 7 next setpoint in the future, time to next setpoint in pos 8/9
telegram->read_value(hc->setpoint_roomTemp, 3, 1); // is * 2, force as single byte changed_ |= telegram->read_value(hc->setpoint_roomTemp, 3, 1); // is * 2, force as single byte
telegram->read_bitvalue(hc->summer_mode, 2, 4); changed_ |= telegram->read_bitvalue(hc->summer_mode, 2, 4);
telegram->read_value(hc->targetflowtemp, 4); changed_ |= telegram->read_value(hc->targetflowtemp, 4);
} }
// type 0x02B9 EMS+ for reading from RC300/RC310 thermostat // type 0x02B9 EMS+ for reading from RC300/RC310 thermostat
@@ -1046,21 +1033,21 @@ void Thermostat::process_RC300Set(std::shared_ptr<const Telegram> telegram) {
// comfort is position 2 // comfort is position 2
// I think auto is position 8? // I think auto is position 8?
// actual setpoint taken from RC300Monitor (Michael 12.06.2020) // actual setpoint taken from RC300Monitor (Michael 12.06.2020)
// telegram->read_value(hc->setpoint_roomTemp, 8, 1); // single byte conversion, value is * 2 - auto? // changed_ |= telegram->read_value(hc->setpoint_roomTemp, 8, 1); // single byte conversion, value is * 2 - auto?
// telegram->read_value(hc->setpoint_roomTemp, 10, 1); // single byte conversion, value is * 2 - manual // changed_ |= telegram->read_value(hc->setpoint_roomTemp, 10, 1); // single byte conversion, value is * 2 - manual
// check why mode is both in the Monitor and Set for the RC300. It'll be read twice! // check why mode is both in the Monitor and Set for the RC300. It'll be read twice!
// telegram->read_value(hc->mode, 0); // Auto = xFF, Manual = x00 eg. 10 00 FF 08 01 B9 FF // changed_ |= telegram->read_value(hc->mode, 0); // Auto = xFF, Manual = x00 eg. 10 00 FF 08 01 B9 FF
telegram->read_value(hc->daytemp, 2); // is * 2 changed_ |= telegram->read_value(hc->daytemp, 2); // is * 2
telegram->read_value(hc->nighttemp, 4); // is * 2 changed_ |= telegram->read_value(hc->nighttemp, 4); // is * 2
} }
// types 0x31D and 0x31E // types 0x31D and 0x31E
void Thermostat::process_RC300WWmode(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC300WWmode(std::shared_ptr<const Telegram> telegram) {
// 0x31D for WW system 1, 0x31E for WW system 2 // 0x31D for WW system 1, 0x31E for WW system 2
wwSystem_ = telegram->type_id - 0x31D + 1; wwSystem_ = telegram->type_id - 0x31D + 1;
telegram->read_value(wwExtra_, 0); // 0=no, 1=yes changed_ |= telegram->read_value(wwExtra_, 0); // 0=no, 1=yes
// pos 1 = holiday mode // pos 1 = holiday mode
// pos 2 = current status of DHW setpoint // pos 2 = current status of DHW setpoint
// pos 3 = current status of DHW circulation pump // pos 3 = current status of DHW circulation pump
@@ -1070,15 +1057,15 @@ void Thermostat::process_RC300WWmode(std::shared_ptr<const Telegram> telegram) {
void Thermostat::process_RC30Monitor(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC30Monitor(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte changed_ |= telegram->read_value(hc->setpoint_roomTemp, 1, 1); // is * 2, force as single byte
telegram->read_value(hc->curr_roomTemp, 2); changed_ |= telegram->read_value(hc->curr_roomTemp, 2);
} }
// type 0xA7 - for reading the mode from the RC30 thermostat (0x10) // type 0xA7 - for reading the mode from the RC30 thermostat (0x10)
void Thermostat::process_RC30Set(std::shared_ptr<const Telegram> telegram) { void Thermostat::process_RC30Set(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->mode, 23); changed_ |= telegram->read_value(hc->mode, 23);
} }
// 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
@@ -1092,14 +1079,14 @@ 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);
telegram->read_value(hc->setpoint_roomTemp, 2, 1); // is * 2, force to single byte, is 0 in summermode changed_ |= telegram->read_value(hc->setpoint_roomTemp, 2, 1); // is * 2, force to single byte, is 0 in summermode
telegram->read_value(hc->curr_roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler changed_ |= telegram->read_value(hc->curr_roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler
telegram->read_bitvalue(hc->mode_type, 1, 1); changed_ |= telegram->read_bitvalue(hc->mode_type, 1, 1);
telegram->read_bitvalue(hc->summer_mode, 1, 0); changed_ |= telegram->read_bitvalue(hc->summer_mode, 1, 0);
telegram->read_bitvalue(hc->holiday_mode, 0, 5); changed_ |= telegram->read_bitvalue(hc->holiday_mode, 0, 5);
telegram->read_value(hc->targetflowtemp, 14); changed_ |= telegram->read_value(hc->targetflowtemp, 14);
} }
// type 0x3D (HC1), 0x47 (HC2), 0x51 (HC3), 0x5B (HC4) - Working Mode Heating - for reading the mode from the RC35 thermostat (0x10) // type 0x3D (HC1), 0x47 (HC2), 0x51 (HC3), 0x5B (HC4) - Working Mode Heating - for reading the mode from the RC35 thermostat (0x10)
@@ -1111,16 +1098,16 @@ void Thermostat::process_RC35Set(std::shared_ptr<const Telegram> telegram) {
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram); std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
telegram->read_value(hc->mode, 7); // night, day, auto changed_ |= telegram->read_value(hc->mode, 7); // night, day, auto
telegram->read_value(hc->daytemp, 2); // is * 2 changed_ |= telegram->read_value(hc->daytemp, 2); // is * 2
telegram->read_value(hc->nighttemp, 1); // is * 2 changed_ |= telegram->read_value(hc->nighttemp, 1); // is * 2
telegram->read_value(hc->holidaytemp, 3); // is * 2 changed_ |= telegram->read_value(hc->holidaytemp, 3); // is * 2
telegram->read_value(hc->heatingtype, 0); // 0- off, 1-radiator, 2-convector, 3-floor changed_ |= telegram->read_value(hc->heatingtype, 0); // 0- off, 1-radiator, 2-convector, 3-floor
telegram->read_value(hc->summertemp, 22); // is * 1 changed_ |= telegram->read_value(hc->summertemp, 22); // is * 1
telegram->read_value(hc->nofrosttemp, 23); // is * 1 changed_ |= telegram->read_value(hc->nofrosttemp, 23); // is * 1
telegram->read_value(hc->designtemp, 17); // is * 1 changed_ |= telegram->read_value(hc->designtemp, 17); // is * 1
telegram->read_value(hc->offsettemp, 6); // is * 2 changed_ |= 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
@@ -1138,6 +1125,7 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
if (datetime_.empty()) { if (datetime_.empty()) {
datetime_.resize(25, '\0'); datetime_.resize(25, '\0');
} }
auto timeold = datetime_;
// render time to HH:MM:SS DD/MM/YYYY // render time to HH:MM:SS DD/MM/YYYY
// had to create separate buffers because of how printf works // had to create separate buffers because of how printf works
char buf1[6]; char buf1[6];
@@ -1156,6 +1144,9 @@ void Thermostat::process_RCTime(std::shared_ptr<const Telegram> telegram) {
Helpers::smallitoa(buf5, telegram->message_data[1]), // month Helpers::smallitoa(buf5, telegram->message_data[1]), // month
Helpers::itoa(buf6, telegram->message_data[0] + 2000, 10) // year Helpers::itoa(buf6, telegram->message_data[0] + 2000, 10) // year
); );
if (timeold != datetime_) {
changed_ = true;
}
} }
// add console commands // add console commands

View File

@@ -121,6 +121,7 @@ class Thermostat : public EMSdevice {
std::string datetime_; // date and time stamp std::string datetime_; // date and time stamp
uint8_t mqtt_format_; // single, nested or ha uint8_t mqtt_format_; // single, nested or ha
bool changed_ = false;
// Installation parameters // Installation parameters
uint8_t ibaMainDisplay_ = uint8_t ibaMainDisplay_ =

View File

@@ -46,7 +46,7 @@ std::string EMSdevice::brand_to_string() const {
break; break;
case EMSdevice::Brand::NO_BRAND: case EMSdevice::Brand::NO_BRAND:
default: default:
return read_flash_string(F("")); return read_flash_string(F("---"));
break; break;
} }

View File

@@ -292,22 +292,37 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
shell.println(); shell.println();
} }
// publish all values from each EMS device to MQTT void EMSESP::publish_device_values(uint8_t device_type) {
// plus the heartbeat and sensor if activated
void EMSESP::publish_all_values() {
if (Mqtt::connected()) { if (Mqtt::connected()) {
// Dallas sensors first
sensors_.publish_values();
// all the connected EMS devices we known about
for (const auto & emsdevice : emsdevices) { for (const auto & emsdevice : emsdevices) {
if (emsdevice) { if (emsdevice && (emsdevice->device_type() == device_type)) {
emsdevice->publish_values(); emsdevice->publish_values();
} }
} }
} }
} }
void EMSESP::publish_other_values() {
if (Mqtt::connected()) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice && (emsdevice->device_type() != EMSdevice::DeviceType::BOILER)
&& (emsdevice->device_type() != EMSdevice::DeviceType::THERMOSTAT)
&& (emsdevice->device_type() != EMSdevice::DeviceType::SOLAR)
&& (emsdevice->device_type() != EMSdevice::DeviceType::MIXING)) {
emsdevice->publish_values();
}
}
}
}
void EMSESP::publish_sensor_values(const bool force) {
if (Mqtt::connected()) {
if (sensors_.updated_values() || force) {
sensors_.publish_values();
}
}
}
// search for recognized device_ids : Me, All, otherwise print hex value // search for recognized device_ids : Me, All, otherwise print hex value
std::string EMSESP::device_tostring(const uint8_t device_id) { std::string EMSESP::device_tostring(const uint8_t device_id) {
if ((device_id & 0x7F) == rxservice_.ems_bus_id()) { if ((device_id & 0x7F) == rxservice_.ems_bus_id()) {
@@ -508,7 +523,7 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
found = emsdevice->handle_telegram(telegram); found = emsdevice->handle_telegram(telegram);
// check to see if we need to follow up after the telegram has been processed // check to see if we need to follow up after the telegram has been processed
if (found) { if (found) {
if (emsdevice->updated_values() || telegram->type_id == publish_id_) { if ((mqtt_.get_publish_onchange(emsdevice->device_type()) && emsdevice->updated_values()) || telegram->type_id == publish_id_) {
if (telegram->type_id == publish_id_) { if (telegram->type_id == publish_id_) {
publish_id_ = 0; publish_id_ = 0;
} }

View File

@@ -59,7 +59,9 @@ class EMSESP {
static void start(); static void start();
static void loop(); static void loop();
static void publish_all_values(); static void publish_device_values(uint8_t device_type);
static void publish_other_values();
static void publish_sensor_values(const bool force = false);
#ifdef EMSESP_STANDALONE #ifdef EMSESP_STANDALONE
static void run_test(uuid::console::Shell & shell, const std::string & command); // only for testing static void run_test(uuid::console::Shell & shell, const std::string & command); // only for testing

View File

@@ -27,8 +27,13 @@ AsyncMqttClient * Mqtt::mqttClient_;
// static parameters we make global // static parameters we make global
std::string Mqtt::hostname_; std::string Mqtt::hostname_;
uint8_t Mqtt::mqtt_qos_; uint8_t Mqtt::mqtt_qos_;
uint16_t Mqtt::publish_time_;
uint8_t Mqtt::bus_id_; uint8_t Mqtt::bus_id_;
uint32_t Mqtt::publish_time_boiler_;
uint32_t Mqtt::publish_time_thermostat_;
uint32_t Mqtt::publish_time_solar_;
uint32_t Mqtt::publish_time_mixing_;
uint32_t Mqtt::publish_time_other_;
uint32_t Mqtt::publish_time_sensor_;
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_; std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
std::vector<Mqtt::MQTTCmdFunction> Mqtt::mqtt_cmdfunctions_; std::vector<Mqtt::MQTTCmdFunction> Mqtt::mqtt_cmdfunctions_;
@@ -111,11 +116,30 @@ void Mqtt::loop() {
uint32_t currentMillis = uuid::get_uptime(); uint32_t currentMillis = uuid::get_uptime();
// create publish messages for each of the EMS device values, adding to queue // create publish messages for each of the EMS device values, adding to queue
if (publish_time_ && (currentMillis - last_publish_ > publish_time_)) { if (publish_time_boiler_ && (currentMillis - last_publish_boiler_ > publish_time_boiler_)) {
last_publish_ = currentMillis; last_publish_boiler_ = currentMillis;
EMSESP::publish_all_values(); EMSESP::publish_device_values(EMSdevice::DeviceType::BOILER);
}
if (publish_time_thermostat_ && (currentMillis - last_publish_thermostat_ > publish_time_thermostat_)) {
last_publish_thermostat_ = currentMillis;
EMSESP::publish_device_values(EMSdevice::DeviceType::THERMOSTAT);
}
if (publish_time_solar_ && (currentMillis - last_publish_solar_ > publish_time_solar_)) {
last_publish_solar_ = currentMillis;
EMSESP::publish_device_values(EMSdevice::DeviceType::SOLAR);
}
if (publish_time_mixing_ && (currentMillis - last_publish_mixing_ > publish_time_mixing_)) {
last_publish_mixing_ = currentMillis;
EMSESP::publish_device_values(EMSdevice::DeviceType::MIXING);
}
if (publish_time_other_ && (currentMillis - last_publish_other_ > publish_time_other_)) {
last_publish_other_ = currentMillis;
EMSESP::publish_other_values();
}
if (currentMillis - last_publish_sensor_ > publish_time_sensor_) {
last_publish_sensor_ = currentMillis;
EMSESP::publish_sensor_values(publish_time_sensor_ != 0);
} }
// publish top item from MQTT queue to stop flooding // publish top item from MQTT queue to stop flooding
if ((uint32_t)(currentMillis - last_mqtt_poll_) > MQTT_PUBLISH_WAIT) { if ((uint32_t)(currentMillis - last_mqtt_poll_) > MQTT_PUBLISH_WAIT) {
last_mqtt_poll_ = currentMillis; last_mqtt_poll_ = currentMillis;
@@ -280,7 +304,7 @@ void Mqtt::on_message(const char * topic, const char * payload, size_t len) {
} }
if (!cmd_known) { if (!cmd_known) {
LOG_ERROR(F("MQTT: no matching cmd or invalid data: %s"), command); LOG_ERROR(F("MQTT: no matching cmd or invalid data: %s"), message);
} }
return; return;
@@ -342,8 +366,13 @@ void Mqtt::start() {
// fetch MQTT settings // fetch MQTT settings
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & mqttSettings) { EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & mqttSettings) {
publish_time_ = mqttSettings.publish_time * 1000; // convert to milliseconds publish_time_boiler_ = mqttSettings.publish_time_boiler * 1000; // convert to milliseconds
mqtt_qos_ = mqttSettings.mqtt_qos; publish_time_thermostat_ = mqttSettings.publish_time_thermostat * 1000;
publish_time_solar_ = mqttSettings.publish_time_solar * 1000;
publish_time_mixing_ = mqttSettings.publish_time_mixing * 1000;
publish_time_other_ = mqttSettings.publish_time_other * 1000;
publish_time_sensor_ = mqttSettings.publish_time_sensor * 1000;
mqtt_qos_ = mqttSettings.mqtt_qos;
}); });
EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { bus_id_ = settings.ems_bus_id; }); EMSESP::emsespSettingsService.read([&](EMSESPSettings & settings) { bus_id_ = settings.ems_bus_id; });
@@ -390,8 +419,51 @@ void Mqtt::start() {
mqtt_subfunctions_.reserve(10); mqtt_subfunctions_.reserve(10);
} }
void Mqtt::set_publish_time(uint16_t publish_time) { void Mqtt::set_publish_time_boiler(uint16_t publish_time) {
publish_time_ = publish_time * 1000; // convert to milliseconds publish_time_boiler_ = publish_time * 1000; // convert to milliseconds
}
void Mqtt::set_publish_time_thermostat(uint16_t publish_time) {
publish_time_thermostat_ = publish_time * 1000; // convert to milliseconds
}
void Mqtt::set_publish_time_solar(uint16_t publish_time) {
publish_time_solar_ = publish_time * 1000; // convert to milliseconds
}
void Mqtt::set_publish_time_mixing(uint16_t publish_time) {
publish_time_mixing_ = publish_time * 1000; // convert to milliseconds
}
void Mqtt::set_publish_time_other(uint16_t publish_time) {
publish_time_other_ = publish_time * 1000; // convert to milliseconds
}
void Mqtt::set_publish_time_sensor(uint16_t publish_time) {
publish_time_sensor_ = publish_time * 1000; // convert to milliseconds
}
bool Mqtt::get_publish_onchange(uint8_t device_type) {
if (device_type == EMSdevice::DeviceType::BOILER) {
if (!publish_time_boiler_) {
return true;
}
} else if (device_type == EMSdevice::DeviceType::THERMOSTAT) {
if (!publish_time_thermostat_) {
return true;
}
} else if (device_type == EMSdevice::DeviceType::SOLAR) {
if (!publish_time_solar_) {
return true;
}
} else if (device_type == EMSdevice::DeviceType::MIXING) {
if (!publish_time_mixing_) {
return true;
}
} else if (!publish_time_other_) {
return true;
}
return false;
} }
void Mqtt::set_qos(uint8_t mqtt_qos) { void Mqtt::set_qos(uint8_t mqtt_qos) {
@@ -482,13 +554,6 @@ void Mqtt::publish(const std::string & topic) {
queue_publish_message(topic, "", false); queue_publish_message(topic, "", false);
} }
// publish all queued messages to MQTT
void Mqtt::process_all_queue() {
while (!mqtt_messages_.empty()) {
process_queue();
}
}
// take top from queue and perform the publish or subscribe action // take top from queue and perform the publish or subscribe action
// assumes there is an MQTT connection // assumes there is an MQTT connection
void Mqtt::process_queue() { void Mqtt::process_queue() {

View File

@@ -67,8 +67,14 @@ class Mqtt {
void loop(); void loop();
void start(); void start();
void set_publish_time(uint16_t publish_time); void set_publish_time_boiler(uint16_t publish_time);
void set_publish_time_thermostat(uint16_t publish_time);
void set_publish_time_solar(uint16_t publish_time);
void set_publish_time_mixing(uint16_t publish_time);
void set_publish_time_other(uint16_t publish_time);
void set_publish_time_sensor(uint16_t publish_time);
void set_qos(uint8_t mqtt_qos); void set_qos(uint8_t mqtt_qos);
bool get_publish_onchange(uint8_t device_type);
enum Operation { PUBLISH, SUBSCRIBE }; enum Operation { PUBLISH, SUBSCRIBE };
@@ -167,7 +173,6 @@ class Mqtt {
void on_publish(uint16_t packetId); void on_publish(uint16_t packetId);
void on_message(const char * topic, const char * payload, size_t len); void on_message(const char * topic, const char * payload, size_t len);
void process_queue(); void process_queue();
void process_all_queue();
static uint16_t mqtt_publish_fails_; static uint16_t mqtt_publish_fails_;
@@ -189,14 +194,25 @@ class Mqtt {
static std::vector<MQTTSubFunction> mqtt_subfunctions_; // list of mqtt subscribe callbacks for all devices static std::vector<MQTTSubFunction> mqtt_subfunctions_; // list of mqtt subscribe callbacks for all devices
static std::vector<MQTTCmdFunction> mqtt_cmdfunctions_; // list of commands static std::vector<MQTTCmdFunction> mqtt_cmdfunctions_; // list of commands
uint32_t last_mqtt_poll_ = 0; uint32_t last_mqtt_poll_ = 0;
uint32_t last_publish_ = 0; uint32_t last_publish_boiler_ = 0;
uint32_t last_publish_thermostat_ = 0;
uint32_t last_publish_solar_ = 0;
uint32_t last_publish_mixing_ = 0;
uint32_t last_publish_other_ = 0;
uint32_t last_publish_sensor_ = 0;
// settings, copied over // settings, copied over
static std::string hostname_; static std::string hostname_;
static uint8_t mqtt_qos_; static uint8_t mqtt_qos_;
static uint16_t publish_time_; static uint32_t publish_time_;
static uint8_t bus_id_; static uint8_t bus_id_;
static uint32_t publish_time_boiler_;
static uint32_t publish_time_thermostat_;
static uint32_t publish_time_solar_;
static uint32_t publish_time_mixing_;
static uint32_t publish_time_other_;
static uint32_t publish_time_sensor_;
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -124,6 +124,15 @@ void Sensors::loop() {
} else { } else {
bus_.depower(); bus_.depower();
if ((found_.size() >= devices_.size()) || (retrycnt_ > 5)) { if ((found_.size() >= devices_.size()) || (retrycnt_ > 5)) {
if (found_.size() == devices_.size()) {
for (uint8_t i = 0; i < devices_.size(); i++) {
if (found_[i].temperature_c != devices_[i].temperature_c) {
changed_ = true;
}
}
} else {
changed_ = true;
}
devices_ = std::move(found_); devices_ = std::move(found_);
retrycnt_ = 0; retrycnt_ = 0;
} else { } else {
@@ -237,6 +246,14 @@ std::string Sensors::Device::to_string() const {
return str; return str;
} }
// check to see if values have been updated
bool Sensors::updated_values() {
if (changed_) {
changed_ = false;
return true;
}
return false;
}
// send all dallas sensor values as a JSON package to MQTT // send all dallas sensor values as a JSON package to MQTT
// assumes there are devices // assumes there are devices
@@ -270,9 +287,10 @@ void Sensors::publish_values() {
char s[7]; char s[7];
if (mqtt_format_ == MQTT_format::CUSTOM) { if (mqtt_format_ == MQTT_format::CUSTOM) {
// e.g. sensors = {28-EA41-9497-0E03-5F":23.30,"28-233D-9497-0C03-8B":24.0}
doc[device.to_string()] = Helpers::render_value(s, device.temperature_c, 1); doc[device.to_string()] = Helpers::render_value(s, device.temperature_c, 1);
} else if ((mqtt_format_ == MQTT_format::NESTED) || (mqtt_format_ == MQTT_format::HA)) { } else if ((mqtt_format_ == MQTT_format::NESTED) || (mqtt_format_ == MQTT_format::HA)) {
// e.g. {"sensor1":{"id":"28-EA41-9497-0E03-5F","temp":"23.30"},"sensor2":{"id":"28-233D-9497-0C03-8B","temp":"24.0"}} // e.g. sensors = {"sensor1":{"id":"28-EA41-9497-0E03-5F","temp":"23.30"},"sensor2":{"id":"28-233D-9497-0C03-8B","temp":"24.0"}}
char sensorID[10]; // sensor{1-n} char sensorID[10]; // sensor{1-n}
strlcpy(sensorID, "sensor", 10); strlcpy(sensorID, "sensor", 10);
strlcat(sensorID, Helpers::itoa(s, i), 10); strlcat(sensorID, Helpers::itoa(s, i), 10);

View File

@@ -60,6 +60,7 @@ class Sensors {
void loop(); void loop();
void publish_values(); void publish_values();
void reload(); void reload();
bool updated_values();
const std::vector<Device> devices() const; const std::vector<Device> devices() const;
@@ -110,6 +111,7 @@ class Sensors {
uint8_t mqtt_format_; uint8_t mqtt_format_;
uint8_t retrycnt_ = 0; uint8_t retrycnt_ = 0;
uint8_t dallas_gpio_ = 0; uint8_t dallas_gpio_ = 0;
bool changed_ = false;
}; };
} // namespace emsesp } // namespace emsesp

View File

@@ -35,6 +35,7 @@ int System::reset_counter_ = 0;
bool System::upload_status_ = false; bool System::upload_status_ = false;
bool System::hide_led_ = false; bool System::hide_led_ = false;
uint8_t System::led_gpio_ = 0; uint8_t System::led_gpio_ = 0;
uint16_t System::analog_ = 0;
// send on/off to a gpio pin // send on/off to a gpio pin
// value: true = HIGH, false = LOW // value: true = HIGH, false = LOW
@@ -188,6 +189,7 @@ void System::loop() {
#endif #endif
led_monitor(); // check status and report back using the LED led_monitor(); // check status and report back using the LED
system_check(); // check system health system_check(); // check system health
measure_analog();
// send out heartbeat // send out heartbeat
uint32_t currentMillis = uuid::get_uptime(); uint32_t currentMillis = uuid::get_uptime();
@@ -233,10 +235,33 @@ void System::send_heartbeat() {
doc["mqttpublishfails"] = Mqtt::publish_fails(); doc["mqttpublishfails"] = Mqtt::publish_fails();
doc["txfails"] = EMSESP::txservice_.telegram_fail_count(); doc["txfails"] = EMSESP::txservice_.telegram_fail_count();
doc["rxfails"] = EMSESP::rxservice_.telegram_error_count(); doc["rxfails"] = EMSESP::rxservice_.telegram_error_count();
doc["adc"] = analog_; //analogRead(A0);
Mqtt::publish("heartbeat", doc, false); // send to MQTT with retain off. This will add to MQTT queue. Mqtt::publish("heartbeat", doc, false); // send to MQTT with retain off. This will add to MQTT queue.
} }
// measure and moving average adc
void System::measure_analog() {
static uint32_t measure_last_ = 0;
static uint32_t sum_ = 0;
if (!measure_last_ || (uint32_t)(uuid::get_uptime() - measure_last_) >= 1100) {
measure_last_ = uuid::get_uptime();
#if defined(ESP8266)
uint16_t a = analogRead(A0);
#elif defined(ESP32)
uint16_t a = analogRead(36);
#endif
if (!analog_) { // init first time
analog_ = a;
sum_ = a * 256;
} else { // simple moving average filter
sum_ = sum_ * 255 / 256 + a;
analog_ = sum_ / 256;
}
}
}
// sets rate of led flash // sets rate of led flash
void System::set_led_speed(uint32_t speed) { void System::set_led_speed(uint32_t speed) {
led_flash_speed_ = speed; led_flash_speed_ = speed;

View File

@@ -74,23 +74,12 @@ class System {
static constexpr uint32_t SYSTEM_HEARTBEAT_INTERVAL = 60000; // in milliseconds, how often the MQTT heartbeat is sent (1 min) static constexpr uint32_t SYSTEM_HEARTBEAT_INTERVAL = 60000; // in milliseconds, how often the MQTT heartbeat is sent (1 min)
// internal LED // internal LED
#ifndef EMSESP_NO_LED
#if defined(ESP8266)
static constexpr uint8_t LED_ON = LOW; static constexpr uint8_t LED_ON = LOW;
#elif defined(ESP32)
#ifdef WEMOS_D1_32
static constexpr uint8_t LED_ON = HIGH;
#else
static constexpr uint8_t LED_ON = LOW;
#endif
#endif
#else
static constexpr uint8_t LED_ON = 0;
#endif
void led_monitor(); void led_monitor();
void set_led_speed(uint32_t speed); void set_led_speed(uint32_t speed);
void system_check(); void system_check();
void measure_analog();
static void show_system(uuid::console::Shell & shell); static void show_system(uuid::console::Shell & shell);
static void show_users(uuid::console::Shell & shell); static void show_users(uuid::console::Shell & shell);
@@ -103,6 +92,7 @@ class System {
static int reset_counter_; static int reset_counter_;
uint32_t last_heartbeat_ = 0; uint32_t last_heartbeat_ = 0;
static bool upload_status_; // true if we're in the middle of a OTA firmware upload static bool upload_status_; // true if we're in the middle of a OTA firmware upload
static uint16_t analog_;
// settings // settings
bool system_heartbeat_; bool system_heartbeat_;

View File

@@ -83,13 +83,17 @@ class Telegram {
std::string to_string() const; std::string to_string() const;
// reads a bit value from a given telegram position // reads a bit value from a given telegram position
void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const { bool read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
uint8_t abs_index = (index - offset); uint8_t abs_index = (index - this->offset);
if (abs_index >= message_length - 1) { if (abs_index >= this->message_length) {
return; // out of bounds return false; // out of bounds
} }
uint8_t val = value;
value = (uint8_t)(((message_data[abs_index]) >> (bit)) & 0x01); value = (uint8_t)(((this->message_data[abs_index]) >> (bit)) & 0x01);
if (val != value) {
return true;
}
return false;
} }
// read a value from a telegram. We always store the value, regardless if its garbage // read a value from a telegram. We always store the value, regardless if its garbage
@@ -99,18 +103,21 @@ class Telegram {
// 2-compliment : https://www.rapidtables.com/convert/number/decimal-to-hex.html // 2-compliment : https://www.rapidtables.com/convert/number/decimal-to-hex.html
// https://en.wikipedia.org/wiki/Two%27s_complement // https://en.wikipedia.org/wiki/Two%27s_complement
// s is to override number of bytes read (e.g. use 3 to simulate a uint24_t) // s is to override number of bytes read (e.g. use 3 to simulate a uint24_t)
void read_value(Value & value, const uint8_t index, uint8_t s = 0) const { bool read_value(Value & value, const uint8_t index, uint8_t s = 0) const {
uint8_t num_bytes = (!s) ? sizeof(Value) : s; uint8_t num_bytes = (!s) ? sizeof(Value) : s;
// check for out of bounds, if so don't modify the value // check for out of bounds, if so don't modify the value
if ((index - this->offset + num_bytes - 1) >= this->message_length) { if ((index < this->offset) || ((index - this->offset + num_bytes - 1) >= this->message_length)) {
return; return false;
} }
auto val = value;
value = 0; value = 0;
for (uint8_t i = 0; i < num_bytes; i++) { for (uint8_t i = 0; i < num_bytes; i++) {
value = (value << 8) + message_data[index - this->offset + i]; // shift by byte value = (value << 8) + this->message_data[index - this->offset + i]; // shift by byte
} }
if (val != value) {
return true;
}
return false;
} }
private: private: