Here you go. note that this is actually authored by Andreas Spiess (Variable Speed Cooling Fan for Raspberry Pi using PWM (video#138) – SensorsIOT)
i have only added the code to publish fan speed and temperature to my MQTT broker, from where HA is picking it up. i have also trimmed the code down a bit to exclude the stuff he had for battery monitoring etc.
fancontrol.py
#!/usr/bin/env python3 # Author: Andreas Spiess import os import time from time import sleep import signal import sys import RPi.GPIO as GPIO import paho.mqtt.publish as publish fanPin = 17 # The pin ID, edit here to change it batterySensPin = 18 desiredTemp = 40 # The maximum temperature in Celsius after which we trigger the fan fanSpeed=100 sum=0 pTemp=15 iTemp=0.4 def Shutdown(): fanOFF() os.system("sudo shutdown -h 1") sleep(100) def getCPUtemperature(): res = os.popen('vcgencmd measure_temp').readline() temp =(res.replace("temp=","").replace("'C\n","")) #print("temp is {0}".format(temp)) #Uncomment here for testing return temp def fanOFF(): myPWM.ChangeDutyCycle(0) # switch fan off return() def handleFan(): global fanSpeed,sum actualTemp = float(getCPUtemperature()) diff=actualTemp-desiredTemp sum=sum+diff pDiff=diff*pTemp iDiff=sum*iTemp fanSpeed=pDiff +iDiff if fanSpeed>100: fanSpeed=100 if fanSpeed<15: fanSpeed=0 if sum>100: sum=100 if sum<-100: sum=-100 #print("actualTemp %4.2f TempDiff %4.2f pDiff %4.2f iDiff %4.2f fanSpeed %5d" % (actualTemp,diff,pDiff,iDiff,fanSpeed)) myPWM.ChangeDutyCycle(fanSpeed) msgs = [{'topic':"RPI/Temperature", 'payload':actualTemp}, ("RPI/FanSpeed", fanSpeed, 0, False)] publish.multiple(msgs, hostname="[mqtt server]", auth = {'username':"[mqtt server username]", 'password':"[mqtt server password]"}) return() def on_disconnect(client, userdata, rc): logging.info("disconnecting reason " +str(rc)) client.connected_flag=False client.disconnect_flag=True def handleBattery(): #print (GPIO.input(batterySensPin)) if GPIO.input(batterySensPin)==0: ("Shutdown()") sleep(5) Shutdown() return() def setPin(mode): # A little redundant function but useful if you want to add logging GPIO.output(fanPin, mode) return() try: GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) GPIO.setup(fanPin, GPIO.OUT) myPWM=GPIO.PWM(fanPin,50) myPWM.start(50) #GPIO.setup(batterySensPin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) GPIO.setwarnings(False) fanOFF() while True: handleFan() #handleBattery() sleep(5) # Read the temperature every 5 sec, increase or decrease this limit if you want except KeyboardInterrupt: # trap a CTRL+C keyboard interrupt fanOFF() GPIO.cleanup() # resets all GPIO ports used by this program except: print("probably mqtt connection failed")