ESPHome 2026.8.0-dev
Loading...
Searching...
No Matches
ip_address.h
Go to the documentation of this file.
1#pragma once
3#ifdef USE_NETWORK
4#include <cstdint>
5#include <string>
6#include <cstdio>
7#include <array>
8#include <cstring>
10#include "esphome/core/macros.h"
11
12#if defined(USE_ESP32) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0)
13#include <lwip/ip_addr.h>
14#endif
15#if USE_ARDUINO
16#include <Arduino.h>
17#include <IPAddress.h>
18#endif /* USE_ADRDUINO */
19
20#ifdef USE_HOST
21#include <arpa/inet.h>
22#if USE_NETWORK_IPV6
23using ip4_addr_t = struct in_addr;
24using ip6_addr_t = struct in6_addr;
25struct ip_addr_t {
26 union {
27 struct in6_addr ip6;
28 struct in_addr ip4;
30 uint8_t type;
31};
32enum : uint8_t { IPADDR_TYPE_V4 = 0, IPADDR_TYPE_V6 = 6 };
33static inline int ipaddr_aton(const char *cp, ip_addr_t *addr) {
34 if (strchr(cp, ':') != nullptr) {
35 if (inet_pton(AF_INET6, cp, &addr->u_addr.ip6) != 1) {
36 return 0;
37 }
38 addr->type = IPADDR_TYPE_V6;
39 return 1;
40 }
41 if (inet_aton(cp, &addr->u_addr.ip4) != 1) {
42 return 0;
43 }
44 addr->type = IPADDR_TYPE_V4;
45 return 1;
46}
47#else
48using ip_addr_t = in_addr;
49using ip4_addr_t = in_addr;
50#define ipaddr_aton(x, y) inet_aton((x), (y))
51#endif // USE_NETWORK_IPV6
52#endif // USE_HOST
53
54#ifdef USE_ZEPHYR
55#include <zephyr/net/net_ip.h>
56#include <zephyr/net/socket.h>
57#include <zephyr/posix/arpa/inet.h>
58using ip_addr_t = struct in6_addr;
59static inline int ipaddr_aton(const char *cp, ip_addr_t *addr) { return inet_pton(AF_INET6, cp, addr) == 1 ? 1 : 0; }
60#endif
61
62#if USE_ESP32_FRAMEWORK_ARDUINO
63#define arduino_ns Arduino_h
64#elif USE_LIBRETINY
65#define arduino_ns arduino
66#elif USE_ARDUINO
67#define arduino_ns
68#endif
69
70#ifdef USE_ESP32
71#include <esp_netif.h>
72#endif
73
75
77static constexpr size_t IP_ADDRESS_BUFFER_SIZE = 40;
78
80inline void lowercase_ip_str(char *buf) {
81 for (char *p = buf; *p; ++p) {
82 if (*p >= 'A' && *p <= 'F')
83 *p += 32;
84 }
85}
86
87struct IPAddress {
88 public:
89#ifdef USE_ZEPHYR
90 IPAddress() { memset(&ip_addr_, 0, sizeof(ip_addr_)); }
91 IPAddress(const std::string &in_address) : ip_addr_{} { ipaddr_aton(in_address.c_str(), &ip_addr_); }
92 IPAddress(const struct in6_addr *other_ip) { ip_addr_ = *other_ip; }
93 IPAddress(const struct sockaddr_in6 *addr) { ip_addr_ = addr->sin6_addr; }
94
95 operator struct in6_addr() const { return ip_addr_; }
96
97 bool is_set() const { return !net_ipv6_is_addr_unspecified(&ip_addr_); }
98 bool is_ip4() const { return false; }
99 bool is_ip6() const { return this->is_set(); }
100 bool is_multicast() const { return net_ipv6_is_addr_mcast(&ip_addr_); }
101 char *str_to(char *buf) const {
102 if (inet_ntop(AF_INET6, &ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE) == nullptr)
103 buf[0] = '\0';
104 return buf;
105 }
106 bool operator==(const IPAddress &other) const { return net_ipv6_addr_cmp(&ip_addr_, &other.ip_addr_); }
107 bool operator!=(const IPAddress &other) const { return !net_ipv6_addr_cmp(&ip_addr_, &other.ip_addr_); }
108
109#elif defined(USE_HOST)
110#if USE_NETWORK_IPV6
111 IPAddress() { memset(&this->ip_addr_, 0, sizeof(this->ip_addr_)); }
112 IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
113 memset(&this->ip_addr_, 0, sizeof(this->ip_addr_));
114 this->ip_addr_.u_addr.ip4.s_addr =
115 htonl(((uint32_t) first << 24) | ((uint32_t) second << 16) | ((uint32_t) third << 8) | fourth);
117 }
118 IPAddress(const char *in_address) {
119 memset(&this->ip_addr_, 0, sizeof(this->ip_addr_));
120 ipaddr_aton(in_address, &this->ip_addr_);
121 }
122 IPAddress(const std::string &in_address) : IPAddress(in_address.c_str()) {}
123 IPAddress(const ip_addr_t *other_ip) { memcpy(&this->ip_addr_, other_ip, sizeof(ip_addr_t)); }
125 memset(&this->ip_addr_, 0, sizeof(this->ip_addr_));
126 this->ip_addr_.u_addr.ip4 = *other_ip;
128 }
130 memset(&this->ip_addr_, 0, sizeof(this->ip_addr_));
131 this->ip_addr_.u_addr.ip6 = *other_ip;
133 }
134 operator ip_addr_t() const { return this->ip_addr_; }
135 bool is_set() const {
136 if (this->ip_addr_.type == IPADDR_TYPE_V6) {
137 static constexpr uint8_t zero[sizeof(struct in6_addr)] = {};
138 return memcmp(this->ip_addr_.u_addr.ip6.s6_addr, zero, sizeof(zero)) != 0;
139 }
140 return this->ip_addr_.u_addr.ip4.s_addr != 0;
141 }
142 bool is_ip4() const { return this->ip_addr_.type == IPADDR_TYPE_V4; }
143 bool is_ip6() const { return this->ip_addr_.type == IPADDR_TYPE_V6; }
144 bool is_multicast() const {
145 if (this->ip_addr_.type == IPADDR_TYPE_V6) {
146 return this->ip_addr_.u_addr.ip6.s6_addr[0] == 0xff;
147 }
148 return (ntohl(this->ip_addr_.u_addr.ip4.s_addr) & 0xF0000000UL) == 0xE0000000UL;
149 }
150 // Remove before 2026.8.0
152 "str() is deprecated: use 'char buf[IP_ADDRESS_BUFFER_SIZE]; ip.str_to(buf);' instead. Removed in 2026.8.0",
153 "2026.2.0")
154 std::string str() const {
155 char buf[IP_ADDRESS_BUFFER_SIZE];
156 this->str_to(buf);
157 return buf;
158 }
159 char *str_to(char *buf) const {
160 if (this->ip_addr_.type == IPADDR_TYPE_V6) {
161 inet_ntop(AF_INET6, &this->ip_addr_.u_addr.ip6, buf, IP_ADDRESS_BUFFER_SIZE);
162 } else {
163 inet_ntop(AF_INET, &this->ip_addr_.u_addr.ip4, buf, IP_ADDRESS_BUFFER_SIZE);
164 }
165 lowercase_ip_str(buf);
166 return buf;
167 }
168 bool operator==(const IPAddress &other) const {
169 if (this->ip_addr_.type != other.ip_addr_.type) {
170 return false;
171 }
172 if (this->ip_addr_.type == IPADDR_TYPE_V6) {
173 return memcmp(&this->ip_addr_.u_addr.ip6, &other.ip_addr_.u_addr.ip6, sizeof(struct in6_addr)) == 0;
174 }
175 return this->ip_addr_.u_addr.ip4.s_addr == other.ip_addr_.u_addr.ip4.s_addr;
176 }
177 bool operator!=(const IPAddress &other) const { return !(*this == other); }
178 IPAddress &operator+=(uint8_t increase) {
179 if (this->ip_addr_.type == IPADDR_TYPE_V4) {
180 (((uint8_t *) (&this->ip_addr_.u_addr.ip4))[3]) += increase;
181 }
182 return *this;
183 }
184#else
185 IPAddress() { ip_addr_.s_addr = 0; }
186 IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
187 this->ip_addr_.s_addr = htonl((first << 24) | (second << 16) | (third << 8) | fourth);
188 }
189 IPAddress(const std::string &in_address) { inet_aton(in_address.c_str(), &ip_addr_); }
190 IPAddress(const ip_addr_t *other_ip) { ip_addr_ = *other_ip; }
192 char *str_to(char *buf) const {
193 inet_ntop(AF_INET, &ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE);
194 return buf; // IPv4 only, no hex letters to lowercase
195 }
196#endif // USE_NETWORK_IPV6
197#else
198 IPAddress() { ip_addr_set_zero(&ip_addr_); }
199 IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
200 IP_ADDR4(&ip_addr_, first, second, third, fourth);
201 }
202 IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); }
203 IPAddress(const char *in_address) { ipaddr_aton(in_address, &ip_addr_); }
204 IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); }
206 memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t));
207#if LWIP_IPV6
209#endif
210 }
211#if USE_ARDUINO
212 IPAddress(const arduino_ns::IPAddress &other_ip) { ip_addr_set_ip4_u32(&ip_addr_, other_ip); }
213#endif
214#if LWIP_IPV6
216 memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip6_addr_t));
218 }
219#endif /* LWIP_IPV6 */
220
221#ifdef USE_ESP32
222#if LWIP_IPV6
223 IPAddress(esp_ip6_addr_t *other_ip) {
224 memcpy((void *) &ip_addr_.u_addr.ip6, (void *) other_ip, sizeof(esp_ip6_addr_t));
226 }
227#endif /* LWIP_IPV6 */
228 IPAddress(esp_ip4_addr_t *other_ip) {
229 memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(esp_ip4_addr_t));
230#if LWIP_IPV6
232#endif
233 }
234 IPAddress(esp_ip_addr_t *other_ip) {
235#if LWIP_IPV6
236 memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip_addr_));
237#else
238 memcpy((void *) &ip_addr_, (void *) &other_ip->u_addr.ip4, sizeof(ip_addr_));
239#endif
240 }
241 operator esp_ip_addr_t() const {
242 esp_ip_addr_t tmp;
243#if LWIP_IPV6
244 memcpy((void *) &tmp, (void *) &ip_addr_, sizeof(ip_addr_));
245#else
246 memcpy((void *) &tmp.u_addr.ip4, (void *) &ip_addr_, sizeof(ip_addr_));
247#endif /* LWIP_IPV6 */
248 return tmp;
249 }
250 operator esp_ip4_addr_t() const {
251 esp_ip4_addr_t tmp;
252#if LWIP_IPV6
253 memcpy((void *) &tmp, (void *) &ip_addr_.u_addr.ip4, sizeof(esp_ip4_addr_t));
254#else
255 memcpy((void *) &tmp, (void *) &ip_addr_, sizeof(ip_addr_));
256#endif /* LWIP_IPV6 */
257 return tmp;
258 }
259#endif /* USE_ESP32 */
260
261 operator ip_addr_t() const { return ip_addr_; }
262#if LWIP_IPV6
263 operator ip4_addr_t() const { return *ip_2_ip4(&ip_addr_); }
264#endif /* LWIP_IPV6 */
265
266#if USE_ARDUINO
267 operator arduino_ns::IPAddress() const { return ip_addr_get_ip4_u32(&ip_addr_); }
268#endif
269
270 bool is_set() const { return !ip_addr_isany(&ip_addr_); } // NOLINT(readability-simplify-boolean-expr)
271 bool is_ip4() const { return IP_IS_V4(&ip_addr_); }
272 bool is_ip6() const { return IP_IS_V6(&ip_addr_); }
273 bool is_multicast() const { return ip_addr_ismulticast(&ip_addr_); }
276 char *str_to(char *buf) const {
277 ipaddr_ntoa_r(&ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE);
278 lowercase_ip_str(buf);
279 return buf;
280 }
281 bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
282 bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
283 IPAddress &operator+=(uint8_t increase) {
284 if (IP_IS_V4(&ip_addr_)) {
285#if LWIP_IPV6
286 (((u8_t *) (&ip_addr_.u_addr.ip4))[3]) += increase;
287#else
288 (((u8_t *) (&ip_addr_.addr))[3]) += increase;
289#endif /* LWIP_IPV6 */
290 }
291 return *this;
292 }
293#endif
294
295 protected:
297};
298
299using IPAddresses = std::array<IPAddress, 5>;
300
301} // namespace esphome::network
302#endif
uint8_t second
struct in6_addr ip6_addr_t
Definition ip_address.h:24
in_addr ip_addr_t
Definition ip_address.h:48
@ IPADDR_TYPE_V6
Definition ip_address.h:32
@ IPADDR_TYPE_V4
Definition ip_address.h:32
struct in_addr ip4_addr_t
Definition ip_address.h:23
void lowercase_ip_str(char *buf)
Lowercase hex digits in IP address string (A-F -> a-f for IPv6 per RFC 5952)
Definition ip_address.h:80
std::array< IPAddress, 5 > IPAddresses
Definition ip_address.h:299
STL namespace.
static void uint32_t
IPAddress(const struct sockaddr_in6 *addr)
Definition ip_address.h:93
IPAddress(const char *in_address)
Definition ip_address.h:118
IPAddress(ip6_addr_t *other_ip)
Definition ip_address.h:129
bool operator!=(const IPAddress &other) const
Definition ip_address.h:107
ESPDEPRECATED("str() is deprecated: use 'char buf[IP_ADDRESS_BUFFER_SIZE]; ip.str_to(buf);' instead. Removed in 2026.8.0", "2026.2.0") std
Definition ip_address.h:151
bool operator==(const IPAddress &other) const
Definition ip_address.h:106
char * str_to(char *buf) const
Definition ip_address.h:101
IPAddress(esp_ip_addr_t *other_ip)
Definition ip_address.h:234
IPAddress(const ip_addr_t *other_ip)
Definition ip_address.h:123
IPAddress(esp_ip6_addr_t *other_ip)
Definition ip_address.h:223
IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth)
Definition ip_address.h:112
IPAddress(const struct in6_addr *other_ip)
Definition ip_address.h:92
IPAddress & operator+=(uint8_t increase)
Definition ip_address.h:283
IPAddress(esp_ip4_addr_t *other_ip)
Definition ip_address.h:228
IPAddress(ip4_addr_t *other_ip)
Definition ip_address.h:124
IPAddress(const std::string &in_address)
Definition ip_address.h:91
IPAddress(const arduino_ns::IPAddress &other_ip)
Definition ip_address.h:212
struct in6_addr ip6
Definition ip_address.h:27
struct in_addr ip4
Definition ip_address.h:28
union ip_addr_t::@146 u_addr
uint8_t type
Definition ip_address.h:30
struct in6_addr sin6_addr
Definition headers.h:79