mirror of
https://github.com/esphome/esphome.git
synced 2025-09-04 12:22:20 +01:00
🏗 Merge C++ into python codebase (#504)
## Description: Move esphome-core codebase into esphome (and a bunch of other refactors). See https://github.com/esphome/feature-requests/issues/97 Yes this is a shit ton of work and no there's no way to automate it :( But it will be worth it 👍 Progress: - Core support (file copy etc): 80% - Base Abstractions (light, switch): ~50% - Integrations: ~10% - Working? Yes, (but only with ported components). Other refactors: - Moves all codegen related stuff into a single class: `esphome.codegen` (imported as `cg`) - Rework coroutine syntax - Move from `component/platform.py` to `domain/component.py` structure as with HA - Move all defaults out of C++ and into config validation. - Remove `make_...` helpers from Application class. Reason: Merge conflicts with every single new integration. - Pointer Variables are stored globally instead of locally in setup(). Reason: stack size limit. Future work: - Rework const.py - Move all `CONF_...` into a conf class (usage `conf.UPDATE_INTERVAL` vs `CONF_UPDATE_INTERVAL`). Reason: Less convoluted import block - Enable loading from `custom_components` folder. **Related issue (if applicable):** https://github.com/esphome/feature-requests/issues/97 **Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):** esphome/esphome-docs#<esphome-docs PR number goes here> ## Checklist: - [ ] The code change is tested and works locally. - [ ] Tests have been added to verify that the new code works (under `tests/` folder). If user exposed functionality or configuration variables are added/changed: - [ ] Documentation added/updated in [esphomedocs](https://github.com/OttoWinter/esphomedocs).
This commit is contained in:
0
esphome/components/max7219/__init__.py
Normal file
0
esphome/components/max7219/__init__.py
Normal file
33
esphome/components/max7219/display.py
Normal file
33
esphome/components/max7219/display.py
Normal file
@@ -0,0 +1,33 @@
|
||||
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, CONF_UPDATE_INTERVAL
|
||||
|
||||
DEPENDENCIES = ['spi']
|
||||
|
||||
max7219_ns = cg.esphome_ns.namespace('max7219')
|
||||
MAX7219Component = max7219_ns.class_('MAX7219Component', cg.PollingComponent, spi.SPIDevice)
|
||||
MAX7219ComponentRef = MAX7219Component.operator('ref')
|
||||
|
||||
CONFIG_SCHEMA = display.BASIC_DISPLAY_SCHEMA.extend({
|
||||
cv.GenerateID(): cv.declare_variable_id(MAX7219Component),
|
||||
|
||||
cv.Optional(CONF_UPDATE_INTERVAL, default='1s'): cv.update_interval,
|
||||
cv.Optional(CONF_NUM_CHIPS, default=1): cv.All(cv.uint8_t, cv.Range(min=1)),
|
||||
cv.Optional(CONF_INTENSITY, default=15): cv.All(cv.uint8_t, cv.Range(min=0, max=15)),
|
||||
}).extend(cv.COMPONENT_SCHEMA).extend(spi.SPI_DEVICE_SCHEMA)
|
||||
|
||||
|
||||
def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID], config[CONF_UPDATE_INTERVAL])
|
||||
yield cg.register_component(var, config)
|
||||
yield spi.register_spi_device(var, config)
|
||||
yield display.register_display(var, config)
|
||||
|
||||
cg.add(var.set_num_chips(config[CONF_NUM_CHIPS]))
|
||||
cg.add(var.set_intensity(config[CONF_INTENSITY]))
|
||||
|
||||
if CONF_LAMBDA in config:
|
||||
lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(MAX7219ComponentRef, 'it')],
|
||||
return_type=cg.void)
|
||||
cg.add(var.set_writer(lambda_))
|
228
esphome/components/max7219/max7219.cpp
Normal file
228
esphome/components/max7219/max7219.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
#include "max7219.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace max7219 {
|
||||
|
||||
static const char *TAG = "max7219";
|
||||
|
||||
static const uint8_t MAX7219_REGISTER_NOOP = 0x00;
|
||||
static const uint8_t MAX7219_REGISTER_DECODE_MODE = 0x09;
|
||||
static const uint8_t MAX7219_REGISTER_INTENSITY = 0x0A;
|
||||
static const uint8_t MAX7219_REGISTER_SCAN_LIMIT = 0x0B;
|
||||
static const uint8_t MAX7219_REGISTER_SHUTDOWN = 0x0C;
|
||||
static const uint8_t MAX7219_UNKNOWN_CHAR = 0b11111111;
|
||||
|
||||
const uint8_t MAX7219_ASCII_TO_RAW[94] PROGMEM = {
|
||||
0b00000000, // ' ', ord 0x20
|
||||
0b10110000, // '!', ord 0x21
|
||||
0b00100010, // '"', ord 0x22
|
||||
MAX7219_UNKNOWN_CHAR, // '#', ord 0x23
|
||||
MAX7219_UNKNOWN_CHAR, // '$', ord 0x24
|
||||
0b01001001, // '%', ord 0x25
|
||||
MAX7219_UNKNOWN_CHAR, // '&', ord 0x26
|
||||
0b00000010, // ''', ord 0x27
|
||||
0b01001110, // '(', ord 0x28
|
||||
0b01111000, // ')', ord 0x29
|
||||
0b01000000, // '*', ord 0x2A
|
||||
MAX7219_UNKNOWN_CHAR, // '+', ord 0x2B
|
||||
0b00010000, // ',', ord 0x2C
|
||||
0b00000001, // '-', ord 0x2D
|
||||
0b10000000, // '.', ord 0x2E
|
||||
MAX7219_UNKNOWN_CHAR, // '/', ord 0x2F
|
||||
0b01111110, // '0', ord 0x30
|
||||
0b00110000, // '1', ord 0x31
|
||||
0b01101101, // '2', ord 0x32
|
||||
0b01111001, // '3', ord 0x33
|
||||
0b00110011, // '4', ord 0x34
|
||||
0b01011011, // '5', ord 0x35
|
||||
0b01011111, // '6', ord 0x36
|
||||
0b01110000, // '7', ord 0x37
|
||||
0b01111111, // '8', ord 0x38
|
||||
0b01110011, // '9', ord 0x39
|
||||
0b01001000, // ':', ord 0x3A
|
||||
0b01011000, // ';', ord 0x3B
|
||||
MAX7219_UNKNOWN_CHAR, // '<', ord 0x3C
|
||||
MAX7219_UNKNOWN_CHAR, // '=', ord 0x3D
|
||||
MAX7219_UNKNOWN_CHAR, // '>', ord 0x3E
|
||||
0b01100101, // '?', ord 0x3F
|
||||
0b01101111, // '@', ord 0x40
|
||||
0b01110111, // 'A', ord 0x41
|
||||
0b00011111, // 'B', ord 0x42
|
||||
0b01001110, // 'C', ord 0x43
|
||||
0b00111101, // 'D', ord 0x44
|
||||
0b01001111, // 'E', ord 0x45
|
||||
0b01000111, // 'F', ord 0x46
|
||||
0b01011110, // 'G', ord 0x47
|
||||
0b00110111, // 'H', ord 0x48
|
||||
0b00110000, // 'I', ord 0x49
|
||||
0b00111100, // 'J', ord 0x4A
|
||||
MAX7219_UNKNOWN_CHAR, // 'K', ord 0x4B
|
||||
0b00001110, // 'L', ord 0x4C
|
||||
MAX7219_UNKNOWN_CHAR, // 'M', ord 0x4D
|
||||
0b00010101, // 'N', ord 0x4E
|
||||
0b01111110, // 'O', ord 0x4F
|
||||
0b01100111, // 'P', ord 0x50
|
||||
0b11111110, // 'Q', ord 0x51
|
||||
0b00000101, // 'R', ord 0x52
|
||||
0b01011011, // 'S', ord 0x53
|
||||
0b00000111, // 'T', ord 0x54
|
||||
0b00111110, // 'U', ord 0x55
|
||||
0b00111110, // 'V', ord 0x56
|
||||
0b00111111, // 'W', ord 0x57
|
||||
MAX7219_UNKNOWN_CHAR, // 'X', ord 0x58
|
||||
0b00100111, // 'Y', ord 0x59
|
||||
0b01101101, // 'Z', ord 0x5A
|
||||
0b01001110, // '[', ord 0x5B
|
||||
MAX7219_UNKNOWN_CHAR, // '\', ord 0x5C
|
||||
0b01111000, // ']', ord 0x5D
|
||||
MAX7219_UNKNOWN_CHAR, // '^', ord 0x5E
|
||||
0b00001000, // '_', ord 0x5F
|
||||
0b00100000, // '`', ord 0x60
|
||||
0b01110111, // 'a', ord 0x61
|
||||
0b00011111, // 'b', ord 0x62
|
||||
0b00001101, // 'c', ord 0x63
|
||||
0b00111101, // 'd', ord 0x64
|
||||
0b01001111, // 'e', ord 0x65
|
||||
0b01000111, // 'f', ord 0x66
|
||||
0b01011110, // 'g', ord 0x67
|
||||
0b00010111, // 'h', ord 0x68
|
||||
0b00010000, // 'i', ord 0x69
|
||||
0b00111100, // 'j', ord 0x6A
|
||||
MAX7219_UNKNOWN_CHAR, // 'k', ord 0x6B
|
||||
0b00001110, // 'l', ord 0x6C
|
||||
MAX7219_UNKNOWN_CHAR, // 'm', ord 0x6D
|
||||
0b00010101, // 'n', ord 0x6E
|
||||
0b00011101, // 'o', ord 0x6F
|
||||
0b01100111, // 'p', ord 0x70
|
||||
MAX7219_UNKNOWN_CHAR, // 'q', ord 0x71
|
||||
0b00000101, // 'r', ord 0x72
|
||||
0b01011011, // 's', ord 0x73
|
||||
0b00000111, // 't', ord 0x74
|
||||
0b00011100, // 'u', ord 0x75
|
||||
0b00011100, // 'v', ord 0x76
|
||||
MAX7219_UNKNOWN_CHAR, // 'w', ord 0x77
|
||||
MAX7219_UNKNOWN_CHAR, // 'x', ord 0x78
|
||||
0b00100111, // 'y', ord 0x79
|
||||
MAX7219_UNKNOWN_CHAR, // 'z', ord 0x7A
|
||||
0b00110001, // '{', ord 0x7B
|
||||
0b00000110, // '|', ord 0x7C
|
||||
0b00000111, // '}', ord 0x7D
|
||||
};
|
||||
|
||||
float MAX7219Component::get_setup_priority() const { return setup_priority::PROCESSOR; }
|
||||
void MAX7219Component::setup() {
|
||||
ESP_LOGCONFIG(TAG, "Setting up MAX7219...");
|
||||
this->spi_setup();
|
||||
this->buffer_ = new uint8_t[this->num_chips_ * 8];
|
||||
for (uint8_t i = 0; i < this->num_chips_ * 8; i++)
|
||||
this->buffer_[i] = 0;
|
||||
|
||||
// let's assume the user has all 8 digits connected, only important in daisy chained setups anyway
|
||||
this->send_to_all_(MAX7219_REGISTER_SCAN_LIMIT, 7);
|
||||
// let's use our own ASCII -> led pattern encoding
|
||||
this->send_to_all_(MAX7219_REGISTER_DECODE_MODE, 0);
|
||||
this->send_to_all_(MAX7219_REGISTER_INTENSITY, this->intensity_);
|
||||
this->display();
|
||||
// power up
|
||||
this->send_to_all_(MAX7219_REGISTER_SHUTDOWN, 1);
|
||||
}
|
||||
void MAX7219Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "MAX7219:");
|
||||
ESP_LOGCONFIG(TAG, " Number of Chips: %u", this->num_chips_);
|
||||
ESP_LOGCONFIG(TAG, " Intensity: %u", this->intensity_);
|
||||
LOG_PIN(" CS Pin: ", this->cs_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
}
|
||||
|
||||
void MAX7219Component::display() {
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
this->enable();
|
||||
for (uint8_t j = 0; j < this->num_chips_; j++) {
|
||||
this->send_byte_(8 - i, this->buffer_[j * 8 + i]);
|
||||
}
|
||||
this->disable();
|
||||
}
|
||||
}
|
||||
void MAX7219Component::send_byte_(uint8_t a_register, uint8_t data) {
|
||||
this->write_byte(a_register);
|
||||
this->write_byte(data);
|
||||
}
|
||||
void MAX7219Component::send_to_all_(uint8_t a_register, uint8_t data) {
|
||||
this->enable();
|
||||
for (uint8_t i = 0; i < this->num_chips_; i++)
|
||||
this->send_byte_(a_register, data);
|
||||
this->disable();
|
||||
}
|
||||
bool MAX7219Component::is_device_msb_first() { return true; }
|
||||
void MAX7219Component::update() {
|
||||
for (uint8_t i = 0; i < this->num_chips_ * 8; i++)
|
||||
this->buffer_[i] = 0;
|
||||
if (this->writer_.has_value())
|
||||
(*this->writer_)(*this);
|
||||
this->display();
|
||||
}
|
||||
uint8_t MAX7219Component::print(uint8_t start_pos, const char *str) {
|
||||
uint8_t pos = start_pos;
|
||||
for (; *str != '\0'; str++) {
|
||||
uint8_t data = MAX7219_UNKNOWN_CHAR;
|
||||
if (*str >= ' ' && *str <= '}')
|
||||
data = pgm_read_byte(&MAX7219_ASCII_TO_RAW[*str - ' ']);
|
||||
|
||||
if (data == MAX7219_UNKNOWN_CHAR) {
|
||||
ESP_LOGW(TAG, "Encountered character '%c' with no MAX7219 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, "MAX7219 String is too long for the display!");
|
||||
break;
|
||||
}
|
||||
this->buffer_[pos] = data;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return pos - start_pos;
|
||||
}
|
||||
uint8_t MAX7219Component::print(const char *str) { return this->print(0, str); }
|
||||
uint8_t MAX7219Component::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 MAX7219Component::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 MAX7219Component::set_writer(max7219_writer_t &&writer) { this->writer_ = writer; }
|
||||
void MAX7219Component::set_intensity(uint8_t intensity) { this->intensity_ = intensity; }
|
||||
void MAX7219Component::set_num_chips(uint8_t num_chips) { this->num_chips_ = num_chips; }
|
||||
|
||||
#ifdef USE_TIME
|
||||
uint8_t MAX7219Component::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 MAX7219Component::strftime(const char *format, time::ESPTime time) { return this->strftime(0, format, time); }
|
||||
#endif
|
||||
|
||||
} // namespace max7219
|
||||
} // namespace esphome
|
68
esphome/components/max7219/max7219.h
Normal file
68
esphome/components/max7219/max7219.h
Normal file
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
|
||||
#ifdef USE_TIME
|
||||
#include "esphome/components/time/real_time_clock.h"
|
||||
#endif
|
||||
|
||||
#include "esphome/components/spi/spi.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace max7219 {
|
||||
|
||||
class MAX7219Component;
|
||||
|
||||
using max7219_writer_t = std::function<void(MAX7219Component &)>;
|
||||
|
||||
class MAX7219Component : public PollingComponent, public spi::SPIDevice {
|
||||
public:
|
||||
MAX7219Component(uint32_t update_interval) : PollingComponent(update_interval) {}
|
||||
|
||||
void set_writer(max7219_writer_t &&writer);
|
||||
|
||||
void setup() override;
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
void update() override;
|
||||
|
||||
float get_setup_priority() const override;
|
||||
|
||||
void display();
|
||||
|
||||
void set_intensity(uint8_t intensity);
|
||||
void set_num_chips(uint8_t num_chips);
|
||||
|
||||
/// 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);
|
||||
|
||||
#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
|
||||
|
||||
protected:
|
||||
void send_byte_(uint8_t a_register, uint8_t data);
|
||||
void send_to_all_(uint8_t a_register, uint8_t data);
|
||||
bool is_device_msb_first() override;
|
||||
|
||||
uint8_t intensity_{15}; /// Intensity of the display from 0 to 15 (most)
|
||||
uint8_t num_chips_{1};
|
||||
uint8_t *buffer_;
|
||||
optional<max7219_writer_t> writer_{};
|
||||
};
|
||||
|
||||
} // namespace max7219
|
||||
} // namespace esphome
|
Reference in New Issue
Block a user