#include "nx/software/SystemSettings.h" #include "nx/software/SystemSettingsApi.h" #include "nx/software/AppSettings.h" #include "nx/software/AppSettingsApi.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_system.h" #include "nx/firmware/Storage.h" #include "nx/firmware/Wifi.h" #include "nx/firmware/MqTriggerHttpServer.h" #include "nx/firmware/MqttClient.h" #include "nx/firmware/SntpClient.h" #include "nx/firmware/StatusIndicator.h" #include "nx/firmware/Restarter.h" #include "HttpHandlers.h" #include "esp_log.h" #include #define TAG "MAIN" #define SNTP_RETRIES 8 #define API_QOS 2 #define HB_QOS 1 static const char* DEVICE_NAME_PREFIX = "mqt-"; static void startWifi(void); static void onWifiConnected(void); static void onWifiError(void); static void onAppSettingsUpdate(void); static void onMqttConnected(); static void onMqttDisconnected(); static void onMqttError(); static void onMqttMessage(const char* msg); static void hbTask(void*); static SystemSettings* systemSettings = NULL; static AppSettings* appSettings = NULL; static WifiSettings wifiSettings; static MqttSettings mqttSettings; static bool wifiStarted = false; static bool mqttStarted = false; static const MqTriggerHttpCallbacks httpCallbacks = { .getRoot = rootHandler, .getJs = jsHandler, .getCss = cssHandler, .getSysSetForm = sysFormHandler, .getAppSetForm = appFormHandler, .getSysSet = nxApiGetSystemSettings, .postSysSet = nxApiUpdateSystemSettings, .getAppSet = nxApiGetAppSettings, .postAppSet = nxApiUpdateAppSettings // .postCmd = nxApiHandleCmd }; void app_main(void) { nxInitStatusIndicator(); nxUpdateStatus(STATUS_BOOT); xTaskCreate(&nxStatusIndicatorTask, "status_task", 2048, NULL, 1, NULL); nxInitStorage(); // uncomment to force default NVS initialization for development // uint8_t zero = 0; // nxStorageWrite("ledinit", &zero, 1); // nxStorageWrite("sysinit", &zero, 1); nxInitSystemSettings(nxStorageWrite, nxStorageRead); nxInitAppSettings(nxStorageWrite, nxStorageRead, onAppSettingsUpdate); systemSettings = nxGetSystemSettings(); appSettings = nxGetAppSettings(); // uncomment to force WiFi settings for development // strcpy(systemSettings->wifiSsid, "androidAp"); // strcpy(systemSettings->wifiPassword, "password"); // systemSettings->useStaticAddr = false; nxStartRestarter(systemSettings->rsSchedule, systemSettings->tzEnv); nxSetWifiConnectedCallback(onWifiConnected); nxSetWifiErrorCallback(onWifiError); startWifi(); } // ----- static void startWifi(void) { wifiSettings = (struct WifiSettings){ .wname = systemSettings->wifiSsid, .wpass = systemSettings->wifiPassword, .devicePrefix = DEVICE_NAME_PREFIX, .usePowerSave = &(systemSettings->wifiPowerSave), .useStaticAddr = &(systemSettings->useStaticAddr), .ip4addr = systemSettings->ip4addr, .ip4gw = systemSettings->ip4gw, .ip4mask = systemSettings->ip4mask, .dns = systemSettings->dnsAddr }; ESP_LOGI(TAG, "Initializing WiFi"); if (!nxInitWifi(&wifiSettings)) { nxUpdateStatus(STATUS_SYSTEM_ERROR); } } static void onWifiConnected(void) { nxUpdateStatus(STATUS_OK); if (wifiStarted) { return; } wifiStarted = true; systemSettings->deviceName = nxGetWifiDeviceName(); nxInitSntpClient(SNTP_RETRIES, systemSettings->sntpAddr, systemSettings->tzEnv); strcpy(mqttSettings.brokerAddr, appSettings->mqttHost); strcpy(mqttSettings.apiTopic, appSettings->mqttApiUri); strcpy(mqttSettings.hbTopic, appSettings->mqttHbUri); strcpy(mqttSettings.user, appSettings->mqttUser); strcpy(mqttSettings.password, appSettings->mqttPassword); strcpy(mqttSettings.clientId, appSettings->overrideDevName ? appSettings->customDevName : systemSettings->deviceName); mqttSettings.hbIntervalSec = appSettings->mqttHbIntervalSec; mqttSettings.caCrt = appSettings->mqttUseTls ? appSettings->caCert : NULL; mqttSettings.messageCb = onMqttMessage; mqttSettings.connectedCb = onMqttConnected; mqttSettings.disconnectedCb = onMqttDisconnected; mqttSettings.errorCb = onMqttError; if (!nxStartMqttClient(&mqttSettings)) { onMqttError(); } nxSetMqTriggerHttpCallbacks(&httpCallbacks); nxStartMqTriggerHttpServer(); } static void onAppSettingsUpdate(void) { ESP_LOGI(TAG, "App settings updated"); nxUpdateStatus(STATUS_OK_WORKING); } static void onMqttMessage(const char* msg) { ESP_LOGI(TAG, "MQTT MESSAGE RECEIVED: %s", msg); nxUpdateStatus(STATUS_OK_WORKING); } static void onWifiError() { ESP_LOGE(TAG, "WiFi ERROR"); nxUpdateStatus(STATUS_SYSTEM_ERROR); } static void onMqttConnected() { ESP_LOGI(TAG, "MQTT CONNECTED"); if (!mqttStarted) { xTaskCreate(&hbTask, "hb_task", 2048, NULL, 1, NULL); mqttStarted = true; } // (re)subscribe if (nxMqttSubscribe(appSettings->mqttApiUri, API_QOS)) { nxUpdateStatus(STATUS_OK); } } static void onMqttDisconnected() { ESP_LOGW(TAG, "MQTT DISCONNECTED"); nxUpdateStatus(STATUS_APP_ERROR); } static void onMqttError() { ESP_LOGE(TAG, "MQTT ERROR"); nxUpdateStatus(STATUS_APP_ERROR); } static void hbTask(void* param) { // UNUSED(param); ESP_LOGI(TAG, "Starting MQTT heartbeat task"); ESP_LOGI(TAG, "hbIntervalSec: %d", appSettings->mqttHbIntervalSec); if (appSettings->mqttHbIntervalSec < 1) { ESP_LOGI(TAG, "Heartbeat interval < 1 sec, skipping"); vTaskDelete(NULL); return; } while (1) { if (nxMqttIsConnected()) { ESP_LOGI(TAG, "Sending MQTT heartbeat"); char timeStr[DT_FORMAT_LEN]; nxGetTimeStr(timeStr); char hbMessage[DT_FORMAT_LEN + strlen(nxGetWifiDeviceName()) + 2]; strcpy(hbMessage, nxGetWifiDeviceName()); strcat(hbMessage, " "); strcat(hbMessage, timeStr); if(nxMqttPublish(appSettings->mqttHbUri, HB_QOS, hbMessage, strlen(hbMessage), 1) < 0) { ESP_LOGE(TAG, "Cannot publish heartbeat message"); } } else { ESP_LOGW(TAG, "Skipping MQTT heartbeat due to the disconnected client"); } vTaskDelay(appSettings->mqttHbIntervalSec*1000 / portTICK_PERIOD_MS); } }