Skip to content

Architecture

Krzysztof Strehlau edited this page Feb 14, 2026 · 2 revisions

Architecture Overview

This section explains the high-level architecture and design principles of ksIotFrameworkLib.


🎯 Design Philosophy

ksIotFrameworkLib is built on three core principles:

1. Composition Over Inheritance

Build applications by composing reusable components rather than creating deep inheritance hierarchies. Each component encapsulates a specific piece of functionality and can be easily combined with others.

2. Separation of Concerns

The framework separates:

  • Hardware interaction from business logic
  • Configuration from runtime behavior
  • Network management from application logic

3. Failover Support

Applications can gracefully fall back to alternative modes (like configuration assistant) when normal operation fails.


πŸ—οΈ High-Level Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Arduino Framework                        β”‚
β”‚            (ESP32/ESP8266 Core + C++ Runtime)               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Application Rotator                       β”‚
β”‚         - Manages application lifecycle                     β”‚
β”‚         - Handles failover between apps                     β”‚
β”‚         - Implements setup() and loop() for Arduino         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β–Ό                               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Main Application    β”‚         β”‚  Config Application  β”‚
β”‚  (Device Logic)      β”‚         β”‚  (Setup Assistant)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              β”‚                               β”‚
              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Component Manager                        β”‚
β”‚              - Component lifecycle management               β”‚
β”‚              - Dependency resolution                        β”‚
β”‚              - State transitions                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
              β–Ό               β–Ό               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ksWifiConnectorβ”‚ β”‚ ksMqttConnector β”‚ β”‚  ksDevicePortal β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                    β”‚                    β”‚
        β–Ό                    β–Ό                    β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Hardware & Network                        β”‚
β”‚           (WiFi, MQTT, WebSockets, Files, GPIO)             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Framework Structure

Directory Organization

ksIotFrameworkLib/
β”œβ”€β”€ src/ksf/
β”‚   β”œβ”€β”€ Core Framework
β”‚   β”‚   β”œβ”€β”€ ksApplication.h/cpp       # Base application class
β”‚   β”‚   β”œβ”€β”€ ksComponent.h/cpp         # Base component class
β”‚   β”‚   β”œβ”€β”€ ksAppRotator.h            # Application rotator
β”‚   β”‚   β”œβ”€β”€ ksRtti.h                  # Custom RTTI system
β”‚   β”‚   └── ksConstants.h/cpp         # Framework constants
β”‚   β”‚
β”‚   β”œβ”€β”€ Components (ksf/comp/)
β”‚   β”‚   β”œβ”€β”€ ksWifiConnector.h/cpp     # WiFi connection management
β”‚   β”‚   β”œβ”€β”€ ksWifiConfigurator.h/cpp  # WiFi provisioning
β”‚   β”‚   β”œβ”€β”€ ksMqttConnector.h/cpp     # MQTT client
β”‚   β”‚   β”œβ”€β”€ ksMqttConfigProvider.h    # MQTT configuration
β”‚   β”‚   β”œβ”€β”€ ksDevicePortal.h/cpp      # Web portal
β”‚   β”‚   β”œβ”€β”€ ksDevStatMqttReporter.h   # Device status
β”‚   β”‚   β”œβ”€β”€ ksLed.h/cpp               # LED control
β”‚   β”‚   β”œβ”€β”€ ksResetButton.h/cpp       # Reset button
β”‚   β”‚   └── ksConfigProvider.h        # Config base class
β”‚   β”‚
β”‚   β”œβ”€β”€ Event System (ksf/evt/)
β”‚   β”‚   β”œβ”€β”€ ksEvent.h                 # Event implementation
β”‚   β”‚   β”œβ”€β”€ ksEventHandle.h           # Event handle management
β”‚   β”‚   └── ksEventInterface.h        # Event interface
β”‚   β”‚
β”‚   β”œβ”€β”€ Utilities (ksf/misc/)
β”‚   β”‚   β”œβ”€β”€ ksConfig.h                # Configuration files
β”‚   β”‚   β”œβ”€β”€ ksSimpleTimer.h           # Timer utility
β”‚   β”‚   β”œβ”€β”€ ksCertUtils.h             # Certificate utilities
β”‚   β”‚   └── ksWSServer.h              # WebSocket server
β”‚   β”‚
β”‚   └── Resources (ksf/res/)
β”‚       └── otaWebpage                # OTA update HTML
β”‚
└── ksIotFrameworkLib.h               # Main include header

πŸ”„ Application Lifecycle

1. Arduino Bootstrap

void setup() {
    // Implemented by ksAppRotator
    // Creates first application
}

void loop() {
    // Implemented by ksAppRotator
    // Manages application switching
}

2. Application Instantiation

// App rotator creates application instance
MyApp* app = new MyApp();

3. Component Initialization

app->init() {
    // Add components
    addComponent<ksWifiConnector>();
    addComponent<ksMqttConnector>();
    // ... more components
}

4. Component Post-Init

app->postInit() {
    // Components can find dependencies
    auto mqtt = findComponent<ksMqttConnector>();
    auto led = findComponent<ksLed>();
}

5. Application Loop

app->loop() {
    // Each component's loop() is called
    for (component : components) {
        component->loop();
    }
}

6. Failover (if needed)

// If any component returns false:
delete app;
app = new ConfigApp(); // Switch to config

🧩 Component Architecture

Component Lifecycle

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Created β”‚  addComponent<T>()
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    Init   β”‚  init() called by app
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ PostInit β”‚  postInit() - find dependencies
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Active  β”‚  loop() called repeatedly
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
      β”‚
      β–Ό false
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ ToRemove β”‚  marked for deletion
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
      β”‚
      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Deleted β”‚  memory freed
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Component Communication

Method 1: Direct Reference (postInit)

bool postInit() {
    auto mqtt = findComponent<ksMqttConnector>();
    if (mqtt) {
        // Use mqtt directly
    }
}

Method 2: Event System

// Publish
event->publish("button_pressed", data);

// Subscribe
event->subscribe("button_pressed", callback);

Method 3: Shared State via Application

// Store shared data in application
app->setData("sensor", value);

// Retrieve from other component
auto value = app->getData("sensor");

πŸ” Application Rotator Pattern

The rotator enables robust multi-application scenarios:

Typical Applications

  1. Main Application

    • Normal device operation
    • Reads sensors, controls actuators
    • Communicates via MQTT
  2. Configuration Application

    • Activates on first boot or error
    • Provides captive portal for setup
    • Saves configuration to storage

Switching Logic

// In main application
bool init() {
    if (!hasWifiCredentials()) {
        return false;  // Trigger switch to config
    }
    return true;
}

Benefits

  • Resilience: Device never gets stuck
  • UX: Easy setup without reflashing
  • Safety: Always recoverable to config mode

🎨 Memory Management

Smart Pointers

Components use smart pointers for automatic memory management:

using ComponentPtr = std::shared_ptr<ksComponent>;

// Automatically cleaned when:
// - Application is destroyed
// - Component is removed

Ownership Rules

  1. Application owns components

    • Components are destroyed with application
  2. Components own their resources

    • Cleanup in destructor or onRemove()
  3. No manual delete needed

    • Framework handles all memory

Best Practices

// βœ… Good - Let framework manage memory
addComponent<ksLed>(LED_PIN);

// ❌ Bad - Manual memory management
ksLed* led = new ksLed(LED_PIN);  // Don't do this

πŸ”€ Threading Model

Single-Threaded Execution

The framework is single-threaded by design:

void loop() {
    for (component : components) {
        component->loop();  // Sequential execution
    }
}

Implications

  • No mutexes needed - Only one thread
  • Predictable timing - Sequential execution
  • Watchdog friendly - Always returns from loop
  • Simpler debugging - No race conditions

Async Operations

For async tasks (network, MQTT):

// Component handles non-blocking I/O
bool loop() {
    mqtt->loop();  // Process available data
    wifi->loop();  // Check connection
    return true;   // Always return quickly
}

πŸ”Œ Extensibility Points

1. Custom Components

class MySensor : public ksComponent {
    KSF_RTTI_DECLARATIONS(MySensor, ksComponent)
    
    bool init() override {
        // Setup sensor
        return true;
    }
    
    bool loop() override {
        // Read sensor
        return true;
    }
};

2. Custom Applications

class MyApp : public ksApplication {
    bool init() override {
        addComponent<MySensor>();
        addComponent<ksMqttConnector>();
        return true;
    }
};

3. Event Handlers

event->subscribe("custom_event", [](auto data) {
    // Handle event
});

4. Configuration Providers

class MyConfigProvider : public ksConfigProvider {
    // Custom storage backend
};

πŸ“Š Performance Characteristics

Memory Footprint

  • Base framework: ~10KB flash
  • Typical app: +20-50KB for components
  • RAM usage: ~30-50KB (varies by components)

CPU Usage

  • Idle: Minimal (main loop overhead)
  • WiFi: Active during connection/data
  • MQTT: Event-driven, low overhead
  • Web portal: Only when accessed

Power Consumption

  • Active: ~100mA (ESP32)
  • Modem sleep: ~20mA (when idle)
  • Deep sleep: ~10Β΅A (application controlled)

🎯 Design Trade-offs

What the Framework Does

βœ… Manages WiFi connections
βœ… Handles MQTT communication
βœ… Provides web interface
βœ… Manages configuration
βœ… Handles OTA updates

What You Provide

  • Application logic - Your specific device behavior
  • Custom components - Specialized functionality
  • Business rules - When/how to act
  • Hardware integration - Sensor/actuator specifics

πŸ“– Next Steps

Now that you understand the architecture:

πŸ“˜ Getting Started

πŸ—οΈ Core Concepts

πŸ“¦ Components Reference

βš™οΈ Configuration & Management

πŸ”¬ Advanced Topics

πŸ’‘ Examples

πŸ”— External Resources

Clone this wiki locally