Skip to content

Instantly share code, notes, and snippets.

@selvakn
Last active June 6, 2026 08:10
Show Gist options
  • Select an option

  • Save selvakn/66d22aae465e9525a84507266d93d6e2 to your computer and use it in GitHub Desktop.

Select an option

Save selvakn/66d22aae465e9525a84507266d93d6e2 to your computer and use it in GitHub Desktop.
esphome:
name: indriya-1
on_boot:
- priority: 850
then:
# Strip driver + RMT init; without a short delay first frames are sometimes dropped.
- delay: 200ms
- script.execute: cycle_status_led_pattern
esp32:
board: esp32dev
framework:
type: arduino
logger:
level: DEBUG
wifi:
ssid: iot-workshop
password: !secret wifi_password
mqtt:
broker: 143.110.189.219
port: 5883
discovery: false
ota:
- platform: esphome
password: !secret ota_password
globals:
- id: led_pattern_index
type: int
restore_value: no
initial_value: "0"
# ==================================
# I2C Bus Configuration
# ==================================
i2c:
sda: GPIO21
scl: GPIO22
scan: true
# ESP32 default I2C timeout is 100us and often triggers "I2C hardware timeout"
# with BME280 / shared bus; allow up to 13ms (ESP32 driver maximum).
frequency: 50kHz
timeout: 13ms
# ==================================
# I2C Sensors
# ==================================
sensor:
- platform: bme280_i2c
temperature:
name: "BME280 Temperature"
id: bme280_temperature
pressure:
name: "BME280 Pressure"
id: bme280_pressure
humidity:
name: "BME280 Humidity"
id: bme280_humidity
address: 0x76 # Common addresses are 0x76 or 0x77. Change to 0x77 if it fails to initialize.
update_interval: 60s
- platform: vl53l0x
id: lidar_distance
name: "Lidar Distance"
address: 0x29
update_interval: 1s
on_value:
then:
- if:
condition:
lambda: |-
return std::isfinite(x) && x < 0.1f;
then:
# Note: trailing digit after a letter is octave (4–7), not duration. Use 8c for an eighth note.
- rtttl.play: "close:d=4,o=6,b=200:8c,8e,8g,8e,8c"
# ==================================
# Analog Sensors (ADC)
# ==================================
- platform: adc
pin: GPIO25
id: ldr_voltage
name: "LDR Light Level"
update_interval: 10s
attenuation: 12db # Required for reading up to ~3.3V (11db deprecated)
# ==================================
# Digital Inputs (Binary Sensors)
# ==================================
binary_sensor:
- platform: gpio
pin: GPIO27
name: "PIR Motion Sensor"
device_class: motion
# Sound module digital output (DO) — threshold is set on the module potentiometer.
- platform: gpio
pin: GPIO5
id: microphone_digital
name: "Microphone (digital)"
device_class: sound
filters:
- delayed_on: 40ms
- delayed_off: 120ms
# ==================================
# Display (Assumed SSD1306)
# ==================================
font:
- file: "gfonts://Roboto"
id: roboto
size: 14
- file: "gfonts://Roboto"
id: roboto_sm
size: 10
display:
- platform: ssd1306_i2c
model: "SSD1306 128x64" # Adjust model if your screen is different
address: 0x3C
update_interval: 500ms
lambda: |-
const int lh = 13;
int y = 0;
it.print(0, y, id(roboto), "indriya-1");
y = 16;
if (id(bme280_temperature).has_state() && id(bme280_humidity).has_state()) {
it.printf(0, y, id(roboto_sm), "T:%.1fC RH:%.0f%%",
id(bme280_temperature).state, id(bme280_humidity).state);
} else {
it.print(0, y, id(roboto_sm), "T:-- RH:--");
}
y += lh;
if (id(bme280_pressure).has_state()) {
if (id(lidar_distance).has_state()) {
float d = id(lidar_distance).state;
if (std::isfinite(d)) {
it.printf(0, y, id(roboto_sm), "P:%.0f D:%.2fm",
id(bme280_pressure).state, d);
} else {
it.printf(0, y, id(roboto_sm), "P:%.0f D:----",
id(bme280_pressure).state);
}
} else {
it.printf(0, y, id(roboto_sm), "P:%.0f D:--", id(bme280_pressure).state);
}
} else {
it.print(0, y, id(roboto_sm), "P:-- D:--");
}
y += lh;
if (id(ldr_voltage).has_state()) {
const char *mic = id(microphone_digital).state ? "ON" : "off";
it.printf(0, y, id(roboto_sm), "LDR:%.2fV Mic:%s", id(ldr_voltage).state, mic);
} else {
const char *mic = id(microphone_digital).state ? "ON" : "off";
it.printf(0, y, id(roboto_sm), "LDR:-- Mic:%s", mic);
}
# ==================================
# Outputs & Lighting
# ==================================
light:
- platform: esp32_rmt_led_strip
pin: GPIO32
num_leds: 3
# WS2812 and WS2812B timing: ESPHome only lists WS2812 (not WS2812B).
chipset: WS2812
rgb_order: GRB
# Boards without PSRAM: default use_psram can prevent the strip from working.
use_psram: false
default_transition_length: 0s
name: "Status LEDs"
id: status_leds
effects:
- addressable_rainbow:
name: Rainbow
speed: 12
width: 3
- addressable_scan:
name: Scan
move_interval: 150ms
scan_width: 1
- addressable_twinkle:
name: Twinkle
twinkle_probability: 18%
progress_interval: 6ms
- addressable_color_wipe:
name: Color Wipe
colors:
- red: 100%
green: 0%
blue: 0%
num_leds: 1
- red: 0%
green: 100%
blue: 0%
num_leds: 1
- red: 0%
green: 0%
blue: 100%
num_leds: 1
add_led_interval: 120ms
- addressable_fireworks:
name: Fireworks
update_interval: 40ms
spark_probability: 20%
use_random_color: true
script:
- id: cycle_status_led_pattern
mode: restart
then:
- lambda: |-
static const int k_n = 5;
static const char *const k_patterns[k_n] = {
"Rainbow", "Scan", "Twinkle", "Color Wipe", "Fireworks",
};
int i = id(led_pattern_index);
auto call = id(status_leds).turn_on();
call.set_effect(k_patterns[i]);
call.perform();
id(led_pattern_index) = (i + 1) % k_n;
interval:
- interval: 8s
then:
- script.execute: cycle_status_led_pattern
# ==================================
# Buzzer (Using LEDC for PWM Tones)
# ==================================
output:
- platform: ledc
pin: GPIO18
id: buzzer_pwm
# Optional: Add RTTTL platform to play ringtones via the buzzer
rtttl:
output: buzzer_pwm
# ==================================
# Infrared (IR) Components
# ==================================
remote_receiver:
pin:
number: GPIO15
inverted: true # Standard for IR receivers
remote_transmitter:
pin: GPIO23
carrier_duty_percent: 50%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment