树莓派4B 采集传感器的温湿度 通过.Net Core 3.1的控制台程序将数据上传到服务器端,程序部署在docker中
客户端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 using Iot.Device.DHTxx;using Microsoft.AspNetCore.SignalR.Client;using NLog;using System;using System.Collections.Generic;using System.Threading.Tasks;namespace IotClient { class Program { private static HubConnection _connection; private static readonly Logger logger = LogManager.GetLogger("IotClient" ); private static Guid DeviceGuid = Guid.Parse("886dae3f-1e08-41ce-9531-e2d326ee693b" ); static async Task Main (string [] args ) { logger.Debug("启动客户端" ); _connection = new HubConnectionBuilder() .WithUrl("http://ip:port/iotHub" ) .WithAutomaticReconnect() .Build(); _connection.On<string >("IotClientRsult" , message => IotClientRsult(message)); try { await _connection.StartAsync(); logger.Info($"SignalR连接成功!" ); } catch (Exception ex) { logger.Fatal($"SignalR连接失败:{ex.Message} " ); } using Dht11 dht = new Dht11(26 ); List<Attribute> attributes = new List<Attribute>() { new Attribute(){Identifier ="humidity" , Data =new List<Data>()}, new Attribute(){Identifier ="temperature" , Data =new List<Data>()}, }; UploadData uploadData = new UploadData() { DeviceGuid = DeviceGuid, Attributes = attributes, Timestamp = DateTimeHelper.GetTimeStamp() }; while (true ) { try { var humidityOrNan = dht.Humidity.ToString("0.0" ); var temperatureOrNan = dht.Temperature.Celsius.ToString("0.0" ); if (dht.IsLastReadSuccessful) { var temperature = decimal .Parse(temperatureOrNan); var humidity = decimal .Parse(humidityOrNan); Console.WriteLine($"Temperature: {temperature} °C, Humidity: { humidity} % " ); if (_connection.State == HubConnectionState.Connected) { try { uploadData.Timestamp = DateTimeHelper.GetTimeStamp(); uploadData.Attributes[0 ].Data.Clear(); uploadData.Attributes[0 ].Data.Add(new Data { Value = humidity, Timestamp = DateTimeHelper.GetTimeStamp(), }); uploadData.Attributes[1 ].Data.Clear(); uploadData.Attributes[1 ].Data.Add(new Data { Value = temperature, Timestamp = DateTimeHelper.GetTimeStamp(), }); await _connection.InvokeAsync("IotClientUpload" , uploadData); } catch (Exception ex) { logger.Fatal($"SignalR发送数据失败:{ex.Message} " ); } } } } catch (Exception ex) { logger.Fatal($"出现错误:{ex.Message} {ex.StackTrace} " ); } await Task.Delay(1000 * 5 ); } } private static void IotClientRsult (string message ) { Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss" )} {message} " ); } } }
数据对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class UploadData { public List<Attribute> Attributes { get ; set ; } public int Timestamp { get ; set ; } public Guid DeviceGuid { get ; set ; } } public class Attribute { public string Identifier { get ; set ; } public List<Data> Data { get ; set ; } } public class Data { public decimal Value { get ; set ; } public int Timestamp { get ; set ; } }
服务器端,SignalR:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 using demo.Database;using demo.Entities;using demo.SignalR.IotClient;using Microsoft.AspNetCore.SignalR;using Microsoft.Extensions.Logging;using System;using System.Threading.Tasks;namespace demo.SignalR { public class IotHub : Hub { private readonly MyContext _myContext; private readonly ILoggerFactory _loggerFactory; public IotHub (MyContext myContext, ILoggerFactory loggerFactory ) { _myContext = myContext; _loggerFactory = loggerFactory; } public async Task IotClientUpload (UploadData uploadData ) { var logger = _loggerFactory.CreateLogger(typeof (IotHub)); logger.LogError(Newtonsoft.Json.JsonConvert.SerializeObject(uploadData)); var connectionId = Context.ConnectionId; if (uploadData is null ) { await IotClientRsult(connectionId, $"上传内容为空!" ); return ; } if (uploadData.Attributes != null ) { foreach (var attribute in uploadData.Attributes) { foreach (var data in attribute.Data) { _myContext.IotData.Add(new IotData() { Guid = Guid.NewGuid(), Timestamp = data.Timestamp, Value = data.Value, Identifier = attribute.Identifier, DeviceGuid = uploadData.DeviceGuid }); } } } int count = await _myContext.SaveChangesAsync(); await IotClientRsult(connectionId, $"成功上传 {count} 条数据!" ); } public async Task IotClientRsult (string connectionId, string message ) { await Clients.Client(connectionId).SendAsync("IotClientRsult" , message); } } }
Dockerfile:
1 2 3 4 5 6 7 8 9 10 11 12 13 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 -buster-slim-arm32v7 AS baseWORKDIR /app ENV LANG C.UTF-8 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime RUN echo 'Asia/Shanghai' >/etc/timezone ENTRYPOINT ["dotnet" , "IotClient.dll" ]
Build:
1 2 3 docker build -t iot-client-image . docker run -d --name iot-client -v /opt/netcore/IotClient:/app --privileged iot-client-image
Docker访问Raspberry Pi GPIO引脚,需要加 –privileged 参数
效果图:
后续再根据数据做异常预警
树莓派 安装 .Net Core 3.1:
1 2 3 4 5 6 7 8 9 wget https://download.visualstudio.microsoft.com/download/pr/8c839c0e-a5ae-4254-8d8b-c012528fe601/c147e26bad68f97eacc287a71e01331d/aspnetcore-runtime-3.1.0-linux-arm.tar.gz wget https://download.visualstudio.microsoft.com/download/pr/67766a96-eb8c-4cd2-bca4-ea63d2cc115c/7bf13840aa2ed88793b7315d5e0d74e6/dotnet-sdk-3.1.100-linux-arm.tar.gz mkdir -p $HOME/pi/dotnet && tar zxf dotnet-sdk-3.1.100-linux-arm.tar.gz -C $HOME/pi/dotnet tar zxf aspnetcore-runtime-3.1.0-linux-arm.tar.gz -C $HOME/pi/dotnet export DOTNET_ROOT=$HOME/pi/dotnet export PATH=$PATH:$HOME/pi/dotnet
临时变量永久生效:
添加:
1 2 export DOTNET_ROOT=$HOME/pi/dotnet export PATH=$PATH:$HOME/pi/dotnet