feat: task manager endpoint, updated documentation

This commit is contained in:
2025-08-22 15:47:08 +02:00
parent d7d307e3ce
commit 30a5f8b8cb
14 changed files with 2550 additions and 551 deletions

444
README.md
View File

@@ -16,420 +16,136 @@ SPORE is a cluster engine for ESP8266 microcontrollers that provides automatic n
## Supported Hardware
- **ESP-01** (1MB Flash)
- **ESP-01S** (1MB Flash)
- **ESP-01 / ESP-01S** (1MB Flash)
- **Wemos D1** (4MB Flash)
- Other ESP8266 boards with 1MB+ flash
## Architecture
### Core Components
The system architecture consists of several key components working together:
SPORE uses a modular architecture with automatic node discovery, health monitoring, and distributed task management.
**Core Components:**
- **Network Manager**: WiFi connection handling and hostname configuration
- **Cluster Manager**: Node discovery, member list management, and health monitoring
- **API Server**: HTTP API server with dynamic endpoint registration
- **Task Scheduler**: Cooperative multitasking system for background operations
- **Node Context**: Central context providing event system and shared resources
### Auto Discovery Protocol
**Key Features:**
- **Auto Discovery**: UDP-based node detection on port 4210
- **Health Monitoring**: Continuous status checking via HTTP API
- **Task Scheduling**: Background tasks at configurable intervals
- **Event System**: Local and cluster-wide event publishing/subscription
The cluster uses a UDP-based discovery protocol for automatic node detection:
1. **Discovery Broadcast**: Nodes periodically send UDP packets on port 4210
2. **Response Handling**: Nodes respond with their hostname and IP address
3. **Member Management**: Discovered nodes are automatically added to the cluster
4. **Health Monitoring**: Continuous status checking via HTTP API calls
### Task Scheduling
The system runs several background tasks at different intervals:
- **Discovery Tasks**: Send/listen for discovery packets (1s/100ms)
- **Status Updates**: Monitor cluster member health (1s)
- **Heartbeat**: Maintain cluster connectivity (2s)
- **Member Info**: Update detailed node information (10s)
- **Debug Output**: Print cluster status (5s)
📖 **Detailed Architecture:** See [`docs/Architecture.md`](./docs/Architecture.md) for comprehensive system design and implementation details.
## API Endpoints
### Node Management
The system provides a comprehensive RESTful API for monitoring and controlling the embedded device.
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/node/status` | GET | Get system resources and API endpoints |
| `/api/node/update` | POST | Upload and install firmware update |
| `/api/node/restart` | POST | Restart the node |
**Core Endpoints:**
- **`/api/node/status`** - System resources and API endpoint registry
- **`/api/cluster/members`** - Cluster membership and health status
- **`/api/node/update`** - OTA firmware updates
- **`/api/node/restart`** - System restart
- **`/api/tasks/status`** - Task management and monitoring
- **`/api/tasks/control`** - Task control operations
### Cluster Management
**Response Format:** All endpoints return JSON with standardized error handling and HTTP status codes.
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/cluster/members` | GET | Get cluster membership and status |
### Node Status Response
```json
{
"freeHeap": 12345,
"chipId": 12345678,
"sdkVersion": "2.2.2-dev(38a443e)",
"cpuFreqMHz": 80,
"flashChipSize": 1048576,
"api": [
{
"uri": "/api/node/status",
"method": "GET"
}
]
}
```
### Cluster Members Response
```json
{
"members": [
{
"hostname": "esp_123456",
"ip": "192.168.1.100",
"lastSeen": 1234567890,
"latency": 5,
"status": "active",
"resources": {
"freeHeap": 12345,
"chipId": 12345678,
"sdkVersion": "2.2.2-dev(38a443e)",
"cpuFreqMHz": 80,
"flashChipSize": 1048576
},
"api": [
{
"uri": "/api/node/status",
"method": "GET"
}
]
}
]
}
```
📖 **Complete API Reference:** See [`docs/API.md`](./docs/API.md) for detailed endpoint documentation, examples, and integration guides.
## Configuration
### Environment Setup
Create a `.env` file in your project root:
```bash
# API node IP for cluster management
export API_NODE=192.168.1.100
```
### PlatformIO Configuration
The project uses PlatformIO with the following configuration:
The project uses PlatformIO with Arduino framework and supports multiple ESP8266 boards.
**Key Settings:**
- **Framework**: Arduino
- **Board**: ESP-01 with 1MB flash
- **Board**: ESP-01 with 1MB flash (default)
- **Upload Speed**: 115200 baud
- **Flash Mode**: DOUT (required for ESP-01S)
### Dependencies
**Dependencies:**
- ESPAsyncWebServer, ArduinoJson, TaskScheduler
- ESP8266WiFi and HTTPClient libraries
The project requires the following libraries:
- `esp32async/ESPAsyncWebServer@^3.8.0` - HTTP API server
- `bblanchon/ArduinoJson@^7.4.2` - JSON processing
- `arkhipenko/TaskScheduler@^3.8.5` - Cooperative multitasking
**Environment Setup:** Create `.env` file for cluster configuration and API node settings.
📖 **Development Guide:** See [`docs/Development.md`](./docs/Development.md) for comprehensive build, deployment, and configuration instructions.
## Development
### Prerequisites
- PlatformIO Core or PlatformIO IDE
- ESP8266 development tools
- `jq` for JSON processing in scripts
### Building
Build the firmware for specific chip:
**Quick Commands:**
```bash
# Build firmware
./ctl.sh build target esp01_1m
```
### Flashing
Flash firmware to a connected device:
```bash
# Flash device
./ctl.sh flash target esp01_1m
```
### Over-The-Air Updates
Update a specific node:
```bash
# OTA update
./ctl.sh ota update 192.168.1.100 esp01_1m
```
Update all nodes in the cluster:
```bash
./ctl.sh ota all esp01_1m
```
### Cluster Management
View cluster members:
```bash
# Cluster management
./ctl.sh cluster members
```
**Prerequisites:** PlatformIO Core, ESP8266 tools, `jq` for JSON processing
📖 **Complete Development Guide:** See [`docs/Development.md`](./docs/Development.md) for detailed build, deployment, and troubleshooting instructions.
## API Reference
The SPORE system provides a comprehensive RESTful API for monitoring and controlling the embedded device. All endpoints return JSON responses and support standard HTTP status codes.
### Quick Reference
| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/tasks/status` | GET | Get comprehensive task status |
| `/api/tasks/control` | POST | Control individual tasks |
| `/api/node/status` | GET | System resource information |
| `/api/cluster/members` | GET | Cluster membership |
| `/api/node/update` | POST | OTA firmware updates |
| `/api/node/restart` | POST | System restart |
**Available Task Actions:** `enable`, `disable`, `start`, `stop`, `status`
📖 **Detailed API Documentation:** See [`docs/API.md`](./docs/API.md) for complete API reference, examples, and integration guides.
🔧 **OpenAPI Specification:** Machine-readable API spec available in [`api/`](./api/) folder for code generation and tooling integration.
## Implementation Details
### Event System
The system uses an event-driven architecture with automatic resource monitoring and WiFi fallback capabilities.
The `NodeContext` provides an event-driven architecture:
**Key Systems:**
- **Event System**: Local and cluster-wide event publishing/subscription
- **Status Tracking**: Automatic node categorization (ACTIVE, INACTIVE, DEAD)
- **Resource Monitoring**: Memory, CPU, flash, and API endpoint tracking
- **WiFi Fallback**: Automatic access point creation if connection fails
```cpp
// Subscribe to events
ctx.on("node_discovered", [](void* data) {
NodeInfo* node = static_cast<NodeInfo*>(data);
// Handle new node discovery
});
// Publish events
ctx.fire("node_discovered", &newNode);
```
### Node Status Tracking
Nodes are automatically categorized by their activity:
- **ACTIVE**: Responding within 10 seconds
- **INACTIVE**: No response for 10-60 seconds
- **DEAD**: No response for over 60 seconds
### Resource Monitoring
Each node tracks:
- Free heap memory
- Chip ID and SDK version
- CPU frequency
- Flash chip size
- API endpoint registry
### WiFi Fallback
The system includes automatic WiFi fallback:
1. Attempts to connect to configured WiFi network
2. If connection fails, creates an access point
3. Hostname is automatically generated from MAC address
📖 **Architecture Details:** See [`docs/Architecture.md`](./docs/Architecture.md) for comprehensive system design and implementation information.
## Task Management
The SPORE system includes a comprehensive TaskManager that provides a clean interface for managing system tasks. This makes it easy to add, configure, and control background tasks without cluttering the main application code.
The SPORE system includes a comprehensive TaskManager for background task management with runtime control and monitoring.
### TaskManager Features
**Key Features:**
- **Easy Registration**: Simple API for adding tasks with configurable intervals
- **Dynamic Control**: Enable/disable tasks at runtime without restart
- **Status Monitoring**: Real-time task health and performance tracking
- **Remote Management**: REST API for cluster-wide task control
- **Easy Task Registration**: Simple API for adding new tasks with configurable intervals
- **Dynamic Control**: Enable/disable tasks at runtime
- **Interval Management**: Change task execution frequency on the fly
- **Status Monitoring**: View task status and configuration
- **Automatic Lifecycle**: Tasks are automatically managed and executed
### Basic Usage
```cpp
#include "TaskManager.h"
// Create task manager
TaskManager taskManager(ctx);
// Register tasks
taskManager.registerTask("heartbeat", 2000, heartbeatFunction);
taskManager.registerTask("maintenance", 30000, maintenanceFunction);
// Initialize and start all tasks
taskManager.initialize();
```
#### Using std::bind with Member Functions
```cpp
#include <functional>
#include "TaskManager.h"
class MyService {
public:
void sendHeartbeat() {
Serial.println("Service heartbeat");
}
void performMaintenance() {
Serial.println("Running maintenance");
}
};
MyService service;
TaskManager taskManager(ctx);
// Register member functions using std::bind
taskManager.registerTask("heartbeat", 2000,
std::bind(&MyService::sendHeartbeat, &service));
taskManager.registerTask("maintenance", 30000,
std::bind(&MyService::performMaintenance, &service));
// Initialize and start all tasks
taskManager.initialize();
```
#### Using Lambda Functions
```cpp
// Register lambda functions directly
taskManager.registerTask("counter", 1000, []() {
static int count = 0;
Serial.printf("Count: %d\n", ++count);
});
// Lambda with capture
int threshold = 100;
taskManager.registerTask("monitor", 5000, [&threshold]() {
if (ESP.getFreeHeap() < threshold) {
Serial.println("Low memory warning!");
}
});
```
#### Complex Task Registration
```cpp
class NetworkManager {
public:
void checkConnection() { /* ... */ }
void sendData(String data) { /* ... */ }
};
NetworkManager network;
// Multiple operations in one task
taskManager.registerTask("network_ops", 3000,
std::bind([](NetworkManager* net) {
net->checkConnection();
net->sendData("status_update");
}, &network));
```
### Task Control API
```cpp
// Enable/disable tasks
taskManager.enableTask("heartbeat");
taskManager.disableTask("maintenance");
// Change intervals
taskManager.setTaskInterval("heartbeat", 5000); // 5 seconds
// Check status
bool isRunning = taskManager.isTaskEnabled("heartbeat");
unsigned long interval = taskManager.getTaskInterval("heartbeat");
// Print all task statuses
taskManager.printTaskStatus();
```
### Remote Task Management
The TaskManager integrates with the API server to provide remote task control:
```bash
# Get task status
curl http://192.168.1.100/api/tasks/status
# Control tasks
curl -X POST http://192.168.1.100/api/tasks/control \
-d "task=heartbeat&action=disable"
# Available actions: enable, disable, start, stop
```
### Adding Custom Tasks
#### Method 1: Using std::bind (Recommended)
1. **Create your service class**:
```cpp
class SensorService {
public:
void readTemperature() {
// Read sensor logic
Serial.println("Reading temperature");
}
void calibrateSensors() {
// Calibration logic
Serial.println("Calibrating sensors");
}
};
```
2. **Register with TaskManager**:
```cpp
SensorService sensors;
taskManager.registerTask("temp_read", 1000,
std::bind(&SensorService::readTemperature, &sensors));
taskManager.registerTask("calibrate", 60000,
std::bind(&SensorService::calibrateSensors, &sensors));
```
#### Method 2: Traditional Functions
1. **Define your task function**:
```cpp
void myCustomTask() {
// Your task logic here
Serial.println("Custom task executed");
}
```
2. **Register with TaskManager**:
```cpp
taskManager.registerTask("my_task", 10000, myCustomTask);
```
### Task Configuration Options
When registering tasks, you can specify:
- **Name**: Unique identifier for the task
- **Interval**: Execution frequency in milliseconds
- **Callback**: Function, bound method, or lambda to execute
- **Enabled**: Whether the task starts enabled (default: true)
- **AutoStart**: Whether to start automatically (default: true)
```cpp
// Traditional function
taskManager.registerTask("delayed_task", 5000, taskFunction, true, false);
// Member function with std::bind
taskManager.registerTask("service_task", 3000,
std::bind(&Service::method, &instance), true, false);
// Lambda function
taskManager.registerTask("lambda_task", 2000,
[]() { Serial.println("Lambda!"); }, true, false);
```
📖 **Complete Task Management Guide:** See [`docs/TaskManagement.md`](./docs/TaskManagement.md) for detailed usage examples, best practices, and advanced features.
## Current Limitations
- WiFi credentials are hardcoded in `Config.cpp` (should be configurable)
- Limited error handling for network failures
- No persistent storage for configuration
- Basic health monitoring without advanced metrics
- Task monitoring and system health metrics
- Task execution history and performance analytics not yet implemented
## Troubleshooting
@@ -448,6 +164,16 @@ Enable serial monitoring to see cluster activity:
pio device monitor
```
📖 **For detailed task management examples and workflows, see [`docs/API.md`](./docs/API.md).**
## Documentation
📚 **Comprehensive documentation is available in the [`docs/`](./docs/) folder:**
- **[API Reference](./docs/API.md)** - Complete API documentation with examples
- **[TaskManager Guide](./docs/TaskManager.md)** - Background task management system
- **[OpenAPI Spec](./api/)** - Machine-readable API specification
## Contributing
1. Fork the repository

201
api/README.md Normal file
View File

@@ -0,0 +1,201 @@
# SPORE API Documentation
This folder contains the OpenAPI specification for the SPORE embedded system API.
## Files
- **`openapi.yaml`** - OpenAPI 3.0 specification file
- **`README.md`** - This documentation file
## OpenAPI Specification
The `openapi.yaml` file provides a complete, machine-readable specification of the SPORE API. It can be used with various tools to:
- Generate client libraries in multiple programming languages
- Create interactive API documentation
- Validate API requests and responses
- Generate mock servers for testing
- Integrate with API management platforms
## Using the OpenAPI Specification
### 1. View Interactive Documentation
#### Option A: Swagger UI Online
1. Go to [Swagger Editor](https://editor.swagger.io/)
2. Copy and paste the contents of `openapi.yaml`
3. View the interactive documentation
#### Option B: Local Swagger UI
```bash
# Install Swagger UI locally
npm install -g swagger-ui-express
# Or use Docker
docker run -p 8080:8080 -e SWAGGER_JSON=/openapi.yaml -v $(pwd):/swagger swaggerapi/swagger-ui
```
### 2. Generate Client Libraries
#### Using OpenAPI Generator
```bash
# Install OpenAPI Generator
npm install @openapitools/openapi-generator-cli -g
# Generate Python client
openapi-generator generate -i openapi.yaml -g python -o python-client
# Generate JavaScript client
openapi-generator generate -i openapi.yaml -g javascript -o js-client
# Generate C# client
openapi-generator generate -i openapi.yaml -g csharp -o csharp-client
```
#### Using Swagger Codegen
```bash
# Install Swagger Codegen
npm install -g swagger-codegen
# Generate Python client
swagger-codegen generate -i openapi.yaml -l python -o python-client
# Generate Java client
swagger-codegen generate -i openapi.yaml -l java -o java-client
```
### 3. Validate API Responses
#### Using OpenAPI Validator
```bash
# Install OpenAPI validator
npm install -g @apidevtools/swagger-parser
# Validate the specification
swagger-parser validate openapi.yaml
```
### 4. Generate Mock Server
#### Using Prism (Stoplight)
```bash
# Install Prism
npm install -g @stoplight/prism-cli
# Start mock server
prism mock openapi.yaml
# The mock server will be available at http://localhost:4010
```
## API Endpoints Overview
The SPORE API provides the following main categories of endpoints:
### Task Management
- **`GET /api/tasks/status`** - Get comprehensive task status
- **`POST /api/tasks/control`** - Control individual tasks
### System Status
- **`GET /api/node/status`** - Get system resource information
- **`GET /api/cluster/members`** - Get cluster membership
### System Management
- **`POST /api/node/update`** - Handle OTA firmware updates
- **`POST /api/node/restart`** - Trigger system restart
## Data Models
The OpenAPI specification includes comprehensive schemas for:
- **Task Information**: Task status, configuration, and execution details
- **System Resources**: Memory usage, chip information, and performance metrics
- **Cluster Management**: Node health, network topology, and resource sharing
- **API Responses**: Standardized response formats and error handling
## Examples
### Basic Task Status Check
```bash
curl -s http://192.168.1.100/api/tasks/status | jq '.'
```
### Task Control
```bash
# Disable a task
curl -X POST http://192.168.1.100/api/tasks/control \
-d "task=heartbeat&action=disable"
# Get detailed status
curl -X POST http://192.168.1.100/api/tasks/control \
-d "task=discovery_send&action=status"
```
### System Monitoring
```bash
# Check system resources
curl -s http://192.168.1.100/api/node/status | jq '.freeHeap'
# Monitor cluster health
curl -s http://192.168.1.100/api/cluster/members | jq '.members[].status'
```
## Integration Examples
### Python Client
```python
import requests
# Get task status
response = requests.get('http://192.168.1.100/api/tasks/status')
tasks = response.json()
# Check active tasks
active_count = tasks['summary']['activeTasks']
print(f"Active tasks: {active_count}")
# Control a task
control_data = {'task': 'heartbeat', 'action': 'disable'}
response = requests.post('http://192.168.1.100/api/tasks/control', data=control_data)
```
### JavaScript Client
```javascript
// Get task status
fetch('http://192.168.1.100/api/tasks/status')
.then(response => response.json())
.then(data => {
console.log(`Total tasks: ${data.summary.totalTasks}`);
console.log(`Active tasks: ${data.summary.activeTasks}`);
});
// Control a task
fetch('http://192.168.1.100/api/tasks/control', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'task=heartbeat&action=disable'
});
```
## Contributing
When adding new API endpoints or modifying existing ones:
1. Update the `openapi.yaml` file
2. Add appropriate schemas for new data models
3. Include example responses
4. Update this README if needed
5. Test the specification with validation tools
## Tools and Resources
- [OpenAPI Specification](https://swagger.io/specification/)
- [OpenAPI Generator](https://openapi-generator.tech/)
- [Swagger Codegen](https://github.com/swagger-api/swagger-codegen)
- [Swagger UI](https://swagger.io/tools/swagger-ui/)
- [Prism Mock Server](https://stoplight.io/open-source/prism/)
- [OpenAPI Validator](https://apitools.dev/swagger-parser/)
## License
This API specification is part of the SPORE project and follows the same license terms.

673
api/openapi.yaml Normal file
View File

@@ -0,0 +1,673 @@
openapi: 3.0.3
info:
title: SPORE Embedded System API
description: |
RESTful API for monitoring and controlling the SPORE embedded system.
The SPORE system provides comprehensive task management, system monitoring,
and cluster management capabilities for ESP8266-based embedded devices.
## Features
- **Task Management**: Monitor and control background tasks
- **System Monitoring**: Real-time system resource tracking
- **Cluster Management**: Multi-node cluster coordination
- **OTA Updates**: Over-the-air firmware updates
- **Health Monitoring**: System and task health metrics
## Authentication
Currently, no authentication is required. All endpoints are accessible
from the local network.
## Rate Limiting
No rate limiting is currently implemented. Use responsibly.
## Base URL
The API is accessible at `http://{device-ip}/` where `{device-ip}` is
the IP address of your SPORE device on the local network.
version: 1.0.0
contact:
name: SPORE Development Team
url: https://git.dcentral.systems/iot/spore
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: http://{device-ip}
description: Local SPORE device
variables:
device-ip:
description: IP address of your SPORE device
default: "10.0.1.60"
paths:
/api/tasks/status:
get:
summary: Get comprehensive task status
description: |
Returns detailed status information for all registered tasks,
including system resource metrics and task execution details.
This endpoint provides a complete overview of the system's
task management status and can be used for monitoring and
debugging purposes.
tags:
- Task Management
responses:
'200':
description: Task status retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/TaskStatusResponse'
examples:
default:
summary: Default response
value:
summary:
totalTasks: 6
activeTasks: 5
tasks:
- name: "discovery_send"
interval: 1000
enabled: true
running: true
autoStart: true
- name: "heartbeat"
interval: 2000
enabled: true
running: true
autoStart: true
- name: "status_update"
interval: 1000
enabled: true
running: true
autoStart: true
system:
freeHeap: 48748
uptime: 12345
'500':
description: Internal server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/tasks/control:
post:
summary: Control individual task operations
description: |
Controls the execution state of individual tasks. Supports
enabling, disabling, starting, stopping, and getting detailed
status for specific tasks.
This endpoint is useful for dynamic task management without
requiring system restarts.
tags:
- Task Management
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
required:
- task
- action
properties:
task:
type: string
description: Name of the task to control
example: "heartbeat"
action:
type: string
description: Action to perform on the task
enum: [enable, disable, start, stop, status]
example: "disable"
responses:
'200':
description: Task operation completed successfully
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/TaskControlResponse'
- $ref: '#/components/schemas/TaskStatusDetailResponse'
examples:
enable:
summary: Task enabled
value:
success: true
message: "Task enabled"
task: "heartbeat"
action: "enable"
status:
summary: Task status retrieved
value:
success: true
message: "Task status retrieved"
task: "discovery_send"
action: "status"
taskDetails:
name: "discovery_send"
enabled: true
running: true
interval: 1000
system:
freeHeap: 48748
uptime: 12345
'400':
description: Bad request - invalid parameters or action
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
examples:
missing_params:
summary: Missing required parameters
value:
success: false
message: "Missing parameters. Required: task, action"
example: "{\"task\": \"discovery_send\", \"action\": \"status\"}"
invalid_action:
summary: Invalid action specified
value:
success: false
message: "Invalid action. Use: enable, disable, start, stop, or status"
task: "heartbeat"
action: "invalid_action"
/api/node/status:
get:
summary: Get system status and API information
description: |
Returns comprehensive system resource information including
memory usage, chip details, and a registry of all available
API endpoints.
tags:
- System Status
responses:
'200':
description: System status retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/SystemStatusResponse'
examples:
default:
summary: Default response
value:
freeHeap: 48748
chipId: 12345678
sdkVersion: "3.1.2"
cpuFreqMHz: 80
flashChipSize: 1048576
api:
- uri: "/api/node/status"
method: 1
- uri: "/api/tasks/status"
method: 1
- uri: "/api/tasks/control"
method: 3
/api/cluster/members:
get:
summary: Get cluster membership information
description: |
Returns information about all nodes in the cluster,
including their health status, resources, and API endpoints.
tags:
- Cluster Management
responses:
'200':
description: Cluster information retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ClusterMembersResponse'
examples:
default:
summary: Default response
value:
members:
- hostname: "spore-node-1"
ip: "192.168.1.100"
lastSeen: 1234567890
latency: 5
status: "ACTIVE"
resources:
freeHeap: 48748
chipId: 12345678
sdkVersion: "3.1.2"
cpuFreqMHz: 80
flashChipSize: 1048576
api:
- uri: "/api/node/status"
method: "GET"
- uri: "/api/tasks/status"
method: "GET"
/api/node/update:
post:
summary: Handle firmware update via OTA
description: |
Initiates an over-the-air firmware update. The firmware
file should be uploaded as multipart/form-data.
tags:
- System Management
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
firmware:
type: string
format: binary
description: Firmware binary file (.bin)
responses:
'200':
description: Firmware update initiated successfully
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateResponse'
examples:
default:
summary: Update initiated
value:
status: "updating"
message: "Firmware update in progress"
'400':
description: Invalid firmware file or update failed
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/node/restart:
post:
summary: Restart the system
description: |
Triggers a system restart. The response will be sent
before the restart occurs.
tags:
- System Management
responses:
'200':
description: System restart initiated
content:
application/json:
schema:
$ref: '#/components/schemas/RestartResponse'
examples:
default:
summary: Restart initiated
value:
status: "restarting"
components:
schemas:
TaskStatusResponse:
type: object
required:
- summary
- tasks
- system
properties:
summary:
$ref: '#/components/schemas/TaskSummary'
tasks:
type: array
items:
$ref: '#/components/schemas/TaskInfo'
system:
$ref: '#/components/schemas/SystemInfo'
TaskSummary:
type: object
required:
- totalTasks
- activeTasks
properties:
totalTasks:
type: integer
minimum: 0
description: Total number of registered tasks
example: 6
activeTasks:
type: integer
minimum: 0
description: Number of currently enabled tasks
example: 5
TaskInfo:
type: object
required:
- name
- interval
- enabled
- running
- autoStart
properties:
name:
type: string
description: Unique task identifier
example: "discovery_send"
interval:
type: integer
minimum: 1
description: Execution frequency in milliseconds
example: 1000
enabled:
type: boolean
description: Whether task is currently enabled
example: true
running:
type: boolean
description: Whether task is actively executing
example: true
autoStart:
type: boolean
description: Whether task starts automatically
example: true
SystemInfo:
type: object
required:
- freeHeap
- uptime
properties:
freeHeap:
type: integer
minimum: 0
description: Available RAM in bytes
example: 48748
uptime:
type: integer
minimum: 0
description: System uptime in milliseconds
example: 12345
TaskControlResponse:
type: object
required:
- success
- message
- task
- action
properties:
success:
type: boolean
description: Whether the operation was successful
example: true
message:
type: string
description: Human-readable operation result
example: "Task enabled"
task:
type: string
description: Name of the task that was operated on
example: "heartbeat"
action:
type: string
description: Action that was performed
example: "enable"
TaskStatusDetailResponse:
allOf:
- $ref: '#/components/schemas/TaskControlResponse'
- type: object
required:
- taskDetails
properties:
taskDetails:
$ref: '#/components/schemas/TaskDetailInfo'
TaskDetailInfo:
type: object
required:
- name
- enabled
- running
- interval
- system
properties:
name:
type: string
description: Task name
example: "discovery_send"
enabled:
type: boolean
description: Whether task is enabled
example: true
running:
type: boolean
description: Whether task is running
example: true
interval:
type: integer
description: Task execution interval
example: 1000
system:
$ref: '#/components/schemas/SystemInfo'
SystemStatusResponse:
type: object
required:
- freeHeap
- chipId
- sdkVersion
- cpuFreqMHz
- flashChipSize
- api
properties:
freeHeap:
type: integer
description: Available RAM in bytes
example: 48748
chipId:
type: integer
description: ESP8266 chip ID
example: 12345678
sdkVersion:
type: string
description: ESP8266 SDK version
example: "3.1.2"
cpuFreqMHz:
type: integer
description: CPU frequency in MHz
example: 80
flashChipSize:
type: integer
description: Flash chip size in bytes
example: 1048576
api:
type: array
items:
$ref: '#/components/schemas/ApiEndpoint'
ApiEndpoint:
type: object
required:
- uri
- method
properties:
uri:
type: string
description: API endpoint URI
example: "/api/node/status"
method:
type: integer
description: HTTP method (1=GET, 3=POST)
example: 1
ClusterMembersResponse:
type: object
required:
- members
properties:
members:
type: array
items:
$ref: '#/components/schemas/ClusterNode'
ClusterNode:
type: object
required:
- hostname
- ip
- lastSeen
- latency
- status
- resources
- api
properties:
hostname:
type: string
description: Node hostname
example: "spore-node-1"
ip:
type: string
format: ipv4
description: Node IP address
example: "192.168.1.100"
lastSeen:
type: integer
description: Timestamp of last communication
example: 1234567890
latency:
type: integer
description: Network latency in milliseconds
example: 5
status:
type: string
enum: [ACTIVE, INACTIVE, DEAD]
description: Node health status
example: "ACTIVE"
resources:
$ref: '#/components/schemas/SystemResources'
api:
type: array
items:
$ref: '#/components/schemas/ApiEndpoint'
SystemResources:
type: object
required:
- freeHeap
- chipId
- sdkVersion
- cpuFreqMHz
- flashChipSize
properties:
freeHeap:
type: integer
description: Available RAM in bytes
example: 48748
chipId:
type: integer
description: ESP8266 chip ID
example: 12345678
sdkVersion:
type: string
description: ESP8266 SDK version
example: "3.1.2"
cpuFreqMHz:
type: integer
description: CPU frequency in MHz
example: 80
flashChipSize:
type: integer
description: Flash chip size in bytes
example: 1048576
UpdateResponse:
type: object
required:
- status
properties:
status:
type: string
enum: [updating, failed]
description: Update operation status
example: "updating"
message:
type: string
description: Additional status information
example: "Firmware update in progress"
RestartResponse:
type: object
required:
- status
properties:
status:
type: string
enum: [restarting]
description: Restart operation status
example: "restarting"
ErrorResponse:
type: object
required:
- success
- message
properties:
success:
type: boolean
description: Always false for error responses
example: false
message:
type: string
description: Error description
example: "Missing parameters. Required: task, action"
example:
type: string
description: Example of correct usage
example: "{\"task\": \"discovery_send\", \"action\": \"status\"}"
task:
type: string
description: Task name (if applicable)
example: "heartbeat"
action:
type: string
description: Action attempted (if applicable)
example: "invalid_action"
securitySchemes:
# Currently no authentication required
# This section can be expanded when authentication is implemented
tags:
- name: Task Management
description: Operations for monitoring and controlling background tasks
- name: System Status
description: System resource monitoring and API information
- name: Cluster Management
description: Multi-node cluster coordination and health monitoring
- name: System Management
description: System-level operations like updates and restarts
externalDocs:
description: SPORE Project Documentation
url: https://github.com/your-org/spore

279
docs/API.md Normal file
View File

@@ -0,0 +1,279 @@
# SPORE API Documentation
The SPORE system provides a comprehensive RESTful API for monitoring and controlling the embedded device. All endpoints return JSON responses and support standard HTTP status codes.
## Quick Reference
### Task Management API
| Endpoint | Method | Description | Parameters | Response |
|----------|--------|-------------|------------|----------|
| `/api/tasks/status` | GET | Get comprehensive status of all tasks and system information | None | Task status overview with system metrics |
| `/api/tasks/control` | POST | Control individual task operations | `task`, `action` | Operation result with task details |
### System Status API
| Endpoint | Method | Description | Response |
|----------|--------|-------------|----------|
| `/api/node/status` | GET | System resource information and API endpoint registry | System metrics and API catalog |
| `/api/cluster/members` | GET | Cluster membership and node health information | Cluster topology and health status |
| `/api/node/update` | POST | Handle firmware updates via OTA | Update progress and status |
| `/api/node/restart` | POST | Trigger system restart | Restart confirmation |
## Detailed API Reference
### Task Management
#### GET /api/tasks/status
Returns comprehensive status information for all registered tasks, including system resource metrics and task execution details.
**Response Fields:**
| Field | Type | Description |
|-------|------|-------------|
| `summary.totalTasks` | integer | Total number of registered tasks |
| `summary.activeTasks` | integer | Number of currently enabled tasks |
| `tasks[].name` | string | Unique task identifier |
| `tasks[].interval` | integer | Execution frequency in milliseconds |
| `tasks[].enabled` | boolean | Whether task is currently enabled |
| `tasks[].running` | boolean | Whether task is actively executing |
| `tasks[].autoStart` | boolean | Whether task starts automatically |
| `system.freeHeap` | integer | Available RAM in bytes |
| `system.uptime` | integer | System uptime in milliseconds |
**Example Response:**
```json
{
"summary": {
"totalTasks": 6,
"activeTasks": 5
},
"tasks": [
{
"name": "discovery_send",
"interval": 1000,
"enabled": true,
"running": true,
"autoStart": true
}
],
"system": {
"freeHeap": 48748,
"uptime": 12345
}
}
```
#### POST /api/tasks/control
Controls the execution state of individual tasks. Supports enabling, disabling, starting, stopping, and getting detailed status for specific tasks.
**Parameters:**
- `task` (required): Name of the task to control
- `action` (required): Action to perform
**Available Actions:**
| Action | Description | Use Case |
|--------|-------------|----------|
| `enable` | Enable a disabled task | Resume background operations |
| `disable` | Disable a running task | Pause resource-intensive tasks |
| `start` | Start a stopped task | Begin task execution |
| `stop` | Stop a running task | Halt task execution |
| `status` | Get detailed status for a specific task | Monitor individual task health |
**Example Response:**
```json
{
"success": true,
"message": "Task enabled",
"task": "heartbeat",
"action": "enable"
}
```
**Task Status Response:**
```json
{
"success": true,
"message": "Task status retrieved",
"task": "discovery_send",
"action": "status",
"taskDetails": {
"name": "discovery_send",
"enabled": true,
"running": true,
"interval": 1000,
"system": {
"freeHeap": 48748,
"uptime": 12345
}
}
}
```
### System Status
#### GET /api/node/status
Returns comprehensive system resource information including memory usage, chip details, and a registry of all available API endpoints.
**Response Fields:**
- `freeHeap`: Available RAM in bytes
- `chipId`: ESP8266 chip ID
- `sdkVersion`: ESP8266 SDK version
- `cpuFreqMHz`: CPU frequency in MHz
- `flashChipSize`: Flash chip size in bytes
- `api`: Array of registered API endpoints
#### GET /api/cluster/members
Returns information about all nodes in the cluster, including their health status, resources, and API endpoints.
**Response Fields:**
- `members[]`: Array of cluster node information
- `hostname`: Node hostname
- `ip`: Node IP address
- `lastSeen`: Timestamp of last communication
- `latency`: Network latency in milliseconds
- `status`: Node health status (ACTIVE, INACTIVE, DEAD)
- `resources`: System resource information
- `api`: Available API endpoints
### System Management
#### POST /api/node/update
Initiates an over-the-air firmware update. The firmware file should be uploaded as multipart/form-data.
**Parameters:**
- `firmware`: Firmware binary file (.bin)
#### POST /api/node/restart
Triggers a system restart. The response will be sent before the restart occurs.
## HTTP Status Codes
| Code | Description | Use Case |
|------|-------------|----------|
| 200 | Success | Operation completed successfully |
| 400 | Bad Request | Invalid parameters or action |
| 404 | Not Found | Task or endpoint not found |
| 500 | Internal Server Error | System error occurred |
## OpenAPI Specification
A complete OpenAPI 3.0 specification is available in the [`api/`](../api/) folder. This specification can be used to:
- Generate client libraries in multiple programming languages
- Create interactive API documentation
- Validate API requests and responses
- Generate mock servers for testing
- Integrate with API management platforms
See [`api/README.md`](../api/README.md) for detailed usage instructions.
## Usage Examples
### Basic Task Status Check
```bash
curl -s http://10.0.1.60/api/tasks/status | jq '.'
```
### Task Control
```bash
# Disable a task
curl -X POST http://10.0.1.60/api/tasks/control \
-d "task=heartbeat&action=disable"
# Get detailed status
curl -X POST http://10.0.1.60/api/tasks/control \
-d "task=discovery_send&action=status"
```
### System Monitoring
```bash
# Check system resources
curl -s http://10.0.1.60/api/node/status | jq '.freeHeap'
# Monitor cluster health
curl -s http://10.0.1.60/api/cluster/members | jq '.members[].status'
```
## Integration Examples
### Python Client
```python
import requests
# Get task status
response = requests.get('http://10.0.1.60/api/tasks/status')
tasks = response.json()
# Check active tasks
active_count = tasks['summary']['activeTasks']
print(f"Active tasks: {active_count}")
# Control a task
control_data = {'task': 'heartbeat', 'action': 'disable'}
response = requests.post('http://10.0.1.60/api/tasks/control', data=control_data)
```
### JavaScript Client
```javascript
// Get task status
fetch('http://10.0.1.60/api/tasks/status')
.then(response => response.json())
.then(data => {
console.log(`Total tasks: ${data.summary.totalTasks}`);
console.log(`Active tasks: ${data.summary.activeTasks}`);
});
// Control a task
fetch('http://10.0.1.60/api/tasks/control', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'task=heartbeat&action=disable'
});
```
## Task Management Examples
### Monitoring Task Health
```bash
# Check overall task status
curl -s http://10.0.1.60/api/tasks/status | jq '.'
# Monitor specific task
curl -s -X POST http://10.0.1.60/api/tasks/control \
-d "task=heartbeat&action=status" | jq '.'
# Watch for low memory conditions
watch -n 5 'curl -s http://10.0.1.60/api/tasks/status | jq ".system.freeHeap"'
```
### Task Control Workflows
```bash
# Temporarily disable discovery to reduce network traffic
curl -X POST http://10.0.1.60/api/tasks/control \
-d "task=discovery_send&action=disable"
# Check if it's disabled
curl -s -X POST http://10.0.1.60/api/tasks/control \
-d "task=discovery_send&action=status" | jq '.taskDetails.enabled'
# Re-enable when needed
curl -X POST http://10.0.1.60/api/tasks/control \
-d "task=discovery_send&action=enable"
```
### Cluster Health Monitoring
```bash
# Monitor all nodes in cluster
for ip in 10.0.1.60 10.0.1.61 10.0.1.62; do
echo "=== Node $ip ==="
curl -s "http://$ip/api/tasks/status" | jq '.summary'
done
```

358
docs/Architecture.md Normal file
View File

@@ -0,0 +1,358 @@
# SPORE Architecture & Implementation
## System Overview
SPORE (SProcket ORchestration Engine) is a cluster engine for ESP8266 microcontrollers that provides automatic node discovery, health monitoring, and over-the-air updates in a distributed network environment.
## Core Components
The system architecture consists of several key components working together:
### Network Manager
- **WiFi Connection Handling**: Automatic WiFi STA/AP configuration
- **Hostname Configuration**: MAC-based hostname generation
- **Fallback Management**: Automatic access point creation if WiFi connection fails
### Cluster Manager
- **Node Discovery**: UDP-based automatic node detection
- **Member List Management**: Dynamic cluster membership tracking
- **Health Monitoring**: Continuous node status checking
- **Resource Tracking**: Monitor node resources and capabilities
### API Server
- **HTTP API Server**: RESTful API for cluster management
- **Dynamic Endpoint Registration**: Automatic API endpoint discovery
- **Service Registry**: Track available services across the cluster
### Task Scheduler
- **Cooperative Multitasking**: Background task management system
- **Task Lifecycle Management**: Automatic task execution and monitoring
- **Resource Optimization**: Efficient task scheduling and execution
### Node Context
- **Central Context**: Shared resources and configuration
- **Event System**: Local and cluster-wide event publishing/subscription
- **Resource Management**: Centralized resource allocation and monitoring
## Auto Discovery Protocol
The cluster uses a UDP-based discovery protocol for automatic node detection:
### Discovery Process
1. **Discovery Broadcast**: Nodes periodically send UDP packets on port 4210
2. **Response Handling**: Nodes respond with their hostname and IP address
3. **Member Management**: Discovered nodes are automatically added to the cluster
4. **Health Monitoring**: Continuous status checking via HTTP API calls
### Protocol Details
- **UDP Port**: 4210 (configurable)
- **Discovery Message**: `CLUSTER_DISCOVERY`
- **Response Message**: `CLUSTER_RESPONSE`
- **Broadcast Address**: 255.255.255.255
- **Discovery Interval**: 1 second (configurable)
- **Listen Interval**: 100ms (configurable)
### Node Status Categories
Nodes are automatically categorized by their activity:
- **ACTIVE**: Responding within 10 seconds
- **INACTIVE**: No response for 10-60 seconds
- **DEAD**: No response for over 60 seconds
## Task Scheduling System
The system runs several background tasks at different intervals:
### Core System Tasks
| Task | Interval | Purpose |
|------|----------|---------|
| **Discovery Send** | 1 second | Send UDP discovery packets |
| **Discovery Listen** | 100ms | Listen for discovery responses |
| **Status Updates** | 1 second | Monitor cluster member health |
| **Heartbeat** | 2 seconds | Maintain cluster connectivity |
| **Member Info** | 10 seconds | Update detailed node information |
| **Debug Output** | 5 seconds | Print cluster status |
### Task Management Features
- **Dynamic Intervals**: Change execution frequency on-the-fly
- **Runtime Control**: Enable/disable tasks without restart
- **Status Monitoring**: Real-time task health tracking
- **Resource Integration**: View task status with system resources
## Event System
The `NodeContext` provides an event-driven architecture for system-wide communication:
### Event Subscription
```cpp
// Subscribe to events
ctx.on("node_discovered", [](void* data) {
NodeInfo* node = static_cast<NodeInfo*>(data);
// Handle new node discovery
});
ctx.on("cluster_updated", [](void* data) {
// Handle cluster membership changes
});
```
### Event Publishing
```cpp
// Publish events
ctx.fire("node_discovered", &newNode);
ctx.fire("cluster_updated", &clusterData);
```
### Available Events
- **`node_discovered`**: New node added to cluster
- **`cluster_updated`**: Cluster membership changed
- **`resource_update`**: Node resources updated
- **`health_check`**: Node health status changed
## Resource Monitoring
Each node tracks comprehensive system resources:
### System Resources
- **Free Heap Memory**: Available RAM in bytes
- **Chip ID**: Unique ESP8266 identifier
- **SDK Version**: ESP8266 firmware version
- **CPU Frequency**: Operating frequency in MHz
- **Flash Chip Size**: Total flash storage in bytes
### API Endpoint Registry
- **Dynamic Discovery**: Automatically detect available endpoints
- **Method Information**: HTTP method (GET, POST, etc.)
- **Service Catalog**: Complete service registry across cluster
### Health Metrics
- **Response Time**: API response latency
- **Uptime**: System uptime in milliseconds
- **Connection Status**: Network connectivity health
- **Resource Utilization**: Memory and CPU usage
## WiFi Fallback System
The system includes automatic WiFi fallback for robust operation:
### Fallback Process
1. **Primary Connection**: Attempts to connect to configured WiFi network
2. **Connection Failure**: If connection fails, creates an access point
3. **Hostname Generation**: Automatically generates hostname from MAC address
4. **Service Continuity**: Maintains cluster functionality in fallback mode
### Configuration
- **SSID Format**: `SPORE_<MAC_LAST_4>`
- **Password**: Configurable fallback password
- **IP Range**: 192.168.4.x subnet
- **Gateway**: 192.168.4.1
## Cluster Topology
### Node Types
- **Master Node**: Primary cluster coordinator (if applicable)
- **Worker Nodes**: Standard cluster members
- **Edge Nodes**: Network edge devices
### Network Architecture
- **Mesh-like Structure**: Nodes can communicate with each other
- **Dynamic Routing**: Automatic path discovery between nodes
- **Load Distribution**: Tasks distributed across available nodes
- **Fault Tolerance**: Automatic failover and recovery
## Data Flow
### Discovery Flow
```
Node A → UDP Broadcast → Node B
Node B → HTTP Response → Node A
Node A → Add to Cluster → Update Member List
```
### Health Monitoring Flow
```
Cluster Manager → HTTP Request → Node Status
Node → JSON Response → Resource Information
Cluster Manager → Update Health → Fire Events
```
### Task Execution Flow
```
Task Scheduler → Check Intervals → Execute Tasks
Task → Update Status → API Server
API Server → JSON Response → Client
```
## Performance Characteristics
### Memory Usage
- **Base System**: ~15-20KB RAM
- **Per Task**: ~100-200 bytes per task
- **Cluster Members**: ~50-100 bytes per member
- **API Endpoints**: ~20-30 bytes per endpoint
### Network Overhead
- **Discovery Packets**: 64 bytes every 1 second
- **Health Checks**: ~200-500 bytes every 1 second
- **Status Updates**: ~1-2KB per node
- **API Responses**: Varies by endpoint (typically 100B-5KB)
### Processing Overhead
- **Task Execution**: Minimal overhead per task
- **Event Processing**: Fast event dispatch
- **JSON Parsing**: Efficient ArduinoJson usage
- **Network I/O**: Asynchronous operations
## Security Considerations
### Current Implementation
- **Network Access**: Local network only (no internet exposure)
- **Authentication**: None currently implemented
- **Data Validation**: Basic input validation
- **Resource Limits**: Memory and processing constraints
### Future Enhancements
- **TLS/SSL**: Encrypted communications
- **API Keys**: Authentication for API access
- **Access Control**: Role-based permissions
- **Audit Logging**: Security event tracking
## Scalability
### Cluster Size Limits
- **Theoretical**: Up to 255 nodes (IP subnet limit)
- **Practical**: 20-50 nodes for optimal performance
- **Memory Constraint**: ~8KB available for member tracking
- **Network Constraint**: UDP packet size limits
### Performance Scaling
- **Linear Scaling**: Most operations scale linearly with node count
- **Discovery Overhead**: Increases with cluster size
- **Health Monitoring**: Parallel HTTP requests
- **Task Management**: Independent per-node execution
## Configuration Management
### Environment Variables
```bash
# API node IP for cluster management
export API_NODE=192.168.1.100
# Cluster configuration
export CLUSTER_PORT=4210
export DISCOVERY_INTERVAL=1000
export HEALTH_CHECK_INTERVAL=1000
```
### PlatformIO Configuration
The project uses PlatformIO with the following configuration:
- **Framework**: Arduino
- **Board**: ESP-01 with 1MB flash
- **Upload Speed**: 115200 baud
- **Flash Mode**: DOUT (required for ESP-01S)
### Dependencies
The project requires the following libraries:
- `esp32async/ESPAsyncWebServer@^3.8.0` - HTTP API server
- `bblanchon/ArduinoJson@^7.4.2` - JSON processing
- `arkhipenko/TaskScheduler@^3.8.5` - Cooperative multitasking
## Development Workflow
### Building
Build the firmware for specific chip:
```bash
./ctl.sh build target esp01_1m
```
### Flashing
Flash firmware to a connected device:
```bash
./ctl.sh flash target esp01_1m
```
### Over-The-Air Updates
Update a specific node:
```bash
./ctl.sh ota update 192.168.1.100 esp01_1m
```
Update all nodes in the cluster:
```bash
./ctl.sh ota all esp01_1m
```
### Cluster Management
View cluster members:
```bash
./ctl.sh cluster members
```
## Troubleshooting
### Common Issues
1. **Discovery Failures**: Check UDP port 4210 is not blocked
2. **WiFi Connection**: Verify SSID/password in Config.cpp
3. **OTA Updates**: Ensure sufficient flash space (1MB minimum)
4. **Cluster Split**: Check network connectivity between nodes
### Debug Output
Enable serial monitoring to see cluster activity:
```bash
pio device monitor
```
### Performance Monitoring
- **Memory Usage**: Monitor free heap with `/api/node/status`
- **Task Health**: Check task status with `/api/tasks/status`
- **Cluster Health**: Monitor member status with `/api/cluster/members`
- **Network Latency**: Track response times in cluster data
## Related Documentation
- **[Task Management](./TaskManagement.md)** - Background task system
- **[API Reference](./API.md)** - REST API documentation
- **[TaskManager API](./TaskManager.md)** - TaskManager class reference
- **[OpenAPI Specification](../api/)** - Machine-readable API specification

437
docs/Development.md Normal file
View File

@@ -0,0 +1,437 @@
# Development & Deployment Guide
## Prerequisites
### Required Tools
- **PlatformIO Core** or **PlatformIO IDE**
- **ESP8266 development tools**
- **`jq`** for JSON processing in scripts
- **Git** for version control
### System Requirements
- **Operating System**: Linux, macOS, or Windows
- **Python**: 3.7+ (for PlatformIO)
- **Memory**: 4GB+ RAM recommended
- **Storage**: 2GB+ free space for development environment
## Project Structure
```
spore/
├── src/ # Source code
│ ├── main.cpp # Main application entry point
│ ├── ApiServer.cpp # HTTP API server implementation
│ ├── ClusterManager.cpp # Cluster management logic
│ ├── NetworkManager.cpp # WiFi and network handling
│ ├── TaskManager.cpp # Background task management
│ └── NodeContext.cpp # Central context and events
├── include/ # Header files
├── lib/ # Library files
├── docs/ # Documentation
├── api/ # OpenAPI specification
├── examples/ # Example code
├── test/ # Test files
├── platformio.ini # PlatformIO configuration
└── ctl.sh # Build and deployment scripts
```
## PlatformIO Configuration
### Framework and Board
The project uses PlatformIO with the following configuration:
```ini
[env:esp01_1m]
platform = platformio/espressif8266@^4.2.1
board = esp01_1m
framework = arduino
upload_speed = 115200
flash_mode = dout
```
### Key Configuration Details
- **Framework**: Arduino
- **Board**: ESP-01 with 1MB flash
- **Upload Speed**: 115200 baud
- **Flash Mode**: DOUT (required for ESP-01S)
- **Build Type**: Release (optimized for production)
### Dependencies
The project requires the following libraries:
```ini
lib_deps =
esp32async/ESPAsyncWebServer@^3.8.0
bblanchon/ArduinoJson@^7.4.2
arkhipenko/TaskScheduler@^3.8.5
ESP8266HTTPClient@1.2
ESP8266WiFi@1.0
```
## Building
### Basic Build Commands
Build the firmware for specific chip:
```bash
# Build for ESP-01 1MB
./ctl.sh build target esp01_1m
# Build for D1 Mini
./ctl.sh build target d1_mini
# Build with verbose output
pio run -v
```
### Build Targets
Available build targets:
| Target | Description | Flash Size |
|--------|-------------|------------|
| `esp01_1m` | ESP-01 with 1MB flash | 1MB |
| `d1_mini` | D1 Mini with 4MB flash | 4MB |
### Build Artifacts
After successful build:
- **Firmware**: `.pio/build/{target}/firmware.bin`
- **ELF File**: `.pio/build/{target}/firmware.elf`
- **Map File**: `.pio/build/{target}/firmware.map`
## Flashing
### Direct USB Flashing
Flash firmware to a connected device:
```bash
# Flash ESP-01
./ctl.sh flash target esp01_1m
# Flash D1 Mini
./ctl.sh flash target d1_mini
# Manual flash command
pio run --target upload
```
### Flash Settings
- **Upload Speed**: 115200 baud (optimal for ESP-01)
- **Flash Mode**: DOUT (required for ESP-01S)
- **Reset Method**: Hardware reset or manual reset
### Troubleshooting Flashing
Common flashing issues:
1. **Connection Failed**: Check USB cable and drivers
2. **Wrong Upload Speed**: Try lower speeds (9600, 57600)
3. **Flash Mode Error**: Ensure DOUT mode for ESP-01S
4. **Permission Denied**: Run with sudo or add user to dialout group
## Over-The-Air Updates
### Single Node Update
Update a specific node:
```bash
# Update specific node
./ctl.sh ota update 192.168.1.100 esp01_1m
# Update with custom firmware
./ctl.sh ota update 192.168.1.100 esp01_1m custom_firmware.bin
```
### Cluster-Wide Updates
Update all nodes in the cluster:
```bash
# Update all nodes
./ctl.sh ota all esp01_1m
```
### OTA Process
1. **Firmware Upload**: Send firmware to target node
2. **Verification**: Check firmware integrity
3. **Installation**: Install new firmware
4. **Restart**: Node restarts with new firmware
5. **Verification**: Confirm successful update
### OTA Requirements
- **Flash Space**: Minimum 1MB for OTA updates
- **Network**: Stable WiFi connection
- **Power**: Stable power supply during update
- **Memory**: Sufficient RAM for firmware processing
## Cluster Management
### View Cluster Status
```bash
# View all cluster members
./ctl.sh cluster members
# View specific node details
./ctl.sh cluster members --node 192.168.1.100
```
### Cluster Commands
Available cluster management commands:
| Command | Description |
|---------|-------------|
| `members` | List all cluster members |
| `status` | Show cluster health status |
| `discover` | Force discovery process |
| `health` | Check cluster member health |
### Cluster Monitoring
Monitor cluster health in real-time:
```bash
# Watch cluster status
watch -n 5 './ctl.sh cluster members'
# Monitor specific metrics
./ctl.sh cluster members | jq '.members[] | {hostname, status, latency}'
```
## Development Workflow
### Local Development
1. **Setup Environment**:
```bash
git clone <repository>
cd spore
pio run
```
2. **Make Changes**:
- Edit source files in `src/`
- Modify headers in `include/`
- Update configuration in `platformio.ini`
3. **Test Changes**:
```bash
pio run
pio check
```
### Testing
Run various tests:
```bash
# Code quality check
pio check
# Unit tests (if available)
pio test
# Memory usage analysis
pio run --target size
```
### Debugging
Enable debug output:
```bash
# Serial monitoring
pio device monitor
# Build with debug symbols
pio run --environment esp01_1m --build-flags -DDEBUG
```
## Configuration Management
### Environment Setup
Create a `.env` file in your project root:
```bash
# API node IP for cluster management
export API_NODE=192.168.1.100
```
### Configuration Files
Key configuration files:
- **`platformio.ini`**: Build and upload configuration
- **`src/Config.cpp`**: Application configuration
- **`.env`**: Environment variables
- **`ctl.sh`**: Build and deployment scripts
### Configuration Options
Available configuration options:
| Option | Default | Description |
|--------|---------|-------------|
| `CLUSTER_PORT` | 4210 | UDP discovery port |
| `DISCOVERY_INTERVAL` | 1000 | Discovery packet interval (ms) |
| `HEALTH_CHECK_INTERVAL` | 1000 | Health check interval (ms) |
| `API_SERVER_PORT` | 80 | HTTP API server port |
## Deployment Strategies
### Development Deployment
For development and testing:
1. **Build**: `pio run`
2. **Flash**: `pio run --target upload`
3. **Monitor**: `pio device monitor`
### Production Deployment
For production systems:
1. **Build Release**: `pio run --environment esp01_1m`
2. **OTA Update**: `./ctl.sh ota update <ip> esp01_1m`
3. **Verify**: Check node status via API
### Continuous Integration
Automated deployment pipeline:
```yaml
# Example GitHub Actions workflow
- name: Build Firmware
run: pio run --environment esp01_1m
- name: Deploy to Test Cluster
run: ./ctl.sh ota all esp01_1m --target test
- name: Deploy to Production
run: ./ctl.sh ota all esp01_1m --target production
```
## Monitoring and Debugging
### Serial Output
Enable serial monitoring:
```bash
# Basic monitoring
pio device monitor
# With specific baud rate
pio device monitor --baud 115200
# Filter specific messages
pio device monitor | grep "Cluster"
```
### API Monitoring
Monitor system via HTTP API:
```bash
# Check system status
curl -s http://192.168.1.100/api/node/status | jq '.'
# Monitor tasks
curl -s http://192.168.1.100/api/tasks/status | jq '.'
# Check cluster health
curl -s http://192.168.1.100/api/cluster/members | jq '.'
```
### Performance Monitoring
Track system performance:
```bash
# Memory usage over time
watch -n 5 'curl -s http://192.168.1.100/api/node/status | jq ".freeHeap"'
# Task execution status
watch -n 10 'curl -s http://192.168.1.100/api/tasks/status | jq ".summary"'
```
## Troubleshooting
### Common Issues
1. **Discovery Failures**: Check UDP port 4210 is not blocked
2. **WiFi Connection**: Verify SSID/password in Config.cpp
3. **OTA Updates**: Ensure sufficient flash space (1MB minimum)
4. **Cluster Split**: Check network connectivity between nodes
### Debug Commands
Useful debugging commands:
```bash
# Check network connectivity
ping 192.168.1.100
# Test UDP port
nc -u 192.168.1.100 4210
# Check HTTP API
curl -v http://192.168.1.100/api/node/status
# Monitor system resources
./ctl.sh cluster members | jq '.members[] | {hostname, status, resources.freeHeap}'
```
### Performance Issues
Common performance problems:
- **Memory Leaks**: Monitor free heap over time
- **Network Congestion**: Check discovery intervals
- **Task Overload**: Review task execution intervals
- **WiFi Interference**: Check channel and signal strength
## Best Practices
### Code Organization
1. **Modular Design**: Keep components loosely coupled
2. **Clear Interfaces**: Define clear APIs between components
3. **Error Handling**: Implement proper error handling and logging
4. **Resource Management**: Efficient memory and resource usage
### Testing Strategy
1. **Unit Tests**: Test individual components
2. **Integration Tests**: Test component interactions
3. **System Tests**: Test complete system functionality
4. **Performance Tests**: Monitor resource usage and performance
### Deployment Strategy
1. **Staged Rollout**: Deploy to test cluster first
2. **Rollback Plan**: Maintain ability to rollback updates
3. **Monitoring**: Monitor system health during deployment
4. **Documentation**: Keep deployment procedures updated
## Related Documentation
- **[Architecture Guide](./Architecture.md)** - System architecture overview
- **[Task Management](./TaskManagement.md)** - Background task system
- **[API Reference](./API.md)** - REST API documentation
- **[OpenAPI Specification](../api/)** - Machine-readable API specification

85
docs/README.md Normal file
View File

@@ -0,0 +1,85 @@
# SPORE Documentation
This folder contains comprehensive documentation for the SPORE embedded system.
## Available Documentation
### 📖 [API.md](./API.md)
Complete API reference with detailed endpoint documentation, examples, and integration guides.
**Includes:**
- API endpoint specifications
- Request/response examples
- HTTP status codes
- Integration examples (Python, JavaScript)
- Task management workflows
- Cluster monitoring examples
### 📖 [TaskManager.md](./TaskManager.md)
Comprehensive guide to the TaskManager system for background task management.
**Includes:**
- Basic usage examples
- Advanced binding techniques
- Task status monitoring
- API integration details
- Performance considerations
### 📖 [TaskManagement.md](./TaskManagement.md)
Complete guide to the task management system with examples and best practices.
**Includes:**
- Task registration methods (std::bind, lambdas, functions)
- Task control and lifecycle management
- Remote task management via API
- Performance considerations and best practices
- Migration guides and compatibility information
### 📖 [Architecture.md](./Architecture.md)
Comprehensive system architecture and implementation details.
**Includes:**
- Core component descriptions
- Auto discovery protocol details
- Task scheduling system
- Event system architecture
- Resource monitoring
- Performance characteristics
- Security and scalability considerations
### 📖 [Development.md](./Development.md)
Complete development and deployment guide.
**Includes:**
- PlatformIO configuration
- Build and flash instructions
- OTA update procedures
- Cluster management commands
- Development workflow
- Troubleshooting guide
- Best practices
## Quick Links
- **Main Project**: [../README.md](../README.md)
- **OpenAPI Specification**: [../api/](../api/)
- **Source Code**: [../src/](../src/)
## Contributing
When adding new documentation:
1. Create a new `.md` file in this folder
2. Use clear, descriptive filenames
3. Include practical examples and code snippets
4. Update this README.md to reference new files
5. Follow the existing documentation style
## Documentation Style Guide
- Use clear, concise language
- Include practical examples
- Use code blocks with appropriate language tags
- Include links to related documentation
- Use emojis sparingly for visual organization
- Keep README.md files focused and scoped

348
docs/TaskManagement.md Normal file
View File

@@ -0,0 +1,348 @@
# Task Management System
The SPORE system includes a comprehensive TaskManager that provides a clean interface for managing system tasks. This makes it easy to add, configure, and control background tasks without cluttering the main application code.
## Overview
The TaskManager system provides:
- **Easy Task Registration**: Simple API for adding new tasks with configurable intervals
- **Dynamic Control**: Enable/disable tasks at runtime
- **Interval Management**: Change task execution frequency on the fly
- **Status Monitoring**: View task status and configuration
- **Automatic Lifecycle**: Tasks are automatically managed and executed
## Basic Usage
```cpp
#include "TaskManager.h"
// Create task manager
TaskManager taskManager(ctx);
// Register tasks
taskManager.registerTask("heartbeat", 2000, heartbeatFunction);
taskManager.registerTask("maintenance", 30000, maintenanceFunction);
// Initialize and start all tasks
taskManager.initialize();
```
## Task Registration Methods
### Using std::bind with Member Functions (Recommended)
```cpp
#include <functional>
#include "TaskManager.h"
class MyService {
public:
void sendHeartbeat() {
Serial.println("Service heartbeat");
}
void performMaintenance() {
Serial.println("Running maintenance");
}
};
MyService service;
TaskManager taskManager(ctx);
// Register member functions using std::bind
taskManager.registerTask("heartbeat", 2000,
std::bind(&MyService::sendHeartbeat, &service));
taskManager.registerTask("maintenance", 30000,
std::bind(&MyService::performMaintenance, &service));
// Initialize and start all tasks
taskManager.initialize();
```
### Using Lambda Functions
```cpp
// Register lambda functions directly
taskManager.registerTask("counter", 1000, []() {
static int count = 0;
Serial.printf("Count: %d\n", ++count);
});
// Lambda with capture
int threshold = 100;
taskManager.registerTask("monitor", 5000, [&threshold]() {
if (ESP.getFreeHeap() < threshold) {
Serial.println("Low memory warning!");
}
});
```
### Complex Task Registration
```cpp
class NetworkManager {
public:
void checkConnection() { /* ... */ }
void sendData(String data) { /* ... */ }
};
NetworkManager network;
// Multiple operations in one task
taskManager.registerTask("network_ops", 3000,
std::bind([](NetworkManager* net) {
net->checkConnection();
net->sendData("status_update");
}, &network));
```
## Task Control API
### Basic Operations
```cpp
// Enable/disable tasks
taskManager.enableTask("heartbeat");
taskManager.disableTask("maintenance");
// Change intervals
taskManager.setTaskInterval("heartbeat", 5000); // 5 seconds
// Check status
bool isRunning = taskManager.isTaskEnabled("heartbeat");
unsigned long interval = taskManager.getTaskInterval("heartbeat");
// Print all task statuses
taskManager.printTaskStatus();
```
### Task Lifecycle Management
```cpp
// Start/stop tasks
taskManager.startTask("heartbeat");
taskManager.stopTask("discovery");
// Bulk operations
taskManager.enableAllTasks();
taskManager.disableAllTasks();
```
## Task Configuration Options
When registering tasks, you can specify:
- **Name**: Unique identifier for the task
- **Interval**: Execution frequency in milliseconds
- **Callback**: Function, bound method, or lambda to execute
- **Enabled**: Whether the task starts enabled (default: true)
- **AutoStart**: Whether to start automatically (default: true)
```cpp
// Traditional function
taskManager.registerTask("delayed_task", 5000, taskFunction, true, false);
// Member function with std::bind
taskManager.registerTask("service_task", 3000,
std::bind(&Service::method, &instance), true, false);
// Lambda function
taskManager.registerTask("lambda_task", 2000,
[]() { Serial.println("Lambda!"); }, true, false);
```
## Adding Custom Tasks
### Method 1: Using std::bind (Recommended)
1. **Create your service class**:
```cpp
class SensorService {
public:
void readTemperature() {
// Read sensor logic
Serial.println("Reading temperature");
}
void calibrateSensors() {
// Calibration logic
Serial.println("Calibrating sensors");
}
};
```
2. **Register with TaskManager**:
```cpp
SensorService sensors;
taskManager.registerTask("temp_read", 1000,
std::bind(&SensorService::readTemperature, &sensors));
taskManager.registerTask("calibrate", 60000,
std::bind(&SensorService::calibrateSensors, &sensors));
```
### Method 2: Traditional Functions
1. **Define your task function**:
```cpp
void myCustomTask() {
// Your task logic here
Serial.println("Custom task executed");
}
```
2. **Register with TaskManager**:
```cpp
taskManager.registerTask("my_task", 10000, myCustomTask);
```
## Enhanced TaskManager Capabilities
### Task Status Monitoring
- **Real-time Status**: Check enabled/disabled state and running status
- **Performance Metrics**: Monitor execution intervals and timing
- **System Integration**: View task status alongside system resources
- **Bulk Operations**: Get status of all tasks at once
### Task Control Features
- **Runtime Control**: Enable/disable tasks without restart
- **Dynamic Intervals**: Change task execution frequency on-the-fly
- **Individual Status**: Get detailed information about specific tasks
- **Health Monitoring**: Track task health and system resources
## Remote Task Management
The TaskManager integrates with the API server to provide comprehensive remote task control and monitoring.
### Task Status Overview
Get a complete overview of all tasks and system status:
```bash
# Get comprehensive task status
curl http://192.168.1.100/api/tasks/status
```
**Response includes:**
- **Summary**: Total task count and active task count
- **Task Details**: Individual status for each task (name, interval, enabled, running, auto-start)
- **System Info**: Free heap memory and uptime
**Example Response:**
```json
{
"summary": {
"totalTasks": 6,
"activeTasks": 5
},
"tasks": [
{
"name": "discovery_send",
"interval": 1000,
"enabled": true,
"running": true,
"autoStart": true
},
{
"name": "heartbeat",
"interval": 2000,
"enabled": true,
"running": true,
"autoStart": true
}
],
"system": {
"freeHeap": 48748,
"uptime": 12345
}
}
```
### Individual Task Control
Control individual tasks with various actions:
```bash
# Control tasks
curl -X POST http://192.168.1.100/api/tasks/control \
-d "task=heartbeat&action=disable"
# Get detailed status for a specific task
curl -X POST http://192.168.1.100/api/tasks/control \
-d "task=discovery_send&action=status"
```
**Available Actions:**
- `enable` - Enable a task
- `disable` - Disable a task
- `start` - Start a task
- `stop` - Stop a task
- `status` - Get detailed status for a specific task
**Task Status Response:**
```json
{
"success": true,
"message": "Task status retrieved",
"task": "discovery_send",
"action": "status",
"taskDetails": {
"name": "discovery_send",
"enabled": true,
"running": true,
"interval": 1000,
"system": {
"freeHeap": 48748,
"uptime": 12345
}
}
}
```
## Performance Considerations
- `std::bind` creates a callable object that may have a small overhead compared to direct function pointers
- For high-frequency tasks, consider the performance impact
- The overhead is typically negligible for most embedded applications
- The TaskManager stores bound functions efficiently in a registry
## Best Practices
1. **Use std::bind for member functions**: Cleaner than wrapper functions
2. **Group related tasks**: Register multiple related operations in a single task
3. **Monitor task health**: Use the status API to monitor task performance
4. **Plan intervals carefully**: Balance responsiveness with system resources
5. **Use descriptive names**: Make task names clear and meaningful
## Migration from Wrapper Functions
### Before (with wrapper functions):
```cpp
void discoverySendTask() { cluster.sendDiscovery(); }
void discoveryListenTask() { cluster.listenForDiscovery(); }
taskManager.registerTask("discovery_send", interval, discoverySendTask);
taskManager.registerTask("discovery_listen", interval, discoveryListenTask);
```
### After (with std::bind):
```cpp
taskManager.registerTask("discovery_send", interval,
std::bind(&ClusterManager::sendDiscovery, &cluster));
taskManager.registerTask("discovery_listen", interval,
std::bind(&ClusterManager::listenForDiscovery, &cluster));
```
## Compatibility
- The new `std::bind` support is fully backward compatible
- Existing code using function pointers will continue to work
- You can mix both approaches in the same project
- All existing TaskManager methods remain unchanged
- New status monitoring methods are additive and don't break existing functionality
## Related Documentation
- **[TaskManager API Reference](./TaskManager.md)** - Detailed API documentation
- **[API Reference](./API.md)** - REST API for remote task management
- **[OpenAPI Specification](../api/)** - Machine-readable API specification

View File

@@ -1,180 +0,0 @@
# TaskManager
## Basic Usage
### Including Required Headers
```cpp
#include <functional> // For std::bind
#include "TaskManager.h"
```
### Registering Member Functions
```cpp
class MyClass {
public:
void myMethod() {
Serial.println("My method called");
}
void methodWithParams(int value, String text) {
Serial.printf("Method called with %d and %s\n", value, text.c_str());
}
};
// Create an instance
MyClass myObject;
// Register member function
taskManager.registerTask("my_task", 1000,
std::bind(&MyClass::myMethod, &myObject));
// Register method with parameters
taskManager.registerTask("param_task", 2000,
std::bind(&MyClass::methodWithParams, &myObject, 42, "hello"));
```
### Registering Lambda Functions
```cpp
// Simple lambda
taskManager.registerTask("lambda_task", 3000, []() {
Serial.println("Lambda executed");
});
// Lambda with capture
int counter = 0;
taskManager.registerTask("counter_task", 4000, [&counter]() {
counter++;
Serial.printf("Counter: %d\n", counter);
});
// Lambda that calls multiple methods
taskManager.registerTask("multi_task", 5000, [&myObject]() {
myObject.myMethod();
// Do other work...
});
```
### Registering Global Functions
```cpp
void globalFunction() {
Serial.println("Global function called");
}
// Still supported for backward compatibility
taskManager.registerTask("global_task", 6000, globalFunction);
```
## Advanced Examples
### Binding to Different Object Types
```cpp
class NetworkManager {
public:
void sendHeartbeat() { /* ... */ }
void checkConnection() { /* ... */ }
};
class SensorManager {
public:
void readSensors() { /* ... */ }
void calibrate() { /* ... */ }
};
NetworkManager network;
SensorManager sensors;
// Bind to different objects
taskManager.registerTask("heartbeat", 1000,
std::bind(&NetworkManager::sendHeartbeat, &network));
taskManager.registerTask("sensor_read", 500,
std::bind(&SensorManager::readSensors, &sensors));
```
### Using std::placeholders for Complex Binding
```cpp
#include <functional>
class ConfigManager {
public:
void updateConfig(int interval, bool enabled) {
Serial.printf("Updating config: interval=%d, enabled=%d\n", interval, enabled);
}
};
ConfigManager config;
// Use placeholders for complex parameter binding
using namespace std::placeholders;
taskManager.registerTask("config_update", 10000,
std::bind(&ConfigManager::updateConfig, &config, _1, _2));
```
### Conditional Task Execution
```cpp
class TaskController {
public:
bool shouldExecute() {
return millis() % 10000 < 5000; // Execute only in first 5 seconds of each 10-second cycle
}
void conditionalTask() {
if (shouldExecute()) {
Serial.println("Conditional task executed");
}
}
};
TaskController controller;
taskManager.registerTask("conditional", 1000,
std::bind(&TaskController::conditionalTask, &controller));
```
## Benefits of Using std::bind
1. **Cleaner Code**: No need for wrapper functions
2. **Direct Binding**: Bind member functions directly to objects
3. **Parameter Passing**: Easily pass parameters to bound methods
4. **Lambda Support**: Use lambdas for complex logic
5. **Type Safety**: Better type checking than function pointers
6. **Flexibility**: Mix and match different callable types
## Migration from Wrapper Functions
### Before (with wrapper functions):
```cpp
void discoverySendTask() { cluster.sendDiscovery(); }
void discoveryListenTask() { cluster.listenForDiscovery(); }
taskManager.registerTask("discovery_send", interval, discoverySendTask);
taskManager.registerTask("discovery_listen", interval, discoveryListenTask);
```
### After (with std::bind):
```cpp
taskManager.registerTask("discovery_send", interval,
std::bind(&ClusterManager::sendDiscovery, &cluster));
taskManager.registerTask("discovery_listen", interval,
std::bind(&ClusterManager::listenForDiscovery, &cluster));
```
## Performance Considerations
- `std::bind` creates a callable object that may have a small overhead compared to direct function pointers
- For high-frequency tasks, consider the performance impact
- The overhead is typically negligible for most embedded applications
- The TaskManager stores bound functions efficiently in a registry
## Compatibility
- The new `std::bind` support is fully backward compatible
- Existing code using function pointers will continue to work
- You can mix both approaches in the same project
- All existing TaskManager methods remain unchanged

View File

@@ -5,6 +5,7 @@
#include <string>
#include <map>
#include "NodeContext.h"
#include <ArduinoJson.h>
// Forward declarations to avoid multiple definition errors
class Task;
@@ -45,6 +46,9 @@ public:
bool isTaskRunning(const std::string& name) const;
unsigned long getTaskInterval(const std::string& name) const;
// Get comprehensive task status information
std::vector<std::pair<std::string, JsonObject>> getAllTaskStatuses(JsonDocument& doc) const;
// Management methods
void initialize();
void enableAllTasks();

View File

@@ -1,4 +1,5 @@
#include "ApiServer.h"
#include <algorithm>
ApiServer::ApiServer(NodeContext& ctx, TaskManager& taskMgr, uint16_t port) : server(port), ctx(ctx), taskManager(taskMgr) {}
@@ -184,13 +185,31 @@ void ApiServer::onRestartRequest(AsyncWebServerRequest *request) {
void ApiServer::onTaskStatusRequest(AsyncWebServerRequest *request) {
JsonDocument doc;
JsonArray tasksArr = doc["tasks"].to<JsonArray>();
// This would need to be implemented in TaskManager to expose task status
// For now, we'll return a basic response
JsonObject taskObj = tasksArr.add<JsonObject>();
taskObj["message"] = "Task status endpoint - implementation pending";
taskObj["note"] = "Task status will be available in future versions";
// Get comprehensive task status from TaskManager
auto taskStatuses = taskManager.getAllTaskStatuses(doc);
// Add summary information
JsonObject summaryObj = doc["summary"].to<JsonObject>();
summaryObj["totalTasks"] = taskStatuses.size();
summaryObj["activeTasks"] = std::count_if(taskStatuses.begin(), taskStatuses.end(),
[](const auto& pair) { return pair.second["enabled"]; });
// Add detailed task information
JsonArray tasksArr = doc["tasks"].to<JsonArray>();
for (const auto& taskPair : taskStatuses) {
JsonObject taskObj = tasksArr.add<JsonObject>();
taskObj["name"] = taskPair.first;
taskObj["interval"] = taskPair.second["interval"];
taskObj["enabled"] = taskPair.second["enabled"];
taskObj["running"] = taskPair.second["running"];
taskObj["autoStart"] = taskPair.second["autoStart"];
}
// Add system information
JsonObject systemObj = doc["system"].to<JsonObject>();
systemObj["freeHeap"] = ESP.getFreeHeap();
systemObj["uptime"] = millis();
String json;
serializeJson(doc, json);
@@ -222,9 +241,39 @@ void ApiServer::onTaskControlRequest(AsyncWebServerRequest *request) {
taskManager.stopTask(taskName.c_str());
success = true;
message = "Task stopped";
} else if (action == "status") {
// Get detailed status for a specific task
success = true;
message = "Task status retrieved";
// Create JsonDocument for status response
JsonDocument statusDoc;
statusDoc["success"] = success;
statusDoc["message"] = message;
statusDoc["task"] = taskName;
statusDoc["action"] = action;
// Add task details to response
statusDoc["taskDetails"] = JsonObject();
JsonObject taskDetails = statusDoc["taskDetails"];
taskDetails["name"] = taskName;
taskDetails["enabled"] = taskManager.isTaskEnabled(taskName.c_str());
taskDetails["running"] = taskManager.isTaskRunning(taskName.c_str());
taskDetails["interval"] = taskManager.getTaskInterval(taskName.c_str());
// Add system context
taskDetails["system"] = JsonObject();
JsonObject systemInfo = taskDetails["system"];
systemInfo["freeHeap"] = ESP.getFreeHeap();
systemInfo["uptime"] = millis();
String statusJson;
serializeJson(statusDoc, statusJson);
request->send(200, "application/json", statusJson);
return; // Early return since we've already sent the response
} else {
success = false;
message = "Invalid action. Use: enable, disable, start, or stop";
message = "Invalid action. Use: enable, disable, start, stop, or status";
}
JsonDocument doc;
@@ -241,7 +290,7 @@ void ApiServer::onTaskControlRequest(AsyncWebServerRequest *request) {
JsonDocument doc;
doc["success"] = false;
doc["message"] = "Missing parameters. Required: task, action";
doc["example"] = "{\"task\": \"discovery_send\", \"action\": \"disable\"}";
doc["example"] = "{\"task\": \"discovery_send\", \"action\": \"status\"}";
String json;
serializeJson(doc, json);

View File

@@ -6,6 +6,8 @@ ClusterManager::ClusterManager(NodeContext& ctx, TaskManager& taskMgr) : ctx(ctx
NodeInfo* node = static_cast<NodeInfo*>(data);
this->addOrUpdateNode(node->hostname, node->ip);
});
// Register tasks
registerTasks();
}
void ClusterManager::registerTasks() {

View File

@@ -191,4 +191,24 @@ Task* TaskManager::findTask(const std::string& name) const {
}
}
return nullptr;
}
std::vector<std::pair<std::string, JsonObject>> TaskManager::getAllTaskStatuses(JsonDocument& doc) const {
std::vector<std::pair<std::string, JsonObject>> taskStatuses;
for (size_t i = 0; i < tasks.size() && i < taskDefinitions.size(); ++i) {
const auto& taskDef = taskDefinitions[i];
const auto& task = tasks[i];
JsonObject taskStatus = doc.add<JsonObject>();
taskStatus["name"] = taskDef.name;
taskStatus["interval"] = task->getInterval();
taskStatus["enabled"] = task->isEnabled();
taskStatus["running"] = task->isEnabled(); // For now, enabled = running
taskStatus["autoStart"] = taskDef.autoStart;
taskStatuses.push_back(std::make_pair(taskDef.name, taskStatus));
}
return taskStatuses;
}

View File

@@ -18,10 +18,7 @@ ApiServer apiServer(ctx, taskManager, ctx.config.api_server_port);
void setup() {
// Setup WiFi first
network.setupWiFi();
// Register tasks in their respective classes
cluster.registerTasks();
// Initialize and start all tasks
taskManager.initialize();