mirror of
https://github.com/esphome/esphome.git
synced 2025-02-07 00:11:59 +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 std::string &in_address) { inet_aton(in_address.c_str(), &ip_addr_); }
|
||||||
IPAddress(const ip_addr_t *other_ip) { ip_addr_ = *other_ip; }
|
IPAddress(const ip_addr_t *other_ip) { ip_addr_ = *other_ip; }
|
||||||
|
std::string str() const { return str_lower_case(inet_ntoa(ip_addr_)); }
|
||||||
#else
|
#else
|
||||||
IPAddress() { ip_addr_set_zero(&ip_addr_); }
|
IPAddress() { ip_addr_set_zero(&ip_addr_); }
|
||||||
IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
|
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_set() { return !ip_addr_isany(&ip_addr_); } // NOLINT(readability-simplify-boolean-expr)
|
||||||
bool is_ip4() { return IP_IS_V4(&ip_addr_); }
|
bool is_ip4() { return IP_IS_V4(&ip_addr_); }
|
||||||
bool is_ip6() { return IP_IS_V6(&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_)); }
|
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_); }
|
||||||
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 = "broadcast"
|
||||||
CONF_BROADCAST_ID = "broadcast_id"
|
CONF_BROADCAST_ID = "broadcast_id"
|
||||||
CONF_ADDRESSES = "addresses"
|
CONF_ADDRESSES = "addresses"
|
||||||
|
CONF_LISTEN_ADDRESS = "listen_address"
|
||||||
CONF_PROVIDER = "provider"
|
CONF_PROVIDER = "provider"
|
||||||
CONF_PROVIDERS = "providers"
|
CONF_PROVIDERS = "providers"
|
||||||
CONF_REMOTE_ID = "remote_id"
|
CONF_REMOTE_ID = "remote_id"
|
||||||
@ -84,6 +85,9 @@ CONFIG_SCHEMA = cv.All(
|
|||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(UDPComponent),
|
cv.GenerateID(): cv.declare_id(UDPComponent),
|
||||||
cv.Optional(CONF_PORT, default=18511): cv.port,
|
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.Optional(CONF_ADDRESSES, default=["255.255.255.255"]): cv.ensure_list(
|
||||||
cv.ipv4address,
|
cv.ipv4address,
|
||||||
),
|
),
|
||||||
@ -154,5 +158,7 @@ async def to_code(config):
|
|||||||
for provider in config.get(CONF_PROVIDERS, ()):
|
for provider in config.get(CONF_PROVIDERS, ()):
|
||||||
name = provider[CONF_NAME]
|
name = provider[CONF_NAME]
|
||||||
cg.add(var.add_provider(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):
|
if encryption := provider.get(CONF_ENCRYPTION):
|
||||||
cg.add(var.set_provider_encryption(name, hash_encryption_key(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_addr.s_addr = ESPHOME_INADDR_ANY;
|
||||||
server.sin_port = htons(this->port_);
|
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));
|
err = this->listen_socket_->bind((struct sockaddr *) &server, sizeof(server));
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
|
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_));
|
ESP_LOGCONFIG(TAG, " Ping-pong: %s", YESNO(this->ping_pong_enable_));
|
||||||
for (const auto &address : this->addresses_)
|
for (const auto &address : this->addresses_)
|
||||||
ESP_LOGCONFIG(TAG, " Address: %s", address.c_str());
|
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
|
#ifdef USE_SENSOR
|
||||||
for (auto sensor : this->sensors_)
|
for (auto sensor : this->sensors_)
|
||||||
ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.id);
|
ESP_LOGCONFIG(TAG, " Sensor: %s", sensor.id);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/network/ip_address.h"
|
||||||
#ifdef USE_SENSOR
|
#ifdef USE_SENSOR
|
||||||
#include "esphome/components/sensor/sensor.h"
|
#include "esphome/components/sensor/sensor.h"
|
||||||
#endif
|
#endif
|
||||||
@ -69,6 +70,7 @@ class UDPComponent : public PollingComponent {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void add_address(const char *addr) { this->addresses_.emplace_back(addr); }
|
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; }
|
void set_port(uint16_t port) { this->port_ = port; }
|
||||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
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_{};
|
std::map<std::string, std::map<std::string, binary_sensor::BinarySensor *>> remote_binary_sensors_{};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
optional<network::IPAddress> listen_address_{};
|
||||||
std::map<std::string, Provider> providers_{};
|
std::map<std::string, Provider> providers_{};
|
||||||
std::vector<uint8_t> ping_header_{};
|
std::vector<uint8_t> ping_header_{};
|
||||||
std::vector<uint8_t> header_{};
|
std::vector<uint8_t> header_{};
|
||||||
|
@ -1168,6 +1168,15 @@ def ipv4address(value):
|
|||||||
return address
|
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):
|
def ipaddress(value):
|
||||||
try:
|
try:
|
||||||
address = ip_address(value)
|
address = ip_address(value)
|
||||||
|
@ -7,6 +7,7 @@ udp:
|
|||||||
encryption: "our key goes here"
|
encryption: "our key goes here"
|
||||||
rolling_code_enable: true
|
rolling_code_enable: true
|
||||||
ping_pong_enable: true
|
ping_pong_enable: true
|
||||||
|
listen_address: 239.0.60.53
|
||||||
binary_sensors:
|
binary_sensors:
|
||||||
- binary_sensor_id1
|
- binary_sensor_id1
|
||||||
- id: binary_sensor_id1
|
- id: binary_sensor_id1
|
||||||
|
Loading…
Reference in New Issue
Block a user