#define TAG "ot_esp_power_save"
+static bool ot_connected = false;
+static bool mqtt_connected = false;
+static QueueHandle_t event_queue;
+
+// for tracking and reporting device uptime
+static uint32_t device_uptime_seconds = 0;
+
+
+
+static void log_error_if_nonzero(const char *message, int error_code)
+{
+ if (error_code != 0) {
+ ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
+ }
+}
+
+static void mqtt_reinit(esp_mqtt_client_handle_t client){
+ ESP_LOGW(TAG, "trying to shutdown old mqtt client here");
+ // get rid of previous handle
+ // the auto reconnect should handle everything else
+ ESP_ERROR_CHECK(esp_mqtt_client_stop(client));
+}
+
+
+/*
+ * @brief Event handler registered to receive MQTT events
+ *
+ * This function is called by the MQTT client event loop.
+ *
+ * @param handler_args user data registered to the event.
+ * @param base Event base for the handler(always MQTT Base in this example).
+ * @param event_id The id for the received event.
+ * @param event_data The data for the event, esp_mqtt_event_handle_t.
+ */
+static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
+{
+ ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
+ esp_mqtt_event_handle_t event = event_data;
+ switch ((esp_mqtt_event_id_t)event_id) {
+ case MQTT_EVENT_CONNECTED:
+ mqtt_client = event->client;
+ mqtt_connected = true;
+ ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
+ break;
+ case MQTT_EVENT_DISCONNECTED:
+ if ( event->client != mqtt_client ){
+ ESP_LOGI(TAG, "disco old mqtt client, staying connected on this one");
+ } else {
+ ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
+ mqtt_connected = false;
+ }
+ break;
+
+ case MQTT_EVENT_SUBSCRIBED:
+ ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
+ break;
+ case MQTT_EVENT_UNSUBSCRIBED:
+ ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
+ break;
+ case MQTT_EVENT_PUBLISHED:
+ ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
+ break;
+ 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);
+ break;
+ case MQTT_EVENT_ERROR:
+ if ( mqtt_client != NULL && event->client != mqtt_client ){
+ ESP_LOGI(TAG, "old mqtt client, staying connected on this one and shutting down old");
+ esp_mqtt_client_handle_t send_item = event->client;
+ xQueueSend(event_queue, &send_item, portMAX_DELAY);
+ } else {
+ mqtt_connected = false;
+ ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
+ }
+ if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
+ log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
+ log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
+ log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
+ ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
+
+ }
+
+ //ESP_ERROR_CHECK(esp_mqtt_client_reconnect(mqtt_client));
+ break;
+ default:
+ ESP_LOGI(TAG, "Other event id:%d", event->event_id);
+ break;
+ }
+}
+
+static void send_report_wifi(){
+ ESP_LOGI(TAG, "send_report_wifi was called!");
+ cJSON *root;
+ root = cJSON_CreateObject();
+ cJSON_AddStringToObject(root, "location", CONFIG_LOCATION);
+ cJSON_AddNumberToObject(root, "uptime", device_uptime_seconds);
+
+ //const char *my_json_string = cJSON_Print(root);
+ char *mqtt_string = cJSON_Print(root);
+ ESP_LOGI(TAG, "sending mqtt_string:\n%s",mqtt_string);
+ if (mqtt_connected == true){
+ int msg_id = esp_mqtt_client_publish(mqtt_client, "esp32/sensor_info", mqtt_string, 0, 1, 0);
+ ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
+ } else {
+ ESP_LOGW(TAG, "well, not quite yet (not connected)");
+ }
+ free(mqtt_string);
+ cJSON_Delete(root);
+}
+
+
+void init_mqtt(){
+ ESP_LOGI(TAG, "attempting to connect to MQTT");
+ mqtt_client = NULL;
+ esp_mqtt_client_config_t mqtt_cfg = {
+ .broker = {
+ .address.uri = CONFIG_BROKER_URL,
+ .verification.certificate = NULL,
+ //.verification.use_global_ca_store = true,
+ //.verification.crt_bundle_attach = esp_crt_bundle_attach,
+ },
+ .session.keepalive = 10,
+ //.cacert_buf = ca_cert,
+ //.cacert_bytes = strlen(ca_cert)+1,
+ };
+ esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
+ /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
+ esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
+ esp_mqtt_client_start(client);
+}
+
+static void monitoring_task(void* discard)
+{
+ int64_t cur_uptime = 0;
+ int64_t next_sleep_uptime = 0;
+ int64_t remaining_time = 0;
+ esp_mqtt_client_handle_t queue_item;
+ for(;;){
+
+ // receive an event we need to deal with from elsewhere, right now just reconnect related
+ if (xQueueReceive(event_queue, &queue_item, 0 )){
+ ESP_LOGW(TAG, "received a queue event in main monitoring loop! %p", queue_item);
+ mqtt_reinit(queue_item);
+ }
+ ESP_LOGI(TAG, "free heap: %"PRIu32, esp_get_free_heap_size());
+ cur_uptime = esp_timer_get_time();
+ // we'll use this to calc our sleeps later
+ next_sleep_uptime = cur_uptime + SLEEP_MS*1000;
+ // first things first (function gives microseconds, just convert to seconds)
+ // 32 bits is enough for >50 years and zigbee stack gets mad if we use more bits
+ device_uptime_seconds = (uint32_t)(cur_uptime/1000000);
+ // one BIG report for wifi
+ send_report_wifi();
+ cur_uptime = esp_timer_get_time();
+ remaining_time = next_sleep_uptime - cur_uptime;
+ ESP_LOGI(TAG, "next sleep uptime %lld cur_uptime %lld remaining time %lld", next_sleep_uptime, cur_uptime, remaining_time);
+ // sleep for 10 seconds before measuring again
+ ESP_LOGI(TAG, "sleeping for %lld ms", remaining_time/1000);
+ vTaskDelay( pdMS_TO_TICKS(remaining_time/1000) );
+ }
+}
+
+
+
+void handleNetifStateChanged(uint32_t aFlags, void *aContext)
+{
+ if ((aFlags & OT_CHANGED_THREAD_ROLE) != 0)
+ {
+ otDeviceRole changedRole = otThreadGetDeviceRole(aContext);
+
+ switch (changedRole)
+ {
+ case OT_DEVICE_ROLE_LEADER:
+ case OT_DEVICE_ROLE_ROUTER:
+ case OT_DEVICE_ROLE_CHILD:
+ ot_connected = true;
+ ESP_LOGI(TAG, "is_connected = true");
+ init_mqtt();
+ break;
+
+ case OT_DEVICE_ROLE_DETACHED:
+ case OT_DEVICE_ROLE_DISABLED:
+ ot_connected = false;
+ ESP_LOGI(TAG, "is_connected = false");
+ break;
+ }
+ }
+}
+
/**
* Override default network settings, such as panid, so the devices can join a
network
ESP_LOGE(TAG, "Failed to set OpenThread linkmode.");
abort();
}
+
+ /* Register Thread state change handler */
+ otSetStateChangedCallback(instance, handleNetifStateChanged, instance);
+
ESP_ERROR_CHECK(esp_openthread_auto_start(NULL));
/* Override default network credentials */
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
ESP_ERROR_CHECK(ot_power_save_init());
+ event_queue = xQueueCreate(5, sizeof(esp_mqtt_client_handle_t));
+
xTaskCreate(ot_task_worker, "ot_power_save_main", 4096, NULL, 5, NULL);
+ xTaskCreate(monitoring_task, "monitoring_task", 4096, NULL, 1, NULL);
}