Skip to content

Blogs de Développeurs: Aggrégateur de Blogs d'Informatique sur .NET, Java, PHP, Ruby, Agile, Gestion de Projet

Forum Logiciel

Forum Logiciel : diffusion de connaissance et d’informations sur toutes les activitĂ©s liĂ©es au dĂ©veloppement d’applications informatiques en entreprise.

Blog Individuel

Configurer une application web pour Google App Engine

Developpef - Paul-Emmanuel Faidherbe - mer, 09/20/2017 - 20:30

GAE requiert une configuration bien prĂ©cise, voir spĂ©cifique, de l'application web destinĂ©e Ă  ĂȘtre dĂ©ployĂ©e sur ces serveurs. Je vais essayer de dĂ©tailler ci-dessous les Ă©lĂ©ments que j'ai rencontrĂ©.

Descripteur de déploiement

En plus du fichier web.xml commun à toutes les applis web, GAE demande la mise en place d'un nouveau fichier de description spécifique, appengine-web.xml présenté dans ce chapitre de la documentation.

Validation des fichiers XML

Le serveur de test peut parfois poser des problÚmes lors de la phase de validation Spring des fichiers XML. Pour la désactiver, il faut indiquer dans le fichier web.xml une classe spécifique de configuration :


<context-param>
<param-name>contextClass</param-name>
<param-value>my.package.MyXmlWebApplicationContext</param-value>
</context-param>

Pour ce besoin, son contenu est assez simple :


import com.google.appengine.api.utils.SystemProperty;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.web.context.support.XmlWebApplicationContext;

public class MyXmlWebApplicationContext extends XmlWebApplicationContext {
@Override
protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {
super.initBeanDefinitionReader(beanDefinitionReader);
if (SystemProperty.environment.value() == SystemProperty.Environment.Value.Development) {
beanDefinitionReader.setValidationMode(XmlBeanDefinitionReader.VALIDATION_NONE);
}
}
}
persistence.xml

Afin de lier notre application au datastore de Google, voici un exemple basique de fichier de persistence :


<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

<persistence-unit name="transactions-optional">
<provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
<properties>
<property name="datanucleus.NontransactionalRead" value="true"/>
<property name="datanucleus.NontransactionalWrite" value="true"/>
<property name="datanucleus.ConnectionURL" value="appengine"/>
</properties>
</persistence-unit>

</persistence>
DĂ©claration du bean "entityManagerFactory" via Spring

Afin de rendre effective la connexion au datastore, il est nécessaire d'ajouter au fichier application-context.xml de Spring :


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="entityManagerFactory" class="com.my.MyEntityManagerFactory"/>
</beans>

Voici le contenu de la classe indiquée :


import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
import org.springframework.orm.jpa.LocalEntityManagerFactoryBean;

public class MyEntityManagerFactory extends LocalEntityManagerFactoryBean {
@Override
protected EntityManagerFactory createNativeEntityManagerFactory() throws PersistenceException {
return EMF.get();
}
}

La classe EMF est tirée des préconisations Google (https://developers.google.com/appengine/docs/java/datastore/jpa/overview?hl=fr) :


import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public final class EMF {
private static final EntityManagerFactory emfInstance =
Persistence.createEntityManagerFactory("transactions-optional");

private static EntityManager entityManager = emfInstance.createEntityManager();

private EMF() {}

public static EntityManagerFactory get() {
return emfInstance;
}

public static EntityManager getEntityManager() {
return entityManager;
}
}

Avec ces éléments, vous devriez pourvoir démarrer votre application rapidement.

Catégories: Blog Individuel

Gestion de l'authentification sur Google App Engine

Developpef - Paul-Emmanuel Faidherbe - mer, 09/20/2017 - 20:28

Lors de la création d'une application sur la plateforme GAE, il est possible de configurer l'usage des comptes Google pour s'y connecter, comme décrit ici : Configuration de l'authentification de votre application

En mode développement, le serveur de test simule automatiquement cette utilisation de compte Google et met en place un systÚme de redirection vers une page de connexion spécifique (https://developers.google.com/appengine/docs/java/tools/devserver#Using_Users) :

L'utilisateur connecté sera alors accessible simplement avec :


import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.api.users.User;
...
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();

Pour ce qui est de la déconnexion, il faut créer une redirection vers l'URL gérée par Google. Pour ce faire, voici un exemple de servlet :


import com.google.appengine.api.users.UserServiceFactory;
import java.io.IOException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.logging.Level;
import java.util.logging.Logger;

public class LogoutController {

@RequestMapping(method = RequestMethod.GET)
public void logout(HttpServletRequest request, HttpServletResponse response) {

SecurityContextHolder.clearContext();

// Remove the cookie
Cookie terminate = new Cookie(
TokenBasedRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY,
null);
terminate.setMaxAge(-1);
terminate.setPath(request.getContextPath() + "/");
response.addCookie(terminate);
try {
response.sendRedirect(UserServiceFactory.getUserService().createLogoutURL("/"));
} catch (IOException ex) {
Logger.getLogger(LogoutController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

Hope this helps!

Catégories: Blog Individuel

Spring et DWR

Developpef - Paul-Emmanuel Faidherbe - mer, 09/20/2017 - 20:27

Direct Web remoting est un framework Ajax permettant un lien direct entre Javascript et Java coté serveur.

D'apparence assez simple, son intégration avec Spring peut rapidement devenir compliquée, notamment à cause de la gestion des namespaces dans le fichier XML de configuration. En effet, les versions récentes de DWR fournissent un namespace facilitant l'écriture des éléments spécifiques :


<dwr:controller id="dwrController" debug="true"/>
<dwr:configuration>...</dwr:configuration>

Mais puisque tout n'est pas rose, j'ai été confronté à une erreur récurrente au démarrage du contexte Spring : No bean named '__dwrConfiguration' found...

Quelque soit la version du namespace utilisé, pas moyen de m'en sortir... Voici donc comment revenir à une configuration plus simple basée sur des éléments XML plus classiques :

application-context-dwr.xml :


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd">

<dwr:url-mapping />

<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />

<bean id="myDwrServerBean" class="my.package.MyDwrServerBean">
<dwr:remote javascript="serverBridge"></dwr:remote> <!-- nom de l'objet javascript utilisable -->
</bean>



<bean id="__dwrController" class="org.directwebremoting.spring.DwrController">
<property name="configurators">
<list>
<ref bean="__dwrConfiguration"/>
</list>
</property>
<property name="debug" value="true"/>
</bean>

<bean id="__dwrConfiguration" class="org.directwebremoting.spring.SpringConfigurator">
<property name="creators">
<map>
<entry key="firstBean">
<bean class="org.directwebremoting.spring.CreatorConfig">
<property name="creator">
<bean class="org.directwebremoting.spring.BeanCreator">
<property name="bean" ref="myDwrServerBean"/>
<property name="javascript"><value>serverBridge</value></property>
</bean>
</property>
</bean>
</entry>
</map>
</property>
<property name="converters">
<map>
<entry key="my.package.MyDwrServerBean">
<bean class="org.directwebremoting.spring.ConverterConfig">
<property name="type">
<value>bean</value>
</property>
</bean>
</entry>
</map>
</property>
</bean>
</beans>

Il est Ă©galement possible de configurer DWR via un bean dans le contexte Spring en utilisant le FluentConfigurator.

En espérant vous avoir fait économiser quelques heures de recherches!

Catégories: Blog Individuel

Arduino : XBee Ethernet data logger

Developpef - Paul-Emmanuel Faidherbe - mer, 09/20/2017 - 20:25

AprÚs plusieurs semaines de galÚre, j'ai décidé de rassembler ici tous les éléments qui m'ont permis, tant bien que mal, de mettre en place l'installation suivante :

D'un cÎté, un module XBee transmettant les informations d'un capteur de température (LM35). De l'autre, un second XBee relié à un Seeduino ATMega 2560 (similaire à un Arduino) qui enregistre toutes les mesures reçues sur une carte SD et expose le fichier créé via une connexion Ethernet. Voici le schéma du montage :

Avant d'aller plus loin, il est indispensable de faire un point sur la notion de SPI afin de comprendre le fonctionnement de notre montage.

SPI est un bus de communication basé sur les principes de Maitre et Esclave. Il est composé de 4 canaux. Pour ne pas plagier un trÚs bon cours existant sur le site rocketnumbernine, voici en quelques mots son fonctionnement :

Each end of a SPI connection is acting in one of two roles - Master or Slave. The master is responsible for initiating and controlling the communication.

SPI Master/Slave Connections

The basic mode of operation is very simple: When the master wishes to initiate transfer of data:
  1. It sets the SS (Slave Select - often called CS - chip select) pin low to tell the slave that communication is about to start
  2. The master writes a bit of information onto the MOSI (Master Out Slave In) wire (sets it to 0 or 1) and the slave does the same on the MISO wire (either of these can be omitted if the data transfer is one way)
  3. As the master ticks the clock line SCLK it will read the value of MISO (Master In Slave Out) wire (which the Slave has written) and the slave will read the value of the MOSI wire (whether the data is sampled as the clock rises or falls depends on which mode is in operation)
  4. The process is repeated from (b), transferring a bit of data on each pulse of the clock until all data is transferred

Ce bus SPI est accessible via les broches ICSP (Arduino UNO et Mega 2560) ET les broches 11,12,13 (pour le UNO) ou 50,51,52 (pour le Mega 2560).

Un Ă©lĂ©ment important est le Chip Select : il s'agit de la broche qui permet de choisir le pĂ©riphĂ©rique cible de l'Ă©change. Pour dĂ©sactiver un pĂ©riphĂ©rique, il faut passer la broche en niveau haut et pour l'activer, en niveau bas. Un seul pĂ©riphĂ©rique ne peut ĂȘtre activĂ© Ă  la fois car les trois broches de communication MOSI, MISO et SCK sont partagĂ©es.

Sur l'Arduino UNO (Revision 3), le Mega 2560 (Rev 3) et sur le shield Ethernet (Rev 3), on trouve le CS :

  • sur la broche A4 pour la carte SD
  • sur la broche A10 pour l'Ethernet

C'est grĂące Ă  cette correspondance des broches qu'il est possible de simplement empiler les cartes sans avoir Ă  faire de connexions supplĂ©mentaires. Il est tout de mĂȘme possible, si vous ne souhaitez pas empiler les cartes, de relier les broches comme indiquĂ© sur le schĂ©ma. Attention cependant, ceci est impossible sur le shield Ethernet car seules les broches CS sont utilisĂ©es et reliĂ©es directement Ă  l'ICSP. Toutes les autres broches ne servent qu'Ă  transfĂ©rer les connexions Ă  une Ă©ventuelle autre carte supperposĂ©e.

Revenons donc à notre projet. La carte Ethernet est apposée sur l'ATMega 2560, le module XBee principal (coordinateur) relié directement au Serial1 : broches RX1 et TX1 (croisées avec les RX/TX du XBee).

CÎté logiciel maintenant : l'application doit, au démarrage, aller lire un fichier de configuration sur la carte SD et initialiser une connexion Ethernet. Pour bien démarrer, voici le code de la fonction setup() :


void setup() {
pinMode(10, OUTPUT);
pinMode(4, OUTPUT);
//
pinMode(53, OUTPUT);
digitalWrite(53, HIGH);
/* disable all slaves */
// disable Ethernet
digitalWrite(10, HIGH);
delay(5);
// disable SD
digitalWrite(4, HIGH);
delay(5);

/* read config file */
// init SD
boolean sd = SD.begin(4);
delay(5);
// ... read file ...
// disable SD
digitalWrite(4, HIGH);
delay(5);
}

A noter qu'il est trÚs important de désactiver à la main l'Ethernet aprÚs son initialisation car la librairie ne le fait pas! Sur un ATMega 2560, il faut également obligatoirement définir la broche de Hardware SS (53) en sortie.

Ensuite, afin que le programme puisse à la fois recevoir en continu des paquets de données XBee à écrire sur la carte SD et assurer son rÎle de serveur web, voici, sous forme algorithmique, le déroulement du code à mettre en place :


void loop() {
- Vérifier la présence d'un packet XBee
- si un paquet a été reçu :
- traiter les informations du paquet
- désactiver l'Ethernet : digitalWrite(10, HIGH)
- activer la carte SD : digitalWrite(4, LOW)
- Ă©crire sur la carte SD
- désactiver la carte SD : digitalWrite(4, HIGH)
- Vérifier la réception d'une requete Ethernet :
- si une requete a été reçue :
- désactiver la carte SD : digitalWrite(4, HIGH)
- activer l'Ethernet : digitalWrite(10, LOW)
- générer la réponse HTTP
- fermer la connexion client
- désactiver l'Ethernet : digitalWrite(10, HIGH)
}

Normalement, la gestion de l'activation/dĂ©sactivation de chaque pĂ©riphĂ©rique SD ou Ethernet est gĂ©rĂ©e en interne par les librairies correspondantes, mais je vous conseille de ne pas hĂ©siter Ă  le faire Ă©galement manuellement afin de renforcer votre programme (on n'est jamais mieux servi que par soi-mĂȘme!).

Un conseil supplémentaire : il est préférable d'ajouter quelques délais aprÚs chaque dés/activation de périphérique (via la méthode delay()), au moins pendant la phase de développement, afin d'éviter tout conflit de communication sur le bus SPI (par les broches partagées) qui pourrait engendrer, par exemple, la destruction de la carte SD (qui arrive plus vite qu'on ne le croit!).

Ci-dessous sont dĂ©crites les erreurs les plus communes qui peuvent ĂȘtre rencontrĂ©es :

  • Impossible de dĂ©marrer la carte SD :
    Si SD.begin() renvoie false, il faut dans un premier temps vĂ©rifier les connexions SPI (MOSI, MISO) dans le cas oĂč elles auraient Ă©tĂ© rĂ©alisĂ©es autrement que par les broches ICSP et dans un second temps s'assurer que seule sa broche CS est active.
  • Impossible de PING la carte Ethernet :
    Les requĂȘtes ping rĂ©pondent "Impossible de joindre l'hĂŽte" ("Host unreachable") et la LED TX de la carte ne s'allume jamais : vĂ©rifier Ă©galement que seule la broche CS de la carte Ethernet est active et qu'aucun autre pĂ©riphĂ©rique ne tente d'accĂ©der au bus SPI.

Vous voilĂ  prĂȘts! J'ai essayĂ© de regrouper ici les connaissances de base dont j'ai eu besoin et pour lesquelles j'ai du Ă©cumer nombre de blogs et forums. J'espĂšre que tout cela vous sera utile!

Catégories: Blog Individuel

Introduction au NoSQL avec Apache CouchDB

Developpef - Paul-Emmanuel Faidherbe - mer, 09/20/2017 - 20:24

Je vais vous montrer comment prendre en main facilement une base de données NoSQL, grùce à un exemple simple.

Nous allons créer une petite application utilisant Ektorp, une API de mapping par annotations et CouchApp, un utilitaire pour déployer des applications HTML5.

Création des données

Pour commencer, il suffit de crĂ©er un simple POJO reprĂ©sentant un objet mĂ©tier. Comme illustrĂ© dans la documentation Ektorp ici, il n'est mĂȘme pas nĂ©cessaire de mapper les attributs Ă  enregistrer. C'est mĂȘme le contraire, Ektorp part du principe que tous les attributs seront sauvegardĂ©s sauf ceux explicitement annotĂ©s comme ignorĂ©s! Un bon gain de temps...

Ensuite, quelques lignes suffisent pour implémenter les fonctionnalités primaires de CRUD :

Here's how a SofaRepository implemented with the generic repository looks like


public class SofaRepository extends CouchDbRepositorySupport {

public SofaRepository(CouchDbConnector db) {
super(Sofa.class, db);
}

}

This repository will have the following methods "out of the box":


SofaRepository repo = new SofaRepository(db);

repo.add(Sofa s);
repo.contains("doc_id");
Sofa sofa = repo.get("doc_id");
repo.update(Sofa s);
repo.remove(Sofa s);
List repo.getAll();

A ce stade, nous avons déjà de quoi mettre en place une moulinette pour insérer des données. Une fois ceci fait, il est possible de consulter le contenu de la base avec Futon, une interface web fournie par CouchDB, à l'adresse http://localhost:5984/_utils/ :

Initier l'application web

CouchDB propose une interface REST trĂšs pratique. Ce qui signifie que n'importe quel outil effectuant des requĂȘtes HTTP peut interroger directement la base, y compris un navigateur et... Ajax!

Seulement, comme certains yeux affûtés l'auront remarqué, CouchDB démarre par défaut sur le port 5984, ce qui rend impossible les accÚs directs via Ajax, par raison de sécurité. Si vous n'avez pas la main sur le serveur hébergeant la base afin de configurer le mécanisme HTTP "CORS", comme indiqué sur cette page, il vous faudra passer par CouchApp afin de déployer votre application sur le serveur interne de CouchDB (comme c'est le cas de Futon).

Un tutoriel trÚs concis explique comment générer et déployer une application basique :

En réalité, tous le fichiers composant cette application sont des documents au sens NoSQL que CouchDB gÚre comme tels. Tous les fichiers "statiques" (images, css, js...) sont des "_attachments".

Lister les documents

Imaginons que nos documents possÚdent un attribut "date", par lequel nous voulons les filtrer, entre une date de début et une de fin.

Nous allons commencer par créer une vue, qui va nous retourner la liste des documents identifiés par une clé issue de notre champ "date".

Ceci se fait par l'intermédiaire des fonctions view, fonctions Javascript pures appelées pour chaque document, pouvant servir de filtre (le cas échéant). Créons par exemple un fichier "by_date.js" dans le répertoire "/views/by_date/" de notre application. Voici donc un exemple de ce que nous cherchons :


function(doc) {
if(doc.date) {
emit(doc.date,doc);
}
}

Le résultat de notre fonction est accessible à l'adresse (objets JSON) : GET /[db]/_design/[appName]/_view/by_date/


{
"total_rows": 2,
"offset": 0,
"rows": [
{
"key": "2014/01/15 15:52:20",
"value": {...}
},

{
"key": "2014/01/30 18:04:11",
"value": {...}
}

]
}
Utiliser JQuery

Maintenant nous pouvons compléter le fichier "index.html" (situé dans "_attachments") afin d'ajouter des fonctionnalités. Mais il faut savoir que CouchDB dispose d'un plugin JQuery pour faciliter les interactions. Par exemple, pour interroger notre vue :


$.couch.db("[db]").view("[appName]/by_date", {
success: function(data) {
console.log(data);
},
error: function(status) {
console.log(status);
}
});

Enfin, pour ajouter simplement des filtres sur les dates, il suffit d'intégrer les mots clés : "[appName]/by_date?startkey=[date1]&endkey=[date2]"

Ainsi, avec REST et HTML5/Javascript, vous voilà équipé pour jouer avec CouchDB! :) Enjoy!

Sources :
Catégories: Blog Individuel

Logstash et MongoDB en 10 minutes

Developpef - Paul-Emmanuel Faidherbe - mer, 09/20/2017 - 20:23

Lorsqu'il s'agit de mettre en place des outils de gestion de logs applicatifs, Logstash est souvent mis en avant.

Il est souvent proposé en combinaison avec d'autres utilitaires comme ElasticSearch et Kibana, qui, bien que remarquables, posent deux soucis :

  1. l'effet "usine à gaz" : en effet, 3 outils à prendre en main d'un coup et à déployer, cela peut paraßtre intimidant.
  2. "Quels sont mes besoins ?" : ces outils sont essentiellement destinés à la création/analyse de statistiques extraites des informations loggées.

Dans l'exemple que j'ai choisi ici, la structure des fichiers de logs ne permet pas ce genre d'utilisation : en effet, une ligne de log en elle-mĂȘme ne comporte que peu d'information (entrĂ©e dans un service, appel d'une procĂ©dure stockĂ©e...). Mais c'est plutĂŽt en ensemble de lignes qui permet de reconstituer un scĂ©nario dans l'application : ce que l'utilisateur a fait, par oĂč est passĂ© le code, etc. En somme une analyse contextuelle (verticale) des logs plutĂŽt que du contenu (horizontale).

Nous allons donc voir comment il est tout de mĂȘme possible d'utiliser Logstash et MongoDB pour crĂ©er une application facilitant l'analyse de fichiers de logs volumineux.

Tout d'abord, pourquoi ces outils?

Logstash : il est prĂ©vu pour traiter des volumes de donnĂ©es importants, de maniĂšre efficace, mĂȘme pour des fichiers au contenu spĂ©cifique grĂące Ă  son moteur d'expressions rĂ©guliĂšres Grok. Sa configuration est Ă©galement trĂšs simple car il embarque des composants tout prĂȘts, comme l'accĂšs aux bases MongoDB.

MongoDB : NoSQL pour une mise en place rapide (schemaless orientée document), sans configuration, gérant également des grands volumes de données (au format JSON, utile pour les applis web).

C'est parti, mise en place!

Logstash

Il se présente sous la forme d'un Jar autonome exécutable et ne nécessite qu'un fichier de configuration. En voici un exemple, l'explication par la suite :


input {
file {
type => "serveur"
path => "C:/log/serveur_*.log"
}

file {
type => "client"
path => "C:/log/client_*.log"
}
}

filter {
grok {
match => [ "message", "%{DATESTAMP:date} %{LOGLEVEL:level} ?(<context>[a-Z0-9_]*) %{GREEDYDATA:message}" ]
}
}

output {
mongodb {
collection => "collec-%{type}"
database => "local"
uri => "mongodb://localhost"
}
}

En détails :

  • Les entrĂ©es (input) de type "fichier" :
    • type : une Ă©tiquette qui permet de diffĂ©rencier nos sources de fichiers (logs serveur d'un cĂŽtĂ© et client de l'autre)
    • path : le chemin d'accĂšs, utilisant des wildcards
  • filter : la traitement a effectuer sur les entrĂ©es, ici un dĂ©coupage via une expression rĂ©guliĂšre Grok
    • %{DATESTAMP:date} : on crĂ©e un champ nommĂ© "date" constituĂ© d'un timestamp, quel que soit le format (trop fort!)
    • %{LOGLEVEL:method} : un champ nommĂ© "level" contenant les constantes classique de niveau de log : INFO, ERROR...
    • ?(<context>[a-Z0-9_]*) : un champ nommĂ© "context" basĂ© sur une expression rĂ©guliĂšre personnalisĂ©e
    • %{GREEDYDATA:message} : un champ nommĂ© "message" contenat... tout et n'importe quoi!
  • Les sorties (output) de type "mongodb", avec les infos de connexion basiques. Petite astuce : il est possible de rendre dynamiques les Ă©lĂ©ments de configuration pour chaque ligne de log traitĂ©e.

Il est possible de se faciliter l'Ă©criture de l'expression Grok avec Grok Debugger. Comme vous le voyez, trĂšs efficace!

Ces quelques lignes placées dans un fichier "ma-config.conf", Logstash se lance simplement avec :

java -jar logstash-1.3.2-flatjar.jar agent -f ma-config.conf

MongoDB

LĂ , rien de plus simple (la doc ici) :

  1. Lancer "mongod.exe" pour démarrer la base
  2. Optionnel : lancer "mongo.exe" pour ouvrir la console d'administration
  3. Dans notre exemple, pas besoin de créer une base de données, "local" est déjà créée par défaut.

Et voilà! Vous pouvez d'ores-et-déjà déposer des fichiers dans les répertoires indiqués, Logstash va lancer nos traitements pour fournir les documents correspondant dans notre base...

Comme je vous sens coupé dans votre élan, allons plus loin.

API Java

Bien Ă©videmment, MongoDB vient avec une API Java trĂšs simple d'utilisation. Quelques lignes de code dĂ©ployĂ©es par exemple sur un serveur Glassfish exposant des webservices REST via Jersey et vous avez une application web pour consulter et requĂȘter dans vos fichiers de logs!

Petits exemples, avec JQuery datatables et un tableau de bord avec gridster :

Plus loin...

Ils vous est également possible de pousser un peu plus loin ce systÚme en utilisant cette extension de log4j, log4mongo, afin d'écrire vos logs en temps réel dans la base MongoDB depuis votre application!

Catégories: Blog Individuel

SQLServer, JDBC et procédures stockées

Developpef - Paul-Emmanuel Faidherbe - mer, 09/20/2017 - 20:17

On ne le repÚtera jamais assez, migrer une base de données n'a rien d'anodin... Surtout lorsque l'application s'appuie sur des procédures stockées. En effet, chaque SGBD en propose son propre moteur et aucun driver JDBC ne se ressemble...


Le diable est dans les détails

Voici donc quelques exemples de "détails" qui vous éviteront de vous arracher les cheveux. La configuration utilisée ici est SQL Server Express 2014 et le driver JDBC Microsoft 4.0.

Un message peut en cacher un autre

Prenons l'exemple de la procédure stockées suivante :


CREATE PROCEDURE p_maproc(@param INTEGER)
AS
BEGIN

UPDATE MATABLE SET COL1 = 'VALEUR'

select 'data1' as RET1, 'data2' as RET2, 'data3' as RET3

END

Rien de bien compliqué, un UPDATE et un SELECT dont le but est de renvoyer un ResultSet avec 3 colonnes de données.

Appelons maintenant cette procédure avec un outil type Squirrel (configuré pour utiliser le driver JDBC) :

Tout se passe bien, le retour est bien constitué des 3 colonnes du SELECT.

Cependant, lorsque cette mĂȘme procĂ©dure est appelĂ©e dans une application Java (via le mĂȘme driver JDBC), l'erreur suivante est renvoyĂ©e :


com.microsoft.sqlserver.jdbc.SQLServerException: L'instruction n'a pas renvoyé le jeu de résultat.

En somme, le driver n'a pas pu remonter le ResultSet qu'il attendait...

Ceci est en fait du Ă  la prĂ©sence de l'instruction UPDATE. Son exĂ©cution gĂ©nĂšre l'Ă©mission d'un message appelĂ© DONE_IN_PROC, qui sert Ă  indiquer le nombre de lignes modifiĂ©es. Et c'est donc ce message qui est en prioritĂ© captĂ© comme retour par le driver JDBC, ce qui l'empĂȘche ensuite de rĂ©cupĂ©rer le vrai ResultSet final.

Pour corriger ce problĂšme, il existe l'instruction

SET NOCOUNT ON
qui permet de désactiver l'envoi des messages DONE_IN_PROC par la base. Notre procédure devient donc :


CREATE PROCEDURE p_maproc(@param INTEGER)
AS
BEGIN

SET NOCOUNT ON
UPDATE MATABLE SET COL1 = 'VALEUR'
SET NOCOUNT OFF

select 'data1' as RET1, 'data2' as RET2, 'data3' as RET3

END

Il est également possible de configurer directement le serveur de base de données pour ne pas avoir à écrire cette instruction dans toutes les procédures (voir les liens plus bas).

Du bon usage des types utilisateur

Les UDT (user defined type) fonctionnent comme des alias, permettant de créer des types de données personnalisés. Exemple :


CREATE TYPE [dbo].[T_DATEHEURE] FROM [datetime] NULL

Cette instruction va créer un type de données T_DATEHEURE basé sur le type primitif datetime, utilisable dans la base de données courante.

Prenons donc maintenant l'instruction suivante (toujours dans une procédure stockée) :


CREATE PROCEDURE p_maproc(@param INTEGER)
AS
BEGIN

CREATE TABLE #TABLETEMP (ID int, DATE T_DATEHEURE);

...

END

Cette fois-ci, l'erreur suivante sera levée :


Msg 2715, Level 16, State 7, Line 1
Colonne, parametre, ou variable #2: Type de données T_DATEHEURE introuvable.

Ceci provient de la nécessité de déclarer également le type de données T_DATEHEURE dans la base de données tempdb, utilisée par SQLServer pour créer les tables temporaires. Ainsi, une fois l'ordre "CREATE TYPE" exécuté sur tempdb, tout fonctionnera normalement...

Hope this helps!

Sources :
Catégories: Blog Individuel

Tester une API REST avec Swagger, Postman et Jenkins

Developpef - Paul-Emmanuel Faidherbe - mer, 09/20/2017 - 08:03

Avec l'essor de l'IoT vient l'Ăąge d'or des APIs (et de REST), pour ouvrir facilement et de maniĂšre universelle des services.

La gestion des APIs devient donc une affaire de pros et doit ĂȘtre de plus en plus rigoureuse. Nous allons voir comment maĂźtriser les Ă©volutions d'une API Ă  partir d'outils spĂ©cialisĂ©s.

Les basiques

Je pense qu'il n'est plus nécessaire de présenter Postman (extension Chrome pour tester une API) ni Jenkins (serveur d'intégration continue). Mais il est intéressant de voir comment les deux peuvent travailler ensemble pour devenir une suite de tests automatisée d'API, via l'utilitaire en ligne de commande Newman et cette trÚs bonne documentation officielle.

Swagger, la documentation simple et efficace!

Le meilleur moyen de s'assurer de la cohérence d'une API reste une bonne documentation. Pour ce faire, il existe Swagger (et sa version en ligne SwaggerHub) qui est l'outil de référence en la matiÚre. En effet, il est trÚs simple d'écrire rapidement une documentation pertinente, avec qui plus est une présentation agréable :

Putting it all together

Maintenant, voyons comment combiner tout cela.

Avec Swagger, vous avez la possibilité de définir, en plus de vos URLs, le formalisme des objets métier que vous manipulez. Pour cela il faut utiliser la section "definitions". Par exemple :


paths:
...
definitions:
Asset :
type: object
additionalProperties: false
required: ['name','owner','type']
properties :
name:
type: string
description: Nom de l'Asset.
owner:
type: string
description: Propriétaire du Device (User / domaine métier)
type:
type: string
description: Type de l'objet
Zone :
type: object
additionalProperties: false
required: ['name','geojson']
properties :
name:
type: string
description: Nom de la Zone.
geojson :
type: object
description: Géométrie au format GeoJSON
properties:
type:
type: string
description: Feature
geometry:
type: object
properties:
type:
type: string
description: Point
coordinates:
type: array
description: tableau de points GPS
items:
type: number
country:
type: string
description: Pays de la Zone, issu du référentiel Country.

ParallÚlement, il est possible dans les tests Postman de vérifier que le contenu d'une réponse correspond à un schéma particulier (via TinyValidator). Et surprise, le formalisme des "schémas" utilisés par Postman correspond parfaitement à celui de nos "definitions" Swagger! Cela vous donne des idées?? Alors allons-y!

Tout d'abord, nous allons récupérer notre définition Swagger en l'exportant au format JSON pour pouvoir l'utiliser avec Postman. Cependant, à l'heure actuelle, il n'est pas possible dans Postman de charger un fichier externe, autre qu'un fichier de données de tests. Donc nous allons devoir faire un copié/collé de notre définition dans Postman. Mais pour essayer de faire cela proprement, nous allons coller notre Swagger dans une variable d'environnement de Postman, afin qu'elle soit accessible dans tous les tests :

Ensuite, nous allons écrire un test de vérification de schéma qui va se baser sur la définition d'un de nos objets métier Swagger :

var swaggerJson = JSON.parse(environment.Swagger);// test schema var jsonData = JSON.parse(responseBody);var schema = {type:array,items: swaggerJson.definitions.Asset};tests[Valid Data] = tv4.validate(jsonData, schema);if(tv4.error) {   console.log(tv4.error);}

Comme vous le voyez, nous chargeons en JSON notre définition Swagger, puis définissons un schéma de type tableau d'Assets, en récupérant la définition des Assets avec swaggerJson.definitions.Asset. Et en plus c'est facile!

Maintenant, lors de l'exĂ©cution de votre requĂȘte, les tests seront lancĂ©s et la rĂ©ponse sera validĂ©e en fonction du schĂ©ma indiquĂ©! Il est important Ă  ce stade de disposer d'une dĂ©finition d'objet stricte, notamment via l'utilisation des propriĂ©tĂ©s Swagger additionalProperties:false et required: ['name','owner','type'], sans quoi n'importe quelle rĂ©ponse passera la validation.

Vous pouvez mĂȘme aller jusqu'Ă  utiliser votre dĂ©finition Swagger pour rĂ©cupĂ©rer les URLs Ă  tester. Pour cela, il faut utiliser la partie "Pre-request Script" de Postman et parcourir de la mĂȘme façon notre Swagger :

Ici, nous définissons une variable d'environnement 'url' à l'aide des attributs 'host' et 'basePath' de Swagger. Cette variable est ensuite utilisée par Postman via la syntaxe {{url}} dans sa barre d'adresse.

Remarque :

Il est également possible d'importer directement la définition Swagger dans Postman (via le bouton Import) pour récupérer automatiquement toutes les URLs à tester. Cependant, si vous avez besoin de réimporter votre définition suite à des modifications, cela va écraser tout ce qui existe déjà, y compris les tests!.

Pour terminer, il ne vous reste plus qu'Ă  mettre tout cela dans Jenkins, via l'export de votre collection et de l'environnement Postman que vous passerez en paramĂštres de Newman! Enjoy!

Catégories: Blog Individuel

Sans Engagement fort du Leader
 Pas de Transformation Agile RĂ©ussie

Qualitystreet - Jean Claude GROSJEAN - mar, 09/19/2017 - 01:35

ou Ce que j’ai appris #3: L’engagement du Top Management TroisiĂšme volet de notre sĂ©rie d’articles consacrĂ©s aux transformations agiles d’organisation. Volet 1: Des transformations Agiles enfin
 agiles Volet 2: Des Saisons pour rythmer votre Transformation Agile L’engagement du Top Management dans le projet de transformation Agile est un facteur clĂ© de succĂšs. Au delĂ  du soutien, qui…

The post Sans Engagement fort du Leader… Pas de Transformation Agile RĂ©ussie appeared first on QualityStreet - Blog Agile depuis 2007.

Catégories: Blog Individuel

Le nomadisme numérique

Barre Verte ! - dim, 09/17/2017 - 23:00

L’agriculture aurait rendu l’homme sĂ©dentaire. A l’avĂšnement d’internet des voix ont prĂ©dit que des formes de nomadismes reviendraient.

La premiÚre conférence DNX, en 2014Ces derniÚres années des conférences sont nées sur ce thÚme comme 7in7 en 2016, Nomad Summit en 2015 ou DNX en 2014 dont la newsletter totalise 20000 abonnés et qui se tient à guichets fermés.

Ces confĂ©rences sur le nomadisme numĂ©rique adoptent des formes trĂšs classiques, avec des salles et des amphithĂ©Ăątres. De la mĂȘme maniĂšre que les premiĂšres confĂ©rences agiles suivaient ces formes classiques. Ensuite la forme de l’Open Space est apparue comme une maniĂšre plus “agile” de faire une confĂ©rence agile.

A la lumiĂšre de ce qui s’est passĂ© pour l’agilitĂ© se pose donc la question : comment faire une confĂ©rence d’une maniĂšre plus nomade ?

La valeur des intermĂšdes

Lors d’une confĂ©rence, qu’elle soit open space ou plus classique je me dĂ©place de salle en salle. Je trouve de la valeur Ă  la fois dans ce que j’entends dans les salles et dans ce que j’entends en dehors des salles, dans les intermĂšdes, les errances, les pauses.

Le lieu que j’ai vu le plus propice Ă  ces intermĂšdes ? Le chalet de la Porte Jaune oĂč se dĂ©roule tous les ans la confĂ©rence Agile France. J’ai par exemple participĂ© il y a deux ans de maniĂšre totalement impromptue Ă  la discussion la plus intĂ©ressante que j’ai entendue Ă  ce jour sur la dichotomie entre Lean Management et AgilitĂ©.

Puisque ces intermĂšdes-dĂ©placements gĂ©nĂšrent autant de valeur, la question se pose : si on leur donnait une dimension plus grande, une raison d’ĂȘtre Ă  part entiĂšre, quelle forme cela prendrait-il ?

Des conférences nomades ?

J’ai participĂ© cet Ă©tĂ© Ă  deux confĂ©rences qui explorent ce concept.

Walking Dev

Walking Dev est une confĂ©rence open space d’une journĂ©e. Les salles de confĂ©rences ? Des cafĂ©s, un restaurant, une librairie, des jardins, un cloĂźtre. Une dĂ©couverte de Toulouse jusque dans des lieux inconnus des Toulousains eux-mĂȘmes. Et entre ces lieux, la marche Ă  travers la ville.

Ce n’était pas une premiĂšre : un participant du Sud-Ouest avait dĂ©jĂ  utilisĂ© ce format pour une formation Ă  Paris pour laquelle il avait eu de trĂšs bon retours.

Nomad Open

Nomad Open se veut une confĂ©rence plus ambitieuse dans sa forme puisque les dĂ©placements Ă  pieds deviennent des voyages en train et chaque Ă©tape est une ville diffĂ©rente. Le sujet s’avĂšre Ă©galement plus radical puisqu’il s’agit du nomadisme lui mĂȘme : la confĂ©rence est un espace de coworking en mouvement oĂč les participants travaillent Ă  leurs tĂąches quotidiennes comme s’ils Ă©taient sĂ©dentaires. A la dichotomie de walking dev entre les sessions plĂ©niĂšres statiques et les discussions informelles en marchant, nomad open substitue un triptyque :

  • coworking en mouvement
  • rencontres de communautĂ©s locales
  • confĂ©rence open space

J’ai Ă©tĂ© surpris de constater que pour certaines tĂąches je devenais plus productif dans un train que dans un bureau. D’autres participants ont partagĂ© cette constatation. Ces formes Ă©phĂ©mĂšres de travail me paraissent donc intĂ©ressantes Ă  explorer. Cet article ouvre une sĂ©rie d’articles qui relate mes apprentissages sur le sujet.

Catégories: Blog Individuel

LCC 177 - Interview sur les devs Ă  Singapour Ă  Voxxed Days Eponyme

A l’occasion de Voxxed Days Singapore, Guillaume et Emmanuel discutent avec des expatriĂ©s de Singapour (Alan, Germain, Mathieu, Nida) sur leur vie de dĂ©veloppeur lĂ  bas.

Enregistré le 18 juillet 2017

TĂ©lĂ©chargement de l’épisode LesCastCodeurs-Episode–177.mp3

Interview Ta vie ton Ɠuvre

Alan Menant Redmart Marina Bay Sands

Germain Potet Zenika Singapore

Mathieu François While 42

Nida Bouzid Active Viam

Voxxed Days Singapore

Voxxed Days Singapore

Singapour

While 42 Singlish Work holiday pass Minostry of manpower

Niveaux de vie:

  • salaire
  • loyer
  • nourriture
  • retraite / santĂ©
  • jours de vacances (14 Ă  21 jours)
  • voiture
G1 et le retour d’expĂ©rience Active Viam

Jean-Claude Van Damme malloc

Nous contacter

Faire un crowdcast ou une crowdquestion Contactez-nous via twitter https://twitter.com/lescastcodeurs sur le groupe Google https://groups.google.com/group/lescastcodeurs ou sur le site web https://lescastcodeurs.com/ Flattr-ez nous (dons) sur https://lescastcodeurs.com/ En savoir plus sur le sponsoring? sponsors@lescastcodeurs.com

 

Catégories: Blog Individuel

Utiliser les librairies Arduino dans Atmel Studio

Developpef - Paul-Emmanuel Faidherbe - jeu, 09/14/2017 - 13:30

Dans cet article je vais vous présenter comment démarrer un projet simple (exemple Blink) avec un Arduino Due, Atmel Studio 6.2 et les librairies du projet Arduino.

Pour commencer, vous pouvez suivre cet article trĂšs clair et trĂšs simple pour initier l'environnement : http://www.engblaze.com/tutorial-using-atmel-studio-6-with-arduino-projects/

Datant cependant de 2012, il mérite quelques mises à jour : il vous faudra télécharger la derniÚre version du software Arduino capable de gérer le Due. Les chemins vers les répertoires à inclure seront donc légÚrement différents, puisque spécifiques à la plateforme (par ex ".\hardware\arduino\sam\variants\arduino_due_x"). Il faudra également ajouter dans le Linker un lien vers la librairie libsam_sam3x8e_gcc_rel située sous ".\hardware\arduino\sam\variants\arduino_due_x".

Il se peut que vous rencontriez des petites erreurs de compilation, que vous pourrez résoudre à la main en commentant/déplaçant du code.

Voici maintenant la nouvelle version de l'exemple Blink :


#include "sam.h"
#include "Arduino.h"


int led = 53;

/**
* \brief SysTick_Handler.
*/
void SysTick_Handler(void)
{
/* Increment counter necessary in delay(). */
TimeTick_Increment();
}

/**
* \brief Application entry point.
*
* \return Unused (ANSI-C compatibility).
*/
int main(void)
{
/* Initialize the SAM system */
SystemInit();
SysTick_Config(SystemCoreClock / 1000); //1ms per interrupt

pinMode(led, OUTPUT);

while (1)
{
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
}

Pour faire fonctionner la méthode delay, il est nécessaire d'ajouter le code activant l'incrémentation du compteur systeme :


void SysTick_Handler(void)
{
/* Increment counter necessary in delay(). */
TimeTick_Increment();
}
...
SysTick_Config(SystemCoreClock / 1000); //1ms per interrupt

Ainsi, la méthode d'incrémentation TimeTick_Increment sera appelée par l'handler interne au processeur SysTick_Handler toutes les 1ms comme indiqué par SysTick_Config

Ne reste plus qu'Ă  indiquer la plateforme cible Ă  la compilation (processeur SAM3X8E) et lancer la programmation!

Edit : il est également possible d'appeler la méthode Arduino TimeTick_Configure(SystemCoreClock)

Catégories: Blog Individuel

Arduino : créer une horloge synchronisée

Developpef - Paul-Emmanuel Faidherbe - jeu, 09/14/2017 - 13:29

Dans cet article, nous allons voir comment afficher sur un écran la date et l'heure courantes, avec la possibilité de se synchroniser sur un serveur de temps public (NTP - Network Time Protocol), comme le font tous les PC ou téléphones.

Matériel

Pour cet exemple, il faut vous munir :

  • d'un arduino (ici un DUE)
  • un shield Ethernet
  • un module RTC (Real Time Clock, ici un Gravitech)
  • un Ă©cran LCD

Voici un schéma du montage :

L'écran est branché, de maniÚre classique, sur des broches numériques. Le module RTC quant à lui est intégré sur le bus I2C par les broches SDA1 et SCL1.

Logiciel

Nous allons utiliser les librairies :

  • Ethernet
  • Wire1 (pour le bus I2C)
  • LiquidCrystal
  • Time (pour faciliter la dĂ©composition de la date Ă  partir d'un timestamp)

Données importantes :

Selon la spécification du constructeur, l'adresse de communication du module RTC sur le bus I2C est 0x68. Le serveur NTP choisi est celui de l'Observatoire de Paris (ntp-p1.obspm.fr, IP: 145.238.203.14). Le dialogue avec un serveur NTP se fait par échange de paquets par le protocole UDP.

C'est parti!

1. Configuration d'une date par défaut sur le module RTC

Commençons par un premier échange avec ce module :


const int I2C_address = 0x68;
...
Wire1.begin(); // join i2c bus (address optional for master)
Wire1.beginTransmission(I2C_address);// DĂ©but de transaction I2C
Wire1.write(0); // ArrĂȘte l'oscillateur
Wire1.write(0); // sec
Wire1.write(0x11); // min
Wire1.write(0x20); // heure
Wire1.write(6); // jour de la semaine
Wire1.write(0x20); // jour
Wire1.write(9); // mois
Wire1.write(0x14); // annee
Wire1.write(0); // Redémarre l'oscillateur
Wire1.endTransmission(); // Fin de transaction I2C

Ici nous définissons la date "20/09/2014 20:11:00". Remarquez que les valeurs transmises sont au format hexadécimal.

2. Lecture de la date sur le module RTC

Interrogeons notre module pour récupérer la date :


void getTime(char* tempData) {
byte i = -1;
byte error;

Wire1.beginTransmission(I2C_address); // DĂ©but de transaction I2C
Wire1.write(0); // Demande les info Ă  partir de l'adresse 0 (soit toutes les info)
error = Wire1.endTransmission(); // Fin de transaction I2C

if(error==0) {
Wire1.requestFrom(I2C_address, 7); // RĂ©cupĂšre les info (7 octets = 7 valeurs correspondant Ă  l'heure et Ă  la date courante)

while(Wire1.available())
{
tempData[++i] = Wire1.read(); // receive a byte as character
}
} else {
// le composant RTC n'etait pas joignable, on relance le bus I2C pour la prochaine fois
Wire1.begin();
}
}

Cette méthode nous permet de récupérer, dans un tableau de 7 char (tempData), les données du module.

3. Affichage de la date sur l'Ă©cran


void displayTime()
{
char tempchar[7] = {'\0'};
// recuperation de la date
getTime(tempchar);
// affichage
if(tempchar[0]!='\0') {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(tempchar[4],HEX);
lcd.write("/");
lcd.print(tempchar[5],HEX);
lcd.write("/20");
lcd.print(tempchar[6],HEX);
lcd.setCursor(0, 1);
lcd.print(tempchar[2],HEX);
lcd.write(":");
lcd.print(tempchar[1],HEX);
lcd.write(":");
lcd.print(tempchar[0],HEX);
}
}

Avec cette méthode, on envoie à l'écran chaque caractÚre (toujours au format hexadecimal) retourné par l'appel au module RTC.

Il ne vous reste plus qu'Ă  placer l'appel Ă  cette mĂ©thode dans une boucle toutes les secondes pour voir dĂ©filer le temps. Essayez mĂȘme de couper l'alimentation du module RTC : l'affichage de l'heure se fige, jusqu'Ă  nouvelle alimentation du module. Elle sera alors mise Ă  jour avec la date qui a continuĂ© Ă  dĂ©filer grĂące Ă  la pile du module.

4. Interrogation du serveur de temps

Le shield Ethernet va nous permettre de contacter le serveur public et de récupérer les informations de date "de référence".


IPAddress timeServer(145, 238, 203, 14); // ntp-p1.obspm.fr (IP: 145.238.203.14)
const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
uint8_t packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
/* Set this to the offset (in seconds) to your local time
GMT - 2 */
const long timeZoneOffset = -7200L;
// A UDP instance to let us send and receive packets over UDP
EthernetUDP udpClient;
EthernetClient client;

/**
* DĂ©marrage des librairies
*/
Ethernet.begin(mac);
udpClient.begin(8888); // port UDP local


/**
* Envoi de la requete
*/
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;

// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
udpClient.beginPacket(timeServer, 123); //NTP requests are to port 123
udpClient.write(packetBuffer,NTP_PACKET_SIZE);
udpClient.endPacket();


/**
* Parcours de la réponse du serveur
*/
unsigned long epoch = 0;
if ( udpClient.parsePacket() ) {
// We've received a packet, read the data from it
udpClient.read(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer

//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;

// now convert NTP time into everyday time:
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
const unsigned long seventyYears = 2208988800UL + timeZoneOffset;
// subtract seventy years:
epoch = secsSince1900 - seventyYears;
}


/**
* Configuration du module RTC avec la nouvelle date
*/
setTime(epoch); // on affecte le timestamp récupéré à la librairie Time
Wire1.beginTransmission(I2C_address);// DĂ©but de transaction I2C
Wire1.write(0); // ArrĂȘte l'oscillateur
String strval = String(second(), DEC);
Wire1.write(strtol(strval.c_str(),NULL, HEX)); // sec
strval = String(minute(), DEC);
Wire1.write(strtol(strval.c_str(),NULL, HEX)); // min
strval = String(hour(), DEC);
Wire1.write(strtol(strval.c_str(),NULL, HEX)); // heure
Wire1.write(weekday()-1); // jour de la semaine
strval = String(day(), DEC);
Wire1.write(strtol(strval.c_str(),NULL, HEX)); // jour
strval = String(month(), DEC);
Wire1.write(strtol(strval.c_str(),NULL, HEX)); // mois
strval = String(year(), DEC);
Wire1.write(strtol(strval.c_str(),NULL, HEX)); // annee
Wire1.write(0); // Redémarre l'oscillateur
Wire1.endTransmission(); // Fin de transaction I2C

La librairie Time nous permet de décomposer facilement les données de la date. Mais le serveur NTP nous a envoyé la date au format décimal "20/09/2014 20:11:00". Il faut donc convertir les données au format hexa avant de configurer le module RTC.

Ainsi, aprÚs l'appel à ce code (à découper en méthodes pour plus de clarté), l'affichage de la date sera automatiquement actualisé avec la date de référence.

Have fun!

Sources :
Catégories: Blog Individuel

Un client CoAP simple en C

Developpef - Paul-Emmanuel Faidherbe - jeu, 09/14/2017 - 13:28

CoAP est un protocole de communication dédié aux objets connectés : basé sur UDP et REST, il permet de diminuer au maximum le contenu des messages pour économiser les ressources des objets lors des transferts de données.

Nous allons voir ici comment implĂ©menter votre propre client, Ă  l'aide de la spĂ©cification du protocole. Le but est d'ĂȘtre capable d'envoyer, de la maniĂšre la plus simple possible, des donnĂ©es Ă  un serveur CoAP exposant des services. Niveau matĂ©riel, un Arduino Mega avec un shield Ethernet communique avec un serveur Java.

Commençons par la structure des messages. Ce chapitre de la spécification nous explique comment les structurer :

8 bits8 bits8 bits8 bitsVerTTKLCodeMessage IDTokenOptionsTerminatorPayload

Je vous laisse vous référer à la spécification pour la signification des champs. Un peu plus en détails, les Options suivent un format propre :

8 bits8 bits8 bits8 bitsVerTTKLCodeMessage IDTokenDeltaLengthValueTerminatorPayload

Ici nous allons construire un message contenant :

  • version : 1
  • type : Request
  • TKL : 0 (pas de Token)
  • Code : POST
  • vers le service : "/sensors"
  • contenu : "test"

Voici ce que cela donne :

8 bits8 bits8 bits8 bits1Request0POSTMessage ID Uri-Path7URI segment "sensors"Terminator"test"

Chaque Option possÚde un code "Option Number" propre. Par exemple, "Uri-Path" qui permet d'indiquer un segment de l'adresse du service, a pour code 11. Le Delta se calcule alors en additionnant le code de l'option avec celles des précédentes :

8 bits8 bits8 bits8 bits1Request0POSTMessage ID 0+117"sensors"Terminator"test"

Si l'on veut spĂ©cifier plusieurs options du mĂȘme type, il n'est pas nĂ©cessaire d'additionner le code. Par exemple, pour pointer sur le service "/sensors/temp" :

8 bits8 bits8 bits8 bits1Request0POSTMessage ID 0+117"sensors"0+11+04"temp"Terminator"test"

En revanche, pour une autre Option, par exemple "Max-Age" qui a le code 14 :

8 bits8 bits8 bits8 bits1Request0POSTMessage ID 0+117"sensors"0+11+14212Terminator"test"

Revenons Ă  notre exemple et transformons tout en valeurs selon la spec et notre cas :

8 bits8 bits8 bits8 bits1100.0252942 117"sensors"Terminator"test"

Ce qui nous donne, en binaire en respectant la longueur des champs (pour les champs les plus simples) :

8 bits8 bits8 bits8 bits010100000000000101100111011001110 10110111"sensors"11111111"test"

Enfin, pour se faciliter l'envoi via le contrÎleur Ethernet, dont la librairie est prévue pour traiter des "char" sur 8 bits, il suffit de transformer le résultat en concaténant les bits par 8 :

8 bits8 bits8 bits8 bits0x500x020xCE0xCE 0xB7"sensors"0xFF"test"

En pratique, un petit exemple de code Arduino pour envoyer nos données :


#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

char coapacket[18];
EthernetUDP udp;

void loop() {
coapacket[0] = 0x50;
coapacket[1] = 0x02;
coapacket[2] = 0xce;
coapacket[3] = 0xce;
coapacket[4] = 0xB7;
coapacket[5] = 's';
coapacket[6] = 'e';
coapacket[7] = 'n';
coapacket[8] = 's';
coapacket[9] = 'o';
coapacket[10] = 'r';
coapacket[11] = 's';
coapacket[12] = 0xff;
coapacket[13] = 't';
coapacket[14] = 'e';
coapacket[15] = 's';
coapacket[16] = 't';
coapacket[17] = '\0';

udp.beginPacket(serverIP, 5683);
udp.write(coapacket);
udp.endPacket();
}

VoilĂ  tout!

Catégories: Blog Individuel

Créer un serveur CoAP

Developpef - Paul-Emmanuel Faidherbe - jeu, 09/14/2017 - 13:27

J’évoquai dans un prĂ©cĂ©dent article comment crĂ©er un client CoAP directement Ă  partir de la spĂ©cification, sans avoir Ă  s’imposer une librairie.

Nous allons donc maintenant voir comment mettre en place facilement un serveur CoAP à partir des différentes solutions déjà existantes sur le marché.

Actinium

IntĂ©grĂ© dans la suite logicielle "Californium" mise en avant par la fondation Eclipse dans le cadre de son grand projet "IOT", cet outil est basĂ© entiĂšrement sur des services REST : de l’administration au dĂ©ploiement de nouveaux services, tout peut ĂȘtre fait par l’appel Ă  des URL. Il est Ă©galement trĂšs simple de crĂ©er de nouvelles application puisque tout est codĂ© en Javascript! Il utilise en effet le moteur open source Rhino de la fondation Mozilla. Petit exemple d’application (issu de la documentation) :


app.root.onget = fnc;
app.root.onpost = fnc;
app.root.onput = fnc;
app.root.ondelete = fnc;

fnc = function(request) {
request.respond(2.05, "Hello World");
}

L’ensemble du code est trĂšs lĂ©ger, le serveur se dĂ©marre Ă  partir d’un simple Jar :

java -jar actinium-*.jar

Cependant, Rhino est dĂ©sormais connu pour ĂȘtre un peu vieillissant et ses performances ne sont plus comparables aux moteurs Javascript plus rĂ©cents, comme le montre ce document. Depuis Java 8, il a d’ailleurs Ă©tĂ© remplacĂ© par Nashorn.

Node.JS

Puisque nous sommes en train de parler de moteurs JS cĂŽtĂ© serveur, qu’en est-il de Node.JS? Il existe en effet un module "node-coap" dĂ©veloppĂ© par Matteo Collina. Il profite alors des trĂšs bonnes performances du moteur “V8” de Google lui permettant de s’insĂ©rer dans des applications "temps rĂ©el".

Egalement trĂšs simple d’utilisation, il permet de tester rapidement les fonctionnalitĂ©s essentielles du protocole. Par exemple :


var coap = require("coap");

var server = coap.createServer();

server.on('request', function(req, res) {
switch(req.url) {
case ('/test') :
if (req.method == 'GET') {
res.end("NodeJS CoAP server OK!!!");
console.log("[test] " + req.method + " to " + req.url);
}
break;
case ('/.well-known/core') :
if (req.method == 'GET') {
res.code = '2.05';
res.setOption("Content-Format", "application/link-format");
res.end(";title=Test server,;title=Hello!");
}
break;
default:
res.code = '4.04';
res.setOption("Content-Format", 'text/html');
res.end('<html><head><title>404 - Not found</title></head><body><h1>Not found.</h1></body></html>');
console.log("[404] " + req.method + " to " + req.url);
break;
}
});

On voit ici qu’il est trĂšs facile de mettre en place un serveur rĂ©pondant Ă  diffĂ©rentes URL et requĂȘtes HTTP.

Au passage, vous pouvez lire dans cet exemple l’implĂ©mentation de la dĂ©couverte de services (discovery) utilisĂ©e par CoAP et constituĂ©e d’une requĂȘte GET sur l’URL "/.well-known/core" renvoyant du contenu au format "CoRE Link Format" (RFC 6690).

Ponte

Pour aller plus loin, cet autre module Node.JS propose une solution complĂšte mĂȘlant HTTP, CoAP et MQTT (protocole basĂ© sur du publish/subscribe), en plus notamment de quelques connecteurs vers des bases de donnĂ©es NoSQL :

Je vous laisse le soin de découvrir ses fonctionnalités.

Amusez-vous bien!

Catégories: Blog Individuel

Cumulocity : une plateforme IoT taillée pour l'industrie

Developpef - Paul-Emmanuel Faidherbe - jeu, 09/14/2017 - 13:24

DĂ©sormais c'est un fait, c'est bien l'industrie qui va guider les prochaines Ă©volutions majeures de l'IoT, pousser l'adoption de certaines normes et standardiser les principaux cas d'usages.

Il est donc temps de commencer à prendre en main les plateformes spécialisées, délivrant des services professionnels : device management, intégration de protocoles, sécurité, mise à l'échelle, analytics, multitenants...

Pour cela, nous allons utiliser la plateforme Cumulocity.

Son nom ne vous dit peut-ĂȘtre rien, mais elle fait partie des leaders du marchĂ©, avec dĂ©jĂ  de belles rĂ©fĂ©rences. Pour en avoir comparĂ© bon nombre, je la place grande premiĂšre de mon top 3 des plateformes, juste devant IBM Watson IoT et theThings.io (je n'oublie bien sĂ»r pas Thingworx de PTC, mais elle est Ă  mon sens beaucoup trop complexe Ă  mettre en oeuvre, et reste difficile d'accĂšs aux nĂ©ophytes du PLM...).

Prise en main en 5 minutes

Pour la tester, rien de plus simple, il suffit de créer un compte d'essai gratuit, qui donne accÚs à la majeure partie des fonctionnalités pendant 1 mois. Ensuite, il est possible d'ajouter par exemple un smartphone en tant que Device, via l'appli Android spécifique. Vous aurez alors accÚs à un dashboard affichant en temps réel les données relevées par votre téléphone (gyroscope, accéléromÚtre, luxmÚtre...).

Explorer toute l'API REST

Puisqu'une plateforme IoT n'est rien sans une interface REST, il est assez simple d'explorer toute l'Ă©tendue des possibilitĂ©s offertes par celle de Cumulocity. Pour cela, le plus pratique est d'utiliser l'extension Chrome Postman et rĂ©cupĂ©rer la librairie publiĂ©e par Cumulocity. Vous aurez ainsi sous la main toutes les requĂȘtes prĂȘtes Ă  ĂȘtre utilisĂ©es pour envoyer des donnĂ©es, crĂ©er des Devices, dĂ©clencher des alarmes, pousser des OpĂ©rations...

Premier cas concret

Maintenant que nous avons fait les premiers tests de la plateforme, il est temps de créer un vrai cas d'usage du monde réel. Voici le scénario envisagé :

Des Devices émettent des données vers la plateforme (quel que soit le protocole) qui sont reçues en temps réel sur des serveurs ou des applications d'analyse. TrÚs commun! Cependant, selon les services offerts par les API REST, il n'est pas toujours trivial de mettre en place un mécanisme de réception en temps réel de la derniÚre donnée émise ou alarme levée par un Device spécifique.

Cumulocity offre de ce point de vue 2 outils intéressants :

  • des connexions par websockets, qui permettent de crĂ©er des flux de donnĂ©es en temps rĂ©el, plus robustes pour ce besoin que du simple HTTP (mĂȘme en long-polling)
  • un ensemble de flux d'Ă©vĂšnements internes au framework, sur lesquels il est possible de s'abonner, pour recevoir des notifications sur TOUT ce qui se passe sur la plateforme (rĂ©ception de donnĂ©es, crĂ©ation de Device, dĂ©clenchement d'Ă©vĂšnements/alarmes...)

Pour établir une connexion, il suffit de respecter le protocole de Bayeux, basé les concepts de publish/subsribe et d'échanges de données en JSON. La documentation de Cumulocity à ce sujet permet de rapidement mettre en place ces flux temps réel.

Afin de réaliser une implémentation la plus simple possible et la plus polyvalente, utilisable tant par un serveur web qu'embarqué dans un Device, nous allons utiliser le langage Python.

Gestion des websockets

Notre premier module s'occupera de la gestion bas niveau des websockets, grùce au package websocket-client. Vous aurez également besoin de simplejson pour créer du contenu JSON.


import websocket
import simplejson

class WebsocketWrapper:
def __init__(self, cnxUrl):
self.ws = websocket.WebSocketApp(cnxUrl,
on_message = self.on_message,
on_error = self.on_error,
on_close = self.on_close)
self.ws.on_open = self.on_open
self.servermsgjson = []

def on_error(self, ws, error):
print(error)

def on_close(self, ws):
print('closed')

def on_open(self, ws):
print('connected')
self.afterOpen()

def on_message(self, ws, message):
print("server msg: "+message)
self.servermsgjson = simplejson.loads(message)
self.parseMsg(self.servermsgjson)

def send(self,msg):
self.ws.send(msg)

def openWebsocket(self):
print('opening websocket...')
# websocket.enableTrace(True)
self.ws.run_forever(http_proxy_host='...', http_proxy_port=80)

def afterOpen(self):
pass

def parseMsg(self, jsonMsg):
pass

def handshake(self):
self.ws.send(simplejson.dumps([{'channel':'/meta/handshake','ext':{'com.cumulocity.authn':{'token':'...'}},'version':'1.0','mininumVersion':'1.0beta','supportedConnectionTypes':['websocket','long-polling','callback-polling'],'advice':{'timeout':120000,'interval':30000}}]))

def connect(self, clientId):
print('realtime connection...')
self.ws.send(simplejson.dumps([{"channel":"/meta/connect","connectionType":"websocket","clientId":clientId}]))

Il vous faudra ici modifier l'adresse du proxy (ou supprimer les paramÚtres s'il n'y a pas de proxy) et ajouter le token d'authentification (usr:pwd encodés en Base64).

Clients websockets

Le code ci-dessous va permettre de créer 2 clients en websockets écoutant des flux différents : gestion des évÚnements et réception de mesures.


import simplejson

from websocket.websocket_wrapper import WebsocketWrapper

class C8YClient:
def __init__(self):
self.clientId = ''
self.findClientId = False
self.readyToConnect = False

self.wrapper = WebsocketWrapper('wss://.cumulocity.com/cep/realtime')
self.wrapper.parseMsg = self.parseMsg
self.wrapper.afterOpen = self.afterOpen

def init(self):
self.wrapper.openWebsocket()

def afterOpen(self):
self.initClient()

def initClient(self):
self.findClientId = True
self.wrapper.handshake()

def parseMsg(self, jsonMsg):
if self.findClientId:
self.findClientId = False
self.doFindClientId(jsonMsg)
self.doSubscription()
elif self.readyToConnect:
self.readyToConnect = False
self.connectClient()
else:
self.useMsg(jsonMsg)

def useMsg(self, jsonMsg):
pass

def doSubscription(self):
pass

def doFindClientId(self, jsonMsg):
self.clientId = jsonMsg[0]['clientId']
print('got clientId : ' + self.clientId)

def connectClient(self):
self.wrapper.connect(self.clientId)

def subscribe(self, channel):
print('subscribing to '+channel+'...')
self.readyToConnect = True
self.wrapper.send(simplejson.dumps([{"channel":"/meta/subscribe","subscription":"/"+channel+"/*","clientId":self.clientId}]))


class MeasurementsClient(C8YClient):
def __init__(self):
super().__init__()

def initClient(self):
print('initMeasurementsClient...')
super().initClient()

def doSubscription(self):
super().subscribe('measurements')

def useMsg(self, jsonMsg):
print('new measurement : ' + simplejson.dumps(jsonMsg))


class EventsClient(C8YClient):
def __init__(self):
super().__init__()

def initClient(self):
print('initEventsClient...')
super().initClient()

def doSubscription(self):
super().subscribe('events')

def useMsg(self, jsonMsg):
print('new event : ' + simplejson.dumps(jsonMsg))

Ne reste plus qu'un petit main pour exécuter tout cela :


from threading import Thread
from websocket.c8y_client import MeasurementsClient, EventsClient

if __name__ == '__main__':

measurementsClient = MeasurementsClient()
threadM = Thread(target = measurementsClient.init, args = ())
threadM.start()

eventsClient = EventsClient()
threadE = Thread(target = eventsClient.init, args = ())
threadE.start()

Nous disposons maintenant d'une simple application Python qui reçoit en temps rĂ©el des notifications d'Ă©vĂšnements de Cumulocity! Vous pouvez le tester simplement via les requĂȘtes REST dĂ©jĂ  existantes dans la librairie Postman. Ainsi, POSTer un nouveau Measurement (relevĂ© de donnĂ©es issu d'un capteur) dĂ©clenchera immĂ©diatement sa rĂ©ception cĂŽtĂ© Python.

A vous l'IIoT !

Catégories: Blog Individuel

Préparer un projet audio avec Arduino

Developpef - Paul-Emmanuel Faidherbe - jeu, 09/14/2017 - 12:46

Je vais tĂącher ici de vous donner quelques informations de base Ă  connaĂźtre lorsque vous dĂ©cidez de vous lancer dans un projet Arduino traitant avec de l’audio.

Mais attention, je ne parle pas de projet “audio-rĂ©actif”, comme on en voit en majoritĂ© sur le net, dont le but est de faire rĂ©agir le matĂ©riel en fonction d’une intensitĂ© sonore ou d’une frĂ©quence particuliĂšre, ni mĂȘme de “vu-meter” (visualisateur de frĂ©quence type Ă©qualiseur). Mon but ici est de prĂ©senter les Ă©lĂ©ments importants Ă  maĂźtriser dans le cas oĂč vous souhaiteriez enregistrer rĂ©ellement du son, c’est-Ă -dire capturer le signal sonore dans son intĂ©gralitĂ© en vue de traitement ultĂ©rieur : re-lecture, analyse spectrale, manipulation en Big Data pour crĂ©er votre propre Shazam... ;-)

Ainsi, sans avoir la prĂ©tention de vous donner un cours d’électronique avancĂ©e ou de traitement du signal (je n’en ai pas les capacitĂ©s), je vais vous livrer tout ce que j’ai appris en tant que nĂ©ophyte aprĂšs m’ĂȘtre plongĂ© tĂȘte baissĂ©e dans ce type de projet sans trop de connaissances de ces domaines.

Passage obligé : la théorie

MĂȘme si vous me voyez venir, je ne vais pas me lancer dans une explication des TransformĂ©es de Fourier (ou Fast Fourier Transform - FFT utilisĂ©es en Ă©lectronique). Cependant, il est intĂ©ressant de comprendre leur concept de base : tout signal (ici sonore) peut ĂȘtre dĂ©composĂ© en signaux sinusoĂŻdaux Ă©lĂ©mentaires, d’amplitudes et de frĂ©quences diffĂ©rentes :

Source : http://music.columbia.edu/cmc/musicandcomputers/chapter3/03_03.php

Comme on le voit ici, il s’agit donc d’ondes oscillant avec une amplitude variable autour de 0. Or, nos traitements numĂ©riques ne peuvent s’appuyer que sur des valeurs positives : nous allons donc devoir commencer par adapter les signaux captĂ©s pour pouvoir les traiter proprement, sans risquer de perdre la moitiĂ© des informations.

Pour ce faire, il va falloir dĂ©caler l’amplitude du signal de sorte que les oscillations aient une valeur minimum de 0. Ceci est possible en ajoutant une composante continue (pour crĂ©er un biais, ou “offset”), ayant pour valeur la moitiĂ© de l’amplitude max du signal : si la source Ă©met une onde Ă  partir d’une tension de 5V, le signal oscillera entre +2.5V et -2.5V. L’ajout d’une composante continue de 2.5V le fera alors osciller entre 0V et 5V.

La thĂ©orie est simple, n’est-ce pas? Mais voyons ce que cela implique au niveau matĂ©riel
 Les choses se compliquent.

Un peu d’électronique

Pour additionner nos tensions (alternatives et continues), nous avons besoins d’un pont diviseur. ComposĂ© de deux rĂ©sistances en sĂ©rie, il permet de faire entrer une tension de chaque cĂŽtĂ© et d’en restituer l’addition entre les deux rĂ©sistances : nous avons d’ores-et-dĂ©jĂ  rĂ©ussi Ă  dĂ©caler notre signal alternatif! Mais on ne peut pas s’arrĂȘter là
 Comme vous le constatez, son amplitude a Ă©tĂ© divisĂ©e de moitiĂ©, Ă  cause des rĂ©sistances. Petit apartĂ© : nous venons de toucher du doigt la notion de Gain : c’est notamment la valeur de ces rĂ©sistances qui fera varier le gain (la puissance) du signal en sortie. Il faut donc ajouter Ă  notre montage un Amplificateur OpĂ©rationnel (AO) pour retrouver l’amplitude d’origine. Mais ce dernier ne fonctionnant qu’avec des tensions alternatives, il faut bloquer la composante continue. Pour ce faire, il faut ajouter un condensateur.

Source : L'électronique pour les débutants qui sÚchent les cours mais soudent sans se brûler les doigts

Un autre exemple avec un micro :

Voici donc le rĂŽle de ce montage de base que vous retrouverez rĂ©guliĂšrement lorsqu’il s’agit de traiter des signaux audio. Vous voyez donc que plusieurs composants Ă©lectroniques entre en jeu : il est alors Ă©vident que les caractĂ©ristiques de chacun vont avoir un impact sur la qualitĂ© du signal restituĂ©. C’est ce dont nous allons traiter par la suite.

Choix du matériel

Le premier Ă©lĂ©ment Ă  choisir est le micro lui-mĂȘme, qui fera la captation du son. Sauf besoin particulier (nous l’aborderons un peu plus loin dans cet article), les modules Ă  Ă©lectrets les plus rĂ©pandus suffisent amplement.

Cependant, ils peuvent s’avĂ©rer trĂšs sensibles au bruit Ă©lectrique du circuit qui les entoure. Par exemple, s’ils sont alimentĂ©s via un adaptateur secteur, un signal de “souffle” peut apparaĂźtre mĂȘme en silence complet. De mĂȘme, sur un Arduino, la sortie 3.3V est connue pour ĂȘtre plus stable que la 5V car plus rĂ©gulĂ©e, mais l’idĂ©al reste de prĂ©voir l’alimentation du micro par pile simple.

Ensuite, l’Amplificateur OpĂ©rationnel joue un rĂŽle primordial dans la prĂ©servation de la qualitĂ© du signal. Prenons pour commencer l’exemple d’un circuit trĂšs rĂ©pandu : le Grove Sound sensor de SeeedStudio.

Il est Ă©quipĂ© d’un AO LM358 dont l’inconvĂ©nient majeur est d’induire une perte de tension d’environ 1.5V par rapport Ă  la tension d’entrĂ©e. Ce qui veut dire que par exemple, pour une tension d’entrĂ©e de 5V, la valeur maximale lue sur l’ADC de l’Arduino sera de 750 au lieu de 1024, comme expliquĂ© ici.

Il vaudra mieux donc s’orienter vers un AO possĂ©dant une vraie caractĂ©ristique “Rail-to-Rail”, c’est Ă  dire fournissant une tension de sortie Ă©gale Ă  la tension d’entrĂ©e. L’exemple le plus courant est le MAX4466, disponible sur ce circuit d’Adafruit :

Cerise sur le gñteau, ce montage dispose d’un gain ajustable, autrement dit un potentiomùtre variable à l’arriùre.

Cependant, il faut garder en tĂȘte l’usage qui va ĂȘtre fait de ce micro : s’il s’agit de capter par exemple une musique, pas de souci, il suffira de rĂ©gler le gain en fonction du volume de la source. Mais dans le cas d’une captation de son ambiant, ou environnemental, la difficultĂ© rĂ©side dans l’impossibilitĂ© de connaĂźtre le volume du son qui sera captĂ©. En effet, il n’est pas si Ă©vident de pouvoir bien capter Ă  la fois un son faible ou Ă©loignĂ© et un son fort ou proche. Dans ce cas, si le gain est rĂ©glĂ© au maximum pour capter les sons faibles, un effet de “clipping” (Ă©crĂȘtage) peut apparaĂźtre sur les sons forts, c’est-Ă -dire qu’ils seront trop amplifiĂ©s pour ĂȘtre captĂ©s entiĂšrement :

L’idĂ©al est donc de se diriger vers des montages disposant de gain automatiques, capable de passer d’un gain fort dans une ambiance calme Ă  un gain faible dans un environnement bruyant. Cela se trouve Ă©galement facilement grĂące Ă  l’AO MAX9814, disponible sur ce module Adafruit :

En plus de ce réglage automatique, il est possible de configurer un gain par défaut (40dB, 50dB ou 60dB) selon le montage.

Enfin, qui dit rĂ©glage automatique, dit rĂ©activitĂ© pour adapter le gain. Pour cela, il faut influer sur le ratio Attack:Release (broche “AR” sur le montage), qui dĂ©termine la vitesse avec laquelle le gain est diminuĂ© (“Attack”) pour atteindre le seuil nĂ©cessaire puis augmentĂ© (“Release”) pour revenir en Ă©tat initial :

Source : http://www.softube.com/images/attack-and-release-times.jpg

J'ai essayé ci-dessous d'illustrer ce concept avec les images d'un oscilloscope :

Pour aller plus loin...

Il reste encore bien des paramÚtres à prendre en compte au niveau du matériel pour obtenir une captation de bonne qualité.

Pour en citer quelques-uns, on peut commencer par la topologie des micros. En effet, une prise de son stĂ©rĂ©o se rĂ©vĂšle Ă©galement bien plus efficace : deux micros permettent de rĂ©duire les sources de bruit (ou en tout cas de le soustraire par diffĂ©rentiel) mais Ă©galement de pallier Ă  l’aspect directif de certains micros.

Cette page explique par exemple comment un couple de micro ORTF permet de reproduire un son entendu par les oreilles humaines, en tenant compte de la distance entre les micros et de leur orientation. Il existe Ă©videmment bien d’autres possibilitĂ©s selon les situations.

Au niveau logiciel

Le programme Ă  mettre en place joue Ă©galement un rĂŽle important dans la qualitĂ© du signal enregistrĂ©. Le dĂ©fi principal est d’arriver Ă  l’enregistrer de maniĂšre continue, sans ĂȘtre interrompu par d’autres tĂąches. Imaginons que vous vouliez enregistrer votre son dans un fichier WAV (sur une carte SD) : il faut ĂȘtre en mesure de continuer l’enregistrement du son le temps de l’écriture des donnĂ©es sur la carte afin de rester fidĂšle au signal d’origine et ne pas le hachurer.

Utilité des interruptions

Pour cette raison, il est prĂ©fĂ©rable d’utiliser les interruptions, disponibles sur tous les micro-contrĂŽleurs, notamment ceux Ă©quipant les Arduino (AVR ou ARM). Ceci nous permettra de lire Ă  intervalles rĂ©guliers les valeurs captĂ©es par le micro sans pour autant bloquer les processus d’écriture du fichier WAV (et inversement). Mais nous ne pouvons pas pour autant nous contenter d’écrire sur dans le fichier chaque valeur lue : en effet, le temps d’écriture dans un fichier n’étant pas nĂ©gligeable, nous perdrions trop d’informations du signal. Pour pallier Ă  ceci, il faut utiliser un tampon, dans lequel nous allons stocker par exemple 512 valeurs, avant de lancer l’écriture sur la carte SD. Mais le problĂšme reste Ă  peu prĂšs le mĂȘme... La solution optimale est d’utiliser 2 tampons en parallĂšle : une fois que le premier est rempli, on lance l’écriture sur la carte SD tandis que le second se rempli en arriĂšre-plan. Une autre technique similaire est celle du “circular buffer”. Sur les plateformes ARM, il est Ă©galement possible d’utiliser le Direct Memory Access.

Enfin, les micro-contrĂŽleurs Arduino Ă©tant cadencĂ©s Ă  plusieurs MHz et un extrait audio ne nĂ©cessitant qu’un Ă©chantillonage de l’ordre du kHz, nous utiliserons un “prescaler”, c’est-Ă -dire un diviseur pour limiter la frĂ©quence de dĂ©clenchement des interrupts.

Comprendre le convertisseur analogique-numérique

Puisque nous voulons enregistrer un signal analogique, nous allons devoir utiliser la fonction “ADC“ qui permet de convertir une valeur analogique en numĂ©rique. Il est Ă  ce stade trĂšs important de jeter un oeil Ă  la spĂ©cification de l’ATmega2560 : elle indique (page 279) qu’une conversion analogique-digital dure 13 cycles d’horloge. Voyons ce que cela implique pour nous.

Comme Ă©voquĂ© plus haut, le micro-contrĂŽleur de l’Arduino Mega 2560 est cadencĂ© Ă  16MHz. Commençons donc par rĂ©duire la frĂ©quence des interrupts par un prescaler de 32 :

16 MHz / 32 = 500 kHz

Cependant, pour prendre en compte le temps de conversion analogique-numérique, il faut encore diviser cette fréquence :

500 kHz / 13 ≈ 38 kHz 

Nous obtenons donc ici une frĂ©quence d’échantillonage finale de 38 kHz, proche de ce qui se pratique sur un CD audio (44,1 kHz). Pour cet exemple je me suis inspirĂ© de cet Instructable. Vous pourrez donc adapter ce rĂ©glage Ă  vos besoins.

Enfin, les Ă©chantillons relevĂ©s par l’ADC de l’Arduino sont codĂ©s sur 10 bits, comme prĂ©sentĂ© sur cette page. Or la plupart des formats audio le sont sur 8 bits. Il faut donc diminuer la prĂ©cision des donnĂ©es acquises (“down-sample”) pour respecter les standards. Pour ce faire, il faut paramĂ©trer l’ADC pour ne lire que les 8 bits ADCH via la commande : ADLAR=1

Prendre en compte l’offset

Vous vous souvenez de l’offset abordĂ© en dĂ©but d’article? Vous remarquerez que sur le dernier montage d’Adafruit, il est indiquĂ© “DC offset : 1.25V”. Ce qui signifie que dans un silence complet, les valeurs retournĂ©es ne seront pas de 0 mais d’une valeur lĂ©gĂšrement supĂ©rieure (dĂ©pendant du la tension d’entrĂ©e).

Ceci convient trĂšs bien Ă  l’enregistrement de fichier WAV 8 bits, qui sont codĂ©s uniquement Ă  partir de valeurs positives (unsigned int). Les logiciels de lecture (type Audacity) le savent et s’adaptent en fonction.

Cependant, Ă  des fins de traitements du signal plus poussĂ©s, il peut s’avĂ©rer nĂ©cessaire de possĂ©der Ă  la fois les valeurs positives et nĂ©gatives. Pour cela, il faudra penser Ă  soustraire la valeur de l’offset (donc du silence) des valeurs mesurĂ©es.

A vous de jouer!

Vous avez dorĂ©navant les Ă©lĂ©ments les plus importants pour vous lancer dans un projet de traitement de signal audio. J’espĂšre que cela vous aura Ă©tĂ© utile!

Catégories: Blog Individuel

L'Ă©coconception, qu'est-ce que c'est ?

Barre Verte ! - mer, 09/13/2017 - 23:00

Il y a un an environ, j’ai dĂ©butĂ© un projet d’entreprise avec deux amis associĂ©s. Ils voulaient intĂ©grer une dĂ©marche Ă©co-responsable dans la construction d’un service en ligne pour classer automatiquement leurs mails dans des dossiers dĂ©matĂ©rialisĂ©s. Comme je n’étais pas rĂ©fractaire au principe de l’écologie, et Ă  dire vrai que je n’en avais presque pas entendu parler pour l’IT, j’ai essayĂ© de me renseigner sur l’écoconception logicielle et de l’appliquer pour l’architecture du site.

Pour faire court, dans mes recherches sur ce domaine je n’ai pas trouvĂ© grand-chose. Je me suis alors demandĂ© :

L’écoconception est-elle un sujet pour le dĂ©veloppement logiciel ?

Afin d’apporter des Ă©lĂ©ments de rĂ©ponse Ă  cette question, j’ai proposĂ© un sujet Ă  l’Agile Open France et prĂ©sentĂ© une session au Lean IT Summit. Je fais Ă  travers cet article un petit pas de cĂŽtĂ© afin de partager et diffuser mon expĂ©rience en matiĂšre d’écoconception logicielle. N’hĂ©sitez pas Ă  participer et Ă  me faire part de votre propre expĂ©rience en la matiĂšre.

Eco-truc, greenIT wot ?

Les termes d’informatique dans les nuages, de serverless architecture, plateformes dĂ©matĂ©rialisĂ©es, serveurs viruels, Ă©voquent pour nous, utilisateurs des services IT/web, une forme d’évanescence, d’immatĂ©rialitĂ© des infrastructures informatiques. Cela Ă©voque en tout cas quelque chose sans lien avec l’écologie. Et a fortiori avec l’écologie appliquĂ©e au monde du numĂ©rique.

GreenIT, Ă©co-reponsabilitĂ© des services informatiques, Ă©coconception, “conception responsable des services numĂ©riques”, derriĂšre ces expressions se cachent en rĂ©alitĂ© deux enjeux majeurs relativement ignorĂ©s pour l’instant des acteurs du numĂ©rique :

  1. prendre conscience que les services numĂ©riques ont un impact sur l’environnement. Par ailleurs, les enjeux environnementaux sont globaux, comme internet. Il y a une certaine congruence entre les deux ;
  2. adopter une approche de rationalisation de l’usage des infrastructures informatiques, en intĂ©grant une rĂ©flexion dĂšs la conception des logiciels et du matĂ©riel

La prise en compte de ces deux enjeux est complexe car elle n’est pas uniquement liĂ©e Ă  l’exploitation des machines (par exemple la consommation Ă©lectrique des centres d’hĂ©bergement), mais elle doit aussi englober tout le cycle de vie des produits :

Cycle de vie produit

En regardant l’ensemble du cycle pour les produits manufacturĂ©s impliquĂ©s dans la mise en oeuvre et l’utilisation d’un service en ligne, nous rĂ©alisons l’étendue de l’impacts des technologies de l’information : production, acheminement, utilisation, recyclage des mobiles, serveurs, routeurs, ordinateurs portables, ordinateurs fixes, tablettes, switches, rĂ©pĂ©teurs, antennes, cĂąbles, fibre optique, climatiseurs, onduleurs, etc.

“OK, ça reprĂ©sente 2% des Ă©missions de CO2, occupons-nous des 98%” entendra-t-on

Oui mais ces 2% ne reprĂ©sentent que l’exploitation des infrastructures du web et cette statistique est statique.

La production des produits Ă©lectroniques nĂ©cessite l’utilisation de matiĂšres premiĂšres non renouvelables et pour certaines en voie d’épuisement. L’OCDE donne encore 30 ans d’exploitation pour le cuivre, plomb, nickel, argent, Ă©tain, zinc. Cette production dĂ©gage Ă©galement des dĂ©chets environnementaux et des gaz Ă  effet de serre.

De plus, le recyclage est une gageure car de plus en plus de matiÚres sont employées pour la miniaturisation, et beaucoup sont toxiques : mercure, cadnium, chrome, diphényls polybromés, PVC, baryum, beryllium, phosphore, etc. Pour certaines de ces matiÚres, ce ne sont pas des quantités négligeables qui sont en jeu : en 2000 les équipements électroniques et informatiques utilisaient 22% de la consommation annuelle de mercure [1]. Par ailleurs, ces matiÚres se retrouvent souvent traitées dans des pays en voie de développement dans des conditions plus que précaires.

Enfin, nous Ă©mettons des gaz Ă  effet de serre par le biais de ces produits tout au long de leur cycle de vie. L’empreinte carbone des infrastructures du web Ă©tait de 0,91 Giga tonnes d’équivalent CO2 (1,9% de l’empreinte mondiale) en 2011. Le Boston Consulting Group prĂ©voit qu’elle sera de 1,27 Giga tonnes en 2020 (2,3% du global) soit une augmentation de prĂšs de 40% en 9 ans. Dans le rapport ci-dessus, il est expliquĂ© (p22) que ces projections ne prennent pas en compte les impacts incertains du recyclage. Je n’y ai pas trouvĂ© non plus de rĂ©fĂ©rences Ă  l’explosion des objets connectĂ©s qui vont passer de 6 milliards en 2016 Ă  20 milliards en 2020 [2].

Alors que les constructeurs d’infrastructures (centre serveurs, rĂ©seaux mobiles, rĂ©seau mondial) ont dĂ©jĂ  pris des mesures pour amĂ©liorer leur efficacitĂ© Ă©cologique (en gĂ©nĂ©ral pour des raisons Ă©conomiques), le monde du logiciel ne semble pas beaucoup concernĂ©.

Pourtant Ă  la lumiĂšre de ces cycles de vie, en tant que dĂ©veloppeur je m’aperçois que mes dĂ©cisions techniques ne sont pas neutres : quelles sont les consĂ©quences pour les internautes si je choisis d’utiliser une prĂ©sentation “flexbox” ? Quelle va ĂȘtre la diffĂ©rence de consommation du serveur si je fais du polling toutes les secondes sur une valeur ? Que se passe-t-il si le navigateur de l’internaute n’exĂ©cute pas le javascript ? Quelle est la diffĂ©rence en performance et en consommation si je fais un service multithreadĂ© ou asynchrone ? Quelle va ĂȘtre la part de charge et consommation si mon service est gratuit, et que je fais du big data/intelligence artificielle pour vendre de la publicitĂ© de maniĂšre profitable ? Quelle diffĂ©rence si je fais du payant sans exploitation de donnĂ©es ? Quelle part du framework lambda j’utilise ? Puis-je m’en passer ?

Bref, si je souhaite participer Ă  l’efficacitĂ© Ă©cologique, cela implique :

  • une rĂ©flexion sur mon service et son modĂšle Ă©conomique
  • une sobriĂ©tĂ© du nombre de fonctions implĂ©mentĂ©es
  • une simplicitĂ© de dĂ©veloppement du code informatique
  • des choix technologiques adaptĂ©s
  • la lutte contre l’obsolescence programmĂ©e des versions logicielles

et concerne bien plus que le périmÚtre des équipes de développement. Cependant, ces derniÚres peuvent apporter leurs éclairages techniques sur la maniÚre dont les machines vont exécuter leur code.

Nous continuerons cet article avec un éclairage sur le dévelopement logiciel et le software craftmanship.

  1. la face cachée du numérique - Fabrice Flipo, Michelle Dobré et Marion Michot
  2. Gartner : http://www.gartner.com/newsroom/id/3165317
Catégories: Blog Individuel

ConfĂ©rence « Des Transformations Agiles
 enfin Agiles »

Qualitystreet - Jean Claude GROSJEAN - sam, 09/09/2017 - 18:06

Retrouvez- moi Ă  Paris lors de la confĂ©rence « Agile en Seine ». Je serai accompagnĂ© pour l’occasion de Sylviane Luong (Coach Interne) pour parler transformation agile des organisations avec comme principale illustration notre actuel terrain de jeu. Ce sera donc le 20 septembre Ă  10 h30. Visiblement salle de 30 places
 Au programme
 et bien vous…

The post ConfĂ©rence « Des Transformations Agiles
 enfin Agiles » appeared first on QualityStreet - Blog Agile depuis 2007.

Catégories: Blog Individuel

LCC 176 - Le paradoxe de la fondation

Antonio, Arnaud, Vincent et Emmanuel commentent les informations de l’étĂ©: diversitĂ©, java dans un container, Java EE dans une fondation, les licences Facebook vs la fondation Apache et plus.

Enregistré le 1 septembre 2017

TĂ©lĂ©chargement de l’épisode LesCastCodeurs-Episode–176.mp3

Comment faire un crowdcasting

News

Les Ă©pisodes des cast codeurs en licence Creative Commons by-nc-nd

Langages

Java Still Number One, But What’s Taking Over? Le guide Bash ultime Ceylon rejoint Eclipse

Server JRE Garbage Collecteur G1 et comment le maitriser la bĂȘte dans tes microservices Java vs Docker: comment configurer sa JVM (Java SE support for Docker CPU and memory limits)

Les principaux paradigmes de programmation Excel est un Nonmonotonic dataflow programming :)

LĂ©gal

Facebook et sa licence BSD + brevet (react.js et RockDB):

Middleware

Java EE dans une fondation ? Bean Validation approuvé Java EE 8 approuvé aussi

Web

Bootstrap passe en béta

Loi, société et organisation

France: un pays de gros lourds Elles inventent un co-fondateur homme pour leur start-up, et c’est « le jour et la nuit »

Cefcys L’épisode de NoLimitSecu sur le Cefcys

Google et le mémo sur la chambre a echo de Google:

How to Raise a Feminist Son

Outils de l’épisode

Un Chromebook pour coder Site Reliability Engineering book

Conférences

JUGSummerCamp 15 septembre devops REX le 2 octobre Ă  Paris DevFest Nantes les 19 & 20 Octobre - Inscriptions Scala.io le 2 et 3 novembre Ă  Lyon - Inscriptions Devoxx Belgique du 6 au 10 novembre - Inscriptions BDX.io 10 novembre Devoxx Maroc 14–16 novembre Codeurs en Seine Ă  Rouen le 23 novembre 7Ăšme Ă©dition de SoftShake - GenĂšve (seulement 3h de Paris en train !) le CfP est ouvert 3eme Ă©dition du Paris OpenSource Summit les 6 & 7 DĂ©cembre (CfP ouvert jusqu’au 15 septembre) Snowcamp 2018 du 24 au 27 janvier ; le CFP est ouvert

Nous contacter

Faire un crowdcast ou une crowdquestion Contactez-nous via twitter https://twitter.com/lescastcodeurs sur le groupe Google https://groups.google.com/group/lescastcodeurs ou sur le site web https://lescastcodeurs.com/ Flattr-ez nous (dons) sur https://lescastcodeurs.com/ En savoir plus sur le sponsoring? sponsors@lescastcodeurs.com

Catégories: Blog Individuel

Partagez la connaissance

Partagez BlogsdeDeveloppeurs.com sur les réseaux sociaux