Skip to content

Configure Device

Send configuration commands to a device (object) identified by its partial UID. This endpoint is specifically designed for device configuration operations, distinct from general control commands.

Request

http
POST /api/config-device

Authentication Required: Must include JWT token in Authorization header.

Required Scope: device_control

Special Scope: If the user has the omit_mpass scope, the operation can proceed without requiring the master password.

Content-Type: application/json

Request Body

json
{
  "partial_uid": "ABCDEF123456",
  "request_id": "config-123",
  "data": "01020304ABCDEF",
  "cloud_access_code": "XYZ123",
  "response_required": true
}

Request Fields

FieldTypeRequiredDescription
partial_uidstringYesPartial UID of the target device (hex format)
request_idstringNoOptional identifier for tracking this configuration request
datastringYesConfiguration data to send to device (hex format)
cloud_access_codestringNoCloud access code for the device
response_requiredbooleanNoWhether to wait for device response (default: false)

Request Examples

Send Configuration Without Response

bash
curl -X POST "http://your-server-ip:port/api/config-device" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "partial_uid": "ABC123",
       "data": "050607080910"
     }'

Send Configuration and Wait for Response

bash
curl -X POST "http://your-server-ip:port/api/config-device" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "partial_uid": "ABC123",
       "request_id": "config-update-001",
       "data": "050607080910ABCDEF",
       "response_required": true
     }'

Response

Success (200 OK)

Configuration Applied Successfully:

json
{
  "partial_uid": "ABCDEF123456",
  "request_id": "config-123",
  "uid": "AABBCCDDEEFF",
  "data": ["050607080910", "ABCDEF123456"],
  "hw_id": "01",
  "oid": "1234567890"
}

Configuration Sent (No Response Required):

json
{
  "partial_uid": "ABCDEF123456",
  "request_id": "config-123",
  "status": "configuration_sent"
}

Response Fields

FieldTypeDescription
partial_uidstringThe queried partial UID
request_idstringRequest identifier (if provided)
uidstringFull unique identifier of the device
dataarrayArray of response data packets from device (hex format)
hw_idstringHardware identifier
oidstringObject identifier
statusstringOperation status (when no response required)

Error Responses

400 Bad Request (Plain Text)

FIELD_UID_IS_MISSING
INVALID_DATA
Invalid request

401 Unauthorized (Plain Text)

NOT_LOGGED_IN

403 Forbidden (Plain Text)

FORBIDDEN

405 Method Not Allowed (Plain Text)

Method Not Allowed

Timeout (JSON)

json
{
  "error": "NO_RESPONSE",
  "message": "Device did not respond within 10 seconds"
}

Configuration Errors (JSON)

json
{
  "error": "Device not connected"
}
json
{
  "error": "Invalid configuration format"
}

Usage Examples

Basic Device Configuration

javascript
async function configureDevice(partialUid, configData, waitForResponse = false) {
  try {
    const response = await fetch('/api/config-device', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        partial_uid: partialUid,
        data: configData,
        response_required: waitForResponse,
        request_id: `config-${Date.now()}`
      })
    });
    
    if (!response.ok) {
      const error = await response.text();
      throw new Error(`HTTP ${response.status}: ${error}`);
    }
    
    const result = await response.json();
    
    if (waitForResponse && result.data) {
      console.log(`Device ${partialUid} configuration response:`, result.data);
    } else {
      console.log(`Configuration sent to device ${partialUid}`);
    }
    
    return result;
  } catch (error) {
    console.error('Device configuration failed:', error);
    throw error;
  }
}

Device Settings Update

javascript
class DeviceConfigurator {
  constructor(token) {
    this.token = token;
  }
  
  async updateDeviceSettings(partialUid, settings) {
    // Convert settings object to device-specific hex format
    const configData = this.encodeSettings(settings);
    
    try {
      const result = await this.sendConfiguration(partialUid, configData, true);
      
      if (result.data && result.data.length > 0) {
        // Parse configuration confirmation
        const confirmation = this.parseConfigResponse(result.data[0]);
        console.log(`Device ${partialUid} configuration updated:`, confirmation);
        return confirmation;
      }
      
      throw new Error('No configuration confirmation received');
    } catch (error) {
      console.error(`Failed to configure device ${partialUid}:`, error);
      throw error;
    }
  }
  
  async sendConfiguration(partialUid, data, waitForResponse = false) {
    const response = await fetch('/api/config-device', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        partial_uid: partialUid,
        data: data,
        response_required: waitForResponse,
        request_id: `config-${Date.now()}`
      })
    });
    
    if (!response.ok) {
      throw new Error(await response.text());
    }
    
    return await response.json();
  }
  
  encodeSettings(settings) {
    // Example: Convert settings to device protocol format
    // This would be device-specific implementation
    let configHex = '';
    
    // Configuration header
    configHex += '05'; // Config command
    
    // Ping interval (2 bytes)
    if (settings.pingInterval) {
      const interval = settings.pingInterval.toString(16).padStart(4, '0');
      configHex += interval;
    }
    
    // Enable/disable features (1 byte)
    let features = 0;
    if (settings.enableGPS) features |= 0x01;
    if (settings.enableSMS) features |= 0x02;
    if (settings.enableAlerts) features |= 0x04;
    configHex += features.toString(16).padStart(2, '0');
    
    return configHex.toUpperCase();
  }
  
  parseConfigResponse(hexData) {
    // Example: Parse device configuration response
    return {
      status: hexData.substr(0, 2) === '06' ? 'success' : 'error',
      configApplied: hexData.substr(2, 2) === 'FF',
      deviceTime: parseInt(hexData.substr(4, 8), 16)
    };
  }
}

// Usage
const configurator = new DeviceConfigurator(authToken);

// Update device settings
await configurator.updateDeviceSettings('ABC123', {
  pingInterval: 300,
  enableGPS: true,
  enableSMS: true,
  enableAlerts: false
});

Batch Configuration

javascript
async function configureMultipleDevices(devices, configData) {
  const results = [];
  
  for (const device of devices) {
    try {
      const result = await configureDevice(device.partial_uid, configData, true);
      
      results.push({
        device: device.partial_uid,
        status: 'success',
        result: result,
        timestamp: new Date().toISOString()
      });
      
      // Small delay between configurations to avoid overwhelming devices
      await new Promise(resolve => setTimeout(resolve, 1000));
      
    } catch (error) {
      results.push({
        device: device.partial_uid,
        status: 'error',
        error: error.message,
        timestamp: new Date().toISOString()
      });
    }
  }
  
  return results;
}

// Usage
const deviceList = [
  { partial_uid: 'ABC123', type: 'sensor' },
  { partial_uid: 'DEF456', type: 'controller' },
  { partial_uid: 'GHI789', type: 'monitor' }
];

const commonConfig = '050A003C01'; // Example configuration
const results = await configureMultipleDevices(deviceList, commonConfig);

// Log results
results.forEach(result => {
  if (result.status === 'success') {
    console.log(`✓ Device ${result.device} configured successfully`);
  } else {
    console.log(`✗ Device ${result.device} failed: ${result.error}`);
  }
});

Configuration Validation

javascript
class ConfigurationValidator {
  static validateHexData(data) {
    // Check if valid hex string
    if (!/^[0-9A-Fa-f]+$/.test(data)) {
      throw new Error('Invalid hex format');
    }
    
    // Check minimum length for configuration commands
    if (data.length < 4) {
      throw new Error('Configuration data too short');
    }
    
    // Check if even length (complete bytes)
    if (data.length % 2 !== 0) {
      throw new Error('Configuration data must have even length');
    }
    
    return true;
  }
  
