Skip to content

IoT Edge Computing — WebAssembly, K3s and ML Inference at the Edge

DodaTech Updated 2026-06-22 7 min read

In this tutorial, you'll learn about IoT Edge Computing. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

IoT Edge Computing processes sensor data locally on gateways and devices near the data source, dramatically reducing latency, bandwidth costs, and cloud dependency while enabling real-time responses for mission-critical applications.

What You'll Learn

You'll master WebAssembly-based edge sandboxing for safe third-party module execution, K3s lightweight Kubernetes for edge Orchestration, TensorFlow Lite ML inference optimization on ARM devices, secure OTA firmware updates with cryptographic signing, and edge-to-cloud sync strategies using CRDTs for disconnected environments.

Why It Matters

A single industrial facility with 10,000 sensors generating 1KB of data per second produces 864 GB of data daily. Sending all of this to the cloud costs approximately $78 per day in bandwidth alone. Edge processing filters 90 percent of data locally, sending only meaningful events. At DodaTech, edge processing patterns power the on-device threat detection engine in Durga Antivirus Pro, analyzing files locally before any cloud upload.

Real-World Use

An oil refinery monitors 5,000 vibration sensors on pumps and compressors. Cloud-only processing means a 10-second delay between sensor reading and anomaly detection — too late to prevent a catastrophic pump failure. Edge processing with TensorFlow Lite running on a local gateway detects anomalies in under 10 milliseconds and triggers an automatic shutdown within 50 milliseconds of the first abnormal reading.

Edge Computing Architecture with K3s

flowchart TD
    subgraph Cloud[Cloud Layer]
        CloudML[ML Training]
        DeviceMgmt[Device Management]
        OTA[OTA Update Service]
        DataLake[(Data Lake)]
    end

    subgraph Edge[Edge Gateway - K3s Cluster]
        K3s[K3s Kubernetes]
        WASM[WasmEdge Runtime]
        TFLite[TensorFlow Lite]
        LocalDB[(SQLite - Edge)]
        MQTT[VerneMQ Broker]
    end

    subgraph Devices[Device Layer]
        Sensor1[Sensor Array 1]
        Sensor2[Sensor Array 2]
        Actuator[Actuator Controller]
    end

    Sensor1 --> MQTT
    Sensor2 --> MQTT
    MQTT --> WASM
    WASM -->|Filtered Events| K3s
    K3s --> TFLite
    TFLite -->|Anomaly| Actuator
    TFLite -->|Telemetry| CloudML
    OTA -->|Signed Updates| K3s
    DeviceMgmt --> K3s

WebAssembly Sandboxing at the Edge

WebAssembly provides secure, sandboxed execution for third-party edge modules without container overhead.

// wasm_edge_module.rs — compiled to .wasm for edge deployment
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub struct SensorProcessor {
    threshold: f32,
    running_avg: f32,
    sample_count: u32,
}

#[wasm_bindgen]
impl SensorProcessor {
    pub fn new(threshold: f32) -> SensorProcessor {
        SensorProcessor {
            threshold,
            running_avg: 0.0,
            sample_count: 0,
        }
    }

    pub fn process_reading(&mut self, value: f32) -> String {
        self.sample_count += 1;
        self.running_avg += (value - self.running_avg) / self.sample_count as f32;

        let z_score = if self.sample_count > 1 {
            (value - self.running_avg) / 0.1
        } else {
            0.0
        };

        if value > self.threshold || z_score.abs() > 3.0 {
            format!("ALERT: value={:.2}, avg={:.2}, z={:.2}",
                    value, self.running_avg, z_score)
        } else {
            format!("OK: value={:.2}, avg={:.2}", value, self.running_avg)
        }
    }

    pub fn get_stats(&self) -> String {
        format!("samples={}, avg={:.2}",
                self.sample_count, self.running_avg)
    }
}

Expected behavior: The WebAssembly module runs in a WasmEdge sandbox on the edge gateway with zero container overhead. Each sensor data stream gets its own sandboxed processor instance. The sandbox can access only the memory and functions explicitly provided to it, preventing one malfunctioning module from crashing the entire gateway.

K3s for Edge Orchestration

K3s is a CNCF-certified Kubernetes distribution optimized for resource-constrained edge devices.

# edge-deployment.yaml — K3s deployment for edge ML inference
apiVersion: apps/v1
kind: Deployment
metadata:
  name: edge-ml-inference
  namespace: edge-processing
spec:
  replicas: 2
  selector:
    matchLabels:
      app: edge-ml-inference
  template:
    metadata:
      labels:
        app: edge-ml-inference
    spec:
      containers:
      - name: tflite-inference
        image: dodatech/edge-ml:arm64-1.2.0
        resources:
          limits:
            memory: "256Mi"
            cpu: "500m"
        env:
        - name: MODEL_PATH
          value: "/models/anomaly_detection.tflite"
        - name: THRESHOLD
          value: "0.85"
        volumeMounts:
        - name: model-storage
          mountPath: /models
        - name: edge-data
          mountPath: /data
      volumes:
      - name: model-storage
        hostPath:
          path: /opt/edge/models
      - name: edge-data
        hostPath:
          path: /data/edge
---
apiVersion: v1
kind: Service
metadata:
  name: edge-inference-svc
spec:
  selector:
    app: edge-ml-inference
  ports:
  - port: 8080
    targetPort: 8080

Edge ML Inference Optimization

import numpy as np
import tflite_runtime.interpreter as tflite
import time

class OptimizedEdgeInference:
    def __init__(self, model_path: str, num_threads: int = 4):
        self.interpreter = tflite.Interpreter(
            model_path=model_path,
            num_threads=num_threads
        )
        self.interpreter.allocate_tensors()
        self.input_details = self.interpreter.get_input_details()
        self.output_details = self.interpreter.get_output_details()

        # Quantization parameters
        self.input_scale = self.input_details[0]["quantization"][0]
        self.input_zero_point = self.input_details[0]["quantization"][1]

    def preprocess(self, raw_data: list) -> np.ndarray:
        arr = np.array(raw_data, dtype=np.float32).reshape(1, -1)
        # Quantize to int8 for faster inference
        if self.input_scale != 0:
            arr = (arr / self.input_scale + self.input_zero_point).astype(np.int8)
        return arr

    def predict(self, sensor_data: list) -> dict:
        start = time.perf_counter()
        input_tensor = self.preprocess(sensor_data)
        self.interpreter.set_tensor(self.input_details[0]["index"], input_tensor)
        self.interpreter.invoke()
        output = self.interpreter.get_tensor(self.output_details[0]["index"])
        inference_ms = (time.perf_counter() - start) * 1000

        return {
            "anomaly_score": float(output[0][0]),
            "is_anomaly": float(output[0][0]) > 0.85,
            "inference_ms": round(inference_ms, 2),
        }

edge_ml = OptimizedEdgeInference("anomaly_model.tflite")
result = edge_ml.predict([2.3, 45.0, 101.2, 3200.0])
print(f"Anomaly: {result['is_anomaly']}, Score: {result['anomaly_score']:.4f}, Time: {result['inference_ms']}ms")

Expected behavior: The optimized inference pipeline processes sensor data in under 5ms on a Raspberry Pi 4 using int8 quantized TFLite models. Quantization reduces model size by 75 percent and improves inference speed by 2-3x compared to float32 models.

Secure OTA Updates

Edge devices must cryptographically verify firmware updates before applying them.

import hashlib
import hmac
import json
import requests

class SecureOTAUpdater:
    def __init__(self, device_id: str, public_key_path: str):
        self.device_id = device_id
        with open(public_key_path, "rb") as f:
            self.public_key = f.read()

    def check_and_apply_update(self, update_url: str):
        manifest_response = requests.get(f"{update_url}/manifest.json")
        manifest = manifest_response.json()

        # Verify manifest signature
        expected_hash = hmac.new(
            self.public_key,
            json.dumps(manifest["payload"]).encode(),
            hashlib.sha256
        ).hexdigest()

        if not hmac.compare_digest(expected_hash, manifest["signature"]):
            print("SIGNATURE MISMATCH — update rejected")
            return False

        # Verify firmware hash
        firmware_response = requests.get(manifest["payload"]["firmware_url"])
        actual_hash = hashlib.sha256(firmware_response.content).hexdigest()
        if actual_hash != manifest["payload"]["firmware_hash"]:
            print("FIRMWARE HASH MISMATCH — update rejected")
            return False

        # Apply update
        with open("/opt/edge/firmware.bin", "wb") as f:
            f.write(firmware_response.content)

        print(f"Update applied: version {manifest['payload']['version']}")
        return True

Common Errors

1. Underpowered Edge Hardware

Running full TensorFlow models on ESP32-class MCUs with 320KB RAM. Use TFLite Micro or WebAssembly sandboxing for constrained devices. Reserve heavier ML for gateway-class hardware.

2. No Offline Fallback

Edge devices that stop working when cloud connectivity drops. Implement local storage with SQLite and sync when connectivity is restored. Use CRDTs for conflict-free synchronization.

3. Unsecured OTA Updates

Edge devices that accept firmware updates without cryptographic verification can be hijacked. Always sign updates with a hardware-backed private key and verify signatures before applying.

4. Monolithic Edge Applications

Deploying a single binary that handles sensor ingestion, ML inference, cloud sync, and actuation creates a rigid system. Use K3s to containerize each function independently for isolated updates and scaling.

5. No Local Alerting

Edge devices that rely on cloud connectivity to trigger alerts introduce latency and single points of failure. Implement local alerting that triggers actuators within 50ms of anomaly detection.

6. Ignoring Thermal Throttling

Raspberry Pi and similar SBCs throttle CPU speed at 80°C, reducing inference performance by 50 percent. Monitor CPU temperature and reduce inference frequency during thermal events.

7. Inefficient Data Filtering

Sending all sensor readings to the cloud wastes bandwidth. Implement tiered filtering — simple threshold checks first, statistical anomaly detection second, ML inference only for borderline cases.

Practice Questions

1. Why use WebAssembly for edge processing instead of containers?

WebAssembly provides faster startup (microseconds vs seconds), smaller binary size, and stronger sandboxing guarantees than containers. WASM modules have no access to the host OS, making them safe for third-party edge modules.

2. How does K3s differ from standard Kubernetes for edge deployment?

K3s removes cloud-dependent components, uses SQLite instead of etcd for state storage, and runs in under 512MB RAM. It provides a lightweight Kubernetes API compatible with standard Kubernetes tooling.

3. What is model quantization and why is it important for edge ML?

Quantization converts model weights from 32-bit floating point to 8-bit integers. This reduces model size by 75 percent, improves inference speed by 2-3x, and enables ML inference on devices without FPU hardware.

4. How do CRDTs help with edge-cloud data synchronization?

CRDTs (Conflict-Free Replicated Data Types) allow multiple nodes to make concurrent edits without coordination. When nodes reconnect, changes merge automatically without conflicts, eliminating the need for complex reconciliation logic.

5. Challenge: Design a predictive maintenance system for a wind turbine. The edge gateway receives 200 sensor readings per second (vibration, temperature, RPM, power output). Use a three-tier filtering approach: simple threshold check, z-score anomaly detection, and a quantized TFLite autoencoder for remaining useful life prediction. Send alerts locally within 100ms and daily telemetry to the cloud.

Mini Project: Edge ML Pipeline

Build a complete edge ML pipeline:

  1. Simulate sensor data with a Python script (10 sensors, 4 readings each, 10Hz)
  2. Edge gateway running K3s with a WasmEdge module for data filtering
  3. TFLite anomaly detection model (train a simple autoencoder on sample data)
  4. Local SQLite store for filtered data with 7-day retention
  5. Cloud sync that sends only anomaly events plus hourly aggregated telemetry
  6. Secure OTA mechanism that signs and verifies model updates
  7. Measure and report: data reduction ratio, inference latency, cloud bandwidth savings

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro