技术开发文档:MES 系统与西门子 PLC 通信软件集成方案

文档信息

项目 内容
文档版本 V1.0
编写日期 2025-12-05
适用范围 MES 系统开发、西门子 PLC 通信软件开发
开发语言 MES:Java(Spring Boot);PLC 通信软件:C#(.NET Framework)
通信协议 HTTP(RESTful API)
PLC 通信方式 S7.NET(西门子 S7 系列 PLC 专用通信库)

一、总体架构设计

1.1 系统整体流程

  1. MES 系统根据业务需求,向 PLC 通信软件发送包含 "PLC 地址、数据点位、采集指令" 的 HTTP 请求;
  2. PLC 通信软件接收请求后,解析指令并通过S7.NET库连接西门子 PLC,抓取指定点位的数据;
  3. PLC 通信软件将采集到的数据封装为 JSON 格式的 HTTP 响应,返回至 MES 系统;
  4. MES 系统接收响应后,解析数据并进行存储、展示、业务逻辑处理。

1.2 系统架构图

plaintext

复制代码
┌─────────────┐         HTTP请求          ┌─────────────────────┐         S7协议         ┌─────────────┐
│  MES系统    │ ────采集指令/参数─────→ │ PLC通信软件(上位机)│ ────数据采集请求────→ │ 西门子PLC   │
│ (Spring Boot)│ ←────采集结果/数据────── │ (.NET Framework)    │ ←────PLC实时数据──── │ (S7-1200/1500)│
└─────────────┘         HTTP响应          └─────────────────────┘                       └─────────────┘

二、MES 系统技术开发文档

2.1 功能需求

功能模块 详细需求
指令发送模块 1. 支持配置 PLC 通信软件的 IP / 端口;2. 支持自定义采集指令(PLC 型号、IP、数据点位、采集频率);3. 发送 HTTP POST 请求至 PLC 通信软件;4. 记录请求日志(请求时间、指令内容、状态)。
响应接收模块 1. 接收 PLC 通信软件的 JSON 格式响应;2. 解析响应数据(点位名称、数值、采集时间、PLC 状态);3. 校验数据完整性,异常数据标记并告警;4. 存储解析后的数据至 MES 数据库。
数据管理模块 1. 支持 PLC 采集数据的查询(按时间、PLC 点位、产线);2. 数据可视化展示(实时监控面板、历史趋势图);3. 异常数据告警(阈值配置、短信 / 邮件通知)。
系统配置模块 1. PLC 通信软件地址配置;2. PLC 点位映射配置(业务字段与 PLC 点位对应);3. 采集频率、超时时间配置;4. 权限管理(不同角色操作权限)。

2.2 技术选型

模块 技术栈 说明
后端框架 Spring Boot 2.7.x 快速开发 RESTful API,集成 Spring MVC、Spring Data JPA
通信方式 HTTP/HTTPS 与 PLC 通信软件的标准化通信,支持 JSON 数据传输
数据库 MySQL 8.0 存储 MES 业务数据、PLC 采集数据、系统配置、日志
缓存 Redis 6.x 缓存高频访问的 PLC 点位配置、实时数据
前端 Vue 3 + Element Plus 数据展示、指令配置、系统监控界面
日志 Logback + ELK 系统日志采集、分析、检索
部署 Docker + Kubernetes 容器化部署,支持集群扩展

2.3 核心接口设计

2.3.1 采集指令发送接口
  • 接口地址:/api/plc/collect

  • 请求方式:POST

  • 请求头:Content-Type: application/json

  • 请求参数:

    参数名 类型 必填 说明
    plcId String PLC 唯一标识(自定义)
    plcIp String PLC 的 IP 地址
    plcModel String PLC 型号(如 S7-1200、S7-1500)
    dataPoints Array 待采集的点位列表
    dataPoints[].pointName String 点位名称(如 DB1.DBW0)
    dataPoints[].dataType String 数据类型(int、float、bool、string)
    timeout Integer 采集超时时间(默认 5000ms)
  • 请求示例:

json

复制代码
{
  "plcId": "PLC_001",
  "plcIp": "192.168.1.100",
  "plcModel": "S7-1500",
  "dataPoints": [
    {
      "pointName": "DB1.DBW0",
      "dataType": "int"
    },
    {
      "pointName": "DB1.DBD2",
      "dataType": "float"
    },
    {
      "pointName": "DB1.DBX5.0",
      "dataType": "bool"
    }
  ],
  "timeout": 5000
}
  • 响应参数:

    参数名 类型 说明
    code Integer 响应码(200 = 成功,500 = 失败)
    msg String 响应信息
    requestId String 请求唯一标识
    data Object 采集结果(异步采集时为 null,同步返回时为数据)
  • 响应示例(同步):

