Gyordan Caminati
Sara Kiade
Igor Lirussi
Smart DogHouse è un progetto che nasce con l’intento di migliorare le condizioni dei cani che si trovano ospiti di un canile, mediante l’introduzione di un supporto informatico che possa, da un lato, facilitare operazioni che già prima venivano svolte e dall’altro introdurre nuovi strumenti che vadano a migliorare la gestione del canile.
Come riferimento è stato preso in considerazione il canile comunale di Pisa, il quale gestore si è offerto di indirizzarci permettendoci di rivolgerci a lui per avere feedback e indicazioni basate su esperienze reali.
L’idea ha avuto origine dopo un colloquio con il gestore del canile che, raccontando la propria esperienza, ha evidenziato alcuni problemi che riscontra nello svolgimento del proprio lavoro, molti dei quali sono risolvibili attraverso gli strumenti e le competenze che abbiamo a disposizione. Successivamente, le informazioni ottenute dal canile di Pisa sono state confrontate e integrate a fronte di un colloquio con il canile Comunale di Cesena, la quale consulenza è stata indispensabile per riuscire a discernere gli aspetti comuni alla maggior parte dei canili da quelle che invece sono peculiarità di un canile specifico. Le domande e le risposte di entrambi i canili sono rese disponibili nel pdf relativo negli extra. Questa capacità di astrazione ci ha permesso di definire meglio gli obiettivi. Anche se questo non può essere considerato un progetto su commissione, abbiamo fede nel fatto che una volta sviluppata la nostra soluzione, essa possa essere utilizzata come base per sviluppare altri sistemi o rendere più tecnologici canili e gattili che riscontrano le stesse difficoltà.
Il canile di Pisa ospita circa una sessantina di cani e gatti di diversa taglia, randagi o abbandonati, che vengono prelevati dagli addetti del canile su segnalazione dei cittadini. I cani restano poi in cura finché non vengono adottati, mentre i gatti vengono rilasciati subito dopo aver ricevuto le cure mediche ed essersi ripresi. Ad occuparsi della salute dei cani è un responsabile sanitario sempre presente nella struttura, che coordina alcuni veterinari convenzionati con la struttura. La situazione al canile di Cesena è similare, con la differenza che quest’ultimo non si occupa più del recupero di gatti randagi e il responsabile sanitario non coordina altri veterinari ma si occupa in autonomia di tutto ciò che riguarda la salute del cane, dai problemi di routine alle operazioni chirurgiche.
I principali problemi che vengono attualmente riscontrati sono i seguenti:
responsabile sanitario: il responsabile sanitario e alcuni veterinari convenzionati, risiedono all’interno del canile. Attualmente non è possibile monitorare in maniera continuativa lo stato di salute di un animale. Questo spesso si traduce in un intervento tardivo che porta con sé delle limitazioni che con una diagnosi più veloce si sarebbero potute evitare.
Rifornimento e consumi di cibo ed acqua: in entrambi i canili la maggior parte del lavoro manuale viene svolta dai volontari che prestano attività in forma gratuita e fortemente discontinua. Non è possibile sapere a priori quanti volontari si presenteranno a dare una mano, ed essendo in tanti non è nemmeno possibile sapere chi ha svolto quali mansioni. Operazioni come il rifornimento di cibo ed acqua vanno quindi monitorate personalmente dal gestore che deve recarsi fisicamente nelle gabbie per controllare gli approvvigionamenti; inoltre non è nemmeno possibile conoscere la quantità di cibo ed acqua consumata da un cane, il che rende più difficile individuare i segnali alimentari che sono sintomi di alcuni problemi di salute.
Sorveglianza: né il canile di Pisa, né quello di Cesena, attualmente, dispongono di un sistema di sorveglianza da remoto, pertanto nel momento in cui si verificano furti, effrazioni ed atti vandalici, non è possibile risalire agevolmente al colpevole. E’ assente anche un sistema che possa permettere di sorvegliare da remoto cani che hanno particolari problemi. Nel caso di una gravidanza che volge al termine, ad esempio, il personale del canile è costretto a recarsi frequentemente sul luogo, durante la notte, per controllare se ha avuto inizio il travaglio o se si stanno verificando delle complicanze. Questa necessità crea un disagio al personale che si trova a doversi recare in canile fuori dall’orario di lavoro.
Assenza di supporto informatico: attualmente nessuno dei due canili dispone di un’infrastruttura informatica già presente, da poter integrare; inoltre non dispongono nemmeno di un gestionale che dia supporto nella catalogazione degli animali presi in cura.
L’obiettivo è quello di rendere il canile più "Smart", introducendo della strumentazione che permetta di risolvere in maniera parziale o totale le problematiche descritte precedentemente, mantenendo un costo accessibile.
Nello specifico si vogliono incontrare le esigenze del gestore e degli addetti, agevolando le operazioni di:
monitoraggio dello stato di salute dei cani tramite:
rilevazione dei consumi di cibo e acqua;
monitoraggio del comportamento del cane.
In questo modo è possibile cogliere in maniera preventiva segnali che possono indicare un problema di salute e aiutare il responsabile sanitario nella risoluzione e nella diagnosi dello stesso.
automatizzazione delle operazioni di cura quotidiana attraverso:
automatizzazione del rifornimento di cibo e acqua
possibilità di scegliere, per ciascun cane, la quantità del cibo da somministrare e la frequenza.
In questo modo è possibile gestire in maniera più precisa l’alimentazione dei cani e impostare delle quantità di cibo particolari in caso di condizioni di salute che richiedono un particolare piano alimentare, sollevando da questo incarico i volontari, che svolgono un’attività non tracciabile e discontinua. Inoltre, sarà possibile per il responsabile sanitario consultare i dati riguardanti l’alimentazione del cane e, di conseguenza, fornire diagnosi più precise.
sorveglianza globale del canile da remoto: l’introduzione di un sistema di sorveglianza permetterà a chi di competenza di monitorare lo stato del canile anche da casa.
Mantenimento dello storico dei dati registrati: in questo modo sarà possibile consultare sia le informazioni riguardanti i cani che i dati che riguardano le condizioni del canile, permettendo anche di fare dei confronti su base temporale;
consultazione dei dati acquisiti ed elaborati: verrà fornita la possibilità di accedere allo storico dei dati medici su un Database, affinché il veterinario abbia una visione globale del quadro medico e possa velocemente filtrare le informazioni anche se non ha seguito il paziente dall’inizio.
[optional] monitoraggio approfondito dei parametri vitali: mediante l’installazione di sensoristica che permetta il monitoraggio di temperatura, battiti, movimento, ecc… sarà possibile tenere ulteriormente sott’occhio cani che si trovano in condizioni di salute che necessitano di particolari attenzioni.
Introduzione di un sistema informatico: poiché non vi è un sistema informatico preesistente da integrare e vi sono poche disponibilità economiche, si è pensato di avvalersi di una piattaforma cloud sulla quale è possibile mantenere lo storico ed operare tramite l’utilizzo di un broker MQTT per la comunicazione con sensori e attuatori. Questa soluzione è stata indicata come preferibile dal canile che ritiene più accessibile pagare mensilmente un servizio piuttosto che investire in una soluzione ad hoc.
Il topic scelto non gode di particolare attenzione in letteratura. Dalle informazioni che abbiamo raccolto su ricerche, studi e applicazione di idee similari alla nostra è emerso quanto segue:
Automazione: sono state condotte alcune ricerche che riguardano interventi di automazione del sistema di alimentazione per gli allevamenti, ma si tratta di progetti con un forte imprinting economico.
Distribuzione del cibo: alcune soluzioni commerciali offrono la distribuzione automatica del cibo ad orari temporizzati, senza possibilità di dosaggio o di rilevamento dei consumi.
Monitoraggio parametri: in ambito commerciale esistono soluzioni che si focalizzano soprattutto sul monitoraggio e la notifica dei parametri vitali dell’animale.
Fusione dei due ambiti: non siamo riusciti a trovare progetti che fondono i due ambiti come invece fa la nostra proposta. La nostra soluzione, infatti, tenta di fondere le due idee e di proporre un sistema remoto e scalabile, che monitori i parametri vitali, che possa anche fornire un automatismo alla gestione del cibo e dell’acqua erogati al cane e, inoltre, che sia in grado sia di intercettare la presenza di sintomi riguardanti il consumo di cibo e acqua in base all’analisi dei dati raccolti.
Per quanto riguarda, invece, l’ambito dei sensori; lo stato dell’arte è in continua evoluzione, e possiamo trovare:
Sensori ad hoc: impiegati nell’ambito della ricerca per il monitoraggio dei parametri vitali dei cani
Collari smart: che si basano su un’idea simile alla nostra ma sono sistemi proprietari, commercializzati come prodotti ad uso domestico, completi di gps e altri sensori e supportati da un’applicazione che si rifà a quelle per gli smartwatch. Il costo di questi collari è dell’ordine delle centinaia di euro e deve essere associato ad un abbonamento mensile o annuale.
[fig:PetPace] 
I sensori di battiti tradizionali utilizzano un fascio luminoso per identificare la frequenza del battito cardiaco. Questa tecnologia si presta male per gli animali che presentano del pelo, come i cani, per questo sono in via di sviluppo sensori specifici che utilizzano principi diversi. Attualmente sono in corso delle ricerche su sensori di altro genere che possano essere adatti anche anche ai cani.
Nonostante ciò la nostra soluzione utilizza un sensore classico. Presupponendo che si utilizzi un collare smart solo per gli animali che, a causa del loro stato di salute, sono in osservazione, è possibile supporre che il pelo possa essere rasato durante il periodo di degenza.
Per quanto riguarda le soluzioni riguardanti l’automatizzazione del cibo e dell’acqua le soluzioni commerciali sono davvero tante molto simili.
Da questo punto di vista la nostra soluzione può dirsi all’avanguardia pur non essendo incentrata sull’uso domestico. Grossa parte di questi sistemi, infatti, usano: sensori del livello dell’acqua, bilance e sensori luminosi. Inoltre alcuni sistemi più all’avanguardia consentono, tramite l’utilizzo di tecnologie come BLE, di monitorare da App i consumi e gli allarmi, non fornendo però alcun tipo di inferenza.
Attualmente il nostro sistema fornisce un’inferenza banale, ciò non toglie che in un futuro sviluppo associato ad uno studio comportamentale dell’animale non sia possibile implementare inferenze più complesse.
Quanto appena detto costituisce lo stato dell’arte nell’uso commerciale. Per quanto riguarda lo specifico ambito del canile, invece, non sono state trovate applicazioni simili.
Per avere una visione più chiara di quello che è lo stato dei canili in Italia ci siamo rivolti a due canili:
ACPA - Canile intercomunale di Cesena Ci siamo recati fisicamente al canile di Cesena per discutere e toccare con mano lo stato tecnologico dello stabile, questo per valutare la fattibilità e la bontà della nostra soluzione. Le immagini della visita possono essere consultate nel pdf del reportage fotografico.
Canile intercomunale "Soffio di Vento"- Pisa Abbiamo contattato in via totalmente telematica il canile per comprendere se una soluzione del genere esistesse o fosse adottata da qualche parte e per avere una visione concreta dei problemi che vengono riscontrati per i quali avremmo potuto proporre una soluzione.
Entrambe le fonti ci hanno confermato che almeno in Italia lo stato dei canili risulta essere tecnologicamente obsoleto. La soluzione proposta ha ricevuto un caloroso interesse da parte di entrambi i canili, con particolare entusiasmo per le rilevazioni dei consumi e il monitoraggio dei parametri vitali, con notifiche in caso di rilevazioni anomale. Attualmente i canili contattati sono privi di una qualunque forma di monitoraggio, o automatizzazione di qualunque genere. Il punto di forza di questo progetto risiede nella sua semplicità di dispiegamento, nelle tecnologie altamente accessibili e nel fatto che molti canili avrebbero il bisogno di una soluzione simile. Il collare e l’inferenza sui consumi sono la parte che ha riscosso più successo poiché l’automatizzazione presenta alcuni svantaggi. A detta del canile di Cesena dipende dalle norme del canile e dal modo con cui si vogliono addestrare i cani poiché buona parte delle pratiche di addestramento ruota attorno al cibo, che viene utilizzato sia come premio che come modo per far si che l’umano venga percepito come alpha. La più grande critica mossa riguarda il fatto che se l’animale viene nutrito in maniera automatica allora non sarà abituato a ricevere cibo da persone, ed essendo l’adozione dei cani lo scopo principe del canile è probabile che il sistema automatizzato venga adottato solo da canili di grandezza medio-grande o la quale gestione non prevede l’addestramento.
Il processo di sviluppo è stato guidato dalla filosofia data dal Domain Driven Design. La realizzazione di questo progetto costituisce, per i membri del team, un ottimo terreno di prova per mettere in campo molti degli aspetti di gestione propri di questo approccio.
Il Domain Driven Design è un approccio che si rivela ideale per la conduzione di progetti non banali che richiedono l’interazione di persone con background differenti. L’obiettivo è quello di evitare gli errori comuni che tendono a verificarsi in mancanza di una buona gestione e comunicazione. Più che un pattern o un framework, il DDD è una filosofia che rappresenta una guida.
Il Domain Driven Design è un approccio operativo che tenta di uniformare il modello di dominio con l’artefatto generato, cercando di muovere concetti fondamentali per l’ambito all’interno del software e della documentazione, che dovranno quindi rispecchiare in dominio utilizzando il giusto linguaggio. Il classico approccio di standardizzazione delle pratiche di analisi e progettazione, tende a deviare il software lontano dal contesto di dominio. Questo rende il prodotto poco robusto e solo parzialmente coerente con l’ambito. Per questo il DDD non è vincolato ad una particolare tecnologia o pattern di design, favorendo lo sviluppo mirato caso per caso. Tenta di trasmettere i costanti cambiamenti del dominio nel prodotto mantenendo una dualità costante che consente di ottenere un prodotto più coerente e leggibile sia per il team che per il cliente.
Generalmente utilizzato per progetti sia di medie che di grandi dimensioni che evolvono nel tempo, non è una metodologia o un architettura. Può essere visto come un approccio che coinvolge più strati socio-tecnologici orizzontalmente, dal business ai vincoli implementativi fino alle buone pratiche di coding.
Concetti chiave che DDD porta con sè:
Strategia: ogni problema ha la sua soluzione, non esiste il famoso silver bullet, bisogna trovare il giusto approccio e non cercare di eccedere con eccessivi strumenti o tecniche ove non richiesti. Non tutte le parti del prodotto necessitano la stessa modellazione, applicare ogni feature dell’ approccio DDD per tutti i problemi può portare a problemi peggiori. DDD impone di identificare e distinguere il Core Domain; la parte che detiene il business value maggiore e di dedicarvi più risorse e tempo. Mentre per le restanti parti, i subdomain, è possibile utilizzare un approccio più conservativo.
Learning: forse il passo più critico per ottenere un prodotto di qualità. Il processo di apprendimento deve essere costante e continuativo, consentendo di diffondere un sapere condiviso che incentiva la comunicazione e agevola la costruzione di una soluzione coerente e coesa con la terminologia del dominio. L’apprendimento ideale dovrebbe essere tale da faticare nel distinguere un Domain expert da un membro del team del progetto in chiave DDD.
Linguaggi: la comunicazione è fondamentale all’interno di un team, il DDD spinge la classica comunicazione oltre i confini del team fino agli attori del dominio stesso promuovendo un linguaggio comune. Fondamentale che i concetti imparati e diffusi siano precisi, cercando di limitare o annullare l’ambiguità,tramite una serie raffinamenti che passa per il colloquio costante e la compartizzazione dei concetti.
Modelli multipli: risolvere un problema con un singolo modello rende il tutto offuscato e poco strutturato, il DDD porta il concetto di Divide et impera a livello di modello promuovendo non solo una divisione il più semanticamente corretta e precisa ma anche una visione d’insieme fornita tramite una mappa delle interazioni che tenga traccia delle comunicazioni. Mette in campo anche pratiche per rendere il bordo dei concetti il più nitido e inalterato possibile.
Architetture sofisticate: le tecnologie si sono evolute e il DDD ne ha preso nota, il DDD promuove l’utilizzo e la progettazione di architetture dedicate al problema e il distaccamento da approcci classici per le parti core del dominio.
Advance and clean coding: il DDD non è adatto a progetti semplici one shot. Il suo focus risiede in quei prodotti fatti per evolversi e durare nel tempo, promuovendo lo studio continuo del dominio che è in costante cambiamento. Per questo non è sufficiente mantenere il codice alla buona. Al contrario è necessario mettere in campo tutte le good practice del caso, lasciando del clean code capibile e facilmente evolvibile in qualcosa anche di drasticamente diverso.
Gli aspetti principali del DDD sono:
Dominio: è l’area tematica in cui si inserisce il progetto che si vuole realizzare. La corretta definizione del dominio è di estrema importanza in quanto esso rappresenta il perno attorno a cui ruota tutto il DDD. La figura dell’esperto del dominio rappresenta pertanto una risorsa inestimabile poiché grazie ad essa è possibile avere una visione reale dell’ambiente in cui si andrà ad operare.
Modello: Una rappresentazione distillata delle regole, assunzioni e scelte del modello. Descrive e astrae dando una formula snella alle tematiche, utilizzato per risolvere problemi correlati al dominio stesso.
Ubiquitous language: si tratta di un linguaggio condiviso tra sviluppatori, utenti e collaboratori, la quale definizione permette di facilitare la comunicazione tra persone con diversi background ed evitare ambiguità che portano a errori e incomprensioni.
Contesto: definisce l’ambiente per il quale un vocabolo dell’Ubiquitous Language o un’espressione assume uno specifico significato.
Per sviluppare il progetto è stata scelto il framework Scrum. Questo per permettere di mantenere alta la qualità, massimizzare la soddisfazione del cliente e minimizzare il rischio nella produzione. Inoltre la sua natura iterativa e incrementale si presta bene allo sviluppo del progetto, di sua natura fortemente basato sull’interazione con il cliente. Tuttavia, essendo il team composto solo da 3 componenti, i quali lavorano sullo stesso progetto, ne è stata adottata una versione leggermente semplificata descritta in seguito.
Il processo di sviluppo Scrum-Inspired modifica in primis i ruoli: il committente è facilmente identificabile nel proprietario del canile, ma il product-owner e lo scrum-master sono sono essi stessi anche developer (parte del team di sviluppo). Inoltre, particolare enfasi è stata posta sulla cross-fertilization, lo scambio di competenze, essendo il team piccolo ma molto eterogeneo, senza struttura interna. L’organizzazione delle attività è stata impostata attorno agli sprint, concetto chiave di Scrum. Ogni sprint fornisce una suddivisione temporale del progetto (composto sia dal software che dal report) definendo i meeting, gli obiettivi e i risultati perseguiti. Per ogni Sprint, seguendo il modello del framework, è stato definito un meeting iniziale di circa un’ora, di pianificazione. Nello Sprint Planning, infatti, la divisione in due parti è stata unificata. Essendo il product-owner anche developer non può essere escluso dalla nella seconda parte come impone la metodologia Scrum. All’interno del meeting iniziale dapprima le priorità degli item sono state assegnate da un membro del team, impersonando temporaneamente il product-owner. In seguito, è stato raffinato collaborativamente il product-backlog: gli item sono stati espansi e sono stati scelti sia i goals/obiettivi generali dello sprint corrente sia quali item prendere in carico per esso (unificando parte due dello Sprint Planning). Generato lo sprint-backlog, sottoinsieme del product-backlog, in cui sono presenti i task identificati in precedenza, questi vengono presi in base volontaria. Ogni giorno, in seguito, è stato fatto il canonico daily-Scrum, per l’aggiornamento dei membri del team relativamente al potentially-shippable-product-increment dello sprint. Per identificare questo la "Definition of Done" è stata formalizzata collettivamente come: "i task sono intesi completi se sono stati sviluppati, testati con successo e documentati". Infine è stato mantenuto il meeting finale, ma la suddivisione nelle tre parti anche qui è stata condensata. Nel meeting la prima parte è stata dedicata al "refinement" del backlog, in cui si aggiorna in base a quello che è stato fatto. In seguito si è passati alla "sprint review" in cui si è condiviso con gli altri ciò che è stato fatto. Inoltre in questa fase è stato coinvolto il committente, spesso per mezzo della piattaforma Telegram, per renderlo partecipe del progresso del progetto e verificare che questo proceda nella giusta direzione. In ultimo, nella "Sprint Retrospective", è stato discusso cosa ha funzionato e cosa no, quali aspetti organizzativi sistemare e correggere per il prossimo sprint.
In questa sezione verrà spiegato come il progetto è stato organizzato dal punto di vista pragmatico, con quali strumenti e tecnologie si è scelto di procedere.
Per ottimizzare il tempo di sviluppo si è scelto di utilizzarne uno per dare un ritmo al progetto in generale e per i vari sprint, questo ci aiuterà nell’ottimizzare il tempo e a rispettare le deadline. Nel capitolo relativo agli sprint, in [Fig. 12.1] si riporta il diagramma di Gantt risultante.
Per quanto riguarda la scelta della licenza da usare sono state prese in considerazione le principali: GNU GPL (general public licence), LGPL (lesser GPL), MIT LICENSE, APACHE LICENSE 2.0. La GNU GPL e la LGPS sono state ritenute troppo dure nella loro imposizione di gratis e open source per gli artefatti derivati, anche se la seconda permette il linking. E’ stata concordata la natura libera e gratuita del software, senza fornire garanzia, per questo motivo è stata scelta la licenza MIT, estremamente permissiva, GPL compatibile e senza forte CopyLeft, per cui i derivati possono essere distribuiti con differente licenza. Questa non protegge marchi e brevetti, tuttavia non forza chi fa un lavoro derivato a scrivere i cambiamenti al software come la Apache Licence 2.0.
Lo scope del versioning scelto è stato interno, quindi le modifiche di maggiore impatto sul codice fanno progredire il numero di versione maggiormente rispetto alle modifiche grafiche percepite dall’utente. Per questo motivo è stato scelto l’utilizzo di semantic versioning: MAJOR.MINOR.PATCH per il prodotto, inclusa la relazione. La logica e il meccanismo retrostante per l’automazione di questo sono spiegati nel capitolo 3.4 CI e Automazione..
Per le Board di Scrum è stato utilizzato GitHub Projects. La scelta è ricaduta su questa opzione anziché sui competitor, quali Trello, data la possibilità di interazione con il progetto stesso e con le repository. La struttura delle varie board è stata organizzata ad albero: Una board principale all’interno dell’organizzazione funge da Product-Backlog-Board. Questa viene mantenuta dal Product-Owner, egli sceglie per ogni Sprint la priorità degli Items.
All’inizio di ogni sprint, gli Item più importanti verranno inoltre eletti come Sprint Goals (COSA fare all’interno dello sprint). Nel progetto gli item corrispondono uno a uno le User Stories, trasformate in Issue, con relativo tag, da risolvere durante gli sprint.Gli Item principali vengono raffinati iterativamente, quelli in cima infatti diverranno via via più specifici.
All’interno delle repository invece sono stati incrementalmente implementate tante board quanti gli Sprint-Backlog. Vi sarà infatti una board per ogni Sprint. Non sono state usate le milestone per gli spint poichè nella piattaforma una issue può essere assegnata ad una sola milestone, mentre è possibile condividerla tra più board qualora non venisse completata in un solo Sprint. Le Sprint Backlog Boards tengono traccia degli specifici task da sviluppare all’interno dei singoli Sprint (COME raggiungere lo Sprint Goal) a partire dall/dagli Item selezionati. Le user stories selezionate dalla board del Product Backlog faranno parte anche della board per lo Sprint Backlog, assieme ai relativi raffinamenti. Gli Item principali vengono infatti raffinati iterativamente, quelli in cima diverranno via via più specifici.
I raffinamenti sono stati istanziati come altre issue, le quali vengono referenziate dalla user story principale, che acquisterà automaticamente in indicatore dei sottotask completati. Questo ci ha permesso di tenere traccia dell’andamento di uno sprint con granularità anche molto fine. Inoltre le sotto-issue possono essere condivise tra user-stories, evitando la ripetizione. Qualora una venga completata tramite l’aggiunta di una porzione di codice è possibile, tramite commit con sintassi closes #NUMERO-ISSUE, chiudere in automatico la sotto-issue. Questa verrà inoltre spostata nella colonna Done, e automaticamente l’indicatore dei task completati di una user-story avanzerà. Una volta completato la/le user-stories dello Sprint anche nel Product Backlog la relativa issue si sposterà nella colonna Done. Per il completamento dello Sprint Goal è stata considerata valida la "Definition of Done" specificata in precedenza.
Una board aggiuntiva è stata creata per tenere traccia dei progressi della relazione. In questo caso ogni capitolo è stato definito come milestone, completabile alla scrittura di tutti i sottocapitoli, identificati come task, quindi issue, appartenenti alla relativa milestone. I vari task sono stati divisi in categorie standard per lo Scrum: "to Do", "in Progress", "Done". Qualora un sottocapitolo della relazione venga completato, tramite Overleaf è semplicemente possibile chiudere la relativa issue tramite il messaggio di commit visto in precedenza. Nel momento in cui un sottocapitolo viene chiuso, la relativa issue si sposta nella colonna Done e il progresso relativo alla milestone del capitolo e dell’intero Report verrà aggiornato. In entrambi i tipi di board, relative agli sprint o alla relazione, è possibile aprire delle issue inerenti bug trovati, problemi alla sicurezza, o accorgimenti. Queste Issue compaiono nella board e possono venire assegnate a un componente specifico del gruppo affinchè se ne occupi.
Come strumento di messaggistica informale all’interno del gruppo, si è scelta la piattaforma Telegram. Accessibile facilmente da smartphone e da computer permette di aggiornare i componenti del gruppo immediatamente qualora vi siano delle urgenze. Il punto di forza rimane la possibilità di spedire file di tutti i formati e di poter inserire nel gruppo dei BOT per automatizzare alcune azioni, tra cui le notifiche. Un’overview più chiara dell’utilizzo dei BOT per l’automatizzione verrà fornita nella .
Per facilitare la coordinazione quotidiana è stato creato un bot per inviare i sondaggi sul gruppo Telegram. Questo sia poiché il progetto è stato svolto prevalentemente a distanza, sia perché alcune parti necessariamente hanno richiesto la presenza di tutto il team.
Discord, nota piattaforma di comunicazione VoIP, è stato utilizzato invece come strumento di comunicazione formale. Si è creato un server apposito per il progetto, chiamato "SmartDogHouseChannel", con multiple stanze lavoro per diverse occasioni. I canali vocali sono stati utilizzati anche per la condivisione dello schermo, fattore chiave per la sincronizzazione e la comprensione senza dispendio non necessario di tempo.
In questo capitolo si analizza la parte di integrazione e automatizzazione sia del progetto software che della relazione.
Considerato che anche la relazione deve essere versionata e automatizzata, essendo parte del software e descrivendolo, abbiamo iniziato partendo da essa. Come linguaggio di markup è stato scelto LaTeX, per la sua flessibilità e potenza. Come strumento per la compilazione invece è stato scelto Overleaf.com, poiché ha 3 vantaggi principali che il team ha individuato. Permette di collaborare sullo stesso progetto, in real-time, osservando i cambiamenti fatti dai collaboratori con la compilazione immediata, discutendone vocalmente i dettagli tramite la piattaforma di comunicazione VoIP. Permette inoltre di non dipendere da diversi IDE per LaTeX installati in locale, che creerebbero conflitti e mismatch visuali. Infine permette di integrarsi con GitHub (solo Overleaf Professional), pushando i commit con i nomi desiderati in tutta fluidità direttamente dalla piattaforma web. Per incorporare gli elementi grafici più importanti si è fatto uso della piattaforma Draw.io. L’integrazione con GitHub è anche qui presente, permettendo di aprire il progetto e pushare le modifiche direttamente dal web. Inoltre è notevole il fatto che gli artefatti PNG abbiano essi stessi i metadati del progetto garantendo tre vantaggi. Il primo riguarda la non necessità di salvare un ulteriore file progetto rispetto all’artefatto. Il secondo riguarda la possibilità di aprire direttamente i PNG e poter fare le modifiche desiderate. Il terzo è l’intrinseco versionamento pure dei progetti assieme ai PNG. Per le grafiche dove è necessaria più una collaborazione real-time dei membri del team, con schemi inerenti al DDD più esotici, oppure ove è più presente il contatto con il cliente, la scelta è ricaduta sulla piattaforma Miro. Nel repository, tramite l’utilizzo di GitHub Actions, è stato implementato un processo di automatizzazione con multipli Job.
Il primo Job si attiva ad ogni push ricevuta, compila il Latex per mezzo di una action e, qualora si verificassero degli errori, li salva in un log più piccolo, che verrà caricato come artefatto. Invece, se nessun errore è presente, è il pdf generato a venire caricato come artefatto.
La terminazione di questo Job attiva altri due Job, dipendenti, che si occupano delle notifiche Telegram. Anche qui per mezzo di una action viene mandato un messaggio di notifica sul gruppo, sia se la build del Latex abbia avuto successo, sia che ci siano stati errori. In caso di fallimento assieme al messaggio viene inoltrato sul gruppo pure il log conciso che contiene solo gli errori Latex.
Per la gestione delle release è stato inoltre implementato un altro Job che verifica se nel messaggio di commit è presente uno speciale segnalatore -TAG. Nel caso sia presente vuol dire che è stato specificato un tag manualmente, ciò può avvenire qualora si voglia far avanzare la versione Major o Minor avendo fatto cambiamenti significativi. La scelta di permettere la numerazione dei tag a mano è stata dettata dalla necessità di controllo e cusotomizzazione di questi ultimi: in una relazione si vuole scegliere quando effettuare la release e, adottando il semantic versioning, il grado di cambiamento che si ritiene più opportuno. Qualora non venisse specificato un tag, in automatico viene incrementato l’ultimo numero (bugfix) del semantic versioning.
Il Job successivo si occupa del deploy, e viene attivato solamente se è stato generato correttamente il tag nella parte precedente. Questo Job scarica il pdf precedentemente generato negli artefatti e si occupa di farne una release con nome coerente e con il tag specificato.
Al termine della release vengono lanciati altri due Job, anch’essi dipendenti, che si occupano di notificarne il completamento. Il primo usa una GitHub Actions per inoltrare una mail ai componenti del gruppo contenente il pdf della release. Per fare ciò si è dovuto creare un account Gmail specifico che funge da casella di invio. Si può inoltre sfruttare come account di notifica per un’eventuale newsletter agli iscritti ad ogni nuova release. Il secondo Job si occupa parallelamente di inoltrare un messaggio Telegram sul gruppo dei developers contenente anch’esso il pdf della release, il responsabile e il testo del commit.
Un ultimo Job è stato creato per gestire anche le GitHub Pages, le quali forniscono un sito in cui consultare la relazione online. Per fare ciò è stato creato un nuovo branch sul quale viene fatto il commit dei file Html generati grazie a Pandoc. In conclusione sarà possibile consultare questo report sia in versione pdf automaticamente generata ad ogni cambiamento, che direttamente via sito web, prodotto dai sorgenti.
HackMD
Overleaf
Draw.io
Miro (link alla board)
GitHub Actions
Telegram Bots
Pandoc
GitHub Pages
Riguardo al software del progetto, sono stati utilizzati parecchi linguaggi di programmazione differenti, quindi le soluzioni adottate variano in base alle implementazioni e all’importanza relativa. Di seguito si riporta una linea generale implementata nel repository principale per il software, poi seguita anche dagli altri repository, con dovute eccezioni in base alle limitazioni dei linguaggi. Avendo usato Python (e il suo derivato MicroPython) per le parti principali non è stato necessario un vero e proprio strumento di build, in quanto basta un’interprete per far girare il codice. Particolare attenzione è stata fatta ai test, implementati tramite unittest in un package dedicato. Tramite il compando discover tutti i test implementati vengono eseguiti in maniera automatica. Ciò ha permesso di scoprire parecchi bug prima di rilasciare il codice online. La procedura è stata automatizzata sfruttando la CI di GitHub Actions, la quale fallisce se i test non vengono eseguiti correttamente.
Si è fatto ricorso agli stub data la necessità di testare il codice per i microcontrollori e l’impossibilità di poterlo testare in maniera totalmente automatica su di essi. Infatti, la soluzione ideale per comodità e qualità è di poter eseguire i test su un normale computer, automatizzando il tutto in cloud. Tuttavia, per poter testare il codice Micropython devono essere presenti le classi che il firmware mette a disposizione quando installato sui microcontrollori. Purtroppo non è possibile installare il firmware su un computer, il che rende normalmente impossibile eseguire e testare il codice. Per ovviare al problema sono stati inseriti nel codice della repository degli stub che permettono di simulare il firmware installato sulla macchina fisica e il comportamento dei rispettivi sensori e attuatori. Gli Stub purtroppo devono essere inseriti a livello del codice, in quanto un’altra posizione modificherebbe i percorsi di import e il codice non sarebbe più eseguibile sul microcontrollore. In questo modo è possibile verificare continuamente il codice scritto attraverso i test eseguiti automaticamente sul repository. Un messaggio Telegram viene mandato anche qui sul gruppo dei developer per segnalarne l’esito.
Eseguiti i test è buona norma osservare la coverage di questi. In questo caso per Python è stato usato il pacchetto coverage, questo permette di generare la coverage dei test e il relativo sito web. Tramite GitHub Actions e GitHub Pages questo è stato messo online, per una rapida consultazione. Eventualmente è anche stata generata la coverage in xml per siti come CodeCov, i quali permettono di ottenere anch’essi un resoconto ordinato. La coverage creata viene pubblicata per entrambi i branch main e develop.
Il codice è stato documentato per assicurare la qualità. Il pacchetto pdoc usato per il repo principale permette di generare la documentazione html a partire dai sorgenti. Anche qui è stato automatizzata la creazione e il deploy del sito web tramite GitHub Actions e GitHub Pages per facilitarne la consultazione.
Anche in questo caso, come nel report, il versioning è automatico, con la possibilità di controllo manuale. Qualora non venga specificato un tag nel commit la CI implementata di GitHub Actions genera un tag con la versione bugfix incrementata di uno. Qualora un tag venisse specificato il progetto si porta avanti a quella versione. Ciò ha reso molto preciso e veloce il versionamento del nostro software in caso di cambiamenti minimi o estesi. Il deploy del software viene fatto puntualmente in automatico con la versione elaborata all’interno delle Releases di GitHub.
Per quanto riguarda la parte di quality assurance, la scelta è ricaduta su tre servizi di aziende completamente diverse: Sonarcloud, Codacy e Codefactor. I relativi servizi offrono un’analisi della qualità codice completamente gratuita per il piano base. La scelta di diversificare i fornitori del servizio è motivata da due ragioni. La prima è che sono state riscontrate interruzioni e bug nei corrispettivi siti, la diversificazione offre una copertura 24/7. La seconda ragione consiste nel fatto che ognuno offre solo alcune misurazioni sul codice tra Maintainaility, Issues, Complexity, Duplicaizione, Coverage, Security, Vulnerabilities, Bugs. Usare tre sevizi offre in conclusione una copertura maggiore sulla qualità. Qualora le pull request o il codice del repo non soddisfi gli standard ciò permette di immediata individuazione. Per l’aggiornamento delle dipendenze è stato attivato Dependabot su tutti i repository, questo permette di ottenere delle pull-request in automatico qualora venisse individuato un possibile aggiornamento.
Test/Coverage/Documentation Software
GitHub Actions
GitHub Pages
Telegram Bots
Dependabot
Sonarcloud/Codacy/Codefactor
Per poter fare un’analisi soddisfacente è fondamentale avere una buona conoscenza del dominio e della sua terminologia, cosa che, se fatta in autonomia, potrebbe richiedere parecchio tempo. Per questo motivo è importante collaborare con gli esperti di dominio, che aiutano a comprendere i componenti del dominio, le dinamiche, i termini tecnici e gli aspetti critici. Il knowledge crunching è il percorso che porta chi deve realizzare il sistema ad avere una migliore comprensione non solo di quanto deve essere fatto, ma del perché, permettendo di non fermarsi alle specifiche, ma di capirne il senso.
Nel nostro caso le sessioni di knowledge crunching sono state svolte interpellando un esperto di dominio per via telematica.
Prima sessione: nella prima sessione, il colloquio con l’esperto ha permesso al team di comprendere:
gli aspetti principali della gestione del canile;
le figure coinvolte;
i ruoli presenti all’interno del canile;
le mansioni che vengono svolte quotidianamente;
i processi di gestione.
Queste conoscenze hanno permesso di dare il kick-off al progetto.
Sessioni successive: successivamente il processo è stato continuo, sono stati svolti degli incontri periodici per:
controllare che il progetto proseguisse nella direzione sperata;
sciogliere alcuni dubbi sorti in corso d’opera;
verificare la corretta comprensione di alcuni concetti chiave.
Data l’ovvia problematicità nell’incontrarsi, la comunicazione è stata gestita da remoto, utilizzando le seguenti piattaforme:
Telegram, per chiamate vocali e brevi chiarimenti
Discord, per la condivisione schermo con gli artefatti visuali
Durante le interazioni sono state create multiple rappresentazioni visuali a guida e supporto della conversazione.
Il gruppo parlando con il responsabile del canile (il maggiore esperto del dominio) ha indagato con maggiore enfasi i concetti necessari per la creazione di un buon software, tralasciando dettagli pleonastici.
Il focus è stato su capire quello che serve per lo sviluppo di un software che soddisfi le reali necessità del cliente. I dettagli su cui l’esperto del dominio ricadeva spesso, infatti, hanno rivelato dove le energie dovessero essere maggiormente spese.
In questo caso gli esperti del dominio sono anche i clienti. Questi ultimi forniscono il problem-space, mentre i primi forniscono il solution-space.
Per la comprensione degli obbiettivi di più alto business value, si è costruita in maniera interattiva e collaborativa un’impact map, sotto la supervisione di team, scrum master e product-owner. L’uso di questo diagramma mira a mantenere un livello non troppo formale da risultare incomprensibile agli estranei al dominio, ma nemmeno totalmente informale, perdendo efficacia comunicativa.
Il risultato ha portato in evidenza i due principali obbiettivi di business, evidenziando in maniera chiara la loro suddivisione, e le soluzioni per raggiungere i risulati attesi.
Con una visone d’insieme leggermente più definita, ci siamo cimentati nella stesura delle user stories per ogni ruolo. Dalla moltitudine emersa, sono state identificate, cercando di seguire i requisiti di business individuati, le più calzanti, legate ad ogni obiettivo dell’impact map.
La definizione delle user-stories ha portato naturalmente a indagare il significato di alcuni termini usati. Questo ha spinto subito allo sviluppo concorrente di un ubiquitous language per i vocaboli più importanti. Questo è stato poi continuamente raffinato durante i successivi meeting. Nel prossimo capitolo viene analizzato questo processo.
L’Ubiquitous Language deve essere espresso nel modello di dominio, infatti unisce le persone del team di progetto. Lo scopo è eliminare le imprecisioni e le contraddizioni degli esperti di dominio, non è infatti imposto da questi, ma raggiunto collaborativamente. L’Ubiquitous Language si evolve nel tempo, non è definito interamente in una sola riunione, i concetti spesso si aggiungono, vengono sviscerati e partecipano nella comprensione del dominio. Infatti quelli che non fanno parte dell’Ubiquitous Language devono essere rifiutati.
La definizione di un organigramma generico che individua le figure che operano all’interno del canile e le loro interazioni è stata raggiunta in seguito all’analisi della struttura gerarchica dei due canili che sono stati interpellati in qualità di esperti del dominio. Si è cercato di cogliere gli aspetti comuni e di utilizzare le differenze come base per elaborare un modello che interiorizzasse un livello di astrazione tale da permettere al sistema che ne deriverà di adattarsi a un qualsiasi canile. Il seguente organigramma più che sulle effettive figure nasce dall’astrazione dei principali ruoli che esse ricoprono. Questa scelta è dovuta al fatto che dallo storytelling di entrambi i canili è emerso un certo grado di caoticità nella suddivisione delle mansioni che spesso, per necessità, tendono ad essere svolte da chi si trova lì in quel momento. Da ciò deriva che, più o meno, tutti i dipendenti dovrebbero essere in grado di fare tutto anche se, nella pratica, una suddivisione dei ruoli esiste, seppure non netta. Ciò accade anche per le mansioni di tipo burocratico, la cui suddivisione avviene mediante accordo verbale tra i colleghi e non in base a ruoli scritti. De facto, si sa che a occuparsi di un certo tipo di pratiche è una determinata persona, ma, sulla carta, i dipendenti hanno lo stesso identico contratto.
I canili da noi consultati, tuttavia, sono di piccole/medie dimensioni. Più il canile è grande, più la gestione risulta complicata e di conseguenza diventa sempre più forte la necessità di definire delle responsabilità. Per questo motivo il seguente organigramma è stato costruito in modo da suddividere secondo criteri logici e concettuali le mansioni, mappandole con delle figure, ma permettendo alla stessa persona di inglobarne più di una.
In questa fase sono stati individuati i requisiti del sistema, partendo dalle descrizioni di alto livello, ottenute dal committente durante il knowledge crunching. Successivamente si è proceduto con un raffinamento che ha portato alla definizione di requisiti più specifici, chiari e strutturati.
Si definiscono di seguito le aspettative del cliente e i requisiti che il prodotto dovrà soddisfare, espressi con una terminologia ad elevato livello astrattivo.
Il prodotto dovrà diminuire l’intervento umano necessario per la quotidiana cura degli ospiti (Riempimento ciotola acqua/cibo); la riduzione del lavoro deve essere maggiore o uguale al 30%.
Il prodotto dovrà consentire di diminuire il lavoro su base volontaria, grazie alla riduzione delle operazioni di cura quotidiana, permettendo ai volontari di concentrarsi solo sulla socializzazione e lo svago dell’animale. Diminuisce così l’interferenza al di fuori delle loro mansioni, e migliora la tracciabilità del lavoro svolto, essendo il lavoro volontario incostante e meno affidabile.
Opzionalmente il prodotto dovrà fornire un monitoraggio a distanza degli animali ospitati. Questo consentirà al personale incaricato di monitorare parametri come: frequenza cardiaca e temperatura corporea. Verrà diminuito anche l’intervento veterinario, non essendo necessaria la presenza in loco del professionista. La riduzione delle presenze dovrà consentire di diminuire i costi di un valore maggiore o uguale al 10%.
Di seguito vengono riportate le richieste mosse dal cliente in maniera informale evitando termini tecnici, successivamente tali richieste saranno formalizzate per quanto possibile. Il prodotto dovrà fornire:
l’accesso al sistema da qualunque dispositivo munito di connessione alla rete, anche esterna al canile
prestazioni adeguate alle operazioni richieste (con soglie adeguate caso per caso), come il rilevare se il cane ha bisogno di cibo o acqua
un interfaccia intuitiva, comprensiva di una pagina per l’accesso e un menu principale
uno storico per ogni animale
un aaccesso rapido e reattivo evitando tempi troppo lunghi per le operazioni
un sistema di sorveglianza semi automatizzato in grado di identificare eventuali anomalie, come cani che escono senza permesso
opzionalmente delle notifiche sullo stato di salute dell’animale al personale
delle notifiche in caso di malfunzionamento del sistema stesso
delle notifiche, nel caso in cui il cibo sia in esaurimento
Di seguito sono riportate tutte le user stories ritenute utili per lo sviluppo del prodotto.
Come gestore voglio:
poter visualizzare le i dati relativi all’occupante di una gabbia
voglio poter impostare i dati dell’occupante di una gabbia
poter aggiungere un cane a una gabbia
poter rimuovere un cane da una gabbia
poter visualizzare i consumi TOTALI del canile
opzionalmente poter visualizzare l’umidità e la temperatura ambientale
poter impostare i dati relativi allo stato di salute di un cane
poter visualizzare i consumi di cibo relativi a un cane in un determinato lasso di tempo
poter visualizzare i consumi di acqua relativi a un cane in un determinato lasso di tempo
Come responsabile sanitario voglio:
opzionalmente poter visualizzare i battiti di un cane
opzionalmente ricevere una notifica in caso di rilevazione di anomalie nei battiti o nella di un cane
opzionalmente poter visualizzare la temperatura corporea di un cane
opzionalmente ricevere una notifica in caso di rilevazione di anomalie nella temperatura corporea di un cane
opzionalmente poter impostare gli intervalli di temperatura e battiti fuori dai quali vi è un’anomalia
poter impostare gli intervalli delle quantità di cibo e acqua assunti, fuori dai quali vi è un’anomalia
ricevere una notifica in caso di anomalie nella quantità di acqua assunta da un cane
ricevere una notifica in caso di anomalie nella quantità di cibo assunto da un cane
poter impostare i dati relativi allo stato di salute di un cane
poter impostare la quantità di cibo da erogare a un cane
poter visualizzare i consumi di cibo relativi a un cane in un determinato lasso di tempo
poter visualizzare i consumi di acqua relativi a un cane in un determinato lasso di tempo
Come addetto ai rifornimenti voglio:
che la distribuzione di cibo agli animali sia automatizzata
che la distribuzione di acqua agli animali sia automatizzata
essere notificato se in una gabbia sta per esaurirsi il cibo
ricevere una notifica in caso di malfunzionamento al sistema
poter impostare la quantità di cibo da erogare a tutti i cani di una determinata taglia
poter impostare la quantità di cibo da erogare a un cane
poter visualizzare i consumi di cibo relativi a un cane in un determinato lasso di tempo
poter visualizzare i consumi di acqua relativi a un cane in un determinato lasso di tempo
Come addetto alla sorveglianza voglio:
poter visualizzare le immagini acquisite dalla videocamera di sorveglianza
notificato in caso di uscita non autorizzata di un cane
opzionalmente essere notificato in caso di rilevazione di suoni forti o anomali
opzionalmente poter visualizzare l’umidità e la temperatura ambientale
Di seguito viene riportato lo schema, sotto-forma di diagramma di Venn, esplicativo delle intersezioni tra le User-Stories e le figure dell’organigramma.
Si elencano i requisiti funzionali per ognuno dei seguenti macro-componenti:
Applicativo web
Opzionale collare
Strumentazione gabbia
Strumentazione videosorveglianza
L’applicativo web deve consentire ad ogni utente di accedere con una serie di credenziali, e dividere le operazioni consentite in base ai permessi concessi. Il sito è suddiviso in tre pagine principali:
pagina di login La pagina iniziale a cui ogni utente deve far riferimento per effettuare l’accesso. Sostanzialmente contiene solo gli elementi necessari per effettuare il login, non è prevista una funzione di registrazione autonoma.
home gestore Il gestore ha accesso alla pagina di amministrazione, dov’è possibile:
registrare un nuovo utente
eliminare un utente
visualizzare le statistiche del canile
home addetto rifornimenti La schermata deve consentire di:
visualizzare le eventuali notifiche
visualizzare i consumi di un cane
impostare la quantità di cibo adeguata per taglia di cane
home addetto sorveglianza La home del sorvegliante deve fornire:
un accesso in diretta alle videocamere disponibili
deve essere possibile aggiungere o rimuovere una videocamera
visualizzare le notifiche se presenti
home altri addetti In un futuro sviluppo del prodotto è certamente contemplata l’aggiunta di altre mansioni o addetti.
responsabile sanitario La pagina deve consentire di:
visualizzare lo stato di salute di un cane
visualizzare i consumi di un cane
impostare la quantità di cibo per un cane degente o in terapia
aggiornare lo stato di salute di un cane
Nonostante un addetto possa ricoprire più ruoli, è stato scelto di modellare separatamente ogni mansione, questo consente: un maggiore controllo, rende più chiara la struttura e aiuta il lettore nella comprensione. Inoltre l’applicativo consentirà ad un utente di detenere uno o più ruoli, rendendo più agevole l’utilizzo.
Il collare smart deve costantemente inviare aggiornamenti sui parametri vitali dell’animale quali:
La frequenza cardiaca
La temperatura dell’animale
La gabbia smart deve:
monitorare il consumo di cibo e acqua del cane inviando aggiornamenti costanti
rifornire la ciotola di acqua quando troppo bassa
rifornire la ciotola di cibo con la quantità desiderata quando mancante
notificare la mancanza di cibo nel serbatoio
La strumentazione deve fornire uno streaming video e audio costante nel tempo. La bidirezionalità è opzionale.
Il primo vicolo individuato è quello economico. Il costo del servizio, essendo l’attività non a scopo di lucro e mantenuta grazie all’azione dei volontari, deve essere minimo. Questo è comprensivo dell’istallazione, dei materiali e dei costi di servizio. Un secondo vincolo rappresenta la sicurezza, l’eventuale introduzione di strumentazione all’interno del canile non deve rappresentare in alcun modo un pericolo per la salute dell’animale.
Il sistema dovrà rispettare alcuni requisiti non funzionali che ne determineranno la qualità:
Reattività:
l’utente non deve percepire ritardi nell’ordine dei secondi tra l’invio di un comando e l’esecuzione dello stesso all’interno della piattaforma.
le notifiche standard del sistema devono essere mostrate ai relativi utenti con un ritardo complessivo massimo non superiore al minuto.
le notifiche urgenti del sistema, ossia quelle relative a malfunzionamenti gravi o alla salute dell’animale, devono essere mostrate ai relativi utenti con un ritardo complessivo massimo non superiore ai dieci secondi.
Scalabilità: L’applicativo deve necessariamente consentire di aumentare o diminuire il numero di animali gestiti. Ciò deve avvenire senza una sensibile ripercussione sulle prestazioni del sistema e un disagio minimo a livello pratico. Per prevenire, inoltre, che la presenza di una connessione cablata limiti la scalabilità del sistema, è desiderabile che non ci siano altri collegamenti al di fuori dell’alimentazione già presente.
Fault tolerance: la gestione degli errori deve essere adeguatamente implementata affinché le interruzioni involontarie non danneggino innanzitutto la salute degli animali. Eventuali malfunzionamenti di apparecchiature o sensoristica all’interno del canile non devono pregiudicare il funzionamento complessivo dell’applicativo, ma al massimo della singola unità logica.
Precisione:
Bilancia lo scostamento massimo tra più misure deve essere inferiore o uguale a 10 grammi.
Temperatura lo scostamento massimo tra più misure deve essere inferiore o uguale a 2 gradi.
Umidità lo scostamento massimo tra più misure deve essere inferiore o uguale a 5%.
Livello acqua lo scostamento massimo tra più misure deve essere inferiore o uguale a 1 centimetro.
Frequenza cardiaca lo scarto tra misure sulla stessa frequenza deve essere al massimo 10 battiti.
Risoluzione:
Bilancia il range di misura, partendo da vuota, deve riuscire a comprendere almeno un Kg.
Temperatura il range deve variare tra 0 e 50 gradi.
Umidità il range di umidità deve essere incluso tra 20-80%.
Livello acqua Il range deve variare almeno di tre cm.
Videocamera: necessaria almeno una risoluzione di 420p, non è richiesta la visione notturna.
Frequenza cardiaca la misurazione deve essere in grado di rilevare una frequenza che oscilla tra i 60 e i 160 battiti al minuto.
Microfono deve essere in grado di determinare suoni ad elevata intensità compresi tra 50 e 130 dB.
Accuratezza:
Bilancia lo scostamento massimo dal valore reale deve essere inferiore o uguale a 10 grammi.
Temperatura Lo scostamento dalla temperatura effettiva deve essere minore di 2 gradi.
Umidità Si accetta un massimo di 5% accuratezza.
Livello acqua l’accuratezza minima deve essere di 2cm.
Frequenza cardiaca l’errore non deve superare i cinque battiti al minuto.
Si definiscono i constraint a livello di implementazione che sarà necessario rispettare nella realizzazione del progetto.
Il software dovrà essere realizzato utilizzando almeno in parte le tecnologie studiate durante il corso di Smart-City. Dovranno inoltre essere necessariamente applicati i principi e i paradigmi assimilati durante lo stesso. Lo scopo infatti è quello di sviluppare software di valore sociale e importanza strategica per le amministrazioni e l’economia locale. L’applicazione software dovrà essere infatti d’ausilio alla realizzazione di servizi innovativi in contesti di città digitali. E’ necessario al raggiungimento di tale scopo, l’utilizzo di tecnologie di sensing e sistemi embedded per l’interfacciamento con il mondo fisico. Il focus preferibilmente sarà sulla programmazione di sistemi studiati, quali Raspberry PI e microcontrollori. A questi dovranno essere interfacciati sensori e attuatori IoT, tra i quali ve ne devono essere alcuni di complessità non banale. L’utilizzo dei protocolli di comunicazione dovrà essere adeguato all’uso che ne verrà fatto (MQTT). La metodologia di progettazione inoltre dovrà favorire lo sviluppo di applicativi mobili, in grado di essere usati in contesti e con dispositivi differenti. Altre tecnologie preferibilmente utilizzabili, data la diffusione oramai pervasiva, sono Cloud Computing e Fog Computing, eventualmente con piattaforme studiate come Amazon Web Services. Per la parte interfaccia utente verranno sviluppate Dashboard ad-hoc per la visualizzazione delle informazioni ricavate dai dati trasmessi dai sensori. Infine verrà possibilmente anche inclusa una parte di visione artificiale tramite l’utilizzo di videocamere per lo streaming, eventualmente con una minima elaborazione per la sorveglianza.
All’interno del Knowledge crunching, domande più significative possibili sono state fatte agli esperti per capire i concetti fondamentali del dominio. Non tutte le parti però hanno egual importanza, in questo capitolo si cerca di individuare il core domain. Infatti, è necessario ridurre la complessità focalizzandosi solo sulle porzioni più importanti del modello, ciò aiuta a diminuire la difficoltà globale. Inoltre, bisogna specificare che il core domain non va confuso con l’organizzazione dell’azienda, ciò che è importante nella gerarchia o nel modello di business non coincide necessariamente con la parte più importante della richiesta. Nel nostro caso, il software va a risolvere un problema mirato, che non collima con l’intero ambito aziendale. Si notino infatti altri problemi emersi, quali l’accalappiamento e la burocrazia, che non concernono il nostro core-domain. Ulteriore attenzione è stata prestata al fatto che il core possa cambiare con il tempo, durante i confronti periodici con il cliente le sue esigenze possono cambiare, o meglio, venir chiarite più adeguatamente agli sviluppatori. Per minimizzare questo rischio si è fatto largo uso dello Sketching. Essendo il modello visuale utile a tutti, sia nel farsi capire che nel comprendere gli altri, in questo capitolo si riportano gli schemi usati.
Sono stati identificati tre domain, dove:
Sanità è il core domain. Contiene tutta la logica e le funzioni utili a determinare lo stato di salute dell’animale, partendo dai soli dati vitali.
Cura quotidiana è il support domain. Tramite la cura e le informazioni ricavate dalle azioni quotidiane dell’animale supporta il core domain nell’analisi di anomalie quali patologie, problemi di salute o comportamentali.
Sorveglianza è il sub domain relativo alla gestione e monitoraggio video del canile.
Una volta individuato il core-domain, sono emersi anche i domini secondari e i sottodomini. Sono stati definiti i seguenti subdomain:
Cura quotidiana: racchiude tutti gli aspetti che riguardano la quotidiana gestione dei cani. Rientrano in questo sotto-dominio il nutrimento e ciò che è strettamente collegato ad esso, ovvero la distribuzione del cibo, il consumo e la rilevazione di anomalie nell’alimentazione.
Sanità: rappresenta tutto ciò che è collegato al monitoraggio della salute del cane e alla rilevazione di anomalie che necessitano di attenzione medica.
Sorveglianza: riguarda il monitoraggio del canile mediante videocamera che è utile non solo per aspetti legati alla sicurezza ma anche per la stretta sorveglianza delle condizioni dei cani prossimi al parto o che hanno una situazione sanitaria che richiede una vigilanza continua anche nelle ore notturne.
Particolare attenzione è stata fatta a creare i sottodomini per il replacement piuttosto per il riuso.
Un altro importante step è il riconoscimento dei Bounded Contexts. In questa fase il focus è incentrato sul confine tra i moduli individuati in precedenza. Lo scopo è di trovare delle porzioni isolate con confini ben definiti. L’isolamento deve essere non di funzionalità tecnica ma di dominio. Questo paradigma è riconoscibile anche nel trend attuale dei micro-servizi, che, tuttavia sono costruiti attorno ai confini di deployment, non del modello. Ciò assicura l’integrità e la facile scalabilità. Il modello del dominio infatti cresce in complessità nel tempo. Questo accade soprattutto nella filosofia Agile che abbraccia il cambiamento. Una continua revisione e raffinamento vengono portati avanti durante tutto l’arco della durata del progetto, per soddisfare differenti business use cases e nuove richieste del cliente. Multipli team che lavorano allo stesso modello, inoltre, possono intralciarsi a vicenda e creare incomprensioni divergenti, a causa delle ambiguità nel linguaggio. Queste sono le sfide avendo un single model, ed è per questo che è meglio avere più contexts/subdomains. Nello schema sottostante i Bounded Contexts sono stati collocati, assieme ai SubDomains che li contengono, in base alla loro complessità e alla relativa Business Differentiation.
Avendo individuato nel sistema ci sono più Bounded Context, è importante riconoscere come dialogano. Creare una mappa concettuale [Fig. 6.1] per definire i rapporti tra i Bounded Contexts è essenziale per il mantenimento del codice e dei vincoli di isolamento. La mappa, durante lo sviluppo, rappresenta lo stato presente e evolve in sincrono con il sistema stesso, più che rappresentare lo stato ideale futuro. Questo permette di chiarire anche agli eventuali team responsabili dei Bounded Context, i punti di contatto.
Il livello scelto è molto più vicino al business, al Domain Problem, che al software. Nonostante ciò non è stata tralasciata la visione della parte implementativa, che comunque dovrà rispecchiare questo modello. Si può notare ciò dalla doppia suddivisione dello schema, sia dal punto di vista dei Sub-Domains, indicati in giallo, che dal punto di vista delle macro-componenti del sistema, indicate a sinistra.
Nella parte fisica, in tutti e tre i sub-domains, troviamo dei contesti che fungono da "supplier" verso altri. Le relazioni tra Bounded Contexts infatti sono state definite seguendo il più possibile i pattern del DDD. In questo caso si nota una Upstream/Downstream Relationship: è stato definito chi è il context customer o chi supplier in base al contesto che fornisce il flusso di informazioni e quello che le riceve. La distribuzione automatizzata è composta da due sottocontesti, uno relativo al cibo erogato e misurato e l’altro all’acqua. Nei primi due casi i dati, essendo i dati trasmessi di grandezza esigua e di facile memorizzazione, vengono trasmessi ai contesti che si occupano della rilevazione e archiviazione degli stessi. Questi due Bounded Context condividono necessariamente uno Shared Kernel, i dati rilevati appartengono infatti allo stesso concetto del modello, ossia all’animale. Essendo la distribuzione del cibo personalizzata in base alla classe dell’animale, un ulteriore contesto relativo alla gestione dei consumi è stato necessario, poichè attivamente definisce quali quantità erogare all’animale. Il flusso video, d’altra parte, data la mole di dati ha come customer direttamente la rilevazione delle anomalie della sicurezza. Questo Bounded Context, assieme agli affini che rilevano anomalie sanitarie e nei consumi, dopo aver preso in ingresso i dati, avvisano delle irregolarità il sistema delle notifiche. Questo passaggio è stato effettuato per mezzo di un "Open Host - Service" che espone le funzionalità del sistema notifiche.
Come specificato, è emersa la necessità di integrare dal punto di vista logico i due Bouned Context relativi ai consumi, nonostante si sia cercato di mantenerli il più possibile autonomi. L’integrazione infatti non deve avvenire mai prima a livello di codice, ma deve dipendere da un’integrazione a livello concettuale.
Dopo un intenso periodo di Domain Driven Design, si è passati si è proceduto alla fase di Design Architetturale, agevolata di molto da quest’ultimo. Infatti da un confronto mirato con il cliente l’architettura ottimale è emersa quasi naturalmente. Lasciando spazio alla definizione dei dettagli più tecnici che riportiamo in seguito.
L’architettura generale del sistema è stata concepita in due macro aree: la parte IoT [Fig. 7.1. in alto] e la parte cloud [Fig. 7.1. in basso]. Le due sfruttano la connessione internet per connettersi, lo scambio di messaggi avviene attraverso il protocollo MQTT, mentre il flusso video viene passato per mezzo del protocollo RTSP.
Il sistema IoT risiede su una rete privata e comunica all’esterno per mezzo di questi due protocolli. Le parti salienti sono la sensoristica che fornisce le informaioni sull’ambiente circostante al microcontrollore, il quale le elabora e utilizza gli attuatori in base alle informazioni ricavate sia dai sensori che dal cloud.
La parte cloud si interfaccia per mezzo dell’applicativo IOT Core ai sensori, i messaggi MQTT vengono elaborati da AWS Lambda e, qualora opportuno, immagazzinati come dati nel database. L’applicativo web, hostato su AWS Amplify, si interfaccia anch’esso con AWS Lambda, passando per Amazon API Gateway. Questo sia per recuperare i dati dal database DynamoDB e mostrare le statistiche, che per diramare il cambio dei settaggi fino ai microcontrollori. Infine, l’applicativo si occupa anche di mostrare il flusso video proveniente dalla board per le telecamere di sorveglianza.
Tra i servizi messi a disposizione da AWS vi è anche Amazon Cognito che permette di gestire gli utenti. E’ stato valutato Amazon Cognito ma è stato scartato perché gli utenti sono troppo pochi.
Come protocolli di comunicazione sono stati considerati i principali protocolli per la comunicazione IoT. Tra quelli di livello applicazione:
AMQP (Advanced Message Queuing Protocol), protocollo che consente a un’ampia gamma di sistemi e applicazioni di interagire, creando messaggistica standardizzata su scala industriale.
CoAP (Constrained Application Protocol), protocollo adatto alle limitazioni di larghezza di banda e di rete, per dispositivi con capacità limitata, ma prevalentemente per la connessione nelle comunicazioni da computer a computer.
DDS (Data Distribution Service), protocollo per comunicazioni peer-to-peer. In generale semplifica la distribuzione, incrementa l’affidabilità e riduce la complessità.
MQTT (Message Queue Telemetry Transport), protocollo di messaggistica progettato per comunicazioni IoT. MQTT usa un criterio di tipo publish-subscribe ed è ideale per dispositivi di dimensioni ridotte che richiedono efficienza a livello di larghezza di banda e uso della batteria.
La scelta è ricaduta su MQTT per la sua leggerezza ed efficienza, per la possibilità di instaurare comunicazioni bidirezionali tra molti dispositivi. Il design inoltre è molto semplificato dalla possibilità di creare topic a cui iscriversi o in cui pubblicare i messaggi.
Per lo streaming video sono stati considerate due opzioni: streaming attraverso RTSP e attraverso HTTP con un server e HTML5. RTSP è di sicuro la scelta più popolare perché adottato come protocollo dalle IP-cam e telecamere di sorveglianza. Nonostante ciò non è compatibile con HTTP e, non potendo fare lo stream su HTTP direttamente, non è visualizzabile nativamente dai browser. Questo protocollo è infatti usato internamente alle reti private. Volendo esporre il flusso video anche al di fuori della rete privata del committente la scelta è ricaduta sulla seconda opzione. Inoltre, con questa tecnologia alla videosorveglianza si ha accesso con qualsiasi browser, da computer o da smartphone.
Le piattaforme di sviluppo per l’IoT tenute presente sono state molteplici, da board con potenza computazionale più elevata, come Raspberry Pi, a scendere fino a ESP e le varianti Arduino.
Le board Arduino sono state scartate quasi subito, per la poca potenza computazionale e la necessità di moduli aggiuntivi per le connessioni. La board RaspBerry Pi è stata scelta per task più computazionalmente onerosi, legati alla gestione ambientale, quali la video sorveglianza e l’analisi immagini. Questa scelta non può essere invece adottata per la gestione delle gabbie. Le principali motivazioni risiedono nel fatto che il numero è variabile e il costo supererebbe molto superiore al budget. La scelta in questo caso è ricaduta sull’ESP, non solo per il forte fattore cost-competitive, e per il supporto a Bluetooth e WiFi integrati, ma anche per il supporto della community e l’ottima potenza computazionale. Inoltre, rinunciando all’analisi immagini e alla qualità video a favore dei costi, il cliente potrà anche scegliere di sostituire la board Raspberry con un più economico ESP32-CAM. Con l’ESP8266 le prime settimane il lavoro di indagine preliminare ha rilevato qualche che risultava troppo limitato per utilizzare MicroPython. Tra ESP8266 e ESP32 è stato preferito quest’ultimo, anche per lasciare della capacità di calcolo per eventuali future espansioni e richieste del committente.
Per quanto riguarda l’implementazione del codice nel microcontrollore, sono state presi in considerazione quattro scelte relative ai framework di sviluppo e ai linguaggi da adottare:
C++ è il linguaggio attualmente più diffuso nell’ambito.
Node-RED è un tool di programmazione flow-based basato su browser, sviluppato su NodeJs e programmabile in JavaScript.
MicroPython è un porting più leggero del compilatore Python3, eseguibile direttamente su microcontrollori. Include le principali librerie di Python e moduli aggiuntivi per l’accesso all’hardware di basso livello.
Espruino è un interprete JavaScript open-source per microcontrollori. E’ stato progettato per unità con poca RAM.
Sicuramente il più performante e con più librerie è C, ma risulta anche difficilmente testabile e pone challange non indifferenti per la configurazione dei sensori e per lo sviluppo di programmi molto complessi. Node-RED, basato su Node.js, ha il pieno vantaggio del suo modello non bloccante e event-driven. MicroPython d’altra parte offre un modello ad oggetti, testabile, sia semplice che elastico, con una buona base di librerie. Infine, Espruino, interprete JavaScript anch’esso, di facile utilizzo e dall’interfaccia semplificata. I fattori chiave che il team ha preso in considerazione per la scelta sono stati:
la potenza espressiva rapportata alla chiarezza del linguaggio.
la testabilità del codice
il numero di librerie e la futura possibilità di estensione del progetto.
Alla luce delle considerazioni fatte, si è scelto MicroPython per lo sviluppo, il testing e l’automatizzazione nei microcontrollori. Questo permette di allinearsi con l’utilizzo di Python per il Raspberry.
L’utilizzo del pattern client-server, nella videosorveglianza, ha permesso di esporre il flusso video su un server apposito e di accederci da qualunque dispositivo dotato di connessione.
L’utilizzo del pattern publish-subscribe, è stata una scelta chiave per la modularità del sistema. La divisione in topic ha portato un maggiore ordine e una modellazione più vicina al vero dominio.
E’ stato fatto uso dell’architettura master-slave per la gestione dei microcontrollori. Questa permette di espanderne il numero a piacimento, mandando istruzioni specifiche o generali per controllarne il comportamento.
Nei sistemi embedded è stato adottato lo scheduling cooperativo per evitare tante pitfall dello scheduling preemptive, quali l’interruzione di un processo di misura Real Time, quale quello della chiusura della valvola dell’acqua o la misura del battito cardiaco.
Per definire il comportamento dei microcontrollori in maniera chiara è stata usata la modellazione con macchine a stati. Questa ha permesso di ridurre la probabilità di bug nel software e di isolare i componenti permettendo una futura espansione del comportamento.
Per l’automatizzazione e la gestione di cibo e acqua si è partiti dalle user-stories e dal modello del dominio costruito per sviluppare l’applicativo desiderato. Osservando i requisiti è stato progettato il modello fisico e l’interazione dell’animale con esso. Si riporta di seguito il design del prototipo fisico, con i sensori e attuatori in giallo e la spiegazione del suo funzionamento [Fig. 8.1]. Il design permette la modularità tra cibo e acqua, scegliendo all’occorrenza solo uno dei due o entrambi.
Per far fronte alla misurazione dei consumi, è stato innanzitutto necessario scegliere un sensore per ricavarne il livello del liquido [Fig. 8.1]. Il sensore deve ritornare un valore proporzionale alla percentuale di liquido rimanente. I consumi dell’animale a questo punto verranno inviati in cloud.
Per quanto riguarda l’esigenza di riempimento dell’acqua, inizialmente la scelta era ricaduta su due sensori che rivelassero quando il liquido è al minimo o al massimo. In seguito questo design è stato semplificato usando direttamente il sensore introdotto per l’invio dei dati relativi al livello del liquido. Successivamente è necessario che il sensore si interfacci con un’elettrovalvola [Fig. 8.1] per poter riempire la ciotola aprendo o chiudendo il flusso d’acqua all’occorrenza.
Il sistema deve essere modulare per design: qualora non si disponga del sistema idrico per poter rifornire la ciotola, devono comunque essere mandati i consumi con l’aggiunta di una notifica se se l’acqua sta per terminare.
Il comportamento è stato modellato come una macchina a stati [Fig. 8.2]. Ciò ha permesso di chiarire meglio le azioni del sistema a fronte di un avvenimento, il suo stato corrente e il suo comportamento generale.
Inizialmente il comportamento prevede il controllo del consumo di acqua, ciclicamente e a intervalli regolari viene fatta una misurazione [Fig. 8.2 "check water consumption"].
E’ stata stabilita una soglia minima di diminuzione del liquido per non incorrere in falsi positivi, dove le naturali oscillazioni del sensore potrebbero inviare consumi inesistenti. Talora questa soglia venisse superata, la percentuale di liquido consumata viene inviata in cloud, memorizzando l’ultima percentuale inviata [Fig. 8.2 "send water consumption"]. Il sistema continua quindi a monitorare di nuovo il livello per ulteriori consumi.
Inevitabilmente il liquido nella ciotola andrà a finire, questo evento innescherà una transizione, dipendente dalla presenza o meno dell’elettrovalvola. Se il sistema non prevede un rifornimento idrico il sistema passerà allo stato di notifica di acqua esaurita [Fig. 8.2 "finished water notify"]. In questo stato una notifica verrà mandata all’addetto ai rifornimenti. Quando la ciotola verrà ricaricata il sistema passerà in automatico nuovamente allo stato per il controllo dei consumi. Qualora il sistema fosse dotato di elettrovalvola, la transizione innescata la aprirebbe, passando allo stato di riempimento [Fig. 8.2 "fill water bowl"].
In questo stato il livello viene controllato continuamente, per non incorrere in allagamenti indesiderati. Un meccanismo di sicurezza temporizzato infatti controlla se un determinato periodo di tempo è passato senza che il sistema sia riuscito a riempire la ciotola con la valvola aperta. In caso affermativo il sistema va in blocco, chiudendo la valvola e passando allo stato di notifica di errore [Fig. 8.2 "water system error notify"]. Se il livello dell’acqua raggiunge il parametro desiderato invece lo stato torna a essere quello iniziale di osservazione.
Per far fronte all’esigenza di monitorare i consumi di cibo dell’animale è stata introdotto un sensore di peso [Fig. 8.1]. Il sensore deve ritornare un valore proporzionale alla quantità di cibo presente nella ciotola. I consumi dell’animale verranno inviati in cloud.
Riguardo all’esigenza di rifornire il cibo, la bilancia si deve interfacciare con un attuatore che si occuperà della distribuzione del materiale [Fig. 8.1 attuatore di sinistra]. Il design meccanico scelto è stato quello di un nastro trasportatore per la semplicità di realizzazione e l’efficacia. Altri design presi in esame comprendevano una botola che si aprisse e chiudesse, ma presentava problemi di forza per trattenere il cibo in caduta, e la vite di Archimede, ma presentava problemi nell’incastrarsi nel meccanismo dell’eventuale cibo in pezzi solidi. Il design con il nastro sfrutta la gravità per far cadere i pezzi su di esso e, all’attivazione, trascinarli con se permettendo ad altri di cadere. La bilancia rileverà l’incremento e fermerà il sistema alla quantità desiderata.
Per evitare che l’animale mangi il cibo durante la distribuzione, falsandone le misure, è stato introdotto un altro attuatore bidirezionale [Fig. 8.1] per estendere o ritrarre uno sportellino che ne previene l’accesso. Per determinare quando lo sportellino arriva al massimo o al minimo della sua estensione sono stati introdotti due pulsanti [Fig. 8.1] che segnalano quando fermare il movimento.
Infine per segnalare quando il cibo di scorta sta anch’esso per finire sono stati introdotti un laser e un sensore luminoso [Fig. 8.1] nella riserva di cibo. Se il cibo è presente il fascio laser verrà interrotto e il sensore non rileverà alcuna luce. Quando il cibo durante l’erogazione scende sotto una soglia critica, il fascio raggiunge il dispositivo di sensing e una notifica verrà inviata all’addetto.
Anche qui il sistema deve essere modulare per design: qualora non ci si voglia avvalere del sistema per rifornire la ciotola, i consumi devono comunque essere mandati in cloud con l’aggiunta di una notifica se il cibo nella ciotola sta per terminare.
Anche in questo caso il comportamento, data la sua complessità, è stato modellato come una macchina a stati [Fig. 8.3]. Il comportamento è simile alla macchina a stati mostrata in precedenza, essendo l’attuatore per il rifornimento del cibo paragonabile all’elettrovalvola e la bilancia paragonabile al sensore di livello dell’acqua.
Inizialmente il comportamento prevede il controllo dei consumi in maniera ciclica tramite la bilancia [Fig. 8.3 "check food consumption"]. Anche in questo caso talora la soglia minima venisse superata, la quantità consumata viene inviata in cloud [Fig. 8.3 "send food consumption"]. Il sistema continua quindi a monitorare di nuovo il peso per ulteriori consumi.
Se è stato scelto di non usufruire della parte di rifornimento cibo, il sistema quando questo si verrà ad esaurire, passerà allo stato di notifica [Fig. 8.3 "food finished notify"]. Similmente al comportamento del sistema per l’acqua , quando la ciotola verrà ricaricata il sistema passerà in automatico nuovamente allo stato per il controllo dei consumi. In caso fosse presente il sistema di ricarica cibo completo, l’attuatore per chiudere l’accesso al cibo si attiverà, passando allo stato di chiusura [Fig. 8.3 "blocking food access"]. Una volta completata la chiusura il nastro per l’erogazione del cibo verrà attivato e il sistema passerà allo stato di erogazione [Fig. 8.3 "fill food bowl"]. Se non fosse presente lo sportellino per l’accesso al cibo, dallo stato iniziale si passerà direttamente a quest’ultimo attivando il nastro, senza il passaggio intermedio.
In questo stato il livello viene controllato continuamente, per un dosaggio corretto. Assieme al peso del cibo erogato, viene controllata anche la presenza del fascio laser. Qualora venisse rilevato significa che il cibo di scorta sta per finire e una notifica viene inviata all’addetto. Anche in questo caso è presente un meccanismo di sicurezza temporizzato che, dopo un periodo di tempo massimo, blocca l’erogazione e passa allo stato di notifica errore di sistema [Fig. 8.3 "food system error notify"]
In caso il cibo invece raggiunga la quantità desiderata, il sistema tornerà allo stato iniziale, garantendo eventualmente l’accesso al cibo tramite lo stato di apertura [Fig. 8.3 "allowing food access"]
Per il monitoraggio dei parametri vitali il design fisico è stato semplificato di molto, richiedendo due sensori e un microcontrollore. Il design del prototipo fisico, con i sensori in giallo e la spiegazione del suo funzionamento [Fig. 8.4] sono riportati di seguito.
Il primo device di sensing necessario è quello di temperatura, che periodicamente deve inviare i valori letti al cloud. Eventualmente, se i valori sono fuori norma, deve segnalarlo inviando una notifica immediatamente. Il secondo sensore è necessariamente quello dei battiti. Anch’esso deve inviare a intervalli regolari i battiti per minuto in cloud, affinché vengano registrati. Opzionalmente sarà presente un LED per visualizzare i battiti in real-time. In caso di anomalie tali da portare i valori oltre il minimo o il massimo, una notifica deve essere mandata tempestivamente. La macchina a stati si compone semplicemente di due stati divisi che ciclano su loro stessi, inviando periodicamente i valori letti ed eventualmente le notifiche per le anomalie.
Per la videosorveglianza il design ha richiesto necessariamente, come descritto in precedenza, una board più potente che sostenesse l’elaborazione delle immagini. Di seguito il design del prototipo fisico, con i sensori in giallo e la spiegazione del suo funzionamento [Fig. 8.5].
Per quanto riguarda i sensori, ovviamente è necessaria una videocamera, che catturi l’ambiente circostante e mandi il flusso video alla board per un analisi. Oltre alla videocamera, opzionalmente, sono stati modellati un sensore di temperatura e umidità, per salvare in cloud i parametri ambientali del canile, e un device di sensing sonoro, per rilevare suoni forti continuativi. La board deve anche fornire opzionalmente lo streaming video della telecamera, facendo da server, per l’addetto alla sorveglianza. Il flusso dei dati è chiaramente unidirezionale, dai sensori e dalla webcam verso l’esterno, come da architettura generale [Fig. 7.1].
Per immagazzinare i dati necessari all’applicazione si è deciso di utilizzare Dynamo DB. Il database principale doveva immagazzinare:
I profili dei cani presenti all’interno del canile;
Gli orari e le quantità di cibo da somministrare a seconda del cane;
I valori rilevati dai dispositivi di sensing, che comprendono:
Temperatura corporea;
Frequenza cardiaca;
Consumo di acqua;
Consumo di cibo;
Temperatura ambientale del canile;
Umidità rilevata all’interno del canile;
I profili degli utenti.
La progettazione del database è stata portata a termine seguendo diversi passaggi:
Definizione di uno schema ER da utilizzare come base di partenza;
Individuazione degli accessi mediante la definizione delle query principali;
Definizione dei pattern di Primary Key e Sort Key;
Introduzione di indici e campi aggiuntivi;
Nonostante non si tratti di un database relazionale, abbozzare uno schema Entity Relationship può essere utile per avere una buona visione di partenza di come devono essere gestiti i dati.
Il primo schema ad essere stato elaborato è stato quello che racchiude tutto ciò che ha a che fare con i dati di un cane, ovvero il profilo del cane, i dettagli della sua relativa distribuzione del cibo e le rilevazioni di cibo, acqua, temperatura e battiti che lo riguardano.
Cane: il profilo del cane è modellato mediante la tabella Dog che, oltre alle consuete informazioni presenta anche le soglie, impostate dal veterinario, al di fuori delle quali si rileva un’anomalia.
Programma dei pasti: l’entità Food_Schedule immagazzina gli orari e le quantità dei pasti. Il criterio secondo cui, nel caso standard, vengono decisi questi dati è la taglia, tuttavia si è deciso di collegare l’entità direttamente al cane poiché ciò permette di effettuare una programmazione più a grana fine. In questo modo, infatti, si può consentire ad un veterinario di effettuare modifiche sul regime alimentare di un unico cane, senza influenzare gli altri cani della stessa taglia.
Rilevazioni: nello schema in figura è già stata collassata la gerarchia delle rilevazioni sopra elencate, concentrandole nell’entità Dog_log che ne distingue la natura mediante il campo type.
In fase di progettazione si voleva che il database gestisse anche gli utenti che agiscono sul sito, in maniera tale che ne fossero definiti i ruoli in base ai quali avrebbero avuto diversi permessi e una diversa visualizzazione dei dati sul sito web. Questo ER si distacca da quello relativo ai cani e si presenta in questo modo:
Anche per quanto riguarda le rilevazioni ambientali ci si trova di fronte a un’area separata dalle precedenti, perché non ha alcun tipo di correlazione né con i cani, né con gli utenti. Esse sono modellate con una tabella di nome Env_Logs che ne immagazzina il timestamp, il type, che serve a distinguere le rilevazioni di temperatura e quelle di umidità e il value che, nel caso della temperatura è espresso in gradi mentre nel caso dell’umidità è espresso in percentuale.
Una volta ottenuta una bozza dello schema Entity Relationship si è passati a definire gli accessi in base alle query che sarà necessario chiamare per interrogare il database. Definire gli accessi si rivela essere di vitale importanza quando si lavora con un database come DynamoDB perché permette di impostare le tabelle in modo da rendere più facile l’accesso ai dati più richiesti. Per permettere ciò si è portati anche a introdurre delle ridondanze e a sacrificare l’integrità referenziale prediligendo i benefici sulle performance. Di seguito le interrogazioni suddivise per frequenza
Frequenza molto elevata (ogni pochi minuti)
inserimento di una rilevazione riguardante consumi, parametri vitali del cane, valori ambientali
Frequenza elevata (poche volte all’ora)
visualizzazione dei cani presenti
visualizzazione dei consumi di un cane
visualizzazione dell’ultima rilevazione di temperatura e battiti di un cane
Frequenza media (una o poche volte al giorno)
visualizzazione storico delle rilevazioni di un cane
visualizzazione dei consumi di un cane
inserimento di un nuovo cane
interrogazione sull’orario e la quantità dei pasti
a fine giornata, comparazione dei consumi totali di acqua e cibo odierni, per ciascun cane, con i rispettivi range giornalieri contenuti nel profilo dell’animale.
Frequenza bassa (meno di una volta a settimana)
impostazione delle soglie dei consumi di un cane oltre le quali vi è un’anomalia
impostazione delle soglie dei parametri vitali di un cane oltre le quali vi è un’anomalia
aggiornamento del programma dei pasti
aggiornamento dello stato di un cane
Dopo aver individuato le interrogazioni che verranno fatte sul database e le loro frequenze si è passati alla progettazione vera e propria dell’unica tabella del database. A differenza di un database relazionale, infatti, DynamoDB non permette di ricorrere alle join, se non con dei workaround la quale adozione è un chiaro sintomo del fatto che non si è scelta correttamente la tipologia di database da adottare. La tabella che è stata creata è strutturata con i seguenti campi:
PK: o Primary Key, è la chiave primaria e consiste in una stringa che determinerà la natura del record a cui appartiene.
SK: o Sort Key, è la chiave di ordinamento e consiste anch’essa in una stringa che segue uno specifico pattern e che assieme alla PK determinerà univocamente il record.
Altri campi: che sono dati dall’unione dei campi di tutte le entità che si è deciso di coinvolgere, con l’aggiunta di alcuni campi introdotti per fornire un’indicizzazione o per inserire delle ridondanze che facilitino l’accesso.
I pattern che sono stati definiti per PK e SK sono i seguenti:
Dalla tabella, oltre ai pattern per i valori delle chiavi è possibile anche intuire il modo in cui si è deciso di effettuare la trasposizione dallo schema relazionale. Si può notare infatti che:
Food_Schedule: si è deciso di mantenere la programmazione dei pasti separata dai dati del cane poiché mantenerla come struttura dati all’interno del profilo avrebbe reso meno immediata la modifica e il recupero degli orari e delle quantità che il sistema automatizzato deve erogare.
Dog_Log: la stessa decisione è stata presa per quanto riguarda i dati delle rilevazioni, poiché la query che permette l’inserimento di questi dati è quella che verrà chiamata con la massima frequenza ed era quindi importante facilitarne la fruizione.
User: una sorte diversa è spettata ai ruoli ricoperti dagli utenti. Si è deciso di modellare i ruoli come una set di stringhe all’interno del profilo dell’utente, poiché si tratterebbe di un campo che viene modificato raramente.
L’ultima fase è stata quella di individuare quali altre modifiche potevano essere apportate al risultato finale della tabella per favorire le interrogazioni. Si è deciso pertanto di:
aggiungere i campi last_temp e last_hb nel profilo del cane per permettere una più prestante interrogazione nel momento in cui, nella homepage del sito si vogliono visualizzare le ultime rilevazioni dei parametri vitali del cane. In assenza di questi due campi sarebbe stato necessario interrogare il database con un range di timestamp sensato per ottenere una fetta dello storico delle rilevazioni, ordinarle e restituire la più recente. Questo per la temperatura che per la frequenza cardiaca.
aggiungere un nuovo indice sul campo size per permettere di effettuare alcune query basandosi sulla taglia del cane.
La WebApp è stata suddivisa in due Macro aree:
Login: la schermata si occupa di fornire un accesso base all’utente, l’unica funzione esposta è la possibilità di effettuare il login, attualmente rappresenta un placeholder, dato che non contine alcuna logica né funzione utile, questo per concentrarsi maggiormente su aspetti più inerenti.
Home: fornisce tutte le funzioni principali dell’applicativo, la schermata è divisa in schede, ogni scheda è a sua volta divisa in più componenti, uno per la visualizzazione dei cani presenti e uno per le azioni specifiche da attuare su di esso, o in generale. L’unica scheda che contiene un solo
dove ogni scheda consente determinate operazioni:
Gestore: Consente di effettuare le principali azioni del sito, inoltre può anche effettuare le azioni seguenti.
Addetto alla salute: Può visualizzare i parametri vitali e lo stato di salute degli animali.
Addetto ai rifornimenti: Può visualizzare i dati di un cane, i suoi consumi e impostare l’orario e la quantità di cibo.
Addetto alla sorveglianza: Puù visualizzare lo streaming video.
Altro addetto: placeholder per funzioni future
L’esposizione delle funzioni del back-end, segue a braccetto la definizione delle query necessarie per interrogare e inserire nuovi dati all’interno di DynamoDB.
Le funzioni sono state divise per innesco, dove abbiamo:
Lambda ad innesco API REST: rappresentano la maggioranza delle funzioni, sono ulteriormente divise in base allo scopo di interrogazione(GET) o inserimento(POST)
Lambda ad innesco Crono: i consumi dei cani sono controllati a fine giornata per verificare che le soglie dei consumi siano nei parametri. l’innesco avviene tramite eventi CloudWatch
Lambda ad innesco MQTT: rappresentano i diretti inserimenti delle rilevazioni all’interno del database, sono in ascolto su un sul topic ESP/#, questo consente di ascoltare tutti i messaggi provenienti da i sotto topic.
Come spiegato nel capitolo Scelte tecnologiche cruciali, i microcontrollori sono stati programmati in MicroPython. Nella classe principale, condivisa e riutilizzabile tra tutti i microcontrollori, dopo la connessione a internet e al broker MQTT è stato creato uno scheduler. Questo si occupa di eseguire i task a lui assegnati, siano relativi al cibo, all’acqua, o ai parametri vitali. In questo modo è facilmente programmabile il comportamento di un microcontrollore con task modulari.
# array of tasks
print("Creating array of tasks")
tasks = [smart_collar_temperature_task.get_behaviour(), smart_collar_heartbeat_task.get_behaviour()] # array of coroutines
# create the scheduler and start tasks
print("--- Starting Scheduler ---")
scheduler = Scheduler()
scheduler.start(tasks)
Avendo adottato MicroPython è stato possibile usufruire del linguaggio ad oggetti per modellare attuatori e sensori come classi, con proprietà chiamabili all’occorrenza. Ogni classe è stata testata individualmente grazie ai test scritti appositamente per prevenire comportamenti indesiderati. Si può trovare il diagramma delle classi di ogni device con cui si interfaccia il microcontrollore in [Fig. 9.1].
In particolare, ogni device di sensing, è stato modellato ereditando dalla classe Sensor, che mette a disposizione una serie di metodi per poter calcolare la media pesata, la percentuale misurata nel range minimo e massimo e l’ultima misurazione. La media è pesata è calcolata esponenzialmente in base alle ultime misure, le quali hanno peso maggiore:
def measure(self):
"""measures 3 times, measure is the mean of them, updates global average, returns measure."""
sum_raw_measures = 0
for _ in range(3):
sum_raw_measures += self.raw_measure()
self.last_measure = sum_raw_measures / 3
# average calculated from last average, weighted and actual measure, weighted
self.average = self.last_measure * self.average_converging_speed + self.average * ( 1 - self.average_converging_speed)
return self.last_measure
L’implementazione del task relativo alla gestione del cibo da passare allo scheduler è stato implementato in una classe dedicata. Il comportamento che il task espone rispecchia la macchina a stati discussa nel design [Fig. 8.3]. Grazie alla possibilità di Python di avere funzioni higher-order, il loop principale esegue ciclicamente lo stato corrente:
async def get_behaviour(self):
"""async method called returns a coroutine"""
while True:
# executes the current state
await self.state()
Quando il task è creato, nel costruttore è possibile scegliere lo stato iniziale assegnando la funzione relativa allo stato corrente.
# state variable holds the current state, this is the initial state
self.state = self.check_food_consumption
All’interno di ogni stato vengono effettuate le operazioni necessarie e, qualora le condizioni si verifichino, le transizioni a un nuovo stato.
# check consumption
self.reduction_percentage = self.previous_sent_perc - self.scale.get_percentage()
print("\t\tReduction Percentage: {:.2f}".format(self.reduction_percentage))
if self.reduction_percentage >= PERCENTAGE_CONSUMPTION_THRESHOLD:
self.state = self.send_food_consumption
return
Particolarmente impegnativa è stata la modellazione della bilancia. Questa va tarata inizialmente affinché il peso della ciotola vuota non vada ad influire sul peso del cibo. Inoltre parecchie prove sono state effettuate per trovare il coefficiente di conversione tra i valori del sensore e il peso in grammi. Infine la gestione del motore bidirezionale per aprire e chiudere lo sportellino di accesso al cibo ha anch’esso richiesto parecchia cura, dovendo implementare una classe che si preoccupasse di invertire la polarità al motore attraverso un ponte-H e la logica di interruzione del movimento al momento giusto.
Il task relativo alla gestione della ciotola dell’acqua è stato implementato, similmente a quello del cibo, in una classe apposita, per poter essere passato allo scheduler. Essendo i task più di uno, a questo punto è sorto naturale implementare una classe task da cui tutti quelli descritti nel seguente capitolo erediteranno. La logica a stati del design è stata implementata rispecchiandolo a pieno. Ciò perché la precedente modellazione dei sensori ha agevolato di parecchio la scrittura del codice, rendendolo pulito e facilmente comprensibile.
# measure
self.waterSensor.measure()
print("\t\t\tWater Measure: {:.2f}".format(self.waterSensor.get_percentage()))
# check empty
if self.waterSensor.get_percentage() < self.min_water_lvl_perc:
print("\t\t\tWater LOW: {:.2f} < {:.2f}".format(self.waterSensor.get_percentage(), self.min_water_lvl_perc))
if self.valve_present:
print("\t\t\tOpening Valve")
self.valve.open()
self.state = self.fill_water_bowl
return
In questo caso il sensore dell’acqua è stato ampliato con delle funzioni per il ritorno della percentuale. Non è possibile infatti dedurre il quantitativo bevuto da un’animale semplicemente dal sensore, poiché il range di questo è proporzionale all’altezza del liquido nel contenitore, ma non è dato sapere la sua capienza. Per questo motivo il parametro capienza massima può essere passato al dispositivo di sensing. Grazie a questo dato verrà calcolata la quantità di acqua bevuta al diminuire della percentuale rilevata dal sensore.
Entrambi i task di cibo e acqua adottano il protocollo MQTT per comunicare con il cloud. Lo scambio è bidirezionale ed è gestito dalla classe "MQTTManager". Questa si occupa dell’invio dei messaggi e, qualora il task "MQTTMessageChecker" sia in esecuzione, di ricevere i messaggi dal server. Questi messaggi innescheranno la gestione delle callback passando allo scheduler un task "MQTTMessageHandler". I messaggi sono scambiati in formato JSON. Ogni unità di controllo gabbia inizialmente si identifica mandando un messaggio al broker. In seguito vengono iniziate le rilevazioni per i consumi e, in caso di necessità, un messaggio affinché il server invii la notifica all’addetto.
Il task relativo al monitoraggio della temperatura nel collare è stato sviluppato affinché possa essere usato con due sensori diversi: il ds18x20 e il dht11. Creando il task si può scegliere il modello posseduto e, quando lo scheduler inizierà a eseguire ciclicamente le misurazioni, i dati e le notifiche verranno inviati in cloud.
# measure temp
if self.using_ds18x20:
temp = self.check_ds18x20()
else:
temp = self.check_dht()
# send data
self.mqtt_manager.send_msg(self.topic, "Temperature: {}".format(temp))
Il task relativo al battito cardiaco svolge, come il precedente, delle misurazioni cicliche e invia i dati rilevati. Un parte particolarmente complessa è stata quella della gestione del sensore per il battito. Il sensore, qualora interpellato, fornisce un singolo valore direttamente proporzionale alla dilatazione dei vasi sanguigni. Ne deriva la necessità di attuare misurazioni frequenti per non incorrere nella perdita della breve variazione di un battito. Abbiamo stabilito la frequenza di campionamento in base a quanto segue: Considerando che in condizioni di riposo, i battiti per minuto di un cane - da intendersi come pulsazioni - sono generalmente compresi tra 60 e 140 bpm, in base alla taglia, età e razza, e il valore può raggiungere valori anche più alti qualora in movimento, abbiamo preso come valore limite da rilevare 150 bpm. Ciò, significa che il tempo di ogni ciclo cardiaco \(T_{cc}\) è: \[T_{cc} = \frac{1}{bps} = \frac{1}{\frac{bpm}{60}}= \frac{60}{bpm} \Rightarrow \frac{60}{150 bpm} = 0.4s\] Considerato che il ciclo cardiaco si compone in sistole (contrazione) e diastole (rilassamento), la fase sistolica è quella più facilmente rilevabile poiché la contrazione ventricolare causata è più violenta e breve. Questa fase durante le rilevazioni effettuate dura circa un mezzo del ciclo cardiaco e produce un picco nei valori particolarmente indicativo per rilevare il battito in mezzo al naturale rumore del sensore. Per non perdere il picco massimo il numero di campionamenti \(N_{c}\) durante questa fase è stato fissato a 20. La frequenza di campionamento minima risultante \(f_{min}\) è stata calcolata come: \[f_{min} = \frac{ \frac{1}{2} * T_{cc} }{N_{c}} \Rightarrow \frac{ \frac{1}{2} * 0.4s }{20} = 0.01s = 10 ms\]
Salvando i valori risultanti e graficandoli con la libreria python "Mathplotlib" si ottiene una linea come quella di colore rosso in [Fig. 9.3]. Si può notare che il campionamento è sufficiente e permette di distinguere intuitivamente i battiti. Per rilevare le pulsazioni a livello digitale però è necessario formalizzare un altro modello matematico che non faccia incorrere il sistema in falsi positivi o falsi negativi. Un primo approccio si è basato su stabilire una singola soglia, oltre la quale il battito è rilevato e registrato. Questa soluzione si è rivelata inadatta in quanto il disturbo del sensore la farebbe attraversare più volte (si veda in [Fig. 9.3] poco prima del campionamento numero 2400 il valore attraversa la linea azzurra parecchie volte). Inadatti si sono rivelati anche i tentativi di normalizzare la linea dei valori, in quanto parecchio discontinui e di frequenza elevata, si perde la differenziazione dei picchi. Si è optato per stabilire una doppia soglia, la prima, più alta, oltre la quale il battito è rilevato, la seconda, più bassa, che determina la fine del battito. La prima volta che il valore attraversa la prima [Fig. 9.3, linea azzurra] una variabile registra il battito e nessun altra registrazione viene effettuata sino a che i valori non scendono sotto la soglia di fine battito [Fig. 9.3, linea gialla]. Queste soglie non possono essere fisse, variando la pressione di animale in animale e pure di giorno in giorno per lo stesso essere vivente. Per questo motivo i valori sono stati fissati per la prima a 4/5 e per la seconda a 1/2 tra minimo [Fig. 9.3, linea verde] e massimo [Fig. 9.3, linea blu] dei precedenti valori. La grandezza della finestra dei valori da cui prendere minimo e massimo è stata fissata a 250 valori. Questo perché, come si può notare dal grafico, comprende almeno due battiti. Un range troppo piccolo creerebbe dei minimi e massimi locali, rilevando picchi non propri e dando parecchi falsi positivi. Una finestra troppo ampia porterebbe a una staticità delle soglie rispetto alla variazione di pressione che creerebbe falsi negativi.
val = self.pulse_sensor.raw_measure()
self.history.append(val) # add to history of values
# crop to MAX_HISTORY length, getting the tail (last ones)
self.history = self.history[-MAX_HISTORY:]
# get min max in the history
minima, maxima = min(self.history), max(self.history)
# get thresholds
threshold_on = (minima + maxima * 4) // 5 # 4/5
threshold_off = (minima + maxima) // 2 # 1/2
# if val goes above beat threshold and no beat has previously been detected.
if val > threshold_on and self.still_beat == False:
# beat detected
self.led.on()
self.still_beat = True # prevents multiple appends for all the measures during a beat
# once every beat
self.beats.append(time.time())
Una volta rilevati i singoli battiti con il modello matematico, il calcolo del battiti al minuto è stato realizzato salvando la cronologia degli istanti di tempo per gli ultimi N battiti \(N_{beats}\). Sperimentalmente si è optato per 30 registrazioni per mantenere il valore dei bpm reattivo ma non dipendente solo da poche unità. Prelevando dalla cronologia il tempo passato \(T_{diff}\) per questi battiti, si può facilmente derivare il rateo di \(bpm\) attuale tramite la formula: \[bpm = \frac{ N_{beats}*60 s/min }{T_{diff}} = \frac{ N_{beats}*60 s/min }{T_{last}-T_{first}}\] Il battito cardiaco risultante viene poi inviato periodicamente al Database e, qualora ci fossero anomalie, una notifica viene invece generata e inviata immediatamente.
# calculate bpm
beats_time = self.beats[-1] - self.beats[0] # time difference between end and start of the queue
if beats_time:
bpm = (len(self.beats) / beats_time) * 60
print("HeartBeat: {}".format(bpm))
# if outside range
if bpm < self.min_heartbeat or bpm > self.max_heartbeat:
# send notification now
self.mqtt_manager.send_msg(MQTT_NOTIFY_TOPIC, ujson.dumps({"Notify":"Heartbeat is abnormal: {}".format(bpm)}))
I task di temperatura e battiti adottano anch’essi il protocollo MQTT per comunicare con il cloud. Lo scambio è bidirezionale per via della necessità di settare i range di temperatura e battiti per le notifiche di anomalia. Ogni unità collare inizialmente si identifica mandando un messaggio al broker. Successivamente partono le rilevazioni per i battiti e la temperatura. I parametri vitali vengono periodicamente inviati al server assieme ai messaggi per le notifiche di anomalie.
Il Raspberry è stato scelto come board per la computazione delle immagini di video-sorveglianza. Il principale concorrente a questa scelta, l’ESP32-CAM è stato testato per lo streaming video ma non è provvisto delle risorse computazionali necessarie per il rilevamento di anomalie. Ciononostante, avendo un costo inferiore rispetto al Raspberry è stato comunque considerato come alternativa low-cost. Il linguaggio scelto per la programmazione è stato Python per continuità con i microcontrollori e per la flessibilità di utilizzo. Sono state programmate multiple classi per di complessità crescente per agevolare l’utilizzo del software in caso di errori. La prima classe "camera tester" ha infatti semplicemente il ruolo di testare lo stream con ffmpeg e OpenCV. Un’altra classe "mqtt tester" si occupa di un semplice test di invio e ricezione attraverso il pacchetto mqtt di "awsiotsdk". Infine l’ultima classe di test "stream base" si occupa di testare lo stream attraverso l’utilizzo del pacchetto "flask" per creare un webserver su cui verrà pubblicato il video feed.
La parte di comunicazione è stata gestita creando una classe MQTT apposita che permette di connettersi, disconnettersi, mandare dei messaggi e impostare le callback. Questa classe viene usata da tutte le classi successive per le comunicazioni. Infine, per passare lo stream video da un dispositivo ad un altro nella stessa rete, sono state incluse due classe "sender udp" e "receiver udp" atte allo scopo.
Una delle due implementazioni proposte per il rilevamento di anomalie utilizza la motion detection. Questa tecnica si basa sul rilevare i cambiamenti dell’immagine corrente dato uno sfondo di riferimento. Il motion detector base è stato costruito come segue: Viene preso il frame corrente e viene sfumato con un filtro gaussiano per rimuovere minime differenze. Il risultato viene sottratto al frame di riferimento per il background. Nel nostro caso il frame di riferimento per il background viene aggiornato periodicamente. L’immagine che contiene le differenze viene passata attraverso una soglia per rilevare le zone con cambiamenti sostanziali e non minimi. Viene applicata la dilatazione per unire le zone discontinue in modo tale da unire aree vicine di cambiamento. Viene calcolata l’area delle zone di differenza e vengono scelte solo le zone con un’area maggiore di una soglia. Le zone scelte sono zone effettive di cambiamento dell’immagine.
# blur
gray_frame = cv2.GaussianBlur(gray_frame, (21, 21), 0)
# compute the absolute difference between the current frame and reference frame
frameDelta = cv2.absdiff(referenceFrame, gray_frame)
thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]
# dilate the thresholded image to fill in holes, then find contours
# on thresholded image
thresh = cv2.dilate(thresh, None, iterations=2)
cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
Il motion detector base è stato ampliato in altre due classi per comprendere l’invio di messaggi MQTT al rilevamento di un movimento ("motion detection mqtt") e lo streaming video assieme all’invio di messaggi ("motion detection mqtt stream").
La seconda implementazione proposta per la rilevazione di anomalie o intrusioni nel sistema di videosorveglianza fa uso di reti neurali per l’object detecion. La classe "object detection base" fa uso della rete neurale Yolo (una più approfondita discussione sulla scelta delle reti è presente nel capitolo Testing) per predire la presenza di oggetti anomali nella scena. Il codice permette di venir usato per il forward alla rete di una singola immagine, di un video, o di uno streaming da webcam. Nel mentre vengono calcolati i tempi di computazione per derivare gli FPS a cui il sistema sta andando. Assieme a questa classe è stata implementata la variante "object detection mqtt" con l’invio su MQTT del messaggio di anomalia e dell’oggetto rilevato per la notifica.
# capture frame
ret, image = cap.read()
#predition
boxes, confidences, classIDs, idxs = make_prediction(net, layer_names, labels, image, args.confidence, args.threshold)
#draw boxes
image = draw_bounding_boxes(image, boxes, confidences, classIDs, idxs, colors)
La Web App è stata sviluppata come un prototipo funzionante, tuttavia per essere considerato completo richiederebbe ancora del lavoro di rifinitura.
L’applicazione è stata sviluppata utilizzando nodeJS e VueJS. Una scelta guidata dalla semplicità del framework javascript, che a differenza di React e Angular offre una curva di apprendimento ben più bassa, favorendo lo sviluppo. VueJS forniva inoltre il vantaggio di integrarsi perfettamente con AWS Amplify, a livello di front-end. Mentre a livello di back-end le comunicazioni sono perfettamente supportate dato che anche l’applicativo back-end è stato sviluppato con nodeJS.
Il comparto estetico è sviluppato utilizzando Vuetify, questa è un’estensione di VueJS che sembrava integrarsi meglio con il framework rispetto a BootstrapVue.
Per la comunicazione con le API REST si è scelto di utilizzare AXIOS rispetto ad AJAX, questo perché risulta di facile integrazione con VueJS, supporta le SPA e consente il facile utilizzo di Async e Await.
Mentre per le websocket si è scelto di usare le librerie di default, principalmente per la loro semplicità di utilizzo. È stata valutata l’adozione di Socket.io che forniva maggiori funzionalità e supporto a comunicazioni come l’utilizzo di fall back. Tali funzionalità, tuttavia, non erano utili per un utilizzo così basilare, pertanto l’idea di utilizzare questa libreria è stata accantonata.
Per quanto riguarda le route della pagina è stato utilizzato VueRouter, essendo l’unica alternativa.
Infine per facilitare lo sviluppo è stato utilizzato Vuex che consente di accedere da più punti ad un oggetto condiviso.
Per questioni di velocità e leggibilità si è deciso di dividere l’applicativo su più view : Home e Login.
Ogni view è composta da più componenti che a loro volta sono composti.
Tutti gli elementi di VueJS sono stati strutturati seguendo il modello del Single File Components che prevede di inserire il codice per lo Style(CSS), Markup(Vue/HTML) e Script(JavaScript) tutto nello stesso file.
Lo sviluppo della Web App è stato fluido fino all’integrazione della prima chiamata alle API. Qui ci si è resi conto che le api non potevano essere chiamate direttamente dal Browser, mentre funzionavano perfettamente utilizzando sistemi come Postman e Reqbin.
E’ stato più volte riscontrato l’errore Cross-Origin Resource Sharing (CORS), che riguarda la possibilità di utilizzare altre sorgenti per attingere alle informazioni. Questo genere di verifica viene effettuata solo dal Browser ed è invece saltata su Postman e simili.
Dopo un investigazione siamo giunti alla conclusione che in fase di sviluppo avremmo potuto consentire ogni richiesta. Abbiamo quindi aggiunto le seguenti linee di codice nel file Template.yaml di SAM, per istruire il proxy cors di AWS a rispondere alle richieste con i campi aggiunti:
Globals:
Api:
EndpointConfiguration: REGIONAL
Cors:
AllowMethods: "'*'"
AllowHeaders: "'*'"
AllowOrigin: "'*'"
L’errore ha smesso di presentarsi, ma poiché avevamo la necessità di testare sempre più funzioni e non era pensabile effettuare il deploy di sam per ogni prova, abbiamo iniziato ad eseguire un’ istanza di AWS Lambda localmente tramite il comando : sam build && sam local start-api.
Giunti a questo punto il problema si è ripresentato e questa volta la soluzione è stata molto più ostica da trovare, nonostante il problema fosse lo stesso, ovvero la mancanza della risposta CORS.
Volenterosi di utilizzare e testare le funzioni lambda localmente abbiamo cercato una soluzione che risolvesse il problema in maniera esaustiva, giungendo finalmente una Issue che ha fornito la soluzione se pur non ottimale.
Il comando utilizzato: npx lcp –proxyUrl http://localhost:3000/
La soluzione adottata implica l’avviare un server proxy CORS che risponda alle richieste OPTIONS e poi reindirizzi all’immagine docker di lambda. Ovviamente la WebApp dovra contattare il proxy e non direttamente il container.
Nonostante gli sviluppatori di SAM confermino il supporto alle chiamate CORS locali non siamo riusciti a farle funzionare in altra maniera.
Il repository è stato collegato e configurato per il continuous deployment, così da pubblicare le modifiche online non appena rilasciate, se il sito compila. Il sito, essendo pubblico, è stato protetto da password con l’utilizzo di Amplify.
In questa sezione del progetto sono, le principali difficoltà affrontate sono state legate all’apprendimento delle tecnologie AWS utilizzate:
Lambda: I due principali problemi incontrati sono stati:
Lo sviluppo e il testing in locale che richiede l’ausilio della SAM CLI e della AWS CLI.
L’utilizzo del sdk di AWS per javascript, sopratutto quando era necessario contattare altri servizi come IoT Core o API Gateways.
IoT Core: Non sono state riscontrate particolari difficoltà se non con i certificati che non sono in un formato compatibile con la libreria UMQTT di Micropython.
CloudWatch: Consultare i log delle funzioni lambda non risulta complicato, stesso non si può dire per i log delle websocket.
IAM: Il sistema dei permessi di AWS è molto articolato e ci sono più modi per fornire i permessi, in generale la gestione dei permessi è stata faticosa. Alcuni permessi sono molto immediati, altri come quello per consultare i log di CloudWatch delle websocket molto meno, non tanto per i permessi più per il tool grafico o la sintassi di SAM.
API gateway: L’esposizione delle API REST e delle web socket non è stata difficoltosa.
SAM: Forse la parte più complicata dell’applicativo serverless, fornisce la possibilità di effettuare il deploy di Stack su AWS CloudFormation, con una sintassi tutta sua, orchestrare il deploy di : Funzioni Lambda, Regole IoT Core, Permessi IAM, Tabelle DynamoDB, API REST, Websocket e CloudWatch Event via Crono. Nonostante il grande sforzo per sfruttare al meglio SAM, il lavoro potrebbe essere ulteriormente automatizzato e perfezionato.
L’intero stack che esclude il database principale, Aws Aplify e i dispositivi IOT può essere dispiegato tramite il comando sam build && sam deploy Attualmente il deploy è dipendente da alcune variabili che sono configurabili con il flag -g, altre variabili sono incorporate e potrebbero essere scorporate alla stessa maniera se si volesse rendere il deploy multi-account.
Lo sviluppo del database è una parte critica del progetto, in un ottica di rendere l’applicativo veloce e scalabile il più possibile, abbiamo scelto di procedere con lo sviluppo di una tabella DynamoDB. DynamoDB offre una scalabilità e una velocità di interrogazione superiori ai database relazionali, per questo lo abbiamo scelto, inoltre la sua prefetta integrazione con il back-end lo rendeva ancora più appetibile.
Le difficoltà durante lo sviluppo del database sono state enormi. Partendo dalla documentazione e dalle guide che siamo riusciti a reperire, subito ci siamo trovati in difficoltà con il mindset necessario allo sviluppo del database, troppo legati all’ambito relazionale. Il database ha passato molti schemi diversi che sono stati raffinati mano a mano che la complessità e i meccanismi del DB venivano compresi. Questo comportava continue modifiche al DB e il testare e studiare sono diventati essenziali, motivo per cui abbiamo scelto di non includerlo all’interno del deploy SAM, non si voleva complicare il complicato.
Durante lo sviluppo abbiamo utilizzato due strumenti per aiutarci aiutarci nella comprensione e nello sviluppo del sistema:
NoSQL Workbench Il nuovo tool grafico di AWS ci ha permesso di visualizzare con maggiore chiarezza il database e di elaborare le query utilizzando PartiQL. Inoltre ci ha anche permesso di effettuare la creazione di tabelle utilizzando la connessione ad AWS.
PartiQL Una gradita sorpresa durante lo studi e lo sviluppo del database. Infatti questo consente di interrogare DynamoDB utilizzando la classica sintassi SQL, molto più espressiva dell’SDK javascript. Purtroppo l’implementazione al supporto PartiQL non è supportata totalmente e quindi grossa parte della sintassi SQL come proiezioni e query annidate non sono disponibili. Questo rende l’implementazione delle query più frammentata, e ci ha obbligato a riscrivere varie parti di codice e DB. Tali limiti sono intrinseci di DynamoDB e non una mancanza di sviluppo parziale.
Per quanto riguarda l’automazione di cibo e acqua e il monitoraggio dei parametri vitali dell’animale sono state testate multiple soluzioni hardware. In fase di validazione del progetto sono stati prese in esame principalmente due board che soddisfacessero i requisiti di economicità, connettività e prestazioni: L’ESP8266 e il successore ESP32. Entrambi offrono la connettività Wi-Fi integrata e buona potenza computazionale, cosa di cui è carente la board Arduino, e un costo contenuto (5€ per il primo e 7€ per il secondo, dati del primo semestre 2021) rispetto alla board Raspberry. Quest’ultima board offre connettività e prestazioni ma i costi sono decisamente fuori budget per il committente e per la natura distribuita dei compiti. La piattaforma ESP si è rivelata un buon compromesso e quindi si è passati a testarne i due differenti modelli.
Dopo i testing eseguiti in fase iniziale sono emerse differenze sostanziali nei tempi di avvio del programma e di connessione. Inoltre l’ESP8266 ha riscontrato spesso problemi nel caricamento dei file e nell’esecuzione di micropython. Di seguito si riporta la tabella riassuntiva per i tempi di esecuzione/comunicazione, accompagnati dalle caratteristiche dell’hardware.

