Initiation à Raspberry Pi

La carte Raspberry Pi avec son système d’exploitation Raspbian constitue un nano ordinateur “à tout faire”. Nous découvrirons ici comment accéder à cette carte via son interface graphique puis via une console.

Les vidéos présentent :

  • présentation de l’interface graphique
  • utiliser un Raspberry Pi à distance avec WinSCP et Putty
  • Installation du serveur web Apache

Utiliser un service de messagerie dédié à l’internet des objets

MQTT ou MQ Telemetry Transport (MQ signifiant Message Queue) est un protocole de messagerie extrêmement simple et léger conçu pour les appareils à faible ressources et des réseaux à bande passante limitée. Ce protocole est idéal pour l’internet des objets ainsi que pour les applications mobiles où bande passante et économie d’énergie sont primordiales

MQTT permet à divers appareils de publier des informations (par exemple une sonde de température peut publier le résultat de ses mesures) vers un serveur nommé « BROKER » (courtier en français). Le broker pousse alors les données vers les clients qui sont abonnés au service. Pour différencier les différents services, les objets publient leurs résultats dans des « topics ». Le topics s’écrivent en utilisant un format permettant plusieurs niveaux, chaque niveau est séparé par un slash « / »

Par exemple : 

smarthome/chambre/temperature
smarthome/chambre/light

mqttschema.png

Activité MQTT

Pour cette activité les élèves utilisent leur téléphone. Ils installeront une application qui permet de créer simplement des interfaces homme machine (IHM) et qui utilise le protocole MQTT pour envoyer des données au téléphones de leurs camarades

Activité Node-Red

Offrir une plateforme permettant de tirer profit d’un parc d’objets connectés est un challenge que certaines entreprises technologiques ont relevé. Des acteurs majeurs, comme AT&T ou IBM, proposent de faciliter la construction de plateformes globales offrant un ensemble de solutions pour gérer cette problématique. Cela couvre la collecte des données émises, leur transport, la capacité à créer des flux de données et de traiter l’information reçue, mais aussi de déclencher des actions sur des capteurs actifs… Le fil conducteur de ces plateformes est de permettre la création rapide de nouvelles applications ou services.
IBM a travaillé autour d’une solution logicielle open sourcée permettant la création de chaînes de traitement. Cette solution se nomme Node-Red (https://nodered.org/). La vocation de cette solution est de permettre de lier aisément des sources de données à des composants de traitement, locaux ou distants, et de créer des chaînes de valeurs en quelques clics.
Cet outils permet au développeur de se concentrer sur le « ce que je veux faire » plus que le « comment je vais faire ». Il s’agit d’un outil graphique permettant la conception simple d’IHM (et temps réel) et la création de chaines de traitement et de commande de parties opératives.

Il existe des plateformes de développement en ligne telle que fred.sensetecnic.com qui permettent de créer des activités sans rien installer. Un ordinateur avec une connexion internet suffit.

L’activité est complémentaire de celle utilisant des téléphones portables : elle permet la création d’IHM sur un ordinateur.

Site RESTful avec Slim3 et ng-admin

SLIM 3 est un microframework php qui permet de créer des API. Associé à un module AngularJS nommé ng-admin[0], il permet de construire un tableau de bord d’administration d’une base de données dans une application de type SPA (Single Page Application). Nous verrons ici comment mettre en œuvre l’ensemble.

Les vidéos

  1. Création du projet dans NetBeans, installation du micro Framework Slim 3 avec composer
  2. Création de l’API. mise en place du routage, interrogation de ma base mySQL
  3. Installation du moteur de vue ng-admin et affichage d’une liste de données.
  4. Ajout, modification et suppression de données en faisant interagir ng-admin et l’API Slim 3

Prérequis

L’ordinateur hôte de la solution doit avoir :

Tous ces logiciels sont multiplateformes et fonctionnent quel que soit l’OS.

Création de la solution (Netbeans)

Dans Netbeans (exemple pour créer un projet portant le nom : « monProjet »)

Fichier->Nouveau Projet cela lance un assistant en 5 points

  1. Sélectionner un projet : Choisir Catégories -> PHP et Projets -> PHP Application, cliquer sur Suivant
  2. Name and Location : Project Name : monProjet, Sources Folder : pointer sur le dossier root du serveur et un sous dossier portant le nom du projet : par exemple c:\laragon\www\monProjet, PHP version (celle qui est installée sur l’ordinateur), Default Encoding : UTF-8, cliquer sur Suivant.
  3. Run Configuration : Run As : Local Web Site, project URL : le chemin du virtual host créé sur le serveur (si ce n’est fait automatiquement, il faut le faire) : http://monProjet.dev:8080
  4. PHP Frameworks : laisser vide, cliquer sur Suivant
  5. Composer : (installation des bibliothèques php nécessaires au projet, ici nous allons ajouter le paquet Slim 3 et le paquet Slim PDO).
    Dans token -> slim puis cliquer sur Search, sélectionner slim/slim, dans la liste déroulante Version choisir 3.x-dev , puis cliquer sur le bouton afin de faire apparaitre slim/slim (3.x-dev) dans la fenêtre de droite.
    refaire la même chose avec le paquet slim/PDO version dev-master

Cliquer sur Terminer, les différents dossiers du projet vont être créés, et composer va télécharger et installer les bibliothèques

A l’issue de l’opération, le dossier du projet ressemble à ceci :

Le dossier nbprojet contient les fichiers de paramétrage du projet necessaires à NetBeans (on n’y touche jamais)

Le dossier vendor, qui contient les bibliothèques téléchargées et un fichier autoload.php, qui comme son nom l’indique, permet de charger automatiquement les classes et leur espace de nom afin de les rendre disponibles facilement.

Composer.json est le fichier qui contient les références des packages installés,

{
    "name": "vendor/mon-projet",
    "description": "Description of project monProjet.",
    "authors": [
        {
            "name": "francois",
            "email": "your@email.here"
        }
    ],
    "require": {
        "slim/slim": "3.x-dev",
        "slim/pdo": "dev-master"
    }
}

Si on ajoute ou supprime une dépendance dans la partie « require » du fichier, puis qu’on effectue une commande composer update, le projet se met à jour automatiquement et chargeant ou déchargeant les bibliothèques ajoutées ou retirées. Un autoload.php est alors recréer. Composer.lock contient les informations de l’autoload actuel. (on ne touche jamais ce fichier).

Enfin un fichier index.php et un squelette de page web

L’API

Dans notre application, tous les accès au modèle de données se font au travers de requêtes web vers une API en respectant le format REST[1].

Le format REST considère l’url, non plus comme l’appel d’une page web mais comme l’appel à une fonction, les arguments étant passés soit dans l’url (pour les requêtes de type GET, DELETE) dans le corps (pour les requêtes POST) ou bien les deux (requêtes PUT).

Dans le format REST, les verbes des requêtes permettent de définir le type d’action que le serveur devra effectuer.

Exemple :

Verbe

url

Action

GET

/products   

Récupère un jeu de
données contenant tous les éléments « products »

GET

/products/:id

Récupère un jeu de
données contenant 1 élément « products » ayant l’identifiant « :id »

POST

/products   

Créer un « product »
dans la table « products » , les paramètres passent dans le corps
de la requête

PUT

/products/:id

Mise à jour du product
 d’identifiant « :id », les
paramètres passent dans le corps de la requête

DELETE

/products/:id

Destruction du product
d’identifiant « :id »

Grâce à ces 4 verbes, on peut créer des services web qu’on nomme CRUD (Create Read Modify Delete).

Le serveur renvoie au client un jeu de données soit au format XML soit au format JSON.

Exemple :

GET /products

Renvoie un tableau JSON de type :

[
    {
      "id": 1,
      "name": "LG P880 4X HD",
      "description": "My first awesome phone!",
      "price": null,
      "category_id": 5,
      "created": "2014-06-01 01:12:26",
      "modified": "2014-05-31 17:12:26"
    },
    {
      "id": 2,
      "name": "Google Nexus 4",
      "description": "The most awesome phone of 2013!",
      "price": "56",
      "category_id": 2,
      "created": "2014-06-01 01:12:26",
      "modified": "2014-05-31 17:12:26"
    },
…
]

GET /products/2

Renvoie un objet JSON ressemblant à ceci :

{
      "id": 2,
      "name": "Google Nexus 4",
      "description": "The most awesome phone of 2013!",
      "price": "56",
      "category_id": 2,
      "created": "2014-06-01 01:12:26",
      "modified": "2014-05-31 17:12:26"
}

 

L’API sera construite à l’aide du microframework Slim Framework 3[2]. Ce dernier a été créé pour développer simplement des API, il possède un routeur pour gérer les diverses requêtes et un injecteur de dépendance qui permet d’utiliser les bibliothèques tierces.

Créer un dossier « api » sur la racine du projet. Ajouter un fichier index.php et un fichier .htaccess

Comme indiqué sur la page https://www.slimframework.com/docs/start/web-servers.html , compléter la fichier .htaccess de la manière suivante :

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]

