Treni Kaçırmamak İçin Bir Rust Projesi
(lilymara.xyz)- San Francisco’da arabasız yaşamda, evden çıkmadan önce yakındaki durağa bir sonraki varış saatini hemen gösteren bir cihaz daha kullanışlı
- Eski bir Kindle jailbreak yapılarak duvara asılan bir e-mürekkep bilgi ekranına dönüştürüldü; ilk aşamada BART web sayfasının ekran görüntüsü düzenli olarak gösteriliyordu
- MUNI de eklenince çok sayıda tarayıcı sekmesi, Raspberry Pi’de bellek yükü ve HTTP 429 bir araya gelerek ekran görüntüsü tabanlı yapının güvenilirliğini düşürdü
- Rust ile yeniden yazılan sürüm, 511.org Stop Monitoring API üzerinden veri alıyor ve
skia-safeile Kindle çözünürlüğü ve 8-bit renk derinliğine uygun PNG’leri doğrudan üretiyor - Tarayıcı motoru kaldırılıp önbellekleme, hata gösterimi ve düzen ayarları da eklenince, günlük kullanım için uygun bir Kindle toplu taşıma ekranı ortaya çıktı
Evden çıkarken gereken bilgi basit
- San Francisco’da arabasız yaşayan yazar, otobüs, tren, tramvay, troleybüs, cable car ve feribot gibi toplu taşıma araçlarını sık kullanıyor
- CityMapper gibi uygulamalar bir yere giderken faydalı olsa da, evin önündeyken “nereye gidileceğinden” çok her hattın bir sonraki varış zamanı önemli
- Hangi durağın ve hangi hattın kullanılacağı zaten biliniyorsa, genel amaçlı navigasyon uygulamalarının mevcut konum-hedef modeli gereğinden karmaşık kalıyor
- Fikir, eski bir Kindle’ı akıllı ev ekranı olarak kullanan Matt Healy’nin yazısından ve eski bir Nook’u iCloud fotoğraf çerçevesine çeviren Ben Borgers’ın yazısından çıktı
Görüntüyü Kindle’da göstermeye kadar
- İlk adım, Kindle’a jailbreak yapıp USBNet’i etkinleştirerek SSH erişimi açmaktı
- Sonrasında cron göreviyle ekran düzenli aralıklarla yenilendi
- mobileread wiki ve forumlarındaki Kindle hack kaynakları başvuru olarak kullanıldı
- BART’ın Real Time Departure sayfası, istenen istasyon için sonraki trenleri ve otomatik yenilemeyi sunduğu için ilk veri kaynağı olarak uygundu
- Kindle CLI içindeki
eipsile PNG göstermeye çalışıldı ama başta görüntü aşırı esniyor veya kesiliyordu - Sorun, Kindle görüntüleme aracının 24-bit RGB PNG dosyalarını doğru işleyemeyip 8-bit görüntü gibi okumasıydı
- ImageMagick
convertkomutunda-colorspace gray -depth 8uygulanınca düzgün görüntülendi - Kindle ekran boyutuna uygun görüntü ve 8-bit renk derinliği temel koşullar oldu
- ImageMagick
İlk uygulama: Node.js, Puppeteer, Raspberry Pi
- İlk sunucu, Node.js ve Puppeteer ile BART web sayfasının gereken bölümünü yakalıyordu
- Yakalanan görüntü, Kindle ekran boyutuna ve 8-bit gri tonlamaya uygun biçime çevrildikten sonra HTTP endpoint’i üzerinden döndürülüyordu
- Sunucu Raspberry Pi üzerinde çalışıyor, Kindle ise cron ile her dakika görüntüyü çekip
eipsile gösteriyordu - BART sayfası zaten otomatik yenilemeyi desteklediği için, sunucu başlarken sayfa bir kez açık tutuluyor ve her istekte yeniden yüklenmiyordu
- Bu sürüm bir süre iyi çalıştı ama bazen yenileme duruyor, bazen de sunucu bellek yetersizliği nedeniyle yeniden başlatılmak zorunda kalıyordu
MUNI genişlemesiyle ortaya çıkan sınırlar
- San Francisco Bay Area’da 27 toplu taşıma işletmecisi var ve ilk uygulama yalnızca bölgesel hızlı tren sistemi BART’ı kapsıyordu
- Daha sonra MUNI’nin otobüs ve hafif raylı durak varış saatlerini de birlikte görmek istendi
- MUNI web sayfası da durak bazlı varış saatleri sunduğu için, önce birden fazla durak sayfasını Puppeteer ile yakalayıp ImageMagick ile birleştirme yöntemi denendi
- Ekrandaki 7 bölümün her biri, Puppeteer’ın açık tutması gereken bir tarayıcı sekmesine karşılık geliyordu
- Raspberry Pi’de yeterli bellek yoktu ve Chrome hafif değildi
- MUNI sayfası sık istek aldığında HTTP 429 döndürüyordu
- BART ve MUNI’yi birlikte gösteren ekran, yalnızca BART gösteren sürümden çok daha kararsızdı; tek bakışta bilgi veren bir ekran için daha güvenilir bir mimari gerekiyordu
Rust ile yeniden tasarlanan mimari
- Yeniden yazılan sürümde Puppeteer çıkarıldı ve Rust HTTP sunucusu PNG’yi doğrudan üretir hale geldi
- Dış arayüz Node.js sunucusuna benzer tutuldu ama iç uygulama tamamen değişti
- Başlıca üç bileşen vardı
- 511.org’dan sonraki varış saatlerini almak
- Varış saatlerini 8-bit PNG görüntü olarak işlemek
- Üretilen PNG’yi HTTP sunucusu üzerinden döndürmek
- HTTP sunucusu için Axum kullanıldı
- PNG çizimi için rust-skia kullanıldı
- Skia, Chrome’un da temel grafik kütüphanesi olduğundan, Puppeteer’a göre daha düşük yükle aynı çizim teknolojisinden yararlanılabildi
- Nihai sunucu kodu yaklaşık 1.200 satır tuttu ve yazıda önemli kısımlar özetlendi
511.org Stop Monitoring API’den veri alma
- 511.org’un Stop Monitoring API, Bay Area durakları için tahmini varış-kalkış saatlerini XML ve JSON olarak sunuyor
- Kullanılan endpoint biçimi
http://api.511.org/transit/StopMonitoring/…]şeklindeydi agency, Bay Area’daki 27 toplu taşıma işletmecisinden birini belirtir; SF MUNI için kodSF- API tek seferde yalnızca tek bir işletmecinin verisini getirebiliyor
- Ya belirli bir durağın varış saatlerini ya da ilgili işletmecinin tüm durak verisini döndürüyor
- Birden fazla durağın alt kümesini tek seferde çekmenin bir yolu bulunamadı
- 511.org API sınırı saatte 60 istek olduğundan, durak başına ayrı ayrı çok sayıda istek atmak gerçek zamanlı ekran için uygun değildi
- SF MUNI’nin tüm verisi istendiğinde HTTP isteği yaklaşık 5 saniye sürüyor, yaklaşık 27 MiB veri dönüyor ve biçimlendirilmiş JSON 1 milyon satırı aşıyordu
- Tüm yanıtta yaklaşık 26k adet
MonitoredStopVisitvardı ama ekranda aslında yalnızca belirli duraklar ve hatlar içinLineRef,DirectionRef,DestinationName,StopPointRef,ExpectedArrivalTime,DestinationDisplaygerekiyordu
Rust ile veri işlerken karşılaşılan ayrıntılar
- HTTP isteği, JSON ayrıştırma, zaman hesaplama, asenkron çalışma ve hata yönetimi için
reqwest,serde,serde_json,chrono,tokio,eyrekullanıldı - MUNI durak kimlikleri SF MUNI sitesindeki durak sayfalarından bulunabiliyor
- Örneğin Persia Ave & Paris St için inbound
15918, outbound15919olarak ayrı ID’ler var - MUNI durakları yön bazında ayrı ID kullanıyor
- Örneğin Persia Ave & Paris St için inbound
- 511.org yanıtı JSON’un başına UTF-8 Byte Order Mark ekleyerek dönüyordu; doğrudan
.json()ile ayrıştırılıncaexpected value at line 1 column 1hatası çıkıyordu - Yanıt
.text()ile UTF-8 metin olarak okununca BOM kaldırılıyor ve sonraserde_json::from_strile ayrıştırılabiliyordu - Filtrelemeden sonra geriye yalnızca ilgilenilen duraklar için yaklaşık 20 varış bilgisi kaldı; bu da başlangıçtaki 26k kayda göre çok daha yönetilebilirdi
- Veriler
LineRefveDirectionReftemelinde gruplanıpExpectedArrivalTime’a göre sıralandı; UTC zaman damgaları da “kaç dakika sonra” biçimine çevrildi
Skia ile Kindle için PNG üretimi
- PNG çizimi
skia-safeile kuruldu - Kindle ekran boyutu olan 1024x758 için
Gray8bitmap oluşturulup arka plan beyaza boyandı, ardından metin ve çizgiler çizildi - Önce yalnızca “Hello World” yazan bir PNG8 üretilerek çizim hattı doğrulandı
- Daha sonra sahte varış verileriyle inbound ve outbound olmak üzere iki sütunlu tablo benzeri bir görüntü üretildi
- Gerçek API verisi eklendiğinde, test verisine göre hedef ve varış süreleri daha çeşitli olduğu için sabit yerleşimde metin çakışmaları oluştu
- Hızlı yineleme ve API sınırından kaçınmak için yanıtı
data.jsoniçinde önbelleğe alan geçici kod eklendi
Ekran düzenini iyileştirme
- İlk gerçek veri ekranında, her satırdaki bilgi miktarı değiştiği için okunabilirlik düşüktü
- Yapılan iyileştirmeler şunlardı
- Varış sürelerini sağa hizalayarak tablonun sonundaki boşluğu azaltmak
- Her sürenin sonundaki
minifadesini kaldırıp yalnızca listenin sonundamingöstermek - Yalnızca sonraki 3 aracı göstermek
- Uzun hat adlarını hesaba katarak hedef adını daha sağa kaydırmak
- Daha sonra hat ID’sini yuvarlatılmış gri konuşma balonu gibi göstermek için
measure_strile metin sınırları hesaplandı - Hedef metni, hat ID balonunun sağ ucundan 15 piksel uzağa yerleştirildi
- Üste açık gri bir başlık eklenip
Muni InboundveMuni Outboundortalanarak gösterildi
PNG’yi Axum ile sunmak
- HTTP sunucusu
Axum 0.7ile kuruldu ve/stops.pngrotasında PNG döndürüldü - Yanıt başlığı
Content-Type: image/pngolarak ayarlandı - İlk olarak boş gövdeli bir HTTP 200 testi yapıldı, ardından görüntü üretim fonksiyonu bağlanarak PNG baytları doğrudan bellekten döndürülmeye başlandı
- Kindle’da
wgetile görüntü çekilipeipsile gösterildiğinde, başta görüntünün döndüğü ve kesildiği görüldü - Kindle varsayılan olarak dikey yön kullandığı için, yatay görünmesi adına çizimden önce döndürme matrisi uygulanması gerekti
- Görüntü boyutu
(758, 1024)olarak ters çevrildi - Tuval
90.0derece döndürüldü
- Görüntü boyutu
Gerçek kullanım sürümüne eklenen özellikler
- Gerçek kullanım sürümüne şu özellikler eklendi
- API verisini arka planda sürekli çekip HTTP sunucusunun hızlı yanıt vermesini sağlayan önbellek sistemi
- Sol altta saat gösterimi ve sağ altta veri önbelleği durumu
- Antialiasing
- Varış saati alanıyla çakışmaması için hedef adını kısaltma işlemi
- Hızlı ayırt edilebilmesi için hatlara göre farklı gri tonları kullanma
- Yapılandırma dosyası tabanlı ayarlar
- Hata olduğunda hatayı ve
.source()zincirini PNG olarak çizip doğrudan Kindle’da gösterebilme
- Birlikte hazırlanan sadeleştirilmiş sunucu kodu transit-kindle-simplified deposunda yer alıyor
- Duvara asılı gerçek Kindle’ı çalıştıran sunucu kodu transit-kindle deposunda bulunuyor
- BART ekran görüntüsü tabanlı sürüm yaklaşık Şubat 2023’te çalışıyordu; Rust ile yeniden yazılan sürümün son arayüz düzenlemeleri ise Ocak 2024’te tamamlandı
1 yorum
Hacker News yorumları
OneBusAway’in arkasındaki kâr amacı gütmeyen kuruluşta çalışıyorum. OneBusAway, her gün milyonlarca kişinin otobüs, tren, tramvay ve füniküler konumlarını ve varış saatlerini kontrol etmek için kullandığı açık kaynaklı bir proje.
Şehrinizde zaten bir OneBusAway sunucusu varsa, yeni SDK ile özel uygulamalar geliştirebilirsiniz: https://github.com/onebusAway/?q=sdk&type=all&language=&sort...
Sunucusu olmayan bir şehir için, bu yıl oluşturduğumuz Docker imajı ve OpenTofu yapılandırması ile GTFS/GTFS-RT beslemelerini REST API’ye dönüştürebilirsiniz.
BART da GTFS ve GTFS-RT sağlıyor: https://mobilitydatabase.org/feeds/mdb-53
ABD’deki diğer toplu taşıma kurumları da yeni federal kurallar nedeniyle en azından statik zaman çizelgesi verilerini GTFS olarak yayımlamak durumunda.
İlgili yazılımlara katkı verecek geliştiricilere her zaman ihtiyaç var; özellikle de günde 250 bin kullanıcının deneyimini iyileştirmeye yardımcı olacak iOS geliştiricilerine çok ihtiyaç var. İletişim: aaron@onebusaway.org
Docker: https://github.com/OneBusAway/onebusaway-docker / OpenTofu: https://github.com/OneBusAway/onebusaway-deployment
Süreç basit olursa kendi şehrimi de eklemek isterim. Son dönemde kütüphane ve SDK desteğine epey mühendislik zamanı harcanmış gibi görünüyor; ama yeni katkıcıların zaman ayırmasını kolaylaştıracak geliştirici deneyimi için kolay bir yola yatırım yapmak daha iyi olur gibi.
Örneğin bu doküman oldukça karmaşık: https://github.com/OneBusAway/onebusaway/wiki/Multi-Region
“4 dakika sonra varacak” yazıyor ama otobüs gözümün önünde ayrılıyor; ya da “5 dakika gecikmeli” denirken 2 dakika erken geliyor. Otobüsün hiç gelmediği de oluyor.
Muhtemelen kaynak veri sorunudur, ama bu güvenilirliğin neden bu kadar düşük olduğuna dair içeriden bilgi edinmek isterim. Bu arada Seattle için konuşuyorum.
BART ve MUNI’nin ikisi de General Transit Feed Specification’ı destekliyor ve bu verileri almanın standart bir yolu var.
https://gtfs.org/documentation/overview/#gtfs-realtime
Gerçekten çok hoşuma gitti. Eskiden Boston’da arabasız yaşarken, A’dan B’ye gitmenin birden fazla yolu olduğu ve “en iyi” seçeneğin zamana ya da arada uğranacak yerlere göre değiştiği durumları yönetmek için çok daha kaba bir şeyi kendim bir araya getirmiştim.
Örneğin işe gitmeden önce oğlumu okula bırakırdım ve bazen bırakıştan sonra kahvaltı ederdim. Sonraki kalkış saatlerini görmek, ilginç bir yerde 4 yaşındaki bir çocukla yürürken ortaya çıkan belirsiz durumlarda ya da kaçırınca sefer aralığı oluşacak bir trene yetişmek için acele edip etmemek gerektiği gibi kararları çok daha esnek vermeyi sağlardı.
https://oeffi.schildbach.de/index.html’ın henüz anılmamış olmasına şaşırdım. İstenen şeyi tam olarak yapıyor.
https://play.google.com/store/apps/details?id=nl.skywave.ovi... / https://apps.apple.com/nl/app/ovinfo/id1144468923
https://drgl.nl/
https://www.rijdendetreinen.nl/
https://spoorkaart.mwnn.nl/
Resmî uygulamadan çok daha iyi; en gerekli bilgiyi, yani yakındaki otobüs durağını ve sonraki otobüsün gerçek zamanlı saatini hemen gösteriyor.
Birleşik Krallık’taysanız, istasyonlardaki kalkış panolarını taklit eden bir kalkış panosu cihazı satın alabiliyorsunuz
https://ukdepartureboards.co.uk/store/product/desktop-depart...
https://tramli.ch/en
Ben de SF’de yaşıyorum ve aynı sorunu çözmek için A Better Ride adlı bir iOS uygulaması yaptım
Yalnızca çevredeki durakların toplu taşıma kalkış saatlerini gösteriyor. Amaç, toplu taşımayı öngörülebilir ve keşfetmesi kolay hâle getirerek stresi azaltmak. Para kazanma amacı olmadan, boş zamanlarımda yaptığım kişisel bir proje
Aktarma derdi olmadan gidebileceğiniz yerleri keşfetmenizi sağlıyor
Ben de bu alanda donanım geliştiriyorum ve son dönemde GTFS ile epey uğraştım; ulaşım verilerini ayrıştırıp göstermenin ne kadar çok iş gerektirdiği hemen belli oluyor
Uygunsa, her duraktan yapılabilecek yolculukları özetleyip gruplama konusundaki UX kararlarınızı ve backend’i konuşmak isterim
Kindle’ı jailbreak yapmanız ya da görüntü render etmeniz gerekmiyor
Kendi yaptığınız web sayfasını Kindle tarayıcısında açıp, debug komutuyla Kindle’ın “ekran koruyucu” reklamlarını veya uyku ekranını kapatmanız yeterli
Tarayıcı çubuğu Kindle’ın bir kenarında kalıyor ama cihazın yönünü çevirerek onu alta ya da sağa alabiliyorsunuz. Bunun karşılığında hava durumu·ulaşım·haber ekranını kolay HTML/CSS/JS ve istediğiniz backend diliyle yapıp, ucuz bir DigitalOcean 4 dolarlık instance gibi bir yerde çalıştırabilirsiniz
https://blog.notfaqs.com/2018/06/kindle-e-reader-disable-scr...
https://www.mobileread.com/forums/showthread.php?t=198334
document.documentElement.requestFullscreen()ile gerçek tam ekrana geçiyor ve durum çubuğu da görünmüyor. Yerel toplu taşıma API’sine web sayfasından doğrudan erişilebildiği için backend’e de gerek kalmadıYine de yerel ağdaki bir sunucuyla iletişim kuracak şekilde ayarlanırsa sorun olmayacağını düşünüyorum
Bu kullanım senaryosunu pek anlamamış gibisiniz. “Trene binmek” istemiyorum; A’dan B’ye gitmek istiyorum
Tren bozulduysa, grev varsa, hat 13.00-16.00 arasında kapalıysa ya da sefer saati değilse alternatif istiyorum. Bu yüzden benim ihtiyacım olan şey Google Maps’in verdiği, ya da vermeye çalıştığı şey
Ferry Building’den Oakland’a gitmek istiyorsam ve BART arızalıysa feribot daha iyi olabilir; saat geçse taksi ya da Uber’dan başka seçenek kalmayabilir
Tokyo’da Shibuya’dan Azabujuban’a gidiyorsam Ginza Line→Namboku Line, Hanzomon Line→Oedo Line, Yamanote Line→Namboku Line, 6 numaralı otobüs, taksi gibi seçenekler var
Her hattın istasyonları ve otobüs durakları arasında da 3-8 dakika yürüme var; şu anda neye daha yakın olduğunuz seçimi etkiliyor. Geç kalıp kalmadığınız, bavulunuzun büyük ya da ağır olup olmadığı da önemli
Örneğin bir yere giderken 39 numaralı otobüse binip 15 dakika yürümek yeterliyken, Google’a sorduğunuzda 2 aktarmalı bir rota veriyor. Şanslıysanız tek otobüs+yürüme ile benzer sürede oluyor
Bu yüzden 39 numaralı otobüsün ne zaman geleceğini bilmek istiyorsam hedefi bilerek farklı söylemem gerekiyor
Ayrıca bulunduğum yerde Google’ın gerçek zamanlı verileri şüpheli; işletmecinin ya da bazı üçüncü tarafların verileri daha güvenilir
Gerçek zamanlı olarak çok gelişmiş plan yapmanız gereken durumlar da var ve böyle bir aracın olması güzel olur; ama günlük ulaşım çok daha basit araçlarla da yeterince karşılanabiliyor
Verdiğiniz Tokyo örneği de ilginç, ama Google’a göre çoğu toplu taşıma seçeneği 30-40 dakika sürdüğü için kaba planlamada neredeyse eşdeğer. Taksi daha hızlı, bisiklet de neredeyse benzer
Tren bozulmuşsa ya da grev varsa, bu gerçek zamanlı tren listesinde beklenmedik bir boşluk olarak ortaya çıkar
Şehir içinde dolaşırken Google Maps’i açıp hedefi giriyorum, ama 500 kez gittiğim bir yere evden çıkarken özellikle açmıyorum
Bu, yalnızca Disneyland içindeki mağaza alışverişi ya da yemek deneyimini ölçüt almak kadar anlamsız. Sadece Suica’yı okutmak bile başka yerlere göre birkaç kat daha hızlı; zaten bazı yerlerde desteklenmiyor bile
Çok özelliği var ama Tokyo’da ne kadar desteklendiğini bilmiyorum. Londra’da eve götürmesini istediğinizde maliyet, yürüme mesafesi, hız, aktarma, erişilebilirlik vb. kriterlere göre optimize edilmiş birden fazla yol gösteriyor
Yeniden değerlendirdiğim Lenovo ThinkSmart View tablet/toplantı odası cihazında Home Assistant ve yerel toplu taşıma kurumu entegrasyonunu ekleyerek benzer bir şey kullanıyorum
Avantajı, kullanıma çok daha hazır olması. Elbette Lenovo’ya özel bir Android ROM yükledim, ama istediğim her şeyi gösterebiliyor; aydınlatma veya robot süpürge gibi şeyleri de kontrol edebiliyorum
BART haritasını fiziksel bir LED tabelaya dönüştüren güzel bir ürün de var: https://www.designrules.co/