OpenWeather: Weather History, Get by Time
OpenWeather: Weather History, Get by Time
Gets weather history for the specific time from OpenWeather (corrected to zero minutes) with the specified latitude and longitude. Temperature, humidity and wind speed can be obtained as well as snow volume and wind gust.
Configs
  • A: Set API Key *#{EL}
  • B1: Set Unit System (Celsius: “metric”, Fahrenheit: “imperial”)#{EL}
  • B2: Set Lang Code to translate description field (eg “ja” “es”)#{EL}
  • C: Set Datetime (of Workflow), Latitude and Longitude in 3 lines *#{EL}
  • E1: Select NUMERIC type Data that stores Temperature (update)
  • E2: Select NUMERIC type Data that store Temperature of Perception (update)
  • E3: Select NUMERIC type Data that stores Dew Point (update)
  • F2: Select NUMERIC type Data that stores Humidity (%) (update)
  • F3: Select NUMERIC type Data that stores Clouds (%) (update)
  • G1: Select STRING type Data that stores Weather Group (update)
  • G2: Select STRING type Data that stores Weather Condition (update)
  • G3: Select STRING type Data that stores Weather Icon URL (update)
  • H0: Select NUMERIC type Data that stores Wind Gust (update)
  • H1: Select NUMERIC type Data that stores Wind Speed (update)
  • H2: Select NUMERIC type Data that stores Wind Direction angle (0:N 90:E) (update)
  • I0: Select NUMERIC type Data that stores Snow Volume for last hour (mm) (update)
  • I1: Select NUMERIC type Data that stores Rain Volume for the last hour (mm) (update)
  • I2: Select NUMERIC type Data that stores Pressure at sea level (update)
Script (click to open)
// GraalJS Script (engine type: 2)

