diff --git a/backend/deploy/mosquitto.conf b/backend/deploy/mosquitto.conf index f871146..e57745d 100644 --- a/backend/deploy/mosquitto.conf +++ b/backend/deploy/mosquitto.conf @@ -1,2 +1,4 @@ +listener 1883 +allow_anonymous true password_file mqtt_users diff --git a/skateboard/main/CMakeLists.txt b/skateboard/main/CMakeLists.txt index 46cb31b..88c9316 100644 --- a/skateboard/main/CMakeLists.txt +++ b/skateboard/main/CMakeLists.txt @@ -1,5 +1,5 @@ idf_component_register( - SRCS skateboard.c app_wifi.c app_mpu.c - PRIV_REQUIRES nvs_flash esp_wifi + SRCS skateboard.c app_wifi.c app_mpu.c app_mqtt.c + PRIV_REQUIRES nvs_flash esp_netif esp_wifi mqtt INCLUDE_DIRS ".") diff --git a/skateboard/main/Kconfig.projbuild b/skateboard/main/Kconfig.projbuild index bb8c6cf..738f53e 100644 --- a/skateboard/main/Kconfig.projbuild +++ b/skateboard/main/Kconfig.projbuild @@ -1,17 +1,31 @@ menu "Skateboard config" - config SKATEBOARD_WIFI_SSID + config WIFI_SSID string "WIFI SSID" default "myssid" - config SKATEBOARD_WIFI_PASSWORD + config WIFI_PASSWORD string "WIFI password" default "mypassword" - config SKATEBOARD_WIFI_MAXIMUM_RETRIES + config WIFI_MAXIMUM_RETRIES int "WIFI maximum connection retries" default 5 + config MQTT_URL + string "MQTT URL" + default "mqtt://mqtt.eclipseprojects.io" + help + URL of the broker to connect to + + config MQTT_USERNAME + string "MQTT Username" + default "test" + + config MQTT_PASSWORD + string "MQTT Password" + default "1234" + choice MPU6050_I2C_ADDRESS prompt "Select I2C address" default MPU6050_I2C_ADDRESS_LOW diff --git a/skateboard/main/app_mqtt.c b/skateboard/main/app_mqtt.c new file mode 100644 index 0000000..f0d0526 --- /dev/null +++ b/skateboard/main/app_mqtt.c @@ -0,0 +1,142 @@ +#include "app_mqtt.h" +#include "esp_event_base.h" +#include "esp_log.h" +#include "freertos/projdefs.h" +#include "mqtt_client.h" +#include "sdkconfig.h" +#include + +extern const char* TAG; + +enum { + Ev_Connected = 1 << 0, + Ev_Failed = 1 << 1, +}; + +static void event_cb(void* arg, esp_event_base_t base, int32_t id, void* data) +{ + AppMqtt* mqtt = arg; + esp_mqtt_event_handle_t event = data; + esp_mqtt_client_handle_t client = event->client; + + (void)client; + + if (id == MQTT_EVENT_CONNECTED) { + xEventGroupSetBits(mqtt->event_group, Ev_Connected); + return; + } + + if (id == MQTT_EVENT_ERROR) { + ESP_LOGE(TAG, "MQTT error occured"); + + if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { + + if (event->error_handle->esp_tls_last_esp_err) { + ESP_LOGE(TAG, + "Error reported in esp-tls: 0x%x", + event->error_handle->esp_tls_last_esp_err); + } else if (event->error_handle->esp_tls_stack_err) { + ESP_LOGE(TAG, + "Error reported in tls stack: 0x%x", + event->error_handle->esp_tls_stack_err); + } else if (event->error_handle->esp_transport_sock_errno) { + ESP_LOGE(TAG, + "Error captured as transport's socket errno: 0x%x", + event->error_handle->esp_transport_sock_errno); + } + + ESP_LOGI(TAG, + "Last errno string (%s)", + strerror(event->error_handle->esp_transport_sock_errno)); + } + + xEventGroupSetBits(mqtt->event_group, Ev_Failed); + return; + } + + if (id == MQTT_EVENT_DATA) { + for (size_t i = 0; i < mqtt->subs_counts; ++i) { + size_t sub_topic_len = strlen(mqtt->subs[i].topic); + + if (sub_topic_len == event->topic_len + && strncmp(mqtt->subs[i].topic, event->topic, event->topic_len) + == 0) { + + mqtt->subs[i].callback(event->topic, + event->topic_len, + event->data, + event->data_len, + mqtt->subs[i].arg); + break; + } + } + return; + } +} + +void app_mqtt_init(AppMqtt* mqtt) +{ + ESP_LOGI(TAG, "Initializing MQTT"); + + *mqtt = (AppMqtt) { + .event_group = xEventGroupCreate(), + .subs_counts = 0, + }; + + esp_mqtt_client_config_t mqtt_config = { + .broker.address.uri = CONFIG_MQTT_URL, + .credentials.username = CONFIG_MQTT_USERNAME, + .credentials.authentication.password = CONFIG_MQTT_PASSWORD, + }; + + mqtt->client = esp_mqtt_client_init(&mqtt_config); + esp_mqtt_client_register_event( + mqtt->client, ESP_EVENT_ANY_ID, event_cb, mqtt); + esp_mqtt_client_start(mqtt->client); + + ESP_LOGI(TAG, "MQTT started"); + + EventBits_t event_bits = xEventGroupWaitBits(mqtt->event_group, + Ev_Connected | Ev_Failed, + pdFALSE, + pdFALSE, + pdMS_TO_TICKS(1000 * 60 * 2)); + + if (event_bits & Ev_Connected) { + ESP_LOGI(TAG, "Connected to MQTT broker at %s", CONFIG_MQTT_URL); + } else { + ESP_LOGE( + TAG, "Could not connect to MQTT broker at %s", CONFIG_MQTT_URL); + } +} + +void app_mqtt_subscribe( + AppMqtt* mqtt, const char* topic, AppMqttSubCb callback, void* arg) +{ + if (mqtt->subs_counts + 1 >= app_mqtt_subs_max_count) { + ESP_LOGE(TAG, + "Max MQTT subscriptions exceeded (%d)", + app_mqtt_subs_max_count); + + return; + } + + int status = esp_mqtt_client_subscribe_single(mqtt->client, topic, 0); + if (status < 0) { + ESP_LOGE(TAG, "Could not subscribe to MQTT topic '%s'", topic); + return; + } + + mqtt->subs[mqtt->subs_counts++] = (AppMqttSub) { topic, callback, arg }; +} + +void app_mqtt_publish( + AppMqtt* mqtt, const char* topic, const void* data, size_t size) +{ + int status + = esp_mqtt_client_publish(mqtt->client, topic, data, (int)size, 1, 0); + if (status < 0) { + ESP_LOGE(TAG, "Could not publish to MQTT topic '%s'", topic); + return; + } +} diff --git a/skateboard/main/app_mqtt.h b/skateboard/main/app_mqtt.h new file mode 100644 index 0000000..7dd974d --- /dev/null +++ b/skateboard/main/app_mqtt.h @@ -0,0 +1,31 @@ +#pragma once + +#include "mqtt_client.h" +#include + +typedef void (*AppMqttSubCb)(const char* topic, + size_t topic_size, + const void* data, + size_t data_size, + void* arg); + +typedef struct { + const char* topic; + AppMqttSubCb callback; + void* arg; +} AppMqttSub; + +#define app_mqtt_subs_max_count 4 + +typedef struct AppMqtt { + EventGroupHandle_t event_group; + esp_mqtt_client_handle_t client; + AppMqttSub subs[app_mqtt_subs_max_count]; + size_t subs_counts; +} AppMqtt; + +void app_mqtt_init(AppMqtt* mqtt); +void app_mqtt_subscribe( + AppMqtt* mqtt, const char* topic, AppMqttSubCb callback, void* arg); +void app_mqtt_publish( + AppMqtt* mqtt, const char* topic, const void* data, size_t size); diff --git a/skateboard/main/app_wifi.c b/skateboard/main/app_wifi.c index dcd3d2a..dd15fed 100644 --- a/skateboard/main/app_wifi.c +++ b/skateboard/main/app_wifi.c @@ -5,17 +5,12 @@ extern const char* TAG; -#define WIFI_SSID CONFIG_SKATEBOARD_WIFI_SSID -#define WIFI_PASSWORD CONFIG_SKATEBOARD_WIFI_PASSWORD -#define WIFI_MAXIMUM_RETRIES CONFIG_SKATEBOARD_WIFI_MAXIMUM_RETRIES - enum { Ev_Connected = 1 << 0, Ev_Failed = 1 << 1, }; -static void event_handler( - void* arg, esp_event_base_t base, int32_t id, void* data) +static void event_cb(void* arg, esp_event_base_t base, int32_t id, void* data) { AppWifi* app = arg; @@ -27,17 +22,17 @@ static void event_handler( if (base == WIFI_EVENT && id == WIFI_EVENT_STA_DISCONNECTED) { esp_wifi_connect(); - if (app->wifi_retries < WIFI_MAXIMUM_RETRIES) { + if (app->wifi_retries < CONFIG_WIFI_MAXIMUM_RETRIES) { esp_wifi_connect(); app->wifi_retries += 1; ESP_LOGE(TAG, "WIFI connection failed. Retrying (%d/%d)", app->wifi_retries + 1, - WIFI_MAXIMUM_RETRIES); + CONFIG_WIFI_MAXIMUM_RETRIES); return; } - xEventGroupSetBits(app->wifi_event_group, Ev_Failed); + xEventGroupSetBits(app->event_group, Ev_Failed); return; } @@ -47,32 +42,32 @@ static void event_handler( ESP_LOGI(TAG, "WIFI connected with IP " IPSTR, IP2STR(&ip_event->ip_info.ip)); - xEventGroupSetBits(app->wifi_event_group, Ev_Connected); + xEventGroupSetBits(app->event_group, Ev_Connected); return; } } void app_wifi_init(AppWifi* wifi) { - wifi->wifi_event_group = xEventGroupCreate(); + ESP_LOGI(TAG, "Initializing WIFI"); + + wifi->event_group = xEventGroupCreate(); - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta(); wifi_init_config_t init_config = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&init_config)); ESP_ERROR_CHECK(esp_event_handler_instance_register( - WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, wifi, NULL)); + WIFI_EVENT, ESP_EVENT_ANY_ID, &event_cb, wifi, NULL)); ESP_ERROR_CHECK(esp_event_handler_instance_register( - IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, wifi, NULL)); + IP_EVENT, IP_EVENT_STA_GOT_IP, &event_cb, wifi, NULL)); wifi_config_t config = { .sta = { - .ssid = WIFI_SSID, - .password = WIFI_PASSWORD, + .ssid = CONFIG_WIFI_SSID, + .password = CONFIG_WIFI_PASSWORD, .threshold.authmode = WIFI_AUTH_WPA2_PSK, }, }; @@ -82,20 +77,15 @@ void app_wifi_init(AppWifi* wifi) ESP_LOGI(TAG, "WIFI started"); - EventBits_t event_bits = xEventGroupWaitBits(wifi->wifi_event_group, + EventBits_t event_bits = xEventGroupWaitBits(wifi->event_group, Ev_Connected | Ev_Failed, pdFALSE, pdFALSE, - portMAX_DELAY); + pdMS_TO_TICKS(1000 * 60 * 2)); if (event_bits & Ev_Connected) { - ESP_LOGI(TAG, "WIFI connected to %s / '%s'", WIFI_SSID, WIFI_PASSWORD); - } else if (event_bits & Ev_Failed) { - ESP_LOGE(TAG, - "WIFI failed connecting to %s / '%s'", - WIFI_SSID, - WIFI_PASSWORD); + ESP_LOGI(TAG, "WIFI connected to %s", CONFIG_WIFI_SSID); } else { - ESP_LOGE(TAG, "Unexpected event"); + ESP_LOGE(TAG, "WIFI failed connecting to %s", CONFIG_WIFI_SSID); } } diff --git a/skateboard/main/app_wifi.h b/skateboard/main/app_wifi.h index 98ce5a0..044f90b 100644 --- a/skateboard/main/app_wifi.h +++ b/skateboard/main/app_wifi.h @@ -3,7 +3,7 @@ #include "freertos/idf_additions.h" typedef struct AppWifi { - EventGroupHandle_t wifi_event_group; + EventGroupHandle_t event_group; int wifi_retries; } AppWifi; diff --git a/skateboard/main/skateboard.c b/skateboard/main/skateboard.c index c8c649c..8bc3808 100644 --- a/skateboard/main/skateboard.c +++ b/skateboard/main/skateboard.c @@ -1,41 +1,66 @@ #include "app_mpu.h" +#include "app_mqtt.h" #include "app_wifi.h" +#include "esp_event.h" #include "esp_log.h" +#include "esp_netif.h" #include "freertos/idf_additions.h" -#include "i2cdev.h" -#include "mpu6050.h" #include "nvs_flash.h" #include +#include const char* TAG = "skateboard"; typedef struct App { AppWifi wifi; AppMpu mpu; + AppMqtt mqtt; } App; +#define msg_buffer_capacity 1024 +char msg_buffer[msg_buffer_capacity]; + +static void configure_cb(const char* topic, + size_t topic_size, + const void* data, + size_t data_size, + void* arg) +{ + App* app = arg; + (void)app; + + ESP_LOGI(TAG, "Received configure event (%.*s)", (int)topic_size, topic); + ESP_LOGI(TAG, "Data: %.*s", (int)data_size, (const char*)data); +} + void app_main(void) { ESP_LOGI(TAG, "Initializing"); ESP_LOGI(TAG, "IDF version: %s", esp_get_idf_version()); - esp_err_t status = nvs_flash_init(); - if (status == ESP_ERR_NVS_NO_FREE_PAGES - || status == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - status = nvs_flash_init(); - } - ESP_ERROR_CHECK(status); + esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE); + esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE); + esp_log_level_set("transport_base", ESP_LOG_VERBOSE); + esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); + esp_log_level_set("transport", ESP_LOG_VERBOSE); + esp_log_level_set("outbox", ESP_LOG_VERBOSE); + + ESP_ERROR_CHECK(nvs_flash_init()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); App app = { .wifi = { - .wifi_event_group = 0, + .event_group = 0, .wifi_retries = 0, }, }; app_wifi_init(&app.wifi); app_mpu_init(&app.mpu); + app_mqtt_init(&app.mqtt); + + app_mqtt_subscribe(&app.mqtt, "/skateboard/configure", configure_cb, &app); ESP_LOGI(TAG, "Initialized"); ESP_LOGI(TAG, "Free memory: %" PRIu32 " bytes", esp_get_free_heap_size()); @@ -54,10 +79,11 @@ void app_main(void) float temp; app_mpu_read_temperature(&app.mpu, &temp); - ESP_LOGI(TAG, - "Acceleration: x=% 7.2f y=% 7.2f z=% 7.2f " - "Rotation: x=% 7.1f y=% 7.1f z=% 7.1f " - "Temperature: % 2.1f", + int msg_size = snprintf(msg_buffer, + msg_buffer_capacity - 1, + "{ \"acceleration\": [%.4f, %.4f, %.4f], " + "\"rotation\": [%.4f, %.4f, %.4f], " + "\"temperature\": %.2f }", accel_x, accel_y, accel_z, @@ -66,6 +92,8 @@ void app_main(void) rotation_z, temp); + app_mqtt_publish(&app.mqtt, "/skateboard/update", msg_buffer, msg_size); + vTaskDelay(pdMS_TO_TICKS(200)); } }