2019年10月31日木曜日

GPS ロガー的なアプリを作ってみた

前回のエントリーで HCL Nomad で NotesGPS クラスが動いたことを書きましたが、今回はその続きで、GPSの位置情報を継続的に保存する仕組みを作ってみたお話です。

LotusScript には NotesTimer という私があまり使ったことの無いクラスが存在します。NotesTimer クラスを使うと、指定した間隔(秒単位)ごとにイベントを発生させることができます。

定期的に発生するイベントでGPSからの位置情報を保存すれば、GPSロガー的なものになりそうです。


まずは、フォームを1つ作成して以下のコードをフォームへ追加しました。

(Globals)の(Declarations)
Dim elapsedTimer As NotesTimer
Dim gps As NotesGPS
Dim position As NotesGPSPosition
Dim ss As NotesSession
%INCLUDE "lsconst.lss"

(Globals)の Initialize
Sub Initialize
 Set  ss = New NotesSession
End Sub

QyeryOpen
Sub Queryopen(Source As Notesuidocument, Mode As Integer, Isnewdoc As Variant, Continue As Variant)
 On Error 4508 Goto ERROR4508
 
 Set gps = ss.CreateGPS
 gps.TimeoutSec = 9
 gps.HighAccuracy = False
 If Not gps.RequestAccess Then
  Messagebox "False",,"Request access"
  Exit Sub
 End If
 Set position = gps.GetCurrentPosition
 Call gpslog( "Start" )
 Exit Sub
 
ERROR4508:
 Messagebox "NotesGPS class のインスタンスを取得できません。" & Chr(10) & "Err: 4508"
 Continue = False
 Exit Sub
End Sub

PostOpen
Sub Postopen(Source As Notesuidocument)
 Set elapsedTimer = New NotesTimer(60, "")
 On Event Alarm From elapsedTimer Call elapsedTimerHandler
End Sub

QueryClose
Sub Queryclose(Source As Notesuidocument, Continue As Variant)
 elapsedTimer.Enabled = False
 Call gpslog( "End" )
End Sub

さらに次の2つのコードを追加しました。

Sub elapsedTimerHandler(Source As NotesTimer)
 Call gpslog( "" )
End Sub
Sub gpslog( msg As String )
 Dim ndt As NotesDateTime
 Dim doc As NotesDocument
 Dim coodinates As NotesGPSCoordinates
 
 position.Update
 Set ndt = position.TimeStamp
 Set coodinates = position.Coordinates
 
 Set doc = New NotesDocument( ss.CurrentDatabase )
 
 doc.Form = "Main"
 doc.Message = msg
 doc.gps.TimeoutSec = gps.TimeoutSec
 doc.gpsposition.TimeStamp = ndt.LSLocalTime
 
 doc.Latitude = coodinates.Latitude
 doc.Longitude = coodinates.Longitude
 doc.Altitude = coodinates.Altitude
 doc.Heading = coodinates.Heading
 doc.Speed = coodinates.Speed
 doc.Accuracy = coodinates.Accuracy
 doc.AltitudeAccuracy = coodinates.AltitudeAccuracy
 
 doc.Save True, False
 
 Set doc = Nothing
 Set ndt = Nothing
End Sub


このフォームを開くとき、NotesGPS のオブジェクトを作り、イベント発生の間隔を60秒にセットします。イベント発生ごとにコールするスクリプトを「elapsedTimerHandler」としました。

このフォームを閉じるとき、NotesTimer を非アクティブの状態にします。これでイベントが発生しなくなります。


さて NotesTimer のヘルプには次のような記述があります。
NotesTimer はエージェントではなく Lotus Notes UI オブジェクトで使用することを意図されています。
なんだか嫌な予感が...

HCL Nomad でこのフォームを前面に開いてる間は 約60秒おきに位置情報が保存されました。

フォームを開いて記録している間、HCL Nomad 上には、3つのタブ(ホーム、GPS Logger ビュー、フォーム)がありましたが、GPS Logger ビューのタブをタップしてフォームのタブが他のタブのうしろにある状態でも、位置情報は記録され続けました。※下図はフォームのタブが前面に表示されてます

しかしながら、画面の操作をしばらくやめて画面が暗転した状態では、位置情報が記録されませんでした。また HCL Nomad から別のアプリに切り替えている間も位置情報は記録されませんでした。

それから、 iPhone などのスマホでは他のアプリからの通知が表示されることがありますが、通知が表示されている間は位置情報は記録されていないような印象です。

