Raspberry Pi & Webex messagingを使って無線LANを監視&通知してみた

この記事は[FUJITSU Advent Calender 2021](https://qiita.com/advent-calendar/2021/fujitsu)の15日目の記事です。

#はじめに
Advent Calender2年目です！
今年もAdvent Calenderの時期が来たということでネタ探しをしていたところ、家で使用していないRaspberry Pi 4があったためWebex messagingと組み合わせて、無線LANを監視してみました。
監視といっても簡単なものですが、複数ベンダのAPが動いていたりする環境でも一括して監視できるので多少は使えるかなと思います。


# 環境・構成・実装内容など
インターネットに接続されている無線LANルータとそのルータにMerakiを接続しています。
Raspberry Piは有線・無線両方でネットワークに接続、端末は無線でネットワークに接続しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858668/6c52e758-bb01-70da-fc11-8a0a3f3827a0.png)



###監視・通知の流れ

ネットワークにRaspberry Piを接続して無線LANを監視させる。⇒異常が発生したらWebex messagingに通知という感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858668/92c7beec-4290-95f0-4991-ff3ef8d6d33d.png)

###Raspberry Piの中身の動き

**1. シェルスクリプト定期起動(cron)**
**2. SSIDの一覧を取得して必要な部分のみ抽出する**
**3. 抽出した情報をJSON形式にする**
**4. Pythonスクリプトで取得したデータを処理**

cronで定期起動して処理しているのでリアルタイム監視とはいきませんが、起動間隔を調整すれば毎分チェックは可能です。

###監視内容

今回実装できた監視内容は以下2つです。

* SSIDのダウン(Raspberry Piから、指定したSSID見えなくなったらダウンとみなして通知)
* SSIDの信号強度の悪化(閾値以下のdBmになると信号強度の悪化とみなして通知)



#実装内容の説明
###シェルスクリプトの内容
3つの処理を記載してあります。

1行目SSID一覧の取得、必要な部分の抽出
iw wlan0 scanコマンドを使用してRaspberry Piから見えるSSIDの一覧を取得します。
その後、少し無理やりですが、sedコマンドで必要な情報の抽出/次に行うJSON形式へ変換のための前処理をします。

2行目wlan0_scan内に記載されたjoコマンドをsourceコマンド経由で実行
[jo](https://github.com/jpmens/jo)コマンドについてここでは詳細記載しませんが、以下のようなコマンドでJSON形式に変換します。
```jo -p BSS~XX:XX:XX:XX:XX:XX=$(jo signal=-36.00dBm SSID=home) BSS~XX:XX:XX:XX:XX:XX=$(jo signal=-86.00dBm SSID=test)```

3行目メインのPythonスクリプトを起動


```WiFi_scan.sh
#!/usr/bin/bash -l

#SSID一覧を取得して必要情報のみ抽出 ＆ joコマンドを実行できる形式に変換
sudo iw wlan0 scan | egrep -e ^BSS -e signal -e SSID | sed -e "s/BSS /BSS~/g" | sed "s/signal: /signal=/g" | sed "s/SSID: /SSID=/g" | sed "s/(.*)//g"  | sed "/BSS/s/$/\=\$\(jo/" | sed "/SSID/s/$/\)/" | sed "s/^[ \t]*//" | sed "s/ //g" | perl -pe "s/\n/ /g" | sed "s/^/jo -p /" > /home/pi/Documents/python/wlan0_scan
#jo コマンド実行してJSON形式に変換したものをwlan0_scan_jsonに格納
source /home/pi/Documents/python/wlan0_scan > /home/pi/Documents/python/wlan0_scan_json
#メインのPythonスクリプトを実行
/usr/bin/python3.7 /home/pi/Documents/python/wlan_alert.py > /home/pi/Documents/python/python.log
```

###Pythonスクリプトで取得したデータをもとに処理

今回はWebex messagingへの通知のために[webexteamssdk](https://community.cisco.com/t5/devnet-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88/webex-messaging-teams-api-%E3%81%AE-python-%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA-webexteamssdk-%E3%81%AE%E7%B4%B9%E4%BB%8B/ta-p/4307424)を使用しています。このPython ライブラリによってWebex messagingのAPIを、シンプルなPython コードで使用することができます。

また、iw wlan0 scanコマンドで出力された結果は、Raspberry Piから見えるSSIDの一覧（使用しないAP含む）なので関係のないSSIDを検知しないよう、対象としたいSSIDをリストで定義しています。

```wlan_alert.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import json
from webexteamssdk import WebexTeamsAPI

ssid_list=['home-wireless','home2','test']
BOT_ACCESS_TOKEN = os.environ.get('BOT_ACCESS_TOKEN_env')
ROOM_ID = os.environ.get('ROOM_ID_env')

def ssid_down(messages):
    api = WebexTeamsAPI(access_token=BOT_ACCESS_TOKEN)
    send_msg = api.messages.create(roomId=ROOM_ID, markdown="SSID:"+messages+" DOWN")
    return send_msg

def signal_low(messages, SIG):
    api = WebexTeamsAPI(access_token=BOT_ACCESS_TOKEN)
    send_msg = api.messages.create(roomId=ROOM_ID, markdown="SSID:"+messages+" signal under -70dBm ["+SIG+"]")
    return send_msg


with open('/home/pi/Documents/python/wlan0_scan_json', 'r') as scan:
    scan = json.load(scan)

l_ssid = [d.get('SSID') for d in scan.values()]
for ssid in ssid_list:
    if (ssid in l_ssid) == False:
        ssid_recv = ssid_down(ssid)
        print(ssid_recv)

for x in scan.values():
    signal = x.get('signal')
    if (x.get('SSID') in ssid_list) == True:
        if int(signal[1:3]) > 70:
            signal_recv = signal_low(x.get('SSID'), signal)
            print(signal_recv)

```


#Webex messagingでの通知の様子

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/858668/10e6efd1-1b25-783f-b957-22ec22d5c4f2.png)



#課題・追加したい機能

* cronが動くタイミングで異常が起きていなければ検知できない。
* 監視対象のSSIDが落ち続けていたり、信号強度が悪いままだと通知が延々と来る。（復旧して再度異常が発生するまで通知しない処理や、復旧時の通知処理を追加したい）
* SSIDは見えるが、通信ができないような状態を検知したい。(SSIDに接続して疎通確認行う処理など)

#おわりに
今回はRaspberry Pi と Webex messagingを使って家の無線LANを監視＆通知してみました。
以前投稿した「CML上に物理環境を自動で複製する」という記事でもそうなのですが、まだまだ実装方法がごちゃごちゃしていたり無理やり感があるのでそういった部分をシンプルに実装できるよう今後も勉強していきたいです！

#参考
[jo](https://github.com/jpmens/jo)
[webexteamssdk](https://community.cisco.com/t5/devnet-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88/webex-messaging-teams-api-%E3%81%AE-python-%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA-webexteamssdk-%E3%81%AE%E7%B4%B9%E4%BB%8B/ta-p/4307424)