Streaming AI Anomaly Detection for IoT Sensors

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1All 1564 services
Streaming AI Anomaly Detection for IoT Sensors
Medium
~2-4 weeks
Frequently Asked Questions

AI Development Areas

AI Solution Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1357
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1250
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    955
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1188
  • image_logo-advance_0.webp
    B2B Advance company logo design
    646
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    926

On a production line, a temperature sensor suddenly shows 95°C instead of the normal 60°C. Is this a physical anomaly (bearing overheating) or a sensor malfunction? Each false alarm reduces operator trust, while a missed alarm can cost millions. We built a streaming system on Kafka, Flink, and ONNX that resolves this dilemma with 95% accuracy and reduces false alarms by 3x. Our experience includes over 50 deployments in industrial and energy sectors.

Traditional threshold methods yield up to 40% false alarms. Contextual anomalies, considering time of day and day of week, reduce this to 5%. We combine statistics (z-score, EWMA) and ML inference on edge devices to minimize latency and maintain 95% accuracy. Typical stack: MQTT broker Mosquitto, Kafka 3.5 for buffering, Flink for windowed processing, PyTorch for training, and ONNX Runtime for inference on edge. Integration with Grafana + InfluxDB for real-time monitoring. Per Apache Kafka documentation, this architecture guarantees fault tolerance and scalability.

How the Streaming Architecture Works

Pipeline from sensor to alert:

MQTT (sensor) → Kafka → Flink / Spark Streaming → ML inference → AlertManager
                              ↓
                         InfluxDB / TimescaleDB
                              ↓
                         Grafana Dashboard

Kafka processing scheme:

from kafka import KafkaConsumer, KafkaProducer
import json
import numpy as np
from collections import defaultdict, deque

class IoTAnomalyProcessor:
    def __init__(self, bootstrap_servers='kafka:9092',
                 window_size=60):  # last 60 values
        self.consumer = KafkaConsumer(
            'iot-sensor-raw',
            bootstrap_servers=bootstrap_servers,
            value_deserializer=lambda m: json.loads(m.decode()),
            group_id='anomaly-detection'
        )
        self.producer = KafkaProducer(
            bootstrap_servers=bootstrap_servers,
            value_serializer=lambda v: json.dumps(v).encode()
        )
        self.sensor_windows = defaultdict(lambda: deque(maxlen=window_size))
        self.sensor_stats = {}  # EWMA mean/std per sensor

    def process(self):
        for message in self.consumer:
            reading = message.value
            sensor_id = reading['sensor_id']
            value = reading['value']

            # Update sliding window
            self.sensor_windows[sensor_id].append(value)
            window = list(self.sensor_windows[sensor_id])

            # Anomaly detection
            if len(window) >= 30:
                result = self.detect_anomaly(sensor_id, value, window)
                if result['anomaly']:
                    self.producer.send('iot-anomalies', result)

    def detect_anomaly(self, sensor_id, current_value, window):
        mean = np.mean(window)
        std = np.std(window)

        z_score = (current_value - mean) / (std + 1e-9)
        is_anomaly = abs(z_score) > 3.5

        return {
            'sensor_id': sensor_id,
            'value': current_value,
            'z_score': round(z_score, 2),
            'anomaly': bool(is_anomaly),
            'window_mean': round(mean, 3),
            'window_std': round(std, 3),
            'severity': 'critical' if abs(z_score) > 5 else 'warning'
        }

Why Contextual Anomaly Matters

85°C may be normal at 2:00 PM but critical at 3:00 AM. Contextual models consider hour, day of week, and month to build a baseline. This reduces false alarms by 3x compared to plain z-score.