位置情報が記録されなかった場合も、フォームを開いている間はタイマーが有効のようで、指定した間隔どおりにはなりませんでしたが遅れて記録され続けました。

こんなことがあったので、フォームを開いた後は、画面が暗くならないように画面をサワサワと触り続けたり、通知が表示されればすぐさま画面の外へスワイプするといったつまらない操作を継続的に行っていました。

そんなこんなで散歩ついでに取得した位置情報から KML ファイルを作り、Google Map へ読み込んでみると、次のように表示できました。→KMLファイルの作り方


GPS ロガーとしては、なかなか使いづらいものが出来上がりました。

2019年10月29日火曜日

Nomad で GPS を使う

つい数日前に Notes/Domino V11 Beta 2 がダウンロード可能になりました。

このベータ版で、私が楽しみにしていた機能のひとつがようやく実装されたのです!

実は V11 Beta 1 の Domino Designer でも LotusScript に新たに追加された3つのクラス、
NotesGPS
NotesGPSPosition
NotesGPSCoodinates
が見えてはいるのですが、NotesSession クラスに CreateGPS メソッドが実装されていないために実質使えなかったのです...

V11 Beta 2 の Domino Designer では、これらが動くことを確認しました。

次のコードがこれらのクラスの動作を確認できたものです。

Dim ss As New NotesSession
Dim gps As NotesGPS
Dim gpscoodinates As NotesGPSCoordinates
Dim gpsposition As NotesGPSPosition
Dim ndt As NotesDateTime
Dim msg$

Set gps = ss.CreateGPS
gps.TimeoutSec = 9
gps.HighAccuracy = False
If Not gps.RequestAccess Then
 MessageBox "False",,"Request access"
 Exit sub
End If

Set gpsposition = gps.GetCurrentPosition
Set ndt = gpsposition.TimeStamp
Set gpscoodinates = gpsposition.Coordinates

msg = _
"タイムスタンプ: " & ndt.LSLocalTime & Chr(10) &_
"緯度(Latitude): " & gpscoodinates.Latitude & Chr(10) &_
"経度(Longitude): " & gpscoodinates.Longitude & Chr(10) &_
"高度(Altitude): " & gpscoodinates.Altitude & Chr(10) &_
"緯度経度の誤差(Accuracy): " & gpscoodinates.Accuracy & Chr(10) &_
"高度の誤差(AltitudeAccuracy): " & gpscoodinates.AltitudeAccuracy & Chr(10) &_
"方角(Heading): " & gpscoodinates.Heading & Chr(10) &_
"速度(Speed): " & gpscoodinates.Speed

MessageBox msg

このコードを私の iPad 上の HCL Nomad 1.0.5 (TestFlight版)で実行すると、次のように表示されました。


ここで取得した緯度と経度の値で現在地がわかります。(自宅なので隠しましたが..)

GPS レシーバの無い端末(=私のパソコン)で実行すると、CreateGPS メソッドでコード 4508 Method is not available となりました。


さて、私がこの GPS の使い道として考えているのは、現在地に最も近い現場の情報を自動で入力/表示することです。

現在地に関係している情報とは、国、地域、住所、現場の名称の他、顧客名、プロジェクト名やこれらのコードなど意外に多いように思います。

また、iPad を持ちながら、HCL Nomad の入力画面をソフトウェアキーボードでタイプすることはかなりしんどい作業になります。リストから選択するにしても、リストが1000件にもなれば小さい画面の中で縦スクロールして見つけ出すことさえ困難なように思います。

そんな時、例えば「現場マスター」へ緯度経度の値を追加しておくことで、現在地から最も近い現場の情報を候補として表示できるようになりそうです。
たったこれだけでも使い勝手がよくなるのではないでしょうか。


これを実現するには、マスター上の緯度経度と現在地の緯度経度から「最も近い」場所を調べる必要があると考え、距離を求めるコードを書いてみました(以下)。戻り値の単位はメートルです
(lat は緯度、lng は経度、lat1 と lng1 が一方の地点、lat2 と lng2 が他方)

Function distance( lat1 As Double, lng1 As Double, lat2 As Double, lng2 As Double ) As Double
 Dim radLat1 As Double, radLng1 As Double
 Dim radLat2 As Double, radLng2 As Double
 Dim aveLat As Double, aveLng As Double
 Dim c As Double
 Const r = 6378137.0 '赤道半径
 
 '円弧の長さを扱うため、角度(緯度経度)をラジアンへ変換
 c = 180 / Pi
 radLat1 = lat1 / c
 radLng1 = lng1 / c
 radLat2 = lat2 / c
 radLng2 = lng2 / c
 
 aveLat = ( radLat1 - radLat2 ) / 2
 aveLng = ( radLng1 - radLng2 ) / 2
 
 distance = r * 2 * Asin( Sqr( Sin( aveLat ) ^ 2 + Cos( radLat1 ) * Cos( radLat2 ) * Sin( aveLng ) ^ 2 ) )
End Function

例えば、マスターに登録した緯度と経度の値を列に表示するビューを用意しておけば、最も近い情報を入力の候補として表示する、といった感じのものは簡単に作れそうです。

2019年10月17日木曜日

Nomad でも OCR

昨日の会社帰りは、約2カ月ぶりに開催された「のの会」に参加しました。


今回、私が担当したのは「iPad で OCR を試した事」のお話です。

既にこのブログでも何度も登場している NotesHTTPRequest や NotesJSONNavigator等の V10 で追加された機能が iPad でも動くことを、実機のデモを通してご紹介しました。

私が所有する iPad の OS は iPadOS にしています。昨日は ThinkPad Bluetooth ワイヤレス・トラックポイント・キーボード を使って、トラックポイントのマウス操作で HCL Nomad とそのアプリがグリグリ動く様子をご覧いただきました。

iPad でデモする時は、設定から「アクセシビリティ - タッチ - AssistiveTouch」をオンにすると、マウスカーソル的なマークがわかりやすく表示されるのがいいですね。

お話した内容をスライドにしていますので、共有いたしました。何かの参考になれば幸いです。





2019年10月11日金曜日

iPhone? iPad? @Platform の拡張について

先日 TestFlight で公開されました HCL Nomad 1.0.5 では iPhone でも使用できるということで、早速ダウンロード。

このバージョンは @Platform 関数が拡張され、iPhone と iPad を区別することができる、と説明されています。

これを試してみました。

まずは、ビューのアクションボタンに次の式を設定しました。

@Prompt([Ok];"Formula";@Platform([Specific]))

これを実行してみると、iPad と iPhone のどちらも "iOS" とだけ表示されます。

「これはバグではないか?」と思い、フィードバックしたところ、すぐさまメールで返事がありました。

回答によれば、@Platform([Specific]) の戻り値は次のようなテキストリストだというのです。

PrimaryOSNamefor example, iOS
PrimaryOSVersionNamefor example, 12.4
iOS Model Typeeither iPad or iPhone
Apple Hardware Identifierfor example, iPad8.4

さらに次の式を iPhone で実行すれば "Platform is iPhone" と表示されると。

@If(@Platform([Specific])="iPhone";@Prompt([Ok]; "Formula"; "Platform is iPhone");@Prompt([Ok]; "Formula"; "Platform is NOT iPhone")) 


よくヘルプを読んでみるとバグでもなんでもなく「文字列リストが返されます」と書いてありました... orz


気をとりなおして、先のボタンの式を次のように書き換えてみました。

@Prompt([Ok];"Formula";@Implode(@Platform([Specific]);@NewLine))

そして表示されたプロンプトがこちらです。
iPhone
iPad
Windows 10
最後の Windows 10 はおまけですが、テキストリストの3番目にある iOS Model Type で iPhone か iPad を識別できることがわかりました。

おかげで私の所有する端末が古い機種ということがバレバレです(笑)

V11 では GPS にも対応するとのことですし、まだまだ Nomad 対応アプリの開発を楽しめそうです。

2019年10月7日月曜日

NDS2019 トラブルチケットアプリの部分的裏話

NDS2019 は5都市を巡り、どの会場も盛況で幕を閉じました。

今年5回目の開催となる NDS ですが、私は今回が初参加でした。

その NDS へ参加することが決まったころ...

日本の IBM Champion でアプリを作り NDS2019 の参加者へのお土産にしよう!

とか

どうせなら iPad でも使えるアプリにしよう

さらには

ついでに CollabSphere の Beauty Contest に応募しよう!

といった話が持ち上がり、各地の NDS 最後のビアバッシュ中に、ケートリック田付様よりご説明いただいた「トラブルチケット」を作ることになりました。



アプリの概要はスライドをご覧ください。

このアプリで私が主に関わったのは Slack への投稿部分です。

開発は Domino Designer のバージョン 10.0.1 FP2 で行っていました。
IBM Domino Mobile Apps(以下 DMA)は 1.0.3 です。

当初の構想では、文書に添付された写真を文書のタイトルとともに Slack へ表示しようと考えていました。ところが、LotusScript では配列の制限があり、ちょっとしたサイズのバイナリデータを送ることができないことと、Base64 エンコードしたデータを Slack 側がサポートしていないことの2点で、写真の送信をあきらめました。Google Drive 等 Slack 以外のクラウドストレージへ送信し、そのURLを Slack で使用するといった代替案もあったのですが、複雑にしたくなかったのです。

さらに悩ましかったのは、投稿の内容が英数字だけなら Notes クライアントも iPad の DMA もうまくいくのに、ダブルバイト文字が入ると iPad では文字化けする問題が発生したことでした。

iPad の DMA から投稿自体はできるものの、Slack に表示される全角文字が "BAD+82" のような文字列になって表示されてしまう現象に遭遇したのです。

エンコードを変えてみたりなんとかできないかと工夫しようと試みましたが、どうにもうまくいきません。

万策尽きて完全にあきらめていたところ、NDS 東京会場の開催前日になり DMA 1.0.4 (このバージョンから名称が HCL Nomad へと変わりました)が TestFlight でダウンロード可能となりました。

なんとこの文字化け、1.0.4 で見事に解消していたのです!

日本語の文字化けは DMA のバグが原因であり 1.0.4 で Fix されていたのでした。

そのような訳で、NDS会場のデモでは iPad 上の HCL Nomad からの投稿後直後に、画面上部からピロンと Slack 通知が日本語で表示されたのでした。めでたしめでたし。


なお、今回作成しましたアプリは設計を公開した状態で、XPAGES.JP のWebサイトからダウンロードできるようになるようですりました。

改行を含む文字列を Slack へ投稿したり、notes:// で始まるリンクを送るコツなど、NDSのビアバッシュでほろ酔いの状態では到底話せないネタを、私の稚拙で汚いコードが語ってくれると思います。

公開されましたらこのページを更新してリンクを掲載したいと思います。
こちらからダウンロード可能です。

2019年9月28日土曜日

LotusScript で携帯電話へSMSを送信

NDS2019 も折り返し地点を回り、残り2か所となりました。

ご来場されたお客様より伺ったお話から「やってみたい」と思うことがあって、早速試したことがありますので、ここに残しておこうと思います。

現状の最新版 Notes/Domino V10 には HTTP Request を送信できる新機能があります。

9.0.1 までは Windows の HTTP Request を呼び出したり Java でプログラムを組んだりしていましたが、これらは iOS 上のクライアント(HCL Nomad) では使えません。

また Notes クライアントは Windows のほか、Mac、iOS (現在は iPad のみ) で動くクライアントがありますが、OS依存の部分など多少考慮しなければならない場合があるものの、LotusScript のコードはどのクライアントでも動くようです。

V10 の新機能を使うことで、より Web サービスとの連携が容易になりました。


さて、やってみたいこととは、携帯電話への SMS (Short Message Service)の送信です。

Twilio (トゥイリオ)というサービスをご存知でしょうか。

詳しくは上のリンクをご覧いただくとして、Twilio は SMS や自動音声通話といった、電話番号を用いたサービスと連携するための API を提供しています。

電話をかけて、文章を日本語で読み上げたり、音声ファイルを再生したりといったようなことが可能なようです。

今回はこの API を使い、私のスマートフォンへ SMS を送信してみます。

SMS を送信する場合は、場合にもよるかもしれませんが料金が発生します。

Twilio の API は Free Trial が可能です。
Sign up を済ませて初回ログインすると、表示された Console Dashboard には 500円分の TRIAL BALANCE が付与されていました。

この Dashboard には、テストに使用する発信用の電話番号(TRIAL NUMBER = Twilio電話番号)を取得できるボタンがあったり、API を使う際に必要となる「アカウント SID」と「AUTH TOKEN」もあります。

なお、私が TRIAL NUMBER を取得したところ +1 で始まる米国の電話番号が取得できました。

次のコードは、サンプルとして作成したエージェントです。

Dim ss As NotesSession
Const accountSid = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Const authToken = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Const phoneFrom = "+11231231234" '発信用電話番号(Twilio電話番号)

Sub Initialize
 Set ss = New NotesSession
 sendSMS "LotusScript から初めての  SMS 送信。ドキドキ...", "+819012345678"
End Sub

