diff --git a/.github/workflows/sonar_check.yml b/.github/workflows/sonar_check.yml index fd7f73f3d..105136618 100644 --- a/.github/workflows/sonar_check.yml +++ b/.github/workflows/sonar_check.yml @@ -27,4 +27,4 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | - sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" + sonar-scanner diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 2e0073aec..11b8cd41d 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -37,3 +37,4 @@ - rename DeviceValueTypes, add UINT32 for custom entities - dynamic register dhw circuits for thermostat - 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)] diff --git a/interface/package.json b/interface/package.json index 21d2ac923..666d8e098 100644 --- a/interface/package.json +++ b/interface/package.json @@ -30,7 +30,7 @@ "@mui/material": "^5.15.20", "@table-library/react-table-library": "4.1.7", "@types/lodash-es": "^4.17.12", - "@types/node": "^20.14.5", + "@types/node": "^20.14.6", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", diff --git a/interface/src/project/ApplicationSettings.tsx b/interface/src/project/ApplicationSettings.tsx index f833f1e96..f28dfd6d9 100644 --- a/interface/src/project/ApplicationSettings.tsx +++ b/interface/src/project/ApplicationSettings.tsx @@ -546,6 +546,26 @@ const ApplicationSettings: FC = () => { justifyContent="flex-start" alignItems="flex-start" > + {data.shower_timer && ( + + {LL.SECONDS()} + ) + }} + variant="outlined" + value={numberValue(data.shower_min_duration)} + fullWidth + type="number" + onChange={updateFormValue} + /> + + )} {data.shower_alert && ( <> diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts index c2a28423b..ed3519035 100644 --- a/interface/src/project/types.ts +++ b/interface/src/project/types.ts @@ -12,6 +12,7 @@ export interface Settings { shower_alert: boolean; shower_alert_coldshot: number; shower_alert_trigger: number; + shower_min_duration: number; rx_gpio: number; tx_gpio: number; telnet_enabled: boolean; diff --git a/interface/src/project/validators.ts b/interface/src/project/validators.ts index ab86314a0..c721dca84 100644 --- a/interface/src/project/validators.ts +++ b/interface/src/project/validators.ts @@ -234,6 +234,16 @@ export const createSettingsValidator = (settings: Settings) => { 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 && { shower_alert_trigger: [ { diff --git a/interface/yarn.lock b/interface/yarn.lock index 8b2b946ce..f0ce345b2 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -1760,12 +1760,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^20.14.5": - version: 20.14.5 - resolution: "@types/node@npm:20.14.5" +"@types/node@npm:^20.14.6": + version: 20.14.6 + resolution: "@types/node@npm:20.14.6" dependencies: undici-types: "npm:~5.26.4" - checksum: 10c0/06a8c304b5f7f190d4497807dc67ad09ee7b14ea2996bfdc823553c624698d8cab1ef9d16f8b764f20cb9eb11caa0e832787741e9ef70e1c89d620797ab28436 + checksum: 10c0/22640f0eb2a955872e4529a93be1b719f67b527b80fdab51419756d20e21b5ce0f4ccbee9a3e2ff20e5def647f77baf77b4b0434ff8896791c102165ec0c3e48 languageName: node linkType: hard @@ -1996,7 +1996,7 @@ __metadata: "@trivago/prettier-plugin-sort-imports": "npm:^4.3.0" "@types/babel__core": "npm:^7" "@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-dom": "npm:^18.3.0" "@types/react-router-dom": "npm:^5.3.3" diff --git a/lib_standalone/emsuart_standalone.cpp b/lib_standalone/emsuart_standalone.cpp index 993ecd30b..8e8f93f6f 100644 --- a/lib_standalone/emsuart_standalone.cpp +++ b/lib_standalone/emsuart_standalone.cpp @@ -84,6 +84,4 @@ char * EMSuart::hextoa(char * result, const uint8_t value) { } // namespace emsesp -#pragma GCC diagnostic pop - #endif \ No newline at end of file diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts index e3c3ccb36..5f1ceb9d3 100644 --- a/mock-api/rest_server.ts +++ b/mock-api/rest_server.ts @@ -610,6 +610,7 @@ let settings = { shower_alert: true, shower_alert_trigger: 7, shower_alert_coldshot: 10, + shower_min_duration: 120, rx_gpio: 23, tx_gpio: 5, phy_type: 0, diff --git a/platformio.ini b/platformio.ini index 5018a2588..3262c6ed7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -13,7 +13,7 @@ extra_configs = pio_local.ini [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 ; my_build_flags is set in pio_local.ini diff --git a/scripts/run_sonar.sh b/scripts/run_sonar.sh index 406a8ef37..2dffd1483 100755 --- a/scripts/run_sonar.sh +++ b/scripts/run_sonar.sh @@ -1,7 +1,12 @@ #!/bin/sh # 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` -# 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" make clean @@ -12,5 +17,5 @@ make clean -Dsonar.projectKey=proddy_EMS-ESP32 \ -Dsonar.projectName=EMS-ESP32 \ -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 diff --git a/sonar-project.properties b/sonar-project.properties index 73ece144b..0da8d5ea3 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,8 @@ sonar.projectKey=emsesp_EMS-ESP32 sonar.projectName=EMS-ESP32 sonar.projectVersion=3.7.0 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.host.url=https://sonarcloud.io # sonar.cfamily.threads=4 diff --git a/src/default_settings.h b/src/default_settings.h index 81514e540..490123987 100644 --- a/src/default_settings.h +++ b/src/default_settings.h @@ -77,6 +77,10 @@ #define EMSESP_DEFAULT_SHOWER_ALERT_TRIGGER 7 #endif +#ifndef EMSESP_DEFAULT_SHOWER_MIN_DURATION +#define EMSESP_DEFAULT_SHOWER_MIN_DURATION 120 +#endif + #ifndef EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT #define EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT 10 #endif diff --git a/src/shower.cpp b/src/shower.cpp index 73ff9184e..5c90aa0c1 100644 --- a/src/shower.cpp +++ b/src/shower.cpp @@ -28,8 +28,9 @@ void Shower::start() { EMSESP::webSettingsService.read([&](WebSettings & settings) { shower_timer_ = settings.shower_timer; 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 + shower_alert_trigger_ = settings.shower_alert_trigger * 60; // convert from minutes to seconds + shower_alert_coldshot_ = settings.shower_alert_coldshot; // in seconds + shower_min_duration_ = settings.shower_min_duration; // in seconds }); Command::add( @@ -60,7 +61,8 @@ void Shower::loop() { 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 (!doing_cold_shot_) { @@ -78,7 +80,7 @@ void Shower::loop() { } else { // 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 - if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) { + if (!shower_state_ && (time_now - timer_start_) > shower_min_duration_) { set_shower_state(true); 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 if ((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; // duration in seconds @@ -145,7 +147,7 @@ void Shower::shower_alert_start() { (void)Command::call(EMSdevice::DeviceType::BOILER, "tapactivated", "false", 9); doing_cold_shot_ = true; 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 diff --git a/src/shower.h b/src/shower.h index e16fce391..8d73e16bf 100644 --- a/src/shower.h +++ b/src/shower.h @@ -36,11 +36,8 @@ class Shower { private: 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_MIN_DURATION = 120000; // in ms. 2 minutes, before recognizing its a 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 + 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_OFFSET_TIME = 5; // 5 seconds grace time, to calibrate actual time under the shower void shower_alert_start(); void shower_alert_stop(); @@ -49,15 +46,17 @@ class Shower { 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 + uint32_t shower_min_duration_; // default 2 minutes (120 seconds), before recognizing its a shower uint32_t next_alert_; bool ha_configdone_ = false; // for HA MQTT Discovery bool shower_state_; - uint32_t timer_start_; // ms - uint32_t timer_pause_; // ms - uint32_t duration_; // ms + + uint32_t timer_start_; // sec + uint32_t timer_pause_; // sec + uint32_t duration_; // sec // 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 }; diff --git a/src/system.cpp b/src/system.cpp index db07845bd..46bc76049 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1448,12 +1448,13 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output // Settings node = output["Settings"].to(); EMSESP::webSettingsService.read([&](WebSettings & settings) { - node["board profile"] = settings.board_profile; - node["locale"] = settings.locale; - node["tx mode"] = settings.tx_mode; - node["ems bus id"] = settings.ems_bus_id; - node["shower timer"] = settings.shower_timer; - node["shower alert"] = settings.shower_alert; + node["board profile"] = settings.board_profile; + node["locale"] = settings.locale; + node["tx mode"] = settings.tx_mode; + node["ems bus id"] = settings.ems_bus_id; + node["shower timer"] = settings.shower_timer; + node["shower alert"] = settings.shower_alert; + node["shpwe_min_duration"] = settings.shower_min_duration; // seconds if (settings.shower_alert) { node["shower alert coldshot"] = settings.shower_alert_coldshot; // seconds node["shower alert trigger"] = settings.shower_alert_trigger; // minutes diff --git a/src/version.h b/src/version.h index 18da8a4a6..00c9d1e6c 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.0-dev.14" +#define EMSESP_APP_VERSION "3.7.0-dev.15" diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index e3805d037..ee12c5f56 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -47,6 +47,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) { root["shower_alert"] = settings.shower_alert; root["shower_alert_coldshot"] = settings.shower_alert_coldshot; root["shower_alert_trigger"] = settings.shower_alert_trigger; + root["shower_min_duration"] = settings.shower_min_duration; root["rx_gpio"] = settings.rx_gpio; root["tx_gpio"] = settings.tx_gpio; root["dallas_gpio"] = settings.dallas_gpio; @@ -237,6 +238,9 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) { 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_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; settings.shower_alert_coldshot = root["shower_alert_coldshot"] | EMSESP_DEFAULT_SHOWER_ALERT_COLDSHOT; check_flag(prev, settings.shower_alert_coldshot, ChangeFlags::SHOWER); diff --git a/src/web/WebSettingsService.h b/src/web/WebSettingsService.h index d820f1ce2..72e95c0ea 100644 --- a/src/web/WebSettingsService.h +++ b/src/web/WebSettingsService.h @@ -36,8 +36,9 @@ class WebSettings { bool boiler_heatingoff; bool shower_timer; bool shower_alert; - uint8_t shower_alert_trigger; - uint8_t shower_alert_coldshot; + uint8_t shower_alert_trigger; // minutes + uint8_t shower_alert_coldshot; // seconds + uint32_t shower_min_duration; // seconds bool syslog_enabled; int8_t syslog_level; // uuid::log::Level uint32_t syslog_mark_interval;