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

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

数据采集系统在网络环境下,性能足够,可以实现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.mfbz.cn/a/871573.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

datawind可视化查询-其他函数

飞书文档学习链接:https://www.volcengine.com/docs/4726/47275 1. 用户名函数 用户名函数并非 ClickHouse 官方函数,而是与项目用户信息相结合,用于返回当前使用用户的指定信息的函数。 USERNAME()可返回当前用户的用户名,如下所示。该函数也可与其他函数组合使用 2. J…

Android 应用集成百度地图定位SDK

在当今的移动互联网时代&#xff0c;位置服务已经成为了众多应用不可或缺的功能之一。无论是社交应用中的位置分享&#xff0c;还是服务类应用中的位置导航&#xff0c;都离不开精准的定位技术。为了满足这一需求&#xff0c;越来越多的开发者选择集成第三方的定位SDK。其中&am…

【ARM Hypervisor And SMMU 系列 5 -- SMMU 和 IOMMU技术】

文章目录 SMMU 和 IOMMU技术ARM 的 SMMUTranslation process overviewTBU 和 TCU 的关系TBUTCUTLBSMMU 和 IOMMU技术 文章 讲到了为支持I/O透传机制中的DMA设备传输而引入的IOMMU/SMMU技术,同时留了一个问题:IOMMU/SMMU是否可以同时支持GVA->GPA和GPA->HPA的转换? 答案…

三种相机模型总结(针孔、鱼眼、全景)

相机标定 文章目录 相机标定前言 前言 我们最常见的投影模型Perspective Projection Model描述的就是针孔相机的成像原理。从上面的图根据相似三角形可以得出 参考链接 https://zhuanlan.zhihu.com/p/540969207 相机标定之张正友标定法数学原理详解&#xff08;含python源码&a…

SpingBoot集成kafka发送读取消息

SpingBoot集成kafka开发 kafka的几个常见概念 1、springboot和kafka对应版本&#xff08;重要&#xff09;2、创建springboot项目&#xff0c;引入kafka依赖2.1、生产者EventProducer2.2、消费者EventConsumer2.3、启动生产者的方法SpringBoot01KafkaBaseApplication2.4、appli…

蓝队技能-应急响应篇挖矿病毒系统样本家族威胁情报异常定性排查分析处置封锁

知识点 1、应急响应-挖矿病毒-定性&排查 2、应急响应-挖矿病毒-应急&处置演示案例-蓝队技能-挖矿病毒-样本&定性&排查&应急&处置 挖矿病毒 随着虚拟货币的疯狂炒作&#xff0c;挖矿病毒已经成为不法分子利用最为频繁的攻击方式之一。 可以利用个人电…

[论文笔记]Improving Retrieval Augmented Language Model with Self-Reasoning

引言 今天带来一篇百度提出的关于提升RAG准确率的论文笔记&#xff0c;Improving Retrieval Augmented Language Model with Self-Reasoning。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 检索增强语言模型(Retrie…

你应该停止使用的 7 个已弃用的 Python 库

欢迎来到雲闪世界。升级您的 Python 工具包&#xff1a;发现 7 个应停止使用的过时库以及替代它们的功能。最近&#xff0c;我回顾了 Python 的新特性&#xff0c;发现每个版本都引入了创新&#xff0c;使我们的日常开发工作变得更加轻松。 这让我意识到科技是一门永无止境的艺…

有了这4款工具,你就知道电脑怎么录屏了!

电脑屏幕录屏这个问题很多人都会碰到&#xff0c;比如教学视频录制&#xff0c;游戏技巧分享&#xff0c;软件操作演示等等。因为场景众多&#xff0c;电脑自带的录屏功能不一定能满足&#xff0c;所以借助第三方工具是一个很有效的办法。如果大家不知道如何录屏&#xff0c;可…

I2C学习:上拉电阻选取

一&#xff0e;I2C简介 I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。I2C总线在使用时&#xff0c;需要接上拉电阻&#xff0c;这是因为I2C接口是开漏输出&#xff0c;如图1所示。 图1 I2C开漏输出 I2C有5种速度模式&#xff1a;标准&#xff08;100KHz&am…

在亚马逊云科技上安全、合规地创建AI大模型训练基础设施并开发AI应用服务

项目简介&#xff1a; 小李哥将继续每天介绍一个基于亚马逊云科技AWS云计算平台的全球前沿AI技术解决方案&#xff0c;帮助大家快速了解国际上最热门的云计算平台亚马逊云科技AWS AI最佳实践&#xff0c;并应用到自己的日常工作里。 本次介绍的是如何在亚马逊云科技利用Servi…

就业c++02 随处可见红黑树

通过key来比较节点插入哪个地方 一种key value 另一种顺序执行 比如查找小于50的数字在左面还是在右面 访问那个资源 他的次数是多少构建了 资源key 次数 value 海量的io 过来访问 知道哪一个io 就是key value查找 根据黑色高度的差异 红色节点和红色节点是不相邻的

Python数据分析:数据可视化(Matplotlib、Seaborn)

数据可视化是数据分析中不可或缺的一部分&#xff0c;通过将数据以图形的方式展示出来&#xff0c;可以更直观地理解数据的分布和趋势。在Python中&#xff0c;Matplotlib和Seaborn是两个非常流行和强大的数据可视化库。本文将详细介绍这两个库的使用方法&#xff0c;并附上一个…

OceanMind海睿思入选《2024中国企业数智化转型升级服务全景图/产业图谱》

近日&#xff0c;国内知名数据智能产业创新服务媒体数据猿携手上海大数据联盟发布了《2024中国企业数智化转型升级服务全景图/产业图谱1.0版》。中新赛克海睿思从数千家企业中脱颖而出&#xff0c;成功入选「底层技术服务 - 大数据」细分领域。 在历经数月的时间里&#xff0c;…

实现Bezier样条曲线

1.给出n1 个控制点pk(xk,yk,zk),这里k可取值0-n,多项式函数公式如下 获取的单个点的代码 void zmBezier::getPoint(float u, double p[3]) {int n m_count - 1;double x 0, y 0, z 0;for(int k 0; k < n; k){x m_ctrlPoints[k][0] * BEZ_k_n(n, k, u);y m_ctrlPoin…

《机器学习》—— 使用过采样方法实现逻辑回归分类问题

文章目录 一、什么是过采样方法&#xff1f;二、使用过采样方法实现逻辑回归分类问题三、过采样的优缺点 本篇内容是 基于Python的scikit-learn库中sklearn.linear_model 类中的 LogisticRegression&#xff08;&#xff09;逻辑回归方法实现的&#xff0c;其内容中只是在处理…

创建、使用、删除 数据库

一、创建数据库 1.1 使用DDL语句创建数据库 CREATE DATABASE 数据库名 CHARACTER SET 字符编码 COLLATE 排序规则; 如果不指定数据库编码&#xff0c;默认是utf8&#xff1b; 如果不指定排序规则&#xff0c;默认是utf8_general_ci&#xff0c;即不区分大小写&#xff0c;区分…

我“开发“了一款大模型应用,AI门槛这么低了吗?

现在国产大模型多如牛毛。虽然可选的大模型产品很多&#xff0c;但普遍存在同质化、高分低能、实用性差、专业性不足的问题&#xff0c;哪怕是诸如ChatGPT、Gemini这样全球顶尖的大模型也会存在这种情况。 还有一点比较重要的是&#xff0c;由于大模型需要算力、算法、数据的基…

vue+ckEditor5 复制粘贴wold文字+图片并保存格式

第一步在vue2项目下安装 npm install --save ckeditor/ckeditor5-build-decoupled-document 第二 项目下新建一个plugins的文件夹将这个包ckeditor5-build-classic放入 &#xff08;包在页面最上方 有个下载按钮 可以下载&#xff09; 刚开始时 ckeditor5-build-classic文件…

「字符串」前缀函数|KMP匹配:规范化next数组 / LeetCode 28(C++)

目录 概述 思路 核心概念&#xff1a;前缀函数 1.前缀函数 2.next数组 1.考研版本 2.竞赛版本 算法过程 构建next数组 匹配过程 复杂度 Code 概述 为什么大家总觉得KMP难&#xff1f;难的根本就不是这个算法本身。 在互联网上你可以见到八十种KMP算法的next数组…