chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

Google App Scriptも多少は使えるようになろうと思いGASの解説本を買った

要約:AppScriptで売上管理システム風なアプリを試作していますが、複雑なビジネスロジックをFunctionで書くスキルがなく、手続き的な処理はGASに頼る必要がある。GASも多少は使える方が良いかと思い、GASの解説本(Google App Script Webアプリ開発入門)を買った
詳細:GASとは、JavaScriptをベースとして、Googleのサービスを叩けるようにクラス?ライブラリ?を拡張した言語と思っています。GASを使うとWebサービスが組めるとのことで、Webサービスにフォーカスを当てた解説本を買った。Webを実現するために必要となるContentsServiceについて多少は詳しく書かれており、これを読めばGASでAPIが構築できるのを期待*1

■追記
本を見ながらWebページを作ってみた。以下のような内容で数分でWebページが実現できた。入口が簡単だからといって、自分のやりたいことが簡単にできるとは限らないので、、喜ぶのは早い

ちなみに、、本で説明されているGUIとはかなり違っている。まぁ頭の中で変換したらいけそうではあるが。
まずやるべきは、、前回はCloud Functionsを使って室内の温湿度計測のWebAPIを作成したが、これをGASに置き換えてみる。

*1:この本の販売日は2018/10/5と4年前で、Amazonの書評を見ると、一部サービスがすでに終わってるそうです。自分はGASのWebサービスに関して知りたかったのでまぁこの本でもOKっす

ヨシタケシンスケ展に行ってきた

ヨメサンに誘われて、伊丹で開催されていていた「ヨシタケシンスケ展」に行ってきた。親子連れも多く盛況でした。自分は次の予定があったので会場を通り抜けたような感じになってしまった。その中で、、ぶくぶく観音という作品があり、観音様がなぜかブクブクしているという作品で、子供の頃に怒られたヤツを観音様がされている・・という作品です。これは惹きつけられてしまい写真を撮ってしまいました*1
写真が撮れませんでしたが、ティッシュのような薄い紙?に息を吹きかけている「トイキ」という作品も良かったです。いやー面白いっす。

■ご参考URL
『ヨシタケシンスケ展かもしれない』公式サイト
作品:トイキの写真は以下(AERA)
写真・図版(4枚目)| ヨシタケシンスケの“頭のなかがのぞける展覧会” 大人も子どもも楽しめる仕掛け〈AERA〉 | AERA dot. (アエラドット)

*1:どの作品も撮影OKだそうです

大阪府スマート農業交流会に参加->熱い会場だった

要約:大阪府主催のスマート農業交流会に参加した。大会場は80人以上の席があってほぼ満席の盛況だった。
大阪での活動事例だけでなく、高知から来ていただいて、高知での取り組みの紹介があった。どのような取り組みを行って、どれぐらいの生産性が改善されたか具体的な数値で話を聞くことができ非常に勉強になった。
交流会は大阪府立環境農林水産総合研究所主催

会議室は満員


詳細:

  • データ分析して農作業にフードバックすることで、収穫量を20%増加させることが可能
  • データ分析により収穫高が改善され、装置投資も確実に回収可能
  • 生育中の計測データは、温湿度、日射量、CO2 (発表事例によっては、葉のサイズや、節の数)
  • 日照量は自然現象なので、人間が関与できない。主に、温度、湿度、CO2濃度をいかに制御するかが重要
  • 温度については、温度が高い方が成長率が高い、一方高い温度を維持するには暖房費がかかる。このバランスを取ることが重要
  • CO2については太陽が出て植物が光合成するとCO2濃度が減少する。CO2が減少した場合に、対策を講じる(CO2のボンベを動かすか、ビニールハウスの扉を開けるか??)
  • 湿度について、あまり高くなると植物は水を吸い上げられなくなる。適切な湿度で生育させる必要がある
  • 土のデータ化は非常に難しい。少し場所が変わるだけで計測データが大きく変わる。土は農家の方々の経験で対応してもらっている(質疑応答より)
  • 農作業データ化のアプローチは何種類か用意してある。参加される農家のモチベーション、目標に応じて提案内容を変える
  • 高知県が立ち上げたPF;SAWACHI、個人情報はLGWAN*1上で管理、センサ情報はAWSに蓄積

総じて、、高知のデータ活用取り組みはすさまじいと思いました。ですが、、海外では何十年も前から、計測データに基づいた栽培を進めていたそうで、世界標準からすると日本が遅れているだけなのかもしれません。データを測って農作業に反映することで、20%の収穫アップが見込めるという説明は非常に貴重な情報でした。データ分析アプローチが投資を含めてペイできている、まれな成功事例ではないかと。。(GAFAは別にして、、)

■追記
BME280 + マイコン + AppSheetで部屋の温湿度見える化をやってみましたが、植物の生育には日射量と、CO2が必要と分かりまして、日射量センサとCO2センサを秋月に発注しました*2

■追記
退職後の次のフィールドとして、農業IoTってありなの?と思い、どんなものか知るために参加しました。参加してみて、解決すべき課題も多く、また、非常に熱い分野だとは思いました。データの収集や分析、見える化といったシステム側で自分の経験が生かせる部分もあるかと思いました。一方で、、農業IoTは県や農協、大学、企業等で推進されており、参画するとしてもどこかの組織に所属しないと、働けないのでは??とも思いました。クラウドワークスのような緩い契約形態は無いだろうと。。仕事を依頼する方も、長期契約でないと難しいだろうし。。

■追記
IoPコミュニティの活動に興味があり、個人として参加できるのか先方に質問してみた。会則から判断すると、どこかの組織か団体に所属してから参加してくださいと言われそうだ。。農家の方々が参加したいとなったら農協経由で参加するのだろうか。。
事務局より回答があり、「コミュニティは企業体等が対象」とのことだった。まぁ会則もそうなっているし、個人がやってきても困りますよね。。

■追記(2022/11/19)
農業IoT/DXに興味を持ったが、農業はデカい組織で一個人が何かできるというものではなさそうだし、ITに詳しい人も一杯いそうで、自分が特に役立てそうにないと思い、今はトーンダウン(大阪でも交流会あるようですが。。)

■ご参考URL
大阪府/大阪府におけるスマート農業の推進
高知県のIoP
農業イノベーション推進課 | 高知県庁ホームページ
高知県のIoP取り組み(PDF)
https://www.pref.kochi.lg.jp/soshiki/160601/files/2021010800303/file_2021120391822_1.pdf
IoPコミュニティ
IoP技術者コミュニティのご案内 | 高知県庁ホームページ

IoP PF Sawachiの通信プロトコルはMQTTらしい
企業の方へ – IoPが導くNext次世代型施設園芸農業への進化プロジェクト

図は、(ホーム>IoPクラウドを使う>企業の方へ)より引用

UECS対応センサユニットA型作製マニュアル | 農研機構
Attainment of Japanese Smart Greenhouse by UECS Platform
www.facebook.com
2019年9月号 | Interface – CQ出版

*1:LGWANは総合行政ネットワークなので、LGWANで接続された政府が管理するオンプレサーバなのでは?と想像

*2:いやいや、課題はそこぢゃぁないだろう・・・

色鉛筆で塗り絵

要約:色鉛筆を使った塗り絵をヨメサンが始めた。その後、忙しくなったのか教本(色鉛筆ワークブック)と色鉛筆(ヴァンゴッホ)は置いておかれたままだった。自分もやってみようと思い、書き心地のいいファーバーカステルの色鉛筆を買ってワークブックをやってみた。が、、すぐに疲れてしまい、一回にワークブックの丸を3つぐらい塗るのが限界であった
以下は今回買ったファーバーカステル ポリクロモス36色*1

詳細:ヨメサンは音楽が好きだが絵はイマイチらしく*2、勉強のためと、「色鉛筆ワークブック」とヴァンゴッホ60色の色鉛筆を買った(買ったのはヨメサン)。が、、その後忙しくなったのか、本と色鉛筆は置かれたままになった。自分の方はといえば、、シンセや作曲とかやってみたがどうも自分には音楽は無理そうと思い、残りの人生の時間を音楽ではなく絵に使おうと思った。使われていないヴァンゴッホの色鉛筆をそのまま借りたら良さそうなものだけど、、どうも書き味が好きになれない。硬い書き味でカリカリした感じで、塗っていて楽しくない*3。画材屋さんに行くといろんなメーカの色鉛筆が置かれていてどれを選んだらいいのか迷ってしまう。だったらということで、、ステッドラー、三菱、ホリベイン、ファーバーカステル等の色鉛筆を買って塗比べをしてみた(↓↓書き味を比べるために買った青色の色鉛筆↓↓)

