Add image publishing functionality to Litter Box Camera: implement base64 encoding and MQTT publishing on image capture
This commit is contained in:
@@ -113,11 +113,15 @@ globals:
|
|||||||
type: int
|
type: int
|
||||||
restore_value: yes
|
restore_value: yes
|
||||||
initial_value: '0'
|
initial_value: '0'
|
||||||
|
|
||||||
- id: motion_cooldown_active
|
- id: motion_cooldown_active
|
||||||
type: bool
|
type: bool
|
||||||
initial_value: 'false'
|
initial_value: 'false'
|
||||||
|
|
||||||
|
- id: publish_next_image
|
||||||
|
type: bool
|
||||||
|
initial_value: 'false'
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Camera Configuration (OV3660 - DFR1154 Specific)
|
# Camera Configuration (OV3660 - DFR1154 Specific)
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -150,6 +154,36 @@ esp32_camera:
|
|||||||
brightness: 0
|
brightness: 0
|
||||||
contrast: 1
|
contrast: 1
|
||||||
saturation: 0
|
saturation: 0
|
||||||
|
on_image:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
if (!id(publish_next_image)) return;
|
||||||
|
id(publish_next_image) = false;
|
||||||
|
|
||||||
|
const uint8_t *data = x->get_data();
|
||||||
|
size_t len = x->get_data_length();
|
||||||
|
size_t out_len = 4 * ((len + 2) / 3);
|
||||||
|
char *buf = (char *)malloc(out_len + 1);
|
||||||
|
if (!buf) return;
|
||||||
|
|
||||||
|
static const char b64[] =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
size_t j = 0;
|
||||||
|
for (size_t i = 0; i < len; i += 3) {
|
||||||
|
uint32_t b = ((uint32_t)data[i] << 16);
|
||||||
|
if (i + 1 < len) b |= ((uint32_t)data[i + 1] << 8);
|
||||||
|
if (i + 2 < len) b |= data[i + 2];
|
||||||
|
buf[j++] = b64[(b >> 18) & 0x3F];
|
||||||
|
buf[j++] = b64[(b >> 12) & 0x3F];
|
||||||
|
buf[j++] = (i + 1 < len) ? b64[(b >> 6) & 0x3F] : '=';
|
||||||
|
buf[j++] = (i + 2 < len) ? b64[b & 0x3F] : '=';
|
||||||
|
}
|
||||||
|
buf[j] = '\0';
|
||||||
|
|
||||||
|
id(mqtt_client).publish("litter_box/camera/image", buf);
|
||||||
|
ESP_LOGI("capture", "Published image (%d bytes raw, %d base64)", len, j);
|
||||||
|
id(status_message).publish_state("Image sent for analysis");
|
||||||
|
free(buf);
|
||||||
|
|
||||||
# Web server for manual viewing
|
# Web server for manual viewing
|
||||||
esp32_camera_web_server:
|
esp32_camera_web_server:
|
||||||
@@ -293,26 +327,8 @@ script:
|
|||||||
- light.turn_on: status_led
|
- light.turn_on: status_led
|
||||||
- delay: 200ms
|
- delay: 200ms
|
||||||
- lambda: |-
|
- lambda: |-
|
||||||
auto cam = id(litter_cam);
|
id(publish_next_image) = true;
|
||||||
camera::Camera::FrameBuffer *fb = cam->get_image();
|
id(litter_cam).request_image(esphome::esp32_camera::SINGLE_SHOT);
|
||||||
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
|
- light.turn_off: status_led
|
||||||
- lambda: 'id(motion_cooldown_active) = true;'
|
- lambda: 'id(motion_cooldown_active) = true;'
|
||||||
- delay: 30s
|
- delay: 30s
|
||||||
|
|||||||
Reference in New Issue
Block a user