This commit is contained in:
zj
2026-03-22 17:17:44 +08:00
commit b64c39ecbd
29 changed files with 2720 additions and 0 deletions

295
README.md Normal file
View File

@@ -0,0 +1,295 @@
# 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发送模块模板
├── scripts/
│ └── generate.py # 代码生成器
├── bin/ # 生成的监听服务文件(自动生成)
│ ├── sender_tcp.py # TCP发送模块
│ ├── sender_udp.py # UDP发送模块
│ └── {device_id}.py # 各设备监听服务
├── crond/ # 生成的保活检查文件(自动生成)
├── log/ # 日志目录
├── start.sh # 启动脚本(自动生成)
├── crontab.txt # 定时任务配置(自动生成)
└── cutlog.sh # 日志清理脚本
```
## 快速开始
### 1. 配置设备
编辑 `config/devices.json`
```json
{
"global": {
"tms_server_ip": "192.168.8.9",
"python_path": "/usr/bin/python3",
"base_dir": "/opt/upc_resent"
},
"devices": [
{
"id": "dev1",
"name": "设备1-TCP",
"protocol": "tcp", // 协议类型: tcp 或 udp
"upc_ip": "192.168.8.73",
"upc_port": 502,
"listen_port": 10079,
"enabled": true
},
{
"id": "dev2",
"name": "设备2-UDP",
"protocol": "udp", // 使用UDP协议
"upc_ip": "192.168.8.200",
"upc_port": 502,
"listen_port": 10080,
"enabled": true
}
]
}
```
### 2. 生成代码
```bash
# 检查配置是否正确
python3 scripts/generate.py --check
# 生成代码
python3 scripts/generate.py
```
### 3. 部署与启动
```bash
# 启动所有服务
./start.sh
# 配置定时任务(保活)
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"` |
| `protocol` | 协议类型:`tcp``udp` | `"tcp"` / `"udp"` |
| `upc_ip` | 控制设备的IP地址 | `"192.168.8.73"` |
| `upc_port` | 控制设备的端口Modbus默认502 | `502` |
| `listen_port` | 本机监听端口(每个设备需不同) | `10079` |
| `enabled` | 是否启用该设备 | `true` / `false` |
#### 指令定义 (commands)
```json
{
"commands": {
"open1": "000100000008010F006400010001",
"close1": "000100000008010F006400010000",
"openall4": "000100000008010F00640004000F",
"closeall4": "000100000008010F006400040000"
}
}
```
格式:指令名 -> 16进制字符串
#### 指令映射 (mappings)
```json
{
"mappings": {
"open": "openall4",
"close": "closeall4",
"guanggao-guan": "closeall4"
}
}
```
## TCP vs UDP 差异
| 特性 | TCP | UDP |
|-----|-----|-----|
| 连接方式 | 面向连接 | 无连接 |
| 可靠性 | 可靠传输 | 尽力传输 |
| 响应 | 有确认响应 | 可选响应(可能超时) |
| 适用场景 | 可靠性要求高 | 实时性要求高 |
| 保活检查 | 端口连通性检查 | 进程状态检查 |
## 如何适配自己的设备
### 场景1添加 TCP 设备
```json
{
"devices": [
{
"id": "dev_tcp",
"name": "TCP设备",
"protocol": "tcp",
"upc_ip": "192.168.1.100",
"upc_port": 502,
"listen_port": 10081,
"enabled": true
}
]
}
```
### 场景2添加 UDP 设备
```json
{
"devices": [
{
"id": "dev_udp",
"name": "UDP设备",
"protocol": "udp",
"upc_ip": "192.168.1.200",
"upc_port": 502,
"listen_port": 10082,
"enabled": true
}
]
}
```
### 场景3添加新的控制指令
```json
{
"commands": {
"open9": "000100000008010F006C00010001",
"close9": "000100000008010F006C00010000"
}
}
```
### 场景4禁用某个设备
```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
```
## 日志文件
| 文件 | 说明 |
|-----|------|
| `log/{device_id}.log` | 设备监听服务的日志 |
| `log/crond-{device_id}.log` | 保活检查的日志 |
日志自动轮转每天清理7天前的日志。
## 注意事项
1. **不要直接修改** `bin/``crond/` 下的文件,这些文件是自动生成的,重新生成时会覆盖。
2. **修改配置后必须重新运行** `python3 scripts/generate.py` 才能生效。
3. 确保每个设备的 `listen_port` 不冲突,无论 TCP 还是 UDP端口都不能重复。
4. UDP 是无连接协议,设备可能不会返回响应,这是正常现象。
5. 部署到生产环境前,请将 `base_dir` 修改为实际的部署路径(如 `/opt/upc_resent`)。

126
bin/192.168.8.125.py Normal file
View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import socket
import os
import time
import logging
import sys
# reload(sys) 和 sys.setdefaultencoding('utf-8') 在 Python 3 中不再需要
if __name__ == '__main__':
#======修改以下参数======
TmsServerIp='192.168.8.9' #TMS服务器IP用于绑定服务等待外部指令
TmsPor='10129' #TMS服务器端口用于绑定服务等待外部指令
upc_dev_ip="192.168.8.125" #自动化控制设备IP
upc_dev_port="502" #自动化控制设备端口
# 注意Senderfile 指向的 sender.py 脚本也需要是 Python 3 版本!
Senderfile='/opt/upc_resent/bin/sender.py' #发送程序位置
Logfile='/opt/upc_resent/log/192.168.8.125.log' #日志文件位置
pythonpath="/usr/bin/python3" # Python 3 执行文件的位置可在操作系统中使用which python3命令获取
#========================
BUFSIZE = 1024
# 配置日志,只执行一次
logging.basicConfig(filename=Logfile,filemode="a", level=logging.DEBUG)
ISOTIMEFORMAT='%Y-%m-%d %X'
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind((TmsServerIp, int(TmsPor))) #启动TMS本地服务等待外部设备发送指令
sock.listen(500)
except OSError as e: # 在 Python 3 中使用 OSError 替代 socket.error
logstr="!!!!!ERROR!!!!!"+time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )+" 无法绑定端口 %s:%s - %s" % (TmsServerIp, TmsPor, e)
logging.error(logstr)
print(logstr) # Python 3 print 函数
sys.exit(1) # 绑定失败则退出
logging.info("服务启动,监听 %s:%s" % (TmsServerIp, TmsPor))
while True:
connection,address = sock.accept()
try:
connection.settimeout(5) #GDC系统长连接
# 接收到的数据是 bytes需要解码成 str 进行比较
buf_bytes = connection.recv(BUFSIZE)
buf = buf_bytes.decode('utf-8').strip() # 解码成 str 并移除空白符
operation = "nodata" # 默认值,如果没有匹配的命令
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
logstr="==="+datetime_str+"收到客户端"+ address[0]+":"+str(address[1])+"发送的指令: '" +str(buf)+"'"
logging.info(logstr)
# 根据接收到的外部命令,映射到单个内部操作指令
if buf == 'open':
operation = 'openall4'
elif buf == 'close':
operation = 'closeall4'
elif buf == 'open1':
operation = 'open1'
elif buf == 'close1':
operation = 'close1'
elif buf == 'open2':
operation = 'open2'
elif buf == 'close2':
operation = 'close2'
elif buf == 'open3':
operation = 'open3'
elif buf == 'close3':
operation = 'close3'
elif buf == 'open4':
operation = 'open4'
elif buf == 'close4':
operation = 'close4'
elif buf == 'open5': # 新增 5-8 路的命令映射
operation = 'open5'
elif buf == 'close5':
operation = 'close5'
elif buf == 'open6':
operation = 'open6'
elif buf == 'close6':
operation = 'close6'
elif buf == 'open7':
operation = 'open7'
elif buf == 'close7':
operation = 'close7'
elif buf == 'open8':
operation = 'open8'
elif buf == 'close8':
operation = 'close8'
elif buf == 'guanggao-guan': # 外部命令 'guanggao-guan' 映射到 'closeall4' (全关)
operation = 'closeall4'
# else: operation 保持为 "nodata"
if operation == "nodata":
logstr="==="+datetime_str+" 未知指令: '" +str(buf)+"'"
logging.warning(logstr)
print(logstr) # Python 3 print 函数
# 给客户端一个反馈,需要编码成 bytes
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
else:
logstr="==="+datetime_str+" 映射到内部指令: '" +str(operation)+"'"
logging.info(logstr)
# 直接执行一次外部脚本
os_command=str(pythonpath)+" " +Senderfile+ " " + str(upc_dev_ip)+" "+str(upc_dev_port)+" "+str(operation)+" "+str(Logfile)
logging.info("执行外部命令: %s" % os_command)
os.system(os_command) # 执行发送指令的脚本
# 成功处理后给客户端反馈,需要编码成 bytes
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
except socket.timeout:
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
logstr="==="+datetime_str+" 客户端连接超时: "+ address[0]+":"+str(address[1])+"==="
logging.warning(logstr)
print('time out') # Python 3 print 函数
except Exception as e: # 捕获其他可能的异常
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
logstr="==="+datetime_str+" 处理客户端 "+ address[0]+":"+str(address[1])+" 请求时发生错误: "+str(e)+"==="
logging.error(logstr, exc_info=True) # 记录异常详情
print("Error processing request:", e) # Python 3 print 函数
# 给客户端一个错误反馈,需要编码成 bytes
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
finally:
connection.close() # 确保每次连接都被关闭

126
bin/192.168.8.73.py Normal file
View File

@@ -0,0 +1,126 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import socket
import os
import time
import logging
import sys
# reload(sys) 和 sys.setdefaultencoding('utf-8') 在 Python 3 中不再需要
if __name__ == '__main__':
#======修改以下参数======
TmsServerIp='192.168.8.9' #TMS服务器IP用于绑定服务等待外部指令
TmsPor='10079' #TMS服务器端口用于绑定服务等待外部指令
upc_dev_ip="192.168.8.73" #自动化控制设备IP
upc_dev_port="502" #自动化控制设备端口
# 注意Senderfile 指向的 sender.py 脚本也需要是 Python 3 版本!
Senderfile='/opt/upc_resent/bin/sender.py' #发送程序位置
Logfile='/opt/upc_resent/log/192.168.8.73.log' #日志文件位置
pythonpath="/usr/bin/python3" # Python 3 执行文件的位置可在操作系统中使用which python3命令获取
#========================
BUFSIZE = 1024
# 配置日志,只执行一次
logging.basicConfig(filename=Logfile,filemode="a", level=logging.DEBUG)
ISOTIMEFORMAT='%Y-%m-%d %X'
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind((TmsServerIp, int(TmsPor))) #启动TMS本地服务等待外部设备发送指令
sock.listen(500)
except OSError as e: # 在 Python 3 中使用 OSError 替代 socket.error
logstr="!!!!!ERROR!!!!!"+time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )+" 无法绑定端口 %s:%s - %s" % (TmsServerIp, TmsPor, e)
logging.error(logstr)
print(logstr) # Python 3 print 函数
sys.exit(1) # 绑定失败则退出
logging.info("服务启动,监听 %s:%s" % (TmsServerIp, TmsPor))
while True:
connection,address = sock.accept()
try:
connection.settimeout(5) #GDC系统长连接
# 接收到的数据是 bytes需要解码成 str 进行比较
buf_bytes = connection.recv(BUFSIZE)
buf = buf_bytes.decode('utf-8').strip() # 解码成 str 并移除空白符
operation = "nodata" # 默认值,如果没有匹配的命令
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
logstr="==="+datetime_str+"收到客户端"+ address[0]+":"+str(address[1])+"发送的指令: '" +str(buf)+"'"
logging.info(logstr)
# 根据接收到的外部命令,映射到单个内部操作指令
if buf == 'open':
operation = 'openall4'
elif buf == 'close':
operation = 'closeall4'
elif buf == 'open1':
operation = 'open1'
elif buf == 'close1':
operation = 'close1'
elif buf == 'open2':
operation = 'open2'
elif buf == 'close2':
operation = 'close2'
elif buf == 'open3':
operation = 'open3'
elif buf == 'close3':
operation = 'close3'
elif buf == 'open4':
operation = 'open4'
elif buf == 'close4':
operation = 'close4'
elif buf == 'open5': # 新增 5-8 路的命令映射
operation = 'open5'
elif buf == 'close5':
operation = 'close5'
elif buf == 'open6':
operation = 'open6'
elif buf == 'close6':
operation = 'close6'
elif buf == 'open7':
operation = 'open7'
elif buf == 'close7':
operation = 'close7'
elif buf == 'open8':
operation = 'open8'
elif buf == 'close8':
operation = 'close8'
elif buf == 'guanggao-guan': # 外部命令 'guanggao-guan' 映射到 'closeall4' (全关)
operation = 'closeall4'
# else: operation 保持为 "nodata"
if operation == "nodata":
logstr="==="+datetime_str+" 未知指令: '" +str(buf)+"'"
logging.warning(logstr)
print(logstr) # Python 3 print 函数
# 给客户端一个反馈,需要编码成 bytes
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
else:
logstr="==="+datetime_str+" 映射到内部指令: '" +str(operation)+"'"
logging.info(logstr)
# 直接执行一次外部脚本
os_command=str(pythonpath)+" " +Senderfile+ " " + str(upc_dev_ip)+" "+str(upc_dev_port)+" "+str(operation)+" "+str(Logfile)
logging.info("执行外部命令: %s" % os_command)
os.system(os_command) # 执行发送指令的脚本
# 成功处理后给客户端反馈,需要编码成 bytes
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
except socket.timeout:
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
logstr="==="+datetime_str+" 客户端连接超时: "+ address[0]+":"+str(address[1])+"==="
logging.warning(logstr)
print('time out') # Python 3 print 函数
except Exception as e: # 捕获其他可能的异常
datetime_str=time.strftime( ISOTIMEFORMAT, time.localtime( time.time() ) )
logstr="==="+datetime_str+" 处理客户端 "+ address[0]+":"+str(address[1])+" 请求时发生错误: "+str(e)+"==="
logging.error(logstr, exc_info=True) # 记录异常详情
print("Error processing request:", e) # Python 3 print 函数
# 给客户端一个错误反馈,需要编码成 bytes
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
finally:
connection.close() # 确保每次连接都被关闭

124
bin/dev1.py Executable file
View File

@@ -0,0 +1,124 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: 设备73-TCP (dev1)
import socket
import os
import time
import logging
import sys
# ====== 配置参数(从配置文件读取)======
TMS_SERVER_IP = '192.168.8.9'
TMS_PORT = 10079
UPC_DEV_IP = '192.168.8.73'
UPC_DEV_PORT = '502'
SENDER_FILE = '/home/smart/pythonPJ/upc_resent/bin/sender_tcp.py'
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/dev1.log'
PYTHON_PATH = '/usr/bin/python3'
DEVICE_ID = 'dev1'
# =========================
BUFSIZE = 1024
# 配置日志
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
ISOTIMEFORMAT = '%Y-%m-%d %X'
# 命令映射表
COMMAND_MAPPINGS = {
"open": "openall4",
"close": "closeall4",
"guanggao-guan": "closeall4",
"open1": "open1",
"close1": "close1",
"open2": "open2",
"close2": "close2",
"open3": "open3",
"close3": "close3",
"open4": "open4",
"close4": "close4",
"open5": "open5",
"close5": "close5",
"open6": "open6",
"close6": "close6",
"open7": "open7",
"close7": "close7",
"open8": "open8",
"close8": "close8",
}
def process_command(buf):
"""处理接收到的命令,返回对应的操作指令"""
buf = buf.strip()
if buf in COMMAND_MAPPINGS:
return COMMAND_MAPPINGS[buf]
return "nodata"
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
sock.listen(500)
except OSError as e:
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
" 无法绑定端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
logging.error(logstr)
print(logstr)
sys.exit(1)
logging.info("服务启动,监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
print(f"[{DEVICE_ID}] 服务启动,监听 {TMS_SERVER_IP}:{TMS_PORT}")
while True:
connection, address = sock.accept()
try:
connection.settimeout(5)
buf_bytes = connection.recv(BUFSIZE)
buf = buf_bytes.decode('utf-8').strip()
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 收到客户端 " + address[0] + ":" + str(address[1]) + \
" 发送的指令: '" + str(buf) + "'"
logging.info(logstr)
print(logstr)
operation = process_command(buf)
if operation == "nodata":
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
logging.warning(logstr)
print(logstr)
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
else:
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
logging.info(logstr)
print(logstr)
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
str(operation) + " " + str(LOG_FILE)
logging.info("执行外部命令: %s" % os_command)
os.system(os_command)
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
except socket.timeout:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 客户端连接超时: " + address[0] + ":" + str(address[1]) + "==="
logging.warning(logstr)
print('time out')
except Exception as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 处理客户端 " + address[0] + ":" + str(address[1]) + \
" 请求时发生错误: " + str(e) + "==="
logging.error(logstr, exc_info=True)
print("Error processing request:", e)
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
finally:
connection.close()
if __name__ == '__main__':
main()

124
bin/dev2.py Executable file
View File

@@ -0,0 +1,124 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: 设备125-TCP (dev2)
import socket
import os
import time
import logging
import sys
# ====== 配置参数(从配置文件读取)======
TMS_SERVER_IP = '192.168.8.9'
TMS_PORT = 10129
UPC_DEV_IP = '192.168.8.125'
UPC_DEV_PORT = '502'
SENDER_FILE = '/home/smart/pythonPJ/upc_resent/bin/sender_tcp.py'
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/dev2.log'
PYTHON_PATH = '/usr/bin/python3'
DEVICE_ID = 'dev2'
# =========================
BUFSIZE = 1024
# 配置日志
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
ISOTIMEFORMAT = '%Y-%m-%d %X'
# 命令映射表
COMMAND_MAPPINGS = {
"open": "openall4",
"close": "closeall4",
"guanggao-guan": "closeall4",
"open1": "open1",
"close1": "close1",
"open2": "open2",
"close2": "close2",
"open3": "open3",
"close3": "close3",
"open4": "open4",
"close4": "close4",
"open5": "open5",
"close5": "close5",
"open6": "open6",
"close6": "close6",
"open7": "open7",
"close7": "close7",
"open8": "open8",
"close8": "close8",
}
def process_command(buf):
"""处理接收到的命令,返回对应的操作指令"""
buf = buf.strip()
if buf in COMMAND_MAPPINGS:
return COMMAND_MAPPINGS[buf]
return "nodata"
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
sock.listen(500)
except OSError as e:
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
" 无法绑定端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
logging.error(logstr)
print(logstr)
sys.exit(1)
logging.info("服务启动,监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
print(f"[{DEVICE_ID}] 服务启动,监听 {TMS_SERVER_IP}:{TMS_PORT}")
while True:
connection, address = sock.accept()
try:
connection.settimeout(5)
buf_bytes = connection.recv(BUFSIZE)
buf = buf_bytes.decode('utf-8').strip()
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 收到客户端 " + address[0] + ":" + str(address[1]) + \
" 发送的指令: '" + str(buf) + "'"
logging.info(logstr)
print(logstr)
operation = process_command(buf)
if operation == "nodata":
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
logging.warning(logstr)
print(logstr)
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
else:
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
logging.info(logstr)
print(logstr)
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
str(operation) + " " + str(LOG_FILE)
logging.info("执行外部命令: %s" % os_command)
os.system(os_command)
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
except socket.timeout:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 客户端连接超时: " + address[0] + ":" + str(address[1]) + "==="
logging.warning(logstr)
print('time out')
except Exception as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 处理客户端 " + address[0] + ":" + str(address[1]) + \
" 请求时发生错误: " + str(e) + "==="
logging.error(logstr, exc_info=True)
print("Error processing request:", e)
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
finally:
connection.close()
if __name__ == '__main__':
main()

118
bin/dev3.py Executable file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: 设备UDP示例 (dev3) - UDP Protocol
import socket
import os
import time
import logging
import sys
# ====== 配置参数(从配置文件读取)======
TMS_SERVER_IP = '192.168.8.9'
TMS_PORT = 10080
UPC_DEV_IP = '192.168.8.200'
UPC_DEV_PORT = 502
SENDER_FILE = '/home/smart/pythonPJ/upc_resent/bin/sender_udp.py'
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/dev3.log'
PYTHON_PATH = '/usr/bin/python3'
DEVICE_ID = 'dev3'
# =========================
BUFSIZE = 1024
# 配置日志
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
ISOTIMEFORMAT = '%Y-%m-%d %X'
# 命令映射表
COMMAND_MAPPINGS = {
"open": "openall4",
"close": "closeall4",
"guanggao-guan": "closeall4",
"open1": "open1",
"close1": "close1",
"open2": "open2",
"close2": "close2",
"open3": "open3",
"close3": "close3",
"open4": "open4",
"close4": "close4",
"open5": "open5",
"close5": "close5",
"open6": "open6",
"close6": "close6",
"open7": "open7",
"close7": "close7",
"open8": "open8",
"close8": "close8",
}
def process_command(buf):
"""处理接收到的命令,返回对应的操作指令"""
buf = buf.strip()
if buf in COMMAND_MAPPINGS:
return COMMAND_MAPPINGS[buf]
return "nodata"
def main():
# 创建 UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
except OSError as e:
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
" 无法绑定UDP端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
logging.error(logstr)
print(logstr)
sys.exit(1)
logging.info("UDP服务启动监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
print(f"[{DEVICE_ID}] UDP服务启动监听 {TMS_SERVER_IP}:{TMS_PORT}")
while True:
try:
# UDP 使用 recvfrom 接收数据,同时获取客户端地址
buf_bytes, client_addr = sock.recvfrom(BUFSIZE)
buf = buf_bytes.decode('utf-8').strip()
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 收到UDP客户端 " + client_addr[0] + ":" + str(client_addr[1]) + \
" 发送的指令: '" + str(buf) + "'"
logging.info(logstr)
print(logstr)
operation = process_command(buf)
if operation == "nodata":
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
logging.warning(logstr)
print(logstr)
# 发送UDP响应
sock.sendto(('Unknown command: %s' % buf).encode('utf-8'), client_addr)
else:
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
logging.info(logstr)
print(logstr)
# 执行发送指令的脚本
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
str(operation) + " " + str(LOG_FILE)
logging.info("执行外部命令: %s" % os_command)
os.system(os_command)
# 发送UDP响应
sock.sendto(('Command %s processed as %s' % (buf, operation)).encode('utf-8'), client_addr)
except Exception as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 处理UDP请求时发生错误: " + str(e) + "==="
logging.error(logstr, exc_info=True)
print("Error processing UDP request:", e)
if __name__ == '__main__':
main()

140
bin/sender.py Executable file
View File

@@ -0,0 +1,140 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
import sys
import socket
import time
import logging
import telnetlib
def tcp_command_send(upc_addr, upc_command, data):
"""负责发送数据和接收一次响应"""
timeout = 2
socket.setdefaulttimeout(timeout)
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
logging.debug(f"尝试连接到 {upc_addr[0]}:{upc_addr[1]}...")
client.connect(upc_addr)
logging.debug(f"成功连接到 {upc_addr[0]}:{upc_addr[1]}")
logging.info(f"正在发送命令 '{upc_command}'{upc_addr}: {data!r} (原始字节)")
client.send(data)
logging.debug(f"数据发送完成。")
recv_buffer_size = 1024
response_bytes = b''
try:
logging.debug(f"尝试从 {upc_addr} 接收响应数据...")
response_bytes = client.recv(recv_buffer_size)
if response_bytes:
logging.info(f"{upc_addr} 收到原始响应字节: {response_bytes!r}")
try:
response_str = response_bytes.decode('utf-8', errors='ignore')
logging.info(f"{upc_addr} 收到解码响应字符串: '{response_str}'")
except Exception as decode_e:
logging.warning(f"解码从 {upc_addr} 收到的响应时发生错误: {decode_e}")
else:
logging.info(f"{upc_addr} 未收到响应数据 (连接可能已关闭或设备未发送)。")
except socket.timeout:
logging.warning(f"{upc_addr} 接收响应超时。")
except OSError as recv_e:
logging.error(f"{upc_addr} 接收响应时发生网络错误: {recv_e}")
client.close()
logging.debug(f"连接关闭。")
return True
except OSError as e:
logging.error(f"命令 '{upc_command}' 发送至 {upc_addr} 失败: {e}")
return False
# 指令定义表(从配置文件读取)
COMMAND_DEFINITIONS = {
"open1": "000100000008010F006400010001",
"close1": "000100000008010F006400010000",
"open2": "000100000008010F006500010001",
"close2": "000100000008010F006500010000",
"open3": "000100000008010F006600010001",
"close3": "000100000008010F006600010000",
"open4": "000100000008010F006700010001",
"close4": "000100000008010F006700010000",
"openall4": "000100000008010F00640004000F",
"closeall4": "000100000008010F006400040000",
"open5": "000100000008010F006800010001",
"close5": "000100000008010F006800010000",
"open6": "000100000008010F006900010001",
"close6": "000100000008010F006900010000",
"open7": "000100000008010F006A00010001",
"close7": "000100000008010F006A00010000",
"open8": "000100000008010F006B00010001",
"close8": "000100000008010F006B00010000",
"getstat": "fe010000000429C6",
"getstat01": "fe010100000429C6",
}
def upc_send_command(upc_addr, upc_command, log_file):
"""将命令发送给终端设备"""
data = None
# 查找指令定义
if upc_command in COMMAND_DEFINITIONS:
hex_str = COMMAND_DEFINITIONS[upc_command]
data = bytes.fromhex(hex_str)
if data is None:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} 未知命令: {upc_command},没有对应的数据可发送。"
logging.warning(logstr)
print(logstr)
else:
i = 1
while i <= 3: # 尝试发送3次
if tcp_command_send(upc_addr, upc_command, data):
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令第{i}次发送成功"
logging.info(logstr)
return
else:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令第{i}次发送失败3秒后进行第{i+1}次尝试"
logging.warning(logstr)
time.sleep(3)
i = i + 1
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令在3次尝试后发送均失败"
logging.error(logstr)
if __name__ == '__main__':
ISOTIMEFORMAT = '%Y-%m-%d %X'
UPC_DEV_IP = sys.argv[1]
UPC_DEV_PORT = sys.argv[2]
upc_command = sys.argv[3]
LOG_FILE = sys.argv[4]
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
UPC_ADDR = (UPC_DEV_IP, int(UPC_DEV_PORT))
# 验证端口是否能Telnet通
try:
logging.debug(f"尝试通过 Telnet 检查端口 {UPC_ADDR[0]}:{UPC_ADDR[1]} 可访问性...")
tn = telnetlib.Telnet(UPC_DEV_IP, UPC_DEV_PORT)
tn.close()
logging.debug(f"端口 {UPC_ADDR[0]}:{UPC_ADDR[1]} Telnet 检查通过。")
except OSError as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"!!!!!ERROR!!!!!{datetime_str} {UPC_ADDR} 端口无法访问,请检查设备或网络连接: {e}!!!!!"
logging.error(logstr)
print(logstr)
except Exception as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"!!!!!ERROR!!!!!{datetime_str} {UPC_ADDR} Telnet检查时发生未知错误: {e}!!!!!"
logging.error(logstr, exc_info=True)
print(logstr)
else:
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)

140
bin/sender_tcp.py Executable file
View File

@@ -0,0 +1,140 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
import sys
import socket
import time
import logging
import telnetlib
def tcp_command_send(upc_addr, upc_command, data):
"""负责发送数据和接收一次响应"""
timeout = 2
socket.setdefaulttimeout(timeout)
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
logging.debug(f"尝试连接到 {upc_addr[0]}:{upc_addr[1]}...")
client.connect(upc_addr)
logging.debug(f"成功连接到 {upc_addr[0]}:{upc_addr[1]}")
logging.info(f"正在发送命令 '{upc_command}'{upc_addr}: {data!r} (原始字节)")
client.send(data)
logging.debug(f"数据发送完成。")
recv_buffer_size = 1024
response_bytes = b''
try:
logging.debug(f"尝试从 {upc_addr} 接收响应数据...")
response_bytes = client.recv(recv_buffer_size)
if response_bytes:
logging.info(f"{upc_addr} 收到原始响应字节: {response_bytes!r}")
try:
response_str = response_bytes.decode('utf-8', errors='ignore')
logging.info(f"{upc_addr} 收到解码响应字符串: '{response_str}'")
except Exception as decode_e:
logging.warning(f"解码从 {upc_addr} 收到的响应时发生错误: {decode_e}")
else:
logging.info(f"{upc_addr} 未收到响应数据 (连接可能已关闭或设备未发送)。")
except socket.timeout:
logging.warning(f"{upc_addr} 接收响应超时。")
except OSError as recv_e:
logging.error(f"{upc_addr} 接收响应时发生网络错误: {recv_e}")
client.close()
logging.debug(f"连接关闭。")
return True
except OSError as e:
logging.error(f"命令 '{upc_command}' 发送至 {upc_addr} 失败: {e}")
return False
# 指令定义表(从配置文件读取)
COMMAND_DEFINITIONS = {
"open1": "000100000008010F006400010001",
"close1": "000100000008010F006400010000",
"open2": "000100000008010F006500010001",
"close2": "000100000008010F006500010000",
"open3": "000100000008010F006600010001",
"close3": "000100000008010F006600010000",
"open4": "000100000008010F006700010001",
"close4": "000100000008010F006700010000",
"openall4": "000100000008010F00640004000F",
"closeall4": "000100000008010F006400040000",
"open5": "000100000008010F006800010001",
"close5": "000100000008010F006800010000",
"open6": "000100000008010F006900010001",
"close6": "000100000008010F006900010000",
"open7": "000100000008010F006A00010001",
"close7": "000100000008010F006A00010000",
"open8": "000100000008010F006B00010001",
"close8": "000100000008010F006B00010000",
"getstat": "fe010000000429C6",
"getstat01": "fe010100000429C6",
}
def upc_send_command(upc_addr, upc_command, log_file):
"""将命令发送给终端设备"""
data = None
# 查找指令定义
if upc_command in COMMAND_DEFINITIONS:
hex_str = COMMAND_DEFINITIONS[upc_command]
data = bytes.fromhex(hex_str)
if data is None:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} 未知命令: {upc_command},没有对应的数据可发送。"
logging.warning(logstr)
print(logstr)
else:
i = 1
while i <= 3: # 尝试发送3次
if tcp_command_send(upc_addr, upc_command, data):
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令第{i}次发送成功"
logging.info(logstr)
return
else:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令第{i}次发送失败3秒后进行第{i+1}次尝试"
logging.warning(logstr)
time.sleep(3)
i = i + 1
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令在3次尝试后发送均失败"
logging.error(logstr)
if __name__ == '__main__':
ISOTIMEFORMAT = '%Y-%m-%d %X'
UPC_DEV_IP = sys.argv[1]
UPC_DEV_PORT = sys.argv[2]
upc_command = sys.argv[3]
LOG_FILE = sys.argv[4]
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
UPC_ADDR = (UPC_DEV_IP, int(UPC_DEV_PORT))
# 验证端口是否能Telnet通
try:
logging.debug(f"尝试通过 Telnet 检查端口 {UPC_ADDR[0]}:{UPC_ADDR[1]} 可访问性...")
tn = telnetlib.Telnet(UPC_DEV_IP, UPC_DEV_PORT)
tn.close()
logging.debug(f"端口 {UPC_ADDR[0]}:{UPC_ADDR[1]} Telnet 检查通过。")
except OSError as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"!!!!!ERROR!!!!!{datetime_str} {UPC_ADDR} 端口无法访问,请检查设备或网络连接: {e}!!!!!"
logging.error(logstr)
print(logstr)
except Exception as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"!!!!!ERROR!!!!!{datetime_str} {UPC_ADDR} Telnet检查时发生未知错误: {e}!!!!!"
logging.error(logstr, exc_info=True)
print(logstr)
else:
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)

