/** Main Loop */ void do_loop() { static ulong last_time = 0; static ulong last_minute = 0; byte bid, sid, s, pid, qid, bitvalue; ProgramStruct prog; os.status.mas = os.options[OPTION_MASTER_STATION]; os.status.mas2= os.options[OPTION_MASTER_STATION_2]; time_t curr_time = os.now_tz(); // ====== Process Ethernet packets ====== #if defined(ARDUINO) // Process Ethernet packets for Arduino uint16_t pos=ether.packetLoop(ether.packetReceive()); if (pos>0) { // packet received handle_web_request((char*)Ethernet::buffer+pos); } wdt_reset(); // reset watchdog timer wdt_timeout = 0; ui_state_machine(); #else // Process Ethernet packets for RPI/BBB EthernetClient client = m_server->available(); if (client) { while(true) { int len = client.read((uint8_t*) ether_buffer, ETHER_BUFFER_SIZE); if (len <=0) { if(!client.connected()) { break; } else { continue; } } else { m_client = &client; ether_buffer[len] = 0; // put a zero at the end of the packet handle_web_request(ether_buffer); m_client = 0; break; } } } #endif // Process Ethernet packets // if 1 second has passed if (last_time != curr_time) { last_time = curr_time; if (os.button_timeout) os.button_timeout--; #if defined(ARDUINO) if (!ui_state) os.lcd_print_time(os.now_tz()); // print time #endif // ====== Check raindelay status ====== if (os.status.rain_delayed) { if (curr_time >= os.nvdata.rd_stop_time) { // rain delay is over os.raindelay_stop(); } } else { if (os.nvdata.rd_stop_time > curr_time) { // rain delay starts now os.raindelay_start(); } } // ====== Check controller status changes and write log ====== if (os.old_status.rain_delayed != os.status.rain_delayed) { if (os.status.rain_delayed) { // rain delay started, record time os.raindelay_start_time = curr_time; } else { // rain delay stopped, write log write_log(LOGDATA_RAINDELAY, curr_time); } os.old_status.rain_delayed = os.status.rain_delayed; } // ====== Check rain sensor status ====== if (os.options[OPTION_SENSOR_TYPE] == SENSOR_TYPE_RAIN) { // if a rain sensor is connected os.rainsensor_status(); if (os.old_status.rain_sensed != os.status.rain_sensed) { if (os.status.rain_sensed) { // rain sensor on, record time os.sensor_lasttime = curr_time; } else { // rain sensor off, write log if (curr_time>os.sensor_lasttime+10) { // add a 10 second threshold // to avoid faulty rain sensors generating // too many log records write_log(LOGDATA_RAINSENSE, curr_time); } } os.old_status.rain_sensed = os.status.rain_sensed; } } // ====== Schedule program data ====== ulong curr_minute = curr_time / 60; boolean match_found = false; RuntimeQueueStruct *q; // since the granularity of start time is minute // we only need to check once every minute if (curr_minute != last_minute) { last_minute = curr_minute; // check through all programs for(pid=0; pid<pd.nprograms; pid++) { pd.read(pid, &prog); if(prog.check_match(curr_time)) { // program match found // process all selected stations for(sid=0;sid<os.nstations;sid++) { bid=sid>>3; s=sid&0x07; // skip if the station is a master station (because master cannot be scheduled independently if ((os.status.mas==sid+1) || (os.status.mas2==sid+1)) continue; // if station has non-zero water time and the station is not disabled if (prog.durations[sid] && !(os.station_attrib_bits_read(ADDR_NVM_STNDISABLE+bid)&(1<<s))) { // water time is scaled by watering percentage ulong water_time = water_time_resolve(water_time_decode(prog.durations[sid])); // if the program is set to use weather scaling if (prog.use_weather) { byte wl = os.options[OPTION_WATER_PERCENTAGE]; water_time = water_time * wl / 100; if (wl < 20 && water_time < 10) // if water_percentage is less than 20% and water_time is less than 10 seconds // do not water water_time = 0; } if (water_time) { // check if water time is still valid // because it may end up being zero after scaling q = pd.enqueue(); if (q) { q->st = 0; q->dur = water_time; q->sid = sid; q->pid = pid+1; match_found = true; } else { // queue is full } }// if water_time }// if prog.durations[sid] }// for sid }// if check_match }// for pid // calculate start and end time if (match_found) { schedule_all_stations(curr_time); // For debugging: print out queued elements DEBUG_PRINT("en:"); for(q=pd.queue;q<pd.queue+pd.nqueue;q++) { DEBUG_PRINT("["); DEBUG_PRINT(q->sid); DEBUG_PRINT(","); DEBUG_PRINT(q->dur); DEBUG_PRINT(","); DEBUG_PRINT(q->st); DEBUG_PRINT("]"); } DEBUG_PRINTLN(""); } }//if_check_current_minute
static void getweather_callback(byte status, uint16_t off, uint16_t len) { #if defined(ARDUINO) char *p = (char*)Ethernet::buffer + off; #else char *p = ether_buffer; #endif DEBUG_PRINTLN(p); /* scan the buffer until the first & symbol */ while(*p && *p!='&') { p++; } if (*p != '&') return; int v; if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("sunrise"), true)) { v = atoi(tmp_buffer); if (v>=0 && v<=1440) { os.nvdata.sunrise_time = v; } } if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("sunset"), true)) { v = atoi(tmp_buffer); if (v>=0 && v<=1440) { os.nvdata.sunset_time = v; } } if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("eip"), true)) { os.nvdata.external_ip = atol(tmp_buffer); } os.nvdata_save(); // save non-volatile memory if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("scale"), true)) { v = atoi(tmp_buffer); if (v>=0 && v<=250 && v != os.options[OPTION_WATER_PERCENTAGE]) { // only save if the value has changed os.options[OPTION_WATER_PERCENTAGE] = v; os.options_save(); } } if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("tz"), true)) { v = atoi(tmp_buffer); if (v>=0 && v<= 96) { if (v != os.options[OPTION_TIMEZONE]) { // if timezone changed, save change and force ntp sync os.options[OPTION_TIMEZONE] = v; os.options_save(); } } } if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("rd"), true)) { v = atoi(tmp_buffer); if (v>0) { os.nvdata.rd_stop_time = os.now_tz() + (unsigned long) v * 3600; os.raindelay_start(); } else if (v==0) { os.raindelay_stop(); } } os.checkwt_success_lasttime = os.now_tz(); write_log(LOGDATA_WATERLEVEL, os.checkwt_success_lasttime); }