//////// START "main()" /////////////////////////////////////////////////////////////////
main();
function main(){ 

//// == Config Retrieving / 工程コンフィグの参照 ==
const strApiKey      = configs.get( "StrConfA" ); // required
  if( strApiKey    === "" ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {A API Key} is empty \n" );
  }
const strUnitSystem  = configs.get( "StrConfB1" );
const strLangCode    = configs.get( "StrConfB2" );
const strTarget3     = configs.get( "StrConfC" ); // required
  if( strTarget3   === "" ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {C Date Latitude Longitude} is empty \n" );
  }
  const arrTarget3   = strTarget3.split("\n");
  if( arrTarget3.length < 3 ){
    throw new Error( "\n AutomatedTask ConfigError:" +
                     " Config {C Date Latitude Longitude} Set in 3 lines \n" );
  }
  const strSpecifiedDate = arrTarget3[0].slice(0, 13); // eg "2021-12-31 23"
  let  dateSpecified = toJsDate( strSpecifiedDate + ":00" ); // Specified DateTime (Platform)
  const strLat       = arrTarget3[1];
  const strLon       = arrTarget3[2];
const numPocketTemp      = configs.getObject( "SelectConfE1" );
const numPocketFeelTemp  = configs.getObject( "SelectConfE2" );
const numPocketDewPoint  = configs.getObject( "SelectConfE3" );
const numPocketHumidity  = configs.getObject( "SelectConfF2" );
const numPocketClouds    = configs.getObject( "SelectConfF3" );
const strPocketGroup     = configs.getObject( "SelectConfG1" );
const strPocketCondition = configs.getObject( "SelectConfG2" );
const strPocketIconUrl   = configs.getObject( "SelectConfG3" );
const numPocketWindGust  = configs.getObject( "SelectConfH0" );
const numPocketWindSpeed = configs.getObject( "SelectConfH1" );
const numPocketWindDeg   = configs.getObject( "SelectConfH2" );
const numPocketSnow      = configs.getObject( "SelectConfI0" );
const numPocketRain      = configs.getObject( "SelectConfI1" );
const numPocketPressure  = configs.getObject( "SelectConfI2" );


//// == Data Retrieving / ワークフローデータの参照 ==
// (Nothing. Retrieved via Expression Language in Config Retrieving)


//// == Calculating / 演算 ==

/// Get all essential weather data for a specific location
/// https://openweathermap.org/api/one-call-api#history
// request1, prepare
let getUri1  = "https://api.openweathermap.org/data/2.5/onecall/timemachine";
let request1 = httpClient.begin(); // HttpRequestWrapper
    request1 = request1.queryParam( "appid", strApiKey ); 
    request1 = request1.queryParam( "lat", strLat ); 
    request1 = request1.queryParam( "lon", strLon ); 
    request1 = request1.queryParam( "dt", ( dateSpecified.getTime() /1000 + "" ) );
    if( strUnitSystem !== "" ){
      request1 = request1.queryParam( "units", strUnitSystem ); 
    }
    if( strLangCode !== "" ){
      request1 = request1.queryParam( "lang", strLangCode ); 
    }
// request1, try
const response1     = request1.get( getUri1 ); // HttpResponseWrapper
engine.log( " AutomatedTask ApiRequest1 Start: " + getUri1 );
const response1Code = response1.getStatusCode() + "";
const response1Body = response1.getResponseAsString() + "";
engine.log( " AutomatedTask ApiResponse1 Status: " + response1Code );
if( response1Code !== "200"){
  throw new Error( "\n AutomatedTask UnexpectedResponseError: " +
                    response1Code + "\n" + response1Body + "\n" );
}
// response1, parse
// engine.log( response1Body ); // debug
/* response sample
{
  lat: 37.25,
  lon: 139.15,
  timezone: "Asia/Tokyo",
  timezone_offset: 32400,
  current: { 略 },
  hourly: [
    {
      dt: 1614038400,
      temp: 2.78,
      feels_like: 0.43,
      pressure: 1016,
      humidity: 80,
      dew_point: -0.28,
      clouds: 100,
      wind_speed: 0.45,
      wind_deg: 320,
      wind_gust: 1.34,
      weather: [
        {
          id: 601,
          main: "Snow",
          description: "雪",
          icon: "13d"
        }
      ],
      snow: {
        1h: 0.64
      }
    },
*/
const response1Obj = JSON.parse( response1Body );
engine.log( " AutomatedTask ApiResponse1 # of Array Hourly: " + response1Obj.hourly.length );
engine.log( " AutomatedTask ApiResponse1 timezone: " + response1Obj.timezone );
engine.log( " AutomatedTask ApiResponse1 offset: " + (response1Obj.timezone_offset /3600) );
engine.log( " AutomatedTask Workflow Platform offset: " + (engine.getTimeZoneOffsetInMinutes() /60) );

/// Find ID of the specified datetime
// Time (recognized by Workflow Platform) == Time (Weather Location Timezone)
let numHourlyId = 0;
engine.log( "  Time to search: " + dateSpecified.getTime() +
                " (" + dateSpecified.toISOString() + ")"
          );
for( let i = 0; i < response1Obj.hourly.length; i++ ){ // must be sorted
  let dateTmp = new Date( response1Obj.hourly[i].dt *1000 );
  if( response1Obj.hourly[i].dt *1000 > dateSpecified.getTime() ){
    engine.log( "    hourly[" + i + "].dt: " + response1Obj.hourly[i].dt +
                " (" + dateTmp.toISOString() + ") is larger"
              );
    break;
  }else{
    engine.log( "    hourly[" + i + "].dt: " + response1Obj.hourly[i].dt +
                " (" + dateTmp.toISOString() + ")"
              );
    numHourlyId = i;
  }
}

/// Extract weather info with Date-ID
let numTemp        = response1Obj.hourly[numHourlyId].temp;
let numFeelTemp    = response1Obj.hourly[numHourlyId].feels_like;
let numDewPoint    = response1Obj.hourly[numHourlyId].dew_point;
let numHumidity    = response1Obj.hourly[numHourlyId].humidity;
let numClouds      = response1Obj.hourly[numHourlyId].clouds;
let strGroup       = response1Obj.hourly[numHourlyId].weather[0].main;
let strCondition   = response1Obj.hourly[numHourlyId].weather[0].description;
let strIconUrl     = "https://openweathermap.org/img/wn/" +
                     response1Obj.hourly[numHourlyId].weather[0].icon + ".png";
                     // eg "https://openweathermap.org/img/wn/10d.png"
let numWindGust    = response1Obj.hourly[numHourlyId].wind_speed; // Case where gusts do not blow
if( response1Obj.hourly[numHourlyId].hasOwnProperty('wind_gust') ){
    numWindGust    = response1Obj.hourly[numHourlyId].wind_gust;
}
let numWindSpeed   = response1Obj.hourly[numHourlyId].wind_speed;
let numWindDeg     = response1Obj.hourly[numHourlyId].wind_deg;
let numSnow        = 0;
if( response1Obj.hourly[numHourlyId].hasOwnProperty('snow') ){
    numSnow        = response1Obj.hourly[numHourlyId].snow['1h'];
}
let numRain        = 0;
if( response1Obj.hourly[numHourlyId].hasOwnProperty('rain') ){
    numRain        = response1Obj.hourly[numHourlyId].rain['1h'];
}
// The period operator format is not available 
// if the first character of the property name begins with a number
// or if the property name contains a hyphen.
let numPressure    = response1Obj.hourly[numHourlyId].pressure;


//// == Data Updating / ワークフローデータへの代入 ==
if( numPocketTemp   !== null ){
  engine.setData( numPocketTemp,      new java.math.BigDecimal( numTemp ) );
}
if( numPocketFeelTemp  !== null ){
  engine.setData( numPocketFeelTemp,  new java.math.BigDecimal( numFeelTemp ) );
}
if( numPocketDewPoint  !== null ){
  engine.setData( numPocketDewPoint,  new java.math.BigDecimal( numDewPoint ) );
}
if( numPocketHumidity  !== null ){
  engine.setData( numPocketHumidity,  new java.math.BigDecimal( numHumidity ) );
}
if( numPocketClouds    !== null ){
  engine.setData( numPocketClouds,    new java.math.BigDecimal( numClouds ) );
}
if( strPocketGroup     !== null ){
  engine.setData( strPocketGroup,     strGroup );
}
if( strPocketCondition !== null ){
  engine.setData( strPocketCondition, strCondition );
}
if( strPocketIconUrl !== null ){
  engine.setData( strPocketIconUrl,   strIconUrl );
}
if( numPocketWindGust  !== null ){
  engine.setData( numPocketWindGust,  new java.math.BigDecimal( numWindGust ) );
}
if( numPocketWindSpeed !== null ){
  engine.setData( numPocketWindSpeed, new java.math.BigDecimal( numWindSpeed ) );
}
if( numPocketWindDeg   !== null ){
  engine.setData( numPocketWindDeg,   new java.math.BigDecimal( numWindDeg ) );
}
if( numPocketSnow      !== null ){
  engine.setData( numPocketSnow,      new java.math.BigDecimal( numSnow ) );
}
if( numPocketRain      !== null ){
  engine.setData( numPocketRain,      new java.math.BigDecimal( numRain ) );
}
if( numPocketPressure  !== null ){
  engine.setData( numPocketPressure,  new java.math.BigDecimal( numPressure ) );
}

} //////// END "main()" /////////////////////////////////////////////////////////////////



function toJsDate( bpmsDateOrDatetimeStr ){
  // BPMS Date:     "2020-04-01"  (subtype "Y/M" "M/D" "Y", not supported)
  // BPMS Datetime: "2020-04-01 23:59"
  let year       = 0;
  let monthIndex = 0;
  let day        = 0;
  let hours      = 0;
  let minutes    = 0;

  //  The ECMA/JavaScript Date object has a large number of methods.
  // "Date.parse" is danger (strongly discouraged)
  // - new Date("2014-11-10") // Mon Nov 10 2014 09:00:00 GMT+0900 (JST)
  // - new Date(2014, 10, 10) // Mon Nov 10 2014 00:00:00 GMT+0900 (JST)
  let arrDatetime = bpmsDateOrDatetimeStr.split(" ");
  if( arrDatetime.length === 1 ){
    let arrDateParts = arrDatetime[0].split("-");
    year       = parseInt(arrDateParts[0], 10);
    monthIndex = parseInt(arrDateParts[1], 10) - 1;
    day        = parseInt(arrDateParts[2], 10);
  }
  if( arrDatetime.length === 2 ){
    let arrDateParts = arrDatetime[0].split("-");
    let arrTimeParts = arrDatetime[1].split(":");
    year       = parseInt(arrDateParts[0], 10);
    monthIndex = parseInt(arrDateParts[1], 10) - 1;
    day        = parseInt(arrDateParts[2], 10);
    hours      = parseInt(arrTimeParts[0], 10);
    minutes    = parseInt(arrTimeParts[1], 10);
  }
  return new Date( year, monthIndex, day, hours, minutes );
}



