@@ -297,7 +297,7 @@ def create_sensor(sensor_name, value, value_type, value_scale, label=None):
297297 except (FileNotFoundError , ValueError , IOError ):
298298 continue
299299
300- # Fan sensors
300+ # Fan sensors (RPM from tachometer)
301301 for fan_file in glob .glob (os .path .join (hwmon_path , "fan*_input" )):
302302 try :
303303 sensor_num = os .path .basename (fan_file ).split ('_' )[0 ].replace ('fan' , '' )
@@ -314,6 +314,36 @@ def create_sensor(sensor_name, value, value_type, value_scale, label=None):
314314 except (FileNotFoundError , ValueError , IOError ):
315315 continue
316316
317+ # PWM fan sensors (duty cycle percentage)
318+ # Only add if no fan*_input exists for this device (avoid duplicates)
319+ has_rpm_sensor = bool (glob .glob (os .path .join (hwmon_path , "fan*_input" )))
320+ if not has_rpm_sensor :
321+ for pwm_file in glob .glob (os .path .join (hwmon_path , "pwm[0-9]*" )):
322+ # Skip pwm*_enable, pwm*_mode, etc. - only process pwm1, pwm2, etc.
323+ pwm_basename = os .path .basename (pwm_file )
324+ if not pwm_basename .replace ('pwm' , '' ).isdigit ():
325+ continue
326+ try :
327+ sensor_num = pwm_basename .replace ('pwm' , '' )
328+ pwm_raw = int (HOST .read (pwm_file ).strip ())
329+ # Convert PWM duty cycle (0-255) to percentage (0-100)
330+ # Note: Some devices are inverted (255=off, 0=max), but we report as-is
331+ # The value represents duty cycle, not necessarily fan speed
332+ # Use "other" value-type since PWM duty cycle isn't a standard IETF type
333+ value = int ((pwm_raw / 255.0 ) * 100 * 1000 ) # Convert to milli-percent (0-100000)
334+ label_file = os .path .join (hwmon_path , f"pwm{ sensor_num } _label" )
335+ raw_label = None
336+ if HOST .exists (label_file ):
337+ raw_label = HOST .read (label_file ).strip ()
338+ label = normalize_sensor_name (raw_label )
339+ sensor_name = f"{ base_name } -{ label } "
340+ else :
341+ sensor_name = base_name if sensor_num == '1' else f"{ base_name } { sensor_num } "
342+ # Use "PWM Fan" as description so it displays nicely in show hardware
343+ add_sensor (base_name , create_sensor (sensor_name , value , "other" , "milli" , raw_label or "PWM Fan" ))
344+ except (FileNotFoundError , ValueError , IOError ):
345+ continue
346+
317347 # Voltage sensors
318348 for voltage_file in glob .glob (os .path .join (hwmon_path , "in*_input" )):
319349 try :
0 commit comments