Raspberry Pi Pico Wを買ったのでスマホからQRコードを表示させてみた

Qiitaさんの書き方なんも覚えてないけどとりあえずメモ
Raspberry Pi Pico Wを買ったので、スマホから入力した文字を電子ペーパーにQRコードを表示させてみた。


使ったのはこの電子ペーパー

https://www.switch-science.com/products/7323




参考にしたのは以下


無線LANに接続してブラウザでアクセスまで作ってくれてる神

https://sozorablog.com/raspberry-pi-pico-w-review/


uQRというライブラリを使ってQRコードをOLEディスプレイに表示してる人

https://github.com/adityad0/pico-phone


電子ペーパー表示のサンプル

https://www.waveshare.com/pico-epaper-2.66.htm


ファイルは
　main.py
　pWifi.py
　ePaperQr,py
　uQR.py
で動いてる



無線LANな部分をメインに改造
```pWifi.py
import time
import network
import socket
import ePaperQr
import rp2

from machine import Pin
import machine

led = Pin("LED", machine.Pin.OUT)
ledState = 'LED State Unknown'

pIpStr = "255.255.255.255"

s = socket.socket()


def pConnect():

    led.value(1)
    time.sleep(1)
    led.value(0)
    time.sleep(1)
    led.value(1)
    time.sleep(1)
    led.value(0)
    time.sleep(1)
    
    #自宅Wi-FiのSSIDとパスワードを入力
    if rp2.bootsel_button() == 1:
        print("ie")
        ssid = '自宅SSID'
        password = '自宅パスワード'
    else:
        print("sumaho")
        ssid = 'スマホSSID'
        password = 'スマホパスワード'
    led.value(1)
    time.sleep(1)

    pIpStr="err"
    
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(ssid, password)

    # Wait for connect or fail
    max_wait = 10
    while max_wait > 0:
        if wlan.status() < 0 or wlan.status() >= 3:
            break
        max_wait -= 1
        print('waiting for connection...')
        time.sleep(1)
        
    # Handle connection error
    print("koko1")
    led.value(0)
    if wlan.status() != 3:
        raise RuntimeError('network connection failed')
    else:
        print('Connected')
        status = wlan.ifconfig()
        pIpStr=str(status[0])
        print( 'get_ip = ' + pIpStr )
        #if (pIpStr=="123"):
        ePaperQr.draw_init()
        print(f"test = http://{pIpStr}")
        ePaperQr.draw_qr(f"http://{pIpStr}", 20, 19)
        ePaperQr.draw_text(f"{pIpStr}", 0, 0)
        ePaperQr.draw_finish()

    try:
        # Open socket
        addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
        #s = socket.socket()
        s.bind(addr)
        s.listen(1)
        led.value(1)
        print('listening on', addr)
        print(f"s={str(s)}")
    except:
        print("er-----------")

    print(f"s={str(s)}")
    return pIpStr
    
def pStart():
    
    html = """<!DOCTYPE html><html>
    <head><meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="data:,">
    <style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}
    .buttonGreen { background-color: #4CAF50; border: 2px solid #000000;; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; }
    .buttonRed { background-color: #D11D53; border: 2px solid #000000;; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; }
    text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
    </style></head>
    <body><center><h1>Raspberry Pi Pico W</h1></center><br><br>
    <form><center>
    <input type="text" name="ppIpStr"><br>
    <input type="submit" value="set">
    </center></form>
    <br><br>
    <br><br>
    <p>%s<p></body></html>
    """

    # Listen for connections, serve client
    while True:
    #try:
        print(str(s))
        cl, addr = s.accept()
        print('client connected from', addr)
        request = cl.recv(1024)
        print("request:")
        print(request)
        request = str(request)
        
        TempStr = request[request.find('ppIpStr='):request.find('ppIpStr=')+100]
        WifiQrStr = TempStr[8:TempStr.find(' ')]
        WifiQrStr = WifiQrStr.replace("%3A",":").replace("%2F","/")
         
        
        # Create and send response
        #stateis = ledState
        stateis = "<br>QR: " + WifiQrStr
        response = html % stateis
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()
        
        print("WifiQrStr:" + str(WifiQrStr))
        if (str(WifiQrStr)==""):
            print("WifiQrStr:" + "space")
        else:
            ePaperQr.draw_init()
            ePaperQr.draw_qr(f"{WifiQrStr}", 20, 49)
            ePaperQr.draw_text(f"QR:{WifiQrStr}", 0, 0)
            ePaperQr.draw_finish()

if __name__=='__main__':
    print('test')
```


電子ペーパーのサンプルをQRコード表示するよう改造
```ePaperQr.py
from machine import Pin, SPI
from time import sleep
import time
import framebuf
import utime
import math
from uQR import QRCode

qr = QRCode()

# Display resolution
EPD_WIDTH       = 152
EPD_HEIGHT      = 296

RST_PIN         = 12
DC_PIN          = 8
CS_PIN          = 9
BUSY_PIN        = 13


WF_PARTIAL_2IN66 =[
0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x40,0x40,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x0A,0x00,0x00,0x00,0x00,0x00,0x02,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x22,0x22,0x22,0x22,0x22,0x22,
0x00,0x00,0x00,0x22,0x17,0x41,0xB0,0x32,0x36,
]

bit2 =[
    0,0,0,0,0,0,0,0
    ]

class EPD_2in9_B:
    def __init__(self):
        self.reset_pin = Pin(RST_PIN, Pin.OUT)
        
        self.busy_pin = Pin(BUSY_PIN, Pin.IN, Pin.PULL_UP)
        self.cs_pin = Pin(CS_PIN, Pin.OUT)
        self.width = EPD_WIDTH
        self.height = EPD_HEIGHT
        self.lut = WF_PARTIAL_2IN66
        
        self.spi = SPI(1)
        self.spi.init(baudrate=4000_000)
        self.dc_pin = Pin(DC_PIN, Pin.OUT)
        
        self.buffer_balck = bytearray(self.height * self.width // 8)
        self.buffer_red = bytearray(self.height * self.width // 8)
        self.imageblack = framebuf.FrameBuffer(self.buffer_balck, self.width, self.height, framebuf.MONO_HLSB)
        self.imagered = framebuf.FrameBuffer(self.buffer_red, self.width, self.height, framebuf.MONO_HLSB)
        self.init()

    def digital_write(self, pin, value):
        pin.value(value)

    def digital_read(self, pin):
        return pin.value()

    def delay_ms(self, delaytime):
        utime.sleep(delaytime / 1000.0)

    def spi_writebyte(self, data):
        self.spi.write(bytearray(data))

    def module_exit(self):
        self.digital_write(self.reset_pin, 0)

    # Hardware reset
    def reset(self):
        self.digital_write(self.reset_pin, 1)
        self.delay_ms(50)
        self.digital_write(self.reset_pin, 0)
        self.delay_ms(2)
        self.digital_write(self.reset_pin, 1)
        self.delay_ms(50)


    def send_command(self, command):
        self.digital_write(self.dc_pin, 0)
        self.digital_write(self.cs_pin, 0)
        self.spi_writebyte([command])
        self.digital_write(self.cs_pin, 1)

    def send_data(self, data):
        self.digital_write(self.dc_pin, 1)
        self.digital_write(self.cs_pin, 0)
        self.spi_writebyte([data])
        self.digital_write(self.cs_pin, 1)
        
    def SetWindow(self, x_start, y_start, x_end, y_end):
        self.send_command(0x44)
        self.send_data((x_start>>3) & 0x1f)
        self.send_data((x_end>>3) & 0x1f)
        
        self.send_command(0x45)
        self.send_data(y_start&0xff)
        self.send_data((y_start&0x100)>>8)
        self.send_data((y_end&0xff))
        self.send_data((y_end&0x100)>>8)
        
    def SetCursor(self, x_start, y_start):
        self.send_command(0x4E)
        self.send_data(x_start & 0x1f)
        
        self.send_command(0x4f)
        self.send_data(y_start&0xff)
        self.send_data((y_start&0x100)>>8)
        
    def ReadBusy(self):
        #print('e-Paper busy')
        utime.sleep_ms(50)   
        while(self.busy_pin.value() == 1):      # 0: idle, 1: busy
            utime.sleep_ms(10)    
        #print('e-Paper busy release')
        utime.sleep_ms(50)  
        
    def TurnOnDisplay(self):
        self.send_command(0x20)
        self.ReadBusy()
        
    def init(self):
        print('init')
        self.reset()
        self.ReadBusy()
        self.send_command(0x12)  
        self.ReadBusy()#waiting for the electronic paper IC to release the idle signal

        self.send_command(0x11)
        self.send_data(0x03)

        self.SetWindow(0, 0, self.width-1, self.height-1)
        
        self.send_command(0x21)    #resolution setting
        self.send_data (0x00)  
        self.send_data (0x80)  
        
        
        self.SetCursor(0,0)
        self.ReadBusy()
    
        
    def display(self):
        high = self.height
        if( self.width % 8 == 0) :
            wide =  self.width // 8
        else :
            wide =  self.width // 8 + 1
        self.send_command(0x24)
        for j in range(0, high):
            for i in range(0, wide):
                self.send_data(self.buffer_balck[i + j * wide])   
        self.send_command(0x26)
        for j in range(0, high):
            for i in range(0, wide):
                self.send_data(~self.buffer_red[i + j * wide])   

        self.TurnOnDisplay()

    
    def Clear(self, colorblack, colorred):
        high = self.height
        if( self.width % 8 == 0) :
            wide =  self.width // 8
        else :
            wide =  self.width // 8 + 1
        self.send_command(0x24)
        for j in range(0, high):
            for i in range(0, wide):
                self.send_data(colorblack)
        self.send_command(0x26)
        for j in range(0, high):
            for i in range(0, wide):
                self.send_data(~colorred)
                                
        self.TurnOnDisplay()

    def sleep(self):
        self.send_command(0X10) # deep sleep
        self.send_data(0x01)

def dec2bit(ddd):
    for VV in range(8, 0, -1):
        bit2[VV-1] = ddd % 2
        ddd = math.floor(ddd / 2)
    return bit2


def draw_init():
    epd.init()

    epd.imageblack.fill(0xff)
    epd.imagered.fill(0xff)

    print("datafile input")
    epd.imageblack.text(str(EPD_WIDTH) + "x" + str(EPD_HEIGHT), 0, EPD_HEIGHT-11, 0x00)
    
    
def draw_finish():
    
    print("display")
    epd.display()
    epd.delay_ms(2000)

    print("sleep")
    epd.sleep()
    print("end")
   
def draw_qr(qr_data, offset_x, offset_y):
    print("drow_qr " + str(qr_data))
    scale = 1
    qr.clear()
    qr.add_data(qr_data)
    matrix = qr.get_matrix()
    print("QR version:", qr.version)
    print("Matrix length", len(matrix))

    print("X:", len(matrix)*scale)
    print("X:", len(matrix[0])*scale)
    
    for y in range(len(matrix)*scale):
        for x in range(len(matrix[0])*scale):
            value = not matrix[int(y/scale)][int(x/scale)]
            if (value):
                epd.imageblack.fill_rect(x + offset_x, y + offset_y, 1, 1, 0xFF)
            else:
                epd.imageblack.fill_rect(x + offset_x, y + offset_y, 1, 1, 0x00)

def draw_text(qr_data, offset_x, offset_y):
    print("drow_text " + str(qr_data))
    epd.imageblack.text(str(qr_data), offset_x, offset_y, 0x00)
    

epd = EPD_2in9_B()

if __name__=='__main__':
    print("OS START")

```

uQR.pyは長いので省略。
数字だけ30文字ぐらい入れたらエラーになったのでその対策したんだけど、そのままでも動くよ。


電源入れると動くやつ
```main.py
import pWifi

IpStr = "255.255.255.255"

try:
    IpStr = pWifi.pConnect()
    IpStr = pWifi.pStart()
except:
    print("er-----------")

```


使い方は以下
１．pWifi.pyのSSIDとパスワードを使っている無線LANのものに変更する
　　(自宅の無線LANだけじゃなくテザリングしてるスマホでも動いたよ)
２．PiPicoWの電源入れたら勝手に無線LAN(スマホ用)に繋ぎに行くので成功したらQRコードが以下に更新される
　　http://PiPicoのIPアドレス
　　(電源いれて最初にLEDが光ってから4秒後にBOOTSELボタン押してると違う無線LAN(家用)に繋ぎにいく)
３．表示されたQRコードからPiPicoWにブラウザでアクセス(http://PiPicoのIPアドレス)
４．テキストボックスにテキストを入力してsetボタンを押すと電子ペーパーのQRコードが変化する
５．電源抜く
６．電子ペーパーなのでQR表示させたまま持ち運び可能



自分用メモなのでここまで