Zabbixマップ機能で「お天気情報マップ」

[Zabbix AdcentCalendar 2019](https://qiita.com/advent-calendar/2019/zabbix) の12日目の記事です。

# はじめに
2019/11/15(金)に開催されたZabbix Conference Japan 2019、今年は [マップコンテスト](https://www.zabbix.com/jp/events/conference_japan_2019_agenda#day1_1400)の参加者として参加をさせていただきました！
発表した内容は特にひねりもなく、誰でも数秒で思いつきそうなネタでした…！😅
ここではそのマップを作った際の手順をまとめますので、「なんやこんなん簡単やん！」と感じたら、ぜひ来年のマップコンテストにもっともっと高度で素敵なマップを応募してください〜！！

# マップコンテストとは
Zabbix Conference Japan 2018からやっているカンファレンス内の1コーナー。以下、アジェンダより。

> Zabbixの標準機能である『マップ』機能を使用したコンテストです。
> 高度な表現力を活かした作品を集め利便性・機能性・芸術性・娯楽性などあらゆる観点で審査し、最も優ている作品を決定するものです。
> 応募に際しての制約は1点『Zabbixのマップ機能を用いて生成された作品であること(Zabbixのバージョンは不問)』のみです。

というわけで、そんな Zabbix Conference Japan 2019の発表資料は[こちら](https://assets.zabbix.com/img/zabconf2019_jp/presentations/07_zabconf2019.pdf)。

# 発表した内容
私が発表した内容は「お天気情報マップ」
同じくコンテストに応募されたサンネットの方とネタかぶり…😓

![図x4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/cfbe58c4-c1a4-e174-f265-347094239aa1.png)

- 全国の天気
- 全国の風向・風速
- 世界のZabbix拠点の天気
- 世界のZabbix拠点の風向・風速

をZabbixのマップ機能を使って表現しました。

# やったこと
## OpenWeatherMapの準備
お天気情報の取得は、OpenWeatherMapを使います。
[OpenWeatherMapのAPI](https://openweathermap.org/api) はアカウント登録することで無料使用が可能です。（有料オプションあり）
Sign UpするとAPI keyをもらえます。
無料プランでは現在の天気情報と、5日間の3時間ごとの予報がjson,XML,HTMLで取得できます。
取得できる項目は、天気概要, 天気アイコンID, 気温, 気圧, 湿度, 最低気温, 最高気温, 風速, 風向き…など。

例えば、札幌の今の天気情報をjsonで取得したい場合は以下のようなURLをリクエストします。

```
https://api.openweathermap.org/data/2.5/weather?APPID={API key}&units=metric&q=sapporo
```

パラメータのunitsにはmetric（摂氏）を、qには都市名（sapporo）を指定します。
すると、以下のようなjsonが取れてきます。

```json
{
    coord: {
        lon: 141.34,
        lat: 43.04
    },
    weather: [
        {
            id: 803,
            main: "Clouds",
            description: "broken clouds",
            icon: "04n"
        }
    ],
    base: "stations",
    main: {
        temp: -1.33,
        pressure: 1025,
        humidity: 68,
        temp_min: -2,
        temp_max: -1
    },
    visibility: 10000,
    wind: {
        speed: 2.6,
        deg: 120
    },
    clouds: {
        all: 75
    },
    dt: 1575892615,
    sys: {
        type: 1,
        id: 7973,
        country: "JP",
        sunrise: 1575842020,
        sunset: 1575874795
    },
    timezone: 32400,
    id: 2130404,
    name: "Sapporo",
    cod: 200
}
```

天気アイコンは、`$.weather[0].icon`にあたり、`04n`のようなアイコンファイル名が返されます。
どのアイコンがどの天気を表しているかは[こちら](https://openweathermap.org/weather-conditions)のページから確認ができます。

## Zabbix側の準備

### ホスト登録
地点をホストとして登録します。例であげた札幌がそのままホスト名「Sapporo」で登録されるイメージです。
全部で以下の都市を登録しました。

札幌: Sapporo
釧路: Kushiro
仙台: Sendai
新潟: Niigata
東京: Tokyo
名古屋: Nagoya
金沢: Kanazawa
大阪: Osaka
広島: Hiroshima
高知: Kochi-shi
福岡: Fukuoka
那覇: Naha-shi

世界のZabbix拠点は以下の地名を登録しています。

ヨーロッパ: Riga
USA: Brooklyn
ロシア: Moscow
中国: Shanghai

メジャーな都市は都市名だけで引き当てられるのですが、たまにXxxx-shi（○○市）としないと取得できない都市もありました。
当然ですが、OpenWeatherMapでデータが収集されている地名でないといけません。
OpenWeatherMapの[Weather maps](https://openweathermap.org/weathermap)ページからどこの地名が対応しているか見てみるとちょっと楽しいです！

### テンプレート、アイテム作成
ホストの登録が終わったらアイテムを登録していきます。
今回、ホストごとに作成するアイテムが全く同じなので、「Template OpenWeatherMap」という名前でテンプレートを作成してアイテムを登録します。
テンプレートにはまず、OpenWeatherMapから取得したjsonを格納する「weather.json」というアイテムを作成します。

![スクリーンショット 2019-12-09 21.25.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/e634a222-e934-dfad-e32e-e3f38c4f491e.png)

> 名前：weather.json
> タイプ：HTTPエージェント
> キー：weather.json
> URL：https://api.openweathermap.org/data/2.5/weather

クエリフィールドは以下のようにしておきます。

> APPID：API key
> units：metric
> q：{HOST.NAME}

さらに、「weather.json」をもとに、各アイテムを依存アイテムとして作成して行きます。
先に上げたSapporoのjsonで、天気概要にあたる `$.weather[0].main` 部分をアイテムに登録する際は以下のようになります。

**「アイテム」タブ**
![スクリーンショット 2019-12-09 21.30.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/2445bc73-2186-db87-b401-a2c72b4e1c11.png)

> 名前：wheather.main
> タイプ：依存アイテム
> キー：weather.main
> マスターアイテム：先ほど作成したweather.jsonを指定
> データ型：テキスト

**「保存前処理」タブ**
![スクリーンショット 2019-12-09 21.31.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/60891018-b184-9f93-6d4c-26a9c77ad2dc.png)

保存前処理の設定で、以下登録しておきます。
> 名前：JSONPath
> パラメータ：$.weather[0].main

天気概要以外の他の要素も同様に、weather.jsonの依存アイテムとして登録します。
各要素のJSONPathはこんな感じです。

天気概要：  $.weather[0].main
天気詳細：  $.weather[0].description
天気アイコン：  $.weather[0].icon
気温：  $.main.temp
気圧：  $.main.pressure
湿度：  $.main.humidity
最低気温：  $.main.temp_min
最高気温：  $.main.temp_max
風速：  $.wind.speed
風向き：  $.wind.deg
地名：  $.name

数値で返ってくる様なアイテム（気温・気圧・湿度など）のデータ型は「数値（浮動小数）」にしておきます。

そして、各ホストに作成したテンプレートを紐付けておきます。
まずこの時点で、OpenWeatherMapから取得した値がZabbixで受け取れているかを確認しておきます。

### 風向きと風速
データが取れたところで、風向き・風速の値をマップで使える形に変換します。
風向きは、0~360の度数で取れてくるので16方向に分類し、0~15の数値を返すアイテムを追加作成します。
風速は、3.6(m/s)といった小数で取れるので、強さの段階(4段階)0~3の数値を返すアイテムを追加作成します。

まずは風向きから。
風向き（$.wind.deg）を「weather.wind.deg」というアイテム名で作成したのですが、更にそれを使って依存アイテム「weather.wind.deg.compass」を作成します。

**「アイテム」タブ**
![スクリーンショット 2019-12-09 22.19.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/88d129ad-2c4e-08e9-e876-8db5d9689ded.png)

> 名前：weather.wind.deg.compass
> タイプ：依存アイテム
> キー：weather.wind.deg.compass
> マスターアイテム：weather.wind.degを指定
> データ型：数値（整数）

**「保存前処理」タブ**

> 名前：Javascript
> パラメータ：以下のコードを登録

```Javascript
if(!value){
 compass=0;
}else{
 compass=parseInt(value/23, 10);
}
return compass;
```

360度の数値を23で割ったときの整数部分を返すようにしています。


次に風速。
風速（$.wind.speed）を「weather.wind.speed」というアイテム名で作成したのですが、更にそれを使って依存アイテム「weather.wind.speed.level」を作成します。

**「アイテム」タブ**
![スクリーンショット 2019-12-09 22.23.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/888c5967-69db-c726-6071-52e84bd30381.png)

> 名前：weather.wind.speed.level
> タイプ：依存アイテム
> キー：weather.wind.speed.level
> マスターアイテム：weather.wind.speedを指定
> データ型：数値（整数）

**「保存前処理」タブ**

> 名前：Javascript
> パラメータ：以下のコードを登録

```Javascript
level=value/3;

if(level>3){
 level=3;
}else{
 level=parseInt(level, 10);
}
return level;
```

風速を3で割ったときの整数部分を返すようにしています。
めっちゃ風が強いときでも3を返すようにします。


さらに！
weather.wind.deg.compassと、weather.wind.speed.levelを合体させた「weather.wind.mapping」というアイテムを作っておきます。
マップ上でのアイコンマッピングに必要なのです。
![スクリーンショット 2019-12-09 22.26.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/d247c4f7-982d-9f7d-3bf4-9e051d44ab33.png)

> 名前：weather.wind.mapping
> タイプ：計算
> キー：weather.wind.mapping
> 式：以下の内容を登録

```
last("weather.wind.deg.compass",#1)*10+last("weather.wind.speed.level",#1)
```

この式は一体何をやっているかというと、
風向きを表す0~15の数字を10の位に、風速レベルを表す0~3の数字を1の位にはめた値を返しています。

例えば、風向きが**4**(西風)、風速レベルが**1**の場合、weather.wind.mappingの値は「41」となります。
…と文字だけで説明しても分かりづらいですね。
マトリクス表にするとこんな感じです！（マトリクス表にしても分かりづらい！）

![図0001s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/e3ddbcd0-9533-9fdd-a7c1-f424134b0812.png)

さらに、実際のアイコンと照らし合わせると、こんな感じになります！

![図 0002s.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/0d204624-367a-b507-3085-01a1a9643a13.png)

多いね！！

## マップ作成前の仕込み
マップを作成する前に、 `インベントリ機能` と、 `アイコンのマッピング機能` を使って、天気・風アイコンの出し分け設定をしていきます。

### インベントリの設定
ホストに登録されている以下2つのアイテムについて、インベントリの設定を行います。

- weather.icon（天気アイコン）
- weather.wind.mapping（風向き＆風速）

「Sapporo」ホストの「weather.icon」アイテムの編集画面にて以下のように設定します。

> ホストインベントリフィールドの自動設定：ソフトウエアアプリケーションA

ホストインベントリフィールドの自動設定に設定する値は使う予定のなさそうなものであれば何でも良いかなと。
weather.wind.mappingは「ソフトウエアアプリケーションB」としておきました。
これを、各ホスト(地点ごと)に対して設定します。（ここは手動でやりました…）

### 素材集めと登録
マップを作りにあたり、[お天気アイコン](https://www.irasutoya.com/2013/03/blog-post_3599.html)、[日本地図](https://www.irasutoya.com/2013/02/blog-post_2906.html)と、[世界地図](https://www.irasutoya.com/2013/02/blog-post_8574.html)を集めてきます。
いらすとやさん、ありがとうございます…。

Zabbixの画面で `管理 > 一般設定` と進み、右上プルダウンから `イメージ` を選択して、タイプ `アイコン` を選択の上、必要なアイコンを登録しておきます。
また、 `管理 > 一般設定` と進み、右上プルダウンから `イメージ` を選択して、タイプ `背景` を選択の上、日本地図画像、世界地図画像を登録しておきます。

なおZabbix4.4になってアニメーションGIFが使えるようになったので、何か動かしたい！と思い、一部のアイコンをGIFアニメにしてみましたが、あまり動きがなく微妙に…。

![0_11d.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/809a01f6-6144-924d-a039-e5868232bfbd.gif) ![0_13d.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/f40da4a1-97ab-261a-252a-7c490fd289cc.gif)

### アイコンのマッピング
`管理 > 一般設定` と進み、右上プルダウンから `アイコンのマッピング` を選択します。
ここで、

- お天気アイコンのマッピング
- 風向きアイコンのマッピング

を設定しておきます。

#### お天気アイコンのマッピング（名称：weather_icon）
OpenWeatherMapは昼間と夜間それぞれでアイコンを用意する必要があります。
（昼間は太陽、夜は月、のように）

> インベントリフィールド：ソフトウエアアプリケーションA（ホストインベントリフィールドの自動設定で設定した値）
> 条件式：jsonから取得できる天気アイコンの値
> アイコン：登録したアイコン名

こんな感じになります。

![mapping_weather.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/75f4a671-4bb6-d155-6637-9aa094508d4f.png)

#### 風向きアイコンのマッピング（名称：weather_wind）
先ほど作成したweather.wind.mappingのマッピング設定になります。

> インベントリフィールド：ソフトウエアアプリケーションB（ホストインベントリフィールドの自動設定で設定した値）
> 条件式：weather.wind.mappingのマトリクス表の値
> アイコン：登録したアイコン名

こんな感じになります。長〜い！！(長すぎなので途中で切っています)

![mapping_wind.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/5accd64d-8985-3c97-dedb-107b5018aa73.png)

なお、この「アイコンのマッピング」機能で一つ注意点があるのですが、 **マッピング設定が上から順に部分一致になっている** みたいです。
例えば、一番上に条件式が「1」のマッピングを設定したとき、その下に「10」「11」「110」などのマッピング設定を追加したとしても、全て最上位にある「1」の条件に合致してしまいます。

そういうわけで、風向きアイコンのマッピングでは部分一致が起こらないよう、 **数値が大きいものから順に並べて設定しています** 。
**アイコンのマッピングで条件式で数値を扱う場合は注意です！！**

## マップ作成
いよいよマップを作り込んでいきます！ここまで長かった…。
以下の4つのマップを作ります。

- 全国の天気
- 全国の風向・風速
- 世界のZabbix拠点の天気
- 世界のZabbix拠点の風向・風速

「全国の天気」の場合、マップのプロパティにて以下のように設定します。

![スクリーンショット 2019-12-09 23.17.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/40e2d3bd-a2b9-d102-4b03-ee9f932ad95f.png)

> 背景のイメージ：{登録した日本地図のイメージ名}　※ここでは”japan”
> アイコンの自動マッピング：weather_icon

「世界のZabbix拠点の風向・風速」の場合はこうなります。

> 背景のイメージ：{登録した世界地図のイメージ名}
> アイコンの自動マッピング：weather_wind

マップ上にアイコンを置いていきます。
タイプ：ホスト として、ホストを設定するところで「Sapporo」などのホスト名を指定します。
そして、アイコンの自動選択にチェックを入れておきます。

![スクリーンショット 2019-12-09 23.21.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/8d50d1b1-bea9-eda5-004f-c083545e2cdb.png)

気温も表示します。
マップ図形を配置し、テキスト欄に`{Sapporo:weather.temp.last(0)} °C`と入れておくと、札幌の気温が表示されるようになります。
こうなります。

![スクリーンショット 2019-12-09 23.24.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/09efcb99-527e-2838-b1f4-5f5c5125929b.png)

風向・風速マップも同じように設定をしてあげます。（詳細省略）
これで、冒頭に貼ったスクリーンショットのようなマップが出来上がります。

# 終わりに
なんか長くなっちゃいました、すいません！
ここまで真面目に（？）Zabbixでマップを作ったことがなく、マップコンテストに参加することで、普段あまり使っていない機能の使い方とか特性を知れることができてよかったです。

ちなみに、マップコンテスト参加賞のボトル、めっちゃかっこいいです！！
また、投票賞でいただいた「はかり」も、自転車の重さはかって遊んでます！

![IMG_6375s.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/128331/bb8b169e-2e1d-fa75-9a99-3c1e9d47afe5.jpeg)

みなさんも、Zabbixのまだ使ったことのない機能にチャレンジしてみてはいかがでしょうか〜？
それでは！