/
thermo32.yml
388 lines (327 loc) · 10.3 KB
/
thermo32.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
esphome:
name: thermostat
comment: Home Thermostat
wifi:
ssid: NotProgrium
password: !secret wifi_password
fast_connect: true
logger:
level: ERROR
web_server:
port: 80
api:
encryption:
key: !secret key_thermo32
esp32:
board: atmegazero_esp32s2
ota:
password: !secret wifi_password
i2c:
sda: GPIO8
scl: GPIO9
spi:
clk_pin: GPIO36
mosi_pin: GPIO35
miso_pin: GPIO37
globals:
- id: show_fahrenheit
type: bool
restore_value: no
initial_value: 'true'
time:
- platform: sntp
id: sntp_time
font:
- id: noto_sans
file: "gfonts://Noto Sans"
size: 80
- id: noto_sans_small
file: "gfonts://Noto Sans"
size: 26
- id: noto_sans_medium
file: "gfonts://Noto Sans"
size: 40
color:
- id: color_red
hex: "FF0000"
- id: color_blue
hex: "0000FF"
- id: color_green
hex: "00FF00"
- id: color_auto
hex: "FFFF00"
- id: light_gray
hex: "EEEEEE"
image:
- file: mdi:fan
id: fan_icon
resize: 80x80
- file: mdi:snowflake
id: cooling_icon
resize: 80x80
- file: mdi:snowflake
id: cooling_icon_small
resize: 26x26
- file: mdi:snowflake
id: cooling_icon_medium
resize: 40x40
- file: mdi:fire
id: heating_icon
resize: 80x80
- file: mdi:fire
id: heating_icon_small
resize: 26x26
- file: mdi:fire
id: heating_icon_medium
resize: 40x40
- file: mdi:autorenew
id: auto_icon
resize: 80x80
- file: mdi:power
id: off_icon
resize: 80x80
- id: arrow_up
file: mdi:arrow-up-bold-box
resize: 80x80
- id: arrow_down
file: mdi:arrow-down-bold-box
resize: 80x80
- id: arrow_left_medium
file: mdi:arrow-left-bold-box
resize: 40x40
- id: arrow_right_medium
file: mdi:arrow-right-bold-box
resize: 40x40
- id: home_temp
file: mdi:home-thermometer
resize: 80x80
display:
- platform: ili9xxx
id: thermostat_display
model: ili9486
dc_pin: GPIO2
cs_pin: GPIO38
reset_pin: GPIO7
rotation: 90°
dimensions: 320x480
data_rate: 20MHz
pages:
- id: home
lambda: |-
auto convertTemp = [](float temp) -> float {
return id(show_fahrenheit) ? (temp * 9.0 / 5.0 + 32) : temp;
};
auto drawIcon = [&it](int x, int y, esphome::image::Image *id, esphome::display::ImageAlign align, esphome::Color color) {
it.image(x, y, id, align, color);
};
auto printText = [&it](int x, int y, esphome::font::Font *font, esphome::display::TextAlign align, const char* text) {
it.print(x, y, font, align, text);
};
auto action = id(thermostat_home).action;
auto mode = id(thermostat_home).mode;
float current_temp = convertTemp(id(bme280_temperature).state);
float target_low = convertTemp(id(thermostat_home).target_temperature_low);
float target_high = convertTemp(id(thermostat_home).target_temperature_high);
char current_temp_str[10];
char target_low_str[10];
char target_high_str[10];
snprintf(current_temp_str, sizeof(current_temp_str), "%.1f", current_temp);
snprintf(target_low_str, sizeof(target_low_str), "%.1f", target_low);
snprintf(target_high_str, sizeof(target_high_str), "%.1f", target_high);
std::string action_text;
it.fill(Color::BLACK);
switch (action) {
case climate::CLIMATE_ACTION_OFF: action_text = "Off"; break;
case climate::CLIMATE_ACTION_HEATING: action_text = "Heating"; break;
case climate::CLIMATE_ACTION_COOLING: action_text = "Cooling"; break;
case climate::CLIMATE_ACTION_IDLE: action_text = "Idle"; break;
default: action_text = "Unknown"; break;
}
switch (mode) {
case climate::CLIMATE_MODE_OFF: drawIcon(475, 315, id(off_icon), ImageAlign::BOTTOM_RIGHT, id(light_gray)); break;
case climate::CLIMATE_MODE_HEAT: drawIcon(475, 315, id(heating_icon), ImageAlign::BOTTOM_RIGHT, id(color_red)); break;
case climate::CLIMATE_MODE_COOL: drawIcon(475, 315, id(cooling_icon), ImageAlign::BOTTOM_RIGHT, id(color_blue)); break;
case climate::CLIMATE_MODE_HEAT_COOL: drawIcon(475, 315, id(auto_icon), ImageAlign::BOTTOM_RIGHT, id(color_auto)); break;
default: drawIcon(475, 315, id(off_icon), ImageAlign::BOTTOM_RIGHT, id(light_gray)); break;
}
// Show current temp icon and text
drawIcon(0, 14, id(home_temp), ImageAlign::TOP_LEFT, id(color_green));
printText(100, 0, id(noto_sans), TextAlign::TOP_LEFT, current_temp_str);
// Show set point icons
drawIcon((it.get_width() /2) - 50, 150, id(heating_icon_medium), ImageAlign::CENTER_LEFT, id(color_red));
drawIcon((it.get_width() /2) - 50, 230, id(cooling_icon_medium), ImageAlign::CENTER_LEFT, id(color_blue));
// Show set point text
printText(it.get_width() / 2, 150, id(noto_sans_medium), TextAlign::CENTER_LEFT, target_low_str);
printText(it.get_width() / 2, 230, id(noto_sans_medium), TextAlign::CENTER_LEFT, target_high_str);
// Show set point arrows
drawIcon((it.get_width() /2) + 130, 150, id(arrow_right_medium), ImageAlign::CENTER_RIGHT, id(color_red));
drawIcon((it.get_width() /2) + 130, 230, id(arrow_right_medium), ImageAlign::CENTER_RIGHT, id(color_blue));
drawIcon((it.get_width() /2) - 100, 150, id(arrow_left_medium), ImageAlign::CENTER_LEFT, id(color_red));
drawIcon((it.get_width() /2) - 100, 230, id(arrow_left_medium), ImageAlign::CENTER_LEFT, id(color_blue));
// Current action text
printText(0, it.get_height(), id(noto_sans_medium), TextAlign::BOTTOM_LEFT, action_text.c_str());
// Current date and time
printText(340, 5, id(noto_sans_small), TextAlign::TOP_LEFT, id(sntp_time).now().strftime("%a, %b %d").c_str());
printText(340, 35, id(noto_sans_small), TextAlign::TOP_LEFT, id(sntp_time).now().strftime("%I:%M %P").c_str());
- id: graphs
lambda: |-
it.graph(0, 0, id(temperature_graph));
graph:
- id: temperature_graph
sensor: bme280_temperature
duration: 1h
width: 240
height: 150
border: false
- id: pressure_graph
sensor: bme280_pressure
duration: 1h
width: 240
height: 150
border: false
touchscreen:
- platform: xpt2046
id: thermostat_touch
cs_pin: GPIO21
display: thermostat_display
interrupt_pin: GPIO33 # This doesn't appear to be working so we comment out to use polling instead
# update_interval: 50ms
# report_interval: 1s
threshold: 400
calibration_x_min: 3870
calibration_x_max: 250
calibration_y_min: 3930
calibration_y_max: 260
on_touch:
- lambda: |-
ESP_LOGE("cal", "x=%d, y=%d, x_raw=%d, y_raw=%0d",
id(thermostat_touch).x,
id(thermostat_touch).y,
id(thermostat_touch).x_raw,
id(thermostat_touch).y_raw
);
button:
- platform: template
id: thermostat_page_next
name: Next Page
icon: mdi:arrow-right
on_press:
# Switch to next page
- display.page.show_next: thermostat_display
switch:
- platform: gpio
pin: GPIO12
name: Fan
id: fan
internal: true
- platform: gpio
pin: GPIO16
name: Air Conditioner
id: cooling
internal: true
- platform: gpio
pin: GPIO18
name: Heater
id: heating
internal: true
sensor:
- platform: bmp280
temperature:
name: Temperature
id: bme280_temperature
internal: true
pressure:
name: Pressure
id: bme280_pressure
internal: true
address: 0x76
update_interval: 60s
binary_sensor:
- platform: touchscreen
id: thermostat_touch_heat_setpoint_down
touchscreen_id: thermostat_touch
name: Lower Heat Setpoint
x_min: 110
x_max: 200
y_min: 110
y_max: 180
internal: true
filters:
- autorepeat:
delay: 100ms
# time_on: 100ms
# time_off: 50ms
on_press:
- climate.control:
id: thermostat_home
target_temperature_low: !lambda |-
float temp_c = id(thermostat_home).target_temperature_low;
if (id(show_fahrenheit)) {
float adjustment_c = 0.2 * 5.0 / 9.0;
temp_c += -adjustment_c;
ESP_LOGE("cal", "temp_c=%f, adjustment_c=%f", temp_c, adjustment_c);
} else {
temp_c += -0.2;
ESP_LOGE("cal", "temp_c=%f", temp_c);
}
return temp_c;
- component.update: thermostat_display
- platform: touchscreen
id: thermostat_touch_heat_setpoint_up
touchscreen_id: thermostat_touch
name: Raise Heat Setpoint
x_min: 310
x_max: 400
y_min: 110
y_max: 180
internal: true
filters:
- autorepeat:
delay: 10s
time_on: 50ms
time_off: 50ms
on_press:
- climate.control:
id: thermostat_home
target_temperature_low: !lambda |-
float temp_c = id(thermostat_home).target_temperature_low;
if (id(show_fahrenheit)) {
float adjustment_c = 0.2 * 5.0 / 9.0;
temp_c += adjustment_c;
ESP_LOGE("cal", "temp_c=%f, adjustment_c=%f", temp_c, adjustment_c);
} else {
temp_c += 0.2;
ESP_LOGE("cal", "temp_c=%f", temp_c);
}
return temp_c;
- component.update: thermostat_display
climate:
- platform: thermostat
name: Thermostat
id: thermostat_home
sensor: bme280_temperature
on_boot_restore_from: memory
min_cooling_off_time: 300s
min_cooling_run_time: 300s
min_heating_off_time: 300s
min_heating_run_time: 300s
min_idle_time: 30s
cool_action:
- switch.turn_on: cooling
heat_action:
- switch.turn_on: heating
idle_action:
- switch.turn_off: cooling
- switch.turn_off: heating
default_preset: Home
preset:
- name: Home
default_target_temperature_low: 68 °F
default_target_temperature_high: 73 °F
mode: heat_cool
visual:
min_temperature: 50 °F
max_temperature: 90 °F
temperature_step:
target_temperature: 0.2
current_temperature: 0.1