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 /* 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; } } 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].value) { // only save if the value has changed os.options[OPTION_WATER_PERCENTAGE].value = 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].value) { // if timezone changed, save change and force ntp sync os.options[OPTION_TIMEZONE].value = v; os.options_save(); } } } if (findKeyVal(p, tmp_buffer, TMP_BUFFER_SIZE, PSTR("eip"), true)) { os.external_ip = atol(tmp_buffer); } os.checkwt_success_lasttime = os.now_tz(); }
// ====================== // Setup Function // ====================== void do_setup() { /* Clear WDT reset flag. */ MCUSR &= ~(1<<WDRF); DEBUG_BEGIN(9600); DEBUG_PRINTLN("started."); os.begin(); // OpenSprinkler init os.options_setup(); // Setup options pd.init(); // ProgramData init setSyncInterval(RTC_SYNC_INTERVAL); // RTC sync interval // if rtc exists, sets it as time sync source setSyncProvider(RTC.get); os.lcd_print_time(os.now_tz()); // display time to LCD // enable WDT /* In order to change WDE or the prescaler, we need to * set WDCE (This will allow updates for 4 clock cycles). */ WDTCSR |= (1<<WDCE) | (1<<WDE); /* set new watchdog timeout prescaler value */ WDTCSR = 1<<WDP3 | 1<<WDP0; // 8.0 seconds /* Enable the WD interrupt (note no reset). */ WDTCSR |= _BV(WDIE); if (os.start_network()) { // initialize network os.status.network_fails = 0; } else { os.status.network_fails = 1; } os.status.req_network = 0; os.status.req_ntpsync = 1; os.apply_all_station_bits(); // reset station bits os.button_timeout = LCD_BACKLIGHT_TIMEOUT; }
void GetWeather() { EthernetClient client; static struct hostent *server = NULL; if (!server) { strcpy(tmp_buffer, WEATHER_SCRIPT_HOST); server = gethostbyname(tmp_buffer); if (!server) { DEBUG_PRINTLN("can't resolve weather server"); return; } DEBUG_PRINT("weather server ip:"); DEBUG_PRINT(((uint8_t*)server->h_addr)[0]); DEBUG_PRINT(":"); DEBUG_PRINT(((uint8_t*)server->h_addr)[1]); DEBUG_PRINT(":"); DEBUG_PRINT(((uint8_t*)server->h_addr)[2]); DEBUG_PRINT(":"); DEBUG_PRINTLN(((uint8_t*)server->h_addr)[3]); } if (!client.connect((uint8_t*)server->h_addr, 80)) { DEBUG_PRINTLN("failed to connect to weather server"); client.stop(); return; } BufferFiller bf = tmp_buffer; char tmp[100]; read_from_file(wtopts_name, tmp, 100); bf.emit_p(PSTR("$D.py?loc=$E&key=$E&fwv=$D&wto=$S"), (int) os.options[OPTION_USE_WEATHER].value, ADDR_NVM_LOCATION, ADDR_NVM_WEATHER_KEY, (int)os.options[OPTION_FW_VERSION].value, tmp); char *src=tmp_buffer+strlen(tmp_buffer); char *dst=tmp_buffer+TMP_BUFFER_SIZE-1; char c; // url encode. convert SPACE to %20 // copy reversely from the end because we are potentially expanding // the string size while(src!=tmp_buffer) { c = *src--; if(c==' ') { *dst-- = '0'; *dst-- = '2'; *dst-- = '%'; } else { *dst-- = c; } }; *dst = *src; char urlBuffer[255]; strcpy(urlBuffer, "GET /weather"); strcat(urlBuffer, dst); strcat(urlBuffer, " HTTP/1.0\r\nHOST: weather.opensprinkler.com\r\n\r\n"); client.write((uint8_t *)urlBuffer, strlen(urlBuffer)); bzero(ether_buffer, ETHER_BUFFER_SIZE); time_t timeout = os.now_tz() + 5; // 5 seconds timeout while(os.now_tz() < timeout) { int len=client.read((uint8_t *)ether_buffer, ETHER_BUFFER_SIZE); if (len<=0) { if(!client.connected()) break; else continue; } peel_http_header(); getweather_callback(0, 0, ETHER_BUFFER_SIZE); } client.stop(); }
/** 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