Add Litter Box Camera configuration for ESP32-S3 with camera and sensor integration

This commit is contained in:
Joshua King
2026-03-05 16:32:49 -05:00
parent b1bb0deb0e
commit 9b86dca27e

318
esphome/litter-box-cam.yaml Normal file
View File

@@ -0,0 +1,318 @@
# =============================================================================
# LITTER BOX MONITOR - DFRobot ESP32-S3 AI Camera
# =============================================================================
substitutions:
device_name: litter-box-cam
friendly_name: "Litter Box Camera"
# -----------------------------------------------------------------------------
# Core Device Configuration
# -----------------------------------------------------------------------------
esphome:
name: ${device_name}
friendly_name: ${friendly_name}
platformio_options:
build_flags: "-DBOARD_HAS_PSRAM"
board_build.arduino.memory_type: qio_opi
esp32:
board: esp32-s3-devkitc-1
framework:
type: arduino
version: latest
flash_size: 16MB
# -----------------------------------------------------------------------------
# PSRAM Configuration (Critical for camera)
# -----------------------------------------------------------------------------
psram:
mode: octal
speed: 80MHz
# -----------------------------------------------------------------------------
# Logging & API
# -----------------------------------------------------------------------------
logger:
level: INFO
api:
encryption:
key: !secret api_encryption_key
services:
- service: capture_and_analyze
then:
- script.execute: capture_image_script
- service: update_status
variables:
needs_scooping: bool
litter_level_low: bool
cat_present: bool
cleanliness_score: int
then:
- lambda: |-
id(needs_scooping_sensor).publish_state(needs_scooping);
id(litter_level_low_sensor).publish_state(litter_level_low);
id(cat_present_sensor).publish_state(cat_present);
id(cleanliness_score_sensor).publish_state(cleanliness_score);
id(last_analysis_time).publish_state(id(homeassistant_time).now().timestamp);
if (cat_present) {
id(daily_cat_visits) += 1;
id(cat_visits_sensor).publish_state(id(daily_cat_visits));
}
ota:
- platform: esphome
password: !secret ota_password
# -----------------------------------------------------------------------------
# WiFi Configuration
# -----------------------------------------------------------------------------
wifi:
ssid: !secret wifi_iot_ssid
password: !secret wifi_password
ap:
ssid: "${device_name}-AP"
password: !secret wifi_password
captive_portal:
# -----------------------------------------------------------------------------
# MQTT Configuration
# -----------------------------------------------------------------------------
mqtt:
broker: !secret mqtt_broker
username: !secret mqtt_username
password: !secret mqtt_password
topic_prefix: litter_box
# -----------------------------------------------------------------------------
# Time Synchronization
# -----------------------------------------------------------------------------
time:
- platform: homeassistant
id: homeassistant_time
on_time:
- seconds: 0
minutes: 0
hours: 0
then:
- lambda: |-
id(daily_cat_visits) = 0;
id(cat_visits_sensor).publish_state(0);
# -----------------------------------------------------------------------------
# Global Variables
# -----------------------------------------------------------------------------
globals:
- id: daily_cat_visits
type: int
restore_value: yes
initial_value: '0'
- id: motion_cooldown_active
type: bool
initial_value: 'false'
# -----------------------------------------------------------------------------
# Camera Configuration (OV3660 - DFR1154 Specific)
# -----------------------------------------------------------------------------
esp32_camera:
id: litter_cam
name: "Litter Box Camera"
# Hardware Interface - DFR1154 Pinout
external_clock:
pin: GPIO5
frequency: 20MHz
i2c_pins:
sda: GPIO8
scl: GPIO9
data_pins: [GPIO16, GPIO18, GPIO21, GPIO17, GPIO14, GPIO7, GPIO6, GPIO4]
vsync_pin: GPIO1
href_pin: GPIO2
pixel_clock_pin: GPIO15
# Image Parameters
max_framerate: 10 fps
idle_framerate: 0.1 fps
resolution: 800x600
jpeg_quality: 10
vertical_flip: true
horizontal_mirror: false
aec_mode: AUTO
agc_mode: AUTO
wb_mode: AUTO
brightness: 0
contrast: 1
saturation: 0
# Web server for manual viewing
esp32_camera_web_server:
- port: 8080
mode: stream
- port: 8081
mode: snapshot
# -----------------------------------------------------------------------------
# GPIO Outputs
# -----------------------------------------------------------------------------
output:
- id: led_status
platform: gpio
pin: GPIO3
- id: ir_led
platform: gpio
pin: GPIO47
- id: speaker_gain
platform: gpio
pin: GPIO41
- id: speaker_mode
platform: gpio
pin: GPIO40
# -----------------------------------------------------------------------------
# Lights
# -----------------------------------------------------------------------------
light:
- platform: binary
name: "Status LED"
id: status_led
output: led_status
- platform: binary
name: "IR Night Vision"
id: ir_night_vision
output: ir_led
restore_mode: RESTORE_DEFAULT_OFF
# -----------------------------------------------------------------------------
# Binary Sensors
# -----------------------------------------------------------------------------
binary_sensor:
- platform: template
name: "Motion Detected"
id: motion_detected
device_class: motion
- platform: template
name: "Needs Scooping"
id: needs_scooping_sensor
device_class: problem
icon: "mdi:shovel"
- platform: template
name: "Litter Level Low"
id: litter_level_low_sensor
device_class: problem
icon: "mdi:cup-outline"
- platform: template
name: "Cat Present"
id: cat_present_sensor
device_class: occupancy
icon: "mdi:cat"
# -----------------------------------------------------------------------------
# Sensors
# -----------------------------------------------------------------------------
sensor:
- platform: wifi_signal
name: "WiFi Signal"
update_interval: 60s
- platform: template
name: "Cleanliness Score"
id: cleanliness_score_sensor
unit_of_measurement: "%"
icon: "mdi:star"
accuracy_decimals: 0
- platform: template
name: "Daily Cat Visits"
id: cat_visits_sensor
icon: "mdi:paw"
accuracy_decimals: 0
- platform: template
name: "Last Analysis"
id: last_analysis_time
device_class: timestamp
icon: "mdi:clock-outline"
# -----------------------------------------------------------------------------
# Text Sensors
# -----------------------------------------------------------------------------
text_sensor:
- platform: version
name: "ESPHome Version"
- platform: template
name: "Status Message"
id: status_message
icon: "mdi:message-text"
# -----------------------------------------------------------------------------
# Switches
# -----------------------------------------------------------------------------
switch:
- platform: restart
name: "Restart Camera"
- platform: template
name: "Auto Capture Enabled"
id: auto_capture_enabled
optimistic: true
restore_mode: RESTORE_DEFAULT_ON
# -----------------------------------------------------------------------------
# Buttons
# -----------------------------------------------------------------------------
button:
- platform: template
name: "Capture Now"
icon: "mdi:camera"
on_press:
- script.execute: capture_image_script
# -----------------------------------------------------------------------------
# Scripts
# -----------------------------------------------------------------------------
script:
- id: capture_image_script
mode: single
then:
- lambda: 'ESP_LOGI("capture", "Capturing image...");'
- light.turn_on: status_led
- delay: 200ms
- lambda: |-
auto cam = id(litter_cam);
camera::Camera::FrameBuffer *fb = cam->get_image();
if (fb) {
size_t out_len = 4 * ((fb->length + 2) / 3);
char *base64_buffer = (char *)malloc(out_len + 1);
if (base64_buffer) {
size_t encoded_len = 0;
int ret = mbedtls_base64_encode(
(unsigned char *)base64_buffer, out_len + 1, &encoded_len,
fb->buf, fb->length);
if (ret == 0) {
base64_buffer[encoded_len] = '\0';
id(mqtt_client).publish("litter_box/camera/image", base64_buffer);
ESP_LOGI("capture", "Published image");
id(status_message).publish_state("Image sent for analysis");
}
free(base64_buffer);
}
cam->return_image(fb);
}
- light.turn_off: status_led
- lambda: 'id(motion_cooldown_active) = true;'
- delay: 30s
- lambda: 'id(motion_cooldown_active) = false;'