watering_nano.ino 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. //#include <avr/wdt.h>
  2. #include <EEPROM.h>
  3. #include <Wire.h>
  4. #include "RTClib.h"
  5. #include <LiquidCrystal_PCF8574.h>
  6. LiquidCrystal_PCF8574 lcd(0x3f); // set the LCD address to 0x27 for a 16 chars and 2 line display
  7. RTC_DS1307 RTC;
  8. int LightsOnTime = (60 * (9)) + 0;
  9. int LightsOutTime = (60 * (12 + 9)) + 30;
  10. int WaterLen = (60 * 4) + 0;
  11. long WaterTime = 60L * ((60L * (12L + 0L)) + 0L);
  12. unsigned char BacklightLevel = 128 + 64;
  13. const char relayPin1 = 2;
  14. const char relayPin2 = 3;
  15. const char waterPin = 7;
  16. // data is aligned to 4 bytes to make room for later type changes
  17. const int LightsOnTimePtr = 0;
  18. const int LightsOutTimePtr = 4;
  19. const int WaterLenPtr = 8;
  20. const int WaterTimePtr = 12;
  21. const int BacklightLevelPtr = 16;
  22. char manualWater = 1; // active low relay
  23. const int PIN_COUNT = 14;
  24. char debounceEnable[PIN_COUNT];
  25. char pinState[PIN_COUNT];
  26. char pinPressed[PIN_COUNT];
  27. char tempPinState[PIN_COUNT];
  28. unsigned long debounceLastTime[PIN_COUNT];
  29. const unsigned long debounceDelay = 50;
  30. void processDebounce() {
  31. int i;
  32. for(i = 0; i < PIN_COUNT; i++) {
  33. if(!debounceEnable[i]) continue;
  34. int r = digitalRead(i);
  35. if(r != tempPinState[i]) {
  36. debounceLastTime[i] = millis();
  37. }
  38. if(millis() - debounceLastTime[i] > debounceDelay) {
  39. if(!r && pinState[i]) {
  40. pinPressed[i]++;
  41. }
  42. pinState[i] = r;
  43. }
  44. tempPinState[i] = r;
  45. }
  46. }
  47. void initDebounce(int pin) {
  48. debounceEnable[pin] = 1;
  49. pinMode(pin, INPUT);
  50. pinMode(pin, INPUT_PULLUP);
  51. }
  52. void saveData() {
  53. EEPROM.put(LightsOnTimePtr, LightsOnTime);
  54. EEPROM.put(LightsOutTimePtr, LightsOutTime);
  55. EEPROM.put(WaterTimePtr, WaterTime);
  56. EEPROM.put(WaterLenPtr, WaterLen);
  57. EEPROM.put(BacklightLevelPtr, BacklightLevel);
  58. }
  59. void loadData() {
  60. EEPROM.get(LightsOnTimePtr, LightsOnTime);
  61. EEPROM.get(LightsOutTimePtr, LightsOutTime);
  62. EEPROM.get(WaterTimePtr, WaterTime);
  63. EEPROM.get(WaterLenPtr, WaterLen);
  64. EEPROM.get(BacklightLevelPtr, BacklightLevel);
  65. }
  66. void resetData() {
  67. LightsOnTime = (60 * (9)) + 0;
  68. LightsOutTime = (60 * (12 + 9)) + 30;
  69. WaterLen = (60 * 4) + 0;
  70. WaterTime = 60L * ((60L * (12L + 0L)) + 0L);
  71. BacklightLevel = 128 + 64;
  72. saveData();
  73. }
  74. unsigned long gettimes() {
  75. DateTime now = RTC.now();
  76. unsigned long mm = now.minute();
  77. unsigned long hh = now.hour();
  78. //Serial.printf("h: %d m: %d\n", hh, mm);
  79. unsigned long s = (unsigned long)now.second() + (mm * 60) + (hh * 3600);
  80. return s;
  81. }
  82. unsigned long gettime() {
  83. DateTime now = RTC.now();
  84. unsigned long mm = now.minute();
  85. unsigned long hh = now.hour();
  86. //Serial.printf("h: %d m: %d\n", hh, mm);
  87. unsigned long s = mm + (hh * 60);
  88. return s;
  89. }
  90. // the setup function runs once when you press reset or power the board
  91. void setup() {
  92. initDebounce(10);
  93. initDebounce(11);
  94. initDebounce(12);
  95. //saveData();
  96. loadData();
  97. //wdt_disable();
  98. //wdt_enable(WDTO_8S);
  99. Serial.begin(115200);
  100. Wire.begin();
  101. delay(10);
  102. RTC.begin();
  103. delay(10);
  104. if ( ! RTC.isrunning()) {
  105. Serial.println("RTC is NOT running!");
  106. // following line sets the RTC to the date & time this sketch was compiled
  107. RTC.adjust(DateTime(__DATE__, __TIME__));
  108. }
  109. DateTime now = RTC.now();
  110. unsigned long mm = now.minute();
  111. unsigned long hh = now.hour();
  112. Serial.print(hh);
  113. Serial.print(":");
  114. Serial.println(mm);
  115. lcd.begin(16, 2); // initialize the lcd
  116. lcd.setBacklight(BacklightLevel);
  117. lcd.display();
  118. lcd.home(); lcd.clear();
  119. lcd.print("starting up...");
  120. pinMode(LED_BUILTIN, OUTPUT);
  121. pinMode(relayPin1, OUTPUT);
  122. pinMode(relayPin2, OUTPUT);
  123. pinMode(waterPin, OUTPUT);
  124. digitalWrite(waterPin, 1);
  125. }
  126. void checkWater() {
  127. unsigned long ss = gettimes();
  128. char st = manualWater;
  129. //DateTime now = RTC.now();
  130. //if(now.day() % 2) return;
  131. if(ss > WaterTime && ss < (WaterTime + WaterLen)) {
  132. st = 0;
  133. //Serial.print("watering ");
  134. //Serial.print(WaterTime + WaterLen - ss);
  135. //Serial.println(" seconds left");
  136. }
  137. //Serial.print("Lights :");
  138. //Serial.print(mins);
  139. //Serial.print("\n");
  140. digitalWrite(waterPin, st);
  141. }
  142. void checkLights() {
  143. unsigned long mins = gettime();
  144. char st = 0;
  145. if(mins > LightsOnTime && mins < LightsOutTime) {
  146. st = 1;
  147. }
  148. //Serial.print("Lights :");
  149. //Serial.print(mins);
  150. //Serial.print("\n");
  151. digitalWrite(relayPin1, st);
  152. digitalWrite(relayPin2, !st);
  153. //digitalWrite(LED_BUILTIN, st);
  154. }
  155. void printTime(unsigned int mins) {
  156. unsigned int m = (mins % 60);
  157. lcd.print(mins / 60);
  158. lcd.print(":");
  159. if(m < 10) lcd.print("0");
  160. lcd.print(m);
  161. }
  162. void loop() {
  163. processDebounce();
  164. //wdt_reset();
  165. unsigned long mil = millis();
  166. //digitalWrite(LED_BUILTIN, mil % 4000 < 100);
  167. checkLights();
  168. checkWater();
  169. delay(50);
  170. static char up = 0;
  171. static char didSave = 0;
  172. static char dispState = 0;
  173. if(pinPressed[10]) {
  174. dispState = (dispState + 1) % 9;
  175. pinPressed[10] = 0;
  176. up = 1;
  177. didSave = 0;
  178. }
  179. if(pinPressed[11] || pinPressed[12]) {
  180. int inc = 1;
  181. if(pinPressed[12]) inc = -1;
  182. switch(dispState) {
  183. case 1:
  184. LightsOnTime = (LightsOnTime + (inc*15)) % (24 * 60);
  185. break;
  186. case 2:
  187. LightsOutTime = (LightsOutTime + (inc*15)) % (24 * 60);
  188. break;
  189. case 3:
  190. WaterTime = (WaterTime + ((long)inc*15L*60L)) % (24L * 3600L);
  191. break;
  192. case 4:
  193. WaterLen = (WaterLen + (inc*5)) % (6 * 60);
  194. break;
  195. case 5:
  196. // adjust backlight
  197. BacklightLevel = (BacklightLevel + (inc * 8));
  198. lcd.setBacklight(BacklightLevel);
  199. break;
  200. case 6:
  201. // manual watering
  202. manualWater = !manualWater;
  203. break;
  204. case 7:
  205. // set clock
  206. break;
  207. case 8:
  208. if(pinPressed[11] && !pinPressed[12]) {
  209. // save
  210. saveData();
  211. didSave = 1;
  212. }
  213. else {
  214. // reset and save default values
  215. resetData();
  216. didSave = 2;
  217. }
  218. default:
  219. break;
  220. }
  221. pinPressed[11] = 0;
  222. pinPressed[12] = 0;
  223. up = 1;
  224. }
  225. if(dispState != 6) manualWater = 1;
  226. if(dispState == 0) {
  227. static unsigned long lastTimeUpdate = millis();
  228. if(millis() - lastTimeUpdate > 1000) {
  229. lastTimeUpdate = millis();
  230. DateTime now = RTC.now();
  231. lcd.clear();
  232. lcd.setCursor(0, 0);
  233. //lcd.print(" ");
  234. //lcd.setCursor(0, 0);
  235. if(now.hour() < 10) lcd.print(" ");
  236. lcd.print(now.hour() % 12);
  237. lcd.print(":");
  238. if(now.minute() < 10) lcd.print("0");
  239. lcd.print(now.minute());
  240. lcd.print(":");
  241. if(now.second() < 10) lcd.print("0");
  242. lcd.print(now.second());
  243. if(now.hour() > 12) lcd.print(" PM");
  244. else lcd.print(" AM");
  245. lcd.setCursor(0, 1);
  246. /*if(now.day() % 2) {
  247. lcd.print("water tomorrow");
  248. }
  249. else {
  250. lcd.print("watering today");
  251. }*/
  252. }
  253. }
  254. else if(dispState == 1) {
  255. if(up) {
  256. lcd.clear();
  257. lcd.setCursor(0, 0);
  258. lcd.print("Lights On Time");
  259. lcd.setCursor(0, 1);
  260. printTime(LightsOnTime);
  261. up = 0;
  262. }
  263. }
  264. else if(dispState == 2) {
  265. if(up) {
  266. lcd.clear();
  267. lcd.setCursor(0, 0);
  268. lcd.print("Lights Off Time");
  269. lcd.setCursor(0, 1);
  270. printTime(LightsOutTime);
  271. up = 0;
  272. }
  273. }
  274. else if(dispState == 3) {
  275. if(up) {
  276. lcd.clear();
  277. lcd.setCursor(0, 0);
  278. lcd.print("Water Time");
  279. lcd.setCursor(0, 1);
  280. printTime(WaterTime / 60);
  281. up = 0;
  282. }
  283. }
  284. else if(dispState == 4) {
  285. if(up) {
  286. lcd.clear();
  287. lcd.setCursor(0, 0);
  288. lcd.print("Water Length");
  289. lcd.setCursor(0, 1);
  290. printTime(WaterLen);
  291. up = 0;
  292. }
  293. }
  294. else if(dispState == 5) {
  295. if(up) {
  296. lcd.clear();
  297. lcd.setCursor(0,0);
  298. lcd.print("LCD Backlight");
  299. lcd.setCursor(0, 1);
  300. lcd.print(BacklightLevel);
  301. up = 0;
  302. }
  303. }
  304. else if(dispState == 6) {
  305. if(up) {
  306. lcd.clear();
  307. lcd.setCursor(0,0);
  308. lcd.print("Manual Water");
  309. lcd.setCursor(0,1);
  310. if(manualWater) {
  311. lcd.print(" turn on");
  312. }
  313. else {
  314. lcd.print(" turn off");
  315. }
  316. up = 0;
  317. }
  318. }
  319. else if(dispState == 7) {
  320. if(up) {
  321. lcd.clear();
  322. lcd.setCursor(0,0);
  323. lcd.print("Set Clock");
  324. lcd.setCursor(0,1);
  325. lcd.print("-not implemented-");
  326. up = 0;
  327. }
  328. }
  329. else if(dispState == 8) {
  330. if(up) {
  331. lcd.clear();
  332. lcd.setCursor(0,0);
  333. lcd.print("Save Settings");
  334. lcd.setCursor(0,1);
  335. if(didSave == 1) {
  336. lcd.print("--saved--");
  337. }
  338. else if(didSave == 2) {
  339. lcd.print("--reset done--");
  340. }
  341. else {
  342. lcd.print("<save reset>");
  343. }
  344. up = 0;
  345. }
  346. }
  347. }