Skip to content

Commit d773295

Browse files
committed
refactor(wsen-pads): Rewrite climate station with steami_screen widgets.
Major rewrite of the station_env example: 1. Use steami_screen (Screen, SSD1327Display, gauge, title, value, subtitle) instead of 100+ lines of pixel-by-pixel manual drawing (draw_hline, draw_vline, draw_rect, draw_fill_rect, draw_circle). The native framebuf primitives behind steami_screen are implemented in C and are orders of magnitude faster than Python pixel loops. 2. Remove fake calibration that forced readings toward arbitrary "ideal" values (20C, 50%RH, 1013hPa). A sensor reading 23C at startup was being shifted to 20C, making every subsequent reading wrong by -3C. The example now shows raw sensor values. For real calibration, use steami_config (see calibrate_temperature.py). 3. Translate all UI text and comments from French to English to match the project convention. 4. Add try/except/finally with power_off() for both sensors so Ctrl+C does not leave WSEN-PADS and HTS221 running. 5. Use named comfort thresholds (TEMP_MIN/MAX, HUM_MIN/MAX, PRES_MIN/MAX) instead of inline magic numbers.
1 parent c2f55d9 commit d773295

1 file changed

Lines changed: 64 additions & 144 deletions

File tree

Lines changed: 64 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,173 +1,93 @@
11
"""Climate station example using WSEN-PADS, HTS221 and SSD1327 OLED.
22
33
Reads temperature and pressure from the WSEN-PADS sensor and humidity
4-
from the HTS221 sensor. Includes a startup calibration phase to compensate
5-
sensor offsets. Displays live temperature, humidity and pressure readings
6-
with horizontal progress bars and a comfort index on a round 128x128 OLED.
4+
from the HTS221 sensor. Displays live readings with a comfort index
5+
on the round 128x128 OLED using steami_screen widgets.
6+
7+
Hardware:
8+
- WSEN-PADS (temperature + pressure)
9+
- HTS221 (humidity)
10+
- SSD1327 128x128 OLED display (round)
711
"""
812

913
from time import sleep_ms
1014

1115
import ssd1327
1216
from hts221 import HTS221
1317
from machine import I2C, SPI, Pin
18+
from steami_screen import GRAY, GREEN, LIGHT, RED, WHITE, Screen, SSD1327Display
1419
from wsen_pads import WSEN_PADS
1520

16-
# === Ecran ===
21+
# --- Display ---
1722
spi = SPI(1)
1823
dc = Pin("DATA_COMMAND_DISPLAY")
1924
res = Pin("RST_DISPLAY")
2025
cs = Pin("CS_DISPLAY")
21-
display = ssd1327.WS_OLED_128X128_SPI(spi, dc, res, cs)
26+
display = SSD1327Display(ssd1327.WS_OLED_128X128_SPI(spi, dc, res, cs))
27+
screen = Screen(display)
2228

23-
# === Capteurs ===
29+
# --- Sensors ---
2430
i2c = I2C(1)
2531
pads = WSEN_PADS(i2c)
2632
hts = HTS221(i2c)
2733

28-
# === Calibration ===
29-
print("Calibration en cours...")
30-
temps = []
31-
hums = []
32-
press = []
33-
for _ in range(10):
34-
temps.append(pads.temperature())
35-
hums.append(hts.humidity())
36-
press.append(pads.pressure_hpa())
37-
sleep_ms(200)
38-
39-
OFFSET_TEMP = 20.0 - (sum(temps) / len(temps))
40-
OFFSET_HUM = 50.0 - (sum(hums) / len(hums))
41-
OFFSET_PRES = 1013.0 - (sum(press) / len(press))
42-
print(f"Offset T:{OFFSET_TEMP:.2f} H:{OFFSET_HUM:.2f} P:{OFFSET_PRES:.2f}")
43-
print("Calibration OK")
44-
45-
46-
# === Dessin ===
47-
def draw_hline(x, y, w, color=15):
48-
for i in range(w):
49-
display.pixel(x + i, y, color)
50-
51-
52-
def draw_vline(x, y, h, color=15):
53-
for i in range(h):
54-
display.pixel(x, y + i, color)
55-
56-
57-
def draw_rect(x, y, w, h, color=15):
58-
draw_hline(x, y, w, color)
59-
draw_hline(x, y + h - 1, w, color)
60-
draw_vline(x, y, h, color)
61-
draw_vline(x + w - 1, y, h, color)
62-
63-
64-
def draw_fill_rect(x, y, w, h, color=15):
65-
for i in range(h):
66-
draw_hline(x, y + i, w, color)
67-
68-
69-
def draw_circle(cx, cy, r, color=15):
70-
x = r
71-
y = 0
72-
err = 0
73-
while x >= y:
74-
display.pixel(cx + x, cy + y, color)
75-
display.pixel(cx + y, cy + x, color)
76-
display.pixel(cx - y, cy + x, color)
77-
display.pixel(cx - x, cy + y, color)
78-
display.pixel(cx - x, cy - y, color)
79-
display.pixel(cx - y, cy - x, color)
80-
display.pixel(cx + y, cy - x, color)
81-
display.pixel(cx + x, cy - y, color)
82-
y += 1
83-
err += 1 + 2 * y
84-
if 2 * (err - x) + 1 > 0:
85-
x -= 1
86-
err += 1 - 2 * x
87-
88-
89-
def draw_bar_h(x, y, w, h, value, min_val, max_val, color=13):
90-
draw_rect(x, y, w, h, 5)
91-
ratio = (value - min_val) / (max_val - min_val)
92-
ratio = max(0.0, min(1.0, ratio))
93-
filled = int((w - 2) * ratio)
94-
if filled > 0:
95-
draw_fill_rect(x + 1, y + 1, filled, h - 2, color)
34+
# --- Comfort thresholds ---
35+
TEMP_MIN, TEMP_MAX = 18.0, 26.0
36+
HUM_MIN, HUM_MAX = 40.0, 60.0
37+
PRES_MIN, PRES_MAX = 1000.0, 1025.0
38+
39+
POLL_MS = 1000
9640

