1- // Copyright 2019 David Conran
1+ // Copyright 2019, 2021 David Conran
22
33// / @file
44// / @brief Support for TCL protocols.
@@ -53,6 +53,26 @@ void IRTcl112Ac::begin(void) { _irsend.begin(); }
5353// / Send the current internal state as an IR message.
5454// / @param[in] repeat Nr. of times the message will be repeated.
5555void IRTcl112Ac::send (const uint16_t repeat) {
56+ uint8_t save[kTcl112AcStateLength ];
57+ // Do we need to send the special "quiet" message?
58+ if (_quiet != _quiet_prev) {
59+ // Backup the current state.
60+ std::memcpy (save, _.raw , kTcl112AcStateLength );
61+ const uint8_t quiet_off[kTcl112AcStateLength ] = {
62+ 0x23 , 0xCB , 0x26 , 0x02 , 0x00 , 0x40 , 0x00 ,
63+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x65 };
64+ // Use a known good quiet/mute off/type 2 state for the time being.
65+ // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1528#issuecomment-876989044
66+ setRaw (quiet_off);
67+ setQuiet (_quiet);
68+ // Send it.
69+ _irsend.sendTcl112Ac (getRaw (), kTcl112AcStateLength , repeat);
70+ // Now it's been sent, update the quiet previous state.
71+ _quiet_prev = _quiet;
72+ // Restore the old state.
73+ setRaw (save);
74+ }
75+ // Send the normal (type 1) state.
5676 _irsend.sendTcl112Ac (getRaw (), kTcl112AcStateLength , repeat);
5777}
5878#endif // SEND_TCL112AC
@@ -62,10 +82,15 @@ void IRTcl112Ac::send(const uint16_t repeat) {
6282// / @param[in] length The length/size of the array.
6383// / @return The calculated checksum value.
6484uint8_t IRTcl112Ac::calcChecksum (uint8_t state[], const uint16_t length) {
65- if (length)
66- return sumBytes (state, length - 1 );
67- else
85+ if (length) {
86+ if (length > 4 && state[3 ] == 0x02 ) { // Special nessage?
87+ return sumBytes (state, length - 1 , 0xF ); // Checksum needs an offset.
88+ } else {
89+ return sumBytes (state, length - 1 );
90+ }
91+ } else {
6892 return 0 ;
93+ }
6994}
7095
7196// / Calculate & set the checksum for the current internal state of the remote.
@@ -91,6 +116,9 @@ void IRTcl112Ac::stateReset(void) {
91116 0x23 , 0xCB , 0x26 , 0x01 , 0x00 , 0x24 , 0x03 , 0x07 , 0x40 , 0x00 , 0x00 , 0x00 ,
92117 0x00 , 0x03 };
93118 std::memcpy (_.raw , reset, kTcl112AcStateLength );
119+ _quiet = false ;
120+ _quiet_prev = false ;
121+ _quiet_explictly_set = false ;
94122}
95123
96124// / Get a PTR to the internal state/code for this protocol.
@@ -115,21 +143,15 @@ void IRTcl112Ac::off(void) { setPower(false); }
115143
116144// / Change the power setting.
117145// / @param[in] on true, the setting is on. false, the setting is off.
118- void IRTcl112Ac::setPower (const bool on) {
119- _.Power = on;
120- }
146+ void IRTcl112Ac::setPower (const bool on) { _.Power = on; }
121147
122148// / Get the value of the current power setting.
123149// / @return true, the setting is on. false, the setting is off.
124- bool IRTcl112Ac::getPower (void ) const {
125- return _.Power ;
126- }
150+ bool IRTcl112Ac::getPower (void ) const { return _.Power ; }
127151
128152// / Get the operating mode setting of the A/C.
129153// / @return The current operating mode setting.
130- uint8_t IRTcl112Ac::getMode (void ) const {
131- return _.Mode ;
132- }
154+ uint8_t IRTcl112Ac::getMode (void ) const { return _.Mode ; }
133155
134156// / Set the operating mode of the A/C.
135157// / @param[in] mode The desired operating mode.
@@ -193,57 +215,39 @@ void IRTcl112Ac::setFan(const uint8_t speed) {
193215
194216// / Get the current fan speed setting.
195217// / @return The current fan speed/mode.
196- uint8_t IRTcl112Ac::getFan (void ) const {
197- return _.Fan ;
198- }
218+ uint8_t IRTcl112Ac::getFan (void ) const { return _.Fan ; }
199219
200220// / Set the economy setting of the A/C.
201221// / @param[in] on true, the setting is on. false, the setting is off.
202- void IRTcl112Ac::setEcono (const bool on) {
203- _.Econo = on;
204- }
222+ void IRTcl112Ac::setEcono (const bool on) { _.Econo = on; }
205223
206224// / Get the economy setting of the A/C.
207225// / @return true, the setting is on. false, the setting is off.
208- bool IRTcl112Ac::getEcono (void ) const {
209- return _.Econo ;
210- }
226+ bool IRTcl112Ac::getEcono (void ) const { return _.Econo ; }
211227
212228// / Set the Health (Filter) setting of the A/C.
213229// / @param[in] on true, the setting is on. false, the setting is off.
214- void IRTcl112Ac::setHealth (const bool on) {
215- _.Health = on;
216- }
230+ void IRTcl112Ac::setHealth (const bool on) { _.Health = on; }
217231
218232// / Get the Health (Filter) setting of the A/C.
219233// / @return true, the setting is on. false, the setting is off.
220- bool IRTcl112Ac::getHealth (void ) const {
221- return _.Health ;
222- }
234+ bool IRTcl112Ac::getHealth (void ) const { return _.Health ; }
223235
224236// / Set the Light (LED/Display) setting of the A/C.
225237// / @param[in] on true, the setting is on. false, the setting is off.
226- void IRTcl112Ac::setLight (const bool on) {
227- _.Light = !on; // Cleared when on.
228- }
238+ void IRTcl112Ac::setLight (const bool on) { _.Light = !on; } // Cleared when on.
229239
230240// / Get the Light (LED/Display) setting of the A/C.
231241// / @return true, the setting is on. false, the setting is off.
232- bool IRTcl112Ac::getLight (void ) const {
233- return !_.Light ;
234- }
242+ bool IRTcl112Ac::getLight (void ) const { return !_.Light ; }
235243
236244// / Set the horizontal swing setting of the A/C.
237245// / @param[in] on true, the setting is on. false, the setting is off.
238- void IRTcl112Ac::setSwingHorizontal (const bool on) {
239- _.SwingH = on;
240- }
246+ void IRTcl112Ac::setSwingHorizontal (const bool on) { _.SwingH = on; }
241247
242248// / Get the horizontal swing setting of the A/C.
243249// / @return true, the setting is on. false, the setting is off.
244- bool IRTcl112Ac::getSwingHorizontal (void ) const {
245- return _.SwingH ;
246- }
250+ bool IRTcl112Ac::getSwingHorizontal (void ) const { return _.SwingH ; }
247251
248252// / Set the vertical swing setting of the A/C.
249253// / @param[in] on true, the setting is on. false, the setting is off.
@@ -253,9 +257,7 @@ void IRTcl112Ac::setSwingVertical(const bool on) {
253257
254258// / Get the vertical swing setting of the A/C.
255259// / @return true, the setting is on. false, the setting is off.
256- bool IRTcl112Ac::getSwingVertical (void ) const {
257- return _.SwingV ;
258- }
260+ bool IRTcl112Ac::getSwingVertical (void ) const { return _.SwingV ; }
259261
260262// / Set the Turbo setting of the A/C.
261263// / @param[in] on true, the setting is on. false, the setting is off.
@@ -269,8 +271,24 @@ void IRTcl112Ac::setTurbo(const bool on) {
269271
270272// / Get the Turbo setting of the A/C.
271273// / @return true, the setting is on. false, the setting is off.
272- bool IRTcl112Ac::getTurbo (void ) const {
273- return _.Turbo ;
274+ bool IRTcl112Ac::getTurbo (void ) const { return _.Turbo ; }
275+
276+ // / Set the Quiet setting of the A/C.
277+ // / @param[in] on true, the setting is on. false, the setting is off.
278+ void IRTcl112Ac::setQuiet (const bool on) {
279+ _quiet_explictly_set = true ;
280+ _quiet = on;
281+ if (_.MsgType == kTcl112AcSpecial ) _.Quiet = on;
282+ }
283+
284+ // / Get the Quiet setting of the A/C.
285+ // / @param[in] def The default value to use if we are not sure.
286+ // / @return true, the setting is on. false, the setting is off.
287+ bool IRTcl112Ac::getQuiet (const bool def) const {
288+ if (_.MsgType == kTcl112AcSpecial )
289+ return _.Quiet ;
290+ else
291+ return _quiet_explictly_set ? _quiet : def;
274292}
275293
276294// / Convert a stdAc::opmode_t enum into its native mode.
@@ -326,26 +344,30 @@ stdAc::fanspeed_t IRTcl112Ac::toCommonFanSpeed(const uint8_t spd) {
326344}
327345
328346// / Convert the current internal state into its stdAc::state_t equivalent.
347+ // / @param[in] prev Ptr to the previous state if required.
329348// / @return The stdAc equivalent of the native settings.
330- stdAc::state_t IRTcl112Ac::toCommon (void ) const {
349+ stdAc::state_t IRTcl112Ac::toCommon (const stdAc:: state_t *prev ) const {
331350 stdAc::state_t result;
351+ // Start with the previous state if given it.
352+ if (prev != NULL ) result = *prev;
332353 result.protocol = decode_type_t ::TCL112AC;
333354 result.model = -1 ; // Not supported.
334- result.power = _.Power ;
335- result.mode = toCommonMode (_.Mode );
336- result.celsius = true ;
337- result.degrees = getTemp ();
338- result.fanspeed = toCommonFanSpeed (_.Fan );
339- result.swingv = _.SwingV ? stdAc::swingv_t ::kAuto :
340- stdAc::swingv_t ::kOff ;
341- result.swingh = _.SwingH ? stdAc::swingh_t ::kAuto :
342- stdAc::swingh_t ::kOff ;
343- result.turbo = _.Turbo ;
344- result.light = getLight ();
345- result.filter = _.Health ;
346- result.econo = _.Econo ;
355+ result.quiet = getQuiet (result.quiet );
356+ // The rest only get updated if it is a "normal" message.
357+ if (_.MsgType == kTcl112AcNormal ) {
358+ result.power = _.Power ;
359+ result.mode = toCommonMode (_.Mode );
360+ result.celsius = true ;
361+ result.degrees = getTemp ();
362+ result.fanspeed = toCommonFanSpeed (_.Fan );
363+ result.swingv = _.SwingV ? stdAc::swingv_t ::kAuto : stdAc::swingv_t ::kOff ;
364+ result.swingh = _.SwingH ? stdAc::swingh_t ::kAuto : stdAc::swingh_t ::kOff ;
365+ result.turbo = _.Turbo ;
366+ result.filter = _.Health ;
367+ result.econo = _.Econo ;
368+ result.light = getLight ();
369+ }
347370 // Not supported.
348- result.quiet = false ;
349371 result.clean = false ;
350372 result.beep = false ;
351373 result.sleep = -1 ;
@@ -357,19 +379,28 @@ stdAc::state_t IRTcl112Ac::toCommon(void) const {
357379// / @return A human readable string.
358380String IRTcl112Ac::toString (void ) const {
359381 String result = " " ;
360- result.reserve (140 ); // Reserve some heap for the string to reduce fragging.
361- result += addBoolToString (_.Power , kPowerStr , false );
362- result += addModeToString (_.Mode , kTcl112AcAuto , kTcl112AcCool ,
363- kTcl112AcHeat , kTcl112AcDry , kTcl112AcFan );
364- result += addTempFloatToString (getTemp ());
365- result += addFanToString (_.Fan , kTcl112AcFanHigh , kTcl112AcFanLow ,
366- kTcl112AcFanAuto , kTcl112AcFanAuto , kTcl112AcFanMed );
367- result += addBoolToString (_.Econo , kEconoStr );
368- result += addBoolToString (_.Health , kHealthStr );
369- result += addBoolToString (getLight (), kLightStr );
370- result += addBoolToString (_.Turbo , kTurboStr );
371- result += addBoolToString (_.SwingH , kSwingHStr );
372- result += addBoolToString (_.SwingV , kSwingVStr );
382+ result.reserve (150 ); // Reserve some heap for the string to reduce fragging.
383+ result += addIntToString (_.MsgType , D_STR_TYPE, false );
384+ switch (_.MsgType ) {
385+ case kTcl112AcNormal :
386+ result += addBoolToString (_.Power , kPowerStr );
387+ result += addModeToString (_.Mode , kTcl112AcAuto , kTcl112AcCool ,
388+ kTcl112AcHeat , kTcl112AcDry , kTcl112AcFan );
389+ result += addTempFloatToString (getTemp ());
390+ result += addFanToString (_.Fan , kTcl112AcFanHigh , kTcl112AcFanLow ,
391+ kTcl112AcFanAuto , kTcl112AcFanAuto ,
392+ kTcl112AcFanMed );
393+ result += addBoolToString (_.Econo , kEconoStr );
394+ result += addBoolToString (_.Health , kHealthStr );
395+ result += addBoolToString (_.Turbo , kTurboStr );
396+ result += addBoolToString (_.SwingH , kSwingHStr );
397+ result += addBoolToString (_.SwingV , kSwingVStr );
398+ result += addBoolToString (getLight (), kLightStr );
399+ break ;
400+ case kTcl112AcSpecial :
401+ result += addBoolToString (_.Quiet , kQuietStr );
402+ break ;
403+ }
373404 return result;
374405}
375406
0 commit comments