.. note::

    ¡Hola! Bienvenido a la comunidad de entusiastas de SunFounder para Raspberry Pi, Arduino y ESP32 en Facebook. Únete a otros apasionados y profundiza en el uso de Raspberry Pi, Arduino y ESP32.

    **¿Por qué unirte?**

    - **Soporte de expertos**: Resuelve problemas postventa y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
    - **Aprende y comparte**: Intercambia consejos y tutoriales para mejorar tus habilidades.
    - **Avances exclusivos**: Obtén acceso anticipado a anuncios de nuevos productos y adelantos exclusivos.
    - **Descuentos especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes.
    - **Promociones festivas y sorteos**: Participa en sorteos y promociones de temporada.

    👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy mismo.

.. _py_pi5_fan:

3.1.4 Ventilador Inteligente
===============================

Introducción
---------------

En este proyecto, usaremos motores, botones y termistores para construir 
un ventilador inteligente manual + automático, con velocidad de viento ajustable.

Componentes necesarios
---------------------------

En este proyecto, necesitamos los siguientes componentes.

.. image:: ../python_pi5/img/4.1.10_smart_fan_list.png
    :width: 800
    :align: center

.. Es definitivamente conveniente comprar un kit completo; aquí tienes el enlace:

.. .. list-table::
..     :widths: 20 20 20
..     :header-rows: 1

..     *   - Nombre
..         - ELEMENTOS EN ESTE KIT
..         - ENLACE
..     *   - Kit Raphael
..         - 337
..         - |link_Raphael_kit|

.. También puedes comprarlos por separado en los enlaces a continuación.

.. .. list-table::
..     :widths: 30 20
..     :header-rows: 1

..     *   - INTRODUCCIÓN AL COMPONENTE
..         - ENLACE DE COMPRA

..     *   - :ref:`gpio_extension_board`
..         - |link_gpio_board_buy|
..     *   - :ref:`breadboard`
..         - |link_breadboard_buy|
..     *   - :ref:`wires`
..         - |link_wires_buy|
..     *   - :ref:`resistor`
..         - |link_resistor_buy|
..     *   - :ref:`power_module`
..         - \-
..     *   - :ref:`thermistor`
..         - |link_thermistor_buy|
..     *   - :ref:`l293d`
..         - \-
..     *   - :ref:`adc0834`
..         - \-
..     *   - :ref:`button`
..         - |link_button_buy|
..     *   - :ref:`motor`
..         - |link_motor_buy|

Diagrama esquemático
------------------------

============ ======== ======== ===
T-Board Name physical wiringPi BCM
GPIO17       Pin 11   0        17
GPIO18       Pin 12   1        18
GPIO27       Pin 13   2        27
GPIO22       Pin 15   3        22
GPIO5        Pin 29   21       5
GPIO6        Pin 31   22       6
GPIO13       Pin 33   23       13
============ ======== ======== ===

.. image:: ../python_pi5/img/4.1.10_smart_fan_schematic.png
   :align: center

Procedimientos experimentales
-----------------------------

**Paso 1:** Construye el circuito.

.. image:: ../python_pi5/img/4.1.10_smart_fan_circuit.png

.. note::
    El módulo de alimentación puede aplicar una batería de 9V con el 
    conector para batería de 9V incluido en el kit. Inserta el puente 
    del módulo de alimentación en la franja de bus de 5V de la protoboard.

.. image:: ../python_pi5/img/4.1.10_smart_fan_battery.jpeg
   :align: center

**Paso 2:** Accede a la carpeta del código.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/davinci-kit-for-raspberry-pi/python-pi5

**Paso 3:** Ejecuta el programa.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo python3 3.1.4_SmartFan.py

Al ejecutar el código, enciende el ventilador presionando el botón. 
Cada vez que lo presionas, la velocidad se ajusta en un nivel hacia 
arriba o hacia abajo. Existen **5** niveles de velocidad: **0~4**. 
Cuando se ajusta al **nivel 4** y presionas el botón, el ventilador 
deja de funcionar con una velocidad de viento de **0**.

Una vez que la temperatura sube o baja más de 2℃, la velocidad 
automáticamente sube o baja un nivel.

Código
--------

.. note::
    Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Pero antes, debes ir a la ruta del código fuente, como ``raphael-kit/python-pi5``. Después de modificar el código, puedes ejecutarlo directamente para ver el efecto.

.. raw:: html

    <run></run>

.. code-block:: python

   #!/usr/bin/env python3

   from gpiozero import Motor, Button
   from time import sleep
   import ADC0834
   import math

   # Inicializa los pines GPIO para el botón y el control del motor
   BtnPin = Button(22)
   motor = Motor(forward=5, backward=6, enable=13)

   # Configura el módulo ADC0834 para la detección de temperatura
   ADC0834.setup()

   # Variables para rastrear el nivel de velocidad del motor y las temperaturas
   level = 0
   currentTemp = 0
   markTemp = 0

   def temperature():
       """
       Reads and calculates the current temperature from the sensor.
       Returns:
           float: The current temperature in Celsius.
       """
       # Lee el valor analógico del módulo ADC0834
       analogVal = ADC0834.getResult()
       # Convierte el valor analógico a voltaje y luego a resistencia
       Vr = 5 * float(analogVal) / 255
       Rt = 10000 * Vr / (5 - Vr)
       # Calcula la temperatura en Celsius
       temp = 1 / (((math.log(Rt / 10000)) / 3950) + (1 / (273.15 + 25)))
       Cel = temp - 273.15
       return Cel

   def motor_run(level):
       """
       Adjusts the motor speed based on the specified level.
       Args:
           level (int): Desired motor speed level.
       Returns:
           int: Adjusted motor speed level.
       """
       # Detiene el motor si el nivel es 0
       if level == 0:
           motor.stop()
           return 0
       # Limita el nivel a 4 para la velocidad máxima
       if level >= 4:
           level = 4
       # Ajusta la velocidad del motor
       motor.forward(speed=float(level / 4))
       return level

   def changeLevel():
       """
       Changes the motor speed level when the button is pressed and updates the reference temperature.
       """
       global level, currentTemp, markTemp
       print("Button pressed")
       # Cicla a través de los niveles 0-4
       level = (level + 1) % 5
       # Actualiza la temperatura de referencia
       markTemp = currentTemp

   # Asigna la función changeLevel al evento de presionar el botón
   BtnPin.when_pressed = changeLevel

   def main():
       """
       Main function to continuously monitor and respond to temperature changes.
       """
       global level, currentTemp, markTemp
       # Establece la temperatura de referencia inicial
       markTemp = temperature()
       while True:
           # Lee continuamente la temperatura actual
           currentTemp = temperature()
           # Ajusta el nivel del motor según la diferencia de temperatura
           if level != 0:
               if currentTemp - markTemp <= -2:
                   level -= 1
                   markTemp = currentTemp
               elif currentTemp - markTemp >= 2:
                   if level < 4:
                       level += 1
                   markTemp = currentTemp
           # Ejecuta el motor en el nivel ajustado
           level = motor_run(level)

   # Ejecuta la función principal y maneja la interrupción por teclado
   try:
       main()
   except KeyboardInterrupt:
       # Detiene el motor cuando el script es interrumpido
       motor.stop()



Explicación del Código
---------------------------

#. Importa clases para gestionar un motor y un botón, además de la función ``sleep`` para introducir pausas. También importa la biblioteca ADC0834 para la detección de temperatura y la biblioteca ``math`` para cálculos matemáticos.

   .. code-block:: python

       #!/usr/bin/env python3

       from gpiozero import Motor, Button
       from time import sleep
       import ADC0834
       import math

#. Configura el botón en el pin GPIO 22 y el motor con pines GPIO específicos para su control. Inicializa el módulo ADC0834 para la medición de temperatura y define variables para monitorear el nivel de velocidad del motor y las temperaturas.

   .. code-block:: python

       # Inicializa los pines GPIO para el botón y el control del motor
       BtnPin = Button(22)
       motor = Motor(forward=5, backward=6, enable=13)

       # Inicializa el módulo ADC0834 para la detección de temperatura
       ADC0834.setup()

       # Inicializa variables para rastrear el nivel de velocidad del motor y las temperaturas
       level = 0
       currentTemp = 0
       markTemp = 0

#. Define una función para leer y calcular la temperatura desde el sensor, convirtiendo la lectura a grados Celsius.

   .. code-block:: python

       def temperature():
           """
           Reads and calculates the current temperature from the sensor.
           Returns:
               float: The current temperature in Celsius.
           """
           # Lee el valor analógico del módulo ADC0834
           analogVal = ADC0834.getResult()
           # Convierte el valor analógico a voltaje y luego a resistencia
           Vr = 5 * float(analogVal) / 255
           Rt = 10000 * Vr / (5 - Vr)
           # Calcula la temperatura en Celsius
           temp = 1 / (((math.log(Rt / 10000)) / 3950) + (1 / (273.15 + 25)))
           Cel = temp - 273.15
           return Cel

#. Introduce una función para ajustar la velocidad del motor de acuerdo con el nivel especificado.

   .. code-block:: python

       def motor_run(level):
           """
           Adjusts the motor speed based on the specified level.
           Args:
               level (int): Desired motor speed level.
           Returns:
               int: Adjusted motor speed level.
           """
           # Detiene el motor si el nivel es 0
           if level == 0:
               motor.stop()
               return 0
           # Limita el nivel a 4 para la velocidad máxima
           if level >= 4:
               level = 4
           # Ajusta la velocidad del motor
           motor.forward(speed=float(level / 4))
           return level

#. Implementa una función para cambiar manualmente el nivel de velocidad del motor usando un botón y asocia esta función al evento de pulsación del botón.

   .. code-block:: python

       def changeLevel():
           """
           Changes the motor speed level when the button is pressed and updates the reference temperature.
           """
           global level, currentTemp, markTemp
           print("Button pressed")
           # Cicla a través de los niveles 0-4
           level = (level + 1) % 5
           # Actualiza la temperatura de referencia
           markTemp = currentTemp

       # Asigna la función changeLevel al evento de pulsar el botón
       BtnPin.when_pressed = changeLevel

#. La función principal, diseñada para ajustar continuamente la velocidad del motor en respuesta a las fluctuaciones de temperatura, monitorea constantemente los cambios.

   .. code-block:: python

       def main():
           """
           Main function to continuously monitor and respond to temperature changes.
           """
           global level, currentTemp, markTemp
           # Establece la temperatura de referencia inicial
           markTemp = temperature()
           while True:
               # Lee continuamente la temperatura actual
               currentTemp = temperature()
               # Ajusta el nivel del motor según la diferencia de temperatura
               if level != 0:
                   if currentTemp - markTemp <= -2:
                       level -= 1
                       markTemp = currentTemp
                   elif currentTemp - markTemp >= 2:
                       if level < 4:
                           level += 1
                       markTemp = currentTemp
               # Ejecuta el motor en el nivel ajustado
               level = motor_run(level)

#. Ejecuta la función principal y asegura que el motor se detenga si el script es interrumpido.

   .. code-block:: python

       # Ejecuta la función principal y maneja la interrupción por teclado
       try:
           main()
       except KeyboardInterrupt:
           # Detiene el motor cuando el script es interrumpido
           motor.stop()


