Fab-O-Matic : back-end Python e Raspberry Pi

Continuiamo la serie di articoli a scopo didattico sulla realizzazione di un progetto all’interno del nostro FabLab, Fab-O-Matic. In questo articolo, tratteremo dello sviluppo della parte server (o “back-end”). Questa parte del progetto funziona su Raspberry Pi, con un server Web https, un’interfaccia MQTT con Mosquitto e una gestione database con Python : mostreremo esempi pratici delle varie tecnologie usate con l’aiuto di ChatGPT.

Sommario degli articoli:

Puoi consultare inoltre le istruzioni per l’uso di Fab-O-Matic qua.

L’applicazione finita

Prima di vedere com’è fatta, presentiamo alcune videate di esempio dell’applicativo back-end nelle sue principali videate. E’ un sito web che usa la classica libreria Bootstrap per l’aspetto grafico.

Il manuale del back-end è disponibile nella repository Github.

Scelte tecnologiche back-end

Sarebbe impraticabile memorizzare le tessere abilitate su ogni board e doverle riprogrammare quando si associa una nuova persona. Un database è più adeguato quando si vuole memorizzare elenchi di dati come utenti, interventi, usi delle macchine, abilitazioni come in Fab-O-Matic. Serve dunque un altro software, che chiameremo “back-end”, per processare le richieste e registrare le informazioni mandate dalle varie board installate nel FabLab.

Un requisito importante è di poter far funzionare questo back-end su un Raspberry Pi Zero, che costa circa 15 EUR : come la board, il back-end è alla portata di tutte le associazioni che desiderano gestire l’accesso macchine con tessere RFID.

Per il database, abbiamo scelto SQLite, che evita attività di manutenzione delle database engine più elaborate. E’ un engine semplice, estremamente veloce, disponibile .

Nell’articolo sul software embedded, abbiamo visto che la board usa il protocollo MQTT per comunicare con il backend. MQTT è un protocollo semplice, leggibile, e molto diffuso per le applicazioni Internet Of Things. Ci servirà dunque un “server MQTT”, un cosidetto “broker”. Abbiamo scelto Mosquitto che è il broker più popolare e diffuso.

Infine, per realizzare il front-end e la logica di interazione fra board e database, abbiamo usato Python con framework Flask. Python e Flask sono molto diffusi nel campo delle applicazioni IoT: ad esempio, stanno alla base di HomeAssistant e sono attivamente mantenuti.

ChatGPT durante lo sviluppo

Durante lo sviluppo di questo progetto è uscito ChatGPT 4.0 e l’abbiamo messo alla prova con questo progetto di back-end. Il bilancio dell’esperimento è che ChatGPT è un ottimo professore e riferimento se vuoi imparare una nuova tecnologia rapidamente ; un po’ come un collega più esperto e disponibile, ma non gli puoi chiedere di fare tutto il tuo lavoro !

Possiamo riassumere l’esperienza con Fab-O-Matic in linguaggio Python come segue:

Caso di utilizzo e link alla chatQualità della rispostaValutazione / Risparmio di tempo
Code generation : riscrivi questo template flask usando bootstrap

https://chatgpt.com/share/9303ee7e-c591-4e00-bd20-1a8e67f63fb8
Boilerplate code ok, qualche inconsistenza fra pagine con risposte lunghe. Ottima base di partenza, da rilavorare.⭐⭐⭐
Code generation : Esamina le entità SQLAlchemy seguenti e genera codice Python per un sito web con Flask per le operazioni CRUD su quelle entità.

https://chatgpt.com/share/4b9a395c-7524-4a70-a40c-1a1266fc68c1
Mancanza di consistenza fra risposte e entità. Ottima base di partenza, da rilavorare.⭐⭐⭐
Debugging degli errori incontratiSolo per problemi semplici o comuni. Funziona meglio in questo caso d’uso CoPilot che beneficia del contesto completo della soluzione.⭐⭐
Learning : Capire come usare un framework nuovo con degli esempi su misuraElimina tante ricerche e (quasi) la necessità di leggere la documentazione fornendo esempi ben commentati.
⭐⭐⭐⭐⭐
Porting : Migrare da un framework (Mongo) ad un altro (SQLAlchemy)

https://chatgpt.com/share/104ffc2f-3379-4a27-9159-23db1df491d7
Molto difficile trovare materiali online senza studiarsi due framework⭐⭐⭐⭐⭐

Python / Flask

Se hai una conoscenza di Python o familiarità con altri framework applicativi come PHP/Laravel, ASPNET.Core, è abbastanza facile imparare ad usare Flask. E quando sei bloccato con problemi di principianti, ChatGPT ti sarà un ottimo aiuto.

Sono due i concetti principali per fare applicativi Flask : i templates e le routes.

Template Flask : generazione di pagine HTML

Un Template Flask è un file contenente codice HTML con un markup specifico {% istruzione %} oppure {{ variabile }}

Questo file viene interpretato dal Runtime per inserire i contenuti dinamici e, per esempio, generare pagine Web che cambiano in base ai contenuti del database.

