ESP8266 - HTTPClient не работает при использовании локального адреса mDNS
У меня есть локальный веб-сервер с mDNS - http://android.local:8182/ Я хочу использовать его с ESP8266, используя класс HTTPClient из библиотеки ESP8266HTTPClient. Код выглядит так:
HTTPClient http;
http.begin("http://android.local:8182");
http.addHeader("values.json", "text/json");
int code = http.POST(jsonStr);
Log(DATA, "HTTP code: " + String(code));
Log(DATA, "Response: " + http.getString());
Но он всегда возвращает -1 код. Когда я буквально копирую и вставляю URL в мой веб-браузер, это работает. Я попытался заменить "android.local" на IP-адрес моего сервера, и это сработало, но не с адресом mDNS. Может кто-нибудь сказать мне, как заставить это работать должным образом?
1 ответ
Windows, macOS и Linux работают на гораздо более мощных компьютерах, чем ESP8266. Хотя обычные DNS и mDNS являются практически одним и тем же протоколом, они используются по-разному и реализуются отдельно. Фактически, для Windows и Linux характерно не поддерживать mDNS без установки дополнительного программного обеспечения ("Bonjour" под Windows и "avahi" под Linux).
Есть два способа добиться этого на ESP8266 с помощью Arduino SDK.
В любом случае вам нужно решить android.local
на его IP-адрес, а затем переписать URL-адрес, чтобы включить IP-адрес вместо имени хоста.
К сожалению, библиотека mSPS ESP8266 не поддерживает прямое разрешение имени хоста по IP-адресу, так что это будет немного искажено.
Первый способ: если устройство, которое является рекламой android.local
предлагает служебную запись mDNS для "http", "tcp" и предоставляет IP-адрес и номер порта (8182) в объявлении, затем вы можете найти служебную запись с помощью библиотеки ESP8266 mDNS.
Ваш код будет выглядеть примерно так:
// your other necessary #include's first
#include <ESP8266mDNS.h>
#define HOSTNAME "the name of this ESP8266"
#define TARGET_HOSTNAME "android"
bool resolve_mdns_service(char* service_name, char* protocol, char* desired_host, IPAddress* ip_addr, uint16_t *port_number) {
Serial.println("Sending mDNS query");
int n = MDNS.queryService(service_name, protocol);
Serial.printf("mDNS query got %d results\n", n);
if(n == 0) {
Serial.println("no services found");
} else {
for (int i = 0; i < n; ++i) {
#ifdef DEBUG
Serial.print(i + 1);
Serial.print(": ");
Serial.print(MDNS.hostname(i));
Serial.print(" (");
Serial.print(MDNS.IP(i));
Serial.print(":");
Serial.print(MDNS.port(i));
Serial.println(")");
#endif
if(strcmp(MDNS.hostname(i).c_str(), desired_host) == 0) {
*ip_addr = MDNS.IP(i);
*port_number = MDNS.port(i);
return true;
}
}
}
return false;
}
void setup() {
// get WiFi setup first
if(!MDNS.begin(HOSTNAME))
Serial.println("Error setting up MDNS responder!");
else
Serial.println("mDNS responder started");
IPAddress server_ip;
uint16_t port_number;
if(resolve_mdns_service("http", "tcp", TARGET_HOSTNAME, &server_ip, &port_number)) {
Serial.printf("got an answer for %s.local!\n", TARGET_HOSTNAME);
Serial.println(server_ip);
Serial.println(port_number);
} else {
Serial.printf("Sorry, %s.local not found\n", TARGET_HOSTNAME);
}
}
Это будет работать только в том случае, если ваше устройство объявляет служебную запись mDNS "http", "tcp".
Если этого не произойдет, лучше всего использовать стороннюю библиотеку.
В этом случае вам нужно будет следовать инструкциям по установке этой библиотеки в вашем проекте:
https://github.com/madpilot/mDNSResolver
Ваш код будет выглядеть примерно так:
// your other necessary #include's first
#include <mDNSResolver.h>
#define TARGET_HOSTNAME "android"
WiFiUDP udp;
mDNSResolver::Resolver resolver(udp);
void setup() {
// get WiFi setup first
Serial.printf("Attempting to resolve %s\n", TARGET_HOSTNAME);
IPAddress answer = resolver.search(TARGET_HOSTNAME);
if(answer == IPADDR_NONE) {
Serial.println("no answer found");
} else {
Serial.println("Gotta result!");
Serial.println(answer);
}
}
Первый метод требует больше кода, но не требует внешней сторонней библиотеки и не будет работать во всех случаях.
Когда у вас есть IP-адрес, вы можете использовать его, чтобы собрать URL, который вы передаете http.begin()
и продолжайте оттуда.
mDNS - это "ненадежный" протокол - он не гарантирует, что вы получите ответ или все ответы. Так что, если вы определите DEBUG
в первом методе вы можете видеть несколько разные наборы результатов каждый раз. И если ваш код не может разрешить имя хоста, вы можете повторить попытку 2-3 раза, прежде чем отказаться.