HomeKit Controller Integration & Hunter fan driver

I recently upgraded to a C-8 Pro, hoping to control all of my Hunter fans through Hubitat, but I’m running into an issue with fan control.

I added the devices using the HomeKit Controller integration. A HomeKit parent device was created with two child devices:

  • Light (device type: HomeKit Dimmer)
  • Fan (device type: HomeKit Fan)

The problem is that the fan ON/OFF control does not work, although I can control the fan speed through Hubitat.

Has anyone been able to fix or modify the fan driver to get ON/OFF control working correctly? Please advise

Below is the raw data I see for the fan device: FAN_V2

{"CHARACTERISTIC_2BD83CC4-6C60-11E5-A837-0800200C9A66":"0","CHARACTERISTIC_2BD83CC5-6C60-11E5-A837-0800200C9A66":"0","ACTIVE":"0","CHARACTERISTIC_2BD83CC8-6C60-11E5-A837-0800200C9A66":"0","ROTATION_DIRECTION":"0","AUDIO_FEEDBACK":"1","CHARACTERISTIC_2BD83CC3-6C60-11E5-A837-0800200C9A66":"0","CHARACTERISTIC_2BD83CC0-6C60-11E5-A837-0800200C9A66":"0","ROTATION_SPEED":"0","CHARACTERISTIC_2BD83CC1-6C60-11E5-A837-0800200C9A66":"0","ON":"0"}

Anyone have same problem pls help

I just paired a TAPO light/fan Homekit device. Paired to HE just fine. I can control the light just fine.

I have the same issue with the fan that mentioned here. Can't turn it on or off. If I turn it on or off from the switch HE shows the correct status. If I set a speed in HE the fan will change speed then a couple seconds later the speed goes to zero.

Correction to my post: Apparently the speed/dimmer bars go blank after a few seconds. Actual value doesn't change.

So only issue I seem to have now is being able to turn the fan on/off. Same as @msmatn

Not sure who to tag. @gopher.ny

Do you have an link for the device?

Not sure about the Hunter, but doing some playing with mine I came up with an observation.

I don't have this installed yet, just sitting on desk with a patch cord to power it up.

I removed it from HE, reset it, added it back into Home. There is no on/off switch in Home, just a slider to control the speed. This particular unit allows 4 speeds, 25%, 50%, 75%, and 100%. When you adjust the speed it will latch in at one of those. In Home when you set it at 0% it shuts off. In HE setting it to 0% it stays at 25%. So don't know if there is some limit in HE driver or what that might cause that.

Just some observations if they are of any help.

1 Like

I have the same problem with the hunter fan. In HE the ON/OFF function does not work. But when I increase the speed from 0 it powers ON and to power OFF I have to set the speed below 25%.

So I am using Alexa skill to link the HE device to alex. To power ON the fan I must ask Alexa to increase the fan speed and to power OFF, ask to Alexa to reduce fan speed until it goes below 25%

I used home assistant before and it doesn't have this problem controlling the same fan.

I've bought one, it will take a couple of days to get here. We'll see what endpoints it exposes.

Do you want to see the end point for the hunter fan m

I actually returned mine. Not so much because of this issue but just didn't like the physical layout. The missus was not happy with the small button to manually turn light or fan on. But will be interested in seeing what you find out.

EDIT: Found this one which I am going to try. It's fan only and that's all we needed.

Let me know how you like it. I am looking into fan control options. Though I would really like something that will let me switch the direction as well without needing to flip a switch on the fan...

1 Like

Inovelli has a couple options but the price is about double. When ever I add something new I’m trying to keep it ‘generic’ so to speak for the next owner of the house. Thus trying to avoid Zwave or Zigbee. At our age the next move will be to either a nursing home or cemetery… So whatever is here stays.

Got the Leviton Fan switch. Complete control from Apple Home.

Added it to HE. Can't issue a straight on/off command. But if I enter a speed value it turns it on. Rounds the actual speed to 25 or 50 or 75 or 100. That is fine. If I enter a speed less than 13 it will turn it off. Except zero. 1 will work but not zero.

So all in all that is aceptable for me. The on/off would be nice but I can make it work otherwise.

It appears that in general homekit fan ON/OFF function is not working across all devices.

Installed the switch. Wrote an app to control it using virtual switches. On/Off, change speed, etc. Using those I can control it from Google or Apple Home. Seems to be working great.

I did similar to pairing it with virtual switch and sync using rules. Can you share your script and if that is efficient and I can adapt it

I wrote this specific for use on a bedroom fan. So it will have reference to bedroom in the code. But you're welcome to it.

/**
 *  Fan Control
 *
 *  Copyright 2026 Jim White
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */
definition(
    name: "Fan Controller",
    namespace: "jwwhite001",
    author: "Jim White",
    description: "Control Bedroom Fans",
    category: "My Apps",
    iconUrl: "",
    iconX2Url: "",
    iconX3Url: "")


preferences {
		section("Bedroom Fan") {
    	      input "BRfanSwitch", "capability.switch", required: true, multiple: false, title: "Fan Wall Switch"

    	      input "BRfanONOFF", "capability.switch", required: true, multiple: false, title: "Fan On/Off Switch"
    	      input "BRfanSpeedUp", "capability.switch", required: true, multiple: false, title: "Increase Fan Speed Switch"
    	      input "BRfanSpeedDwn", "capability.switch", required: true, multiple: false, title: "Decrease Fan Speed Switch"

        }
}


def installed() {
	log.debug "Installed with settings: ${settings}"
	unsubscribe()
    unschedule
	initialize()
}

def updated() {
	log.debug "Updated with settings: ${settings}"

	unsubscribe()
    unschedule
	initialize()
}

def initialize() {

    subscribe(BRfanSwitch,"switch",BRfanManual)
    subscribe(BRfanONOFF,"switch",BRfanAuto)

    subscribe(BRfanSpeedUp,"switch",BRSpeedUp)
    subscribe(BRfanSpeedDwn,"switch",BRSpeedDwn)

}

//Control Routines

def BRfanManual(evt) {
    if (evt.value == "on") {
        BRfanONOFF.on()
        BRfanSwitch.setLevel(50)
    }
    if (evt.value == "off") {
        BRfanONOFF.off()
    }
}

def BRfanAuto(evt) {

    if (evt.value == "on") {
        if (BRfanSwitch.currentswitch == "off") {
            BRfanSwitch.setLevel(50)
        }
    }
    if (evt.value == "off") {
        if (BRfanSwitch.currentswitch == "on") {
            BRfanSwitch.setLevel(10)
        }
    }
}

def BRSpeedUp(evt) {
    if (evt.value == "on" && BRfanSwitch.currentswitch == "on") {
        if (BRfanSwitch.currentLevel == 25) {BRfanSwitch.setLevel(50)}
        if (BRfanSwitch.currentLevel == 50) {BRfanSwitch.setLevel(75)}
        if (BRfanSwitch.currentLevel == 75) {BRfanSwitch.setLevel(100)}
    }
}

def BRSpeedDwn(evt) {
    if (evt.value == "on" && BRfanSwitch.currentswitch == "on") {
        if (BRfanSwitch.currentLevel == 100) {BRfanSwitch.setLevel(75)}
        if (BRfanSwitch.currentLevel == 75) {BRfanSwitch.setLevel(50)}
        if (BRfanSwitch.currentLevel == 50) {BRfanSwitch.setLevel(25)}
    }
}


1 Like

Thanks much. i tried the app and was able to make it work with my Hunter fan. So it has 3 virtual switches and also when you enable it to Alexa/Google did you enable all the three virtual switches and call each a different name? By the way rather than using 3 virtual switch, can this be done with one single virtual dimmer?

i tried to play around with your code to replace the 3 virtual switches with 1 virtual dimmer. ON, speed increase and decrease works but i cannot Switch off the fan, tired multiple options as suggested by chatgpt but still OFF function doesn't work.

/**
 *  Fan Controller - Single Virtual Dimmer with Minimal OFF Fix
 *
 *  Copyright 2026 Jim White
 */