/*
Notes:
- For snow removal (snowfall), forecasting of vegetable prices (temperature and cloud in production), etc.
- Weather data in OpenWeatherMap is calculated mechanically based on public info or airport observations.
    - There is a difference from the weather data provided by the weather company.
- The acquired forecast data and historical data can be freely used under the Open Database License.
    - https://openweathermap.org/full-price#licenses

- Datetime up to 5 days ago
    - If a date and time outside the range is specified, an error will occur.
    - Specify with a string starting with "YYYY-MM-DD HH". (Date type + static HH is also acceptable)

Notes-ja:
- 気象履歴データは、除排雪の計画業務(降雪量)や野菜価格の変動予測(生産地の気温と雲量)等で活用されます。
- OpenWeatherMap の気象データは、公的情報や空港観測値などを元に機械的に算出されています。
    - 気象会社による気象データとは、違いがあります。
- 取得した予報データや履歴データは、Open Database License 下で自由に利用できます。
    - https://openweathermap.org/full-price#licenses
- 5日前(世界標準時換算)までの日時が指定可能です。
    - 範囲外の日時が指定された場合、エラーとなります。
    - "YYYY-MM-DD HH" で始まる文字列で指定します。("日付型データ+固定時刻文字列" でも構いません)
*/


/*
APPENDIX
- Create an API key on the "API keys" page of your personal account beforehand.
    - https://home.openweathermap.org/api_keys
- In this Addon, the weather data is acquired via "One Call API (Historical weather data)".
    - Available in OpenWeather Free subscription.
- Units of measurement in response
    - (default): temperature in Kelvin and wind speed in meter/sec
    - "metric": temperature in Celsius and wind speed in meter/sec
    - "imperial": temperature in Fahrenheit and wind speed in miles/hour
- Translation samples of weather description field, corresponding language codes
    - eg. "broken clouds: muy nuboso", "overcast clouds: nubes", "light snow: nevada ligera"
    - https://openweathermap.org/api/one-call-api#multi
    - https://openweathermap.org/weather-conditions
- Wind Direction degrees
    - 0 to 11, 349 to 359: N
    - 12 to 33: NNE
    - 34 to 56: NE
    - 57 to 78: ENE
    - 79 to 101: E
    - 102 to 123: ESE
    - 124 to 146: SE
    - 147 to 168: SSE
    - 169 to 191: S
    - 192 to 213: SSW
    - 214 to 236: SW
    - 237 to 258: WSW
    - 259 to 281: W
    - 282 to 303: WNW
    - 304 to 326: NW
    - 327 to 348: NNW
- Latitude Longitude sample
    - Metropolitan Government Building, Tokyo: 35.689472, 139.69175
    - Kiyomizu-dera Temple, Kyoto: 34.994831, 135.785003
    - Waikiki Beach, Hawaii: 21.275278, -157.825
    - Oymyakon, Russia: 63.25, 143.15 (the coldest permanently inhabited settlement on Earth)
    - Use Google Maps, Wikipedia, etc. to obtain the latitude and longitude of any point.
        - https://www.google.co.jp/maps/

APPENDIX-ja
- 個人アカウントの "API keys" ページにて、あらかじめ API Key を生成しておく必要があります。
    - https://home.openweathermap.org/api_keys
- このAddonにおける気象データは "One Call API (Historical weather data)" 経由で取得されます。
    - OpenWeather Free subscription(無料)で利用可能です。
- レスポンス数値の物理単位系
    - (デフォルト): 気温は「ケルビン(絶対温度)」にて、風速は「メートル毎秒」にて表示されます
    - "metric": 気温は「摂氏」、風速は「メートル毎秒」にて表示されます
    - "imperial": 気温は「華氏」、風速は「マイル毎時」にて表示されます
- 天気概況フィールドの翻訳サンプル、および対応言語コード
    - 例 "broken clouds: 曇りがち"、"overcast clouds: 厚い雲"、"light snow: 小雪"
    - https://openweathermap.org/api/one-call-api#multi
    - https://openweathermap.org/weather-conditions
- 風向と角度
    - 0 to 11, 349 to 359: 北の風、北風
    - 12 to 33: 北北東の風
    - 34 to 56: 北東の風
    - 57 to 78: 東北東の風
    - 79 to 101: 東の風
    - 102 to 123: 東南東の風
    - 124 to 146: 南東の風
    - 147 to 168: 南南東の風
    - 169 to 191: 南の風
    - 192 to 213: 南南西の風
    - 214 to 236: 南西の風
    - 237 to 258: 西南西の風
    - 259 to 281: 西の風
    - 282 to 303: 西北西の風
    - 304 to 326: 北西の風
    - 327 to 348: 北北西の風
- 緯度経度サンプル
    - 東京都庁: 35.689472, 139.69175
    - 京都 清水寺: 34.994831, 135.785003
    - ハワイ ワイキキビーチ: 21.275278, -157.825
    - ロシア オイミャコン: 63.25, 143.15 (世界で最も寒い定住地)
    - 任意地点の緯度経度は Google マップや Wikipedia 等で取得してください
        - https://www.google.co.jp/maps/
*/


