This commit is contained in:
MichaelDvP
2024-06-20 14:51:23 +02:00
19 changed files with 85 additions and 37 deletions

View File

@@ -27,4 +27,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: | run: |
sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" sonar-scanner

View File

@@ -37,3 +37,4 @@
- rename DeviceValueTypes, add UINT32 for custom entities - rename DeviceValueTypes, add UINT32 for custom entities
- dynamic register dhw circuits for thermostat - dynamic register dhw circuits for thermostat
- removed OTA feature [#1738](https://github.com/emsesp/EMS-ESP32/issues/1738) - removed OTA feature [#1738](https://github.com/emsesp/EMS-ESP32/issues/1738)
- added shower min duration [[#1801](https://github.com/emsesp/EMS-ESP32/issues/1801)]

View File

@@ -30,7 +30,7 @@
"@mui/material": "^5.15.20", "@mui/material": "^5.15.20",
"@table-library/react-table-library": "4.1.7", "@table-library/react-table-library": "4.1.7",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.14.5", "@types/node": "^20.14.6",
"@types/react": "^18.3.3", "@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0", "@types/react-dom": "^18.3.0",
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",

View File

@@ -546,6 +546,26 @@ const ApplicationSettings: FC = () => {
justifyContent="flex-start" justifyContent="flex-start"
alignItems="flex-start" alignItems="flex-start"
> >
{data.shower_timer && (
<Grid item xs={12} sm={6}>
<ValidatedTextField
fieldErrors={fieldErrors}
name="shower_min_duration"
// TODO translate
label="Dp this"
InputProps={{
endAdornment: (
<InputAdornment position="end">{LL.SECONDS()}</InputAdornment>
)
}}
variant="outlined"
value={numberValue(data.shower_min_duration)}
fullWidth
type="number"
onChange={updateFormValue}
/>
</Grid>
)}
{data.shower_alert && ( {data.shower_alert && (
<> <>
<Grid item xs={12} sm={6}> <Grid item xs={12} sm={6}>

View File

@@ -12,6 +12,7 @@ export interface Settings {
shower_alert: boolean; shower_alert: boolean;
shower_alert_coldshot: number; shower_alert_coldshot: number;
shower_alert_trigger: number; shower_alert_trigger: number;
shower_min_duration: number;
rx_gpio: number; rx_gpio: number;
tx_gpio: number; tx_gpio: number;
telnet_enabled: boolean; telnet_enabled: boolean;

View File

@@ -234,6 +234,16 @@ export const createSettingsValidator = (settings: Settings) =>
{ type: 'number', min: 0, max: 10, message: 'Must be between 0 and 10' } { type: 'number', min: 0, max: 10, message: 'Must be between 0 and 10' }
] ]
}), }),
...(settings.shower_timer && {
shower_min_duration: [
{
type: 'number',
min: 1,
max: 3000,
message: 'Time must be between 1 and 3000 seconds'
}
]
}),
...(settings.shower_alert && { ...(settings.shower_alert && {
shower_alert_trigger: [ shower_alert_trigger: [
{ {

View File

@@ -1760,12 +1760,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/node@npm:^20.14.5": "@types/node@npm:^20.14.6":
version: 20.14.5 version: 20.14.6
resolution: "@types/node@npm:20.14.5" resolution: "@types/node@npm:20.14.6"
dependencies: dependencies:
undici-types: "npm:~5.26.4" undici-types: "npm:~5.26.4"
checksum: 10c0/06a8c304b5f7f190d4497807dc67ad09ee7b14ea2996bfdc823553c624698d8cab1ef9d16f8b764f20cb9eb11caa0e832787741e9ef70e1c89d620797ab28436 checksum: 10c0/22640f0eb2a955872e4529a93be1b719f67b527b80fdab51419756d20e21b5ce0f4ccbee9a3e2ff20e5def647f77baf77b4b0434ff8896791c102165ec0c3e48
languageName: node languageName: node
linkType: hard linkType: hard
@@ -1996,7 +1996,7 @@ __metadata:
"@trivago/prettier-plugin-sort-imports": "npm:^4.3.0" "@trivago/prettier-plugin-sort-imports": "npm:^4.3.0"
"@types/babel__core": "npm:^7" "@types/babel__core": "npm:^7"
"@types/lodash-es": "npm:^4.17.12" "@types/lodash-es": "npm:^4.17.12"
"@types/node": "npm:^20.14.5" "@types/node": "npm:^20.14.6"
"@types/react": "npm:^18.3.3" "@types/react": "npm:^18.3.3"
"@types/react-dom": "npm:^18.3.0" "@types/react-dom": "npm:^18.3.0"
"@types/react-router-dom": "npm:^5.3.3" "@types/react-router-dom": "npm:^5.3.3"

View File

@@ -84,6 +84,4 @@ char * EMSuart::hextoa(char * result, const uint8_t value) {
} // namespace emsesp } // namespace emsesp
#pragma GCC diagnostic pop
#endif #endif

View File

@@ -610,6 +610,7 @@ let settings = {
shower_alert: true, shower_alert: true,
shower_alert_trigger: 7, shower_alert_trigger: 7,
shower_alert_coldshot: 10, shower_alert_coldshot: 10,
shower_min_duration: 120,
rx_gpio: 23, rx_gpio: 23,
tx_gpio: 5, tx_gpio: 5,
phy_type: 0, phy_type: 0,

View File

@@ -13,7 +13,7 @@ extra_configs =
pio_local.ini pio_local.ini
[common] [common]
core_build_flags = -std=gnu++2a -Isrc -Wno-type-limits -Wall -Wextra -Wno-unused-parameter core_build_flags = -std=gnu++2a -Isrc -Wno-type-limits -Wall -Wextra -Wno-unused-parameter -Wno-unused-variable -Wno-format
core_unbuild_flags = -std=gnu++11 core_unbuild_flags = -std=gnu++11
; my_build_flags is set in pio_local.ini ; my_build_flags is set in pio_local.ini

View File

@@ -1,7 +1,12 @@
#!/bin/sh #!/bin/sh
# This is an example file to run sonar from a Linux command line # This is an example file to run sonar from a Linux command line
#
# Make sure Sonar CLI is installed (https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/scanners/sonarscanner/)
# Download Solar Scanner from https://github.com/SonarSource/sonar-scanner-cli/releases
# or https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/
#
# Run from the root of the project like `./scripts/run_sonar.sh` # Run from the root of the project like `./scripts/run_sonar.sh`
# Follow the setup in Sonar for your prpject and make sure chmod 755 +x on all the files # Follow the setup in Sonar for your project and make sure chmod 755 +x on all the files
# and make sure you set the token in the shell like export SONAR_TOKEN="xxxxx" # and make sure you set the token in the shell like export SONAR_TOKEN="xxxxx"
make clean make clean
@@ -12,5 +17,5 @@ make clean
-Dsonar.projectKey=proddy_EMS-ESP32 \ -Dsonar.projectKey=proddy_EMS-ESP32 \
-Dsonar.projectName=EMS-ESP32 \ -Dsonar.projectName=EMS-ESP32 \
-Dsonar.sources="./src, ./lib/framework" \ -Dsonar.sources="./src, ./lib/framework" \
-Dsonar.cfamily.build-wrapper-output=bw-output \ -Dsonar.cfamily.compile-commands=compile_commands.json \
-Dsonar.host.url=https://sonarcloud.io -Dsonar.host.url=https://sonarcloud.io

View File

@@ -3,7 +3,8 @@ sonar.projectKey=emsesp_EMS-ESP32
sonar.projectName=EMS-ESP32 sonar.projectName=EMS-ESP32
sonar.projectVersion=3.7.0 sonar.projectVersion=3.7.0
sonar.sources=./src sonar.sources=./src
sonar.cfamily.build-wrapper-output=bw-output # sonar.cfamily.build-wrapper-output=bw-output
sonar.cfamily.compile-commands=compile_commands.json
sonar.sourceEncoding=UTF-8 sonar.sourceEncoding=UTF-8
sonar.host.url=https://sonarcloud.io sonar.host.url=https://sonarcloud.io
# sonar.cfamily.threads=4 # sonar.cfamily.threads=4

View File

@@ -77,6 +77,10 @@
#define EMSESP_DEFAULT_SHOWER_ALERT_TRIGGER 7 #define EMSESP_DEFAULT_SHOWER_ALERT_TRIGGER 7
#endif #endif
#ifndef EMSESP_DEFAULT_SHOWER_MIN_DURATION
#define EMSESP_DEFAULT_SHOWER_MIN_DURATION 120
#endif
#ifndef EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT #ifndef EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT
#define EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT 10 #define EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT 10
#endif #endif

View File

@@ -28,8 +28,9 @@ 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_trigger_ = settings.shower_alert_trigger * 60; // convert from minutes to seconds
shower_alert_coldshot_ = settings.shower_alert_coldshot * 1000; // convert from seconds shower_alert_coldshot_ = settings.shower_alert_coldshot; // in seconds
shower_min_duration_ = settings.shower_min_duration; // in seconds
}); });
Command::add( Command::add(
@@ -60,7 +61,8 @@ void Shower::loop() {
return; return;
} }
uint32_t time_now = uuid::get_uptime(); // uint32_t time_now = uuid::get_uptime(); // in ms
auto time_now = uuid::get_uptime_sec(); // in sec
// if already in cold mode, ignore all this logic until we're out of the cold blast // if already in cold mode, ignore all this logic until we're out of the cold blast
if (!doing_cold_shot_) { if (!doing_cold_shot_) {
@@ -78,7 +80,7 @@ void Shower::loop() {
} else { } else {
// hot water has been on for a while // hot water has been on for a while
// first check to see if hot water has been on long enough to be recognized as a Shower/Bath // first check to see if hot water has been on long enough to be recognized as a Shower/Bath
if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) { if (!shower_state_ && (time_now - timer_start_) > shower_min_duration_) {
set_shower_state(true); set_shower_state(true);
LOG_DEBUG("hot water still running, starting shower timer"); LOG_DEBUG("hot water still running, starting shower timer");
} }
@@ -99,7 +101,7 @@ void Shower::loop() {
// because its unsigned long, can't have negative so check if length is less than OFFSET_TIME // because its unsigned long, can't have negative so check if length is less than OFFSET_TIME
if ((timer_pause_ - timer_start_) > SHOWER_OFFSET_TIME) { if ((timer_pause_ - timer_start_) > SHOWER_OFFSET_TIME) {
duration_ = (timer_pause_ - timer_start_ - SHOWER_OFFSET_TIME); duration_ = (timer_pause_ - timer_start_ - SHOWER_OFFSET_TIME);
if (duration_ > SHOWER_MIN_DURATION) { if (duration_ > shower_min_duration_) {
JsonDocument doc; JsonDocument doc;
// duration in seconds // duration in seconds
@@ -145,7 +147,7 @@ void Shower::shower_alert_start() {
(void)Command::call(EMSdevice::DeviceType::BOILER, "tapactivated", "false", 9); (void)Command::call(EMSdevice::DeviceType::BOILER, "tapactivated", "false", 9);
doing_cold_shot_ = true; doing_cold_shot_ = true;
force_coldshot = false; force_coldshot = false;
alert_timer_start_ = uuid::get_uptime(); // timer starts now alert_timer_start_ = uuid::get_uptime_sec(); // timer starts now
} }
// turn back on the hot water for the shower // turn back on the hot water for the shower

View File

@@ -36,11 +36,8 @@ 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 = 15; // 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_OFFSET_TIME = 5; // 5 seconds grace time, to calibrate actual time under the shower
// static constexpr uint32_t SHOWER_MIN_DURATION = 5000; // for testing in ms. 5 seconds
static constexpr uint32_t SHOWER_OFFSET_TIME = 5000; // in ms. 5 seconds grace time, to calibrate actual time under the shower
void shower_alert_start(); void shower_alert_start();
void shower_alert_stop(); void shower_alert_stop();
@@ -49,15 +46,17 @@ class Shower {
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_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 uint32_t shower_alert_coldshot_; // default 10 seconds for cold water before turning back hot water
uint32_t shower_min_duration_; // default 2 minutes (120 seconds), before recognizing its a shower
uint32_t next_alert_; uint32_t next_alert_;
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_pause_; // ms uint32_t timer_start_; // sec
uint32_t duration_; // ms uint32_t timer_pause_; // sec
uint32_t duration_; // sec
// cold shot // cold shot
uint32_t alert_timer_start_; // ms uint32_t alert_timer_start_; // sec
bool doing_cold_shot_; // true if we've just sent a jolt of cold water bool doing_cold_shot_; // true if we've just sent a jolt of cold water
}; };

View File

@@ -1448,12 +1448,13 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
// Settings // Settings
node = output["Settings"].to<JsonObject>(); node = output["Settings"].to<JsonObject>();
EMSESP::webSettingsService.read([&](WebSettings & settings) { EMSESP::webSettingsService.read([&](WebSettings & settings) {
node["board profile"] = settings.board_profile; node["board profile"] = settings.board_profile;
node["locale"] = settings.locale; node["locale"] = settings.locale;
node["tx mode"] = settings.tx_mode; node["tx mode"] = settings.tx_mode;
node["ems bus id"] = settings.ems_bus_id; node["ems bus id"] = settings.ems_bus_id;
node["shower timer"] = settings.shower_timer; node["shower timer"] = settings.shower_timer;
node["shower alert"] = settings.shower_alert; node["shower alert"] = settings.shower_alert;
node["shpwe_min_duration"] = settings.shower_min_duration; // seconds
if (settings.shower_alert) { if (settings.shower_alert) {
node["shower alert coldshot"] = settings.shower_alert_coldshot; // seconds node["shower alert coldshot"] = settings.shower_alert_coldshot; // seconds
node["shower alert trigger"] = settings.shower_alert_trigger; // minutes node["shower alert trigger"] = settings.shower_alert_trigger; // minutes

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.7.0-dev.14" #define EMSESP_APP_VERSION "3.7.0-dev.15"

View File

@@ -47,6 +47,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
root["shower_alert"] = settings.shower_alert; root["shower_alert"] = settings.shower_alert;
root["shower_alert_coldshot"] = settings.shower_alert_coldshot; root["shower_alert_coldshot"] = settings.shower_alert_coldshot;
root["shower_alert_trigger"] = settings.shower_alert_trigger; root["shower_alert_trigger"] = settings.shower_alert_trigger;
root["shower_min_duration"] = settings.shower_min_duration;
root["rx_gpio"] = settings.rx_gpio; root["rx_gpio"] = settings.rx_gpio;
root["tx_gpio"] = settings.tx_gpio; root["tx_gpio"] = settings.tx_gpio;
root["dallas_gpio"] = settings.dallas_gpio; root["dallas_gpio"] = settings.dallas_gpio;
@@ -237,6 +238,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
prev = settings.shower_alert_trigger; prev = settings.shower_alert_trigger;
settings.shower_alert_trigger = root["shower_alert_trigger"] | EMSESP_DEFAULT_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); check_flag(prev, settings.shower_alert_trigger, ChangeFlags::SHOWER);
prev = settings.shower_min_duration;
settings.shower_min_duration = root["shower_min_duration"] | EMSESP_DEFAULT_SHOWER_MIN_DURATION;
check_flag(prev, settings.shower_min_duration, ChangeFlags::SHOWER);
prev = settings.shower_alert_coldshot; prev = settings.shower_alert_coldshot;
settings.shower_alert_coldshot = root["shower_alert_coldshot"] | EMSESP_DEFAULT_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); check_flag(prev, settings.shower_alert_coldshot, ChangeFlags::SHOWER);

View File

@@ -36,8 +36,9 @@ class WebSettings {
bool boiler_heatingoff; bool boiler_heatingoff;
bool shower_timer; bool shower_timer;
bool shower_alert; bool shower_alert;
uint8_t shower_alert_trigger; uint8_t shower_alert_trigger; // minutes
uint8_t shower_alert_coldshot; uint8_t shower_alert_coldshot; // seconds
uint32_t shower_min_duration; // seconds
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;