diff --git a/code/config_template.py b/code/config_template.py index fd1e88e..5f2bfc8 100644 --- a/code/config_template.py +++ b/code/config_template.py @@ -1,15 +1,13 @@ """Fichier de configuration """ -CLIENT_ID = "" -ADAFRUIT_IO_HOST = "" -ADAFRUIT_IO_USERNAME = "" -ADAFRUIT_IO_KEY = "" +CLIENT_ID = "Test" +LOCATION = "On desk" -MQTT_HOST = "" +MQTT_HOST = "192.168.0.1" MQTT_PORT = 1883 -MQTT_USERNAME = "" -MQTT_PASSWD = "" +MQTT_USERNAME = "user" +MQTT_PASSWD = "passwd" -WIFI_SSID = "" -WIFI_PSK = "" +WIFI_SSID = "my_wifi_ssid" +WIFI_PSK = "my_wifi_wpa_key" diff --git a/code/lib/bme280_i2c.mpy b/code/lib/bme280_i2c.mpy new file mode 100644 index 0000000..40963ea Binary files /dev/null and b/code/lib/bme280_i2c.mpy differ diff --git a/code/lib/umqtt/robust.mpy b/code/lib/umqtt/robust.mpy new file mode 100644 index 0000000..6acf72b Binary files /dev/null and b/code/lib/umqtt/robust.mpy differ diff --git a/code/lib/umqtt/robust.py b/code/lib/umqtt/robust.py new file mode 100644 index 0000000..7ee40e0 --- /dev/null +++ b/code/lib/umqtt/robust.py @@ -0,0 +1,43 @@ +import utime +from . import simple + +class MQTTClient(simple.MQTTClient): + + DELAY = 2 + DEBUG = False + + def delay(self, i): + utime.sleep(self.DELAY) + + def log(self, in_reconnect, e): + if self.DEBUG: + if in_reconnect: + print("mqtt reconnect: %r" % e) + else: + print("mqtt: %r" % e) + + def reconnect(self): + i = 0 + while 1: + try: + return super().connect(False) + except OSError as e: + self.log(True, e) + i += 1 + self.delay(i) + + def publish(self, topic, msg, retain=False, qos=0): + while 1: + try: + return super().publish(topic, msg, retain, qos) + except OSError as e: + self.log(False, e) + self.reconnect() + + def wait_msg(self): + while 1: + try: + return super().wait_msg() + except OSError as e: + self.log(False, e) + self.reconnect() diff --git a/code/lib/umqtt/simple.mpy b/code/lib/umqtt/simple.mpy new file mode 100644 index 0000000..773e62e Binary files /dev/null and b/code/lib/umqtt/simple.mpy differ diff --git a/code/lib/mqtt.py b/code/lib/umqtt/simple.py similarity index 86% rename from code/lib/mqtt.py rename to code/lib/umqtt/simple.py index d6e5102..8216fa5 100644 --- a/code/lib/mqtt.py +++ b/code/lib/umqtt/simple.py @@ -1,11 +1,3 @@ -# Copyright (c) 2019, Pycom Limited. -# -# This software is licensed under the GNU GPL version 3 or any -# later version, with permitted additional terms. For more information -# see the Pycom Licence v1.0 document supplied with this file, or -# available at https://www.pycom.io/opensource/licensing -# - import usocket as socket import ustruct as struct from ubinascii import hexlify @@ -21,7 +13,8 @@ class MQTTClient: port = 8883 if ssl else 1883 self.client_id = client_id self.sock = None - self.addr = socket.getaddrinfo(server, port)[0][-1] + self.server = server + self.port = port self.ssl = ssl self.ssl_params = ssl_params self.pid = 0 @@ -61,24 +54,36 @@ class MQTTClient: def connect(self, clean_session=True): self.sock = socket.socket() - self.sock.connect(self.addr) + 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) - msg = bytearray(b"\x10\0\0\x04MQTT\x04\x02\0\0") - msg[1] = 10 + 2 + len(self.client_id) - msg[9] = clean_session << 1 + 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: - msg[1] += 2 + len(self.user) + 2 + len(self.pswd) - msg[9] |= 0xC0 + sz += 2 + len(self.user) + 2 + len(self.pswd) + msg[6] |= 0xC0 if self.keepalive: assert self.keepalive < 65536 - msg[10] |= self.keepalive >> 8 - msg[11] |= self.keepalive & 0x00FF + msg[7] |= self.keepalive >> 8 + msg[8] |= self.keepalive & 0x00FF if self.lw_topic: - msg[1] += 2 + len(self.lw_topic) + 2 + len(self.lw_msg) - msg[9] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3 - msg[9] |= self.lw_retain << 5 + 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) diff --git a/code/main.py b/code/main.py index 15bd1bd..05103d4 100644 --- a/code/main.py +++ b/code/main.py @@ -1,12 +1,13 @@ """Station météo connectée au service Adafruit IO """ - import time import machine import network +import esp import bme280_i2c -from mqtt import MQTTClient +from ntptime import settime +from umqtt.robust import MQTTClient import config # connect to WLAN @@ -44,6 +45,15 @@ bme.set_measurement_settings({ bme.set_power_mode(bme280_i2c.BME280_NORMAL_MODE) +def MqttPublish(client, topic, message, retain=False, qos=0, sleep=10): + """MQTT publish helper""" + client.publish("test/{device}/{topic}".format(device=config.CLIENT_ID, topic=topic), + message, + retain=retain, + qos=qos) + time.sleep_ms(sleep) + + client = MQTTClient(client_id=config.CLIENT_ID, server=config.MQTT_HOST, user=config.MQTT_USERNAME, @@ -51,34 +61,40 @@ client = MQTTClient(client_id=config.CLIENT_ID, port=config.MQTT_PORT) client.connect() -client.publish("test/bme280/humidity/unit", "%", retain=True, qos=0) -client.publish("test/bme280/humidity/desc", "Capteur Bosch BME280", retain=True, qos=0) -time.sleep_ms(100) -client.publish("test/bme280/pressure/unit", "hPa", retain=True, qos=0) -client.publish("test/bme280/pressure/desc", "Capteur Bosch BME280", retain=True, qos=0) -time.sleep_ms(100) -client.publish("test/bme280/temperature/unit", "degC", retain=True, qos=0) -client.publish("test/bme280/temperature/desc", "Capteur Bosch BME280", retain=True, qos=0) -time.sleep_ms(100) -client.publish("test/esp8266_0/wifi/ssid", config.WIFI_SSID, retain=True, qos=0) -client.publish("test/esp8266_0/wifi/ip", wlan.ifconfig()[0], retain=True, qos=0) +MqttPublish(client, "location", config.LOCATION, retain=True, qos=1) +MqttPublish(client, "humidity/unit", "%", retain=True) +MqttPublish(client, "humidity/desc", "Capteur Bosch BME280", retain=True, qos=0) +MqttPublish(client, "pressure/unit", "hPa", retain=True, qos=0) +MqttPublish(client, "pressure/desc", "Capteur Bosch BME280", retain=True, qos=0) +MqttPublish(client, "temperature/unit", "degC", retain=True, qos=0) +MqttPublish(client, "temperature/desc", "Capteur Bosch BME280", retain=True, qos=0) +MqttPublish(client, "wifi/ssid", config.WIFI_SSID, retain=True, qos=0) +MqttPublish(client, "wifi/ip", wlan.ifconfig()[0], retain=True, qos=0) +MqttPublish(client, "wifi/channel", "{:d}".format(net[2]), retain=True, qos=0) +MqttPublish(client, "sys/esp8266_device_id", "{:d}".format(esp.flash_id()), retain=True, qos=0) + time.sleep_ms(1000) -# For each nature, a list describe: +# For each nature, a list describes: # - mqtt topic # - string format # - factor (multiplier) -topics = {"humidity" : ["test/esp8266_0/humidity/value", "{:.0f}", 1], - "pressure" : ["test/esp8266_0/pressure/value", "{:.2f}", 0.01], - "temperature" : ["test/esp8266_0/temperature/value", "{:.1f}", 1]} +# - qos +topics = {"humidity" : ["humidity/value", "{:.0f}", 1, 1], + "pressure" : ["pressure/value", "{:.2f}", 0.01, 1], + "temperature" : ["temperature/value", "{:.1f}", 1, 1]} while 1: bme_data = bme.get_measurement() print(bme_data) for nature, param in topics.items(): - client.publish(param[0], param[1].format(bme_data[nature]*param[2])) + MqttPublish(client, + param[0], + param[1].format(bme_data[nature]*param[2]), + qos=param[3], + sleep=50) - client.publish("test/esp8266_0/wifi/rssi", "{:.0f}".format(wlan.status('rssi'))) + MqttPublish(client, "wifi/rssi", "{:.0f}".format(wlan.status('rssi'))) time.sleep_ms(1000)