От данных к графику: создание IoT-панели на Flask‑SQLite с Raspberry Pi
Сбор реальных данных с датчика DHT22, их сохранение в легкой базе SQLite и визуализация результатов на веб-панели, построенной на Flask.
1. Введение
В предыдущем уроке, Python WebServer With Flask and Raspberry Pi, мы научились отдавать данные датчика через веб-фронтенд. Логичный следующий шаг — сохранять показания для последующего анализа.
2. Необходимые материалы
- Raspberry Pi 3 – $32.00
- Датчик температуры и влажности DHT22 – $9.95
- Подтягивающий резистор 4.7 кОм
3. Установка SQLite
SQLite — идеальный движок БД для одноплатника: бессерверный, легкий, полностью открытый. Установите:
sudo apt-get install sqlite3 Затем создайте рабочую директорию и файл БД:
mkdir Sensors_Database cd Sensors_Database sqlite3 sensorsData.db Когда появится приглашение SQLite, выйдите командой .quit и вернетесь в шелл.
4. Создание таблицы DHT
Таблица DHT_data хранит временную метку, температуру и влажность.
sqlite3 sensorsData.db BEGIN; CREATE TABLE DHT_data (timestamp DATETIME, temp NUMERIC, hum NUMERIC); COMMIT; Альтернативно, через Python:
import sqlite3 con = sqlite3.connect('sensorsData.db') with con: cur = con.cursor() cur.execute('DROP TABLE IF EXISTS DHT_data') cur.execute('CREATE TABLE DHT_data(timestamp DATETIME, temp NUMERIC, hum NUMERIC)') 5. Вставка примеров строк
Ручная вставка через SQLite:
INSERT INTO DHT_data VALUES(datetime('now'), 20.5, 30); Или массовая вставка в Python:
with con: cur.execute('INSERT INTO DHT_data VALUES(datetime('now'), 20.5, 30)') cur.execute('INSERT INTO DHT_data VALUES(datetime('now'), 25.8, 40)') cur.execute('INSERT INTO DHT_data VALUES(datetime('now'), 30.3, 50)') 6. Подключение DHT22
Соедините VCC с 3.3 В, Data с GPIO 16, GND с землей, и поставьте подтягивающий резистор 4.7 кОм между VCC и Data.
7. Установка библиотеки Adafruit DHT
Скачайте с GitHub и установите:
sudo python3 setup.py install 8. Чтение и логирование данных
Минимальный скрипт, читающий датчик, округляющий значения и пишущий их в БД:
import time import sqlite3 import Adafruit_DHT DB_NAME = 'sensorsData.db' SAMPLE_FREQ = 120 # seconds DHT_SENSOR = Adafruit_DHT.DHT22 DHT_PIN = 16 def read_and_log(): humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN) if humidity is not None and temperature is not None: humidity = round(humidity) temperature = round(temperature, 1) conn = sqlite3.connect(DB_NAME) cur = conn.cursor() cur.execute('INSERT INTO DHT_data VALUES(datetime('now'), ?, ?)', (temperature, humidity)) conn.commit() conn.close() for _ in range(3): read_and_log() time.sleep(SAMPLE_FREQ) 9. Непрерывное логирование
Для реального логгера запустите в отдельном терминале. Делает замер каждую минуту:
import time, sqlite3, Adafruit_DHT DB = 'sensorsData.db' SAMPLE_FREQ = 60 while True: humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 16) if humidity is not None and temperature is not None: conn = sqlite3.connect(DB) cur = conn.cursor() cur.execute('INSERT INTO DHT_data VALUES(datetime('now'), ?, ?)', (round(temperature,1), round(humidity))) conn.commit() conn.close() time.sleep(SAMPLE_FREQ) 10. Запросы к базе
Типичные запросы:
- Все строки:
SELECT * FROM DHT_data - Последняя запись:
SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1 - Температура > 30 °C:
SELECT * FROM DHT_data WHERE temp > 30 - Влажность = 29 %:
SELECT * FROM DHT_data WHERE hum = 29
11. Веб-сервер Flask
Установите Flask: sudo apt-get install python3-flask. Создайте структуру проекта:
mkdir dhtWebServer cd dhtWebServer mkdir templates static В appDhtWebServer.py:
from flask import Flask, render_template import sqlite3 app = Flask(__name__) def fetch_latest(): conn = sqlite3.connect('../sensorsData.db') cur = conn.cursor() cur.execute('SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1') row = cur.fetchone() conn.close() return row @app.route('/') def index(): time, temp, hum = fetch_latest() return render_template('index.html', time=time, temp=temp, hum=hum) if __name__ == '__main__': app.run(host='0.0.0.0', port=80, debug=False) Шаблон templates/index.html:
<!DOCTYPE html> <html> <head> <title>DHT Sensor Dashboard</title> <link rel='stylesheet' href='../static/style.css'> </head> <body> <h1>DHT Sensor Data</h1> <p>Temperature: {{ temp }} °C</p> <p>Humidity: {{ hum }} %</p> <p>Last reading: {{ time }}</p> <a href='/' class='button'>Refresh</a> </body> </html> 12. Улучшение фронтенда с датчиками (Gauges)
Скачайте JustGage и положите justgage.js и raphael-2.1.4.min.js в static. Обновите шаблон для анимированных датчиков:
<div id='g1'></div> <div id='g2'></div> <script src='../static/raphael-2.1.4.min.js'></script> <script src='../static/justgage.js'></script> <script> new JustGage({id:'g1', value:{{ temp }}, min:-10, max:50, title:'Temperature', label:'°C'}); new JustGage({id:'g2', value:{{ hum }}, min:0, max:100, title:'Humidity', label:'%'}); </script> 13. Исторические графики с Matplotlib
Установите Matplotlib: sudo apt-get install python3-matplotlib. Создайте новый Flask-приложение appDhtWebHist.py, отдающее PNG-графики на лету.
from flask import Flask, render_template, make_response from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas from matplotlib.figure import Figure import sqlite3, io app = Flask(__name__) DB = '../sensorsData.db' def get_latest(): conn = sqlite3.connect(DB) cur = conn.cursor() cur.execute('SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1') row = cur.fetchone() conn.close() return row def get_history(samples): conn = sqlite3.connect(DB) cur = conn.cursor() cur.execute('SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT ?', (samples,)) rows = cur.fetchall() conn.close() rows.reverse() # хронологический порядок times, temps, hums = zip(*rows) return times, temps, hums @app.route('/') def index(): time, temp, hum = get_latest() return render_template('index.html', time=time, temp=temp, hum=hum, samples=100) @app.route('/plot/temp') def plot_temp(): times, temps, _ = get_history(100) fig = Figure() ax = fig.add_subplot(1,1,1) ax.plot(range(len(temps)), temps) ax.set_title('Temperature (°C)') canvas = FigureCanvas(fig) output = io.BytesIO() canvas.print_png(output) return make_response(output.getvalue(), 200, {'Content-Type':'image/png'}) @app.route('/plot/hum') def plot_hum(): _, _, hums = get_history(100) fig = Figure() ax = fig.add_subplot(1,1,1) ax.plot(range(len(hums)), hums) ax.set_title('Humidity (%)') canvas = FigureCanvas(fig) output = io.BytesIO() canvas.print_png(output) return make_response(output.getvalue(), 200, {'Content-Type':'image/png'}) if __name__ == '__main__': app.run(host='0.0.0.0', port=80, debug=False) Шаблон templates/index.html включает два тега <img>, запрашивающие PNG-маршруты.
14. Заключение
Этот комплексный проект показывает, как превратить дешевый датчик в платформу логирования и мониторинга: захват, сохранение, запрос и визуализация всего через локальный Flask-веб-сервер. Весь исходный код доступен на GitHub и дальнейшие примеры на MJRoBot.org.
Производственный процесс
- Безопасное хранение и управление чувствительными данными с Google Cloud Secret Manager
- Microchip представляет 24-бит и 16-бит Delta-Sigma ADC с 153.6 кSPS data rates
- Домашний монитор температуры и влажности на Raspberry Pi с веб-дашбордом — удаленный трекинг в реальном времени
- Создание робота на Raspberry Pi и Python: полное руководство
- Ускорение цифровой трансформации: Edge-to-Cloud IoT платформа Cisco & IBM
- От Edge к Cloud: мастерство IoT data pipelines
- Удаленная телеметрия: фундамент успешного IIoT-развертывания
- Оживление IoT с IBM и Tech Data — Часть 2
- Превращение IoT в реальность: инсайты Tech Data и IBM — Часть 1
- Максимизация бизнес-ценности через интеграцию Big Data и AI