Raspberry Pi and HID Omnikey 5321 CLI USB

I recently come across a project where I needed to interact with some RFID tag. I wanted to retrieve the Unique ID of the each badge. I had absolutely no information on the badge except the string “HID iClass” written on it.

I start doing some research and found out that there are 2 big frequencies used in RFID: 125 kHz and 13.56 MHz. The iClass seems mainly based on the 13.56 MHz standard so I decided to go for a reader on this frequency.

Then I found out that there are several standard on this frequency. The most used are (in order) ISO 14443A, ISO 14443B, and ISO 15693. Nevertheless the iClass type includes several tag variations with all these standards. Finally I decided to buy the ADA fruit reader which handles both ISO 14443A and B: https://www.adafruit.com/products/364

I set it up with a Raspberry Pi 2 and was able to read the TAG send with the reader but sadly not the tag I wanted to read… Since I was unable to read my tag I guess they are using the third protocol: ISO 15693.

I look for some reader for the ISO 15693 but the choice is very limited (since it is not widely use). In the meantime I found a cheap HID reader on amazon (https://www.hidglobal.fr/products/readers/omnikey/5321-cli) which should be compatible with HID iClass card so I decided to buy it.

It works pretty well on Windows with their driver and software and gives me some useful information about my badge. It allowed me to confirm that it use the ISO 15693 standard:

It’s a good start nevertheless I wanted to use it on Raspberry Pi. I decided to do some research and found out that this type of RFID card reader is called “PCSC”:

PC/SC (short for “Personal Computer/Smart Card”) is a specification for smart-card integration into computing environments. (wikipedia)

Moreover there is a USB standard for such device: CCID.

CCID (chip card interface device) protocol is a USB protocol that allows a smartcard to be connected to a computer via a card reader using a standard USB interface (wikipedia)

Most USB-based readers are complying with a common USB-CCID specification and therefore are relying on the same driver (libccid under Linux) part of the MUSCLE project: https://pcsclite.alioth.debian.org/

There are plenty of soft related to RFID reading on Linux that I found during my research before choosing to try CCID. Here are my raw notes for future reference:

  • PCSC lite project
  • PCSC-tools
  • librfid
    • Seems dead
    • https://github.com/dpavlin/librfid
    • low-level RFID access library
    • This library intends to provide a reader and (as much as possible)
    • PICC / tag independent API for RFID applications
  • pcscd
  • libnfc
    • https://github.com/nfc-tools/libnfc
    • forum is dead
    • libnfc is the first libre low level NFC SDK and Programmers API
    • Platform independent Near Field Communication (NFC) library http://nfc-tools.org
    • libnfc seems to depend on libccid but it seems to depend on the hardware reader used :Note: If you want all libnfc hardware drivers, you will need to have libusb (library and headers) plus on *BSD and GNU/Linux systems, libpcsclite (library and headers).Because some dependencies (e.g. libusb and optional PCSC-Lite) are used
  • Opensc

I decided to go with the MUSCLE project available here: https://pcsclite.alioth.debian.org/ccid.html

After I installed the driver/daemon and the tools to interact with the reader I had trouble since the reader was not detected by pcscd. Luckily there is a section “Check reader’s compliance to CCID specification” on the pcsc page to know if the driver is supported. I follow it and send the repport to the main maintainer of pcsc driver: Ludovic Rousseau.

He confirms me that the driver was never tested with this driver and give me the instruction to try it :

Edit the file CCID/readers/supported_readers.txt and add the line:
0x076B:0x532A:5321 CLi USB
Then (re)install the CCID reader and try again to use the reader.
https://ludovicrousseau.blogspot.fr/2014/03/level-1-smart-card-support-on-gnulinux.html

I follow it and the reader gets detected by the daemon. Nevertheless the card is not detected so I provided more feedback/logs to Ludovic for debugging and sadly the result is that the reader cannot be supported:

The conclusion is that this reader is not CCID compliant. I am not surprised by this result.
You have to use the proprietary driver and no driver is provided for RaspberryPi.
If you are looking for a contactless reader have a look at https://pcsclite.alioth.debian.org/select_readers/?features=contactless

I will try to see if I can interact with the reader and libusb and also found a cheap open source ISO 15693 reader to continue this project.

Update 23JAN2017

I contact Omnikey to have support to use their reader for my project and they confirmed there is no driver on the Pi for it.

we don’t have any drivers for 5321 CLi on Raspberry Pi. Please have a look at OMNIKEY 5022 or OMNIKEY 5427 CK instead. The can be accessed through native ccidlib.

In the meantime I also bought another reader compatible with the ISO standard 15693: http://www.solutions-cubed.com/bm019/

I plug it with an Arduino Uno thanks to their blog article : http://blog.solutions-cubed.com/near-field-communication-nfc-with-the-arduino/

Nevertheless I was still unable to read the TAGS. I start doing deeper research and found that the ISO 15693 can have several settings and I do not know which one my iClass tags are using. I tried all the possible combinations that the BM019 handle:

Even with all the tests I made I’m still unable to read them. I dig deeper and found out that the BM019 module is built around the CR95HF ST chip. It seems that I’m not the only one trying to read Icalss with their IC and their support forum has several post explaining that it is not possible since iClass do not properly follow the ISO 15693 standard:

issue comes from Picopass which is not ISO 15693 complliant  ,
timing are not respected . 
We have already implemented a triccky commannd which allow us to support Picopass , a new version of CR95HF devevelopment softaware will be soon available including a dedicated window for PICOPASS .

After 3 readers and countless hours of attempt I’m still unable to read the iClass badges since they do not seems to implement any real standard.

BT discovery on Android

This article present how to use Bluetooth on Android device. The full project include Arduino Leonardo card and is detailed on this article : http://djynet.net/?p=639

First….some ressources to understand BT communication and BT handling on Android :

  • https://learn.sparkfun.com/tutorials/using-the-bluesmirf/all
  • https://learn.sparkfun.com/tutorials/bluetooth-basics/all
  • http://developer.android.com/guide/topics/connectivity/bluetooth.html

Before starting….I thanks the guy who wrote the following article which help me a lot to understand android – Arduino BT links :
http://english.cxem.net/arduino/arduino5.php

I finish the DEV but it happen to be more complicated than I originaly think it would be… Especialy the “receive” part from Android which require ansynch tasks. Nevertheless I put lot of comments in the code so it should be easy to understand it.

The first things is to request BT use in the manifest :

<uses-permission android:name=”android.permission.BLUETOOTH” />

Then I created a simple layout with some button and textview to interact with the user

BT_Moisture_interface

The first section hold the potential BT devices and allow to connect to the one selected. The second section is only 1 button “Moisture request” which will send the char ‘h’ to the arduino board. Last text view is used to display the Arduino response which is the moisture value in the earth.

The association button-callback is done in the xml view directly :

<Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/connect"
        android:onClick="myClickHandler"
        android:text="@string/hello_world" />

At startup the program check if the phone as BT capability :

if (mBluetoothAdapter == null) {
            // Device does not support Bluetooth
            Log.w("MyActivity", "Device does not support Bluetooth");
            Toast.makeText(this.getParent(), "Go buy a more recent phone", Toast.LENGTH_LONG).show();
        }
and if the BT is not turn on it will request it to the OS (which will prompt the user) :
if (!mBluetoothAdapter.isEnabled()) {
                Log.i("MyActivity", "BT is not enabled. I request to start it");
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableBtIntent, 643);
            }

