2 poin oleh GN⁺ 2024-10-25 | 1 komentar | Bagikan ke WhatsApp
  • Dalam kehidupan berpindah tanpa mobil di San Francisco, perangkat yang bisa langsung menampilkan waktu kedatangan berikutnya di halte terdekat sebelum keluar rumah ternyata lebih praktis
  • Sebuah Kindle lama dijailbreak lalu diubah menjadi papan informasi e-ink yang dipasang di dinding, dan pada awalnya menampilkan tangkapan halaman web BART secara berkala
  • Saat MUNI ikut ditambahkan, banyak tab browser, beban memori Raspberry Pi, dan HTTP 429 membuat arsitektur berbasis tangkapan layar menjadi kurang andal
  • Versi yang ditulis ulang dengan Rust mengambil data dari Stop Monitoring API milik 511.org dan langsung membuat PNG yang sesuai dengan resolusi Kindle dan kedalaman warna 8-bit menggunakan skia-safe
  • Dengan menghilangkan mesin browser dan menambahkan cache, tampilan error, serta penyesuaian tata letak, proyek ini akhirnya menjadi papan tampilan transportasi umum Kindle yang layak dipakai sehari-hari

Informasi yang dibutuhkan saat hendak keluar rumah itu sederhana

  • Saat bepergian tanpa mobil di San Francisco, penulis sering menggunakan transportasi umum seperti bus, kereta, trem, trolleybus, cable car, dan feri
  • Aplikasi seperti CityMapper berguna untuk panduan menuju tujuan, tetapi di depan rumah, yang lebih penting daripada “mau pergi ke mana” adalah waktu kedatangan berikutnya untuk tiap rute
  • Jika halte dan rute yang akan dipakai sudah diketahui, model lokasi saat ini dan tujuan pada aplikasi navigasi umum terasa lebih rumit daripada yang dibutuhkan
  • Ide ini terinspirasi dari tulisan Matt Healy tentang penggunaan Kindle lama sebagai layar smart home dan tulisan Ben Borgers tentang penggunaan Nook lama sebagai bingkai foto iCloud

Sampai gambar bisa ditampilkan di Kindle

  • Langkah pertama adalah menjailbreak Kindle untuk mengaktifkan USBNet dan memungkinkan akses SSH
    • Setelah itu, tampilan diperbarui secara berkala dengan tugas cron
    • Materi peretasan Kindle di wiki dan forum mobileread dipakai sebagai referensi
  • Halaman Real Time Departure milik BART menyediakan kereta berikutnya untuk stasiun yang diinginkan serta pemuatan ulang otomatis, sehingga cocok sebagai sumber data awal
  • PNG sempat dicoba ditampilkan dengan eips dari CLI Kindle, tetapi awalnya gambar sangat melar atau terpotong sehingga tidak bisa dipakai
  • Penyebabnya adalah alat tampilan Kindle tidak menangani PNG RGB 24-bit dengan benar dan membacanya seolah gambar 8-bit
    • Setelah -colorspace gray -depth 8 diterapkan di ImageMagick convert, gambar tampil normal
    • Gambar yang sesuai ukuran layar Kindle dan kedalaman warna 8-bit menjadi syarat utama

Implementasi pertama: Node.js, Puppeteer, Raspberry Pi

  • Server awal menggunakan Node.js dan Puppeteer untuk mengambil tangkapan area yang dibutuhkan dari halaman web BART
  • Gambar hasil tangkapan kemudian diubah agar sesuai ukuran layar Kindle dan grayscale 8-bit, lalu dikembalikan lewat endpoint HTTP
  • Server dijalankan di Raspberry Pi, dan Kindle mengambil gambar setiap menit lewat cron lalu menampilkannya dengan eips
  • Karena halaman BART sendiri mendukung pemuatan ulang otomatis, implementasinya membuka halaman sekali saat server dimulai dan tidak memuat ulang dari awal untuk setiap permintaan
  • Versi ini sempat bekerja dengan baik, tetapi kadang pemuatan ulang berhenti atau server perlu dijalankan ulang karena kehabisan memori