def contextual_anomaly_detection(sensor_id: str,
                                   current_value: float,
                                   timestamp: pd.Timestamp,
                                   historical_data: pd.DataFrame) -> dict:
    """
    Normal range depends on:
    - Time of day (hour)
    - Day of week
    - Season (month)
    Baseline built separately for each context.
    """
    # Current moment context
    context = {
        'hour': timestamp.hour,
        'day_of_week': timestamp.dayofweek,
        'month': timestamp.month
    }

    # Historical data in the same context
    context_data = historical_data[
        (historical_data['sensor_id'] == sensor_id) &
        (historical_data['hour'] == context['hour']) &
        (historical_data['day_of_week'] == context['day_of_week'])
    ]['value']

    if len(context_data) < 10:
        return {'status': 'insufficient_context_data'}

    context_mean = context_data.mean()
    context_std = context_data.std()
    context_z = (current_value - context_mean) / (context_std + 1e-9)

    return {
        'sensor_id': sensor_id,
        'value': current_value,
        'context': context,
        'context_mean': round(context_mean, 3),
        'context_z_score': round(context_z, 2),
        'contextual_anomaly': abs(context_z) > 3,
        'context_samples': len(context_data)
    }

How to Distinguish Sensor Malfunction from Process Anomaly

If only one sensor in a group of five shows anomaly, it's likely a sensor fault. If all five do, it's a process anomaly. We use the single anomaly rule: when the proportion of anomalous sensors is below 25%, we conclude a sensor malfunction; above 60%, a physical anomaly.

def distinguish_sensor_vs_process_anomaly(sensor_group: dict,
                                           anomalous_sensor_id: str) -> dict:
    """
    If only one sensor in the group is anomalous → likely sensor fault.
    If all/most sensors are anomalous → process anomaly.
    Applied when multiple sensors measure the same physical zone.
    """
    anomaly_count = sum(1 for s_id, result in sensor_group.items()
                        if result.get('anomaly', False))
    total = len(sensor_group)

    group_anomaly_ratio = anomaly_count / total

    if group_anomaly_ratio <= 0.25:
        return {
            'conclusion': 'sensor_fault',
            'sensor_id': anomalous_sensor_id,
            'anomaly_ratio': group_anomaly_ratio,
            'action': 'replace_or_recalibrate_sensor',
            'process_alert': False
        }
    elif group_anomaly_ratio >= 0.6:
        return {
            'conclusion': 'process_anomaly',
            'anomaly_ratio': group_anomaly_ratio,
            'action': 'investigate_physical_process',
            'process_alert': True
        }
    else:
        return {
            'conclusion': 'uncertain',
            'anomaly_ratio': group_anomaly_ratio,
            'action': 'manual_investigation',
            'process_alert': True  # just in case
        }

What Is Edge Inference and Why Do You Need It?

For industrial networks with limited connectivity, cloud latency is unacceptable. We deploy ONNX models on ESP32 or Raspberry Pi. Inference runs locally with no network delay, consuming less than 100 ms per prediction.

import onnxruntime as ort
import numpy as np

class EdgeAnomalyDetector:
    """
    ONNX model deployed on edge device.
    Inference without cloud: critical for industrial networks with limited connectivity.
    """
    def __init__(self, model_path: str, window_size: int = 30):
        self.session = ort.InferenceSession(model_path)
        self.window_size = window_size
        self.buffer = []
        self.threshold = 0.5

    def infer(self, new_value: float) -> dict:
        self.buffer.append(new_value)
        if len(self.buffer) > self.window_size:
            self.buffer.pop(0)

        if len(self.buffer) < self.window_size:
            return {'status': 'warming_up'}

        # Normalization
        arr = np.array(self.buffer, dtype=np.float32)
        arr = (arr - arr.mean()) / (arr.std() + 1e-9)
        input_tensor = arr.reshape(1, self.window_size, 1)

        result = self.session.run(None, {'input': input_tensor})[0]
        anomaly_score = float(result[0][0])

        return {
            'anomaly': anomaly_score > self.threshold,
            'score': round(anomaly_score, 3),
            'latency_ms': 'local'  # no network latency
        }

Comparison of Detection Methods

Method Sensitivity False Positives Implementation Complexity
Z-score (sliding window) Medium High (outliers) Low — 1 day
Contextual Z-score High Low — accounts for time/day Medium — 2-3 days
ML model (LSTM/Transformer) Very High Very Low High — 2-3 weeks

ML detection gives 3x fewer false positives compared to threshold methods. We choose the approach based on your data.

