fig.txt
{"cmd":"update_machine","mes":{"sn":"100016813","name":"testlight","type":"切割机","department":"smd","station":"五樓"}}
main_V3_2_2.py
"""
@三色灯採集程序
@功能:通过環境光传感器,采集三色灯各灯的亮灭状态和时间,并上传到MQTT服务器
@by Gansen
@硬件:ESP32采集模块V2版本
@接口: 红灯--> GPIO36
黄灯--> GPIO35
绿灯--> GPIO34
@版本:V3.2.2
修改说明:与V2.2.2版本对应,更换esp32硬件为V2版本
修改日期:2022-11-19
"""
import machine, esp32, network, utime, ds1307, ubinascii, ujson, uos, uftp,untp
from umqtt import MQTTClient
from machine import Pin
import _thread
print('ESP32工作頻率爲%dMhz' % int(machine.freq()/1000000)) # 打印當前CPU工作頻率
#machine.freq(240000000) #設置工作頻率240 MHz
wdt = machine.WDT(id=0,timeout=600000) #看门狗1分钟重启动
feed_flag=False
#串口1配置
uart1=machine.UART(1,tx=16,rx=17)
uart1.init(19200,bits=8,parity=None,stop=1)
#DS1307时钟配置
i2c=machine.I2C(0,scl=machine.Pin(22),sda=machine.Pin(21))
ds=ds1307.DS1307(i2c)
ds.halt(False)
#RTC时钟配置
rtc=machine.RTC()
rtc.datetime(ds.datetime())
#ntp配置
NTP_DELTA = 3155644800 #3155673600 # 可选 UTC+8偏移时间(秒),不设置就是UTC0
ntp_server = '172.16.xxx.xxx' # 可选,ntp服务器,默认是"pool.ntp.org"
#配置FTP
ftp=uftp.FtpTiny()
ftp.start()
#重启原因日志文件
def write_file(ss):
file_name = 'reset_log.txt'
file = open (file_name, 'a')
file.write(ds.DT() +' -- '+ ss + '\n')
file.close()
#重启原因保存
print('程序开始执行,重启原因:',end='')
cause = machine.reset_cause()#获取重启原因
if cause==1:
print('POWER_RESET-上电重启')
write_file('POWER_RESET-上电重启')
if cause==2:
print('HARD_RESET-硬重启')
write_file('HARD_RESET-硬重启')
if cause==3:
print('WDT_RESET-看门狗定时器重启')
write_file('WDT_RESET-看门狗定时器重启')
if cause==4:
print('DEEPSLEEP_RESET-休眠重启')
write_file('DEEPSLEEP_RESET-休眠重启')
if cause==5:
print('SOFT_RESET-软重启')
write_file('SOFT_RESET-软重启')
#获取目录文件大小
def print_directory(path,tabs = 0):
for file in uos.listdir(path):
# print(file)
stats = uos.stat(path+'/'+file)
filesize = stats[6]
isdir = stats[0] & 0x4000
# print(isdir)
if filesize < 1024:
sizestr = str(filesize)+' bytes'
elif filesize < 1024000:
sizestr = '%0.1f KB'%(filesize/1024)
else:
sizestr = '%0.1f MB'%(filesize/1024000)
prettyprintname = ''
for i in range(tabs):
prettyprintname +=' '
prettyprintname += file
if isdir:
prettyprintname+= '/'
print('{0:<30} Sise: {1:>2}'.format(prettyprintname,sizestr))
if isdir:
print_directory(path+'/'+file,tabs+1)
if prettyprintname=='reset_log.txt':
if filesize >10240:
uos.rmdir('/reset_log.txt')
print('reset_log remove')
else:
print('filesize;',filesize)
#日志文件>10k删除
print_directory('')
#MQTT配置
ssid = "wifi"
password = "pass"
mqtt_server = '172.16.xx.xx' #MQTT服務器IP地址
mqtt_user='xxx' #MQTT服務器用戶
mqtt_pwd='xxx' #MQTT服務器密碼
#client_id = ubinascii.hexlify(machine.unique_id()) #ESP模塊uid(mac地址)
client_id = ubinascii.hexlify(machine.unique_id() + utime.time().to_bytes(4,'little',False)) #mqtt client_id
esp32_mac = ubinascii.hexlify(machine.unique_id(),':').upper() #大寫mac
topic_sub = b'/machine/light/' + esp32_mac+ b'/cmd' #訂閱命令主旨
topic_pub = b'/machine/light/' + esp32_mac #數據發布主旨
topic_pub_res = b'/Res/' + esp32_mac #命令反饋發布主旨
collect_time = 100 #採集傳感器數據時間間隔 單位ms
message_time = 5000 #MQTT消息發送時間間隔 單位ms
#wlan_timeout =10 #wifi连接超时时间 单位s
#设备信息配置
esp32_IP = '0.0.0.0'#ip地址
isopen = True #刚开始发为true,后续为false
VERsion = 'V2.2.2' #程序版本号
sn = '100000001' #资产编号
Name = 'light' #设备名称
department = 'smd' #部门
type = 'smd' #机台类型
station = 'smd' #坐落位置
lamp_event = '' #机台灯事件
machine_state = False #机台警示棒故障标志,正常为true,故障为false
#讀取配置文件
try:
f = open('fig.txt', 'r')
config = ujson.loads(f.read())
f.close()
sn = config['mes']['sn']
Name = config['mes']['name']
type = config['mes']['type']
department = config['mes']['department']
station = config['mes']['station']
except Exception as e : #访问异常的错误编号和详细信息
print("Exception:",e)
# 若初次运行,则将进入excpet,执行配置文件的创建
print('not found file.')
#網絡配置
def do_connect(timeout):
global esp32_IP
at = utime.ticks_ms()
print('檢測%s熱點AP強度...'%(ssid))
uart1.write('print kingbright AP...\r\n')
wlan = network.WLAN(network.STA_IF)
try:
wlan.active(True)
except Exception as e : #访问异常的错误编号和详细信息
print("Exception:",e)
wlan.disconnect()
if wlan.ifconfig()[0] == '0.0.0.0' and len(rtc.memory()) == 0:
aplist = wlan.scan()
for one in aplist:
if one[0] == b'%s'%ssid:
print(one[0],one[2],one[3])
uart1.write(b'%s\r\n'%one[3])
# print('start...')
# print(wlan.ifconfig())
if wlan.ifconfig()[0] == '0.0.0.0':
print('準備連接到',ssid,end='')
uart1.write('kingbright conneting...\r\n')
try:
wlan.connect(ssid,password)
except Exception as e : #访问异常的错误编号和详细信息
print("Exception:",e)
wlan.active(False)
wlan.active(True)
wlan.connect(ssid,password)
start = utime.time() #獲取當前時間節點
while not wlan.isconnected() and utime.time() - start < timeout:
pass
if utime.time() - start < timeout:
print(wlan.ifconfig())
esp32_IP = wlan.ifconfig()[0]
print('已經連接到',ssid)
rtc.memory(b'\x00\x00')
uart1.write('kingbright conneted!\r\n')
print('do_connect time0:',utime.ticks_diff(utime.ticks_ms(),at))
else:
print('無法連接到',ssid)
uart1.write('kingbright connet error!\r\n')
else:
print(wlan.ifconfig())
esp32_IP = wlan.ifconfig()[0]
print('IP=',esp32_IP)
print('已經連接到',ssid)
uart1.write('kingbright conneted!\r\n')
print('do_connect time1:',utime.ticks_diff(utime.ticks_ms(),at))
return wlan
#wifi连接
def my_connect(timeout):
global esp32_IP
ast = utime.ticks_ms()
wlan=network.WLAN(network.STA_IF)
wlan.active(True)
wlan.disconnect()
print('wlan.isconnected()-0:',wlan.isconnected())
if not wlan.isconnected():
print('准备連接中...')
wlan.connect('kingbright','28699007')
start = utime.time() #獲取當前時間節點
while not wlan.isconnected() and utime.time() - start < timeout:
pass
if utime.time() - start < timeout:
esp32_IP = wlan.ifconfig()[0]
print('已經連接到kingbright-0')
print('my_connet time:',utime.ticks_diff(utime.ticks_ms(),ast))
else:
print('無法連接到kingbright')
else:
print('已經連接到kingbright-1')
esp32_IP = wlan.ifconfig()[0]
print('wlan.isconnected()-1:',wlan.isconnected())
return wlan
#訂閱消息中斷
def sub_cb(topic, msg):
#msg=msg.decode('uft-8')
print(msg.decode('uft-8'))
sub_cb_deal(msg)
#連接MQTT並訂閱消息
def connect_and_subscribe():
global client1
client_id = ubinascii.hexlify(machine.unique_id() + utime.time().to_bytes(4,'little',False)) #mqtt client_id
try:
client1 = MQTTClient(client_id, mqtt_server,user=mqtt_user, password=mqtt_pwd, keepalive=10)
client1.set_status()#status初始未True,設置為False,MQTT連接成功後再通過ping和check_msg確定當前狀態
client1.set_callback(sub_cb)
client1.connect()
client1.subscribe(topic_sub)
client1.ping()#設置ping,方便check_msg確定當前狀態
print('連接到 %s MQTT服務器, 訂閱主旨爲 %s 的消息.' % (mqtt_server, topic_sub))
except Exception as e :
print("MQTT服務器連接失敗-",e)
return False
return True
#定时发送
def timing_send(self):
global red_on_time0,yellow_on_time0,green_on_time0
global red_on_total_time,yellow_on_total_time,green_on_total_time
if red_state:
red_on_time0 = utime.ticks_diff(utime.ticks_ms(),red_on_current_time)#红灯时间差
red_on_total_time = red_on_total_time_temp+red_on_time0#红灯时间累计
if yellow_state:
yellow_on_time0 = utime.ticks_diff(utime.ticks_ms(),yellow_on_current_time)#黄灯时间差
yellow_on_total_time = yellow_on_total_time_temp + yellow_on_time0#黄灯时间累计
if green_state:
green_on_time0 = utime.ticks_diff(utime.ticks_ms(),green_on_current_time)#绿灯时间差
green_on_total_time=green_on_total_time_temp+green_on_time0#绿灯时间累计
print('*********************')
uart1.write('******timing******!\r\n')
str1=jsondata(red_state,yellow_state,green_state,'none')
send_data(topic_pub, str1) #发布
# print(str1.decode('uft-8'))
uart1.write(b'%s\r\n'% str1)
#状态变化发送
def change_send(lamp_event):
str1 = jsondata(red_state,yellow_state,green_state,lamp_event)
send_data(topic_pub, str1)
# print(str1.decode('uft-8'))
uart1.write(b'%s\r\n'% str1 )
#JSON数据
def jsondata(state1,state2,state3,lamp_event):
global isopen
data={
'mac':'',
'ip':'0.0.0.0',
'isopen':True,
'machine_state':False,
'sn':'',
'name':'',
'type':'',
'department':'',
'station':'',
'VER':'',
'lamp_event':'none',
'machine_data':{
'red':{'state':False,'time':0},
'yellow':{'state':False,'time':0},
'green':{'state':False,'time':0}},
'stamp_time':'2021-06-30 13:35:05'}
#data0={}
#data = ujson.loads(ujson.dumps(data))
data['mac'] = esp32_mac #mac地址
data['ip'] = esp32_IP #esp32_IP;//ip地址
data['isopen'] = isopen #刚开始发为true,后续为false
data['machine_state'] = machine_state #故障为false
data['sn'] = sn #资产编号
data['name'] = Name #设备名称
data['type'] = type #机台类型
data['department'] = department #部门
data['station'] = station #坐落位置
data['VER'] = VERsion #版本号
data['lamp_event'] = lamp_event #灯状态事件
data['stamp_time'] = ds.DT() #实时时间
data['machine_data']['red']['state']=state1
data['machine_data']['red']['time']=int(red_on_total_time/1000)
data['machine_data']['yellow']['state']=state2
data['machine_data']['yellow']['time']=int(yellow_on_total_time/1000)
data['machine_data']['green']['state']=state3
data['machine_data']['green']['time']=int(green_on_total_time/1000)
isopen = False
string=ujson.dumps(data)
return b'%s'%string
#三色灯设备状态和时间获取
red_pin = Pin(36, Pin.IN) # create input pin on GPIO36
yellow_pin = Pin(35, Pin.IN) # create input pin on GPIO35
green_pin = Pin(34, Pin.IN) # create input pin on GPIO34
red_state0 = False;
yellow_state0 = False;
green_state0 = False;
#开始点量时间戳
red_on_current_time=0
yellow_on_current_time=0
green_on_current_time=0
#单次点亮时间
red_on_time=0
yellow_on_time=0
green_on_time=0
#点亮总累计时间
red_on_total_time=0
yellow_on_total_time=0
green_on_total_time=0
#累计时间变量
red_on_total_time_temp = 0
yellow_on_total_time_temp = 0
green_on_total_time_temp = 0
machine_state_false_time = 0#机台状态
#燈狀態和時間變量
light_state = 0
light_state_temp = 0
#各燈狀態
red_state=False
yellow_state=False
green_state=False
#閃爍間隔,ms
red_flicker_time = 300
yellow_flicker_time = 300
green_flicker_time = 300
#燈狀態轉換表
'''
紅黃綠
0 0 0-全滅0
0 0 1-綠1
0 1 0-黃2
0 1 1-黃綠3
1 0 0-紅4
1 0 1-紅綠5
1 1 0-紅黃6
1 1 1-全亮7
'''
#狀態表
#当前状态,下个状态,执行函数
state_table= [
1,2,6,#绿->黄(綠灭)
1,2,3,#绿->黃(黄亮)
1,4,6,#绿->紅(綠灭)
1,4,1,#绿->红(红亮)
2,1,4,#黄->绿(黄滅)
2,1,5,#黄->绿(綠亮)
2,4,4,#黃->红(黄灭)
2,4,1,#黄->紅(红亮)
4,1,2,#红->绿(红灭)
4,1,5,#红->绿(绿亮)
4,2,2,#红->黄(红灭)
4,2,3,#红->黄(黄亮)
1,0,6,#绿->全灭(绿灭)
2,0,4,#黄->全灭(黄灭)
4,0,2,#红->全灭(红灭)
0,1,5,#全灭->绿(绿亮)
0,2,3,#全灭->黄(黄亮)
0,4,1#全灭->红(红亮)
]
#状态表转换
def state_table_trans(state_table,n):
state0=[0,0,0]
for i in range(3*n,3*n+3):
state0[i-3*n]=state_table[i]
return state0
curr_state = 0#当前状态
next_state = 0#下个状态
#狀態更新
def state_update(next_state):
global curr_state
for i in range(0,18):
if next_state == state_table_trans(state_table,i)[1]:
if curr_state == state_table_trans(state_table,i)[0]:
# print('state_update')
if next_state is not 0 and curr_state is not 0:
state_func(state_table_trans(state_table,i)[2])
state_func(state_table_trans(state_table,i+1)[2])
else:
state_func(state_table_trans(state_table,i)[2])
curr_state = next_state
def state_func(n):
if n==1:
redtrue()
if n==2:
redfalse()
if n==3:
yellowtrue()
if n==4:
yellowfalse()
if n==5:
greentrue()
if n==6:
greenfalse()
def redtrue():
print('redtrue')
change_send("red")#发送
def redfalse():
global red_on_total_time_temp,red_on_total_time
print('redfalse:',red_on_time)
red_on_total_time = red_on_total_time_temp + red_on_time
red_on_total_time_temp = red_on_total_time
change_send("red")#发送
def yellowtrue():
print('yellowtrue')
change_send("yellow")#发送
def yellowfalse():
global yellow_on_total_time_temp,yellow_on_total_time
print('yellowfalse:',yellow_on_time)
yellow_on_total_time = yellow_on_total_time_temp + yellow_on_time
yellow_on_total_time_temp = yellow_on_total_time
change_send("yellow")#发送
def greentrue():
print('greentrue')
change_send("green")#发送
def greenfalse():
global green_on_total_time_temp,green_on_total_time
print('greenfalse:',green_on_time)
green_on_total_time= green_on_total_time_temp + green_on_time
green_on_total_time_temp = green_on_total_time
# print("green_on_total_time_temp:",green_on_total_time_temp)
change_send("green")#发送
def get_state():
global red_state0,yellow_state0,green_state0,red_state,yellow_state,green_state
global red_on_current_time,red_on_time,red_on_total_time,red_on_total_time_temp
global yellow_on_current_time,yellow_on_time,yellow_on_total_time,yellow_on_total_time_temp
global green_on_current_time,green_on_time,green_on_total_time,green_on_total_time_temp
global lamp_event,machine_state_false_time,machine_state,light_state,light_state_temp
#global red_flicker_time,yellow_flicker_time,green_flicker_time
global tt,rtt,ytt
#红灯
if red_pin.value() ==0:
if red_pin.value() ==0 and not red_state0:
red_state0=True
if red_state==False:
red_on_current_time = utime.ticks_ms()
red_state=True
# print('redtrue')
else:
if red_pin.value() ==1 and red_state0:
red_state0=False
rtt= utime.ticks_ms()
red_on_time = utime.ticks_ms()-red_on_current_time
else:
if red_state== True and red_state0== False:
if utime.ticks_diff(utime.ticks_ms(),rtt) < red_flicker_time:
if green_state==True or yellow_state==True:
#print('==========redfalsetime:',red_on_time)
red_state=False
if utime.ticks_diff(utime.ticks_ms(),rtt) > 1000:
red_state=False
#黄灯
if yellow_pin.value()==0:
if yellow_pin.value()==0 and not yellow_state0:
yellow_state0=True
if yellow_state==False:
yellow_on_current_time = utime.ticks_ms()
yellow_state=True
#print('yellowtrue')
else:
if yellow_pin.value() ==1 and yellow_state0:
yellow_state0 = False
ytt = utime.ticks_ms()
yellow_on_time = utime.ticks_ms()-yellow_on_current_time
else:
if yellow_state== True and yellow_state0== False:
if utime.ticks_diff(utime.ticks_ms(),ytt) < yellow_flicker_time:
if red_state==True or green_state==True:
#print('==========yellowfalsetime:',yellow_on_time)
yellow_state=False
if utime.ticks_diff(utime.ticks_ms(),ytt) > 1000:
yellow_state=False
#绿灯
if green_pin.value()==0:
if green_pin.value()==0 and not green_state0:
green_state0=True
if green_state==False:
#print('greentrue')
green_on_current_time = utime.ticks_ms()
green_state=True
#print('grtrue',green_on_current_time)
else:
if green_pin.value() ==1 and green_state0:
green_state0=False
tt= utime.ticks_ms()
green_on_time = utime.ticks_ms()-green_on_current_time
#print("greenfalse",utime.ticks_ms())
else:
if green_state == True and green_state0== False:
if utime.ticks_diff(utime.ticks_ms(),tt) < green_flicker_time:
if red_state==True or yellow_state==True:
# print('==========greenfalsetime:',green_on_time)
green_state=False
if utime.ticks_diff(utime.ticks_ms(),tt) > 1000:
green_state=False
light_state = (green_state|yellow_state<<1|red_state<<2)
if light_state ==1 or light_state ==2 or light_state ==4 or light_state ==0:
if light_state!= light_state_temp:
light_state_temp =light_state
print('****')
print(light_state)
state_update(light_state)
#三个灯状态都为灭且持续10S以上则认为警示棒故障
if light_state is not 0:
machine_state_false_time = utime.ticks_ms()
machine_state = True
else:
if utime.ticks_diff(utime.ticks_ms(),machine_state_false_time)> 3000:
machine_state_false_time = utime.ticks_ms()
machine_state = False
print("//the machine lights is all false ")
#Ds1307 64位数据存储
def Write8byte(addr,data):
buf = bytearray(8)
buf[7] = ((data >> 56) & 0xFF)
buf[6] = ((data >> 48) & 0xFF)
buf[5] = ((data >> 40) & 0xFF)
buf[4] = ((data >> 32) & 0xFF)
buf[3] = ((data >> 24) & 0xFF)
buf[2] = ((data >> 16) & 0xFF)
buf[1] = ((data >> 8) & 0xFF)
buf[0] = (data & 0xFF)
ds.set_datamem(addr,buf)
#Ds1307 64位数据读取
def Read8byte(addr):
buff=ds.get_datamem(addr,addr+8)
Data=buff[0]+(buff[1]<<8)+(buff[2]<<16)+(buff[3]<<24)+(buff[4]<<32)+(buff[5]<<40)+(buff[6]<<48)+(buff[7]<<56)
return Data
#Ds1307 字节存储
def Writebyte(addr,byte):
buf = bytearray(1)
buf[0]=byte & 0xFF
ds.set_datamem(addr,buf)
#Ds1307 字节读取
def Readbyte(addr):
return ord(ds.get_datamem(addr,1))
#DS1307 内存数据清除
def data_clear():
for i in range(56):
Writebyte(i,0)
machine.reset()
#数据保存
def data_save(self):
Write8byte(0,red_on_total_time)#红灯累计时间保存
Write8byte(8,yellow_on_total_time)#黄灯累计时间保存
Write8byte(16,green_on_total_time)#绿灯累计时间保存
#重启时数据恢复
def data_read():
# global red_state0,yellow_state0,green_state0
global red_on_total_time,red_on_total_time_temp,red_on_current_time
global yellow_on_total_time,yellow_on_total_time_temp,yellow_on_current_time
global green_on_total_time,green_on_total_time_temp,green_on_current_time
red_on_total_time = Read8byte(0)
red_on_total_time_temp = red_on_total_time
yellow_on_total_time = Read8byte(8)
yellow_on_total_time_temp = yellow_on_total_time
green_on_total_time = Read8byte(16)
green_on_total_time_temp = green_on_total_time
print(red_on_total_time)
print(yellow_on_total_time)
print(green_on_total_time)
#恢复数据
data_read()
#mqtt订阅消息处理
def sub_cb_deal(string):
try:
data = ujson.loads(string)
if isinstance(data,dict):
if 'cmd' in data.keys():
cmd = data['cmd']
print(cmd)
#重启
if cmd == 'restart':
send_data(topic_pub_res, Res_data(b'reset'))
uart1.write(b'reset\r\n' )
utime.sleep(2)
machine.reset()
#清空数据
elif cmd == 'clear':
send_data(topic_pub_res, Res_data(b'clear'))
uart1.write(b'clear\r\n' )
data_clear()
#设备信息配置
elif cmd == 'update_machine':
global sn,Name,type,department,station
sn = data['mes']['sn']
Name = data['mes']['name']
type = data['mes']['type']
department = data['mes']['department']
station = data['mes']['station']
#写入配置文件
file = open ('fig.txt', 'w')
string = ujson.dumps(data)
file.write(string)
file.close()
print("update_machine")
uart1.write(b'update_machine\r\n')
send_data(topic_pub_res, Res_data(b'update_machine'))
#NTP网络对时
elif cmd == 'settime':
global ntp_server
if 'ntp_server' in data.keys():
ntp_server = data['ntp_server']
if not sync_ntp():
send_data(topic_pub_res, Res_data('ntp_server: '+ntp_server+' timeout'))
else:
uart1.write(b'settime\r\n' )
send_data(topic_pub_res, Res_data(b'ntp successed'))
#反馈IP地址
elif cmd == 'IP':
print(esp32_IP)
uart1.write(b'IP\r\n' )
send_data(topic_pub_res,Res_data(esp32_IP))
#反馈DS1307时间
elif cmd == 'time':
print(ds.datetime())#读取NTP时间
send_data(topic_pub_res,Res_data(ds.DT()))
#反馈wifi信号强度
elif cmd == 'dbm':
aplist=wlan.scan()
for one in aplist:
if one[0] == b'%s'%ssid:
print(one[0],one[2],one[3])
db=b' %s'%one[0]+b' %s'%one[2]+b' %s'%one[3]
send_data(topic_pub_res,Res_data(db))
except ValueError as e:
print('不是JSON格式')
#MQTT命令反馈信息
def Res_data(mes):
Res = {'Res':''}
Res['Res']= mes
ss = ujson.dumps(Res)
return b'%s' % ss
#ntp时间同步
def sync_ntp():
for i in range(5):
try:
untp.NTP_DELTA = 3155644800 #3155673600 # 可选 UTC+8偏移时间(秒),不设置就是UTC0
untp.host = ntp_server # 可选,ntp服务器,默认是"pool.ntp.org"
print('ntptime:',end='')
untp.settime() #RTC时间同步
ds.datetime(rtc.datetime()) #DS1307时钟设置
print(untp.DT())
return True
except Exception as e : #访问异常的错误编号和详细信息
print("Exception:",e)
utime.sleep(2)
print('時間服務器'+ ntp_server +'超時')
return False
def sync_ntp_timer(self):
for i in range(5):
try:
untp.NTP_DELTA = 3155644800 #3155673600 # 可选 UTC+8偏移时间(秒),不设置就是UTC0
untp.host = ntp_server # 可选,ntp服务器,默认是"pool.ntp.org"
print('ntptime:',end='')
if abs(untp.time()-ds.time()) > 5: #ds1307时间误差大于5s
print('时间误差大')
untp.settime() #RTC时间同步
ds.datetime(rtc.datetime()) #DS1307时钟设置
print('自动对时完成')
return True
else:
print('时间误差小')
return True
except Exception as e : #访问异常的错误编号和详细信息
print("Exception:",e)
utime.sleep(1)
print('時間服務器'+ ntp_server +'超時')
return False
mqtt_online = False #MQTT已連接标志
thread_start = False#线程开始标志
#无线网络和MQTT连接线程
def connect_thread(id = 0,interval = 2):
global mqtt_online,wlan
global thread_start,reset_count
thread_start = True
print('connect_thread start')
try:
wlan = my_connect(interval)
except Exception as e : #访问异常的错误编号和详细信息
print("wlan error Exception:",e)
machine.reset()
if wlan.isconnected() is True:
print('MQTT连接中...')
client1_status = connect_and_subscribe()
print("MQTT連接結果:",client1_status)
if client1_status is True:
mqtt_online = True
reset_count = 0
thread_start = False
_thread.exit()
#MQTT在线才发布数据
def send_data(topic,json_data):
if mqtt_online is True:
try:
if client1.get_status() is True:
client1.publish(topic,json_data)
print('MQTT发布成功',json_data)
else:
print("MQTT发布失败")
except Exception as e:
print("MQTT发布失败-",e)
else:
print('MQTT offline')
#發送MQTT消息定時中斷 5秒
tim1 = machine.Timer(1)
tim1.init(period=message_time, mode=machine.Timer.PERIODIC, callback=timing_send)
#数据保存定时中断 1S
tim0 = machine.Timer(0)
tim0.init(period=1000, mode=machine.Timer.PERIODIC, callback=data_save)
#ntp自动对时定時中斷 1小时
tim2 = machine.Timer(2)
tim2.init(period=3600000, mode=machine.Timer.PERIODIC, callback=sync_ntp_timer)
# thread測試,無法創建新thread則看門狗重啟
def thread_check(id = 0,interval = 2):
global feed_flag
feed_flag = True
# print("thread check")
_thread.exit()
reset_count = 0 #一定次数未连接则重启
st = utime.ticks_ms()
while True:
try:
#check_msg確定當前MQTT連線狀態
if mqtt_online is True:
client1.check_msg()
#检测MQTT是否在线
if utime.ticks_diff(utime.ticks_ms(),st) > 10000 :
st = utime.ticks_ms()
#thread異常檢測
_thread.start_new_thread(thread_check,(1,2))
try:
getstatus = client1.get_status()
except Exception as e : #访问异常的错误编号和详细信息
print('MQTT状态错误:',e)
getstatus = False #避免第一次未創建client時client1.get_status()語句出錯
print("get_status:",getstatus)
if getstatus is not True:
mqtt_online = False
#上個連接線程結束才新建線程
if not thread_start:
reset_count += 1
#超过10次仍未连上则重启
if reset_count > 10:
machine.reset()
print('MQTT断开,重新连接---')
_thread.start_new_thread(connect_thread,(utime.time(),20))#创建线程
else:
print("connect_thread......")
else:
client1.set_status()
client1.ping()
except Exception as e : #访问异常的错误编号和详细信息
print("MQTT連接線程異常:",e)
machine.reset()
#线程异常则看门狗重启
if feed_flag is True:
wdt.feed() #喂狗
print("feed")
feed_flag = False
get_state() #状态获取
ds1307.py
"""
MicroPython TinyRTC I2C Module, DS1307 RTC + AT24C32N EEPROM
https://en.wikipedia.org/wiki/Binary-coded_decimal
"""
from micropython import const
DATETIME_REG = const(0) # 0x00-0x06
CHIP_HALT = const(128)
CONTROL_REG = const(7) # 0x07
RAM_REG = const(8) # 0x08-0x3F
class DS1307(object):
"""Driver for the DS1307 RTC."""
def __init__(self, i2c, addr=0x68):
self.i2c = i2c
self.addr = addr
self.weekday_start = 1
self._halt = False
def _dec2bcd(self, value):
"""Convert decimal to binary coded decimal (BCD) format"""
return (value // 10) << 4 | (value % 10)
def _bcd2dec(self, value):
"""Convert binary coded decimal (BCD) format to decimal"""
return ((value >> 4) * 10) + (value & 0x0F)
def datamem(self, datetime=None):
if datetime is None:
return self.i2c.readfrom_mem(self.addr, RAM_REG, 56)
self.i2c.writeto_mem(self.addr, RAM_REG, datetime)
def set_datamem(self, addr=0, datetime = None):
if datetime is None:
self.i2c.writeto_mem(self.addr, RAM_REG + addr, bytes(56-addr))
return 56-addr
else:
self.i2c.writeto_mem(self.addr, RAM_REG + addr, datetime)
return len(datetime)
def get_datamem(self, addr=0, count=56):
return self.i2c.readfrom_mem(self.addr, RAM_REG + addr, count)
def datetime(self, datetime=None):
"""Get or set datetime"""
if datetime is None:
buf = self.i2c.readfrom_mem(self.addr, DATETIME_REG, 7)
return (
self._bcd2dec(buf[6]) + 2000, # year
self._bcd2dec(buf[5]), # month
self._bcd2dec(buf[4]), # day
self._bcd2dec(buf[3] - self.weekday_start), # weekday
self._bcd2dec(buf[2]), # hour
self._bcd2dec(buf[1]), # minute
self._bcd2dec(buf[0] & 0x7F), # second
0 # subseconds
)
buf = bytearray(7)
buf[0] = self._dec2bcd(datetime[6]) & 0x7F # second, msb = CH, 1=halt, 0=go
buf[1] = self._dec2bcd(datetime[5]) # minute
buf[2] = self._dec2bcd(datetime[4]) # hour
buf[3] = self._dec2bcd(datetime[3] + self.weekday_start) # weekday
buf[4] = self._dec2bcd(datetime[2]) # day
buf[5] = self._dec2bcd(datetime[1]) # month
buf[6] = self._dec2bcd(datetime[0] - 2000) # year
if (self._halt):
buf[0] |= (1 << 7)
self.i2c.writeto_mem(self.addr, DATETIME_REG, buf)
def halt(self, val=None):
"""Power up, power down or check status"""
if val is None:
return self._halt
reg = self.i2c.readfrom_mem(self.addr, DATETIME_REG, 1)[0]
if val:
reg |= CHIP_HALT
else:
reg &= ~CHIP_HALT
self._halt = bool(val)
self.i2c.writeto_mem(self.addr, DATETIME_REG, bytearray([reg]))
def DT(self):
buf = self.datetime()
return '%4d'%buf[0] + '-%02d'%buf[1]+'-%02d'%buf[2]+' %02d'%buf[4]+':%02d'%buf[5]+':%02d'%buf[6]
def time(self):
import utime
tm = self.datetime()
return utime.mktime((tm[0], tm[1], tm[2],tm[4], tm[5], tm[6], tm[3]-1,0))
def square_wave(self, sqw=0, out=0):
"""Output square wave on pin SQ at 1Hz, 4.096kHz, 8.192kHz or 32.768kHz,
or disable the oscillator and output logic level high/low."""
rs0 = 1 if sqw == 4 or sqw == 32 else 0
rs1 = 1 if sqw == 8 or sqw == 32 else 0
out = 1 if out > 0 else 0
sqw = 1 if sqw > 0 else 0
reg = rs0 | rs1 << 1 | sqw << 4 | out << 7
self.i2c.writeto_mem(self.addr, CONTROL_REG, bytearray([reg]))
uftp.py
# this code is from uftpserver (https://github.com/cpopp/MicroFTPServer/tree/master/uftp).
# there's no license so I used MIT and then...
# packed it into a class, added missing FTP commands, and added the threading
import socket
import network
import os
import _thread
import gc
DATA_PORT = 13333
class FtpTiny:
'''This class creates a very tiny FTP server in a thread
x = ftptiny.FtpTiny()
x.start()
x.stop()'''
def __init__(self) :
self.dorun = True
self.isrunning = False
self.cwd = os.getcwd()
self.ftpsocket = None
self.datasocket = None
self.dataclient = None
def start_listen(self) :
# the two sockets are the persistant and the pasv sockets
# so this requires pasv
self.ftpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.ftpsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.ftpsocket.bind(socket.getaddrinfo("0.0.0.0", 21)[0][4])
self.datasocket.bind(socket.getaddrinfo("0.0.0.0", DATA_PORT)[0][4])
self.ftpsocket.listen(1)
self.datasocket.listen(1)
self.datasocket.settimeout(10)
self.lastpayload = ''
def send_list_data(self, client):
for file in os.listdir(self.cwd):
stat = os.stat(self.get_absolute_path(file))
file_permissions = "drwxr-xr-x" if (stat[0] & 0o170000 == 0o040000) else "-rw-r--r--"
file_size = stat[6]
description = "{} 1 owner group {:>13} Jan 1 1980 {}".format(file_permissions, file_size, file)
self.sendcmdline(client, description)
def send_file_data(self, path, client):
with open(path) as file:
chunk = file.read(128)
while len(chunk) > 0:
client.sendall(chunk)
if len(chunk) == 128:
chunk = file.read(128)
else:
chunk = []
def save_file_data(self, path, client):
client.settimeout(.5)
with open(path, "w") as file:
try:
chunk = client.recv(128)
while chunk and len(chunk) > 0:
file.write(chunk)
if len(chunk) == 128 :
chunk = client.recv(128)
else :
chunk = None # done?
except Exception as ex:
pass
def get_absolute_path(self, payload):
# if it doesn't start with / consider
# it a relative path
rslt = payload
if not payload.startswith("/"):
if len(self.cwd) > 1 :
rslt = self.cwd + "/" + payload
else :
rslt = self.cwd + payload
# and don't leave any trailing /
if len(rslt) > 1 :
return rslt.rstrip("/")
return rslt
def stop(self):
self.dorun = False
self.thread = 0
def start(self):
if not self.isrunning :
self.dorun = True
tid = _thread.start_new_thread(runserver, (self, ))
self.thread = tid
else :
print("An instance is already running.")
def sendcmdline(self, cl, txt) :
cl.sendall(txt)
cl.sendall("\r\n")
def closeclient(self) :
if self.dataclient :
self.dataclient.close()
self.dataclient = None
def client(self, cl) :
return self.dataclient if self.dataclient else cl
def _handle_command(self, cl, command, payload) :
if command == "USER":
print('usr = '+ payload)
self.sendcmdline(cl, "230 Logged in.")
#530 user or pwd error
elif command == "SYST":
self.sendcmdline(cl, "215 ESP32 MicroPython")
elif command == "SYST":
self.sendcmdline(cl, "502")
elif command == "PWD":
self.sendcmdline(cl, '257 "{}"'.format(self.cwd))
elif command == "CWD":
path = self.get_absolute_path(payload)
try:
os.chdir(path)
self.sendcmdline(cl, '250 Directory changed successfully')
except:
self.sendcmdline(cl, '550 Failed to change directory')
finally:
self.cwd = os.getcwd()
elif command == "EPSV":
self.sendcmdline(cl, '502')
elif command == "TYPE":
# probably should switch between binary and not
self.sendcmdline(cl, '200 Transfer mode set')
elif command == "SIZE":
path = self.get_absolute_path(payload)
try:
size = os.stat(path)[6]
self.sendcmdline(cl, '213 {}'.format(size))
except:
self.sendcmdline(cl, '550 Could not get file size')
elif command == "QUIT":
self.sendcmdline(cl, '221 Bye.')
elif command == "PASV":
addr = network.WLAN().ifconfig()[0]
self.sendcmdline(cl, '227 Entering Passive Mode ({},{},{}).'.format(addr.replace('.',','), DATA_PORT>>8, DATA_PORT%256))
self.dataclient, data_addr = self.datasocket.accept()
print("FTP Data connection from:", data_addr)
elif command == "LIST":
try:
# list folder contents
self.send_list_data(self.client(cl))
self.closeclient()
self.sendcmdline(cl, "150 Here comes the directory listing.")
self.sendcmdline(cl, "226 Listed.")
except:
self.sendcmdline(cl, '550 Failed to list directory')
finally:
self.closeclient()
elif command == "RETR":
try:
# send a file to the client
self.send_file_data(self.get_absolute_path(payload), self.client(cl))
self.closeclient()
self.sendcmdline(cl, "150 Opening data connection.")
self.sendcmdline(cl, "226 Transfer complete.")
except:
self.sendcmdline(cl, '550 Failed to send file')
self.closeclient()
elif command == "STOR":
try:
# receive a file and save to disk
self.sendcmdline(cl, "150 Ok to send data.")
self.save_file_data(self.get_absolute_path(payload), self.client(cl))
self.closeclient()
print("Finished receiving file")
self.sendcmdline(cl, "226 Transfer complete.")
except Exception as ex:
print("Failed to receive file: " + str(ex))
self.sendcmdline(cl, '550 Failed to send file')
finally:
print("Finally closing dataclient")
self.closeclient()
elif command == "DELE":
try:
# delete a file
path = self.get_absolute_path(payload)
os.remove(path)
print("Deleted file: " + path)
self.sendcmdline(cl, "250 File deleted ok.")
except Exception as ex:
print("Failed to delete file: " + str(ex))
self.sendcmdline(cl, '550 Failed to delete file.')
finally:
self.closeclient()
elif command == "MKD":
try:
# create a folder
path = self.get_absolute_path(payload)
os.mkdir(path)
print("Create folder: " + path)
self.sendcmdline(cl, "257 Path created ok.")
except Exception as ex:
print("Failed to create folder: " + str(ex))
self.sendcmdline(cl, '550 Failed to create folder.')
finally:
self.closeclient()
elif command == "RMD":
try:
# delete a folder
path = self.get_absolute_path(payload)
os.rmdir(path)
print("Deleted folder: " + path)
self.sendcmdline(cl, "250 Folder deleted ok.")
except Exception as ex:
print("Failed to delete folder: " + str(ex))
self.sendcmdline(cl, '550 Failed to delete file.')
finally:
self.closeclient()
elif command == "CDUP":
try:
# change to parent folder
if self.cwd and len(self.cwd) > 1 :
paths = self.cwd.split('/')
xpat = '/' + '/'.join(paths[:-1])
else :
xpat = '/'
os.chdir(xpat)
self.cwd = xpat
print("Go to parent: " + xpat)
self.sendcmdline(cl, "250 Went to parent folder.")
except Exception as ex:
print("Failed to delete folder: " + str(ex))
self.sendcmdline(cl, '550 Failed to go to parent.')
finally:
self.closeclient()
elif command == "RNFR":
# rename file start...
self.lastpayload = payload
self.sendcmdline(cl, "226 Starting rename.")
elif command == "RNTO":
if self.lastpayload :
try:
# rename file end...
os.rename(self.lastpayload, payload)
self.sendcmdline(cl, "250 Renamed file.")
except Exception as ex:
print("Failed to rename file: " + str(ex))
self.sendcmdline(cl, '550 Failed to rename file.')
finally:
self.closeclient()
self.lastpayload = None
else:
self.sendcmdline(cl, "502 Unsupported command.")
print("Unsupported command {} with payload {}".format(command, payload))
# called by the threader
def dolisten(self):
self.isrunning = True
try:
self.start_listen()
while self.dorun:
cl, remote_addr = self.ftpsocket.accept()
cl.settimeout(300)
try:
print("FTP connection from:", remote_addr)
self.sendcmdline(cl, "220 Hello. Welcome to FtpTiny.")
# --- here's the command loop
# since it's waiting at readline this doesn't end after stop() unless you
# send a command
while self.dorun:
data = cl.readline().decode("utf-8").replace("\r\n", "")
if len(data) <= 0:
print("Client is gone")
break
print(data)
command, payload = (data.split(" ") + [""])[:2]
command = command.upper()
print("Command={}, Payload={}".format(command, payload))
self._handle_command(cl, command, payload)
# we use up memory here, so deal with it
gc.collect()
# --- end of command loop
except Exception as ex :
print(str(ex))
finally:
print("Closing dataclient socket")
cl.close()
except Exception as ex :
print("TinyFtp error: " + str(ex))
finally:
self.isrunning = False
self.closeclient()
self.datasocket.close()
self.ftpsocket.close()
# we use up memory here, so deal with it
gc.collect()
# our thread calls this which then listens
def runserver(myself):
myself.dolisten()
umqtt.py
import usocket as socket
import ustruct as struct
from ubinascii import hexlify
class MQTTException(Exception):
pass
class MQTTClient:
def __init__(self, client_id, server, port=0, user=None, password=None, keepalive=0,
ssl=False, ssl_params={}):
if port == 0:
port = 8883 if ssl else 1883
self.client_id = client_id
self.sock = None
self.server = server
self.port = port
self.ssl = ssl
self.ssl_params = ssl_params
self.pid = 0
self.cb = None
self.user = user
self.pswd = password
self.keepalive = keepalive
self.lw_topic = None
self.lw_msg = None
self.lw_qos = 0
self.lw_retain = False
self.online = True
def _send_str(self, s):
self.sock.write(struct.pack("!H", len(s)))
self.sock.write(s)
def _recv_len(self):
n = 0
sh = 0
while 1:
b = self.sock.read(1)[0]
n |= (b & 0x7f) << sh
if not b & 0x80:
return n
sh += 7
def set_callback(self, f):
self.cb = f
def set_last_will(self, topic, msg, retain=False, qos=0):
assert 0 <= qos <= 2
assert topic
self.lw_topic = topic
self.lw_msg = msg
self.lw_qos = qos
self.lw_retain = retain
def connect(self, clean_session=True):
self.sock = socket.socket()
addr = socket.getaddrinfo(self.server, self.port)[0][-1]
self.sock.connect(addr)
if self.ssl:
import ussl
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
premsg = bytearray(b"\x10\0\0\0\0\0")
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
sz = 10 + 2 + len(self.client_id)
msg[6] = clean_session << 1
if self.user is not None:
sz += 2 + len(self.user) + 2 + len(self.pswd)
msg[6] |= 0xC0
if self.keepalive:
assert self.keepalive < 65536
msg[7] |= self.keepalive >> 8
msg[8] |= self.keepalive & 0x00FF
if self.lw_topic:
sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
msg[6] |= self.lw_retain << 5
i = 1
while sz > 0x7f:
premsg[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
premsg[i] = sz
self.sock.write(premsg, i + 2)
self.sock.write(msg)
#print(hex(len(msg)), hexlify(msg, ":"))
self._send_str(self.client_id)
if self.lw_topic:
self._send_str(self.lw_topic)
self._send_str(self.lw_msg)
if self.user is not None:
self._send_str(self.user)
self._send_str(self.pswd)
resp = self.sock.read(4)
assert resp[0] == 0x20 and resp[1] == 0x02
if resp[3] != 0:
raise MQTTException(resp[3])
return resp[2] & 1
def disconnect(self):
self.sock.write(b"\xe0\0")
self.sock.close()
def ping(self):
self.sock.write(b"\xc0\0")
def publish(self, topic, msg, retain=False, qos=0):
pkt = bytearray(b"\x30\0\0\0")
pkt[0] |= qos << 1 | retain
sz = 2 + len(topic) + len(msg)
if qos > 0:
sz += 2
assert sz < 2097152
i = 1
while sz > 0x7f:
pkt[i] = (sz & 0x7f) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt, i + 1)
self._send_str(topic)
if qos > 0:
self.pid += 1
pid = self.pid
struct.pack_into("!H", pkt, 0, pid)
self.sock.write(pkt, 2)
self.sock.write(msg)
if qos == 1:
while 1:
op = self.wait_msg()
if op == 0x40:
sz = self.sock.read(1)
assert sz == b"\x02"
rcv_pid = self.sock.read(2)
rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
if pid == rcv_pid:
return
elif qos == 2:
assert 0
def subscribe(self, topic, qos=0):
assert self.cb is not None, "Subscribe callback is not set"
pkt = bytearray(b"\x82\0\0\0")
self.pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
#print(hex(len(pkt)), hexlify(pkt, ":"))
self.sock.write(pkt)
self._send_str(topic)
self.sock.write(qos.to_bytes(1, "little"))
while 1:
op = self.wait_msg()
if op == 0x90:
resp = self.sock.read(4)
#print(resp)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
return
def set_status(self):
self.online = False
def get_status(self):
return self.online
# Wait for a single incoming MQTT message and process it.
# Subscribed messages are delivered to a callback previously
# set by .set_callback() method. Other (internal) MQTT
# messages processed internally.
def wait_msg(self):
res = self.sock.read(1)
self.sock.setblocking(True)
if res is None:
return None
if res == b"":
print('OSError -1')
#return None
raise OSError(-1)
if res == b"\xd0": # PINGRESP
self.online = True
sz = self.sock.read(1)[0]
assert sz == 0
return None
op = res[0]
if op & 0xf0 != 0x30:
return op
sz = self._recv_len()
topic_len = self.sock.read(2)
topic_len = (topic_len[0] << 8) | topic_len[1]
topic = self.sock.read(topic_len)
sz -= topic_len + 2
if op & 6:
pid = self.sock.read(2)
pid = pid[0] << 8 | pid[1]
sz -= 2
msg = self.sock.read(sz)
self.cb(topic, msg)
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
self.sock.write(pkt)
elif op & 6 == 4:
assert 0
# Checks whether a pending message from server is available.
# If not, returns immediately with None. Otherwise, does
# the same processing as wait_msg.
def check_msg(self):
self.sock.setblocking(False)
return self.wait_msg()
untp.py
try:
import usocket as socket
except:
import socket
try:
import ustruct as struct
except:
import struct
# (date(2000, 1, 1) - date(1900, 1, 1)).days * 24*60*60
NTP_DELTA = 3155673600
# The NTP host can be configured at runtime by doing: ntptime.host = 'myhost.org'
host = "pool.ntp.org"
def time():
NTP_QUERY = bytearray(48)
NTP_QUERY[0] = 0x1B
addr = socket.getaddrinfo(host, 123)[0][-1]
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.settimeout(1)
res = s.sendto(NTP_QUERY, addr)
msg = s.recv(48)
finally:
s.close()
val = struct.unpack("!I", msg[40:44])[0]
return val - NTP_DELTA
# There's currently no timezone support in MicroPython, so
# utime.localtime() will return UTC time (as if it was .gmtime())
def settime():
t = time()
import machine
import utime
tm = utime.localtime(t)
machine.RTC().datetime((tm[0], tm[1], tm[2],tm[6]+1, tm[3], tm[4], tm[5],0))
def datetime():
t = time()
import utime
tm = utime.localtime(t)
return tm
def DT():
buf = datetime()
return '%4d'%buf[0] + '-%02d'%buf[1]+'-%02d'%buf[2]+' %02d'%buf[3]+':%02d'%buf[4]+':%02d'%buf[5]