diff --git a/.github/workflows/build-datalogger-iot.yml b/.github/workflows/build-datalogger-iot.yml index 45068d3..9114e46 100644 --- a/.github/workflows/build-datalogger-iot.yml +++ b/.github/workflows/build-datalogger-iot.yml @@ -18,9 +18,7 @@ jobs: steps: - name: Checkout Repo and submodules - uses: actions/checkout@v3 - with: - ref: main + uses: actions/checkout@v4 # setup the ssh key used to pull in the Flux SDK source. This was the # only way found to make this work when using private models (ssh private key here, public on Flux deploy keys @@ -33,7 +31,7 @@ jobs: # checkout flux-sdk - name: Checkout the flux-sdk run: | - git clone --branch main git@github.com:sparkfun/flux-sdk.git + git clone --branch feature/version-1.2.0 git@github.com:sparkfun/flux-sdk.git echo "FLUX_SDK_PATH=`pwd`/flux-sdk" >> $GITHUB_ENV # Run cmake - this will build a custom SparkFun_Flux library we can use with @@ -48,7 +46,7 @@ jobs: # Setup Arduino command line - install esp32 and all the libs flux needs - name: Arduino - Install and setup the Arduino CLI - uses: arduino/setup-arduino-cli@v1 + uses: arduino/setup-arduino-cli@v2 - name: Arduino - Start config file run: arduino-cli config init --additional-urls "https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" @@ -56,16 +54,35 @@ jobs: - name: Arduino - Update index run: arduino-cli core update-index - # Install ESP32 - v2.0.9 (May, 2023) + # Install ESP32 - v3.0.7 - working as of June 2025 (latest versions fail for various reasons) - name: Arduino - Install ESP32 platform - run: arduino-cli core install esp32:esp32@2.0.14 + run: arduino-cli core install esp32:esp32@3.1.3 # install the libraries Flux uses - name: Install Flux dependant libraries. run: ./flux-sdk/install-libs.sh - name: Install datalogger libraries - run: arduino-cli lib install FastLED ESPAsyncWebSrv + run: arduino-cli lib install FastLED "ESP Async WebServer" "Async TCP" + + - name: Checkout BMV080 Arduino library repo + uses: actions/checkout@v4 + with: + repository: sparkfun/SparkFun_BMV080_Arduino_Library + path: SparkFun_BMV080_Arduino_Library + + - name: Checkout BMV080 libraries repo + uses: actions/checkout@v4 + with: + token: ${{ secrets.BMV080_LIBS_REPO_KEY }} + repository: sparkfun/sfe-datalogger-bmv080-libs + path: sfe-datalogger-bmv080-libs + + ## copy in the BMV080 libraries + - name: Copy BMV080 libraries + run: | + cp sfe-datalogger-bmv080-libs/inc/* ./SparkFun_BMV080_Arduino_Library/src/sfTk + cp sfe-datalogger-bmv080-libs/esp32/* ./SparkFun_BMV080_Arduino_Library/src/esp32 # Compile time - build the Firmware for the data logger. # Note: @@ -75,10 +92,10 @@ jobs: - name: Compile DataLogger firmware binary run: arduino-cli compile --fqbn esp32:esp32:esp32 ./sfeDataLoggerIoT/sfeDataLoggerIoT.ino - --build-property upload.maximum_size=3145728 --build-property build.flash_size=16MB --build-property build.partitions=partitions + --build-property upload.maximum_size=4980736 --build-property build.flash_size=16MB --build-property build.partitions=partitions --build-property build.flash_mode=dio --build-property build.flash_freq=80m --build-property "compiler.cpp.extra_flags=\"-DDATALOGGER_IOT_APP_KEY=$DATALOGGER_IOT_APP_KEY\" \"-DDATALOGGER_IOT_ID_KEY=$DATALOGGER_IOT_ID_KEY\" \"-DBUILD_NUMBER=$GITHUB_RUN_NUMBER\"" - --export-binaries --clean --library `pwd`/SparkFun_Flux + --export-binaries --clean --library `pwd`/SparkFun_DataLoggerIoT --library `pwd`/SparkFun_BMV080_Arduino_Library # - name: Rename Library # run: | @@ -86,7 +103,7 @@ jobs: # mv sfeDataLoggerIoT.ino.bin SparkFun_DataLoggerIoT.bin # Upload the build files - bootloader, paritions, firmware - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: sfeDataLoggerIoT-build path: sfeDataLoggerIoT/build/esp32.esp32.esp32/sfeDataLoggerIoT.ino*.bin @@ -107,7 +124,7 @@ jobs: cd fuse_id python setup.py sdist - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: Flash ID CLI Tool path: fuse_id/dist diff --git a/.gitignore b/.gitignore index d88a2db..7ecdb5e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,12 @@ fuse_id/sfe_dl_fuseid.egg-info build/ SparkFun_Flux/ + +sfeDataLoggerIoT/Doxyfile + +sfeDataLoggerIoT/html/ + +sfeDataLoggerIoT/latex/ +.gitignore + +SparkFun_DataLoggerIoT/ diff --git a/CMakeLists.txt b/CMakeLists.txt index ef06194..304b5be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,10 @@ cmake_minimum_required(VERSION 3.13) project(DataLoggerIoT NONE) # Import the flux-dk cmake system -include(flux_sdk_import.cmake) +include($ENV{FLUX_SDK_PATH}/external/flux_sdk_import.cmake) + +# set our Arduino Library name to something unique to this project +flux_sdk_set_library_name(SparkFun_DataLoggerIoT) # Where is directory that the flux stuff will be added to? This is the relative path from this file # to the aurdiuno sketch directory this is also used as the name of the cmake project diff --git a/sfeDataLoggerIoT/sfeDLBoard.h b/sfeDataLoggerIoT/sfeDLBoard.h index 167c047..d4ce6fd 100644 --- a/sfeDataLoggerIoT/sfeDLBoard.h +++ b/sfeDataLoggerIoT/sfeDLBoard.h @@ -11,6 +11,7 @@ // Board specific things for the DataLogger.. #pragma once +#include // Pins // Das Boot button @@ -24,3 +25,13 @@ const uint8_t kDLBoardLEDBuiltin = 25; // RGB LED const uint8_t kDLBoardLEDRGBBuiltin = 26; + +// Define the GNSS PPS pin for the datalogger IoT board +const uint16_t kDLBoardGNSSPPSPins[] = {33, 36}; + +// External Serial pins on the board +const uint8_t kDLBoardExtSerialRXPin = 16; +const uint8_t kDLBoardExtSerialTXPin = 17; + +// pins that can be used for interrupts. +const uint16_t kDLBoardInterruptPins[] = {33, 36}; \ No newline at end of file diff --git a/sfeDataLoggerIoT/sfeDLCommands.h b/sfeDataLoggerIoT/sfeDLCommands.h index d789543..ee5b89e 100644 --- a/sfeDataLoggerIoT/sfeDLCommands.h +++ b/sfeDataLoggerIoT/sfeDLCommands.h @@ -193,41 +193,31 @@ class sfeDLCommands } //--------------------------------------------------------------------- /// - /// @brief Enables *normal* log level output - /// - /// @param dlApp Pointer to the DataLogger App - /// @retval bool indicates success (true) or failure (!true) - /// - bool logLevelNormal(sfeDataLogger *dlApp) - { - flxLog.setLogLevel(flxLogInfo); - flxLog_I(F("Output level set to Normal")); - return true; - } - //--------------------------------------------------------------------- - /// - /// @brief Enables debug log level output + /// @brief Enables verbose log level output /// /// @param dlApp Pointer to the DataLogger App /// @retval bool indicates success (true) or failure (!true) /// - bool logLevelDebug(sfeDataLogger *dlApp) + bool logLevelVerbose(sfeDataLogger *dlApp) { - flxLog.setLogLevel(flxLogDebug); - flxLog_D(F("Output level set to Debug")); + flxLog.setLogLevel(flxLogVerbose); + flxLog_V(F("Output level set to Verbose")); return true; } //--------------------------------------------------------------------- /// - /// @brief Enables verbose log level output + /// @brief Toggle verbose output /// - /// @param dlApp Pointer to the DataLogger App + /// @param theApp Pointer to the DataLogger App /// @retval bool indicates success (true) or failure (!true) /// - bool logLevelVerbose(sfeDataLogger *dlApp) + bool toggleVerboseOutput(sfeDataLogger *theApp) { - flxLog.setLogLevel(flxLogVerbose); - flxLog_V(F("Output level set to Verbose")); + + if (theApp) + theApp->set_verbose(!theApp->get_verbose()); + flxLog_I("Verbose Output %s", theApp->get_verbose() ? "Enabled" : "Disabled"); + return true; } //--------------------------------------------------------------------- @@ -416,7 +406,7 @@ class sfeDLCommands if (!dlApp) return false; - dlApp->_logger.logObservation(); + flxSendEvent(flxEvent::kOnLogObservationWithSource, "CLI"); return true; } @@ -474,9 +464,7 @@ class sfeDLCommands {"devices", &sfeDLCommands::listLoadedDevices}, {"save-settings", &sfeDLCommands::saveSettings}, {"heap", &sfeDLCommands::heapStatus}, - {"normal-output", &sfeDLCommands::logLevelNormal}, - {"debug-output", &sfeDLCommands::logLevelDebug}, - {"verbose-output", &sfeDLCommands::logLevelVerbose}, + {"verbose", &sfeDLCommands::toggleVerboseOutput}, {"systime", &sfeDLCommands::outputSystemTime}, {"uptime", &sfeDLCommands::outputUpTime}, {"device-id", &sfeDLCommands::printDeviceID}, diff --git a/sfeDataLoggerIoT/sfeDLLed.cpp b/sfeDataLoggerIoT/sfeDLLed.cpp index 3d7ee76..ea0710b 100644 --- a/sfeDataLoggerIoT/sfeDLLed.cpp +++ b/sfeDataLoggerIoT/sfeDLLed.cpp @@ -123,7 +123,7 @@ bool _sfeLED::initialize(void) // Event processing task BaseType_t xReturnValue = xTaskCreate(_sfeLED_TaskProcessing, // Event processing task function - "eventProc", // String with name of task. + "LEDEventProc", // String with name of task. kStackSize, // Stack size in 32 bit words. NULL, // Parameter passed as input of the task 1, // Priority of the task. @@ -319,7 +319,7 @@ void _sfeLED::blink(uint32_t timeout) //--------------------------------------------------------- // Blink - change state, start blinking -void _sfeLED::blink(sfeLEDColor_t color, uint timeout) +void _sfeLED::blink(sfeLEDColor_t color, uint32_t timeout) { if (_disabled) return; diff --git a/sfeDataLoggerIoT/sfeDLMode.cpp b/sfeDataLoggerIoT/sfeDLMode.cpp index c4acadf..9fddedf 100644 --- a/sfeDataLoggerIoT/sfeDLMode.cpp +++ b/sfeDataLoggerIoT/sfeDLMode.cpp @@ -132,7 +132,10 @@ uint32_t dlModeCheckSystem(void) for (int32_t block3Address = EFUSE_BLK3_RDATA0_REG; block3Address <= EFUSE_BLK3_RDATA7_REG; block3Address += 4) { // this is read in 4 byte chunks... - uint32_t block = REG_GET_FIELD(block3Address, EFUSE_BLK3_DOUT0); + // uint32_t block = REG_GET_FIELD(block3Address, EFUSE_BLK3_DOUT0); + // Arduion ESP32 core v 3.2.0 -- may 23, 2025 - looks like this defines changed, trying this. + // TODO: Still needs testing, but it's complining (which measn nada) + uint32_t block = REG_GET_FIELD(block3Address, EFUSE_BLK3_DIN0); data_buffer[i++] = block & 0xFF; data_buffer[i++] = block >> 8 & 0xFF; diff --git a/sfeDataLoggerIoT/sfeDLWebServer.h b/sfeDataLoggerIoT/sfeDLWebServer.h index 6bff626..6d8fba6 100644 --- a/sfeDataLoggerIoT/sfeDLWebServer.h +++ b/sfeDataLoggerIoT/sfeDLWebServer.h @@ -20,7 +20,9 @@ #include // Testing -#include +// Used a different version for v1.0* +// #include +#include class sfeDLWebServer : public flxActionType { diff --git a/sfeDataLoggerIoT/sfeDataLogger.cpp b/sfeDataLoggerIoT/sfeDataLogger.cpp index 33fff07..2073666 100644 --- a/sfeDataLoggerIoT/sfeDataLogger.cpp +++ b/sfeDataLoggerIoT/sfeDataLogger.cpp @@ -145,6 +145,7 @@ sfeDataLogger::sfeDataLogger() flxRegister(startupOutputMode, "Startup Messages", "Level of message output at startup"); flxRegister(startupDelaySecs, "Startup Delay", "Startup Menu Delay in Seconds"); flxRegister(verboseDevNames, "Device Names", "Name always includes the device address"); + flxRegister(verboseEnabled, "Verbose Messages", "Enable verbose messages"); // about? flxRegister(aboutApplication, "About...", "Details about the system"); @@ -167,6 +168,9 @@ sfeDataLogger::sfeDataLogger() // app key flux.setAppToken(_app_jump, sizeof(_app_jump)); + + // do not want the wifi connect() call made until after initialize + _wifiConnection.setDelayedStartup(true); } //--------------------------------------------------------------------------- @@ -242,7 +246,7 @@ void sfeDataLogger::onSystemActivityLow(void) //--------------------------------------------------------------------------- // // CAlled when the button is pressed and an increment time passed -void sfeDataLogger::onButtonPressed(uint increment) +void sfeDataLogger::onButtonPressed(uint32_t increment) { // we need LED on for visual feedback... @@ -270,7 +274,7 @@ void sfeDataLogger::onButtonPressed(uint increment) } } //--------------------------------------------------------------------------- -void sfeDataLogger::onButtonReleased(uint increment) +void sfeDataLogger::onButtonReleased(uint32_t increment) { if (increment > 0) sfeLED.off(); @@ -474,6 +478,16 @@ void sfeDataLogger::onDeviceLoad() for (auto tw : *twists) _logger.listen(tw->on_clicked); // Connect logger to the clicked event } + + // setup the GNSS device - will create some properties that should be visible + // after the device is loaded and before restore (if the settings are saved) + setupGNSS(); + + // setup the external serial device manager + setupExtSerial(); + + // setup interrupt event + setInterruptEvent(); } //--------------------------------------------------------------------- // onRestore() @@ -525,11 +539,14 @@ void sfeDataLogger::onInitStartupCommands(uint delaySecs) uint16_t mode; const char *name; } startupCommand_t; - startupCommand_t commands[] = {{'n', kDataLoggerOpNone, "normal-startup"}, - {'a', kDataLoggerOpStartNoAutoload, "device-auto-load-disabled"}, - {'l', kDataLoggerOpStartListDevices, "i2c-driver-listing-enabled"}, - {'w', kDataLoggerOpStartNoWiFi, "wifi-disabled"}, - {'s', kDataLoggerOpStartNoSettings, "settings-restore-disabled"}}; + startupCommand_t commands[] = { + {'n', kDataLoggerOpNone, "normal-startup"}, + {'v', kAppOpStartVerboseOutput, "verbose-output-enabled"}, + {'a', kDataLoggerOpStartNoAutoload, "device-auto-load-disabled"}, + {'l', kDataLoggerOpStartListDevices, "i2c-driver-listing-enabled"}, + {'w', kDataLoggerOpStartNoWiFi, "wifi-disabled"}, + {'s', kDataLoggerOpStartNoSettings, "settings-restore-disabled"}, + }; // Default int iCommand = 0; @@ -599,8 +616,8 @@ void sfeDataLogger::onInitStartupCommands(uint delaySecs) void sfeDataLogger::onInit(void) { // Did the user set a serial value? - uint theRate; - uint theDelay; + uint32_t theRate; + uint32_t theDelay; getStartupProperties(theRate, theDelay); // just to be safe... @@ -619,6 +636,20 @@ void sfeDataLogger::onInit(void) startupDelaySecs = theDelay; onInitStartupCommands(theDelay); + + // change the order of the system settings + flux.insert_after(&flxSettings, &flxClock); + + // set interrupt event after the output file + flux.insert_after(&_extIntrEvent, &_theOutputFile); + + // GPIO devices in the menu + _extSerial.setTitle("GPIO Devices"); + flux.insert_after(&_extSerial, &_extIntrEvent); + flux.insert_after(&_soilMoistureEnable, &_extSerial); + flux.insert_after(&_analogPinEnable, &_soilMoistureEnable); + + flux.insert_after(&_iotEndpoints, &_analogPinEnable); } //--------------------------------------------------------------------------- // Check our platform status @@ -689,9 +720,11 @@ bool sfeDataLogger::onStart() boot_count++; + // init wifi + _wifiConnection.connect(); // Logging is done at an interval - using an interval timer. // Connect logger to the timer event - _logger.listen(_timer.on_interval); + _logger.listen(_timer.on_interval_with_name); // - Add the JSON and CVS format to the logger _logger.add(_fmtJSON); @@ -707,6 +740,15 @@ bool sfeDataLogger::onStart() // setup NFC - it provides another means to load WiFi credentials setupNFDevice(); + // now lets rock on the external serilal device + if (_extSerial.begin()) + flxLog_I(F("External Serial Device started: RX %u, TX %u, Baud: %u"), _extSerial.rxPin(), _extSerial.txPin(), + _extSerial.serialBaudRate()); + else + flxLog_I(F("External Serial Device not started")); + + flxLog_N(""); + // check our I2C devices // Loop over the device list - note that it is iterable. flxLog_I_(F("Loading devices ... ")); @@ -723,8 +765,10 @@ bool sfeDataLogger::onStart() flxLog_N_(F(" %-20s - %-40s {"), device->name(), device->description()); if (device->getKind() == flxDeviceKindI2C) flxLog_N("%s x%x}", "qwiic", device->address()); - else + else if (device->getKind() == flxDeviceKindSPI) flxLog_N("%s p%u}", "SPI", device->address()); + else if (device->getKind() == flxDeviceKindGPIO) + flxLog_N("%s p%u}", "GPIO", device->address()); if (device->nOutputParameters() > 0) _logger.add(device); @@ -768,6 +812,10 @@ bool sfeDataLogger::onStart() // for our web server file search _iotWebServer.setFilePrefix(_theOutputFile.filePrefix()); + // Register our device management event handlers + flxRegisterEventCB(flxEvent::kOnFluxAddDevice, this, &sfeDataLogger::onDeviceAdded); + flxRegisterEventCB(flxEvent::kOnFluxRemoveDevice, this, &sfeDataLogger::onDeviceRemoved); + // clear startup flags/mode clearOpMode(kDataLoggerOpStartup); clearOpMode(kDataLoggerOpStartAllFlags); @@ -776,14 +824,15 @@ bool sfeDataLogger::onStart() if (_pDisplay) _pDisplay->update(); #endif + sfeLED.off(); // we are done with startup - reset output mode if (startupOutputMode() != kAppStartupMsgNormal) flxLog.setLogLevel(flxLogInfo); - // flxLog_I("DEBUG: onStart() - exit - Free Heap: %d", ESP.getFreeHeap()); - + // log now! + _timer.trigger(); return true; } @@ -857,6 +906,35 @@ void sfeDataLogger::checkBatteryLevels(void) sfeLED.flash(color); } +//--------------------------------------------------------------------------- +// Device bookkeeping +//--------------------------------------------------------------------------- +void sfeDataLogger::onDeviceAdded(uint32_t uiDevice) +{ + // if in startup skip + if (inOpMode(kDataLoggerOpStartup)) + return; + + flxDevice *pDevice = (flxDevice *)uiDevice; + if (pDevice == nullptr) + return; + + // add this device to the logger + _logger.add(pDevice); +} +void sfeDataLogger::onDeviceRemoved(uint32_t uiDevice) +{ + // if in startup skip + if (inOpMode(kDataLoggerOpStartup)) + return; + + flxDevice *pDevice = (flxDevice *)uiDevice; + if (pDevice == nullptr) + return; + + // remove this device from the logger + _logger.remove(pDevice); +} //--------------------------------------------------------------------------- // loop() // @@ -871,7 +949,11 @@ bool sfeDataLogger::loop() uint8_t chIn = Serial.read(); if (chIn == '!') { + flxSerial.textToWhite(); + Serial.write('>'); + flxSerial.textToNormal(); Serial.write('!'); + Serial.flush(); sfeDLCommands cmdProcessor; bool status = cmdProcessor.processCommand(this); } diff --git a/sfeDataLoggerIoT/sfeDataLogger.h b/sfeDataLoggerIoT/sfeDataLogger.h index 61a7d41..6c5ad5d 100644 --- a/sfeDataLoggerIoT/sfeDataLogger.h +++ b/sfeDataLoggerIoT/sfeDataLogger.h @@ -25,9 +25,9 @@ #include // settings storage +#include #include #include -#include #include // SD Card output @@ -63,6 +63,19 @@ #include #include +// External Serial Device connection and use +#include + +// Interrupt event to drive logging +#include + +// Soil moisture sensor enable +#include +#include + +// analog pin +#include + // System Firmware update/reset #include @@ -112,10 +125,11 @@ const uint32_t kStartupMenuDefaultDelaySecs = 2; #define kDataLoggerOpStartListDevices (1 << 4) #define kDataLoggerOpStartNoSettings (1 << 5) #define kDataLoggerOpStartNoWiFi (1 << 6) +#define kAppOpStartVerboseOutput (1 << 7) #define kDataLoggerOpStartAllFlags \ (kDataLoggerOpStartNoAutoload | kDataLoggerOpStartListDevices | kDataLoggerOpStartNoSettings | \ - kDataLoggerOpStartNoWiFi) + kDataLoggerOpStartNoWiFi | kAppOpStartVerboseOutput) #define inOpMode(__mode__) ((_opFlags & __mode__) == __mode__) #define setOpMode(__mode__) _opFlags |= __mode__ @@ -184,6 +198,17 @@ class sfeDataLogger : public flxApplication //--------------------------------------------------------------------- void setupENS160(void); + //--------------------------------------------------------------------- + void setupGNSS(void); + // void gnssPPSEventCB(void); + + //--------------------------------------------------------------------------- + // serial input device setup and event methods ... + // void extSerialDataEventCB(void); + void setupExtSerial(void); + + void setInterruptEvent(void); + //------------------------------------------ // For controlling the log output types @@ -242,6 +267,9 @@ class sfeDataLogger : public flxApplication std::string get_local_name(void); void set_local_name(std::string name); + bool get_verbose(void); + void set_verbose(bool enable); + // color text bool get_color_text(void); void set_color_text(bool); @@ -320,6 +348,9 @@ class sfeDataLogger : public flxApplication kAppStartupMsgNormal, {{"Normal", kAppStartupMsgNormal}, {"Compact", kAppStartupMsgCompact}, {"Disabled", kAppStartupMsgNone}}}; + // Verbose messages enabled? + flxPropertyRWBool verboseEnabled = {false}; + // log system info // Enabled/Disabled flxPropertyRWBool logSysInfo; @@ -342,15 +373,19 @@ class sfeDataLogger : public flxApplication void onErrorMessage(uint8_t); - void getStartupProperties(uint &baudRate, uint &startupDelay); + void getStartupProperties(uint32_t &baudRate, uint32_t &startupDelay); // Board button callbacks - void onButtonPressed(uint); - void onButtonReleased(uint); + void onButtonPressed(uint32_t); + void onButtonReleased(uint32_t); // battery level checks void checkBatteryLevels(void); + // system device add/remove events -- when this happens, bookkeeping is requires + void onDeviceAdded(uint32_t); + void onDeviceRemoved(uint32_t); + // Class members -- that make up the application structure // WiFi and NTP @@ -375,7 +410,7 @@ class sfeDataLogger : public flxApplication flxFileRotate _theOutputFile; // settings things - flxStorageESP32Pref _sysStorage; + flxPreferences _sysStorage; flxSettingsSerial _serialSettings; flxStorageJSONPrefFile _jsonStorage; @@ -386,6 +421,31 @@ class sfeDataLogger : public flxApplication // a biometric sensor hub flxDevBioHub _bioHub; + // the external serial connection manager + flxOptExtSerial _extSerial; + + // interrupt event to drive logging + flxOptInterruptEvent _extIntrEvent; + + // Soil moisture sensor Enable manager. We use the flxOptEnableDevice template to manage the device + // This allows us to enable/disable the device and manage its lifecycle. + // We pass in an initialiser list that contains: + // - The name and description of the device. + // - The default pins for the soil sensor - VCC and Sensor pin. + flxOptEnableDevice _soilMoistureEnable = { + "Soil Moisture Sensor", "Enable GPIO attached Soil Moisture Sensor", (uint8_t)33, (uint8_t)2}; + + // Analog pin device + // This allows us to enable/disable the device and manage its lifecycle. + // We pass in an initialiser list that contains: + // - The name and description of the device. + // - Available pins + // - The pin names for the analog pins. + flxOptEnableDevice _analogPinEnable = { + "Analog Pin Sensor", "Read analog values from a pin", {{"A0", 36}, {"A3", 39}, {"A7", 35}}}; + + // Container for IoT endpoint drivers + flxActionContainer _iotEndpoints; // IoT endpoints // An generic MQTT client flxMQTTESP32 _mqttClient; diff --git a/sfeDataLoggerIoT/sfeDataLoggerAbout.cpp b/sfeDataLoggerIoT/sfeDataLoggerAbout.cpp index 53710a6..75fdb42 100644 --- a/sfeDataLoggerIoT/sfeDataLoggerAbout.cpp +++ b/sfeDataLoggerIoT/sfeDataLoggerAbout.cpp @@ -1,7 +1,7 @@ /* *--------------------------------------------------------------------------------- * - * Copyright (c) 2022-2024, SparkFun Electronics Inc. + * Copyright (c) 2022-2025, SparkFun Electronics Inc. * * SPDX-License-Identifier: MIT * @@ -98,7 +98,6 @@ void sfeDataLogger::displayAppStatus(bool useInfo) char szSize[32]; char szCap[32]; char szAvail[32]; - flx_utils::formatByteString(_theSDCard.size(), 2, szSize, sizeof(szSize)); flx_utils::formatByteString(_theSDCard.total(), 2, szCap, sizeof(szCap)); flx_utils::formatByteString(_theSDCard.total() - _theSDCard.used(), 2, szAvail, sizeof(szAvail)); @@ -176,6 +175,48 @@ void sfeDataLogger::displayAppStatus(bool useInfo) _theOutputFile.currentFilename().length() == 0 ? "" : _theOutputFile.currentFilename().c_str()); flxLog_N("%c Rotate Period: %d Hours", pre_ch, _theOutputFile.rotatePeriod()); + bool bEnabled = _extIntrEvent.isEnabled(); + flxLog__(logLevel, "%cInterrupt Log Trigger: %s", pre_ch, bEnabled ? "Enabled" : "Disabled"); + if (bEnabled) + { + flxLog__(logLevel, "%c Pin: %d", pre_ch, _extIntrEvent.intrPin()); + flxLog__(logLevel, "%c Event: %s", pre_ch, _extIntrEvent.eventName().c_str()); + } + flxLog_N(""); + if (!useInfo) + { + flxSerial.textToWhite(); + flxLog_N(" GPIO:"); + flxSerial.textToNormal(); + } + bEnabled = _extSerial.serialDeviceEnabled(); + flxLog__(logLevel, "%cSerial Device Logging: %s", pre_ch, bEnabled ? "Enabled" : "Disabled"); + if (bEnabled) + { + flxLog__(logLevel, "%c RX Pin: %d", pre_ch, _extSerial.rxPin()); + flxLog__(logLevel, "%c TX Pin: %d", pre_ch, _extSerial.txPin()); + flxLog__(logLevel, "%c Baud Rate: %d", pre_ch, _extSerial.serialBaudRate()); + } + bEnabled = _soilMoistureEnable.isEnabled(); + flxLog__(logLevel, "%cSoil Moisture Device: %s", pre_ch, bEnabled ? "Enabled" : "Disabled"); + if (bEnabled) + { + auto soilDevices = flux.get(); + if (soilDevices->size() > 0) + { + flxDevSoilMoisture *pSoil = soilDevices->at(0); + flxLog__(logLevel, "%c VCC Pin: %d", pre_ch, pSoil->vccPin()); + flxLog__(logLevel, "%c Sensor Pin: %d", pre_ch, pSoil->sensorPin()); + } + } + bEnabled = _analogPinEnable.isEnabled(); + flxLog__(logLevel, "%cAnalog Pin Sensor: %s", pre_ch, bEnabled ? "Enabled" : "Disabled"); + if (bEnabled) + { + auto analogDevices = flux.get(); + if (analogDevices->size() > 0) + flxLog__(logLevel, "%c Pin: %d", pre_ch, analogDevices->at(0)->sensorPin()); + } flxLog_N(""); if (!useInfo) { @@ -228,8 +269,10 @@ void sfeDataLogger::displayAppStatus(bool useInfo) flxLog_N_(F("%c %-20s - %-40s {"), pre_ch, device->name(), device->description()); if (device->getKind() == flxDeviceKindI2C) flxLog_N("%s x%x}", "qwiic", device->address()); - else + else if (device->getKind() == flxDeviceKindSPI) flxLog_N("%s p%u}", "SPI", device->address()); + else if (device->getKind() == flxDeviceKindGPIO) + flxLog_N("%s p%u}", "GPIO", device->address()); } flxLog_N(""); diff --git a/sfeDataLoggerIoT/sfeDataLoggerProps.cpp b/sfeDataLoggerIoT/sfeDataLoggerProps.cpp index b7dec12..c39eeaa 100644 --- a/sfeDataLoggerIoT/sfeDataLoggerProps.cpp +++ b/sfeDataLoggerIoT/sfeDataLoggerProps.cpp @@ -167,7 +167,7 @@ void sfeDataLogger::set_termBaudRate(uint32_t newRate) } } //--------------------------------------------------------------------------- -void sfeDataLogger::getStartupProperties(uint &baudRate, uint &startupDelay) +void sfeDataLogger::getStartupProperties(uint32_t &baudRate, uint32_t &startupDelay) { // Do we have this block in storage? And yes, a little hacky with name :) flxStorageBlock *stBlk = _sysStorage.getBlock(((flxObject *)this)->name()); @@ -249,3 +249,29 @@ void sfeDataLogger::set_logsysinfo(bool bEnableSysLog) else _logger.remove(_pSystemInfo); } +//--------------------------------------------------------------------------- +// verbose messages +//--------------------------------------------------------------------------- +void sfeDataLogger::set_verbose(bool enable) +{ + + // If disable, but we are in startup mode that enables verbose, don't set disable + if (enable) + { + + flxSetLoggingVerbose(); + + // if in startup, the verbose mode is being set via pref restore. Note the change to user + if (inOpMode(kDataLoggerOpStartup)) + { + flxLog_N(""); + flxLog_V(F("Verbose output enabled")); + } + } + else if (!inOpMode(kAppOpStartVerboseOutput)) + flxSetLoggingInfo(); +} +bool sfeDataLogger::get_verbose(void) +{ + return flxIsLoggingVerbose(); +} \ No newline at end of file diff --git a/sfeDataLoggerIoT/sfeDataLoggerSetup.cpp b/sfeDataLoggerIoT/sfeDataLoggerSetup.cpp index 6776ad9..78c7604 100644 --- a/sfeDataLoggerIoT/sfeDataLoggerSetup.cpp +++ b/sfeDataLoggerIoT/sfeDataLoggerSetup.cpp @@ -13,6 +13,7 @@ * SparkFun Data Logger - setup methods * */ +#include "sfeDLBoard.h" #include "sfeDataLogger.h" #include @@ -20,6 +21,7 @@ #include #include #include +#include // Biometric Hub -- requires pins to be set on startup static const uint8_t kAppBioHubReset = 17; // Use the TXD pin as the bio hub reset pin @@ -63,18 +65,23 @@ bool sfeDataLogger::setupSDCard(void) bool sfeDataLogger::setupIoTClients() { + _iotEndpoints.setTitle("Services"); + _iotEndpoints.setName("IoT Services", "IoT Service Connection Drivers"); // Add title for this section _mqttClient.setTitle("IoT Services"); // setup the network connection for the mqtt _mqttClient.setNetwork(&_wifiConnection); // add mqtt to JSON _fmtJSON.add(_mqttClient); + _iotEndpoints.push_back(_mqttClient); // setup the network connection for the mqtt _mqttSecureClient.setNetwork(&_wifiConnection); // add mqtt to JSON _fmtJSON.add(_mqttSecureClient); + _iotEndpoints.push_back(_mqttSecureClient); + // AWS _iotAWS.setName("AWS IoT", "Connect to an AWS Iot Thing"); _iotAWS.setNetwork(&_wifiConnection); @@ -83,6 +90,8 @@ bool sfeDataLogger::setupIoTClients() _iotAWS.setFileSystem(&_theSDCard); _fmtJSON.add(_iotAWS); + _iotEndpoints.push_back(_iotAWS); + // Thingspeak driver _iotThingSpeak.setNetwork(&_wifiConnection); @@ -90,6 +99,9 @@ bool sfeDataLogger::setupIoTClients() _iotThingSpeak.setFileSystem(&_theSDCard); _fmtJSON.add(_iotThingSpeak); + // Add the ThingSpeak driver to the flux system + _iotEndpoints.push_back(_iotThingSpeak); + // Azure IoT _iotAzure.setNetwork(&_wifiConnection); @@ -97,20 +109,30 @@ bool sfeDataLogger::setupIoTClients() _iotAzure.setFileSystem(&_theSDCard); _fmtJSON.add(_iotAzure); + // Add the Azure IoT driver to the flux system + _iotEndpoints.push_back(_iotAzure); + // general HTTP / URL logger _iotHTTP.setNetwork(&_wifiConnection); _iotHTTP.setFileSystem(&_theSDCard); _fmtJSON.add(_iotHTTP); + // Add the HTTP driver to the flux system + _iotEndpoints.push_back(_iotHTTP); // Machine Chat _iotMachineChat.setNetwork(&_wifiConnection); _iotMachineChat.setFileSystem(&_theSDCard); _fmtJSON.add(_iotMachineChat); + // Add the Machine Chat driver to the flux system + _iotEndpoints.push_back(_iotMachineChat); + // Arduino IoT _iotArduinoIoT.setNetwork(&_wifiConnection); _fmtJSON.add(_iotArduinoIoT); + // Add the Arduino IoT driver to the flux system + _iotEndpoints.push_back(_iotArduinoIoT); // Web server _iotWebServer.setTitle("Preview"); _iotWebServer.setNetwork(&_wifiConnection); @@ -227,4 +249,44 @@ void sfeDataLogger::setupENS160(void) flxLog_I(F("%s: compensation values applied from %s"), pENS160->name(), pSHTC3->name()); return; } -} \ No newline at end of file +} + +//--------------------------------------------------------------------------- +void sfeDataLogger::setupGNSS(void) +{ + // do we have one attached? + auto gnssDevices = flux.get(); + if (gnssDevices->size() == 0) + return; + + // get the first GNSS device and set the PPS Pin that can be used + flxDevGNSS *pGNSS = gnssDevices->at(0); + if (!pGNSS) + return; + + // set the in we use for PPS -- expect the input to be wired to this + pGNSS->setAvailablePPSPins(kDLBoardGNSSPPSPins, sizeof(kDLBoardGNSSPPSPins) / sizeof(kDLBoardGNSSPPSPins[0])); + + // map the GNSS PPS event to the log observation event + flxAddEventAliasWithValue(flxEvent::kOnGNSSPPSEvent, flxEvent::kOnLogObservationWithSource, "PPS"); +} + +//--------------------------------------------------------------------------- +void sfeDataLogger::setupExtSerial(void) +{ + // setup the default pins + _extSerial.rxPin(kDLBoardExtSerialRXPin); + _extSerial.txPin(kDLBoardExtSerialTXPin); + + // map the data available event to the log observation event + flxAddEventAliasWithValue(flxEvent::kOnSerialDataAvailable, flxEvent::kOnLogObservationWithSource, "SERIAL"); +} +//--------------------------------------------------------------------------- +void sfeDataLogger::setInterruptEvent(void) +{ + _extIntrEvent.setDescription("Trigger a logging event from an interrupt"); + _extIntrEvent.setAvailablePins(kDLBoardInterruptPins, + sizeof(kDLBoardInterruptPins) / sizeof(kDLBoardInterruptPins[0])); + + _extIntrEvent.setEventToSend(flxEvent::kOnLogObservationWithSource); +}