帮我把如下代码改写为python2环境:#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# ---------------------------------------------------------
# Copyright (C), 2025, Lianzhou International Co.,Ltd.
#
# description: GWSChamberCtrl.py for GWS chamber
# Author: zhouziqi@tp-link.com.hk
# history:
# 2025/6/9 14:20, zhouziqi@tp-link.com.hk, Created.
# ---------------------------------------------------------
import serial
import time
import logging
from typing import List
class Program:
"""老化箱程序步骤模型"""
def __init__(self, temperature: float, humidity: float, hour: int, minute: int):
self.temperature = temperature
self.humidity = humidity
self.hour = hour
self.minute = minute
class GWSChamberCtrl(object):
#串口命令常量
COMMAND_GET_TEMP = "1, TEMP?"
COMMAND_GET_HUMI = "1, HUMI?"
COMMAND_GET_PRGM = "1, PRGM SET?"
COMMAND_STOP_DEV = "1, MODE, OFF"
COMMAND_EXECUTE_PROGRAM = "1, PRGM, RUN, RAM:1, STEP1"
COMMAND_SET_CONSTANT_TEMP = "1, TEMP"
COMMAND_SET_MODE_CONSTANT = "1, MODE, CONSTANT"
# 特殊响应标识
NA_PREFIX = "NA:"
NOT_READY_CODE = "NA:CONT NOT READY-1"
# 设置成功响应标识
OK_SIGN = "[b'OK:1"
def __init__(self, port, baudrate=19200, bytesize=8, stopbits=1, parity=None):
self.logger = logging.getLogger()
if not logging.root.handlers:
self.logger.setLevel(logging.INFO)
self.console_handler = logging.StreamHandler()
self.formatter = logging.Formatter(u"[%(asctime)s] [%(levelname)s] %(message)s", u"%m-%d %H:%M:%S")
self.console_handler.setFormatter(self.formatter)
self.logger.addHandler(self.console_handler)
self.port = port
self.baudrate = baudrate
self.bytesize = bytesize
self.stopbits = stopbits
self.parity = parity
try:
self.ser = self.open_serial(port=self.port, baudrate=self.baudrate, bytesize=self.bytesize,
stopbits=self.stopbits, parity=self.parity)
self.logger.info("Serial Port Opened")
except Exception as e:
self.logger.error("Error Opening Serial Port: ", e)
def SInterval(self):
"""命令执行间隔延时"""
time.sleep(0.5)
def open_serial(self, port, baudrate, bytesize, stopbits, parity):
"""open serial connection"""
try:
if port is None:
port = self.port
else:
self.port = port
if baudrate is None:
baudrate = self.baudrate
else:
self.baudrate = baudrate
if bytesize is None:
bytesize = self.bytesize
else:
self.bytesize = bytesize
if stopbits is None:
stopbits = self.stopbits
else:
self.stopbits = stopbits
if parity is None:
parity = self.parity
else:
self.parity = parity
bytesize = serial.EIGHTBITS if bytesize == 8 else serial.SEVENBITS
parity = serial.PARITY_NONE if parity is None else parity
stopbits = serial.STOPBITS_ONE if stopbits == 1 else serial.STOPBITS_TWO
ser = serial.Serial(port=port, baudrate=baudrate, bytesize=bytesize, parity=parity,
stopbits=stopbits, timeout=1, xonxoff=False)
self.logger.info('%s has opened, baudrate is %s' % (port, baudrate))
return ser
except serial.SerialException as e:
self.logger.error('Can\'t open %s: %s' % (port,e))
raise
def send_command(self, command):
"""send command to the serial port"""
try:
if self.ser is not None and self.ser.isOpen():
self.ser.write(command.encode('utf-8'))
self.logger.info('Send command:<%s>' % command)
time.sleep(0.5)
data = self.receive_data()
return data
else:
self.logger.error('Serial port is closed or not exist')
except Exception as e:
self.logger.error('Error sending command <%s>: %s' % (command, e))
raise
def receive_data(self):
"""get data from the serial port"""
try:
if self.ser is not None and self.ser.isOpen():
data = self.ser.readlines()
self.logger.info('Receive data:<%s>' % data)
return data
else:
self.logger.error('Serial port is closed or not exist')
return None
except Exception as e:
self.logger.error('Error receiving data: %s' % e)
raise
def close_serial(self):
"""close the serial connection"""
try:
if self.ser is not None and self.ser.isOpen():
self.ser.close()
self.logger.info('Serial port has been closed')
else:
self.logger.error('Serial port is already closed')
except Exception as e:
self.logger.error('Error closing serial port: %s' % e)
raise
def get_temperature(self):
"""
:get chamber\'s temperature
:return: [monitored temperature, target temperature, highlimit temperature, lowlimit temperature]
"""
try:
# 发送温度查询命令
response = self.send_command(command=self.COMMAND_GET_TEMP)
# 验证响应格式
if not response or not isinstance(response, list):
raise ValueError(f"Invalid response format: {response}")
# 从列表中取出第一个元素(字符串)
data_str = str(response[0].decode('utf-8'))
# 分割字符串并转换为浮点数
temp_values = data_str.strip().split(',')
# 验证分割结果数量
if len(temp_values) != 4:
raise ValueError(f"Expected 4 temperature values, got {len(temp_values)}")
# 将每个值转换为浮点数
temperatures = [float(value.strip()) for value in temp_values]
return temperatures
except ValueError as ve:
self.logger.error(f"Temperature value error: {ve}")
# 可在此处添加默认值返回或重新抛出异常
raise
except Exception as e:
self.logger.error(f"Error getting temperature: {e}")
raise
def get_current_temperature(self,temperature_data):
"""
从温度数据列表中获取第一个数据(当前温度)
参数:
temperature_data (list): 包含温度数据的列表,格式为 [监控温度, 目标温度, 高温限制, 低温限制]
返回:
float: 当前温度值
"""
try:
# 验证输入是否为列表
if not isinstance(temperature_data, list):
raise TypeError("参数必须是列表类型")
# 验证列表是否非空
if len(temperature_data) < 1:
raise IndexError("温度数据列表不能为空")
# 获取第一个元素并赋值给current_temp
current_temp = temperature_data[0]
# 验证数据类型是否是数值
if not isinstance(current_temp, (int, float)):
raise TypeError("第一个温度数据必须是数值类型")
return current_temp
except Exception as e:
self.logger.error(f"Error getting current temperature: {e}")
raise
def get_humidity(self):
"""
:get chamber\'s humidity
:return: [monitored humidity, target humidity, highlimit humidity, lowlimit humidity]
"""
try:
# 发送湿度查询命令
response = self.send_command(command=self.COMMAND_GET_HUMI)
response_decode = response[0].decode('utf-8')
if response_decode == self.NOT_READY_CODE:
self.logger.error("无法查询湿度: 设备不支持或未开启湿度控制")
response = [0, 0, 0, 0]
return response
# 验证响应格式
if not response or not isinstance(response, list):
raise ValueError(f"Invalid response format: {response}")
# 从列表中取出第一个元素(字符串)
data_str = str(response[0].decode('utf-8'))
# 分割字符串并转换为浮点数
humi_values = data_str.strip().split(',')
# 验证分割结果数量
if len(humi_values) != 4:
raise ValueError(f"Expected 4 humidity values, got {len(humi_values)}")
# 将每个值转换为浮点数
humiditys = [float(value.strip()) for value in humi_values]
return humiditys
except ValueError as ve:
self.logger.error(f"humidity value error: {ve}")
# 可在此处添加默认值返回或重新抛出异常
raise
except Exception as e:
self.logger.error(f"Error getting humidity: {e}")
raise
def get_current_humidity(self,humidity_data):
"""
从湿度数据列表中获取第一个数据(当前湿度)
参数:
humidity_data (list): 包含湿度数据的列表,格式为 [监控湿度, 目标湿度, 高温限制, 低温限制]
返回:
float: 当前湿度值
"""
try:
# 验证输入是否为列表
if not isinstance(humidity_data, list):
raise TypeError("参数必须是列表类型")
# 验证列表是否非空
if len(humidity_data) < 1:
raise IndexError("湿度数据列表不能为空")
# 获取第一个元素并赋值给current_humi
current_humi = humidity_data[0]
# 验证数据类型是否是数值
if not isinstance(current_humi, (int, float)):
raise TypeError("第一个湿度数据必须是数值类型")
return current_humi
except Exception as e:
self.logger.error(f"Error getting current humidity: {e}")
raise
def constant_mode_set(self, constant_target_temp, constant_target_humi):
"""
设置定值模式下老化箱的目标温度和湿度
参数:
constant_target_temp (float): 要设置的目标温度值
constant_target_humi (float): 要设置的目标湿度值
返回:
str: 发送到老化箱的完整指令字符串
功能:
根据输入的目标温度值,构建"1, TEMP, SX.X"格式的指令
根据输入的目标湿度值,构建"1, HUMI, SX.X"格式的指令
"""
try:
# 温度设置
# 验证输入是否为数值类型
if not isinstance(constant_target_temp, (int, float)):
raise TypeError("目标温度必须是数值类型")
# 格式化温度值为带一位小数的字符串
formatted_temp = f"{constant_target_temp:.1f}"
# 构建完整的指令字符串
constant_temp_command = f"1, TEMP, S{formatted_temp}"
# 湿度设置
# 验证输入是否为数值类型
if not isinstance(constant_target_humi, (int, float)):
raise TypeError("目标湿度必须是数值类型")
# 格式化湿度值为带一位小数的字符串
formatted_humi = f"{constant_target_humi:.1f}"
# 构建完整的指令字符串
constant_humi_command = f"1, HUMI, S{formatted_humi}"
# 发送指令到设备
# 通过send_command方法来实际发送指令
self.send_command(command=constant_temp_command)
time.sleep(1)
self.send_command(command=constant_humi_command)
time.sleep(1)
self.send_command(command=self.COMMAND_SET_MODE_CONSTANT)
time.sleep(1)
time.sleep(1)
# 检查设置是否成功
temp_result_data = self.get_temperature()
time.sleep(1)
current_temp_set = temp_result_data[1]
self.logger.info(f"current temp set: {current_temp_set}")
# 当前设置温度是否与预期一致
if current_temp_set != constant_target_temp:
raise ValueError(f"Expected set temp to {constant_target_temp}, current {current_temp_set}")
humi_result_data = self.get_humidity()
time.sleep(1)
current_humi_set = humi_result_data[1]
self.logger.info(f"current humi set: {current_humi_set}")
# 当前设置湿度是否与预期一致
if current_humi_set != constant_target_humi:
raise ValueError(f"Expected set humi to {constant_target_humi}, current {current_humi_set}")
except Exception as e:
self.logger.error(f"设置出错: {e}")
raise
def WriteProgram(self, program_list: List[Program]):
"""向设备写入程序"""
# 发送开始编辑命令
try:
self.send_command("1, PRGM DATA WRITE, PGM1, EDIT START")
step = 1
for program in program_list:
commands = self.ConvertProgramToCommands(program, step)
for cmd in commands:
# 检查命令长度限制
if len(cmd) > 50:
self.logger.info(f"命令过长,可能被截断: {cmd}")
if not self.send_command(cmd):
self.logger.info("程序写入失败")
return False
step += 1
self.SInterval() # 步骤间隔
# 发送结束编辑命令
self.send_command("1, PRGM DATA WRITE, PGM1, END, OFF")
self.send_command("1, PRGM DATA WRITE, PGM1, EDIT END")
self.logger.info("程序写入成功")
return True
except Exception as e:
self.logger.error(f"设置出错: {e}")
raise
def ConvertProgramToCommands(self, program: Program, step: int):
"""
将程序步骤转换为命令
:param program: 程序步骤
:param step: 步骤编号
:return: 命令列表
"""
try:
commands = []
step_cmd = f"STEP{step}"
if program.temperature != 0:
temp_cmd = (
f"1, PRGM DATA WRITE, PGM1, {step_cmd}, "
f"TEMP{program.temperature}, "
f"TIME{program.hour:02d}:{program.minute:02d}"
)
commands.append(temp_cmd)
if program.humidity != 0:
humi_cmd = (
f"1, PRGM DATA WRITE, PGM1, {step_cmd}, "
f"HUMI{program.humidity}, "
f"TIME{program.hour:02d}:{program.minute:02d}"
)
commands.append(humi_cmd)
return commands
except Exception as e:
self.logger.error(f"设置出错: {e}")
raise
def SetProgram(self, program_list: List[Program]) -> bool:
"""设置老化箱程序(带重试机制)"""
try:
# 三次重试机制
for tryout in range(1, 4):
if self.WriteProgram(program_list):
return True
self.logger.info(f"第{tryout}次尝试写入程序失败,将在1秒后重试")
time.sleep(1.0)
self.logger.error("程序写入失败: 达到最大重试次数")
return False
except Exception as e:
self.logger.error(f"设置出错: {e}")
raise
def RunProgram(self) -> bool:
"""执行程序(带重试机制)"""
try:
# 三次重试机制
for tryout in range(1, 4):
response = str(self.send_command(self.COMMAND_EXECUTE_PROGRAM))
if response.startswith(self.OK_SIGN):
self.logger.info("程序启动成功")
return True
self.logger.info(f"第{tryout}次尝试启动程序失败,响应: {response}")
time.sleep(1.0)
return False
except Exception as e:
self.logger.error(f"设置出错: {e}")
raise
def StopDevice(self) -> bool:
"""停止程序(带重试机制)"""
try:
# 三次重试机制
for tryout in range(1, 4):
response = str(self.send_command(self.COMMAND_STOP_DEV))
if response and not response.startswith(self.NA_PREFIX):
self.logger.info("设备已停止")
return self.close_serial()
self.logger.info(f"第{tryout}次尝试停止设备失败")
time.sleep(1.0)
self.logger.error("设备停止失败")
return False
except Exception as e:
self.logger.error(f"设置出错: {e}")
raise
if __name__ == "__main__":
chamber = GWSChamberCtrl(port='COM4')
temp_result_data = chamber.get_temperature()
print(temp_result_data)
current_temp = chamber.get_current_temperature(temp_result_data)
print(current_temp)
humi_result_data = chamber.get_humidity()
print(humi_result_data)
current_humi = chamber.get_current_humidity(humi_result_data)
print(current_humi)
chamber.constant_mode_set(25.0, 10.0)
# 示例程序设置
program_steps = [
Program(temperature=15, humidity=10, hour=2, minute=30),
Program(temperature=20, humidity=15, hour=1, minute=40),
Program(temperature=10, humidity=5, hour=0, minute=30)
]
# 设置程序
if chamber.SetProgram(program_steps):
# 运行程序
if chamber.RunProgram():
# 运行5秒后停止
time.sleep(5)
chamber.StopDevice()
chamber.StopDevice()
chamber.close_serial()
最新发布