mirror of
https://github.com/esphome/esphome.git
synced 2026-08-25 15:46:20 +00:00
136 lines
4.5 KiB
Python
136 lines
4.5 KiB
Python
"""Tests for the GPIO binary sensor component."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Callable
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from esphome.core import CORE
|
|
|
|
INTERRUPT_DEFINE = "USE_GPIO_BINARY_SENSOR_INTERRUPT"
|
|
|
|
|
|
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 "static gpio::GPIOBinarySensor *const" in main_cpp
|
|
assert ") gpio::GPIOBinarySensor();" in main_cpp
|
|
assert "App.register_binary_sensor" in main_cpp
|
|
# set_use_interrupt(true) should NOT be generated (uses C++ default)
|
|
assert "bs_gpio->set_use_interrupt(true);" not 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 (default, so no setter call)
|
|
assert "bs_gpio5->set_use_interrupt(true);" not 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
|
|
|
|
|
|
def test_gpio_binary_sensor_interrupt_emits_define(
|
|
generate_main: Callable[[str | Path], str],
|
|
) -> None:
|
|
"""
|
|
An interrupt-mode sensor must emit the define that compiles the ISR code,
|
|
since the platform ISR pin implementation is only built when needed
|
|
"""
|
|
generate_main("tests/component_tests/gpio/test_gpio_binary_sensor.yaml")
|
|
|
|
assert INTERRUPT_DEFINE in {d.name for d in CORE.defines}
|
|
|
|
|
|
def test_gpio_binary_sensor_polling_omits_define(
|
|
generate_main: Callable[[str | Path], str],
|
|
) -> None:
|
|
"""
|
|
A polling-only config must not emit the interrupt define, so the ISR code
|
|
(and its reference to ISRInternalGPIOPin) is compiled out
|
|
"""
|
|
generate_main("tests/component_tests/gpio/test_gpio_binary_sensor_polling.yaml")
|
|
|
|
assert INTERRUPT_DEFINE not in {d.name for d in CORE.defines}
|
|
|
|
|
|
def test_gpio_binary_sensor_mixed_modes_emit_define(
|
|
generate_main: Callable[[str | Path], str],
|
|
) -> None:
|
|
"""
|
|
With one interrupt and one polling sensor, the define is emitted and the
|
|
polling instance still opts out via its setter
|
|
"""
|
|
main_cpp = generate_main(
|
|
"tests/component_tests/gpio/test_gpio_binary_sensor_mixed.yaml"
|
|
)
|
|
|
|
assert INTERRUPT_DEFINE in {d.name for d in CORE.defines}
|
|
assert "bs_polling->set_use_interrupt(false);" in main_cpp
|
|
assert "bs_interrupt->set_use_interrupt" not in main_cpp
|
|
|
|
|
|
def test_gpio_binary_sensor_expander_pin_omits_define(
|
|
generate_main: Callable[[str | Path], str],
|
|
caplog: pytest.LogCaptureFixture,
|
|
) -> None:
|
|
"""
|
|
An expander pin can't use interrupts: final validation falls back to
|
|
polling and the interrupt define must not be emitted. This is the config
|
|
that fails to link if the ISR code is compiled without an internal pin
|
|
"""
|
|
with caplog.at_level(logging.INFO):
|
|
main_cpp = generate_main(
|
|
"tests/component_tests/gpio/test_gpio_binary_sensor_expander.yaml"
|
|
)
|
|
|
|
assert "bs_expander->set_use_interrupt(false);" in main_cpp
|
|
assert INTERRUPT_DEFINE not in {d.name for d in CORE.defines}
|
|
assert "falling back to polling mode" in caplog.text
|