2019年8月31日土曜日

8/30 仕様書の再確認、

ゼミの初めに仕様書を現段階の進度でまとめたものを確認した。それぞれの担当で何が残っているのか何をしなければいけないのか、それぞれの担当の仕事がどう繋がっているのかの確認をした。

谷口・勇
IFTTTでWehookとの連携をした。しかし、今日改めて作成したトリガーは動かなかった。前回以前に作成したものは動いた。前回移行のを作りなおすと動かなくなった。時間を置いて30分後に動作の確認を行うと動いたが、動く時と動かない時があったので原因は何かよく分からなく、IFTTT側の問題かと、、、
Webhookとの連携をしているがIFTTTは動いているがカレンダーの書き換えが行われていないのでWebAPI側の問題なのかも分からず。

小山
今日はAIの編集を主に行った。Webから送信するとGoogleカレンダーにイベントが追加されるようになった。処方箋の情報から回数を把握し、朝・昼・夕・就寝それぞれ作成できるようにしなければならない。
谷口・勇に渡したURLが間違っているかもしれないので次回直す。

平松
現在の時刻とカレンダーに入力された時刻の差を求めることに成功した。取得したデータがグリニッジ標準時だったが、時間差自体は変わらないのでそのままにすることにした。

内田
先生の協力もありMonacaを使用したQRコードのアプリケーションで読み取ったデータを取り出して複数読み取っても全てのデータが一時的に保存されるようになった。また、先頭で改行もできるようになったがAJAXで送信するときに、 /n が消えずに残ってしまっているので次回までに解決し、使いやすいように全体のレイアウトを変えていきたいと思う。


UTC時刻とローカル時刻

Googleカレンダーは日時をUTC時刻で管理している。 そのため、UTC時刻とローカル時刻の変換が必要になる。
new Dateの引数にUTC時刻を指定するとローカル時刻が得られる。
また、引数なしではnew Dateはローカル時刻で現在時刻を取得する。
以上から、UTC時刻をローカル時刻に変換する特別な関数は必要ない。
以下にサンプルを示す。
var data = {
 "drug_notifies": 
 [
  {
   "title": "朝の薬の時間です",
   "description": "クラビット細粒10% 100mg 3錠",
   "id": "t4s1bi3v05bhvcjp41rr89qulg@google.com",
   "location": "5",
   "startTime": "2019-08-03T00:31:51.000Z",
   "endTime": "2019-08-03T01:01:51.000Z",
   "color": "11"
  },
  {
   "title": "夜の薬の時間です",
   "description": "クラビット細粒10% 100mg",
   "id": "v84ho65ceseoja7257s1moj1o8@google.com",
   "location": "0",
   "startTime": "2019-08-03T09:00:00.000Z",
   "endTime": "2019-08-03T09:30:00.000Z",
   "color": "11"
  }
 ],
 "num_reminder": "5",    // 催促回数
 "taiking_status": "0",  // 服用状況 (0:未服用, 1:服用済)
 "status": "0"         // 0=成功, 1:失敗
}

var startTime = data.drug_notifies[0].startTime;
var localTime = new Date(startTime);
console.log('startTime=' + startTime);
console.log('localTime=' + localTime);
var now = new Date();
console.log('now=' + now);
このプログラムの実行結果は次のようになる。
$ node utc2local.js
startTime=2019-08-03T00:31:51.000Z
localTime=Sat Aug 03 2019 09:31:51 GMT+0900 (GMT+09:00)
now=Sun Sep 01 2019 15:38:59 GMT+0900 (GMT+09:00)

2019年8月30日金曜日

monacaを使ったQRコードリーダー作成


前回まではmonacaの「BarcodeScanner」というCordovaプラグインを使ったところスマホでのQRコードの認識率が悪く実用をあきらめていたのだが、新たにCordovaのver. 7.1 から「PhoneGap BarcodeScanner」というものが追加されており、これを使うことによってAndroidにてQRコードの認識率が大幅に向上していることが確認できた。




iphoneユーザーのみ
iOS 10以降、info.plistに使用に関する説明を設定してやらないとアプリが強制終了するようだ。

NSCameraUsageDescriptionには、アプリがユーザーのカメラにアクセスする理由を記述します。
この設定を info.plist に追加するには、config.xml ファイルの <edit-config> タグに以下のように設定します。

<edit-config target="NSCameraUsageDescription" file="*-Info.plist" mode="merge">
    <string>To scan barcodes</string>
</edit-config>


iphone、androidユーザー共通


monacaは最小限の設定でプラグインを有効化しindex.htmlを下記のように書き換えるだけで使用することが出来る。詳しくはプラグインの名前から公式サイトに飛べます。
<!DOCTYPE HTML>
<html>
<head>
    <title>Barcode Scanner DEMO</title>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no">
    <script src="components/loader.js"></script>
    <link rel="stylesheet" href="components/loader.css">

    <script type="text/javascript">

    function scanBarcode() {
        window.plugins.barcodeScanner.scan( function(result) {
                alert("We got a barcode\n" +
                          "Result: " + result.text + "\n" +
                          "Format: " + result.format + "\n" +
                          "Cancelled: " + result.cancelled);
            }, function(error) {
                alert("Scanning failed: " + error);
            }
        );

    }
    </script>
</head>

<body>
    <hr> BarcodeReader DEMO <hr><br>
    <input type="button" onClick ="scanBarcode()" value ="Scan" />
</body>
</html>
                                                                                                                        

参考文献

[1]Monaca Docs

役割に分かれて作業12

全体
どこまで進んだか、何が足りないのか話し合った。
9月末までにそれぞれ完成させることになった 。

勇・谷口
URLをもらってWebAPIをWebhookに繋げたがカレンダーの書き換えができなかった。
(済)(応答無)に反応してLINEに通知がいくようになった。

平松
GETメソッドを使ってAPIを取得・カレンダーの書き換えなどのプログラムを組んだ。

内田
monacaの新しいプラグインを入れることで読み取りの高いアプリを作ることができた。
次回はAJAXを使い、WebAPIと連携させたい。

小山
③④5つのWebAPIを作るということでそれぞれプロジェクトを作成。勇・谷口の書き換えができたかったのは渡したものが間違っていたため次回直したものでできるかどうか確認する。
①②イベントの取得・色の取得はできているが、必要ないものも取得しているため次回添削。

2019年8月22日木曜日

役割に分かれて作業11

谷口・勇:色のやつとかの表を作る。
ドキュメントにIFTTTのやり方を入れた。パワーポイントに流れを整理してイラストを入れた。

平松:google notifire,カレンダーを見て薬を飲んでいなければ5分おきに催促する。飲んだらカレンダーを書き換える。一定時間ごとに催促するサンプルプログラムはかけたのでここからgoogleカレンダーを見たり書き換えたりする作業に取り掛かりたい。

内田:javaでの書き方が分からないため再度monacaで作ることにした。

小山:web api作り。書き換えたら文字化けするようになったので(html)次回直す。

2019年8月13日火曜日

役割に分かれて作業10

谷口・勇:催促したら家族・本人にLINEを送るようにした。(グループLINE)
催促したらタイトルが応答なしになるためそれをサーチしてラインを送れるようにした。
IFTTTとGoogleアシスタントが連携できなくなったがツイッターで検索した結果ただの障害であった。

平松:nodejsのforeverを使ってexample.jsを常時起動させることに成功した。
$ sudo npm install -g forever
$ forever start example.js
$ forever stop example.js
$ forever list example.js
$ forever logs example.js
$ forever config example.js
次回はタイマーをセットし朝昼夜の薬の飲み忘れを伝えるなどしていきたい。

小山:わかるところからスクリプトを引き続き入力中
当日の予定がタイトルに含まれる単語とIFTTTから送られてきたキーがイコールで結ばれた時にタイトルと色を変更するif文考え中。


2019年8月8日木曜日

8.6日

勇・谷口
IFTTTでGoogleカレンダーとWebhook(GAS)との連携できることが分かった。
連携にはGASのURL(Web API)がいるため今回はまだできてない無い。

平松
example.jsが動くようになった。node.jsをrequestモジュールで通信する方法を調べた。

内田
Javaでどのように変更すればイベントの更新が出来るのかがわかった。
が、書き換え方がまだよく分かっていない。

小山
GASにてスクリプト入力中
テストカレンダーは作成できたが色の着いた予定などはまだ入っていないため次週する。

【お薬の時間を通知するプログラム】 

下図はお薬を飲む時間を知らせるプログラムの動きを表したものである。このプログラムはベアボーンサーバ上でNodejsのスクリプトとして実装する。

図1.服用通知プログラムの状態遷移図

①初期化

  1. Googleカレンダーから当日のイベントを取得して,服用時刻になったら服用通知を行うタイマーを設定する。
  2. タイマーは当日分のうち,現在時刻より後で,かつ,未服用分のイベントに対して設定する。
  3. 翌日の早朝に日付変更通知が届くようにタイマーを設定する。
  • 服用通知にはパラメータとしてイベントidと0に初期化したカウンタを渡す。
  • 服用済みかどうかはイベントの色で判断する(赤:未服用,青:服用済み,黄:応答なし)。

②服用通知

  1. Googleカレンダーから当該idの服用イベントを取得して,服用済みかどうかを判定する。
  2. 服用済みでなければGoogle Homeに服用を促すメッセージを送り,事前に設定された時間後に服用確認通知が届くようにタイマーを設定する。
    Googleカレンダーから当該idの服用イベントを取得して,服用済みかどうかを判定する。
  • 服用確認通知にはパラメータとしてイベントidとカウンタを渡す。

③服用確認

  1. Googleカレンダーから当該idの服用イベントを取得して,服用済みかどうかを判定する。
  2. 服用済みでなければ服用通知回数カウンタを1upする。
  3. 服用通知回数カウンタが規定回数以下ならばGoogle Homeに服用を促すメッセージを送り,事前に設定された時間後に服用確認通知が届くようにタイマーを設定する。
  4. 服用通知回数カウンタが規定回数を超えていたらGoogleカレンダーの当該イベントを応答なし(黄)に設定する。
  • 服用確認通知にはパラメータとしてイベントidとカウンタを渡す。

服用時:朝・昼・夜・就寝前
カレンダーの色:未服用=赤,服用済み=青,応答なし=黄
※応答なしの場合,親族にLINEすると同時に利用者にもLINEする


【QRコードから読み込む処方情報】

QRコードから読み込んだ処方情報はJAHIS電子版お薬手帳データフォーマット仕様書Ver.2.2にしたがって記述する。その例を以下に示す。

1,鈴木 太郎,1,S330303,,東京都港区新橋1丁目△番 ○×ビル 5階,03-1234-1234,,B+,63.7,スズキ タロウ
2,1,乳製品,1
2,2,セフェム系(発熱),1
5,20190808,1
11,医療法人 オルカ医院,13,1,1234567,1130021,東京都文京区本駒込2-28-26,03-3946-0001,1
15,工業会 次郎,03-4567-4567,1
201,1,ノルバスク錠2.5mg,1,錠,1,,1
201,1,クラビット細粒10% 100mg(レボフロキシンとして),3,g,2,621925901,1
301,1,【1日3回毎食後に】,1,日分,1,1,,1
201,1,ペンニードル30Gテーパー,14,本,1,,1
201,1,バイアグラ,1,錠,1,,1
301,1,毎食後服用,3,日分,1,1,,1
リスト1.お薬手帳データフォーマット

リスト1に示すようなCSV形式だとプログラムからは扱いにくいので,これを以下のJSONフォーマットに変換する。
{
 "patientInfo": {
  "No1": {
   "name": "鈴木 太郎",
   "gender": "1",
   "birthdate": "S330303",
   "zipcode": "",
   "address": "東京都港区新橋1丁目△番 ○×ビル 5階",
   "phone": "03-1234-1234",
   "emergencyContact": "",
   "bloodType": "B+",
   "weight": "63.7",
   "kana": "スズキ タロウ"
  },
  "No2": [
   {
    "type": "1",
    "content": "乳製品",
    "creator": "1"
   },
   {
    "type": "2",
    "content": "セフェム系(発熱)",
    "creator": "1"
   }
  ]
 },
 "dispensing": [
  {
   "institution": {
    "No5": {
     "date": "20190808",
     "creator": "1"
    },
    "No11": {
     "name": "医療法人 オルカ医院",
     "prefCode": "13",
     "tensuCode": "1",
     "code": "1234567",
     "zipCode": "1130021",
     "address": "東京都文京区本駒込2-28-26",
     "phone": "03-3946-0001",
     "creator": "1"
    },
    "No15": {
     "name": "工業会 次郎",
     "contact": "03-4567-4567",
     "creator": "工業会 次郎"
    }
   },
   "RPs": [
    {
     "drugs": [
      {
       "No201": {
        "rp": "1",
        "name": "ノルバスク錠2.5mg",
        "dose": "1",
        "unit": "錠",
        "codeType": "1",
        "code": "",
        "creator": "1"
       }
      },
      {
       "No201": {
        "rp": "1",
        "name": "クラビット細粒10% 100mg(レボフロキシンとして)",
        "dose": "3",
        "unit": "g",
        "codeType": "2",
        "code": "621925901",
        "creator": "1"
       }
      }
     ],
     "dosage": {
      "No301": {
       "rp": "1",
       "name": "【1日3回毎食後に】",
       "quantity": "1",
       "unit": "日分",
       "formCode": "1",
       "dosageType": "1",
       "dosageCode": "",
       "creator": "1"
      }
     }
    },
    {
     "drugs": [
      {
       "No201": {
        "rp": "1",
        "name": "ペンニードル30Gテーパー",
        "dose": "14",
        "unit": "本",
        "codeType": "1",
        "code": "",
        "creator": "1"
       }
      },
      {
       "No201": {
        "rp": "1",
        "name": "バイアグラ",
        "dose": "1",
        "unit": "錠",
        "codeType": "1",
        "code": "",
        "creator": "1"
       }
      }
     ],
     "dosage": {
      "No301": {
       "rp": "1",
       "name": "毎食後服用",
       "quantity": "3",
       "unit": "日分",
       "formCode": "1",
       "dosageType": "1",
       "dosageCode": "",
       "creator": "1"
      }
     }
    }
   ]
  }
 ]
}
リスト2.JSON形式のお薬手帳データ 

この変換を行うNodejsで書かれたスクリプトを以下に示す。
//-----------------------------------------------
//
// CSVファイルを解析する(構造化)※PR情報は1つのみ
//
//-----------------------------------------------
var csv_data = '';
csv_data += '1,鈴木 太郎,1,S330303,,東京都港区新橋1丁目△番 ○×ビル 5階,03-1234-1234,,B+,63.7,スズキ タロウ\r\l';
csv_data += '2,1,乳製品,1\r\l';
csv_data += '2,2,セフェム系(発熱),1\r\l';
csv_data += '5,20190808,1\r\l';
csv_data += '11,医療法人 オルカ医院,13,1,1234567,1130021,東京都文京区本駒込2-28-26,03-3946-0001,1\r\l';
csv_data += '15,工業会 次郎,03-4567-4567,1\r\l';
csv_data += '201,1,ノルバスク錠2.5mg,1,錠,1,,1\r\l';
csv_data += '201,1,クラビット細粒10% 100mg(レボフロキシンとして),3,g,2,621925901,1\r\l';
csv_data += '301,1,【1日3回毎食後に】,1,日分,1,1,,1\r\l';
csv_data += '201,1,ペンニードル30Gテーパー,14,本,1,,1\r\l';
csv_data += '201,1,バイアグラ,1,錠,1,,1\r\l';
csv_data += '301,1,毎食後服用,3,日分,1,1,,1';

function barcode2json(csv_data) {
 var lines = csv_data.split('\r\l');

 var prescription = {
  patientInfo: {
   No1: {},
   No2: []
  },
  dispensing: [],
 };

 var dispensing = {
  institution: {
   No5: {},
   No11: {},
   No15: {},
  },
  RPs: [],
 };

 var RP = {
  drugs: [],
  dosage: '',
 };

 lines.forEach(function(line){
  var items = line.split(',');
  
  switch(items[0]) {
  // 患者基本情報(レコードNo.1 患者情報レコード)
  case "1":
   prescription.patientInfo.No1 = {
    name: items[1],
    gender: items[2],
    birthdate: items[3],
    zipcode: items[4],
    address: items[5],
    phone: items[6],
    emergencyContact: items[7],
    bloodType: items[8],
    weight: items[9],
    kana: items[10],
   };
   break;
  // 基本情報(レコードNo.2 患者特記レコード)
  case "2":
   prescription.patientInfo.No2.push({
    type: items[1],
    content: items[2],
    creator: items[3],
   });
   break;
  // 調剤-医療機関情報(レコードNo.5 調剤等年月日レコード)
  case "5":
   dispensing.institution.No5 = {
    date: items[1],
    creator: items[2],
   };
   break;
  // 調剤-医療機関情報(レコードNo.11 調剤-医療機関等レコード)
  case "11":
   dispensing.institution.No11 = {
    name: items[1],
    prefCode: items[2],
    tensuCode: items[3],
    code: items[4],
    zipCode: items[5],
    address: items[6],
    phone: items[7],
    creator: items[8],
   };
   break;
  // 調剤-医療機関情報(レコードNo.15 調剤-医師・薬剤師レコード)
  case "15":
   dispensing.institution.No15 = {
    name: items[1],
    contact: items[2],
    creator: items[1],
   };
   break;
  // 薬品情報(レコードNo.201 薬品レコード)
  case "201":
   RP.drugs.push({
    No201: {
     rp: items[1],
     name: items[2],
     dose: items[3],
     unit: items[4],
     codeType: items[5],
     code: items[6],
     creator: items[7],
    }
   });
   break;
  // 用法情報(レコードNo.301 用法レコード)
  case "301":
   RP.dosage = {
    No301: {
     rp: items[1],
     name: items[2],
     quantity: items[3],
     unit: items[4],
     formCode: items[5],
     dosageType: items[6],
     dosageCode: items[7],
     creator: items[8],
    }
   };
   dispensing.RPs.push(RP);
   RP = {
    drugs: [],
    dosage: '',
   };
   break;
  default:
   console.log('default:' + items[0]);
   break;
  }
 });
 prescription.dispensing.push(dispensing);
 return prescription;
}

var prescription = barcode2json(csv_data);
console.log(JSON.stringify(prescription, null, ' '));
リスト3.CSV形式の電子お薬手帳データをJSON形式に変換するNodejsのスクリプト

2019年8月2日金曜日

8/2のゼミ

<<進捗状況の確認>>
平松:AIスピーカーに自発的に喋らすことができるのかどうかをやる
内田:Javaできるのかどうかをやる
小山:薬の種類が3つ上でQRコードが2つになってしまう問題発生
   googleカレンダーの予定の変更をAPIで行う(何が必要か学ぶ)
勇・谷口:googleカレンダーの予定を変更できるのかどうか

<<今日の進捗状況>>

<勇・谷口>
前回できたと思っていたIFTTTのレシピに欠陥があったことが分かった。
欠陥はAIスピーカーに”薬飲んだ”と言ったらGoogleカレンダーに予定が書かれてLINEに”おばあちゃんが薬を飲んだ”という内容が送られてくるというものを作成していたが、
カレンダーに手動で予定を入れてもLINEに”おばあちゃんが薬飲んだ”というのが送られてきたことだ。
これは、IFTTTのGoogleカレンダーのレシピの"search"を使用して、特定のキーワードに反応してLINEに送られるようにした。
ネットで調べると、IFTTTではカレンダーの予定の変更とキャンセル(削除)はできないとのことが載っていた。

<平松>
Googleカレンダーに繋ぐことができた。ここからnoti-fireもつなげて、googleカレンダーの内容をAIスピーカーに喋らせたい。

<内田>
Javaを使用してgoogleカレンダーにアクセスできるようにできるようになった
次回は書き込めるようにしたいと思う。

<小山>
Googleカレンダーの修正の方法を探した。GAS(GoogleAppsScript)を使用すれば中身の書き換えができそうです。
次回はどこの欄にスクリプトを書くのか調べようと思う。

いい感じに進んできていると思うのでみんなで頑張っていきましょう~!



【システム設計】


正常な場合の情報の流れを図1に示す。
図1.正常な場合の情報の流れ
 図中の①でQRコードから服薬情報を読み込んだスマホは,処方された用法と日数に基づいてGoogleカレンダーに服用スケジュールを書き込む。
たとえば,朝・昼・晩・就寝前に4日間処方された場合のカレンダーおよびイベントの情報は次の図のようになる。

図2.Googleカレンダーにおける服用スケジュール

 また,Google Homeからの「○○のお薬の時間ですよ」というリマインドに対して「○○のお薬飲みました」との応答がなかった場合の情報の流れを図2に示す。

図3.応答がない場合の情報の流れ
図中の⑧までは同じであるが,⑨の応答がないので事前に設定した時間だけ待ってからベアボーンサーバから⑦の服用通知依頼をGoogle Homeへ送る。応答があるまでこれを繰り返し,これが事前に設定した回数を超えた場合薬が服用されなかった旨のメッセージを家族のもとへLINEで送る。
図1,図3の情報についてまとめたものを下表に示す。

表1.流れる情報とその詳細
 朝・昼・晩・就寝前など,システムを稼働させる上で必要な値はパラメータとしてスマホに設定できるようにする。必要なパラメータとしては次のようなものがある。

表2.必要なパラメータ

【Google Apps Script:イベントの取得】

図1の「⑫カレンダー更新」は,「⑨服用完了通知」をIFTTTがトリガーにしてWebhookを利用することによって実現する。Webhookで作動するプログラムはGAS (Google Apps Script) で開発し,Webサービスとして公開する。
GASはGoogleドライブから[新規]→[その他]→[アプリを追加]で[Google Apps Script]をインストールすると利用できるようになる。
以降,Googleドライブから[新規]→[その他]→[Google Apps Script]で編集画面が表示されるようになる。

例えば,下記はGoogleカレンダーから当日のイベントを取得するスクリプトである。

//
// Google calendarから当日のイベントを取得する
// webapi_googleCal_getEventsForDay

function doGet(e) {

  var eventData = getEventsForDay();
  responseText = JSON.stringify(eventData);
  
  var out = ContentService.createTextOutput();

  //Mime Typeをapplication/jsonに設定
  out.setMimeType(ContentService.MimeType.JSON);
  
  //JSONPテキストをセットする
  out.setContent(responseText);
  
  return out;
}

//プログラム起動日の予定をすべて取得して予定タイトルをログに表示するコード
function getEventsForDay() {
  var date = new Date();
  var options = {
    'search': 'お薬の時間です',
  };
  var events = CalendarApp.getEventsForDay(date, options);
  var eventData = [];
  events.forEach(function(event){
    var data = {
      'title': event.getTitle(),
      'description': event.getDescription(),
      'id': event.getId(),
      'location': event.getLocation(),
      'startTime': event.getStartTime(),
      'endTime': event.getEndTime(),
      'color': event.getColor(),
    }
    eventData.push(data);
  });
  return eventData;
}
関数doGetはHTTP GETメソッドの実装関数である。これを外部に公開するには,メニューから[公開]→[Webアプリケーションとして導入...]を選択する。
作成したWebサービスは以下のURLで利用できる。

