feat: task manager endpoint, updated documentation
This commit is contained in:
444
README.md
444
README.md
@@ -16,420 +16,136 @@ SPORE is a cluster engine for ESP8266 microcontrollers that provides automatic n
|
|||||||
|
|
||||||
## Supported Hardware
|
## Supported Hardware
|
||||||
|
|
||||||
- **ESP-01** (1MB Flash)
|
- **ESP-01 / ESP-01S** (1MB Flash)
|
||||||
- **ESP-01S** (1MB Flash)
|
- **Wemos D1** (4MB Flash)
|
||||||
- Other ESP8266 boards with 1MB+ flash
|
- Other ESP8266 boards with 1MB+ flash
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
### Core Components
|
SPORE uses a modular architecture with automatic node discovery, health monitoring, and distributed task management.
|
||||||
|
|
||||||
The system architecture consists of several key components working together:
|
|
||||||
|
|
||||||
|
**Core Components:**
|
||||||
- **Network Manager**: WiFi connection handling and hostname configuration
|
- **Network Manager**: WiFi connection handling and hostname configuration
|
||||||
- **Cluster Manager**: Node discovery, member list management, and health monitoring
|
- **Cluster Manager**: Node discovery, member list management, and health monitoring
|
||||||
- **API Server**: HTTP API server with dynamic endpoint registration
|
- **API Server**: HTTP API server with dynamic endpoint registration
|
||||||
- **Task Scheduler**: Cooperative multitasking system for background operations
|
- **Task Scheduler**: Cooperative multitasking system for background operations
|
||||||
- **Node Context**: Central context providing event system and shared resources
|
- **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:
|
📖 **Detailed Architecture:** See [`docs/Architecture.md`](./docs/Architecture.md) for comprehensive system design and implementation details.
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
## API Endpoints
|
## API Endpoints
|
||||||
|
|
||||||
### Node Management
|
The system provides a comprehensive RESTful API for monitoring and controlling the embedded device.
|
||||||
|
|
||||||
| Endpoint | Method | Description |
|
**Core Endpoints:**
|
||||||
|----------|--------|-------------|
|
- **`/api/node/status`** - System resources and API endpoint registry
|
||||||
| `/api/node/status` | GET | Get system resources and API endpoints |
|
- **`/api/cluster/members`** - Cluster membership and health status
|
||||||
| `/api/node/update` | POST | Upload and install firmware update |
|
- **`/api/node/update`** - OTA firmware updates
|
||||||
| `/api/node/restart` | POST | Restart the node |
|
- **`/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 |
|
📖 **Complete API Reference:** See [`docs/API.md`](./docs/API.md) for detailed endpoint documentation, examples, and integration guides.
|
||||||
|----------|--------|-------------|
|
|
||||||
| `/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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
### Environment Setup
|
The project uses PlatformIO with Arduino framework and supports multiple ESP8266 boards.
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
|
**Key Settings:**
|
||||||
- **Framework**: Arduino
|
- **Framework**: Arduino
|
||||||
- **Board**: ESP-01 with 1MB flash
|
- **Board**: ESP-01 with 1MB flash (default)
|
||||||
- **Upload Speed**: 115200 baud
|
- **Upload Speed**: 115200 baud
|
||||||
- **Flash Mode**: DOUT (required for ESP-01S)
|
- **Flash Mode**: DOUT (required for ESP-01S)
|
||||||
|
|
||||||
### Dependencies
|
**Dependencies:**
|
||||||
|
- ESPAsyncWebServer, ArduinoJson, TaskScheduler
|
||||||
|
- ESP8266WiFi and HTTPClient libraries
|
||||||
|
|
||||||
The project requires the following libraries:
|
**Environment Setup:** Create `.env` file for cluster configuration and API node settings.
|
||||||
- `esp32async/ESPAsyncWebServer@^3.8.0` - HTTP API server
|
|
||||||
- `bblanchon/ArduinoJson@^7.4.2` - JSON processing
|
📖 **Development Guide:** See [`docs/Development.md`](./docs/Development.md) for comprehensive build, deployment, and configuration instructions.
|
||||||
- `arkhipenko/TaskScheduler@^3.8.5` - Cooperative multitasking
|
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Prerequisites
|
**Quick Commands:**
|
||||||
|
|
||||||
- PlatformIO Core or PlatformIO IDE
|
|
||||||
- ESP8266 development tools
|
|
||||||
- `jq` for JSON processing in scripts
|
|
||||||
|
|
||||||
### Building
|
|
||||||
|
|
||||||
Build the firmware for specific chip:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Build firmware
|
||||||
./ctl.sh build target esp01_1m
|
./ctl.sh build target esp01_1m
|
||||||
```
|
|
||||||
|
|
||||||
### Flashing
|
# Flash device
|
||||||
|
|
||||||
Flash firmware to a connected device:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./ctl.sh flash target esp01_1m
|
./ctl.sh flash target esp01_1m
|
||||||
```
|
|
||||||
|
|
||||||
### Over-The-Air Updates
|
# OTA update
|
||||||
|
|
||||||
Update a specific node:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./ctl.sh ota update 192.168.1.100 esp01_1m
|
./ctl.sh ota update 192.168.1.100 esp01_1m
|
||||||
```
|
|
||||||
|
|
||||||
Update all nodes in the cluster:
|
# Cluster management
|
||||||
|
|
||||||
```bash
|
|
||||||
./ctl.sh ota all esp01_1m
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cluster Management
|
|
||||||
|
|
||||||
View cluster members:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./ctl.sh cluster members
|
./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
|
## 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
|
📖 **Architecture Details:** See [`docs/Architecture.md`](./docs/Architecture.md) for comprehensive system design and implementation information.
|
||||||
// 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
|
|
||||||
|
|
||||||
## Task Management
|
## 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
|
📖 **Complete Task Management Guide:** See [`docs/TaskManagement.md`](./docs/TaskManagement.md) for detailed usage examples, best practices, and advanced features.
|
||||||
- **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);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Current Limitations
|
## Current Limitations
|
||||||
|
|
||||||
- WiFi credentials are hardcoded in `Config.cpp` (should be configurable)
|
- WiFi credentials are hardcoded in `Config.cpp` (should be configurable)
|
||||||
- Limited error handling for network failures
|
- Limited error handling for network failures
|
||||||
- No persistent storage for configuration
|
- 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
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -448,6 +164,16 @@ Enable serial monitoring to see cluster activity:
|
|||||||
pio device monitor
|
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
|
## Contributing
|
||||||
|
|
||||||
1. Fork the repository
|
1. Fork the repository
|
||||||
|
|||||||
201
api/README.md
Normal file
201
api/README.md
Normal 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
673
api/openapi.yaml
Normal 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
279
docs/API.md
Normal 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
358
docs/Architecture.md
Normal 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
437
docs/Development.md
Normal 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
85
docs/README.md
Normal 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
348
docs/TaskManagement.md
Normal 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
|
||||||
@@ -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
|
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "NodeContext.h"
|
#include "NodeContext.h"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
// Forward declarations to avoid multiple definition errors
|
// Forward declarations to avoid multiple definition errors
|
||||||
class Task;
|
class Task;
|
||||||
@@ -45,6 +46,9 @@ public:
|
|||||||
bool isTaskRunning(const std::string& name) const;
|
bool isTaskRunning(const std::string& name) const;
|
||||||
unsigned long getTaskInterval(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
|
// Management methods
|
||||||
void initialize();
|
void initialize();
|
||||||
void enableAllTasks();
|
void enableAllTasks();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "ApiServer.h"
|
#include "ApiServer.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
ApiServer::ApiServer(NodeContext& ctx, TaskManager& taskMgr, uint16_t port) : server(port), ctx(ctx), taskManager(taskMgr) {}
|
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) {
|
void ApiServer::onTaskStatusRequest(AsyncWebServerRequest *request) {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
JsonArray tasksArr = doc["tasks"].to<JsonArray>();
|
|
||||||
|
|
||||||
// This would need to be implemented in TaskManager to expose task status
|
// Get comprehensive task status from TaskManager
|
||||||
// For now, we'll return a basic response
|
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>();
|
JsonObject taskObj = tasksArr.add<JsonObject>();
|
||||||
taskObj["message"] = "Task status endpoint - implementation pending";
|
taskObj["name"] = taskPair.first;
|
||||||
taskObj["note"] = "Task status will be available in future versions";
|
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;
|
String json;
|
||||||
serializeJson(doc, json);
|
serializeJson(doc, json);
|
||||||
@@ -222,9 +241,39 @@ void ApiServer::onTaskControlRequest(AsyncWebServerRequest *request) {
|
|||||||
taskManager.stopTask(taskName.c_str());
|
taskManager.stopTask(taskName.c_str());
|
||||||
success = true;
|
success = true;
|
||||||
message = "Task stopped";
|
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 {
|
} else {
|
||||||
success = false;
|
success = false;
|
||||||
message = "Invalid action. Use: enable, disable, start, or stop";
|
message = "Invalid action. Use: enable, disable, start, stop, or status";
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
@@ -241,7 +290,7 @@ void ApiServer::onTaskControlRequest(AsyncWebServerRequest *request) {
|
|||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
doc["success"] = false;
|
doc["success"] = false;
|
||||||
doc["message"] = "Missing parameters. Required: task, action";
|
doc["message"] = "Missing parameters. Required: task, action";
|
||||||
doc["example"] = "{\"task\": \"discovery_send\", \"action\": \"disable\"}";
|
doc["example"] = "{\"task\": \"discovery_send\", \"action\": \"status\"}";
|
||||||
|
|
||||||
String json;
|
String json;
|
||||||
serializeJson(doc, json);
|
serializeJson(doc, json);
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ ClusterManager::ClusterManager(NodeContext& ctx, TaskManager& taskMgr) : ctx(ctx
|
|||||||
NodeInfo* node = static_cast<NodeInfo*>(data);
|
NodeInfo* node = static_cast<NodeInfo*>(data);
|
||||||
this->addOrUpdateNode(node->hostname, node->ip);
|
this->addOrUpdateNode(node->hostname, node->ip);
|
||||||
});
|
});
|
||||||
|
// Register tasks
|
||||||
|
registerTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClusterManager::registerTasks() {
|
void ClusterManager::registerTasks() {
|
||||||
|
|||||||
@@ -192,3 +192,23 @@ Task* TaskManager::findTask(const std::string& name) const {
|
|||||||
}
|
}
|
||||||
return nullptr;
|
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;
|
||||||
|
}
|
||||||
@@ -19,9 +19,6 @@ void setup() {
|
|||||||
// Setup WiFi first
|
// Setup WiFi first
|
||||||
network.setupWiFi();
|
network.setupWiFi();
|
||||||
|
|
||||||
// Register tasks in their respective classes
|
|
||||||
cluster.registerTasks();
|
|
||||||
|
|
||||||
// Initialize and start all tasks
|
// Initialize and start all tasks
|
||||||
taskManager.initialize();
|
taskManager.initialize();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user