Brad Bishop | 2fa78fb | 2016-08-30 19:51:51 -0400 | [diff] [blame] | 1 | #!/usr/bin/env python |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 2 | |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 3 | import os |
| 4 | import gobject |
Norman James | 3bb97d9 | 2015-12-18 14:57:22 -0600 | [diff] [blame] | 5 | import glob |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 6 | import dbus |
| 7 | import dbus.service |
| 8 | import dbus.mainloop.glib |
Norman James | 3bb97d9 | 2015-12-18 14:57:22 -0600 | [diff] [blame] | 9 | import re |
Brad Bishop | 84e73b5 | 2016-05-12 15:57:52 -0400 | [diff] [blame] | 10 | from obmc.dbuslib.bindings import get_dbus |
Norman James | 3bb97d9 | 2015-12-18 14:57:22 -0600 | [diff] [blame] | 11 | |
Brad Bishop | ee1b154 | 2016-05-12 16:55:00 -0400 | [diff] [blame] | 12 | from obmc.sensors import SensorValue as SensorValue |
| 13 | from obmc.sensors import HwmonSensor as HwmonSensor |
| 14 | from obmc.sensors import SensorThresholds as SensorThresholds |
Brad Bishop | 67a6f45 | 2016-08-30 19:56:58 -0400 | [diff] [blame^] | 15 | |
| 16 | try: |
| 17 | import obmc_system_config as System |
| 18 | have_system = True |
| 19 | except ImportError: |
| 20 | have_system = False |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 21 | |
| 22 | SENSOR_BUS = 'org.openbmc.Sensors' |
| 23 | SENSOR_PATH = '/org/openbmc/sensors' |
Norman James | 3bb97d9 | 2015-12-18 14:57:22 -0600 | [diff] [blame] | 24 | DIR_POLL_INTERVAL = 30000 |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 25 | HWMON_PATH = '/sys/class/hwmon' |
| 26 | |
| 27 | ## static define which interface each property is under |
| 28 | ## need a better way that is not slow |
| 29 | IFACE_LOOKUP = { |
Brad Bishop | 2fa78fb | 2016-08-30 19:51:51 -0400 | [diff] [blame] | 30 | 'units': SensorValue.IFACE_NAME, |
| 31 | 'adjust': HwmonSensor.IFACE_NAME, |
| 32 | 'scale': HwmonSensor.IFACE_NAME, |
| 33 | 'offset': HwmonSensor.IFACE_NAME, |
| 34 | 'critical_upper': SensorThresholds.IFACE_NAME, |
| 35 | 'warning_upper': SensorThresholds.IFACE_NAME, |
| 36 | 'critical_lower': SensorThresholds.IFACE_NAME, |
| 37 | 'warning_lower': SensorThresholds.IFACE_NAME, |
| 38 | 'emergency_enabled': SensorThresholds.IFACE_NAME, |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 39 | } |
| 40 | |
Brad Bishop | 2fa78fb | 2016-08-30 19:51:51 -0400 | [diff] [blame] | 41 | |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 42 | class Hwmons(): |
Brad Bishop | 2fa78fb | 2016-08-30 19:51:51 -0400 | [diff] [blame] | 43 | def __init__(self, bus): |
| 44 | self.sensors = {} |
| 45 | self.hwmon_root = {} |
Brad Bishop | 67a6f45 | 2016-08-30 19:56:58 -0400 | [diff] [blame^] | 46 | |
| 47 | if have_system: |
| 48 | self.scanDirectory() |
| 49 | gobject.timeout_add(DIR_POLL_INTERVAL, self.scanDirectory) |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 50 | |
Brad Bishop | 2fa78fb | 2016-08-30 19:51:51 -0400 | [diff] [blame] | 51 | def readAttribute(self, filename): |
| 52 | val = "-1" |
| 53 | try: |
| 54 | with open(filename, 'r') as f: |
| 55 | for line in f: |
| 56 | val = line.rstrip('\n') |
| 57 | except (OSError, IOError): |
| 58 | print "Cannot read attributes:", filename |
| 59 | return val |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 60 | |
Brad Bishop | 2fa78fb | 2016-08-30 19:51:51 -0400 | [diff] [blame] | 61 | def writeAttribute(self, filename, value): |
| 62 | with open(filename, 'w') as f: |
| 63 | f.write(str(value)+'\n') |
| 64 | |
| 65 | def poll(self, objpath, attribute): |
| 66 | try: |
| 67 | raw_value = int(self.readAttribute(attribute)) |
| 68 | obj = bus.get_object(SENSOR_BUS, objpath, introspect=False) |
| 69 | intf = dbus.Interface(obj, HwmonSensor.IFACE_NAME) |
| 70 | rtn = intf.setByPoll(raw_value) |
| 71 | if rtn[0]: |
| 72 | self.writeAttribute(attribute, rtn[1]) |
| 73 | except: |
| 74 | print "HWMON: Attibute no longer exists: "+attribute |
| 75 | self.sensors.pop(objpath, None) |
| 76 | return False |
| 77 | |
| 78 | return True |
| 79 | |
| 80 | def addObject(self, dpath, hwmon_path, hwmon): |
| 81 | objsuf = hwmon['object_path'] |
| 82 | objpath = SENSOR_PATH+'/'+objsuf |
| 83 | |
| 84 | if objpath not in self.sensors: |
| 85 | print "HWMON add: "+objpath+" : "+hwmon_path |
| 86 | |
| 87 | ## register object with sensor manager |
| 88 | obj = bus.get_object(SENSOR_BUS, SENSOR_PATH, introspect=False) |
| 89 | intf = dbus.Interface(obj, SENSOR_BUS) |
| 90 | intf.register("HwmonSensor", objpath) |
| 91 | |
| 92 | ## set some properties in dbus object |
| 93 | obj = bus.get_object(SENSOR_BUS, objpath, introspect=False) |
| 94 | intf = dbus.Interface(obj, dbus.PROPERTIES_IFACE) |
| 95 | intf.Set(HwmonSensor.IFACE_NAME, 'filename', hwmon_path) |
| 96 | |
| 97 | ## check if one of thresholds is defined to know |
| 98 | ## whether to enable thresholds or not |
| 99 | if 'critical_upper' in hwmon: |
| 100 | intf.Set( |
| 101 | SensorThresholds.IFACE_NAME, 'thresholds_enabled', True) |
| 102 | |
| 103 | for prop in hwmon.keys(): |
| 104 | if prop in IFACE_LOOKUP: |
| 105 | intf.Set(IFACE_LOOKUP[prop], prop, hwmon[prop]) |
| 106 | print "Setting: "+prop+" = "+str(hwmon[prop]) |
| 107 | |
| 108 | self.sensors[objpath] = True |
| 109 | self.hwmon_root[dpath].append(objpath) |
| 110 | gobject.timeout_add( |
| 111 | hwmon['poll_interval'], self.poll, objpath, hwmon_path) |
| 112 | |
| 113 | def scanDirectory(self): |
| 114 | devices = os.listdir(HWMON_PATH) |
| 115 | found_hwmon = {} |
| 116 | regx = re.compile('([a-z]+)\d+\_') |
| 117 | for d in devices: |
| 118 | dpath = HWMON_PATH+'/'+d+'/' |
| 119 | found_hwmon[dpath] = True |
| 120 | if dpath not in self.hwmon_root: |
| 121 | self.hwmon_root[dpath] = [] |
| 122 | ## the instance name is a soft link |
| 123 | instance_name = os.path.realpath(dpath+'device').split('/').pop() |
| 124 | |
| 125 | if instance_name in System.HWMON_CONFIG: |
| 126 | hwmon = System.HWMON_CONFIG[instance_name] |
| 127 | |
| 128 | if 'labels' in hwmon: |
| 129 | label_files = glob.glob(dpath+'/*_label') |
| 130 | for f in label_files: |
| 131 | label_key = self.readAttribute(f) |
| 132 | if label_key in hwmon['labels']: |
| 133 | namef = f.replace('_label', '_input') |
| 134 | self.addObject( |
| 135 | dpath, namef, hwmon['labels'][label_key]) |
| 136 | else: |
| 137 | pass |
| 138 | |
| 139 | if 'names' in hwmon: |
| 140 | for attribute in hwmon['names'].keys(): |
| 141 | self.addObject( |
| 142 | dpath, dpath+attribute, hwmon['names'][attribute]) |
| 143 | |
| 144 | else: |
| 145 | print "WARNING - hwmon: Unhandled hwmon: "+dpath |
| 146 | |
| 147 | for k in self.hwmon_root.keys(): |
| 148 | if k not in found_hwmon: |
| 149 | ## need to remove all objects associated with this path |
| 150 | print "Removing: "+k |
| 151 | for objpath in self.hwmon_root[k]: |
| 152 | if objpath in self.sensors: |
| 153 | print "HWMON remove: "+objpath |
| 154 | self.sensors.pop(objpath, None) |
| 155 | obj = bus.get_object( |
| 156 | SENSOR_BUS, SENSOR_PATH, introspect=False) |
| 157 | intf = dbus.Interface(obj, SENSOR_BUS) |
| 158 | intf.delete(objpath) |
| 159 | |
| 160 | self.hwmon_root.pop(k, None) |
| 161 | |
| 162 | return True |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 163 | |
| 164 | |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 165 | if __name__ == '__main__': |
Brad Bishop | 2fa78fb | 2016-08-30 19:51:51 -0400 | [diff] [blame] | 166 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) |
| 167 | bus = get_dbus() |
| 168 | root_sensor = Hwmons(bus) |
| 169 | mainloop = gobject.MainLoop() |
Norman James | 323ed97 | 2015-12-09 09:06:37 -0600 | [diff] [blame] | 170 | |
Brad Bishop | 2fa78fb | 2016-08-30 19:51:51 -0400 | [diff] [blame] | 171 | print "Starting HWMON sensors" |
| 172 | mainloop.run() |