Evirici çok mu ısındı acaba?

Benim Raspberry Pi cihazlarına olan ilgimi bu blogun okuyucuları biliyor. Yine birgün mühendislik hizmetleri verdiğimiz bir tesiste başımız sıkıştı ve imdadımıza Raspberry yetişti. Nasıl mı? Toplanın anlatıyorum 🙂

Merkezi evirici kullanılan bir sahadayız. Yaz sıcağında güneşin tam tepede olduğu saatlerde gün içerisinde eviricilerde güç kısılması oluyor ama nedenini bulamıyoruz. PR analizlerini gerçekleştirdiğimizde yüksek güçlerde ve sıcak havalarda enerji üretiminde bir düşüş olduğunu saptıyoruz. Bu aşamada raporumuza bunu eksiklik olarak yazıp geçiyoruz ama sorun bir türlü bulunmuyor. Bir gün yine bu konu ile ilgili saçma sapan bir sürü epostada cc’de yer alırken işe el atmaya karar verdim. Bunu anlamanın bir yolu olmalıydı.

“Ah bu cc’yi bulanın gözü kör olsun”

– Zeki Müren

Eviricinin modbus haberleşme listesinde her hata için bir kod tanımlanmıştı. Mevcutta kullanılan izleme sistemi ise bu hata kodlarından hiçbirini almıyordu. Sadece akım, gerilim, güç, sıcaklık vb. gibi bilgileri sistemde izleyebiliyorduk. Evirici de kendi içerisinde geçmiş durum kayıtlarını tutmuyordu. İzleme firması ile sonsuza giden yazışmaların sonucunda bize bu hata kodlarını INTEGER olarak verdiler. 16BIT registerda her BITin farklı bir anlama geldiği durumda bu sayıyı INTEGER olarak vermek nedir? Hata kodunun ne olduğunu anlamak için oturup 2 tabanına çekip sağ baştan bit-bit saymanız gerekiyor sayıyı. Böyle bir çözüm olabilir mi? Lakin bu epostaların birisinde modbus adresleme kitapçığı gözüme ilişti. O anda şimşek çaktı; bunları biz haricen neden okumuyoruz?

Blogumu okuyanlar bilir evde kendi dataloggerim ile enerji tüketimimi takip ediyorum. Düzenli olarak Grafana ve InfluxDB üzerinden evin enerji tüketimini 10sn’lik aralıklarla izlediğim için geçmiş verilerime baktım. Hiç kayıp yoktu -evde elektriğin gittiği günler hariç-. Sonra dedim ki bu sade-minik python kodu bu kadar sağlam çalışabiliyorsa tesiste neden çalışmasın?

Burada dikkat etmeniz gereken kelime “sade”. Benim minimalizm‘e olan takıntımı bilen dostlarım mevcuttur. Aslında tam bu noktada yıllardır süregelen, binlerce kişi tarafından yazılıp test edilmiş Linux gibi bir açık kaynak kodun üzerinde duruyorum; önemli olan işlerin Linux ve sistem araçları tarafından yapılabilecek kısımlarını “ben daha iyi yaparım yeeeaah!” havalarına girmeden onlara delege etmek. Gerisi çorap söküğü.

Linux var, Raspberry var, Python var. Gelin bu helvayı beraber karalım.

– Entegratör 28/m/İstanbul

Önce yine bir Raspberry’e ihtiyacımız var. Ben bu projede RPi3 kullandım ama RPi3 bile bu proje için çok fazla. Pi Zero işinizi görecektir ama Pi Zero’da ethernet çıkışı olmadığı için ben kolayına kaçtım. Daha önce de bahsettiğim Polly Electronics (Türk firması) bu konuda güzel bir shield (ek) geliştirmiş. Onu da kullanabilirsiniz.

https://www.instagram.com/p/B9MZrZjntDJ/

Zaten bu eklentiyi de Solarify için yapmış gibi duruyorlar. Bilmeyenler için Solarify Türkiye’de bilhassa GES konusunda izleme sistemleri üzerine çalışan genç ve yetenekli bir ekip. Neyse dağıtmadan konumuza dönelim.

Raspberry Debian (linux) üzerinde çalıştığı için “Lite” sürümü çok stabil çalışan bir sürüm. Debian’ı hali hazırda tüm sunucularımda kullanıyorum hayatta da değişmem. Raspbian (artık Raspberry OS oldu adı) ise yıllardır hiç tökezletmedi. Sorun yaşadığım noktalar sadece kendimin pintilik yaptığı ucuz güç kaynağı kullanmak, dandik SD kart kullanmak gibi konular oldu. O zaman ne diyoruz? Raspberry’i endüstriyel uygulamalarda kullanacaksanız;

