2 # -*- coding: utf-8 -*-
5 from ctypes import CDLL, c_char_p, c_int, c_void_p, c_uint, c_double, byref, Structure, get_errno,\
6 POINTER, c_short, c_size_t, create_string_buffer
7 from ctypes.util import find_library
9 version_info = (0, 0, 3)
11 __version__ = '.'.join(map(str, version_info))
12 __date__ = '2014-08-17'
13 __author__ = "Marc 'BlackJack' Rintsch"
14 __contact__ = 'marc@rintsch.de'
15 __license__ = 'LGPL v2.1'
18 DEFAULT_CONFIG_FILENAME = '/etc/sensors3.conf'
20 LIB_FILENAME = os.environ.get('SENSORS_LIB') or find_library('sensors')
21 SENSORS_LIB = CDLL(LIB_FILENAME)
22 VERSION = c_char_p.in_dll(SENSORS_LIB, 'libsensors_version').value
23 MAJOR_VERSION = version_info[0]
24 STDC_LIB = CDLL(find_library('c'), use_errno=True)
41 class SensorsError(Exception):
42 def __init__(self, message, error_number=None):
43 Exception.__init__(self, message)
44 self.error_number = error_number
47 def _error_check(result, _func, _arguments):
49 raise SensorsError(_strerror(result), result)
52 _strerror = SENSORS_LIB.sensors_strerror
53 _strerror.argtypes = [c_int]
54 _strerror.restype = c_char_p
56 _init = SENSORS_LIB.sensors_init
57 _init.argtypes = [c_void_p]
59 _init.errcheck = _error_check
61 cleanup = SENSORS_LIB.sensors_cleanup
62 cleanup.argtypes = None
63 cleanup.restype = None
66 def init(config_filename=DEFAULT_CONFIG_FILENAME):
67 file_p = STDC_LIB.fopen(config_filename.encode('utf-8'), b'r')
69 error_number = get_errno()
70 raise OSError(error_number, os.strerror(error_number), config_filename)
74 STDC_LIB.fclose(file_p)
77 class Subfeature(Structure):
87 return '<%s name=%r number=%d type=%d mapping=%d flags=%08x>' % (
88 self.__class__.__name__,
98 _get_value(byref(self.parent.chip), self.number, byref(result))
101 SUBFEATURE_P = POINTER(Subfeature)
104 class Feature(Structure):
109 ('_first_subfeature', c_int),
110 ('_padding1', c_int),
114 return '<%s name=%r number=%r type=%r>' % (
115 self.__class__.__name__,
124 result_p = _get_all_subfeatures(
131 result = result_p.contents
132 result.chip = self.chip
139 # TODO Maybe this is a memory leak!
141 return _get_label(byref(self.chip), byref(self)).decode('utf-8')
145 # TODO Is the first always the correct one for all feature types?
147 return next(iter(self)).get_value()
149 FEATURE_P = POINTER(Feature)
152 class Bus(Structure):
163 '*' if self.type == self.TYPE_ANY
164 else _get_adapter_name(byref(self)).decode('utf-8')
168 return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.nr)
171 def has_wildcards(self):
172 return self.type == self.TYPE_ANY or self.nr == self.NR_ANY
177 class Chip(Structure):
179 # TODO Move common stuff into `AbstractChip` class.
182 ('prefix', c_char_p),
191 def __new__(cls, *args):
192 result = super(Chip, cls).__new__(cls)
194 _parse_chip_name(args[0].encode('utf-8'), byref(result))
197 def __init__(self, *_args):
198 Structure.__init__(self)
200 # Need to bind the following to the instance so it is available in
201 # `__del__()` when the interpreter shuts down.
203 self._free_chip_name = _free_chip_name
207 if self._b_needsfree_:
208 self._free_chip_name(self.byref(self))
211 return '<%s prefix=%r bus=%r addr=%r path=%r>' % (
213 self.__class__.__name__,
223 result = create_string_buffer(buffer_size)
224 used = _snprintf_chip_name(result, len(result), byref(self))
225 assert used < buffer_size
226 return result.value.decode('utf-8')
231 result_p = _get_features(byref(self), byref(number))
234 result = result_p.contents
239 def adapter_name(self):
243 def has_wildcards(self):
245 self.prefix == self.PREFIX_ANY
246 or self.addr == self.ADDR_ANY
247 or self.bus.has_wildcards
250 CHIP_P = POINTER(Chip)
253 _parse_chip_name = SENSORS_LIB.sensors_parse_chip_name
254 _parse_chip_name.argtypes = [c_char_p, CHIP_P]
255 _parse_chip_name.restype = c_int
256 _parse_chip_name.errcheck = _error_check
258 _free_chip_name = SENSORS_LIB.sensors_free_chip_name
259 _free_chip_name.argtypes = [CHIP_P]
260 _free_chip_name.restype = None
262 _snprintf_chip_name = SENSORS_LIB.sensors_snprintf_chip_name
263 _snprintf_chip_name.argtypes = [c_char_p, c_size_t, CHIP_P]
264 _snprintf_chip_name.restype = c_int
265 _snprintf_chip_name.errcheck = _error_check
267 _get_adapter_name = SENSORS_LIB.sensors_get_adapter_name
268 _get_adapter_name.argtypes = [BUS_P]
269 _get_adapter_name.restype = c_char_p
271 _get_label = SENSORS_LIB.sensors_get_label
272 _get_label.argtypes = [CHIP_P, FEATURE_P]
273 _get_label.restype = c_char_p
275 _get_value = SENSORS_LIB.sensors_get_value
276 _get_value.argtypes = [CHIP_P, c_int, POINTER(c_double)]
277 _get_value.restype = c_int
278 _get_value.errcheck = _error_check
281 # TODO sensors_set_value()
282 # TODO sensors_do_chip_sets()
285 _get_detected_chips = SENSORS_LIB.sensors_get_detected_chips
286 _get_detected_chips.argtypes = [CHIP_P, POINTER(c_int)]
287 _get_detected_chips.restype = CHIP_P
289 _get_features = SENSORS_LIB.sensors_get_features
290 _get_features.argtypes = [CHIP_P, POINTER(c_int)]
291 _get_features.restype = FEATURE_P
293 _get_all_subfeatures = SENSORS_LIB.sensors_get_all_subfeatures
294 _get_all_subfeatures.argtypes = [CHIP_P, FEATURE_P, POINTER(c_int)]
295 _get_all_subfeatures.restype = SUBFEATURE_P
298 # TODO sensors_get_subfeature() ?
302 def iter_detected_chips(chip_name='*-*'):
303 chip = Chip(chip_name)
306 result = _get_detected_chips(byref(chip), byref(number))
309 yield result.contents