Rozdíly
Zde můžete vidět rozdíly mezi vybranou verzí a aktuální verzí dané stránky.
Obě strany předchozí revize Předchozí verze Následující verze | Předchozí verze | ||
it:iot:esp8266:vyroba-wifi-teplomeru [2023/01/04 21:54] – Petr Nosek | it:iot:esp8266:vyroba-wifi-teplomeru [2024/01/02 17:17] (aktuální) – Petr Nosek | ||
---|---|---|---|
Řádek 1: | Řádek 1: | ||
====== Výroba Wi-Fi teploměru s ESP8266 ====== | ====== Výroba Wi-Fi teploměru s ESP8266 ====== | ||
- | Wi-Fi teploměr | + | Wi-Fi teploměr |
* [[https:// | * [[https:// | ||
Řádek 7: | Řádek 7: | ||
Pro programování jsem na destičku esp8266 nahrál Micropython. Cílem je, aby se destička připojovala k Mosquitto a posílala tak zprávy skrze MQTT protokol. | Pro programování jsem na destičku esp8266 nahrál Micropython. Cílem je, aby se destička připojovala k Mosquitto a posílala tak zprávy skrze MQTT protokol. | ||
+ | |||
+ | <adm warning> | ||
Jako výborný zdroj posloužil článek [[https:// | Jako výborný zdroj posloužil článek [[https:// | ||
ESP32 MQTT – Publish and Subscribe with Arduino IDE senzor BME280]]. Nicméně v článku nepoužívají Python - kód jsem čerpat tedy odjinud. | ESP32 MQTT – Publish and Subscribe with Arduino IDE senzor BME280]]. Nicméně v článku nepoužívají Python - kód jsem čerpat tedy odjinud. | ||
- | |||
Později jsem objevil tento článek [[https:// | Později jsem objevil tento článek [[https:// | ||
Řádek 493: | Řádek 494: | ||
</ | </ | ||
+ | |||
+ | |||
+ | ==== Problém s přerušením spojení s MQTT serverem ==== | ||
+ | |||
+ | V provozu se mi ukázalo, že když dojde k přerušení spojení s MQTT serverem, tak mi nezbyde nic jiného, než zařízení fyzicky resetovat. Což není zrovna příjemný počin - zejména, pokud budu mít více takových zařízení. Hledal jsem způsob, jak kontrolovat, | ||
+ | |||
+ | Proto jsem vytvořil funkci, která kontroluje, zda je připojení aktivní. V rámci funkce posílám testovací zprávu na mqtt servrer. Podmínkou je, že řeším Quality Of Service = 1, tedy čekám na odpověď ze serveru, zda byla zpráva opravdu doručena. Pokud nebyla, vyvolá se výjimka. | ||
+ | |||
+ | <code python> | ||
+ | def is_connected(mqttc): | ||
+ | try: | ||
+ | mqttc.publish(b" | ||
+ | return True | ||
+ | except OSError: | ||
+ | return False | ||
+ | </ | ||
+ | |||
+ | <adm warning> | ||
+ | |||
+ | Proto jsem použití MicroPython přehodnotil. Vede mě k tomu víc důvodů: | ||
+ | |||
+ | * softwarová podpora - je mnoho kódu v C pro Arduino, ale málo pro MicroPython. Pro další vzdělávání je to problém. Navíc u MicroPythonu se musí využívat knihovny, které jsou nějak minimalizované. Proto kód pro Micropython není jednoduše přenesitelný na Python a naopak, jak jsem si mylně sliboval. | ||
+ | * výkon/ | ||
+ | * bezpečnost použití - kód v C je kompilovaný. Takže když někdo přijde k zařízení s esp8266, nebude mít jednoduché vyčíst hesla k Wi-Fi, certifikát atp. Kdežto při použití Micro Pythonu to bude velmi jednoduché. Stačí zařízení na chvíli připojit k USB portu a program a certifikát v otevřené podobě. | ||
+ | * od C++ očekávám větší stabilitu - co se týče čipu esp8266 | ||
+ | |||
+ | Proto jsem myšlenku použití Micro Pythonu pro moje účely opustil a raději si napíšu program v C++. V rámci stránky připojuji i kód v C++ pro esp8266. | ||
+ | </ | ||
Řádek 543: | Řádek 572: | ||
print(' | print(' | ||
sleep(10) | sleep(10) | ||
- | machine.reset() | + | |
+ | try: | ||
+ | mqttc = connect_and_subscribe() | ||
+ | except OSError as e: | ||
+ | restart_and_reconnect() | ||
+ | # alternativou je reset celého zařízení | ||
+ | #machine.reset() | ||
+ | |||
+ | def is_connected(mqttc): | ||
+ | try: | ||
+ | mqttc.publish(b" | ||
+ | return True | ||
+ | except OSError: | ||
+ | return False | ||
+ | | ||
try: | try: | ||
Řádek 560: | Řádek 603: | ||
data[' | data[' | ||
data[' | data[' | ||
+ | | ||
+ | | ||
+ | if not is_connected(mqttc): | ||
+ | restart_and_reconnect() | ||
+ | | ||
| | ||
print(ujson.dumps(data)) | print(ujson.dumps(data)) | ||
Řádek 583: | Řádek 631: | ||
+ | |||
+ | ===== Kód pro teploměr s ESP8266 napsaný v C++ ===== | ||
+ | |||
+ | I když jsem začal stránku s tím, že budu používat MicroPython, | ||
+ | |||
+ | <code cpp> | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | #include < | ||
+ | |||
+ | #include " | ||
+ | #include " | ||
+ | |||
+ | |||
+ | |||
+ | const char* WiFiName = " | ||
+ | const char* WiFiPassword = " | ||
+ | |||
+ | |||
+ | // MQTT connection | ||
+ | const char* clientName = " | ||
+ | const char* mqttBroker = " | ||
+ | const int mqttPort = 8883; | ||
+ | const char* mqttUser = " | ||
+ | const char* mqttPassword = " | ||
+ | const char* mqttTopic = "/ | ||
+ | |||
+ | Adafruit_BME280 bme; | ||
+ | |||
+ | |||
+ | |||
+ | WiFiClientSecure espClient; | ||
+ | PubSubClient mqttClient(espClient); | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | void setupWiFi() { | ||
+ | | ||
+ | | ||
+ | WiFi.mode(WIFI_STA); | ||
+ | WiFi.begin(WiFiName, | ||
+ | | ||
+ | // connect to WiFi | ||
+ | Serial.print(" | ||
+ | | ||
+ | // wait for connecting to the server | ||
+ | // during this waiting it will write dot to serial link | ||
+ | while (WiFi.status() != WL_CONNECTED) { | ||
+ | delay(500); | ||
+ | Serial.print(" | ||
+ | } | ||
+ | |||
+ | // write new line, Wi-Fi network and IP address of connection | ||
+ | Serial.println("" | ||
+ | Serial.print(" | ||
+ | Serial.println(WiFiName); | ||
+ | Serial.print(" | ||
+ | Serial.println(WiFi.localIP()); | ||
+ | |||
+ | WiFi.setAutoReconnect(true); | ||
+ | WiFi.persistent(true); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | void reconnectMQTT() { | ||
+ | |||
+ | int retryCount = 0; | ||
+ | |||
+ | while (!mqttClient.connected()) { | ||
+ | |||
+ | Serial.println(" | ||
+ | |||
+ | // SSL/TLS certificate and key settings | ||
+ | // The BearSSL:: | ||
+ | // for the duration of their usage by espClient. If these objects are defined | ||
+ | // within a separate function and used here, they will be destroyed when that | ||
+ | // function exits, leading to undefined behavior and potential device resets. | ||
+ | // A solution to this is to declare them as global variables if they need to | ||
+ | // be used across multiple functions. | ||
+ | BearSSL:: | ||
+ | BearSSL:: | ||
+ | |||
+ | |||
+ | |||
+ | espClient.setInsecure(); | ||
+ | espClient.setClientRSACert(& | ||
+ | |||
+ | mqttClient.setServer(mqttBroker, | ||
+ | |||
+ | |||
+ | if (mqttClient.connect(clientName, | ||
+ | | ||
+ | Serial.println(" | ||
+ | | ||
+ | } else { | ||
+ | Serial.print(" | ||
+ | Serial.print(mqttClient.state()); | ||
+ | Serial.println(" | ||
+ | delay(5000); | ||
+ | |||
+ | retryCount++; | ||
+ | |||
+ | if (retryCount > 5) { // Restart the ESP if it fails to connect 5 times | ||
+ | // | ||
+ | } | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | |||
+ | void setup() { | ||
+ | |||
+ | |||
+ | // put your setup code here, to run once: | ||
+ | |||
+ | | ||
+ | // start communication on serial line | ||
+ | Serial.begin(9600); | ||
+ | |||
+ | |||
+ | // Inicializace BME280 | ||
+ | if (!bme.begin(0x76)) { // BME280 I2C sensor address | ||
+ | Serial.println(" | ||
+ | while (1); | ||
+ | } | ||
+ | | ||
+ | setupWiFi(); | ||
+ | | ||
+ | reconnectMQTT(); | ||
+ | |||
+ | } | ||
+ | |||
+ | |||
+ | void loop() { | ||
+ | // put your main code here, to run repeatedly: | ||
+ | |||
+ | if (!mqttClient.connected()) { | ||
+ | reconnectMQTT(); | ||
+ | } | ||
+ | mqttClient.loop(); | ||
+ | |||
+ | |||
+ | // send message each 5 sec | ||
+ | static unsigned long lastMsg = 0; | ||
+ | unsigned long now = millis(); | ||
+ | |||
+ | if (now - lastMsg > 5000) { | ||
+ | lastMsg = now; | ||
+ | |||
+ | // read data from BME280 | ||
+ | float humidity = bme.readHumidity(); | ||
+ | float temperature = bme.readTemperature(); | ||
+ | float pressure = bme.readPressure() / 100.0F; | ||
+ | |||
+ | |||
+ | // Vytvoření JSON objektu | ||
+ | StaticJsonDocument< | ||
+ | | ||
+ | doc[" | ||
+ | doc[" | ||
+ | doc[" | ||
+ | |||
+ | // Serializace JSON objektu do řetězce | ||
+ | char jsonBuffer[200]; | ||
+ | serializeJson(doc, | ||
+ | |||
+ | // Odeslání JSON řetězce na MQTT server | ||
+ | mqttClient.publish(mqttTopic, | ||
+ | | ||
+ | } | ||
+ | |||
+ | |||
+ | } | ||
+ | |||
+ | </ | ||
+ | |||
+ | <adm warning> |