Skip to content

IoT Data Ingestion

This page documents how sensor data flows from a physical IoT device into the system, triggering threshold comparisons and live alerts.


Endpoint

POST /api/v1/devices/sensor-data

Auth: deviceAuthCheck — static token in Authorization header (hardware devices only, not user JWT).


Request Format

http
POST /api/v1/devices/sensor-data
Authorization: Au@jsjKAKL9IJK@@Kks
Content-Type: application/json

{
  "id": "DEVICE-CODE-001",
  "temperature": 5.2,
  "humidity": 62.1,
  "volt": 220.5,
  "seq_no": 1234
}

The id field is the unique device code stored in the devices collection.


Processing Pipeline

POST body arrives


deviceAuthCheck  →  static token match


saveSensorData() in deviceSensorData.controller.js

        ├─ 1. Find Device by code
        │       DeviceModel.findOne({ code: body.id })

        ├─ 2. Find associated Unit
        │       UnitModel.findOne({ device_id: device._id })

        ├─ 3. Parse sensor records
        │       prepareSensorRecords(body)
        │       → sensorRecords[]   (temperature, humidity, volt, seq_no, date)
        │       → networkRecords[]  (operator, mnc, sinr, mcc, rssi, band, tech ...)

        ├─ 4. Compute live alerts
        │       generateErrorAlerts(recentSensorData, unit)

        ├─ 5. Persist data
        │       SensorDataModel.insertMany(sensorRecords)
        │       NetworkDataModel.insertMany(networkRecords)
        │       unit.set({ recent_sensor_data, live_alerts, last_communicated_at })
        │       unit.save()
        │       device.set({ recent_sensor_data, last_communicated_at })
        │       device.save()

        └─ 6. Return success response

Alert Generation (generateErrorAlerts)

This function computes the current alert state by comparing the latest sensor reading against the unit's configured thresholds.

js
generateErrorAlerts(recentSensorData, unit)

Threshold Checks

SensorBelow minimumAbove maximum
temperatureerror_code: 'LOW_TEMP'error_code: 'HIGH_TEMP'
humidityerror_code: 'LOW_HUM'error_code: 'HIGH_HUM'
voltageerror_code: 'LOW_VOLT'error_code: 'HIGH_VOLT'

Alert Object Shape

json
{
  "error_code": "HIGH_TEMP",
  "start_date": "2024-01-15T08:30:00.000Z",
  "value": 12.4,
  "count": 7
}
FieldDescription
error_codeIdentifies the type of threshold breach
start_dateWhen the breach started — preserved from previous alerts
valueCurrent sensor value at the time of this reading
countHow many consecutive readings have been in breach

Start Date Preservation

A key feature: if an alert with the same error_code already existed in unit.live_alerts, the new alert inherits its start_date. This prevents the start time from resetting on every reading.

js
// Pseudocode
const existingAlert = previousAlerts.find(a => a.error_code === errorCode)
const startDate = existingAlert?.start_date ?? new Date()

Alert Clearing

When the sensor value returns to within the acceptable range, the corresponding alert is simply not included in the new live_alerts array. Setting unit.live_alerts to the new array atomically clears resolved alerts.


Cached Readings (recent_sensor_data)

Both Device and Unit documents store recent_sensor_data — a copy of the latest reading. This enables:

  • Fast retrieval of "current conditions" without querying the time-series sensor_data collection
  • Populating the live dashboard without a database aggregation
json
{
  "temperature": 5.2,
  "humidity": 62.1,
  "volt": 220.5,
  "date": "2024-01-15T08:30:00.000Z"
}

Historical Storage

Every incoming payload also creates permanent time-series records:

CollectionModelStored fields
sensor_dataDeviceSensorDataModeltemperature, humidity, volt, seq_no, date
network_dataDeviceNetworkDataModeloperator, mnc, sinr, mcc, rssi, channel, tech, band, ...
raw_sensor_dataRawDeviceSensorDataModeldevice_id, date (raw payload reference)

This historical data is used for report generation, admin dashboards, and diagnostic analysis.


Reports from Historical Data

The ReportBusiness class queries sensor_data for a date range and computes aggregate statistics:

js
// MongoDB aggregation
{
  avg_temperature: { $avg: '$temperature' },
  min_temperature: { $min: '$temperature' },
  max_temperature: { $max: '$temperature' },
  avg_humidity:    { $avg: '$humidity' },
  // ... etc.
}

Reports can be downloaded as:

  • CSV — streamed directly from the Express response
  • PDF — generated with pdfkit and streamed; uses moment-timezone for formatted dates

Intecog Logistech IoT Monitoring Platform