Alla luce della minima differenza di prezzo tra i due device rispetto alla capacità computazionale, la scelta è ricaduta sul più recente ESP32.
Come anticipato in precedenza, il lato visione, di per se più computazionalmente oneroso, ha reso necessaria un’analisi più approfondita delle performance e la scelta è ricaduta su Raspberry Pi e ESP32-CAM. Inizialmente stato implementato un server web in C, per l’ESP ma il development è stato in seguito interrotto per la scarsa potenza potenza di quest’ultimo nell’elaborazione delle immagini. E’ stato tuttavia ritenuto valido per un’alternativa economica per il semplice streaming video senza elaborazione e notifica. Le board Raspberry Pi testate sono state le seguenti, con i rispettivi tempi di elaborazione:

* i tempi si riferiscono all’attesa media per ottenere i risultati di object-detection attraverso una rete neurale con architettura Yolo3 con lo stesso set di immagini.
Considerando il rapporto costo/prestazioni, la scelta è ricaduta sul Raspberry Pi 3 B+ che con soli 0.7 secondi di distacco dal suo successore si posiziona su una fascia decisamente più economica.
Per quanto riguarda il software sono state testate le prestazioni dei due metodi per la detection di anomalie/intrusioni.Il secondo, più elaborato, su riconoscimento oggetti per mezzo di una rete neurale.
Il primo, più lineare, si basa su elaborazione delle immagini tramite sottrazione dello sfondo per rilevare del movimento. Le semplici operazioni di sfocatura gaussiana, differenza, soglia e calcolo dell’area sono state studiate per ottenere alte prestazioni circa la velocità di esecuzione dell’algoritmo. I test sperimentali sulla piattaforma scelta Raspberry Pi 3B+ hanno rilevato una media di 30 FPS sul materiale di test. Questa misura si è rivelata parecchio costante, poiché l’algoritmo non effettua un’analisi semantica delle immagini ma semplicemente delle operazioni matematiche indipendentemente dal contenuto. L’unico overhead dell’algoritmo risiede infatti nel calcolo dell’area dell’immagine cambiata qualora presente. Più questa è grande più tempo viene impiegato per calcolarla. Rispetto ai tempi di esecuzione e alle normale fluttuazioni delle prestazioni non è stata rilevata una differenza degna di nota (Si vedano gli FPS nonostante la grande area rilevata in [Fig. 10.1]
La velocità dell’algoritmo va a discapito della precisione dello stesso. A seguito delle rilevazioni la matrice di confusione risulta non ottimale. Le motivazioni principali trovate risiedono nei seguenti scenari:
qualora una figura da rilevare stesse ferma o si muovesse lentamente, la soglia non sarebbe abbastanza alta da venir rilevata e ciò comporta dei falsi negativi. Non avendo nozione della semantica dell’immagine, l’algoritmo non può venir calibrato ulteriormente.
qualora un oggetto irrilevante (es: una mosca che passa vicino sulle lenti) produca un cambiamento significativo nell’immagine, la soglia viene superata e viene prodotto un falso positivo. Anche qui la mancanza di discernimento dell’algoritmo non può essere superata se non cambiandolo.
qualora l’oggetto estraneo sia lontano l’area di cambiamento risulta piccola e non supera la soglia, producendo falsi negativi. Se la soglia viene abbassata si incorre in falsi positivi per via di minimi cambiamenti ambientali.
La matrice di confusione risultante in [Fig. 10.2] risulta chiaramente sbilanciata con parecchi falsi positivi. Questo deriva chiaramente dall’impossibilità discussa di discernere tra oggetti in movimento "non allarmanti" e viceversa. Per ovviare a questo problema nella sezione successiva si discuterà l’uso delle reti neurali e le prestazioni inerenti l’uso dell’object-detection.
Il secondo metodo testato per la sorveglianza è l’object detection. Sono state confrontate 4 reti neurali per trovare la più adatta tra prestazioni e precisione. Nonostante sia stata scelta la board Raspberry tenendo il considerazione la potenza di calcolo, i fotogrammi al secondo hanno subito una brusca riduzione rispetto alla soluzione precedente. Il parametro minimo è stato fissato a 1 FPS, sotto il quale il divario temporale tra due immagini analizzate mancherebbe la rilevazione di possibili avvenimenti. La causa principale di tale crollo nelle prestazioni utilizzando questa soluzione è la mancanza di una GPU adatta nei Raspberry. Tale carenza è comunque colmabile con l’acquisto di espansioni USB dedicate all’espansione delle capacità grafiche della board (TPU). Immediatamente è risultato palese che le architetture delle reti tradizionalmente usate sui pc fossero troppo pesanti per il sistema ospitante. Per referenza è stata lasciata l’architettura (già di per se performante) Yolo3. Il focus quindi è stato soprattutto sull’individuazione di reti "leggere" che offrissero prestazioni adeguate. Sono state confrontate e testate le varie versioni "Tiny" della stessa rete come in tabella seguente:

Dopo l’analisi è risultato chiara la scelta della versione Yolo V4-Tiny, con il miglior numero di rilevazioni e una velocità adeguata alla videosorveglianza.
Le prestazioni sono state a livello di precisione sono state alte, come ci si aspetta da una rete neurale comparata "in the wild" a metodi tradizionali. Di seguito si riporta la matrice di confusione delle prove effettuate:
L’applicativo è stato modellato in ogni sua parte per scalare facilmente all’occorrenza. Il design distribuito e in cloud ne facilita l’eventuale evoluzione su larga scala. Verranno di seguito brevemente analizzati due scenari:
Evoluzione Interna In termini di scalabilità del singolo software lo scenario più realistico consiste nell’aggiunta di elementi (gabbie o animali) da parte di un grande canile. L’aggiunta, anche cospicua, di elementi non porterebbe ulteriore complessità al sistema. Gli unici requisiti riguardano comprare l’hardware specifico da installare. Questo si occuperà attraverso il programma di mandare i dati direttamente al cloud, il quale li processerà e mostrerà le informazioni aggiornate sull’applicativo.
Diffusione su Larga Scala In termini di diffusione del software in molteplici copie lo scenario riguarderebbe l’adozione dell’applicativo da parte di molteplici amministrazioni. Grazie all’adozione dei servizi AWS in Cloud, l’ availability e la scalability del sistema sono garantite anche ad alti livelli.
L’attuale architettura hub and spoke, si rivela essere la scelta più fattibile anche su larga scala, data la sua buona integrazione con MQTT.
Uno dei principali punti di criticità dell’attuale architettura, nel momento in cui verrebbe fatto un deploy su larga scala, è dato dalla forte dipendenza del sistema dalla disponibilità di AWS in quanto se l’infrastruttura web crollasse o avesse dei problemi che ne influenzano il servizio, l’applicativo smetterebbe di funzionare. Questo problema può essere affrontato principalmente in due modi:
effettuare una replica dei servizi e dei dati in un’altra Availability Zone che si trova sotto la stessa region per ottenere fault tolerance
effettuare una replica in una diversa regione di AWS. questa farà da base per l’applicazione di una strategia di disaster recovery.
I cambiamenti nella rete interna sono relativamente limitati, si suddividono in due parti
L’utilizzo di Micro-python consente di sviluppare codice per una grande famiglia di micro-controllori. L’ESP-32 è stato scelto anche pensando ad uno sviluppo futuro dato che la sua famiglia presenta varie board che forniscono feature adatte agli ambienti più disparati. Su larga scala è ragionevole pensare che il codice di micro-python opportunamente riadattato consenta la scelta di una qualcunque di queste board alternative fornendo così un’adattabilità in termini di hardware elevata. Ad esempio, vi è la possibilità di integrare ESP che dispongono di tipi di connessione diversi, come l’ESP32-Ethernet-Kit V1.2 e l’ESP32-PICO-KIT-1.
Dato che ogni ESP gestisce un singolo cane e ha una funzione critica, avere un ulteriore livello di controllo dell’ESP locale può aiutare nella preventiva rilevazione dei guasti locali dato che la rete locale è più affidabile ha una minore propensione ai guasti, fornendo alla centralina la possibilità di diagnosticare tramite messaggi interni eventuali guasti, effettuando controlli periodici.
L’integrazione delle funzioni tralasciate nell’applicativo locale realizzato durante questo progetto possono essere introdotte tramite Cloud formation mediante l’utilizzo di SAM (Serverless Application Model). Alcune di queste funzioni sono:
Amazon Cognito: attualmente il sistema gestisce il salvataggio degli utenti all’interno del DataBase. In un’ottica di deployment su larga scala l’attuale soluzione risulterebbe poco adatta. Un approccio decisamente migliore sarebbe quello di affidare la gestione degli utenti ad Amazon Cognito ed integrarlo con Amazon AWS Amplify.
Dynamo DB: il sistema attuale utilizza due tabelle Dynamo DB, la prima è creata tramite SAM e viene utilizzata per la gestione delle WebSocket, la seconda è creata manualmente e contiene i dati del canile. Dato che la seconda modalità non è applicabile su larga scala, sarebbe necessario automatizzare anche la creazione del database principale, specificando le varie proprietà come lo schema e i valori di throughput.
IoT Core: è possibile automatizzare il rilascio dei certificati e dei permessi necessari per i dispositivi e aggiungere il relativo dispositivo shadow che mantiene l’ultimo stato conosciuto consentendo così di interrogare il dispositivo anche quando offline.
La libreria UMQTT di Micro-Python consente di utilizzare solo la QoS (Quality of Service) di livello 1 o 0. Attualmente il sistema utilizza QoS di livello 0. Poiché questo applicativo non ha particolari vincoli di velocità per lo scambio dei messaggi è possibile valutare anche l’utilizzo di una QoS superiore. Nel caso in cui si volesse avere la possibilità di avere una QoS di livello 2, che garantisce di ricevere messaggi con certezza, sarà necessario ricorre ad un’alternativa poiché UMQTT supporta fino al livello 1. Sarà inoltre necessario sostituire il broker MQTT di IoT Core con un broker in grado di supportare lvl 2, come ad esempio HiveMQ
Il database principale gestisce attualmente i dati dei cani, le relative rilevazioni e gli utenti. Questa struttura si è rivelata necessaria poiché ai fini della realizzazione del progetto non vi era la possibilità di sviluppare una parte gestionale in quanto non inerente al corso. Uno sviluppo futuro vede necessaria una rielaborazione del sistema che permetta di effettuare una netta divisione tra la parte gestionale e quella relativa ai dati provenienti dai dispositivi di sensing. Questo porterebbe ad utilizzare il Database attuale solo per immagazzinare le rilevazioni, le quali generano una grande quantità di record. La gestione dei profili dei cani e di quelli degli utenti, andrebbe invece considerata a parte all’interno di un sistema prettamente gestionale. Si potrebbe, ad esempio, utilizzare Amazon Cognito per gestire gli utenti e un DB relazionale per i profili dei cani, il quale porterebbe come vantaggio l’integrità referenziale dei dati e seppur meno performante dovrebbe gestire pochi record.
Nella realizzazione della soluzione attuale non ci si è preoccupati particolarmente della sicurezza. Attualmente le API REST disponibili su API Gateway sono prive di qualunque tipo di autenticazione, questo vale anche per le WEB Socket. Per effettuare il deploy dell’applicativo è necessario autenticare ogni richiesta utilizzando, ad esempio API Gateway Lambda Authorizer. Ciò richiede la scrittura di policy dedicate e maggiormente restrittive rispetto alle attuali full access policy.
Attualmente i micro-controllori, per autenticarsi presso AWS, utilizzano una chiave privata senza verificare la validità del certificato del server. Questo espone i micro-controllori ad un attacco di tipo man in the middle. Se si volesse fare un utilizzo reale del sistema, questo sarebbe un problema da risolvere in maniera prioritaria.
Se il sistema dovesse essere dispiegato su larga scala si dovrebbe tenere in considerazione il fatto che, a fronte di modifiche a livello di codice, sarebbe pesante dover fare ogni volta il deploy in corso d’opera per testare le funzionalità. Per questo motivo è utile fare in modo che le funzionalità possano essere provate anche in locale, permettendo così di fare il deploy solo quando davvero necessario. Per abilitare il testing in locale è possibile utilizzare SAM CLI che permette di hostare localmente un’istanza Docker per le chiamale Lambda.
Il lavoro è stato svolto utilizzando un approccio Scrum, con quattro sprint, più uno iniziale incentrato sullo studio delle tecnologie.
Di seguito vi è una descrizione delle mansioni che sono state svolte dai membri del gruppo.
progettazione e realizzazione del database
implementazione logiche di interrogazione e calcolo nel back-end della Web-App
implementazione e testing delle funzioni nel front end
stesura template delle funzioni nel back-end
configurazione SAM
prototyping della sensoristica
realizzazione diagrammi sequenza
implementazione del front-end
integrazione nelle adeguate pagine del front-end delle chiamate al backend
configurazione SAM
implementazione di alcune funzioni nel backend
scheduling di funzioni lambda innescate da Crono Cloud Watch, MQTT, Api Gateway
implementazione scheduler Micropython
prototyping della sensoristica
realizzazione diagrammi sequenza
implementazione scheduler Micropython
implementazione funzioni core di Micropython e classi per sensori/attuatori
implementazione sistema di videosorveglianza con motion detecion e object detection
implementazione script di automatizzazione caricamento file
prototyping della sensoristica
progettazione e implementazione macchina a stati
La collocazione temporale degli sprint è descritta nel seguente diagramma di Gantt:
Gli sprint sono stati portati avanti nel seguente modo:
Pianificazione a inizio sprint degli obiettivi, tempistiche e responsabilità nel periodo dello sprint corrente. Diviso in due parti:
parte 1 Viene raffinato e rivisto il product backlog, viene effettuata la scelta dello sprint goal (what).
parte 2 Si decidono gli item e viene raffinato come implementarli (how). Effettuato con solo il team senza la figura del product owner
Breve meeting svolto giornalmente. Viene utilizzato per gli aggiornamenti sull’andamento del progetto, senza scendere nei dettagli implementativi.
Utilizzato per risolvere problemi che causano il blocco di un componente del team per parecchio tempo su una issue.
Riflessioni e considerazioni finali sullo spint passato. Suggerimenti per migliorare il prossimo. Diviso in tre parti:
Product backlog refinement aggiunta di dettagli e riordino del product backlog
Sprint review è stato ispezionato l’incremento, il Minimum Viable Product o di risultati sul processo. Discernere cosa è stato fatto e cosa no
Retrospettiva Considerazioni sul team stesso e sui miglioramenti per il prossimo sprint.
All’interno dello sprint 0 il focus è stato sullo scegliere le giuste tecnologie di sviluppo e sull’apprenderle in maniera sufficiente per il kick-off del progetto. L’obiettivo è stato raggiungere una conoscenza e competenza minima per sviluppare il design in maniera consapevole e ottimale.
al termine di questo sprint si sono acquisite le competenze di base per poter iniziare a lavorare con AWS e i dispositivi IoT. Inoltre ci si è portati avanti con lo scheletro del sito.
ambiente di lavoro Linux standardizzato e virtualizzato
sito linkato, con le prime due pagine base: home e login
ESP32 con firmware installato MicroPython, script e guida all’uso
codice per sensori base, test relativi e stubs per eseguirli senza necessità del micro-controllore
repository software con CI e test automatizzati
database progettato e popolato con qualche dato ai fini di testing
All’interno dello sprint 1 il focus è stato sull’usare le competenze tecnologiche acquisite precedentemente per sviluppare i componenti principali del progetto. Sono stati scelti come obiettivi le user stories per l’automatizzazione di cibo e acqua e la visualizzazione delle informazioni relative a un animale sulla webpage.
al termine di questo sprint sono state implementate le funzioni base dei maggiori componenti per l’automatizzazione fisica di cibo e acqua e il relativo prototipo fisico. Sono state aggiunte sull’applicativo la vista delle informazioni dell’animale e l’impostazione del cibo da erogargli.
codice per i sensori/attuatori per acqua e cibo, con stubs, test e automatizzazione. (Livello acqua, elettrovalvola, motore, bilancia, laser e rilevatore di luce)
prototipo fisico per i sensori per acqua e cibo.
database migliorato e rifattorizzato
visualizzazione dei dati del cane sul sito
visualizzazione dei grafici delle statistiche sul sito
Nello sprint 2 il focus è stato sul realizzare la logica d’orchestrazione della sensoristica e l’integrazione tra essa e l’applicativo per mezzo del protocollo MQTT. Sono stati prodotti gli artefatti di documentazione e schemi esemplificativi. Inoltre, è stato dato peso alla creazione delle query che permettono di integrare le funzioni del sito con il database. In particolare ci si è concentrati sulle user-stories prioritarie, che costituiscono il core del dominio.
sviluppate query necessarie alla logica centrale dell’applicazione web
grafici per la temperatura e l’umidità nell’applicazione web
implementata coverage dei test Python, con relativa pagina web su Github pages.
aggiunta Quality Assurance con SonarCloud, Codacy e Codefactor
implementata Continuous Delivery con GitHub Actions e GitHub Releases
implementata macchina a stati per food delivery e water automation
Nello sprint 3 sono state implementate le query che verranno chiamate dal sito per mostrare gli elementi all’utente. Inoltre, è stato migrato il codice JavaScript in un repository dedicato che permette il deployment delle funzioni in automatico su AWS con SAM. Sono state sviluppate le funzioni per ottenere i dati della sensoristica del collare smart, implementando la logica per il controllo dei valori e l’invio delle notifiche su MQTT.
sviluppate query complesse necessarie alla logica centrale dell’applicazione web
repository dedicato delle funzioni JavaScript per AWS
setup framework SAM per automazione AWS
prototipo fisico per i sensori di temperatura e battito
implementata macchina a stati per smart-collar heartbeat e temperature
Lo sprint 4 è stato il più impegnativo, perché vi era la necessità di chiudere il progetto, portando a termine tutti i task preventivati. Una grossa parte dello sprint è stata dedicata all’integrazione delle diverse parti, alla chiusura delle ultime interrogazioni al database, all’inserimento degli ultimi pezzi dell’interfaccia grafica che permettono all’utente di interagire con il back-end e alla conclusione del sistema di sorveglianza.
Completamento WebApp che permette all’utente di interagire con il sistema, visualizzando i dati e apportando delle modifiche.
Completamento Back-end che gestisce la logica del sito
Completamento gestione di sensori, attuatori e sistema di sorveglianza.
Lo sprint 5 è stato lo sprint finale di revisione progetto, per assicurare la massima qualità e rifinire gli ultimi dettagli. In questo sprint si sono corretti piccoli bug, sono state apportate migliorie estetiche e funzionali. Infine anche la documentazione e il report sono stati revisionati.
Migliorie grafiche.
Migliorie al codice.
Video del prototipo.
Al termine del percorso che ha portato alla realizzazione di questo progetto è stato raggiunto un risultato che riteniamo molto soddisfacente. Sono state utilizzate e integrate diverse tecnologie, il che ci ha permesso di acquisire ed affinare competenze a tutto tondo. Riteniamo inoltre che il progetto sia stato particolarmente ambizioso e gli sforzi sono stati commisurati alla soddisfazione finale per averlo completato. Questo lavoro, inoltre, potrebbe rappresentare una buona base di partenza per lo sviluppo di un sistema reale che porti un reale vantaggio alla realtà dei rifugi per animali.
In futuro sarebbe possibile estendere il sistema aggiungendo una parte gestionale. I due canili che abbiamo interpellato, infatti, sono sprovvisti anche della più basilare forma di sistema informatico, fatta eccezione per l’anagrafe canina che però non è ottimizzata per l’utilizzo che ne devono fare e ancora tanto lavoro viene affidato alle capacità di ragionamento e deduzione del personale del canile. Si potrebbe inoltre integrare il sistema aggiungendo altre feature, come l’inserimento di un nuovo cane mediante la lettura dei dati direttamente dal chip oppure l’introduzione di una più importante elaborazione dei dati, soprattutto per quanto riguarda le immagini provenienti dalla videocamera che potrebbero dare un importante aiuto ai gestori se gli venisse applicata una logica che, ad esempio, permette di rilevare comportamenti anomali del cane. Si potrebbe inoltre aggiungere un sistema di tracciamento mediante gps in maniera tale da permettere ai volontari o alle famiglie che, nella fase di pre-affidamento, vorrebbero abituare il cane alla loro presenza, di portare il cane a fare una passeggiata, senza temere che il cane possa scappare e perdersi.
Un altro possibile sviluppo riguarda il dispiegamento del sistema su larga scala, affinché possa essere utilizzato da più canili. A questo punto se si riuscisse ad introdurre un’elaborazione migliore delle soglie standard dei consumi e dei parametri vitali, ci si potrebbe basare sulle medie di più cani, cosa che permetterebbe di evitare che debba essere il veterinario ad impostare manualmente le soglie che ritiene più adeguate per ciascuna cane basandosi su razza, tagli, età e precedenti clinici.