PicoW can use TCPIP, so it’s really easy for me.

This time, I installed only a servo motor and temperature, pressure, and humidity sensors on Pico.

I had never used solder before, so there were a lot of disconnections, and I had a lot of unnecessary trouble with debugging, but now that I’ve learned how to solder, I was able to concentrate on PG.

We displayed humidity, air pressure, and humidity on a classic web page, specified the angle with the slider, and moved the servo.


import time
import network
import socket
import re
from lcd1602 import LCD
from machine import Pin, PWM, I2C
from NetInfo import NetInfo
from bme280 import BME280

def servo_value(degree):
    return int((degree * 9.5 / 180 + 2.5) * 65535 / 100)

try:
    led = Pin('LED', Pin.OUT)
    led.value(1)
    time.sleep(1)
    lcd = LCD()
    lcd.clear()
    lcd.message("read setting")
    netInfo = NetInfo()
    wifiText = netInfo.getWifiSetting()
    netInfo.setWifiSetting(wifiText,netInfo)
    led.value(0)
    lcd.clear()
    lcd.message("wifi connecting \n" + netInfo.Ssid + ':' + netInfo.Pass)
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(netInfo.Ssid, netInfo.Pass)
    lcd.clear()
    lcd.message("wifi connect \n" + netInfo.Ssid + ':' + netInfo.Pass)

    bme = BME280()
    
    while wlan.isconnected() == False:
        pass
    lcd.clear()
    lcd.message("wifi connected!")
    wlan.ifconfig((netInfo.Ip, netInfo.Mask, netInfo.Gw, '8.8.8.8'))
    time.sleep(1)
    wlan_status = wlan.ifconfig()
    lcd.clear()
    lcd.message(f'IP Address: \n{wlan_status[0]}')
    pwmServo = PWM(Pin(15))
    pwmServo.freq(50)
    ang = 0
    pwmServo.duty_u16(servo_value(ang))
    
    addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
    s = socket.socket()
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    s.bind(addr)
    s.listen(1)
    lcd.clear()
    lcd.message('listening on\n' + wlan_status[0])
    led.value(1)



    while True:
        cl, addr = s.accept()
        try:       
            lcd.clear()
            lcd.message('client connected from \n' + str(addr[0]))
            request = cl.recv(1024)
            request = str(request)
            print(request)
            anglevalue = request.find('angle=')
            if (anglevalue >= 0):
                anglevalue = request.index('angle=')
                anglevalue = anglevalue + len('angle=')
                ang = int(re.sub(r"\D", "", request[anglevalue:anglevalue + 4]))
                print('anglevalue:' + str(ang))
                pwmServo.duty_u16(servo_value(ang))
                lcd.clear()
                lcd.message('client ' + str(ang) + ' from \n' + str(addr[0]))

            print('@num' + str(ang))
            threeValues = bme.values
            print(threeValues)
            temp = str(threeValues[0]) + '°C'
            print('@Temperature' + threeValues[0])
            press = str(threeValues[1]) + 'hPa'
            print('@Pressure' + threeValues[1])
            humi = str(threeValues[2]) + '%'
            print('@Humidity' + threeValues[2])

            response = netInfo.getHtml().replace('@num',str(ang))
            print('getHtml() done')
            response = response.replace('@Temperature',temp)
            response = response.replace('@Pressure',press)
            response = response.replace('@Humidity',humi)
            full_response = 'HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n' + response
            print(full_response)
            cl.send(full_response)
            cl.close()
            
        except OSError as e:
            cl.close()
            lcd.clear()
            lcd.message('OSError')
        except:
            cl.close()
            lcd.clear()
            lcd.message('Error')
            pass
except KeyboardInterrupt:
    pass

class NetInfo:
    Ssid = ''
    Pass = ''
    Ip = ''
    Mask = ''
    Gw = ''
    def set(self,Ssid,Pass,Ip,Mask,Gw):
        self.Ssid = Ssid
        self.Pass = Pass
        self.Ip = Ip
        self.Mask = Mask
        self.Gw = Gw
        
    def getWifiSetting(self):
        path = '/wifi.txt'
        try:
            with open(path,'r') as rf:
                strReadData = rf.read()
                print("rf.read : " + strReadData)
                return strReadData
        except:
            strWriteData = ''
            with open(path,'w') as wf:
                strWriteData = 'ssid:240258107387' + '\n'
                strWriteData = strWriteData + 'pass:36113521' + '\n'
                strWriteData = strWriteData + 'ip:192.168.32.140' + '\n'
                strWriteData = strWriteData + 'mask:255.255.254.0' + '\n'
                strWriteData = strWriteData + 'gw:192.168.32.1' + '\n'
                try:
                    wf.write(strWriteData)
                    print("wf.write : " + strReadData)
                except:
                    pass
                return strWriteData
                pass
    def setWifiSetting(self,inText,netInfo):
        try:
            netInfo.Ssid = ''
            netInfo.Pass = ''
            netInfo.Ip = ''
            netInfo.Mask = ''
            netInfo.Gw = ''
            for item in inText.split('\n'):
                if (item.rfind('ssid:') != -1):
                    netInfo.Ssid = item[5:]
                if (item.rfind('pass:') != -1):
                    netInfo.Pass = item[5:]
                if (item.rfind('ip:') != -1):
                    netInfo.Ip = item[3:]
                if (item.rfind('mask:') != -1):
                    netInfo.Mask = item[5:]
                if (item.rfind('gw:') != -1):
                    netInfo.Gw = item[3:]
            print("setWifiSetting : \n" + netInfo.Ssid)
            return
        except:
            pass
        
    def getHtml(self):
        strHtml = 'HTML string'
        return strHtml



import machine
import time

class LCD():
    def __init__(self, addr=0x27, blen=1):
        sda = machine.Pin(16)
        scl = machine.Pin(17)
        self.bus = machine.I2C(0,sda=sda, scl=scl, freq=400000)
        print(self.bus)
        print(str(self.bus.scan()))
        print(str(hex(self.bus.scan()[0])))
        self.addr = addr
        self.blen = blen
        self.send_command(0x33) # Must initialize to 8-line mode at first
        time.sleep(0.005)
        self.send_command(0x32) # Then initialize to 4-line mode
        time.sleep(0.005)
        self.send_command(0x28) # 2 Lines & 5*7 dots
        time.sleep(0.005)
        self.send_command(0x0C) # Enable display without cursor
        time.sleep(0.005)
        self.send_command(0x01) # Clear Screen
        self.bus.writeto(self.addr, bytearray([0x08]))

    def write_word(self, data):
        temp = data
        if self.blen == 1:
            temp |= 0x08
        else:
            temp &= 0xF7
        self.bus.writeto(self.addr, bytearray([temp]))

    def send_command(self, cmd):
        # Send bit7-4 firstly
        buf = cmd & 0xF0
        buf |= 0x04               # RS = 0, RW = 0, EN = 1
        self.write_word(buf)
        time.sleep(0.002)
        buf &= 0xFB               # Make EN = 0
        self.write_word(buf)

        # Send bit3-0 secondly
        buf = (cmd & 0x0F) << 4
        buf |= 0x04               # RS = 0, RW = 0, EN = 1
        self.write_word(buf)
        time.sleep(0.002)
        buf &= 0xFB               # Make EN = 0
        self.write_word(buf)

    def send_data(self, data):
        # Send bit7-4 firstly
        buf = data & 0xF0
        buf |= 0x05               # RS = 1, RW = 0, EN = 1
        self.write_word(buf)
        time.sleep(0.002)
        buf &= 0xFB               # Make EN = 0
        self.write_word(buf)

        # Send bit3-0 secondly
        buf = (data & 0x0F) << 4
        buf |= 0x05               # RS = 1, RW = 0, EN = 1
        self.write_word(buf)
        time.sleep(0.002)
        buf &= 0xFB               # Make EN = 0
        self.write_word(buf)

    def clear(self):
        self.send_command(0x01) # Clear Screen

    def openlight(self):  # Enable the backlight
        self.bus.writeto(self.addr,bytearray([0x08]))
        # self.bus.close()

    def write(self, x, y, str):
        if x < 0: x = 0 if x > 15:
            x = 15
        if y < 0: y = 0 if y > 1:
            y = 1

        # Move cursor
        addr = 0x80 + 0x40 * y + x
        self.send_command(addr)

        for chr in str:
            self.send_data(ord(chr))

    def message(self, text):
        #print("message: %s"%text)
        for char in text:
            if char == '\n':
                self.send_command(0xC0) # next line
            else:
                self.send_data(ord(char))

import time
from ustruct import unpack, unpack_from
from array import array
import machine

# BME280 default address.
BME280_I2CADDR = 0x76

# Operating Modes
BME280_OSAMPLE_1 = 1
BME280_OSAMPLE_2 = 2
BME280_OSAMPLE_4 = 3
BME280_OSAMPLE_8 = 4
BME280_OSAMPLE_16 = 5

BME280_REGISTER_CONTROL_HUM = 0xF2
BME280_REGISTER_CONTROL = 0xF4