  static validateConfiguration(config) {
    // Validate configuration object
    if (!config.partial_uid) {
      throw new Error('Partial UID is required');
    }
    
    if (!config.data) {
      throw new Error('Configuration data is required');
    }
    
    this.validateHexData(config.data);
    
    return true;
  }
}

// Usage with validation
async function safeConfigureDevice(partialUid, configData) {
  try {
    // Validate before sending
    ConfigurationValidator.validateConfiguration({
      partial_uid: partialUid,
      data: configData
    });
    
    return await configureDevice(partialUid, configData, true);
  } catch (error) {
    console.error('Configuration validation failed:', error);
    throw error;
  }
}

Configuration Examples

Device Time Synchronization

javascript
async function syncDeviceTime(partialUid) {
  const currentTime = Math.floor(Date.now() / 1000);
  const timeHex = currentTime.toString(16).padStart(8, '0');
  const configData = `10${timeHex}`; // Command 0x10 + timestamp
  
  return await configureDevice(partialUid, configData, true);
}

Update Reporting Interval

javascript
async function setReportingInterval(partialUid, intervalMinutes) {
  const intervalHex = intervalMinutes.toString(16).padStart(4, '0');
  const configData = `20${intervalHex}`; // Command 0x20 + interval
  
  return await configureDevice(partialUid, configData, true);
}

Configure Alert Thresholds

javascript
async function setAlertThresholds(partialUid, thresholds) {
  let configData = '30'; // Command 0x30
  
  // Temperature threshold (1 byte, signed)
  const tempThreshold = (thresholds.temperature + 128) & 0xFF;
  configData += tempThreshold.toString(16).padStart(2, '0');
  
  // Humidity threshold (1 byte)
  configData += thresholds.humidity.toString(16).padStart(2, '0');
  
  // Battery threshold (1 byte, percentage)
  configData += thresholds.battery.toString(16).padStart(2, '0');
  
  return await configureDevice(partialUid, configData, true);
}

// Usage
await setAlertThresholds('ABC123', {
  temperature: 35,  // °C
  humidity: 80,     // %
  battery: 20       // %
});

Error Handling and Recovery

javascript
async function configureWithRetry(partialUid, configData, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const result = await configureDevice(partialUid, configData, true);
      
      // Verify configuration was applied
      if (result.data && result.data[0].startsWith('06')) {
        console.log(`Configuration successful on attempt ${attempt}`);
        return result;
      } else {
        throw new Error('Configuration not confirmed by device');
      }
    } catch (error) {
      console.log(`Configuration attempt ${attempt} failed:`, error.message);
      
      if (attempt === maxRetries) {
        throw new Error(`Configuration failed after ${maxRetries} attempts: ${error.message}`);
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Security and Best Practices

Configuration Logging

javascript
class ConfigurationLogger {
  static log(operation, partialUid, configData, result) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      operation: operation,
      device: partialUid,
      config: configData,
      result: result.status || 'unknown',
      user: this.getCurrentUser() // Implement based on your auth system
    };
    
    // Send to audit log
    console.log('CONFIG_AUDIT:', JSON.stringify(logEntry));
  }
  
  static getCurrentUser() {
    // Extract user from JWT token
    try {
      const token = localStorage.getItem('authToken');
      const payload = JSON.parse(atob(token.split('.')[1]));
      return payload.username || payload.sub;
    } catch {
      return 'unknown';
    }
  }
}

// Use in configuration functions
const result = await configureDevice(partialUid, configData);
ConfigurationLogger.log('device_config', partialUid, configData, result);

Important Notes

  • Scope Required: Users must have the device_control scope
  • Configuration vs Control: Use this endpoint for device settings, use /api/control-device for operational commands
  • Hex Format: All configuration data must be in valid hexadecimal format
  • Response Timeout: 10 seconds maximum wait time for device responses
  • Validation: Always validate configuration data before sending
  • Device Protocol: Configuration format depends on specific device protocol implementation

Released under the MIT License.