Compare commits

..
12 changed files with 93 additions and 90 deletions

No files matched your search

@@ -17,20 +17,16 @@ void IPAddressEthernetInfo::on_ip_state(const network::IPAddresses &ips, const n
char buf[network::IP_ADDRESS_BUFFER_SIZE];
ips[0].str_to(buf);
this->publish_state(buf);
#ifdef ETHERNET_INFO_IP_SENSOR_COUNT
uint8_t sensor = 0;
for (const auto &ip : ips) {
if (!ip.is_set())
continue;
if (sensor == ETHERNET_INFO_IP_SENSOR_COUNT)
break;
if (this->ip_sensors_[sensor] != nullptr) {
ip.str_to(buf);
this->ip_sensors_[sensor]->publish_state(buf);
if (ip.is_set()) {
if (this->ip_sensors_[sensor] != nullptr) {
ip.str_to(buf);
this->ip_sensors_[sensor]->publish_state(buf);
}
sensor++;
}
sensor++;
}
#endif
}
void DNSAddressEthernetInfo::setup() { ethernet::global_eth_component->add_ip_state_listener(this); }
@@ -18,19 +18,14 @@ class IPAddressEthernetInfo final : public Component,
void setup() override;
void dump_config() override;
#ifdef ETHERNET_INFO_IP_SENSOR_COUNT
void add_ip_sensors(uint8_t index, text_sensor::TextSensor *s) { this->ip_sensors_[index] = s; }
#endif
// EthernetIPStateListener interface
void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
const network::IPAddress &dns2) override;
protected:
#ifdef ETHERNET_INFO_IP_SENSOR_COUNT
// Sized to the highest configured address_N
std::array<text_sensor::TextSensor *, ETHERNET_INFO_IP_SENSOR_COUNT> ip_sensors_{};
#endif
std::array<text_sensor::TextSensor *, 5> ip_sensors_{};
};
class DNSAddressEthernetInfo final : public Component,
@@ -12,7 +12,6 @@ from esphome.types import ConfigType
DEPENDENCIES = ["ethernet"]
ethernet_info_ns = cg.esphome_ns.namespace("ethernet_info")
_request_ip_sensor_slot = cg.slot_counter("ETHERNET_INFO_IP_SENSOR_COUNT")
IPAddressEthernetInfo = ethernet_info_ns.class_(
"IPAddressEthernetInfo", text_sensor.TextSensor, cg.Component
@@ -58,13 +57,10 @@ async def to_code(config: ConfigType) -> None:
if conf := config.get(CONF_IP_ADDRESS):
ip_info = await text_sensor.new_text_sensor(config[CONF_IP_ADDRESS])
await cg.register_component(ip_info, config[CONF_IP_ADDRESS])
indexes = [x for x in range(5) if f"address_{x}" in conf]
# One shared array size: the largest highest index of any entry, so add_ip_sensors(x) stays in range
for _ in range(max(indexes, default=-1) + 1):
_request_ip_sensor_slot(str(ip_info))
for x in indexes:
sens = await text_sensor.new_text_sensor(conf[f"address_{x}"])
cg.add(ip_info.add_ip_sensors(x, sens))
for x in range(5):
if sensor_conf := conf.get(f"address_{x}"):
sens = await text_sensor.new_text_sensor(sensor_conf)
cg.add(ip_info.add_ip_sensors(x, sens))
if conf := config.get(CONF_DNS_ADDRESS):
dns_info = await text_sensor.new_text_sensor(conf)
await cg.register_component(dns_info, conf)
@@ -15,25 +15,34 @@ ESPHOME_LOG_TAG(TAG, "http_request.ota");
void OtaHttpRequestComponent::dump_config() { ESP_LOGCONFIG(TAG, "Over-The-Air updates via HTTP request"); };
OtaHttpRequestComponent::Request &OtaHttpRequestComponent::get_request_() {
if (this->request_ == nullptr)
this->request_ = make_unique<Request>();
return *this->request_;
}
void OtaHttpRequestComponent::set_md5_url(const std::string &url) {
if (!this->validate_url_(url)) {
this->md5_url_.clear(); // URL was not valid; prevent flashing until it is
if (this->request_ != nullptr)
this->request_->md5_url.clear(); // URL was not valid; prevent flashing until it is
return;
}
this->md5_url_ = url;
this->md5_expected_.clear(); // to be retrieved later
Request &request = this->get_request_();
request.md5_url = url;
request.md5_expected.clear(); // to be retrieved later
}
void OtaHttpRequestComponent::set_url(const std::string &url) {
if (!this->validate_url_(url)) {
this->url_.clear(); // URL was not valid; prevent flashing until it is
if (this->request_ != nullptr)
this->request_->url.clear(); // URL was not valid; prevent flashing until it is
return;
}
this->url_ = url;
this->get_request_().url = url;
}
void OtaHttpRequestComponent::flash() {
if (this->url_.empty()) {
if (this->request_ == nullptr || this->request_->url.empty()) {
ESP_LOGE(TAG, "URL not set; cannot start update");
return;
}
@@ -58,8 +67,8 @@ void OtaHttpRequestComponent::flash() {
#ifdef USE_OTA_STATE_LISTENER
this->notify_state_(ota::OTA_ERROR, 0.0f, ota_status);
#endif
this->md5_computed_.clear(); // will be reset at next attempt
this->md5_expected_.clear(); // will be reset at next attempt
this->request_->md5_computed.clear(); // will be reset at next attempt
this->request_->md5_expected.clear(); // will be reset at next attempt
break;
}
}
@@ -81,18 +90,18 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
md5::MD5Digest md5_receive;
char md5_receive_str[33];
if (this->md5_expected_.empty() && !this->http_get_md5_()) {
if (this->request_->md5_expected.empty() && !this->http_get_md5_()) {
return OTA_MD5_INVALID;
}
ESP_LOGD(TAG, "MD5 expected: %s", this->md5_expected_.c_str());
ESP_LOGD(TAG, "MD5 expected: %s", this->request_->md5_expected.c_str());
auto url_with_auth = this->get_url_with_auth_(this->url_);
auto url_with_auth = this->get_url_with_auth_(this->request_->url);
if (url_with_auth.empty()) {
return OTA_BAD_URL;
}
ESP_LOGVV(TAG, "url_with_auth: %s", url_with_auth.c_str());
ESP_LOGI(TAG, "Connecting to: %s", this->url_.c_str());
ESP_LOGI(TAG, "Connecting to: %s", this->request_->url.c_str());
auto container = this->parent_->get(url_with_auth);
@@ -179,9 +188,9 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
// verify MD5 is as expected and act accordingly
md5_receive.calculate();
md5_receive.get_hex(md5_receive_str);
this->md5_computed_ = md5_receive_str;
if (strncmp(this->md5_computed_.c_str(), this->md5_expected_.c_str(), MD5_SIZE) != 0) {
ESP_LOGE(TAG, "MD5 computed: %s - Aborting due to MD5 mismatch", this->md5_computed_.c_str());
this->request_->md5_computed = md5_receive_str;
if (strncmp(this->request_->md5_computed.c_str(), this->request_->md5_expected.c_str(), MD5_SIZE) != 0) {
ESP_LOGE(TAG, "MD5 computed: %s - Aborting due to MD5 mismatch", this->request_->md5_computed.c_str());
this->cleanup_(std::move(backend), container, /*abort_backend=*/true);
return ota::OTA_RESPONSE_ERROR_MD5_MISMATCH;
} else {
@@ -223,11 +232,15 @@ static std::string url_encode(const std::string &str) {
return result;
}
void OtaHttpRequestComponent::set_password(const std::string &password) { this->password_ = url_encode(password); }
void OtaHttpRequestComponent::set_username(const std::string &username) { this->username_ = url_encode(username); }
void OtaHttpRequestComponent::set_password(const std::string &password) {
this->get_request_().password = url_encode(password);
}
void OtaHttpRequestComponent::set_username(const std::string &username) {
this->get_request_().username = url_encode(username);
}
std::string OtaHttpRequestComponent::get_url_with_auth_(const std::string &url) {
if (this->username_.empty() || this->password_.empty()) {
if (this->request_->username.empty() || this->request_->password.empty()) {
return url;
}
@@ -240,23 +253,23 @@ std::string OtaHttpRequestComponent::get_url_with_auth_(const std::string &url)
ESP_LOGD(TAG, "Using basic HTTP authentication");
start_char += 3; // skip '://' characters
auto url_with_auth =
url.substr(0, start_char) + this->username_ + ":" + this->password_ + "@" + url.substr(start_char);
auto url_with_auth = url.substr(0, start_char) + this->request_->username + ":" + this->request_->password + "@" +
url.substr(start_char);
return url_with_auth;
}
bool OtaHttpRequestComponent::http_get_md5_() {
if (this->md5_url_.empty()) {
if (this->request_->md5_url.empty()) {
return false;
}
auto url_with_auth = this->get_url_with_auth_(this->md5_url_);
auto url_with_auth = this->get_url_with_auth_(this->request_->md5_url);
if (url_with_auth.empty()) {
return false;
}
ESP_LOGVV(TAG, "url_with_auth: %s", url_with_auth.c_str());
ESP_LOGI(TAG, "Connecting to: %s", this->md5_url_.c_str());
ESP_LOGI(TAG, "Connecting to: %s", this->request_->md5_url.c_str());
auto container = this->parent_->get(url_with_auth);
if (container == nullptr) {
ESP_LOGE(TAG, "Failed to connect to MD5 URL");
@@ -273,8 +286,8 @@ bool OtaHttpRequestComponent::http_get_md5_() {
return false;
}
this->md5_expected_.resize(MD5_SIZE);
auto result = http_read_fully(container.get(), (uint8_t *) this->md5_expected_.data(), MD5_SIZE, MD5_SIZE,
this->request_->md5_expected.resize(MD5_SIZE);
auto result = http_read_fully(container.get(), (uint8_t *) this->request_->md5_expected.data(), MD5_SIZE, MD5_SIZE,
this->parent_->get_timeout());
container->end();
@@ -27,29 +27,36 @@ class OtaHttpRequestComponent final : public ota::OTAComponent, public Parented<
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void set_md5_url(const std::string &md5_url);
void set_md5(const std::string &md5) { this->md5_expected_ = md5; }
void set_md5(const std::string &md5) { this->get_request_().md5_expected = md5; }
void set_password(const std::string &password);
void set_url(const std::string &url);
void set_username(const std::string &username);
std::string md5_computed() { return this->md5_computed_; }
std::string md5_expected() { return this->md5_expected_; }
std::string md5_computed() { return this->request_ != nullptr ? this->request_->md5_computed : std::string(); }
std::string md5_expected() { return this->request_ != nullptr ? this->request_->md5_expected : std::string(); }
void flash();
protected:
/// Allocated by the first setter, which only runs before a flash, and never freed, so a flash never loses it.
struct Request {
std::string md5_computed;
std::string md5_expected;
std::string md5_url;
std::string password;
std::string username;
std::string url;
};
Request &get_request_();
void cleanup_(ota::OTABackendPtr backend, const std::shared_ptr<HttpContainer> &container, bool abort_backend);
// Only reached from flash(), which returns early while request_ is null
uint8_t do_ota_();
std::string get_url_with_auth_(const std::string &url);
bool http_get_md5_();
bool validate_url_(const std::string &url);
std::string md5_computed_{};
std::string md5_expected_{};
std::string md5_url_{};
std::string password_{};
std::string username_{};
std::string url_{};
std::unique_ptr<Request> request_;
int status_ = -1;
static const uint16_t HTTP_RECV_BUFFER = 256; // the firmware GET chunk size
};
+4 -8
View File
@@ -16,7 +16,6 @@ from esphome.types import ConfigType
DEPENDENCIES = ["wifi"]
wifi_info_ns = cg.esphome_ns.namespace("wifi_info")
_request_ip_sensor_slot = cg.slot_counter("WIFI_INFO_IP_SENSOR_COUNT")
IPAddressWiFiInfo = wifi_info_ns.class_(
"IPAddressWiFiInfo", text_sensor.TextSensor, cg.Component
)
@@ -111,10 +110,7 @@ async def to_code(config: ConfigType) -> None:
if conf := config.get(CONF_IP_ADDRESS):
wifi_info = await text_sensor.new_text_sensor(config[CONF_IP_ADDRESS])
await cg.register_component(wifi_info, config[CONF_IP_ADDRESS])
indexes = [x for x in range(5) if f"address_{x}" in conf]
# One shared array size: the largest highest index of any entry, so add_ip_sensors(x) stays in range
for _ in range(max(indexes, default=-1) + 1):
_request_ip_sensor_slot(str(wifi_info))
for x in indexes:
sens = await text_sensor.new_text_sensor(conf[f"address_{x}"])
cg.add(wifi_info.add_ip_sensors(x, sens))
for x in range(5):
if sensor_conf := conf.get(f"address_{x}"):
sens = await text_sensor.new_text_sensor(sensor_conf)
cg.add(wifi_info.add_ip_sensors(x, sens))
@@ -26,20 +26,16 @@ void IPAddressWiFiInfo::on_ip_state(const network::IPAddresses &ips, const netwo
char buf[network::IP_ADDRESS_BUFFER_SIZE];
ips[0].str_to(buf);
this->publish_state(buf);
#ifdef WIFI_INFO_IP_SENSOR_COUNT
uint8_t sensor = 0;
for (const auto &ip : ips) {
if (!ip.is_set())
continue;
if (sensor == WIFI_INFO_IP_SENSOR_COUNT)
break;
if (this->ip_sensors_[sensor] != nullptr) {
ip.str_to(buf);
this->ip_sensors_[sensor]->publish_state(buf);
if (ip.is_set()) {
if (this->ip_sensors_[sensor] != nullptr) {
ip.str_to(buf);
this->ip_sensors_[sensor]->publish_state(buf);
}
sensor++;
}
sensor++;
}
#endif
}
/*********************
@@ -16,19 +16,14 @@ class IPAddressWiFiInfo final : public Component, public text_sensor::TextSensor
public:
void setup() override;
void dump_config() override;
#ifdef WIFI_INFO_IP_SENSOR_COUNT
void add_ip_sensors(uint8_t index, text_sensor::TextSensor *s) { this->ip_sensors_[index] = s; }
#endif
// WiFiIPStateListener interface
void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
const network::IPAddress &dns2) override;
protected:
#ifdef WIFI_INFO_IP_SENSOR_COUNT
// Sized to the highest configured address_N
std::array<text_sensor::TextSensor *, WIFI_INFO_IP_SENSOR_COUNT> ip_sensors_{};
#endif
std::array<text_sensor::TextSensor *, 5> ip_sensors_{};
};
class DNSAddressWifiInfo final : public Component, public text_sensor::TextSensor, public wifi::WiFiIPStateListener {
-2
View File
@@ -166,7 +166,6 @@
#define LV_USE_LOG 1
#define USE_MDNS
#define USE_MDNS_STORE_SERVICES
#define ETHERNET_INFO_IP_SENSOR_COUNT 5
#define GPS_LISTENER_COUNT 1
#define HDMI_CEC_MESSAGE_CALLBACK_COUNT 2
#define I2C_PORT_FREQUENCY_COUNT 1
@@ -194,7 +193,6 @@
#define PYLONTECH_SENSOR_CELL_COUNT 2
#define REMOTE_BASE_DUMPER_COUNT 1
#define REMOTE_BASE_LISTENER_COUNT 1
#define WIFI_INFO_IP_SENSOR_COUNT 5
#define USE_REMOTE_PROTOCOL_ABBWELCOME
#define USE_REMOTE_PROTOCOL_AEHA
#define USE_REMOTE_PROTOCOL_AOK
@@ -17,10 +17,6 @@ text_sensor:
- platform: ethernet_info
ip_address:
name: IP Address
address_0:
name: IP Address 0
address_1:
name: IP Address 1
dns_address:
name: DNS Address
mac_address:
+17
View File
@@ -72,6 +72,23 @@ button:
id(ota_update).set_source_url(std::string("http://my.ha.net:8123/local/esphome/manifest.json"));
ESP_LOGI("test", "Manifest is now %s", id(ota_update).get_source_url());
- component.update: ota_update
# The OTA component's public setters and getters as lambdas use them; every shape must compile.
- platform: template
name: Flash from lambda
on_press:
then:
- lambda: |-
std::string url = "http://my.ha.net:8123/local/esphome/";
url += "firmware.bin";
id(http_request_ota).set_md5_url("http://my.ha.net:8123/local/esphome/firmware.md5");
id(http_request_ota).set_md5(std::string("0123456789abcdef0123456789abcdef"));
id(http_request_ota).set_username("user");
id(http_request_ota).set_password(std::string("pass"));
id(http_request_ota).set_url(url);
id(http_request_ota).set_url(url.c_str());
ESP_LOGI("test", "MD5 %s / %s", id(http_request_ota).md5_expected().c_str(),
id(http_request_ota).md5_computed().c_str());
id(http_request_ota).flash();
update:
- platform: http_request
-2
View File
@@ -8,8 +8,6 @@ text_sensor:
name: Scan Results
ip_address:
name: IP Address
address_1:
name: IP Address 1
ssid:
name: SSID
bssid: