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


import os
import serial
import time
import threading
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_bootstrap import Bootstrap
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, <br/>    current_user

app = Flask(name)
app.secret_key = os.urandom(24)

# Настройка базы данных
app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘sqlite:///my_advanced_web_app.db’
app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False
db = SQLAlchemy(app)

migrate = Migrate(app, db)
Bootstrap(app)

login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = ‘login’

serialPort = “/dev/ttyS1”
baudRate = 9600
arduinoSerialData = serial.Serial(serialPort, baudRate)


# Модель устройства для базы данных
class Device(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    device_id = db.Column(db.String(32), unique=True, nullable=False)
    name = db.Column(db.String(32), nullable=True)
    min_temp = db.Column(db.Float, nullable=False)
    max_temp = db.Column(db.Float, nullable=False)
    input_status = db.Column(db.Boolean, nullable=False)
    temperature = db.Column(db.Float, nullable=False)
    online = db.Column(db.Boolean, default=False)


class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(120), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))


def read_serial_data():
    while True:
        if arduinoSerialData.inWaiting() > 0:
            receivedData = arduinoSerialData.readline().strip().decode(‘utf-8’)
            dataComponents = receivedData.split(‘,’)

            if len(dataComponents) == 3:
                deviceId, temperature, digitalInputState = dataComponents
                device = Device.query.filter_by(device_id=deviceId).first()

                # Если устройство существует в базе данных, обновить показания и состояния
                if device:
                    device.temperature = temperature
                    device.input_status = True if digitalInputState == “1” else False
                    device.online = True
                    db.session.commit()
            time.sleep(5)


def update_offline_status():
    while True:
        devices = Device.query.all()
        for device in devices:
            if int(time.time()) - int(device.last_seen) > 60:
                device.online = False
                db.session.commit()
        time.sleep(10)


serial_reader_thread = threading.Thread(target=read_serial_data)
serial_reader_thread.daemon = True
serial_reader_thread.start()

update_offline_status_thread = threading.Thread(target=update_offline_status)
update_offline_status_thread.daemon = True
update_offline_status_thread.start()

# Главная страница с отображением данных датчиков
@app.route(‘/’, methods=[‘GET’, ‘POST’])
def index():
    devices = Device.query.all()
    return render_template(‘index.html’, devices=devices)


# Административная страница для управления устройствами
@app.route(‘/admin’, methods=[‘GET’, ‘POST’])
@login_required
def admin():
    if request.method == ‘POST’:
        deviceId = request.form.get(‘device_id’)
        name = request.form.get(‘name’)
        min_temp = float(request.form.get(‘min_temp’))
        max_temp = float(request.form.get(‘max_temp’))

        existing_device = Device.query.filter_by(device_id=deviceId).first()

        if existing_device:
            flash(“Устройство с таким deviceID уже существует!”, “danger”)
        else:
            new_device = Device(device_id=deviceId, name=name, min_temp=min_temp, max_temp=max_temp,
                                temperature=0, input_status=False, online=False)
            db.session.add(new_device)
            db.session.commit()
            flash(“Устройство добавлено!”, ‘success’)
            return redirect(url_for(‘admin’))

    devices = Device.query.all()
    return render_template(‘admin.html’, devices=devices)


