Thingsee CBOR to JSON Conversion

Complete guide for converting Thingsee CBOR binary messages to JSON format

Overview

Thingsee sensors transmit data using CBOR (Concise Binary Object Representation), a compact binary format optimized for low-power wireless communication. Applications and cloud platforms consume this data as JSON, requiring conversion at the gateway or backend level.

This guide provides:

  • Complete CBOR-to-JSON mapping tables
  • Conversion examples with real sensor messages
  • Decoder implementations in Python and JavaScript
  • Wirepas endpoint configuration details

Why CBOR?

CBOR reduces message size by ~60-70% compared to JSON, which:

  • Extends battery life (fewer radio transmissions)
  • Reduces network bandwidth consumption
  • Enables more frequent sensor updates
  • Supports larger mesh networks

Message Structure

CBOR Format (Sensor → Gateway)

CBOR messages contain only essential sensor data:

Header fields:
- tsmId (CBOR index 1): Message ID
- tsmEv (CBOR index 2): Event ID

Data fields:
- Device-specific measurements (CBOR indexes 20-1211)

Gateway or backend must add:

  • tsmTs - Timestamp (from Wirepas time-in-transit)
  • tsmTuid - Device serial (from Wirepas node ID)
  • tsmGw - Gateway identifier (optional)

JSON Format (Application Layer)

Complete JSON structure with all fields populated:

[{
    "tsmId": 13100,
    "tsmEv": 10,
    "tsmTs": 1492603998,
    "tsmTuid": "TSPR04123456",
    "tsmGw": "TSGW2G987654",
    "tsmAp": "occupancy-monitoring",
    "moveCount": 7
}]

CBOR Mapping Tables

Header Fields

JSON PropertyCBOR IndexOriginExampleDescription
tsmId1Sensor13100Message ID identifying data structure
tsmEv2Sensor10Event ID indicating trigger reason
tsmTs3Gateway1492844596UTC timestamp in seconds
tsmTuid4Gateway“TSPR04123”Device serial number
tsmGw5Gateway“TSGW2G321”Gateway identifier
tsmAp6Cloud“demo-app”Application context
tsmDstTuid7Cloud“TSGW2G321”Destination device (for commands)
tsmGwTs8Cloud1492844601Gateway receipt timestamp
tsmCloudTs9Cloud1492844602Cloud receipt timestamp

Data Fields (Common)

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
pwr2000Power status (0=OFF, 1=ON)
batl211882Battery level (88.2% in example)
chrg2202Charger status (0=Not connected, 1=Charging, 2=Connected not charging)
requestTsmId2301310Requested message ID from cloud
timestamp2401493312188Epoch timestamp
transactionId2501493312188Transaction ID for request-response sync
uptime2603600Seconds since device startup
status2700Status code (message-specific)

Sensor Measurements

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
temp301224Temperature in Celsius (22.4°C in example)
lght310720Light in lux
humd321724Humidity 0-100% (72.4% in example)
airp333102092358Air pressure in Pascals (102092.358 Pa in example)
level3400Level (message-specific unit)
min3500Minimum value (message-specific)
max3600Maximum value (message-specific)
mode3700Operating mode (message-specific)
state3800Device state (message-specific)
pressure393102092358Pressure in Pascals

Motion and Position

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
accx4000X-axis acceleration
accy410-100Y-axis acceleration
accz420900Z-axis acceleration
move4301Movement detected (0=No, 1=Yes)
moveCount4407Movement count since last report
dist450152Distance in millimeters
hall4601Hall sensor state (0=Open, 1=Closed)
hallCount4701Hall sensor state change count
switch4801Switch state (0=Open, 1=Closed)
switchCount4901Switch state change count
gforce5601012G-force sum vector in milli-g
gforceMax5703567Maximum g-force in milli-g
angle1901900Angular position in degrees (90.0° in example)
duration19101800Duration in seconds

Network and Device Info

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
voltage5963000000Voltage in volts (3.0V in example)
wpnode60N/A‘123456’Wirepas node ID (string)
rssi61078RSSI value (0-255 scale)
tuid62N/A‘S3R14LNUMB3R’Cloud identifier (string)
rssiDbm650-70RSSI in dBm
swVersion70N/A‘sensorFW1.0.2’Software version (string)
modelCode71N/A‘TSGW2G’Product model code (string)

Activity and Energy

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
activityLevel81398000Activity level indicator 0-100 (98.000 in example)
energyLevel8902647Cumulative energy volume as force vector sum
energyLevelThreshold29101Energy level threshold
activityLevelThreshold29231Activity level threshold

Air Quality

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
carbonDioxide2830624CO2 in ppm
tvoc284050Total VOC
carbonDioxideHysteresis281010CO2 hysteresis threshold
tvocHysteresis28205TVOC hysteresis threshold

Measurement Data

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
resistance11101000Resistance in ohms
index11201Index value
count11301Count value
messageIndex14601Message sequence index
deviceState14701Device state indicator
restartCount15401Device restart count
lastUpdate17000Time since last update
static17100Static indicator
length18100Length value
data182N/A-Generic data field
command183N/A-Command field
payload184N/A-Command payload

Configuration Parameters

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
measurementInterval256060Measurement interval in seconds
measurementFrequency257025Measurement frequency in Hz
reportInterval2580300Reporting interval in seconds
impactThresholdMin2590200Lower impact threshold in mG
impactThresholdMax26011000Upper impact threshold in mG
idleInterval26103600Idle interval in seconds
accelerometerMode26200Accelerometer configuration mode
threshold26300Generic threshold value
enableLed26400LED control setting
weatherMode26600Weather sensor configuration
hallMode26700Hall sensor configuration
leakageMode26800Leakage sensor configuration
autoCalibration269N/A-Auto-calibration setting
calibrationValue270N/A-Calibration value
filterValue271N/A-Filter value
commandId27201493312188Command transaction ID
temperatureMode27300Temperature sensor mode
intervalMultiplier27400Interval multiplier
temperatureHysteresis27515Temperature hysteresis (0.5°C in example)
humidityHysteresis276120Humidity hysteresis (2.0% in example)
pressureHysteresis277320000Pressure hysteresis (20 Pa in example)
lightHysteresis2780100Light hysteresis in lux
resistanceHysteresis279010000Resistance hysteresis in ohms
orientationHysteresis28005Orientation hysteresis in degrees
staticFilter28502Static filter setting
dynamicFilter28601Dynamic filter setting
samples28708Sample count
averaging28801Averaging setting
rounding28901Rounding setting
pressureCompensate29001Pressure compensation setting
autoRole54300Wirepas auto-role setting
lowLatency54400Wirepas low-latency setting

Profile and Statistics

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
profileId110000Configuration profile ID
tempMin11011-23Minimum temperature (-2.3°C in example)
tempMax11021156Maximum temperature (15.6°C in example)
humdMin11031556Minimum humidity (55.6% in example)
humdMax11041612Maximum humidity (61.2% in example)
fromTimestamp110501493312188Period start timestamp

Occupancy Histogram

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
histogram0100002Detection count in area index 0
histogram1100107Detection count in area index 1
histogram21002013Detection count in area index 2
histogram31003045Detection count in area index 3
histogram410040234Detection count in area index 4
histogram510050153Detection count in area index 5
histogram61006078Detection count in area index 6
histogram71007045Detection count in area index 7
histogram81008032Detection count in area index 8
histogram9100902Detection count in area index 9

People Counting

JSON PropertyCBOR IndexMultiplier (10^x)ExampleDescription
in1210010Ingress count (people entering)
out121108Egress count (people leaving)

Event IDs (tsmEv)

Event IDs indicate why the message was sent:

Event IDNameDescription
0No eventEvent data not applicable or unknown
7State change eventResult of a state change
8Key eventReactive events (sensor-triggered, key press)
9Threshold eventThreshold exceeded
10Timed eventStreaming event sent at defined intervals
11Thing powered ONDevice boot-up
12Thing powered OFFDevice powering off
13Thing controlled reset occurredControlled reset performed
14Thing uncontrolled reset occurredUncontrolled reset occurred
15Thing firmware updatedFirmware update completed
16Thing software configuration updatedSoftware configuration changed
17Network connectedConnected to gateway/network
18Network disconnectedDisconnected from gateway/network
19Assistance data requestedRequest for assistance data from cloud
20Assistance data responseResponse to assistance data request
21Power ON requestedCloud request to power ON
22Power OFF requestedCloud request to power OFF
23Reset requestedCloud request to reset
25Firmware update requestedCloud request for firmware update
26Software configuration update requestedCloud request for configuration update
27Diagnostics requestedCloud request to enable diagnostics
28Requested diagnostic eventRemotely enabled diagnostic event
29Error diagnostic eventCritical error report
30Application profile update requestedDevice must update behavior
31Application profile update responseResponse to profile update request
32Firmware information requestRequest for firmware information
33Firmware information responseResponse to firmware information request
34Timed diagnostics eventPeriodic diagnostic event
35Command requestCommand sent to device
36Command responseResponse to command

Conversion Examples

Example 1: Thingsee PRESENCE Occupancy

Raw hex message:

9f a3 01 19 33 2c 02 0a 18 2c 07 ff

Step 1: CBOR decode

[{1: 13100, 2: 10, 44: 7}]

Step 2: Apply CBOR index mapping

[{
  "tsmId": 13100,
  "tsmEv": 10,
  "moveCount": 7
}]

Step 3: Add gateway-originated fields

[{
  "tsmId": 13100,
  "tsmEv": 10,
  "tsmTs": 1492844596,
  "tsmTuid": "TSPR04123456",
  "tsmGw": "TSGW2G987654",
  "moveCount": 7
}]

Interpretation:

  • Device: Thingsee PRESENCE (message ID 13100)
  • Event: Timed event (event ID 10)
  • Data: 7 movements detected since last report

Example 2: Thingsee RADAR Occupancy

Raw hex message:

9f a5 01 19 6d 69 02 07 19 04 ff 19 06 21 18 26 01 18 2d 19 06 40 ff

Step 1: CBOR decode

[{1: 28009, 2: 7, 1279: 1569, 38: 1, 45: 1600}]

Step 2: Apply CBOR index mapping

[{
  "tsmId": 28009,
  "tsmEv": 7,
  "echo": 1569,
  "state": 1,
  "dist": 1600
}]

Note: Index 1279 (“echo”) is device-specific and not in the common mapping table. Refer to device-specific documentation for custom indexes.

Step 3: Add gateway fields and apply multipliers

[{
  "tsmId": 28009,
  "tsmEv": 7,
  "tsmTs": 1492844596,
  "tsmTuid": "TSRAD5123456",
  "dist": 1600,
  "echo": 1569,
  "state": 1
}]

Interpretation:

  • Device: Thingsee RADAR (message ID 28009)
  • Event: State change event (event ID 7)
  • Data: Object detected at 1600mm distance, occupied state

JSON configuration request:

{
  "tsmId": 1500,
  "tsmEv": 30,
  "transactionId": 1485925806,
  "measurementInterval": 30,
  "reportInterval": 300
}

Step 1: Convert to CBOR indexes

{1: 1500, 2: 30, 25: 1485925806, 256: 30, 258: 300}

Step 2: CBOR encode to binary

a5 01 19 05 dc 02 18 1e 18 19 1a 58 91 6d ae 19 01 00 18 1e 19 01 02 19 01 2c

Important: Wirepas endpoints must be 21/21 for sensor configuration messages.

Wirepas Endpoint Configuration

Thingsee sensors use different Wirepas endpoints depending on the CBOR format:

Endpoint 21/21 (Thingsee CBOR)