json

复制代码
{
  "code": 200,
  "msg": "采集成功",
  "requestId": "REQ_20251205100001",
  "data": {
    "plcId": "PLC_001",
    "collectTime": "2025-12-05 10:00:05",
    "dataPoints": [
      {
        "pointName": "DB1.DBW0",
        "dataType": "int",
        "value": 100,
        "status": "success"
      },
      {
        "pointName": "DB1.DBD2",
        "dataType": "float",
        "value": 25.5,
        "status": "success"
      },
      {
        "pointName": "DB1.DBX5.0",
        "dataType": "bool",
        "value": true,
        "status": "success"
      }
    ],
    "plcStatus": "online"
  }
}
2.3.2 采集结果查询接口(异步场景)
  • 接口地址:/api/plc/collect/result/{requestId}
  • 请求方式:GET
  • 响应参数:同上述同步响应示例

2.4 数据库设计(核心表)

2.4.1 PLC 配置表(plc_config)
字段名 类型 主键 说明
id BIGINT 自增 ID
plc_id VARCHAR(50) PLC 唯一标识
plc_ip VARCHAR(20) PLC IP 地址
plc_model VARCHAR(20) PLC 型号
communication_software_ip VARCHAR(20) PLC 通信软件 IP
communication_software_port INT PLC 通信软件端口
create_time DATETIME 创建时间
update_time DATETIME 更新时间
2.4.2 PLC 采集数据表(plc_collect_data)
字段名 类型 主键 说明
id BIGINT 自增 ID
request_id VARCHAR(50) 请求唯一标识
plc_id VARCHAR(50) PLC 唯一标识
point_name VARCHAR(50) 点位名称
data_type VARCHAR(20) 数据类型
value VARCHAR(100) 采集值(统一存储为字符串)
collect_time DATETIME 采集时间
status VARCHAR(20) 采集状态(success/fail)
error_msg VARCHAR(200) 错误信息(失败时填充)
2.4.3 请求日志表(plc_request_log)
字段名 类型 主键 说明
id BIGINT 自增 ID
request_id VARCHAR(50) 请求唯一标识
request_content TEXT 请求内容(JSON)
response_content TEXT 响应内容(JSON)
request_time DATETIME 请求时间
response_time DATETIME 响应时间
status VARCHAR(20) 请求状态(success/fail)

2.5 核心代码示例(Java)

2.5.1 采集指令发送服务

java

运行

复制代码
@Service
@Slf4j
public class PlcCollectService {

    @Autowired
    private RestTemplate restTemplate;

    @Value("${plc.communication.software.url}")
    private String plcSoftwareUrl;

    @Autowired
    private PlcRequestLogMapper requestLogMapper;

    /**
     * 发送采集指令至PLC通信软件
     * @param collectRequest 采集请求参数
     * @return 采集响应结果
     */
    public PlcCollectResponse sendCollectRequest(PlcCollectRequest collectRequest) {
        // 生成请求ID
        String requestId = "REQ_" + System.currentTimeMillis();
        collectRequest.setRequestId(requestId);

        PlcCollectResponse response = null;
        try {
            // 记录请求日志(请求中)
            PlcRequestLog log = new PlcRequestLog();
            log.setRequestId(requestId);
            log.setRequestContent(JSON.toJSONString(collectRequest));
            log.setRequestTime(new Date());
            log.setStatus("processing");
            requestLogMapper.insert(log);

            // 发送HTTP请求
            ResponseEntity<PlcCollectResponse> responseEntity = restTemplate.postForEntity(
                    plcSoftwareUrl + "/api/plc/collect",
                    collectRequest,
                    PlcCollectResponse.class
            );

            // 处理响应
            if (responseEntity.getStatusCode().is2xxSuccessful()) {
                response = responseEntity.getBody();
                log.setResponseContent(JSON.toJSONString(response));
                log.setResponseTime(new Date());
                log.setStatus("success");
            } else {
                log.setStatus("fail");
                log.setResponseTime(new Date());
                log.setErrorMsg("PLC通信软件返回非200状态码:" + responseEntity.getStatusCode());
                throw new BusinessException("采集请求失败,PLC通信软件返回异常状态码");
            }
        } catch (Exception e) {
            log.error("发送采集指令失败,requestId={}", requestId, e);
            response = new PlcCollectResponse();
            response.setCode(500);
            response.setMsg("采集请求失败:" + e.getMessage());
            response.setRequestId(requestId);
            // 更新日志
            PlcRequestLog log = requestLogMapper.selectByRequestId(requestId);
            if (log != null) {
                log.setStatus("fail");
                log.setResponseTime(new Date());
                log.setErrorMsg(e.getMessage());
                requestLogMapper.updateById(log);
            }
        }
        return response;
    }
}
2.5.2 控制器层

