diff --git a/docs/en/temperature_fan_control.md b/docs/en/temperature_fan_control.md new file mode 100644 index 0000000..95370db --- /dev/null +++ b/docs/en/temperature_fan_control.md @@ -0,0 +1,62 @@ +# Temperature fan control + +This package is designed to manage a fan with the objective to control the temperature of the solar router. +This module is reading the temperature from a `temperature limiter`. +The fan can be configured to start spinning as soon as the start temperature is reached and stop spinning when the measured temperature comes below the stop temperature. + +??? Note "More about the mechanism avoiding regulation bouncing" + The two thresholds regulation used here is named **hysteresis**. This mechanism avoids regulation bouncing. + See ***More details about hysteresis and Schmitt trigger*** in [temperature_limiter](temperature_limiter.md) page. + + +!!! danger "WARNING: Conduct some tests before letting the system regulate alone" + This fan control logic may have some bugs. It is strongly advised to validate the behaviour of your system carefully before letting the system working by its own. + +## Prerequisites + +This package is not standalone. It relies on symbols provided by two other packages that must be included in your configuration: + +- an `engine_*` package (e.g. `engine_1dimmer.yaml`) that provides the `activate` switch, +- a `temperature_limiter_*` package (e.g. `temperature_limiter_DS18B20.yaml`) that provides the `safety_temperature` sensor. + +## Cooling direction + +The fan is meant to cool the object monitored by `safety_temperature`. Fan **on** when the temperature rises above `fan_start_temperature`, fan **off** when it falls below `fan_stop_temperature`. if you need the opposite behaviour, this package is not the right fit. + +## Threshold invariant + +The two thresholds are coupled: `fan_start_temperature > fan_stop_temperature` is always enforced. If you change one of them to a value that would break the invariant, the other one is nudged automatically by 1 °C so a valid hysteresis is preserved: + +- setting `fan_stop_temperature` to a value `>=` the current `fan_start_temperature` pushes `fan_start_temperature` to `fan_stop_temperature + 1`, +- setting `fan_start_temperature` to a value `<=` the current `fan_stop_temperature` pulls `fan_stop_temperature` to `fan_start_temperature - 1`. + +You can therefore edit either value in any order without ever landing on an invalid configuration. + +## Wiring + +The energy available on a pin of the ESP32 is not sufficient to directly power the fan. It is then required to add an additional circuit to use 5V or 12V with the fan. + +The following schematic represents the wiring of the fan: + +![FanControl](images/fan_controller.png){width=400} + +## Configuration + +To use this package, add the following lines to your configuration file: + +```yaml linenums="1" +packages: + fan_controller: + url: https://github.com/hacf-fr/Solar-Router-for-ESPHome/ + files: + - path: solar_router/temperature_fan_control.yaml + vars: + fan_control_pin: GPIO4 +``` + +### Variables + +| Variable | Required | Default | Description | +| ---------------------- | -------- | --------- | -------------------------------------------------------------------------------------------- | +| `fan_control_pin` | yes | — | GPIO pin driving the fan control circuit. | +| `fan_control_inverted` | no | `"False"` | Set to `"True"` if the driving circuit inverts the logic (e.g. active‑low transistor stage). | diff --git a/docs/fr/temperature_fan_control.md b/docs/fr/temperature_fan_control.md new file mode 100644 index 0000000..f000d77 --- /dev/null +++ b/docs/fr/temperature_fan_control.md @@ -0,0 +1,62 @@ +# Contrôle du ventilateur + +Ce package est conçu pour piloter un ventilateur afin de contrôler la température du routeur solaire. +Ce module lit la température fournie par un `temperature limiter`. +Le ventilateur peut être configuré pour démarrer dès que la température de démarrage est atteinte et s'arrêter lorsque la température mesurée passe sous la température d'arrêt. + +??? Note "Détails du mécanisme de régulation anti-rebond" + La régulation à deux seuils utilisée ici est appelée **hystérésis**. Ce mécanisme évite les oscillations de la régulation. + Voir ***Plus de détails sur l'hystérésis et le trigger de Schmitt*** sur la page [temperature_limiter](temperature_limiter.md). + + +!!! danger "ATTENTION : effectuez des tests avant de laisser le système réguler seul" + La logique de contrôle du ventilateur peut contenir des bugs. Il est fortement conseillé de valider soigneusement le comportement de votre système avant de le laisser fonctionner seul. + +## Prérequis + +Ce package n'est pas autonome. Il repose sur des identifiants fournis par deux autres packages qui doivent être inclus dans votre configuration : + +- un package `engine_*` (par exemple `engine_1dimmer.yaml`) qui fournit l'interrupteur `activate`, +- un package `temperature_limiter_*` (par exemple `temperature_limiter_DS18B20.yaml`) qui fournit le capteur `safety_temperature`. + +## Sens de régulation + +Le ventilateur est destiné à refroidir l'élément surveillé par `safety_temperature`. Il se met en marche lorsque la température dépasse `fan_start_temperature` et s'arrête lorsqu'elle descend en dessous de `fan_stop_temperature`. Si vous avez besoin d'un fonctionnement inverse, ce paquet ne convient pas. + +## Invariant des seuils + +Les deux seuils sont couplés : `fan_start_temperature > fan_stop_temperature` est garanti en permanence. Si vous modifiez l'un des deux à une valeur qui casserait cet invariant, l'autre est automatiquement ajusté de 1 °C pour préserver une hystérésis valide : + +- fixer `fan_stop_temperature` à une valeur `>=` à l'actuel `fan_start_temperature` remonte `fan_start_temperature` à `fan_stop_temperature + 1`, +- fixer `fan_start_temperature` à une valeur `<=` à l'actuel `fan_stop_temperature` descend `fan_stop_temperature` à `fan_start_temperature - 1`. + +Vous pouvez donc modifier l'un ou l'autre des seuils dans n'importe quel ordre sans jamais tomber sur une configuration invalide. + +## Câblage + +L'énergie disponible sur une broche de l'ESP32 n'est pas suffisante pour alimenter directement un ventilateur. Il est donc nécessaire d'ajouter un circuit supplémentaire pour piloter un ventilateur en 5 V ou 12 V. + +Le schéma suivant présente le câblage du ventilateur : + +![FanControl](images/fan_controller.png){width=400} + +## Configuration + +Pour utiliser ce package, ajoutez les lignes suivantes à votre fichier de configuration : + +```yaml linenums="1" +packages: + fan_controller: + url: https://github.com/hacf-fr/Solar-Router-for-ESPHome/ + files: + - path: solar_router/temperature_fan_control.yaml + vars: + fan_control_pin: GPIO4 +``` + +### Variables + +| Variable | Obligatoire | Défaut | Description | +| ---------------------- | ----------- | --------- | --------------------------------------------------------------------------------------------------------------------- | +| `fan_control_pin` | oui | — | Broche GPIO qui pilote le circuit de commande du ventilateur. | +| `fan_control_inverted` | non | `"False"` | À mettre à `"True"` si le circuit de commande inverse la logique (par exemple étage à transistor actif à l'état bas). | diff --git a/docs/images/fan_controller.png b/docs/images/fan_controller.png new file mode 100644 index 0000000..cffb2fe Binary files /dev/null and b/docs/images/fan_controller.png differ diff --git a/docs/images/packages.drawio.png b/docs/images/packages.drawio.png index 28f1a1d..5029bd5 100644 Binary files a/docs/images/packages.drawio.png and b/docs/images/packages.drawio.png differ diff --git a/mkdocs.yml b/mkdocs.yml index cf90b1e..e3769aa 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,6 +43,7 @@ nav: - Overview: temperature_limiter.md - Home Assistant: temperature_limiter_home_assistant.md - DS18B20: temperature_limiter_DS18B20.md + - Fan controller: temperature_fan_control.md - Scheduler: - Overview: scheduler.md - Forced Run: scheduler_forced_run.md @@ -102,6 +103,7 @@ plugins: Contributing: Contribution Disclamer: Avertissement Energy Counter: Compteur d'énergie + Fan controller: Contrôle du ventilateur Usage Examples: Exemples d'utilisation Hardware: Materiel Home: Accueil diff --git a/solar_router/temperature_fan_control.yaml b/solar_router/temperature_fan_control.yaml new file mode 100644 index 0000000..b4ed76b --- /dev/null +++ b/solar_router/temperature_fan_control.yaml @@ -0,0 +1,90 @@ +substitutions: + fan_control_inverted: "False" + +number: + - platform: template + id: fan_stop_temperature + name: "Temperature to stop fan" + max_value: 99999 + initial_value: 40 + min_value: -273 + step: 1 + optimistic: True + mode: box + unit_of_measurement: "°C" + restore_value: true + # Enforce fan_start_temperature > fan_stop_temperature. + # If the user pushes stop to a value that would break the invariant, + # start is bumped just above it. + on_value: + then: + - if: + condition: + lambda: |- + return !isnan(id(fan_start_temperature).state) + && x >= id(fan_start_temperature).state; + then: + - number.set: + id: fan_start_temperature + value: !lambda 'return x + 1;' + + - platform: template + id: fan_start_temperature + name: "Temperature to start fan" + max_value: 99999 + initial_value: 50 + min_value: -273 + step: 1 + optimistic: True + mode: box + unit_of_measurement: "°C" + restore_value: true + # Symmetric guard: if start is pulled below stop, stop is lowered. + on_value: + then: + - if: + condition: + lambda: |- + return !isnan(id(fan_stop_temperature).state) + && x <= id(fan_stop_temperature).state; + then: + - number.set: + id: fan_stop_temperature + value: !lambda 'return x - 1;' + +interval: + # Trigger action every second + - interval: 1s + then: + - if: + condition: + switch.is_on: activate + then: + - script.execute: fan_control_check + +script: + - id: fan_control_check + mode: single + then: + - lambda: |- + if ( isnan( id(safety_temperature).state ) ){ + // Can't read temperature. Turn fan on as a failsafe. + id(fan_control).turn_on(); + return; + } + if (id(safety_temperature).state >= id(fan_start_temperature).state) + { + id(fan_control).turn_on(); + return; + } + if (id(safety_temperature).state <= id(fan_stop_temperature).state) + { + id(fan_control).turn_off(); + } + +output: + - id: fan_control + platform: gpio + pin: + number: ${fan_control_pin} + inverted: ${fan_control_inverted} diff --git a/solar_router/temperature_limiter_common.yaml b/solar_router/temperature_limiter_common.yaml index a2ef2d3..cb5038c 100644 --- a/solar_router/temperature_limiter_common.yaml +++ b/solar_router/temperature_limiter_common.yaml @@ -1,6 +1,6 @@ -# If temperature is higher than stop_temperature, +# If temperature is higher than stop_temperature, # then safety_limit is set to True -# It safety_limit is True and temperature is smaller the restart_temperature, +# It safety_limit is True and temperature is smaller the restart_temperature, # then safety_limit is set to False # ... or the opposit if you want to use it for a cooling system esphome: @@ -32,7 +32,7 @@ number: name: "Restart temperature" max_value: 99999 initial_value: 40 - min_value: -273 + min_value: -273 step: 1 optimistic: True mode: box @@ -65,7 +65,7 @@ script: then: - lambda: |- if ( isnan( id(safety_temperature).state ) ){ - // Can't read temperature. Activatinf safety limit. + // Can't read temperature. Activating safety limit. id(safety_limit) = true; id(red_led).turn_on(); return; @@ -124,7 +124,6 @@ script: output: - id: red_led platform: gpio - pin: + pin: number: ${red_led_pin} inverted: ${red_led_inverted} - diff --git a/wt32-eth01-solar-water-heater.yaml b/wt32-eth01-solar-water-heater.yaml index db111cd..6cff664 100644 --- a/wt32-eth01-solar-water-heater.yaml +++ b/wt32-eth01-solar-water-heater.yaml @@ -83,5 +83,6 @@ packages: DS18B20_pin: GPIO02 temperature_update_interval: 1s red_led_pin: GPIO5 - # Fan control - # fan_control_pin: GPIO4 + - path: solar_router/temperature_fan_control.yaml + vars: + fan_control_pin: GPIO4