Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 80 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
80
Dung lượng
3,69 MB
Nội dung
BỘ CÔNG THƯƠNG TRƯỜNG ĐẠI HỌC CÔNG NGHIỆP THÀNH PHỐ HỒ CHÍ MINH TRẦN THANH ĐÀN ỨNG DỤNG CƠNG NGHỆ LORA VÀO NUÔI TRỒNG THỦY SẢN THÔNG MINH Ngành: KHOA HỌC MÁY TÍNH Mã ngành: 8480101 LUẬN VĂN THẠC SĨ THÀNH PHỐ HỒ CHÍ MINH, NĂM 2023 Cơng trình hồn thành Trường Đại học Cơng nghiệp TP Hồ Chí Minh Người hướng dẫn khoa học: TS Nguyễn Chí Kiên Luận văn thạc sĩ bảo vệ Hội đồng chấm bảo vệ Luận văn thạc sĩ Trường Đại học Cơng nghiệp thành phố Hồ Chí Minh ngày 17 tháng 06 năm 2023 Thành phần Hội đồng đánh giá luận văn thạc sĩ gồm: PGS.TS Huỳnh Tường Nguyên - Chủ tịch Hợi đồng TS Phạm Hồng Anh - Phản biện TS Đặng Thị Phúc - Phản biện TS Huỳnh Khả Tú - Ủy viên TS Phạm Thị Thiết - Thư ký (Ghi rõ họ, tên, học hàm, học vị Hội đồng chấm bảo vệ luận văn thạc sĩ) CHỦ TỊCH HỘI ĐỒNG TRƯỞNG KHOA CÔNG NGHỆ THÔNG TIN BỘ CÔNG THƯƠNG TRƯỜNG ĐẠI HỌC CƠNG NGHIỆP THÀNH PHỐ HỒ CHÍ MINH CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM Độc lập - Tự - Hạnh phúc NHIỆM VỤ LUẬN VĂN THẠC SĨ Họ tên học viên: Trần Thanh Đàn MSHV: 18000401 Ngày, tháng, năm sinh: 14/08/1981 Nơi sinh: Quy Nhơn, Bình Định Ngành: Khoa học máy tính Mã ngành: 8480101 I TÊN ĐỀ TÀI: Ứng Dụng Công Nghệ LoRa Vào Nuôi Trồng Thủy Sản Thông Minh NHIỆM VỤ VÀ NỘI DUNG: Xây dựng mơ hình ứng dụng IoT sử dụng công nghệ LoRa để thu thập liệu từ cảm biến, truyền nhận liệu bộ điều khiển hiển thị liệu thu thập thiết bị theo dõi (máy tính, điện thoại di đợng, …) II NGÀY GIAO NHIỆM VỤ: 04/10/2021 III NGÀY HOÀN THÀNH NHIỆM VỤ: IV NGƯỜI HƯỚNG DẪN KHOA HỌC: TS Nguyễn Chí Kiên Tp Hồ Chí Minh, ngày … tháng … năm 20 … NGƯỜI HƯỚNG DẪN CHỦ NHIỆM BỘ MÔN ĐÀO TẠO (Họ tên chữ ký) (Họ tên chữ ký) TRƯỞNG KHOA CÔNG NGHỆ THÔNG TIN (Họ tên chữ ký) LỜI CẢM ƠN Lời đầu tiên, học viên xin bày tỏ biết ơn chân thành sâu sắc nhất tới TS Nguyễn Chí Kiên, hết lòng hỗ trợ, hướng dẫn giúp đỡ học viên q trình nghiên cứu hồn thiện luận văn thạc sĩ Bên cạnh đó, học viên xin cảm ơn hai đồng nghiệp Lê Văn Triết Võ Bá Việt Nghĩa thuộc bộ phận Center of Excellence trường Cao Đẳng Sài Gòn, nơi học viên công tác, hỗ trợ giải đáp thắc mắc liên quan lĩnh vực IoT mà học viên gặp phải trình nghiên cứu, thiết kế bo mạch đế cho mạch Arduino NodeMCU hỗ trợ cơng trình nghiên cứu học viên Tiếp theo, học viên xin gửi lời cảm ơn đến TS Lê Nhật Duy, phó khoa Khoa Công nghệ tin trường Trường Đại học Công Nghiệp Tp Hồ Chí Minh, hỗ trợ hướng dẫn học viên hồn thành thủ tục hành suốt trình học tập thạc sĩ trường đặc biệt giai đoạn cách ly đại dịch Covid-19 Học viên xin gửi lời cảm ơn chân thành tới thầy, cô giảng viên Trường Đại học Cơng Nghiệp Tp Hồ Chí Minh tận tình dạy dỗ hướng dẫn cho học viên suốt trình học tập thạc sĩ trường Xin chân thành cảm ơn anh chị em học viên cao học bạn bè đồng nghiệp trao đổi, khích lệ học viên q trình học tập làm luận văn Trường Đại học Công Nghiệp Tp Hồ Chí Minh Cuối học viên xin gửi lời cảm ơn đến gia đình, người ln bên cạnh, hỗ trợ, đợng viên khuyến khích học viên để học viên có thêm tâm hồn thành luận văn thạc sĩ i TÓM TẮT LUẬN VĂN THẠC SĨ Luận văn “Ứng Dụng Công Nghệ LoRa Vào Nuôi Trồng Thủy Sản Thơng Minh” nhằm nghiên cứu, tìm hiểu kết hợp công nghệ, giải pháp truyền nhận thông thiết bị IoT, điện thoại di động, máy tính, … mợt cách hiệu tiết kiệm chi phí Mục tiêu đề tài nghiên cứu cơng nghệ LoRa để truyền nhận tín hiệu thiết bị IoT phục vụ cho việc nuôi trồng thủy sản thơng minh Bên cạnh đó, đề tài nghiên cứu kết hợp công nghệ truyền nhận khác để hồn thành mợt hệ thống phần mềm ứng dụng, cung cấp cho người nuôi một công cụ, một giải pháp giám sát bể nuôi, trồng thủy sản mà không tốn nhiều thời gian công sức Đề tài nghiên cứu này, sử dụng công nghệ LoRa để truyền giá trị thu từ cảm biến (nhiệt độ, độ ẩm, pH, …) đến một thiết bị IoT trạm, sau sử dụng giao thức MQTT để gửi giá trị nhận lên máy chủ lưu trữ liệu, đồng thời sử dụng thư viện SignalR giao thức HTTP để cập nhật liệu thiết bị đầu cuối sử dụng như: điện thoại, máy tính Giúp người giám sát ln có liệu nhất, nhanh nhất mà không cần phải đến tận bể nuôi trồng thủy sản Kết luận văn cho thấy việc ứng dụng công nghệ LoRa kết hợp với công nghệ truyền nhận khác một giải pháp giúp xây dựng một hệ thống giám sát mà liệu cập nhật tức thời, tính hiệu cao chi phí phù hợp Cùng với phát triển công nghệ, thiết bị IoT ngày đại hơn, chất lượng ngày tốt Điều giúp cho giải pháp mà đề tài nghiên cứu nâng cao độ xác cảm biến, nâng cao đợ ổn định gửi nhận liệu thiết bị ii ABSTRACT The thesis titled “Application of LoRa technololgy in smart aquaculture” aims to research, understand, and integrate various technologies and solutions for efficient and cost-effective communication between IoT devices, mobile phones, computers, etc The main objective of the study is to investigate LoRa technology for transmitting and receiving signals between IoT devices in the context of smart aquaculture Additionally, the thesis explores the integration of other communication technologies to develop an application software system that provides farmers with a monitoring tool and solution for aquaculture ponds, saving time and effort This research project utilizes LoRa technology to transmit sensor data (such as temperature, humidity, pH, etc.) to an IoT gateway device, then employs the MQTT protocol to send the received data to a data storage server Simultaneously, SignalR technology and the HTTP protocol are used to immediately update data on end-user devices, such as phones and computers This ensures that supervisors have the latest and fastest data without physically being present at the aquaculture ponds The results of the thesis demonstrate that the application of LoRa technology combined with other communication technologies provides an effective and costefficient solution for building a real-time monitoring system Alongside the continuous development of technology, IoT devices are becoming more advanced and of higher quality, which contributes to enhancing sensor accuracy and stability in data transmission/reception between devices iii LỜI CAM ĐOAN Học viên cam đoan kết thu luận văn sản phẩm trình nghiên cứu, tìm hiểu thử nghiệm thân học viên, hướng dẫn TS Nguyễn Chí Kiên Các kết nghiên cứu kết luận luận văn trung thực, không chép từ bất kỳ nguồn khơng vi phạm bất kỳ hình thức Việc tham khảo nguồn tài liệu (nếu có) thực theo quy định trích dẫn ghi nguồn tài liệu tham khảo Học viên hoàn toàn chịu trách nhiệm sẵn sàng chấp nhận hình thức kỷ luật theo quy định liên quan đến lời cam đoan Học viên (chữ ký) Trần Thanh Đàn iv MỤC LỤC LỜI CẢM ƠN i TÓM TẮT LUẬN VĂN THẠC SĨ ii ABSTRACT iii LỜI CAM ĐOAN iv MỤC LỤC v DANH MỤC HÌNH ẢNH vii DANH MỤC BẢNG BIỂU viii DANH MỤC TỪ VIẾT TẮT ix Đặt vấn đề .1 Mục tiêu nghiên cứu .2 Đối tượng phạm vi nghiên cứu 3.1 Đối tượng nghiên cứu .3 3.2 Phạm vi nghiên cứu Cách tiếp cận phương pháp nghiên cứu 4.1 Cách tiếp cận 4.2 Phương pháp nghiên cứu Ý nghĩa thực tiễn đề tài CHƯƠNG NGHIÊN CỨU TỔNG QUAN 1.1 Giới thiệu IoT 1.1.1 Công nghệ Wi-Fi 1.1.2 Công nghệ Cellular 1.1.3 Công nghệ BLE .8 1.1.4 Công nghệ LoRa 1.1.5 Giao thức MQTT 11 1.1.6 Thư viện SignalR 12 1.1.7 Giao thức HTTP/HTTPS .13 1.2 Khảo sát ứng dụng IoT 13 1.3 Khảo sát ứng dụng IoT nuôi trồng thuỷ sản 15 v CHƯƠNG GIẢI PHÁP ĐỀ XUẤT 19 2.1 Thiết kế hệ thống lựa chọn giải pháp 19 2.1.1 Lựa chọn giải pháp truyền/nhận liệu đề tài 19 2.1.2 Các hướng tiếp cận 22 2.1.3 Khó khăn thách thức .22 2.1.4 Hướng giải 23 2.2 Hiện thực hệ thống 23 2.3 Triển khai thử nghiệm 25 2.3.1 Thử nghiệm điều chỉnh thông số LoRa 25 2.3.2 Giải pháp gửi nhận liệu hiệu .31 2.3.3 Lập trình nạp chương trình vào thiết bị IoT .37 2.3.4 Triển khai hệ thống thu thập liệu phần mềm máy chủ .39 2.3.5 Phát triển cài đặt ứng dụng giám sát vào điện thoại thông minh 42 2.3.6 Hiển thị kết tập liệu thu thập lên trình duyệt web 45 CHƯƠNG KẾT LUẬN VÀ ĐỀ NGHỊ 49 TÀI LIỆU THAM KHẢO 50 PHỤ LỤC 51 LÝ LỊCH TRÍCH NGANG CỦA HỌC VIÊN 67 vi DANH MỤC HÌNH ẢNH Hình 1.1 Sơ đồ mạng LoRaWAN .10 Hình 1.2 Sơ đồ ứng dụng MQTT .11 Hình 1.3 Các giao thức SignalR hỗ trợ .13 Hình 1.4 Giao thức HTTP/HTTPS 13 Hình 1.5 Hệ thống IoT giám sát tự đợng chất lượng nước .16 Hình 2.1 Sơ đồ tổng quát hệ thống giám sát 20 Hình 2.2 Mơ hình CSDL hệ thống giám sát .21 Hình 2.3 Biểu đồ so sánh loại sóng theo băng thơng khoảng cách 26 Hình 2.4 Khu vực vị trí thử nghiệm hoạt đợng LoRa .28 Hình 2.5 Bo mạch Arduino Nano, NodeMCU ESP32 LoRa SX1278 433Mhz 30 Hình 2.6 Mạch Arduino Nano, LoRa, cảm biến DHT21 cảm biến DS18B20 .31 Hình 2.7 Bợ linh kiện, phụ kiện LoRa gateway 32 Hình 2.8 Cấu trúc quản lý thơng tin hệ thống giám sát 34 Hình 2.9 Cách tổ chức liệu truyền LoRa lưu trữ hàng đợi .35 Hình 2.10 Cách lưu trữ gửi liệu LoRa gateway 36 Hình 2.11 Thiết bị LoRa gateway hồn thành đóng gói .39 Hình 2.12 Mơ hình hồ cá thu nhỏ ứng dụng công nghệ LoRa 40 Hình 2.13 Lưu đồ giao tiếp MQTT & SignalR 40 Hình 2.14 Mợt liệu JSON từ API phần mềm Postman 41 Hình 2.15 Mợt liệu cảm biến JSON từ API phần mềm Postman .42 Hình 2.16 Màn hình đăng nhập điện thoại di đợng 43 Hình 2.17 Màn hình theo dõi giá trị cảm biến 44 Hình 2.18 Màn hình theo dõi chi tiết một cảm biến 45 Hình 2.19 Màn hình đăng nhập trình duyệt web 46 Hình 2.20 Màn hình giám sát cảm biến mợt người dùng .47 Hình 2.21 Màn hình xem lịch sử liệu một cảm biến nhiệt độ .48 vii } float getCTemperature() { float tempC = -127; dallas.requestTemperatures(); // Send the command to get temperatures for(int i=0;i interval) { count++; // check MQTT connected if (!client.connected()) { reconnect(); } client.loop(); if (!isSending) { isSending = true; if (senders[currentSend] > 0) { if (sendData(senders[currentSend], sensors[currentSend], values[currentSend])) { senders[currentSend] = 0; currentSend = incRound(currentSend, maxQueue-1); } } else { currentSend = incRound(currentSend, maxQueue-1); } isSending = false; } lastSendTime = millis(); // timestamp the message } } // The call back function to receive data void callback(char* topic, byte* payload, unsigned int length) { String topicTitle = String(topic); String data = ""; for (int i = 0; i < length; i++) data += (char)payload[i]; Serial.print(data); } // The reconnect function to reconnect if lost connection from MQTT Broker void reconnect() { 55 while (!client.connected()) // wait when connected { // Connect to Broker with clientId, username and password if (client.connect(GATEWAY_ID, MQTT_CLIENT_USERNAME, MQTT_CLIENT_PASSWORD)) // connect to broker { Serial.println("MQTT Broker Connected!"); client.subscribe(MQTT_SUB_TOPIC); // register receive from topic } else { pubSubErr(client.state()); Serial.println("Try again in seconds"); delay(5000); } } } // MQTT errors void pubSubErr(int8_t MQTTErr) { if (MQTTErr == MQTT_CONNECTION_TIMEOUT) Serial.println("MQTT - Connection timeout"); else if (MQTTErr == MQTT_CONNECTION_LOST) Serial.println("MQTT - Connection lost"); else if (MQTTErr == MQTT_CONNECT_FAILED) Serial.println("MQTT - Connect failed"); else if (MQTTErr == MQTT_DISCONNECTED) Serial.println("MQTT - Disconnected"); else if (MQTTErr == MQTT_CONNECTED) Serial.println("MQTT - Connected"); else if (MQTTErr == MQTT_CONNECT_BAD_PROTOCOL) Serial.println("MQTT - Connect bad protocol"); else if (MQTTErr == MQTT_CONNECT_BAD_CLIENT_ID) Serial.println("MQTT - Connect bad Client-ID"); else if (MQTTErr == MQTT_CONNECT_UNAVAILABLE) Serial.println("MQTT - Connect unavailable"); else if (MQTTErr == MQTT_CONNECT_BAD_CREDENTIALS) Serial.println("MQTT - Connect bad credentials"); else if (MQTTErr == MQTT_CONNECT_UNAUTHORIZED) Serial.println("MQTT - Connect unauthorized"); } // MQTT send data bool sendData(int sender, int sensorId, int value) { DynamicJsonDocument jsonData(1024); jsonData["UserId"] = MQTT_CLIENT_USERNAME; 56 jsonData["GatewayId"] = GATEWAY_ID; jsonData["DeviceId"] = "DEV" + String(sender); jsonData["SensorId"] = "SEN" + String(sensorId); jsonData["Value"] = String((float)value/10); // divide 10 to float value char json[1024]; serializeJson(jsonData, json); if (!client.publish(MQTT_PUB_TOPIC, json, false)) { pubSubErr(client.state()); return false; } return true; } int incRound(int currentValue, int maxValue) { if (currentValue < maxValue) return currentValue + 1; return 0; } // LoRa receive void onReceive(int packetSize) { if (packetSize == 0) return; // if there's no packet, return else { byte SENDER = LoRa.read(); // read sender, 1st byte, sender:DEVICEID Serial.print("Received packet of sender #"); Serial.println(SENDER); // read packet int value; while (LoRa.available()) { byte sensorId = LoRa.read(); buf[0] = LoRa.read(); buf[1] = LoRa.read(); value = buf[0] | buf[1] { await Task.Delay(new Random().Next(0, 5) * 1000); await connection.StartAsync(); }; connection.On("ReceiveMessageBroker", (user, message) => { }); try { await connection.StartAsync(); } catch (Exception ex) { Console.WriteLine(ex.Message); } // CORS builder.Services.AddCors(options => { options.AddPolicy(name: MyPolicies, builder => { builder.SetIsOriginAllowed(_ => true) AllowAnyHeader() AllowCredentials() AllowAnyMethod(); }); }); //MQTT Configuration builder.WebHost.ConfigureKestrel(options => { options.ListenAnyIP(1883, l => l.UseMqtt()); // MQTT pipeline options.ListenAnyIP(5000); // Default HTTP pipeline }); builder.Services.AddControllers(); builder.Services.AddDbContext(); 58 builder.Services.AddHostedMqttServer(mqttServer => mqttServer.WithDefaultEndpoint().WithDefaultEndpointPort(1883)) AddMqttConnectionHandler() AddConnections() AddMqttTcpServerAdapter(); var app = builder.Build(); app.UseRouting(); app.UseCors(MyPolicies); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapConnectionHandler( "/mqtt", httpConnectionDispatcherOptions => httpConnectionDispatcherOptions.WebSockets.SubProtocolSelector = protocolList => protocolList.FirstOrDefault() ?? string.Empty); }); app.UseMqttServer(server => { server.ValidatingConnectionAsync += (e) => { using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); var user = db.Users.Where(x => x.IsEnabled && !x.IsDeleted && x.UserName == e.UserName) AsNoTracking() FirstOrDefault(); if (user != null && BCrypt.Net.BCrypt.Verify(e.Password, user.Password)) { if (user.UserName == "system") return Task.CompletedTask; Gateway? gateway = db.Gateways.Where(x => !x.IsDeleted && x.USE_ID == user.Id && x.Code == e.ClientId) AsNoTracking() FirstOrDefault(); if (gateway != null) return Task.CompletedTask; } } return Task.FromException(new Exception("User not authorized")); }; server.InterceptingPublishAsync += (e) => { using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); var gateway = db.Gateways.Where(x => !x.IsDeleted && x.Code == e.ClientId) 59 .AsNoTracking() FirstOrDefault(); if (gateway != null || e.ClientId.Equals("SystemMQTTClient")) { var payload = e.ApplicationMessage?.Payload == null ? null : Encoding.UTF8.GetString(e.ApplicationMessage.Payload); if (payload != null) { try { Data? data = JsonSerializer.Deserialize(payload); if (data != null) { db.Datas.Add(data); db.SaveChanges(); // send to SignalR data.Sender = e.ClientId; connection.InvokeAsync("SyncData", data.UserId, data); } } catch { } } return Task.CompletedTask; } } return Task.FromException(new Exception("User not authorized")); }; }); app.MapControllers(); app.Run(); Phụ lục 3: Mã lệnh MQTT Broker Server Visual Studio 2022 using using using using using using using using using using IoTMon; IoTMon.Hubs; IoTMon.Models; Microsoft.AspNetCore.Authentication.JwtBearer; Microsoft.AspNetCore.Http.Connections; Microsoft.EntityFrameworkCore; Microsoft.IdentityModel.Tokens; System.Text; System.Text.Json; System.Text.Json.Serialization; var MyPolicies = "_PoliciesAllowAll"; var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors(options => { options.AddPolicy(name: MyPolicies, builder => 60 { builder.SetIsOriginAllowed(_ => true) AllowAnyHeader() AllowCredentials() AllowAnyMethod(); }); }); // services.AddResponseCaching(); builder.Services.AddSignalR(hubOptions => { hubOptions.EnableDetailedErrors = true; //hubOptions.KeepAliveInterval = TimeSpan.FromMinutes(1); }).AddJsonProtocol(options => { options.PayloadSerializerOptions.PropertyNamingPolicy = null; }); // Add services to the container builder.Services.Configure(builder.Configuration.GetSection( "AppSettings")); // map settings section to object builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme ) AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateIssuerSigningKey = true, RequireExpirationTime = true, ValidateLifetime = true, ValidIssuer = builder.Configuration["AppSettings:Issuer"], ValidAudience = builder.Configuration["AppSettings:Issuer"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["AppSet tings:AppKey"])) }; options.Events = new CustomJwtBearerEvents(); }); builder.Services.AddControllers().AddJsonOptions(options => { options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles; options.JsonSerializerOptions.WriteIndented = true; options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; // options.JsonSerializerOptions.PropertyNamingPolicy = null; }); builder.Services.AddDbContext(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); 61 // Configure the HTTP request pipeline if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseCors(MyPolicies); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.MapHub("/IoTMonHub", options => { options.Transports = HttpTransportType.WebSockets | HttpTransportType.LongPolling; }); app.Run(); Phụ lục 4: Mã lệnh SignalR Web Server Visual Studio 2022 using IoTMon.Models; using Microsoft.AspNetCore.SignalR; namespace IoTMon.Hubs { public class MessageHub: Hub { public async Task SendAll(string user, object message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } public async Task SendToBroker(string user, object message) { await Clients.All.SendAsync("ReceiveMessageBroker", user, message); } public async Task JoinGroup(string group) { await Groups.AddToGroupAsync(Context.ConnectionId, group); } public async Task SendMessageToGroup(string groupName, string sender, object message) { await Clients.Group(groupName).SendAsync("SendMessage", sender, message); } 62 public async Task SyncData(string groupName, Data data) { await Clients.Group(groupName).SendAsync("SyncData", data.Sender, data); } } } Phụ lục 5: Mã lệnh phương thức SignalR Hub Visual Studio 2022 const updateData = (data) => { const deviceId = `${data.GatewayId}-${data.DeviceId}-${data.SensorId}`; console.log(data); const chartData = seriesData.find((x) => x.id === deviceId); if (chartData) { if (chartData.chart.series[0].data.length > topValue) chartData.chart.series[0].data.shift(); chartData.chart.series[0].data.push({ x: moment(data.CreatedDate).format("DD/MM/YYYY HH:mm"), y: Number(data.Value), }); ApexCharts.exec(deviceId, "updateSeries", chartData.chart.series); } }; useEffect(() => { if (connection) { connection start() then((result) => { connection.invoke("JoinGroup", userInfo.userName); connection.on("SyncData", (sender, data) => { updateData(data); }); }) catch((e) => console.log("Connection failed: ", e)); } }, [connection]); Phụ lục 6: Đoạn mã lệnh React làm việc với SignalR Hub Visual Studio Code class SignalRHelper { final url = 'https://iotmon.dnd-group.net/IoTMonHub'; late HubConnection hubConnection; String textMessage = ''; void connect(String groupName, receiveMessageHandler) { 63 hubConnection = HubConnectionBuilder().withUrl(url).withAutomaticReconnect().build(); hubConnection.on('SyncData', receiveMessageHandler); hubConnection.start()?.then((result) { hubConnection.invoke("JoinGroup", args: [groupName]); }); } void sendMessage(String name, String message) { hubConnection.invoke('SendMessage', args: [name, message]); textMessage = ''; } void disconnect() { hubConnection.stop(); } } late HubConnection hubConnection; SignalRHelper signalR = SignalRHelper(); final dashboardViewModel = DashboardViewModel(); @override void initState() { super.initState(); if (AppVariables.userInfo != null) { String userName = AppVariables.userInfo?.userName ?? ""; signalR.connect(userName, receiveMessageHandler); } } @override void dispose() { signalR.disconnect(); super.dispose(); } void receiveMessageHandler(args) { final data = args[1]; final sensorId = "${data["GatewayId"]}-${data["DeviceId"]}-${data["SensorId"]}"; dashboardViewModel.updateSensorData(sensorId, data["Value"]); } Phụ lục 7: Đoạn mã lệnh Flutter làm việc với SignalR Hub Visual Studio Code class SensorItem extends StatelessWidget { SensorDevice sensorDevice; VoidCallback onTap; SensorItem({super.key, required this.sensorDevice, required this.onTap}); 64 @override Widget build(BuildContext context) { late Icon icon; if (sensorDevice.code == "SEN1") { icon = const Icon(Icons.device_thermostat, size: 80, color: Colors.green); } else if (sensorDevice.code == "SEN2") { icon = const Icon(Icons.ac_unit, size: 80, color: Colors.blue); } else if (sensorDevice.code == "SEN3") { icon = const Icon(Icons.water_drop, size: 80, color: Color.fromARGB(255, 100, 181, 246)); } else if (sensorDevice.code == "SEN4") { icon = const Icon(Icons.opacity, size: 80, color: Color.fromARGB(255, 246, 226, 8)); } else { icon = const Icon(Icons.question_mark, size: 80, color: Color.fromARGB(255, 246, 226, 8)); } return Card( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ const SizedBox(height: 10), Padding( padding: const EdgeInsets.symmetric(horizontal: 3), child: Text( "${sensorDevice.deviceName} - ${sensorDevice.name}", style: const TextStyle(color: Colors.green, fontSize: 18), textAlign: TextAlign.center, ), ), Expanded( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ InkWell( onTap: onTap, child: icon, ), const SizedBox( width: 1, ), Text( sensorDevice.value, style: const TextStyle(fontSize: 30, color: Colors.green), ) 65 ], )), Padding( padding: const EdgeInsets.symmetric(vertical: 5), child: Text( Jiffy.parse(sensorDevice.createdDate) format(pattern: 'dd MMM yyyy HH:mm'), style: const TextStyle(color: Colors.blue), textAlign: TextAlign.center, ), ), ], ), ); } } Phụ lục 8: Đoạn mã lệnh Flutter hiển thị giá trị mợt cảm biến hình ứng dụng di động Visual Studio Code 66 LÝ LỊCH TRÍCH NGANG CỦA HỌC VIÊN I LÝ LỊCH SƠ LƯỢC: Họ tên: Trần Thanh Đàn Giới tính: Nam Ngày, tháng, năm sinh: 14/08/1981 Nơi sinh: Quy Nhơn, Bình Định Email: tranthanhdan@yahoo.com Điện thoại: 0919082949 II QUÁ TRÌNH ĐÀO TẠO: Từ tháng 9/1999 – 03/2004 tốt nghiệp Đại học quy ngành công nghệ thông tin Trường Đại Học Cơng Nghệ Tp Hồ Chí Minh III Q TRÌNH CƠNG TÁC CHUN MƠN: Thời gian Nơi cơng tác Cơng việc đảm nhiệm 04/2004 - 2006 Trường SaigonTech, Công viên Lập trình viên Phần mềm Quang Trung, Quận 12, Tp HCM 2006 - 2021 Trường SaigonTech, Cơng viên Trưởng nhóm phần mềm, Phần mềm Quang Trung, Quận Giảng viên Công nghệ 12, Tp HCM thông tin 2021 – 07/2022 Trường Cao Đẳng Sài Gịn, Cơng Trưởng bợ mơn Kỹ thuật viên Phần mềm Quang Trung, phần mềm Quận 12, Tp HCM 08/2022 – 02/2023 Trường Cao Đẳng Sài Gịn, Cơng Phó khoa Khoa Công viên Phần mềm Quang Trung, nghệ Thông tin Quận 12, Tp HCM 03/2023 – Trường Cao Đẳng Sài Gịn, Cơng Trưởng khoa Khoa Cơng viên Phần mềm Quang Trung, nghệ Thông tin Quận 12, Tp HCM Tp HCM, ngày tháng Năm 20 Người khai (Ký tên) 67