mirror of
https://github.com/esphome/esphome.git
synced 2024-11-22 23:18:10 +01:00
Tm1637 binarysensor (#2792)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
2e436eae6b
commit
70fafa473b
3 changed files with 132 additions and 17 deletions
26
esphome/components/tm1637/binary_sensor.py
Normal file
26
esphome/components/tm1637/binary_sensor.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import binary_sensor
|
||||||
|
from esphome.const import CONF_ID, CONF_KEY
|
||||||
|
|
||||||
|
CONF_TM1637_ID = "tm1637_id"
|
||||||
|
|
||||||
|
tm1637_ns = cg.esphome_ns.namespace("tm1637")
|
||||||
|
TM1637Display = tm1637_ns.class_("TM1637Display", cg.PollingComponent)
|
||||||
|
TM1637Key = tm1637_ns.class_("TM1637Key", binary_sensor.BinarySensor)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(TM1637Key),
|
||||||
|
cv.GenerateID(CONF_TM1637_ID): cv.use_id(TM1637Display),
|
||||||
|
cv.Required(CONF_KEY): cv.int_range(min=0, max=15),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await binary_sensor.register_binary_sensor(var, config)
|
||||||
|
cg.add(var.set_keycode(config[CONF_KEY]))
|
||||||
|
hub = await cg.get_variable(config[CONF_TM1637_ID])
|
||||||
|
cg.add(hub.add_tm1637_key(var))
|
|
@ -7,11 +7,17 @@ namespace esphome {
|
||||||
namespace tm1637 {
|
namespace tm1637 {
|
||||||
|
|
||||||
static const char *const TAG = "display.tm1637";
|
static const char *const TAG = "display.tm1637";
|
||||||
const uint8_t TM1637_I2C_COMM1 = 0x40;
|
const uint8_t TM1637_CMD_DATA = 0x40; //!< Display data command
|
||||||
const uint8_t TM1637_I2C_COMM2 = 0xC0;
|
const uint8_t TM1637_CMD_CTRL = 0x80; //!< Display control command
|
||||||
const uint8_t TM1637_I2C_COMM3 = 0x80;
|
const uint8_t TM1637_CMD_ADDR = 0xc0; //!< Display address command
|
||||||
const uint8_t TM1637_UNKNOWN_CHAR = 0b11111111;
|
const uint8_t TM1637_UNKNOWN_CHAR = 0b11111111;
|
||||||
|
|
||||||
|
// Data command bits
|
||||||
|
const uint8_t TM1637_DATA_WRITE = 0x00; //!< Write data
|
||||||
|
const uint8_t TM1637_DATA_READ_KEYS = 0x02; //!< Read keys
|
||||||
|
const uint8_t TM1637_DATA_AUTO_INC_ADDR = 0x00; //!< Auto increment address
|
||||||
|
const uint8_t TM1637_DATA_FIXED_ADDR = 0x04; //!< Fixed address
|
||||||
|
|
||||||
//
|
//
|
||||||
// A
|
// A
|
||||||
// ---
|
// ---
|
||||||
|
@ -138,6 +144,36 @@ void TM1637Display::dump_config() {
|
||||||
LOG_UPDATE_INTERVAL(this);
|
LOG_UPDATE_INTERVAL(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
void TM1637Display::loop() {
|
||||||
|
uint8_t val = this->get_keys();
|
||||||
|
for (auto *tm1637_key : this->tm1637_keys_)
|
||||||
|
tm1637_key->process(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TM1637Display::get_keys() {
|
||||||
|
this->start_();
|
||||||
|
this->send_byte_(TM1637_CMD_DATA | TM1637_DATA_READ_KEYS);
|
||||||
|
this->start_();
|
||||||
|
uint8_t key_code = read_byte_();
|
||||||
|
this->stop_();
|
||||||
|
if (key_code != 0xFF) {
|
||||||
|
// Invert key_code:
|
||||||
|
// Bit | 7 6 5 4 3 2 1 0
|
||||||
|
// ------+-------------------------
|
||||||
|
// From | S0 S1 S2 K1 K2 1 1 1
|
||||||
|
// To | S0 S1 S2 K1 K2 0 0 0
|
||||||
|
key_code = ~key_code;
|
||||||
|
// Shift bits to:
|
||||||
|
// Bit | 7 6 5 4 3 2 1 0
|
||||||
|
// ------+------------------------
|
||||||
|
// To | 0 0 0 0 K2 S2 S1 S0
|
||||||
|
key_code = (uint8_t)((key_code & 0x80) >> 7 | (key_code & 0x40) >> 5 | (key_code & 0x20) >> 3 | (key_code & 0x08));
|
||||||
|
}
|
||||||
|
return key_code;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void TM1637Display::update() {
|
void TM1637Display::update() {
|
||||||
for (uint8_t &i : this->buffer_)
|
for (uint8_t &i : this->buffer_)
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -165,14 +201,14 @@ void TM1637Display::stop_() {
|
||||||
void TM1637Display::display() {
|
void TM1637Display::display() {
|
||||||
ESP_LOGVV(TAG, "Display %02X%02X%02X%02X", buffer_[0], buffer_[1], buffer_[2], buffer_[3]);
|
ESP_LOGVV(TAG, "Display %02X%02X%02X%02X", buffer_[0], buffer_[1], buffer_[2], buffer_[3]);
|
||||||
|
|
||||||
// Write COMM1
|
// Write DATA CMND
|
||||||
this->start_();
|
this->start_();
|
||||||
this->send_byte_(TM1637_I2C_COMM1);
|
this->send_byte_(TM1637_CMD_DATA);
|
||||||
this->stop_();
|
this->stop_();
|
||||||
|
|
||||||
// Write COMM2 + first digit address
|
// Write ADDR CMD + first digit address
|
||||||
this->start_();
|
this->start_();
|
||||||
this->send_byte_(TM1637_I2C_COMM2);
|
this->send_byte_(TM1637_CMD_ADDR);
|
||||||
|
|
||||||
// Write the data bytes
|
// Write the data bytes
|
||||||
if (this->inverted_) {
|
if (this->inverted_) {
|
||||||
|
@ -187,20 +223,17 @@ void TM1637Display::display() {
|
||||||
|
|
||||||
this->stop_();
|
this->stop_();
|
||||||
|
|
||||||
// Write COMM3 + brightness
|
// Write display CTRL CMND + brightness
|
||||||
this->start_();
|
this->start_();
|
||||||
this->send_byte_(TM1637_I2C_COMM3 + ((this->intensity_ & 0x7) | 0x08));
|
this->send_byte_(TM1637_CMD_CTRL + ((this->intensity_ & 0x7) | 0x08));
|
||||||
this->stop_();
|
this->stop_();
|
||||||
}
|
}
|
||||||
bool TM1637Display::send_byte_(uint8_t b) {
|
bool TM1637Display::send_byte_(uint8_t b) {
|
||||||
uint8_t data = b;
|
uint8_t data = b;
|
||||||
|
|
||||||
// 8 Data Bits
|
|
||||||
for (uint8_t i = 0; i < 8; i++) {
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
// CLK low
|
// CLK low
|
||||||
this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
this->bit_delay_();
|
this->bit_delay_();
|
||||||
|
|
||||||
// Set data bit
|
// Set data bit
|
||||||
if (data & 0x01) {
|
if (data & 0x01) {
|
||||||
this->dio_pin_->pin_mode(gpio::FLAG_INPUT);
|
this->dio_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
|
@ -209,19 +242,16 @@ bool TM1637Display::send_byte_(uint8_t b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
this->bit_delay_();
|
this->bit_delay_();
|
||||||
|
|
||||||
// CLK high
|
// CLK high
|
||||||
this->clk_pin_->pin_mode(gpio::FLAG_INPUT);
|
this->clk_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
this->bit_delay_();
|
this->bit_delay_();
|
||||||
data = data >> 1;
|
data = data >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for acknowledge
|
// Wait for acknowledge
|
||||||
// CLK to zero
|
// CLK to zero
|
||||||
this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
this->dio_pin_->pin_mode(gpio::FLAG_INPUT);
|
this->dio_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
this->bit_delay_();
|
this->bit_delay_();
|
||||||
|
|
||||||
// CLK to high
|
// CLK to high
|
||||||
this->clk_pin_->pin_mode(gpio::FLAG_INPUT);
|
this->clk_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
this->bit_delay_();
|
this->bit_delay_();
|
||||||
|
@ -237,8 +267,38 @@ bool TM1637Display::send_byte_(uint8_t b) {
|
||||||
return ack;
|
return ack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t TM1637Display::read_byte_() {
|
||||||
|
uint8_t retval = 0;
|
||||||
|
// Prepare DIO to read data
|
||||||
|
this->dio_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
|
this->bit_delay_();
|
||||||
|
// Data is shifted out by the TM1637 on the CLK falling edge
|
||||||
|
for (uint8_t bit = 0; bit < 8; bit++) {
|
||||||
|
this->clk_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
|
this->bit_delay_();
|
||||||
|
// Read next bit
|
||||||
|
retval <<= 1;
|
||||||
|
if (this->dio_pin_->digital_read()) {
|
||||||
|
retval |= 0x01;
|
||||||
|
}
|
||||||
|
this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
this->bit_delay_();
|
||||||
|
}
|
||||||
|
// Return DIO to output mode
|
||||||
|
// Dummy ACK
|
||||||
|
this->dio_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
this->bit_delay_();
|
||||||
|
this->clk_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
|
this->bit_delay_();
|
||||||
|
this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
this->bit_delay_();
|
||||||
|
this->dio_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
|
this->bit_delay_();
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t TM1637Display::print(uint8_t start_pos, const char *str) {
|
uint8_t TM1637Display::print(uint8_t start_pos, const char *str) {
|
||||||
ESP_LOGV(TAG, "Print at %d: %s", start_pos, str);
|
// ESP_LOGV(TAG, "Print at %d: %s", start_pos, str);
|
||||||
uint8_t pos = start_pos;
|
uint8_t pos = start_pos;
|
||||||
for (; *str != '\0'; str++) {
|
for (; *str != '\0'; str++) {
|
||||||
uint8_t data = TM1637_UNKNOWN_CHAR;
|
uint8_t data = TM1637_UNKNOWN_CHAR;
|
||||||
|
|
|
@ -8,10 +8,17 @@
|
||||||
#include "esphome/components/time/real_time_clock.h"
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace tm1637 {
|
namespace tm1637 {
|
||||||
|
|
||||||
class TM1637Display;
|
class TM1637Display;
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
class TM1637Key;
|
||||||
|
#endif
|
||||||
|
|
||||||
using tm1637_writer_t = std::function<void(TM1637Display &)>;
|
using tm1637_writer_t = std::function<void(TM1637Display &)>;
|
||||||
|
|
||||||
|
@ -46,10 +53,15 @@ class TM1637Display : public PollingComponent {
|
||||||
|
|
||||||
void display();
|
void display();
|
||||||
|
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
void loop() override;
|
||||||
|
uint8_t get_keys();
|
||||||
|
void add_tm1637_key(TM1637Key *tm1637_key) { this->tm1637_keys_.push_back(tm1637_key); }
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USE_TIME
|
#ifdef USE_TIME
|
||||||
/// Evaluate the strftime-format and print the result at the given position.
|
/// Evaluate the strftime-format and print the result at the given position.
|
||||||
uint8_t strftime(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0)));
|
uint8_t strftime(uint8_t pos, const char *format, time::ESPTime time) __attribute__((format(strftime, 3, 0)));
|
||||||
|
|
||||||
/// Evaluate the strftime-format and print the result at position 0.
|
/// Evaluate the strftime-format and print the result at position 0.
|
||||||
uint8_t strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0)));
|
uint8_t strftime(const char *format, time::ESPTime time) __attribute__((format(strftime, 2, 0)));
|
||||||
#endif
|
#endif
|
||||||
|
@ -58,6 +70,7 @@ class TM1637Display : public PollingComponent {
|
||||||
void bit_delay_();
|
void bit_delay_();
|
||||||
void setup_pins_();
|
void setup_pins_();
|
||||||
bool send_byte_(uint8_t b);
|
bool send_byte_(uint8_t b);
|
||||||
|
uint8_t read_byte_();
|
||||||
void start_();
|
void start_();
|
||||||
void stop_();
|
void stop_();
|
||||||
|
|
||||||
|
@ -68,7 +81,23 @@ class TM1637Display : public PollingComponent {
|
||||||
bool inverted_;
|
bool inverted_;
|
||||||
optional<tm1637_writer_t> writer_{};
|
optional<tm1637_writer_t> writer_{};
|
||||||
uint8_t buffer_[6] = {0};
|
uint8_t buffer_[6] = {0};
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
std::vector<TM1637Key *> tm1637_keys_{};
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef USE_BINARY_SENSOR
|
||||||
|
class TM1637Key : public binary_sensor::BinarySensor {
|
||||||
|
friend class TM1637Display;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_keycode(uint8_t key_code) { key_code_ = key_code; }
|
||||||
|
void process(uint8_t data) { this->publish_state(static_cast<bool>(data == this->key_code_)); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t key_code_{0};
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace tm1637
|
} // namespace tm1637
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
Loading…
Reference in a new issue