I am quite new in micropython and ESP boards and I have the following problem:
The project is a ESP8266 board with a DHT22 and a door contact.
The idea is to read temperature and humidity every 10 minutes and publish them on a MQTT broker.
The temperature is read by another ESP8266 which, when needed, turns a heating ON.
When the heating is ON, the first ESP8266 read and publish the temperature every minute.
And of course, the board constantly check if the door opens and publish any modification of state.
There is also a button, allowing to avoid starting the program when pressed at start-up.
Connection to the Wi-Fi is performed with the following boot.py
Code: Select all
WIFI_SSID = "XXXXXXXXXX"
WIFI_PASSWORD = "XXXXXXXXXXXX"
def sta_connect( timeout = None, disable_ap = False ):
import network, time
from machine import Pin
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
# connecting to network...
wlan.connect( WIFI_SSID, WIFI_PASSWORD )
# Skip connexion wait when RunApp=False to avoids REPL timeout
# testing machine.reset_cause() is not reliable on Huzza ESP8266
runapp = Pin( 12, Pin.IN, Pin.PULL_UP )
if runapp.value() == 0:
print( "WLAN: no wait!")
else:
ctime = time.time()
while not wlan.isconnected():
if timeout and ((time.time()-ctime)>timeout):
print( "WLAN: timeout!" )
break
else:
# print(".")
time.sleep( 0.500 )
# Decommenter pour obtenir des infos
# print('network config:', wlan.ifconfig())
if wlan.isconnected() and disable_ap:
ap = network.WLAN(network.AP_IF)
if ap.active():
ap.active(False)
print( "AP disabled!" )
return wlan.isconnected()
# Disable Access Point if connected as STATION
# Connexion timeout of 40 sec
if sta_connect( disable_ap=True, timeout=20 ):
print( "WLAN: connected!" )
import gc
#import webrepl
#webrepl.start()
gc.collect()
Code: Select all
# coding: utf8
from machine import Pin, reset
import time
from ubinascii import hexlify
from network import WLAN
CLIENT_ID = 'AbriSud'
MQTT_SERVER = "192.168.1.xx"
MQTT_USER = 'Pxxxxxxxs'
MQTT_PSWD = 'xxxxxxxx'
# Auto restart after error
ERROR_REBOOT_TIME = 3600 # 1 h = 3600 sec
# pins and variables
Etat_Chauf = "OFF"
# Temp. DHT22
DHT_PIN = 13
#Door contact
CONTACT_PIN = 14
last_contact_state = 0 # 0 = Fermé - 1 = Ouvert
# --- Conditionnal start ---
runapp = Pin( 12, Pin.IN, Pin.PULL_UP )
led = Pin( 2, Pin.OUT )
led.value( 1 ) # eteindre
def led_error( step ):
global led
t = time.time()
while ( time.time()-t ) < ERROR_REBOOT_TIME:
for i in range( 20 ):
led.value(not(led.value()))
time.sleep(0.100)
led.value( 1 ) # eteindre
time.sleep( 1 )
# clignote nbr fois
for i in range( step ):
led.value( 0 )
time.sleep( 0.5 )
led.value( 1 )
time.sleep( 0.5 )
time.sleep( 1 )
# Re-start the ESP
reset()
if runapp.value() != 1:
from sys import exit
exit(0)
led.value( 0 ) # allumer
# --- MAin programm ---
def sub_cb( topic, msg ):
""" MQTT subscriptions callback """
# debogage
#print( '-'*20 )
#print ('réception message')
#print( topic )
#print( msg )
global Etat_Chauf
# bytes -> str
t = topic.decode( 'utf8' )
m = msg.decode('utf8')
try:
if t == "Maison/Abri/Sud/Etat_chauf":
Etat_Chauf = m
#print("Etat du chauffage:")
#print(Etat_Chauf)
except Exception as e:
# Capturer TOUTE exception sur souscription
# Ne pas crasher check_mqtt_sub et
# asyncio.run_until_complete et l'ESP!
# Info debug sur REPL
print( "="*20 )
print( "Subscriber callback (sub_cb) catch an exception:" )
print( e )
print( "for topic and message" )
print( t )
print( m )
print( "="*20 )
from umqtt.simple import MQTTClient
try:
q = MQTTClient( client_id = CLIENT_ID,
server = MQTT_SERVER,
user = MQTT_USER, password = MQTT_PSWD )
q.set_callback( sub_cb )
if q.connect() != 0:
led_error( step=1 )
q.subscribe( 'Maison/Abri/Sud/Etat_chauf' )
except Exception as e:
print( e )
# check MQTT_SERVER, MQTT_USER, MQTT_PSWD
led_error( step=2 )
# chargement des bibliotheques
try:
from dht import DHT22
from machine import Pin
from math import log
except Exception as e:
print( e )
led_error( step=3 )
# create sensors
try:
# Senseur temp&Co DHT22
DHT = DHT22(Pin(DHT_PIN))
# Contact de porte et lecture
contact = Pin( CONTACT_PIN, Pin.IN, Pin.PULL_UP )
last_contact_state = contact.value()
except Exception as e:
print( e )
led_error( step=4 )
try:
# annonce connexion objet
sMac = hexlify( WLAN().config( 'mac' ) ).decode()
q.publish( "connect/%s" % CLIENT_ID , sMac )
# Annonce l'état
except Exception as e:
print( e )
led_error( step=5 )
import uasyncio as asyncio
def capture_10min():
""" Read and send temp etc. every 10 minutes """
global DHT
DHT.measure()
temp = DHT.temperature()
hum = DHT.humidity()
#print('Temperature: %3.1f °C' %temp)
#print('Humidité: %3.1f%%' %hum)
if hum < 30:
feel = 2
# feel = "Sec"
elif hum < 45:
feel= 0
# feel = "Normal"
elif hum < 70:
feel = 1
# feel = "Agréable"
else:
feel = 3
#feel = "Humide"
alpha = 17.27 * temp/(237.7+temp)+log(hum/100)
dp = 237.7 * alpha / (17.27 - alpha)
dew = "{0:.2f}".format(dp)
t = "{0:.2f}".format(temp)
h = "{0:.2f}".format(hum)
#print('Feel ' + str(feel))
#print('point de rosée : ' + dew)
#message = '{ "idx" : '+str(sensor_idx)+', "nvalue" : 0, "svalue" : "'+ t +';'+ h +';'+str(feel)+'"}'
#q.publish( "domoticz/in", message )
q.publish("Maison/Abri/Sud/Temp", t)
time.sleep(0.5)
q.publish("Maison/Abri/Sud/Hum", h)
time.sleep(0.5)
q.publish("Maison/Abri/Sud/Feel", str(feel))
time.sleep(0.5)
q.publish ("Maison/Abri/Sud/DewP", dew)
def capture_1min():
""" When heating is ON, read and send temp etc. every minute """
global Etat_Chauf
if Etat_Chauf == "ON":
# execution par la routine de capture
capture_10min()
def heartbeat():
""" Led OFF during 200ms every 10 sec """
# PS: LED déjà éteinte par run_every!
time.sleep( 0.2 )
def check_mqtt_sub():
global q
# Non-Blocking wait_msg(). Will call mqtt callback
# (sub_cb) when a message is received for subscription
try:
q.check_msg()
except Exception as e:
print(e)
led_error(step=7)
def check_contact():
""" Publish any state change of door contact """
global q
global last_contact_state
# if nothing changed
if contact.value()==last_contact_state:
return
# if satte changed -> soft clean-up
time.sleep( 0.100 )
# read again and see if changed
valeur = contact.value()
if valeur != last_contact_state:
q.publish( "Maison/Abri/Sud/Porte",
"OUVERTE" if valeur==1 else "FERMEE" )
last_contact_state = valeur
async def run_every( fn, min= 1, sec=None):
""" Execute a function fn every min minutes
or sec secondes"""
global led
wait_sec = sec if sec else min*60
while True:
led.value( 1 ) # eteindre pendant envoi/traitement
try:
fn()
except Exception:
print( "run_every catch exception for %s" % fn)
raise # quitter loop
led.value( 0 ) # allumer
await asyncio.sleep( wait_sec )
async def run_app_exit():
""" fin d'execution lorsque quitte la fonction """
global runapp
while runapp.value()==1:
await asyncio.sleep( 10 )
return
loop = asyncio.get_event_loop()
loop.create_task( run_every(capture_10min , min=10) )
loop.create_task( run_every(capture_1min , min=1) )
loop.create_task( run_every(heartbeat , sec=10 ) )
loop.create_task( run_every(check_contact, sec=2 ) )
loop.create_task( run_every(check_mqtt_sub, sec=2.5) )
try:
# Annonce initial state
q.publish( "Maison/Abri/Sud/Porte", "OUVERTE" if last_contact_state==1 else "FERMEE" )
# Execution of scheduler
loop.run_until_complete( run_app_exit() )
except Exception as e :
print( e )
led_error( step=6 )
loop.close()
led.value( 1 ) # eteindre
print( "Fin!")
But when I try to use all this together with uasyncio, it is quite erratic.
It starts well, the ESP publishes data as supposed to do. It reacts to the opening or closing of the door and change the frequency of temperature reading if MQTT announces that the heater is ON.
But after a certain time (from 5 to 45 minutes) nothing more is published and there is no more reactivity of the board.
With the above main.py running (renamed main_AbriSud.py for testing), I have these lines on the terminal:
Code: Select all
[Errno 103] ECONNABORTED
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "main_AbriSud.py", line 266, in <module>
File "uasyncio/core.py", line 1, in run_until_complete
File "uasyncio/core.py", line 1, in run_until_complete
File "main_AbriSud.py", line 240, in run_every
File "main_AbriSud.py", line 214, in check_mqtt_sub
File "main_AbriSud.py", line 57, in led_error
Code: Select all
run_every catch exception for <function check_mqtt_sub at 0x3fff04d0>
Task exception wasn't retrieved
future: <Task> coro= <generator object 'run_every' at 3fff0eb0>
Traceback (most recent call last):
File "uasyncio/core.py", line 1, in run_until_complete
File "main_AbriSud.py", line 237, in run_every
File "main_AbriSud.py", line 211, in check_mqtt_sub
File "umqtt/simple.py", line 215, in check_msg
File "umqtt/simple.py", line 179, in wait_msg
OSError: [Errno 103] ECONNABORTED
Thank you in advance.