mirror of
https://github.com/esphome/esphome.git
synced 2025-07-28 22:26:36 +00:00
Automatically disable interrupts for ESP8266 GPIO16 binary sensors (#9467)
This commit is contained in:
parent
8f42bc6aac
commit
77d1d0414d
@ -1,11 +1,16 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
from esphome import pins
|
from esphome import pins
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import binary_sensor
|
from esphome.components import binary_sensor
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import CONF_PIN
|
from esphome.const import CONF_ID, CONF_NAME, CONF_NUMBER, CONF_PIN
|
||||||
|
from esphome.core import CORE
|
||||||
|
|
||||||
from .. import gpio_ns
|
from .. import gpio_ns
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
GPIOBinarySensor = gpio_ns.class_(
|
GPIOBinarySensor = gpio_ns.class_(
|
||||||
"GPIOBinarySensor", binary_sensor.BinarySensor, cg.Component
|
"GPIOBinarySensor", binary_sensor.BinarySensor, cg.Component
|
||||||
)
|
)
|
||||||
@ -41,6 +46,22 @@ async def to_code(config):
|
|||||||
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
pin = await cg.gpio_pin_expression(config[CONF_PIN])
|
||||||
cg.add(var.set_pin(pin))
|
cg.add(var.set_pin(pin))
|
||||||
|
|
||||||
cg.add(var.set_use_interrupt(config[CONF_USE_INTERRUPT]))
|
# Check for ESP8266 GPIO16 interrupt limitation
|
||||||
if config[CONF_USE_INTERRUPT]:
|
# GPIO16 on ESP8266 is a special pin that doesn't support interrupts through
|
||||||
|
# the Arduino attachInterrupt() function. This is the only known GPIO pin
|
||||||
|
# across all supported platforms that has this limitation, so we handle it
|
||||||
|
# here instead of in the platform-specific code.
|
||||||
|
use_interrupt = config[CONF_USE_INTERRUPT]
|
||||||
|
if use_interrupt and CORE.is_esp8266 and config[CONF_PIN][CONF_NUMBER] == 16:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"GPIO binary_sensor '%s': GPIO16 on ESP8266 doesn't support interrupts. "
|
||||||
|
"Falling back to polling mode (same as in ESPHome <2025.7). "
|
||||||
|
"The sensor will work exactly as before, but other pins have better "
|
||||||
|
"performance with interrupts.",
|
||||||
|
config.get(CONF_NAME, config[CONF_ID]),
|
||||||
|
)
|
||||||
|
use_interrupt = False
|
||||||
|
|
||||||
|
cg.add(var.set_use_interrupt(use_interrupt))
|
||||||
|
if use_interrupt:
|
||||||
cg.add(var.set_interrupt_type(config[CONF_INTERRUPT_TYPE]))
|
cg.add(var.set_interrupt_type(config[CONF_INTERRUPT_TYPE]))
|
||||||
|
69
tests/component_tests/gpio/test_gpio_binary_sensor.py
Normal file
69
tests/component_tests/gpio/test_gpio_binary_sensor.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
"""Tests for the GPIO binary sensor component."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
def test_gpio_binary_sensor_basic_setup(
|
||||||
|
generate_main: Callable[[str | Path], str],
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
When the GPIO binary sensor is set in the yaml file, it should be registered in main
|
||||||
|
"""
|
||||||
|
main_cpp = generate_main("tests/component_tests/gpio/test_gpio_binary_sensor.yaml")
|
||||||
|
|
||||||
|
assert "new gpio::GPIOBinarySensor();" in main_cpp
|
||||||
|
assert "App.register_binary_sensor" in main_cpp
|
||||||
|
assert "bs_gpio->set_use_interrupt(true);" in main_cpp
|
||||||
|
assert "bs_gpio->set_interrupt_type(gpio::INTERRUPT_ANY_EDGE);" in main_cpp
|
||||||
|
|
||||||
|
|
||||||
|
def test_gpio_binary_sensor_esp8266_gpio16_disables_interrupt(
|
||||||
|
generate_main: Callable[[str | Path], str],
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Test that ESP8266 GPIO16 automatically disables interrupt mode with a warning
|
||||||
|
"""
|
||||||
|
main_cpp = generate_main(
|
||||||
|
"tests/component_tests/gpio/test_gpio_binary_sensor_esp8266.yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check that interrupt is disabled for GPIO16
|
||||||
|
assert "bs_gpio16->set_use_interrupt(false);" in main_cpp
|
||||||
|
|
||||||
|
# Check that the warning was logged
|
||||||
|
assert "GPIO16 on ESP8266 doesn't support interrupts" in caplog.text
|
||||||
|
assert "Falling back to polling mode" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_gpio_binary_sensor_esp8266_other_pins_use_interrupt(
|
||||||
|
generate_main: Callable[[str | Path], str],
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Test that ESP8266 pins other than GPIO16 still use interrupt mode
|
||||||
|
"""
|
||||||
|
main_cpp = generate_main(
|
||||||
|
"tests/component_tests/gpio/test_gpio_binary_sensor_esp8266.yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
# GPIO5 should still use interrupts
|
||||||
|
assert "bs_gpio5->set_use_interrupt(true);" in main_cpp
|
||||||
|
assert "bs_gpio5->set_interrupt_type(gpio::INTERRUPT_ANY_EDGE);" in main_cpp
|
||||||
|
|
||||||
|
|
||||||
|
def test_gpio_binary_sensor_explicit_polling_mode(
|
||||||
|
generate_main: Callable[[str | Path], str],
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Test that explicitly setting use_interrupt: false works
|
||||||
|
"""
|
||||||
|
main_cpp = generate_main(
|
||||||
|
"tests/component_tests/gpio/test_gpio_binary_sensor_polling.yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "bs_polling->set_use_interrupt(false);" in main_cpp
|
11
tests/component_tests/gpio/test_gpio_binary_sensor.yaml
Normal file
11
tests/component_tests/gpio/test_gpio_binary_sensor.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
esphome:
|
||||||
|
name: test
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
board: esp32dev
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: gpio
|
||||||
|
pin: 5
|
||||||
|
name: "Test GPIO Binary Sensor"
|
||||||
|
id: bs_gpio
|
@ -0,0 +1,20 @@
|
|||||||
|
esphome:
|
||||||
|
name: test
|
||||||
|
|
||||||
|
esp8266:
|
||||||
|
board: d1_mini
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: gpio
|
||||||
|
pin:
|
||||||
|
number: 16
|
||||||
|
mode: INPUT_PULLDOWN_16
|
||||||
|
name: "GPIO16 Touch Sensor"
|
||||||
|
id: bs_gpio16
|
||||||
|
|
||||||
|
- platform: gpio
|
||||||
|
pin:
|
||||||
|
number: 5
|
||||||
|
mode: INPUT_PULLUP
|
||||||
|
name: "GPIO5 Button"
|
||||||
|
id: bs_gpio5
|
@ -0,0 +1,12 @@
|
|||||||
|
esphome:
|
||||||
|
name: test
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
board: esp32dev
|
||||||
|
|
||||||
|
binary_sensor:
|
||||||
|
- platform: gpio
|
||||||
|
pin: 5
|
||||||
|
name: "Polling Mode Sensor"
|
||||||
|
id: bs_polling
|
||||||
|
use_interrupt: false
|
Loading…
x
Reference in New Issue
Block a user