489 lines
12 KiB
Markdown
489 lines
12 KiB
Markdown
# UPC Resent - 自动化控制设备指令转发系统
|
||
|
||
基于配置驱动的代码生成系统,支持 TCP 和 UDP 协议,监听端口接收外部指令,转换为 Modbus TCP/UDP 协议发送到控制设备(继电器/PLC等)。
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
upc_resent/
|
||
├── config/
|
||
│ └── devices.json # 设备配置文件(唯一需要修改的文件)
|
||
├── templates/ # 代码模板目录
|
||
│ ├── listener_tcp.py.tpl # TCP监听服务模板
|
||
│ ├── listener_udp.py.tpl # UDP监听服务模板
|
||
│ ├── crond_tcp.py.tpl # TCP保活检查模板
|
||
│ ├── crond_udp.py.tpl # UDP保活检查模板
|
||
│ ├── sender_tcp.py.tpl # TCP发送模块模板
|
||
│ ├── sender_udp.py.tpl # UDP发送模块模板
|
||
│ └── control.sh.tpl # 控制脚本模板
|
||
├── scripts/
|
||
│ └── generate.py # 代码生成器
|
||
├── bin/ # 生成的监听服务文件(自动生成)
|
||
│ ├── sender_tcp.py # TCP发送模块
|
||
│ ├── sender_udp.py # UDP发送模块
|
||
│ └── {device_id}.py # 各设备监听服务
|
||
├── crond/ # 生成的保活检查文件(自动生成)
|
||
├── log/ # 日志目录
|
||
├── control.sh # 服务控制脚本(自动生成)
|
||
├── crontab.txt # 定时任务配置(自动生成)
|
||
└── cutlog.sh # 日志清理脚本
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
### 1. 克隆仓库
|
||
|
||
```bash
|
||
git clone https://git.yuyujing.cn/zj/UPC-Resent/
|
||
cd UPC-Resent
|
||
```
|
||
|
||
### 2. 配置设备
|
||
|
||
编辑 `config/devices.json`:
|
||
|
||
```json
|
||
{
|
||
"global": {
|
||
"tms_server_ip": "192.168.8.9",
|
||
"python_path": "/usr/bin/python3",
|
||
"base_dir": "/opt/upc_resent"
|
||
},
|
||
"command_sets": {
|
||
"set1": {
|
||
"name": "标准8路控制",
|
||
"commands": {
|
||
"open1": "000100000008010F006400010001",
|
||
"close1": "000100000008010F006400010000",
|
||
"open2": "000100000008010F006500010001",
|
||
"close2": "000100000008010F006500010000"
|
||
}
|
||
}
|
||
},
|
||
"devices": [
|
||
{
|
||
"id": "dev1",
|
||
"name": "设备1-TCP",
|
||
"listen_protocol": "tcp", // 监听协议: tcp 或 udp
|
||
"device_protocol": "tcp", // 设备协议: tcp 或 udp
|
||
"command_set": "set1", // 使用的指令集
|
||
"upc_ip": "192.168.8.73",
|
||
"upc_port": 502,
|
||
"listen_port": 10079,
|
||
"enabled": true,
|
||
"keep_alive": true // TCP长连接模式(可选,默认false)
|
||
},
|
||
{
|
||
"id": "dev2",
|
||
"name": "设备2-UDP",
|
||
"listen_protocol": "udp",
|
||
"device_protocol": "udp",
|
||
"command_set": "set1",
|
||
"upc_ip": "192.168.8.200",
|
||
"upc_port": 502,
|
||
"listen_port": 10080,
|
||
"enabled": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 3. 生成代码
|
||
|
||
```bash
|
||
# 检查配置是否正确
|
||
python3 scripts/generate.py --check
|
||
|
||
# 生成代码
|
||
python3 scripts/generate.py
|
||
```
|
||
|
||
### 4. 部署与启动
|
||
|
||
```bash
|
||
# 查看服务状态
|
||
./control.sh status
|
||
|
||
# 启动所有服务
|
||
./control.sh start
|
||
|
||
# 停止所有服务
|
||
./control.sh stop
|
||
|
||
# 重启所有服务
|
||
./control.sh restart
|
||
|
||
# 配置定时任务(保活)
|
||
crontab crontab.txt
|
||
```
|
||
|
||
## 配置文件详解
|
||
|
||
### `config/devices.json`
|
||
|
||
#### 全局配置 (global)
|
||
|
||
| 参数 | 说明 | 示例 |
|
||
|-----|------|-----|
|
||
| `tms_server_ip` | 本机监听IP,接收外部指令 | `"192.168.8.9"` |
|
||
| `python_path` | Python3 解释器路径 | `"/usr/bin/python3"` |
|
||
| `base_dir` | 项目部署路径 | `"/opt/upc_resent"` |
|
||
|
||
#### 设备配置 (devices)
|
||
|
||
| 参数 | 说明 | 示例 |
|
||
|-----|------|-----|
|
||
| `id` | 设备唯一标识(用于文件名) | `"dev1"` |
|
||
| `name` | 设备名称(用于日志显示) | `"设备1-TCP"` |
|
||
| `listen_protocol` | 客户端连接协议:`tcp` 或 `udp` | `"tcp"` / `"udp"` |
|
||
| `device_protocol` | 设备通信协议:`tcp` 或 `udp` | `"tcp"` / `"udp"` |
|
||
| `command_set` | 使用的指令集ID | `"set1"` |
|
||
| `upc_ip` | 控制设备的IP地址 | `"192.168.8.73"` |
|
||
| `upc_port` | 控制设备的端口(Modbus默认502) | `502` |
|
||
| `listen_port` | 本机监听端口(每个设备需不同) | `10079` |
|
||
| `enabled` | 是否启用该设备 | `true` / `false` |
|
||
| `keep_alive` | **TCP 专用** 是否保持连接(长连接模式) | `true` / `false` (默认)
|
||
|
||
**协议组合说明**:
|
||
- `listen_protocol`: 主机监听客户端连接的协议(客户端 -> 主机)
|
||
- `device_protocol`: 主机与设备通信的协议(主机 -> 设备)
|
||
- 支持任意组合:TCP->TCP、UDP->UDP、TCP->UDP、UDP->TCP
|
||
|
||
**配置示例**:
|
||
|
||
```json
|
||
// 场景1: 客户端TCP -> 主机TCP -> 设备TCP
|
||
{
|
||
"id": "dev1",
|
||
"name": "设备1-纯TCP",
|
||
"listen_protocol": "tcp",
|
||
"device_protocol": "tcp",
|
||
"upc_ip": "192.168.8.73",
|
||
"upc_port": 502,
|
||
"listen_port": 10079
|
||
}
|
||
|
||
// 场景2: 客户端TCP -> 主机UDP -> 设备UDP(协议转换)
|
||
{
|
||
"id": "dev2",
|
||
"name": "设备2-TCP转UDP",
|
||
"listen_protocol": "tcp",
|
||
"device_protocol": "udp",
|
||
"upc_ip": "192.168.8.200",
|
||
"upc_port": 502,
|
||
"listen_port": 10080
|
||
}
|
||
|
||
// 场景3: 客户端UDP -> 主机TCP -> 设备TCP(协议转换)
|
||
{
|
||
"id": "dev3",
|
||
"name": "设备3-UDP转TCP",
|
||
"listen_protocol": "udp",
|
||
"device_protocol": "tcp",
|
||
"upc_ip": "192.168.8.201",
|
||
"upc_port": 502,
|
||
"listen_port": 10081
|
||
}
|
||
```
|
||
|
||
#### 指令集定义 (command_sets)
|
||
|
||
支持为不同设备配置不同的指令集:
|
||
|
||
```json
|
||
{
|
||
"command_sets": {
|
||
"set1": {
|
||
"name": "标准8路控制",
|
||
"commands": {
|
||
"open1": "000100000008010F006400010001",
|
||
"close1": "000100000008010F006400010000",
|
||
"open2": "000100000008010F006500010001",
|
||
"close2": "000100000008010F006500010000"
|
||
}
|
||
},
|
||
"set2": {
|
||
"name": "4路精简控制",
|
||
"commands": {
|
||
"open1": "000100000008010F006400010001",
|
||
"close1": "000100000008010F006400010000",
|
||
"openall": "000100000008010F00640004000F",
|
||
"closeall": "000100000008010F006400040000"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
设备通过 `command_set` 字段指定使用的指令集:
|
||
|
||
```json
|
||
{
|
||
"id": "dev1",
|
||
"command_set": "set1"
|
||
}
|
||
```
|
||
|
||
#### 指令映射 (mappings)
|
||
|
||
```json
|
||
{
|
||
"mappings": {
|
||
"open": "openall4",
|
||
"close": "closeall4",
|
||
"guanggao-guan": "closeall4"
|
||
}
|
||
}
|
||
```
|
||
|
||
## TCP vs UDP 差异
|
||
|
||
| 特性 | TCP | UDP |
|
||
|-----|-----|-----|
|
||
| 连接方式 | 面向连接 | 无连接 |
|
||
| 可靠性 | 可靠传输 | 尽力传输 |
|
||
| 响应 | 有确认响应 | 可选响应(可能超时) |
|
||
| 适用场景 | 可靠性要求高 | 实时性要求高 |
|
||
| 保活检查 | 端口连通性检查 | 进程状态检查 |
|
||
|
||
## 如何适配自己的设备
|
||
|
||
### 场景1:添加 TCP 设备(客户端TCP -> 主机TCP -> 设备TCP)
|
||
|
||
```json
|
||
{
|
||
"devices": [
|
||
{
|
||
"id": "dev_tcp",
|
||
"name": "TCP设备",
|
||
"listen_protocol": "tcp",
|
||
"device_protocol": "tcp",
|
||
"upc_ip": "192.168.1.100",
|
||
"upc_port": 502,
|
||
"listen_port": 10081,
|
||
"enabled": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 场景2:添加 UDP 设备(客户端UDP -> 主机UDP -> 设备UDP)
|
||
|
||
```json
|
||
{
|
||
"devices": [
|
||
{
|
||
"id": "dev_udp",
|
||
"name": "UDP设备",
|
||
"listen_protocol": "udp",
|
||
"device_protocol": "udp",
|
||
"upc_ip": "192.168.1.200",
|
||
"upc_port": 502,
|
||
"listen_port": 10082,
|
||
"enabled": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 场景3:协议转换(客户端TCP -> 主机UDP -> 设备UDP)
|
||
|
||
```json
|
||
{
|
||
"devices": [
|
||
{
|
||
"id": "dev_tcp2udp",
|
||
"name": "TCP转UDP设备",
|
||
"listen_protocol": "tcp",
|
||
"device_protocol": "udp",
|
||
"upc_ip": "192.168.1.201",
|
||
"upc_port": 502,
|
||
"listen_port": 10083,
|
||
"enabled": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 场景4:协议转换(客户端UDP -> 主机TCP -> 设备TCP)
|
||
|
||
```json
|
||
{
|
||
"devices": [
|
||
{
|
||
"id": "dev_udp2tcp",
|
||
"name": "UDP转TCP设备",
|
||
"listen_protocol": "udp",
|
||
"device_protocol": "tcp",
|
||
"upc_ip": "192.168.1.202",
|
||
"upc_port": 502,
|
||
"listen_port": 10084,
|
||
"enabled": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 场景5:不同设备使用不同指令集
|
||
|
||
```json
|
||
{
|
||
"command_sets": {
|
||
"set1": {
|
||
"name": "8路控制",
|
||
"commands": {
|
||
"open1": "000100000008010F006400010001",
|
||
"close1": "000100000008010F006400010000",
|
||
"open8": "000100000008010F006B00010001",
|
||
"close8": "000100000008010F006B00010000"
|
||
}
|
||
},
|
||
"set2": {
|
||
"name": "4路控制",
|
||
"commands": {
|
||
"open1": "000100000008010F006400010001",
|
||
"close1": "000100000008010F006400010000",
|
||
"openall": "000100000008010F00640004000F",
|
||
"closeall": "000100000008010F006400040000"
|
||
}
|
||
}
|
||
},
|
||
"devices": [
|
||
{
|
||
"id": "dev1",
|
||
"name": "8路设备",
|
||
"command_set": "set1",
|
||
"upc_ip": "192.168.1.100"
|
||
},
|
||
{
|
||
"id": "dev2",
|
||
"name": "4路设备",
|
||
"command_set": "set2",
|
||
"upc_ip": "192.168.1.200"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 场景6:禁用某个设备
|
||
|
||
```json
|
||
{
|
||
"devices": [
|
||
{
|
||
"id": "dev2",
|
||
"enabled": false
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## 测试指令发送
|
||
|
||
### TCP 设备测试
|
||
|
||
```bash
|
||
# 向TCP设备发送开灯指令
|
||
echo "open1" | nc 192.168.8.9 10079
|
||
|
||
# 向TCP设备发送全关指令
|
||
echo "close" | nc 192.168.8.9 10079
|
||
```
|
||
|
||
### UDP 设备测试
|
||
|
||
```bash
|
||
# 向UDP设备发送开灯指令
|
||
echo "open1" | nc -u 192.168.8.9 10080
|
||
|
||
# 向UDP设备发送全关指令
|
||
echo "close" | nc -u 192.168.8.9 10080
|
||
|
||
# 使用 socat 测试 UDP
|
||
echo "open1" | socat - UDP:192.168.8.9:10080
|
||
```
|
||
|
||
## 支持的指令列表
|
||
|
||
| 外部指令 | 内部指令 | 功能 |
|
||
|---------|---------|------|
|
||
| `open` | `openall4` | 1-4路全开 |
|
||
| `close` | `closeall4` | 1-4路全关 |
|
||
| `open1`~`open8` | `open1`~`open8` | 第N路开 |
|
||
| `close1`~`close8` | `close1`~`close8` | 第N路关 |
|
||
| `guanggao-guan` | `closeall4` | 广告关闭(全关) |
|
||
|
||
## Modbus 指令格式
|
||
|
||
本项目支持 Modbus TCP/UDP 协议,指令为16进制字符串:
|
||
|
||
```
|
||
示例:000100000008010F006400010001
|
||
│ │ │ │ │ │ │ │ │ │ │
|
||
│ │ │ │ │ │ │ │ │ │ └── 数据值 (01=开, 00=关)
|
||
│ │ │ │ │ │ │ │ │ └──── 寄存器数量
|
||
│ │ │ │ │ │ │ │ └─────── 起始地址 (64=100)
|
||
│ │ │ │ │ │ │ └────────── 功能码 (0F=写多个线圈)
|
||
│ │ │ │ │ │ └──────────── 单元标识
|
||
│ │ │ │ └───────────────── 协议标识
|
||
│ │ │ └─────────────────── 长度
|
||
│ └─────────────────────── 事务标识
|
||
└────────────────────────── 事务标识
|
||
```
|
||
|
||
## 代码生成器用法
|
||
|
||
```bash
|
||
# 检查配置是否正确
|
||
python3 scripts/generate.py --check
|
||
|
||
# 生成代码
|
||
python3 scripts/generate.py
|
||
|
||
# 查看帮助
|
||
python3 scripts/generate.py --help
|
||
```
|
||
|
||
## 服务控制脚本
|
||
|
||
`control.sh` 提供以下命令:
|
||
|
||
| 命令 | 说明 |
|
||
|-----|------|
|
||
| `start` | 启动所有服务 |
|
||
| `stop` | 停止所有服务 |
|
||
| `restart` | 重启所有服务 |
|
||
| `status` | 查看服务运行状态 |
|
||
|
||
示例:
|
||
|
||
```bash
|
||
./control.sh status
|
||
./control.sh start
|
||
./control.sh stop
|
||
./control.sh restart
|
||
```
|
||
|
||
## 日志文件
|
||
|
||
| 文件 | 说明 |
|
||
|-----|------|
|
||
| `log/{device_id}.log` | 设备监听服务的日志 |
|
||
| `log/crond-{device_id}.log` | 保活检查的日志 |
|
||
|
||
日志自动轮转:每天清理7天前的日志。
|
||
|
||
## 注意事项
|
||
|
||
1. **不要直接修改** `bin/`、`crond/` 和 `control.sh`,这些文件是自动生成的,重新生成时会覆盖。
|
||
|
||
2. **修改配置后必须重新运行** `python3 scripts/generate.py` 才能生效。
|
||
|
||
3. 确保每个设备的 `listen_port` 不冲突,无论 TCP 还是 UDP,端口都不能重复。
|
||
|
||
4. UDP 是无连接协议,设备可能不会返回响应,这是正常现象。
|
||
|
||
5. 部署到生产环境前,请将 `base_dir` 修改为实际的部署路径(如 `/opt/upc_resent`)。
|
||
|
||
6. 控制脚本使用 `pgrep` 来查找进程,确保系统中没有同名脚本冲突。
|