@akospasztor/homebridge-create-ceiling-fan - v1.3.0
    Preparing search index...

    Class CreateCeilingFanAccessory

    CreateCeilingFanAccessory: the accessory implementation for CREATE ceiling fans.

    This class contains the accessory implementation and follows the Homebridge plugin development recommendations.

    Service Characteristics
    Fanv2 Active, Rotation Direction, Rotation Speed
    Lightbulb On

    Note: the Lightbulb service is only exposed if the accessory has been configured with the light option enabled.

    CREATE fans have speed settings ranging from 1 (lowest) to 6 (highest). The HomeKit UI slider for the fan rotation speed provides a value from 1 to 100 and 0 means the fan is turned off. The slider steps can be configured to a desired value via the Min Step Characteristic. This works well e.g. for Dyson devices where the speed settings ranges from 1 to 10. In this case the Min Step Characteristic can be configured to 10, resulting in a nice user experience where the 0 - 100 UI slider is divided into 10 steps. However, this does not work well for CREATE fans with 6 speed steps. In order to provide smooth user experience, the following representation is implemented:

    • The UI slider is configured with the default Min Step Characteristic of 1. This provides smooth and fluid user input and slider operation.

    • The following UI slider inputs represent the different speed settings of the fan:

      Device fan speed Corresponding UI slider value User input range on the slider
      1 10 1 - 19
      2 30 20 - 39
      3 50 40 - 59
      4 70 60 - 79
      5 90 80 - 94
      6 100 95 - 100
    • When the user operates the slider, a debouncing timer with the value of fanSetSpeedDebouncePeriod member is set. When the timer fires, the current state of the slider value is converted to the nearest value that corresponds to the device fan speed. The purpose of the debounce timer is to provide great user experience. Without the debounce timer, every moment the user slides the finger would result in generating lots of events - making the slider jump around immediately, without waiting for the user to finish adjusting the speed.

       UI slider    │ Fan speed
       input value  │ value
       ─────────────┼──────────────
       ┌──────┐     │
       │ 100 ─┼─────┼─► Fan speed 6
       │      │ ▲   │
       │  95  ├─┘   │
       │  94  ├─┐   │
       │      │ ▼   │
       │  90 ─┼─────┼─► Fan speed 5
       │      │ ▲   │
       │  80  ├─┘   │
       │  79  ├─┐   │
       │      │ ▼   │
       │  70 ─┼─────┼─► Fan speed 4
       │      │ ▲   │
       │  60  ├─┘   │
       │  59  ├─┐   │
       │      │ ▼   │
       │  50 ─┼─────┼─► Fan speed 3
       │      │ ▲   │
       │  40  ├─┘   │
       │  39  ├─┐   │
       │      │ ▼   │
       │  30 ─┼─────┼─► Fan speed 2
       │      │ ▲   │
       │  20  ├─┘   │
       │  19  ├─┐   │
       │      │ ▼   │
       │  10 ─┼─────┼─► Fan speed 1
       │      │ ▲   │
       │   1  ├─┘   │
       │   0 ─┼─────┼─► Fan off
       └──────┘     │
      

    The rotation of the device as seen from standing below the fan follows the HomeKit rotation representation.

    Device direction raw value HomeKit representation Fan operation
    forward (default) Counter-clockwise Fan blows downwards (i.e. summer mode)
    reverse Clockwise Fan blows upwards (i.e. winter mode)

    The fan is a Tuya-compatible device and its firmware is mildly put: not the best. Among other issues, devices with these firmware are known to stop responding to commands, randomly drop connection, etc (see e.g. https://github.com/jasonacox/tinytuya/discussions/443 and https://github.com/moifort/homebridge-create-fan/issues/18).

    To provide reliable operation via HomeKit, this plugin implements the device communication the following way:

    • The device accepts one connection at a time. Therefore, a mutex with a waiting queue is used for ensuring that only one command is sent to the device at a time. For detailed description refer to: Mutex.
    • The device state is cached. Whenever the device state is requested by HomeKit (e.g. the user opens up the Home app), the implementation immediately returns the requested value from the cache.
    • The status of the device is periodically (defined by getDeviceStatusPeriod) queried from the device. After obtaining the device status, the device state cache as well as the HomeKit Characteristics are automatically updated.
    • If the device fails to respond to the get status request, the polling period is reduced significantly (defined by getDeviceStatusFastRetryPeriod), so that the attempt is retried quickly.
    • The communication with the device happens in a synchronous way, supported by the mutex queue and timeout mechanism. This seems to provide the most reliable communication with the device.

    Communication failure tends to happen when attempting to control the device via HomeKit right after using the device's physical remote. The device used for development & testing (CREATE Wind Calm model purchased in 2025) seemed to always recover from a failed communication latest after a few retry attempts.

    Index

    Constructors

    Properties

    accessory: PlatformAccessory

    The homebridge platform accessory object.

    deviceCommunicator: TuyaDevice
    fanRotationSpeedNormalized: readonly number[] = ...
    fanService: Service
    fanSetSpeedDebouncePeriod: number = 500
    fanSetSpeedDebounceTimer: null | Timeout = null
    getDeviceStatusConnectTimeout: number = 3000
    getDeviceStatusFastRetryPeriod: number = 1000
    getDeviceStatusPeriod: number = 10000
    getDeviceStatusReadTimeout: number = 1000
    getDeviceStatusTimer: Timeout
    isGetStatusInProgress: boolean = false
    lightService: undefined | Service
    mutex: Mutex

    The plugin platform object.

    setDeviceStatusTimeout: number = 2500
    state: {
        fanOn: boolean;
        fanRotationClockwise: boolean;
        fanSpeed: number;
        isValid: boolean;
        lightOn: boolean;
    } = ...

    Methods

    • Adjust the rotation speed input value.

      This method is used for converting the input state of the slider value to the nearest value that corresponds to the device fan speed.

      See the CreateCeilingFanAccessory class description for more details.

      Parameters

      • value: number

        The input value of the rotation speed.

      Returns number

      The adjusted value of the rotation speed.

    • Convert the fan active state of the accessory to Fanv2 Active characteristic value.

      Returns CharacteristicValue

      The Fanv2 Active characteristic value.

    • Convert the fan rotation direction of the accessory to Fanv2 Rotation Direction characteristic value.

      Returns CharacteristicValue

      The Fanv2 Rotation Direction characteristic value.

    • Convert the fan rotation speed of the accessory to Fanv2 Rotation Speed characteristic value.

      Returns CharacteristicValue

      The Fanv2 Rotation Speed characteristic value.

    • Get device status.

      This method reads the status of the device periodically and updates the accessory state after completing the operation. The actual communication is carried out with a timeout mechanism, so that an unresponsive device will not make the plugin and HomeKit unresponsive. If the communication fails, the periodic timer will be set with a shorter timeout so that the next retry attempt happens fast. After the communication with the device is recovered, the period will be reset to the original period value.

      The function can be called in two ways:

      1. Calling it with await: the method starts the reading operation and waits (i.e. blocks) until the reading has been completed (or timed out).
      2. Simply calling it (without await): the method starts the reading operation and returns right afterwards, not waiting for the reading to be completed. This is used when handling accessory GET requests from HomeKit. Get requests should return as fast as possible, because long delays will result in HomeKit being unresponsive and a bad user experience in general.

      If the function is called again while there is already an ongoing read operation, the reading will simply be skipped - the accessory status will be updated anyway after executing the already ongoing reading operation. This can happen e.g. when a periodic read operation is already in place and a GET request arrives from HomeKit at the same time.

      Returns Promise<void>

    • Handle the get requests from HomeKit to get the current value of the Fanv2 Active characteristic

      Returns Promise<CharacteristicValue>

      The Fanv2 Active characteristic value from the device state cache.

    • Handle the set requests from HomeKit to set the device with the Fanv2 Active characteristic value

      Parameters

      • value: CharacteristicValue

        The Fanv2 Active characteristic value to be set.

      Returns Promise<void>

    • Handle the get requests from HomeKit to get the current value of the Fanv2 Rotation Direction characteristic

      Returns Promise<CharacteristicValue>

      The Fanv2 Rotation Direction characteristic value from the device state cache.

    • Handle the set requests from HomeKit to set the device with the Fanv2 Rotation Direction characteristic value

      Parameters

      • value: CharacteristicValue

        The Fanv2 Rotation Direction characteristic value to be set.

      Returns Promise<void>

    • Handle the get requests from HomeKit to get the current value of the Fanv2 Rotation Speed characteristic

      Returns Promise<CharacteristicValue>

      The Fanv2 Rotation Speed characteristic value from the device state cache.

    • Handle the set requests from HomeKit to set the device with the Fanv2 Rotation Speed characteristic value

      Parameters

      • value: CharacteristicValue

        The Fanv2 Rotation Speed characteristic value to be set.

      Returns Promise<void>

    • Handle the get requests from HomeKit to get the current value of the Lightbulb On characteristic

      Returns Promise<CharacteristicValue>

      The Lightbulb On characteristic value from the device state cache.

    • Handle the set requests from HomeKit to set the device with the Lightbulb On characteristic value

      Parameters

      • value: CharacteristicValue

        The Lightbulb On characteristic value to be set.

      Returns Promise<void>

    • Convert the light on state of the accessory to Lightbulb On characteristic value.

      Returns CharacteristicValue

      The Lightbulb On characteristic value.

    • Wrapper function to log device communication errors depending on the device configuration.

      By default, the device communication errors are logged as debug logs, and they are only visible if the Homebridge Debug Mode is enabled. If the corresponding setting is set in the device configuration, the communication errors are logged as info messages and they are visible in the Homebridge log regardless whether the Homebridge Debug Mode is enabled.

      Parameters

      • message: string

        Message to be logged; analogous to the Logger interface.

      • ...parameters: unknown[]

        Additional arguments; analogous to the Logger interface.

      Returns void

    • Set device value.

      This method sends a command to the device to set the device into the required state. Only one parameter can be set at a time.

      Parameters

      • dps: number

        The data point index of the device to be set.

      • value: string | number | boolean

        The value to be set.

      Returns Promise<void>

    • Set device value with timeout.

      This is a simple wrapper for the setDeviceValue method with a timeout mechanism. If the method fails to execute within the setDeviceStatusTimeout value, it throws a HomeKit No Response status.

      Parameters

      • dps: number

        The data point index of the device to be set.

      • value: string | number | boolean

        The value to be set.

      Returns Promise<void>

    • Throw a HomeKit No Response status if the accessory state is invalid.

      Returns void

    • Update all accessory service characteristics based on the accessory state.

      Returns void

    • Update the accessory state with the values received from the device.

      Parameters

      • status: DPSObject

        The raw data points object received from the device.

      Returns void

    • Wait for a promise to be resolved within a given timeout.

      Type Parameters

      • T

      Parameters

      • promise: Promise<T>

        The promise to be resolved within a given timeout.

      • ms: number

        The timeout in [ms] within the promise should be resolved.

      Returns Promise<T>

      The resolved promise if it gets resolved within the timeout, otherwise reject the promise.