Problème Serial + Socket.io

Ce sujet est résolu
Default
,

Bonjour,

J'ai un soucis avec nodejs.
Mon but est de créer un système d'alarme. Pour le moment je detecte comme il faut la presence d'un mouvement et l'arret de detection de celui ci pour tout mes capteurs (une arduino qui envoie un message par le port série: 1/1 par exemple pour dire il y a du monde dans le couloir).


Voici mon code:

var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var housePlan = [{"roomNumber" : 0, "roomName" : "garage", "roomDetection":1, "roomIsDetected":0}, { "roomNumber" : 1, "roomName" : "couloir", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 2, "roomName" : "cuisine", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 3, "roomName" : "salon", "roomDetection": 1, "roomIsDetected": 0 }]

app.use('/', express.static('./webapp'));

http.listen(3000, function () {
    console.log('serveur socket.io lancé sur le port *:3000');
});

getRoom = function (number) {
    for (var i = 0; i < housePlan.length; i++) {
        if (parseInt(housePlan[i].roomNumber) == number) {
            return housePlan[i];
        }
    }
    return "Introuvé";
};

getRoomName = function (number) {
    return getRoom(number).roomName;
};

mouvementIn = function (number) {

};



io.on('connection', function (socket) {
    console.log("Connection");
    socket.emit("receivePlan", housePlan); 
});



var sp = new SerialPort("COM5", {
    parser: serialport.parsers.readline("\n"),
    baudrate: 9600
});

sp.on("open", function () {
    console.log('open');
    sp.on('data', function (data) {
        dataSplit = data.split("/");
        if (parseInt(dataSplit[0]) == 0) {
            console.log("Mouvement repéré dans: ");
            console.log(getRoomName(parseInt(dataSplit[1])));
        } else {
            console.log("Fin du mouvement dans: ");
            console.log(getRoomName(parseInt(dataSplit[1])));
        }
    });
});

J'étais assez content que tout fonctionne et je pensais qu'il ne me restais plus qu'a faire un belle appli angular utilisant Socket.io pour communiquer avec le serveur.
J'ai commencé et je me suis rendu compte que dès qu'une connection socket opère il oublie complètement ma belle connection Série... Du coup plus de communication avec mon arduino et mes capteurs...



Si vous pouviez m'aider ce serait juste génial!!! Je crois que je n'y arriverais pas sans un petit coup de pouce ou au moins une explication de ce qu'il se passe car c'est quand même assez bizarre pour moi ... Je croyais que les choses étaient asynchrone...

Merci 1000 fois d'avance!!

12 Réponse

29456
,

Ok ok, après je sais pas si c'est vraiment le bon choix pour un système d'alarme...
Par exemple si tu n'es pas connecté sur ta vue tu n'auras aucune information de ton système...
Le mieux c'est que faire une architecture comme celle-ci :

Arduino : capteur/acquisition des données ----- Serial ----> Serveur : Stockage des données dans une base de données (MySql) + jouer un son lorsqu'on détecte du mouvement (lib de son avec NodeJs) + API Rest ----------- Données --------> Web App (AngularJs)

Après si tu veux te Temps réel entre ta vue et ton serveur, rien ne t'empèche de synchro les deux avec un web socket.

Sinon, j'ai travaillé sur un projet de domotique, si ça peut t'intéresser tout est là : Open Home Automation
Le daemon Temps réel est en Python, l'API Rest c'est du Symfony 2 et la web App c'est des backboneJS mais tu peux t'inspirer de l'architecture.

Bon courage et n'hésite pas si tu as un soucis à demander ;)

Librairie du son avec NodeJs :

29456
,

Bonjour, pourrais-tu donner le code embarqué sur l'Arduino stp ?

Default
,

Sans aucun soucis :)

/*
 * PIR sensor tester
 */

int inputPin[5] = {2,3,4,5,6};               // choose the input pin (for PIR sensor)
int pirState[5] = {LOW, LOW, LOW, LOW, LOW};             // we start, assuming no motion detected
int val[5] = {0,0,0,0,0};                    // variable for reading the pin status


void setup() {
  for(int i; i < 5; i++){
    pinMode(inputPin[i], INPUT);     // declare sensor as input
  }
  Serial.begin(9600);
}

void loop(){
  for (int i = 0; i < 5; i++){
      val[i] = digitalRead(inputPin[i]);  // read input value
      if (val[i] == HIGH) {            // check if the input is HIGH
        if (pirState[i] == LOW) {
          // we have just turned on
          Serial.print("1");
          Serial.print("/");
          Serial.print(i);
          Serial.println();
          pirState[i] = HIGH;
        }
      } else {
        if (pirState[i] == HIGH){
          // we have just turned of
          Serial.print("0");
          Serial.print("/");
          Serial.print(i);
          Serial.println();
          // We only want to print on the output change, not state
          pirState[i] = LOW;
        }
      }
      delay(10);
  }
}

c'est vraiment du code très "bidon" mais ça marhce en tous cas sur le moniteur serie et même en nodejs avant que je n'utilise Socket.io

au cas où le code angular.js:

angular.module('alarme', [])
  .controller('alarmeController', function ($scope, filterFilter) {
    var socket = io.connect();

    socket.on("receivePlan", function (plan) {
        $scope.housePlan = plan;
        $scope.$digest();
    });
});
29456
,

Re-,
ok merci ;) pour le code NodeJs, aucun moyen que ça fonctionne ^^ tu ne renvois jamais les datas sur la socket !

essaye ça sur ton serveur :

var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var housePlan = [{"roomNumber" : 0, "roomName" : "garage", "roomDetection":1, "roomIsDetected":0}, { "roomNumber" : 1, "roomName" : "couloir", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 2, "roomName" : "cuisine", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 3, "roomName" : "salon", "roomDetection": 1, "roomIsDetected": 0 }]
var sp = new SerialPort("COM5", {
    parser: serialport.parsers.readline("\n"),
    baudrate: 9600
});

app.use('/', express.static('./webapp'));

http.listen(3000, function () {
    console.log('serveur socket.io lancé sur le port *:3000');
});



// new connection on the socket !
io.on('connection', function (socket) {
    console.log("Connection");
    // send houseplan
    socket.emit("receivePlan", housePlan); 

    // listen on serial
    sp.on("open", function () {
    console.log('open');
    // listen on data
    sp.on('data', function (data) {
        dataSplit = data.split("/");
        if (parseInt(dataSplit[0]) == 0) {
            console.log("Mouvement repéré dans: ");
            console.log(getRoomName(parseInt(dataSplit[1])));
            socket.emit('newMvt', "Mouvement repéré dans: "+getRoomName(parseInt(dataSplit[1])));
        } else {
            console.log("Fin du mouvement dans: ");
            console.log(getRoomName(parseInt(dataSplit[1])));
            socket.emit('endMvt', "Fin du mouvement dans: "+getRoomName(parseInt(dataSplit[1])));
        }
    });
});


});


// functions
getRoom = function (number) {
    for (var i = 0; i < housePlan.length; i++) {
        if (parseInt(housePlan[i].roomNumber) == number) {
            return housePlan[i];
        }
    }
    return "Introuvé";
};

getRoomName = function (number) {
    return getRoom(number).roomName;
};

mouvementIn = function (number) {

};



Et sur Angular :

angular.module('alarme', [])
  .controller('alarmeController', function ($scope, filterFilter) {
    var socket = io.connect();

    socket.on("receivePlan", function (plan) {
        $scope.housePlan = plan;
        $scope.$digest();
    });

    socket.on("newMvt", function (data) {
        $scope.newMvt = data;
        $scope.$digest();
    });

    socket.on("endMvt", function (data) {
        $scope.endMvt = data;
        $scope.$digest();
    });

});

