tamberg / circuitpython-workshop-pico-w

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

IoT Embedded Programming with CircuitPython

TODO: Port examples and images to Raspberry Pi Pico W

Workshop

The Internet of Things (IoT) is the convergence of internet and real world. IoT embedded devices typically have limited resources, but they are also becoming more performant with each generation. This allows an interpreted language like Python, which is less efficient but more convenient than C, to run on a microcontroller.

Topics

Objective

This workshop teaches the basics of embedded programming on the latest IoT hardware, with CircuitPython.

Target audience

This workshop is aimed at interested people with basic programming experience in Python.

Prerequisites

Participants need a laptop with MacOS, Windows or Linux, and one USB/USB-C port. IoT hardware including sensors is available on loan.

The workshop requires a Wi-Fi network that is accessible without a portal. Alternatively, a personal smartphone can be used as a hotspot.

Introduction

CircuitPython

The easiest way to program microcontrollers — https://circuitpython.org/

To program a CircuitPython microcontroller, plug it in via USB.

It shows up as a USB drive called CIRCUITPY.

(If not, see hardware setup.)

Toolchain setup

Code editor

CircuitPython works with any text editor, e.g. Mu Editor, VS Code, or nano.

$ nano /Volumes/CIRCUITPY/code.py

Serial monitor

To see output you'll need a serial monitor like PuTTY on Windows or screen on MacOS, Linux (or tio).

$ screen /dev/tty.u<TAB> 115200

If there is no output, use CTRL-D to reload

Hello, World!

Code done running.

Or press any other key to enter the REPL

>>>

CircuitPython libraries

Download the library bundle ZIP file from https://circuitpython.org/libraries

You will selectively copy files from the ZIP to your microcontroller later on.

Run Python code

Plug in your board via USB and open the CIRCUITPY drive.

Copy required libraries from the bundle to the lib folder.

Copy your code to a file named code.py on the drive.

$ cp hello/code.py /Volumes/CIRCUITPY/code.py

Now you are ready to try GPIO & sensors.

Hardware setup

We use a Pico W microcontroller with Grove sensors and actuators.

Pico W

Buy

Board

https://circuitpython.org/board/raspberry_pi_pico_w/

Pico W ROM bootloader mode (once)

To get the Pico W into ROM bootloader mode

  • Press and hold the BOOTSEL button
  • Unplug, then plug in the Pico W via USB

Now the board should show up as a USB device, e.g. /dev/cu.usbmodem01 on MacOS or COM3 on Windows.

Install CircuitPython (once)

Download the board specific .UF2 file from https://circuitpython.org/board/raspberry_pi_pico_w/

Drop it on the USB drive named RPI-RP2 and wait until the drive disconnects.

Now the board should show up as a USB drive named CIRCUITPY.

Troubleshooting

Pinout

Schematic

  • TODO (Schematic)

Datasheets

Grove sensors & actuators

Buy

GPIO & sensors

Blink (digital output)

Control a LED or any other digital actuator.

/CIRCUITPY
└── code.py # copied from below
import board
import digitalio
import time

actuator = digitalio.DigitalInOut(board.LED) # or board.GP1 (Grove), GP3 (Grove), GP8 (badge LED)
actuator.direction = digitalio.Direction.OUTPUT

while True:
    actuator.value = True
    time.sleep(1)
    actuator.value = False
    time.sleep(1)
# No output, but LED should blink

Button (digital input)

Read a button or any other digital sensor.

/CIRCUITPY
└── code.py # copied from below
import board
import digitalio
import time

sensor = digitalio.DigitalInOut(board.GP6) # or board.GP1 (Grove), GP3 (Grove)
sensor.direction = digitalio.Direction.INPUT
sensor.pull = digitalio.Pull.UP

while True:
    print(sensor.value)
    time.sleep(0.1)
False
False
True
...

DHT11 temperature & humidity

Read a DHT11 sensor using the adafruit_dht library.

/CIRCUITPY
├── code.py # copied from below
└── lib # libraries from bundle
    └── adafruit_dht.mpy
import adafruit_dht
import board
import time

sensor = adafruit_dht.DHT11(board.D18)

while True:
    try:
        temp = sensor.temperature
        humi = sensor.humidity
        print("{:.2f} °C, {:.2f} %".format(temp, humi))

    except RuntimeError as e:
        print("Oops, reading the sensor did not work.")

    time.sleep(5)
23.00 °C, 42.00 %
...

More

Search the library bundle docs for a sensor or actuator name.

Wi-Fi, HTTP & MQTT

Wi-Fi connect

Connect to the Internet using Wi-Fi.

/CIRCUITPY
└── code.py # copied from below
import wifi

WIFI_SSID = "MY_SSID" # TODO
WIFI_PASS = "MY_PASSWORD" # TODO

print("Connecting to Wi-Fi \"{0}\"...".format(WIFI_SSID))
wifi.radio.connect(WIFI_SSID, WIFI_PASS) # waits for IP address
print("Connected, IP address = {0}".format(wifi.radio.ipv4_address))
Connecting to Wi-Fi "MY_SSID"...
Connected, IP address = 192.168.0.23

Code done running.

Once a device is connected to the Internet, it can send data to a cloud backend.

To see how this works, try the HTTP post or MQTT publish examples.

HTTP post

Post data to the https://thingspeak.com/ cloud backend using HTTPS.

Create a free ThingSpeak account to get a Write API Key.

/CIRCUITPY
├── code.py # copied from below
└── lib # libraries from bundle
    └── adafruit_requests.mpy
import ssl
import time
import wifi
import socketpool

import adafruit_requests

WIFI_SSID = "MY_SSID" # TODO
WIFI_PASS = "MY_PASSWORD" # TODO
CLOUD_KEY = "****************" # TODO, ThingSpeak Write API Key
CLOUD_URL = "https://api.thingspeak.com/update.json"

print("Connecting to Wi-Fi \"{0}\"...".format(WIFI_SSID))
wifi.radio.connect(WIFI_SSID, WIFI_PASS) # waits for IP address
print("Connected, IP address = {0}".format(wifi.radio.ipv4_address))

socket = socketpool.SocketPool(wifi.radio)
context = ssl.create_default_context()
https = adafruit_requests.Session(socket, context)

while True:
    value = 23.0 # e.g. from sensor
    json_data = {
        "api_key": CLOUD_KEY,
        "field1": value, 
    }
    print("Posting to {0}\n> {1}".format(CLOUD_URL, json_data))
    response = https.post(CLOUD_URL, json=json_data)
    print("< {0}".format(response.json()))
    time.sleep(30) # s

Connecting to Wi-Fi "MY_SSID"...
Connected, IP address = 192.168.0.42
Posting to https://api.thingspeak.com/update.json
> {'field1': 23.0, 'api_key': '****************'}
< {'field1': 23.0, 'channel_id': 555, 'created_at': '2022-08-30T13:37:00Z', ...

Now, try to merge in the DHT11 example to send real sensor values.

Or learn more about Internet protocols and HTTP.

MQTT publish

Publish data to the https://thingspeak.com/ cloud backend using MQTT.

/CIRCUITPY
├── code.py # copied from below
└── lib # libraries from bundle
    └── adafruit_minimqtt
        ├── __init__.py
        ├── adafruit_minimqtt.mpy
        └── matcher.mpy
from random import randint
import ssl
import time
import wifi
import socketpool
import adafruit_minimqtt.adafruit_minimqtt as minimqtt

WIFI_SSID = "MY_SSID" # TODO
WIFI_PASS = "MY_PASSWORD" # TODO

# See https://ch.mathworks.com/help/thingspeak/mqtt-basics.html
MQTT_HOST = "mqtt3.thingspeak.com"
MQTT_PORT = 8883

# https://thingspeak.com/devices/mqtt > Add a device
MQTT_CLNT = "***********************" # TODO, Client ID
MQTT_USER = "***********************" # TODO, Username
MQTT_PASS = "***********************" # TODO, Password
THSP_CHAN = "000000" # TODO, ThingSpeak Channel ID

print("Connecting to Wi-Fi \"{0}\"...".format(WIFI_SSID))
wifi.radio.connect(WIFI_SSID, WIFI_PASS) # waits for IP address
print("Connected, IP address = {0}".format(wifi.radio.ipv4_address))

pool = socketpool.SocketPool(wifi.radio)
context = ssl.create_default_context()

def handle_connect(client, userdata, flags, rc):
    print("Connected to {0}".format(client.broker))

def handle_publish(client, userdata, topic, pid):
    print("Published to {0} with PID {1}".format(topic, pid))

mqtt_client = minimqtt.MQTT(
    broker = MQTT_HOST,
    port = MQTT_PORT,
    client_id = MQTT_CLNT,
    username = MQTT_USER,
    password = MQTT_PASS,
    socket_pool = pool,
    ssl_context = context)

mqtt_client.on_connect = handle_connect
mqtt_client.on_publish = handle_publish

print("\nConnecting to {0}...".format(MQTT_HOST))
mqtt_client.connect()

while True:
    value = 23 # e.g. from sensor
    mqtt_topic = "channels/" + THSP_CHAN + "/publish"
    mqtt_payload = "field1=" + str(value)
    mqtt_client.publish(mqtt_topic, mqtt_payload)
    time.sleep(5)

Learn more about the MQTT messaging protocol.

About

License:MIT License


Languages

Language:Python 100.0%