366 lines
9.0 KiB
Markdown
366 lines
9.0 KiB
Markdown
# SPORE
|
|
|
|
> **S**Procket **OR**chestration **E**ngine
|
|
|
|
SPORE is a cluster engine for ESP8266 microcontrollers that provides automatic node discovery, health monitoring, and over-the-air updates in a distributed network environment.
|
|
|
|
## Features
|
|
|
|
- **WiFi Management**: Automatic WiFi STA/AP configuration with MAC-based hostname generation
|
|
- **Auto Discovery**: UDP-based node discovery with automatic cluster membership
|
|
- **Service Registry**: Dynamic API endpoint discovery and registration
|
|
- **Health Monitoring**: Real-time node status tracking with resource monitoring
|
|
- **Event System**: Local and cluster-wide event publishing/subscription
|
|
- **Over-The-Air Updates**: Seamless firmware updates across the cluster
|
|
- **REST API**: HTTP-based cluster management and monitoring
|
|
|
|
## Supported Hardware
|
|
|
|
- **ESP-01** (1MB Flash)
|
|
- **ESP-01S** (1MB Flash)
|
|
- Other ESP8266 boards with 1MB+ flash
|
|
|
|
## Architecture
|
|
|
|
### Core Components
|
|
|
|
The system architecture consists of several key components working together:
|
|
|
|
- **Network Manager**: WiFi connection handling and hostname configuration
|
|
- **Cluster Manager**: Node discovery, member list management, and health monitoring
|
|
- **API Server**: HTTP API server with dynamic endpoint registration
|
|
- **Task Scheduler**: Cooperative multitasking system for background operations
|
|
- **Node Context**: Central context providing event system and shared resources
|
|
|
|
### Auto Discovery Protocol
|
|
|
|
The cluster uses a UDP-based discovery protocol for automatic node detection:
|
|
|
|
1. **Discovery Broadcast**: Nodes periodically send UDP packets on port 4210
|
|
2. **Response Handling**: Nodes respond with their hostname and IP address
|
|
3. **Member Management**: Discovered nodes are automatically added to the cluster
|
|
4. **Health Monitoring**: Continuous status checking via HTTP API calls
|
|
|
|
### Task Scheduling
|
|
|
|
The system runs several background tasks at different intervals:
|
|
|
|
- **Discovery Tasks**: Send/listen for discovery packets (1s/100ms)
|
|
- **Status Updates**: Monitor cluster member health (1s)
|
|
- **Heartbeat**: Maintain cluster connectivity (2s)
|
|
- **Member Info**: Update detailed node information (10s)
|
|
- **Debug Output**: Print cluster status (5s)
|
|
|
|
## API Endpoints
|
|
|
|
### Node Management
|
|
|
|
| Endpoint | Method | Description |
|
|
|----------|--------|-------------|
|
|
| `/api/node/status` | GET | Get system resources and API endpoints |
|
|
| `/api/node/update` | POST | Upload and install firmware update |
|
|
| `/api/node/restart` | POST | Restart the node |
|
|
|
|
### Cluster Management
|
|
|
|
| Endpoint | Method | Description |
|
|
|----------|--------|-------------|
|
|
| `/api/cluster/members` | GET | Get cluster membership and status |
|
|
|
|
### Node Status Response
|
|
|
|
```json
|
|
{
|
|
"freeHeap": 12345,
|
|
"chipId": 12345678,
|
|
"sdkVersion": "2.2.2-dev(38a443e)",
|
|
"cpuFreqMHz": 80,
|
|
"flashChipSize": 1048576,
|
|
"api": [
|
|
{
|
|
"uri": "/api/node/status",
|
|
"method": "GET"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Cluster Members Response
|
|
|
|
```json
|
|
{
|
|
"members": [
|
|
{
|
|
"hostname": "esp_123456",
|
|
"ip": "192.168.1.100",
|
|
"lastSeen": 1234567890,
|
|
"latency": 5,
|
|
"status": "active",
|
|
"resources": {
|
|
"freeHeap": 12345,
|
|
"chipId": 12345678,
|
|
"sdkVersion": "2.2.2-dev(38a443e)",
|
|
"cpuFreqMHz": 80,
|
|
"flashChipSize": 1048576
|
|
},
|
|
"api": [
|
|
{
|
|
"uri": "/api/node/status",
|
|
"method": "GET"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Configuration
|
|
|
|
### Environment Setup
|
|
|
|
Create a `.env` file in your project root:
|
|
|
|
```bash
|
|
# API node IP for cluster management
|
|
export API_NODE=192.168.1.100
|
|
```
|
|
|
|
### PlatformIO Configuration
|
|
|
|
The project uses PlatformIO with the following configuration:
|
|
|
|
- **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
|
|
|
|
### Prerequisites
|
|
|
|
- PlatformIO Core or PlatformIO IDE
|
|
- ESP8266 development tools
|
|
- `jq` for JSON processing in scripts
|
|
|
|
### Building
|
|
|
|
Build the firmware:
|
|
|
|
```bash
|
|
./ctl.sh build
|
|
```
|
|
|
|
### Flashing
|
|
|
|
Flash firmware to a connected device:
|
|
|
|
```bash
|
|
./ctl.sh flash
|
|
```
|
|
|
|
### Over-The-Air Updates
|
|
|
|
Update a specific node:
|
|
|
|
```bash
|
|
./ctl.sh ota update 192.168.1.100
|
|
```
|
|
|
|
Update all nodes in the cluster:
|
|
|
|
```bash
|
|
./ctl.sh ota all
|
|
```
|
|
|
|
### Cluster Management
|
|
|
|
View cluster members:
|
|
|
|
```bash
|
|
./ctl.sh cluster members
|
|
```
|
|
|
|
## Implementation Details
|
|
|
|
### Event System
|
|
|
|
The `NodeContext` provides an event-driven architecture:
|
|
|
|
```cpp
|
|
// Subscribe to events
|
|
ctx.on("node_discovered", [](void* data) {
|
|
NodeInfo* node = static_cast<NodeInfo*>(data);
|
|
// Handle new node discovery
|
|
});
|
|
|
|
// Publish events
|
|
ctx.fire("node_discovered", &newNode);
|
|
```
|
|
|
|
### Node Status Tracking
|
|
|
|
Nodes are automatically categorized by their activity:
|
|
|
|
- **ACTIVE**: Responding within 10 seconds
|
|
- **INACTIVE**: No response for 10-60 seconds
|
|
- **DEAD**: No response for over 60 seconds
|
|
|
|
### Resource Monitoring
|
|
|
|
Each node tracks:
|
|
- Free heap memory
|
|
- Chip ID and SDK version
|
|
- CPU frequency
|
|
- Flash chip size
|
|
- API endpoint registry
|
|
|
|
### WiFi Fallback
|
|
|
|
The system includes automatic WiFi fallback:
|
|
1. Attempts to connect to configured WiFi network
|
|
2. If connection fails, creates an access point
|
|
3. Hostname is automatically generated from MAC address
|
|
|
|
## 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.
|
|
|
|
### TaskManager Features
|
|
|
|
- **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 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
|
|
|
|
To add custom tasks to your SPORE system:
|
|
|
|
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);
|
|
```
|
|
|
|
3. **The TaskManager handles the rest** - automatic execution, lifecycle management, and monitoring.
|
|
|
|
### Task Configuration Options
|
|
|
|
When registering tasks, you can specify:
|
|
|
|
- **Name**: Unique identifier for the task
|
|
- **Interval**: Execution frequency in milliseconds
|
|
- **Enabled**: Whether the task starts enabled (default: true)
|
|
- **AutoStart**: Whether to start automatically (default: true)
|
|
|
|
```cpp
|
|
taskManager.registerTask("delayed_task", 5000, taskFunction, true, false);
|
|
// Creates a task that's enabled but won't auto-start
|
|
```
|
|
|
|
## Current Limitations
|
|
|
|
- WiFi credentials are hardcoded in `Config.cpp` (should be configurable)
|
|
- Limited error handling for network failures
|
|
- No persistent storage for configuration
|
|
- Basic health monitoring without advanced metrics
|
|
|
|
## 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
|
|
```
|
|
|
|
## Contributing
|
|
|
|
1. Fork the repository
|
|
2. Create a feature branch
|
|
3. Make your changes
|
|
4. Test thoroughly on ESP8266 hardware
|
|
5. Submit a pull request
|
|
|
|
## License
|
|
|
|
[Add your license information here]
|
|
|
|
## Acknowledgments
|
|
|
|
- Built with [PlatformIO](https://platformio.org/)
|
|
- Uses [TaskScheduler](https://github.com/arkhipenko/TaskScheduler) for cooperative multitasking
|
|
- [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) for HTTP API
|
|
- [ArduinoJson](https://arduinojson.org/) for JSON processing |