Raspberry Pi’de SD karttan ve güç kaynağından tasarruf olmaz.

– Raspberry Gazisi

Öncelikle Python ile modbus TCP haberleşmesi yapacaktım. Python doğası gereği aynı işe yarayan pek çok kütüphaneye sahip. Bu aşamada doğru kütüphane ile ilerlemek ileride sizi pek çok dertten kurtarabilir. Python’un kendi içerisinde bir kütüphane olmadığı için harici kütüphane kullanmak zorundaydım. Aradığım cevabı stackoverflow’da buldum. Meraklıları buraya bakabilir. Makale Modbus RTU üzerine ama ben TCP için de geçerli olduğunu düşünüyorum.

Verileri okumamızı sağlayacak modbus kütüphanemizi (modbus-tk) seçtiğimize göre minimal bir kod yazabiliriz. Önce modüler bir modbus haberleşme scripti yazayım diye düşündüm ama modbus haberleşmesinde tek seferde birden fazla register okumak hız açısından önemli. Dışarıdan YAML benzeri bir dosya ile tek tek register okutmak hiç efektif olmuyor o zaman neyi nasıl okuyacağını ben belirleyeyim diye düşündüm. Bu da beni modbus haberleşmesi yazmak yerine o cihaz için bir sürücü yazmaya götürdü (evet aslında bu yaptığıma bir sürücü yazmak denebilir). Evirici için şöyle bir kod çıktı ortaya.

https://gist.github.com/orcunbaslak/3cf12a4596e971e0f5a98012dcceaa62

Eğer böyle özelleştirilmiş bir yapı değil de genel bir yapı kullansaydım her register için ayrı ayrı okuma gerçekleştirecektim. Bu modelde 3 okuma ile istediğim tüm verileri alabiliyorum. Gerisi dosyanın içerisinde kesip biçme, dönüştürme vb. Eğer ileride başka cihazları da okumam gerekirse hepsi için bir driver yazmam gerekecek ama tek seferde en hızlı şekilde okumuş olacağım. Bu modelin gelecek için daha uygun olduğunu düşünüyorum.

İlk olarak bu kodu yazdığımda nasıl daha hızlı okuyabilirim, nasıl paralelliyebilirim diye düşünmüştüm. Python’da işleri parallelemek için asyncio gibi asenkron çalışmayı sağlayan kütüphaneler var ama bu konulara girmek tek kişiyle yapılacak işler değil. En başında amacımız neydi? İşi sadeleştirmek. Ne kadar az kod, ne kadar çok open-source o kadar iyi.

Eğer ModbusTCP üzerinden farklı cihazlar okuyorsanız aynı programı birlikte 2-3 kere çalıştırıp farklı cihazları aynı anda okumasını sağlayabilirsiniz. Şimdi bu aşamada değinmek istediğim bir durum daha var; uygulamaların sürekli arka planda çalışması. Bizim sektörde datalogger cihazlarında veri okuma yazılımları sürekli arkaplanda çalışır. 1-2 haftadır hiç durmadan çalışan bir yazılımın ne hatalar ile karşılaşacağını öngöremezsiniz. Hata olsa da kolayca test edilebilir değildir ki bizim yaptığımız iş 6 eviriciyi 3sn’de okumak. 1 dakikalık veri aldığınız durumda sadece 3 saniye çalışıyor, 57 saniye hiçbir şey yapmıyoruz demek.

Dizayn aklınızda oluşmaya başladı mı? Basit bir python kodu; 6 evirici için 3 paralel çalışıyor, eviriciyi okuyup sonucu yazıp çıkıyor. Yani kod çalışıyor ve bitiyor kapanıyor. Debug etmeniz gereken süre 3-5sn’lik bir süre. Eğer bu aşamada hata varsa var; yoksa 1-2 hafta hiç durmadan çalışan bir yazılımı debug etmiyorsunuz. Bu işi paralellemek için Debian’da efsane bir shell komutumuz var

PARALLEL’le paralelle.

Şimdi burada 2-3 tane Python yorumlayıcısını paralel çalıştırdığın için fazla sistem kaynağı tüketiyorsun diyebilirsin ama Raspbian ilk açıldığında sadece 30MB bellek kullanıyor. Geriye 895MB kalıyor 🙂 (PiZero’da 418MB) Yani özetle kimseyi kasmadan, yormadan bu iş için fazla fazla kaynağımız var. Burada kilit nokta işlemci kaç çekirdekli ise o kadar paralellemek (RPi3 4 core, PiZero 1 core). Test etmedim ama PiZero’da da belki paralel çalıştırıldığında daha iyi verim alınabilir.

Bu scriptlerin her dakika çalıştırılması için ise Linux Cron’dan daha efektif ne olabilir sizce? Python’da infinite-loop ve scheduler ile artistlikler yapmak yerine yılların Cron’una bu işi versek? Muhteşem oldu. Saat gibi işliyor. Kod tam zamanında çalışıyor; execute ediyor ve çıkıyor. Süper! Gayet minimal.

CRON, İsviçre saatlerine taş çıkartan eski kadim dostumuz.

Şimdi dosyaları okuduk bunları sunucuya göndermemiz gerekli. Öncelikle kısa bir web servisi yazayım diye düşündüm; dosyayı alsın, parse etsin ve veritabanına yazsın ama sürekli bir web sunucunun çalışıp bir web servisi dinlemesi yine minimalist gelmedi. Bu konuyu eldeki imkanlar ile ve mümkünse Debian’ın kendi araçları ile çözmek istedim. Aslında bu konuda gidebileceğim tek bir dostum vardı; FTP sunucu.

Linux’da FTP sunucularda kullanmak üzere yazılmış LFTP diye bir araç var. Basit bir komut geçiyorsunuz ve tüm işlemleri (ve FTP sunucuların tüm nazını buzunu) bu yazılım hallediyor. Eğer Python kullansa idim ftplib kullanmak zorunda kalacaktım (Çok şükür Python içinde halihazırda var) ama bu aşamada oluşacak bir çalışma hatası kodun diğer kısımlarını etkileyebilirdi. Kod neydi? Kod minimalizmdi. Dolayısı ile mikroservis yapısı amacımız. Modbus’u okuyan kod ile FTP’ye dosyaları gönderen servis farklı olmalıydı. Burada da imdadıma LFTP yetişti.

LFTP sen ne güzel bir linux komutusun 🙂

Her saniye yazılan dosyaları kendi sunucuma FTP ile göndermek için de LFTP’yi yine eski dostumuz CRON üzerinden çağırdım. CRON’a her 5 dakikada bir LFTP’yi çalıştırmasını söyledim.

Voila! Dosyalar tıkır tıkır sunucuya gidiyordu; lakin her 5. dakikanın dosyası kayıptı. Acaba neden?

Multithreading’in en önemli problemlerinden birisi yarış durumudur. Bir çekirdekteki işlem diğer çekirdektekinden önce biterse sonuç istemediğimiz bir şey çıkabilir (ki bilgisayarlarımız çoğu zaman tek çekirdek çalışır o konuya şimdi girmeyeceğim) ki bizde de böyle bir durum oldu. 5. dakikada çalışan Modbus kodu daha yazmayı bitirmeden LFTP dosyaları gönderiyor kalanları da siliyordu. 5. dakika da gönderilmeden siliniyordu. Peki iki farklı program arasındaki yarış durumunu nasıl çözecektik? Tabiki yine bir linux komutu ile; FLOCK.

Şişe çevirme oynarken doğruluk mu cesaret mi sorusunun cevabı gelmeden diğer oyuncuya geçmenin önündeki en büyük engel; FLOCK.

Flock adı üstünde file-lock’dan geliyor. Eğer bir programlar silsilesi çalışacaksa bir dosya üzerinde kilit oluşturuyor; o kilit çözülmeden diğer programlar çalışamıyor. Bu aşamada LFTP ve Python Modbus aynı FLOCK dosyasına bağlı. Birisi çalışırsa diğeri çalışmıyor. Öteki çalışıyorsa beriki bekliyor gibi.

Peki ya birisi hiç durmaz ise? Her ne kadar gerek LFTP’nin configürasyon dosyasında, gerek de Python’da “bi dur artık yeter yeaw!” şeklinde korumalar koymuş olsam da bazen işler istediğiniz gibi gitmez. Bir program sürekli çalışıp takılı kalır, diğeri çalışmaz al başına belayı. Zaten cihaz Türkiye’nin diğer ucunda nasıl müdahale edeceksin (Burada da remote + watchdog timer var ama o konulara da şimdi girmiyorum)? Bu durumda karşımıza SIGINT’lerin efendisi güzide bir linux komutumuz çıkıyor; TIMEOUT.

TIMEOUT’u yazanlar demiş ki; okursa okur okumazsa ekime kadar yolu var.

