IRremote
ac_LG.hpp
Go to the documentation of this file.
1 /*
2  * ac_LG.hpp
3  *
4  * Contains functions for sending LG air conditioner IR Protocol
5  * There is no state plausibility check, e.g. you can send fan speed in Mode D and change temperature in mode F
6  *
7  * This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.
8  *
9  ************************************************************************************
10  * MIT License
11  *
12  * Copyright (c) 2021-2022 Armin Joachimsmeyer
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a copy
15  * of this software and associated documentation files (the "Software"), to deal
16  * in the Software without restriction, including without limitation the rights
17  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18  * copies of the Software, and to permit persons to whom the Software is furnished
19  * to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included in all
22  * copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
25  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
26  * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
28  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
29  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30  *
31  ************************************************************************************
32  */
33 #ifndef _AC_LG_HPP
34 #define _AC_LG_HPP
35 #include <Arduino.h>
36 
37 #if defined(INFO) && !defined(LOCAL_INFO)
38 #define LOCAL_INFO
39 #else
40 //#define LOCAL_INFO // This enables info output only for this file
41 #endif
42 //#define DEBUG // for more output from the LG-AC driver.
43 #include "IRremoteInt.h"
44 #include "ac_LG.h" // useful constants
45 #include "LongUnion.h"
46 
50 /*
51  * LG remote measurements: Type AKB73315611, Ver1.1 from 2011.03.01
52  * Internal crystal: 4 MHz
53  * Header: 8.9 ms mark 4.15 ms space
54  * Data: 500 / 540 and 500 / 1580;
55  * Clock is nor synchronized with gate so you have 19 and sometimes 19 and a spike pulses for mark
56  * Duty: 9 us on 17 us off => around 33 % duty
57  * NO REPEAT: If value like temperature has changed during long press, the last value is send at button release
58  * If you do a double press -tested with the fan button-, the next value can be sent after 118 ms
59  */
60 #define SIZE_OF_FAN_SPEED_MAPPING_TABLE 4
61 const int AC_FAN_TOWER[SIZE_OF_FAN_SPEED_MAPPING_TABLE] = { 0, 4, 6, 6 }; // last dummy entry to avoid out of bounds access
62 const int AC_FAN_WALL[SIZE_OF_FAN_SPEED_MAPPING_TABLE] = { 0, 2, 4, 5 }; // 0 -> low, 4 high, 5 -> cycle
63 
64 void Aircondition_LG::setType(bool aIsWallType) {
65  ACIsWallType = aIsWallType;
66 #if defined(LOCAL_INFO)
67  Serial.print(F("Set wall type to "));
68  Serial.println(aIsWallType);
69 #endif
70 }
71 
72 void Aircondition_LG::printMenu(Print *aSerial) {
73  aSerial->println();
74  aSerial->println();
75  aSerial->println(F("Type command and optional parameter without a separator"));
76  aSerial->println(F("0 Off"));
77  aSerial->println(F("1 On"));
78  aSerial->println(F("s Swing <0 or 1>"));
79  aSerial->println(F("a Auto clean <0 or 1>"));
80  aSerial->println(F("j Jet on"));
81  aSerial->println(F("e Energy saving <0 or 1>"));
82  aSerial->println(F("l Lights toggle"));
83  aSerial->println(F("f Fan speed <0 to 2 or 3 for cycle>"));
84  aSerial->println(F("t Temperature <18 to 30> degree"));
85  aSerial->println(F("+ Temperature + 1"));
86  aSerial->println(F("- Temperature - 1"));
87  aSerial->println(F("m <c(ool) or a(uto) or d(ehumidifying) or h(eating) or f(an) mode>"));
88  aSerial->println(F("S Sleep after <0 to 420> minutes"));
89  aSerial->println(F("T Timer on after <0 to 1439> minutes"));
90  aSerial->println(F("O Timer off after <0 to 1439> minutes"));
91  aSerial->println(F("C Clear all timer and sleep"));
92  aSerial->println(F("e.g. \"s1\" or \"t23\" or \"mc\" or \"O60\" or \"+\""));
93  aSerial->println(F("No plausibility check is made!"));
94  aSerial->println();
95 }
96 
97 /*
98  * Send repeat
99  * Repeat commands should be sent in a 110 ms raster.
100  * @param aCommand one of LG_COMMAND_OFF, LG_COMMAND_ON etc.
101  */
102 bool Aircondition_LG::sendCommandAndParameter(char aCommand, int aParameter) {
103  // Commands without parameter
104  switch (aCommand) {
105  case LG_COMMAND_OFF: // off
107  PowerIsOn = false;
108  return true;
109 
110  case LG_COMMAND_ON: // on
111  PowerIsOn = false; // set to false in order to suppress on bit
113  return true;
114 
115  case LG_COMMAND_JET:
116  IR_DEBUG_PRINTLN(F("Send jet on"));
118  return true;
119 
120  case LG_COMMAND_LIGHT:
122  return true;
123 
126  return true;
127 
129  if (18 <= Temperature && Temperature <= 29) {
130  Temperature++;
132  } else {
133  return false;
134  }
135  return true;
136 
138  if (19 <= Temperature && Temperature <= 30) {
139  Temperature--;
141  } else {
142  return false;
143  }
144  return true;
145 
146  }
147 
148  PowerIsOn = true;
149 
150  /*
151  * Now the commands which require a parameter
152  */
153  if (aParameter < 0) {
154  IR_DEBUG_PRINT(F("Error: Parameter is less than 0"));
155  return false;
156  }
157  switch (aCommand) {
158 
159  case LG_COMMAND_MODE:
160  Mode = aParameter + '0';
162  break;
163 
164  case LG_COMMAND_SWING:
165  IR_DEBUG_PRINT(F("Send air swing="));
166  IR_DEBUG_PRINTLN(aParameter);
167  if (ACIsWallType) {
168  if (aParameter) {
170  } else {
172  }
173  } else {
174  if (aParameter) {
176  } else {
178  }
179  }
180  break;
181 
183  IR_DEBUG_PRINT(F("Send auto clean="));
184  IR_DEBUG_PRINTLN(aParameter);
185  if (aParameter) {
187  } else {
189  }
190  break;
191 
192  case LG_COMMAND_ENERGY:
193  IR_DEBUG_PRINT(F("Send energy saving on="));
194  IR_DEBUG_PRINTLN(aParameter);
195  if (aParameter) {
197  } else {
199  }
200  break;
201 
203  if (aParameter < SIZE_OF_FAN_SPEED_MAPPING_TABLE) {
204  FanIntensity = aParameter;
206  } else {
207  return false;
208  }
209  break;
210 
212  if (18 <= aParameter && aParameter <= 30) {
213  Temperature = aParameter;
215  } else {
216  return false;
217  }
218  break;
219 
220  case LG_COMMAND_SLEEP:
221  // 420 = maximum I have recorded
222  if (aParameter <= 420) {
223  sendIRCommand(LG_SLEEP + aParameter);
224  } else {
225  return false;
226  }
227  break;
228 
229  case LG_COMMAND_TIMER_ON:
230  // 1440 = minutes of a day
231  if (aParameter <= 1439) {
232  sendIRCommand(LG_TIMER_ON + aParameter);
233  } else {
234  return false;
235  }
236  break;
237 
239  if (aParameter <= 1439) {
240  sendIRCommand(LG_TIMER_OFF + aParameter);
241  } else {
242  return false;
243  }
244  break;
245 
246  default:
247  return false;
248  }
249  return true;
250 }
251 
252 void Aircondition_LG::sendIRCommand(uint16_t aCommand) {
253 
254 #if defined(LOCAL_INFO)
255  Serial.print(F("Send code=0x"));
256  Serial.print(aCommand, HEX);
257  Serial.print(F(" | 0b"));
258  Serial.println(aCommand, BIN);
259 #endif
260 
261  IrSender.sendLG2((uint8_t) LG_ADDRESS, aCommand, 0);
262 }
263 
264 /*
265  * Takes values from static variables
266  */
268 
269  uint8_t tTemperature = Temperature;
270 #if defined(LOCAL_INFO)
271  Serial.print(F("Send temperature="));
272  Serial.print(tTemperature);
273  Serial.print(F(" fan intensity="));
274  Serial.print(FanIntensity);
275  Serial.print(F(" mode="));
276  Serial.println((char )Mode);
277 #endif
278 
279  WordUnion tIRCommand;
280  tIRCommand.UWord = 0;
281 
282  // Temperature is coded in the upper nibble of the LowByte
283  tIRCommand.UByte.LowByte = ((tTemperature - 15) << 4); // 16 -> 0x00, 18 -> 0x30, 30 -> 0xF0
284 
285  // Fan intensity is coded in the lower nibble of the LowByte
286  if (ACIsWallType) {
287  tIRCommand.UByte.LowByte |= AC_FAN_WALL[FanIntensity];
288  } else {
289  tIRCommand.UByte.LowByte |= AC_FAN_TOWER[FanIntensity];
290  }
291 
292  switch (Mode) {
293  case AC_MODE_COOLING:
294  tIRCommand.UByte.HighByte = LG_MODE_COOLING >> 8;
295  break;
296  case AC_MODE_HEATING:
297  tIRCommand.UByte.HighByte = LG_MODE_HEATING >> 8;
298  break;
299  case AC_MODE_AUTO:
300  tIRCommand.UByte.HighByte = LG_MODE_AUTO >> 8;
301  break;
302  case AC_MODE_FAN:
303  tTemperature = 18;
304  tIRCommand.UByte.HighByte = LG_MODE_FAN >> 8;
305  break;
307  tIRCommand.UWord = LG_MODE_DEHUMIDIFIYING;
308  break;
309  default:
310  break;
311  }
312  if (!PowerIsOn) {
313  // switch on requires masked bit
314  tIRCommand.UByte.HighByte &= ~(LG_SWITCH_ON_MASK >> 8);
315  }
316  PowerIsOn = true;
317 
318  sendIRCommand(tIRCommand.UWord);
319 }
320 
322 #endif // _AC_LG_HPP
LG_COMMAND_AUTO_CLEAN
#define LG_COMMAND_AUTO_CLEAN
Definition: ac_LG.h:77
Aircondition_LG::Temperature
uint8_t Temperature
Definition: ac_LG.h:132
LG_COMMAND_LIGHT
#define LG_COMMAND_LIGHT
Definition: ac_LG.h:80
LG_COMMAND_TEMPERATURE
#define LG_COMMAND_TEMPERATURE
Definition: ac_LG.h:82
WordUnion
Union to specify parts / manifestations of a 16 bit Word without casts and shifts.
Definition: LongUnion.h:34
LG_WALL_SWING_OFF
#define LG_WALL_SWING_OFF
Definition: ac_LG.h:59
LG_AUTO_CLEAN_ON
#define LG_AUTO_CLEAN_ON
Definition: ac_LG.h:68
LG_COMMAND_FAN_SPEED
#define LG_COMMAND_FAN_SPEED
Definition: ac_LG.h:81
WordUnion::UByte
struct WordUnion::@2 UByte
WordUnion::HighByte
uint8_t HighByte
Definition: LongUnion.h:37
Aircondition_LG::setType
void setType(bool aIsWallType)
Definition: ac_LG.hpp:64
LG_COMMAND_TIMER_OFF
#define LG_COMMAND_TIMER_OFF
Definition: ac_LG.h:88
LG_ENERGY_SAVING_OFF
#define LG_ENERGY_SAVING_OFF
Definition: ac_LG.h:56
Aircondition_LG::ACIsWallType
bool ACIsWallType
Definition: ac_LG.h:127
LG_COMMAND_ENERGY
#define LG_COMMAND_ENERGY
Definition: ac_LG.h:79
LG_MODE_FAN
#define LG_MODE_FAN
Definition: ac_LG.h:52
AC_MODE_DEHUMIDIFIYING
#define AC_MODE_DEHUMIDIFIYING
Definition: ac_LG.h:95
IR_DEBUG_PRINT
#define IR_DEBUG_PRINT(...)
If DEBUG, print the arguments, otherwise do nothing.
Definition: IRremoteInt.h:133
LG_MODE_HEATING
#define LG_MODE_HEATING
Definition: ac_LG.h:54
Aircondition_LG::sendTemperatureFanSpeedAndMode
void sendTemperatureFanSpeedAndMode()
Definition: ac_LG.hpp:267
Aircondition_LG::Mode
uint8_t Mode
Definition: ac_LG.h:133
LG_WALL_SWING_ON
#define LG_WALL_SWING_ON
Definition: ac_LG.h:58
ac_LG.h
LG_COMMAND_SWING
#define LG_COMMAND_SWING
Definition: ac_LG.h:76
SIZE_OF_FAN_SPEED_MAPPING_TABLE
#define SIZE_OF_FAN_SPEED_MAPPING_TABLE
Definition: ac_LG.hpp:60
LG_COMMAND_MODE
#define LG_COMMAND_MODE
Definition: ac_LG.h:85
Aircondition_LG::sendIRCommand
void sendIRCommand(uint16_t aCommand)
Definition: ac_LG.hpp:252
LG_SLEEP
#define LG_SLEEP
Definition: ac_LG.h:64
LG_COMMAND_JET
#define LG_COMMAND_JET
Definition: ac_LG.h:78
LG_SWITCH_ON_MASK
#define LG_SWITCH_ON_MASK
Definition: ac_LG.h:49
AC_FAN_TOWER
const int AC_FAN_TOWER[SIZE_OF_FAN_SPEED_MAPPING_TABLE]
Definition: ac_LG.hpp:61
LG_LIGHT
#define LG_LIGHT
Definition: ac_LG.h:67
Aircondition_LG::sendCommandAndParameter
bool sendCommandAndParameter(char aCommand, int aParameter)
Definition: ac_LG.hpp:102
AC_MODE_HEATING
#define AC_MODE_HEATING
Definition: ac_LG.h:98
LG_COMMAND_CLEAR_ALL
#define LG_COMMAND_CLEAR_ALL
Definition: ac_LG.h:89
LongUnion.h
LG_COMMAND_TIMER_ON
#define LG_COMMAND_TIMER_ON
Definition: ac_LG.h:87
Aircondition_LG::FanIntensity
uint8_t FanIntensity
Definition: ac_LG.h:131
LG_MODE_AUTO
#define LG_MODE_AUTO
Definition: ac_LG.h:53
LG_MODE_DEHUMIDIFIYING
#define LG_MODE_DEHUMIDIFIYING
Definition: ac_LG.h:51
LG_ENERGY_SAVING_ON
#define LG_ENERGY_SAVING_ON
Definition: ac_LG.h:55
LG_COMMAND_SLEEP
#define LG_COMMAND_SLEEP
Definition: ac_LG.h:86
AC_MODE_FAN
#define AC_MODE_FAN
Definition: ac_LG.h:96
LG_SWING_OFF
#define LG_SWING_OFF
Definition: ac_LG.h:61
LG_AUTO_CLEAN_OFF
#define LG_AUTO_CLEAN_OFF
Definition: ac_LG.h:69
LG_CLEAR_ALL
#define LG_CLEAR_ALL
Definition: ac_LG.h:65
IrSender
IRsend IrSender
Definition: IRSend.hpp:59
AC_MODE_AUTO
#define AC_MODE_AUTO
Definition: ac_LG.h:97
LG_COMMAND_TEMPERATURE_MINUS
#define LG_COMMAND_TEMPERATURE_MINUS
Definition: ac_LG.h:84
LG_ADDRESS
#define LG_ADDRESS
Definition: ac_LG.h:42
LG_MODE_COOLING
#define LG_MODE_COOLING
Definition: ac_LG.h:50
LG_TIMER_ON
#define LG_TIMER_ON
Definition: ac_LG.h:62
Aircondition_LG::PowerIsOn
bool PowerIsOn
Definition: ac_LG.h:128
LG_COMMAND_TEMPERATURE_PLUS
#define LG_COMMAND_TEMPERATURE_PLUS
Definition: ac_LG.h:83
AC_FAN_WALL
const int AC_FAN_WALL[SIZE_OF_FAN_SPEED_MAPPING_TABLE]
Definition: ac_LG.hpp:62
LG_SWING_ON
#define LG_SWING_ON
Definition: ac_LG.h:60
AC_MODE_COOLING
#define AC_MODE_COOLING
Definition: ac_LG.h:94
WordUnion::LowByte
uint8_t LowByte
Definition: LongUnion.h:36
LG_TIMER_OFF
#define LG_TIMER_OFF
Definition: ac_LG.h:63
WordUnion::UWord
uint16_t UWord
Definition: LongUnion.h:45
IR_DEBUG_PRINTLN
#define IR_DEBUG_PRINTLN(...)
If DEBUG, print the arguments as a line, otherwise do nothing.
Definition: IRremoteInt.h:137
LG_COMMAND_OFF
#define LG_COMMAND_OFF
Definition: ac_LG.h:74
IRremoteInt.h
Contains all declarations required for the interface to IRremote. Could not be named IRremote....
Aircondition_LG::printMenu
void printMenu(Print *aSerial)
Definition: ac_LG.hpp:72
IRsend::sendLG2
void sendLG2(uint8_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats)
LG2 uses a special repeat.
Definition: ir_LG.hpp:180
LG_JET_ON
#define LG_JET_ON
Definition: ac_LG.h:57
LG_POWER_DOWN
#define LG_POWER_DOWN
Definition: ac_LG.h:66
LG_COMMAND_ON
#define LG_COMMAND_ON
Definition: ac_LG.h:75