@cryptotaxi247 / netdata-1 / commits / 15d4e6b9e

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"