Raspberry Pi 3 – Java – Un projet conséquent

Mon nouveau livre chez Eyrolles sur Java et le Raspberry Pi 3 est presque terminé et en précommande sur Amazon. Nous y retrouverons plein d’exemples et d’exercices comme décrit ici. Vous pouvez me contacter: jean-bernard@boichat.ch

J’ai écrit une application similaire, en Java, sur mon premier Raspberry, il y a quelques années, qui marche vraiment bien. Je suis en train de l’étendre et de l’améliorer, pour mon dernier Pi 3.

Voici en quelques mots la démarche et les spécifications:

Cette application va allumer et éteindre une lampe de bureau ou un lampadaire, pour à la fois simuler une présence dans la maison et lors de déplacement de personnes en cas de basse lumière. 

Le lever et le coucher du soleil doivent être calculés suivant la saison et un certain nombre de paramètres doivent être définis. A 2 heures du matin, nous ne ferons pas de simulation, mais un déplacement de personne sera détectée.

En cas de très basse lumière (ou d’éclipse de soleil), nous aurons donc la lampe qui s’allume aussi pour nous permettre de descendre les escaliers!

Un serveur Web va nous permettre de vérifier le bon fonctionnement de la bête, de montrer les périodes actives, et d’autres valeurs comme la température au voisinage du système ou l’accès à des données extérieurs dans d’autres objets connectés.  

 

Il faudra donc un certain nombre de composants que je poserai sur une platine de test et vérifierai avec des scripts Python avant les intégrer dans le code Java:

– Un relais 220V pour la lampe
– Un senseur de mouvement
– Un senseur de lumière
– Un senseur de température
– Une LED d’alarme ou d’indication
– Un buzzer (avertisseur sonore) 

 

Pour le relais 5/220V et le buzzer, j’ai reçu de Chine des composants dont j’ai eu des difficultés à retrouver les schémas et spécifications. Afin de ne pas endommager mon Raspberry, j’ai commencé par les tester sur mon vieux Arduino Duemilanove.

L’application (a été) et est développée sous Eclipse Oxygen et fonctionne sous Windows en simulant les composants hardware ou autres mouvements.

 
 public SystemControl() { 
   if (System.getProperty("os.name").startsWith("Windows")) {
      System.out.println("SystemControl - We are on Windows ");
    
      withPrint = true;    //Message de déroulement du programme
      isTarget  = false;   //Identifie si on se trouve sur le Pi 3
   } 
 }

 

Je ne suis pas certain que je vais déposer ici tout mon matériel, car je n’aime pas trop montrer du code pas trop propre! Et cette application est plus que conséquente.

Chaque fois qu’une classe peut être testée séparément, c’est un plus d’y ajouter une entrée main(). Nous pourrons donc la tester séparément. Ici la classe ConfigParam qui va lire nos paramètres du fichier config.txt:
 

 import java.io.BufferedReader;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.HashMap;
 import java.util.Map;

public class ConfigParam {
  private String paramFile = null;
  private boolean withPrint = false;

private Map<String, String> configParamMap = null;

public ConfigParam(String paramFile, boolean withPrint) {
  this.paramFile = paramFile;
  this.withPrint = withPrint;

  configParamMap = new HashMap<String, String>();
 }

/**
 * Read the configuration parameters for the SystemControl application
 *
 * @return 0 (ok) or different error cases
 */
 public boolean readConfig() {
   BufferedReader br = null;
   try {
     br = new BufferedReader(new FileReader(paramFile));
   }
   catch (FileNotFoundException e) {
     if (withPrint) {
       System.out.println("File " + paramFile + " does not exist");
       System.exit(-1);
     }

     return false;
   }

   String line = null;
   for (;;) {
     try {
       line = br.readLine();
     }
     catch (IOException e) {
       break;
    
   }

   if (line == null) {
     break;
   }

   line = line.replace("\t"," "); //No tabs
   line = line.replace(" ",""); //No spaces at all

   int indexSep = line.indexOf('=');
   int indexSemiCol = line.indexOf(';'); //Position of the comment if any

   if ((indexSep > 0) && (indexSemiCol > 0)) {
     String key = line.substring(0, indexSep);
     String value = line.substring(indexSep + 1, indexSemiCol);
     configParamMap.put(key, value);
   }

   //In this way line without parameters are ignored (doc or other info)
 }

 try {
   br.close();
 }
 catch (IOException e) {
   return false;
 }

 if (configParamMap.size() == 0) {
   if (withPrint) {
     System.out.println("File " + paramFile + " is empty");
   }
   return false; //Empty file
 }

   return true;
 }

public int getInt(String parameter) {
  String value = (String)configParamMap.get(parameter);
  if (value == null) {
    return -2; //No such parameter
  }

  try {
    return Integer.parseInt(value);
  }
  catch(Exception e) {
    return -3; //Invalid value
  }
 }

 public String getString(String parameter) {
  String value = (String)configParamMap.get(parameter);
  return value; //Null if not exist
 }

 public boolean getBoolean(String parameter) {
   String value = (String)configParamMap.get(parameter);
   if (value == null) {
     return false;
   }

   if (value.toLowerCase().compareTo("true") == 0) {
     return true;
   }

   return false;
 }

/**
 * Change the value in one parameter
 *
 * @param parameter
 * @param value
 */
 public void setValue(String parameter, String value) {
   for (Map.Entry<String, String> entry : configParamMap.entrySet()) {
     if (entry.getKey().compareTo(parameter) == 0) {
       entry.setValue(value); //In the map
       break;
     }
   }
 }

public boolean saveConfig() {
  StringBuffer strBuf = new StringBuffer();

  BufferedReader br = null;
  try {
    br = new BufferedReader(new FileReader(paramFile));
  }
  catch (FileNotFoundException e) {
    if (withPrint) {
       System.out.println("File " + paramFile + " does not exist");
    }

   return false;
 }

 String line = null;
 for (;;) {
   try {
     line = br.readLine();
   }
   catch (IOException e) {
     break;
 }

 if (line == null) {
   break;
 }

 int indexSemiCol = line.indexOf('='); //Position of the comment if any
 if (indexSemiCol > 0) {
   String key = line.substring(0, indexSemiCol).trim(); //The parameter
   String value = (String)configParamMap.get(key); //The value change at runtime

   String comment = line.substring(line.indexOf(';') + 1);

   String firstPart = key + "=" + value;
   strBuf.append(firstPart);

   for (int i = firstPart.length(); i < 25; i++) {
     strBuf.append(" ");
   }

   strBuf.append(";" + comment + "\n");
 }

 //In this way line without parameters are ignored (doc or other info)
 }

 try {
   br.close();
 }
 catch (IOException e) {
   return false;
 }

PrintWriter out;
 try {
   out = new PrintWriter(paramFile);
 }
 catch (FileNotFoundException e) {
   return false;
 }

 out.println(strBuf);
 out.close();

 return true;
}

public Map<String, String> getParamMap() {
  return configParamMap;
}

public static void main(String[] args) {
  ConfigParam cfgPara = new ConfigParam("config.txt", true);
  cfgPara.readConfig();

  Map<String, String> theConfigParamMap = cfgPara.getParamMap();
  theConfigParamMap.forEach((k,v)->System.out.println("Param: " + k + " \tValue : " + v));
 }
}

 
Et voici le résultat:

Param: delaySunset 	 Value : 30
Param: afterSunset 	 Value : 22:40
Param: urlBbbLightSensor Value : http://192.168.1.61:8001/lightsync
Param: bbbSensorLevel 	 Value : 3900
Param: beforeSunrise 	 Value : 07:12
Param: delaySunrise 	 Value : 15
Param: withPrint 	 Value : false
Param: onPeriod 	 Value : 300
Param: offPeriod 	 Value : 60
Param: mouvementDelay 	 Value : 91
Param: t1DS1820file 	 Value : w1_slave

Je vais rapidement expliquer ces paramètres et leurs impacts sur le programme.

A suivre ….