📜 ⬆️ ⬇️

Forecaster Class for Weather Station or Weather Predictor

Many beginners (and not only) Arduinschiki went through the creation of a device with a loud name - Weather Station, I am among them.

Many of the options that I studied are interesting from the point of view of the flight of the creator’s thoughts; I learned from many ideas about which I don’t hide. In addition to capturing readings from my own sensors, visualizing them through various interfaces such as various Displays and Web pages, I was interested to use the weather forecast data for a while ahead.

Here, in my opinion, there are two ways: I read the first one in this article , but I liked the opportunity to get a forecast from the Internet more. I got the basic information about this from an article on Amperk and developed this idea further, the benefit of the resource offered in the article allows you to do this, completely free of charge.
As a result, my version of the weather station received the Forecaster class, which is responsible for weather prediction. This is the class in the context of a test project that I want to present to the public.

Immediately make a reservation:
1. I have a server part of the weather station built on the Arduino Mega 2560, so I do not experience a lack of memory in the project.
2. I had to make some changes to the standard Ethernet library, the changes affected the number of sockets and the buffer memory allocated for them.
The original version has 4 sockets 2kB for each socket, but I made 2 sockets 4kB each. Buffer memory had to be increased due to the fact that when receiving weather forecast information from the server, the amount of information can reach 15-18kB (when a 3-hour forecast is received). Those. with a buffer size of 2kb - most of it was simply lost. With 4kB buffer, it is possible to get a forecast for 2 days with a discreteness of 3 hours, which is not bad at all. All library changes are documented directly in the code of the class itself. If someone tells you how to solve this problem by hand, without touching the sockets, I will only be glad.
')
Sometimes, when receiving and analyzing a 3-hour forecast, it is possible to process a smaller number of elements (not 16, but only 3-6), I did not understand why this happens, perhaps Arduinka does not have time to select data from the buffer. To demonstrate the work of the Predictor, I assembled a test project that I tested on 2 devices:
1. Arduino Uno + Ethernet shield (w5100)
2. iBoard
Due to the lack of memory in these devices, I had to comment out some related functions. Inside the class:
int FORECAST::GetForecastDays(FORECAST::_WeatherDay* wdp) //  4   int FORECAST::GetForecast(FORECAST::_WeatherPacket& whr) //    

In the body of the main loop, the code that calls these functions is commented out. Their work can be checked by commenting and removing comments from the corresponding sections of the code. If the code is poured into the Mega2560, then the need for commenting will disappear and everything will work. The project is built under IDE version 1.6.5. (At 1.0.5r2 - also without problems).

I also want to make a reservation, I am not an adept of C (C ++), so I often ask questions on the forums how to work with strings and the like. In this regard, it is likely that some parts of the code are written strangely or not optimally, in short - healthy criticism is welcome.

The city for which the requested forecast is registered in the class declarations:
 const char p_request3Hour[] PROGMEM = "GET /data/2.5/forecast?q=Krasnoyarsk&mode=xml&units=metric"; const char p_request4Day[] PROGMEM = "GET /data/2.5/forecast/daily?q=Krasnoyarsk&mode=xml&units=metric&cnt=4"; const char p_requestToDay[] PROGMEM = "GET /data/2.5/weather?q=Krasnoyarsk&mode=xml&units=metric"; 

Weather Prediction Class Announcement:
 FORECAST frc; FORECAST::_WeatherPacket weather; //     FORECAST::_WeatherDay wPack1Day; //      4  (  ) FORECAST::_WeatherThreeHour wPack3Hour; // 3       2  

Initialization:
 frc.Init(client, 7); // client -  EthernetClient, 7 -    

Request weather on the server:
 frc.GetForecast(weather) // weather -     frc.GetForecast3Hour(&wPack3Hour) //wPack3Hour -   16   3   frc.GetForecastDays(&wPack1Day) //wPack1Day -   4     4  

Description of structures with weather data
 //   struct _WeatherPacket { int P; // int T; // int H; // int WS; //  (/) char WD[4]; // char Icon[4]; //    }; //      4   typedef struct OneDay { time_t Data; //   "20141010' int TD; //  int TN; //  byte H; // int P; // byte WS; //  char WD[4]; //  byte Cloud; //  % int RainVal; //  (*100), 0 -  , -  +  char Icon[4]; //Icon } wdPack; //    3   2   typedef struct ThreeHour { time_t Data; //     "2014-10-10 21:00' int T; // int TT; // Min  Max byte H; // int P; // byte WS; //  char WD[4]; // byte Cloud; //  % int RainVal; //  (*100), 0 -  , -  +  char Icon[4]; //Icon } whPack; 


Structures with meteorological data have a small length and therefore can be easily transferred via nRF24. Naturally, 1 structure contains data for 1 day or 3 hours, and in order to transfer all the melons completely, a corresponding number of transmission sessions will be required. For this, I created a special exchange protocol between the display and server modules. Well, actually the source itself:
forecast.h
 #ifndef FORECAST_H #define FORECAST_H #include "Arduino.h" #include <Ethernet.h> #include <Time.h> //      4   typedef struct OneDay { time_t Data; //   "20141010' int TD; //  int TN; //  byte H; // int P; // byte WS; //  char WD[4]; //  byte Cloud; //  % int RainVal; //  (*100), 0 -  , -  +  char Icon[4]; //Icon } wdPack; // = 23 byte //    3   2   typedef struct ThreeHour { time_t Data; //   "2014-10-10 21:00' int T; // int TT; // Min  Max byte H; // int P; // byte WS; //  char WD[4]; // byte Cloud; //  % int RainVal; //  (*100), 0 -  , -  +  char Icon[4]; //Icon } whPack; //=23 byte class FORECAST { private : EthernetClient client; void clearStr (char* str); void addChar (char ch, char* str); void SubStrA(int Num,String& source, String& str); void SubStrB(int Num,String& source, String& str); time_t _ConvertDate(char _Data[10]); time_t _ConvertDateTime(char DatTim[16]); char* GetWord(uint8_t numWord); String dataString; boolean tagFlag; boolean dataFlag; int tZone; long tDelay; public : FORECAST(); void Init (EthernetClient& clnt,int timeZone); struct _WeatherPacket { int P; // int T; // int H; // int WS; //  char WD[4]; // char Icon[4]; //Icon }; typedef wdPack _WeatherDay[4]; typedef whPack _WeatherThreeHour[16]; int GetForecast(_WeatherPacket& whr); int GetForecastDays(_WeatherDay *wdp); int GetForecast3Hour(_WeatherThreeHour *whp); int iPacket3H; time_t SunRise; time_t SunSet; boolean fDebug; }; #endif 


