Zum Inhalt springen

Temperature Curve Dual

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

The Temperature Curve Dual module holds two complete 5-point temperature-to-speed curves, A and B, and lets you switch between them from Home Assistant with a single switch. Curve A is meant to be an aggressive profile (cools hard, early) and curve B a defensive one (stays quiet longer, spins up later), but both are fully configurable.

Choose Temperature Curve Dual when you want two distinct fan profiles you can flip between, instead of constantly re-tuning a single curve. The classic case is pairing it with an air-quality automation: when the air is bad, a Home Assistant automation flips to the defensive curve so the fans stay quiet and ramp up later.

The module is sensor-agnostic. It does not read any air-quality sensor itself. Curve selection is just a switch; the automation logic lives in Home Assistant. For a single fixed curve, see Temperature Curve. The modules overview has a comparison table.

VariableDefaultDescription
friendly_name"Fancontroller"Device name prefix for the output sensor
curveA_temp1"20.0"Curve A temperature point 1 (C)
curveA_speed1"0.0"Curve A fan speed at point 1 (%)
curveA_temp2"22.0"Curve A temperature point 2 (C)
curveA_speed2"30.0"Curve A fan speed at point 2 (%)
curveA_temp3"28.0"Curve A temperature point 3 (C)
curveA_speed3"60.0"Curve A fan speed at point 3 (%)
curveA_temp4"35.0"Curve A temperature point 4 (C)
curveA_speed4"85.0"Curve A fan speed at point 4 (%)
curveA_temp5"40.0"Curve A temperature point 5 (C)
curveA_speed5"100.0"Curve A fan speed at point 5 (%)
curveB_temp1"25.0"Curve B temperature point 1 (C)
curveB_speed1"0.0"Curve B fan speed at point 1 (%)
curveB_temp2"35.0"Curve B temperature point 2 (C)
curveB_speed2"25.0"Curve B fan speed at point 2 (%)
curveB_temp3"45.0"Curve B temperature point 3 (C)
curveB_speed3"50.0"Curve B fan speed at point 3 (%)
curveB_temp4"50.0"Curve B temperature point 4 (C)
curveB_speed4"65.0"Curve B fan speed at point 4 (%)
curveB_temp5"55.0"Curve B temperature point 5 (C)
curveB_speed5"80.0"Curve B fan speed at point 5 (%)
temperature_sensor_id"fancontroller_temperature"Id of the sensor supplying the control temperature

Every 10 seconds the module reads the board temperature, picks the active curve based on the Curve Selection switch (off = A, on = B), sorts that curve’s five points by temperature, and linearly interpolates the fan speed. Below the lowest point it holds the first speed; above the highest point it holds the last speed.

The result drives all four fans, gated per fan by the Auto Control Fan 1Fan 4 switches and by any active user override, and clamped by each fan’s safety floor (the floor only applies to non-zero speeds; a commanded 0% always turns the fan off).

EntityTypePurpose
Curve SelectionswitchSelects curve A (off) or B (on). Remembers its last state across reboots.
Curve A/B Temperature 1—5, Speed 1—5number (20)The two curves’ points, editable live
Auto Control Fan 1—4switch (4)Per-fan enable for automatic control
$friendly_name Curve OutputsensorThe active curve’s computed fan speed (%)
Curve Configuration Warningbinary_sensorFlags a non-monotonic curve at boot

This block goes in your own configuration, not in the module. See why the assignment lives in the consuming config for the reason. version: 3 is what makes entity grouping work at all; without it, entity grouping has no effect.

web_server:
version: 3
sorting_groups:
- id: grp_temp_curve_dual
name: "Temperature Curve Dual"
sorting_weight: 120
number:
- id: !extend curveA_temp1
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 10
- id: !extend curveA_speed1
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 20
- id: !extend curveA_temp2
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 30
- id: !extend curveA_speed2
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 40
- id: !extend curveA_temp3
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 50
- id: !extend curveA_speed3
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 60
- id: !extend curveA_temp4
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 70
- id: !extend curveA_speed4
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 80
- id: !extend curveA_temp5
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 90
- id: !extend curveA_speed5
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 100
- id: !extend curveB_temp1
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 110
- id: !extend curveB_speed1
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 120
- id: !extend curveB_temp2
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 130
- id: !extend curveB_speed2
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 140
- id: !extend curveB_temp3
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 150
- id: !extend curveB_speed3
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 160
- id: !extend curveB_temp4
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 170
- id: !extend curveB_speed4
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 180
- id: !extend curveB_temp5
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 190
- id: !extend curveB_speed5
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 200
switch:
- id: !extend curve_select
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 210
- id: !extend auto_control_fan1
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 220
- id: !extend auto_control_fan2
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 230
- id: !extend auto_control_fan3
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 240
- id: !extend auto_control_fan4
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 250
sensor:
- id: !extend curve_output_value
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 260
binary_sensor:
- id: !extend curve_config_warning_sensor
web_server:
sorting_group_id: grp_temp_curve_dual
sorting_weight: 900

Pair the Curve Selection switch with a Home Assistant automation. For example, switch to the defensive curve when an air-quality sensor reports poor air:

automation:
- alias: "Defensive fan curve on poor air quality"
trigger:
- platform: numeric_state
entity_id: sensor.living_room_pm2_5
above: 35
action:
- service: switch.turn_on
target: { entity_id: switch.my_fancontroller_curve_selection }

See examples/with-temperature-curve-dual-rev-3.1.yaml for a complete configuration.

By default the module reads fancontroller_temperature, the onboard HDC1080 that every hardware package declares. Set temperature_sensor_id to the id of any other temperature sensor in your configuration to control from that instead:

packages:
# modules/bme680.yaml is not standalone - it needs the shared I2C bus (bus_a)
# that your hardware package declares. Use your own board revision here.
hardware:
url: https://github.com/zeroflow/wifi-fancontroller
ref: main
files: [hardware-rev-3.1.yaml]
bme680:
url: https://github.com/zeroflow/wifi-fancontroller
ref: main
files: [modules/bme680.yaml]
temperature_curve_dual:
url: https://github.com/zeroflow/wifi-fancontroller
ref: main
files:
- path: modules/temperature_curve_dual.yaml
vars:
temperature_sensor_id: "bme680_temperature"

Both curves read the same sensor; the A/B switch selects which curve is applied, not which sensor is used.

Omit the variable and it falls back to fancontroller_temperature, so existing configurations keep working unchanged. A misspelled id fails the build rather than quietly falling back to the onboard sensor.

The Qwiic modules build their sensor ids from an id-prefix substitution, so BME680 gives you bme680_temperature, SCD41 gives scd41_temperature, and DS2484 gives whatever ids you assign your own dallas_temp sensors.

If you also run the SSD1306 OLED module, note that it displays the onboard sensor regardless of this setting, so the screen and the fan control can show different temperatures.

The module names the sensor it is reading in its boot log, so you can confirm from a log dump that the override took effect.