// 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, 10); // eg "2021-12-31"
let dateSpecified = toJsDate( strSpecifiedDate + " 23:59" ); // LastTime in Date (Platform)
const strLat = arrTarget3[1];
const strLon = arrTarget3[2];
const timePocketSunrise = configs.getObject( "SelectConfD1" );
const timePocketSunset = configs.getObject( "SelectConfD2" );
const numPocketMinTemp = configs.getObject( "SelectConfE1" );
const numPocketMaxTemp = configs.getObject( "SelectConfE2" );
const numPocketFeelTemp = configs.getObject( "SelectConfE3" );
const numPocketDewPoint = configs.getObject( "SelectConfE4" );
const numPocketPop = configs.getObject( "SelectConfF1" );
const numPocketHumidity = configs.getObject( "SelectConfF2" );
const numPocketClouds = configs.getObject( "SelectConfF3" );
const strPocketGroup = configs.getObject( "SelectConfG1" );
const strPocketCondition = configs.getObject( "SelectConfG2" );
const numPocketWindSpeed = configs.getObject( "SelectConfH1" );
const numPocketWindDeg = configs.getObject( "SelectConfH2" );
const numPocketRain = configs.getObject( "SelectConfI1" );
const numPocketPressure = configs.getObject( "SelectConfI2" );
const numPocketUvi = configs.getObject( "SelectConfI3" );
//// == 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
// request1, prepare
let getUri1 = "https://api.openweathermap.org/data/2.5/onecall";
let request1 = httpClient.begin(); // HttpRequestWrapper
request1 = request1.queryParam( "appid", strApiKey );
request1 = request1.queryParam( "lat", strLat );
request1 = request1.queryParam( "lon", strLon );
request1 = request1.queryParam( "exclude", "minutely,hourly" );
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: 43.0687,
lon: 141.3508,
timezone: "Asia/Tokyo",
timezone_offset: 32400,
daily: [
{
dt: 1613440800,
sunrise: 1613424690,
sunset: 1613462769,
temp: {
day: -1.47,
min: -7.04,
max: 3.61,
night: -7.04,
eve: -6.05,
morn: 3.39
},
feels_like: {
day: -14.13,
night: -14.19,
eve: -15.56,
morn: -0.52
},
pressure: 976,
humidity: 92,
dew_point: -5.77,
wind_speed: 14.75,
wind_deg: 271,
weather: [
{
id: 616,
main: "Snow",
description: "rain and snow",
icon: "13d"
}
],
clouds: 100,
pop: 1,
rain: 10.85,
snow: 6.1,
uvi: 0.74
},
*/
const response1Obj = JSON.parse( response1Body );
engine.log( " AutomatedTask ApiResponse1 # of Array Daily: " + response1Obj.daily.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 date
// LastTime in Date (Workflow Platform Time) -> LastTime in Date (Weather Location Time)
dateSpecified.setSeconds( dateSpecified.getSeconds() +
engine.getTimeZoneOffsetInMinutes() * 60 -
response1Obj.timezone_offset
);
let numDailyId = 0;
engine.log( " Last in Date: " + dateSpecified.getTime() +
" (" + dateSpecified.toISOString() + ")"
);
for( let i = 0; i < response1Obj.daily.length; i++ ){ // must be sorted
let dateTmp = new Date( response1Obj.daily[i].dt *1000 );
if( response1Obj.daily[i].dt *1000 > dateSpecified.getTime() ){
engine.log( " daily[" + i + "].dt: " + response1Obj.daily[i].dt +
" (" + dateTmp.toISOString() + ") is larger"
);
break;
}else{
engine.log( " daily[" + i + "].dt: " + response1Obj.daily[i].dt +
" (" + dateTmp.toISOString() + ")"
);
numDailyId = i;
}
}
/// Extract weather info with Date-ID
let numMsecSunrise = response1Obj.daily[numDailyId].sunrise *1000;
let dateSunrise = new Date( numMsecSunrise );
let strSunrise = dateSunrise.toLocaleTimeString();
let numMsecSunset = response1Obj.daily[numDailyId].sunset *1000;
let dateSunset = new Date( numMsecSunset );
let strSunset = dateSunset.toLocaleTimeString();
let numMinTemp = response1Obj.daily[numDailyId].temp.min;
let numMaxTemp = response1Obj.daily[numDailyId].temp.max;
let numFeelTemp = response1Obj.daily[numDailyId].feels_like.day;
let numDewPoint = response1Obj.daily[numDailyId].dew_point;
let numPop = response1Obj.daily[numDailyId].pop *100; // "0.51" to "51"%
let numHumidity = response1Obj.daily[numDailyId].humidity;
let numClouds = response1Obj.daily[numDailyId].clouds;
let strGroup = response1Obj.daily[numDailyId].weather[0].main;
let strCondition = response1Obj.daily[numDailyId].weather[0].description;
let numWindSpeed = response1Obj.daily[numDailyId].wind_speed;
let numWindDeg = response1Obj.daily[numDailyId].wind_deg;
let numRain = 0;
if( response1Obj.daily[numDailyId].hasOwnProperty('rain') ){
numRain = response1Obj.daily[numDailyId].rain;
}
let numPressure = response1Obj.daily[numDailyId].pressure;
let numUvi = response1Obj.daily[numDailyId].uvi;
//// == Data Updating / ワークフローデータへの代入 ==
if( timePocketSunrise !== null ){
if( timePocketSunrise.matchDataType( "STRING" ) ){
engine.log( " AutomatedTask: Pocket for Sunrise is STRING type" );
engine.setData( timePocketSunrise, strSunrise );
}else{
engine.log( " AutomatedTask: Pocket for Sunrise is DATETIME type" );
engine.setData( timePocketSunrise, new java.sql.Timestamp( numMsecSunrise ) );
}
}
if( timePocketSunset !== null ){
if( timePocketSunset.matchDataType( "STRING" ) ){
engine.log( " AutomatedTask: Pocket for Sunset is STRING type" );
engine.setData( timePocketSunset, strSunset );
}else{
engine.log( " AutomatedTask: Pocket for Sunset is DATETIME type" );
engine.setData( timePocketSunset, new java.sql.Timestamp( numMsecSunset ) );
}
}
if( numPocketMinTemp !== null ){
engine.setData( numPocketMinTemp, new java.math.BigDecimal( numMinTemp ) );
}
if( numPocketMaxTemp !== null ){
engine.setData( numPocketMaxTemp, new java.math.BigDecimal( numMaxTemp ) );
}
if( numPocketFeelTemp !== null ){
engine.setData( numPocketFeelTemp, new java.math.BigDecimal( numFeelTemp ) );
}
if( numPocketDewPoint !== null ){
engine.setData( numPocketDewPoint, new java.math.BigDecimal( numDewPoint ) );
}
if( numPocketPop !== null ){
engine.setData( numPocketPop, new java.math.BigDecimal( numPop ) );
}
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( numPocketWindSpeed !== null ){
engine.setData( numPocketWindSpeed, new java.math.BigDecimal( numWindSpeed ) );
}
if( numPocketWindDeg !== null ){
engine.setData( numPocketWindDeg, new java.math.BigDecimal( numWindDeg ) );
}
if( numPocketRain !== null ){
engine.setData( numPocketRain, new java.math.BigDecimal( numRain ) );
}
if( numPocketPressure !== null ){
engine.setData( numPocketPressure, new java.math.BigDecimal( numPressure ) );
}
if( numPocketUvi !== null ){
engine.setData( numPocketUvi, new java.math.BigDecimal( numUvi ) );
}
} //////// 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 agriculture, transportation, retail, hotel, restaurant service, 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
- Dates up to 7 days in advance are valid.
- If a date outside the range is specified, it will be updated with the data 7 days ahead.
- Specify with a string starting with "YYYY-MM-DD". (DateTime type is also acceptable)
Notes-ja:
- 農業・運送業の稼働判断や小売・宿泊・飲食における仕入業務の自動化省力化等に活用されます。
- OpenWeatherMap の気象データは、公的情報や空港観測値などを元に機械的に算出されています。
- 気象会社による気象データとは、違いがあります。
- 取得した予報データや履歴データは、Open Database License 下で自由に利用できます。
- https://openweathermap.org/full-price#licenses
- 7日先までの日付が指定可能です。
- 範囲外の日付が指定された場合、7日先のデータで更新されます。
- "YYYY-MM-DD" で始まる文字列で指定します。(時刻型データでも構いません)
*/
/*
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".
- Available in OpenWeather Free subscription.
- Sunrise and sunset times are displayed with Workflow platform timezone.
- The UTC offset of weather location time can be confirmed in the log.
- Storing in string type data, the time format depends on toLocaleTimeString().
- eg. "06:40:06", "6:40:06 AM", etc
- https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString
- 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" 経由で取得されます。
- OpenWeather Free subscription(無料)で利用可能です。
- 日の出、日の入り時刻は、ワークフロー基盤のタイムゾーンで表示されます。
- 現地時間のUTCオフセット(協定世界時との差)は、ログにて確認可能です。
- 文字列型データに格納する場合、時刻書式は toLocaleTimeString() に依存します。
- 例 "06:40:06", "6:40:06 AM", etc (秒まで出力されます)
- https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString
- レスポンス数値の物理単位系
- (デフォルト): 気温は「ケルビン(絶対温度)」にて、風速は「メートル毎秒」にて表示されます
- "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/
*/
Pingback: OpenWeather: Weather Forecast, Get by Time – Questetra Support
Pingback: OpenWeather: Weather History, Get by Time – Questetra Support
Pingback: Daily report flow-weather record (Add-on) – Questetra Support
Pingback: Daily report flow-weather record (Script Task) – Questetra Support