forecast.cpp
 #include "forecast.h" #include "math.h" #include <string.h> #include <stdlib.h> #include <math.h> #include <Time.h> #include <avr/pgmspace.h> ////////////////////////////////////////////////////////////////////////// //     w5100    2 (4   2) //  XML    3    15-18 //           //  4 (  1   8,     ). ////////////////////////////////////////////////////////////////////////// //       w5100.h // MAX_SOCK_NUM 2 // SOCKETS = 2; // SMASK = 0x0FFF; // Tx buffer MASK // RMASK = 0x0FFF; // Rx buffer MASK // SSIZE = 4096; // Max Tx buffer size // RSIZE = 4096; // Max Rx buffer size ////////////////////////////////////////////////////////////////////////// //   w5100.cpp // TX_RX_MAX_BUF_SIZE 4096 // writeTMSR(0xAA); // writeRMSR(0xAA); ////////////////////////////////////////////////////////////////////////// //   Ethernet.h // MAX_SOCK_NUM 2 ////////////////////////////////////////////////////////////////////////// //   Ethernet.cpp // uint8_t EthernetClass::_state[MAX_SOCK_NUM] = { 0, 0 }; // uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = { 0 , 0 }; ////////////////////////////////////////////////////////////////////////// #include <Ethernet.h> /////////////////////////////////////////////////////////////////////////////////////////////// //    PROGMEM ,   .    504  RAM const char p_FCserver[] PROGMEM = "api.openweathermap.org"; const char p_APIID[] PROGMEM = "&APPID="; //    API-,    ! const char p_request3Hour[] PROGMEM = "GET /data/2.5/forecast?q=Krasnoyarsk&mode=xml&units=metric"; const char p_request4Day[] PROGMEM = "GET /data/2.5/forecast/daily?q=Krasnoyarsk&mode=xml&units=metric&cnt=4"; const char p_requestToDay[] PROGMEM = "GET /data/2.5/weather?q=Krasnoyarsk&mode=xml&units=metric"; const char p_ConnClose[] PROGMEM = "Connection: close"; const char p_HTTP[] PROGMEM = " HTTP/1.1"; PGM_P const string_table[] PROGMEM = {p_FCserver, p_APIID,p_request3Hour,p_request4Day,p_requestToDay,p_ConnClose,p_HTTP}; char words[80]; /////////////////////////////////////////////////////////////////////////////////////////////// #define MAX_STRING_LEN 100 char tagStr[MAX_STRING_LEN] = ""; char tmpStr[MAX_STRING_LEN] = ""; char endTag[3] = {'<', '/', '\0'}; char inChar; //  FORECAST::FORECAST() { fDebug = false; } //       EthernetClient,    //         , ..      void FORECAST::Init(EthernetClient& clnt, int timeZone) { client = clnt; tZone = timeZone; tDelay = 1000; } //  3   (2    3 ) int FORECAST::GetForecast3Hour(FORECAST::_WeatherThreeHour *whp) { int p1 = 0,p2 = 0; char TMP[20]; String temp = ""; float T; if (client.connected()) client.stop(); if (client.connect(GetWord(0), 80)) { temp = GetWord(2); //temp += GetWord(1); temp += GetWord(6); //if (fDebug) Serial.println(temp); client.println(temp); client.print("Host: "); client.println(GetWord(0)); client.println(GetWord(5)); client.println(); temp = ""; //    ,     -  while (!client.available()) { p1++; delay(50); if ( p1 > tDelay ) { client.stop(); return 0; } } iPacket3H = 0; while (client.available()) { //----------------------------------------------------------- inChar = client.read(); if (inChar == '<') //   { addChar(inChar, tmpStr); tagFlag = true; } else if (inChar == '>') //   { addChar(inChar, tmpStr); if (tagFlag) //      { strncpy(tagStr, tmpStr, strlen(tmpStr)+1); } clearStr(tmpStr); tagFlag = false; } else if (inChar != 10) { if (tagFlag) { addChar(inChar, tmpStr); // Check for </XML> end tag, ignore it if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) { clearStr(tmpStr); tagFlag = false; } } } //    -   if ((inChar == 10 ) || (inChar == '>')) { dataString = tagStr; if( !strncmp(tagStr,"<time from",10)) { //<time from="2014-11-26T03:00:00" to="2014-11-26T06:00:00"> //if (fDebug) Serial.println(tagStr); p1 = dataString.indexOf('"',1); p1++; p2 = dataString.indexOf('"',p1); temp = dataString.substring(p1,p2-3); temp.replace("T"," "); temp.toCharArray(TMP,temp.length()+1); (*whp)[iPacket3H].Data = _ConvertDateTime(TMP); } else if( !strncmp(tagStr,"<symbol",7)) { // <symbol number="600" name="light snow" var="13d"/> p1 = dataString.indexOf("var"); SubStrA(p1,dataString,temp); temp.toCharArray((*whp)[iPacket3H].Icon,temp.length()+1); } else if( !strncmp(tagStr,"<precipitation",14)) { // <precipitation unit="3h" value="0.125" type="rain"> //if (fDebug) Serial.println(tagStr); int sign; clearStr(TMP); if (dataString.indexOf("rain") > 0) sign = 1; //  else if (dataString.indexOf("snow") > 0 || dataString.indexOf("show") > 0) sign = -1; //  //29.09.2015 -       snow  show else sign = 0; //   p1 = dataString.indexOf("value"); if (sign != 0) { SubStrA(p1,dataString,temp); temp.toCharArray(TMP,temp.length()+1); (*whp)[iPacket3H].RainVal = atof(TMP) * sign * 100; } else (*whp)[iPacket3H].RainVal = 0; } else if( !strncmp(tagStr,"<windDirection",14)) { //<windDirection deg="235" code="SW" name="Southwest"/> p1 = dataString.indexOf("code"); SubStrA(p1,dataString,temp); temp.toCharArray((*whp)[iPacket3H].WD,temp.length()+1); } else if( !strncmp(tagStr,"<windSpeed",10)) { //<windSpeed mps="4.62" name="Gentle Breeze"/> clearStr(TMP); SubStrA(1,dataString,temp); temp.toCharArray(TMP,temp.length()+1); T = atof(TMP); (*whp)[iPacket3H].WS = round(T); } else if( !strncmp(tagStr,"<temperature",12)) { //<temperature unit="celsius" value="-12.92" min="-17.91" max="-12.92"/> clearStr(TMP); p1 = dataString.indexOf("value"); SubStrA(p1,dataString,temp); temp.toCharArray(TMP,temp.length()+1); T = atof(TMP); (*whp)[iPacket3H].T = round(T); if (T < 0) p1 = dataString.indexOf("min"); else p1 = dataString.indexOf("max"); clearStr(TMP); SubStrA(p1,dataString,temp); temp.toCharArray(TMP,temp.length()+1); T = atof(TMP); (*whp)[iPacket3H].TT = round(T); } else if( !strncmp(tagStr,"<pressure",9)) { //<pressure unit="hPa" value="999.14"/> p1 = dataString.indexOf("value"); SubStrA(p1,dataString,temp); (*whp)[iPacket3H].P = temp.toInt(); (*whp)[iPacket3H].P =((*whp)[iPacket3H].P * 0.75); // - 17 } else if( !strncmp(tagStr,"<humidity",9)) { //<humidity value="73" unit="%"/> SubStrA(1,dataString,temp); (*whp)[iPacket3H].H = temp.toInt(); } else if( !strncmp(tagStr,"<clouds",7)) { // <clouds value="broken clouds" all="56" unit="%"/> p1 = dataString.indexOf("all"); SubStrA(p1,dataString,temp); (*whp)[iPacket3H].Cloud = temp.toInt(); iPacket3H++; } clearStr(tmpStr); clearStr(tagStr); tagFlag = false; } //----------------------------------------------------------- if (iPacket3H==16) {break;} } client.stop(); return 1; } else {return 0;} } ///////////////////////////////////////////////  4  /////////////////////////////////////////////////////// /* int FORECAST::GetForecastDays(FORECAST::_WeatherDay* wdp) { int iPack=0,p=0; char TMP[20]; String temp; float T; if (client.connected()) client.stop(); if (client.connect(GetWord(0), 80)) { temp = GetWord(3); //temp += GetWord(1); temp += GetWord(6); if (fDebug) Serial.println(temp); client.println(temp); client.print("Host: "); client.println(GetWord(0)); client.println(GetWord(5)); client.println(); temp = ""; while (!client.available()) { p++; delay(50); if ( p > tDelay ) { client.stop(); return 0; } } while (client.available()) { inChar = client.read(); if (inChar == '<') //   { addChar(inChar, tmpStr); tagFlag = true; } else if (inChar == '>') //   { addChar(inChar, tmpStr); if (tagFlag) //      { strncpy(tagStr, tmpStr, strlen(tmpStr)+1); } clearStr(tmpStr); tagFlag = false; } else if (inChar != 10) { if (tagFlag) { addChar(inChar, tmpStr); // Check for </XML> end tag, ignore it if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) { clearStr(tmpStr); tagFlag = false; } } } //    -   if ((inChar == 10 ) || (inChar == '>')) { dataString = tagStr; if( !strncmp(tagStr,"<time day",9)) { //<time day="2014-10-09"> SubStrA(1,dataString,temp); //temp.toCharArray((*wdp)[iPack].Data,temp.length()+1); temp.toCharArray(TMP,temp.length()+1); (*wdp)[iPack].Data = _ConvertDate(TMP); //if (fDebug) Serial.println(temp); } else if( !strncmp(tagStr,"<symbol",7)) { // <symbol number="600" name="light snow" var="13d"/> p = dataString.indexOf("var"); SubStrA(p,dataString,temp); temp.toCharArray((*wdp)[iPack].Icon,temp.length()+1); } else if( !strncmp(tagStr,"<precipitation",14)) { // <precipitation value="1.25" type="snow"/> int sign; clearStr(TMP); if (dataString.indexOf("rain") > 0) sign = 1; //  else if (dataString.indexOf("snow") > 0 || dataString.indexOf("show") > 0) sign = -1; //  else sign = 0; //   if (sign != 0) { p=1; SubStrA(p,dataString,temp); temp.toCharArray(TMP,temp.length()+1); (*wdp)[iPack].RainVal = atof(TMP) * sign * 100; } else (*wdp)[iPack].RainVal = 0; } else if( !strncmp(tagStr,"<windDirection",14)) { //<windDirection deg="235" code="SW" name="Southwest"/> p = dataString.indexOf("code"); SubStrA(p,dataString,temp); temp.toCharArray((*wdp)[iPack].WD,temp.length()+1); } else if( !strncmp(tagStr,"<windSpeed",10)) { //<windSpeed mps="4.62" name="Gentle Breeze"/> clearStr(TMP); SubStrA(1,dataString,temp); temp.toCharArray(TMP,temp.length()+1); T = atof(TMP); (*wdp)[iPack].WS = round(T); } else if( !strncmp(tagStr,"<temperature",12)) { //<temperature day="4.48" min="-1.12" max="4.48" night="-0.94" eve="-1.12" morn="2.26"/> clearStr(TMP); SubStrA(1,dataString,temp); temp.toCharArray(TMP,temp.length()+1); T = atof(TMP); (*wdp)[iPack].TD = round(T); clearStr(TMP); p = dataString.indexOf("night"); SubStrA(p,dataString,temp); temp.toCharArray(TMP,temp.length()+1); T = atof(TMP); (*wdp)[iPack].TN = round(T); } else if( !strncmp(tagStr,"<pressure",9)) { //<pressure unit="hPa" value="999.14"/> p = dataString.indexOf("value"); SubStrA(p,dataString,temp); (*wdp)[iPack].P = temp.toInt(); (*wdp)[iPack].P =((*wdp)[iPack].P * 0.75 - 17); } else if( !strncmp(tagStr,"<humidity",9)) { //<humidity value="73" unit="%"/> SubStrA(1,dataString,temp); (*wdp)[iPack].H = temp.toInt(); } else if( !strncmp(tagStr,"<clouds",7)) { // <clouds value="broken clouds" all="56" unit="%"/> p = dataString.indexOf("all"); SubStrA(p,dataString,temp); (*wdp)[iPack].Cloud = temp.toInt(); iPack++; } clearStr(tmpStr); clearStr(tagStr); tagFlag = false; } } //   client.stop(); return 1; } else {return 0;} } */ /////////////////////////////    ////////////////////////////////////////////////////////////// /* int FORECAST::GetForecast(FORECAST::_WeatherPacket& whr) { int p1 = 0; char TMP[20]; String temp = ""; float T; int step = 0; if (client.connected()) client.stop(); if (client.connect(GetWord(0), 80)) { temp = GetWord(4); //temp += GetWord(1); temp += GetWord(6); if (fDebug) Serial.println(temp); client.println(temp); client.print("Host: "); client.println(GetWord(0)); client.println(GetWord(5)); client.println(); temp = ""; while (!client.available()) //     { p1++; delay(50); if ( p1 > tDelay ) //    -   { client.stop(); return 0; } } while (client.available()) //  -   { // Read a char inChar = client.read(); //if (fDebug) Serial.print(inChar); if (inChar == '<') { addChar(inChar, tmpStr); tagFlag = true; } else if (inChar == '>') { addChar(inChar, tmpStr); if (tagFlag) { strncpy(tagStr, tmpStr, strlen(tmpStr)+1); } clearStr(tmpStr); tagFlag = false; dataFlag = true; } else if (inChar != 10) { if (tagFlag) { addChar(inChar, tmpStr); // Check for </XML> end tag, ignore it if ( tagFlag && strcmp(tmpStr, endTag) == 0 ) { clearStr(tmpStr); tagFlag = false; dataFlag = false; } } } // If a LF, process the line if ((inChar == 10 ) || (inChar == '>')) { dataString = tagStr; if( !strncmp(tagStr,"<sun",4)) { // <sun rise="2014-10-14T00:18:33" set="2014-10-14T10:51:01"/> SubStrA(1,dataString,temp); temp.replace("T"," "); temp.toCharArray(TMP,temp.length()+1); if (fDebug) {Serial.print("SunRise_w_");Serial.println(TMP);} SunRise = _ConvertDateTime(TMP); p1 = dataString.indexOf("set"); p1++; SubStrA(p1,dataString,temp); temp.replace("T"," "); temp.toCharArray(TMP,temp.length()+1); SunSet = _ConvertDateTime(TMP); step++; } else if( !strncmp(tagStr,"<temperature",12)) { //<temperature value="-9.86" min="-16" max="-6.3" unit="celsius"/> clearStr(TMP); SubStrA(1,dataString,temp); temp.toCharArray(TMP,temp.length()+1); T = atof(TMP); whr.T = round(T); step++; if (fDebug) Serial.println(tagStr); } else if( !strncmp(tagStr,"<humidity",9)) { //<humidity value="65" unit="%"/> SubStrA(1,dataString,temp); whr.H = temp.toInt(); step++; } else if( !strncmp(tagStr,"<pressure",9) ) { //<pressure value="1027" unit="hPa"/> SubStrA(1,dataString,temp); // whr.P = round(temp.toInt() * 0.75 - 17); whr.P = temp.toInt() ; step++; if (fDebug) Serial.println(tagStr); } else if( !strncmp(tagStr,"<speed",6) ) { //<speed value="1.51" name=""/> clearStr(TMP); SubStrA(1,dataString,temp); temp.toCharArray(TMP,temp.length()+1); T = atof(TMP); whr.WS = round(T); step++; if (fDebug) Serial.println(tagStr); } else if( !strncmp(tagStr,"<direction",10) ) { //<direction value="160.501" code="SSE" name="South-southeast"/> p1 = dataString.indexOf("code"); SubStrB(p1,dataString,temp); temp.toCharArray(whr.WD,temp.length()+1); step++; if (fDebug) Serial.println(tagStr); } else if( !strncmp(tagStr,"<weather",8) ) { //<weather number="803" value="broken clouds" icon="04d"/> p1 = dataString.indexOf("icon"); SubStrA(p1,dataString,temp); temp.toCharArray(whr.Icon,temp.length()+1); step++; if (fDebug) {Serial.println(tagStr);Serial.println("-------------------");} } clearStr(tmpStr); clearStr(tagStr); tagFlag = false; dataFlag = false; } } //   client.stop(); if (step > 5) return 1; else return 0; } else {return 0;} } */ ////////////////////   //////////////////////////////////////////////////// void FORECAST::SubStrA(int Num,String& source, String& str) { int p1 = source.indexOf('"',Num); p1++; int p2 = source.indexOf('"',p1); str = source.substring(p1,p2); } //          void FORECAST::SubStrB(int Num,String& source, String& str) { int p1 = source.indexOf('"',Num); p1++; int p2 = source.indexOf('"',p1+1); if (p2 - p1 < 1) str = "WNW"; else str = source.substring(p1,p2); } //Function to add a char to a string and check its length void FORECAST::addChar(char ch, char* str) { char const *tagMsg = "!=!"; if (strlen(str) > MAX_STRING_LEN - 2) { if (tagFlag) { clearStr(tagStr); strcpy(tagStr,tagMsg); } // Clear the temp buffer and flags to stop current processing clearStr(tmpStr); tagFlag = false; } else { // Add char to string str[strlen(str)] = ch; } } // Function to clear a string void FORECAST::clearStr(char* str) { int len = strlen(str); for (int c = 0; c < len; c++) { str[c] = 0; } } time_t FORECAST::_ConvertDate(char _Data[11]) { int Y, M, D; TimeElements te; sscanf ( _Data,"%i-%d-%d", &Y, &M, &D); te.Year = Y -1900; te.Month = M; te.Day = D; te.Hour=0; te.Minute=0; te.Second=0; return makeTime(te); } time_t FORECAST::_ConvertDateTime(char _DateTime[17]) { int Y, M, D, hh, mm; TimeElements te; //   (    ) sscanf ( _DateTime,"%i-%d-%d %d:%d", &Y, &M, &D, &hh, &mm ); //     TimeZone hh = hh + tZone; if (hh > 24) { hh = hh - 24; if ( (M == 2 && D == 28 && Y%4 != 0)|| (M == 2 && D == 29 && Y%4 == 0) || ((M == 1 || M == 3 || M == 5 || M == 7 || M == 8 || M == 10 || M == 12) && D == 31) || ((M == 4 || M == 6 || M == 9 || M == 11) && D == 30) ) { M++; D = 1; if (M==13) {M=1;Y++;} } else D++; } te.Year = Y -1900; te.Month = M; te.Day = D; te.Hour = hh; te.Minute = mm; te.Second=0; return makeTime(te); } //    flash -   № char* FORECAST::GetWord(uint8_t numWord) { strcpy_P(words, (PGM_P)pgm_read_word(&(string_table[numWord]))); return words; } 


Forecast.ino
 #include <Time.h> #include <SPI.h> #include <Ethernet.h> #include "forecast.h" /////////////////////////////////////////////////// byte mac[] = { 0xEA, 0xCD, 0xCE, 0x17, 0x19, 0x66 }; char server[] = "192.168.1.120"; //      EthernetClient client; ////////////////////////////////////////////////// //    FORECAST frc; FORECAST::_WeatherPacket weather; //     FORECAST::_WeatherDay wPack1Day; //      4  (  ) FORECAST::_WeatherThreeHour wPack3Hour; // 3       2  //   4   const unsigned long dInterval = 300000; unsigned long last_dForecast; //   3   const unsigned long hInterval = 300000; // unsigned long last_hForecast; //           const unsigned long wInterval = 200000; //~30 . unsigned long last_wForecast; ////////////////////////////////////// #define DEBUG_MODE 1 ////////////////////////////////////// void setup() { frc.fDebug = false; if (Ethernet.begin(mac) == 0) { while (1) { delay(1000); } } //    unsigned long now = millis(); frc.Init(client, 7); last_wForecast = now - wInterval + 2000; last_hForecast = now - hInterval + 15000; last_dForecast = now - dInterval + 25000; } void loop() { unsigned long now = millis(); /* if ( now - last_wForecast > wInterval ) { if (frc.GetForecast(weather) == 1) //     { last_wForecast = now; } } */ if ( now - last_hForecast > hInterval) { if (frc.GetForecast3Hour(&wPack3Hour) == 1) //   2   3  { if ( frc.iPacket3H > 2 ) //   ,   2 last_hForecast = millis(); else last_hForecast = millis() - hInterval + 30000; PrintForecast3H(); } } /* if ( now - last_dForecast > dInterval) { if (frc.GetForecastDays(&wPack1Day) == 1) //   4  { last_dForecast = millis(); PrintForecastDay(); } } */ } void ConvertDT(time_t tt, char dt[17]) { TimeElements t_e; int Y, M, D, hh, mm; breakTime(tt, t_e); Y = t_e.Year + 1900; M = t_e.Month; D = t_e.Day; hh = t_e.Hour; mm = t_e.Minute; sprintf(dt, "%i.%i.%i %i:%i", D, M, Y, hh, mm); } void PrintForecast3H() { char DT[17]; for (int i = 0; i < frc.iPacket3H; i++) { ConvertDT(wPack3Hour[i].Data, DT); Serial.print("Data= "); Serial.print(DT); Serial.print("; "); Serial.print(wPack3Hour[i].RainVal / 100.0); Serial.print("; "); Serial.print(wPack3Hour[i].WS); Serial.print("; "); Serial.print(wPack3Hour[i].WD); Serial.print("; "); Serial.print(wPack3Hour[i].T); Serial.print("; "); Serial.print(wPack3Hour[i].TT); Serial.print("; "); Serial.print(wPack3Hour[i].H); Serial.print("; "); Serial.print(wPack3Hour[i].P); Serial.print("; "); Serial.println(wPack3Hour[i].Icon); } } /* void ConvertD(time_t tt, char dd[11]) { TimeElements t_e; int Y, M, D; breakTime(tt, t_e); Y = t_e.Year + 1900; M = t_e.Month; D = t_e.Day; sprintf(dd, "%i.%i.%i", D, M, Y); } void PrintForecastDay() { char D[11]; for (int i = 0; i < 4; i++) { ConvertD(wPack1Day[i].Data, D); Serial.print("Data= "); Serial.print(D); Serial.print("; "); Serial.print(wPack1Day[i].RainVal / 100.0); Serial.print("; "); Serial.print(wPack1Day[i].WS); Serial.print("; "); Serial.print(wPack1Day[i].WD); Serial.print("; "); Serial.print(wPack1Day[i].TD); Serial.print("; "); Serial.print(wPack1Day[i].TN); Serial.print("; "); Serial.print(wPack1Day[i].P); Serial.print("; "); Serial.print(wPack1Day[i].H); Serial.print("; "); Serial.print(wPack1Day[i].Cloud); Serial.print("; "); Serial.println(wPack1Day[i].Icon); } } */ 

Source: https://habr.com/ru/post/357884/


All Articles