Sitelet https://github.com/crankyoldgit/IRremoteESP8266/commit/0f2ff1455af50ca7483de4e2ebaa762abbe262bc
Skip to content

Commit 0f2ff14

Browse files
authored
MITSUBISHI_AC: Added support for i-SAVE mode. (#1666)
* Added support for reading i-SAVE mode from a remote for Mitsubishi MSZ-FHnnVE A/C * Added mode modes which is supported by MZS-FH series. (unknown if existing in other series): - I-See mode - Absense Detect mode - Ecocool mode - Natural Flow mode
1 parent 187c533 commit 0f2ff14

9 files changed

Lines changed: 195 additions & 26 deletions

File tree

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ tools/mode2_decode
5151

5252
# Mac extended attributes
5353
.DS_Store
54+
/.vs

‎src/IRac.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,7 @@ void IRac::mitsubishi(IRMitsubishiAC *ac,
15721572
ac->setVane(ac->convertSwingV(swingv));
15731573
ac->setWideVane(ac->convertSwingH(swingh));
15741574
if (quiet) ac->setFan(kMitsubishiAcFanSilent);
1575+
ac->setISave10C(false);
15751576
// No Turbo setting available.
15761577
// No Light setting available.
15771578
// No Filter setting available.

‎src/IRtext.cpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ IRTEXT_CONST_STRING(kHoldStr, D_STR_HOLD); ///< "Hold"
8181
IRTEXT_CONST_STRING(kButtonStr, D_STR_BUTTON); ///< "Button"
8282
IRTEXT_CONST_STRING(k8CHeatStr, D_STR_8C_HEAT); ///< "8C Heat"
8383
IRTEXT_CONST_STRING(k10CHeatStr, D_STR_10C_HEAT); ///< "10C Heat"
84+
IRTEXT_CONST_STRING(kISeeStr, D_STR_ISEE); ///< "ISee"
85+
IRTEXT_CONST_STRING(kAbsenseDetectStr, D_STR_ABSENSEDETECT);
86+
///< "AbsenseDetect"
87+
IRTEXT_CONST_STRING(kDirectIndirectModeStr, D_STR_DIRECTINDIRECTMODE);
88+
///< "Direct/Indirect mode"
89+
IRTEXT_CONST_STRING(kDirectStr, D_STR_DIRECT); ///< "Direct"
90+
IRTEXT_CONST_STRING(kIndirectStr, D_STR_INDIRECT); ///< "Indirect"
91+
8492
IRTEXT_CONST_STRING(kNightStr, D_STR_NIGHT); ///< "Night"
8593
IRTEXT_CONST_STRING(kSilentStr, D_STR_SILENT); ///< "Silent"
8694
IRTEXT_CONST_STRING(kFilterStr, D_STR_FILTER); ///< "Filter"

‎src/IRtext.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,5 +231,11 @@ extern IRTEXT_CONST_PTR(kYbofbStr);
231231
extern IRTEXT_CONST_PTR(kYesStr);
232232
extern IRTEXT_CONST_PTR(kZoneFollowStr);
233233
extern IRTEXT_CONST_PTR(kAllProtocolNamesStr);
234+
extern IRTEXT_CONST_PTR(kISeeStr);
235+
extern IRTEXT_CONST_PTR(kEcocoolStr);
236+
extern IRTEXT_CONST_PTR(kAbsenseDetectStr);
237+
extern IRTEXT_CONST_PTR(kDirectIndirectModeStr);
238+
extern IRTEXT_CONST_PTR(kDirectStr);
239+
extern IRTEXT_CONST_PTR(kIndirectStr);
234240

235241
#endif // IRTEXT_H_

‎src/ir_Mitsubishi.cpp‎

Lines changed: 116 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ void IRMitsubishiAC::setTemp(const float degrees) {
399399
// Do we have a half degree celsius?
400400
_.HalfDegree = nrHalfDegrees & 1;
401401
_.Temp = static_cast<uint8_t>(nrHalfDegrees / 2 - kMitsubishiAcMinTemp);
402+
// If temp is modified, iSave10C cannot be ON (because temp is then > 10C)
403+
setISave10C(false);
402404
}
403405

404406
/// Get the current temperature setting.
@@ -452,8 +454,104 @@ void IRMitsubishiAC::setMode(const uint8_t mode) {
452454
return;
453455
}
454456
_.Mode = mode;
457+
// iSave10C can only be on in Heat mode.
458+
if (mode != kMitsubishiAcHeat) {
459+
setISave10C(false);
460+
}
461+
}
462+
463+
/// Set the iSave10C (i-SAVE) mode of the A/C.
464+
/// @param[in] state true, the setting is on. false, the setting is off.
465+
/// @note Normal minimum temp is 16C; i-SAVE mode works as gate to enable AC
466+
/// to use 10C as setting. However, when Remote control shows 10C, it still
467+
/// emits 16C on the "Temp" bits, and instead it uses other bits to indicate
468+
/// a target temp of 10C.
469+
/// Slightly strange, but I guess it's to keep compatibility to systems
470+
/// without i-SAVE.
471+
/// i-SAVE only has this 10C functionality when the AC is already in Heat mode.
472+
/// In all other modes, minimum temp is 16C.
473+
/// I have found no other difference between normal Heat mode and i-SAVE
474+
/// other than the ability to go to 10C.
475+
/// In this implementation, i-SAVE mode is ONLY used to enable the AC
476+
/// temperature setting to 10C. Therefore "Temp" is set to 16 disregarding
477+
/// what the remote shows, and mode is set to Heat.
478+
void IRMitsubishiAC::setISave10C(const bool state) {
479+
if (state) setMode(kMitsubishiAcHeat);
480+
if (state) setTemp(kMitsubishiAcMinTemp);
481+
_.iSave10C = state;
482+
}
483+
484+
/// Get the iSave10C (i-SAVE) mode of the A/C.
485+
/// @return true, the setting is on. false, the setting is off.
486+
bool IRMitsubishiAC::getISave10C(void) const {
487+
return _.iSave10C;
488+
}
489+
490+
/// Set the requested iSee mode.
491+
/// @param[in] state requested iSee mode.
492+
void IRMitsubishiAC::setISee(const bool state) {
493+
_.ISee = state;
494+
}
495+
496+
/// Get the iSee mode of the A/C.
497+
/// @return The iSee mode setting.
498+
bool IRMitsubishiAC::getISee(void) const {
499+
return _.ISee;
500+
}
501+
502+
/// Set the requested Ecocool mode.
503+
/// @param[in] state requested Ecocool mode.
504+
void IRMitsubishiAC::setEcocool(const bool state) {
505+
_.Ecocool = state;
506+
}
507+
508+
/// Get the Ecocool mode of the A/C.
509+
/// @return The Ecocool mode setting.
510+
bool IRMitsubishiAC::getEcocool(void) const {
511+
return _.Ecocool;
512+
}
513+
514+
/// Set the requested Absense Detect mode.
515+
/// @param[in] state requested Absense Detect mode.
516+
void IRMitsubishiAC::setAbsenseDetect(const bool state) {
517+
_.AbsenseDetect = state;
518+
}
519+
520+
/// Get the Absense Detect mode of the A/C.
521+
/// @return The Absense Detect mode setting.
522+
bool IRMitsubishiAC::getAbsenseDetect(void) const {
523+
return _.AbsenseDetect;
524+
}
525+
526+
/// Set the requested Direct/Indirect mode. Only works if I-See mode is ON.
527+
/// @param[in] mode requested Direct/Indirect mode.
528+
void IRMitsubishiAC::setDirectIndirect(const uint8_t mode) {
529+
if (_.ISee) {
530+
_.DirectIndirect = std::min(mode, kMitsubishiAcDirect); // bounds check
531+
} else {
532+
_.DirectIndirect = 0;
533+
}
534+
}
535+
536+
/// Get the Direct/Indirect mode of the A/C.
537+
/// @return The native mode setting.
538+
uint8_t IRMitsubishiAC::getDirectIndirect(void) const {
539+
return _.DirectIndirect;
540+
}
541+
542+
/// Set the requested Natural Flow mode.
543+
/// @param[in] state requested Natural Flow mode.
544+
void IRMitsubishiAC::setNaturalFlow(const bool state) {
545+
_.NaturalFlow = state;
546+
}
547+
548+
/// Get the Natural Flow mode of the A/C.
549+
/// @return The Natural Flow mode setting.
550+
bool IRMitsubishiAC::getNaturalFlow(void) const {
551+
return _.NaturalFlow;
455552
}
456553

554+
457555
/// Set the requested vane (Vertical Swing) operation mode of the a/c unit.
458556
/// @note On some models, this represents the Right vertical vane.
459557
/// @param[in] position The position/mode to set the vane to.
@@ -463,25 +561,13 @@ void IRMitsubishiAC::setVane(const uint8_t position) {
463561
_.Vane = pos;
464562
}
465563

466-
/// Set the requested wide-vane (Horizontal Swing) operation mode of the a/c.
467-
/// @param[in] position The position/mode to set the wide vane to.
468-
void IRMitsubishiAC::setWideVane(const uint8_t position) {
469-
_.WideVane = std::min(position, kMitsubishiAcWideVaneAuto);
470-
}
471-
472564
/// Get the Vane (Vertical Swing) mode of the A/C.
473565
/// @note On some models, this represents the Right vertical vane.
474566
/// @return The native position/mode setting.
475567
uint8_t IRMitsubishiAC::getVane(void) const {
476568
return _.Vane;
477569
}
478570

479-
/// Get the Wide Vane (Horizontal Swing) mode of the A/C.
480-
/// @return The native position/mode setting.
481-
uint8_t IRMitsubishiAC::getWideVane(void) const {
482-
return _.WideVane;
483-
}
484-
485571
/// Set the requested Left Vane (Vertical Swing) operation mode of the a/c unit.
486572
/// @param[in] position The position/mode to set the vane to.
487573
void IRMitsubishiAC::setVaneLeft(const uint8_t position) {
@@ -492,6 +578,18 @@ void IRMitsubishiAC::setVaneLeft(const uint8_t position) {
492578
/// @return The native position/mode setting.
493579
uint8_t IRMitsubishiAC::getVaneLeft(void) const { return _.VaneLeft; }
494580

581+
/// Set the requested wide-vane (Horizontal Swing) operation mode of the a/c.
582+
/// @param[in] position The position/mode to set the wide vane to.
583+
void IRMitsubishiAC::setWideVane(const uint8_t position) {
584+
_.WideVane = std::min(position, kMitsubishiAcWideVaneAuto);
585+
}
586+
587+
/// Get the Wide Vane (Horizontal Swing) mode of the A/C.
588+
/// @return The native position/mode setting.
589+
uint8_t IRMitsubishiAC::getWideVane(void) const {
590+
return _.WideVane;
591+
}
592+
495593
/// Get the clock time of the A/C unit.
496594
/// @return Nr. of 10 minute increments past midnight.
497595
/// @note 1 = 1/6 hour (10 minutes). e.g. 4pm = 48.
@@ -777,6 +875,12 @@ String IRMitsubishiAC::toString(void) const {
777875
result += ')';
778876
}
779877
result += addBoolToString(_.WeeklyTimer, kWeeklyTimerStr);
878+
result += addBoolToString(_.iSave10C, k10CHeatStr);
879+
result += addBoolToString(_.ISee, kISeeStr);
880+
result += addBoolToString(_.Ecocool, kEconoStr);
881+
result += addBoolToString(_.AbsenseDetect, kAbsenseDetectStr);
882+
result += addIntToString(_.DirectIndirect, kDirectIndirectModeStr);
883+
result += addBoolToString(_.NaturalFlow, kFreshStr);
780884
return result;
781885
}
782886

‎src/ir_Mitsubishi.h‎

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
// Brand: Mitsubishi Electric, Model: MSZ-SF25VE3 A/C (MITSUBISHI_AC)
3535
// Brand: Mitsubishi Electric, Model: SG15D remote (MITSUBISHI_AC)
3636
// Brand: Mitsubishi Electric, Model: MSZ-ZW4017S A/C (MITSUBISHI_AC)
37+
// Brand: Mitsubishi Electric, Model: MSZ-FHnnVE A/C (MITSUBISHI_AC)
3738

3839
#ifndef IR_MITSUBISHI_H_
3940
#define IR_MITSUBISHI_H_
@@ -62,7 +63,8 @@ union Mitsubishi144Protocol{
6263
// Byte 6
6364
uint8_t :3;
6465
uint8_t Mode :3;
65-
uint8_t :2;
66+
uint8_t ISee : 1;
67+
uint8_t :1;
6668
// Byte 7
6769
uint8_t Temp :4;
6870
uint8_t HalfDegree :1;
@@ -72,7 +74,7 @@ union Mitsubishi144Protocol{
7274
uint8_t WideVane:4; // SwingH
7375
// Byte 9
7476
uint8_t Fan :3;
75-
uint8_t Vane :3; // SwingV
77+
uint8_t Vane :3; // SwingV or VaneRight
7678
uint8_t VaneBit :1;
7779
uint8_t FanAuto :1;
7880
// Byte 10
@@ -86,13 +88,21 @@ union Mitsubishi144Protocol{
8688
uint8_t WeeklyTimer :1;
8789
uint8_t :4;
8890
// Byte 14
89-
uint8_t :8;
91+
uint8_t :5;
92+
uint8_t Ecocool :1;
93+
uint8_t :2;
9094
// Byte 15
91-
uint8_t :8;
95+
uint8_t DirectIndirect:2;
96+
uint8_t AbsenseDetect :1;
97+
uint8_t :2;
98+
uint8_t iSave10C :1; // i-SAVE:mode=Heat & iSave=on AND 10C on remote
99+
uint8_t :2;
92100
// Byte 16
93-
uint8_t :3;
94-
uint8_t VaneLeft :3; // SwingV(Left)
95-
uint8_t :2;
101+
uint8_t :1;
102+
uint8_t NaturalFlow :1;
103+
uint8_t :1;
104+
uint8_t VaneLeft :3; // SwingV(Left)
105+
uint8_t :2;
96106
// Byte 17
97107
uint8_t Sum :8;
98108
};
@@ -126,6 +136,9 @@ const uint8_t kMitsubishiAcWideVaneRight = 0b0100; // 4
126136
const uint8_t kMitsubishiAcWideVaneRightMax = 0b0101; // 5
127137
const uint8_t kMitsubishiAcWideVaneWide = 0b0110; // 6
128138
const uint8_t kMitsubishiAcWideVaneAuto = 0b1000; // 8
139+
const uint8_t kMitsubishiAcDirectOff = 0b00; // Vanes move when AC wants to.
140+
const uint8_t kMitsubishiAcIndirect = 0b01;
141+
const uint8_t kMitsubishiAcDirect = 0b11;
129142
const uint8_t kMitsubishiAcNoTimer = 0;
130143
const uint8_t kMitsubishiAcStartTimer = 5;
131144
const uint8_t kMitsubishiAcStopTimer = 3;
@@ -274,12 +287,24 @@ class IRMitsubishiAC {
274287
uint8_t getFan(void) const;
275288
void setMode(const uint8_t mode);
276289
uint8_t getMode(void) const;
277-
void setVane(const uint8_t position);
278-
void setWideVane(const uint8_t position);
290+
void setISave10C(const bool state);
291+
bool getISave10C(void) const;
292+
void setISee(const bool state);
293+
bool getISee(void) const;
294+
void setDirectIndirect(const uint8_t position);
295+
uint8_t getDirectIndirect(void) const;
296+
void setEcocool(const bool state);
297+
bool getEcocool(void) const;
298+
void setAbsenseDetect(const bool state);
299+
bool getAbsenseDetect(void) const;
300+
void setNaturalFlow(const bool state);
301+
bool getNaturalFlow(void) const;
302+
void setVane(const uint8_t position); // controls RIGHT vane on some models
279303
uint8_t getVane(void) const;
280-
uint8_t getWideVane(void) const;
281304
void setVaneLeft(const uint8_t position);
282305
uint8_t getVaneLeft(void) const;
306+
void setWideVane(const uint8_t position);
307+
uint8_t getWideVane(void) const;
283308
uint8_t* getRaw(void);
284309
void setRaw(const uint8_t* data);
285310
uint8_t getClock(void) const;

‎src/locale/defaults.h‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@
120120
#ifndef D_STR_IFEEL
121121
#define D_STR_IFEEL "IFeel"
122122
#endif // D_STR_IFEEL
123+
#ifndef D_STR_ISEE
124+
#define D_STR_ISEE "ISee"
125+
#endif // D_STR_ISEE
123126
#ifndef D_STR_HUMID
124127
#define D_STR_HUMID "Humid"
125128
#endif // D_STR_HUMID
@@ -207,6 +210,19 @@
207210
#ifndef D_STR_SENSOR
208211
#define D_STR_SENSOR "Sensor"
209212
#endif // D_STR_SENSOR
213+
#ifndef D_STR_ABSENSEDETECT
214+
#define D_STR_ABSENSEDETECT "Absense detect"
215+
#endif // D_STR_ABSENSEDETECT
216+
#ifndef D_STR_DIRECT
217+
#define D_STR_DIRECT "Direct"
218+
#endif // D_STR_DIRECT
219+
#ifndef D_STR_INDIRECT
220+
#define D_STR_INDIRECT "Indirect"
221+
#endif // D_STR_INDIRECT
222+
#ifndef D_STR_DIRECTINDIRECTMODE
223+
#define D_STR_DIRECTINDIRECTMODE D_STR_DIRECT " / " \
224+
D_STR_INDIRECT " " D_STR_MODE
225+
#endif // D_STR_DIRECTINDIRECTMODE
210226
#ifndef D_STR_DISPLAY
211227
#define D_STR_DISPLAY "Display"
212228
#endif // D_STR_DISPLAY

‎test/IRac_test.cpp‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1449,7 +1449,9 @@ TEST(TestIRac, Mitsubishi) {
14491449
"Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 2 (Medium), "
14501450
"Swing(V): 0 (Auto), Swing(H): 3 (Middle), "
14511451
"Clock: 14:30, On Timer: 00:00, Off Timer: 00:00, Timer: -, "
1452-
"Weekly Timer: Off";
1452+
"Weekly Timer: Off"
1453+
", 10C Heat: Off, ISee: Off, Econo: Off, Absense detect: Off, "
1454+
"Direct / Indirect Mode: 0, Fresh: Off";
14531455

14541456
ac.begin();
14551457
irac.mitsubishi(&ac,

‎test/ir_Mitsubishi_test.cpp‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -913,15 +913,19 @@ TEST(TestMitsubishiACClass, HumanReadable) {
913913
"Power: On, Mode: 1 (Heat), Temp: 22C, Fan: 6 (Quiet), "
914914
"Swing(V): 0 (Auto), Swing(H): 3 (Middle), "
915915
"Clock: 17:10, On Timer: 00:00, Off Timer: 00:00, Timer: -, "
916-
"Weekly Timer: Off",
916+
"Weekly Timer: Off"
917+
", 10C Heat: Off, ISee: Off, Econo: Off, Absense detect: Off, "
918+
"Direct / Indirect Mode: 0, Fresh: Off",
917919
ac.toString());
918920
ac.setTemp(21.5);
919921
ac.setWeeklyTimerEnabled(true);
920922
EXPECT_EQ(
921923
"Power: On, Mode: 1 (Heat), Temp: 21.5C, Fan: 6 (Quiet), "
922924
"Swing(V): 0 (Auto), Swing(H): 3 (Middle), "
923925
"Clock: 17:10, On Timer: 00:00, Off Timer: 00:00, Timer: -, "
924-
"Weekly Timer: On",
926+
"Weekly Timer: On"
927+
", 10C Heat: Off, ISee: Off, Econo: Off, Absense detect: Off, "
928+
"Direct / Indirect Mode: 0, Fresh: Off",
925929
ac.toString());
926930
}
927931

@@ -1434,7 +1438,9 @@ TEST(TestDecodeMitsubishiAC, Issue891) {
14341438
"Power: Off, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), "
14351439
"Swing(V): 0 (Auto), Swing(H): 3 (Middle), "
14361440
"Clock: 00:00, On Timer: 00:00, Off Timer: 00:00, Timer: -, "
1437-
"Weekly Timer: Off",
1441+
"Weekly Timer: Off"
1442+
", 10C Heat: Off, ISee: Off, Econo: Off, Absense detect: Off, "
1443+
"Direct / Indirect Mode: 0, Fresh: Off",
14381444
ac.toString());
14391445
}
14401446

0 commit comments

Comments
 (0)