// GraalJS Script (engine type: 2)
//////// START "main()" /////////////////////////////////////////////////////////////////
main();
function main(){
//// == Config Retrieving / 工程コンフィグの参照 ==
const strAuthzSetting = configs.get ( "AuthzConfU" ); /// REQUIRED
engine.log( " AutomatedTask Config: Authz Setting: " + strAuthzSetting );
const strDurationStart = configs.get ( "StrConfA1" ); /// REQUIRED
if( strDurationStart === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {A1: DurationStart} is empty \n" );
}
const strDurationEnd = configs.get ( "StrConfA2" ); /// REQUIRED
if( strDurationEnd === "" ){
throw new Error( "\n AutomatedTask ConfigError:" +
" Config {A2: DurationEnd} is empty \n" );
}
const numPocketStep = configs.getObject( "SelectConfB1" ); /// REQUIRED
const numPocketDistance = configs.getObject( "SelectConfB2" ); // NotRequired
//// == Data Retrieving / ワークフローデータの参照 ==
// (Nothing. Retrieved via Expression Language in Config Retrieving)
//// == Calculating / 演算 ==
/// Times in milliseconds since epoch
/// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime
let dateDurationStart = toJsDate( strDurationStart );
let numDurationStart = dateDurationStart.getTime();
let dateDurationEnd = toJsDate( strDurationEnd );
let numDurationEnd = dateDurationEnd.getTime();
/// Get StepCounts (and Distance)
/// Google Fit API
/// https://developers.google.com/fit/rest/v1/reference/users/dataset/aggregate
let request1Obj = {};
request1Obj.aggregateBy = [];
request1Obj.aggregateBy[0] = {};
request1Obj.aggregateBy[0].dataTypeName = "com.google.step_count.delta";
if( numPocketDistance !== null ){
request1Obj.aggregateBy[1] = {};
request1Obj.aggregateBy[1].dataTypeName = "com.google.distance.delta";
}
request1Obj.endTimeMillis = numDurationEnd;
request1Obj.startTimeMillis = numDurationStart;
request1Obj.bucketByTime = {};
request1Obj.bucketByTime.durationMillis = numDurationEnd - numDurationStart;
let request1Uri = "https://www.googleapis.com/fitness/v1/users/me/dataset:aggregate";
let request1 = httpClient.begin(); // HttpRequestWrapper
request1 = request1.authSetting( strAuthzSetting ); // with "Authorization: Bearer XX"
// https://questetra.zendesk.com/hc/en-us/articles/360024574471-R2300#HttpRequestWrapper
request1 = request1.body( JSON.stringify( request1Obj ), "application/json" );
// request1, try
const response1 = request1.post( request1Uri ); // HttpResponseWrapper
engine.log( " AutomatedTask ApiRequest1 Start: " + request1Uri );
const response1Code = response1.getStatusCode() + "";
const response1Body = response1.getResponseAsString() + "";
engine.log( " AutomatedTask ApiResponse Status: " + response1Code );
if( response1Code !== "200"){
throw new Error( "\n AutomatedTask UnexpectedResponseError: " +
response1Code + "\n" + response1Body + "\n" );
}
// response1, parse
/*
engine.log( response1Body ); // debug
{
"bucket": [
{
"startTimeMillis": "1621436400000",
"endTimeMillis": "1621522800000",
"dataset": [
{
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:aggregated",
"point": [
{
"startTimeNanos": "1621456113977325463",
"endTimeNanos": "1621488145246312108",
"dataTypeName": "com.google.step_count.delta",
"originDataSourceId": "raw:com.google.step_count.cumulative:Sony:SO-41A:cdfccXXXXX8b674Y:pedometer Non-wakeup",
"value": [
{
"intVal": 9987,
"mapVal": []
}
]
}
]
},
{
"dataSourceId": "derived:com.google.distance.delta:com.google.android.gms:aggregated",
"point": [
{
"startTimeNanos": "1621456169872000000",
"endTimeNanos": "1621488145246312108",
"dataTypeName": "com.google.distance.delta",
"originDataSourceId": "derived:com.google.distance.delta:com.google.android.gms:merge_distance_delta",
"value": [
{
"fpVal": 8987.1162967085838,
"mapVal": []
}
]
}
]
}
]
}
]
}
== if no record ==
{
"bucket": [
{
"startTimeMillis": "1621782000000",
"endTimeMillis": "1621782010000",
"dataset": [
{
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:aggregated",
"point": []
},
{
"dataSourceId": "derived:com.google.distance.delta:com.google.android.gms:aggregated",
"point": []
}
]
}
]
}
*/
const response1Obj = JSON.parse( response1Body );
let numStep = 0;
if( response1Obj.bucket[0].dataset[0].point.length === 0 ){
engine.log( " AutomatedTask RuntimeWarning:" +
" No Record of StepCount (no point in dataset)" );
}else{
numStep = response1Obj.bucket[0].dataset[0].point[0].value[0].intVal;
}
let numDistance = 0;
if( numPocketDistance !== null ){
if( response1Obj.bucket[0].dataset[1].point.length === 0 ){
engine.log( " AutomatedTask RuntimeWarning:" +
" No Record of Distance (no point in dataset)" );
}else{
numDistance = response1Obj.bucket[0].dataset[1].point[0].value[0].fpVal;
}
}
//// == Data Updating / ワークフローデータへの代入 ==
engine.setData( numPocketStep, new java.math.BigDecimal( numStep ) );
if( numPocketDistance !== null ){
engine.setData( numPocketDistance, new java.math.BigDecimal( numDistance ) );
}
} //////// 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:
- Used in the daily reporting process of caregiver, deliveryman, etc. GoogleFitSteps
- It is possible to count periods that exceed 24 hours.
- Long-term like over 2 months will result in an "aggregate duration too large" error.
- Only the data of the person who permitted API communication (OAuth Authz) can be acquired.
- That is, only one person's data can be acquired for each automated task.
- As of 2021-05, data cannot be acquired with any user ID (userId).
- The unit of travel distance data is meters.
- Variable decimal numbers follow the numeric data definition of the workflow app.
- If the datetime (DurationStart and DurationEnd) are set in date format, considered as "00:00".
- eg: "2021-12-31" to "2021-12-31 00:00"
Notes-ja:
- 介護職員や配達員などが勤務時間内の歩数や距離を報告する業務プロセス等で利用します。 GoogleFitSteps
- 24時間を超えるような時間範囲での集計も可能です。
- ただし、2カ月を超えるような長期間の集計は "aggregate duration too large" エラーとなります。
- API通信を許可(OAuth認可)した本人のデータしか取得できません。 "HTTP認証設定"
- すなわち、自動処理工程1つにつき、1人のデータしか取得できません。
- 2021-05現在、任意のユーザID(userId)でのデータ取得はできません。
- 移動距離データの単位はメートルです。
- 小数点以下有効数字(切り捨て位置)は、ワークフローアプリの数値型データ定義に従います。
- 日時(範囲開始と範囲終了)が日付フォーマットで設定された場合、"00:00" とみなされます。
- 例: "2021-12-31" → "2021-12-31 00:00"
APPENDIX-en
- For usage of Google Fit itself, refer to the Google Fit documents.
- Track your fitness activity
- https://support.google.com/fit/answer/6075066?hl=en
- Find your activity
- https://support.google.com/fit/answer/6090183?hl=en
- Fit isn't tracking activities correctly
- https://support.google.com/fit/answer/6075068?hl=en
- Connect other apps with Google Fit
- https://support.google.com/accounts/answer/6098255?hl=en
- Setting example of "HTTP Authentication" (OAuth2)
- Authorization Endpoint URL:
- https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force
- Token Endpoint URL:
- https://accounts.google.com/o/oauth2/token
- Scope:
- https://www.googleapis.com/auth/fitness.activity.read https://www.googleapis.com/auth/fitness.location.read
- Client ID, Consumer Secret:
- ( from https://console.developers.google.com/ )
- Redirect URLs: https://s.questetra.net/oauth2callback
APPENDIX-ja
- Google Fit 自体の基本的な利用方法は、Google Fit のドキュメントを参照してください。
- フィットネス アクティビティを記録する
- https://support.google.com/fit/answer/6075066?hl=ja
- アクティビティを確認する
- https://support.google.com/fit/answer/6090183?hl=ja
- Fit がアクティビティを正しくトラッキングしていない
- https://support.google.com/fit/answer/6075068?hl=ja
- 他のアプリと Google Fit を接続する
- https://support.google.com/accounts/answer/6098255?hl=ja
- "HTTP認証"(OAuth2)の設定例
- Authorization Endpoint URL:
- https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=force
- Token Endpoint URL:
- https://accounts.google.com/o/oauth2/token
- Scope:
- https://www.googleapis.com/auth/fitness.activity.read https://www.googleapis.com/auth/fitness.location.read
- Client ID, Consumer Secret:
- ( from https://console.developers.google.com/ )
- Redirect URLs: https://s.questetra.net/oauth2callback
*/