Windows Sensors (Part II) (#20988)
thiagoftsm committed
Oct 22, 2025 at 11:25 UTC
15d4e6b9e3e89c1b77ced64683479767889dafdd
2 files changed
+275
-45
src/collectors/windows.plugin/GetSensors.c
+211
-45
@@ -15,13 +15,34 @@ static ISensorManager *pSensorManager = NULL;
15
static ND_THREAD *sensors_thread_update = NULL;
16
17
#define NETDATA_WIN_SENSOR_STATES (6)
18
+#define NETDATA_WIN_VECTOR_POS (3)
19
20
enum netdata_win_sensor_monitored {
21
NETDATA_WIN_SENSOR_CELSIUS,
22
NETDATA_WIN_SENSOR_POWER_WATTS,
23
NETDATA_WIN_SENSOR_CURRENT_AMPS,
24
NETDATA_WIN_SENSOR_RELATIVITY_HUMIDITY,
24
- NETDATA_WIN_SENSOR_LIGHT_LEVEL
25
+ NETDATA_WIN_SENSOR_LIGHT_LEVEL,
26
+ NETDATA_WIN_SENSOR_DATA_TYPE_LIGHT_TEMPERATURE,
27
+ NETDATA_WIN_SENSOR_VOLTAGE,
28
+ NETDATA_WIN_SENSOR_RESISTENCE,
29
+ NETDATA_WIN_SENSOR_ATMOSPHERE_PRESSURE,
30
+ NETDATA_WIN_SENSOR_LATITUDE_DEGREES,
31
+ NETDATA_WIN_SENSOR_LONGITUDE_DEGREES,
32
+ NETDATA_WIN_SENSOR_FORCE_NEWTONS,
33
+ NETDATA_WIN_SENSOR_GAUGE_PRESSURE,
34
+
35
+ // Add only one vector axis here
36
+ NETDATA_WIN_SENSOR_TYPE_DISTANCE_X,
37
+ NETDATA_WIN_SENSOR_ACCELERATION_X_G,
38
+
39
+ NETDATA_WIN_SENSOR_NEVER_USE_ME,
40
+
41
+ // Remaining axis should be added here
42
+ NETDATA_WIN_SENSOR_TYPE_DISTANCE_Y,
43
+ NETDATA_WIN_SENSOR_TYPE_DISTANCE_Z,
44
+ NETDATA_WIN_SENSOR_ACCELERATION_Y_G,
45
+ NETDATA_WIN_SENSOR_ACCELERATION_Z_G
46
};
47
48
REFPROPERTYKEY sensor_keys[] = {
@@ -30,8 +51,27 @@ REFPROPERTYKEY sensor_keys[] = {
51
&SENSOR_DATA_TYPE_CURRENT_AMPS,
52
&SENSOR_DATA_TYPE_RELATIVE_HUMIDITY_PERCENT,
53
&SENSOR_DATA_TYPE_LIGHT_LEVEL_LUX,
54
+ &SENSOR_DATA_TYPE_LIGHT_TEMPERATURE_KELVIN,
55
+ &SENSOR_DATA_TYPE_VOLTAGE_VOLTS,
56
+ &SENSOR_DATA_TYPE_RESISTANCE_OHMS,
57
+ &SENSOR_DATA_TYPE_ATMOSPHERIC_PRESSURE_BAR,
58
+ &SENSOR_DATA_TYPE_LATITUDE_DEGREES,
59
+ &SENSOR_DATA_TYPE_LONGITUDE_DEGREES,
60
+ &SENSOR_DATA_TYPE_FORCE_NEWTONS,
61
+ &SENSOR_DATA_TYPE_GAUGE_PRESSURE_PASCAL,
62
34
- NULL};
63
+ // Add only one vector axis here
64
+ &SENSOR_DATA_TYPE_DISTANCE_X_METERS,
65
+ &SENSOR_DATA_TYPE_ACCELERATION_X_G,
66
+
67
+ // Main loop stop
68
+ NULL,
69
+
70
+ // Remaining axis should be added here
71
+ &SENSOR_DATA_TYPE_DISTANCE_Y_METERS,
72
+ &SENSOR_DATA_TYPE_DISTANCE_Z_METERS,
73
+ &SENSOR_DATA_TYPE_ACCELERATION_Y_G,
74
+ &SENSOR_DATA_TYPE_ACCELERATION_Z_G};
75
76
77
static struct win_sensor_config {
@@ -76,6 +116,76 @@ static struct win_sensor_config {
116
.context = "system.hw.sensor.lux.input",
117
.family = "illuminance",
118
.priority = 70010,
119
+ },
120
+ {
121
+ .title = "Color temperature of light",
122
+ .units = "Cel",
123
+ .context = "system.hw.sensor.color.input",
124
+ .family = "Temperature",
125
+ .priority = 70011,
126
+ },
127
+ {
128
+ .title = "Electrical potential.",
129
+ .units = "V",
130
+ .context = "system.hw.sensor.voltage.input",
131
+ .family = "Potential",
132
+ .priority = 70012,
133
+ },
134
+ {
135
+ .title = "Electrical resistence.",
136
+ .units = "Ohms",
137
+ .context = "system.hw.sensor.resistence.input",
138
+ .family = "Resistence",
139
+ .priority = 70013,
140
+ },
141
+ {
142
+ .title = "Ambient atmospheric pressure",
143
+ .units = "Pa",
144
+ .context = "system.hw.sensor.pressure.input",
145
+ .family = "Pressure",
146
+ .priority = 70014,
147
+ },
148
+ {
149
+ .title = "Geographic latitude",
150
+ .units = "Degrees",
151
+ .context = "system.hw.sensor.latitude.input",
152
+ .family = "Location",
153
+ .priority = 70015,
154
+ },
155
+ {
156
+ .title = "Geographic longitude",
157
+ .units = "Degrees",
158
+ .context = "system.hw.sensor.longitude.input",
159
+ .family = "Location",
160
+ .priority = 70016,
161
+ },
162
+ {
163
+ .title = "Force",
164
+ .units = "N",
165
+ .context = "system.hw.sensor.force.input",
166
+ .family = "Force",
167
+ .priority = 70017,
168
+ },
169
+ {
170
+ .title = "Gauge Pressure",
171
+ .units = "Pa",
172
+ .context = "system.hw.sensor.gauge_pressure.input",
173
+ .family = "Pressure",
174
+ .priority = 70018,
175
+ },
176
+ {
177
+ .title = "Distance",
178
+ .units = "m",
179
+ .context = "system.hw.sensor.distance.input",
180
+ .family = "Distance",
181
+ .priority = 70019,
182
+ },
183
+ {
184
+ .title = "Acceleration.",
185
+ .units = "g",
186
+ .context = "system.hw.sensor.acceleration.input",
187
+ .family = "Acceleration",
188
+ .priority = 70022,
189
}
190
};
191
@@ -98,9 +208,15 @@ struct sensor_data {
208
RRDDIM *rd_sensor_state[NETDATA_WIN_SENSOR_STATES];
209
210
RRDSET *st_sensor_data;
101
- RRDDIM *rd_sensor_data;
102
-
103
- collected_number current_data_value;
211
+ RRDDIM *rd_sensor_data_0;
212
+ RRDDIM *rd_sensor_data_1;
213
+ RRDDIM *rd_sensor_data_2;
214
+
215
+ // Some sensors are vectors, this means they have three different values (Time is ignored here)
216
+ collected_number current_data_value[NETDATA_WIN_VECTOR_POS];
217
+ NETDATA_DOUBLE mult_factor;
218
+ NETDATA_DOUBLE div_factor;
219
+ NETDATA_DOUBLE add_factor;
220
};
221
222
DICTIONARY *sensors;
@@ -127,18 +243,18 @@ static inline char *netdata_convert_guid_to_string(HRESULT hr, GUID *value) {
243
return NULL;
244
}
245
130
-static inline void netdata_fill_sensor_type(struct sensor_data *s, ISensor *pSensor)
246
+static inline void netdata_fill_sensor_type(struct sensor_data *sd, ISensor *pSensor)
247
{
248
GUID type = {0};
249
HRESULT hr = pSensor->lpVtbl->GetType(pSensor, &type);
134
- s->type = netdata_convert_guid_to_string(hr, &type);
250
+ sd->type = netdata_convert_guid_to_string(hr, &type);
251
}
252
137
-static inline void netdata_fill_sensor_category(struct sensor_data *s, ISensor *pSensor)
253
+static inline void netdata_fill_sensor_category(struct sensor_data *sd, ISensor *pSensor)
254
{
255
GUID category = {0};
256
HRESULT hr = pSensor->lpVtbl->GetCategory(pSensor, &category);
141
- s->category = netdata_convert_guid_to_string(hr, &category);
257
+ sd->category = netdata_convert_guid_to_string(hr, &category);
258
}
259
260
static inline char *netdata_pvar_to_char(const PROPERTYKEY *key, ISensor *pSensor)
@@ -157,17 +273,17 @@ static inline char *netdata_pvar_to_char(const PROPERTYKEY *key, ISensor *pSenso
273
return NULL;
274
}
275
160
-static void netdata_initialize_sensor_dict(struct sensor_data *s, ISensor *pSensor)
276
+static void netdata_initialize_sensor_dict(struct sensor_data *sd, ISensor *pSensor)
277
{
162
- netdata_fill_sensor_type(s, pSensor);
163
- netdata_fill_sensor_category(s, pSensor);
164
- s->name = netdata_pvar_to_char(&SENSOR_PROPERTY_FRIENDLY_NAME, pSensor);
165
- s->model = netdata_pvar_to_char(&SENSOR_PROPERTY_MODEL, pSensor);
166
- s->manufacturer = netdata_pvar_to_char(&SENSOR_PROPERTY_MANUFACTURER, pSensor);
278
+ netdata_fill_sensor_type(sd, pSensor);
279
+ netdata_fill_sensor_category(sd, pSensor);
280
+ sd->name = netdata_pvar_to_char(&SENSOR_PROPERTY_FRIENDLY_NAME, pSensor);
281
+ sd->model = netdata_pvar_to_char(&SENSOR_PROPERTY_MODEL, pSensor);
282
+ sd->manufacturer = netdata_pvar_to_char(&SENSOR_PROPERTY_MANUFACTURER, pSensor);
283
}
284
285
static int
170
-netdata_collect_sensor_data(struct sensor_data *s, ISensor *pSensor, REFPROPERTYKEY key)
286
+netdata_collect_sensor_data(struct sensor_data *sd, ISensor *pSensor, REFPROPERTYKEY key, int vector_idx)
287
{
288
ISensorDataReport *pReport = NULL;
289
PROPVARIANT pv = {};
@@ -181,36 +297,49 @@ netdata_collect_sensor_data(struct sensor_data *s, ISensor *pSensor, REFPROPERTY
297
if (SUCCEEDED(hr) && (pv.vt == VT_R4 || pv.vt == VT_R8 || pv.vt == VT_UI4)) {
298
switch (pv.vt) {
299
case VT_UI4:
184
- s->current_data_value = (collected_number)(pv.ulVal * 100);
300
+ sd->current_data_value[vector_idx] = (collected_number)(pv.ulVal * 100);
301
break;
302
case VT_R4:
187
- s->current_data_value = (collected_number)(pv.fltVal * 100.0);
303
+ sd->current_data_value[vector_idx] = (collected_number)(pv.fltVal * sd->div_factor);
304
break;
305
case VT_R8:
190
- s->current_data_value = (collected_number)(pv.dblVal * 100.0);
306
+ sd->current_data_value[vector_idx] = (collected_number)(pv.dblVal * sd->div_factor);
307
break;
308
}
309
defined = 1;
310
}
311
PropVariantClear(&pv);
312
pReport->lpVtbl->Release(pReport);
313
+ } else {
314
+ sd->current_data_value[vector_idx] = 0;
315
}
316
317
return defined;
318
}
319
202
-static void netdata_sensors_get_data(struct sensor_data *s, ISensor *pSensor)
320
+static void netdata_sensors_get_data(struct sensor_data *sd, ISensor *pSensor)
321
{
322
for (int i = 0; sensor_keys[i]; i++) {
205
- if (netdata_collect_sensor_data(s, pSensor, sensor_keys[i])) {
206
- s->sensor_data_type = i;
207
- s->config = &configs[i];
208
- s->enabled = true;
323
+ if (netdata_collect_sensor_data(sd, pSensor, sensor_keys[i], 0)) {
324
+ sd->sensor_data_type = i;
325
+ sd->config = &configs[i];
326
+ sd->enabled = true;
327
+
328
+ if (i == NETDATA_WIN_SENSOR_TYPE_DISTANCE_X) {
329
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[NETDATA_WIN_SENSOR_TYPE_DISTANCE_Y], 1);
330
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[NETDATA_WIN_SENSOR_TYPE_DISTANCE_Z], 2);
331
+ } else if (i == NETDATA_WIN_SENSOR_ACCELERATION_X_G) {
332
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[NETDATA_WIN_SENSOR_ACCELERATION_Y_G], 1);
333
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[NETDATA_WIN_SENSOR_ACCELERATION_Z_G], 2);
334
+ } else if (i == NETDATA_WIN_SENSOR_DATA_TYPE_LIGHT_TEMPERATURE) {
335
+ sd->div_factor = 100.0;
336
+ sd->add_factor = -27315.0; // 273.15 * 100.0
337
+ }
338
break;
339
}
340
}
341
213
- s->first_time = false;
342
+ sd->first_time = false;
343
}
344
345
static void netdata_get_sensors()
@@ -243,20 +372,28 @@ static void netdata_get_sensors()
372
}
373
netdata_clsid_to_char(thread_values, &id);
374
246
- struct sensor_data *s = dictionary_set(sensors, thread_values, NULL, sizeof(*s));
375
+ struct sensor_data *sd = dictionary_set(sensors, thread_values, NULL, sizeof(*sd));
376
248
- if (unlikely(!s->initialized)) {
249
- netdata_initialize_sensor_dict(s, pSensor);
250
- s->initialized = true;
377
+ if (unlikely(!sd->initialized)) {
378
+ netdata_initialize_sensor_dict(sd, pSensor);
379
+ sd->initialized = true;
380
}
381
253
- s->current_state = SENSOR_STATE_MIN;
254
- (void)pSensor->lpVtbl->GetState(pSensor, &s->current_state);
255
-
256
- if (likely(s->first_time))
257
- netdata_sensors_get_data(s, pSensor);
258
- else if (likely(s->enabled))
259
- netdata_collect_sensor_data(s, pSensor, sensor_keys[s->sensor_data_type]);
382
+ sd->current_state = SENSOR_STATE_MIN;
383
+ (void)pSensor->lpVtbl->GetState(pSensor, &sd->current_state);
384
+
385
+ if (sd->first_time)
386
+ netdata_sensors_get_data(sd, pSensor);
387
+ else if (likely(sd->enabled)) {
388
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[sd->sensor_data_type], 0);
389
+ if (sd->sensor_data_type == NETDATA_WIN_SENSOR_TYPE_DISTANCE_X) {
390
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[NETDATA_WIN_SENSOR_TYPE_DISTANCE_Y], 1);
391
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[NETDATA_WIN_SENSOR_TYPE_DISTANCE_Z], 2);
392
+ } else if (sd->sensor_data_type == NETDATA_WIN_SENSOR_ACCELERATION_X_G) {
393
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[NETDATA_WIN_SENSOR_ACCELERATION_Y_G], 1);
394
+ netdata_collect_sensor_data(sd, pSensor, sensor_keys[NETDATA_WIN_SENSOR_ACCELERATION_Z_G], 2);
395
+ }
396
+ }
397
398
pSensor->lpVtbl->Release(pSensor);
399
}
@@ -286,6 +423,9 @@ void dict_sensor_insert(const DICTIONARY_ITEM *item __maybe_unused, void *value,
423
sd->first_time = true;
424
sd->sensor_data_type = 0;
425
sd->config = NULL;
426
+ sd->mult_factor = 1.0;
427
+ sd->div_factor = 100.0;
428
+ sd->add_factor = 0.0;
429
}
430
431
static int initialize(int update_every)
@@ -319,7 +459,7 @@ static int initialize(int update_every)
459
return 0;
460
}
461
322
-static void mssql_db_states_chart(struct sensor_data *sd, int update_every)
462
+static void sensors_states_chart(struct sensor_data *sd, int update_every)
463
{
464
if (!sd->st_sensor_state) {
465
char id[RRD_ID_LENGTH_MAX + 1];
@@ -335,7 +475,7 @@ static void mssql_db_states_chart(struct sensor_data *sd, int update_every)
475
"status",
476
PLUGIN_WINDOWS_NAME,
477
"GetSensors",
338
- 70010,
478
+ 69999,
479
update_every,
480
RRDSET_TYPE_LINE);
481
@@ -352,9 +492,9 @@ static void mssql_db_states_chart(struct sensor_data *sd, int update_every)
492
}
493
}
494
355
-static void mssql_sensor_state_chart_loop(struct sensor_data *sd, int update_every)
495
+static inline void sensors_state_chart_loop(struct sensor_data *sd, int update_every)
496
{
357
- mssql_db_states_chart(sd, update_every);
497
+ sensors_states_chart(sd, update_every);
498
collected_number set_value = (collected_number)sd->current_state;
499
for (collected_number i = 0; i < NETDATA_WIN_SENSOR_STATES; i++) {
500
rrddim_set_by_pointer(sd->st_sensor_state, sd->rd_sensor_state[i], i == set_value);
@@ -362,7 +502,23 @@ static void mssql_sensor_state_chart_loop(struct sensor_data *sd, int update_eve
502
rrdset_done(sd->st_sensor_state);
503
}
504
365
-static void mssql_sensor_data_chart(struct sensor_data *sd, int update_every)
505
+static inline RRDDIM *netdata_add_sensor_dimension(struct sensor_data *sd, char *label)
506
+{
507
+ return rrddim_add(sd->st_sensor_data,
508
+ label,
509
+ NULL,
510
+ (collected_number )sd->mult_factor,
511
+ (collected_number )sd->div_factor,
512
+ RRD_ALGORITHM_ABSOLUTE);
513
+}
514
+
515
+static inline void netdata_state_chart_set_value(RRDDIM *dim, struct sensor_data *sd, int value_idx)
516
+{
517
+ collected_number value = sd->current_data_value[value_idx] + (collected_number )sd->add_factor;
518
+ rrddim_set_by_pointer(sd->st_sensor_data, dim, value);
519
+}
520
+
521
+static void sensors_data_chart(struct sensor_data *sd, int update_every)
522
{
523
if (!sd->st_sensor_data) {
524
char id[RRD_ID_LENGTH_MAX + 1];
@@ -386,10 +542,20 @@ static void mssql_sensor_data_chart(struct sensor_data *sd, int update_every)
542
rrdlabels_add(sd->st_sensor_data->rrdlabels, "manufacturer", sd->manufacturer, RRDLABEL_SRC_AUTO);
543
rrdlabels_add(sd->st_sensor_data->rrdlabels, "model", sd->model, RRDLABEL_SRC_AUTO);
544
389
- sd->rd_sensor_data = rrddim_add(sd->st_sensor_data, "input", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
545
+ if (sd->sensor_data_type != NETDATA_WIN_SENSOR_TYPE_DISTANCE_X && sd->sensor_data_type != NETDATA_WIN_SENSOR_ACCELERATION_X_G)
546
+ sd->rd_sensor_data_0 = netdata_add_sensor_dimension(sd, "input");
547
+ else {
548
+ sd->rd_sensor_data_0 = netdata_add_sensor_dimension(sd, "inputX");
549
+ sd->rd_sensor_data_1 = netdata_add_sensor_dimension(sd, "inputY");
550
+ sd->rd_sensor_data_2 = netdata_add_sensor_dimension(sd, "inputZ");
551
+ }
552
}
553
392
- rrddim_set_by_pointer(sd->st_sensor_data, sd->rd_sensor_data, sd->current_data_value);
554
+ netdata_state_chart_set_value(sd->rd_sensor_data_0, sd, 0);
555
+ if (sd->sensor_data_type == NETDATA_WIN_SENSOR_TYPE_DISTANCE_X || sd->sensor_data_type == NETDATA_WIN_SENSOR_ACCELERATION_X_G) {
556
+ netdata_state_chart_set_value(sd->rd_sensor_data_1, sd, 1);
557
+ netdata_state_chart_set_value(sd->rd_sensor_data_2, sd, 2);
558
+ }
559
rrdset_done(sd->st_sensor_data);
560
}
561
@@ -401,12 +567,12 @@ int dict_sensors_charts_cb(const DICTIONARY_ITEM *item __maybe_unused, void *val
567
if (unlikely(!sd->name))
568
return 1;
569
404
- mssql_sensor_state_chart_loop(sd, *update_every);
570
+ sensors_state_chart_loop(sd, *update_every);
571
572
if (unlikely(!sd->enabled))
573
return 1;
574
409
- mssql_sensor_data_chart(sd, *update_every);
575
+ sensors_data_chart(sd, *update_every);
576
577
return 1;
578
}
src/collectors/windows.plugin/metadata.yaml
+64
@@ -1190,6 +1190,70 @@ modules:
1190
chart_type: line
1191
dimensions:
1192
- name: input
1193
+ - name: system.hw.sensor.color.input
1194
+ description: Color temperature of light
1195
+ unit: "Cel"
1196
+ chart_type: line
1197
+ dimensions:
1198
+ - name: input
1199
+ - name: system.hw.sensor.voltage.input
1200
+ description: Electrical potential
1201
+ unit: "V"
1202
+ chart_type: line
1203
+ dimensions:
1204
+ - name: input
1205
+ - name: system.hw.sensor.resistence.input
1206
+ description: Electrical resistence.
1207
+ unit: "Ohms"
1208
+ chart_type: line
1209
+ dimensions:
1210
+ - name: input
1211
+ - name: system.hw.sensor.pressure.input
1212
+ description: Ambient atmospheric pressure
1213
+ unit: "Pa"
1214
+ chart_type: line
1215
+ dimensions:
1216
+ - name: input
1217
+ - name: system.hw.sensor.latitude.input
1218
+ description: Geographic latitude
1219
+ unit: "Degrees"
1220
+ chart_type: line
1221
+ dimensions:
1222
+ - name: input
1223
+ - name: system.hw.sensor.longitude.input
1224
+ description: Geographic longitude
1225
+ unit: "Degrees"
1226
+ chart_type: line
1227
+ dimensions:
1228
+ - name: input
1229
+ - name: system.hw.sensor.force.input
1230
+ description: Force
1231
+ unit: "N"
1232
+ chart_type: line
1233
+ dimensions:
1234
+ - name: input
1235
+ - name: system.hw.sensor.gauge_pressure.input
1236
+ description: Gauge Pressure
1237
+ unit: "Pa"
1238
+ chart_type: line
1239
+ dimensions:
1240
+ - name: input
1241
+ - name: system.hw.sensor.distance.input
1242
+ description: Distance
1243
+ unit: "m"
1244
+ chart_type: line
1245
+ dimensions:
1246
+ - name: inputX
1247
+ - name: inputY
1248
+ - name: inputZ
1249
+ - name: system.hw.sensor.acceleration.input
1250
+ description: Acceleration
1251
+ unit: "g"
1252
+ chart_type: line
1253
+ dimensions:
1254
+ - name: inputX
1255
+ - name: inputY
1256
+ - name: inputZ
1257
- name: system.hw.sensor.state.input
1258
description: Current sensor state.
1259
unit: "status"