При использовании прямого вызова метода DS18B20.Measure в предыдущей версии нашего приложения наблюдается задержка обновления температурных данных на веб-странице. Это связано с тем, что цикл температурного преобразования цифровых термометров занимает порядка одной секунды, и построителю веб-страницы (flask.render_template()) приходится ждать завершение этого преобразования, прежде чем представить новую веб-страницу с новыми температурными данными.
Решение – в разделении задач по потокам. При инициализации приложения запускается модуль в отдельном потоке, который в цикле стартует процедуру измерения цифровых термометров DS18B20, ожидает её завершение и сохраняет свежие температурные данные в какое-то хранилище. Построитель же веб-страницы будет получать эти температурные данные уже из хранилища.
Конечно, можно было бы хранить список термометров в какой-либо переменной в памяти. Но есть один довод в пользу постоянного хранения параметров термометров в базе данных. Автоматика должна знать, в каком месте установлен конкретный термометр, чтобы производить соответствующие управляющие действия. Информация о местоположении термометра не должна исчезать после отключения питания, поэтому её нужно хранить в базе данных вместе с другими параметрами термометра.
Выше уже описывалась соответствующая модель базы данных ([сообщение #12969061]).
Для работы с базой данных нам потребуются:
1. Добавить в виртуальное окружение python пакет flask-sqlalchemy;
2. Создать при инициализации приложения и сконфигурировать объект sqlalchemy для работы с базами данных и связать этот объект с приложением flask;
3. Описать модели таблиц баз данных;
4. Написать класс-поток, сохраняющий актуальные температурные значения в базу данных;
5. Научить построитель веб-страницы получать температурные значения из базы данных.
Добавление пакета flask-sqlalchemy
В обозревателе решений разворачиваем Окружения Python, жмем правой кнопкой мыши на папке env, из контекстного меню выбираем Установить пакет Python... В строчке, где написано Поиск PyPI и установленных пакетов, набираем flask-SQLAlchemy и выбираем пункт «установить flask-SQLAlchemy с помощью pip» из PyPI. В нижнем окне Вывод можно наблюдать ход установки. По завершении установки пакета, открыв вкладку Обозреватель решений можем увидеть в списке виртуального окружения Flask-SQLAlchemy(2.2).
Объект sqlalchemy для работы с базами данных
Объект sqlalchemy лучше создать в отдельном модуле с именем database.py в корне проекта, чтобы остальные модули проекта могли получать к нему доступ. Файл модуля содержит всего две строчки:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
--------------------------------------
Colored with http://dumpz.org
Конфигурирование объекта sqlalchemy на самом деле производится из конфигурации связываемого с ним объекта приложения flask.
Например, для указания в конфигурации пути доступа к базе данных, можно было бы в процессе инициализации приложения flask добавить такие строки:
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'Если указывать конфигурационные параметры в коде, потом трудно будет ими управлять. Поэтому гораздо удобнее собрать все конфигурационные параметры в один файл с именем config.py:
db = SQLAlchemy(app)
import os
from datetime import datetime
class Config(object):
"""Содержит базовые параметры конфигурации приложения"""
#Наименование управляемого устройства
DEVICE_NAME = u'Дистиллятор'
# Путь к каталогу запуска программы
BASEDIR = os.path.abspath(os.path.dirname(__file__))
# Определяет, включен ли режим отладки.
# Если включен, flask будет показывать
# подробную отладочную информацию. Если выключен -
# - 500 ошибку без какой-либо дополнительной информации.
DEBUG = False
# Включение защиты против "Cross-site Request Forgery (CSRF)"
CSRF_ENABLED = True
# Случайный ключ, который будет использоваться для подписи
# данных, например cookies.
SECRET_KEY = "YOUR_RANDOM_SECRET_KEY"
# URI используемый для подключения к базе данных
# Основная база данных
SQLALCHEMY_DATABASE_URI = "sqlite:///" + os.path.join(BASEDIR, "Distiller.db")
#Базы данных приложения
SQLALCHEMY_BINDS = {'Distiller':'sqlite:///' + os.path.join(BASEDIR, "Distiller.db"),
'log':'sqlite:///' + os.path.join(BASEDIR, datetime.now().strftime('%Y_%m_%d %H-%M-%S.log'))}
SQLALCHEMY_TRACK_MODIFICATIONS = False
--------------------------------------
Colored with http://dumpz.org
В файле конфигурации написаны пути к базам данных SQLite. Основные параметры устройства будут храниться в базе данных в файле с именем Distiller.db. В базах данных с динамически формируемым по дате и времени именем файла будут записываться журналы работы устройства.
Конфигурирование объекта приложения flask с объектом sqlalchemy сделаем в файле инициализации всего приложения Distiller.__init__.py:
"""
The flask application package.
"""
from flask import Flask
import Distiller.models
from Distiller.config import Config
from Distiller.database import db
app = Flask(__name__)
# Загрузка конфигурации из config.py
app.config.from_object(Config)
#Подключение, инициализация и создание (при необходимости) базы данных
db.app=app
db.init_app(app)
# Создать базу данных
db.create_all(bind='Distiller')
#Подключение функций представления веб-страниц
import Distiller.views
--------------------------------------
Colored with http://dumpz.org
Модели таблиц баз данных
Модели таблиц баз данных хранятся в виде классов в модуле models.py в корневой папке программы. Создаем в папке Distiller пустой файл Python с именем models.py и наполняем его следующим содержимым:
from Distiller. database import db
class DS18B20(db.Model):
'''Table of digital thermometers DS18B20'''
__bind_key__ = 'Distiller'
__tablename__ = 'DS18B20'
id = db.Column(db.Integer, primary_key=True)
IDthermometer = db.Column(db.String(16), nullable=False, unique=True)
Name = db.Column(db.String(64), nullable=False, unique=True)
T = db.Column(db.Float)
Timestamp = db.Column(db.DateTime)
def __str__(self):
return self.Name
--------------------------------------
Colored with http://dumpz.org
Создание потока, сохраняющего температурные значения в базе данных и вывод этих значений из базы данных на веб-страницу - во второй части.
Текущее состояние проекта - в файле Distiller.zip