mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 19:44:08 +00:00
[sx1509] Keep the keypad keys in flash (#20111)
This commit is contained in:
@@ -43,6 +43,10 @@ SX1509KeyTrigger = sx1509_ns.class_(
|
||||
|
||||
|
||||
def check_keys(config: ConfigType) -> ConfigType:
|
||||
for ch in config.get(CONF_KEYS, ""):
|
||||
if not ch.isascii():
|
||||
# Each key is reported as one byte, so only ASCII characters can be key codes
|
||||
raise cv.Invalid(f"Key code {ch!r} is not an ASCII character")
|
||||
if (
|
||||
CONF_KEYS in config
|
||||
and len(config[CONF_KEYS]) != config[CONF_KEY_ROWS] * config[CONF_KEY_COLUMNS]
|
||||
@@ -98,8 +102,11 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add(var.set_sleep_time(conf[CONF_SLEEP_TIME]))
|
||||
cg.add(var.set_scan_time(conf[CONF_SCAN_TIME]))
|
||||
cg.add(var.set_debounce_time(conf[CONF_DEBOUNCE_TIME]))
|
||||
if keys := conf.get(CONF_KEYS):
|
||||
cg.add(var.set_keys(keys))
|
||||
if (keys := conf.get(CONF_KEYS)) is not None:
|
||||
table = cg.shared_progmem_array(
|
||||
"sx1509_keys", cg.uint8, list(keys.encode())
|
||||
)
|
||||
cg.add(var.set_keys(table))
|
||||
for tconf in conf.get(CONF_ON_KEY, []):
|
||||
trigger = cg.new_Pvariable(tconf[CONF_TRIGGER_ID])
|
||||
cg.add(var.register_key_trigger(trigger))
|
||||
|
||||
@@ -48,7 +48,7 @@ void SX1509Component::loop() {
|
||||
uint16_t key_data = this->read_key_data();
|
||||
for (auto *binary_sensor : this->keypad_binary_sensors_)
|
||||
binary_sensor->process(key_data);
|
||||
if (this->keys_.empty())
|
||||
if (this->keys_ == nullptr)
|
||||
return;
|
||||
if (key_data == 0) {
|
||||
this->last_key_ = 0;
|
||||
@@ -64,7 +64,9 @@ void SX1509Component::loop() {
|
||||
break;
|
||||
}
|
||||
col -= 8;
|
||||
uint8_t key = this->keys_[row * this->cols_ + col];
|
||||
if (row >= this->rows_ || col >= this->cols_) // a partial read can leave only a row or a column bit
|
||||
return;
|
||||
uint8_t key = progmem_read_byte(&this->keys_[row * this->cols_ + col]);
|
||||
if (key == this->last_key_)
|
||||
return;
|
||||
this->last_key_ = key;
|
||||
|
||||
@@ -51,7 +51,8 @@ class SX1509Component final : public Component,
|
||||
this->cols_ = cols;
|
||||
this->has_keypad_ = true;
|
||||
};
|
||||
void set_keys(std::string keys) { this->keys_ = std::move(keys); }; // NOLINT(performance-unnecessary-value-param)
|
||||
/// `keys` is a codegen PROGMEM table with one key code per button.
|
||||
void set_keys(const uint8_t *keys) { this->keys_ = keys; }
|
||||
void set_sleep_time(uint16_t sleep_time) { this->sleep_time_ = sleep_time; };
|
||||
void set_scan_time(uint8_t scan_time) { this->scan_time_ = scan_time; };
|
||||
void set_debounce_time(uint8_t debounce_time = 1) { this->debounce_time_ = debounce_time; };
|
||||
@@ -76,7 +77,7 @@ class SX1509Component final : public Component,
|
||||
bool has_keypad_ = false;
|
||||
uint8_t rows_ = 0;
|
||||
uint8_t cols_ = 0;
|
||||
std::string keys_;
|
||||
const uint8_t *keys_{nullptr};
|
||||
uint16_t sleep_time_ = 128;
|
||||
uint8_t scan_time_ = 1;
|
||||
uint8_t debounce_time_ = 1;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp8266:
|
||||
board: esp01_1m
|
||||
|
||||
i2c:
|
||||
sda: 4
|
||||
scl: 5
|
||||
|
||||
sx1509:
|
||||
- id: sx_a
|
||||
address: 0x3E
|
||||
keypad:
|
||||
key_rows: 2
|
||||
key_columns: 2
|
||||
keys: "abcd"
|
||||
- id: sx_b
|
||||
address: 0x3F
|
||||
keypad:
|
||||
key_rows: 2
|
||||
key_columns: 2
|
||||
keys: "abcd"
|
||||
@@ -0,0 +1,27 @@
|
||||
"""SX1509 keypad key codes live in a shared PROGMEM table instead of a std::string."""
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.sx1509 import check_keys
|
||||
import esphome.config_validation as cv
|
||||
|
||||
|
||||
def test_keys_use_shared_progmem_table(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
main_cpp = generate_main(component_config_path("keys.yaml"))
|
||||
|
||||
assert (
|
||||
"static constexpr uint8_t sx1509_keys[] PROGMEM = {97, 98, 99, 100};"
|
||||
in main_cpp
|
||||
)
|
||||
assert main_cpp.count("->set_keys(sx1509_keys);") == 2
|
||||
|
||||
|
||||
def test_non_ascii_keys_are_rejected() -> None:
|
||||
with pytest.raises(cv.Invalid, match="'é' is not an ASCII"):
|
||||
check_keys({"keys": "1é34"})
|
||||
Reference in New Issue
Block a user