java

运行

复制代码
@RestController
@RequestMapping("/api/plc")
@RequiredArgsConstructor
public class PlcCollectController {

    private final PlcCollectService plcCollectService;

    @PostMapping("/collect")
    public Result<PlcCollectResponse> collect(@RequestBody @Valid PlcCollectRequest request) {
        PlcCollectResponse response = plcCollectService.sendCollectRequest(request);
        return Result.success(response);
    }

    @GetMapping("/collect/result/{requestId}")
    public Result<PlcCollectResponse> getCollectResult(@PathVariable String requestId) {
        PlcCollectResponse response = plcCollectService.getCollectResult(requestId);
        return Result.success(response);
    }
}

2.6 部署与运维

  1. 环境要求:JDK 11+、MySQL 8.0+、Redis 6.x+;
  2. 配置文件:application.yml 中配置 PLC 通信软件地址、数据库连接、Redis 连接;
  3. 容器化:编写 Dockerfile,打包为镜像,通过 K8s 部署;
  4. 监控:集成 Prometheus + Grafana,监控接口调用量、响应时间、异常率;
  5. 备份:MySQL 数据每日定时备份,日志保留 30 天。

三、上位机西门子 PLC 通信软件技术开发文档

3.1 功能需求

功能模块 详细需求
HTTP 接口接收模块 1. 监听指定端口的 HTTP POST 请求;2. 解析 MES 发送的采集指令(PLC IP、点位、数据类型);3. 校验请求参数合法性,非法请求返回错误响应;4. 记录请求日志(请求时间、指令内容、MES IP)。
PLC 数据采集模块 1. 通过S7.NET库连接西门子 PLC;2. 根据指令抓取指定点位的数据,支持 int/float/bool/string 类型;3. 处理 PLC 连接异常(超时、离线),返回错误信息;4. 采集完成后断开 PLC 连接,释放资源。
响应封装模块 1. 将采集到的数据封装为 JSON 格式的 HTTP 响应;2. 响应包含采集值、采集时间、PLC 状态、点位状态;3. 异常场景返回错误码和错误描述。
日志管理模块 1. 记录 PLC 连接日志、数据采集日志、HTTP 请求日志;2. 日志支持按时间、PLC ID、请求 ID 检索;3. 日志文件自动分割(按天),保留 30 天。
系统配置模块 1. 配置 HTTP 监听端口、PLC 连接超时时间;2. 配置日志存储路径、日志级别;3. 支持开机自启动。

3.2 技术选型

模块 技术栈 说明
开发框架 .NET Framework 4.8 兼容 Windows 系统,成熟稳定,支持S7.NET
HTTP 服务 ASP.NET Web API 轻量级 HTTP 接口开发框架,支持 RESTful API
PLC 通信 S7.NET(NuGet 包) 西门子 S7 系列 PLC 专用通信库,支持 S7-1200/1500/300/400
日志 log4net .NET 平台主流日志框架,支持文件、控制台输出
配置管理 App.config 系统配置存储,支持动态加载
部署 Windows 服务 以 Windows 服务形式运行,后台常驻,开机自启
调试工具 Visual Studio 2022 开发、调试、打包一体化

3.3 核心接口设计

3.3.1 采集指令接收接口(对外)
  • 接口地址:/api/plc/collect
  • 请求方式:POST
  • 请求参数:同 MES 系统的采集指令发送接口请求参数;
  • 响应参数:同 MES 系统的采集指令发送接口响应参数。

3.4 核心代码示例(C#)

3.4.1 PLC 数据采集服务

csharp

运行

复制代码
using System;
using System.Collections.Generic;
using System.Net;
using S7.Net;

namespace PlcCommunicationSoftware.Service
{
    public class PlcDataCollectService
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(PlcDataCollectService));

        /// <summary>
        /// 采集PLC数据
        /// </summary>
        /// <param name="plcIp">PLC IP地址</param>
        /// <param name="plcModel">PLC型号</param>
        /// <param name="dataPoints">采集点位列表</param>
        /// <param name="timeout">超时时间(ms)</param>
        /// <returns>采集结果</returns>
        public PlcCollectResult CollectPlcData(string plcIp, string plcModel, List<DataPoint> dataPoints, int timeout)
        {
            PlcCollectResult result = new PlcCollectResult();
            result.PlcId = Guid.NewGuid().ToString("N");
            result.CollectTime = DateTime.Now;
            result.DataPoints = new List<DataPointResult>();
            Plc plc = null;

            try
            {
                // 初始化PLC连接
                plc = CreatePlcInstance(plcModel, plcIp);
                if (plc == null)
                {
                    result.PlcStatus = "offline";
                    throw new Exception("不支持的PLC型号:" + plcModel);
                }

                // 设置超时时间
                plc.ConnectTimeout = timeout;

                // 连接PLC
                var connectResult = plc.Open();
                if (!connectResult)
                {
                    result.PlcStatus = "offline";
                    throw new Exception("PLC连接失败,IP:" + plcIp);
                }
                result.PlcStatus = "online";

                // 遍历采集点位
                foreach (var point in dataPoints)
                {
                    DataPointResult pointResult = new DataPointResult();
                    pointResult.PointName = point.PointName;
                    pointResult.DataType = point.DataType;
                    try
                    {
                        // 读取点位数据
                        object value = ReadPlcData(plc, point.PointName, point.DataType);
                        pointResult.Value = value;
                        pointResult.Status = "success";
                        log.Info($"采集点位{point.PointName}成功,值:{value}");
                    }
                    catch (Exception ex)
                    {
                        pointResult.Status = "fail";
                        pointResult.ErrorMsg = ex.Message;
                        log.Error($"采集点位{point.PointName}失败", ex);
                    }
                    result.DataPoints.Add(pointResult);
                }
            }
            catch (Exception ex)
            {
                result.Code = 500;
                result.Msg = ex.Message;
                log.Error("PLC数据采集失败", ex);
            }
            finally
            {
                // 关闭PLC连接
                plc?.Close();
                plc?.Dispose();
            }
            return result;
        }

        /// <summary>
        /// 创建PLC实例
        /// </summary>
        private Plc CreatePlcInstance(string plcModel, string plcIp)
        {
            PlcType plcType;
            switch (plcModel.ToUpper())
            {
                case "S7-1200":
                    plcType = PlcType.S71200;
                    break;
                case "S7-1500":
                    plcType = PlcType.S71500;
                    break;
                case "S7-300":
                    plcType = PlcType.S7300;
                    break;
                case "S7-400":
                    plcType = PlcType.S7400;
                    break;
                default:
                    return null;
            }
            return new Plc(plcType, plcIp, 0, 1);
        }

        /// <summary>
        /// 读取PLC点位数据
        /// </summary>
        private object ReadPlcData(Plc plc, string pointName, string dataType)
        {
            switch (dataType.ToLower())
            {
                case "int":
                    return plc.ReadInt16(pointName);
                case "float":
                    return plc.ReadFloat(pointName);
                case "bool":
                    return plc.ReadBit(pointName);
                case "string":
                    return plc.ReadString(pointName, 256);
                default:
                    throw new Exception("不支持的数据类型:" + dataType);
            }
        }
    }
}
3.4.2 HTTP 接口控制器

csharp

运行

复制代码
using System.Web.Http;

namespace PlcCommunicationSoftware.Controllers
{
    [RoutePrefix("api/plc")]
    public class PlcController : ApiController
    {
        private readonly PlcDataCollectService _collectService = new PlcDataCollectService();
        private static readonly ILog log = LogManager.GetLogger(typeof(PlcController));

        [HttpPost]
        [Route("collect")]
        public IHttpActionResult Collect([FromBody] PlcCollectRequest request)
        {
            // 参数校验
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            log.Info($"接收采集请求,requestId={request.RequestId},plcIp={request.PlcIp}");

            // 采集PLC数据
            var result = _collectService.CollectPlcData(
                request.PlcIp,
                request.PlcModel,
                request.DataPoints,
                request.Timeout ?? 5000
            );

            // 封装响应
            var response = new PlcCollectResponse
            {
                Code = result.Code ?? 200,
                Msg = result.Msg ?? "采集成功",
                RequestId = request.RequestId,
                Data = result
            };

            return Ok(response);
        }
    }
}

