first commit
This commit is contained in:
BIN
test/__pycache__/protocol.cpython-312.pyc
Normal file
BIN
test/__pycache__/protocol.cpython-312.pyc
Normal file
Binary file not shown.
23
test/control.py
Normal file
23
test/control.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import socket
|
||||
from protocol import build_frame
|
||||
|
||||
SERVER_IP = '127.0.0.1'
|
||||
SERVER_PORT = 9000
|
||||
|
||||
TARGET_DEVICE = 10000052
|
||||
|
||||
# 控制 2、3 开;5 关
|
||||
payload = bytes([
|
||||
0x02, 0x01,
|
||||
0x03, 0x01,
|
||||
0x05, 0x00
|
||||
])
|
||||
|
||||
frame = build_frame(0xA0, TARGET_DEVICE, payload)
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.connect((SERVER_IP, SERVER_PORT))
|
||||
# CTRL + device_id + frame
|
||||
msg = b'CTRL' + TARGET_DEVICE.to_bytes(4, 'little') + frame
|
||||
s.sendall(msg)
|
||||
print("[CONTROL] send command")
|
||||
29
test/device.py
Normal file
29
test/device.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import socket
|
||||
import time
|
||||
from protocol import build_frame
|
||||
|
||||
SERVER_IP = '127.0.0.1'
|
||||
SERVER_PORT = 9000
|
||||
|
||||
DEVICE_ID = 10000052 # 每个设备改这个
|
||||
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.connect((SERVER_IP, SERVER_PORT))
|
||||
print(f"[DEVICE {DEVICE_ID}] connected")
|
||||
|
||||
while True:
|
||||
# 发送心跳
|
||||
hb = build_frame(0x00, DEVICE_ID)
|
||||
s.sendall(hb)
|
||||
|
||||
# 接收控制指令
|
||||
s.settimeout(1)
|
||||
try:
|
||||
data = s.recv(1024)
|
||||
if data and data[8] == 0xA0:
|
||||
print(f"[DEVICE {DEVICE_ID}] recv A0:", data.hex(' '))
|
||||
# 这里执行你的 IO / GPIO
|
||||
except socket.timeout:
|
||||
pass
|
||||
|
||||
time.sleep(3)
|
||||
22
test/protocol.py
Normal file
22
test/protocol.py
Normal file
@@ -0,0 +1,22 @@
|
||||
def sum16(data: bytes) -> int:
|
||||
return sum(data) & 0xFFFF
|
||||
|
||||
|
||||
def build_frame(cmd: int, device_id: int, payload: bytes = b"") -> bytes:
|
||||
frame = bytearray()
|
||||
frame += b'\x23\xA9' # 帧头
|
||||
frame += b'\x00\x00' # 长度占位
|
||||
frame += device_id.to_bytes(4, 'little')
|
||||
frame += bytes([cmd])
|
||||
frame += payload
|
||||
|
||||
length = len(frame) + 2 # 加上校验和
|
||||
frame[2:4] = length.to_bytes(2, 'big')
|
||||
|
||||
s = sum16(frame)
|
||||
frame += s.to_bytes(2, 'big')
|
||||
return bytes(frame)
|
||||
|
||||
|
||||
def parse_device_id(frame: bytes) -> int:
|
||||
return int.from_bytes(frame[4:8], 'little')
|
||||
41
test/server.py
Normal file
41
test/server.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import socket
|
||||
import threading
|
||||
|
||||
HOST = "127.0.0.1"
|
||||
PORT = 9000
|
||||
|
||||
devices = {} # device_id -> socket
|
||||
|
||||
def handle_client(conn):
|
||||
while True:
|
||||
data = conn.recv(1024)
|
||||
if not data:
|
||||
break
|
||||
|
||||
# 前 4 字节当 device_id(小端)
|
||||
device_id = int.from_bytes(data[4:8], "little")
|
||||
print("[SERVER] recv for device:", device_id, data.hex(" "))
|
||||
|
||||
if device_id in devices:
|
||||
devices[device_id].send(data)
|
||||
print("[SERVER] forwarded to device", device_id)
|
||||
|
||||
def accept_loop():
|
||||
s = socket.socket()
|
||||
s.bind((HOST, PORT))
|
||||
s.listen()
|
||||
print("[SERVER] listening")
|
||||
|
||||
while True:
|
||||
conn, _ = s.accept()
|
||||
|
||||
# 第一次 recv 认为是设备注册
|
||||
first = conn.recv(1024)
|
||||
if first.startswith(b"DEVICE"):
|
||||
device_id = int(first.split(b":")[1])
|
||||
devices[device_id] = conn
|
||||
print(f"[SERVER] device {device_id} registered")
|
||||
else:
|
||||
threading.Thread(target=handle_client, args=(conn,), daemon=True).start()
|
||||
|
||||
accept_loop()
|
||||
149
test/test_play_data.py
Normal file
149
test/test_play_data.py
Normal file
@@ -0,0 +1,149 @@
|
||||
import time
|
||||
import requests
|
||||
import pandas as pd
|
||||
from io import BytesIO
|
||||
|
||||
|
||||
class CheckStation:
|
||||
def __init__(self):
|
||||
self.station_num = 0
|
||||
self.last_data = None
|
||||
|
||||
def get_measure_data(self):
|
||||
# 模拟获取测量数据
|
||||
pass
|
||||
|
||||
def add_transition_point(self):
|
||||
# 添加转点逻辑
|
||||
print("添加转点")
|
||||
return True
|
||||
|
||||
def get_excel_from_url(self, url):
|
||||
"""
|
||||
从URL获取Excel文件并解析为字典
|
||||
Excel只有一列数据(A列),每行是站点值
|
||||
|
||||
Args:
|
||||
url: Excel文件的URL地址
|
||||
|
||||
Returns:
|
||||
dict: 解析后的站点数据字典 {行号: 值},失败返回None
|
||||
"""
|
||||
try:
|
||||
print(f"正在从URL获取数据: {url}")
|
||||
response = requests.get(url, timeout=30)
|
||||
response.raise_for_status() # 检查请求是否成功
|
||||
|
||||
# 使用pandas读取Excel数据,指定没有表头,只读第一个sheet
|
||||
excel_data = pd.read_excel(
|
||||
BytesIO(response.content),
|
||||
header=None, # 没有表头
|
||||
sheet_name=0, # 只读取第一个sheet
|
||||
dtype=str # 全部作为字符串读取
|
||||
)
|
||||
|
||||
station_dict = {}
|
||||
|
||||
# 解析Excel数据:使用行号+1作为站点编号,A列的值作为站点值
|
||||
print("解析Excel数据(使用行号作为站点编号)...")
|
||||
for index, row in excel_data.iterrows():
|
||||
station_num = index + 1 # 行号从1开始作为站点编号
|
||||
station_value = str(row[0]).strip() if pd.notna(row[0]) else ""
|
||||
|
||||
if station_value: # 只保存非空值
|
||||
station_dict[station_num] = station_value
|
||||
|
||||
print(f"成功解析Excel,共{len(station_dict)}条数据")
|
||||
return station_dict
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"请求URL失败: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"解析Excel失败: {e}")
|
||||
return None
|
||||
|
||||
def check_station_exists(self, station_data: dict, station_num: int) -> str:
|
||||
"""
|
||||
根据站点编号检查该站点的值是否以Z开头
|
||||
|
||||
Args:
|
||||
station_data: 站点数据字典 {编号: 值}
|
||||
station_num: 要检查的站点编号
|
||||
|
||||
Returns:
|
||||
str: 如果站点存在且以Z开头返回"add",否则返回"pass"
|
||||
"""
|
||||
if station_num not in station_data:
|
||||
print(f"站点{station_num}不存在")
|
||||
return "error"
|
||||
|
||||
value = station_data[station_num]
|
||||
str_value = str(value).strip()
|
||||
is_z = str_value.upper().startswith('Z')
|
||||
|
||||
result = "add" if is_z else "pass"
|
||||
print(f"站点{station_num}: {value} -> {result}")
|
||||
return result
|
||||
|
||||
|
||||
def run(self):
|
||||
last_station_num = 0
|
||||
|
||||
url = f"https://database.yuxindazhineng.com/team-bucket/69378c5b4f42d83d9504560d/前测点表/20260309/CDWZQ-2标-龙家沟左线大桥-0-11号墩-平原.xlsx"
|
||||
station_data = self.get_excel_from_url(url)
|
||||
print(station_data)
|
||||
station_quantity = len(station_data)
|
||||
over_station_num = 0
|
||||
over_station_list = []
|
||||
while over_station_num < station_quantity:
|
||||
try:
|
||||
# 键盘输出线路编号
|
||||
station_num_input = input("请输入线路编号:")
|
||||
if not station_num_input.isdigit(): # 检查输入是否为数字
|
||||
print("输入错误:请输入一个整数")
|
||||
continue
|
||||
station_num = int(station_num_input) # 转为整数
|
||||
|
||||
if station_num in over_station_list:
|
||||
print("已处理该站点,跳过")
|
||||
continue
|
||||
|
||||
if last_station_num == station_num:
|
||||
print("输入与上次相同,跳过处理")
|
||||
continue
|
||||
last_station_num = station_num
|
||||
|
||||
result = self.check_station_exists(station_data, station_num)
|
||||
if result == "error":
|
||||
print("处理错误:站点不存在")
|
||||
# 错误处理逻辑,比如记录日志、发送警报等
|
||||
elif result == "add":
|
||||
print("执行添加操作")
|
||||
# 添加转点
|
||||
if not self.add_transition_point():
|
||||
print("添加转点失败")
|
||||
# 可以决定是否继续循环
|
||||
continue
|
||||
over_station_num += 1
|
||||
else: # result == "pass"
|
||||
print("跳过处理")
|
||||
over_station_num += 1
|
||||
|
||||
over_station_list.append(station_num)
|
||||
|
||||
# 可以添加适当的延时,避免CPU占用过高
|
||||
# time.sleep(1)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("程序被用户中断")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"发生错误: {e}")
|
||||
time.sleep(20)
|
||||
# 错误处理,可以继续循环或退出
|
||||
print(f"已处理{over_station_num}个站点")
|
||||
|
||||
if __name__ == "__main__":
|
||||
monitor = StationMonitor()
|
||||
monitor.run()
|
||||
Reference in New Issue
Block a user