DeltaLab est une association ‘loi 1901’ d’intérêt général, dont l’objectif est la création d’un espace dédié à l’innovation, à la production numérique au prototypage et à l’«expression artistique».
Le principe fondateur de l’association est d’apprendre à faire soi-même, pour passer de l’idée à l’objet.
Deltalab se spécialise en Objets Connectés, et est en train de créer un vaste «écosystème numérique» entre Drôme et Vaucluse, pour répondre à des besoins non couverts, mettre à disposition ressources et équipements pour usage professionnels et instaurer des partenariats avec les autres structures et initiatives numériques existantes.
Deltalab est aussi un FabLab (Fabrication Laboratory / Laboratoire de Fabrication ), un tiers-lieu de type makerspace où se trouve un atelier qui dispose de machines de fabrication comme des Imprimantes 3D ou des découpeuses Laser.
Deltalab se veut ouvert à tous publics : étudiants, professionnels, associations, inventeurs, designers, artistes, etc.
Un des projets à moyen termes de DeltaLab est l’installation d’un réseau LoRaWAN permettant la collecte et le traitement d’un grand nombre de données, et ce sur une grande zone s’étendant sur l’enclave des Papes et la Drôme Provençale.
Ce document est une présentation de l’utilisation du réseau LoRaWAN dans un exemple concret : la mise en place d’un objet connecté, ici un CubeCell, équipé d’un capteur de température / humidité / pression, le BME280.
Ce document a pour but de montrer comment monter / programmer votre CubeCell afin qu’il puisse envoyer les données via le réseau LoRaWAN. Ici il s’agit d’une capsule équipée d’un panneau solaire, le modèle HTCC-AC02.
On verra plus tard pour l’équiper d’un capteur de température, de pression et d’humidité.
Arduino IDE : téléchargeable à www.arduino.cc/en/main/software
Node-RED : on assume que vous en avez un, sinon installez-le avec ceci.
CubeCell capsule solar sensor HTCC-AC02
CubeCell capsule debug board
Câble USB-micro USB type B (vous pouvez en acheter ici)
Capteur BME280
Un PC (sous Windows)
Dévissez la partie transparente de la capsule.
Emboîtez le debug board de sorte que les deux points blancs soient face à face.
Branchez le câble au debug board, et......STOP!!!!!
On arrête la manipulation ici, on passe à Arduino.
Pour installer Arduino IDE, suivez le tuto du site.
Une fois installé, allez dans Fichier > Préférences et ajoutez ce lien dans URL de gestionnaire de cartes supplémentaires en cliquant sur le bouton à droite.
https://github.com/HelTecAutomation/CubeCell-Arduino/releases/download/V1.3.0/package_CubeCell_index.json
Ce fichier va vous permettre de coder pour des CubeCell.
Ensuite, allez dans Outils > type de carte > Gestionnaire de carte.
Et tapez cube dans la barre de recherche, puis installez cette carte à la dernière version.
Toujours dans Outils, sélectionnez la carte HTCC-AC0X en allant dans Type de carte > CubeCell.
Une fois fait, vous devriez voir cela dans Outils. Veuillez donc mettre les paramètres comme indiqués sur l'image.
Avant de lancer le code, il faut brancher le CubeCell au PC, MAIS il y a une manipulation à faire avant chaque branchement du CubeCell au PC. Veuillez maintenir le bouton USER du debug board > branchez le CubeCell > relachez USER.
Une fois fait retournez dans Outils pour sélectionner le port où est branché le CubeCell.
Puis, il faut rentrer le CubeCell en mode bootloader ce qui aura pour effet de le réinitialiser. Pour cela maintenez le bouton USER > cliquez sur RST > relâchez USER.
Affichez maintenant le Moniteur série en cliquant sur la loupe en haut à droite :
Vous devriez avoir ce message sur l'image ci-dessous.
ATTENTION : Il faut pensez à la batterie de l'objet, donc tant que vous testez votre CubeCell il faut le réinitialiser après chaque upload pour ne pas qu'il tourne en boucle.
Munissez-vous du capteur BME280, et faite attention à ne pas prendre le BMP280 leur différence est à peine visible.
Branchez-le à l'arrière du debug board sur les ports indiqués.
Pour tester le capteur avec Arduino, allez dans Fichier > Exemples > Sensor - Third Party > BME280 > bme280_example.
Avant de lancer le programme, il faut installer la librairie qui correspond au capteur: Grove-Barometer Sensor BME280 - version 1.0.2
Dans Arduino: Croquis > Inclure une bibliothèque > Gérer les bibliothèques, copiez le nom de la librairie dans la barre de recherche et prenez la version indiquée.
Faites marcher le programme avec le Moniteur série en allant dans Outils pour voir le résultat.
Grove-Barometer Sensor BME280-version 1.0.2 (allez dans Outils > Gérer les bibliothèques et tapez bme280 dans la barre de recherche, puis trouvez et installez cette librairie à la dernière version)
LoRaWan_APP
Arduino
Wire
Copiez-collez le code ci-dessous dans un nouveau fichier Arduino
/*Librairies*/
#include "LoRaWan_APP.h"
#include "Arduino.h"
#include "Seeed_BME280.h"
#include <Wire.h>
/*Constantes de temps*/
static const uint32_t DELAI_1_S = 1000;
static const uint32_t DELAI_1_M = 60 * DELAI_1_S;
static const uint32_t DELAI_1_H = 60 * DELAI_1_M;
/*Variables*/
/* OTAA para*/
/* format msb*/
uint8_t devEui[] = { /*disponible lors de la création de l'objet sur TheThingsNetwork */};
uint8_t appEui[] = { /*disponible lors de la création de l'objet sur TheThingsNetwork */ };
uint8_t appKey[] = { /*disponible lors de la création de l'objet sur TheThingsNetwork */};
/* ABP para*/
uint8_t nwkSKey[] = { 0x15, 0xb1, 0xd0, 0xef, 0xa4, 0x63, 0xdf, 0xbe, 0x3d, 0x11, 0x18, 0x1e, 0x1e, 0xc7, 0xda, 0x85 };
uint8_t appSKey[] = { 0xd7, 0x2c, 0x78, 0x75, 0x8c, 0xdc, 0xca, 0xbf, 0x55, 0xee, 0x4a, 0x77, 0x8d, 0x16, 0xef, 0x67 };
uint32_t devAddr = ( uint32_t )0x007e6ae1;
/*LoraWan channelsmask, default channels 0-7*/
uint16_t userChannelsMask[6] = { 0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 };
/*LoraWan region, sélectionné dans Outils de Arduino*/
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;
/*LoraWan Class, sélectionné CLASS A dans Outils de Arduino*/
DeviceClass_t loraWanClass = LORAWAN_CLASS;
/*délai de transmission entre chaque paquet de données. valeur en [ms].*/
uint32_t appTxDutyCycle = DELAI_1_H;
/*OTAA ou ABP*/
bool overTheAirActivation = LORAWAN_NETMODE;
/*ADR enable*/
bool loraWanAdr = LORAWAN_ADR;
/*configurez LORAWAN_Net_Reserve sur ON, le noeud peut sauvegarder les informations du réseau en flash, lorsque le noeud est réinitialisé, il n'est pas nécessaire de le rejoindre à nouveau. */
bool keepNet = LORAWAN_NET_RESERVE;
/* Indicates if the node is sending confirmed or unconfirmed messages */
bool isTxConfirmed = LORAWAN_UPLINKMODE;
/* Application port */
uint8_t appPort = 2;
/*Nombre d’essais pour envoyer le paquet de données */
uint8_t confirmedNbTrials = 4;
/* Variable des données*/
float temperature, humidity, pressure;
/* Compteur*/
int count;
/* Maximum du compteur*/
int maxtry = 50;
/* Variable du capteur*/
BME280 bme;
/*!
\brief Prépare le contenu de la trame
*/
static void prepareTxFrame( uint8_t port ){
pinMode(Vext, OUTPUT);
digitalWrite(Vext, LOW);
delay(500);
count = 0;
if (!bme.init()) {/*Si le capteur ne s’ initialise pas il affiche une erreur*/
Serial.println("Device error!");
}
delay(500);
temperature = bme.getTemperature(); //récupère la donnée de température
pressure = (float)bme.getPressure() / 100.0; //récupère la donnée de pression
humidity = bme.getHumidity(); //récupère la donnée d'humidité
Wire.end();
while (pressure > 1190.0 && count < maxtry) {/*Si la valeur de pression est incorrecte*/
bme.init();
delay(500);
pressure = (float)bme.getPressure() / 100.0;
Wire.end();
count++;
delay(500);
}
if (pressure > 1190.0) {/*Si la valeur de pression n’est toujours pas correcte*/
pressure = 0;
Serial.println("BME ERROR");
}
Wire.end();
digitalWrite(Vext, HIGH);
uint16_t batteryVoltage = getBatteryVoltage(); //récupère la quantité de batterie restante en mV
// Insertion des données dans le tableau de donnée qui sera envoyé
unsigned char *puc;
puc = (unsigned char *)(&temperature);
appDataSize = 15;
appData[0] = puc[0];
appData[1] = puc[1];
appData[2] = puc[2];
appData[3] = puc[3];
puc = (unsigned char *)(&humidity);
appData[4] = puc[0];
appData[5] = puc[1];
appData[6] = puc[2];
appData[7] = puc[3];
puc = (unsigned char *)(&pressure);
appData[8] = puc[0];
appData[9] = puc[1];
appData[10] = puc[2];
appData[11] = puc[3];
puc = (unsigned char *)(&batteryVoltage);
appData[12] = puc[0];
appData[13] = puc[1];
//Affichage des données sur le Moniteur Série
Serial.print("T = ");
Serial.print(temperature);
Serial.print(" C, RH = ");
Serial.print(humidity);
Serial.print(" % ");
Serial.print("Pressure = ");
Serial.print(pressure);
Serial.print(" hPA");
Serial.print(", BatteryVoltage: ");
Serial.println(batteryVoltage);
}
void setup() {/*Initialisation du programme*/
Serial.begin(115200); //Démarrage du moniteur série
#if(AT_SUPPORT)
enableAt();
#endif
deviceState = DEVICE_STATE_INIT; // Statut de l'objet mis sur initialisation
LoRaWAN.ifskipjoin(); // Envoi directement les données si LORAWAN_Net_Reserve est sur ON
}
void loop() {/*Tourne en boucle le programme*/
switch ( deviceState )
{
case DEVICE_STATE_INIT:
{
#if(LORAWAN_DEVEUI_AUTO) // Génère le DevEUI si cette option est mise sur Generate by ChipID dans // les Outils
LoRaWAN.generateDeveuiByChipID();
#endif
#if(AT_SUPPORT)
getDevParam(); //Récupère les EUIs de l'objet
#endif
printDevParam(); //Affiche les EUIs de l'objet
LoRaWAN.init(loraWanClass, loraWanRegion); // Initialise la connection avec TheThingsNetwork
deviceState = DEVICE_STATE_JOIN; // passe l'état de l'objet à joindre pour dire qu'il est prêt à // rentrer en communication avec TTN
break;
}
case DEVICE_STATE_JOIN:
{
LoRaWAN.join(); // l'objet établie la connection avec TTN
break;
}
case DEVICE_STATE_SEND:
{
prepareTxFrame( appPort ); // Prépare le message de données à envoyer
LoRaWAN.send(); // Envoi du message
deviceState = DEVICE_STATE_CYCLE;
break;
}
case DEVICE_STATE_CYCLE:
{
//Prépare le temps de cycle de sommeil
txDutyCycleTime = appTxDutyCycle + randr( 0, APP_TX_DUTYCYCLE_RND );
LoRaWAN.cycle(txDutyCycleTime);
deviceState = DEVICE_STATE_SLEEP; // passe l'état de l'objet en sommeil
break;
}
case DEVICE_STATE_SLEEP:
{
LoRaWAN.sleep(); // Cycle de sommeil de l'objet
break;
}
default:
{
deviceState = DEVICE_STATE_INIT; // Par défaut, l'objet est en état d'initialisation
break;
}
}
}
Avant de lancer le programme, il faut créer la réception des données sinon le code tournera en boucle sans rien faire.
Sur The Things Network, il est possible d'enregistrer son objet pour voir le flux de données.
Avant cela, si vous n'avez pas d'antenne LoRaWAN pour recevoir les données allez ici.
Sur TTN (www.thethingsnetwork.org/), connectez-vous (ou créez un compte), allez dans la console en cliquant sur votre profil, allez dans Applications et Ajoutez une nouvelle appli. Renseignez un ID, un nom et une description (facultatif).
Dans cette application, ajoutez un nouveau End Device. Renseignez les informations de votre objet connecté.
Brand: HelTec AutoMation
Model: HTCC-AC02 (Class A OTAA)
Profile (Region): EU_863_870
Sélectionnez la fréquence dans Frequency plan dont l'endroit correspond à la région où sera placé votre objet. En Europe, on prendra la fréquence Europe 863-870 MHz(SF9 for RX2-recommended).
L’AppEUI devrait être renseigné par le fabricant ou remplissez avec des zéros.
Le DevEUI est soit renseigné par le fabricant ou imprimé sur le paquet soit générer par le bouton juste à droite.
L’Appkey est soit renseigné par le fabricant soit générer par le bouton juste à droite.
ET MAINTENANT
Dans l'overview de votre End Device , vous avez accès aux EUIs et à l’AppKey nécessaires dans le programme. Pour les EUIs, cliquez sur les chevrons à droite de chacun d'eux, ils seront au format msb.
Et ça tombe bien, sur Arduino les EUIs sont au format msb. Vous pouvez les copiez et les collez dans le code.
ATTENTION: Pour l' AppKey, il faudra la rendre visible en cliquant sur l'œil et dans le code remplacez seulement les chiffres après les 0x.
On utilise un décodeur sur TTN car les données qui sont créées par les objets sont au format binaire donc illisible pour l’homme.
On utilisera le langage Javascript pour créer notre propre décodeur.
Dans Application > End devices > votre device > Payload Formatters et dans Uplink sélectionnez Javascript dans le menu déroulant. Copiez-collez le code ci-dessous dans la zone 'Formatter parameter'. Et cliquez sur Save changes pour sauvegarder. Et vérifiez l'indentation sinon cela ne fonctionnera pas.
function B2F32(bytes) { // Convertit les données binaires en nombres à virgules
var sign = (bytes & 0x80000000) ? -1 : 1;
var exponent = ((bytes >> 23) & 0xFF) - 127;
var significand = (bytes & ~(-1 << 23));
if (exponent == 128)
return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);
if (exponent == -127) {
if (significand === 0) return sign * 0.0;
exponent = -126;
significand /= (1 << 22);
} else significand = (significand | (1 << 23)) / (1 << 23);
return sign * significand * Math.pow(2, exponent);
}
function Decoder(bytes, port) { // Envoi du message de donnée au serveur MQTT
var tmp = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
var hum = bytes[7] << 24 | bytes[6] << 16 | bytes[5] << 8 | bytes[4];
var pre = bytes[11] << 24 | bytes[10] << 16 | bytes[9] << 8 | bytes[8];
var batterie = bytes[13] << 8 | bytes[12];
return{
tmp: B2F32(tmp) , press: B2F32(pre), hum: B2F32(hum), batterie
}; }
Maintenant vous pouvez upload votre programme, si vous voulez suivre ce que le programme fait allez dans Outils et cliquez sur Moniteur série.
Pour que l’on puisse récupérer les données avec Node-RED, nous allons créer un serveur MQTT.
Toujours dans TheThingsNetwork dans votre Application, allez dans Integrations > MQTT. Cliquez sur Generate new API key et copiez-la car elle ne sera plus visible si vous quittez la page. L' API key servira de mot de passe.
Ça y est, on peut maintenant traiter les données avec Node-RED.
Le capteur envoie ses données et TTN les récupère. Node-RED les lit ensuite grâce à la node mqtt-in.
Les données sont récupérées par les nodes de dashboard qui permettent de les afficher : des jauges pour la pression, l'humidité et la température, ainsi qu'un graphe pour l'évolution de ces deux dernières.
Chaque fois que vous finissez de configurer un node, cliquez sur Done.
ATTENTION : pour enregistrer vos modifications, cliquez sur Deploy.
Pour commencer, on va vouloir récupérer les données reçu par l’antenne LoRaWAN via TTN. Prenez ce node, double-cliquez dessus.
Dans le menu de sélection Server, prenez Add new mqtt-broker et cliquez sur le bouton à côté.
Dans la partie Security, entrez les identifiants en accord avec ceux lors de la création du serveur MQTT.
Dans la partie Connection, précisez l’adresse du serveur MQTT de la Console The Things Stack. Et dans Protocol, sélectionnez MQTT V3.1.1.
Revenez dans les propriétés. Le topic sert à préciser de quel objet on veut traiter les données. Voici le format du topic : v3/username/devices/device_id/up. Faites attention à ce qu’il n’y est pas d’espace surtout au début et à la fin.
Sélectionnez le QoS que vous voulez (privilégiez le 2).
Et dans Output, prenez a parsed JSON object.
Pour finir, branchez une node de debug pour voir si les données de l’objet choisi arrive bien.
N'hésitez pas à connectez des nodes de debug, cela permet de savoir si vos données arrive bien et au bon format.
Pour voir les données là où vous avez connecté des debug, cliquez sur le petit insecte en haut à droite de l'écran, puis all nodes puis current flow pour voir le flux du flow sur lequel vous travaillez.
Pour les jauges, prenez trois de ce node et connectez-les au mqtt-in et configurez-les de cette manière :
Group: créez un nouveau groupe
ui_tab : créez une nouvelle table
width(largeur) : à votre guise
name : celui que vous voulez
Type: gauge
Label: température, humidité, pression
Value format:
température: {{msg.payload.uplink_message.decoded_payload.tmp.toFixed(2)}}
humidité: {{msg.payload.uplink_message.decoded_payload.hum.}}
pression: {{msg.payload.uplink_message.decoded_payload.press.toFixed(2)}}
Echelle:
température: -5 à 45, unité : °C
humidité: 0 à 100, unité : %
pression: 900 à 1200, unité : hPa
Pour la température, cliquez sur add en bas à gauche de Rules.
Mettez la première règle sur Set. Entrez topic, puis tmp ou Température en-dessous.
Ajoutez une deuxième règle et mettez-la sur Move, entrez payload.uplink_message.decoded_payload.tmp dans le premier champ et payload dans le deuxième.
Faites la même chose pour l’humidité et batterie, changez juste les valeurs de température( remplacez tmp par hum pour humidité et batterie pour la batterie ).
Pour le node change Séléc des données, prenez les règles Move de la température et de l' humidité et copiez-les.
Et n’oubliez pas de faire attention à ne pas laisser d’espace.
Copiez-collez ceci dans la section Function
Pour la température:
var temp1 = msg.payload.toFixed(2);
var newMsgtemp = { payload: temp1 , topic:"Temperature"};
return newMsgtemp;
Pour la batterie:
var value = msg.payload;
if (value < 3000){
msg = "Batterie faible!!!";
}
else msg = "Batterie en bon état";
return {
payload:{ msg:msg }
}
Pour la carte:
return{
payload:{
name:"CubeCell",
lat: utilisez géoportail pour connaître les valeurs GPS de l'endroit où est posé le Cubecell ,
lon: idem ,
icon:"fa-map-marker",
iconColor:"red",
ttl:800,
capteur:"BME280",
temp:msg.payload.tmp.toFixed(2) + " °C",
hum:msg.payload.hum + " %"
}
}
Group: le même que celui des gauges
Type: line chart
axe Y: min = -15 , max = 45 (ou 0 / 40 - pour la beauté de la grille )
Cochez la case enlarge points
Réglez le nombre de points max ou la durée représentée comme vous le souhaitez
Group: le même que celui des gauges
Label: Etat de la Batterie
Value format: {{msg.payload.msg}}
Layout: prenez celui avec label au-dessus de value
Name(optionnel): donnez un nom
Send: the existing msg object
then: resend it every
4 seconds
Name(optionnel): donnez un nom
Group: le même que celui des gauges
Latitude: celle trouvez sur géoportail
Longitude: idem
Zoom: 12
Base map: OpenStreetMap
Web Path: /worldmap
Name(optionnel): donnez un nom
L'intérêt de tout ceci est pour la visualisation des données. Node-RED permet ceci avec une interface utilisateur.
Pour y accéder, avec le moteur de recherche que vous voulez, tapez l'ip du serveur Node-RED, puis deux points, puis le numéro port puis /ui (XXX.XXX.XXX.XXX:YYYY/ui).
Pour mettre en forme l'interface utilisateur, retournez dans Node-RED
Cliquez sur les trois barres en haut à droite, allez dans View puis cliquez sur Dashboard.
En mettant le curseur sur le nom du groupe des jauges et du graphe, cliquez sur layout.
Sur la droite réglez la largeur de l'interface sur Width. Ensuite cliquez sur Done, puis sur Deploy et revenez dans le layout pour faire la mise en forme. Essayez d'obtenir le résultat ci-dessous.
Pour modifier la taille des composants, cliquez sur le cadenas en haut à droite du composant et une double flèche apparait en bas à droite de ce dernier. Maintenez le clique dessus pour modifier la taille.