
Cet article fait suite à l’article précédent SARAH gagne quelques Neurones (1/2)
Eedomus 2.0
Pour interroger le capteur de luminosité j’ai mis à jour le plugin Eedomus en v2.0. Il est maintenant possible de lire ou modifier des périphériques de la box.
exports.action = function(data, callback, config, SARAH){
SARAH.call('eedomus', { 'periphId' : LUMENS}, function(options){
var lumens = options.json.last_value;
...
scenario(state, callback, SARAH);
});
}
La méthode SARAH.call est une version simplifiée de SARAH.run qui sera disponible en v2.9
Algorithmique
Le plugin scenario peut prendre 2 états: 1 Allumer et 0 Éteindre les lampes de la pièce.
var scenario= function(state, callback, SARAH){
var tts = '';
if (state == 1){
lights(BUREAU, true, SARAH);
lights(SALON, true, SARAH);
tts = 'Bonjour';
}
else {
lights(BUREAU, false, SARAH);
lights(SALON, false, SARAH);
tts = 'Aurevoir';
}
callback({'tts': tts});
}
Learn
Le plugin scenario peut être appelé avec un paramètre learn pour apprendre le comportement.
- Calendrier:
learn=false
- Mouvement:
learn=false
- Reconnaissance vocale:
learn=true
- QR Code:
learn=true
Subtilités
1. Les ordres d’éteindre sont toujours exécutés indépendamment de la luminosité:
- Je vais me coucher: c’est explicite on va pas négocier
- Je ne suis pas là: il faut faire des économies d’énergie
2. Le temps est très important ! On peut éteindre ou allumer pour des raisons de luminosité mais aussi d’heure de la journée.
set.push({'input': {l: lum/100, t: minutes() }, 'output': {s: state}});
Typiquement je vais me coucher, j’éteint explicitement, le réseau apprends mais ce n’est pas lié à la luminosité.
Code
Le code s’initialise avec un set de valeurs prédéterminées.
var brain = require('./lib/brain');
var set = [{'input': {l: 100/100, t: 0}, 'output': {s: 0}},
{'input': {l: 0/100, t: 0}, 'output': {s: 1}}];
var net = new brain.NeuralNetwork();
net.train(set);
La fonction compute() se charge d’améliorer le set et relancer l’apprentissage.
La librairie brain.js impose de refaire tout l’apprentissage. Cela pourrait poser des problèmes de perfs à terme.
var compute = function(learn, state, lum){
if (learn){
set.push({'input': {l: lum/100, t: minutes() }, 'output': {s: state}});
net.train(set);
return state;
}
// Guess only for switch 'on'. Not 'off'
if (state == 1){
return Math.round(net.run({l: lum/100, t: minutes() }).s);
}
return state;
}
La fonction minutes() retourne le nombre de minutes écoulées dans la journée.
Sauvegarde du réseau
Au moment de l’apprentissage il faut enregistrer l’ensemble des données:
if (learn){
fs.writeFileSync(file, JSON.stringify(set), 'utf8');
}
Au chargement du plugin il faut relire le réseau:
if (fs.existsSync(file)){
set = JSON.parse(fs.readFileSync(file,'utf8'));
}
net.train(set);
Conclusion
Lors d’un mouvement, l’algo détermine en fonction de l’heure et de la luminosité si il faut vraiment allumer les lampes.
| Action |
Apprendre ? |
Raisonner ? |
| Mouvement |
Non |
Oui |
| Plus de Mvt |
Non |
Non |
| Vocale On |
Oui |
Non |
| Vocale Off |
Oui |
Non |
Si SARAH allume alors que ce n’est pas nécessaire. Pour lui apprendre je dois éteindre explicitement.
Mais comme le remarque Giom, SARAH va apprendre qu’il faut éteindre pour (Luminosité + Lampe) alors qu’elle devrait apprendre de ne pas allumer pour (Luminosité)
Il faudra peut-être mémoriser l’état N-1 pendant X minutes. Le code est ici: http://jsfiddle.net/jpencausse/Ukj3t/