9741

9842
def comfort_label(temp, hum, pres):
99-
if 18 <= temp <= 26 and 40 <= hum <= 60 and 1000 <= pres <= 1025:
100-
return "IDEAL", 15
101-
elif temp > 30 or hum > 75:
102-
return "CHAUD", 11
103-
elif temp < 15 or hum < 25:
104-
return "FROID", 9
105-
elif pres < 1000:
106-
return "BASSE P", 9
107-
elif pres > 1025:
108-
return "HAUTE P", 13
109-
else:
110-
return "CORRECT", 12
43+
"""Return a (label, color) tuple describing indoor comfort."""
44+
if TEMP_MIN <= temp <= TEMP_MAX and HUM_MIN <= hum <= HUM_MAX and PRES_MIN <= pres <= PRES_MAX:
45+
return "IDEAL", GREEN
46+
if temp > 30 or hum > 75:
47+
return "HOT", RED
48+
if temp < 15 or hum < 25:
49+
return "COLD", GRAY
50+
if pres < PRES_MIN:
51+
return "LOW P", GRAY
52+
if pres > PRES_MAX:
53+
return "HIGH P", LIGHT
54+
return "OK", WHITE
11155

11256

11357
def draw_screen(temp, hum, pres):
114-
display.fill(0)
115-
116-
# Bordure circulaire
117-
draw_circle(64, 64, 62, 4)
118-
draw_circle(64, 64, 60, 2)
119-
120-
# === TITRE ===
121-
display.text("CLIMAT", 35, 20, 15)
122-
draw_hline(19, 29, 90, 6)
123-
124-
# === TEMPERATURE ===
125-
display.text("T", 19, 35, 7)
126-
temp_str = f"{temp:.1f}C"
127-
display.text(temp_str, 29, 35, 15)
128-
draw_bar_h(19, 44, 90, 5, temp, 0, 50, 13)
129-
130-
# === HUMIDITE ===
131-
display.text("H", 19, 52, 7)
132-
hum_str = f"{hum:.1f}%"
133-
display.text(hum_str, 29, 52, 15)
134-
draw_bar_h(19, 61, 90, 5, hum, 0, 100, 11)
135-
136-
# === PRESSION ===
137-
display.text("P", 19, 69, 7)
138-
pres_str = f"{pres:.0f}hPa"
139-
display.text(pres_str, 29, 69, 15)
140-
draw_bar_h(19, 78, 90, 5, pres, 950, 1050, 10)
141-
142-
# === SEPARATEUR ===
143-
draw_hline(19, 86, 90, 4)
144-
145-
# === CONFORT ===
146-
label, c_color = comfort_label(temp, hum, pres)
147-
cx = 64 - len(label) * 4
148-
display.text(label, cx, 92, c_color)
149-
150-
# === CAPTEURS ===
151-
draw_hline(19, 102, 90, 3)
152-
display.text("PADS+HTS221", 22, 106, 4)
153-
154-
display.show()
155-
156-
157-
# === Boucle principale ===
158-
print("Station climatique demarree")
159-
while True:
160-
try:
161-
temp = pads.temperature() + OFFSET_TEMP
162-
hum = hts.humidity() + OFFSET_HUM
163-
pres = pads.pressure_hpa() + OFFSET_PRES
58+
"""Render one frame with all readings and comfort index."""
59+
label, color = comfort_label(temp, hum, pres)
60+
61+
screen.clear()
62+
screen.gauge(
63+
int(temp), min_val=0, max_val=50, color=color,
64+
)
65+
screen.title("CLIMATE")
66+
screen.value("{:.1f}".format(temp), unit="C")
67+
screen.subtitle(
68+
"H:{:.0f}% P:{:.0f}hPa".format(hum, pres),
69+
label,
70+
)
71+
screen.show()
72+
73+
74+
# --- Main loop ---
75+
print("Climate station started")
76+
print("Press Ctrl+C to exit.")
77+
78+
try:
79+
while True:
80+
temp = pads.temperature()
81+
hum = hts.humidity()
82+
pres = pads.pressure_hpa()
16483
hum = max(0.0, min(100.0, hum))
165-
print(f"T:{temp:.2f}C H:{hum:.2f}% P:{pres:.1f}hPa")
84+
print("T:{:.1f}C H:{:.1f}% P:{:.0f}hPa".format(temp, hum, pres))
16685
draw_screen(temp, hum, pres)
167-
except Exception as e:
168-
print("Erreur:", e)
169-
display.fill(0)
170-
display.text("ERREUR", 35, 55, 15)
171-
display.text(str(e)[:16], 0, 70, 9)
172-
display.show()
173-
sleep_ms(1000)
86+
sleep_ms(POLL_MS)
87+
except KeyboardInterrupt:
88+
print("\nClimate station stopped.")
89+
finally:
90+
screen.clear()
91+
screen.show()
92+
pads.power_off()
93+
hts.power_off()

0 commit comments

Comments
 (0)