Add normalized sensor data

For select values, provide normalized
data.

Use DCMI get power readings command to provide a system power value.

Use DCMI guidance to steer sensors for cpus and inlet.  Use
standard sensor reading code.

Change-Id: If6db6a3f2829aba4d0c62a360fa47fb0d4795704
This commit is contained in:
Jarrod Johnson 2023-10-20 16:35:15 -04:00
parent b67912283c
commit e2ba4f12fc
3 changed files with 87 additions and 1 deletions

View File

@ -778,6 +778,18 @@ class Command(object):
summary['badreadings'] = fallbackreadings
return summary
def get_system_power_watts(self):
self.oem_init()
return self._oem.get_system_power_watts(self)
def get_inlet_temperature(self):
self.oem_init()
return self._oem.get_inlet_temperature(self)
def get_average_processor_temperature(self):
self.oem_init()
return self._oem.get_average_processor_temperature(self)
def get_sensor_reading(self, sensorname):
"""Get a sensor reading by name

View File

@ -14,7 +14,7 @@
import pyghmi.exceptions as exc
import pyghmi.ipmi.private.constants as event_const
import struct
class OEMHandler(object):
"""Handler class for OEM capabilities.
@ -41,6 +41,79 @@ class OEMHandler(object):
"""
return {}
def get_system_power_watts(self, ipmicmd):
# Use DCMI getpower reading command
rsp = ipmicmd.xraw_command(netfn=0x2c, command=2, data=(0xdc, 1, 0, 0))
wattage = struct.unpack('<H', rsp['data'][1:3])[0]
return wattage
def get_average_processor_temperature(self, ipmicmd):
# DCMI suggests preferrence for 0x37 ('Air inlet')
# If not that, then 0x40 ('Air inlet')
# in practice, some implementations use 0x27 ('External environment')
if not hasattr(self, '_processor_names'):
self._processor_names = []
readings = []
if not self._processor_names:
sdr = ipmicmd.init_sdr()
for sensename in sdr.sensors:
sensor = sdr.sensors[sensename]
if sensor.reading_type != 1:
continue
if not sensor.baseunit:
continue
if sensor.sensor_type != 'Temperature':
continue
if sensor.entity == 'Processor':
self._processor_names.append(sensor.sensor_name)
readingvalues = []
tmplreading = None
for procsensor in self._processor_names:
try:
reading = ipmicmd.get_sensor_reading(procsensor)
except exc.IpmiException:
continue
tmplreading = reading
readingvalues.append(reading.value)
avgval = sum(readingvalues) / len(readingvalues)
tmplreading.name = 'Average Processor Temperature'
tmplreading.value = avgval
return tmplreading
def get_inlet_temperature(self, ipmicmd):
# DCMI suggests preferrence for 0x37 ('Air inlet')
# If not that, then 0x40 ('Air inlet')
# in practice, some implementations use 0x27 ('External environment')
if not hasattr(self, '_inlet_name'):
self._inlet_name = None
if self._inlet_name:
return ipmicmd.get_sensor_reading(self._inlet_name)
sdr = ipmicmd.init_sdr()
extenv = []
airinlets = []
for sensename in sdr.sensors:
sensor = sdr.sensors[sensename]
if sensor.reading_type != 1:
continue
if not sensor.baseunit:
continue
if sensor.sensor_type != 'Temperature':
continue
if sensor.entity == 'External environment':
extenv.append(sensor.sensor_name)
if sensor.entity == 'Air inlet':
airinlets.append(sensor.sensor_name)
if airinlets:
if len(airinlets) > 1:
raise Exception('TODO: how to deal with multiple inlets')
self._inlet_name = airinlets[0]
elif extenv:
if len(extenv) > 1:
raise Exception('TODO: how to deal with multiple external environments')
self._inlet_name = extenv[0]
return ipmicmd.get_sensor_reading(self._inlet_name)
def process_event(self, event, ipmicmd, seldata):
"""Modify an event according with OEM understanding.

View File

@ -28,6 +28,7 @@ class EnergyManager(object):
# get the handle (which has always been the same, but just in case
self.iana = bytearray(b'\x66\x4a\x00')
self._usefapm = False
self._mypowermeters = ()
try:
rsp = ipmicmd.xraw_command(netfn=0x3a, command=0x32, data=[4, 2, 0, 0, 0])
if len(rsp['data']) >= 8: