mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into idf4
This commit is contained in:
@@ -35,6 +35,8 @@
|
|||||||
- Read time from IVT-controller [#439](https://github.com/emsesp/EMS-ESP32/issues/439)
|
- Read time from IVT-controller [#439](https://github.com/emsesp/EMS-ESP32/issues/439)
|
||||||
- Hybrid Heatpump product-id 168 [#459](https://github.com/emsesp/EMS-ESP32/issues/459), thermostat settings
|
- Hybrid Heatpump product-id 168 [#459](https://github.com/emsesp/EMS-ESP32/issues/459), thermostat settings
|
||||||
- Junkers ISM2 and IPM in warm water mode [#437](https://github.com/emsesp/EMS-ESP32/issues/437)
|
- Junkers ISM2 and IPM in warm water mode [#437](https://github.com/emsesp/EMS-ESP32/issues/437)
|
||||||
|
- Added Shower Alert trigger time and cold shot time [#436](https://github.com/emsesp/EMS-ESP32/issues/436)
|
||||||
|
- Improved Table layout in Web UI (searching, filtering, sorting, exporting to CSV)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@@ -53,6 +55,7 @@
|
|||||||
- Burner selected max power can have a value higher than 100% [#314](https://github.com/emsesp/EMS-ESP32/issues/314)
|
- Burner selected max power can have a value higher than 100% [#314](https://github.com/emsesp/EMS-ESP32/issues/314)
|
||||||
- some missing fahrenheit calculations
|
- some missing fahrenheit calculations
|
||||||
- limited number of exclusions [#339](https://github.com/emsesp/EMS-ESP32/issues/339)
|
- limited number of exclusions [#339](https://github.com/emsesp/EMS-ESP32/issues/339)
|
||||||
|
- MQTT sometimes would not reconnect after a WiFi outage
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@@ -63,7 +66,7 @@
|
|||||||
- Show Sensors quality in WebUI
|
- Show Sensors quality in WebUI
|
||||||
- Controller not shown in WebUI dashboard
|
- Controller not shown in WebUI dashboard
|
||||||
- renamed "Home Assistant Integration" to "MQTT Discovery" in MQTT Settings [#290](https://github.com/emsesp/EMS-ESP32/issues/290)
|
- renamed "Home Assistant Integration" to "MQTT Discovery" in MQTT Settings [#290](https://github.com/emsesp/EMS-ESP32/issues/290)
|
||||||
- Show ems tx reads and writes separatly
|
- Show ems tx reads and writes separately
|
||||||
- Show ems device handlers separated for received, fetched and pending handlers.
|
- Show ems device handlers separated for received, fetched and pending handlers.
|
||||||
- Wired renamed to Ethernet
|
- Wired renamed to Ethernet
|
||||||
- removed system/pin command, new commands in analogsensors
|
- removed system/pin command, new commands in analogsensors
|
||||||
|
|||||||
@@ -343,11 +343,6 @@ const SettingsApplication: FC = () => {
|
|||||||
label="Convert temperature values to Fahrenheit"
|
label="Convert temperature values to Fahrenheit"
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
/>
|
/>
|
||||||
<BlockFormControlLabel
|
|
||||||
control={<Checkbox checked={data.low_clock} onChange={updateFormValue} name="low_clock" />}
|
|
||||||
label="Underclock CPU speed"
|
|
||||||
disabled={saving}
|
|
||||||
/>
|
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox checked={data.notoken_api} onChange={updateFormValue} name="notoken_api" />}
|
control={<Checkbox checked={data.notoken_api} onChange={updateFormValue} name="notoken_api" />}
|
||||||
label="Bypass Access Token authorization on API calls"
|
label="Bypass Access Token authorization on API calls"
|
||||||
@@ -358,6 +353,11 @@ const SettingsApplication: FC = () => {
|
|||||||
label="Enable Read only mode (blocks all outgoing EMS Tx write commands)"
|
label="Enable Read only mode (blocks all outgoing EMS Tx write commands)"
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
/>
|
/>
|
||||||
|
<BlockFormControlLabel
|
||||||
|
control={<Checkbox checked={data.low_clock} onChange={updateFormValue} name="low_clock" />}
|
||||||
|
label="Underclock CPU speed"
|
||||||
|
disabled={saving}
|
||||||
|
/>
|
||||||
<Grid container spacing={0} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
<Grid container spacing={0} direction="row" justifyContent="flex-start" alignItems="flex-start">
|
||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox checked={data.shower_timer} onChange={updateFormValue} name="shower_timer" />}
|
control={<Checkbox checked={data.shower_timer} onChange={updateFormValue} name="shower_timer" />}
|
||||||
@@ -367,8 +367,36 @@ const SettingsApplication: FC = () => {
|
|||||||
<BlockFormControlLabel
|
<BlockFormControlLabel
|
||||||
control={<Checkbox checked={data.shower_alert} onChange={updateFormValue} name="shower_alert" />}
|
control={<Checkbox checked={data.shower_alert} onChange={updateFormValue} name="shower_alert" />}
|
||||||
label="Enable Shower Alert"
|
label="Enable Shower Alert"
|
||||||
disabled={saving}
|
disabled={!data.shower_timer}
|
||||||
/>
|
/>
|
||||||
|
{data.shower_alert && (
|
||||||
|
<>
|
||||||
|
<Grid item xs={2}>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors}
|
||||||
|
name="shower_alert_trigger"
|
||||||
|
label="Trigger Time (minutes)"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.shower_alert_trigger}
|
||||||
|
type="number"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
disabled={!data.shower_timer}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={2}>
|
||||||
|
<ValidatedTextField
|
||||||
|
fieldErrors={fieldErrors}
|
||||||
|
name="shower_alert_coldshot"
|
||||||
|
label="Cold Shot Time (seconds)"
|
||||||
|
variant="outlined"
|
||||||
|
value={data.shower_alert_coldshot}
|
||||||
|
type="number"
|
||||||
|
onChange={updateFormValue}
|
||||||
|
disabled={!data.shower_timer}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
|
<Typography sx={{ pt: 2 }} variant="h6" color="primary">
|
||||||
Formatting Options
|
Formatting Options
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ export interface Settings {
|
|||||||
master_thermostat: number;
|
master_thermostat: number;
|
||||||
shower_timer: boolean;
|
shower_timer: boolean;
|
||||||
shower_alert: boolean;
|
shower_alert: boolean;
|
||||||
|
shower_alert_coldshot: number;
|
||||||
|
shower_alert_trigger: number;
|
||||||
rx_gpio: number;
|
rx_gpio: number;
|
||||||
tx_gpio: number;
|
tx_gpio: number;
|
||||||
telnet_enabled: boolean;
|
telnet_enabled: boolean;
|
||||||
@@ -41,8 +43,8 @@ export enum busConnectionStatus {
|
|||||||
export interface Stat {
|
export interface Stat {
|
||||||
id: string; // name
|
id: string; // name
|
||||||
s: number; // success
|
s: number; // success
|
||||||
f: number; // fail
|
f: number; // fail
|
||||||
q: number; // quality
|
q: number; // quality
|
||||||
}
|
}
|
||||||
export interface Status {
|
export interface Status {
|
||||||
status: busConnectionStatus;
|
status: busConnectionStatus;
|
||||||
|
|||||||
@@ -40,5 +40,9 @@ export const createSettingsValidator = (settings: Settings) =>
|
|||||||
{ required: true, message: 'Mark interval is required' },
|
{ required: true, message: 'Mark interval is required' },
|
||||||
{ type: 'number', min: 0, max: 10, message: 'Port must be between 0 and 10' }
|
{ type: 'number', min: 0, max: 10, message: 'Port must be between 0 and 10' }
|
||||||
]
|
]
|
||||||
|
}),
|
||||||
|
...(settings.shower_alert && {
|
||||||
|
shower_alert_trigger: [{ type: 'number', min: 1, max: 20, message: 'Time must be between 1 and 20 minutes' }],
|
||||||
|
shower_alert_coldshot: [{ type: 'number', min: 1, max: 10, message: 'Time must be between 1 and 10 seconds' }]
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,39 +19,41 @@
|
|||||||
|
|
||||||
class DummySettings {
|
class DummySettings {
|
||||||
public:
|
public:
|
||||||
uint8_t tx_mode = 1;
|
uint8_t tx_mode = 1;
|
||||||
uint8_t ems_bus_id = 0x0B;
|
uint8_t ems_bus_id = 0x0B;
|
||||||
bool syslog_enabled = false;
|
bool syslog_enabled = false;
|
||||||
int8_t syslog_level = 3; // uuid::log::Level
|
int8_t syslog_level = 3; // uuid::log::Level
|
||||||
uint32_t syslog_mark_interval = 0;
|
uint32_t syslog_mark_interval = 0;
|
||||||
String syslog_host = "192.168.1.4";
|
String syslog_host = "192.168.1.4";
|
||||||
uint16_t syslog_port = 514;
|
uint16_t syslog_port = 514;
|
||||||
uint8_t master_thermostat = 0;
|
uint8_t master_thermostat = 0;
|
||||||
bool shower_timer = true;
|
bool shower_timer = true;
|
||||||
bool shower_alert = false;
|
bool shower_alert = false;
|
||||||
bool hide_led = false;
|
uint8_t shower_alert_coldshot = 10;
|
||||||
bool notoken_api = false;
|
uint8_t shower_alert_trigger = 7;
|
||||||
bool readonly_mode = false;
|
bool hide_led = false;
|
||||||
uint8_t bool_format = 1; // using "on" and "off"
|
bool notoken_api = false;
|
||||||
uint8_t enum_format = 1;
|
bool readonly_mode = false;
|
||||||
bool nosleep = false;
|
uint8_t bool_format = 1; // using "on" and "off"
|
||||||
bool fahrenheit = false;
|
uint8_t enum_format = 1;
|
||||||
bool bandwidth20 = false;
|
bool nosleep = false;
|
||||||
bool telnet_enabled = false;
|
bool fahrenheit = false;
|
||||||
String board_profile = "CUSTOM";
|
bool bandwidth20 = false;
|
||||||
bool trace_raw = false;
|
bool telnet_enabled = false;
|
||||||
bool analog_enabled = true; // analog is enabled
|
String board_profile = "CUSTOM";
|
||||||
int8_t weblog_level = 1;
|
bool trace_raw = false;
|
||||||
uint8_t weblog_buffer = 50;
|
bool analog_enabled = true; // analog is enabled
|
||||||
bool weblog_compact = true;
|
int8_t weblog_level = 1;
|
||||||
uint8_t rx_gpio = 0;
|
uint8_t weblog_buffer = 50;
|
||||||
uint8_t tx_gpio = 0;
|
bool weblog_compact = true;
|
||||||
uint8_t dallas_gpio = 16; // to ensure its enabled
|
uint8_t rx_gpio = 0;
|
||||||
bool dallas_parasite = false;
|
uint8_t tx_gpio = 0;
|
||||||
uint8_t led_gpio = 0;
|
uint8_t dallas_gpio = 16; // to ensure its enabled
|
||||||
bool low_clock = false;
|
bool dallas_parasite = false;
|
||||||
uint8_t pbutton_gpio = false;
|
uint8_t led_gpio = 0;
|
||||||
uint8_t solar_maxflow = 30;
|
bool low_clock = false;
|
||||||
|
uint8_t pbutton_gpio = false;
|
||||||
|
uint8_t solar_maxflow = 30;
|
||||||
|
|
||||||
// MQTT
|
// MQTT
|
||||||
uint16_t publish_time = 10;
|
uint16_t publish_time = 10;
|
||||||
|
|||||||
@@ -316,7 +316,9 @@ settings = {
|
|||||||
syslog_port: 514,
|
syslog_port: 514,
|
||||||
master_thermostat: 0,
|
master_thermostat: 0,
|
||||||
shower_timer: true,
|
shower_timer: true,
|
||||||
shower_alert: false,
|
shower_alert: true,
|
||||||
|
shower_alert_trigger: 7,
|
||||||
|
shower_alert_coldshot: 10,
|
||||||
rx_gpio: 23,
|
rx_gpio: 23,
|
||||||
tx_gpio: 5,
|
tx_gpio: 5,
|
||||||
phy_type: 0,
|
phy_type: 0,
|
||||||
|
|||||||
@@ -64,6 +64,14 @@
|
|||||||
#define EMSESP_DEFAULT_SHOWER_ALERT false
|
#define EMSESP_DEFAULT_SHOWER_ALERT false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef EMSESP_DEFAULT_SHOWER_ALERT_TRIGGER
|
||||||
|
#define EMSESP_DEFAULT_SHOWER_ALERT_TRIGGER 7
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT
|
||||||
|
#define EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT 10
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef EMSESP_DEFAULT_HIDE_LED
|
#ifndef EMSESP_DEFAULT_HIDE_LED
|
||||||
#define EMSESP_DEFAULT_HIDE_LED false
|
#define EMSESP_DEFAULT_HIDE_LED false
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace emsesp {
|
|||||||
// this includes commands since they can also be entities and visible in the web UI
|
// this includes commands since they can also be entities and visible in the web UI
|
||||||
uint8_t EMSdevice::count_entities() {
|
uint8_t EMSdevice::count_entities() {
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
for (auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.hasValue()) {
|
if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.hasValue()) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@@ -338,15 +338,17 @@ char * EMSdevice::show_telegram_handlers(char * result, const size_t len, const
|
|||||||
strlcat(result, Helpers::hextoa(tf.telegram_type_id_, true).c_str(), len);
|
strlcat(result, Helpers::hextoa(tf.telegram_type_id_, true).c_str(), len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlers == Handlers::ALL || handlers == Handlers::IGNORED) {
|
if (handlers == Handlers::ALL || handlers == Handlers::IGNORED) {
|
||||||
i = 0;
|
i = 0;
|
||||||
for (auto handlers : handlers_ignored_) {
|
for (auto h : handlers_ignored_) {
|
||||||
if (i++ > 0) {
|
if (i++ > 0) {
|
||||||
strlcat(result, " ", len);
|
strlcat(result, " ", len);
|
||||||
}
|
}
|
||||||
strlcat(result, Helpers::hextoa(handlers).c_str(), len);
|
strlcat(result, Helpers::hextoa(h).c_str(), len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -667,7 +669,7 @@ void EMSdevice::generate_values_web(JsonObject & output) {
|
|||||||
|
|
||||||
// handle Booleans (true, false), use strings, no native true/false)
|
// handle Booleans (true, false), use strings, no native true/false)
|
||||||
if (dv.type == DeviceValueType::BOOL) {
|
if (dv.type == DeviceValueType::BOOL) {
|
||||||
bool value_b = (bool)*(uint8_t *)(dv.value_p);
|
auto value_b = (bool)*(uint8_t *)(dv.value_p);
|
||||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
||||||
obj["v"] = value_b ? 1 : 0;
|
obj["v"] = value_b ? 1 : 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -786,7 +788,7 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
|
|||||||
if (dv.hasValue()) {
|
if (dv.hasValue()) {
|
||||||
// handle Booleans (true, false), use strings, no native true/false)
|
// handle Booleans (true, false), use strings, no native true/false)
|
||||||
if (dv.type == DeviceValueType::BOOL) {
|
if (dv.type == DeviceValueType::BOOL) {
|
||||||
bool value_b = (bool)*(uint8_t *)(dv.value_p);
|
auto value_b = (bool)*(uint8_t *)(dv.value_p);
|
||||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
||||||
obj["v"] = value_b ? 1 : 0;
|
obj["v"] = value_b ? 1 : 0;
|
||||||
} else {
|
} else {
|
||||||
@@ -890,17 +892,17 @@ void EMSdevice::mask_entity(const std::string & entity_id) {
|
|||||||
|
|
||||||
// populate a string vector with entities that have masks set
|
// populate a string vector with entities that have masks set
|
||||||
void EMSdevice::getMaskedEntities(std::vector<std::string> & entity_ids) {
|
void EMSdevice::getMaskedEntities(std::vector<std::string> & entity_ids) {
|
||||||
for (auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
std::string entity_name =
|
std::string entity_name =
|
||||||
dv.tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(dv.short_name) : tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
|
dv.tag < DeviceValueTAG::TAG_HC1 ? read_flash_string(dv.short_name) : tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
|
||||||
uint8_t mask = dv.state >> 4;
|
uint8_t mask = dv.state >> 4;
|
||||||
|
|
||||||
if (mask) {
|
if (mask) {
|
||||||
entity_ids.push_back(Helpers::hextoa(mask, false) + entity_name);
|
entity_ids.push_back(Helpers::hextoa(mask, false) + entity_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// builds json for a specific device value / entity
|
// builds json for a specific device value / entity
|
||||||
// cmd is the endpoint or name of the device entity
|
// cmd is the endpoint or name of the device entity
|
||||||
// returns false if failed, otherwise true
|
// returns false if failed, otherwise true
|
||||||
@@ -995,7 +997,7 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
|
|||||||
|
|
||||||
case DeviceValueType::BOOL:
|
case DeviceValueType::BOOL:
|
||||||
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
||||||
bool value_b = (bool)*(uint8_t *)(dv.value_p);
|
auto value_b = (bool)*(uint8_t *)(dv.value_p);
|
||||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||||
json[value] = value_b;
|
json[value] = value_b;
|
||||||
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
|
||||||
@@ -1128,7 +1130,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
|
|||||||
// handle Booleans
|
// handle Booleans
|
||||||
if (dv.type == DeviceValueType::BOOL && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
if (dv.type == DeviceValueType::BOOL && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
||||||
// see how to render the value depending on the setting
|
// see how to render the value depending on the setting
|
||||||
bool value_b = (bool)*(uint8_t *)(dv.value_p);
|
auto value_b = (bool)*(uint8_t *)(dv.value_p);
|
||||||
if (Mqtt::ha_enabled() && (output_target == OUTPUT_TARGET::MQTT)) {
|
if (Mqtt::ha_enabled() && (output_target == OUTPUT_TARGET::MQTT)) {
|
||||||
char s[7];
|
char s[7];
|
||||||
json[name] = Helpers::render_boolean(s, value_b); // for HA always render as string
|
json[name] = Helpers::render_boolean(s, value_b); // for HA always render as string
|
||||||
|
|||||||
164
src/helpers.cpp
164
src/helpers.cpp
@@ -464,91 +464,142 @@ uint32_t Helpers::abs(const int32_t i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// for booleans, use isBool true (EMS_VALUE_BOOL)
|
// for booleans, use isBool true (EMS_VALUE_BOOL)
|
||||||
bool Helpers::hasValue(const uint8_t & v, const uint8_t isBool) {
|
bool Helpers::hasValue(const uint8_t & value, const uint8_t isBool) {
|
||||||
if (isBool == EMS_VALUE_BOOL) {
|
if (isBool == EMS_VALUE_BOOL) {
|
||||||
return (v != EMS_VALUE_BOOL_NOTSET);
|
return (value != EMS_VALUE_BOOL_NOTSET);
|
||||||
}
|
}
|
||||||
return (v != EMS_VALUE_UINT_NOTSET);
|
return (value != EMS_VALUE_UINT_NOTSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Helpers::hasValue(const int8_t & v) {
|
bool Helpers::hasValue(const int8_t & value) {
|
||||||
return (v != EMS_VALUE_INT_NOTSET);
|
return (value != EMS_VALUE_INT_NOTSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Helpers::hasValue(const char * v) {
|
bool Helpers::hasValue(const char * value) {
|
||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
if ((value == nullptr) || (strlen(value) == 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (v[0] != '\0');
|
return (value[0] != '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
// for short these are typically 0x8300, 0x7D00 and sometimes 0x8000
|
// for short these are typically 0x8300, 0x7D00 and sometimes 0x8000
|
||||||
bool Helpers::hasValue(const int16_t & v) {
|
bool Helpers::hasValue(const int16_t & value) {
|
||||||
return (abs(v) < EMS_VALUE_USHORT_NOTSET);
|
return (abs(value) < EMS_VALUE_USHORT_NOTSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Helpers::hasValue(const uint16_t & v) {
|
bool Helpers::hasValue(const uint16_t & value) {
|
||||||
return (v < EMS_VALUE_USHORT_NOTSET);
|
return (value < EMS_VALUE_USHORT_NOTSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Helpers::hasValue(const uint32_t & v) {
|
bool Helpers::hasValue(const uint32_t & value) {
|
||||||
return (v != EMS_VALUE_ULONG_NOTSET);
|
return (value != EMS_VALUE_ULONG_NOTSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks if we can convert a char string to an int value
|
// checks if we can convert a char string to an int value
|
||||||
bool Helpers::value2number(const char * v, int & value, const int min, const int max) {
|
bool Helpers::value2number(const char * value, int & value_i, const int min, const int max) {
|
||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
if ((value == nullptr) || (strlen(value) == 0)) {
|
||||||
value = 0;
|
value_i = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = atoi(v);
|
value_i = atoi(value);
|
||||||
if (value >= min && value <= max) {
|
if (value_i >= min && value_i <= max) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks if we can convert a char string to a float value
|
// checks if we can convert a char string to a float value
|
||||||
bool Helpers::value2float(const char * v, float & value) {
|
bool Helpers::value2float(const char * value, float & value_f) {
|
||||||
value = 0;
|
value_f = 0;
|
||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
if ((value == nullptr) || (strlen(value) == 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v[0] == '-' || v[0] == '.' || (v[0] >= '0' && v[0] <= '9')) {
|
if (value[0] == '-' || value[0] == '.' || (value[0] >= '0' && value[0] <= '9')) {
|
||||||
value = atof(v);
|
value_f = atof(value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v[0] == '+' && (v[1] == '.' || (v[1] >= '0' && v[1] <= '9'))) {
|
if (value[0] == '+' && (value[1] == '.' || (value[1] >= '0' && value[1] <= '9'))) {
|
||||||
value = atof(v + 1);
|
value_f = atof(value + 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Helpers::value2temperature(const char * v, float & value, bool relative) {
|
bool Helpers::value2temperature(const char * value, float & value_f, bool relative) {
|
||||||
if (value2float(v, value)) {
|
if (value2float(value, value_f)) {
|
||||||
if (EMSESP::system_.fahrenheit()) {
|
if (EMSESP::system_.fahrenheit()) {
|
||||||
value = relative ? (value / 1.8) : (value - 32) / 1.8;
|
value_f = relative ? (value_f / 1.8) : (value_f - 32) / 1.8;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Helpers::value2temperature(const char * v, int & value, const bool relative, const int min, const int max) {
|
bool Helpers::value2temperature(const char * value, int & value_i, const bool relative, const int min, const int max) {
|
||||||
if (value2number(v, value, min, max)) {
|
if (value2number(value, value_i, min, max)) {
|
||||||
if (EMSESP::system_.fahrenheit()) {
|
if (EMSESP::system_.fahrenheit()) {
|
||||||
value = relative ? (value / 1.8) : (value - 32) / 1.8;
|
value_i = relative ? (value_i / 1.8) : (value_i - 32) / 1.8;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checks if we can convert a char string to a lowercase string
|
||||||
|
bool Helpers::value2string(const char * value, std::string & value_s) {
|
||||||
|
if ((value == nullptr) || (strlen(value) == 0)) {
|
||||||
|
value_s = std::string{};
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_s = toLower(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks to see if a string (usually a command or payload cmd) looks like a boolean
|
||||||
|
// on, off, true, false, 1, 0
|
||||||
|
bool Helpers::value2bool(const char * value, bool & value_b) {
|
||||||
|
if ((value == nullptr) || (strlen(value) == 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string bool_str = toLower(value); // convert to lower case
|
||||||
|
|
||||||
|
if ((bool_str == read_flash_string(F_(on))) || (bool_str == "1") || (bool_str == "true")) {
|
||||||
|
value_b = true;
|
||||||
|
return true; // is a bool
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bool_str == read_flash_string(F_(off))) || (bool_str == "0") || (bool_str == "false")) {
|
||||||
|
value_b = false;
|
||||||
|
return true; // is a bool
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // not a bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks to see if a string is member of a vector and return the index, also allow true/false for on/off
|
||||||
|
bool Helpers::value2enum(const char * value, uint8_t & value_ui, const __FlashStringHelper * const * strs) {
|
||||||
|
if ((value == nullptr) || (strlen(value) == 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string str = toLower(value);
|
||||||
|
|
||||||
|
for (value_ui = 0; strs[value_ui]; value_ui++) {
|
||||||
|
std::string str1 = toLower(read_flash_string(strs[value_ui]));
|
||||||
|
if ((str1 != "")
|
||||||
|
&& ((str1 == read_flash_string(F_(off)) && str == "false") || (str1 == read_flash_string(F_(on)) && str == "true") || (str == str1)
|
||||||
|
|| (value[0] == ('0' + value_ui) && value[1] == '\0'))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/313970/how-to-convert-stdstring-to-lower-case
|
// https://stackoverflow.com/questions/313970/how-to-convert-stdstring-to-lower-case
|
||||||
std::string Helpers::toLower(std::string const & s) {
|
std::string Helpers::toLower(std::string const & s) {
|
||||||
std::string lc = s;
|
std::string lc = s;
|
||||||
@@ -562,55 +613,6 @@ std::string Helpers::toUpper(std::string const & s) {
|
|||||||
return lc;
|
return lc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks if we can convert a char string to a lowercase string
|
|
||||||
bool Helpers::value2string(const char * v, std::string & value) {
|
|
||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
|
||||||
value = std::string{};
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value = toLower(v);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks to see if a string (usually a command or payload cmd) looks like a boolean
|
|
||||||
// on, off, true, false, 1, 0
|
|
||||||
bool Helpers::value2bool(const char * v, bool & value) {
|
|
||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string bool_str = toLower(v); // convert to lower case
|
|
||||||
|
|
||||||
if ((bool_str == read_flash_string(F_(on))) || (bool_str == "1") || (bool_str == "true")) {
|
|
||||||
value = true;
|
|
||||||
return true; // is a bool
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((bool_str == read_flash_string(F_(off))) || (bool_str == "0") || (bool_str == "false")) {
|
|
||||||
value = false;
|
|
||||||
return true; // is a bool
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // not a bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks to see if a string is member of a vector and return the index, also allow true/false for on/off
|
|
||||||
bool Helpers::value2enum(const char * v, uint8_t & value, const __FlashStringHelper * const * strs) {
|
|
||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
std::string str = toLower(v);
|
|
||||||
for (value = 0; strs[value]; value++) {
|
|
||||||
std::string str1 = toLower(read_flash_string(strs[value]));
|
|
||||||
if ((str1 != "")
|
|
||||||
&& ((str1 == read_flash_string(F_(off)) && str == "false") || (str1 == read_flash_string(F_(on)) && str == "true") || (str == str1)
|
|
||||||
|| (v[0] == ('0' + value) && v[1] == '\0'))) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace char in char string
|
// replace char in char string
|
||||||
void Helpers::replace_char(char * str, char find, char replace) {
|
void Helpers::replace_char(char * str, char find, char replace) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|||||||
@@ -57,20 +57,20 @@ class Helpers {
|
|||||||
static std::string toUpper(std::string const & s);
|
static std::string toUpper(std::string const & s);
|
||||||
static void replace_char(char * str, char find, char replace);
|
static void replace_char(char * str, char find, char replace);
|
||||||
|
|
||||||
static bool hasValue(const uint8_t & v, const uint8_t isBool = 0);
|
static bool hasValue(const uint8_t & value, const uint8_t isBool = 0);
|
||||||
static bool hasValue(const int8_t & v);
|
static bool hasValue(const int8_t & value);
|
||||||
static bool hasValue(const int16_t & v);
|
static bool hasValue(const int16_t & value);
|
||||||
static bool hasValue(const uint16_t & v);
|
static bool hasValue(const uint16_t & value);
|
||||||
static bool hasValue(const uint32_t & v);
|
static bool hasValue(const uint32_t & value);
|
||||||
static bool hasValue(const char * v);
|
static bool hasValue(const char * value);
|
||||||
|
|
||||||
static bool value2number(const char * v, int & value, const int min = -2147483648, const int max = 2147483647);
|
static bool value2number(const char * value, int & value_i, const int min = -2147483648, const int max = 2147483647);
|
||||||
static bool value2float(const char * v, float & value);
|
static bool value2float(const char * value, float & value_f);
|
||||||
static bool value2bool(const char * v, bool & value);
|
static bool value2bool(const char * value, bool & value_b);
|
||||||
static bool value2string(const char * v, std::string & value);
|
static bool value2string(const char * value, std::string & value_s);
|
||||||
static bool value2enum(const char * v, uint8_t & value, const __FlashStringHelper * const * strs);
|
static bool value2enum(const char * value, uint8_t & value_ui, const __FlashStringHelper * const * strs);
|
||||||
static bool value2temperature(const char * v, float & value, bool relative = false);
|
static bool value2temperature(const char * value, float & value_f, bool relative = false);
|
||||||
static bool value2temperature(const char * v, int & value, const bool relative = false, const int min = -2147483648, const int max = 2147483647);
|
static bool value2temperature(const char * value, int & value_i, const bool relative = false, const int min = -2147483648, const int max = 2147483647);
|
||||||
|
|
||||||
#ifdef EMSESP_STANDALONE
|
#ifdef EMSESP_STANDALONE
|
||||||
static char * ultostr(char * ptr, uint32_t value, const uint8_t base);
|
static char * ultostr(char * ptr, uint32_t value, const uint8_t base);
|
||||||
|
|||||||
@@ -24,8 +24,10 @@ uuid::log::Logger Shower::logger_{F_(shower), uuid::log::Facility::CONSOLE};
|
|||||||
|
|
||||||
void Shower::start() {
|
void Shower::start() {
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
shower_timer_ = settings.shower_timer;
|
shower_timer_ = settings.shower_timer;
|
||||||
shower_alert_ = settings.shower_alert;
|
shower_alert_ = settings.shower_alert;
|
||||||
|
shower_alert_trigger_ = settings.shower_alert_trigger * 60000; // convert from minutes
|
||||||
|
shower_alert_coldshot_ = settings.shower_alert_coldshot * 1000; // convert from seconds
|
||||||
});
|
});
|
||||||
|
|
||||||
set_shower_state(false, true); // turns shower to off and creates HA topic if not already done
|
set_shower_state(false, true); // turns shower to off and creates HA topic if not already done
|
||||||
@@ -59,7 +61,7 @@ void Shower::loop() {
|
|||||||
LOG_DEBUG(F("[Shower] hot water still running, starting shower timer"));
|
LOG_DEBUG(F("[Shower] hot water still running, starting shower timer"));
|
||||||
}
|
}
|
||||||
// check if the shower has been on too long
|
// check if the shower has been on too long
|
||||||
else if ((time_now - timer_start_) > SHOWER_MAX_DURATION) {
|
else if ((time_now - timer_start_) > shower_alert_trigger_) {
|
||||||
shower_alert_start();
|
shower_alert_start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +97,7 @@ void Shower::loop() {
|
|||||||
|
|
||||||
// at this point we're in the shower cold shot (doing_cold_shot_ == true)
|
// at this point we're in the shower cold shot (doing_cold_shot_ == true)
|
||||||
// keep repeating until the time is up
|
// keep repeating until the time is up
|
||||||
if ((time_now - alert_timer_start_) > SHOWER_COLDSHOT_DURATION) {
|
if ((time_now - alert_timer_start_) > shower_alert_coldshot_) {
|
||||||
shower_alert_stop();
|
shower_alert_stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/shower.h
10
src/shower.h
@@ -49,11 +49,9 @@ class Shower {
|
|||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
static constexpr uint32_t SHOWER_PAUSE_TIME = 15000; // in ms. 15 seconds, max time if water is switched off & on during a shower
|
static constexpr uint32_t SHOWER_PAUSE_TIME = 15000; // in ms. 15 seconds, max time if water is switched off & on during a shower
|
||||||
static constexpr uint32_t SHOWER_MIN_DURATION = 120000; // in ms. 2 minutes, before recognizing its a shower
|
static constexpr uint32_t SHOWER_MIN_DURATION = 120000; // in ms. 2 minutes, before recognizing its a shower
|
||||||
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
|
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
|
||||||
static constexpr uint32_t SHOWER_COLDSHOT_DURATION = 10000; // 10 seconds for cold water before turning back hot water
|
|
||||||
static constexpr uint32_t SHOWER_MAX_DURATION = 420000; // in ms. 7 minutes, before trigger a shot of cold water
|
|
||||||
|
|
||||||
void publish_shower_data() const;
|
void publish_shower_data() const;
|
||||||
void shower_alert_start();
|
void shower_alert_start();
|
||||||
@@ -61,6 +59,8 @@ class Shower {
|
|||||||
|
|
||||||
bool shower_timer_; // true if we want to report back on shower times
|
bool shower_timer_; // true if we want to report back on shower times
|
||||||
bool shower_alert_; // true if we want the alert of cold water
|
bool shower_alert_; // true if we want the alert of cold water
|
||||||
|
uint32_t shower_alert_trigger_; // default 7 minutes, before trigger a shot of cold water
|
||||||
|
uint32_t shower_alert_coldshot_; // default 10 seconds for cold water before turning back hot water
|
||||||
bool ha_configdone_ = false; // for HA MQTT Discovery
|
bool ha_configdone_ = false; // for HA MQTT Discovery
|
||||||
bool shower_state_;
|
bool shower_state_;
|
||||||
uint32_t timer_start_; // ms
|
uint32_t timer_start_; // ms
|
||||||
|
|||||||
@@ -998,6 +998,10 @@ bool System::command_settings(const char * value, const int8_t id, JsonObject &
|
|||||||
|
|
||||||
node["shower_timer"] = settings.shower_timer;
|
node["shower_timer"] = settings.shower_timer;
|
||||||
node["shower_alert"] = settings.shower_alert;
|
node["shower_alert"] = settings.shower_alert;
|
||||||
|
if (settings.shower_alert) {
|
||||||
|
node["shower_alert_coldshot"] = settings.shower_alert_coldshot / 1000; // seconds
|
||||||
|
node["shower_alert_trigger"] = settings.shower_alert_trigger / 60000; // minutes
|
||||||
|
}
|
||||||
|
|
||||||
node["rx_gpio"] = settings.rx_gpio;
|
node["rx_gpio"] = settings.rx_gpio;
|
||||||
node["tx_gpio"] = settings.tx_gpio;
|
node["tx_gpio"] = settings.tx_gpio;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.4.0b14a0"
|
#define EMSESP_APP_VERSION "3.4.0b15idf4"
|
||||||
|
|||||||
@@ -137,8 +137,9 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) {
|
|||||||
for (const auto & sensor : EMSESP::analogsensor_.sensors()) {
|
for (const auto & sensor : EMSESP::analogsensor_.sensors()) {
|
||||||
// don't send if it's marked for removal
|
// don't send if it's marked for removal
|
||||||
if (sensor.type() != AnalogSensor::AnalogType::MARK_DELETED) {
|
if (sensor.type() != AnalogSensor::AnalogType::MARK_DELETED) {
|
||||||
|
count++;
|
||||||
JsonObject obj = analogs.createNestedObject();
|
JsonObject obj = analogs.createNestedObject();
|
||||||
obj["id"] = Helpers::smallitoa(buffer, ++count); // needed for sorting table
|
obj["id"] = Helpers::smallitoa(buffer, count); // needed for sorting table
|
||||||
obj["g"] = sensor.gpio();
|
obj["g"] = sensor.gpio();
|
||||||
obj["n"] = sensor.name();
|
obj["n"] = sensor.name();
|
||||||
obj["u"] = sensor.uom();
|
obj["u"] = sensor.uom();
|
||||||
|
|||||||
@@ -37,41 +37,43 @@ WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, Securit
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebSettings::read(WebSettings & settings, JsonObject & root) {
|
void WebSettings::read(WebSettings & settings, JsonObject & root) {
|
||||||
root["tx_mode"] = settings.tx_mode;
|
root["tx_mode"] = settings.tx_mode;
|
||||||
root["ems_bus_id"] = settings.ems_bus_id;
|
root["ems_bus_id"] = settings.ems_bus_id;
|
||||||
root["syslog_enabled"] = settings.syslog_enabled;
|
root["syslog_enabled"] = settings.syslog_enabled;
|
||||||
root["syslog_level"] = settings.syslog_level;
|
root["syslog_level"] = settings.syslog_level;
|
||||||
root["trace_raw"] = settings.trace_raw;
|
root["trace_raw"] = settings.trace_raw;
|
||||||
root["syslog_mark_interval"] = settings.syslog_mark_interval;
|
root["syslog_mark_interval"] = settings.syslog_mark_interval;
|
||||||
root["syslog_host"] = settings.syslog_host;
|
root["syslog_host"] = settings.syslog_host;
|
||||||
root["syslog_port"] = settings.syslog_port;
|
root["syslog_port"] = settings.syslog_port;
|
||||||
root["master_thermostat"] = settings.master_thermostat;
|
root["master_thermostat"] = settings.master_thermostat;
|
||||||
root["shower_timer"] = settings.shower_timer;
|
root["shower_timer"] = settings.shower_timer;
|
||||||
root["shower_alert"] = settings.shower_alert;
|
root["shower_alert"] = settings.shower_alert;
|
||||||
root["rx_gpio"] = settings.rx_gpio;
|
root["shower_alert_coldshot"] = settings.shower_alert_coldshot;
|
||||||
root["tx_gpio"] = settings.tx_gpio;
|
root["shower_alert_trigger"] = settings.shower_alert_trigger;
|
||||||
root["dallas_gpio"] = settings.dallas_gpio;
|
root["rx_gpio"] = settings.rx_gpio;
|
||||||
root["dallas_parasite"] = settings.dallas_parasite;
|
root["tx_gpio"] = settings.tx_gpio;
|
||||||
root["led_gpio"] = settings.led_gpio;
|
root["dallas_gpio"] = settings.dallas_gpio;
|
||||||
root["hide_led"] = settings.hide_led;
|
root["dallas_parasite"] = settings.dallas_parasite;
|
||||||
root["low_clock"] = settings.low_clock;
|
root["led_gpio"] = settings.led_gpio;
|
||||||
root["telnet_enabled"] = settings.telnet_enabled;
|
root["hide_led"] = settings.hide_led;
|
||||||
root["notoken_api"] = settings.notoken_api;
|
root["low_clock"] = settings.low_clock;
|
||||||
root["readonly_mode"] = settings.readonly_mode;
|
root["telnet_enabled"] = settings.telnet_enabled;
|
||||||
root["analog_enabled"] = settings.analog_enabled;
|
root["notoken_api"] = settings.notoken_api;
|
||||||
root["pbutton_gpio"] = settings.pbutton_gpio;
|
root["readonly_mode"] = settings.readonly_mode;
|
||||||
root["solar_maxflow"] = settings.solar_maxflow;
|
root["analog_enabled"] = settings.analog_enabled;
|
||||||
root["board_profile"] = settings.board_profile;
|
root["pbutton_gpio"] = settings.pbutton_gpio;
|
||||||
root["fahrenheit"] = settings.fahrenheit;
|
root["solar_maxflow"] = settings.solar_maxflow;
|
||||||
root["bool_format"] = settings.bool_format;
|
root["board_profile"] = settings.board_profile;
|
||||||
root["enum_format"] = settings.enum_format;
|
root["fahrenheit"] = settings.fahrenheit;
|
||||||
root["weblog_level"] = settings.weblog_level;
|
root["bool_format"] = settings.bool_format;
|
||||||
root["weblog_buffer"] = settings.weblog_buffer;
|
root["enum_format"] = settings.enum_format;
|
||||||
root["weblog_compact"] = settings.weblog_compact;
|
root["weblog_level"] = settings.weblog_level;
|
||||||
root["phy_type"] = settings.phy_type;
|
root["weblog_buffer"] = settings.weblog_buffer;
|
||||||
root["eth_power"] = settings.eth_power;
|
root["weblog_compact"] = settings.weblog_compact;
|
||||||
root["eth_phy_addr"] = settings.eth_phy_addr;
|
root["phy_type"] = settings.phy_type;
|
||||||
root["eth_clock_mode"] = settings.eth_clock_mode;
|
root["eth_power"] = settings.eth_power;
|
||||||
|
root["eth_phy_addr"] = settings.eth_phy_addr;
|
||||||
|
root["eth_clock_mode"] = settings.eth_clock_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call on initialization and also when settings are updated via web or console
|
// call on initialization and also when settings are updated via web or console
|
||||||
@@ -152,6 +154,12 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings)
|
|||||||
prev = settings.shower_alert;
|
prev = settings.shower_alert;
|
||||||
settings.shower_alert = root["shower_alert"] | EMSESP_DEFAULT_SHOWER_ALERT;
|
settings.shower_alert = root["shower_alert"] | EMSESP_DEFAULT_SHOWER_ALERT;
|
||||||
check_flag(prev, settings.shower_alert, ChangeFlags::SHOWER);
|
check_flag(prev, settings.shower_alert, ChangeFlags::SHOWER);
|
||||||
|
prev = settings.shower_alert_trigger;
|
||||||
|
settings.shower_alert_trigger = root["shower_alert_trigger"] | EMSESP_DEFAULT_SHOWER_ALERT_TRIGGER;
|
||||||
|
check_flag(prev, settings.shower_alert_trigger, ChangeFlags::SHOWER);
|
||||||
|
prev = settings.shower_alert_coldshot;
|
||||||
|
settings.shower_alert_coldshot = root["shower_alert_coldshot"] | EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT;
|
||||||
|
check_flag(prev, settings.shower_alert_coldshot, ChangeFlags::SHOWER);
|
||||||
|
|
||||||
// led
|
// led
|
||||||
prev = settings.led_gpio;
|
prev = settings.led_gpio;
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ class WebSettings {
|
|||||||
uint8_t master_thermostat;
|
uint8_t master_thermostat;
|
||||||
bool shower_timer;
|
bool shower_timer;
|
||||||
bool shower_alert;
|
bool shower_alert;
|
||||||
|
uint8_t shower_alert_trigger;
|
||||||
|
uint8_t shower_alert_coldshot;
|
||||||
bool syslog_enabled;
|
bool syslog_enabled;
|
||||||
int8_t syslog_level; // uuid::log::Level
|
int8_t syslog_level; // uuid::log::Level
|
||||||
uint32_t syslog_mark_interval;
|
uint32_t syslog_mark_interval;
|
||||||
|
|||||||
Reference in New Issue
Block a user