#include // These are protected methods, i.e. generic MitsubishiHeavy instances cannot be created directly MitsubishiHeavyHeatpumpIR::MitsubishiHeavyHeatpumpIR() : HeatpumpIR() { } // The different models just set the model accordingly MitsubishiHeavyZJHeatpumpIR::MitsubishiHeavyZJHeatpumpIR() : MitsubishiHeavyHeatpumpIR() { static const char model[] PROGMEM = "mitsubishi_heavy_zj"; static const char info[] PROGMEM = "{\"mdl\":\"mitsubishi_heavy_zj\",\"dn\":\"Mitsubishi Heavy ZJ\",\"mT\":18,\"xT\":30,\"fs\":3}"; _model = model; _info = info; _mitsubishiModel = MITSUBISHIHEAVY_ZJ; } MitsubishiHeavyZMHeatpumpIR::MitsubishiHeavyZMHeatpumpIR() : MitsubishiHeavyHeatpumpIR() { static const char model[] PROGMEM = "mitsubishi_heavy_zm"; static const char info[] PROGMEM = "{\"mdl\":\"mitsubishi_heavy_zm\",\"dn\":\"Mitsubishi Heavy ZM\",\"mT\":18,\"xT\":30,\"fs\":4}"; _model = model; _info = info; _mitsubishiModel = MITSUBISHIHEAVY_ZM; } MitsubishiHeavyZMPHeatpumpIR::MitsubishiHeavyZMPHeatpumpIR() : MitsubishiHeavyHeatpumpIR() { static const char model[] PROGMEM = "mitsubishi_heavy_zmp"; static const char info[] PROGMEM = "{\"mdl\":\"mitsubishi_heavy_zmp\",\"dn\":\"Mitsubishi Heavy ZMP\",\"mT\":18,\"xT\":30,\"fs\":3}"; _model = model; _info = info; _mitsubishiModel = MITSUBISHIHEAVY_ZMP; } void MitsubishiHeavyHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd) { send(IR, powerModeCmd, operatingModeCmd, fanSpeedCmd, temperatureCmd, swingVCmd, swingHCmd, true, false, false); } // This is a virtual dummy method, i.e. MitsubishiHeavyZJHeatpumpIR::send or MitsubishiHeavyZMHeatpumpIR::send is called instead void MitsubishiHeavyHeatpumpIR::send(IRSender&, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, bool, bool, bool) { } void MitsubishiHeavyZJHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool cleanModeCmd, bool silentModeCmd, bool _3DAutoCmd) { // Sensible defaults for the heat pump mode uint8_t powerMode = MITSUBISHI_HEAVY_MODE_ON; uint8_t operatingMode = MITSUBISHI_HEAVY_MODE_HEAT; uint8_t fanSpeed = MITSUBISHI_HEAVY_ZJ_FAN_AUTO; uint8_t temperature = 23; uint8_t swingV = MITSUBISHI_HEAVY_ZJ_VS_STOP; uint8_t swingH = MITSUBISHI_HEAVY_ZJ_HS_STOP; uint8_t cleanMode = MITSUBISHI_HEAVY_ZJ_CLEAN_OFF; if (powerModeCmd == POWER_OFF) { powerMode = MITSUBISHI_HEAVY_MODE_OFF; } if (cleanModeCmd && powerModeCmd == POWER_OFF && (operatingModeCmd == MODE_AUTO || operatingModeCmd == MODE_COOL || operatingModeCmd == MODE_DRY)) { powerMode = MITSUBISHI_HEAVY_MODE_ON; cleanMode = MITSUBISHI_HEAVY_CLEAN_ON; } switch (operatingModeCmd) { case MODE_AUTO: operatingMode = MITSUBISHI_HEAVY_MODE_AUTO; break; case MODE_HEAT: operatingMode = MITSUBISHI_HEAVY_MODE_HEAT; break; case MODE_COOL: operatingMode = MITSUBISHI_HEAVY_MODE_COOL; break; case MODE_DRY: operatingMode = MITSUBISHI_HEAVY_MODE_DRY; break; case MODE_FAN: operatingMode = MITSUBISHI_HEAVY_MODE_FAN; break; } switch (fanSpeedCmd) { case FAN_AUTO: fanSpeed = MITSUBISHI_HEAVY_ZJ_FAN_AUTO; break; case FAN_1: fanSpeed = MITSUBISHI_HEAVY_ZJ_FAN1; break; case FAN_2: fanSpeed = MITSUBISHI_HEAVY_ZJ_FAN2; break; case FAN_3: fanSpeed = MITSUBISHI_HEAVY_ZJ_FAN3; break; } if (silentModeCmd) { // Silent mode doesn't exist on ZJ model, use ECONO mode instead fanSpeed = MITSUBISHI_HEAVY_ZJ_SILENT_ON; } if ( temperatureCmd > 17 && temperatureCmd < 31) { temperature = (~((temperatureCmd - 17) << 4)) & 0xF0; } switch (swingVCmd) { case VDIR_MANUAL: swingV = MITSUBISHI_HEAVY_ZJ_VS_STOP; break; case VDIR_SWING: swingV = MITSUBISHI_HEAVY_ZJ_VS_SWING; break; case VDIR_UP: swingV = MITSUBISHI_HEAVY_ZJ_VS_UP; break; case VDIR_MUP: swingV = MITSUBISHI_HEAVY_ZJ_VS_MUP; break; case VDIR_MIDDLE: swingV = MITSUBISHI_HEAVY_ZJ_VS_MIDDLE; break; case VDIR_MDOWN: swingV = MITSUBISHI_HEAVY_ZJ_VS_MDOWN; break; case VDIR_DOWN: swingV = MITSUBISHI_HEAVY_ZJ_VS_DOWN; break; } switch (swingHCmd) { case HDIR_MANUAL: swingH = MITSUBISHI_HEAVY_ZJ_HS_STOP; break; case HDIR_SWING: swingH = MITSUBISHI_HEAVY_ZJ_HS_SWING; break; case HDIR_MIDDLE: swingH = MITSUBISHI_HEAVY_ZJ_HS_MIDDLE; break; case HDIR_LEFT: swingH = MITSUBISHI_HEAVY_ZJ_HS_LEFT; break; case HDIR_MLEFT: swingH = MITSUBISHI_HEAVY_ZJ_HS_MLEFT; break; case HDIR_RIGHT: swingH = MITSUBISHI_HEAVY_ZJ_HS_RIGHT; break; case HDIR_MRIGHT: swingH = MITSUBISHI_HEAVY_ZJ_HS_MRIGHT; break; } if (_3DAutoCmd == true && (operatingModeCmd == MODE_AUTO || operatingModeCmd == MODE_COOL || operatingModeCmd == MODE_HEAT)) { swingH = MITSUBISHI_HEAVY_ZJ_HS_3DAUTO; } sendMitsubishiHeavy(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH, cleanMode); } void MitsubishiHeavyZMHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool cleanModeCmd, bool silentModeCmd, bool _3DAutoCmd) { // Sensible defaults for the heat pump mode uint8_t powerMode = MITSUBISHI_HEAVY_MODE_ON; uint8_t operatingMode = MITSUBISHI_HEAVY_MODE_HEAT; uint8_t fanSpeed = MITSUBISHI_HEAVY_ZM_FAN_AUTO; uint8_t temperature = 23; uint8_t swingV = MITSUBISHI_HEAVY_ZM_VS_STOP; uint8_t swingH = MITSUBISHI_HEAVY_ZM_HS_STOP; uint8_t cleanMode = MITSUBISHI_HEAVY_ZM_CLEAN_OFF; uint8_t _3DAuto = MITSUBISHI_HEAVY_ZM_3DAUTO_OFF; uint8_t silentMode = MITSUBISHI_HEAVY_ZM_SILENT_OFF; if (powerModeCmd == POWER_OFF) { powerMode = MITSUBISHI_HEAVY_MODE_OFF; } if (cleanModeCmd && powerModeCmd == POWER_OFF && (operatingModeCmd == MODE_AUTO || operatingModeCmd == MODE_COOL || operatingModeCmd == MODE_DRY)) { powerMode = MITSUBISHI_HEAVY_MODE_ON; cleanMode = MITSUBISHI_HEAVY_CLEAN_ON; } if (silentModeCmd && !(operatingModeCmd == MODE_DRY || operatingModeCmd == MODE_FAN)) { silentMode = MITSUBISHI_HEAVY_ZM_SILENT_ON; } if (_3DAutoCmd && !(operatingModeCmd == MODE_DRY || operatingModeCmd == MODE_FAN)) { _3DAuto = MITSUBISHI_HEAVY_ZM_3DAUTO_ON; } switch (operatingModeCmd) { case MODE_AUTO: operatingMode = MITSUBISHI_HEAVY_MODE_AUTO; break; case MODE_HEAT: operatingMode = MITSUBISHI_HEAVY_MODE_HEAT; break; case MODE_COOL: operatingMode = MITSUBISHI_HEAVY_MODE_COOL; break; case MODE_DRY: operatingMode = MITSUBISHI_HEAVY_MODE_DRY; break; case MODE_FAN: operatingMode = MITSUBISHI_HEAVY_MODE_FAN; break; } switch (fanSpeedCmd) { case FAN_AUTO: fanSpeed = MITSUBISHI_HEAVY_ZM_FAN_AUTO; break; case FAN_1: fanSpeed = MITSUBISHI_HEAVY_ZM_FAN1; break; case FAN_2: fanSpeed = MITSUBISHI_HEAVY_ZM_FAN2; break; case FAN_3: fanSpeed = MITSUBISHI_HEAVY_ZM_FAN3; break; case FAN_4: fanSpeed = MITSUBISHI_HEAVY_ZM_FAN4; break; case FAN_5: //Eco mode fanSpeed = MITSUBISHI_HEAVY_ZM_ECONO; break; } if ( temperatureCmd > 17 && temperatureCmd < 31) { temperature = (~(temperatureCmd - 17) & 0x0F); } switch (swingVCmd) { case VDIR_MANUAL: swingV = MITSUBISHI_HEAVY_ZM_VS_STOP; break; case VDIR_SWING: swingV = MITSUBISHI_HEAVY_ZM_VS_SWING; break; case VDIR_UP: swingV = MITSUBISHI_HEAVY_ZM_VS_UP; break; case VDIR_MUP: swingV = MITSUBISHI_HEAVY_ZM_VS_MUP; break; case VDIR_MIDDLE: swingV = MITSUBISHI_HEAVY_ZM_VS_MIDDLE; break; case VDIR_MDOWN: swingV = MITSUBISHI_HEAVY_ZM_VS_MDOWN; break; case VDIR_DOWN: swingV = MITSUBISHI_HEAVY_ZM_VS_DOWN; break; } switch (swingHCmd) { case HDIR_MANUAL: swingH = MITSUBISHI_HEAVY_ZM_HS_STOP; break; case HDIR_SWING: swingH = MITSUBISHI_HEAVY_ZM_HS_SWING; break; case HDIR_MIDDLE: swingH = MITSUBISHI_HEAVY_ZM_HS_MIDDLE; break; case HDIR_LEFT: swingH = MITSUBISHI_HEAVY_ZM_HS_LEFT; break; case HDIR_MLEFT: swingH = MITSUBISHI_HEAVY_ZM_HS_MLEFT; break; case HDIR_RIGHT: swingH = MITSUBISHI_HEAVY_ZM_HS_RIGHT; break; case HDIR_MRIGHT: swingH = MITSUBISHI_HEAVY_ZM_HS_MRIGHT; break; } sendMitsubishiHeavy(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH, cleanMode, silentMode, _3DAuto); } void MitsubishiHeavyZMPHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd, bool cleanModeCmd, bool silentModeCmd, bool _3DAutoCmd) { // Sensible defaults for the heat pump mode uint8_t powerMode = MITSUBISHI_HEAVY_MODE_ON; uint8_t operatingMode = MITSUBISHI_HEAVY_MODE_HEAT; uint8_t fanSpeed = MITSUBISHI_HEAVY_ZMP_FAN_AUTO; uint8_t temperature = 23; uint8_t swingV = MITSUBISHI_HEAVY_ZMP_VS_STOP; uint8_t swingH = MITSUBISHI_HEAVY_ZMP_HS_STOP; uint8_t cleanMode = MITSUBISHI_HEAVY_ZMP_CLEAN_OFF; if (powerModeCmd == POWER_OFF) { powerMode = MITSUBISHI_HEAVY_MODE_OFF; } if (operatingModeCmd == MODE_MAINT && powerModeCmd == POWER_OFF) { powerMode = MITSUBISHI_HEAVY_MODE_ON; cleanMode = MITSUBISHI_HEAVY_ZMP_CLEAN_ON; } switch (operatingModeCmd) { case MODE_AUTO: operatingMode = MITSUBISHI_HEAVY_MODE_AUTO; //In MODE_AUTO we need to handle temperature differently. It can range from -6 to +6 temperature = 0x80 - (0x10*temperatureCmd); break; case MODE_HEAT: operatingMode = MITSUBISHI_HEAVY_MODE_HEAT; break; case MODE_COOL: operatingMode = MITSUBISHI_HEAVY_MODE_COOL; break; case MODE_DRY: operatingMode = MITSUBISHI_HEAVY_MODE_DRY; break; case MODE_FAN: //Fan mode has no temperature setting //ZMP model uses different code for fan mode. operatingMode = MITSUBISHI_HEAVY_ZMP_MODE_FAN; temperature = 0; break; case MODE_MAINT: //Specify maintenance mode to activate clean mode operatingMode = MITSUBISHI_HEAVY_ZMP_MODE_MAINT; break; } switch (fanSpeedCmd) { case FAN_AUTO: fanSpeed = MITSUBISHI_HEAVY_ZMP_FAN_AUTO; break; case FAN_1: fanSpeed = MITSUBISHI_HEAVY_ZMP_FAN1; break; case FAN_2: fanSpeed = MITSUBISHI_HEAVY_ZMP_FAN2; break; case FAN_3: fanSpeed = MITSUBISHI_HEAVY_ZMP_FAN3; break; case FAN_4: //Map FAN_4 to HiPower fanSpeed = MITSUBISHI_HEAVY_ZMP_HIPOWER; break; case FAN_5: //Map FAN_5 to Econo fanSpeed = MITSUBISHI_HEAVY_ZMP_ECONO; break; } if (silentModeCmd) { // Silent mode doesn't exist on ZMP model, use ECONO mode instead fanSpeed = MITSUBISHI_HEAVY_ZMP_SILENT_ON; } if ( temperatureCmd > 17 && temperatureCmd < 31) { temperature = (~((temperatureCmd - 17) << 4)) & 0xF0; } switch (swingVCmd) { case VDIR_MANUAL: swingV = MITSUBISHI_HEAVY_ZMP_VS_STOP; break; case VDIR_SWING: swingV = MITSUBISHI_HEAVY_ZMP_VS_SWING; break; case VDIR_UP: swingV = MITSUBISHI_HEAVY_ZMP_VS_UP; break; case VDIR_MUP: swingV = MITSUBISHI_HEAVY_ZMP_VS_MUP; break; case VDIR_MIDDLE: swingV = MITSUBISHI_HEAVY_ZMP_VS_MIDDLE; break; case VDIR_MDOWN: swingV = MITSUBISHI_HEAVY_ZMP_VS_MDOWN; break; case VDIR_DOWN: swingV = MITSUBISHI_HEAVY_ZMP_VS_DOWN; break; } /* ZMP model has no horizontal swing */ LOGLN("Calling sendHeavy from ZMP with"); LOG(F("PowerMode: ")); LOGLN(powerMode); LOG(F("OperatingMode: ")); LOGLN(operatingMode); LOG(F("FanSpeed: ")); LOGLN(fanSpeed); LOG(F("Temperature: ")); LOGLN(temperature); LOG(F("swingV: ")); LOGLN(swingV); LOG(F("swingH: ")); LOGLN(swingH); LOG(F("cleanMode: ")); LOGLN(cleanMode); sendMitsubishiHeavy(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, swingH, cleanMode); } void MitsubishiHeavyZJHeatpumpIR::sendMitsubishiHeavy(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, uint8_t swingH, uint8_t cleanMode) { uint8_t MitsubishiHeavyZJTemplate[] = { 0x52, 0xAE, 0xC3, 0x26, 0xD9, 0x11, 0x00, 0x07, 0x00, 0x00, 0x00 }; // 0 1 2 3 4 5 6 7 8 9 10 // Horizontal & vertical air flow + allergen + clean + 3D MitsubishiHeavyZJTemplate[5] |= swingH | (swingV & 0b00000010) | cleanMode; // Vertical air flow + fan speed MitsubishiHeavyZJTemplate[7] |= fanSpeed | (swingV & 0b00011000); // Power state + operating mode + temperature MitsubishiHeavyZJTemplate[9] |= operatingMode | powerMode | temperature; // There is no checksum, but some bytes are inverted MitsubishiHeavyZJTemplate[6] = ~MitsubishiHeavyZJTemplate[5]; MitsubishiHeavyZJTemplate[8] = ~MitsubishiHeavyZJTemplate[7]; MitsubishiHeavyZJTemplate[10] = ~MitsubishiHeavyZJTemplate[9]; // 38 kHz PWM frequency IR.setFrequency(38); // Header IR.mark(MITSUBISHI_HEAVY_HDR_MARK); IR.space(MITSUBISHI_HEAVY_HDR_SPACE); // Data for (uint8_t i=0; i