Skip to main content

CodeSOD: Heating Up

2 months ago

A common option for retrofitting heating and cooling into older homes is a mini-split, frequently tied to a heat pump. They're (relatively) cheap to install, energy efficient, and can be added without substantial modifications to the home. They also, annoyingly, are mostly controlled via IR remotes, making them challenging to wire up to home automation or even a household thermostat.

People have made solutions, and today's code comes from one of those solutions. Which, I want to stress, this code comes from an open source project for home automation, so it's not the code that's wrong, here. At first I thought it was, and had a moment of, "I'm not going to pick on some hobby project," but then I realised the hobby project points at a deeper issue.

// temperature helper these are direct mappings based on the remote float toFahrenheit(float fromCelsius) { // Lookup table for specific mappings const std::map<float, int> lookupTable = { {16.0, 61}, {16.5, 62}, {17.0, 63}, {17.5, 64}, {18.0, 65}, {18.5, 66}, {19.0, 67}, {20.0, 68}, {21.0, 69}, {21.5, 70}, {22.0, 71}, {22.5, 72}, {23.0, 73}, {23.5, 74}, {24.0, 75}, {24.5, 76}, {25.0, 77}, {25.5, 78}, {26.0, 79}, {26.5, 80}, {27.0, 81}, {27.5, 82}, {28.0, 83}, {28.5, 84}, {29.0, 85}, {29.5, 86}, {30.0, 87}, {30.5, 88} }; // Check if the input is in the lookup table auto it = lookupTable.find(fromCelsius); if (it != lookupTable.end()) { return it->second; } // Default conversion and rounding to nearest integer return roundf(fromCelsius * 1.8 + 32.0); }

Okay, I am going to pick on their code a little bit; using float as a key in a map is asking for trouble, because rounding errors are going to surprise you. But honestly, failing to find the key you're looking for is better than the opposite, since that actually does the correct thing. Because if you look carefully at the table, you'll see that it's wrong.

18C, for example, should be 64F. Well, 64.4F, but we're rounding to an integer. The choice here is to roughly map every 0.5C increase to a 1F increase, which is not the conversion factor. They try and correct- note how the table mostly steps by 0.5C, but skips 19.5C.

The opposite direction is similarly bad:

// temperature helper these are direct mappings based on the remote float toCelsius(float fromFahrenheit) { // Lookup table for specific mappings const std::map<int, float> lookupTable = { {61, 16.0}, {62, 16.5}, {63, 17.0}, {64, 17.5}, {65, 18.0}, {66, 18.5}, {67, 19.0}, {68, 20.0}, {69, 21.0}, {70, 21.5}, {71, 22.0}, {72, 22.5}, {73, 23.0}, {74, 23.5}, {75, 24.0}, {76, 24.5}, {77, 25.0}, {78, 25.5}, {79, 26.0}, {80, 26.5}, {81, 27.0}, {82, 27.5}, {83, 28.0}, {84, 28.5}, {85, 29.0}, {86, 29.5}, {87, 30.0}, {88, 30.5} }; // Check if the input is in the lookup table auto it = lookupTable.find(static_cast<int>(fromFahrenheit)); if (it != lookupTable.end()) { return it->second; } // Default conversion and rounding to nearest 0.5 return roundf((fromFahrenheit - 32.0) / 1.8 * 2) / 2.0; }

Here, we can be off by as much as a 1C, which is certainly a noticeable feeling.

At first glance, I thought this was just a misguided attempt at optimizing the lookup. For common values, do a lookup instead of calculating because it's faster. Seems like the kind of mistake a hobby project might make, and definitely not a WTF. But it's the comment which corrects me: these are direct mappings based on the remote.

These remotes usually have a display. So when you see on the remote that you're trying to set the temperature to a comfortable 72F, the remote is actually sending 22.5C to the unit. That's the actual temperature being sent.

Now, why on Earth does the remote behave this way? Well, I haven't cracked one open to read off the part numbers, but I'm going to go out on a limb and guess that the microcontoller in the remote doesn't handle floating point operations all that well. So it almost certainly does use a lookup table to decide what signal to send, and the lookup table is populated by "good enough" approximations of temperature conversions. There aren't a lot of places that use Fahrenheit, so being "close enough" is a reasonable solution. If you want accurate temperatures, use SI units, not "freedom units".

In the end, I'd say that neither the hobby project, nor the remote control are the WTF here; locales that insist on using weird ass units are.

.comment { border: none } [Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.
Remy Porter

Global Heating Will Hit At Least 1.8C, UN Warns, and There Are 'No Good Outcomes'

2 months ago
An anonymous reader quotes a report from The Guardian: Global heating will reach at least 1.8C under even the most optimistic future, well beyond the Paris agreement goal of 1.5C, according to a UN report that warns every fraction of temperature rise intensifies destructive extreme weather, glacier melt, ecosystem loss, and island and coastal city submersion. The report by the Nairobi-based UN Environment Program confirmed overshooting the 1.5C goal inscribed in the landmark Paris agreement of 2015 was now "unavoidable" and, despite some progress in addressing the human-caused climate crisis driven by burning fossil fuels, likely in the next few years. It said: "There are no good outcomes above 1.5C." Heating of up to 3C above preindustrial levels could lead to glaciers losing more than a quarter of their mass by 2100, raising sea levels by up to 13cm. Global food production could decline by up to 14% by 2050 if there are not effective strategies to adapt. Human health, water supplies, nature, cities, infrastructure and economies could all be severely damaged. Some losses would be irreversible. Many communities may have to relocate or change their livelihoods. The report said the best hope for humanity to limit damage was to adopt an "overshoot, peak and decline" pathway that required immediate and sustained greenhouse gas emissions cuts combined with steps to remove carbon dioxide from the atmosphere. It described the goal of net zero emissions -- increasingly politically contentious in some countries -- as "an essential milestone that cannot be skipped" and stressed carbon dioxide removal through steps such as establishing vast new forests must occur alongside, not as an alternative to, deep cuts in fossil pollution. Crucially, the authors of the report, titled Limiting Overshoot, said the average global temperature could be returned to 1.5C this century only if heating stayed below about 1.8C. They warned nature's capacity to store carbon was uncertain and would shrink the more the planet heats. [...] The report's authors cited earlier work that found limiting heating to about 1.8C required global emissions to be halved by 2035. They said existing national policies were projected to lead to at least 2.3C heating, but it would still be possible to limit stay below 2C if countries delivered on net zero emissions commitments by mid-century.

Read more of this story at Slashdot.

BeauHD