feat: basic cluster overview
This commit is contained in:
147
src/client/README.md
Normal file
147
src/client/README.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# SPORE API Client
|
||||
|
||||
A JavaScript client for the SPORE Embedded System API, generated from the OpenAPI specification.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Setup
|
||||
|
||||
```javascript
|
||||
const SporeApiClient = require('./index');
|
||||
|
||||
// Create client instance with default base URL
|
||||
const client = new SporeApiClient();
|
||||
|
||||
// Or specify a custom base URL
|
||||
const client = new SporeApiClient('http://192.168.1.100');
|
||||
```
|
||||
|
||||
### API Methods
|
||||
|
||||
#### Task Management
|
||||
|
||||
```javascript
|
||||
// Get comprehensive task status
|
||||
const taskStatus = await client.getTaskStatus();
|
||||
|
||||
// Control individual tasks
|
||||
await client.controlTask('heartbeat', 'disable');
|
||||
await client.controlTask('discovery_send', 'start');
|
||||
await client.controlTask('status_update', 'status');
|
||||
```
|
||||
|
||||
#### System Status
|
||||
|
||||
```javascript
|
||||
// Get system status and API information
|
||||
const systemStatus = await client.getSystemStatus();
|
||||
|
||||
// Get device information
|
||||
const deviceInfo = await client.getDeviceInfo();
|
||||
```
|
||||
|
||||
#### Cluster Management
|
||||
|
||||
```javascript
|
||||
// Get cluster discovery information
|
||||
const discovery = await client.getClusterDiscovery();
|
||||
|
||||
// Get cluster status
|
||||
const clusterStatus = await client.getClusterStatus();
|
||||
```
|
||||
|
||||
#### Network Management
|
||||
|
||||
```javascript
|
||||
// Get network configuration
|
||||
const networkConfig = await client.getNetworkConfig();
|
||||
|
||||
// Update network configuration
|
||||
await client.updateNetworkConfig({
|
||||
wifi: {
|
||||
ssid: 'MyNetwork',
|
||||
password: 'password123'
|
||||
}
|
||||
});
|
||||
|
||||
// Scan for WiFi networks
|
||||
const networks = await client.getWifiNetworks();
|
||||
|
||||
// Connect to WiFi network
|
||||
await client.connectWifi('MyNetwork', 'password123');
|
||||
```
|
||||
|
||||
#### System Health
|
||||
|
||||
```javascript
|
||||
// Get OTA update status
|
||||
const otaStatus = await client.getOtaStatus();
|
||||
|
||||
// Get health metrics
|
||||
const healthMetrics = await client.getHealthMetrics();
|
||||
|
||||
// Get system logs
|
||||
const logs = await client.getSystemLogs({
|
||||
level: 'INFO',
|
||||
limit: 100,
|
||||
offset: 0
|
||||
});
|
||||
```
|
||||
|
||||
#### Device Control
|
||||
|
||||
```javascript
|
||||
// Restart the device
|
||||
await client.restartDevice();
|
||||
|
||||
// Factory reset (use with caution!)
|
||||
await client.factoryReset();
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
```javascript
|
||||
try {
|
||||
const status = await client.getTaskStatus();
|
||||
console.log('Task status:', status);
|
||||
} catch (error) {
|
||||
console.error('API request failed:', error.message);
|
||||
}
|
||||
```
|
||||
|
||||
### Response Format
|
||||
|
||||
All API methods return promises that resolve to the response data. The client automatically:
|
||||
|
||||
- Parses JSON responses
|
||||
- Handles HTTP error status codes
|
||||
- Provides meaningful error messages
|
||||
- Supports both CommonJS and ES modules
|
||||
|
||||
## API Endpoints
|
||||
|
||||
The client supports all endpoints defined in the OpenAPI specification:
|
||||
|
||||
- **Task Management**: `/api/tasks/status`, `/api/tasks/control`
|
||||
- **System Status**: `/api/node/status`
|
||||
- **Cluster Management**: `/api/cluster/discovery`, `/api/cluster/status`
|
||||
- **OTA Updates**: `/api/ota/status`
|
||||
- **Health Monitoring**: `/api/health/metrics`
|
||||
- **System Logs**: `/api/system/logs`
|
||||
- **Network Management**: `/api/network/config`, `/api/network/wifi/*`
|
||||
- **Device Control**: `/api/device/info`, `/api/device/restart`, `/api/device/factory-reset`
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js 18.0.0 or higher
|
||||
- Fetch API support (built-in for Node.js 18+)
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file for details.
|
||||
74
src/client/example.js
Normal file
74
src/client/example.js
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Example usage of the SPORE API Client
|
||||
*/
|
||||
|
||||
const SporeApiClient = require('./index');
|
||||
|
||||
async function main() {
|
||||
// Create client instance
|
||||
const client = new SporeApiClient('http://10.0.1.60');
|
||||
|
||||
console.log('🚀 SPORE API Client Example');
|
||||
console.log('============================\n');
|
||||
|
||||
try {
|
||||
// Example 1: Get system status
|
||||
console.log('1. Getting system status...');
|
||||
const systemStatus = await client.getSystemStatus();
|
||||
console.log('✅ System Status:', JSON.stringify(systemStatus, null, 2));
|
||||
console.log('');
|
||||
|
||||
// Example 2: Get task status
|
||||
console.log('2. Getting task status...');
|
||||
const taskStatus = await client.getTaskStatus();
|
||||
console.log('✅ Task Status:', JSON.stringify(taskStatus, null, 2));
|
||||
console.log('');
|
||||
|
||||
// Example 3: Get device information
|
||||
console.log('3. Getting device information...');
|
||||
const deviceInfo = await client.getDeviceInfo();
|
||||
console.log('✅ Device Info:', JSON.stringify(deviceInfo, null, 2));
|
||||
console.log('');
|
||||
|
||||
// Example 4: Get cluster discovery
|
||||
console.log('4. Getting cluster discovery...');
|
||||
const discovery = await client.getClusterDiscovery();
|
||||
console.log('✅ Cluster Discovery:', JSON.stringify(discovery, null, 2));
|
||||
console.log('');
|
||||
|
||||
// Example 5: Get network configuration
|
||||
console.log('5. Getting network configuration...');
|
||||
const networkConfig = await client.getNetworkConfig();
|
||||
console.log('✅ Network Config:', JSON.stringify(networkConfig, null, 2));
|
||||
console.log('');
|
||||
|
||||
// Example 6: Get health metrics
|
||||
console.log('6. Getting health metrics...');
|
||||
const healthMetrics = await client.getHealthMetrics();
|
||||
console.log('✅ Health Metrics:', JSON.stringify(healthMetrics, null, 2));
|
||||
console.log('');
|
||||
|
||||
// Example 7: Get system logs (limited to 5 entries)
|
||||
console.log('7. Getting recent system logs...');
|
||||
const logs = await client.getSystemLogs({ limit: 5 });
|
||||
console.log('✅ System Logs:', JSON.stringify(logs, null, 2));
|
||||
console.log('');
|
||||
|
||||
console.log('🎉 All API calls completed successfully!');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error occurred:', error.message);
|
||||
|
||||
if (error.message.includes('fetch')) {
|
||||
console.log('\n💡 Make sure the SPORE device is running and accessible at the specified IP address.');
|
||||
console.log('💡 Check if the device is powered on and connected to the network.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run the example if this file is executed directly
|
||||
if (require.main === module) {
|
||||
main().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = { main };
|
||||
205
src/client/index.js
Normal file
205
src/client/index.js
Normal file
@@ -0,0 +1,205 @@
|
||||
/**
|
||||
* SPORE API Client
|
||||
* Generated from api/openapi.yaml
|
||||
*/
|
||||
|
||||
class SporeApiClient {
|
||||
constructor(baseUrl = 'http://10.0.1.60') {
|
||||
this.baseUrl = baseUrl;
|
||||
this.defaultHeaders = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP request
|
||||
* @param {string} method - HTTP method
|
||||
* @param {string} path - API path
|
||||
* @param {Object} options - Request options
|
||||
* @returns {Promise<Object>} Response data
|
||||
*/
|
||||
async request(method, path, options = {}) {
|
||||
const url = `${this.baseUrl}${path}`;
|
||||
const config = {
|
||||
method,
|
||||
headers: { ...this.defaultHeaders, ...options.headers },
|
||||
...options
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, config);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
// Handle empty responses
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
return await response.text();
|
||||
} catch (error) {
|
||||
throw new Error(`Request failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comprehensive task status
|
||||
* @returns {Promise<Object>} Task status response
|
||||
*/
|
||||
async getTaskStatus() {
|
||||
return this.request('GET', '/api/tasks/status');
|
||||
}
|
||||
|
||||
/**
|
||||
* Control individual task operations
|
||||
* @param {string} task - Name of the task to control
|
||||
* @param {string} action - Action to perform (enable, disable, start, stop, status)
|
||||
* @returns {Promise<Object>} Task control response
|
||||
*/
|
||||
async controlTask(task, action) {
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('task', task);
|
||||
formData.append('action', action);
|
||||
|
||||
return this.request('POST', '/api/tasks/control', {
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: formData.toString()
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system status and API information
|
||||
* @returns {Promise<Object>} System status response
|
||||
*/
|
||||
async getSystemStatus() {
|
||||
return this.request('GET', '/api/node/status');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cluster discovery information
|
||||
* @returns {Promise<Object>} Cluster discovery response
|
||||
*/
|
||||
async getClusterDiscovery() {
|
||||
return this.request('GET', '/api/cluster/members');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cluster status
|
||||
* @returns {Promise<Object>} Cluster status response
|
||||
*/
|
||||
async getClusterStatus() {
|
||||
return this.request('GET', '/api/cluster/members');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OTA update status
|
||||
* @returns {Promise<Object>} OTA update status response
|
||||
*/
|
||||
async getOtaStatus() {
|
||||
return this.request('GET', '/api/ota/status');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system health metrics
|
||||
* @returns {Promise<Object>} Health metrics response
|
||||
*/
|
||||
async getHealthMetrics() {
|
||||
return this.request('GET', '/api/health/metrics');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get system logs
|
||||
* @param {Object} options - Query options
|
||||
* @returns {Promise<Object>} System logs response
|
||||
*/
|
||||
async getSystemLogs(options = {}) {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (options.level) queryParams.append('level', options.level);
|
||||
if (options.limit) queryParams.append('limit', options.limit);
|
||||
if (options.offset) queryParams.append('offset', options.offset);
|
||||
|
||||
const queryString = queryParams.toString();
|
||||
const path = queryString ? `/api/system/logs?${queryString}` : '/api/system/logs';
|
||||
|
||||
return this.request('GET', path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get network configuration
|
||||
* @returns {Promise<Object>} Network configuration response
|
||||
*/
|
||||
async getNetworkConfig() {
|
||||
return this.request('GET', '/api/network/config');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update network configuration
|
||||
* @param {Object} config - Network configuration
|
||||
* @returns {Promise<Object>} Update response
|
||||
*/
|
||||
async updateNetworkConfig(config) {
|
||||
return this.request('POST', '/api/network/config', {
|
||||
body: JSON.stringify(config)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get WiFi networks
|
||||
* @returns {Promise<Object>} WiFi networks response
|
||||
*/
|
||||
async getWifiNetworks() {
|
||||
return this.request('GET', '/api/network/wifi/scan');
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to WiFi network
|
||||
* @param {string} ssid - Network SSID
|
||||
* @param {string} password - Network password
|
||||
* @returns {Promise<Object>} Connection response
|
||||
*/
|
||||
async connectWifi(ssid, password) {
|
||||
return this.request('POST', '/api/network/wifi/connect', {
|
||||
body: JSON.stringify({ ssid, password })
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get device information
|
||||
* @returns {Promise<Object>} Device info response
|
||||
*/
|
||||
async getDeviceInfo() {
|
||||
return this.request('GET', '/api/device/info');
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart the device
|
||||
* @returns {Promise<Object>} Restart response
|
||||
*/
|
||||
async restartDevice() {
|
||||
return this.request('POST', '/api/device/restart');
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory reset the device
|
||||
* @returns {Promise<Object>} Factory reset response
|
||||
*/
|
||||
async factoryReset() {
|
||||
return this.request('POST', '/api/device/factory-reset');
|
||||
}
|
||||
}
|
||||
|
||||
// Export the client class
|
||||
module.exports = SporeApiClient;
|
||||
|
||||
// Also export for ES modules if available
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
exports = module.exports = SporeApiClient;
|
||||
}
|
||||
}
|
||||
27
src/client/package.json
Normal file
27
src/client/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "spore-api-client",
|
||||
"version": "1.0.0",
|
||||
"description": "JavaScript client for the SPORE Embedded System API",
|
||||
"main": "index.js",
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"spore",
|
||||
"api",
|
||||
"client",
|
||||
"embedded",
|
||||
"iot",
|
||||
"esp8266"
|
||||
],
|
||||
"author": "SPORE Development Team",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.dcentral.systems/iot/spore"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user