Singkatnya, proyek ini memiliki dua fitur. Pertama: tabel terhubung dari Google Smart Home ke Heroku menggunakan perintah suara, dan kedua: Heroku dan tabel itu sendiri berkomunikasi menggunakan protokol MQTT Internet of Things. MQTT adalah solusi yang baik untuk Internet of Things, serta untuk mengatasi beberapa kendala lain yang harus kita hadapi.
Pertama-tama, saya akan mengatakan bahwa saya melakukan proyek ini hanya untuk kesenangan. Saya harap artikel ini menghibur dan memotivasi Anda untuk meluangkan waktu untuk melakukan sesuatu sendiri.
Bagian perangkat keras
Bagian pertama dan mungkin pekerjaan tersulit adalah mendesain ulang tabel. Di kehidupan sebelumnya, meja memiliki pegangan yang bisa dilepas, itu terletak di tepi atas meja. Awalnya saya terpikir untuk memasang sesuatu ke lubang pegangan tanpa harus mengganggu desain meja. Saya membeli beberapa drive untuk mencari cara memasang motor ke meja, tetapi tidak berhasil. Kemudian muncul ide: tongkat yang dipasang di sepanjang meja, yang akan menghubungkan kedua kakinya sehingga mereka naik dan turun pada saat yang bersamaan. Jika saya memasang penggerak yang cocok dengan batang, maka saya dapat menggunakan sabuk untuk menghubungkan batang ke motor. Dimungkinkan juga untuk melengkapi meja dengan motor tanpa banyak mengganggu desainnya.
Pentingnya torsi
Setelah memesan drive dan sabuk yang benar, saya mulai mencari motor torsi tinggi di Amazon. Dan - oh, keajaiban! - Saya telah menemukan banyak mesin yang cocok! Atau begitulah menurut saya ... Setelah membeli motor kecil, saya menunggu kedatangannya dari China selama sekitar satu bulan. Saya sangat bersemangat ketika motor akhirnya tiba! Tidak bisa menunggu akhir pekan untuk akhirnya menyelesaikan semuanya dan memiliki meja bermotor saya.
Hal-hal tidak berjalan sesuai rencana. Saya menghabiskan hari itu dengan membuat lubang untuk batang di panel logam meja. Saat itu, saya hanya punya perkakas tangan, jadi prosesnya memakan waktu lebih lama dari yang saya kira. Menjelang penghujung hari, saya selesai merakit meja dan siap untuk mencobanya.
Saya menyalakan motor, tegangan pada catu daya desktop saya dan ... tidak ada yang terjadi. Beberapa saat kemudian, motor mulai berputar dan gigi sabuk yang didapat bergetar. Saya mendapat dua pelajaran dari ini: sabuk jelas tidak melakukan tugasnya, dan kata "Motor dalam torsi tinggi" tidak berarti "Saya dapat mengangkat apa pun." Pelajaran kedua adalah melihat seberapa besar motor dibandingkan dengan jari-jari Anda. Punyaku ternyata kecil!
Di sebelah kiri di foto adalah motor dan ikat pinggang. Kanan atas adalah motor yang terpasang pada tabel (Anda akan melihat lebih banyak tentang ini nanti). Di kanan bawah, motor ada di atas meja.
Motor yang cocok
Untuk memilih motor yang tepat, perlu dihitung berapa torsi yang dibutuhkan untuk menaikkan bagian atas meja. Saya terkejut betapa mudahnya melakukan ini.
Torsi adalah gaya yang dikalikan dengan panjang lengan tuas.
Nah, saya punya lengan tuas (ini pegangan meja), hanya perlu menghitung gaya yang akan dengan mudah memutar lengan tuas. Saya mengisi meja dengan mengikat kendi susu ke pegangannya dan secara bertahap menambahkan air ke kendi sampai tuas mulai berputar. Dengan memutar pegangan ke atas dengan kendi penuh, saya memastikan bobotnya memutar pegangan dengan mudah. Saya menemukan bahwa lengan tuas memiliki panjang 11 cm dan gaya yang dibutuhkan adalah 4 lbs. Mengganti angka-angka ini ke dalam rumus, saya menemukan bahwa motor harus menghasilkan torsi minimal 19,95 kg / cm. Dan saya mulai mencari dia.
Saya memutuskan untuk membuat ulang tabel secara permanen. Saya tahu bahwa tongkat yang melewati tengah meja itu berlubang. Setelah mencari motor poros ganda, saya bisa memotong batangnya dan memasang kembali dengan motor di tengah. Dengan membeli dua motor dengan torsi 20 kg / cm, saya memastikan ada cukup torsi untuk mengangkat meja.
Pada hari Sabtu yang indah lainnya, saya memisahkan meja saya menjadi empat bagian, menggergaji poros motor agar dapat digunakan saat memasang batang. Saya mendorong lebih banyak lubang di logam agar sesuai dengan motor. Tidak ada sabuk kali ini: motor dihubungkan langsung ke batang, lubangnya cukup besar. Saat malam tiba, saya memasang kembali meja dan mengisinya dengan perlengkapan kantor.
Dua foto teratas adalah motor yang terpasang sepenuhnya di atas meja. Dua foto bawah adalah batang terintegrasi yang membentang di sepanjang meja dengan bantuan motor.
Saya menghubungkan motor dan menghubungkannya ke catu daya. Menghidupkan daya, saya melihat meja bergerak! Kali ini, saya lebih percaya diri, karena saya mengukur motor dengan benar. Saya menggandakan tenaga mesin demi kepercayaan diri, tetapi sungguh menakjubkan melihat mereka bergerak!
Namun, izinkan saya mengklarifikasi bahwa tabel itu lambat. Saya merekam video untuk menunjukkan kepada seorang teman bagaimana meja bekerja, tetapi dia harus mengaktifkan akselerasi waktu pada video tersebut agar tidak menonton meja mengubah posisi atas tabel selama 5 menit.
Omset itu penting. Versi akhir
Akhirnya saya menyadari bahwa semuanya bermuara pada dua hal: torsi dan putaran. Itu perlu untuk menemukan motor dengan jumlah putaran yang cukup pada torsi yang sudah diketahui.
Tidak terlalu sulit. Meskipun saya tidak menemukan motor poros ganda, saya menemukan kotak roda gigi persegi panjang yang mengubah motor poros tunggal menjadi motor poros ganda.
Singkatnya, bulan berikutnya adalah bulan menunggu gearbox dari China, dan Sabtu berikutnya setelah menunggu, saya memiliki meja yang bergerak dengan kecepatan yang tepat.
Motor terakhir itu sendiri ada di sebelah kiri, dan motor yang dipasang di sebelah kanan. Sedikit perangkat keras dan banyak perangkat lunak.
Saya tidak senang dengan catu daya besar di meja saya, berbohong hanya untuk mengontrol ketinggian bagian atas meja. Selain itu, untuk mengubah posisi meja dari satu ke yang lain dan kembali lagi, saya menukar kabelnya. Masalah kecil, tetapi proyek itu dilakukan idealnya hanya menekan tombol dan memiliki beberapa preset ketinggian.
Bluetooth
Solusi pertama adalah menambahkan Bluetooth ke tabel. Pada akhirnya, sepertinya hampir setiap perangkat di rumah memiliki Nluetooth, dan telepon tampaknya menjadi antarmuka kontrol yang nyaman untuk sesuatu seperti meja saya.
Jadi sekarang saya mendapatkan papan pengontrol motor, papan bluetooth Nordic NRF52, sensor jarak dan mulai mengutak-atik firmware pengontrol.
Di akhir artikel, saya akan meninggalkan link ke software dan firmware yang saya tulis untuk proyek tersebut. Jangan ragu untuk mengomentari kode: Saya bukan pengembang firmware profesional dan ingin menerima beberapa panduan.
Sebagai pengantar singkat: ESP32 ditulis dalam C ++ menggunakan pustaka Arduino untuk berinteraksi dengan aplikasi Terminal BLE di telepon. Instalasi dan konfigurasi BLE cukup rumit. Pertama, Anda perlu membuat semua karakteristik untuk nilai yang ingin Anda kontrol melalui BLE. Pikirkan karakteristik sebagai variabel dalam kode Anda. BLE membungkus variabel dalam beberapa penangan untuk mendapatkan dan menetapkan nilai variabel itu.
Karakteristik tersebut kemudian dikemas ke dalam layanan dengan UUID-nya sendiri, yang membuat layanan unik dan dapat diidentifikasi dari aplikasi. Terakhir, Anda harus menambahkan layanan ini ke payload iklan sehingga layanan Anda dapat ditemukan oleh perangkat. Saat perangkat jarak jauh terhubung ke layanan Anda dan mengirimkan data melalui spesifikasi, tabel mengenali bahwa pengguna ingin menyesuaikan ketinggian ke preset yang berbeda dan mulai bergerak.
Untuk penyetelan ketinggian, bagian atas meja memiliki sensor TFMini-S LiDAR yang mendeteksi ketinggian saat ini. Ini adalah sensor yang menyenangkan: disebut LiDAR, padahal sebenarnya itu adalah laser. Ia menggunakan optik dan LED untuk menentukan waktu penerbangan dari radiasi infra merah. Dengan satu atau lain cara, sensor menentukan ketinggian meja. Papan kontrol kemudian mendeteksi perbedaan antara ketinggian saat ini dan ketinggian yang diminta dan menghidupkan motor, yang berputar ke arah yang diinginkan. Beberapa bagian utama kode ditampilkan di bawah ini, tetapi Anda dapat melihat keseluruhan file di sini .
void setup()
{
Serial.begin(115200);
Serial2.begin(TFMINIS_BAUDRATE);
EEPROM.begin(3); // used for saving the height presets between reboots
tfminis.begin(&Serial2);
tfminis.setFrameRate(0);
ledcSetup(UP_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
ledcAttachPin(UP_PWM_PIN, UP_PWM_CHANNEL);
ledcSetup(DOWN_PWM_CHANNEL, PWM_FREQUENCY, PWM_RESOLUTION);
ledcAttachPin(DOWN_PWM_PIN, DOWN_PWM_CHANNEL);
state_machine = new StateMachine();
state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);
BLEDevice::init("ESP32_Desk");
...
BLEServer *p_server = BLEDevice::createServer();
BLEService *p_service = p_server->createService(BLEUUID(SERVICE_UUID), 20);
/* ------------------- SET HEIGHT TO PRESET CHARACTERISTIC -------------------------------------- */
BLECharacteristic *p_set_height_to_preset_characteristic = p_service->createCharacteristic(...);
p_set_height_to_preset_characteristic->setCallbacks(new SetHeightToPresetCallbacks());
/* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */
BLECharacteristic *p_move_desk_up_characteristic = p_service->createCharacteristic(...);
p_move_desk_up_characteristic->setCallbacks(new MoveDeskUpCallbacks());
/* ------------------- MOVE DESK UP CHARACTERISTIC ---------------------------------------------- */
BLECharacteristic *p_move_desk_down_characteristic = p_service->createCharacteristic(...);
p_move_desk_down_characteristic->setCallbacks(new MoveDeskDownCallbacks());
/* ------------------- GET/SET HEIGHT 1 CHARACTERISTIC ------------------------------------------ */
BLECharacteristic *p_get_height_1_characteristic = p_service->createCharacteristic(...);
p_get_height_1_characteristic->setValue(state_machine->getHeightPreset1(), 1);
BLECharacteristic *p_save_current_height_as_height_1_characteristic = p_service->createCharacteristic(...);
p_save_current_height_as_height_1_characteristic->setCallbacks(new SaveCurrentHeightAsHeight1Callbacks());
/* ------------------- GET/SET HEIGHT 2 CHARACTERISTIC ------------------------------------------ */
...
/* ------------------- GET/SET HEIGHT 3 CHARACTERISTIC ------------------------------------------ */
...
/* ------------------- END CHARACTERISTIC DEFINITIONS ------------------------------------------ */
p_service->start();
BLEAdvertising *p_advertising = p_server->getAdvertising();
p_advertising->start();
xTaskCreate(
updateDeskHeight, // Function that should be called
"Update Desk Height", // Name of the task (for debugging)
1024, // Stack size
NULL, // Parameter to pass
5, // Task priority
NULL // Task handle
);
}
Ada lebih banyak hal yang terjadi di file, tetapi kode ini memiliki konteks yang cukup untuk memahami apa yang terjadi. Perhatikan bahwa kami membuat dan mengkonfigurasi semua callback BLE untuk semua karakteristik, termasuk pergerakan manual, pengaturan dan pengambilan nilai preset, dan yang terpenting, menyelaraskan tabel dengan preset.
Gambar di bawah menunjukkan interaksi dengan karakteristik untuk mengatur ketinggian meja. Bagian terakhir dari teka-teki adalah mesin negara yang mengetahui tinggi tabel saat ini, tinggi yang diinginkan pengguna, dan bekerja dengan dua nilai ini.
Jadi akhirnya saya memiliki meja yang melakukan apa pun yang saya inginkan. Saya dapat menyimpan ketinggian ke preset dan mengekstrak ketinggian dari memori untuk mengatur tabel ke posisi favorit saya. Saya menggunakan Terminal BLEdi ponsel dan komputer saya, sehingga saya dapat mengirim pesan mentah ke meja saya dan memantau posisinya. Itu berhasil, tetapi saya tahu pertempuran dengan BLE baru saja dimulai.
Antarmuka bluetooth telanjang ... Yang tersisa saat ini hanyalah mempelajari cara menulis aplikasi untuk iOS ...
Setelah semua ini, istri saya mengatakan sesuatu yang mengubah keseluruhan proyek: "Bagaimana jika Anda mengontrol suara Anda?"
Selain menjadi keren dan menambahkan perangkat baru ke daftar Asisten Google, tidak perlu menulis aplikasi iOS untuk mengontrol tabel. Dan Anda tidak lagi harus meraih ponsel Anda untuk menyesuaikan ketinggian. Kemenangan kecil lainnya!
Menambahkan Internet of Things
Sekarang mari kita bicara tentang meningkatkan meja Anda ke kontrol suara melalui Google Smart Home dan cara membuatnya ramah Wi-Fi.
Menambahkan Wi-Fi cukup mudah. Saya mengganti mikrokontroler Nordic NRF52 dengan ESP32 dengan WiFi bawaan. Sebagian besar perangkat lunak portabel karena ditulis dalam C ++, dan kedua perangkat dapat diprogram dengan Platform.IO dan pustaka Arduino, termasuk tfmini-s yang saya tulis untuk mengukur tinggi tabel saat ini.
Di bawah ini adalah arsitektur sistem interaksi tabel dengan Google Smart Home Mari kita bicara tentang interaksi antara saya dan Google.
Jadi Bluetooth telah dihidupkan. Saatnya mencari tahu cara berinteraksi dengan Google Smart Home. Teknologi ini mengontrol rumah menggunakan Smart Home Actions . Yang menarik dari tindakannya adalah layanan tersebut bertindak sebagai server OAuth2, bukan klien. Sebagian besar pekerjaan yang dilakukan di server adalah menerapkan aplikasi OAuth2 Node.js Express yang masuk ke Heroku dan berkomunikasi seperti proxy antara Google dan meja saya.
Saya beruntung: ada implementasi server yang layak menggunakan dua perpustakaan. Perpustakaan pertama, node-oauth2-server, ditemukan di sini . Library express-oauth-server kedua untuk koneksi Express ditemukan di sini .
const { Pool } = require("pg");
const crypto = require("crypto");
const pool = new Pool({
connectionString: process.env.DATABASE_URL
});
module.exports.pool = pool;
module.exports.getAccessToken = (bearerToken) => {...};
module.exports.getClient = (clientId, clientSecret) => {...};
module.exports.getRefreshToken = (bearerToken) => {...};
module.exports.getUser = (email, password) => {...};
module.exports.getUserFromAccessToken = (token) => {...};
module.exports.getDevicesFromUserId = (userId) => {...};
module.exports.getDevicesByUserIdAndIds = (userId, deviceIds) => {...};
module.exports.setDeviceHeight = (userId, deviceId, newCurrentHeight) => {...};
module.exports.createUser = (email, password) => {...};
module.exports.saveToken = (token, client, user) => {...};
module.exports.saveAuthorizationCode = (code, client, user) => {...};
module.exports.getAuthorizationCode = (code) => {...};
module.exports.revokeAuthorizationCode = (code) => {...};
module.exports.revokeToken = (code) => {...};
Berikutnya adalah konfigurasi aplikasi Express itu sendiri. Di bawah ini adalah titik akhir yang diperlukan untuk server OAuth, tetapi Anda dapat membaca file lengkapnya di sini.
const express = require("express");
const OAuth2Server = require("express-oauth-server");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const flash = require("express-flash-2");
const session = require("express-session");
const pgSession = require("connect-pg-simple")(session);
const morgan = require("morgan");
const { google_actions_app } = require("./google_actions");
const model = require("./model");
const { getVariablesForAuthorization, getQueryStringForLogin } = require("./util");
const port = process.env.PORT || 3000;
// Create an Express application.
const app = express();
app.set("view engine", "pug");
app.use(morgan("dev"));
// Add OAuth server.
app.oauth = new OAuth2Server({
model,
debug: true,
});
// Add body parser.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static("public"));
// initialize cookie-parser to allow us access the cookies stored in the browser.
app.use(cookieParser(process.env.APP_KEY));
// initialize express-session to allow us track the logged-in user across sessions.
app.use(session({...}));
app.use(flash());
// This middleware will check if user's cookie is still saved in browser and user is not set, then automatically log the user out.
// This usually happens when you stop your express server after login, your cookie still remains saved in the browser.
app.use((req, res, next) => {...});
// Post token.
app.post("/oauth/token", app.oauth.token());
// Get authorization.
app.get("/oauth/authorize", (req, res, next) => {...}, app.oauth.authorize({...}));
// Post authorization.
app.post("/oauth/authorize", function (req, res) {...});
app.get("/log-in", (req, res) => {...});
app.post("/log-in", async (req, res) => {...});
app.get("/log-out", (req, res) => {...});
app.get("/sign-up", async (req, res) => {...});
app.post("/sign-up", async (req, res) => {...});
app.post("/gaction/fulfillment", app.oauth.authenticate(), google_actions_app);
app.get('/healthz', ((req, res) => {...}));
app.listen(port, () => {
console.log(`Example app listening at port ${port}`);
});
Ada cukup banyak kodenya, tapi saya akan menjelaskan poin utamanya. Dua rute OAuth2 yang digunakan untuk server adalah / oauth / token dan / oauth / authorize. Mereka digunakan untuk menerima token baru atau menyegarkan token kedaluwarsa. Selanjutnya, Anda perlu membuat server merespons tindakan Google. Anda akan melihat bahwa titik akhir / gaction / pemenuhan menunjuk ke sebuah objek
google_actions_app
.
Google mengirimkan permintaan ke server Anda dalam format tertentu dan menyediakan perpustakaan untuk membantu memproses permintaan tersebut. Di bawah ini adalah fungsi yang diperlukan untuk berkomunikasi dengan Google, dan seluruh file ada di sini. Terakhir, ada titik akhir / healthz, yang akan saya bahas di akhir artikel.
Titik akhir / gaction / pemenuhan menggunakan middleware yang disebut app.oauth.authenticate (), kerja keras untuk mengaktifkan dan menjalankan server OAuth2 adalah membuat middleware ini berfungsi. Ini memverifikasi bahwa token pembawa yang diberikan kepada kami oleh Google merujuk ke pengguna yang ada dan belum kedaluwarsa. Rute kemudian mengirimkan permintaan dan respons ke objek
google_actions_app
.
Google mengirimkan permintaan ke server Anda dalam format tertentu dan menyediakan perpustakaan untuk membantu menganalisis dan memproses permintaan tersebut. Di bawah ini adalah fitur yang Anda perlukan untuk menghubungi Google, tetapi Anda dapat melihat seluruh file di sini .
const { smarthome } = require('actions-on-google');
const mqtt = require('mqtt');
const mqtt_client = mqtt.connect(process.env.CLOUDMQTT_URL);
const model = require('./model');
const { getTokenFromHeader } = require('./util');
mqtt_client.on('connect', () => {
console.log('Connected to mqtt');
});
const updateHeight = {
"preset one": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "1");
},
"preset two": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "2");
},
"preset three": (deviceId) => {
mqtt_client.publish(`/esp32_iot_desk/${deviceId}/command`, "3");
},
};
const google_actions_app = smarthome({...});
google_actions_app.onSync(async (body, headers) => {...});
google_actions_app.onQuery(async (body, headers) => {...});
google_actions_app.onExecute(async (body, headers) => {...});
module.exports = { google_actions_app };
Saat Anda menambahkan tindakan cerdas ke akun Google Anda, Google akan membuat permintaan sinkronisasi. Permintaan ini memberi tahu Anda perangkat mana yang tersedia dari akun Anda. Berikutnya muncul pertanyaan polling: Google menanyakan perangkat Anda untuk menentukan statusnya saat ini.
Saat pertama kali menambahkan Tindakan Google ke akun Smart Home Anda, Anda akan melihat bahwa Google terlebih dahulu mengirimkan permintaan sinkronisasi dan kemudian permintaan polling untuk mendapatkan tampilan holistik perangkat Anda. Yang terakhir adalah permintaan adalah permintaan untuk memenuhi yang Google memberi tahu perangkat Anda untuk melakukan sesuatu.
"Fitur" (ciri) perangkat Google Smart Home
Google menggunakan fitur khusus perangkat untuk menyediakan elemen antarmuka pengguna untuk mengontrol perangkat Anda ke Google, dan untuk membuat template komunikasi kontrol suara. Beberapa fitur termasuk pengaturan berikut: ColorSetting, Modes, OnOff, dan StartStop. Butuh beberapa saat bagi saya untuk memutuskan fitur mana yang akan bekerja paling baik dalam aplikasi saya, tetapi kemudian saya memilih mode.
Anda dapat menganggap mode sebagai daftar drop-down di mana salah satu dari N nilai yang telah ditentukan dipilih atau, dalam kasus saya, tinggi yang telah ditetapkan. Saya menamai mode saya "height" dan nilai yang mungkin adalah "preset one", "preset two" dan "preset three". Ini memungkinkan saya untuk mengontrol meja saya dengan mengatakan, "Hai Google, setel tinggi meja saya ke yang sebelumnya", dan Google akan mengirimkan permintaan eksekusi yang sesuai ke sistem saya. Anda dapat membaca lebih lanjut tentang fitur perangkat Google di sini .
Proyek sedang beraksi
Akhirnya, Google Smart Home dan komputer saya mulai berkomunikasi. Sebelumnya, saya menggunakan ngrok untuk menjalankan server Express secara lokal . Sekarang server saya akhirnya berfungsi dengan cukup baik, sekarang saatnya membuatnya tersedia untuk Google kapan saja. Jadi, aplikasi harus dihosting di Heroku - ini adalah penyedia PaaS yang memudahkan penerapan dan pengelolaan aplikasi.
Salah satu keunggulan utama Heroku adalah mode add-on. Dengan add-on, sangat mudah untuk menambahkan server CloudMQTT dan Postgres ke aplikasi Anda. Manfaat lain menggunakan Heroku adalah kemudahan perakitan dan penerapannya. Heroku secara otomatis mendeteksi kode apa yang Anda gunakan dan membangun / menyebarkannya untuk Anda. Anda dapat menemukan detail lebih lanjut tentang ini dengan membaca tentang Heroku Buildpacks . Dalam kasus saya, setiap kali saya memasukkan kode ke git remote Heroku, ia menginstal semua paket saya, menghapus semua dependensi pengembangan dan menyebarkan aplikasi, semua dengan perintah "git push heroku main" sederhana.
Hanya dengan beberapa klik, CloudMQTT dan Postgres tersedia untuk aplikasi saya, dan saya hanya perlu menggunakan beberapa variabel lingkungan untuk mengintegrasikan layanan ini dengan aplikasi saya. Heroku tidak meminta uang. Namun, CloudMQTT adalah add-on pihak ketiga seharga $ 5 per bulan.
Saya yakin bahwa kebutuhan Postgres sudah cukup jelas, tetapi CloudMQTT perlu lebih diperhatikan.
Dari Internet ke jaringan pribadi. Cara yang sulit
Ada beberapa cara untuk menyediakan akses ke aplikasi atau, dalam kasus saya, perangkat IoT. Yang pertama adalah membuka port di jaringan rumah saya untuk membawa perangkat ke Internet. Dalam kasus ini, aplikasi Heroku Express saya akan mengirimkan permintaan ke perangkat saya menggunakan alamat IP publik. Ini mengharuskan saya untuk memiliki IP statis publik serta IP statis untuk ESP32. ESP32 juga harus bertindak sebagai server HTTP dan mendengarkan instruksi dari Heroku sepanjang waktu. Ini adalah pengeluaran besar untuk perangkat yang menerima instruksi beberapa kali sehari.
Metode kedua disebut pukulan lubang. Dengannya, Anda dapat menggunakan server eksternal pihak ketiga untuk mengakses perangkat ke Internet tanpa perlu port forwarding. Perangkat Anda pada dasarnya terhubung ke server yang menyiapkan port terbuka. Kemudian layanan lain dapat terhubung langsung ke backend Anda dengan mendapatkan port terbuka dari server luar. Terakhir, ini terhubung langsung ke perangkat menggunakan port terbuka ini. Pendekatannya mungkin atau mungkin tidak sepenuhnya benar: Saya hanya membaca sebagian artikel tentangnya.
Ada banyak hal yang terjadi di dalam "lubang pukulan", dan saya tidak sepenuhnya mengerti apa yang terjadi. Namun, jika Anda tertarik, ada beberapa artikel menarik yang menjelaskan lebih lanjut. Berikut adalah dua artikel yang saya baca untuk lebih memahami lubang pukulan: Wikipediadan artikel dari MIT oleh Brian Ford dan lainnya .
Dari Internet ke jaringan pribadi melalui IoT
Saya tidak terlalu senang dengan solusi ini. Saya menghubungkan banyak perangkat pintar ke rumah saya dan tidak pernah membuka porta di router saya, jadi tidak ada penerusan port. Selain itu, lubang punching tampaknya jauh lebih sulit daripada yang saya cari dan lebih cocok untuk jaringan P2P. Sebagai hasil dari penelitian lebih lanjut, saya menemukan MQTT dan mengetahui bahwa itu adalah protokol untuk IoT. Ini memiliki beberapa keunggulan seperti konsumsi daya yang rendah, toleransi kesalahan yang dapat dikonfigurasi, dan tidak memerlukan penerusan port. MQTT adalah protokol penerbit / pelanggan, yang berarti bahwa tabel adalah pelanggan topik tertentu, dan aplikasi Heroku adalah penerbit topik tersebut.
Jadi, Google menghubungi Heroku, permintaan ini dianalisis untuk menentukan perangkat yang diminta dan status atau mode barunya. Aplikasi Heroku kemudian menerbitkan pesan ke server CloudMQTT yang digunakan sebagai add-on untuk Heroku yang menginstruksikan tabel untuk menavigasi ke preset baru. Akhirnya, tabel berlangganan ke topik dan menerima pesan yang diposting oleh aplikasi Heroku, akhirnya, tabel menyesuaikan tingginya seperti yang diminta! Di file googleactionsapp, Anda akan melihat bahwa ada fungsi updateHeight yang menerbitkan satu nomor MQTT untuk ID perangkat tertentu. Ini adalah cara aplikasi Heroku menerbitkan permintaan pemindahan tabel ke MQTT.
Langkah terakhir adalah menerima pesan di ESP32 dan memindahkan tabel. Saya akan menunjukkan kepada Anda beberapa hal penting dari kode tabel di bawah ini, dan semua kode sumber ada di sini .
void setup()
{
Serial.begin(115200);
...
tfminis.begin(&Serial2);
tfminis.setFrameRate(0);
...
state_machine = new StateMachine();
state_machine->begin(*t_desk_height, UP_PWM_CHANNEL, DOWN_PWM_CHANNEL);
setup_wifi();
client.setServer(MQTT_SERVER_DOMAIN, MQTT_SERVER_PORT);
client.setCallback(callback);
...
}
Saat tabel dimuat, pertama-tama kami memulai komunikasi antara TFMini-S - sensor jarak - untuk mendapatkan tinggi tabel saat ini. Kemudian kami menyiapkan mesin negara untuk pergerakan meja. Mesin negara menerima perintah melalui MQTT dan kemudian bertanggung jawab untuk mencocokkan permintaan pengguna dengan ketinggian tabel aktual seperti yang dibaca oleh sensor jarak. Terakhir, kami menyambungkan ke jaringan Wi-Fi, menyambungkan ke server MQTT, dan mengatur panggilan balik untuk setiap data yang diterima pada topik MQTT langganan kami. Di bawah ini saya akan menunjukkan fungsi panggilan balik.
void callback(char *topic, byte *message, unsigned int length)
{
...
String messageTemp;
for (int i = 0; i < length; i++)
{
messageTemp += (char)message[i];
}
if (messageTemp == "1") {
state_machine->requestStateChange(ADJUST_TO_PRESET_1_HEIGHT_STATE);
}
if (messageTemp == "2") {
state_machine->requestStateChange(ADJUST_TO_PRESET_2_HEIGHT_STATE);
}
if (messageTemp == "3") {
state_machine->requestStateChange(ADJUST_TO_PRESET_3_HEIGHT_STATE);
}
...
}
Mesin negara mendaftarkan perubahan status yang diterima di topik MQTT. Kemudian memproses status baru di loop utama.
void loop()
{
if (!client.connected())
{
reconnect();
}
client.loop();
state_machine->processCurrentState();
}
Loop utama melakukan beberapa hal: pertama, terhubung kembali ke server MQTT jika belum terhubung. Kemudian memproses semua data yang diterima melalui topik MQTT. Terakhir, kode tersebut bekerja dengan memindahkan bagian atas meja ke lokasi yang diinginkan yang diminta dalam topik MQTT.
Itu saja! Tabel sepenuhnya dikontrol dengan suara dan berkomunikasi dengan Google untuk menerima perintah!
Catatan Terbaru
Titik akhir terakhir yang tidak saya sebutkan adalah titik akhir / healthz. Ini karena Google mengharapkan respons yang cukup cepat, dan memuat aplikasi Heroku di setiap permintaan tidak berfungsi dalam kasus saya. Saya menyiapkan layanan ping untuk melakukan ping ke / healthz endpoint setiap menit agar layanan tetap aktif dan siap merespons. Jika Anda berencana melakukan sesuatu seperti ini, ingatlah bahwa semua jam bebas di stan akan dihabiskan untuk itu. Semuanya baik-baik saja sekarang: ini adalah satu-satunya aplikasi yang digunakan di Heroku. Plus, dengan $ 7 sebulan, Anda dapat meningkatkan ke paket Hobby Heroku yang membuat aplikasi tetap berjalan.
Membangun perangkat IoT membutuhkan banyak biaya pada awalnya. Saya merancang perangkat keras, membuat skema kontrol, mengonfigurasi server MQTT, menulis server Express OAuth2, dan mempelajari cara berinteraksi dengan Google Smart Home melalui tindakan. Overhead awal sangat besar, tetapi saya merasa saya telah mencapai banyak hal! Belum lagi, MQTT Server, Express OAuth2 Application Server, dan Google Smart Home Actions bisa digunakan untuk project lain. Saya tertarik dengan rumah pintar, dan saya dapat mencoba memperluas repertoar perangkat IoT saya untuk menyertakan sensor yang melacak apa yang terjadi di sekitar rumah saya dan melaporkannya melalui MQTT. Sensor untuk memantau tanah, suhu dan sensor cahaya akan sangat menarik untuk dimonitor dan dianalisis.
Apa berikutnya?
Ketinggian meja sekarang diukur paling tidak dapat diandalkan. Saya menggunakan secara umum sensor jarak inframerah TFMini-S yang berfungsi. Telah diketahui bahwa ketinggian meja berubah sedikit pada siang hari saat pencahayaan sekitar di ruangan berubah. Saya memesan sensor sudut rotasi untuk menghitung putaran batang melalui tabel. Ini akan memberi saya pergerakan yang lebih akurat setiap saat sepanjang hari. Saya juga memiliki akses ke server yang saya host di ruang bawah tanah. Di atasnya saya dapat menjelajahi server Mosquitto MQTT saya sendiri, aplikasi Node-RED dan Express OAuth2 jika saya ingin meng-host sesuatu sendiri. Akhirnya, sekarang semua barang elektronik ada di meja saya. Saya berencana untuk mengatur perangkat agar semuanya bagus dan rapi!
Terima kasih telah membaca artikelnya! Untuk kenyamanan, saya memberikan semua tautan.
- Torque Calculator
- 90 degree right angle gear box
- BLE Terminal
- Platform.IO
- TFMini-S Arduino Driver
- Google Smart Home Actions
- Node OAuth2 Server
- Express OAuth2 Server
- ESP32 IoT Desk Server model.js
- ESP32 IoT Desk Server index.js
- ESP32 IoT Desk Server google_actions.js
- Google Smart Home Device Traits
- NGROK
- ESP32 IoT Desk Firmware
- Node-RED
- Heroku
- Heroku Hobby Plan
- Heroku Buildpacks
- Wikipedia Hole Punching
- MIT Paper on Hole Punching by Bryan Ford et al.