刘鹏
Published © Apache-2.0

Automated HA Fish Tank Design Based on Seeed xiao ESP32S3 Se

Automatic feeding; Environmental monitoring (including temperature, humidity, water quality); Real-time video monitoring; Remote management

AdvancedWork in progress451
Automated HA Fish Tank Design Based on Seeed xiao ESP32S3 Se

Things used in this project

Hardware components

Seeed Studio XIAO ESP32S3 Sense
Seeed Studio XIAO ESP32S3 Sense
controller
×1
Raspberry Pi 4 Model B
Raspberry Pi 4 Model B
Homeassistant Server
×1
DHT11 Temperature & Humidity Sensor (3 pins)
DHT11 Temperature & Humidity Sensor (3 pins)
Detect the temperature and humidity outside the fish tank
×1
SG90 Micro-servo motor
SG90 Micro-servo motor
Fish tank feeder
×1
LED (generic)
LED (generic)
Fish tank lighting
×1

Software apps and online services

Home Assistant
Home Assistant

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Fish Tape, Reel
Fish Tape, Reel
Soldering Station, Temperature Controlled
Soldering Station, Temperature Controlled

Story

Read more

Schematics

Pin wiring

Pin wiring

Code

Seeed xiao ESP32S3 Sense access esphome.yaml

YAML
Seeed xiao ESP32S3 Sense access esphome
esphome:
  name: xiao-cam
  # friendly_name: xiao-cam

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino


# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "Fabc3YZ2bYG7x8WhupncrCMPqZuPMwxyeCPsgrbQIAI="

ota:
  password: "412c844a7b10765fcd89954e7587e5af"

wifi:
  ssid: "J09 502"
  password: "qwertyuiop111"
  # use_address: elkontrol1
  # use_address: elkontrol1.local

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Xiao Fallback Hotspot1"
    password: "YpeK5OYS4Xej"


captive_portal:
# Example configuration entry
external_components:
  - source:
      type: git
      url: https://github.com/MichaKersloot/esphome_custom_components
    components: [ esp32_camera ]


esp32_camera:
  external_clock:
    pin: GPIO10
    frequency: 20MHz
  i2c_pins:
    sda: GPIO40
    scl: GPIO39
  data_pins: [GPIO15, GPIO17, GPIO18, GPIO16, GPIO14, GPIO12, GPIO11, GPIO48]
  vsync_pin: GPIO38
  href_pin: GPIO47
  pixel_clock_pin: GPIO13

  # Image settings
  name: My Camera
  # ...

# Configuration for the status LED light
light:
  - platform: status_led
    id: light0
    name: "Voice Assistant State"
    pin:
      number: GPIO21
      inverted: true

# Configuration for I2S audio
i2s_audio:
  i2s_lrclk_pin: GPIO46 # Note: labeled as "useless"
  i2s_bclk_pin: GPIO42

# Configuration for the microphone using I2S audio
microphone:
  - platform: i2s_audio
    id: echo_microphone
    i2s_din_pin: GPIO41
    adc_type: external
    pdm: true

# Configuration for the Voice Assistant
voice_assistant:
  microphone: echo_microphone

# Configuration for the binary sensor (Boot Switch)
binary_sensor:    
  - platform: gpio
    pin: 
      number: GPIO2
      mode:
        input: true
        pullup: true
    name: Boot Switch
    internal: true
    on_press:
      - voice_assistant.start:
      - light.turn_off: light0
    on_release:
      - voice_assistant.stop:
      - light.turn_on: light0

# Example configuration entry (D2)
sensor:
  - platform: dht
    pin: GPIO7
    temperature:
      name: "Temperature"
    humidity:
      name: "Humidity"
    update_interval: 5s

number:
  - platform: template
    name: Servo Control
    min_value: -100
    max_value: 100
    step: 1
    set_action:
      then:
        - servo.write:
            id: my_servo
            level: !lambda 'return x / 100.0;'

# Example configuration entry
servo:
  - id: my_servo
    output: pwm_output

# Example output platform
# On ESP32, use ledc output
output:
  - platform: ledc
    id: pwm_output
    pin: GPIO8
    frequency: 50 Hz

Automation NodeRED.json

JSON
Automation NodeRED
[
    {
        "id": "31531595a3887301",
        "type": "tab",
        "label": "",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "13c9e0ee685611ac",
        "type": "tab",
        "label": "",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "10765693b6bcfeaf",
        "type": "tab",
        "label": "",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "9e5db24f.d50e5",
        "type": "server",
        "name": "Home Assistant",
        "addon": true
    },
    {
        "id": "c8dc251df8e97718",
        "type": "xiaoai-tts-configurator",
        "name": ""
    },
    {
        "id": "41ef4b78.2e2ab4",
        "type": "server",
        "name": "Home Assistant",
        "version": 5,
        "addon": true,
        "rejectUnauthorizedCerts": true,
        "ha_boolean": "y|yes|true|on|home|open",
        "connectionDelay": true,
        "cacheJson": true,
        "heartbeat": false,
        "heartbeatInterval": "30",
        "areaSelector": "friendlyName",
        "deviceSelector": "friendlyName",
        "entitySelector": "friendlyName",
        "statusSeparator": "at: ",
        "statusYear": "hidden",
        "statusMonth": "short",
        "statusDay": "numeric",
        "statusHourCycle": "h23",
        "statusTimeFormat": "h:m",
        "enableGlobalContextStore": true
    },
    {
        "id": "01c4904dbc06f88c",
        "type": "inject",
        "z": "31531595a3887301",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 260,
        "y": 120,
        "wires": [
            [
                "5d641ec6b07a673c"
            ]
        ]
    },
    {
        "id": "95179cc4df24244c",
        "type": "debug",
        "z": "31531595a3887301",
        "name": "debug 1",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 820,
        "y": 120,
        "wires": []
    },
    {
        "id": "d03f58e01f4a16b3",
        "type": "inject",
        "z": "31531595a3887301",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 220,
        "y": 220,
        "wires": [
            [
                "a89d1daebe024134"
            ]
        ]
    },
    {
        "id": "8d8e1bd016c64e63",
        "type": "debug",
        "z": "31531595a3887301",
        "name": "debug 2",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 740,
        "y": 220,
        "wires": []
    },
    {
        "id": "5d641ec6b07a673c",
        "type": "xiaoai-volume",
        "z": "31531595a3887301",
        "name": "",
        "xiaoai": "c8dc251df8e97718",
        "volume": "51",
        "device": "",
        "x": 460,
        "y": 120,
        "wires": [
            [
                "95179cc4df24244c"
            ],
            []
        ]
    },
    {
        "id": "a89d1daebe024134",
        "type": "api-call-service",
        "z": "31531595a3887301",
        "name": "",
        "server": "9e5db24f.d50e5",
        "version": 5,
        "debugenabled": false,
        "domain": "xiaomi_miot",
        "service": "intelligent_speaker",
        "areaId": [],
        "deviceId": [],
        "entityId": [
            "sensor.xiaomi_lx04_5e02_conversation"
        ],
        "data": "{\"text\":\"\"}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 480,
        "y": 220,
        "wires": [
            [
                "8d8e1bd016c64e63"
            ]
        ]
    },
    {
        "id": "6f985e77ba2239d8",
        "type": "inject",
        "z": "31531595a3887301",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 150,
        "y": 380,
        "wires": [
            [
                "c87ec627c3d65acc"
            ]
        ]
    },
    {
        "id": "cdf9b42ee3b909ee",
        "type": "debug",
        "z": "31531595a3887301",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1040,
        "y": 380,
        "wires": []
    },
    {
        "id": "c87ec627c3d65acc",
        "type": "xiaoai-volume",
        "z": "31531595a3887301",
        "name": "",
        "xiaoai": "c8dc251df8e97718",
        "volume": "43",
        "device": "",
        "x": 320,
        "y": 380,
        "wires": [
            [
                "06efbebf06c2e680"
            ],
            [
                "710be66d9ae5fa19"
            ]
        ]
    },
    {
        "id": "710be66d9ae5fa19",
        "type": "api-call-service",
        "z": "31531595a3887301",
        "name": "",
        "server": "41ef4b78.2e2ab4",
        "version": 5,
        "debugenabled": false,
        "domain": "smtp",
        "service": "notify",
        "areaId": [],
        "deviceId": [],
        "entityId": [],
        "data": "{\t   \"message\":\"<b></b>\",\t   \"title\":\"HomeAssistant\",\t   \"email\":\"3126171871@qq.com\"\t}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 700,
        "y": 420,
        "wires": [
            [
                "cdf9b42ee3b909ee"
            ]
        ]
    },
    {
        "id": "06efbebf06c2e680",
        "type": "api-call-service",
        "z": "31531595a3887301",
        "name": "",
        "server": "9e5db24f.d50e5",
        "version": 5,
        "debugenabled": false,
        "domain": "xiaomi_miot",
        "service": "intelligent_speaker",
        "areaId": [],
        "deviceId": [],
        "entityId": [
            "sensor.xiaomi_lx04_5e02_conversation"
        ],
        "data": "{\"text\":\"\"}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 700,
        "y": 320,
        "wires": [
            [
                "cdf9b42ee3b909ee"
            ]
        ]
    },
    {
        "id": "2ee71350eab9a05b",
        "type": "inject",
        "z": "13c9e0ee685611ac",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "00 12 * * *",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 260,
        "y": 100,
        "wires": [
            [
                "fd353374c78d82f8"
            ]
        ]
    },
    {
        "id": "87a1d11f9c89367d",
        "type": "debug",
        "z": "13c9e0ee685611ac",
        "name": "debug 3",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1060,
        "y": 380,
        "wires": []
    },
    {
        "id": "2e6d7d5839debb53",
        "type": "api-call-service",
        "z": "13c9e0ee685611ac",
        "name": "90",
        "server": "41ef4b78.2e2ab4",
        "version": 5,
        "debugenabled": false,
        "domain": "number",
        "service": "set_value",
        "areaId": [
            "ke_ting"
        ],
        "deviceId": [
            "dc2bd470f44cfb196986ae81f0c54a1b"
        ],
        "entityId": [
            "number.servo_control"
        ],
        "data": "{\"value\":100}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "90",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 800,
        "y": 100,
        "wires": [
            [
                "508e5a9410e2423c"
            ]
        ]
    },
    {
        "id": "a81f43e407aa0c35",
        "type": "api-call-service",
        "z": "13c9e0ee685611ac",
        "name": "0",
        "server": "41ef4b78.2e2ab4",
        "version": 5,
        "debugenabled": false,
        "domain": "number",
        "service": "set_value",
        "areaId": [
            "ke_ting"
        ],
        "deviceId": [
            "dc2bd470f44cfb196986ae81f0c54a1b"
        ],
        "entityId": [
            "number.servo_control"
        ],
        "data": "{\"value\":-100}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "0",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 400,
        "y": 220,
        "wires": [
            [
                "7a2b85ccb60380df"
            ]
        ]
    },
    {
        "id": "45dbf177629c65d5",
        "type": "api-call-service",
        "z": "13c9e0ee685611ac",
        "name": "90",
        "server": "41ef4b78.2e2ab4",
        "version": 5,
        "debugenabled": false,
        "domain": "number",
        "service": "set_value",
        "areaId": [
            "ke_ting"
        ],
        "deviceId": [
            "dc2bd470f44cfb196986ae81f0c54a1b"
        ],
        "entityId": [
            "number.servo_control"
        ],
        "data": "{\"value\":100}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "90",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 860,
        "y": 220,
        "wires": [
            [
                "c595f13eb99d5d01"
            ]
        ]
    },
    {
        "id": "d4dce4fd5a1de16d",
        "type": "api-call-service",
        "z": "13c9e0ee685611ac",
        "name": "0",
        "server": "41ef4b78.2e2ab4",
        "version": 5,
        "debugenabled": false,
        "domain": "number",
        "service": "set_value",
        "areaId": [
            "ke_ting"
        ],
        "deviceId": [
            "dc2bd470f44cfb196986ae81f0c54a1b"
        ],
        "entityId": [
            "number.servo_control"
        ],
        "data": "{\"value\":-100}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "0",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 480,
        "y": 380,
        "wires": [
            [
                "07266ceecfd9a08f"
            ]
        ]
    },
    {
        "id": "508e5a9410e2423c",
        "type": "delay",
        "z": "13c9e0ee685611ac",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 1060,
        "y": 100,
        "wires": [
            [
                "a81f43e407aa0c35"
            ]
        ]
    },
    {
        "id": "c595f13eb99d5d01",
        "type": "delay",
        "z": "13c9e0ee685611ac",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 1180,
        "y": 220,
        "wires": [
            [
                "d4dce4fd5a1de16d"
            ]
        ]
    },
    {
        "id": "7a2b85ccb60380df",
        "type": "delay",
        "z": "13c9e0ee685611ac",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 640,
        "y": 220,
        "wires": [
            [
                "45dbf177629c65d5"
            ]
        ]
    },
    {
        "id": "07266ceecfd9a08f",
        "type": "api-call-service",
        "z": "13c9e0ee685611ac",
        "name": "",
        "server": "41ef4b78.2e2ab4",
        "version": 5,
        "debugenabled": false,
        "domain": "xiaomi_miot",
        "service": "intelligent_speaker",
        "areaId": [],
        "deviceId": [],
        "entityId": [
            "sensor.xiaomi_lx04_5e02_conversation"
        ],
        "data": "{\"text\":\"\"}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 800,
        "y": 380,
        "wires": [
            [
                "87a1d11f9c89367d"
            ]
        ]
    },
    {
        "id": "fd353374c78d82f8",
        "type": "api-call-service",
        "z": "13c9e0ee685611ac",
        "name": "",
        "server": "41ef4b78.2e2ab4",
        "version": 5,
        "debugenabled": false,
        "domain": "xiaomi_miot",
        "service": "intelligent_speaker",
        "areaId": [],
        "deviceId": [],
        "entityId": [
            "sensor.xiaomi_lx04_5e02_conversation"
        ],
        "data": "{\"text\":\"\"}",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 460,
        "y": 100,
        "wires": [
            [
                "2e6d7d5839debb53"
            ]
        ]
    },
    {
        "id": "3eca89300da6a067",
        "type": "api-call-service",
        "z": "10765693b6bcfeaf",
        "name": "",
        "server": "9e5db24f.d50e5",
        "version": 5,
        "debugenabled": false,
        "domain": "light",
        "service": "turn_on",
        "areaId": [
            "ke_ting"
        ],
        "deviceId": [
            "dc2bd470f44cfb196986ae81f0c54a1b"
        ],
        "entityId": [
            "light.voice_assistant_state"
        ],
        "data": "",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 810,
        "y": 300,
        "wires": [
            [
                "d4b489b84d3a1a11"
            ]
        ]
    },
    {
        "id": "d16b213857492fcb",
        "type": "time-range-switch",
        "z": "10765693b6bcfeaf",
        "name": "",
        "lat": "",
        "lon": "",
        "startTime": "07:28",
        "endTime": "12:28",
        "startOffset": 0,
        "endOffset": 0,
        "x": 550,
        "y": 320,
        "wires": [
            [
                "784f9bc1adca590d"
            ],
            [
                "3eca89300da6a067"
            ]
        ]
    },
    {
        "id": "784f9bc1adca590d",
        "type": "api-call-service",
        "z": "10765693b6bcfeaf",
        "name": "",
        "server": "9e5db24f.d50e5",
        "version": 5,
        "debugenabled": false,
        "domain": "light",
        "service": "turn_off",
        "areaId": [
            "ke_ting"
        ],
        "deviceId": [
            "dc2bd470f44cfb196986ae81f0c54a1b"
        ],
        "entityId": [
            "light.voice_assistant_state"
        ],
        "data": "",
        "dataType": "jsonata",
        "mergeContext": "",
        "mustacheAltTags": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "",
                "valueType": "str"
            }
        ],
        "queue": "none",
        "x": 790,
        "y": 400,
        "wires": [
            [
                "d4b489b84d3a1a11"
            ]
        ]
    },
    {
        "id": "d4b489b84d3a1a11",
        "type": "debug",
        "z": "10765693b6bcfeaf",
        "name": "debug 5",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1000,
        "y": 360,
        "wires": []
    },
    {
        "id": "56a173656eee3993",
        "type": "inject",
        "z": "10765693b6bcfeaf",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "0 7-13 * * *",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 370,
        "y": 320,
        "wires": [
            [
                "d16b213857492fcb"
            ]
        ]
    },
    {
        "id": "1ff3db3ea7622884",
        "type": "inject",
        "z": "10765693b6bcfeaf",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 650,
        "y": 220,
        "wires": [
            [
                "3eca89300da6a067"
            ]
        ]
    },
    {
        "id": "6c19a3bec41654a6",
        "type": "inject",
        "z": "10765693b6bcfeaf",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 650,
        "y": 460,
        "wires": [
            [
                "784f9bc1adca590d"
            ]
        ]
    }
]

Credits

刘鹏

刘鹏

1 project • 3 followers
My journey began with Arduino and ESP32 microcontroller projects, along with IoT system development using platforms like Home Assistant.

Comments