You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

460 lines
12 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Air Quality Monitor
**Air Quality Monitor** is a lightweight web interface that displays real-time data from two environmental sensors: **HTU21D** and **BMP180**. The system uses **NGINX** to serve an HTML page that reads live data from JSON files.
## Project Description
This project was designed to visualize environmental parameters in a simple, fast, and efficient way using an embedded graphical interface. The data is obtained from the following sensors:
- **HTU21D**: Temperature and relative humidity.
- **BMP180**: Atmospheric pressure and temperature.
The data is stored in two JSON files, updated by the embedded system and displayed through an HTML/JavaScript-based frontend.
---
## Project Structure
air-quality-monitor/
├── BMP180.json # Pressure and temperature data from BMP180
├── HTU21D.json # Temperature and humidity data from HTU21D
├── index.html # Main web interface
├── index.js # JavaScript logic to fetch and display JSON data
├── style.css # Custom CSS styles
> The `.json` files are automatically updated by C programs that communicate with the sensors via I2C.
---
## 🚀 Installation & Deployment with NGINX
### Requirements
- Linux server with `nginx` installed.
- Root access or permission to modify NGINX configuration.
### Steps
1. Install NGINX (if not already installed):
```bash
sudo apt update
sudo apt install nginx
```
2. Copy the project files to NGINXs public directory (e.g., /var/www/html):
``` bash
```
3. Redirect the configuration file to our repository folder:
```bash
sudo vi /etc/nginx/sites-available/default
```
4. Replace the line:
```bash
root /var/www/html;
```
with:
```bash
root /home/debian/path/to/your/repository;
```
5. Apply chages with:
```bash
sudo systemctl restart nginx
```
## User interface
This is a simple web page that displays real-time sensor data from two devices:
• BMP180: Shows temperature and pressure.
• HTU21D: Shows humidity and temperature.
Its styled with a separate CSS file (style.css) and fetches live data using JavaScript (index.js), which likely reads values from two JSON files (BMP180.json and HTU21D.json).
### HTML
#### Complete code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Sensor Dashboard</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="background"></div>
<div class="container">
<h1>Sensor Dashboard</h1>
<div class="sensor-card">
<img src="https://cdn-icons-png.flaticon.com/512/1126/1126741.png" alt="Temperature & Pressure Icon">
<h2>BMP180</h2>
<div class="data">
<span id="temperature">Temperature: -- °C</span>
<span id="pressure">Pressure: -- hPa</span>
</div>
</div>
<div class="sensor-card">
<img src="https://cdn-icons-png.flaticon.com/512/728/728093.png" alt="Humidity Icon">
<h2>HTU21D</h2>
<div class="data">
<span id="humidity">Humidity: -- %</span>
<span id="tempHTU">Temperature: -- °C</span>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
```
#### Explanation
```html
<!DOCTYPE html>
<html lang="en">
```
• Declares this document as HTML5.
• lang="en" sets the document language to English, which is useful for accessibility and SEO.
##### HEAD
```html
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Sensor Dashboard</title>
<link rel="stylesheet" href="style.css" />
</head>
```
• charset="UTF-8" ensures proper text encoding.
• viewport makes the layout responsive on mobile devices.
• title is what appears in the browser tab.
• link imports the external CSS file (style.css) for styling.
##### BODY
```html
<body>
<div class="background"></div>
<div class="container">
...
</div>
<script src="index.js"></script>
</body>
```
• The background div might be used for a visual effect like a background image or color gradient (defined in your CSS).
• container holds the main content (dashboard).
• index.js is loaded at the end to ensure the DOM is ready before scripts run.
##### Dashboard Title
```html
<h1>Sensor Dashboard</h1>
```
• This is the main heading of your web page.
##### Sensor Card: BMP180
```hmtl
<div class="sensor-card">
<img src="https://cdn-icons-png.flaticon.com/512/1126/1126741.png" alt="Temperature & Pressure Icon">
<h2>BMP180</h2>
<div class="data">
<span id="temperature">Temperature: -- °C</span>
<span id="pressure">Pressure: -- hPa</span>
</div>
</div>
```
• This block represents the BMP180 sensor.
• The icon (from flaticon.com) visually represents pressure/temperature.
• The id attributes (temperature, pressure) are hooks used by JavaScript to insert real values from BMP180.json.
##### Sensor Card: HTU21D
```html
<div class="sensor-card">
<img src="https://cdn-icons-png.flaticon.com/512/728/728093.png" alt="Humidity Icon">
<h2>HTU21D</h2>
<div class="data">
<span id="humidity">Humidity: -- %</span>
<span id="tempHTU">Temperature: -- °C</span>
</div>
</div>
```
• This block represents the HTU21D sensor.
• The image is a humidity icon.
• The id attributes (humidity, tempHTU) are also updated by JavaScript using HTU21D.json.
##### JavaScript Integration
```hmtl
<script src="index.js"></script>
```
• This line loads your script, which is responsible for:
• Fetching the JSON files.
• Parsing their content.
• Replacing the placeholder values (-- °C, -- hPa, etc.) with live sensor data.
### Index.js
The script fetches data from two local JSON files:
• BMP180.json — contains temperature and pressure.
• HTU21D.json — contains temperature and humidity.
Then it updates the HTML every 3 seconds so the page always shows live sensor values.
#### Full code
```js
function updateBMP180() {
fetch('BMP180.json')
.then(res => res.json())
.then(data => {
document.getElementById('temperature').textContent = `Temperature: ${data.temperature.toFixed(2)} °C`;
document.getElementById('pressure').textContent = `Pressure: ${data.pressure.toFixed(2)} hPa`;
})
.catch(err => console.error("Error BMP180:", err));
}
function updateHTU21D() {
fetch('HTU21D.json')
.then(res => res.json())
.then(data => {
document.getElementById('humidity').textContent = `Humidity: ${data.humidity.toFixed(1)} %`;
document.getElementById('tempHTU').textContent = `Temperature: ${data.temperature.toFixed(1)} °C`;
})
.catch(err => console.error("Error HTU21D:", err));
}
setInterval(() => {
updateBMP180();
updateHTU21D();
}, 3000);
// Carga inicial
updateBMP180();
updateHTU21D();
```
### Code explanation
#### Function: updateBMP180
```js
function updateBMP180() {
fetch('BMP180.json')
.then(res => res.json())
.then(data => {
document.getElementById('temperature').textContent = `Temperature: ${data.temperature.toFixed(2)} °C`;
document.getElementById('pressure').textContent = `Pressure: ${data.pressure.toFixed(2)} hPa`;
})
.catch(err => console.error("Error BMP180:", err));
}
```
- This defines a new function named updateBMP180. Youll call this function when you want to update the BMP180 sensor data on the page.
- fetch('BMP180.json'): Loads the JSON file from the same directory.
- .then(res =\>json()): Parses the response as JSON
- .then(data +\> {}): Accesses the data inside the file.
- document.getElementById(...) updates the corresponding <span> elements in your HTML.
#### Function: updateHTU21D
```js
function updateHTU21D() {
fetch('HTU21D.json')
.then(res => res.json())
.then(data => {
document.getElementById('humidity').textContent = `Humidity: ${data.humidity.toFixed(1)} %`;
document.getElementById('tempHTU').textContent = `Temperature: ${data.temperature.toFixed(1)} °C`;
})
.catch(err => console.error("Error HTU21D:", err));
}
```
Works the same way as updateBMP180(), but:
- Fetches from HTU21D.json.
- Displays humidity and temperature.
- Uses .toFixed(1) for 1 decimal place (common for humidity values).
#### Auto-update every 3 seconds
```js
setInterval(() => {
updateBMP180();
updateHTU21D();
}, 3000);
```
- Calls both update functions every 3,000 milliseconds (3 seconds).
- Keeps the UI in sync with new sensor readings, assuming the .json files are being updated continuously.
#### Initial load
```js
updateBMP180();
updateHTU21D();
```
- Ensures the data is shown immediately on page load, before the 3-second interval kicks in.
### CSS
#### Full code
```css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Segoe UI", sans-serif;
}
body, html {
height: 100%;
background-color: #0d1117;
color: #ffffff;
position: relative;
overflow: hidden;
}
.background {
background-image: url('https://wallpapers.com/images/hd/blue-circuit-board-traces-zn0xezd4t8axj9r6.webp');
background-size: cover;
background-position: center;
opacity: 0.1;
filter: blur(3px);
position: absolute;
top: 0; left: 0;
width: 100%;
height: 100%;
z-index: -1;
}
.container {
max-width: 800px;
margin: 40px auto;
background-color: #161b22;
padding: 30px;
border-radius: 20px;
box-shadow: 0 0 30px rgba(0, 255, 255, 0.2);
animation: fadeIn 1s ease-in;
}
h1 {
text-align: center;
margin-bottom: 30px;
font-size: 2.5rem;
color: #58a6ff;
}
.sensor-card {
background-color: #1f2937;
padding: 20px;
border-radius: 15px;
margin-bottom: 20px;
box-shadow: 0 0 20px rgba(100, 255, 255, 0.1);
animation: slideIn 1s ease;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.sensor-card img {
width: 64px;
height: 64px;
margin-bottom: 10px;
}
.sensor-card h2 {
margin-bottom: 10px;
color: #90cdf4;
}
.data span {
display: block;
margin: 5px 0;
font-size: 1.2rem;
color: #ffffff;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes slideIn {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
```
#### Explaining
Global Styling
- *: Resets default browser spacing (margin, padding) and sets a consistent font and box model across the entire page.
- body, html:
- Sets full height layout.
- Applies a dark background (#0d1117) with white text.
- Hides overflow and enables positioning for internal layers.
Background Layer
- .background:
- Adds a faint, blurred circuit board image as the background.
- Uses opacity: 0.1 and filter: blur(3px) to give it a soft tech feel.
- Positioned absolutely behind everything (z-index: -1).
Main Container
- .container:
- A centered, card-like section with:
- A dark background (#161b22)
- Rounded corners and soft glowing shadow.
- Padding and a fade-in animation on load.
Title
- h1:
- Large, centered header in light blue (#58a6ff).
- Styled to stand out at the top of the dashboard.
Sensor Cards
- .sensor-card:
- Styled boxes for each sensor.
- Darker background (#1f2937) with a soft shadow.
- Rounded corners, padding, and a slide-in animation when they load.
- Contents are centered vertically and horizontally.
- .sensor-card img:
- Sensor icons sized to 64×64 pixels with margin for spacing.
- .sensor-card h2:
- Sub-headers for each sensor card in a soft blue (#90cdf4).
Data Text
- .data span:
- Each line of sensor data (e.g., temperature, humidity).
- Displayed as blocks with spacing and larger font for visibility.
Animations
- @keyframes fadeIn:
- Smooth slide-down + fade-in for the container.
- @keyframes slideIn:
- Subtle zoom-in effect for each sensor card.
## Sensor library
### HTU21D library
The library contains 3 files, HTU21D.c, htu21d.h and main.c
#### htu21d.h
```h
#ifndef HTU21D_H
#define HTU21D_H
// HTU21D i2c address
#define HTU21D_ADDR 0x40
//commands for readings
#define HTU21D_TEMP 0xE3
#define HTU21D_HUM 0xE5
#define HTU21D_RESET 0xFE
//funtion declarations
//Temp:
int getTemp(int fd, double *temp);
//HUM
int getHum(int fd, double *hum);
//RESET
int getReset(int fd);
#endif
```
- HTU21D_ADDR: The I2C address of the sensor (0x40).
- HTU21D_TEMP: Command to read temperature (0xE3).
- HTU21D_HUM: Command to read humidity (0xE5).
- HTU21D_RESET: Command to reset the sensor (0xFE).
- Declares three functions:
1. getTemp() for reading temperature,
2. getHum() for reading humidity,
3. getReset() for resetting the sensor.