Domotica Aire Acondicionado LG

Hola,
Me gustaría a la vez que pido ayuda, compartir mi proyecto.
El proyecto consta de un Arduino mega + shield Ethernet para poder controlar 2 aires acondicionados de la marca LG. El proyecto original es de Antonis G. Kanaris para software 0022. Lo he modificado para trabajar con arduino 1.0.

Adjunto esquema eléctrico de placa.

Edito: He subido el proyecto corregido. Ahora el que quiera usarlo lo tiene funcional para 2 aires.

Gracias y un saludo!

PulsesIR_LG.cpp (18 KB)

PulsesIR_LG.h (1.56 KB)

AA_LG_IR_remote_2Aires_v2.ino (22.9 KB)

Supongo que los procesos son independientes, puedes enviar un comando al Aire1 y luego otro al Aire2 sin problemas, según lo que dice la librería que has posteado.

Prueba sin la parte web comandar ambos AireAcondicionados?

Ahora veo que definiste esto int IR_PIN = 3; // Declaración de variables - Ir led pin puerto 3 para aire acondicionado1 int IR_PIN2 = 9; // Declaración de variables - Ir ped pin2 puerto 9 para aire acondicionado2

La librería solo emite pulsos IR a intervalos (useg) determinados por el protocolo LG. yo creo que tu problema esta en la parte web que no he mirado.

Desdobla tu proyecto y prueba la parte emisión IR por un lado usando ambos Aires acondicionados y enviando comandos ya sea vía Serial o arma una repetición determinada. Cuando compruebes que eso esta bien, entonces volvemos al tema WEB y su interfaz.

Hola surbyte, gracias por responder. Referente a lo que comentas, creo que he dado con la solución mientras de estaba intentando responder. Cuando llegue a casa lo probaré, pero creo que la solución seria...

PulsesIR_LG pulsesIR_LG(IR_PIN); // Pin IR para Aire 1 PulsesIR_LG pulsesIR_LG*A2*(IR_PIN2); // Pin IR para Aire 2

Para aire 1 if (Comando.indexOf("cmd=CALOR_25_FAN2")>0){ pulsesIR_LG.SendACCode_CALOR_25_Fan2(); }

Para aire 2 if (Comando.indexOf("cmd=A2_CALOR_25_FAN2")>0){ pulsesIR_LG*A2*.SendACCode_CALOR_25_Fan2(); }

Gracias!

Por supuesto, lo único que tenias que haces era definir dos objetos. tal como lo hiciste. Yo pensé inicialmente que la librería era bidireccional y que por alguna razón tenías un problema de tiempos. Al verla solo veo envío de comandos, y por eso lo que te respondí. A veces con explicar un problema uno VE la solución.

Yo uso en el buen sentido a mi madre con estos problemas. Voy y le explico algo complicado... por lo que debo bajar la explicación a niveles simples, y muchas veces eso me responde en lo que estoy atorado.

Bueno, ya tengo esto funcionando con dos aires. ;D Ahora he terminado de conectarle una raspberry pi con un archivo bash que me enciende y apaga los aires. El codifo es muy sencillo y además le he metido un cron que me enciende el aire a las 7 de la mañana para que me encuentre la casa calentita para cuando me levanto y me apague el aire cuando me voy de casa.

Los scripts son:

encender_aire.sh

!/bin/bash

curl http://192.168.1.252/?cmd=CALOR_25_FAN2

apagar_aire.sh

!/bin/bash

curl http://192.168.1.252/?cmd=AC_OFF

Ahora me gustaría evolucionar un poco el proyecto y ponerle un lector de estados para que desde la página web me muestre si el aire está encendido o apagado.

