【進撃の東さん】第2回：ハウス内のセンシングシステムを作ってみましょう

# 概要

Raspberry Pi Pico Wを使ってハウス内の温度を遠隔監視するシステムを作ってみようと思います。

Raspberry Pi Pico Wには温度センサーが内蔵されているので、

* 1時間ごとに測定した温度がLINEに通知される（定期通知）
* 温度が30℃を超えたらLINEに通知される（緊急通知）

の二つをやってみようと思います。

Raspberry Pi Pico WにはADC（アナログデジタルコンバータ）も搭載されているので、センサーを追加することで他の値もモニタリングできるようになります。

詳しい作り方はYouTubeで解説しています。

**農家も電子工作やプログラミングを学べばセンシングシステムを簡単に自作できる時代です。**

https://youtu.be/ib6GEvhG39E

## 作り方

### 手順1：温度センサーの値を取得する

* [Raspberry Pi Pico Python SDK公式ドキュメント](https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-python-sdk.pdf?_gl=1*1slf2q9*_ga*MzY1NDEzMTI1LjE2OTYyOTQ1ODY.*_ga_22FD70LWDS*MTY5NjMyMzA0Ny4yLjEuMTY5NjMyMzE0OC4wLjAuMA..)

* 3.3.ADCの項目に内蔵された温度センサーの使い方が載っている
* 以下は温度センサーの値を2秒おきに読み取ってシェルに出力するプログラム

```python:sensor_temp.py
import machine
import utime

sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / 65535

while True:
    reading = sensor_temp.read_u16() * conversion_factor
    temperature = 27 - (reading - 0.706)/0.001721
    print(temperature)
    utime.sleep(2)

```



### 手順2：Wi-Fiに接続する

* [Connecting to the Internet with Raspberry Pi Pico W公式ドキュメント](https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf?_gl=1*118agbs*_ga*MzY1NDEzMTI1LjE2OTYyOTQ1ODY.*_ga_22FD70LWDS*MTY5NjMyMzA0Ny4yLjEuMTY5NjMyMzMwNi4wLjAuMA..)
* 3.6. Connecting to a wireless networkにMicroPythonを使ってインターネットに接続する方法が載っている
* Raspberry Pi Pico Wには2.4GHz帯のみ対応のWi-Fiモジュールが搭載されているので、SSIDとパスワードをconfig.pyに記述する

```python:config.py
SSID = '2.4GHz帯のSSID'
PASSWORD = 'Wi-Fiのパスワード'

```

* config.pyを/にアップロードする
* 以下のプログラムでWi-Fiに接続できるとプライベートIPが表示される

```python:wifi.py
import network
from config import SSID, PASSWORD, ACCESS_TOKEN
from utime import sleep

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)

while not wlan.isconnected() and wlan.status() >= 0:
    print('Waiting for connection...')
    sleep(1)
    
ip = wlan.ifconfig()[0]
print(ip)

```


### 手順3：LINE Notifyのアクセストークンを取得する

* 動画では実演していますが、以下の記事とやっていることは同じです。

https://qiita.com/grundtein/items/fd51f5ba1e40994b8254

### 手順4：温度センサーの値をLINEに通知する

* [LINE Notify API Document](https://notify-bot.line.me/doc/ja/)
* config.pyにLINE Notifyのアクセストークンを追加する（Raspberry Pi Pico W上にアップロードされているconfig.pyを直接編集すればいい）

```python:config.py
SSID = '2.4GHz帯のSSID'
PASSWORD = 'Wi-Fiのパスワード'
ACCESS_TOKEN = 'LINE Notifyのアクセストークン'

```

* line.pyを作成して実行すると、line_nofityメソッドがシェルで使えるようになる。

```python:line.py
import urequests
from config import ACCESS_TOKEN

def line_notify(message):
    endpoint = 'https://notify-api.line.me/api/notify'
    headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': f'Bearer {ACCESS_TOKEN}'}
    data = f'message={message}'.encode('utf-8')
    response = urequests.post(endpoint, headers=headers, data=data)
    response.close()

```

* シェル（REPL）からLINEにメッセージを送ってみる。

```python:REPL
message='初めてのLINE通知'
line_notify(message)
```

* 温度センサーの値を取得するプログラムをメソッド化する。

```python:sensor_temp.py
import machine

sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / 65535

def get_sensor_temp():
    reading = sensor_temp.read_u16() * conversion_factor
    temperature = 27 - (reading - 0.706)/0.001721
    return temperature

```

* Wi-Fiに接続するプログラムをメソッド化する。

```python:wifi.py
import network
import time
from config import SSID, PASSWORD

def connect():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(SSID, PASSWORD)

    while not wlan.isconnected() and wlan.status() >= 0:
        print("Waiting to connect:")
        time.sleep(1)

    ip = wlan.ifconfig()[0]
    return ip

```

* wifi.py, sensor_temp.py, line.pyをRaspberry Pi Pico Wの/にアップロードする。
* main.py（電源を入れたら起動するプログラムファイル）を作成してLINEに温度を通知してみる。

```python:main.py
from wifi import connect
from sensor_temp import get_sensor_temp
from line import line_notify

ip = connect()
print(f'Connected on {ip}')

sensor_temp = get_sensor_temp()
print(f'{round(sensor_temp,2)} ℃')

message = f'現在の温度は{round(sensor_temp,2)}℃です。'
line_notify(message)

```

### 手順5：Timerを使って温度センサーの値を定期的にLINEに通知する

* Timerで指定するコールバック関数では引数が使えないので、プログラムを書き換えます。

```python:main.py
from wifi import connect
from machine import ADC, Timer
import urequests
from config import ACCESS_TOKEN


ip = connect()
print(f'Connected on {ip}')

sensor_temp = ADC(4)
conversion_factor = 3.3 / 65535

def get_sensor_temp():
    reading = sensor_temp.read_u16() * conversion_factor
    temperature = 27 - (reading - 0.706)/0.001721
    return temperature


def line_notify(timer):
    endpoint = 'https://notify-api.line.me/api/notify'
    headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': f'Bearer {ACCESS_TOKEN}'}
    temperature = get_sensor_temp()
    data = f'message= 現在の温度は{temperature}℃ です。'.encode('utf-8')
    response = urequests.post(endpoint, headers=headers, data=data)
    response.close()

timer = Timer()
try:
    timer.init(mode=Timer.PERIODIC, period=10000, callback=line_notify)
except Exception as e:
    print(e)
    timer.deinit()
    
```

### 手順6：温度が30℃を超えたらLINEに緊急通知をする

```python:main.py
from machine import Timer
from config import ACCESS_TOKEN
import urequests
import machine
from utime import sleep

MAX_TEMP = 30

sensor_temp = machine.ADC(4)

def get_sensor_temp():
    conversion_factor = 3.3 / 65535
    reading = sensor_temp.read_u16() * conversion_factor
    temperature = 27 - (reading - 0.706)/0.001721
    return temperature


def periodic_notify(timer):
    endpoint = 'https://notify-api.line.me/api/notify'
    headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': f'Bearer {ACCESS_TOKEN}'}
    temperature = get_sensor_temp()
    message = f'現在の温度は{round(temperature, 2)} ℃です。'
    print(message)
    data = f'message={message}'.encode('utf-8')
    response = urequests.post(endpoint, headers=headers, data=data)
    response.close()
    
def alert_notify(temperature):
    endpoint = 'https://notify-api.line.me/api/notify'
    headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': f'Bearer {ACCESS_TOKEN}'}
    message = f'【緊急】現在の温度は{round(temperature, 2)} ℃です。'
    print(message)
    data = f'message={message}'.encode('utf-8')
    response = urequests.post(endpoint, headers=headers, data=data)
    response.close()

timer = Timer()


try:
    timer.init(mode=Timer.PERIODIC, period=360000, callback=periodic_notify)
    
    while True:
        temperature = get_sensor_temp()
        print(temperature)
        if temperature >= MAX_TEMP:
            alert_notify(temperature)
            sleep(60*30)
        sleep(2)
except Exception as e:
    print(e)
    timer.deinit()

```

## 追記
今回はRaspberry Pi Pico Wに内蔵された温度センサーを使って温度を測定しましたが、

* 土壌水分センサー
* 湿度センサー
* 二酸化炭素濃度センサー
* 気圧センサー

なんかをつけることによって、監視できるデータを増やすことができます。