結果、ファーバーカステルが一番塗っていて気持ちがいいと思い、カステルの色鉛筆を買うことにした。一生モノだからと色の多いのを買おうかとも思ったけど、アマゾンコメントには、「欲しい色がなかなか無くてばら売りで補充」とか、「相性もあるのでまずは36色から」とか書かれていて、とりあえず36色を買ってみた。自分は発色性はまったく分からない人間ので、書き味だけ言うと、思った通りの柔らかさで、色鉛筆を動かしているだけでもう満足な感じです。
以下は「色鉛筆ワークブック」の「カラーチャートを作ろう」のページ。本に書き込む形式なのですが、本は厚みがあって描きづらいので、本からページを切り離して使っています*4。だから。。。最後まで練習したら全部バラバラになってしまう。。

色見本の小さな丸を塗るだけでも疲れてしまって、一度に2つか3つぐらいしか塗れない(根気がつづかないというか)。ですがまぁ先は長いので毎日数個ずつ塗りながら少しずつ上達したらそれでいいかと思っています。しかし、よく見ると2日かかって塗った丸が13なので、、一日あたり6.5個か。昨日は色鉛筆が届いて嬉しかったので一杯塗ったのであった。今日は4つぐらいかと。

当初ヨメサンが勉強するために買った「色鉛筆ワークブック」ですが、基礎練習から段々と写実的な塗り絵にステップアップするので、これを続けたら少しは絵が上手になるのではと期待。塗りむらとかを気にしながら塗っているとすごく疲れる。全部終えるには1年ぐらいかかるだろう。

*1:買ったのは内緒、バレると何を無駄な事をしているのか?と怒られるだろう

*2:本人より

*3:あくまでも個人的な意見

*4:切り離しているのがバレたら怒られそうだ

AppSheetを使って部屋の温湿度を見える化

要約:温湿度センサ(BME280)の計測値をマイコンを使ってGCPにアップロード、AppSheetを使ってスマフォでグラフ表示するシステムを試作した

詳細:自分の部屋は西向きでエアコンが無い。部屋の中で熱中症になるのでは?と思われる程に暑い。前から温湿度を記録したいと思っていて、AppSheetの試作例にもちょうどいいので、温湿度の見える化をやってみた。BME280で計測した値をマイコンからGoogleDrive?のSpreadSheetに上げる際、本来はOAuthを使って認証すべきなんだけど、マイコンでOAuthは大変なので、、CloudFunctionを使って軽量のWebAPIを作成し、マイコンからはこのWebAPIにデータをPOSTする仕様とした。SpreadSheetにデータが追記されると、あとはAppSheetでグラフ化すれば部屋の温湿度の推移が見えるようになる。
システムのブロック図は以下。JS使いの人は、CloudFunctionsを使わず、GASを使ってAPIを実装すると思います

開発中のAppSheetの画面

スマフォ上の表示画面は以下。スマフォアプリを自作するとデプロイが面倒ですが、スマフォ上にAppSheetのアプリをインストールして、このアプリ上で動作するので、リリースが楽(更新操作するだけで反映される)。

8/15の場合、16:54の時点で室内の温度が36℃まで上昇している。

■ご参考
CloudFunctionsのソース(マイコンから計測データを受け取るためのWebAPI用関数)
正しく設定された場合のみ動作するコードであり、エラー処理等ほとんどなし

from googleapiclient.discovery import build
import datetime

SPREADSHEET_ID = '1g *シートID*  seM'
SHEET_NAME = "*シート名*"
RANGE = f"'{SHEET_NAME}'!A2"
SENSOR_ID = "*センサーID*"
API_KEY = "** API KEY(適当な乱数)** "

