Nature Remo のAPIを叩いて、室温をAzure FunctionsとCosmosDBで記録する

Nature Remoというスマートリモコンがあります。スマホのアプリやGoogle Homeなどから家電を操作できるもので去年くらいから愛用しています。このRemoにはセンサーが積んであり、温度、湿度、照度、人の動きをAPIから取得することができます(Remo miniは温度のみ)。今回、このAPIを叩きデータをためるところまでAzureのSaasを用いてクラウドだけで完結したいと思います。

### クラウド上で完結させたかった理由
- メンテナンスが必要ない
- ほぼ無料で構築できる(ストレージアカウントに数円課金される)
- 外出先でもデータが確認可能

ラズパイなどを使ったほうが構築は簡単かと思いましたが、家庭のネットワークが切れることもありますし、外から確認することも考えクラウドでやりました。


### 使うもの
- Nature Remo / Remo mini
- Remo API
- Azure Functions(以下Functions)
- Azure Consmos DB(以下CosomosDB)
- Python 3系
- VScode

## 事前準備
今回FunctionsをPythonで使うため、ポータル上でのコードの編集はできません。VVScodeからAzureへデプロイします。そこでVScodeと以下の拡張機能を用意します。

VScode 拡張機能

- Azure Account
- Azure Functions
- Azure CLI Tools
- Azure CosmosDB

Azure Functions Core Tool
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash

### VScodeでAzureにサインイン 
上記の拡張機能をインストールしたら、VScode上でF1を押し、Azure: sign in をせんたくします。開いたブラウザ上でサインインするとVScodeでAzureのサインインができます。

## Azureのリソースを準備する
### CosmosDB 
CosmosDBを作成します。これはポータル上から行っても、VScodeからデプロイしてもかまいません。
VScodeで作成する場合

1. VScode上でF1を押し、CosmosDB:Create Account...を選択
2. Account名に任意の名前を入力します。(グローバルに一意)
3. CosomosDBのAPIをCore(SQL)と選択します。
4. Apply Free Tier Discountをapplyとします。
5. ほかの質問に順に回答してください。

https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-integrate-store-unstructured-data-cosmosdb?tabs=javascript

CosmosDBは無料範囲があり、以下のFAQにあるように400RU/秒と5GBのストレージが無料で使えます。
https://azure.microsoft.com/pricing/details/cosmos-db/

### Functions

Functionsは今回Pythonで構築するためVScodeから行います。

1. VScodeでF1を押す。
2. Functionsを検索しAzure Functions: Create New Projectをする。
3. ローカルで開発するディレクトリを選択する
4. Pythonを選び、ローカルにインストールしているPython本体の実行ファイルを選択します。
5. Triggerを選択します。今回はTimerTriggerで行います。
6. Functionの名前を入力します。
7. TimerTriggerの実行頻度をCRON式で入力する。デフォルトの```0 */5 * * * *```は5分ごとの実行です。
   
これでローカルにプロジェクトと関数のテンプレートができました。

## 関数作り

まず普通にPythonでRemoのAPIを叩けることを確認します。以下の記事のPythonのコード用いました。アクセストークンを入手し、ローカルでAPIが叩けることを確認しましょう。この記事中でも注意されいているように、APIkeyを流出させないように気をつけましょう。API経由で家電が他人に操作し放題となります。
https://qiita.com/sohsatoh/items/b710ab3fa05e77ab2b0a

結果は以下のようなjsonが返ってきます。Remo miniを用いたので```newest_event```において```te```の項目で温度のみ出力されています。

```
[
    {
        "name": "Remomini",
        "id": <your remo id>,
        "created_at": "2019-07-21T13:01:54Z",
        "updated_at": "2020-04-29T05:18:05Z",
        "mac_address": <your remo mac address>,
        "serial_number": <your remo serial number>,
        "firmware_version": "Remo-mini/1.0.92-g86d241a",
        "temperature_offset": 0,
        "humidity_offset": 0,
        "users": [
            {
                "id": <your id>,
                "nickname": <your nickname>,
                "superuser": true
            }
        ],
        "newest_events": {
            "te": {
                "val": 23,
                "created_at": "2020-04-30T05:10:10Z"
            }
        }
    }
]
```

```created_at``` がRemoを設定した日時、```updated_at``` がRemoをアップデートした日時(自動でアップデートされる？)のようです。


今回知りたいのは```newest_event```なので、その中身とAPIを叩いた時間をCosmosDBに送ります。```newest_events```はセンサーの値が変化した際に更新される仕様のようなので、この```created_at```はAPIを叩いた時間とは異なります。

このコードをtimetriggerのテンプレートコードに載せていきます。


