Arduino,  Hardware

Haciendo inteligente mi aire acondicionado – Epílogo

Haciendo mantenimiento en mi casa, me decidí a arreglar el aire acondicionado del salón, un Johnson MGE-30-BC, que lleva bastante tiempo sin funcionar.

Compré mi casa hace casi dos años, y por entonces el aire del salón no funcionaba. Siempre había dejado a un lado el proyecto de repararlo porque me esperaba lo peor (que el gas se habría escapado y habría que buscar la fuga, repararla y volver a cargarlo, que el compresor estaría estropeado y habría que cambiarlo, con la descarga y recarga de gas correspondiente, que habría que cambiar el aire acondicionado al completo… vamos, reparaciones no baratas precisamente), pero ha resultado ser la reparación más sencilla en mucho tiempo: la manguera que interconecta split y unidad exterior tiene todos los cables del mismo color, y dos de ellos estaban cambiados.

No llego a comprender cómo llegó a ocurrir este problema… ¿el que lo instaló no lo probó? ¿pensó que estaba estropeado? ¿no persiguió al que le vendió la máquina para que le devolviese el dinero o algo? ¿le dió pereza?. Lo único que sé es que ahora funciona 😂.

Ahora que ya estaba funcionando, y con el aire acondicionado de mi habitación modificado para poder controlarlo con el móvil, dije que el del salón no podía ser menos, por lo que me puse a descodificar los códigos del mando, igual que hice hace unos meses con el de mi habitación.

IRrecvDumpV2 me dijo que el protocolo era NEC, y que la longitud era 73:

Siguiendo el mismo protocolo que hice para el de mi habitación, apunté multitud de códigos, pasando por todos los modos, temperaturas y otras funciones de las que permitía el mando. El resultado, un montón de datos en los que buscar patrones, por lo que ¡manos a la obra! ¡Hora de Excel!

