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