Batasan yang terlihat saat diperluas ke MUNI

  • Di wilayah Teluk San Francisco ada 27 operator transportasi umum, dan implementasi pertama hanya menangani BART, yaitu kereta cepat regional
  • Setelah itu muncul keinginan untuk ikut melihat waktu kedatangan bus dan light rail MUNI
  • Halaman web MUNI juga menyediakan waktu kedatangan per halte, sehingga pada awalnya dicoba pendekatan mengambil tangkapan beberapa halaman halte dengan Puppeteer lalu menggabungkannya memakai ImageMagick
  • Tujuh bagian layar masing-masing berarti tab browser yang harus dipertahankan oleh Puppeteer
    • Raspberry Pi tidak punya memori yang cukup, dan Chrome bukanlah aplikasi ringan
    • Halaman MUNI mengembalikan HTTP 429 jika diminta terlalu sering
  • Layar gabungan BART dan MUNI jauh lebih tidak stabil dibanding layar BART saja, sehingga papan informasi sekali lihat membutuhkan arsitektur yang lebih andal

Arsitektur yang didesain ulang dengan Rust

  • Versi tulis ulang menghapus Puppeteer dan menggantinya dengan server HTTP Rust yang langsung membuat PNG
  • Antarmuka publik dipertahankan mirip dengan server Node.js, tetapi implementasi internalnya berubah total
  • Ada tiga komponen utama
    • Mengambil waktu kedatangan berikutnya dari 511.org
    • Merender waktu kedatangan menjadi gambar PNG 8-bit
    • Mengembalikan PNG yang dihasilkan lewat server HTTP
  • Server HTTP dibuat dengan Axum
  • Untuk rendering PNG digunakan rust-skia
    • Skia juga merupakan pustaka grafis dasar Chrome, jadi teknik rendering bisa dimanfaatkan dengan beban yang lebih ringan daripada Puppeteer
  • Kode server akhirnya sekitar 1.200 baris, dan hanya bagian pentingnya yang dirangkum

Mengambil data dari 511.org Stop Monitoring API

  • Stop Monitoring API milik 511.org menyediakan perkiraan waktu kedatangan dan keberangkatan halte di wilayah Teluk dalam format XML dan JSON
  • Endpoint yang digunakan berbentuk http://api.511.org/transit/StopMonitoring/…]
  • agency menentukan salah satu dari 27 operator transportasi umum di wilayah Teluk, dan kode untuk SF MUNI adalah SF
  • API ini hanya bisa mengambil data untuk satu operator dalam satu kali permintaan
    • API dapat mengembalikan waktu kedatangan untuk satu halte tertentu atau data seluruh halte milik operator tersebut
    • Tidak ditemukan cara untuk mengambil subset beberapa halte sekaligus
  • Batas API 511.org adalah 60 permintaan per jam, sehingga pendekatan meminta data beberapa kali per halte tidak cocok untuk tampilan real-time
  • Saat meminta seluruh data SF MUNI, satu permintaan HTTP memakan waktu sekitar 5 detik, mengembalikan sekitar 27 MiB data, dan JSON yang sudah diformat melebihi 1 juta baris
  • Respons penuh berisi sekitar 26k entri MonitoredStopVisit, tetapi layar sebenarnya hanya membutuhkan LineRef, DirectionRef, DestinationName, StopPointRef, ExpectedArrivalTime, dan DestinationDisplay untuk halte dan rute tertentu

Detail kecil yang ditemui saat memproses data di Rust

  • reqwest, serde, serde_json, chrono, tokio, dan eyre dipakai untuk permintaan HTTP, parsing JSON, perhitungan waktu, eksekusi asinkron, dan penanganan error
  • ID halte MUNI bisa dilihat di halaman halte pada situs SF MUNI
    • Misalnya untuk Persia Ave & Paris St, ada 15918 untuk inbound dan 15919 untuk outbound
    • Halte MUNI memiliki ID terpisah untuk tiap arah
  • Respons 511.org mengembalikan UTF-8 Byte Order Mark di depan JSON, dan jika langsung diparse dengan .json() akan muncul error expected value at line 1 column 1
  • Jika respons dibaca sebagai string UTF-8 dengan .text(), BOM dihapus sehingga bisa diparse menggunakan serde_json::from_str
  • Setelah difilter, hanya tersisa sekitar 20 data kedatangan untuk halte yang diminati, jauh lebih mudah ditangani dibanding 26k entri awal
  • Data kemudian dikelompokkan berdasarkan LineRef dan DirectionRef, diurutkan menurut ExpectedArrivalTime, lalu timestamp UTC diubah ke format “berapa menit lagi”

