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.

Electric Train V3

Feel free to have a look on the V2 first:
http://djynet.net/?p=759

The biggest change is in the camera able to follow the phone orientation to update its angle. I also replace the front/rear sensors.

TrainV3

Camera tracking

I used the html5 API to detect the phone orientation:

if (window.DeviceOrientationEvent) {
  // Our browser supports DeviceOrientation
  window.addEventListener("deviceorientation", deviceOrientationListener);
} else {
  console.log("Sorry, your browser doesn't support Device Orientation");
}
function deviceOrientationListener(event) {
  var c = document.getElementById("myCanvas");
  var ctx = c.getContext("2d");

  ctx.clearRect(0, 0, c.width, c.height);
  ctx.fillStyle = "#FF7777";
  ctx.font = "14px Verdana";
  ctx.fillText("Alpha: " + Math.round(event.alpha), 10, 20);
  ctx.beginPath();
  ctx.moveTo(180, 75);
  ctx.lineTo(210, 75);
  ctx.arc(180, 75, 60, 0, event.alpha * Math.PI / 180);
  ctx.fill();

  ctx.fillStyle = "#FF6600";
  ctx.fillText("Beta: " + Math.round(event.beta), 10, 140);
  ctx.beginPath();
  ctx.fillRect(180, 150, event.beta, 90);

  ctx.fillStyle = "#FF0000";
  ctx.fillText("Gamma: " + Math.round(event.gamma), 10, 270);
  ctx.beginPath();
  ctx.fillRect(90, 340, 180, event.gamma);
  
  var aMsg = event.alpha.toString()+"_"+event.beta.toString()+"_"+event.gamma.toString();
  console.log("aMsg" + aMsg);
  doSend(aMsg);
}

Which send the 3 orientation information to the Tornado python server running on the Raspberry pi of the train. First I was doing JSON REST call to send the string containing the information but it was too slow to have the camera moving in real time. This was the perfect opportunity to use websocket for more real time communication.


function onOpen(evt) { 
        console.log("CONNECTED");
        doSend("Hi there!");
    }
    function onClose(evt) { 
        console.log("DISCONNECTED");
    }
    function onMessage(evt) { 
        console.log('message: ' + evt.data);
    }
    function onError(evt) { 
        writeToScreen('error' + evt.data);
    }
    function doSend(message) { 
        websocket.send(message);
    }
function testWebSocket() {
        websocket.onopen = function(evt) { onOpen(evt) };
        websocket.onclose = function(evt) { onClose(evt) };
        websocket.onmessage = function(evt) { onMessage(evt) };
        websocket.onerror = function(evt) { onError(evt) };
}
        

if (!'WebSocket' in window){
    console.log("Sorry, your browser doesn't support Websockets");
} else {
var wsUri = "ws://192.168.10.1:80/ws";
var websocket = new WebSocket(wsUri);
    testWebSocket();
}

Which is received on the server side and put in a variable (see the class Handler_WS) :

    def on_message(self, iMessage):
        """Methode call when the server receive a message"""
        logging.info('Receive incoming message:'+str(iMessage))
        #self.write_message("toto")
        self.aTrainRef._cellAngles=str(iMessage)

This variable is then read every 125ms by the “foo” function:

tornado.ioloop.PeriodicCallback(lambda: foo(aTrain), 125).start()

At the end the real method called is in charge of updating the turret position. The whole stuff is based on an existing framework called servoBlaster which will take care of driving the Servo.

def updateTurretFromScreenAngle(self):
        if (self._cellAngles!=""):
            #Update Gamma
            aGamma = self._cellAngles.split("_")[2]
            aGammaF = float(aGamma)
            aGammaI = int(aGammaF)
            aGammaisNegative = False
            if (aGammaI<0): aGammaI=(aGammaI*-1)-40 aGammaisNegative = True else: aGammaI=140-aGammaI if ((aGammaI>0)and(aGammaI<100)):
                self._turretHeight = 100 - aGammaI
                self.sendPos(ConstModule.CONST_SERVO_HEIGHT,self._turretHeight)
            #Update Alpha
            ...

Servo Blaster is library able to drive Servo on the Raspberry pi using software PWM. It is pretty hard to do since the Pi is not running a real-time OS. It relies on very low level interruption to ensure the timing needed to have a proper PWM are respected. You can have more info on it here:

https://github.com/richardghirst/PiBits/tree/master/ServoBlaster

It basically start a daemon (which I added in the crontab to be launch at boot time) on which you can interact with writing the desired position of each servo in /dev/servoblaster like:

echo 3=120 > /dev/servoblaster 

I also used servo blaster to send PWM info to the motor driver to change the train speed (since this functionality was broken when I moved from Arduino to Rapsberry Pi).

Contact sensors

I replace the old contact sensor by some new sensor able to detect an incoming obstacle before impact.

TrainSensorNew

They are still binary sensors that will turn high if they detect an obstacle but they have a wider range between 2 and 10 centimeters. This allows the train to detect incoming obstacle and stop before hitting it. The sensor is available on ADAfruit:
https://www.adafruit.com/products/1927

Demo

I made some videos on this new version on YouTube:

Code

As always the code is available here:
https://bitbucket.org/charly37/train/overview

Electric train V2

Following the first version of the electric train : http://djynet.net/?p=731

After some weeks of works I’m proud to announce the Version 2 of the electric train:

TrainV2

Wifi capabilities

The train can now be control with Wifi. It creates a wifi hotspot at boot time allowing people to connect to access a UI with some commands. The Wifi hotspot creation is describe HERE

Web

The train now offers a Web UI which allows controlling it and seeing the camera broadcast. The UI is done in Angular JS (with Bootsrap Angular UI). The Web server used to render the page is a python one : Tornado.

In addition of the UI it offers REST API to control the train (which are called today by the UI but could be used for a native Android application). The Web creation setup is detail HERE (TODO).

Embedded camera

The train is now equipped with a camera (the official Raspberry camera). The camera stream is broadcast and available on the train Web UI. The camera broadcast setup is describe HERE

Raspberry Pi brain

I replace the Arduino board with a Raspberry Pi A+. This extra boost of power was needed to broadcast the camera stream and create a wifi hotspot.

UBEC Power source

The biggest surprise I had when creating the new version was lot of unexpected Raspberry Pi reboot. Every time I was starting to move the train the Raspberry Pi was rebooting. I quickly suspect it was due to the motor which either took too much current or create perturbation that the 7805 cannot handle by itself. I done some research to understand how this issue was usually handle in R/C world and find out that they already have the perfect solution : BEC.

It is used to power the command part of the RC model from the same source than the motor. It provides a smooth tension and is able to absorb the impact of the motors on the power source with use of self and capacitor (wikipedia link). Since it is standard component in R/C world you can buy them pretty easily on the Web :

UBEC

The final result is visible in this video : TODO

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.

Test Analyseur logique Scanalogic-2 de IKA-LOGIC

Suite a la comparaison des analyseurs logiques realise le mois dernier et disponibles ici :
http://djynet.net/?p=547

J’ai décidé de présenter plus précisément le Scanalogic-2 que je me suis offert pour noël. Pour ce test j’ai choisit d’analyser les échanges entre un Arduino Leonardo et un récepteur TCM310 EnOcean.

TCM_310

EnOcean est un groupement industriel qui développe des capteurs fonctionnant sans fils et sans batterie (le capteur utilise l’énergie de son environnement).

Capture du 2014-01-19 11:01:15

Je vous conseil de visiter le site web officiel :
ICI

Pour ce test j’ai également acheter un interrupteur compatible EnOcean : le VITA 1001 de VITEC

interrupteur-vimar-plana-eclate

L’interrupteur est un peu plus “dure” a enfoncer qu’un interrupteur standard car la force de notre appuie va également créer l’énergie nécessaire au circuit embarque qui enverra un signal radio au récepteur TCM310. Le TCM310 enverra ensuite un signal a l’Arduino que nous voulons analyser dans cet article.

Voila le montage complet :

20140119_111549

Les branchements entre l’analyseur logique et le système sont :

  • Masse – Masse
  • Ch3 (rouge) – Arduino Rx – TCM310 Tx
  • Ch1 (vert) – Arduino Tx – TCM310 Rx

L’installation de l’analyseur logique est extrêmement simple sous Windows et ne nécessite aucun drivers. Une fois lance il est assez simple d’utilisation puisqu’il suffit de choisir la fréquence échantillonnage et le critère de start (front descendant par exemple). Voila le résultat lors d’un appuie sur l’interrupteur :

555

On constate donc une communication du module 310 vers l’Arduino lors de l’appuie sur l’interrupteur. Il existe une fonction assez pratique dans le logiciel scanlogic pour afficher les valeur hexa de chaque bytes échangés (visible sur la photo ci dessus). Dans notre exemple la communication commence par 0x55.

Pour mieux comprendre la trame il suffit de jeter un œil a la documentation du protocole EnOcean disponible sur internet et ci dessous :
EnOceanSerialProtocol3

On trouvera notamment le format standard d’une trame copier ci-dessous :

EnOceanTrame

“As soon as a Sync.-Byte (value 0x55) is identified….” confirme également que nous analysons la bonne trame.

Voila la trame complète récupérée et sa signification obtenue grâce a la documentation :

Value (Hexa) Note
Sync Byte 0x55
Header Data Length 1 0x00
Data Length 2 0x07 Data payload is 7 Bytes
Optional Length 0x07 Opt Data Payload is 7 Bytes
Packet Type 0x01 Type : Radio
CRC8 Header 0x7A OK
Data ORG F6
70
Sender ID 1 0 Module ID : 008BA977
Sender ID 2 8B
Sender ID 3 A9
Sender ID 4 77
Status 30
Optional Data Number of sub telegram 1 1 sub telegram
Destination (4 bytes) FF Broadcast message
FF
FF
FF
dBm 2D 45 for best RSSI
Security level 0 No encryption
CRC8 Data 3F OK

l’étape suivante est la création d’une libraire Arduino pour décoder la trame et interagir avec le TCM310…… dans un autre post !

Analyseur logique

Je cherche un analyseur logique “pas chère” pour debugger mes montages électroniques. j’ai trouve 3 bons candidats :

Scanalogic-2 de IKA-LOGIC

Prix : 60E
http://www.ikalogic.com/ikalogic-products/scanalogic-2/

Open Workbench Logic Sniffer de Dangerous Prototypes

Prix : 50$
http://www.seeedstudio.com/depot/preorder-open-workbench-logic-sniffer-p-612.html?cPath=75

Logic de Saleae

Prix : 120E
http://www.saleae.com/logic

Le Logic semble être un très bon choix mais hors budget 😉 Il existe des clones a 50E mais ils semble que le logiciel officiel les détectes et change leur firmware pour les rendre inutilisables….

Le scanalogic et l OWLS sont sensiblement équivalent (en tout cas pour mes besoins) et j’ai décidé d’essayer la version française 😉

Update des que j’essaye la bête.

Test carte Rocket scream Mini Ultra +

Cela fait longtemps que je cherche une carte Arduino qui consomme le minimum de courant pour pouvoir la mettre dehors sur batterie…. A force de chercher j’ai trouve une carte spécialement conçue dans cette optique : Rocket scream Mini Ultra +. La carte est disponible en ligne ICI.

dev00054-front

J’ai décidé de la tester avec un petit programme qui fait clignoter une led. Pour avoir un point de référence j’ai uploader le programme sur une arduino leonardo et sur la MiniUltra+.

20130508_100502

Voila la consommation des 2 cartes :

Arduino Leonardo : 48.4 mA
Rocket scream Mini Ultra + : 6.7 mA

La carte consomme 7 fois moins que l’Arduino Leonardo ! Je vais lui ajouter un module Xbee avec un mode sleep et refaire des mesures 😉

Update du 9 Mai :

Si on ajoute un module Xbee la consommation passe de 6.7 mA a 45 mA (ce qui correspond a la datasheet Xbee +40mA). J’ajoute aussi un capteur de lumière qui permettra au système domotique de savoir quand il faut fermer les volets ;). On a donc une consommation de 45 mA…..encore un peu trop a mon gout !

L’étape suivante est de faire dormir le module Xbee en utilisant la broche “DTR” du module. Il faut la mettre a l’état haut pour faire dormir le module et donc diminuer sa consommation (il faut aussi que le module soit configurer en sleep mode PIN). Je fais donc “dormir” le module 5 min puis ensuite l’Arduino allume le module et envoie la valeur de la luminosité. Voila le code :

//Libraries definitions
//Xbee library
#include 
//Deipara library
#include 

//pin guirlande led
const int _OutDebugLed = 8;
const int _OutXbeeWakeUp = 7;
const int _InLightPin = 4;

//Xbee objects
//create Xbee object to control a Xbee
XBee _Xbee = XBee(); 
//Create reusable response objects for responses we expect to handle
ZBRxResponse _ZbRxResp = ZBRxResponse(); 
//Global variable used in the program
int _CmdReceived = 0;
int _DataToSend = 0;

void setup()
{
  // start serial
  _Xbee.begin(XBEE_SPEED); 
  Serial.begin(XBEE_SPEED);
  //defined IO
  pinMode(_OutDebugLed, OUTPUT);
  pinMode(_OutXbeeWakeUp, OUTPUT);
  pinMode(_InLightPin, INPUT);

  digitalWrite(_OutDebugLed, LOW);

  delay(2000);
}

void loop()
{
  //digitalWrite(_OutDebugLed, HIGH);
  digitalWrite(_OutXbeeWakeUp, LOW);
  delay(5000);
  unsigned int val = analogRead(_InLightPin);    // read the input pin
  sendZigBeeMsg2(_Xbee,36,val,COORD_ADDR);
  //digitalWrite(_OutDebugLed, LOW);
  digitalWrite(_OutXbeeWakeUp, HIGH);
  delay(300000);

}

En utilisant ce code la consommation passe de 45 mA a 7mA (avec un petit pic a 30mA toutes les 5 minutes) ! Une dernière optimisation est de faire dormir le micro en plus du module Xbee. Je me suis inspire d’un article dispo ICI. Il s’agit d’utiliser le WatchDog pour réveiller le micro toutes les 8s (on ne peut pas faire plus) et attendre d’avoir fait ça pendant 5 minutes pour ensuite faire le vrai processus. Voila le code :

//Xbee library
#include <XBee.h>
//Deipara library
#include <Deipara.h>
// This library contains functions to set various low-power states for the ATmega328
#include <avr/sleep.h>

// This variable is made volatile because it is changed inside an interrupt function
// Keep track of how many sleep cycles have been completed.
volatile int sleep_count = 0; 
// 75 loop needed since ze sleep for 8s and want to wait 10 minutes
const int sleep_total = 75; 

//pin
const int _OutDebugLed = 8;
const int _InLightPin = 4;
const int _OutXbeeWakeUp = 7;

//Xbee objects
//create Xbee object to control a Xbee
XBee _Xbee = XBee(); 
//Create reusable response objects for responses we expect to handle
ZBRxResponse _ZbRxResp = ZBRxResponse(); 
//Global variable used in the program
int _CmdReceived = 0;
int _DataToSend = 0;

void goToSleep()   
{
  // The ATmega328 has five different sleep states.
  // See the ATmega 328 datasheet for more information.
  // SLEEP_MODE_IDLE -the least power savings 
  // SLEEP_MODE_ADC
  // SLEEP_MODE_PWR_SAVE
  // SLEEP_MODE_STANDBY
  // SLEEP_MODE_PWR_DOWN -the most power savings
  // I am using the deepest sleep mode from which a
  // watchdog timer interrupt can wake the ATMega328
  //digitalWrite(_OutDebugLed, HIGH);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode.
  sleep_enable(); // Enable sleep mode.
  sleep_mode(); // Enter sleep mode.
  // After waking from watchdog interrupt the code continues
  // to execute from this point.

  sleep_disable(); // Disable sleep mode after waking.
  //digitalWrite(_OutDebugLed, LOW);                   
}

void watchdogOn() 
{ 
  // Clear the reset flag, the WDRF bit (bit 3) of MCUSR.
  MCUSR = MCUSR & B11110111;

  // Set the WDCE bit (bit 4) and the WDE bit (bit 3) 
  // of WDTCSR. The WDCE bit must be set in order to 
  // change WDE or the watchdog prescalers. Setting the 
  // WDCE bit will allow updtaes to the prescalers and 
  // WDE for 4 clock cycles then it will be reset by 
  // hardware.
  WDTCSR = WDTCSR | B00011000; 

  // Set the watchdog timeout prescaler value to 1024 K 
  // which will yeild a time-out interval of about 8.0 s.
  WDTCSR = B00100001;

  // Enable the watchdog timer interupt.
  WDTCSR = WDTCSR | B01000000;
  MCUSR = MCUSR & B11110111;
}

ISR(WDT_vect)
{
  sleep_count ++; // keep track of how many sleep cycles have been completed.
}

void setup(void) 
{
  // start serial
  _Xbee.begin(XBEE_SPEED); 
  Serial.begin(XBEE_SPEED);
  watchdogOn(); // Turn on the watch dog timer.
  pinMode(_OutDebugLed, OUTPUT);
  pinMode(_OutXbeeWakeUp, OUTPUT);
  pinMode(_InLightPin, INPUT);
}

void loop(void) 
{
  goToSleep(); // ATmega328 goes to sleep for about 8 seconds and continues to execute code when it wakes up

  if (sleep_count == sleep_total) 
    {
    sleep_count = 0;
    // CODE TO BE EXECUTED PERIODICALLY
    //digitalWrite(_OutDebugLed, HIGH);
    digitalWrite(_OutXbeeWakeUp, LOW);
    delay(5000);
    unsigned int val = analogRead(_InLightPin);    // read the input pin
    sendZigBeeMsg2(_Xbee,36,val,COORD_ADDR);
    //digitalWrite(_OutDebugLed, LOW);
    digitalWrite(_OutXbeeWakeUp, HIGH);
  }
}

Avec cet toute derniere version le module (Micro + Xbee) se reveille toutes les 10 minutes pour recuperer la luminosite et l’envoyer au systeme domotique. La consomation finale du module complet est de 4.9mA pendant la veille !! On passe donc d’un montage V1 de 96mA (Arduino Uno + Xbee) a un nouveau module consomant 4.9mA (UltraMini+ et Xbee et sleep mode pour tous).

On a donc diviser la consommation du module par 20!!!!

Update du 17 Mai :

J’ai remarque que la batterie se decharge beaucoup plus vite que prevue….et apres quelques investigations le probleme vient du module Xbee qui ne repasse pas en mode sleep lorsque il est en dehors du reseau ZigBee. En googlant un peu j ai trouve un post similaire sur les forum DIGI (constructeur du Xbee) :

XBee S2 end device goes crazy when coordinator loses power

“The Xbee product manual states that when an end device loses contact with it’s parent, the end device will poll for the parent, and if no reply is received in three polls the unit will go into a search for network mode.

I find that with Xbee S2 modems (that came in several L/H/T sensors I purchased), when the coordinator inadvertently loses power the end device modem instead starts a rapid fire output of data requests (assumed to be polls) at approximately 5ms intervals for indeterminate amounts of time, a minimum of 30+ seconds. In some instances the polling appears to never stop. In some instances the polling finally stops and a beacon request is sent as a start to a network search.”

Dans mon cas il est possible que le module soit hors réseau pendant un moment (je coupe les modules quand je ne suis pas a la maison)…. Il s’agit d un bug qui est normalement corriger dans les derniers firmware (j ai pourtant mis a jour les modules mais le pb continue).

J’ai donc decider de ne plus utiliser le “sleep mode” des modules et de simplement les alimenter a la demande avec 2 broches de la platine Arduino. J’ai applique la meme methode a tous les autres capteurs de la platine (Temperature, Humidite, et luminosite). Il ne sont alimenter que toutes les X minutes pour effectuer les mesures et les envoyer a la centrale. Voila la derniere version du code :

//Xbee library
#include <XBee.h>
//Deipara library
#include <Deipara.h>
// This library contains functions to set various low-power states for the ATmega328
#include <avr/sleep.h>
//RHT03 library
#include <DHT22.h>

// This variable is made volatile because it is changed inside an interrupt function
// Keep track of how many sleep cycles have been completed.
volatile int sleep_count = 0; 
// 75 loop needed since ze sleep for 8s and want to wait 10 minutes
//const int sleep_total = 75; 
const int sleep_total = 60; 

//pin
const int _InPinDht22 = 6;
const int _OutPowerLightSensor = 7;
const int _OutXbeePower1 = 8;
const int _OutXbeePower2 = 9;
const int _OutPowerDHT22 = 10;
const int _InLightPin = 4;

//Xbee objects
//create Xbee object to control a Xbee
XBee _Xbee = XBee(); 
//Create reusable response objects for responses we expect to handle
ZBRxResponse _ZbRxResp = ZBRxResponse();
//Setup a DHT22 instance
DHT22 _Dht22(_InPinDht22); //Setup a DHT22 instance 
//Global variable used in the program
int _CmdReceived = 0;
int _DataToSend = 0;

void goToSleep()   
{
  // The ATmega328 has five different sleep states.
  // See the ATmega 328 datasheet for more information.
  // SLEEP_MODE_IDLE -the least power savings 
  // SLEEP_MODE_ADC
  // SLEEP_MODE_PWR_SAVE
  // SLEEP_MODE_STANDBY
  // SLEEP_MODE_PWR_DOWN -the most power savings
  // I am using the deepest sleep mode from which a
  // watchdog timer interrupt can wake the ATMega328
  //digitalWrite(_OutDebugLed, HIGH);

  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode.
  sleep_enable(); // Enable sleep mode.
  sleep_mode(); // Enter sleep mode.
  // After waking from watchdog interrupt the code continues
  // to execute from this point.

  sleep_disable(); // Disable sleep mode after waking.
  //digitalWrite(_OutDebugLed, LOW);                   
}

void watchdogOn() 
{ 
  // Clear the reset flag, the WDRF bit (bit 3) of MCUSR.
  MCUSR = MCUSR & B11110111;

  // Set the WDCE bit (bit 4) and the WDE bit (bit 3) 
  // of WDTCSR. The WDCE bit must be set in order to 
  // change WDE or the watchdog prescalers. Setting the 
  // WDCE bit will allow updtaes to the prescalers and 
  // WDE for 4 clock cycles then it will be reset by 
  // hardware.
  WDTCSR = WDTCSR | B00011000; 

  // Set the watchdog timeout prescaler value to 1024 K 
  // which will yeild a time-out interval of about 8.0 s.
  WDTCSR = B00100001;

  // Enable the watchdog timer interupt.
  WDTCSR = WDTCSR | B01000000;
  MCUSR = MCUSR & B11110111;
}

ISR(WDT_vect)
{
  sleep_count ++; // keep track of how many sleep cycles have been completed.
}

void setup(void) 
{
  pinMode(_OutPowerLightSensor, OUTPUT);
  pinMode(_OutPowerDHT22, OUTPUT);
  pinMode(_OutXbeePower1, OUTPUT);
  pinMode(_OutXbeePower2, OUTPUT);
  pinMode(_InLightPin, INPUT);

  digitalWrite(_OutPowerLightSensor, LOW);
  digitalWrite(_OutPowerDHT22, LOW);
  digitalWrite(_OutXbeePower1, LOW);
  digitalWrite(_OutXbeePower2, LOW);

  // start serial
  _Xbee.begin(XBEE_SPEED); 
  Serial.begin(XBEE_SPEED);

  delay(500);

  watchdogOn(); // Turn on the watch dog timer.
}

void loop(void) 
{
  goToSleep(); // ATmega328 goes to sleep for about 8 seconds and continues to execute code when it wakes up

  if (sleep_count > sleep_total) 
    {
    sleep_count = 0;
    //First we power the Xbee so it has time to reach the network and the other captor
    digitalWrite(_OutXbeePower1, HIGH);
    digitalWrite(_OutXbeePower2, HIGH);
    digitalWrite(_OutPowerDHT22, HIGH);
    digitalWrite(_OutPowerLightSensor, HIGH);
    //Then wait 0.5s to be ready 
    delay(1000);
    //we read the light sensor value
    unsigned int aLightValue = analogRead(_InLightPin);
    //we turn it off
    digitalWrite(_OutPowerLightSensor, LOW);
    delay(2000);
    //Then read T
    DHT22_ERROR_t errorCode;
    errorCode = _Dht22.readData();
    int aTempValue=_Dht22.getTemperatureCAsInt();
    int aHumidityValue=_Dht22.getHumidityAsInt();

    digitalWrite(_OutPowerDHT22, LOW);

    //we wait few second to be sure Xbee reach the network
    delay(3000);
    //we send the info
    sendZigBeeMsg2(_Xbee,36,aLightValue,COORD_ADDR);
    delay(50);
    sendZigBeeMsg2(_Xbee,37,aTempValue,COORD_ADDR);
    delay(50);
    sendZigBeeMsg2(_Xbee,38,aHumidityValue,COORD_ADDR);
    //we turn off the xbee module
    digitalWrite(_OutXbeePower1, LOW);
    digitalWrite(_OutXbeePower2, LOW);
  }
}

Grâce a ce nouveau code/design le module ne consomme que 1.6mA en veille et aux alentours de 40mA lorsqu’il se réveille pour effectuer les mesures toutes les X minutes (toutes les 9 minutes pour l instant). Voila une photo du montage final :

20130517_113148