Diyarbakır merkezli 280 üyeli bir tarım kooperatifi, sulama ve gübreleme verimini artırmak için 4.200 toprak/iklim/sulama sensörünü Azure IoT Hub ile yönetmeye karar verdi. 9 ay sonunda su tüketimi %22 azaldı, gübre maliyetleri %18 düştü, verim %14 arttı. Bu yazı projenin sahadaki teknik notlarını paylaşıyor.
Mimari Genel Bakış
- 4.200 cihaz: 2.800 toprak nemi/sıcaklık (LoRaWAN gateway üzerinden), 800 hava istasyonu (NB-IoT), 600 sulama vana kontrolcüsü (LTE-M)
- Azure IoT Hub Standard S2 (1.5M msg/gün): cihaz yönetimi, mesaj routing
- IoT Edge gateway: Tarla başlarında 38 Edge cihaz (downstream sensörlerin lokal aggregation’ı)
- Device Provisioning Service (DPS): Otomatik cihaz kayıt
- Stream Analytics: Real-time anomali (anormal sıcaklık, vana kaçağı)
- Cosmos DB: Telemetri (12 ay hot)
- Azure Data Explorer: Time-series analytics, dashboard
- Azure Functions: Sulama kararı (toprak nemi eşiğine göre vana açma komutu)
Device Provisioning Service (DPS)
4.200 cihazı manuel kaydetmek imkansız. DPS ile X.509 sertifika tabanlı zero-touch provisioning:
using var security = new SecurityProviderX509Certificate(deviceCert);
using var transport = new ProvisioningTransportHandlerAmqp();
var provClient = ProvisioningDeviceClient.Create(
"global.azure-devices-provisioning.net",
"0ne00ABCDEF", // ID Scope
security,
transport);
var result = await provClient.RegisterAsync();
// result.AssignedHub: "iot-tarim-prod.azure-devices.net"
// result.DeviceId: cihaz seri numarası
using var iotClient = DeviceClient.Create(
result.AssignedHub,
new DeviceAuthenticationWithX509Certificate(result.DeviceId, deviceCert),
TransportType.Mqtt);
Cihaz tarlaya yerleştirilip ilk kez bağlanınca DPS hangi IoT Hub’a yönlendireceğine karar veriyor (allocation policy: load balancing).
Message Routing
Tek IoT Hub’a düşen mesajlar tipine göre farklı destination’lara routing edildi:
# Telemetri (toprak nemi, sıcaklık) → Cosmos DB
az iot hub route create -g rg-iot --hub-name iot-tarim-prod
--route-name r-telemetry
--source devicemessages
--condition "messageType = 'telemetry'"
--endpoint-name eh-telemetry
--enabled true
# Alarm (vana kaçağı) → Service Bus → Functions
az iot hub route create -g rg-iot --hub-name iot-tarim-prod
--route-name r-alarms
--source devicemessages
--condition "messageType = 'alarm' AND severity > 'warning'"
--endpoint-name sb-alarms
--enabled true
# Diagnostics (cihaz durum) → Log Analytics
az iot hub route create -g rg-iot --hub-name iot-tarim-prod
--route-name r-diag
--source devicemessages
--condition "messageType = 'diagnostics'"
--endpoint-name la-diag
--enabled true
IoT Edge: Tarla Başında Lokal İşleme
38 Edge gateway her biri ~110 sensörü topluyor. Cloud bağlantısı koptuğunda son 24 saat lokal storage’da, bağlantı geri gelince batch upload. Lokal anomali detection da Edge’de:
version: '3'
modules:
edgeAgent:
image: mcr.microsoft.com/azureiotedge-agent:1.4
edgeHub:
image: mcr.microsoft.com/azureiotedge-hub:1.4
environment:
OptimizeForPerformance: false
MqttSettings__Enabled: true
sensorAggregator:
image: tarim.azurecr.io/sensor-agg:1.2
createOptions:
HostConfig:
Binds: ["/data:/data"]
anomalyDetector:
image: tarim.azurecr.io/anomaly:1.5
routes:
sensorIn: FROM /messages/modules/sensorAggregator/* INTO BrokeredEndpoint("/modules/anomalyDetector/inputs/sensors")
Sulama Otomasyonu (Cloud-to-Device)
Toprak nemi % 35’in altına düşünce Azure Functions vana cihazına direct method çağırıyor:
[Function("IrrigationDecider")]
public async Task Run(
[CosmosDBTrigger("telemetry", "soil", LeaseContainerName = "leases")]
IReadOnlyList<SoilReading> readings)
{
foreach (var r in readings.Where(x => x.MoisturePct < 35))
{
var valveDevice = $"valve-{r.FieldId}";
var method = new CloudToDeviceMethod("OpenValve")
.SetPayloadJson($@"{{""durationMinutes"":{CalcDuration(r)}}}");
var resp = await _serviceClient.InvokeDeviceMethodAsync(valveDevice, method);
await _audit.LogAsync(r.FieldId, resp.Status);
}
}
OTA Firmware Update
4.200 cihaza fiziksel erişim imkansız. Device Update for IoT Hub (ADU) ile OTA güncelleme:
# Yeni firmware import
az iot du update import
--account adu-tarim --instance prod
--update-source ./firmware-1.5.0.json
# Deployment grup oluştur (sadece soil sensörler)
az iot du deployment create
--account adu-tarim --instance prod
--deployment-id soil-fw-1.5.0
--group-id soil-sensors
--update-name soil-firmware --update-version 1.5.0
Strateji: %5 canary, 24 saat metrik takibi, sonra %100 rollout.
Maliyet
| Servis | Aylık (USD) |
|---|---|
| IoT Hub Standard S2 (1.5M msg/gün quota) | 250 |
| DPS | ~~5 |
| IoT Edge (free tier) | 0 |
| Stream Analytics (3 SU) | 240 |
| Cosmos DB (autoscale 1K-10K RU/s) | ~~340 |
| Azure Data Explorer (Dev SKU 2 vCPU) | ~~280 |
| Functions + Storage | ~~25 |
| NB-IoT/LTE-M data plan (operatör) | ~~480 |
| Toplam | ~~$1.620 |
4.200 cihaz başına ~$0.39/ay. Tasarruf: yıllık ~~480.000 TL su+gübre maliyeti azalması.
Sahada Düşülen Üç Tuzak
- Cihaz başına ayrı bağlantı kurmak: 4.200 doğrudan bağlantı IoT Hub quota’sını yer. Edge gateway aggregation şart.
- Telemetriyi sadece Cosmos’ta tutmak: 12 ay sonra Cosmos pahalı. ADX veya cold storage’a archival politikası kurulmalı.
- OTA’yı tek seferde tüm filoya yapmak: Bozuk firmware tüm filoyu offline bırakır. Canary + faz şart.
CloudSpark olarak Azure IoT Hub mimarisi, IoT Edge deployment, DPS otomasyonu, OTA firmware ve endüstriyel IoT projeleri için danışmanlık veriyoruz.



