Tag - planet-libre

Entries feed

Sunday, September 8 2019

Installer un serveur TURN/STUN pour Talk@Nextcloud

L'application "Talk" de Nextcloud gagne toujours plus en maturité à chaque nouvelle version. Pour en profiter pleinement, il est nécessaire de paramétrer un serveur TURN/STUN dans la page de configuration du module Talk de Nextcloud.

Nous allons voir ici comment installer un serveur TURN/STUN sous Debian Buster.

On commence, sans originalité, par installer le paquet :

apt install coturn

Et on le configure dans /etc/turnserver.conf :

tls-listening-port=5349
fingerprint
use-auth-secret
static-auth-secret=secretkey
realm=turn.monurl.tld
total-quota=100
bps-capacity=0
stale-nonce
cert=/etc/turnserver/cert.pem
pkey=/etc/turnserver/privkey.pem
cipher-list="ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
no-loopback-peers
no-multicast-peers

Conformément à ce que nous venons d'écrire dans le fichier de configuration, il faut alors ouvrir le port 5349 de l'éventuel pare-feu, par exemple si on utilise nftables en ajoutant cette ligne dans /etc/nftables.conf :

tcp dport 5349 accept

Il convient également de rendre la clé et le certificat permettant le chiffrement accessibles à l'utilisateur turnserver dans /etc/turnserver/*.pem. Si les certificats ont été obtenus avec letsencrypt, on pourra par exemple effectuer les commandes suivantes :

mkdir /etc/turnserver
cp /etc/letsencrypt/live/turn.monurl.tld/privkey.pem /etc/turnserver/
cp /etc/letsencrypt/live/turn.monurl.tld/cert.pem /etc/turnserver/
chmod a+r /etc/turnserver/privkey.pem
systemctl restart turnserver

Il sera nécessaire de répéter les opérations ci-dessous à chaque mise à jour du certificat et de la clé privée par let's encrypt (ou votre fournisseur de certificat TLS) !

Le serveur TURN/STUN doit alors être fonctionnel !

Saturday, September 7 2019

Asus UX331 et Debian Buster : tout fonctionne parfaitement

À l'achat d'un nouvel ordinateur, tous les utilisateurs de Linux s'interrogent sur le support complet de la machine qu'ils visent par leur distribution préférée. Je n'échappe pas à ce questionnement (fort légitime). Je partage donc ici mon retour d'expérience sur l'installation de Debian Buster sur un ordinateur Asus Zenbook UX331.

Tout fonctionne parfaitement pendant et après l'installation sauf le Wifi qui nécessite un firmware non libre non disponible dans l'installateur. Il est toutefois possible de fournir à l'installateur le firmware à l'aide périphérique amovible avec le fichier en cours d'installation ou bien il faut installer avec un adaptateur Ethernet <-> USB reconnu par Linux.

Principaux points :

  • affichage : écran parfaitement reconnu, la luminosité est correctement contrôlée par les touches ad-hoc du clavier
  • son : parfaitement reconnu, en revanche les touches "volume +" et "volume -" du clavier ne fonctionnent pas
  • rétro-éclairage du clavier : totalement fonctionnel et réglable avec les touches du clavier
  • wifi : pleinement fonctionnel après installation du package "firmware-misc-nonfree"
  • touchpad : pleinement fonctionnel sauf la touche de désactivation du touchpad
  • lecteur d'empreinte : non testé
  • la mise en veille (suspend) et en hibernation se fait sans problème

Au final, absolument rien de bloquant ou de gênant au quotidien ! Ah si, une petite particularité à laquelle il faut s'habituer : la batterie est équipée d'un système de prévention de son usure et donc par défaut la batterie ne se recharge que lorsqu'elle est descendue en-dessous de 80%. Autrement dit, branchée au secteur alors qu'elle se trouve à 88% de charge, la batterie ne bouge pas. Il existe un utilitaire sous Windows pour régler ce comportement. Cela n'existe pas à ma connaissance sous Linux.

Voici ce que rapporte lspci :

00:00.0 Host bridge: Intel Corporation Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers (rev 08)
00:02.0 VGA compatible controller: Intel Corporation UHD Graphics 620 (rev 07)
00:04.0 Signal processing controller: Intel Corporation Skylake Processor Thermal Subsystem (rev 08)
00:14.0 USB controller: Intel Corporation Sunrise Point-LP USB 3.0 xHCI Controller (rev 21)
00:14.2 Signal processing controller: Intel Corporation Sunrise Point-LP Thermal subsystem (rev 21)
00:15.0 Signal processing controller: Intel Corporation Sunrise Point-LP Serial IO I2C Controller #0 (rev 21)
00:15.1 Signal processing controller: Intel Corporation Sunrise Point-LP Serial IO I2C Controller #1 (rev 21)
00:16.0 Communication controller: Intel Corporation Sunrise Point-LP CSME HECI #1 (rev 21)
00:17.0 SATA controller: Intel Corporation Sunrise Point-LP SATA Controller [AHCI mode] (rev 21)
00:1c.0 PCI bridge: Intel Corporation Sunrise Point-LP PCI Express Root Port #5 (rev f1)
00:1c.5 PCI bridge: Intel Corporation Sunrise Point-LP PCI Express Root Port #6 (rev f1)
00:1e.0 Signal processing controller: Intel Corporation Sunrise Point-LP Serial IO UART Controller #0 (rev 21)
00:1e.2 Signal processing controller: Intel Corporation Sunrise Point-LP Serial IO SPI Controller #0 (rev 21)
00:1f.0 ISA bridge: Intel Corporation Sunrise Point LPC Controller/eSPI Controller (rev 21)
00:1f.2 Memory controller: Intel Corporation Sunrise Point-LP PMC (rev 21)
00:1f.3 Audio device: Intel Corporation Sunrise Point-LP HD Audio (rev 21)
00:1f.4 SMBus: Intel Corporation Sunrise Point-LP SMBus (rev 21)
01:00.0 Unassigned class [ff00]: Realtek Semiconductor Co., Ltd. RTS522A PCI Express Card Reader (rev 01)
02:00.0 Network controller: Intel Corporation Wireless 8265 / 8275 (rev 78)

et lsusb :

Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 8087:0a2b Intel Corp. 
Bus 001 Device 002: ID 13d3:5a09 IMC Networks 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Sunday, August 25 2019

Configuration de zsh, inspirée de la formation Debian d'Alexis de Lattre

Ceux qui ont débuté sous Debian il y a quelques années ont peut-être découvert la formation Debian d'Alexis de Lattre. Celle-ci a récemment migré vers un nouveau domaine : https://formation-debian.viarezo.fr/ mais il me semble qu'elle n'a plus été mise à jour depuis quelques temps.

Je stocke ici les fichiers de paramétrage de ZSH légèrement modifiés pour tenir compte de ce billet et de ce billet.

On pourra télécharger les fichiers et les placer à l'endroit adéquat du serveur avec cette série de commandes :

wget https://blog.bandinelli.net/public/zshrc
wget https://blog.bandinelli.net/public/zshenv
wget https://blog.bandinelli.net/public/zlogin
wget https://blog.bandinelli.net/public/zlogout
wget https://blog.bandinelli.net/public/dir_colors
mv zshrc zshenv zlogin zlogout /etc/zsh/
mv dir_colors /etc/

LXC 3 sur Debian Buster, "bad template"

Sur une version de Debian Buster fraîchement installée, il était impossible de déployer une instance LXC car aucun template n'était trouvé :

get_template_path: 918 No such file or directory - bad template: debian

Il faut seulement installer les templates de LXC par :

apt install lxc-templates

Monday, March 12 2018

Utiliser HAProxy pour profiter d'HTTP/2

Les versions 1.8.x d'HAProxy (premier représentant de la branche publié fin 2017) supportent le protocole HTTP/2 pour la communication frontale (section frontend). L'utiliser en amont de votre infrastructure est un moyen facile de rendre ce protocole disponible même si certains de vos serveurs sous-jacents (backend) n'en sont pas encore capables.