3.5 部署与运维

  1. 环境要求:Windows Server 2016+、.NET Framework 4.8 运行时;
  2. 部署方式:
    • 将编译后的程序打包为 Windows 服务;
    • 通过 InstallUtil 工具安装服务,设置为开机自启;
  3. 配置文件:App.config 中配置 HTTP 监听端口、PLC 连接超时时间、日志路径;
  4. 日志管理:日志文件默认存储在C:\PlcCommunicationSoftware\Logs,按天分割;
  5. 监控:通过 Windows 事件查看器监控服务运行状态,异常时触发邮件告警;
  6. 调试:通过 Visual Studio 远程调试,或查看日志文件定位问题。

四、通信交互规范

4.1 数据格式

  • 所有 HTTP 请求 / 响应均采用 JSON 格式;
  • 字符编码:UTF-8;
  • 时间格式:yyyy-MM-dd HH:mm:ss(东八区)。

4.2 错误码定义

错误码 说明 归属系统
200 操作成功 MES/PLC 通信软件
400 请求参数错误 PLC 通信软件
404 PLC 点位不存在 PLC 通信软件
500 系统内部错误 MES/PLC 通信软件
501 PLC 连接失败 PLC 通信软件
502 PLC 通信软件无响应 MES
503 数据采集超时 PLC 通信软件

4.3 安全规范

  1. HTTP 通信建议使用 HTTPS 加密;
  2. PLC 通信软件仅开放指定 MES 服务器的 IP 访问权限;
  3. 接口请求添加签名验证(如 MD5 + 时间戳),防止非法请求;
  4. PLC 点位配置权限严格管控,仅授权人员可修改。

五、测试方案

5.1 MES 系统测试

  1. 功能测试:指令发送、响应接收、数据存储、查询展示;
  2. 性能测试:并发发送 100 个采集请求,测试响应时间、成功率;
  3. 异常测试:PLC 通信软件离线、参数错误、采集超时等场景;
  4. 兼容性测试:不同浏览器、不同分辨率下前端界面展示。

5.2 PLC 通信软件测试

  1. 功能测试:HTTP 接口接收、PLC 连接、数据采集、响应封装;
  2. 兼容性测试:支持 S7-1200/1500/300/400 等型号 PLC;
  3. 稳定性测试:7*24 小时持续运行,模拟高频采集请求;
  4. 异常测试:PLC 断电、网络中断、点位不存在等场景。

5.3 集成测试

  1. 端到端测试:MES 发送指令→PLC 通信软件采集→MES 接收数据→存储展示;
  2. 数据一致性测试:对比 PLC 实际值与 MES 存储值;
  3. 压力测试:模拟 100 个 MES 并发请求,测试整体响应效率。

六、附录

6.1 西门子 PLC 点位格式说明

数据类型 点位格式示例 说明
整数(int) DB1.DBW0 数据块 1,字地址 0
浮点数(float) DB1.DBD2 数据块 1,双字地址 2
布尔值(bool) DB1.DBX5.0 数据块 1,字节 5,位 0
字符串(string) DB1.DBB10 数据块 1,字节 10 开始的字符串

6.2 依赖库版本

库名称 版本 用途
S7.NET 0.15.0 PLC 通信
log4net 2.0.15 日志记录
Newtonsoft.Json 13.0.3 JSON 序列化 / 反序列化
Spring Boot 2.7.10 MES 后端框架
MyBatis-Plus 3.5.3.1 数据库操作
相关推荐
00后程序员张3 小时前
HTTPS Everywhere 时代的抓包挑战,从加密流量解析到底层数据流捕获的全流程方案
网络协议·http·ios·小程序·https·uni-app·iphone
地球驾驶员4 小时前
NX二次开发C#----C#和C++的二次开发程序如何签名?
c#
小码编匠5 小时前
C# 实现网络文件传输:打造稳定可靠的工业级工具
后端·c#·.net
MM_MS6 小时前
SQL Server数据库和Visual Studio (C#)联合编程
开发语言·数据库·sqlserver·c#·visual studio
张人玉6 小时前
MES 系统、上位机(西门子 PLC 对接)数据交互技术与使用文档
plc·mes系统
c#上位机9 小时前
halcon计算区域骨架
图像处理·人工智能·计算机视觉·c#·halcon
曹牧10 小时前
C#:Dictionary类型数组
java·开发语言·c#
2501_9159214310 小时前
Bundle Id 创建与管理的工程化方法,一次团队多项目协作中的流程重构
服务器·ios·小程序·重构·https·uni-app·iphone
GeekyGuru11 小时前
C#:游戏开发的高效利器
开发语言·c#