0
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.

【高先さんの電子工作】第15回:PWMを使ってRGB LEDを制御する

Last updated at Posted at 2023-09-14

main.py
from machine import Pin, PWM, reset
import socket
import network
import ujson
from utime import sleep, sleep_ms


red = PWM(Pin(13))
green = PWM(Pin(14))
blue = PWM(Pin(15))
red.freq(1000)
green.freq(1000)
blue.freq(1000)
r = 0
g = 0
b = 0


def interval_mapping(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min


def color_to_duty(rgb_value):
    rgb_value = int(interval_mapping(rgb_value,0,255,0,65535))
    return rgb_value


def color_set(red_value,green_value,blue_value):
    red.duty_u16(color_to_duty(red_value))
    green.duty_u16(color_to_duty(green_value))
    blue.duty_u16(color_to_duty(blue_value))
    

def callback(Timer):
    color_set(r,g,b)


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
        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): ソケット接続
    """
    global r
    global g
    global b
    print('Starting Web Server...')


    while True:
        
        # 接続があるまで待機し、クライアントのソケットオブジェクトを取得する
        client = connection.accept()[0]
        # クライアントからのデータを受信する(最大1024バイト)
        request = client.recv(1024)
        # 受信したバイナリデータを文字列にする
        request = str(request)
        try:
            # リソースのパスを取得する
            # request.split()[0]: HTTPメソッド
            # request.split()[1]: リソースのパス
            request = request.split()[1]
            print(request)
        except IndexError:
            pass

        # スライドバーの値を取得する        
        if '/led?' in request:
            params = request.split('?')[1].split('&')
            r = int(params[0].split('=')[1])
            g = int(params[1].split('=')[1])
            b = int(params[2].split('=')[1])
            response = ujson.dumps({'message': 'ok'})
            client.send("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n" + response)
            client.close()
            continue

        # HTTPレスポンスを生成する
        response = 'HTTP/1.1 200 OK\r\n'
        response += 'Content-Type: text/html\r\n\r\n'
        response += """
            <!DOCTYPE html>
            <html>
            <head>
                <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
                <title>PWMでRGB LEDを制御する</title>
            </head>
            <body style="display: flex;justify-content: center;align-items: center;height: 100vh;margin: 0;">
                <div style="text-align: center;">
                    <h1 style="font-family: Arial, sans-serif;"></h1>
                    <input type="color" id="colorPicker" onchange="getColorValue()">
                </div>


                <script>
                    function getColorValue() {
                        // input要素から選択された色を取得
                        var colorPicker = document.getElementById("colorPicker");
                        var selectedColor = colorPicker.value;

                        // 色をRGB値に変換
                        var hex = selectedColor.slice(1); // 先頭の#を削除
                        var bigint = parseInt(hex, 16);
                        var r = (bigint >> 16) & 255;
                        var g = (bigint >> 8) & 255;
                        var b = bigint & 255;

                        // APIを呼び出す
                        fetch(`/led?r=${r}&g=${g}&b=${b}`, {
                            method: 'GET',
                            headers: {
                                'Content-Type': 'application/json'
                            }
                        })
                        .then(response => {
                            if (!response.ok) {
                                throw new Error('API呼び出しエラー');
                            }
                            return response.json();
                        })
                        .then(data => {
                            console.log(data);
                            var rgbValue = document.querySelector('h1');
                            rgbValue.textContent = "RGB: (" + r + ", " + g + ", " + b + ")";
                        })
                        .catch(error => {
                            console.error('API呼び出しエラー:', error);
                        });
                    }
                </script>
            </body>
            </html>
        """
        # HTTPレスポンスを送信する
        client.send(response)
        # クライアントソケットを閉じる
        client.close()


if __name__ == '__main__':
    try:
        # Wi-Fiに接続する
        ip = connect()

        # ソケットを開く
        connection = open_socket(ip)
        
        # 1秒ごとにcallback関数を呼び出す設定をする
        timer = machine.Timer(-1)
        timer.init(period=3000, mode=machine.Timer.PERIODIC, callback=callback)

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

config.json
{"ssid": "Your SSID", "password": "Your Password"}
0
0
0

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
0
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?