ワンライナーコードでNetatmoからデータを取得, 表示する

# 概要

NetatmoのAPIを使用してデータを取得するためのスクリプトをご紹介します。ここではデータ取得するための道具としてcurl, jqを選択しました。これらはwindows版も公開されていることから、サンプルスクリプトはバッチファイルとシェルスクリプトを用意しました。

先日、コマンドラインからNetatmoのデータを見ることができればとその手法について考えていた時、多く報告されているような手法ではなくあまり見られないcurl, jqで作ってはどうかということ、そしてバッチファイル、シェルスクリプトを比較勉強するチャンスとの考えに至り、ご紹介するような方法を採用しました。今回の手法はまだ不慣れなこともあり、簡略化、改善できる所も多いかと思われます。お見苦しいところがありましたらご容赦ください。改善点がありましたらご指摘いただけますと嬉しいです。また、この記事が少しでもお役に立てますと幸いです。

作成したスクリプトはこちら（[GitHub](https://github.com/tanaikech/cui4netatmo)）にまとめています。

# 準備

## 必要な道具の準備

- Netatmo ウェザーステーション : 概要 [https://www.netatmo.com/product/weather/weatherstation](https://www.netatmo.com/product/weather/weatherstation)

- curl : 概要 [https://ja.wikipedia.org/wiki/CURL](https://ja.wikipedia.org/wiki/CURL)

こちら（[https://curl.haxx.se/download.html](https://curl.haxx.se/download.html)）からダウンロードすることができます。

- jq : 概要 [https://github.com/stedolan/jq/wiki/Cookbook](https://github.com/stedolan/jq/wiki/Cookbook)

こちら（[https://stedolan.github.io/jq/download/](https://stedolan.github.io/jq/download/)）からダウンロードすることができます。

※windowsで使用する場合は、上記からwindows版をダウンロードして解凍し、パスを通してください。

## APIを使用するための準備

1. NetatmoのNetatmo Developers（[https://dev.netatmo.com/](https://dev.netatmo.com/)）ページを開いて上部の「CREATE YOUR APP」をクリックしてログインし、「App name」「App Description」を記入して「Client id」、「Client secret」を取得します。

2. 自分のNetatmoのデバイスIDを取得しておきます。デバイスIDは、NetatmoのMACアドレスを指します。これが"device_id"に当たります。確認方法は、通常のNetatmoへのログイン後、歯車マークのデバイス設定を開き、屋内モジュールのMACアドレスがそれに当たります。

この記事の作成中に初めて気付いたのですが、Netatmo本体を所持していなくとも本体を所持しているユーザから招待され、ゲストとしてログインすることができればアプリ登録ができるようになり、「Client id」、「Client secret」を取得することができるようです。これらを使用することでAPIを使用したデータ取得が可能になります。これまで本体を所持していないとAPIは使用できないと考えていましたので驚きました。

# データ取得

ここでご紹介する全てのスクリプトについて、出力結果は全て同じです。

## ワンライナーコード

'#####'の部分はシングルコーテーションも含めて環境に合わせて上書きしてください。
例えばclient idが12345の場合、「client_id='#####'」に対して「client_id=12345」に変更してください。
username, passwordはブラウザなどで通常Netatmoへログインする際に使用するアカウントです。
両スクリプトの流れは、アクセストークン取得後、そのアクセストークンを使ってデータを取得し、jqを使ってJSONをパースしてデータを表示しています。この場合、リフレッシュトークンは使用しません。

### cmd（windowsコマンドプロンプト）

動作確認したcmdのバージョンは10.0.14393（windows10）です。

```bat:
> setlocal & curl -s -d "grant_type=password&client_id='#####'&client_secret='#####'&username='#####'&password='#####'&scope=read_station" "https://api.netatmo.net/oauth2/token" | for /f "usebackq tokens=*" %a in (`jq -r ".access_token"`) do @set a="%a" | curl -s -d "access_token=%a&device_id='#####'" "https://api.netatmo.net/api/getstationsdata" > dat.txt & for /f "usebackq tokens=*" %b in (`jq -r ".body.devices[0].dashboard_data.Temperature" dat.txt`) do @set b="%b" | echo: & set /p nb=Indoor: Temperature %b [degree C],<nul & for /f "usebackq tokens=*" %b in (`jq -r ".body.devices[0].dashboard_data.Humidity" dat.txt`) do @set b="%b" | set /p nb=Humidity %b [%],<nul & for /f "usebackq tokens=*" %b in (`jq -r ".body.devices[0].dashboard_data.Pressure" dat.txt`) do @set b="%b" | set /p nb=Pressure %b [hPa]<nul & for /f "usebackq tokens=*" %b in (`jq -r ".body.devices[0].modules[0].dashboard_data.Temperature" dat.txt`) do @set b="%b" | echo: & set /p nb=Outdoor: Temperature %b [degree C],<nul & for /f "usebackq tokens=*" %b in (`jq -r ".body.devices[0].modules[0].dashboard_data.Humidity" dat.txt`) do @set b="%b" | set /p nb=Humidity %b [%]<nul & del dat.txt

Indoor: Temperature 12 [degree C], Humidity 56 [%], Pressure 1000.2 [hPa]
Outdoor: Temperature 12.3 [degree C], Humidity 56 [%]
```

***コメント***

1. bashのようにjqで値を取得しつつテキストとともに整形、表示したかったのですが、シングルコーテーションを使用するとエラーになるため上記のような流れになりました。

2. 取得したデータを環境変数に保存し、それを利用してデータ整形、表示をしたかったのですが、環境変数に保存することができなかったため一時ファイルを作成してそこへデータを格納し、データ表示後に削除しています。

### bash

動作確認したbashのバージョンは4.3.46です。

```sh:
$ curl -s -d "grant_type=password&client_id='#####'&client_secret='#####'&username='#####'&password='#####'&scope=read_station" "https://api.netatmo.net/oauth2/token"|curl -s -d "access_token=`jq -r '.access_token'`&device_id='#####'" "https://api.netatmo.net/api/getstationsdata"|jq -r '"\nIndoor: Temperature "+(.body.devices[0].dashboard_data.Temperature|tostring)+" [degree C], Humidity "+(.body.devices[0].dashboard_data.Humidity|tostring)+" [%], Pressure "+(.body.devices[0].dashboard_data.Pressure|tostring)+" [hPa]\nOutdoor: Temperature "+(.body.devices[0].modules[0].dashboard_data.Temperature|tostring)+" [degree C], Humidity "+(.body.devices[0].modules[0].dashboard_data.Humidity|tostring)+" [%]"'

Indoor: Temperature 12 [degree C], Humidity 56 [%], Pressure 1000.2 [hPa]
Outdoor: Temperature 12.3 [degree C], Humidity 56 [%]
```

## リフレッシュトークン使用機能の追加

OAuth2.0認証で取得した情報をファイルに保存し、アクセストークンの期限が切れた場合はリフレッシュトークンを使ってアクセストークンを再取得します。アクセストークンの期限はアクセストークンが保存されたファイルの日付から計算しています。取得したデータはデータファイルへ保存しています。今の場合、実行時のデータだけ（最新のデータ）を参照したいと考えていたため、実行１回分のデータのみ保存しています。データを蓄積していく場合はスクリプトを変更してください。

また、 用意した上記の情報を別ファイルとしてaccount.jsonへ記入します。こちら（[GitHub](https://github.com/tanaikech/cui4netatmo)）からダウンロードするか、テキストエディタで作成しても問題ありません。別ファイルにした理由は、バッチファイルおよびシェルスクリプトから使用できるようにするためです。"#####"の部分はダブルコーテーションを含めず環境に合わせて上書きしてください。例えばclient idが12345の場合、「client_id="#####"」に対して「client_id="12345"」に変更してください。

```
{
    "client_id"    : "#####",
    "client_secret": "#####",
    "username"     : "#####",
    "password"     : "#####",
    "device_id"    : "#####"
}
```

### バッチファイル

下記スクリプトをバッチファイル（拡張子は bat）として保存するか、こちら（[GitHub](https://github.com/tanaikech/cui4netatmo)）からダウンロードしてください。

```bat:
@echo off
setlocal
set accountfile="account.json"
for /f "usebackq tokens=*" %%a in (`jq -r ".client_id" %accountfile%`) do @set client_id=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".client_secret" %accountfile%`) do @set client_secret=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".username" %accountfile%`) do @set username=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".password" %accountfile%`) do @set password=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".device_id" %accountfile%`) do @set device_id=%%a
set authurl="https://api.netatmo.net/oauth2/token"
set tokenfile="token.json"
set datafile="data.json"

if not exist %tokenfile% (
    echo Get new access token
    curl -s -d "grant_type=password&client_id=%client_id%&client_secret=%client_secret%&username=%username%&password=%password%&scope=read_station" "%authurl%" > %tokenfile%
)
for /f "usebackq tokens=*" %%a in (`jq -r ".access_token" %tokenfile%`) do @set atoken=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".refresh_token" %tokenfile%`) do @set rtoken=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".expires_in" %tokenfile%`) do @set expiration=%%a

for %%i in (%tokenfile%) do @set tokent=%%~ti
set y1=%tokent:~0,4%
set /a m1=1%tokent:~5,2%-100
set /a d1=1%tokent:~8,2%-100
set /a j1=1%tokent:~11,2%-100
set /a f1=1%tokent:~14,2%-100
set b1=0
call :ConvUnixTime %y1% %m1% %d1% %j1% %f1% %b1%
set /a limittime=%UT%+%expiration%
set y2=%date:~0,4%
set /a m2=1%date:~5,2%-100
set /a d2=1%date:~8,2%-100
set /a j2=1%time:~0,2%-100
set /a f2=1%time:~3,2%-100
set b2=0
call :ConvUnixTime %y2% %m2% %d2% %j2% %f2% %b2%
set currenttime=%UT%

if %limittime% lss %currenttime% (
    echo Using refresh token
    curl -s -d "grant_type=refresh_token&refresh_token=%rtoken%&client_id=%client_id%&client_secret=%client_secret%" "%authurl%" > %tokenfile%
    for /f "usebackq tokens=*" %%a in (`jq -r ".access_token" %tokenfile%`) do @set atoken=%%a
)

curl -s -d "access_token=%atoken%&device_id=%device_id%" "https://api.netatmo.net/api/getstationsdata" > %datafile%
for /f "usebackq tokens=*" %%a in (`jq -r ".body.devices[0].dashboard_data.Temperature" %datafile%`) do @set intemp=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".body.devices[0].dashboard_data.Humidity" %datafile%`) do @set inhumi=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".body.devices[0].dashboard_data.Pressure" %datafile%`) do @set pres=%%a
echo Indoor: Temperature %intemp% [degree C], Humidity %inhumi% [%%], Pressure %pres% [hPa]
for /f "usebackq tokens=*" %%a in (`jq -r ".body.devices[0].modules[0].dashboard_data.Temperature" %datafile%`) do @set extemp=%%a
for /f "usebackq tokens=*" %%a in (`jq -r ".body.devices[0].modules[0].dashboard_data.Humidity" %datafile%`) do @set exhumi=%%a
echo Outdoor: Temperature %extemp% [degree C], Humidity %exhumi% [%%]
goto :EOF

:ConvUnixTime
set y=%1
set m=%2
set d=%3
set j=%4
set f=%5
set b=%6
set /a utime=86400*(365*%y%+(%y%/4)-(%y%/100)+(%y%/400)+(306*(%m%+1)/10)-428+%d%-719161)+3600*%j%+60*%f%+%b%-(9*3600)
set "UT=%utime%"
goto :EOF
```

実行結果は下記のようになります。

```bat:
Indoor: Temperature 12 [degree C], Humidity 56 [%], Pressure 1000.2 [hPa]
Outdoor: Temperature 12.3 [degree C], Humidity 56 [%]
```
### シェルスクリプト

下記スクリプトをシェルスクリプト（拡張子は sh）として保存するか、こちら（[GitHub](https://github.com/tanaikech/cui4netatmo)）からダウンロードしてください。

```sh:
#! /bin/sh
set +x
accountfile="account.json"
client_id=`jq -r ".client_id" $accountfile`
client_secret=`jq -r ".client_secret" $accountfile`
username=`jq -r ".username" $accountfile`
password=`jq -r ".password" $accountfile`
device_id=`jq -r ".device_id" $accountfile`
authurl="https://api.netatmo.net/oauth2/token"
tokenfile="token.json"
datafile="data.json"

if [ ! -f $tokenfile ]; then
    echo "Get new access token"
    curl -s -d "grant_type=password&client_id=${client_id}&client_secret=${client_secret}&username=${username}&password=${password}&scope=read_station" "${authurl}" > ${tokenfile}
fi
atoken=`jq -r ".access_token" $tokenfile`
rtoken=`jq -r ".refresh_token" $tokenfile`
expiration=`jq -r ".expires_in" $tokenfile`

filedate=`date +%Y-%m-%d_%H:%M:%S -r $tokenfile`
filedate=${filedate/_/ }
filedate=`date -d "$filedate" +%s`
limittime=`expr $filedate + $expiration`
currenttime=`date +%s`

if [ $limittime -lt $currenttime ]; then
    echo "Using refresh token"
    curl -s -d "grant_type=refresh_token&refresh_token=${rtoken}&client_id=${client_id}&client_secret=${client_secret}" "${authurl}" > $tokenfile
    atoken=`jq -r ".access_token" $tokenfile`
fi

curl -s -d "access_token=${atoken}&device_id=${device_id}" "https://api.netatmo.net/api/getstationsdata" > $datafile
intemp=`jq -r ".body.devices[0].dashboard_data.Temperature" $datafile`
inhumi=`jq -r ".body.devices[0].dashboard_data.Humidity" $datafile`
pres=`jq -r ".body.devices[0].dashboard_data.Pressure" $datafile`
echo "Indoor: Temperature $intemp [degree C], Humidity $inhumi [%], Pressure $pres [hPa]"
extemp=`jq -r ".body.devices[0].modules[0].dashboard_data.Temperature" $datafile`
exhumi=`jq -r ".body.devices[0].modules[0].dashboard_data.Humidity" $datafile`
echo "Outdoor: Temperature $extemp [degree C], Humidity $exhumi [%]"

```

実行結果は下記のようになります。

```sh:
Indoor: Temperature 12 [degree C], Humidity 56 [%], Pressure 1000.2 [hPa]
Outdoor: Temperature 12.3 [degree C], Humidity 56 [%]
```