Skip to content

Commit f87697f

Browse files
angeloINTJclaude
andcommitted
feat: move icon drawing and panel rendering into sensor drivers
New files: sensors/SensorDrawing.h — shared procedural icons (thermometer large/mini, drop large/mini, degC unit normal/mini). Each function guarded by SIMUT_SENSOR_* flags — stripped when sensor disabled. sensors/SensorPanelDispatch.h — dispatches to correct driver's renderPanel Modified drivers: DS18B20Driver.h — +DS18B20_renderPanel(): full panel rendering with thermometer icon, formatted temperature, degC unit. Centered layout. DHT22Driver.h — +DHT22_renderPanel(): full panel with thermometer + drop icon + humidity value + % suffix. Left-anchor or centered. Architecture: panel rendering is now driver-owned. DisplayManager calls sensorRenderPanel(type, ...) and the driver handles icon, formatting, and unit placement. New sensors (BME280 etc.) just add their renderPanel. Flash: unchanged (1031536) — functions inline, stripped when not called. Tests: 49/49 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6aa0da9 commit f87697f

4 files changed

Lines changed: 265 additions & 0 deletions

File tree

src/sensors/DHT22Driver.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <Arduino.h>
1818
#include "DHTBus.h"
1919
#include "DHT22PIO.h"
20+
#include "SensorDrawing.h"
2021

2122
#define PIN_DHT_DEFAULT 10
2223

@@ -61,8 +62,79 @@ struct DHT22Driver {
6162
void reset( ) {
6263
sensor.reset( );
6364
}
65+
6466
};
6567

68+
/* ── Panel rendering (normal mode, free function) ─────────────────────── */
69+
inline void DHT22_renderPanel(GFXcanvas16* cv, float t, float h, bool isValid,
70+
int16_t cardW, bool leftAnchor, bool isRedPhase,
71+
uint16_t panelBg, const GFXfont& font24,
72+
const GFXfont& font12, const GFXfont& font9) {
73+
uint16_t txtSub = isRedPhase ? RGB565(255,255,255) : 0xCE9A52; /* C_TEXT_SUB */
74+
uint16_t tempCol = isRedPhase ? RGB565(255,255,255) : 0x04B04C; /* C_TEMP_OK */
75+
uint16_t humCol = isRedPhase ? RGB565(255,255,255) : 0x5252DC; /* C_HUMIDITY */
76+
uint16_t icTherm = isRedPhase ? RGB565(220,200,200) : txtSub;
77+
uint16_t icDrop = isRedPhase ? RGB565(220,200,200) : humCol;
78+
uint16_t shine = isRedPhase ? RGB565(255,255,255) : RGB565(200,230,255);
79+
uint16_t merc = isRedPhase ? RGB565(255,255,255) : 0xD04020; /* C_TEMP_HOT */
80+
81+
if (!isValid || isnan(t)) {
82+
cv->setFont(&font12);
83+
cv->setTextColor(0x8A7A6A); /* C_TEXT_OFF */
84+
cv->setCursor(leftAnchor ? 80 : (cardW - 160) / 2 + 30, 15);
85+
cv->print("--.-");
86+
drawThermometerLarge(cv, leftAnchor ? 14 : (cardW - 160) / 2 - 10, 4,
87+
icTherm, panelBg, merc);
88+
return;
89+
}
90+
91+
int negMul = (t < 0.0f) ? -1 : 1;
92+
float absT = (t < 0.0f) ? -t : t;
93+
int intPart = (int)absT;
94+
int decPart = (int)((absT - (float)intPart) * 10.0f + 0.5f);
95+
if (decPart >= 10) { intPart++; decPart = 0; }
96+
char iP[8]; snprintf(iP, sizeof(iP), "%d", intPart);
97+
char dP[4]; snprintf(dP, sizeof(dP), "%d", decPart);
98+
int16_t xx, yy; uint16_t iw, ih;
99+
cv->getTextBounds(iP, 0, 0, &xx, &yy, &iw, &ih);
100+
101+
int anchorX = leftAnchor ? 92 : (cardW - (int)iw - 8) / 2 + 10;
102+
int iconX = leftAnchor ? 14 : (cardW - 160) / 2 - 10;
103+
104+
drawThermometerLarge(cv, iconX, 4, icTherm, panelBg, merc);
105+
106+
cv->setFont(&font24);
107+
cv->setTextColor(tempCol);
108+
if (negMul < 0) { cv->setCursor(anchorX - (int)iw - 6, 35); cv->print("-"); }
109+
cv->setCursor(anchorX - (int)iw + (negMul < 0 ? 0 : 0), 35);
110+
cv->print(iP);
111+
cv->setCursor(anchorX + 4, 35); cv->print(".");
112+
cv->print(dP);
113+
114+
int unitX = anchorX + 4 + (int)((intPart >= 10 ? iw + 6 : iw)) + 6;
115+
drawUnitDegC_Normal(cv, unitX, txtSub, font9, font12);
116+
117+
/* Humidity */
118+
if (!isnan(h)) {
119+
char hb[6];
120+
if (isnan(h)) snprintf(hb, sizeof(hb), "--");
121+
else snprintf(hb, sizeof(hb), "%d", (int)h);
122+
int16_t px, py; uint16_t pw, ph;
123+
cv->getTextBounds(hb, 0, 0, &px, &py, &pw, &ph);
124+
int humAnchor = cardW - 15 - pw;
125+
cv->setFont(&font24);
126+
cv->setTextColor(humCol);
127+
cv->setCursor(humAnchor, 35);
128+
cv->print(hb);
129+
int dropX = humAnchor - (int)pw - 20;
130+
drawDropLarge(cv, dropX, 4, icDrop, shine);
131+
cv->setFont(&font12);
132+
cv->setTextColor(isRedPhase ? RGB565(220,200,200) : 0xD6C090); /* C_TEXT_MAIN */
133+
cv->setCursor(cardW - 15 - pw - 4, 34);
134+
cv->print("%");
135+
}
136+
}
137+
66138
#else
67139
#define PIN_DHT_DEFAULT 255
68140
#endif /* SIMUT_SENSOR_DHT22 */

src/sensors/DS18B20Driver.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <Arduino.h>
1818
#include "OneWirePIO.h"
1919
#include "DS18B20PIO.h"
20+
#include "SensorDrawing.h"
2021

2122
#define PIN_ONEWIRE_DEFAULT 0
2223

@@ -74,8 +75,56 @@ struct DS18B20Driver {
7475
}
7576
return true;
7677
}
78+
7779
};
7880

81+
/* ── Panel rendering (normal mode, centered, temperature only) ─────── */
82+
inline void DS18B20_renderPanel(GFXcanvas16* cv, float t, bool isValid,
83+
int16_t cardW, bool isRedPhase, uint16_t panelBg,
84+
const GFXfont& font24, const GFXfont& font12,
85+
const GFXfont& font9) {
86+
uint16_t txtSub = isRedPhase ? RGB565(255,255,255) : 0xCE9A52;
87+
uint16_t tempCol = isRedPhase ? RGB565(255,255,255) : 0x04B04C;
88+
uint16_t icTherm = isRedPhase ? RGB565(220,200,200) : txtSub;
89+
uint16_t merc = isRedPhase ? RGB565(255,255,255) : 0xD04020;
90+
91+
if (!isValid || isnan(t)) {
92+
cv->setFont(&font12);
93+
cv->setTextColor(0x8A7A6A);
94+
cv->setCursor((cardW - 60) / 2, 15);
95+
cv->print("--.-");
96+
drawThermometerLarge(cv, (cardW - 160) / 2 - 10, 4,
97+
icTherm, panelBg, merc);
98+
return;
99+
}
100+
101+
int negMul = (t < 0.0f) ? -1 : 1;
102+
float absT = (t < 0.0f) ? -t : t;
103+
int intPart = (int)absT;
104+
int decPart = (int)((absT - (float)intPart) * 10.0f + 0.5f);
105+
if (decPart >= 10) { intPart++; decPart = 0; }
106+
char iP[8]; snprintf(iP, sizeof(iP), "%d", intPart);
107+
char dP[4]; snprintf(dP, sizeof(dP), "%d", decPart);
108+
int16_t xx, yy; uint16_t iw, ih;
109+
cv->getTextBounds(iP, 0, 0, &xx, &yy, &iw, &ih);
110+
111+
int anchorX = (cardW - (int)iw - 8) / 2 + 10;
112+
int iconX = (cardW - 160) / 2 - 10;
113+
114+
drawThermometerLarge(cv, iconX, 4, icTherm, panelBg, merc);
115+
116+
cv->setFont(&font24);
117+
cv->setTextColor(tempCol);
118+
if (negMul < 0) { cv->setCursor(anchorX - (int)iw - 6, 35); cv->print("-"); }
119+
cv->setCursor(anchorX - (int)iw, 35);
120+
cv->print(iP);
121+
cv->setCursor(anchorX + 4, 35); cv->print(".");
122+
cv->print(dP);
123+
124+
int unitX = anchorX + 4 + (int)iw + 6;
125+
drawUnitDegC_Normal(cv, unitX, txtSub, font9, font12);
126+
}
127+
79128
#else
80129
#define PIN_ONEWIRE_DEFAULT 255
81130
#endif /* SIMUT_SENSOR_DS18B20 */

