闲聊:

最近更新的有点慢了,工作上的事加上朋友的婚礼,还好我赶在参加婚礼前把前一个发了,不然两篇博客的周期就是二十多天了。以前想的是争取每周发一篇,现在想想我的工作性质不太现实了;还有一个考虑就是我确实不知道该写一些什么上来,低端的不想写,高端的写不了。(也可征集一下网友们的意见)    导致目前就有点被动,又想着最近疫情又有反复,自己一个人在家还是需要把学到的东西做一个积累,我还是把之后想做的写出来,也好和其他网友对比一下做项目的方式方法。

整体思路:

使用ESP32作为客户端连接路由器继而连接远程服务器,通过服务器后台程序对数据库做保存和读取,实现手机微信小程序访问远程服务器的数据库做状态设置和获取,ESP32连接远程服务器做底层设备的状态查询和开关量动作。我目前是在虚拟机里面安装的Ubuntu18.04,然后使用esp-idf-v3.3.1   VScode配置开发esp sdk开发。要是同样使用此方法开发的朋友门,可以搜一下  Ubuntu 搭建 ESP32 开发环境(vscode)。开发环境搭建,就不在本章文章中展现了。只需要做一个后台控制程序,然后做了一个网页版的设备管理平台就可以实现这个过程。

设备管理平台如下图,主要功能是添加设备,更改底层设备类型,绑定微信用户名,管理微信用户名下的底层设备。

源码链接:https://download.csdn.net/download/L_e_c/14141534

硬件设计:

淘宝购买的220转12V的模块,加上两个LDO,设计两路继电器,画的PCB之前想的是学习用处,所以把引脚都引出来了,比较大。有想学习的,也可以私信我,成品原价出。原理图及PCB效果图如下。

源码设计:

因为ESP32SDK开发,乐鑫提供的程序入口其实就是一个任务函数,所以启动后的任务名字是固定的,我们可以根据这个任务处理函数来做我们自己的程序,这样开发起来也更简单。我们主要使用了GPIO,UART,TCP,CJSON。主函数里面主要做一些初始化,然后建立WiFi_STA,创建客户端,然后设置一个连接服务器的任务,连接任务中做了一个底层设备注册函数Sign_IN_Device()和设备状态反馈函数Device_State()。在连接任务函数里面再设置两个接收任务,一个是串口调试用的,一个是网络接收任务,接收到的字符串放到processMessage()函数来处理,根据不同的键值和键值对反馈不同的结果,处理不同的命令。程序的源码差不多就只需要这么多,我只是分享了一个思路和基于乐鑫提供的源码上做的一个工程,要是想做这方面的还是需要多了解乐鑫源码或者WiFi协议。

void app_main(void)
{
    //初始化IO口
    gpio_pad_select_gpio(LED_R_IO);
    gpio_set_direction(LED_R_IO,GPIO_MODE_OUTPUT);  //设置IO为输出
    //初始化串口,主要做调试使用
    uart_init();
    //初始化flash
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

#if TCP_SERVER_CLIENT_OPTION
    //server,建立ap
    wifi_init_softap();
#else
    //client,建立sta
    wifi_init_sta();
#endif
    
    //新建一个tcp连接任务
    xTaskCreate(&tcp_connect, "tcp_connect", 4096, NULL, 5, NULL);
}
static void tcp_connect(void *pvParameters)
{
    while (1)
    {
        Sign_IN_State = 0;
        g_rxtx_need_restart = false;
        //等待WIFI连接信号量,死等
        xEventGroupWaitBits(tcp_event_group, WIFI_CONNECTED_BIT, false, true, portMAX_DELAY);
        ESP_LOGI(TAG, "start tcp connected");

        TaskHandle_t tx_rx_task = NULL;
#if TCP_SERVER_CLIENT_OPTION
        //延时3S准备建立server
        vTaskDelay(3000 / portTICK_RATE_MS);
        ESP_LOGI(TAG, "create tcp server");
        //建立server
        int socket_ret = create_tcp_server(true);
#else
        //延时3S准备建立clien
        vTaskDelay(3000 / portTICK_RATE_MS);
        ESP_LOGI(TAG, "create tcp Client");
        //建立client
        int socket_ret = create_tcp_client();
#endif
        if (socket_ret == ESP_FAIL)
        {
            //建立失败
            ESP_LOGI(TAG, "create tcp socket error,stop...");
            continue;
        }
        else
        {
            //建立成功
            ESP_LOGI(TAG, "create tcp socket succeed...");            
            Sign_IN_Device();
            //建立tcp接收数据任务
            //创建串口2接收任务
            xTaskCreate(uart2_rx_task, "uart2_rx_task", 1024*2, NULL, configMAX_PRIORITIES-1, NULL);
            //串口2数据发送测试		
            uart_write_bytes(UART_NUM_2, "uart2 test OK ", strlen("uart2 test OK "));
            if (pdPASS != xTaskCreate(&recv_data, "recv_data", 4096, NULL, 4, &tx_rx_task))
            {
                //建立失败
                ESP_LOGI(TAG, "Recv task create fail!");
            }
            else
            {
                //建立成功
                ESP_LOGI(TAG, "Recv task create succeed!");
            }

        }


        while (1)
        {

            vTaskDelay(3000 / portTICK_RATE_MS);

#if TCP_SERVER_CLIENT_OPTION
            //重新建立server,流程和上面一样
            if (g_rxtx_need_restart)
            {
                ESP_LOGI(TAG, "tcp server error,some client leave,restart...");
                //建立server
                if (ESP_FAIL != create_tcp_server(false))
                {
                    if (pdPASS != xTaskCreate(&recv_data, "recv_data", 4096, NULL, 4, &tx_rx_task))
                    {
                        ESP_LOGE(TAG, "tcp server Recv task create fail!");
                    }
                    else
                    {
                        ESP_LOGI(TAG, "tcp server Recv task create succeed!");
                        //重新建立完成,清除标记
                        g_rxtx_need_restart = false;
                    }
                }
            }
#else
            //重新建立client,流程和上面一样
            if (g_rxtx_need_restart)
            {
                Sign_IN_State=0;
                vTaskDelay(3000 / portTICK_RATE_MS);
                ESP_LOGI(TAG, "reStart create tcp client...");
                //建立client
                int socket_ret = create_tcp_client();

                if (socket_ret == ESP_FAIL)
                {
                    ESP_LOGE(TAG, "reStart create tcp socket error,stop...");
                    continue;
                }
                else
                {
                    ESP_LOGI(TAG, "reStart create tcp socket succeed...");
                    //重新建立完成,清除标记
                    g_rxtx_need_restart = false;
                    //建立tcp接收数据任务
                    if (pdPASS != xTaskCreate(&recv_data, "recv_data", 4096, NULL, 4, &tx_rx_task))
                    {
                        ESP_LOGE(TAG, "reStart Recv task create fail!");
                    }
                    else
                    {
                        ESP_LOGI(TAG, "reStart Recv task create succeed!");
                    }
                }
            }
            else 
            {
                if(Sign_IN_State==0)
                {
                    Send_Count=0;
                    Sign_IN_Device();   
                    ESP_LOGI(TAG, "delay_3s!"); 
                }
                else 
                {
                    if(++Send_Count>=3)
                    {
                        Send_Count=0;
                        Device_State();
                        ESP_LOGI(TAG, "delay_9s!");
                    }
                    
                }
                
            }
#endif
        }
    }

    vTaskDelete(NULL);
}
void Sign_IN_Device(void)
{
    cJSON *pRoot = cJSON_CreateObject();

	//新增一个字段TYPE到根点
	cJSON_AddStringToObject(pRoot,"TYPE","HS");
	cJSON_AddStringToObject(pRoot,"CID","bangongshi");
	char *s = cJSON_Print(pRoot);
	send(connect_socket, s, strlen(s), 0);
	//释放内存
	cJSON_free((void *) s);
	cJSON_Delete(pRoot);
}

void Device_State(void)
{
    cJSON *pRoot = cJSON_CreateObject();

	//新增一个字段TYPE到根点
	cJSON_AddStringToObject(pRoot,"TYPE","STATE");
    cJSON_AddNumberToObject(pRoot,"state",1);
	cJSON_AddNumberToObject(pRoot,"relay",Relay_Num);
	char *s = cJSON_Print(pRoot);
	send(connect_socket, s, strlen(s), 0);
	//释放内存
	cJSON_free((void *) s);
	cJSON_Delete(pRoot);
}

int processMessage(char *msg) {
	cJSON *jsonObj=cJSON_Parse(msg);
	cJSON *method;
	cJSON *typ;
    char *m;
	int x;
	
    
    //json字符串解析失败,直接退出
    if(!jsonObj)
    {
		cJSON_Delete(jsonObj);
        return 0;
    }
    method = cJSON_GetObjectItem(jsonObj, "TYPE");
    m = method->valuestring;
	if(strncmp(m, "AUTHERROR", 9) == 0 ) //设备未注册,重新注册
    {
		cJSON_Delete(jsonObj);
        return 1;
//        char *content = cJSON_GetObjectItem(jsonObj, "DATA")->valuestring;	
//        if(strncmp(content, "No identity", 4) == 0)
//        {
//			
//        }
    }
    if(strncmp(m, "HSOK", 4) == 0 ) //注册信息返回
    {
        char *content = cJSON_GetObjectItem(jsonObj, "DATA")->valuestring;	
        if(strncmp(content, "HSOK", 4) == 0)
        {
			cJSON_Delete(jsonObj);
            return 2;
        }
    }
	if(strncmp(m, "DATAOK", 6) == 0 ) //
    {
        char *content = cJSON_GetObjectItem(jsonObj, "TYPE")->valuestring;	
        if(strncmp(content, "DATAOK", 6) == 0)
        {
			// Resert_Cnt_10S=0; //重启时间清零
			cJSON_Delete(jsonObj);
            return 3;
        }
    }
	if(strncmp(m, "CDATA", 5) == 0 ) //
    {
		typ = cJSON_GetObjectItem(jsonObj, "relay");
		x=typ->valueint;
//		if(strncmp(m, "1", 1) == 0 ) 
		if(x==0)    //关灯
		{	
            return 4;
		}
		else if(x==1) //
		{
            return 5;
		}
    }
	
//    if(jsonObj)
		cJSON_Delete(jsonObj);
    return 0;
}

调试结果:

视频演示地址:微信小程序远程控制家用设备开关。esp32 SDK开发,CSDN上有文章介绍。%电子产品 %孤独的最高境界  https://v.douyin.com/JnkgxVw/ 复制此链接,打开抖音搜索,直接观看视频!

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