Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 61 additions & 7 deletions multigeiger/ble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ static NimBLEServer *bleServer;
#define BLE_CHAR_HR_MEASUREMENT BLEUUID((uint16_t)0x2A37) // 16 bit UUID of Heart Rate Measurement Characteristic
#define BLE_CHAR_HR_POSITION BLEUUID((uint16_t)0x2A38) // 16 bit UUID of Heart Rate Sensor Position Characteristic
#define BLE_CHAR_HR_CONTROLPOINT BLEUUID((uint16_t)0x2A39) // 16 bit UUID of Heart Rate Control Point Characteristic

#define BLE_SERVICE_ENVIRONMENTAL BLEUUID((uint16_t)0x181A) // 16 bit UUID of EnvironmentaL Service
#define BLE_CHAR_ENV_TEMPERATURE BLEUUID((uint16_t)0x2A6E) // 16 bit UUID of EnvironmentaL Temperature Characteristic (yields 16 bit little endian, 0.01 degC)
#define BLE_CHAR_ENV_HUMIDITY BLEUUID((uint16_t)0x2A6F) // 16 bit UUID of EnvironmentaL Humidity Characteristic (yields 16 bit little endian, 0.01 %)
#define BLE_CHAR_ENV_PRESSURE BLEUUID((uint16_t)0x2A6D) // 16 bit UUID of EnvironmentaL Air Pressure Characteristic (yields 32 bit little endian, 0.1 Pa)
#define BLE_CHAR_ENV_IAQ BLEUUID(0x422302f1, 0x2342, 0x2342, 0x2342234223422342) // 128 bit UUID of Environmental Indoor Air Quality (yields 16 bit little endian IAQ)
// Characteristic for IAQ from 2019 Chaos Communication Camp card10 https://firmware.card10.badge.events.ccc.de/bluetooth/ess.html

#define BLE_DESCR_UUID BLEUUID((uint16_t)0x2901) // 16 bit UUID of BLE Descriptor

static bool ble_enabled = false;
Expand Down Expand Up @@ -57,7 +65,7 @@ class MyCharacteristicCallbacks: public NimBLECharacteristicCallbacks {
}
};

void update_bledata(unsigned int cpm) {
void update_bledata(unsigned int cpm, float temperature, float humidity, float pressure, int iaq) {
if (!ble_enabled)
return;
cpm_update_counter++;
Expand All @@ -81,7 +89,34 @@ void update_bledata(unsigned int cpm) {
bleChr->notify();
}
}
NimBLEService *bleEnvSvc = bleServer->getServiceByUUID(BLE_SERVICE_ENVIRONMENTAL);
if (bleEnvSvc) {
uint8_t txBufferEnv[4];
NimBLECharacteristic *bleEnvTChr = bleEnvSvc->getCharacteristic(BLE_CHAR_ENV_TEMPERATURE);
if (bleEnvTChr) {
bleEnvTChr->setValue<int>(int(temperature * 100));
bleEnvTChr->notify();
}
NimBLECharacteristic *bleEnvHChr = bleEnvSvc->getCharacteristic(BLE_CHAR_ENV_HUMIDITY);
if (bleEnvHChr) {
bleEnvHChr->setValue<int>(int(humidity * 100));
bleEnvHChr->notify();
}
NimBLECharacteristic *bleEnvPChr = bleEnvSvc->getCharacteristic(BLE_CHAR_ENV_PRESSURE);
if (bleEnvPChr) {
bleEnvPChr->setValue<int>(int(pressure * 10));
bleEnvPChr->notify();
}
NimBLECharacteristic *bleEnvIAQChr = bleEnvSvc->getCharacteristic(BLE_CHAR_ENV_IAQ);
if (bleEnvIAQChr) {
txBufferEnv[0] = iaq & 0xFF;
txBufferEnv[1] = (iaq >> 8) & 0xFF;
bleEnvIAQChr->setValue(txBufferEnv, 2);
Comment on lines +112 to +114
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't one use setValue<int> here also?

bleEnvIAQChr->notify();
}
}
}

}

void setup_ble(char *device_name, bool ble_on) {
Expand All @@ -98,29 +133,48 @@ void setup_ble(char *device_name, bool ble_on) {
bleServer = NimBLEDevice::createServer();
bleServer->setCallbacks(new MyServerCallbacks());

NimBLEService *bleService = bleServer->createService(BLE_SERVICE_HEART_RATE);
// Heart Rate Service for CPM
NimBLEService *bleHRService = bleServer->createService(BLE_SERVICE_HEART_RATE);

NimBLECharacteristic *bleCharHRM = bleService->createCharacteristic(BLE_CHAR_HR_MEASUREMENT, NIMBLE_PROPERTY::NOTIFY);
NimBLECharacteristic *bleCharHRM = bleHRService->createCharacteristic(BLE_CHAR_HR_MEASUREMENT, NIMBLE_PROPERTY::NOTIFY);
NimBLEDescriptor *bleDescriptorHRM = bleCharHRM->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 20);
bleDescriptorHRM->setValue("Radiation rate CPM");
// bleCharHRM.addDescriptor(new BLE2902()); // required for notification management of the service; automatically added by NimBLE lib

NimBLECharacteristic *bleCharHRCP = bleService->createCharacteristic(BLE_CHAR_HR_CONTROLPOINT, NIMBLE_PROPERTY::WRITE);
NimBLECharacteristic *bleCharHRCP = bleHRService->createCharacteristic(BLE_CHAR_HR_CONTROLPOINT, NIMBLE_PROPERTY::WRITE);
NimBLEDescriptor *bleDescriptorHRCP = bleCharHRCP->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 50);
bleDescriptorHRCP->setValue("0x01 for Energy Exp. (packet counter) reset");
NimBLECharacteristic *bleCharHRPOS = bleService->createCharacteristic(BLE_CHAR_HR_POSITION, NIMBLE_PROPERTY::READ);
NimBLECharacteristic *bleCharHRPOS = bleHRService->createCharacteristic(BLE_CHAR_HR_POSITION, NIMBLE_PROPERTY::READ);
NimBLEDescriptor *bleDescriptorHRPOS = bleCharHRPOS->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 30);
bleDescriptorHRPOS->setValue("Geiger Mueller Tube Type");
bleCharHRCP->setCallbacks(new MyCharacteristicCallbacks());

bleCharHRPOS->setValue(txBuffer_HRPOS, 1);

// Environmental Service for temperature, humidity, air pressure, IAQ indoor air quality
NimBLEService *bleEnvService = bleServer->createService(BLE_SERVICE_ENVIRONMENTAL);

NimBLECharacteristic *bleCharEnvT = bleEnvService->createCharacteristic(BLE_CHAR_ENV_TEMPERATURE, NIMBLE_PROPERTY::NOTIFY);
NimBLEDescriptor *bleDescriptorEnvT = bleCharEnvT->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 30);
bleDescriptorEnvT->setValue("Temperature (.01 Celsius)");
NimBLECharacteristic *bleCharEnvH = bleEnvService->createCharacteristic(BLE_CHAR_ENV_HUMIDITY, NIMBLE_PROPERTY::NOTIFY);
NimBLEDescriptor *bleDescriptorEnvH = bleCharEnvH->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 30);
bleDescriptorEnvH->setValue("Rel. humidity (.01 %)");
NimBLECharacteristic *bleCharEnvP = bleEnvService->createCharacteristic(BLE_CHAR_ENV_PRESSURE, NIMBLE_PROPERTY::NOTIFY);
NimBLEDescriptor *bleDescriptorEnvP = bleCharEnvP->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 30);
bleDescriptorEnvP->setValue("Air pressure (.1 Pa)");
NimBLECharacteristic *bleCharEnvIAQ = bleEnvService->createCharacteristic(BLE_CHAR_ENV_IAQ, NIMBLE_PROPERTY::NOTIFY);
NimBLEDescriptor *bleDescriptorEnvIAQ = bleCharEnvIAQ->createDescriptor(BLE_DESCR_UUID, NIMBLE_PROPERTY::READ, 50);
bleDescriptorEnvIAQ->setValue("Indoor air quality (25 good .. 500 bad)");


bleServer->getAdvertising()->addServiceUUID(BLE_SERVICE_HEART_RATE);
bleServer->getAdvertising()->addServiceUUID(BLE_SERVICE_ENVIRONMENTAL);
bleServer->getAdvertising()->setScanResponse(true);
bleServer->getAdvertising()->setMinPreferred(0x06);
bleServer->getAdvertising()->setMinPreferred(0x12);