128
bin/sender_udp.py Executable file
View File

@@ -0,0 +1,128 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
import sys
import socket
import time
import logging
def udp_command_send(upc_addr, upc_command, data, timeout=2):
"""通过UDP发送数据并接收响应"""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(timeout)
try:
logging.debug(f"尝试发送UDP数据到 {upc_addr[0]}:{upc_addr[1]}...")
logging.info(f"正在发送UDP命令 '{upc_command}'{upc_addr}: {data!r} (原始字节)")
sock.sendto(data, upc_addr)
logging.debug(f"UDP数据发送完成。")
# 尝试接收响应
recv_buffer_size = 1024
try:
logging.debug(f"等待从 {upc_addr} 接收UDP响应...")
response_bytes, addr = sock.recvfrom(recv_buffer_size)
if response_bytes:
logging.info(f"{addr} 收到UDP原始响应字节: {response_bytes!r}")
try:
response_str = response_bytes.decode('utf-8', errors='ignore')
logging.info(f"{addr} 收到UDP解码响应字符串: '{response_str}'")
except Exception as decode_e:
logging.warning(f"解码UDP响应时发生错误: {decode_e}")
else:
logging.info(f"未收到UDP响应数据。")
except socket.timeout:
logging.warning(f"接收UDP响应超时设备可能不返回响应这通常是正常的")
except OSError as recv_e:
logging.error(f"接收UDP响应时发生网络错误: {recv_e}")
sock.close()
logging.debug(f"UDP socket关闭。")
return True
except OSError as e:
logging.error(f"UDP命令 '{upc_command}' 发送至 {upc_addr} 失败: {e}")
return False
finally:
try:
sock.close()
except:
pass
# 指令定义表(从配置文件读取)
COMMAND_DEFINITIONS = {
"open1": "000100000008010F006400010001",
"close1": "000100000008010F006400010000",
"open2": "000100000008010F006500010001",
"close2": "000100000008010F006500010000",
"open3": "000100000008010F006600010001",
"close3": "000100000008010F006600010000",
"open4": "000100000008010F006700010001",
"close4": "000100000008010F006700010000",
"openall4": "000100000008010F00640004000F",
"closeall4": "000100000008010F006400040000",
"open5": "000100000008010F006800010001",
"close5": "000100000008010F006800010000",
"open6": "000100000008010F006900010001",
"close6": "000100000008010F006900010000",
"open7": "000100000008010F006A00010001",
"close7": "000100000008010F006A00010000",
"open8": "000100000008010F006B00010001",
"close8": "000100000008010F006B00010000",
"getstat": "fe010000000429C6",
"getstat01": "fe010100000429C6",
}
def upc_send_command(upc_addr, upc_command, log_file):
"""将命令发送给终端设备"""
data = None
# 查找指令定义
if upc_command in COMMAND_DEFINITIONS:
hex_str = COMMAND_DEFINITIONS[upc_command]
data = bytes.fromhex(hex_str)
if data is None:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} 未知命令: {upc_command},没有对应的数据可发送。"
logging.warning(logstr)
print(logstr)
else:
i = 1
while i <= 3: # 尝试发送3次
if udp_command_send(upc_addr, upc_command, data):
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令第{i}次发送成功"
logging.info(logstr)
return
else:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令第{i}次发送失败3秒后进行第{i+1}次尝试"
logging.warning(logstr)
time.sleep(3)
i = i + 1
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{datetime_str} {upc_command}命令在3次尝试后发送均失败"
logging.error(logstr)
if __name__ == '__main__':
ISOTIMEFORMAT = '%Y-%m-%d %X'
UPC_DEV_IP = sys.argv[1]
UPC_DEV_PORT = int(sys.argv[2])
upc_command = sys.argv[3]
LOG_FILE = sys.argv[4]
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
UPC_ADDR = (UPC_DEV_IP, UPC_DEV_PORT)
# UDP 是无连接的无需像TCP那样预先检查端口连通性
# 直接发送数据
logging.info(f"UDP模式准备发送命令到 {UPC_ADDR}")
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)

63
config/devices.json Normal file
View File

@@ -0,0 +1,63 @@
{
"global": {
"tms_server_ip": "192.168.8.9",
"python_path": "/usr/bin/python3",
"base_dir": "/home/smart/pythonPJ/upc_resent"
},
"devices": [
{
"id": "dev1",
"name": "设备73-TCP",
"protocol": "tcp",
"upc_ip": "192.168.8.73",
"upc_port": 502,
"listen_port": 10079,
"enabled": true
},
{
"id": "dev2",
"name": "设备125-TCP",
"protocol": "tcp",
"upc_ip": "192.168.8.125",
"upc_port": 502,
"listen_port": 10129,
"enabled": true
},
{
"id": "dev3",
"name": "设备UDP示例",
"protocol": "udp",
"upc_ip": "192.168.8.200",
"upc_port": 502,
"listen_port": 10080,
"enabled": true
}
],
"commands": {
"open1": "000100000008010F006400010001",
"close1": "000100000008010F006400010000",
"open2": "000100000008010F006500010001",
"close2": "000100000008010F006500010000",
"open3": "000100000008010F006600010001",
"close3": "000100000008010F006600010000",
"open4": "000100000008010F006700010001",
"close4": "000100000008010F006700010000",
"openall4": "000100000008010F00640004000F",
"closeall4": "000100000008010F006400040000",
"open5": "000100000008010F006800010001",
"close5": "000100000008010F006800010000",
"open6": "000100000008010F006900010001",
"close6": "000100000008010F006900010000",
"open7": "000100000008010F006A00010001",
"close7": "000100000008010F006A00010000",
"open8": "000100000008010F006B00010001",
"close8": "000100000008010F006B00010000",
"getstat": "fe010000000429C6",
"getstat01": "fe010100000429C6"
},
"mappings": {
"open": "openall4",
"close": "closeall4",
"guanggao-guan": "closeall4"
}
}

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import time
import logging
import os
import socket
import sys # sys 模块用于 sys.exit(),虽然这里没有直接使用,但通常在脚本中需要
# --- 配置日志 ---
# 确保日志文件路径正确
LOG_FILE = '/opt/upc_resent/log/upc-192.168.8.125.log'
# 定义时间格式,将被 logging.basicConfig 的 datefmt 使用
ISOTIMEFORMAT = '%Y-%m-%d %X'
# 配置日志,确保只执行一次
# format 中包含了时间戳 %(asctime)s所以不需要手动在日志字符串中添加 datetime
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
# --- 日志配置结束 ---
def IsOpen(ip, port):
"""
检查指定IP和端口是否可达。
如果端口不可达则记录警告并尝试重启另一个Python脚本。
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1) # 设置连接超时为1秒避免无限期阻塞
try:
logging.debug(f"尝试连接到 {ip}:{port}...")
s.connect((ip, int(port)))
s.shutdown(socket.SHUT_RDWR) # 使用 SHUT_RDWR 代替数字 2更具可读性
print(f"端口 {port} is open") # Python 3 print 函数
logging.info(f"端口 {port} is open")
return True
except (OSError, socket.timeout) as e: # 捕获具体的网络错误和超时
print(f"端口 {port} is down") # Python 3 print 函数
logging.warning(f"端口 {port} 检查失败: {e},尝试重启程序")
# --- 重启命令 ---
# 确保这里的 python3 路径和脚本路径正确
# 这里的脚本名 "192.168.8.125.py" 看起来是硬编码的,请确认是否正确
restart_command = "/usr/bin/python3 /opt/upc_resent/bin/192.168.8.125.py &"
logging.info(f"执行重启命令: {restart_command}")
os.system(restart_command)
# --- 重启命令结束 ---
return False
except ValueError: # 捕获 int(port) 转换失败的情况
print(f"错误: 端口 '{port}' 不是有效的数字。")
logging.error(f"端口 '{port}' 不是有效的数字。")
return False
finally:
s.close() # 确保无论成功或失败socket 都会被关闭
if __name__ == '__main__':
# --- 目标设备IP和端口 ---
# 这些值在原脚本中是硬编码的,如果需要从命令行参数获取,请修改
target_ip = '192.168.8.9'
target_port = 10129
# --- 目标设备IP和端口结束 ---
logging.info(f"启动端口检查程序,检查 {target_ip}:{target_port}")
IsOpen(target_ip, target_port)

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
import time
import logging
import os
import socket
import sys # sys 模块用于 sys.exit(),虽然这里没有直接使用,但通常在脚本中需要
# --- 配置日志 ---
# 确保日志文件路径正确
LOG_FILE = '/opt/upc_resent/log/upc-192.168.8.73.log'
# 定义时间格式,将被 logging.basicConfig 的 datefmt 使用
ISOTIMEFORMAT = '%Y-%m-%d %X'
# 配置日志,确保只执行一次
# format 中包含了时间戳 %(asctime)s所以不需要手动在日志字符串中添加 datetime
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
# --- 日志配置结束 ---
def IsOpen(ip, port):
"""
检查指定IP和端口是否可达。
如果端口不可达则记录警告并尝试重启另一个Python脚本。
"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1) # 设置连接超时为1秒避免无限期阻塞
try:
logging.debug(f"尝试连接到 {ip}:{port}...")
s.connect((ip, int(port)))
s.shutdown(socket.SHUT_RDWR) # 使用 SHUT_RDWR 代替数字 2更具可读性
print(f"端口 {port} is open") # Python 3 print 函数
logging.info(f"端口 {port} is open")
return True
except (OSError, socket.timeout) as e: # 捕获具体的网络错误和超时
print(f"端口 {port} is down") # Python 3 print 函数
logging.warning(f"端口 {port} 检查失败: {e},尝试重启程序")
# --- 重启命令 ---
# 确保这里的 python3 路径和脚本路径正确
# 这里的脚本名 "192.168.8.125.py" 看起来是硬编码的,请确认是否正确
restart_command = "/usr/bin/python3 /opt/upc_resent/bin/192.168.8.73.py &"
logging.info(f"执行重启命令: {restart_command}")
os.system(restart_command)
# --- 重启命令结束 ---
return False
except ValueError: # 捕获 int(port) 转换失败的情况
print(f"错误: 端口 '{port}' 不是有效的数字。")
logging.error(f"端口 '{port}' 不是有效的数字。")
return False
finally:
s.close() # 确保无论成功或失败socket 都会被关闭
if __name__ == '__main__':
# --- 目标设备IP和端口 ---
# 这些值在原脚本中是硬编码的,如果需要从命令行参数获取,请修改
target_ip = '192.168.8.9'
target_port = 10079
# --- 目标设备IP和端口结束 ---
logging.info(f"启动端口检查程序,检查 {target_ip}:{target_port}")
IsOpen(target_ip, target_port)