```
__init__.py
import datetime
import logging
import json
import requests
import azure.functions as func


def main(mytimer: func.TimerRequest, doc: func.Out[func.Document]) -> func.HttpResponse:
    utc_timestamp = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc).isoformat()

    if mytimer.past_due:
        logging.info('The timer is past due!')

    apikey= "<your remo API key>"
    # get JSON
    headers = {
        'accept' : 'application/json',
        'Authorization' : 'Bearer ' + apikey ,
    }
    response = requests.get('https://api.nature.global/1/devices', headers= headers, verify=False)
    rjson = response.json()
    res_json = rjson[0]["newest_events"]["te"]
    res_json["request_time"]= utc_timestamp
    res_json = json.dumps(res_json,indent=2)
    logging.info('Python timer trigger function ran at %s', utc_timestamp)
    doc.set(func.Document.from_json(res_json))
```

```mytimer: func.TimerRequest```はazure.functionsのモジュールからのタイマー
、```doc: func.Out[func.Document]```はazure.functionsの出力を意味しています。

今設定した```doc```という変数に値をセットすることで出力することができます。```doc```という変数は関数作成時に生成された```function.json```にCosmosDBへ送る値だということを記述します。

## 関数アプリの設定

1. F1キーでコマンドターミナルを出し、bindingと入力し、Azure Functions: Add bindingを選択します。(サイドバーのAzureロゴからローカルの先ほど作成した関数を右クリックすることでもできます。)
2. 先ほど作成した関数を選択します。
3. 今回は出力なのでoutを選択します。
4. Azure CosmosDBを選択します。
5. 関数の中で用いる変数名を入力します。今回は```doc```とします。
6. CosmosDB内のデータベース名を入力します。今回は```home```とします。
7. データベース内のcollection名を入力します。今回は```temperature```にします。
8. DBが存在しない場合に作成するかについて、```true```とします。
9. ローカル環境の設定について聞かれるので```Create new local app setting```で作成します。
10. データベースのアカウントを聞かれるので、作成した```home```を選択します。
11. Partitionkeyは任意なのでスルーします。

! Database名はグローバルに一意でないといけないため、任意の名前としてください

これでfunction.jsonに以下の内容が追加されます。

```
    {
      "type": "cosmosDB",
      "direction": "out",
      "name": "doc",
      "databaseName": "home",
      "collectionName": "temperature",
      "createIfNotExists": "true",
      "connectionStringSetting": "cielohome_DOCUMENTDB"
    }
```

これで出力の設定ができました。なおCosmosDBのconnectionStringは同ディレクトリの```local.settings.json```に記載されています。

```
"cielohome_DOCUMENTDB": "AccountEndpoint=https://hogehoge.documents.azure.com:443/;AccountKey=fugafuga;"
```

## ローカルでテスト

ローカルでテストするために、必要なモジュールを入手します。今回は必要なモジュールは```azure-functions```, ```requests```なので同ディレクトリのrequirements.txtに記載します。

```
azure-functions
requests
```
これを```pip install requirements.txt```で入手します。

F5キーを押すとデバッグできます。

## Functionsにデプロイする

1. F1キーでコマンドターミナルを出し、deployと検索し、```Azure Functions: deploy to function app ....```を選択する。
2. ```Create new Function App in Azure (Advanced)```を選択
3. 任意のリソース名を入力する。(グローバルに一意の名前)
4. Python 3.7を選択する。
5. Coonsumptionを選択する。従量課金です。Functionsも無料枠があるため5分に一回程度であれば基本的に課金されません。
6. リソースグループ選択する。CosmosDBと同じリソースグループとします。違うものでも大丈夫です。リソースグループがLinuxで作っていないとPythonのアプリが動かないので注意する。
7. storage accountを選択します。
8. Application insightsを選択します。ログを見たりするSaasです。

これでデプロイが完了しています。

## CosmosDBでデータを確認する

関数のデプロイができたら、データを見てみましょう。
VScode上からAzureのロゴをクリックしてサイドバーのCosmosDBを確認します。データベースを開くと```temperature```にドキュメントとしてできています。

```
  "val": 24.2,
  "created_at": "2020-05-02T13:49:12Z",
  "request_time": "2020-05-02T14:00:00.007771+00:00"
```
これで完成です。

## まとめ

これでAzureでFunctionsとCosmosDBを用いてデータを格納することができました。次回はこのデータを可視化してみたいと思います。

## 参考
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-integrate-store-unstructured-data-cosmosdb?tabs=javascript
https://docs.microsoft.com/ja-jp/azure/azure-functions/
https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference-python
<a target="_blank" href="https://www.amazon.co.jp/gp/product/B07CWNLHJ8/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B07CWNLHJ8&linkCode=as2&tag=shirou463-22&linkId=fcd34229fc07d77adde43a00fe48cb3a">Nature スマートリモコン Nature Remo mini 家電コントロール Amazon Alexa / Google Home / Siri 対応 GPS連携 温度センサー Remo-2W1</a><img src="//ir-jp.amazon-adsystem.com/e/ir?t=shirou463-22&l=am2&o=9&a=B07CWNLHJ8" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

##  おまけ
MicrosoftのPowerBI Desktopというソフトがあるので、それで簡単に簡単に可視化してみるとこんな感じでした。Azureとの連携が簡単なので楽でいいですね。

![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550841/c28f406c-18d8-5d29-2a2e-4d354b1bb394.png)