Membuat PNG untuk Kindle dengan Skia

  • Rendering PNG dibuat dengan skia-safe
  • Sebuah bitmap Gray8 berukuran 1024x758, sesuai layar Kindle, dibuat lalu diisi latar putih sebelum teks dan garis digambar di atasnya
  • Pipeline rendering mula-mula diuji dengan membuat gambar PNG8 yang menampilkan “Hello World”
  • Setelah itu dibuat gambar berbentuk tabel dengan dua kolom, inbound dan outbound, menggunakan data waktu kedatangan palsu
  • Saat digabungkan dengan data API nyata, tujuan dan waktu kedatangannya lebih beragam daripada data uji, sehingga tata letak tetap menyebabkan teks saling bertumpuk
  • Untuk iterasi cepat dan menghindari batas API, ditambahkan kode sementara untuk menyimpan respons ke data.json

Menyempurnakan tata letak tampilan

  • Tampilan awal dengan data nyata kurang mudah dibaca karena jumlah data yang ditampilkan di tiap baris berbeda-beda
  • Perbaikannya meliputi
    • Meratakan waktu kedatangan ke kanan untuk mengurangi ruang kosong di akhir tabel
    • Menghapus min setelah tiap waktu dan hanya menaruh min di akhir daftar
    • Hanya menampilkan 3 kendaraan berikutnya
    • Menggeser nama tujuan ke kanan dengan mempertimbangkan nama rute yang panjang
  • Setelah itu, ID rute ditampilkan dalam bentuk gelembung abu-abu membulat dengan menghitung batas teks lewat measure_str
  • String tujuan ditempatkan 15 piksel dari ujung kanan gelembung ID rute
  • Di bagian atas ditambahkan header abu-abu muda, dengan Muni Inbound dan Muni Outbound diratakan ke tengah

Menyajikan PNG dengan Axum

  • Server HTTP dibuat dengan Axum 0.7 dan mengembalikan PNG melalui rute /stops.png
  • Header respons diatur ke Content-Type: image/png
  • Awalnya HTTP 200 diuji dengan body kosong, lalu fungsi pembuatan gambar dihubungkan agar byte PNG langsung dikembalikan dari memori
  • Saat gambar diambil di Kindle dengan wget dan ditampilkan memakai eips, mula-mula muncul masalah gambar terputar dan terpotong
  • Karena Kindle secara default digunakan dalam orientasi potret, perlu diterapkan matriks rotasi sebelum rendering agar tampil seperti layar lanskap
    • Ukuran gambar dibalik menjadi (758, 1024)
    • Kanvas diputar 90.0 derajat

Fitur tambahan pada versi pemakaian nyata

  • Versi yang benar-benar dipakai menambahkan fitur berikut
    • Sistem cache yang terus mengambil data API di latar belakang agar server HTTP bisa merespons dengan cepat
    • Tampilan waktu di kiri bawah dan status cache data di kanan bawah
    • Anti-aliasing
    • Pemotongan nama tujuan agar tidak bertabrakan dengan area waktu kedatangan
    • Pemberian tingkat abu-abu berbeda untuk tiap rute agar lebih cepat dibedakan
    • Konfigurasi berbasis file pengaturan
    • Jika terjadi error, error beserta rantai .source() dirender menjadi PNG agar bisa langsung dilihat di Kindle
  • Kode server sederhana yang dibuat bersama ada di transit-kindle-simplified
  • Kode server yang menjalankan Kindle dinding versi nyata ada di transit-kindle
  • Versi berbasis tangkapan layar BART sempat berfungsi sekitar Februari 2023, dan penyempurnaan UI akhir untuk penulisan ulang Rust selesai pada Januari 2024

