Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ukmetoffice.js 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /* global WeatherProvider, WeatherObject */
  2. /* Magic Mirror
  3. * Module: Weather
  4. *
  5. * By Malcolm Oakes https://github.com/maloakes
  6. * MIT Licensed.
  7. *
  8. * This class is a provider for UK Met Office Datapoint.
  9. */
  10. WeatherProvider.register("ukmetoffice", {
  11. // Set the name of the provider.
  12. // This isn't strictly necessary, since it will fallback to the provider identifier
  13. // But for debugging (and future alerts) it would be nice to have the real name.
  14. providerName: "UK Met Office",
  15. // Set the default config properties that is specific to this provider
  16. defaults: {
  17. apiBase: "http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/json/",
  18. locationID: false,
  19. apiKey: ""
  20. },
  21. units: {
  22. imperial: "us",
  23. metric: "si"
  24. },
  25. // Overwrite the fetchCurrentWeather method.
  26. fetchCurrentWeather() {
  27. this.fetchData(this.getUrl("3hourly"))
  28. .then((data) => {
  29. if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) {
  30. // Did not receive usable new data.
  31. // Maybe this needs a better check?
  32. return;
  33. }
  34. this.setFetchedLocation(`${data.SiteRep.DV.Location.name}, ${data.SiteRep.DV.Location.country}`);
  35. const currentWeather = this.generateWeatherObjectFromCurrentWeather(data);
  36. this.setCurrentWeather(currentWeather);
  37. })
  38. .catch(function (request) {
  39. Log.error("Could not load data ... ", request);
  40. })
  41. .finally(() => this.updateAvailable());
  42. },
  43. // Overwrite the fetchCurrentWeather method.
  44. fetchWeatherForecast() {
  45. this.fetchData(this.getUrl("daily"))
  46. .then((data) => {
  47. if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) {
  48. // Did not receive usable new data.
  49. // Maybe this needs a better check?
  50. return;
  51. }
  52. this.setFetchedLocation(`${data.SiteRep.DV.Location.name}, ${data.SiteRep.DV.Location.country}`);
  53. const forecast = this.generateWeatherObjectsFromForecast(data);
  54. this.setWeatherForecast(forecast);
  55. })
  56. .catch(function (request) {
  57. Log.error("Could not load data ... ", request);
  58. })
  59. .finally(() => this.updateAvailable());
  60. },
  61. /** UK Met Office Specific Methods - These are not part of the default provider methods */
  62. /*
  63. * Gets the complete url for the request
  64. */
  65. getUrl(forecastType) {
  66. return this.config.apiBase + this.config.locationID + this.getParams(forecastType);
  67. },
  68. /*
  69. * Generate a WeatherObject based on currentWeatherInformation
  70. */
  71. generateWeatherObjectFromCurrentWeather(currentWeatherData) {
  72. const currentWeather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
  73. const location = currentWeatherData.SiteRep.DV.Location;
  74. // data times are always UTC
  75. let nowUtc = moment.utc();
  76. let midnightUtc = nowUtc.clone().startOf("day");
  77. let timeInMins = nowUtc.diff(midnightUtc, "minutes");
  78. // loop round each of the (5) periods, look for today (the first period may be yesterday)
  79. for (const period of location.Period) {
  80. const periodDate = moment.utc(period.value.substr(0, 10), "YYYY-MM-DD");
  81. // ignore if period is before today
  82. if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
  83. // check this is the period we want, after today the diff will be -ve
  84. if (moment().diff(periodDate, "minutes") > 0) {
  85. // loop round the reports looking for the one we are in
  86. // $ value specifies the time in minutes-of-the-day: 0, 180, 360,...1260
  87. for (const rep of period.Rep) {
  88. const p = rep.$;
  89. if (timeInMins >= p && timeInMins - 180 < p) {
  90. // finally got the one we want, so populate weather object
  91. currentWeather.humidity = rep.H;
  92. currentWeather.temperature = this.convertTemp(rep.T);
  93. currentWeather.feelsLikeTemp = this.convertTemp(rep.F);
  94. currentWeather.precipitation = parseInt(rep.Pp);
  95. currentWeather.windSpeed = this.convertWindSpeed(rep.S);
  96. currentWeather.windDirection = this.convertWindDirection(rep.D);
  97. currentWeather.weatherType = this.convertWeatherType(rep.W);
  98. }
  99. }
  100. }
  101. }
  102. }
  103. // determine the sunrise/sunset times - not supplied in UK Met Office data
  104. currentWeather.updateSunTime(location.lat, location.lon);
  105. return currentWeather;
  106. },
  107. /*
  108. * Generate WeatherObjects based on forecast information
  109. */
  110. generateWeatherObjectsFromForecast(forecasts) {
  111. const days = [];
  112. // loop round the (5) periods getting the data
  113. // for each period array, Day is [0], Night is [1]
  114. for (const period of forecasts.SiteRep.DV.Location.Period) {
  115. const weather = new WeatherObject(this.config.units, this.config.tempUnits, this.config.windUnits, this.config.useKmh);
  116. // data times are always UTC
  117. const dateStr = period.value;
  118. let periodDate = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD");
  119. // ignore if period is before today
  120. if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
  121. // populate the weather object
  122. weather.date = moment.utc(dateStr.substr(0, 10), "YYYY-MM-DD");
  123. weather.minTemperature = this.convertTemp(period.Rep[1].Nm);
  124. weather.maxTemperature = this.convertTemp(period.Rep[0].Dm);
  125. weather.weatherType = this.convertWeatherType(period.Rep[0].W);
  126. weather.precipitation = parseInt(period.Rep[0].PPd);
  127. days.push(weather);
  128. }
  129. }
  130. return days;
  131. },
  132. /*
  133. * Convert the Met Office icons to a more usable name.
  134. */
  135. convertWeatherType(weatherType) {
  136. const weatherTypes = {
  137. 0: "night-clear",
  138. 1: "day-sunny",
  139. 2: "night-alt-cloudy",
  140. 3: "day-cloudy",
  141. 5: "fog",
  142. 6: "fog",
  143. 7: "cloudy",
  144. 8: "cloud",
  145. 9: "night-sprinkle",
  146. 10: "day-sprinkle",
  147. 11: "raindrops",
  148. 12: "sprinkle",
  149. 13: "night-alt-showers",
  150. 14: "day-showers",
  151. 15: "rain",
  152. 16: "night-alt-sleet",
  153. 17: "day-sleet",
  154. 18: "sleet",
  155. 19: "night-alt-hail",
  156. 20: "day-hail",
  157. 21: "hail",
  158. 22: "night-alt-snow",
  159. 23: "day-snow",
  160. 24: "snow",
  161. 25: "night-alt-snow",
  162. 26: "day-snow",
  163. 27: "snow",
  164. 28: "night-alt-thunderstorm",
  165. 29: "day-thunderstorm",
  166. 30: "thunderstorm"
  167. };
  168. return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null;
  169. },
  170. /*
  171. * Convert temp (from degrees C) if required
  172. */
  173. convertTemp(tempInC) {
  174. return this.tempUnits === "imperial" ? (tempInC * 9) / 5 + 32 : tempInC;
  175. },
  176. /*
  177. * Convert wind speed (from mph to m/s or km/h) if required
  178. */
  179. convertWindSpeed(windInMph) {
  180. return this.windUnits === "metric" ? (this.useKmh ? windInMph * 1.60934 : windInMph / 2.23694) : windInMph;
  181. },
  182. /*
  183. * Convert the wind direction cardinal to value
  184. */
  185. convertWindDirection(windDirection) {
  186. const windCardinals = {
  187. N: 0,
  188. NNE: 22,
  189. NE: 45,
  190. ENE: 67,
  191. E: 90,
  192. ESE: 112,
  193. SE: 135,
  194. SSE: 157,
  195. S: 180,
  196. SSW: 202,
  197. SW: 225,
  198. WSW: 247,
  199. W: 270,
  200. WNW: 292,
  201. NW: 315,
  202. NNW: 337
  203. };
  204. return windCardinals.hasOwnProperty(windDirection) ? windCardinals[windDirection] : null;
  205. },
  206. /**
  207. * Generates an url with api parameters based on the config.
  208. *
  209. * @param {string} forecastType daily or 3hourly forecast
  210. * @returns {string} url
  211. */
  212. getParams(forecastType) {
  213. let params = "?";
  214. params += "res=" + forecastType;
  215. params += "&key=" + this.config.apiKey;
  216. return params;
  217. }
  218. });