Installer la solution domotique NextDom sous Debian9.5

Le projet NextDom avance bien. Il s’agit d’une refonte du core de Jeedom dans le but d’en améliorer la maintenabilité et les performances. Un gros travail a été fournis par des personnes formidable sur ces points. Nous en avons profité pour améliorer l’aspect visuel en utilisant le template basé sur bootstrap (pour la compatibilité) adminLte.

En exclusivité voici la procédure d’installation.

J’attends des retours de votre part pour rechercher les bugs qui aurais pu rester.

Je vous conseille de vérifier que vous n’avez pas de dossier html dans /var/www/ dans ce cas, supprimez le avant de commencer.

voici la procédure de test :

Installation

apt install -y software-properties-common gnupg wget unzip curl
add-apt-repository non-free
wget -qO - http://debian.nextdom.org/debian/nextdom.gpg.key | apt-key add -
echo "deb http://debian.nextdom.org/debian nextdom main" > /etc/apt/sources.list.d/nextdom.list
apt update 

1/ Solution simple pour installer la version stable sur une machine

apt install nextdom

Installe Nextdom et la BDD (base de données) en local sur la machine.
Les paquets nextdom-common et nextdom-mysql sont automatiquement installés.

Vous avez aussi la possibilité de faire tous cela automatiquement en rendant ce script exécutable : https://raw.githubusercontent.com/NextDom/NextDom-DebInstaller/master/deb-install.sh

Bon test 😉

NextDom fait sa conférence

Salut à tous !

Juste un petit message pour vous dire que NextDom sera présenté officiellement lors du Open Source Summit de Paris 2018.

A cette occasion, Vincent Fresnel aka byackee et Astral0 seront heureux de vous faire découvrir notre solution Domotique et Opensource. Venez nombreux leurs poser des questions !

Le 6 décembre vers 15h20 !

Css 3.0

Bonne pratiques des nommages en css

Dans le projet NextDom nous sommes confronté à la refonte du style. Beaucoup de style est directement présent dans le HTML. Il fallait repartit sur de bonnes bases si nous voulions assurer la pérennité de notre développement.
En premier lieux, nous avons décidé d’utiliser SASS. On y gagne :

  • les variables,
  • la vérification de syntaxe,
  • une meilleure lisibilité
  • la possibilité d’utiliser la syntaxe CSS et de la transformer petit à petit en SCSS
  • la possibilité de découper facilement d’énormes feuilles de styles en de plus petits fichiers plus digeste

la sortie du style du HTML est un gros morceau que mes collègues ont commencés et ce n’est pas simple. Très vite est apparu le besoin de créer de nouvelles classes et surtout de les nommer correctement.

C’est un point très compliqué en informatique, savoir nommer les choses et ce n’est pas que moi qui le dit :

There are only two hard things in Computer Science: cache invalidation and naming things.

– Phil Karlton

Lorsque je fait une intégration j’essaie de concilier deux choses vraiment pas évidentes. Je veux rendre le plus abstrait possible le nom de mes classes et en même temps il faut ce même nom soit le plus compréhensible possible. Sachant que je ne suis pas un spécialiste du frontend et que j’en fait que quand je suis vraiment obligé.

Des exemples de ce qu’il ne faut pas faire

Mon expérience m’a fait rencontrer des choses étranges  :

.h1, .h2, .h3 ...

Vouloir créer des classes pour faire passer une balise pour ce qu’elle n’est pas n’est pas une bonne pratique. C’est comme si on mettait une étiquette girafe à un éléphant, un éléphant reste un éléphant. Pour l’accessibilité des personnes défaillantes visuelles ou autre, elle perdent la sémantique de l’information qui leur est présentée.

.span_colorblue, .pre_code-php ...

Dans le cas vu ci-dessus on mélange la sémantique de la balise et le style qu’on veux lui appliquer. Par ailleurs, span_colorblue ne donne pas d’information sur l’utilité réelle de cette classe si ce n’est que le texte est en bleu. Pourquoi n’aurait on pas besoin d’une couleur bleu ailleurs qu’avec un span.

