lm_sensors.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. # SPDX-License-Identifier: LGPL-2.1
  2. """
  3. @package sensors.py
  4. Python Bindings for libsensors3
  5. use the documentation of libsensors for the low level API.
  6. see example.py for high level API usage.
  7. @author: Pavel Rojtberg (http://www.rojtberg.net)
  8. @see: https://github.com/paroj/sensors.py
  9. @copyright: LGPLv2 (same as libsensors) <http://opensource.org/licenses/LGPL-2.1>
  10. """
  11. from ctypes import *
  12. import ctypes.util
  13. _libc = cdll.LoadLibrary(ctypes.util.find_library("c"))
  14. # see https://github.com/paroj/sensors.py/issues/1
  15. _libc.free.argtypes = [c_void_p]
  16. _hdl = cdll.LoadLibrary(ctypes.util.find_library("sensors"))
  17. version = c_char_p.in_dll(_hdl, "libsensors_version").value.decode("ascii")
  18. class SensorsError(Exception):
  19. pass
  20. class ErrorWildcards(SensorsError):
  21. pass
  22. class ErrorNoEntry(SensorsError):
  23. pass
  24. class ErrorAccessRead(SensorsError, OSError):
  25. pass
  26. class ErrorKernel(SensorsError, OSError):
  27. pass
  28. class ErrorDivZero(SensorsError, ZeroDivisionError):
  29. pass
  30. class ErrorChipName(SensorsError):
  31. pass
  32. class ErrorBusName(SensorsError):
  33. pass
  34. class ErrorParse(SensorsError):
  35. pass
  36. class ErrorAccessWrite(SensorsError, OSError):
  37. pass
  38. class ErrorIO(SensorsError, IOError):
  39. pass
  40. class ErrorRecursion(SensorsError):
  41. pass
  42. _ERR_MAP = {
  43. 1: ErrorWildcards,
  44. 2: ErrorNoEntry,
  45. 3: ErrorAccessRead,
  46. 4: ErrorKernel,
  47. 5: ErrorDivZero,
  48. 6: ErrorChipName,
  49. 7: ErrorBusName,
  50. 8: ErrorParse,
  51. 9: ErrorAccessWrite,
  52. 10: ErrorIO,
  53. 11: ErrorRecursion
  54. }
  55. def raise_sensor_error(errno, message=''):
  56. raise _ERR_MAP[abs(errno)](message)
  57. class bus_id(Structure):
  58. _fields_ = [("type", c_short),
  59. ("nr", c_short)]
  60. class chip_name(Structure):
  61. _fields_ = [("prefix", c_char_p),
  62. ("bus", bus_id),
  63. ("addr", c_int),
  64. ("path", c_char_p)]
  65. class feature(Structure):
  66. _fields_ = [("name", c_char_p),
  67. ("number", c_int),
  68. ("type", c_int)]
  69. # sensors_feature_type
  70. IN = 0x00
  71. FAN = 0x01
  72. TEMP = 0x02
  73. POWER = 0x03
  74. ENERGY = 0x04
  75. CURR = 0x05
  76. HUMIDITY = 0x06
  77. MAX_MAIN = 0x7
  78. VID = 0x10
  79. INTRUSION = 0x11
  80. MAX_OTHER = 0x12
  81. BEEP_ENABLE = 0x18
  82. class subfeature(Structure):
  83. _fields_ = [("name", c_char_p),
  84. ("number", c_int),
  85. ("type", c_int),
  86. ("mapping", c_int),
  87. ("flags", c_uint)]
  88. _hdl.sensors_get_detected_chips.restype = POINTER(chip_name)
  89. _hdl.sensors_get_features.restype = POINTER(feature)
  90. _hdl.sensors_get_all_subfeatures.restype = POINTER(subfeature)
  91. _hdl.sensors_get_label.restype = c_void_p # return pointer instead of str so we can free it
  92. _hdl.sensors_get_adapter_name.restype = c_char_p # docs do not say whether to free this or not
  93. _hdl.sensors_strerror.restype = c_char_p
  94. ### RAW API ###
  95. MODE_R = 1
  96. MODE_W = 2
  97. COMPUTE_MAPPING = 4
  98. def init(cfg_file=None):
  99. file = _libc.fopen(cfg_file.encode("utf-8"), "r") if cfg_file is not None else None
  100. result = _hdl.sensors_init(file)
  101. if result != 0:
  102. raise_sensor_error(result, "sensors_init failed")
  103. if file is not None:
  104. _libc.fclose(file)
  105. def cleanup():
  106. _hdl.sensors_cleanup()
  107. def parse_chip_name(orig_name):
  108. ret = chip_name()
  109. err = _hdl.sensors_parse_chip_name(orig_name.encode("utf-8"), byref(ret))
  110. if err < 0:
  111. raise_sensor_error(err, strerror(err))
  112. return ret
  113. def strerror(errnum):
  114. return _hdl.sensors_strerror(errnum).decode("utf-8")
  115. def free_chip_name(chip):
  116. _hdl.sensors_free_chip_name(byref(chip))
  117. def get_detected_chips(match, nr):
  118. """
  119. @return: (chip, next nr to query)
  120. """
  121. _nr = c_int(nr)
  122. if match is not None:
  123. match = byref(match)
  124. chip = _hdl.sensors_get_detected_chips(match, byref(_nr))
  125. chip = chip.contents if bool(chip) else None
  126. return chip, _nr.value
  127. def chip_snprintf_name(chip, buffer_size=200):
  128. """
  129. @param buffer_size defaults to the size used in the sensors utility
  130. """
  131. ret = create_string_buffer(buffer_size)
  132. err = _hdl.sensors_snprintf_chip_name(ret, buffer_size, byref(chip))
  133. if err < 0:
  134. raise_sensor_error(err, strerror(err))
  135. return ret.value.decode("utf-8")
  136. def do_chip_sets(chip):
  137. """
  138. @attention this function was not tested
  139. """
  140. err = _hdl.sensors_do_chip_sets(byref(chip))
  141. if err < 0:
  142. raise_sensor_error(err, strerror(err))
  143. def get_adapter_name(bus):
  144. return _hdl.sensors_get_adapter_name(byref(bus)).decode("utf-8")
  145. def get_features(chip, nr):
  146. """
  147. @return: (feature, next nr to query)
  148. """
  149. _nr = c_int(nr)
  150. feature = _hdl.sensors_get_features(byref(chip), byref(_nr))
  151. feature = feature.contents if bool(feature) else None
  152. return feature, _nr.value
  153. def get_label(chip, feature):
  154. ptr = _hdl.sensors_get_label(byref(chip), byref(feature))
  155. val = cast(ptr, c_char_p).value.decode("utf-8")
  156. _libc.free(ptr)
  157. return val
  158. def get_all_subfeatures(chip, feature, nr):
  159. """
  160. @return: (subfeature, next nr to query)
  161. """
  162. _nr = c_int(nr)
  163. subfeature = _hdl.sensors_get_all_subfeatures(byref(chip), byref(feature), byref(_nr))
  164. subfeature = subfeature.contents if bool(subfeature) else None
  165. return subfeature, _nr.value
  166. def get_value(chip, subfeature_nr):
  167. val = c_double()
  168. err = _hdl.sensors_get_value(byref(chip), subfeature_nr, byref(val))
  169. if err < 0:
  170. raise_sensor_error(err, strerror(err))
  171. return val.value
  172. def set_value(chip, subfeature_nr, value):
  173. """
  174. @attention this function was not tested
  175. """
  176. val = c_double(value)
  177. err = _hdl.sensors_set_value(byref(chip), subfeature_nr, byref(val))
  178. if err < 0:
  179. raise_sensor_error(err, strerror(err))
  180. ### Convenience API ###
  181. class ChipIterator:
  182. def __init__(self, match=None):
  183. self.match = parse_chip_name(match) if match is not None else None
  184. self.nr = 0
  185. def __iter__(self):
  186. return self
  187. def __next__(self):
  188. chip, self.nr = get_detected_chips(self.match, self.nr)
  189. if chip is None:
  190. raise StopIteration
  191. return chip
  192. def __del__(self):
  193. if self.match is not None:
  194. free_chip_name(self.match)
  195. def next(self): # python2 compability
  196. return self.__next__()
  197. class FeatureIterator:
  198. def __init__(self, chip):
  199. self.chip = chip
  200. self.nr = 0
  201. def __iter__(self):
  202. return self
  203. def __next__(self):
  204. feature, self.nr = get_features(self.chip, self.nr)
  205. if feature is None:
  206. raise StopIteration
  207. return feature
  208. def next(self): # python2 compability
  209. return self.__next__()
  210. class SubFeatureIterator:
  211. def __init__(self, chip, feature):
  212. self.chip = chip
  213. self.feature = feature
  214. self.nr = 0
  215. def __iter__(self):
  216. return self
  217. def __next__(self):
  218. subfeature, self.nr = get_all_subfeatures(self.chip, self.feature, self.nr)
  219. if subfeature is None:
  220. raise StopIteration
  221. return subfeature
  222. def next(self): # python2 compability
  223. return self.__next__()