From b128efecd329a4f3cefadceeccd8aae4151799aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 29 Jun 2024 22:21:19 +0200 Subject: [PATCH 1/7] Suche dny, rucni rezim. Netestovano --- CMakeLists.txt | 2 + src/app_config.c | 15 +++- src/app_config.h | 29 ++++---- src/app_io.c | 20 ++++-- src/app_io.h | 2 + src/ds_rtc.c | 9 ++- src/ds_rtc.h | 1 + src/screens/app_gui.c | 78 +++++++++++++++++++-- src/screens/app_gui.h | 11 +++ src/screens/gui_event.h | 2 + src/screens/screen_cyklus.c | 6 +- src/screens/screen_delka_zalivky.c | 4 +- src/screens/screen_home.c | 21 ++++-- src/screens/screen_kompenzace_tlaku.c | 4 +- src/screens/screen_manual_control.c | 68 ++++++++++++++++++ src/screens/screen_moisture_calib.c | 4 +- src/screens/screen_program_edit.c | 4 +- src/screens/screen_program_prehled.c | 4 +- src/screens/screen_set_moisture_threshold.c | 4 +- src/screens/screen_set_time.c | 4 +- src/screens/screen_settings.c | 18 +++-- src/screens/screen_suche_dny.c | 44 ++++++++++++ 22 files changed, 298 insertions(+), 56 deletions(-) create mode 100644 src/screens/screen_manual_control.c create mode 100644 src/screens/screen_suche_dny.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 192da2b..ceb60bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,8 @@ add_executable(zavlaha src/screens/screen_kompenzace_tlaku.c src/screens/screen_program_prehled.c src/screens/screen_program_edit.c + src/screens/screen_suche_dny.c + src/screens/screen_manual_control.c src/app_io.c src/app_config.c) diff --git a/src/app_config.c b/src/app_config.c index c14d567..2d52d22 100644 --- a/src/app_config.c +++ b/src/app_config.c @@ -9,10 +9,10 @@ #define APPCONFIG_EE_BASE_ADDR 0 -// TODO sensible defaults, loading and saving to/from EE struct AppConfig app_config; static const struct AppConfig DEFAULTS = { + .magic_version = APPCONFIG_MAGIC1, .circuit_base_time_s = 300, // for a test .circuit_time_percent = {100, 100, 100, 100}, // for a test .scheduler_enable = true, @@ -26,6 +26,8 @@ static const struct AppConfig DEFAULTS = { .moisture_dry = 2800, .moisture_wet = 1600, .moisture_threshold_percent = 70, + .magic2 = APPCONFIG_MAGIC2, + .scheduler_dry_days = 0, }; static void load_fallback_config() { @@ -36,7 +38,7 @@ static void load_fallback_config() { void appconfig_load() { uint8_t magic = 0; - if (0 > ee_read(APPCONFIG_EE_BASE_ADDR, &magic, 1) || magic != APPCONFIG_VERSION) { + if (0 > ee_read(APPCONFIG_EE_BASE_ADDR, &magic, 1) || magic != APPCONFIG_MAGIC1) { printf("Couldn't read EE to check magic!\r\n"); load_fallback_config(); return; @@ -45,6 +47,12 @@ void appconfig_load() if (0 > ee_read(APPCONFIG_EE_BASE_ADDR, (uint8_t *) &app_config, APPCONFIG_SIZE)) { printf("Couldn't read EE to load config!\r\n"); load_fallback_config(); + return; + } + + if (app_config.magic2 != APPCONFIG_MAGIC2) { + app_config.magic2 = APPCONFIG_MAGIC2; + app_config.scheduler_dry_days = 0; } } @@ -53,7 +61,8 @@ void appconfig_save() // printf("PERSISTENCE DISABLED - NOT SAVING\r\n"); // return; // FIXME - when all GUIs are finished, add persistence // whatever, just write everything - app_config.magic_version = APPCONFIG_VERSION; + app_config.magic_version = APPCONFIG_MAGIC1; + app_config.magic2 = APPCONFIG_MAGIC2; if (0 > ee_write(APPCONFIG_EE_BASE_ADDR, (const uint8_t *) &app_config, APPCONFIG_SIZE)) { printf("Couldn't write EE!"); } diff --git a/src/app_config.h b/src/app_config.h index 8767bd9..65be91b 100644 --- a/src/app_config.h +++ b/src/app_config.h @@ -13,26 +13,29 @@ #define MENU_AUTOEXIT_TIME_S 120 struct __attribute__((packed)) ScheduleTime { - bool enable; - uint8_t h; - uint8_t m; + bool enable; /// True if the schedule time is enabled + uint8_t h; /// Hour + uint8_t m; /// Minute }; struct __attribute__((packed)) AppConfig { - uint8_t magic_version; - uint16_t circuit_base_time_s; - uint16_t circuit_time_percent[CIRCUIT_COUNT]; // 0% can be used to disable a branch - bool scheduler_enable; - struct ScheduleTime schedules[SCHEDULE_COUNT]; - bool moisture_enable; - uint16_t moisture_dry; - uint16_t moisture_wet; - uint8_t moisture_threshold_percent; + uint8_t magic_version; /// Magic (byte reserved) + uint16_t circuit_base_time_s; /// Base time for each branch (scaled by percent) + uint16_t circuit_time_percent[CIRCUIT_COUNT]; /// Relative time of each branch 0% can be used to disable a branch + bool scheduler_enable; /// Enable automatic watering + struct ScheduleTime schedules[SCHEDULE_COUNT]; /// Scheduled times in a day + bool moisture_enable; /// Enable blocking watering by high soil humidity + uint16_t moisture_dry; /// Saved humidity value as 0% + uint16_t moisture_wet; /// Saved humidity value as 100% + uint8_t moisture_threshold_percent; /// % of soil humidity that deactivates watering + uint8_t magic2; + uint8_t scheduler_dry_days; /// Days to skip between watering }; #define APPCONFIG_SIZE sizeof(struct AppConfig) -#define APPCONFIG_VERSION 0b11100001 +#define APPCONFIG_MAGIC1 0b11100001 +#define APPCONFIG_MAGIC2 0b00111001 extern struct AppConfig app_config; diff --git a/src/app_io.c b/src/app_io.c index 19d0ee6..6587610 100644 --- a/src/app_io.c +++ b/src/app_io.c @@ -9,21 +9,29 @@ #include "pinout.h" #include "app_config.h" - void set_relays(bool one, bool two, bool three, bool four) { gpio_put(PIN_RE1, one); gpio_put(PIN_RE2, two); gpio_put(PIN_RE3, three); - gpio_put(PIN_RE1, four); + gpio_put(PIN_RE4, four); } void open_valve(uint8_t num) { - gpio_put(PIN_RE1, num == 1); - gpio_put(PIN_RE2, num == 2); - gpio_put(PIN_RE3, num == 3); - gpio_put(PIN_RE4, num == 4); + set_relays(num == 1, num == 2, num == 3, num == 4); +} + +void set_one_relay(uint8_t num, bool on) +{ + if (num < 1 || num > 4) { + return; + } + + if (num == 1) { gpio_put(PIN_RE1, on); } + if (num == 2) { gpio_put(PIN_RE2, on); } + if (num == 3) { gpio_put(PIN_RE3, on); } + if (num == 4) { gpio_put(PIN_RE4, on); } } uint16_t moisture_read() diff --git a/src/app_io.h b/src/app_io.h index 90bb13e..93b6256 100644 --- a/src/app_io.h +++ b/src/app_io.h @@ -13,6 +13,8 @@ void set_relays(bool one, bool two, bool three, bool four); /** Open valve, 1,2,3,4; 0=close all */ void open_valve(uint8_t num); +void set_one_relay(uint8_t num, bool on); + uint16_t moisture_read(); uint16_t moisture_convert(uint16_t moisture); diff --git a/src/ds_rtc.c b/src/ds_rtc.c index 81bf2d9..9f9b208 100644 --- a/src/ds_rtc.c +++ b/src/ds_rtc.c @@ -1,5 +1,5 @@ /** - * TODO file description + * Functions to access the RTC (DS3231) */ #include @@ -35,11 +35,13 @@ static int rtc_write(uint8_t start, const uint8_t *data, size_t len) { int rtc_get_time(struct rtc_time *dest) { int rv; - uint8_t buf[3]; - TRY(rtc_read(0x00, buf, 3)); + uint8_t buf[4]; + TRY(rtc_read(0x00, buf, 4)); dest->second = (buf[0] & 15) + (buf[0] >> 4) * 10; dest->minute = (buf[1] & 15) + (buf[1] >> 4) * 10; + dest->weekday = buf[3] & 7; + if (dest->weekday > 0) dest->weekday -= 1; // Normalize to 0-6, with failsafe in case we got zero, should not happen. if (buf[2] & 0x40) { // 12h time? @@ -60,5 +62,6 @@ int rtc_set_time(const struct rtc_time *time) { buf[2] = (time->hour % 10) + ((time->hour / 10) << 4); TRY(rtc_write(0x00, buf, 3)); + // just let the week counter go on its own - we only care about it incrementing return 0; } diff --git a/src/ds_rtc.h b/src/ds_rtc.h index 18eb5b9..2eee507 100644 --- a/src/ds_rtc.h +++ b/src/ds_rtc.h @@ -10,6 +10,7 @@ struct rtc_time { uint8_t hour; uint8_t minute; uint8_t second; + uint8_t weekday; // 0-6, We use this as a counter for dry days }; int rtc_get_time(struct rtc_time *dest); diff --git a/src/screens/app_gui.c b/src/screens/app_gui.c index 88bfeed..9ac7c47 100644 --- a/src/screens/app_gui.c +++ b/src/screens/app_gui.c @@ -28,12 +28,53 @@ static void draw_common_overlay(); //stratch string buffer char sbuf[100]; -void gui_read_moisture() { +void gui_read_moisture() +{ s_app.moisture_pt = moisture_convert(s_app.moisture_raw = moisture_read()); } -static void read_time_and_moisture() { +/** + * Get days remaining to next watering day + * + * @return + */ +uint8_t days_to_next_watering() +{ + if (app_config.scheduler_dry_days == 0) { + return 0; + } + + uint8_t wd = s_app.rtc_time.weekday; + uint8_t last_wd = s_app.last_watering_day_wd; + uint8_t normalized_next = (last_wd + 1 + app_config.scheduler_dry_days) % 7; + if (wd > normalized_next) { + normalized_next += 7; + } + return normalized_next - wd; +} + +static void read_time_and_moisture() +{ + uint8_t prev_wd = s_app.rtc_time.weekday; rtc_get_time(&s_app.rtc_time); // now is a good time to update timestamp - we could just increment it though + + // decide if today is a watering day + if (app_config.scheduler_dry_days == 0) { + s_app.today_is_watering_day = true; + s_app.last_watering_day_wd = s_app.rtc_time.weekday; + } else { + uint8_t cur_wd = s_app.rtc_time.weekday; + if (cur_wd != prev_wd) { + s_app.today_is_watering_day = false; + uint8_t now_normalized = cur_wd + (cur_wd < s_app.last_watering_day_wd ? 7 : 0); + uint8_t elapsed_days = now_normalized - s_app.last_watering_day_wd; + if (elapsed_days >= app_config.scheduler_dry_days) { + s_app.today_is_watering_day = true; + s_app.last_watering_day_wd = cur_wd; + } + } + } + gui_read_moisture(); } @@ -44,11 +85,19 @@ void gui_init() read_time_and_moisture(); + s_app.today_is_watering_day = true; + s_app.last_watering_day_wd = s_app.rtc_time.weekday; + LcdBuffer_Init(&lcd, CGROM_A00, CGRAM_CZ); } static bool blink_state = 0; +bool is_valve_control_screen() +{ + return s_app.screen == screen_cyklus || s_app.screen == screen_manual_control; +} + void gui_loop_iter(GuiEvent message) { uint32_t tickNow = timestamp_ms(); @@ -56,7 +105,7 @@ void gui_loop_iter(GuiEvent message) // Time program logic - since this runs very often, we are guaranteed not to miss a cycle - unless there is a power outage // exactly in the scheduled watering time - if (s_app.screen != screen_cyklus && app_config.scheduler_enable) { + if (!is_valve_control_screen() && app_config.scheduler_enable && (s_app.today_is_watering_day || app_config.scheduler_dry_days == 0)) { // if dry days=0, is_wd should always be true, but making sure here if (s_app.cycle_time_checking) { if (s_app.rtc_time.hour != s_app.last_cycle_time.hour || s_app.rtc_time.minute != s_app.last_cycle_time.minute) { @@ -88,7 +137,7 @@ void gui_loop_iter(GuiEvent message) } // screen auto-close - if (s_app.screen != screen_home && s_app.screen != screen_cyklus) { + if (s_app.screen != screen_home && !is_valve_control_screen()) { if ((tickNow - s_app.screen_open_time) >= (MENU_AUTOEXIT_TIME_S * 1000)) { switch_screen(screen_home, true); } @@ -154,13 +203,17 @@ void gui_loop_iter(GuiEvent message) /** Switch to a different screen handler. * If "init" is true, immediately call it with the init event. */ -void switch_screen(screen_t pScreen, bool init) +static void switch_screen_ex(screen_t pScreen, bool init, bool deinit_current) { if (s_app.screen == pScreen) { // already, no op return; } + if (s_app.screen && deinit_current) { + s_app.screen(GUI_EVENT_SCREEN_DEINIT); + } + s_app.screen_open_time = timestamp_ms(); s_app.screen = pScreen; @@ -178,6 +231,21 @@ void switch_screen(screen_t pScreen, bool init) } } +void switch_screen(screen_t pScreen, bool init) +{ + switch_screen_ex(pScreen, init, true); +} + +void switch_to_subscreen(screen_t pScreen) +{ + switch_screen_ex(pScreen, true, false); +} + +void switch_to_parent_screen(screen_t pScreen) +{ + switch_screen_ex(pScreen, false, true); +} + /** Draw GUI common to all screens */ static void draw_common_overlay() { diff --git a/src/screens/app_gui.h b/src/screens/app_gui.h index 930dff4..08181f2 100644 --- a/src/screens/app_gui.h +++ b/src/screens/app_gui.h @@ -45,6 +45,9 @@ void gui_init(); */ void switch_screen(screen_t pScreen, bool init); +void switch_to_subscreen(screen_t pScreen); +void switch_to_parent_screen(screen_t pScreen); + void request_paint(); // prototypes for screen handlers @@ -59,6 +62,10 @@ void screen_moisture_calib(GuiEvent event); void screen_delka_zalivky(GuiEvent event); void screen_kompenzace_tlaku(GuiEvent event); void screen_program_prehled(GuiEvent event); +void screen_suche_dny(GuiEvent event); +void screen_manual_control(GuiEvent event); + +uint8_t days_to_next_watering(); extern int pgm_edit_slot; void screen_program_edit(GuiEvent event); @@ -66,6 +73,7 @@ void screen_program_edit(GuiEvent event); void gui_read_moisture(); +// This is actually the global app state! struct State { struct rtc_time rtc_time; uint16_t moisture_raw; @@ -85,6 +93,9 @@ struct State { uint32_t screen_open_time; + + bool today_is_watering_day; + uint8_t last_watering_day_wd; }; extern struct State s_app; diff --git a/src/screens/gui_event.h b/src/screens/gui_event.h index 0e0a5fc..862f7d7 100644 --- a/src/screens/gui_event.h +++ b/src/screens/gui_event.h @@ -13,6 +13,8 @@ typedef enum GuiEvent { GUI_EVENT_PAINT, /// Used as the argument when initing a screen GUI_EVENT_SCREEN_INIT, + /// Screen is about to close (this will NOT be called for middle pages when auto-closing a multi-level hierarchy!) + GUI_EVENT_SCREEN_DEINIT, /// Time tick, used to carry timing to the screen functions. /// This tick has 10ms interval GUI_EVENT_SCREEN_TICK_10MS, diff --git a/src/screens/screen_cyklus.c b/src/screens/screen_cyklus.c index 2f06d82..c28b5d9 100644 --- a/src/screens/screen_cyklus.c +++ b/src/screens/screen_cyklus.c @@ -82,6 +82,10 @@ void screen_cyklus(GuiEvent event) case GUI_EVENT_KEY_D: end_cycle(); switch_screen(screen_home, true); - return; + break; + + case GUI_EVENT_SCREEN_DEINIT: + open_valve(0); // close all - this should not be needed here, this screen does not autoclose. + break; } } diff --git a/src/screens/screen_delka_zalivky.c b/src/screens/screen_delka_zalivky.c index f2026b0..f595f38 100644 --- a/src/screens/screen_delka_zalivky.c +++ b/src/screens/screen_delka_zalivky.c @@ -38,12 +38,12 @@ void screen_delka_zalivky(GuiEvent event) case GUI_EVENT_KEY_A: // Confirm if (cursor > 0) { settings_scratch.circuit_base_time_s = value; - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); } break; case GUI_EVENT_KEY_D: // CANCEL - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); break; default: diff --git a/src/screens/screen_home.c b/src/screens/screen_home.c index 2227750..2830d25 100644 --- a/src/screens/screen_home.c +++ b/src/screens/screen_home.c @@ -49,6 +49,7 @@ void screen_home(GuiEvent event) } else { int found = -1; int first = -1; + bool wrapped_around = false; uint16_t m_now = s_app.rtc_time.hour * 60 + s_app.rtc_time.minute; for (int i = 0; i < SCHEDULE_COUNT; i++) { if (!app_config.schedules[i].enable) { @@ -68,27 +69,37 @@ void screen_home(GuiEvent event) if (found == -1) { found = first; + wrapped_around = true; } if (found == -1) { - LcdBuffer_Write(&lcd, 1, 0, "Program nenastaven!"); + LcdBuffer_Write(&lcd, 1, 0, "Program nenastaven! "); } else { - snprintf(sbuf, sbuf_len, "Další závlaha %d:%02d ", - app_config.schedules[found].h, app_config.schedules[found].m); + uint8_t days = days_to_next_watering(); + if (days > 0 && (!s_app.today_is_watering_day || wrapped_around)) { + snprintf(sbuf, sbuf_len, "Další závlaha za %d d", days); + } else { + snprintf(sbuf, sbuf_len, "Další závlaha %d:%02d ", + app_config.schedules[found].h, app_config.schedules[found].m); + } LcdBuffer_Write(&lcd, 1, 0, sbuf); } } LcdBuffer_Write(&lcd, 2, 0, "🅰Spustit cyklus"); - LcdBuffer_Write(&lcd, 3, 0, "🅱Nastavení"); + LcdBuffer_Write(&lcd, 3, 0, "🅱Nastavení 🅳Test"); break; case GUI_EVENT_KEY_A: - switch_screen(screen_cyklus, true); // fake cycle + switch_screen(screen_cyklus, true); // manually started cycle break; case GUI_EVENT_KEY_B: switch_screen(screen_settings, true); break; + + case GUI_EVENT_KEY_D: + switch_screen(screen_manual_control, true); + break; } } diff --git a/src/screens/screen_kompenzace_tlaku.c b/src/screens/screen_kompenzace_tlaku.c index 08775a6..989bce4 100644 --- a/src/screens/screen_kompenzace_tlaku.c +++ b/src/screens/screen_kompenzace_tlaku.c @@ -46,11 +46,11 @@ void screen_kompenzace_tlaku(GuiEvent event) case GUI_EVENT_KEY_A: // Confirm memcpy(settings_scratch.circuit_time_percent, ratios, sizeof(settings_scratch.circuit_time_percent)); - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); break; case GUI_EVENT_KEY_D: // CANCEL - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); break; case GUI_EVENT_KEY_1: diff --git a/src/screens/screen_manual_control.c b/src/screens/screen_manual_control.c new file mode 100644 index 0000000..97acf85 --- /dev/null +++ b/src/screens/screen_manual_control.c @@ -0,0 +1,68 @@ +#include +#include "app_gui.h" +#include "gui_event.h" +#include "app_io.h" +#include "lcd.h" + +static bool valve1, valve2, valve3, valve4; + +void screen_manual_control(GuiEvent event) +{ + switch (event) { + case GUI_EVENT_SCREEN_INIT: + open_valve(0); // make sure all are closed + valve1 = valve2 = valve3 = valve4 = false; + break; + + case GUI_EVENT_PAINT: + LcdBuffer_Write(&lcd, 0, 0, "== MANUÁLNÍ REŽIM =="); + LcdBuffer_Write(&lcd, 1, 0, "1-4 ventil,0 vyp.vše"); + + LcdBuffer_SetCursor(&lcd, 2, 0, CURSOR_BOTH); + + snprintf(sbuf, sbuf_len, " %s %s %s %s ", + valve1 ? "█1█" : " 1 ", + valve2 ? "█2█" : " 2 ", + valve3 ? "█3█" : " 3 ", + valve4 ? "█4█" : " 4 "); + LcdBuffer_Write(&lcd, 2, 0, sbuf); + + LcdBuffer_Write(&lcd, 3, 0, "🅳Konec"); + break; + + case GUI_EVENT_KEY_D: // CANCEL + open_valve(0); + switch_screen(screen_home, true); + break; + + case GUI_EVENT_KEY_0: + valve1 = valve2 = valve3 = valve4 = false; + open_valve(0); + request_paint(); + break; + + case GUI_EVENT_KEY_1: + valve1 = !valve1; + set_one_relay(1, valve1); + break; + + case GUI_EVENT_KEY_2: + valve2 = !valve2; + set_one_relay(2, valve2); + break; + + case GUI_EVENT_KEY_3: + valve3 = !valve3; + set_one_relay(3, valve3); + break; + + case GUI_EVENT_KEY_4: + valve4 = !valve4; + set_one_relay(4, valve4); + break; + + case GUI_EVENT_SCREEN_DEINIT: + open_valve(0); // close all + break; + } +} diff --git a/src/screens/screen_moisture_calib.c b/src/screens/screen_moisture_calib.c index c3e3bc2..0cb6f92 100644 --- a/src/screens/screen_moisture_calib.c +++ b/src/screens/screen_moisture_calib.c @@ -42,12 +42,12 @@ void screen_moisture_calib(GuiEvent event) } else { settings_scratch.moisture_dry = sample_dry; settings_scratch.moisture_wet = s_app.moisture_raw; - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); } break; case GUI_EVENT_KEY_D: // CANCEL - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); break; } } diff --git a/src/screens/screen_program_edit.c b/src/screens/screen_program_edit.c index 8ca8f27..c297cd2 100644 --- a/src/screens/screen_program_edit.c +++ b/src/screens/screen_program_edit.c @@ -42,7 +42,7 @@ void screen_program_edit(GuiEvent event) case GUI_EVENT_KEY_A: // Confirm if (!time.enable || cursor == 4) { memcpy(&settings_scratch.schedules[pgm_edit_slot], &time, sizeof(time)); - switch_screen(screen_program_prehled, false); + switch_to_parent_screen(screen_program_prehled); } break; @@ -54,7 +54,7 @@ void screen_program_edit(GuiEvent event) break; case GUI_EVENT_KEY_D: // CANCEL - switch_screen(screen_program_prehled, false); + switch_to_parent_screen(screen_program_prehled); break; default: diff --git a/src/screens/screen_program_prehled.c b/src/screens/screen_program_prehled.c index 99d3836..760f686 100644 --- a/src/screens/screen_program_prehled.c +++ b/src/screens/screen_program_prehled.c @@ -44,7 +44,7 @@ void screen_program_prehled(GuiEvent event) break; case GUI_EVENT_KEY_D: // CANCEL - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); break; case GUI_EVENT_KEY_1: @@ -52,7 +52,7 @@ void screen_program_prehled(GuiEvent event) case GUI_EVENT_KEY_3: case GUI_EVENT_KEY_4: pgm_edit_slot = event - '1'; // 0-3 - switch_screen(screen_program_edit, true); + switch_to_subscreen(screen_program_edit); break; } } diff --git a/src/screens/screen_set_moisture_threshold.c b/src/screens/screen_set_moisture_threshold.c index 5ba02ba..c15c8bb 100644 --- a/src/screens/screen_set_moisture_threshold.c +++ b/src/screens/screen_set_moisture_threshold.c @@ -37,12 +37,12 @@ void screen_set_moisture_threshold(GuiEvent event) case GUI_EVENT_KEY_A: // Confirm if (cursor > 0) { settings_scratch.moisture_threshold_percent = threshold; - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); } break; case GUI_EVENT_KEY_D: // CANCEL - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); break; default: diff --git a/src/screens/screen_set_time.c b/src/screens/screen_set_time.c index 455f0f8..c1cc084 100644 --- a/src/screens/screen_set_time.c +++ b/src/screens/screen_set_time.c @@ -32,12 +32,12 @@ void screen_set_time(GuiEvent event) case GUI_EVENT_KEY_A: // Confirm if (cursor == 4) { rtc_set_time(&time); - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); } break; case GUI_EVENT_KEY_D: // CANCEL - switch_screen(screen_settings, false); + switch_to_parent_screen(screen_settings); break; default: diff --git a/src/screens/screen_settings.c b/src/screens/screen_settings.c index 13615e1..182a7b8 100644 --- a/src/screens/screen_settings.c +++ b/src/screens/screen_settings.c @@ -43,6 +43,8 @@ void screen_settings(GuiEvent event) case 2: LcdBuffer_Write(&lcd, 0, 0, "1. Délka zálivky"); LcdBuffer_Write(&lcd, 1, 0, "2. Kompenzace tlaku"); + snprintf(sbuf, sbuf_len, "3. Suché dny (%d)", settings_scratch.scheduler_dry_days); + LcdBuffer_Write(&lcd, 2, 0, sbuf); break; case 3: @@ -96,11 +98,11 @@ void screen_settings(GuiEvent event) break; case GUI_EVENT_KEY_2: // Upravit program - switch_screen(screen_program_prehled, true); + switch_to_subscreen(screen_program_prehled); break; case GUI_EVENT_KEY_3: // Nastavit cas - switch_screen(screen_set_time, true); + switch_to_subscreen(screen_set_time); break; } break; @@ -108,11 +110,15 @@ void screen_settings(GuiEvent event) case 2: switch (event) { case GUI_EVENT_KEY_1: // Délka zálivky - switch_screen(screen_delka_zalivky, true); + switch_to_subscreen(screen_delka_zalivky); break; case GUI_EVENT_KEY_2: // Kompenzace tlaku - switch_screen(screen_kompenzace_tlaku, true); + switch_to_subscreen(screen_kompenzace_tlaku); + break; + + case GUI_EVENT_KEY_3: // Nastavit suche dny + switch_to_subscreen(screen_suche_dny); break; } break; @@ -125,11 +131,11 @@ void screen_settings(GuiEvent event) break; case GUI_EVENT_KEY_2: // Kalibrace vlhkomeru - switch_screen(screen_moisture_calib, true); + switch_to_subscreen(screen_moisture_calib); break; case GUI_EVENT_KEY_3: // Nastavit prah - switch_screen(screen_set_moisture_threshold, true); + switch_to_subscreen(screen_set_moisture_threshold); break; } break; diff --git a/src/screens/screen_suche_dny.c b/src/screens/screen_suche_dny.c new file mode 100644 index 0000000..7d869a9 --- /dev/null +++ b/src/screens/screen_suche_dny.c @@ -0,0 +1,44 @@ +#include +#include "app_gui.h" +#include "gui_event.h" +#include "app_io.h" +#include "lcd.h" +#include "app_config.h" + +static int value; + +void screen_suche_dny(GuiEvent event) +{ + switch (event) { + case GUI_EVENT_SCREEN_INIT: + value = app_config.scheduler_dry_days; + break; + + case GUI_EVENT_PAINT: + LcdBuffer_Write(&lcd, 0, 0, "Vynechat dny mezi"); + LcdBuffer_Write(&lcd, 1, 0, "auto. zálivkou (0-5)"); + + LcdBuffer_SetCursor(&lcd, 2, 0, CURSOR_BOTH); + + snprintf(sbuf, sbuf_len, "%d d", value); + LcdBuffer_Write(&lcd, 2, 0, sbuf); + + LcdBuffer_Write(&lcd, 3, 0, "🅳Zrušit 🅰OK"); + break; + + case GUI_EVENT_KEY_A: // Confirm + settings_scratch.scheduler_dry_days = value; + switch_to_parent_screen(screen_settings); + break; + + case GUI_EVENT_KEY_D: // CANCEL + switch_to_parent_screen(screen_settings); + break; + + default: + if (event >= '0' && event <= '5') { + value = (uint8_t) (event - '0'); + request_paint(); + } + } +} From 7ab451e702e59eb3ccc7204883dddbb296f83c91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 29 Jun 2024 23:01:18 +0200 Subject: [PATCH 2/7] readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..0511efb --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ + +kompilovano s SDK ver 3352ccf5de3a704e74355f72aa61143fb36cfec9 + From 73e7f6520b81f272f698b1efb2148b0de91a2b34 Mon Sep 17 00:00:00 2001 From: ondra Date: Sun, 30 Jun 2024 14:28:28 +0200 Subject: [PATCH 3/7] fix manual control screen not refreshing, hide cursor --- src/screens/screen_manual_control.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/screens/screen_manual_control.c b/src/screens/screen_manual_control.c index 97acf85..e2587bb 100644 --- a/src/screens/screen_manual_control.c +++ b/src/screens/screen_manual_control.c @@ -18,7 +18,7 @@ void screen_manual_control(GuiEvent event) LcdBuffer_Write(&lcd, 0, 0, "== MANUÁLNÍ REŽIM =="); LcdBuffer_Write(&lcd, 1, 0, "1-4 ventil,0 vyp.vše"); - LcdBuffer_SetCursor(&lcd, 2, 0, CURSOR_BOTH); + //LcdBuffer_SetCursor(&lcd, 2, 0, CURSOR_BOTH); snprintf(sbuf, sbuf_len, " %s %s %s %s ", valve1 ? "█1█" : " 1 ", @@ -44,21 +44,25 @@ void screen_manual_control(GuiEvent event) case GUI_EVENT_KEY_1: valve1 = !valve1; set_one_relay(1, valve1); + request_paint(); break; case GUI_EVENT_KEY_2: valve2 = !valve2; set_one_relay(2, valve2); + request_paint(); break; case GUI_EVENT_KEY_3: valve3 = !valve3; set_one_relay(3, valve3); + request_paint(); break; case GUI_EVENT_KEY_4: valve4 = !valve4; set_one_relay(4, valve4); + request_paint(); break; case GUI_EVENT_SCREEN_DEINIT: From 3821e04bd9011f66cb1326f5a4c9da1550a45a94 Mon Sep 17 00:00:00 2001 From: ondra Date: Sun, 30 Jun 2024 16:10:19 +0200 Subject: [PATCH 4/7] fix variable shown when opening dryday page --- src/screens/screen_suche_dny.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/screen_suche_dny.c b/src/screens/screen_suche_dny.c index 7d869a9..0d682cb 100644 --- a/src/screens/screen_suche_dny.c +++ b/src/screens/screen_suche_dny.c @@ -11,7 +11,7 @@ void screen_suche_dny(GuiEvent event) { switch (event) { case GUI_EVENT_SCREEN_INIT: - value = app_config.scheduler_dry_days; + value = settings_scratch.scheduler_dry_days; break; case GUI_EVENT_PAINT: From 76b2da8ed358f26d9beb6a3fe887c5a84d22b2e3 Mon Sep 17 00:00:00 2001 From: ondra Date: Sun, 30 Jun 2024 16:26:39 +0200 Subject: [PATCH 5/7] blbuvzdor --- src/screens/screen_manual_control.c | 40 ++++++++++++----------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/screens/screen_manual_control.c b/src/screens/screen_manual_control.c index e2587bb..5478864 100644 --- a/src/screens/screen_manual_control.c +++ b/src/screens/screen_manual_control.c @@ -4,14 +4,15 @@ #include "app_io.h" #include "lcd.h" -static bool valve1, valve2, valve3, valve4; +static int cur_valve = 0; void screen_manual_control(GuiEvent event) { + int num = 0; switch (event) { case GUI_EVENT_SCREEN_INIT: open_valve(0); // make sure all are closed - valve1 = valve2 = valve3 = valve4 = false; + cur_valve = 0; break; case GUI_EVENT_PAINT: @@ -21,10 +22,10 @@ void screen_manual_control(GuiEvent event) //LcdBuffer_SetCursor(&lcd, 2, 0, CURSOR_BOTH); snprintf(sbuf, sbuf_len, " %s %s %s %s ", - valve1 ? "█1█" : " 1 ", - valve2 ? "█2█" : " 2 ", - valve3 ? "█3█" : " 3 ", - valve4 ? "█4█" : " 4 "); + (cur_valve == 1) ? "█1█" : " 1 ", + (cur_valve == 2) ? "█2█" : " 2 ", + (cur_valve == 3) ? "█3█" : " 3 ", + (cur_valve == 4) ? "█4█" : " 4 "); LcdBuffer_Write(&lcd, 2, 0, sbuf); LcdBuffer_Write(&lcd, 3, 0, "🅳Konec"); @@ -36,32 +37,23 @@ void screen_manual_control(GuiEvent event) break; case GUI_EVENT_KEY_0: - valve1 = valve2 = valve3 = valve4 = false; + cur_valve = 0; open_valve(0); request_paint(); break; case GUI_EVENT_KEY_1: - valve1 = !valve1; - set_one_relay(1, valve1); - request_paint(); - break; - case GUI_EVENT_KEY_2: - valve2 = !valve2; - set_one_relay(2, valve2); - request_paint(); - break; - case GUI_EVENT_KEY_3: - valve3 = !valve3; - set_one_relay(3, valve3); - request_paint(); - break; - case GUI_EVENT_KEY_4: - valve4 = !valve4; - set_one_relay(4, valve4); + num = (int) (event - '0'); + if (cur_valve == num) { + cur_valve = 0; + open_valve(0); + } else { + cur_valve = num; + open_valve(num); + } request_paint(); break; From e58dafad2bbdaa6cc4be256227b92f88c6c81796 Mon Sep 17 00:00:00 2001 From: ondra Date: Sun, 30 Jun 2024 16:51:06 +0200 Subject: [PATCH 6/7] blbuvzdor 2 - exit manual mode after 1 hour --- src/screens/app_gui.c | 8 ++++++++ src/screens/app_gui.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/screens/app_gui.c b/src/screens/app_gui.c index 9ac7c47..910591b 100644 --- a/src/screens/app_gui.c +++ b/src/screens/app_gui.c @@ -65,6 +65,7 @@ static void read_time_and_moisture() } else { uint8_t cur_wd = s_app.rtc_time.weekday; if (cur_wd != prev_wd) { + // Weekday change, decide now s_app.today_is_watering_day = false; uint8_t now_normalized = cur_wd + (cur_wd < s_app.last_watering_day_wd ? 7 : 0); uint8_t elapsed_days = now_normalized - s_app.last_watering_day_wd; @@ -143,6 +144,13 @@ void gui_loop_iter(GuiEvent message) } } + // exit manual mode after long time + if (s_app.screen == screen_manual_control) { + if ((tickNow - s_app.screen_open_time) >= (3600 * 1000)) { + switch_screen(screen_home, true); + } + } + // Read RTC every second if (tickNow - s_app.last_1s_time >= 1000) { s_app.screen(GUI_EVENT_SCREEN_TICK_1S); diff --git a/src/screens/app_gui.h b/src/screens/app_gui.h index 08181f2..62ca2e0 100644 --- a/src/screens/app_gui.h +++ b/src/screens/app_gui.h @@ -79,7 +79,7 @@ struct State { uint16_t moisture_raw; uint16_t moisture_pt; struct rtc_time last_cycle_time; - bool cycle_time_checking; + bool cycle_time_checking; // TODO unclear what this does??? /// Repaint was requested from the screen code bool paint_needed; From 61513c9e57e31597daa13eefacac0dcae2ecdcb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 30 Jun 2024 19:28:45 +0200 Subject: [PATCH 7/7] add explanation --- src/screens/app_gui.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/app_gui.h b/src/screens/app_gui.h index 62ca2e0..eb132cf 100644 --- a/src/screens/app_gui.h +++ b/src/screens/app_gui.h @@ -79,7 +79,7 @@ struct State { uint16_t moisture_raw; uint16_t moisture_pt; struct rtc_time last_cycle_time; - bool cycle_time_checking; // TODO unclear what this does??? + bool cycle_time_checking; // This is used to prevent cycle being started again and again during the same minute - it is cleared once the HH:MM time changes. /// Repaint was requested from the screen code bool paint_needed;