3 * Copyright (C) 2015 IPFire Team (www.ipfire.org)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <sensors/error.h>
24 #include <sensors/sensors.h>
26 #include "_collectymodule.h"
28 static PyGetSetDef Sensor_getsetters
[] = {
29 {"bus", (getter
)Sensor_get_bus
, NULL
, NULL
, NULL
},
30 {"critical", (getter
)Sensor_get_critical
, NULL
, NULL
, NULL
},
31 {"high", (getter
)Sensor_get_high
, NULL
, NULL
, NULL
},
32 {"label", (getter
)Sensor_get_label
, NULL
, NULL
, NULL
},
33 {"maximum", (getter
)Sensor_get_maximum
, NULL
, NULL
, NULL
},
34 {"minumum", (getter
)Sensor_get_minimum
, NULL
, NULL
, NULL
},
35 {"name", (getter
)Sensor_get_name
, NULL
, NULL
, NULL
},
36 {"type", (getter
)Sensor_get_type
, NULL
, NULL
, NULL
},
37 {"value", (getter
)Sensor_get_value
, NULL
, NULL
, NULL
},
41 PyTypeObject SensorType
= {
42 PyObject_HEAD_INIT(NULL
)
43 "_collecty.Sensor", /*tp_name*/
44 sizeof(SensorObject
), /*tp_basicsize*/
46 (destructor
)Sensor_dealloc
, /*tp_dealloc*/
61 Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
, /*tp_flags*/
62 "Sensor objects", /* tp_doc */
65 0, /* tp_richcompare */
66 0, /* tp_weaklistoffset */
71 Sensor_getsetters
, /* tp_getset */
76 0, /* tp_dictoffset */
77 (initproc
)Sensor_init
, /* tp_init */
79 Sensor_new
, /* tp_new */
82 void Sensor_dealloc(SensorObject
* self
) {
83 Py_TYPE(self
)->tp_free((PyObject
*)self
);
86 PyObject
* Sensor_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
87 SensorObject
* self
= (SensorObject
*)type
->tp_alloc(type
, 0);
89 return (PyObject
*)self
;
92 int Sensor_init(SensorObject
* self
, PyObject
* args
, PyObject
* kwds
) {
96 PyObject
* Sensor_get_label(SensorObject
* self
) {
97 char* label
= sensors_get_label(self
->chip
, self
->feature
);
100 PyObject
* string
= PyUnicode_FromString(label
);
109 PyObject
* Sensor_get_name(SensorObject
* self
) {
112 int r
= sensors_snprintf_chip_name(chip_name
, sizeof(chip_name
), self
->chip
);
114 PyErr_Format(PyExc_RuntimeError
, "Could not print chip name");
118 return PyUnicode_FromString(chip_name
);
121 PyObject
* Sensor_get_type(SensorObject
* self
) {
122 const char* type
= NULL
;
124 switch (self
->feature
->type
) {
125 case SENSORS_FEATURE_IN
:
129 case SENSORS_FEATURE_FAN
:
133 case SENSORS_FEATURE_TEMP
:
134 type
= "temperature";
137 case SENSORS_FEATURE_POWER
:
146 return PyUnicode_FromString(type
);
151 PyObject
* Sensor_get_bus(SensorObject
* self
) {
152 const char* type
= NULL
;
154 switch (self
->chip
->bus
.type
) {
155 case SENSORS_BUS_TYPE_I2C
:
159 case SENSORS_BUS_TYPE_ISA
:
163 case SENSORS_BUS_TYPE_PCI
:
167 case SENSORS_BUS_TYPE_SPI
:
171 case SENSORS_BUS_TYPE_VIRTUAL
:
175 case SENSORS_BUS_TYPE_ACPI
:
179 case SENSORS_BUS_TYPE_HID
:
188 return PyUnicode_FromString(type
);
193 static const sensors_subfeature
* Sensor_get_subfeature(SensorObject
* sensor
, sensors_subfeature_type type
) {
194 const sensors_subfeature
* subfeature
;
195 int subfeature_num
= 0;
197 while ((subfeature
= sensors_get_all_subfeatures(sensor
->chip
, sensor
->feature
, &subfeature_num
))) {
198 if (subfeature
->type
== type
)
205 PyObject
* Sensor_return_value(SensorObject
* sensor
, sensors_subfeature_type subfeature_type
) {
208 const sensors_subfeature
* subfeature
= Sensor_get_subfeature(sensor
, subfeature_type
);
210 PyErr_Format(PyExc_AttributeError
, "Could not find sensor of requested type");
214 // Fetch value from the sensor
215 int r
= sensors_get_value(sensor
->chip
, subfeature
->number
, &value
);
217 PyErr_Format(PyExc_ValueError
, "Error retrieving value from sensor: %s",
218 sensors_strerror(errno
));
222 // Convert all temperature values from Celcius to Kelvon
223 if (sensor
->feature
->type
== SENSORS_FEATURE_TEMP
)
226 return PyFloat_FromDouble(value
);
229 static PyObject
* Sensor_no_value() {
230 PyErr_Format(PyExc_ValueError
, "Value not supported for this sensor type");
234 PyObject
* Sensor_get_value(SensorObject
* self
) {
235 sensors_subfeature_type subfeature_type
;
237 switch (self
->feature
->type
) {
238 case SENSORS_FEATURE_IN
:
239 subfeature_type
= SENSORS_SUBFEATURE_IN_INPUT
;
242 case SENSORS_FEATURE_FAN
:
243 subfeature_type
= SENSORS_SUBFEATURE_FAN_INPUT
;
246 case SENSORS_FEATURE_TEMP
:
247 subfeature_type
= SENSORS_SUBFEATURE_TEMP_INPUT
;
250 case SENSORS_FEATURE_POWER
:
251 subfeature_type
= SENSORS_SUBFEATURE_POWER_INPUT
;
255 return Sensor_no_value();
258 return Sensor_return_value(self
, subfeature_type
);
261 PyObject
* Sensor_get_critical(SensorObject
* self
) {
262 sensors_subfeature_type subfeature_type
;
264 switch (self
->feature
->type
) {
265 case SENSORS_FEATURE_IN
:
266 subfeature_type
= SENSORS_SUBFEATURE_IN_CRIT
;
269 case SENSORS_FEATURE_TEMP
:
270 subfeature_type
= SENSORS_SUBFEATURE_TEMP_CRIT
;
273 case SENSORS_FEATURE_POWER
:
274 subfeature_type
= SENSORS_SUBFEATURE_POWER_CRIT
;
278 return Sensor_no_value();
281 return Sensor_return_value(self
, subfeature_type
);
284 PyObject
* Sensor_get_maximum(SensorObject
* self
) {
285 sensors_subfeature_type subfeature_type
;
287 switch (self
->feature
->type
) {
288 case SENSORS_FEATURE_IN
:
289 subfeature_type
= SENSORS_SUBFEATURE_IN_MAX
;
292 case SENSORS_FEATURE_FAN
:
293 subfeature_type
= SENSORS_SUBFEATURE_FAN_MAX
;
296 case SENSORS_FEATURE_TEMP
:
297 subfeature_type
= SENSORS_SUBFEATURE_TEMP_MAX
;
300 case SENSORS_FEATURE_POWER
:
301 subfeature_type
= SENSORS_SUBFEATURE_POWER_MAX
;
305 return Sensor_no_value();
308 return Sensor_return_value(self
, subfeature_type
);
311 PyObject
* Sensor_get_minimum(SensorObject
* self
) {
312 sensors_subfeature_type subfeature_type
;
314 switch (self
->feature
->type
) {
315 case SENSORS_FEATURE_IN
:
316 subfeature_type
= SENSORS_SUBFEATURE_IN_MIN
;
319 case SENSORS_FEATURE_FAN
:
320 subfeature_type
= SENSORS_SUBFEATURE_FAN_MIN
;
323 case SENSORS_FEATURE_TEMP
:
324 subfeature_type
= SENSORS_SUBFEATURE_TEMP_MIN
;
328 return Sensor_no_value();
331 return Sensor_return_value(self
, subfeature_type
);
334 PyObject
* Sensor_get_high(SensorObject
* self
) {
335 sensors_subfeature_type subfeature_type
;
337 switch (self
->feature
->type
) {
338 case SENSORS_FEATURE_TEMP
:
339 subfeature_type
= SENSORS_SUBFEATURE_TEMP_MAX
;
343 return Sensor_no_value();
346 return Sensor_return_value(self
, subfeature_type
);
349 static SensorObject
* make_sensor_object(const sensors_chip_name
* chip
, const sensors_feature
* feature
) {
350 SensorObject
* sensor
= PyObject_New(SensorObject
, &SensorType
);
354 if (!PyObject_Init((PyObject
*)sensor
, &SensorType
)) {
360 sensor
->feature
= feature
;
365 PyObject
* _collecty_sensors_init() {
366 // Clean up everything first in case sensors_init was called earlier
369 int r
= sensors_init(NULL
);
371 PyErr_Format(PyExc_OSError
, "Could not initialise sensors: %s",
372 sensors_strerror(errno
));
379 PyObject
* _collecty_sensors_cleanup() {
384 PyObject
* _collecty_get_detected_sensors(PyObject
* o
, PyObject
* args
) {
385 const char* name
= NULL
;
386 sensors_chip_name chip_name
;
388 if (!PyArg_ParseTuple(args
, "|z", &name
))
392 int r
= sensors_parse_chip_name(name
, &chip_name
);
394 PyErr_Format(PyExc_ValueError
, "Could not parse chip name: %s", name
);
399 PyObject
* list
= PyList_New(0);
401 const sensors_chip_name
* chip
;
404 while ((chip
= sensors_get_detected_chips((name
) ? &chip_name
: NULL
, &chip_num
))) {
405 const sensors_feature
* feature
;
408 while ((feature
= sensors_get_features(chip
, &feature_num
))) {
409 // Skip sensors we do not want to support
410 switch (feature
->type
) {
411 case SENSORS_FEATURE_IN
:
412 case SENSORS_FEATURE_FAN
:
413 case SENSORS_FEATURE_TEMP
:
414 case SENSORS_FEATURE_POWER
:
421 SensorObject
* sensor
= make_sensor_object(chip
, feature
);
422 PyList_Append(list
, (PyObject
*)sensor
);