ESPHome 2026.10.0
Loading...
Searching...
No Matches
api_outgoing_connection.h
Go to the documentation of this file.
1#pragma once
2
4#if defined(USE_API) && defined(USE_API_OUTGOING_CONNECTION)
5
6#ifndef USE_API_NOISE
7#error "api outgoing_connection needs noise encryption so the peer is verified by key"
8#endif
9
12
13#include <memory>
14
15namespace esphome::api {
16
17class APIServer;
18class APIConnection;
19
20// Room for an IPv6 address in every build, so a remembered IPv4 target is
21// still dialed after enable_ipv6 is turned on. A size that followed the build
22// would also shift every preference registered after this one on ESP8266,
23// where slots are positional. An IPv6 target on a build without IPv6 is
24// dropped by target_sockaddr_() and relearned.
25// Bytes in an IPv6 address
26static constexpr size_t TARGET_ADDR_LEN = 16;
27
29 // 0 when none is remembered, else AF_INET or AF_INET6
30 uint8_t family;
31 // Network order, IPv4 in the first four bytes and the rest zero
32 uint8_t addr[TARGET_ADDR_LEN];
33 // Interface a link-local IPv6 target is reachable on, 0 when it needs none.
34 // Free in flash: the record still rounds up to the same five words.
35 uint8_t scope_id;
36} PACKED; // NOLINT
37
42 public:
43 void setup();
44 void loop(APIServer *server);
48 void on_client_removed(APIConnection *conn, bool was_authenticated);
49 void on_shutdown() { this->dial_socket_.reset(); }
50 void dump_config() const;
51
52 protected:
53 enum class DialState : uint8_t {
57 };
58
59 static constexpr uint32_t BACKOFF_MIN_MS = 5000;
60 static constexpr uint32_t BACKOFF_MAX_MS = 300000;
61 static constexpr uint32_t CONNECT_TIMEOUT_MS = 10000;
62 static constexpr uint32_t PRECONDITION_RETRY_MS = 5000;
63 // A deep sleep wake window is too short to spend on the delay, so those
64 // builds dial out as soon as the target is gone
65#ifdef USE_DEEP_SLEEP
66 static constexpr uint32_t BOOT_WAIT_MS = 0;
68#else
69 static constexpr uint32_t BOOT_WAIT_MS = API_OUTGOING_CONNECTION_DELAY;
70 static constexpr uint32_t IDLE_WAIT_MS = API_OUTGOING_CONNECTION_DELAY;
71#endif
72
73 void try_dial_(APIServer *server, uint32_t now);
74 void poll_connect_(APIServer *server, uint32_t now);
75 // Hand the connected socket to the server and gate on the new connection
76 void handoff_(APIServer *server, uint32_t now);
77 // Close any half-open dial and wait a jittered backoff before retrying
78 void schedule_retry_(uint32_t now);
79 // Wait without escalating the backoff (used for unmet preconditions)
80 void schedule_wait_(uint32_t now, uint32_t wait);
83#ifndef API_OUTGOING_CONNECTION_HOST
84 // Write saved_ to flash, tracking success in host_persisted_
87 return this->host_persisted_;
88 }
90 void format_target_(std::span<char, socket::SOCKADDR_STR_LEN> buf) const;
91#endif
92
93 // Pointers first (4 bytes each on 32-bit)
94 std::unique_ptr<socket::Socket> dial_socket_;
95 // Compared only, never dereferenced
97#ifndef API_OUTGOING_CONNECTION_HOST
99#endif
100
101 // 4-byte types
105
106 // Byte-aligned types last
107#ifndef API_OUTGOING_CONNECTION_HOST
109 // False while saved_ holds a value the flash write failed for; retried on
110 // the next flagged hello
111 bool host_persisted_{false};
112#endif
114};
115
116} // namespace esphome::api
117#endif // USE_API && USE_API_OUTGOING_CONNECTION
Dials out when no dial-back target client is connected.
void poll_connect_(APIServer *server, uint32_t now)
void handoff_(APIServer *server, uint32_t now)
socklen_t target_sockaddr_(struct sockaddr_storage *addr) const
Fill addr with the target and return its length, or 0 when there is none.
void format_target_(std::span< char, socket::SOCKADDR_STR_LEN > buf) const
Format the remembered target for a log line; empty when there is none.
void on_client_removed(APIConnection *conn, bool was_authenticated)
Clears the dialed-connection gate; dying unauthenticated escalates the backoff.
void schedule_wait_(uint32_t now, uint32_t wait)
void on_target_client(APIConnection *conn)
A key-verified client declared itself a dial-back target; last one wins.
std::unique_ptr< socket::Socket > dial_socket_
void try_dial_(APIServer *server, uint32_t now)
uint32_t socklen_t
Definition headers.h:99
void loop()
struct esphome::api::SavedOutgoingTarget PACKED
ESPPreferences * global_preferences
static void uint32_t
bool sync()
Commit pending writes to flash.
Definition preferences.h:33