我正在尝试为 ESP32 编写一个温度控制器,它通过 mqtt 将传感器读数发送到安装在 rasperry pi 上的 mosquitto。只要连接了 wifi 并且 mosquitto 在树莓派上运行,代码就会运行。一旦 ESP32 未连接到 wifi 或无法到达 mqtt 代理,代码就会以重新连接循环结束。 这个想法是,即使 wifi 或 mqtt 出现错误,代码的温度控制器端也会继续运行。
由于我对编程相当陌生,我怀疑我的代码非常混乱,因此我收到此错误。我尝试了不同的方式来安排我的函数和循环,但没有运气。
也许有人可以为我指明如何构建代码的正确方向,以便它可以处理异常
from machine import Pin, SoftI2C
import ssd1306
import machine
import utime
import onewire, ds18x20, time
from umqtt.robust import MQTTClient
import ubinascii
from machine import RTC
import os
import micropython
import network
import esp
esp.osdebug(None)
import asyncio
import gc
gc.collect()
###################### define global variables##########################
tempsetpoint = 30.0 # temperature set point
last_message = 0
message_interval = 5
integral = 0
lastupdate = utime.time()
lasterror = 0
output1=0
output2=0
checkin = 0
maxtemperaturedifference = 10
datalogging = False
Kp=100. # 400 Proportional term - Basic steering (This is the first parameter you should tune for a particular setup)
Ki=.01 # .05 Integral term - Compensate for heat loss by vessel
Kd=0. # Derivative term - to prevent overshoot due to inertia - if it is zooming towards setpoint this
# will cancel out the proportional term due to the large negative gradient
output1= 0
output2=0
maxtemperaturedifference = 10
################### Connect to WIFI and MQTT server ##################################
ssid = 'Inabnit'
password = 'Buochserhorn'
mqtt_server = '192.168.50.31'
"""
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(ssid, password)
while station.isconnected() == False:
pass
print('Connection to WIFI successful')
"""
class wifi:
def __init__(self, ssid, password):
self.ssid = ssid
self.password = password
def connect(self):
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(self.ssid, self.password)
while station.isconnected() == False:
pass
print("Connection to %s successful" %self.ssid)
credentials = wifi("Inabnit", "Buochserhorn")
credentials.connect()
################### MQTT Setup ##################################
client_id = ubinascii.hexlify(machine.unique_id())
topic_pub_temp1 = b'esp/ds18b20/temperature1' #topic name, add more if needed
topic_pub_temp2 = b'esp/ds18b20/temperature2' #topic name, add more if needed
topic_pub_output1 = b'esp/mosfet/output1' #topic name, add more if needed
topic_pub_output2 = b'esp/mosfet/output2' #topic name, add more if needed
################### RTC setup ##################################
rtc=RTC()
timeStamp=0
################### Mosfet setup ##################################
#define mosfet1 pin
p0 = machine.Pin(0)
pwm0 = machine.PWM(p0)
pwm0.freq(500)
pwm0.duty_u16(0)
#define mosfet2 pin
p0 = machine.Pin(1)
pwm1 = machine.PWM(p0)
pwm1.freq(500)
pwm1.duty_u16(0)
################### DS18b20 setup ##################################
#define temp sensor pin
ds_pin = machine.Pin(21)
ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin))
#roms = ds_sensor.scan()
#print('Found DS devices: ', roms)
Sensor1 = b"('/\x07\x00\x00\x00<"
Sensor2 = b'\x10Fd\x16\x03\x08\x00\x91'
Sensor3 = b'\x10Fd\x16\x03\x08\x00\x80' #update rom with actual address
################### OLED Setup ##################################
#setup oled
WIDTH = 128 # oled display width
HEIGHT = 64 # oled display height
i2c = SoftI2C(scl=Pin(8), sda=Pin(9))
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
################### Functions ##################################
######################## Logging function#########################
with open('savedata.txt', 'a') as f:
f.write('Temperature Data Logging')
f.write('\n')
def logData():
timeTuple=rtc.datetime()
file_size=os.stat('/savedata.txt')
if(file_size[6]<2000000):
try:
with open('savedata.txt', 'a') as f:
f.write(str(timeTuple[4])+':'+str(timeTuple[5])+':'+str(timeTuple[6])+ ',')
f.write(str(temp)+ ',')
f.write(str(output1))
#f.write(scaled_output)
f.write('\n')
print("Data Saved!")
except:
print("Error! Could not save")
################scaling function to scale X-XXX to X-XXX exapmple: scale_value(output, 0, 100, 0, 65535)#############
def scale_value(value, in_min, in_max, out_min, out_max):
scaled_value = (value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
return int(scaled_value)
################################
def checktemperature():
global temp_max
global temp1
global temp2
global tempdifference
#global temp3 #uncomment if 3 sensors will be used
ds_sensor.convert_temp()
temp1 = round(ds_sensor.read_temp(Sensor1),1)
temp2 = round(ds_sensor.read_temp(Sensor2),1)
#temp3 = round(ds_sensor.read_temp(Sensor3),1) #uncomment if 3 sensors will be used
temp_max = round(max(temp1, temp2),1)
#temp_max = round(max(temp1, temp2, temp3),1) #uncomment if 3 sensors will be used
#print(temp_max)
tempdifference = abs(temp1-temp2)
################################
def displayonOLED():
#display data on the oled
# Clear the oled display in case it has junk on it.
oled.fill(0)
oled.contrast(255) # bright
# Add some text
#oled.text("Temperature ",12,5)
oled.text("Setpoint: ",1,5)
oled.text(str(tempsetpoint),88,5)
oled.text("Sensor 1: ",1,15)
oled.text(str(temp1),88,15)
oled.text("Sensor 2: ",1,25)
oled.text(str(temp2),88,25)
oled.text("Sensor Max: ",1,35)
oled.text(str(temp_max),88,35)
oled.text("Output 1: ",1,45)
oled.text(str(output1),88,45)
# Finally update the oled display so the image & text is displayed
oled.show()
###################################
def displayonOLED_tempdiff():
#display data on the oled
# Clear the oled display in case it has junk on it.
oled.fill(0)
"""### Blink OLED###
oled.show()
utime.sleep_ms(200)
oled.fill(1)
oled.show()
utime.sleep_ms(200)
"""
oled.fill(0)
oled.contrast(255) # bright
# Add some text
oled.text("Temp diff.> 10",1,5)
oled.text("Sensor 1: ",1,15)
oled.text(str(temp1),88,15)
oled.text("Sensor 2: ",1,25)
oled.text(str(temp2),88,25)
# Finally update the oled display so the image & text is displayed
oled.show()
####################### Connect to MQTT Broker###################
def connect_mqtt():
global client_id, mqtt_server
try:
client = MQTTClient(client_id, mqtt_server)
#client = MQTTClient(client_id, mqtt_server, user=your_username, password=your_password)
client.DEBUG = True
client.connect()
#client.loop_start()
print('Connected to %s MQTT broker' % (mqtt_server))
return client
except:
print("Error: MQTT client not reachable")
######################### restart MQTT
def restart_and_reconnect():
failsafe()
print('Failed to connect to MQTT broker. Reconnecting...')
#time.sleep(10)
#machine.reset()
###########publish to mqtt#################
def publishtomqtt():
global client_id, mqtt_server
temp1_mqtt = (b'{0:3.1f}'.format(temp1))
temp2_mqtt = (b'{0:3.1f}'.format(temp2))
output1_mqtt = (b'{0:3.1f}'.format(output1))
output2_mqtt = (b'{0:3.1f}'.format(output2))
try:
client = MQTTClient(client_id, mqtt_server)
#client = MQTTClient(client_id, mqtt_server, user=your_username, password=your_password)
client.DEBUG = True
client.connect()
#client.loop_start()
print('Connected to %s MQTT broker' % (mqtt_server))
except OSError as e:
#restart_and_reconnect()
print("Error puplishtomqtt")
#client = connect_mqtt()
client.publish(topic_pub_temp1, temp1_mqtt)
client.publish(topic_pub_temp2, temp2_mqtt)
client.publish(topic_pub_output1, output1_mqtt)
client.publish(topic_pub_output2, output2_mqtt)
client.disconnect()
#######################Heater Failsafe##############################
def failsafe():
pwm0.duty_u16(0)
pwm1.duty_u16(0)
print("Heating Stopped!")
################### Main Logic ##################################
checktemperature()
while True:
if (time.ticks_ms()-timeStamp)>5000:
timeStamp=time.ticks_ms()
if tempdifference <= maxtemperaturedifference:
try:
checktemperature()
displayonOLED()
if (time.ticks_ms()-timeStamp)>5000:
if datalogging == True :
logData()
try:
publishtomqtt()
except Exception as e:
print( "An error has occurred!")
timeStamp=time.ticks_ms()
now = utime.time()
dt= now-lastupdate
if dt > checkin:
error=tempsetpoint-temp1
integral = integral + dt * error
derivative = (error - lasterror)/dt
output1 = Kp * error + Ki * integral + Kd * derivative
#print(str(output)+"= Kp term: "+str(Kp*error)+" + Ki term:" + str(Ki*integral) + "+ Kd term: " + str(Kd*derivative))
output1 = max(min(100, output1), 0) # Clamp output between 0 and 100
scaled_output1 = scale_value(output1, 0, 100, 0, 65535)
error=tempsetpoint-temp2
integral = integral + dt * error
derivative = (error - lasterror)/dt
output2 = Kp * error + Ki * integral + Kd * derivative
#print(str(output)+"= Kp term: "+str(Kp*error)+" + Ki term:" + str(Ki*integral) + "+ Kd term: " + str(Kd*derivative))
output2 = max(min(100, output2), 0) # Clamp output between 0 and 100
scaled_output2 = scale_value(output2, 0, 100, 0, 65535)
print('Output1: ', round(output1),'% ', 'Output2: ', round(output2),'% ', 'Temp_max: ', temp_max,'°C ', 'Temp1: ', temp1, '°C ', 'Temp2: ', temp2, '°C')
#print('Output: ', output,'% ', 'Temp_max: ', temp_max,'°C ', 'Temp1: ', temp1, '°C ', 'Temp2: ', temp2, '°C', 'Temp3: ', temp3, '°C') #uncomment if 3 sensors will be used
if output1>0:
pwm0.duty_u16(scaled_output1)
if output2>0:
pwm1.duty_u16(scaled_output2)
else:
pwm0.duty_u16(0)
pwm1.duty_u16(0)
#utime.sleep(.1)
lastupdate = now
lasterror = error
except Exception as e:
if (time.ticks_ms()-timeStamp)>1000:
timeStamp=time.ticks_ms()
failsafe()
print('error encountered:'+str(e))
utime.sleep(checkin)
else:
if (time.ticks_ms()-timeStamp)>1000:
timeStamp=time.ticks_ms()
print("Temperature difference >5!")
checktemperature()
displayonOLED_tempdiff()
failsafe()
我只是尝试构建您的代码并提供一些有关处理代码中异常的示例。
from machine import Pin, SoftI2C
import ssd1306
import machine
import utime
import onewire
import ds18x20
from umqtt.robust import MQTTClient
import ubinascii
from machine import RTC
import os
import network
import esp
# ... (Other imports)
###################### Define Global Variables ##########################
tempsetpoint = 30.0
integral = 0
lastupdate = utime.time()
lasterror = 0
output1 = 0
output2 = 0
checkin = 0
maxtemperaturedifference = 10
datalogging = False
Kp = 100.0
Ki = 0.01
Kd = 0.0
# ... (Other global variables)
ssid = 'Inabnit'
password = 'Buochserhorn'
mqtt_server = '192.168.50.31'
# ... (Other configurations)
class Wifi:
def __init__(self, ssid, password):
self.ssid = ssid
self.password = password
def connect(self):
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(self.ssid, self.password)
while not station.isconnected():
pass
print("Connection to %s successful" % self.ssid)
credentials = Wifi("Inabnit", "Buochserhorn")
credentials.connect()
# ... (Other configurations)
client_id = ubinascii.hexlify(machine.unique_id())
topic_pub_temp1 = b'esp/ds18b20/temperature1'
topic_pub_temp2 = b'esp/ds18b20/temperature2'
topic_pub_output1 = b'esp/mosfet/output1'
topic_pub_output2 = b'esp/mosfet/output2'
# ... (Other configurations)
###################### Functions ##########################
def connect_mqtt():
global client_id, mqtt_server
try:
client = MQTTClient(client_id, mqtt_server)
client.DEBUG = True
client.connect()
print('Connected to %s MQTT broker' % mqtt_server)
return client
except Exception as e:
print("Error: MQTT client not reachable")
return None
def restart_and_reconnect():
failsafe()
print('Failed to connect to MQTT broker. Reconnecting...')
def publish_to_mqtt(client):
if client is not None:
temp1_mqtt = b'{0:3.1f}'.format(temp1)
temp2_mqtt = b'{0:3.1f}'.format(temp2)
output1_mqtt = b'{0:3.1f}'.format(output1)
output2_mqtt = b'{0:3.1f}'.format(output2)
try:
client.publish(topic_pub_temp1, temp1_mqtt)
client.publish(topic_pub_temp2, temp2_mqtt)
client.publish(topic_pub_output1, output1_mqtt)
client.publish(topic_pub_output2, output2_mqtt)
except Exception as e:
print("Error publishing to MQTT:", e)
finally:
client.disconnect()
# ... (Other functions)
###################### Main Logic ##########################
checktemperature()
while True:
if (utime.ticks_ms() - timeStamp) > 5000:
timeStamp = utime.ticks_ms()
if tempdifference <= maxtemperaturedifference:
try:
checktemperature()
displayonOLED()
if (utime.ticks_ms() - timeStamp) > 5000:
if datalogging:
logData()
try:
mqtt_client = connect_mqtt()
if mqtt_client:
publishtomqtt(mqtt_client)
except Exception as e:
print("An error has occurred:", e)
timeStamp = utime.ticks_ms()
now = utime.time()
dt = now - lastupdate
if dt > checkin:
error = tempsetpoint - temp1
integral = integral + dt * error
derivative = (error - lasterror) / dt
output1 = Kp * error + Ki * integral + Kd * derivative
output1 = max(min(100, output1), 0)
scaled_output1 = scale_value(output1, 0, 100, 0, 65535)
error = tempsetpoint - temp2
integral = integral + dt * error
derivative = (error - lasterror) / dt
output2 = Kp * error + Ki * integral + Kd * derivative
output2 = max(min(100, output2), 0)
scaled_output2 = scale_value(output2, 0, 100, 0, 65535)
print('Output1: ', round(output1), '% ', 'Output2: ', round(output2), '% ',
'Temp_max: ', temp_max, '°C ', 'Temp1: ', temp1, '°C ', 'Temp2: ', temp2, '°C')
if output1 > 0:
pwm0.duty_u16(scaled_output1)
if output2 > 0:
pwm1.duty_u16(scaled_output2)
else:
pwm0.duty_u16(0)
pwm1.duty_u16(0)
lastupdate = now
lasterror = error
except Exception as e:
if (utime.ticks_ms() - timeStamp) > 1000:
timeStamp = utime.ticks_ms()
failsafe()
print('Error encountered:', e)
utime.sleep(checkin)
else:
if (utime.ticks_ms() - timeStamp) > 1000:
timeStamp = utime.ticks_ms()
print("Temperature difference > 5!")
checktemperature()
displayonOLED_tempdiff()
failsafe()
在修改后的代码中,我添加了一些异常处理,以提高处理潜在错误的稳健性。以下是代码各个部分处理异常的总结:
MQTT 连接异常:
在 connect_mqtt 函数中,如果连接到 MQTT 代理出现问题,则会捕获异常。
try:
# MQTT connection logic
except Exception as e:
print("Error: MQTT client not reachable")
MQTT 发布异常:
在publish_to_mqtt函数中,如果在向MQTT主题发布消息的过程中出现错误,则会捕获异常。
try:
# MQTT publishing logic
except Exception as e:
print("Error publishing to MQTT:", e)
finally:
# Disconnect the MQTT client even if an exception occurred
client.disconnect()
主要逻辑异常:
在主逻辑循环中,添加了通用异常处理程序来捕获主循环执行过程中可能发生的任何意外错误。
try:
# Main logic
except Exception as e:
if (utime.ticks_ms() - timeStamp) > 1000:
timeStamp = utime.ticks_ms()
failsafe()
print('Error encountered:', e)
utime.sleep(checkin)
这些异常旨在捕获错误,例如连接到 MQTT 代理时的网络连接问题或程序主逻辑中的意外错误。使用特定的异常类型(Exception)是为了简单起见,在生产环境中,您可能希望根据潜在错误的性质来处理更具体的异常。