Skip to content

Commit 2d25ecf

Browse files
author
Samuel Sieb
committed
add component for CardKB
1 parent 4f6af89 commit 2d25ecf

File tree

6 files changed

+184
-0
lines changed

6 files changed

+184
-0
lines changed

components/cardkb/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# CardKB: https://shop.m5stack.com/products/cardkb-mini-keyboard
2+
3+
This component is for the CardKB device. Define a `cardkb` component then add `binary_sensor`s to handle individual keys.
4+
If you want automatic handling for multiple keys, e.g. PIN entry, use the `key_collector` component.
5+
6+
Example:
7+
```yaml
8+
cardkb:
9+
- id: mykb #optional
10+
11+
binary_sensor:
12+
- platform: cardkb
13+
cardkb_id: mykb #optional if only one keyboard
14+
id: a_key
15+
key: a
16+
- platform: cardkb
17+
id: enter_key
18+
key: 13
19+
```
20+

components/cardkb/__init__.py

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import esphome.codegen as cg
2+
import esphome.config_validation as cv
3+
from esphome.components import i2c, key_provider
4+
from esphome.const import CONF_ID
5+
6+
CODEOWNERS = ["@ssieb"]
7+
DEPENDENCIES = ["i2c"]
8+
9+
AUTO_LOAD = [ "key_provider" ]
10+
11+
MULTI_CONF = True
12+
13+
cardkb_ns = cg.esphome_ns.namespace('cardkb')
14+
CardKB = cardkb_ns.class_('CardKB', cg.Component, i2c.I2CDevice, key_provider.KeyProvider)
15+
16+
CONF_CARDKB_ID = 'cardkb_id'
17+
18+
CONFIG_SCHEMA = i2c.i2c_device_schema(None).extend(
19+
{
20+
cv.GenerateID(): cv.declare_id(CardKB),
21+
}
22+
)
23+
24+
async def to_code(config):
25+
var = cg.new_Pvariable(config[CONF_ID])
26+
await cg.register_component(var, config)
27+
await i2c.register_i2c_device(var, config)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import esphome.codegen as cg
2+
import esphome.config_validation as cv
3+
from esphome.components import binary_sensor
4+
from esphome.const import CONF_ID, CONF_KEY
5+
from .. import CardKB, cardkb_ns, CONF_CARDKB_ID
6+
7+
DEPENDENCIES = ['cardkb']
8+
9+
CardKBBinarySensor = cardkb_ns.class_('CardKBBinarySensor', binary_sensor.BinarySensor)
10+
11+
def key(value):
12+
if isinstance(value, str):
13+
if len(value) == 1:
14+
return ord(value[0])
15+
elif isinstance(value, int):
16+
if value > 0 and value <= 255:
17+
return value
18+
raise cv.Invalid("Number must be between 1 and 255")
19+
raise cv.Invalid("Must be a string with one character or a number")
20+
21+
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
22+
{
23+
cv.GenerateID(): cv.declare_id(CardKBBinarySensor),
24+
cv.GenerateID(CONF_CARDKB_ID): cv.use_id(CardKB),
25+
cv.Required(CONF_KEY): key,
26+
}
27+
)
28+
29+
30+
async def to_code(config):
31+
key = config[CONF_KEY]
32+
var = cg.new_Pvariable(config[CONF_ID], config[CONF_KEY])
33+
await binary_sensor.register_binary_sensor(var, config)
34+
cardkb = await cg.get_variable(config[CONF_CARDKB_ID])
35+
cg.add(cardkb.register_listener(var))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#pragma once
2+
3+
#include "esphome/components/cardkb/cardkb.h"
4+
#include "esphome/components/binary_sensor/binary_sensor.h"
5+
6+
namespace esphome {
7+
namespace cardkb {
8+
9+
class CardKBBinarySensor : public CardKBListener, public binary_sensor::BinarySensor {
10+
public:
11+
CardKBBinarySensor(uint8_t key) : key_(key) {};
12+
13+
void key_pressed(uint8_t key) override {
14+
if (key == this->key_)
15+
this->publish_state(true);
16+
}
17+
18+
void key_released(uint8_t key) override {
19+
if (key == this->key_)
20+
this->publish_state(false);
21+
}
22+
23+
protected:
24+
uint8_t key_;
25+
};
26+
27+
} // namespace cardkb
28+
} // namespace esphome

components/cardkb/cardkb.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include "cardkb.h"
2+
#include "esphome/core/hal.h"
3+
#include "esphome/core/log.h"
4+
5+
namespace esphome {
6+
namespace cardkb {
7+
8+
static const char *TAG = "cardkb";
9+
10+
void CardKB::loop() {
11+
uint8_t c;
12+
static uint32_t last_error = 0;
13+
c = this->pressed_key_;
14+
if (c) {
15+
for (auto &listener : this->listeners_)
16+
listener->key_released(c);
17+
this->pressed_key_ = 0;
18+
}
19+
i2c::ErrorCode res = this->read(&c, 1);
20+
if ((res != i2c::NO_ERROR) || (c == 0))
21+
return;
22+
if (c < 32)
23+
ESP_LOGD(TAG, "keycode '%d' pressed", c);
24+
else
25+
ESP_LOGD(TAG, "key '%c' pressed", c);
26+
for (auto &listener : this->listeners_)
27+
listener->key_pressed(c);
28+
this->pressed_key_ = c;
29+
this->send_key_(c);
30+
}
31+
32+
void CardKB::dump_config() {
33+
ESP_LOGCONFIG(TAG, "CardKB:");
34+
}
35+
36+
void CardKB::register_listener(CardKBListener *listener) {
37+
this->listeners_.push_back(listener);
38+
}
39+
40+
} // namespace cardkb
41+
} // namespace esphome
42+

components/cardkb/cardkb.h

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
3+
#include "esphome/components/i2c/i2c.h"
4+
#include "esphome/components/key_provider/key_provider.h"
5+
#include "esphome/core/component.h"
6+
7+
namespace esphome {
8+
namespace cardkb {
9+
10+
class CardKBListener {
11+
public:
12+
virtual void key_pressed(uint8_t key) {};
13+
virtual void key_released(uint8_t key) {};
14+
};
15+
16+
class CardKB : public key_provider::KeyProvider, public Component, public i2c::I2CDevice {
17+
public:
18+
void loop() override;
19+
void dump_config() override;
20+
21+
void register_listener(CardKBListener *listener);
22+
23+
protected:
24+
int pressed_key_ = -1;
25+
26+
std::vector<CardKBListener *> listeners_{};
27+
};
28+
29+
} // namespace cardkb
30+
} // namespace esphome
31+
32+

0 commit comments

Comments
 (0)