# Удаление устройства через его id
@app.route(‘/delete/<int:device_id>’, methods=[‘POST’])
@login_required
def delete_device(device_id):
    device = Device.query.get_or_404(device_id)
    db.session.delete(device)
    db.session.commit()
    flash(f"Устройство {device.device_id} удалено!“, “success”)
    return redirect(url_for(‘admin’))


# Обновление устройства
@app.route(‘/update_device/<int:device_id>’, methods=[‘POST’])
@login_required
def update_device(device_id):
    device = Device.query.get_or_404(device_id)
    name = request.form.get(‘name’)
    min_temp = float(request.form.get(‘min_temp’))
    max_temp = float(request.form.get(‘max_temp’))

    device.name = name
    device.min_temp = min_temp
    device.max_temp = max_temp
    db.session.commit()
    flash(f"Устройство {device.device_id} обновлено!”, “success”)
    return redirect(url_for(‘admin’))


# Аутентификация
@app.route(‘/login’, methods=[‘GET’, ‘POST’])
def login():
    if current_user.is_authenticated:
        return redirect(url_for(‘admin’))

    if request.method == ‘POST’:
        username = request.form.get(‘username’)
        password = request.form.get(‘password’)
        user = User.query.filter_by(username=username, password=password).first()
        if user is not None:
            login_user(user)
            return redirect(url_for(‘admin’))
        else:
            flash(“Неверное имя пользователя или пароль”, ‘danger’)
    return render_template(‘login.html’)


# Выход из аккаунта
@app.route(‘/logout’)
@login_required
def logout():
    logout_user()
    return redirect(url_for(‘login’))


# Получение данных в формате JSON для обновления пользовательского интерфейса
@app.route(‘/data’)
def get_data():
    devices = Device.query.all()
    devices_data = {
        device.device_id: {
            ‘name’: device.name,
            ‘temperature’: device.temperature,
            ‘input_status’: device.input_status,
            ‘min_temp’: device.min_temp,
            ‘max_temp’: device.max_temp,
            ‘online’: device.online
        }
        for device in devices
    }
    return jsonify(devices_data)


if name == “main”:
    app.run(host=‘0.0.0.0’, port=80, debug=True)


Теперь обновим наши HTML-шаблоны, добавив все необходимые изменения.

1. base.html - остается без изменений.

2. index.html:


{% extends ‘base.html’ %}

{% block content %}
    <h1>Temperature Monitor</h1>
    <div id=“devices”>
        {% for device in devices %}
            <div{% if device.temperature > device.max_temp or device.temperature < device.min_temp %} class=“alert alert-danger”{% elif not device.online %} class=“alert alert-warning”{% endif %}>
                <h2>{{ device.name }} (Device {{ device.device_id }})</h2>
                <p>{% if device.online %}Temperature: {{ device.temperature }} C {% else %}Устройство не в сети{% endif %}</p>
                <p>Digital Input Status: {{ device.input_status }}</p>
            </div>
        {% endfor %}
    </div>

    <script>
        setInterval(() => {
            .getJSON("/data", (data) => {
                console.log(data);


(“#devices”).html(“”);
                for (let deviceId in data) {
                    let deviceData = data[deviceId];
                    let deviceDivClasses = deviceData.temperature > deviceData.max_temp || deviceData.temperature < deviceData.min_temp
                        ? “alert alert-danger”
                        : deviceData.online ? “” : “alert alert-warning”;
                        
                    let temperatureText = deviceData.online ? Temperature: ${deviceData.temperature} C : “Устройство не в сети”;

                    ("#devices").append(`
                        <div class="
{deviceDivClasses}“>
                            <h2>{deviceData.name} (Device
{deviceId})</h2>
                            <p>{temperatureText}</p>
                            <p>Digital Input Status:
{deviceData.input_status}</p>
                        </div>
                    `);
                }
            });
        }, 10000);
    </script>
{% endblock %}


3. admin.html:


{% extends ‘base.html’ %}

{% block content %}
    <h1>Admin Panel</h1>
    <button id=“addDeviceBtn” class=“btn btn-primary”>Добавить устройство</button>
    <div id=“addDeviceModal” class=“modal” tabindex=”-1" role=“dialog”>
        <div class=“modal-dialog” role=“document”>
            <div class=“modal-content”>
                <div class=“modal-header”>
                    <h5 class=“modal-title”>Добавление устройства</h5>

<button type=“button” class=“close” data-dismiss=“modal” aria-label=“Close”>
                        <span aria-hidden=“true”>×</span>
                    </button>
                </div>
                <form action=“{{ url_for(‘admin’) }}” method=“POST” novalidate>
                    <div class=“modal-body”>
                        <div class=“form-group”>
                            <label for=“device_id”>Device ID:</label>
                            <input type=“text” class=“form-control” id=“add_device_id” name=“device_id” required>
                        </div>
                        <div class=“form-group”>
                            <label for=“name”>Device Name:</label>
                            <input type=“text” class=“form-control” id=“add_name” name=“name” required>
                        </div>
                        <div class=“form-group”>
                            <label for=“min_temp”>Min Temperature:</label>
                            <input type=“number” step=“0.1” class=“form-control” id=“add_min_temp” name=“min_temp” required>
                        </div>
                        <div class=“form-group”>
                            <label for=“max_temp”>Max Temperature:</label>
                            <input type=“number” step=“0.1” class=“form-control” id=“add_max_temp” name=“max_temp” required>
                        </div>
                    </div>
                    <div class=“modal-footer”>
                        <button type=“submit” class=“btn btn-primary”>Добавить устройство</button>
                        <button type=“button” class=“btn btn-secondary” data-dismiss=“modal”>Отмена</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <table class=“table table-bordered”>
        <thead>
            <tr>
                <th>Name</th>
                <th>Device ID</th>
                <th>Min Temp</th>
                <th>Max Temp</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
        {% for device in devices %}
            <tr>
                <td>{{ device.name }}</td>
                <td>{{ device.device_id }}</td>
                <td>{{ device.min_temp }}</td>
                <td>{{ device.max_temp }}</td>
                <td>
                    <button class=“btn btn-warning”>Редактировать</button>
                    <form action=“{{ url_for(‘delete_device’, device_id=device.id) }}” style=“display: inline-block;” method=“POST”>
                        <button type=“submit” class=“btn btn-danger”>Удалить</button>
                    </form>
                </td>
            </tr>
        {% endfor %}
        </tbody>
    </table>

    <script>
    (document).ready(function() {

(“#addDeviceBtn”).click(function() {
            $(“#addDeviceModal”).modal(“show”);
        });
    });
    </script>
{% endblock %}


4. Добавим новый файл login.html:


{% extends ‘base.html’ %}

{% block content %}
    <h2>Вход</h2>
    <form method=“POST” action=“{{ url_for(‘login’) }}”>
        <div class=“form-group”>
            <label for=“username”>Имя пользователя:</label>
            <input type=“text” class=“form-control” id=“username” name=“username” required>
        </div>
        <div class=“form-group”>
            <label for=“password”>Пароль:</label>
            <input type=“password” class=“form-control” id=“password” name=“password” required>
        </div>
        <button type=“submit” class=“btn btn-primary”>Войти</button>
    </form>
{% endblock %}


Теперь у вас есть совершенствованное веб-приложение с возможностью авторизации для администратора, добавления, удаления и обновления устройств Arduino Pro Mini по Device ID, контроля диапазона температур и отображения состояния подключения устройств. Приложение сохраняет все изменения и данные для устройств, даже после перезагрузки.
каково здесь назначение файла base.html?