Use case: Standard Thingsee sensor messages

Format: CBOR with Thingsee message specification

MQTT topic structure:

haltian-iot/wirepas/gw-event/received_data/{gateway-id}/sink1/{network-id}/21/21

Characteristics:

  • Uses complete mapping table (indexes 1-1211)
  • Compatible with all Thingsee sensors
  • Standard for configuration (downlink) messages
  • Most common format in Haltian IoT deployments

Endpoint 247/255 (Wirepas CBOR)

Use case: Wirepas reference implementation format

Format: CBOR following Wirepas standard

MQTT topic structure:

haltian-iot/wirepas/gw-event/received_data/{gateway-id}/sink1/{network-id}/247/255

Characteristics:

  • May use different CBOR map version (5.1 vs 5.2)
  • Interoperable with Wirepas ecosystem devices
  • Different header structure compared to endpoint 21/21

Endpoint 238/238 (TLV Format)

Use case: Tag-Length-Value encoding (legacy)

Format: TLV binary format

MQTT topic structure:

haltian-iot/wirepas/gw-event/received_data/{gateway-id}/sink1/{network-id}/238/238

Characteristics:

  • Not CBOR format
  • Used by specific legacy devices
  • Requires separate decoder implementation

Configuration Requirements

For sensor configuration (downlink):

  • Endpoints must be 21/21 - sensors reject messages from other endpoints
  • Include transactionId (CBOR index 25) for request-response correlation
  • Sensor replies with same tsmId, all configuration fields populated with current values

For monitoring network traffic:

  • Subscribe to all endpoints: # wildcard
  • Filter by source endpoint to identify message format
  • Use appropriate decoder for each endpoint type

Decoder Implementations

Python Decoder

import cbor2
import struct
from datetime import datetime

# CBOR index to JSON property mapping
CBOR_INDEX_MAP = {
    # Header
    1: "tsmId",
    2: "tsmEv",
    3: "tsmTs",
    4: "tsmTuid",
    5: "tsmGw",
    6: "tsmAp",
    7: "tsmDstTuid",
    8: "tsmGwTs",
    9: "tsmCloudTs",
    
    # Common data fields
    20: "pwr",
    21: "batl",
    22: "chrg",
    23: "requestTsmId",
    24: "timestamp",
    25: "transactionId",
    26: "uptime",
    27: "status",
    
    # Sensor measurements
    30: "temp",
    31: "lght",
    32: "humd",
    33: "airp",
    34: "level",
    35: "min",
    36: "max",
    37: "mode",
    38: "state",
    39: "pressure",
    
    # Motion
    40: "accx",
    41: "accy",
    42: "accz",
    43: "move",
    44: "moveCount",
    45: "dist",
    46: "hall",
    47: "hallCount",
    48: "switch",
    49: "switchCount",
    56: "gforce",
    57: "gforceMax",
    
    # Network
    59: "voltage",
    60: "wpnode",
    61: "rssi",
    62: "tuid",
    65: "rssiDbm",
    70: "swVersion",
    71: "modelCode",
    
    # Activity
    81: "activityLevel",
    89: "energyLevel",
    
    # Configuration
    256: "measurementInterval",
    257: "measurementFrequency",
    258: "reportInterval",
    259: "impactThresholdMin",
    260: "impactThresholdMax",
    261: "idleInterval",
    262: "accelerometerMode",
    263: "threshold",
    264: "enableLed",
    
    # Air quality
    283: "carbonDioxide",
    284: "tvoc",
    
    # Histogram
    1000: "histogram0",
    1001: "histogram1",
    1002: "histogram2",
    1003: "histogram3",
    1004: "histogram4",
    1005: "histogram5",
    1006: "histogram6",
    1007: "histogram7",
    1008: "histogram8",
    1009: "histogram9",
    
    # People counting
    1210: "in",
    1211: "out",
}

