Skip to content

OID Override

Set or update the override OID for a device (object) or its related objects. This endpoint allows you to change the OID value used for a specific device identified by UID or OID.

Request

http
PUT /api/oid-override

Authentication Required: Must include JWT token in Authorization header.

Required Scope: objects

Content-Type: application/json

Request Body:

json
{
  "uid": "ABCDEF123456",           // hex string, optional
  "oid": "1234567890",             // hex string, optional  
  "related_oid": "9876543210",     // hex string, optional
  "new_override_oid": "1122334455" // hex string, required
}

Parameter Logic:

  • UID Priority: When uid is provided, oid is ignored (UID takes precedence)
  • OID Fallback: oid is only used when uid is empty/not provided
  • Override Target:
    • If related_oid is specified → Updates the related object's OID override
    • If related_oid is not specified → Updates the main device's OID override
  • At least one of uid or oid must be provided
  • new_override_oid is always required

Request Examples

Set Override OID for Main Device by UID

bash
curl -X PUT "http://your-server-ip:port/api/oid-override" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "uid": "ABCDEF123456",
       "new_override_oid": "1122334455"
     }'

Set Override OID for Main Device by OID

bash
curl -X PUT "http://your-server-ip:port/api/oid-override" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "oid": "1234567890",
       "new_override_oid": "1122334455"
     }'
bash
curl -X PUT "http://your-server-ip:port/api/oid-override" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "uid": "ABCDEF123456",
       "related_oid": "9876543210",
       "new_override_oid": "1122334455"
     }'
bash
curl -X PUT "http://your-server-ip:port/api/oid-override" \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{
       "oid": "1234567890",
       "related_oid": "9876543210",
       "new_override_oid": "1122334455"
     }'

Response

Success (200 OK)

json
{
  "success": true
}

Error Responses

All error responses are returned as JSON:

400 Bad Request

json
{
  "error": "Invalid data"
}
json
{
  "error": "UID or OID must be provided"
}
json
{
  "error": "New override OID is required"
}
json
{
  "error": "UID is too long"
}
json
{
  "error": "UID must be numeric"
}
json
{
  "error": "UID must be hexadecimal"
}
json
{
  "error": "UID parse error"
}
json
{
  "error": "Invalid OID"
}
json
{
  "error": "Invalid related_oid"
}
json
{
  "error": "Invalid new_override_oid"
}

401 Unauthorized

json
{
  "error": "NOT_LOGGED_IN"
}

403 Forbidden

json
{
  "error": "FORBIDDEN"
}

405 Method Not Allowed

json
{
  "error": "Method Not Allowed"
}

503 Service Unavailable

json
{
  "error": "Database is not ready"
}

Parameter Precedence and Override Target

Parameter Priority Rules:

  1. UID Priority: When uid is provided, oid is completely ignored
  2. OID Fallback: oid is only used when uid is empty or not provided
  3. Override Target Logic: related_oid determines which object gets the override

Override Behavior:

  • uid=ABC123&new_override_oid=555 → Sets override OID 555 for main device ABC123 (oid ignored if present)
  • oid=123456&new_override_oid=555 (no uid) → Sets override OID 555 for main device with OID 123456
  • uid=ABC123&related_oid=XYZ789&new_override_oid=555 → Sets override OID 555 for related object XYZ789 of device ABC123
  • oid=123456&related_oid=XYZ789&new_override_oid=555 (no uid) → Sets override OID 555 for related object XYZ789 of device with OID 123456

Important Notes:

  • The override affects the OID value used for the specified object
  • Main device identification follows UID priority over OID
  • Related objects can have independent OID overrides from their parent device

Usage Examples

Basic OID Override

javascript
async function setOidOverride(uid = null, oid = null, relatedOid = null, newOverrideOid) {
  // Validate required parameters
  if (!uid && !oid) {
    throw new Error('At least one of uid or oid must be provided');
  }
  
  if (!newOverrideOid) {
    throw new Error('new_override_oid is required');
  }
  
  const payload = {
    new_override_oid: newOverrideOid
  };
  
  if (uid) payload.uid = uid;
  if (oid && !uid) payload.oid = oid; // Only include OID if UID is not provided
  if (relatedOid) payload.related_oid = relatedOid;
  
  try {
    const response = await fetch('/api/oid-override', {
      method: 'PUT',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload)
    });
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(`HTTP ${response.status}: ${error.error}`);
    }
    
    const result = await response.json();
    console.log('OID override set successfully');
    return result;
  } catch (error) {
    console.error('Failed to set OID override:', error);
    throw error;
  }
}

OID Override Manager Class

javascript
class OidOverrideManager {
  constructor(token) {
    this.token = token;
  }
  
  async setMainDeviceOverrideByUid(uid, newOverrideOid) {
    console.log(`Setting OID override ${newOverrideOid} for main device UID ${uid}`);
    return await this.setOverride({ uid, newOverrideOid });
  }
  
  async setMainDeviceOverrideByOid(oid, newOverrideOid) {
    console.log(`Setting OID override ${newOverrideOid} for main device OID ${oid}`);
    return await this.setOverride({ oid, newOverrideOid });
  }
  
  async setRelatedObjectOverrideByUid(parentUid, relatedOid, newOverrideOid) {
    console.log(`Setting OID override ${newOverrideOid} for related object ${relatedOid} of device UID ${parentUid}`);
    return await this.setOverride({ uid: parentUid, relatedOid, newOverrideOid });
  }
  
  async setRelatedObjectOverrideByOid(parentOid, relatedOid, newOverrideOid) {
    console.log(`Setting OID override ${newOverrideOid} for related object ${relatedOid} of device OID ${parentOid}`);
    return await this.setOverride({ oid: parentOid, relatedOid, newOverrideOid });
  }
  
  async setOverride({ uid = null, oid = null, relatedOid = null, newOverrideOid }) {
    const payload = {
      new_override_oid: newOverrideOid
    };
    
    if (uid) {
      payload.uid = uid;
      if (oid) {
        console.warn('Both UID and OID provided - OID will be ignored, using UID only');
      }
    } else if (oid) {
      payload.oid = oid;
    }
    
    if (relatedOid) {
      payload.related_oid = relatedOid;
    }
    
    const response = await fetch('/api/oid-override', {
      method: 'PUT',
      headers: {
        'Authorization': `Bearer ${this.token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(payload)
    });
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(`Override failed: ${error.error}`);
    }
    
    return await response.json();
  }
}

// Usage
const overrideManager = new OidOverrideManager(authToken);

// Set override for main device
await overrideManager.setMainDeviceOverrideByUid('ABC123', '1122334455');

// Set override for main device by OID (when UID not available)
await overrideManager.setMainDeviceOverrideByOid('1234567890', '1122334455');

// Set override for related object
await overrideManager.setRelatedObjectOverrideByUid('ABC123', 'SENSOR001', '1122334455');

Batch Override Operations

javascript
class BatchOidOverrideManager {
  constructor(token) {
    this.token = token;
    this.overrideManager = new OidOverrideManager(token);
  }
  
  async setMultipleOverrides(overrideOperations, confirmCallback = null) {
    const results = [];
    
    for (const operation of overrideOperations) {
      try {
        // Optional confirmation for each override
        if (confirmCallback && !await confirmCallback(operation)) {
          results.push({
            operation: operation,
            status: 'skipped',
            reason: 'User cancelled'
          });
          continue;
        }
        
        const result = await this.overrideManager.setOverride(operation);
        results.push({
          operation: operation,
          status: 'success',
          result: result
        });
        
        const target = operation.relatedOid ? `related object ${operation.relatedOid}` : 'main device';
        const identifier = operation.uid || operation.oid;
        console.log(`✓ Set OID override ${operation.newOverrideOid} for ${target} (${identifier})`);
        
      } catch (error) {
        results.push({
          operation: operation,
          status: 'error',
          error: error.message
        });
        
        const target = operation.relatedOid ? `related object ${operation.relatedOid}` : 'main device';
        const identifier = operation.uid || operation.oid;
        console.error(`✗ Failed to set override for ${target} (${identifier}): ${error.message}`);
      }
    }
    
    return results;
  }
  
  async setDeviceAndComponentOverrides(deviceUid, mainOverrideOid, componentOverrides) {
    const operations = [
      // Main device override
      { uid: deviceUid, newOverrideOid: mainOverrideOid }
    ];
    
    // Add component overrides
    for (const component of componentOverrides) {
      operations.push({
        uid: deviceUid,
        relatedOid: component.relatedOid,
        newOverrideOid: component.newOverrideOid
      });
    }
    
    return await this.setMultipleOverrides(operations);
  }
}

// Usage
const batchOverride = new BatchOidOverrideManager(authToken);

// Set overrides for device and its components
const componentOverrides = [
  { relatedOid: 'SENSOR001', newOverrideOid: 'AAAA0001' },
  { relatedOid: 'MODULE001', newOverrideOid: 'BBBB0001' },
  { relatedOid: 'GPS001', newOverrideOid: 'CCCC0001' }
];

const results = await batchOverride.setDeviceAndComponentOverrides(
  'ABC123',           // Device UID
  '1122334455',       // Main device override OID
  componentOverrides  // Component overrides
);

Error Handling and Validation

javascript
class OidOverrideValidator {
  static validateHexString(value, fieldName) {
    if (!value) return true; // Optional fields
    
    // Check hex format
    if (!/^[0-9A-Fa-f]+$/.test(value)) {
      throw new Error(`${fieldName} must be in hexadecimal format`);
    }
    
    // Check length (adjust based on your system requirements)
    if (value.length < 6 || value.length > 16) {
      throw new Error(`${fieldName} length must be between 6 and 16 characters`);
    }
    
    return true;
  }
  
  static validateParameters(uid, oid, relatedOid, newOverrideOid) {
    // At least one identifier required
    if (!uid && !oid) {
      throw new Error('At least one of uid or oid must be provided');
    }
    
    // New override OID is required
    if (!newOverrideOid) {
      throw new Error('new_override_oid is required');
    }
    
    // Warn if both UID and OID provided
    if (uid && oid) {
      console.warn('Both UID and OID provided - OID will be ignored, using UID only');
    }
    
    this.validateHexString(uid, 'UID');
    this.validateHexString(oid, 'OID');
    this.validateHexString(relatedOid, 'Related OID');
    this.validateHexString(newOverrideOid, 'New Override OID');
    
    return true;
  }
}

// Usage with validation
async function safeSetOidOverride(uid, oid, relatedOid, newOverrideOid) {
  try {
    // Validate parameters
    OidOverrideValidator.validateParameters(uid, oid, relatedOid, newOverrideOid);
    
    // Proceed with override
    return await setOidOverride(uid, oid, relatedOid, newOverrideOid);
  } catch (error) {
    console.error('Validation failed:', error.message);
    throw error;
  }
}

Override Management Dashboard

javascript
class OidOverrideDashboard {
  constructor(token) {
    this.token = token;
    this.overrideManager = new OidOverrideManager(token);
  }
  
  async showOverrideForm(deviceInfo) {
    const form = {
      deviceUid: deviceInfo.uid,
      deviceOid: deviceInfo.oid,
      currentOverride: deviceInfo.override_oid,
      relatedObjects: deviceInfo.related_objects || []
    };
    
    return form;
  }
  
  async applyOverrideFromForm(formData) {
    const operations = [];
    
    // Main device override
    if (formData.mainDeviceOverride) {
      operations.push({
        uid: formData.deviceUid,
        newOverrideOid: formData.mainDeviceOverride
      });
    }
    
    // Related object overrides
    for (const relatedOverride of formData.relatedOverrides || []) {
      if (relatedOverride.newOverrideOid) {
        operations.push({
          uid: formData.deviceUid,
          relatedOid: relatedOverride.relatedOid,
          newOverrideOid: relatedOverride.newOverrideOid
        });
      }
    }
    
    // Apply all overrides
    const results = [];
    for (const operation of operations) {
      try {
        const result = await this.overrideManager.setOverride(operation);
        results.push({ operation, success: true, result });
      } catch (error) {
        results.push({ operation, success: false, error: error.message });
      }
    }
    
    return results;
  }
}

Security Considerations

Override Validation

javascript
async function validateAndSetOverride(uid, oid, relatedOid, newOverrideOid) {
  // Validate override OID format and range
  if (!newOverrideOid.match(/^[0-9A-Fa-f]{8,16}$/)) {
    throw new Error('Invalid override OID format');
  }
  
  // Check for conflicts with existing OIDs
  const existingObjects = await getObjects();
  const conflictingObject = existingObjects.find(obj => 
    obj.oid === newOverrideOid || obj.override_oid === newOverrideOid
  );
  
  if (conflictingObject) {
    throw new Error(`Override OID ${newOverrideOid} conflicts with existing object`);
  }
  
  return await setOidOverride(uid, oid, relatedOid, newOverrideOid);
}

Audit Logging

javascript
class OverrideAuditLogger {
  static async logOverride(uid, oid, relatedOid, newOverrideOid, success, error = null) {
    const logEntry = {
      timestamp: new Date().toISOString(),
      action: 'oid_override',
      target: {
        uid: uid || null,
        oid: oid || null,
        related_oid: relatedOid || null,
        new_override_oid: newOverrideOid
      },
      success: success,
      error: error,
      user: this.getCurrentUser()
    };
    
    console.log('OVERRIDE_AUDIT:', JSON.stringify(logEntry));
    
    // Send to audit service
    try {
      await fetch('/api/audit/log', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(logEntry)
      });
    } catch (auditError) {
      console.error('Failed to log audit entry:', auditError);
    }
  }
  
  static getCurrentUser() {
    try {
      const token = localStorage.getItem('authToken');
      const payload = JSON.parse(atob(token.split('.')[1]));
      return payload.username || payload.sub;
    } catch {
      return 'unknown';
    }
  }
}

// Usage with audit logging
async function auditedSetOidOverride(uid, oid, relatedOid, newOverrideOid) {
  try {
    const result = await setOidOverride(uid, oid, relatedOid, newOverrideOid);
    await OverrideAuditLogger.logOverride(uid, oid, relatedOid, newOverrideOid, true);
    return result;
  } catch (error) {
    await OverrideAuditLogger.logOverride(uid, oid, relatedOid, newOverrideOid, false, error.message);
    throw error;
  }
}

Important Notes

  • Scope Required: Users must have the objects scope to access this endpoint
  • Override Target: related_oid determines whether main device or related object gets the override
  • Parameter Precedence: UID always takes precedence over OID when both are provided
  • Hex Format: All OID and UID values must be valid hexadecimal strings
  • JSON Request: Request body must be valid JSON (unlike some GET endpoints)
  • Database Dependency: Requires active database connection
  • Override Persistence: OID overrides are stored permanently until changed again
  • Conflict Prevention: Consider checking for OID conflicts before setting overrides

Released under the MIT License.