mirror of
https://github.com/esphome/esphome.git
synced 2025-01-29 22:51:32 +01:00
Add multicast support to udp component (#8051)
This commit is contained in:
parent
a23ce416ea
commit
9957840dfc
@ -49,6 +49,7 @@ struct IPAddress {
|
||||
}
|
||||
IPAddress(const std::string &in_address) { inet_aton(in_address.c_str(), &ip_addr_); }
|
||||
IPAddress(const ip_addr_t *other_ip) { ip_addr_ = *other_ip; }
|
||||
std::string str() const { return str_lower_case(inet_ntoa(ip_addr_)); }
|
||||
#else
|
||||
IPAddress() { ip_addr_set_zero(&ip_addr_); }
|
||||
IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
|
||||
@ -119,6 +120,7 @@ struct IPAddress {
|
||||
bool is_set() { return !ip_addr_isany(&ip_addr_); } // NOLINT(readability-simplify-boolean-expr)
|
||||
bool is_ip4() { return IP_IS_V4(&ip_addr_); }
|
||||
bool is_ip6() { return IP_IS_V6(&ip_addr_); }
|
||||
bool is_multicast() { return ip_addr_ismulticast(&ip_addr_); }
|
||||
std::string str() const { return str_lower_case(ipaddr_ntoa(&ip_addr_)); }
|
||||
bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
|
||||
bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
|
||||
|
@ -27,6 +27,7 @@ UDPComponent = udp_ns.class_("UDPComponent", cg.PollingComponent)
|
||||
CONF_BROADCAST = "broadcast"
|
||||
CONF_BROADCAST_ID = "broadcast_id"
|
||||
CONF_ADDRESSES = "addresses"
|
||||
CONF_LISTEN_ADDRESS = "listen_address"
|
||||
CONF_PROVIDER = "provider"
|
||||
CONF_PROVIDERS = "providers"
|
||||
CONF_REMOTE_ID = "remote_id"
|
||||
@ -84,6 +85,9 @@ CONFIG_SCHEMA = cv.All(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(UDPComponent),
|
||||
cv.Optional(CONF_PORT, default=18511): cv.port,
|
||||
cv.Optional(
|
||||
CONF_LISTEN_ADDRESS, default="255.255.255.255"
|
||||
): cv.ipv4address_multi_broadcast,
|
||||
cv.Optional(CONF_ADDRESSES, default=["255.255.255.255"]): cv.ensure_list(
|
||||
cv.ipv4address,
|
||||
),
|
||||
@ -154,5 +158,7 @@ async def to_code(config):
|
||||
for provider in config.get(CONF_PROVIDERS, ()):
|
||||
name = provider[CONF_NAME]
|
||||
cg.add(var.add_provider(name))
|
||||
if (listen_address := str(config[CONF_LISTEN_ADDRESS])) != "255.255.255.255":
|
||||
cg.add(var.set_listen_address(listen_address))
|
||||
if encryption := provider.get(CONF_ENCRYPTION):
|
||||
cg.add(var.set_provider_encryption(name, hash_encryption_key(encryption)))
|
||||
|
@ -249,6 +249,21 @@ void UDPComponent::setup() {
|
||||
server.sin_addr.s_addr = ESPHOME_INADDR_ANY;
|
||||
server.sin_port = htons(this->port_);
|
||||
|
||||
if (this->listen_address_.has_value()) {
|
||||
struct ip_mreq imreq = {};
|
||||
imreq.imr_interface.s_addr = ESPHOME_INADDR_ANY;
|
||||
inet_aton(this->listen_address_.value().str().c_str(), &imreq.imr_multiaddr);
|
||||
server.sin_addr.s_addr = imreq.imr_multiaddr.s_addr;
|
||||
ESP_LOGV(TAG, "Join multicast %s", this->listen_address_.value().str().c_str());
|
||||
err = this->listen_socket_->setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, &imreq, sizeof(imreq));
|
||||
if (err < 0) {
|
||||
ESP_LOGE(TAG, "Failed to set IP_ADD_MEMBERSHIP. Error %d", errno);
|
||||
this->mark_failed();
|
||||
this->status_set_error("Failed to set IP_ADD_MEMBERSHIP");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
err = this->listen_socket_->bind((struct sockaddr *) &server, sizeof(server));
|
||||
if (err != 0) {
|
||||
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
|
||||
@ -565,6 +580,9 @@ void UDPComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, " Ping-pong: %s", YESNO(this->ping_pong_enable_));
|
||||
for (const auto &address : this->addresses_)
|
||||
ESP_LOGCONFIG(TAG, " Address: %s", address.c_str());
|
||||
if (this->listen_address_.has_value()) {
|
||||
ESP_LOGCONFIG(TAG, " Listen address: %s", this->listen_address_.value().str().c_str());
|
||||
}
|
||||
#ifdef USE_SENSOR
|
||||
for (auto sensor : this->sensors_)
|
||||
ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.id);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/network/ip_address.h"
|
||||
#ifdef USE_SENSOR
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
#endif
|
||||
@ -69,6 +70,7 @@ class UDPComponent : public PollingComponent {
|
||||
}
|
||||
#endif
|
||||
void add_address(const char *addr) { this->addresses_.emplace_back(addr); }
|
||||
void set_listen_address(const char *listen_addr) { this->listen_address_ = network::IPAddress(listen_addr); }
|
||||
void set_port(uint16_t port) { this->port_ = port; }
|
||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
||||
|
||||
@ -143,6 +145,7 @@ class UDPComponent : public PollingComponent {
|
||||
std::map<std::string, std::map<std::string, binary_sensor::BinarySensor *>> remote_binary_sensors_{};
|
||||
#endif
|
||||
|
||||
optional<network::IPAddress> listen_address_{};
|
||||
std::map<std::string, Provider> providers_{};
|
||||
std::vector<uint8_t> ping_header_{};
|
||||
std::vector<uint8_t> header_{};
|
||||
|
@ -1168,6 +1168,15 @@ def ipv4address(value):
|
||||
return address
|
||||
|
||||
|
||||
def ipv4address_multi_broadcast(value):
|
||||
address = ipv4address(value)
|
||||
if not (address.is_multicast or (address == IPv4Address("255.255.255.255"))):
|
||||
raise Invalid(
|
||||
f"{value} is not a multicasst address nor local broadcast address"
|
||||
)
|
||||
return address
|
||||
|
||||
|
||||
def ipaddress(value):
|
||||
try:
|
||||
address = ip_address(value)
|
||||
|
@ -7,6 +7,7 @@ udp:
|
||||
encryption: "our key goes here"
|
||||
rolling_code_enable: true
|
||||
ping_pong_enable: true
|
||||
listen_address: 239.0.60.53
|
||||
binary_sensors:
|
||||
- binary_sensor_id1
|
||||
- id: binary_sensor_id1
|
||||
|
Loading…
Reference in New Issue
Block a user