mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
@@ -150,15 +150,75 @@ class MqttSettingsForm extends React.Component<MqttSettingsFormProps> {
|
||||
<MenuItem value={2}>2</MenuItem>
|
||||
</SelectValidator>
|
||||
<TextValidator
|
||||
validators={['required', 'isNumber', 'minNumber:1', 'maxNumber:65535']}
|
||||
errorMessages={['Publish time is required', "Must be a number", "Must be greater than 0", "Max value is 65535"]}
|
||||
name="publish_time"
|
||||
label="MQTT Publish Time (seconds)"
|
||||
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_boiler"
|
||||
label="MQTT Boiler Publish Period (seconds, 0=on change)"
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={data.publish_time}
|
||||
value={data.publish_time_boiler}
|
||||
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"
|
||||
/>
|
||||
<FormActions>
|
||||
|
||||
@@ -27,7 +27,12 @@ export interface MqttSettings {
|
||||
keep_alive: number;
|
||||
clean_session: boolean;
|
||||
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_qos: number;
|
||||
system_heartbeat: boolean;
|
||||
|
||||
@@ -184,10 +184,15 @@ void MqttSettings::read(MqttSettings & settings, JsonObject & root) {
|
||||
root["max_topic_length"] = settings.maxTopicLength;
|
||||
|
||||
// added by proddy for EMS-ESP
|
||||
root["system_heartbeat"] = settings.system_heartbeat;
|
||||
root["publish_time"] = settings.publish_time;
|
||||
root["mqtt_format"] = settings.mqtt_format;
|
||||
root["mqtt_qos"] = settings.mqtt_qos;
|
||||
root["system_heartbeat"] = settings.system_heartbeat;
|
||||
root["publish_time_boiler"] = settings.publish_time_boiler;
|
||||
root["publish_time_thermostat"] = settings.publish_time_thermostat;
|
||||
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) {
|
||||
@@ -203,10 +208,15 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting
|
||||
newSettings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION;
|
||||
newSettings.maxTopicLength = root["max_topic_length"] | FACTORY_MQTT_MAX_TOPIC_LENGTH;
|
||||
|
||||
newSettings.system_heartbeat = root["system_heartbeat"] | EMSESP_DEFAULT_SYSTEM_HEARTBEAT;
|
||||
newSettings.publish_time = root["publish_time"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.mqtt_format = root["mqtt_format"] | EMSESP_DEFAULT_MQTT_FORMAT;
|
||||
newSettings.mqtt_qos = root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS;
|
||||
newSettings.system_heartbeat = root["system_heartbeat"] | EMSESP_DEFAULT_SYSTEM_HEARTBEAT;
|
||||
newSettings.publish_time_boiler = root["publish_time_boiler"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
newSettings.publish_time_thermostat = root["publish_time_thermostat"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (newSettings.publish_time != settings.publish_time) {
|
||||
emsesp::EMSESP::mqtt_.set_publish_time(newSettings.publish_time);
|
||||
if (newSettings.publish_time_boiler != settings.publish_time_boiler) {
|
||||
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
|
||||
|
||||
@@ -86,7 +86,12 @@ class MqttSettings {
|
||||
uint16_t maxTopicLength;
|
||||
|
||||
// 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_qos;
|
||||
bool system_heartbeat;
|
||||
|
||||
@@ -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
|
||||
bool Boiler::updated_values() {
|
||||
if (changed_) {
|
||||
changed_ = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -468,40 +472,40 @@ void Boiler::check_active() {
|
||||
|
||||
// 0x33
|
||||
void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(wWActivated_, 1); // 0xFF means on
|
||||
telegram->read_value(wWCircPump_, 6); // 0xFF means on
|
||||
telegram->read_value(wWCircPumpMode_, 7); // 1=1x3min... 6=6x3min, 7=continuous
|
||||
telegram->read_value(wWCircPumpType_, 10); // 0 = charge pump, 0xff = 3-way valve
|
||||
telegram->read_value(wWSelTemp_, 2);
|
||||
telegram->read_value(wWDisinfectTemp_, 8);
|
||||
telegram->read_value(wWComfort_, 9);
|
||||
changed_ |= telegram->read_value(wWActivated_, 1); // 0xFF means on
|
||||
changed_ |= telegram->read_value(wWCircPump_, 6); // 0xFF means on
|
||||
changed_ |= telegram->read_value(wWCircPumpMode_, 7); // 1=1x3min... 6=6x3min, 7=continuous
|
||||
changed_ |= telegram->read_value(wWCircPumpType_, 10); // 0 = charge pump, 0xff = 3-way valve
|
||||
changed_ |= telegram->read_value(wWSelTemp_, 2);
|
||||
changed_ |= telegram->read_value(wWDisinfectTemp_, 8);
|
||||
changed_ |= telegram->read_value(wWComfort_, 9);
|
||||
}
|
||||
|
||||
// 0x18
|
||||
void Boiler::process_UBAMonitorFast(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(selFlowTemp_, 0);
|
||||
telegram->read_value(curFlowTemp_, 1);
|
||||
telegram->read_value(selBurnPow_, 3); // burn power max setting
|
||||
telegram->read_value(curBurnPow_, 4);
|
||||
changed_ |= telegram->read_value(selFlowTemp_, 0);
|
||||
changed_ |= telegram->read_value(curFlowTemp_, 1);
|
||||
changed_ |= telegram->read_value(selBurnPow_, 3); // burn power max setting
|
||||
changed_ |= telegram->read_value(curBurnPow_, 4);
|
||||
|
||||
telegram->read_bitvalue(burnGas_, 7, 0);
|
||||
telegram->read_bitvalue(fanWork_, 7, 2);
|
||||
telegram->read_bitvalue(ignWork_, 7, 3);
|
||||
telegram->read_bitvalue(heatPmp_, 7, 5);
|
||||
telegram->read_bitvalue(wWHeat_, 7, 6);
|
||||
telegram->read_bitvalue(wWCirc_, 7, 7);
|
||||
changed_ |= telegram->read_bitvalue(burnGas_, 7, 0);
|
||||
changed_ |= telegram->read_bitvalue(fanWork_, 7, 2);
|
||||
changed_ |= telegram->read_bitvalue(ignWork_, 7, 3);
|
||||
changed_ |= telegram->read_bitvalue(heatPmp_, 7, 5);
|
||||
changed_ |= telegram->read_bitvalue(wWHeat_, 7, 6);
|
||||
changed_ |= telegram->read_bitvalue(wWCirc_, 7, 7);
|
||||
|
||||
// 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
|
||||
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(wwStorageTemp1_, 9); // 0x8300 if not available
|
||||
changed_ |= telegram->read_value(wwStorageTemp2_, 11); // 0x8000 if not available - this is boiler temp
|
||||
|
||||
telegram->read_value(retTemp_, 13);
|
||||
telegram->read_value(flameCurr_, 15);
|
||||
telegram->read_value(serviceCode_, 20);
|
||||
changed_ |= telegram->read_value(retTemp_, 13);
|
||||
changed_ |= telegram->read_value(flameCurr_, 15);
|
||||
changed_ |= telegram->read_value(serviceCode_, 20);
|
||||
|
||||
// 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
|
||||
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)
|
||||
*/
|
||||
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
|
||||
*/
|
||||
void Boiler::process_UBAParameters(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(heating_temp_, 1);
|
||||
telegram->read_value(burnPowermax_, 2);
|
||||
telegram->read_value(burnPowermin_, 3);
|
||||
telegram->read_value(boilTemp_off_, 4);
|
||||
telegram->read_value(boilTemp_on_, 5);
|
||||
telegram->read_value(burnPeriod_, 6);
|
||||
telegram->read_value(pumpDelay_, 8);
|
||||
telegram->read_value(pump_mod_max_, 9);
|
||||
telegram->read_value(pump_mod_min_, 10);
|
||||
changed_ |= telegram->read_value(heating_temp_, 1);
|
||||
changed_ |= telegram->read_value(burnPowermax_, 2);
|
||||
changed_ |= telegram->read_value(burnPowermin_, 3);
|
||||
changed_ |= telegram->read_value(boilTemp_off_, 4);
|
||||
changed_ |= telegram->read_value(boilTemp_on_, 5);
|
||||
changed_ |= telegram->read_value(burnPeriod_, 6);
|
||||
changed_ |= telegram->read_value(pumpDelay_, 8);
|
||||
changed_ |= telegram->read_value(pump_mod_max_, 9);
|
||||
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
|
||||
*/
|
||||
void Boiler::process_UBAMonitorWW(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(wWSetTmp_, 0);
|
||||
telegram->read_value(wWCurTmp_, 1);
|
||||
telegram->read_value(wWCurTmp2_, 3);
|
||||
telegram->read_value(wWCurFlow_, 9);
|
||||
changed_ |= telegram->read_value(wWSetTmp_, 0);
|
||||
changed_ |= telegram->read_value(wWCurTmp_, 1);
|
||||
changed_ |= telegram->read_value(wWCurTmp2_, 3);
|
||||
changed_ |= telegram->read_value(wWCurFlow_, 9);
|
||||
|
||||
telegram->read_value(wWWorkM_, 10, 3); // force to 3 bytes
|
||||
telegram->read_value(wWStarts_, 13, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(wWWorkM_, 10, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(wWStarts_, 13, 3); // force to 3 bytes
|
||||
|
||||
telegram->read_bitvalue(wWOneTime_, 5, 1);
|
||||
telegram->read_bitvalue(wWDisinfecting_, 5, 2);
|
||||
telegram->read_bitvalue(wWReadiness_, 5, 3);
|
||||
telegram->read_bitvalue(wWRecharging_, 5, 4);
|
||||
telegram->read_bitvalue(wWTemperatureOK_, 5, 5);
|
||||
changed_ |= telegram->read_bitvalue(wWOneTime_, 5, 1);
|
||||
changed_ |= telegram->read_bitvalue(wWDisinfecting_, 5, 2);
|
||||
changed_ |= telegram->read_bitvalue(wWReadiness_, 5, 3);
|
||||
changed_ |= telegram->read_bitvalue(wWRecharging_, 5, 4);
|
||||
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
|
||||
*/
|
||||
void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(selFlowTemp_, 6);
|
||||
telegram->read_bitvalue(burnGas_, 11, 0);
|
||||
telegram->read_bitvalue(wWHeat_, 11, 2);
|
||||
telegram->read_value(curBurnPow_, 10);
|
||||
telegram->read_value(selBurnPow_, 9);
|
||||
telegram->read_value(curFlowTemp_, 7);
|
||||
telegram->read_value(flameCurr_, 19);
|
||||
changed_ |= telegram->read_value(selFlowTemp_, 6);
|
||||
changed_ |= telegram->read_bitvalue(burnGas_, 11, 0);
|
||||
changed_ |= telegram->read_bitvalue(wWHeat_, 11, 2);
|
||||
changed_ |= telegram->read_value(curBurnPow_, 10);
|
||||
changed_ |= telegram->read_value(selBurnPow_, 9);
|
||||
changed_ |= telegram->read_value(curFlowTemp_, 7);
|
||||
changed_ |= telegram->read_value(flameCurr_, 19);
|
||||
|
||||
// read the service code / installation status as appears on the display
|
||||
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
|
||||
*/
|
||||
void Boiler::process_UBAMonitorSlow(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(extTemp_, 0);
|
||||
telegram->read_value(boilTemp_, 2);
|
||||
telegram->read_value(exhaustTemp_, 4);
|
||||
telegram->read_value(switchTemp_, 25); // only if there is a mixing module present
|
||||
telegram->read_value(pumpMod_, 9);
|
||||
telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes
|
||||
telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes
|
||||
telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(extTemp_, 0);
|
||||
changed_ |= telegram->read_value(boilTemp_, 2);
|
||||
changed_ |= telegram->read_value(exhaustTemp_, 4);
|
||||
changed_ |= telegram->read_value(switchTemp_, 25); // only if there is a mixing module present
|
||||
changed_ |= telegram->read_value(pumpMod_, 9);
|
||||
changed_ |= telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAMonitorSlowPlus2 - type 0xE3
|
||||
*/
|
||||
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+
|
||||
*/
|
||||
void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_bitvalue(fanWork_, 2, 2);
|
||||
telegram->read_bitvalue(ignWork_, 2, 3);
|
||||
telegram->read_bitvalue(heatPmp_, 2, 5);
|
||||
telegram->read_bitvalue(wWCirc_, 2, 7);
|
||||
telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes
|
||||
telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes
|
||||
telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes
|
||||
telegram->read_value(pumpMod_, 25);
|
||||
changed_ |= telegram->read_bitvalue(fanWork_, 2, 2);
|
||||
changed_ |= telegram->read_bitvalue(ignWork_, 2, 3);
|
||||
changed_ |= telegram->read_bitvalue(heatPmp_, 2, 5);
|
||||
changed_ |= telegram->read_bitvalue(wWCirc_, 2, 7);
|
||||
changed_ |= telegram->read_value(burnStarts_, 10, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(burnWorkMin_, 13, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(heatWorkMin_, 19, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(pumpMod_, 25);
|
||||
}
|
||||
|
||||
// 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
|
||||
void Boiler::process_UBADHWStatus(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(wWSetTmp_, 0);
|
||||
telegram->read_value(wWCurTmp_, 1);
|
||||
telegram->read_value(wWCurTmp2_, 3);
|
||||
changed_ |= telegram->read_value(wWSetTmp_, 0);
|
||||
changed_ |= telegram->read_value(wWCurTmp_, 1);
|
||||
changed_ |= telegram->read_value(wWCurTmp2_, 3);
|
||||
|
||||
telegram->read_value(wWWorkM_, 17, 3); // force to 3 bytes
|
||||
telegram->read_value(wWStarts_, 14, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(wWWorkM_, 17, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_value(wWStarts_, 14, 3); // force to 3 bytes
|
||||
|
||||
telegram->read_bitvalue(wWOneTime_, 12, 2);
|
||||
telegram->read_bitvalue(wWDisinfecting_, 12, 3);
|
||||
telegram->read_bitvalue(wWReadiness_, 12, 4);
|
||||
telegram->read_bitvalue(wWRecharging_, 13, 4);
|
||||
telegram->read_bitvalue(wWTemperatureOK_, 13, 5);
|
||||
telegram->read_bitvalue(wWCircPump_, 13, 2);
|
||||
changed_ |= telegram->read_bitvalue(wWOneTime_, 12, 2);
|
||||
changed_ |= telegram->read_bitvalue(wWDisinfecting_, 12, 3);
|
||||
changed_ |= telegram->read_bitvalue(wWReadiness_, 12, 4);
|
||||
changed_ |= telegram->read_bitvalue(wWRecharging_, 13, 4);
|
||||
changed_ |= telegram->read_bitvalue(wWTemperatureOK_, 13, 5);
|
||||
changed_ |= telegram->read_bitvalue(wWCircPump_, 13, 2);
|
||||
|
||||
telegram->read_value(wWActivated_, 20);
|
||||
telegram->read_value(wWSelTemp_, 10);
|
||||
telegram->read_value(wWDisinfectTemp_, 9);
|
||||
changed_ |= telegram->read_value(wWActivated_, 20);
|
||||
changed_ |= telegram->read_value(wWSelTemp_, 10);
|
||||
changed_ |= telegram->read_value(wWDisinfectTemp_, 9);
|
||||
}
|
||||
|
||||
// 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
|
||||
// see https://github.com/proddy/EMS-ESP/issues/397
|
||||
void Boiler::process_MC10Status(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(wwMixTemperature_, 14);
|
||||
telegram->read_value(wwBufferBoilerTemperature_, 18);
|
||||
changed_ |= telegram->read_value(wwMixTemperature_, 14);
|
||||
changed_ |= telegram->read_value(wwBufferBoilerTemperature_, 18);
|
||||
}
|
||||
|
||||
/*
|
||||
* UBAOutdoorTemp - type 0xD1 - external temperature EMS+
|
||||
*/
|
||||
void Boiler::process_UBAOutdoorTemp(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(extTemp_, 0);
|
||||
changed_ |= telegram->read_value(extTemp_, 0);
|
||||
}
|
||||
|
||||
// UBASetPoint 0x1A
|
||||
void Boiler::process_UBASetPoints(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(setFlowTemp_, 0); // boiler set temp from thermostat
|
||||
telegram->read_value(setBurnPow_, 1); // max output power in %
|
||||
telegram->read_value(setWWPumpPow_, 2); // ww pump speed/power?
|
||||
changed_ |= telegram->read_value(setFlowTemp_, 0); // boiler set temp from thermostat
|
||||
changed_ |= telegram->read_value(setBurnPow_, 1); // max output power in %
|
||||
changed_ |= telegram->read_value(setWWPumpPow_, 2); // ww pump speed/power?
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
|
||||
@@ -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 mqtt_format_; // single, nested or ha
|
||||
bool changed_ = false;;
|
||||
|
||||
static constexpr uint8_t EMS_TYPE_UBAParameterWW = 0x33;
|
||||
static constexpr uint8_t EMS_TYPE_UBAFunctionTest = 0x1D;
|
||||
|
||||
@@ -82,6 +82,10 @@ void Mixing::device_info(JsonArray & root) {
|
||||
|
||||
// check to see if values have been updated
|
||||
bool Mixing::updated_values() {
|
||||
if (changed_) {
|
||||
changed_ = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -165,10 +169,10 @@ void Mixing::publish_values() {
|
||||
void Mixing::process_MMPLUSStatusMessage_HC(std::shared_ptr<const Telegram> telegram) {
|
||||
type_ = Type::HC;
|
||||
hc_ = telegram->type_id - 0x02D7 + 1; // determine which circuit this is
|
||||
telegram->read_value(flowTemp_, 3); // is * 10
|
||||
telegram->read_value(flowSetTemp_, 5);
|
||||
telegram->read_value(pumpMod_, 2);
|
||||
telegram->read_value(status_, 1); // valve status
|
||||
changed_ |= telegram->read_value(flowTemp_, 3); // is * 10
|
||||
changed_ |= telegram->read_value(flowSetTemp_, 5);
|
||||
changed_ |= telegram->read_value(pumpMod_, 2);
|
||||
changed_ |= telegram->read_value(status_, 1); // valve status
|
||||
}
|
||||
|
||||
// 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) {
|
||||
type_ = Type::WWC;
|
||||
hc_ = telegram->type_id - 0x0331 + 1; // determine which circuit this is. There are max 2.
|
||||
telegram->read_value(flowTemp_, 0); // is * 10
|
||||
telegram->read_value(pumpMod_, 2);
|
||||
telegram->read_value(status_, 11); // temp status
|
||||
changed_ |= telegram->read_value(flowTemp_, 0); // is * 10
|
||||
changed_ |= telegram->read_value(pumpMod_, 2);
|
||||
changed_ |= telegram->read_value(status_, 11); // temp status
|
||||
}
|
||||
|
||||
// Mixing IMP - 0x010C
|
||||
@@ -189,17 +193,17 @@ void Mixing::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram)
|
||||
type_ = Type::HC;
|
||||
hc_ = get_device_id() - 0x20 + 1;
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
if (ismixed == 2) { // we have a mixed circuit
|
||||
telegram->read_value(flowTemp_, 3); // is * 10
|
||||
telegram->read_value(flowSetTemp_, 5);
|
||||
telegram->read_value(status_, 2); // valve status
|
||||
changed_ |= telegram->read_value(flowTemp_, 3); // is * 10
|
||||
changed_ |= telegram->read_value(flowSetTemp_, 5);
|
||||
changed_ |= telegram->read_value(status_, 2); // valve status
|
||||
}
|
||||
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) {
|
||||
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
|
||||
// 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;
|
||||
telegram->read_value(flowTemp_, 1); // is * 10
|
||||
telegram->read_value(pumpMod_, 3);
|
||||
telegram->read_value(flowSetTemp_, 0);
|
||||
changed_ |= telegram->read_value(flowTemp_, 1); // is * 10
|
||||
changed_ |= telegram->read_value(pumpMod_, 3);
|
||||
changed_ |= telegram->read_value(flowSetTemp_, 0);
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
|
||||
@@ -66,6 +66,7 @@ class Mixing : public EMSdevice {
|
||||
uint8_t status_ = EMS_VALUE_UINT_NOTSET;
|
||||
uint8_t flowSetTemp_ = EMS_VALUE_UINT_NOTSET;
|
||||
Type type_ = Type::NONE;
|
||||
bool changed_ = false;
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -168,11 +168,18 @@ void Solar::publish_values() {
|
||||
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
|
||||
bool Solar::updated_values() {
|
||||
if (changed_) {
|
||||
changed_ = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -182,11 +189,11 @@ void Solar::console_commands() {
|
||||
|
||||
// SM10Monitor - type 0x97
|
||||
void Solar::process_SM10Monitor(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(collectorTemp_, 2); // collector temp from SM10, is *10
|
||||
telegram->read_value(tankBottomTemp_, 5); // bottom temp from SM10, is *10
|
||||
telegram->read_value(solarPumpModulation_, 4); // modulation solar pump
|
||||
telegram->read_bitvalue(solarPump_, 7, 1);
|
||||
telegram->read_value(pumpWorkMin_, 8);
|
||||
changed_ |= telegram->read_value(collectorTemp_, 2); // collector temp from SM10, is *10
|
||||
changed_ |= telegram->read_value(tankBottomTemp_, 5); // bottom temp from SM10, is *10
|
||||
changed_ |= telegram->read_value(solarPumpModulation_, 4); // modulation solar pump
|
||||
changed_ |= telegram->read_bitvalue(solarPump_, 7, 1);
|
||||
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
|
||||
*/
|
||||
void Solar::process_SM100Monitor(std::shared_ptr<const Telegram> telegram) {
|
||||
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
|
||||
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(collectorTemp_, 0); // is *10 - TS1: Temperature sensor for collector array 1
|
||||
changed_ |= telegram->read_value(tankBottomTemp_, 2); // is *10 - TS2: Temperature sensor 1 cylinder, bottom
|
||||
changed_ |= telegram->read_value(tankBottomTemp2_, 16); // is *10 - TS5: Temperature sensor 2 cylinder, bottom, or swimming pool
|
||||
changed_ |= telegram->read_value(heatExchangerTemp_, 20); // is *10 - TS6: Heat exchanger temperature sensor
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
@@ -221,9 +228,9 @@ void Solar::process_SM100Monitor2(std::shared_ptr<const Telegram> telegram) {
|
||||
// SM100Config - 0x0366
|
||||
// e.g. B0 00 FF 00 02 66 01 62 00 13 40 14
|
||||
void Solar::process_SM100Config(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(availabilityFlag_, 0);
|
||||
telegram->read_value(configFlag_, 1);
|
||||
telegram->read_value(userFlag_, 2);
|
||||
changed_ |= telegram->read_value(availabilityFlag_, 0);
|
||||
changed_ |= telegram->read_value(configFlag_, 1);
|
||||
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) {
|
||||
uint8_t solarpumpmod = solarPumpModulation_;
|
||||
uint8_t cylinderpumpmod = cylinderPumpModulation_;
|
||||
telegram->read_value(cylinderPumpModulation_, 8);
|
||||
telegram->read_value(solarPumpModulation_, 9);
|
||||
changed_ |= telegram->read_value(cylinderPumpModulation_, 8);
|
||||
changed_ |= telegram->read_value(solarPumpModulation_, 9);
|
||||
|
||||
if (solarpumpmod == 0 && solarPumpModulation_ == 100) { // mask out boosts
|
||||
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
|
||||
cylinderPumpModulation_ = 15; // set to minimum
|
||||
}
|
||||
telegram->read_bitvalue(tankHeated_, 3, 1); // issue #422
|
||||
telegram->read_bitvalue(collectorShutdown_, 3, 0); // collector shutdown
|
||||
changed_ |= telegram->read_bitvalue(tankHeated_, 3, 1); // issue #422
|
||||
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)
|
||||
*/
|
||||
void Solar::process_SM100Status2(std::shared_ptr<const Telegram> telegram) {
|
||||
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(valveStatus_, 4, 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
|
||||
*/
|
||||
void Solar::process_SM100Energy(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(energyLastHour_, 0); // last hour / 10 in Wh
|
||||
telegram->read_value(energyToday_, 4); // todays in Wh
|
||||
telegram->read_value(energyTotal_, 8); // total / 10 in kWh
|
||||
changed_ |= telegram->read_value(energyLastHour_, 0); // last hour / 10 in Wh
|
||||
changed_ |= telegram->read_value(energyToday_, 4); // todays in Wh
|
||||
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
|
||||
*/
|
||||
void Solar::process_ISM1StatusMessage(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(collectorTemp_, 4); // Collector Temperature
|
||||
telegram->read_value(tankBottomTemp_, 6); // Temperature Bottom of Solar Boiler
|
||||
changed_ |= telegram->read_value(collectorTemp_, 4); // Collector Temperature
|
||||
changed_ |= telegram->read_value(tankBottomTemp_, 6); // Temperature Bottom of Solar Boiler
|
||||
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) {
|
||||
energyLastHour_ = Wh * 10; // set to *10
|
||||
}
|
||||
|
||||
telegram->read_bitvalue(solarPump_, 8, 0); // PS1 Solar pump on (1) or off (0)
|
||||
telegram->read_value(pumpWorkMin_, 10, 3); // force to 3 bytes
|
||||
telegram->read_bitvalue(collectorShutdown_, 9, 0); // collector shutdown on/off
|
||||
telegram->read_bitvalue(tankHeated_, 9, 2); // tank full
|
||||
changed_ |= telegram->read_bitvalue(solarPump_, 8, 0); // PS1 Solar pump on (1) or off (0)
|
||||
changed_ |= telegram->read_value(pumpWorkMin_, 10, 3); // force to 3 bytes
|
||||
changed_ |= telegram->read_bitvalue(collectorShutdown_, 9, 0); // collector shutdown on/off
|
||||
changed_ |= telegram->read_bitvalue(tankHeated_, 9, 2); // tank full
|
||||
}
|
||||
|
||||
/*
|
||||
* Junkers ISM1 Solar Module - type 0x0101 EMS+ for setting values
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -65,6 +65,7 @@ class Solar : public EMSdevice {
|
||||
uint8_t availabilityFlag_ = EMS_VALUE_BOOL_NOTSET;
|
||||
uint8_t configFlag_ = 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_SM100Monitor(std::shared_ptr<const Telegram> telegram);
|
||||
|
||||
@@ -242,23 +242,10 @@ bool Thermostat::updated_values() {
|
||||
if (EMSESP::actual_master_thermostat() != this->get_device_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// quick hack to see if it changed. We simply just add up all the raw values
|
||||
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;
|
||||
if (changed_) {
|
||||
changed_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -902,16 +889,16 @@ void Thermostat::show_values(uuid::console::Shell & shell) {
|
||||
void Thermostat::process_RC20Set(std::shared_ptr<const Telegram> 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)
|
||||
void Thermostat::process_RC20Monitor_2(std::shared_ptr<const Telegram> 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
|
||||
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_bitvalue(hc->mode_type, 0, 7); // day/night MSB 7th bit is day
|
||||
changed_ |= telegram->read_value(hc->setpoint_roomTemp, 2, 1); // is * 2, force as single byte
|
||||
changed_ |= telegram->read_value(hc->curr_roomTemp, 3); // is * 10
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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, ..)
|
||||
void Thermostat::process_RC20Remote(std::shared_ptr<const Telegram> 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)
|
||||
void Thermostat::process_RC10Monitor(std::shared_ptr<const Telegram> telegram) {
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||
|
||||
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->setpoint_roomTemp, 1, 1); // is * 2, force as single byte
|
||||
changed_ |= telegram->read_value(hc->curr_roomTemp, 2); // is * 10
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
@@ -948,56 +935,56 @@ void Thermostat::process_RC10Set(std::shared_ptr<const Telegram> telegram) {
|
||||
// type 0x0165, ff
|
||||
void Thermostat::process_JunkersSet(std::shared_ptr<const Telegram> telegram) {
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||
telegram->read_value(hc->daytemp, 17); // is * 2
|
||||
telegram->read_value(hc->nighttemp, 16); // is * 2
|
||||
telegram->read_value(hc->nofrosttemp, 15); // is * 2
|
||||
changed_ |= telegram->read_value(hc->daytemp, 17); // is * 2
|
||||
changed_ |= telegram->read_value(hc->nighttemp, 16); // is * 2
|
||||
changed_ |= telegram->read_value(hc->nofrosttemp, 15); // is * 2
|
||||
}
|
||||
// type 0x0179, ff
|
||||
void Thermostat::process_JunkersSet2(std::shared_ptr<const Telegram> telegram) {
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||
telegram->read_value(hc->daytemp, 7); // is * 2
|
||||
telegram->read_value(hc->nighttemp, 6); // is * 2
|
||||
telegram->read_value(hc->nofrosttemp, 5); // is * 2
|
||||
changed_ |= telegram->read_value(hc->daytemp, 7); // is * 2
|
||||
changed_ |= telegram->read_value(hc->nighttemp, 6); // 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)
|
||||
void Thermostat::process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram) {
|
||||
telegram->read_value(dampedoutdoortemp_, 0);
|
||||
telegram->read_value(tempsensor1_, 3); // sensor 1 - is * 10
|
||||
telegram->read_value(tempsensor2_, 5); // sensor 2 - is * 10
|
||||
changed_ |= telegram->read_value(dampedoutdoortemp_, 0);
|
||||
changed_ |= telegram->read_value(tempsensor1_, 3); // sensor 1 - is * 10
|
||||
changed_ |= telegram->read_value(tempsensor2_, 5); // sensor 2 - is * 10
|
||||
}
|
||||
|
||||
// 0x91 - data from the RC20 thermostat (0x17) - 15 bytes long
|
||||
void Thermostat::process_RC20Monitor(std::shared_ptr<const Telegram> telegram) {
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||
|
||||
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->setpoint_roomTemp, 1, 1); // is * 2, force as single byte
|
||||
changed_ |= telegram->read_value(hc->curr_roomTemp, 2); // is * 10
|
||||
}
|
||||
|
||||
// type 0x0A - data from the Nefit Easy/TC100 thermostat (0x18) - 31 bytes long
|
||||
void Thermostat::process_EasyMonitor(std::shared_ptr<const Telegram> telegram) {
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||
|
||||
telegram->read_value(hc->curr_roomTemp, 8); // is * 100
|
||||
telegram->read_value(hc->setpoint_roomTemp, 10); // is * 100
|
||||
changed_ |= telegram->read_value(hc->curr_roomTemp, 8); // is * 100
|
||||
changed_ |= telegram->read_value(hc->setpoint_roomTemp, 10); // is * 100
|
||||
}
|
||||
|
||||
// Settings Parameters - 0xA5 - RC30_1
|
||||
void Thermostat::process_IBASettings(std::shared_ptr<const Telegram> telegram) {
|
||||
// 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
|
||||
telegram->read_value(ibaLanguage_, 1); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian
|
||||
telegram->read_value(ibaCalIntTemperature_, 2); // offset int. temperature sensor, by * 0.1 Kelvin
|
||||
telegram->read_value(ibaBuildingType_, 6); // building type: 0 = light, 1 = medium, 2 = heavy
|
||||
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(ibaLanguage_, 1); // language on Thermostat: 0 german, 1 dutch, 2 french, 3 italian
|
||||
changed_ |= telegram->read_value(ibaCalIntTemperature_, 2); // offset int. temperature sensor, by * 0.1 Kelvin
|
||||
changed_ |= telegram->read_value(ibaBuildingType_, 6); // building type: 0 = light, 1 = medium, 2 = heavy
|
||||
changed_ |= telegram->read_value(ibaMinExtTemperature_, 5); // min ext temp for heating curve, in deg., 0xF6=-10, 0x0 = 0, 0xFF=-1
|
||||
changed_ |= telegram->read_value(ibaClockOffset_, 12); // offset (in sec) to clock, 0xff = -1 s, 0x02 = 2 s
|
||||
}
|
||||
|
||||
// Settings WW 0x37 - RC35
|
||||
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
|
||||
@@ -1009,21 +996,21 @@ void Thermostat::process_JunkersMonitor(std::shared_ptr<const Telegram> telegram
|
||||
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||
|
||||
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->curr_roomTemp, 4); // 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
|
||||
telegram->read_value(hc->mode, 1); // 1 = manual, 2 = auto
|
||||
changed_ |= telegram->read_value(hc->mode_type, 0); // 1 = nofrost, 2 = eco, 3 = heat
|
||||
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
|
||||
void Thermostat::process_RC300Monitor(std::shared_ptr<const Telegram> 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);
|
||||
telegram->read_bitvalue(hc->mode, 10, 0); // bit 1, mode (auto=1 or manual=0)
|
||||
changed_ |= telegram->read_bitvalue(hc->mode_type, 10, 1);
|
||||
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 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 6 actual setpoint according to programmed changes eco/comfort
|
||||
// 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
|
||||
telegram->read_bitvalue(hc->summer_mode, 2, 4);
|
||||
telegram->read_value(hc->targetflowtemp, 4);
|
||||
changed_ |= telegram->read_value(hc->setpoint_roomTemp, 3, 1); // is * 2, force as single byte
|
||||
changed_ |= telegram->read_bitvalue(hc->summer_mode, 2, 4);
|
||||
changed_ |= telegram->read_value(hc->targetflowtemp, 4);
|
||||
}
|
||||
|
||||
// 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
|
||||
// I think auto is position 8?
|
||||
// actual setpoint taken from RC300Monitor (Michael 12.06.2020)
|
||||
// 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, 8, 1); // single byte conversion, value is * 2 - auto?
|
||||
// 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!
|
||||
// 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
|
||||
telegram->read_value(hc->nighttemp, 4); // is * 2
|
||||
changed_ |= telegram->read_value(hc->daytemp, 2); // is * 2
|
||||
changed_ |= telegram->read_value(hc->nighttemp, 4); // is * 2
|
||||
}
|
||||
|
||||
// types 0x31D and 0x31E
|
||||
void Thermostat::process_RC300WWmode(std::shared_ptr<const Telegram> telegram) {
|
||||
// 0x31D for WW system 1, 0x31E for WW system 2
|
||||
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 2 = current status of DHW setpoint
|
||||
// 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) {
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||
|
||||
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->setpoint_roomTemp, 1, 1); // is * 2, force as single byte
|
||||
changed_ |= telegram->read_value(hc->curr_roomTemp, 2);
|
||||
}
|
||||
|
||||
// type 0xA7 - for reading the mode from the RC30 thermostat (0x10)
|
||||
void Thermostat::process_RC30Set(std::shared_ptr<const Telegram> 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
|
||||
@@ -1092,14 +1079,14 @@ void Thermostat::process_RC35Monitor(std::shared_ptr<const Telegram> 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
|
||||
telegram->read_value(hc->curr_roomTemp, 3); // is * 10 - or 0x7D00 if thermostat is mounted on boiler
|
||||
changed_ |= telegram->read_value(hc->setpoint_roomTemp, 2, 1); // is * 2, force to single byte, is 0 in summermode
|
||||
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);
|
||||
telegram->read_bitvalue(hc->summer_mode, 1, 0);
|
||||
telegram->read_bitvalue(hc->holiday_mode, 0, 5);
|
||||
changed_ |= telegram->read_bitvalue(hc->mode_type, 1, 1);
|
||||
changed_ |= telegram->read_bitvalue(hc->summer_mode, 1, 0);
|
||||
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)
|
||||
@@ -1111,16 +1098,16 @@ void Thermostat::process_RC35Set(std::shared_ptr<const Telegram> telegram) {
|
||||
|
||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(telegram);
|
||||
|
||||
telegram->read_value(hc->mode, 7); // night, day, auto
|
||||
telegram->read_value(hc->daytemp, 2); // is * 2
|
||||
telegram->read_value(hc->nighttemp, 1); // is * 2
|
||||
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->mode, 7); // night, day, auto
|
||||
changed_ |= telegram->read_value(hc->daytemp, 2); // is * 2
|
||||
changed_ |= telegram->read_value(hc->nighttemp, 1); // is * 2
|
||||
changed_ |= telegram->read_value(hc->holidaytemp, 3); // is * 2
|
||||
changed_ |= telegram->read_value(hc->heatingtype, 0); // 0- off, 1-radiator, 2-convector, 3-floor
|
||||
|
||||
telegram->read_value(hc->summertemp, 22); // is * 1
|
||||
telegram->read_value(hc->nofrosttemp, 23); // is * 1
|
||||
telegram->read_value(hc->designtemp, 17); // is * 1
|
||||
telegram->read_value(hc->offsettemp, 6); // is * 2
|
||||
changed_ |= telegram->read_value(hc->summertemp, 22); // is * 1
|
||||
changed_ |= telegram->read_value(hc->nofrosttemp, 23); // is * 1
|
||||
changed_ |= telegram->read_value(hc->designtemp, 17); // is * 1
|
||||
changed_ |= telegram->read_value(hc->offsettemp, 6); // is * 2
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
datetime_.resize(25, '\0');
|
||||
}
|
||||
auto timeold = datetime_;
|
||||
// render time to HH:MM:SS DD/MM/YYYY
|
||||
// had to create separate buffers because of how printf works
|
||||
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::itoa(buf6, telegram->message_data[0] + 2000, 10) // year
|
||||
);
|
||||
if (timeold != datetime_) {
|
||||
changed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// add console commands
|
||||
|
||||
@@ -121,6 +121,7 @@ class Thermostat : public EMSdevice {
|
||||
std::string datetime_; // date and time stamp
|
||||
|
||||
uint8_t mqtt_format_; // single, nested or ha
|
||||
bool changed_ = false;
|
||||
|
||||
// Installation parameters
|
||||
uint8_t ibaMainDisplay_ =
|
||||
|
||||
@@ -46,7 +46,7 @@ std::string EMSdevice::brand_to_string() const {
|
||||
break;
|
||||
case EMSdevice::Brand::NO_BRAND:
|
||||
default:
|
||||
return read_flash_string(F(""));
|
||||
return read_flash_string(F("---"));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -292,22 +292,37 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
|
||||
shell.println();
|
||||
}
|
||||
|
||||
// publish all values from each EMS device to MQTT
|
||||
// plus the heartbeat and sensor if activated
|
||||
void EMSESP::publish_all_values() {
|
||||
void EMSESP::publish_device_values(uint8_t device_type) {
|
||||
if (Mqtt::connected()) {
|
||||
// Dallas sensors first
|
||||
sensors_.publish_values();
|
||||
|
||||
// all the connected EMS devices we known about
|
||||
for (const auto & emsdevice : emsdevices) {
|
||||
if (emsdevice) {
|
||||
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
||||
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
|
||||
std::string EMSESP::device_tostring(const uint8_t device_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);
|
||||
// check to see if we need to follow up after the telegram has been processed
|
||||
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_) {
|
||||
publish_id_ = 0;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,9 @@ class EMSESP {
|
||||
static void start();
|
||||
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
|
||||
static void run_test(uuid::console::Shell & shell, const std::string & command); // only for testing
|
||||
|
||||
99
src/mqtt.cpp
99
src/mqtt.cpp
@@ -27,8 +27,13 @@ AsyncMqttClient * Mqtt::mqttClient_;
|
||||
// static parameters we make global
|
||||
std::string Mqtt::hostname_;
|
||||
uint8_t Mqtt::mqtt_qos_;
|
||||
uint16_t Mqtt::publish_time_;
|
||||
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::MQTTCmdFunction> Mqtt::mqtt_cmdfunctions_;
|
||||
@@ -111,11 +116,30 @@ void Mqtt::loop() {
|
||||
uint32_t currentMillis = uuid::get_uptime();
|
||||
|
||||
// create publish messages for each of the EMS device values, adding to queue
|
||||
if (publish_time_ && (currentMillis - last_publish_ > publish_time_)) {
|
||||
last_publish_ = currentMillis;
|
||||
EMSESP::publish_all_values();
|
||||
if (publish_time_boiler_ && (currentMillis - last_publish_boiler_ > publish_time_boiler_)) {
|
||||
last_publish_boiler_ = currentMillis;
|
||||
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
|
||||
if ((uint32_t)(currentMillis - last_mqtt_poll_) > MQTT_PUBLISH_WAIT) {
|
||||
last_mqtt_poll_ = currentMillis;
|
||||
@@ -280,7 +304,7 @@ void Mqtt::on_message(const char * topic, const char * payload, size_t len) {
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -342,8 +366,13 @@ void Mqtt::start() {
|
||||
|
||||
// fetch MQTT settings
|
||||
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & mqttSettings) {
|
||||
publish_time_ = mqttSettings.publish_time * 1000; // convert to milliseconds
|
||||
mqtt_qos_ = mqttSettings.mqtt_qos;
|
||||
publish_time_boiler_ = mqttSettings.publish_time_boiler * 1000; // convert to milliseconds
|
||||
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; });
|
||||
@@ -390,8 +419,51 @@ void Mqtt::start() {
|
||||
mqtt_subfunctions_.reserve(10);
|
||||
}
|
||||
|
||||
void Mqtt::set_publish_time(uint16_t publish_time) {
|
||||
publish_time_ = publish_time * 1000; // convert to milliseconds
|
||||
void Mqtt::set_publish_time_boiler(uint16_t publish_time) {
|
||||
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) {
|
||||
@@ -482,13 +554,6 @@ void Mqtt::publish(const std::string & topic) {
|
||||
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
|
||||
// assumes there is an MQTT connection
|
||||
void Mqtt::process_queue() {
|
||||
|
||||
26
src/mqtt.h
26
src/mqtt.h
@@ -67,8 +67,14 @@ class Mqtt {
|
||||
void loop();
|
||||
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);
|
||||
bool get_publish_onchange(uint8_t device_type);
|
||||
|
||||
enum Operation { PUBLISH, SUBSCRIBE };
|
||||
|
||||
@@ -167,7 +173,6 @@ class Mqtt {
|
||||
void on_publish(uint16_t packetId);
|
||||
void on_message(const char * topic, const char * payload, size_t len);
|
||||
void process_queue();
|
||||
void process_all_queue();
|
||||
|
||||
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<MQTTCmdFunction> mqtt_cmdfunctions_; // list of commands
|
||||
|
||||
uint32_t last_mqtt_poll_ = 0;
|
||||
uint32_t last_publish_ = 0;
|
||||
uint32_t last_mqtt_poll_ = 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
|
||||
static std::string hostname_;
|
||||
static uint8_t mqtt_qos_;
|
||||
static uint16_t publish_time_;
|
||||
static uint32_t publish_time_;
|
||||
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
|
||||
|
||||
@@ -124,6 +124,15 @@ void Sensors::loop() {
|
||||
} else {
|
||||
bus_.depower();
|
||||
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_);
|
||||
retrycnt_ = 0;
|
||||
} else {
|
||||
@@ -237,6 +246,14 @@ std::string Sensors::Device::to_string() const {
|
||||
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
|
||||
// assumes there are devices
|
||||
@@ -270,9 +287,10 @@ void Sensors::publish_values() {
|
||||
char s[7];
|
||||
|
||||
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);
|
||||
} 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}
|
||||
strlcpy(sensorID, "sensor", 10);
|
||||
strlcat(sensorID, Helpers::itoa(s, i), 10);
|
||||
|
||||
@@ -60,6 +60,7 @@ class Sensors {
|
||||
void loop();
|
||||
void publish_values();
|
||||
void reload();
|
||||
bool updated_values();
|
||||
|
||||
const std::vector<Device> devices() const;
|
||||
|
||||
@@ -110,6 +111,7 @@ class Sensors {
|
||||
uint8_t mqtt_format_;
|
||||
uint8_t retrycnt_ = 0;
|
||||
uint8_t dallas_gpio_ = 0;
|
||||
bool changed_ = false;
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
@@ -35,6 +35,7 @@ int System::reset_counter_ = 0;
|
||||
bool System::upload_status_ = false;
|
||||
bool System::hide_led_ = false;
|
||||
uint8_t System::led_gpio_ = 0;
|
||||
uint16_t System::analog_ = 0;
|
||||
|
||||
// send on/off to a gpio pin
|
||||
// value: true = HIGH, false = LOW
|
||||
@@ -188,6 +189,7 @@ void System::loop() {
|
||||
#endif
|
||||
led_monitor(); // check status and report back using the LED
|
||||
system_check(); // check system health
|
||||
measure_analog();
|
||||
|
||||
// send out heartbeat
|
||||
uint32_t currentMillis = uuid::get_uptime();
|
||||
@@ -233,10 +235,33 @@ void System::send_heartbeat() {
|
||||
doc["mqttpublishfails"] = Mqtt::publish_fails();
|
||||
doc["txfails"] = EMSESP::txservice_.telegram_fail_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.
|
||||
}
|
||||
|
||||
// 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
|
||||
void System::set_led_speed(uint32_t speed) {
|
||||
led_flash_speed_ = speed;
|
||||
|
||||
14
src/system.h
14
src/system.h
@@ -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)
|
||||
|
||||
// internal LED
|
||||
#ifndef EMSESP_NO_LED
|
||||
#if defined(ESP8266)
|
||||
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 set_led_speed(uint32_t speed);
|
||||
void system_check();
|
||||
void measure_analog();
|
||||
|
||||
static void show_system(uuid::console::Shell & shell);
|
||||
static void show_users(uuid::console::Shell & shell);
|
||||
@@ -103,6 +92,7 @@ class System {
|
||||
static int reset_counter_;
|
||||
uint32_t last_heartbeat_ = 0;
|
||||
static bool upload_status_; // true if we're in the middle of a OTA firmware upload
|
||||
static uint16_t analog_;
|
||||
|
||||
// settings
|
||||
bool system_heartbeat_;
|
||||
|
||||
@@ -83,13 +83,17 @@ class Telegram {
|
||||
std::string to_string() const;
|
||||
|
||||
// reads a bit value from a given telegram position
|
||||
void read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
|
||||
uint8_t abs_index = (index - offset);
|
||||
if (abs_index >= message_length - 1) {
|
||||
return; // out of bounds
|
||||
bool read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
|
||||
uint8_t abs_index = (index - this->offset);
|
||||
if (abs_index >= this->message_length) {
|
||||
return false; // out of bounds
|
||||
}
|
||||
|
||||
value = (uint8_t)(((message_data[abs_index]) >> (bit)) & 0x01);
|
||||
uint8_t val = value;
|
||||
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
|
||||
@@ -99,18 +103,21 @@ class Telegram {
|
||||
// 2-compliment : https://www.rapidtables.com/convert/number/decimal-to-hex.html
|
||||
// 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)
|
||||
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;
|
||||
|
||||
// check for out of bounds, if so don't modify the value
|
||||
if ((index - this->offset + num_bytes - 1) >= this->message_length) {
|
||||
return;
|
||||
if ((index < this->offset) || ((index - this->offset + num_bytes - 1) >= this->message_length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto val = value;
|
||||
value = 0;
|
||||
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:
|
||||
|
||||
Reference in New Issue
Block a user