mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 11:26:39 +00:00
[matrix_keypad] Keep the keys in flash (#20110)
This commit is contained in:
@@ -27,6 +27,10 @@ CONF_HAS_PULLDOWNS = "has_pulldowns"
|
||||
|
||||
|
||||
def check_keys(obj: ConfigType) -> ConfigType:
|
||||
for ch in obj.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 obj and len(obj[CONF_KEYS]) != len(obj[CONF_ROWS]) * len(
|
||||
obj[CONF_COLUMNS]
|
||||
):
|
||||
@@ -74,8 +78,11 @@ async def to_code(config: ConfigType) -> None:
|
||||
pin = await cg.gpio_pin_expression(conf[CONF_PIN])
|
||||
col_pins.append(pin)
|
||||
cg.add(var.set_columns(col_pins))
|
||||
if CONF_KEYS in config:
|
||||
cg.add(var.set_keys(config[CONF_KEYS]))
|
||||
if (keys := config.get(CONF_KEYS)) is not None:
|
||||
table = cg.shared_progmem_array(
|
||||
"matrix_keypad_keys", cg.uint8, list(keys.encode())
|
||||
)
|
||||
cg.add(var.set_keys(table))
|
||||
cg.add(var.set_debounce_time(config[CONF_DEBOUNCE_TIME]))
|
||||
if CONF_HAS_DIODES in config:
|
||||
cg.add(var.set_has_diodes(config[CONF_HAS_DIODES]))
|
||||
|
||||
@@ -58,8 +58,8 @@ void MatrixKeypad::loop() {
|
||||
ESP_LOGD(TAG, "key @ row %d, col %d released", row, col);
|
||||
for (auto &listener : this->listeners_)
|
||||
listener->button_released(row, col);
|
||||
if (this->pressed_key_ < (int) this->keys_.size()) {
|
||||
uint8_t keycode = this->keys_[this->pressed_key_];
|
||||
if (this->keys_ != nullptr) {
|
||||
uint8_t keycode = progmem_read_byte(&this->keys_[this->pressed_key_]);
|
||||
ESP_LOGD(TAG, "key '%c' released", keycode);
|
||||
for (auto &listener : this->listeners_)
|
||||
listener->key_released(keycode);
|
||||
@@ -81,8 +81,8 @@ void MatrixKeypad::loop() {
|
||||
ESP_LOGD(TAG, "key @ row %d, col %d pressed", row, col);
|
||||
for (auto &listener : this->listeners_)
|
||||
listener->button_pressed(row, col);
|
||||
if (key < (int) this->keys_.size()) {
|
||||
uint8_t keycode = this->keys_[key];
|
||||
if (this->keys_ != nullptr) {
|
||||
uint8_t keycode = progmem_read_byte(&this->keys_[key]);
|
||||
ESP_LOGD(TAG, "key '%c' pressed", keycode);
|
||||
for (auto &trigger : this->key_triggers_)
|
||||
trigger->trigger(keycode);
|
||||
|
||||
@@ -27,7 +27,8 @@ class MatrixKeypad final : public key_provider::KeyProvider, public Component {
|
||||
void dump_config() override;
|
||||
void set_columns(std::vector<GPIOPin *> pins) { columns_ = std::move(pins); };
|
||||
void set_rows(std::vector<GPIOPin *> pins) { rows_ = std::move(pins); };
|
||||
void set_keys(std::string keys) { keys_ = std::move(keys); };
|
||||
/// `keys` is a codegen PROGMEM table with one key code per button.
|
||||
void set_keys(const uint8_t *keys) { this->keys_ = keys; }
|
||||
void set_debounce_time(uint32_t debounce_time) { debounce_time_ = debounce_time; };
|
||||
void set_has_diodes(bool has_diodes) { has_diodes_ = has_diodes; };
|
||||
void set_has_pulldowns(bool has_pulldowns) { has_pulldowns_ = has_pulldowns; };
|
||||
@@ -38,7 +39,7 @@ class MatrixKeypad final : public key_provider::KeyProvider, public Component {
|
||||
protected:
|
||||
std::vector<GPIOPin *> rows_;
|
||||
std::vector<GPIOPin *> columns_;
|
||||
std::string keys_;
|
||||
const uint8_t *keys_{nullptr};
|
||||
uint32_t debounce_time_ = 0;
|
||||
bool has_diodes_{false};
|
||||
bool has_pulldowns_{false};
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp8266:
|
||||
board: esp01_1m
|
||||
|
||||
matrix_keypad:
|
||||
- id: keypad_a
|
||||
rows:
|
||||
- pin: 12
|
||||
- pin: 13
|
||||
columns:
|
||||
- pin: 14
|
||||
- pin: 15
|
||||
keys: "1234"
|
||||
- id: keypad_b
|
||||
rows:
|
||||
- pin: 4
|
||||
- pin: 5
|
||||
columns:
|
||||
- pin: 0
|
||||
- pin: 2
|
||||
keys: "1234"
|
||||
@@ -0,0 +1,27 @@
|
||||
"""Matrix 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.matrix_keypad 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 matrix_keypad_keys[] PROGMEM = {49, 50, 51, 52};"
|
||||
in main_cpp
|
||||
)
|
||||
assert main_cpp.count("->set_keys(matrix_keypad_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