更新proto
This commit is contained in:
296
main.py
296
main.py
@@ -7,305 +7,19 @@
|
||||
|
||||
import machine
|
||||
import time
|
||||
import struct
|
||||
import client_pb
|
||||
# import struct # 根据需要保留或删除
|
||||
# import client_pb # 根据需要保留或删除
|
||||
|
||||
# 初始化RS485串口
|
||||
# 使用UART2,连接到ESP32的GPIO16(RX)和GPIO17(TX)
|
||||
rs485_uart = machine.UART(2, baudrate=9600, bits=8, parity=None, stop=1, rx=16, tx=17)
|
||||
rs485_uart.init()
|
||||
|
||||
# RS485收发控制引脚
|
||||
rs485_re_de_pin = machine.Pin(5, machine.Pin.OUT)
|
||||
rs485_re_de_pin.value(0) # 默认接收模式
|
||||
|
||||
# ESP32设备地址(应该唯一标识这个ESP32设备)
|
||||
ESP32_ADDRESS = 1
|
||||
|
||||
# LoRaWAN模块地址
|
||||
LORA_MODULE_ADDRESS = 254
|
||||
|
||||
def receive_lora_message():
|
||||
"""
|
||||
接收来自LoRaWAN模块的消息
|
||||
返回: 字节数据
|
||||
"""
|
||||
# 在共享的RS485总线上监听来自LoRaWAN模块的消息
|
||||
# 需要检查消息是否是发给本设备的
|
||||
buffer = bytearray()
|
||||
|
||||
# 持续监听,不设置超时
|
||||
while rs485_uart.any():
|
||||
data = rs485_uart.read()
|
||||
if data:
|
||||
buffer.extend(data)
|
||||
# 简单的帧检测逻辑
|
||||
if len(buffer) >= 3 and buffer[0] == 0xAA and buffer[-1] == 0x55:
|
||||
# 检查地址是否匹配
|
||||
if len(buffer) >= 3 and buffer[2] == ESP32_ADDRESS:
|
||||
# 提取有效数据(去掉帧头、地址、校验和帧尾)
|
||||
return buffer[3:-2]
|
||||
else:
|
||||
break # 没有更多数据可读
|
||||
|
||||
return None
|
||||
|
||||
def send_lora_message(data):
|
||||
"""
|
||||
通过LoRaWAN模块发送消息
|
||||
|
||||
参数:
|
||||
data: 要发送的字节数据
|
||||
"""
|
||||
# 切换到发送模式
|
||||
rs485_re_de_pin.value(1)
|
||||
time.sleep_ms(10)
|
||||
|
||||
try:
|
||||
# 构造发送给LoRaWAN模块的RS485帧
|
||||
frame = bytearray()
|
||||
frame.append(0xAA) # 帧头
|
||||
frame.append(LORA_MODULE_ADDRESS & 0xFF) # LoRaWAN模块地址
|
||||
frame.append(ESP32_ADDRESS & 0xFF) # 本设备地址(作为源地址)
|
||||
|
||||
# 添加数据
|
||||
frame.extend(data)
|
||||
|
||||
# 计算校验和
|
||||
checksum = sum(frame[1:]) & 0xFF
|
||||
frame.append(checksum)
|
||||
frame.append(0x55) # 帧尾
|
||||
|
||||
# 发送命令
|
||||
rs485_uart.write(frame)
|
||||
print(f"通过LoRa发送数据: {frame.hex()}")
|
||||
|
||||
finally:
|
||||
# 切换回接收模式
|
||||
time.sleep_ms(10)
|
||||
rs485_re_de_pin.value(0)
|
||||
|
||||
def send_rs485_command(bus_number, bus_address, command, channel=None):
|
||||
"""
|
||||
发送命令到RS485总线上的设备
|
||||
|
||||
参数:
|
||||
bus_number: 总线号
|
||||
bus_address: 设备地址
|
||||
command: 命令内容
|
||||
channel: 通道号(可选)
|
||||
"""
|
||||
# 切换到发送模式
|
||||
rs485_re_de_pin.value(1)
|
||||
time.sleep_ms(10)
|
||||
|
||||
try:
|
||||
# 构造RS485命令帧
|
||||
frame = bytearray()
|
||||
frame.append(0xAA) # 帧头
|
||||
frame.append(bus_number & 0xFF) # 总线号
|
||||
frame.append(bus_address & 0xFF) # 设备地址
|
||||
|
||||
# 添加命令数据
|
||||
if isinstance(command, str):
|
||||
frame.extend(command.encode('utf-8'))
|
||||
elif isinstance(command, bytes):
|
||||
frame.extend(command)
|
||||
elif isinstance(command, int):
|
||||
frame.append(command & 0xFF)
|
||||
|
||||
# 如果有通道号,则添加
|
||||
if channel is not None:
|
||||
frame.append(channel & 0xFF)
|
||||
|
||||
# 计算校验和
|
||||
checksum = sum(frame[1:]) & 0xFF
|
||||
frame.append(checksum)
|
||||
frame.append(0x55) # 帧尾
|
||||
|
||||
# 发送命令
|
||||
rs485_uart.write(frame)
|
||||
print(f"已发送RS485命令: {frame.hex()}")
|
||||
|
||||
finally:
|
||||
# 切换回接收模式
|
||||
time.sleep_ms(10)
|
||||
rs485_re_de_pin.value(0)
|
||||
|
||||
def collect_sensor_data(bus_number, bus_address):
|
||||
"""
|
||||
从传感器收集数据
|
||||
|
||||
参数:
|
||||
bus_number: 总线号
|
||||
bus_address: 传感器地址
|
||||
|
||||
返回:
|
||||
传感器数据
|
||||
"""
|
||||
# 切换到发送模式
|
||||
rs485_re_de_pin.value(1)
|
||||
time.sleep_ms(10)
|
||||
|
||||
try:
|
||||
# 构造读取传感器数据的命令
|
||||
frame = bytearray([0xAA, bus_number & 0xFF, bus_address & 0xFF, 0x01, 0x00, 0x55])
|
||||
rs485_uart.write(frame)
|
||||
print(f"已发送传感器读取命令: {frame.hex()}")
|
||||
|
||||
# 等待响应
|
||||
time.sleep_ms(50) # 短暂等待响应
|
||||
|
||||
# 读取传感器返回的数据
|
||||
buffer = bytearray()
|
||||
|
||||
while rs485_uart.any():
|
||||
data = rs485_uart.read()
|
||||
if data:
|
||||
buffer.extend(data)
|
||||
# 简单的帧检测逻辑
|
||||
if len(buffer) >= 3 and buffer[0] == 0xAA and buffer[-1] == 0x55:
|
||||
# 检查地址是否匹配
|
||||
if len(buffer) >= 3 and buffer[2] == ESP32_ADDRESS:
|
||||
# 提取有效数据
|
||||
if len(buffer) >= 5:
|
||||
# 模拟一个浮点数值
|
||||
value = float(buffer[3] + (buffer[4] << 8)) / 100.0
|
||||
return value
|
||||
else:
|
||||
break
|
||||
|
||||
if len(buffer) > 0:
|
||||
print(f"传感器响应不完整: {buffer.hex()}")
|
||||
else:
|
||||
print("传感器无响应")
|
||||
return None
|
||||
|
||||
finally:
|
||||
# 切换回接收模式
|
||||
time.sleep_ms(10)
|
||||
rs485_re_de_pin.value(0)
|
||||
|
||||
def parse_instruction(data):
|
||||
"""
|
||||
解析来自LoRaWAN的指令
|
||||
|
||||
参数:
|
||||
data: protobuf编码的指令数据
|
||||
|
||||
返回:
|
||||
解析后的指令对象,失败时返回None
|
||||
"""
|
||||
try:
|
||||
instruction = client_pb.decode_instruction(data)
|
||||
return instruction
|
||||
except Exception as e:
|
||||
print(f"解析指令失败: {e}")
|
||||
return None
|
||||
|
||||
def handle_switch_instruction(switch_msg):
|
||||
"""
|
||||
处理开关指令
|
||||
|
||||
参数:
|
||||
switch_msg: Switch消息字典
|
||||
"""
|
||||
action = switch_msg.get('device_action', '')
|
||||
bus_number = switch_msg.get('bus_number', 0)
|
||||
bus_address = switch_msg.get('bus_address', 0)
|
||||
channel = switch_msg.get('relay_channel', 0)
|
||||
|
||||
print(f"处理开关指令: 动作={action}, 总线={bus_number}, 地址={bus_address}, 通道={channel}")
|
||||
|
||||
if action.upper() == "ON":
|
||||
# 发送开启设备命令
|
||||
send_rs485_command(bus_number, bus_address, 0x01, channel)
|
||||
elif action.upper() == "OFF":
|
||||
# 发送关闭设备命令
|
||||
send_rs485_command(bus_number, bus_address, 0x00, channel)
|
||||
else:
|
||||
# 其他自定义命令
|
||||
send_rs485_command(bus_number, bus_address, action, channel)
|
||||
|
||||
def handle_collect_instruction(collect_msg):
|
||||
"""
|
||||
处理采集指令
|
||||
|
||||
参数:
|
||||
collect_msg: Collect消息字典
|
||||
"""
|
||||
bus_number = collect_msg.get('bus_number', 0)
|
||||
bus_address = collect_msg.get('bus_address', 0)
|
||||
|
||||
print(f"处理采集指令: 总线={bus_number}, 地址={bus_address}")
|
||||
|
||||
# 从传感器采集数据
|
||||
value = collect_sensor_data(bus_number, bus_address)
|
||||
|
||||
if value is not None:
|
||||
# 构造Collect响应消息
|
||||
collect_data = client_pb.encode_collect(bus_number, bus_address, value)
|
||||
|
||||
# 构造Instruction消息包装Collect数据
|
||||
instruction_data = client_pb.encode_instruction(client_pb.METHOD_TYPE_COLLECT, collect_data)
|
||||
|
||||
# 发送回上位机
|
||||
send_lora_message(instruction_data)
|
||||
else:
|
||||
print("采集数据失败")
|
||||
|
||||
def process_instruction(instruction):
|
||||
"""
|
||||
处理解析后的指令
|
||||
|
||||
参数:
|
||||
instruction: 解析后的指令字典
|
||||
"""
|
||||
method = instruction.get('method', -1)
|
||||
|
||||
if method == client_pb.METHOD_TYPE_SWITCH:
|
||||
# 处理开关指令
|
||||
if 'data' in instruction:
|
||||
switch_msg = client_pb.decode_switch(instruction['data'])
|
||||
handle_switch_instruction(switch_msg)
|
||||
else:
|
||||
print("开关指令缺少data字段")
|
||||
elif method == client_pb.METHOD_TYPE_COLLECT:
|
||||
# 处理采集指令
|
||||
if 'data' in instruction:
|
||||
collect_msg = client_pb.decode_collect(instruction['data'])
|
||||
handle_collect_instruction(collect_msg)
|
||||
else:
|
||||
print("采集指令缺少data字段")
|
||||
else:
|
||||
print(f"不支持的指令类型: {method}")
|
||||
|
||||
def main_loop():
|
||||
"""
|
||||
主循环
|
||||
"""
|
||||
print("猪舍控制系统启动...")
|
||||
print(f"设备地址: {ESP32_ADDRESS}")
|
||||
|
||||
while True:
|
||||
# 接收LoRaWAN消息
|
||||
lora_data = receive_lora_message()
|
||||
|
||||
if lora_data:
|
||||
print(f"收到LoRaWAN消息: {lora_data.hex()}")
|
||||
|
||||
# 解析指令
|
||||
instruction = parse_instruction(lora_data)
|
||||
|
||||
if instruction:
|
||||
# 处理指令
|
||||
process_instruction(instruction)
|
||||
else:
|
||||
print("无效的指令数据")
|
||||
|
||||
# 其他周期性任务可以放在这里
|
||||
# 例如定时采集传感器数据等
|
||||
time.sleep(0.01) # 短暂休眠避免过度占用CPU
|
||||
# 在这里添加你的逻辑
|
||||
time.sleep(1) # 避免空循环占用过多CPU
|
||||
|
||||
# 程序入口
|
||||
if __name__ == "__main__":
|
||||
@@ -314,4 +28,4 @@ if __name__ == "__main__":
|
||||
except KeyboardInterrupt:
|
||||
print("程序被中断")
|
||||
except Exception as e:
|
||||
print(f"程序异常: {e}")
|
||||
print(f"程序异常: {e}")
|
||||
|
||||
Reference in New Issue
Block a user