à adapter pour ton besoin !

29456
,

Hummm, si tu utilises cette lib pour le Serial : https://github.com/voodootikigod/node-serialport
Le code pour le serveur sera plutôt ça :

var serialport = require("serialport"); // https://github.com/voodootikigod/node-serialport
var SerialPort = serialport.SerialPort;

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var housePlan = [{"roomNumber" : 0, "roomName" : "garage", "roomDetection":1, "roomIsDetected":0}, { "roomNumber" : 1, "roomName" : "couloir", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 2, "roomName" : "cuisine", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 3, "roomName" : "salon", "roomDetection": 1, "roomIsDetected": 0 }]
var sp = new SerialPort("COM5", {
    parser: serialport.parsers.readline("\n"),
    baudrate: 9600
});

app.use('/', express.static('./webapp'));

http.listen(3000, function () {
    console.log('serveur socket.io lancé sur le port *:3000');
});



// new connection on the socket !
io.on('connection', function (socket) {
    console.log("Connection");
    // send houseplan
    socket.emit("receivePlan", housePlan); 

    // If serial is open
    if(sp.isOpen()) {
        console.log('Serial open');
        // listen on data
        sp.on('data', function (data) {
            dataSplit = data.split("/");
            if (parseInt(dataSplit[0]) == 0) {
                console.log("Mouvement repéré dans: ");
                console.log(getRoomName(parseInt(dataSplit[1])));
                socket.emit('newMvt', "Mouvement repéré dans: "+getRoomName(parseInt(dataSplit[1])));
            } else {
                console.log("Fin du mouvement dans: ");
                console.log(getRoomName(parseInt(dataSplit[1])));
                socket.emit('endMvt', "Fin du mouvement dans: "+getRoomName(parseInt(dataSplit[1])));
            }
        });
    }


});


// functions
getRoom = function (number) {
    for (var i = 0; i < housePlan.length; i++) {
        if (parseInt(housePlan[i].roomNumber) == number) {
            return housePlan[i];
        }
    }
    return "Introuvé";
};

getRoomName = function (number) {
    return getRoom(number).roomName;
};

mouvementIn = function (number) {

};
Default
,

Merci beaucoup pour ton aide :)
Oui je sais pour les data j'étais en train de le faire quand je me suis rendu compte du soucis en amont (dans la fonction mouvementIn j'allais faire en sorte de changer la valeur isDetected de la pièce et de renvoyer l'objet homePlan et que angular me gère le truc comme un grand :) ) .

Alors j'ai testé ce que tu m'as envoyé ça me marche malheureusement pas :/

Et j'aurais peut être un autre soucis à l'avenir car quand je detecterais un mouvement à l'avenir j'aimerais egalement déclencher une siren mais pas que quand il y a une connection au socket

Du coup faut que je je change de librairie pour la communication série ?

Faut que je m'interesse a une sorte de multithreading (je sais même pas si ça existe j'ai entendu worker quelque part... Mais bon ^^ )

Fin bref j'espère reussir mon projet ! :) ( si je reussis j'aurais econnomiser pas mal en alarme :p )

Default
,

J'ai trouver ça: http://www.codeproject.com/Articles/389676/Arduino-and-the-Web-using-NodeJS-and-SerialPort
je remarque qu'il utilise serialport2 au lieu de serialport

Dès que j'arrive à l'installer (oui j'utilise visual studio comme ide c'est pratique ... quand ça marche... ) je vous tiens au courant ! :)

Default
,

Oui mais l'idée justement c'est que lorsque je ne suis pas sur le socket ça se déclenche quand même :)
Quand je suis sur le socket à la fois ça se déclenche à la fois j'ai du son à la fois j'ai l'image :) et puis je trouvais ma façon de faire plus simple (mais visiblement trop pour que ça marche ^^ )

Merci beaucoup pour tes infos :-)

Je vais regarder ton projet ça à l'air interessant d'autant plus que j'hesitais à developper le miens en python mais je trouve nodejs avec socket.io tellement puissant et je connais mieux (oui c'est déjà pas terrible alors :p ) javacript que python :)

Pour le son merci pour ces liens ça risque de m'être très utile! :)

Default
,

Ok donc la solution c'était:

var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var housePlan = [{ "roomNumber" : 0, "roomName" : "garage", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 1, "roomName" : "couloir", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 2, "roomName" : "cuisine", "roomDetection": 1, "roomIsDetected": 0 }, { "roomNumber" : 3, "roomName" : "salon", "roomDetection": 1, "roomIsDetected": 0 }]

app.use('/', express.static('./webapp'));

http.listen(3000, function () {
    console.log('serveur socket.io lancé sur le port *:3000');
});

getRoom = function (number) {
    for (var i = 0; i < housePlan.length; i++) {
        if (parseInt(housePlan[i].roomNumber) == number) {
            return housePlan[i];
        }
    }
    return "Introuvé";
};

getRoomName = function (number) {
    return getRoom(number).roomName;
};

mouvementIn = function (number) {

};






var sp = new SerialPort("COM5", {
    parser: serialport.parsers.readline("\n"),
    baudrate: 9600
});

sp.on("open", function () {
    io.on('connection', function (socket) {
        console.log("Connection");
        socket.emit("receivePlan", housePlan);
    });

    console.log('open');
    sp.on('data', function (data) {
        dataSplit = data.split("/");
        if (parseInt(dataSplit[0]) == 0) {
            console.log("Mouvement repéré dans: ");
            console.log(getRoomName(parseInt(dataSplit[1])));
        } else {
            console.log("Fin du mouvement dans: ");
            console.log(getRoomName(parseInt(dataSplit[1])));
        }
    });
});

en faisant comme ça la tout ça marche c'était suptile :)

j'ai en effet juste eu à mettre le code des socket à l'interieur de la callback sp.on :)

Default
,

J'ai un gros soucis encore !
si tu pouvais m'aider vu que tu t'y connais en arduino ... : /

va savoir pourquoi cet aprem j'avais l'impression que ça marchait tout bien comme il faut.. Mais la maintenant que j'ai regler les autres soucis ben plus rien marche ça m'envoie eteind/fermé en boucle ^^'

J'utilise ça comme capteur: http://wiki.t-o-f.info/Arduino/CapteurPIRDeMouvement

donc ma question serait: est-ce que mon code est tellement à chier que ça marche pas (mais alors pourquoi ça aurait marcher cet aprem?..)
ou c'est les capteurs eux même qui sont à chier (chose possible après tout vu la qualité de fabrication ^^' ) ?

Si tu pouvais me donner un dernier coup de pouce ce serait super ! :)

29456
,

Salut,
vérifie bien tous tes branchements, que tu as bien une masse commune. Si ça fonctionnait dans l'aprem c'est bizarre que ça ne fonctionne plus si tu n'as pas changé le code embarqué.
Sinon test de façon isolé, tu ouvres la console Serial de l'IDE Arduino et tu vois ce que ton système de renvoit. Si ça ne fonctionne toujours pas c'est ton système (soit hardware, soit software) si ça fonctionne comme voulu, c'est ton code NodeJs qui merde.
Après à voir, peut être qu'il faut filtrer les entrées ou mettre une capacité de découplage...

Tiens moi au courant.

29456
,

Je viens de voir ça,
"Ce capteur nécessite au moins 20 secondes de calibration automatique au démarrage. Durant ces 20 secondes, il est complètement inactif et ne doit pas être obstrué par des sources de chaleurs (main, corps, chat, etc). "

Je pense que tu devrais rajouter un delay de 20 secondes dans la phase d'init pour être sûr que les capteurs sont bien init.