.toto > div > p > img {
    width: 500px;
}

Il faut aussi faire attention de ne pas trop lier l’imbrication des balises avec la feuille de style. Un seul sous niveau est un maximum. Au-delà, l’imbrication est trop forte et le moindre changement est trop long à répercuter.  Si vous voulez atteindre les images, mettez une classe à « img » et le problème est réglé.

CammelCase ou snake-case

A la lecture de la norme su le document de référence du W3C on se rende compte que les attributs id et classes sont « case-insensitive », les seules séparateurs autorisés son le – et le _ .

https://www.w3.org/TR/CSS21/syndata.html#characters

All CSS syntax is case-insensitive within the ASCII range (i.e., [a-z] and [A-Z] are equivalent), except for parts that are not under the control of CSS. For example, the case-sensitivity of values of the HTML attributes « id » and « class », of font names, and of URIs lies outside the scope of this specification. Note in particular that element names are case-insensitive in HTML, but case-sensitive in XML.

La symbolique

la première question à se poser est : « Qu’est-ce que je veux représenter et dans quel contexte« . Si on répond à ces deux questions, on a rapidement des noms qui nous viennes à l’esprit.

Regardons le code HTML suivant :

<div class="background-blue">
    <h1 class="strong">Un super titre</h1>
    <h2>Un super sous titre</h2>
</div>
<div class="normal">    
    <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima ratione vero ad repellat ea. Sint, est, eligendi expedita ducimus magnam quae voluptate! 
        Amet possimus error sapiente consectetur dolore qui illo?    
    </p>
</div>

Les classes « background-blue », « strong » et « normal » sont instanciées. Le problème, vous l’aurez compris est qu’elles n’indiquent pas pour quel usage réelle elles sont destinées. La classe « normal » n’a pas de signification. Qu’est-ce qui est normal ?

Selon moi, voici ce qu’il aurai fallu faire.

<div class="head">
    <h1 class="head-title">Un super titre</h1>
    <h2>Un super sous titre</h2>
</div>
<div class="content">    
    <p>
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima ratione vero ad repellat ea. Sint, est, eligendi expedita ducimus magnam quae voluptate! 
        Amet possimus error sapiente consectetur dolore qui illo?    
    </p>
</div>

J’ai choisi l’anglais pour nommer mes classes, c’est un choix qui n’engage que moi. Regardons attentivement la première div, la classe « head » indique que nous sommes dans le contexte d’une entête qui contiens des titre et sous titre. On a le schéma suivant A contient A-B etc…

Dans la div suivante « normal » a été remplacé par « content » car c’est l’objet de cette div de contenir un texte.
J’attend vos retours pour agrémenter cet article…

NextDom, l’avenir de la domotique !

Je vais vous parler de NextDom un projet domotique ambitieux. J’ai longtemps été un contributeur de l’application en PHP Jeedom. Avec le temps, j’ai voulu aider le projet en contribuant plus et en mettant en avant les bonnes pratiques du développement. J’ai donc fait de nombreux PR sur le Github du projet. Ce fut la douche froide !!

Le lead développeur est fermé à toutes évolutions qu’il considère comme une perte de temps.

Celles qui font perdre du temps sont :

L’ajout de documentation dans le code sous forme de PHPDoc

  • La refactorisation de code faisant plus de 200 ligne pour une méthode/fonction
  • La normalisation du coding style vers les PSR
  • L’introduction de tests unitaires
  • L’introduction de Namespaces
  • L’utilisation cohérente de composer

On parle d’un projet sous Licence GPL, pas d’un projet dont le code source est privé.

Je n’était pas le seul à vouloir faire évoluer Jeedom vers plus de qualité. Avec le temps, j’ai découvert un groupe de personnes partageant le même point de vue que moi. Un très bon groupe, ouvert et sympathique. Ce groupe a tenté une médiation avec Jeedom SAS, la maison mère de Jeedom. A l’issu de cette discutions, il a été convenu que la communication avec les développeur serai revue et améliorée.

Malheureusement, rien n’est allé dans le bon sens. Les CGV/CGU de Jeedom ont été modifié en rendant responsable le développeur de tous dommages physiques ou moral. Inacceptable et contraire au principe de responsabilité de chaque un.

D’autant plus que Jeedom s’exonère ce cette responsabilité. 2 poids 2 mesures…

Comme cette situation n’est pas tenable on n’a décidé de donner un nom à notre organisation : « NextDom« .

La situation s’est envenimée aujourd’hui. Sur le forum Jeedom, il est interdit d’utiliser le mot NextDom. Il est automatiquement remplacé par « NotAutorized », comme si on avais écrit des insultes…

Longue vie à NextDom un fork de Jeedom voir une solution complètement alternative.

Règlement général sur la protection des données personnelles (RGPD)

Bonjour,
Le Règlement général sur la protection des données personnelles (RGPD) sera appliqué le 25/05/2018. C’est une notion qu’il faudra intégrer dans votre vie professionnelle.
Je vous ai trouvé cet article en libre accès sur NextImpact expliquant ligne par ligne ce qu’il faut faire.
Bonne lecture !

Soumettre un sitemap.xml à Google, et Bing

Bonjour,

Ce petit code va vous permettre de soumettre votre sitemap.xml aux 2 principaux moteurs de recherche, soit Google search et Bing.

<?php

class searchEngineSubmitter{
    
    private $urls;
    
    public function getUrls(){
        return  $this->urls ;
    }
    /**
     * @param array $urlsForSubmitting
     */
    public function __construct(array $urlsForSubmitting){
        $this->urls = $urlsForSubmitting;
    }
    
    /**
         * 
         * @param string $url
         * @return type
         */
    private function myCurl($url) {
        $ch       = curl_init($url);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        return $httpCode;
    }
    
    /*
         * @abstract Sitemap Submitter Use this script to submit your site maps automatically to Google, Bing.MSN and Ask Trigger this script on a schedule of your choosing or after your site map gets updated.
     * @param string
    */
    public function submitSitemap($sitemapUrl) {

        foreach ( $this->getUrls() as $url) {
            $code = $this->myCurl($url . $sitemapUrl);
            if ($code == '200') {
                  return 'success: ' . parse_url($url, PHP_URL_HOST) . ' has been pinged (return code: ' . $code . ' )';
            } else {
                  return 'warning' . parse_url($url, PHP_URL_HOST) . ' return error (return code: ' . $code . ' )';
            }
        }
    }
    
}

Pour l’utiliser on fait comme ceci :

<?php

$submit = (new searchEngineSubmitter(
    ["http://www.google.com/webmasters/sitemaps/ping?sitemap=",
    "http://www.bing.com/webmaster/ping.aspx?siteMap="]))
    ->submitSitemap('http://www.mywebsite.com');

Et voilà 🙂

@ bientôt

Valider les champs d’un formulaire avec Silex et « Validator Constraints »

Je me suis associé à Baptiste Pesquet l’auteur du cours sur Openclassrooms « Évoluez vers une architecture PHP professionnelle ». La validation des champs est désormais compatible avec la version 2.1 de silex c’est l’itération 14.

Bonjour,

Aujourd’hui nous allons voir comment ajouter la validation des valeurs de retour d’un formulaire dans le framework Silex.

Après avoir suivi le cours sur Openclassrooms « Évoluez vers une architecture PHP professionnelle », il vous manquera cette partie avant de mettre votre site en ligne.

Pourquoi valider les champs ?

Pour s’assurer que les utilisateurs du site ne cherche pas à enter n’importe quelle donnée n’importe où. Par exemple un numéro de téléphone dans le champ email, tenter de faire passer des valeurs inapproprié et exploiter une faille xss…

Voici comment nous allons procéder :

Dans un premier temps nous allons ajouter un namespace qui sera utilisé par votre buildForm:: ce namespace c’est :

use Symfony\Component\Validator\Constraints as Assert;

Voici ce que j’ai fait pour l’enregistrement d’un email :

<?php

namespace MicroCMS\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class NewsletterType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add('email', 'email', [
            'label'      => '',
            'required'   => true,
        ]);
    }

    public function getName() {
        return 'newsletter';
    }

}

On vois que j’ai mis plusieurs contraintes. En premier lieu j’ai décidé que le champ est de type « email »et qu’il est « requis » (required), c’est à dire que sur le html généré, on verra ceci :

<input id="newsletter_email" name="newsletter[email]" required="required" placeholder="Votre email pour vous inscrire à la Newsletter" type="email">

Si l’utilisateur a un navigateur récent, et qu’il soumet le formulaire directement, un message lui dira que ce n’est pas possible car le champ est vide. Si il remplit ce champ avec autre chose qu’un email le navigateur va là aussi l’informer que cette donnée n’est pas valide. C’est une première étape car si l’utilisateur est un petit malin, il peut modifier le type de champ dans le input, supprimer le required et le email. à ce moment là, il pourra soumettre le formulaire sans message d’erreur.

Il faut donc procéder à une deuxième vérification sur les données au niveau du framework et pas seulement dans le navigateur.

Pour cela on va rajouter cette ligne dans notre méthode buildForm, ‘constraints’ => new Assert\Email(),

<?php 
namespace MicroCMS\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert;

class NewsletterType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add('email', 'email', [
            'label'      => '',
            'required'   => true,
            'constraints' => new Assert\Email(),
        ]);
    }

    public function getName() {
        return 'newsletter';
    }

}

Là, on est certain que la valeur attendu sera un email et pas autre chose. Si l’utilisateur fait le malin au niveau de son navigateur, voici ce qui va s’afficher :

  • This value is not a valid email address.

Grand maître L

Thomas pesquet

Hop Hop Hop ! je sors ce blog de son sommeil pour vous rappeler à tous que ce soir Thomas Pesquet prend son envol pour l’ISS. Je lui souhaite bon vol !

thomas pesquet official portrait
PHOTO DATE: 01-14-16
LOCATION: Bldg. 8, Room 183 – Photo Studio
SUBJECT: Official portrait of ESA astronaut & Expedition 50/51 crew member Thomas Pesquet in blue flight suit.
PHOTOGRAPHER: BILL STAFFORD
veille techno

L’importance de la veille technologique…

Hier, j’ai été invité à être membre d’un jury en tant que professionnel pour le passage du BTS SIO. J’ai à cette occasion pu rencontrer les futurs diplômés.

Dans l’ensemble, leurs parcours professionnels étaient très intéressants et variés.

Dans cette épreuve, il est demandé aux élèves de faire une rétrospective de leur veille technologique réalisée pendant les deux années de leur formation. A partir de ce moment, les choses se gâtent… Les élèves n’ont pas toujours compris l’intérêt de parcourir le Web ou d’assister à des conférences afin de se tenir au courant des évolutions de l’informatique et des systèmes d’informations. C’est d’autant plus dommageable qu’ils sont au début de leur formation et qu’ils ont tout à « découvrir » et j’insiste sur ce terme « découvrir ». Le but n’est pas qu’ils soient en mesure d’être des experts d’une technologie mais plutôt qu’ils aient une culture générale.

Enfin, j’ai remarqué que pour eux, veille technologique == nouvelles technologies, alors que non ! Découvrir une nouvelle technologie n’est qu’une partie de la veille, mais découvrir des anciennes peux faire partie des objectifs de carrière, le secteur des banques à énormément de mal à recruter pour la maintenance de leur code en COBOL, les développeurs qui font l’effort de l’apprendre aujourd’hui (2016) ne manquent pas de travail !

A méditer…

Grand maître L

boite de senseï

Diaballik devient Senseï

