从零开始的DIY智能家居

您所在的位置:网站首页 懒人浇花器怎么做 从零开始的DIY智能家居

从零开始的DIY智能家居

2024-07-13 03:01| 来源: 网络整理| 查看: 265

文章目录 前言硬件选择改造接线代码解析设备控制命令:设备和协议初始化流程:配置设备信息回调函数注册数据获取与发送流程 总结

前言

上次 土壤湿度传感器 完成之后,就立下一个 flag 要搭建一个智慧浇水的智能场景,现在终于有时间填坑了!(o゚▽゚)o

智慧浇水场景的核心设备有三个: 检测土壤状态的:土壤湿度传感器 通过这个传感器来获取土壤信息,作为是否浇水的依据。 智能浇水器:执行装置,通过 Spirit 1 控制。 Spirit 1

这次就来制作智慧浇水的智能场景的核心: 智能浇水器,我准备买一个便宜的傻不拉几的浇水器自己改造一下,想办法给他连上脑子。 在这里插入图片描述 主要交互流程如下图: 在这里插入图片描述

(σ゚∀゚)σ…:*☆哎哟不错哦,是不是很厉害啊!

硬件选择

万年不变的 安信可的 ESP32S ,别问,问就是便宜才 24元。

继电器,因为不清楚浇水器电路情况保险起见,使用了继电器进行隔离,4.5元

浇水器 淘宝随便找的 99元,选择它是因为这个方便改造,有一个可以拆卸的电池盒方便塞开发板和继电器,按钮是机械式的,可以通过继电器短接模拟按钮效果进行控制,并且有一个手动浇水的功能,也就是按钮摁一下就浇水,再摁一下就关闭,我们从这个功能下手。 在这里插入图片描述 (写文章的时候这东西已经被我拆掉了,就拿淘宝的图凑活一下吧,图上按的中间按钮就是我们需要接管的按钮)

(((((((((((っ•ω•)っ Σ(σ`•ω•´)σ 起飞!

改造接线

硬件都到了之后就开始改造电路! 控制电路: 控制电路 浇水器面板中间的按钮就是手动控制按钮下降沿触发,而我们在这里使用了一个继电器常开端接到按钮上,当开发板 12号 IO 口给继电器电压时,继电器常开端闭合,按钮被短接,两端电压被拉至5V,0.1S后断开,电压拉低,下降沿触发。

休眠检测电路: 在这里插入图片描述

浇水器中有一个10S左右没有控制就进入休眠状态的设置我们没办法修改,进入休眠状态后需要一个额外的触发来唤醒浇水器,而浇水器唤醒时,会点亮数码管,于是就通过 A0 引脚接到数码管的共阳级,如果检测到数码管的共阳级为低电平,就认为浇水器进入休眠状态,在触发命令之前额外触发一次,解除浇水器的休眠状态。

浇水器工作状态检测电路: 电机检测

浇水器面板通过信号线来控制下面水泵电机的工作,这里我通过5号 IO 监控信号线的电压来确定电机的工作状态。

代码解析

为了方便讲解逻辑,我会打乱代码的顺序可能还会进行裁剪,要是想直接拿代码跑的朋友可以直接去 灵感桌面的秘密宝库 获取代码,或者直接 clone:

https://gitee.com/inspiration-desktop/DEV-lib-arduino.git

要是连 git 是什么都不知道,可以参考简单无脑,上手即用 - 手把手教你使用 智能红外温度传感器代码以及依赖的 gitee 库! 下载或者 clone 代码后这次用到的是这个三个文件夹:

在这里插入图片描述 cjson:我移植的 cjson 库,就是标准的 cjson 库,放到 arduino 安装目录下的 libraries 文件夹里,百度一下 cjson 的函数使用就行了。

libsddc:是我移植自官方的SDDC库和自己写的 SDK,也是放入 libraries 文件夹里就行。里面是 SDDC 协议的处理函数,我们不用管。

demo 文件夹里面就是我们各种传感器的 demo 代码了: 在这里插入图片描述 具体 arduino 使用教程可以看我之前的文章 arduino开发指导 和 手把手带你 arduino 开发:基于ESP32S 的第一个应用-红外测温枪(带引脚图)

设备控制命令:

通过 Spirit 1 的应用程序或者 嗅探器 向传感器设备发送的命令: 通过向浇水器发送 “ON”/“OFF” 的 set 命令可以控制浇水器是否浇水:

{ "method": "set", // 控制浇水器开始/停止浇水 "watering": "ON"/"OFF" }

通过向浇水器发送 “watering” 的 get 命令可以获取浇水器是否有在浇水:

{ "method": "get", // 获取浇水器工作状态 "obj": ["watering"] } 设备和协议初始化流程:

基于官方 demo 写的不需要做什么修改,主要是设备初始化,管脚配置,和协议初始化部分。

因为涉及到 IO 口的输入和输出,所以需要手动配置一下 IO 口状态。并且创建一个一个消息队列来储存和传递收到的命令

void sensor_init() { pinMode(water_pin, OUTPUT); pinMode(sign_pin, INPUT); pinMode(monitor_pin,INPUT); // 设置一个消息队列来缓存命令,防止命令丢失 Message_Queue = xQueueCreate(MESSAGE_Q_NUM, MESSAGE_REC_LEN); //创建消息Message_Queue if(Message_Queue == 0) { printf("队列 Message_Queue 创建失败!\r\n"); } } void setup() { // 这部分主要是协议初始化和设备初始化,没有需要修改的地方,详见gitee库 } void loop() { // 这部分主要是协议初始化和设备初始化,没有需要修改的地方,详见gitee库 } 配置设备信息

这部分代码可以配置 WiFi 名字和 WiFi 密码,要使用的引脚,并且配置设备在 Spirit 1 上显示的信息:

// 依赖度头文件和库 #include "Arduino.h" #include #include #include #include #include #include #define SDDC_CFG_PORT 680U // SDDC 协议使用的端口号 #define PIN_INPUT 0 // 选择 IO0 进行控制 #define ESP_TASK_STACK_SIZE 4096 #define ESP_TASK_PRIO 25 #define MESSAGE_Q_NUM 5 // 数据的消息队列的数量 #define MESSAGE_REC_LEN 5 // 数据的消息队列的长度 static sddc_t *g_sddc; static const char* ssid = "TP-LINK_54F9C2"; // WiFi 名 static const char* password = "1234567890"; // WiFi 密码 static const int water_pin = 12; // 浇水器的控制引脚,控制浇水器启停 static const int sign_pin = A0; // 浇水器的状态监视引脚,查看浇水器是否休眠 static const int monitor_pin = 5; // 工作状态监视引脚,监视浇水器启停 QueueHandle_t Message_Queue; static int xTicksToDelay = 5000; // 周期延时时间 OneButton button(PIN_INPUT, true);

这里填写设备的信息,方便在 Spirit 1 上查看和寻找你需要的设备:

/* * 当前设备的信息定义 */ DEV_INFO dev_info = { .name = "智能浇水", // 设备的名字 .type = "device", .excl = SDDC_FALSE, .desc = "ESP-32S", .model = "1", .vendor = "inspiration-desktop", }; 回调函数注册

这是收到命令后回调函数注册的位置,在这里注册的函数才能被 SDK 正确的调用,执行正确的动作。

因为浇水器 set 命令为 string 类型,所以对应的处理函数 water_set 注册到 IO设备对象设置函数与处理方法注册 中。

/* * IO设备对象设置函数与处理方法注册 */ IO_DEV_REGINFO io_dev[] = { {"watering",water_set}, };

而 get 处理函数返回的同样是 string 类型,所以在 系统对象状态获取注册 中第二个参数选择 DEV_IO_TYPE,并且注册 get 处理函数 single_get_sensor。

/* * 系统对象状态获取注册 */ DEV_STATE_GET dev_state_get_reg[] = { {"watering", DEV_IO_TYPE, single_get_sensor}, };

具体 SDK 的解析可以参考 同人逼死官方系列!基于sddc 协议的SDK框架 sddc_sdk_lib 解析 和 同人逼死官方系列!从 DDC 嗅探器到 sddc_sdk_lib 的数据解析

数据获取与发送流程

这里是自己编写的处理流程 ,可以根据需求自己更改,收到 set 或者 get 后上文注册的函数,进入对应的处理函数。

收到 set 命令后,通过关键字寻找到对应的处理函数 water_set ,判断命令是否正确(比如说正在浇水的时候,收到一个ON命令),检测浇水器是否休眠,如果休眠了那在触发前就唤醒设备。

而收到 get 命令后进入对应的处理函数 single_get_sensor 通过读取面板信号线判断电机工作状态,并且返回给 Spirit 1。

/* * 主动数据上报函数 */ static void report_sensor() { int sensorValue = 0; cJSON *value; cJSON *root; value = cJSON_CreateArray(); root = cJSON_CreateObject(); sddc_return_if_fail(value); sddc_return_if_fail(root); // 按格式生成需要的数据 cJSON_AddItemToArray(value, cJSON_CreateString("上报数据 1 ")); // 这里的字符串要和系统对象状态获取注册结构体里的对应 // cJSON_AddItemToArray(value, cJSON_CreateString("上报数据 2 ")); // 需要上报几个就添加几个 cJSON_AddItemToObject(root, "obj", value); // 发送数据给 EdgerOS object_report(root); cJSON_Delete(value); } /* * 浇水状态监控函数 */ static void monitor_task(void *arg) { int newval = 1; int oldval = 1; // 监控浇水开启和关闭状态 while(1) { newval = digitalRead(monitor_pin); if(newval != oldval) { report_sensor(); } oldval = newval; // 任务创建之后,设定延时周期 delay(100); } vTaskDelete(NULL); } /* * 浇水触发任务 */ static void button_task(void *arg) { char SW[5]; char *value; BaseType_t err; if(Message_Queue != NULL) { err = xQueueReceive(Message_Queue, &value, portMAX_DELAY ); if(err == pdFALSE) { printf("队列 Message_Queue 数据获取失败!\r\n"); } } sddc_printf("\nMessage_Queue value: %s!!!!!\n", value); // 监控电机工作状态 if(digitalRead(monitor_pin)) { strcpy(SW,"OFF"); }else { strcpy(SW,"ON"); } // 如果命令要求与电机当前工作状态一致就不处理 if(0 != strcmp(value,SW) && (value != NULL)) { // 判断机器是否休眠如果休眠了就行唤醒机器 delay(100); int a = analogRead(sign_pin); sddc_printf("\n a1 == : %d!!!!!\r\n", analogRead(sign_pin)); if(!(a > 1) && (0 == strcmp(value,"ON"))) { Serial.println("唤醒"); digitalWrite(water_pin, HIGH); delay(100); digitalWrite(water_pin, LOW); delay(100); // 因为是下降沿触发,所以加延迟保证下降沿不会被后面的命令冲掉 } // 触发浇水器开或者关 Serial.println("触发"); digitalWrite(water_pin, HIGH); delay(100); digitalWrite(water_pin, LOW); delay(100); } vTaskDelete(NULL); } /* * 浇水器控制函数 */ sddc_bool_t water_set(const char* value) { BaseType_t err; sddc_printf("\niot_pi_on_message: %s!!!!!\n", value); if((Message_Queue != NULL)&&(value)) { // 通过消息队列储存收到的命令,防止命令丢失 err = xQueueSendToFront(Message_Queue,&value,0 ); if(err == pdFALSE) { printf("队列 Message_Queue 已满,数据发送失败!\r\n"); } } // 创建电机触发任务,防止阻塞message_ack回复 xTaskCreate(button_task, "button_task", ESP_TASK_STACK_SIZE, NULL, ESP_TASK_PRIO, NULL); return SDDC_TRUE; } /* * 填写浇水状态 */ sddc_bool_t single_get_sensor(char *objvalue, int value_len) // 注意函数名要和上文注册的函数名保持一致,当收到 get 消息之后通过关键字就能找到并且调用这个函数 { if(digitalRead(monitor_pin)) { strncpy(objvalue, "OFF", value_len); }else { strncpy(objvalue, "ON", value_len); } return SDDC_TRUE; }

代码写完之后烧录进去就完事了,和之前完全一样,点一下保存,然后上传OK,具体可以看之前的文档,我就懒得再写一遍啦 (/ω\)。

总结

智能浇水器制作完成!加上之前制作的土壤湿度传感器,和 Spirit 1 就完成了我们智能浇花场景的搭建。接下来就写一个智能浇花的应用就能完美的解决忘记浇水的麻烦!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3