MicroPython 101 IoT Basics
Tags: micropython, iot, tutorial, python
Published: 2023-06-19 13:54:00

MicroPython is a lean and efficient implementation of the Python 3 programming language that includes a small subset of the Python standard library. It's optimized to run on microcontrollers, which are small, low-power computers on a single integrated circuit.

MicroPython offers a complete implementation of Python 3.4 and includes significant aspects of Python 3.5. However, it doesn't incorporate every feature introduced from Python 3.5 onwards. That said, it does adopt some fresh syntax from Python 3.6 and specific features from subsequent versions like 3.8 (assignment expressions) and 3.9. It also encompasses a selection of the standard library.

Here are some of the key features:

**Interactive Prompt:** MicroPython runs an interactive prompt (REPL) when a board is connected and powered.

**Extensive libraries:** These include hardware-specific modules like machine, network, etc., that allows you to control GPIO pins, connect to WiFi, and much more.

**Python Syntax:** It uses Python syntax which makes it easy to learn and use.

**Efficiency:** MicroPython is designed to be efficient both in terms of memory usage and speed.

## Installation:
To get started, you need to install MicroPython firmware onto your microcontroller. This process differs from device to device, but usually, it involves downloading the firmware and then using a tool to flash it onto the board.

## Hello World with MicroPython:
Let's look at a basic example of blinking an LED (a "Hello, World!" equivalent in the hardware world).

```
from machine import Pin
from time import sleep

led = Pin(2, Pin.OUT)

while True:
    led.on()
    sleep(0.5)
    led.off()
    sleep(0.5)
```

This script does the following:

- It imports the `Pin` class from the `machine` module and the `sleep` function from the `time` module.
- It defines `led` to be pin number 2 and sets it as an output.
- In an infinite loop, it turns the LED on, waits for half a second, turns the LED off, and then waits for another half a second before repeating.

## Interacting with the REPL:
After you've flashed MicroPython onto your board, you can connect to it to start programming. You typically do this via a serial connection over USB. Once connected, you'll see the Python prompt >>>, where you can type commands and see their output immediately.

## Using Digital Inputs
MicroPython allows you to read the state of buttons, switches, or any digital input. For example, if you have a push-button switch connected to pin 5, you could read its state as follows:

```
from machine import Pin

button = Pin(5, Pin.IN)

while True:
    print(button.value())
```
This script continuously prints the state of the button.

## Using Analog Inputs
Microcontrollers often have pins that can read analog values, like varying voltages. You can use MicroPython's ADC (Analog-to-Digital Converter) class for this:

```
from machine import Pin, ADC
from time import sleep

adc = ADC(Pin(32))  # assuming an analog sensor is connected to pin 32

while True:
    print(adc.read())
    sleep(1)
```
This script will read and print the analog value every second.

## Networking with MicroPython
One of the big advantages of MicroPython (especially on network-capable hardware like the ESP8266 or ESP32) is its networking capabilities. Here's a simple example of connecting to a Wi-Fi network:

import network

```
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect("<your ssid>", "<your password>")

# Wait for the module to connect to the wifi
while station.isconnected() == False:
    pass

print('Connection successful')
print(station.ifconfig())
```

This script attempts to connect to the given SSID with the provided password, then it waits until a connection is established. Once connected, it prints the network configuration which includes the assigned IP address.

## Pulse Width Modulation (PWM):
PWM is a technique for getting analog results with digital means. It is commonly used to control servos, LEDs, and other devices that need a varying amount of power. Here is an example of using PWM to control the brightness of an LED:

```
from machine import Pin, PWM
from time import sleep

pwm = PWM(Pin(5))  # create PWM object from a pin
pwm.freq(500)      # set frequency
pwm.duty(512)      # set duty cycle

while True:
    for duty in range(0, 1024, 10):
        pwm.duty(duty)
        sleep(0.005)
```
This will cause the LED to fade in and out smoothly.

## Timers and Interrupts:
MicroPython can also handle hardware interrupts and timers. These can be used for time-sensitive operations or tasks that need to occur at regular intervals:

```
from machine import Pin, Timer

led = Pin(5, Pin.OUT)
timer = Timer()

def toggle_led(timer):
    led.value(not led.value())

timer.init(period=500, mode=Timer.PERIODIC, callback=toggle_led)
```
This script will toggle the state of the LED every 500 milliseconds.

## Working with Files:
MicroPython also provides a pyb module that includes functions for file I/O operations. Here's how you could write to a file:

```
with open('myfile.txt', 'w') as f:
    f.write('Hello, MicroPython!')
```
And here's how you could read from a file:

```
with open('myfile.txt', 'r') as f:
    print(f.read())
```

## Web Server:
MicroPython even allows you to create a simple web server to control or monitor your device over the internet:

