-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
910 additions
and
141 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,38 @@ | ||
# ESP32 Standalone Memfault Demo Application | ||
# esp32 Demo Application | ||
|
||
This Demo App is based on the example in the Memfault Firmware SDK: | ||
This Demo App is based on the console example from ESP-IDF, which can be found | ||
here relative to the ESP-IDF SDK root folder: | ||
|
||
https://github.com/memfault/memfault-firmware-sdk/tree/0.39.0/examples/esp32 | ||
- `examples/system/console/advanced/` | ||
|
||
It also showcases including the Memfault SDK as a submodule for an ESP-IDF | ||
project. | ||
## Configuring for MQTT | ||
|
||
The submodule was added with this command: | ||
This application includes an option to send Memfault data over MQTT. This option requires a few extra pieces to set up. | ||
You can either follow the steps outlined here or use your own MQTT setup. | ||
|
||
```bash | ||
❯ git submodule add https://github.com/memfault/memfault-firmware-sdk.git \ | ||
third-party/memfault-firmware-sdk | ||
``` | ||
### Broker Setup | ||
|
||
When cloning this repo, either use the `--recursive` flag or update submodules | ||
after cloning: | ||
1. Install a local installtion of Cedalo by following the [installation guide](https://docs.cedalo.com/management-center/installation/) | ||
2. Login to Cedalo at <http://localhost:8088> | ||
3. Create a new client login for the device | ||
- Ensure device client has the "client" role to allow publishing data | ||
4. Create a new client login for the Python service | ||
- Ensure Python service client has "client" role to allow subscribing to data | ||
|
||
```bash | ||
❯ git clone --recursive https://github.com/memfault/esp32-standalone-example | ||
# or | ||
❯ git clone https://github.com/memfault/esp32-standalone-example | ||
❯ cd esp32-standalone-example | ||
❯ git submodule update --init --recursive | ||
``` | ||
### Service Setup | ||
|
||
## Building | ||
1. Modify the script found in Docs->Best Practices->MQTT with Memfault with the the following: | ||
1. The service client login information previously created | ||
2. Connection info for your local broker | ||
3. Map of Memfault projects to project keys | ||
2. Start the service by running `python mqtt.py` | ||
|
||
Can be built using `idf.py build` as usual. | ||
### Device Setup | ||
|
||
1. Make the following modifications to `main/app_memfault_transport_mqtt.c`: | ||
1. Update `MEMFAULT_PROJECT` macro with your project's name | ||
2. Update `s_mqtt_config` with your setup's IP address, and MQTT client username and password | ||
2. Clean your existing build with `idf.py fullclean && rm sdkconfig` | ||
3. Set your target: `idf.py set-target <esp32_platform_name>` | ||
4. Build your image: `idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.mqtt" build` | ||
5. Flash to your device using `idf.py flash` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//! @file | ||
//! | ||
//! Copyright (c) Memfault, Inc. | ||
//! See License.txt for details | ||
|
||
#pragma once | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
//! Initializes any components needed for configured transport | ||
//! | ||
//! Transport is selected via CONFIG_APP_MEMFAULT_TRANSPORT choices | ||
void app_memfault_transport_init(void); | ||
|
||
//! Sends all available Memfault chunks over configured transport | ||
//! | ||
//! Transport is selected via CONFIG_APP_MEMFAULT_TRANSPORT choices | ||
//! | ||
//! @return 0 on success or non-zero on error | ||
int app_memfault_transport_send_chunks(void); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
//! @file | ||
//! | ||
//! Copyright (c) Memfault, Inc. | ||
//! See License.txt for details | ||
|
||
#include "app_memfault_transport.h" | ||
#include "memfault/esp_port/http_client.h" | ||
|
||
void app_memfault_transport_init(void) {} | ||
|
||
int app_memfault_transport_send_chunks(void) { | ||
return memfault_esp_port_http_client_post_data(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
//! @file | ||
//! | ||
//! Copyright (c) Memfault, Inc. | ||
//! See License.txt for details | ||
|
||
#include <stddef.h> | ||
#include <stdint.h> | ||
|
||
#include "app_memfault_transport.h" | ||
#include "esp_log.h" | ||
#include "memfault/components.h" | ||
#include "mqtt_client.h" | ||
|
||
// TODO: Fill in with device's Memfault project | ||
#define MEMFAULT_PROJECT "my_project" | ||
|
||
static const char *TAG = "app_memfault_transport_mqtt"; | ||
|
||
// TODO: Fill in with broker connection configuration | ||
static esp_mqtt_client_config_t s_mqtt_config = { | ||
.broker.address.uri = "mqtt://192.168.50.88", | ||
.credentials.username = "test", | ||
.credentials.authentication.password = "test1234", | ||
.session.protocol_ver = MQTT_PROTOCOL_V_5, | ||
}; | ||
static SemaphoreHandle_t s_mqtt_connected = NULL; | ||
|
||
static esp_mqtt_client_handle_t s_mqtt_client = NULL; | ||
static esp_mqtt5_publish_property_config_t s_publish_property = { | ||
.topic_alias = 1, | ||
}; | ||
static char s_topic_string[128] = {0}; | ||
|
||
static uint8_t s_chunk_data[1024] = {0}; | ||
|
||
static void mqtt_event_handler(MEMFAULT_UNUSED void *handler_args, | ||
MEMFAULT_UNUSED esp_event_base_t base, | ||
MEMFAULT_UNUSED int32_t event_id, void *event_data) { | ||
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data; | ||
|
||
switch (event->event_id) { | ||
case MQTT_EVENT_CONNECTED: | ||
ESP_LOGI(TAG, "Connected to MQTT broker"); | ||
xSemaphoreGive(s_mqtt_connected); | ||
break; | ||
default: | ||
ESP_LOGE(TAG, "Unknown MQTT event received[%d]", event->event_id); | ||
break; | ||
} | ||
} | ||
|
||
static void prv_close_client(void) { | ||
int rv = esp_mqtt_client_disconnect(s_mqtt_client); | ||
if (rv) { | ||
ESP_LOGW(TAG, "Failed to disconnect[%d]", rv); | ||
} | ||
|
||
rv = esp_mqtt_client_destroy(s_mqtt_client); | ||
if (rv) { | ||
ESP_LOGW(TAG, "Failed to destroy client[%d]", rv); | ||
} | ||
memfault_metrics_heartbeat_timer_stop(MEMFAULT_METRICS_KEY(mqtt_conn_uptime)); | ||
|
||
s_mqtt_client = NULL; | ||
} | ||
|
||
static int prv_create_client(void) { | ||
if (s_mqtt_client) { | ||
return 0; | ||
} | ||
|
||
s_mqtt_client = esp_mqtt_client_init(&s_mqtt_config); | ||
if (s_mqtt_client == NULL) { | ||
ESP_LOGE(TAG, "MQTT client failed to initialize"); | ||
return -1; | ||
} | ||
|
||
int rv = | ||
esp_mqtt_client_register_event(s_mqtt_client, MQTT_EVENT_CONNECTED, mqtt_event_handler, NULL); | ||
if (rv) { | ||
ESP_LOGE(TAG, "MQTT event handler registration failed[%d]", rv); | ||
} | ||
|
||
rv = esp_mqtt_client_start(s_mqtt_client); | ||
if (rv) { | ||
ESP_LOGE(TAG, "MQTT client start failed[%d]", rv); | ||
return -1; | ||
} | ||
|
||
// Wait for successful connection | ||
rv = xSemaphoreTake(s_mqtt_connected, (1000 * 10) / portTICK_PERIOD_MS); | ||
if (rv != pdTRUE) { | ||
ESP_LOGE(TAG, "MQTT client failed to connect[%d]", rv); | ||
memfault_metrics_heartbeat_timer_start(MEMFAULT_METRICS_KEY(mqtt_conn_downtime)); | ||
prv_close_client(); | ||
return -1; | ||
} | ||
|
||
// Update connection metrics when connected | ||
memfault_metrics_heartbeat_timer_stop(MEMFAULT_METRICS_KEY(mqtt_conn_downtime)); | ||
memfault_metrics_heartbeat_timer_start(MEMFAULT_METRICS_KEY(mqtt_conn_uptime)); | ||
|
||
// Set topic alias before publishing | ||
rv = esp_mqtt5_client_set_publish_property(s_mqtt_client, &s_publish_property); | ||
if (rv != 0) { | ||
ESP_LOGW(TAG, "MQTT client could not set publish property [%d]", rv); | ||
} | ||
return 0; | ||
} | ||
|
||
static const char *prv_get_device_serial(void) { | ||
sMemfaultDeviceInfo info = {0}; | ||
memfault_platform_get_device_info(&info); | ||
return info.device_serial; | ||
} | ||
|
||
void prv_build_topic_string(void) { | ||
// String already built | ||
if (strlen(s_topic_string) > 0) { | ||
return; | ||
} | ||
|
||
const char *device_serial = prv_get_device_serial(); | ||
snprintf(s_topic_string, MEMFAULT_ARRAY_SIZE(s_topic_string), | ||
"memfault/" MEMFAULT_PROJECT "/%s/chunks", device_serial); | ||
} | ||
|
||
void app_memfault_transport_init(void) { | ||
#if MEMFAULT_FREERTOS_PORT_USE_STATIC_ALLOCATION != 0 | ||
static StaticSemaphore_t s_mqtt_connected; | ||
s_mqtt_connected = xSemaphoreCreateBinaryStatic(&s_mqtt_connected); | ||
#else | ||
s_mqtt_connected = xSemaphoreCreateBinary(); | ||
#endif | ||
} | ||
|
||
int app_memfault_transport_send_chunks(void) { | ||
int rv = prv_create_client(); | ||
|
||
if (rv) { | ||
return rv; | ||
} | ||
|
||
prv_build_topic_string(); | ||
|
||
ESP_LOGD(TAG, "Checking for packetizer data"); | ||
while (memfault_packetizer_data_available()) { | ||
size_t chunk_size = MEMFAULT_ARRAY_SIZE(s_chunk_data); | ||
bool chunk_filled = memfault_packetizer_get_chunk(s_chunk_data, &chunk_size); | ||
|
||
if (!chunk_filled) { | ||
ESP_LOGW(TAG, "No chunk data produced"); | ||
break; | ||
} | ||
|
||
rv = esp_mqtt_client_publish(s_mqtt_client, s_topic_string, (char *)s_chunk_data, chunk_size, 1, | ||
0); | ||
if (rv < 0) { | ||
ESP_LOGE(TAG, "MQTT failed to publish[%d]", rv); | ||
memfault_packetizer_abort(); | ||
break; | ||
} | ||
|
||
memfault_metrics_heartbeat_add(MEMFAULT_METRICS_KEY(mqtt_publish_bytes), chunk_size); | ||
memfault_metrics_heartbeat_add(MEMFAULT_METRICS_KEY(mqtt_publish_count), 1); | ||
ESP_LOGD(TAG, "chunk[%d], len[%zu] published to %s", rv, chunk_size, s_topic_string); | ||
} | ||
|
||
prv_close_client(); | ||
return rv; | ||
} |
Oops, something went wrong.