definition(
    name: "Fan Controller Single Dimmer Fixed OFF 15",
    namespace: "jwwhite001",
    author: "Jim White",
    description: "Control Bedroom Fans with a single virtual dimmer, minimal speed on OFF, and retain last speed",
    category: "My Apps",
    iconUrl: "",
    iconX2Url: "",
    iconX3Url: ""
)

preferences {
    section("Bedroom Fan") {
        input "fanDimmer", "capability.switchLevel", required: true, multiple: false, title: "Virtual Fan Dimmer"
        input "fanDevice", "capability.switchLevel", required: true, multiple: false, title: "Actual Fan Device"
    }
}

// Lifecycle methods
def installed() {
    log.debug "Installed with settings: ${settings}"
    unsubscribe()
    unschedule()
    initialize()
}

def updated() {
    log.debug "Updated with settings: ${settings}"
    unsubscribe()
    unschedule()
    initialize()
}

def initialize() {
    // Subscribe to virtual dimmer events
    subscribe(fanDimmer, "switch", dimmerHandler)
    subscribe(fanDimmer, "level", dimmerHandler)

    // Initialize lastLevel if not set
    if (!state.lastLevel) {
        state.lastLevel = 33
    }
}

// Handler for dimmer changes
def dimmerHandler(evt) {
    // Ignore programmatic events caused by setLevel()
    if (state.ignoreNextLevelEvent) {
        log.debug "Ignoring programmatic event: ${evt.name}=${evt.value}"
        state.ignoreNextLevelEvent = false
        return
    }

    def level = fanDimmer.currentLevel
    log.debug "Dimmer event: ${evt.name} = ${evt.value}, currentLevel = ${level}, lastLevel = ${state.lastLevel}"

    // -------------------
    // Switch OFF → minimal speed 10
    // -------------------
    if (evt.name == "switch" && evt.value == "off") {
        if (!state.lastLevel || state.lastLevel == 10) state.lastLevel = 33

        // Set guard before changing dimmer to avoid feedback
        state.ignoreNextLevelEvent = true

        // Set fan to minimal speed 10 without turning it ON
        fanDevice.setLevel(10)

        // Keep virtual dimmer in sync
        if (fanDimmer.currentLevel != 10) fanDimmer.setLevel(10)

        return
    }

    // -------------------
    // Switch ON → restore last speed
    // -------------------
    if (evt.name == "switch" && evt.value == "on") {
        if (!state.lastLevel || state.lastLevel == 10) state.lastLevel = 33
        setFanSpeed(state.lastLevel)
        return
    }

    // -------------------
    // Slider level changes → map to discrete fan speeds
    // -------------------
    def newLevel = 0
    if (level == 0) {
        newLevel = 10
    } else if (level <= 33) {
        newLevel = 33
    } else if (level <= 66) {
        newLevel = 66
    } else {
        newLevel = 99
    }

    setFanSpeed(newLevel)

    // Only update lastLevel if not minimal
    if (newLevel != 10) {
        state.lastLevel = newLevel
    }
}

// Helper method to set fan speed
def setFanSpeed(level) {
    log.debug "Setting fan speed to ${level}"
    fanDevice.setLevel(level)

    // Only turn ON if level > 10
    if (level > 10) {
        fanDevice.on()
    }

    // Keep virtual dimmer in sync, avoid feedback
    if (fanDimmer.currentLevel != level) {
        state.ignoreNextLevelEvent = true
        fanDimmer.setLevel(level)
    }
}

The reason I did it this way was for voice control. The only thing I use Google for is voice control.

I didn't try a dimmer as there are only 4 speeds anyway. When I shared the switch back to Apple Home it shows up as a dimmer and works ok there. I use that as my 'dashboard' so to speak.

As far as turning off the fan. The original switch I had, Tapo one, I couldn't turn it off either. Setting the speed value low did not turn it off. This one seems to work differently. So don't know what the differences are. I think @gopher.ny is working on why the straight on/off commands don't work.