Как обновить скетч до NodeMCU «по воздуху» с помощью Arduino IDE?
Я пытаюсь использовать скетч из этого репозитория, который использует MQTT для отправки уведомления в Home-Assistant, который действует как «датчик присутствия». Когда NodeMCU попадает в диапазон указанного SSID, контроллер подключается к Wi-Fi и отправляет сообщение MQTT домашнему помощнику, который затем может выполнить некоторые команды домашней автоматизации. Этот код делает именно это. Сообщения MQTT отправляются и принимаются.
Что не работает, так это то, что я не могу обновить скетч по беспроводной сети (OTA) через включенную библиотеку ArduinoOTA. После загрузки этого скетча в NodeMCU он подключается к Wi-Fi, и на выходе консоли я получаю сообщение о том, что устройство готово к OTA-обновлениям. Судя по всему, что я прочитал, я полагаю, что в меню Arduino должна быть опция, где я могу указать, что хочу обновлять OTA вместо com-порта. Как я могу включить это в IDE? Кроме того, есть ли способ «подключиться» к последовательному монитору, чтобы я мог видеть выходной сигнал OTA?
Для вашего удобства прилагаю скетч:
///////////////////////////////////////////// /////////////////////////////////////////////////// //////
// Измените эти значения для вашей среды
const char* wifiSSID = "wifissid"; // Имя вашей сети Wi-Fi
const char* wifiPassword = "wifipassword"; // Пароль вашей сети Wi-Fi
const char* otaPassword = "myotapassword"; // ОТА-обновление пароля
const char* mqttServer = "192.168.1.2"; // IP-адрес вашего MQTT-сервера
const char* mqttUser = ""; // имя пользователя mqtt, установлено значение "" для отсутствия пользователя
const char* mqttPassword = ""; // пароль mqtt, установлен на "" для отсутствия пароля
const String mqttNode = "CarPresence"; // Ваше уникальное имя хоста для этого устройства
const String mqttDiscoveryPrefix = "homeassistant"; // Home Assistant MQTT Discovery, см. https://home-assistant.io/docs/mqtt/discovery/
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// Home Assistant MQTT Discovery, см. https://home-assistant.io/docs/mqtt/discovery/
// Мы создадим одно устройствоbinary_sensor для отслеживания подключения MQTT.
const String mqttDiscoBinaryStateTopic = mqttDiscoveryPrefix + "/binary_sensor/" + mqttNode + "/state";
const String mqttDiscoBinaryConfigTopic = mqttDiscoveryPrefix + "/binary_sensor/" + mqttNode + "/config";
// И датчик уровня сигнала Wi-Fi
const String mqttDiscoSignalStateTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-signal/state";
const String mqttDiscoSignalConfigTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-signal/config";
// И датчик времени безотказной работы устройства
const String mqttDiscoUptimeStateTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-uptime/state";
const String mqttDiscoUptimeConfigTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-uptime/config";
// Строки ниже будут распространяться на PubSubClient_MAX_PACKET_SIZE 128
// Вам нужно будет вручную установить MQTT_MAX_PACKET_SIZE в PubSubClient.h на 512
const String mqttDiscoBinaryConfigPayload = "{\"name\": \"" + mqttNode + "\", \"device_class\": \"connectivity\", \"state_topic\": \"" + mqttDiscoBinaryStateTopic + "\"}";
const String mqttDiscoSignalConfigPayload = "{\"name\": \"" + mqttNode + "-signal\", \"state_topic\": \"" + mqttDiscoSignalStateTopic + "\", \"unit_of_measurement\": \"dBm\", \"value_template\": \"{{ value }}\"}";
const String mqttDiscoUptimeConfigPayload = "{\"name\": \"" + mqttNode + "-uptime\", \"state_topic\": \"" + mqttDiscoUptimeStateTopic + "\", \"unit_of_measurement\": \"msec\", \"value_template\": \"{{ value }}\"}";
// Устанавливаем уровень сигнала и интервал отчета о времени безотказной работы в миллисекундах
const unsigned long reportInterval = 5000;
unsigned long reportTimer = millis();
// Устанавливаем время «мерцания» светодиода для максимальной видимости при дневном свете
const unsigned long twinkleInterval = 50;
unsigned long twinkleTimer = millis();
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// Настройка системы
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
Serial.begin(115200);
Serial.println("\nHardware initialized, starting program load");
// Запускаем сеть
setupWifi();
// Создаем сервер и назначаем обратные вызовы для MQTT
mqttClient.setServer(mqttServer, 1883);
mqttClient.setCallback(mqtt_callback);
// Запускаем ОТА
if (otaPassword[0]) {
setupOTA();
}
Serial.println("Initialization complete\n");
}
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// Основной цикл выполнения
void loop() {
// проверяем соединение Wi-Fi
if (WiFi.status() != WL_CONNECTED) {
setupWifi();
}
// проверяем соединение MQTT
if (!mqttClient.connected()) {
mqttConnect();
}
// Клиентский цикл MQTT
if (mqttClient.connected()) {
mqttClient.loop();
}
// мерцание светодиода
if (mqttClient.connected() && ((millis() - twinkleTimer) >= twinkleInterval)) {
digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
twinkleTimer = millis();
}
// Сообщаем о силе сигнала и времени безотказной работы
if (mqttClient.connected() && ((millis() - reportTimer) >= reportInterval)) {
String signalStrength = String(WiFi.RSSI());
String uptimeTimer = String(millis());
mqttClient.publish(mqttDiscoSignalStateTopic.c_str(), signalStrength.c_str());
mqttClient.publish(mqttDiscoUptimeStateTopic.c_str(), uptimeTimer.c_str());
reportTimer = millis();
}
// OTA-цикл
if (otaPassword[0]) {
ArduinoOTA.handle();
}
}
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// Функции
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// Обработка входящих команд от MQTT
void mqtt_callback(char* topic, byte* payload, unsigned int payloadLength) {
}
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// Подключаемся к Wi-Fi
void setupWifi() {
Serial.print("Connecting to WiFi network: " + String(wifiSSID));
WiFi.hostname(mqttNode.c_str());
WiFi.mode(WIFI_STA);
WiFi.begin(wifiSSID, wifiPassword);
while (WiFi.status() != WL_CONNECTED) {
// Подождите 500 мс перед повторной попыткой
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected successfully and assigned IP: " + WiFi.localIP().toString());
}
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// MQTT-соединение и подписки
void mqttConnect() {
digitalWrite(LED_BUILTIN, HIGH);
Serial.println("Attempting MQTT connection to broker: " + String(mqttServer));
// Попытка подключения к брокеру, установка последней воли и завещания
if (mqttClient.connect(mqttNode.c_str(), mqttUser, mqttPassword, mqttDiscoBinaryStateTopic.c_str(), 1, 1, "OFF")) {
// при подключении записываем уровень сигнала и сбрасываем таймер отчетов
String signalStrength = String(WiFi.RSSI());
reportTimer = millis();
String uptimeTimer = String(millis());
// публикуем темы обнаружения MQTT и состояние устройства
Serial.println("MQTT discovery connectivity config: [" + mqttDiscoBinaryConfigTopic + "] : [" + mqttDiscoBinaryConfigPayload + "]");
Serial.println("MQTT discovery connectivity state: [" + mqttDiscoBinaryStateTopic + "] : [ON]");
Serial.println("MQTT discovery signal config: [" + mqttDiscoSignalConfigTopic + "] : [" + mqttDiscoSignalConfigPayload + "]");
Serial.println("MQTT discovery signal state: [" + mqttDiscoSignalStateTopic + "] : " + WiFi.RSSI());
Serial.println("MQTT discovery uptime config: [" + mqttDiscoUptimeConfigTopic + "] : [" + mqttDiscoUptimeConfigPayload + "]");
Serial.println("MQTT discovery uptime state: [" + mqttDiscoUptimeStateTopic + "] : " + uptimeTimer);
mqttClient.publish(mqttDiscoUptimeConfigTopic.c_str(), mqttDiscoUptimeConfigPayload.c_str(), true);
mqttClient.publish(mqttDiscoUptimeStateTopic.c_str(), uptimeTimer.c_str());
mqttClient.publish(mqttDiscoBinaryConfigTopic.c_str(), mqttDiscoBinaryConfigPayload.c_str(), true);
mqttClient.publish(mqttDiscoBinaryStateTopic.c_str(), "ON");
mqttClient.publish(mqttDiscoSignalConfigTopic.c_str(), mqttDiscoSignalConfigPayload.c_str(), true);
mqttClient.publish(mqttDiscoSignalStateTopic.c_str(), signalStrength.c_str());
Serial.println("MQTT connected");
digitalWrite(LED_BUILTIN, LOW);
}
else {
Serial.println("MQTT connection failed, rc=" + String(mqttClient.state()));
}
}
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
// (в основном) шаблонная настройка OTA из примеров библиотеки
void setupOTA() {
// Запускаем ОТА
// ArduinoOTA.setPort(8266); // Порт по умолчанию 8266
ArduinoOTA.setHostname(mqttNode.c_str());
ArduinoOTA.setPassword(otaPassword);
ArduinoOTA.onStart([]() {
Serial.println("ESP OTA: update start");
});
ArduinoOTA.onEnd([]() {
Serial.println("ESP OTA: update complete");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
//Serial.printf("Прогресс: %u%%\r", (прогресс / (всего / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.println("ESP OTA: ERROR code " + String(error));
if (error == OTA_AUTH_ERROR) Serial.println("ESP OTA: ERROR - Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("ESP OTA: ERROR - Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("ESP OTA: ERROR - Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("ESP OTA: ERROR - Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("ESP OTA: ERROR - End Failed");
});
ArduinoOTA.begin();
Serial.println("ESP OTA: Over the Air firmware update ready");
}
@WhiskerBiscuit, 👍1
2 ответа
Следуйте инструкциям здесь https://arduino-esp8266.readthedocs.io /en/latest/ota_updates/readme.html#application-example
Сначала загрузите указанный пример OTA. Не тратьте время на реализацию его в своем коде, пока предоставленный пример не заработает.
Если вы используете Windows, вам будет полезно иметь приложение под названием Bonjour Browser. Метод OTA использует mDNS. Я использую браузер Bonjour, чтобы подтвердить, что ESP виден. Затем я захожу в порты в IDE и там есть запись о только что добавленном ОТА-устройстве.
Выберите запись вместо com-портов. Затем скомпилируйте и загрузите.
Если вы получили сообщение об ошибке, выключите и включите питание на плате ESP. Вам нужно будет сделать это только один раз после последовательной загрузки.
Я использую этот метод, но иногда устройство не отображается под списком com. Мне пришлось закрыть и перезапустить IDE, чтобы обновить список устройств. (Я думаю, что это проблема Windows). По этой причине я предпочитаю метод веб-обновления. https://arduino-esp8266.readthedocs.io/en/latest/ota_updates/ readme.html#веб-браузер
Это делается из командной строки ноутбука с Linux.
Для загрузки на платы Arduino я использовал (через обычное соединение через USB-порт) методы командной строки, как описано по адресу: https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc Что касается метода загрузки OTA в ESP, я случайно обнаружил следующий метод.
В качестве аргумента для «--port» я просто использовал IP-адрес платы ESP, подключенной к Wi-Fi.
Предположим, я хочу загрузить скетч «myexample1.ino» на свою плату ESP8266 «ESP-01 (1MB)» с прошивкой OTA. Я использую Arduino 1.8.8 и версию сообщества ESP8266 2.4.2. Как уже говорилось, в ESP-01 через обычный USB-порт загружен пример скетча «BasicOTA.ino». Теперь ESP-01 не подключен через USB. Он подключен к моему Wi-Fi-маршрутизатору по IP-адресу (скажем, 192.168.22.221). Следующая команда успешно загрузила код:
~/Arduino/myexample1 $ arduino --upload myexample1.ino --port 192.168.22.221
Просто захотелось поделиться приятным опытом, которого нет нигде в Интернете.
- Как определить размер Flash?
- WebSocketsServer.h: No such file or directory
- В ESP-12E NodeMCU, какой выход PIN A0?
- Преобразование byte* в int в Arduino
- Каково использование зарезервированных контактов и контактов SDD2, SDD3 NodeMCU?
- Было найдено несколько библиотек для «WiFiClient.h» с помощью nodemcu.
- NodeMCU (Arduino IDE) «DynamicJsonBuffer» не был объявлен в этой области
- NodeMCU поддерживает внедрение ключей?
хороший ответ, Руди. В Sloeber (плагин Arduino Eclipse) я могу ввести IP-адрес и не должен ретранслировать mDNS., @Juraj
из доступных ОТА методов этот имхо самый простой., @dandavis