mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
Add support for TM1638 Led and Key component (#3340)
This commit is contained in:
parent
9ff187c3f8
commit
cbd8d70431
17 changed files with 855 additions and 0 deletions
|
@ -230,6 +230,7 @@ esphome/components/time/* @OttoWinter
|
||||||
esphome/components/tlc5947/* @rnauber
|
esphome/components/tlc5947/* @rnauber
|
||||||
esphome/components/tm1621/* @Philippe12
|
esphome/components/tm1621/* @Philippe12
|
||||||
esphome/components/tm1637/* @glmnet
|
esphome/components/tm1637/* @glmnet
|
||||||
|
esphome/components/tm1638/* @skykingjwc
|
||||||
esphome/components/tmp102/* @timsavage
|
esphome/components/tmp102/* @timsavage
|
||||||
esphome/components/tmp117/* @Azimath
|
esphome/components/tmp117/* @Azimath
|
||||||
esphome/components/tof10120/* @wstrzalka
|
esphome/components/tof10120/* @wstrzalka
|
||||||
|
|
0
esphome/components/tm1638/__init__.py
Normal file
0
esphome/components/tm1638/__init__.py
Normal file
22
esphome/components/tm1638/binary_sensor/__init__.py
Normal file
22
esphome/components/tm1638/binary_sensor/__init__.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import binary_sensor
|
||||||
|
from esphome.const import CONF_KEY
|
||||||
|
from ..display import tm1638_ns, TM1638Component, CONF_TM1638_ID
|
||||||
|
|
||||||
|
TM1638Key = tm1638_ns.class_("TM1638Key", binary_sensor.BinarySensor)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(TM1638Key),
|
||||||
|
cv.GenerateID(CONF_TM1638_ID): cv.use_id(TM1638Component),
|
||||||
|
cv.Required(CONF_KEY): cv.int_range(min=0, max=15),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await binary_sensor.new_binary_sensor(config)
|
||||||
|
cg.add(var.set_keycode(config[CONF_KEY]))
|
||||||
|
hub = await cg.get_variable(config[CONF_TM1638_ID])
|
||||||
|
cg.add(hub.register_listener(var))
|
13
esphome/components/tm1638/binary_sensor/tm1638_key.cpp
Normal file
13
esphome/components/tm1638/binary_sensor/tm1638_key.cpp
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
#include "tm1638_key.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
|
||||||
|
void TM1638Key::keys_update(uint8_t keys) {
|
||||||
|
bool pressed = keys & (1 << key_code_);
|
||||||
|
if (pressed != this->state)
|
||||||
|
this->publish_state(pressed);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
19
esphome/components/tm1638/binary_sensor/tm1638_key.h
Normal file
19
esphome/components/tm1638/binary_sensor/tm1638_key.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||||
|
#include "../tm1638.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
|
||||||
|
class TM1638Key : public binary_sensor::BinarySensor, public KeyListener {
|
||||||
|
public:
|
||||||
|
void set_keycode(uint8_t key_code) { key_code_ = key_code; };
|
||||||
|
void keys_update(uint8_t keys) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t key_code_{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
55
esphome/components/tm1638/display.py
Normal file
55
esphome/components/tm1638/display.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome import pins
|
||||||
|
from esphome.components import display
|
||||||
|
from esphome.const import (
|
||||||
|
CONF_ID,
|
||||||
|
CONF_INTENSITY,
|
||||||
|
CONF_LAMBDA,
|
||||||
|
CONF_CLK_PIN,
|
||||||
|
CONF_DIO_PIN,
|
||||||
|
CONF_STB_PIN,
|
||||||
|
)
|
||||||
|
|
||||||
|
CODEOWNERS = ["@skykingjwc"]
|
||||||
|
|
||||||
|
CONF_TM1638_ID = "tm1638_id"
|
||||||
|
|
||||||
|
tm1638_ns = cg.esphome_ns.namespace("tm1638")
|
||||||
|
TM1638Component = tm1638_ns.class_("TM1638Component", cg.PollingComponent)
|
||||||
|
TM1638ComponentRef = TM1638Component.operator("ref")
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(TM1638Component),
|
||||||
|
cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema,
|
||||||
|
cv.Required(CONF_STB_PIN): pins.gpio_output_pin_schema,
|
||||||
|
cv.Required(CONF_DIO_PIN): pins.gpio_output_pin_schema,
|
||||||
|
cv.Optional(CONF_INTENSITY, default=7): cv.int_range(min=0, max=8),
|
||||||
|
}
|
||||||
|
).extend(cv.polling_component_schema("1s"))
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
await display.register_display(var, config)
|
||||||
|
|
||||||
|
clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN])
|
||||||
|
cg.add(var.set_clk_pin(clk))
|
||||||
|
|
||||||
|
dio = await cg.gpio_pin_expression(config[CONF_DIO_PIN])
|
||||||
|
cg.add(var.set_dio_pin(dio))
|
||||||
|
|
||||||
|
stb = await cg.gpio_pin_expression(config[CONF_STB_PIN])
|
||||||
|
cg.add(var.set_stb_pin(stb))
|
||||||
|
|
||||||
|
cg.add(var.set_intensity(config[CONF_INTENSITY]))
|
||||||
|
|
||||||
|
if CONF_LAMBDA in config:
|
||||||
|
lambda_ = await cg.process_lambda(
|
||||||
|
config[CONF_LAMBDA], [(TM1638ComponentRef, "it")], return_type=cg.void
|
||||||
|
)
|
||||||
|
|
||||||
|
cg.add(var.set_writer(lambda_))
|
25
esphome/components/tm1638/output/__init__.py
Normal file
25
esphome/components/tm1638/output/__init__.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import output
|
||||||
|
from esphome.const import CONF_ID, CONF_LED
|
||||||
|
from ..display import tm1638_ns, TM1638Component, CONF_TM1638_ID
|
||||||
|
|
||||||
|
TM1638OutputLed = tm1638_ns.class_("TM1638OutputLed", output.BinaryOutput, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = output.BINARY_OUTPUT_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(TM1638OutputLed),
|
||||||
|
cv.GenerateID(CONF_TM1638_ID): cv.use_id(TM1638Component),
|
||||||
|
cv.Required(CONF_LED): cv.int_range(min=0, max=7),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await output.register_output(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
cg.add(var.set_lednum(config[CONF_LED]))
|
||||||
|
hub = await cg.get_variable(config[CONF_TM1638_ID])
|
||||||
|
cg.add(var.set_tm1638(hub))
|
17
esphome/components/tm1638/output/tm1638_output_led.cpp
Normal file
17
esphome/components/tm1638/output/tm1638_output_led.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include "tm1638_output_led.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
|
||||||
|
static const char *const TAG = "tm1638.led";
|
||||||
|
|
||||||
|
void TM1638OutputLed::write_state(bool state) { tm1638_->set_led(led_, state); }
|
||||||
|
|
||||||
|
void TM1638OutputLed::dump_config() {
|
||||||
|
LOG_BINARY_OUTPUT(this);
|
||||||
|
ESP_LOGCONFIG(TAG, " LED: %d", led_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
25
esphome/components/tm1638/output/tm1638_output_led.h
Normal file
25
esphome/components/tm1638/output/tm1638_output_led.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/output/binary_output.h"
|
||||||
|
#include "../tm1638.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
|
||||||
|
class TM1638OutputLed : public output::BinaryOutput, public Component {
|
||||||
|
public:
|
||||||
|
void dump_config() override;
|
||||||
|
|
||||||
|
void set_tm1638(TM1638Component *tm1638) { tm1638_ = tm1638; }
|
||||||
|
void set_lednum(int led) { led_ = led; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool state) override;
|
||||||
|
|
||||||
|
TM1638Component *tm1638_;
|
||||||
|
int led_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
107
esphome/components/tm1638/sevenseg.h
Normal file
107
esphome/components/tm1638/sevenseg.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
namespace TM1638Translation {
|
||||||
|
|
||||||
|
const unsigned char SEVEN_SEG[] PROGMEM = {
|
||||||
|
0x00, /* (space) */
|
||||||
|
0x86, /* ! */
|
||||||
|
0x22, /* " */
|
||||||
|
0x7E, /* # */
|
||||||
|
0x6D, /* $ */
|
||||||
|
0xD2, /* % */
|
||||||
|
0x46, /* & */
|
||||||
|
0x20, /* ' */
|
||||||
|
0x29, /* ( */
|
||||||
|
0x0B, /* ) */
|
||||||
|
0x21, /* * */
|
||||||
|
0x70, /* + */
|
||||||
|
0x10, /* , */
|
||||||
|
0x40, /* - */
|
||||||
|
0x80, /* . */
|
||||||
|
0x52, /* / */
|
||||||
|
0x3F, /* 0 */
|
||||||
|
0x06, /* 1 */
|
||||||
|
0x5B, /* 2 */
|
||||||
|
0x4F, /* 3 */
|
||||||
|
0x66, /* 4 */
|
||||||
|
0x6D, /* 5 */
|
||||||
|
0x7D, /* 6 */
|
||||||
|
0x07, /* 7 */
|
||||||
|
0x7F, /* 8 */
|
||||||
|
0x6F, /* 9 */
|
||||||
|
0x09, /* : */
|
||||||
|
0x0D, /* ; */
|
||||||
|
0x61, /* < */
|
||||||
|
0x48, /* = */
|
||||||
|
0x43, /* > */
|
||||||
|
0xD3, /* ? */
|
||||||
|
0x5F, /* @ */
|
||||||
|
0x77, /* A */
|
||||||
|
0x7C, /* B */
|
||||||
|
0x39, /* C */
|
||||||
|
0x5E, /* D */
|
||||||
|
0x79, /* E */
|
||||||
|
0x71, /* F */
|
||||||
|
0x3D, /* G */
|
||||||
|
0x76, /* H */
|
||||||
|
0x30, /* I */
|
||||||
|
0x1E, /* J */
|
||||||
|
0x75, /* K */
|
||||||
|
0x38, /* L */
|
||||||
|
0x15, /* M */
|
||||||
|
0x37, /* N */
|
||||||
|
0x3F, /* O */
|
||||||
|
0x73, /* P */
|
||||||
|
0x6B, /* Q */
|
||||||
|
0x33, /* R */
|
||||||
|
0x6D, /* S */
|
||||||
|
0x78, /* T */
|
||||||
|
0x3E, /* U */
|
||||||
|
0x3E, /* V */
|
||||||
|
0x2A, /* W */
|
||||||
|
0x76, /* X */
|
||||||
|
0x6E, /* Y */
|
||||||
|
0x5B, /* Z */
|
||||||
|
0x39, /* [ */
|
||||||
|
0x64, /* \ */
|
||||||
|
0x0F, /* ] */
|
||||||
|
0x23, /* ^ */
|
||||||
|
0x08, /* _ */
|
||||||
|
0x02, /* ` */
|
||||||
|
0x5F, /* a */
|
||||||
|
0x7C, /* b */
|
||||||
|
0x58, /* c */
|
||||||
|
0x5E, /* d */
|
||||||
|
0x7B, /* e */
|
||||||
|
0x71, /* f */
|
||||||
|
0x6F, /* g */
|
||||||
|
0x74, /* h */
|
||||||
|
0x10, /* i */
|
||||||
|
0x0C, /* j */
|
||||||
|
0x75, /* k */
|
||||||
|
0x30, /* l */
|
||||||
|
0x14, /* m */
|
||||||
|
0x54, /* n */
|
||||||
|
0x5C, /* o */
|
||||||
|
0x73, /* p */
|
||||||
|
0x67, /* q */
|
||||||
|
0x50, /* r */
|
||||||
|
0x6D, /* s */
|
||||||
|
0x78, /* t */
|
||||||
|
0x1C, /* u */
|
||||||
|
0x1C, /* v */
|
||||||
|
0x14, /* w */
|
||||||
|
0x76, /* x */
|
||||||
|
0x6E, /* y */
|
||||||
|
0x5B, /* z */
|
||||||
|
0x46, /* { */
|
||||||
|
0x30, /* | */
|
||||||
|
0x70, /* } */
|
||||||
|
0x01, /* ~ */
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace TM1638Translation
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
24
esphome/components/tm1638/switch/__init__.py
Normal file
24
esphome/components/tm1638/switch/__init__.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import switch
|
||||||
|
from esphome.const import CONF_LED
|
||||||
|
from ..display import tm1638_ns, TM1638Component, CONF_TM1638_ID
|
||||||
|
|
||||||
|
TM1638SwitchLed = tm1638_ns.class_("TM1638SwitchLed", switch.Switch, cg.Component)
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = switch.SWITCH_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(TM1638SwitchLed),
|
||||||
|
cv.GenerateID(CONF_TM1638_ID): cv.use_id(TM1638Component),
|
||||||
|
cv.Required(CONF_LED): cv.int_range(min=0, max=7),
|
||||||
|
}
|
||||||
|
).extend(cv.COMPONENT_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = await switch.new_switch(config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
cg.add(var.set_lednum(config[CONF_LED]))
|
||||||
|
hub = await cg.get_variable(config[CONF_TM1638_ID])
|
||||||
|
cg.add(var.set_tm1638(hub))
|
20
esphome/components/tm1638/switch/tm1638_switch_led.cpp
Normal file
20
esphome/components/tm1638/switch/tm1638_switch_led.cpp
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include "tm1638_switch_led.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
|
||||||
|
static const char *const TAG = "tm1638.led";
|
||||||
|
|
||||||
|
void TM1638SwitchLed::write_state(bool state) {
|
||||||
|
tm1638_->set_led(led_, state);
|
||||||
|
publish_state(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638SwitchLed::dump_config() {
|
||||||
|
LOG_SWITCH("", "TM1638 LED", this);
|
||||||
|
ESP_LOGCONFIG(TAG, " LED: %d", led_);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
23
esphome/components/tm1638/switch/tm1638_switch_led.h
Normal file
23
esphome/components/tm1638/switch/tm1638_switch_led.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#include "../tm1638.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
|
||||||
|
class TM1638SwitchLed : public switch_::Switch, public Component {
|
||||||
|
public:
|
||||||
|
void dump_config() override;
|
||||||
|
|
||||||
|
void set_tm1638(TM1638Component *tm1638) { tm1638_ = tm1638; }
|
||||||
|
void set_lednum(int led) { led_ = led; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool state) override;
|
||||||
|
TM1638Component *tm1638_;
|
||||||
|
int led_;
|
||||||
|
};
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
288
esphome/components/tm1638/tm1638.cpp
Normal file
288
esphome/components/tm1638/tm1638.cpp
Normal file
|
@ -0,0 +1,288 @@
|
||||||
|
#include "tm1638.h"
|
||||||
|
#include "sevenseg.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
|
||||||
|
static const char *const TAG = "display.tm1638";
|
||||||
|
static const uint8_t TM1638_REGISTER_FIXEDADDRESS = 0x44;
|
||||||
|
static const uint8_t TM1638_REGISTER_AUTOADDRESS = 0x40;
|
||||||
|
static const uint8_t TM1638_REGISTER_READBUTTONS = 0x42;
|
||||||
|
static const uint8_t TM1638_REGISTER_DISPLAYOFF = 0x80;
|
||||||
|
static const uint8_t TM1638_REGISTER_DISPLAYON = 0x88;
|
||||||
|
static const uint8_t TM1638_REGISTER_7SEG_0 = 0xC0;
|
||||||
|
static const uint8_t TM1638_REGISTER_LED_0 = 0xC1;
|
||||||
|
static const uint8_t TM1638_UNKNOWN_CHAR = 0b11111111;
|
||||||
|
|
||||||
|
static const uint8_t TM1638_SHIFT_DELAY = 4; // clock pause between commands, default 4ms
|
||||||
|
|
||||||
|
void TM1638Component::setup() {
|
||||||
|
ESP_LOGD(TAG, "Setting up TM1638...");
|
||||||
|
|
||||||
|
this->clk_pin_->setup(); // OUTPUT
|
||||||
|
this->dio_pin_->setup(); // OUTPUT
|
||||||
|
this->stb_pin_->setup(); // OUTPUT
|
||||||
|
|
||||||
|
this->clk_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
this->dio_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
this->stb_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
|
||||||
|
this->clk_pin_->digital_write(false);
|
||||||
|
this->dio_pin_->digital_write(false);
|
||||||
|
this->stb_pin_->digital_write(false);
|
||||||
|
|
||||||
|
this->set_intensity(intensity_);
|
||||||
|
|
||||||
|
this->reset_(); // all LEDs off
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 8; i++) // zero fill print buffer
|
||||||
|
this->buffer_[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, "TM1638:");
|
||||||
|
ESP_LOGCONFIG(TAG, " Intensity: %u", this->intensity_);
|
||||||
|
LOG_PIN(" CLK Pin: ", this->clk_pin_);
|
||||||
|
LOG_PIN(" DIO Pin: ", this->dio_pin_);
|
||||||
|
LOG_PIN(" STB Pin: ", this->stb_pin_);
|
||||||
|
LOG_UPDATE_INTERVAL(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::loop() {
|
||||||
|
if (this->listeners_.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t keys = this->get_keys();
|
||||||
|
for (auto &listener : this->listeners_)
|
||||||
|
listener->keys_update(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TM1638Component::get_keys() {
|
||||||
|
uint8_t buttons = 0;
|
||||||
|
|
||||||
|
this->stb_pin_->digital_write(false);
|
||||||
|
|
||||||
|
this->shift_out_(TM1638_REGISTER_READBUTTONS);
|
||||||
|
|
||||||
|
this->dio_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
|
|
||||||
|
delayMicroseconds(10);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 4; i++) { // read the 4 button registers
|
||||||
|
uint8_t v = this->shift_in_();
|
||||||
|
buttons |= v << i; // shift bits to correct slots in the byte
|
||||||
|
}
|
||||||
|
|
||||||
|
this->dio_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
|
||||||
|
this->stb_pin_->digital_write(true);
|
||||||
|
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::update() { // this is called at the interval specified in the config.yaml
|
||||||
|
if (this->writer_.has_value()) {
|
||||||
|
(*this->writer_)(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->display();
|
||||||
|
}
|
||||||
|
|
||||||
|
float TM1638Component::get_setup_priority() const { return setup_priority::PROCESSOR; }
|
||||||
|
|
||||||
|
void TM1638Component::display() {
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
this->set_7seg_(i, buffer_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::reset_() {
|
||||||
|
uint8_t num_commands = 16; // 16 addresses, 8 for 7seg and 8 for LEDs
|
||||||
|
uint8_t commands[num_commands];
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < num_commands; i++) {
|
||||||
|
commands[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->send_command_sequence_(commands, num_commands, TM1638_REGISTER_7SEG_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////// LEDs /////////////////
|
||||||
|
|
||||||
|
void TM1638Component::set_led(int led_pos, bool led_on_off) {
|
||||||
|
this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
|
||||||
|
|
||||||
|
uint8_t commands[2];
|
||||||
|
|
||||||
|
commands[0] = TM1638_REGISTER_LED_0 + (led_pos << 1);
|
||||||
|
commands[1] = led_on_off;
|
||||||
|
|
||||||
|
this->send_commands_(commands, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::set_7seg_(int seg_pos, uint8_t seg_bits) {
|
||||||
|
this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
|
||||||
|
|
||||||
|
uint8_t commands[2] = {};
|
||||||
|
|
||||||
|
commands[0] = TM1638_REGISTER_7SEG_0 + (seg_pos << 1);
|
||||||
|
commands[1] = seg_bits;
|
||||||
|
|
||||||
|
this->send_commands_(commands, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::set_intensity(uint8_t brightness_level) {
|
||||||
|
this->intensity_ = brightness_level;
|
||||||
|
|
||||||
|
this->send_command_(TM1638_REGISTER_FIXEDADDRESS);
|
||||||
|
|
||||||
|
if (brightness_level > 0) {
|
||||||
|
this->send_command_((uint8_t)(TM1638_REGISTER_DISPLAYON | intensity_));
|
||||||
|
} else {
|
||||||
|
this->send_command_(TM1638_REGISTER_DISPLAYOFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////// DISPLAY PRINT /////////////////
|
||||||
|
|
||||||
|
uint8_t TM1638Component::print(uint8_t start_pos, const char *str) {
|
||||||
|
uint8_t pos = start_pos;
|
||||||
|
|
||||||
|
bool last_was_dot = false;
|
||||||
|
|
||||||
|
for (; *str != '\0'; str++) {
|
||||||
|
uint8_t data = TM1638_UNKNOWN_CHAR;
|
||||||
|
|
||||||
|
if (*str >= ' ' && *str <= '~') {
|
||||||
|
data = progmem_read_byte(&TM1638Translation::SEVEN_SEG[*str - 32]); // subract 32 to account for ASCII offset
|
||||||
|
} else if (data == TM1638_UNKNOWN_CHAR) {
|
||||||
|
ESP_LOGW(TAG, "Encountered character '%c' with no TM1638 representation while translating string!", *str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*str == '.') // handle dots
|
||||||
|
{
|
||||||
|
if (pos != start_pos &&
|
||||||
|
!last_was_dot) // if we are not at the first position, backup by one unless last char was a dot
|
||||||
|
{
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
this->buffer_[pos] |= 0b10000000; // turn on the dot on the previous position
|
||||||
|
last_was_dot = true; // set a bit in case the next chracter is also a dot
|
||||||
|
} else // if not a dot, then just write the character to display
|
||||||
|
{
|
||||||
|
if (pos >= 8) {
|
||||||
|
ESP_LOGI(TAG, "TM1638 String is too long for the display!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->buffer_[pos] = data;
|
||||||
|
last_was_dot = false; // clear dot tracking bit
|
||||||
|
}
|
||||||
|
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return pos - start_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////// PRINT /////////////////
|
||||||
|
|
||||||
|
uint8_t TM1638Component::print(const char *str) { return this->print(0, str); }
|
||||||
|
|
||||||
|
uint8_t TM1638Component::printf(uint8_t pos, const char *format, ...) {
|
||||||
|
va_list arg;
|
||||||
|
va_start(arg, format);
|
||||||
|
char buffer[64];
|
||||||
|
int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
|
||||||
|
va_end(arg);
|
||||||
|
if (ret > 0)
|
||||||
|
return this->print(pos, buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint8_t TM1638Component::printf(const char *format, ...) {
|
||||||
|
va_list arg;
|
||||||
|
va_start(arg, format);
|
||||||
|
char buffer[64];
|
||||||
|
int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
|
||||||
|
va_end(arg);
|
||||||
|
if (ret > 0)
|
||||||
|
return this->print(buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_TIME
|
||||||
|
uint8_t TM1638Component::strftime(uint8_t pos, const char *format, time::ESPTime time) {
|
||||||
|
char buffer[64];
|
||||||
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
|
if (ret > 0)
|
||||||
|
return this->print(pos, buffer);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint8_t TM1638Component::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////// SPI ////////////////
|
||||||
|
|
||||||
|
void TM1638Component::send_command_(uint8_t value) {
|
||||||
|
this->stb_pin_->pin_mode(gpio::FLAG_OUTPUT);
|
||||||
|
this->stb_pin_->digital_write(false);
|
||||||
|
this->shift_out_(value);
|
||||||
|
this->stb_pin_->digital_write(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::send_commands_(uint8_t const commands[], uint8_t num_commands) {
|
||||||
|
this->stb_pin_->digital_write(false);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < num_commands; i++) {
|
||||||
|
uint8_t command = commands[i];
|
||||||
|
this->shift_out_(command);
|
||||||
|
}
|
||||||
|
this->stb_pin_->digital_write(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::send_command_leave_open_(uint8_t value) {
|
||||||
|
this->stb_pin_->digital_write(false);
|
||||||
|
this->shift_out_(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::send_command_sequence_(uint8_t commands[], uint8_t num_commands, uint8_t starting_address) {
|
||||||
|
this->send_command_(TM1638_REGISTER_AUTOADDRESS);
|
||||||
|
this->send_command_leave_open_(starting_address);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < num_commands; i++) {
|
||||||
|
this->shift_out_(commands[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->stb_pin_->digital_write(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TM1638Component::shift_in_() {
|
||||||
|
uint8_t value = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
value |= dio_pin_->digital_read() << i;
|
||||||
|
delayMicroseconds(TM1638_SHIFT_DELAY);
|
||||||
|
this->clk_pin_->digital_write(true);
|
||||||
|
delayMicroseconds(TM1638_SHIFT_DELAY);
|
||||||
|
this->clk_pin_->digital_write(false);
|
||||||
|
delayMicroseconds(TM1638_SHIFT_DELAY);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TM1638Component::shift_out_(uint8_t val) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
this->dio_pin_->digital_write((val & (1 << i)));
|
||||||
|
delayMicroseconds(TM1638_SHIFT_DELAY);
|
||||||
|
|
||||||
|
this->clk_pin_->digital_write(true);
|
||||||
|
delayMicroseconds(TM1638_SHIFT_DELAY);
|
||||||
|
|
||||||
|
this->clk_pin_->digital_write(false);
|
||||||
|
delayMicroseconds(TM1638_SHIFT_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
81
esphome/components/tm1638/tm1638.h
Normal file
81
esphome/components/tm1638/tm1638.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/defines.h"
|
||||||
|
#include "esphome/core/automation.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
|
||||||
|
#ifdef USE_TIME
|
||||||
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace tm1638 {
|
||||||
|
|
||||||
|
class KeyListener {
|
||||||
|
public:
|
||||||
|
virtual void keys_update(uint8_t keys){};
|
||||||
|
};
|
||||||
|
|
||||||
|
class TM1638Component;
|
||||||
|
|
||||||
|
using tm1638_writer_t = std::function<void(TM1638Component &)>;
|
||||||
|
|
||||||
|
class TM1638Component : public PollingComponent {
|
||||||
|
public:
|
||||||
|
void set_writer(tm1638_writer_t &&writer) { this->writer_ = writer; }
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
void update() override;
|
||||||
|
float get_setup_priority() const override;
|
||||||
|
void set_intensity(uint8_t brightness_level);
|
||||||
|
void display();
|
||||||
|
|
||||||
|
void set_clk_pin(GPIOPin *pin) { this->clk_pin_ = pin; }
|
||||||
|
void set_dio_pin(GPIOPin *pin) { this->dio_pin_ = pin; }
|
||||||
|
void set_stb_pin(GPIOPin *pin) { this->stb_pin_ = pin; }
|
||||||
|
|
||||||
|
void register_listener(KeyListener *listener) { this->listeners_.push_back(listener); }
|
||||||
|
|
||||||
|
/// Evaluate the printf-format and print the result at the given position.
|
||||||
|
uint8_t printf(uint8_t pos, const char *format, ...) __attribute__((format(printf, 3, 4)));
|
||||||
|
/// Evaluate the printf-format and print the result at position 0.
|
||||||
|
uint8_t printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
|
|
||||||
|
/// Print `str` at the given position.
|
||||||
|
uint8_t print(uint8_t pos, const char *str);
|
||||||
|
/// Print `str` at position 0.
|
||||||
|
uint8_t print(const char *str);
|
||||||
|
|
||||||
|
void loop() override;
|
||||||
|
uint8_t get_keys();
|
||||||
|
|
||||||
|
#ifdef USE_TIME
|
||||||
|
/// 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)));
|
||||||
|
/// 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)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void set_led(int led_pos, bool led_on_off);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void set_7seg_(int seg_pos, uint8_t seg_bits);
|
||||||
|
void send_command_(uint8_t value);
|
||||||
|
void send_command_leave_open_(uint8_t value);
|
||||||
|
void send_commands_(uint8_t const commands[], uint8_t num_commands);
|
||||||
|
void send_command_sequence_(uint8_t commands[], uint8_t num_commands, uint8_t starting_address);
|
||||||
|
void shift_out_(uint8_t value);
|
||||||
|
void reset_();
|
||||||
|
uint8_t shift_in_();
|
||||||
|
uint8_t intensity_{}; /// brghtness of the display 0 through 7
|
||||||
|
GPIOPin *clk_pin_;
|
||||||
|
GPIOPin *stb_pin_;
|
||||||
|
GPIOPin *dio_pin_;
|
||||||
|
uint8_t *buffer_ = new uint8_t[8];
|
||||||
|
optional<tm1638_writer_t> writer_{};
|
||||||
|
std::vector<KeyListener *> listeners_{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tm1638
|
||||||
|
} // namespace esphome
|
|
@ -334,6 +334,7 @@ CONF_LAMBDA = "lambda"
|
||||||
CONF_LAST_CONFIDENCE = "last_confidence"
|
CONF_LAST_CONFIDENCE = "last_confidence"
|
||||||
CONF_LAST_FINGER_ID = "last_finger_id"
|
CONF_LAST_FINGER_ID = "last_finger_id"
|
||||||
CONF_LATITUDE = "latitude"
|
CONF_LATITUDE = "latitude"
|
||||||
|
CONF_LED = "led"
|
||||||
CONF_LEGEND = "legend"
|
CONF_LEGEND = "legend"
|
||||||
CONF_LENGTH = "length"
|
CONF_LENGTH = "length"
|
||||||
CONF_LEVEL = "level"
|
CONF_LEVEL = "level"
|
||||||
|
@ -653,6 +654,7 @@ CONF_STATE_CLASS = "state_class"
|
||||||
CONF_STATE_TOPIC = "state_topic"
|
CONF_STATE_TOPIC = "state_topic"
|
||||||
CONF_STATIC_IP = "static_ip"
|
CONF_STATIC_IP = "static_ip"
|
||||||
CONF_STATUS = "status"
|
CONF_STATUS = "status"
|
||||||
|
CONF_STB_PIN = "stb_pin"
|
||||||
CONF_STEP = "step"
|
CONF_STEP = "step"
|
||||||
CONF_STEP_MODE = "step_mode"
|
CONF_STEP_MODE = "step_mode"
|
||||||
CONF_STEP_PIN = "step_pin"
|
CONF_STEP_PIN = "step_pin"
|
||||||
|
|
133
tests/test5.yaml
133
tests/test5.yaml
|
@ -80,6 +80,91 @@ binary_sensor:
|
||||||
bitmask: 0x80 # (bit 8)
|
bitmask: 0x80 # (bit 8)
|
||||||
lambda: "return x;"
|
lambda: "return x;"
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Button0
|
||||||
|
key: 0
|
||||||
|
filters:
|
||||||
|
- delayed_on: 10ms
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- switch.turn_on: Led0
|
||||||
|
on_release:
|
||||||
|
then:
|
||||||
|
- switch.turn_off: Led0
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Button1
|
||||||
|
key: 1
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- switch.turn_on: Led1
|
||||||
|
on_release:
|
||||||
|
then:
|
||||||
|
- switch.turn_off: Led1
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Button2
|
||||||
|
key: 2
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- switch.turn_on: Led2
|
||||||
|
on_release:
|
||||||
|
then:
|
||||||
|
- switch.turn_off: Led2
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Button3
|
||||||
|
key: 3
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- switch.turn_on: Led3
|
||||||
|
on_release:
|
||||||
|
then:
|
||||||
|
- switch.turn_off: Led3
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Button4
|
||||||
|
key: 4
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- output.turn_on: Led4
|
||||||
|
on_release:
|
||||||
|
then:
|
||||||
|
- output.turn_off: Led4
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Button5
|
||||||
|
key: 5
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- output.turn_on: Led5
|
||||||
|
on_release:
|
||||||
|
then:
|
||||||
|
- output.turn_off: Led5
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Button6
|
||||||
|
key: 6
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- output.turn_on: Led6
|
||||||
|
on_release:
|
||||||
|
then:
|
||||||
|
- output.turn_off: Led6
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Button7
|
||||||
|
key: 7
|
||||||
|
on_press:
|
||||||
|
then:
|
||||||
|
- output.turn_on: Led7
|
||||||
|
on_release:
|
||||||
|
then:
|
||||||
|
- output.turn_off: Led7
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
tlc5947:
|
tlc5947:
|
||||||
data_pin: GPIO12
|
data_pin: GPIO12
|
||||||
clock_pin: GPIO14
|
clock_pin: GPIO14
|
||||||
|
@ -106,6 +191,22 @@ output:
|
||||||
address: 0x9001
|
address: 0x9001
|
||||||
value_type: U_WORD
|
value_type: U_WORD
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Led4
|
||||||
|
led: 4
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Led5
|
||||||
|
led: 5
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Led6
|
||||||
|
led: 6
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Led7
|
||||||
|
led: 7
|
||||||
|
|
||||||
demo:
|
demo:
|
||||||
|
|
||||||
esp32_ble:
|
esp32_ble:
|
||||||
|
@ -354,3 +455,35 @@ switch:
|
||||||
register_type: coil
|
register_type: coil
|
||||||
address: 2
|
address: 2
|
||||||
bitmask: 1
|
bitmask: 1
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Led0
|
||||||
|
led: 0
|
||||||
|
name: TM1638Led0
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Led1
|
||||||
|
led: 1
|
||||||
|
name: TM1638Led1
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Led2
|
||||||
|
led: 2
|
||||||
|
name: TM1638Led2
|
||||||
|
|
||||||
|
- platform: tm1638
|
||||||
|
id: Led3
|
||||||
|
led: 3
|
||||||
|
name: TM1638Led3
|
||||||
|
|
||||||
|
display:
|
||||||
|
- platform: tm1638
|
||||||
|
id: primarydisplay
|
||||||
|
stb_pin: 5 #TM1638 STB
|
||||||
|
clk_pin: 18 #TM1638 CLK
|
||||||
|
dio_pin: 23 #TM1638 DIO
|
||||||
|
update_interval: 5s
|
||||||
|
intensity: 5
|
||||||
|
lambda: |-
|
||||||
|
it.print("81818181");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue