mirror of
https://github.com/jdillenburg/esphome.git
synced 2026-01-07 22:20:38 -07:00
I modified the component to remove all Adafruit library dependencies and instead use a lightweight, self-contained ESPHome driver for ADXL345. After these changes, multiple ADXL345 sensors can be used in combination with a TCA9548A I²C multiplexer without conflicts.
308 lines
12 KiB
C++
308 lines
12 KiB
C++
// font_5x7_aa.h - 5x7 pixel anti-aliased font for LED Matrix
|
|
#pragma once
|
|
|
|
#include <cmath>
|
|
|
|
// 5x7 font data - each character is 5 bytes (5 columns x 7 rows)
|
|
// Bit 0 is top row, bit 6 is bottom row
|
|
const uint8_t font_5x7[][5] = {
|
|
{0x00, 0x00, 0x00, 0x00, 0x00}, // 32 space
|
|
{0x00, 0x00, 0x5F, 0x00, 0x00}, // 33 !
|
|
{0x00, 0x07, 0x00, 0x07, 0x00}, // 34 "
|
|
{0x14, 0x7F, 0x14, 0x7F, 0x14}, // 35 #
|
|
{0x24, 0x2A, 0x7F, 0x2A, 0x12}, // 36 $
|
|
{0x23, 0x13, 0x08, 0x64, 0x62}, // 37 %
|
|
{0x36, 0x49, 0x56, 0x20, 0x50}, // 38 &
|
|
{0x00, 0x08, 0x07, 0x03, 0x00}, // 39 '
|
|
{0x00, 0x1C, 0x22, 0x41, 0x00}, // 40 (
|
|
{0x00, 0x41, 0x22, 0x1C, 0x00}, // 41 )
|
|
{0x2A, 0x1C, 0x7F, 0x1C, 0x2A}, // 42 *
|
|
{0x08, 0x08, 0x3E, 0x08, 0x08}, // 43 +
|
|
{0x00, 0x80, 0x70, 0x30, 0x00}, // 44 ,
|
|
{0x08, 0x08, 0x08, 0x08, 0x08}, // 45 -
|
|
{0x00, 0x00, 0x60, 0x60, 0x00}, // 46 .
|
|
{0x20, 0x10, 0x08, 0x04, 0x02}, // 47 /
|
|
{0x3E, 0x51, 0x49, 0x45, 0x3E}, // 48 0
|
|
{0x00, 0x42, 0x7F, 0x40, 0x00}, // 49 1
|
|
{0x72, 0x49, 0x49, 0x49, 0x46}, // 50 2
|
|
{0x21, 0x41, 0x49, 0x4D, 0x33}, // 51 3
|
|
{0x18, 0x14, 0x12, 0x7F, 0x10}, // 52 4
|
|
{0x27, 0x45, 0x45, 0x45, 0x39}, // 53 5
|
|
{0x3C, 0x4A, 0x49, 0x49, 0x31}, // 54 6
|
|
{0x41, 0x21, 0x11, 0x09, 0x07}, // 55 7
|
|
{0x36, 0x49, 0x49, 0x49, 0x36}, // 56 8
|
|
{0x46, 0x49, 0x49, 0x29, 0x1E}, // 57 9
|
|
{0x00, 0x00, 0x14, 0x00, 0x00}, // 58 :
|
|
{0x00, 0x40, 0x34, 0x00, 0x00}, // 59 ;
|
|
{0x00, 0x08, 0x14, 0x22, 0x41}, // 60 <
|
|
{0x14, 0x14, 0x14, 0x14, 0x14}, // 61 =
|
|
{0x00, 0x41, 0x22, 0x14, 0x08}, // 62 >
|
|
{0x02, 0x01, 0x59, 0x09, 0x06}, // 63 ?
|
|
{0x3E, 0x41, 0x5D, 0x59, 0x4E}, // 64 @
|
|
{0x7C, 0x12, 0x11, 0x12, 0x7C}, // 65 A
|
|
{0x7F, 0x49, 0x49, 0x49, 0x36}, // 66 B
|
|
{0x3E, 0x41, 0x41, 0x41, 0x22}, // 67 C
|
|
{0x7F, 0x41, 0x41, 0x41, 0x3E}, // 68 D
|
|
{0x7F, 0x49, 0x49, 0x49, 0x41}, // 69 E
|
|
{0x7F, 0x09, 0x09, 0x09, 0x01}, // 70 F
|
|
{0x3E, 0x41, 0x41, 0x51, 0x73}, // 71 G
|
|
{0x7F, 0x08, 0x08, 0x08, 0x7F}, // 72 H
|
|
{0x00, 0x41, 0x7F, 0x41, 0x00}, // 73 I
|
|
{0x20, 0x40, 0x41, 0x3F, 0x01}, // 74 J
|
|
{0x7F, 0x08, 0x14, 0x22, 0x41}, // 75 K
|
|
{0x7F, 0x40, 0x40, 0x40, 0x40}, // 76 L
|
|
{0x7F, 0x02, 0x1C, 0x02, 0x7F}, // 77 M
|
|
{0x7F, 0x04, 0x08, 0x10, 0x7F}, // 78 N
|
|
{0x3E, 0x41, 0x41, 0x41, 0x3E}, // 79 O
|
|
{0x7F, 0x09, 0x09, 0x09, 0x06}, // 80 P
|
|
{0x3E, 0x41, 0x51, 0x21, 0x5E}, // 81 Q
|
|
{0x7F, 0x09, 0x19, 0x29, 0x46}, // 82 R
|
|
{0x26, 0x49, 0x49, 0x49, 0x32}, // 83 S
|
|
{0x03, 0x01, 0x7F, 0x01, 0x03}, // 84 T
|
|
{0x3F, 0x40, 0x40, 0x40, 0x3F}, // 85 U
|
|
{0x1F, 0x20, 0x40, 0x20, 0x1F}, // 86 V
|
|
{0x3F, 0x40, 0x38, 0x40, 0x3F}, // 87 W
|
|
{0x63, 0x14, 0x08, 0x14, 0x63}, // 88 X
|
|
{0x03, 0x04, 0x78, 0x04, 0x03}, // 89 Y
|
|
{0x61, 0x59, 0x49, 0x4D, 0x43}, // 90 Z
|
|
{0x00, 0x7F, 0x41, 0x41, 0x41}, // 91 [
|
|
{0x02, 0x04, 0x08, 0x10, 0x20}, // 92 backslash
|
|
{0x41, 0x41, 0x41, 0x7F, 0x00}, // 93 ]
|
|
{0x04, 0x02, 0x01, 0x02, 0x04}, // 94 ^
|
|
{0x40, 0x40, 0x40, 0x40, 0x40}, // 95 _
|
|
{0x00, 0x03, 0x07, 0x08, 0x00}, // 96 `
|
|
{0x20, 0x54, 0x54, 0x78, 0x40}, // 97 a
|
|
{0x7F, 0x28, 0x44, 0x44, 0x38}, // 98 b
|
|
{0x38, 0x44, 0x44, 0x44, 0x28}, // 99 c
|
|
{0x38, 0x44, 0x44, 0x28, 0x7F}, // 100 d
|
|
{0x38, 0x54, 0x54, 0x54, 0x18}, // 101 e
|
|
{0x00, 0x08, 0x7E, 0x09, 0x02}, // 102 f
|
|
{0x18, 0xA4, 0xA4, 0x9C, 0x78}, // 103 g
|
|
{0x7F, 0x08, 0x04, 0x04, 0x78}, // 104 h
|
|
{0x00, 0x44, 0x7D, 0x40, 0x00}, // 105 i
|
|
{0x20, 0x40, 0x40, 0x3D, 0x00}, // 106 j
|
|
{0x7F, 0x10, 0x28, 0x44, 0x00}, // 107 k
|
|
{0x00, 0x41, 0x7F, 0x40, 0x00}, // 108 l
|
|
{0x7C, 0x04, 0x78, 0x04, 0x78}, // 109 m
|
|
{0x7C, 0x08, 0x04, 0x04, 0x78}, // 110 n
|
|
{0x38, 0x44, 0x44, 0x44, 0x38}, // 111 o
|
|
{0xFC, 0x18, 0x24, 0x24, 0x18}, // 112 p
|
|
{0x18, 0x24, 0x24, 0x18, 0xFC}, // 113 q
|
|
{0x7C, 0x08, 0x04, 0x04, 0x08}, // 114 r
|
|
{0x48, 0x54, 0x54, 0x54, 0x24}, // 115 s
|
|
{0x04, 0x04, 0x3F, 0x44, 0x24}, // 116 t
|
|
{0x3C, 0x40, 0x40, 0x20, 0x7C}, // 117 u
|
|
{0x1C, 0x20, 0x40, 0x20, 0x1C}, // 118 v
|
|
{0x3C, 0x40, 0x30, 0x40, 0x3C}, // 119 w
|
|
{0x44, 0x28, 0x10, 0x28, 0x44}, // 120 x
|
|
{0x4C, 0x90, 0x90, 0x90, 0x7C}, // 121 y
|
|
{0x44, 0x64, 0x54, 0x4C, 0x44}, // 122 z
|
|
{0x00, 0x08, 0x36, 0x41, 0x00}, // 123 {
|
|
{0x00, 0x00, 0x77, 0x00, 0x00}, // 124 |
|
|
{0x00, 0x41, 0x36, 0x08, 0x00}, // 125 }
|
|
{0x02, 0x01, 0x02, 0x04, 0x02}, // 126 ~
|
|
};
|
|
|
|
// Helper function to draw a character at position
|
|
void draw_char(light::AddressableLight &it, char c, int x_pos, int y_pos, Color color) {
|
|
if (c < 32 || c > 126) return; // Character out of range
|
|
|
|
const uint8_t *char_data = font_5x7[c - 32];
|
|
|
|
for (int col = 0; col < 5; col++) {
|
|
int x = x_pos + col;
|
|
if (x < 0 || x >= 32) continue; // Skip if out of bounds
|
|
|
|
uint8_t column = char_data[col];
|
|
for (int row = 0; row < 7; row++) {
|
|
if (column & (1 << row)) {
|
|
int y = y_pos + row;
|
|
if (y < 0 || y >= 8) continue; // Skip if out of bounds
|
|
|
|
// Convert to LED index with serpentine mapping
|
|
int flipped_y = 7 - y;
|
|
int led_index;
|
|
if (flipped_y % 2 == 0) {
|
|
led_index = flipped_y * 32 + x;
|
|
} else {
|
|
led_index = flipped_y * 32 + (31 - x);
|
|
}
|
|
|
|
if (led_index >= 0 && led_index < 256) {
|
|
it[led_index] = color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper function to draw a string
|
|
void draw_string(light::AddressableLight &it, const std::string &text, int x_pos, int y_pos, Color color) {
|
|
int current_x = x_pos;
|
|
|
|
for (size_t i = 0; i < text.length(); i++) {
|
|
draw_char(it, text[i], current_x, y_pos, color);
|
|
current_x += 6; // 5 pixels for char + 1 pixel spacing
|
|
}
|
|
}
|
|
|
|
// Calculate text width in pixels
|
|
int get_text_width(const std::string &text) {
|
|
return text.length() * 6 - 1; // 6 pixels per char minus 1 for last spacing
|
|
}
|
|
|
|
|
|
// Anti-aliased drawing with sub-pixel positioning
|
|
void draw_char_aa(light::AddressableLight &it, char c, float x_pos, float y_pos, Color color, float brightness = 1.0) {
|
|
if (c < 32 || c > 126) return;
|
|
|
|
const uint8_t *char_data = font_5x7[c - 32];
|
|
|
|
// Calculate fractional offsets
|
|
int x_start = (int)floor(x_pos);
|
|
int y_start = (int)floor(y_pos);
|
|
float x_frac = x_pos - x_start;
|
|
float y_frac = y_pos - y_start;
|
|
|
|
// Draw with 2x2 supersampling for anti-aliasing
|
|
for (int col = 0; col < 5; col++) {
|
|
uint8_t column = char_data[col];
|
|
|
|
for (int row = 0; row < 7; row++) {
|
|
if (column & (1 << row)) {
|
|
// Calculate anti-aliased pixel coverage for 4 affected pixels
|
|
float coverage[2][2] = {
|
|
{(1.0f - x_frac) * (1.0f - y_frac), x_frac * (1.0f - y_frac)},
|
|
{(1.0f - x_frac) * y_frac, x_frac * y_frac}
|
|
};
|
|
|
|
// Draw to up to 4 pixels with appropriate brightness
|
|
for (int dy = 0; dy < 2; dy++) {
|
|
for (int dx = 0; dx < 2; dx++) {
|
|
int x = x_start + col + dx;
|
|
int y = y_start + row + dy;
|
|
|
|
if (x >= 0 && x < 32 && y >= 0 && y < 8) {
|
|
// Convert to LED index
|
|
int flipped_y = 7 - y;
|
|
int led_index;
|
|
if (flipped_y % 2 == 0) {
|
|
led_index = flipped_y * 32 + x;
|
|
} else {
|
|
led_index = flipped_y * 32 + (31 - x);
|
|
}
|
|
|
|
if (led_index >= 0 && led_index < 256) {
|
|
// Apply anti-aliased brightness
|
|
float pixel_brightness = coverage[dy][dx] * brightness;
|
|
|
|
// Blend with existing pixel
|
|
Color existing = it[led_index].get();
|
|
Color new_color(
|
|
existing.r + (color.r - existing.r) * pixel_brightness,
|
|
existing.g + (color.g - existing.g) * pixel_brightness,
|
|
existing.b + (color.b - existing.b) * pixel_brightness
|
|
);
|
|
it[led_index] = new_color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper for edge smoothing using 3x3 kernel
|
|
void apply_edge_smoothing(light::AddressableLight &it, int x, int y, Color color, float strength) {
|
|
// 3x3 Gaussian kernel for smoothing
|
|
const float kernel[3][3] = {
|
|
{0.075f, 0.124f, 0.075f},
|
|
{0.124f, 0.204f, 0.124f},
|
|
{0.075f, 0.124f, 0.075f}
|
|
};
|
|
|
|
for (int dy = -1; dy <= 1; dy++) {
|
|
for (int dx = -1; dx <= 1; dx++) {
|
|
int px = x + dx;
|
|
int py = y + dy;
|
|
|
|
if (px >= 0 && px < 32 && py >= 0 && py < 8) {
|
|
int flipped_y = 7 - py;
|
|
int led_index;
|
|
if (flipped_y % 2 == 0) {
|
|
led_index = flipped_y * 32 + px;
|
|
} else {
|
|
led_index = flipped_y * 32 + (31 - px);
|
|
}
|
|
|
|
if (led_index >= 0 && led_index < 256) {
|
|
float weight = kernel[dy + 1][dx + 1] * strength;
|
|
Color existing = it[led_index].get();
|
|
Color new_color(
|
|
existing.r + (color.r - existing.r) * weight,
|
|
existing.g + (color.g - existing.g) * weight,
|
|
existing.b + (color.b - existing.b) * weight
|
|
);
|
|
it[led_index] = new_color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Improved string drawing with anti-aliasing
|
|
void draw_string_aa(light::AddressableLight &it, const std::string &text, float x_pos, float y_pos, Color color) {
|
|
float current_x = x_pos;
|
|
|
|
for (size_t i = 0; i < text.length(); i++) {
|
|
draw_char_aa(it, text[i], current_x, y_pos, color);
|
|
current_x += 6.0f; // Can use fractional spacing
|
|
}
|
|
}
|
|
|
|
// Alternative: Pre-rendered anti-aliased font (2-bit per pixel)
|
|
// This would store 4 brightness levels per pixel for better quality
|
|
struct AAGlyph {
|
|
uint8_t width;
|
|
uint8_t height;
|
|
uint8_t data[35]; // 5x7 pixels, 2 bits each = 70 bits = ~9 bytes
|
|
};
|
|
|
|
// Function to render with pre-computed anti-aliased glyphs
|
|
void draw_aa_glyph(light::AddressableLight &it, const AAGlyph &glyph, int x, int y, Color color) {
|
|
for (int row = 0; row < glyph.height; row++) {
|
|
for (int col = 0; col < glyph.width; col++) {
|
|
// Extract 2-bit brightness value (0, 85, 170, 255)
|
|
int bit_index = (row * glyph.width + col) * 2;
|
|
int byte_index = bit_index / 8;
|
|
int bit_offset = bit_index % 8;
|
|
|
|
uint8_t brightness_bits = (glyph.data[byte_index] >> bit_offset) & 0x03;
|
|
float brightness = brightness_bits / 3.0f;
|
|
|
|
if (brightness > 0) {
|
|
int px = x + col;
|
|
int py = y + row;
|
|
|
|
if (px >= 0 && px < 32 && py >= 0 && py < 8) {
|
|
int flipped_y = 7 - py;
|
|
int led_index;
|
|
if (flipped_y % 2 == 0) {
|
|
led_index = flipped_y * 32 + px;
|
|
} else {
|
|
led_index = flipped_y * 32 + (31 - px);
|
|
}
|
|
|
|
if (led_index >= 0 && led_index < 256) {
|
|
it[led_index] = Color(
|
|
color.r * brightness,
|
|
color.g * brightness,
|
|
color.b * brightness
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |