Air Quality Monitor
Portable C application for collecting, storing, and analyzing air quality sensor readings
Loading...
Searching...
No Matches
dht22_plugin.c
1#include "../include/sensor/sensor.h"
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <time.h>
6
7#ifdef _WIN32
8#define SENSOR_PLUGIN_EXPORT __declspec(dllexport)
9#else
10#define SENSOR_PLUGIN_EXPORT
11#endif
12
13#if defined(HAVE_WIRINGPI) && !defined(_WIN32)
14#include <wiringPi.h>
15
16#ifndef MAX_TIMINGS
17#define MAX_TIMINGS 85
18#endif
19
20static int dht_pin(void) {
21 const char *env = getenv("DHT22_PIN");
22 if (!env || !env[0])
23 return 7; // wiringPi pin numbering by default
24 int v = atoi(env);
25 return (v >= 0) ? v : 7;
26}
27
28static int dht22_data[5] = {0, 0, 0, 0, 0};
29
30static int dht22_read(float *out_temp_c, float *out_humidity_pct) {
31 if (!out_temp_c || !out_humidity_pct)
32 return -1;
33
34 const int pin = dht_pin();
35 unsigned char laststate = HIGH;
36 unsigned char counter = 0;
37 unsigned char j = 0;
38 unsigned char i;
39
40 dht22_data[0] = dht22_data[1] = dht22_data[2] = dht22_data[3] = dht22_data[4] = 0;
41
42 pinMode(pin, OUTPUT);
43 digitalWrite(pin, LOW);
44 delay(18);
45 digitalWrite(pin, HIGH);
46 delayMicroseconds(40);
47 pinMode(pin, INPUT);
48
49 for (i = 0; i < MAX_TIMINGS; i++) {
50 counter = 0;
51 while (digitalRead(pin) == laststate) {
52 counter++;
53 delayMicroseconds(1);
54 if (counter == 255)
55 break;
56 }
57 laststate = digitalRead(pin);
58 if (counter == 255)
59 break;
60 if ((i >= 4) && (i % 2 == 0)) {
61 dht22_data[j / 8] <<= 1;
62 if (counter > 16)
63 dht22_data[j / 8] |= 1;
64 j++;
65 }
66 }
67
68 if ((j >= 40) && (dht22_data[4] == ((dht22_data[0] + dht22_data[1] + dht22_data[2] + dht22_data[3]) & 0xFF))) {
69 float h = (float)((dht22_data[0] << 8) + dht22_data[1]) / 10.0f;
70 if (h > 100)
71 h = (float)dht22_data[0];
72 float c = (float)(((dht22_data[2] & 0x7F) << 8) + dht22_data[3]) / 10.0f;
73 if (c > 125)
74 c = (float)dht22_data[2];
75 if (dht22_data[2] & 0x80)
76 c = -c;
77
78 *out_temp_c = c;
79 *out_humidity_pct = h;
80 return 0;
81 }
82
83 return -1;
84}
85
86static int dht22_init(void) {
87 if (wiringPiSetup() == -1) {
88 fprintf(stderr, "DHT22: wiringPi setup failed\n");
89 return -1;
90 }
91 printf("DHT22 initialized (hardware mode, pin %d).\n", dht_pin());
92 return 0;
93}
94
95static int dht22_shutdown(void) {
96 printf("DHT22 shutdown.\n");
97 return 0;
98}
99
100#else
101
102// Portable simulated DHT22. Works on Windows/macOS/Linux without extra deps.
103static int dht22_read(float *out_temp_c, float *out_humidity_pct) {
104 if (!out_temp_c || !out_humidity_pct)
105 return -1;
106
107 // Stable-ish values, slightly jittery.
108 float temp = 22.0f + (float)(rand() % 800) / 100.0f; // 22.00 .. 29.99
109 float hum = 40.0f + (float)(rand() % 4000) / 100.0f; // 40.00 .. 79.99
110 if (hum > 100.0f)
111 hum = 100.0f;
112
113 *out_temp_c = temp;
114 *out_humidity_pct = hum;
115 return 0;
116}
117
118static int dht22_init(void) {
119 printf("DHT22 initialized (simulated mode). Set HAVE_WIRINGPI=1 on Linux to use hardware.\n");
120 return 0;
121}
122
123static int dht22_shutdown(void) {
124 printf("DHT22 shutdown.\n");
125 return 0;
126}
127
128#endif
129
130static void fill_timestamp(char *buf, size_t len) {
131 time_t now = time(NULL);
132 const struct tm *ptm = localtime(&now);
133 if (!ptm) {
134 snprintf(buf, len, "1970-01-01 00:00:00");
135 return;
136 }
137 if (strftime(buf, len, "%Y-%m-%d %H:%M:%S", ptm) == 0) {
138 snprintf(buf, len, "1970-01-01 00:00:00");
139 }
140}
141
142static int dht22_read_sample(AirQualityData *out) {
143 if (!out)
144 return -1;
145
146 float t = 0.0f, h = 0.0f;
147 if (dht22_read(&t, &h) != 0)
148 return -1;
149
150 memset(out, 0, sizeof(*out));
151 out->sensor_id = 22;
152 snprintf(out->model, sizeof(out->model), "DHT22");
153 fill_timestamp(out->timestamp, sizeof(out->timestamp));
154
155 // Current schema doesn't have temperature/humidity fields; map into pm25/pm10 for now.
156 out->pm25 = t;
157 out->pm10 = h;
158 out->co = 0.0f;
159 out->no2 = 0.0f;
160 out->o3 = 0.0f;
161 out->so2 = 0.0f;
162
163 return 0;
164}
165
166SENSOR_PLUGIN_EXPORT SensorPlugin sensor_plugin = {
167 .api_version = SENSOR_PLUGIN_API_VERSION,
168 .name = "DHT22",
169 .plugin_version = "1.0.0",
170 .description = "DHT22 plugin (hardware with wiringPi or simulated fallback).",
171 .sensor_id = 22,
172 .init = dht22_init,
173 .read_sample = dht22_read_sample,
174 .shutdown = dht22_shutdown,
175};
176
One air quality reading: pollutant values plus sensor/timestamp metadata.
Definition globals.h:27
char timestamp[32]
Reading timestamp, formatted "%Y-%m-%d %H:%M:%S".
Definition globals.h:31
char model[64]
Sensor model name, e.g.
Definition globals.h:33
int sensor_id
Numeric sensor identifier, matches SensorPlugin::sensor_id.
Definition globals.h:29
Runtime contract every sensor plugin (.so/.dylib/.dll) must implement.
Definition sensor.h:35
int api_version
Must equal SENSOR_PLUGIN_API_VERSION at build time.
Definition sensor.h:37