之前章节的工具code放在gitee上,大家有兴趣可以下载。欢迎交流
gitee地址:gitee.com/vectorli/te…
ps:目前匿名访问刚申请,需要等些时间。大家7月5号以后可以再次尝试
架构分析
之前,我们制作的软件。采集服务和显示界面集中在一个软件中。
这样做的好处是,简单明了,安装方便
弊端就是,需要用户一直开启界面,才能保证数据不间断。先然,这个问题无法让人接受\
分离式架构
解决以上问题,我们需要采用分离式架构。
提供数据采集后端服务+数据显示和配置前端界面:
后端服务
- 自动开机运行
- 读取串口配置,并定时获取数据
- 数据入库
前端界面
- 实时数据展示
- 历史数据查询
- 报表导出
- 报警提示
新建功能温湿度v2.0解决方案
- 添加之前的界面项目
- 新增一个win worker项目
worker 服务
把以下文件copy到work中去
- 数据库操作类
- 串口通讯类
- 温湿度传感器类
- 工具类
实现work的执行函数
work执行函数主要逻辑:
- 打开串口
- 启动定时器
- 获取数据
- main while
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO.Ports;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
namespace THWorker
{
public class Worker : BackgroundService
{
/// <summary>
/// 串口配置
/// </summary>
JObject ComConfInfo;
/// <summary>
/// 串口
/// </summary>
SerialPort Runport;
/// <summary>
/// 执行入口
/// </summary>
/// <param name="stoppingToken"></param>
/// <returns></returns>
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
//获取串口配置
if (!GetComInfo())
return;
//启动定时器
StartMainTimer();
//main while
while (!stoppingToken.IsCancellationRequested)
{
MyLogger._.Info($"Worker running at: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
await Task.Delay(30*1000, stoppingToken);
}
}
#region 5s 定时器回调
/// <summary>
/// 获取串口配置
/// </summary>
private bool GetComInfo()
{
MyLogger._.Debug("获取串口配置");
DataTable dt = DB_SerAPI.GetComConfFromDB();
if (dt != null && dt.Rows.Count > 0)
{
ComConfInfo = JObject.Parse(dt.Rows[0]["data"].ToString());
//打开串口
string comname = ComConfInfo["port"].ToString();
//波特率
int baudrate = int.Parse(ComConfInfo["baute"].ToString());
//打开串口
Runport = ComPort.V_OpenPort8N1(comname, baudrate);
if (Runport == null)
{
MyLogger._.Error("打开串口失败");
return false;
}
return true;
}
else
{
MyLogger._.Error("获取串口配置失败,请重新配置");
return false;
}
}
/// <summary>
/// Timer类执行定时到点事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void TimerOutCallBack(object sender, ElapsedEventArgs e)
{
MyLogger._.Debug("获取温湿度数据。。。");
try
{
if (Runport.IsOpen)
{
byte addr = 3;
if (ComConfInfo.ContainsKey("devaddr"))
addr = byte.Parse(ComConfInfo["devaddr"].ToString());
//获取数据
string ret = THSensor.ReadTHDataFromSensor(Runport, addr);
if (!string.IsNullOrEmpty(ret))
{
string temp = ret.Split('&')[0];
string humi = ret.Split('&')[1];
//入库操作
DB_SerAPI.SaveTHData(temp, humi);
//debug
MyLogger._.Debug($"T:{temp} - H:{humi}");
}
else
MyLogger._.Error("无数据,请检查配置参数");
}
}
catch (Exception ex)
{
MyLogger._.Error(ex.Message + "\r\n" + ex.StackTrace);
}
}
/// <summary>
/// 启动timer
/// </summary>
public void StartMainTimer()
{
System.Timers.Timer Read_Timer;
//设置定时间隔(毫秒为单位) 5s
int interval = 5*1000;
Read_Timer = new System.Timers.Timer(interval);
Read_Timer.AutoReset = true;
Read_Timer.Enabled = true;
Read_Timer.Elapsed += new ElapsedEventHandler((s, e) => TimerOutCallBack(s, e));
Read_Timer.Start();
}
#endregion
}
}
编译运行
编写服务安装和卸载bat脚本
关于win服务的安装和卸载脚本网上帖子很多,有兴趣可以查询。
卸载服务
echo off
::停止服务
sc stop TH_DATA_SER
::删除服务
sc delete TH_DATA_SER
::回车退出
set /p temp="按下回车键退出"
安装服务
echo off
::输出当前路径
echo 当前路径:%~dp0
::安装服务
echo %~dp0\THWorker.exe
::服务路径
set binPath= %~dp0%\THWorker.exe
::echo %binPath
::安装服务
sc create TH_DATA_SER binPath= %binPath%
::自动启动
sc config TH_DATA_SER start= auto
::启动服务
net start TH_DATA_SER
::回车退出
set /p temp="按下回车键退出"
测试服务安装
查看系统服务
下一章节介绍修改本地操作界面