Back to Blog
3 min read

Azure IoT Edge: Intelligence at the Edge

Azure IoT Edge runs cloud workloads on edge devices. Machine learning, stream processing, and business logic—where your data is generated.

IoT Edge Architecture

┌──────────────────────────────────────────┐
│              Azure Cloud                  │
│  ┌─────────────┐  ┌─────────────────┐   │
│  │  IoT Hub    │  │ Container       │   │
│  │             │  │ Registry        │   │
│  └─────────────┘  └─────────────────┘   │
└──────────────────────────────────────────┘


┌──────────────────────────────────────────┐
│           IoT Edge Device                 │
│  ┌─────────────────────────────────────┐ │
│  │         IoT Edge Runtime            │ │
│  │  ┌─────────┐ ┌─────────┐ ┌───────┐ │ │
│  │  │ Module 1│ │ Module 2│ │Module3│ │ │
│  │  │ (ML)    │ │(Stream) │ │(Logic)│ │ │
│  │  └─────────┘ └─────────┘ └───────┘ │ │
│  └─────────────────────────────────────┘ │
│  ┌─────────────┐  ┌─────────────┐       │
│  │  edgeHub    │  │  edgeAgent  │       │
│  └─────────────┘  └─────────────┘       │
└──────────────────────────────────────────┘

Deployment Manifest

{
    "modulesContent": {
        "$edgeAgent": {
            "properties.desired": {
                "modules": {
                    "TempSensor": {
                        "type": "docker",
                        "settings": {
                            "image": "mcr.microsoft.com/azureiotedge-simulated-temperature-sensor:1.0"
                        },
                        "status": "running",
                        "restartPolicy": "always"
                    },
                    "FilterModule": {
                        "type": "docker",
                        "settings": {
                            "image": "myacr.azurecr.io/filter-module:1.0"
                        },
                        "env": {
                            "TEMP_THRESHOLD": { "value": "25" }
                        }
                    }
                }
            }
        },
        "$edgeHub": {
            "properties.desired": {
                "routes": {
                    "sensorToFilter": "FROM /messages/modules/TempSensor/* INTO BrokeredEndpoint(\"/modules/FilterModule/inputs/input1\")",
                    "filterToCloud": "FROM /messages/modules/FilterModule/* INTO $upstream"
                }
            }
        }
    }
}

Custom Module (C#)

public class Program
{
    static double temperatureThreshold = 25;

    static async Task Init()
    {
        var moduleClient = await ModuleClient.CreateFromEnvironmentAsync();
        await moduleClient.OpenAsync();

        // Set input message handler
        await moduleClient.SetInputMessageHandlerAsync("input1", FilterMessages, moduleClient);

        // Handle twin updates
        await moduleClient.SetDesiredPropertyUpdateCallbackAsync(OnDesiredPropertiesUpdate, null);
    }

    static async Task<MessageResponse> FilterMessages(Message message, object userContext)
    {
        var moduleClient = (ModuleClient)userContext;
        var messageBody = message.GetBytes();
        var data = JsonConvert.DeserializeObject<SensorData>(Encoding.UTF8.GetString(messageBody));

        if (data.Temperature > temperatureThreshold)
        {
            var alertMessage = new Message(messageBody);
            alertMessage.Properties.Add("alertType", "temperature");
            await moduleClient.SendEventAsync("output1", alertMessage);
        }

        return MessageResponse.Completed;
    }
}

ML at the Edge

{
    "MLModule": {
        "type": "docker",
        "settings": {
            "image": "myacr.azurecr.io/ml-module:1.0",
            "createOptions": {
                "HostConfig": {
                    "Binds": ["/var/lib/azurecv:/azurecv"]
                }
            }
        }
    }
}
# Python module with ONNX model
import onnxruntime as rt

class MLModule:
    def __init__(self):
        self.session = rt.InferenceSession('/azurecv/model.onnx')

    def score(self, input_data):
        result = self.session.run(None, {'input': input_data})
        return result

Stream Analytics at Edge

-- Edge SQL query
SELECT
    System.Timestamp() AS WindowEnd,
    AVG(temperature) AS AvgTemp,
    MAX(temperature) AS MaxTemp,
    COUNT(*) AS EventCount
INTO
    AlertOutput
FROM
    SensorInput TIMESTAMP BY timestamp
GROUP BY
    TumblingWindow(second, 30)
HAVING
    AVG(temperature) > 25

Offline Capabilities

{
    "$edgeHub": {
        "properties.desired": {
            "storeAndForwardConfiguration": {
                "timeToLiveSecs": 7200
            }
        }
    }
}

CLI Operations

# Set deployment
az iot edge set-modules \
    --hub-name myiothub \
    --device-id myedgedevice \
    --content deployment.json

# Monitor messages
az iot hub monitor-events \
    --hub-name myiothub \
    --device-id myedgedevice

IoT Edge: cloud intelligence where it matters most.

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.