class BME280:

    def __init__(self,
                 mode=BME280_OSAMPLE_1,
                 address=BME280_I2CADDR,
                 i2c=None,
                 **kwargs):
        # Check that mode is valid.
        if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
                        BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
            raise ValueError(
                'Unexpected mode value {0}. Set mode to one of '
                'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
                'BME280_ULTRAHIGHRES'.format(mode))
        self._mode = mode
        self.address = address
        if i2c is None:
            i2c = machine.I2C(1,scl=machine.Pin(3, machine.Pin.IN), sda=machine.Pin(2, machine.Pin.IN), freq=400000)
            print(i2c)
            print(str(hex(i2c.scan()[0])))
            #raise ValueError('An I2C object is required.')
        self.i2c = i2c

        # load calibration data
        dig_88_a1 = self.i2c.readfrom_mem(self.address, 0x88, 26)
        dig_e1_e7 = self.i2c.readfrom_mem(self.address, 0xE1, 7)
        self.dig_T1, self.dig_T2, self.dig_T3, self.dig_P1, \
            self.dig_P2, self.dig_P3, self.dig_P4, self.dig_P5, \
            self.dig_P6, self.dig_P7, self.dig_P8, self.dig_P9, \
            _, self.dig_H1 = unpack("<HhhHhhhhhhhhBB", dig_88_a1)

        self.dig_H2, self.dig_H3 = unpack("<hB", dig_e1_e7)
        e4_sign = unpack_from("<b", dig_e1_e7, 3)[0]
        self.dig_H4 = (e4_sign << 4) | (dig_e1_e7[4] & 0xF)

        e6_sign = unpack_from("<b", dig_e1_e7, 5)[0]
        self.dig_H5 = (e6_sign << 4) | (dig_e1_e7[4] >> 4)

        self.dig_H6 = unpack_from("<b", dig_e1_e7, 6)[0]

        self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
                             bytearray([0x3F]))
        self.t_fine = 0

        # temporary data holders which stay allocated
        self._l1_barray = bytearray(1)
        self._l8_barray = bytearray(8)
        self._l3_resultarray = array("i", [0, 0, 0])

    def read_raw_data(self, result):
        """ Reads the raw (uncompensated) data from the sensor.

            Args:
                result: array of length 3 or alike where the result will be
                stored, in temperature, pressure, humidity order
            Returns:
                None
        """

        self._l1_barray[0] = self._mode
        self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL_HUM,
                             self._l1_barray)
        self._l1_barray[0] = self._mode << 5 | self._mode << 2 | 1
        self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
                             self._l1_barray)

        sleep_time = 1250 + 2300 * (1 << self._mode)
        sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
        sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
        time.sleep_us(sleep_time)  # Wait the required time

        # burst readout from 0xF7 to 0xFE, recommended by datasheet
        self.i2c.readfrom_mem_into(self.address, 0xF7, self._l8_barray)
        readout = self._l8_barray
        # pressure(0xF7): ((msb << 16) | (lsb << 8) | xlsb) >> 4
        raw_press = ((readout[0] << 16) | (readout[1] << 8) | readout[2]) >> 4
        # temperature(0xFA): ((msb << 16) | (lsb << 8) | xlsb) >> 4
        raw_temp = ((readout[3] << 16) | (readout[4] << 8) | readout[5]) >> 4
        # humidity(0xFD): (msb << 8) | lsb
        raw_hum = (readout[6] << 8) | readout[7] result[0] = raw_temp result[1] = raw_press result[2] = raw_hum def read_compensated_data(self, result=None): """ Reads the data from the sensor and returns the compensated data. Args: result: array of length 3 or alike where the result will be stored, in temperature, pressure, humidity order. You may use this to read out the sensor without allocating heap memory Returns: array with temperature, pressure, humidity. Will be the one from the result parameter if not None """ self.read_raw_data(self._l3_resultarray) raw_temp, raw_press, raw_hum = self._l3_resultarray # temperature var1 = ((raw_temp >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
        var2 = (((((raw_temp >> 4) - self.dig_T1) *
                  ((raw_temp >> 4) - self.dig_T1)) >> 12) * self.dig_T3) >> 14
        self.t_fine = var1 + var2
        temp = (self.t_fine * 5 + 128) >> 8

        # pressure
        var1 = self.t_fine - 128000
        var2 = var1 * var1 * self.dig_P6
        var2 = var2 + ((var1 * self.dig_P5) << 17)
        var2 = var2 + (self.dig_P4 << 35) var1 = (((var1 * var1 * self.dig_P3) >> 8) +
                ((var1 * self.dig_P2) << 12))
        var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
        if var1 == 0:
            pressure = 0
        else:
            p = 1048576 - raw_press
            p = (((p << 31) - var2) * 3125) // var1 var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
            var2 = (self.dig_P8 * p) >> 19
            pressure = ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)

        # humidity
        h = self.t_fine - 76800
        h = (((((raw_hum << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) + 16384) >> 15) * (((((((h * self.dig_H6) >> 10) *
                            (((h * self.dig_H3) >> 11) + 32768)) >> 10) +
                          2097152) * self.dig_H2 + 8192) >> 14))
        h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
        h = 0 if h < 0 else h h = 419430400 if h > 419430400 else h
        humidity = h >> 12

        if result:
            result[0] = temp
            result[1] = pressure
            result[2] = humidity
            return result

        return array("i", (temp, pressure, humidity))

    @property
    def values(self):
        """ human readable values """

        t, p, h = self.read_compensated_data()

        p = p // 256
        pi = p // 100
        pd = p - pi * 100

        hi = h // 1024
        hd = h * 100 // 1024 - hi * 100
        return ("{}".format(t / 100), "{}.{:02d}".format(pi, pd),
                "{}.{:02d}".format(hi, hd))