Portada! Creando un reloj binario (cuarta parte)

unreal4u

I solve problems.
Miembro del Equipo
ADMIN
Se incorporó
2 Octubre 2005
Mensajes
13.465
Breadboard con todas las piezas montadas


En la primera parte, revisé cuáles serían los requisitos para armar el reloj. Luego en la segunda parte, encargué la lista de materiales a comprar y en la tercera parte preparé y escribí gran parte del código. Hoy vamos a (por fin!) crear un producto un poco más funcional e integrar todos los sensores en una breadboard para ir probando si todas las partes funcionan!

Parte 5: Creando un primer demo​


Lo primero que hice al llegarme todas las piezas fue comprobar que todas estuvieran funcionando: desenrollé el metro de LEDs y comprobé mediante un demo de un arcoiris que todos los LEDs pudieran mostrar todos los colores sin problemas.

Sin embargo, al empezar a programar me di cuenta muy rápidamente que estar contando LEDs de 6 en 6 en una tira de 30 era casi imposible: tenía que hacer una matriz base para poder avanzar y entender lo que estaba haciendo de forma rápida.

Así que agarré una hoja A4 y empecé a dibujar varias posibilidades. Encontré que lo más óptimo era dejar un espacio de unos 30cm x 25cm para dejar los LEDs efectivamente en una matriz de 6 filas y 5 columnas en total: con eso ocupaba exacto los 30 LEDs que había encargado, aunque tuve que cerciorarme eso si que los LEDs en si quedaran con exactamente la misma distancia tanto en el eje horizontal como vertical:

Probando y armando esquemas en papel para probar


Acto seguido agarré una plancha de madera de un proyecto previo que me había sobrado y la preparé. Cabe destacar que una vez que tenga listo todo, lo pintaré de negro (tapando los LEDs con cinta aislante o masking tape en el intertanto) pero necesito pegar los LEDs ahora ya que de lo contrario se pueden despegar de la superficie pintada. Lo primero que hice fue cortar la tabla a las dimensiones finales, dibujar el mismo dibujo que había hecho en papel, hacer los hoyos para pasar los cables por atrás y pegar la segunda columna de LEDs, ya que esta estaba libre de cables y era lo más fácil. Esta era importante ya que esta iba a ser la guía para pegar las demás:

Traspasando la idea a una plancha de madera


De ahí vino el trabajo ya más simple gracias a la buena preparación previa: pegar las demás guiándome siempre por el primer LED. Las pegué todas y quedé conforme con el resultado:

Asegurándome de que todo quede cuadrado



El siguiente trabajo fue soldar todo lo que tenía que soldar y si alguna vez en el futuro haré de nuevo esta misma pega, me cercioraré de comprar más LEDs y de cortar el primero y último de la serie, ya que los más webeados de trabajar fueron justamente los cables que ya venían soldados de fábrica a la serie:

Ya no hay vuelta atrás: soldando todo


En fin, terminé de soldar todo y organizé los cables atrás con un simple sujetacable que había comprado hacía años en AliExpress también, y era hora de crear un primer demo funcional! (Quieren ver el código? Sigan leyendo!)

Primer demo funcional


Dicho y hecho: en este punto ya llevaba días programando la wea (anoche por ejemplo me quedé hasta las 2 de la mañana aprendiendo sobre includes en esphome... que al final ni ocupé!), midiendo todo con doble precisión, pasando rabias con el código, optimizando la wea, aprendiendo un montón y lo primero que me dijo mi esposa al ver el primer prototipo funcionando fue "no puedes cambiarle los colores? Parece árbol de pascua".

Bueno, gracias a todo el trabajo por detrás esto fue bastante simple y le mostré el nuevo demo, esta vez en blanco con los segundos en púrpura:



Parte 6: Código del demo​

Mirando el video de arriba me di cuenta de un detalle: no les he compartido el código! Así que menos bla bla y vamos directo a la acción!

YAML:
light:
  - platform: fastled_clockless
    chipset: WS2812B
    pin: 18
    num_leds: 30
    rgb_order: GRB
    name: "led_matrix"
    id: led_matrix_light
    internal: False
    restore_mode: RESTORE_AND_ON
    effects:
      - addressable_lambda:
          name: "Easy Binary clock"
          update_interval: 100ms
          lambda: |-
            auto time = id(local_time).now();
            if (!time.is_valid()) {
                return;
            }

            // Always clear screen before a new run
            it.all() = Color(0, 0, 0);

            Color purple = Color(0xFF00FF);
            //Color warm_white = Color(0xD5CA97); // Looks great with -100 color
            Color warm_white = Color(0xD7974F); // Try this one out with the smoke grey screen

            int column = 6;
            const int TIME_PARTS [column] = {
                floor(time.hour / 10),   // first_hour_digit
                (int) time.hour % 10,    // last_hour_digit
                floor(time.minute / 10), // first_minute_digit
                (int) time.minute % 10,  // last_minute_digit
                floor(time.second / 10), // first_second_digit
                (int) time.second % 10,  // last_second_digit
            };

            int row = 4;
            const int POSSIBLE_NUMBERS [row] = { 1, 2, 4, 8 };

            for (column = 5; column >= 0; column--) {
                // The base color that will illuminate hours and minutes
                Color chosen_color = warm_white;

                // Seconds have a distinct color (visual aid)
                if (column >= 4) {
                    // Seconds are always a bit less bright than minutes and hours
                    chosen_color = purple - 25;
                }

                // Include the measurements of the light sensor to determine LED brightness
                chosen_color -= id(clock_brightness);

                int tmp = TIME_PARTS[column];
                for (row = 3; row >= 0; row--) {
                    int current = POSSIBLE_NUMBERS[row];
                    if (tmp >= current && (tmp & current) != 0) {
                        // Calculates row offset using "row" and adds up the chosen column using "column"
                        it[(6 * (3 - row)) + column] = chosen_color;
                        tmp -= current;
                    }
                }
            }

Eso sería todo para un reloj binario simple. La primera parte es más que nada un poco de boilerplate necesario para cada tira LED, y la parte interesante empieza en los efectos: los efectos en ESPHome para una pantalla de LEDs se refiere a una configuración predeterminada: simplemente llena el siguiente listado en Home Assistant:

Efectos en Home Assistant


Ahí puedo elegir un efecto y ese efecto se mostrará. En este caso, sólo muestro uno pero tengo varios más como muestra el listado. Por el momento no van al caso.

El código en sí primero valida que tengo una hora válida. Luego borra la pantalla completa (este código se ejecuta 10 veces por segundo) y defino algunas variables que ocuparé: el color de los LEDs y una constante que me permite hacer una referencia fácil a cada parte de la hora.

Luego viene la parte más interesante del algoritmo: parto con los segundos y me voy haciendo camino a la hora, calculando en el intertanto qué luz se tiene que prender y si es que tengo que prenderlo, mando la señal de que dibuje el color elegido (los segundos tienen otro color).

Esto lo hago con un poco de magia ocupando operadores lógicos y una simple suma para saber en qué columna tengo que estar para esa posición.
Técnicamente la última operación que ejecuto es restar el número actual del total binario y si bien esto debería poder hacerse con operaciones bitwise esto último no me ejecutaba bien la aplicación. Decidí dejarlo así por ahora ya que corre y tampoco me ahorraría tantos ciclos como para que valga la pena.

Ya que tenía distintos efectos, me di cuenta que ocupando efectos podría muy fácilmente cambiar de un efecto a otro. Ya que básicamente tenía una pantalla de 6x5 pixeles, me podía dar el lujo de experimentar un poco sin interferir en lo que ya había hecho!

Así fue como se me ocurrió también incorporar en esta etapa un "Rotary Encoder": la gracia de este sensor es que uno puede girar la perilla y además trae un botón: ideal para cambiar algo con un botón físico que todos saben ocupar.

Decidí crear 2 "pantallas" adicionales más: una que me muestre un reloj binario más complejo, usando la secuencia 1-2-4-8-16-32 para cubrir todos los números del 1 al 60 y la otra que me fuese mostrando la hora de forma progresiva:



Con esto ya me quedó algo presentable y listo para diseñar la base que envuelve todo el proyecto. Basándome en las mediciones al ojo que hice, calculé que si dejo pasar un 50% a un 75% de luz debería estar bien, mientras no sea demasiado difuminado (que en parte puedo controlar al ajustar a qué distancia queda el acrílico).

Así que ya en la próxima entrega les daré detalles de algunos de los obstáculos que enfrenté y por supuesto cómo se verá el proyecto finalmente finalizado! Hasta la próxima!
 
Subir