От датчика к графику: создаём консольную метеостанцию на Arduino и Python

от автора

Введение

Привет, читатель, меня зовут Морозов Алексей, и в этой статье я наглядно покажу, как сделать метеостанцию! За работу.

Идея и ответы на почему

Я хочу сделать простую и модульную метеостанцию с консольным выводом данных

  • Сделать плату-опросчик, которая читает данные с датчиков и отправляет их в порт.

  • Сделать скрипт на питоне, который будет обрабатывать и выводить значения в консоль

Почему модульность?

Разделение метеостанции на два уровня, низкий(опрос датчиков) и высокий(обработка и вывод данных) позволяет быстро вносить изменения в систему, добавлять новые датчики или даже менять сами устройства.

Почему именно консольный вывод?

TUI — отличная отправная точка для вывода данных, можно быстро менять формат вывода, добавлять новые диаграммы и даже окна.

Подбор компонентов

  1. В качестве платы опросчика, подойдёт arduino nano, у неё достаточно мощности и портов, чтобы развивать метеостанцию до предела

  2. В качестве датчика я решил взять htu21d, который умеет определять температуру и влажность воздуха. Отличная плата для начала, потом заменю на bmp280

Подключение

Приступим к сборке метеостанции! Вот схема подключения:

схема подключения

схема подключения
Пример сборки тут.
Ардуино нано

Ардуино нано
Ардуино нано в корпусе

Ардуино нано в корпусе
dht21d в корпусе

dht21d в корпусе
dht21d вид внутри корпуса

dht21d вид внутри корпуса

Код для ардуино

Вот код для считывания данных с датчика и отправки их в порт:

#include <GyverHTU21D.h>GyverHTU21D htu;void getTemp(){    Serial.print("Temp:");  Serial.print(htu.getTemperature());  Serial.print(",");  Serial.print("Humd:");  Serial.println(htu.getHumidity());}void setup() {  Serial.begin(115200);  htu.begin();}void loop() {  if (htu.readTick()) {    getTemp();  }}
вывод данных

вывод данных

Если открыть вывод в ардуино иде, то мы увидим вот такую картину.

Код на питон

Вот код скрипта на питон, для парсинга и вывода данных в виде графика:

import serialimport plotext as pltimport timeser = serial.Serial('/dev/ttyUSB0', 115200)def read_and_parse():        response = ser.readline()    if not response:        return None, None        try:        decoded_response = response.decode('utf-8')            input_string = decoded_response.rstrip('\n')            # Разбиваем строку на пары ключ:значение        pairs = input_string.split(',')        if len(pairs) != 2:            print("Ошибка: строка должна содержать ровно две пары ключ:значение")            return None, None                expected_key1 = "Temp"          expected_key2 = "Humd"          value1 = None        value2 = None        for pair in pairs:            parts = pair.split(':', 1)  # Разбиваем только по первому ':'            if len(parts) != 2:                print(f"Ошибка: некорректный формат пары: {pair}")                return None, None            key, value = parts[0].strip(), parts[1].strip()            if key == expected_key1:                value1 = value            elif key == expected_key2:                value2 = value            else:                print(f"Предупреждение: неизвестный ключ '{key}' найден в строке")        # Проверяем, нашли ли оба ожидаемых значения        if value1 is None or value2 is None:            print("Ошибка: не найдены значения для одного или обоих ожидаемых ключей")            return None, None        return value1, value2    except Exception as e:        print(f"Произошла ошибка при парсинге: {e}")        return None, None    def plot_data(temp, humd):    x = ["Температура", "Влажность"]    # Значения    y = (float(temp), float(humd))    colors = ["cyan", "red"]     plt.clear_data()        plt.bar(x, y, color=colors, orientation="horizontal", width=3/5)    plt.title("Данные с датчика")    plt.ylabel("Значение")    plt.clt()    plt.show() def main():    print("Начало работы! Нажмите Ctrl+C для завершения.")    try:        while True:            temp, humd = read_and_parse()                        # Рисуем только если данные успешно получены            if temp is not None and humd is not None:                plot_data(temp, humd)                            # Небольшая пауза, чтобы не нагружать процессор и дать время Arduino            time.sleep(0.1)                 except KeyboardInterrupt:        print("\nЗавершение работы...")    finally:        ser.close()if __name__ == "__main__":    main()

Обратите внимание!

На 4 строчке, если вы работаете на windows, то нужно поменять с /dev/ttyUSB0 на COMX(заменить на номер порта куда подключена ваша плата, можно посмотреть в ардуино иде)

Тесты

Всё исправно работает!

вывод данных

вывод данных

Завершение

Всё заработало — это успех.

Идеи по доработке:

  1. Поставить датчик давления(bmp280)

  2. сделать GUI, например на PyQt6 + Qt creator

Спасибо за внимание!

ссылка на оригинал статьи https://habr.com/ru/articles/1055066/