前言

上次 土壤湿度传感器 完成之后,就立下一个 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 <OneButton.h>
#include <WiFi.h>
#include <sddc.h>
#include <cJSON.h>
#include <Wire.h>
#include <SDDC_SDK_lib.h> #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 就完成了我们智能浇花场景的搭建。接下来就写一个智能浇花的应用就能完美的解决忘记浇水的麻烦!

从零开始的DIY智能家居 - 基于 ESP32 的智能浇水器的更多相关文章

  1. 从零开始的DIY智能家居 - 基于 ESP32 的智能水浊度传感器

    前言 家里有个鱼缸养了几条鱼来玩玩,但是换水的问题着实头疼,经常一个不注意就忘记换水,鱼儿就没了.o(╥﹏╥)o 在获得 Spirit 1 边缘计算机 后就相当于有了一个人智能设备服务器,可以自己开发 ...

  2. 从零开始 DIY 智能家居 - 基于 ESP32 的智能紫外线传感器模块

    目录 前言 硬件选择 二.使用步骤 获取代码 设备控制命令: 设备和协议初始化流程: 配置设备信息 回调函数注册 数据获取与上报流程 总结 前言 做了这么多传感器都是自己玩,这次家里人看不下去了,非得 ...

  3. 从零开始 DIY 智能家居 - 基于 ESP32 的智能语音合成播报模块

    目录 前言 硬件选择 代码解析 获取代码 设备控制命令: 设备和协议初始化流程: 配置设备信息 回调函数注册 语音播报与设置流程 总结 前言 这里这么多设备,突然发现我做的好像都是传感器之类的居多好像 ...

  4. 从零开始的DIY智能家居 - 基于 ESP32 的智能光照传感器

    前言 上周出差有点急,结果家里灯没关,开了整整一周的时间(T▽T),整个人都裂开了,准备做一个能够远程控制灯的东西,让我以后出差能远程把家里灯关了. 第一步就是做这期的主题 - 智能光照传感器,因为我 ...

  5. 从零开始的DIY智能家居 - 基于 ESP32 的土壤湿度传感器

    前言 自从上次做了那个 甲醛传感器 和 水浊度传感器 之后开始尝到智能家居的甜头了,这两东西有没有用我不知道,但是没事的时候掏出手机瞄两眼,看着就让人很安心( ̄︶ ̄). 于是懒惰的我开始琢磨把给植物浇 ...

  6. 基于ESP32的智能家居管理系统的设计与实现

    基于ESP32的智能家居管理系统的设计与实现 ESP32的智能家居管理系统访问链接: https://www.cnblogs.com/easyidea/p/13101165.html 一.需求分析 1 ...

  7. 手把手搭建自己的智能家居 - 基于 IOT Pi 的智能甲醛检测器

    智慧家居 - 基于 IOT Pi 的智能甲醛检测器 之前的文章体验 MS-RTOS 的时候入手了一个块 IOT Pi ,放着也是浪费,这次我们就利用 IOT PI 开发一个智能甲醛检测器.φ(> ...

  8. 基于能量收集的智能家居-2013国家级大学生创业实践项目申报_商业计划书_V0.2

    SmartHome项目商业计划 基于能量收集的 免电池无线智能家居系统    IA-SmartHome团队    2012.12     l  基于无线的智能家居解决方案,节省施工成本: l  基于能 ...

  9. 谁才是智能家居的未来?视声M+O融合方案给出答案

    有些智能家居,你不能说它不智能. 但在现实生活中,常常帅不过一秒. 就比如,当你经历了一天的疲惫后回到家,发现玄关的智能开关突然没反应,家里的灯怎么都打不开.这种时候你得明白,你的智能开关面板很有可能 ...

随机推荐

  1. java 基础语法学习01

    Java基础语法 注释 初次使用idea时相关配置 new project ->Empty project->进入页面 再选择file->project structure-> ...

  2. C语言学习笔记---3.字符串格式化输入输出

    1.C语言字符串 字符串(character string)是一个或多个字符的序列,例如:"Zing went the strings of my heart!" C语言没有专门用 ...

  3. 机器学习——K-Means算法

    1 基础知识 相似度或距离 假设有 $m$ 个样本,每个样本由 $n$ 个属性的特征向量组成,样本合集 可以用矩阵 $X$ 表示 $X=[x_{ij}]_{mn}=\begin{bmatrix}x_{ ...

  4. Python爬无止境,获得王者荣耀全部高清皮肤

    作为一名热爱王者两年的程序员,早就想爬取所有英雄皮肤的高清照片,在设个幻灯片放映,真香,这次只用16行代码就能实现,对于新手拿这个作为实战练手项目既简单又容易上手,快来尝试下. 百度"王者荣 ...

  5. Linux系列(4) - 目录处理命令(1)

    前言 linux中一切皆文件.目录为目录文件,普通文件用来保存数据,目录文件用来保存文件 建立目录:mkdir mkdir -p [目录名] -p 递归创建目录,例子:mkdir -p LinuxTe ...

  6. java eclipse 使用随笔

    1,无法import java.awt. 等各种文件,解决办法:(在module-info.java文件中加入requires java,desktop这句话)

  7. 使用uView UI+UniApp开发微信小程序--微信授权绑定和一键登录系统

    在前面随笔<使用uView UI+UniApp开发微信小程序>和<使用uView UI+UniApp开发微信小程序--判断用户是否登录并跳转>介绍了微信小程序的常规登录处理和验 ...

  8. Docker 配置国内镜像加速器

    Docker 默认是从官方镜像地址 Docker Hub 下下载镜像,由于服务器在国外的缘故,导致经常下载速度非常慢.为了提升镜像的下载速度,我们可以手动配置国内镜像加速器,让下载速度飚起来. 国内的 ...

  9. centos 7 & 6 优化脚本

    简单优化 ,未涉及安全优化,如有需求请自行修改脚本实现 1 #!/bin/bash 2 SysVer=`cat /etc/redhat-release | awk -F'release' '{prin ...

  10. django安装xadmin

    环境:pycharm  django1.11.20  python2.7(根据网络上的资料,自己整理实现) 下载:https://github.com/sshwsfc/xadmin/tree/mast ...