Lesson 3.3 — Apply Programming Libraries to Manage Sensor Data and Actuators
One of the most powerful aspects of the Arduino and MicroPython ecosystems is the availability of pre-written libraries that handle the complex low-level communication with sensors and actuators.
ANALOGY
A library is like a ready-made cooking sauce in a restaurant kitchen. Instead of making it from scratch every time, the chef opens the jar and uses it. Libraries let you use sensors without becoming an expert in their internal communication protocols.
Installing Arduino Libraries
| Method |
How to install |
When to use |
| Library Manager (recommended) |
Arduino IDE: Sketch → Include Library → Manage Libraries. Search by sensor name. Click Install. |
Best for popular sensors |
| ZIP file install |
Download ZIP from GitHub. Sketch → Include Library → Add .ZIP Library. |
For libraries not in manager |
| Manual install |
Extract ZIP to ~/Documents/Arduino/libraries/. Restart Arduino IDE. |
For troubleshooting installs |
| PlatformIO |
Professional alternative IDE: add libraries in platformio.ini with lib_deps. Handles versioning automatically. |
For production development |
DHT11 / DHT22 — Temperature and Humidity Sensor
| DHT Pin |
Connect to |
Notes |
| VCC |
3.3 V or 5 V (check your module) |
Power supply |
| DATA |
Arduino pin 4 (any digital pin) |
Single-wire data signal |
| GND |
GND |
Ground |
| Pull-up |
4.7 kΩ between DATA and VCC |
Required for reliable communication (some modules include on board) |
C/C++ — DHT Sensor with Arduino (DHT library by Adafruit)
#include <DHT.h>
#define DHTPIN 4 // Data pin connected to GPIO 4
#define DHTTYPE DHT22 // DHT22 or DHT11
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
dht.begin();
Serial.println("DHT Sensor ready");
}
void loop() {
delay(2000); // DHT22 needs minimum 2 seconds between reads
float humidity = dht.readHumidity();
float temperature = dht.readTemperature(); // Celsius by default
float heatIndex = dht.computeHeatIndex(temperature, humidity, false);
// Check for read failures
if (isnan(humidity) || isnan(temperature)) {
Serial.println("ERROR: Failed to read from DHT sensor!");
return;
}
Serial.print("Humidity: "); Serial.print(humidity, 1); Serial.print(" % ");
Serial.print("Temperature: "); Serial.print(temperature, 1); Serial.print(" C ");
Serial.print("Heat Index: "); Serial.print(heatIndex, 1); Serial.println(" C");
}
MicroPython — DHT Sensor on ESP32 (built-in dht module)
# MicroPython has a built-in DHT module — no installation needed!
import dht
from machine import Pin
import time
sensor = dht.DHT22(Pin(4)) # Or dht.DHT11(Pin(4))
while True:
try:
sensor.measure()
temp = sensor.temperature()
hum = sensor.humidity()
print(f'Temperature: {temp:.1f} C Humidity: {hum:.1f} %')
except Exception as e:
print('Sensor error:', e)
time.sleep(2)
Servo Motor Control
| Wire colour |
Connection |
| Red wire (VCC) |
5 V (directly from Arduino 5V pin or external supply — do NOT power from ESP32 3.3V output) |
| Brown/Black wire |
GND |
| Orange/Yellow wire |
Signal: connect to PWM pin (Arduino pin 9, or any ESP32 GPIO) |
C/C++ — Servo Control (Arduino Servo library)
#include <Servo.h>
Servo gateServo;
void setup() {
gateServo.attach(9); // Attach servo signal to pin 9
Serial.begin(9600);
}
void loop() {
// Sweep 0 to 180 degrees
for (int angle = 0; angle <= 180; angle += 10) {
gateServo.write(angle);
delay(100);
}
delay(1000);
gateServo.write(0); // Return to 0
delay(1000);
}
// IoT use case: Open/close a valve based on sensor input
void setValve(bool open) {
gateServo.write(open ? 90 : 0); // 90 = open, 0 = closed
Serial.println(open ? "Valve OPEN" : "Valve CLOSED");
}
MicroPython — Servo Control on ESP32
from machine import Pin, PWM
import time
servo = PWM(Pin(9), freq=50) # Servo needs 50 Hz PWM signal
def set_angle(degrees):
"""Convert degrees (0-180) to PWM duty cycle."""
min_duty = int(65535 * 0.5 / 20) # 0.5ms pulse
max_duty = int(65535 * 2.5 / 20) # 2.5ms pulse
duty = min_duty + int((max_duty - min_duty) * degrees / 180)
servo.duty_u16(duty)
# Sweep servo
for angle in range(0, 181, 10):
set_angle(angle)
time.sleep_ms(100)
set_angle(0) # Return to start
I2C Sensor — BMP280 Barometric Pressure
| BMP Pin |
Connection |
| VCC |
3.3 V (NOT 5 V — these sensors are 3.3 V only) |
| GND |
GND |
| SDA |
Arduino A4 or ESP32 GPIO 21 (default I2C SDA) |
| SCL |
Arduino A5 or ESP32 GPIO 22 (default I2C SCL) |
C/C++ — BMP280 with Adafruit BMP280 Library
#include <Wire.h>
#include <Adafruit_BMP280.h>
Adafruit_BMP280 bmp;
void setup() {
Serial.begin(9600);
Wire.begin();
if (!bmp.begin(0x76)) { // I2C address: 0x76 or 0x77
Serial.println("ERROR: BMP280 not found. Check wiring and I2C address.");
while (1) delay(1000);
}
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,
Adafruit_BMP280::SAMPLING_X2, // temperature
Adafruit_BMP280::SAMPLING_X16, // pressure
Adafruit_BMP280::FILTER_X16,
Adafruit_BMP280::STANDBY_MS_500);
}
void loop() {
float temp = bmp.readTemperature();
float pressure = bmp.readPressure() / 100.0; // Pa to hPa
float altitude = bmp.readAltitude(1013.25);
Serial.print("Temp: "); Serial.print(temp, 1); Serial.print(" C ");
Serial.print("Pressure: "); Serial.print(pressure, 1); Serial.print(" hPa ");
Serial.print("Altitude: "); Serial.print(altitude, 1); Serial.println(" m");
delay(2000);
}
OLED Display — Showing Sensor Data Locally
A 0.96-inch SSD1306 OLED display connected via I2C allows your IoT device to show sensor readings without a computer. Essential for standalone deployments.
C/C++ — OLED with Adafruit SSD1306 Library
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
DHT dht(4, DHT22);
void setup() {
Serial.begin(9600);
dht.begin();
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 OLED not found");
while(1);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Weather Station");
display.println("Initialising...");
display.display();
delay(2000);
}
void loop() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.print(temp, 1);
display.println(" C");
display.setTextSize(1);
display.print("Humidity: ");
display.print(hum, 0);
display.println("%");
display.display(); // Push buffer to screen
delay(2000);
}
JSON — Formatting Sensor Data for IoT Transmission
JSON (JavaScript Object Notation) is the universal data format for IoT cloud communication. Sensor readings are packed into a JSON object before being sent to a cloud platform, MQTT broker, or REST API.
C/C++ — Building JSON with ArduinoJson Library
#include <ArduinoJson.h>
void sendSensorPayload(float temp, float hum, float pressure) {
StaticJsonDocument<200> doc; // stack memory (safer on small MCUs)
doc["device_id"] = "weather-station-kigali-01";
doc["temperature"] = round(temp * 10) / 10.0; // 1 decimal place
doc["humidity"] = round(hum * 10) / 10.0;
doc["pressure_hpa"] = round(pressure * 10) / 10.0;
doc["timestamp_ms"] = millis();
char jsonBuffer[200];
serializeJson(doc, jsonBuffer);
Serial.println(jsonBuffer);
// Output: {"device_id":"weather-station-kigali-01","temperature":24.5,...}
// In Unit 6 you will replace Serial.println with:
// mqttClient.publish("sensors/weather", jsonBuffer);
}
MicroPython — JSON Encoding with ujson
import ujson, time
def build_payload(temp, hum):
data = {
'device_id': 'weather-esp32-01',
'temperature': round(temp, 1),
'humidity': round(hum, 1),
'uptime_ms': time.ticks_ms()
}
return ujson.dumps(data)
payload = build_payload(24.5, 68.2)
print(payload)
# Output: {"device_id": "weather-esp32-01", "temperature": 24.5, ...}
Library Best Practices for IoT
| Practice |
Explanation |
| Always check .begin() return value |
Most sensor libraries return false or 0 if initialisation fails. Handle this with a clear error message, not a silent continue. |
| Pin the library version |
Libraries update and sometimes introduce breaking changes. Note the version to ensure consistency across team members. |
| Minimise includes |
Each #include adds to compile time and flash usage. Only include libraries you actually use. |
| Read the examples first |
Every Arduino library includes working example sketches under File → Examples. Always start from the example and adapt it rather than writing from scratch. |
| Check for conflicting pin usage |
Some libraries claim GPIO pins internally (e.g. Servo library uses Timer1 on AVR, interfering with PWM on pins 9 and 10). Read the docs. |
Check Your Understanding — Lesson 3.3
?
1. Write the C/C++ code to read temperature and humidity from a DHT22 on pin 4, check if the reading is valid using isnan(), and print a formatted message like ‘T: 24.5C H: 68%’ to the Serial Monitor.
?
2. What is the purpose of calling display.clearDisplay() before each update cycle on an OLED display? What would happen if you omitted this call?
?
3. In ArduinoJson, what is the difference between StaticJsonDocument and DynamicJsonDocument? Which is recommended for IoT devices with limited RAM and why?