Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for the ClimateGuard RadSens Geiger-Muller tube #5425

Merged
merged 10 commits into from
Nov 24, 2024
1 change: 1 addition & 0 deletions src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define NAU7802_ADDR 0x2A
#define MAX30102_ADDR 0x57
#define MLX90614_ADDR_DEF 0x5A
#define CGRADSENS_ADDR 0x66

// -----------------------------------------------------------------------------
// ACCELEROMETER
Expand Down
3 changes: 2 additions & 1 deletion src/detect/ScanI2C.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ class ScanI2C
ICM20948,
MAX30102,
TPS65233,
MPR121KB
MPR121KB,
CGRADSENS
} DeviceType;

// typedef uint8_t DeviceAddress;
Expand Down
10 changes: 10 additions & 0 deletions src/detect/ScanI2CTwoWire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 33 additions & 9 deletions src/modules/Telemetry/EnvironmentTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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),
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down
75 changes: 75 additions & 0 deletions src/modules/Telemetry/Sensor/CGRadSensSensor.cpp
Original file line number Diff line number Diff line change
@@ -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 <Wire.h>
#include <typeinfo>

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
30 changes: 30 additions & 0 deletions src/modules/Telemetry/Sensor/CGRadSensSensor.h
Original file line number Diff line number Diff line change
@@ -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 <Wire.h>

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
1 change: 1 addition & 0 deletions src/serialization/MeshPacketSerializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/serialization/MeshPacketSerializer_nRF52.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down