Markdown source

<script>
var randomString = function(length) {
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    for(var i = 0; i < length; i++) {
        text += possible.charAt(Math.floor(Math.random() * possible.length));
    }
    return text;
}
var clientId=randomString(5);
var cube;
var render,scene,camera;

//var broker="www.tanzolab.it";
//var port=1884;

var broker="iot.eclipse.org";
var port=80;

var topic = "tanzolab/" + clientId + "/#";
var client;
var delta_x=0;
var delta_y=0;
var delta_z=0;

function onConnect() {
	console.log("onConnect");
	client.subscribe(topic);
}

function onSuccess() {
	console.log("onSuccess");
}

// called when the client loses its connection
function onConnectionLost(responseObject) {
	console.log("onConnectionLost");
	if (responseObject.errorCode !== 0) {
		console.log("onConnectionLost:"+responseObject.errorMessage);
	}
}


// Messaggi in arrivo dallo smartphone via MQTT
function onMessageArrived(message) {
	//$("#inbox").val(message.destinationName + " " + message.payloadString);	

	//console.log("destinationName:" + message.destinationName);
	//console.log("payloadString:" + message.payloadString);

	if (message.destinationName.search("acc")>-1) {
		json_string = JSON.parse(message.payloadString);
		$("#incoming_payloads").text(message.payloadString);
	
		//console.log("x=" + json_string.x);
		//console.log("y=" + json_string.y);
		//console.log("z=" + json_string.z);
		
		// Estrae i dati dell'accellerazione
		acc_x = parseFloat(json_string.x);
		acc_y = parseFloat(json_string.y);
		acc_z = parseFloat(json_string.z);

		console.log("payloadString:" + acc_x);
		delta_x = acc_x;
		delta_y = acc_y;
		delta_z = acc_z;
	}
}	
	
$(document).ready(function() {
	client = new Paho.MQTT.Client(broker, Number(port), "/ws",clientId);
	
	// set callback handlers
	client.onConnectionLost = onConnectionLost;
	client.onMessageArrived = onMessageArrived;
	
	// connect the client
	client.connect({onSuccess:onConnect});

	function animate() {
		requestAnimationFrame( animate );
		renderer.render( scene, camera );
		
		cube.rotation.z += -(delta_x/100);
		cube.rotation.x += -(delta_y/100);
		//cube.rotation.y += -(delta_z/100);
	}
	scene = new THREE.Scene();
	camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 1000 );
	
	renderer = new THREE.WebGLRenderer({ alpha: true });
	//renderer.setSize( window.innerWidth, window.innerHeight );
	renderer.setSize( 400, 400 );
	document.getElementById("3d").appendChild(renderer.domElement);

	var geometry = new THREE.BoxGeometry( 2, 2, 2,5,5,5 );
	var material = new THREE.MeshBasicMaterial( { 
		color: 0x000000, 
		wireframe: true
	} );
	cube = new THREE.Mesh( geometry, material );
	scene.add( cube );
	
	camera.position.z = 5;
	renderer.render( scene, camera );
	animate();
	
	$("#xyz_home").click(function() {
		delta_x = 0.00;
		delta_y = 0.00;
		delta_z = 0.00;
		cube.rotation.x=0;
		cube.rotation.y=0;
		cube.rotation.z=0;
	})
	$("#xyz_stop").click(function() {
		delta_x = 0.00;
		delta_y = 0.00;
		delta_z = 0.00;
	})
	$("#x_rotation").click(function() {
		if (delta_x==0) {
			delta_x = 0.05;
		} else {
			delta_x = 0.00;
		}	
	})
	$("#y_rotation").click(function() {
		if (delta_y==0) {
			delta_y = 0.05;
		} else {
			delta_y = 0.00;
		}	
	})
	$("#z_rotation").click(function() {
		if (delta_z==0) {
			delta_z = 0.05;
		} else {
			delta_z = 0.00;
		}	
	})
	
	var typeNumber = 4;
	var errorCorrectionLevel = 'L';
	var qr = qrcode(typeNumber, errorCorrectionLevel);
	var data='http://www.tanzolab.it/webapp/acc2mqtt/?client_id=' + clientId;
	qr.addData(data);
	qr.make();
	document.getElementById('placeHolder').innerHTML = qr.createImgTag();
	document.getElementById('placeHolder_url').innerHTML = "<a href='" + data + "' target='_blank'>" + data + "</a>";

	// Questa line serve solo per aggiornare il contenuto dell'articolo web
	$("#web_client_id").html(clientId);

});	
</script>

#Idee per realizzare una WebApp di controllo remoto

<h6>
In questo esperimento ho messo in fila una serie di tecnologie per 
realizzare la base per un telecomando su smartphone in logica IOT
</h6>

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcode-generator/1.2.0/qrcode.min.js"></script>

Il cubo che appare qui sotto è stato disegnato con [WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API) 
che è la tecnologia per disegnare oggetti 3D all'interno di pagine Web. Per interagire
con questi oggetti si usa ovviamente il linguaggio Javascript ma il rendering
è comunque molto veloce perchè WebGL permette di accedere direttamente alle
capacità di accellerazione grafica della vostra scheda video tramite OpenGL.

<div id="3d"></div>

Useremo questo cubo come oggetto da controllare in remoto tramite il nostro telefono 
cellulare.

<!--<button id="xyz_home" class="btn btn-primary">Home</button>
<button id="xyz_stop" class="btn btn-primary">Stop</button>
<button id="x_rotation" class="btn btn-primary">X</button>
<button id="y_rotation" class="btn btn-primary">Y</button>
<button id="z_rotation" class="btn btn-primary">Z</button>
-->

Se provate a leggere, con il vostro smartphone, il QR-code riprodotto qui sotto:

<div id="placeHolder"></div>	

oppure ad aprire questo link: <span id="placeHolder_url"></span> vedrete che 
sarà possibile muovere il cubo sul video del PC dal telefono semplicemente muovendo 
il telefono. Ovviamente è richiesto un telefono dotato di accellerometro a bordo ormai presente in 
tutti gli smartphone. Sul telefono appariranno i dati di lettura rilevati dall'accellerometro di bordo.

Da notare che il telefono riesce a inviare dati al cubo senza dover intervenire in
alcun modo nella configurazione della rete dove è connesso il PC. Il tutto funziona 
perfettamente anche in caso di presenza di un firewall o di un proxy server.

E' anche possibile aprire una seconda finestra con questa pagina, leggere il nuovo 
QR-code con un altro telefono e controllare in maniera indipendente i due cubi sul video.

Allo stesso modo se qualcun altro fa lo stesso esperimento in un'altra parte del mondo,
telefoni e cubi agiranno in maniera del tutto indipendente tra loro.

Se invece farete il refresh della pagina la relazione con il telefono si perderà e andrà
riletto il QR-Code. La relazione non si perde se invece fate il refresh della WepApp 
solo sul telefono in quanto l'identificativo che consente di mantenerla è ancora 
presente nella url della pagina. Questo è utile per riprendere il controllo dopo che
il telefono è andato in stand-by.

##Come funziona ?

Nella seguente figura è riportato lo schema di funzionamento del sistema. 

<img src="./acc2mqtt.jpg" class="img-responsive" width="60%">

