Sandwich IoT
Published © GPL3+

Fully-Functional Smart Indoor Garden

In this project, we retrofit an ordinary indoor garden into a fully-functional and IoT-enabled growing system.

BeginnerFull instructions provided24 hours497
Fully-Functional Smart Indoor Garden

Things used in this project

Hardware components

WB3S network module
WB3S is a low power Wi-Fi and BLE combo module developed by Tuya Smart. It consists of a highly integrated radio-frequency identification (RFID) chip BK7231T and a few peripheral components, with a built-in Wi-Fi network protocol stack and various library functions.
×1
Tuya Sandwich DC-DC power supply board
Provide power supply to other components of the Tuya Sandwich Evaluation Kit.
×1

Software apps and online services

Tuya Smart app
https://developer.tuya.com/en/docs/iot/tuya-smart-app-smart-life-app-advantages?id=K989rqa49rluq
Adobe AutoCAD
https://www.autodesk.com/products/autocad/overview?support=ADVANCED&term=1-YEAR

Story

Read more

Code

Code snippet #8

Plain text
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;
}

Code snippet #9

Plain text
OPERATE_RET app_plant_init(IN APP_PLANT_MODE mode)
{
    OPERATE_RET op_ret = OPRT_OK;

    if(APP_PLANT_NORMAL == mode) {
        
        // Initialize I/O, sensors, PWM, and more
        plant_device_init();
        
        // Create data collection tasks for I2C sensors
        xTaskCreate(sensor_data_get_iic_theard,"thread_data_get_iic",512,NULL,TRD_PRIO_3,NULL);

        // Create data collection tasks for ADC sensors
        xTaskCreate(sensor_data_get_adc_theard,"thread_data_get_adc",512,NULL,TRD_PRIO_4,NULL);

        // Create data processing tasks
        xTaskCreate(sensor_data_deal_theard,"thread_data_deal",512,NULL,TRD_PRIO_4,NULL);

        // Create scheduled tasks for DP data reporting
        xTaskCreate(sensor_data_report_theard,"thread_data_report",512,NULL,TRD_PRIO_4,NULL);
    }else {
        // Non-production test mode
    }

    return op_ret;
}

Code snippet #10

Plain text
OPERATE_RET app_plant_init(IN APP_PLANT_MODE mode)
{
    OPERATE_RET op_ret = OPRT_OK;

    if(APP_PLANT_NORMAL == mode) {
        
        // Initialize I/O, sensors, PWM, and more
        plant_device_init();
        
        // Create data collection tasks for I2C sensors
        xTaskCreate(sensor_data_get_iic_theard,"thread_data_get_iic",512,NULL,TRD_PRIO_3,NULL);

        // Create data collection tasks for ADC sensors
        xTaskCreate(sensor_data_get_adc_theard,"thread_data_get_adc",512,NULL,TRD_PRIO_4,NULL);

        // Create data processing tasks
        xTaskCreate(sensor_data_deal_theard,"thread_data_deal",512,NULL,TRD_PRIO_4,NULL);

        // Create scheduled tasks for DP data reporting
        xTaskCreate(sensor_data_report_theard,"thread_data_report",512,NULL,TRD_PRIO_4,NULL);
    }else {
        // Non-production test mode
    }

    return op_ret;
}

Code snippet #11

Plain text
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;
}

Code snippet #12

Plain text
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;
}

Code snippet #13

Plain text
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();
    }

}

Code snippet #14

Plain text
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();
    }

}

Code snippet #15

Plain text
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;

}

Code snippet #16

Plain text
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;

}

Code snippet #17

Plain text
typedef struct 
{
    UCHAR_T SDA_PIN;            ///< SDA pin
    UCHAR_T SCL_PIN;            ///< SCL pin
    sht21_resolution_t RESOLUTION;   
}sht21_init_t;

Code snippet #18

Plain text
typedef struct 
{
    UCHAR_T SDA_PIN;            ///< SDA pin
    UCHAR_T SCL_PIN;            ///< SCL pin
    sht21_resolution_t RESOLUTION;   
}sht21_init_t;

Code snippet #19

Plain text
#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);
    
}

Code snippet #20

Plain text
#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);
    
}

Code snippet #21

Plain text
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){ // Remove invalid humidity values less than 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);
}

Code snippet #22

Plain text
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){ // Remove invalid humidity values less than 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);
}

Code snippet #23

Plain text
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;

}

Code snippet #24

Plain text
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;

}

Code snippet #25

Plain text
#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                 LOW

STATIC VOID __ctrl_gpio_init(CONST TY_GPIO_PORT_E port, CONST BOOL_T high)
{
    // Set I/O pin to output mode
    tuya_gpio_inout_set(port, FALSE);
    // Set I/O level
    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();
    
}

