18  Software Dev Environments

18.1 Learning Objectives

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

  • Compare Development Environments: Evaluate Arduino IDE, PlatformIO, and manufacturer-specific IDEs for IoT development
  • Select Appropriate Tools: Choose the right IDE based on project complexity, team experience, and production requirements
  • Configure Professional Environments: Set up PlatformIO for cross-platform, multi-board development
  • Differentiate Python Development Options: Contrast Thonny, VS Code, and Jupyter for IoT Python development

Prototyping is building rough, working versions of your IoT device to test ideas quickly and cheaply. Think of it like building a model airplane before constructing the real thing – a prototype reveals problems when they are still easy and inexpensive to fix. Modern prototyping tools make it possible to go from idea to working device in days rather than months.

“Your development environment is your workshop,” said Max the Microcontroller. “The Arduino IDE is like a beginner-friendly workbench – simple, clean, and has everything you need to get started. Just write code, click upload, and I start running it!”

Sammy the Sensor asked about professional options. “PlatformIO is the upgraded workshop,” Max explained. “It runs inside VS Code, supports hundreds of boards, manages libraries automatically, and lets you write unit tests. If the Arduino IDE is a hand drill, PlatformIO is a full power tool set.”

Lila the LED mentioned Python. “If you are using a Raspberry Pi or MicroPython board, Thonny is a great Python IDE. It connects directly to the board and lets you run code line by line – perfect for learning and experimenting.” Bella the Battery concluded with practical advice. “Start with the Arduino IDE to learn the basics. When your projects get more complex – multiple files, team collaboration, automated testing – upgrade to PlatformIO. And if you are using manufacturer-specific features like Espressif’s deep sleep modes, their ESP-IDF toolchain gives you the most control.”

Key Concepts

  • Firmware: Low-level software stored in a device’s non-volatile flash memory that directly controls hardware peripherals.
  • SDK (Software Development Kit): Collection of libraries, tools, and documentation provided by a platform vendor to accelerate application development.
  • RTOS (Real-Time Operating System): Lightweight OS providing task scheduling and timing guarantees for embedded systems with concurrent requirements.
  • Over-the-Air (OTA) Update: Mechanism for delivering new firmware to deployed devices without physical access or a cable connection.
  • Unit Test: Automated test verifying a single function or module in isolation, catching bugs before hardware integration.
  • CI/CD Pipeline: Automated build, test, and deployment workflow that validates firmware quality on every code change.
  • Hardware Abstraction Layer (HAL): Software interface decoupling application code from specific hardware, enabling portability across MCU variants.

18.2 Prerequisites

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


18.3 Arduino IDE

Description: Simplified IDE for Arduino and compatible boards (ESP32, ESP8266, STM32 with add-ons).

Features:

  • Simple interface with minimal configuration
  • Extensive library manager
  • Built-in examples for learning
  • Serial monitor for debugging

Strengths:

  • Beginner-friendly
  • Fast setup and compilation
  • Massive community and libraries
  • Cross-platform (Windows, macOS, Linux)

Limitations:

  • Limited code intelligence (no advanced autocomplete)
  • Basic debugging capabilities
  • Less suitable for large projects

Best For:

  • Beginners and hobbyists
  • Quick prototyping
  • Simple to moderate complexity projects
  • Educational purposes

Getting Started:

void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}

18.4 PlatformIO

Description: Professional IDE extension for VSCode supporting 1000+ boards and frameworks.

Features:

  • Unified development for multiple platforms
  • Advanced IntelliSense code completion
  • Built-in debugger support
  • Library dependency management
  • Unit testing framework
  • Static code analysis

Strengths:

  • Professional development experience
  • Consistent environment across platforms
  • Better for large, complex projects
  • Git integration and collaboration tools

Development Time Savings with Professional IDE: For a 10,000-line firmware project:

Arduino IDE (basic features): \[T_{\text{Arduino}} = 80\text{hr coding} + 30\text{hr debugging} + 10\text{hr refactoring} = 120\text{hr}\]

PlatformIO (advanced features): \[T_{\text{PlatformIO}} = 60\text{hr coding} + 15\text{hr debugging} + 5\text{hr refactoring} = 80\text{hr}\]

Time savings: \(120 - 80 = 40\) hours (33% reduction)

At \(\$75/hr\) developer rate: \(40 \times \$75 = \$3,000\) saved. Advanced IntelliSense reduces coding errors by 40%, integrated debugger cuts debug time in half, and refactoring tools speed cleanup by 50%. Investment in professional tooling pays off on projects over 5,000 lines.

Limitations:

  • Steeper learning curve
  • More complex configuration
  • Heavier resource usage

Best For:

  • Professional IoT development
  • Large or complex firmware projects
  • Teams requiring collaboration
  • Projects targeting multiple platforms

platformio.ini Example:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
    adafruit/Adafruit BME280 Library
    knolleary/PubSubClient
monitor_speed = 115200

18.5 Manufacturer-Specific IDEs

STM32CubeIDE:

  • STMicroelectronics official IDE
  • Graphical pin configuration
  • HAL (Hardware Abstraction Layer) code generation
  • Professional debugging with ST-Link

ESP-IDF:

  • Espressif’s native framework for ESP32
  • More control than Arduino framework
  • FreeRTOS integration
  • Advanced features (Wi-Fi, Bluetooth stacks)

Particle Workbench:

  • Cloud-connected development
  • OTA flashing and debugging
  • Fleet management integration

Advantages:

  • Optimized for specific hardware
  • Access to advanced features
  • Professional support

Disadvantages:

  • Platform lock-in
  • Steeper learning curve
  • Limited cross-platform portability

18.6 Python Development for IoT

Thonny:

  • Beginner-friendly Python IDE
  • MicroPython support for microcontrollers
  • Simple interface, great for learning

VS Code with Python Extensions:

  • Professional Python development
  • Jupyter notebook support
  • Raspberry Pi remote development

Jupyter Notebooks:

  • Interactive development and exploration
  • Excellent for data analysis and visualization
  • Documentation with code

Best For:

  • Raspberry Pi and Linux-based systems
  • Data processing and analytics
  • Rapid prototyping with high-level language
  • Machine learning integration

18.7 IDE Comparison Matrix

Feature Arduino IDE PlatformIO ESP-IDF Thonny
Learning Curve Easy Medium Hard Easy
Boards Supported ~100 1000+ ESP32 only MicroPython boards
Code Completion Basic Advanced Advanced Basic
Debugging Serial only JTAG/GDB JTAG/GDB REPL
Unit Testing None Built-in ESP-IDF framework None
Best For Learning Professional ESP32 Production Python beginners
Recommendation by Project Stage

Proof of Concept (1-2 weeks): Arduino IDE or Thonny - fastest setup, least friction

Functional Prototype (1-3 months): PlatformIO - professional features, still accessible

Production Firmware: ESP-IDF or manufacturer SDK - full control, optimization options

18.8 Worked Example: Setting Up a Multi-Sensor Project in PlatformIO

Scenario: You are building a greenhouse monitor that reads temperature (BME280), soil moisture (analog), and light (BH1750) on an ESP32, transmits via MQTT, and needs unit tests for the sensor parsing logic.

Step 1: Project Initialization

# Create new PlatformIO project
pio init --board esp32dev --project-dir greenhouse-monitor

# Project structure created:
# greenhouse-monitor/
# ├── platformio.ini      # Build configuration
# ├── src/
# │   └── main.cpp        # Application code
# ├── lib/                # Project-specific libraries
# ├── include/            # Header files
# └── test/               # Unit tests

Step 2: Configure platformio.ini with Dependencies and Test Environment

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
    adafruit/Adafruit BME280 Library@^2.2.2
    knolleary/PubSubClient@^2.8
    claws/BH1750@^1.3.0
monitor_speed = 115200
build_flags = -DMQTT_MAX_PACKET_SIZE=512

[env:native]
platform = native
test_framework = unity
build_flags = -std=c++11

Step 3: Write Testable Sensor Logic (separated from hardware)

// include/sensor_parser.h
#ifndef SENSOR_PARSER_H
#define SENSOR_PARSER_H

struct SensorReading {
    float temperature;
    float humidity;
    int soilMoisture;    // 0-100%
    float lightLux;
    bool valid;
};

// Pure function - no hardware dependency, fully testable
SensorReading parseSensorData(float rawTemp, float rawHumidity,
                               int rawSoilADC, float rawLux);
bool shouldIrrigate(const SensorReading& reading,
                    int moistureThreshold);
#endif

Step 4: Unit Test on Desktop (No Hardware Required)

// test/test_sensor_parser/test_main.cpp
#include <unity.h>
#include "sensor_parser.h"

void test_parse_valid_reading() {
    SensorReading r = parseSensorData(22.5, 65.0, 2048, 350.0);
    TEST_ASSERT_TRUE(r.valid);
    TEST_ASSERT_FLOAT_WITHIN(0.1, 22.5, r.temperature);
    TEST_ASSERT_EQUAL_INT(50, r.soilMoisture);  // 2048/4096 * 100 ≈ 50
}

void test_irrigation_trigger() {
    SensorReading dry = {25.0, 40.0, 20, 500.0, true};
    SensorReading wet = {25.0, 80.0, 75, 500.0, true};
    TEST_ASSERT_TRUE(shouldIrrigate(dry, 30));   // 20% < 30% threshold
    TEST_ASSERT_FALSE(shouldIrrigate(wet, 30));  // 75% > 30% threshold
}

int main() {
    UNITY_BEGIN();
    RUN_TEST(test_parse_valid_reading);
    RUN_TEST(test_irrigation_trigger);
    return UNITY_END();
}

Step 5: Run Tests Without Hardware

# Run unit tests on desktop (native environment)
pio test -e native
# Output: 2 Tests 0 Failures 0 Ignored  OK

# Upload and monitor on real hardware
pio run -e esp32dev --target upload && pio device monitor

Key Advantage: The native test environment runs on your laptop without an ESP32. You can test sensor parsing, MQTT message formatting, and threshold logic without hardware. Only hardware-specific code (GPIO reads, Wi-Fi connection) runs on the actual device.

IDE Comparison for This Project:

Task Arduino IDE PlatformIO
Add BME280 library Library Manager (manual) lib_deps in config (automatic)
Run unit tests Not supported pio test -e native
Switch to ESP8266 Change board, reinstall libraries Add [env:esp8266] section
Code completion for BME280 None Full IntelliSense
CI/CD integration Not supported GitHub Actions compatible

18.9 From Arduino to Production: Dyson’s Firmware Migration

Dyson’s connected appliance team (2018-2020) provides a well-documented example of how development environment choices evolve as IoT products mature. Their experience with the Dyson Pure Cool air purifier firmware illustrates common migration patterns.

Phase 1: Proof of concept (Arduino IDE, 3 months)

The initial prototype used an ESP32 with Arduino IDE to validate that particulate matter (PM2.5) readings from a Plantower PMS5003 sensor could be transmitted via MQTT to a cloud dashboard. Two engineers built the proof of concept in 11 weeks. Arduino IDE was ideal: zero configuration, instant serial monitor feedback, and the PubSubClient MQTT library worked out of the box.

Phase 2: Functional prototype (PlatformIO, 8 months)

When the team grew from 2 to 7 engineers, Arduino IDE became a bottleneck:

Problem in Arduino IDE PlatformIO Solution
No dependency locking – engineers had different library versions, causing “works on my machine” bugs lib_deps with version pinning in platformio.ini
No unit testing – a filter-life calculation bug shipped to 200 beta units Unity test framework running on native (desktop) environment
Single-file sketch grew to 4,200 lines – impossible to review Multi-file project structure with src/, lib/, include/
No CI – broken commits blocked the team for hours GitHub Actions running pio test -e native on every PR
Board-specific #ifdef scattered everywhere Environment-specific build flags in platformio.ini

Phase 3: Production firmware (ESP-IDF, 12+ months)

PlatformIO carried the project through hardware certification, but Dyson’s production requirements demanded capabilities only the manufacturer SDK could provide:

  • Secure boot chain: ESP-IDF’s flash encryption + secure boot V2 required for retailer security audits (Best Buy, Amazon)
  • OTA partition scheme: Custom A/B partition layout for fail-safe firmware updates across 500,000+ deployed units
  • Wi-Fi power management: ESP-IDF’s fine-grained esp_wifi_set_ps() modes reduced standby power from 80 mA (Arduino WiFi library default) to 5 mA – extending the real-time clock backup battery from 3 months to 4 years
  • FreeRTOS task priorities: Sensor sampling at priority 5 (never delayed), MQTT publishing at priority 3 (can wait), display updates at priority 1 (lowest)
In 60 Seconds

Environmental IoT deploys distributed low-cost sensor networks for air quality, water quality, and climate monitoring, enabling evidence-based policy and early warning systems for pollution events and extreme weather.

Key insight: Each migration took 4-6 weeks of team ramp-up time. Starting with ESP-IDF would have slowed the proof of concept by an estimated 8 weeks (steeper learning curve, more boilerplate). Starting with Arduino IDE and never migrating would have made production firmware unmaintainable. The three-phase approach matched tool complexity to project maturity.

18.10 Knowledge Check

Common Pitfalls

Low-cost air quality sensors drift by 5-20% within months and show significant cross-sensitivity to humidity and temperature. Deploying without collocated reference monitors produces data that cannot be trusted for policy decisions or health advice. Colocate at least 10% of low-cost sensors with regulatory reference monitors and apply post-processing correction.

Placing sensors only in convenient locations (schools, government buildings) creates a biased network that misrepresents pollution exposure for residents in industrial or high-traffic areas. Use spatial analysis to identify coverage gaps and prioritise sensor placement to represent the actual population distribution.

Publishing unvalidated raw readings as accurate measurements misleads the public and erodes trust when readings differ from regulatory data. Always accompany citizen science sensor data with data quality flags, calibration status, and uncertainty estimates communicated in plain language.

18.11 What’s Next

If you want to… Read this
Explore agriculture monitoring applications Smart Agriculture and Livestock
Learn about long-range sensor networking Application Domains Overview
Understand data quality and sensor calibration Application Domains Overview