src/sensors/SensorDrawing.h

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/**
2+
* @file SensorDrawing.h
3+
* @brief Shared procedural icons for sensor panel rendering.
4+
*
5+
* Each icon function is guarded by its sensor's compile flag — when a sensor
6+
* is disabled via SIMUT_SENSOR_*, its icon code is stripped from flash.
7+
*
8+
* All functions draw into a GFXcanvas16. The caller is responsible for
9+
* blitting the canvas to the TFT at the correct position.
10+
*
11+
* @project SIMUT — Integrated Universal Monitoring and Telemetry System
12+
* @license MIT License
13+
*/
14+
15+
#pragma once
16+
#include <Adafruit_GFX.h>
17+
#ifndef RGB565
18+
#define RGB565(r,g,b) ((((r) & 0xF8) << 8) | (((g) & 0xFC) << 3) | ((b) >> 3))
19+
#endif
20+
21+
/* ── Thermometer (large, 18×28 px) ──────────────────────────────────────── */
22+
23+
#if SIMUT_SENSOR_DS18B20 || SIMUT_SENSOR_DHT22 || SIMUT_SENSOR_BME280
24+
inline void drawThermometerLarge(GFXcanvas16* cv, int16_t x, int16_t y,
25+
uint16_t outline, uint16_t bg, uint16_t mercury) {
26+
cv->fillCircle(x + 5, y + 26, 7, outline);
27+
cv->fillRoundRect(x + 1, y, 8, 24, 4, outline);
28+
cv->fillRoundRect(x + 3, y + 2, 4, 20, 2, bg);
29+
cv->fillCircle(x + 5, y + 26, 5, bg);
30+
cv->fillRect(x + 4, y + 10, 2, 14, mercury);
31+
cv->fillCircle(x + 5, y + 26, 4, mercury);
32+
cv->fillCircle(x + 5, y + 2, 2, outline);
33+
}
34+
#endif
35+
36+
/* ── Thermometer (mini, ~12×20 px) ──────────────────────────────────────── */
37+
38+
#if SIMUT_SENSOR_DS18B20 || SIMUT_SENSOR_DHT22 || SIMUT_SENSOR_BME280
39+
inline void drawThermometerMini(GFXcanvas16* cv, int16_t x, int16_t y,
40+
uint16_t outline, uint16_t bg, uint16_t mercury) {
41+
cv->fillCircle(x + 4, y + 15, 5, outline);
42+
cv->fillRoundRect(x + 1, y, 7, 14, 3, outline);
43+
cv->fillRoundRect(x + 2, y + 1, 5, 12, 2, bg);
44+
cv->fillCircle(x + 4, y + 15, 4, bg);
45+
cv->fillRect(x + 3, y + 8, 3, 6, mercury);
46+
cv->fillCircle(x + 4, y + 15, 3, mercury);
47+
cv->fillCircle(x + 4, y + 2, 2, outline);
48+
}
49+
#endif
50+
51+
/* ── Drop / water droplet (large, ~20×22 px) ────────────────────────────── */
52+
53+
#if SIMUT_SENSOR_DHT22 || SIMUT_SENSOR_BME280
54+
inline void drawDropLarge(GFXcanvas16* cv, int16_t x, int16_t y,
55+
uint16_t color, uint16_t shine) {
56+
cv->fillCircle(x + 6, y + 20, 8, color);
57+
cv->fillTriangle(x + 6, y, x - 1, y + 18, x + 13, y + 18, color);
58+
cv->fillCircle(x + 4, y + 17, 3, shine);
59+
cv->fillCircle(x + 3, y + 14, 1, shine);
60+
}
61+
#endif
62+
63+
/* ── Drop / water droplet (mini, ~12×14 px) ─────────────────────────────── */
64+
65+
#if SIMUT_SENSOR_DHT22 || SIMUT_SENSOR_BME280
66+
inline void drawDropMini(GFXcanvas16* cv, int16_t x, int16_t y,
67+
uint16_t color, uint16_t shine) {
68+
cv->fillCircle(x + 5, y + 7, 6, color);
69+
cv->fillTriangle(x + 5, y - 5, x, y + 5, x + 10, y + 5, color);
70+
cv->fillCircle(x + 3, y + 5, 2, shine);
71+
cv->drawPixel(x + 3, y + 2, shine);
72+
}
73+
#endif
74+
75+
/* ── "°C" unit (normal mode, 24pt value) ────────────────────────────────── */
76+
77+
inline void drawUnitDegC_Normal(GFXcanvas16* cv, int16_t x,
78+
uint16_t color, const GFXfont& font9,
79+
const GFXfont& font12) {
80+
cv->setFont(&font9);
81+
cv->setTextColor(color);
82+
cv->setCursor(x, 17);
83+
cv->print("o");
84+
cv->setFont(&font12);
85+
cv->setCursor(x + 8, 35);
86+
cv->print("C");
87+
}
88+
89+
/* ── "°C" unit (min/max mode, 9pt value) ────────────────────────────────── */
90+
91+
inline void drawUnitDegC_Mini(GFXcanvas16* cv, int16_t x, int16_t baseY,
92+
uint16_t color, const GFXfont& font9) {
93+
cv->setFont(NULL);
94+
cv->setTextSize(1);
95+
cv->setTextColor(color);
96+
cv->setCursor(x, baseY + 2);
97+
cv->print("o");
98+
cv->setFont(&font9);
99+
cv->setCursor(x + 6, baseY + 15);
100+
cv->print("C");
101+
}
102+

src/sensors/SensorPanelDispatch.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @file SensorPanelDispatch.h
3+
* @brief Dispatches panel rendering to the correct sensor driver.
4+
*
5+
* Include this from DisplayManager_Dashboard.cpp to call
6+
* sensorRenderPanel() with a SensorType. The correct driver's
7+
* renderPanel is called based on the type.
8+
*
9+
* @project SIMUT — Integrated Universal Monitoring and Telemetry System
10+
* @license MIT License
11+
*/
12+
13+
#pragma once
14+
#include "SensorDrawing.h"
15+
#include "DS18B20Driver.h"
16+
#include "DHT22Driver.h"
17+
18+
/** Calls the appropriate driver's renderPanel for the given sensor type. */
19+
inline void sensorRenderPanel(GFXcanvas16* cv, SensorType type,
20+
float v1, float v2, bool isValid,
21+
int16_t cardW, bool leftAnchor, bool isRedPhase,
22+
uint16_t panelBg, const GFXfont& font24,
23+
const GFXfont& font12, const GFXfont& font9) {
24+
switch (type) {
25+
#if SIMUT_SENSOR_DHT22
26+
case TYPE_DHT22:
27+
DHT22_renderPanel(cv, v1, v2, isValid, cardW, leftAnchor,
28+
isRedPhase, panelBg, font24, font12, font9);
29+
return;
30+
#endif
31+
#if SIMUT_SENSOR_DS18B20
32+
case TYPE_DS18B20:
33+
DS18B20_renderPanel(cv, v1, isValid, cardW, isRedPhase, panelBg,
34+
font24, font12, font9);
35+
return;
36+
#endif
37+
default: break;
38+
}
39+
/* Fallback: basic thermometer + temperature */
40+
DS18B20_renderPanel(cv, v1, isValid, cardW, isRedPhase, panelBg,
41+
font24, font12, font9);
42+
}

0 commit comments

Comments
 (0)