Code snippet #26

Plain text
#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                 LOW

STATIC VOID __ctrl_gpio_init(CONST TY_GPIO_PORT_E port, CONST BOOL_T high)
{
    // Set I/O pin to output mode
    tuya_gpio_inout_set(port, FALSE);
    // Set I/O level
    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();
    
}

Code snippet #27

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

Code snippet #1

Plain text
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;
}

Code snippet #28

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

Code snippet #29

Plain text
#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);
......
}

Code snippet #30

Plain text
#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);
......
}

Code snippet #31

Plain text
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){ // Remove invalid humidity values less than 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;
    }

}

Code snippet #32

Plain text
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){ // Remove invalid humidity values less than 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;
    }

}

Code snippet #35

Plain text
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){ // If the I2C temperature and humidity sensor operates previously
        return;
    }

    if((TRUE == plant_ctrl_data.Auto_switch)) { // Automatic light filling is switched on
        USHORT_T current = device_data.light_intensity_value;
        USHORT_T set = light_value_set;

        if((current - set) > ACCURACY) { // Current light intensity is greater than the set value but not within the error range
            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) { // Current light intensity is less than the set value but not within the error range
            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) { // Automatic light filling is switched on
        PR_NOTICE("Ligth open !!!!");
        if(plant_ctrl_data.Light_color == red) { // Set light color to 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) { // Set light color to 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 { // Automatic light filling is switched off. Users manually schedule light filling.
        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);
        }
        // Save timer's remaining time in minute
        plant_report_data.Countdown_left = light_flag_min;
    }
                                                                        
}

VOID plant_ctrl_handle(VOID)
{   
    ......
    __passive_ctrl_module_light();
    __initiative_ctrl_module_light();
}

Code snippet #36

Plain text
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){ // If the I2C temperature and humidity sensor operates previously
        return;
    }

    if((TRUE == plant_ctrl_data.Auto_switch)) { // Automatic light filling is switched on
        USHORT_T current = device_data.light_intensity_value;
        USHORT_T set = light_value_set;

        if((current - set) > ACCURACY) { // Current light intensity is greater than the set value but not within the error range
            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) { // Current light intensity is less than the set value but not within the error range
            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) { // Automatic light filling is switched on
        PR_NOTICE("Ligth open !!!!");
        if(plant_ctrl_data.Light_color == red) { // Set light color to 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) { // Set light color to 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 { // Automatic light filling is switched off. Users manually schedule light filling.
        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);
        }
        // Save timer's remaining time in minute
        plant_report_data.Countdown_left = light_flag_min;
    }
                                                                        
}

VOID plant_ctrl_handle(VOID)
{   
    ......
    __passive_ctrl_module_light();
    __initiative_ctrl_module_light();
}

Code snippet #37

Plain text
VOID plant_get_adc_sensor_data(VOID)
{   // Control switch analog chip to select soil moisture channel
    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);

}

Code snippet #38

Plain text
VOID plant_get_adc_sensor_data(VOID)
{   // Control switch analog chip to select soil moisture channel
    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);

}

Code snippet #39

Plain text
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();
    ......
}

Code snippet #2

Plain text
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;
}

Code snippet #40

Plain text
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();
    ......
}

Code snippet #41

Plain text
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);

}

Code snippet #42

Plain text
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);

}

Code snippet #43

Plain text
#define WATER_PUMP_PORT                     (22)
#define WATER_PUMP_LEVEL                    LOW

STATIC VOID __initiative_ctrl_module_pump(VOID)
{   
    // Convert water level sensor value into remaining water level percentage for data transmission
    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){ // If water pump is switched on
        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) { // When the water level approaches the threshold, the water pump is switched off
        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();
    ......
}

Code snippet #44

Plain text
#define WATER_PUMP_PORT                     (22)
#define WATER_PUMP_LEVEL                    LOW

STATIC VOID __initiative_ctrl_module_pump(VOID)
{   
    // Convert water level sensor value into remaining water level percentage for data transmission
    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){ // If water pump is switched on
        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) { // When the water level approaches the threshold, the water pump is switched off
        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();
    ......
}

Code snippet #3

Plain text
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;
}	 

Code snippet #4

Plain text
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;
}	 

Code snippet #5

Plain text
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;
}

Code snippet #6

Plain text
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;
}

Code snippet #7

Plain text
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;
}

Github

https://github.com/tuya/tuya-iotos-embeded-sdk-wifi-ble-bk7231t

Github

https://github.com/tuya/tuya-iotos-embeded-demo-wifi-ble-smart-planter

Credits

Sandwich IoT
40 projects • 5 followers

Comments