He encontrado esta web http://startingelectronics.com/tutorials/arduino/ethernet-shield-web-server-tutorial/web-server-read-switch-automatically-using-AJAX/ pero no me funciona la implementación
del código, he extraido:

  • el script:
                       client.println("<script>");
                       client.println("function GetSwitchState() {");
                       client.println("nocache = \"&nocache=\"\
                                                        + Math.random() * 1000000;");
                       client.println("var request = new XMLHttpRequest();");
                       client.println("request.onreadystatechange = function() {");
                       client.println("if (this.readyState == 4) {");
                       client.println("if (this.status == 200) {");
                       client.println("if (this.responseText != null) {");
                       client.println("document.getElementById(\"switch_txt\")\
.innerHTML = this.responseText;");
                       client.println("}}}}");
                       client.println(
                       "request.open(\"GET\", \"ajax_switch\" + nocache, true);");
                       client.println("request.send(null);");
                       client.println("setTimeout('GetSwitchState()', 1000);");
                       client.println("}");
                       client.println("</script>");
                       client.println("</head>");
                       client.println("<body onload=\"GetSwitchState()\">");
  • Codigo arduino:
void GetSwitchState(EthernetClient cl)   // send the state of the switch to the web browser
{
   if (digitalRead(3)) {
       cl.println("Switch state: ON");
   }
   else {
       cl.println("Switch state: OFF");
   }
}
  • Donde iria esta parte del código?
if (HTTP_req.indexOf("ajax_switch") > -1) {                          // read switch state and send appropriate paragraph text
GetSwitchState(client);
}

Adjunto skecth por si puedes encajar las piezas y hacerlo funcionar. Si se pudiese hacer 2 lectores de estado uno para cada aire seria genial.
PD= como puedo adjuntar otro archivo si no es en el primer post?
Gracias!!!

los códigos van con tags. Por favor edita

surbyte: los códigos van con tags. Por favor edita

Hecho!

Gracias.. se nota el cambio.

En tu proyecto de manejar dos aires acondicionados, cual es la idea? Pregunto porque vienen ambos con control remoto y armar lo que has hecho parece no tener un objetivo mas que didáctico.

Interesante, gracias por el aporte, le voy a dar muy buen uso...

surbyte: Gracias.. se nota el cambio.

En tu proyecto de manejar dos aires acondicionados, cual es la idea? Pregunto porque vienen ambos con control remoto y armar lo que has hecho parece no tener un objetivo mas que didáctico.

Mis aires vienen con mando a distancia. La idea era poder encender y apagar los aires a distancia (fuera de casa por 3G). EL llegar a casa cuando te has pasado el día fuera y encontrártela calentita es una gozada.

Alguna idea de como solucionar el tema del lector de estados?

MSL: Interesante, gracias por el aporte, le voy a dar muy buen uso...

De nada. En el proyecto no tengo implementadas todas las temperaturas ni todos los estados del ventilador. Por como funciona el sistema en LG. Por eso el proyecto lo he hecho en el Arduino Mega. En el Arduino UNO se quedaba corto de memoria. Actualmente tengo las temperaturas de 23,24,25 para frio y calor y en FAN1 y FAN2.

Tenes los códigos completos del IR LG, es decir, como son los bits para cada temperatura y estado del Aire acondicionado.
Estoy viendo cierto patrón en como estan hechos pero no logro completar algo.
Pasame una referencia a donde esten dichos códigos.

Aca encontré una pagina que tiene 2000 protocolos IR
no se cual es el tuyo

Busco alguna peculiaridad entre las temperaturas 23,24,25
fan 1 y 2 ya la encontré. Ultimos dos bits.
De todos modos si tenes todos los códigos podrias definir cada uno y hacer que la librería los genere con toda la variedad de temperaturas que el Aire Acondicionado tenga disponible.

Bueno, como siempre cuando me pongo a buscar un tema es increíble lo que encuentro.
Este es tu protocolo LG para aire acondicionado decodificado por alguien del foro en inglés.

the output for the IR library
8250h 4300l = header
next
450h 1700l = 1
450h 700l = 0

first byte after header: 1 0 0 0 1 0 0 0 (i will not repeat this below)
power on: 0 0 0 0 0 1 0 0 1 1 1 1 0 1 0 0 + CRC 0 1 1 1 ( = 1 0 0 0 + 1 0 0 0 + 0 0 0 0 + 0 1 0 0 + 1 1 1 1 + 0 1 0 0; I will not repeat CRC below)
(this power on includes mode, temp and fan speed)
power off:1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 ( dont’t see here any info about mode, temp and fan speed)
change temp/fan / mode:
0 0 0 0 1 1 0 0 1 1 1 0 0 1 0 0 = heating 29 C Fan4
1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
1-5 always the same except for timer set, or jet mode (or other SF I was not interested)
6-8 heating 4, auto 3, dehumidification 1, cooling 0
9-12 = temp -15
13 = 0
14-16 = fan1 1, fan2 0 (strange), fan3 2, fan4 4