Function base64Encode( textString As String ) As String
 Dim stream As NotesStream 
 Dim db As NotesDatabase 
 Dim doc As NotesDocument 
 Dim body As NotesMIMEEntity
 
 Set stream = ss.CreateStream 
 Call stream.WriteText ( textString ) 
 
 Set db = ss.CurrentDatabase
 Set doc = db.CreateDocument
 Set body  = doc.CreateMIMEEntity
 
 Call body.SetContentFromText ( stream, "", ENC_NONE )
 Call body.EncodeContent ( ENC_BASE64 )
 
 base64encode = Replace( Replace( body.ContentAsText, Chr( 13 ), ""), Chr( 10 ), "" )
 
 Call stream.Close
End Function

Sub sendSMS( message As String, phoneTo As String )
 Dim req As NotesHTTPRequest
 Dim url$, body$, res As Variant

 url = "https://api.twilio.com/2010-04-01/Accounts/" & accountSid & "/Messages.json"

 body = |From=| & urlEncode( phoneFrom ) & _
 |&To=| & urlEncode( phoneTo ) & _
 |&Body=| & urlEncode( message )

 Set req = ss.Createhttprequest()
 req.Preferstrings = True
 req.Setheaderfield "Content-Type", "application/x-www-form-urlencoded"
 req.Setheaderfield "Accept", "application/json"
 req.Setheaderfield "Authorization", "Basic " & base64Encode( accountSid & ":" & authToken )
 res = req.Post( url, body )
End Sub

Function urlEncode( textString ) As String
 Dim notesmacro As String, res As Variant

 notesmacro = |@URLEncode( "Domino";"| & textString & |" )|
 res = Evaluate( notesmacro )
 urlEncode = res( 0 )
End Function

以下、上のコードを補足します。

2~4行目
実行に必要なアカウントSID、AUTH TOKEN、発信者番号(Twilio電話番号)を定数(Const)で設定していますが、実行時は Console Dashboard のもので置換します。
※本番で使う場合、認証情報のハードコーディングはお勧めしません

4行目、8行目
このサービスのすばらしい点のひとつは、対応する国が日本だけではないことです。ここでは私のスマホの電話番号を指定したいので、最初のゼロを除いた番号の頭に日本の番号を示す +81 を付けました。たとえば電話番号が 090-1234-5678 の場合、発信先番号へは +819012345678 と指定します。

36行目
API の URL ですが、最後を .json とすると、レスポンス(47行目)が JSON 形式で返ります。このコードではレスポンスをほぼ無視していますが、SMSが送信されない理由を調べたい場合はコードの追加が必要です。※ res を messagebox で表示するだけでも、レスポンスにあるエラーコード等がなんとなく見えます

38行目、39行目
From(発信者番号)と To(受信者番号)と Body(メッセージ)は、URLエンコードが必要です。

46行目
API は Basic 認証をサポートしています。認証情報として
アカウントSID + ":" + AUTH TOKEN
の文字列を Base64 エンコードした値を "Authorization" ヘッダーへ追加しています。

そして、エージェントを実行して、実際に iPhone で受信したところが下図です。




今回はトライアルのアカウントを使用したからでしょうか、メッセージの冒頭には "Sent from your Twilio trial account - " と追加されてしまいました。まあ、仕方ありませんね...

SMS の料金などを調べずに3回 API をコールしてしまいましたが、Dashboard を覗いてみると、まだ 500円以内に収まっていました。
もう少し楽しめそうです..

もし「私も試してみたい!」と思った方は、Qiita に「[最新版]Twilioのサインアップ」という記事がありますので、ご参考まで。

2019年9月26日木曜日

V11 新機能 テーマのカラーを変えてみた

V11ベータ1 では、Notesクライアントのテーマの色を notes.ini パラメータを追加することで変更できる機能が追加されていました。

notes.ini へセットするパラメータは次のとおりです。
CUSTOM_THEME_COLOR=<R>,<G>,<B>
<R>,<G>,<B> には、それぞれ赤、緑、青を示す数値をセットします。

V11ベータ1のデフォルトのテーマは、新たに追加された "Notes 11 Theme" です。
私には少々青が強いように感じていますが、これが HCL 社のカラーなのでしょうか...

さて、昔懐かしのロータス・カラーへ変更したい場合、
CUSTOM_THEME_COLOR=255,211,2
あたりの値をセットします。

すると、メールを開いたときの見た目は次のようになります。


notes.ini パラメータであれば、デスクトップポリシーを使ってクライアントへ設定を配布することができます。

そこで今回ご紹介した notes.ini パラメータをデスクトップポリシーを使って配布するための設定手順をスライドにまとめました。
説明がほとんどありませんがご容赦くださいませ。