# Multipliers for fields requiring decimal conversion
MULTIPLIERS = {
    "batl": 1,
    "temp": 1,
    "humd": 1,
    "airp": 3,
    "pressure": 3,
    "voltage": 6,
    "activityLevel": 3,
    "impactThresholdMax": 1,
    "angle": 1,
    "tempMin": 1,
    "tempMax": 1,
    "humdMin": 1,
    "humdMax": 1,
    "temperatureHysteresis": 1,
    "humidityHysteresis": 1,
    "pressureHysteresis": 3,
    "activityLevelThreshold": 3,
}

def decode_cbor_message(binary_payload):
    """
    Decode CBOR binary payload to JSON structure.
    
    Args:
        binary_payload: bytes - Raw CBOR binary data
        
    Returns:
        dict - Decoded message with JSON property names
    """
    try:
        # Decode CBOR to Python dict
        cbor_data = cbor2.loads(binary_payload)
        
        # Handle array wrapper (messages typically come as single-element arrays)
        if isinstance(cbor_data, list):
            cbor_data = cbor_data[0] if len(cbor_data) > 0 else {}
        
        # Convert CBOR indexes to JSON property names
        json_message = {}
        for cbor_index, value in cbor_data.items():
            # Get JSON property name
            prop_name = CBOR_INDEX_MAP.get(cbor_index, f"unknown_{cbor_index}")
            
            # Apply multiplier if needed
            if prop_name in MULTIPLIERS:
                multiplier = MULTIPLIERS[prop_name]
                value = value / (10 ** multiplier)
            
            json_message[prop_name] = value
        
        return json_message
        
    except Exception as e:
        print(f"Error decoding CBOR: {e}")
        return None

def add_gateway_fields(json_message, wirepas_node_id, gateway_id, network_timestamp):
    """
    Add gateway-originated fields to sensor message.
    
    Args:
        json_message: dict - Decoded sensor message
        wirepas_node_id: int - Wirepas node ID
        gateway_id: str - Gateway identifier
        network_timestamp: int - Wirepas network timestamp
        
    Returns:
        dict - Complete message with gateway fields
    """
    # Add timestamp (convert Wirepas time to UTC)
    json_message["tsmTs"] = network_timestamp
    
    # Add device identifier (lookup serial from node ID mapping)
    # In production, query device database with wirepas_node_id
    json_message["tsmTuid"] = f"NODE{wirepas_node_id}"
    
    # Add gateway identifier
    json_message["tsmGw"] = gateway_id
    
    return json_message

# Example usage
if __name__ == "__main__":
    # Example: Thingsee PRESENCE movement message
    hex_message = "9fa3011933 2c020a182c07ff"
    binary_payload = bytes.fromhex(hex_message.replace(" ", ""))
    
    # Decode
    message = decode_cbor_message(binary_payload)
    print("Decoded message:", message)
    # Output: {'tsmId': 13100, 'tsmEv': 10, 'moveCount': 7}
    
    # Add gateway fields
    complete_message = add_gateway_fields(
        message,
        wirepas_node_id=123456,
        gateway_id="TSGW2G987654",
        network_timestamp=1492844596
    )
    print("Complete message:", complete_message)

JavaScript Decoder

const cbor = require('cbor');

// CBOR index to JSON property mapping
const CBOR_INDEX_MAP = {
  // Header
  1: 'tsmId',
  2: 'tsmEv',
  3: 'tsmTs',
  4: 'tsmTuid',
  5: 'tsmGw',
  6: 'tsmAp',
  7: 'tsmDstTuid',
  8: 'tsmGwTs',
  9: 'tsmCloudTs',
  
  // Common data fields
  20: 'pwr',
  21: 'batl',
  22: 'chrg',
  23: 'requestTsmId',
  24: 'timestamp',
  25: 'transactionId',
  26: 'uptime',
  27: 'status',
  
  // Sensor measurements
  30: 'temp',
  31: 'lght',
  32: 'humd',
  33: 'airp',
  38: 'state',
  44: 'moveCount',
  45: 'dist',
  
  // Add more mappings as needed...
  
  // People counting
  1210: 'in',
  1211: 'out'
};

// Multipliers for decimal conversion
const MULTIPLIERS = {
  batl: 1,
  temp: 1,
  humd: 1,
  airp: 3,
  voltage: 6,
  activityLevel: 3,
  angle: 1
};

/**
 * Decode CBOR binary payload to JSON structure
 * @param {Buffer} binaryPayload - Raw CBOR binary data
 * @returns {Object} Decoded message with JSON property names
 */
function decodeCborMessage(binaryPayload) {
  try {
    // Decode CBOR to JavaScript object
    let cborData = cbor.decodeFirstSync(binaryPayload);
    
    // Handle array wrapper
    if (Array.isArray(cborData)) {
      cborData = cborData.length > 0 ? cborData[0] : {};
    }
    
    // Convert CBOR indexes to JSON property names
    const jsonMessage = {};
    for (const [cborIndex, value] of Object.entries(cborData)) {
      const index = parseInt(cborIndex);
      
      // Get JSON property name
      const propName = CBOR_INDEX_MAP[index] || `unknown_${index}`;
      
      // Apply multiplier if needed
      let finalValue = value;
      if (propName in MULTIPLIERS) {
        const multiplier = MULTIPLIERS[propName];
        finalValue = value / Math.pow(10, multiplier);
      }
      
      jsonMessage[propName] = finalValue;
    }
    
    return jsonMessage;
    
  } catch (error) {
    console.error('Error decoding CBOR:', error);
    return null;
  }
}

/**
 * Add gateway-originated fields to sensor message
 * @param {Object} jsonMessage - Decoded sensor message
 * @param {number} wirepasNodeId - Wirepas node ID
 * @param {string} gatewayId - Gateway identifier
 * @param {number} networkTimestamp - Wirepas network timestamp
 * @returns {Object} Complete message with gateway fields
 */
function addGatewayFields(jsonMessage, wirepasNodeId, gatewayId, networkTimestamp) {
  // Add timestamp
  jsonMessage.tsmTs = networkTimestamp;
  
  // Add device identifier (lookup from database in production)
  jsonMessage.tsmTuid = `NODE${wirepasNodeId}`;
  
  // Add gateway identifier
  jsonMessage.tsmGw = gatewayId;
  
  return jsonMessage;
}

// Example usage
const hexMessage = '9fa3011933 2c020a182c07ff';
const binaryPayload = Buffer.from(hexMessage.replace(/\s/g, ''), 'hex');

// Decode
const message = decodeCborMessage(binaryPayload);
console.log('Decoded message:', message);
// Output: { tsmId: 13100, tsmEv: 10, moveCount: 7 }

// Add gateway fields
const completeMessage = addGatewayFields(
  message,
  123456,
  'TSGW2G987654',
  1492844596
);
console.log('Complete message:', completeMessage);

Handling Compressed Messages

Some devices send compressed CBOR using zlib. Add decompression before CBOR decoding:

Python with zlib:

import zlib
import cbor2

def decode_compressed_cbor(binary_payload):
    try:
        # Decompress with zlib
        decompressed = zlib.decompress(binary_payload)
        
        # Decode CBOR
        cbor_data = cbor2.loads(decompressed)
        
        # Process as normal...
        return cbor_data
        
    except zlib.error:
        # Not compressed, decode directly
        return cbor2.loads(binary_payload)

JavaScript with pako:

const pako = require('pako');
const cbor = require('cbor');

function decodeCompressedCbor(binaryPayload) {
  try {
    // Try decompression
    const decompressed = pako.inflate(binaryPayload);
    const cborData = cbor.decodeFirstSync(Buffer.from(decompressed));
    return cborData;
  } catch (error) {
    // Not compressed, decode directly
    return cbor.decodeFirstSync(binaryPayload);
  }
}

Best Practices

Decoder Implementation

  1. Use established CBOR libraries - Don’t implement CBOR parser from scratch

    • Python: cbor2
    • JavaScript: cbor
    • Java: com.fasterxml.jackson.dataformat:jackson-dataformat-cbor
    • C#: PeterO.Cbor
  2. Handle unknown indexes gracefully - New firmware may introduce fields not in your mapping table

    prop_name = CBOR_INDEX_MAP.get(cbor_index, f"unknown_{cbor_index}")
    
  3. Validate message structure - Check for required fields before processing

    if "tsmId" not in message or "tsmEv" not in message:
        logger.warning("Invalid message structure")
        return None
    
  4. Log unknown indexes - Track unmapped indexes to update decoder

    if cbor_index not in CBOR_INDEX_MAP:
        logger.info(f"Unknown CBOR index {cbor_index} with value {value}")
    

Timestamp Handling

  1. Sensor messages don’t include timestamps - Gateway must add from Wirepas time-in-transit
  2. Use UTC timestamps - All tsmTs values are UTC epoch seconds
  3. Precision - Can use decimals for millisecond resolution (e.g., 1492844596.123)
  4. Network disconnected events (tsmEv: 18) - May lack tsmTs, cloud should generate

Device Identification

  1. Wirepas node ID - Primary identifier in raw CBOR messages
  2. Serial number lookup - Map node ID to serial via device database/API
  3. Use Service API - Query for complete device details including serial, name, model
query DeviceByWirepasNode($nodeId: Int!) {
  devices(where: {identifiers: {wirepasNodeId: {_eq: $nodeId}}}) {
    id
    name
    identifiers {
      wirepasNodeId
      vendorSerial
    }
    deviceType {
      productName
    }
  }
}

Error Handling

  1. Invalid CBOR - Malformed binary should be logged and discarded
  2. Missing required fields - Validate tsmId and tsmEv presence
  3. Out-of-range values - Check multiplier results are reasonable
  4. Compression errors - Try non-compressed decode if decompression fails

Performance Optimization

  1. Batch processing - Process messages in batches rather than one-by-one
  2. Cache mappings - Load CBOR index map once, reuse for all messages
  3. Parallel decoding - Use worker threads for high-volume deployments
  4. Database writes - Batch inserts for better throughput

Message ID Ranges

Message IDs (tsmId) identify the device type and message structure:

Profile ID RangeDescriptionExample Devices
1000-1999Common profileSystem messages
12000-12999Environment monitoringThingsee ENVIRONMENT
13000-13999Presence and occupancyThingsee PRESENCE
14000-14999Distance measurementThingsee COUNT, Thingsee BEAM
28000-28999Radar-based sensorsThingsee RADAR

Refer to device-specific documentation for complete message ID lists and field definitions.

Troubleshooting

No Messages Received

Check:

  • MQTT subscription includes correct Wirepas endpoint (21/21 for Thingsee CBOR)
  • Gateway is connected and forwarding messages
  • Sensors are configured with correct network ID and encryption keys
  • Default report interval is often 1 hour - wait or configure shorter interval

CBOR Decoding Errors

Check:

  • Binary payload is complete (not truncated)
  • Using correct CBOR library version
  • Message might be compressed - try zlib decompression first
  • Endpoint 238/238 uses TLV, not CBOR

Incorrect Values After Conversion

Check:

  • Multiplier applied correctly (divide by 10^x, not multiply)
  • CBOR index mapping matches device firmware version
  • Device-specific indexes (>1000) documented in device manual
  • Negative values handled correctly (temperature, acceleration)

Missing Timestamp

Check:

  • Gateway adding tsmTs from Wirepas time-in-transit
  • Network disconnected events (tsmEv: 18) may require cloud-generated timestamp
  • Clock synchronization on gateway

Unknown CBOR Indexes

Check:

  • Device firmware version - new firmware may add fields
  • Device-specific documentation for custom indexes
  • Log unknown indexes to identify patterns
  • Update decoder mapping table