複数ソース(SwitchBot, OpenWeater,etc)からの温度・湿度情報をInfluxDBに保存してGrafanaで表示する

## 今年も暑い

[“今日も暑ーい1日になりそうです” ほら言ってる わっ超あおられる ♪](https://www.oricon.co.jp/prof/93788/lyrics/I010228/)

ほんとテレビのニュースをみると暑いって話ばかり。なので家で安全に過ごしたい。外に出る場合も温度や温度を把握しておきたい。

## 参考にした記事

次のデバイス or APIから温度あるいは湿度の情報を得て

- [OpenWeather](https://openweathermap.org/) (Cloud API)
- [SwitchBot](https://www.switchbot.jp/)温湿時計シリーズ (IoTデバイス)
- [TEMPer](https://www.amazon.co.jp/dp/B004FI1570/)温度計 (USBデバイス)

次の記事で InfluxDBv2 に格納し Grafana で可視化することができる。

https://qiita.com/yoroyasu/items/56e687df4e8970c5e49a

https://zenn.dev/tanny/articles/a5c0fa5c2230a7

https://qiita.com/hkato/items/173e1008cbec8054787b

## やりたいこと

私は [SwitchBot Hub2](https://www.switchbot.jp/products/switchbot-hub2) も [TEMPer](https://www.amazon.co.jp/dp/B004FI1570) も所有してるので、OpenWeather 含め、これらの温湿度情報まとめて表示したい。

## Grafana から InfluxDB の Flux Query

Fluxを良くわかってないので間違っているかもしれません。とりあえずユニオンすれば良いかなぁとやって出来たので…他に良い方法があるのかもしれませんが…。

SwitchBotの記事の様に単一の情報元なら次の様なクエリーでGrafanaに表示できる。

```sql
from(bucket: "switchbot")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
    r._measurement == "MeterPlus" and
    r._field == "humidity"
  )
```

じゃあ複数をまとめるには？

fromで取得したデータはstreamという様なので、各情報を一旦streamに入れる。

### OpenWeatherMap

上記のOpenWeatherの参考記事の様にTelegrafのOpenWeatherMap PlugIn で取得しているのでCPU, MEMなどの情報も入っている。ここから私は`raspi`という名前のバケットに格納した。`_measurement`の`weather`に天気情報が入っているが`cpu`, `mem`なども入っているので`weather`でフィルタし、温度の場合は`temperature`でフィルタする。後でまとめるセンサーのデータと混ぜると`city`,`condition_name`などが邪魔になるので最低限必要なカラムだけキープする。

```sql
openweathermap = 
from(bucket: "raspi")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_measurement"] == "weather")
  |> filter(fn: (r) => r["_field"] == "temperature")
  |> keep(columns: ["_measurement", "_field", "_time", "_value"])
```

### SwitchBot

上記のSwitchBotの参考記事のやり方で行い、`switchbot`バケットに入れているのと、私は複数デバイスを持っているので`temperature`だけでフィルタした。

```sql
switchbot =
from(bucket: "switchbot")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_field"] == "temperature")
```

### TEMPer

こちらも同様。

```sql
temper = 
from(bucket: "temper")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_field"] == "temperature")
```

### まとめる

`union`でまとめて必要なカラムだけ残す。

```sql
union(tables: [openweathermap, switchbot, temper])
```

### 結果

```sql
openweathermap = 
from(bucket: "raspi")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_measurement"] == "weather")
  |> filter(fn: (r) => r["_field"] == "temperature")
  |> keep(columns: ["_measurement", "_field", "_time", "_value"])

switchbot =
from(bucket: "switchbot")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_field"] == "temperature")

temper = 
from(bucket: "temper")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_field"] == "temperature")

union(tables: [openweathermap, switchbot, temper])
```

同様に湿度は`humidity`でフィルタ。

## 凡例の名前を変える

下記のGrafanaフォーラムに書かれた方法の通りの手順で凡例名(Legend names)をわかりやすい名前に変えていく(家族も見るので)。

https://community.grafana.com/t/grafana-time-series-mqtt-legend-names-change/72506

## できたグラフ

QNAPでGradana+InfluxDBを動かしReverse Proxyで公開してるので外からスマフォ画面で。

![20240625-grafana.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132537/6466b30e-ffa4-f742-b711-c5072541fd3f.png)

## もろもろ

- Flux Queryがこれで良いのかどうか不明なので勉強する
- 夏に負けない