Alla base di
tutto c'e' un [Broker MQTT](http://www.hivemq.com/blog/mqtt-essentials-part-3-client-broker-connection-establishment) 
fornito gratuitamente da [Eclipse.org](https://iot.eclipse.org/) che risponde 
all'indirizzo <b>iot.eclipse.it</b>. Si tratta di un Broker pubblico senza alcun
tipo di privacy per cui si sconsiglia di usarlo per far viaggiare i pacchetti di 
un sistema di controllo vero.

In questo caso meglio installarsi un Broker MQTT Open Source in un sistema privato. 
Il broker per eccellezza è [Mosquitto](https://mosquitto.org/) ed è installabile
gratuitamente su qualsiasi sistema Linux.

Essendo il broker un oggetto che deve essere sempre operativo, pena il blocco totale di tutto il 
sistema di controllo, l'ideale sarebbe farlo girare su una scheda Linux Embedded. 
Anche una piccola scheda [Arietta G25](https://www.acmesystems.it/arietta) 
andrebbe benissimo.

Per poter far comunicare i due programmi Javascript che stanno girando nel browser
del PC e nel browser dello Smartphone ho usato le librerie [Eclipse Paho](http://www.eclipse.org/paho/)
sempre Open Source e disponibili per qualsiasi linguaggio di programmazione.

### Il topic MQTT usato

Ogni coppia Smartphone/PC usa un topic MQTT diverso per comunicare. In questo modo 
non c'è possibilità di interferire con altre coppie Smartphone/PC.

Un esempio di topic è:

<div class="lead">
<blockquote>
<strong>
tanzolab/[<font color=red>client id</font>]/acc;
</strong>
</blockquote>
</div>

Il <font color=red>client id</font> viene generato casualmente dalla pagina web su PC
ed inserito nella URL da leggere con il cellulare quello generato da questa pagina 
ad esempio è:

<div class="lead">
<blockquote>
<strong>
http://www.tanzolab.it/webapp/acc2mqtt/?client_id=<font id="web_client_id" color="red"></font>
</strong>
</blockquote>
</div>

Nel topic il programma Javascript che gira sullo smartphone invia un messaggio denominato payload.
Il formato del messaggio che abbiamo scelto per comunicare con il cubo sul PC è  per
forza di cose JSON. Nella riga seguente vengono visualizzati i messaggi JSON che
sta inviando lo smartphone

<div class="lead">
<blockquote>
<strong>
<font id="incoming_payloads">In attesa di payloads....</font>
</strong>
</blockquote>
</div>


##Sorgenti

* [Accedi al sorgente di questa pagina](http://www.tanzolab.it/?id=view_md_source&source_id=acc2mqtt)
* [Accedi al sorgente della webapp](http://www.tanzolab.it/?id=view_md_source&type=webapp&source_id=acc2mqtt)

##Link

* [Librerie Javascript three.js usate per disegnare il cubo](https://threejs.org/)
* [Librerie Javascript per generare il QR-Code](https://github.com/kazuhikoarase/qrcode-generator/tree/master/js)
* [Filtro software per eliminare il rumore dell'accellerometro](https://stackoverflow.com/questions/24119672/android-low-pass-filter-and-high-pass-filter)
suggerito da Andrea. Devo ancora integrarlo.
@include='bio_sergio_tanzilli'

<!-- 
<pre>
RewriteRule ^([a-zA-Z0-9_-]+)$ /index.php?id=$1 [L,QSA]
</pre>
-->

The TanzoLab Project

Il TanzoLab è una iniziativa senza fini di lucro, nata da un'idea di Sergio Tanzilli socio fondatore di Acme Systems srl nel Novembre 2015, per trasferire ad appassionati di elettronica e informatica, professionisti e aziende nel settore, le conoscenze necessarie per poter creare prodotti embedded adatti per la produzione industriale.

Le attività del TanzoLab si svolgono ogni lunedi sera, salvo casi speciali, dalle ore 18:30 presso i locali della Acme Systems srl e consistono in:

  • Talk monotematici a cura di professionisti in vari settori tecnologici
  • Workshop pratici su elettronica embedded, produzione e informatica
  • Progettazione e realizzazione di nuovi prodotti embedded per l'IT

Le attività vengono coordinate tramite questo sito, in cui vengono pubblicati tutti i lavori svolti o in via di sviluppo, e tramite un gruppo Telegram con cui per interagire direttamente via chat con gli altri membri.