Google plus sing-in API

Maintenant que je connais les bases de Flask je peux continuer mon test de l’API Google Plus.

La documentation la plus a jour est disponible ICI : https://developers.google.com/+/ et je vous conseil aussi de jeter un œil au tutorial disponible ICI : http://www.googleplusdaily.com/2013/03/add-google-sign-in-in-6-easy-steps.html

J’ai réalisé un site web minimaliste en utilisant Jquery Mobile et Flask. Le site offre la possibilité de se logger avec son compte Google grâce a la méthode de sign in de Google plus.

Création du client ID

Pour pouvoir utiliser les services de google il faut déclarer notre projet dans la console disponible a l’adresse suivante :

https://console.developers.google.com/project

Il faut ensuite créer un nouveau projet (ou utiliser un de vos projets existants). Il faut ensuite activer l API Google + pour ce projet en cliquant sur API.

GoogleApiOn

Il faut enfin créer une clé d’identification pour utiliser l’API. Pour cela on clique sur le sous menu “credentials” situe en dessous du menu API.

GoogleApiCle

 Site web

Le site est très simple et repose sur l’utilisation de Flask (voir mon article précédant). L’utilisation de l’API google est assez bien documente (voir liens au début de l’article) et je ne vais pas répéter toutes les étapes.

L’ensemble du code est disponible sur bitbucket ICI :
https://bitbucket.org/charly37/googlesign/overview

Il suffit de remplacer le client ID présent dans le code par celui crée dans l’étape précédente :

class="g-signin"
data-callback="signinCallback"
data-clientid="67694002414-idd640ukscsntd4nmn80gg66i6sirup1.apps.googleusercontent.com"
data-cookiepolicy="single_host_origin"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-scope="https://www.googleapis.com/auth/plus.login">

Le résultat :

GoogleSignInApiLogin

A la fin du logging le site affichera le nom de l’utilisateur :

GoogleApiResult

Voila 😉

 

Flask

J’ai décidé de tester le système de “sign-in” de google pour authentification des gens sur un site web. En regardant plusieurs vidéos de google DEV sur youtube j’ai remarqué qu’ils utilisent souvent un serveur web python : Flask

Voilà donc quelques tests rapides de ce que l’on peut faire avec Falsk.

Test basique

Création d’un site qui affiche une string de bienvenu.

##############
#Test basique#
##############
#On creer un decorateur qui prend en parametre une route correspondant a une page web
@app.route('/')
#on decore notre fonction avec le decorateur precedement creer. Cette fonction sera en charge de creer la page web correspondant a la route du decorateur
def index():
    return "Hello"

#On refait un autre test pour une autre page web. Pour info le nom de la fonction n a aucun importance
@app.route('/test1')
def unTest():
    return "Test 1

FlaskBasic

Test multi-route

Plusieurs adresses renvoyant vers le même site basique.

##################
#Test multi route#
##################
#On refait un autre test pour une autre page web. On peut avoir plusieur decorateur pour un seul fonction
@app.route('/test31')
@app.route('/test32')
@app.route('/test33')
def unTest():
    return "Meme page pour test31 et test32 et test33"

FlasMultiRoute

Test route dynamique

Le site est un peu plus complexe car il utilise des informations passe dans l’adresse du site.

######################
#Test route dynamique#
######################
@app.route('/dynamique/<nom>')
#Attention : le parametre de la route doit etre le meme que le nom de l argument dans la fonction
def routeDynamik(nom):
    return "Bonjour : " + nom

FlaskComplexe

Test route redirection

le site vous redirige vers google en utilisant le code erreur 301

########################
#Test route redirection#
########################
@app.route('/testRedirect')
def testRedirect():
    return redirect('http://www.google.fr')

Test template

Le site est créé à partir d’un Template html

################
#Test templates#
################
@app.route('/template')
#Il faut absolument que la page correspondante html existe dans le repertoire template. La commande ll permetera de le verifier avec ll templates/hello_world.html
def TestTemplate():
    return render_template('hello_world.html')

Il faut également créer un fichier html de Template dans le répertoire “/template” avec le nom correspondant. Le nom du répertoire doit être respecte.

[root@domU-12-31-39-14-5D-9B templates]# cat hello_world.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>hello</title>
    </head>

    <body>
        <h1>hello</h1>
    </body>
</html>

FalskTemplate

Test template dynamique

Le site crée à partir du Template prend en compte des informations passe depuis la fonction python.

#################################
#test avec template plus dynamik#
#################################
@app.route('/template2')
#Il faut absolument que la page correspondante html existe dans le repertoire template. La commande ll permetera de le verifier avec ll templates/hello_world.html
def TestTemplateidyna():
    return render_template('complex.html', titre="un titre de site", contenu="un contenu de site")

Comme pour l’exemple précédant il faut créer le Template html dans le répertoire template.

[root@domU-12-31-39-14-5D-9B templates]# cat complex.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>{{ titre }}</title>
    </head>

    <body>
        <h1>{{ titre }}</h1>
            {{ contenu }}
    </body>
</html>

FalskTemplateComplexe

L’ensemble du code est disponible sur bitbucket : https://bitbucket.org/charly37/decouverteflask

Depot docker

Création d’un dépôt d’image docker prive pour distribuer notre application sur un ensemble de nœuds distribues.

Pour ceux qui ne connaissent pas Docker : https://www.docker.io/

Un Dépôt d’image docker s’appelle un “registery”. Il s’agit d’un serveur code en python et demande donc certaines dépendance pour être installe….

Heureusement les gens de docker ont également créé une image docker qui contient tout ce qu’il faut pour mettre en place notre registery en quelques secondes. Le seul pré-requit est donc d’installer docker

Installation de docker

Pour tester j’utilise une centOs 6.4 sur AWS. L’installation de Docker est assez simple grâce à la documentation : http://docs.docker.io/en/latest/

[root@ip-10-170-79-155 conf]# sudo yum -y install docker-io

puis

[root@ip-10-170-79-155 conf]# sudo service docker start
 Starting cgconfig service:                                 [  OK  ]
 Starting docker:                                           [  OK  ]
 [root@ip-10-170-79-155 conf]#

Vérification de l’installation

La vérification de l’installation peut se faire simplement en démarrant un bash depuis un container contenant fedora

[root@ip-10-170-79-155 conf]# sudo docker run -i -t fedora /bin/bash
Unable to find image 'fedora' (tag: latest) locally
Pulling repository fedora
58394af37342: Download complete
0d20aec6529d: Download complete
511136ea3c5a: Download complete
8abc22fbb042: Download complete
bash-4.2# ls
bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
bash-4.2#

Maintenant que l’on a installé docker on va pouvoir créer notre repository privé.

Création d’un repository privé

Il suffit de récupérer un container docker qui contient le serveur python faisant office de repository avec toutes ses dépendances

[root@ip-10-235-32-145 conf]# docker pull samalba/docker-registry
Pulling repository samalba/docker-registry
2eabb5a82e71: Download complete
511136ea3c5a: Download complete
46e4dee27895: Download complete
476aa49de636: Download complete
8332c1d90a62: Download complete
324b0d2e019a: Download complete
c19da4fc3dea: Download complete
4b494adef24f: Download complete
10e80f2583d5: Download complete
76b4a87578b7: Download complete
ac854be3b13a: Download complete
1fd060b2bdb1: Download complete

Il suffit ensuite de démarrer le container

[root@ip-10-235-32-145 conf]# docker run -d -p 5000:5000 samalba/docker-registry
71e3adbb75eaad87e8f32462cd0963988092935f60fce9ffd74a43b852e942a7