def upload(request):
    
    sensor_id = SENSOR_ID
    serial_number = ""
    temperature = 0.0
    humidity = 0.0
    pressure = 0.0
    regist_date = ""
    device_id = ""
    #print("headers....")
    #print(request.headers)

    request_json = request.get_json()
    #print(request_json)
    #print(request)
    JST = datetime.timezone(datetime.timedelta(hours=9), 'JST')
    dt = datetime.datetime.now(JST)
    jst_dt_str = dt.strftime("%Y-%m-%d %H:%M:%S")

    # check API KEY
    if "API_KEY" in request_json:
    #    print(type(request_json)) 
        api_key = request_json["API_KEY"]
    #    print(type(api_key)) 
        if api_key  == API_KEY:
            pass
        else:
            return None
    else:
        return None

    regist_date = jst_dt_str
    if "temperature" in request_json:
        temperature = request_json["temperature"]

    if "humidity" in request_json:
        humidity = request_json["humidity"]

    if "pressure" in request_json:
        pressure = request_json["pressure"]

    if "device_id" in request_json:
        device_id = request_json["device_id"]

    if "serial_number" in request_json:
        serial_number = request_json["serial_number"]

    body = {
        'values': [
            [sensor_id, temperature, humidity, pressure, serial_number, regist_date]
        ]
    }

    service = build('sheets', 'v4')  # , credentials=creds
    sheet = service.spreadsheets()
    result = sheet.values().append(spreadsheetId=SPREADSHEET_ID, range=RANGE, body=body,
                               valueInputOption="USER_ENTERED",
                               insertDataOption="INSERT_ROWS").execute()
    print(result)

    if request.args and 'message' in request.args:
        return request.args.get('message')
    elif request_json and 'message' in request_json:
        return request_json['message']
    else:
        return f'data registered'

GCP内のサービスは、Application Default Credentials(ADC)によりリソースへのアクセス権が管理できるので、SpreadSeetsAPI呼び出しの際に、credentialファイルは指定していません。

■追記
計測できるようになったとグラフ見ながら家族の面々に話をしたら、「雨が降った時間と計測グラフの山がずれている」と言われて、、確かに計測された数値が合ってるのか、家にある温湿度計と見比べる必要があると思った。(計測は30分周期なので、30分間隔でサンプリングされた結果のグラフではあるのだが)

■ご参考URL
actionの使い方解説
execute an action on a set of rows(第1回)テーブルをまたいだ処理

手を抜かずにOAuthも使ってGoogle のSheets APIを叩いてみる(gspreadを利用)

GCPの環境から手抜きでSheets APIを叩こうとして、ADCが正しく機能しないせいか、権限不足でエラーになっていた。原因の切り分けが困難なので、、まずはGCPの外側の一般アプリとしてOAuthの認証もきっちり行ってセルにアクセスしてみることにする
Python Quickstart  |  Sheets API  |  Google Developers

以下の記事の手順に従って行う
PythonでGoogle Sheetsを編集する方法

事例説明の中で、「SpreadSheetに対して鍵を作った際のメールアドレスを追加すること」という説明があった。メールアドレスに基づいてアクセス管理するから、鍵のメールアドレスをSheet側に追加する必要があると理解した。GCPからのアクセスでもこの操作が抜けていたと思える。GCP用のデフォルトID(システムが作った仮のメールアドレス)をSheetに許可追加したら、Cloud Functionからのアクセスが正常に行えるようになった。

作業メモ
1. サービスアカウントから鍵を追加してJSON形式でDL
2. Sheetの権限に対して、DLした中のメールアドレスをアクセス許可に設定
3. サンプルソースを実行

import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope =['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']
creds = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', scope)
client = gspread.authorize(creds)
sheet = client.open("SENSORLOG").sheet1
list_of_hashes = sheet.get_all_records()
print(list_of_hashes)

DLして使ったJSONファイル(一部マスクしていますが。。)

{
  "type": "service_account",
  "project_id": "home-iot-0000005",
  "private_key_id": "ded2xxxxxxxxxxxxxxxx237f",
  "private_key": "-----BEGIN PRIVATE KEY-----\n
      MIIEvQIxxxxxxxxxxxxxM2psqewwk3q2OzU=\n
      -----END PRIVATE KEY-----\n",
  "client_email": "home-iot-0000005@appspot.gserviceaccount.com",
  "client_id": "107xxxxxxxxxxxxx686",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/home-iot-00000005%40appspot.gserviceaccount.com"
}

温湿度を計測してAppSheetにアップロード、グラフ化する-> ADCで壁にあたる

やりたいこと:宅内に温湿度センサーを設置、温湿度を計測してデータをAppSheetにアップロード、スマフォでグラフ表示する

できたこと:Google スプレッドシートに計測データ管理用のシートを作成、ダミーデータを追記、AppSheetでテーブル間のRefを設定、Viewでチャートを指定してダミーデータをグラフ化。

