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))