1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【高先さんの電子工作】第19回:シフトレジスタとLINEを使ってLEDを操作する

Last updated at Posted at 2023-09-20

概要

動画の中で実演しています。

準備

1. LINE Notifyのアクセストークンを取得する

以下の記事を参考にすると良いと思います。

2. 設定ファイルを準備する

config.jsonファイルにWi-Fiの接続情報とLINE Notifyのアクセストークンを書き込んでRaspberry Pi Pico W上に配置してください。

config.json
{
    "ssid": "2.4GHz帯のSSID",
    "password": "Wi-Fiのパスワード",
    "access_token": "1で取得したLINE Notifyのアクセストークン"
}

3. ソースコードを配置する

以下のindex.htmlとmain.pyをRaspberry Pi Pico W上に配置する。

ブラウザから操作するためのWebページ。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
  <title>シフトレジスタを使ってLEDを操作する</title>
</head>
<body>

<div class="container">
  <div class="row">
    <div class="col-sm-3" style="display: flex; justify-content: center; align-items: center; margin-top: 30px;">
      <form action="./red">
        <button type="submit" class="btn btn-danger" style="font-size: 1.5em; padding: 10px 20px;"></button>
      </form>
    </div>
    <div class="col-sm-3" style="display: flex; justify-content: center; align-items: center; margin-top: 30px;">
      <form action="./green">
        <button type="submit" class="btn btn-success" style="font-size: 1.5em; padding: 10px 20px;"></button>
      </form>
    </div> 
    <div class="col-sm-3" style="display: flex; justify-content: center; align-items: center; margin-top: 30px;">
      <form action="./blue">
        <button type="submit" class="btn btn-primary" style="font-size: 1.5em; padding: 10px 20px;"></button>
      </form>
    </div>
    <div class="col-sm-3" style="display: flex; justify-content: center; align-items: center; margin-top: 30px;">
      <form action="./yellow">
        <button type="submit" class="btn btn-warning" style="font-size: 1.5em; padding: 10px 20px;"></button>
      </form>
    </div>
  </div>
</div>
</body>
</html>

メインとなるプログラム。

main.py
from machine import Pin, reset
import time
import socket
import network
import ujson
import urequests


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


def get_line_config():
    """
    LINE Notifyの設定情報を取得する

    Returns:
        access_token(str): LINE Notifyのアクセストークン
    """
    with open('config.json', 'r') as f:
        data = ujson.load(f)
        return data['access_token']


def notify(message):
    """
    LINE Notifyを利用してトークルームにメッセージを送信する。

    Parameters:
        message(str): 送信するメッセージの内容

    Returns:
        response(Response) LINE Notifyのレスポンス
    """
    endpoint = 'https://notify-api.line.me/api/notify'
    access_token = get_line_config()
    headers = {
        'Authorization': 'Bearer ' + access_token,
        'Content-Type' : 'application/x-www-form-urlencoded'
    }
    data = f'message={message}'.encode('utf-8')
    response = urequests.post(endpoint, headers=headers, data=data)
    return response


def hc595_shift(dat):
    """
    8ビットのデータを入力して8チャンネルを同時にON/OFFする。
    """
    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()
    time.sleep_ms(5)


class WiFiConnectError(Exception):
    pass

def connect():
    """
    Wi-Fiに接続する。

    Returns:
        ip (str): IPアドレス
    Raises:
        WiFiConnectError: Wi-Fiに接続できなかった場合
    """
    # Wi-Fiの接続情報を取得する
    config = {}
    with open('config.json', 'r') as f:
        config = ujson.load(f)

    # Wi-Fiに接続する
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(config['ssid'], config['password'])

    timeout = 10
    while timeout > 0:
        timeout -= 1
        print('Waiting for connection...')
        if wlan.isconnected():
            ip = wlan.ifconfig()[0]
            print(f'Connected: {ip}')
            return ip
        time.sleep(1)
    
    raise WiFiConnectError('Wi-Fiに接続できませんでした。')


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}'
    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__':
    try:
        # LEDを初期化する
        hc595_shift(0b00000000)

        # Wi-Fiに接続する
        ip = connect()

        # ソケットを開く
        connection = open_socket(ip)

        # Web Serverを起動する
        serve(connection)
    except WiFiConnectError as e:
        print(f'Error: {e}')
    except Exception as e:
        # 再起動する
        reset()

4. 電子回路を組む

電子回路は以下の記事を参考にしてください。

5. モバイルバッテリーに接続する

モバイルバッテリーに接続するとLINEにRaspberry Pi Pico WにアクセスするためのURL(IP)が通知される。

IMG_39E7A09B1AB2-1.jpeg

URLをクリックするとLEDを操作する画面が表示される。

IMG_263F44DF42C1-1.jpeg

ボタンを押すと各色のLEDが点灯する。

1
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?