Raspberry Pi с BME280: Логгер данных температуры, влажности и давления (Python)
В этом проекте вы создадите логгер данных с помощью Raspberry Pi и датчика BME280, который автоматически сохраняет данные о температуре, влажности, давлении и соответствующую временную метку в файл .txt. Этот проект даёт вам основы сбора данных, что полезно во множестве различных приложений, использующих датчики. Вы можете применить концепции из этого проекта к любому датчику.
Впервые работаете с датчиком BME280? Прочитайте наше руководство по началу работы: :doc:`Raspberry Pi: Датчик температуры, влажности и давления BME280 (Python) </raspberry/rnt/raspberry-pi-bme280-python/index>`_.
Предварительные требования
Перед тем как продолжить работу с этим руководством, проверьте следующие предварительные требования.
Ознакомьтесь с платой Raspberry Pi — если вы не знакомы с Raspberry Pi, вы можете прочитать наше :doc:`руководство по началу работы с Raspberry Pi здесь </raspberry/rnt/getting-started-with-raspberry-pi/index>`_.
Вы должны знать, как запускать и создавать Python-файлы на вашем Raspberry Pi. Мы предпочитаем программировать Raspberry Pi удалённо через SSH, используя расширение в VS Code. У нас есть подробное руководство по этой теме: :doc:`Программирование Raspberry Pi удалённо с помощью VS Code (Remote-SSH) </raspberry/rnt/raspberry-pi-remote-ssh-vs-code/index>`_.
Знайте, как использовать GPIO Raspberry Pi, чтобы правильно собрать схему. Прочитайте следующее руководство: :doc:`Распиновка Raspberry Pi: Как использовать GPIO Raspberry Pi? </raspberry/rnt/raspberry-pi-pinout-gpios/index>`_
Знакомство с модулем датчика BME280
Модуль датчика BME280 считывает барометрическое давление, температуру и влажность. Поскольку давление изменяется с высотой, вы также можете оценить высоту над уровнем моря. Существует несколько версий этого модуля датчика. Мы используем модуль, показанный на рисунке ниже.
Этот датчик обменивается данными по протоколу связи I2C, поэтому подключение очень простое. Вы можете использовать стандартные выводы I2C на Raspberry Pi, как показано в следующей таблице:
BME280 |
Raspberry Pi |
|---|---|
Vin |
3.3V |
GND |
GND |
SCL |
GPIO 3 |
SDA |
GPIO 2 |
Узнайте больше о GPIO Raspberry Pi: :doc:`Распиновка Raspberry Pi: Как использовать GPIO Raspberry Pi? </raspberry/rnt/raspberry-pi-pinout-gpios/index>`_
Необходимые компоненты
Вот список компонентов, необходимых для сборки схемы:
Вы можете использовать приведённые выше ссылки или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!
Включение I2C на Raspberry Pi
Связь по I2C не включена по умолчанию. Вам нужно включить её вручную. Откройте окно терминала на вашем Raspberry Pi и введите следующую команду:
sudo raspi-config
Откроется следующее меню. Выберите Interface Options.
Затем выберите опцию I2C.
Наконец, включите I2C, выбрав Yes.
I2C должен быть успешно включён.
После включения I2C перезагрузите Raspberry Pi, выполнив следующую команду:
sudo reboot
Подключение BME280 к Raspberry Pi
Подключите BME280 к стандартным выводам I2C на Raspberry Pi.
BME280 |
Raspberry Pi |
|---|---|
Vin |
3.3V |
GND |
GND |
SCL |
GPIO 3 |
SDA |
GPIO 2 |
Получение I2C-адреса датчика
После подключения датчика к Raspberry Pi давайте проверим, правильно ли подключён датчик, найдя его I2C-адрес.
Откройте окно терминала на вашем Raspberry Pi и выполните следующую команду:
sudo i2cdetect -y 1
Она должна показать I2C-адрес вашего датчика:
Установка библиотеки BME280
Существует несколько библиотек, совместимых с Raspberry Pi, для чтения данных с датчика BME280. Мы будем использовать библиотеку RPi.BME280. Помимо функций для чтения данных с датчика BME280, она также имеет возможность получать временную метку, связанную с каждым показанием. Это делает её чрезвычайно простой в использовании для приложений по логированию данных.
Эта библиотека доступна для установки через PIP (менеджер пакетов для пакетов Python).
Сначала установите или обновите pip, выполнив следующую команду:
sudo pip install --upgrade pip
Затем выполните следующую команду для установки библиотеки с помощью pip:
sudo pip install RPI.BME280
Установка библиотеки pytz
Библиотека RPi.BME280 имеет возможность получать временную метку, связанную с каждым показанием. Однако эта временная метка будет в формате UTC. Если вы хотите преобразовать её в определённый часовой пояс, вы можете использовать библиотеку pytz. Откройте окно терминала на вашем Raspberry Pi и выполните следующую команду для установки библиотеки pytz.
pip install pytz
Python-скрипт логгера данных BME280 для Raspberry Pi
Создайте новый Python-файл на вашем Raspberry Pi с именем bme280_data_logger.py и скопируйте следующий код.
# Complete Project Details: https://RandomNerdTutorials.com/raspberry-pi-bme280-data-logger/
import smbus2
import bme280
import os
import time
import pytz
# BME280 sensor address (default address)
address = 0x76
# Initialize I2C bus
bus = smbus2.SMBus(1)
# Load calibration parameters
calibration_params = bme280.load_calibration_params(bus, address)
# create a variable to control the while loop
running = True
# Check if the file exists before opening it in 'a' mode (append mode)
file_exists = os.path.isfile('sensor_readings_bme280.txt')
file = open('sensor_readings_bme280.txt', 'a')
# Write the header to the file if the file does not exist
if not file_exists:
file.write('Time and Date, temperature (ºC), temperature (ºF), humidity (%), pressure (hPa)\n')
# loop forever
while running:
try:
# Read sensor data
data = bme280.sample(bus, address, calibration_params)
# Extract temperature, pressure, humidity, and corresponding timestamp
temperature_celsius = data.temperature
humidity = data.humidity
pressure = data.pressure
timestamp = data.timestamp
# Adjust timezone
# Define the timezone you want to use (list of timezones: https://gist.github.com/mjrulesamrat/0c1f7de951d3c508fb3a20b4b0b33a98)
desired_timezone = pytz.timezone('Europe/Lisbon') # Replace with your desired timezone
# Convert the datetime to the desired timezone
timestamp_tz = timestamp.replace(tzinfo=pytz.utc).astimezone(desired_timezone)
# Convert temperature to Fahrenheit
temperature_fahrenheit = (temperature_celsius * 9/5) + 32
# Print the readings
print(timestamp_tz.strftime('%H:%M:%S %d/%m/%Y') + " Temp={0:0.1f}ºC, Temp={1:0.1f}ºF, Humidity={2:0.1f}%, Pressure={3:0.2f}hPa".format(temperature_celsius, temperature_fahrenheit, humidity, pressure))
# Save time, date, temperature, humidity, and pressure in .txt file
file.write(timestamp_tz.strftime('%H:%M:%S %d/%m/%Y') + ', {:.2f}, {:.2f}, {:.2f}, {:.2f}\n'.format(temperature_celsius, temperature_fahrenheit, humidity, pressure))
time.sleep(10)
except KeyboardInterrupt:
print('Program stopped')
running = False
file.close()
except Exception as e:
print('An unexpected error occurred:', str(e))
running = False
file.close()
Как работает код
Вот краткое описание того, что делает код:
он сохраняет показания датчика и соответствующую временную метку в файл с именем sensor_readings_bme280.txt.
но сначала он проверяет, существует ли уже файл с именем sensor_readings_bme280.txt (это сделано для предотвращения многократной записи заголовка файла при перезапуске или остановке/запуске программы).
если файл не существует, он создаст новый файл.
есть бесконечный цикл, в котором вы получаете показания температуры, влажности и давления, а также соответствующую временную метку в формате UTC.
он преобразует временную метку в нужный вам часовой пояс, а затем записывает все данные в файл, включая временную метку.
программа продолжает работать и записывать данные в файл до тех пор, пока вы не скажете программе остановиться с помощью прерывания с клавиатуры или пока программа не остановится по какой-либо другой причине. В этом случае мы закрываем файл.
Продолжайте чтение для более подробного объяснения кода, или перейдите к разделу демонстрации.
Код очень похож на тот, что в :doc:`ЭТОМ ПРОЕКТЕ </raspberry/rnt/raspberry-pi-bme280-python/index>`_ (но с добавлением нескольких строк для логирования данных).
Импорт необходимых библиотек
Сначала вам нужно импортировать необходимые библиотеки. Библиотека smbus2 необходима для использования I2C-связи, RPi.BME280 — для получения показаний с датчика BME280, модуль time — для добавления задержек в ваш код, модуль os — для взаимодействия с операционной системой (в нашем случае нам нужно проверить, существует ли файл в файловой системе), и, наконец, модуль pytz — для настройки часового пояса.
import smbus2
import bme280
import os
import time
import pytz
Инициализация датчика BME280
Мы устанавливаем адрес датчика BME280 по умолчанию равным 0x76. Это адрес, по которому датчик обменивается данными по шине I2C (проверьте предыдущий раздел).
# BME280 sensor address (default address)
address = 0x76
Затем мы инициализируем шину I2C с помощью команды smbus2.SMBus(1).
# Initialize I2C bus
bus = smbus2.SMBus(1)
Далее мы инициализируем датчик, задав шину I2C и его I2C-адрес.
# Load calibration parameters
calibration_params = bme280.load_calibration_params(bus, address)
Работа с файлом
Следующая строка проверяет, существует ли уже файл с именем sensor_readings_bme280.txt (он будет искать его в папке проекта). Если файл уже существует, переменная file_exists будет равна True. В противном случае она будет равна False.
file_exists = os.path.isfile('sensor_readings_bme280.txt')
Затем он открывает файл в режиме „a“ (добавление). Если файл ещё не существует, он автоматически создаст файл перед его открытием.
file = open('sensor_readings_bme280.txt', 'a')
При использовании функции open() вы можете указать различные режимы для управления тем, как файл будет открыт и использован. При записи в файл наиболее популярными методами являются „w“ (запись) и „a“ (добавление).
Запись vs Добавление: режим записи открывает файл для записи и очищает файл, если он уже существует. Режим добавления открывает файл для записи и добавляет новые данные в конец файла. Если вы хотите вести запись показаний с течением времени, лучший режим — это добавление, чтобы сохранить все предыдущие данные.
Если файл ещё не существует, код записывает строку заголовка в файл, содержащую названия столбцов. Мы сохраняем сначала дату и время, затем температуру в градусах Цельсия и Фаренгейта, влажность и, наконец, давление.
# Write the header to the file if the file does not exist
if not file_exists:
file.write('Time and Date, temperature (ºC), temperature (ºF), humidity (%), pressure (hPa)\n')
Обратите внимание, что мы добавляем \n в конец строки. \n указывает Python начать следующий выводимый текст с новой строки, что известно как перевод строки.
Получение показаний датчика
Затем у нас есть цикл while, который постоянно выполняется, пока переменная running равна True. Мы установили эту переменную в True в начале кода. Переменная running изменится на False, когда выполнение программы будет остановлено прерыванием с клавиатуры или при возникновении непредвиденной ошибки.
while running:
Внутри цикла блок try пытается прочитать данные с датчика: мы используем функцию bme280.sample(bus, address, calibration_params) для чтения данных датчика.
data = bme280.sample(bus, address, calibration_params)
Мы извлекаем температуру, влажность, давление и соответствующую временную метку из данных, возвращённых датчиком, и сохраняем каждое показание в переменной: temperature_celsius, humidity, pressure и timestamp.
# Extract temperature, pressure, humidity, and corresponding timestamp
temperature_celsius = data.temperature
humidity = data.humidity
pressure = data.pressure
timestamp = data.timestamp
Настройка часового пояса
Как мы упоминали ранее, временная метка, возвращаемая объектом data библиотеки BME280, по умолчанию приходит в формате UTC. Мы можем использовать функции библиотеки pytz для преобразования этого времени в нужный нам часовой пояс.
Сначала укажите желаемый часовой пояс в следующей строке (вы можете найти список всех поддерживаемых часовых поясов здесь). Мы живём в Португалии, поэтому наш часовой пояс — „Europe/Lisbon“.
desired_timezone = pytz.timezone('Europe/Lisbon') # Replace with your desired timezone
Затем преобразуйте временную метку в нужный часовой пояс следующим образом.
# Convert the datetime to the desired timezone
timestamp_tz = timestamp.replace(tzinfo=pytz.utc).astimezone(desired_timezone)
Новая временная метка, скорректированная для вашего конкретного часового пояса, сохраняется в переменной timestamp_tz.
Преобразование температуры в градусы Фаренгейта
Мы преобразуем температуру из градусов Цельсия в градусы Фаренгейта следующим образом (температура в градусах Фаренгейта сохраняется в переменной temperature_fahrenheit).
# Convert temperature to Fahrenheit
temperature_fahrenheit = (temperature_celsius * 9/5) + 32
Вывод показаний
Наконец, мы выводим показания, отформатированные с двумя десятичными знаками, и соответствующую временную метку:
# Print the readings
print(timestamp_tz.strftime('%H:%M:%S %d/%m/%Y') + " Temp={0:0.1f}ºC, Temp={1:0.1f}ºF, Humidity={2:0.1f}%, Pressure={3:0.2f}hPa".format(temperature_celsius, temperature_fahrenheit, humidity, pressure))
Функция strftime() преобразует объекты datetime, time и date в строковый объект в соответствии с заданным форматом. В нашем случае мы используем формат часы:минуты:секунды для времени и день/месяц/год для даты.
%H: десятичное число, представляющее Час в 24-часовом формате (от 00 до 23)
%M: десятичное число, представляющее Минуту (от 01 до 59)
%S: десятичное число, представляющее Секунду (от 01 до 59)
%d: день месяца в виде десятичного числа с ведущим нулём (от 01 до 31)
%m: месяц в виде десятичного числа с ведущим нулём (от 01 до 12)
%Y: десятичное число, представляющее Год с указанием века
Для различных форматов даты и времени ознакомьтесь со всеми кодами форматирования здесь.
Запись данных в файл
Затем мы используем функцию write() для объекта файла, чтобы фактически записать данные в файл. Мы записываем временную метку, температуру в градусах Цельсия, температуру в градусах Фаренгейта, влажность и давление.
file.write(timestamp_tz.strftime('%H:%M:%S %d/%m/%Y') + ', {:.2f}, {:.2f}, {:.2f}, {:.2f}\n'.format(temperature_celsius, temperature_fahrenheit, humidity, pressure))
Новые показания выводятся и записываются в файл каждые 10 секунд. Вы можете настроить время между каждым измерением, передав другое число в метод sleep().
time.sleep(10)
Обработка прерываний и исключений
Если вы прервёте программу, нажав Ctrl + C, код перехватит исключение KeyboardInterrupt, выведет сообщение о завершении программы, а затем закроет файл перед установкой running в False для выхода из цикла.
except KeyboardInterrupt:
print('Program stopped')
running = False
file.close()
Важно: вам нужно вызвать file.close(), чтобы все данные были записаны в файл.
Мы поступаем аналогичным образом, если возникает любая другая ошибка или исключение.
except Exception as e:
print('An unexpected error occurred:', str(e))
running = False
file.close()
Демонстрация
Сохраните ваш Python-файл. Затем запустите его на вашем Raspberry Pi. Выполните следующую команду в директории вашего файла:
python bme280_data_logger.py
Вы начнёте получать новые показания температуры и влажности в окне терминала, и новый файл с именем sensors_readings_bme280.txt будет создан в папке вашего проекта. Если вы используете VS Code, вы увидите только что созданный файл в проводнике файлов (пока не открывайте его).
Дайте коду поработать некоторое время, чтобы он собрал достаточное количество данных. Затем остановите выполнение кода, нажав CTRL+C.
Теперь вы можете открыть файл sensors_readings_bme280.txt и увидеть все собранные данные. Вы можете запустить программу снова, чтобы собрать больше данных, и она не перезапишет предыдущие данные.
Если вы используете PuTTY, перейдите в папку вашего проекта. Выведите список всех файлов в папке проекта с помощью команды ls и обратите внимание, что файл с именем sensor_readings_bme280.txt присутствует в списке.
Чтобы открыть этот файл, используйте следующую команду:
cat sensor_readings_bme280.txt
Затем вы увидите все данные, собранные вашим датчиком, с соответствующими временными метками.
Заключение
В этом проекте вы изучили очень полезную концепцию: логирование данных. Теперь вы можете использовать логирование данных в других проектах мониторинга или с другими датчиками. У нас есть руководства для других датчиков, которые могут быть полезны:
Мы надеемся, что это руководство оказалось полезным для вас. Если вы новичок в работе с Raspberry Pi, ознакомьтесь со следующими руководствами:
:doc:`Начало работы с Raspberry Pi </raspberry/rnt/getting-started-with-raspberry-pi/index>`_
:doc:`Распиновка Raspberry Pi </raspberry/rnt/raspberry-pi-pinout-gpios/index>`_
Вы можете ознакомиться со всеми нашими проектами для Raspberry Pi по следующей ссылке: