Smart Plant IoT: Bangun Rumah Hijau Terhubung dengan Arduino & Azure
Komponen dan Perlengkapan
Seeed Base Shield V2 – 1 unit
SeeedGrove - Relay – 1 unit
SeeedGrove - Temperature Sensor – 1 unit
Arduino UNO – 1 unit
Helium Starter Kit (LEGACY) – 1 unit
Aplikasi dan Layanan Online
Microsoft Azure
Microsoft Visual Studio 2015
Tentang Proyek Ini
Diperbarui untuk Lomba Pencipta Muda China-AS 2019
Pengantar
Berkebun mungkin menjadi hobi yang menyenangkan bagi sebagian, tetapi bagi banyak orang lain ini merupakan hal yang merepotkan. Dalam artikel ini saya menulis panduan sederhana tentang cara membuat tanaman IoT cerdas yang akan mengirim data sensor ke Azure IoT Hub dan menyimpannya melalui Azure SQL dengan Azure Functions, sambil pada saat yang sama mengontrol air untuk tanaman secara otomatis dan jarak jauh.
Helium IoT Hub terhubung ke Azure IoT Hub dengan lancar. Dalam artikel ini kami akan menjelaskan bagaimana seluruh proses bekerja. Karena seluruh proyek bersifat serverless, satu-satunya kode yang diperlukan agar seluruh proses bekerja hanyalah Azure Function dan kode Arduino.
Langkah 1: Kumpulkan Komponen
Kami sedang membangun produk sederhana menggunakan
Arduino UNO
SEEED Grove Base shield
Helium Atom + Helium Element dengan Helium Arduino Breakout board
Pompa air
Sensor Suhu/Kelembaban, Sensor Kelembaban Tanah, Sensor Cahaya UV
Layar OLED Grove
Langkah 2: Siapkan Arduino dengan Helium dan Sensor
Dalam artikel ini kami akan fokus pada penggunaan Arduino sebagai aplikasi kami, hal pertama adalah kami akan mendorong data dari Helium Atom ke Helium Hub. Kami pertama-tama harus mendaftarkan Atom kami di Helium Network Dashboard.
Setelah mengatur Atom kami juga harus mendaftarkan Element karena mereka adalah titik akses, (untuk mereka yang memiliki versi seluler menyala akan cukup).
Setelah mengaktifkan element kita seharusnya melihatnya di Access Point.
Selanjutnya, kami perlu melekatkan semua sensor serta Helium Atom, ketika semuanya selesai seharusnya terlihat seperti ini, sedikit berantakan tetapi kami dapat membersihkannya nanti.
Kami dapat menjalankan kode berikut untuk mengetahui bahwa program berjalan.
#include "Arduino.h" #include "Board.h" #include "Helium.h" #include "HeliumUtil.h" #include <TH02_dev.h> #include "Arduino.h" #include "Wire.h" #include <SeeedGrayOLED.h> #include <avr/pgmspace.h> #define CHANNEL_NAME "Azure IoT App" Helium helium(&atom_serial); Channel channel(&helium); int relay = 5; void setDisplayToOriginalState() { SeeedGrayOled.init(SSD1327); } void setup() { // put your setup code here, to run once: Serial.begin(9600); pinMode(relay, OUTPUT); delay(150); /* Reset HP20x_dev */ TH02.begin(); delay(100); Serial.println("TH02_dev is available.\n"); DBG_PRINTLN(F("Starting")); // Begin communication with the Helium Atom // The baud rate differs per supported board // and is configured in Board.h helium.begin(HELIUM_BAUD_RATE); // Connect the Atom to the Helium Network helium_connect(&helium); // Begin communicating with the channel. This should only need to // be done once. The HeliumUtil functions add simple retry logic // to re-create a channel if it disconnects. channel_create(&channel, CHANNEL_NAME); Wire.begin(); } void loop() { //Sound Pollution int moisture = 0; for (int i = 0; i < 32; i++) { moisture += analogRead(A0); } int uvlight = 0; for (int i = 0; i < 32; i++) { uvlight += analogRead(A1); } float temper = TH02.ReadTemperature(); float humidity = TH02.ReadHumidity(); String dataString = "Moisture=" + String(moisture) + "&UVLight=" + String(uvlight) + "&Temperature=" + String(temper) + "&Humidity=" + String(humidity); char data[dataString.length()]; dataString.toCharArray(data, dataString.length()); channel_send(&channel, CHANNEL_NAME, data, strlen(data)); Serial.println(data); setDisplayToOriginalState(); SeeedGrayOled.clearDisplay(); //Clear Display. SeeedGrayOled.setNormalDisplay(); //Set Normal Display Mode SeeedGrayOled.setVerticalMode(); // Set to vertical mode for displaying text SeeedGrayOled.setTextXY(0, 0); //Set the cursor to 0th line, 0th Column String moisturestring = "Moisture: " + String(moisture); char moibuffer[moisturestring.length()]; moisturestring.toCharArray(moibuffer, moisturestring.length()); SeeedGrayOled.putString(moibuffer); SeeedGrayOled.setTextXY(2, 0); String uvstring = "UVLight: " + String(uvlight); char uvbuffer[uvstring.length()]; uvstring.toCharArray(uvbuffer, uvstring.length()); SeeedGrayOled.putString(uvbuffer); SeeedGrayOled.setTextXY(4, 0); String temperaturestring = String(temper) + " C"; char tempbuffer[temperaturestring.length()]; temperaturestring.toCharArray(tempbuffer, temperaturestring.length()); SeeedGrayOled.putString(tempbuffer); SeeedGrayOled.setTextXY(6, 0); String humidstring = "Humid: " + String(humidity); char humidbuffer[temperaturestring.length()]; humidstring.toCharArray(humidbuffer, humidstring.length()); SeeedGrayOled.putString(humidbuffer); if(moisture < 100) { digitalWrite(relay, HIGH); delay(5000); digitalWrite(relay, LOW); } delay(60000); }
Pompa air membutuhkan 12V, sedangkan Arduino normal hanya mengeluarkan 5V maks, jadi untuk membuat kunci bekerja kita dapat menyalah sumber daya dengan menyolder dua kabel di sumber daya seperti gambar di bawah. Kami akan menggunakan kabel merah sebagai 12V dan kabel hitam sebagai ground.
Rel akan bertindak sebagai kontrol apakah air akan dipompa atau tidak.
Langkah 3: Siapkan Helium Hub dan Azure IoT Hub
Kami pertama membuat IoT Hub di bawah semua layanan, akan lebih baik untuk memindahkan IoT Hub ke favorit sehingga akan dapat diakses lebih mudah. Kami dapat menggunakan lapisan standar karena kredit uji coba gratis $200 dapat menutupnya. Anda juga dapat memilih untuk menggunakan Free Tier.
Setelah memilih nama Anda dapat pindah ke Size and Scale.
Setelah dibuat kami perlu pergi ke Shared Access Policies->RegistryReadWrite entry-> Connection String -- Primary Key, juga pastikan Registry Read dan Registry Write dicentang, meskipun mereka seharusnya default
Kami dapat membuat perangkat pertama kami untuk prototipe untuk menguji koneksi
Setelah mendapatkan primary connection string, pergi ke Helium Dashboard dan buat Helium Connection, setelah menempelkan connection string ke kolom connection, semuanya lainnya seharusnya secara otomatis terisi.
Setelah mengatur ini, kami akan dapat mendapatkan semua string MQTT yang secara otomatis dihasilkan di Helium Hub. Ini dapat dengan mudah diakses melalui channel.
Karena Azure memerlukan perangkat untuk mempublish dan berlangganan ke topik MQTT tetap, ini akan memungkinkan Helium Atom untuk melakukan itu serta memungkinkan IoT Hub untuk mendorong pesan ke Helium Atom. Kami dapat melakukan hal berikut untuk menguji pengiriman ke Azure.
git clone https://github.com/helium/helium-cli.git cd helium-cli make ./helium -p /dev/
Itu akan memeriksa apakah Helium terinstal dengan benar
Ini akan mengirim informasi dari Atom ke Azure secara langsung, kita harus memeriksa di Helium Dashboard serta Azure IoT Hub Overview
Dan di Azure IoT Hub di bawah ini kita seharusnya melihat hasil yang sama
Perangkat diotentikasi melalui X509, dan platform Helium menangani semuanya. Membuatnya sederhana dan bersih.
Langkah 5: Siapkan Azure SQL Database
Selanjutnya kami perlu dapat menyimpan data yang datang dari perangkat IoT. Ada panduan yang bagus tentang ini yang ditulis secara rinci di https://blogs.msdn.microsoft.com/sqlserverstorageengine/2018/01/23/working-with-azure-iot-data-in-azure-sql-database/ Dalam artikel ini kami akan fokus pada integrasi cepat bagaimana itu terjadi. Kami pertama pergi ke SQL databases untuk membuat database seperti gambar di bawah, kami dapat memilih Basic Tier karena kami baru memulai aplikasi, kredit uji coba gratis seharusnya dapat menutupnya. Ini adalah opsi termurah untuk prototipe, saat Anda menskala, Anda mungkin ingin pindah ke Azure Cosmos di masa depan karena minimum pada Cosmos adalah $25.
Setelah itu kami dapat menggunakan Query editor untuk membuat tabel berikut, untuk memulai kami hanya akan menggunakan struktur data sederhana Smart Plant IoT untuk memulai
CREATE TABLE SmartPlant ( id bigint IDENTITY (1,1) NOT NULL, Temperature int NOT NULL, Humidity int NOT NULL, Moisture int NOT NULL, UVLight int NOT NULL, DateCreated datetime default CURRENT_TIMESTAMP )
Sekarang kami memiliki tabel untuk menyimpan data, kami perlu menghubungkannya ke eventhub sehingga data dapat disimpan di sana. Pergi ke Connection Strings dan ambil connection string untuk langkah berikutnya.
Langkah 4: Buat Azure Function App
Untuk terhubung ke function kami akan menggunakan Event Hub. Kami pertama-tama perlu membuat Azure Function App, yang memungkinkan struktur serverless, yang bagus untuk aplikasi IoT karena kami tidak perlu memelihara lagi. Untuk memulai kami pertama-tama perlu membuat function App di bawah compute.
Kami dapat membuat Function di bawah pengaturan ini
Cukup tunggu beberapa menit dan kita akan mendapatkannya di bawah notifikasi kami.
Function App Deployed
Sekarang kami memiliki functions, Selanjutnya kami akan membuat function di bawah IoT Hub (Event Hub) trigger sehingga kami dapat menjalankan event hub. Pergi ke function->platform features->Application settings
Di sini kami akan menambahkan connection string yang kami buat di langkah sebelumnya. Simpan setelah dibuat
Langkah selanjutnya adalah membuat Event Hub function, untuk contoh ini kami akan menggunakan C#. Setelah klik new connection semestinya akan diisi otomatis.
Ubah Function menjadi berikut, ini adalah untuk memasukkan data secara langsung ke Azure SQL Database.
using System.Configuration; using System.Data.SqlClient; using System.Threading.Tasks; public static async Task Run(string myIoTHubMessage, TraceWriter log) { var map = myIoTHubMessage.Split('&').Select(x => x.Split('=')).ToDictionary(x => x[0], x => x[1]); String Temperature = map["Temperature"]; String H String Moisture = map["Moisture"]; String UVLight = map["UVLight"]; var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString; using (SqlConnection conn = new SqlConnection(str)) { conn.Open(); var text = "INSERT INTO dbo.SmartPlant (Temperature, using (SqlCommand cmd = new SqlCommand(text, conn)) { // Execute the command and log the # rows affected. var rows = await cmd.ExecuteNonQueryAsync(); log.Info($"{rows} rows were updated"); } } log.Info($"C# IoT Hub trigger function processed a message: {myIoTHubMessage}"); }
Saat berhasil, Anda seharusnya dapat melihat
Pada titik ini kami memiliki seluruh ujung ke ujung pengiriman data dari Helium ke Azure SQL melalui Azure IoT Hub. Selanjutnya kami perlu mengambil data, yang perlu kami buat HTTP Trigger melalui Azure Function API.
Kami akan mengubah beberapa nilai, routing menjadi /data sehingga kami dapat mengakses /api/smartplant, dan Authorization level menjadi anonymous, dan HTTP method hanya GET
Untuk kode, kami dapat mengujinya dengan mengakses alamat
Ini akan menguji hasil dan mengembalikan "hello foobar". Ketika ini selesai, kami dapat menggunakan kode berikut untuk mengembalikan data aktual. Selanjutnya kami dapat menggunakan kode berikut untuk menguji seluruh aplikasi. Ini adalah kueri paling sederhana, yang informasi tambahan dapat dikumpulkan dengan menulis kueri yang lebih kompleks, tetapi untuk prototipe kami hanya akan fokus pada mendapatkan satu catatan.
#r "System.Configuration" #r "System.Data" #r "Newtonsoft.Json" using System; using System.Net; using System.Configuration; using System.Data.SqlClient; using System.Threading.Tasks; using System.Text; using Newtonsoft.Json; public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { log.Info("C# HTTP trigger function processed a request."); var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString; using (SqlConnection conn = new SqlConnection(str)) { conn.Open(); var text = "SELECT Top 100 Temperature, Moisture, UVLight SmartPlant ret = new SmartPlant(); using (SqlCommand cmd = new SqlCommand(text, conn)) { SqlDataReader reader = await cmd.ExecuteReaderAsync(); try { while (reader.Read()) { ret.Temperature = (int)reader[0]; ret.Moisture = (int)reader[1]; ret.UVLight = (int)reader[2]; ret.Humidity = (int)reader[3]; } } finally { // Always call Close when done reading. reader.Close(); } var json = JsonConvert.SerializeObject(ret, Formatting.Indented); return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(json, Encoding.UTF8, "application/json") }; } } } public class SmartPlant { public float Temperature { get; set; } public float Moisture { get; set; } public float UVLight { get; set; } public float Humidity { get; set; } }
Saat semua selesai, seharusnya menghasilkan hasil untuk catatan terbaru.
Langkah 5: UI untuk Output
Sekarang semua sudah terhubung dari ujung ke ujung, kami dapat membangun aplikasi Android sederhana yang dapat memeriksa kesehatan keseluruhan tanaman. Dalam hal ini kami menggunakan aplikasi Android yang sangat sederhana untuk memantau 4 sensor yang ada di sekitar tanaman, serta memicu pompa peristaltic untuk menyiram tanaman jika diperlukan. Ini harus menampilkan dan memperbarui informasi seperti di bawah ini. Data harus dikirim setiap 60 detik (atau sesuai keinginan Anda)
Di sisi lain enclosure Arduino dapat ditutup sehingga akan memiliki tampilan yang jauh lebih baik di samping tanaman.
Kami dapat dengan mudah mensimulasikan pemompaan miliknya sendiri.
Extra: Integrasi Alexa
Kode
Azure Function GET Request
Azure function data insert from IoT Hub
Azure function shortcut
Kode Arduino
Azure Function GET Request
Restful call from calling /api/smartplant
#r "System.Configuration" #r "System.Data" #r "Newtonsoft.Json" using System; using System.Net; using System.Configuration; using System.Data.SqlClient; using System.Threading.Tasks; using System.Text; using Newtonsoft.Json; public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { log.Info("C# HTTP trigger function processed a request."); var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString; using (SqlConnection conn = new SqlConnection(str)) { conn.Open(); var text = "SELECT Top 100 Temperature, Moisture, UVLight from dbo.IoTData Order by DateCreated DESC";; EventData ret = new EventData(); using (SqlCommand cmd = new SqlCommand(text, conn)) { SqlDataReader reader = await cmd.ExecuteReaderAsync(); try { while (reader.Read()) { ret.Temperature = (int)reader[0]; ret.Moisture = (int)reader[1]; ret.UVLight = (int)reader[1]; } } finally { // Always call Close when done reading. reader.Close(); } var json = JsonConvert.SerializeObject(ret, Formatting.Indented); return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(json, Encoding.UTF8, "application/json") }; } } } public class SmartPlant { public float Temperature { get; set; } public float Moisture { get; set; } public float UVLight { get; set; } }
Azure function data insert from IoT Hub
Inserting data via Azure function
using System.Configuration; using System.Data.SqlClient; using System.Threading.Tasks; public static async Task Run(string myIoTHubMessage, TraceWriter log) { var map = myIoTHubMessage.Split('&').Select(x => x.Split('=')).ToDictionary(x => x[0], x => x[1]); String Type = map["Type"]; String Confidence = map["Confidence"]; log.Info(Type); log.Info(Confidence); var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString; using (SqlConnection conn = new SqlConnection(str)) { conn.Open(); var text = "INSERT INTO dbo.IoTData (Type, Confidence) VALUES ('" + Type + "', " + Confidence + ");"; using (SqlCommand cmd = new SqlCommand(text, conn)) { // Execute the command and log the # rows affected. var rows = await cmd.ExecuteNonQueryAsync(); log.Info($"{rows} rows were updated"); } } log.Info($"C# IoT Hub trigger function processed a message: {myIoTHubMessage}"); }
Azure function shortcut
directly inserting into AzureSQL
#r "System.Configuration" #r "System.Data" using System; using System.Configuration; using System.Data.SqlClient; using System.Threading.Tasks; using System.Net; public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) { string Temperature = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "Temperature", true) == 0) .Value; string Moisture = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "Moisture", true) == 0) .Value; string UVLight = req.GetQueryNameValuePairs() .FirstOrDefault(q => string.Compare(q.Key, "UVLight", true) == 0) .Value; if (Temperature == null || Moisture == null || UVLight == null) { // Get request body return req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body"); } var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString; using (SqlConnection conn = new SqlConnection(str)) { conn.Open(); var text = "INSERT INTO dbo.SmartPlant (Temperature, Moisture, UVLight) VALUES (" + Temperature + ", " + Moisture + ", " + UVLight + ");"; using (SqlCommand cmd = new SqlCommand(text, conn)) { // Execute the command and log the # rows affected. var rows = await cmd.ExecuteNonQueryAsync(); log.Info($"{rows} rows were updated"); } } return req.CreateResponse(HttpStatusCode.OK, "Success"); }
Kode Arduino
Arduino code for uploading the data as well as automatically watering the plant
#include "Arduino.h" #include "Board.h" #include "Helium.h" #include "HeliumUtil.h" #include <TH02_dev.h> #include "Arduino.h" #include "Wire.h" #include <SeeedGrayOLED.h> #include <avr/pgmspace.h> #define CHANNEL_NAME "Azure IoT App" Helium helium(&atom_serial); Channel channel(&helium); int relay = 5; void setDisplayToOriginalState() { SeeedGrayOled.init(SSD1327); } void setup() { // put your setup code here, to run once: Serial.begin(9600); pinMode(relay, OUTPUT); delay(150); /* Reset HP20x_dev */ TH02.begin(); delay(100); Serial.println("TH02_dev is available.\n"); DBG_PRINTLN(F("Starting")); // Begin communication with the Helium Atom // The baud rate differs per supported board // and is configured in Board.h helium.begin(HELIUM_BAUD_RATE); // Connect the Atom to the Helium Network helium_connect(&helium); // Begin communicating with the channel. This should only need to // be done once. The HeliumUtil functions add simple retry logic // to re-create a channel if it disconnects. channel_create(&channel, CHANNEL_NAME); Wire.begin(); } void loop() { //Sound Pollution int moisture = 0; for (int i = 0; i < 32; i++) { moisture += analogRead(A0); } int uvlight = 0; for (int i = 0; i < 32; i++) { uvlight += analogRead(A1); } float temper = TH02.ReadTemperature(); float humidity = TH02.ReadHumidity(); String dataString = "Moisture=" + String(moisture) + "&UVLight=" + String(uvlight) + "&Temperature=" + String(temper) + "&Humidity=" + String(humidity); char data[dataString.length()]; dataString.toCharArray(data, dataString.length()); channel_send(&channel, CHANNEL_NAME, data, strlen(data)); Serial.println(data); setDisplayToOriginalState(); SeeedGrayOled.clearDisplay(); //Clear Display. SeeedGrayOled.setNormalDisplay(); //Set Normal Display Mode SeeedGrayOled.setVerticalMode(); // Set to vertical mode for displaying text SeeedGrayOled.setTextXY(0, 0); //Set the cursor to 0th line, 0th Column String moisturestring = "Moisture: " + String(moisture); char moibuffer[moisturestring.length()]; moisturestring.toCharArray(moibuffer, moisturestring.length()); SeeedGrayOled.putString(moibuffer); SeeedGrayOled.setTextXY(2, 0); String uvstring = "UVLight: " + String(uvlight); char uvbuffer[uvstring.length()]; uvstring.toCharArray(uvbuffer, uvstring.length()); SeeedGrayOled.putString(uvbuffer); SeeedGrayOled.setTextXY(4, 0); String temperaturestring = String(temper) + " C"; char tempbuffer[temperaturestring.length()]; temperaturestring.toCharArray(tempbuffer, temperaturestring.length()); SeeedGrayOled.putString(tempbuffer); SeeedGrayOled.setTextXY(6, 0); String humidstring = "Humid: " + String(humidity); char humidbuffer[temperaturestring.length()]; humidstring.toCharArray(humidbuffer, humidstring.length()); SeeedGrayOled.putString(humidbuffer); if(moisture < 100) { digitalWrite(relay, HIGH); delay(5000); digitalWrite(relay, LOW); } delay(60000); }
Project repo
Project repo for netduino smart planthttps://github.com/Nyceane/smart-plant-iot
Skema Rangkaian
Helium architecture connects IoT Device directly to Azure IoT Hub