Para poner orden en el caos, lo que hice fue pegar los códigos en horizontal para cada acción, que son las filas de color azul-claro grisáceo. Tras cada fila azul hay una fila con el valor de la diferencia de cada código el de la acción anterior, para ver qué ha cambiado entre código y código. A estas filas con el valor de la diferencia, les apliqué formato condicional, para que tomaran color rojizo cuanto mayor valor tuviesen (así, las celdas de color rojo corresponderían a los códigos que cambian entre acción y acción.

Con esta información pude sacar las siguientes conclusiones:

  • Los códigos 4, 6 y 8 corresponden al modo de funcionamiento (COLD, DEHUMIDIFICATION, HEAT, AUTO o FAN)
  • El código 10 corresponde al estado de funcionamiento (encendido o apagado)
  • Los códigos 12 y 14 corresponden a la velocidad del ventilador (LOW, MEDIUM, HIGH, o AUTO)
  • El código 16 corresponde a la función SWING (el movimiento constante y de vaivén del aire) (encendido o apagado)
  • Los códigos 20, 22, 24 y 26 corresponden a la temperatura (de 16 a 30ºC)

Los códigos que corresponden a las distintas funciones parecen tener dos valores posibles: alrededor de -500 y alrededor de -1600, que son las representaciones de un valor falso (0) y uno verdadero (1) respectivamente. Siguiendo esta lógica, podemos ver que los valores de las distintas funciones son:

  • Para el modo de funcionamiento:
    • 000 – AUTO (automático)
    • 100 – COLD (frío)
    • 010 – DEHUMIDIFICATION (deshumidificación)
    • 110 – FAN (ventilador)
    • 001 – HEAT (calor)
  • Para el estado de funcionamiento:
    • 0 – Apagado
    • 1 – Encendido
  • Para la velocidad del ventilador:
    • 00 – AUTO (automático)
    • 10 – LOW (baja)
    • 01 – MEDIUM (media)
    • 11 – HIGH (alta)
  • Para la función SWING:
    • 0 – Apagado
    • 1 – Encendido
  • Para la temperatura:
    • 0000 – 16ºC
    • 1000 – 17ºC
    • 0100 – 18ºC
    • 1100 – 19ºC
    • 0010 – 20ºC
    • 1010 – 21ºC
    • 0110 – 22ºC
    • 1110 – 23ºC
    • 0001 – 24ºC
    • 1001 – 25ºC
    • 0101 – 26ºC
    • 1101 – 27ºC
    • 0011 – 28ºC
    • 1011 – 29ºC
    • 0111 – 30ºC

Como curiosidad, los valores siguen un orden binario invertido (primero 000, luego 001 que invertido es 100, luego 010 que invertido es el mismo valor 010…)

Con esto claro, ahora nos queda montar un sketch de arduino para probar. El hardware es el mismo que en mi aire de la habitación, y el sketch en gran parte también.

Declaramos arrays para cada función con sus respectivos valores:

/**
 * Another weird point here is the value for COOL here is the same as the value for OFF mode. Oh well...
 */
const byte modeCommandValues[] { 0b00000000,    //AUTO -> 000
                                 0b00000100,    //COOL -> 100
                                 0b00000010,    //DRY  -> 010
                                 0b00000110,    //FAN  -> 110
                                 0b00000001 };  //HEAT -> 001

/**
 * Speed values follow a reverse binary count, being 00 = AUTO and counting up 01 LOW,
 * which once reversed gives 10.
 */
const byte speedCommandValues[] { 0b00000000,   //AUTO -> 00
                                  0b00000010,   //LOW  -> 10
                                  0b00000001,   //MED  -> 01
                                  0b00000011 }; //HIGH -> 11

/**
 * Temperatures follow a reverse binary count, being 0000 = 16ºC and counting up 0001,
 * which once reversed gives 1000.
 */
const byte temperatureCommandValues[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  //Filler positions
                                        0b00000000,                       //16ºC -> 0000
                                        0b00001000,                       //17ºC -> 1000
                                        0b00000100,                       //18ºC -> 0100
                                        0b00001100,                       //19ºC -> 1100
                                        0b00000010,                       //20ºC -> 0010
                                        0b00001010,                       //21ºC -> 1010
                                        0b00000110,                       //22ºC -> 0110
                                        0b00001110,                       //23ºC -> 1110
                                        0b00000001,                       //24ºC -> 0001
                                        0b00001001,                       //25ºC -> 1001
                                        0b00000101,                       //26ºC -> 0101
                                        0b00001101,                       //27ºC -> 1101
                                        0b00000011,                       //28ºC -> 0011
                                        0b00001011,                       //29ºC -> 1011
                                        0b00000111 };                     //30ºC -> 0111

Y a la hora de montar el comando a mandar, los mezclo todos en una variable de 64 bits. No llegamos a ocupar todo el contenido, ya que los 73 valores que forman nuestro comando del mando a distancia corresponden a bits en proporción 2:1, por lo que en verdad serían 35 bits (los 3 primeros valores de cada comando son una «firma» estática, no cambia, y la agrega automáticamente la librería IRRemote).

  uint64_t command;
  command = modeCommandValues[modeState];             //Mode
  command <<= 1;
  command |= (powerState?1:0);                        //On-Off
  command <<= 2;
  command |= speedCommandValues[speedState];          //Speed
  command <<= 1;
  command |= (swingState?1:0);                        //Swing enabled/disabled
  command <<= 5;
  if (modeState != 0) {
    command |= temperatureCommandValues[tempState];   //Temperature
  } else {
    command |= temperatureCommandValues[25];          //25ºC for auto mode
  }
  command <<= 20;
  command |= 0b1010;                                  //End of command
  command <<= 3;

Expliquemos esto último un poco: la variable command es de tipo uint64_t (entero sin signo de 64 bits), y lo que vamos haciendo con cada valor es cargarle el valor de la función que estamos cargando sin borrar lo que ya existía de la anterior función (una operación booleana OR. Por ejemplo, 100 OR 001 = 101) y luego le aplicamos un corrimiento hacia la izquierda por tantas posiciones como tiene el siguiente valor que vamos a cargar (por ejemplo, 111 << 3 = 111000). Al fin y al cabo lo que conseguimos con esto es «concatenar» los valores binarios de las distintas funciones.

Como caso especial, cabe indicar el del modo «AUTO». En este modo, este modelo de aire acondicionado no espera otro valor de temperatura que no sean 25 grados (1001). En caso de enviarle otro, el ventilador se para y no hace nada más. Así que cuando estemos en modo automático, enviamos manualmente el valor 1001.

Como el protocolo que usa el aire es NEC, podemos llamar directamente a irsend.sendNEC(), indicándole la variable command y la longitud del comando, en nuestro caso, 35.

  irsend.sendNEC(command, 35);
  delay(40);

Y con eso ya tendríamos funcionando el segundo aire acondicionado inteligente. Falta la parte aburrida de configurarlo en nuestro sistema domótico, en mi caso OpenHAB, pero no lo detallaremos aquí porque es exactamente igual que el anterior aire acondicionado, a excepción de que en este tenemos un par de topics más (para la función SWING).

Es un lujo poder controlar la temperatura desde el móvil o cualquier dispositivo que tenga un navegador web, y la posibilidad de romper algo en el camino es nula, siempre que se te dé medianamente bien la electrónica, ya que no hay conexión electrónica entre nuestro controlador y la placa electrónica del aire acondicionado: la comunicación es por infrarrojos.

Con esto dejamos esta aventura de modificación/mejora/tuneo o como queramos llamar de aires acondicionados. Los otros dos aires que tengo en casa son otro johnson, esta vez el modelo MGE-20-BC, pero que tiene el mismo protocolo, por lo que este mismo sketch me vale, y otro Daitsu DSG-07HRN2, por lo que el mismo sketch que el aire de mi habitación me sirve. En el futuro, si compro otro modelo, podemos continuar, en caso que no venga ya con posibilidad de control a través de WiFi 😊

Os dejo abajo el excel de códigos, y podéis encontrar el sketch de arduino en mi github.

¡Nos vemos en la siguiente entrada!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Ver
Privacidad