5. Ingredienti – 1 / 2
• Lampadine Philips Hue + bridge
• Un browser moderno (per quanto riguarda l’implementazione attuale)
• XMLHttpRequest
• CORS (due cucchiai)
• DocumentFragment
• MutationObserver
• localStorage
• jQuery*(dojo, altra libreria o solo querySelector e querySelectorAll)
* non strettamente indispensabile; ho scelto jQuery per il gioco di parole e per la notorietà, ma in ogni
caso non è una dipendenza
5
9. Selezione elementi DOM
• Utilizzando dei selettori CSS è immediato ottenere gli elementi corrispondenti:
per esempio
jQuery(‘.light’);
restituisce tutti gli elementi con classe “light”.
jQuery però ha un secondo parametro facoltativo, a che cosa serve?
http://api.jquery.com/jQuery/
9
10. Contesto
• Il secondo parametro è un “contesto”, un nodo o un oggetto dal quale far partire il
selettore
Dato il frammento:
<div class=“light”></div>
<div id=“context”>
<div class=“light”></div>
<div class=“light”></div>
</div>
…
var context = document.getElementById(‘context’);
jQuery(‘.light’, context);
selezionerà solo i due div contenuti in context
10
11. HOME (Home Object ModEl)
home
kitchen
light light
room
room
home
kitchen
light light
room
room
11
12. L’idea
• Se fosse possibile rappresentare la propria casa con come un nodo DOM, potremmo
scrivere:
…
var jHuery = (function(){
var homNode = hom.getRootNode();
return function(selector){
return jQuery(selector, homNode);
};
})();
...
partial application
12
13. Risultato desiderato
// accende tutte le luci della cucina
jHuery(‘kitchen light’).attr(‘on’, ‘true’);
è possibile?
Notare, non ho usato classi ma nomi di tag
13
14. Philips Hue
• Sono lampadine led RGB colorate wireless
comandabili
• Il bridge è da collegare al router di casa con un
cavo di rete: invia e riceve informazioni verso e
dalle lampadine
• Sul bridge gira un web server** che espone
delle uri REST per l’esecuzione dei comandi da
un qualsiasi client, anche da un browser
(documentazione su
http://developers.meethue.com )
** ma avevi detto “niente server”!
intendevo che non l’avremmo sviluppato noi :P
14
15. Spazio CIE
Le lampadine Hue non usano RGB per definire il
proprio colore; è possibile utilizzare le due
coordinate x, y per arrivare ai colori del diagramma
a destra.
E’ possibile convertire in modo più o meno
(in)esatto una terna RGB in CIE (x, y).
15
16. Hue + saturation
Un altro modo possibile per assegnare un colore è dato dalla coppia
• hue: 16 bit: 0 e 65535 sono rosso, 25500 è verde, 46920 è blu
• saturation: 8 bit: 254 è colorato, 0 è meno saturo, toni di grigio
Nota: è possibile assegnare un colore in css usando la forma hsl(Hue, Saturation, Lightness), o hsla, aggiungendo
il canale alpha. In questa forma Hue varia da 0 a 360, poiché è un angolo; s ed l sono percentuali
16
17. Ingredienti – AJAX e CORS (Cross-origin
Resource Sharing
• Come faccio a inviare i miei comandi?
• Via AJAX! Non ci sono problemi di sicurezza X-origin, visto che
il bridge espone l’header
Access-Control-Allow-Origin: *
per accendere la lampadina numero 1 occorre mandare all’indirizzo:
http://indirizzoBridge/apikey/lights/1/state
questo pacchetto in PUT:
{
“on”: true
}
17
18. Ingredienti – CORS, secondo cucchiaio
• Come trovare l’indirizzo del bridge nella rete locale?
• via U-PnP (ma non è il nostro caso)
• Con una GET a questo indirizzo:
https://www.meethue.com/api/nupnp
Ovviamente il server risponde con le intestazioni CORS e con un pacchetto del tipo
[{"id":"iddelbridge","internalipaddress":"192.168.0.5"}]
A questo punto occorre registrare la propria applicazione con una chiamata POST nei
30 secondi successivi alla pressione del pulsante sul bridge da parte dell’utente, per
motivi di sicurezza
18
19. DocumentFragment
• Un DocumentFragment è un nodo document non collegato a ciò che viene
renderizzato nel browser. E’ il candidato ideale per svolgere operazioni “dietro le
quinte” utilizzando dei nodi che non devono essere mostrati.
Una volta che sia stata letta la lista delle lampadine disponibili, sarà possibile quindi
creare dei div (o un elemento a piacere) con almeno la classe “light”, oppure
addirittura un element <light>, visto che DocumentFragment può contenere XML*** e
che i selettori funzionano lo stesso, quindi:
var light = document.createElement('light');
è perfettamente lecito.
Prima di appendere al DF, si possono aggiungere vari attributi – tra cui l’id - al nodo, in
modo da facilitare i selettori
19
*** XML is crap. Really. There are no excuses. XML is nasty to parse for humans, and it's a disaster to parse even for
computers. There's just no reason for that horrible crap to exist - Torvalds, Linus (2014-03-06)
20. MutationObserver
Per modificare lo stato di una o più lampadine contemporaneamente è sufficiente
modificare gli attributi corrispondenti sull’insieme di nodi selezionato.
Come fare a intercettare i cambiamenti di attributo?
L’API MutationObserver consente di monitorare i cambiamenti di struttura di un nodo
target, attributi compresi.
new MutationObserver(function(mutations){…});
La funzione di callback viene invocata come un gestore d’eventi ogni volta che sul nodo
target avviene una delle mutazioni monitorate.
Il medesimo observer può essere applicato a più nodi; l’array mutations può essere
iterato ottenendo per ogni elemento l’elemento su cui è stato applicato
20
21. localStorage
Non è strettamente necessario per il funzionamento, ma è un buon posto in cui salvare
i dati relativi al bridge per non doverli richiedere ogni volta (in particolare la chiave
relativa all’applicazione)
Ovviamente occorre fidarsi del sito ospitante
21
22. Resta da fare
• Scrivere un polyfill per MutationObserver (usando MutationEvent)
• Estendere il concetto a oggetti diversi dalle lampadine
• Estensione CSSOM?
• Bookmarklet per youtube o altri siti?
• Generare gli eventi per i cambiamenti di stato delle lampade
• Permettere la modifica di più attributi contemporaneamente
• Permettere la modifica a più lampade contemporaneamente (barando)
• Usare un browser headless (phantomjs) per il caso generale
• Test! Test! Test!
22
Hinweis der Redaktion
…ho avuto qualche problema con la tastiera svizzera :-)
breve carrellata di ciascun elemento, a braccio andrà bene; hue starter kit, 180 euro
Demo a mano QUI
Due chiacchiere qui ce le posso anche spendere, no?
certo, altrimenti non sarei qui a raccontarla :-)
Ah, hai mentito, avevi detto senza web server? Io intendevo che non lo avremmo dovuto implementare ;-)
International Commission on Illumination; raccontare da dove ho rubato la matrice dei pesi. Per fortuna la libreria per il calcolo matriciale l’avevo già scritta anni fa!
Qui potrebbe già starci una prova :-)
Ovviamente non è finita qui, se l’utente dà il permesso, si deve registrare l’applicazione al bridge
Parlare della peculiarità del DocumentFragment, se serve
Event, initEvent e dispatchEvent; initEvent necessario su IE, che non supporta il costruttore Event ma usa document.createEvent