树莓派4B 采集传感器的温湿度 通过.Net Core 3.1的控制台程序将数据上传到服务器端,程序部署在docker中
客户端代码:
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("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 attributes = new List()
{
new Attribute(){Identifier ="humidity", Data =new List()},
new Attribute(){Identifier ="temperature", Data =new List()},
};
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}");
}
}
}
数据对象:
public class UploadData
{
public List Attributes { get; set; }
public int Timestamp { get; set; }
public Guid DeviceGuid { get; set; }
}
public class Attribute
{
public string Identifier { get; set; }
public List Data { get; set; }
}
public class Data
{
public decimal Value { get; set; }
public int Timestamp { get; set; }
}
服务器端,SignalR:
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:
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim-arm32v7 AS base
WORKDIR /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:
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:
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
临时变量永久生效:
vi /etc/profile
添加:
export DOTNET_ROOT=$HOME/pi/dotnet
export PATH=$PATH:$HOME/pi/dotnet