bleService->start();
bleHRService->start();
bleEnvService->start();
bleServer->getAdvertising()->start();

set_status(STATUS_BLE, ST_BLE_CONNECTABLE);
Expand Down
2 changes: 1 addition & 1 deletion multigeiger/ble.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#define _BLE_H_

void setup_ble(char *device_name, bool ble_enabled);
void update_bledata(unsigned int cpm);
void update_bledata(unsigned int cpm, float temperature, float humidity, float pressure, int iaq);
bool is_ble_connected(void);
void disable_ble(void);

Expand Down
14 changes: 7 additions & 7 deletions multigeiger/log_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
int Serial_Print_Mode;

static const char *Serial_Logging_Name = "Simple Multi-Geiger";
static const char *dashes = "------------------------------------------------------------------------------------------------------------------------";
static const char *dashes = "-----------------------------------------------------------------------------------------------------------------------------";

static const char *Serial_Logging_Header = " %10s %15s %10s %9s %9s %8s %9s %9s %9s %5s %5s %6s";
static const char *Serial_Logging_Body = "DATA %10d %15d %10f %9f %9d %8d %9d %9f %9f %5.1f %5.1f %6.0f";
static const char *Serial_Logging_Header = " %10s %15s %10s %9s %9s %8s %9s %9s %9s %5s %5s %6s %4s";
static const char *Serial_Logging_Body = "DATA %10d %15d %10f %9f %9d %8d %9d %9f %9f %5.1f %5.1f %6.0f %4d";
static const char *Serial_One_Minute_Log_Header = " %4s %10s %29s";
static const char *Serial_One_Minute_Log_Body = "DATA %4d %10d %29d";

Expand All @@ -28,19 +28,19 @@ void setup_log_data(int mode) {

void log_data(int GMC_counts, int time_difference, float Count_Rate, float Dose_Rate, int HV_pulse_count,
int accumulated_GMC_counts, int accumulated_time, float accumulated_Count_Rate, float accumulated_Dose_Rate,
float t, float h, float p) {
float t, float h, float p, int iaq) {
static int counter = 0;
if (counter++ % 20 == 0) { // output the header now and then, so table is better readable
log(INFO, Serial_Logging_Header,
"GMC_counts", "Time_difference", "Count_Rate", "Dose_Rate", "HV Pulses", "Accu_GMC", "Accu_Time", "Accu_Rate", "Accu_Dose", "Temp", "Humi", "Press");
"GMC_counts", "Time_difference", "Count_Rate", "Dose_Rate", "HV Pulses", "Accu_GMC", "Accu_Time", "Accu_Rate", "Accu_Dose", "Temp", "Humi", "Press", "IAQ");
log(INFO, Serial_Logging_Header,
"[Counts]", "[ms]", "[cps]", "[uSv/h]", "[-]", "[Counts]", "[ms]", "[cps]", "[uSv/h]", "[C]", "[%]", "[hPa]");
"[Counts]", "[ms]", "[cps]", "[uSv/h]", "[-]", "[Counts]", "[ms]", "[cps]", "[uSv/h]", "[C]", "[%]", "[hPa]", "[-]");
log(INFO, dashes);
}
log(INFO, Serial_Logging_Body,
GMC_counts, time_difference, Count_Rate, Dose_Rate, HV_pulse_count,
accumulated_GMC_counts, accumulated_time, accumulated_Count_Rate, accumulated_Dose_Rate,
t, h, p);
t, h, p, iaq);
}

void log_data_one_minute(int time_s, int cpm, int counts) {
Expand Down
2 changes: 1 addition & 1 deletion multigeiger/log_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extern int Serial_Print_Mode;
void setup_log_data(int mode);
void log_data(int GMC_counts, int time_difference, float Count_Rate, float Dose_Rate, int HV_pulse_count,
int accumulated_GMC_counts, int accumulated_time, float accumulated_Count_Rate, float accumulated_Dose_Rate,
float t, float h, float p);
float t, float h, float p, int iaq);
void log_data_one_minute(int time_s, int cpm, int counts);
void log_data_statistics(int count_time_between);

Expand Down
22 changes: 11 additions & 11 deletions multigeiger/multigeiger.ino
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ int update_ble_status(void) { // currently no error detection
}

void publish(unsigned long current_ms, unsigned long current_counts, unsigned long gm_count_timestamp, unsigned long current_hv_pulses,
float temperature, float humidity, float pressure) {
float temperature, float humidity, float pressure, int iaq) {
static unsigned long last_timestamp = millis();
static unsigned long last_counts = 0;
static unsigned long last_hv_pulses = 0;
Expand Down Expand Up @@ -144,7 +144,7 @@ void publish(unsigned long current_ms, unsigned long current_counts, unsigned lo
accumulated_Dose_Rate = accumulated_Count_Rate * GMC_factor_uSvph;

// ... and update the data on display, notify via BLE
update_bledata((unsigned int)(Count_Rate * 60));
update_bledata((unsigned int)(Count_Rate * 60), temperature, humidity, pressure, iaq);
display_GMC((unsigned int)(accumulated_time / 1000), (int)(accumulated_Dose_Rate * 1000), (int)(Count_Rate * 60),
(showDisplay && switches.display_on));

Expand All @@ -162,15 +162,15 @@ void publish(unsigned long current_ms, unsigned long current_counts, unsigned lo
if (Serial_Print_Mode == Serial_Logging) {
log_data(counts, dt, Count_Rate, Dose_Rate, hv_pulses,
accumulated_GMC_counts, accumulated_time, accumulated_Count_Rate, accumulated_Dose_Rate,
temperature, humidity, pressure);
temperature, humidity, pressure, iaq);
}
} else {
// If there were no pulses after AFTERSTART msecs after boot, clear display anyway and show 0 counts.
static unsigned long boot_timestamp = millis();
static unsigned long afterStartTime = AFTERSTART;
if (afterStartTime && ((current_ms - boot_timestamp) >= afterStartTime)) {
afterStartTime = 0;
update_bledata(0);
update_bledata(0, 0, 0, 0, 0);
display_GMC(0, 0, 0, (showDisplay && switches.display_on));
}
}
Expand Down Expand Up @@ -200,14 +200,13 @@ void statistics_log(unsigned long current_counts, unsigned int time_between) {
}
}

void read_THP(unsigned long current_ms,
bool *have_thp, float *temperature, float *humidity, float *pressure) {
void read_THP(unsigned long current_ms, bool *have_thp, float *temperature, float *humidity, float *pressure, int *iaq) {
static unsigned long last_timestamp = 0;
// first call: immediately query thp sensor
// subsequent calls: only query every MEASUREMENT_INTERVAL
if (!last_timestamp || (current_ms - last_timestamp) >= (MEASUREMENT_INTERVAL * 1000)) {
// subsequent calls: only query every BME680_BSEC_LP_READOUT_INTERVAL
if (!last_timestamp || (current_ms - last_timestamp) >= BME680_BSEC_LP_READOUT_INTERVAL) {
last_timestamp = current_ms;
*have_thp = read_thp_sensor(temperature, humidity, pressure);
*have_thp = read_thp_sensor(temperature, humidity, pressure, iaq);
}
}

Expand Down Expand Up @@ -246,6 +245,7 @@ void loop() {

static bool have_thp = false;
static float temperature = 0.0, humidity = 0.0, pressure = 0.0;
static int iaq = 0;

unsigned long current_ms = millis(); // to save multiple calls to millis()

Expand All @@ -270,7 +270,7 @@ void loop() {

read_GMC(&gm_counts, &gm_count_timestamp, &gm_count_time_between);

read_THP(current_ms, &have_thp, &temperature, &humidity, &pressure);
read_THP(current_ms, &have_thp, &temperature, &humidity, &pressure, &iaq);

read_hv(&hv_error, &hv_pulses);
set_status(STATUS_HV, hv_error ? ST_HV_ERROR : ST_HV_OK);
Expand All @@ -283,7 +283,7 @@ void loop() {
// do any other periodic updates for uplinks
poll_transmission();

publish(current_ms, gm_counts, gm_count_timestamp, hv_pulses, temperature, humidity, pressure);
publish(current_ms, gm_counts, gm_count_timestamp, hv_pulses, temperature, humidity, pressure, iaq);

if (Serial_Print_Mode == Serial_One_Minute_Log)
one_minute_log(current_ms, gm_counts);
Expand Down
Loading