Structure
The web application is a flask app, running on the gunicorn server and uses NGINX has a proxy server.
- __init__.py - initialization of the app
- main.py - main app running on server
- auth.py - management of the accounts: validation and intermediate on the access to the database
- /templates - folder containing all the Static rendered Jinja2 HTML files
- /templates/template.html - contains the base HTML page for the dashboard
- /templates/detection.html - extends template and has the HTML code to show the detection of vehicles, devices, people and two-wheelers
- /templates/moliceiros.html - extends template and has the HTML code to show the detection data of moliceiros
- /templates/base.html - contains the base HTML page for managing the accounts
- /templates/login.html - extends base and has the HTML code to login into the account
- /templates/signup.html - extends base and has the HTML code to create an account
The main functions of the app are:
- main.detection() - renders the template of the main page where the detection data of vehicles, people, devices and two-wheelers is showed.
- main.people() - renders the template of the page where the detection data of moliceiros is showed.
- auth.login() - takes care of the account authentication and the page is rendered based on the success of it
- auth.signup() - takes care of the creation of accounts and the page is rendered based on the success of it
- auth.logout() - logouts the account and redirects to the main page, the detection dashboard
To render the HTML pages with jinja the functions return render_template(‘person.html’, pagename=“Moliceiros and People detection”) the argument pagename renders the page name on the html files
In flask, we access the broker and subscribe to topics to get real-time data. On these lines of code we access the broker
app.config['MQTT_BROKER_URL'] = '###.nap.av.it.pt'
app.config['MQTT_BROKER_PORT'] = 1883
app.config['MQTT_REFRESH_TIME'] = 1.0
mqtt = Mqtt(app)
mqtt = Mqtt(app) starts the broker access for the Broker. handle_connect subscribes to the topic, and handle_mqtt_message, gets the message in real-time and sends it through a socket to the web app
@mqtt.on_connect()
def handle_connect(client, userdata, flags, rc):
mqtt.subscribe('sniffing') #where the topic is called 'sniffing'
@mqtt.on_message()
def handle_mqtt_message(client, userdata, message):
data = dict(
topic=message.topic,
payload=message.payload.decode()
)
# emit a mqtt_message event to the socket containing the message data
socketio.emit('mqtt_message', data=data)
print(data)
To show in real time the broker data from flask to HTML, we need to open a socket using server sent events, for that in the app.py file app routes were created for the server sent events, where is returned a Response of type “text/event-stream”
For the html - template page, on the DIVS regarding the cards and charts a connection to the respective SSE is made, and the values are showed in real-time.
In order to store and manage the user’s accounts it was created an SQLite database called user.
Flask makes it more intuitive and practical with the integration of classes/libraries like: SQLAlchemy, LoginManager and UserMixin.
- SQLAlchemy - library that facilitates the communication between the app and the database
- LoginManager - class used to hold the settings used for logging in
- UserMixin - class that provides default implementations for methods that flask_login expects user objects to have
The configuration is done in the __init__.py file:
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin
# ...
# init SQLAlchemy
db = SQLAlchemy()
#define database
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True) # primary keys are required by SQLAlchemy
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(100))
name = db.Column(db.String(1000))
def create_app():
# ...
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite' #the path to the SQLite database file
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # deactivate Flask-SQLAlchemy track modifications
db.init_app(app) # Initialiaze sqlite database
# The login manager contains the code that lets your application and Flask-Login work together
login_manager = LoginManager() # Create a Login Manager instance
login_manager.login_view = 'auth.login' # define the redirection path when login required and we attempt to access without being logged in
login_manager.init_app(app) # configure it for login
# ...
Then the database is created in the __main__ function in the main.py file:
if __name__ == "__main__":
# ...
db.create_all(app=create_app()) # create the SQLite database
Flask-Babel is an extension to Flask that helps get text translations with the help of Jinja.
On the createapp() function in the __init__.py file:
#Babel Configuration
app.config['BABEL_DEFAULT_LOCALE'] = 'en'
#Creation of mqtt, socket and babel objects for the app
babel = Babel(app)
# set up babel
@babel.localeselector
def get_locale():
if request.args.get('lang'):
session['lang'] = request.args.get('lang')
return session.get('lang', 'en')
To generate the translation files the following steps need to be made:
Run the pybabel command that comes with Babel to extract your strings:
pybabel extract -F babel.cfg -o messages.pot .
Generate the language translation file (ex.: pt)
pybabel init -i messages.pot -d translations -l pt
After translating the web application strings on the generated file (ex.: pt.po) compile
pybabel compile -d translations