完成全功能智慧植物生长系统以后,我们就可以为它赋能了,让它活起来。

创建产品

首先进入涂鸦智能IoT平台,点击创建产品。选择小家电->宠物->植物生长机。

  • 选择自定义方案,输入产品名称,选择通讯协议为WIFI+蓝牙,点击创建产品。
  • 添加标准功能,选择“开关”、“水泵开关”、“当前温度”、“当前湿度”、“倒计时”、“倒计时剩余时间”、“故障告警”,功能点名称、枚举值等可自行编辑修改。

  • 要实现所有的设备功能,还需要根据功能需求自行创建额外的DP功能点。点击添加功能按钮,编辑功能点名称、标识名,勾选数据类型和数据传输类型即可完成功能点创建。
  • 添加最大温度、最小温度、最大湿度、最小湿度四个DP点,用于设置植物生长机的温湿度控制区间。
  • 添加水箱水量,数值型只上报类DP点,用于上报水箱内水量的剩余情况。
  • 添加灯光颜色,枚举型DP点,用于控制补光灯颜色。
  • 添加自动补光,布尔型DP点,用于控制设备切换手动定时补光模式和自动补光模式。

  • 设定完功能点后,下一步点击设备面板,选择app的面板样式。推荐选择开发调试面板,比较直观,且可以开到dp数据包的接收和发送,方便开发阶段调试使用。
  • 至此,产品的创建基本完成,可以正式开始嵌入式软件部分的开发。

嵌入式开发

嵌入式代码基于BK7231平台,使用涂鸦通用Wi-Fi SDK进行SOC开发,具体环境可以拉取涂鸦git库上的demo例程或者直接下载已经包含了SDK环境的demo例程。

下载方式一:ty_iot_wf_bt_sdk_bk7231t* GitHub 仓库
下载方式二:在GitHub了解代码详情

1.应用层入口

将库克隆至本地后,打开文件目录,找到apps文件夹,该文件夹用于存放应用层代码,也就是demo的代码。在这里创建一个文件夹,命名为 bk7231t_plant_grow_mach_demo,与demo有关的所有源文件、头文件以及编译产物都将放到该文件夹中。

若为初次进行该平台的开发,为求快速上手,推荐将apps文件下的bk7231t_bl0973_1_plug_demo中的tuya_device.c、tuya_device.h文件都复制过来。

打开tuya_device.c文件,找的device_init #4CAF50函数:

OPERATE_RET device_init(VOID)
{OPERATE_RET op_ret = OPRT_OK;TY_IOT_CBS_S wf_cbs = {status_changed_cb,\gw_ug_inform_cb,\gw_reset_cb,\dev_obj_dp_cb,\dev_raw_dp_cb,\dev_dp_query_cb,\NULL,};op_ret = tuya_iot_wf_soc_dev_init_param(hw_get_wifi_mode(),WF_START_SMART_FIRST,\&wf_cbs,NULL,PRODECT_KEY,DEV_SW_VERSION);if(OPRT_OK != op_ret) {PR_ERR("tuya_iot_wf_soc_dev_init_param error,err_num:%d",op_ret);return op_ret;}op_ret = tuya_iot_reg_get_wf_nw_stat_cb(wf_nw_status_cb);if(OPRT_OK != op_ret) {PR_ERR("tuya_iot_reg_get_wf_nw_stat_cb is error,err_num:%d",op_ret);return op_ret;}op_ret= app_dltj_init(APP_DLTJ_NORMAL);if(OPRT_OK != op_ret) {PR_ERR("dltj init err!");return op_ret;}op_ret = app_switch_init(APP_SW_MODE_NORMAL);if(op_ret != OPRT_OK) {return op_ret;}return op_ret;
}

在BK7231t平台的SDK环境中,该函数为重要的应用代码入口,设备上电后平台适配层运行完一系列初始化代码后就会调用该函数来进行应用层的初始化操作。

该函数做了三件事:

  • 调用tuya_iot_wf_soc_dev_init_param()接口进行SDK初始化,配置了工作模式、配网模式,同时注册了各种回调函数并存入了固件key和PID。
TY_IOT_CBS_S wf_cbs = {status_changed_cb,\gw_ug_inform_cb,\gw_reset_cb,\dev_obj_dp_cb,\dev_raw_dp_cb,\dev_dp_query_cb,\NULL,};op_ret = tuya_iot_wf_soc_dev_init_param(hw_get_wifi_mode(),WF_START_SMART_FIRST,\&wf_cbs,NULL,PRODECT_KEY,DEV_SW_VERSION);if(OPRT_OK != op_ret) {PR_ERR("tuya_iot_wf_soc_dev_init_param error,err_num:%d",op_ret);return op_ret;}
  • 调用tuya_iot_reg_get_wf_nw_stat_cb()接口注册设备网络状态回调函数。
   op_ret = tuya_iot_reg_get_wf_nw_stat_cb(wf_nw_status_cb);if(OPRT_OK != op_ret) {PR_ERR("tuya_iot_reg_get_wf_nw_stat_cb is error,err_num:%d",op_ret);return op_ret;}
  • 调用应用层初始化函数
op_ret= app_dltj_init(APP_DLTJ_NORMAL);if(OPRT_OK != op_ret) {PR_ERR("dltj init err!");return op_ret;}op_ret = app_switch_init(APP_SW_MODE_NORMAL);if(op_ret != OPRT_OK) {return op_ret;}
  • 由于该文件是从别的demo中复制过来的,所以这里调用的也是别的demo的函数。此时就需要再实现一个本demo自己的应用初始化函数:新建一个app_plant.c #4CAF50和对应头文件,实现app_plant_init() #4CAF50函数,然后在device_init #4CAF50中调用。

2.应用结构

本demo应用代码主要分三层来实现:

  • 最底层为各个传感器的驱动代码,封装出传感器的初始化、采集等接口;
  • 第二层为控制逻辑部分的代码,调用驱动层的传感器接口,实现各个组件的控制逻辑,封装出数据处理轮询接口;
  • 第一层为主要应用层,创建应用任务调用第二层的接口,同时处理DP点数据的上报和接受解析。
  • 第一层就是在app_plant.c #4CAF50文件中实现的,大致内容如下:

app_plant_init() 调用第二层封装出的设备初始化接口,创建应用任务;

OPERATE_RET app_plant_init(IN APP_PLANT_MODE mode)
{OPERATE_RET op_ret = OPRT_OK;if(APP_PLANT_NORMAL == mode) {// IO、传感器、pwm等初始化plant_device_init();// 创建I2C类传感器数据采集任务xTaskCreate(sensor_data_get_iic_theard,"thread_data_get_iic",512,NULL,TRD_PRIO_3,NULL);// 创建ADC类传感器数据采集任务xTaskCreate(sensor_data_get_adc_theard,"thread_data_get_adc",512,NULL,TRD_PRIO_4,NULL);// 创建数据处理任务xTaskCreate(sensor_data_deal_theard,"thread_data_deal",512,NULL,TRD_PRIO_4,NULL);// 创建dp点数据定时循环上报任务xTaskCreate(sensor_data_report_theard,"thread_data_report",512,NULL,TRD_PRIO_4,NULL);}else {// 非产测模式}return op_ret;
}
  • app_report_all_dp_status()上报所有DP数据
VOID app_report_all_dp_status(VOID)
{OPERATE_RET op_ret = OPRT_OK;INT_T dp_cnt = 0;dp_cnt = 12;TY_OBJ_DP_S *dp_arr = (TY_OBJ_DP_S *)Malloc(dp_cnt*SIZEOF(TY_OBJ_DP_S));if(NULL == dp_arr) {PR_ERR("malloc failed");return;}memset(dp_arr, 0, dp_cnt*SIZEOF(TY_OBJ_DP_S));dp_arr[0].dpid = DPID_SWITCH_P;dp_arr[0].type = PROP_BOOL;dp_arr[0].time_stamp = 0;dp_arr[0].value.dp_value = plant_ctrl_data.Switch;......op_ret = dev_report_dp_json_async(NULL,dp_arr,dp_cnt);Free(dp_arr);if(OPRT_OK != op_ret) {PR_ERR("dev_report_dp_json_async relay_config data error,err_num",op_ret);}PR_DEBUG("dp_query report_all_dp_data");return;
}
  • 任务函数,任务内循环调用的plant_get_iic_sensor_data()、plant_get_adc_sensor_data()、plant_ctrl_handle()、plant_ctrl_all_off()都是第二层的接口,实现在plant_control.c #4CAF50文件中。

STATIC VOID sensor_data_get_iic_theard(PVOID_T pArg)
{   while(1) {PR_DEBUG("plant_get_i2c_sensor_data");vTaskDelay(TASKDELAY_SEC);if(TRUE == plant_ctrl_data.Switch) {    plant_get_iic_sensor_data();}}
}STATIC VOID sensor_data_get_adc_theard(PVOID_T pArg)
{   while(1) {PR_DEBUG("plant_get_adc_sensor_data");vTaskDelay(TASKDELAY_SEC*2);if(TRUE == plant_ctrl_data.Switch) {plant_get_adc_sensor_data();}}
}STATIC VOID sensor_data_deal_theard(PVOID_T pArg)
{   while(1) {vTaskDelay(TASKDELAY_SEC);if(TRUE == plant_ctrl_data.Switch) {plant_ctrl_handle();}else {plant_ctrl_all_off();}}}STATIC VOID sensor_data_report_theard(PVOID_T pArg)
{   while(1) {vTaskDelay(TASKDELAY_SEC*5);app_report_all_dp_status();}}
  • deal_dp_proc()处理接受到的DP数据,通过识别DP id来进行相应的数据接收处理
VOID deal_dp_proc(IN CONST TY_OBJ_DP_S *root)
{UCHAR_T dpid;dpid = root->dpid;PR_DEBUG("dpid:%d",dpid);switch (dpid) {case DPID_SWITCH_P:PR_DEBUG("set switch:%d",root->value.dp_bool);plant_ctrl_data.Switch = root->value.dp_bool;break;case DPID_PUMP:PR_DEBUG("set pump:%d",root->value.dp_bool);plant_ctrl_data.Pump = root->value.dp_bool;break;......default:break;}return;}

实现了上述的几个函数后,应用层代码的大概结构就已经确定下来了,接下来就需要实现上面提到的被调用的第二层接口,这些接口都放在本demo的plant_control.c #4CAF50文件中。在下面的内容里,本篇文档将按照温湿度、光照、土壤水份等不同的控制功能闭环来一步步解说demo例程。

3.温湿度控制

要实现温湿度控制,首先要做的就是采集到温湿度。本demo方案采集温湿度的方式是使用SHT21温湿度传感器,该传感器是IIC协议通讯,因此首先需要根据该传感器的技术手册编写传感器驱动代码。在完成驱动代码后,再封装出传感器的初始化、数据采集、数据换算等接口。本demo有关SHT21传感器的驱动和外部接口都实现在sht21.c #4CAF50文件中,封装的外部接口都在plant_control.c #4CAF50中被调用:

  • tuya_sht21_init(sht21_init_t* param)传感器初始化,传参为一个包含SDA、SCL对应IO口和解析度的结构体的指针
typedef struct
{UCHAR_T SDA_PIN;            ///< SDA pinUCHAR_T SCL_PIN;            ///< SCL pinsht21_resolution_t RESOLUTION;
}sht21_init_t;

在plant_control.c #4CAF50中定义这个结构体变量,并在plant_device_init()里调用初始化

#define IIC_SDA_PIN                         (6)
#define IIC_SCL_PIN                         (7)STATIC sht21_init_t sht21_int_param = {IIC_SDA_PIN, IIC_SCL_PIN, SHT2x_RES_10_13BIT};VOID plant_device_init(VOID)
{// SHT21 IIC driver init tuya_sht21_init(&sht21_int_param);}

初始化完成后,就可以获取环境温湿度了。因为植物生长机需要不断的获取环境参数,所以代码上也需要不断的使用传感器数据获取接口。在上一节内容中有提到在app_plant.c #4CAF50文件中有创建过各个功能逻辑任务,其中有一个任务函数循环调用了plant_control.c #4CAF50的plant_get_iic_sensor_data(),所以这里需要在该接口中调用SHT21传感器的数据采集接口tuya_sht21_measure()和计算接口tuya_sht21_cal_RH(),两个接口的传参都为一个用于切换是获取温度还是湿度的枚举值:

VOID plant_get_iic_sensor_data(VOID)
{SHORT_T hum;SHORT_T temp;tuya_sht21_init(&sht21_int_param);hum = tuya_sht21_measure(HUMIDITY);device_data.humidity = tuya_sht21_cal_RH(hum);if(device_data.humidity > 0){ // 剔除小于0的无效湿度值plant_report_data.Humidity_current = (UCHAR_T)device_data.humidity;PR_NOTICE("humidity = %d",plant_report_data.Humidity_current);}temp = tuya_sht21_measure(TEMP);device_data.temperature = tuya_sht21_cal_temperature(temp);plant_report_data.Temp_current = (UCHAR_T)device_data.temperature;PR_NOTICE("tempre = %d",plant_report_data.Temp_current);}

获取到环境温湿度值后,就可以和温湿度设定值做一个判断。在创建产品的时候新建了最大最小温度和最大最小湿度四个自定义功能点,所以可以在app上进行设置,并通过云端下发给设备。下发的DP点数据在app_plant.c #4CAF50的deal_dp_proc()函数中进行处理:

VOID deal_dp_proc(IN CONST TY_OBJ_DP_S *root)
{UCHAR_T dpid;dpid = root->dpid;PR_DEBUG("dpid:%d",dpid);switch (dpid) {......case DPID_TEMP_MAX:PR_DEBUG("set temp max:%d",root->value.dp_value);plant_ctrl_data.Temp_max = root->value.dp_value;break;case DPID_HUMIDITY_MAX:PR_DEBUG("set humidity max:%d",root->value.dp_value);plant_ctrl_data.Humidity_max = root->value.dp_value;break;case DPID_TEMP_MIN:PR_DEBUG("set temp min:%d",root->value.dp_value);plant_ctrl_data.Temp_min = root->value.dp_value;break;case DPID_HUMIDITY_MIN:PR_DEBUG("set humidity min:%d",root->value.dp_value);plant_ctrl_data.Humidity_min = root->value.dp_value;break;......default:break;}return;}

在app_plant.c #4CAF50中创建过一个任务用于数据判断和IO设备控制,该任务循环调用了plant.control.c #4CAF50中的plant_ctrl_handle()函数,所有有关具体的控制逻辑实现都放在plant_ctrl_handle()中。本demo方案用于控制温湿度的器件为一个加湿器、一个加热灯和一个风扇,通过继电器实现用IO口的高低电平控制这些器件的开和关。控制IO口电平需要用到SDK封装好的接口tuya_gpio_inout_set()和tuya_gpio_write()。温湿度控制相关代码如下:

#define HUMIDIFIER_PORT                     (24)
#define HUMIDIFIER_LEVEL                    LOW#define HEATING_ROD_PORT                    (20)
#define HEATING_ROD_LEVEL                   LOW#define COOL_DOWN_FAN_PORT                  (21)
#define COOL_DOWN_FAN_LEVEL                 LOWSTATIC VOID __ctrl_gpio_init(CONST TY_GPIO_PORT_E port, CONST BOOL_T high)
{// 设置IO口为输出模式tuya_gpio_inout_set(port, FALSE);// 设置IO口电平tuya_gpio_write(port, high);
}VOID plant_device_init(VOID)
{// SHT21 IIC driver init tuya_sht21_init(&sht21_int_param);// gpio init__ctrl_gpio_init(HUMIDIFIER_PORT, HUMIDIFIER_LEVEL);__ctrl_gpio_init(COOL_DOWN_FAN_PORT, COOL_DOWN_FAN_LEVEL);  __ctrl_gpio_init(HEATING_ROD_PORT, HEATING_ROD_LEVEL);}STATIC VOID __passive_ctrl_module_temp_humidity(VOID)
{   if(device_data.humidity < plant_ctrl_data.Humidity_min) {tuya_gpio_write(HUMIDIFIER_PORT, !HUMIDIFIER_LEVEL);}else {tuya_gpio_write(HUMIDIFIER_PORT, HUMIDIFIER_LEVEL);}if(device_data.temperature < plant_ctrl_data.Temp_min) {tuya_gpio_write(HEATING_ROD_PORT, !HEATING_ROD_LEVEL);}else {tuya_gpio_write(HEATING_ROD_PORT, HEATING_ROD_LEVEL);}if((device_data.temperature > plant_ctrl_data.Temp_max)||(device_data.humidity > plant_ctrl_data.Humidity_max)) {tuya_gpio_write(COOL_DOWN_FAN_PORT,!COOL_DOWN_FAN_LEVEL);}else {tuya_gpio_write(COOL_DOWN_FAN_PORT,COOL_DOWN_FAN_LEVEL);}}VOID plant_ctrl_handle(VOID)
{   PR_DEBUG("enter ctrl handle");__passive_ctrl_module_temp_humidity();}

4.光照控制

本demo方案使用BH1750照度检测传感器,和温湿度传感器一样也是IIC协议的。根据该传感器的数据手册编写传感器驱动代码。在完成驱动代码后,封装出传感器的初始化、数据采集等接口。本demo有关BH1750传感器的驱动和外部接口都实现在bh1750.c #4CAF50文件中,封装的外部接口都在plant_control.c #4CAF50中被调用:

  • tuya_bh1750_init(sht21_init_t* param)传感器初始化,传参为一个包含SDA、SCL对应IO的结构体的指针;

typedef struct
{UCHAR_T SDA_PIN;            ///< SDA pinUCHAR_T SCL_PIN;            ///< SCL pin
}bh1750_init_t;

在plant_control.c #4CAF50中定义这个结构体变量,并在plant_device_init()里调用初始化:

#define IIC_SDA_PIN                         (6)
#define IIC_SCL_PIN                         (7)STATIC bh1750_init_t bh1750_int_param = {IIC_SDA_PIN, IIC_SCL_PIN};VOID plant_device_init(VOID)
{......// SHT21 IIC driver init tuya_bh1750_init(&bh1750_int_param);......
}

初始化完成后,在plant_get_iic_sensor_data()函数里调用BH1750传感器的数据采集接口tuya_bh1750_get_bright_value()获取光照强度值。由于调试过程中发现光照传感器和温湿度传感器的采集中间不加延时的话会影响通讯,因此做了点改动让每次进入plant_get_iic_sensor_data()函数时只启用其中一个传感器:

VOID plant_get_iic_sensor_data(VOID)
{SHORT_T hum;SHORT_T temp;switch (IIC_SELECT_FLAG){case 0:    tuya_sht21_init(&sht21_int_param);hum = tuya_sht21_measure(HUMIDITY);device_data.humidity = tuya_sht21_cal_RH(hum);if(device_data.humidity > 0){ // 剔除小于0的无效湿度值plant_report_data.Humidity_current = (UCHAR_T)device_data.humidity;PR_NOTICE("humidity = %d",plant_report_data.Humidity_current);}temp = tuya_sht21_measure(TEMP);device_data.temperature = tuya_sht21_cal_temperature(temp);plant_report_data.Temp_current = (UCHAR_T)device_data.temperature;PR_NOTICE("tempre = %d",plant_report_data.Temp_current);IIC_SELECT_FLAG = 1;break;case 1:    tuya_bh1750_init(&bh1750_int_param);device_data.light_intensity_value = tuya_bh1750_get_bright_value();PR_NOTICE("light_intensity_value = %d",device_data.light_intensity_value);IIC_SELECT_FLAG = 0;break;default:break;}}

光照控制方面的设定值没有创建对应的DP点,无法用app设置,只在代码内写死了一个数值,通过控制灯光亮度来使光照传感器采集值不断逼近该数值,并给定了一个误差范围值来防止在亮度临界点时发生的灯光不断闪烁的现象。

#define ACCURACY                         (2000)  // 误差范围值
#define light_value_set                  (12000) // 亮度设定值 unit:lux

本demo方案通过输出PWM波的方式来控制灯板的亮度,有关PWM的初始化和输出控制函数接口都实现在plant_pwm.c #4CAF50中,在plant_device_init()中初始化PWM,并在plant_ctrl_handle()中调用实现灯光控制逻辑的接口:

USER_PWM_DUTY_T user_pwm_duty = {0,0};VOID plant_device_init(VOID)
{......plant_pwm_init();......
}STATIC VOID __passive_ctrl_module_light(VOID)
{   if(IIC_SELECT_FLAG){ // 若上一次启用的iic传感器为温湿度传感器return;}if((TRUE == plant_ctrl_data.Auto_switch)) { // 自动补光开关为开USHORT_T current = device_data.light_intensity_value;USHORT_T set = light_value_set;if((current - set) > ACCURACY) { // 当前光照强度大于设定值且不在误差范围内if((current - set) >= 200) {if(plant_ctrl_data.Bright_value >= 50)plant_ctrl_data.Bright_value -= 50;}else if((current - set) > 150) {if(plant_ctrl_data.Bright_value >= 20)plant_ctrl_data.Bright_value -= 20;}else {if(plant_ctrl_data.Bright_value >= 1)plant_ctrl_data.Bright_value--;}}else if((set - current) > ACCURACY) { // 当前光照强度小于设定值且不在误差范围内if((set - current) >= 200) {if(plant_ctrl_data.Bright_value <= 950)plant_ctrl_data.Bright_value += 50;}else if((set - current) > 150) {if(plant_ctrl_data.Bright_value <= 980)plant_ctrl_data.Bright_value += 20;}else {if(plant_ctrl_data.Bright_value <= 999)plant_ctrl_data.Bright_value++;}}}
}STATIC VOID __initiative_ctrl_module_light(VOID)
{   if(TRUE == plant_ctrl_data.Auto_switch) { // 自动补光开关为开PR_NOTICE("Ligth open !!!!");if(plant_ctrl_data.Light_color == red) { // 灯光颜色设为红灯user_pwm_duty.duty_red = plant_ctrl_data.Bright_value;user_pwm_duty.duty_blue = 0;}else if(plant_ctrl_data.Light_color == blue) { // 灯光颜色设为蓝灯user_pwm_duty.duty_blue = plant_ctrl_data.Bright_value;user_pwm_duty.duty_red = 0;}else {user_pwm_duty.duty_blue = plant_ctrl_data.Bright_value;user_pwm_duty.duty_red = user_pwm_duty.duty_blue;}plant_pwm_set(&user_pwm_duty);}else { // 自动补光开关为关 用户手动定时控制if(plant_ctrl_data.Light_color == red) {user_pwm_duty.duty_red = 1000;user_pwm_duty.duty_blue = 0;}else if(plant_ctrl_data.Light_color == blue) {user_pwm_duty.duty_blue = 1000;user_pwm_duty.duty_red = 0;}else {user_pwm_duty.duty_red = 1000;user_pwm_duty.duty_blue = 1000;}if((IsThisSysTimerRun(light_timer) == FALSE)&&(plant_ctrl_data.Countdown_set != cancel)) {light_flag_min = (USHORT_T)plant_ctrl_data.Countdown_set * 60;plant_pwm_set(&user_pwm_duty);sys_start_timer(light_timer,1000*60,TIMER_CYCLE);}else if(plant_ctrl_data.Countdown_set == cancel) {user_pwm_duty.duty_blue = 0;user_pwm_duty.duty_red = 0;plant_pwm_set(&user_pwm_duty);light_flag_min = 0;sys_stop_timer(light_timer);}else if(IsThisSysTimerRun(light_timer) == TRUE) {plant_pwm_set(&user_pwm_duty);}// 保存定时剩余时间 单位分钟plant_report_data.Countdown_left = light_flag_min;}}VOID plant_ctrl_handle(VOID)
{   ......__passive_ctrl_module_light();__initiative_ctrl_module_light();
}

5.土壤湿度控制

本demo方案使用的土壤湿度检测传感器可以根据土壤的湿度情况输出模拟量,因此代码上就需要通过ADC采集模拟量转换为数字量的方式来监测土壤湿度。
在app_plant.c #4CAF50文件中创建的获取ADC采集任务中循环调用了plant_control.c #4CAF50的plant_get_adc_sensor_data(),所有有关adc采集的代码都放在该函数接口内:

VOID plant_get_adc_sensor_data(VOID)
{   // 控制开关模拟芯片选择土壤湿度的通道rs2255_channel_checkout(SOIL_MOISTURE_SENSOR_PORT);tuya_hal_adc_init(&tuya_adc);tuya_hal_adc_value_get(TEMP_ADC_DATA_LEN, &device_data.soil_humidity);PR_NOTICE("soil_humidity = %d",device_data.soil_humidity);tuya_hal_adc_finalize(&tuya_adc);}

获取土壤湿度值后,根据湿度情况控制水泵是否打开来实现自动浇水。在plant_ctrl_handle()中调用实现控制浇水逻辑的接口:

  • 引入了ADD_WATER_COUNT #F44336、ADD_WATER_READY #F44336两个变量,实现水泵每开启一段时间后就会关闭一段时间,防止浇水过度。
STATIC VOID __passive_ctrl_module_soil_humidity(VOID)
{   if(device_data.soil_humidity > plant_ctrl_data.Soil_humidity_threshold) { if(ADD_WATER_READY) { tuya_gpio_write(WATER_VALVE_PORT, !WATER_VALVE_LEVEL);ADD_WATER_COUNT++;if(ADD_WATER_COUNT > 5) {ADD_WATER_READY = 0;}} else{tuya_gpio_write(WATER_VALVE_PORT, WATER_VALVE_LEVEL);ADD_WATER_COUNT++;if(ADD_WATER_COUNT >15) {ADD_WATER_READY = 1;ADD_WATER_COUNT = 0;}}}else {ADD_WATER_READY = 1;ADD_WATER_COUNT = 0;tuya_gpio_write(WATER_VALVE_PORT, WATER_VALVE_LEVEL);}
}VOID plant_ctrl_handle(VOID)
{   ......__passive_ctrl_module_soil_humidity();......
}

6.水箱控制

给土壤浇水的水泵是从水箱中抽水,当水箱中的水量过少时则需要另一个水泵给水箱加水。控制水箱自动加水就用到了水位传感器,该传感器也是通过输出模拟量的大小来反映测量区域水位的位置的,因此和土壤湿度传感器一样也使用ADC采集模拟量转换数字量:

rs2255_init()为模拟开关芯片的初始化函数,用于解决IO口不够用的问题。由于使用的控制脚和做为SDA、SCL的是同一对IO口,所有在每次采集adc数据时都要重新初始化。IIC传感器的初始化也同理。

VOID plant_get_adc_sensor_data(VOID)
{rs2255_init();switch (ADC_SELECT_FLAG){case 0:    rs2255_channel_checkout(WATER_SENSOR_PORT);tuya_hal_adc_init(&tuya_adc);tuya_hal_adc_value_get(TEMP_ADC_DATA_LEN, &device_data.water_tank_value);PR_NOTICE("water_tank_value = %d",device_data.water_tank_value);ADC_SELECT_FLAG = 1;break;case 1:    rs2255_channel_checkout(SOIL_MOISTURE_SENSOR_PORT);tuya_hal_adc_init(&tuya_adc);tuya_hal_adc_value_get(TEMP_ADC_DATA_LEN, &device_data.soil_humidity);PR_NOTICE("soil_humidity = %d",device_data.soil_humidity);ADC_SELECT_FLAG = 0;break;default:break;}tuya_hal_adc_finalize(&tuya_adc);}

plant_ctrl_handle()中调用实现水箱水量控制的接口:

#define WATER_PUMP_PORT                     (22)
#define WATER_PUMP_LEVEL                    LOWSTATIC VOID __initiative_ctrl_module_pump(VOID)
{   // 根据水位传感器值转换剩余水量百分比,用于上报if(device_data.water_tank_value < 1700) {plant_report_data.Water_remain = 10;}else if(device_data.water_tank_value < 2500) {plant_report_data.Water_remain = 25;}else if(device_data.water_tank_value < 2700) {plant_report_data.Water_remain = 50;}else if(device_data.water_tank_value < 2900) {plant_report_data.Water_remain = 75;}else if(device_data.water_tank_value >= 3000) {plant_report_data.Water_remain = 100;}if(TRUE == plant_ctrl_data.Pump){ // 若水泵开关为开PR_NOTICE("water pump open !!!!");tuya_gpio_write(WATER_PUMP_PORT,!WATER_PUMP_LEVEL);}else {tuya_gpio_write(WATER_PUMP_PORT,WATER_PUMP_LEVEL);}if(device_data.water_tank_value >= 3000) { // 当水量接近测量上限时关闭水泵PR_NOTICE("water tank is full !!!!");tuya_gpio_write(WATER_PUMP_PORT,WATER_PUMP_LEVEL);plant_ctrl_data.Pump = FALSE;}}VOID plant_ctrl_handle(VOID)
{   ......__initiative_ctrl_module_pump();......
}

至此,本demo的大部分控制逻辑代码就基本完成了,在完善dp点上报和接收部分后即可开始后续的功能调试。想了解demo代码的其他细节请自行查看demo例程。

7.编译和烧录

在linux终端输入指令运行SDK环境目录下的build_app.sh #4CAF50脚本来编译代码生成固件,指令格式为 sh build_app.sh APP_PATH #F44336 APP_NAME #F44336 APP_VERSION #F44336:

若出现下图所示提示,则表示编译成功,固件已经生成:

固件生成路径为:apps->APP_PATH #F44336->output

将固件烧录至模组即可开始功能调试阶段,有关烧录和授权方式请参照文档:WB系列模组烧录授权

赋能完成

程序烧录完以后,我们就完成了赋能部分,之后我们就可以对各个功能进行调试了。

全功能智慧植物生长系统更多支持,请点击以下网站:

涂鸦开发者中心:http://developer.tuya.com
涂鸦帮助中心:http://support.tuya.com/cn/help
涂鸦技术支持工单中心:http://service.sonsole.tuya.com

戳我:更多物联网应用在这里!

嵌入式——涂鸦智能全功能智慧植物生长系统相关推荐

  1. 涂鸦智能全功能智慧植物生长系统是什么样的?

    哇--,终于结束了.自己都想感叹.终于做完了,功能确实有点多,这篇分享估计要成为涂鸦智能从入门到劝退了,嘿嘿,欢迎大家分享自己方案,别忘私信我转载,之后我再做一个简单的,让大家做起来更加方便,不过涂鸦 ...

  2. 涂鸦智能全功能智慧植物生长系统(硬件)

    在前面,我们分析完市面上的植物生长机,也选了一款植物生长机进行了拆机,接下来我们就开始搭建一个全功能智慧植物生长系统. 我们想要实现的功能有这些: 涂鸦智能APP远程遥控.监测 光照监测 温湿度监测 ...

  3. 涂鸦智能全功能智慧植物生长系统(测试)

    烧录授权完成后,设备就可以正常配网了.连接WiFi,打开蓝牙,按照配网流程成功配网后,即可使用app控制设备. 以下内容为本demo设备调试流程和结果: 1.定时补光和自动补光 打开开关,设定灯光定时 ...

  4. 涂鸦智能全功能智慧植物生长系统(展示)

    哇--,终于结束了.自己都想感叹.终于做完了,功能确实有点多,这篇分享估计要成为涂鸦智能从入门到劝退了,嘿嘿,欢迎大家分享自己方案,别忘私信我转载,之后我再做一个简单的,让大家做起来更加方便,不过涂鸦 ...

  5. 搭建一个全功能 GPS 追踪系统

    0X00    前言 Traccar 是一个开源的 GPS 跟踪系统.此存储库包含基于 Java 的后端服务.它支持 170 多种 GPS 协议和 1500 多种型号的 GPS 跟踪设备.Tracca ...

  6. 智能驾驶功能软件平台设计规范 第一部分:系统架构

    智能驾驶功能软件平台设计规范 第一部分:系统架构 2020-07-29 发布 1 规范应用范围 本规范规定了智能驾驶功能软件平台的系统架构.功能模块和算法组件划分. 本规范适用于 GB/T<汽车 ...

  7. 涂鸦智能植物生长机lite(硬件篇)

    前面我们设计了一款功能极全面的 智慧植物生长系统,设计到植物生长的绝大多数因素.不过制作起来太复杂了不便于大家快速制作,然后我们就设计了这款精简版的智能植物生长机.这次我们几乎把上次的方案给全部推翻, ...

  8. 全球及中国智慧养老系统行业市场需求预测及投资竞争力分析报告2022-2028年

    全球及中国智慧养老系统行业市场需求预测及投资竞争力分析报告2022-2028年 详情内容请咨询鸿晟信合研究院! [全新修订]:2022年3月 [撰写单位]:鸿晟信合研究网 1 智慧养老系统市场概述 1 ...

  9. 基于涂鸦智能开发的墨水屏座位管理器——2.嵌入式功能实现篇

    随着互联网连接技术的日益普及,以及大众环保意识增强,电子纸显示市场不断发展,墨水屏的应用场景也越来越多.墨水屏座位管理器方案具体功耗低,多节点管控,信息实时同步等特点,可应用于智慧办公,智慧零售,智慧 ...

最新文章

  1. plsql连接oracle无响应,求教 pl/sql连接本机数据库是未响应问题
  2. Android移动开发者必须知道的Deep Linking技术
  3. 贾跃亭画了一个8500亿的大饼
  4. 拉格朗日乘数法(一种寻找变量受一个或多个条件所限制的多元函数的极值的方法)
  5. github开源项目免费使用Azure PipeLine
  6. ssl2644-线段树练习1【线段树】
  7. idea springboot 发布webservice 发布服务_阿里云发布 Spring Boot 新脚手架,真香
  8. 【NOIP模拟】健美猫
  9. Mysql: 图解 inner join、left join、right join、full outer join、union、union all的区别
  10. ubuntu14.04 remmina远程连接rdp服务器失败解决办法
  11. 在vue-cli 中使用 axios
  12. python中10none_Python中的None与Null(空字符)的区别
  13. Android ASM插桩探索及实战
  14. 分享几款强大的录音软件,厉害炸了!
  15. Android TimePicker
  16. 【OpenCV-Python-课程学习(贾)】OpenCV3.3课程学习笔记:图像色彩空间转换(cvtColor),imread()的grayscale和cvtColor()的区别、通道分离与转换
  17. AutoCAD中导入图片
  18. 价格敏感度测试(PSM)模型及其在网游中的运用
  19. 反需求函数和边际收益_[转载]关于所谓反需求函数
  20. linux远程服务器环境_如何使用Linux为孩子设置远程学校环境

热门文章

  1. #负分小组WEEK1#确定项目——“宝宝睡吧!”儿童睡前服务服务软件+计划分工...
  2. 前端工程师高效H5开发工具,强力推荐这12款!
  3. VB+ACCESS干部档案管理系统设计与实现
  4. 二十世纪模型论发展迅猛,势不可挡
  5. ADB安装及使用详解
  6. 资金实力大涨,底气十足的小米电视强力阻击华为电视
  7. STM32的完整启动流程分析
  8. 小白学3D游戏建模全流程详细教程
  9. 大学四年我终于成材了(爆笑)
  10. 新手适合用什么Vue组件库?TinyVue组件库好用吗?