Another solution is to turn it on without asking kindly but it request more permission (in manifest).

Once the BT is ready the program will populate the UI with the list of paired devices :

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
        // If there are paired devices
        if (pairedDevices.size() > 0) {

            //Fill the spinner on view with devices
            Spinner spinner = (Spinner) findViewById(R.id.spinner);
            // Create an empty ArrayAdapter
            ArrayAdapter <CharSequence> adapter = new ArrayAdapter <CharSequence> (this, android.R.layout.simple_spinner_item );
            // Specify the layout to use when the list of choices appears
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            // Apply the adapter to the spinner
            spinner.setAdapter(adapter);
            //Populate IT !!
            for (BluetoothDevice device : pairedDevices) {
                adapter.add(device.getName() + "\n" + device.getAddress());
            }
        }

I didn’t handle the BT discovery here….which means that I already paired my Arduino with my phone. This operation could be done directly in android when you turn on the BT. It need to be done only 1 time and will ask you the code of the arduino BT module (1234).

Then….the user can select its module in the drop down menu (that we just populate in the previous function) and open a connection with it by pressing the “connect” button. It will call button callback :

public void myClickHandler(View v) {
        Log.i("MyActivity", "click button");
        connectMoisture();
    }

which call the real interesting process 🙂

protected void connectMoisture()
    {
        BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        Log.i("MyActivity", "We open the connection");
        // I will use the standard SPP UUID - remember it is not link to our device on contrary of MAC address
        UUID aSppUuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
        // The Arduino BT receiver address
        String aArduinoBtAddress = "00:06:66:60:42:BE";
        try{
            Log.i("MyActivity", "Going to retrieve the device");
            BluetoothDevice aBtDevice = mBluetoothAdapter.getRemoteDevice(aArduinoBtAddress);
            Log.i("MyActivity", "Device retrieved, creating socket now");
            _blueToothSocket = aBtDevice.createRfcommSocketToServiceRecord(aSppUuid);
            Log.i("MyActivity", "Socket created");
        }catch(IOException createSocketException){
            Log.e("MyActivity", "error1508"+ createSocketException.getMessage());
        }
        // Establish the connection.  This will block until it connects.
        Log.i("MyActivity", "Will try to connect to remote device");
        try {
            _blueToothSocket.connect();
            Log.i("MyActivity", "Connection is done");
        } catch (IOException e) {
            Log.e("MyActivity", "error148"+ e.getMessage());
            try {
                Log.i("MyActivity", "Closing socket");
                _blueToothSocket.close();
                Log.i("MyActivity", "Socket closed");
            } catch (IOException e2) {
                Log.e("MyActivity", "another issue" + e2.getMessage());
            }
        }
        // Step 3 create stream to talk with BT deice
        try {
            _streamOutgoing = _blueToothSocket.getOutputStream();
        } catch (IOException e) {
            Log.e("MyActivity", "another issue" + e.getMessage());
        }
    }
Now the program is connected to the device (the Ardunio BT board will probably have a LED which will reflect this new state). The user can now request the moisture value by clicking on the second button :
public void mySecondClickHandler(View v) {
        Log.i("MyActivity", "Sending h");
        //sendData("l");
        sendData("h");

    }

which call a sending routing with ‘h’ char :

protected void sendData(String message) {
        // start thread which handle input BT data before we send the request to Arduino.
        // With this design we know that we will be able to handle response
        ImplementsRunnable rc = new ImplementsRunnable();
        Thread t1 = new Thread(rc);
        t1.start();
        // The thread which is listening to input data from Arduino is now started
        // We can go to next step and send request to Arduino

        //Convert the String to send to byte
        byte[] msgBuffer = message.getBytes();
        Log.d("MyActivity", "About to send : " + message);

        try {
            _streamOutgoing.write(msgBuffer);
            //The next line is sending h char. I kept it as a debug test because I was worried Android will add extra char which will not be understand on Arduino side like end of line
            //_streamOutgoing.write('h');
        } catch (IOException e) {
            Log.e("MyActivity", "Error when trying to send data : " + e.getMessage());
        }
        //This is over. The Arduino response will be handle separately by another thread that we started before sending the request
    }

OK….So here I have to explain the first part where we start a dedicated thread. Before sending the request to Arduino Board we start a thread which will wait for incoming data on BT. It is the normal way to handle incoming message. The other part of the function is the data sending to arduino.

After this call the arduino received the char ‘h’ which trig a moisture detection and it will send back the moisture value to the BT module which will send it to the Android Phone.

As explained the reception is done in a dedicated thread. This is done by the following class which implement the “runable” interface :

class ImplementsRunnable implements Runnable {
        private InputStream _streamIncoming = null;

        public void run() {
            Log.d("MyActivity", "Thread run");

            //First we retrieve the input stream of the BT socket to be able to read incoming bytes
            try {
                _streamIncoming = _blueToothSocket.getInputStream();
                Log.i("MyActivity", "Input stream acquired");
            } catch (IOException e) {
                Log.e("MyActivity", "another issue" + e.getMessage());
            }

            //This single read works because I only wait for one message from Arduino but we should have a infinite loop here to catch everything arriving all the time
            try {
                //Not clean but we only receive a small message
                BufferedReader aMyBufferReader = new BufferedReader(new InputStreamReader(_streamIncoming));
                String aArduinoDataStr = "";
                aArduinoDataStr = aMyBufferReader.readLine();

                Log.i("MyActivity", "Received " + aArduinoDataStr );
                _ThreadMsgHandler.obtainMessage(31444, aArduinoDataStr).sendToTarget();     // Send to message queue Handler

            } catch (IOException e) {
                Log.e("MyActivity", "another issue" + e.getMessage());
            }
            Log.i("MyActivity", "Leaving thread run method " );
        }
    }

Once data are received by this thread they will be forwarded to the UI thread. This is done by the use of ‘Android handler’ in the UI thread :

_ThreadMsgHandler = new Handler(Looper.getMainLooper()) {
            //Will be called when new message arrive from other threads
            public void handleMessage(Message msg) {
                Log.d("MyActivity", "Handler is handling a message of type : " + msg.what);
                switch (msg.what) {
                    //Random ID .... should be the same as the one use when sending the msg from the thread
                    case 31444:
                        String aMyMoistureValue = (String) msg.obj;
                        // For now we only log it and toast it
                        Log.i("MyActivity", "Toasting moisture value : " + aMyMoistureValue);
                        Toast.makeText(MyActivity.this, aMyMoistureValue, Toast.LENGTH_LONG).show();
                        TextView aMyTextViewHandlingResponse = (TextView) findViewById(R.id.textView);
                        aMyTextViewHandlingResponse.setText("Moisture: " + aMyMoistureValue);
                        break;
                    //I think it should never occurs but just to be safe we log it
                    default:
                        Log.w("MyActivity", "Received an unknown message type : " + msg.what);
                }
            };
        };

Don’t forget…..this methods in on the UI thread ! We will come back to it after I finish explaining my runable class…..

The Data are send from the runable class to the UI thread with the handler :

_ThreadMsgHandler.obtainMessage(31444, aArduinoDataStr).sendToTarget();     // Send to message queue Handler

which is “catch” in the UI thread by the handler I just show before. The important point is the 31444 which has to be the same and act as an unique identifier. To finish the UI thread toast this value (debuging) and update the textview.

The results with the sensor in moist earth (or not) with the Arduino and Android output.

Moisture_Ardu

Andro_Moisture

The whole code for the project (Android and Arduino) is on my bitbucket account here.

 

 

Bluetooth Arduino for moisture sensor

This WE I wanted to try BT communication with an Arduino…. To have a real project I decided to use a moisture sensor to detect from my phone if my green plant needs some water.

Global1

Global2

Arduino Board

To do so I bought a sparkfun BT module “Bluetooth Mate Silver” available following this direct link : https://www.sparkfun.com/products/12576

The moisture sensor is pretty standard : http://www.dfrobot.com/index.php?route=product/product&product_id=599#.U8JDQbE39b0

The connection to the BT module is pretty easy with Power (+3.3V, Gnd) and serial Data (Rx BT – Tx Leonardo and Tx BT – Rx Leonardo). As soon as the BT module is powered up it will be visible as a BT module.

2014-07-12-09-38-59

On the Arduino side I done a very simple program which will listen on the serial link established with the BT module. Once the Leonardo received a char ‘h’ it will read the humidity sensor value (analog read) and send it back on the BT link. Here is the code :

/*
Created by Charles Walker (charles.walker.37@gmail.com)
 Test program for bluetooth communication
 Tested with Arduino Leonardo and BT module Mate Silver (sparkfun)
 */

void setup()
{
  //USB Serial port
  Serial.begin(115200);
  //BT module serial port
  Serial1.begin(115200); 
}

void loop()
{
  delay(5000);
  if(Serial1.available())  
  {
    //We received something on BT module
    char aReceived;
    aReceived = (char)Serial1.read();
    Serial.print("Receveid from BT module :");
    Serial.println(aReceived);  

    // if we received a read humidity request
    if (aReceived=='h')
    {
      // Reading humidity
      unsigned int aHumidityValue;
      aHumidityValue=analogRead(0);
      Serial.print("Moisture Sensor Value:");
      Serial.println(aHumidityValue);
      // Sending it to the BT module
      Serial1.println(aHumidityValue);
    }
  }
  if(Serial.available())  
  {
    //We received something on USB serial line - We will send it to the BT module
    char aToBeSend;
    aToBeSend = (char)Serial.read();
    Serial.print("Going to send :");
    Serial.println(aToBeSend);

    //Sending it to the BT module
    Serial1.print(aToBeSend);
  }
}

The last version is available on bitbucket HERE.

The second part is the Android application which will be able to interact with the Arduino module through BT communication. Before starting coding it I wanted to verify that the Arduino part is working fine.

To do so I download a Arduino App able to communicate over BT. I tried few of them and the best one I find is :

https://play.google.com/store/apps/details?id=ptah.apps.bluetoothterminal

I installed it and then try sending some commands to the Leonardo board.

BT_Moisture_Test

The application properly connects to the BT module and then we are able to send some commands. The Leonardo only respond to the ‘h’ command which trig moisture read and send it back to the phone.

Android application

First step….. Fix android Studio Beta 0.8 issue….. See : http://djynet.net/?p=652
Android APP creation in a dedicated thread….. See : http://djynet.net/?p=658

Conclusion :

The results with the sensor in moist earth (or not) with the Arduino and Android output.

Moisture_Ardu

Andro_Moisture

The whole code for the project (Android and Arduino) is on my bitbucket account here.

Reconnaissance vocale

Création d’une application android pour le système de domotique qui sera capable de reconnaitre la parole pour actionner certaines actions. Le but est de remplacer “Tasker + auto voice” par une application fait maison et plus plus adapte au système.

on utilise l API google et c est google qui fait tout le boulot de décodage de la parole (et plutôt bien) :

public void speak(View view) {
 Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
// Specify the calling package to identify your application
 intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getClass().getPackage().getName());
// Given an hint to the recognizer about what the user is going to say
 //There are two form of language model available
 //1.LANGUAGE_MODEL_WEB_SEARCH : For short phrases
 //2.LANGUAGE_MODEL_FREE_FORM  : If not sure about the words or phrases and its domain.
 intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
// Specify how many results you want to receive. The results will be sorted where the first result is the one with higher confidence.
 int noOfMatches = 4;
 intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, noOfMatches);
 //Start the Voice recognizer activity for the result.
 startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
 }

et on attend la réponse de l’activité :

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 if (requestCode == VOICE_RECOGNITION_REQUEST_CODE)
//If Voice recognition is successful then it returns RESULT_OK
 if(resultCode == RESULT_OK) {
ArrayList<java.lang.String> textMatchList = data
 .getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
if (!textMatchList.isEmpty()) {
 mlvTextMatches
 .setAdapter(new ArrayAdapter<java.lang.String>(this,
 android.R.layout.simple_list_item_1,
 textMatchList));
 sendMsgToServer(textMatchList);
}

ensuite avec les résultats (plusieurs phrases correspondant a ce que google a décoder) on appel une fonction “sendMsgToServer” qui va envoyer ses phrases aux serveur python qui gère tout la centrale domotique.

public void sendMsgToServer(ArrayList<java.lang.String> aStrings){
String url = "http://192.168.0.6/Sender/XbeeWrapper.php?iCmdType=CMD_SPEAK&iCmdStrings=";
 String aCmd = combine(aStrings,"_");
 url = url + aCmd;
 url = url.replace(' ','-');
 url = Normalizer.normalize(url, Normalizer.Form.NFD);
 url = url.replaceAll("[^\\p{ASCII}]", "");
 grabURL(url);
 }

Attention : pour faire cela on utilise une autre classe qui dérive de classe asynch car dans android toutes les opérations longues doivent être faites ailleurs que dans le thread principale.

private class GrabURL extends AsyncTask<String, Void, Void> {

je vais pas détailler ici pkoi et comment car il existe une multitude de référence sur le sujet sur internet. Bref le serveur python reçoit les phrases et parcours tous les objets du réseaux domotique pour savoir auquel est destine la commande :

def TranslateVocalAction(self,Sentences, Devices):
 logging.warning("Translate : " + str(Sentences))
 #Weight, Device ID, CommandID
 aBestDeviceMatch=(0,0,0)
 for aOneObj in Devices.registeredDevices:
 (aWeight,aCmdId)=aOneObj.getDeviceWeightSpeech(Sentences)
 logging.warning ("DeviceId : " + str(aOneObj.id) + " has weight : " + str(aWeight))
 if(aWeight > aBestDeviceMatch[0]):
 aBestDeviceMatch=(aWeight,aOneObj.id,aCmdId)
 logging.warning("Device is : " + str(aBestDeviceMatch))
 self.SendMessage( str(aBestDeviceMatch[2]),"VoiceAction",Devices)
 return (Devices.getDevice(aBestDeviceMatch[1]).description,aBestDeviceMatch[2])

Pour cela il parcours la description et les commandes possible de tous les objets qui se présentes sous la forme :

VoletSalon = InterupteurMultiStable()
 VoletSalon.id =5
 VoletSalon.description="volets salon"
 VoletSalon.InPossibleCmd ={ "10" : "off fermer ferme","9" : "on ouvre ouvrir","25" : "stop arreter arrete"}
 VoletSalon.InActionsCommands={ "9" : "self.turnOn(9)","10" : "self.turnOff(10)","25" : "self.turnOff(10)"}
 self.registeredDevices.append(VoletSalon)
LumiereSalonHalogene = InterupteurBiStable()
 LumiereSalonHalogene.id =6
 LumiereSalonHalogene.description="lumiere halogene salon"
 LumiereSalonHalogene.InPossibleCmd ={ "13" : "off eteint eteindre","14" : "on allume allumer"}
 LumiereSalonHalogene.InActionsCommands={ "13" : "self.turnOff(13)","14" : "self.turnOn(14)"}
 self.registeredDevices.append(LumiereSalonHalogene)
....

et donne un poids pour chaque objet en fonction de sa description et de ses possibles commandes. Le poids dépend du nombre de mots commun entre les strings et les mots présent dans la phrase (pondéré par leur longueur)

Ensuite il exécute la commande qui a le poids le plus grand. C’est assez facile en fin de compte. En parallèle le serveur python renvoi la commande exécuté et l’objet associe :

return (Devices.getDevice(aBestDeviceMatch[1]).description,aBestDeviceMatch[2])

Ces infos sont ensuite affiches sur la UI du telephonne portable pour que l utilisateur puisse vérifier :

protected void onPostExecute(Void unused) {
 Dialog.dismiss();
 if (Error != null) {
 Toast.makeText(VoiceRecognitionActivity.this, Error, Toast.LENGTH_LONG).show();
 } else {
 Toast.makeText(VoiceRecognitionActivity.this, "Source: " + Content, Toast.LENGTH_LONG).show();
 }
 }

Je ne détaille pas bcp plus car tous le code est tjs visible au même endroit sur le dépôt central de mon projet domotique et assez court pour être compris facilement.

Je ferais une vidéo du système en action ASAP.

Capteur meteo terrasse

Création d’un nouveau “end device” pour la terrasse :
20130602_203639

Il est base sur une carte Arduino non officielle : Ultra mini dont j ai déjà parle lors d article précédant. C’est la seule carte arduino que je connais qui est designe pour consommer le moins de courant possible (Cf article précédant) !

La carte consomme moins de 1mA en veille (et monte a 30 environ) lorsqu’elle passe a l état actif pour récupérer la température, humidité, et luminosité. Les données sont ensuite envoyées au système. Grâce a ces nouvelles data j’ai pu supprimer la “crontab” des volets qui ete fixe a 21h00. Maintenant les volets se ferme quand la luminosité extérieur est trop faible 😉

Le plus difficile a été de réduire la consommation de la carte (96mA a l origine avec une carte Arduino Leonardo) a un niveau acceptable pour que le chargeur solaire soit suffisant (1mA en veille et 30mA en émission pendant 5s toutes les 10 minutes). Tout les optimes pour la consomation de courant sont déjà explique dans mon article sur la carte “Mini Ultra +”.

Smart tableau – nouveau End Device pour mon system domotique

J’ai décidé d’ajouter un nouveau « end device » dans le système pour pouvoir mesure/contrôler certains éléments de la cuisine.

Cadre_avant

Les fonctions de ce nouveau « end device » sont :

  • Détection de personne (capteur PIR)
  • Détecteur de fumée (démontage d’un détecteur de fumée du commerce)
  • Mesure Température et humidité

L’ensemble des capteurs est monte à l’arrière d’un cadre qui est pose dans la cuisine au-dessus des rangements. Le capteur de fumée est donc très prêt du plafond pour être sur qu’il détectera bien un incendie.

L’ensemble du montage communique par ZigBee avec le coordinateur. Ensuite le coordinateur transmet les infos au « brain » au travers d’une liaison série USB (exactement comme les autres devices).

Le « brain » python doit donc maintenant être capable de comprendre ce nouveau device pour, par exemple, prévenir de la détection d’un incendie.

Ceci est très simple grâce au design du system domotique puisque le « détecteur incendie » correspond parfaitement à un device de type « interrupteur stable » et donc il suffit de rajouter dans le « brain » une nouvelle action pour cet interrupteur stable en particulier. On ajoute donc :

if ((aOneDevice.id == 2) and (aOneDevice.currentStatus=="unstable")):
 sendEmailFireDetected()

dans la boucle des détections évènements trigger par les interrupteurs stable :

#Step 1 : Verifier tous les detecteurs (interupteurs stables) pour voir si ils ont ete actives et prendre les actions correspondantes avant de les reset
        #Par exemple si le detecteur de fumee a ete active alors on va envoyer un mail 
        logging.info("Checking all possible event")
        for aOneDevice in iListOfDevice.registeredDevices:
            logging.debug("checking event : " + str(aOneDevice.id))
            if ((aOneDevice.id == 2) and (aOneDevice.currentStatus=="unstable")):
                sendEmailFireDetected()
            elif ((aOneDevice.id == 10) and (aOneDevice.currentStatus=="unstable")):
                self.PeopleDetectedEntree(iListOfDevice)
            elif ((aOneDevice.id == 9) and (aOneDevice.currentStatus=="unstable")):
                self.PeopleDetectedCharlesRoom(iListOfDevice)
            aOneDevice.reset()

Ensuite il ne reste plus qu’à créer la fonction « send fire detection » pour prévenir l’utilisateur qu’un incendie a été détecté. Pour le moment on se contente d’envoyer un email mais dans l’avenir on peut simplement faire évoluer cette action avec par exemple un appel automatique au pompier

L’envoie de l’email est assure par la fonction suivante :

def sendEmailFireDetected():
 '''Envoie email lors de la detection incendie'''
 logging.error("Envoi email detection incendie")
 # Define email addresses to use
 addr_to = Config["addr_to"]
 addr_from = Config["addr_from"]
 # Define SMTP email server details
 smtp_server = Config["smtp_server"]
 smtp_user = Config["smtp_user"]
 smtp_pass = Config["smtp_pass"]

 # Construct email
 expires = datetime.datetime.now()
 msg = MIMEText('Fire detected at ' + str(expires))
 msg['To'] = addr_to
 msg['From'] = addr_from
 msg['Subject'] = 'Fire alarm'

 # Send the message via an SMTP server
 s = smtplib.SMTP(smtp_server, 587)
 s.login(smtp_user,smtp_pass)
 s.sendmail(addr_from, addr_to, msg.as_string())
 s.quit()