【.Net Core】樹莓派通過Signalr上傳傳感器數據

樹莓派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<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}");
        }
    }
}

數據對象:

    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:

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

 

 
發佈了189 篇原創文章 · 獲贊 153 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章