On dispose maintenant d’un registery docker que l’on peut utiliser pour déployer notre application. Il ne faut pas oublier d’ouvrir le port 5000 sur la machine ou tourne notre registery….

Utilisation du registery privé

Création d’une image docker

On va tester l’utilisation de notre registre privee depuis une autre machine. La première chose à faire est de créer une nouvelle image qui contient notre software. Pour cela on utilise la fonction build de docker.

La création d’une image est très bien expliquée sur les sites suivants :

Voilà le dockerfile correspondant à mon application :

#https://index.docker.io/search?q=centos
#https://www.docker.io/learn/dockerfile/level1/
#http://docs.docker.io/en/latest/use/builder/

#Image docker de base : Centos (https://index.docker.io/_/centos/)
FROM centos

#le mainteneur du package
MAINTAINER Charles Walker, charles.walker.37@gmail.com

# Usage: ADD [source directory or URL] [destination directory]
# It has to be a relative path ! It will not works if runing build with stdin like docker build -t TEST1 - < Dockerfile
ADD ./packages /root/packages
ADD ./Data /root/Data
ADD ./conf /root/conf
ADD ./AWS_Non1aData /root/AWS_Non1aData

#commande a lancer sur le container pdt sa creation
#RUN

#La commande a execute qd le container se lance
#le hash dans la commande indique un argument
ENTRYPOINT /root/conf/installAgent.sh #

#Port to "open"
EXPOSE 22 80 443 4001 4369 5000 5984 7001 8080 8091 8092 8140 10000 10001 10002 10003 11210 11211 14111 20022 21100 22222 48007 49007 50007

#le repetoire qu on monte depuis le host physique
VOLUME ["/ama"]

Je vais maintenant demander a docker de mon construire une nouvelle image a partir de ce dockerfile avec :

[root@ip-10-138-39-50 ~]# docker build -t TEST4 .
Uploading context 1.489 GB
Uploading context
Step 1 : FROM centos
 ---> 539c0211cd76
Step 2 : MAINTAINER Charles Walker, charles.walker.37@gmail.com
 ---> Using cache
 ---> 719b786c1be6
Step 3 : ADD ./packages /root/packages
 ---> Using cache
 ---> 6b65b75fd77c
Step 4 : ADD ./Data /root/Data
 ---> e34e5c199d29
Step 5 : ADD ./conf /root/conf
 ---> d438752ee616
Step 6 : ADD ./AWS_Non1aData /root/AWS_Non1aData
 ---> 419f91258841
Step 7 : ENTRYPOINT /root/conf/installAgent.sh #
 ---> Running in ad779fd56403
 ---> d6156694fbb6
Step 8 : EXPOSE 22 80 443 4001 4369 5000 5984 7001 8080 8091 8092 8140 10000 10001 10002 10003 11210 11211 14111 20022 21100 22222 48007 49007 50007
 ---> Running in 492ee8547e8b
 ---> c91f6583e370
Step 9 : VOLUME ["/ama"]
 ---> Running in 7b35f3a0dedd
 ---> b220758ee96e
Successfully built b220758ee96e

La vérification est simple :

[root@ip-10-138-39-50 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
TEST4               latest              b220758ee96e        8 minutes ago       1.782 GB
centos              6.4                 539c0211cd76        10 months ago       300.6 MB
centos              latest              539c0211cd76        10 months ago       300.6 MB

Upload d’image docker sur notre registery privé

On va maintenant pousser cette image sur notre registery local. Pour rappel ce dernier tourne sur un autre serveur AWS :

DockerAwsNode

On commencer par renommerl’image puisque Docker utilise le namespace présent dans le nom de l’image pour savoir sur quel registery il doit pousser.

[root@ip-10-238-143-211 ~]# docker tag TEST4 domU-12-31-39-14-5D-9B.compute-1.internal:5000/myrepo

Ainsi Docker va maintenant pousser cette image sur notre registery privé. Le push se fait de la manière suivante :

[root@ip-10-238-143-211 ~]# docker push domU-12-31-39-14-5D-9B.compute-1.internal:5000/myrepo
The push refers to a repository [domU-12-31-39-14-5D-9B.compute-1.internal:5000/myrepo] (len: 1)
Sending image list
Pushing repository domU-12-31-39-14-5D-9B.compute-1.internal:5000/myrepo (1 tags)
539c0211cd76: Image successfully pushed
155d292465db: Image successfully pushed
0cee42788752: Image successfully pushed
9eadab9e81c4: Image successfully pushed
3baae99c022d: Image successfully pushed
54cd5c7eccc3: Image successfully pushed
b58b382eb217: Image successfully pushed
f768630bab4c: Image successfully pushed
feab39ed50f7: Image successfully pushed
Pushing tags for rev [feab39ed50f7] on {http://domU-12-31-39-14-5D-9B.compute-1.internal:5000/v1/repositories/myrepo/tags/latest}

 Utilisation de notre image

Nous allons maintenant créer un 3eme nœud AWS pour downloader notre image docker et l’utiliser.

On va récupérer notre image depuis notre nouveau noeud avec :

[root@ip-10-73-145-136 conf]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
[root@ip-10-73-145-136 conf]# docker pull domU-12-31-39-14-5D-9B.compute-1.internal:5000/myrepo
Pulling repository domU-12-31-39-14-5D-9B.compute-1.internal:5000/myrepo
155d292465db: Download complete
0cee42788752: Download complete
feab39ed50f7: Download complete
539c0211cd76: Download complete
b58b382eb217: Download complete
f768630bab4c: Download complete
3baae99c022d: Download complete
54cd5c7eccc3: Download complete
9eadab9e81c4: Download complete
[root@ip-10-73-145-136 conf]# docker images
REPOSITORY                                              TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
domU-12-31-39-14-5D-9B.compute-1.internal:5000/myrepo   latest              feab39ed50f7        3 hours ago         1.782 GB
[root@ip-10-73-145-136 conf]#

Maintenant que l’on a notre image on va lancer son exécution avec un paramètre. Pour rappel le container va essayer de lancer un script shell “installAgent.sh” au démarrage. Ce script a besoin d’une adresse IP que je passe donc en paramètrede la commande run de docker.

[root@ip-10-239-7-206 conf]# docker run domU-12-31-39-14-5D-9B.compute-1.internal:5000/myrepo 127.0.0.1
**********Install OS Packages with YUM**********
Loaded plugins: fastestmirror
Error: Cannot retrieve repository metadata (repomd.xml) for repository: base. Please verify its path and try again
Could not retrieve mirrorlist http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=os error was
14: PYCURL ERROR 7 - "Failed to connect to 2a02:2498:1:3d:5054:ff:fed3:e91a: Network is unreachable"
Loaded plugins: fastestmirror

Le container est lancé correctement. Mon script s’exécute avec le paramètre spécifié dans le run de docker. Cependant mon script ne fonctionne pas car yum ne réussit pas à récupérer les packages.

YUM ne réussit pas installer les packages car il essaye de communiquer avec les serveur distant en IPV6 et docker ne supporte pas l IPv6 :

Je dois donc trouver une solution pour mon script mais cela n’a aucun rapport avec notre sujet actuel.

Voilà donc comment mettre en place un registery privé Docker pour partager une application propriétaire dans notre Cluster.

Android Widget V2 : Ajout Wifi

Suite de mon precedant artcile sur la creation d’un widget android :
http://djynet.net/?p=585

J’ai décidé d’ajouter un bouton supplémentaire pour changer l’état du wifi sur le téléphone. La premiere etape est d’ajouter la possibilite de controler le widi depuis notre application en ajoutant les permissions dans le manifest :

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

Puis ajouter un bouton dans le layout du widget :

<Button
        android:id="@ id/sync_button2"
        android:layout_width="40dp"
        android:layout_height="match_parent"
        android:background="@color/green"
        android:text="@string/button1"
        android:layout_toLeftOf="@ id/sync_button"/>

Il est ensuite possible d’utiliser la classe android “wifimanager” pour intergair avec le module wifi.

import android.net.wifi.WifiManager;
...
 WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
        if (wifiManager.isWifiEnabled()) {
            wifiManager.setWifiEnabled(false);
        } else {
            wifiManager.setWifiEnabled(true);
        }

Dans notre cas on utilisera un event/broadcast pour déclenché cette action. Il s’agit du même type de code utilise dans mon article précédant.

Screenshots_2014-02-12-21-15-57

L’ensemble du code est disponible sur Bitbucket :

https://charly37@bitbucket.org/charly37/wifi3gstarterv2

 

Creation widget android

Dans cet article je vais expliquer comment creer un widget pour android. Le but etant d’avoir un widget sur le bureau avec un bouton et un compteur de clique.

Widget layout

La première étape est la création du layout pour notre widget. Ce dernier sera compose d’un « textview » pour afficher notre compteur et d’un bouton pour augmenter le compteur. On Placera le tout dans un « relative layout » avec la zone de text a gauche et le bouton a droite.

Voila le xml correspondant :

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/yellow">

    <Button
        android:id="@ id/sync_button"
        android:layout_width="40dp"
        android:layout_height="match_parent"
        android:background="@color/blue"
        android:layout_alignParentRight="true"
        android:text="" />

    <TextView
        android:id="@ id/desc"
        android:layout_width="80dp"
        android:layout_height="match_parent"
        android:maxLines="1"
        android:text=""
        android:background="@color/pink"
        android:textColor="#fcfcfc"
        android:textSize="13sp"
        android:textStyle="normal" />

</RelativeLayout>

Ce fichier xml est a place dans /res/layout/widget_layout.xml

PS : Ce widget utilise des couleurs définies dans le fichier colors.xml. Cette méthode est décrite dans un de mes précédents posts.

Widget info

La seconde étape est de créer un fichier xml qui décrit notre widget. Ce fichier xml contient les informations générale de notre widget comme sa taille et la fréquence a laquelle on souhaite que l ‘OS l’update. Pour éviter une trop grand utilisation de la batterie Android ne prendra pas en compte les valeurs inférieur a 30 minutes.

Voila le fichier xml :

<?xml version="1.0" encoding="utf-8"?>

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/widget_layout"
    android:minHeight="40dp"
    android:minWidth="120dp"
    android:previewImage="@drawable/ic_launcher2"
    android:resizeMode="horizontal|vertical"
    android:updatePeriodMillis="1800000" >
</appwidget-provider>

TODO

AppWidgetProvider

Il s’agit d’une classe qui va se charger de la mise a jour du layout lors de la réception de l’événement “android.appwidget.action.APPWIDGET_UPDATE”. Pour cela la classe hérite de la classe de base android “AppWidgetProvider”.

public class MyAppWidgetProvider extends AppWidgetProvider

Cette classe facilite la création de widget en étendant la classe android générique de réception d’événement “BroadcastReceiver”.

Notre classe “MyAppWidgetProvider” doit donc implémenter la méthode “onUpdate” qui est appele a chaque update de notre widget. Dans cette méthode on va updater la view “remote” du widget. En effet le widget est embarque dans le homescreen et utilise donc une “remote view”.

On définie aussi le comportement du widget lors de l’appuie sur le bouton. Plus exactement on va générer un événement “net.djynet.intent.action.UPDATE_WIDGET” :

Intent intent = new Intent();
intent.setAction("net.djynet.intent.action.UPDATE_WIDGET");
return PendingIntent.getBroadcast(context, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);

Cet événement sera capture par une autre classe décrite ci-dessous.

BroadcastReceiver

Cette seconde classe sera en charge de gérer l’événement “net.djynet.intent.action.UPDATE_WIDGET” crée lors d’un clique sur le bouton. Pour cela notre classe va également hérité de”BroadcastReceiver” (et non AppWidgetProvider car il ne s’agit pas directement d’un événement standard android pour les widgets)

public class MyBroadcastReceiver extends BroadcastReceiver

La méthode “onreceive” doit être surcharge pour gérer l’événement de clique avec :

public void onReceive(Context context, Intent intent) {
        Log.i(context.getString(R.string.app_name_log), "Entering MyBroadcastReceiver:onReceive");
        if (intent.getAction().equals("net.djynet.intent.action.UPDATE_WIDGET")) {
            updateWidgetPictureAndButtonListener(context);
        }
    }

Tout comme notre “AppWidgetProvider” cette méthode va mettre a jour la vue de notre widget en indiquant le nombre de clique effectue sur le bouton.

private void updateWidgetPictureAndButtonListener(Context context) {
        Log.i(context.getString(R.string.app_name_log), "Entering MyBroadcastReceiver:updateWidgetPictureAndButtonListener");
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout);

        // updating view
        remoteViews.setTextViewText(R.id.desc, getDesc(context));

        // re-registering for click listener
        remoteViews.setOnClickPendingIntent(R.id.sync_button, MyAppWidgetProvider.buildButtonPendingIntent(context));

        MyAppWidgetProvider.pushWidgetUpdate(context.getApplicationContext(),remoteViews);
    }

Manifest

Pour rappel le manifest d’une application android permet au système de savoir ce que fait notre application et ses interactions avec le système android.

Dans notre manifest on va créer 2 « receiver » pour notre widget. On utilise le tag « receiver » pour les widget car ils font partis des « boradcast receiver ». Cela signifie qu’ils fonctionne sur la réception d’événements. Pour chaque receiver on indique donc l’événement et la classe qui sera en charge de sa gestion.

  • android.appwidget.action.APPWIDGET_UPDATE : Il s’agit de l’événement trige par le systeme lorsque ce dernier pense qu il est nécessaire d’updater le widget. La classe en charge de la gestion de cet événement est “net.djynet.wifistarter3g_main.MyAppWidgetProvider”
  • net.djynet.intent.action.UPDATE_WIDGET : Il s’agit de l’événement qu on va triger lors d’un appuie sur le bouton du widget. La classe en charge de la gestion de cet événement est “net.djynet.wifistarter3g_main.MyBroadcastReceiver”.

On va également indiquer le fichier de configuration associe a notre widget dans le tag « meta-data ».

Voila notre manifest :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.djynet.wifistarter3g_main" >

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <receiver android:name="net.djynet.wifistarter3g_main.MyAppWidgetProvider"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/demo_widget_provider" />
        </receiver>

        <receiver android:name="net.djynet.wifistarter3g_main.MyBroadcastReceiver"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="net.djynet.intent.action.UPDATE_WIDGET" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/demo_widget_provider" />
        </receiver>

    </application>

</manifest>

 Resultat

Voila le résultat une fois le widget installe sur le bureau :

WidgetResult1

Les appuies sur le bouton (en bleue a droite du widget) vont augmenter le compteur affiche comme on peut le voir ci dessous.

Widget2

Le résultat n’est pas très jolie mais permet de bien visualise les différents éléments du layout.

L’ensemble du code est disponible sur bitbucket ICI.

Couleur fond dans layout android

Pour mettre une couleur de fond a un layout Android on peut directement utiliser le code couleur dans le xml du layout :

android:background="#DC143C"

mais il est préférable de définir nos couleurs dans un fichier de ressource xml a part auquel on fera référence dans le xml du layout.

Pour ça il faut donc créer un fichier xml dans les ressource du projet. Par exemple créer le fichier xml colors.xml dans le répertoire /res/values

On peut ensuite définir nos couleurs dans ce fichier :

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="red">#FF0000</color>
    <color name="green">#58FA82</color>
    <color name="blue">#81BEF7</color>
    <color name="yellow">#F7FE2E</color>
    <color name="pink">#FA58F4</color>
</resources>

L’utilisation des couleurs est maintenant possible dans le layout de notre application/widget avec :

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/yellow">

    <RelativeLayout
        android:id="@+id/buttonContainer"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@color/red"
        android:layout_alignParentBottom="true" >

        <Button
            android:id="@+id/sync_button"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:background="@color/blue"
            android:layout_centerInParent="true"
            android:text="" />
    </RelativeLayout>
...

Librarie EnOcean pour TCM 310 sur Arduino

Suite a mon article sur le décodeur EnOcean j’ai décidé de créer une libraire pour Arduino pour le TCM310.

Le code est extrêmement simple avec une classe “EnOcean” reprenant les éléments de la trame envoyé par le TCM310.

EnOceanMsg::EnOceanMsg()
{
  _dataLength1 = 0;
  _dataLength2 = 0;
  _optLength = 0;
  _packetType = 0;
  _headerCrc8 = 0;
  _org = 0;
  _payload = 0;
  _senderId1 = 0;
  _senderId2 = 0;
  _senderId3 = 0;
  _senderId4 = 0;
}

Cette classe possède une méthode “decode” qui utilise la lib software de l’arduino pour décoder ce qui arrive sur l USART :

void EnOceanMsg::decode()
{
while(Serial1.available() > 0)
{
    //Serial.println("Decoding");
    uint8_t aChar = Serial1.read();
    switch(_pos) 
    {
        case 0:
        if (aChar == START_BYTE) 
        {
            _pos++;
            //Serial.println("START");
        }
        break;

        case 1:
        // length msb
        _dataLength1=aChar;
        _pos++;
        //Serial.print("length msb:");
        //Serial.println(_dataLength1, HEX);
        break;
...

La classe offre également une méthode “pretty print” pour afficher ses éléments (et donc les informations reçu du TCM 310) :

void EnOceanMsg::prettyPrint()
{
Serial.println("Pretty print start");

Serial.print("length:");
char buf1[9];
sprintf(buf1, "%04x", getPacketLength());
Serial.println(buf1);
//Serial.println(getPacketLength());

Serial.print("Optional length:");
Serial.println(_optLength);

Serial.print("Packet type:0x");
Serial.println(_packetType, HEX);

La dernière version du code de la librairie est disponible sur BitBucket :
https://bitbucket.org/charly37/arduino_enocean_lib

Voila un exemple d’utilisation de la lib avec mon interrupteur EnOcean :

#include 

EnOceanMsg aMsg;

void setup()
{
  //USB
  Serial.begin(9600);
  //Pin 0/1
  Serial1.begin(57600);
}

void loop()
{
  delay(500); 
  aMsg.decode();
  Serial.println("Working");
  if (aMsg.getPayload() == 0x50)
  {
    Serial.println("OKOK");
  }
}

Ce qui produira le résultat suivant sur le moniteur série :

Working
Working
Pretty print start
length:0007
Optional length:7
Packet type:0x1
ORG:0xF6
Payload:0x70
Sender Id:8ba977
Pretty print end
Working
Pretty print start
length:0007
Optional length:7
Packet type:0x1
ORG:0xF6
Payload:0x0
Sender Id:8ba977
Pretty print end
Working
Working

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 !

Editeur de presentation ImpressJs

Pour ce qui ne connaissent pas encore ImpressJs :
http://bartaz.github.io/impress.js/#/bored

Cependant il est assez long et fastidieux de faire une présentation avec puisqu il faut “la programmer” en html/css. Pour les personnes plus presses ou moins experte dans le domaine il existe quelques éditeur en ligne. J’ai décidé d en tester quelqu’un…

Strut semble être pour le moment le plus efficace.

 

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.