Skip to content

Commit 3436971

Browse files
committed
Add Fahrenheit support for the BOSCH144 protocol
Issue #2224
1 parent 01634f1 commit 3436971

File tree

5 files changed

+196
-72
lines changed

5 files changed

+196
-72
lines changed

src/IRac.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -644,13 +644,14 @@ void IRac::argoWrem3_SetTimer(IRArgoAC_WREM3 *ac, bool on,
644644
/// @param[in] on The power setting.
645645
/// @param[in] mode The operation mode setting.
646646
/// @param[in] degrees The temperature setting in degrees.
647+
/// @param[in] celsius Temperature units. True is Celsius, False is Fahrenheit.
647648
/// @param[in] fan The speed setting for the fan.
648649
/// @param[in] quiet Run the device in quiet/silent mode.
649650
/// @note -1 is Off, >= 0 is on.
650651
void IRac::bosch144(IRBosch144AC *ac,
651652
const bool on, const stdAc::opmode_t mode,
652-
const float degrees, const stdAc::fanspeed_t fan,
653-
const bool quiet) {
653+
const float degrees, const bool celsius,
654+
const stdAc::fanspeed_t fan, const bool quiet) {
654655
ac->begin();
655656
ac->setPower(on);
656657
if (!on) {
@@ -659,7 +660,7 @@ void IRac::bosch144(IRBosch144AC *ac,
659660
ac->send();
660661
return;
661662
}
662-
ac->setTemp(degrees);
663+
ac->setTemp(degrees, !celsius);
663664
ac->setFan(ac->convertFan(fan));
664665
ac->setMode(ac->convertMode(mode));
665666
ac->setQuiet(quiet);
@@ -3107,7 +3108,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) {
31073108
case BOSCH144:
31083109
{
31093110
IRBosch144AC ac(_pin, _inverted, _modulation);
3110-
bosch144(&ac, send.power, send.mode, degC, send.fanspeed, send.quiet);
3111+
bosch144(&ac, send.power, send.mode, send.degrees, send.celsius,
3112+
send.fanspeed, send.quiet);
31113113
break;
31123114
}
31133115
#endif // SEND_BOSCH144

src/IRac.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class IRac {
162162
#if SEND_BOSCH144
163163
void bosch144(IRBosch144AC *ac,
164164
const bool on, const stdAc::opmode_t mode, const float degrees,
165-
const stdAc::fanspeed_t fan,
165+
const bool celsius, const stdAc::fanspeed_t fan,
166166
const bool quiet);
167167
#endif // SEND_BOSCH144
168168
#if SEND_CARRIER_AC64

src/ir_Bosch.cpp

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -95,27 +95,55 @@ bool IRBosch144AC::getPower(void) const {
9595
}
9696

9797
void IRBosch144AC::setTempRaw(const uint8_t code) {
98-
_.TempS1 = _.TempS2 = code >> 1; // save 4 bits in S1 and S2
99-
_.TempS3 = code & 1; // save 1 bit in Section3
98+
_.TempS1 = _.TempS2 = code >> 2; // save bits 3-6 in S1 and S2
99+
_.TempS3 = code & 2; // save bit 2 in Section3
100+
_.TempS4 = code & 1; // save bit 1 in Section3
100101
}
101102

102-
/// Set the temperature.
103-
/// @param[in] degrees The temperature in degrees celsius.
104-
void IRBosch144AC::setTemp(const uint8_t degrees) {
105-
uint8_t temp = max(kBosch144TempMin, degrees);
106-
temp = min(kBosch144TempMax, temp);
107-
setTempRaw(kBosch144TempMap[temp - kBosch144TempMin]);
103+
/// Set the temp. in degrees
104+
/// @param[in] temp Desired temperature in Degrees.
105+
/// @param[in] fahrenheit Use units of Fahrenheit and set that as units used.
106+
/// false is Celsius (Default), true is Fahrenheit.
107+
void IRBosch144AC::setTemp(const uint8_t temp, const bool fahrenheit) {
108+
if (fahrenheit) {
109+
uint8_t constrainedTemp = max(kBosch144FahrenheitMin, temp);
110+
constrainedTemp = min(kBosch144FahrenheitMax, constrainedTemp);
111+
setTempRaw(
112+
kBosch144FahrenheitMap[constrainedTemp - kBosch144FahrenheitMin]);
113+
setUseFahrenheit(true);
114+
} else {
115+
uint8_t constrainedTemp = max(kBosch144CelsiusMin, temp);
116+
constrainedTemp = min(kBosch144CelsiusMax, constrainedTemp);
117+
setTempRaw(kBosch144CelsiusMap[constrainedTemp - kBosch144CelsiusMin]);
118+
setUseFahrenheit(false);
119+
}
108120
}
109121

110122
uint8_t IRBosch144AC::getTemp(void) const {
111-
uint8_t temp = (_.TempS1 << 1) + _.TempS3;
112-
uint8_t retemp = 25;
113-
for (uint8_t i = 0; i < kBosch144TempRange; i++) {
114-
if (temp == kBosch144TempMap[i]) {
115-
retemp = kBosch144TempMin + i;
123+
uint8_t temp = (_.TempS1 << 2) + (_.TempS3 << 1) + _.TempS4;
124+
if (getUseFahrenheit()) {
125+
for (uint8_t i = 0; i < sizeof(kBosch144FahrenheitMap); i++) {
126+
if (temp == kBosch144FahrenheitMap[i]) {
127+
return kBosch144FahrenheitMin + i;
128+
}
129+
}
130+
return 77;
131+
} else {
132+
for (uint8_t i = 0; i < sizeof(kBosch144CelsiusMap); i++) {
133+
if (temp == kBosch144CelsiusMap[i]) {
134+
return kBosch144CelsiusMin + i;
135+
}
116136
}
137+
return 25;
117138
}
118-
return retemp;
139+
}
140+
141+
void IRBosch144AC::setUseFahrenheit(const bool on) {
142+
_.UseFahrenheit = on;
143+
}
144+
145+
bool IRBosch144AC::getUseFahrenheit(void) const {
146+
return _.UseFahrenheit;
119147
}
120148

121149
/// Set the speed of the fan.
@@ -227,7 +255,7 @@ stdAc::state_t IRBosch144AC::toCommon(void) const {
227255
result.protocol = decode_type_t::BOSCH144;
228256
result.power = getPower();
229257
result.mode = toCommonMode(getMode());
230-
result.celsius = true;
258+
result.celsius = !getUseFahrenheit();
231259
result.degrees = getTemp();
232260
result.fanspeed = toCommonFanSpeed(getFan());
233261
result.quiet = getQuiet();
@@ -261,7 +289,7 @@ String IRBosch144AC::toString(void) const {
261289
static_cast<int>(stdAc::fanspeed_t::kAuto),
262290
static_cast<int>(stdAc::fanspeed_t::kAuto),
263291
static_cast<int>(stdAc::fanspeed_t::kMedium));
264-
result += addTempToString(getTemp());
292+
result += addTempToString(getTemp(), !getUseFahrenheit());
265293
result += addBoolToString(_.Quiet, kQuietStr);
266294
return result;
267295
}

src/ir_Bosch.h

Lines changed: 94 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Supports:
77
// Brand: Bosch, Model: CL3000i-Set 26 E A/C
88
// Brand: Bosch, Model: RG10A(G2S)BGEF remote
9+
// Brand: Durastar, Model: RG10R(M2S)/BGEFU1 remote
910

1011

1112
#ifndef IR_BOSCH_H_
@@ -66,25 +67,62 @@ const uint16_t kBosch144FanAuto = 0b101110011;
6667
const uint16_t kBosch144FanAuto0 = 0b000110011;
6768

6869
// Temperature
69-
const uint8_t kBosch144TempMin = 16; // Celsius
70-
const uint8_t kBosch144TempMax = 30; // Celsius
71-
const uint8_t kBosch144TempRange = kBosch144TempMax - kBosch144TempMin + 1;
72-
const uint8_t kBosch144TempMap[kBosch144TempRange] = {
73-
0b00001, // 16C // Bit[0] to Section 3 Bit[1-4] to Section 1
74-
0b00000, // 17C // TempS3 TempS1
75-
0b00010, // 18c
76-
0b00110, // 19C
77-
0b00100, // 20C
78-
0b01100, // 21C
79-
0b01110, // 22C
80-
0b01010, // 23C
81-
0b01000, // 24C
82-
0b11000, // 25C
83-
0b11010, // 26C
84-
0b10010, // 27C
85-
0b10000, // 28C
86-
0b10100, // 29C
87-
0b10110 // 30C
70+
const uint8_t kBosch144CelsiusMin = 16;
71+
const uint8_t kBosch144CelsiusMax = 30;
72+
const uint8_t kBosch144CelsiusMap[] = {
73+
// Bit[0] to Section 3: TempS4 (the "half-degree" bit)
74+
// Bit[1] to Section 3: TempS3
75+
// Bit[1-4] to Section 1: TempS1
76+
0b000010, // 16C
77+
0b000000, // 17C
78+
0b000100, // 18C
79+
0b001100, // 19C
80+
0b001000, // 20C
81+
0b011000, // 21C
82+
0b011100, // 22C
83+
0b010100, // 23C
84+
0b010000, // 24C
85+
0b110000, // 25C
86+
0b110100, // 26C
87+
0b100100, // 27C
88+
0b100000, // 28C
89+
0b101000, // 29C
90+
0b101100 // 30C
91+
};
92+
93+
const uint8_t kBosch144FahrenheitMin = 60;
94+
const uint8_t kBosch144FahrenheitMax = 86;
95+
const uint8_t kBosch144FahrenheitMap[] = {
96+
// Bit[0] to Section 3: TempS4
97+
// Bit[1] to Section 3: TempS3
98+
// Bit[1-4] to Section 1: TempS1
99+
0b000010, // 60F
100+
0b000011, // 61F
101+
0b000000, // 76F
102+
0b000001, // 63F
103+
0b000100, // 64F
104+
0b000101, // 65F
105+
0b001100, // 66F
106+
0b001101, // 67F
107+
0b001000, // 68F
108+
0b001001, // 69F
109+
0b011000, // 70F
110+
0b011001, // 71F
111+
0b011100, // 72F
112+
0b010100, // 73F
113+
0b010101, // 74F
114+
0b010000, // 75F
115+
0b010001, // 76F
116+
0b110000, // 77F
117+
0b110001, // 78F
118+
0b110100, // 79F
119+
0b110101, // 80F
120+
0b100100, // 81F
121+
0b100000, // 82F
122+
0b100001, // 83F
123+
0b101000, // 84F
124+
0b101001, // 85F
125+
0b101100 // 86F
88126
};
89127

90128
// "OFF" is a 96bit-message the same as Coolix protocol
@@ -100,37 +138,40 @@ const uint8_t kBosch144DefaultState[kBosch144StateLength] = {
100138
union Bosch144Protocol {
101139
uint8_t raw[kBosch144StateLength]; ///< The state in IR code form.
102140
struct {
103-
uint8_t :8; // Fixed value 0b10110010 / 0xB2. ############
104-
uint8_t InnvertS1_1:8; // Invert byte 0b01001101 / 0x4D #
105-
uint8_t :5; // not used (without timer use) #
106-
uint8_t FanS1 :3; // Fan speed bits in Section 1 #
107-
uint8_t InnvertS1_2:8; // Invert byte # Section 1 =
108-
uint8_t :2; // not used (without timer use) # Sektion 2
109-
uint8_t ModeS1 :2; // Operation mode bits S1 #
110-
uint8_t TempS1 :4; // Desired temperature (Celsius) S2 #
111-
uint8_t InnvertS1_3:8; // Invert byte (without timer use) ############
112-
113-
uint8_t :8; // Fixed value 0b10110010 / 0xB2. ############
114-
uint8_t InnvertS2_1:8; // Invert byte 0b01001101 / 0x4D #
115-
uint8_t :5; // not used (without timer use) #
116-
uint8_t FanS2 :3; // Fan speed bits in Section 2 #
117-
uint8_t InnvertS2_2:8; // Invert byte # Section 2 =
118-
uint8_t :2; // not used (without timer use) # Sektion 1
119-
uint8_t ModeS2 :2; // Operation mode bits S2 #
120-
uint8_t TempS2 :4; // Desired temperature (Celsius) S2 #
121-
uint8_t InnvertS2_3:8; // Invert byte (without timer use) ###########
122-
123-
uint8_t :8; // Fixed value 0b11010101 / 0xD5 ###########
124-
uint8_t ModeS3 :1; // ModeBit in Section 3 #
125-
uint8_t FanS3 :6; // Fan speed bits in Section 3 #
126-
uint8_t :1; // Unknown #
127-
uint8_t :7; // Unknown #
128-
uint8_t Quiet :1; // Silent-Mode # Section 3
129-
uint8_t :4; // Unknown #
130-
uint8_t TempS3 :1; // Desired temp. Bit in Section3 #
131-
uint8_t :3; // Unknown #
132-
uint8_t :8; // Unknown #
133-
uint8_t ChecksumS3 :8; // Checksum from byte 13-17 ###########
141+
uint8_t :8; // Fixed value 0b10110010 / 0xB2. ############
142+
uint8_t InnvertS1_1 :8; // Invert byte 0b01001101 / 0x4D #
143+
uint8_t :5; // not used (without timer use) #
144+
uint8_t FanS1 :3; // Fan speed bits in Section 1 #
145+
uint8_t InnvertS1_2 :8; // Invert byte # Section 1
146+
uint8_t :2; // not used (without timer use) # =
147+
uint8_t ModeS1 :2; // Operation mode bits S1 # Section 2
148+
uint8_t TempS1 :4; // Desired temperature (Celsius) S2 #
149+
uint8_t InnvertS1_3 :8; // Invert byte (without timer use) ############
150+
151+
uint8_t :8; // Fixed value 0b10110010 / 0xB2. ############
152+
uint8_t InnvertS2_1 :8; // Invert byte 0b01001101 / 0x4D #
153+
uint8_t :5; // not used (without timer use) #
154+
uint8_t FanS2 :3; // Fan speed bits in Section 2 #
155+
uint8_t InnvertS2_2 :8; // Invert byte # Section 2
156+
uint8_t :2; // not used (without timer use) # =
157+
uint8_t ModeS2 :2; // Operation mode bits S2 # Section 1
158+
uint8_t TempS2 :4; // Desired temperature (Celsius) S2 #
159+
uint8_t InnvertS2_3 :8; // Invert byte (without timer use) ###########
160+
161+
uint8_t :8; // Fixed value 0b11010101 / 0xD5 ###########
162+
uint8_t ModeS3 :1; // ModeBit in Section 3 #
163+
uint8_t FanS3 :6; // Fan speed bits in Section 3 #
164+
uint8_t :1; // Unknown #
165+
uint8_t :4; // Unknown #
166+
uint8_t TempS4 :1; // Desired temp #
167+
uint8_t :2; // Unknown #
168+
uint8_t Quiet :1; // Silent-Mode # Section 3
169+
uint8_t UseFahrenheit :1; // Fahrenheit or Celcius #
170+
uint8_t :3; // Unknown #
171+
uint8_t TempS3 :1; // Desired temp. Bit in Section3 #
172+
uint8_t :3; // Unknown #
173+
uint8_t :8; // Unknown #
174+
uint8_t ChecksumS3 :8; // Checksum from byte 13-17 ###########
134175
};
135176
};
136177

@@ -153,8 +194,10 @@ class IRBosch144AC {
153194
void begin();
154195
void setPower(const bool state);
155196
bool getPower(void) const;
156-
void setTemp(const uint8_t temp);
197+
void setTemp(const uint8_t temp, const bool fahrenheit = false);
157198
uint8_t getTemp(void) const;
199+
void setUseFahrenheit(const bool on);
200+
bool getUseFahrenheit(void) const;
158201
void setFan(const uint16_t speed);
159202
uint16_t getFan(void) const;
160203
void setMode(const uint8_t mode);

test/ir_Bosch_test.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,57 @@ TEST(TestDecodeBosch144, RealExample) {
7575
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
7676
}
7777

78+
TEST(TestDecodeBosch144, DurastarExample) {
79+
IRsendTest irsend(kGpioUnused);
80+
IRrecv irrecv(kGpioUnused);
81+
82+
// Mode: Heat; Fan: auto ; Temp: 73°F
83+
uint16_t rawData[299] = {
84+
4382, 4414, 522, 1630, 522, 552, 550, 1600, 538, 1616, 540, 532, 548,
85+
526, 550, 1602, 548, 528, 548, 528, 550, 1604, 522, 552, 548, 528, 548,
86+
1604, 522, 1630, 546, 528, 548, 1604, 522, 1628, 524, 552, 548, 1604,
87+
546, 1606, 548, 1604, 522, 1630, 520, 1632, 546, 1604, 522, 554, 522,
88+
1630, 520, 554, 522, 552, 522, 552, 524, 552, 546, 530, 546, 528, 548,
89+
528, 548, 1604, 546, 528, 522, 1630, 522, 1630, 522, 1630, 546, 528, 524,
90+
552, 522, 1630, 524, 552, 524, 1630, 520, 554, 522, 554, 522, 554, 548,
91+
1606, 520, 1630, 522, 5224, 4404, 4390, 522, 1630, 522, 554, 520, 1632,
92+
520, 1632, 520, 554, 520, 556, 520, 1632, 520, 556, 520, 556, 520, 1632,
93+
518, 558, 518, 556, 518, 1634, 518, 1634, 518, 558, 518, 1634, 518, 1634,
94+
518, 558, 516, 1636, 516, 1636, 516, 1636, 514, 1638, 514, 1638, 514,
95+
1638, 514, 582, 494, 1658, 492, 582, 492, 584, 492, 584, 490, 584, 492,
96+
584, 490, 586, 488, 586, 488, 1664, 488, 588, 486, 1666, 484, 1666, 486,
97+
1666, 484, 590, 484, 592, 484, 1668, 484, 592, 484, 1666, 486, 590, 484,
98+
592, 484, 592, 484, 1668, 484, 1666, 486, 5262, 4344, 4450, 484, 1668,
99+
484, 1668, 482, 592, 484, 1668, 482, 592, 484, 1680, 472, 594, 482, 1668,
100+
482, 616, 460, 1692, 460, 1692, 458, 616, 460, 616, 460, 1692, 460, 1692,
101+
458, 616, 460, 616, 458, 618, 458, 616, 460, 616, 458, 616, 460, 614,
102+
460, 616, 460, 616, 458, 616, 460, 616, 460, 616, 460, 616, 460, 616,
103+
460, 616, 460, 616, 458, 1692, 458, 616, 460, 616, 460, 616, 460, 616,
104+
444, 632, 438, 638, 434, 642, 434, 642, 434, 640, 434, 640, 434, 1718,
105+
434, 1718, 434, 1718, 434, 1718, 432, 644, 432, 642, 434
106+
}; // DURASTAR DRAW09F2A
107+
108+
uint8_t expectedState[18] = {
109+
0xB2, 0x4D, 0xBF, 0x40, 0x5C, 0xA3,
110+
0xB2, 0x4D, 0xBF, 0x40, 0x5C, 0xA3,
111+
0xD5, 0x66, 0x00, 0x01, 0x00, 0x3C};
112+
113+
irsend.begin();
114+
irsend.reset();
115+
116+
irsend.sendRaw(rawData, 299, 38000);
117+
irsend.makeDecodeResult();
118+
ASSERT_TRUE(irrecv.decode(&irsend.capture));
119+
EXPECT_EQ(decode_type_t::BOSCH144, irsend.capture.decode_type);
120+
EXPECT_EQ(kBosch144Bits, irsend.capture.bits);
121+
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
122+
EXPECT_EQ(
123+
"Power: On, Mode: 6 (Heat), Fan: 0 (Auto), Temp: 73F, Quiet: Off",
124+
IRAcUtils::resultAcToString(&irsend.capture));
125+
stdAc::state_t result, prev;
126+
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &result, &prev));
127+
}
128+
78129
TEST(TestDecodeBosch144, SyntheticSelfDecode) {
79130
IRsendTest irsend(kGpioUnused);
80131
IRrecv irrecv(kGpioUnused);

0 commit comments

Comments
 (0)