1538  Software Prototyping: Libraries and Version Control

1538.1 Learning Objectives

By the end of this chapter, you will be able to:

  • Use Sensor Libraries: Integrate Adafruit Unified Sensor and similar libraries for standardized sensor access
  • Implement Communication Protocols: Add Wi-Fi, MQTT, and HTTP connectivity using established libraries
  • Manage Dependencies: Track library versions and handle dependency conflicts
  • Apply Version Control: Use Git effectively for IoT firmware projects

1538.2 Prerequisites

Before diving into this chapter, you should be familiar with:


1538.3 Sensor Libraries

Adafruit Unified Sensor Library: Standardized interface for various sensors.

Example:

#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>

DHT_Unified dht(DHTPIN, DHT22);

void setup() {
  dht.begin();
  sensor_t sensor;
  dht.temperature().getSensor(&sensor);
}

void loop() {
  sensors_event_t event;
  dht.temperature().getEvent(&event);
  Serial.print("Temp: ");
  Serial.println(event.temperature);
}

Benefits: - Consistent API across sensors - Easy to swap sensors - Well-documented and tested

Popular Sensor Libraries:

Sensor Type Library Sensors Supported
Environmental Adafruit BME280 Temperature, humidity, pressure
Motion Adafruit MPU6050 Accelerometer, gyroscope
Light Adafruit TSL2591 Lux measurement
Distance NewPing Ultrasonic sensors
GPS TinyGPS++ NMEA parsing

1538.4 Communication Libraries

1538.4.1 Wi-Fi

#include <WiFi.h>

void setup() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  Serial.println(WiFi.localIP());
}

1538.4.2 MQTT

#include <PubSubClient.h>

WiFiClient espClient;
PubSubClient client(espClient);

void callback(char* topic, byte* payload, unsigned int length) {
  // Handle incoming messages
}

void setup() {
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  // Publish data
  client.publish("sensors/temperature", "25.5");
}

1538.4.3 HTTP/REST

#include <HTTPClient.h>

void sendData() {
  HTTPClient http;
  http.begin("http://api.example.com/data");
  http.addHeader("Content-Type", "application/json");

  int httpCode = http.POST("{\"sensor\":\"temp\",\"value\":25.5}");

  if (httpCode > 0) {
    String response = http.getString();
    Serial.println(response);
  }

  http.end();
}

1538.4.4 WebSocket

#include <WebSocketsClient.h>

WebSocketsClient webSocket;

void webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {
  switch(type) {
    case WStype_CONNECTED:
      webSocket.sendTXT("Hello Server");
      break;
    case WStype_TEXT:
      Serial.printf("Received: %s\n", payload);
      break;
  }
}

void setup() {
  webSocket.begin("server.com", 80, "/ws");
  webSocket.onEvent(webSocketEvent);
}

void loop() {
  webSocket.loop();
}

1538.5 Display Libraries

OLED Displays:

#include <Adafruit_SSD1306.h>

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire);

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println("Hello IoT!");
  display.display();
}

TFT Displays:

#include <TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();

void setup() {
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);
  tft.setTextColor(TFT_WHITE);
  tft.drawString("Sensor Data", 10, 10);
}

1538.6 Cloud Integration Libraries

AWS IoT:

#include <AWS_IOT.h>

AWS_IOT aws;

void setup() {
  aws.connect(HOST, CLIENT_ID);
}

void loop() {
  if (aws.publish(TOPIC, "{\"temp\":25.5}")) {
    Serial.println("Published");
  }
}

Azure IoT Hub:

#include <AzureIoTHub.h>
#include <AzureIoTProtocol_MQTT.h>

void sendMessage() {
  IOTHUB_MESSAGE_HANDLE messageHandle =
    IoTHubMessage_CreateFromString(message);
  IoTHubClient_SendEventAsync(iotHubClientHandle,
    messageHandle, sendCallback, NULL);
}

Firebase:

#include <Firebase_ESP_Client.h>

FirebaseData fbdo;
FirebaseAuth auth;
FirebaseConfig config;

void setup() {
  config.api_key = API_KEY;
  config.database_url = DATABASE_URL;
  Firebase.begin(&config, &auth);
}

void loop() {
  Firebase.RTDB.setFloat(&fbdo, "/sensors/temp", 25.5);
}

1538.7 Git for IoT Projects

Repository Structure:

iot-project/
β”œβ”€β”€ firmware/
β”‚   β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ test/
β”‚   └── platformio.ini
β”œβ”€β”€ hardware/
β”‚   β”œβ”€β”€ schematics/
β”‚   └── pcb/
β”œβ”€β”€ docs/
β”œβ”€β”€ .gitignore
└── README.md

.gitignore for IoT:

# Build artifacts
.pio/
build/
*.hex
*.bin
*.elf

# IDE files
.vscode/
.idea/
*.swp

# Environment-specific
secrets.h
credentials.json

# OS files
.DS_Store
Thumbs.db

Branching Strategy: - main: Production-ready code - develop: Integration branch - feature/*: New features - bugfix/*: Bug fixes - release/*: Release preparation

Commit Best Practices:

# Good commit messages
git commit -m "Add BME280 sensor support with I2C interface"
git commit -m "Fix deep sleep wake-up issue on ESP32"
git commit -m "Optimize Wi-Fi reconnection logic to reduce power"

# Poor commit messages
git commit -m "Update"
git commit -m "Fix bug"
git commit -m "Changes"

1538.8 Collaborative Development

Pull Request Workflow: 1. Create feature branch 2. Implement and test changes 3. Push to remote repository 4. Create pull request 5. Code review 6. Merge to develop

Code Review Checklist: - [ ] Code compiles without warnings - [ ] Follows project coding style - [ ] Adequate comments and documentation - [ ] No hardcoded credentials or secrets - [ ] Memory leaks checked - [ ] Power consumption considered - [ ] Tested on target hardware

1538.9 Dependency Management

PlatformIO lib_deps:

[env:esp32dev]
lib_deps =
    # Exact version
    knolleary/PubSubClient@2.8

    # Version range (semver)
    adafruit/Adafruit BME280 Library@^2.2.2

    # Git repository
    https://github.com/me/mylib.git

    # Local library
    lib/custom_sensor

Version Pinning Best Practices:

Approach Syntax Use Case
Exact version @2.8.0 Production builds
Compatible updates @^2.8.0 Accept patches
Any version (no version) Only for prototyping
WarningCommon Pitfall: Library Version Conflicts

Symptom: Code compiles fine, then fails after pio lib update

Cause: Library update introduced breaking change

Prevention: 1. Pin exact versions in production: lib@2.8.0 2. Test updates in separate branch 3. Read library changelogs before updating 4. Use CI/CD to catch breakages early

Recovery:

# Revert to known working versions
pio lib uninstall PubSubClient
pio lib install "PubSubClient@2.8.0"

1538.10 Knowledge Check

Question: A development team maintains IoT firmware across 5 different sensor models. They need to track changes, enable collaboration, and support rollback to previous versions. Which version control strategy is BEST?

Explanation: Git with branching workflow is industry-standard for firmware development. Feature branches isolate work, pull requests enable code review, semantic versioning (v1.2.3) tracks releases, and Git history enables precise rollback. Manual backups lack collaboration features. Cloud storage creates sync conflicts. ZIP archives are unmaintainable at scale.

1538.11 What’s Next

The next section covers Over-the-Air Updates, where you’ll learn to implement secure OTA firmware updates, rollback mechanisms, and update orchestration for deployed IoT devices.