From 0c41f90ef5ed3485f5155781e9876d0e9e63f2ca Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Fri, 7 Mar 2025 20:22:52 +0800 Subject: [PATCH] [WIP] Add RAK12035VB Soil Moisture Sensor support Introduce the RAK12035 sensor as an environmental telemetry sensor, including necessary calibration checks and default values. Update relevant files to integrate the sensor into the existing telemetry system. This hardware is not just one module, but a couple.. RAK12023 and RAK12035 is the component stack, the RAK12023 does not seem to matter much and allows for multiple RAK12035 devices to be used. Co-Authored-By: @Justin-Mann --- src/configuration.h | 9 ++ src/detect/ScanI2C.h | 1 + src/detect/ScanI2CTwoWire.cpp | 14 ++- src/main.cpp | 1 + .../Telemetry/EnvironmentTelemetry.cpp | 30 ++++- .../Telemetry/Sensor/RAK12035Sensor.cpp | 118 ++++++++++++++++++ src/modules/Telemetry/Sensor/RAK12035Sensor.h | 29 +++++ variants/rak4631/platformio.ini | 3 +- variants/rak4631/variant.h | 5 +- variants/rak4631_epaper/platformio.ini | 1 + variants/rak4631_epaper/variant.h | 5 +- variants/rak4631_epaper_onrxtx/platformio.ini | 1 + variants/rak4631_epaper_onrxtx/variant.h | 7 +- variants/rak4631_eth_gw/variant.h | 5 +- variants/rak_wismeshtap/platformio.ini | 1 + variants/rak_wismeshtap/variant.h | 4 +- 16 files changed, 225 insertions(+), 9 deletions(-) create mode 100644 src/modules/Telemetry/Sensor/RAK12035Sensor.cpp create mode 100644 src/modules/Telemetry/Sensor/RAK12035Sensor.h diff --git a/src/configuration.h b/src/configuration.h index fd4a5b196..3a0a2ac6e 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -186,6 +186,15 @@ along with this program. If not, see . // ----------------------------------------------------------------------------- #define FT6336U_ADDR 0x48 +// ----------------------------------------------------------------------------- +// RAK12035VB Soil Monitor (using RAK12023 up to 3 RAK12035 monitors can be connected) +// - the default i2c address for this sensor is 0x20, and users are instructed to +// set 0x21 and 0x22 for the second and third sensor if present. +// ----------------------------------------------------------------------------- +#define RAK120351_ADDR 0x20 +#define RAK120352_ADDR 0x21 +#define RAK120353_ADDR 0x22 + // ----------------------------------------------------------------------------- // BIAS-T Generator // ----------------------------------------------------------------------------- diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 5b6bbe629..8f6f5e7c2 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -69,6 +69,7 @@ class ScanI2C DFROBOT_RAIN, DPS310, LTR390UV, + RAK12035, } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 8b779277d..d28d0f687 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -417,9 +417,21 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) logFoundDevice("BMA423", (uint8_t)addr.address); } break; + case TCA9535_ADDR: + case RAK120352_ADDR: + case RAK120353_ADDR: + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x02), 1); + if (registerValue == addr.address) { // RAK12035 returns its I2C address at 0x02 (eg 0x20) + type = RAK12035; + logFoundDevice("RAK12035", (uint8_t)addr.address); + } else { + type = TCA9535; + logFoundDevice("TCA9535", (uint8_t)addr.address); + } + + break; SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address); - SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535", (uint8_t)addr.address); SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address); SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address); SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address); diff --git a/src/main.cpp b/src/main.cpp index 4634c7c14..59d76c4c7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -643,6 +643,7 @@ void setup() scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_RAIN, meshtastic_TelemetrySensorType_DFROBOT_RAIN); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LTR390UV, meshtastic_TelemetrySensorType_LTR390UV); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DPS310, meshtastic_TelemetrySensorType_DPS310); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RAK12035, meshtastic_TelemetrySensorType_RAK12035); i2cScanner.reset(); #endif diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 8835c985d..adbe65c67 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -41,6 +41,9 @@ #include "Sensor/SHTC3Sensor.h" #include "Sensor/TSL2591Sensor.h" #include "Sensor/VEML7700Sensor.h" +#ifdef RAK4630 +#include "Sensor/RAK12035Sensor.h" +#endif BMP085Sensor bmp085Sensor; BMP280Sensor bmp280Sensor; @@ -63,6 +66,9 @@ DFRobotGravitySensor dfRobotGravitySensor; NAU7802Sensor nau7802Sensor; BMP3XXSensor bmp3xxSensor; CGRadSensSensor cgRadSens; +#ifdef RAK4630 +RAK12035Sensor rak12035Sensor; +#endif #endif #ifdef T1000X_SENSOR_EN #include "Sensor/T1000xSensor.h" @@ -72,6 +78,7 @@ T1000xSensor t1000xSensor; #include "Sensor/IndicatorSensor.h" IndicatorSensor indicatorSensor; #endif + #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true @@ -171,6 +178,11 @@ int32_t EnvironmentTelemetryModule::runOnce() result = rak9154Sensor.runOnce(); #endif +#ifdef RAK4630 + if (rak12035Sensor.hasSensor()) { + result = rak12035Sensor.runOnce(); + } +#endif #endif } // it's possible to have this module enabled, only for displaying values on the screen. @@ -498,6 +510,12 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m valid = valid && rak9154Sensor.getMetrics(m); hasSensor = true; #endif +#ifdef RAK4630 + if (rak12035Sensor.hasSensor()) { + valid = valid && rak12035Sensor.getMetrics(m); + hasSensor = true; + } +#endif #endif return valid && hasSensor; } @@ -552,6 +570,9 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) LOG_INFO("Send: radiation=%fµR/h", m.variant.environment_metrics.radiation); + LOG_INFO("Send: soil_temperature=%f, soil_moisture=%u", m.variant.environment_metrics.soil_temperature, + m.variant.environment_metrics.soil_moisture); + sensor_read_error_count = 0; meshtastic_MeshPacket *p = allocDataProtobuf(m); @@ -710,8 +731,15 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } +#ifdef RAK4630 + if (rak12035Sensor.hasSensor()) { + result = rak12035Sensor.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } +#endif #endif return result; } -#endif \ No newline at end of file +#endif diff --git a/src/modules/Telemetry/Sensor/RAK12035Sensor.cpp b/src/modules/Telemetry/Sensor/RAK12035Sensor.cpp new file mode 100644 index 000000000..b31e34ee5 --- /dev/null +++ b/src/modules/Telemetry/Sensor/RAK12035Sensor.cpp @@ -0,0 +1,118 @@ +#include "configuration.h" +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(RAK4630) + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "RAK12035Sensor.h" + +RAK12035Sensor::RAK12035Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RAK12035, "RAK12035") {} + +int32_t RAK12035Sensor::runOnce() +{ + LOG_INFO("Init sensor: %s", sensorName); + if (!hasSensor()) { + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + + sensor.set_sensor_addr(RAK120351_ADDR); + + sensor.begin(nodeTelemetrySensorsMap[sensorType].first); + // Get sensor firmware version + uint8_t data = 0; + sensor.get_sensor_version(&data); + LOG_INFO("Sensor Firmware version: %i", data); + + if (data != 0) { + LOG_DEBUG("RAK12035Sensor Init Succeed"); + status = true; + } else { + LOG_ERROR("RAK12035Sensor Init Failed"); + status = false; + } + sensor.sensor_sleep(); + return initI2CSensor(); +} + +void RAK12035Sensor::setup() +{ + // Set the calibration values + // Reading the saved calibration values from the sensor. + uint16_t zero_val = 0; + uint16_t hundred_val = 0; + uint16_t default_zero_val = 550; + uint16_t default_hundred_val = 420; + sensor.sensor_on(); + delay(200); + sensor.get_dry_cal(&zero_val); + sensor.get_wet_cal(&hundred_val); + delay(200); + if (zero_val == 0 || zero_val <= hundred_val) { + LOG_ERROR("Dry calibration value is %d", zero_val); + LOG_ERROR("Wet calibration value is %d", hundred_val); + LOG_ERROR("This does not make sense. Youc can recalibrate this sensor using the calibration sketch included here: " + "https://github.com/RAKWireless/RAK12035_SoilMoisture."); + LOG_ERROR("For now, setting default calibration value for Dry Calibration: %d", default_zero_val); + sensor.set_dry_cal(default_zero_val); + sensor.get_dry_cal(&zero_val); + LOG_ERROR("Dry calibration reset complete. New value is %d", zero_val); + } + if (hundred_val == 0 || hundred_val >= zero_val) { + LOG_ERROR("Dry calibration value is %d", zero_val); + LOG_ERROR("Wet calibration value is %d", hundred_val); + LOG_ERROR("This does not make sense. Youc can recalibrate this sensor using the calibration sketch included here: " + "https://github.com/RAKWireless/RAK12035_SoilMoisture."); + LOG_ERROR("For now, setting default calibration value for Wet Calibration: %d", default_hundred_val); + sensor.set_wet_cal(default_hundred_val); + sensor.get_wet_cal(&hundred_val); + LOG_ERROR("Wet calibration reset complete. New value is %d", hundred_val); + } + sensor.sensor_sleep(); + delay(200); + LOG_INFO("Dry calibration value is %d", zero_val); + LOG_INFO("Wet calibration value is %d", hundred_val); +} + +bool RAK12035Sensor::getMetrics(meshtastic_Telemetry *measurement) +{ + measurement->variant.environment_metrics.has_soil_temperature = true; + measurement->variant.environment_metrics.has_soil_moisture = true; + + uint8_t moisture = 0; + uint16_t temp = 0; + bool success = false; + + sensor.sensor_on(); + delay(200); + success = sensor.get_sensor_moisture(&moisture); + delay(200); + success = sensor.get_sensor_temperature(&temp); + delay(200); + sensor.sensor_sleep(); + + if (success == false) { + LOG_ERROR("Failed to read sensor data"); + return false; + } + LOG_INFO("Successful read from sensor Temperature: %.2f, Moisture: %ld%", (double)(temp / 10), moisture); + measurement->variant.environment_metrics.soil_temperature = (float)(temp / 10); + measurement->variant.environment_metrics.soil_moisture = moisture; + + LOG_INFO("Check if the original temperature and moisture (relative_humidity) are being used.. if not just use them for the " + "soil monitoring."); + + if (!measurement->variant.environment_metrics.has_temperature) { + LOG_INFO("Overwrite the temp metrics (not being set right now and this will allow the soil temp value to be used in the " + "client interface)."); + measurement->variant.environment_metrics.has_temperature = true; + measurement->variant.environment_metrics.temperature = (float)(temp / 10); + } + + if (!measurement->variant.environment_metrics.has_relative_humidity) { + LOG_INFO("Overwrite the moisture metrics (not being used for air humidity and this will allow the soil humidity to " + "appear in the client interfaces without adjustments)."); + measurement->variant.environment_metrics.has_relative_humidity = true; + measurement->variant.environment_metrics.relative_humidity = (float)moisture; + } + + return true; +} +#endif diff --git a/src/modules/Telemetry/Sensor/RAK12035Sensor.h b/src/modules/Telemetry/Sensor/RAK12035Sensor.h new file mode 100644 index 000000000..77ffe24fa --- /dev/null +++ b/src/modules/Telemetry/Sensor/RAK12035Sensor.h @@ -0,0 +1,29 @@ +#pragma once + +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(RAK4630) +#ifndef _MT_RAK12035VBSENSOR_H +#define _MT_RAK12035VBSENSOR_H +#endif + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "RAK12035_SoilMoisture.h" +#include "TelemetrySensor.h" +#include + +class RAK12035Sensor : public TelemetrySensor +{ + private: + RAK12035 sensor; + + protected: + virtual void setup() override; + + public: + RAK12035Sensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; +}; + +#endif diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index ced93df66..4823ccdfa 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -20,6 +20,7 @@ lib_deps = https://github.com/RAKWireless/RAK13800-W5100S.git#1.0.2 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 https://github.com/RAKWireless/RAK12034-BMX160.git#dcead07ffa267d3c906e9ca4a1330ab989e957e2 + beegee-tokyo/RAK12035_SoilMoisture@^1.0.3 ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds @@ -52,4 +53,4 @@ lib_deps = upload_protocol = stlink ; eventually use platformio/tool-pyocd@^2.3600.0 instad ;upload_protocol = custom -;upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE \ No newline at end of file +;upload_command = pyocd flash -t nrf52840 $UPLOADERFLAGS $SOURCE diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h index bc5541336..c8a2f83ae 100644 --- a/variants/rak4631/variant.h +++ b/variants/rak4631/variant.h @@ -90,6 +90,8 @@ static const uint8_t A7 = PIN_A7; // Other pins #define PIN_AREF (2) #define PIN_NFC1 (9) +#define WB_IO5 PIN_NFC1 +#define WB_IO4 (4) #define PIN_NFC2 (10) static const uint8_t AREF = PIN_AREF; @@ -217,6 +219,7 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG // enables 3.3V periphery like GPS or IO Module // Do not toggle this for GPS power savings #define PIN_3V3_EN (34) +#define WB_IO2 PIN_3V3_EN // RAK1910 GPS module // If using the wisblock GPS module and pluged into Port A on WisBlock base @@ -270,4 +273,4 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif \ No newline at end of file +#endif diff --git a/variants/rak4631_epaper/platformio.ini b/variants/rak4631_epaper/platformio.ini index b851691ed..9fe7ac1c7 100644 --- a/variants/rak4631_epaper/platformio.ini +++ b/variants/rak4631_epaper/platformio.ini @@ -17,6 +17,7 @@ lib_deps = melopero/Melopero RV3028@^1.1.0 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 beegee-tokyo/RAKwireless RAK12034@^1.0.0 + beegee-tokyo/RAK12035_SoilMoisture@^1.0.3 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink diff --git a/variants/rak4631_epaper/variant.h b/variants/rak4631_epaper/variant.h index 0bb97498c..c1e11bee5 100644 --- a/variants/rak4631_epaper/variant.h +++ b/variants/rak4631_epaper/variant.h @@ -90,6 +90,8 @@ static const uint8_t A7 = PIN_A7; // Other pins #define PIN_AREF (2) #define PIN_NFC1 (9) +#define WB_IO5 PIN_NFC1 +#define WB_IO4 (4) #define PIN_NFC2 (10) static const uint8_t AREF = PIN_AREF; @@ -188,6 +190,7 @@ static const uint8_t SCK = PIN_SPI_SCK; // enables 3.3V periphery like GPS or IO Module #define PIN_3V3_EN (34) +#define WB_IO2 PIN_3V3_EN // RAK1910 GPS module // If using the wisblock GPS module and pluged into Port A on WisBlock base @@ -231,4 +234,4 @@ static const uint8_t SCK = PIN_SPI_SCK; * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif \ No newline at end of file +#endif diff --git a/variants/rak4631_epaper_onrxtx/platformio.ini b/variants/rak4631_epaper_onrxtx/platformio.ini index 8612a3f3d..c5300243d 100644 --- a/variants/rak4631_epaper_onrxtx/platformio.ini +++ b/variants/rak4631_epaper_onrxtx/platformio.ini @@ -19,6 +19,7 @@ lib_deps = melopero/Melopero RV3028@^1.1.0 rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2 beegee-tokyo/RAKwireless RAK12034@^1.0.0 + beegee-tokyo/RAK12035_SoilMoisture@^1.0.3 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink diff --git a/variants/rak4631_epaper_onrxtx/variant.h b/variants/rak4631_epaper_onrxtx/variant.h index 5888cff33..1f8257e8e 100644 --- a/variants/rak4631_epaper_onrxtx/variant.h +++ b/variants/rak4631_epaper_onrxtx/variant.h @@ -69,7 +69,9 @@ static const uint8_t A7 = PIN_A7; // Other pins #define PIN_AREF (2) -// #define PIN_NFC1 (9) +#define PIN_NFC1 (9) +#define WB_IO5 PIN_NFC1 +#define WB_IO4 (4) // #define PIN_NFC2 (10) static const uint8_t AREF = PIN_AREF; @@ -160,6 +162,7 @@ static const uint8_t SCK = PIN_SPI_SCK; // enables 3.3V periphery like GPS or IO Module #define PIN_3V3_EN (34) +#define WB_IO2 PIN_3V3_EN // NO GPS #undef GPS_RX_PIN @@ -202,4 +205,4 @@ static const uint8_t SCK = PIN_SPI_SCK; * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif \ No newline at end of file +#endif diff --git a/variants/rak4631_eth_gw/variant.h b/variants/rak4631_eth_gw/variant.h index bc5541336..c8a2f83ae 100644 --- a/variants/rak4631_eth_gw/variant.h +++ b/variants/rak4631_eth_gw/variant.h @@ -90,6 +90,8 @@ static const uint8_t A7 = PIN_A7; // Other pins #define PIN_AREF (2) #define PIN_NFC1 (9) +#define WB_IO5 PIN_NFC1 +#define WB_IO4 (4) #define PIN_NFC2 (10) static const uint8_t AREF = PIN_AREF; @@ -217,6 +219,7 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG // enables 3.3V periphery like GPS or IO Module // Do not toggle this for GPS power savings #define PIN_3V3_EN (34) +#define WB_IO2 PIN_3V3_EN // RAK1910 GPS module // If using the wisblock GPS module and pluged into Port A on WisBlock base @@ -270,4 +273,4 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif \ No newline at end of file +#endif diff --git a/variants/rak_wismeshtap/platformio.ini b/variants/rak_wismeshtap/platformio.ini index bcf46b90d..a40a27ae4 100644 --- a/variants/rak_wismeshtap/platformio.ini +++ b/variants/rak_wismeshtap/platformio.ini @@ -23,6 +23,7 @@ lib_deps = bodmer/TFT_eSPI beegee-tokyo/RAKwireless RAK12034@^1.0.0 beegee-tokyo/RAK14014-FT6336U @ 1.0.1 + beegee-tokyo/RAK12035_SoilMoisture@^1.0.3 debug_tool = jlink ; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm) ;upload_protocol = jlink diff --git a/variants/rak_wismeshtap/variant.h b/variants/rak_wismeshtap/variant.h index c21a11ac1..3006189cf 100644 --- a/variants/rak_wismeshtap/variant.h +++ b/variants/rak_wismeshtap/variant.h @@ -90,6 +90,8 @@ static const uint8_t A7 = PIN_A7; // Other pins #define PIN_AREF (2) #define PIN_NFC1 (9) +#define WB_IO5 PIN_NFC1 +#define WB_IO4 (4) #define PIN_NFC2 (10) static const uint8_t AREF = PIN_AREF; @@ -311,4 +313,4 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG * Arduino objects - C++ only *----------------------------------------------------------------------------*/ -#endif \ No newline at end of file +#endif