在python3.5中使用serial模块进行串口通信,通过while 1循环进行持续性的设备通信,但是第一个设备完成之后对下一个设备进行通信会有问题:Attempting to use a port that is not open
一下是我的代码:
import serial
import time
import base64
import hmac
import pymysql
from esptool import ESP8266StubLoader
from esptool import erase_flash, read_mac, write_flash
from log import TNLog
values = ['0x01000', 'D:\esp8266\user1.4096.new.4(3).bin']
v1 = ['0x00000', 'D:\esp8266\boot_v1.7.bin']
v2 = ['0x3fb000', 'D:\esp8266\blank.bin']
v3 = ['0x3fe000', 'D:\esp8266\blank.bin']
v4 = ['0x3fc000', 'D:\esp8266\esp_init_data_default_v08.bin']
argfile = open(values[1], 'rb')
a1 = open(v1[1], 'rb')
a2 = open(v2[1], 'rb')
a3 = open(v3[1], 'rb')
a4 = open(v4[1], 'rb')
db = pymysql.connect("192.168.0.250", "dev_v7", "vvvvvv7", "db_iot_v7", charset='utf8')
cursor = db.cursor()
logger = TNLog()
prorts = serial.serial_for_url('COM3')
prorts.baudrate = 115200
class WriteOpthons(object):
def init(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
class MyClass(object):
def init(self):
self._port = prorts
self._trace_enabled = False
logger.info('接口初始化已经完成:{}'.format(self._port))
class SerialPort():
logger.info('现在开始进行调试硬件设备操作!')
message = ''
def connectport(self, com, baud):
try:
super(SerialPort, self).__init__()
self.port = serial.Serial(com, baud)
try:
if self.port.isOpen():
logger.info('已经连接OK:blfadd:connect port is ok')
print("blfadd:connect port is ok")
return 1
except Exception as e: # 捕获异常输出并终止运行
logger.error('硬件连接失败:{}'.format(e))
return 0
raise
except Exception as e:
logger.error('硬件调试连接操作出错:{}'.format(e))
def restart(self):
self.port.write()
def restart(self):
self.port.setDTR(True) # 0wei gao
self.port.setRTS(True)
time.sleep(1.5)
self.port.setDTR(True)
self.port.setRTS(False)
def setDTR(self, state):
self.port.setDTR(state)
def read_data(self):
global timeStamp
test1 = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
start_time = time.strptime(test1, "%Y-%m-%d %H:%M:%S")
# strftime是转换为特定格式输出,而strptime是将一个(时间)字符串解析为时间的一个类型对象。一个是按照想要的格式,去转换。重点是格式!另外一个不管什么格式,我只要把特定的时间字符串转成时间类型即可!
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())))
while True:
self.message = self.port.readline().decode('utf8', 'ignore')
test2 = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
end_time = time.strptime(test2, "%Y-%m-%d %H:%M:%S")
timeStamp = int(time.mktime(end_time)) - int(time.mktime(start_time))
if (self.message[0:10] == "uart begin" and timeStamp <= 80):
return 1
elif (timeStamp > 90):
raise Exception("blfadd:Time out")
def getwifiinfo(self, query_command, catchnum): # catchnum增加参数为捕获的wifi数量
try:
global count # 定义变量couunt用来计数
global macId
count = 0
self.port.write((query_command + '\n').encode())
huixian = self.port.readline().decode('utf8', 'ignore')
while (huixian[0:8] == "scandone"):
continue
while 100:
m = self.port.readline()
data_2 = m.decode('utf8', 'ignore')
data = m.decode('utf8', 'ignore')[0:-3]
if (data[0:5] == "data="): # 只读取开头为data=的信息
data_1 = data[6:]
# m1=data_1.split(',')[0:1]
m2 = data_1.split(',')[1:2]
m3 = data_1.split(',')[2:3]
m4 = data_1.split(',')[3:4]
# m5=data_1.split(',')[4:5]
wifiName = str(m2[0]).replace('"', '') # 替换掉“”
macId = str(m4[0]).replace('"', '')
# cursor =db.cursor()
count += 1 # if 语句每执行一次计数器加1
# 下面将wifi信息插入到数据库
# sql = """INSERT INTO WIFIDATA(INFO_1,INFO_2,INFO_3,INFO_4,INFO_5) VALUES(%s,%s,%s,%s,%s)"""
# try:
# val=(m1[0], wifiName, m3[0],macId, m5[0] )
# print("1111"+str(val))
# cursor.execute(sql,val)
# db.commit()
# except Exception as e:
# print("Error!"+e)
# db.rollback()
# db.close()
# print(m1[0],wifiName,m3[0],macId,m5[0])
print(wifiName, m3[0], macId) # blfalter:不展示搜索到的wifi
logger.info('获取wifi的信息:{}-{}-{}'.format(wifiName, m3[0], macId))
if (data_2[0:8] == "data_end"): # 这里没有进入if语句的原因是前面data收集信息时已经把
break # data_end截取掉了改用data_2收信息
if (count < catchnum): # 当前wifi数量与阈值作比
print("blfadd:Cannot catch nomal wifi singal") # 如果小于阈值将输出未能捕获wifi信号
elif (count >= catchnum):
logger.info('wifi模块完美检查完毕')
print("blfadd:Wifi Module checks ok")
print("blfadd:Now WifiNum:%d" % count) # 输出当前搜索到的wifi总数量
logger.info('搜索到的wifi个数:{}'.format(count))
return count
except Exception as e:
logger.error('硬件获取wifi操作报错:{}'.format(e))
def getcpuid(self, query_command):
try:
global cpuid
self.port.write((query_command + '\n').encode())
while 1:
m = self.port.readline()
data_2 = m.decode('utf8', 'ignore')
data = m.decode('utf8', 'ignore')[0:-2]
if (data[0:4] == "rec="): # 只读取开头为data=的信息
cpuid = data[4:]
if (data_2[0:16] == "command run over"):
return cpuid
except Exception as e:
logger.error('硬件获取cpuid操作报错:{}'.format(e))
def getmemid(self, query_command):
try:
global memid
self.port.write((query_command + '\n').encode())
while 1:
m = self.port.readline()
data_2 = m.decode('utf8', 'ignore')
data = m.decode('utf8', 'ignore')[0:-2]
if (data[0:4] == "rec="): # 只读取开头为data=的信息
memid = data[4:]
if (data_2[0:16] == "command run over"):
return memid
except Exception as e:
logger.error('硬件获取memid操作报错:{}'.format(e))
def ramdomId(self,s): # 获取20位产品序列号devicekey
res = {}
try:
sql = "SELECT * FROM device_status WHERE device = %s"
device_info = cursor.execute(sql, (s,))
if device_info:
devicekey = cursor.fetchone()[1]
# global devicekey
# devicekey = random.randint(10000000000000000000, 99999999999999999999) # random.sample()生成不相同的随机数
logger.info('数据库中与设备的SN匹配:{}'.format(devicekey))
sql = "UPDATE device_status SET `status` = 2 WHERE device = %s"
cursor.execute(sql, (s,))
db.commit()
logger.info('更改SN状态为2成功!!')
res.update({'status': 200, 'devicekey': devicekey})
# return str(devicekey)
else:
logger.info('SN与数据库中的SN扫描结果不一致')
res.update({'status': 403})
except Exception as e:
logger.info('硬件获取SN操作报错:{}'.format(e))
finally:
return res
def generate_token(self, key, expire):
r'''
@Args:
key: str (用户给定的key,需要用户保存以便之后验证token,每次产生token时的key 都可以是同一个key)
expire: int(最大有效时间,单位为s)
@Return:
state: str
'''
try:
ts_str = str(time.time() + expire)
ts_byte = ts_str.encode("utf-8")
sha1_tshexstr = hmac.new(key.encode("utf-8"), ts_byte, 'sha1').hexdigest()
# hmac是密钥相关的哈希运算消息认证码,HMAC运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。
token = ts_str + ':' + sha1_tshexstr
b64_token = base64.urlsafe_b64encode(token.encode("utf-8")) # Base64是一种用64个字符来表示任意二进制数据的方法
return b64_token.decode("utf-8")
except Exception as e:
logger.error('硬件生成token操作报错:{}'.format(e))
def certify_token(self, key, token):
r'''
@Args:
key: str
token: str
@Returns:
boolean
'''
try:
token_str = base64.urlsafe_b64decode(token).decode('utf-8')
token_list = token_str.split(':')
if len(token_list) != 2:
return 0
ts_str = token_list[0]
if float(ts_str) < time.time():
print("blfadd222222222222222>") # bldadd buzou
# token expired
return 0
known_sha1_tsstr = token_list[1]
sha1 = hmac.new(key.encode("utf-8"), ts_str.encode('utf-8'), 'sha1')
calc_sha1_tsstr = sha1.hexdigest()
if calc_sha1_tsstr != known_sha1_tsstr:
# token certification failed
print("Not ok") # 不走这一步
return 0
print("ok") # bldadd zou
return 1
except Exception as e:
logger.error('硬件验证token操作报错:{}'.format(e))
def setdev(self, query_command):
try:
self.port.write((query_command).encode())
while 1:
m = self.port.readline()
data = m.decode('utf8', 'ignore')
if (data[0:16] == "command run over"):
break
except Exception as e:
logger.error('硬件TOKEN/SN写入板子操作报错:{}'.format(e))
def setflag(self, query_command):
try:
self.port.write((query_command + '\n').encode())
while 1:
m = self.port.readline()
data = m.decode('utf8', 'ignore')
if (data[0:16] == "command run over"):
break
except Exception as e:
logger.error('硬件完成调试操作报错:{}'.format(e))
def getwifiname1(self, query_command, Abvalue, valuechange):
try:
# wifiName
global Intensity
self.port.write((query_command + '\n').encode())
huixian = self.port.readline().decode('utf8', 'ignore')
while (huixian[0:8] == "scandone"):
continue
while 100:
m = self.port.readline()
data_2 = m.decode('utf8', 'ignore')
data = m.decode('utf8', 'ignore')[0:-3]
if (data[0:5] == "data="): # 只读取开头为data=的信息
data_1 = data[6:]
m2 = data_1.split(',')[1:2]
m3 = data_1.split(',')[2:3]
m4 = data_1.split(',')[3:4]
Intensity = m3[0]
wifiName = str(m2[0]).replace('"', '') # 替换掉“”
if (wifiName == "XunMingIOT" and Abvalue + valuechange >= int(
m3[0]) >= Abvalue - valuechange): # 判断输出wifi信号强度值
print("blfadd:Standard Intensity:" + m2[0], m3[0], m4[0])
return m2[0], m3[0], m4[0]
elif (wifiName == "XunMingIOT" and Abvalue - valuechange > int(m3[0])):
print("blfadd:Low Intensity:" + m2[0], m3[0], m4[0]) # 输出wifi名称
return m2[0], m3[0], m4[0]
elif (wifiName == "XunMingIOT"):
print("blfadd:High Intensity:" + m2[0], m3[0], m4[0])
return m2[0], m3[0], m4[0]
if (data_2[0:8] == "data_end"): # 检测到data end结尾时候跳出循环
break
except Exception as e:
logger.error('硬件获取wifi操作报错:{}'.format(e))
# def mysql_hardinfo(self):
# key = s
# cpu = cpuid
# mac = macId
# mem = memid
# wificount = count
# time = timeStamp
# wifivalue = Intensity
# return key, mac, cpu, mem, wificount, wifivalue, time
def _main():
while 1:
count = 0
s = input('请输入SN号:').strip()
try:
obj = ESP8266StubLoader(obA)
except Exception as e:
print(type(e))
print(e)
pass
continue
obj.connect()
read_mac(obj, None) # mac地址
obj.IS_STUB = False
esp = obj.run_stub()
print('>>>>>>>>>>>>>>>>>>')
print(obj)
print(prorts)
print(esp)
res = erase_flash(esp, None) # 擦除操作
if res['status'] == int(404):
logger.info('设备擦除命令执行失败,失败的原因是:擦除任务超时')
logger.info('接口已经关闭')
count = count+1
if count < 3:
logger.info('现在设备执行次数为:{}'.format(count))
return _main()
else:
logger.info('设备已经执行3次还是有问题现在怀疑是设备硬件的问题!')
obj._port.close()
prorts.close()
prorts.isOpen()
else:
# 下载文件操作
write_option = WriteOpthons(
addr_filename=[(4096, argfile), (0, a1), (4173824, a2), (4186112, a3), (4177920, a4)],
after='hard_reset', baud=115200, before='default_reset', chip='auto', compress=None,
erase_all=False, flash_freq='40m', flash_mode='dio', flash_size='4MB',
no_compress=False, no_progress=False, no_stub=False, operation='write_flash',
override_vddsdio=None, port='COM3', spi_connection=None, trace=False, verify=False)
res = write_flash(esp=esp, args=write_option)
if res:
logger.info('文件下载完成')
obj._port.close()
prorts.close()
print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
nb = prorts.isOpen() # False 关闭端口了
print(nb)
else:
logger.info('文件下载失败')
obj._port.close()
prorts.close()
prorts.isOpen()
# 调试命令操作
f1 = SerialPort() # f1为实例化接口
f1.connectport('COM3', 74880)
f1.read_data() # 初始化串口返回串口信息 # 1
f1.getwifiinfo('command: getwifiinfo', 2) # 读取wifi信息并插入数据库
f1.getwifiname1('command: getwifiinfo', -50, 4) # 读取wifi信息并插入数据库
cpuid = f1.getcpuid('command: getcpuid')
logger.info('设备cpuid:{}'.format(cpuid))
memid = f1.getmemid('command: getmemid')
logger.info('设备memid是:{}'.format(memid))
serial_number = f1.ramdomId(s)
if serial_number['status'] == 403:
logger.info('获取sn不一致导致串口关闭')
f1.port.close()
prorts.close()
else:
logger.info('生成产品SN:{}'.format(serial_number['devicekey']))
key = cpuid + memid # 使用cpuid与memid拼接作为key
token = f1.generate_token(key, 3600) # 生成token
f1.certify_token(key, token) # 验证token成功返回ok
token_str = token[20:60]
logger.info('依据cpuid+memid生成的token值为:{}'.format(token_str))
f1.setdev('command: settockenkey' + str(token_str))
logger.info('token已经写入到板子之中')
f1.setdev('command: setdevkey' + str(serial_number['devicekey']))
logger.info('SN已经写入到板子之中了')
f1.setflag('command: setflag')
logger.info('调试已经完成')
f1.port.close() # 关闭串口
# prorts.close()
ss = f1.port.isOpen()
print(ss) # 串口已经关闭
print('<>')
# print(prorts.is_open())
# obj._port.close()
logger.info('串口已经关闭!')
print(obj._port.isOpen())
obj._port.open()
print(obj._port.isOpen())
continue
if name == 'main':
while 1:
# obA = MyClass()
class MyClass(object):
def init(self):
self._port = prorts
self._trace_enabled = False
logger.info('接口初始化已经完成:{}'.format(self._port))
obA = MyClass()
_main()
# count = 0
# s = input('请输入SN号:').strip()
# try:
# obj = ESP8266StubLoader(obA)
# except Exception as e:
# print(type(e))
# print(e)
# pass
# continue
# obj.connect()
# read_mac(obj, None) # mac地址
# obj.IS_STUB = False
# esp = obj.run_stub()
#
# res = erase_flash(esp, None) # 擦除操作
# if res['status'] == int(404):
# logger.info('设备擦除命令执行失败,失败的原因是:擦除任务超时')
# logger.info('接口已经关闭')
# count = count + 1
# if count < 3:
# logger.info('现在设备执行次数为:{}'.format(count))
# # return _main()
# _main()
# else:
# logger.info('设备已经执行3次还是有问题现在怀疑是设备硬件的问题!')
# obj._port.close()
# prorts.close()
#
#
# else:
# # 下载文件操作
# write_option = WriteOpthons(
# addr_filename=[(4096, argfile), (0, a1), (4173824, a2), (4186112, a3), (4177920, a4)],
# after='hard_reset', baud=115200, before='default_reset', chip='auto', compress=None,
# erase_all=False, flash_freq='40m', flash_mode='dio', flash_size='4MB',
# no_compress=False, no_progress=False, no_stub=False, operation='write_flash',
# override_vddsdio=None, port='COM3', spi_connection=None, trace=False, verify=False)
# res = write_flash(esp=esp, args=write_option)
# if res:
# logger.info('文件下载完成')
# obj._port.close()
# prorts.close()
# print('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<')
# print(prorts.isOpen())
# else:
# logger.info('文件下载失败')
# obj._port.close()
# prorts.close()
#
# # 调试命令操作
# f1 = SerialPort() # f1为实例化接口
# f1.connectport('COM3', 74880)
# f1.read_data() # 初始化串口返回串口信息 # 1
#
# f1.getwifiinfo('command: getwifiinfo', 2) # 读取wifi信息并插入数据库
# f1.getwifiname1('command: getwifiinfo', -50, 4) # 读取wifi信息并插入数据库
#
# cpuid = f1.getcpuid('command: getcpuid')
# logger.info('设备cpuid:{}'.format(cpuid))
#
# memid = f1.getmemid('command: getmemid')
# logger.info('设备memid是:{}'.format(memid))
#
# serial_number = f1.ramdomId(s)
# if serial_number['status'] == 403:
# logger.info('获取sn不一致导致串口关闭')
# prorts.close()
# else:
# logger.info('生成产品SN:{}'.format(serial_number['devicekey']))
#
# key = cpuid + memid # 使用cpuid与memid拼接作为key
# token = f1.generate_token(key, 3600) # 生成token
# f1.certify_token(key, token) # 验证token成功返回ok
# token_str = token[20:60]
# logger.info('依据cpuid+memid生成的token值为:{}'.format(token_str))
#
# f1.setdev('command: settockenkey' + str(token_str))
# logger.info('token已经写入到板子之中')
#
# f1.setdev('command: setdevkey' + str(serial_number['devicekey']))
# logger.info('SN已经写入到板子之中了')
#
# f1.setflag('command: setflag')
# logger.info('调试已经完成')
#
# f1.port.close() # 关闭串口
# # prorts.close()
# ss = f1.port.isOpen()
# print(ss) # 串口已经关闭
# print('<>')
# # print(prorts.is_open())
# # obj._port.close()
# logger.info('串口已经关闭!')
问题已经解决,端口关闭的问题,还有就是whil 1 的逻辑
好长的代码
– 会长 5年前@会长: 有的注释掉可以直接去掉,还没解耦,这只是为了调试
– 你说我记 5年前