54
crond/upcrond-dev1.py Executable file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: 设备73-TCP (dev1)
import time
import logging
import os
import socket
import sys
# ====== 配置参数(从配置文件读取)======
TARGET_IP = '192.168.8.9'
TARGET_PORT = 10079
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/crond-dev1.log'
RESTART_COMMAND = "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev1.py &"
DEVICE_ID = 'dev1'
# =========================
ISOTIMEFORMAT = '%Y-%m-%d %X'
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
def is_port_open(ip, port):
"""检查指定IP和端口是否可达"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
try:
logging.debug(f"尝试连接到 {ip}:{port}...")
s.connect((ip, int(port)))
s.shutdown(socket.SHUT_RDWR)
print(f"[{DEVICE_ID}] 端口 {port} is open")
logging.info(f"端口 {port} is open")
return True
except (OSError, socket.timeout) as e:
print(f"[{DEVICE_ID}] 端口 {port} is down")
logging.warning(f"端口 {port} 检查失败: {e},尝试重启程序")
logging.info(f"执行重启命令: {RESTART_COMMAND}")
os.system(RESTART_COMMAND)
return False
except ValueError:
print(f"错误: 端口 '{port}' 不是有效的数字。")
logging.error(f"端口 '{port}' 不是有效的数字。")
return False
finally:
s.close()
if __name__ == '__main__':
logging.info(f"[{DEVICE_ID}] 启动端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
print(f"[{DEVICE_ID}] 启动端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
is_port_open(TARGET_IP, TARGET_PORT)

54
crond/upcrond-dev2.py Executable file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: 设备125-TCP (dev2)
import time
import logging
import os
import socket
import sys
# ====== 配置参数(从配置文件读取)======
TARGET_IP = '192.168.8.9'
TARGET_PORT = 10129
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/crond-dev2.log'
RESTART_COMMAND = "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev2.py &"
DEVICE_ID = 'dev2'
# =========================
ISOTIMEFORMAT = '%Y-%m-%d %X'
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
def is_port_open(ip, port):
"""检查指定IP和端口是否可达"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
try:
logging.debug(f"尝试连接到 {ip}:{port}...")
s.connect((ip, int(port)))
s.shutdown(socket.SHUT_RDWR)
print(f"[{DEVICE_ID}] 端口 {port} is open")
logging.info(f"端口 {port} is open")
return True
except (OSError, socket.timeout) as e:
print(f"[{DEVICE_ID}] 端口 {port} is down")
logging.warning(f"端口 {port} 检查失败: {e},尝试重启程序")
logging.info(f"执行重启命令: {RESTART_COMMAND}")
os.system(RESTART_COMMAND)
return False
except ValueError:
print(f"错误: 端口 '{port}' 不是有效的数字。")
logging.error(f"端口 '{port}' 不是有效的数字。")
return False
finally:
s.close()
if __name__ == '__main__':
logging.info(f"[{DEVICE_ID}] 启动端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
print(f"[{DEVICE_ID}] 启动端口检查程序,检查 {TARGET_IP}:{TARGET_PORT}")
is_port_open(TARGET_IP, TARGET_PORT)

85
crond/upcrond-dev3.py Executable file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: 设备UDP示例 (dev3) - UDP Protocol
import time
import logging
import os
import socket
import sys
import subprocess
# ====== 配置参数(从配置文件读取)======
TARGET_IP = '192.168.8.9'
TARGET_PORT = 10080
LOG_FILE = '/home/smart/pythonPJ/upc_resent/log/crond-dev3.log'
RESTART_COMMAND = "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev3.py &"
DEVICE_ID = 'dev3'
# =========================
ISOTIMEFORMAT = '%Y-%m-%d %X'
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
def is_udp_port_open(ip, port):
"""
检查UDP端口是否可用。
UDP是无连接的这里通过检查端口是否被占用或发送测试数据来判断。
"""
try:
# 尝试绑定到该端口,如果成功说明端口未被占用(服务未启动)
# 如果失败说明端口已被占用(服务正在运行)
test_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
test_sock.settimeout(1)
test_sock.bind((ip, int(port)))
test_sock.close()
# 如果绑定成功,说明服务未启动
print(f"[{DEVICE_ID}] UDP端口 {port} 未被占用,服务可能未运行")
logging.warning(f"UDP端口 {port} 未被占用,服务可能未运行,尝试重启程序")
logging.info(f"执行重启命令: {RESTART_COMMAND}")
os.system(RESTART_COMMAND)
return False
except OSError as e:
# 绑定失败,说明端口已被占用,服务正在运行
if "Address already in use" in str(e) or "98" in str(e):
print(f"[{DEVICE_ID}] UDP端口 {port} is open (已被占用,服务运行中)")
logging.info(f"UDP端口 {port} is open (服务运行中)")
return True
else:
print(f"[{DEVICE_ID}] 检查UDP端口 {port} 时发生错误: {e}")
logging.error(f"检查UDP端口 {port} 时发生错误: {e}")
return False
def check_process_running():
"""通过进程名检查服务是否正在运行"""
try:
# 检查是否有对应设备的Python进程在运行
cmd = f"ps aux | grep '{DEVICE_ID}.py' | grep -v grep"
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode == 0 and result.stdout.strip():
print(f"[{DEVICE_ID}] 进程检查: 服务正在运行")
logging.info(f"进程检查: 服务正在运行")
return True
else:
print(f"[{DEVICE_ID}] 进程检查: 服务未运行")
logging.warning(f"进程检查: 服务未运行,尝试重启")
logging.info(f"执行重启命令: {RESTART_COMMAND}")
os.system(RESTART_COMMAND)
return False
except Exception as e:
print(f"[{DEVICE_ID}] 进程检查失败: {e}")
logging.error(f"进程检查失败: {e}")
return False
if __name__ == '__main__':
logging.info(f"[{DEVICE_ID}] 启动UDP端口检查程序检查 {TARGET_IP}:{TARGET_PORT}")
print(f"[{DEVICE_ID}] 启动UDP端口检查程序检查 {TARGET_IP}:{TARGET_PORT}")
# 对于UDP优先使用进程检查方式
check_process_running()

4
crontab.txt Normal file
View File

@@ -0,0 +1,4 @@
* */1 * * * /usr/bin/python3 /home/smart/pythonPJ/upc_resent/crond/upcrond-dev1.py
* */1 * * * /usr/bin/python3 /home/smart/pythonPJ/upc_resent/crond/upcrond-dev2.py
* */1 * * * /usr/bin/python3 /home/smart/pythonPJ/upc_resent/crond/upcrond-dev3.py
0 0 * * * /home/smart/pythonPJ/upc_resent/cutlog.sh

8
cutlog.sh Normal file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
declare logs_path="/opt/upc_resent/log";
declare need_delete_path=${logs_path}/$(date -d "7 days ago" "+%Y_%m_%d");
declare yestoday_log_path=${logs_path}/$(date -d "yesterday" "+%Y_%m_%d");
rm -rf ${need_delete_path}
rm -rf ${yestoday_log_path}
mv ${logs_path}/today ${yestoday_log_path}
mkdir -p ${logs_path}/today

BIN
log/192.168.8.125.log Normal file

Binary file not shown.

5
log/192.168.8.73.log Normal file
View File

@@ -0,0 +1,5 @@
INFO:root:服务启动,监听 192.168.8.9:10079
INFO:root:===2026-03-21 20:14:40收到客户端192.168.9.71:56925发送的指令: 'close1'
INFO:root:===2026-03-21 20:14:40 映射到内部指令: 'close1'
INFO:root:执行外部命令: /usr/bin/python3 /opt/upc_resent/bin/sender.py 192.168.8.73 502 close1 /opt/upc_resent/log/192.168.8.73.log
INFO:root:2026-03-21 20:14:40 close1命令第1次发送成功

View File

@@ -0,0 +1,3 @@
2026-03-21 21:06:19 - INFO - 启动端口检查程序,检查 192.168.8.9:10129
2026-03-21 21:06:19 - DEBUG - 尝试连接到 192.168.8.9:10129...
2026-03-21 21:06:19 - INFO - 端口 10129 is open

403
scripts/generate.py Normal file
View File

@@ -0,0 +1,403 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""
代码生成器:根据配置文件自动生成 Python 执行文件
支持 TCP 和 UDP 协议
用法: python scripts/generate.py [--check]
--check: 仅检查配置,不生成文件
"""
import json
import os
import sys
import argparse
def load_config(config_file='config/devices.json'):
"""加载配置文件"""
with open(config_file, 'r', encoding='utf-8') as f:
return json.load(f)
def ensure_dirs(base_dir):
"""确保必要的目录存在"""
dirs = [
os.path.join(base_dir, 'bin'),
os.path.join(base_dir, 'crond'),
os.path.join(base_dir, 'log')
]
for d in dirs:
os.makedirs(d, exist_ok=True)
def dict_to_python_string(d):
"""将字典转换为 Python 代码字符串"""
lines = ['{']
for k, v in d.items():
if isinstance(v, str):
lines.append(f' "{k}": "{v}",')
else:
lines.append(f' "{k}": {v},')
lines.append('}')
return '\n'.join(lines)
def get_template_path(protocol, template_type):
"""
根据协议类型和模板类型获取模板文件路径
protocol: 'tcp''udp'
template_type: 'listener', 'crond', 'sender'
"""
protocol = protocol.lower()
if template_type == 'listener':
return f'templates/listener_{protocol}.py.tpl'
elif template_type == 'crond':
return f'templates/crond_{protocol}.py.tpl'
elif template_type == 'sender':
return f'templates/sender_{protocol}.py.tpl'
else:
raise ValueError(f"未知的模板类型: {template_type}")
def generate_listener(device, global_config, mappings):
"""生成监听服务文件"""
protocol = device.get('protocol', 'tcp').lower()
template_file = get_template_path(protocol, 'listener')
# 检查模板文件是否存在
if not os.path.exists(template_file):
print(f"[!] 警告: 模板文件不存在: {template_file}使用TCP模板作为后备")
template_file = 'templates/listener_tcp.py.tpl'
with open(template_file, 'r', encoding='utf-8') as f:
template = f.read()
# 构建命令映射字典字符串
mappings_str = "{\n"
for cmd, op in mappings.items():
mappings_str += f' "{cmd}": "{op}",\n'
# 添加默认映射open1-open8, close1-close8
for i in range(1, 9):
mappings_str += f' "open{i}": "open{i}",\n'
mappings_str += f' "close{i}": "close{i}",\n'
mappings_str += " }"
# 替换模板变量
content = template.format(
device_id=device['id'],
device_name=device['name'],
tms_server_ip=global_config['tms_server_ip'],
listen_port=device['listen_port'],
upc_ip=device['upc_ip'],
upc_port=device['upc_port'],
base_dir=global_config['base_dir'],
python_path=global_config['python_path'],
command_mappings=mappings_str
)
output_file = os.path.join(global_config['base_dir'], 'bin', f"{device['id']}.py")
with open(output_file, 'w', encoding='utf-8') as f:
f.write(content)
os.chmod(output_file, 0o755)
print(f"[生成] {output_file} ({protocol.upper()})")
return output_file
def generate_crond(device, global_config):
"""生成保活检查文件"""
protocol = device.get('protocol', 'tcp').lower()
template_file = get_template_path(protocol, 'crond')
# 检查模板文件是否存在
if not os.path.exists(template_file):
print(f"[!] 警告: 模板文件不存在: {template_file}使用TCP模板作为后备")
template_file = 'templates/crond_tcp.py.tpl'
with open(template_file, 'r', encoding='utf-8') as f:
template = f.read()
content = template.format(
device_id=device['id'],
device_name=device['name'],
tms_server_ip=global_config['tms_server_ip'],
listen_port=device['listen_port'],
base_dir=global_config['base_dir'],
python_path=global_config['python_path']
)
output_file = os.path.join(global_config['base_dir'], 'crond', f"upcrond-{device['id']}.py")
with open(output_file, 'w', encoding='utf-8') as f:
f.write(content)
os.chmod(output_file, 0o755)
print(f"[生成] {output_file} ({protocol.upper()})")
return output_file
def generate_sender(commands, global_config, protocol='tcp'):
"""生成发送模块文件"""
protocol = protocol.lower()
template_file = get_template_path(protocol, 'sender')
# 检查模板文件是否存在
if not os.path.exists(template_file):
print(f"[!] 警告: 模板文件不存在: {template_file}使用TCP模板作为后备")
template_file = 'templates/sender_tcp.py.tpl'
with open(template_file, 'r', encoding='utf-8') as f:
template = f.read()
# 构建指令定义字典字符串
cmd_defs = "{\n"
for cmd, hex_str in commands.items():
cmd_defs += f' "{cmd}": "{hex_str}",\n'
cmd_defs += "}"
content = template.format(
command_definitions=cmd_defs
)
# 根据协议生成不同的文件名
output_file = os.path.join(global_config['base_dir'], 'bin', f'sender_{protocol}.py')
with open(output_file, 'w', encoding='utf-8') as f:
f.write(content)
os.chmod(output_file, 0o755)
print(f"[生成] {output_file} ({protocol.upper()})")
return output_file
def generate_all_senders(config, global_config):
"""为所有使用到的协议生成 sender 文件"""
commands = config['commands']
devices = config['devices']
# 收集所有使用的协议类型
protocols = set()
for device in devices:
if device.get('enabled', True):
protocol = device.get('protocol', 'tcp').lower()
protocols.add(protocol)
generated = []
for protocol in protocols:
generated.append(generate_sender(commands, global_config, protocol))
return generated
def generate_crontab(devices, global_config):
"""生成 crontab 配置"""
lines = []
for device in devices:
if not device.get('enabled', True):
continue
# 每分钟执行一次保活检查
lines.append(f"* */1 * * * {global_config['python_path']} {global_config['base_dir']}/crond/upcrond-{device['id']}.py")
# 添加日志清理任务
lines.append(f"0 0 * * * {global_config['base_dir']}/cutlog.sh")
content = '\n'.join(lines) + '\n'
output_file = 'crontab.txt'
with open(output_file, 'w', encoding='utf-8') as f:
f.write(content)
print(f"[生成] {output_file}")
return output_file
def generate_start_script(devices, global_config):
"""生成启动脚本"""
lines = ['#!/bin/bash']
lines.append('# Auto-generated start script')
lines.append('')
lines.append('# 启动所有监听服务')
for device in devices:
if not device.get('enabled', True):
lines.append(f"# {device['name']} ({device['id']}) - 已禁用")
continue
protocol = device.get('protocol', 'tcp').upper()
script_path = f"{global_config['base_dir']}/bin/{device['id']}.py"
lines.append(f"echo '启动 {device['name']} ({device['id']}) - {protocol}...'")
lines.append(f"su root -c \"{global_config['python_path']} {script_path} &\"")
lines.append('')
lines.append('echo "所有服务已启动"')
content = '\n'.join(lines) + '\n'
output_file = 'start.sh'
with open(output_file, 'w', encoding='utf-8') as f:
f.write(content)
os.chmod(output_file, 0o755)
print(f"[生成] {output_file}")
return output_file
def check_config(config):
"""检查配置是否合法"""
errors = []
warnings = []
global_cfg = config.get('global', {})
devices = config.get('devices', [])
commands = config.get('commands', {})
mappings = config.get('mappings', {})
# 检查全局配置
required_globals = ['tms_server_ip', 'python_path', 'base_dir']
for key in required_globals:
if key not in global_cfg:
errors.append(f"缺少全局配置: {key}")
# 检查设备配置
if not devices:
errors.append("没有配置任何设备")
device_ids = []
listen_ports = []
for device in devices:
device_id = device.get('id')
if not device_id:
errors.append("设备缺少 id 字段")
continue
if device_id in device_ids:
errors.append(f"设备 id 重复: {device_id}")
device_ids.append(device_id)
required_device_fields = ['name', 'upc_ip', 'upc_port', 'listen_port']
for field in required_device_fields:
if field not in device:
errors.append(f"设备 {device_id} 缺少字段: {field}")
# 检查协议类型
protocol = device.get('protocol', 'tcp').lower()
if protocol not in ['tcp', 'udp']:
errors.append(f"设备 {device_id} 的协议类型无效: {protocol} (必须是 tcp 或 udp)")
if 'listen_port' in device:
port = device['listen_port']
if port in listen_ports:
errors.append(f"设备 {device_id} 的监听端口 {port} 与其他设备冲突")
listen_ports.append(port)
# 检查指令定义
if not commands:
warnings.append("没有定义任何指令")
# 检查映射
for cmd, op in mappings.items():
if op not in commands and not any(op == f"open{i}" or op == f"close{i}" for i in range(1, 9)):
warnings.append(f"映射 '{cmd}' -> '{op}' 的目标指令未在 commands 中定义")
# 检查模板文件是否存在
protocols = set()
for device in devices:
if device.get('enabled', True):
protocols.add(device.get('protocol', 'tcp').lower())
for protocol in protocols:
for template_type in ['listener', 'crond', 'sender']:
template_file = get_template_path(protocol, template_type)
if not os.path.exists(template_file):
warnings.append(f"模板文件不存在: {template_file}")
# 输出检查结果
if errors:
print("\n[!] 配置错误:")
for e in errors:
print(f" - {e}")
if warnings:
print("\n[*] 配置警告:")
for w in warnings:
print(f" - {w}")
if not errors and not warnings:
print("\n[✓] 配置检查通过")
return True
return len(errors) == 0
def main():
parser = argparse.ArgumentParser(description='UPC Resent 代码生成器 (支持 TCP/UDP)')
parser.add_argument('--check', action='store_true', help='仅检查配置,不生成文件')
args = parser.parse_args()
print("=" * 50)
print("UPC Resent 代码生成器 (支持 TCP/UDP)")
print("=" * 50)
# 加载配置
try:
config = load_config()
print("\n[✓] 配置文件加载成功")
except Exception as e:
print(f"\n[!] 加载配置文件失败: {e}")
sys.exit(1)
# 检查配置
if not check_config(config):
print("\n[!] 配置检查失败,请修正后重试")
sys.exit(1)
if args.check:
print("\n[✓] 仅检查模式,不生成文件")
sys.exit(0)
# 提取配置
global_config = config['global']
devices = [d for d in config['devices'] if d.get('enabled', True)]
# 确保目录存在
ensure_dirs(global_config['base_dir'])
print(f"[✓] 目录检查完成: {global_config['base_dir']}")
print("\n" + "-" * 50)
print("开始生成文件...")
print("-" * 50)
# 生成文件
generated_files = []
# 1. 为所有使用到的协议生成 sender.py
print("\n[生成发送模块]")
generated_files.extend(generate_all_senders(config, global_config))
# 2. 为每个设备生成监听服务和保活脚本
print("\n[生成设备服务]")
for device in devices:
print(f"\n处理设备: {device['name']} ({device['id']}) - {device.get('protocol', 'tcp').upper()}")
generated_files.append(generate_listener(device, global_config, config['mappings']))
generated_files.append(generate_crond(device, global_config))
# 3. 生成 crontab
print("\n[生成配置文件]")
generated_files.append(generate_crontab(config['devices'], global_config))
# 4. 生成启动脚本
generated_files.append(generate_start_script(devices, global_config))
print("\n" + "=" * 50)
print(f"[✓] 代码生成完成!共生成 {len(generated_files)} 个文件")
print("=" * 50)
print(f"\n部署目录: {global_config['base_dir']}")
print("\n使用方法:")
print(f" 1. 启动服务: ./{generated_files[-1]}")
print(f" 2. 配置 crontab: crontab crontab.txt")
print("\n支持的协议:")
protocols = set(d.get('protocol', 'tcp').upper() for d in devices)
for p in protocols:
print(f" - {p}")
if __name__ == '__main__':
main()

12
start.sh Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
# Auto-generated start script
# 启动所有监听服务
echo '启动 设备73-TCP (dev1) - TCP...'
su root -c "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev1.py &"
echo '启动 设备125-TCP (dev2) - TCP...'
su root -c "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev2.py &"
echo '启动 设备UDP示例 (dev3) - UDP...'
su root -c "/usr/bin/python3 /home/smart/pythonPJ/upc_resent/bin/dev3.py &"
echo "所有服务已启动"

View File

@@ -0,0 +1,54 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: {device_name} ({device_id})
import time
import logging
import os
import socket
import sys
# ====== 配置参数(从配置文件读取)======
TARGET_IP = '{tms_server_ip}'
TARGET_PORT = {listen_port}
LOG_FILE = '{base_dir}/log/crond-{device_id}.log'
RESTART_COMMAND = "{python_path} {base_dir}/bin/{device_id}.py &"
DEVICE_ID = '{device_id}'
# =========================
ISOTIMEFORMAT = '%Y-%m-%d %X'
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
def is_port_open(ip, port):
"""检查指定IP和端口是否可达"""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
try:
logging.debug(f"尝试连接到 {{ip}}:{{port}}...")
s.connect((ip, int(port)))
s.shutdown(socket.SHUT_RDWR)
print(f"[{{DEVICE_ID}}] 端口 {{port}} is open")
logging.info(f"端口 {{port}} is open")
return True
except (OSError, socket.timeout) as e:
print(f"[{{DEVICE_ID}}] 端口 {{port}} is down")
logging.warning(f"端口 {{port}} 检查失败: {{e}},尝试重启程序")
logging.info(f"执行重启命令: {{RESTART_COMMAND}}")
os.system(RESTART_COMMAND)
return False
except ValueError:
print(f"错误: 端口 '{{port}}' 不是有效的数字。")
logging.error(f"端口 '{{port}}' 不是有效的数字。")
return False
finally:
s.close()
if __name__ == '__main__':
logging.info(f"[{{DEVICE_ID}}] 启动端口检查程序,检查 {{TARGET_IP}}:{{TARGET_PORT}}")
print(f"[{{DEVICE_ID}}] 启动端口检查程序,检查 {{TARGET_IP}}:{{TARGET_PORT}}")
is_port_open(TARGET_IP, TARGET_PORT)

View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: {device_name} ({device_id}) - UDP Protocol
import time
import logging
import os
import socket
import sys
import subprocess
# ====== 配置参数(从配置文件读取)======
TARGET_IP = '{tms_server_ip}'
TARGET_PORT = {listen_port}
LOG_FILE = '{base_dir}/log/crond-{device_id}.log'
RESTART_COMMAND = "{python_path} {base_dir}/bin/{device_id}.py &"
DEVICE_ID = '{device_id}'
# =========================
ISOTIMEFORMAT = '%Y-%m-%d %X'
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s', datefmt=ISOTIMEFORMAT)
def is_udp_port_open(ip, port):
"""
检查UDP端口是否可用。
UDP是无连接的这里通过检查端口是否被占用或发送测试数据来判断。
"""
try:
# 尝试绑定到该端口,如果成功说明端口未被占用(服务未启动)
# 如果失败说明端口已被占用(服务正在运行)
test_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
test_sock.settimeout(1)
test_sock.bind((ip, int(port)))
test_sock.close()
# 如果绑定成功,说明服务未启动
print(f"[{{DEVICE_ID}}] UDP端口 {{port}} 未被占用,服务可能未运行")
logging.warning(f"UDP端口 {{port}} 未被占用,服务可能未运行,尝试重启程序")
logging.info(f"执行重启命令: {{RESTART_COMMAND}}")
os.system(RESTART_COMMAND)
return False
except OSError as e:
# 绑定失败,说明端口已被占用,服务正在运行
if "Address already in use" in str(e) or "98" in str(e):
print(f"[{{DEVICE_ID}}] UDP端口 {{port}} is open (已被占用,服务运行中)")
logging.info(f"UDP端口 {{port}} is open (服务运行中)")
return True
else:
print(f"[{{DEVICE_ID}}] 检查UDP端口 {{port}} 时发生错误: {{e}}")
logging.error(f"检查UDP端口 {{port}} 时发生错误: {{e}}")
return False
def check_process_running():
"""通过进程名检查服务是否正在运行"""
try:
# 检查是否有对应设备的Python进程在运行
cmd = f"ps aux | grep '{{DEVICE_ID}}.py' | grep -v grep"
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
if result.returncode == 0 and result.stdout.strip():
print(f"[{{DEVICE_ID}}] 进程检查: 服务正在运行")
logging.info(f"进程检查: 服务正在运行")
return True
else:
print(f"[{{DEVICE_ID}}] 进程检查: 服务未运行")
logging.warning(f"进程检查: 服务未运行,尝试重启")
logging.info(f"执行重启命令: {{RESTART_COMMAND}}")
os.system(RESTART_COMMAND)
return False
except Exception as e:
print(f"[{{DEVICE_ID}}] 进程检查失败: {{e}}")
logging.error(f"进程检查失败: {{e}}")
return False
if __name__ == '__main__':
logging.info(f"[{{DEVICE_ID}}] 启动UDP端口检查程序检查 {{TARGET_IP}}:{{TARGET_PORT}}")
print(f"[{{DEVICE_ID}}] 启动UDP端口检查程序检查 {{TARGET_IP}}:{{TARGET_PORT}}")
# 对于UDP优先使用进程检查方式
check_process_running()

View File

@@ -0,0 +1,104 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: {device_name} ({device_id})
import socket
import os
import time
import logging
import sys
# ====== 配置参数(从配置文件读取)======
TMS_SERVER_IP = '{tms_server_ip}'
TMS_PORT = {listen_port}
UPC_DEV_IP = '{upc_ip}'
UPC_DEV_PORT = '{upc_port}'
SENDER_FILE = '{base_dir}/bin/sender_tcp.py'
LOG_FILE = '{base_dir}/log/{device_id}.log'
PYTHON_PATH = '{python_path}'
DEVICE_ID = '{device_id}'
# =========================
BUFSIZE = 1024
# 配置日志
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
ISOTIMEFORMAT = '%Y-%m-%d %X'
# 命令映射表
COMMAND_MAPPINGS = {command_mappings}
def process_command(buf):
"""处理接收到的命令,返回对应的操作指令"""
buf = buf.strip()
if buf in COMMAND_MAPPINGS:
return COMMAND_MAPPINGS[buf]
return "nodata"
def main():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
sock.listen(500)
except OSError as e:
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
" 无法绑定端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
logging.error(logstr)
print(logstr)
sys.exit(1)
logging.info("服务启动,监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
print(f"[{{DEVICE_ID}}] 服务启动,监听 {{TMS_SERVER_IP}}:{{TMS_PORT}}")
while True:
connection, address = sock.accept()
try:
connection.settimeout(5)
buf_bytes = connection.recv(BUFSIZE)
buf = buf_bytes.decode('utf-8').strip()
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 收到客户端 " + address[0] + ":" + str(address[1]) + \
" 发送的指令: '" + str(buf) + "'"
logging.info(logstr)
print(logstr)
operation = process_command(buf)
if operation == "nodata":
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
logging.warning(logstr)
print(logstr)
connection.send(('Unknown command: %s' % buf).encode('utf-8'))
else:
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
logging.info(logstr)
print(logstr)
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
str(operation) + " " + str(LOG_FILE)
logging.info("执行外部命令: %s" % os_command)
os.system(os_command)
connection.send(('Command %s processed as %s' % (buf, operation)).encode('utf-8'))
except socket.timeout:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 客户端连接超时: " + address[0] + ":" + str(address[1]) + "==="
logging.warning(logstr)
print('time out')
except Exception as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 处理客户端 " + address[0] + ":" + str(address[1]) + \
" 请求时发生错误: " + str(e) + "==="
logging.error(logstr, exc_info=True)
print("Error processing request:", e)
connection.send(('Error processing command: %s' % str(e)).encode('utf-8'))
finally:
connection.close()
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
# Device: {device_name} ({device_id}) - UDP Protocol
import socket
import os
import time
import logging
import sys
# ====== 配置参数(从配置文件读取)======
TMS_SERVER_IP = '{tms_server_ip}'
TMS_PORT = {listen_port}
UPC_DEV_IP = '{upc_ip}'
UPC_DEV_PORT = {upc_port}
SENDER_FILE = '{base_dir}/bin/sender_udp.py'
LOG_FILE = '{base_dir}/log/{device_id}.log'
PYTHON_PATH = '{python_path}'
DEVICE_ID = '{device_id}'
# =========================
BUFSIZE = 1024
# 配置日志
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
ISOTIMEFORMAT = '%Y-%m-%d %X'
# 命令映射表
COMMAND_MAPPINGS = {command_mappings}
def process_command(buf):
"""处理接收到的命令,返回对应的操作指令"""
buf = buf.strip()
if buf in COMMAND_MAPPINGS:
return COMMAND_MAPPINGS[buf]
return "nodata"
def main():
# 创建 UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
sock.bind((TMS_SERVER_IP, int(TMS_PORT)))
except OSError as e:
logstr = "!!!!!ERROR!!!!!" + time.strftime(ISOTIMEFORMAT, time.localtime(time.time())) + \
" 无法绑定UDP端口 %s:%s - %s" % (TMS_SERVER_IP, TMS_PORT, e)
logging.error(logstr)
print(logstr)
sys.exit(1)
logging.info("UDP服务启动监听 %s:%s" % (TMS_SERVER_IP, TMS_PORT))
print(f"[{{DEVICE_ID}}] UDP服务启动监听 {{TMS_SERVER_IP}}:{{TMS_PORT}}")
while True:
try:
# UDP 使用 recvfrom 接收数据,同时获取客户端地址
buf_bytes, client_addr = sock.recvfrom(BUFSIZE)
buf = buf_bytes.decode('utf-8').strip()
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 收到UDP客户端 " + client_addr[0] + ":" + str(client_addr[1]) + \
" 发送的指令: '" + str(buf) + "'"
logging.info(logstr)
print(logstr)
operation = process_command(buf)
if operation == "nodata":
logstr = "===" + datetime_str + " 未知指令: '" + str(buf) + "'"
logging.warning(logstr)
print(logstr)
# 发送UDP响应
sock.sendto(('Unknown command: %s' % buf).encode('utf-8'), client_addr)
else:
logstr = "===" + datetime_str + " 映射到内部指令: '" + str(operation) + "'"
logging.info(logstr)
print(logstr)
# 执行发送指令的脚本
os_command = str(PYTHON_PATH) + " " + SENDER_FILE + " " + \
str(UPC_DEV_IP) + " " + str(UPC_DEV_PORT) + " " + \
str(operation) + " " + str(LOG_FILE)
logging.info("执行外部命令: %s" % os_command)
os.system(os_command)
# 发送UDP响应
sock.sendto(('Command %s processed as %s' % (buf, operation)).encode('utf-8'), client_addr)
except Exception as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = "===" + datetime_str + " 处理UDP请求时发生错误: " + str(e) + "==="
logging.error(logstr, exc_info=True)
print("Error processing UDP request:", e)
if __name__ == '__main__':
main()

119
templates/sender_tcp.py.tpl Normal file
View File

@@ -0,0 +1,119 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
import sys
import socket
import time
import logging
import telnetlib
def tcp_command_send(upc_addr, upc_command, data):
"""负责发送数据和接收一次响应"""
timeout = 2
socket.setdefaulttimeout(timeout)
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
logging.debug(f"尝试连接到 {{upc_addr[0]}}:{{upc_addr[1]}}...")
client.connect(upc_addr)
logging.debug(f"成功连接到 {{upc_addr[0]}}:{{upc_addr[1]}}。")
logging.info(f"正在发送命令 '{{upc_command}}' 到 {{upc_addr}}: {{data!r}} (原始字节)")
client.send(data)
logging.debug(f"数据发送完成。")
recv_buffer_size = 1024
response_bytes = b''
try:
logging.debug(f"尝试从 {{upc_addr}} 接收响应数据...")
response_bytes = client.recv(recv_buffer_size)
if response_bytes:
logging.info(f"从 {{upc_addr}} 收到原始响应字节: {{response_bytes!r}}")
try:
response_str = response_bytes.decode('utf-8', errors='ignore')
logging.info(f"从 {{upc_addr}} 收到解码响应字符串: '{{response_str}}'")
except Exception as decode_e:
logging.warning(f"解码从 {{upc_addr}} 收到的响应时发生错误: {{decode_e}}")
else:
logging.info(f"从 {{upc_addr}} 未收到响应数据 (连接可能已关闭或设备未发送)。")
except socket.timeout:
logging.warning(f"从 {{upc_addr}} 接收响应超时。")
except OSError as recv_e:
logging.error(f"从 {{upc_addr}} 接收响应时发生网络错误: {{recv_e}}")
client.close()
logging.debug(f"连接关闭。")
return True
except OSError as e:
logging.error(f"命令 '{{upc_command}}' 发送至 {{upc_addr}} 失败: {{e}}")
return False
# 指令定义表(从配置文件读取)
COMMAND_DEFINITIONS = {command_definitions}
def upc_send_command(upc_addr, upc_command, log_file):
"""将命令发送给终端设备"""
data = None
# 查找指令定义
if upc_command in COMMAND_DEFINITIONS:
hex_str = COMMAND_DEFINITIONS[upc_command]
data = bytes.fromhex(hex_str)
if data is None:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{{datetime_str}} 未知命令: {{upc_command}},没有对应的数据可发送。"
logging.warning(logstr)
print(logstr)
else:
i = 1
while i <= 3: # 尝试发送3次
if tcp_command_send(upc_addr, upc_command, data):
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{{datetime_str}} {{upc_command}}命令第{{i}}次发送成功"
logging.info(logstr)
return
else:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{{datetime_str}} {{upc_command}}命令第{{i}}次发送失败3秒后进行第{{i+1}}次尝试"
logging.warning(logstr)
time.sleep(3)
i = i + 1
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{{datetime_str}} {{upc_command}}命令在3次尝试后发送均失败"
logging.error(logstr)
if __name__ == '__main__':
ISOTIMEFORMAT = '%Y-%m-%d %X'
UPC_DEV_IP = sys.argv[1]
UPC_DEV_PORT = sys.argv[2]
upc_command = sys.argv[3]
LOG_FILE = sys.argv[4]
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
UPC_ADDR = (UPC_DEV_IP, int(UPC_DEV_PORT))
# 验证端口是否能Telnet通
try:
logging.debug(f"尝试通过 Telnet 检查端口 {{UPC_ADDR[0]}}:{{UPC_ADDR[1]}} 可访问性...")
tn = telnetlib.Telnet(UPC_DEV_IP, UPC_DEV_PORT)
tn.close()
logging.debug(f"端口 {{UPC_ADDR[0]}}:{{UPC_ADDR[1]}} Telnet 检查通过。")
except OSError as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"!!!!!ERROR!!!!!{{datetime_str}} {{UPC_ADDR}} 端口无法访问,请检查设备或网络连接: {{e}}!!!!!"
logging.error(logstr)
print(logstr)
except Exception as e:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"!!!!!ERROR!!!!!{{datetime_str}} {{UPC_ADDR}} Telnet检查时发生未知错误: {{e}}!!!!!"
logging.error(logstr, exc_info=True)
print(logstr)
else:
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)

107
templates/sender_udp.py.tpl Normal file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Auto-generated from template. DO NOT EDIT DIRECTLY!
import sys
import socket
import time
import logging
def udp_command_send(upc_addr, upc_command, data, timeout=2):
"""通过UDP发送数据并接收响应"""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(timeout)
try:
logging.debug(f"尝试发送UDP数据到 {{upc_addr[0]}}:{{upc_addr[1]}}...")
logging.info(f"正在发送UDP命令 '{{upc_command}}' 到 {{upc_addr}}: {{data!r}} (原始字节)")
sock.sendto(data, upc_addr)
logging.debug(f"UDP数据发送完成。")
# 尝试接收响应
recv_buffer_size = 1024
try:
logging.debug(f"等待从 {{upc_addr}} 接收UDP响应...")
response_bytes, addr = sock.recvfrom(recv_buffer_size)
if response_bytes:
logging.info(f"从 {{addr}} 收到UDP原始响应字节: {{response_bytes!r}}")
try:
response_str = response_bytes.decode('utf-8', errors='ignore')
logging.info(f"从 {{addr}} 收到UDP解码响应字符串: '{{response_str}}'")
except Exception as decode_e:
logging.warning(f"解码UDP响应时发生错误: {{decode_e}}")
else:
logging.info(f"未收到UDP响应数据。")
except socket.timeout:
logging.warning(f"接收UDP响应超时设备可能不返回响应这通常是正常的。")
except OSError as recv_e:
logging.error(f"接收UDP响应时发生网络错误: {{recv_e}}")
sock.close()
logging.debug(f"UDP socket关闭。")
return True
except OSError as e:
logging.error(f"UDP命令 '{{upc_command}}' 发送至 {{upc_addr}} 失败: {{e}}")
return False
finally:
try:
sock.close()
except:
pass
# 指令定义表(从配置文件读取)
COMMAND_DEFINITIONS = {command_definitions}
def upc_send_command(upc_addr, upc_command, log_file):
"""将命令发送给终端设备"""
data = None
# 查找指令定义
if upc_command in COMMAND_DEFINITIONS:
hex_str = COMMAND_DEFINITIONS[upc_command]
data = bytes.fromhex(hex_str)
if data is None:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{{datetime_str}} 未知命令: {{upc_command}},没有对应的数据可发送。"
logging.warning(logstr)
print(logstr)
else:
i = 1
while i <= 3: # 尝试发送3次
if udp_command_send(upc_addr, upc_command, data):
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{{datetime_str}} {{upc_command}}命令第{{i}}次发送成功"
logging.info(logstr)
return
else:
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{{datetime_str}} {{upc_command}}命令第{{i}}次发送失败3秒后进行第{{i+1}}次尝试"
logging.warning(logstr)
time.sleep(3)
i = i + 1
datetime_str = time.strftime(ISOTIMEFORMAT, time.localtime(time.time()))
logstr = f"{{datetime_str}} {{upc_command}}命令在3次尝试后发送均失败"
logging.error(logstr)
if __name__ == '__main__':
ISOTIMEFORMAT = '%Y-%m-%d %X'
UPC_DEV_IP = sys.argv[1]
UPC_DEV_PORT = int(sys.argv[2])
upc_command = sys.argv[3]
LOG_FILE = sys.argv[4]
logging.basicConfig(filename=LOG_FILE, filemode="a", level=logging.DEBUG)
UPC_ADDR = (UPC_DEV_IP, UPC_DEV_PORT)
# UDP 是无连接的无需像TCP那样预先检查端口连通性
# 直接发送数据
logging.info(f"UDP模式准备发送命令到 {{UPC_ADDR}}")
upc_send_command(UPC_ADDR, upc_command, LOG_FILE)

3
upcstart.sh Normal file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
su root -c "/usr/bin/python /opt/upc_resent/bin/192.168.8.73.py &"
su root -c "/usr/bin/python /opt/upc_resent/bin/192.168.8.125.py &"