Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

От данных к графику:веб-путешествие с Flask и SQLite

Сбор реальных данных (RPi / DHT22), сохранение их в базе данных (SQLite), создание графиков (Matplotlib) и их представление на веб-странице (Flask).

Введение:от данных к графику. веб-путешествие с Flask и SQLite

В моем предыдущем руководстве Python WebServer с Flask и Raspberry Pi мы узнали, как взаимодействовать с физическим миром через интерфейсную веб-страницу, созданную с помощью Flask. Итак, следующий естественный шаг - собрать данные из реального мира, чтобы они были доступны для нас на веб-странице. Очень простой! Но что произойдет, если, например, мы захотим узнать, какая была ситуация накануне? Или провести какой-то анализ с этими данными? В таких случаях данные также должны храниться в базе данных.

Короче говоря, в этом новом руководстве мы:

Захват реальных данных (температура и относительная влажность воздуха) с помощью датчика DHT22; Загрузите эти данные в локальной базе данных , построенный с помощью SQLite; Создать графику с историческими данными используя Matplotlib; Показать данные с анимированными «датчиками», созданными с помощью JustGage; Сделайте все доступным в Интернете через локальный веб-сервер, созданный с помощью Python и Flask;

Блок-схема дает нам представление обо всем проекте:

Шаг 1:BoM - Bill of Materials

Шаг 2. Установка SQLite

Хорошо, общая идея состоит в том, чтобы собрать данные с датчика и сохранить их в базе данных.

Но какой «движок» базы данных следует использовать?

На рынке есть много вариантов, и, вероятно, 2 наиболее часто используемых с Raspberry Pi и датчиками - это MySQL и SQLite. MySQL очень известен, но немного «тяжел» для использования в простых проектах на базе Raspberry (кроме того, он принадлежит Oracle!). SQLite, вероятно, является наиболее подходящим выбором. Потому что он бессерверный, легкий, с открытым исходным кодом и поддерживает большую часть кода SQL (его лицензия - «Public Domain»). Еще одна удобная вещь - SQLite хранит данные в одном файле, который можно хранить где угодно.

Но что такое SQLite?

SQLite - это система управления реляционными базами данных, содержащаяся в библиотеке программирования C. В отличие от многих других систем управления базами данных, SQLite не является механизмом базы данных клиент-сервер. Скорее, он встроен в конечную программу.

SQLite - популярное общественное достояние выбор в качестве встроенного программного обеспечения базы данных для локального / клиентского хранилища в прикладном программном обеспечении, таком как веб-браузеры. Это, пожалуй, наиболее широко распространенный механизм баз данных, поскольку он используется сегодня, среди прочего, несколькими широко распространенными браузерами, операционными системами и встроенными системами (такими как мобильные телефоны). SQLite привязан ко многим языкам программирования, таким как Python, который используется в нашем проекте.

(Подробнее в Википедии)

Мы не будем вдаваться в подробности здесь, но полную документацию по SQLite можно найти по этой ссылке:https://www.sqlite.org/docs.html

Быть по сему! Давайте установим SQLite на наш Pi

Установка:

Чтобы создать базу данных, выполните следующие действия.

1. Установите SQLite в Raspberry Pi с помощью команды:

  sudo apt-get install sqlite3  

2. Создайте каталог для разработки проекта:

  mkdir Sensors_Database  

3. Переместитесь в этот каталог:

  cd mkdir Sensors_Database /  

3. Дайте имя и создайте базу данных, например databaseName.db . (в моем случае «sensorData.db»):

  sqlite3 sizesData.db  

Появится «оболочка», в которую вы можете войти с помощью команд SQLite. Мы вернемся к нему позже.

  sqlite>  

Команды начинаются с символа «.», Например «.help», «.quit» и т. Д.

4. Закройте оболочку, чтобы вернуться в Терминал:

  sqlite> .quit  

На приведенном выше экране печати терминала показано, что было объяснено.

Вышеупомянутый «sqlite>» предназначен только для иллюстрации того, как будет выглядеть оболочка SQLite. Вам не нужно его вводить. Он появится автоматически.

Шаг 3. Создание и заполнение таблицы

Чтобы зарегистрировать данные измерений датчика DHT в базе данных, мы должны создать таблицу (база данных может содержать несколько таблиц). Наша таблица будет называться «DHT_data» и будет иметь 3 столбца, в которых мы будем регистрировать собранные данные:Дата и Час (имя столбца: отметка времени ), Температура (название столбца: temp ) и влажности (название столбца: шум ).

Создание таблицы:

Чтобы создать таблицу, вы можете сделать это:

1. Использование оболочки:

Откройте базу данных, созданную на последнем шаге:

  sqlite3 sizesData.db  

И ввод с помощью операторов SQL:

  sqlite> BEGIN; sqlite> СОЗДАТЬ ТАБЛИЦУ DHT_data (временная метка DATETIME, temp NUMERIC, hum NUMERIC); sqlite> COMMIT;  

Все операторы SQL должны заканчиваться на «;». Также обычно эти заявления пишутся заглавными буквами. Это не обязательно, но это хорошая практика.

2. Использование Python

  импортировать sqlite3 как liteimport syscon =lite.connect ('sizesData.db') с con:cur =con.cursor () cur.execute ("DROP TABLE IF EXISTS DHT_data ") cur.execute (" СОЗДАТЬ ТАБЛИЦУ DHT_data (временная метка DATETIME, temp NUMERIC, гудение NUMERIC) ")  

Откройте приведенный выше код из моего GitHub:createTableDHT.py

Запустите его на своем Терминале:

  python3 createTableDHT.py  

Где бы ни использовался метод, таблица должна быть создана. Вы можете проверить это в SQLite Shell, используя команду «.table». Откройте оболочку базы данных:

  sqlite3> sizesData.db  

В оболочке после использования .table отобразятся имена созданных таблиц (в нашем случае будет только одно:«DHT_table». После этого выйдите из оболочки, используя .quit команда.

  sqlite> .tableDHT_datasqlite> .quit  

Вставка данных в таблицу:

Давайте введем в нашу базу данных 3 набора данных, каждый из которых будет иметь по 3 компонента:(отметка времени, температура и шум). Компонент отметка времени будут реальны и взяты из системы с помощью встроенной функции «сейчас» и temp и гудеть - фиктивные данные в ° C и% соответственно.

Примечание что время указано в формате «UTC», что хорошо, потому что вам не нужно беспокоиться о проблемах, связанных с переходом на летнее время и другими вопросами. Если вы хотите вывести дату в локализованном времени, просто преобразуйте ее в соответствующий часовой пояс позже.

То же самое было сделано с созданием таблицы, вы можете вставлять данные вручную через оболочку SQLite или через Python. В оболочке вы бы сделали это, данные за данными, используя такие операторы SQL (в нашем примере вы сделаете это 3 раза):

  sqlite> ВСТАВИТЬ ЗНАЧЕНИЯ DHT_data (datetime ('now'), 20.5, 30);  

И в Python вы бы сделали то же самое, но сразу:

  импортировать sqlite3 как liteimport syscon =lite.connect ('sensorData.db') с con:cur =con.cursor () cur.execute ("ВСТАВИТЬ ЗНАЧЕНИЯ DHT_data (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) ")  

Откройте приведенный выше код из моего GitHub:insertTableDHT.py

Запустите его на терминале Pi:

  python3 insertTableDHT.py  

Чтобы убедиться, что приведенный выше код работает, вы можете проверить данные в таблице через оболочку с помощью оператора SQL:

  sqlite> SELECT * FROM DHT_DATA;  

На приведенном выше экране печати терминала показано, как будут выглядеть строки таблицы.

Шаг 4. Вставка и проверка данных с помощью Python

Для начала давайте сделаем то же самое, что и раньше (ввод и получение данных), но сделаем и то, и другое с помощью python, а также распечатаем данные на терминале:

  import sqlite3import sysconn =sqlite3.connect ('sizesData.db') curs =conn.cursor () # функция для вставки данных в tabledef add_data (temp, hum) :curs.execute ("INSERT INTO DHT_data values ​​(datetime ('now'), (?), (?))", (temp, hum)) conn.commit () # вызвать функцию для вставки данныхadd_data (20.5, 30 ) add_data (25.8, 40) add_data (30.3, 50) # печать содержимого базы данных ("\ nВсе содержимое базы данных:\ n") для строки в curs.execute ("SELECT * FROM DHT_data"):print (row) # закрыть база данных после useconn.close ()  

Откройте приведенный выше код из моего GitHub:insertDataTableDHT.py и запустите его на своем терминале:

  python3 insertDataTableDHT.py  

На приведенном выше экране печати терминала показан результат.

Шаг 5. Датчик температуры и влажности DHT22

Пока что мы создали таблицу в нашей базе данных, в которой будем сохранять все данные, которые будет считывать датчик. Мы также ввели туда фиктивные данные. Теперь пришло время использовать реальные данные для сохранения в нашей таблице температуры воздуха и относительной влажности. Для этого мы будем использовать старый и хороший DHTxx (DHT11 или DHT22). Сайт ADAFRUIT предоставляет отличную информацию об этих датчиках. Ниже приводится информация, полученная оттуда:

Обзор

Недорогие датчики температуры и влажности DHT очень простые и медленные, но отлично подходят для любителей, которые хотят выполнить базовую регистрацию данных. Датчики DHT состоят из двух частей:емкостного датчика влажности и термистора. Внутри также находится очень простой чип, который выполняет некоторое аналого-цифровое преобразование и выдает цифровой сигнал с температурой и влажностью. Цифровой сигнал довольно легко считывается с помощью любого микроконтроллера.

DHT11 против DHT22

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

DHT11 (обычно синий)

Подходит для показаний влажности 20-80% с точностью 5%. Подходит для показаний температуры 0-50 ° C с точностью ± 2 ° C. Частота дискретизации не более 1 Гц (один раз в секунду)

DHT22 (обычно белый)

Подходит для показаний влажности 0-100% с точностью 2-5% Подходит для показаний температуры от -40 до 125 ° C с точностью ± 0,5 ° C Частота дискретизации не более 0,5 Гц (один раз в 2 секунды)

Как видите, DHT22 немного точнее и хорош в чуть большем диапазоне. Оба используют один цифровой контакт и работают «медленно» в том смысле, что вы не можете запрашивать их чаще, чем раз в секунду (DHT11) или два раза (DHT22).

Оба датчика будут работать нормально, сохраняя информацию внутри помещения в нашей базе данных.

DHTxx имеет 4 контакта (обращенный к датчику, контакт 1 - крайний левый):

В нашем проекте мы будем использовать DHT22.

Как только вы обычно будете использовать датчик на расстоянии менее 20 м, между выводами Data и VCC необходимо подключить резистор 4K7 Ом. Вывод данных выхода DHT22 будет подключен к Raspberry GPIO 16.

Проверьте приведенную выше электрическую схему подключения датчика к контактам RPi, как показано ниже:

Не забудьте установить резистор 4K7 Ом между выводами Vcc и Data. После подключения датчика мы также должны установить его библиотеку на наш RPi. Мы сделаем это на следующем шаге.

Шаг 6. Установка библиотеки DHT

На Raspberry, начиная с / home, перейдите в / Documents:

  документы на компакт-диске  

Создайте каталог для установки библиотеки и перейдите туда:

  mkdir DHT22_Sensorcd DHT22_Sensor  

В своем браузере перейдите на Adafruit GITHub:https://github.com/adafruit/Adafruit_Python_DHT

Загрузите библиотеку, щелкнув ссылку загрузки zip справа, и распакуйте архив в недавно созданной папке Raspberry Pi. Затем перейдите в каталог библиотеки (подпапка, которая автоматически создается при распаковке файла) и выполните команду:

  sudo python3 setup.py install  

Откройте тестовую программу (DHT22_test.py) с моего GITHUB:

  import Adafruit_DHTDHT22Sensor =Adafruit_DHT.DHT22DHTpin =16humidity, temperature =Adafruit_DHT.read_retry (DHT22Sensor, DHTpin), если влажность не None и температура не None:print ('Temp ={0:0.1f} * C Humidity ={1:0.1f}% '. Format (температура, влажность)) else:print (' Не удалось получить показания. Повторите попытку! ')  

Запустите программу с помощью команды:

  python3 DHT22_test.py  

На приведенном выше экране печати терминала показан результат.

Шаг 7. Сбор реальных данных

Теперь, когда у нас есть и датчик, и наша база данных, все установлено и настроено, пора читать и сохранять реальные данные.

Для этого мы будем использовать код:

  import timeimport sqlite3import Adafruit_DHTdbname ='sensorData.db'sampleFreq =2 # время в секундах # получение данных из DHT sensordef getDHTdata ():DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 hum, temp =Adafruit_DHT.read_retry (DHT22Sensor, DHTpin), если шум не равен None, а temp не равен None:hum =round (hum) temp =round (temp, 1) logData (temp, hum) # записать данные датчика в databasedef logData (temp, hum):conn =sqlite3.connect (dbname) curs =conn.cursor () curs.execute ("INSERT INTO DHT_data values ​​(datetime ('now'), (?), (?))", (temp , hum)) conn.commit () conn.close () # отображение данных базы данныхdef displayData ():conn =sqlite3.connect (dbname) curs =conn.cursor () print ("\ nВсе содержимое базы данных:\ n") для строка в curs.execute ("SELECT * FROM DHT_data"):print (row) conn.close () # main functiondef main ():for i in range (0,3):getDHTdata () time.sleep (sampleFreq) displayData () # Выполнить программу main ()  

Откройте указанный выше файл из моего GitHub:appDHT.py и запустите его на своем Терминале:

  python3 appDHT.py  

Функция getDHTdata () захватывает 3 образца датчика DHT, проверяет их на наличие ошибок и, если все в порядке, сохраняет данные в базе данных с помощью функции logData (temp, hum) . Последняя часть кода вызывает функцию displayData () который печатает все содержимое нашей таблицы в Терминале.

На приведенном выше экране печати показан результат. Обратите внимание, что последние 3 строки (строки) - это реальные данные, полученные с помощью этой программы, а 3 предыдущие строки были теми, которые ранее были введены вручную.

На самом деле appDHT.py - плохое имя. Как правило, appSomething.py используется со скриптами Python на веб-серверах, как мы увидим далее в этом руководстве. Но, конечно, вы можете использовать это здесь.

Шаг 8. Автоматический сбор данных

На этом этапе мы должны реализовать механизм для автоматического чтения и вставки данных в нашу базу данных, наш «Регистратор».

Откройте новое окно терминала и введите следующий код Python:

  import timeimport sqlite3import Adafruit_DHTdbname ='sensorData.db'sampleFreq =1 * 60 # время в секундах ==> Выборка каждые 1 мин # получение данных из DHT sensordef getDHTdata () :DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 гул, temp =Adafruit_DHT.read_retry (DHT22Sensor, DHTpin), если гул не равен None, а темп не равен None:hum =round (гул) temp =round (temp, 1) вернуть темп, гул # записать данные датчика в базу данных ?)) ", (temp, hum)) conn.commit () conn.close () # main functiondef main ():while True:temp, hum =getDHTdata () logData (temp, hum) time.sleep (sampleFreq) # ------------ Выполнить программу main ()  

Или получите его с моего GitHub:logDHT.py. Запустите его в Терминале:

  python3 logDHT.py  

Что делает функция main ():

Вызов функции getDHTdata () , который вернет данные, полученные датчиком DHT22. Возьмите эти данные (температуру и влажность) и передайте их другой функции: logData (temp, hum) которые вставляют их вместе с фактической датой и временем в нашу таблицу. И переходит в спящий режим, ожидая следующего запланированного времени для сбора данных (определяется параметром sampleFreq , что в этом примере составляет 1 минуту).

Оставьте окно Терминала открытым.

Например, до тех пор, пока вы не завершите программу нажатием [Ctr + z], программа будет постоянно захватывать данные, передавая их в нашу базу данных. Я оставил его работать на некоторое время с периодичностью в 1 минуту, чтобы быстрее заполнить базу данных, и изменил частоту через несколько часов на 10 минут.

Существуют и другие механизмы, гораздо более эффективные для выполнения такого «автоматического журнала», чем использование «time.sleep», но приведенный выше код отлично подойдет для нашей цели. В любом случае, если вы хотите реализовать лучший «планировщик», вы можете использовать Crontab , который представляет собой удобный инструмент UNIX для планирования заданий. Хорошее объяснение того, что такое Crontab, можно найти в этом руководстве:«Планирование задач в Linux с помощью Crontab» Кевина ван Зонневельда.

Шаг 9. Запросы

Теперь, когда наша база данных загружается автоматически, мы должны найти способы работать со всеми этими данными. Мы делаем это с помощью запросов!

Что такое запрос?

Одна из наиболее важных особенностей работы с языком SQL над базами данных - это возможность создавать «запросы к базе данных». Другими словами, запросы извлекают данные из базы данных, форматируя их в удобочитаемой форме. Запрос должен быть написан на языке SQL . , который использует SELECT оператор для выбора конкретных данных.

Фактически, мы использовали его «в широком смысле» на последнем шаге:«SELECT * FROM DHT_data».

Примеры:

Давайте создадим несколько запросов к данным в таблице, которую мы уже создали. Для этого введите следующий код:

  import sqlite3conn =sqlite3.connect ('sizesData.db') curs =conn.cursor () maxTemp =27.6print ("\ nВсе содержимое базы данных:\ n") для строки в curs.execute ("SELECT * FROM DHT_data"):print (row) print ("\ nЗаписи базы данных для определенного значения влажности:\ n") для строки в curs.execute ("SELECT * FROM DHT_data WHERE hum ='29' "):print (row) print (" \ nЗаписи базы данных, где температура выше 30oC:\ n ") для строки в curs.execute (" SELECT * FROM DHT_data WHERE temp>
 30.0 "):print (row) print ("\ nЗаписи базы данных, где температура выше x:\ n") для строки в curs.execute ("SELECT * FROM DHT_data WHERE temp>
 (?)", (maxTemp,)):print (row)  

Или получите его с моего GitHub:queryTableDHT.py и запустите в Терминале:

  python3 queryTableDHT.py  

Вы можете увидеть результат на экране печати Терминала выше. Это простые примеры, чтобы дать вам представление о запросах. Найдите время, чтобы понять операторы SQL в приведенном выше коде.

Если вы хотите узнать больше о языке SQL, хорошим источником является W3School SQL Tutorial.

Шаг 10. Последние данные, введенные в таблицу:

Очень важный запрос - получить последние введенные данные . (или вошли) на стол. Мы можем сделать это прямо в оболочке SQLite с помощью команды:

  sqlite> SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1;  

Или запустите простой код Python, как показано ниже:

  import sqlite3conn =sqlite3.connect ('sizesData.db') curs =conn.cursor () print ("\ nПоследние данные, зарегистрированные в базе данных:\ n") для строка в curs.execute ("ВЫБРАТЬ * ИЗ DHT_data ORDER BY timestamp DESC LIMIT 1"):print (row)  

Вы можете увидеть результат на первом экране печати Терминала выше.

Обратите внимание, что результат будет представлен в виде «кортежа значений»:(«отметка времени», темп, шум).

Кортеж вернул содержимое последней строки нашей таблицы, состоящей из трех элементов:

Итак, мы можем улучшить наш код, чтобы получать «чистые» данные из таблицы, например:

  import sqlite3conn =sqlite3.connect ('sizesData.db') curs =conn.cursor () print ("\ nПоследние необработанные данные, зарегистрированные в базе данных:\ n") для строки в curs.execute ("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):print (str (row [0]) + "==> Temp =" + str (row [1]) + "Hum ="+ str (строка [2]))  

Откройте файл с моего GitHub:lastLogDataTableDHT.py и запустите его в Терминале:

  python3 lastLogDataTableDHT.py  

Вы можете увидеть результат на втором экране печати терминала выше.

Шаг 11. Веб-интерфейс для визуализации данных

В моем последнем руководстве:Python WebServer с Flask и Raspberry Pi мы узнали, как реализовать веб-сервер (используя Flask) для сбора данных с датчиков и отображения их статуса на веб-странице.

Этого мы и здесь хотим добиться. Разница заключается в данных, которые будут отправлены на наш интерфейс, которые будут взяты из базы данных . а не напрямую с датчиков, как мы делали в этом руководстве.

Создание среды веб-сервера:

Первое, что нужно сделать, это установить Flask на Raspberry Pi. Если у вас его нет, зайдите в Терминал и введите:

  sudo apt-get install python3-flask  

Лучшее, когда вы начинаете новый проект, - это создать папку, в которой будут организованы ваши файлы. Например:

Из дома перейдите в наш рабочий каталог:

  cd Documents / Sensors_Database  

Создайте новую папку, например:

  mkdir dhtWebServer  

Приведенная выше команда создаст папку с именем «dhtWebServer», в которой мы будем сохранять наши скрипты python:

  / home / pi / Documents / Sensor_Database / rpiWebServer  

Теперь в этой папке создадим две подпапки: static для CSS и, возможно, файлов JavaScript и шаблонов для файлов HTML . Перейдите в новую созданную папку:

  cd dhtWebServer  

И создайте 2 новые подпапки:

  mkdir static  

и

  шаблоны mkdir  

Окончательное «дерево» каталогов будет выглядеть так:

  ├── Sensors_Database ├── sizesData.db ├── logDHT.py ├── dhtWebSensor ├── templates └── static  

Мы оставим нашу созданную базу данных в каталоге / Sensor_Database, поэтому вам нужно будет подключить SQLite с «../sensorsData.db».

В ПОРЯДКЕ! Создав нашу среду, давайте соберем части и создадим наше приложение Python WebServer . . Приведенная выше диаграмма дает нам представление о том, что нужно делать!

Шаг 12. Приложение Python WebServer

Начиная с последней диаграммы, давайте создадим веб-сервер на Python с помощью Flask. Я предлагаю Geany в качестве IDE, как только вы сможете работать одновременно с разными типами файлов (.py, .html и .css).

Приведенный ниже код представляет собой сценарий Python, который будет использоваться на нашем первом веб-сервере:

  from flask import Flask, render_template, requestapp =Flask (__ name __) import sqlite3 # Получить данные из databasedef getData ():conn =sqlite3.connect ('../ sensorData .db ') curs =conn.cursor () для строки в curs.execute ("ВЫБРАТЬ * ИЗ DHT_data ORDER BY timestamp DESC LIMIT 1"):time =str (row [0]) temp =row [1] hum =row [2] conn.close () return time, temp, hum # main route @ app.route ("/") def index ():time, temp, hum =getData () templateData ={'time':time, ' temp ':temp,' hum ':hum} return render_template (' index.html ', ** templateData) if __name__ =="__main__":app.run (host =' 0.0.0.0 ', port =80, debug =Ложь)  

Вы можете получить скрипт python appDhtWebServer.py с моего GitHub. Приведенный выше код делает следующее:

С помощью этого запроса первое, что делается в коде, - это берет данные из базы данных с помощью функции time, temp, hum =getData (). Эта функция в основном представляет собой тот же запрос, который использовался ранее для получения данных, хранящихся в таблице. Имея под рукой данные, наш скрипт возвращается на веб-страницу ( index.html ): время , темп и гудеть в ответ на предыдущий запрос.

Итак, давайте посмотрим на index.html и style.css файлы, которые будут использоваться для создания нашего интерфейса:

index.html

     Данные датчика DHT     

Данные датчика DHT

TEMPERATURE ==> {{tempLab}} oC

ВЛАЖНОСТЬ (отн.) ==> { {humLab}}%


Последнее считывание датчиков:{{time}} ==> REFRESH


@ 2018 Разработано MJRoBot.org

Вы можете получить файл index.html с моего GitHub.

style.css

  body {background:blue; цвет:желтый; отступ:1%}. button {font:bold 15px Arial; текстовое оформление:нет; цвет фона:#EEEEEE; цвет:# 333333; отступ:2px 6px 2px 6px; верхняя граница:сплошной 1px #CCCCCC; граница справа:сплошной 1px # 333333; нижняя граница:твердое тело 1px # 333333; border-left:1px solid #CCCCCC;}  

Вы можете получить файл style.css с моего GitHub. Файлы должны быть размещены в вашем каталоге следующим образом:

  ├── Sensors_Database ├── sizesData.db ├── logDHT.py ├── dhtWebSensor ├── appDhtWebSensor.py ├── templates │ ├── index .html └── статический ├── style.css  

Теперь запустите скрипт python в Терминале:

  sudo python3 appDhtWebServer.py  

Откройте любой браузер в вашей сети и введите http:// YOUR_RPI_IP (например, в моем случае:http://10.0.1.27)

На приведенном выше экране печати показано то, что вы должны видеть. ПРИМЕЧАНИЕ. Если вы не уверены в своем IP-адресе RPi, запустите на своем терминале:

  ifconfig  

Вы найдете его в разделе wlan0 :. В моем случае:10.0.1.27

Шаг 13:Делаем наш веб-интерфейс более привлекательным!

Давайте познакомимся с некоторыми датчиками, чтобы лучше представить фактические значения температуры и влажности. Обратите внимание, что наш скрипт Python не изменится, но использование JustGage в наших файлах html / css значительно улучшит представление данных.

Что такое JustGage?

JustGage - удобный плагин JavaScript для создания и анимации красивых и чистых датчиков. Он основан на библиотеке Raphaël для векторной графики, поэтому полностью независим от разрешения и саморегулируется, работает практически в любом браузере.

Установка:

justgage-1.2.2.zip

      Датчик данных DHT       

Данные датчика DHT


Последнее считывание датчиков:{{time}} ==> REFRESH


@ 2018 Разработано MJRoBot.org

Загрузите с моего GitHub файл index_gage.html и переименуйте его в index.html (не забудьте переименовать предыдущий с другим именем, например, index_txt.html, если хотите его оставить).

Окончательное дерево каталогов должно выглядеть следующим образом:

  ├── Sensors_Database ├── sizesData.db ├── logDHT.py ├── dhtWebServer ├── appDhtWebServer.py ├── templates │ ├── index .html └── static ├── style.css ├── justgage.js ├── raphael-2.1.4.min.js  

Нажмите [Crl-C] на вашем Терминале, чтобы выйти из appDhtWebServer.py и просто запустите его снова. Когда вы обновите страницу в браузере, вы должны увидеть показанный выше экран для печати. ​​

Посмотрите файлы примеров, которые вы скачали с сайта JustGage. Попробуйте внести изменения в свои датчики. Это очень просто.

Шаг 14:Полный процесс

Приведенная выше диаграмма является резюме того, что мы сделали до сих пор:2 отдельных скрипта, работающих параллельно, выполняющих свои задачи независимо:

Сбор данных датчиком и загрузка их в базу данных ( logDHT.py ) Найдите данные в базе данных и представьте их в веб-интерфейсе ( appDhtWebServer.py ).

В общем, наш проект сбора данных, сохранения их в базе данных и отображения этих данных на веб-странице завершен. Но нет смысла иметь базу данных с историческими данными и использовать ее только для последних собранных данных. Мы должны играть с историческими данными, и самое простое, что нужно сделать, - это представить их на графике. Поехали!

Шаг 15. Построение графика исторических данных

Очень хорошей библиотекой для графических данных является Matplotlib , that is a Python 2D plotting library which produces publication quality figures in a variety of hardcopy formats and interactive environments across platforms.

To install matplotlib , run the command below on your Terminal:

sudo apt-get install python3-matplotlib 

Before we start, let’s create a new environment, where we will save the new application to be developed: appDhtWebHist.py  and its correspondent index.html  and style.css

├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebHist ├── appDhtWebHist.py ├── templates │ ├── index.html └── static ├── style.css  

Create the new 3 directories (dhtWebHist; /templates  and /static ) same as we did before and open from my GitHub the 3 files below:

1. appDhtWebHist.py

from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfrom matplotlib.figure import Figureimport iofrom flask import Flask, render_template, send_file, make_response, requestapp =Flask(__name__)import sqlite3conn=sqlite3.connect('../sensorsData.db')curs=conn.cursor()# Retrieve LAST data from databasedef getLastData():for row in curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):time =str(row[0]) temp =row[1] hum =row[2] #conn.close() return time, temp, humdef getHistData (numSamples):curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT "+str(numSamples)) data =curs.fetchall() dates =[] temps =[] hums =[] for row in reversed(data):dates.append(row[0]) temps.append(row[1]) hums.append(row[2]) return dates, temps, humsdef maxRowsTable():for row in curs.execute("select COUNT(temp) from DHT_data"):maxNumberRows=row[0] return maxNumberRows# define and initialize global variablesglobal numSamplesnumSamples =maxRowsTable() if (numSamples> 101):numSamples =100# main [email protected]("/")def index():time, temp, hum =getLastData() templateData ={ 'time' :time, 'temp' :temp, 'hum' :hum, 'numSamples' :numSamples } return render_template('index.html', **templateData)@app.route('/', methods=['POST'])def my_form_post():global numSamples numSamples =int (request.form['numSamples']) numMaxSamples =maxRowsTable() if (numSamples> numMaxSamples):numSamples =(numMaxSamples-1) time, temp, hum =getLastData() templateData ={ 'time' :time, 'temp' :temp, 'hum' :hum, 'numSamples' :numSamples } return render_template('index.html', **templateData)@app.route('/plot/temp')def plot_temp():times, temps, hums =getHistData(numSamples) ys =temps fig =Figure() axis =fig.add_subplot(1, 1, 1) axis.set_title("Temperature [°C]") axis.set_xlabel("Samples") axis.grid(True) xs =range(numSamples) axis.plot(xs, ys) canvas =FigureCanvas(fig) output =io.BytesIO() canvas.print_png(output) response =make_response(output.getvalue()) response.mimetype ='image/png' return [email protected]('/plot/hum')def plot_hum():times, temps, hums =getHistData(numSamples) ys =hums fig =Figure() axis =fig.add_subplot(1, 1, 1) axis.set_title("Humidity [%]") axis.set_xlabel("Samples") axis.grid(True) xs =range(numSamples) axis.plot(xs, ys) canvas =FigureCanvas(fig) output =io.BytesIO() canvas.print_png(output) response =make_response(output.getvalue()) response.mimetype ='image/png' return responseif __name__ =="__main__":app.run(host='0.0.0.0', port=80, debug=False) 

A new function was created here: getHistData (numSamples) , that receives as a parameter the number of rows that should be taken from the database. Basically, it is very similar to getLastData(), where numSamples  was “1”. Of course, now we must “append” the return array for all required rows.

In fact, we could use only this last function for both tasks.

The number of samples is set by default as 100, at the beginning (if there are more them 100 rows into the database) and also received it as an input from the webpage, during normal operation. When we receive the number of samples to be retrieved, we must also check if it is lower than the maximum number of rows in the database (otherwise we will get an error). The function maxRowsTable() , returns this number.

With the historical data in hand: times, temps  and hums  that are arrays, we must build the graphs saving them as a .png ímage . Those images will be the return for the routes:

@app.route(‘/plot/temp’)  and @app.route(‘/plot/hum’).

The request for the images is done by index.html, by the IMG TAG.

2. index.html

  DHT Sensor data     

DHT Sensor Data

TEMPERATURE ==> {{ temp }} oC

HUMIDITY (Rel.) ==> {{ hum }} %


Last Sensors Reading:{{ time }} ==> REFRESH


HISTORICAL DATA

Enter number of samples to retrieve:


Image Placeholder Image Placeholder

@2018 Developed by MJRoBot.org

3. style.css

body{ background:blue; color:yellow; padding:1%}.button { font:bold 15px Arial; текстовое оформление:нет; background-color:#EEEEEE; color:#333333; padding:2px 6px 2px 6px; border-top:1px solid #CCCCCC; border-right:1px solid #333333; border-bottom:1px solid #333333; border-left:1px solid #CCCCCC;}img{ display:display:inline-block} 

The above print screen shows the result.

Step 16:Including Gage on History Webpage

If instead of text, you want also to include gages to display the actual data, you must have the 2 .js files that you have used before on /static and change the index.html file on /templates:

Below how the directory tree looks like:

├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebHist ├── appDhtWebHist.py ├── templates │ ├── index.html └── static ├── style.css ├── justgage.js ├── raphael-2.1.4.min.js 

From my GitHub, open index_gage.html and rename it index.html. Replace the actual index.html (text version) and voilá! You will get a beautiful webpage, showing as gages the last captured data of temperature and humidity by the DHT22 and the historical graphs of those data.

Press[Crl-C] on your Terminal to Quit appDhtWebServer.py and just start it again. When you refresh your browser you must see the above print screen.

Step 17:Retrieving Data by Time Instead of Samples

So far we have build our graphics based on historical data, sending as a input parameter the numbers of samples to be retrieved from our database. Alternatively we could use as a parameter the number of past minutes that we want to show on a graph.

In order to do that, the first thing to know is the frequency of logged data on our database. Remember that this task is done for an independent program (in our case, logDHT.py ). One simple way to finfd this frequency is to retrieve the last 2 data logged on database and subtracting their correspondent timeStamp data:

in general terms: frequency =timeStamp(1) – timeStamp(0)

The function below does the work for us, using “datetime.striptime()”:

# Get sample frequency in minutesdef freqSample():times, temps, hums =getHistData (2) fmt ='%Y-%m-%d %H:%M:%S' tstamp0 =datetime.strptime(times[0], fmt) tstamp1 =datetime.strptime(times[1], fmt) freq =tstamp1-tstamp0 freq =int(round(freq.total_seconds()/60)) return (freq) 

Once we we have this frequency parameter in minutes, we will show it on index.html and asking for a “rangeTime” number of minutes to be send back to our server ==> @app.route(‘/’, methods=[‘POST’]):

@app.route('/', methods=['POST'])def my_form_post():global numSamples global freqSamples global rangeTime rangeTime =int (request.form['rangeTime']) if (rangeTime  numMaxSamples):numSamples =(numMaxSamples-1) 

The picture shows the result:

Eliminating Possible errors when constructing the graphs:

Ocasionally, strange (or corrupted) data can be storaged on database, jeopardizing our analysis. Those data can be verified (or cleaneed) on several places (like during the time sensor are capturing the data, etc). But once the script that display data is independent of the one that logged the data, let’s “cap” the maximum and minimum values of our sensors, before using the data to buit the graphs. This can be achieved with the function testData(temps, hums) :

# Test data for cleanning possible "out of range" valuesdef testeData(temps, hums):n =len(temps) for i in range(0, n-1):if (temps[i] <-10 or temps[i]>50):temps[i] =temps[i-2] if (hums[i] <0 or hums[i]>100):hums[i] =temps[i-2] return temps, hums 

The scripts for this new version can be download from my GitHub: dhtWebHist_v2

Step 18:Conclusion

As always, I hope this project can help others find their way into the exciting world of electronics!

For details and final code, please visit my GitHub depository: RPI-Flask-SQLite

For more projects, please visit my blog: MJRoBot.org

Saludos from the south of the world!

See you at my next tutorial!

Thank you,

Source:From Data to Graph:A Web Journey With Flask and SQLite


Производственный процесс

  1. Хранение конфиденциальных данных и управление ими с помощью диспетчера секретов
  2. Микрочип:24-битные и 16-битные АЦП со скоростью передачи данных до 153,6 kSPS
  3. Монитор температуры и влажности в домашних условиях (в комнате) с веб-диаграммой - Raspberry Pi
  4. Создание роботов с Raspberry Pi и Python
  5. Ускорение цифровой трансформации с помощью данных Интернета вещей благодаря Cisco и IBM
  6. Использование данных Интернета вещей от края до облака и обратно
  7. Путешествие по IIoT начинается с удаленной телеметрии
  8. Как сделать IOT реальным с помощью Tech Data и IBM Part 2
  9. Как сделать Интернет вещей реальным с помощью Tech Data и IBM Часть 1
  10. Повышение бизнес-результатов с помощью проектов больших данных и искусственного интеллекта