1 komentar

 
GN⁺ 2024-10-25
Komentar Hacker News
  • Saya bekerja di organisasi nirlaba di balik OneBusAway. OneBusAway adalah proyek open source yang digunakan jutaan orang setiap hari untuk memeriksa lokasi dan waktu kedatangan bus, kereta, trem, dan funikular
    Jika kota Anda sudah memiliki server OneBusAway, Anda bisa membuat aplikasi khusus dengan SDK baru: https://github.com/onebusAway/?q=sdk&type=all&language=&sort...
    Jika kotanya belum memiliki server, dengan image Docker dan konfigurasi OpenTofu yang dibuat tahun ini, feed GTFS/GTFS-RT bisa diubah menjadi REST API
    BART juga menyediakan GTFS dan GTFS-RT: https://mobilitydatabase.org/feeds/mdb-53
    Badan transportasi umum lain di AS juga, karena aturan federal baru, setidaknya harus membuka data jadwal statis dalam format GTFS
    Kami selalu membutuhkan pengembang untuk berkontribusi pada perangkat lunak terkait, dan terutama sangat membutuhkan pengembang iOS yang bisa membantu peningkatan bagi 250 ribu pengguna per hari. Kontak: aaron@onebusaway.org
    Docker: https://github.com/OneBusAway/onebusaway-docker / OpenTofu: https://github.com/OneBusAway/onebusaway-deployment

    • Saat ini kota yang didukung di seluruh dunia baru 9, dan 2 di antaranya masih beta, jadi sepertinya perlu penyebaran yang lebih luas agar kontribusi open source juga jadi lebih mudah
      Saya juga ingin menambahkan kota saya kalau prosesnya sederhana. Sepertinya belakangan ini banyak waktu engineering dihabiskan untuk dukungan library dan SDK, tetapi akan lebih baik jika berinvestasi pada jalur pengalaman pengembang yang mudah agar kontributor baru mau meluangkan waktu
      Misalnya, dokumen ini cukup rumit: https://github.com/OneBusAway/onebusaway/wiki/Multi-Region
    • Saya penasaran di mana bisa menemukan daftar kota tempat OneBusAway dideploy. Kalau mencari “onebusaway cities”, yang muncul adalah https://onebusaway.org/onebusaway-deployments/, tetapi kota seperti Adelaide yang disebut di sana tidak ada
    • Kalau ini open source, saya penasaran kenapa hanya dirilis di Play Store dan tidak didistribusikan lewat F-Droid
    • Saya penasaran kenapa bukan cuma OneBusAway, tetapi juga aplikasi pelacak bus seperti Google Maps, sering sekali tidak akurat
      Tertulis “tiba dalam 4 menit” tetapi bus berangkat tepat di depan mata, atau katanya “terlambat 5 menit” tapi ternyata datang 2 menit lebih awal. Kadang busnya bahkan tidak muncul sama sekali
      Sepertinya masalahnya ada di data sumber, tetapi saya ingin tahu kondisi internal yang membuat keandalannya serendah ini. Sebagai konteks, ini berdasarkan pengalaman di Seattle
  • BART dan MUNI sama-sama mendukung General Transit Feed Specification, dan ada cara standar untuk mendapatkan data ini
    https://gtfs.org/documentation/overview/#gtfs-realtime

    • Saya penasaran seberapa bisa dipercaya informasi real-time ini. Google Maps bilang “bus tiba dalam 4 menit”, tetapi saya melihat busnya sudah berangkat, atau katanya “terlambat 5 menit” padahal sebenarnya sering datang 2 menit lebih awal
  • Saya sangat menyukainya. Dulu saat tinggal tanpa mobil di Boston, saya pernah merangkai sendiri sesuatu yang jauh lebih kasar untuk menangani situasi ketika ada beberapa cara pergi dari A ke B dan pilihan “terbaik” berubah tergantung waktu atau tempat singgah di tengah jalan
    Misalnya, sebelum berangkat kerja saya mengantar anak saya ke sekolah, dan kadang setelah itu kami sarapan. Jika ada fitur lihat waktu keberangkatan berikutnya, itu akan sangat membantu untuk mengambil keputusan secara lebih fleksibel dalam situasi yang tidak deterministik, seperti berjalan-jalan dengan anak usia 4 tahun ke tempat yang menarik, atau memutuskan apakah perlu buru-buru mengejar kereta yang jika terlewat akan menimbulkan jeda headway

  • Saya heran https://oeffi.schildbach.de/index.html belum disebut. Ini melakukan persis hal yang diinginkan di sini

  • Di Inggris, Anda bisa membeli perangkat papan informasi keberangkatan yang meniru papan keberangkatan di stasiun
    https://ukdepartureboards.co.uk/store/product/desktop-depart...

  • Saya juga tinggal di SF, dan untuk menyelesaikan masalah yang sama saya membuat aplikasi iOS bernama A Better Ride
    Aplikasi ini hanya menampilkan waktu keberangkatan transportasi umum dari halte terdekat. Tujuannya adalah membuat transportasi umum lebih mudah diprediksi dan dijelajahi sehingga mengurangi stres. Ini adalah proyek pribadi yang saya kerjakan di waktu luang tanpa monetisasi

    • Aplikasi ini benar-benar luar biasa. Bedanya dari aplikasi transportasi umum lain adalah aplikasi ini hanya menunjukkan rute di sekitar dan ke mana rute itu pergi
      Ini memungkinkan kita menjelajahi tempat-tempat yang bisa dicapai tanpa perlu memikirkan transit
    • Aplikasinya benar-benar keren. Peta real-time-nya sangat bagus
      Saya juga sedang membuat perangkat keras di bidang ini dan belakangan banyak bekerja dengan GTFS, jadi langsung terlihat betapa banyak pekerjaan yang dibutuhkan untuk mem-parsing dan menampilkan data transportasi
      Kalau berkenan, saya ingin membahas keputusan UX untuk merangkum dan mengelompokkan perjalanan yang memungkinkan di tiap halte, serta backend-nya
    • Sangat bagus. Ada banyak detail kecil yang penuh perhatian, seperti menunjukkan sisi jalan yang benar dan arah perjalanan secara keseluruhan
  • Tidak perlu melakukan jailbreak pada Kindle atau merender gambar
    Cukup buka halaman web buatan sendiri di browser Kindle, lalu matikan iklan “screensaver” atau layar tidur Kindle dengan perintah debug
    Memang bilah browser akan tetap ada di salah satu tepi Kindle, tetapi orientasi perangkat bisa diputar agar berada di bawah atau di kanan. Sebagai gantinya, Anda bisa membuat layar cuaca, transportasi, atau berita dengan HTML/CSS/JS yang mudah dan bahasa backend apa pun yang Anda inginkan, lalu menjalankannya di tempat seperti instance DigitalOcean murah seharga 4 dolar
    https://blog.notfaqs.com/2018/06/kindle-e-reader-disable-scr...
    https://www.mobileread.com/forums/showthread.php?t=198334

    • Akan lebih keren jika Amazon mendorong dan menyediakan mode kiosk di browser Kindle untuk hack tampilan seperti ini
    • Saya pernah melakukan ini dengan inkBOOK yang menjalankan Android. Saya memasang APK Chrome dan membuka halaman web buatan sendiri
      Dengan document.documentElement.requestFullscreen() bisa masuk ke layar penuh sungguhan, jadi bilah status pun tidak terlihat. API transportasi umum lokal bisa diakses langsung dari halaman web, jadi backend juga tidak diperlukan
    • Saya sempat mengecek dengan Kindle generasi ke-4, dan tampaknya hampir tidak bisa memakai situs HTTPS karena sertifikatnya tidak valid
      Meski begitu, sepertinya tetap bisa kalau dibuat berkomunikasi dengan server di jaringan lokal
    • Hampir bisa dipastikan bahwa pada Kindle versi berikutnya fitur menonaktifkan screensaver telah dihapus
  • Sepertinya saya kurang memahami use case ini. Bukan ingin “naik kereta”, melainkan ingin pergi dari A ke B
    Kalau keretanya rusak, sedang mogok, jalurnya ditutup dari jam 1 sampai 4 sore, atau memang di luar jam operasional, saya ingin alternatif. Jadi bagi saya, yang dibutuhkan adalah apa yang diberikan, atau setidaknya ingin diberikan, oleh Google Maps
    Jika ingin pergi dari Ferry Building ke Oakland dan BART sedang bermasalah, feri mungkin lebih baik, dan kalau sudah larut mungkin hanya taksi atau Uber yang tersedia
    Jika pergi dari Shibuya ke Azabujuban di Tokyo, opsinya bisa berupa Ginza Line→Namboku Line, Hanzomon Line→Oedo Line, Yamanote Line→Namboku Line, bus nomor 6, taksi, dan sebagainya
    Berjalan kaki di antara tiap stasiun dan halte bus pada masing-masing rute juga memakan 3–8 menit, jadi mana yang paling dekat dengan posisi Anda saat ini memengaruhi pilihan. Apakah sedang terlambat, serta apakah membawa barang besar atau berat, juga penting

    • Google Maps tampaknya sangat berasumsi bahwa berjalan kaki itu hal yang sangat buruk dan tidak diinginkan siapa pun
      Misalnya untuk pergi ke suatu tempat, saya bisa naik bus 39 lalu jalan kaki 15 menit, tetapi kalau ditanya ke Google, yang diberikan justru rute dengan 2 kali transit. Kalau beruntung, waktu totalnya hanya mirip dengan satu kali naik bus plus jalan kaki
      Jadi kalau saya ingin tahu kapan bus 39 datang, saya harus sengaja menyebut tujuan yang berbeda
      Selain itu, di tempat saya, data real-time Google meragukan, dan data operator atau beberapa pihak ketiga lebih bisa dipercaya
    • Use case-nya adalah perjalanan rutin. Banyak orang memang pada sebagian besar waktu benar-benar ingin “naik kereta”
      Memang ada situasi yang membutuhkan perencanaan hebat secara real-time, dan akan bagus jika ada alat untuk itu, tetapi perjalanan sehari-hari bisa sangat tercakup dengan alat yang jauh lebih sederhana
      Contoh Tokyo yang diberikan juga menarik, tetapi menurut Google sebagian besar opsi transportasi umum memakan 30–40 menit, jadi untuk perencanaan kasar semuanya hampir setara. Taksi lebih cepat, dan sepeda juga hampir mirip
    • Saat saya pergi kerja setiap hari, saya memang benar-benar hanya ingin “naik kereta”
      Kalau kereta rusak atau sedang mogok, itu terlihat sebagai kekosongan tak terduga di daftar kereta real-time
      Saat berkeliling kota saya membuka Google Maps dan memasukkan tujuan, tetapi saat keluar rumah menuju tempat yang sudah saya kunjungi 500 kali, saya tidak merasa perlu membukanya
    • Pengalaman transportasi umum di pusat Tokyo tidak bisa digeneralisasi ke seluruh dunia
      Ini tidak jauh berarti dibanding membicarakan pengalaman belanja atau makan hanya berdasarkan yang ada di dalam Disneyland. Hanya untuk tap Suica saja sudah beberapa kali lebih cepat daripada di tempat lain, dan di banyak tempat bahkan tidak didukung sejak awal
    • Anda mungkin akan menyukai https://citymapper.com
      Fiturnya banyak, tetapi saya tidak tahu seberapa baik dukungannya di Tokyo. Di London, kalau Anda minta dibawa pulang, aplikasi ini menunjukkan beberapa cara yang dioptimalkan berdasarkan biaya, jarak jalan kaki, kecepatan, transit, aksesibilitas, dan sebagainya
  • Menggunakan sesuatu yang mirip dengan menghubungkan Home Assistant dan integrasi dengan otoritas transportasi lokal ke perangkat tablet/ruang rapat Lenovo ThinkSmart View yang didaur ulang
    Kelebihannya adalah jauh lebih siap pakai. Tentu saja saya memasang ROM Android kustom di Lenovo, tetapi perangkat itu bisa menampilkan apa pun yang saya inginkan dan juga dapat mengendalikan hal-hal seperti lampu atau robot penyedot debu

  • Ada juga produk indah yang mengubah peta BART menjadi papan penunjuk LED fisik: https://www.designrules.co/