Comparison of IoT Protocols for Data Transfer
Protocol Latency Reliability Application
MQTT Low High IoT sensors
CoAP Low Medium Constrained devices
HTTP High High Monitoring

For most industrial scenarios, we recommend MQTT due to low latency and built-in quality of service (QoS).

What's Included in the Work

  1. Audit — analysis of current data sources, frequency, quality, and available infrastructure.
  2. Design — stack selection (Kafka / Flink / Spark / ONNX), topic schemes, and models.
  3. Development — pipeline coding, baseline and ML model training, alert configuration.
  4. Integration — connecting MQTT broker, InfluxDB, Grafana.
  5. Deployment — on servers or edge devices (ESP32, Raspberry Pi).
  6. Documentation — architecture description, operator instructions, retraining guide.
  7. Support — staff training, 1-month warranty support.

Timing and Estimated Cost

Timeline depends on complexity and volume: basic pipeline with z-score starts from 2 weeks; comprehensive solution with ML and edge up to 8 weeks. Cost is calculated individually. Certified engineers with 5 years of ML and IoT experience guarantee results. Example savings: reducing false alarms by 80% can save up to 2 million rubles per year in maintenance. Contact us — we will analyze your data and propose the optimal architecture within 3 days.

Integration with platforms: AWS IoT Core, Azure IoT Hub, Yandex IoT Core, EdgeX Foundry. MQTT brokers: Eclipse Mosquitto, EMQ X. Storage and visualization: Grafana + InfluxDB.

Need a consultation? Describe your task — we'll find a solution within one day.

Anomaly Detection: Autoencoders, Isolation Forest, PyOD

Server monitoring shows CPU 85%, memory 91% — is this the start of an attack or normal peak load? A classifier won’t help: anomalies are by definition rare, diverse, and not pre-labeled. Supervised learning requires examples of anomalies in the training set — so it fails on what you haven’t seen yet. Without an unsupervised approach, detection turns into guesswork.

Why Does Anomaly Detection Require an Unsupervised Approach?

The main problem: no labels and extreme class imbalance. Fraud transactions account for 0.01–0.1% of total volume, production defects 0.5–3%. With such ratios, a naive “all normal” classifier gives 99.9% accuracy but recall for the anomalous class near zero. Supervised models are powerless.

Second: “normality” is always contextual. A login at 3 AM may be normal for a night‑shift user but suspicious for a day‑worker. Bearing vibration at 2.3 mm/s depends on operating mode and machine age. So we embed context via feature engineering and time windows.

Third: quality assessment without ground truth. No standard test set — AUC‑ROC is possible only if a few labeled examples exist. For fully unlabeled data, only domain expert validation and indirect metrics work.

How to Distinguish an Anomaly from Noise in Real Time?

With adaptive thresholds and continuous monitoring of model statistics. In the case section we show how.

Method Data Type Training Speed Typical Application
Isolation Forest Tabular, categorical High Baseline for initial hypotheses
Autoencoder Images, time series, logs Medium Unstructured data
LSTM-AE Multivariate time series Low Industrial telemetry
PyOD (ensemble) Tabular High Quick comparison of 40+ methods

Isolation Forest is the standard baseline for tabular data. Idea: anomalies are isolated faster by random partitioning of the feature space. Works well at contamination=0.01–0.1, robust to feature scale, no normalization required. Implementation in sklearn.ensemble.IsolationForest.

Typical mistake: setting contamination='auto' without understanding the data. Auto mode assumes a threshold of -0.5, which may not match the actual anomaly proportion. Better: estimate expected anomaly percentage through domain knowledge and set it explicitly. We guarantee contamination tuning for your case.

PyOD (Python Outlier Detection) is a library with 40+ algorithms under a unified API — OCSVM, LOF, COPOD, ECOD, DeepSVDD, AutoEncoder. Useful for quickly comparing methods on the same data.

Autoencoders are the main method for unstructured data (time series, images, logs). Train the network to reconstruct normal data; anomalies yield high reconstruction error. Anomaly threshold is the 95th or 99th percentile of error on a validation set of normal data.

Practical problem with autoencoders: overfitting on “normal” patterns that are still rare. If the training set contains even a few anomalies, the model may learn to reconstruct them well. Solution: thorough cleaning of training data or using a Variational Autoencoder (VAE), which generalizes better.

LSTM‑AE for time series captures temporal dependencies better than a regular AE. Especially effective for multivariate time series (10+ sensors simultaneously). Implementation via PyTorch, training with MSELoss on sliding windows.

In Detail: Anomaly Detection in Industrial Time Series

Problem: vibration sensors on 12 pumps at a chemical plant, 6 sensors per pump, frequency 100 Hz. Need to warn of impending failure 4–24 hours in advance.

Solution architecture: raw data → feature extraction (RMS, kurtosis, peak factor, FFT amplitudes at resonant frequencies) → normalization by 24‑hour sliding window → LSTM‑AE → reconstruction error → threshold logic + alerting.

LSTM window size: 60 seconds (6000 points at 100 Hz). Too small a window misses slow patterns, too large loses sensitivity to rapid changes.

Anomaly threshold: not fixed, but adaptive. threshold = mean(errors_last_7d) + 3 * std(errors_last_7d). As normal state drifts (planned wear), the threshold adapts, avoiding false positives.

Result over a 6‑month pilot: detected 4 out of 5 real pre‑failure conditions (recall 0.8), with 2 false alarms over 6 months (precision 0.67). Before implementation: 3 unplanned shutdowns. After implementation: cost savings verified in the pilot report.

What Specifics Does Fraud Detection Face?

Financial transactions have several features that complicate detection:

  • Concept drift: fraud patterns change faster than normal behavior. A model trained six months ago becomes obsolete.
  • Adversarial adaptation: advanced fraudsters adapt — making transactions resemble normal ones.
  • Temporal dependency: a series of normal transactions followed by one unusual transfer is a sequence anomaly, not a single point.

Practical stack for fraud detection: LightGBM with SMOTE oversampling for the supervised part (known fraud cases) + Isolation Forest for unsupervised (new patterns). Both signals combined in an ensemble; final decision via thresholds tuned for acceptable FPR (0.1–1% of transactions sent to manual review).

How to Evaluate Quality Without Labels?

When ground truth is absent, we evaluate using:

  • Synthetic anomaly injection: add artificial anomalies (spike, level shift, point outlier) and check if the model detects them.
  • Expert validation: random sample of top‑K anomalies → expert review → precision.
  • Business metric: did the number of missed incidents / false alarms decrease after deployment?

Technical detail: the adaptive threshold is computed as mean(errors) + k * std(errors) on a 7‑day sliding window. Coefficient k is tuned on a validation set with synthetic anomalies to achieve FPR < 0.1%. When features drift, the window automatically shifts.

Process

  1. Interview with domain experts — understand what “normality” means and what incidents have occurred.
  2. EDA and data preparation — cleaning, feature creation, time windows.
  3. Baseline (Isolation Forest) — fast validation on known incidents.
  4. Model selection and customization — Autoencoder / LSTM‑AE / ensemble.
  5. Training, validation with synthetic anomalies.
  6. Deployment to production — pipeline on Kafka + Flink / Airflow, alerting to Telegram/Slack, drift monitoring.
  7. Post‑deployment support — monitor model metrics, update thresholds.

What's Included

  • Audit of current data and processes
  • Development and training of models (Isolation Forest / Autoencoder / LSTM‑AE / ensemble)
  • Configuration of adaptive thresholds and alerting
  • Anomaly monitoring dashboard (Grafana / Streamlit)
  • Model card and pipeline documentation
  • Training for your team (2–3 sessions)
  • 3‑month warranty support

Timeline: baseline system with one method — 2–4 weeks. Production system with adaptive thresholds, alerting, and monitoring — 2–5 months. Pricing is calculated individually for your case.

Our team has 8+ years of experience in industrial analytics and 15+ successful projects in anomaly detection for telemetry, finance, and IT monitoring. Get a consultation — we’ll tell you how to solve your problem. Contact us to discuss your data and receive a preliminary architecture proposal.