Raspberry Pi с BME280: Логгер данных температуры, влажности и давления (Python)

В этом проекте вы создадите логгер данных с помощью Raspberry Pi и датчика BME280, который автоматически сохраняет данные о температуре, влажности, давлении и соответствующую временную метку в файл .txt. Этот проект даёт вам основы сбора данных, что полезно во множестве различных приложений, использующих датчики. Вы можете применить концепции из этого проекта к любому датчику.

Raspberry Pi с BME280 — логгер данных температуры, влажности и давления на Python

Впервые работаете с датчиком BME280? Прочитайте наше руководство по началу работы: :doc:`Raspberry Pi: Датчик температуры, влажности и давления BME280 (Python) </raspberry/rnt/raspberry-pi-bme280-python/index>`_.

Предварительные требования

Перед тем как продолжить работу с этим руководством, проверьте следующие предварительные требования.

  1. Ознакомьтесь с платой Raspberry Pi — если вы не знакомы с Raspberry Pi, вы можете прочитать наше :doc:`руководство по началу работы с Raspberry Pi здесь </raspberry/rnt/getting-started-with-raspberry-pi/index>`_.

  2. Вы должны знать, как запускать и создавать Python-файлы на вашем Raspberry Pi. Мы предпочитаем программировать Raspberry Pi удалённо через SSH, используя расширение в VS Code. У нас есть подробное руководство по этой теме: :doc:`Программирование Raspberry Pi удалённо с помощью VS Code (Remote-SSH) </raspberry/rnt/raspberry-pi-remote-ssh-vs-code/index>`_.

  3. Знайте, как использовать GPIO Raspberry Pi, чтобы правильно собрать схему. Прочитайте следующее руководство: :doc:`Распиновка Raspberry Pi: Как использовать GPIO Raspberry Pi? </raspberry/rnt/raspberry-pi-pinout-gpios/index>`_

Знакомство с модулем датчика BME280

Модуль датчика BME280 считывает барометрическое давление, температуру и влажность. Поскольку давление изменяется с высотой, вы также можете оценить высоту над уровнем моря. Существует несколько версий этого модуля датчика. Мы используем модуль, показанный на рисунке ниже.

Модуль датчика BME280 I2C — считывает давление, температуру и влажность

Этот датчик обменивается данными по протоколу связи 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>`_

Необходимые компоненты

Raspberry Pi с датчиком BME280

Вот список компонентов, необходимых для сборки схемы:

Вы можете использовать приведённые выше ссылки или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!

Включение I2C на Raspberry Pi

Связь по I2C не включена по умолчанию. Вам нужно включить её вручную. Откройте окно терминала на вашем Raspberry Pi и введите следующую команду:

sudo raspi-config

Откроется следующее меню. Выберите Interface Options.

Raspberry Pi — включение I2C связи

Затем выберите опцию I2C.

Raspberry Pi — включение I2C связи

Наконец, включите I2C, выбрав Yes.

Raspberry Pi — включение I2C связи

I2C должен быть успешно включён.

Raspberry Pi — I2C связь включена

После включения I2C перезагрузите Raspberry Pi, выполнив следующую команду:

sudo reboot

Подключение BME280 к Raspberry Pi

Подключите BME280 к стандартным выводам I2C на Raspberry Pi.

Схема подключения BME280 к 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 — получение I2C-адреса BME280

Установка библиотеки 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, вы увидите только что созданный файл в проводнике файлов (пока не открывайте его).

Raspberry Pi — логгер данных BME280 в VS Code

Дайте коду поработать некоторое время, чтобы он собрал достаточное количество данных. Затем остановите выполнение кода, нажав CTRL+C.

Raspberry Pi — остановка Python-программы в VS Code

Теперь вы можете открыть файл sensors_readings_bme280.txt и увидеть все собранные данные. Вы можете запустить программу снова, чтобы собрать больше данных, и она не перезапишет предыдущие данные.

Показания датчика — логгер данных Raspberry Pi в VS Code

Если вы используете PuTTY, перейдите в папку вашего проекта. Выведите список всех файлов в папке проекта с помощью команды ls и обратите внимание, что файл с именем sensor_readings_bme280.txt присутствует в списке.

Raspberry Pi — список файлов в PuTTY

Чтобы открыть этот файл, используйте следующую команду:

cat sensor_readings_bme280.txt

Затем вы увидите все данные, собранные вашим датчиком, с соответствующими временными метками.

Raspberry Pi — файл логгера данных в PuTTY

Заключение

В этом проекте вы изучили очень полезную концепцию: логирование данных. Теперь вы можете использовать логирование данных в других проектах мониторинга или с другими датчиками. У нас есть руководства для других датчиков, которые могут быть полезны:

Мы надеемся, что это руководство оказалось полезным для вас. Если вы новичок в работе с Raspberry Pi, ознакомьтесь со следующими руководствами:

Вы можете ознакомиться со всеми нашими проектами для Raspberry Pi по следующей ссылке: