mirror of
https://github.com/esphome/esphome.git
synced 2026-09-07 05:26:01 +00:00
Compare commits
26
Commits
2026.9.0b2
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d34d3994e1 | ||
|
|
d58b37faa1 | ||
|
|
8966567be0 | ||
|
|
20c7dcb1dd | ||
|
|
688af60cbf | ||
|
|
9c00f13606 | ||
|
|
833dd0e812 | ||
|
|
8e1044e8ea | ||
|
|
e5200db6fd | ||
|
|
e3dd2f44a4 | ||
|
|
3ef7460fca | ||
|
|
ae187f81f2 | ||
|
|
84f78831f9 | ||
|
|
13dbbcaa32 | ||
|
|
b66822d9bd | ||
|
|
d1829c495d | ||
|
|
ce87bf9b17 | ||
|
|
51ea97deff | ||
|
|
ab800dc09d | ||
|
|
f65ab5629e | ||
|
|
b84532d254 | ||
|
|
6b11636491 | ||
|
|
2bb98f2d64 | ||
|
|
f3c786c784 | ||
|
|
2250430999 | ||
|
|
d1068d582f |
@@ -553,6 +553,7 @@ file does, and it is the authority when they disagree. The most useful starting
|
||||
4. **Lint:** Run `prek` to ensure code is compliant.
|
||||
5. **Commit:** Commit your changes. There is no strict format for commit messages.
|
||||
6. **Pull Request:** Submit a PR against the `dev` branch. The Pull Request title must start with a `[tag]` prefix. For component work, use the component name (e.g., `[display] Fix bug`, `[abc123] Add new component`); for changes to shared/core code that isn't tied to a single component, use `[core]` (e.g., `[core] Add validator`). Update documentation, examples, and add `CODEOWNERS` entries as needed. Pull requests should always be made using the `.github/PULL_REQUEST_TEMPLATE.md` template - fill out all sections completely without removing any parts of the template.
|
||||
7. **Comments:** When commenting on GitHub PRs or issues, don't tag contributors, especially bots. Avoid referring to list items (e.g. from reviews) with the form #nn - this will be interpreted by GitHub as a reference to issue or PR nn. Keep comments short and exclude irrelevant details, backstories, restatement of previous comments and anything that is already obvious to the reader.
|
||||
|
||||
* **Documentation Contributions:**
|
||||
* Documentation is hosted in the separate `esphome/esphome.io` repository.
|
||||
|
||||
@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 2026.9.0b2
|
||||
PROJECT_NUMBER = 2026.10.0-dev
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -35,8 +35,8 @@ void MipiDsi::setup() {
|
||||
.bus_id = 0, // index from 0, specify the DSI host to use
|
||||
.num_data_lanes =
|
||||
this->lanes_, // Number of data lanes to use, can't set a value that exceeds the chip's capability
|
||||
.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, // Clock source for the DPHY
|
||||
.lane_bit_rate_mbps = this->lane_bit_rate_, // Bit rate of the data lanes, in Mbps
|
||||
// phy_clk_src left at 0 to enable runtime auto-select.
|
||||
.lane_bit_rate_mbps = this->lane_bit_rate_, // Bit rate of the data lanes, in Mbps
|
||||
};
|
||||
auto err = esp_lcd_new_dsi_bus(&bus_config, &this->bus_handle_);
|
||||
if (err != ESP_OK) {
|
||||
|
||||
@@ -66,13 +66,14 @@ from esphome.const import (
|
||||
)
|
||||
from esphome.core import (
|
||||
CORE,
|
||||
ID,
|
||||
CoroPriority,
|
||||
EsphomeError,
|
||||
HexInt,
|
||||
coroutine_with_priority,
|
||||
)
|
||||
import esphome.final_validate as fv
|
||||
from esphome.types import ConfigType
|
||||
from esphome.types import ConfigType, TemplateArgsType
|
||||
|
||||
from . import wpa2_eap
|
||||
|
||||
@@ -208,6 +209,7 @@ WiFiEnabledCondition = wifi_ns.class_("WiFiEnabledCondition", Condition)
|
||||
WiFiAPActiveCondition = wifi_ns.class_("WiFiAPActiveCondition", Condition)
|
||||
WiFiEnableAction = wifi_ns.class_("WiFiEnableAction", automation.Action)
|
||||
WiFiDisableAction = wifi_ns.class_("WiFiDisableAction", automation.Action)
|
||||
WiFiRoamAction = wifi_ns.class_("WiFiRoamAction", automation.Action)
|
||||
WiFiConfigureAction = wifi_ns.class_(
|
||||
"WiFiConfigureAction", automation.Action, cg.Component
|
||||
)
|
||||
@@ -820,6 +822,18 @@ async def wifi_disable_to_code(config, action_id, template_arg, args):
|
||||
return cg.new_Pvariable(action_id, template_arg)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"wifi.roam", WiFiRoamAction, cv.Schema({}), synchronous=True
|
||||
)
|
||||
async def wifi_roam_to_code(
|
||||
config: ConfigType,
|
||||
action_id: ID,
|
||||
template_arg: cg.TemplateArguments,
|
||||
args: TemplateArgsType,
|
||||
) -> cg.MockObj:
|
||||
return cg.new_Pvariable(action_id, template_arg)
|
||||
|
||||
|
||||
KEEP_SCAN_RESULTS_KEY = "wifi_keep_scan_results"
|
||||
RUNTIME_POWER_SAVE_KEY = "wifi_runtime_power_save"
|
||||
RUNTIME_ROAMING_SUPPRESSION_KEY = "wifi_runtime_roaming_suppression"
|
||||
|
||||
@@ -31,6 +31,11 @@ template<typename... Ts> class WiFiDisableAction final : public Action<Ts...> {
|
||||
void play(const Ts &...x) override { global_wifi_component->disable(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class WiFiRoamAction final : public Action<Ts...> {
|
||||
public:
|
||||
void play(const Ts &...x) override { global_wifi_component->force_roam_check(); }
|
||||
};
|
||||
|
||||
template<typename... Ts> class WiFiConfigureAction final : public Action<Ts...>, public Component {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(std::string, ssid)
|
||||
|
||||
@@ -846,17 +846,18 @@ void WiFiComponent::loop() {
|
||||
this->notify_connect_state_listeners_();
|
||||
#endif
|
||||
|
||||
// Post-connect roaming: check for better AP
|
||||
if (this->post_connect_roaming_) {
|
||||
if (this->is_roaming_scan_active()) {
|
||||
if (this->scan_done_) {
|
||||
this->process_roaming_scan_();
|
||||
}
|
||||
// else: scan in progress, wait
|
||||
} else if (this->roaming_state_ == RoamingState::IDLE && this->roaming_attempts_ < ROAMING_MAX_ATTEMPTS &&
|
||||
now - this->roaming_last_check_ >= ROAMING_CHECK_INTERVAL && !this->roaming_suppressed_()) {
|
||||
this->check_roaming_(now);
|
||||
// Post-connect roaming: check for better AP. A scan may have been started by an
|
||||
// explicit force_roam_check() even when post_connect_roaming_ is disabled, so the
|
||||
// scan must always be consumed here to avoid leaving roaming_state_ stuck.
|
||||
if (this->is_roaming_scan_active()) {
|
||||
if (this->scan_done_) {
|
||||
this->process_roaming_scan_();
|
||||
}
|
||||
// else: scan in progress, wait
|
||||
} else if (this->post_connect_roaming_ && this->roaming_state_ == RoamingState::IDLE &&
|
||||
this->roaming_attempts_ < ROAMING_MAX_ATTEMPTS &&
|
||||
now - this->roaming_last_check_ >= ROAMING_CHECK_INTERVAL && !this->roaming_suppressed_()) {
|
||||
this->check_roaming_(now);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2463,6 +2464,17 @@ void WiFiComponent::notify_scan_results_listeners_() {
|
||||
}
|
||||
#endif // USE_WIFI_SCAN_RESULTS_LISTENERS
|
||||
|
||||
void WiFiComponent::force_roam_check() {
|
||||
if (!this->is_connected() || this->roaming_state_ != RoamingState::IDLE || this->roaming_suppressed_()) {
|
||||
ESP_LOGD(TAG, "Roam check requested, but not able to check now");
|
||||
return;
|
||||
}
|
||||
// Reset the attempt counter so a prior run of failed roams doesn't block this explicit request
|
||||
// Note that this re-arms automatic roaming if enabled.
|
||||
this->roaming_attempts_ = 0;
|
||||
this->check_roaming_(millis());
|
||||
}
|
||||
|
||||
void WiFiComponent::check_roaming_(uint32_t now) {
|
||||
// Guard: not for hidden networks (may not appear in scan)
|
||||
const WiFiAP *selected = this->get_selected_sta_();
|
||||
@@ -2484,7 +2496,11 @@ void WiFiComponent::check_roaming_(uint32_t now) {
|
||||
|
||||
ESP_LOGD(TAG, "Roam scan (%d dBm, attempt %u/%u)", rssi, this->roaming_attempts_, ROAMING_MAX_ATTEMPTS);
|
||||
this->roaming_state_ = RoamingState::SCANNING;
|
||||
this->wifi_scan_start_(this->passive_scan_);
|
||||
if (!this->wifi_scan_start_(this->passive_scan_)) {
|
||||
// Scan failed to start (e.g. busy) - don't get stuck in SCANNING forever
|
||||
ESP_LOGD(TAG, "Roam scan failed to start");
|
||||
this->roaming_state_ = RoamingState::IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void WiFiComponent::process_roaming_scan_() {
|
||||
|
||||
@@ -565,6 +565,12 @@ class WiFiComponent final : public Component {
|
||||
void set_keep_scan_results(bool keep_scan_results) { this->keep_scan_results_ = keep_scan_results; }
|
||||
void set_post_connect_roaming(bool enabled) { this->post_connect_roaming_ = enabled; }
|
||||
|
||||
/** Force an immediate post-connect roaming check, bypassing the periodic interval and the
|
||||
* per-connection attempt limit. Does nothing (besides a debug log) if not connected, if a
|
||||
* roam scan or connect is already in progress, or if roaming is currently suppressed.
|
||||
*/
|
||||
void force_roam_check();
|
||||
|
||||
#ifdef USE_WIFI_CONNECT_TRIGGER
|
||||
Trigger<> *get_connect_trigger() { return &this->connect_trigger_; }
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ from enum import Enum
|
||||
|
||||
from esphome.enum import StrEnum
|
||||
|
||||
__version__ = "2026.9.0b2"
|
||||
__version__ = "2026.10.0-dev"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||
|
||||
+4
-4
@@ -14,7 +14,7 @@ esptool==5.3.1
|
||||
click==8.3.3
|
||||
aioesphomeapi==46.3.0
|
||||
aiohappyeyeballs==2.7.1 # Happy Eyeballs for requests downloads; already pulled in by aioesphomeapi
|
||||
zeroconf==0.151.2
|
||||
zeroconf==0.151.3
|
||||
puremagic==2.2.0
|
||||
ruamel.yaml==0.19.1 # dashboard_import
|
||||
ruamel.yaml.clib==0.2.15 # dashboard_import
|
||||
@@ -27,9 +27,9 @@ bleak==3.0.2
|
||||
smpclient==7.2.0
|
||||
requests==2.34.2
|
||||
py7zr==1.1.3
|
||||
platformdirs==4.11.5 # native esp-idf toolchain global cache dir
|
||||
ninja==1.13.0 # native esp8266 arduino toolchain build driver
|
||||
filelock==3.32.4 # inter-process locks (PlatformIO cache heal, git clone cache); >=3.32 for FileLock(fallback_to_soft=...), older versions silently drop the kwarg
|
||||
platformdirs==4.11.7 # native esp-idf toolchain global cache dir
|
||||
ninja==1.13.2 # native esp8266 arduino toolchain build driver
|
||||
filelock==3.32.5 # inter-process locks (PlatformIO cache heal, git clone cache); >=3.32 for FileLock(fallback_to_soft=...), older versions silently drop the kwarg
|
||||
|
||||
# esp-idf >= 5.0 requires this
|
||||
pyparsing >= 3.3.2
|
||||
|
||||
@@ -2,7 +2,7 @@ pylint==4.0.8
|
||||
flake8==7.3.0 # also change in .pre-commit-config.yaml when updating
|
||||
ruff==0.16.5 # also change in .pre-commit-config.yaml when updating
|
||||
pyupgrade==3.21.2 # also change in .pre-commit-config.yaml when updating
|
||||
prek==0.5.0 # also change in .github/workflows/ci.yml when updating
|
||||
prek==0.5.1 # also change in .github/workflows/ci.yml when updating
|
||||
|
||||
# Unit tests
|
||||
pytest==9.1.1
|
||||
|
||||
@@ -14,6 +14,7 @@ esphome:
|
||||
condition: wifi.ap_active
|
||||
then:
|
||||
- logger.log: "WiFi AP is active!"
|
||||
- wifi.roam
|
||||
|
||||
wifi:
|
||||
networks:
|
||||
|
||||
Reference in New Issue
Block a user