```
import socket
from machine import Pin

led = Pin(2, Pin.OUT)

def web_page():
    if led.value():
        gpio_state="ON"
    else:
        gpio_state="OFF"
    
    html = """
    <html>
    <body>
    <p>GPIO state: <strong>""" + gpio_state + """</strong></p>
    </body>
    </html>
    """
    return html

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 80))
s.listen(5)

while True:
    conn, addr = s.accept()
    request = conn.recv(1024)
    response = web_page()
    conn.send('HTTP/1.1 200 OK\n')
    conn.send('Content-Type: text/html\n')
    conn.send('Connection: close\n\n')
    conn.sendall(response)
    conn.close()
```
This server responds with a simple web page showing the current state of the LED.

## Built-in Libraries

MicroPython includes a selection of Python standard libraries, along with some MicroPython-specific modules for hardware access:

`machine` Module: This module contains functions related to the hardware and peripherals like pins, ADC, PWM, I2C, SPI, etc.

`network` Module: As seen in previous examples, this module allows you to connect your MicroPython device to a network.

`ujson` Module: Similar to Python's json module, it allows you to work with JSON data.

`usocket` Module: Provides a subset of Python's socket module for networking.

`utime` Module: This module provides functions for time access and conversions.

`uos` Module: Provides functions for file and directory access, similar to Python's os module.

## Some Useful Tools for MicroPython

**Mu Editor:** A simple Python editor that works with MicroPython. It can connect directly to a microcontroller board and provides a built-in REPL.

**uPyCraft:** A dedicated IDE designed specifically for MicroPython. It supports flashing firmware onto devices, has a built-in file manager for managing the filesystem on your microcontroller, and provides a built-in REPL.

**rshell:** A remote shell for MicroPython that allows file transfer and running scripts on the microcontroller.

**mpfshell:** A simple shell-based file explorer for MicroPython devices.

## Example Project: IoT Thermometer

Let's consider a simple IoT project where we use a temperature sensor (DS18B20) to measure the temperature and then send this data over MQTT:

```
from machine import Pin
from time import sleep
import ds18x20
import onewire
import network
import umqtt.simple

# Connect to Wi-Fi
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect("<your ssid>", "<your password>")
while station.isconnected() == False:
    pass

# Connect to the MQTT broker
client = umqtt.simple.MQTTClient("umqtt_client", "<broker_url>")
client.connect()

# DS18B20 data line connected to pin P10
ow = onewire.OneWire(Pin(10))
ds = ds18x20.DS18X20(ow)
roms = ds.scan()

while True:
    ds.convert_temp()
    sleep_ms(750)
    for rom in roms:
        temp = ds.read_temp(rom)
        client.publish("temperature", str(temp))
    sleep(60)
```
In this script, we first connect to the Wi-Fi, then to the MQTT broker. We then read the temperature from the sensor every minute and publish it to the "temperature" topic on the MQTT broker.

## Deep Sleep and Power Saving:

One major advantage of using MicroPython with microcontrollers is the ability to put the device into deep sleep, which is essential for battery-powered projects. When a device is in deep sleep, it consumes significantly less power. It can be awakened by a timer or an external interrupt.

```
from machine import Pin, deepsleep

# Put the device into deep sleep for 10 seconds
deepsleep(10000)
```

The device will wake up from deep sleep as if it has been reset, and it will execute the script from the beginning.

## Displaying Data:

MicroPython supports several types of displays. One common type is the OLED display, which can be used to display text, graphics, or data from sensors. Here's an example:

```
from machine import Pin, I2C
import ssd1306

i2c = I2C(scl=Pin(5), sda=Pin(4))
display = ssd1306.SSD1306_I2C(128, 64, i2c)

display.text('Hello, MicroPython!', 0, 0)
display.show()
```

This script initializes an OLED display and displays the text 'Hello, MicroPython!' on it.

## Interacting with Web APIs:

MicroPython can make HTTP requests and interact with web APIs. For example, it can send data to an API, or retrieve and process data from an API.

Here's how to make a GET request to an API:

```
import urequests

response = urequests.get('https://api.example.com/data')
data = response.json()

print(data)
```

This script sends a GET request to 'https://api.example.com/data', retrieves the response, and parses it as JSON.

## Using External Libraries:

Besides the built-in libraries, MicroPython has an ecosystem of external libraries that can be added to your projects. These include libraries for specific sensors, displays, and other hardware, as well as libraries for cloud services, protocols, and other utilities.

These libraries can usually be loaded onto your device using tools like ampy, rshell, or through the REPL.

## Interrupts:

Interrupts are a powerful feature in MicroPython that allows a program to respond immediately to certain events. For instance, you can use interrupts to trigger a function call when a button is pressed:

```
from machine import Pin

def button_pressed(pin):
    print("Button pressed!")

button = Pin(14, Pin.IN)
button.irq(trigger=Pin.IRQ_RISING, handler=button_pressed)
```

In this example, the `button_pressed` function will be called immediately whenever the button is pressed.

## Threading:

MicroPython supports basic multithreading with the _thread module, allowing you to run multiple functions at the same time. Note that threading can make programs more complex and harder to debug:

```
import _thread
import time

def task(name, delay):
    while True:
        print("Task", name)
        time.sleep(delay)

_thread.start_new_thread(task, ("A", 1))
_thread.start_new_thread(task, ("B", 2))
```
This program runs two tasks in parallel that print their name every 1 or 2 seconds.

## MicroPython with IoT Platforms:

MicroPython can be integrated with IoT platforms like AWS IoT, Google Cloud IoT, etc. These platforms can collect, process, analyze, and visualize IoT data, and they also provide other features like device management, security, and more.

Here is an example of publishing data to AWS IoT:

```
from umqtt.simple import MQTTClient
import network
import machine

# Connect to WiFi
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect("<your ssid>", "<your password>")
while station.isconnected() == False:
    pass

# Create MQTT client and connect to AWS IoT
client = MQTTClient(machine.unique_id(), "<aws-endpoint>", port=8883, keepalive=4000)
client.connect()

# Publish data
while True:
    temperature = read_temperature()  # Your function to read temperature
    client.publish("sensors/temperature", str(temperature))
    time.sleep(10)
```
In this example, the device continuously reads a temperature and publishes it.

## Error Handling:

Like Python, MicroPython supports exceptions and error handling. Using try/except blocks, you can anticipate and respond to errors in your code. Here's an example:

```
try:
    # Code that may raise an exception
    x = 1 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")
```

## MicroPython's uasyncio Library:

MicroPython supports asynchronous I/O using the `uasyncio` library, which is a minimal implementation of Python's asyncio library. Asynchronous I/O is useful for managing tasks that can block program execution, such as reading from sensors or waiting for network data.

Here's an example of how to use `uasyncio` to blink an LED without using `time.sleep()`:

```
import uasyncio as asyncio
from machine import Pin

led = Pin(2, Pin.OUT)

async def blink(led):
    while True:
        led.on()
        await asyncio.sleep(1)
        led.off()
        await asyncio.sleep(1)

# Run the blink coroutine
loop = asyncio.get_event_loop()
loop.run_until_complete(blink(led))
```

## Best Practices for MicroPython:

**Comment your code:** This is particularly important when working with hardware where code can interact with physical elements in non-obvious ways.

**Handle exceptions:** Microcontrollers work in the real world and things can go wrong. Exception handling helps to diagnose and recover from errors.

**Keep it simple:** MicroPython's environment has limited resources, so strive for simplicity and efficiency in your code.

**Reuse and share code:** Reuse your own code and leverage community libraries where possible. If you've written a useful library, consider sharing it with the community.

**Optimize for low power:** Many MicroPython applications are battery-powered. Use power-saving techniques like deep sleep, turning off unnecessary peripherals, etc.

## Resources:

**Official MicroPython Documentation:** The official documentation is a comprehensive resource that provides detailed information about MicroPython, its functions, and modules. It's a great starting point for anyone looking to learn MicroPython.

Link: [MicroPython Documentation](https://docs.micropython.org/en/latest/)

**MicroPython for the Internet of Things by Charles Bell:** This is a comprehensive book for those who prefer structured learning. It walks you through setting up and programming hardware to use MicroPython.

Link: [MicroPython for the Internet of Things: A Beginner’s Guide to Programming with Python on Microcontrollers](https://amzn.to/43Mwkei)

**Adafruit's MicroPython Tutorials:** Adafruit, a popular platform for DIY electronics, has a series of tutorials on MicroPython that are easy to follow. They also sell hardware compatible with MicroPython.

Link: [Adafruit MicroPython Tutorials](https://learn.adafruit.com/category/micropython)

**Online Course Platforms:** Websites like Udemy, Coursera, and LinkedIn Learning often have courses on MicroPython.

**YouTube Channels:** There are several YouTube channels that post MicroPython tutorials and project guides, such as Tech With Tim, Andreas Spiess, and many more.

**Forums and Community Groups:** Online communities like the official MicroPython Forum, Stack Overflow, and Reddit often have threads dedicated to MicroPython. They can be a good place to ask questions and learn from others' experiences.

**GitHub:** Various projects and libraries on GitHub use MicroPython, providing real-world examples of how it can be used.

Remember, the best way to learn is by doing. Once you have a basic understanding of MicroPython, start a project and learn as you go. MicroPython opens a world of possibilities for Python programmers to enter into the realm of hardware and IoT devices. Enjoy exploring and building with MicroPython!

If you enjoy my technology-focused articles and insights and wish to support my work, feel free to visit my Ko-fi page at https://ko-fi.com/philipjohnbasile. Every coffee you buy me helps keep the tech wisdom flowing and allows me to continue sharing valuable content with our community. Your support is greatly appreciated!