昨日、定年サポートアプリを久しぶりにビルドして、スマフォアプリももうちょっと作り込まないとなーと思ったので、作りかけで放置してたFlutterによる電力データ表示アプリをもう少し仕上げることにした。
作り込みたい機能
1. スマフォアプリを起動したら電力値がMQTTで配信開始されるようにする(自動化が難しかったらボタン押下)
2. 最新データ取得機能(待ってられない場合に、更新ボタンを押したら最新の電力データがグラフに反映される)
3. スマフォからのアクセスがなくなったら、MQTTによる配信を自動で止める
経緯
かつて、自宅のメータをスマートメータに変えて、電力データを取れるようにNature remo E Liteを入れて、AWS LambdaからNature社のWebAPIを叩いて自宅の電力データを取得して、AWS IoT Coreを使ってMQTTで配信してスマフォで見るところまでは作った。
が、、ビジュアルに訴えるにはサンプリング周期を30秒程度で行う必要があり、ずっと30秒で上記経路を動かしているとお金がかかってしょうがない。だから、1時間周期でCRONで走らせて積算値をS3に蓄える*1以外、MQTT配信は止めていた。スマフォで見たい時だけ30秒周期のCRONを走らせてMQTT配信して、見たくなくなったらCRONを止めるというあり得ない仕様であった。利用者にMQTT配信のOn/Offをさせるのではなく、スマフォアプリの接続状態を感知して自動で配信のOn/Offするように仕込みたい。
■追記
久しぶりにFlutter動かそうと思ったらどうやってビルドしていたか、テストはEmulatorだったか実機だったかも忘れた。普段Flutter使っていたら当たり前のことだけど、時間が経つと当たり前の知識が消失している。暗黙知(俺)というやつか。暗黙知は時間が経つと消えてしまう。だから、、当たり前でもビルド手順とかインストール手順とかはメモに残すか、batch でシェル化しておかないと思い出せない。Terminalのhistoryコマンドでも当時の操作記録は古すぎて出てこないだろう。。
■追記
iOSのshellでgrepしてみた。当時の操作履歴が残っていた。なるほど、、こういうコマンドだったか。。
(理解しやすくなるよう上下入れ替えています)
$ history 0 | grep flutter 67 flutter emulators 69 flutter devices 84 flutter build 85 flutter build ios 68 flutter emulators --launch iOS 73 flutter emulators --list 74 flutter emulators 70 flutter run -d iPhone 75 flutter run --release
iPhoneをMacに接続した状態で、command historyを頼りに以下を実行した。
flutter run
iPhoneには画面が表示されて、AWS IoT Coreには接続できた(Client証明書も生きてるようだ)
利用者の立場では困惑しかないだろうが、定期収集のCRONをユーザがOn/Offする仕様で実装。以下がCRON制御付きの画面(update, start , stop のボタンが増えている)
本来、これらの操作は自動化できるはずなので、今後改定する
テストしている際、IoT Coreに接続できない時があり以下のエラーが出る。エラーメッセージが、Failed host lookupなので、ホスト名が解決できないか、ホストに到達できないような言いぶりだ。なぜだろうか。エラーになる前にすでに先方から怒られているような。。
flutter: 1-2022-07-10 16:23:35.769250 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer flutter: 1-2022-07-10 16:23:35.948536 -- MqttConnectionBase::_onError - calling disconnected callback flutter: *** in fail *** flutter: SocketException: Failed host lookup: 'a3xxxxxxxt-ats.iot.ap-northeast-1.amazonaws.com' (OS Error: nodename nor servname provided, or not known, errno = 8) flutter: 1-2022-07-10 16:23:35.968145 -- MqttConnectionHandlerBase::disconnect - entered flutter: 1-2022-07-10 16:23:35.970955 -- MqttConnectionHandlerBase::_performConnectionDisconnect entered flutter: 1-2022-07-10 16:23:35.980196 -- MqttConnectionKeepAlive::stop - stopping keep alive flutter: *** disconnected *** flutter: Subscribing to the topic:[topic_1] [VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: mqtt-client::ConnectionException: The connection must be in the Connected state in order to perform this operation. #0 MqttClient.subscribe (package:mqtt_client/src/mqtt_client.dart:345:7) #1 _MyHomePageState._connect (package:awsiot/main.dart:182:12) <asynchronous suspension>
原因は、スマフォ内でWiFiと正常に接続できない状況になっていたため。電波をつかんでいるアイコンは出ているが、アプリによるのか、疎通できない場合がある。スマフォのWiFiをOff/Onしたら正常化した
IoT Coreに向けてMQTTで topic: viewer/requestで投げると IoT CoreのMessage RoutingのruleにマッチしてLambdaがキックされるようにした。Lambdaは以下のような内容で、1分定期CRON(execute_every_1min)のOn/Offを制御できるようにした。On/Offを手動で操作しないといけないのがなんともイマイチだけど、スマフォからできるようになったので、今日のところはここまで
import json import boto3 client = boto3.client('events') RULE_NAME = 'execute_every_1min' def lambda_handler(event, context): global client # TODO implement print("----!!!!-------") print(event) # if event['msgType'] == 'request': if event['request'] == 'start_CRON': print('going enable') client.enable_rule(Name=RULE_NAME) elif event['request'] == 'stop_CRON': print('going disable') client.disable_rule(Name=RULE_NAME) return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') }
MQTTで電力データを表示、CRONをOn/Offするフローまとめ
<CRON On/Off> [SmartPhone]--(pub)-->[IoT Core]--(Route)-->[Lambda]--->[EventBridge] <Report> [EventBridge]-->[Lambda] [Nature API] [IoT Core] [SmartPhone] |--------->| | | |<---------| | | |----------------------> | | |----(pub)----> |
Flutter CLIメモ
% flutter build ios // release版のビルド % flutter install // iPhoneへのインストール
■課題
安定してMQTTブローカと接続できない印象で、本当にCRON制御できているか、かなり不安なので、状態報告機能を強化したい。このままでは任せられない。
*1:データレークというやつでしょうか