Primer commit: Estructura base del proyecto Implementación de un Sistema de Monitoreo de Temperatura Basado en Raspberry Pi, Sensor EZO™ RTD y Sonda PT1000 Completada

main
EMOTIONS-HUNTER 1 week ago
commit 7c423a8266

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

@ -0,0 +1,248 @@
# Readme basic-aqm
# Air Quality Monitor
The Air Quality Monitor (AQM) project is a large development that requieres hardware, back-end programmming for the sensor, and front-end programming/configuration to display the measuring data. **To read about each step please visit the specific repositories.**
This repository is about the setup and configuration of the sensors, back-end (APIs), and front-end (dashboard).
# Sensors setup
The project uses a PCB custom designed that includes the following sensors:
- HTU21D: Board Mount Humidity Sensors I.C 20D RH/T with I2C
- BH1750: Ambient Light Sensors Ambient Light Sensor Digital 16bit Serial I2C
- ZMOD4410: Air Quality Sensors TVOC IAQ Sensor with I2C output
- BMP581: Board Mount Pressure Sensors The BMP581 is a very small, low-power and low-noise 24-bit absolute barometric pressure sensor.
**Todo: add here the pcb image**
**However, you can connect the sensor-module version that is already prepared to communicate by I2C, like the one shown in the figure; htu21d module.**
![HTU21D-Module-Pinout](TZCBIN8qL-HTU21D-Module-Pinout.png)
## The HTU21D sensor
In case you want to test the application without the complete AQM-Hat, the sensor must be connected to the second I2C peripherical by:
P9.03 -> +3.3V (2nd pin - left position)
P9.01 -> DGND (1st pin - left position)
P9.19 -> I2C2_SCL (10th pin - left position)
P9.20 -> I2C2_SDA (10th pin - right position)
![beaglebone_black_pinmap](2MbNe2guV-beaglebone_black_pinmap.png)
## Reading Data from HTU21D
The HTU21D sensor uses specific commands to read temperature and humidity data. Heres how you can properly read and interpret this data. But first let us check if the device is connected and detected by the B3.
Before starting, install the bash tools to work with I2C:
```sh
sudo apt update
sudo apt install i2c-tools
```
Also install the build essential libraries to compile in C:
```sh
sudo apt update
sudo apt install build-essential
```
Next, to check if the sensor is connected and detected by the B3 into the I2C port 2, try the next command:
```sh
sudo i2cdetect -y 2
Warning: Can't use SMBus Quick Write command, will skip some addresses
0 1 2 3 4 5 6 7 8 9 a b c d e f
00:
10:
20:
30: -- -- -- -- -- -- -- --
40:
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60:
70:
```
This output **looks like there is no sensor connected at any address**. Nevertheless, for some reason the detection command is not checking the `0x40` line-address for the I2C. Thus we can try to directly read the specific addresses. To read the temperature, send the temperature measurement command (0xE3 for no hold mode or 0xF3 for hold mode) and then read two bytes of data.
```sh
sudo i2cget -y 2 0x40 0xE3 w
0x3871
```
if you get a similar output in the terminal the sensor is properly connected and ready.
## Converting temperature measurements
**Pending Todo**
# Back-end Apps
## Compiling and testing the sensor C-Programs
In the repository folder, go to the `sensors` sub-folder and make each main.c file to read and store the measurements:
```sh
$ cd sensors/HTU21D
$ make
gcc -c -o main.o main.c -I.
gcc -o HTU21D main.o htu21d.o -I. -li2c
$ ./HTU21D
{ "temperature": 24.60, "humidity": 52.50 }
```
The previous output indicates that the `HTU21D` executable is now working. **Do the same for all sensors.**
```sh
cd sensors/BMP180
make
cd ..
cd sensors/XXXX
make
cd ..
```
Finally, let us prepare the `JSON` files to test the Dashboard:
```sh
./sensors/HTU21D/HTU21D > ./data/HTU21D.json
...
```
# Front-end Dashboard
This project provides a basic web dashboard to test the functionality of the AQM-hat. The way it works and a improved version are presented later, after understanding how to prepare data and the web server to visualize the dashboard.
## Configuring Nginx
First install the Nginx package in the B3 board:
```sh
sudo apt update
sudo apt install nginx
```
Next, let's redirect the configuration file to our repository folder:
```sh
sudo vi /etc/nginx/sites-available/default
```
Replace the line:
```
root /var/www/html;
```
with:
```
root /home/debian/path/to/your/repository;
```
in my particular case:
```sh
root /home/debian/lwc/7-air-quality-ui/basic-ui;
```
```sh
sudo systemctl restart nginx
```
Open the web interface and type the IP addess of your device or visit the hostname + .local (`http://bbgmarx.local`); you should see a UI similar to the next one:
![basic-ui](C8ZLtB-py-basic-ui.jpg)
# Simple Sensor Dashboard
A simple sensor dashboard has been developed to fetch the data from the `JSON` files and then show them in a HTML fashion. The dashboard UI es updated every 60 seconds and considers a minimal HTML with CSS and JavaScript.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Sensor Dashboard</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; }
.sensor { margin: 10px; padding: 10px; border: 1px solid #ccc; }
.sensor-title { font-weight: bold; }
.sensor-value { font-size: 2em; color: #333; }
</style>
</head>
<body>
<h1>Sensor Data</h1>
<div id="temperature" class="sensor">
<div class="sensor-title">Temperature</div>
<div class="sensor-value" id="temp-value">--</div>
</div>
<div id="humidity" class="sensor">
<div class="sensor-title">Humidity</div>
<div class="sensor-value" id="humidity-value">--</div>
</div>
<script>
async function fetchData() {
try {
const tempResponse = await fetch('./data/HTU21D.json');
const tempData = await tempResponse.json();
document.getElementById('temp-value').textContent = tempData.temperature.toFixed(1) + ' ℃';
document.getElementById('humidity-value').textContent = tempData.humidity.toFixed(1) + ' %';
} catch (error) {
console.error('Error fetching data:', error);
}
}
// Update data every 60 seconds
setInterval(fetchData, 60000);
fetchData(); // Initial fetch
</script>
</body>
</html>
```
## Code Explanation
### HTML Structure
1. **Header**:
- Sets the character encoding and viewport for responsiveness.
- Styles the page with a basic CSS structure for sensor data presentation.
2. **Sensor Display Elements**:
- The dashboard includes two sensors: **Temperature** and **Humidity**.
- Each sensor reading is displayed in a `.sensor` box with a title and value.
### CSS Styling
- **General Styles**: Applies a basic font style (Arial) and centers the text.
- **Sensor Box Styling**: `.sensor` boxes have a border, padding, and margin to create separation between sensor readings.
### JavaScript Logic
1. **Data Fetching (`fetchData`)**:
- Uses `fetch()` to retrieve JSON data for temperature and humidity.
- Updates the corresponding HTML elements with the latest data.
2. **Automatic Refresh**:
- `setInterval(fetchData, 60000);` updates the sensor data every 60 seconds, ensuring it stays current.
Ensure that the JSON file is regularly updated by a background service or script to keep the data current.
# Data updating
Configure roots crontab to update data every 5 minutes
```sh
sudo crontab -e
```
Edit it like so:
```sh
*/5 * * * * /usr/bin/python -m mh_z19 > /home/pi/anavi-phat-sensors-ui/data/MH_Z19.json
*/5 * * * * /home/pi/anavi-phat-sensors-ui/sensors/HTU21D/HTU21D > /home/pi/anavi-phat-sensors-ui/data/HTU21D.json
*/5 * * * * /home/pi/anavi-phat-sensors-ui/sensors/BMP180/BMP180 > /home/pi/anavi-phat-sensors-ui/data/BMP180.json
*/5 * * * * /home/pi/anavi-phat-sensors-ui/sensors/BH1750/BH1750 > /home/pi/anavi-phat-sensors-ui/data/BH1750.json
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@ -0,0 +1 @@
timestamp,temperature
1 timestamp temperature

@ -0,0 +1 @@
{ "temperature": 24.414 }

@ -0,0 +1 @@
{ "temperature": 24.60, "humidity": 52.68 }

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><title>ionicons-v5-f</title><path d="M400,240c-8.89-89.54-71-144-144-144-69,0-113.44,48.2-128,96C68,198,16,235.59,16,304c0,66,54,112,120,112H396c55,0,100-27.44,100-88C496,268.18,443,242.24,400,240Z" style="fill:none;stroke:white;stroke-linejoin:round;stroke-width:32px"/></svg>

After

Width:  |  Height:  |  Size: 365 B

@ -0,0 +1 @@
<svg xmlns='http://www.w3.org/2000/svg' width='512' height='512' viewBox='0 0 512 512'><title>ionicons-v5-q</title><line x1='256' y1='48' x2='256' y2='96' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><line x1='256' y1='416' x2='256' y2='464' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><line x1='403.08' y1='108.92' x2='369.14' y2='142.86' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><line x1='142.86' y1='369.14' x2='108.92' y2='403.08' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><line x1='464' y1='256' x2='416' y2='256' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><line x1='96' y1='256' x2='48' y2='256' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><line x1='403.08' y1='403.08' x2='369.14' y2='369.14' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><line x1='142.86' y1='142.86' x2='108.92' y2='108.92' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/><circle cx='256' cy='256' r='80' style='fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px'/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><title>ionicons-v5-q</title><path d="M307.72,302.27a8,8,0,0,1-3.72-6.75V80a48,48,0,0,0-48-48h0a48,48,0,0,0-48,48V295.52a8,8,0,0,1-3.71,6.74,97.51,97.51,0,0,0-44.19,86.07A96,96,0,0,0,352,384,97.49,97.49,0,0,0,307.72,302.27Z" style="fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"/><line x1="256" y1="112" x2="256" y2="384" style="fill:none;stroke:white;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"/><circle cx="256" cy="384" r="48"/></svg>

After

Width:  |  Height:  |  Size: 578 B

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><title>ionicons-v5-r</title><path d="M400,320c0,88.37-55.63,144-144,144S112,408.37,112,320c0-94.83,103.23-222.85,134.89-259.88a12,12,0,0,1,18.23,0C296.77,97.15,400,225.17,400,320Z" style="fill:none;stroke:white;stroke-miterlimit:10;stroke-width:32px"/><path d="M344,328a72,72,0,0,1-72,72" style="fill:none;stroke:white;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/></svg>

After

Width:  |  Height:  |  Size: 476 B

@ -0,0 +1,147 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Air Quality Monitor</title>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400&display=swap" rel="stylesheet">
<style>
/* General Styles */
* { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Roboto', sans-serif; }
body { display: flex; flex-direction: column; align-items: center; justify-content: center; background: #f5f5f5; color: #333; height: 100vh; }
h1 { font-size: 2em; color: #444; margin-bottom: 20px; }
/* Container for Sensors */
.sensor-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
width: 100%;
max-width: 800px;
padding: 10px;
}
/* Sensor Box */
.sensor {
background: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
border-radius: 10px;
width: 180px;
padding: 20px;
text-align: center;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.sensor:hover { transform: scale(1.05); box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); }
/* Sensor Titles */
.sensor-title {
font-weight: 400;
color: #555;
font-size: 1.2em;
margin-bottom: 10px;
display: flex;
align-items: center;
justify-content: center;
}
/* Sensor Value */
.sensor-value {
font-size: 2.5em;
font-weight: 300;
color: #333;
margin-bottom: 5px;
animation: fadeIn 0.5s ease;
}
.unit { font-size: 0.8em; color: #777; }
/* Icon Styles */
.sensor-icon {
width: 30px;
height: 30px;
margin-right: 8px;
filter: grayscale(50%);
}
/* Keyframes for Smooth Animations */
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
</style>
</head>
<body>
<h1>Room Air Quality Monitor</h1>
<div class="sensor-container">
<div id="temperature" class="sensor">
<div class="sensor-title">
<img src="./images/thermometer-outline.svg" class="sensor-icon" alt="Temperature Icon">
Temperature
</div>
<div class="sensor-value" id="temp-value">--</div>
<div class="unit"></div>
</div>
<div id="humidity" class="sensor">
<div class="sensor-title">
<img src="./images/water-outline.svg" class="sensor-icon" alt="Humidity Icon">
Humidity
</div>
<div class="sensor-value" id="humidity-value">--</div>
<div class="unit">%</div>
</div>
<div id="co2" class="sensor">
<div class="sensor-title">
<img src="./images/cloud-outline.svg" class="sensor-icon" alt="CO2 Icon">
CO₂
</div>
<div class="sensor-value" id="co2-value">--</div>
<div class="unit">ppm</div>
</div>
<div id="pressure" class="sensor">
<div class="sensor-title">
<img src="./images/sunny-outline.svg" class="sensor-icon" alt="Pressure Icon">
Pressure
</div>
<div class="sensor-value" id="pressure-value">--</div>
<div class="unit">hPa</div>
</div>
</div>
<script>
async function fetchData() {
try {
const res = await Promise.all([
//fetch("./data/BH1750.json"),
//fetch("./data/BMP180.json"),
fetch("./data/HTU21D.json"),
//fetch("./data/MH_Z19.json")
]);
const data = (await Promise.all(res.map(r => r.json()))).reduce((acc, item) => ({ ...acc, ...item }), {});
return data;
} catch (error) {
console.error("Failed to fetch sensor data:", error);
return {};
}
}
function updateUI(data) {
document.getElementById("temp-value").textContent = data.temperature ? data.temperature.toFixed(1) : "--";
document.getElementById("humidity-value").textContent = data.humidity ? data.humidity.toFixed(1) : "--";
document.getElementById("co2-value").textContent = data.co2 ? data.co2 : "--";
document.getElementById("pressure-value").textContent = data.pressure ? data.pressure.toFixed(1) : "--";
}
async function refreshData() {
const data = await fetchData();
updateUI(data);
}
setInterval(refreshData, 6000); // Refresh every 60 seconds
refreshData(); // Initial fetch
</script>
</body>
</html>

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Simple Sensor Dashboard</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; }
.sensor { margin: 10px; padding: 10px; border: 1px solid #ccc; }
.sensor-title { font-weight: bold; }
.sensor-value { font-size: 2em; color: #333; }
</style>
</head>
<body>
<h1>EZO RTD Temperature Monitor</h1>
<div id="temperature" class="sensor">
<div class="sensor-title">Temperature</div>
<div class="sensor-value" id="temp-value">--</div>
<div id="last-update">--</div>
</div>
<script>
async function fetchData() {
try {
const response = await fetch('./data/EZORTD.json');
const data = await response.json();
document.getElementById('temp-value').textContent =
data.temperature.toFixed(3) + ' ℃';
document.getElementById('last-update').textContent =
"Updated: " + new Date().toLocaleTimeString();
} catch (error) {
console.error('Error fetching data:', error);
}
}
setInterval(fetchData, 1000);
fetchData();
</script>
</body>
</html>

Binary file not shown.

Binary file not shown.

@ -0,0 +1,12 @@
CC=gcc
CFLAGS=-I.
OBJ=main.o ezortd.o
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
EZORTD: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)
clean:
rm -f EZORTD *.o

@ -0,0 +1,47 @@
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <stdlib.h>
#include "ezortd.h"
int getTemperature(int fd, double *temperature)
{
if(ioctl(fd, I2C_SLAVE, EZORTD_I2C_ADDR) < 0)
{
perror("ioctl");
return -1;
}
char cmd[] = "R";
if(write(fd, cmd, strlen(cmd)) < 0)
{
perror("write");
return -1;
}
usleep(1000000);
unsigned char response[32];
int n = read(fd, response, sizeof(response));
if(n < 0)
{
perror("read");
return -1;
}
if(response[0] != 0x01)
{
fprintf(stderr,"EZO error code: %d\n", response[0]);
return -1;
}
*temperature = atof((char *)&response[1]);
return 0;
}

@ -0,0 +1,8 @@
#ifndef EZORTD_H
#define EZORTD_H
#define EZORTD_I2C_ADDR 0x66
int getTemperature(int fd, double *temperature);
#endif

Binary file not shown.

@ -0,0 +1,77 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include "ezortd.h"
int main()
{
int fd;
fd = open("/dev/i2c-1", O_RDWR);
if (fd < 0)
{
perror("open");
return -1;
}
while (1)
{
double temperature;
if (getTemperature(fd, &temperature) == 0)
{
FILE *f = fopen(
"/home/cristian/airquality/basic-ui-dashboard/data/EZORTD.json",
"w");
if (f)
{
time_t now = time(NULL);
struct tm *t = localtime(&now);
char timestamp[32];
strftime(timestamp,
sizeof(timestamp),
"%Y-%m-%d %H:%M:%S",
t);
fprintf(f,
"{ \"temperature\": %.3f }\n",
temperature);
fclose(f);
}
}
FILE *log = fopen(
"/home/cristian/airquality/basic-ui-dashboard/logs/temp.csv",
"a");
if (log)
{
time_t now = time(NULL);
struct tm *t = localtime(&now);
char timestamp[32];
strftime(timestamp,
sizeof(timestamp),
"%Y-%m-%d %H:%M:%S",
t);
fprintf(log,
"%ld,%.3f\n",
now,
temperature);
fclose(log);
}
sleep(1);
}
return 0;
}

@ -0,0 +1,37 @@
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "ezortd.h"
int main()
{
int fd;
fd = open("/dev/i2c-1", O_RDWR);
if(fd < 0)
{
fprintf(stderr,
"ERROR: Unable to access EZO RTD: %s\n",
strerror(errno));
return -1;
}
double temperature = 0;
if(getTemperature(fd, &temperature) < 0)
{
fprintf(stderr,
"ERROR: Failed to read temperature\n");
return -1;
}
printf("{ ");
printf("\"temperature\": %.3f ", temperature);
printf("}");
return 0;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,16 @@
CC=gcc
CFLAGS=-I.
DEPS =
OBJ = main.o htu21d.o
EXTRA_LIBS=-li2c
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
HTU21D: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS) $(EXTRA_LIBS)
.PHONY: clean
clean:
rm -f HTU21D $(OBJ)

@ -0,0 +1,180 @@
# Introduction
This repository guides you to implement and use the HTU21D temperature and humidity sensor by using I2C communication. The repository contains the following files:
- `htu21d.h` library header files
- `htu21d.c` implemenation methods file
- `main.c` an example file to test I2C communication using the library `htu21d`
- `example` output file precompiled in a raspberry pi zero that returns temperature and humidity
# Setup the raspberry
## Enable I2C on the Raspberry Pi:
- Run sudo raspi-config.
- Navigate to Interfacing Options → I2C and enable it.
- Reboot the Pi.
## Install I2C Tools and Development Libraries:
```
sudo apt-get update
sudo apt-get install i2c-tools libi2c-dev
```
## Check if the sensor is detected:
```
sudo i2cdetect -y 1
```
This command should show an address for the HTU21D, typically 0x40.
```
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: 40 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
```
# My own header files for HTU21D sensor
This is a detailed guide to configure and create your own files to comunicate with each sensor used by the air-quality sensor.
## Header
Create the Header File `htu21d.h` with Header Guard and Includes:
```c
#ifndef HTU21D_H
#define HTU21D_H
// I2C Address
#define HTU21D_I2C_ADDR 0x40
// Commands
#define HTU21D_TEMP 0xE3
#define HTU21D_HUMID 0xE5
#define HTU21D_RESET 0xFE
// Function declarations:
// Temp
int getTemperature(int fd, double *temperature);
// Humidity
int getHumidity(int fd, double *humidity);
#endif // HTU21D_H
```
## Implement the Sensor Communication `htu21d.c`
```c
#include <unistd.h> //to send commands to and receive from I2C device
#include <sys/ioctl.h>//setting up and controlling the I2C device settings
#include <linux/i2c-dev.h>//definitions for system calls and structures specific to I2C
#include <i2c/smbus.h>//SMBus commands in a more standardized way for I2C
#include <stdio.h>//perror
#include "htu21d.h" // my own header file
// Reset function:
int reset(int fd)
{
if(0 > ioctl(fd, I2C_SLAVE, HTU21D_I2C_ADDR))
{
perror("Failed to open the bus");
return -1;
}
i2c_smbus_write_byte(fd, HTU21D_RESET);
return 0;
}
// Get temperature:
int getTemperature(int fd, double *temperature)
{
reset(fd);
char buf[3];
__s32 res = i2c_smbus_read_i2c_block_data(fd, HTU21D_TEMP,3,buf);
if(res<0)
{
perror("Failed to read from the device");
return -1;
}
*temperature = -46.85 + 175.72 * (buf[0]*256 + buf[1]) / 65536.0;
return 0;
}
// Get humidity:
int getHumidity(int fd, double *humidity)
{
reset(fd);
char buf[3];
__s32 res = i2c_smbus_read_i2c_block_data(fd, HTU21D_HUMID, 3, buf);
if(res<0)
{
perror("Failed to read from the device");
return -1;
}
*humidity = -6 + 125 * (buf[0]*256 + buf[1]) / 65536.0;
return 0;
}
```
### Using the library
```c
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "htu21d.h"
int main()
{
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", 1);
int fd = open(filename, O_RDWR);
if (0 > fd)
{
fprintf(stderr, "ERROR: Unable to access HTU21D sensor module: %s\n", strerror (errno));
exit(-1);
}
// Retrieve temperature and humidity
double temperature = 0;
double humidity = 0;
if ( (0 > getHumidity(fd, &humidity)) || (0 > getTemperature(fd, &temperature)) )
{
fprintf(stderr, "ERROR: HTU21D sensor module not found\n");
exit(-1);
}
// Print temperature and humidity on the screen
printf("HTU21D Sensor Module\n");
printf("%5.2fC\n", temperature);
printf("%5.2f%%rh\n", humidity);
return 0;
}
```
# Compiling and testing
Then to properly compile whitout a make file:
```sh
gcc -o example main.c htu21d.c -li2c
```
or
```sh
gcc -o example main.c htu21d.c -I. -li2c
```
### Wiring htu21d to Rasp-zero
Htu -> Rasp-Zero
VIN -> GPIO 1
GND -> GPIO 9 or (6)
SCL -> GPIO 5
SDA -> GPIO 3
![Raspberry Pi Zero GPIO layout](rpiz.png)

@ -0,0 +1,52 @@
#include <unistd.h> //to send commands to and receive from I2C device
#include <sys/ioctl.h>//setting up and controlling the I2C device settings
#include <linux/i2c-dev.h>//definitions for system calls and structures specific to I2C
#include <i2c/smbus.h>//SMBus commands in a more standardized way for I2C
#include <stdio.h>//perror
#include "htu21d.h" // my own header file
// Reset function:
int reset(int fd)
{
if(0 > ioctl(fd, I2C_SLAVE, HTU21D_I2C_ADDR))
{
perror("Failed to open the bus");
return -1;
}
i2c_smbus_write_byte(fd, HTU21D_RESET);
return 0;
}
// Get temperature:
int getTemperature(int fd, double *temperature)
{
reset(fd);
char buf[3];
__s32 res = i2c_smbus_read_i2c_block_data(fd, HTU21D_TEMP,3,buf);
if(res<0)
{
perror("Failed to read from the device");
return -1;
}
*temperature = -46.85 + 175.72 * (buf[0]*256 + buf[1]) / 65536.0;
return 0;
}
// Get humidity:
int getHumidity(int fd, double *humidity)
{
reset(fd);
char buf[3];
__s32 res = i2c_smbus_read_i2c_block_data(fd, HTU21D_HUMID, 3, buf);
if(res<0)
{
perror("Failed to read from the device");
return -1;
}
*humidity = -6 + 125 * (buf[0]*256 + buf[1]) / 65536.0;
return 0;
}

@ -0,0 +1,19 @@
#ifndef HTU21D_H
#define HTU21D_H
// I2C Address
#define HTU21D_I2C_ADDR 0x40
// Commands
#define HTU21D_TEMP 0xE3
#define HTU21D_HUMID 0xE5
#define HTU21D_RESET 0xFE
// Function declarations:
// Temp
int getTemperature(int fd, double *temperature);
// Humidity
int getHumidity(int fd, double *humidity);
#endif // HTU21D_H

Binary file not shown.

@ -0,0 +1,39 @@
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "htu21d.h"
int main()
{
char filename[20];
snprintf(filename, 19, "/dev/i2c-%d", 1);
int fd = open(filename, O_RDWR);
if (0 > fd)
{
fprintf(stderr, "ERROR: Unable to access HTU21D sensor module: %s\n", strerror (errno));
exit(-1);
}
// Retrieve temperature and humidity
double temperature = 0;
double humidity = 0;
if ( (0 > getHumidity(fd, &humidity)) || (0 > getTemperature(fd, &temperature)) )
{
fprintf(stderr, "ERROR: HTU21D sensor module not found\n");
exit(-1);
}
// Print temperature and humidity on the screen
printf("{ ");
printf("\"temperature\": %5.2f, ", temperature);
printf("\"humidity\": %5.2f ", humidity);
printf("}");
//printf("HTU21D Sensor Module\n");
//printf("%5.2fC\n", temperature);
//printf("%5.2f%%rh\n", humidity);
return 0;
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Loading…
Cancel
Save