Files

152 lines
4.8 KiB
C++
Raw Permalink Normal View History

2026-02-13 21:27:38 +01:00
//
// Write SCD4x sensor values into a JSON file
// written by Larry Bank Feb 13, 2026
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
#include <bb_scd41.h>
#include <time.h>
SCD41 co2;
2026-02-20 16:54:39 +01:00
// Structure holding all of the info for a JSON sensor record
typedef struct tagjsonrec
2026-02-13 21:27:38 +01:00
{
2026-02-20 16:54:39 +01:00
const char *szMake;
const char *szModel;
const char *szKind;
const char *szValue;
const char *szUnit;
} JSONREC;
2026-02-13 21:27:38 +01:00
2026-02-20 16:54:39 +01:00
// Enumerated value indicating the position of the record in the JSON
// We need this to know where to start/end the nested curly braces
enum {
REC_INVALID = 0,
REC_FIRST,
REC_ANY,
REC_LAST
};
//
// Add one item to the JSON file
// f - an open file handle
// pRec - pointer to a JSONREC structure
// iRecOrder - indicates if this is the first, middle or last value
//
void AddJSONItem(FILE *f, JSONREC *pRec, int iRecOrder)
{
time_t tt;
char szOut[1024], szTemp[256];
tt = time(NULL); // get the current system time
if (iRecOrder == REC_FIRST) {
2026-02-13 21:27:38 +01:00
strcpy(szOut, "{\n \"data\": [\n {\n");
2026-02-20 16:54:39 +01:00
} else {
strcpy(szOut, " {\n");
2026-02-13 21:27:38 +01:00
}
2026-02-20 16:54:39 +01:00
sprintf(szTemp, " \"make\": \"%s\",\n \"model\": \"%s\",\n", pRec->szMake, pRec->szModel);
strcat(szOut, szTemp);
sprintf(szTemp, " \"kind\": \"%s\",\n \"value\": %s,\n", pRec->szKind, pRec->szValue);
strcat(szOut, szTemp);
sprintf(szTemp, " \"unit\": \"%s\",\n", pRec->szUnit);
strcat(szOut, szTemp);
2026-02-23 13:01:34 +01:00
sprintf(szTemp, " \"created_at\": %lu\n }", (unsigned long)tt);
2026-02-20 16:54:39 +01:00
strcat(szOut, szTemp);
if (iRecOrder == REC_LAST) {
strcat(szOut, "\n ]\n}\n");
} else {
strcat(szOut, ",\n");
}
fwrite(szOut, 1, strlen(szOut), f);
} /* AddJSONItem() */
2026-02-13 21:27:38 +01:00
int main(int argc, char *argv[])
{
int i, iBus;
DIR *pDir;
struct dirent *pDE;
uint32_t u32Buses = 0; // available I2C bus numbers (0-31)
2026-02-20 16:54:39 +01:00
JSONREC rec;
2026-02-13 21:27:38 +01:00
printf("sensor2json example\n");
printf("Finds which I2C bus has the supported sensor, then\ninitializes, configures, and loops updating the json with the latest sensor values.\n");
if (argc != 2) {
printf("usage: sensor2json <json file>\n");
return -1;
}
// I2C buses in Linux are defined as a file in the /dev directory
pDir = opendir("/dev");
if (!pDir) {
printf("Error searching /dev directory; aborting.\n");
return -1;
}
// Search all names in the /dev directory for those starting with i2c-
while ((pDE = readdir(pDir)) != NULL) {
if (memcmp(pDE->d_name, "i2c-", 4) == 0) { // found one!
iBus = atoi(&pDE->d_name[4]);
u32Buses |= (1 << iBus); // collect the bus numbers
}
}
closedir(pDir);
if (u32Buses == 0) { // Something went wrong; no I2C buses
printf("No I2C buses found!\n");
printf("Check your system configuration (e.g. raspi-config)\n");
printf("to ensure that I2C is enabled.\n");
return -1;
}
// Search each I2C bus for a supported proximited sensor
for (iBus=0; iBus<32; iBus++) {
if (u32Buses & (1<<iBus)) { // a bus that we found in /dev
i = co2.init(iBus); // scan for supported sensors
if (i == SCD41_SUCCESS) {
printf("Found a device on i2c-%d!\n", iBus);
break;
}
}
} // for each possible bus
if (iBus == 32) { // scanned all buses and didn't find anything
printf("No supported device found\n");
printf("Your system may require sudo to access I2C.\n");
return -1; // problem - quit
}
printf("SCD41 detected and initialized\n");
co2.start(); // start the sensor with the default options
while (1) {
2026-02-20 16:54:39 +01:00
char szValue[32];
FILE *f;
co2.getSample();
f = fopen(argv[1], "w+b");
if (f) { // open succeeded
// The constant info for each JSON record
rec.szMake = "Sensirion";
rec.szModel = "SCD41";
rec.szValue = szValue;
// Add CO2 value
2026-02-23 11:38:01 -07:00
rec.szKind = "carbon_dioxide";
2026-02-20 16:54:39 +01:00
sprintf(szValue, "%d", co2.co2());
rec.szUnit = "parts_per_million";
2026-02-20 16:54:39 +01:00
AddJSONItem(f, &rec, REC_FIRST);
// Add temperature value
rec.szKind = "temperature";
sprintf(szValue, "%.1f", (float)co2.temperature() / 10.0f);
rec.szUnit = "celsius";
AddJSONItem(f, &rec, REC_ANY);
// Add humidity value
rec.szKind = "humidity";
sprintf(szValue, "%d", co2.humidity());
rec.szUnit = "percent";
AddJSONItem(f, &rec, REC_LAST);
// write any remaining data and close the file
fflush(f);
fclose(f);
2026-02-13 21:27:38 +01:00
usleep(5000000); // one sample every 5 seconds
2026-02-20 16:54:39 +01:00
} // if file opened
} // while (1)
2026-02-13 21:27:38 +01:00
return 0;
} /* main() */