1. What Board To Buy
Main Board
ESP32 Dev Board (e.g., “ESP32 DEVKIT V1”, “ESP32-WROOM-32”)
Buy from a reputable brand or supplier (e.g., AZDelivery, DOIT, Adafruit, SparkFun, etc.).
Add-On Boards/Modules
RS485 to TTL Module (based on MAX485 chip, for connecting ZEH100 sensor)
Optocoupler PWM Module (for safe PWM output to 230V EC fan’s PWM input, e.g., PC817 or pre-made PWM isolation module)
12V DC Power Supply (for ZEH100 and optocoupler,
with 5V step-down for ESP32 if needed)
Jumper wires, breadboard or screw terminals for prototyping
2. How to Connect
ESP32 Pinout Recommendation:
Function ESP32 Pin To Module/Device Notes
RS485 DE/RE GPIO18 RS485 Module DE+RE (tie) Direction control
RS485 RX GPIO16 RS485 Module RO Serial RX
RS485 TX GPIO17 RS485 Module DI Serial TX
PWM Output GPIO25 Optocoupler IN (via 1k resistor) PWM to EC fan (use optocoupler!)
3.3V 3V3 RS485 Module VCC (if 3.3V) Or 5V if board supports it
GND G All module GNDs Common ground
ZEH100 sensor wiring:
V+ (Pin 1): 12V DC
G (Pin 4): GND
A (Pin 2): RS485 A
B (Pin 3): RS485 B
EC Fan PWM:
PWM IN: From optocoupler output (isolated from ESP32)
GND: Fan GND (to optocoupler output GND side)
3. Code: ESP32 with WiFiManager and Email Alert
This code:
Lets you choose WiFi from a list (WiFiManager captive portal on first boot).
Reads ZEH100 via RS485.
Controls EC fan speed via PWM using your logic.
Sends an email notification when the fan activates, with current PWM, temp, and gas readings.
Install these Arduino libraries:
WiFiManager
ESP-Mail-Client
You MUST fill in your own SMTP/email provider credentials!C:
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
| zeh100_ecfan_email_esp32.ino
v2
#include <WiFiManager.h>
#include <ESP_Mail_Client.h>
#include <HardwareSerial.h>
// RS485/ZEH100 pins
#define RS485_DE_RE 18
4. In Summary — Shopping List
1x ESP32 Dev Board
1x RS485 to TTL Module (MAX485)
1x Optocoupler PWM Module (or build with PC817)
1x 12V DC Power Supply (enough current for ZEH100 and fan control modules)
1x ZEH100 sensor
1x 230V EC Fan (with 0-10V or 0-5V PWM input)
Jumper wires, breadboard, or screw terminals
Let me know if you want a schematic/wiring diagram, photos, or pre-made Amazon/Aliexpress links for the modules!
---
#include <WiFiManager.h>
#include <ESP_Mail_Client.h>
#include <HardwareSerial.h>
// RS485/ZEH100 pins
#define RS485_DE_RE 18
#define RS485_RX 16
#define RS485_TX 17
// EC Fan PWM
#define FAN_PWM_PIN 25
#define FAN_PWM_CHANNEL 0
#define FAN_PWM_FREQ 25000 // 25kHz
#define FAN_PWM_RES 8 // 8-bit
// Fan logic thresholds
#define TEMP_START 25
#define TEMP_FULL 55
#define TEMP_STOP 60
// Email config - FILL THESE IN
#define SMTP_HOST "smtp.gmail.com"
#define SMTP_PORT 465 // SSL
#define AUTHOR_EMAIL "your_email@gmail.com"
#define AUTHOR_PASSWORD "your_app_password"
#define RECIPIENT_EMAIL "your_email@gmail.com"
// ZEH100 Query cmd for 485
uint8_t zeh100_query[8] = {0x01, 0x03, 0x00, 0x01, 0x00, 0x04, 0x15, 0xC9};
HardwareSerial RS485Serial(2);
bool fanActive = false;
unsigned long lastEmailSent = 0;
const unsigned long emailInterval = 60000; // 1 minute
SMTPSession smtp;
void setup() {
Serial.begin(115200);
// WiFiManager for easy WiFi selection
WiFiManager wm;
bool res = wm.autoConnect("ECFan_ConfigAP");
if(!res) {
Serial.println("Failed to connect. Restarting...");
ESP.restart();
}
Serial.println("WiFi connected!");
// PWM setup
ledcSetup(FAN_PWM_CHANNEL, FAN_PWM_FREQ, FAN_PWM_RES);
ledcAttachPin(FAN_PWM_PIN, FAN_PWM_CHANNEL);
// RS485
pinMode(RS485_DE_RE, OUTPUT);
digitalWrite(RS485_DE_RE, LOW); // RX mode
RS485Serial.begin(9600, SERIAL_8N1, RS485_RX, RS485_TX);
}
void loop() {
// Query ZEH100
digitalWrite(RS485_DE_RE, HIGH); // TX mode
delay(1);
RS485Serial.write(zeh100_query, 8);
RS485Serial.flush();
digitalWrite(RS485_DE_RE, LOW); // RX mode
delay(100);
if (RS485Serial.available() >= 13) {
uint8_t resp[13];
RS485Serial.readBytes(resp, 13);
int co = (resp[3] << 8) | resp[4];
int h2 = (resp[5] << 8) | resp[6];
uint8_t tempRaw = resp[9];
int temp = (int)tempRaw - 40;
uint8_t alarm = resp[10];
bool co_alarm = alarm & 0x01;
bool h2_alarm = alarm & 0x02;
bool smoke_alarm = alarm & 0x08;
int fanSpeed = 0;
String cause = "";
if (temp >= TEMP_STOP) {
fanSpeed = 0;
cause = "Overheat (>60°C)";
} else if (smoke_alarm) {
fanSpeed = 100;
cause = "Smoke detected";
} else if (co_alarm || h2_alarm) {
fanSpeed = 100;
cause = (co_alarm ? "CO " : "") + (h2_alarm ? "H2 " : "");
cause.trim();
cause += "alarm";
} else if (temp >= TEMP_FULL) {
fanSpeed = 100;
cause = "Temperature high";
} else if (temp >= TEMP_START) {
float ramp = (float)(temp - TEMP_START) / (TEMP_FULL - TEMP_START);
fanSpeed = 5 + ramp * 95;
if (fanSpeed > 100) fanSpeed = 100;
cause = "Temperature ramp";
} else {
fanSpeed = 0;
cause = "Temperature low";
}
setFanSpeed(fanSpeed);
// Email notification logic
if (fanSpeed > 0 && !fanActive && millis() - lastEmailSent > emailInterval) {
String msg = "FAN ACTIVATED: Cause: " + cause
+ "\nPWM: " + String(fanSpeed) + "%"
+ "\nTemp: " + String(temp) + "C"
+ "\nCO: " + String(co) + "ppm"
+ "\nH2: " + String(h2) + "ppm";
sendEmail(msg);
lastEmailSent = millis();
fanActive = true;
} else if (fanSpeed == 0) {
fanActive = false;
}
Serial.printf("CO:%d H2:%d Temp:%d Fan:%d%% Cause:%s\n", co, h2, temp, fanSpeed, cause.c_str());
}
delay(500);
}
void setFanSpeed(int percent) {
int pwm = map(percent, 0, 100, 0, 255);
ledcWrite(FAN_PWM_CHANNEL, pwm);
}
void sendEmail(String message) {
SMTP_Message email;
email.sender.name = "ECFan ESP32";
email.sender.email = AUTHOR_EMAIL;
email.subject = "ECFan ALERT";
email.addRecipient("User", RECIPIENT_EMAIL);
email.text.content = message.c_str();
smtp.debug(0);
smtp.callback(NULL);
ESP_Mail_Session session;
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "";
if (!smtp.connect(&session)) {
Serial.println("Email connection failed");
return;
}
if (!MailClient.sendMail(&smtp, &email, true)) {
Serial.println("Email send failed: " + smtp.errorReason());
} else {
Serial.println("Email sent!");
}
smtp.closeSession();
} |
Deze voorgestelde modules blijkt OK
Dan beetje proberen met voorgestelde code.