【高先さんの電子工作】第24回：第19回の詳細な補足

# 概要

第19回ではRaspberry Pi Pico W、シフトレジスタ、LEDを使ってLINE連携とブラウザから8つのLEDを操作するIoTプロジェクトについてやりましたが、高先さんが苦戦していたようなのでその詳細な補足動画となっています。

https://youtu.be/of-g6lv7r9I

ハンスオン形式でコーディングや電子回路を組み上げているので、できたコードの全体像は以下に貼り付けておきます。

* LINE Notifyのアクセストークンの発行方法
* LINE NotifyのAPI Documentを読み解きながら、urequestsモジュールでメッセージを送信する方法
* HTTP Responseの扱い方
* Raspberry Pi Pico Wから2.4GHz帯のWi-Fiに接続する方法
* シフトレジスタの説明と電子回路の組み方
* シフトレジスタのプログラムからの操作方法
* ソケットを使ってウェブサーバーを立ち上げる方法
* ウェブサーバーの起動→LINEへURL通知→ウェブアプリケーションからLEDを操作する流れ
* etc...（高先さんの反応的に説明した方がよさそうなこと全般）




## プログラム

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

```python:main.py
from config import ACCESS_TOKEN, SSID, PASSWORD
import network
from utime import sleep
import urequests
from machine import Pin
import time
import socket


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

    while not wlan.isconnected():
        print('Waiting for connection...')
        sleep(1)
        
    ip = wlan.ifconfig()[0]
    print(f'Connected on {ip}')
    return ip


def line_notify(message):
    """
    LINEにメッセージを通知する。
    
    Paratemers:
        message(str): 通知するメッセージ
    """
    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()


sdi = Pin(0, Pin.OUT)
rclk = Pin(1, Pin.OUT)
srclk = Pin(2, Pin.OUT)

def hc595_shift(dat):
    rclk.low()
    time.sleep_ms(5)
    for bit in range(7, -1, -1):
        srclk.low()
        time.sleep_ms(5)
        value = 1 & (dat >> bit)
        sdi.value(value)
        time.sleep_ms(5)
        srclk.high()
        time.sleep_ms(5)
    time.sleep_ms(5)
    rclk.high()
    
def open_socket(ip):
    """
    ソケットを開く。このソケットオブジェクトを介してクライアントとの通信を行う。

    Parameters:
        ip: WLAN上で自分自身を表すIPアドレス

    Returns:
        connection(socket.socket): ソケット接続
    """
    address = (ip, 80) # 80ポートでソケット通信を行う
    connection = socket.socket()
    connection.bind(address)
    connection.listen(1) # 同時接続の最大数1
    return connection


def serve(connection):
    """
    WEBサーバーを起動する。

    Parameters:
        connection(socket.socket): ソケット接続
    """
    print('Starting Web Server...')

    # LINEにIPを通知する
    message = f'http://{ip}'
    line_notify(message)

    while True:
        
        # 接続があるまで待機し、クライアントのソケットオブジェクトを取得する
        client = connection.accept()[0]
        # クライアントからのデータを受信する（最大1024バイト）
        request = client.recv(1024)
        # 受信したバイナリデータを文字列にする
        request = str(request)
        try:
            # リソースのパスを取得する
            request = request.split()[1]
            print(request)
        except IndexError:
            pass
  
        if '/red' in request:
            hc595_shift(0b00010001)
        elif '/green' in request:
            hc595_shift(0b00100010)
        elif '/blue' in request:
            hc595_shift(0b01000100)
        elif '/yello' in request:
            hc595_shift(0b10001000)


        # HTTPレスポンスを生成する
        response = 'HTTP/1.1 200 OK\r\n'
        response += 'Content-Type: text/html\r\n\r\n'

        with open('index.html', 'r') as f:
            response += f.read()

        # HTTPレスポンスを送信する
        client.send(response)
        # クライアントソケットを閉じる
        client.close()


if __name__ == '__main__':
    # LEDを初期化する
    hc595_shift(0b00000000)
    # Wi-Fiに接続する
    ip = connect()
    # ソケットを開く
    connection = open_socket(ip)
    try:
        # Web Serverを起動する
        serve(connection)
    except Exception as e:
        machine.soft_reset()
        print(e)

```