Ad esempio, il codice sotto enumera un elenco di macchine e genera, per ognuna di loro una riga di tabella con ID, nome, tipo di macchina, ore lavorate, icona di blocco e 3 bottoni di VIEW/EDIT/DELETE.

{% for machine in machines %}
            <tr>
                <td class="d-none d-lg-table-cell">{{ machine.machine_id }}</td>
                <td>{{ machine.machine_name }}</td>
                <td class="d-none d-lg-table-cell"><span class="badge bg-info">{{ machine.machine_type.type_name }}</span></td>
                <td>{{ machine.machine_hours | format_hours }}</td>
                <td>
                    {% if machine.blocked %}
                    <i class="fa-solid fa-lock"></i> <!-- Locked Icon -->
                    {% else %}
                    <i class="fa-solid fa-lock-open"></i> <!-- Unlocked Icon -->
                    {% endif %}
                </td>
                <td>
                    <a href="{{ url_for('view_machine_use_history', machine_id=machine.machine_id) }}"
                        class="btn btn-info">{{ _("View history") }}</a>
                    <a href="{{ url_for('edit_machine', machine_id=machine.machine_id) }}"
                        class="btn btn-warning">{{ _("Edit") }}</a>
                    <a href="{{ url_for('delete_machine', machine_id=machine.machine_id) }}"
                        class="btn btn-danger">{{ _("Delete") }}</a>
                </td>
            </tr>
 {% endfor %}

Routes : collegamento browser/logica

Le variabili usate nel template Flask di sopra devono essere passate da qualche logica Python. Sono i file di routes che uniscono le azioni su database con i template.

La tabella è sopra è gestita da questa route:

@app.route("/machines", methods=["GET"])
@login_required
def view_machines():
    session = DBSession()
    machine_repo = MachineRepository(session)
    machines = session.query(Machine).order_by(Machine.machine_id).all()
    return render_template("view_machines.html", machines=machines)

In questo frammento di codice python:

  • L’attributo @app.route("/machines", methods=["GET"]) indica al framework Flask che la funzione view_machines() va chiamata quando il browser fa una richiesta GET sull’URL /machines.
  • L’attributo @login_required richiede che l’utente sia autenticato per mostrare la pagina.
  • La logica Python tramite Alchemy interroga la tabella delle macchine, ordina per ID e passa la variabile ottenuta alla funzione render_templates per il frammento html di sopra.

Python / SQLAlchemy

SQLAlchemy è una potente libreria per Python che permette di gestire in modo efficiente e intuitivo l’interazione con i database.

Fornendo un’astrazione di più alto livello, SQLAlchemy facilita lo sviluppo di applicazioni che necessitano di interagire con database relazionali. In questo articolo esploreremo alcune delle funzionalità più rilevanti offerte da SQLAlchemy, concentrandoci in particolare sugli approcci “code-first” e il versioning.

Approccio “Code-First”

L’approccio “code-first” è uno dei principali punti di forza di SQLAlchemy. Invece di creare prima il database e poi scrivere il codice per interagirvi, SQLAlchemy consente di definire le entità direttamente nel codice. Questo approccio offre una maggiore flessibilità e controllo sullo schema del database, permettendo di gestire le modifiche in modo più semplice ed efficace.

Un esempio di definizione di una entità utilizzando SQLAlchemy è il seguente:

class Role(Base):
    """Dataclass handling a role."""

    __tablename__ = "roles"

    role_id = Column(Integer, primary_key=True, autoincrement=True)
    role_name = Column(String, unique=True, nullable=False)
    authorize_all = Column(Boolean, default=False, nullable=False)
    reserved = Column(Boolean, default=False, nullable=False)
    maintenance = Column(Boolean, default=False, nullable=False)
    backend_admin = Column(Boolean, default=False, nullable=False)

    users = relationship("User", back_populates="role")
    __table_args__ = (Index("idx_roles_role_name_unique", "role_name", unique=True),)

In questo esempio, abbiamo definito una classe Role che rappresenta una tabella del database. Utilizzando gli attributi di classe, possiamo specificare i campi della tabella, i loro tipi di dati, le restrizioni e le relazioni con altre tabelle.

Versioning del database

Una delle sfide nello sviluppo di applicazioni che utilizzano un database è gestire le modifiche allo schema durante la vita del progetto. La libreria Alembic costruita sopra SQLAlchemy affronta questa sfida attraverso il versioning, che consente di generare script di aggiornamento del database automaticamente quando vengono apportate modifiche alle entità, chiamate “migrazioni”. Le migrazioni del database sono dei file Python che applicano le modifiche al database rilevate.

Ad esempio, se si aggiunge un nuovo attributo alla classe Role, Alembic genererà automaticamente uno script di migrazione in Python per eseguire un’istruzione SQL "ALTER TABLE ... ADD COLUMN ...", lasciandoti comunque la possibilità di applicare manuale altre trasformazioni ai dati nello script di migrazione.

Durante lo sviluppo del progetto è stato modificato più volte lo schema del database: grazie alla tecnologia sopra, l’aggiornamento del server è sempre stato trasparente, veloce e senza perdita di dati. Ci sono molti esempi di migrazioni nella repository di Fab-O-Matic.

Navigazione Semplice fra le Entità in Relazione

SQLAlchemy facilita la gestione delle relazioni tra entità utilizzando relazioni e join. Nell’esempio precedente, la connessione tra Role e User è rappresentata dall’attributo users, che impiega la funzione relationship per creare un legame bidirezionale tra le due entità. Questo consente di accedere agevolmente agli utenti associati a un ruolo specifico e viceversa. Non è più necessario scrivere manualmente comandi SQL come “SELECT … FROM A JOIN B ON …”!

Concludendo su SQLAlchemy

SQLAlchemy è una libreria che raccomandiamo per chiunque lavori con database relazionali in Python, perché ti concentri sulla logica dell’applicazione, piuttosto che sui dettagli implementativi della gestione del database.

Librerie, packaging e distribuzione

Per semplificare l’installazione di Python con i suoi prerequisiti, Fab-O-Matic usa il formato TOML per la configurazione e la pubblicazione di un package Python su PyPi. Il file pyproject.toml offre in fatti un metodo più intuitivo e leggibile per specificare le dipendenze e le informazioni di build rispetto ai tradizionali file setup.py e setup.cfg.

Troviamo elencate nel file pyproject.toml di Fab-O-Matic le dipendenze:

Titolo LibreriaBreve DescrizioneLink al Sito di Riferimento
HatchlingStrumento di build per Python che semplifica la creazione di pacchetti.Hatchling
SQLAlchemyToolkit SQL per Python e Object-Relational Mapping (ORM).SQLAlchemy
tomlLibreria per lavorare con i file TOML in Python. Usato per il parsing del file di configurazione.toml
paho-mqttClient MQTT per Python per collegarsi al broker Mosquitto della Eclipse Foundation.paho-mqtt
colorlogLibreria per la colorazione dei log in Python.colorlog
flaskMicro framework web per Python usato per il sito web.Flask
requestsLibreria per fare richieste HTTP in modo semplice e intuitivo.
pyopensslWrapper Python per la libreria OpenSSL, usata per crittografia e sicurezza. Usato per fornire https.pyopenssl
flask-loginEstensione Flask per la gestione dell’autenticazione degli utenti.flask-login
flask-mailEstensione Flask per l’invio di email.flask-mail
alembicStrumento di migrazione e versioning del database per SQLAlchemy.alembic
psutilLibreria per l’accesso a informazioni di sistema e processi. Usato per lanciare aggiornamenti automatici nella pagina di sistema.psutil
flask-excelEstensione Flask per il supporto dell’importazione e dell’esportazione di file Excel (analisi manuali o richieste di accesso ai dati GDPR).flask-excel
pyexcel-xlsxLibreria per la lettura e la scrittura di file Excel in formato xlsx.pyexcel-xlsx
Flask-BabelEstensione Flask per l’internazionalizzazione e la localizzazione delle applicazioni web.Flask-Babel

Pubblicare il software per altri utenti

PyPi, abbreviazione di Python Package Index, è il repository ufficiale di software per il linguaggio di programmazione Python. Funziona come una grande libreria online dove gli sviluppatori possono caricare e condividere i propri pacchetti Python, rendendoli facilmente accessibili alla comunità globale. Grazie a PyPi, gli utenti possono installare rapidamente le librerie necessarie utilizzando strumenti di gestione dei pacchetti come pip.

Questo sistema centralizzato semplifica notevolmente la distribuzione e l’installazione di software, promuovendo la riusabilità del codice e accelerando lo sviluppo di applicazioni Python. Fab-O-Matic usa un’azione Github per pubblicare automaticamente i commit sul ramo main, che passano i test con successo, verso PyPi.

Conclusione

Lo sviluppo del back-end è stato molto più semplice e veloce rispetto al software embedded, perché i framework scelti sono molto rapidi da usare e ChatGPT ha velocizzato la scrittura del codice boilerplate.

Dopo il periodo di prova iniziale di funzionamento su Raspberry Pi Zero, a Giugno 2024, abbiamo spostato questo back-end su una macchina virtuale Debian 12 (1GB RAM) ospitata in un server PROXMOX configurato in FabLab dal BGLUG : se queste tecnologie ti incuriosiscono, vienici a trovare un martedì sera e troverai esperti con cui parlarne.

Nel prossimo articolo, vedremo come è stato possibile automatizzare i test di questi software embedded e back-end per garantire una buona qualità e evitare bug che potrebbero inficiare sul normale funzionamento delle macchine del FabLab !

Utilizzando il sito, accetti l'utilizzo dei cookie da parte nostra. Per maggiori informazioni.

Questo sito utilizza i cookie per fornire la migliore esperienza di navigazione possibile. Continuando a utilizzare questo sito senza modificare le impostazioni dei cookie o clicchi su "Accetta" permetti al loro utilizzo. Privacy Policy di FABLAB BERGAMO

Chiudi