We’re finally able to get our hands on some sweet Pis after a long shortage. I got a Pi Pico W because it’s just that cheap, why not? It’s the W that really makes the difference; years ago I went from full Pis to Pi Zeros because the Wifi capabilities meant I didn’t have to worry about USB dongles. Everything I do tends to be Wifi connected so not having it makes a board irrelevant. And so with a W next to the Pico’s name, I’m definitely interested. It’s pretty smart of the Raspberry Pi foundation to put in this functionality into a microcontroller, it’s just enough to get me curious in what I could actually do with it.
Now I have to get over the barrier of not having a fully fledged OS (and the sweet package managers with all the Debian packages that comes with it), but with Wifi I can definitely do some tasks with a Pico I’m usually doing with a Zero. So I figured I’d try replacing the house temperature sensor and see how that goes. I initially tried to use the Pico’s built in temperature sensor, but it’s terribly inaccurate so I did rewire the DS18B20 from the Zero to the Pico.
Brain transfer, The size gain is nice but not particularly significant
Coding was a breeze, there is isn’t much to say about that, but if you’re interested, here the code I’m running for a web server I can ask for current temperature. One thing I learned is that you need to make sure you have a “lib” directory with libraries you might need for your code.
import machine
import time
import network
import socket
from machine import ADC
import machine, onewire, ds18x20
html = """{\"house_temperature\":<TEMPERATURE>}"""
led = machine.Pin( "LED", machine.Pin.OUT )
ds_pin = machine.Pin( 17 )
ds_sensor = ds18x20.DS18X20( onewire.OneWire(ds_pin) )
roms = ds_sensor.scan()
print( "Found DS devices: ", roms )
ssid = "<redacted>"
password = "<redacted>"
wlan = network.WLAN( network.STA_IF )
wlan.active( True )
wlan.connect( ssid, password )
# wait for connect or fail
max_wait = 20
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
if wlan.status()!=3:
raise RuntimeError( "network connection failed" )
else:
print( "connected" )
status = wlan.ifconfig()
print( "ip = " + status[0] )
# open socket
addr = socket.getaddrinfo( "0.0.0.0", 80)[0][-1]
s = socket.socket()
s.bind( addr )
s.listen( 1 )
print( "web server listening on", addr )
# listen for connections
while True:
try:
cl, addr = s.accept()
print( "client connected from", addr)
request = cl.recv( 1024 )
print( request )
request = str( request )
ds_sensor.convert_temp()
time.sleep_ms(750)
response = html.replace( "<TEMPERATURE>", str(ds_sensor.read_temp(roms[0])) )
led.value( 1 )
cl.send('HTTP/1.0 200 OK\r\nContent-type: application/json\r\n\r\n')
led.value( 0 )
cl.send(response)
cl.close()
except OSError as e:
cl.close()
print('connection closed')
I got the libraries online, but here they are in case it’s useful.
# 1-Wire driver for MicroPython
# MIT license; Copyright (c) 2016 Damien P. George
import _onewire as _ow
class OneWireError(Exception):
pass
class OneWire:
SEARCH_ROM = 0xF0
MATCH_ROM = 0x55
SKIP_ROM = 0xCC
def __init__(self, pin):
self.pin = pin
self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP)
def reset(self, required=False):
reset = _ow.reset(self.pin)
if required and not reset:
raise OneWireError
return reset
def readbit(self):
return _ow.readbit(self.pin)
def readbyte(self):
return _ow.readbyte(self.pin)
def readinto(self, buf):
for i in range(len(buf)):
buf[i] = _ow.readbyte(self.pin)
def writebit(self, value):
return _ow.writebit(self.pin, value)
def writebyte(self, value):
return _ow.writebyte(self.pin, value)
def write(self, buf):
for b in buf:
_ow.writebyte(self.pin, b)
def select_rom(self, rom):
self.reset()
self.writebyte(self.MATCH_ROM)
self.write(rom)
def scan(self):
devices = []
diff = 65
rom = False
for i in range(0xFF):
rom, diff = self._search_rom(rom, diff)
if rom:
devices += [rom]
if diff == 0:
break
return devices
def _search_rom(self, l_rom, diff):
if not self.reset():
return None, 0
self.writebyte(self.SEARCH_ROM)
if not l_rom:
l_rom = bytearray(8)
rom = bytearray(8)
next_diff = 0
i = 64
for byte in range(8):
r_b = 0
for bit in range(8):
b = self.readbit()
if self.readbit():
if b: # there are no devices or there is an error on the bus
return None, 0
else:
if not b: # collision, two devices with different bit meaning
if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i):
b = 1
next_diff = i
self.writebit(b)
if b:
r_b |= 1 << bit
i -= 1
rom[byte] = r_b
return rom, next_diff
def crc8(self, data):
return _ow.crc8(data)
# DS18x20 temperature sensor driver for MicroPython.
# MIT license; Copyright (c) 2016 Damien P. George
from micropython import const
_CONVERT = const(0x44)
_RD_SCRATCH = const(0xBE)
_WR_SCRATCH = const(0x4E)
class DS18X20:
def __init__(self, onewire):
self.ow = onewire
self.buf = bytearray(9)
def scan(self):
return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)]
def convert_temp(self):
self.ow.reset(True)
self.ow.writebyte(self.ow.SKIP_ROM)
self.ow.writebyte(_CONVERT)
def read_scratch(self, rom):
self.ow.reset(True)
self.ow.select_rom(rom)
self.ow.writebyte(_RD_SCRATCH)
self.ow.readinto(self.buf)
if self.ow.crc8(self.buf):
raise Exception("CRC error")
return self.buf
def write_scratch(self, rom, buf):
self.ow.reset(True)
self.ow.select_rom(rom)
self.ow.writebyte(_WR_SCRATCH)
self.ow.write(buf)
def read_temp(self, rom):
buf = self.read_scratch(rom)
if rom[0] == 0x10:
if buf[1]:
t = buf[0] >> 1 | 0x80
t = -((~t + 1) & 0xFF)
else:
t = buf[0] >> 1
return t - 0.25 + (buf[7] - buf[6]) / buf[7]
else:
t = buf[1] << 8 | buf[0]
if t & 0x8000: # sign bit set
t = -((t ^ 0xFFFF) + 1)
return t / 16
Half the amp draw from a Zero
That’s it!