スプレッドシートは以下(場所情報、センサ情報、計測データを各シートに分けて管理)

AppSheetの画面は以下。凝らなければチャートを選べばサクッとグラフになる。あぁ便利

残作業と方針:マイコンからどうにかしてAppSheetにデータを書き込みたい。スプレッドシートAPIはややこしいのでマイコンからは直接アクセスせず、GoogleのCloud Functionsで簡易的なWebAPIを作って、マイコンからは左記の簡易版WebAPIを叩いてAppSheetにデータをPOSTする*1
GCPの環境からSpreadSheetにアクセスするので、できたらIAMロールで権限管理したい(アカウント認証用の鍵が不要になるから)。実装サンプルにはアカウントに紐づいた権限ファイルを指定するようになっている。
IAMベストプラクティスを確認したが、IAM Roleだけで管理する方法は提示されておらず、サービスアカウントを作って、最小限の権限を与えるような説明。だから、、例に倣って、サービスアカウントを作ることにする。サンプルを見ていると、サービスアカウントにOwner権限を設定しているような。。権限が強すぎるのではなかろうか。

サービスアカウントを作る作業を始めると、「App EngineやCloud Functions」で使うのか?と選択があり、「Functionsで使う」を選ぶと「認証情報の自動検出が使えるので認証情報のファイルは要らないでしょ」と作られなかった。いわゆる、Cloud FunctionsにIAMロールが割り当てられたということだろうか。デフォルト認証方式(ADC)というらしい。余計なファイルを管理するのは漏洩リスクがあるので、IAMロールで?許可してもらえるのはありがたい。ただし、、よく見るサンプルは認証用ファイルを読み込ませているパターンであり、ファイルを指定しない方法に変更しないといけない。

Authenticating as a service account  |  Authentication  |  Google Cloud

認証処理をすっ飛ばして以下のコードでSpreadSheetsにアクセスしたら、権限異常のエラーになった。やっぱり許可されていないようだ

    service = build('sheets', 'v4')  # , credentials=creds
    sheet = service.spreadsheets()
    result = sheet.values().get(spreadsheetId=SPREADSHEET_ID,range=RANGE_NAME).execute()
    print(result)

エラー内容

HttpError(resp, content, uri=self.uri) googleapiclient.errors.HttpError: <HttpError 403 when requesting https://sheets.googleapis.com/v4/spreadsheets/1gBvm-Ku1xxxxxxxxxxxxxxKCseM/values/%E3%82%BB%E3%83%B3%E3%82%B5%5B%21A1%3AB1%5D?alt=json returned "The caller does not have permission". Details: "The caller does not have permission">

エラーを見ていると、GCP内でサービス間接続ではなく、一般権限しかないClientが普通に正面からアクセスしているだけのように思えるのだが。。

ADCが動かないのだが?といったQA
python - Use Application Default Credentials on Google Compute Engine to access Sheets API - Stack Overflow
AIP-4110: Application Default Credentials
AIP-4115: Default Credentials From Google Virtual Machines

Google Cloud Platform Japan 公式ブログ: Application Default Credentials による Google Cloud API で認証設定をシンプルに

Credential credential =  GoogleCredential.getApplicationDefault();

権限エラーが解消できず、ADCの設定がおかしいのか、Sheetsへのアクセスがおかしいのかどちらが原因かわからない。だから、、認証キーを生成して、GCP外からアクセスして、正しくアクセスできるのを確認してから、GCP内で同一リソースにアクセスするアプローチの方がいいのではないか。

ADC解説記事
GCP の Application Default Credentials を使った認証 - ぽ靴な缶

■補足
記事を読んでると、他の方々はgcloud CLIを使って動作確認をしているようだ。gcloud CLIとは何なのか詳細不明だが、テストのたびにデプロイしていたら時間がかかってしょうがないので、自分もgcloud CLI を調べて使えるようにセットアップしたい。
gcloud ツールのクイック リファレンス  |  Cloud SDK のドキュメント  |  Google Cloud

■ご参考URL
A Guide on Google Sheets with Python API using Google Cloud Platform
Google Spreadsheets and Python

*1:こういう場合、GASを使うのが一般的らしいけど、JSが苦手なので、、若干回り道だけど、Cloud Funcitonsを使う方針