Make sure you add the header, the first byte and the CRC.
The code was tested with 38kHz modulation and it worked

Estudialo a ver si coincide, si coincide cosa que estoy seguro que si, entonces puedes reescribir la librería y poder armar el código a enviar según lo que necesites y no con valores fijos como ahora.
Esto tambien será mas cómodo para manejarlo via Android mas tarde.
ya que todo se reduce a pocos comandos.

Urgando mas resulta que estaba resuelto.
Ejemplo

#include <LG.h>
#include <IRremote.h>

// the LG code generator object

// the IR emitter object
IRsend irsend;

void setup()
{
Serial.begin(9600);
Serial.println("Start");


// wait 5 seconds
//delay(5000);
//LG LG(mode_heating,fan_4,30,state_on);
//LG LG(mode_heating,fan_4,30,state_off);
LG LG(mode_cooling,fan_1,18 ,state_on);


LG.debug();
// change the state
//LG.setState(STATE_off);
// send the code

irsend.sendRaw(LG.codes,LG_buffer_size,38);
//
Serial.println("End");


 
// wait 10 seconds
//delay(10000);

// change the state
//LG.setState(STATE_on); 
// send the code
//irsend.sendRaw(LG.codes,LG_buffer_size,38);
}

void loop() {}

LG.H

#ifndef LG_h
#define LG_h
#include <WProgram.h>

#define first_byte 136 //b10001000

#define state_on 0
#define state_off 24 //b11000
#define state_change_mode 1

#define mode_heating 4 //b100
#define mode_auto 3 //b011
#define mode_dehuidification 1 //b001
#define mode_cooling 0
#define mode_none 0

#define temperature_offset 15

#define fan_1 1
#define fan_2 0
#define fan_3 2
#define fan_4 4 //b100
#define fan_none 5 //b101

#define first_high 8271
#define first_low 4298
#define zero_and_one_high 439
#define zero_low 647
#define one_low 1709

#define LG_buffer_size 59

class LG
{
 public:
 // fields
 unsigned int codes[LG_buffer_size];
 // methods
 // setter
 LG(int _mode, 
 int _fan, 
 int _temperature,
 int _state);
 // getter
 // debugging
 void debug();
 private:
 // fields
 byte crc;
 // methods
 void FillBuffer(byte _pos, byte _bit, byte _value);
};

#endif;

LG.CPP

#include "LG.h"
LG::LG(int _mode, 
				 int _fan, 
				 int _temperature,
				 int _state)
{
	// set sync
	codes[0] = first_high;
	codes[1] = first_low;
	crc = 0;
	FillBuffer(0,8,first_byte);
	FillBuffer(8,5,_state);
	if(_state==state_off)
		FillBuffer(13,3,mode_none);
	else
		FillBuffer(13,3,_mode);
	if(_state==state_off)
		FillBuffer(16,4,0);
	else
		FillBuffer(16,4,(byte)_temperature-temperature_offset);
	FillBuffer(20,1,0); //jet
	if(_state==state_off)
		FillBuffer(21,3,fan_none);
	else
		FillBuffer(21,3,_fan);
	FillBuffer(24,4,crc);
	codes[LG_buffer_size-1] = zero_and_one_high;
}

void LG::FillBuffer(byte _pos, byte _bits, byte _value){
	for (int i=_bits;i>0;i--){
		codes[2+2*(_pos+_bits-i)] = zero_and_one_high;
		codes[2+2*(_pos+_bits-i)+1] = (bitRead(_value,i-1)==1?one_low:zero_low);
		if(bitRead(_value,i-1)==1){
			byte bitset = 0;
			bitSet(bitset,(128+i-_pos-_bits-1)%4);
			crc = crc + bitset;
		}
	}
}
void LG::debug()
{
	for(byte i=0;i<LG_buffer_size;i++){
		Serial.print(codes[i],DEC);
		Serial.print(",");
	}
}

Aquí te paso lo que he ido decodificando hasta ahora. El problema es el CRC que son los 4 últimos bits.

