Hi,
We have a solarboilar with a 300 liter storage tank. The sensors only tell me the temp at the top and at the bottom. I can never tell how much USABLE warm water is in the tank. I want to use 5 ds18b20 sensors and draw a gradient colorbar on a TFT LCD screen so my family can see how many more showers are left. I know how to draw a rectangle and colorfill it, but how to make that a gradient color?
Can someone please point me in the right direction?
I'm using Adafruit_GFX and MCUFRIEND_kbv lib's. See attachement.
There are several ways to implement a vertical color gradient. One simple approach is to break up your large rectangular region into a series of thin horizontal strips of incrementing color. In essence, you would:
- FOR-LOOP from the bottom Y coordinate to the top Y coordinate
- Calculate the color of the thin strip (at a given Y position) and render with fillRect()
- Advance the Y coordinate to the next strip. The width of the strip will define the smoothness of the gradient, with a single pixel height increment being the smoothest (at the expense of rendering performance)
To calculate the color of each strip, you will want to use a color "interpolation" scheme to blend between the two "color stops" (blue and red). Perhaps the easiest method to accomplish this is to use a "linear interpolation" between the RGB value of the blue end and the RGB value of the red end. One very simple method is to calculate the position of the current strip as a percentage of the total distance from the starting Y coordinate to the ending Y coordinate. This percentage is used to pro-rate the RGB value blending.
In general, it is best to treat colors as independent Red/Green/Blue channel values when manipulating. Note that this very simple blend method does not give ideal results in all scenarios, but is probably fine for your particular use-case.
For example, assume you are drawing from the bottom (blue) to top (red) and the total height of the bar is 100 pixels.
- ColStart = Blue = (0,0,255)
- ColEnd = Red = (255,0,0)
In the case of computing the color of the strip at a Y coordinate 25 pixels from the bottom, you could do the following:
- Position = 25/100 = 25%
- ColStrip.R = ColStart.R + 0.25*(ColEnd.R-ColStart.R) = 0 + 0.25*(255-0) = 63
- ColStrip.G = ColStart.G + 0.25*(ColEnd.G-ColStart.G) = 0 + 0.25*(0-0) = 0
- ColStrip.B = ColStart.B + 0.25*(ColEnd.B-ColStart.B) = 255 + 0.25*(0-255) = 192
- ColStrip = (63,0,192)
Thx Impulsive, I'll give it a try!
It is easy enough to map a colour to a temperature.
You can either display a smooth gradient like your picture.
Or you can map a colour to each Sensor.
I suspect that a human wants to see N red blocks to signify N baths / showers are available.
There are obviously many ways to display your information. Choosing attractive colours and graphics make all the difference.
uint16_t temp2color(int degree, int lo, int hi)
{
uint8_t r, g, b;
r = map(degree, lo, hi, 255, 0);
g = 0;
b = map(degree, lo, hi, 0, 255);
return tft.color565(r, g, b);
}
void colorgradient(int x, int y, int w, int h, int percent)
{
tft.drawRect(x, y, w, h, TFT_BLACK);
for (int row = 1; row < h - 1; row++) {
tft.drawFastHLine(x + 1, y + row, w - 2, temp2color(row, 0, h));
}
}
Please have a look at the attachment.
If I use only two sensors, that'll give me one big fluent gradient from top to bottom. If I use 5 sensors, that'll gives me 4 blocks, each with their own gradient. Compare the right side of the drawing. The more sensors I use, the more detailed information I get. Sensor B, C and D serve double. So basicly that would make one colored bar based on 4 gradients on top off each other.
I could then use tft.drawFastHLine( x, y, 30, GRADIENTCOLOR) where GRADIENTCOLOR is calculated for every line in the block, based on the sensors that belong to that block.
Am I right David?
I gave you a function for determining the colour.
You can use multiple sensors and interpolate between them.
Now think about driving your car.
Would you like a battery gauge to show a graduated colour or an unambiguous pointer?
Yes, you can display all sorts of graphics.
What "looks" best?
Sometimes an indicator is better than an "accurate" representation.
Sometimes a single sensor half-way up the cylinder gives a good enough indication. Think about natural convection and regular conduction.
David.
I know by experience that you never know how much 40-degrees-and-up water is in the tank. Temperatures can vary heavily depending on sunshine. If the solarcontroler show 70 degrees in the upper part, I still don't know how much water of 70 degrees is in there. Only if the bottom sensor also says there's 70 degrees, then I know that the whole tank is filled with 70 degrees. I prefer the accurate version and therefor need more sensors (and interpolate between them as you suggest). I think that 5 sensors gives us accurate information and can produce a very nice resolution/gradient. Thank you for the input and the example. I'll show the code when I'm done. That can take some time because I'm dyslectic and writing code is a pain...
a fun pain though...