weather.ino 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /*
  2. Weather Access API
  3. Information provided by the Hong Kong Observatory open data API
  4. */
  5. //Scheduler entry point, update today weather information (executed per hr)
  6. void todayWeatherUpdateCallback() {
  7. updateCurrentWeatherInfo();
  8. renderHomepageWeatherInfo();
  9. }
  10. //Scheduler entry point, updated every 6 hr
  11. void weatherForcastCallback() {
  12. updateAndRenderForcastInfo();
  13. }
  14. //Current weather info
  15. const char* rhurl = "https://data.weather.gov.hk/weatherAPI/opendata/weather.php?dataType=rhrread&lang=en";
  16. //Weather forcast info
  17. const char* wfurl = "https://data.weather.gov.hk/weatherAPI/opendata/weather.php?dataType=fnd&lang=en";
  18. /*
  19. Weather Forcast Loaders
  20. */
  21. bool updateAndRenderForcastInfo() {
  22. Serial.println("Updating weather forcast info...");
  23. WiFiClientSecure httpsClient; // Use WiFiClientSecure for HTTPS
  24. httpsClient.setInsecure(); // Ignore SSL certificate verification (for simplicity)
  25. if (httpsClient.connect("data.weather.gov.hk", 443)) {
  26. Serial.println("Downloading forcast info");
  27. httpsClient.print(String("GET ") + wfurl + " HTTP/1.1\r\n" +
  28. "Host: data.weather.gov.hk\r\n" +
  29. "Connection: close\r\n\r\n");
  30. String response = "";
  31. //Skip through the headers
  32. while (httpsClient.connected()) {
  33. String line = httpsClient.readStringUntil('\n');
  34. if (line == "\r") {
  35. break;
  36. }
  37. }
  38. //Read the JSON body
  39. String line = "";
  40. while (httpsClient.available()) {
  41. line = httpsClient.readStringUntil('\n'); //Read Line by Line
  42. response += line;
  43. }
  44. //Trim the first unwannted byte and the last
  45. int startTrimPos = response.indexOf("{");
  46. int lastTrimPos = response.lastIndexOf("}");
  47. response = response.substring(startTrimPos, lastTrimPos + 1);
  48. //Serial.println(response);
  49. if (response.length() < 10){
  50. changePage("error");
  51. sendCommand("t1.txt=\"Invalid resp: " + response + "\"");
  52. delay(10000);
  53. changePage("home");
  54. return false;
  55. }
  56. // Build the filter
  57. StaticJsonDocument<1024> filter;
  58. for (int i = 0; i < 7; i++) {
  59. filter["weatherForecast"][i]["week"] = true;
  60. filter["weatherForecast"][i]["forecastMintemp"]["value"] = true;
  61. filter["weatherForecast"][i]["forecastMaxtemp"]["value"] = true;
  62. filter["weatherForecast"][i]["forecastMaxrh"]["value"] = true;
  63. filter["weatherForecast"][i]["ForecastIcon"] = true;
  64. }
  65. // Parse JSON data
  66. StaticJsonDocument<5120> jsonDoc;
  67. auto error = deserializeJson(jsonDoc, response, DeserializationOption::Filter(filter));
  68. if (error) {
  69. Serial.print(F("deserializeJson() failed with code "));
  70. Serial.println(error.c_str());
  71. return false;
  72. }
  73. //serializeJsonPretty(jsonDoc, Serial);
  74. //Render the weather forcast onto the HMI
  75. for (int i = 0; i < 7; i++) {
  76. //Get day of week
  77. String dow = jsonDoc["weatherForecast"][i]["week"];
  78. dow = dow.substring(0, 3);
  79. //Get min-max temp
  80. int minTemp = jsonDoc["weatherForecast"][i]["forecastMintemp"]["value"];
  81. int maxTemp = jsonDoc["weatherForecast"][i]["forecastMaxtemp"]["value"];
  82. int maxRh = jsonDoc["weatherForecast"][i]["forecastMaxrh"]["value"];
  83. //Get forcast icon
  84. int forcastIcon = jsonDoc["weatherForecast"][i]["ForecastIcon"];
  85. renderForcastField(String(i), dow, minTemp, maxTemp, maxRh, forcastIcon);
  86. }
  87. }
  88. return true;
  89. }
  90. /*
  91. Current Weather Loaders
  92. */
  93. //Render the homepage weather info from the buffered information
  94. void renderHomepageWeatherInfo() {
  95. if (currentPage == 0) {
  96. printIntCommand("home.temp.txt=", currentTemp);
  97. printIntCommand("home.humd.txt=", currentHumd);
  98. printIntCommand("home.rain.txt=", currentRain);
  99. //Change the main weather icon
  100. if (isNight()) {
  101. if (currentIsRaining) {
  102. sendCommand("home.wicon.pic=11");
  103. } else {
  104. sendCommand("home.wicon.pic=7");
  105. }
  106. } else {
  107. if (currentIsRaining) {
  108. sendCommand("home.wicon.pic=11");
  109. } else {
  110. sendCommand("home.wicon.pic=6");
  111. }
  112. }
  113. }
  114. }
  115. void updateCurrentWeatherInfo() {
  116. WiFiClientSecure httpsClient; // Use WiFiClientSecure for HTTPS
  117. httpsClient.setInsecure(); // Ignore SSL certificate verification (for simplicity)
  118. if (httpsClient.connect("data.weather.gov.hk", 443)) {
  119. Serial.println("Downloading current weather info");
  120. httpsClient.print(String("GET ") + rhurl + " HTTP/1.1\r\n" +
  121. "Host: data.weather.gov.hk\r\n" +
  122. "Connection: close\r\n\r\n");
  123. String response = "";
  124. //Skip through the headers
  125. while (httpsClient.connected()) {
  126. String line = httpsClient.readStringUntil('\n');
  127. if (line == "\r") {
  128. break;
  129. }
  130. }
  131. //Read the JSON body
  132. String line;
  133. while (httpsClient.available()) {
  134. line = httpsClient.readStringUntil('\n'); //Read Line by Line
  135. response += line;
  136. }
  137. //Trim the first unwannted byte and the last
  138. int startTrimPos = response.indexOf("{");
  139. int lastTrimPos = response.lastIndexOf("}");
  140. response = response.substring(startTrimPos, lastTrimPos + 1);
  141. //Serial.println(response);
  142. // Build the filter
  143. StaticJsonDocument<1024> filter;
  144. filter["temperature"]["data"][0]["value"] = true;
  145. filter["humidity"]["data"][0]["value"] = true;
  146. filter["rainfall"]["data"][0]["max"] = true;
  147. filter["rainfall"]["data"][0]["main"] = true;
  148. // Parse JSON data
  149. /*
  150. DynamicJsonDocument jsonDoc(8192); // Change the size according to your JSON data
  151. auto error = deserializeJson(jsonDoc, response);
  152. if (error) {
  153. Serial.print(F("deserializeJson() failed with code "));
  154. Serial.println(error.c_str());
  155. return;
  156. }
  157. */
  158. // Parse JSON data
  159. StaticJsonDocument<4096> jsonDoc;
  160. auto error = deserializeJson(jsonDoc, response, DeserializationOption::Filter(filter));
  161. if (error) {
  162. Serial.print(F("deserializeJson() failed with code "));
  163. Serial.println(error.c_str());
  164. return;
  165. }
  166. // Access and return the temperature value
  167. currentTemp = jsonDoc["temperature"]["data"][19]["value"];
  168. currentHumd = jsonDoc["humidity"]["data"][0]["value"];
  169. currentRain = jsonDoc["rainfall"]["data"][16]["max"];
  170. currentIsRaining = String(jsonDoc["rainfall"]["data"][16]["main"]) == "TRUE";
  171. // Serial debug prints
  172. Serial.println(int(jsonDoc["temperature"]["data"][19]["value"]));
  173. Serial.println(int(jsonDoc["humidity"]["data"][0]["value"]));
  174. Serial.println(int(jsonDoc["rainfall"]["data"][16]["max"]));
  175. Serial.println(String(jsonDoc["rainfall"]["data"][16]["main"]));
  176. } else {
  177. Serial.println("Failed to connect to server");
  178. }
  179. }