#include <Wire.h>
#include <DHT.h>
#include "HX711.h"
#include <LCD_I2C.h> // Include library LCD_I2C by BlackHack
#include <math.h>
#include <EEPROM.h>
#include "DFRobot_ENS160.h" // Librería para ENS160
#include "Adafruit_AHTX0.h" // Librería para AHT21
LCD_I2C lcd(0x27, 16, 2); // Default address of most PCF8574 modules, change according
// Inicializar el sensor ENS160
DFRobot_ENS160_I2C ens160(&Wire, 0x53); // Dirección I2C por defecto para ENS160 (0x53)
// Inicializar el sensor AHT21 (AHTX0)
Adafruit_AHTX0 aht;
#define useCO2 1
#define CALWEIGHT 1.00 // Set known value for calibration (In Kg 1.0 = 1000 gram)
#define LB2KG 0.45352 // Conversion factor of Lbs to Kg
#define DEFAULT_CALIFACTOR -7050
#define number_of_digits 2
unsigned long lcdUpdateTime = 5000; // Lcd update time for next sensor value
unsigned long lastLCDUpdateTime = millis() - lcdUpdateTime; // variable to hold last lcd update time
// Variables to hold sensor data values
int hIn = 0;
float tIn = 0; // or dhtIn.readTemperature(true) for Fahrenheit
int hOut = 0;
float tOut = 0; // or dhtIn.readTemperature(true) for Fahrenheit
int soundValue = 0; // Variable to hold sound sensor value
float peso = 0.0; // variable to hold weight sensor
int co2Value = 0; // read CO2 value
int tvocValue = 0; // Read TVOC value
// Pins Definition
#define DHTPINin 2 // What digital pin we're connected to
const byte soundSensorPin = A0; // Pin analógico del sensor de sonido
const byte DOUT_PIN = 4; // Pin digital conectado a DOUT del módulo HX711
const byte SCK_PIN = 5; // Pin digital conectado a SCK del módulo HX711
#define calibrationBtnPin 3 // Scale calibration button pin
HX711 scale;
long currentOffset;
float calibration_factor;
// Uncomment whatever type you're using!
#define DHTTYPEin DHT22 // DHT 22 for inside temperature
DHT dhtIn(DHTPINin, DHTTYPEin);
int displayCount = 0; // variable to hold display count
void setup() {
Serial.begin(9600);
Wire.begin(); // Iniciar el bus I2C
pinMode(soundSensorPin, INPUT); // Set sound sensor pin as input
dhtIn.begin(); // Initialize DHT in sensor
lcd.begin(); // If you are using more I2C devices using the Wire library use lcd.begin(false)
// this stop the library(LCD_I2C) from calling Wire.begin()
lcd.backlight();
pinMode(calibrationBtnPin, INPUT_PULLUP);
// eeprom
if (EEPROM.read(0x00) != 0x01) {
Serial.println("NOT INIT !!!!");
currentOffset = 0;
calibration_factor = DEFAULT_CALIFACTOR;
// show instructions
displayMessage(0, 0, "MUST CALIBIRATE", HIGH);
displayMessage(0, 1, "Press Calib BTn");
lcd.clear();
delay(2000); // wait for 2 seconds
} else {
EEPROM.get(0x01, currentOffset);
EEPROM.get(0x01 + sizeof(long), calibration_factor);
Serial.println("currentOffset = " + String(currentOffset));
Serial.println("calibration_factor = " + String(calibration_factor));
}
//scale
scale.begin(DOUT_PIN, SCK_PIN);
delay(100);
Serial.println("calibration_factor = " + String(calibration_factor));
scale.set_scale(calibration_factor / LB2KG);
scale.set_offset(currentOffset); // Apply saved offset value
Serial.println("setup done ...");
delay(1000);
// Inicializar el sensor ENS160
if (ens160.begin() != 0) {
Serial.println("Error al iniciar el sensor ENS160. Verifica las conexiones.");
displayMessage(0, 0, "ENS160 Error");
delay(1000);
// while (1); // Detiene el programa si falla la inicialización
}
Serial.println("Sensor ENS160 iniciado correctamente.");
// Inicializar el sensor AHT21
if (!aht.begin()) {
Serial.println("Error al iniciar el sensor AHT21. Verifica las conexiones.");
displayMessage(0, 0, "AHT Error");
delay(1000);
// while (1); // Detiene el programa si falla la inicialización
}
Serial.println("Sensor AHT21 iniciado correctamente.");
}
void loop() {
// if calibrationBtnPin is pressed (LOW) start calibiration
if (digitalRead(calibrationBtnPin) == LOW) {
performCalibration();
}
if ((millis() - lastLCDUpdateTime) > lcdUpdateTime) {
lastLCDUpdateTime = millis(); // Note current lcd update time
switch (displayCount) {
case 0:
displayHumidityTemp(); // Display humidity and temperature values
break;
case 1:
displaySoundWight(); // Display sound and weight value
break;
case 2:
readCO2Sensor(); // Display CO2 sensor value
break;
default:
break;
}
displayCount++; // Increase counter
displayCount = (displayCount > 2) ? 0 : displayCount;
}
}
void readCO2Sensor() {
// Read CO2 sensor data
// ens160.update();
co2Value = ens160.getECO2(); // read CO2 value
tvocValue = ens160.getTVOC(); // Read TVOC value
Serial.print("CO2: ");
Serial.print(co2Value);
Serial.print("ppm, TVOC: ");
Serial.print(tvocValue);
Serial.println("ppb");
displayMessage(0, 0, "CO2 Value:", HIGH);
displayMessage(10, 0, co2Value);
lcd.print(" ppm ");
displayMessage(0, 1, "TVOC Value:", LOW);
displayMessage(12, 1, tOut);
lcd.print(" ppb ");
}
void displaySoundWight() {
// Read sound sensor and Weight sensor
// Lectura del sensor de sonido
int soundValue = analogRead(soundSensorPin);
Serial.print("Nivel de sonido: ");
Serial.println(soundValue);
// Lectura de peso
// get data
double data = abs(scale.get_units());
// issue with abs missing at the 4th digit after the dot (bug!!)
if (0.0000 - data > 0.0001)
data = 0.00; //reset to zero
// serial
Serial.print(data, number_of_digits);
Serial.println(" Kg");
displayMessage(0, 0, "Sound:", HIGH);
displayMessage(6, 0, soundValue);
displayMessage(0, 1, "Weight:", LOW);
lcd.setCursor(8, 1);
lcd.print(data, number_of_digits);
}
void displayHumidityTemp() {
// Read inside dht sensor and display on lcd
hIn = dhtIn.readHumidity();
tIn = dhtIn.readTemperature(); // or dhtIn.readTemperature(true) for Fahrenheit
if (isnan(hIn) || isnan(tIn)) {
Serial.println("Failed to read from Inside DHT sensor!");
hIn = 0;
tIn = 0;
}
displayMessage(0, 0, "Humidity In:", HIGH);
displayMessage(12, 0, hIn);
displayMessage(15, 0, "% ", LOW);
displayMessage(0, 1, "Temp In:", LOW);
displayMessage(9, 1, tIn);
displayMessage(15, 1, "C ", LOW);
lcd.print(" *C ");
delay(lcdUpdateTime);
// Obtener temperatura y humedad del AHT21
sensors_event_t humidity, temp;
aht.getEvent(&humidity, &temp); // Obtener datos de temperatura y humedad
// display outside temperature
hOut = humidity.relative_humidity;
tOut = temp.temperature; // or dhtIn.readTemperature(true) for Fahrenheit
Serial.print("Inside Temp:");
Serial.print(tIn);
Serial.print(" | Humidity:");
Serial.print(hIn);
Serial.print(" | Outside Temp:");
Serial.print(tOut);
Serial.print(" | Humidity:");
Serial.println(hOut);
if (isnan(hOut) || isnan(tOut)) {
Serial.println("Failed to read from Outside DHT sensor!");
hOut = 0;
tOut = 0;
}
displayMessage(0, 0, "Humidity Out:", HIGH);
displayMessage(12, 0, hOut);
displayMessage(15, 0, "% ", LOW);
displayMessage(0, 1, "Temp Out:", LOW);
displayMessage(9, 1, tOut);
displayMessage(15, 1, "C", LOW);
}
void displayMessage(int x, int y, const String& msg, bool clearScreen) {
// This function will receive cursor x, y position and message to display and a flag to clear previous display or not
if (clearScreen) { // If clear screen flag is high clear lcd
lcd.clear();
delay(500); // Wait for 500 seconds
}
lcd.setCursor(x, y); // Set cursor at x, y position
lcd.print(msg); // Print msg on lcd
}
void performCalibration() {
// show instructions
displayMessage(0, 0, "Clear Scale", HIGH);
displayMessage(0, 1, "Press Cal Button", LOW);
// wait till person leaves the calibrationBtnPin
while (!digitalRead(calibrationBtnPin))
;
//short delay
delay(500);
// set tare and save value
scale.tare();
currentOffset = scale.get_offset();
Serial.println(currentOffset);
// show on lcd
lcd.clear();
lcd.print("Place ");
lcd.print(CALWEIGHT);
lcd.print(" Kg");
displayMessage(0, 1, "Press Cal Button", LOW);
//wait for calibrationBtnPin press
while (digitalRead(calibrationBtnPin))
;
delay(500);
displayMessage(0, 0, "Calibration Start");
displayMessage(2, 1, "Wait");
Serial.println("calibirte");
// calibiation
boolean done = false;
uint8_t flipDirCount = 0;
int8_t direction = 1;
uint8_t dirScale = 100;
double data = abs(scale.get_units());
double prevData = data;
char runningSign[] = { '-', '\\', '|', '/' };
uint8_t runningSignIdx = 0;
while (!done) {
// get data
data = abs(scale.get_units());
Serial.println("data = " + String(data, 2));
Serial.println("abs = " + String(abs(data - CALWEIGHT), 4));
Serial.println("calibration_factor = " + String(calibration_factor));
// if not match
if (abs(data - CALWEIGHT) >= 0.01) {
if (abs(data - CALWEIGHT) < abs(prevData - CALWEIGHT) && direction != 1 && data < CALWEIGHT) {
direction = 1;
flipDirCount++;
} else if (abs(data - CALWEIGHT) >= abs(prevData - CALWEIGHT) && direction != -1 && data > CALWEIGHT) {
direction = -1;
flipDirCount++;
}
if (flipDirCount > 2) {
if (dirScale != 1) {
dirScale = dirScale / 10;
flipDirCount = 0;
Serial.println("dirScale = " + String(dirScale));
}
}
// set new factor
calibration_factor += direction * dirScale;
scale.set_scale(calibration_factor / LB2KG);
// show still running
lcd.setCursor(15, 1);
lcd.print(runningSign[runningSignIdx]);
runningSignIdx = (runningSignIdx + 1) % 4;
//short delay
delay(5);
// keep old data
prevData = data;
}
// if match
else {
Serial.println("NEW currentOffset = " + String(currentOffset));
Serial.println("NEW calibration_factor = " + String(calibration_factor));
EEPROM.put(0x00, 0x01); // set init
EEPROM.put(0x01, currentOffset);
EEPROM.put(0x01 + sizeof(long), calibration_factor);
done = true;
lcd.clear();
}
displayMessage(0, 0, "Calibration Done", HIGH);
delay(2000); // wait for 2 second
lcd.clear(); // clear display
} // end while
scale.set_offset(currentOffset);
displayCount = 0;
lastLCDUpdateTime = lastLCDUpdateTime - lcdUpdateTime;
delay(50);
}
void displayMessage(int x, int y, int value) { // This function will receive cursor x, y position and integer value to display
lcd.setCursor(x, y); // Set cursor at x, y position
lcd.print(value); // Print msg on lcd
lcd.print(" "); // Remove any extra value
}
void displayMessage(int x, int y, float value) { // This function will receive cursor x, y position and integer value to display
lcd.setCursor(x, y); // Set cursor at x, y position
lcd.print(value); // Print msg on lcd
lcd.print(" "); // Remove any extra value
}