C#实现数据采集系统-多设备采集

news2024/11/27 3:11:09

系统功能升级-多设备采集

数据采集系统在网络环境下,性能足够,可以实现1对多采集,需要支持多个设备进行同时采集功能,现在就开发多设备采集功能

修改多设备配置

设备配置

  1. DeviceLink 改成List集合的DeviceLinks
  2. 删掉Points,将点位集合放到对应的设备中去
    public class DaqOption
    {
        //单设备
        //public DeviceLink DeviceLink { get; set; }
        //多设备
        public List<DeviceLink> DeviceLinks { get; set; }

        public MqttConfig MqttConfig { get; set; }

        public ServiceConfig ServiceConfig { get; set; }
        
        //public List<RegisterPoint> Points { get; set; }

        public DaqOption() { }
    }
    
    
/// <summary>
 /// 设备链路类
 /// </summary>
 public class DeviceLink
 {
     public string UID { get; set; }
     public string Ip { get; set; }

     public int Port { get; set; }

     public int SlaveId { get; set; } = 1;

     /// <summary>
     /// 采集周期 单位:S   200ms 0.2s
     /// </summary>
     public double AcqTimeSpan { get; set; }
     
     
      //增加
     public List<RegisterPoint> Points { get; set; }

     public DeviceLink()
     {
         Points = new List<RegisterPoint>();
     }
 }

同时配置文件也跟着变化,DeviceLinks改成数组形式,变成两个设备的配置

{
  "DeviceLinks": [
    {
      "UID": "device01",
      "Ip": "127.0.0.1",
      "Port": 502,
      "SlaveId": 1,
      "AcqTimeSpan": 1
    },
    {
      "UID": "device02",
      "Ip": "127.0.0.1",
      "Port": 503,
      "SlaveId": 1,
      "AcqTimeSpan": 1
    }
  ],
  "MqttConfig": {
   //...
  },
  "ServiceConfig": {
  //...
  }
}

数据点位配置

RegisterPoint中增加设备Id的属性,用于区分,这个数据点位属于哪个设备

    public class RegisterPoint
    {
        //...

        public string DeviceId { get; set; }
    }

配置加载

DaqOptionBuilder修改配置加载,主要就是点位的加载,多设备配置的加载,按上面的配置修改后,自动反序列化加载。

点位的加载,需要读入新加的设备Id,然后根据设备id在DeviceLinks中查找到对应的设备,然后将点位加入到对应设备的点位集合Points中去。

 public class DaqOptionBuilder
 {
     //...

     public DaqOption Build()
     {
         var str = File.ReadAllText(_path + "\\Config.json");
         var option = JsonSerializer.Deserialize<DaqOption>(str);

         List<RegisterPoint> points = new List<RegisterPoint>();
         var lines = File.ReadAllLines(_path + "\\AllPoint.csv").ToList();
         lines.RemoveAt(0);
         foreach (var line in lines)
         {
             var values = line.Split(',');
             var point = new RegisterPoint
             {
                 UID = values[0],
                 Name = values[1],
                 Type = Type.GetType("System." + values[2]),
                 RegisterType = values[3],
                 Address = int.Parse(values[4]),
                 Length = int.Parse(values[5]),
                 DeviceId = values[6] //读入点位对应的设备ID
             };
             //查找对应的设备,将点位加入进去
             option.DeviceLinks.FirstOrDefault(x => x.UID == point.DeviceId)?.Points.Add(point);
         }

         return option;
     }
 }

主服务修改

多设备属性修改

修改DaqService服务类中,原来设备对象_deviceLink_points,改成设备集合_deviceLinks,然后对应的服务类中同步修改

 public class DaqService
 {
     // 原来
     // private DeviceLink _deviceLink;
     // private List<RegisterPoint> _points;
     
     //新
     private List<DeviceLink> _deviceLinks;
     
     
      public DaqService(DaqOption option)
     {
        
         //...
         //修改
         _deviceLinks = option.DeviceLinks;
         //...
     }
 }

功能修改

在启动和定时推送中,都改成循环_deviceLinks来实现功能

 public void Start()
 {
     foreach (var item in _deviceLinks)
     {
         ModbusTcp modbusTcp = new ModbusTcp(item);
         modbusTcp.ValueUpdated += ModbusTcp_ValueUpdated;
         modbusTcp.DoMitor();
     }

     mqttControllor = new MqttControllor(_option.MqttConfig);
     mqttControllor.MqttConnect();
     if (_serviceConfig.IsPushScheduled)
     {
         _timer.Start();
     }
 }
 
     private void Timer_Elapsed(object? sender, ElapsedEventArgs e)
    {
        foreach (var link in _deviceLinks)
        {
            try
            {
                DeviceMessage deviceMessage = new DeviceMessage() { DeviceId = link.UID };
                foreach (var point in link.Points)
                {
                    Console.WriteLine($"Point:{point.UID}-->Value:{point.Value}");
                    deviceMessage.Data.Add(point.UID, point.Value);
                }
                var str1 = JsonSerializer.Serialize(deviceMessage);
                mqttControllor.Publish("Device/" + link.UID + "/Time", str1);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

在变化推送中,可以直接使用点位中DeviceId 替代原设备ID(_deviceLink.UID

 //事件方法
 private void ModbusTcp_ValueUpdated(RegisterPoint point, object value)
 {
     if (_serviceConfig.IsPushChanged)
     {
         try
         {
             DeviceMessage device = new DeviceMessage { DeviceId = point.DeviceId };
             device.Data.Add(point.UID, value);
             var data = JsonSerializer.Serialize(device);
             mqttControllor.Publish($"Device/{point.DeviceId}/Update", data); //采集立刻推送
         }
         catch (Exception ex)
         {
             Console.WriteLine(ex.Message);
         }
         Console.WriteLine($"Point:{point.UID}-->Value:{value}");
     }
 }

完整的服务代码

 public class DaqService
 {
     private DaqOption _option;
     private List<DeviceLink> _deviceLinks;
     private ServiceConfig _serviceConfig;

     MqttControllor mqttControllor { get; set; }

     private Timer _timer;

     public DaqService(DaqOption option)
     {
         _option = option;
         _deviceLinks = option.DeviceLinks;
         _serviceConfig = option.ServiceConfig;
         if (_serviceConfig.IsPushScheduled)
         {
             _timer = new Timer(_serviceConfig.PushTimeSpan * 1000);
             _timer.Elapsed += Timer_Elapsed;
         }
     }

     public void Start()
     {
         foreach (var item in _deviceLinks)
         {
             ModbusTcp modbusTcp = new ModbusTcp(item);
             modbusTcp.ValueUpdated += ModbusTcp_ValueUpdated;
             modbusTcp.DoMitor();
         }

         mqttControllor = new MqttControllor(_option.MqttConfig);
         mqttControllor.MqttConnect();
         if (_serviceConfig.IsPushScheduled)
         {
             _timer.Start();
         }
     }

     private void Timer_Elapsed(object? sender, ElapsedEventArgs e)
     {
         foreach (var link in _deviceLinks)
         {
             try
             {
                 DeviceMessage deviceMessage = new DeviceMessage() { DeviceId = link.UID };
                 foreach (var point in link.Points)
                 {
                     Console.WriteLine($"Point:{point.UID}-->Value:{point.Value}");
                     deviceMessage.Data.Add(point.UID, point.Value);
                 }
                 var str1 = JsonSerializer.Serialize(deviceMessage);
                 mqttControllor.Publish("Device/" + link.UID + "/Time", str1);
             }
             catch (Exception ex)
             {
                 Console.WriteLine(ex.Message);
             }
         }
     }

     //事件方法
     private void ModbusTcp_ValueUpdated(RegisterPoint point, object value)
     {
         if (_serviceConfig.IsPushChanged)
         {
             try
             {
                 DeviceMessage device = new DeviceMessage { DeviceId = point.DeviceId };
                 device.Data.Add(point.UID, value);
                 var data = JsonSerializer.Serialize(device);
                 mqttControllor.Publish($"Device/{point.DeviceId}/Update", data); //采集立刻推送
             }
             catch (Exception ex)
             {
                 Console.WriteLine(ex.Message);
             }
             Console.WriteLine($"Point:{point.UID}-->Value:{value}");
         }
     }
 }

最终实现效果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2062673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【知识图谱】2.知识抽取与知识存储

目录 一、知识抽取 1、实体命名识别&#xff08;Name Entity Recognition&#xff09; 2、关系抽取&#xff08;Relation Extraction&#xff09; 3、实体统一&#xff08;Entity Resolution&#xff09; 4、指代消解&#xff08;Coreference Resolution&#xff0…

聚水潭ERP集成金蝶云星瀚(聚水潭主供应链)

源系统成集云目标系统 金蝶云星瀚介绍 金蝶云星瀚是专为大企业设计的新一代数字化管理云服务、大型企业SaaS管理云&#xff0c;旨在凭借千亿级高性能和世界一流企业的实践&#xff0c;帮助大企业实现可信的数字化系统升迁&#xff0c;打造韧性企业&#xff0c;支撑商…

【xilinx】Vivado : 解决 I/O 时钟布局器错误:Versal 示例

示例详细信息&#xff1a; 设备&#xff1a; XCVM1802 Versal Prime问题&#xff1a;尽管使用 CCIO 引脚作为时钟端口&#xff0c;但该工具仍返回 I/O 时钟布局器错误 错误&#xff1a; <span style"background-color:#f3f3f3"><span style"color:#…

Windows+ONNX+TensorRT+YOLOV8+C++环境搭建

需求 跑通了Python环境下的Yolov8&#xff0c;但是考虑到性能&#xff0c;想试试C环境下的优化效果。 环境 Windows11 TensorRT8.6.1.6 CUDA 12.0 cudnn 8.9.7 opencv4.5.5 VS2019 参考目录 本次搭建主要参考以下博客和视频。第一个博客以下简称“博客1”&#xff0c…

Python画笔案例-004 绘制等腰三角形

1、绘制等腰三角形 通过 python 的turtle 库绘制一个等腰三角形的图案&#xff0c;如下图&#xff1a; 2、实现代码 这节课引入了新的指令&#xff0c;speed()-移动速度&#xff0c;home()-回到初始位置&#xff0c;回家的意思。hideturtle()&#xff0c;这个是隐藏海龟图形,并…

deepin 23丨如意玲珑正式集成至deepin 23,生态适配超千款

查看原文 近日&#xff0c;deepin 23正式发布&#xff0c;如意玲珑&#xff08;Linyaps&#xff09;&#xff08;以下简称玲珑&#xff09;作为deepin 23的重要特性之一&#xff0c;已经正式集成至deepin系统仓库&#xff0c;所有deepin 23的用户都可以无门槛地使用玲珑应用。…

Nginx: 配置项之events段核心参数用法梳理

events 核心参数 看一下配置文件 events 段中常用的一些核心参数 经常使用的参数并不多&#xff0c;比较常配置的就这6个 1 ) use 含义是 nginx使用何种事件驱动模型 这个事件驱动模型和linux操作系统底层的IO事件处理模型有关系语法&#xff1a;use methodmethod可选值&am…

云服务器常见问题及解决方案

1. 性能问题 问题描述&#xff1a;云服务器性能可能会受到多种因素影响&#xff0c;如虚拟化开销、资源竞争等&#xff0c;导致应用程序运行缓慢。 解决方案&#xff1a; 选择合适的实例类型&#xff1a;根据应用需求选择适当的实例类型&#xff0c;如计算优化型、内存优化型…

API篇(Java - 随机器(Random))(doing)

目录 一、Random 1. 简介 2. 什么是种子 3. 相关方法 4. Random对象的生成 5. Random类中的常用方法 6. 使用 6.1. 创建对象 6.2. 生成[0,1.0)区间的小数 6.3. 生成[0,5.0)区间的小数 6.4. 生成[1,2.5)区间的小数 6.5. 生成任意整数 6.6. 生成[0,10)区间的整数 6.…

LCP9回文数[leetcode-9-easy]

LCP&#xff0c;9回文数 给你一个整数 x &#xff0c;如果 x 是一个回文整数&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 回文数 是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。 例如&#xff…

Vue 3 的 emit 简单使用

在 Vue 3 中使用 emit&#xff0c;子组件可以将事件通知父组件&#xff0c;父组件可以在响应这些事件时执行特定的逻辑。 emit 是一种非常灵活的通信方式&#xff0c;允许组件之间以解耦的方式进行交互。 1. 基本用法 1、使用 defineEmits 子组件 <template><div…

【Hadoop】知识点总结、大学期末复习

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; Yaoyao2024往期回顾&#xff1a; 【论文精读】上交大、上海人工智能实验室等提出基于配准的少样本异常检测框架超详细解读&#xff08;翻译&#xff0b;精读&#xff09;每日一…

关于Hipe并发库中动态线程库DynamicThreadPond的一点解读(四)

文章目录 前提提交的任务有返回值怎么办总结 前提 上一节关于Hipe并发库中动态线程库DynamicThreadPond的一点解读(三)我们分析了以何种方式向线程池提交任务、提交的任务若有参数怎么办&#xff0c;这一节我们分析提交的任务若有返回值怎么办&#xff1f; 提交的任务有返回值…

bootloader相关内容的辨析

在PC机中&#xff0c;BIOS&#xff08;Basic Input/Output System&#xff0c;基本输入输出系统&#xff09;和UEFI&#xff08;Unified Extensible Firmware Interface&#xff0c;统一可扩展固件接口&#xff09;是两种用于初始化系统硬件、加载操作系统启动程&#xff08;如…

nestjs nest-cli.json中的assets不生效

官方文档 Documentation | NestJS - A progressive Node.js framework // nest-cli.json{"collection": "nestjs/schematics","sourceRoot": "src","compilerOptions": {"assets": ["microservices/mail/te…

【宠粉赠书】智能计算系统:从深度学习到大模型 第2版

为了回馈粉丝们的厚爱&#xff0c;今天小智给大家送上一套关于图神经网络的学习宝典——《智能计算系统&#xff1a;从深度学习到大模型 第2版》。下面我会详细给大家介绍这本书&#xff0c;文末留有领取方式。 “只要你想把大模型做得更好、做得更大、做得更快、做得更省电&am…

Docker部署常用开发组件(保姆级教程)

说明 本文总结了一些常用组件的Docker启动命令及过程&#xff0c;在开发过程中只需花费数分钟下载和配置即可完美使用这些服务。 Mysql MySQL 是一种开源关系数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;目前由 Oracle 公司维护。MySQL 以其高性能、可靠性和易用…

Qt4代码实现下面的界面

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

AI预测体彩排3采取888=3策略+和值012路或胆码测试8月22日升级新模型预测第59弹

经过近60期的测试&#xff0c;当然有很多彩友也一直在观察我每天发的预测结果&#xff0c;得到了一个非常有价值的信息&#xff0c;那就是9码定位的命中率非常高&#xff0c;已到达90%的命中率&#xff0c;这给喜欢打私菜的朋友提供了极高价值的预测结果~当然了&#xff0c;大部…

【C++】map、set基本用法

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; 前言: C的STL已经学习很大一部分了&#xff0c;接下来介绍的是map set是c的是两种关联容器。 简单介绍 map set&#xff1a; 两者都使用红黑树作为底层数据结构来存储元素。map是一种键值对容器&#xff0c;其中每个键…