Download

2021-02-25 (C) Questetra, Inc. (MIT License)
https://support.questetra.com/addons/openweather-weather-history-get-by-time/
The Add-on import feature is available with Professional or Enterprise edition.

Notes

  • Weather history data is used for planning snow removal (snowfall), forecasting of vegetable prices (temperature and cloud in production areas), etc.
  • Weather data in OpenWeatherMap is calculated mechanically based on public information and airport observations.
    • It differs from the weather data provided by meteorological companies.
  • The acquired forecast data and historical data can be freely used under the Open Database License.
  • The date and time can be specified up to 5 days in advance (in World Standard Time).
    • A date and time outside this range will cause an error.
    • The string must begin with “YYYY-MM-DD HH” (Date type + static HH is also acceptable).

Capture

Gets weather history for the specific time (corrected to zero minutes) from OpenWeather with specifying latitude and longitude of the world. Not only temperature, humidity and wind speed, but also snow volume and wind gust can be obtained.

Appendix

  • Create an API key on the “API keys” page of your personal account beforehand.
  • In this Addon the weather data is acquired via “One Call API (Historical weather data)”.
    • Available in OpenWeather Free subscription.
  • Units of measurement in response
    • (default): temperature in Kelvin and wind speed in meter/sec
    • “metric”: temperature in Celsius and wind speed in meter/sec
    • “imperial”: temperature in Fahrenheit and wind speed in miles/hour
  • Translation samples of weather description field, corresponding language codes
  • Wind Direction degrees
    • 0 to 11, 349 to 359: N
    • 12 to 33: NNE
    • 34 to 56: NE
    • 57 to 78: ENE
    • 79 to 101: E
    • 102 to 123: ESE
    • 124 to 146: SE
    • 147 to 168: SSE
    • 169 to 191: S
    • 192 to 213: SSW
    • 214 to 236: SW
    • 237 to 258: WSW
    • 259 to 281: W
    • 282 to 303: WNW
    • 304 to 326: NW
    • 327 to 348: NNW
  • Latitude and Longitude sample
    • Metropolitan Government Building, Tokyo: 35.689472, 139.69175
    • Kiyomizu-dera Temple, Kyoto: 34.994831, 135.785003
    • Waikiki Beach, Hawaii: 21.275278, -157.825
    • Oymyakon, Russia: 63.25, 143.15 (the coldest permanently inhabited settlement on Earth)
    • Use Google Maps, Wikipedia, etc. to obtain the latitude and longitude of any point.

See also

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: