E’ la porzione della pagina che viene modificata più volte recuperando i vari contenuti da visualizzare tramite richieste specifiche (utilizzando il protocollo MQTT) senza ricaricare nuovamente il contenuto statico della pagina.
Consiste generalmente in codice javascript che riguarda principalmente:
Per scelta progettuale, ogni messaggio di comando deve riportare l’indirizzo applicativo MQTT del dispositivo più la coppia tag_comando:valore_comando
.
var vls = ['{"devid":"'+mqttid+'","up1":"255"}','{"devid":"'+mqttid+'","down1":"255"}','{"devid":"'+mqttid+'","conf":"255"}'];
I messaggi sono raccolti in uno o più array e recuperati mediante un indice che rappresenta la loro posizion nell’arraye. Per quanto riguarda i pulsanti la scelta organizzativa adoperata è di tenere vicini i messaggi di un gruppo facendo seguire quelli di un eventuale altro gruppo. Ad esempio, le funzioni “up1” e “down1” del motore 1 sono raggruppate nelle locazion 0 e 1 dell’array, a seguire si troveranno le funzioni “up2” e “down2” del motore 2.
Per scelta progettuale, le callback degli eventi di input non sono inserite nei tag degli elementi HTML della pagina ad esempio con codice tipo <button onclick="myFunction()">Click me</button>
ma si è preferito registrare delle callback inline come ascoltatori di eventi specifici di un certo oggetto del DOM della pagina HTML (stile java).
Il riferimento alla rappresentazione ad oggetti di un elemento HTML si recupera tramite la funzione document.getElementById('elem_id')
dove elem_id
è l’attributo univoco id del tag HTML di cui si vuole “ascoltare” un certo evento.
var up1=document.getElementById('up1');
var dw1=document.getElementById('down1');
up1.addEventListener('click', function(){press(vls[0]);});
dw1.addEventListener('click', function(){press(vls[1]);});
I messaggi di feedback sono obbligatori da parte del dispositivo perchè hanno l’importante funzione di confermare, a livello applicativo, l’effettiva applicazione del comando. Per quanto è possibile, dovrebbero riportare lo stato effettivo delle porte di uscita del dispositivo, possibilmente leggendone il reale valore. Al ricevimento delle informazioni di feedback queste devono essere smistate all’ elemento HTML di input corrispondente al comando a cui esse si riferiscono. Il feedback può coambiare un elemento decorativo quale colore di un tasto o posizione di un cursore, oppure riportare un valore numerico o testuale in una casella di testo.
I messaggi di feddback, come quelli di comando, sono codificati in JSON e possono essere interpretati da un parser fornito dalla classe statica javascript JSON.
function onRcv(d) {
var obj = JSON.parse(d);
for(var x in obj){
var el = document.getElementById(x);
if(el != null){ //controlla se il campo esiste nel DOM della pagina
//console.log(x);
if(x=='up1' || x=='down1' || x=='up2' || x=='down2'){
console.log('stato:'+obj[x]);
if(Number(obj[x]) == 255){
el.style.backgroundColor = "#b30000";
}else{
el.style.backgroundColor = "#00ccff";
}
}
//{"devid":"pippo","up1":"0","sp1":"10000","tr1":"50"}
//{"devid":"pippo","up1":"1","sp1":"10000","tr1":"10","pr1":"10"}
//errori nel json staccano la connessione!!
};
}
}
L’istruzione
var obj = JSON.parse(d);
recupera un oggetto javascript avente per campi i campi della stringa JSON. I campi possono essere:
Il ciclo
for(var x in obj){
var el = document.getElementById(x);
if(x=='up1' || x=='down1' || x=='up2' || x=='down2'){
if(Number(obj[x]) == 255){
el.style.backgroundColor = "#b30000";
}else{
el.style.backgroundColor = "#00ccff";
}
}
}
x
if-then-else
Number(obj[x])
el = document.getElementById(x);
el.style.backgroundColor = "#b30000";
Serve ad impostare i parametri della comunicazione tra la pagina e il broker MQTT:
var mqttid = "soggiorno-gruppo06";
var mqttAddr = "broker.hivemq.com";
var wsport = "8000";
var mqttProto ="/mqtt"; //default
var intopic = "soggiorno/in";
var outtopic = "soggiorno/out";
Gli eventi principali sono:
onFailed
onMessageArrived
onConnectionLost
In particolare, critico è l’evento onConnectionLost
che, per evitare perdite di sincronizzazione della pagina con il dispositivo, viene gestito pianificando la riconnessione periodica fino ad una nuova connessione avvenuta con successo.
start();
function start(){
var clientID = mqttid+'_' + parseInt(Math.random() * 100);
conn = new Paho.MQTT.Client(mqttAddr, Number(wsport), mqttProto,clientID);
//client = new Paho.MQTT.Client("iot.eclipse.org", Number(443), "/wss");
//"var conn = new Paho.MQTT.Client('{MA}', Number('{MT}'), clientID);"
console.log(conn);
console.log('broker:'+mqttAddr+', port:'+wsport+', path:'+mqttProto+', id:'+clientID);
// connect the client
conn.connect(
{
cleanSession : false,
onSuccess : onConnect,
onFailure : onFailed,
keepAliveInterval: 30
});
function onFailed(err) {
//"conn.send('Connect ' + new Date());"
console.log('Initial connect request failed. Error message : ' + err.errorMessage);
};
function onConnect(resObj) {
//"conn.send('Connect ' + new Date());"
console.log('onConnect');
conn.subscribe(outtopic);
console.log('Connected to ' + resObj.uri);
if (resObj.reconnect){
console.log('It was a result of automatic reconnect.');
}
// carica parametri di configurazione
press(vls[4]);
};
conn.onMessageArrived = function (e) {
console.log('Received: '+e.payloadString);
if(e.payloadString){
var obj = JSON.parse(e.payloadString);
//controlla se è indirizzato al dispositivo associato alla pagina
if(obj.devid==''+mqttid+''||obj.devid=='FF'){//FF id broadcast valido per tutti i dispositivi
console.log('Received: '+e.payloadString);
onRcv(e.payloadString);
}
}else{
console.log('Message received error: '+e.payloadString);
}
};
conn.onConnectionLost = function (resObj) {
//console.log('Lost connection to ' + resObj.uri + ' Error code: ' + resObj.errorCode + ' Error text: ' + resObj.errorMessage);
if (resObj.reconnect){
console.log('Automatic reconnect is currently active.');
}else{
console.log('Lost connection to host, reconnect in 5 seconds');
// Try to reconnect in 5 seconds
setTimeout(function(){start()}, 5000);
}
};
};
function send(str){
console.log('send: '+str);
var msg = new Paho.MQTT.Message(str);
msg.destinationName = intopic;
console.log('topic: '+msg.destinationName);
conn.send(msg);
};
function press(s){
send(s);
};