Google Cloud PlatformとSigfoxとの連携方法を説明します。今回の例は、Sigfoxデバイスから送信されたメッセージをSigfoxクラウドのCallback機能で、GCPに接続。Cloud FunctionsからPub/Sub、Data FlowからBigQueryまでを対象とします。
※こちら(動画)(チュートリアル)も参考に。
事前準備
事前に、Google Cloud PlatformのアカウントとSigfoxバックエンドのアカウントを取得してください。Sigfoxバックエンドクラウドのアカウントをお持ちでない方は、Sigfox Shield for ArduinoやM5Stack COM.X Sigfoxをご購入いただき、Sigfox Buyからアカウントを取得してください。
Google Cloud Platformプロジェクトの作成
下記手順でGCPプロジェクトを作成してください
- GCPコンソールに移動
- 画面左上のプロジェクト選択後、【新しいプロジェクト】を選択
- プロジェクト名を入力し【作成】ボタンをクリック(今回は”Sigfox-GCT"というプロジェクト名で説明します)
- 再度、プロジェクト選択をクリックし、先ほど作成した新規プロジェクトを選択
- 左ナビゲーションメニューから"APIとサービス" > "ライブラリ"を開く
- 下記APIが有効になっているかを確認し、もし有効になっていない場合は有効にしてください
- Cloud Functions API
- Cloud Pub/Sub API
- Cloud Datastore API
- Cloud Build API
Sigfox Callback用Cloud Functionsをデプロイ
1.ローカル開発環境にGoogle Cloud SDK (gcloudコマンドラインツール)、git、python、pip、virtualenv、curlをインストールしてください。
2.先程作成したGCPプロジェクトの初期設定を下記コマンドで行います
$ gcloud init
3.Sigfoxデバイスのデータを受け取るPub/Sub topicを作成
$ gcloud pubsub topics create sigfox-data
4.必要に応じ、上記topicのメッセージをモニタリングするためのPub/Subサブスクリプションを作成します
$ gcloud pubsub subscriptions create sigfox-data-sub --topic sigfox-data
5.Sigfoxコールバックを受け付けるCloud Functions用に下記3ファイルを適当なフォルダ下に作成します。(ここでは"sigfox-gw"フォルダを作成し、そこに保存しておきます。)
import sys
def callback_data(request):
# [START functions_callback_data]
import os
import json
import base64
import datetime
from flask import abort
from rfc3339 import rfc3339
from google.cloud import datastore, pubsub_v1
if request.method == 'POST':
http_user = os.environ.get('HTTP_USER')
http_passwd = os.environ.get('HTTP_PASSWD')
request_user = request.authorization["username"]
request_passwd = request.authorization["password"]
if request_user == http_user and request_passwd == http_passwd:
request_dict = request.get_json()
print('Received Sigfox message: {}'.format(request_dict))
publisher = pubsub_v1.PublisherClient()
topic = os.environ.get('PUBSUB_TOPIC_DATA')
project_id = os.environ.get('GCP_PROJECT')
if not topic or not project_id:
print('Error reading Function environment variables')
return abort(500)
topic_name = 'projects/{project_id}/topics/{topic}'.format(
project_id=project_id, topic=topic)
try:
time_int = int(request_dict['time'])
except ValueError:
time_int = float(request_dict['time'])
time_int = int(time_int)
event_time = rfc3339(time_int)
request_json = json.dumps(request_dict)
message_id = publisher.publish(topic_name, request_json.encode('utf-8'),
ts=event_time.encode('utf-8'))
print('Message published to Pub/Sub topic: {}'.format(topic_name))
return '', 200
else:
print('Invalid HTTP Basic Authentication: '
'{}'.format(request.authorization))
return abort(401)
else:
print('Invalid HTTP Method to invoke Cloud Function. '
'Only POST supported')
return abort(405)
# [END functions_callback_data]
PUBSUB_TOPIC_DATA: sigfox-data
HTTP_USER: user
HTTP_PASSWD: password
.env.yamlファイルの
HTTP_USER
とHTTP_PASSWORD
をご自由に設定してください。これらの項目は、SigfoxバックエンドクラウドからGCPにCallbackする際のCloud FunctionsがHTTPS通信時に、Sigfoxバックエンドを認証するために使用するBasic認証情報となります。
rfc3339
google-cloud-pubsub
6.sigfox-gwディレクトリに移動します
$ cd sigfox-gw
7.新たにPythonの仮想環境を作成します
$ py -3.7 -m venv myvenv
(windows)
$ python3.7 -m venv myvenv
(mac, linux)
8.Pythone仮想環境を起動します
$ myvenv\Scripts\activate
(windows)
$ source myvenv/bin/activate
(mac, linux)
9.必要なPythonモジュール群をインストールします。
(myvenv) $ pip install -r requirements.txt
10.下記コマンドを使用し、Cloud Functionsをデプロイします。(--region値は、ご自身がデータの蓄積・処理を希望するCloud Functionsリージョンを設定してください。)
(myvenv) $ gcloud functions deploy --region asia-northeast1 --runtime python37 --env-vars-file .env.yaml --trigger-http callback_data
このコマンドを実行すると、下記例のようなHTTPS Trigger URLがコマンド出力されます。
httpsTrigger:
url: https://asia-northeast1-sigfox-gcp.cloudfunctions.net/callback_data
このURLはCloud FunctionsのリージョンやGCPプロジェクト名に応じ、下記フォーマットで出力されます。
https://[リージョン]-[プロジェクト名].cloudfunctions.net/callback_data
11.デプロイが終了すれば、Cloud FunctionsのWebコンソールで、Cloud Functionsがデプロイされていることを確認することができます。
Sigfox Callbackを作成
Sigfoxコールバックを受け付けるCloud Functionsが作成出来たので、次は、Sigfoxバックエンドクラウド上で、コールバックを作成します。
Sigfox Callbackは、デバイスタイプ単位で設定するため、DEVICETYPEリストから、ご自身のデバイスのデバイスタイプを選択し、Callback設定を開始してください。
AWSやAzureは専用のCallback作成メニューがありますが、GCPの場合は、Custom callbackを選択します。
各設定は下記の通りとなります。
項目 | 入力値 |
---|---|
Type | DATA_UPLINK |
Channel | URL |
Url pattern | 作成されたHTTPS Trigger URL* |
Use HTTP Method | POST |
Send SNI | ☑ |
Headers | Authorization Basic ** |
Content type | application/json |
Body | { "deviceType" : "KCCS Network Monitoring", "device" : "{device}", "time" : {time}, "data" : "{data}", "seqNumber" : {seqNumber} } |
※GCP Cloud Functionsのデプロイで生成されたURL。(https://[リージョン]-[プロジェクト名].cloudfunctions.net/callback_data )
※※Atuthorizationは、.env.yamlファイルで定義したHTTP_USERとHTTP_PASSWDからBase64エンコードした文字列となります。
全て設定し、[OK]ボタンをクリックするとCallbackが追加され、成功すると、下図のようにCloud Functionsのログで、SigfoxメッセージがPub/Sub Publishされていることが確認できます。
Sigfoxメッセージ保存用データベースを作成
次にSigfoxメッセージを保存するデータベースを作成します。
BigQueryテーブルの作成
- Google Cloud ConsoleのBigQuery画面へ移動します。
自身のプロジェクトにデータセットを作成します。データセットIDは任意(ここではds_sigfox)、ロケーションは今回は東京(asia-northeast1)にしておきます。
作成したデータセットを選択し、テーブルを新規に作成します。
テーブルを作成する際には、Pub/Sub で入力されるデータ構造に準拠したテーブル定義をする必要があります。今回は、Sigfoxコールバックとして設定したdeviceType, device, time, data, seqNumberの5項目になります。テーブルが作成出来たら、テーブルの詳細画面から表IDをメモしておきます。
表IDは、[プロジェクトID]:[データソースID].[テーブルID]になります。
Pub/SubからBigQueryに保存するCloud Functionsを作成
Pub/SubからBigQueryにデータ保存する方法は、Dataflowを使うと簡単にできますが、Dataflowの料金体系が、数個のデバイスだけの場合には割高になるため、ここではCloud Functionsで実装します。
上述のSigfox Callback用Cloud Functionsをデプロイと同様に下記コードをデプロイします。
import os
import base64
import json
from google.cloud import bigquery
def main(event, context):
"""Triggered from a message on a Cloud Pub/Sub topic.
Args:
event (dict): Event payload.
context (google.cloud.functions.Context): Metadata for the event.
"""
PROJECT = os.environ.get('PROJECT')
DATASET = os.environ.get('DATASET')
TABLE = os.environ.get('TABLE')
print(DATASET)
pubsub_message = base64.b64decode(event['data']).decode('utf-8')
print(pubsub_message)
d = json.loads(pubsub_message)
output_rows = []
output_rows.append([
d['deviceType'],
d['device'],
d['time'],
d['data'],
d['seqNumber']
])
bq_client = bigquery.Client('zservice-295907')
dataset_ref = bq_client.dataset('ds_pressure')
table_ref = dataset_ref.table('tb_pressure')
table_obj = bq_client.get_table(table_ref)
error = bq_client.insert_rows(table_obj, output_rows)
google-api-python-client
google-cloud-bigquery
PROJECT: [ご自身のプロジェクト名]
DATASET: [ご自身のプロジェクト名]:[BigQueryのデータセット名]
TABLE: [ご自身のプロジェクト名]:[BigQueryのデータセット名].[テーブル名]
上記3種類のコードを準備できれば、下記コマンドを使用し、Cloud Functionsをデプロイします。
gcloud functions deploy FUNCTION_NAME --trigger-topic TOPIC_NAME FLAGS
ここでは、FUNCTION_NAME = storeToBigQuery、TOPIC_NAMEは、先に作成したPub/Subトピックであるsigfox-dataを指定します。FLAGSは、デプロイ時に指定するオプションですので、ここでは、--runtime python37 --env-vars-file .env.yaml
としておきます。