https://script.google.com/macros/s/XXX...X/exec
この結果,次のようなJSON形式のイベントデータが取得できる。
[
    {
        "title": "朝のお薬の時間です",
        "description": "クラビット細粒10% 100mg 3錠",
        "id": "t4s1bi3v05bhvcjp41rr89qulg@google.com",
        "location": "医療法人 川崎病院",
        "startTime": "2019-08-03T00:31:51.000Z",
        "endTime": "2019-08-03T01:01:51.000Z",
        "color": "11"
    },
    {
        "title": "夜のお薬の時間です",
        "description": "クラビット細粒10% 100mg",
        "id": "v84ho65ceseoja7257s1moj1o8@google.com",
        "location": "医療法人 オルカ医院",
        "startTime": "2019-08-03T09:00:00.000Z",
        "endTime": "2019-08-03T09:30:00.000Z",
        "color": "11"
    }
]

【Google Apps Script:イベントの登録】 

 Googleカレンダーにイベントを登録するプログラム例を以下に示す。
//
// Google calendarにイベントを登録する
// webapi_googleCal_createEvent

function doPost(e) {

  var parameter = e.parameter;
  
  var eventData = {
    'title': parameter.title,
    'description': parameter.description,
    'location': parameter.location,
    'color': parameter.color,
 
  }
  
  var id = createEvents(eventData);
  
  var result = {
    'id': id
  }
  
  var out = ContentService.createTextOutput();
  
  responseText = JSON.stringify(result);
  
  //Mime Typeをapplication/jsonに設定
  out.setMimeType(ContentService.MimeType.JSON);
  
  //JSONPテキストをセットする
  out.setContent(responseText);
  
  return out;
}

// イベントの作成
function createEvents(eventData) {
  var calendar = CalendarApp.getDefaultCalendar();
  var title = eventData.title;
  var startTime = new Date();
  var endTime = new Date();
  endTime.setMinutes(endTime.getMinutes() + 30);
  
  var option = {
    description: eventData.description,
    location: eventData.location
  }
  
  // イベントを登録
  var event = calendar.createEvent(title, startTime, endTime, option);

  // 色を設定(赤色)
  event.setColor(eventData.color);

  // idを取得
  var id = event.getId();

  return id;
}

function testCreateEvent() {

    var eventData = {
        'title': '朝のお薬の時間です',
        'description': 'クラビット細粒10% 100mg 3錠',
        'location': '医療法人 川崎病院',
        'color': 11,
    }
    var id = createEvents(eventData);
}
このスクリプトはPOSTメッセージでイベント情報(タイトル,説明,場所,色)を受け取り,イベントを登録している。関数testCreateEventはデバッグ用の関数で,doPostの動作テストに利用する。
イベントを登録するとイベントを一意に識別するイベントidを返すので,それをJSON形式に編集してHTTP POSTリクエストのレスポンスとする。

このスクリプトをWebサービスとして公開し,それをテストするために下記のHTMLファイルを作成して簡易イベント登録ページを作成した。

<!--
  Google Calendar にイベントを登録する
-->
<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>Googleカレンダーにイベントを登録</title>
</head>
<body>
  <h1>webapi_googleCal_createEvent</h1>
  <!-- webapi_googleCal_createEvent -->
  <form method="post" action="https://script.google.com/macros/s/XXX...X/exec">
  
    <table>
  <tr><th align="left">タイトル:</th><td><input type="text" name="title" value="昼のお薬の時間です"></td></tr>
  <tr>
   <th align="left">お薬の内容:</th>
   <td>
    <textarea name="description" rows="5", cols="80">クラビット細粒10% 100mg 3錠</textarea>
   </td>
  </tr>
  <tr><th align="left">病院名:</th><td><input type="text" name="location" value="医療法人 川崎病院"></td></tr>
  <tr>
   <th align="left">色:</th>
   <td>
    <select name="color">
     <option value=0>0
     <option value=1>1
     <option value=2>2
     <option value=3>3
     <option value=4>4
     <option value=5>5
     <option value=6>6
     <option value=7>7
     <option value=8>8
     <option value=9>9
     <option value=10>10
     <option value=11>11
     <option value=12>12
    </select>
   </td>
  </tr>
    </table>
    <p>
      <input type="submit" value="送信">
    </p>
  </form>
</body>
</html>
このHTMLで作成したWebページを下図に示す。

図4.イベント登録のテスト用ページ