Geçen gün Twitter’dan bir tweet paylaşmıştım. Yeni bir yazının yolda olduğu mesajı ile beraber. Ahaaa da işte bu o yazı 🙂 Buyrun başlıyoruz…
Pazar akşamı eğlencesi… Raspberry Pi, sensörler, dirençler vs…. Tabi ki Azure ile entegrasyon… Ve tabi ki yeni bir yazı… 👨🏻💻#IoT #Azure pic.twitter.com/HEfawQfB8s
— Arda Cetinkaya (@ArdaCetinkaya) November 12, 2017
Bu küçük ve basit projeden bahsederek, Internet Of Things(IoT)’in ne olduğu, neleri nasıl yapabiliyoruz, bunu bir “konsept” olarak anlatmaya çalışacağım.
Öncelikle projemiz Raspberry Pi(3) üzerinde; Windows IoT Core ile basit bir sıcaklık ve nem ölçer. DHT11 sıcaklık sensörü ile ortamdaki sıcaklığı ölçüp, I2C üzerinden bir LCD(16×2) ekrana bunu yazdırıyoruz. Aynı zamanda Azure IoT Hub servisi üzerinden bu bilgiyi düzenli aralıklar ile Microsoft Azure’a aktarıyoruz. Kullandığım sensör, bunların bir biri ile bağlantısı ve bunları nasıl alabilirsiniz gibi konuları yazının sonunda bulabilirsiniz. Şimdilik bunlara takılmayalım.
Nem ve sıcaklık ölçen Raspberry Pi cihazımızı basit bir IoT cihazı olarak düşünebiliriz. Bu cihazın üzerinde Windows IoT Core çalışıyor. Dolayısıyla UWP tipinde bir uygulamayı bu cihazın üzerinde geliştirip, çalıştırabiliyoruz. Window IoT Core’da çalışacak uygulamamız bir Background Application(IoT) uygulaması olacak. Dolayısıyla projemizi seçerken buna göre seçmek gerekecek. Tabi öncelikle proje şablonunu yüklemek gerekecek. Yüklemek için Visual Studio Market Place‘e gitmeniz yeterli.
Projemize başlamadan önce, geliştireceğimiz senaryo için aşağıdaki NuGet paketlerini de projemize eklememiz gerekecek.
Dht, sensörümüzü kullanabilmemiz için gerekli kütüphane, Microsoft.Azure.Device.Client, IoT cihazımızın Azure IoT Hub ile iletişim kurmasını sağlayan kütüphaneler. Microsoft.NETCore.UniversalWindowsPlatform ise Windows IoT Core için temel kütüphaneleri barındırıyor. Bu zaten projeyi yarattığımız zaman otomatik olarak geliyor.
Projeyi yarattıktan sonra aşağıdaki gibi bir metoda sahip bir sınıf oluşacak.
public sealed class StartupTask : IBackgroundTask { public void Run(IBackgroundTaskInstance taskInstance) { } }
IBackgroudTask arayüzünden oluşturulan bu sınıf, Windows IoT Core’da arka tarafta çalışan uygulamalar için başlangıç noktası. Run() metodunun içerisinde bütün gereksinimlerimizi yazabiliriz. Bizim projemizde de burası giriş noktamız.
public void Run(IBackgroundTaskInstance taskInstance) { //Attach to cancel event to cancel if it is needed; taskInstance.Canceled += TaskInstance_Canceled; _deferral = taskInstance.GetDeferral(); _deviceClient = DeviceClient.CreateFromConnectionString(_deviceConnectionString); //Thread timer to check sensor data _periodicTimer = ThreadPoolTimer.CreatePeriodicTimer(new TimerElapsedHandler(PeriodicTimerCallback), TimeSpan.FromSeconds(60)); //Init PINs and LCD _pin = GpioController.GetDefault().OpenPin(4, GpioSharingMode.Exclusive); _screen = new displayI2C.LCDisplay(DEVICE_I2C_ADDRESS, I2C_CONTROLLER_NAME, RS, RW, EN, D4, D5, D6, D7, BL); _screen.Init(); }
Burada bir kaç önemli satırın üzerinden geçerek bazı şeyleri netleştirmek isterim. Öncelikle uygulamamızın Azure IoT Hub ile iletişimini sağlayan DeviceClient sınıfı üzerinden sağlıyoruz. 8 satırda, bu cihazımızı oluşturuyoruz. Azure tarafında oluşturduğumuz cihaz bilgileri ile cihazımız bu sınıf üzerinden eşleşiyor. Cihazımızın Azure IoT Hub ile iletişimini sağlamak için öncelikle Azure IoT Hub üzerinde bir Hub yaratıp, daha sonra cihazımızı Provision etmemiz lazım. Bunlar ile ilgili daha ayrıntılı linkleri yine aşağıda paylaşacağım. Azure IoT Hub üzerinde tanımladığımız Hub bilgileri içerisinde bir ConnectionString bilgisi var. Bunu DeviceClient.CreateFromConnectionString() ile kullanıp cihazımızı Hub ile eşleştiriyoruz. Burada önemli bir nokta var, bizim senaryomuzda Hub’ın Azure Iot Hub tarafında yaratılmış olduğunu varsaydık. Eğer orada yaratmadıysak, kod tarafında önce Hub’ı yaratan bir geliştirmemiz lazım.
TheadPoolTimer ile sensörleri ne kadar bir sürede kontrol edeceğimizi belirtiyoruz. Daha sonra Raspberry Pi tarafındaki PIN’leri ve LCD ekranımızı tanımlıyoruz. LCD ekranı için yine bir kütüphane kullandım.
ThreadPoolTimer‘ı yaratırken PeriodicTimerCallback isimli callback metodumuz içinde sensör bilgilerini okuyacak ReadTemprature() metodunu yazıyoruz. Burada dikkat ederseniz, iptal etme durumunu da kontrol ediyoruz. Yani işi biraz daha ileri götürüp, dışardan bir komut ile sensörlerin çalışmasını ve hatta uygulamayı durdurabiliriz.
private void PeriodicTimerCallback(ThreadPoolTimer timer) { if ((_cancelRequested == false)) { ReadTemprature(_pin); } else { _periodicTimer.Cancel(); _deferral.Complete(); } } public async void ReadTemprature(GpioPin pin) { Dht11 dht11 = new Dht11(pin, GpioPinDriveMode.Input); var result = await dht11.GetReadingAsync(); if (result.IsValid) { var temp = Convert.ToSingle(result.Temperature); var humidity = Convert.ToSingle(result.Humidity); _screen.ClearScreen(); _screen.Print($"Temp : {temp}"); _screen.GotoSecondLine(); _screen.Print($"Humidity : {humidity}"); var telemeteryData = new { date = DateTime.Now, temperature = temp, humidity = humidity }; var messageString = JsonConvert.SerializeObject(telemeteryData); var message = new Microsoft.Azure.Devices.Client.Message(Encoding.ASCII.GetBytes(messageString)); message.Properties.Add("lowTemp", (temp < 20) ? "true" : "false"); await _deviceClient.SendEventAsync(message); Debug.WriteLine($"{DateTime.Now} > Sending message to IoT Hub {messageString}"); await Task.Delay(1000); } }
ReadTemprature() metodu içerisinde Dht kütüphanesi ile sıcaklık ve nem ölçen sensörümüzün bilgilerine ulaşıyoruz. _screen değişkeni ile tanımlı olan LCD ekranımıza bunları yazdırıp hemen sonrasında da _deviceClient.SendEventAsync() metodu ile Azure IoT Hub’a bu bilgileri gönderiyoruz. Bu gönderdiğimiz verilere(mesajlar) çeşitli ek bilgiler ekleyip bunlara göre çeşitli Route’lar tanımlayabiliriz. Yukarıdaki örnekte, lowTemp şeklinde bir özellik ile sıcaklık 20 derecenin altındaysa, true şeklinde ek bir bilgi gönderiyoruz.
Görmüş olduğunuz gibi oldukça kolay. Açıkçası çok fazla elektronik devrelerden anlayan biri değilim, ancak internette anlayan ve bunları paylaşan bir çok insanın geliştirdiği kütüphaneler ile artık çok da fazla anlamaya gerek yok. Çözüm üreteceğiniz problemleri tespit etmek, problemleri çözmekten daha önemli artık.
Azure IoT Hub tarafından devam edelim. IoT cihazımızdan gönderilen bu bilgileri nasıl iletip, nasıl işleyebiliriz biraz da bundan bahsetmek istiyorum. Azure tarafında bir Endpoint ve bu Endpoint’e yöneltecek bir Route tanımlamamız gerekmekte. Varsayılan olarak gelen iki tane Endpoint, IoT Hub ile tanımlı bir şekilde geliyor. Burada biz Events ile devam edeceğiz.
Biraz ama Custom Endpoints’lerden bahsetmek istiyorum ki, Endpoint kavramı biraz daha otursun. Endpoint’leri, cihazlardan gelen verilerin iletildiği son noktalar olarak düşünebiliriz. Bu son noktalar yine Azure servisleri aslında. Burada kullanabileceğimiz servisler, Event Hub, Service Bus ve Azure Storage. Yani, cihazımızdan gelen bir veri ile bir event oluşturabilir, Service Bus üzerinde bir mesaj oluşturabilir ya da Azure Storage’da saklayabiliriz. Bu sayede farklı uygulamalara iletebiliriz. Mesela Endpoint olarak Service Bus kullanıp, Service Bus’a gelen mesaj ile bir Azure Function tetikleyip farklı bir iş yapabiliriz. IoT cihazımızdan gelen sıcaklık bilgsine göre, telefona bildirim gönderip bilgilendirme ya da farklı IoT cihazları sayesinde kombi ya da ısıtıcı gibi sistemleri tetikleyebiliriz.
IoT Hub’da yarattığımız Endpoint’lere cihaz verilerini iletmek için Routes tanımlarını kullanıyoruz. Mesela cihazdan gelen verinin belli değerlerine göre farklı Endpoint’lere iletip, farklı işlemlerin yapılmasını sağlayabiliriz. Az önce yukarıda bahsettiğim lowTemp özelliği ile Route kuralı yazarak farklı Endpoint’lere yöneltebiliriz.
Son olarak IoT cihazlarından gelen verileri farklı uygulamalarda nasıl okuyabiliriz bundan bahsetmek istiyorum. Yukardaki sıcaklık ve nem ölçen cihazımızın bilgilerini takip eden bir client(konsol) uygulaması olsun basitçe. IoT Hub’daki Event’leri alabilmek için projemize Nuget’den WindowsAzure.ServiceBus paketini eklememiz lazım. Bu uygulama örneğini ile ilgili ayrıntıları buradan daha iyi bir şekilde öğrenebilirsiniz. Ben biraz basitçe anlatmaya çalışacağım. Yine kodları GitHub üzerinden bulabilirsiniz.
public class EventListener { private readonly string _connectionString = "SHARED ACCESS CONNECTION STRING"; private readonly string _endPoint = "messages/events"; private EventHubClient _eventHubClient; private string[] _partions; public EventListener() { _eventHubClient = EventHubClient.CreateFromConnectionString(_connectionString, _endPoint); _partions = _eventHubClient.GetRuntimeInformation().PartitionIds; } public void Start() { CancellationTokenSource cts = new CancellationTokenSource(); System.Console.CancelKeyPress += (s, e) => { e.Cancel = true; cts.Cancel(); Console.WriteLine("Exiting...Please wait."); }; var tasks = new List<Task>(); foreach (string partition in _partions) { tasks.Add(ReceiveMessagesFromDeviceAsync(partition, cts.Token)); } Task.WaitAll(tasks.ToArray()); } private async Task ReceiveMessagesFromDeviceAsync(string partition, CancellationToken ct) { var eventHubReceiver = _eventHubClient.GetDefaultConsumerGroup().CreateReceiver(partition, DateTime.UtcNow); while (true) { if (ct.IsCancellationRequested) break; EventData eventData = await eventHubReceiver.ReceiveAsync(); if (eventData == null) { Console.WriteLine("No data"); continue; } string data = Encoding.UTF8.GetString(eventData.GetBytes()); Console.WriteLine($"Message is received. Data {data}"); } } }
Yukarıdaki kodlarda basitçe bir EventListener adında bir sınıf göreceksiniz. IoT Hub tarafında, cihazdan gelen mesajları Event Hub’a yönelttiğimiz için Event Hub’ı dinleyerek bu verilere ulaşacağız. EventListener sınıfında constructor’da EventHub.CreateFromConnectionString() ile yine connectionstring’i belirterek, ek olarak da hangi path üzerinden event’leri dinleyeceksek bunu belirtiyoruz.ReceiveMessagesFromDeviceAsync() metodunda ilgili ConsumerGroup()’una erişip Event Reveiver oluşturuyoruz, ve gelen event’leri ReceiveAsync() metodu ile alıyoruz. Açıkçası bu noktalar direkt olarak IoT Hub ile ilgili değil. Azure Service Bus ve Event Hub konularını araştırırsanız daha ayrıntılı bilgilere ulaşabilirsiniz. Söyleyebileceğim tek şey IoT Hub tarafında default olarak gelen Event endpoint’i Azure’daki Event Hub’ı kullanıyor. Çok farklı değil yani. Sonuç olarak konsol uygulamamız çıktısı, IoT cihazımdan gelen mesajlar, veriler olacaktır.
Başta da dediğim gibi IoT konseptini daha iyi anlamak, neler nasıl yapılabilir biraz bunlar konusunda ip ucu vermek amaçlı paylaşmak istedim. Umarım faydalı olmuştur. Çok geniş ve kapsamlı bir çok konu, örnek, çözüm, vs.. var. Bunlar ile ilgilenmek gerçekten çok keyifli. Keyif aldıkça ve zaman ayırabildikçe burdan paylaşmaya çalışacağım. Sizin de böyle çalışmalarınız varsa çekinmeden iletişime geçebilirsiniz. Paylaştıkça daha güzel 🙂
Bu arada son halini de paylaşmak isterim. LEGO’dan güzel bir kutu ile olayın bütün rengi değişiyor 😛
Son olarak aşağıda faydalı olabileceğini düşündüğüm bir kaç link paylaşıyorum. Yazıda bahsettiğim kodlar dahil.
- Yukarıda bahsedilen tüm kodlar: https://github.com/ardacetinkaya/IoT/tree/master/IoT.Learn
- Raspberry Pi 3: https://www.robotistan.com/raspberry-pi-3
- LED Ekran: https://www.robotizmo.net/2×16-lcd-ekran-mavi-iic-i2c-seri-61
- DHT11 Sıcaklık ve Nem Sensörü: https://www.robotistan.com/dht11-sicaklik-ve-nem-sensoru
- Windows IoT Core kurulumu: https://developer.microsoft.com/en-us/windows/iot/getstarted
- Windows IoT Core Provision: https://docs.microsoft.com/en-us/windows/iot-core/connect-to-cloud/connectdevicetocloud
- Windows IoT dökümantasyon: https://docs.microsoft.com/en-us/windows/iot-core/
- DHT sensörü C# kütüphanesi: https://www.nuget.org/packages/Dht/