-
-
Notifications
You must be signed in to change notification settings - Fork 32
/
air-gradient-pro-diy.yaml
287 lines (258 loc) · 9.59 KB
/
air-gradient-pro-diy.yaml
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
# AirGradient Pro v4.2 DIY edition
#
# Upstream AirGradient Firmware can be found here:
# https://github.com/airgradienthq/arduino/blob/master/examples/DIY_PRO_V4_2/DIY_PRO_V4_2.ino
#
# Instructions:
# - Update your device id in `substitutions`
# - Select your temperature unit in `substitutions`
# - If you have the VOC/NOx sensor installed, uncomment `platform: sgp4x` and page3 of `display`
#
substitutions:
id: "1"
devicename: "airgradient-pro"
upper_devicename: "AirGradient Pro"
# Pick your temperature unit:
# temperature_units: "F"
temperature_units: "C"
esphome:
name: "${devicename}-${id}"
friendly_name: "${upper_devicename} ${id}"
# Automatically add the mac address to the name
# so you can use a single firmware for all devices
# name_add_mac_suffix: true
platform: ESP8266
board: d1_mini
# Enable logging
logger:
baud_rate: 0
# Enable Home Assistant API (API password is deprecated in favor of encryption key)
# https://esphome.io/components/api.html
api:
encryption:
key: !secret home_assistant_encryption_key
ota:
password: !secret ota_password
wifi:
networks:
- ssid: !secret wifi_ssid
password: !secret wifi_password
reboot_timeout: 15min
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "${upper_devicename} Fallback Hotspot"
password: !secret fallback_ssid_password
# The captive portal is a fallback mechanism for when connecting to the configured WiFi fails.
# https://esphome.io/components/captive_portal.html
captive_portal:
# Creates a simple web server on the node that can be accessed through any browser
# https://esphome.io/components/web_server.html
web_server:
port: 80
include_internal: true
# Used to support POST request to send data to AirGradient
# https://esphome.io/components/http_request.html
http_request:
# Create a switch for safe_mode in order to flash the device
# Solution from this thread:
# https://community.home-assistant.io/t/esphome-flashing-over-wifi-does-not-work/357352/1
switch:
- platform: safe_mode
name: "Flash Mode (Safe Mode)"
icon: "mdi:cellphone-arrow-down"
i2c:
sda: D2
scl: D1
font:
- file: "gfonts://Ubuntu"
id: font_data
size: 18
- file: "gfonts://Ubuntu"
id: font_layout
size: 10
glyphs: # We only need a subset of glyphs
- " "
- "."
- "/"
- "°"
- "0"
- "1"
- "2"
- "₂"
- "³"
- "%"
- "5"
- "C"
- "d"
- "e"
- "F"
- "g"
- "H"
- "i"
- "m"
- "M"
- "N"
- "O"
- "p"
- "P"
- "t"
- "T"
- "u"
- "V"
- "x"
- "y"
- "µ"
display:
# https://esphome.io/components/display/ssd1306.html
- platform: ssd1306_i2c
id: oled
address: 0x3c
model: "SH1106 128x64"
pages:
- id: page1
lambda: |-
it.print(51, 2, id(font_layout), TextAlign::TOP_RIGHT, "CO₂");
it.printf(it.get_width() - 30, 18, id(font_data), TextAlign::BOTTOM_RIGHT, isnan(id(co2).state) ? "N/A" : "%.0f", id(co2).state);
it.print(it.get_width() - 28, 16, id(font_layout), TextAlign::BOTTOM_LEFT, "ppm");
it.print(50, 25, id(font_layout), TextAlign::TOP_RIGHT, "Temp.");
float degrees = "${temperature_units}" == "F" ? id(temp).state * 1.8 + 32.0 : id(temp).state;
it.printf(it.get_width() - 30, 41, id(font_data), TextAlign::BOTTOM_RIGHT, "%.0f", degrees);
it.print(it.get_width() - 28, 39, id(font_layout), TextAlign::BOTTOM_LEFT, "°${temperature_units}");
it.print(50, 48, id(font_layout), TextAlign::TOP_RIGHT, "Humidity");
it.printf(it.get_width() - 30, 64, id(font_data), TextAlign::BOTTOM_RIGHT, "%.0f", id(humidity).state);
it.print(it.get_width() - 28, 62, id(font_layout), TextAlign::BOTTOM_LEFT, "%");
// This no longer fits on the page. You're on your own if you've added a nonstandard PMSX003* with formaldehyde sensor.
// it.printf(0, 40, id(font_data), isnan(id(hcho).state) ? "HCHO: N/A" : "HCHO: %.0f µg/m³", id(hcho).state);
- id: page2
lambda: |-
it.print(50, 2, id(font_layout), TextAlign::TOP_RIGHT, "PM 1.0");
it.printf(it.get_width() - 30, 18, id(font_data), TextAlign::BOTTOM_RIGHT, isnan(id(pm_1_0).state) ? "N/A" : "%.0f", id(pm_1_0).state);
it.print(it.get_width() - 28, 16, id(font_layout), TextAlign::BOTTOM_LEFT, "µg/m³");
it.print(50, 25, id(font_layout), TextAlign::TOP_RIGHT, "PM 2.5");
it.printf(it.get_width() - 30, 41, id(font_data), TextAlign::BOTTOM_RIGHT, isnan(id(pm_2_5).state) ? "N/A" : "%.0f", id(pm_2_5).state);
it.print(it.get_width() - 28, 39, id(font_layout), TextAlign::BOTTOM_LEFT, "µg/m³");
it.print(50, 48, id(font_layout), TextAlign::TOP_RIGHT, "PM 10");
it.printf(it.get_width() - 30, 64, id(font_data), TextAlign::BOTTOM_RIGHT, isnan(id(pm_10_0).state) ? "N/A" : "%.0f", id(pm_10_0).state);
it.print(it.get_width() - 28, 62, id(font_layout), TextAlign::BOTTOM_LEFT, "µg/m³");
# - id: page3
# lambda: |-
# it.print(50, 2, id(font_layout), TextAlign::TOP_RIGHT, "VOC");
# it.printf(it.get_width() - 30, 18, id(font_data), TextAlign::BOTTOM_RIGHT, isnan(id(voc).state) ? "N/A" : "%.0f", id(voc).state);
# it.print(50, 25, id(font_layout), TextAlign::TOP_RIGHT, "NOx");
# it.printf(it.get_width() - 30, 41, id(font_data), TextAlign::BOTTOM_RIGHT, isnan(id(nox).state) ? "N/A" : "%.0f", id(nox).state);
interval:
- interval: 10s
then:
- display.page.show_next: oled
- component.update: oled
- interval: 5min
# Send data to AirGradient API server
# for more details have a look at sendToServer() function:
# https://www.airgradient.com/open-airgradient/blog/airgradient-diy-pro-instructions/
then:
- http_request.post:
# AirGradient URL with the last 3 bytes of the MAC address in Hex format all lower case
url: !lambda |-
return "http://hw.airgradient.com/sensors/airgradient:" + get_mac_address().substr(6,11) + "/measures";
headers:
Content-Type: application/json
# "!lambda return to_string(id(pm2).state);" Converts sensor output from double to string
json:
wifi: id(airgradient_wifi_signal).state
pm01: !lambda return to_string(id(pm_1_0).state);
pm02: !lambda return to_string(id(pm_2_5).state);
pm10: !lambda return to_string(id(pm_10_0).state);
pm003_count: !lambda return to_string(id(pm_0_3um).state);
rco2: !lambda return to_string(id(co2).state);
atmp: !lambda return to_string(id(temp).state);
rhum: !lambda return to_string(id(humidity).state);
tvoc: !lambda return to_string(id(voc).state);
verify_ssl: false
uart:
- rx_pin: D5
tx_pin: D6
baud_rate: 9600
id: uart_1
- rx_pin: D4
tx_pin: D3
baud_rate: 9600
id: uart_2
sensor:
# https://esphome.io/components/sensor/sht3xd.html
- platform: sht3xd
temperature:
id: temp
name: ${upper_devicename} Temperature
humidity:
id: humidity
name: ${upper_devicename} Relative Humidity
address: 0x44
update_interval: 10s
# https://esphome.io/components/sensor/pmsx003.html
- platform: pmsx003
type: PMSX003
uart_id: uart_1
pm_1_0:
id: pm_1_0
name: "${upper_devicename} Particulate Matter <1.0µm Concentration"
pm_2_5:
id: pm_2_5
name: "${upper_devicename} Particulate Matter <2.5µm Concentration"
pm_10_0:
id: pm_10_0
name: "${upper_devicename} Particulate Matter <10.0µm Concentration"
pm_0_3um:
id: pm_0_3um
name: "${upper_devicename} Particulate Matter >0.3µm Count"
icon: mdi:blur
pm_0_5um:
id: pm_0_5um
name: "${upper_devicename} Particulate Matter >0.5µm Count"
icon: mdi:blur
pm_1_0um:
id: pm_1_0um
name: "${upper_devicename} Particulate Matter >1.0µm Count"
icon: mdi:blur
pm_2_5um:
id: pm_2_5um
name: "${upper_devicename} Particulate Matter >2.5µm Count"
icon: mdi:blur
# The basic PMSX003 version doesn't have a formaldehyde sensor.
# formaldehyde:
# id: hcho
# name: "${upper_devicename} Formaldehyde (HCHO) concentration in µg per cubic meter"
update_interval: 3min # Sensor will go into sleep mode for extended operation lifetime
# https://esphome.io/components/sensor/senseair.html
- platform: senseair
uart_id: uart_2
co2:
id: co2
name: "${upper_devicename} SenseAir CO2 Value"
update_interval: 60s
# https://esphome.io/components/sensor/sgp4x.html
# https://sensirion.com/products/catalog/SGP41/
# Note that these "index" values don't have a unit. They are a scale from 1-500.
# - platform: sgp4x
# voc:
# id: voc
# name: "VOC Index"
# icon: mdi:chemical-weapon
# # See https://sensirion.com/media/documents/02232963/6294E043/Info_Note_VOC_Index.pdf
# # 0-150 green, 151-250 yellow, 251-400 orange, 401+ red
# nox:
# id: nox
# name: "NOx Index"
# icon: mdi:chemical-weapon
# # See https://sensirion.com/media/documents/9F289B95/6294DFFC/Info_Note_NOx_Index.pdf
# # 0-19 green, 20+ yellow (see PDF for why we don't do more than this)
# compensation:
# humidity_source: humidity
# temperature_source: temp
- platform: wifi_signal
name: "WiFi Signal Sensor"
id: airgradient_wifi_signal
update_interval: 60s
- platform: uptime
name: "Uptime Sensor"
id: uptime_sensor
update_interval: 60s