matthiazzz - The current adxl345 component in ESPHome relies on multiple external Adafruit libraries (Adafruit Unified Sensor, Adafruit BusIO, Adafruit ADXL345). This causes unnecessary dependencies, compilation overhead, and sometimes incompatibilities when used with tca9548a multiplexers.

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.
This commit is contained in:
John Dillenburg
2025-09-06 15:38:59 -05:00
parent 1176f8d9f9
commit 7dc846a6eb
31 changed files with 713 additions and 2289 deletions

View File

@@ -53,7 +53,8 @@ esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
level: WARN
@@ -197,11 +198,11 @@ number:
- script.execute: start_motor_if_needed
light:
- platform: neopixelbus
variant: WS2812
- platform: esp32_rmt_led_strip
chipset: WS2811
pin: GPIO8
num_leds: 1
type: GRB
rgb_order: GRB
restore_mode: RESTORE_DEFAULT_ON
id: onboard_led
name: "Status light"

View File

@@ -6,7 +6,6 @@ from esphome.components import i2c, sensor
DEPENDENCIES = ['i2c']
AUTO_LOAD = ['sensor']
MULTI_CONF = True
CODEOWNERS = ["@jdillenburg"]
adxl345_ns = cg.esphome_ns.namespace('adxl345')
ADXL345Component = adxl345_ns.class_('ADXL345Component', cg.PollingComponent, i2c.I2CDevice)
@@ -61,17 +60,15 @@ CONFIG_SCHEMA = cv.Schema({
accuracy_decimals=3,
state_class=STATE_CLASS_MEASUREMENT,
),
}).extend(cv.polling_component_schema("100ms")).extend(i2c.i2c_device_schema(0x53))
}).extend(cv.polling_component_schema("1s")).extend(i2c.i2c_device_schema(0x53))
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await i2c.register_i2c_device(var, config)
# Configure the range
cg.add(var.set_range(config[CONF_RANGE]))
# Register sensors if configured
if CONF_OFF_VERTICAL in config:
sens = await sensor.new_sensor(config[CONF_OFF_VERTICAL])
cg.add(var.set_off_vertical_sensor(sens))
@@ -90,4 +87,4 @@ async def to_code(config):
if CONF_ACCEL_Z in config:
sens = await sensor.new_sensor(config[CONF_ACCEL_Z])
cg.add(var.set_accel_z_sensor(sens))
cg.add(var.set_accel_z_sensor(sens))

View File

@@ -1,41 +1,44 @@
#include "adxl345.h"
##include "adxl345.h"
#include "esphome/core/log.h"
#include <cmath>
namespace esphome {
namespace adxl345 {
static const char *const TAG = "adxl345";
// Register map
static const uint8_t REG_DEVID = 0x00;
static const uint8_t REG_POWER_CTL = 0x2D;
static const uint8_t REG_DATA_FORMAT = 0x31;
static const uint8_t REG_DATAX0 = 0x32;
void ADXL345Component::setup() {
ESP_LOGCONFIG(TAG, "Setting up ADXL345...");
if (!accel_.begin(this->address_)) {
ESP_LOGE(TAG, "Could not find ADXL345 sensor at address 0x%02X!", this->address_);
// Check device ID
uint8_t devid;
if (this->read_register(REG_DEVID, &devid, 1) != i2c::ERROR_OK || devid != 0xE5) {
ESP_LOGE(TAG, "ADXL345 not found at 0x%02X (id=0x%02X)", this->address_, devid);
this->mark_failed();
return;
}
// Map our range enum values to Adafruit library constants
range_t adafruit_range;
ESP_LOGI(TAG, "Found ADXL345 at 0x%02X", this->address_);
// Set range
uint8_t range_bits = 0;
switch (this->range_) {
case 0: // RANGE_2G
adafruit_range = ADXL345_RANGE_2_G;
break;
case 1: // RANGE_4G
adafruit_range = ADXL345_RANGE_4_G;
break;
case 2: // RANGE_8G
adafruit_range = ADXL345_RANGE_8_G;
break;
case 3: // RANGE_16G
adafruit_range = ADXL345_RANGE_16_G;
break;
default:
adafruit_range = ADXL345_RANGE_2_G;
break;
case 0: range_bits = 0x00; break; // ±2g
case 1: range_bits = 0x01; break; // ±4g
case 2: range_bits = 0x02; break; // ±8g
case 3: range_bits = 0x03; break; // ±16g
}
accel_.setRange(adafruit_range);
this->write_register(REG_DATA_FORMAT, &range_bits, 1);
// Enable measurement mode
uint8_t power = 0x08;
this->write_register(REG_POWER_CTL, &power, 1);
ESP_LOGD(TAG, "ADXL345 setup complete");
}
@@ -43,7 +46,7 @@ void ADXL345Component::dump_config() {
ESP_LOGCONFIG(TAG, "ADXL345:");
LOG_I2C_DEVICE(this);
LOG_UPDATE_INTERVAL(this);
const char* range_str;
switch (this->range_) {
case 0: range_str = "2G"; break;
@@ -53,57 +56,46 @@ void ADXL345Component::dump_config() {
default: range_str = "Unknown"; break;
}
ESP_LOGCONFIG(TAG, " Range: %s", range_str);
if (this->off_vertical_ != nullptr) {
LOG_SENSOR(" ", "Off Vertical", this->off_vertical_);
}
if (this->jitter_ != nullptr) {
LOG_SENSOR(" ", "Jitter", this->jitter_);
}
if (this->accel_x_ != nullptr) {
LOG_SENSOR(" ", "Acceleration X", this->accel_x_);
}
if (this->accel_y_ != nullptr) {
LOG_SENSOR(" ", "Acceleration Y", this->accel_y_);
}
if (this->accel_z_ != nullptr) {
LOG_SENSOR(" ", "Acceleration Z", this->accel_z_);
}
if (this->off_vertical_ != nullptr) LOG_SENSOR(" ", "Off Vertical", this->off_vertical_);
if (this->jitter_ != nullptr) LOG_SENSOR(" ", "Jitter", this->jitter_);
if (this->accel_x_ != nullptr) LOG_SENSOR(" ", "Acceleration X", this->accel_x_);
if (this->accel_y_ != nullptr) LOG_SENSOR(" ", "Acceleration Y", this->accel_y_);
if (this->accel_z_ != nullptr) LOG_SENSOR(" ", "Acceleration Z", this->accel_z_);
}
void ADXL345Component::update() {
sensors_event_t event;
accel_.getEvent(&event);
// Publish raw accelerometer values if sensors are configured
if (this->accel_x_ != nullptr) {
this->accel_x_->publish_state(event.acceleration.x);
uint8_t buffer[6];
if (this->read_register(REG_DATAX0, buffer, 6) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Failed to read data");
return;
}
if (this->accel_y_ != nullptr) {
this->accel_y_->publish_state(event.acceleration.y);
}
if (this->accel_z_ != nullptr) {
this->accel_z_->publish_state(event.acceleration.z);
}
// Calculate and publish off_vertical if sensor is configured
int16_t raw_x = (int16_t)(buffer[1] << 8 | buffer[0]);
int16_t raw_y = (int16_t)(buffer[3] << 8 | buffer[2]);
int16_t raw_z = (int16_t)(buffer[5] << 8 | buffer[4]);
// Scale: 4 mg/LSB in full-res mode (0.004 g), convert to m/s²
float scale = 0.004f * 9.80665f;
float x = raw_x * scale;
float y = raw_y * scale;
float z = raw_z * scale;
if (this->accel_x_ != nullptr) this->accel_x_->publish_state(x);
if (this->accel_y_ != nullptr) this->accel_y_->publish_state(y);
if (this->accel_z_ != nullptr) this->accel_z_->publish_state(z);
if (this->off_vertical_ != nullptr) {
double pitch_amount = atan(event.acceleration.y /
sqrt(pow(event.acceleration.x, 2) + pow(event.acceleration.z, 2))) * 180 / PI;
double roll_amount = atan(-1 * event.acceleration.x /
sqrt(pow(event.acceleration.y, 2) + pow(event.acceleration.z, 2))) * 180 / PI;
this->off_vertical_->publish_state(max(abs(pitch_amount), abs(roll_amount)));
double pitch = atan(y / sqrt(pow(x, 2) + pow(z, 2))) * 180.0 / M_PI;
double roll = atan(-x / sqrt(pow(y, 2) + pow(z, 2))) * 180.0 / M_PI;
this->off_vertical_->publish_state(std::max(std::abs(pitch), std::abs(roll)));
}
// Calculate and publish jitter if sensor is configured
if (this->jitter_ != nullptr) {
float jitter_value = abs(event.acceleration.x) + abs(event.acceleration.y) + abs(event.acceleration.z);
this->jitter_->publish_state(jitter_value);
float jitter = fabs(x) + fabs(y) + fabs(z);
this->jitter_->publish_state(jitter);
}
}
} // namespace adxl345
} // namespace esphome
} // namespace adxl345
} // namespace esphome

View File

@@ -3,16 +3,13 @@
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_ADXL345_U.h>
namespace esphome {
namespace adxl345 {
class ADXL345Component : public PollingComponent, public i2c::I2CDevice {
public:
ADXL345Component() : PollingComponent(100) {}
ADXL345Component() : PollingComponent(1000) {}
void setup() override;
void update() override;
@@ -23,18 +20,16 @@ class ADXL345Component : public PollingComponent, public i2c::I2CDevice {
void set_accel_x_sensor(sensor::Sensor *accel_x) { accel_x_ = accel_x; }
void set_accel_y_sensor(sensor::Sensor *accel_y) { accel_y_ = accel_y; }
void set_accel_z_sensor(sensor::Sensor *accel_z) { accel_z_ = accel_z; }
void set_range(uint8_t range) { range_ = range; }
protected:
Adafruit_ADXL345_Unified accel_{12345};
sensor::Sensor *off_vertical_{nullptr};
sensor::Sensor *jitter_{nullptr};
sensor::Sensor *accel_x_{nullptr};
sensor::Sensor *accel_y_{nullptr};
sensor::Sensor *accel_z_{nullptr};
uint8_t range_{0}; // Default to 2G range (0)
uint8_t range_{0}; // Default 2G
};
} // namespace adxl345
} // namespace esphome
} // namespace adxl345
} // namespace esphome

308
font_5x7_aa.h Normal file
View File

@@ -0,0 +1,308 @@
// 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
);
}
}
}
}
}
}

199
font_aa_generated.h Normal file
View File

@@ -0,0 +1,199 @@
// font_aa_generated.h - Anti-aliased font for LED Matrix
// Generated from TrueType font with 4-level anti-aliasing
#pragma once
#include <cstdint>
struct AAChar {
uint8_t width;
uint8_t data[16]; // 8x8 pixels, 2 bits each = 128 bits = 16 bytes
};
// Anti-aliased font data for ASCII 32-126
const AAChar aa_font[] = {
{8, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 32 ' '
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 33 '!'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 34 '\"'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 35 '#'
{5, {0x00, 0x00, 0x00, 0x00, 0x90, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 36 '$'
{6, {0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0xA0, 0x01, 0x40, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 37 '%'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x01, 0x90, 0x02, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 38 '&'
{4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 39 '\''
{4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 40 '('
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 41 ')'
{4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 42 '*'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 43 '+'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 44 ','
{4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 45 '-'
{8, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 46 '.'
{4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 47 '/'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50, 0x01, 0x50, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 48 '0'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 49 '1'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x00, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 50 '2'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 51 '3'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x90, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 52 '4'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 53 '5'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x90, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 54 '6'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 55 '7'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x01, 0x50, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 56 '8'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x80, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 57 '9'
{8, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 58 ':'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 59 ';'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 60 '<'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 61 '='
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 62 '>'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 63 '?'
{6, {0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x50, 0x05, 0x50, 0x06, 0x90, 0x06, 0x00, 0x00, 0x00, 0x00}}, // 64 '@'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x01, 0x90, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 65 'A'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x02, 0x50, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 66 'B'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x01, 0x50, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 67 'C'
{6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x05, 0x50, 0x05, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 68 'D'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0x50, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 69 'E'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 70 'F'
{6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x01, 0x50, 0x06, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 71 'G'
{6, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x02, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 72 'H'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 73 'I'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 74 'J'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x90, 0x01, 0x90, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 75 'K'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x50, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 76 'L'
{5, {0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x60, 0x02, 0x90, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 77 'M'
{6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x50, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 78 'N'
{6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x05, 0x50, 0x05, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 79 'O'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x02, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 80 'P'
{6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x06, 0x10, 0x04, 0x80, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 81 'Q'
{6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x90, 0x02, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 82 'R'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 83 'S'
{5, {0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 84 'T'
{6, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x50, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 85 'U'
{5, {0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x50, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 86 'V'
{6, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x50, 0x05, 0x50, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 87 'W'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 88 'X'
{5, {0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 89 'Y'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x50, 0x00, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 90 'Z'
{4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 91 '['
{4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 92 '\\'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x01, 0x00, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 93 ']'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 94 '^'
{6, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 95 '_'
{4, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 96 '`'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x01, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 97 'a'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x50, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 98 'b'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 99 'c'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 100 'd'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x90, 0x01, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 101 'e'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 102 'f'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x40, 0x01, 0x40, 0x02, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 103 'g'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x02, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 104 'h'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 105 'i'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 106 'j'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 107 'k'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 108 'l'
{5, {0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x50, 0x01, 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 109 'm'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 110 'n'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50, 0x01, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 111 'o'
{5, {0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x50, 0x01, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 112 'p'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x40, 0x01, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 113 'q'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 114 'r'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80, 0x01, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 115 's'
{4, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 116 't'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 117 'u'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 118 'v'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50, 0x02, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 119 'w'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 120 'x'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 121 'y'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 122 'z'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 123 '{'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}}, // 124 '|'
{5, {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x01, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 125 '}'
{5, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, // 126 '~'
};
// Draw anti-aliased character at position
void draw_aa_char(light::AddressableLight &it, char c, int x_pos, int y_pos, Color color, float alpha = 1.0f) {
if (c < 32 || c > 126) return;
const AAChar &char_data = aa_font[c - 32];
for (int y = 0; y < 8; y++) {
for (int x = 0; x < 8; x++) {
// Extract 2-bit brightness value
int byte_idx = (y * 2) + (x / 4);
int bit_shift = (x % 4) * 2;
uint8_t brightness_level = (char_data.data[byte_idx] >> bit_shift) & 0x03;
if (brightness_level > 0) {
float brightness = (brightness_level / 3.0f) * alpha;
int px = x_pos + x;
int py = y_pos + y;
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) {
// Apply brightness with alpha blending
Color existing = it[led_index].get();
it[led_index] = Color(
existing.r + (color.r - existing.r) * brightness,
existing.g + (color.g - existing.g) * brightness,
existing.b + (color.b - existing.b) * brightness
);
}
}
}
}
}
}
// Draw anti-aliased string at position
void draw_aa_string(light::AddressableLight &it, const std::string &text, int x_pos, int y_pos, Color color, float alpha = 1.0f) {
int current_x = x_pos;
for (char c : text) {
if (c >= 32 && c <= 126) {
draw_aa_char(it, c, current_x, y_pos, color, alpha);
current_x += aa_font[c - 32].width + 1; // Add 1 pixel spacing
}
}
}
// Get width of anti-aliased string in pixels
int get_aa_text_width(const std::string &text) {
int width = 0;
for (size_t i = 0; i < text.length(); i++) {
char c = text[i];
if (c >= 32 && c <= 126) {
width += aa_font[c - 32].width;
if (i < text.length() - 1) width += 1; // spacing
}
}
return width;
}
// Draw with sub-pixel positioning for smooth scrolling
void draw_aa_string_subpixel(light::AddressableLight &it, const std::string &text, float x_pos, float y_pos, Color color) {
float current_x = x_pos;
for (char c : text) {
if (c >= 32 && c <= 126) {
int x_int = (int)x_pos;
float x_frac = x_pos - x_int;
// Draw character at two positions with appropriate alpha
if (x_frac > 0.01f) {
draw_aa_char(it, c, x_int, (int)y_pos, color, 1.0f - x_frac);
draw_aa_char(it, c, x_int + 1, (int)y_pos, color, x_frac);
} else {
draw_aa_char(it, c, x_int, (int)y_pos, color, 1.0f);
}
current_x += aa_font[c - 32].width + 1;
}
}
}

View File

@@ -16,7 +16,7 @@ substitutions:
esp32:
board: esp32dev
framework:
type: arduino
type: esp-idf
# Enable logging
@@ -265,7 +265,6 @@ cover:
#********** LED Strip configuration **********
light:
- platform: esp32_rmt_led_strip
rmt_channel: 1
id: led_strip
chipset: WS2812
pin: GPIO16

120
led_matrix_custom.h Normal file
View File

@@ -0,0 +1,120 @@
// led_matrix_custom.h
// Optional custom functions for the LED matrix
#pragma once
#include "esphome.h"
// Helper function to convert x,y coordinates to serpentine LED index
int xy_to_serpentine(int x, int y) {
// Your layout: bottom-left start, serpentine
// Row 0 (bottom): left to right
// Row 1: right to left
// etc.
if (y < 0 || y >= 8 || x < 0 || x >= 32) {
return -1; // Out of bounds
}
int row = 7 - y; // Flip y coordinate (0 is bottom)
if (row % 2 == 0) {
// Even rows go left to right
return row * 32 + x;
} else {
// Odd rows go right to left
return row * 32 + (31 - x);
}
}
// Draw a pixel at x,y coordinates
void draw_pixel(light::AddressableLight *display, int x, int y, Color color) {
int index = xy_to_serpentine(x, y);
if (index >= 0 && index < 256) {
(*display)[index] = color;
}
}
// Draw a horizontal line
void draw_hline(light::AddressableLight *display, int x, int y, int width, Color color) {
for (int i = 0; i < width; i++) {
draw_pixel(display, x + i, y, color);
}
}
// Draw a vertical line
void draw_vline(light::AddressableLight *display, int x, int y, int height, Color color) {
for (int i = 0; i < height; i++) {
draw_pixel(display, x, y + i, color);
}
}
// Draw a rectangle
void draw_rect(light::AddressableLight *display, int x, int y, int width, int height, Color color, bool filled = false) {
if (filled) {
for (int j = 0; j < height; j++) {
draw_hline(display, x, y + j, width, color);
}
} else {
draw_hline(display, x, y, width, color);
draw_hline(display, x, y + height - 1, width, color);
draw_vline(display, x, y, height, color);
draw_vline(display, x + width - 1, y, height, color);
}
}
// Simple bitmap font (3x5 pixels for numbers)
const uint8_t FONT_3X5[][5] = {
{0x7, 0x5, 0x5, 0x5, 0x7}, // 0
{0x2, 0x6, 0x2, 0x2, 0x7}, // 1
{0x7, 0x1, 0x7, 0x4, 0x7}, // 2
{0x7, 0x1, 0x3, 0x1, 0x7}, // 3
{0x5, 0x5, 0x7, 0x1, 0x1}, // 4
{0x7, 0x4, 0x7, 0x1, 0x7}, // 5
{0x7, 0x4, 0x7, 0x5, 0x7}, // 6
{0x7, 0x1, 0x1, 0x1, 0x1}, // 7
{0x7, 0x5, 0x7, 0x5, 0x7}, // 8
{0x7, 0x5, 0x7, 0x1, 0x7}, // 9
};
// Draw a digit
void draw_digit(light::AddressableLight *display, int x, int y, int digit, Color color) {
if (digit < 0 || digit > 9) return;
for (int row = 0; row < 5; row++) {
uint8_t line = FONT_3X5[digit][row];
for (int col = 0; col < 3; col++) {
if (line & (1 << (2 - col))) {
draw_pixel(display, x + col, y + row, color);
}
}
}
}
// Draw a number (up to 2 digits)
void draw_number(light::AddressableLight *display, int x, int y, int number, Color color) {
if (number < 0 || number > 99) return;
if (number >= 10) {
draw_digit(display, x, y, number / 10, color);
draw_digit(display, x + 4, y, number % 10, color);
} else {
draw_digit(display, x, y, number, color);
}
}
// Scrolling text buffer structure
struct ScrollBuffer {
std::vector<uint8_t> buffer;
int width;
int position;
ScrollBuffer(int w) : width(w), position(0) {}
void scroll() {
position++;
if (position >= width) {
position = 0;
}
}
};

View File

@@ -1,6 +1,18 @@
esphome:
text_sensor:
- platform: wifi_info
ip_address:
id: ip_addr
name: "IP Address"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
on_connect:
then:
- delay: 2s # give the sensor a moment to update
- logger.log:
level: INFO
format: "Connected! IP Address: %s"
args: ["id(ip_addr).state.c_str()"]

View File

@@ -1,46 +0,0 @@
esphome:
name: 3d-printer-camera
friendly_name: 3d-printer-camera
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "+b+DVoSdU4U5jlaO2hMcfj1SpIvrJS0nTY2VRz4ZJ8I="
ota:
password: "eda8ea0564c19dafc36915ef38f83911"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "3D-Printer-Camera"
password: "mhZotMxOa70S"
captive_portal:
esp32_camera:
external_clock:
pin: GPIO21
frequency: 20MHz
i2c_pins:
sda: GPIO26
scl: GPIO27
data_pins: [GPIO4, GPIO5, GPIO18, GPIO19, GPIO36, GPIO39, GPIO34, GPIO35]
vsync_pin: GPIO25
href_pin: GPIO23
pixel_clock_pin: GPIO22
# Image settings
name: Camera
resolution: 1024x768

View File

@@ -1,61 +0,0 @@
esphome:
name: adxl345-test
friendly_name: ADXL345 Test
includes:
- ADXL345.h
libraries:
- "Wire"
- "SPI"
- "Adafruit BusIO"
- "Adafruit Unified Sensor"
- "Adafruit ADXL345"
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "/v0qaJ9WNLlO/ceNxMjQN/4L1kDpg4xF3GB+huSE9uU="
ota:
password: "d29c9732c14ab553c7b61cf7518893b8"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Adxl345-Test Fallback Hotspot"
password: "51tWtojf169e"
captive_portal:
i2c:
sda: 21
scl: 22
scan: true
sensor:
- platform: custom
lambda: |-
auto adxl345 = new ADXL345Sensor();
App.register_component(adxl345);
return {
adxl345->off_vertical
};
sensors:
- name: "Off Vertical"
unit_of_measurement: percentage
filters:
- sliding_window_moving_average:
window_size: 5
send_every: 5
- lambda: return 100 * x / 45.0;

View File

@@ -1,31 +0,0 @@
esphome:
name: basement-stairs-led-controller
friendly_name: basement stairs led controller
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "1zN1Evl3kkRYTLWmSw+iLL6Gpufn/QJru2X17YroAns="
ota:
password: "d980c05ac4810f46717c0d8ea10b3b2b"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Basement-Stairs-Led-Controller"
password: "tJdG3X0m0TcY"
captive_portal:

View File

@@ -1,31 +0,0 @@
esphome:
name: basement-stairs-mini
friendly_name: basement stairs mini
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "He3sclXVKUDGA2Cv7Q0OxiOwpaAQ0CDRL8IkvfT8Zsc="
ota:
password: "8ded3b7c8f13033cbf018b5672b74b21"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Basement-Stairs-Mini"
password: "4HwDF0m7w9Zb"
captive_portal:

View File

@@ -1,39 +0,0 @@
substitutions:
device_name: basement-stairs-mmwave-c3
device_name_pretty: "basement stairs mmwave c3"
esphome:
name: ${device_name}
friendly_name: ${device_name_pretty}
includes:
- leapmmw_sensor.h
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
level: DEBUG #You Can Use "INFO" Level
baud_rate: 0
# Enable Home Assistant API
api:
encryption:
key: "m/VImzYhHfGuPU0NyGGiP/6tJlcv8JPy9pDXG2UtqiE="
ota:
password: "ebfa17f36e2d90de09facad6650e8944"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Basement-Stairs-Mmwave-C3"
password: "uoD8kJDKcaXq"
captive_portal:

View File

@@ -1,199 +0,0 @@
substitutions:
device_name: basement-stairs-mmwave-sensor
device_name_pretty: "basement stairs mmwave sensor"
esphome:
name: ${device_name}
friendly_name: ${device_name_pretty}
includes:
- leapmmw_sensor.h
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
level: DEBUG #You Can Use "INFO" Level
baud_rate: 0
# Enable Home Assistant API
api:
encryption:
key: "gNh+IsnVWnhDp3rXf2hMHB7ZpAx6ScnZo1TCQxYibQg="
ota:
password: "c56a9c1d07dc8f2eff30e19b961b405c"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Basement-Stairs-Mmwave-Sensor"
password: "zwj6vOqPQePO"
captive_portal:
uart:
id: SEN095_UART_BUS
rx_pin: GPIO16
tx_pin: GPIO17
baud_rate: 115200
data_bits: 8
stop_bits: 1
parity: NONE
# Example configuration entry
dfrobot_sen0395:
binary_sensor:
- platform: gpio
name: "${device_name_pretty}"
id: mmwave_presence_detection
device_class: motion
pin:
number: 27
mode: INPUT_PULLDOWN
# when motion is detected, the radar sensor is on so publish radar state to HA
on_press:
then:
lambda: !lambda |-
if (!id(mmwave_sensor).state) {
id(mmwave_sensor).publish_state(true);
}
sensor:
- platform: custom
lambda: |-
auto s = new leapmmw(id(SEN095_UART_BUS));
App.register_component(s);
return {};
sensors:
switch:
- platform: safe_mode
name: use_safe_mode
- platform: template
name: "${device_name_pretty} mmwave_sensor"
id: mmwave_sensor # do not change
entity_category: config
optimistic: true
turn_on_action:
- uart.write: "setUartOutput 1 0"
- delay: 1s
- uart.write: "saveConfig"
- delay: 4s
- uart.write: "sensorStart"
turn_off_action:
- uart.write: "sensorStop"
- delay: 2s
- platform: template
name: "${device_name_pretty} led"
id: led # do not change
entity_category: config
optimistic: true
turn_on_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: "setLedMode 1 0"
- delay: 3s
- lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLedMode 1");
- delay: 2s
- switch.turn_on: mmwave_sensor
turn_off_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: "setLedMode 1 1"
- delay: 3s
- lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLedMode 1");
- delay: 2s
- switch.turn_on: mmwave_sensor
number:
- platform: template
name: "${device_name_pretty} distance"
id: distance # do not change
entity_category: config
min_value: 0.15
max_value: 9.45
step: 0.15
unit_of_measurement: M
mode: box
lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getRange");
return {};
set_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: !lambda
std::string range = "setRange 0 " + str_sprintf("%.2f", x);
return std::vector<unsigned char>(range.begin(), range.end());
- delay: 3s
- switch.turn_on: mmwave_sensor
- platform: template
name: "${device_name_pretty} latency"
id: latency # do not change
entity_category: config
min_value: 1
max_value: 600
lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLatency");
return {};
step: 1
unit_of_measurement: s
mode: box
set_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: !lambda
std::string setL = "setLatency 0.1 " + str_sprintf("%.0f", x);
return std::vector<unsigned char>(setL.begin(), setL.end());
- delay: 3s
- switch.turn_on: mmwave_sensor
- platform: template
name: "${device_name_pretty} sensitivity"
id: sensitivity # do not change
entity_category: config
min_value: 0
max_value: 9
lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getSensitivity");
return {};
step: 1
set_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: !lambda
std::string mss = "setSensitivity " + to_string((int)x);
return std::vector<unsigned char>(mss.begin(), mss.end());
- delay: 3s
- switch.turn_on: mmwave_sensor
button:
- platform: restart
name: Restart_ESP_${device_name}
entity_category: diagnostic
on_press:
- uart.write:
id: SEN095_UART_BUS
data: "resetSystem 0"
- platform: template
name: factory_reset_mmwMCU_${device_name}
id: factory_reset_mmwMCU
entity_category: diagnostic
on_press:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: "resetCfg"
- delay: 3s

View File

@@ -1,232 +0,0 @@
# https://wiki.dfrobot.com/mmWave_Radar_Human_Presence_Detection_SKU_SEN0395
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/hw-reference/esp32c3/user-guide-devkitm-1.html
substitutions:
device_name: basement-stairs-presence-sensor
device_name_pretty: "basement stairs presence sensor"
esphome:
name: ${device_name}
friendly_name: ${device_name_pretty}
includes:
- leapmmw_sensor.h
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "KxojXV7TOX//Kmk+sZZmq4jOXc1DgdJ0Va9SQE4hajk="
ota:
password: "4ad514a273ab653495d4389be22df9e8"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Basement-Stairs-Mmwave-Sensor"
password: "zwj6vOqPQePO"
captive_portal:
uart:
id: SEN095_UART_BUS
rx_pin: GPIO0
tx_pin: GPIO1
baud_rate: 115200
data_bits: 8
stop_bits: 1
parity: NONE
# Example configuration entry
dfrobot_sen0395:
light:
- platform: neopixelbus
id: status_light
type: GRB
variant: WS2811
pin: GPIO8
num_leds: 1
name: "Status Light"
internal: True
binary_sensor:
- platform: gpio
name: "${device_name_pretty}"
id: mmwave_presence_detection
device_class: motion
pin:
number: 10
mode: INPUT_PULLDOWN
# when motion is detected, the radar sensor is on so publish radar state to HA
on_press:
then:
- lambda: !lambda |-
if (!id(mmwave_sensor).state) {
id(mmwave_sensor).publish_state(true);
}
- light.turn_on:
id: status_light
brightness: 100%
red: 100%
green: 0%
blue: 0%
on_release:
then:
- light.turn_off: status_light
sensor:
- platform: custom
lambda: |-
auto s = new leapmmw(id(SEN095_UART_BUS));
App.register_component(s);
return {};
sensors:
- platform: ultrasonic
trigger_pin: 4
echo_pin: 5
name: "Ultrasonic Sensor"
update_interval: 100ms
timeout: 4m
pulse_time: 10us
filters:
- filter_out: nan
- sliding_window_moving_average:
window_size: 10
send_every: 10
switch:
- platform: safe_mode
name: use_safe_mode
- platform: template
name: "${device_name_pretty} mmwave_sensor"
id: mmwave_sensor # do not change
entity_category: config
optimistic: true
turn_on_action:
- uart.write: "setUartOutput 1 0"
- delay: 1s
- uart.write: "saveConfig"
- delay: 4s
- uart.write: "sensorStart"
turn_off_action:
- uart.write: "sensorStop"
- delay: 2s
- platform: template
name: "${device_name_pretty} led"
id: led # do not change
entity_category: config
optimistic: true
turn_on_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: "setLedMode 1 0"
- delay: 3s
- lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLedMode 1");
- delay: 2s
- switch.turn_on: mmwave_sensor
turn_off_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: "setLedMode 1 1"
- delay: 3s
- lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLedMode 1");
- delay: 2s
- switch.turn_on: mmwave_sensor
number:
- platform: template
name: "${device_name_pretty} distance"
id: distance # do not change
entity_category: config
min_value: 0.15
max_value: 9.45
step: 0.15
unit_of_measurement: M
mode: box
lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getRange");
return {};
set_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: !lambda
std::string range = "setRange 0 " + str_sprintf("%.2f", x);
return std::vector<unsigned char>(range.begin(), range.end());
- delay: 3s
- switch.turn_on: mmwave_sensor
- platform: template
name: "${device_name_pretty} latency"
id: latency # do not change
entity_category: config
min_value: 1
max_value: 600
lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLatency");
return {};
step: 1
unit_of_measurement: s
mode: box
set_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: !lambda
std::string setL = "setLatency 0.1 " + str_sprintf("%.0f", x);
return std::vector<unsigned char>(setL.begin(), setL.end());
- delay: 3s
- switch.turn_on: mmwave_sensor
- platform: template
name: "${device_name_pretty} sensitivity"
id: sensitivity # do not change
entity_category: config
min_value: 0
max_value: 9
lambda: |-
leapmmw(id(SEN095_UART_BUS)).getmmwConf("getSensitivity");
return {};
step: 1
set_action:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: !lambda
std::string mss = "setSensitivity " + to_string((int)x);
return std::vector<unsigned char>(mss.begin(), mss.end());
- delay: 3s
- switch.turn_on: mmwave_sensor
button:
- platform: restart
name: Restart_ESP_${device_name}
entity_category: diagnostic
on_press:
- uart.write:
id: SEN095_UART_BUS
data: "resetSystem 0"
- platform: template
name: factory_reset_mmwMCU_${device_name}
id: factory_reset_mmwMCU
entity_category: diagnostic
on_press:
- switch.turn_off: mmwave_sensor
- delay: 2s
- uart.write: "resetCfg"
- delay: 3s

View File

@@ -1,31 +0,0 @@
esphome:
name: basement-stairs-upper-motion-sensor
friendly_name: basement stairs upper motion sensor
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "JAlRbqj1ibnN5gMo3eXS/7jqSaaTbSy09APYSWNUb0c="
ota:
password: "90e404650dd4953147f82e5e257be7b5"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Basement-Stairs-Upper-Motion-Sensor"
password: "higGVbGCXDPT"
captive_portal:

View File

@@ -1,64 +0,0 @@
esphome:
name: "basement-stairs"
friendly_name: basement stairs upper motion
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "J1Pl6cIH8ormuwRNFrCU49bVDtFAOE+4r4oboq8gJnM="
ota:
password: "d735909e801bb482b0989c3befb43865"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Basement-Stairs-Upper-Motion"
password: "sFbohjRvYyMn"
captive_portal:
binary_sensor:
- platform: gpio
pin: GPIO7
name: "PIR Sensor"
device_class: motion
on_press:
then:
light.turn_on:
id: status_light
red: 10%
green: 0%
blue: 0%
on_release:
then:
light.turn_off: status_light
light:
- platform: neopixelbus
id: status_light
type: GRB
variant: WS2811
pin: GPIO8
num_leds: 1
name: "Status Light"
internal: True
- platform: neopixelbus
type: GRB
variant: WS2811
pin: GPIO9
num_leds: 60
name: "Stairs Right"

View File

@@ -1,231 +0,0 @@
esphome:
name: bed-controller
friendly_name: Bed Controller
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "uyMwFllQp/7nzMdnRhAqybJymJ/IjqIl+yf1QtDEw/s="
ota:
password: "db4d5c0eeda9ef797ebbfbaa2b397720"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Bed-Controller Fallback Hotspot"
password: "vHlYMuWAHvnp"
captive_portal:
# Sync time with Home Assistant.
time:
- platform: homeassistant
id: homeassistant_time
# Text sensors with general information.
text_sensor:
# Expose ESPHome version as sensor.
- platform: version
name: ESPHome Version
# Expose WiFi information as sensors.
- platform: wifi_info
ip_address:
name: IP
ssid:
name: SSID
bssid:
name: BSSID
switch:
- platform: restart
name: "Restart"
globals:
- id: min_speed
type: float
restore_value: False
initial_value: '10'
- id: motor_speed
type: float
restore_value: False
initial_value: id(min_speed)
- id: num_speeds
type: int
restore_value: False
initial_value: '4'
output:
- platform: ledc
pin: GPIO32
id: motor_forward_pin
- platform: ledc
pin: GPIO33
id: motor_reverse_pin
- platform: ledc
pin: GPIO25
id: motor_enable
fan:
- platform: hbridge
id: bed_motor
name: "Bed Motor"
pin_a: motor_forward_pin
pin_b: motor_reverse_pin
enable_pin: motor_enable
# enable_pin: motor_enable
decay_mode: slow
number:
- platform: template
name: Lower limit (meters)
id: bed_lower_limit
icon: "mdi:cogs"
optimistic: true
restore_value: true # If you don't want to store the setting at ESP, set it to false.
initial_value: "0.04" # Default bed_lower_limit Setting
min_value: 0.0
max_value: 2.0
step: 0.01
on_value:
then:
- script.execute: start_motor_if_needed
- platform: template
name: Upper limit (meters)
id: bed_upper_limit
icon: "mdi:cogs"
optimistic: true
restore_value: true # If you don't want to store the setting at ESP, set it to false.
initial_value: "0.9" # Default bed_upper_limit Setting
min_value: 0.0
max_value: 2.0
step: 0.01
on_value:
then:
- script.execute: start_motor_if_needed
- platform: template
name: Accuracy
id: accuracy
icon: "mdi:cogs"
optimistic: true
restore_value: true # If you don't want to store the setting at ESP, set it to false.
initial_value: "2.0" # Default accuracy Setting 2%
min_value: 0.0
max_value: 100.0
step: 1.0
on_value:
then:
- script.execute: start_motor_if_needed
- platform: template
name: Desired percentage
id: bed_desired_position
icon: "mdi:cogs"
optimistic: true
restore_value: true # If you don't want to store the setting at ESP, set it to false.
initial_value: "0.0" # Default desired position Setting
min_value: 0.0
max_value: 100.0
step: 1.0
unit_of_measurement: percentage
on_value:
then:
- script.execute: start_motor_if_needed
sensor:
- platform: ultrasonic
trigger_pin: GPIO27
echo_pin: GPIO14
name: "Bed Position"
update_interval: 0.1s
id: bed_position
accuracy_decimals: 0
unit_of_measurement: percentage
filters:
- filter_out: nan
- sliding_window_moving_average:
window_size: 10
send_every: 10
- lambda: return 100.0 * (x - id(bed_lower_limit).state) / ( id(bed_upper_limit).state - id(bed_lower_limit).state );
on_value:
then:
- script.execute: start_motor_if_needed
script:
- id: calc_motor_speed
then:
- lambda: |-
float diff = abs(id(bed_desired_position).state - id(bed_position).state);
float speed_size = 100.0 / id(num_speeds);
if (diff > 20) {
id(motor_speed) = 100.0;
}
else if (diff > 10 && id(num_speeds) > 1) {
id(motor_speed) = speed_size * 2;
}
else {
id(motor_speed) = speed_size;
}
- id: start_motor_if_needed
then:
- script.execute: calc_motor_speed
- if:
condition:
lambda: 'return id(bed_position).state < -id(accuracy).state;'
then:
- logger.log: 'bed lower then lower limit!'
- fan.turn_on:
id: bed_motor
direction: FORWARD
speed:
!lambda |-
return id(motor_speed);
else:
- if:
condition:
lambda: 'return id(bed_position).state > 100.0 + id(accuracy).state;'
then:
- logger.log: 'bed higher than high limit!'
- fan.turn_on:
id: bed_motor
direction: REVERSE
speed:
!lambda |-
return id(motor_speed);
else:
- if:
condition:
- lambda: 'return id(bed_position).state < id(bed_desired_position).state - id(accuracy).state;'
then:
- logger.log: 'bed lower than desired, moving up'
- fan.turn_on:
id: bed_motor
direction: FORWARD
speed:
!lambda |-
return id(motor_speed);
else:
- if:
condition:
- lambda: 'return id(bed_position).state > id(bed_desired_position).state + id(accuracy).state;'
then:
- logger.log: 'bed higher than desired, moving down'
- fan.turn_on:
id: bed_motor
direction: REVERSE
speed:
!lambda |-
return id(motor_speed);
else:
- fan.turn_off: bed_motor

View File

@@ -1,31 +0,0 @@
esphome:
name: corner-sump-pump-water-level-sensor
friendly_name: corner-sump-pump-water-level-sensor
esp32:
board: esp32-c3-devkitm-1
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "/h9vgMgrlzY8kYJAiUxFnk4uEopKs1NsacRHOG7jbKQ="
ota:
password: "2420232558a55e485717e5a3410caac4"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Corner-Sump-Pump-Water-Level-Sensor"
password: "dzFmWniE42y7"
captive_portal:

View File

@@ -1,39 +0,0 @@
esphome:
name: corner-sump-water-level-sensor
friendly_name: corner-sump-water-level-sensor
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "92TRSyzjZq5bbw8/wipmn7zWZWC2XPmxNEbJZv6+M30="
ota:
password: "18cb2f0dd54a6bd7e56c3e5e79efe314"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Corner-Sump-Water-Level-Sensor"
password: "UGeBCJnN3PX2"
captive_portal:
# https://learn.sparkfun.com/tutorials/esp32-thing-plus-hookup-guide/all
# https://esphome.io/components/i2c.html#
# https://learn.sparkfun.com/tutorials/qwiic-ultrasonic-distance-sensor-hc-sr04-hookup-guide/all
i2c:
sda: GPIO01
scl: GPIO02
scan: true
id: bus_a

View File

@@ -1,50 +0,0 @@
esphome:
name: garage-camera
friendly_name: Garage Camera
comment: esp32dev
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "6o4U+71ZOTxfjpi1mTOG6ThajzFEWEyJPJdKk/0nUAg="
ota:
- platform: esphome
password: "ef8d191e2007e0fe89477dd296817f25"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Garage-Camera Fallback Hotspot"
password: "VotNjbPdTfyf"
captive_portal:
esp32_camera:
external_clock:
pin: GPIO21
frequency: 20MHz
i2c_pins:
sda: GPIO26
scl: GPIO27
data_pins: [GPIO4, GPIO5, GPIO18, GPIO19, GPIO36, GPIO39, GPIO34, GPIO35]
vsync_pin: GPIO25
href_pin: GPIO23
pixel_clock_pin: GPIO22
# Image settings
name: Camera
resolution: 1024x768
vertical_flip: false
horizontal_mirror: false

View File

@@ -1,68 +0,0 @@
esphome:
name: garage-ha-master
friendly_name: garage-ha-master
esp32:
board: esp32dev
framework:
type: arduino
# Enable Home Assistant API
api:
encryption:
key: "voq2rWJn8dFl/rtHRAqAnIipjcwWqdh/WAAn6BEle3Y="
ota:
password: "84faa1ee621712bd8c06f8382b7c1fda"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Garage-Ha-Master"
password: "0OyBvaAOSOcL"
captive_portal:
external_components:
- source:
type: git
url: https://github.com/ssieb/custom_components #Thanks for @ssieb components.
components: [ serial ]
# Enable logging
logger:
baud_rate: 0
uart:
rx_pin: GPIO22
tx_pin: GPIO23
baud_rate: 9600
data_bits: 8
stop_bits: 2
parity: NONE
debug:
direction: BOTH
dummy_receiver: false
after:
delimiter: "\n"
sequence:
- lambda: UARTDebug::log_string(direction, bytes);
text_sensor:
- platform: serial
name: Received slave text
id: slave_text
text:
- platform: template
mode: text
name: Send to slave
id: send_to_slave
set_action:
then:
- uart.write: !lambda |-
std::string sendme = x + "\n";
return std::vector<uint8_t>(sendme.begin(), sendme.end());

View File

@@ -1,87 +0,0 @@
packages:
beacon: !include packages/beacon.yaml
esphome:
name: garage-ha-slave
friendly_name: garage-ha-slave
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# do not log to serial
baud_rate: 0
# Enable Home Assistant API
api:
encryption:
key: "SUI+2tAU4QM6jDKw4utdwmpFKyZrvoCD4IyJ8+OmwU4="
# disable reboot because we disconnect to scan wifi
reboot_timeout: 0s
ota:
password: "d55d376ed4bcfee485afea8865120189"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Garage-Ha-Slave Fallback Hotspot"
password: "g3K334QqPiX7"
captive_portal:
esp32_ble_tracker:
scan_parameters:
window: 120ms
external_components:
- source:
type: git
url: https://github.com/ssieb/custom_components #Thanks for @ssieb components.
components: [ serial ]
uart:
rx_pin: GPIO22
tx_pin: GPIO23
baud_rate: 9600
data_bits: 8
stop_bits: 2
parity: NONE
# debug:
# direction: BOTH
# dummy_receiver: false
# after:
# delimiter: "\n"
# sequence:
# - lambda: UARTDebug::log_string(direction, bytes);
text_sensor:
- platform: serial
name: Received master text
id: master_text
- platform: wifi_info
scan_results:
name: ESP Latest Scan Results
id: scan_results
text:
- platform: template
mode: text
name: Send to master
id: send_to_master
set_action:
then:
- uart.write: !lambda |-
std::string sendme = x + "\n";
return std::vector<uint8_t>(sendme.begin(), sendme.end());

View File

@@ -1,70 +0,0 @@
esphome:
name: garage-master
friendly_name: garage-master
comment: esp32dev
esp32:
board: esp32dev
framework:
type: arduino
# Disable logging
logger:
baud_rate: 0
# Enable Home Assistant API
api:
encryption:
key: "RoWkhYIHXIB92Q4zNPcweZvZgWSChT1A1oRmD2hRolk="
ota:
password: "c279b490f4994e36755058ed0e40460b"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Garage-Master Fallback Hotspot"
password: "a5ZRCKrJLKVt"
captive_portal:
uart:
rx_pin: GPIO1
tx_pin: GPIO3
baud_rate: 115200
data_bits: 8
stop_bits: 1
parity: NONE
debug:
direction: BOTH
dummy_receiver: false
after:
delimiter: "\n"
sequence:
- lambda: UARTDebug::log_string(direction, bytes);
external_components:
- source:
type: git
url: https://github.com/ssieb/custom_components #Thanks for @ssieb components.
components: [ serial ]
# text_sensor:
# - platform: serial
# name: Slave text
text:
- platform: template
mode: text
name: Send to slave
id: send_to_slave
set_action:
then:
- uart.write: !lambda |-
std::string sendme = x + "\n";
return std::vector<uint8_t>(sendme.begin(), sendme.end());

View File

@@ -1,69 +0,0 @@
esphome:
name: garage-control-master2
friendly_name: garage-control-master2
esp32:
board: esp32dev
framework:
type: arduino
external_components:
- source:
type: git
url: https://github.com/ssieb/custom_components #Thanks for @ssieb components.
components: [ serial ]
# Enable logging
logger:
baud_rate: 0
# Enable Home Assistant API
api:
encryption:
key: "ku0BYi9By5cFFEYDyETyZmszDR7Jphpz24uJzIbQTrg="
ota:
password: "38913e884c1425dd1757bf7606abf233"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Garage-Master2 Fallback Hotspot"
password: "fRCUAI46FNga"
captive_portal:
uart:
rx_pin: GPIO22
tx_pin: GPIO23
baud_rate: 9600
data_bits: 8
stop_bits: 1
parity: NONE
debug:
direction: BOTH
dummy_receiver: false
after:
delimiter: "\n"
sequence:
- lambda: UARTDebug::log_string(direction, bytes);
text_sensor:
- platform: serial
name: Received slave text
id: slave_text
text:
- platform: template
mode: text
name: Send to slave
id: send_to_slave
set_action:
then:
- uart.write: !lambda |-
std::string sendme = x + "\n";
return std::vector<uint8_t>(sendme.begin(), sendme.end());

View File

@@ -1,63 +0,0 @@
esphome:
name: garage-wifi-slave
friendly_name: garage-wifi-slave
esp32:
board: esp32dev
framework:
type: arduino
# Disable logging
logger:
baud_rate: 0
# Enable Home Assistant API
api:
encryption:
key: "M64t2wRHjGVpPBAu6AxxRKY3WyZLdB3yK7jQOJyE5AU="
ota:
password: "abf5c4123fd2db9bf4c5aef1237f4243"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Garage-Slave Fallback Hotspot"
password: "f2XLmIgz8PaN"
captive_portal:
uart:
rx_pin: GPIO22
tx_pin: GPIO23
baud_rate: 9600
data_bits: 8
stop_bits: 1
parity: NONE
debug:
direction: BOTH
dummy_receiver: false
after:
delimiter: "\n"
sequence:
- lambda: UARTDebug::log_string(direction, bytes);
# text_sensor:
# - platform: serial
# id: master_text
# name: Master text
text:
- platform: template
mode: text
name: Send to master
id: send_to_master
set_action:
then:
- uart.write: !lambda |-
std::string sendme = x + "\n";
return std::vector<uint8_t>(sendme.begin(), sendme.end());

View File

@@ -1,48 +0,0 @@
esphome:
name: hires-camera
friendly_name: HiRes Camera
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "6qCk7lS2wL6m4yWXWy/9vj1/sY2nS3PBHEQNnS3b4z8="
ota:
password: "659656f65e27665316018491a0b247ba"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Hires-Camera Fallback Hotspot"
password: "FMUtqFrZ3eUN"
captive_portal:
esp32_camera:
external_clock:
pin: GPIO21
frequency: 20MHz
i2c_pins:
sda: GPIO26
scl: GPIO27
data_pins: [GPIO4, GPIO5, GPIO18, GPIO19, GPIO36, GPIO39, GPIO34, GPIO35]
vsync_pin: GPIO25
href_pin: GPIO23
pixel_clock_pin: GPIO22
# Image settings
name: Camera
resolution: 1600x1200
jpeg_quality: 20
max_framerate: 20 fps

View File

@@ -1,338 +0,0 @@
# Enable Home Assistant API
api:
encryption:
key: "xyD+0n3g/k38yhwyo8uE2uMZQM/Ik5ltCUKKC3tFCv8="
ota:
password: "f0c5694107ac2f6a4beb6d18b0e39bb5"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
power_save_mode: LIGHT
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Mmwave-Detector1"
password: "qDakHkuHkpRO"
substitutions:
devicename: "mmwave-detector1" #Rename the device what you want.
upper_devicename: ESP Radar #Rename the device what you want.
esphome:
name: $devicename
friendly_name: $devicename
on_boot: #LD1125H Initial Setting
priority: -200
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th1stm = "mth1_mov=" + str_sprintf("%.0f",id(LD1125H_mth1_mov).state) +"\r\n";
return std::vector<uint8_t>(th1stm.begin(), th1stm.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th2stm = "mth2_mov=" + str_sprintf("%.0f",id(LD1125H_mth2_mov).state) +"\r\n";
return std::vector<uint8_t>(th2stm.begin(), th2stm.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th3stm = "mth3_mov=" + str_sprintf("%.0f",id(LD1125H_mth3_mov).state) +"\r\n";
return std::vector<uint8_t>(th3stm.begin(), th3stm.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th1sto = "mth1_occ=" + str_sprintf("%.0f",id(LD1125H_mth1_occ).state) +"\r\n";
return std::vector<uint8_t>(th1sto.begin(), th1sto.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th2sto = "mth2_occ=" + str_sprintf("%.0f",id(LD1125H_mth2_occ).state) +"\r\n";
return std::vector<uint8_t>(th2sto.begin(), th2sto.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th3sto = "mth3_occ=" + str_sprintf("%.0f",id(LD1125H_mth3_occ).state) +"\r\n";
return std::vector<uint8_t>(th3sto.begin(), th3sto.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string rmaxst = "rmax=" + str_sprintf("%.1f",id(LD1125H_rmax).state) +"\r\n";
return std::vector<uint8_t>(rmaxst.begin(), rmaxst.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string getallst = "get_all\r\n";
return std::vector<uint8_t>(getallst.begin(), getallst.end());
esp32:
board: nodemcu-32s
framework:
type: arduino
external_components:
- source:
type: git
url: https://github.com/ssieb/custom_components #Thanks for @ssieb components.
components: [ serial ]
logger:
level: DEBUG #You Can Use "INFO" Level
baud_rate: 0
uart:
id: LD1125H_UART_BUS
rx_pin: GPIO16 #For ESP32, you can use any pin, Recommend Use UART_2, Don't use UART_0, It might Cause Boot Fail or System Hang
tx_pin: GPIO17 #For ESP32, you can use any pin, Recommend Use UART_2, Don't use UART_0, It might Cause Boot Fail or System Hang
baud_rate: 115200
data_bits: 8
stop_bits: 1
parity: NONE
# debug:
# direction: BOTH
# dummy_receiver: false
# after:
# delimiter: "\n"
# sequence:
# - lambda: UARTDebug::log_string(direction, bytes);
globals:
- id: LD1125H_Last_Time
type: time_t
restore_value: no
initial_value: time(NULL)
- id: LD1125H_Last_Mov_Time
type: time_t
restore_value: no
initial_value: time(NULL)
- id: LD1125H_Clearence_Status
type: bool
restore_value: no
initial_value: "false"
status_led:
pin:
number: GPIO2 #ESP32 OnBroad LED
inverted: false
#web_server: #Avoid Using Web Server To Prevent Hang
# port: 80
interval:
- interval: 1s #Clearance Scan Time
setup_priority: -200
then:
lambda: |-
if ((time(NULL)-id(LD1125H_Last_Time))>id(LD1125H_Clear_Time).state) {
if ((id(LD1125H_Clearence_Status) == false) || (id(LD1125H_Occupancy).state != "Clearance")) {
id(LD1125H_Occupancy).publish_state("Clearance");
id(LD1125H_Clearence_Status) = true;
}
if (id(LD1125H_MovOcc_Binary).state == true) {
id(LD1125H_MovOcc_Binary).publish_state(false);
}
if (id(LD1125H_Mov_Binary).state == true) {
id(LD1125H_Mov_Binary).publish_state(false);
}
}
number:
- platform: template
name: ${upper_devicename} LD1125H mth1 mov #mth1 mov is 0~2.8m motion detection threshold.
id: LD1125H_mth1_mov
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "30.0" #Default mth1_mov Setting
min_value: 10.0
max_value: 600.0
step: 5.0
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th1st = "mth1_mov=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th1st.begin(), th1st.end());
- platform: template
name: ${upper_devicename} LD1125H mth2 mov #mth2 mov is 2.8~8m motion detection threshold.
id: LD1125H_mth2_mov
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "15" #Default mth2_mov Setting
min_value: 5
max_value: 300
step: 5
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th2st = "mth2_mov=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th2st.begin(), th2st.end());
- platform: template
name: ${upper_devicename} LD1125H mth3 mov #mth3 mov is above 8m motion detection threshold.
id: LD1125H_mth3_mov
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "6" #Default mth3_mov Setting
min_value: 5
max_value: 200
step: 5
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th3st = "mth3_mov=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th3st.begin(), th3st.end());
- platform: template
name: ${upper_devicename} LD1125H mth1 occ #mth1 occ is 0~2.8m detection threshold.
id: LD1125H_mth1_occ
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "30.0" #Default mth1_mov Setting
min_value: 10.0
max_value: 600.0
step: 5.0
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th1st = "mth1_occ=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th1st.begin(), th1st.end());
- platform: template
name: ${upper_devicename} LD1125H mth2 occ #mth2 occ is 2.8~8m detection threshold.
id: LD1125H_mth2_occ
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "15" #Default mth2_mov Setting
min_value: 5
max_value: 300
step: 5
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th2st = "mth2_occ=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th2st.begin(), th2st.end());
- platform: template
name: ${upper_devicename} LD1125H mth3 occ #mth3 occ is above 8m detection threshold.
id: LD1125H_mth3_occ
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "6" #Default mth3_mov Setting
min_value: 5
max_value: 200
step: 5
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th3st = "mth3_occ=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th3st.begin(), th3st.end());
- platform: template
name: ${upper_devicename} LD1125H rmax #rmax is max detection distance.
id: LD1125H_rmax
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "8" #Default rmax Setting
min_value: 0.4
max_value: 12
step: 0.2
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string rmaxst = "rmax=" + str_sprintf("%.1f",x) +"\r\n";
return std::vector<uint8_t>(rmaxst.begin(), rmaxst.end());
- platform: template
name: ${upper_devicename} LD1125H Clearence Time
id: LD1125H_Clear_Time
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "5" #LD1125H Mov/Occ > Clearence Time Here
min_value: 0.5
max_value: 60
step: 0.5
- platform: template
name: ${upper_devicename} LD1125H Movement Time
id: LD1125H_Mov_Time
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "1" #LD1125H Mov > Occ Time Here
min_value: 0.5
max_value: 10
step: 0.5
sensor:
- platform: template
name: ${upper_devicename} LD1125H Distance
id: LD1125H_Distance
icon: "mdi:signal-distance-variant"
unit_of_measurement: "m"
accuracy_decimals: 2
filters: # Use Fliter To Debounce
- sliding_window_moving_average:
window_size: 8
send_every: 2
- heartbeat: 0.2s
text_sensor:
- platform: serial
uart_id: LD1125H_UART_BUS
name: ${upper_devicename} LD1125H UART Text
id: LD1125H_UART_Text
icon: "mdi:format-text"
internal: False #If Don't Want to See UART Receive Data, Set To True
on_value:
lambda: |-
if (id(LD1125H_UART_Text).state.substr(0,3) == "occ") {
id(LD1125H_Distance).publish_state(atof(id(LD1125H_UART_Text).state.substr(9).c_str()));
if ((time(NULL)-id(LD1125H_Last_Mov_Time))>id(LD1125H_Mov_Time).state) {
id(LD1125H_Occupancy).publish_state("Occupancy");
if (id(LD1125H_MovOcc_Binary).state == false) {
id(LD1125H_MovOcc_Binary).publish_state(true);
}
if (id(LD1125H_Mov_Binary).state == true) {
id(LD1125H_Mov_Binary).publish_state(false);
}
}
if (id(LD1125H_MovOcc_Binary).state == false) {
id(LD1125H_MovOcc_Binary).publish_state(true);
}
id(LD1125H_Last_Time) = time(NULL);
if (id(LD1125H_Clearence_Status) == true) {
id(LD1125H_Clearence_Status) = false;
}
}
else if (id(LD1125H_UART_Text).state.substr(0,3) == "mov") {
id(LD1125H_Distance).publish_state(atof(id(LD1125H_UART_Text).state.substr(9).c_str()));
id(LD1125H_Occupancy).publish_state("Movement");
if (id(LD1125H_MovOcc_Binary).state == false) {
id(LD1125H_MovOcc_Binary).publish_state(true);
}
if (id(LD1125H_Mov_Binary).state == false) {
id(LD1125H_Mov_Binary).publish_state(true);
}
id(LD1125H_Last_Mov_Time) = time(NULL);
id(LD1125H_Last_Time) = time(NULL);
if (id(LD1125H_Clearence_Status) == true) {
id(LD1125H_Clearence_Status) = false;
}
}
- platform: template
name: ${upper_devicename} LD1125H Occupancy Status
id: LD1125H_Occupancy
icon: "mdi:motion-sensor"
binary_sensor:
- platform: template
name: ${upper_devicename} LD1125H Occupancy or Movement
id: LD1125H_MovOcc_Binary
device_class: occupancy
- platform: template
name: ${upper_devicename} LD1125H Movement
id: LD1125H_Mov_Binary
device_class: motion

View File

@@ -1,339 +0,0 @@
# Enable Home Assistant API
api:
encryption:
key: "eBrxqMp+lU7nOEmQBcl5hZsexSr+NcdhF6xa/0HPbig="
ota:
password: "7ca0ac054d39eec0e41ab0e28b7916ee"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Mmwave-Detector3"
password: "xNAPBrJVQfuy"
captive_portal:
substitutions:
devicename: "mmwave-detector3" #Rename the device what you want.
upper_devicename: ESP Radar #Rename the device what you want.
esphome:
name: $devicename
friendly_name: $devicename
on_boot: #LD1125H Initial Setting
priority: -200
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th1stm = "mth1_mov=" + str_sprintf("%.0f",id(LD1125H_mth1_mov).state) +"\r\n";
return std::vector<uint8_t>(th1stm.begin(), th1stm.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th2stm = "mth2_mov=" + str_sprintf("%.0f",id(LD1125H_mth2_mov).state) +"\r\n";
return std::vector<uint8_t>(th2stm.begin(), th2stm.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th3stm = "mth3_mov=" + str_sprintf("%.0f",id(LD1125H_mth3_mov).state) +"\r\n";
return std::vector<uint8_t>(th3stm.begin(), th3stm.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th1sto = "mth1_occ=" + str_sprintf("%.0f",id(LD1125H_mth1_occ).state) +"\r\n";
return std::vector<uint8_t>(th1sto.begin(), th1sto.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th2sto = "mth2_occ=" + str_sprintf("%.0f",id(LD1125H_mth2_occ).state) +"\r\n";
return std::vector<uint8_t>(th2sto.begin(), th2sto.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th3sto = "mth3_occ=" + str_sprintf("%.0f",id(LD1125H_mth3_occ).state) +"\r\n";
return std::vector<uint8_t>(th3sto.begin(), th3sto.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string rmaxst = "rmax=" + str_sprintf("%.1f",id(LD1125H_rmax).state) +"\r\n";
return std::vector<uint8_t>(rmaxst.begin(), rmaxst.end());
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string getallst = "get_all\r\n";
return std::vector<uint8_t>(getallst.begin(), getallst.end());
esp32:
board: nodemcu-32s
framework:
type: arduino
external_components:
- source:
type: git
url: https://github.com/ssieb/custom_components #Thanks for @ssieb components.
components: [ serial ]
logger:
level: DEBUG #You Can Use "INFO" Level
baud_rate: 0
uart:
id: LD1125H_UART_BUS
rx_pin: GPIO16 #For ESP32, you can use any pin, Recommend Use UART_2, Don't use UART_0, It might Cause Boot Fail or System Hang
tx_pin: GPIO17 #For ESP32, you can use any pin, Recommend Use UART_2, Don't use UART_0, It might Cause Boot Fail or System Hang
baud_rate: 115200
data_bits: 8
stop_bits: 1
parity: NONE
# debug:
# direction: BOTH
# dummy_receiver: false
# after:
# delimiter: "\n"
# sequence:
# - lambda: UARTDebug::log_string(direction, bytes);
globals:
- id: LD1125H_Last_Time
type: time_t
restore_value: no
initial_value: time(NULL)
- id: LD1125H_Last_Mov_Time
type: time_t
restore_value: no
initial_value: time(NULL)
- id: LD1125H_Clearence_Status
type: bool
restore_value: no
initial_value: "false"
status_led:
pin:
number: GPIO2 #ESP32 OnBroad LED
inverted: false
#web_server: #Avoid Using Web Server To Prevent Hang
# port: 80
interval:
- interval: 1s #Clearance Scan Time
setup_priority: -200
then:
lambda: |-
if ((time(NULL)-id(LD1125H_Last_Time))>id(LD1125H_Clear_Time).state) {
if ((id(LD1125H_Clearence_Status) == false) || (id(LD1125H_Occupancy).state != "Clearance")) {
id(LD1125H_Occupancy).publish_state("Clearance");
id(LD1125H_Clearence_Status) = true;
}
if (id(LD1125H_MovOcc_Binary).state == true) {
id(LD1125H_MovOcc_Binary).publish_state(false);
}
if (id(LD1125H_Mov_Binary).state == true) {
id(LD1125H_Mov_Binary).publish_state(false);
}
}
number:
- platform: template
name: ${upper_devicename} LD1125H mth1 mov #mth1 mov is 0~2.8m motion detection threshold.
id: LD1125H_mth1_mov
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "30.0" #Default mth1_mov Setting
min_value: 10.0
max_value: 600.0
step: 5.0
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th1st = "mth1_mov=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th1st.begin(), th1st.end());
- platform: template
name: ${upper_devicename} LD1125H mth2 mov #mth2 mov is 2.8~8m motion detection threshold.
id: LD1125H_mth2_mov
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "15" #Default mth2_mov Setting
min_value: 5
max_value: 300
step: 5
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th2st = "mth2_mov=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th2st.begin(), th2st.end());
- platform: template
name: ${upper_devicename} LD1125H mth3 mov #mth3 mov is above 8m motion detection threshold.
id: LD1125H_mth3_mov
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "6" #Default mth3_mov Setting
min_value: 5
max_value: 200
step: 5
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th3st = "mth3_mov=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th3st.begin(), th3st.end());
- platform: template
name: ${upper_devicename} LD1125H mth1 occ #mth1 occ is 0~2.8m detection threshold.
id: LD1125H_mth1_occ
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "30.0" #Default mth1_mov Setting
min_value: 10.0
max_value: 600.0
step: 5.0
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th1st = "mth1_occ=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th1st.begin(), th1st.end());
- platform: template
name: ${upper_devicename} LD1125H mth2 occ #mth2 occ is 2.8~8m detection threshold.
id: LD1125H_mth2_occ
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "15" #Default mth2_mov Setting
min_value: 5
max_value: 300
step: 5
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th2st = "mth2_occ=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th2st.begin(), th2st.end());
- platform: template
name: ${upper_devicename} LD1125H mth3 occ #mth3 occ is above 8m detection threshold.
id: LD1125H_mth3_occ
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "6" #Default mth3_mov Setting
min_value: 5
max_value: 200
step: 5
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string th3st = "mth3_occ=" + str_sprintf("%.0f",x) +"\r\n";
return std::vector<uint8_t>(th3st.begin(), th3st.end());
- platform: template
name: ${upper_devicename} LD1125H rmax #rmax is max detection distance.
id: LD1125H_rmax
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "8" #Default rmax Setting
min_value: 0.4
max_value: 12
step: 0.2
set_action:
then:
- uart.write:
id: LD1125H_UART_BUS
data: !lambda |-
std::string rmaxst = "rmax=" + str_sprintf("%.1f",x) +"\r\n";
return std::vector<uint8_t>(rmaxst.begin(), rmaxst.end());
- platform: template
name: ${upper_devicename} LD1125H Clearence Time
id: LD1125H_Clear_Time
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "5" #LD1125H Mov/Occ > Clearence Time Here
min_value: 0.5
max_value: 60
step: 0.5
- platform: template
name: ${upper_devicename} LD1125H Movement Time
id: LD1125H_Mov_Time
icon: "mdi:cogs"
optimistic: true
restore_value: true #If you don't want to store the setting at ESP, set it to false.
initial_value: "1" #LD1125H Mov > Occ Time Here
min_value: 0.5
max_value: 10
step: 0.5
sensor:
- platform: template
name: ${upper_devicename} LD1125H Distance
id: LD1125H_Distance
icon: "mdi:signal-distance-variant"
unit_of_measurement: "m"
accuracy_decimals: 2
filters: # Use Fliter To Debounce
- sliding_window_moving_average:
window_size: 8
send_every: 2
- heartbeat: 0.2s
text_sensor:
- platform: serial
uart_id: LD1125H_UART_BUS
name: ${upper_devicename} LD1125H UART Text
id: LD1125H_UART_Text
icon: "mdi:format-text"
internal: False #If Don't Want to See UART Receive Data, Set To True
on_value:
lambda: |-
if (id(LD1125H_UART_Text).state.substr(0,3) == "occ") {
id(LD1125H_Distance).publish_state(atof(id(LD1125H_UART_Text).state.substr(9).c_str()));
if ((time(NULL)-id(LD1125H_Last_Mov_Time))>id(LD1125H_Mov_Time).state) {
id(LD1125H_Occupancy).publish_state("Occupancy");
if (id(LD1125H_MovOcc_Binary).state == false) {
id(LD1125H_MovOcc_Binary).publish_state(true);
}
if (id(LD1125H_Mov_Binary).state == true) {
id(LD1125H_Mov_Binary).publish_state(false);
}
}
if (id(LD1125H_MovOcc_Binary).state == false) {
id(LD1125H_MovOcc_Binary).publish_state(true);
}
id(LD1125H_Last_Time) = time(NULL);
if (id(LD1125H_Clearence_Status) == true) {
id(LD1125H_Clearence_Status) = false;
}
}
else if (id(LD1125H_UART_Text).state.substr(0,3) == "mov") {
id(LD1125H_Distance).publish_state(atof(id(LD1125H_UART_Text).state.substr(9).c_str()));
id(LD1125H_Occupancy).publish_state("Movement");
if (id(LD1125H_MovOcc_Binary).state == false) {
id(LD1125H_MovOcc_Binary).publish_state(true);
}
if (id(LD1125H_Mov_Binary).state == false) {
id(LD1125H_Mov_Binary).publish_state(true);
}
id(LD1125H_Last_Mov_Time) = time(NULL);
id(LD1125H_Last_Time) = time(NULL);
if (id(LD1125H_Clearence_Status) == true) {
id(LD1125H_Clearence_Status) = false;
}
}
- platform: template
name: ${upper_devicename} LD1125H Occupancy Status
id: LD1125H_Occupancy
icon: "mdi:motion-sensor"
binary_sensor:
- platform: template
name: ${upper_devicename} LD1125H Occupancy or Movement
id: LD1125H_MovOcc_Binary
device_class: occupancy
- platform: template
name: ${upper_devicename} LD1125H Movement
id: LD1125H_Mov_Binary
device_class: motion

View File

@@ -1,32 +0,0 @@
esphome:
name: mmwave-georgias-room
friendly_name: mmwave-georgias-room
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "vV0VUgxpbVcQrDGzuFY11LcGK5VJqe74NJpIZ3h8JXk="
ota:
- platform: esphome
password: "d97940b1e0e73dec0830379228389185"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Mmwave-Georgias-Room"
password: "vzn4DYKUeR6m"
captive_portal: