diff --git a/src/configuration.h b/src/configuration.h
index 15912be3f..2e81557b1 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -148,6 +148,7 @@ along with this program. If not, see .
#define NAU7802_ADDR 0x2A
#define MAX30102_ADDR 0x57
#define MLX90614_ADDR_DEF 0x5A
+#define CGRADSENS_ADDR 0x66
// -----------------------------------------------------------------------------
// ACCELEROMETER
diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h
index 8591b8433..f4516458b 100644
--- a/src/detect/ScanI2C.h
+++ b/src/detect/ScanI2C.h
@@ -63,7 +63,8 @@ class ScanI2C
ICM20948,
MAX30102,
TPS65233,
- MPR121KB
+ MPR121KB,
+ CGRADSENS
} DeviceType;
// typedef uint8_t DeviceAddress;
diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp
index 2413c44c9..55f13c5a0 100644
--- a/src/detect/ScanI2CTwoWire.cpp
+++ b/src/detect/ScanI2CTwoWire.cpp
@@ -479,6 +479,16 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
}
break;
+ case CGRADSENS_ADDR:
+ // Register 0x00 of the RadSens sensor contains is product identifier 0x7D
+ registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1);
+ if (registerValue == 0x7D) {
+ type = CGRADSENS;
+ LOG_INFO("ClimateGuard RadSens Geiger-Muller Sensor found");
+ break;
+ }
+ break;
+
default:
LOG_INFO("Device found at address 0x%x was not able to be enumerated", addr.address);
}
diff --git a/src/main.cpp b/src/main.cpp
index 97a64a378..df18dae98 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -614,6 +614,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948)
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102)
+ SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS)
i2cScanner.reset();
#endif
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index 4ef68d4b7..92d964f7d 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -25,6 +25,7 @@
#include "Sensor/BMP085Sensor.h"
#include "Sensor/BMP280Sensor.h"
#include "Sensor/BMP3XXSensor.h"
+#include "Sensor/CGRadSensSensor.h"
#include "Sensor/DFRobotLarkSensor.h"
#include "Sensor/LPS22HBSensor.h"
#include "Sensor/MCP9808Sensor.h"
@@ -60,6 +61,7 @@ BMP3XXSensor bmp3xxSensor;
#ifdef T1000X_SENSOR_EN
T1000xSensor t1000xSensor;
#endif
+CGRadSensSensor cgRadSens;
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
@@ -147,6 +149,8 @@ int32_t EnvironmentTelemetryModule::runOnce()
result = nau7802Sensor.runOnce();
if (max17048Sensor.hasSensor())
result = max17048Sensor.runOnce();
+ if (cgRadSens.hasSensor())
+ result = cgRadSens.runOnce();
#endif
}
return result;
@@ -210,16 +214,19 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
// Display "Env. From: ..." on its own
display->drawString(x, y, "Env. From: " + String(lastSender) + "(" + String(agoSecs) + "s)");
- String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C";
- if (moduleConfig.telemetry.environment_display_fahrenheit) {
- last_temp =
- String(UnitConversions::CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F";
- }
+ if (lastMeasurement.variant.environment_metrics.has_temperature ||
+ lastMeasurement.variant.environment_metrics.has_relative_humidity) {
+ String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C";
+ if (moduleConfig.telemetry.environment_display_fahrenheit) {
+ last_temp =
+ String(UnitConversions::CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F";
+ }
- // Continue with the remaining details
- display->drawString(x, y += _fontHeight(FONT_SMALL),
- "Temp/Hum: " + last_temp + " / " +
- String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%");
+ // Continue with the remaining details
+ display->drawString(x, y += _fontHeight(FONT_SMALL),
+ "Temp/Hum: " + last_temp + " / " +
+ String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%");
+ }
if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) {
display->drawString(x, y += _fontHeight(FONT_SMALL),
@@ -243,6 +250,10 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
if (lastMeasurement.variant.environment_metrics.weight != 0)
display->drawString(x, y += _fontHeight(FONT_SMALL),
"Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg");
+
+ if (lastMeasurement.variant.environment_metrics.radiation != 0)
+ display->drawString(x, y += _fontHeight(FONT_SMALL),
+ "Rad: " + String(lastMeasurement.variant.environment_metrics.radiation, 2) + "µR/h");
}
bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t)
@@ -263,6 +274,8 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction,
t->variant.environment_metrics.weight);
+ LOG_INFO("(Received from %s): radiation=%fµR/h", sender, t->variant.environment_metrics.radiation);
+
#endif
// release previous packet before occupying a new spot
if (lastMeasurementPacket != nullptr)
@@ -390,6 +403,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
valid = valid && max17048Sensor.getMetrics(m);
hasSensor = true;
}
+ if (cgRadSens.hasSensor()) {
+ valid = valid && cgRadSens.getMetrics(m);
+ hasSensor = true;
+ }
#endif
return valid && hasSensor;
@@ -443,6 +460,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
LOG_INFO("Send: wind speed=%fm/s, direction=%d degrees, weight=%fkg", m.variant.environment_metrics.wind_speed,
m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight);
+ LOG_INFO("Send: radiation=%fµR/h", m.variant.environment_metrics.radiation);
+
sensor_read_error_count = 0;
meshtastic_MeshPacket *p = allocDataProtobuf(m);
@@ -585,6 +604,11 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule
if (result != AdminMessageHandleResult::NOT_HANDLED)
return result;
}
+ if (cgRadSens.hasSensor()) {
+ result = cgRadSens.handleAdminMessage(mp, request, response);
+ if (result != AdminMessageHandleResult::NOT_HANDLED)
+ return result;
+ }
return result;
}
diff --git a/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp
new file mode 100644
index 000000000..5e69cc22f
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp
@@ -0,0 +1,75 @@
+/*
+ * Support for the ClimateGuard RadSens Dosimeter
+ * A fun and educational sensor for Meshtastic; not for safety critical applications.
+ */
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "CGRadSensSensor.h"
+#include "TelemetrySensor.h"
+#include
+#include
+
+CGRadSensSensor::CGRadSensSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RADSENS, "RadSens") {}
+
+int32_t CGRadSensSensor::runOnce()
+{
+ // Initialize the sensor following the same pattern as RCWL9620Sensor
+ LOG_INFO("Init sensor: %s", sensorName);
+ if (!hasSensor()) {
+ return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
+ }
+
+ status = true;
+ begin(nodeTelemetrySensorsMap[sensorType].second, nodeTelemetrySensorsMap[sensorType].first);
+
+ return initI2CSensor();
+}
+
+void CGRadSensSensor::setup() {}
+
+void CGRadSensSensor::begin(TwoWire *wire, uint8_t addr)
+{
+ // Store the Wire and address to the sensor following the same pattern as RCWL9620Sensor
+ _wire = wire;
+ _addr = addr;
+ _wire->begin();
+}
+
+float CGRadSensSensor::getStaticRadiation()
+{
+ // Read a register, following the same pattern as the RCWL9620Sensor
+ uint32_t data;
+ _wire->beginTransmission(_addr); // Transfer data to addr.
+ _wire->write(0x06); // Radiation intensity (static period T = 500 sec)
+ if (_wire->endTransmission() == 0) {
+ if (_wire->requestFrom(_addr, (uint8_t)3)) {
+ ; // Request 3 bytes
+ data = _wire->read();
+ data <<= 8;
+ data |= _wire->read();
+ data <<= 8;
+ data |= _wire->read();
+
+ // As per the data sheet for the RadSens
+ // Register 0x06 contains the reading in 0.1 * μR / h
+ float microRadPerHr = float(data) / 10.0;
+ return microRadPerHr;
+ }
+ }
+ return -1.0;
+}
+
+bool CGRadSensSensor::getMetrics(meshtastic_Telemetry *measurement)
+{
+ // Store the meansurement in the the appropriate fields of the protobuf
+ measurement->variant.environment_metrics.has_radiation = true;
+
+ LOG_DEBUG("CGRADSENS getMetrics");
+ measurement->variant.environment_metrics.radiation = getStaticRadiation();
+
+ return true;
+}
+#endif
\ No newline at end of file
diff --git a/src/modules/Telemetry/Sensor/CGRadSensSensor.h b/src/modules/Telemetry/Sensor/CGRadSensSensor.h
new file mode 100644
index 000000000..3b15a19a2
--- /dev/null
+++ b/src/modules/Telemetry/Sensor/CGRadSensSensor.h
@@ -0,0 +1,30 @@
+/*
+ * Support for the ClimateGuard RadSens Dosimeter
+ * A fun and educational sensor for Meshtastic; not for safety critical applications.
+ */
+#include "configuration.h"
+
+#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
+
+#include "../mesh/generated/meshtastic/telemetry.pb.h"
+#include "TelemetrySensor.h"
+#include
+
+class CGRadSensSensor : public TelemetrySensor
+{
+ private:
+ uint8_t _addr = 0x66;
+ TwoWire *_wire = &Wire;
+
+ protected:
+ virtual void setup() override;
+ void begin(TwoWire *wire = &Wire, uint8_t addr = 0x66);
+ float getStaticRadiation();
+
+ public:
+ CGRadSensSensor();
+ virtual int32_t runOnce() override;
+ virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/serialization/MeshPacketSerializer.cpp b/src/serialization/MeshPacketSerializer.cpp
index 05a98f7a6..b4603186b 100644
--- a/src/serialization/MeshPacketSerializer.cpp
+++ b/src/serialization/MeshPacketSerializer.cpp
@@ -78,6 +78,7 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp,
msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction);
msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust);
msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull);
+ msgPayload["radiation"] = new JSONValue(decoded->variant.environment_metrics.radiation);
} else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) {
msgPayload["pm10"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm10_standard);
msgPayload["pm25"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm25_standard);
diff --git a/src/serialization/MeshPacketSerializer_nRF52.cpp b/src/serialization/MeshPacketSerializer_nRF52.cpp
index 15b8b1a34..89ecddfad 100644
--- a/src/serialization/MeshPacketSerializer_nRF52.cpp
+++ b/src/serialization/MeshPacketSerializer_nRF52.cpp
@@ -77,6 +77,7 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp,
jsonObj["payload"]["wind_direction"] = (uint)decoded->variant.environment_metrics.wind_direction;
jsonObj["payload"]["wind_gust"] = decoded->variant.environment_metrics.wind_gust;
jsonObj["payload"]["wind_lull"] = decoded->variant.environment_metrics.wind_lull;
+ jsonObj["payload"]["radiation"] = decoded->variant.environment_metrics.radiation;
} else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) {
jsonObj["payload"]["pm10"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_standard;
jsonObj["payload"]["pm25"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_standard;