├── CMakeLists.txt ├── LICENSE ├── README.md ├── main ├── CMakeLists.txt ├── Kconfig.projbuild ├── component.mk ├── idf_component.yml ├── main.c ├── mqtt_publisher.c ├── mqtt_server.c ├── mqtt_server.h └── mqtt_subscriber.c ├── mqtt_pub.sh ├── mqtt_sub.sh ├── pub_example.py ├── sdkconfig.defaults ├── sub_example.py └── unsub_example.py /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following five lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 6 | project(mqtt-broker) 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 nopnop2002 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp-idf-mqtt-broker 2 | MQTT Broker for esp-idf. 3 | This project use [Mongoose networking library](https://github.com/cesanta/mongoose). 4 | I forked from [here](https://github.com/bigw00d/esp32_mongoose_sample). 5 | However, with the release of mongoose ver7, I rewrote it. 6 | Your fork is welcome. 7 | 8 | 9 | # Installation overview 10 | 11 | 1. In this project directory, create a components directory. 12 | 13 | 2. In the components directory, clone Mongoose version 7.9: 14 | ``` 15 | git clone -b 7.9 https://github.com/cesanta/mongoose.git 16 | ``` 17 | 18 | 3. In the new Mongoose directory, create a CMakeLists.txt file containing: 19 | ``` 20 | idf_component_register(SRCS "mongoose.c" PRIV_REQUIRES esp_timer INCLUDE_DIRS ".") 21 | ``` 22 | 23 | 4. Compile this project. 24 | 25 | # Software requiment 26 | - mongoose version 7.9. 27 | The version of mongoose is written [here](https://github.com/cesanta/mongoose/blob/master/mongoose.h#L23). 28 | 29 | - ESP-IDF V5.0 or later. 30 | ESP-IDF V4.4 release branch reached EOL in July 2024. 31 | 32 | 33 | # Installation 34 | ``` 35 | git clone https://github.com/nopnop2002/esp-idf-mqtt-broker 36 | cd esp-idf-mqtt-broker 37 | mkdir components 38 | cd components/ 39 | git clone -b 7.9 https://github.com/cesanta/mongoose.git 40 | cd mongoose/ 41 | echo "idf_component_register(SRCS \"mongoose.c\" PRIV_REQUIRES esp_timer INCLUDE_DIRS \".\")" > CMakeLists.txt 42 | cd ../.. 43 | idf.py set-target {esp32/esp32s2/esp32s3/esp32c2/esp32c3/esp32c6} 44 | idf.py menuconfig 45 | idf.py flash monitor 46 | ``` 47 | 48 | 49 | # Application Setting 50 | 51 | ![config-1](https://user-images.githubusercontent.com/6020549/110200312-a307da00-7ea0-11eb-85fa-c76f932b8023.jpg) 52 | 53 | ## Station mode with dynamic address 54 | ![config-2](https://github.com/user-attachments/assets/27656823-913b-4d91-8582-b4d9d74e36d2) 55 | 56 | SSID:SSID of your Wifi router 57 | ESP32 get IP using DHCP. 58 | 59 | ## Station mode with static address 60 | ![config-3](https://github.com/user-attachments/assets/7a9fef57-be24-4f40-bc20-50ab08d26dab) 61 | 62 | SSID:SSID of your Wifi router 63 | ESP32 set your specific IP. 64 | 65 | ## Using mDNS hostname 66 | You can connect using the mDNS hostname instead of the IP address. 67 | 68 | ![mdns-1](https://user-images.githubusercontent.com/6020549/93420660-60e6de00-f8ea-11ea-9783-3c295130a840.jpg) 69 | 70 | ![mdns-2](https://user-images.githubusercontent.com/6020549/93420837-cdfa7380-f8ea-11ea-952c-64113c929df7.jpg) 71 | 72 | You can change mDNS hostname using menuconfig. 73 | 74 | ![config-5](https://github.com/user-attachments/assets/6c7186e0-cd0a-4637-b80d-2c28e5544915) 75 | 76 | ## Access Point Mode 77 | ![config-4](https://github.com/user-attachments/assets/86827b30-6de7-4ff9-b0ac-62ec1cb1b9c0) 78 | 79 | SSID:SSID of ESP32 80 | ESP32 have 192.168.4.1. 81 | 82 | 83 | 84 | ## Start Built-In MQTT Subscriber 85 | ![config-6](https://github.com/user-attachments/assets/29422815-1711-4c6a-8731-8aee51ac854c) 86 | 87 | ## Start Built-In MQTT Publisher 88 | ![config-7](https://github.com/user-attachments/assets/ec60c145-467e-4a62-aaa4-cea89680b43c) 89 | 90 | ## Enable Authentication 91 | When authentication is enabled, a username and password are required to connect to the server. 92 | ![config-8](https://github.com/user-attachments/assets/f4554a18-31d6-4e95-9839-8d292130383f) 93 | 94 | 95 | # Limitations 96 | - will topics 97 | will qos and will retain are ignored. 98 | 99 | - Unsupported MQTT request 100 | Do not respond to these MQTT requests: 101 | PUBREC 102 | PUBREL 103 | PUBCOMP 104 | 105 | # Publish using mosquitto-clients 106 | ``` 107 | $ sudo apt install mosquitto-clients moreutils 108 | $ chmod 777 ./mqtt_sub.sh 109 | $ ./mqtt_pub.sh 110 | ``` 111 | 112 | # Subscribe using mosquitto-clients 113 | ``` 114 | $ sudo apt install mosquitto-clients moreutils 115 | $ chmod 777 ./mqtt_sub.sh 116 | $ ./mqtt_sub.sh 117 | 23/02/19 12:35:16 topic 2023/02/19-12:35:16 118 | 23/02/19 12:35:17 topic 2023/02/19-12:35:17 119 | 23/02/19 12:35:18 topic 2023/02/19-12:35:18 120 | 23/02/19 12:35:19 topic 2023/02/19-12:35:19 121 | 23/02/19 12:35:21 topic 2023/02/19-12:35:20 122 | ``` 123 | 124 | # Notify topic of will using mosquitto-clients 125 | - In Terminal #1, do the following: 126 | ``` 127 | $ mosquitto_sub -v -h esp32-broker.local -p 1883 -t "topic/#" --will-topic "topic/will" --will-payload "GOODBYE" 128 | ``` 129 | 130 | - Open new terminal. In Terminal #2, do the following: 131 | ``` 132 | $ mosquitto_sub -v -h esp32-broker.local -p 1883 -t "topic/#" 133 | ``` 134 | 135 | - Press Control+C in Terminal #1: 136 | 137 | - The following is displayed in Terminal #2: 138 | ``` 139 | topic/will GOODBYE 140 | ``` 141 | 142 | # Unsubscribe using python and paho 143 | V2 of the Paho library was released in February 2024. 144 | ``` 145 | $ python3 -m pip install -U paho-mqtt 146 | $ python3 unsub_example.py 147 | 148 | Connected with result code 0 149 | subscribe hoge 150 | 151 | Received message 'b'test'' on topic 'hoge/1' with QoS 1 152 | unsubscribe hoge, subscribe fuga 153 | 154 | Received message 'b'test'' on topic 'fuga/1' with QoS 1 155 | unsubscribe fuga, subscribe hoge 156 | ``` 157 | 158 | First, it subscribes to the topic [hoge/#]. 159 | When it receives the topic [hoge/1], it unsubscribes [hoge/#] and subscribes to [fuga/#]. 160 | When it receives the topic [fuga/1], it unsubscribes [fuga/#] and subscribes to [hoge/#] again. 161 | 162 | # Screen Shot 163 | The message flows like this: 164 | PUBLISH->BROKER->SUBSCRIBE 165 | ![ScreenShot](https://user-images.githubusercontent.com/6020549/110209284-e2e5b600-7ece-11eb-8fb3-941e6fdf56c6.jpg) 166 | 167 | 168 | # mosquitto broker 169 | mosquitto broker is [here](https://github.com/espressif/esp-protocols/tree/master/components/mosquitto). 170 | mosquitto broker supports not only WiFi but also Ethernet. 171 | mosquitto broker supports TLS transport layer. 172 | ``` 173 | git clone --recursive https://github.com/espressif/esp-protocols 174 | cd esp-protocols/components/mosquitto/ 175 | cd examples/broker/ 176 | idf.py menuconfig 177 | idf.py build 178 | ``` 179 | -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(COMPONENT_SRCS main.c mqtt_server.c mqtt_subscriber.c mqtt_publisher.c) 2 | set(COMPONENT_ADD_INCLUDEDIRS ".") 3 | 4 | register_component() 5 | -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Application Configuration" 2 | 3 | choice WIFI_MODE 4 | prompt "Wi-Fi Access mode" 5 | default ST_MODE 6 | help 7 | Select Wi-Fi Access mode. 8 | config ST_MODE 9 | bool "Station MODE" 10 | help 11 | Wi-Fi is Station Mode. 12 | config AP_MODE 13 | bool "Access Point MODE" 14 | help 15 | Wi-Fi is Access Point Mode. 16 | endchoice 17 | 18 | config ESP_WIFI_SSID 19 | string "WiFi SSID" 20 | default "myssid" 21 | help 22 | SSID (network name) for the example to connect to. 23 | 24 | config ESP_WIFI_PASSWORD 25 | string "WiFi Password" 26 | default "mypassword" 27 | help 28 | WiFi password (WPA or WPA2) for the example to use. 29 | 30 | config ESP_MAX_STA_CONN 31 | depends on AP_MODE 32 | int "Maximum STA connections" 33 | default 4 34 | help 35 | Max number of the STA connects to AP. 36 | 37 | config ESP_MAXIMUM_RETRY 38 | depends on ST_MODE 39 | int "Maximum number of retries" 40 | default 5 41 | help 42 | Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. 43 | 44 | config MDNS_HOSTNAME 45 | depends on ST_MODE 46 | string "mDNS Hostname" 47 | default "esp32-broker" 48 | help 49 | mDNS Hostname for example to use 50 | 51 | config STATIC_IP 52 | depends on ST_MODE 53 | bool "Enable Static IP Address" 54 | default false 55 | help 56 | Enable Static IP Address. 57 | 58 | config STATIC_IP_ADDRESS 59 | depends on STATIC_IP 60 | string "Static IP Address" 61 | default "192.168.10.100" 62 | help 63 | Static IP Address for Station. 64 | 65 | config STATIC_GW_ADDRESS 66 | depends on STATIC_IP 67 | string "Static GW Address" 68 | default "192.168.10.1" 69 | help 70 | Static GW Address for Station. 71 | 72 | config STATIC_NM_ADDRESS 73 | depends on STATIC_IP 74 | string "Static Netmask" 75 | default "255.255.255.0" 76 | help 77 | Static Netmask for Station. 78 | 79 | config SUBSCRIBE 80 | bool "Start MQTT SUBSCRIBER" 81 | default false 82 | help 83 | Start MQTT SUBSCRIBER. 84 | 85 | config PUBLISH 86 | bool "Start MQTT PUBLISHER" 87 | default false 88 | help 89 | Start MQTT PUBLISHER. 90 | 91 | config BROKER_AUTHENTICATION 92 | bool "Server requests for password when connecting" 93 | default false 94 | help 95 | Server requests for password when connecting. 96 | 97 | config AUTHENTICATION_USERNAME 98 | depends on BROKER_AUTHENTICATION 99 | string "Username used for connecting to the broker" 100 | default "user" 101 | help 102 | Username used for connecting to the broker. 103 | 104 | config AUTHENTICATION_PASSWORD 105 | depends on BROKER_AUTHENTICATION 106 | string "Password used for connecting to the broker" 107 | default "password" 108 | help 109 | Username used for connecting to the broker. 110 | 111 | endmenu 112 | -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /main/idf_component.yml: -------------------------------------------------------------------------------- 1 | ## IDF Component Manager Manifest File 2 | dependencies: 3 | espressif/mdns: 4 | version: "^1.0.3" 5 | rules: 6 | - if: "idf_version >=5.0" 7 | -------------------------------------------------------------------------------- /main/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | MQTT Broker for ESP32 3 | 4 | This code is in the Public Domain (or CC0 licensed, at your option.) 5 | 6 | Unless required by applicable law or agreed to in writing, this 7 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include "freertos/FreeRTOS.h" 15 | #include "freertos/task.h" 16 | #include "freertos/event_groups.h" 17 | #include "esp_mac.h" 18 | #include "esp_wifi.h" 19 | #include "esp_event.h" 20 | #include "esp_log.h" 21 | #include "nvs_flash.h" 22 | #include "esp_vfs_fat.h" 23 | #include "mdns.h" 24 | 25 | #include "lwip/dns.h" 26 | 27 | #include "mongoose.h" 28 | 29 | #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) 30 | #define esp_vfs_fat_spiflash_mount esp_vfs_fat_spiflash_mount_rw_wl 31 | #define esp_vfs_fat_spiflash_unmount esp_vfs_fat_spiflash_unmount_rw_wl 32 | #endif 33 | 34 | /* This project use WiFi configuration that you can set via 'make menuconfig'. 35 | 36 | If you'd rather not, just change the below entries to strings with 37 | the config you want - ie #define ESP_WIFI_SSID "mywifissid" 38 | */ 39 | 40 | #if CONFIG_ST_MODE 41 | /* FreeRTOS event group to signal when we are connected*/ 42 | static EventGroupHandle_t s_wifi_event_group; 43 | static int s_retry_num = 0; 44 | #endif 45 | 46 | /* The event group allows multiple bits for each event, but we only care about one event 47 | * - are we connected to the AP with an IP? */ 48 | const int WIFI_CONNECTED_BIT = BIT0; 49 | 50 | static const char *TAG = "MAIN"; 51 | 52 | char *MOUNT_POINT = "/root"; 53 | 54 | static void event_handler(void* arg, esp_event_base_t event_base, 55 | int32_t event_id, void* event_data) 56 | { 57 | if (event_base == WIFI_EVENT) ESP_LOGI(TAG, "WIFI_EVENT event_id=%"PRIi32, event_id); 58 | if (event_base == IP_EVENT) ESP_LOGI(TAG, "IP_EVENT event_id=%"PRIi32, event_id); 59 | 60 | #if CONFIG_AP_MODE 61 | if (event_id == WIFI_EVENT_AP_STACONNECTED) { 62 | wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data; 63 | ESP_LOGI(TAG, "station "MACSTR" join, AID=%d", 64 | MAC2STR(event->mac), event->aid); 65 | } else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) { 66 | wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data; 67 | ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d", 68 | MAC2STR(event->mac), event->aid); 69 | } 70 | #endif 71 | 72 | #if CONFIG_ST_MODE 73 | if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { 74 | esp_wifi_connect(); 75 | } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { 76 | if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) { 77 | esp_wifi_connect(); 78 | xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT); 79 | s_retry_num++; 80 | ESP_LOGI(TAG, "retry to connect to the AP"); 81 | } 82 | ESP_LOGI(TAG,"connect to the AP fail"); 83 | } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { 84 | ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; 85 | ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); 86 | s_retry_num = 0; 87 | xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); 88 | } 89 | #endif 90 | } 91 | 92 | #if CONFIG_AP_MODE 93 | void wifi_init_softap() 94 | { 95 | ESP_LOGI(TAG,"ESP-IDF Ver%d.%d", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR); 96 | ESP_LOGI(TAG,"ESP_IDF_VERSION %d", ESP_IDF_VERSION); 97 | 98 | //#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 1 99 | #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 1, 0) 100 | ESP_LOGI(TAG,"ESP-IDF esp_netif"); 101 | ESP_ERROR_CHECK(esp_netif_init()); 102 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 103 | esp_netif_create_default_wifi_ap(); 104 | #else 105 | ESP_LOGE(TAG,"esp-idf version 4.1 or higher required"); 106 | while(1) { 107 | vTaskDelay(1); 108 | } 109 | #endif 110 | 111 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 112 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 113 | 114 | //ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL)); 115 | ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); 116 | 117 | wifi_config_t wifi_config = { 118 | .ap = { 119 | .ssid = CONFIG_ESP_WIFI_SSID, 120 | .ssid_len = strlen(CONFIG_ESP_WIFI_SSID), 121 | .password = CONFIG_ESP_WIFI_PASSWORD, 122 | .max_connection = CONFIG_ESP_MAX_STA_CONN, 123 | .authmode = WIFI_AUTH_WPA_WPA2_PSK 124 | }, 125 | }; 126 | if (strlen(CONFIG_ESP_WIFI_PASSWORD) == 0) { 127 | wifi_config.ap.authmode = WIFI_AUTH_OPEN; 128 | } 129 | 130 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); 131 | ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config)); 132 | ESP_ERROR_CHECK(esp_wifi_start()); 133 | 134 | ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s", 135 | CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD); 136 | } 137 | #endif // CONFIG_AP_MODE 138 | 139 | #if CONFIG_ST_MODE 140 | void wifi_init_sta() 141 | { 142 | s_wifi_event_group = xEventGroupCreate(); 143 | 144 | ESP_LOGI(TAG,"ESP-IDF Ver%d.%d", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR); 145 | ESP_LOGI(TAG,"ESP_IDF_VERSION %d", ESP_IDF_VERSION); 146 | 147 | //#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 1 148 | #if ESP_IDF_VERSION > ESP_IDF_VERSION_VAL(4, 1, 0) 149 | ESP_LOGI(TAG,"ESP-IDF esp_netif"); 150 | ESP_ERROR_CHECK(esp_netif_init()); 151 | ESP_ERROR_CHECK(esp_event_loop_create_default()); 152 | esp_netif_t *netif = esp_netif_create_default_wifi_sta(); 153 | assert(netif); 154 | #else 155 | ESP_LOGE(TAG,"esp-idf version 4.1 or higher required"); 156 | while(1) { 157 | vTaskDelay(1); 158 | } 159 | #endif // ESP_IDF_VERSION 160 | 161 | #if CONFIG_STATIC_IP 162 | 163 | ESP_LOGI(TAG, "CONFIG_STATIC_IP_ADDRESS=[%s]",CONFIG_STATIC_IP_ADDRESS); 164 | ESP_LOGI(TAG, "CONFIG_STATIC_GW_ADDRESS=[%s]",CONFIG_STATIC_GW_ADDRESS); 165 | ESP_LOGI(TAG, "CONFIG_STATIC_NM_ADDRESS=[%s]",CONFIG_STATIC_NM_ADDRESS); 166 | 167 | /* Stop DHCP client */ 168 | ESP_ERROR_CHECK(esp_netif_dhcpc_stop(netif)); 169 | ESP_LOGI(TAG, "Stop DHCP Services"); 170 | 171 | /* Set STATIC IP Address */ 172 | esp_netif_ip_info_t ip_info; 173 | memset(&ip_info, 0 , sizeof(esp_netif_ip_info_t)); 174 | ip_info.ip.addr = ipaddr_addr(CONFIG_STATIC_IP_ADDRESS); 175 | ip_info.netmask.addr = ipaddr_addr(CONFIG_STATIC_NM_ADDRESS); 176 | ip_info.gw.addr = ipaddr_addr(CONFIG_STATIC_GW_ADDRESS);; 177 | esp_netif_set_ip_info(netif, &ip_info); 178 | 179 | /* 180 | I referred from here. 181 | https://www.esp32.com/viewtopic.php?t=5380 182 | 183 | if we should not be using DHCP (for example we are using static IP addresses), 184 | then we need to instruct the ESP32 of the locations of the DNS servers manually. 185 | Google publicly makes available two name servers with the addresses of 8.8.8.8 and 8.8.4.4. 186 | */ 187 | 188 | ip_addr_t d; 189 | d.type = IPADDR_TYPE_V4; 190 | d.u_addr.ip4.addr = 0x08080808; //8.8.8.8 dns 191 | dns_setserver(0, &d); 192 | d.u_addr.ip4.addr = 0x08080404; //8.8.4.4 dns 193 | dns_setserver(1, &d); 194 | 195 | #endif // CONFIG_STATIC_IP 196 | 197 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 198 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 199 | 200 | ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); 201 | ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); 202 | 203 | wifi_config_t wifi_config = { 204 | .sta = { 205 | .ssid = CONFIG_ESP_WIFI_SSID, 206 | .password = CONFIG_ESP_WIFI_PASSWORD 207 | }, 208 | }; 209 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); 210 | ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); 211 | ESP_ERROR_CHECK(esp_wifi_start() ); 212 | 213 | ESP_LOGI(TAG, "wifi_init_sta finished."); 214 | ESP_LOGI(TAG, "connect to ap SSID:%s password:%s", 215 | CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD); 216 | 217 | // wait for IP_EVENT_STA_GOT_IP 218 | while(1) { 219 | /* Wait forever for WIFI_CONNECTED_BIT to be set within the event group. 220 | Clear the bits beforeexiting. */ 221 | EventBits_t uxBits = xEventGroupWaitBits(s_wifi_event_group, 222 | WIFI_CONNECTED_BIT, /* The bits within the event group to waitfor. */ 223 | pdTRUE, /* WIFI_CONNECTED_BIT should be cleared before returning. */ 224 | pdFALSE, /* Don't waitfor both bits, either bit will do. */ 225 | portMAX_DELAY);/* Wait forever. */ 226 | if ( ( uxBits & WIFI_CONNECTED_BIT ) == WIFI_CONNECTED_BIT ){ 227 | ESP_LOGI(TAG, "WIFI_CONNECTED_BIT"); 228 | break; 229 | } 230 | } 231 | ESP_LOGI(TAG, "Got IP Address."); 232 | } 233 | 234 | void initialise_mdns(void) 235 | { 236 | //initialize mDNS 237 | ESP_ERROR_CHECK( mdns_init() ); 238 | //set mDNS hostname (required if you want to advertise services) 239 | ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) ); 240 | ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME); 241 | 242 | //initialize service 243 | ESP_ERROR_CHECK( mdns_service_add(NULL, "_mqtt", "_tcp", 1883, NULL, 0) ); 244 | 245 | #if 0 246 | //set default mDNS instance name 247 | ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") ); 248 | #endif 249 | } 250 | #endif // CONFIG_ST_MODE 251 | 252 | void mqtt_server(void *pvParameters); 253 | void http_server(void *pvParameters); 254 | void mqtt_subscriber(void *pvParameters); 255 | void mqtt_publisher(void *pvParameters); 256 | 257 | void app_main() 258 | { 259 | //Initialize NVS 260 | esp_err_t ret = nvs_flash_init(); 261 | if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { 262 | ESP_ERROR_CHECK(nvs_flash_erase()); 263 | ret = nvs_flash_init(); 264 | } 265 | ESP_ERROR_CHECK(ret); 266 | 267 | #if CONFIG_AP_MODE 268 | ESP_LOGI(TAG, "ESP_WIFI_MODE_AP"); 269 | wifi_init_softap(); 270 | esp_netif_ip_info_t ip_info; 271 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_AP_DEF"), &ip_info)); 272 | ESP_LOGI(TAG, "ESP32 is AP MODE"); 273 | #endif 274 | 275 | #if CONFIG_ST_MODE 276 | ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); 277 | wifi_init_sta(); 278 | initialise_mdns(); 279 | esp_netif_ip_info_t ip_info; 280 | ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info)); 281 | ESP_LOGI(TAG, "ESP32 is STA MODE"); 282 | #endif 283 | 284 | /* Print the local IP address */ 285 | //ESP_LOGI(TAG, "IP Address : %s", ip4addr_ntoa(&ip_info.ip)); 286 | //ESP_LOGI(TAG, "Subnet mask: %s", ip4addr_ntoa(&ip_info.netmask)); 287 | //ESP_LOGI(TAG, "Gateway : %s", ip4addr_ntoa(&ip_info.gw)); 288 | ESP_LOGI(TAG, "IP Address : " IPSTR, IP2STR(&ip_info.ip)); 289 | ESP_LOGI(TAG, "Subnet Mask: " IPSTR, IP2STR(&ip_info.netmask)); 290 | ESP_LOGI(TAG, "Gateway : " IPSTR, IP2STR(&ip_info.gw)); 291 | 292 | /* Start MQTT Server using tcp transport */ 293 | //ESP_LOGI(TAG, "MQTT broker started on %s using Mongoose v%s", ip4addr_ntoa(&ip_info.ip), MG_VERSION); 294 | ESP_LOGI(TAG, "MQTT broker started on " IPSTR " using Mongoose v%s", IP2STR(&ip_info.ip), MG_VERSION); 295 | xTaskCreate(mqtt_server, "BROKER", 1024*4, NULL, 2, NULL); 296 | vTaskDelay(10); // You need to wait until the task launch is complete. 297 | 298 | #if CONFIG_SUBSCRIBE 299 | /* Start Subscriber */ 300 | char cparam1[64]; 301 | //sprintf(cparam1, "mqtt://%s:1883", ip4addr_ntoa(&ip_info.ip)); 302 | sprintf(cparam1, "mqtt://" IPSTR ":1883", IP2STR(&ip_info.ip)); 303 | xTaskCreate(mqtt_subscriber, "SUBSCRIBE", 1024*4, (void *)cparam1, 2, NULL); 304 | vTaskDelay(10); // You need to wait until the task launch is complete. 305 | #endif 306 | 307 | #if CONFIG_PUBLISH 308 | /* Start Publisher */ 309 | char cparam2[64]; 310 | //sprintf(cparam2, "mqtt://%s:1883", ip4addr_ntoa(&ip_info.ip)); 311 | sprintf(cparam2, "mqtt://" IPSTR ":1883", IP2STR(&ip_info.ip)); 312 | xTaskCreate(mqtt_publisher, "PUBLISH", 1024*4, (void *)cparam2, 2, NULL); 313 | vTaskDelay(10); // You need to wait until the task launch is complete. 314 | #endif 315 | } 316 | -------------------------------------------------------------------------------- /main/mqtt_publisher.c: -------------------------------------------------------------------------------- 1 | /* MQTT Broker Publisher 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "freertos/FreeRTOS.h" 14 | #include "freertos/task.h" 15 | #include "freertos/event_groups.h" 16 | #include "esp_system.h" 17 | #include "esp_log.h" 18 | 19 | #include "mongoose.h" 20 | 21 | #if CONFIG_PUBLISH 22 | 23 | #if 0 24 | static const char *sub_topic = "#"; 25 | #endif 26 | static const char *pub_topic = "esp32"; 27 | static const char *will_topic = "WILL"; 28 | 29 | static EventGroupHandle_t s_wifi_event_group; 30 | /* The event group allows multiple bits for each event, but we only care about one event 31 | * - are we connected to the MQTT? */ 32 | static int MQTT_CONNECTED_BIT = BIT0; 33 | 34 | static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { 35 | if (ev == MG_EV_ERROR) { 36 | // On error, log error message 37 | ESP_LOGE(pcTaskGetName(NULL), "MG_EV_ERROR %p %s", c->fd, (char *) ev_data); 38 | xEventGroupClearBits(s_wifi_event_group, MQTT_CONNECTED_BIT); 39 | } else if (ev == MG_EV_CONNECT) { 40 | ESP_LOGI(pcTaskGetName(NULL), "MG_EV_CONNECT"); 41 | // If target URL is SSL/TLS, command client connection to use TLS 42 | if (mg_url_is_ssl((char *)fn_data)) { 43 | struct mg_tls_opts opts = {.ca = "ca.pem"}; 44 | mg_tls_init(c, &opts); 45 | } 46 | } else if (ev == MG_EV_MQTT_OPEN) { 47 | ESP_LOGI(pcTaskGetName(NULL), "MG_EV_OPEN"); 48 | // MQTT connect is successful 49 | ESP_LOGI(pcTaskGetName(NULL), "CONNECTED to %s", (char *)fn_data); 50 | xEventGroupSetBits(s_wifi_event_group, MQTT_CONNECTED_BIT); 51 | 52 | #if 0 53 | struct mg_str topic = mg_str(sub_topic); 54 | struct mg_str data = mg_str("hello"); 55 | mg_mqtt_sub(c, &topic); 56 | LOG(LL_INFO, ("SUBSCRIBED to %.*s", (int) topic.len, topic.ptr)); 57 | #endif 58 | 59 | #if 0 60 | struct mg_str topic = mg_str("esp32"), data = mg_str("hello"); 61 | mg_mqtt_pub(c, &topic, &data, 1, false); 62 | LOG(LL_INFO, ("PUBSLISHED %.*s -> %.*s", (int) data.len, data.ptr, 63 | (int) topic.len, topic.ptr)); 64 | #endif 65 | 66 | } else if (ev == MG_EV_MQTT_MSG) { 67 | // When we get echo response, print it 68 | struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data; 69 | ESP_LOGI(pcTaskGetName(NULL), "RECEIVED %.*s <- %.*s", (int) mm->data.len, mm->data.ptr, 70 | (int) mm->topic.len, mm->topic.ptr); 71 | } 72 | 73 | #if 0 74 | if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE || ev == MG_EV_MQTT_MSG) { 75 | *(bool *) fn_data = true; // Signal that we're done 76 | } 77 | #endif 78 | } 79 | 80 | 81 | 82 | void mqtt_publisher(void *pvParameters) 83 | { 84 | char *task_parameter = (char *)pvParameters; 85 | ESP_LOGD(pcTaskGetName(NULL), "Start task_parameter=%s", task_parameter); 86 | char url[64]; 87 | strcpy(url, task_parameter); 88 | ESP_LOGI(pcTaskGetName(NULL), "started on %s", url); 89 | 90 | /* Starting Publisher */ 91 | struct mg_mgr mgr; 92 | struct mg_mqtt_opts opts; // MQTT connection options 93 | //bool done = false; // Event handler flips it to true when done 94 | mg_mgr_init(&mgr); // Initialise event manager 95 | memset(&opts, 0, sizeof(opts)); // Set MQTT options 96 | //opts.client_id = mg_str("PUB"); // Set Client ID 97 | opts.client_id = mg_str(pcTaskGetName(NULL)); // Set Client ID 98 | //opts.qos = 1; // Set QoS to 1 99 | //for Ver7.6 100 | opts.will_qos = 1; // Set QoS to 1 101 | opts.will_topic = mg_str(will_topic); // Set last will topic 102 | opts.will_message = mg_str("goodbye"); // And last will message 103 | 104 | #if CONFIG_BROKER_AUTHENTICATION 105 | opts.user = mg_str(CONFIG_AUTHENTICATION_USERNAME); 106 | opts.pass = mg_str(CONFIG_AUTHENTICATION_PASSWORD); 107 | #endif 108 | 109 | // Connect address is x.x.x.x:1883 110 | // 0.0.0.0:1883 not work 111 | ESP_LOGD(pcTaskGetName(NULL), "url=[%s]", url); 112 | //static const char *url = "mqtt://broker.hivemq.com:1883"; 113 | //mg_mqtt_connect(&mgr, url, &opts, fn, &done); // Create client connection 114 | //mg_mqtt_connect(&mgr, url, &opts, fn, &done); // Create client connection 115 | //mg_mqtt_connect(&mgr, url, &opts, fn, &url); // Create client connection 116 | struct mg_connection *mgc; 117 | mgc = mg_mqtt_connect(&mgr, url, &opts, fn, &url); // Create client connection 118 | 119 | /* Processing events */ 120 | s_wifi_event_group = xEventGroupCreate(); 121 | int32_t counter = 0; 122 | struct mg_str topic = mg_str(pub_topic); 123 | 124 | while (1) { 125 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, 126 | MQTT_CONNECTED_BIT, 127 | pdFALSE, 128 | pdTRUE, 129 | 0); 130 | ESP_LOGD(pcTaskGetName(NULL), "bits=0x%"PRIx32, bits); 131 | if ((bits & MQTT_CONNECTED_BIT) != 0) { 132 | counter++; 133 | if (counter > 100) { 134 | counter=0; 135 | char payload[64]; 136 | sprintf(payload, "TickCount=%"PRIu32, xTaskGetTickCount()); 137 | struct mg_str data = mg_str(payload); 138 | //mg_mqtt_pub(mgc, &topic, &data); 139 | //mg_mqtt_pub(mgc, &topic, &data, 1, false); 140 | //for Ver7.6 141 | mg_mqtt_pub(mgc, topic, data, 1, false); 142 | ESP_LOGI(pcTaskGetName(NULL), "PUBSLISHED %.*s -> %.*s", (int) data.len, data.ptr, 143 | (int) topic.len, topic.ptr); 144 | } 145 | } 146 | mg_mgr_poll(&mgr, 0); 147 | vTaskDelay(1); 148 | } 149 | 150 | // Never reach here 151 | ESP_LOGI(pcTaskGetName(NULL), "finish"); 152 | mg_mgr_free(&mgr); // Finished, cleanup 153 | } 154 | #endif 155 | -------------------------------------------------------------------------------- /main/mqtt_server.c: -------------------------------------------------------------------------------- 1 | /* 2 | MQTT Broker using mongoose 3 | 4 | This code is in the Public Domain (or CC0 licensed, at your option.) 5 | 6 | Unless required by applicable law or agreed to in writing, this 7 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 8 | CONDITIONS OF ANY KIND, either express or implied. 9 | */ 10 | 11 | #include 12 | #include "freertos/FreeRTOS.h" 13 | #include "freertos/task.h" 14 | #include "esp_system.h" 15 | #include "esp_event.h" 16 | #include "esp_log.h" 17 | 18 | #include "mongoose.h" 19 | #include "mqtt_server.h" 20 | 21 | static const char *s_listen_on = "mqtt://0.0.0.0:1883"; 22 | 23 | // A list of client, held in memory 24 | struct client *s_clients = NULL; 25 | 26 | // A list of subscription, held in memory 27 | struct sub *s_subs = NULL; 28 | 29 | // A list of will topic & message, held in memory 30 | struct will *s_wills = NULL; 31 | 32 | // Since version 7.8, mg_mqtt_next_sub() and mg_mqtt_next_unsub() are no longer supported. 33 | static size_t mg_mqtt_next_topic(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, size_t pos) { 34 | unsigned char *buf = (unsigned char *) msg->dgram.ptr + pos; 35 | size_t new_pos; 36 | if (pos >= msg->dgram.len) return 0; 37 | 38 | topic->len = (size_t) (((unsigned) buf[0]) << 8 | buf[1]); 39 | topic->ptr = (char *) buf + 2; 40 | new_pos = pos + 2 + topic->len + (qos == NULL ? 0 : 1); 41 | if ((size_t) new_pos > msg->dgram.len) return 0; 42 | if (qos != NULL) *qos = buf[2 + topic->len]; 43 | return new_pos; 44 | } 45 | 46 | size_t mg_mqtt_next_sub(struct mg_mqtt_message *msg, struct mg_str *topic, uint8_t *qos, size_t pos) { 47 | uint8_t tmp; 48 | return mg_mqtt_next_topic(msg, topic, qos == NULL ? &tmp : qos, pos); 49 | } 50 | 51 | size_t mg_mqtt_next_unsub(struct mg_mqtt_message *msg, struct mg_str *topic, size_t pos) { 52 | return mg_mqtt_next_topic(msg, topic, NULL, pos); 53 | } 54 | 55 | // Wildcard(#/+) support version 56 | int _mg_strcmp(const struct mg_str str1, const struct mg_str str2) { 57 | size_t i1 = 0; 58 | size_t i2 = 0; 59 | while (i1 < str1.len && i2 < str2.len) { 60 | int c1 = str1.ptr[i1]; 61 | int c2 = str2.ptr[i2]; 62 | //printf("c1=%c c2=%c\n",c1, c2); 63 | 64 | // str2=[/hoge/#] 65 | if (c2 == '#') return 0; 66 | 67 | // str2=[/hoge/+/123] 68 | // Search next slash 69 | if (c2 == '+') { 70 | // str1=[/hoge//123] 71 | // str2=[/hoge/+/123] 72 | if (c1 == '/') { 73 | i2++; 74 | // str1=[/hoge/123/123] 75 | // str2=[/hoge/+/123] 76 | } else { 77 | for (i1=i1;i1+1 c2) return 1; 88 | i1++; 89 | i2++; 90 | } 91 | } 92 | if (i1 < str1.len) return 1; 93 | if (i2 < str2.len) return -1; 94 | return 0; 95 | } 96 | 97 | void _mg_mqtt_dump(char * tag, struct mg_mqtt_message *msg) { 98 | unsigned char *buf = (unsigned char *) msg->dgram.ptr; 99 | ESP_LOGI(pcTaskGetName(NULL),"%s=%x %x", tag, buf[0], buf[1]); 100 | int length = buf[1] + 2; 101 | ESP_LOG_BUFFER_HEXDUMP(tag, buf, length, ESP_LOG_INFO); 102 | } 103 | 104 | #define WILL_FLAG 0x04 105 | #define WILL_QOS 0x18 106 | #define WILL_RETAIN 0x20 107 | #define PASSWORD_FLAG 0x40 108 | #define USERNAME_FLAG 0x80 109 | 110 | int _mg_mqtt_parse_header(struct mg_mqtt_message *msg, struct mg_str *client, 111 | struct mg_str *topic, struct mg_str *payload, 112 | struct mg_str *username, struct mg_str *password, uint8_t *qos, uint8_t *retain) { 113 | client->len = 0; 114 | topic->len = 0; 115 | payload->len = 0; 116 | username->len = 0; 117 | password->len = 0; 118 | unsigned char *buf = (unsigned char *) msg->dgram.ptr; 119 | int Protocol_Name_length = buf[2] << 8 | buf[3]; 120 | int Connect_Flags_position = Protocol_Name_length + 5; 121 | uint8_t Connect_Flags = buf[Connect_Flags_position]; 122 | ESP_LOGD("_mg_mqtt_parse_header", "Connect_Flags=0x%02x", Connect_Flags); 123 | //uint8_t Will_Flag = (Connect_Flags & WILL_FLAG) >> 2; 124 | int will = (Connect_Flags & WILL_FLAG) >> 2; 125 | *qos = (Connect_Flags & WILL_QOS) >> 3; 126 | *retain = (Connect_Flags & WILL_RETAIN) >> 5; 127 | int pass = (Connect_Flags & PASSWORD_FLAG) >> 6; 128 | int user = (Connect_Flags & USERNAME_FLAG) >> 7; 129 | ESP_LOGD("_mg_mqtt_parse_header", "will=%d *qos=%x *retain=%x pass=%d user=%d", 130 | will, *qos, *retain, pass, user); 131 | 132 | int Keep_Alive_Id_position = Connect_Flags_position + 1; 133 | uint16_t Keep_Alive = buf[Keep_Alive_Id_position] << 8 | buf[Keep_Alive_Id_position + 1]; 134 | ESP_LOGD("_mg_mqtt_parse_header", "Keep_Alive=0x%02x", Keep_Alive); 135 | 136 | //int Client_Id_position = Connect_Flags_position + 3; 137 | int Client_Id_position = Keep_Alive_Id_position + 2; 138 | //client->len = buf[Connect_Flags_position+3] << 8 | buf[Connect_Flags_position+4]; 139 | //client->ptr = (char *)&buf[Connect_Flags_position+5]; 140 | client->len = buf[Client_Id_position] << 8 | buf[Client_Id_position+1]; 141 | client->ptr = (char *)&buf[Client_Id_position+2]; 142 | ESP_LOGD("_mg_mqtt_parse_header", "client->len=%d client->ptr=[%.*s]", client->len, client->len, client->ptr); 143 | 144 | int next_position = Client_Id_position + 2 + client->len; 145 | ESP_LOGD("_mg_mqtt_parse_header", "next_position=%d", next_position); 146 | 147 | if (will == 1) { 148 | topic->len = buf[next_position] << 8 | buf[next_position+1]; 149 | topic->ptr = (char *)&(buf[next_position]) + 2; 150 | ESP_LOGD("_mg_mqtt_parse_header", "topic->len=%d topic->ptr=[%.*s]", topic->len, topic->len, topic->ptr); 151 | next_position = next_position + 2 + topic->len; 152 | payload->len = buf[next_position] << 8 | buf[next_position+1]; 153 | payload->ptr = (char *)&(buf[next_position]) + 2; 154 | ESP_LOGD("_mg_mqtt_parse_header", "payload->len=%d payload->ptr=[%.*s]", payload->len, payload->len, payload->ptr); 155 | next_position = next_position + 2 + payload->len; 156 | } 157 | 158 | if (user == 1) { 159 | username->len = buf[next_position] << 8 | buf[next_position+1]; 160 | username->ptr = (char *)&(buf[next_position]) + 2; 161 | ESP_LOGD("_mg_mqtt_parse_header", "username->len=%d username->ptr=[%.*s]", username->len, username->len, username->ptr); 162 | next_position = next_position + 2 + username->len; 163 | } 164 | 165 | if (pass == 1) { 166 | password->len = buf[next_position] << 8 | buf[next_position+1]; 167 | password->ptr = (char *)&(buf[next_position]) + 2; 168 | ESP_LOGD("_mg_mqtt_parse_header", "password->len=%d password->ptr=[%.*s]", password->len, password->len, password->ptr); 169 | next_position = next_position + 2 + password->len; 170 | } 171 | 172 | return will; 173 | } 174 | 175 | int _mg_mqtt_status() { 176 | for (struct client *client = s_clients; client != NULL; client = client->next) { 177 | ESP_LOGI(pcTaskGetName(NULL), "CLIENT(ALL) %p [%.*s]", client->c->fd, (int) client->cid.len, client->cid.ptr); 178 | for (struct will *will = s_wills; will != NULL; will = will->next) { 179 | if (client->c != will->c) continue; 180 | ESP_LOGI(pcTaskGetName(NULL), "WILL(ALL) %p [%.*s] [%.*s] %d %d", 181 | will->c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 182 | } 183 | for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) { 184 | if (client->c != sub->c) continue; 185 | ESP_LOGI(pcTaskGetName(NULL), "SUB(ALL) %p [%.*s]", sub->c->fd, (int) sub->topic.len, sub->topic.ptr); 186 | } 187 | } 188 | 189 | #if 0 190 | for (struct will *will = s_wills; will != NULL; will = will->next) { 191 | ESP_LOGI(pcTaskGetName(NULL), "WILL(ALL) %p [%.*s] [%.*s] %d %d", 192 | will->c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 193 | } 194 | #endif 195 | 196 | #if 0 197 | for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) { 198 | ESP_LOGI(pcTaskGetName(NULL), "SUB(ALL) %p [%.*s]", sub->c->fd, (int) sub->topic.len, sub->topic.ptr); 199 | } 200 | #endif 201 | 202 | return 0; 203 | } 204 | 205 | int isasciis(char * buffer, int length) { 206 | for (int i=0;icmd, mm->qos); 218 | switch (mm->cmd) { 219 | case MQTT_CMD_CONNECT: { 220 | ESP_LOGI(pcTaskGetName(NULL), "CONNECT"); 221 | ESP_LOGD(pcTaskGetName(NULL),"total_size(MALLOC_CAP_8BIT):%d", heap_caps_get_total_size(MALLOC_CAP_8BIT)); 222 | ESP_LOGD(pcTaskGetName(NULL),"total_size(MALLOC_CAP_32BIT):%d", heap_caps_get_total_size(MALLOC_CAP_32BIT)); 223 | ESP_LOGD(pcTaskGetName(NULL),"free_size(MALLOC_CAP_8BIT):%d", heap_caps_get_free_size(MALLOC_CAP_8BIT)); 224 | ESP_LOGD(pcTaskGetName(NULL),"free_size(MALLOC_CAP_32BIT):%d", heap_caps_get_free_size(MALLOC_CAP_32BIT)); 225 | 226 | // Parse the header to retrieve will information. 227 | //_mg_mqtt_dump("CONNECT", mm); 228 | struct mg_str cid; 229 | struct mg_str topic; 230 | struct mg_str payload; 231 | struct mg_str username; 232 | struct mg_str password; 233 | int willFlag; 234 | uint8_t qos; 235 | uint8_t retain; 236 | willFlag = _mg_mqtt_parse_header(mm, &cid, &topic, &payload, &username, &password, &qos, &retain); 237 | ESP_LOGI(pcTaskGetName(NULL), "willFlag=%d cid.len=%d username.len=%d password.len=%d", willFlag, cid.len, username.len, password.len); 238 | if (cid.len) 239 | ESP_LOGI(pcTaskGetName(NULL), "cid.len=%d cid.ptr=[%.*s]", cid.len, cid.len, cid.ptr); 240 | if (username.len) 241 | ESP_LOGI(pcTaskGetName(NULL), "username.len=%d username.ptr=[%.*s]", username.len, username.len, username.ptr); 242 | if (password.len) 243 | ESP_LOGI(pcTaskGetName(NULL), "password.len=%d password.ptr=[%.*s]", password.len, password.len, password.ptr); 244 | 245 | #if CONFIG_BROKER_AUTHENTICATION 246 | if (username.len != strlen(CONFIG_AUTHENTICATION_USERNAME) || 247 | (strncmp(username.ptr, CONFIG_AUTHENTICATION_USERNAME, username.len) != 0) ) { 248 | // Connection Refused, bad user name or password 249 | uint8_t response[] = {0, 4}; 250 | mg_mqtt_send_header(c, MQTT_CMD_CONNACK, 0, sizeof(response)); 251 | mg_send(c, response, sizeof(response)); 252 | break; 253 | } 254 | 255 | if (password.len != strlen(CONFIG_AUTHENTICATION_PASSWORD) || 256 | (strncmp(password.ptr, CONFIG_AUTHENTICATION_PASSWORD, password.len) != 0) ) { 257 | // Connection Refused, bad user name or password 258 | uint8_t response[] = {0, 4}; 259 | mg_mqtt_send_header(c, MQTT_CMD_CONNACK, 0, sizeof(response)); 260 | mg_send(c, response, sizeof(response)); 261 | break; 262 | } 263 | #endif 264 | 265 | // Set tcp socket keepalive options 266 | // timeout = keepidle+(keepcnt*keepintvl) 267 | // timeout = 60+(1*10)=70 268 | int keepAlive = 1; 269 | setsockopt( (int) c->fd, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int)); 270 | int keepIdle = 60; // default is 7200 Sec 271 | setsockopt( (int) c->fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int)); 272 | int keepInterval = 10; // default is 75 Sec 273 | setsockopt( (int) c->fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int)); 274 | int keepCount = 1; // default is 9 count 275 | setsockopt( (int) c->fd, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int)); 276 | 277 | #if 0 278 | // Client connects. Add to the client-id list 279 | struct client *client = calloc(1, sizeof(*client)); 280 | client->c = c; 281 | client->cid = mg_strdup(cid); 282 | LIST_ADD_HEAD(struct client, &s_clients, client); 283 | ESP_LOGD(pcTaskGetName(NULL), "CLIENT ADD %p [%.*s]", c->fd, (int) client->cid.len, client->cid.ptr); 284 | ESP_LOGI(pcTaskGetName(NULL), "CLIENT ADD %p", client); 285 | #endif 286 | 287 | // Client connects. Add to the will list 288 | if (willFlag == 1) { 289 | struct will *will = calloc(1, sizeof(*will)); 290 | will->c = c; 291 | will->topic = mg_strdup(topic); 292 | will->payload = mg_strdup(payload); 293 | will->qos = qos; 294 | will->retain = retain; 295 | LIST_ADD_HEAD(struct will, &s_wills, will); 296 | ESP_LOGD(pcTaskGetName(NULL), "WILL ADD %p [%.*s] [%.*s] %d %d", 297 | c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 298 | } 299 | _mg_mqtt_status(); 300 | 301 | // Client connects. Return success, do not check user/password 302 | uint8_t response[] = {0, 0}; 303 | mg_mqtt_send_header(c, MQTT_CMD_CONNACK, 0, sizeof(response)); 304 | mg_send(c, response, sizeof(response)); 305 | break; 306 | } 307 | case MQTT_CMD_SUBSCRIBE: { 308 | // Client subscribe 309 | ESP_LOGI(pcTaskGetName(NULL), "MQTT_CMD_SUBSCRIBE"); 310 | int pos = 4; // Initial topic offset, where ID ends 311 | uint8_t qos, resp[256]; 312 | struct mg_str topic; 313 | int num_topics = 0; 314 | while ((pos = mg_mqtt_next_sub(mm, &topic, &qos, pos)) > 0) { 315 | struct sub *sub = calloc(1, sizeof(*sub)); 316 | sub->c = c; 317 | sub->topic = mg_strdup(topic); 318 | sub->qos = qos; 319 | LIST_ADD_HEAD(struct sub, &s_subs, sub); 320 | ESP_LOGI(pcTaskGetName(NULL), "SUB ADD %p [%.*s]", c->fd, (int) sub->topic.len, sub->topic.ptr); 321 | resp[num_topics++] = qos; 322 | } 323 | mg_mqtt_send_header(c, MQTT_CMD_SUBACK, 0, num_topics + 2); 324 | uint16_t id = mg_htons(mm->id); 325 | mg_send(c, &id, 2); 326 | mg_send(c, resp, num_topics); 327 | _mg_mqtt_status(); 328 | break; 329 | } 330 | case MQTT_CMD_UNSUBSCRIBE: { 331 | // Client unsubscribes. Remove from the subscription list 332 | ESP_LOGI(pcTaskGetName(NULL), "MQTT_CMD_UNSUBSCRIBE"); 333 | //_mg_mqtt_dump("UNSUBSCRIBE", mm); 334 | int pos = 4; // Initial topic offset, where ID ends 335 | struct mg_str topic; 336 | while ((pos = mg_mqtt_next_unsub(mm, &topic, pos)) > 0) { 337 | ESP_LOGI(pcTaskGetName(NULL), "UNSUB %p [%.*s]", c->fd, (int) topic.len, topic.ptr); 338 | // Remove from the subscription list 339 | for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) { 340 | ESP_LOGI(pcTaskGetName(NULL), "SUB[b] %p [%.*s]", sub->c->fd, (int) sub->topic.len, sub->topic.ptr); 341 | } 342 | for (struct sub *next, *sub = s_subs; sub != NULL; sub = next) { 343 | next = sub->next; 344 | ESP_LOGD(pcTaskGetName(NULL), "c->fd=%p sub->c->fd=%p", c->fd, sub->c->fd); 345 | if (c != sub->c) continue; 346 | if (strncmp(topic.ptr, sub->topic.ptr, topic.len) != 0) continue; 347 | ESP_LOGI(pcTaskGetName(NULL), "DELETE SUB %p [%.*s]", c->fd, (int) sub->topic.len, sub->topic.ptr); 348 | free((void *)sub->topic.ptr); 349 | LIST_DELETE(struct sub, &s_subs, sub); 350 | free(sub); 351 | } 352 | for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) { 353 | ESP_LOGI(pcTaskGetName(NULL), "SUB[a] %p [%.*s]", sub->c->fd, (int) sub->topic.len, sub->topic.ptr); 354 | } 355 | } 356 | _mg_mqtt_status(); 357 | break; 358 | } 359 | case MQTT_CMD_PUBLISH: { 360 | // Client published message. Push to all subscribed channels 361 | //ESP_LOGI(pcTaskGetName(NULL), "mm->data.ptr[0]=0x%x", mm->data.ptr[0]); 362 | //if (isascii(mm->data.ptr[0])) { 363 | // Make sure all characters are ASCII codes 364 | if (isasciis((char *)mm->data.ptr, mm->topic.len)) { 365 | ESP_LOGI(pcTaskGetName(NULL), "PUB %p [%.*s] -> [%.*s]", c->fd, (int) mm->data.len, 366 | mm->data.ptr, (int) mm->topic.len, mm->topic.ptr); 367 | } else { 368 | ESP_LOGI(pcTaskGetName(NULL), "PUB %p [BINARY] -> [%.*s]", c->fd, 369 | (int) mm->topic.len, mm->topic.ptr); 370 | } 371 | for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) { 372 | if (_mg_strcmp(mm->topic, sub->topic) != 0) continue; 373 | //mg_mqtt_pub(sub->c, &mm->topic, &mm->data); 374 | //mg_mqtt_pub(sub->c, &mm->topic, &mm->data, 1, false); 375 | //for Ver7.6 376 | mg_mqtt_pub(sub->c, mm->topic, mm->data, 1, false); 377 | } 378 | break; 379 | } 380 | case MQTT_CMD_PINGREQ: { 381 | ESP_LOGI(pcTaskGetName(NULL), "PINGREQ %p", c->fd); 382 | mg_mqtt_pong(c); // Send PINGRESP 383 | break; 384 | } 385 | } 386 | } else if (ev == MG_EV_CLOSE) { 387 | ESP_LOGI(pcTaskGetName(NULL), "MG_EV_CLOSE %p", c->fd); 388 | 389 | ESP_LOGD(pcTaskGetName(NULL),"total_size(MALLOC_CAP_8BIT):%d", heap_caps_get_total_size(MALLOC_CAP_8BIT)); 390 | ESP_LOGD(pcTaskGetName(NULL),"total_size(MALLOC_CAP_32BIT):%d", heap_caps_get_total_size(MALLOC_CAP_32BIT)); 391 | ESP_LOGI(pcTaskGetName(NULL),"free_size(MALLOC_CAP_8BIT):%d", heap_caps_get_free_size(MALLOC_CAP_8BIT)); 392 | ESP_LOGI(pcTaskGetName(NULL),"free_size(MALLOC_CAP_32BIT):%d", heap_caps_get_free_size(MALLOC_CAP_32BIT)); 393 | 394 | // Client disconnects. Remove from the client-id list 395 | for (struct client *client = s_clients; client != NULL; client = client->next) { 396 | ESP_LOGD(pcTaskGetName(NULL), "CLIENT(b) %p [%.*s]", client->c->fd, (int) client->cid.len, client->cid.ptr); 397 | } 398 | for (struct client *next, *client = s_clients; client != NULL; client = next) { 399 | next = client->next; 400 | ESP_LOGD(pcTaskGetName(NULL), "c->fd=%p client->c->fd=%p", c->fd, client->c->fd); 401 | if (c != client->c) continue; 402 | ESP_LOGD(pcTaskGetName(NULL), "CLIENT DEL %p [%.*s]", c->fd, (int) client->cid.len, client->cid.ptr); 403 | ESP_LOGI(pcTaskGetName(NULL), "CLIENT DEL %p", client); 404 | free((void *)client->cid.ptr); 405 | LIST_DELETE(struct client, &s_clients, client); 406 | free(client); 407 | } 408 | for (struct client *client = s_clients; client != NULL; client = client->next) { 409 | ESP_LOGD(pcTaskGetName(NULL), "CLIENT(a) %p [%.*s]", client->c->fd, (int) client->cid.len, client->cid.ptr); 410 | } 411 | 412 | // Client disconnects. Remove from the subscription list 413 | for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) { 414 | ESP_LOGD(pcTaskGetName(NULL), "SUB[b] %p [%.*s]", sub->c->fd, (int) sub->topic.len, sub->topic.ptr); 415 | } 416 | for (struct sub *next, *sub = s_subs; sub != NULL; sub = next) { 417 | next = sub->next; 418 | ESP_LOGD(pcTaskGetName(NULL), "c->fd=%p sub->c->fd=%p", c->fd, sub->c->fd); 419 | if (c != sub->c) continue; 420 | ESP_LOGD(pcTaskGetName(NULL), "SUB DEL %p [%.*s]", c->fd, (int) sub->topic.len, sub->topic.ptr); 421 | free((void *)sub->topic.ptr); 422 | LIST_DELETE(struct sub, &s_subs, sub); 423 | free(sub); 424 | } 425 | 426 | // Judgment to send will 427 | for (struct sub *sub = s_subs; sub != NULL; sub = sub->next) { 428 | ESP_LOGD(pcTaskGetName(NULL), "SUB[a] %p [%.*s]", sub->c->fd, (int) sub->topic.len, sub->topic.ptr); 429 | for (struct will *will = s_wills; will != NULL; will = will->next) { 430 | ESP_LOGD(pcTaskGetName(NULL), "WILL(ALL) %p [%.*s] [%.*s] %d %d", 431 | will->c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 432 | //if (c == will->c) continue; 433 | if (sub->c == will->c) continue; 434 | ESP_LOGD(pcTaskGetName(NULL), "WILL(CMP) %p [%.*s] [%.*s] %d %d", 435 | will->c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 436 | if (_mg_strcmp(will->topic, sub->topic) != 0) continue; 437 | //mg_mqtt_pub(sub->c, &will->topic, &will->payload); 438 | //mg_mqtt_pub(sub->c, &will->topic, &will->payload, 1, false); 439 | //for Ver7.6 440 | mg_mqtt_pub(sub->c, will->topic, will->payload, 1, false); 441 | } 442 | } 443 | 444 | // Client disconnects. Remove from the will list 445 | for (struct will *will = s_wills; will != NULL; will = will->next) { 446 | ESP_LOGD(pcTaskGetName(NULL), "WILL[b] %p [%.*s] [%.*s] %d %d", 447 | will->c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 448 | } 449 | for (struct will *next, *will = s_wills; will != NULL; will = next) { 450 | next = will->next; 451 | ESP_LOGD(pcTaskGetName(NULL), "WILL %p [%.*s] [%.*s] %d %d", 452 | c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 453 | if (c != will->c) continue; 454 | ESP_LOGD(pcTaskGetName(NULL), "WILL DEL %p [%.*s] [%.*s] %d %d", 455 | c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 456 | free((void *)will->topic.ptr); 457 | free((void *)will->payload.ptr); 458 | LIST_DELETE(struct will, &s_wills, will); 459 | free(will); 460 | } 461 | for (struct will *will = s_wills; will != NULL; will = will->next) { 462 | ESP_LOGD(pcTaskGetName(NULL), "WILL[a] %p [%.*s] [%.*s] %d %d", 463 | will->c->fd, (int) will->topic.len, will->topic.ptr, (int) will->payload.len, will->payload.ptr, will->qos, will->retain); 464 | } 465 | _mg_mqtt_status(); 466 | } // MG_EV_CLOSE 467 | (void) fn_data; 468 | } 469 | 470 | void mqtt_server(void *pvParameters) 471 | { 472 | /* Starting Broker */ 473 | ESP_LOGI(pcTaskGetName(NULL), "Start"); 474 | struct mg_mgr mgr; 475 | mg_log_set(1); // Set to log level to LL_ERROR 476 | //mg_log_set(3); // Set to log level to LL_DEBUG 477 | mg_mgr_init(&mgr); 478 | mg_mqtt_listen(&mgr, s_listen_on, fn, NULL); // Create MQTT listener 479 | //ESP_LOGI(pcTaskGetName(NULL), "Starting Mongoose v%s MQTT Server", MG_VERSION); 480 | 481 | /* Processing events */ 482 | while (1) { 483 | mg_mgr_poll(&mgr, 0); 484 | vTaskDelay(1); 485 | } 486 | 487 | // Never reach here 488 | ESP_LOGI(pcTaskGetName(NULL), "finish"); 489 | mg_mgr_free(&mgr); 490 | } 491 | 492 | -------------------------------------------------------------------------------- /main/mqtt_server.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_MQTT_SERVER_H_ 2 | #define MAIN_MQTT_SERVER_H_ 3 | 4 | // A list of client, held in memory 5 | struct client { 6 | struct client *next; 7 | struct mg_connection *c; 8 | struct mg_str cid; 9 | }; 10 | 11 | // A list of subscription, held in memory 12 | struct sub { 13 | struct sub *next; 14 | struct mg_connection *c; 15 | struct mg_str topic; 16 | uint8_t qos; 17 | }; 18 | 19 | // A list of will topic & message, held in memory 20 | struct will { 21 | struct will *next; 22 | struct mg_connection *c; 23 | struct mg_str topic; 24 | struct mg_str payload; 25 | uint8_t qos; 26 | uint8_t retain; 27 | }; 28 | 29 | #endif /* MAIN_MQTT_SERVER_H_ */ 30 | -------------------------------------------------------------------------------- /main/mqtt_subscriber.c: -------------------------------------------------------------------------------- 1 | /* MQTT Broker Subscriber 2 | 3 | This example code is in the Public Domain (or CC0 licensed, at your option.) 4 | 5 | Unless required by applicable law or agreed to in writing, this 6 | software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 7 | CONDITIONS OF ANY KIND, either express or implied. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "freertos/FreeRTOS.h" 14 | #include "freertos/task.h" 15 | #include "freertos/event_groups.h" 16 | #include "esp_system.h" 17 | #include "esp_log.h" 18 | 19 | #include "mongoose.h" 20 | 21 | #if CONFIG_SUBSCRIBE 22 | 23 | static const char *sub_topic = "#"; 24 | static const char *will_topic = "WILL"; 25 | 26 | static EventGroupHandle_t s_wifi_event_group; 27 | /* The event group allows multiple bits for each event, but we only care about one event 28 | * - are we connected to the MQTT? */ 29 | static int MQTT_CONNECTED_BIT = BIT0; 30 | 31 | static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { 32 | if (ev == MG_EV_ERROR) { 33 | // On error, log error message 34 | ESP_LOGE(pcTaskGetName(NULL), "MG_EV_ERROR %p %s", c->fd, (char *) ev_data); 35 | xEventGroupClearBits(s_wifi_event_group, MQTT_CONNECTED_BIT); 36 | } else if (ev == MG_EV_CONNECT) { 37 | ESP_LOGI(pcTaskGetName(NULL), "MG_EV_CONNECT"); 38 | // If target URL is SSL/TLS, command client connection to use TLS 39 | if (mg_url_is_ssl((char *)fn_data)) { 40 | struct mg_tls_opts opts = {.ca = "ca.pem"}; 41 | mg_tls_init(c, &opts); 42 | } 43 | } else if (ev == MG_EV_MQTT_OPEN) { 44 | ESP_LOGI(pcTaskGetName(NULL), "MG_EV_OPEN"); 45 | // MQTT connect is successful 46 | ESP_LOGI(pcTaskGetName(NULL), "CONNECTED to %s", (char *)fn_data); 47 | xEventGroupSetBits(s_wifi_event_group, MQTT_CONNECTED_BIT); 48 | 49 | #if 0 50 | struct mg_str topic = mg_str(sub_topic); 51 | struct mg_str data = mg_str("hello"); 52 | mg_mqtt_sub(c, &topic, 1); 53 | ESP_LOGI(pcTaskGetName(NULL), "SUBSCRIBED to %.*s", (int) topic.len, topic.ptr); 54 | #endif 55 | 56 | #if 0 57 | mg_mqtt_pub(c, &topic, &data); 58 | LOG(LL_INFO, ("PUBSLISHED %.*s -> %.*s", (int) data.len, data.ptr, 59 | (int) topic.len, topic.ptr)); 60 | #endif 61 | 62 | } else if (ev == MG_EV_MQTT_MSG) { 63 | // When we get echo response, print it 64 | struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data; 65 | ESP_LOGI(pcTaskGetName(NULL), "RECEIVED %.*s <- %.*s", (int) mm->data.len, mm->data.ptr, 66 | (int) mm->topic.len, mm->topic.ptr); 67 | } 68 | 69 | #if 0 70 | if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE || ev == MG_EV_MQTT_MSG) { 71 | *(bool *) fn_data = true; // Signal that we're done 72 | } 73 | #endif 74 | } 75 | 76 | 77 | 78 | void mqtt_subscriber(void *pvParameters) 79 | { 80 | char *task_parameter = (char *)pvParameters; 81 | ESP_LOGD(pcTaskGetName(NULL), "Start task_parameter=%s", task_parameter); 82 | char url[64]; 83 | strcpy(url, task_parameter); 84 | ESP_LOGI(pcTaskGetName(NULL), "started on %s", url); 85 | 86 | /* Starting Subscriber */ 87 | struct mg_mgr mgr; 88 | struct mg_mqtt_opts opts; // MQTT connection options 89 | //bool done = false; // Event handler flips it to true when done 90 | mg_mgr_init(&mgr); // Initialise event manager 91 | memset(&opts, 0, sizeof(opts)); // Set MQTT options 92 | //opts.client_id = mg_str("SUB"); // Set Client ID 93 | opts.client_id = mg_str(pcTaskGetName(NULL)); // Set Client ID 94 | //opts.qos = 1; // Set QoS to 1 95 | //for Ver7.6 96 | opts.will_qos = 1; // Set QoS to 1 97 | opts.will_topic = mg_str(will_topic); // Set last will topic 98 | opts.will_message = mg_str("goodbye"); // And last will message 99 | 100 | #if CONFIG_BROKER_AUTHENTICATION 101 | opts.user = mg_str(CONFIG_AUTHENTICATION_USERNAME); 102 | opts.pass = mg_str(CONFIG_AUTHENTICATION_PASSWORD); 103 | #endif 104 | 105 | // Connect address is x.x.x.x:1883 106 | // 0.0.0.0:1883 not work 107 | ESP_LOGD(pcTaskGetName(NULL), "url=[%s]", url); 108 | //static const char *url = "mqtt://broker.hivemq.com:1883"; 109 | //mg_mqtt_connect(&mgr, url, &opts, fn, &done); // Create client connection 110 | //mg_mqtt_connect(&mgr, url, &opts, fn, &done); // Create client connection 111 | struct mg_connection *mgc; 112 | mgc = mg_mqtt_connect(&mgr, url, &opts, fn, &url); // Create client connection 113 | 114 | /* Processing events */ 115 | s_wifi_event_group = xEventGroupCreate(); 116 | 117 | while (1) { 118 | EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, 119 | MQTT_CONNECTED_BIT, 120 | pdTRUE, 121 | pdTRUE, 122 | 0); 123 | ESP_LOGD(pcTaskGetName(NULL), "bits=0x%"PRIx32, bits); 124 | if ((bits & MQTT_CONNECTED_BIT) != 0) { 125 | struct mg_str topic = mg_str(sub_topic); 126 | //mg_mqtt_sub(mgc, &topic); 127 | //mg_mqtt_sub(mgc, &topic, 1); 128 | //for Ver7.6 129 | mg_mqtt_sub(mgc, topic, 1); 130 | ESP_LOGI(pcTaskGetName(NULL), "SUBSCRIBED to %.*s", (int) topic.len, topic.ptr); 131 | } 132 | mg_mgr_poll(&mgr, 0); 133 | vTaskDelay(1); 134 | } 135 | 136 | // Never reach here 137 | ESP_LOGI(pcTaskGetName(NULL), "finish"); 138 | mg_mgr_free(&mgr); // Finished, cleanup 139 | } 140 | #endif 141 | -------------------------------------------------------------------------------- /mqtt_pub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # sudo apt install mosquitto-clients moreutils 4 | # 5 | 6 | #set -x 7 | mdns="esp32-broker.local" 8 | while : 9 | do 10 | payload=`date "+%Y/%m/%d-%H:%M:%S"` 11 | mosquitto_pub -h ${mdns} -p 1883 -t "topic" -m ${payload} 12 | sleep 1 13 | done 14 | -------------------------------------------------------------------------------- /mqtt_sub.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # sudo apt install mosquitto-clients moreutils 4 | # 5 | 6 | #set -x 7 | mdns="esp32-broker.local" 8 | topic="#" 9 | mosquitto_sub -v -h ${mdns} -p 1883 -t ${topic} | ts "%y/%m/%d %H:%M:%S" 10 | -------------------------------------------------------------------------------- /pub_example.py: -------------------------------------------------------------------------------- 1 | #!usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # python3 -m pip install -U paho-mqtt 5 | 6 | import time 7 | import argparse 8 | import paho.mqtt 9 | import paho.mqtt.client as mqtt 10 | 11 | # Handler when connecting to broker 12 | def on_connect(client, userdata, flag, rc): 13 | print("Connected with result code " + str(rc)) 14 | client.subscribe("/system/#") 15 | 16 | # Handler when broker disconnects 17 | def on_disconnect(client, userdata, flag): 18 | print("disconnection.") 19 | 20 | # # Handler when message arrives 21 | def on_message(client, userdata, msg): 22 | # msg.topic contains the topic name and msg.payload contains the received data 23 | print("Received message '" + str(msg.payload) + "' on topic '" + msg.topic + "' with QoS " + str(msg.qos)) 24 | 25 | if __name__=='__main__': 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument('--topic', help='mqtt topic', default="/system/test") 28 | parser.add_argument('--host', help='mqtt host', default="esp32-broker.local") 29 | parser.add_argument('--port', type=int, help='mqtt port', default=1883) 30 | args = parser.parse_args() 31 | print("args.topic={}".format(args.topic)) 32 | print("args.host={}".format(args.host)) 33 | print("args.port={}".format(args.port)) 34 | 35 | client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1) 36 | client.on_connect = on_connect 37 | client.on_disconnect = on_disconnect 38 | client.on_message = on_message 39 | 40 | client.will_set('/system/message', 'Publisher Down') 41 | client.connect(args.host, args.port, 60) 42 | 43 | # keep waiting in an endless loop 44 | #client.loop_forever() 45 | while True: 46 | t = time.time() 47 | local_time = time.localtime(t) 48 | payload = time.asctime(local_time) 49 | print("payload={}".format(payload)) 50 | result = client.publish(args.topic, payload) 51 | print("result={}".format(result)) 52 | time.sleep(1) 53 | -------------------------------------------------------------------------------- /sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | # 2 | # mDNS 3 | # 4 | #CONFIG_MDNS_STRICT_MODE=y 5 | -------------------------------------------------------------------------------- /sub_example.py: -------------------------------------------------------------------------------- 1 | #!usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # python3 -m pip install -U paho-mqtt 5 | 6 | import argparse 7 | import paho.mqtt 8 | import paho.mqtt.client as mqtt 9 | 10 | # Handler when connecting to broker 11 | def on_connect(client, userdata, flag, rc): 12 | print("Connected with result code " + str(rc)) 13 | client.subscribe("/system/#") 14 | 15 | # Handler when broker disconnects 16 | def on_disconnect(client, userdata, flag): 17 | print("disconnection.") 18 | 19 | # # Handler when message arrives 20 | def on_message(client, userdata, msg): 21 | # msg.topic contains the topic name and msg.payload contains the received data 22 | print("Received message '" + str(msg.payload) + "' on topic '" + msg.topic + "' with QoS " + str(msg.qos)) 23 | 24 | if __name__=='__main__': 25 | parser = argparse.ArgumentParser() 26 | parser.add_argument('--host', help='mqtt host', default="esp32-broker.local") 27 | parser.add_argument('--port', type=int, help='mqtt port', default=1883) 28 | args = parser.parse_args() 29 | print("args.host={}".format(args.host)) 30 | print("args.port={}".format(args.port)) 31 | 32 | client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1) 33 | client.on_connect = on_connect 34 | client.on_disconnect = on_disconnect 35 | client.on_message = on_message 36 | 37 | client.will_set('/system/message', 'Subscriber Down') 38 | client.connect(args.host, args.port, 60) 39 | 40 | # keep waiting in an endless loop 41 | client.loop_forever() 42 | -------------------------------------------------------------------------------- /unsub_example.py: -------------------------------------------------------------------------------- 1 | #!usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # python3 -m pip install -U paho-mqtt 5 | 6 | import argparse 7 | import paho.mqtt 8 | import paho.mqtt.client as mqtt 9 | 10 | # Handler when connecting to broker 11 | def on_connect(client, userdata, flag, rc): 12 | print("Connected with result code " + str(rc)) 13 | print("subscribe hoge") 14 | client.subscribe("hoge/#") 15 | 16 | # Handler when broker disconnects 17 | def on_disconnect(client, userdata, flag): 18 | print("disconnection.") 19 | 20 | # Handler when message arrives 21 | def on_message(client, userdata, msg): 22 | # msg.topic contains the topic name and msg.payload contains the received data 23 | print("Received message '" + str(msg.payload) + "' on topic '" + msg.topic + "' with QoS " + str(msg.qos)) 24 | topics = msg.topic 25 | topics = topics.split('/') 26 | #print("topics={}".format(topics)) 27 | if (topics[0] == "hoge"): 28 | print("unsubscribe hoge, subscribe fuga"); 29 | client.unsubscribe("hoge/#") 30 | client.subscribe("fuga/#") 31 | if (topics[0] == "fuga"): 32 | print("unsubscribe fuga, subscribe hoge"); 33 | client.unsubscribe("fuga/#") 34 | client.subscribe("hoge/#") 35 | 36 | if __name__=='__main__': 37 | parser = argparse.ArgumentParser() 38 | parser.add_argument('--host', help='mqtt host', default="esp32-broker.local") 39 | parser.add_argument('--port', type=int, help='mqtt port', default=1883) 40 | args = parser.parse_args() 41 | print("args.host={}".format(args.host)) 42 | print("args.port={}".format(args.port)) 43 | 44 | client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1) 45 | client.on_connect = on_connect 46 | client.on_disconnect = on_disconnect 47 | client.on_message = on_message 48 | 49 | client.connect(args.host, args.port, 60) 50 | 51 | # keep waiting in an endless loop 52 | client.loop_forever() 53 | --------------------------------------------------------------------------------