Installer HAProxy 1.8.x sur Debian Stretch

La version distribuée officiellement dans Debian Stretch est 1.7.x. Pour installer une version de la branche 1.8.x, il y a au moins 2 alternatives :

  1. compiler l'outil à partir du code source disponible sur le site officiel
  2. utiliser https://haproxy.debian.net/ qui va fournir un dépôt spécifique

Configurer HAProxy

La configuration d'HAProxy se fait par défaut dans /etc/haproxy/haproxy.cfg.

Voici un exemple de fichier de configuration dont les principales sections sont commentées plus bas :

global
	log /dev/log	local0
	log /dev/log	local1 notice
	chroot /var/lib/haproxy
	stats socket /run/haproxy/admin.sock mode 660 level admin
	stats timeout 30s
	user haproxy
	group haproxy
	daemon

	# Default SSL material locations
	ca-base /etc/ssl/certs
	crt-base /etc/ssl/private

	# Default ciphers offered by Mozilla here:
	#  https://mozilla.github.io/server-side-tls/ssl-config-generator
    ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets
    ssl-default-server-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
    ssl-default-server-options no-sslv3 no-tlsv10 no-tlsv11 no-tls-tickets

defaults
	log	global
	mode	http
	option	httplog
	option	dontlognull
        timeout connect 5000
        timeout client  50000
        timeout server  50000
	errorfile 400 /etc/haproxy/errors/400.http
	errorfile 403 /etc/haproxy/errors/403.http
	errorfile 408 /etc/haproxy/errors/408.http
	errorfile 500 /etc/haproxy/errors/500.http
	errorfile 502 /etc/haproxy/errors/502.http
	errorfile 503 /etc/haproxy/errors/503.http
	errorfile 504 /etc/haproxy/errors/504.http

frontend http-in
	bind :::80 v4v6

	acl host_letsencrypt path_beg /.well-known/acme-challenge/
	use_backend letsencrypt if host_letsencrypt

	redirect scheme https code 301 if !host_letsencrypt
 
frontend https-in
	bind :::443 v4v6 ssl crt-list /etc/haproxy/crt-list.txt alpn h2,http/1.1
	option forwardfor
	http-request add-header X-Forwarded-Proto https

        # Define hosts
        acl host_alpha hdr_end(host) -i a.fr
	acl host_beta hdr(host) -i precis.b.fr
	acl host_gamma hdr_reg(host) ^d1.c.fr|d2.c.fr$

        # figure out which one to use
        use_backend alpha if host_alpha
	use_backend beta if host_beta
	use_backend gamma if host_gamma

	default_backend iota

backend alpha
        server alpha 192.168.1.1:80

backend beta
        server beta 192.168.1.2:80

backend gamma
        server gamma 192.168.1.3:80

backend iota
        server iota 192.168.1.4:80

backend letsencrypt
        server letsencrypt 192.168.1.1:8080

Quelques commentaires pour bien comprendre...

On écoute d'abord en HTTP (donc sur le port 80, en IPv4 et IPv6) et on redirige tout vers l'HTTPS (redirect scheme https code 301) car c'est une bonne pratique aujourd'hui de n'offrir que du contenu protégé par SSL/TLS.

frontend http-in
	bind :::80 v4v6
	redirect scheme https code 301

Si l'on utilise letsencrypt pour générer ses certificats et qu'ils sont tous générés sur une machine dédiée pour ne pas avoir à se poser de questions sur les différents types de serveurs sous-jacents, on peut rajouter une exception pour les appels utilisés dans l'ACME challenge de letsencrypt et rediriger alors le trafic vers une machine spécifique ici nommée letsencrypt.

frontend http-in
	bind :::80 v4v6

	acl host_letsencrypt path_beg /.well-known/acme-challenge/
	use_backend letsencrypt if host_letsencrypt

	redirect scheme https code 301 if !host_letsencrypt

On écoute bien sûr également sur le port 443 pour gérer les connexions en SSL/TLS :

frontend https-in
	bind :::443 v4v6 ssl crt-list /etc/haproxy/crt-list.txt alpn h2,http/1.1
	option forwardfor
	http-request add-header X-Forwarded-Proto https

Il y a beaucoup de choses intéressantes ici :

  • bind :::443 v4v6 : IPv4 et IPv6 activés
  • bind :::443 v4v6 ssl crt-list /etc/haproxy/crt-list.txt : on active le SSL/TLS et on spécifie un fichier texte qui contient la liste des certificats à charger pour chiffrer les communications
  • bind :::443 v4v6 ssl crt-list /etc/haproxy/crt-list.txt alpn h2,http/1.1 : on active l'HTTP/2 (en plus de l'HTTP/1)
  • option forwardfor : comme on fonctionne en reverse proxy, on demande à HAProxy de passer les en-têtes X-FORWARDED-FOR aux serveurs sous-jacents (utile pour avoir les vraies adresses IP appelantes dans les logs)
  • http-request add-header X-Forwarded-Proto https : on informe les serveurs sous-jacents que la communication est bien chiffrée (et on évite donc une boucle de redirection si le serveur sous-jacent veut forcer le passage en HTTPS, avec ce paramètre il sera déjà satisfait)

On définit ensuite quelques règles ACL pour, selon le nom d'hôte, orienter la connexion vers un backend ou autre. J'ai mis ici plusieurs exemples que j'utilise - il existe des dizaines d'autres filtres y compris sur d'autres critères que le nom d'hôte (on a vu l'URL dans le cas de letsencrypt un peu plus) : filtre sur la fin du nom d'hôte (tout nom d'hôte finissant par a.fr sera redirigé vers le backend alpha), filtre sur le nom d'hôte complet (precis.b.fr sera envoyé vers beta) ou filtre sur le nom d'hôte avec des expressions régulières.

        # Define hosts
        acl host_alpha hdr_end(host) -i a.fr
	acl host_beta hdr(host) -i precis.b.fr
	acl host_gamma hdr_reg(host) ^d1.c.fr|d2.c.fr$

        # figure out which one to use
        use_backend alpha if host_alpha
	use_backend beta if host_beta
	use_backend gamma if host_gamma

On définit également un backend par défaut (iota ici) :

	default_backend iota

Et il reste alors à définir chaque backend :

backend example
        server example 1.2.3.4:80

Pour aller plus loin

Les options possibles dans HAProxy sont fort évidemment beaucoup plus nombreuses ! La documentation est très détaillée et claire ici https://www.haproxy.org/#docs.

Wednesday, January 24 2018

Données personnelles : le RGPD au format liseuse

Le règlement général sur la protection des données (RGPD) est applicable à compter du 25 mai 2018 en Europe. Le texte intégral du règlement est bien sûr disponible sur le site de l'Union Européenne au format PDF et au format HTML mais impossible d'en trouver une version facile à lire sur la liseuse de son choix.

J'ai donc entrepris de créer des versions EPUB et MOBI du dit règlement (version française, téléchargée en HTML sur le site mentionné plus haut le 22 janvier 2018) et les mets à disposition de tous. Bien plus confortable à lire dans ces conditions !

La version EPUB du RGPD

RGPD en EPUB

La version MOBI du RGPD

RGPD en MOBI

Quel fut le processus de génération ?

  1. Le fichier HTML de base a été téléchargé depuis le site de l'Union Européenne.
  2. Afin de s'afficher correctement après export en EPUB/MOBI, toutes les balises de tableau ont été supprimées du fichier HTML.
  3. A l'aide d'expressions régulières, les titres de chapitre ont été placés dans des balises <h1></h1>.
  4. Toujours à l'aide d'expressions régulières, les titres et sous-titre d'article ont été placés respectivement dans des balises <h2></h2> et <h3></h3>.
  5. La conversion en EPUB et MOBI a été réalisée à l'aide de Calibre.

Saturday, October 28 2017

Tomato by Shibby n'est peut-être pas mort ? Mais vive LEDE malgré tout !

Si j'en crois Wikipedia, l'histoire du micrologiciel Tomato remonte au vénérable Linksys WRT54G et au projet HyperWRT qui avait été développé pour ce routeur. HyperWRT a été supporté par les bénévoles de 2004 à 2008 et en 2008 un fork aura lieu et mènera à Tomato qui sera développé jusqu'en version 1.28. Et là, nouvel abandon, et nouveaux forks, celui de Shibby (un développeur polonais) acquiert une certaine renommée. En 2017, deux vulnérabilités majeures sont publiées :

  • l'une concerne le logiciel dnsmasq (un petit serveur DNS/DHCP) : elle est publiée le 2 octobre 2017 sous le numéro CVE-2017-14491. Brièvement, une faille est détectée qui permet l'exécution de code distant sur une machine propulsant dnsmasq
  • la seconde est KRACK, la découverte par un chercheur belge d'une faille dans le protocole WPA2

Deux très bonnes raisons de mise à jour !

Tous les utilisateurs de firmware de routeurs & points d'accès se sont alors tournés vers les fournisseurs de ceux-ci, et les utilisateurs de Tomato by Shibby ont attendu avec impatience la sortie d'une nouvelle version. Malheureusement, deux semaines après ces annonces, aucun signe de vie et le site qui hébergeait les données de Tomato by Shibby n'est plus accessible au moment où j'écris ces lignes.

Edition au 30 octobre, 8h19 : Shibby m'a répondu - ce n'est qu'un problème temporaire de réseau chez le fournisseur de VPS qui héberge son site internet. Il répond également sur la mise à jour KRACK de la façon suivante : Tomato is using NAS daemon for WPA2 security. The problem is that sources for this daemon are closed by Broadcom. So we have to wait when Asus or Netgear etc will fix it and then try to move newer binaries to Tomato. But that means (probably) only newest routers will have fix for KRACK. I dont think that Asus etc will release fixed firmwares for Mipsel..

Il y a de nombreuses distributions basées sur Tomato by Shibby et d'autres forks de Tomato (cf. la page de Wikipedia sur Tomato, cependant si celle-ci est un jour, aucun des forks n'a été mis à jour post-annonce de KRACK ce qui n'augure rien de bon). Le code source étant disponible, de bonnes âmes expertes sauront peut-être faire renaître la tomate de ses cendres.

Pas de panique, il semble que LEDE soit une bonne alternative à Tomato dans la plupart des cas. Supporté par une communauté qui semble un peu plus large (Tomato by Shibby est (était), ne semble-t-il, soutenu que par un seul homme), LEDE est un fork d'OpenWRT. La dernière version 17.01.4 est très stable, très pratique et a été patchée pour KRACK !

Il est délicat de comparer LEDE et Tomato : là où Tomato se borne (bornait ?) à propulser routeurs et autres périphériques réseau, LEDE (Linux Embedded Development Environment) veut aller plus loin et propose une véritable micro-distribution avec gestion de paquets (avec l'utilitaire opkg). L'interface graphique LuCI de LEDE est très agréable, elle comporte moins de fonctionnalités que Tomato et il est probable qu'il faille recourir plus fréquemment à la ligne de commande de LEDE pour les paramétrages complexes possibles dans Tomato (par ex. la QoS, la gestion avancée des VLAN etc...). Mais dans les situations simples, LEDE peut-être un remplacement immédiat à Tomato. Pour les cas complexes, la migration est à évaluer, surtout si personne ne reprend le flambeau de Shibby !

Pour découvrir LEDE, c'est ici.

Comment LEDE a sauvé mes "vieux" points d'accès Wifi

J'avais acheté il y a peut-être 2-3 ans des petits points d'accès Wifi d'une marque chinoise. Lors de la divulgation de KRACK, je vérifiais le site du fabricant mais je constatais qu'aucune mise à jour n'était publiée pour ces appareils.

Je me tournais alors vers LEDE, le fork open source d'OpenWRT. En quelques minutes, j'identifiais le matériel dans la liste des matériels supportés, je téléchargeais la version 17.01.4 publiée le 18 octobre avec les corrections nécessaires pour KRACK.

L'installation de LEDE sur les points d'accès fut très facile :

  1. réinitialiser les points d'accès à l'aide du bouton RESET
  2. se connecter à l'interface du constructeur chinois, et se rendre dans la section "Firmware upgrade"
  3. téléverser le fichier de micrologiciel de LEDE
  4. ... patienter pendant le processus et le redémarrage
  5. se connecter sur http://192.168.1.1 pour trouver LuCI, l'interface graphique de LEDE

Deux enseignements :

  • si vous ne connaissez pas LEDE, c'est une très belle distribution pour les routeurs/points d'accès et autres petits périphériques du genre ; une bien pratique suite à OpenWRT
  • le llbre est une bonne solution à l'obsolescence et peut apporter une pérennité d'usage de matériels délaissés par les fabricants

Saturday, June 3 2017

Nombre de déclenchements d'un appareil Canon sous Linux avec gphoto2

Si vous êtes l'heureux possesseur d'un appareil photo reflex Canon (et peut-être d'autres marques, je n'ai pas pu tester), vous vous demandez peut-être comment accéder au compteur de déclenchements par exemple pour mesurer le degré d'usure de votre matériel (http://www.olegkikin.com/shutterlife/).

gphoto2 sera votre complice pour cela. Il faut d'abord l'installer avec votre gestionnaire de paquet préféré (ici apt) :

apt install gphoto2

Après avoir branché l'appareil photo en USB sur le PC, on exécute la commande suivante :

gphoto2 --auto-detect

qui doit retourner le type d'appareil photo connecté et reconnu :

Model                          Port                                            
----------------------------------------------------------
Canon EOS 700D                 usb:001,007

Accédons maintenant à l'info souhaitée :

gphoto2 --get-config /main/status/shuttercounter

et voilà :

Label: Shutter Counter                                                         
Type: TEXT
Current: 14611

Sunday, February 19 2017

Réduire l'empreinte mémoire de GitLab en contrôlant le nombre de processus Sidekiq

Par défaut, GitLab démarre 25 processus Sidekiq pour gérer les travaux de tâche de fond de GitLab. Si ce nombre est justifié sur une instance à fort traffic, il y a fort à parier qu'un bien plus petit nombre de processus suffit pour gérer une instance de GitLab de petit volume.

Le nombre de processus Sidekiq se règle aisément dans le fichier /path/to/gitlab/config/sidekiq_queues.yml par ajout de la ligne suivante :

:concurrency: 2

où l'on remplacera "2" par le nombre de processus souhaités. 2 semble suffisant pour ma petite installation GitLab personnelle et ses quelques utilisateurs et dizaines de projets.

Voilà de quoi optimiser l'empreinte mémoire et processeur de GitLab !

Wednesday, February 15 2017

Installer john (theripper) avec support de multiples coeurs sous Debian Stretch

Par défaut sous Debian Stretch, john (theripper), ami de l'adminsys testeur de la solidité des mots de passe, fonctionne en utilisant un seul coeur/processeur.

Il est nécessaire de recompiler john pour faire usage de multiples processeurs. Pas de panique, cela se fait très aisément.

Il faut d'abord install gcc et make pour permettre la compilation :

apt install gcc make

Ensuite, on télécharge la dernière version de john sur le site d'Openwall :

wget http://www.openwall.com/john/j/john-1.8.0.tar.xz

On décompresse l'archive :

tar xvf john-1.8.0.tar.xz

(si tar ne reconnaît pas tar.xz, c'est qu'il faut installer le paquet xz-utils)

On rentre dans le dossier source de john

cd john-1.8.0/src/

et on modifie le fichier Makefile pour décommenter les lignes OMPFLAGS. Ainsi :

#OMPFLAGS = -fopenmp
#OMPFLAGS = -fopenmp -msse2

devient

OMPFLAGS = -fopenmp
OMPFLAGS = -fopenmp -msse2

On lance alors la compilation par la commande

make linux-x86-64-avx

(attention, la cible peut être différente selon votre processeur et votre système... make vous proposera tous les choix possible si vous l'appelez sans paramètre)

Une fois la compilation terminée, vous pouvez lancer john :

cd ../run/
./john --test

et modifier lors de l'exécution le nombre de coeurs à utiliser si vous le souhaitez :

OMP_NUM_THREADS=1 ./john --test

Sunday, February 12 2017

Installer Rainloop sur Nextcloud

Rainloop s'installe extrêmement facilement sur Nextcloud 11 pour transformer votre gestionnaire cloud favori en webmail fort pratique.

Activer l'application

La première étape consiste à activer l'application dans le magasin à application de Nextcloud. D'abord, cliquer sur le menu en haut à gauche puis sur le bouton "+ Apps" pour ouvrir le magasin à application. Screenshot_2017-02-12_16-24-48.png

Dans la catégorie "Social & communication", on trouve l'application Rainloop qu'il suffit alors d'activer : Screenshot_2017-02-12_16-23-33.png

Accéder à l'administration de Rainloop

Après activation, réfrénez cette envie irrépressible de cliquer sur l'icône "Email" apparue aux côtés de vos applications (ça ne servira à rien sans quelques paramétrages préalables) et rendez-vous dans la page d'administration de Nextcloud, section "Additionnal settings". Là, dans le paragraphe "RainLoop Webmail" fraîchement apparu, cliquez sur "Go to RainLoop Webmail admin panel". Alternativement, vous pouvez appeler cette URL http://cloud.url/index.php/apps/rainloop/app/?admin (en remplaçant http://cloud.url par une URL valide et conforme à votre cas).

Au premier usage, le nom d'utilisateur de l'administration est "admin" et le mot de passe "12345". Nul besoin de vous inviter à modifier cela !

Paramétrer Rainloop

Les paramétrages et optimisations de Rainloop abondent. Pour aller à l'essentiel, rendez-vous dans la section "Domains".

Le principe est simple : vous allez paramétrer (et de fait autoriser) les utilisateurs de Rainloop (dans Nextcloud) à se connecter à un IMAP/SMTP selon le domaine de leur adresse courriel. Par exemple, vos utilisateurs ont des adresses alice@mondomaine.fr et bob@mondomaine.fr. Nous allons donc ajouter le domaine "mondomaine.fr" et paramétrer l'IMAP et le SMTP pour ce domaine :

Screenshot_2017-02-12_16-37-32.png

Désormais, sur leur compte Nextcloud, quand Alice et Bob ouvriront Rainloop, ils pourront saisir leur adresse (respectivement alice@mondomaine.fr et bob@mondomaine.fr) et Rainloop saura quels paramétrages IMAP/SMTP utiliser pour rapatrier le contenu de leur boîte courriel.

Saturday, November 12 2016

OpenSCAD pour faire de la 3D comme un programmeur, exemple de conception d'une boîte

OpenSCAD m'a réconcilié avec la conception 3D : plus la peine d'apprendre à utiliser Blender pour quelques pièces mécaniques, OpenSCAD permet de générer des pièces en 3D avec du code :-)

Avec le petit exemple ci-dessous, vous aurez vite compris l'intérêt d'OpenSCAD pour certaines petites pièces à construire, et si comme moi vous n'avez pas jusqu'ici eu le courage de vous lancer dans Blender ou FreeCAD. Contrairement à Blender par exemple, chaque forme est définie dans un langage propre à OpenSCAD et la forme apparaît à la compilation. Ce n'est donc clairement pas adapté pour des représentations artistiques mais pour la fabrication de pièces mécaniques dont les cotes sont bien connues, cela permet très vite d'arriver au résultat escompté !

Installation d'OpenSCAD

Sous Debian, OpenSCAD s'installe très simplement car il est disponible dans les paquets de la distribution :

apt install openscad

Exemple de conception d'une boîte

Imaginons que l'on souhaite fabriquer une boîte avec une grille pour y ranger par exemple de petits montages électriques.

Commençons par la face principale : dessinons un rectangle de 82 mm par 40 mm :

square([82,40],center);

form1.png

Pour fabriquer les fentes, nous allons soustraire un rectangle de 32 mm par 1 mm :

difference() {
  square([82,40],center);
   square([1,32]);
}

form1b.png

Cela a fonctionné, mais il faudrait mieux placer notre fente : nous allons le faire à l'aide d'une translation :

difference() {''''
  square([82,40],center);
    translate([3,4,0]) {
      square([1,32]);
    }
}

form1c.png

Nous pourrions maintenant répéter ces lignes de code autant de fois que nécessaire pour obtenir notre grille. Mais il y a mieux ; il est possible de paramétrer la création de chaque fente à l'aide d'une boucle :

difference() {
  square([82,40],center);
  for ( i = [1 : 26] ){
    translate([i*3,4,0]) {
      square([1,32]);
    }
  }
}

form2.png

Nous allons maintenant donner un peu d'épaisseur à cette première forme en l'extrudant : on ajoute cette instruction *avant* la forme 2D créée à l'instant :

 linear_extrude(height = 3, center = false)

form3.png

Ajoutons maintenant une première paroi latérale :

cube([82,1,15]);

form4.png

Puis une seconde paroi qui est identique à la première avec une translation :

translate([0,40,0]) {
    cube([82,1,15]);
}

form5.png

Rajoutons les dernières parois nécessaires :

cube([1,40,15]);
translate([81,0,0]) {
 cube([1,40,15]);
}

form6.png

Pour finir la boîte, nous voulons ajouter 2 petites surfaces qui en permettront la fixation. Comme la boîte sera imprimée en 3D, il est nécessaire que ces surfaces apparaissent progressivement. Nous allons donc les modéliser avec un prisme :

module prism(l, w, h){
  polyhedron(
     points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
     faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]] );
}

translate([6,30,15]) {
    rotate([0,180,90]) {
        prism(20,5,15);
    }
}

translate([76,10,15]) {
    rotate([0,180,270]) {
        prism(20,5,15);
    }
}

form7.png

Et voilà le tour est joué !

Pour aller plus loin

Dans l'exemple précédent, la longueur de la boîte (82 mm) a été écrite en dur et tous les autres objets ont été placés d'après cette dimension. Il eut bien sûr été possible de définir une variable (par exemple "length") en début de fichier et adapter le code !

Cela donne alors :

length=82;
linear_extrude(height = 3, center = false)
difference() {
  square([length,40],center);
  for ( i = [1 : (length / 3)] ){
    translate([i*3,4,0]) {
      square([1,32]);
    }
  }
}
cube([length,1,15]);
translate([0,40,0]) {
    cube([length,1,15]);
}

cube([1,40,15]);
translate([length-1,0,0]) {
 cube([1,40,15]);
}

module prism(l, w, h){
  polyhedron(
     points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
     faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]] );
}

translate([6,30,15]) {
    rotate([0,180,90]) {
        prism(20,5,15);
    }
}

translate([length-6,10,15]) {
    rotate([0,180,270]) {
        prism(20,5,15);
    }
}

Il n'y a alors plus qu'une seule variable à modifier pour fabriquer une boîte beaucoup plus longue !

form8.png

Tuesday, November 8 2016

Se connecter à l'ESP8266 avec ampy d'Adafruit pour plus de facilité

Dans les articles précédents (ici et ici), nous avons proposé de téléverser des fichiers sur l'ESP8266/NodeMCU à l'aide de l'utilitaire webcli.py fourni avec WebREPL. Si l'on accède physiquement à la puce (via le port série), il est possible d'utiliser l'utilitaire Ampy développé par Adafruit.

  1. Installons adafruit-ampy avec pip (pip3 si Python3)
pip3 install adafruit-ampy

Il se peut qu'il faille lancer cette commande en root ou avec sudo selon votre distribution.

  1. Flashons micropython sur le NodeMCU/ESP8266 sans surprise :
esptool.py --port /dev/ttyUSB0 --baud 460800 erase_flash
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m 0 /path/to/esp8266-20161017-v1.8.5.bin
  1. Après re-démarrage, connectons-nous à l'ESP8266 pour vérifier que tout fonctionne correctement :
picocom /dev/ttyUSB0 -b 115200
  1. Connectons-nous alors à l'aide d'ampy et affichons la liste des fichiers contenus sur la puce avec l'option "ls" :
ampy -p /dev/ttyUSB0 ls

Sur l'ESP8266 fraîchement flashé, on verra seulement le fichier "boot.py".

  1. Pour ajouter un fichier, il faut utiliser l'option "put"
ampy -p /dev/ttyUSB0 put /path/to/file

Les commandes disponibles avec ampy sont :

  get    Télécharger un fichier depuis la puce.
  ls     Lister le contenu de la puce.
  mkdir  Créer un dossier sur la puce.
  put    Téléverser un fichier sur la puce.
  reset  Provoquer un soft reset/reboot de la puce.
  rm     Supprimer un fichier de la puce.
  run    Exécuter un script sur la puce et afficher la sortie standard.

Thursday, October 27 2016

Envoyer un courriel avec NodeMCU sur l'ESP8266

Nous avons précédemment parlé de l'ESP8266 en le propulsant à l'aide de Micropython. Il est églament possible de propulser un ESP8266 à l'aide de NodeMCU, un microframework en lua (attention, c'est trompeur, NodeMCU désigne à la fois un type de matériel et le logiciel qui le propulse).

9865736.png

Pour bâtir la version du firmware NodeMCU adapté à son usage, on peut utiliser ce site internet : https://nodemcu-build.com/

Une fois NodeMCU construit, on l'envoie à l'aide des commandes :

esptool.py --port /dev/ttyUSB0 erase_flash
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m 0 /path/to/nodemcu.bin

Voyons maintenant comment utiliser NodeMCU. Nous allons d'abord placer sur l'ESP8266 un fichier "init.lua" qui servira à l'initialisation de l'ESP8266 et notamment à sa connexion au WIfi local :

function startup()
    if file.open("init.lua") == nil then
      print("init.lua deleted")
    else
      print("Running")
      file.close("init.lua")
      print("Running main.lua")
      dofile("main.lua")
    end
end

--init.lua
wifi.sta.disconnect()
print("Set up wifi mode")
wifi.setmode(wifi.STATION) --on active la connexion à un point d'accès
wifi.sta.config("ssid","password",0) --SSID et mot de passe du point d'accès
wifi.sta.connect()
tmr.alarm(1, 1000, 1, function()
    if wifi.sta.getip()== nil then
        print("IP unavailable, Waiting...")
    else
        tmr.stop(1)
        print("Config done, IP is "..wifi.sta.getip()) --si réussite, alors on affiche les infos du réseau
        print("You have 5 seconds to abort Startup")
        print("Waiting...")
        tmr.alarm(0,5000,0,startup)
    end
 end)

Le code est assez facile à lire. Une fois les instructions de init.lua terminées, on lance le fichier main.lua. Il est alors possible de faire exécuter les actions de son choix à l'ESP8266.

Imaginons que l'on souhaite faire envoyer des courriels de notification par l'ESP8266 : on utiliserait alors le code suivant dans main.lua. Comme la librairie crypto est utilisée, il faut bien évidemment construire NodeMCU avec cette librairie.

require("crypto")

-- The email and password from the account you want to send emails from
local LOGIN = "login"
local MY_EMAIL = "name@domain.tld"
local EMAIL_PASSWORD = "password"

-- The SMTP server and port of your email provider.
-- If you don't know it google [my email provider] SMTP settings
local SMTP_SERVER = "smtp.domain.tld"
local SMTP_PORT = "465"

-- The account you want to send email to
local mail_to = "name@domain.tld"

-- These are global variables. Don't change their values
-- they will be changed in the functions below
local email_subject = ""
local email_body = ""
local count = 0

local smtp_socket = nil -- will be used as socket to email server

-- The display() function will be used to print the SMTP server's response
function display(sck,response)
     print(response)
end

-- The do_next() function is used to send the SMTP commands to the SMTP
server in the required sequence.
-- I was going to use socket callbacks but the code would not run
callbacks after the first 3.
function do_next()
            if(count == 0)then
                count = count+1
                local IP_ADDRESS = wifi.sta.getip()
                smtp_socket:send("HELO "..IP_ADDRESS.."\r\n")
            elseif(count==1) then
                count = count+1
                smtp_socket:send("AUTH LOGIN\r\n")
            elseif(count == 2) then
                count = count + 1
                smtp_socket:send(crypto.toBase64(LOGIN).."\r\n")
            elseif(count == 3) then
                count = count + 1
                smtp_socket:send(crypto.toBase64(EMAIL_PASSWORD).."\r\n")
            elseif(count==4) then
                count = count+1
               smtp_socket:send("MAIL FROM:<" .. MY_EMAIL .. ">\r\n")
            elseif(count==5) then
                count = count+1
               smtp_socket:send("RCPT TO:<" .. mail_to ..">\r\n")
            elseif(count==6) then
                count = count+1
               smtp_socket:send("DATA\r\n")
            elseif(count==7) then
                count = count+1
                local message = string.gsub(
                "From: "".. MY_EMAIL ..""<"..MY_EMAIL..">\r\n" ..
                "To: "".. mail_to .. ""<".. mail_to..">\r\n"..
                "Subject: ".. email_subject .. "\r\n\r\n"  ..
                email_body,"\r\n.\r\n","")

                smtp_socket:send(message.."\r\n.\r\n")
            elseif(count==8) then
               count = count+1
                 tmr.stop(0)
                 smtp_socket:send("QUIT\r\n")
            else
               smtp_socket:close()
            end
end

-- The connectted() function is executed when the SMTP socket is
connected to the SMTP server.
-- This function will create a timer to call the do_next function which
will send the SMTP commands
-- in sequence, one by one, every 5000 milliseconds.
-- You can change the time to be smaller if that works for you, I used
5000ms just because.
function connected(sck)
    tmr.alarm(0,5000,1,do_next)
end

-- @name send_email
-- @description Will initiated a socket connection to the SMTP server
and trigger the connected() function
-- @param subject The email's subject
-- @param body The email's body
function send_email(subject,body)
     count = 0
     email_subject = subject
     email_body = body
     smtp_socket = net.createConnection(net.TCP,1) -- the last paramater indicates the connection is secured by TLS/SSL
     smtp_socket:on("connection",connected)
     smtp_socket:on("receive",display)
     smtp_socket:connect(SMTP_PORT,SMTP_SERVER)
end

function query()
    subject = "Notification email"
    body = "This is the body of the email"
    send_email(subject,body.."\n.\n")
end

print("Ready to work. Sending email.")
query()

Tuesday, October 25 2016

Un couple d'enfer : ESP8266 et DS18B20, un petit objet connecté à quelques euros qui mesure la température et la transmet par Wifi

Nous avons parlé de l'ESP8266 propulsé par micropython dans le billet précent. Parmi la multitude d'application possible, nous allons voir aujourd'hui comment coupler l'ESP8266 à une sonde DS18B20 pour relever périodiquement la température d'une pièce et transférer la valeur en Wifi à une base InfluxDB.

Principe

Nous parlons ici de mesure de température dans un lieu de vie : une prise de température toutes les 10 minutes est suffisante. Nous allons dès lors mettre en place le fonctionnement suivant pour l'ESP8266 :

  1. allumage, mise en route du Wifi, connexion au Wifi local
  2. mesure à 10 reprises de la température
  3. suppression des 2 valeurs extrêmes supérieures et des 2 valeurs extrêmes inférieures
  4. moyenne des 6 valeurs restantes
  5. envoi de la valeur à une base de données InfluxDB au moyen d'une requête POST
  6. mise en sommeil de l'ESP8266 pour 10 minutes

A la sortie de la mise en sommeil le cycle recommence.

En outre, un minuteur logiciel provoquera un redémarrage de l'ESP8266 s'il est bloqué 2 minutes sans arriver au bout de son cycle.

Branchements

Rien de sorcier : on alimente la sonde 1-wire DS18B20 en 3.3V (comme l'ESP8266), on en relie les masses et on place le pin de données de la sonde 1-wire sur un GPIO adéquat de l'ESP8266. Il ne faudra pas oublier la résistance de 4.7 kOhms entre le pin Vin et le pin Data de la sonde ! Et pour permettre la sortie du sommeil, il faudra relier le pin RESET (RST) de l'ESP8266 avec le GPIO 16 (celui de l'alarme RTC).

Code sur l'ESP8266

Nous allons placer le code ci-dessous dans le fichier main.py qui sera ensuite envoyé sur l'ESP8266 à l'aide des outils évoqués dans le billet précent :

./webrepl_cli.py /path/to/main.py 192.168.4.1:/

Le code intégral, fortement commenté, est là :

import socket
import time
import machine #pour accéder aux GPIOs
import onewire, ds18x20 #pour lire la sonde 1-wire
import urequests  #pour envoyer la requête POST
from machine import Timer

#Faire flasher i fois la petite LED bleue de la puce ESP8266
def do_flashes(i):
    if i<1:
        i=1
    pin = machine.Pin(2, machine.Pin.OUT)
    for z in range(0,i):
        time.sleep_ms(250)
        pin.value(not pin.value())
        time.sleep_ms(250)
        pin.value(not pin.value())
    pin.value(1) #On s'assure que la LED finit dans l'état "éteint"

#Se connecter au Wifi local
def do_connect():
    import network
    sta_if = network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print('connecting to network...')
        sta_if.active(True)
        sta_if.connect('SSID', 'password') #Remplacer le nom du SSID et le mot de passe de connexion
        while not sta_if.isconnected():
            pass
    print('network config:', sta_if.ifconfig())  #On imprime l'IP de la puce une fois connectée, pratique pour déboguer sur le port série
    do_flashes(4)

#Effectuer une requête POST sur une URL InfluxDB (ou autre)
def http_post(data):
    url = 'https://path.to.influx.db/write?db=dbname'
    data = ("temperature,tag1=x1,tag2=x2 value=%s" %
(str(data)))
    resp = urequests.post(url, data=data)

#Effectuer une mesure sur le GPIO 4
def do_ds18b20():
    dat = machine.Pin(4)
    ds = ds18x20.DS18X20(onewire.OneWire(dat)) #On crée l'objet OneWire
    roms = ds.scan()  #On scanne le bus pour trouver toutes les sondes
    print('found devices:', roms)

    #On mesure 10 fois la température
    if len(roms)>0:
        templist = []
        for i in range(10):
            ds.convert_temp()
            time.sleep_ms(1000) #On attend 1 seconde entre chaque prise de mesure pour laisser le temps à la sonde de se réinitialiser
            temp = ds.read_temp(roms[0])
            templist.append(temp)
        templist.remove(max(templist)) #On supprime les valeurs extrêmes
        templist.remove(max(templist))
        templist.remove(min(templist))
        templist.remove(min(templist))
        sum_of_temps = 0
        for temp in templist:
            sum_of_temps = sum_of_temps + temp
        final_temp = sum_of_temps/6
        print('Final temp: ', final_temp)
        return final_temp

#Redémarre l'ESP8266, "machine.reset" est équivalent à un redémarrage électrique
def force_reset():
    print("Machine inactive for too long, this is not normal, rebooting!")
    machine.reset()

#Regarde si l'ESP8266 se réveille d'un sommeil profond (et non d'un (re)démarrage électrique)
if machine.reset_cause() == machine.DEEPSLEEP_RESET:
    print('Woke from a deep sleep')

#On active le minuteur qui provoque le redémarrage dans 2 minutes
tim = Timer(-1)
tim.init(period=120000, mode=Timer.ONE_SHOT, callback=lambda
t:force_reset())

do_flashes(2) #On signale le démarrage du travail par 2 clignotements
do_connect() #Connexion au Wifi
time.sleep_ms(2000) #On attend 2 secondes
temp = do_ds18b20() #On mesure la température
http_post(temp) #On l'envoie sur InfluxDB

print('set RTC alarm to wake up later')
rtc = machine.RTC() 
rtc.irq(trigger=rtc.ALARM0, wake=machine.DEEPSLEEP) #On configure RTC.ALARM0 pour être capable de re-démarrer le périphérique
rtc.alarm(rtc.ALARM0, 600000) #  Après 600 secondes RTC.ALARM0 redémarrera la machine !
#Petit compte à rebours, pratique pour l'interrompre par Ctrl+C, quand l'on veut se connecter à l'ESP8266 pour en modifier le comportement
print('deep sleep in 20 seconds')
time.sleep_ms(15000)
print('deep sleep in 5 seconds')
time.sleep_ms(2000)
print('deep sleep in 3 seconds')
time.sleep_ms(1000)
print('deep sleep in 2 seconds')
time.sleep_ms(2000)
print('deep sleep in 1 seconds')
time.sleep_ms(1000)
print('deep sleep now! waking up in 600 seconds')
machine.deepsleep()

Et voilà une petite sonde qui prend la température toutes les 10 minutes.

Consommation ?

Un petit test rapide a montré que mon ESP8266 monté sur un kit de développement NodeMCU v1.0 (je pressens que la consommation serait moindre sans le kit de développement) :

  • demande ~100 mA lors des périodes de fonctionnement
  • demande <~10 mA lors de la phase de sommeil

C'est à creuser plus finement mais cela donne déjà quelques ordres de grandeur.

Sunday, October 23 2016

Micropython sur ESP8266, l'électronique toujours plus libre et puissante !

L'ESP8266 est un petite puce développée par Espressif qui a de multiples qualités :

  • elle dispose d'un petit coeur programmable
  • elle se connecte en Wifi ou/et se comporte comme un point d'accès Wifi
  • elle est fort peu onéreuse (quelques euros à peine)
  • elle a été largement adoptée par de nombreux bricoleurs de la blogosphère et on trouve une abondante littérature à son sujet

Initialement, elle a été beaucoup utilisée comme extension Wifi peu chère pour montages Arduino.

Mais ses qualités l'ont peu à peu rendu intéressante et utilisable seule : différents micro-systèmes ont été portés sur l'ESP8266 et l'ont peu à peu transformé en puce Wifi programmable. Ainsi, sur certains montages simples (internet des choses, domotique...) elle remplacera aisément un Arduino ou un Raspberry Pi et apportera en sus faible coût, faible consommation et encombrement réduit.

Nous allons voir dans ces lignes comment démarrer avec cette carte en l'équipement du micro-système micropython. Micropython a été porté récemment sur ESP8266 et le code en a été libéré suite à une campagne Kickstarter fructueuse.

Commençons par le matériel

La puce ESP8266 ressemble à ceci dans sa version 12 (qui est la plus performance notamment avec le plus grand nombre d'entrées-sorties) : esp8266-esp12.jpg

Pour un usage plus facile, on pourra la préférer pré-montée au sein d'un kit de développement qui en rendra :

  • l'alimentation facile (en USB 5V, la puce elle-même ne supporte que 3.3V)
  • le flashage aisé (toujours au travers d'un port USB fourni)
  • également le reset facilité à l'aide d'un bouton poussoir
  • enfin l'utilisation facile sur une breadboard pour prototypage

En inconvénient, la consommation électrique sera un peu plus forte et l'encombrement sera plus important. Mais passée la phase de prototypage, rien n'empêche d'utiliser la carte seule !

Parmi les kits de développement pratiques, on peut noter les planches NodeMCU (prendre la v1) qui sont très bien, sont libres (code source ici) et ressemblent à ceci : NodeMCU_DEVKIT_1.0.jpg

Attention toutefois à la correspondance des pins de la planche de développement et les GPIOs de l'ESP8266 : D1, D2, ... ne correspondent pas à GPIO1, GPIO2... Cf. le schéma ci-dessous : NODEMCU_DEVKIT_V1.0_PINMAP.png

Envoyons Micropython

Une fois en possession d'une puce ESP8266 et de son kit de développement, il suffit de s'y connecter à l'aide d'un câble USB et un nouveau périphérique /dev/ttyUSB0 doit devenir disponible pour le système.

On peut alors :

  • télécharger la dernière version du système micropython ici en prenant bien la version pour ESP8266
  • installer esptools.py sur sa machine par exemple avec la commande
pip install esptool
  • vider la mémoire actuelle de l'ESP8266 (pour éviter tout problème) avec la commande
esptool.py --port /dev/ttyUSB0 erase_flash
  • puis envoyer micropython (remplacer esp8266.bin par le fichier que vous avez obtenu sur le site de micropython)
esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=8m 0 /path/to/esp8266.bin

Premier usage via le port série

Après redémarrage de la puce, on peut s'y connecter en série au travers de l'USB par exemple avec picocom (ou un autre logiciel de son choix) :

picocom /dev/ttyUSB0 -b 115200

et on obtient alors une console REPL Python qui permet d'exécuter toute commande de son choix dans l'environnement micropython.

Par exemple pour changer l'état d'un GPIO (attention à la numérotation, cf supra), on pourra appeler les commandes suivantes :

pin = machine.Pin(2, machine.Pin.OUT)
pin.value(1)
pin.value(0)

qui feront basculer en état HIGH/LOW le GPIO2 (D4 sur la planche de développement).

Usage au travers de WebREPL

Encore plus pratique, il est possible de se connecter à l'ESP8266 et à la console Python au travers du Wifi. Pour ce faire, l'ESP8266 se positionne comme un point d'accès Wifi auquel on peut se connecter : le mot de passe de connexion est "micropythoN".

Une fois connecté, on peut appeler l'ESP8266 à l'adresse 192.168.4.1 et se connecter à la console Python à l'aide de WebREPL, une page avec un peu de javascript qui aide à se connecter à la console REPL depuis un navigateur.

Il suffit de télécharger le contenu du dépôt WebREPL et lancer le fichier webrepl.html.

Envoyer un fichier sur l'ESP8266

Pour envoyer un fichier sur l'ESP8266, par exemple un fichier main.py qui sera exécuté à chaque lancement après initialisation, on pourra utiliser le commande outil webrepl_cli.py livré dans le dépôt WebREPL.

Connecté au point d'accès de l'ESP8266, la commande :

./webrepl_cli.py /path/to/main.py 192.168.4.1:/

se chargera de copier le fichier main.py à la racine de l'ESP8266.

Main.py pour tout contrôler

Dès lors, il est possible de placer le code de son choix dans le fichier main.py à la racine de l'ESP8266 pour l'asservir et lui faire exécuter le code de son choix.

On pourra par exemple :

  • désactiver le point d'accès
  • faire se connecter l'ESP8266 à un réseau WIfi local
  • faire agir l'ESP8266 sur le réseau (envoi de paquets, exécution de requêtes diverses...)
  • jouer avec les ports GPIOs

Les idées ne vous manqueront certainement pas pour peupler le fichier main.py. Voilà un bon point de départ dans la documentation de micropython sur ESP8266.

Mesurer l'humidité avec une sonde DHT22 et la température avec une sonde DS18B20 sur Arduino, transférer l'information à un Raspberry Pi

L'objectif de ce billet est d'illustrer l'appariement et le travail synchronisé d'un Arduino et d'un Raspberry Pi. Concrètement, l'Arduino mesure l'humidité avec une sonde DHT22 et la température avec une sonde DS18B20 et l'objectif est de transférer cette information à un Raspberry Pi qui traite l'information et l'envoie sur Internet.

Certains se demanderont pourquoi ne pas tout faire directement avec le Raspberry Pi :

  1. on peut imaginer que tous les ports du Pi sont déjà utilisés
  2. ou que le montage se complique et qu'il n'est plus possible de tout gérer depuis le Pi mais qu'il est plus aisé de lui adjoindre une (ou des) planche(s) Arduino

Principe de communication entre Raspberry Pi et Arduino

Nous allons utiliser un lien série entre les 2 composants au travers d'une connexion USB qui relie les deux équipements. Concrètement, le Raspberry Pi enverra des ordres à l'Arduino sur le port série et écoutera attentivement la réponse qui viendra également sur le port série.

Code Arduino

Mesurer la température avec une sonde DS18B20

Pour faciliter les choses, on utilisera la bibliothèque DallasTemperature.h (disponible ici sur GitHub). Le code est développé ci-dessous et ne présente aucune difficulté particulière :

#include <OneWire.h> // Inclusion de la librairie OneWire
#include "DallasTemperature.h" //Librairie du capteur

// Initialize 1-wire
OneWire oneWire(10); //Bus 1-Wire sur la pin 10 de l'arduino
DallasTemperature sensors(&oneWire); //Utilistion du bus Onewire pour les capteurs
DeviceAddress sensorDeviceAddress; //Vérifie la compatibilité des capteurs

void doMeasures() {
  sensors.requestTemperatures(); //Demande la température aux capteurs
  Serial.print("temperature=");
  Serial.println(sensors.getTempCByIndex(0)); //Récupération de la température en degrés celsius du capteur n°0
}

// setup()
void setup() {
  sensors.begin(); //Activation des capteurs
  sensors.getAddress(sensorDeviceAddress, 0); //Demande l'adresse du capteur à l'index 0 du bus
  sensors.setResolution(sensorDeviceAddress, 11); //Résolutions possibles: 9,10,11,12
}

Pour mesurer la température, on appellera la fonction doMeasures().

Mesurer l'humidité avec une sonde DHT22

Là encore, le code n'est pas bien compliqué tant que l'on utilise la librairie DHT.h (par exemple celle d'Adafruit).

#include "DHT.h"

// Initialisation du capteur DHT
#define DHTPIN 12    // Pin sur lequel la sonde DHT 22 est attachée
#define DHTTYPE DHT22   // Type de sonde DHT22 : AM2302, AM2321
DHT dht(DHTPIN, DHTTYPE);

void doMeasures() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
  }

  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print("humidity=");
  Serial.println(h);
  Serial.print("temperature="); //Oui, un DHT22 ça mesure aussi la température :-) 
  Serial.println(t);
  Serial.print("heat_index=");
  Serial.println(hic);
}

// setup()
void setup() {
  dht.begin();
}
Écoute sur le port série et actions

Là encore, pas de surprise. La boucle loop() est utilisée pour réagir quand des données sont présentes sur l'interface série. On détecte la nature de l'appel et on peut imaginer différents comportements selon le message reçu. Par exemple, un caractère pourra déclencher le relevé de l'humidité sur DHT22 tandis qu'un autre caractère reçu déclenchera la prise de température sur la sonde DS18B20.

//setup()
void setup() {
  Serial.begin(9600); // Initialisation du port série
}

// for incoming serial data
int incomingByte = 0;
String res = "";

// loop()
void loop() {
  // On écoute sur le port série
  if (Serial.available() > 0) {
          // On lit le contenu du message série et selon le caractère reçu on déclenche une action différente
          incomingByte = Serial.read(); 
          if (incomingByte == 103) { //g
            doAction1();
          }
          if (incomingByte == 104) { //h
            doAction2();
          }
  }
}
Il suffit alors de tout combiner !

Il n'est pas difficile de combiner ces trois morceaux de code !

#include "DHT.h"
#include <OneWire.h>
#include "DallasTemperature.h" 

// Initialize DHT sensor.
#define DHTPIN 12
#define DHTTYPE DHT22  
DHT dht(DHTPIN, DHTTYPE);

// Initialize 1-wire
OneWire oneWire(10);
DallasTemperature sensors(&oneWire); //Utilistion du bus Onewire pour les capteurs
DeviceAddress sensorDeviceAddress; //Vérifie la compatibilité des capteurs

// for incoming serial data
int incomingByte = 0;
String res = "";

void doMeasures() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
  }

  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print("humidity=");
  Serial.println(h);
  Serial.print("temperature=");
  Serial.println(t);
  Serial.print("heat_index=");
  Serial.println(hic);

  sensors.requestTemperatures(); //Demande la température aux capteurs
  Serial.print("temperature=");
  Serial.println(sensors.getTempCByIndex(0)); //Récupération de la température en celsius du capteur n°0
}

// setup()
void setup() {
  Serial.begin(9600); // Initialisation du port série
  dht.begin();
  sensors.begin(); //Activation des capteurs
  sensors.getAddress(sensorDeviceAddress, 0); //Demande l'adresse du capteur à l'index 0 du bus
  sensors.setResolution(sensorDeviceAddress, 11); //Résolutions possibles: 9,10,11,12
}

// loop()
void loop() {
  // send data only when you receive data:
  if (Serial.available() > 0) {
          // read the incoming byte:
          incomingByte = Serial.read();
          if (incomingByte == 103) { //g
            doMeasures();
          }
  }
}

Code sur le Raspberry Pi

Nous allons utiliser un script Python qui se connectera via le port série à l'Arduino et :

  1. émettra le signal déclenchant l'action (dans notre cas le caractère "g")
  2. écoutera pendant 20 secondes l'éventuelle réponse
  3. transmettra la réponse à un serveur distant dans une requête GET
import serial
import os
import glob
import time
import requests

#Timeout de 20 secondes
tf = time.time()+20

#Initialisation du port série /dev/ttyUSB0 (cela peut varier selon la version de Raspbian et le type de planche Arduino, /dev/ttyUSB0 semble le défaut avec Raspbian Jessie et un Arduino Nano328)
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)

#On attend 2 secondes : si l'on écrit trop vite après l'ouverture du bus série, la communication risque d'échouer
time.sleep(2)

#On écrit le caractère "g" (ASCII 103) sur le port série
print("Now, we are sending the command to Arduino!")
ser.write("g".encode())

#Et on boucle désormais en lecture sur le port série
while time.time()<tf:
  line = ser.readline()
  if line:
    result = str(line).rstrip('\r\n')
    print(result)
    try:
      #Dans notre cas, le résultat brut de l'Arduino est passé à un serveur distant qui stocke l'information
      r = requests.post('https://monserveurdecollectedesdonnees', data=result, timeout=5.0)
      print(str(r.status_code)+" "+result)
    except:
      print("Failed, with payload: "+result)

#On ferme le canal de communication
ser.close()

Ce script peut alors être placé dans le crontab du système pour être exécuté périodiquement.

Saturday, October 22 2016

Volumio 2, pour un Raspberry Pi musical

Bonne nouvelle, Volumio 2 est tout juste sorti et cette nouvelle version améliore encore ce splendide logiciel libre.

Qu'est-ce que c'est ?

Volumio est une version de Raspbian spécialement préparée pour transformer un Raspberry Pi (ou d'autres cartes comme Odroid, Beaglebone...) en serveur musical. Ainsi équipé de Volumio, un Raspberry Pi servira de la musique disponible localement (par exemple dans un disque dur attaché à Volumio) ou sur le réseau local (par exemple un NAS). La première version de Volumio était déjà super (on en parlait ici), la nouvelle édition embellit l'interface, facilite la gestion de systèmes avec plusieurs Volumio (pour des installations dans différentes pièces) tout en conservant les caractéristiques qui faisaient la force de la première itération.

À quoi ça ressemble ?

Voilà l'écran principal de Volumio : Screenshot_2016-10-21_09-13-20.png

Et voici l'affichage des différents Volumio indépendants mais connectés à un même réseau : il n'a jamais été aussi commode de passer de l'un à l'autre ! Screenshot_2016-10-21_09-13-31.png

Comment l'installer ?

C'est d'une grande simplicité. Tout a été déployé et a été fonctionnel sur mon Raspberry Pi équipé d'Hifiberry Amp+ en 15 minutes.

  1. D'abord, télécharger l'image correspondant à votre matériel sur le site de Volumio
  2. Ensuite, sortir le fichier .img de son archive
  3. Le transférer sur une carte micro-SD (/dev/sdb dans l'exemple ci-dessous, à adapter, attention à ne pas se tromper !) avec la commande dd :
dd if=volumio.img of=/dev/sdb bs=4M
  1. Insérer la carte dans le Raspberry Pi et le démarrer
  2. Et voilà ;-)

Après chargement, l'interface graphique est disponible via le navigateur internet que l'on fera pointer vers http://volumio ou vers l'adresse IP du Pi.

Enfin, il est toujours possible d'accéder en SSH au Raspbian sous-jacent avec le nom d'utilisateur "volumio" et le mot de passe "volumio".

L'essayer, c'est l'adopter !

Wednesday, October 19 2016

Let's Encrypt, comment l'usage d'un reverse proxy permet l'obtention de certificats sans se soucier nullement de la nature du service sous-jacent, cas pratique avec Pound et Apache

Quand on utilise un reverse proxy, il est possible de grandement simplifier l'usage de Let's Encrypt pour protéger tous ses accès avec HTTPS.

Méthodologie

Pour mémoire, afin de vérifier la bonne possession d'un domaine abc.tld, Let's Encrypt appelle l'adresse 'abc.tld/.well-known/acme-challenge/X' où X correspond à un nom de fichier unique que le client Let's Encrypt (par exemple certbot) aura créé lors du challenge ACME. Si le test réussit, c'est que l'utilisateur qui revendique le domaine en a pleinement la possession puisqu'il est capable de créer et rendre visible un fichier à sa racine ; le certificat est alors accordé et créé.

Dès lors : créons une règle sur le reverse proxy qui redirige toutes les requêtes de l'ACME challenge vers un seul emplacement dans lequel le client Let's Encrypt écrira !

En pratique avec Pound comme reverse proxy

Ajoutons un paragraphe en tête de la configuration de Pound :

        Service
                URL "/.well-known/acme-challenge/.*"
                BackEnd
                        Address 1.2.3.4
                        Port 8000
                End
        End

Désormais, toute requête de type ACME challenge est envoyé vers le serveur 1.2.3.4 sur le port 8000.

Imaginons que ce serveur soit un Apache. Paramétrons-le comme suit :

  • dans /etc/apache2/ports.conf, on ajoute une ligne Listen 8000
  • dans /etc/apache2/sites-available/letsencrypt.conf, on ajoute ceci :
<VirtualHost *:8000>
        DocumentRoot /var/www/letsencrypt
        <Directory /var/www/letsencrypt/>
                Options FollowSymLinks MultiViews
                AllowOverride All
		Require all granted
        </Directory>
</VirtualHost>
  • on active le site par a2ensite letsencrypt.conf
  • on redémarre Apache par service apache2 restart

Dès lors, tout appel à

certbot certonly --renew-by-default -a webroot --webroot-path /var/www/letsencrypt/ -d mondomaine.tld

devra aboutir à la génération du certificat souhaité, quelque soit le service sous-jacent !

En pratique avec un autre reverse proxy ?

La même stratégie est possible ! Seule la configuration du reverse proxy changera. On pourra également utiliser tout autre serveur web (même le micro-serveur web fourni dans python) pour servir les fichiers du ACME challenge !

- page 1 of 6