mirror of https://github.com/esphome/esphome.git
Merge 3ae611844a
into c7c0d97a5e
This commit is contained in:
commit
8a0ff5d591
|
@ -3,6 +3,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/network/ip_address.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace mdns {
|
namespace mdns {
|
||||||
|
@ -35,6 +36,8 @@ class MDNSComponent : public Component {
|
||||||
|
|
||||||
void add_extra_service(MDNSService service) { services_extra_.push_back(std::move(service)); }
|
void add_extra_service(MDNSService service) { services_extra_.push_back(std::move(service)); }
|
||||||
|
|
||||||
|
std::vector<network::IPAddress> resolve(const std::string &servicename);
|
||||||
|
|
||||||
void on_shutdown() override;
|
void on_shutdown() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -44,5 +47,7 @@ class MDNSComponent : public Component {
|
||||||
void compile_records_();
|
void compile_records_();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern MDNSComponent *global_mdns; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
} // namespace mdns
|
} // namespace mdns
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace mdns {
|
||||||
static const char *const TAG = "mdns";
|
static const char *const TAG = "mdns";
|
||||||
|
|
||||||
void MDNSComponent::setup() {
|
void MDNSComponent::setup() {
|
||||||
|
global_mdns = this;
|
||||||
this->compile_records_();
|
this->compile_records_();
|
||||||
|
|
||||||
esp_err_t err = mdns_init();
|
esp_err_t err = mdns_init();
|
||||||
|
@ -48,11 +49,43 @@ void MDNSComponent::setup() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<network::IPAddress> MDNSComponent::resolve(const std::string &servicename) {
|
||||||
|
std::vector<network::IPAddress> resolved;
|
||||||
|
mdns_result_t *results = nullptr;
|
||||||
|
mdns_ip_addr_t *a = nullptr;
|
||||||
|
esp_err_t err = mdns_query_ptr(("_" + servicename).c_str(), "_tcp", 3000, 20, &results);
|
||||||
|
if (err) {
|
||||||
|
ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (!results) {
|
||||||
|
ESP_LOGW(TAG, "No results found!");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
while (results) {
|
||||||
|
a = results->addr;
|
||||||
|
while (a) {
|
||||||
|
network::IPAddress ip_addr = network::IPAddress(&a->addr);
|
||||||
|
if (std::count(resolved.begin(), resolved.end(), ip_addr) == 0) {
|
||||||
|
resolved.push_back(ip_addr);
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "Found mDNS %s", ip_addr.str().c_str());
|
||||||
|
a = a->next;
|
||||||
|
}
|
||||||
|
results = results->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
mdns_query_results_free(results);
|
||||||
|
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
void MDNSComponent::on_shutdown() {
|
void MDNSComponent::on_shutdown() {
|
||||||
mdns_free();
|
mdns_free();
|
||||||
delay(40); // Allow the mdns packets announcing service removal to be sent
|
delay(40); // Allow the mdns packets announcing service removal to be sent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MDNSComponent *global_mdns = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
} // namespace mdns
|
} // namespace mdns
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace mdns {
|
namespace mdns {
|
||||||
|
|
||||||
|
static const char *const TAG = "mdns";
|
||||||
|
|
||||||
void MDNSComponent::setup() {
|
void MDNSComponent::setup() {
|
||||||
|
global_mdns = this;
|
||||||
this->compile_records_();
|
this->compile_records_();
|
||||||
|
|
||||||
MDNS.begin(this->hostname_.c_str());
|
MDNS.begin(this->hostname_.c_str());
|
||||||
|
@ -34,6 +37,18 @@ void MDNSComponent::setup() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::vector<network::IPAddress> MDNSComponent::resolve(const std::string &servicename) {
|
||||||
|
std::vector<network::IPAddress> resolved;
|
||||||
|
uint8_t n = MDNS.queryService(servicename.c_str(), "tcp");
|
||||||
|
for (uint8_t i = 0; i < n; i++) {
|
||||||
|
network::IPAddress ip_addr = network::IPAddress(MDNS.IP(i));
|
||||||
|
if (std::count(resolved.begin(), resolved.end(), ip_addr) == 0) {
|
||||||
|
resolved.push_back(ip_addr);
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "Found mDNS %s", ip_addr.str().c_str());
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
void MDNSComponent::loop() { MDNS.update(); }
|
void MDNSComponent::loop() { MDNS.update(); }
|
||||||
|
|
||||||
|
@ -42,6 +57,8 @@ void MDNSComponent::on_shutdown() {
|
||||||
delay(10);
|
delay(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MDNSComponent *global_mdns = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
} // namespace mdns
|
} // namespace mdns
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace esphome {
|
||||||
namespace mdns {
|
namespace mdns {
|
||||||
|
|
||||||
void MDNSComponent::setup() {
|
void MDNSComponent::setup() {
|
||||||
|
global_mdns = this;
|
||||||
this->compile_records_();
|
this->compile_records_();
|
||||||
|
|
||||||
MDNS.begin(this->hostname_.c_str());
|
MDNS.begin(this->hostname_.c_str());
|
||||||
|
@ -35,8 +36,12 @@ void MDNSComponent::setup() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Libre tiny doesn't have a "full" mDNS implementation
|
||||||
|
std::vector<network::IPAddress> MDNSComponent::resolve(const std::string &servicename) { return {}; }
|
||||||
|
|
||||||
void MDNSComponent::on_shutdown() {}
|
void MDNSComponent::on_shutdown() {}
|
||||||
|
|
||||||
|
MDNSComponent *global_mdns = nullptr;
|
||||||
} // namespace mdns
|
} // namespace mdns
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace mdns {
|
namespace mdns {
|
||||||
|
|
||||||
|
static const char *const TAG = "mdns";
|
||||||
|
|
||||||
void MDNSComponent::setup() {
|
void MDNSComponent::setup() {
|
||||||
|
global_mdns = this;
|
||||||
this->compile_records_();
|
this->compile_records_();
|
||||||
|
|
||||||
MDNS.begin(this->hostname_.c_str());
|
MDNS.begin(this->hostname_.c_str());
|
||||||
|
@ -35,6 +38,19 @@ void MDNSComponent::setup() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<network::IPAddress> MDNSComponent::resolve(const std::string &servicename) {
|
||||||
|
std::vector<network::IPAddress> resolved;
|
||||||
|
uint8_t n = MDNS.queryService(servicename.c_str(), "tcp");
|
||||||
|
for (uint8_t i = 0; i < n; i++) {
|
||||||
|
network::IPAddress ip_addr_ = network::IPAddress(MDNS.IP(i));
|
||||||
|
if (std::count(resolved.begin(), resolved.end(), ip_addr_) == 0) {
|
||||||
|
resolved.push_back(ip_addr_);
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "Found mDNS %s", ip_addr_.str().c_str());
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
void MDNSComponent::loop() { MDNS.update(); }
|
void MDNSComponent::loop() { MDNS.update(); }
|
||||||
|
|
||||||
void MDNSComponent::on_shutdown() {
|
void MDNSComponent::on_shutdown() {
|
||||||
|
@ -42,6 +58,7 @@ void MDNSComponent::on_shutdown() {
|
||||||
delay(40);
|
delay(40);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MDNSComponent *global_mdns = nullptr;
|
||||||
} // namespace mdns
|
} // namespace mdns
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,29 @@
|
||||||
from esphome.core import CORE
|
from __future__ import annotations
|
||||||
|
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
|
from esphome import helpers
|
||||||
from esphome.components.esp32 import add_idf_sdkconfig_option
|
from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||||
|
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_ENABLE_IPV6,
|
CONF_ENABLE_IPV6,
|
||||||
CONF_MIN_IPV6_ADDR_COUNT,
|
CONF_MIN_IPV6_ADDR_COUNT,
|
||||||
PLATFORM_ESP32,
|
PLATFORM_ESP32,
|
||||||
PLATFORM_ESP8266,
|
PLATFORM_ESP8266,
|
||||||
PLATFORM_RP2040,
|
PLATFORM_RP2040,
|
||||||
|
CONF_HOSTS,
|
||||||
|
CONF_HOSTSFILE,
|
||||||
|
CONF_IP_ADDRESS,
|
||||||
|
CONF_NAME,
|
||||||
)
|
)
|
||||||
|
from esphome.core import CORE
|
||||||
|
|
||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
AUTO_LOAD = ["mdns"]
|
AUTO_LOAD = ["mdns"]
|
||||||
|
|
||||||
network_ns = cg.esphome_ns.namespace("network")
|
network_ns = cg.esphome_ns.namespace("network")
|
||||||
IPAddress = network_ns.class_("IPAddress")
|
IPAddress = network_ns.class_("IPAddress")
|
||||||
|
Resolver = network_ns.class_("Resolver")
|
||||||
|
CONF_NETWORK_ID = "network_id"
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
|
@ -23,10 +31,34 @@ CONFIG_SCHEMA = cv.Schema(
|
||||||
cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040])
|
cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040])
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int,
|
cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int,
|
||||||
|
cv.GenerateID(CONF_NETWORK_ID): cv.declare_id(Resolver),
|
||||||
|
cv.Optional(CONF_HOSTSFILE): cv.file_,
|
||||||
|
cv.Optional(CONF_HOSTS): cv.ensure_list(
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_NAME): cv.string,
|
||||||
|
cv.Required(CONF_IP_ADDRESS): cv.string,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_hosts_file(hosts_contents: str) -> list[tuple[str, IPAddress]]:
|
||||||
|
"""Parse a hosts file"""
|
||||||
|
hosts: list[tuple[str, IPAddress]] = []
|
||||||
|
for line in hosts_contents.splitlines():
|
||||||
|
if line.startswith("#"):
|
||||||
|
continue
|
||||||
|
split_line = line.split()
|
||||||
|
if len(split_line) < 2:
|
||||||
|
continue
|
||||||
|
ip_address: IPAddress = IPAddress(split_line[0])
|
||||||
|
hosts.extend([(host, ip_address) for host in split_line[1:]])
|
||||||
|
return hosts
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
if CONF_ENABLE_IPV6 in config:
|
if CONF_ENABLE_IPV6 in config:
|
||||||
cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6])
|
cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6])
|
||||||
|
@ -46,3 +78,17 @@ async def to_code(config):
|
||||||
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6")
|
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6")
|
||||||
if CORE.is_esp8266:
|
if CORE.is_esp8266:
|
||||||
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY")
|
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY")
|
||||||
|
hosts = []
|
||||||
|
if CONF_HOSTS in config:
|
||||||
|
hosts = [
|
||||||
|
(host[CONF_NAME], IPAddress(host[CONF_IP_ADDRESS]))
|
||||||
|
for host in config[CONF_HOSTS]
|
||||||
|
]
|
||||||
|
if CONF_HOSTSFILE in config:
|
||||||
|
hosts_contents = helpers.read_file(
|
||||||
|
CORE.relative_config_path(config[CONF_HOSTSFILE])
|
||||||
|
)
|
||||||
|
hosts.extend(parse_hosts_file(hosts_contents))
|
||||||
|
|
||||||
|
map_ = cg.std_ns.class_("multimap").template(cg.std_string, IPAddress)
|
||||||
|
cg.new_Pvariable(config[CONF_NETWORK_ID], map_(hosts))
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
#include <vector>
|
||||||
|
#include "resolver.h"
|
||||||
|
#include "lwip/dns.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/defines.h"
|
||||||
|
#ifdef USE_MDNS
|
||||||
|
#include "esphome/components/mdns/mdns_component.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_IPV6
|
||||||
|
#define ESPHOME_DNS_ADDRTYPE LWIP_DNS_ADDRTYPE_IPV6_IPV4
|
||||||
|
#else
|
||||||
|
#define ESPHOME_DNS_ADDRTYPE LWIP_DNS_ADDRTYPE_IPV4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace network {
|
||||||
|
|
||||||
|
static const char *const TAG = "resolver";
|
||||||
|
|
||||||
|
Resolver::Resolver() { global_resolver = this; }
|
||||||
|
Resolver::Resolver(std::multimap<std::string, network::IPAddress> hosts) : hosts_(std::move(hosts)) {
|
||||||
|
global_resolver = this;
|
||||||
|
}
|
||||||
|
// TODO(HeMan): resolve needs to return multiple IP addresses
|
||||||
|
std::vector<network::IPAddress> Resolver::resolve(const std::string &hostname) {
|
||||||
|
if (this->hosts_.count(hostname) > 0) {
|
||||||
|
std::vector<network::IPAddress> resolved;
|
||||||
|
for (auto a = hosts_.find(hostname); a != hosts_.end(); a++) {
|
||||||
|
resolved.push_back(a->second);
|
||||||
|
ESP_LOGVV(TAG, "Found %s in hosts section", hostname.c_str());
|
||||||
|
}
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
#ifdef USE_MDNS
|
||||||
|
ESP_LOGV(TAG, "Looking for %s with mDNS", hostname.c_str());
|
||||||
|
std::vector<network::IPAddress> resolved_mdns = mdns::global_mdns->resolve(hostname);
|
||||||
|
if (!resolved_mdns.empty()) {
|
||||||
|
ESP_LOGVV(TAG, "Found %s in mDNS", hostname.c_str());
|
||||||
|
return resolved_mdns;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ip_addr_t addr;
|
||||||
|
ESP_LOGVV(TAG, "Resolving %s", hostname.c_str());
|
||||||
|
err_t err =
|
||||||
|
dns_gethostbyname_addrtype(hostname.c_str(), &addr, Resolver::dns_found_callback, this, ESPHOME_DNS_ADDRTYPE);
|
||||||
|
if (err == ERR_OK) {
|
||||||
|
return {network::IPAddress(&addr)};
|
||||||
|
}
|
||||||
|
this->connect_begin_ = millis();
|
||||||
|
while (!this->dns_resolved_ && !this->dns_resolve_error_ && (millis() - this->connect_begin_ < 2000)) {
|
||||||
|
switch (err) {
|
||||||
|
case ERR_OK: {
|
||||||
|
// Got IP immediately
|
||||||
|
ESP_LOGVV(TAG, "Found %s in DNS", hostname.c_str());
|
||||||
|
this->dns_resolved_ = true;
|
||||||
|
this->ip_ = network::IPAddress(&addr);
|
||||||
|
return {this->ip_};
|
||||||
|
}
|
||||||
|
case ERR_INPROGRESS: {
|
||||||
|
// wait for callback
|
||||||
|
ESP_LOGVV(TAG, "Resolving IP address...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
case ERR_ARG: {
|
||||||
|
// error
|
||||||
|
ESP_LOGW(TAG, "Error resolving IP address: %d", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delay_microseconds_safe(100);
|
||||||
|
}
|
||||||
|
if (this->dns_resolve_error_) {
|
||||||
|
ESP_LOGV(TAG, "Error resolving IP address");
|
||||||
|
}
|
||||||
|
if (!this->dns_resolved_) {
|
||||||
|
ESP_LOGVV(TAG, "Not resolved");
|
||||||
|
}
|
||||||
|
return {this->ip_};
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resolver::dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg) {
|
||||||
|
auto *a_this = (Resolver *) callback_arg;
|
||||||
|
if (ipaddr == nullptr) {
|
||||||
|
a_this->dns_resolve_error_ = true;
|
||||||
|
} else {
|
||||||
|
ESP_LOGVV(TAG, "Found %s in DNS", name);
|
||||||
|
a_this->ip_ = network::IPAddress(ipaddr);
|
||||||
|
a_this->dns_resolved_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Resolver *global_resolver = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
} // namespace network
|
||||||
|
} // namespace esphome
|
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include "ip_address.h"
|
||||||
|
namespace esphome {
|
||||||
|
namespace network {
|
||||||
|
|
||||||
|
class Resolver {
|
||||||
|
public:
|
||||||
|
Resolver();
|
||||||
|
Resolver(std::multimap<std::string, network::IPAddress> hosts);
|
||||||
|
~Resolver();
|
||||||
|
std::vector<network::IPAddress> resolve(const std::string &hostname);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void dns_found_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg);
|
||||||
|
std::multimap<std::string, network::IPAddress> hosts_;
|
||||||
|
network::IPAddress ip_;
|
||||||
|
bool dns_resolved_{false};
|
||||||
|
bool dns_resolve_error_{false};
|
||||||
|
uint32_t connect_begin_;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Resolver *global_resolver; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
} // namespace network
|
||||||
|
} // namespace esphome
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <map>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "esphome/core/defines.h"
|
#include "esphome/core/defines.h"
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ extern "C" {
|
||||||
#include "esphome/core/hal.h"
|
#include "esphome/core/hal.h"
|
||||||
#include "esphome/core/util.h"
|
#include "esphome/core/util.h"
|
||||||
#include "esphome/core/application.h"
|
#include "esphome/core/application.h"
|
||||||
|
#include "esphome/components/network/util.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace wifi {
|
namespace wifi {
|
||||||
|
|
|
@ -335,6 +335,8 @@ CONF_HIDDEN = "hidden"
|
||||||
CONF_HIDE_TIMESTAMP = "hide_timestamp"
|
CONF_HIDE_TIMESTAMP = "hide_timestamp"
|
||||||
CONF_HIGH = "high"
|
CONF_HIGH = "high"
|
||||||
CONF_HIGH_VOLTAGE_REFERENCE = "high_voltage_reference"
|
CONF_HIGH_VOLTAGE_REFERENCE = "high_voltage_reference"
|
||||||
|
CONF_HOSTS = "hosts"
|
||||||
|
CONF_HOSTSFILE = "hostsfile"
|
||||||
CONF_HOUR = "hour"
|
CONF_HOUR = "hour"
|
||||||
CONF_HOURS = "hours"
|
CONF_HOURS = "hours"
|
||||||
CONF_HUMIDITY = "humidity"
|
CONF_HUMIDITY = "humidity"
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# IPv4 test
|
||||||
|
192.168.1.1 other.example.com
|
||||||
|
# IPv6 test
|
||||||
|
2001:db8:4455:6677::35 other6.example.com
|
||||||
|
# Empty line test
|
||||||
|
|
||||||
|
# multi name test
|
||||||
|
192.168.1.10 multi1.example.com multi1
|
||||||
|
|
|
@ -80,6 +80,14 @@ wifi:
|
||||||
|
|
||||||
network:
|
network:
|
||||||
enable_ipv6: true
|
enable_ipv6: true
|
||||||
|
hosts:
|
||||||
|
- name: www.example.com
|
||||||
|
ip_address: 192.168.1.80
|
||||||
|
- name: www.mqtt.com
|
||||||
|
ip_address: 10.20.18.33
|
||||||
|
- name: ipv6.example.com
|
||||||
|
ip_address: 2001:db8:4455:6677::32
|
||||||
|
hostsfile: hosts
|
||||||
|
|
||||||
mdns:
|
mdns:
|
||||||
disabled: false
|
disabled: false
|
||||||
|
|
|
@ -36,6 +36,14 @@ ethernet:
|
||||||
|
|
||||||
network:
|
network:
|
||||||
enable_ipv6: true
|
enable_ipv6: true
|
||||||
|
hosts:
|
||||||
|
- name: www.example.com
|
||||||
|
ip_address: 192.168.1.80
|
||||||
|
- name: www.mqtt.com
|
||||||
|
ip_address: 10.20.18.33
|
||||||
|
- name: ipv6.example.com
|
||||||
|
ip_address: 2001:db8:4455:6677::32
|
||||||
|
hostsfile: hosts
|
||||||
|
|
||||||
mdns:
|
mdns:
|
||||||
disabled: true
|
disabled: true
|
||||||
|
|
|
@ -29,6 +29,14 @@ ethernet:
|
||||||
|
|
||||||
network:
|
network:
|
||||||
enable_ipv6: true
|
enable_ipv6: true
|
||||||
|
hosts:
|
||||||
|
- name: www.example.com
|
||||||
|
ip_address: 192.168.1.80
|
||||||
|
- name: www.mqtt.com
|
||||||
|
ip_address: 10.20.18.33
|
||||||
|
- name: ipv6.example.com
|
||||||
|
ip_address: 2001:db8:4455:6677::32
|
||||||
|
hostsfile: hosts
|
||||||
|
|
||||||
mqtt:
|
mqtt:
|
||||||
broker: test.mosquitto.org
|
broker: test.mosquitto.org
|
||||||
|
|
|
@ -24,6 +24,13 @@ wifi:
|
||||||
|
|
||||||
network:
|
network:
|
||||||
enable_ipv6: true
|
enable_ipv6: true
|
||||||
|
hosts:
|
||||||
|
- name: www.example.com
|
||||||
|
ip_address: 192.168.1.80
|
||||||
|
- name: www.mqtt.com
|
||||||
|
ip_address: 10.20.18.33
|
||||||
|
- name: ipv6.example.com
|
||||||
|
ip_address: 2001:db8:4455:6677::32
|
||||||
|
|
||||||
api:
|
api:
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,14 @@ wifi:
|
||||||
|
|
||||||
network:
|
network:
|
||||||
enable_ipv6: true
|
enable_ipv6: true
|
||||||
|
hosts:
|
||||||
|
- name: www.example.com
|
||||||
|
ip_address: 192.168.1.80
|
||||||
|
- name: www.mqtt.com
|
||||||
|
ip_address: 10.20.18.33
|
||||||
|
- name: ipv6.example.com
|
||||||
|
ip_address: 2001:db8:4455:6677::32
|
||||||
|
hostsfile: hosts
|
||||||
|
|
||||||
api:
|
api:
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,14 @@ wifi:
|
||||||
|
|
||||||
network:
|
network:
|
||||||
enable_ipv6: true
|
enable_ipv6: true
|
||||||
|
hosts:
|
||||||
|
- name: www.example.com
|
||||||
|
ip_address: 192.168.1.80
|
||||||
|
- name: www.mqtt.com
|
||||||
|
ip_address: 10.20.18.33
|
||||||
|
- name: ipv6.example.com
|
||||||
|
ip_address: 2001:db8:4455:6677::32
|
||||||
|
hostsfile: hosts
|
||||||
|
|
||||||
esp32:
|
esp32:
|
||||||
board: lolin_c3_mini
|
board: lolin_c3_mini
|
||||||
|
|
|
@ -9,6 +9,16 @@ rtl87xx:
|
||||||
esphome:
|
esphome:
|
||||||
name: rtl87xx-test
|
name: rtl87xx-test
|
||||||
|
|
||||||
|
network:
|
||||||
|
hosts:
|
||||||
|
- name: www.example.com
|
||||||
|
ip_address: 192.168.1.80
|
||||||
|
- name: www.mqtt.com
|
||||||
|
ip_address: 10.20.18.33
|
||||||
|
- name: ipv6.example.com
|
||||||
|
ip_address: 2001:db8:4455:6677::32
|
||||||
|
hostsfile: hosts
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
|
|
||||||
ota:
|
ota:
|
||||||
|
|
|
@ -9,6 +9,16 @@ bk72xx:
|
||||||
esphome:
|
esphome:
|
||||||
name: bk72xx-test
|
name: bk72xx-test
|
||||||
|
|
||||||
|
network:
|
||||||
|
hosts:
|
||||||
|
- name: www.example.com
|
||||||
|
ip_address: 192.168.1.80
|
||||||
|
- name: www.mqtt.com
|
||||||
|
ip_address: 10.20.18.33
|
||||||
|
- name: ipv6.example.com
|
||||||
|
ip_address: 2001:db8:4455:6677::32
|
||||||
|
hostsfile: hosts
|
||||||
|
|
||||||
logger:
|
logger:
|
||||||
|
|
||||||
ota:
|
ota:
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from esphome.components import network
|
||||||
|
from esphome.cpp_generator import MockObj
|
||||||
|
|
||||||
|
|
||||||
|
def _convert_mockobjs_to_string_literal(obj: Any) -> Any:
|
||||||
|
"""Convert mock objects to their base objects."""
|
||||||
|
if isinstance(obj, MockObj):
|
||||||
|
return str(obj.base.args.args[0].string)
|
||||||
|
if isinstance(obj, list):
|
||||||
|
return [_convert_mockobjs_to_string_literal(x) for x in obj]
|
||||||
|
if isinstance(obj, tuple):
|
||||||
|
return tuple(_convert_mockobjs_to_string_literal(x) for x in obj)
|
||||||
|
if isinstance(obj, dict):
|
||||||
|
return {k: _convert_mockobjs_to_string_literal(v) for k, v in obj.items()}
|
||||||
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("contents", "expected"),
|
||||||
|
(
|
||||||
|
("127.0.0.1 localhost", [("localhost", "127.0.0.1")]),
|
||||||
|
(":1 localhost", [("localhost", ":1")]),
|
||||||
|
("#192.168.1.1 commented", []),
|
||||||
|
(
|
||||||
|
"192.168.1.10 multi1.example.com multi1\n:1 localhost",
|
||||||
|
[
|
||||||
|
("multi1.example.com", "192.168.1.10"),
|
||||||
|
("multi1", "192.168.1.10"),
|
||||||
|
("localhost", ":1"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_parse_hosts_file(contents: str, expected: list[tuple[str, str]]):
|
||||||
|
"""Test parsing a hosts file."""
|
||||||
|
actual = network.parse_hosts_file(contents)
|
||||||
|
unmocked_actual = _convert_mockobjs_to_string_literal(actual)
|
||||||
|
assert _convert_mockobjs_to_string_literal(unmocked_actual) == expected
|
Loading…
Reference in New Issue