Vérifier aussi que dans la configuration de Apache l’option AllowOverride est sur All.

Sur un raspberry il s’agit du fichier /etc/apache2/apache2.conf, section :

<Directory /var/www/>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

Comme indiqué page https://www.slimframework.com/docs/tutorial/first-app.html , le squelette de la page index est le suivant :

<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require '../vendor/autoload.php';

$app = new \Slim\App;
$app->get('/hello/{name}', function (Request $request, Response $response) {
    $name = $request->getAttribute('name');
    $response->getBody()->write("Hello, $name");

    return $response;
});
$app->run();

Nous allons nous inspirer de ce squelette afin que l’api puisse répondre  des données statiques dans un premier temps, puis des données issues de la BDD

exemple avec des données issues de la base de données

On suppose que la base de données est créée et qu’elle contient une table « ouvrants » (champs id et nom) avec quelques valeurs.

Dans Slim l’accès à la base de donnée est simplifié grâce à la bibliothèque slim/PDO . D’après la documentation[3]

L’usage typique se fait de la manière suivante :

require_once 'vendor/autoload.php';

$dsn = 'mysql:host=your_db_host;dbname=your_db_name;charset=utf8';
$usr = 'your_db_username';
$pwd = 'your_db_password';

$pdo = new \Slim\PDO\Database($dsn, $usr, $pwd);

// SELECT * FROM users WHERE id = ?
$selectStatement = $pdo->select()
                       ->from('users')
                       ->where('id', '=', 1234);

$stmt = $selectStatement->execute();
$data = $stmt->fetch();

// INSERT INTO users ( id , usr , pwd ) VALUES ( ? , ? , ? )
$insertStatement = $pdo->insert(array('id', 'usr', 'pwd'))
                       ->into('users')
                       ->values(array(1234, 'your_username', 'your_password'));

$insertId = $insertStatement->execute(false);

// UPDATE users SET pwd = ? WHERE id = ?
$updateStatement = $pdo->update(array('pwd' => 'your_new_password'))
                       ->table('users')
                       ->where('id', '=', 1234);

$affectedRows = $updateStatement->execute();

// DELETE FROM users WHERE id = ?
$deleteStatement = $pdo->delete()
                       ->from('users')
                       ->where('id', '=', 1234);

$affectedRows = $deleteStatement->execute();

 

On a ici les prototypes de l’instanciation d’un objet $pdo et des diverses requêtes select, delete, insert et update. L’intégration dans Slim se fait via un « container » permettant d’instancier un objet de la bibliothèque slim/PDO qui se situe dans un autre espace de nom que l’objet $app de Slim…

Le container va permettre de préparer, gérer et injecter des dépendances à l’application. L’avantage est que l’objet lié au container est créé à la demande et non de manière permanente. D’autre part les objets de l’application pourront accéder à des ressources dans d’autres espaces de nom.

Pour créer un container « db », insérer le code suivant :

<?php

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require '../vendor/autoload.php';

$config = [
    'settings' => [
        'displayErrorDetails' => true,

       
    ],
];
$app = new \Slim\App($config);
$container = $app->getContainer();
$container['db'] = function () {
    $dsn = 'mysql:host=localhost;dbname=apidb;charset=utf8';
    $usr = 'root';
    $pwd = '';
    $pdo = new \Slim\PDO\Database($dsn, $usr, $pwd);
    return $pdo;
};

Cela permet de créer un objet « db » qui sera instancié à la demande.

création d’une requête SELECT

Remplacer le code de la fonction $app->get(…) par celui-ci

/*********************************************************
 *    gestion des requêtes GET
 ******************************************************** */
$app->get('/{table}', function (Request $request, Response $response) {
    $table = $request->getAttribute('table');
    // SELECT * FROM {table}
    $selectStatement = $this->db->select()
            ->from($table);
    $stmt = $selectStatement->execute();
    $data = $stmt->fetchAll();
    return $response->withJson($data);
});

$this->db fait référence au container  « db » créé précédemment.

Sur le même principe si on veut que l’api renvoie juste un produit dont on spécifie l’id, le code sera le suivant :

$app->get('/{table}/{id}', function (Request $request, Response $response) {
    $table = $request->getAttribute('table');
    $id = $request->getAttribute('id');
    // SELECT * FROM {table} WHERE id = {id}
    $selectStatement = $this->db->select()->from($table)->where("id","=",$id);
    $stmt = $selectStatement->execute();
    $data = $stmt->fetch();
    return $response->withJson($data);
});

Code complet de la page /api/index.php

<?php

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require '../vendor/autoload.php';

$config = [
    'settings' => [
        'displayErrorDetails' => true,
       
    ],
];
$app = new \Slim\App($config);
$container = $app->getContainer();
$container['db'] = function () {
    $dsn = 'mysql:host=localhost;dbname=apidb;charset=utf8';
    $usr = 'root';
    $pwd = '';
    $pdo = new \Slim\PDO\Database($dsn, $usr, $pwd);
    return $pdo;
};

$app->get('/{table}', function (Request $request, Response $response) {
    $table = $request->getAttribute('table');
    // SELECT * FROM users WHERE id = ?
    $selectStatement = $this->db->select()
            ->from($table);
    $stmt = $selectStatement->execute();
    $data = $stmt->fetchAll();
    return $response->withJson($data);
});

$app->get('/{table}/{id}', function (Request $request, Response $response) {
    $table = $request->getAttribute('table');
    $id = $request->getAttribute('id');
    // SELECT * FROM {table} WHERE id = {id}
    $selectStatement = $this->db->select()->from($table)->where("id","=",$id);
    $stmt = $selectStatement->execute();
    $data = $stmt->fetch();
    return $response->withJson($data);
});

$app->run();

Installation de NG-ADMIN

ouvrir un terminal dans le dossier qui contient la solution puis effectuer la commande

npm install -g npm@2.x (sous linux faire précéder de sudo)
npm install ng-admin –-save

Cela installera le dossier node_modules et le sous dossier ng-admin qui contient tout le matériel pour le front-end.

Le dossier du projet va ressembler à ceci :

Modifier la page web index.php à la racine du site. Le code de la page est le suivant :

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Controle d'accès</title>
       <link rel="stylesheet" href="node_modules/ng-admin/build/ng-admin.min.css">
    </head>
    <body ng-app="myApp">
        <div ui-view="ng-admin"></div>
        <script src="node_modules/ng-admin/build/ng-admin.min.js" type="text/javascript"></script>
        <script src="js/app.js"></script>
    </body>
</html>

Le corps de la page est constitué d’une simple balise <div ui-view=”ng-admin”></div> et le <body> fait référence à l’application angularJS sous-jacente grâce à l’attribut ng-app=”myApp”[4]

Rajouter un dossier « js » et un fichier nommé app.js (dont il est fait référence dans la page index.php). Le script va créer un module angularJS nommé « myApp » et qui intégrera la bibliothèque [‘ng-admin’], la suite permet de configurer l’application. La documentation détaillée au format pdf de ng-admin est accessible ici : https://www.gitbook.com/book/marmelab/ng-admin/details

Code de /js/app.js

// declare a new module called 'myApp', and make it require the `ng-admin` module as a dependency
var myApp = angular.module('myApp', ['ng-admin']);
// declare a function to run when the module bootstraps (during the 'config' phase)
myApp.config(['NgAdminConfigurationProvider', function (nga) {
        // create an admin application
        var admin = nga.application('Mes produits')
                .baseApiUrl('/api/'); // main API endpoint;

        /************************************
         *  entité produts
         ************************************/
        var produits = nga.entity('products');
        var categories= nga.entity('categories');
        categories.listView();
        // tableau = listview
        produits.listView()
                .title('les produits')
                .fields([
                    nga.field('id'),
                    nga.field('name').label('nom'),
                    nga.field('description'),
                    nga.field('price').label('prix')
                  ]) ;
        admin.addEntity(produits);
        admin.addEntity(categories);
        nga.configure(admin);
    }]);

L’application fonctionne,

Reste à intégrer dasn l’API les fonctions d’ajout, de mise à jour et d’effacement des produits.

code complet

/api /index.php

<?php

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

require '../vendor/autoload.php';

$config = [
    'settings' => [
        'displayErrorDetails' => true,

       
    ],
];
$app = new \Slim\App($config);
$container = $app->getContainer();
$container['db'] = function () {
    $dsn = 'mysql:host=localhost;dbname=apidb;charset=utf8';
    $usr = 'root';
    $pwd = '';
    $pdo = new \Slim\PDO\Database($dsn, $usr, $pwd);
    return $pdo;
};

$app->get('/{table}', function (Request $request, Response $response) {
    $table = $request->getAttribute('table');
    // SELECT * FROM users WHERE id = ?
    $selectStatement = $this->db->select()
            ->from($table);
    $stmt = $selectStatement->execute();
    $data = $stmt->fetchAll();
    return $response->withJson($data);
});

$app->get('/{table}/{id}', function (Request $request, Response $response) {
    $table = $request->getAttribute('table');
    $id = $request->getAttribute('id');
    // SELECT * FROM users WHERE id = ?
    $selectStatement = $this->db->select()->from($table)->where("id","=",$id);
    $stmt = $selectStatement->execute();
    $data = $stmt->fetch();
    return $response->withJson($data);
});

$app->post('/{table}', function (Request $request, Response $response) {
    $data=$request->getParsedBody();
    $table = $request->getAttribute('table');
    $keys= array_keys($data);
    $values=array_values($data);
    $insertStatement= $this->db->insert($keys)
            ->into($table)
            ->values($values);
    $stmt = $insertStatement->execute();
    $response->withJson($stmt);  
    
});

$app->put('/{table}/{id}', function (Request $request, Response $response) {
    $table = $request->getAttribute('table');
    $id = $request->getAttribute('id');
    $data=$request->getParsedBody();
    $updateStatement = $this->db->update($data)
            ->table($table)
            ->where('id',"=",$id);
        $stmt = $updateStatement->execute();
    $response->withJson($stmt);

});
$app->delete('/{table}/{id}', function (Request $request, Response $response) {
    $table = $request->getAttribute('table');
    $id = $request->getAttribute('id');
    $deleteStatement = $this->db->delete()->from($table)->where('id', '=', $id);
    $stmt = $deleteStatement->execute();
    $response->withJson($stmt);
});

$app->run();

 

/js/app.js

// declare a new module called 'myApp', and make it require the `ng-admin` module as a dependency
var myApp = angular.module('myApp', ['ng-admin']);
// declare a function to run when the module bootstraps (during the 'config' phase)
myApp.config(['NgAdminConfigurationProvider', function (nga) {
        // create an admin application
        var admin = nga.application('Mes produits')
                .baseApiUrl('/api/'); // main API endpoint;

        /************************************
         *  entité produts
         ************************************/
        var produits = nga.entity('products');
        var categories= nga.entity('categories');
        categories.listView();
        // tableau = listview
        produits.listView()
                .title('les produits')
                .fields([
                    nga.field('id'),
                    nga.field('name').label('nom'),
                    nga.field('description'),
                    nga.field('price').label('prix'),
                    nga.field('category_id','reference')
                            .targetEntity(categories)
                            .targetField(nga.field('name'))
                            .label('catégorie')
                ])
                .listActions(['edit']);
        produits.creationView()
                .title('Ajout d\'un produit')
                .fields(produits.listView().fields());
        
        produits.editionView()
                .fields(produits.creationView().fields());
        admin.addEntity(produits);
        admin.addEntity(categories);
        nga.configure(admin);
    }]);

 

  1. https://marmelab.com/fr/blog
  2. https://openclassrooms.com/courses/utilisez-des-api-rest-dans-vos-projets-web/pourquoi-rest
  3. https://www.grafikart.fr/tutoriels/php/slim-framework-831
  4. https://github.com/FaaPz/Slim-PDO
  5. Voir formation angularJS : https://www.grafikart.fr/formations/angularjs
    ou le livre « AngularJS » editions ENI ISBN 978-2-7460-9334-8

PHP mySQL

L’objectif est ici d’afficher dans une page HTML des données issues d’une base de données mySQL. La page web va emettre des requêtes AJAX vers une page PHP. Cette dernière se chargera d’interroger la base et de fournir en réponse un fichier JSON que la page HTML pourra traiter et afficher les résultats

La première vidéo présente l’installation de la base de donnée  (elle est téléchargeable ici ). Ensuite on voit comment utiliser phpmyadmin afin de faire une requête avec des tables liées. Enfin, elle aborde la construction du script PHP, permettant d’interroger la base et de fournir un fichier JSON en réponse à une requête de type GET.

La seconde vidéo présente comment utiliser jQuery pour émettre une requête AJAX afin de récupérer un jeu de données. Puis comment insérer ces données dans un tableau.

La troisième vidéo montre comment peupler une liste déroulante à partir de la base de données, puis d’afficher les détails  de l’élément sélectionné. (Master/Detail)

phpMyAdmin

PhpMyAdmin est un outils graphique via des page web permettant de manipuler un serveur de base de données mySQL. Il est intégré aux packages genre Wamp, Lamp, Laragon.
nous verrons ici comment débuter avec cet outils.

La première vidéo (Part 01) explique comment :

  • Créer une nouvelle base de donnée.
  • Créer une table et ses colonnes
  • Effectuer les 4 opérations de base d’un CRUD (Create, Read, Update, Delete) c’est à dire créer des valeurs, les lire, les mettre à jour ou les effacer.

la seconde vidéo (Part 02) explique comment :

  • Créer une seconde table et créer une liaison entre les 2 tables
  • Utiliser l’utilitaire de requête pour extraire une jeu d’informations  prélevé dans les 2 tables.

Attention pour que les liaisons fonctionnent avec mySQL il faut bien s’assurer lors de la création de la table que le moteur stockage est de type InnoDB