Ampelmännchen adalah simbol populer dari Jerman Timur, yang dipajang di lampu lalu lintas pejalan kaki di setiap sudut jalan. Bahkan ada jaringan ritel berbasis di Berlin yang terinspirasi oleh desain mereka.
Saya menemukan serangkaian sinyal Ampelmann bekas di pasar loak, dan saya ingin mengontrolnya dari ponsel saya. Jika Anda ingin melakukan hal yang sama, baca terus!
Peringatan Kesehatan: Proyek ini menggunakan daya listrik 220V. Saya bukan tukang listrik. Ikuti petunjuk ini dengan risiko Anda sendiri.
Saya ingin membangun sesuatu dengan estetika Berlin , dan akan menyenangkan bagi pengunjung rumah saya untuk berinteraksi. Sayangnya jumlah pengunjung kami menurun drastis tahun ini, namun masih mengharapkan reaksi yang luar biasa di tahun 2021...?
Setiap perangkat di jaringan lokal Anda memiliki alamat IP pribadinya sendiri (misalnya 192.168.1.20
). Beberapa router seperti FritzBox juga memungkinkan Anda menelusuri berdasarkan nama host lokal, sehingga 192.168.1.20
juga dapat diakses di mydevice.fritz.box
. Untuk traffic light, hostname perangkatnya adalah traffic-light
sehingga kita bisa mengunjunginya di http://traffic-light.fritz.box
.
Webapp adalah aplikasi satu halaman responsif yang sangat sederhana. Ini menunjukkan:
Kode berada di bawah direktori /webapp. Tidak diperlukan ketergantungan eksternal karena hanya mengandalkan fitur browser standar, seperti transformasi CSS, WebSockets, dan XHR. Anda dapat melihat pratinjau aplikasi yang sedang berjalan di sini meskipun tidak mengontrol apa pun, karena tentu saja Anda tidak menggunakan LAN saya. Jika Anda mengunjunginya dari jaringan lokal, misalnya http://traffic-light.fritz.box
itu akan berfungsi sepenuhnya.
Setelah memuat halaman, aplikasi membuat permintaan GET untuk menemukan status saat ini di /api/status
, dan kemudian membuka koneksi WebSocket ke server pada port 81
. Pembaruan status selanjutnya akan selalu datang melalui WebSocket, untuk menjaga sinkronisasi beberapa klien. Setiap kali peristiwa websocket tiba, kami menerapkan perubahan pada satu objek state
global. Tak lama kemudian, metode updateScreen()
menerapkan perubahan tersebut ke DOM.
Saat startup, kami juga mendeteksi apakah pengguna menggunakan perangkat seluler atau desktop, untuk menangani peristiwa sentuh atau peristiwa klik. Kami sebenarnya menggunakan acara touchend
untuk mengirim perintah ke server, karena ini bekerja lebih andal di iPhone X. Menggesek layar dari bawah ke atas untuk keluar dari Safari mengaktifkan acara touchstart
, sehingga tidak mungkin untuk keluar dari aplikasi tanpa menyalakannya lampu hijau!
Terakhir, kami ingin mengurangi beban pada server sedapat mungkin. Ingat ESP8266 berjalan pada prosesor 80MHz dengan RAM hanya sekitar 50kB . Ini BUKAN perangkat yang besar. Jadi ketika browser tidak aktif, kita putuskan sambungan websocketnya. Saat tab atau browser dibuka kembali, kami memeriksa kembali statusnya, dan menyambungkan kembali WebSocket.
ESP8266 sibuk menangani permintaan API dan kode waktu, sehingga tidak memiliki sumber daya yang diperlukan untuk melayani aplikasi web itu sendiri. Selain itu, membuat perubahan tampilan pada aplikasi web juga sulit, jika saya harus terhubung secara fisik ke perangkat keras setiap kali saya ingin menerapkan pembaruan.
Index.html aplikasi web mengikuti prinsip aplikasi satu halaman bahwa semuanya harus dirender dengan Javascript, membuat konten HTML itu sendiri menjadi sangat kecil. Seperti 550 byte kecil. Segala sesuatu yang lain dimuat oleh browser klien, tanpa perlu melakukan panggilan lebih lanjut ke server. Jadi aplikasi web sebenarnya dihosting secara keseluruhan di Halaman GitHub, alat hosting situs statis gratis. Menekan /index.html
sebenarnya membuat permintaan proxy ke halaman GitHub, dan mengembalikan hasilnya ke browser klien.
Sekarang kita dapat mengubah apa pun di aplikasi web, dan server tidak terpengaruh. Besar! Yah, hampir...
Sebagian besar kode untuk webapp ini ada di file CSS dan JS, bukan di index.html
itu sendiri. Browser menyimpan file apa pun yang dimuat dalam cache untuk jangka waktu yang tidak ditentukan sebelum memintanya kembali. Jika index.html tidak berubah, namun kami telah menerapkan versi JS baru, bagaimana klien kami tahu bahwa mereka perlu memuat versi JS baru?
Saat kami memasukkan versi baru kode kami ke cabang git master
, Tindakan GitHub berjalan, yang mengeksekusi penerapan ke Halaman GitHub tempat halaman tersebut benar-benar disajikan kepada publik. Caranya di sini adalah dengan menambahkan akhiran ?version=latest
di akhir file CSS dan JS kita, di index.html
. Sebelum menyalin konten ke cabang gh-pages
, tindakan tersebut menggunakan perintah sed
untuk mengganti " latest
" itu dengan nilai variabel $GITHUB_SHA
, yang sebenarnya merupakan ID komit terakhir di cabang master
. (misalnya nilai seperti b43200422c4f5da6dd70676456737e5af46cb825
).
Kemudian saat klien mengunjungi aplikasi web lagi, browser akan melihat nilai baru yang berbeda setelah ?version=
, dan meminta file JS atau CSS baru yang diperbarui, yang belum di-cache.
Lihat metode setup(void)
di traffic-light-controller.ino
dan bagian Kode Arduino untuk mengetahui cara kerjanya dalam praktik.
Saya memutuskan untuk menggunakan REST dan WebSockets secara bersamaan. REST sebagian besar digunakan oleh klien untuk mengontrol server. WebSockets digunakan untuk menyiarkan informasi status ke klien. Ada banyak alat seperti Tukang Pos yang memungkinkan Anda bereksperimen dengan mudah dengan REST API, jadi menurut saya ini lebih nyaman.
HTTP API: Lihat dokumentasi Swagger di sini.
WebSocket API: Koneksi websocket mengirimkan blob JSON yang digunakan aplikasi web untuk memperbarui status internalnya. Acara websocket dapat berisi satu atau lebih bidang untuk diperbarui. Contoh yang berisi informasi lingkungan mungkin terlihat seperti:
{
"redTemperature" : 21.6 ,
"greenTemperature" : 22.7 ,
"greenHumidity" : 55 ,
"redHumidity" : 59
}
Saat ini tidak ada data yang dikirim dari klien ke server melalui soket web, meskipun hal ini dimungkinkan.
Semua kode Arduino ada dalam satu file yang menyertakan komentar penjelasan.
Ini dimulai dengan serangkaian definisi untuk lokasi pin, impor perpustakaan, dan nilai hardcode untuk hal-hal seperti Tipe Konten HTTP dan nilai kode respons. Berikut ini adalah sekumpulan variabel yang dapat berubah saat runtime, semuanya diawali dengan garis bawah. Beberapa objek juga diinisialisasi di sini, termasuk objek untuk server web, server soket web, klien WiFi, dan sensor suhu. "Jam sistem" dikelola oleh bidang _currentMillis
.
Setelah boot, metode setup(void)
berjalan. Setelah melakukan beberapa pengaturan pin, ini membuat pemetaan yang diperlukan untuk titik akhir REST, dan memulai server mendengarkan permintaan klien. Metode loop(void)
bertanggung jawab atas segalanya. Setiap siklus memproses permintaan web yang tertunda, memperbarui siklus ritme, dan membaca sensor jika perlu. Jika kita berada dalam mode pesta, ini akan mengatur status flash/pulsa saat ini.
Irama (untuk mode pesta) dikodekan secara keras untuk memainkan urutan di bidang RHYTHM_PATTERN
, tetapi secara teori dapat diubah saat runtime ke ritme lain. Setiap kali kita memanggil metode rhythm()
, kita menggunakan nilai _bpm
dan _currentMillis
saat ini untuk menentukan posisi kita seharusnya dalam pola tersebut. Ini disimpan di bidang _rhythmStep
.
Selama pola ritme, ada periode dimana kedua relay benar-benar dimatikan. Namun karena lampunya adalah lampu pijar, lampu tersebut tidak langsung menyala atau berhenti memancarkan cahaya. Sepertinya bohlam membutuhkan waktu sekitar 1,7 detik untuk menyala atau mati sepenuhnya. Jadi dengan menambahkan periode dalam pola di mana keduanya dimatikan, kita akan mendapatkan pola berdenyut lembut saat bohlam memanas dan mendingin.
Dalam metode partyFlash()
, kita mendapatkan item pola yang seharusnya ditampilkan saat ini (atau keduanya harus dimatikan) dan memanggil lightSwitch(...)
dengan parameter yang sesuai. lightSwitch(...)
pada gilirannya memanggil sendToWebSocketClients(...)
sehingga semua klien yang terhubung diperbarui ke status baru.
Jika pengguna cukup mengklik salah satu lampu untuk menyalakan atau mematikannya, prosesnya serupa, namun ditangani sebagai permintaan REST. Salah satu metode handleX
dipanggil, yang memvalidasi permintaan, dan pada gilirannya memanggil lightSwitch(...)
.
Pada interval yang lebih jarang, kami memeriksa suhu kedua enklosur, dan juga mengirimkannya melalui WebSocket ke semua klien. Saat ini hanya digunakan untuk tujuan informasi tetapi dapat digunakan untuk menonaktifkan lampu ketika suhu melebihi batas keamanan tertentu.
Penghargaan untuk @mrcosta atas bantuannya meninjau artikel ini.