Choquet Mathieu Masson Jérôme Groupe 6 Domotique p.1
SOMMAIRE : Introduction...... I/ Envoi de SMS...... II/ Architecture...... III/ Serveur...... IV/ Détection de mouvement...... V/ Problème rencontré...... V/ Organisation du travail...... ANNEXES...... p.3 p.3 p.4 p.4 p.5 p.5 P;5 p.6 p.2
Ce projet a pour but de proposer dans un premier temps un service de sécurité pour les maisons. Par la suite il pourra s'étendre à un contrôle global des différents éléments d'une maison ( Télévision, stores électriques, lumière, etc...). Nous nous limitons pour cette année à la réalisation d'un serveur domotique offrant des services de sécurité. Une webcam tournera chez le client. En cas de détection d'intrusion (de mouvement ici), une alerte sera générée et traitée afin d'informer le client. Le client, ainsi alerté, pourra se connecter sur notre site afin de voir en temps réel ce qui se déroule chez lui. Il peut également à tout moment se connecter et observer ce qui se déroule chez lui. I/Envoi de SMS : Nous avons étudier trois techniques d'envoi de SMS résumé ici dans le tableau suivant. Technique Avantages Inconvénients Site spécialisé Pas de surcoût matériel Dépendance vis à vis du site proposant le service Délai entre l'envoi et la réception trop aléatoire Carte D41E Indépendance Prix relativement très élevé à l'achat (court terme) Modem + carte sim Indépendance Crédit de la carte sim à long terme Pour des raisons de coûts et de simplicité, nous retenons la première technique. En effet, les sites spécialisés offrent des tarifs avantageux. De plus, pour envoyer un sms, il leur suffit de recevoir un e mail ce qui est facile à implémenter en java. II/ Architecture : Voici résumé dans un tableau les deux architectures possibles. p.3
Architecture Avantages Inconvénients Serveur /Client Client Maintenance facile puisque site unique Si un client plante, le système reste opérationnel pour les autres En cas de crash du serveur, tout le système tombe Déplacement obligatoire pour chaque maintenance Coût matériel multiplié par chaque client supplémentaire Par Client, nous entendons le fait qu'il n'y ai pas de serveur central et que chaque client et indépendant des autres en tout point de vue. Pour des raisons de commodités (maintenance...), nous retenons la première architecture et implémenterons donc un serveur central qui comportera une application JAVA qui s'occupera de récupérer les alertes générés par les clients, d'envoyer un e mail pour déclencher l'envoi de sms. Le client quand à lui, ne s'occupera que de la détection de mouvement et, le cas échéant, de l'envoi d'une alerte au serveur. III/ Serveur : Le serveur principal sera donc accessible par le client à partir d'un site web, qui aura pour tâches l'authentification d'un client, la gestion de ses installations ainsi que la liaison entre le client et celles ci. Ce site comportera une base de données pour la création d'un lien entre le client et ses modules, la gestion de double l'authentification (Login+Pass et SSL pour la connexion entre le site et le serveur) d'un client pour éviter un piratage du serveur. Voici les tables qui seront dans notre bases de données : Table client Table house Table LM Id Nom Prénom Tél Mobile Mail Pass ( cryptage md5) Id Id_client Rue Code Postal Ville Nb_Module @IP Id_house Id_module @IP_MOD A terme, l'application devra être supportée sur le serveur web central sans besoin de redirection pour une plus grande sécurité ( serveur de secours au cas où ). Pour se faire, il y aura nécessité de trouver la technologie la mieux adaptée ( J2SE à priori ). p.4
IV/ Détection de mouvement : Cahier des Charges du Projet Domotique Il y a plusieurs techniques afin de détecter un mouvement mais le principe de base reste le même c a d des images sont prises à intervalles réguliers puis comparer entre elles. En C, on peut utiliser des vecteurs. Cependant ayant choisi le Java comme langage de programmation, nous sommes obligés de traiter par pixels. Après nous pouvons faire les moyennes de chaque couleur ( rouge, vert et bleu) et les comparer. Ou, comme nous l'avons choisi, comparer chaque pixel (x,y) avec son équivalent dans l'image suivante selon leur caractéristique ARGB. Il faut définir jusqu'à quel pourcentage un pixel peut «changer». Ceci est important car deux images consécutives ne sont jamais à 100% égales ne serait ce que par la variation de luminosité ( nuage qui passe devant le soleil par exemple). Enfin il faut définir le pourcentage général c a d le nombre de pixel à partir duquel nous pouvons considérer qu'il y a eu mouvement. Il est inutile de tout lancer pour un seul pixel qui change. V/ Problèmes rencontrés : Le principal problème rencontré se porte sur la détection de mouvement. En effet, il faut avoir une webcam de très bonne qualité car sinon entre deux prises successives, la différence est trop marquée et du coup est détectée comme un mouvement et une alerte est générée pour rien. Ensuite pour des raisons de temps, nous n'avons pas pu faire exactment le projet comme nous le voulions c a d avec une interface web et une gestion de base de données. Un autre problème rencontré qui, s'il n'est pas apparu clairement lors du développement et des tests sur la même machine, concerne l'envoi d'e mail. En effet, pour cela il faut disposer d'un serveur smtp accessible. En général le seul accessible est celuidu fournisseur d'accès mais il n'est accessible que depuis l'endroit où l'abonnement est pris c a d non accessible d'un autre réseau (Renater par exemple). Quand aux «accessibles», ils sont qualifiés de «relais ouverts» et sont en général blacklisté car utilisés par les spammeurs. Il est donc très important de connaître le FAI afin de pouvoir activer l'envoi de mail. V/ Organisation du travail: Choquet Mathieu s'est occupé de la partie Java comprenant la détection de mouvement et l'envoi d'e mail. Masson Jérôme s'est occupé de la partie site Internet comprenant l'interface web et la gestion de la base de donnée. p.5
Voici le code source du client : Cahier des Charges du Projet Domotique ANNEXES / Client Domotique Version finale Choquet Mathieu Masson Jérôme M2 RTM / import java.io.; import java.net.; import java.awt.graphics2d; import java.awt.image; import java.awt.image.; import javax.media.buffer; import javax.media.capturedeviceinfo; import javax.media.capturedevicemanager; import javax.media.manager; import javax.media.medialocator; import javax.media.nodatasourceexception; import javax.media.noplayerexception; import javax.media.noprocessorexception; import javax.media.player; import javax.media.control.framegrabbingcontrol; import javax.media.format.videoformat; import javax.media.protocol.datasource; import javax.media.util.buffertoimage; import javax.swing.imageicon; import com.sun.image.codec.jpeg.jpegcodec; import com.sun.image.codec.jpeg.jpegencodeparam; import com.sun.image.codec.jpeg.jpegimageencoder; public class Client extends Thread p.6
//Fonction permettant d'enregistrer les captures d'images de la webcam en JPEG public static void savejpg(image img, String s) BufferedImage bi = new BufferedImage(img.getWidth(null), img.getheight(null), BufferedImage.TYPE_INT_RGB); Graphics2D g2 = bi.creategraphics(); g2.drawimage(img, null, null); FileOutputStream out = null; try out = new FileOutputStream(s); catch (java.io.filenotfoundexception io) // création du fichier automatiquement si inexistant // encodeur JPEG JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); // paramètres d'encodage JPEGEncodeParam param = encoder.getdefaultjpegencodeparam(bi); param.setquality(0.5f, false); // assignation des paramètres d'encodage encoder.setjpegencodeparam(param); try // encodage de l'image encoder.encode(bi); out.close(); catch (java.io.ioexception io) System.out.println("IOException"); public static void main(string[] args) throws IOException p.7
String addr = "127.0.0.1"; Socket soc = null; PrintWriter out = null; BufferedReader in = null; String rec, mess; Image img1 = null,img2 = null; ImageIcon imgicon1 = null, imgicon2 = null; Buffer buf; FrameGrabbingControl fgc = null; BufferToImage btoi; BufferedImage bi1 = null, bi2 = null; int w = 0, h = 0, rgb1 = 0, rgb2 = 0, compteur = 0, total = 0, num = 2, blo = 0; float alpha1 = 0, rouge1 = 0, vert1 = 0, bleu1 = 0; float alpha2 = 0, rouge2 = 0, vert2 = 0, bleu2 = 0; try soc = new Socket (addr, 55333); out = new PrintWriter(soc.getOutputStream(),true); in = new BufferedReader (new InputStreamReader(soc.getInputStream())); catch(exception ex) ex.printstacktrace(); BufferedReader clavier = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Veuillez entrer votre nom"); rec = clavier.readline(); out.println(rec); mess = in.readline(); p.8
System.out.println(mess); // récupération d'un périphérique à partir de son nom CaptureDeviceInfo capturedevice = CaptureDeviceManager.getDevice("vfw:Microsoft WDM Image Capture (Win32):0"); // récupération du MediaLocator lié au périphérique de capture MediaLocator medialocator = capturedevice.getlocator(); try // récupération d'une datasource à partir d'un MediaLocator DataSource ds = Manager.createDataSource(mediaLocator); // connexion sur la DataSource ds.connect(); // connexion d'un player sur la datasource Player player = Manager.createPlayer(ds); // préparation du player et du périphérique player.realize(); // démarrage de la lecture player.start(); // attend 2 secondes try Thread.sleep(2000); catch (InterruptedException e) e.printstacktrace(); // récupère un contrôle sur le flux fgc = (FrameGrabbingControl) player.getcontrol("javax.media.control.framegrabbingcontrol"); // récupère un Buffer contenant l'image demandée p.9
buf = fgc.grabframe(); // convertion du buffer en image (via BufferToImage) btoi = new BufferToImage((VideoFormat) buf.getformat()); // création de l'image et sauvegarde img1 = btoi.createimage(buf); imgicon1 = new ImageIcon(img1); bi1 = (BufferedImage)img1; System.out.println("Premiere image prise"); catch (NoDataSourceException e) e.printstacktrace(); catch (IOException e) e.printstacktrace(); catch (NoProcessorException e) e.printstacktrace(); catch (NoPlayerException e) e.printstacktrace(); while(mess.compareto("fin")!=0) // attend 1 minute entre chaque capture try Thread.sleep(10000); catch (InterruptedException e) p.10
e.printstacktrace(); // récupère un Buffer contenant l'image demandée buf = fgc.grabframe(); // convertion du buffer en image (via BufferToImage) btoi = new BufferToImage((VideoFormat) buf.getformat()); // création de l'image 2 et sauvegarde dans un fichier img2 = btoi.createimage(buf); imgicon2 = new ImageIcon(img2); bi2 = (BufferedImage)img2; System.out.println("Image "+num+" prise"); //comparaison //Récupération de la taille de l'image w = imgicon1.geticonwidth(); h = imgicon1.geticonheight(); //Récupération du nombre de pixels total total = w h; l'image 1 //Double boucle permettant de parcourir tous les pixels des images for(int i = 0 ; i < w ; i++) for(int j = 0 ; j < h ; j++) //Récupération des paramètres ARGB du pixel (i,j) de rgb1 = bi1.getrgb(i,j); alpha1 = ((rgb1 >>24 ) & 0xFF); rouge1 = ((rgb1 >>16 ) & 0xFF); vert1 = ((rgb1 >>8 ) & 0xFF); bleu1 = (rgb1 & 0xFF); //Récupération des paramètres ARGB du pixel (i,j) de l'image 2 rgb2 = bi2.getrgb(i,j); alpha2 = ((rgb2 >>24 ) & 0xFF); rouge2 = ((rgb2 >>16 ) & 0xFF); vert2 = ((rgb2 >>8 ) & 0xFF); bleu2 = (rgb2 & 0xFF); p.11
//Comparaison sur les paramètres de luminance, de rouge, de vert et de bleu //Ici variation tolérée à 80% de différence if( alpha2 < (alpha1 (alpha1 (float)0.8)) alpha2 > (alpha1 + (alpha1 (float)0.8)) rouge2 < (rouge1 (rouge1 (float)0.8)) rouge2 > (rouge1 + (rouge1 (float)0.8)) vert2 < (vert1 (vert1 (float)0.8)) vert2 > (vert1 + (vert1 (float)0.8)) bleu2 < (bleu1 (bleu1 (float)0.8)) bleu2 > (bleu1 + (bleu1 (float)0.8))) //Si il y a une variation de plus de 50%, incrémentation du compteur de pixels différents compteur++; alerte vers le serveur //Si le nombre de pixels différents est de plus de 50 % génération d'une if( compteur > (total 0.5) && blo == 0) savejpg(img2, "img"+num+".jpg"); System.out.println("Une intrusion a ete detectee "); out.println("alerte"); blo = 1; if(compteur < (total 0.5) && blo == 1) blo = 0; img1 = img2; imgicon1 = imgicon2; bi1 = bi2; compteur = 0; num++; soc.close(); Le code source du serveur : / p.12
Serveur Domotique Version finale Choquet Mathieu Masson Jérôme M2 RTM / import java.io.; import java.net.; public class Serveur extends Thread //initialisation d'une ServerSocket et acceptation de connexion entrante static Socket socketservice=null; public Serveur(Socket sock) this.socketservice=sock; public static void main(string args []) ServerSocket socketecoute; System.out.println("Bienvenu sur le serveur de Domotique"); System.out.println("En attente de connexion entrante"); try socketecoute=new ServerSocket(55333); while(true) socketservice=socketecoute.accept(); Serveur SE=new Serveur(socketService); //Lancement du multithread p.13
Cahier des Charges du Projet Domotique SE.start(); //gestion des erreurs catch(exception ex) ex.printstacktrace(); //menu d'exécution du multithread public void run() System.out.println("Nouvelle connexion: " +socketservice); InetAddress ip = socketservice.getinetaddress(); try //Initialisation de variables servant à la com entre le serveur et le client BufferedReader in = new BufferedReader (new InputStreamReader(socketService.getInputStream())); PrintWriter out = new PrintWriter(socketService.getOutputStream(),true); String input; input = in.readline(); System.out.println(input + " vient de se connecter"); out.println("ack"); //Condition de validité de la communication while(input.compareto("fin")!=0) //Le serveur est en attente du client input = in.readline(); p.14
//Si ALERTE est remontée par le client if(input.compareto("alerte") == 0) out.println("une intrusion a ete detectee "); smtp d'orange //TRES IMPORTANT //Faire attention à l'adresse du serveur SMTP //Ici ayant Orange pour FAI l'adresse est donc celui du serveur //Ne fonctionne que si votre FAI est Orange //Connexion au serveur smtp d'orange et envoi d'un mail Socket sock = new Socket("smtp.orange.fr",25); MailIo.sendMail(sock,"goula","mgoulamass@hotmail.com","Projetjava@hotmail.com","Intrusion"," Une intrusion a ete detectee"); //Fin de la com et fermeture de la socket out.println("fin"); socketservice.close(); //gestion des erreurs catch(exception ex) ex.printstacktrace(); Et enfin le code source de l'envoi d'e mail : / Envoi d'e mail Version finale Choquet Mathieu p.15
Masson Jérôme M2 RTM / import java.io.; import java.net.socket; import java.util.date; import java.util.stringtokenizer; public class MailIo public MailIo() public static boolean sendmail(socket sock, String localhost,string Destinataire, String from, String subject, String message) throws IOException //connection à la socket passée en paramètre out = new PrintWriter(sock.getOutputStream()); in = new BufferedReader(new InputStreamReader(sock.getInputStream())); //Vérification de la connection receive(); //on envoie la premiere ligne qui indique de qui elle provient send("helo " + localhost); //Accusé de réception receive(); //on envoie l'adresse de l'expediteur send("mail FROM: <" + from + ">"); //Accusé de réception receive(); //on envoie l'adresse du destinataire send("rcpt TO: <" + Destinataire + ">"); p.16
//Accusé de réception receive(); Cahier des Charges du Projet Domotique //On annonce que l'on va envoyer des données send("data"); //Accusé de réception receive(); //on remplit les différents champs send("subject: " + subject); send("date: " + new Date()); send("reply To:" + from); send("to: " + Destinataire); //on envoi chaque ligne séparément en utilisant \n comme délimitateur StringTokenizer tokenizer = new StringTokenizer(message, "\n"); //la ligne ci dessous se traduit par : tant qu'il y a encore des ligne, on envoi while (tokenizer.hasmoretokens()) send(tokenizer.nexttoken()); //pour finir l'envoi d'un mail il faut envoyer sur une ligne un seul point send("."); //Accusé de réception receive(); //on quitte send("quit"); //Accusé de réception receive(); //on ferme les flux in.close(); out.close(); sock.close(); return true; //methode qui recoit les information du serveur private static void receive() throws IOException String line = in.readline(); p.17
if (line!= null) System.out.println(line); System.out.println("\n"); //methode qui envoi des infos au serveur private static void send(string s) System.out.print(s); System.out.print("\r\n"); System.out.flush(); out.print(s); out.print("\r\n"); out.flush(); private static BufferedReader in; private static PrintWriter out; p.18