Para cada cosa que se quiere hacer en el aire (un comando de subir temeratura, o cambiar de velocidad del aire) se envia todo el string completo con la temperatura + frio o calor + velocidad de los ventiladores + swing o no, etc…

Por eso en el HTML no hay un simple ON, directamente hay un botón de temeratura

codigos.zip (29.8 KB)

el crc se calcula. funciona lo que te pasé?

Después de una semana de vértigo, me voy a poner un ratillo con ello. Te aviso con lo que sea. Gracias surbyte!

1º test. Ejecuto el sketch que has puesto y corrijo un pequeño error al compilar (falta en el LG.h el comando #define uint8_t byte

Al ejecutar el sketch me da el siguiente mensajer por el serial:

8850,4100,439,1709,439,647,439,647,439,647,439,1709,439,647,439,647,439,647,439,647,439,647,439,647,439,647,439,647,439,1709,439,647,439,647,439,1709,439,647,439,1709,439,647,439,647,439,647,439,647,439,1709,439,1709,439,1709,439,1709,439,1709,439

Cuando tendría que ser algo como:

8850,4100,1709,439,647,439,1709,439,647,439,647,439,647,439,439,1709,439,1709,439,647,439,439,647,1709,1709,1709,439   (Hot 25º, swing, fan 1)

Parece que si que saca el comando IR, pero mi aire trabaja con un 30 bits y este saca 59 bits. Si cambio el #define LG_buffer_size 30 (LG.h) al ejecutar el sketck me saca consantemente

8850,4100,439,1500,439,480,439,480,439,480,439,1500,439,480,439,480,439,480,439,480,439,480,439,480,439,480,439,4øStart
8850,4100,439,1500,439,480,439,480,439,480,439,1500,439,480,439,480,439,480,439,480,439,480,439,480,439,480,439,4øStart
8850,4100,439,1500,439,480,439,480,439,480,439,1500,439,480,439,480,439,480,439,480,439,480,439,480,439,480,439,4øStart

en vez de un único comando (aunque los bits tampoco coincidan)

Bien, entiendes el porque de que insista en esa librería no? Si logras hacerla funcionar, tendrás la flexibilidad para enviar cualquier cosa desde el Android y tus LG reaccionarán correctamente.

Esa es la idea. De otro modo tienes que agregar cada comando. Ya lo tienes resuelto, ahora se trata mas de un ejercicio de aprendizaje pero si lo resuelves será muy buen trabajo. Ahora no dispongo de tiempo porque estoy con un problema con sensores y estoy atascado, sino te daba una mano

Le echare un ojo. Te agradecería si me pudieses explicar el código:

LG::LG(int _mode, int _fan, int _temperature, int _state)
{
    // set sync
    codes[0] = first_high;
    codes[1] = first_low;
    crc = 0;
    FillBuffer(0,8,first_byte);
    FillBuffer(8,5,_state);
    if(_state==state_off)
        FillBuffer(13,3,mode_none);
    else
        FillBuffer(13,3,_mode);
    if(_state==state_off)
        FillBuffer(16,4,0);
    else
        FillBuffer(16,4,(byte)_temperature-temperature_offset);
    FillBuffer(20,1,0); //jet
    if(_state==state_off)
        FillBuffer(21,3,fan_none);
    else
        FillBuffer(21,3,_fan);
    FillBuffer(24,4,crc);
    codes[LG_buffer_size-1] = zero_and_one_high;
}

Por lo que veo es el array code definido en el LG.h con posiciones de array = LG_buffer_size En la posición 0 del array pone el valor 8850 (first_high) y luego en la posición 1 del array pone el valor 4100 (first_low). Para que mete luego el crc = 0? En mi caso lo puedo obviar? Que haría por ejemplo FillBuffer(0,8,first_byte) ?

Gracias

Estoy viendo la librería. Te comento que la ausencia de byte o el error de type que genera no es un errore. es un problema de compabilidad de versiones. A mi no me genera error.

Por otro lado tal como esta la librería no me funciona. Puedes subirla? tal como la tienes guardada. Creo que acá tenemos un problema de compatibilidades en las versiones de IDE. Yo con la 1.5.4 y tu seguro 1.0.X