ESPHome 2026.10.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; }
191 bool is_ip4() const { return true; }
192 bool is_ip6() const { return false; }
194 char *str_to(char *buf) const {
195 inet_ntop(AF_INET, &ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE);
196 return buf; // IPv4 only, no hex letters to lowercase
197 }
198#endif // USE_NETWORK_IPV6
199#else
200 IPAddress() { ip_addr_set_zero(&ip_addr_); }
201 IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
202 IP_ADDR4(&ip_addr_, first, second, third, fourth);
203 }
204 IPAddress(const ip_addr_t *other_ip) { ip_addr_copy(ip_addr_, *other_ip); }
205 IPAddress(const char *in_address) { ipaddr_aton(in_address, &ip_addr_); }
206 IPAddress(const std::string &in_address) { ipaddr_aton(in_address.c_str(), &ip_addr_); }
208 memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip4_addr_t));
209#if LWIP_IPV6
211#endif
212 }
213#if USE_ARDUINO
214 IPAddress(const arduino_ns::IPAddress &other_ip) { ip_addr_set_ip4_u32(&ip_addr_, other_ip); }
215#endif
216#if LWIP_IPV6
218 memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip6_addr_t));
220 }
221#endif /* LWIP_IPV6 */
222
223#ifdef USE_ESP32
224#if LWIP_IPV6
225 IPAddress(esp_ip6_addr_t *other_ip) {
226 memcpy((void *) &ip_addr_.u_addr.ip6, (void *) other_ip, sizeof(esp_ip6_addr_t));
228 }
229#endif /* LWIP_IPV6 */
230 IPAddress(esp_ip4_addr_t *other_ip) {
231 memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(esp_ip4_addr_t));
232#if LWIP_IPV6
234#endif
235 }
236 IPAddress(esp_ip_addr_t *other_ip) {
237#if LWIP_IPV6
238 memcpy((void *) &ip_addr_, (void *) other_ip, sizeof(ip_addr_));
239#else
240 memcpy((void *) &ip_addr_, (void *) &other_ip->u_addr.ip4, sizeof(ip_addr_));
241#endif
242 }
243 operator esp_ip_addr_t() const {
244 esp_ip_addr_t tmp;
245#if LWIP_IPV6
246 memcpy((void *) &tmp, (void *) &ip_addr_, sizeof(ip_addr_));
247#else
248 memcpy((void *) &tmp.u_addr.ip4, (void *) &ip_addr_, sizeof(ip_addr_));
249#endif /* LWIP_IPV6 */
250 return tmp;
251 }
252 operator esp_ip4_addr_t() const {
253 esp_ip4_addr_t tmp;
254#if LWIP_IPV6
255 memcpy((void *) &tmp, (void *) &ip_addr_.u_addr.ip4, sizeof(esp_ip4_addr_t));
256#else
257 memcpy((void *) &tmp, (void *) &ip_addr_, sizeof(ip_addr_));
258#endif /* LWIP_IPV6 */
259 return tmp;
260 }
261#endif /* USE_ESP32 */
262
263 operator ip_addr_t() const { return ip_addr_; }
264#if LWIP_IPV6
265 operator ip4_addr_t() const { return *ip_2_ip4(&ip_addr_); }
266#endif /* LWIP_IPV6 */
267
268#if USE_ARDUINO
269 operator arduino_ns::IPAddress() const { return ip_addr_get_ip4_u32(&ip_addr_); }
270#endif
271
272 bool is_set() const { return !ip_addr_isany(&ip_addr_); } // NOLINT(readability-simplify-boolean-expr)
273 bool is_ip4() const { return IP_IS_V4(&ip_addr_); }
274 bool is_ip6() const { return IP_IS_V6(&ip_addr_); }
275 bool is_multicast() const { return ip_addr_ismulticast(&ip_addr_); }
278 char *str_to(char *buf) const {
279 ipaddr_ntoa_r(&ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE);
280 lowercase_ip_str(buf);
281 return buf;
282 }
283 bool operator==(const IPAddress &other) const { return ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
284 bool operator!=(const IPAddress &other) const { return !ip_addr_cmp(&ip_addr_, &other.ip_addr_); }
285 IPAddress &operator+=(uint8_t increase) {
286 if (IP_IS_V4(&ip_addr_)) {
287#if LWIP_IPV6
288 (((u8_t *) (&ip_addr_.u_addr.ip4))[3]) += increase;
289#else
290 (((u8_t *) (&ip_addr_.addr))[3]) += increase;
291#endif /* LWIP_IPV6 */
292 }
293 return *this;
294 }
295#endif
296
297 protected:
299};
300
301using IPAddresses = std::array<IPAddress, 5>;
302
303} // namespace esphome::network
304#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:301
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:236
IPAddress(const ip_addr_t *other_ip)
Definition ip_address.h:123
IPAddress(esp_ip6_addr_t *other_ip)
Definition ip_address.h:225
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:285
IPAddress(esp_ip4_addr_t *other_ip)
Definition ip_address.h:230
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:214
struct in6_addr ip6
Definition ip_address.h:27
union ip_addr_t::@147 u_addr
struct in_addr ip4
Definition ip_address.h:28
uint8_t type
Definition ip_address.h:30
struct in6_addr sin6_addr
Definition headers.h:79