目的:更廉价的物联网仪器解决方案。
当前方案:配置串口安卓平板。
-优势:开发简单,安卓一大把人,好维护。操作人员熟悉操作方式。学习成本低。
-劣势:成本巨高,推广困难。仪器必须预留平板位置。
ESP方案:Bluff配网+Mqtt+tcp/IP+uart
-优势:真便宜啊。占地更小,尤其小仪器。
-劣势:找人很费劲,尤其小团队。用的还不是stm。
实现方式:糅合和官方各种案例,包括,blufi,uart publish,mqtt,socks等样例。(码农原来是这个样子,抄过来整合一下。。)
以下代码是老板亲自糅合的,自己现学现用。代码规范啥的,大家多多给指点以下。一定及时修改更新。以下代码方案完全给大家贡献出来。
PASS:我这边传递的都是stm直接使用的串口指令。所以都是十六进制的BYTE字符串。所以如果有用到传递其他字符串的。需要各位手动修改。代码太多了,就贴重点了。具体代码大家私信我要。人多的话,我再考虑上传git,毕竟有点献丑。。
1.首先:串口接收。
static void uart_event_task(void *pvParameters)
...
uart_event_t event;
size_t buffered_size;
uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE);
char *hexstr_data = malloc(RX_BUF_SIZE);
BLUFI_INFO("for uart event loop begin:");
for(;;)
{
//Waiting for UART event.
if(xQueueReceive(uart_queue, (void * )&event, (portTickType)portMAX_DELAY))
{
bzero(dtmp, RD_BUF_SIZE);
ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
switch(event.type) {
//Event of UART receving data
/*We'd better handler data event fast, there would be much more data events than
other types of events. If we take too much time on data event, the queue might
be full.*/
case UART_DATA:
ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
const int rxBytes = uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
//send to mqtt server
if (rxBytes > 0 && mqtt_is_connected ) {
dtmp[rxBytes] = 0;
ESP_LOGW(TAG, "Read %d bytes: '%s'", rxBytes, dtmp);
esp_log_buffer_hex("Receive Data", dtmp, rxBytes);
int cir_len= sizeof(*dtmp) / sizeof(dtmp[0]);
ESP_LOGI(TAG, "recv data lenth is:%d\n",cir_len);
if ( cir_len > 1 ){
byte_str_hex(dtmp,hexstr_data,cir_len);
// BLUFI_INFO("event publish data is:%s\n",hexstr_data);
if(tcp_socked){
tcp_tx_data = hexstr_data;
}else{
int msg_id = mqtt_send_data(TOPIC_UART,hexstr_data);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d\n", msg_id);
}
}
}
ESP_LOGI(TAG, "[DATA EVT]:");
uart_write_bytes(EX_UART_NUM, (const char*) dtmp, event.size);
break;
//Event of HW FIFO overflow detected
case UART_FIFO_OVF:
ESP_LOGI(TAG, "hw fifo overflow");
// If fifo overflow happened, you should consider adding flow control for your application.
// The ISR has already reset the rx FIFO,
// As an example, we directly flush the rx buffer here in order to read more data.
uart_flush_input(EX_UART_NUM);
xQueueReset(uart_queue);
break;
//Event of UART ring buffer full
case UART_BUFFER_FULL:
ESP_LOGI(TAG, "ring buffer full");
// If buffer full happened, you should consider encreasing your buffer size
// As an example, we directly flush the rx buffer here in order to read more data.
uart_flush_input(EX_UART_NUM);
xQueueReset(uart_queue);
break;
//Event of UART RX break detected
case UART_BREAK:
ESP_LOGI(TAG, "uart rx break");
break;
//Event of UART parity check error
case UART_PARITY_ERR:
ESP_LOGI(TAG, "uart parity error");
break;
//Event of UART frame error
case UART_FRAME_ERR:
ESP_LOGI(TAG, "uart frame error");
break;
//UART_PATTERN_DET
case UART_PATTERN_DET:
uart_get_buffered_data_len(EX_UART_NUM, &buffered_size);
int pos = uart_pattern_pop_pos(EX_UART_NUM);
ESP_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
if (pos == -1) {
// There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
// record the position. We should set a larger queue size.
// As an example, we directly flush the rx buffer here.
uart_flush_input(EX_UART_NUM);
} else {
uart_read_bytes(EX_UART_NUM, dtmp, pos, 100 / portTICK_PERIOD_MS);
uint8_t pat[PATTERN_CHR_NUM + 1];
memset(pat, 0, sizeof(pat));
uart_read_bytes(EX_UART_NUM, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "read data: %s", dtmp);
ESP_LOGI(TAG, "read pat : %s", pat);
}
break;
//Others
default:
ESP_LOGI(TAG, "uart event type: %d", event.type);
break;
}
}
}
free(hexstr_data);
free(dtmp);
dtmp = NULL;
vTaskDelete(NULL);
......
2.其次:MQTT接收。
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
...
static const char *MQTT_TASK_TAG = "MQTT_TASK";
esp_log_level_set(MQTT_TASK_TAG, ESP_LOG_INFO);
esp_mqtt_client_handle_t client = event->client;
int msg_id;
char mqtt_subscribe_topic[128];
sprintf(mqtt_subscribe_topic,"%s%s%s","/",ble_mac_str,"/#");
//inert code from publish
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
xEventGroupSetBits(mqtt_event_group, CONNECTED_BIT);
mqtt_is_connected = true;
BLUFI_INFO("subscribe topic=%s",mqtt_subscribe_topic);
msg_id = esp_mqtt_client_subscribe(client, mqtt_subscribe_topic, 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
//MQTT disconnection
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
mqtt_is_connected = false;
break;
//MQTT send subscribed
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = mqtt_send_data(TOPIC_HEAD,"successful subscribe");
ESP_LOGI(TAG, "sent publish finished, msg_id=%d", msg_id);
BLUFI_INFO("mqtt start and subcribe then send ip\n");
send_ip();
break;
//MQTT unsubscribed
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
//MQTT publish topic
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
//MQTT accept data
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
printf("ID=%d, total_len=%d, data_len=%d, current_data_offset=%d\n", event->msg_id, event->total_data_len, event->data_len, event->current_data_offset);
//send to uart
if( uart_is_connected && strncmp((event->topic),TOPIC_START,strlen(TOPIC_START)) == 0 ) {
// uart_tx_str = malloc(event->data_len);
memcpy(uart_tx_str,(char *)event->data,event->data_len);
uart_tx_str[event->data_len]='\0';
BLUFI_INFO("MQTT TO UART DATA: %s\n",uart_tx_str);
msg_id = mqtt_send_data( TOPIC_CHECK,"equ starting");
}else{
ESP_LOGI(TAG, "MQTT unconnected or topic is not wright code, DATA=%.*s\r\n",event->data_len,event->data);
}
msg_id = mqtt_send_data( TOPIC_CHECK,"65831");
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
break;
case MQTT_EVENT_BEFORE_CONNECT:
ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT");
xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
return ESP_OK;
...
3.其次:TCP/IP接收。(这里有个坑,本来打算用 #ifdef #else #endif 来把代码缩减一下。一直调试不通。。然后直接把IP6,注释掉了。。)
static void tcp_server_task(void *pvParameters)
...
char rx_buffer[128];
char addr_str[128];
int addr_family;
int ip_protocol;
while (1) {
// if(IP_TYPE == AF_INET6){
// struct sockaddr_in6 dest_addr;
// ip6_addr_t ip6_info;
// bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
// dest_addr.sin6_family = IP_TYPE;
// dest_addr.sin6_port = htons(PORT);
// addr_family = IP_TYPE;
// ip_protocol = IPPROTO_IPV6;
// inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
// int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
// if (listen_sock < 0) {
// ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
// break;
// }
// ESP_LOGI(TAG, "Socket created");
// int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
// if (err != 0) {
// ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
// break;
// }
// ESP_LOGI(TAG, "Socket bound, port %d", PORT);
// err = listen(listen_sock, 1);
// if (err != 0) {
// ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
// break;
// }
// ESP_LOGI(TAG, "Socket listening");
// // Large enough for both IPv4 or IPv6
// struct sockaddr_in6 source_addr;
// uint addr_len = sizeof(source_addr);
// int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
// if (sock < 0) {
// ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
// break;
// }
// ESP_LOGI(TAG, "Socket accepted");
// //IP to mqtt server
// tcp_socked = true;
// err = tcpip_adapter_get_ip6_linklocal(TCPIP_IF,&ip6_info);
// char * ptr = inet_ntop(IP_TYPE, &ip6_info, ip_addr_str, sizeof(ip6_addr_t));
// int msg_id= mqtt_send_data(TOPIC_TCP,ip_addr_str);
// ESP_LOGI(TAG, "id=%d\r\nipstr=%s", msg_id, ip_addr_str);
// }else{
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
dest_addr.sin_family = IP_TYPE;
dest_addr.sin_port = htons(PORT);
addr_family = IP_TYPE;
ip_protocol = IPPROTO_IP;
inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (listen_sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket created");
int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket bound, port %d", PORT);
err = listen(listen_sock, 1);
if (err != 0) {
ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket listening");
// Large enough for both IPv4 or IPv6
struct sockaddr_in6 source_addr;
uint addr_len = sizeof(source_addr);
int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket accepted");
//IP to mqtt server
tcp_socked = true;
// }
while (1) {
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
// Error occurred during receiving
if (len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno);
break;
}
// Connection closed
else if (len == 0) {
ESP_LOGI(TAG, "Connection closed");
tcp_socked = false;
break;
}
// Data received
else {
// Get the sender's ip address as string
if (source_addr.sin6_family == PF_INET)
{
inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
} else if (source_addr.sin6_family == PF_INET6)
{
inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
}
// Null-terminate whatever we received and treat like a string
rx_buffer[len] = 0;
ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str);
ESP_LOGI(TAG, "%s", rx_buffer);
//send tcp_data to uart
uart_tx_str = rx_buffer;
//send date by tcp
// int err = send(sock, tcp_tx_data, strlen(tcp_tx_data), 0);
int err = tcp_send_data(sock,rx_buffer,strlen(rx_buffer));
if (err < 0)
{
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break;
}
}
}
if (sock != -1)
{
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
}
}
vTaskDelete(NULL);
...
4.WIFI获得IP后的事件:这里时机很重要。我之前放在独立去初始化后,启动mqtt以及tcpserver的。发现有问题。我改到了WIFI获取到IP事件后。就可以了。
static esp_err_t blufi_net_event_handler(void *ctx, system_event_t *event)
...
wifi_mode_t mode;
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP: {
esp_blufi_extra_info_t info;
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
esp_wifi_get_mode(&mode);
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
memcpy(info.sta_bssid, gl_sta_bssid, 6);
info.sta_bssid_set = true;
info.sta_ssid = gl_sta_ssid;
info.sta_ssid_len = gl_sta_ssid_len;
if (ble_is_connected == true) {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, &info);
} else {
BLUFI_INFO("BLUFI BLE is not connected yet\n");
}
// check wifi link mqtt
if( !mqtt_is_connected ){
BLUFI_INFO("mqtt start\n");
init_mqtt();//MQTT sart
BLUFI_INFO("tcpsever_start\n");
tcpsever_start();
} else {
BLUFI_INFO("MQTT connected yet,evnetid=%d\n",event->event_id);
}
break;
}
case SYSTEM_EVENT_STA_CONNECTED:
gl_sta_connected = true;
memcpy(gl_sta_bssid, event->event_info.connected.bssid, 6);
memcpy(gl_sta_ssid, event->event_info.connected.ssid, event->event_info.connected.ssid_len);
gl_sta_ssid_len = event->event_info.connected.ssid_len;
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
gl_sta_connected = false;
memset(gl_sta_ssid, 0, 32);
memset(gl_sta_bssid, 0, 6);
gl_sta_ssid_len = 0;
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_AP_START:
esp_wifi_get_mode(&mode);
/* TODO: get config or information of softap, then set to report extra_info */
if (ble_is_connected == true) {
if (gl_sta_connected) {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, NULL);
} else {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, 0, NULL);
}
} else {
BLUFI_INFO("BLUFI BLE is not connected yet\n");
}
break;
case SYSTEM_EVENT_SCAN_DONE: {
uint16_t apCount = 0;
esp_wifi_scan_get_ap_num(&apCount);
if (apCount == 0) {
BLUFI_INFO("Nothing AP found");
break;
}
wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);
if (!ap_list) {
BLUFI_ERROR("malloc error, ap_list is NULL");
break;
}
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, ap_list));
esp_blufi_ap_record_t * blufi_ap_list = (esp_blufi_ap_record_t *)malloc(apCount * sizeof(esp_blufi_ap_record_t));
if (!blufi_ap_list) {
if (ap_list) {
free(ap_list);
}
BLUFI_ERROR("malloc error, blufi_ap_list is NULL");
break;
}
for (int i = 0; i < apCount; ++i)
{
blufi_ap_list[i].rssi = ap_list[i].rssi;
memcpy(blufi_ap_list[i].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid));
}
if (ble_is_connected == true) {
//send result
esp_blufi_send_wifi_list(apCount, blufi_ap_list);
} else {
BLUFI_INFO("BLUFI BLE is not connected yet\n");
}
esp_wifi_scan_stop();
free(ap_list);
free(blufi_ap_list);
break;
}
default:
break;
}
return ESP_OK;
...
5.其他,之后的都不是重点了,我把结构给大家贴出来。
...
static esp_mqtt_client_config_t mqtt_cfg = {
static esp_ble_adv_data_t ble_adv_data = {
static esp_ble_adv_params_t ble_adv_params = {
static void init_mqtt(void);
static char hex_char(char cstr)
int hexstr_to_hexbyte( char *hexstr, char *bytestr)
void byte_str_hex( uint8_t *sSrc, char *sDest,int nSrcLen )
int uart_send_data(const char* logName, const char* data,size_t size)
void tx_task()
int mqtt_send_data(const char *topic_str,char *data )
int tcp_send_data(int s,void *data,size_t size)
static void tcp_server_task(void *pvParameters)
static void send_ip()
static void tcpsever_start()
static void uart_event_task(void *pvParameters)
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
static void blufi_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
static void ble_gap_event_adv_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
static esp_err_t blufi_net_event_handler(void *ctx, system_event_t *event)
static esp_blufi_callbacks_t security_callbacks = {
static void init_mqtt(void){
static void set_ble_adv(void){
static void init_blufi(void){
static void init_wifi(void)
static void init_uart(void){
void app_main()
{
esp_err_t ret;
/* init NVS
*/
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
/* link to MCU
*/
BLUFI_INFO("UART start initialise,please wait a miniutes\n");
init_uart();
BLUFI_INFO("UART finished initialise\n");
/* link to wifi
*/
BLUFI_INFO("WIFI start initialise,please wait a miniutes\n");
init_wifi();
BLUFI_INFO("wifi finished initialise\n");
/* open the ble
*/
BLUFI_INFO("BLE start initialise,please wait a miniutes\n");
init_blufi();
BLUFI_INFO("BLE finished initialise\n");
}
...
好了,基本就是这样。如果大家有需要私信我吧。