From 998c1282e470552e25303b23c7a36adb3a60a9dd Mon Sep 17 00:00:00 2001 From: aattww <52109748+aattww@users.noreply.github.com> Date: Sun, 13 Jun 2021 15:27:16 +0300 Subject: [PATCH] Initial working release --- VaillantHeatpumpIR.cpp | 186 +++++++++++++++++++++++++++++++++++++++++ VaillantHeatpumpIR.h | 56 +++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 VaillantHeatpumpIR.cpp create mode 100644 VaillantHeatpumpIR.h diff --git a/VaillantHeatpumpIR.cpp b/VaillantHeatpumpIR.cpp new file mode 100644 index 0000000..7f82c9a --- /dev/null +++ b/VaillantHeatpumpIR.cpp @@ -0,0 +1,186 @@ +#include "VaillantHeatpumpIR.h" + + +VaillantHeatpumpIR::VaillantHeatpumpIR() +{ + static const char model[] PROGMEM = "vaillantvai8"; + static const char info[] PROGMEM = "{\"mdl\":\"vaillantvai8\",\"dn\":\"Vaillant VAI8\",\"mT\":16,\"xT\":30,\"fs\":3}"; + + _model = model; + _info = info; +} + +void VaillantHeatpumpIR::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, false, true); +} + +void VaillantHeatpumpIR::send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, bool turboModeCmd, bool lightCmd) +{ + + // Sensible defaults for the heat pump mode + + uint8_t powerMode = VAILLANT_AIRCON1_POWER_ON; + uint8_t operatingMode = VAILLANT_AIRCON1_MODE_COOL; + uint8_t fanSpeed = VAILLANT_AIRCON1_FAN1; + uint8_t temperature = 25; + uint8_t swingV = VAILLANT_VDIR_UP; + + if (powerModeCmd == POWER_OFF) + { + powerMode = VAILLANT_AIRCON1_POWER_OFF; + } + else + { + switch (operatingModeCmd) + { + case MODE_AUTO: + operatingMode = VAILLANT_AIRCON1_MODE_AUTO; + temperatureCmd = 25; + break; + case MODE_HEAT: + operatingMode = VAILLANT_AIRCON1_MODE_HEAT; + break; + case MODE_COOL: + operatingMode = VAILLANT_AIRCON1_MODE_COOL; + break; + case MODE_DRY: + operatingMode = VAILLANT_AIRCON1_MODE_DRY; + fanSpeedCmd = FAN_1; + break; + case MODE_FAN: + operatingMode = VAILLANT_AIRCON1_MODE_FAN; + break; + } + } + + switch (fanSpeedCmd) + { + case FAN_AUTO: + fanSpeed = VAILLANT_AIRCON1_FAN_AUTO; + break; + case FAN_1: + fanSpeed = VAILLANT_AIRCON1_FAN1; + break; + case FAN_2: + fanSpeed = VAILLANT_AIRCON1_FAN2; + break; + case FAN_3: + fanSpeed = VAILLANT_AIRCON1_FAN3; + break; + } + + switch (swingVCmd) + { + case VDIR_AUTO: + swingV = VAILLANT_VDIR_AUTO; + break; + case VDIR_SWING: + swingV = VAILLANT_VDIR_SWING; + break; + case VDIR_UP: + swingV = VAILLANT_VDIR_UP; + break; + case VDIR_MUP: + swingV = VAILLANT_VDIR_MUP; + break; + case VDIR_MIDDLE: + swingV = VAILLANT_VDIR_MIDDLE; + break; + case VDIR_MDOWN: + swingV = VAILLANT_VDIR_MDOWN; + break; + case VDIR_DOWN: + swingV = VAILLANT_VDIR_DOWN; + break; + } + + if (temperatureCmd > 15 && temperatureCmd < 31) + { + temperature = temperatureCmd - 16; + } + + sendVaillant(IR, powerMode, operatingMode, fanSpeed, temperature, swingV, turboModeCmd, lightCmd); +} + +// Send the Vaillant code +void VaillantHeatpumpIR::sendVaillant(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, bool turboMode, bool light) +{ + + uint8_t vaillantTemplate[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + // 0 1 2 3 4 5 6 7 + + uint8_t i; + + // Set the Fan speed, operating mode and power state + vaillantTemplate[0] = fanSpeed | operatingMode | powerMode; + // Set the temperature + vaillantTemplate[1] = temperature; + + + if (powerMode == VAILLANT_AIRCON1_POWER_ON) + { + vaillantTemplate[2] = 0x40; // bits 0..3 always 0000, bits 4..7 TURBO,LIGHT,HEALTH,X-FAN + } + + vaillantTemplate[3] = 0x50; + vaillantTemplate[4] = swingV; + vaillantTemplate[5] = 0x02; + vaillantTemplate[6] = 0x00; + + if (turboMode) + { + vaillantTemplate[2] |= (1 << 4); // Set bit 4 (TURBO) + } + if (light) + { + vaillantTemplate[2] |= (1 << 5); // Set bit 5 (light) + } + if (swingV == VAILLANT_VDIR_SWING) + { + vaillantTemplate[0] |= (1 << 6); // Enable swing by setting bit 6 + } + + // Calculate the checksum + vaillantTemplate[7] = ((( + (vaillantTemplate[0] & 0x0F) + + (vaillantTemplate[1] & 0x0F) + + (vaillantTemplate[2] & 0x0F) + + (vaillantTemplate[3] & 0x0F) + + ((vaillantTemplate[5] & 0xF0) >> 4) + + ((vaillantTemplate[6] & 0xF0) >> 4) + + ((vaillantTemplate[7] & 0xF0) >> 4) + + 0x0A) & 0x0F) << 4) | (vaillantTemplate[7] & 0x0F); + + // 38 kHz PWM frequency + IR.setFrequency(38); + + // Send Header mark + IR.mark(VAILLANT_AIRCON1_HDR_MARK); + IR.space(VAILLANT_AIRCON1_HDR_SPACE); + + // Payload part #1 + for (i=0; i<4; i++) { + IR.sendIRbyte(vaillantTemplate[i], VAILLANT_AIRCON1_BIT_MARK, VAILLANT_AIRCON1_ZERO_SPACE, VAILLANT_AIRCON1_ONE_SPACE); + } + // Only three first bits of byte 4 are sent, this is always '010' + IR.mark(VAILLANT_AIRCON1_BIT_MARK); + IR.space(VAILLANT_AIRCON1_ZERO_SPACE); + IR.mark(VAILLANT_AIRCON1_BIT_MARK); + IR.space(VAILLANT_AIRCON1_ONE_SPACE); + IR.mark(VAILLANT_AIRCON1_BIT_MARK); + IR.space(VAILLANT_AIRCON1_ZERO_SPACE); + + // Message space + IR.mark(VAILLANT_AIRCON1_BIT_MARK); + IR.space(VAILLANT_AIRCON1_MSG_SPACE); + + // Payload part #2 + for (i=4; i<8; i++) { + IR.sendIRbyte(vaillantTemplate[i], VAILLANT_AIRCON1_BIT_MARK, VAILLANT_AIRCON1_ZERO_SPACE, VAILLANT_AIRCON1_ONE_SPACE); + } + + // End mark + IR.mark(VAILLANT_AIRCON1_BIT_MARK); + IR.space(0); +} diff --git a/VaillantHeatpumpIR.h b/VaillantHeatpumpIR.h new file mode 100644 index 0000000..c09e0c3 --- /dev/null +++ b/VaillantHeatpumpIR.h @@ -0,0 +1,56 @@ +/* + Vaillant VAI8 heatpump control (remote control P/N YAN1F1) +*/ +#ifndef VaillantHeatpumpIR_h +#define VaillantHeatpumpIR_h + +#include + +// Vaillant timing constants +#define VAILLANT_AIRCON1_HDR_MARK 9000 +#define VAILLANT_AIRCON1_HDR_SPACE 4000 +#define VAILLANT_AIRCON1_BIT_MARK 620 +#define VAILLANT_AIRCON1_ONE_SPACE 1600 +#define VAILLANT_AIRCON1_ZERO_SPACE 540 +#define VAILLANT_AIRCON1_MSG_SPACE 19000 + +// Power state +#define VAILLANT_AIRCON1_POWER_OFF 0x00 +#define VAILLANT_AIRCON1_POWER_ON 0x08 + +// Operating modes +#define VAILLANT_AIRCON1_MODE_AUTO 0x00 +#define VAILLANT_AIRCON1_MODE_COOL 0x01 +#define VAILLANT_AIRCON1_MODE_DRY 0x02 +#define VAILLANT_AIRCON1_MODE_FAN 0x03 +#define VAILLANT_AIRCON1_MODE_HEAT 0x04 + +// Fan speeds. Note that some heatpumps have less than 5 fan speeds +#define VAILLANT_AIRCON1_FAN_AUTO 0x00 // Fan speed +#define VAILLANT_AIRCON1_FAN1 0x10 // * low +#define VAILLANT_AIRCON1_FAN2 0x20 // * med +#define VAILLANT_AIRCON1_FAN3 0x30 // * high + +// Vertical air directions. Note that these cannot be set on all heat pumps +#define VAILLANT_VDIR_AUTO 0x00 +#define VAILLANT_VDIR_MANUAL 0x00 +#define VAILLANT_VDIR_SWING 0x01 +#define VAILLANT_VDIR_UP 0x02 +#define VAILLANT_VDIR_MUP 0x03 +#define VAILLANT_VDIR_MIDDLE 0x04 +#define VAILLANT_VDIR_MDOWN 0x05 +#define VAILLANT_VDIR_DOWN 0x06 + + +class VaillantHeatpumpIR : public HeatpumpIR +{ + public: + VaillantHeatpumpIR(); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, bool turboModeCmd, bool lightCmd); + void send(IRSender& IR, uint8_t powerModeCmd, uint8_t operatingModeCmd, uint8_t fanSpeedCmd, uint8_t temperatureCmd, uint8_t swingVCmd, uint8_t swingHCmd); + + private: + void sendVaillant(IRSender& IR, uint8_t powerMode, uint8_t operatingMode, uint8_t fanSpeed, uint8_t temperature, uint8_t swingV, bool turboMode, bool light); +}; + +#endif