sensors.chart.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. # -*- coding: utf-8 -*-
  2. # Description: sensors netdata python.d plugin
  3. # Author: Pawel Krupa (paulfantom)
  4. # SPDX-License-Identifier: GPL-3.0-or-later
  5. from bases.FrameworkServices.SimpleService import SimpleService
  6. from third_party import lm_sensors as sensors
  7. ORDER = [
  8. 'temperature',
  9. 'fan',
  10. 'voltage',
  11. 'current',
  12. 'power',
  13. 'energy',
  14. 'humidity',
  15. ]
  16. # This is a prototype of chart definition which is used to dynamically create self.definitions
  17. CHARTS = {
  18. 'temperature': {
  19. 'options': [None, 'Temperature', 'Celsius', 'temperature', 'sensors.temperature', 'line'],
  20. 'lines': [
  21. [None, None, 'absolute', 1, 1000]
  22. ]
  23. },
  24. 'voltage': {
  25. 'options': [None, 'Voltage', 'Volts', 'voltage', 'sensors.voltage', 'line'],
  26. 'lines': [
  27. [None, None, 'absolute', 1, 1000]
  28. ]
  29. },
  30. 'current': {
  31. 'options': [None, 'Current', 'Ampere', 'current', 'sensors.current', 'line'],
  32. 'lines': [
  33. [None, None, 'absolute', 1, 1000]
  34. ]
  35. },
  36. 'power': {
  37. 'options': [None, 'Power', 'Watt', 'power', 'sensors.power', 'line'],
  38. 'lines': [
  39. [None, None, 'absolute', 1, 1000]
  40. ]
  41. },
  42. 'fan': {
  43. 'options': [None, 'Fans speed', 'Rotations/min', 'fans', 'sensors.fan', 'line'],
  44. 'lines': [
  45. [None, None, 'absolute', 1, 1000]
  46. ]
  47. },
  48. 'energy': {
  49. 'options': [None, 'Energy', 'Joule', 'energy', 'sensors.energy', 'line'],
  50. 'lines': [
  51. [None, None, 'incremental', 1, 1000]
  52. ]
  53. },
  54. 'humidity': {
  55. 'options': [None, 'Humidity', 'Percent', 'humidity', 'sensors.humidity', 'line'],
  56. 'lines': [
  57. [None, None, 'absolute', 1, 1000]
  58. ]
  59. }
  60. }
  61. LIMITS = {
  62. 'temperature': [-127, 1000],
  63. 'voltage': [-127, 127],
  64. 'current': [-127, 127],
  65. 'fan': [0, 65535]
  66. }
  67. TYPE_MAP = {
  68. 0: 'voltage',
  69. 1: 'fan',
  70. 2: 'temperature',
  71. 3: 'power',
  72. 4: 'energy',
  73. 5: 'current',
  74. 6: 'humidity',
  75. 7: 'max_main',
  76. 16: 'vid',
  77. 17: 'intrusion',
  78. 18: 'max_other',
  79. 24: 'beep_enable'
  80. }
  81. class Service(SimpleService):
  82. def __init__(self, configuration=None, name=None):
  83. SimpleService.__init__(self, configuration=configuration, name=name)
  84. self.order = list()
  85. self.definitions = dict()
  86. self.chips = configuration.get('chips')
  87. def get_data(self):
  88. data = dict()
  89. try:
  90. for chip in sensors.ChipIterator():
  91. prefix = sensors.chip_snprintf_name(chip)
  92. for feature in sensors.FeatureIterator(chip):
  93. sfi = sensors.SubFeatureIterator(chip, feature)
  94. val = None
  95. for sf in sfi:
  96. try:
  97. val = sensors.get_value(chip, sf.number)
  98. break
  99. except sensors.SensorsError:
  100. continue
  101. if val is None:
  102. continue
  103. type_name = TYPE_MAP[feature.type]
  104. if type_name in LIMITS:
  105. limit = LIMITS[type_name]
  106. if val < limit[0] or val > limit[1]:
  107. continue
  108. data[prefix + '_' + str(feature.name.decode())] = int(val * 1000)
  109. except sensors.SensorsError as error:
  110. self.error(error)
  111. return None
  112. return data or None
  113. def create_definitions(self):
  114. for sensor in ORDER:
  115. for chip in sensors.ChipIterator():
  116. chip_name = sensors.chip_snprintf_name(chip)
  117. if self.chips and not any([chip_name.startswith(ex) for ex in self.chips]):
  118. continue
  119. for feature in sensors.FeatureIterator(chip):
  120. sfi = sensors.SubFeatureIterator(chip, feature)
  121. vals = list()
  122. for sf in sfi:
  123. try:
  124. vals.append(sensors.get_value(chip, sf.number))
  125. except sensors.SensorsError as error:
  126. self.error('{0}: {1}'.format(sf.name, error))
  127. continue
  128. if not vals or (vals[0] == 0 and feature.type != 1):
  129. continue
  130. if TYPE_MAP[feature.type] == sensor:
  131. # create chart
  132. name = chip_name + '_' + TYPE_MAP[feature.type]
  133. if name not in self.order:
  134. self.order.append(name)
  135. chart_def = list(CHARTS[sensor]['options'])
  136. self.definitions[name] = {'options': chart_def}
  137. self.definitions[name]['lines'] = []
  138. line = list(CHARTS[sensor]['lines'][0])
  139. line[0] = chip_name + '_' + str(feature.name.decode())
  140. line[1] = sensors.get_label(chip, feature)
  141. self.definitions[name]['lines'].append(line)
  142. def check(self):
  143. try:
  144. sensors.init()
  145. except sensors.SensorsError as error:
  146. self.error(error)
  147. return False
  148. self.create_definitions()
  149. return bool(self.get_data())