springboot 连接西门子plc,读取对应的值,并修改到数据库

springboot 连接西门子plc,读取对应的值,并修改到数据库

需求:服务器连接plc,读取数据,之后写入到数据库,但是要求速度很快,而且plc中命令对应的值是不断变化的,这个变化,服务器要实时的看到;本地测试,可以通过博途
一、代码实现
1. maven依赖
<dependency><groupId>com.github.xingshuangs</groupId><artifactId>iot-communication</artifactId><version>1.4.4</version>
</dependency>
2. 入口函数
@SpringBootApplication
@MapperScan("com.gotion.modules.dao")
public class FamenYaokongApplication implements ApplicationRunner {private static Logger logger = LoggerFactory.getLogger(FamenYaokongApplication.class);public static void main(String[] args) {SpringApplication.run(FamenYaokongApplication.class, args);}@Autowiredprivate OtherProgram otherProgram;@Overridepublic void run(ApplicationArguments args) throws Exception {// 创建子线程Thread thread = new Thread(otherProgram);// 这句话保证主线程停掉的时候,子线程持续运行thread.setDaemon(true);// 启动子线程thread.start();}
}
3. 子线程类
package com.gotion.modules.task;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.xingshuangs.iot.protocol.common.serializer.ByteArraySerializer;
import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
import com.gotion.modules.dao.SysPlcDao;
import com.gotion.modules.dao.SysPlcMlDao;
import com.gotion.modules.entity.SysPlcEntity;
import com.gotion.modules.entity.SysPlcMlEntity;
import com.gotion.modules.plc.PlcReadDataUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;/*** @Author: Administrator* @Date: 2023/11/5* @Description:*/
@Service
public class OtherProgram implements Runnable {private static Logger logger = LoggerFactory.getLogger(OtherProgram.class);@Autowiredprivate SysPlcDao plcIpDao;@Autowiredprivate SysPlcMlDao plcMlDao;@Overridepublic void run() {// 在这里编写子线程的执行逻辑// 可以调用其他程序的入口方法或执行其他操作logger.info("plc startTime:" + System.currentTimeMillis());QueryWrapper<SysPlcEntity> queryWrapper = new QueryWrapper<>();queryWrapper.select("id", "ip_address").eq("is_flag", 1);List<SysPlcEntity> ipList = plcIpDao.selectList(queryWrapper);if (!ipList.isEmpty()) {ipList.stream().forEach(plcIp -> {// 建立连接S7PLC s7PLC = new S7PLC(EPlcType.S1200, plcIp.getIpAddress()); // 使用plcIp的IP地址while (true) {// 构建序列化对象ByteArraySerializer serializer = ByteArraySerializer.newInstance();// 获取对应plc下db1的命令最大字节的数字SysPlcMlEntity db1PlcMl = plcMlDao.getOneOrderByIdDescLimitOneAndIpIdAndContentLike(plcIp.getId(), "DB1");SysPlcMlEntity db3PlcMl = plcMlDao.getOneOrderByIdDescLimitOneAndIpIdAndContentLike(plcIp.getId(), "DB3");SysPlcMlEntity db4PlcMl = plcMlDao.getOneOrderByIdDescLimitOneAndIpIdAndContentLike(plcIp.getId(), "DB4");SysPlcMlEntity db5PlcMl = plcMlDao.getOneOrderByIdDescLimitOneAndIpIdAndContentLike(plcIp.getId(), "DB5");SysPlcMlEntity db6PlcMl = plcMlDao.getOneOrderByIdDescLimitOneAndIpIdAndContentLike(plcIp.getId(), "DB6");SysPlcMlEntity db7PlcMl = plcMlDao.getOneOrderByIdDescLimitOneAndIpIdAndContentLike(plcIp.getId(), "DB7");//-----------------读取plc1的字节   DBW两个字节,DBD4个字节  DBX/B一个字节 看最后一个以什么结尾,就在对应的字节数上添加2或者4或者1// DB1地址范围是0~220+4   224if (db1PlcMl != null) {byte[] db1Datas = s7PLC.readByte("DB1.DBD0", PlcReadDataUtils.getMaxByteOffsite(db1PlcMl));if (db1Datas != null && db1Datas.length > 0) {//DB1数据块PlcReadDataUtils.readData(plcIp.getId(), "DB1", serializer, db1Datas, plcMlDao);}}// DB3地址范围是0~284+4   288  DBW两个字节,DBD4个字节  B一个字节if (db3PlcMl != null) {byte[] db3Datas = s7PLC.readByte("DB3.DBW0", PlcReadDataUtils.getMaxByteOffsite(db3PlcMl));if (db3Datas != null && db3Datas.length > 0) {//DB3数据块PlcReadDataUtils.readData(plcIp.getId(), "DB3", serializer, db3Datas, plcMlDao);}}if (db4PlcMl != null) {// DB4地址范围是0~286     287byte[] db4Datas = s7PLC.readByte("DB4.DBD0", PlcReadDataUtils.getMaxByteOffsite(db4PlcMl));if (db4Datas != null && db4Datas.length>0) {// DB4数据块PlcReadDataUtils.readData(plcIp.getId(), "DB4", serializer, db4Datas, plcMlDao);}}if (db5PlcMl != null) {// DB5地址范围是0~374+2   376byte[] db5Datas = s7PLC.readByte("DB5.DBX0.0", PlcReadDataUtils.getMaxByteOffsite(db5PlcMl));if (db5Datas != null && db5Datas.length > 0) {// DB5数据块PlcReadDataUtils.readData(plcIp.getId(), "DB5", serializer, db5Datas, plcMlDao);}}if (db6PlcMl != null) {byte[] db6Datas = s7PLC.readByte("DB6.DBX0.0", PlcReadDataUtils.getMaxByteOffsite(db6PlcMl));if (db6Datas != null && db6Datas.length >0) {PlcReadDataUtils.readData(plcIp.getId(),"DB6", serializer, db6Datas, plcMlDao);}}if (db7PlcMl != null) {// DB7byte[] db7Datas = s7PLC.readByte("DB7.DBX0.0", PlcReadDataUtils.getMaxByteOffsite(db7PlcMl));if (db7Datas != null && db7Datas.length > 0) {// DB7数据块PlcReadDataUtils.readData(plcIp.getId(),"DB7", serializer, db7Datas, plcMlDao);}}logger.info("plc endTime:" + System.currentTimeMillis());}});}}
}
  1. dao层和sql语句
/**
* 根据id和db块的命令查询最新的一条数据,目的:获取最大的命令值
* @param ipId
* @param mlContent
* @return
*/
SysPlcMlEntity getOneOrderByIdDescLimitOneAndIpIdAndContentLike(@Param("ipId") Long ipId, @Param("mlContent") String mlContent);
<select id="getOneOrderByIdDescLimitOneAndIpIdAndContentLike" resultType="com.gotion.modules.entity.SysPlcMlEntity">SELECT id,ip_id,type_id,name,ml_name,ml_content,ml_value FROM `sys_plc_ml`<where><if test="ipId != null">and ip_id = #{ipId}</if><if test="mlContent != null and mlContent.trim() != ''">and ml_content like concat(#{mlContent},'%')</if></where>ORDER BY id DESC LIMIT 1
</select>
  1. 工具类
package com.gotion.modules.plc;import com.github.xingshuangs.iot.protocol.common.enums.EDataType;
import com.github.xingshuangs.iot.protocol.common.serializer.ByteArrayParameter;
import com.github.xingshuangs.iot.protocol.common.serializer.ByteArraySerializer;
import com.gotion.modules.dao.SysPlcMlDao;
import com.gotion.modules.entity.SysPlcMlEntity;import java.util.ArrayList;
import java.util.List;/*** @Author: Administrator* @Date: 2023/11/5* @Description:*/
public class PlcReadDataUtils {public static Integer getMaxByteOffsite(SysPlcMlEntity plcMl) {int count = 0;String[] mlContents =  plcMl.getMlContent().split("\\.");String byteOffset = mlContents[1].replaceAll("[^0-9]", "");if (plcMl.getMlContent().contains("DBD")) {count = Integer.valueOf(byteOffset) + 4;} else if (plcMl.getMlContent().contains("DBW")) {count = Integer.valueOf(byteOffset) + 2;} else if (plcMl.getMlContent().contains("DBX")) {count = Integer.valueOf(byteOffset) + 1;}return count;}public static List<ByteArrayParameter> readData(Long ipId, String dbNumber, ByteArraySerializer serializer, byte[] datas, SysPlcMlDao plcMlDao) {// 查询plc1对应的db1的数据集合List<SysPlcMlEntity> plcMlList = plcMlDao.getListByIpIdAndMlContentLike(ipId, dbNumber);List<ByteArrayParameter> db1ParameterList = new ArrayList<>();plcMlList.stream().forEach(plcMl-> {String[] mlContents =  plcMl.getMlContent().split("\\.");String byteOffset = mlContents[1].replaceAll("[^0-9]", "");// 先判断DB1.DBX0.0 第二个点后面有没有小数,没有就设置为0String bitOffset = "0";if (mlContents.length > 2) {bitOffset = mlContents[2];}if (plcMl.getMlContent().contains("DBD")) {db1ParameterList.add(new ByteArrayParameter(Integer.valueOf(byteOffset), Integer.valueOf(bitOffset), 1, EDataType.FLOAT32));}if (plcMl.getMlContent().contains("DBW")) {db1ParameterList.add(new ByteArrayParameter(Integer.valueOf(byteOffset), Integer.valueOf(bitOffset), 1, EDataType.INT16));}if (plcMl.getMlContent().contains("DBX")) {db1ParameterList.add(new ByteArrayParameter(Integer.valueOf(byteOffset), Integer.valueOf(bitOffset),1, EDataType.BOOL));}});// 读取db1的 字节数据List<ByteArrayParameter> byteList = serializer.extractParameter(db1ParameterList, datas);for (int i = 0; i < plcMlList.size(); i++) {plcMlList.get(i).setMlValue(byteList.get(i).getValue().toString());}plcMlDao.batchUpdateMlList(plcMlList);return byteList;}
}
  1. 数据库结构
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
二、解释:

思路:有多个plc,先查出plc的数量,根据plc地址创建连接,然后根据命令读取值
DB5.DBW2.1:数据块5,字节索引:2,位索引:1
DB4.DBW3:数据块4,字节索引:3,位索引:0
DB5.DBD2.3:数据块5,字节索引:2,位索引:3
DB5.DBD2:数据块:5,字节索引:2,位索引:0
DB4.DBX1.1:数据块:4,字节索引:1,位索引:1
DB4.DBX1:数据块:4,字节索引:1,位索引:0

每个命令后面的数据分别代表字节索引和位索引

我代码的逻辑:
(1)获取最大的字节数:先查询出每个plc中,每个db块的最大的字节索引,命令是连续的,我就从数据库中倒叙查询每个plc中每个db块,然后取一条数据;
SysPlcMlEntity db1PlcMl = plcMlDao.getOneOrderByIdDescLimitOneAndIpIdAndContentLike(plcIp.getId(), "DB1");
(2)因为每个db块的初始字节索引和位索引都是0,所以代码中直接写死初始值,根据初始值和每个db块的数量读取plc字节数组;
byte[] db1Datas = s7PLC.readByte("DB1.DBD0", PlcReadDataUtils.getMaxByteOffsite(db1PlcMl));
(3)解析读取到的字节数组:
① 由于要读取字节数组,同时把获取到的值写进数据库,所以我需要根据ip和db块查询数据库对应的集合数据:
List<SysPlcMlEntity> plcMlList = plcMlDao.getListByIpIdAndMlContentLike(ipId, dbNumber);
②循环集合plcMlList ,然后获取单个命令,截取后边的字节索引和位索引,然后根据字节索引和位索引读取每个命令得到对象ByteArrayParameter,添加到集合List中
③读取数据:根据字节数组和对象集合读取数据
List<ByteArrayParameter> byteList = serializer.extractParameter(db1ParameterList, datas);
④赋值,修改数据库
通过fori循环,将获取的值赋值给每个对象,最后修改数据。由于我们解析字节获取的值和我们查询数据库的值的长度是一样的,所以循环一个集合的长度就可以的。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习框架TensorFlow.NET环境搭建1(C#)

测试环境 visual studio 2017 window10 64位 测试步骤如下&#xff1a; 1 新建.net framework控制台项目&#xff0c;工程名称为TensorFlowNetDemo&#xff0c;.net framework的版本选4.7.2&#xff0c;如下图&#xff1a; 2 分别安装TensorFlow.NET包(先装)和SciSharp.…

QT+SQLite数据库配置和使用

一、简介 1.1 SQLite&#xff08;sql&#xff09;是一款开源轻量级的数据库软件&#xff0c;不需要server&#xff0c;可以集成在其他软件中&#xff0c;非常适合嵌入式系统。Qt5以上版本可以直接使用SQLite&#xff08;Qt自带驱动&#xff09;。 二、下载和配置 2.1 SQLite下载…

Docker Compose安装milvus向量数据库单机版-milvus基本操作

目录 安装Ubuntu 22.04 LTS在power shell启动milvus容器安装docker desktop下载yaml文件启动milvus容器Milvus管理软件Attu python连接milvus配置下载wget示例导入必要的模块和类与Milvus数据库建立连接创建名为"hello_milvus"的Milvus数据表插入数据创建索引基于向量…

7.spark sql编程

概述 spark 版本为 3.2.4&#xff0c;注意 RDD 转 DataFrame 的代码出现的问题及解决方案 本文目标如下&#xff1a; RDD ,Datasets,DataFrames 之间的区别入门 SparkSession创建 DataFramesDataFrame 操作编程方式运行 sql 查询创建 DatasetsDataFrames 与 RDDs 互相转换 使用…

动态规划(Dynamic Programming)—— Java解释

一、基本思想 动态规划(Dynamic Programming)算法的核心思想是&#xff1a;将大问题划分为小问题进行解决&#xff0c;并将子问题的求解结果存储起来避免重复求解&#xff0c;从而一步步获取最优解的处理算法。 动态规划算法与分治算法类似&#xff0c;其基本思想也是将待求解…

计算机毕设 基于大数据的社交平台数据爬虫舆情分析可视化系统

文章目录 0 前言1 课题背景2 实现效果**实现功能****可视化统计****web模块界面展示**3 LDA模型 4 情感分析方法**预处理**特征提取特征选择分类器选择实验 5 部分核心代码6 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕…

在 Python 中使用 Selenium 按文本查找元素

我们将通过示例介绍在Python中使用selenium通过文本查找元素的方法。 在 Python 中使用 Selenium 按文本查找元素 软件测试是检查应用程序是否满足用户需求的技术。 该技术有助于使应用程序成为无错误的应用程序。 软件测试可以手动完成&#xff0c;也可以通过某些软件完成。…

AI:60-基于深度学习的瓜果蔬菜分类识别

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

Unity地面交互效果——3、曲面细分基础知识

大家好&#xff0c;我是阿赵。   之前介绍了使用动态法线贴图混合的方式模拟轨迹的凹凸感&#xff0c;这次来讲一下更真实的凹凸感制作。不过在说这个内容之前&#xff0c;这一篇先要介绍一下曲面细分着色器(Tessellation Shader)的用法。 一、为什么要做曲面细分 之前通过法…

docker离线部署

docker离线部署 1、目的 在可以连接互联网的情况下&#xff0c;可以在线安装Docker《Linux下Docker安装部署》&#xff0c;如果遇到内网服务器就没有办法进行在线安装&#xff0c;那么需要使用离线安装的方法。 2、下载安装包 创建工作文件夹&#xff1a; mkdir /opt/dock…

window10 定时任务

window10 定时任务 1、背景2、目标3、思路4、实操4.1、设置定时任务4.2、配置策略4.3、验证 1、背景 项目上由于业务调试需要&#xff0c;开具了一台window10系统&#xff0c;此台window10为项目组公共使用&#xff0c;为防止误操作分配了不通的账号&#xff0c;日常使用各自账…

Redis-使用java代码操作Redis->java连接上redis,java操作redis的常见类型数据存储,redis中的项目应用

java连接上redisjava操作redis的常见类型数据存储redis中的项目应用 1.java连接上redis package com.zlj.ssm.redis;import redis.clients.jedis.Jedis;/*** author zlj* create 2023-11-03 19:27*/ public class Demo1 {public static void main(String[] args) { // …

「Verilog学习笔记」移位运算与乘法

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 1、在硬件中进行乘除法运算是比较消耗资源的一种方法&#xff0c;想要在不影响延迟并尽量减少资源消耗&#xff0c;必须从硬件的特点上进行设计。根据寄存器的原理&a…

宏转录组分析揭示不同土壤生境中氮循环基因的表达

发表期刊&#xff1a;msystems 发表时间&#xff1a;2023 影响因子&#xff1a;6.4 DOI: 10.1128/msystems.00315-23 01、研究背景 与空白土壤相比&#xff0c;植物根系和根际细菌之间的相互作用调节了氮&#xff08;N&#xff09;的循环过程&#xff0c;并创造了富含低分…

最近非常火的电子木鱼流量主小程序源码系统 带完整搭建教程

在当今数字化时代&#xff0c;人们对于休闲娱乐的需求越来越高。近年来&#xff0c;一种结合了传统文化和现代科技的新型休闲娱乐方式——电子木鱼&#xff0c;迅速在年轻人群中流行开来。电子木鱼流量主小程序源码系统的出现&#xff0c;为这种新型娱乐方式提供了更加便捷的途…

吴恩达《机器学习》4-1->4-5:多变量线性回归

一、引入多维特征 在多维特征中&#xff0c;我们考虑的不再是单一的特征&#xff0c;而是一组特征&#xff0c;例如房价模型中可能包括房间数、楼层等多个特征。这些特征将组成一个向量&#xff0c;表示为(&#x1d465;₁, &#x1d465;₂, . . . , &#x1d465;ₙ)&#x…

记一次pdjs时安装glob出现,npm ERR! code ETARGET和npm ERR! code ELIFECYCLE

如往常一样&#xff0c;我使用pdjs来编译proto文件&#xff0c;但出现了以下报错&#xff1a; 大致就是pdjs的util在尝试执行npm install glob^7.2.1 escodegen^1.13.0时出错了 尝试手动执行安装&#xff0c;escodegen被正确安装&#xff0c;但glob^7.2.1出错 npm ERR! code E…

陕西某小型水库雨水情测报及大坝安全监测项目案例

项目背景 根据《陕西省小型病险水库除险加固项目管理办法》、《陕西省小型水库雨水情测报和大坝安全监测设施建设与运行管理办法》的要求&#xff0c;为保障水库安全运行&#xff0c;对全省小型病险水库除险加固&#xff0c;建设完善雨水情测报、监测预警、防汛道路、通讯设备、…

安装anaconda时控制台conda-version报错

今天根据站内的一篇博客教程博客在此安装anaconda时&#xff0c;检查conda版本时报错如下&#xff1a; >>>>>>>>>>>> ERROR REPORT <<<<<<<<<<<< Traceback (most recent call last): File “D:\An…

办公套件全家桶 Office2019 mac中文版新功能

office 2019 mac是 Microsoft office 应用程序套件的最新版本。它包括流行的软件&#xff0c;例如 Microsoft Word、Excel、PowerPoint 和 Outlook&#xff0c;office 2019 比其前身有许多新功能和改进&#xff0c;包括增强的协作工具、与 OneDrive 和 SharePoint 等云服务的更…