I am updating the project everyday.
Sorry if there are any mistakes.
What could be improved?
Please let me know in the comments.
Thanks.
Story:I decided to make an Automatic Air purifier.
The reasons I wanted to make this are:
I saw a newer air purifier made by the same company, and it had an app where you could control the device through WiFi.
I wanted to make my Air Purifier have that capability, and make the timer better.
So I decided to make it… and now here it is:
Features:Microcontroller: FireBeetle ESP-32E
Connects to Arduino IoT Cloud.
I controlled the purifier with a IR LED.
You can control this Air Purifier remotely.
Siren, LDR, Automation, Auto mode, and scheduler are still work in progress.
Automatic Air Purifier with Arduino IoT Cloud, and a FireBeetle ESP-32E.Here are the instructions for this project:Please note still Work In ProgressStep 0(Yes, zero because this step is important): Check if your remote uses IR signals.Check if the Air Purifier’s remote uses IR signals.
You will need your device that has a camera that can “see” IR light or use a IR receiver and hook it up to the receiver
First way:
Open a camera app on a computer/phone.
Point the remote at the camera.
Press buttons on the remote.
Look for purple light in the camera app.
Note that not all cameras can “see” IR light.
Second way:
Go to step 5.
Instructions are listed there.
Make sure you installed the IR remote library.
Step 1: Getting started.Install the Arduino IDE on your computer if you haven't done that yet.
Get the IDE from: https://www.arduino.cc/en/software
You can also use the web editor if you want.
If your computer can run IDE 2.x.x install that. It's much better.
Make a Arduino account if haven't made one yet.
This tutorial will tell you how to make the account.
https://support.arduino.cc/hc/en-us/articles/360016724040-Create-an-Arduino-account
Step 2: Set up the cloud thingGo to cloud.arduino.cc/home/
You might have to log in with your Arduino account.
Create a new device.
Select third party board.
Enter the following info
Type: ESP32
Board: FireBeetle ESP-32
Give your device a name.
Arduino Cloud automatically generates some names for the devices.
But, it's names are not very descriptive, so I picked a name of my own.
Note: as this is the tutorial, not the actual one, I used TestFireBeetle as the name.
I recommend picking some thing like the device type, like: FirebeetleESP-32E
Click on continue, then save your device ID and secret key.
I hid mine in the photo.
I like the download the PDF option.
Make sure you have saved them because you cannot recover them.
NEVER share these credentials as they are for accessing your device.
If you accidentally share them, delete the device and make it again.
Create a new arduino cloud thing.
Create 3 variables for it:
Let's start with an integer variable called fanSpeedLevel.
Click the add button.
Enter the following info.
This is for the fan speed.
Name: fanSpeedLevel
Type: Integer Number
Declaration:
int fanSpeedLevel;
Variable Permissions:
Read and write.
Variable Update Policy:
On change:
Threshold:1
Add another variable.
This is for recording the VOC index.
Enter the following info.
Name: VOCIndex
Type: Integer Number
Declaration:
int VOCIndex; //Read Only
Variable Permissions:
Read Only.
Variable Update Policy:
On change: Threshold: 1
Add another variable.
Enter the following info.
Name: Schedule
Type: CloudSchedule
Declaration:
CloudSchedule schedule;// read and write. on change
Variable Permissions:
Read and write.
Note: If you were curious and took a look at “thingProperties.h” you will find that my declarations are slightly different that is because I have not have the time to update that part of this project. This configuration should work though.
Enter your wifi credentials and device credentials in to the proper space:
If you don't know anything about arduino libraries take a look at these:
https://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use/arduino-libraries
https://learn.sparkfun.com/tutorials/installing-an-arduino-library
https://docs.arduino.cc/learn/starting-guide/software-libraries
If you have not installed these libraries install them now.
Install Arduino IoT cloud libraries from library manager.
Install IRremote from library manager.
IRremote GitHub: https://github.com/Arduino-IRremote/Arduino-IRremote
IRremote Arduino Libraries page: https://www.arduinolibraries.info/libraries/i-rremote
Manually install the SGP 40 Library from GitHub:
https://github.com/DFRobot/DFRobot_SGP40
If you don't know how to install libraries manualy take a look at this:
https://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use/how-to-install-a-library
Step 4: Install the board support and drivers.Go to this link and select the appropriate driver for your OS.
https://wiki.dfrobot.com/FireBeetle_Board_ESP32_E_SKU_DFR0654#target_27
Don't install the boards manager provided by DFRobot!
It has some bugs.
Download the driver package and open it's folder.
Inside it will be two files, a pdf, and a installer.
Open the PDF and follow the instructions inside it.
You may need Administrator privileges!
That will install the CH340 driver.
If you don't know how to install third party cores read this:
docs.arduino.cc/learn/starting-guide/cores#how-to-install-a-third-party-core
Read this tutorial on how to install the board core for the FireBeetle:
https://forum.arduino.cc/t/how-to-dfrobot-firebeetle-2-esp32-e-dfr0654-installation-advice/1094480
Now install this link in to the additional boards manager section in the preferences section:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
Wait until it is properly installed.
If you upload a program and get “Property 'upload.tool.serial' is undefined”
Follow this link’s last instructions:
https://forum.arduino.cc/t/how-to-dfrobot-firebeetle-2-esp32-e-dfr0654-installation-advice/1094480
Step 5: Get the IR codesFind out your IR receiver's pinout.
Look at the receiver and look for a code like: VS1838B
I am using a VS1838B
Here are some more IR receiver pinouts(Thanks to LarryD for the photo).
Connect + or VCC to 3.3v.
Connect - or GND to GND.
Connect OUT or S to digital pin 3 on the FireBeetle.
Note if you are using the IO shield change:
const byte IR_RECEIVE_PIN = 3; //IR receiver output pin
To:
const byte IR_RECEIVE_PIN = D3; //IR receiver output pin
Upload this code by pasting this code in to a new Arduino sketch, then select
“FireBeetle ESP-32E” as the board name, after that click the green arrow to upload your code.
Code( “DecodeIRcodes.ino” ):
/*
IR receive test
by GroundFungus
BOM:
FireBeetle ESP-32E
Wiring:
*/
#include <IRremote.h> //Include IRremote Library.
const byte IR_RECEIVE_PIN = 3; //IR receiver output pin
void setup()
{
Serial.begin(115200); //Setup Serial
Serial.println("IR receive test");
Serial.println("press a remote key to get its address and command");
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
}
void loop()
{
if (IrReceiver.decode())
{
unsigned long sCommand = IrReceiver.decodedIRData.command;
//Serial.print(keycommand);
unsigned long sAddress = IrReceiver.decodedIRData.address;
// ignore repeat codes
if ((IrReceiver.decodedIRData.flags & IRDATA_FLAGS_IS_REPEAT))
{
IrReceiver.resume();
return;
}
IrReceiver.resume();
Serial.print("address = ");
Serial.print(sAddress, HEX);
Serial.print(" decoded command = ");
Serial.print(sCommand, HEX);
Serial.println();
}
}
Open the serial monitor and set the baud rate to 115200
.
Then press buttons on your remote.
Take note of the different IR codes and what they do.
Move the IR codes to the main program.
Edit this part of the main program( “AutomaticAirPurifier.ino” ) to your IR codes:
uint8_t sRepeats = 0;//Repeats just zero.
struct IrRemoteKeys // declare the struct
{
byte command;
unsigned long address;
char name[12];//Name can only be up to 12 characters long
char comment[16];//Comment can only be up to 16 characters long
};
IrRemoteKeys IRcodes[] = // decare an array of the struct
{ //Command, Address, Name, Comment.
{ 0x13, 0x12, "power", "power toggle" },//change to your power code
{ 0x11, 0x12, "fanUp", "Make fan faster" },//change to increase fan code
{ 0x10, 0x12, "fanDown", "Make fan slower" },//change to decrease fan code
{ 0x12, 0x12, "Turbo", "Make fan turbo" },// change to turbo code.
{ 0x16, 0x12, "Auto", "toggle auto" }// change to auto code.
};
Note that this code and project is only compatible with NEC codes(I think).
Step 6: Modify the code for your Air Purifier.Now it’s time to change my code to a program that you can use with your Air Purifier.
This is the all the code:
#include "arduino_secrets.h"
// All the wifi and device credentials
/*
Automatic Air Purifier
By V205
Credits:
Arduino(For making all this possible, documentaion, IDE, and IoT cloud), Dfrobot(For documentation, software and hardware),
Adafruit(for documentation), GroundFungus(for help with IR stuff), Xfpd(for help with compiler errors), DaveX(for help with IR reciever pinout), JohnLincoln(for help with IR reciever pinout), LarryD(for help with IR reciever pinout)
Espressif(For ESP-32 arduino core), Ptillich(For debugging uploading problem), Pennam(fot help with complier errors),
Everyone who made IRremote and IoT cloud, Everyone who made the ESP-32 core, Everyone who made the SGP40 library, Eveeryone who made c++, and Ascii.
Thank you to everyone listed above.
Please tell me if I forgot to give atribution to you.
I will add you in to the list.
Arduino IoT Cloud Variables description
The following variables are automatically generated and updated when changes are made to the Thing
int fanSpeedLevel;
int VOCIndex;
CloudSchedule schedule;
Variables which are marked as READ/WRITE in the Cloud Thing will also have functions
which are called when their values are changed from the Dashboard.
These functions are generated with the Thing and added at the end of this sketch.
*/
#include "thingProperties.h" // includes arduino cloud settings
#include <DFRobot_SGP40.h> //libary for SGP40 Voc sensor
#include "TinyIRSender.hpp" // includes TinySender sublibrary of IRremote
DFRobot_SGP40 mySgp40; // initialize SGP 40
#define IR_SEND_PIN D3 // The pin for sending the IR signals.
#define LDRinputPin A5 // LDR pin.
uint8_t sRepeats = 0;//Repeats just zero.
struct IrRemoteKeys // declare the struct
{
byte command;
unsigned long address;
char name[12];//Name can only be up to 12 characters long
char comment[16];//Comment can only be up to 16 characters long
};
IrRemoteKeys IRcodes[] = // decare an array of the struct
{ //Command, Address, Name, Comment.
{ 0x13, 0x12, "power", "power toggle" },
{ 0x11, 0x12, "fanUp", "Make fan faster" },
{ 0x10, 0x12, "fanDown", "Make fan slower" },
{ 0x12, 0x12, "Turbo", "Make fan turbo" },
{ 0x16, 0x12, "Auto", "toggle auto" }
};
const int speakerPin = 9;
int pitch = 805;
int increment = 5;
const int updateInterval = 10; // interval between updates
unsigned long lastUpdate; // last update of position
const int alertDuration = 15000; //lenght of alarm work in progress
const int fanLDRbrightnessTrigger = 100;
int VOCAlert = 400; // change to the VOC level tht you want to trigger the alarm with
int fanLDRvalue; // for sensing fan's LDR
/*
int speakerFreq = 0;
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // will store last time buzzer was updated
unsigned long alertHold = 0;
*/
bool freqGoingUp = true;
bool VOC_alertToggleSwitch = true; // replace with false if you don't want an alarm when voc level exceeds vocalert
//bool autoMode = false;
void setup() {
// Initialize serial and wait for port to open:
Serial.begin(9600);
// This delay gives the chance to wait for a Serial Monitor without blocking if none is found
delay(10000);
Serial.println(F("Running" __FILE__ " by viggo v205"));
Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing tiny IR library version " VERSION_TINYIR));
Serial.println(F(__DATE__));
Serial.println(F(__TIME__));
//delay(9000);
// while (mySgp40.begin(/*duration = */ 10000) != true) {
// Serial.println(F("failed to connect to SGP 40 , please check the wiring"));
// delay(1000);
// }
//Serial.println("sgp40 initialized successfully!");
// Defined in thingProperties.h
initProperties();// init IoT Cloud Properties
// Connect to Arduino IoT Cloud
ArduinoCloud.begin(ArduinoIoTPreferredConnection); //Begin Connection to Arduino Cloud.
/*
The following function allows you to obtain more information
related to the state of network and IoT Cloud connection and errors
the higher number the more granular information you’ll get.
The default is 0 (only errors).
Maximum is 4
*/
setDebugMessageLevel(4);
ArduinoCloud.printDebugInfo(); // Send debug info to Arduino cloud.
}
void loop() {
ArduinoCloud.update(); // Update arduino cloud variables.
unsigned long millisCounter = millis(); // counter
//Serial.println(F("looping..."));
VOCIndex = mySgp40.getVoclndex(); // set VOC index to SGP 40 sensor value.
if (schedule.isActive()) {
// turn air purifier on
}
if (VOCIndex >= VOCAlert && VOC_alertToggleSwitch == true || pitch != 805) { // checks if VOC level is higher then VOC Alert level
UpdateSpeakerPitch();// sound alert.
} else {
noTone(speakerPin);
}
}
/*
Since FanSpeedLevel is READ_WRITE variable, onFanSpeedLevelChange() is
executed every time a new value is received from IoT Cloud.
*/
void onFanSpeedLevelChange() {
// Add your code here to act upon FanSpeedLevel change
Serial.println("fanSpeedLevel = ");
Serial.println(fanSpeedLevel);
if (fanSpeedLevel <= 4) {
if (fanSpeedLevel == 0) {
// Turn of air purifier
//send turbo code
sendNEC(IR_SEND_PIN, IRcodes[4].address, IRcodes[4].command, sRepeats);
delay(1000);
fanLDRvalue = analogRead(LDRinputPin);
if (fanLDRvalue >= fanLDRbrightnessTrigger) {
sendNEC(IR_SEND_PIN, IRcodes[1].address, IRcodes[1].command, sRepeats); // send IR code for power on/ off
Serial.println(F("Sending power Code"));
delay(1000);
}
} else {
//send turbo
sendNEC(IR_SEND_PIN, IRcodes[4].address, IRcodes[4].command, sRepeats);
Serial.println(F("Sending turbo Code line 187"));
delay(1000);
//int fanSigNumber = 4 - fanSpeedLevel;
fanLDRvalue = analogRead(LDRinputPin);
if (fanLDRvalue >= fanLDRbrightnessTrigger) {
sendNEC(IR_SEND_PIN, IRcodes[1].address, IRcodes[1].command, sRepeats); // send IR code for power on/ off
Serial.println(F("Sending power Code"));
delay(1000);
}
for (int fanSigNumber; fanSigNumber <= 4 - fanSpeedLevel; fanSigNumber++) {
sendNEC(IR_SEND_PIN, IRcodes[3].address, IRcodes[3].command, sRepeats); // send IR code for lower fan speed
Serial.println(F("Sending lower fan speed Code"));
Serial.println(fanSigNumber);
delay(1000);
}
}
} else if (fanSpeedLevel == 5) {
// do built in auto mode
//send turbo
sendNEC(IR_SEND_PIN, IRcodes[4].address, IRcodes[4].command, sRepeats);
Serial.println(F("Sending turbo Code"));
delay(1000);
fanLDRvalue = analogRead(LDRinputPin);
if (fanLDRvalue >= fanLDRbrightnessTrigger) {
sendNEC(IR_SEND_PIN, IRcodes[1].address, IRcodes[1].command, sRepeats); // send IR code for power on/ off
Serial.println(F("Sending power Code"));
delay(1000);
}
sendNEC(IR_SEND_PIN, IRcodes[5].address, IRcodes[5].command, sRepeats); // send IR code for Built in auto mode
Serial.println(F("Sending Auto Code"));
delay(1000);
}
}
void UpdateSpeakerPitch() {
if ((millis() - lastUpdate) > updateInterval) // time to update
{
lastUpdate = millis();
pitch += increment;
tone(speakerPin, pitch);
//Serial.println(pitch);
if ((pitch >= 900) || (pitch <= 800)) // tone boundaries.
{
// reverse pitch direction
increment = -increment;
}
}
}
int playing = 0;
void tone(byte pin, int freq) {
ledcSetup(0, 2000, 8); // setup beeper
ledcAttachPin(pin, 0); // attach beeper
ledcWriteTone(0, freq); // play tone
playing = pin; // store pin
}
void noTone() {
tone(playing, 0);// Stop tone
}
/*
Everything under here is the unused onVARIABLE_NAMEChange() functions
I have not used these functions.
It is possible that I may use them in the future.
Since Schedule is READ_WRITE variable, onScheduleChange() is
executed every time a new value is received from IoT Cloud.
*/
void onScheduleChange() {
//No code is needed here
// Add your code here to act upon Schedule change
}
This are the section that you will need to change.
My Air purifier has these modes:
- Built in auto mode
- Fan speed 1
- Fan speed 2
- Fan Speed 3
- Fan Speed 4
My remote has these buttons:
- Auto
- Increase fan speed
- Decrease fan speed
- Turbo
- Power
Sorry, but I can’t really provide guidance on how to edit the code to your Air Purifier. I don’t have time(Deadline at midnight Fri Jun 16(Today!!!!!)).
/*
Since FanSpeedLevel is READ_WRITE variable, onFanSpeedLevelChange() is
executed every time a new value is received from IoT Cloud.
*/
void onFanSpeedLevelChange() {
// Add your code here to act upon FanSpeedLevel change
Serial.println("fanSpeedLevel = ");
Serial.println(fanSpeedLevel);
if (fanSpeedLevel <= 4) {
if (fanSpeedLevel == 0) {
// Turn of air purifier
//send turbo code
sendNEC(IR_SEND_PIN, IRcodes[4].address, IRcodes[4].command, sRepeats);
delay(1000);
fanLDRvalue = analogRead(LDRinputPin);
if (fanLDRvalue >= fanLDRbrightnessTrigger) {
sendNEC(IR_SEND_PIN, IRcodes[1].address, IRcodes[1].command, sRepeats); // send IR code for power on/ off
Serial.println(F("Sending power Code"));
delay(1000);
}
} else {
//send turbo
sendNEC(IR_SEND_PIN, IRcodes[4].address, IRcodes[4].command, sRepeats);
Serial.println(F("Sending turbo Code line 187"));
delay(1000);
//int fanSigNumber = 4 - fanSpeedLevel;
fanLDRvalue = analogRead(LDRinputPin);
if (fanLDRvalue >= fanLDRbrightnessTrigger) {
sendNEC(IR_SEND_PIN, IRcodes[1].address, IRcodes[1].command, sRepeats); // send IR code for power on/ off
Serial.println(F("Sending power Code"));
delay(1000);
}
for (int fanSigNumber; fanSigNumber <= 4 - fanSpeedLevel; fanSigNumber++) {
sendNEC(IR_SEND_PIN, IRcodes[3].address, IRcodes[3].command, sRepeats); // send IR code for lower fan speed
Serial.println(F("Sending lower fan speed Code"));
Serial.println(fanSigNumber);
delay(1000);
}
}
} else if (fanSpeedLevel == 5) {
// do built in auto mode
//send turbo
sendNEC(IR_SEND_PIN, IRcodes[4].address, IRcodes[4].command, sRepeats);
Serial.println(F("Sending turbo Code"));
delay(1000);
fanLDRvalue = analogRead(LDRinputPin);
if (fanLDRvalue >= fanLDRbrightnessTrigger) {
sendNEC(IR_SEND_PIN, IRcodes[1].address, IRcodes[1].command, sRepeats); // send IR code for power on/ off
Serial.println(F("Sending power Code"));
delay(1000);
}
sendNEC(IR_SEND_PIN, IRcodes[5].address, IRcodes[5].command, sRepeats); // send IR code for Built in auto mode
Serial.println(F("Sending Auto Code"));
delay(1000);
}
}
Step 7: Upload the codeMake sure that you entered your wifi credentials and device credentials in to the proper spaces in arduino_secrets.h.
Open your cloud sketch from the thing we made earlier and paste every thing in the AutomaticAirPurifier.ini file into the cloud sketch ino file.
Click the green arrow to upload the code.
Note that I used the tinyIRSender sub library of IRremote because it uses less memory(I was running out of it currently using 90% of the FireBeetle's flash memory).
Step 8: WiringUnplug the arduino.
Wire everything together according to the attached schematic.
Check your connections again.
You can also check for short circuits with a DMM, if you want.
Don’t let any of the components legs touch each other.
Sorry if the schematic is very ugly, it's my first!
Feedback: https://forum.arduino.cc/t/schematic-review-is-this-schematic-okay/1136072
Step 9: Testing the Cloud ConnectionPlug the Arduino back in.
Test if it connect by going to cloud.arduino.cc/home/
Then go to devices and see if your device says it is online.
Open the Serial monitor and set it to Forgot baud rate.
If you see these messages, you’re good!
Messages:
Coming soon.
Step 10: Make the DashboardCreate a new dashboard and add widgets and link the widgets to your variables.
I have Graph, Value Selector , Gauge, and scheduler(Work in progress for this project) widgets.
Make a Gauge widget.
Make a Value Selector widget.
Link it to the FanSpeedLevel.
Enter the following settings.
Please note that the modes “Auto” and “BI Auto” are not finished.
- Scheduler.
- Auto mode.
Flaws:
- Used pin as supply for IR LED.
- Used Non-blocking code in code(onFanSpeedLevelChange(will fix)).
- The code I used for controlling the air purifier might not work with other Air Purifiers because my remote has a ”turbo“ button.
Improvements:
- 3d printed case(I don’t have a 3d printer, and I am horrible at 3d design)
- More photos.
- Proper schematic(looking into KiCAD)
- e-ink or TFT display.
- HomeKit or Home Assistant support(will take a longgggg time).
- More sensors, eg co2 sensor, gas sensor, smoke sensor, temp and humidity sensors.
- A second “thing“ that can be used to display the voc index.
- RGB LED for signaling.
- Display. Maybe TFT or Eink?
- Better board with more memory(ESP32?)
- Better code.
- Speak the VOC level(talkie?)
- GitHub Repo.
- Add your suggestions in the comments, please note that I don't have the money/time/skills/want to make all these improvements. But, if you make a improved version let me know in the comments, I will add the link to the project.
Coming soon.
Debugging:- Have you entered the proper credentials into the Arduino_secrets.h? No extra spaces at the end?
- Have you installed ALL the libraries needed?
- Have you installed the CH340 driver properly?
- Are you using the correct USB port?
- Do you have the ESP32 core installed?
- Have you selected the proper board?
- Check you wiring.
- Check everything again.
- Check out Arduino's trouble shooting tips: https://docs.arduino.cc/learn/starting-guide/troubleshooting-sketches
- Ask your question on forum.arduino.cc . Don’t post your device and WiFi credentials.
- Report bugs in the comments.
- If you have a solution for a bug please attach it.
- Does the code have enough comments?
- Is there a better way to code this program?
- Is there a better circuit?
Please note
If you would like to contribute to this project you can help by doing the following:
- Liking this project
- Give the code a upgrade(GitHub repo coming soon).
- Add new features.
- Provide feedback about this project in the comments.
Thanks.
Comments