TIMEOUT’da program 30sn’den fazla çalışırsa çak kill -9’u diyorsun; ohh mis. Sistemde hiç takılma olmuyor. Velevki saçma bir konuya takıldı; işte kız arkadaşına bozuldu v.s. basıyor cayırtıyı. Bu da bizim için gayet güzel bir emniyet sibobu.

Farkındaysanız ne kadar farklı hali hazırda bulunan aracı kullandık. Python’u ise sadece modbus okumak ve verileri json şeklinde gzipleyip yazmak için kullandık. Gzip benim ağ trafiğini azaltmak için kullandığım bir sıkıştırma; düz CSV transfer ettiğimizde dosyalar çok büyük oluyor (16KB->2KB). Tabi 16KB büyük mü diyeceksiniz? Elbette değil, mevcut ağlar bunu taşımak için gayet yeterli ama ben burada elde ettiğim boyut farkının bir kısmını TLS’de harcıyorum. Tabi TLS nedir diye soranlar olmuştur. Raspberry konusunu çok dağıtmadan kısaca değineyim; piyasadaki datalogger cihazları internet üzerinde FTP’ye dosya gönderirken tüm haberleşme açık gider gelir. Şifreler açık açık gözükür. Ağı dinleyen kişiler bunu kolayca gözlemleyebilir. Bu konuyu her datalogger/santral için farklı kullanıcı adı/şifre ile çözmeye çalışanlar var ama bu yeterli bir metod değil; önemli olan TLS (transport-layer-security) kullanılması. Siz tabi yine farklı user/pass kombinasyonu ile ekstra bir güvenlik sağlayın. TLS kullandığımızda veriler şifreli kanaldan gittiği için ~%10 gibi bir overhead oluşuyor. O sebeple 8 kat küçülttüğümüz dosya transfer sırasında %10 kadar büyüyebiliyor. Tabi bunlar çok küçük şeyler ama farkında olmak önemli. FTP’de de Let’s Encrypt’den edinilen imzalı sertifikalar kullanmak önemli yoksa verify edemeyebiliyor bazı yazılımlar.

Bu aşamada kod kullandığım tek kısım Modbus okuma kısmı oldu. Ne yazık ki linux araçlarında modbus için sistemle gelen bir araç yok; olsaydı onu kullanırdım. Geriye kalan tüm paketleme, kod çağırma, gönderme işleri linux tarafından hallediliyor. Yıllardır denetlene denetlene gelen yazılım parçacıkları ile. İşte bu açık kaynak kod dünyasının en güzel örneği. Çok minimal bir şekilde bir datalogger sahibi olabiliyorsunuz.

Şöyle bir geriye çekilip baktığınızda ne kadar az kod ile mevcut yazılımları kullanarak ne kadar çok şey yapabiliyoruz değil mi? Bu bence muazzam güzellikte bir durum. Yapmak istediğiniz çoğu şey önceden zaten yapılmış. Önemli olan sizin neyi nerede bulabileceğinizi bilmeniz. 2020 yılında; Github ve stackoverflow’un olduğu bir dünyada -eğer çok spesifik bir talebiniz yoksa- mevcut açık kaynak kodlu yazılımlar sizin pek çok işinizi çözebilir.

Ehhh; bir de ana konumuz vardı, kesintiye uğrayan bir inverter. Ona ne oldu diyenleriniz olabilir (bu kadar teknikten sonra ilk paragrafı hatırlamak da helal), birşey olmadı.

ÇÜNKÜ HAVALAR SOĞUDUĞU VE IŞINIM AZALDIĞI İÇİN INVERTER MEVCUT DURUMDA DA TAM GÜCE ULAŞAMAMAYA BAŞLADI

Şaka gibi değil mi? Ne yazık ki. Neyse, biz önümüzdeki maçlara hazırlanalım.

Fakir ama gururlu. Raspberry Pi’ımız şuanda bir switchin üzerinde ters dönmüş vaziyette eviricileri en ince detayına kadar okuyup bize bildiriyor 🙂

Yazılar eğer ilginizi çekiyorsa aşağıya eposta adresinizi yazarak abone olabilirsiniz

Her yeni makale yayınlandığında size e-posta gönderilecektir.


Yorumlar

“Evirici çok mu ısındı acaba?” için 2 yanıt

  1. Kitap aşığı avatarı
    Kitap aşığı

    Kütüphane mi kaldı diyenlere inat yaşasın kütüphaneli hayat !

    1. Kütüphane mi kaldı?

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir