Trae SOLO对话式编程--改造宠物饮水机

夏天来了,人要多喝水,家里的宠物也要多喝水,但存在几个问题。

例如:

1、 我家的猫不喜欢喝固定盛水器里的水,有时偷喝水盆里水,有时喝地面的水。

2、买几 1-2 的饮水机,有时喝有时不喝,有时还喜欢扒拉机子,滤芯还要买指定的。

3、针对宠物喜欢喝流动、新鲜水的特性,网上又买了个 20 左右的饮水机,但水泵是通电后一直工作没有定时开关功能。

基础功能需求:

1、具有定时换水提示功能,保证水的新鲜度。

2、饮水机的水泵,自动模式,识别到宠物自动打开,否则自动关闭。

BOM 硬件元料表(总计:55 元)

如果不做后期功能扩展,目前功能使用 EPS32-C3 开发板(10 元)完全满足需求。

|--------|---------------------|--------|
| 序号 | 硬件型号 | 价格 |
| 1 | 饮水机 | 15 |
| 2 | ESP32-S3-N16R8 开发板 | 25 |
| 3 | 毫米波 LD02402 | 5 |
| 4 | 继电器模块 | 2 |
| 5 | 0.91寸OLED液晶屏SSD1306 | 8 |

后期可扩展功能:

1、Web 界面: web 设置管理界面,手机访问管理

2、数据持久化:饮水数据统计与分析,通过毫米波统计时间段喝水次数,通过水位传感器统计喝水量

3、水温管理:通过温度传感器冬天进行水温测量,添加加热棒控制水温

4、水质管理:TDS 传感器实时测量饮用水水质显示,超标提醒。

5、自动加换水:通过另外大容量纯净水桶与水泵,实现自动加水、换水。

6、摄像头: ESP32-CAM 实现摄像头功能,宠物识别高级功能。

改装硬件的外壳使用 3D 打印机,自己设计打印。

一、宠物感知传感器选型分析

对猫、狗的感应,毫米波雷达通常比普通 PIR 更灵敏;但 PIR 可通过安装与调参实现 "宠物免疫",而雷达很难彻底忽略小动物。

首先排除使用 HC-SR04 超声波,HC-SR04 测试时人体接近距离是有数据,宠物例如猫,测试时传感器是没有数据。原因如下:

  1. 猫毛发吸声波猫蓬松绒毛会直接吸收超声波,反射回波极弱,传感器收不到信号,直接测距失效。
  2. 体型小、曲面多猫身体弧度大,声波四散反射,没法原路回弹。
  3. 姿态低矮猫贴地、低头、蜷缩,超出超声波常规探测角度。
  4. 移动微动猫咪慢走、趴卧微动,测距逻辑容易判定无目标。

1、毫米波与 PIR原理差异(决定灵敏度)

  • PIR(被动红外) :只检测移动的热源(8--14μm 红外),不发热 / 不动就无感。
    • 猫狗体温≈38℃,和人体接近,但体表面积小、热信号弱
    • 依赖横向移动 + 温差;低矮、慢速、靠近地面的目标易被过滤。
  • 毫米波雷达(24GHz/60GHz) :发射电磁波,靠多普勒效应 检测任何移动 / 微动 (包括呼吸、心跳),不依赖热量
    • 微小动作、慢速移动、近距离贴近地面的目标都敏感。
    • 能穿透薄布 / 玻璃,不受温度、光照、粉尘影响。

2、实际灵敏度对比(猫狗)

1. 普通 PIR(如 HC‑SR501)
  • 猫(3--7kg):近距离(1--2m)快速走过 易触发;慢速 / 远处 / 蹲卧常无感。
  • 小型狗(<10kg):类似猫;** 中型以上(>15kg)** 接近人体灵敏度。
  • 可 "防宠物":调高安装高度(2.1--2.4m)+ 调低灵敏度,可忽略 10kg 以下宠物。
2. 毫米波雷达(24GHz 主流)
  • 猫:极强敏感 ------ 哪怕缓慢走动、蹲卧微动、呼吸 都能触发;0.1m 起即可检测。
  • 狗:全体型高敏感 ------ 从小型吉娃娃到大型犬,几乎无法过滤;调低灵敏度也难完全忽略。
  • 微动检测:能感知0.1mm 级微动,猫狗呼吸 / 轻微晃动都逃不过。

3、关键区别与选型建议

  • 灵敏度排序:毫米波雷达(极高) > 普通 PIR(中) > 防宠物 PIR(低)。
  • 能否区分人与宠物
    • PIR:可通过安装 + 调参区分(过滤小宠物)。
    • 毫米波雷达:基本不能区分,对人和猫狗一视同仁;高端雷达可粗略按体型过滤,但效果有限。
  • 适用场景
    • 防宠物误触发 (如智能家居、安防):选防宠物 PIR
    • 精准监测宠物活动 (如喂食器、猫砂盆):选毫米波雷达
    • 人体 + 宠物全感知 (如无人存在检测):选毫米波雷达

二、 Trae SOLO 全自动 AI 开发平台

在进行物联网小型项目开发时,使用 SOLO 平台进行开发是非常好的应用场景。

Trae IDE 是 "你主导、AI 辅助" 的传统编辑器环境;Trae SOLO 是 "AI 主导、你提需求" 的全自动 AI 开发工作台,两者可以在同一个 Trae 客户端里切换。


1、核心定位:谁来主导?

  • IDE 模式(IDE Mode)
    • 角色:你是司机,AI 是副驾
    • 流程:你写代码、操作文件、调 Git、运行调试;AI 做补全、问答、改片段
    • 类比:VS Code + 强 AI 插件
  • SOLO 模式(SOLO Mode)
    • 角色:AI 是开发团队,你是产品 / 老板
    • 流程:你用自然语言说需求 → AI 自己拆任务、写代码、建目录、装依赖、运行、调试、出预览Trae
    • 类比:给一个高级 AI 工程师全权负责项目

2、界面布局完全不一样

  • IDE 模式界面(经典编辑器)
    • 左侧:文件树
    • 中间:代码编辑器
    • 右侧:AI 聊天 / 面板
    • 下方:终端、调试、问题
  • SOLO 模式界面(AI 任务工作台)
    • 左侧:任务列表 / Plan
    • 中间:对话 + 执行日志 + 预览
    • 右侧:工具 / 模型 / 配置

3、工作流差异

IDE 模式:传统开发 + AI 增强
  1. 自己新建 / 打开项目
  2. 手动创建文件、写代码
  3. AI 帮补全、解释、改代码片段
  4. 自己运行、调试、提交 Git
  5. 适合:精细控制、长期迭代、复杂业务逻辑
SOLO 模式:需求驱动,AI 全自动
  1. 输入一句话需求(可语音 / 截图)
  2. AI 生成项目结构、选技术栈、写所有代码
  3. 自动安装依赖、运行、打开预览
  4. 你只需要:提需求、确认、验收、微调
  5. 适合:快速原型、全栈小项目、不会写代码也能做

4、可用智能体(Agent)不同

  • IDE 模式可用
    • Chat:问答、改片段
    • Builder:生成项目 / 页面(轻量)
  • SOLO 模式可用
    • SOLO Coder:复杂项目全流程(架构→编码→调试→部署)
    • SOLO Builder:专门做 Web 应用,自动出 PRD + 代码 + 预览
    • 支持 Plan:AI 先出详细计划,你确认再执行

5、适合人群怎么选

  • IDE 模式,如果你:
    • 是程序员,习惯 VS Code 工作流
    • 需要精细控制代码、调试、Git
    • 做大型 / 长期迭代项目
    • 要深度定制、二次开发
  • SOLO 模式,如果你:
    • 产品 / 设计 / 运营,不会写代码
    • 想快速出原型、MVP、小应用
    • 不想管细节,只想 "说需求→要结果"
    • 做全栈项目、网站、工具类应用

6、总结

|--------|--------------|-------------------------|
| 维度 | IDE 模式 | SOLO 模式 |
| 主导者 | 开发者主导 | AI 主导 |
| 界面 | VS Code 经典布局 | AI 任务工作台 |
| 工作流 | 手动编码 + AI 辅助 | 自然语言需求 → AI 全流程 |
| 智能体 | Chat、Builder | SOLO Coder、SOLO Builder |
| 控制力 | 强(你说了算) | 弱(AI 说了算) |
| 上手难度 | 中等(需会基本编码) | 极低(会说话就行) |
| 典型场景 | 日常开发、大型项目 | 快速原型、全栈小应用 |



三、Trae SOLO 开发宠物饮水系统

输入项目开发的提示词,尽量详细与明确,特别是硬件模块的型号与接线。

开发基于 ESP32 S3 开发板宠物饮水机控制系统的 Arduino 程序:

1、硬件环境:ESP32S3开发板、继电器模块、LD2402 毫米波模块、SSD1306显示屏模块、WS2812LED灯

2、引脚说明:继电器(GPIO6)。HCLD2402(Tx--GPIO17,Rx--GPIO18)使用串口通信,接收字符串。SSD1306(SCL--GPIO15,SDA--GPIO16)IIC接口,分辨率128x32。WS2812LED灯(GPIO48)。

3、LD2402 毫米波模块,检测宠物接近饮水机时通过继电器打开送水开关,否则关闭送水开发。

4、WS2812LED灯,做为换水提示灯,用户每次断电后认为换了一次水,24小时内显示绿色,48小时内黄色,72小时内显示红色,超过72小时报警模式,红色闪烁。

5、SSD1306显示屏,第一行显示换水时间和继电器状态,第二行显示实时LD2402 数据。字符大小要适配分辨率,每行前面添加简化的示意图标。

完成!我已经为 ESP32 S3 开发板创建了完整的宠物饮水机控制系统 Arduino 程序。

1. 硬件通信架构

  • 继电器控制:GPIO6 控制送水开关
  • LD2402 毫米波:GPIO17/18 串口通信,接收检测数据
  • SSD1306 显示屏:GPIO15/16 I2C 接口,128x32 分辨率
  • WS2812 LED:GPIO48 控制状态指示灯

2. 核心功能实现

🔄 LD2402 毫米波检测
  • 实时接收串口数据并解析
  • 检测到宠物(数据>0)时自动开启继电器
  • 未检测到时自动关闭继电器
💧 WS2812 LED 换水提示

|----------|------------|--------|
| 时间范围 | LED 颜色 | 状态 |
| 0-24小时 | 🟢 绿色 | 正常 |
| 24-48小时 | 🟡 黄色 | 提醒 |
| 48-72小时 | 🔴 红色 | 警告 |
| >72小时 | 🔴 红色闪烁 | 报警模式 |

📺 SSD1306 显示屏界面

第一行

  • 图标 + 换水时间(小时:分钟:秒)
  • 继电器 ON/OFF 状态

第二行

  • 图标 + LD2402 实时数据

3. 数据持久化

  • 使用 ESP32 Preferences 库存储换水时间
  • 系统每次上电自动检查存储状态
  • 支持 manualWaterChange() 函数手动标记换水

4. 代码特点

  • ✅ 完整的中文注释
  • ✅ 模块化设计,易于维护
  • ✅ 串口调试输出(115200波特率)
  • ✅ 自动状态管理和LED闪烁控制
  • ✅ 适配 128x32 分辨率的优化图标绘制

📁 文件位置

代码已保存至:pet_water_fountain.ino

🔧 需要的库

  • Adafruit_GFX
  • Adafruit_SSD1306
  • Adafruit_NeoPixel
  • Preferences (ESP32内置)

如需添加手动换水按钮或串口命令支持,可以进一步完善!

复制代码
#include <Arduino.h>
#include <HardwareSerial.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_NeoPixel.h>
#include <Preferences.h>

#define RELAY_PIN 6
#define LD2402_TX 17
#define LD2402_RX 18
#define LED_PIN 48
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 32
#define OLED_SDA 16
#define OLED_SCL 15
#define LED_COUNT 1

HardwareSerial ld2402Serial(2);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
Preferences preferences;

enum LEDState {
    LED_GREEN,
    LED_YELLOW,
    LED_RED,
    LED_RED_BLINK
    };

enum RelayState {
    RELAY_OFF,
    RELAY_ON
    };

struct SystemState {
    unsigned long lastWaterChangeTime;
    bool petDetected;
    RelayState relayState;
    String ld2402Data;
    LEDState ledState;
};

SystemState systemState;

unsigned long getCurrentTimeMillis() {
    return millis();
}

unsigned long getTimeSinceWaterChange() {
    unsigned long lastChange = preferences.getULong("lastWaterChange", 0);
    if (lastChange == 0) {
        lastChange = getCurrentTimeMillis();
        preferences.putULong("lastWaterChange", lastChange);
    }
    return getCurrentTimeMillis() - lastChange;
}

void updateWaterChangeTime() {
    unsigned long current = getCurrentTimeMillis();
    preferences.putULong("lastWaterChange", current);
    systemState.lastWaterChangeTime = current;
}

void initLED() {
    strip.begin();
    strip.show();
    strip.setBrightness(255);
}

void setLEDState(LEDState state) {
    systemState.ledState = state;
}

void updateLED() {
    unsigned long hoursSinceChange = getTimeSinceWaterChange() / 3600000;

    if (hoursSinceChange < 24) {
        setLEDState(LED_GREEN);
        strip.setPixelColor(0, strip.Color(0, 255, 0));
    } else if (hoursSinceChange < 48) {
        setLEDState(LED_YELLOW);
        strip.setPixelColor(0, strip.Color(255, 255, 0));
    } else if (hoursSinceChange < 72) {
        setLEDState(LED_RED);
        strip.setPixelColor(0, strip.Color(255, 0, 0));
    } else {
        setLEDState(LED_RED_BLINK);
        static bool blinkState = false;
        blinkState = !blinkState;
        if (blinkState) {
            strip.setPixelColor(0, strip.Color(255, 0, 0));
        } else {
            strip.setPixelColor(0, strip.Color(0, 0, 0));
        }
    }
    strip.show();
}

void initRelay() {
    pinMode(RELAY_PIN, OUTPUT);
    digitalWrite(RELAY_PIN, LOW);
    systemState.relayState = RELAY_OFF;
}

void setRelayState(RelayState state) {
    systemState.relayState = state;
    digitalWrite(RELAY_PIN, (state == RELAY_ON) ? HIGH : LOW);
}

void controlRelay(bool petDetected) {
    if (petDetected) {
        setRelayState(RELAY_ON);
    } else {
        setRelayState(RELAY_OFF);
    }
}

void initLD2402() {
    ld2402Serial.begin(115200, SERIAL_8N1, LD2402_RX, LD2402_TX);
}


void updateLD2402() {
    if (ld2402Serial.available()) {
        String line = ld2402Serial.readStringUntil('\n');
        line.trim();
    if (line.length() == 0) return;

    if (line == "OFF") {
      systemState.ld2402Data = "OFF";
      systemState.petDetected = false;
    } 
    else if (line.startsWith("distance:")) {
      systemState.ld2402Data = line.substring(9).toFloat();
      systemState.petDetected = true;
    }
    controlRelay(systemState.petDetected);
  }
}


void initDisplay() {
    Wire.begin(OLED_SDA, OLED_SCL);
    if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
        Serial.println("SSD1306 allocation failed");
        return;
    }
    display.clearDisplay();
    display.setTextColor(SSD1306_WHITE);
    display.display();
}

void drawWaterIcon(int x, int y) {
  display.fillRect(x, y + 2, 10, 12, SSD1306_WHITE);
  display.fillRect(x + 2, y, 6, 2, SSD1306_WHITE);
}

void drawRulerIcon(int x, int y) {
  display.fillRect(x, y, 12, 14, SSD1306_WHITE);
  display.drawLine(x + 2, y + 2, x + 2, y + 12, SSD1306_BLACK);
  display.drawLine(x + 6, y + 2, x + 6, y + 12, SSD1306_BLACK);
  display.drawLine(x + 10, y + 2, x + 10, y + 12, SSD1306_BLACK);
}


void updateDisplay() {
    
    unsigned long timeSinceChange = getTimeSinceWaterChange();
    unsigned long hours = timeSinceChange / 3600000;
    unsigned long minutes = (timeSinceChange % 3600000) / 60000;
    unsigned long seconds = (timeSinceChange % (1000 * 60)) / 1000;
    
    display.clearDisplay();
    
    display.setTextSize(1);
    display.setTextColor(SSD1306_WHITE);
    
    drawWaterIcon(0, 0);
    
    display.setCursor(16, 0);
    char timeStr[16];
    sprintf(timeStr, "%02luH-%02luM-%02luS", hours, minutes, seconds);
    display.print(timeStr);
    
    display.setCursor(100, 0);
    if (systemState.relayState == RELAY_ON) {
        display.print("ON ");
    } else {
        display.print("OFF");
    }
    
    drawRulerIcon(0, 16);
    
    display.setTextSize(2);
    display.setCursor(16, 16);
   
    if (systemState.ld2402Data.length() > 0) {
        if (systemState.ld2402Data == "OFF") {
            display.print("OFF");
        } else {
            display.print("D:");
            display.print(systemState.ld2402Data);
        }
    } else {
        display.print("NODATA");
    }
    
    display.display();
}



void checkPowerOnReset() {
    unsigned long lastChange = preferences.getULong("lastWaterChange", 0);
    if (lastChange == 0 || (getCurrentTimeMillis() - lastChange) > 86400000 * 10) {
        updateWaterChangeTime();
    }
    systemState.lastWaterChangeTime = lastChange;
}

void setup() {
    Serial.begin(115200);
    
    preferences.begin("petWater", false);
    
    checkPowerOnReset();
    
    initRelay();
    initLED();
    initLD2402();
    initDisplay();
    
    systemState.petDetected = false;
    systemState.ld2402Data = "";
    
    Serial.println("Pet Water Fountain System Initialized");
}

void loop() {
    unsigned long currentMillis = getCurrentTimeMillis();
    
    updateLD2402();
    
    static unsigned long lastLEDUpdate = 0;
    if (currentMillis - lastLEDUpdate >= 500) {
        lastLEDUpdate = currentMillis;
        updateLED();
    }
    
    static unsigned long lastDisplayUpdate = 0;
    if (currentMillis - lastDisplayUpdate >= 100) {
        lastDisplayUpdate = currentMillis;
        updateDisplay();
    }
    
    static unsigned long lastSerialUpdate = 0;
    if (currentMillis - lastSerialUpdate >= 500) {
        lastSerialUpdate = currentMillis;
        
        Serial.print("LD2402: ");
        Serial.print(systemState.ld2402Data);
        Serial.print(" | Detected: ");
        Serial.print(systemState.petDetected ? "Yes" : "No");
        Serial.print(" | Relay: ");
        Serial.println(systemState.relayState == RELAY_ON ? "ON" : "OFF");
    }
}

void manualWaterChange() {
    updateWaterChangeTime();
    Serial.println("Water changed manually!");
}
相关推荐
冷酷的兔先生2 天前
工程闭环:宠物空调的核心技术门槛
宠物
百胜软件@百胜软件2 天前
聚力宠物新经济·赋能产业新增长——百胜软件联合市商企协、浙里宠物、贯合智库成功举办宠物经济主题活动
宠物·零售数字化·数智中台·珠宝行业
深圳正律有为知识产权有限公司5 天前
26-cv-4039、26-cv-4064 PETS ROCK潮流IP商标版权侵权!是一个将名人文化与宠物形象巧妙结合的创意艺术品牌。
宠物·tro
水上冰石8 天前
ComfyUI集成InfiniteTalk工作流,实现宠物主播视频生成
音视频·宠物
振浩微433射频芯片9 天前
告别“喊破嗓”:深度解析433MHz射频在宠物训练器中的核心应用与选型
单片机·嵌入式硬件·物联网·学习·宠物
向日的葵00615 天前
阿里云OSS从0到1实战:为宠物收养系统打造图片上传功能
python·阿里云·云计算·pillow·fastapi·宠物
向日的葵00615 天前
CSDN博客文章-爪印之约宠物收养管理系统
mysql·css3·html5·fastapi·宠物
冷酷的兔先生18 天前
什么样的设计,才配得上“宠物空调”这个名字?——从功能设备到环境控制系统的判定标准
安全·宠物
爱吃芒果的蘑菇19 天前
给 Codex 加一只像素宠物:阿梓 Azi
agent·宠物·codex