Compare commits
No commits in common. "main" and "temp2" have entirely different histories.
9 changed files with 247 additions and 725 deletions
20
Readme.md
20
Readme.md
|
@ -6,24 +6,14 @@ by SN74HC595 shift registers.
|
||||||
## Hardware
|
## Hardware
|
||||||
Connect the shift registers like this, or adapt the pin config as needed:
|
Connect the shift registers like this, or adapt the pin config as needed:
|
||||||
|
|
||||||
- Data input (DIO) to ESP:
|
- Data input (DIO) to ESP GPIO19
|
||||||
- GPIO23 (first display),
|
- Shift clock input (SCK) to ESP GPIO18
|
||||||
- GPIO19 (second display),
|
- Latch / register clock input (RCK) to ESP GPIO5
|
||||||
- GPIO22 (third display),
|
|
||||||
- GPIO21 (fourth display)
|
|
||||||
- Shift clock input (SCK) to ESP GPIO18 (all displays)
|
|
||||||
- Latch / register clock input (RCK) to ESP GPIO5 (all display)
|
|
||||||
|
|
||||||
Keep in mind that the ESP32 is a 3.3V device when connecting to a 5V display. The shift registers should handle the 3.3V
|
Keep in mind that the ESP32 is a 3.3V device when connecting to a 5V display.
|
||||||
signals from the ESP, annd in some cases, 3.3V can also be used to power the displays at a lower brightness.
|
|
||||||
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
> Note: the QSPI driver in esphome is (as of 2024-01-28) not yet in the released package.
|
|
||||||
> Install a suitable version directly from github with:
|
|
||||||
> `pip install "esphome @ git+https://github.com/esphome/esphome@1fef769496ed89c0062d8e70f5964b8318ba4550"`
|
|
||||||
|
|
||||||
Set the board type in the YAML (default should also work on most ESP32 devices)
|
Set the board type in the YAML (default should also work on most ESP32 devices)
|
||||||
Adapt the config as needed for the fallback AP and if wanted, api key.
|
Adapt the config as needed for the fallback AP and if wanted, api key.
|
||||||
Create a `secrets.yaml` containing this:
|
Create a `secrets.yaml` containing this:
|
||||||
|
@ -45,4 +35,4 @@ The driver in `components/` is directly based on the existing MAX7219 driver in
|
||||||
subject to the GPLv3 and MIT licenses, as outlined in the LICENSE document (also copied from ESPHome).
|
subject to the GPLv3 and MIT licenses, as outlined in the LICENSE document (also copied from ESPHome).
|
||||||
|
|
||||||
## Open Issues
|
## Open Issues
|
||||||
|
The actual segment mapping is not tested well, due to missing hardware.
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
import esphome.codegen as cg
|
|
||||||
import esphome.config_validation as cv
|
|
||||||
from esphome.components import display, spi
|
|
||||||
from esphome.const import CONF_ID, CONF_INTENSITY, CONF_LAMBDA, CONF_NUM_CHIPS
|
|
||||||
|
|
||||||
DEPENDENCIES = ["spi"]
|
|
||||||
|
|
||||||
qspi_74hc595_4x_display_ns = cg.esphome_ns.namespace("qspi_74hc595_4x_display")
|
|
||||||
QSPI_74HC595_4X_DISPLAYComponent = qspi_74hc595_4x_display_ns.class_(
|
|
||||||
"QSPI_74HC595_4X_DISPLAYComponent", cg.PollingComponent, spi.SPIDevice
|
|
||||||
)
|
|
||||||
QSPI_74HC595_4X_DISPLAYComponentRef = QSPI_74HC595_4X_DISPLAYComponent.operator("ref")
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
|
||||||
display.BASIC_DISPLAY_SCHEMA.extend(
|
|
||||||
{
|
|
||||||
cv.GenerateID(): cv.declare_id(QSPI_74HC595_4X_DISPLAYComponent),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.extend(cv.polling_component_schema("1s"))
|
|
||||||
.extend(spi.spi_device_schema(quad=True))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
|
||||||
await spi.register_spi_device(var, config)
|
|
||||||
await display.register_display(var, config)
|
|
||||||
|
|
||||||
if CONF_LAMBDA in config:
|
|
||||||
lambda_ = await cg.process_lambda(
|
|
||||||
config[CONF_LAMBDA], [(QSPI_74HC595_4X_DISPLAYComponentRef, "it")], return_type=cg.void
|
|
||||||
)
|
|
||||||
cg.add(var.set_writer(lambda_))
|
|
|
@ -1,265 +0,0 @@
|
||||||
#include "qspi_74hc595_4x_display.h"
|
|
||||||
#include "esphome/core/hal.h"
|
|
||||||
#include "esphome/core/helpers.h"
|
|
||||||
#include "esphome/core/log.h"
|
|
||||||
|
|
||||||
namespace esphome
|
|
||||||
{
|
|
||||||
namespace qspi_74hc595_4x_display
|
|
||||||
{
|
|
||||||
|
|
||||||
static const char *const TAG = "qspi_74hc595_4x_display";
|
|
||||||
|
|
||||||
static const uint32_t QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR = 0x11111111;
|
|
||||||
|
|
||||||
static const uint32_t QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW[95] = {
|
|
||||||
// BADCFE.G
|
|
||||||
// 0xBADCFE.G
|
|
||||||
0x00000000, // ' ', ord 0x20
|
|
||||||
0x10010010, // '!', ord 0x21
|
|
||||||
0x10001000, // '"', ord 0x22
|
|
||||||
0x10011100, // '#', ord 0x23
|
|
||||||
0x01111000, // '$', ord 0x24
|
|
||||||
0x01100001, // '%', ord 0x25
|
|
||||||
0x11100100, // '&', ord 0x26
|
|
||||||
0x00001000, // ''', ord 0x27
|
|
||||||
0x01101100, // '(', ord 0x28
|
|
||||||
0x11110000, // ')', ord 0x29
|
|
||||||
0x01000000, // '*', ord 0x2A
|
|
||||||
0x00000100, // '+', ord 0x2B
|
|
||||||
0x00010000, // ',', ord 0x2C
|
|
||||||
0x00000001, // '-', ord 0x2D
|
|
||||||
0x00000010, // '.', ord 0x2E
|
|
||||||
0x10000101, // '/', ord 0x2F
|
|
||||||
0x11111100, // '0', ord 0x30
|
|
||||||
0x10010000, // '1', ord 0x31
|
|
||||||
0x11100101, // '2', ord 0x32
|
|
||||||
0x11110001, // '3', ord 0x33
|
|
||||||
0x10011001, // '4', ord 0x34
|
|
||||||
0x01111001, // '5', ord 0x35
|
|
||||||
0x01111101, // '6', ord 0x36
|
|
||||||
0x11010000, // '7', ord 0x37
|
|
||||||
0x11111101, // '8', ord 0x38
|
|
||||||
0x11111001, // '9', ord 0x39
|
|
||||||
0x01100000, // ':', ord 0x3A
|
|
||||||
0x01110000, // ';', ord 0x3B
|
|
||||||
0x00100100, // '<', ord 0x3C
|
|
||||||
0x00100001, // '=', ord 0x3D
|
|
||||||
0x00110000, // '>', ord 0x3E
|
|
||||||
0x11000101, // '?', ord 0x3F
|
|
||||||
0x11101101, // '@', ord 0x40
|
|
||||||
0x11011101, // 'A', ord 0x41
|
|
||||||
0x00111101, // 'B', ord 0x42
|
|
||||||
0x01101100, // 'C', ord 0x43
|
|
||||||
0x10110101, // 'D', ord 0x44
|
|
||||||
0x01101101, // 'E', ord 0x45
|
|
||||||
0x01001101, // 'F', ord 0x46
|
|
||||||
0x01111100, // 'G', ord 0x47
|
|
||||||
0x10011101, // 'H', ord 0x48
|
|
||||||
0x10010000, // 'I', ord 0x49
|
|
||||||
0x10110100, // 'J', ord 0x4A
|
|
||||||
QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR, // 'K', ord 0x4B
|
|
||||||
0x00101100, // 'L', ord 0x4C
|
|
||||||
0x11011100, // 'M', ord 0x4D
|
|
||||||
0x00010101, // 'N', ord 0x4E
|
|
||||||
0x11111100, // 'O', ord 0x4F
|
|
||||||
0x11001101, // 'P', ord 0x50
|
|
||||||
0x11111110, // 'Q', ord 0x51
|
|
||||||
0x00000101, // 'R', ord 0x52
|
|
||||||
0x01111001, // 'S', ord 0x53
|
|
||||||
0x00001101, // 'T', ord 0x54
|
|
||||||
0x10111100, // 'U', ord 0x55
|
|
||||||
0x10111100, // 'V', ord 0x56
|
|
||||||
0x10111101, // 'W', ord 0x57
|
|
||||||
QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR, // 'X', ord 0x58
|
|
||||||
0x10001101, // 'Y', ord 0x59
|
|
||||||
0x11100101, // 'Z', ord 0x5A
|
|
||||||
0x01101100, // '[', ord 0x5B
|
|
||||||
0x00011001, // '\', ord 0x5C
|
|
||||||
0x11110000, // ']', ord 0x5D
|
|
||||||
0x11001000, // '^', ord 0x5E
|
|
||||||
0x00100000, // '_', ord 0x5F
|
|
||||||
0x10000000, // '`', ord 0x60
|
|
||||||
0x11011101, // 'a', ord 0x61
|
|
||||||
0x00111101, // 'b', ord 0x62
|
|
||||||
0x00100101, // 'c', ord 0x63
|
|
||||||
0x10110101, // 'd', ord 0x64
|
|
||||||
0x01101101, // 'e', ord 0x65
|
|
||||||
0x01001101, // 'f', ord 0x66
|
|
||||||
0x01111100, // 'g', ord 0x67
|
|
||||||
0x00011101, // 'h', ord 0x68
|
|
||||||
0x00010000, // 'i', ord 0x69
|
|
||||||
0x10110100, // 'j', ord 0x6A
|
|
||||||
QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR, // 'k', ord 0x6B
|
|
||||||
0x00101100, // 'l', ord 0x6C
|
|
||||||
0x11011100, // 'm', ord 0x6D
|
|
||||||
0x00010101, // 'n', ord 0x6E
|
|
||||||
0x00110101, // 'o', ord 0x6F
|
|
||||||
0x11001101, // 'p', ord 0x70
|
|
||||||
0x11011001, // 'q', ord 0x71
|
|
||||||
0x00000101, // 'r', ord 0x72
|
|
||||||
0x01111001, // 's', ord 0x73
|
|
||||||
0x00001101, // 't', ord 0x74
|
|
||||||
0x00110100, // 'u', ord 0x75
|
|
||||||
0x00110100, // 'v', ord 0x76
|
|
||||||
QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR, // 'w', ord 0x77
|
|
||||||
QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR, // 'x', ord 0x78
|
|
||||||
0x10001101, // 'y', ord 0x79
|
|
||||||
QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR, // 'z', ord 0x7A
|
|
||||||
0x10010001, // '{', ord 0x7B
|
|
||||||
0x00001100, // '|', ord 0x7C
|
|
||||||
0x00001101, // '}', ord 0x7D
|
|
||||||
0x11001001, // '~', ord 0x7E (degree symbol)
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr uint8_t QSPI_74HC595_4X_DISPLAY_DIGIT_MAP[8] = {2, 3, 0, 1, 6, 7, 4, 5};
|
|
||||||
|
|
||||||
static constexpr uint8_t QSPI_74HC595_4X_DISPLAY_ZEROS[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
|
|
||||||
float QSPI_74HC595_4X_DISPLAYComponent::get_setup_priority() const
|
|
||||||
{
|
|
||||||
return setup_priority::PROCESSOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSPI_74HC595_4X_DISPLAYComponent::setup()
|
|
||||||
{
|
|
||||||
ESP_LOGCONFIG(TAG, "Setting up QSPI_74HC595_4X_DISPLAY...");
|
|
||||||
this->spi_setup();
|
|
||||||
memset(this->buffer_, 0xff, sizeof(this->buffer_));
|
|
||||||
// this->buffer_[0*2] = ~QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW['.'-' '];
|
|
||||||
// this->buffer_[1*2] = ~QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW['*'-' '];
|
|
||||||
// this->buffer_[2*2] = ~QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW['`'-' '];
|
|
||||||
// this->buffer_[3*2] = ~QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW[','-' '];
|
|
||||||
// this->buffer_[4*2] = ~QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW['_'-' '];
|
|
||||||
// this->buffer_[5*2] = ~QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW['+'-' '];
|
|
||||||
// this->buffer_[6*2] = ~QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW['\''-' '];
|
|
||||||
// this->buffer_[7*2] = ~QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW['-'-' '];
|
|
||||||
for (uint8_t i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
this->buffer_[(i * 2) + 1] = 0xF << (QSPI_74HC595_4X_DISPLAY_DIGIT_MAP[i] * 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSPI_74HC595_4X_DISPLAYComponent::dump_config()
|
|
||||||
{
|
|
||||||
ESP_LOGCONFIG(TAG, "QSPI_74HC595_4X_DISPLAY:");
|
|
||||||
LOG_PIN(" CS Pin: ", this->cs_);
|
|
||||||
LOG_UPDATE_INTERVAL(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSPI_74HC595_4X_DISPLAYComponent::display()
|
|
||||||
{
|
|
||||||
uint32_t delay = static_cast<uint64_t>(this->get_update_interval()) * 1000 / 8;
|
|
||||||
const uint8_t *buf_ptr = reinterpret_cast<const uint8_t *>(this->buffer_);
|
|
||||||
for (uint8_t i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
uint32_t start = micros();
|
|
||||||
this->enable();
|
|
||||||
this->write_cmd_addr_data(0, 0, 0, 0, buf_ptr, 8, 4);
|
|
||||||
buf_ptr += 8;
|
|
||||||
this->disable();
|
|
||||||
delay_microseconds_safe(delay - (micros() - start));
|
|
||||||
}
|
|
||||||
// zero out everything to have a somewhat uniform duty cycle for all digits
|
|
||||||
this->enable();
|
|
||||||
this->write_cmd_addr_data(0, 0, 0, 0, QSPI_74HC595_4X_DISPLAY_ZEROS, 32, 4);
|
|
||||||
this->disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSPI_74HC595_4X_DISPLAYComponent::update()
|
|
||||||
{
|
|
||||||
for (uint8_t i = 0; i < 8; i++)
|
|
||||||
this->buffer_[i * 2] = 0xFFFFFFFF;
|
|
||||||
if (this->writer_.has_value())
|
|
||||||
(*this->writer_)(*this);
|
|
||||||
this->display();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t QSPI_74HC595_4X_DISPLAYComponent::print(uint8_t start_pos, const char *str)
|
|
||||||
{
|
|
||||||
uint8_t pos = start_pos;
|
|
||||||
|
|
||||||
for (; *str != '\0'; str++)
|
|
||||||
{
|
|
||||||
uint32_t data = QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR;
|
|
||||||
if (*str >= ' ' && *str <= '~')
|
|
||||||
data = QSPI_74HC595_4X_DISPLAY_ASCII_TO_RAW[*str - ' '];
|
|
||||||
|
|
||||||
if (data == QSPI_74HC595_4X_DISPLAY_UNKNOWN_CHAR)
|
|
||||||
{
|
|
||||||
ESP_LOGW(
|
|
||||||
TAG,
|
|
||||||
"Encountered character '%c' with no QSPI_74HC595_4X_DISPLAY representation while translating string!",
|
|
||||||
*str);
|
|
||||||
}
|
|
||||||
if (*str == '.')
|
|
||||||
{
|
|
||||||
if (pos != start_pos)
|
|
||||||
pos--;
|
|
||||||
this->buffer_[(pos % 8) * 2] &= ~(0x00000010 << (pos / 8));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pos >= 32)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "QSPI_74HC595_4X_DISPLAY String is too long for the display!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this->buffer_[(pos % 8) * 2] &= ~(data << (pos / 8));
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pos - start_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t QSPI_74HC595_4X_DISPLAYComponent::print(const char *str)
|
|
||||||
{
|
|
||||||
return this->print(0, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t QSPI_74HC595_4X_DISPLAYComponent::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 QSPI_74HC595_4X_DISPLAYComponent::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QSPI_74HC595_4X_DISPLAYComponent::set_writer(qspi_74hc595_4x_display_writer_t &&writer)
|
|
||||||
{
|
|
||||||
this->writer_ = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t QSPI_74HC595_4X_DISPLAYComponent::strftime(uint8_t pos, const char *format, 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 QSPI_74HC595_4X_DISPLAYComponent::strftime(const char *format, ESPTime time)
|
|
||||||
{
|
|
||||||
return this->strftime(0, format, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace qspi_74hc595_4x_display
|
|
||||||
} // namespace esphome
|
|
|
@ -1,56 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
|
||||||
#include "esphome/core/time.h"
|
|
||||||
|
|
||||||
#include "esphome/components/spi/spi.h"
|
|
||||||
|
|
||||||
namespace esphome {
|
|
||||||
namespace qspi_74hc595_4x_display {
|
|
||||||
|
|
||||||
class QSPI_74HC595_4X_DISPLAYComponent;
|
|
||||||
|
|
||||||
using qspi_74hc595_4x_display_writer_t = std::function<void(QSPI_74HC595_4X_DISPLAYComponent &)>;
|
|
||||||
|
|
||||||
class QSPI_74HC595_4X_DISPLAYComponent : public PollingComponent,
|
|
||||||
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
|
|
||||||
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_10MHZ> {
|
|
||||||
public:
|
|
||||||
void set_writer(qspi_74hc595_4x_display_writer_t &&writer);
|
|
||||||
|
|
||||||
void setup() override;
|
|
||||||
|
|
||||||
void dump_config() override;
|
|
||||||
|
|
||||||
void update() override;
|
|
||||||
|
|
||||||
float get_setup_priority() const override;
|
|
||||||
|
|
||||||
void display();
|
|
||||||
|
|
||||||
/// 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);
|
|
||||||
|
|
||||||
/// Evaluate the strftime-format and print the result at the given position.
|
|
||||||
uint8_t strftime(uint8_t pos, const char *format, ESPTime time) __attribute__((format(strftime, 3, 0)));
|
|
||||||
|
|
||||||
/// Evaluate the strftime-format and print the result at position 0.
|
|
||||||
uint8_t strftime(const char *format, ESPTime time) __attribute__((format(strftime, 2, 0)));
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void send_byte_(uint8_t a_register, uint8_t data);
|
|
||||||
void send_to_all_(uint8_t a_register, uint8_t data);
|
|
||||||
|
|
||||||
uint32_t buffer_[16]; // 8* segment+digit words
|
|
||||||
optional<qspi_74hc595_4x_display_writer_t> writer_{};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace qspi_74hc595_4x_display
|
|
||||||
} // namespace esphome
|
|
|
@ -12,6 +12,8 @@ SPI_74HC595_DISPLAYComponent = spi_74hc595_display_ns.class_(
|
||||||
SPI_74HC595_DISPLAYComponentRef = SPI_74HC595_DISPLAYComponent.operator("ref")
|
SPI_74HC595_DISPLAYComponentRef = SPI_74HC595_DISPLAYComponent.operator("ref")
|
||||||
|
|
||||||
CONF_REVERSE = "reverse"
|
CONF_REVERSE = "reverse"
|
||||||
|
CONF_SEGMENT_FIRST = "segment_first"
|
||||||
|
CONF_COMMON_CATHODE = "common_cathode"
|
||||||
|
|
||||||
CONFIG_SCHEMA = (
|
CONFIG_SCHEMA = (
|
||||||
display.BASIC_DISPLAY_SCHEMA.extend(
|
display.BASIC_DISPLAY_SCHEMA.extend(
|
||||||
|
@ -19,6 +21,8 @@ CONFIG_SCHEMA = (
|
||||||
cv.GenerateID(): cv.declare_id(SPI_74HC595_DISPLAYComponent),
|
cv.GenerateID(): cv.declare_id(SPI_74HC595_DISPLAYComponent),
|
||||||
cv.Optional(CONF_NUM_CHIPS, default=1): cv.int_range(min=1, max=255),
|
cv.Optional(CONF_NUM_CHIPS, default=1): cv.int_range(min=1, max=255),
|
||||||
cv.Optional(CONF_REVERSE, default=False): cv.boolean,
|
cv.Optional(CONF_REVERSE, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_SEGMENT_FIRST, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_COMMON_CATHODE, default=False): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.extend(cv.polling_component_schema("1s"))
|
.extend(cv.polling_component_schema("1s"))
|
||||||
|
@ -33,6 +37,8 @@ async def to_code(config):
|
||||||
|
|
||||||
cg.add(var.set_num_chips(config[CONF_NUM_CHIPS]))
|
cg.add(var.set_num_chips(config[CONF_NUM_CHIPS]))
|
||||||
cg.add(var.set_reverse(config[CONF_REVERSE]))
|
cg.add(var.set_reverse(config[CONF_REVERSE]))
|
||||||
|
cg.add(var.set_segment_first(config[CONF_SEGMENT_FIRST]))
|
||||||
|
cg.add(var.set_common_cathode(config[CONF_COMMON_CATHODE]))
|
||||||
|
|
||||||
if CONF_LAMBDA in config:
|
if CONF_LAMBDA in config:
|
||||||
lambda_ = await cg.process_lambda(
|
lambda_ = await cg.process_lambda(
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
#include "spi_74hc595_display.h"
|
#include "spi_74hc595_display.h"
|
||||||
#include "esphome/core/hal.h"
|
|
||||||
#include "esphome/core/helpers.h"
|
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
|
||||||
namespace esphome
|
namespace esphome {
|
||||||
{
|
namespace spi_74hc595_display {
|
||||||
namespace spi_74hc595_display
|
|
||||||
{
|
|
||||||
|
|
||||||
static const char *const TAG = "spi_74hc595_display";
|
static const char *const TAG = "spi_74hc595_display";
|
||||||
|
|
||||||
|
@ -14,261 +12,224 @@ static const uint8_t SPI_74HC595_DISPLAY_UNKNOWN_CHAR = 0b11111111;
|
||||||
|
|
||||||
const uint8_t SPI_74HC595_DISPLAY_ASCII_TO_RAW[95] PROGMEM = {
|
const uint8_t SPI_74HC595_DISPLAY_ASCII_TO_RAW[95] PROGMEM = {
|
||||||
//.GFEDCBA
|
//.GFEDCBA
|
||||||
0b00000000, // ' ', ord 0x20
|
0b00000000, // ' ', ord 0x20
|
||||||
0b10000110, // '!', ord 0x21
|
0b10000110, // '!', ord 0x21
|
||||||
0b00100010, // '"', ord 0x22
|
0b00100010, // '"', ord 0x22
|
||||||
0b00110110, // '#', ord 0x23
|
0b00110110, // '#', ord 0x23
|
||||||
0b00101101, // '$', ord 0x24
|
0b00101101, // '$', ord 0x24
|
||||||
0b01001001, // '%', ord 0x25
|
0b01001001, // '%', ord 0x25
|
||||||
0b00011011, // '&', ord 0x26
|
0b00011011, // '&', ord 0x26
|
||||||
0b00100000, // ''', ord 0x27
|
0b00100000, // ''', ord 0x27
|
||||||
0b00111001, // '(', ord 0x28
|
0b00111001, // '(', ord 0x28
|
||||||
0b00001111, // ')', ord 0x29
|
0b00001111, // ')', ord 0x29
|
||||||
0b00000001, // '*', ord 0x2A
|
0b00000001, // '*', ord 0x2A
|
||||||
0b00010000, // '+', ord 0x2B
|
0b00010000, // '+', ord 0x2B
|
||||||
0b00000100, // ',', ord 0x2C
|
0b00000100, // ',', ord 0x2C
|
||||||
0b01000000, // '-', ord 0x2D
|
0b01000000, // '-', ord 0x2D
|
||||||
0b10000000, // '.', ord 0x2E
|
0b10000000, // '.', ord 0x2E
|
||||||
0b01010010, // '/', ord 0x2F
|
0b01010010, // '/', ord 0x2F
|
||||||
0b00111111, // '0', ord 0x30
|
0b00111111, // '0', ord 0x30
|
||||||
0b00000110, // '1', ord 0x31
|
0b00000110, // '1', ord 0x31
|
||||||
0b01011011, // '2', ord 0x32
|
0b01011011, // '2', ord 0x32
|
||||||
0b01001111, // '3', ord 0x33
|
0b01001111, // '3', ord 0x33
|
||||||
0b01100110, // '4', ord 0x34
|
0b01100110, // '4', ord 0x34
|
||||||
0b01101101, // '5', ord 0x35
|
0b01101101, // '5', ord 0x35
|
||||||
0b01111101, // '6', ord 0x36
|
0b01111101, // '6', ord 0x36
|
||||||
0b00000111, // '7', ord 0x37
|
0b00000111, // '7', ord 0x37
|
||||||
0b01111111, // '8', ord 0x38
|
0b01111111, // '8', ord 0x38
|
||||||
0b01101111, // '9', ord 0x39
|
0b01101111, // '9', ord 0x39
|
||||||
0b00001001, // ':', ord 0x3A
|
0b00001001, // ':', ord 0x3A
|
||||||
0b00001101, // ';', ord 0x3B
|
0b00001101, // ';', ord 0x3B
|
||||||
0b00011000, // '<', ord 0x3C
|
0b00011000, // '<', ord 0x3C
|
||||||
0b01001000, // '=', ord 0x3D
|
0b01001000, // '=', ord 0x3D
|
||||||
0b00001100, // '>', ord 0x3E
|
0b00001100, // '>', ord 0x3E
|
||||||
0b01010011, // '?', ord 0x3F
|
0b01010011, // '?', ord 0x3F
|
||||||
0b01111011, // '@', ord 0x40
|
0b01111011, // '@', ord 0x40
|
||||||
0b01110111, // 'A', ord 0x41
|
0b01110111, // 'A', ord 0x41
|
||||||
0b01111100, // 'B', ord 0x42
|
0b01111100, // 'B', ord 0x42
|
||||||
0b00111001, // 'C', ord 0x43
|
0b00111001, // 'C', ord 0x43
|
||||||
0b01011110, // 'D', ord 0x44
|
0b01011110, // 'D', ord 0x44
|
||||||
0b01111001, // 'E', ord 0x45
|
0b01111001, // 'E', ord 0x45
|
||||||
0b01110001, // 'F', ord 0x46
|
0b01110001, // 'F', ord 0x46
|
||||||
0b00111101, // 'G', ord 0x47
|
0b00111101, // 'G', ord 0x47
|
||||||
0b01110110, // 'H', ord 0x48
|
0b01110110, // 'H', ord 0x48
|
||||||
0b00000110, // 'I', ord 0x49
|
0b00000110, // 'I', ord 0x49
|
||||||
0b00011110, // 'J', ord 0x4A
|
0b00011110, // 'J', ord 0x4A
|
||||||
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'K', ord 0x4B
|
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'K', ord 0x4B
|
||||||
0b00111000, // 'L', ord 0x4C
|
0b00111000, // 'L', ord 0x4C
|
||||||
0b00110111, // 'M', ord 0x4D
|
0b00110111, // 'M', ord 0x4D
|
||||||
0b01010100, // 'N', ord 0x4E
|
0b01010100, // 'N', ord 0x4E
|
||||||
0b00111111, // 'O', ord 0x4F
|
0b00111111, // 'O', ord 0x4F
|
||||||
0b01110011, // 'P', ord 0x50
|
0b01110011, // 'P', ord 0x50
|
||||||
0b10111111, // 'Q', ord 0x51
|
0b10111111, // 'Q', ord 0x51
|
||||||
0b01010000, // 'R', ord 0x52
|
0b01010000, // 'R', ord 0x52
|
||||||
0b01101101, // 'S', ord 0x53
|
0b01101101, // 'S', ord 0x53
|
||||||
0b01110000, // 'T', ord 0x54
|
0b01110000, // 'T', ord 0x54
|
||||||
0b00111110, // 'U', ord 0x55
|
0b00111110, // 'U', ord 0x55
|
||||||
0b00111110, // 'V', ord 0x56
|
0b00111110, // 'V', ord 0x56
|
||||||
0b01111110, // 'W', ord 0x57
|
0b01111110, // 'W', ord 0x57
|
||||||
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'X', ord 0x58
|
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'X', ord 0x58
|
||||||
0b01110010, // 'Y', ord 0x59
|
0b01110010, // 'Y', ord 0x59
|
||||||
0b01011011, // 'Z', ord 0x5A
|
0b01011011, // 'Z', ord 0x5A
|
||||||
0b00111001, // '[', ord 0x5B
|
0b00111001, // '[', ord 0x5B
|
||||||
0b01100100, // '\', ord 0x5C
|
0b01100100, // '\', ord 0x5C
|
||||||
0b00001111, // ']', ord 0x5D
|
0b00001111, // ']', ord 0x5D
|
||||||
0b00100011, // '^', ord 0x5E
|
0b00100011, // '^', ord 0x5E
|
||||||
0b00001000, // '_', ord 0x5F
|
0b00001000, // '_', ord 0x5F
|
||||||
0b00000010, // '`', ord 0x60
|
0b00000010, // '`', ord 0x60
|
||||||
0b01110111, // 'a', ord 0x61
|
0b01110111, // 'a', ord 0x61
|
||||||
0b01111100, // 'b', ord 0x62
|
0b01111100, // 'b', ord 0x62
|
||||||
0b01011000, // 'c', ord 0x63
|
0b01011000, // 'c', ord 0x63
|
||||||
0b01011110, // 'd', ord 0x64
|
0b01011110, // 'd', ord 0x64
|
||||||
0b01111001, // 'e', ord 0x65
|
0b01111001, // 'e', ord 0x65
|
||||||
0b01110001, // 'f', ord 0x66
|
0b01110001, // 'f', ord 0x66
|
||||||
0b00111101, // 'g', ord 0x67
|
0b00111101, // 'g', ord 0x67
|
||||||
0b01110100, // 'h', ord 0x68
|
0b01110100, // 'h', ord 0x68
|
||||||
0b00000100, // 'i', ord 0x69
|
0b00000100, // 'i', ord 0x69
|
||||||
0b00011110, // 'j', ord 0x6A
|
0b00011110, // 'j', ord 0x6A
|
||||||
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'k', ord 0x6B
|
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'k', ord 0x6B
|
||||||
0b00111000, // 'l', ord 0x6C
|
0b00111000, // 'l', ord 0x6C
|
||||||
0b00110111, // 'm', ord 0x6D
|
0b00110111, // 'm', ord 0x6D
|
||||||
0b01010100, // 'n', ord 0x6E
|
0b01010100, // 'n', ord 0x6E
|
||||||
0b01011100, // 'o', ord 0x6F
|
0b01011100, // 'o', ord 0x6F
|
||||||
0b01110011, // 'p', ord 0x70
|
0b01110011, // 'p', ord 0x70
|
||||||
0b01100111, // 'q', ord 0x71
|
0b01100111, // 'q', ord 0x71
|
||||||
0b01010000, // 'r', ord 0x72
|
0b01010000, // 'r', ord 0x72
|
||||||
0b01101101, // 's', ord 0x73
|
0b01101101, // 's', ord 0x73
|
||||||
0b01110000, // 't', ord 0x74
|
0b01110000, // 't', ord 0x74
|
||||||
0b00011100, // 'u', ord 0x75
|
0b00011100, // 'u', ord 0x75
|
||||||
0b00011100, // 'v', ord 0x76
|
0b00011100, // 'v', ord 0x76
|
||||||
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'w', ord 0x77
|
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'w', ord 0x77
|
||||||
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'x', ord 0x78
|
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'x', ord 0x78
|
||||||
0b01110010, // 'y', ord 0x79
|
0b01110010, // 'y', ord 0x79
|
||||||
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'z', ord 0x7A
|
SPI_74HC595_DISPLAY_UNKNOWN_CHAR, // 'z', ord 0x7A
|
||||||
0b01000110, // '{', ord 0x7B
|
0b01000110, // '{', ord 0x7B
|
||||||
0b00110000, // '|', ord 0x7C
|
0b00110000, // '|', ord 0x7C
|
||||||
0b01110000, // '}', ord 0x7D
|
0b01110000, // '}', ord 0x7D
|
||||||
0b01100011, // '~', ord 0x7E (degree symbol)
|
0b01100011, // '~', ord 0x7E (degree symbol)
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t SPI_74HC595_DISPLAY_DIGIT_MASK[8] PROGMEM = {
|
float SPI_74HC595_DISPLAYComponent::get_setup_priority() const { return setup_priority::PROCESSOR; }
|
||||||
(1U << 4), (1U << 5), (1U << 6), (1U << 7), (1U << 0), (1U << 1), (1U << 2), (1U << 3),
|
|
||||||
};
|
|
||||||
|
|
||||||
float SPI_74HC595_DISPLAYComponent::get_setup_priority() const
|
void SPI_74HC595_DISPLAYComponent::setup() {
|
||||||
{
|
ESP_LOGCONFIG(TAG, "Setting up SPI_74HC595_DISPLAY...");
|
||||||
return setup_priority::PROCESSOR;
|
this->spi_setup();
|
||||||
|
this->buffer_ = new uint8_t[this->num_chips_ * 8]; // NOLINT
|
||||||
|
for (uint8_t i = 0; i < this->num_chips_ * 8; i++)
|
||||||
|
this->buffer_[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_74HC595_DISPLAYComponent::setup()
|
void SPI_74HC595_DISPLAYComponent::dump_config() {
|
||||||
{
|
ESP_LOGCONFIG(TAG, "SPI_74HC595_DISPLAY:");
|
||||||
ESP_LOGCONFIG(TAG, "Setting up SPI_74HC595_DISPLAY...");
|
ESP_LOGCONFIG(TAG, " Number of Chips: %u", this->num_chips_);
|
||||||
this->spi_setup();
|
LOG_PIN(" CS Pin: ", this->cs_);
|
||||||
this->buffer_ = new uint8_t[this->num_chips_ * 8]; // NOLINT
|
LOG_UPDATE_INTERVAL(this);
|
||||||
for (uint8_t i = 0; i < this->num_chips_ * 8; i++)
|
|
||||||
{
|
|
||||||
this->buffer_[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_74HC595_DISPLAYComponent::dump_config()
|
void SPI_74HC595_DISPLAYComponent::display() {
|
||||||
{
|
uint32_t delay = static_cast<uint64_t>(this->get_update_interval())*1000 / 8;
|
||||||
ESP_LOGCONFIG(TAG, "SPI_74HC595_DISPLAY:");
|
uint8_t flip_digit=(this->common_cathode_)?0xFF:0x00;
|
||||||
ESP_LOGCONFIG(TAG, " Number of Chips: %u", this->num_chips_);
|
uint8_t flip_segment = ~flip_digit;
|
||||||
LOG_PIN(" CS Pin: ", this->cs_);
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
LOG_UPDATE_INTERVAL(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SPI_74HC595_DISPLAYComponent::display()
|
|
||||||
{
|
|
||||||
uint32_t delay = static_cast<uint64_t>(this->get_update_interval()) * 1000 / 8;
|
|
||||||
for (uint8_t i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
this->enable();
|
|
||||||
for (uint8_t j = 0; j < this->num_chips_; j++)
|
|
||||||
{
|
|
||||||
if (reverse_)
|
|
||||||
{
|
|
||||||
this->send_byte_(SPI_74HC595_DISPLAY_DIGIT_MASK[i], ~buffer_[(num_chips_ - j - 1) * 8 + i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->send_byte_(SPI_74HC595_DISPLAY_DIGIT_MASK[i], ~buffer_[j * 8 + i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this->disable();
|
|
||||||
delay_microseconds_safe(delay);
|
|
||||||
}
|
|
||||||
// zero out everything to have a somewhat uniform duty cycle for all digits
|
|
||||||
this->enable();
|
this->enable();
|
||||||
for (uint8_t j = 0; j < this->num_chips_; j++)
|
for (uint8_t j = 0; j < this->num_chips_; j++) {
|
||||||
{
|
if (reverse_) {
|
||||||
this->send_byte_(0, 0);
|
this->send_byte_((1U << i)^flip_digit, buffer_[(num_chips_ - j - 1) * 8 + i]^flip_segment);
|
||||||
|
} else {
|
||||||
|
this->send_byte_((1U << i)^flip_digit, (buffer_[j * 8 + i])^flip_segment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this->disable();
|
this->disable();
|
||||||
|
delay_microseconds_safe(delay);
|
||||||
|
}
|
||||||
|
// zero out everything to have a somewhat uniform duty cycle for all digits
|
||||||
|
this->enable();
|
||||||
|
for (uint8_t j = 0; j < this->num_chips_; j++) {
|
||||||
|
this->send_byte_(0, 0);
|
||||||
|
}
|
||||||
|
this->disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_74HC595_DISPLAYComponent::send_byte_(uint8_t a_digit, uint8_t data)
|
void SPI_74HC595_DISPLAYComponent::send_byte_(uint8_t a_digit, uint8_t data) {
|
||||||
{
|
if(this->segment_first_){
|
||||||
this->write_byte(data);
|
this->write_byte(data);
|
||||||
this->write_byte(a_digit);
|
this->write_byte(a_digit);
|
||||||
|
} else {
|
||||||
|
this->write_byte(a_digit);
|
||||||
|
this->write_byte(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SPI_74HC595_DISPLAYComponent::update()
|
void SPI_74HC595_DISPLAYComponent::update() {
|
||||||
{
|
for (uint8_t i = 0; i < this->num_chips_ * 8; i++)
|
||||||
for (uint8_t i = 0; i < this->num_chips_ * 8; i++)
|
this->buffer_[i] = 0;
|
||||||
this->buffer_[i] = 0;
|
if (this->writer_.has_value())
|
||||||
if (this->writer_.has_value())
|
(*this->writer_)(*this);
|
||||||
(*this->writer_)(*this);
|
this->display();
|
||||||
this->display();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SPI_74HC595_DISPLAYComponent::print(uint8_t start_pos, const char *str)
|
uint8_t SPI_74HC595_DISPLAYComponent::print(uint8_t start_pos, const char *str) {
|
||||||
{
|
uint8_t pos = start_pos;
|
||||||
uint8_t pos = start_pos;
|
for (; *str != '\0'; str++) {
|
||||||
for (; *str != '\0'; str++)
|
uint8_t data = SPI_74HC595_DISPLAY_UNKNOWN_CHAR;
|
||||||
{
|
if (*str >= ' ' && *str <= '~')
|
||||||
uint8_t data = SPI_74HC595_DISPLAY_UNKNOWN_CHAR;
|
data = progmem_read_byte(&SPI_74HC595_DISPLAY_ASCII_TO_RAW[*str - ' ']);
|
||||||
if (*str >= ' ' && *str <= '~')
|
|
||||||
data = progmem_read_byte(&SPI_74HC595_DISPLAY_ASCII_TO_RAW[*str - ' ']);
|
|
||||||
|
|
||||||
if (data == SPI_74HC595_DISPLAY_UNKNOWN_CHAR)
|
if (data == SPI_74HC595_DISPLAY_UNKNOWN_CHAR) {
|
||||||
{
|
ESP_LOGW(TAG, "Encountered character '%c' with no SPI_74HC595_DISPLAY representation while translating string!", *str);
|
||||||
ESP_LOGW(TAG,
|
|
||||||
"Encountered character '%c' with no SPI_74HC595_DISPLAY representation while translating string!",
|
|
||||||
*str);
|
|
||||||
}
|
|
||||||
if (*str == '.')
|
|
||||||
{
|
|
||||||
if (pos != start_pos)
|
|
||||||
pos--;
|
|
||||||
this->buffer_[pos] |= 0b10000000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pos >= this->num_chips_ * 8)
|
|
||||||
{
|
|
||||||
ESP_LOGE(TAG, "SPI_74HC595_DISPLAY String is too long for the display!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this->buffer_[pos] = data;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
}
|
||||||
return pos - start_pos;
|
if (*str == '.') {
|
||||||
|
if (pos != start_pos)
|
||||||
|
pos--;
|
||||||
|
this->buffer_[pos] |= 0b10000000;
|
||||||
|
} else {
|
||||||
|
if (pos >= this->num_chips_ * 8) {
|
||||||
|
ESP_LOGE(TAG, "SPI_74HC595_DISPLAY String is too long for the display!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->buffer_[pos] = data;
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
return pos - start_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SPI_74HC595_DISPLAYComponent::print(const char *str)
|
uint8_t SPI_74HC595_DISPLAYComponent::print(const char *str) { return this->print(0, str); }
|
||||||
{
|
|
||||||
return this->print(0, str);
|
uint8_t SPI_74HC595_DISPLAYComponent::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 SPI_74HC595_DISPLAYComponent::printf(uint8_t pos, const char *format, ...)
|
uint8_t SPI_74HC595_DISPLAYComponent::printf(const char *format, ...) {
|
||||||
{
|
va_list arg;
|
||||||
va_list arg;
|
va_start(arg, format);
|
||||||
va_start(arg, format);
|
char buffer[64];
|
||||||
char buffer[64];
|
int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
|
||||||
int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
|
va_end(arg);
|
||||||
va_end(arg);
|
if (ret > 0)
|
||||||
if (ret > 0)
|
return this->print(buffer);
|
||||||
return this->print(pos, buffer);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t SPI_74HC595_DISPLAYComponent::printf(const char *format, ...)
|
void SPI_74HC595_DISPLAYComponent::set_writer(spi_74hc595_display_writer_t &&writer) { this->writer_ = writer; }
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SPI_74HC595_DISPLAYComponent::set_writer(spi_74hc595_display_writer_t &&writer)
|
void SPI_74HC595_DISPLAYComponent::set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; }
|
||||||
{
|
|
||||||
this->writer_ = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SPI_74HC595_DISPLAYComponent::set_num_chips(uint8_t num_chips)
|
uint8_t SPI_74HC595_DISPLAYComponent::strftime(uint8_t pos, const char *format, ESPTime time) {
|
||||||
{
|
char buffer[64];
|
||||||
this->num_chips_ = num_chips;
|
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||||
|
if (ret > 0)
|
||||||
|
return this->print(pos, buffer);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
uint8_t SPI_74HC595_DISPLAYComponent::strftime(const char *format, ESPTime time) { return this->strftime(0, format, time); }
|
||||||
|
|
||||||
uint8_t SPI_74HC595_DISPLAYComponent::strftime(uint8_t pos, const char *format, ESPTime time)
|
} // namespace spi_74hc595_display
|
||||||
{
|
} // namespace esphome
|
||||||
char buffer[64];
|
|
||||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
|
||||||
if (ret > 0)
|
|
||||||
return this->print(pos, buffer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint8_t SPI_74HC595_DISPLAYComponent::strftime(const char *format, ESPTime time)
|
|
||||||
{
|
|
||||||
return this->strftime(0, format, time);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace spi_74hc595_display
|
|
||||||
} // namespace esphome
|
|
|
@ -30,6 +30,8 @@ class SPI_74HC595_DISPLAYComponent : public PollingComponent,
|
||||||
|
|
||||||
void set_num_chips(uint8_t num_chips);
|
void set_num_chips(uint8_t num_chips);
|
||||||
void set_reverse(bool reverse) { this->reverse_ = reverse; };
|
void set_reverse(bool reverse) { this->reverse_ = reverse; };
|
||||||
|
void set_segment_first(bool segment_first) { this->segment_first_ = segment_first; };
|
||||||
|
void set_common_cathode(bool common_cathode) { this->common_cathode_ = common_cathode; };
|
||||||
|
|
||||||
/// Evaluate the printf-format and print the result at the given position.
|
/// 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)));
|
uint8_t printf(uint8_t pos, const char *format, ...) __attribute__((format(printf, 3, 4)));
|
||||||
|
@ -54,6 +56,8 @@ class SPI_74HC595_DISPLAYComponent : public PollingComponent,
|
||||||
uint8_t num_chips_{1};
|
uint8_t num_chips_{1};
|
||||||
uint8_t *buffer_;
|
uint8_t *buffer_;
|
||||||
bool reverse_{false};
|
bool reverse_{false};
|
||||||
|
bool segment_first_{false};
|
||||||
|
bool common_cathode_{false};
|
||||||
optional<spi_74hc595_display_writer_t> writer_{};
|
optional<spi_74hc595_display_writer_t> writer_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ esphome:
|
||||||
esp32:
|
esp32:
|
||||||
board: esp32dev
|
board: esp32dev
|
||||||
framework:
|
framework:
|
||||||
type: esp-idf
|
type: arduino
|
||||||
|
|
||||||
# Enable logging
|
# Enable logging
|
||||||
logger:
|
logger:
|
||||||
|
@ -44,147 +44,63 @@ time:
|
||||||
- platform: sntp
|
- platform: sntp
|
||||||
id: sntp_time
|
id: sntp_time
|
||||||
timezone: Europe/Berlin
|
timezone: Europe/Berlin
|
||||||
|
on_time:
|
||||||
|
- seconds: /10
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
level: INFO
|
||||||
|
format: "%2d %2d %2d %2d"
|
||||||
|
args:
|
||||||
|
- 'uint32_t(id(runtime).state/3600) - uint32_t(id(runtime).state/86400)*1440'
|
||||||
|
- 'uint32_t(id(runtime).state/60) - uint32_t(id(runtime).state/3600)*60'
|
||||||
|
- 'uint32_t(id(runtime).state) - uint32_t(id(runtime).state/60)*60'
|
||||||
|
- 'uint32_t((id(runtime).state - uint32_t(id(runtime).state))*25)'
|
||||||
|
|
||||||
spi:
|
spi:
|
||||||
- id: quad_spi_bus
|
clk_pin: GPIO18
|
||||||
interface: spi3
|
mosi_pin: GPIO19
|
||||||
clk_pin: 18
|
|
||||||
data_pins:
|
|
||||||
- 23
|
|
||||||
- 19
|
|
||||||
- 22
|
|
||||||
- 21
|
|
||||||
|
|
||||||
sensor:
|
sensor:
|
||||||
- platform: uptime
|
- platform: uptime
|
||||||
id: runtime
|
id: runtime
|
||||||
update_interval: 100ms
|
update_interval: 100ms
|
||||||
|
|
||||||
globals:
|
|
||||||
- id: countdown_end
|
|
||||||
type: time_t
|
|
||||||
- id: uptime_start
|
|
||||||
type: time_t
|
|
||||||
|
|
||||||
number:
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown set H"
|
|
||||||
id: cd_set_h
|
|
||||||
initial_value: 0
|
|
||||||
min_value: 0
|
|
||||||
max_value: 99
|
|
||||||
step: 1
|
|
||||||
optimistic: true
|
|
||||||
mode: box
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown set M"
|
|
||||||
id: cd_set_m
|
|
||||||
initial_value: 0
|
|
||||||
min_value: 0
|
|
||||||
max_value: 59
|
|
||||||
step: 1
|
|
||||||
optimistic: true
|
|
||||||
mode: box
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown set S"
|
|
||||||
id: cd_set_s
|
|
||||||
initial_value: 0
|
|
||||||
min_value: 0
|
|
||||||
max_value: 59
|
|
||||||
step: 1
|
|
||||||
optimistic: true
|
|
||||||
mode: box
|
|
||||||
|
|
||||||
button:
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown set"
|
|
||||||
on_press:
|
|
||||||
- lambda: |-
|
|
||||||
id(countdown_end) =
|
|
||||||
id(sntp_time).timestamp_now()
|
|
||||||
+ uint32_t(id(cd_set_h).state)*3600
|
|
||||||
+ uint32_t(id(cd_set_m).state)*60
|
|
||||||
+ uint32_t(id(cd_set_s).state);
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown Minutes 1m"
|
|
||||||
on_press:
|
|
||||||
- lambda: |-
|
|
||||||
id(countdown_end) = id(sntp_time).timestamp_now() + 60;
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown Minutes 5m"
|
|
||||||
on_press:
|
|
||||||
- lambda: |-
|
|
||||||
id(countdown_end) = id(sntp_time).timestamp_now() + 300;
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown Minutes 10m"
|
|
||||||
on_press:
|
|
||||||
- lambda: |-
|
|
||||||
id(countdown_end) = id(sntp_time).timestamp_now() + 600;
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown Hours 1h"
|
|
||||||
on_press:
|
|
||||||
- lambda: |-
|
|
||||||
id(countdown_end) = id(sntp_time).timestamp_now() + 3600;
|
|
||||||
- platform: template
|
|
||||||
name: "Countdown Hours 2h"
|
|
||||||
on_press:
|
|
||||||
- lambda: |-
|
|
||||||
id(countdown_end) = id(sntp_time).timestamp_now() + 7200;
|
|
||||||
- platform: template
|
|
||||||
name: "Runtime Reset"
|
|
||||||
on_press:
|
|
||||||
- lambda: |-
|
|
||||||
id(uptime_start) = id(runtime).state;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
display:
|
display:
|
||||||
- platform: qspi_74hc595_4x_display
|
- platform: spi_74hc595_display
|
||||||
cs_pin: GPIO5
|
cs_pin: GPIO5
|
||||||
data_rate: 10MHz
|
data_rate: 1MHz #10MHz
|
||||||
update_interval: 10ms
|
num_chips: 1 #3
|
||||||
spi_id: quad_spi_bus
|
update_interval: 4s #16ms
|
||||||
|
common_cathode: false
|
||||||
|
segment_first: false
|
||||||
|
reverse: false
|
||||||
lambda: |-
|
lambda: |-
|
||||||
static uint32_t last_micros=0;
|
|
||||||
static uint32_t clock_frames=0;
|
static uint32_t clock_frames=0;
|
||||||
static uint32_t old_clock=0;
|
static uint32_t old_clock=0;
|
||||||
|
|
||||||
if(id(sntp_time).now().second!=old_clock){
|
if(id(sntp_time).now().second!=old_clock){
|
||||||
last_micros = micros();
|
clock_frames=0;
|
||||||
old_clock=id(sntp_time).now().second;
|
old_clock=id(sntp_time).now().second;
|
||||||
} else {
|
} else {
|
||||||
clock_frames = (micros()-last_micros)/10000;
|
clock_frames++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////// first display
|
//it.printf(0, ".*`,_+'-");
|
||||||
it.printf(0, ".*`,_+'-");
|
it.printf(0, "88888888");
|
||||||
|
//it.strftime(0, "%H%M%s", id(sntp_time).now());
|
||||||
|
//it.printf(6, "%2d", clock_frames);
|
||||||
|
|
||||||
/////////// second display
|
//it.strftime(8, "%H%M%s", id(sntp_time).now());
|
||||||
it.strftime(8, "%H%M%S", id(sntp_time).now());
|
//it.printf(14, "%2d", clock_frames);
|
||||||
it.printf(14, "%02d", clock_frames%100);
|
/*it.strftime(8, "%H%M%s", id(sntp_time).now());*/
|
||||||
|
/*it.printf(14, "%1d", 0)*/
|
||||||
|
|
||||||
/////////// third display
|
/*it.printf(16, "%02d%02d%02d%02d",
|
||||||
{
|
uint32_t(id(runtime).state/3600) - uint32_t(id(runtime).state/86400)*1440,
|
||||||
double delta = id(runtime).state - id(uptime_start);
|
uint32_t(id(runtime).state/60) - uint32_t(id(runtime).state/3600)*60,
|
||||||
uint32_t hours = delta/3600;
|
uint32_t(id(runtime).state) - uint32_t(id(runtime).state/60)*60,
|
||||||
delta -= hours*3600;
|
uint32_t((id(runtime).state - uint32_t(id(runtime).state))*25) );
|
||||||
uint32_t minutes = delta/60;
|
*/
|
||||||
delta -= minutes*60;
|
|
||||||
uint32_t seconds = delta;
|
|
||||||
uint32_t frames = (100*delta) - (100*seconds);
|
|
||||||
it.printf(16, "%02d%02d%02d%02d", hours, minutes, seconds, frames);
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////// fourth display
|
|
||||||
if (id(countdown_end) > id(sntp_time).timestamp_now()) {
|
|
||||||
time_t delta=difftime(id(countdown_end), id(sntp_time).timestamp_now());
|
|
||||||
time_t hours = delta/3600;
|
|
||||||
delta -= hours*3600;
|
|
||||||
time_t minutes = (delta)/60;
|
|
||||||
delta -= minutes*60;
|
|
||||||
time_t seconds = delta;
|
|
||||||
it.printf(24, "%02ld%02ld%02ld%02d", hours, minutes, seconds, (99-clock_frames%100));
|
|
||||||
}
|
|
||||||
|
|
||||||
# the first display should display a test string to figure out the digit and segment map:
|
# the first display should display a test string to figure out the digit and segment map:
|
||||||
# digit 0: >.< character (dot segment on)
|
# digit 0: >.< character (dot segment on)
|
||||||
|
|
Loading…
Reference in a new issue