From 98e63353d3f210eba7093598d18444b3d68be1e9 Mon Sep 17 00:00:00 2001 From: Tuomas Airaksinen Date: Thu, 14 Sep 2023 19:02:21 +0300 Subject: [PATCH 1/3] Transform to PlatformIO project --- .gitignore | 2 + include/README | 39 ++++ lib/README | 46 +++++ platformio.ini | 17 ++ pulputin.ino | 517 ++++++++++++++++++++++++------------------------- test/README | 11 ++ 6 files changed, 371 insertions(+), 261 deletions(-) create mode 100644 .gitignore create mode 100644 include/README create mode 100644 lib/README create mode 100644 platformio.ini create mode 100644 test/README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b43bfca --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.pio +.idea diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..0590a58 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,17 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:megaatmega2560] +platform = atmelavr +board = megaatmega2560 +framework = arduino +lib_deps = + LiquidCrystal I2C @ 1.1.2 + RTCLib by NeiroN @ 1.6.3 diff --git a/pulputin.ino b/pulputin.ino index a0c40a0..5f75d66 100644 --- a/pulputin.ino +++ b/pulputin.ino @@ -1,6 +1,7 @@ // Copyright (C) 2023 Tuomas Airaksinen // License: GPL. See GPL.txt for more info +#include #include #include #include @@ -25,31 +26,28 @@ static const uint16_t ALARM_PIN = 3; static const uint16_t MOTION_PIN = 52; static const uint16_t MOTION_GROUND_PIN = 50; - -uint16_t moisture1Percent = 0; bool waterLevel = false; -bool maxWaterLevel = false; +bool maxWaterLevel = false; bool motionSns = false; - // How many ml water has been pumped each hour // Latest is first item. // Once an hour last item is removed and each item is moved one forward. -uint16_t pumpStatistics[24]; +uint16_t pumpStatistics[24]; uint16_t pumpedTotal = 0; // EEPROM addresses static const uint16_t EEPROM_PUMP_STATISTICS = 0; -static const uint16_t EEPROM_CONFIGURED = 48; -static const uint16_t EEPROM_PUMP_TOTAL = 49; -static const uint16_t EEPROM_LAST_HOUR_STARTED = 51; -static const uint16_t EEPROM_PUMP_STARTED = 59; -static const uint16_t EEPROM_IDLE_STARTED = 67; -static const uint16_t EEPROM_LAST_WET = 75; -static const uint16_t EEPROM_STATS_CUR_DAY = 83; -static const uint16_t EEPROM_LAST = 83; +static uint8_t* EEPROM_CONFIGURED = reinterpret_cast(48); +static uint16_t* EEPROM_PUMP_TOTAL = reinterpret_cast(49); +static const void* EEPROM_LAST_HOUR_STARTED = reinterpret_cast(51); +static const void* EEPROM_PUMP_STARTED = reinterpret_cast(59); +static const void* EEPROM_IDLE_STARTED = reinterpret_cast(67); +static const void* EEPROM_LAST_WET = reinterpret_cast(75); +static uint8_t* EEPROM_STATS_CUR_DAY = reinterpret_cast(83); +static const uint16_t* EEPROM_LAST = reinterpret_cast(83); -static const byte EEPROM_CHECKVALUE = 0b10101010; +static const uint8_t EEPROM_CHECKVALUE = 0b10101010; static const uint32_t EPOCH_OFFSET = 1694490000; @@ -99,87 +97,94 @@ static const uint32_t MOTION_STOP_TIME = ONE_MINUTE * 15; LiquidCrystal_I2C lcd(0x3F, 16, 2); DS3231 rtc; -void initializePins() { - pinMode(BUTTON1_PIN, INPUT_PULLUP); - pinMode(BUTTON2_PIN, INPUT_PULLUP); - pinMode(BUTTON3_PIN, INPUT_PULLUP); - pinMode(BUTTON4_PIN, INPUT_PULLUP); - pinMode(BUTTON5_PIN, INPUT_PULLUP); - pinMode(BUTTON6_PIN, INPUT_PULLUP); - pinMode(BUTTON7_PIN, INPUT_PULLUP); - pinMode(BUTTON8_PIN, INPUT_PULLUP); - pinMode(MOTION_PIN, INPUT); - - pinMode(IN_MOISTURE1_PIN, INPUT); - pinMode(OUT_PUMP_PIN, OUTPUT); - pinMode(LED_BUILTIN, OUTPUT); - pinMode(ALARM_PIN, OUTPUT); - - pinMode(MOTION_GROUND_PIN, OUTPUT); - digitalWrite(MOTION_GROUND_PIN, LOW); - - pinMode(WATER_LEVEL_PIN, INPUT_PULLUP); - - digitalWrite(LED_BUILTIN, LOW); - digitalWrite(ALARM_PIN, LOW); - digitalWrite(OUT_PUMP_PIN, LOW); +void resetMaxWaterLevel() { + maxWaterLevel = waterLevel; } -void readEeprom() { - if (eeprom_read_byte(EEPROM_CONFIGURED) != EEPROM_CHECKVALUE) { - resetEEPROM(); - } - for (uint16_t i = 0; i < 24; i++) { - pumpStatistics[i] = eeprom_read_word(EEPROM_PUMP_STATISTICS + i*2); - } - - pumpedTotal = eeprom_read_word(EEPROM_PUMP_TOTAL); - - eeprom_read_block(&lastHourStarted, EEPROM_LAST_HOUR_STARTED, 8); - eeprom_read_block(&pumpStartedMs, EEPROM_PUMP_STARTED, 8); - eeprom_read_block(&idleStartedMs, EEPROM_IDLE_STARTED, 8); - eeprom_read_block(&lastWetMs, EEPROM_LAST_WET, 8); - - statisticsCurrentDay = eeprom_read_byte(EEPROM_STATS_CUR_DAY); +bool wetRecently() { return wasWet && (timeNow - lastWetMs < WET_TIME); } +bool forceStoppedRecently() { return wasForceStopped && (timeNow - forceStopStartedMs < FORCE_STOP_TIME); } +bool motionStoppedRecently() { return wasMotionStopped && (timeNow - motionStopStartedMs < MOTION_STOP_TIME); } +bool cantStart() { return wetRecently() || forceStoppedRecently() || motionStoppedRecently(); } + +void initializePins() { + pinMode(BUTTON1_PIN, INPUT_PULLUP); + pinMode(BUTTON2_PIN, INPUT_PULLUP); + pinMode(BUTTON3_PIN, INPUT_PULLUP); + pinMode(BUTTON4_PIN, INPUT_PULLUP); + pinMode(BUTTON5_PIN, INPUT_PULLUP); + pinMode(BUTTON6_PIN, INPUT_PULLUP); + pinMode(BUTTON7_PIN, INPUT_PULLUP); + pinMode(BUTTON8_PIN, INPUT_PULLUP); + pinMode(MOTION_PIN, INPUT); + + pinMode(IN_MOISTURE1_PIN, INPUT); + pinMode(OUT_PUMP_PIN, OUTPUT); + pinMode(LED_BUILTIN, OUTPUT); + pinMode(ALARM_PIN, OUTPUT); + + pinMode(MOTION_GROUND_PIN, OUTPUT); + digitalWrite(MOTION_GROUND_PIN, LOW); + + pinMode(WATER_LEVEL_PIN, INPUT_PULLUP); + + digitalWrite(LED_BUILTIN, LOW); + digitalWrite(ALARM_PIN, LOW); + digitalWrite(OUT_PUMP_PIN, LOW); } void saveEeprom() { - for (uint16_t i = 0; i < 24; i++) { - eeprom_update_word(EEPROM_PUMP_STATISTICS + i*2, pumpStatistics[i]); - } - eeprom_update_word(EEPROM_PUMP_TOTAL, pumpedTotal); - - eeprom_update_block(&lastHourStarted, EEPROM_LAST_HOUR_STARTED, 8); - eeprom_update_block(&pumpStartedMs, EEPROM_PUMP_STARTED, 8); - eeprom_update_block(&idleStartedMs, EEPROM_IDLE_STARTED, 8); - eeprom_update_block(&lastWetMs, EEPROM_LAST_WET, 8); - - eeprom_update_byte(EEPROM_STATS_CUR_DAY, statisticsCurrentDay); -} + for (uint16_t i = 0; i < 24; i++) { + eeprom_update_word(reinterpret_cast(EEPROM_PUMP_STATISTICS + i * 2), pumpStatistics[i]); + } + eeprom_update_word(EEPROM_PUMP_TOTAL, pumpedTotal); + eeprom_update_block(&lastHourStarted, &EEPROM_LAST_HOUR_STARTED, 8); + eeprom_update_block(&pumpStartedMs, &EEPROM_PUMP_STARTED, 8); + eeprom_update_block(&idleStartedMs, &EEPROM_IDLE_STARTED, 8); + eeprom_update_block(&lastWetMs, &EEPROM_LAST_WET, 8); -void dayPassed() { - for (int16_t i = 23; i > 0; i--) { - pumpStatistics[i] = pumpStatistics[i - 1]; - } - pumpStatistics[0] = 0; + eeprom_update_byte(EEPROM_STATS_CUR_DAY, statisticsCurrentDay); } void resetEEPROM() { - for (int16_t i = 23; i >= 0; i--) { - pumpStatistics[i] = 0; - } - - pumpedTotal = 0; - lastHourStarted = timeNow; - pumpStartedMs = timeNow; - idleStartedMs = timeNow; - lastWetMs = 0; - forceStopStartedMs = 0; - statisticsCurrentDay = dateTimeNow.day(); - eeprom_update_byte(EEPROM_CONFIGURED, EEPROM_CHECKVALUE); - saveEeprom(); - //readEeprom(); + for (int16_t i = 23; i >= 0; i--) { + pumpStatistics[i] = 0; + } + + pumpedTotal = 0; + lastHourStarted = timeNow; + pumpStartedMs = timeNow; + idleStartedMs = timeNow; + lastWetMs = 0; + forceStopStartedMs = 0; + statisticsCurrentDay = dateTimeNow.day(); + eeprom_update_byte(EEPROM_CONFIGURED, EEPROM_CHECKVALUE); + saveEeprom(); +} + +void readEeprom() { + if (eeprom_read_byte(EEPROM_CONFIGURED) != EEPROM_CHECKVALUE) { + resetEEPROM(); + } + for (uint16_t i = 0; i < 24; i++) { + pumpStatistics[i] = eeprom_read_word(reinterpret_cast(EEPROM_PUMP_STATISTICS + i * 2)); + } + + pumpedTotal = eeprom_read_word(EEPROM_PUMP_TOTAL); + + eeprom_read_block(&lastHourStarted, EEPROM_LAST_HOUR_STARTED, 8); + eeprom_read_block(&pumpStartedMs, EEPROM_PUMP_STARTED, 8); + eeprom_read_block(&idleStartedMs, EEPROM_IDLE_STARTED, 8); + eeprom_read_block(&lastWetMs, EEPROM_LAST_WET, 8); + + statisticsCurrentDay = eeprom_read_byte(EEPROM_STATS_CUR_DAY); +} + +void dayPassed() { + for (int16_t i = 23; i > 0; i--) { + pumpStatistics[i] = pumpStatistics[i - 1]; + } + pumpStatistics[0] = 0; } static const uint16_t BUF_SIZE = 18; @@ -189,60 +194,60 @@ char floatBuf1[BUF_SIZE]; char floatBuf2[BUF_SIZE]; void updateLcd() { - bool showForceStop = !digitalRead(BUTTON4_PIN); - bool showResetContainer = !digitalRead(BUTTON6_PIN); - bool backlightBtn = !digitalRead(BUTTON3_PIN); - bool showTimes = !digitalRead(BUTTON1_PIN); - bool showContainer = !digitalRead(BUTTON5_PIN); - float leftWater = (CONTAINER_SIZE - pumpedTotal)/1000.0; - - if(showContainer) { - float pumpedTotalLitres = pumpedTotal / 1000.0; - - dtostrf(pumpedTotalLitres, 0, 2, floatBuf1); - snprintf(lcdBuf1, BUF_SIZE, "Pumped: %s l ", floatBuf1); - dtostrf(leftWater, 0, 2, floatBuf1); - snprintf(lcdBuf2, BUF_SIZE, "Left: %s l ", floatBuf1); - } - else if (showForceStop) { - snprintf(lcdBuf1, BUF_SIZE, "Force stopping "); - snprintf(lcdBuf2, BUF_SIZE, "for 1 hour "); - } - else if (showResetContainer) { - snprintf(lcdBuf1, BUF_SIZE, "Container "); - snprintf(lcdBuf2, BUF_SIZE, "filled "); - } - else if (showTimes) { - snprintf(lcdBuf1, BUF_SIZE, "Wet %u min ago ", minutesAgo(lastWetMs)); - snprintf(lcdBuf2, BUF_SIZE, "Pumped %u min ago ", minutesAgo(pumpStartedMs)); - } else { - dtostrf((float)(pumpStatistics[0]/1000.0), 4, 1, floatBuf1); - dtostrf((float)(pumpStatistics[1]/1000.0), 4, 1, floatBuf2); - - int32_t totalMinutes = minutesAgo(waterLevel ? pumpStartedMs: lastWetMs); - int32_t hours = totalMinutes/60; - int32_t minutesLeft = totalMinutes - hours*60; - uint16_t waterRemainingPercent = ((float)(CONTAINER_SIZE - pumpedTotal - 1) / CONTAINER_SIZE)*100; - snprintf(lcdBuf1, BUF_SIZE, "%s %s %luh %lum ", floatBuf1, floatBuf2, hours, minutesLeft); - snprintf(lcdBuf2, BUF_SIZE, "%2d%% %s%s%s %2u:%02u ", - waterRemainingPercent, - waterLevel ? "We" : "Dr", - motionSns ? "Mo": " ", - cantStart() ? "St" : " ", - dateTimeNow.hour(), dateTimeNow.minute() - ); - } - - if(backlightBtn || (leftWater < 3.0 && timeNow/100 % 100 == 0 && !forceStoppedRecently())) { - analogWrite(ALARM_PIN, 50); - } else { - analogWrite(ALARM_PIN, 0); - } - - lcd.setCursor(0, 0); - lcd.print(lcdBuf1); - lcd.setCursor(0, 1); - lcd.print(lcdBuf2); + bool showForceStop = !digitalRead(BUTTON4_PIN); + bool showResetContainer = !digitalRead(BUTTON6_PIN); + bool backlightBtn = !digitalRead(BUTTON3_PIN); + bool showTimes = !digitalRead(BUTTON1_PIN); + bool showContainer = !digitalRead(BUTTON5_PIN); + double leftWater = (CONTAINER_SIZE - pumpedTotal)/1000.0; + + if(showContainer) { + double pumpedTotalLitres = pumpedTotal / 1000.0; + + dtostrf(pumpedTotalLitres, 0, 2, floatBuf1); + snprintf(lcdBuf1, BUF_SIZE, "Pumped: %s l ", floatBuf1); + dtostrf(leftWater, 0, 2, floatBuf1); + snprintf(lcdBuf2, BUF_SIZE, "Left: %s l ", floatBuf1); + } + else if (showForceStop) { + snprintf(lcdBuf1, BUF_SIZE, "Force stopping "); + snprintf(lcdBuf2, BUF_SIZE, "for 1 hour "); + } + else if (showResetContainer) { + snprintf(lcdBuf1, BUF_SIZE, "Container "); + snprintf(lcdBuf2, BUF_SIZE, "filled "); + } + else if (showTimes) { + snprintf(lcdBuf1, BUF_SIZE, "Wet %u min ago ", minutesAgo(lastWetMs)); + snprintf(lcdBuf2, BUF_SIZE, "Pumped %u min ago ", minutesAgo(pumpStartedMs)); + } else { + dtostrf((float)(pumpStatistics[0]/1000.0), 4, 1, floatBuf1); + dtostrf((float)(pumpStatistics[1]/1000.0), 4, 1, floatBuf2); + + int32_t totalMinutes = minutesAgo(waterLevel ? pumpStartedMs: lastWetMs); + int32_t hours = totalMinutes/60; + int32_t minutesLeft = totalMinutes - hours*60; + uint16_t waterRemainingPercent = (uint16_t)((double)(CONTAINER_SIZE - pumpedTotal - 1) / CONTAINER_SIZE)*100; + snprintf(lcdBuf1, BUF_SIZE, "%s %s %luh %lum ", floatBuf1, floatBuf2, hours, minutesLeft); + snprintf(lcdBuf2, BUF_SIZE, "%2d%% %s%s%s %2u:%02u ", + waterRemainingPercent, + waterLevel ? "We" : "Dr", + motionSns ? "Mo": " ", + cantStart() ? "St" : " ", + dateTimeNow.hour(), dateTimeNow.minute() + ); + } + + if(backlightBtn || (leftWater < 3.0 && timeNow/100 % 100 == 0 && !forceStoppedRecently())) { + analogWrite(ALARM_PIN, 50); + } else { + analogWrite(ALARM_PIN, 0); + } + + lcd.setCursor(0, 0); + lcd.print(lcdBuf1); + lcd.setCursor(0, 1); + lcd.print(lcdBuf2); } bool forceStopPressed = false; @@ -252,160 +257,150 @@ bool backlightOn = false; bool resetContainerPressed = false; void readInput() { - bool containerBtn = !digitalRead(BUTTON6_PIN); + bool containerBtn = !digitalRead(BUTTON6_PIN); - if(containerBtn != resetContainerPressed && containerBtn) { - pumpedTotal = 0; - saveEeprom(); - } - resetContainerPressed = containerBtn; + if(containerBtn != resetContainerPressed && containerBtn) { + pumpedTotal = 0; + saveEeprom(); + } + resetContainerPressed = containerBtn; - bool resetBtn = !digitalRead(BUTTON8_PIN); - if (resetBtn != resetButtonPressed && resetBtn) { - resetEEPROM(); - readEeprom(); - } - resetButtonPressed = resetBtn; - bool backlightBtn = !digitalRead(BUTTON3_PIN); - if (backlightBtn != backlightButtonPressed && backlightBtn) { - backlightOn = !backlightOn; - if(backlightOn) { - lcd.backlight(); - } else { - lcd.noBacklight(); + bool resetBtn = !digitalRead(BUTTON8_PIN); + if (resetBtn != resetButtonPressed && resetBtn) { + resetEEPROM(); + readEeprom(); + } + resetButtonPressed = resetBtn; + bool backlightBtn = !digitalRead(BUTTON3_PIN); + if (backlightBtn != backlightButtonPressed && backlightBtn) { + backlightOn = !backlightOn; + if(backlightOn) { + lcd.backlight(); + } else { + lcd.noBacklight(); + } } - } - backlightButtonPressed = backlightBtn; - - bool forceBtn = !digitalRead(BUTTON4_PIN); - if (forceBtn != forceStopPressed && forceBtn) { - forceStopStartedMs = timeNow; - wasForceStopped = true; - } - forceStopPressed = forceBtn; - motionSns = digitalRead(MOTION_PIN); - if(motionSns) { - motionStopStartedMs = timeNow; - wasMotionStopped = true; - } - - moisture1Percent = 100 - (uint16_t)((float)analogRead(IN_MOISTURE1_PIN)/ 1023. * 100); - waterLevel = digitalRead(WATER_LEVEL_PIN); + backlightButtonPressed = backlightBtn; + + bool forceBtn = !digitalRead(BUTTON4_PIN); + if (forceBtn != forceStopPressed && forceBtn) { + forceStopStartedMs = timeNow; + wasForceStopped = true; + } + forceStopPressed = forceBtn; + motionSns = digitalRead(MOTION_PIN); + if(motionSns) { + motionStopStartedMs = timeNow; + wasMotionStopped = true; + } + + waterLevel = digitalRead(WATER_LEVEL_PIN); } void startPump() { - pumpRunning = true; - pumpStartedMs = timeNow; - digitalWrite(OUT_PUMP_PIN, HIGH); - digitalWrite(LED_BUILTIN, HIGH); - resetMaxWaterLevel(); - saveEeprom(); + pumpRunning = true; + pumpStartedMs = timeNow; + digitalWrite(OUT_PUMP_PIN, HIGH); + digitalWrite(LED_BUILTIN, HIGH); + resetMaxWaterLevel(); + saveEeprom(); } void stopPump() { - pumpRunning = false; - digitalWrite(OUT_PUMP_PIN, LOW); - digitalWrite(LED_BUILTIN, LOW); - uint16_t pumped = msToMl(timeNow - pumpStartedMs); - pumpStatistics[0] += pumped; - pumpedTotal += pumped; - idleStartedMs = timeNow; - saveEeprom(); + pumpRunning = false; + digitalWrite(OUT_PUMP_PIN, LOW); + digitalWrite(LED_BUILTIN, LOW); + uint16_t pumped = msToMl(timeNow - pumpStartedMs); + pumpStatistics[0] += pumped; + pumpedTotal += pumped; + idleStartedMs = timeNow; + saveEeprom(); } void updateMaxWaterLevel() { - if (waterLevel) { - maxWaterLevel = true; - } -} - -void resetMaxWaterLevel() { - maxWaterLevel = waterLevel; + if (waterLevel) { + maxWaterLevel = true; + } } bool stopPumpTimePassed() { return timeNow - pumpStartedMs > PUMP_TIME;} bool idleTimePassed() { return timeNow - idleStartedMs > IDLE_TIME; } -bool wetRecently() { return wasWet && (timeNow - lastWetMs < WET_TIME); } -bool forceStoppedRecently() { return wasForceStopped && (timeNow - forceStopStartedMs < FORCE_STOP_TIME); } -bool motionStoppedRecently() { return wasMotionStopped && (timeNow - motionStopStartedMs < MOTION_STOP_TIME); } - -bool cantStart() { return wetRecently() || forceStoppedRecently() || motionStoppedRecently(); } void manageWaterPump() { - updateMaxWaterLevel(); + updateMaxWaterLevel(); - if (maxWaterLevel) { - lastWetMs = timeNow; - wasWet = true; - } - - if (pumpRunning) { - if (stopPumpTimePassed() || cantStart()) { - stopPump(); + if (maxWaterLevel) { + lastWetMs = timeNow; + wasWet = true; } - } else if (idleTimePassed()) { - if (!maxWaterLevel && !cantStart()) { - startPump(); - } else { - resetMaxWaterLevel(); - idleStartedMs = timeNow; + + if (pumpRunning) { + if (stopPumpTimePassed() || cantStart()) { + stopPump(); + } + } else if (idleTimePassed()) { + if (!maxWaterLevel && !cantStart()) { + startPump(); + } else { + resetMaxWaterLevel(); + idleStartedMs = timeNow; + } } - } } void printStats() { - for(uint16_t i = 0; i<24; i++) { - Serial.println(pumpStatistics[i]); - } + for(unsigned int pumpStatistic : pumpStatistics) { + Serial.println(pumpStatistic); + } } void setup() { - Serial.begin(9600); - Wire.begin(); - rtc.begin(); - - if (!rtc.isrunning()) { - Serial.println("RTC is NOT running!"); - rtc.adjust(DateTime(__DATE__, __TIME__)); - } - //Serial.println(__TIME__); - //rtc.adjust(DateTime(__DATE__, __TIME__)); - - dateTimeNow = rtc.now(); - - dateTimeNow.tostr(lcdBuf1); - Serial.println(lcdBuf1); - Serial.println(dateTimeNow.hour()); - Serial.println(dateTimeNow.minute()); - - epochAtStart = (uint64_t)(dateTimeNow.unixtime() - EPOCH_OFFSET) * 1000; - - initializePins(); - readEeprom(); - printStats(); - lcd.init(); + Serial.begin(9600); + Wire.begin(); + rtc.begin(); + + if (!rtc.isrunning()) { + Serial.println("RTC is NOT running!"); + rtc.adjust(DateTime(__DATE__, __TIME__)); + } + //Serial.println(__TIME__); + //rtc.adjust(DateTime(__DATE__, __TIME__)); + + dateTimeNow = rtc.now(); + + dateTimeNow.tostr(lcdBuf1); + Serial.println(lcdBuf1); + Serial.println(dateTimeNow.hour()); + Serial.println(dateTimeNow.minute()); + + epochAtStart = (uint64_t)(dateTimeNow.unixtime() - EPOCH_OFFSET) * 1000; + + initializePins(); + readEeprom(); + printStats(); + lcd.init(); } void loop() { - timeNow = epochAtStart + millis(); - dateTimeNow.setunixtime((timeNow / 1000) + EPOCH_OFFSET); + timeNow = epochAtStart + millis(); + dateTimeNow.setunixtime((timeNow / 1000) + EPOCH_OFFSET); - if(dateTimeNow.day() != statisticsCurrentDay) { - dayPassed(); - statisticsCurrentDay = dateTimeNow.day(); - saveEeprom(); - } + if(dateTimeNow.day() != statisticsCurrentDay) { + dayPassed(); + statisticsCurrentDay = dateTimeNow.day(); + saveEeprom(); + } - if (timeNow - lastHourStarted > ONE_HOUR && !pumpRunning) { - int32_t correction = rtc.now().unixtime() - dateTimeNow.unixtime(); - epochAtStart += correction * 1000; - timeNow = epochAtStart + millis(); + if (timeNow - lastHourStarted > ONE_HOUR && !pumpRunning) { + int32_t correction = (int32_t)(rtc.now().unixtime() - dateTimeNow.unixtime()); + epochAtStart += correction * 1000; + timeNow = epochAtStart + millis(); - lastHourStarted = timeNow; - saveEeprom(); - } - readInput(); - manageWaterPump(); - updateLcd(); + lastHourStarted = timeNow; + saveEeprom(); + } + readInput(); + manageWaterPump(); + updateLcd(); } \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html From d1c8a56a2171a9359c19d88b30aa81195ba7183a Mon Sep 17 00:00:00 2001 From: Tuomas Airaksinen Date: Thu, 14 Sep 2023 19:03:43 +0300 Subject: [PATCH 2/3] Move pulputin.ino -> src/main.cpp --- pulputin.ino => src/main.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pulputin.ino => src/main.cpp (100%) diff --git a/pulputin.ino b/src/main.cpp similarity index 100% rename from pulputin.ino rename to src/main.cpp From ae5cf99d691e0dd730346956cc521bc8dbcd9aec Mon Sep 17 00:00:00 2001 From: Tuomas Airaksinen Date: Thu, 14 Sep 2023 19:30:07 +0300 Subject: [PATCH 3/3] EEPROM address fixes Could be broken. Will check in winter when pulputin is not in use. --- src/main.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5f75d66..f5bb842 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,14 +37,14 @@ uint16_t pumpStatistics[24]; uint16_t pumpedTotal = 0; // EEPROM addresses -static const uint16_t EEPROM_PUMP_STATISTICS = 0; -static uint8_t* EEPROM_CONFIGURED = reinterpret_cast(48); -static uint16_t* EEPROM_PUMP_TOTAL = reinterpret_cast(49); +static const void* EEPROM_PUMP_STATISTICS = reinterpret_cast(0); +static const uint8_t* EEPROM_CONFIGURED = reinterpret_cast(48); +static const uint16_t* EEPROM_PUMP_TOTAL = reinterpret_cast(49); static const void* EEPROM_LAST_HOUR_STARTED = reinterpret_cast(51); static const void* EEPROM_PUMP_STARTED = reinterpret_cast(59); static const void* EEPROM_IDLE_STARTED = reinterpret_cast(67); static const void* EEPROM_LAST_WET = reinterpret_cast(75); -static uint8_t* EEPROM_STATS_CUR_DAY = reinterpret_cast(83); +static const uint8_t* EEPROM_STATS_CUR_DAY = reinterpret_cast(83); static const uint16_t* EEPROM_LAST = reinterpret_cast(83); static const uint8_t EEPROM_CHECKVALUE = 0b10101010; @@ -134,16 +134,16 @@ void initializePins() { void saveEeprom() { for (uint16_t i = 0; i < 24; i++) { - eeprom_update_word(reinterpret_cast(EEPROM_PUMP_STATISTICS + i * 2), pumpStatistics[i]); + eeprom_update_block(&pumpStatistics[i], &EEPROM_PUMP_STATISTICS + i * 2, sizeof (pumpStatistics[i])); } - eeprom_update_word(EEPROM_PUMP_TOTAL, pumpedTotal); + eeprom_update_block(&pumpedTotal, &EEPROM_PUMP_TOTAL, sizeof pumpedTotal); - eeprom_update_block(&lastHourStarted, &EEPROM_LAST_HOUR_STARTED, 8); - eeprom_update_block(&pumpStartedMs, &EEPROM_PUMP_STARTED, 8); - eeprom_update_block(&idleStartedMs, &EEPROM_IDLE_STARTED, 8); - eeprom_update_block(&lastWetMs, &EEPROM_LAST_WET, 8); + eeprom_update_block(&lastHourStarted, &EEPROM_LAST_HOUR_STARTED, sizeof lastHourStarted); + eeprom_update_block(&pumpStartedMs, &EEPROM_PUMP_STARTED, sizeof pumpStartedMs); + eeprom_update_block(&idleStartedMs, &EEPROM_IDLE_STARTED, sizeof idleStartedMs); + eeprom_update_block(&lastWetMs, &EEPROM_LAST_WET, sizeof lastWetMs); - eeprom_update_byte(EEPROM_STATS_CUR_DAY, statisticsCurrentDay); + eeprom_update_block(&statisticsCurrentDay, &EEPROM_STATS_CUR_DAY, sizeof statisticsCurrentDay); } void resetEEPROM() { @@ -158,7 +158,7 @@ void resetEEPROM() { lastWetMs = 0; forceStopStartedMs = 0; statisticsCurrentDay = dateTimeNow.day(); - eeprom_update_byte(EEPROM_CONFIGURED, EEPROM_CHECKVALUE); + eeprom_update_block(&EEPROM_CHECKVALUE, &EEPROM_CONFIGURED, sizeof EEPROM_CHECKVALUE); saveEeprom(); } @@ -167,7 +167,7 @@ void readEeprom() { resetEEPROM(); } for (uint16_t i = 0; i < 24; i++) { - pumpStatistics[i] = eeprom_read_word(reinterpret_cast(EEPROM_PUMP_STATISTICS + i * 2)); + eeprom_read_block(&pumpStatistics[i], &EEPROM_PUMP_STATISTICS + i * 2, 2); } pumpedTotal = eeprom_read_word(EEPROM_PUMP_TOTAL);