#include "DHT.h"
#include <ESP32Servo.h>
#include <ThingSpeak.h>
#include <WiFi.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Adafruit_ILI9341.h>
#include <Arduino.h>
#include <Adafruit_FT6206.h>
#include <Adafruit_NeoPixel.h>
#include <map>
#include <cmath>
using namespace std;
#define NUMPIXELS 16
#define NEO_PIN 14
Adafruit_NeoPixel pixels(NUMPIXELS, NEO_PIN, NEO_GRB + NEO_KHZ800);
#define TFT_DC 12
#define TFT_CS 13
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
Adafruit_FT6206 ts = Adafruit_FT6206();
int brightnessBarY = 40;
int redBarY = 90;
int greenBarY = 130;
int blueBarY = 170;
String bar;
int R,G,B,BRIGHT;
boolean tolerateFirstOutBound = false;
int red[8],green[8],blue[8];
std::map<string, string> bin_hex;
//wifi details
const char* WIFI_NAME = "Wokwi-GUEST";
const char* WIFI_PASS = "";
WiFiClient client;
//thingspeak details
const int myChannelNumber = 2544553;
const char* write_API_Key = "RJVPD5U00E5XJQHL";
const char* server = "api.thingspeak.com";
// variables globales
float humd;
float temp;
int potValue;
float lux_a;
int brightness;
int humdAngle;
int potAngle;
// Déclaration des constantes pour les seuils de luminosité
const int DARK = 200;
const int LIGHT = 600;
const int BRIGHT = 1000;
// Déclaration des broches pour les composants
#define PIN_RED 12
#define PIN_GREEN 14
#define PIN_BLUE 27
#define digital_In 33
#define analog_In 35
#define POT_PIN 36
#define SERVO_PIN 32
#define DHT_PIN 13
//Seuil CO2 (Scenario 1)
const int CO2_UNDER_7500 = 45;
const int CO2_UNDER_10000 = 90;
const int CO2_UNDER_15000 = 135;
//Seuil humidité
const int HUMD_UNDER_50 = 45;
const int HUMD_UNDER_60 = 90;
const int HUMD_UNDER_70 = 135;
//Seuil temperature (Scenario 2)
const int SEUIL_TEMP = 23;
// Déclaration des objets
DHT dht(DHT_PIN, DHT22);
Servo servo;
// Déclaration du tableau de broches LED
const int ledCount = 10;
int ledPins[] = {21, 19, 18, 5, 17, 16, 4, 0, 2, 15};
// L'angle d'ouvertures courante du servo
int CURRENT_ANGLE = 0;
void setup() {
Serial.begin(115200);
// WiFi and ThingSpeak setup
WiFi.begin(WIFI_NAME, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED){
delay(1000);
Serial.println("Wifi not connected");
}
Serial.println("Wifi connected !");
Serial.println("Local IP: " + String(WiFi.localIP()));
WiFi.mode(WIFI_STA);
ThingSpeak.begin(client);
//Initialisation des composants
dht.begin();
servo.attach(SERVO_PIN);
servo.write(0);
//Configuration des entrées et sorties
pinMode(POT_PIN, INPUT);
pinMode(PIN_RED, OUTPUT);
pinMode(PIN_GREEN, OUTPUT);
pinMode(PIN_BLUE, OUTPUT);
pinMode(digital_In, INPUT);
pinMode(analog_In, INPUT);
for (int thisLed = 0; thisLed < ledCount; thisLed++) {
pinMode(ledPins[thisLed], OUTPUT);
}
//lcd
bin_hex["0000"] = "0";
bin_hex["0001"] = "1";
bin_hex["0010"] = "2";
bin_hex["0011"] = "3";
bin_hex["0100"] = "4";
bin_hex["0101"] = "5";
bin_hex["0110"] = "6";
bin_hex["0111"] = "7";
bin_hex["1000"] = "8";
bin_hex["1001"] = "9";
bin_hex["1010"] = "A";
bin_hex["1011"] = "B";
bin_hex["1100"] = "C";
bin_hex["1101"] = "D";
bin_hex["1110"] = "E";
bin_hex["1111"] = "F";
pixels.begin();
tft.begin();
ts.begin();
tft.setRotation(1);
tft.setTextSize(2);
display();
R = 255;
G = 255;
B = 255;
BRIGHT = 255;
pixels.setBrightness(BRIGHT);
delay(2000);
}
void ouvrirServo(int angle) {
for (int i = 0; i <= angle; i++) {
servo.write(CURRENT_ANGLE + i);
delay(15);
}
}
void fermerServo(int angle) {
for (int i = 0; i <= angle; i++) {
servo.write(CURRENT_ANGLE - i);
delay(15);
}
}
void angleFromPot() {
//lire valeur du potentiometre
potValue = analogRead(POT_PIN);
potValue = map(potValue, 0, 4095, 0, 17000);
Serial.print("CO2 :");
Serial.println(potValue);
//choisir l'angle d'ouverture de la fenetre
int angle = 0;
if (potValue < 400) {
angle = 0;
Serial.println("CO2 concentration below 400ppm, close window");
} else if (potValue < 7500) {
angle = CO2_UNDER_7500;
Serial.print("CO2 concentration below 7500ppm, open window by ");
Serial.println(CO2_UNDER_7500);
} else if (potValue < 10000) {
angle = CO2_UNDER_10000;
Serial.print("CO2 concentration below 10000ppm, open window by ");
Serial.println(CO2_UNDER_10000);
} else if (potValue < 15000) {
angle = CO2_UNDER_15000;
Serial.print("CO2 concentration below 15000ppm, open window by ");
Serial.println(CO2_UNDER_15000);
} else {
Serial.println("CO2 concentration over 15000ppm, open window fully");
angle = 180;
}
potAngle= angle;
}
void angleFromDht(){
humd = dht.readHumidity();
//choisir l'angle d'ouverture de la fenetre
int angle = 0;
if(humd < 40){
angle = 0;
Serial.println("Humidity below 40%, close window");
}else if(humd < 50){
angle = HUMD_UNDER_50;
Serial.print("Humidity below 50%, open window by ");
Serial.println(HUMD_UNDER_50);
}else if(humd < 60){
angle = HUMD_UNDER_60;
Serial.print("Humidity below 60%, open window by ");
Serial.println(HUMD_UNDER_60);
}else if(humd < 70){
angle = HUMD_UNDER_70;
Serial.print("Humidity below 70%, open window by ");
Serial.println(HUMD_UNDER_70);
}else{
Serial.println("Humidity over 70%, open window fully");
angle = 180;
}
humdAngle=angle;
}
void fenetre(){
//angle d'ouverture selon concentration CO2
angleFromPot();
//angle d'ouverture selon l'humidite
angleFromDht();
int angle = max(potAngle, humdAngle);
//changer l'angle d'ouverture du servo
int difference = CURRENT_ANGLE - angle;
if(difference < 0){
ouvrirServo(abs(difference));
}else{
fermerServo(difference);
}
CURRENT_ANGLE = angle;
}
void climatiseur(){
temp = dht.readTemperature();
if(isnan(temp)){
Serial.println(F("Failed to read Temperature"));
}else{
Serial.print("Current temperature is ");
Serial.print(temp);
Serial.print(" °C, ");
if(temp > SEUIL_TEMP){
Serial.println("bigger then threshold (23 °C) => Cooling");
analogWrite(PIN_RED, 0);
analogWrite(PIN_GREEN, 0);
analogWrite(PIN_BLUE, 255);
}else{
Serial.println("smaller then threshold (23 °C) => Heating");
analogWrite(PIN_RED, 255);
analogWrite(PIN_GREEN, 0);
analogWrite(PIN_BLUE, 0);
}
}
}
void luminosite() {
int analogValue = analogRead(analog_In);
float voltage = analogValue / 4096.0 * 5.0;
float resistance = 2000.0 * voltage / (1.0 - voltage / 5.0);
lux_a = pow(50.0 * 1000.0 * pow(10.0, 0.7) / resistance, 1.0 / 0.7);
Serial.print("Analog: Lux ");
Serial.println(lux_a);
// Allumer les LED en fonction de la luminosité
if (lux_a <= DARK) {
Serial.println("Dark");
for (int i = 0; i < 4; i++) {
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[1], LOW);
digitalWrite(ledPins[2], LOW);
digitalWrite(ledPins[3], LOW);
brightness =0;
}
} else if (lux_a > DARK && lux_a <= LIGHT) {
Serial.println("Light");
for (int i = 0; i < 4; i++) {
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[1], HIGH);
digitalWrite(ledPins[2], LOW);
digitalWrite(ledPins[3], LOW);
brightness =1;
}
} else if (lux_a > LIGHT && lux_a <= BRIGHT) {
Serial.println("Bright");
for (int i = 0; i < 4; i++) {
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[1], HIGH);
digitalWrite(ledPins[2], HIGH);
digitalWrite(ledPins[3], LOW);
brightness = 2;
}
} else {
Serial.println("Very Bright");
for (int i = 0; i < 4; i++) {
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[1], HIGH);
digitalWrite(ledPins[2], HIGH);
digitalWrite(ledPins[3], HIGH);
brightness =2;
}
}
}
void loop() {
//1. Scénario : CO2 élevé
fenetre();
//2. Scénario : Température
climatiseur();
//3. Scénario : Luminosité
luminosite();
sendDataToThingSpeak();
if(ts.touched()){
barClicked();
if(bar=="red"){
modulateRed();
}else if(bar=="green"){
modulateGreen();
}else if(bar=="blue"){
modulateBlue();
}else if(bar=="brightness"){
modulateBrightness();
}
bar = "";
}
tolerateFirstOutBound = false;
lightLamp();
delay(15000);
}
void sendDataToThingSpeak(){
ThingSpeak.setField(1,temp);
delay(500);
ThingSpeak.setField(2,humd);
delay(500);
ThingSpeak.setField(3, potValue);
delay(500);
ThingSpeak.setField(4, brightness);
int writeResult = ThingSpeak.writeFields(myChannelNumber,write_API_Key);
if(writeResult == 200){
Serial.println("Data pushed successfull");
}else{
Serial.println("Push error" + String(writeResult));
}
Serial.println("---");
}
void barClicked(){
TS_Point p = ts.getPoint();
p.x = ::map(p.x, 0, 240, 240, 0);
p.y = ::map(p.y, 0, 320, 320, 0);
int x = tft.width() - p.y;
int y = p.x;
int redY = redBarY-3;
int greenY = greenBarY-3;
int blueY = blueBarY-3;
int brightnessY = brightnessBarY-3;
/*
Adding an error margin in case the cursor missed the bar by 3px up and down
3px(up) + 3px(down) + 6px(bar height) = 12px
*/
for(int i = 0; i < 12 ; i++){
++redY;
++greenY;
++blueY;
++brightnessY;
if(redY == y){
bar = "red";
}else if(greenY == y){
bar = "green";
}else if(blueY == y){
bar = "blue";
}else if(brightnessY == y){
bar = "brightness";
}
}
}
void display(){
brightnessInput();
redInput();
greenInput();
blueInput();
displayColorOnScreen();
}
void brightnessInput(){
tft.setCursor(90,10);
tft.setTextColor(ILI9341_WHITE);
tft.println("Brightness");
tft.fillRect(0, brightnessBarY, 300, 6,ILI9341_WHITE);
}
void redInput(){
tft.setCursor(0, 70);
tft.setTextColor(ILI9341_RED);
tft.println("RED");
tft.fillRect(0, redBarY, 300, 6, ILI9341_RED);
}
void greenInput(){
tft.setCursor(0, 110);
tft.setTextColor(ILI9341_GREEN);
tft.println("GREEN");
tft.fillRect(0, greenBarY, 300, 6, ILI9341_GREEN);
}
void blueInput(){
tft.setCursor(0, 150);
tft.setTextColor(ILI9341_BLUE);
tft.println("BLUE");
tft.fillRect(0, blueBarY, 300, 6, ILI9341_BLUE);
}
void displayColorOnScreen(){
tft.setCursor(0, 200);
tft.setTextColor(ILI9341_WHITE);
tft.println("Led Color");
tft.fillRoundRect(120, 193, 188, 30, 5, ILI9341_WHITE);
}
void modulateRed(){
while(ts.touched()){
TS_Point p = ts.getPoint();
p.y = ::map(p.y, 0, 320, 320, 0);
int x = tft.width() - p.y;
int X_axis = x;
x = ::map(x, 0, 300, 0, 255);
if(x >255){
x = 255;
}
R = x;
lightLamp();
updateRedBar(X_axis);
updateColorOnScreen();
}
}
void updateRedBar(int x){
if(x <= 300){
tft.fillRect(0, 90, 300, 6, ILI9341_BLACK);
tft.fillRect(0, 90, x, 6, ILI9341_RED);
}else if(!tolerateFirstOutBound){
tolerateFirstOutBound = true;
tft.fillRect(0, 90, 300, 6, ILI9341_BLACK);
tft.fillRect(0, 90, 300, 6, ILI9341_RED);
}
}
void modulateGreen(){
while(ts.touched()){
TS_Point p = ts.getPoint();
p.y = ::map(p.y, 0, 320, 320, 0);
int x = tft.width() - p.y;
int X_axis = x;
x = ::map(x, 0, 300, 0, 255);
if(x >255){
x = 255;
}
G = x;
lightLamp();
updateGreenBar(X_axis);
updateColorOnScreen();
}
}
void updateGreenBar(int x){
if(x <= 300){
tft.fillRect(0, 130, 300, 6, ILI9341_BLACK);
tft.fillRect(0, 130, x, 6, ILI9341_GREEN);
}else if(!tolerateFirstOutBound){
tolerateFirstOutBound = true;
tft.fillRect(0, 130, 300, 6, ILI9341_BLACK);
tft.fillRect(0, 130, 300, 6, ILI9341_GREEN);
}
}
void modulateBlue(){
while(ts.touched()){
TS_Point p = ts.getPoint();
p.y = ::map(p.y, 0, 320, 320, 0);
int x = tft.width() - p.y;
int X_axis = x;
x = ::map(x, 0, 300, 0, 255);
if(x >255){
x = 255;
}
B = x;
updateBlueBar(X_axis);
updateColorOnScreen();
lightLamp();
}
}
void updateBlueBar(int x){
if(x <= 300){
tft.fillRect(0, 170, 300, 6, ILI9341_BLACK);
tft.fillRect(0, 170, x, 6, ILI9341_BLUE);
}else if(!tolerateFirstOutBound){
tolerateFirstOutBound = true;
tft.fillRect(0, 170, 300, 6, ILI9341_BLACK);
tft.fillRect(0, 170, 300, 6, ILI9341_BLUE);
}
}
void modulateBrightness(){
while(ts.touched()){
TS_Point p = ts.getPoint();
p.y = ::map(p.y, 0, 320, 320, 0);
int x = tft.width() - p.y;
int X_axis = x;
x = ::map(x, 0, 300, 0, 255);
if(x >255){
x = 255;
}
BRIGHT = x;
updateBrightnessBar(X_axis);
updateColorOnScreen();
pixels.setBrightness(BRIGHT);
}
}
void updateBrightnessBar(int x){
if(x <= 300){
tft.fillRect(0, 40, 300, 6, ILI9341_BLACK);
tft.fillRect(0, 40, x, 6, ILI9341_WHITE);
}else if(!tolerateFirstOutBound){
tolerateFirstOutBound = true;
tft.fillRect(0, 40, 300, 6, ILI9341_BLACK);
tft.fillRect(0, 40, 300, 6, ILI9341_WHITE);
}
}
void updateColorOnScreen(){
decimalToBinary(R, red);
decimalToBinary(G, green);
decimalToBinary(B, blue);
int color[16];
int counter = -1;
for(int i= 3;i < 8;i++){
color[++counter] = blue[i];
}
for(int i=2;i < 8;i++){
color[++counter] = green[i];
}
for(int i= 3;i < 8;i++){
color[++counter] = red[i];
}
uint16_t finalColor = binarytoDecimal(color);
tft.fillRoundRect(120, 193, 188, 30, 5, finalColor);
}
void lightLamp(){
for (int i = 0; i < NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(R, G, B));
pixels.show();
}
}
void decimalToBinary(int n, int* arr){
int i = 0;
for(int i = 0;i < 8;i++){
if(n >= 1){
arr[i] = n % 2;
n = n/2;
}else{
arr[i] = 0;
}
}
}
uint16_t binarytoDecimal(int *arr){
uint16_t color = 0;
for(int i = 0; i < 16 ; i++){
if(arr[i] == 1){
color += pow(2,i);
}
}
return color;
}