Il y a longtemps maintenant, je vous ai parlé du jeu de société Diaballik, lui même décliné en version iPad. Beaucoup d’eau a coulé sous les ponts et Philippe Lefrançois (le créateur a passé un deal avec un nouvel éditeur FERTI).

plateau animé

On y gagne un visuel très différent et deux nouveaux modes de jeux. Très honnêtement c’est vraiment excitant de se replonger dans ce jeu qui n’a pas pris une ride. je vous laisse le redécouvrir :

figurines senseï

Les pions et le plateau

ensemble figurine et plateau

Le jeux est disponible chez tous les bon vendeurs au prix de 32,15€.

…et pendant ce temps, l’horreur continue

Encore une fois l’horreur a frappé la France et Paris en particulier. Ce déchaînement de violence doit nous amener à reconnaître que notre façon d’être et de vivre ne plaît pas à tous le monde.

Ce n’est pas une raison pour renoncer à nos idées et nos valeurs de liberté, d’égalité et de fraternité. Ce sont les valeurs de la France et elles me sont chères.

J’ai une pensée émue pour les familles endeuillées.

Vive la liberté 😐

Grosse mise à jour de ma librairie PHP Json-heitz

Le logiciel Heitz System expose toujours une API avec laquelle on peux discuter via JSON. Je vous avais déjà présenté la première version de cette class ici.

Elle rencontre un petit succès 162 téléchargements aux dernières nouvelles sur Packagist.

Pour l’invoquer, voici comment faire :

<?php
require_once 'vendor/autoload.php';

    use JsonHeitz\JsonHeitz;
    use JsonHeitzCredential\Credential;
    use JsonHeitz\JsonHeitzException\JsonHeitzException;

try {
        $connect = (new Credential())
                ->setPort(80)
                ->setUserLogin('test1@heitzsystem.com')
                ->setUserPass('1')
                ->setHost('http://heitz.no-ip.com')
                ->setHostPassword('AuthentificationBaseTest')
                ->urlWebServeurHeitz()
        ;
    } catch (JsonHeitzException $exc) {
        echo $exc->getMessage();
    }

    try {

        $call = (new Query($connect))->setConnectHeitzAPI()
            //    ->setDebug(true) //optional
        ;

        $resultat = $call->callWSHeitz();

        $call->setIdSession($resultat->idSession)
                ->setIdClient($resultat->idClient);


        var_dump($call->getOneClient());
        var_dump($call->getTaskList());
        var_dump($call->getTest());
        var_dump($call->getFormTraining());
        var_dump($call->getActiveReservation());
        var_dump($call->getConfigServeur());
        var_dump($call->getBilan());
        var_dump($call->getTest());
        var_dump($call->getClientMessage(10));
        var_dump($call->getListOfActiveAccess());
        var_dump($call->getListOfPassages());
        var_dump($call->getArrowPoints());
        var_dump($call->getTaskGroup());
        var_dump($call->getPlaceForTheTask());
        var_dump($call->getListOfFinancialDeadlines());
        var_dump($call->getListOfLevies());
        var_dump($call->getListOfBills());
        var_dump($call->getListOfFinancial());
        var_dump($call->getListOfFinancialDeadlines());
        var_dump($call->getListOfLevies());
        var_dump($call->getListOfPoints());
        var_dump($call->getListOfCures());
        var_dump($call->getListOfActiveAccess());
        var_dump($call->getAllArticles());
        var_dump($call->getAllCity());
        var_dump($call->getAllCivility());
        var_dump($call->getAllJobs());
        var_dump($call->getAllWhereTheCustomerHasPracticed());
        var_dump($call->getAllMotivation());
        var_dump($call->getAllVAT());
        var_dump($call->getAllPayment());
        var_dump($call->getAllWayToKnowTheInstitution());
        var_dump($call->getAllTypeOfProspects());
        var_dump($call->getAllDiscountLevel());
        var_dump($call->getAllCustomerGroup());
        var_dump($call->getAllEmployee());
        var_dump($call->getAllFamilySituation());
        var_dump($call->getArrowPoints());
        var_dump($call->getDetailOfCures());
        var_dump($call->getCriterion1());
        var_dump($call->getCriterion2());
        var_dump($call->getCriterion3());
        var_dump($call->getCriterion4());
        var_dump($call->getCriterion5());
        var_dump($call->getDashboard('01-03-2012', '01-03-2013'));
        var_dump($call->getDashbordFinancial('01-03-2012'));
        var_dump($call->getFinancial());
        var_dump($call->getFormTraining());
        var_dump($call->getScheduleSEPA());

        $sale = array(
            'vente'     => '{"ventes":[{"idArticle":300024225, "idTva":0, "quantite":3, "prixUnitaire":12.34},
                                                   {"idArticle":300185150, "idTva":0, "quantite":2, "prixUnitaire":987.654}]}',
            'reglement' => '{"reglements":[{"idMode":1, "montant":12.34},
                                        {"idMode":3, "montant":987.654},{"idMode":2, "montant":122.3}]}'
        );
        var_dump($call->addSale($sale));

        $search = array(
            "idClientRecherche" => '',
            "nom"               => 'sa%',
            "prenom"            => '',
            "secondPrenom"      => '',
            "email"             => '',
            "idCivilite"        => '',
            "naissance"         => '',
            "telephone"         => '',
            "portable"          => '',
            "idVille"           => '',
            "idSituation"       => '',
            "idProfession"      => '',
            "dateCreation"      => '',
            "contactSMS"        => '',
            "contactEmail"      => '',
            "contactCourrier"   => '',
            "contactTelephone"  => ''
        );

        var_dump($call->searchClient($search, 1));
        var_dump($call->getClientIdByEmail('toto@toto.fr'));
        var_dump($call->clientWithAnActiveSpecificAccess(1018874, 16485527));
        var_dump($call->accessListForAClient(19435255));
    } catch ( JsonHeitzException $exc) {
        echo $exc->getMessage();
    }

Et voila, @Bientôt Grand Maître L

SgAutoRepondeur avec composer

J’ai développé une petite classe en PHP pour utiliser facilement l’API de SGAutoRépondeur.

Elle est bien-sûr disponible pour tous sur mon Bitbucket. Elle respecte les conventions PSR-4 pour l’auto-chargement des classes et ça c’est important !!!

Pour information, voici comment l’utiliser :

<?php
require_once 'vendor/autoload.php';

try {
    $monTest = (new \SgAutoRepondeur\SgAutoRepondeur())
            ->setCodeActivationClient('1010201000162121718617151918911')
            ->setMembreID('32')
            ->setInscriptionNormale('non')
            ->setEmailSG('sebastienXXX_@hotmail.com')
            ->setListeID('779')

    ;
} catch (SgAutoRepondeur\SgException\SgException $exc) {
    echo $exc->getMessage();
}

try {
    $userSG = (new \SgAutoRepondeur\User\User())
            ->setEmail('tutu@tutu.fr')
            ->setNom('Dupont')
            ->setPrenom('Jean')
            ->setAdresse('125 rue de nulle part')
            ->setPays('France')
            ->setAnneeNaissance('1979')
            ->setMoisNaissance('01')
            ->setJourNaissance('10')
            ->setVille('lyon')
            ->setIp('192.168.1.236');

    $monTest->setFields($monTest, $userSG);

  //  var_dump($monTest->getFields());
} catch (SgAutoRepondeur\SgException\SgException $exc) {
    echo $exc->getMessage();
}

try {
    var_dump( $result = (new SgAutoRepondeur\ResponseDictionary\ResponseDictionary())
        ->value( $monTest->callWebService($monTest->getFields()) ));
} catch (SgAutoRepondeur\SgException\SgException $exc) {
    echo $exc->getMessage();
}

Pour avoir plus d’informations sur l’autorépondeur et à quoi cela sert, je vous invite à vous rendre sur leur site internet

http://sg-autorepondeur.com/index.php

@ plus Grand Maitre L