Custom integration for Home Assistant to configure ceiling fans for use with the Fanpy Card Lovelace card.
Fanpy Pro is the evolution of the Fanpy integration.
Fanpy allowed configuring ceiling fans using a Broadlink device to transmit RF commands, making non-smart fans controllable from Home Assistant. However, the main problem was desynchronization: when someone used the physical remote, the integration had no way of knowing the fan had changed state.
Fanpy Pro was born to solve this. The idea was to build a combined RF receiver and transmitter using an ESP32 + CC1101 module running ESPHome (based on the Daedilus dual-pin wiring). This way the integration could capture every RF code sent by the physical remote and keep state perfectly synchronized — removing the need for a Broadlink device entirely.
More info can be found at ESPHome project details
However, while all codes are captured correctly by ESPHome, some of them fail to trigger the fan when retransmitted (what appears to be an ESPHome bug). To work around this, Fanpy Pro introduced the Hybrid mode: the ESP32+CC1101 continues receiving all codes from the physical remote (keeping HA synchronized), while a Broadlink device handles transmission using the previously learned codes. This gives reliable synchronization with zero desync.
The Hybrid mode has been tested on Inspire brand fans sold at Leroy Merlin, specifically the Huelva L and Sirocco Plus models, where it works perfectly. If ESPHome transmission reliability improves in the future, the Broadlink could be removed entirely and the CC1101 alone would handle both receiving and transmitting.
Fanpy Pro is the backend companion for the Fanpy Card. While the card provides the frontend UI, this integration provides the configuration wizard and generates all the necessary entities and scripts.
- ✅ Multi-step setup wizard — area selection, mode choice, light/features toggles, gateway configuration, optional Broadlink transmitter setup
- ✅ Two integration modes — Remote (Gateway RF) and Direct (native
switch.*/light.*entities) - ✅ Hybrid RF+Broadlink mode — combine an ESP32+CC1101 gateway (receiver) with a Broadlink device (transmitter) for reliable code transmission
- ✅ Automatic entity creation — (Remote):
fan.*(power + speed),light.*(light),select.*(speed selector + timer count) - ✅ Automatic entity creation — (Direct):
select.*only (speed selector + timer count) — fan/light entities managed externally - ✅ State persistence — entities restore their last state after HA restart (power, speed, light)
- ✅ Timer support — configurable number of timer buttons (0-3), exposed via a
select.fanpypro_<prefix>_num_timersentity that the card reads at runtime. Timer entities are created manually with the native HA timer helper; the fan entity cancels active timers automatically when the fan turns off. Timer entities entitiy_id should look liketimer.ventilador_{area}_*. - ✅ Multi-language support — English, Spanish, Catalan
- ✅ HACS compatible
| Mode | Description | Integration | Card entity selection | Card service calls |
|---|---|---|---|---|
| Fanpy Remote | Fanpy entities (fan.fanpypro_*, light.fanpypro_*, select.fanpypro_*) + auto-generated ESPHome RF scripts |
Creates fan, light, select entities + Resync Luz button | Auto by prefix (fanpypro_ventilador_{area}_*) |
Calls fan.turn_on/off, fan.set_percentage, light.turn_on/off natively; speed via fan.set_percentage |
| Fanpy Direct | Fanpy speed select (select.fanpypro_*_velocidad) + user's own switch.* / light.* (Shelly) |
Creates only select.fanpypro_*_velocidad |
Manual (entity_fan, entity_light) |
Calls switch.turn_on/off, light.turn_on/off directly; speed via scripts |
The card also supports two manual modes (Helpers and Direct) that don't require the Fanpy integration -- see the card documentation for details.
- Open HACS.
- Search for Fanpy and install it.
- Restart Home Assistant.
Install using HACS before the integration is added to the default HACS repository.
- Open HACS within Home Assistant.
- Select the 3-dot button (top right) and then Custom repositories.
- In the dialog that appears, enter:
- Repository: Add the URL to the repository
- Category: Integration
- Click Add.
- Go to the Search tab of HACS and search for Fanpy.
- Install it and restart Home Assistant.
- Download the
fanpypro.zipfrom the latest release. - Unzip and copy
custom_components/fanpypro/to your Home Assistantcustom_componentsdirectory:/config/custom_components/fanpypro/ - Restart Home Assistant.
- After restart, go to Settings > Devices & Services > Add Integration.
- Search for Fanpy and select it.
- Follow the wizard steps:
Requires: ESPHome-based RF gateway (ESP32 + CC1101) with the Daedilus dual-pin wiring and a matching
gateway_{zone}_codes.yamlfile.
More info can be found at ESPHome project details
- Step 1 -- Mode: Select Remote
- Step 2 -- Area: Select the area where the fan is located and choose the fan number
- Step 3 -- Speeds: Set the number of speeds (1-10)
- Step 4 -- Light: Toggle whether the fan has a light
- Step 5 -- Light Features (if has light): Toggle color temperature and brightness controls
- Step 6 -- Timer: Select the number of timers (0-3)
- Step 7 -- Gateway: Select the RF gateway (e.g. Salon, Cocina, Pasillo). The dropdown is populated from files matching
gateway_*_codes.yamlin thefanpypro_codes/directory. - Step 8 -- Transmitter: Choose whether to use the RF gateway (ESP32+CC1101) or a Broadlink device as transmitter:
- No (default): Scripts use
esphome.*_transmit_rc_switchvia the CC1101 - Sí: A new form opens to configure a Broadlink device (select entity
remote.*, remote name, and the command codes for each function). Scripts useremote.send_commandvia the Broadlink instead
- No (default): Scripts use
Note: Even when using Broadlink as transmitter, the RF gateway continues to receive signals from the physical remote. This keeps the HA entities synchronized when you use the physical remote.
This mode creates fan.fanpypro_*, light.fanpypro_*, select.fanpypro_* entities plus a Resync Luz button (only if the fan has light). Scripts are auto-generated by the integration into {custom_components_dir}/fanpypro/generated/scripts.yaml - no manual script creation needed. Use the card in Fanpy Remote mode.
- Step 1 -- Mode: Select Direct
- Step 2 -- Area: Select the area where the fan is located and choose the fan number
- Step 3 -- Fan & Speeds: Select the existing
switch.*entity (e.g. your Shelly relay) and set the number of speeds - Step 4 -- Light: Toggle whether the fan has a light
- Step 5 -- Light Entity (if has light): Select the existing
light.*entity - Step 6 -- Light Features (if has light): Toggle color temperature and brightness controls
- Step 7 -- Timer: Select the number of timers (0-3). The card will show that many timer buttons and call native
timer.start/timer.cancelon the timer entities you create manually with the HA timer helper.
This mode creates only select.fanpypro_*_velocidad. The card reads your Shelly entities directly. Use the card in Fanpy Direct mode.
For the Gateway RF mode to work, you must have the corresponding codes files in:
{config_dir}/custom_components/fanpypro_codes/gateway_{zone}_codes.yaml
For example, if you select the Salon gateway, the integration looks for:
/config/custom_components/fanpypro_codes/gateway_salon_codes.yaml
These files contain the RC Switch codes captured from your physical remote. Without them:
- The gateway dropdown in the config flow will appear empty (no options to select)
- scripts.yaml will not be generated (auto-generation depends on code data)
- RF event synchronization will not work (the integration cannot match incoming RF codes to commands)
The integration itself will not crash on startup — it logs a warning and continues. But the fan will not respond to the physical remote and scripts will not be created.
Tip: After capturing codes (e.g., via ESPHome logs), save them as
gateway_{zone}_codes.yamlin the directory above before running the config flow. If you add a new gateway later, just create the corresponding file and restart HA.
After creating entities with the integration, add the card to your Lovelace dashboard:
type: custom:fanpy-card
mode: fanpypro_remote # or fanpypro_direct
prefix: ventilador_bodega # auto-generated by the integration
name: BODEGA # auto-generated by the integration
has_light: trueFor Fanpy Direct, you must also specify the entity IDs:
type: custom:fanpy-card
mode: fanpypro_direct
name: BODEGA
entity_fan: switch.shelly_relay_0
entity_light: light.shelly_rgb_1
has_light: trueFor Gateway RF mode, scripts are auto-generated into {custom_components_dir}/fanpypro/generated/scripts.yaml every time Home Assistant starts or the integration reloads — no manual creation needed.
Make sure your configuration.yaml includes your scripts:
script: !include scripts.yamlThe generated scripts use one of two transmission methods depending on your configuration:
- RF Gateway only — calls the ESPHome
transmit_rc_switchservice via the CC1101 - Broadlink combo — calls
remote.send_commandvia the Broadlink device
Entity state updates are handled by the integration's Python code — scripts only send the RF command. You can combine both methods in the same scripts.yaml: some fans can use CC1101 while others use Broadlink.
Make sure the command names match what you learned with remote.learn_command. You can test them with remote.send_command.
When you press a button in the Fanpy Card:
Card -> fan.set_percentage (service)
-> FanpyProFanEntity updates HA state (is_on, percentage)
-> Calls script.{prefix}_velocidad_{n} (RF via ESPHome CC1101)
-> Updates select.fanpypro_{prefix}_velocidad to match
Card -> fan.turn_off (service)
-> FanpyProFanEntity saves last speed, sets is_on=false
-> Cancels active timers (Python)
-> Calls script.{prefix}_power_off (RF via ESPHome CC1101)
Card -> fan.set_percentage (service)
-> FanpyProFanEntity updates HA state (is_on, percentage)
-> Calls script.{prefix}_velocidad_{n} (RF via Broadlink remote.send_command)
-> Updates select.fanpypro_{prefix}_velocidad to match
Card -> fan.turn_off (service)
-> FanpyProFanEntity saves last speed, sets is_on=false
-> Cancels active timers (Python)
-> Calls script.{prefix}_power_off (RF via Broadlink remote.send_command)
Card -> switch.turn_on/off (service, power)
Card -> light.turn_on/off (service, light)
Card -> script.{prefix}_velocidad_{n} (speed, RF via ESPHome)
The card calls switch.* / light.* entities directly. Speed scripts send the RF command — no entity updates are needed in scripts since the integration manages speed state via select.fanpypro_{prefix}_velocidad.
When you press the physical remote:
Remote button -> ESP32 gateway -> esphome.fanpypro_rf_code event
-> FanpyProFanEntity.async_process_rf_command()
-> Updates HA state (power, speed, light)
-> Does NOT re-send RF (avoids echo)
Each entity is created with:
- Friendly names:
Fanpy {Name},Fanpy {Name} Luz,Fanpy {Name} Velocidad - Entity IDs:
fan.fanpypro_{prefix}— fan power and speed (state: on/off, percentage)light.fanpypro_{prefix}_luz— light power (state: on/off)select.fanpypro_{prefix}_velocidad— speed selector (options: 1–N)select.fanpypro_{prefix}_num_timers— number of timer buttons (set via config flow)
The fanpypro_ prefix lets the card find related entities automatically.
To change settings after initial setup:
- Go to Settings > Devices & Services
- Find the Fanpy integration entry
- Remove and re-add it, selecting the new values
- Home Assistant 2025.12.5 or newer
- Fanpy Card v3.0.2 or newer (for the Lovelace UI)
git clone https://github.com/figorr/fanpypropro.git
cd fanpyproTo add a new language:
- Create
custom_components/fanpypro/translations/{lang}.jsonwith the same keys asen.json. - Submit a PR.
Apache-2.0. See LICENSE.





