Jeudi, mai 31 2018

Un pegboard pour mes outils -1-

  • Le pegboard, ou panneau à trous pour accrocher des trucs, c'est comme son nom l'indique un panneau avec des trous pour y enficher des crochets et y suspendre des trucs…

Taper ce mot clef sur l'ternet, et vous découvrirez pléthore de « trucs déco » relativement inutiles, pendant que je redécouvrais le concept au détour d'une recherche d'objet3D sur Thingiverse, alors que je connaissais la version planche à clous de l'atelier du père qui ne m'a jamais vraiment convaincu.

  • Alors ici on va mixer les 3 :

- Un truc pas trop moche, sans appeler ça déco…
- Un truc fiable et plus efficace que des clous en guise de crochet.
- Un truc à base de crochets imprimés3D sur mesures.

Parce que oui, j'en ai marre de voir traîner mes outils d'usage courant traîner et encombrer mon plan de travail… Objectif, tout suspendre !

  • On peut trouver au brico, autour de 10€, une simple plaque d'isorel percée… Bon j'aurais pu acheter ça, mais d'un j'ai trouvé ça cher, et deux elle était trop petite.

Alors j'ai pris une grande plaque d'isorel pour 3€ , et j'ai fait des p'tis trous, des p'tis trous, encore des p'tis trouuuuus… Des trous d'quatre millimèèèètreuuuuu, tous les 25 millimèèèètreuuuu.
Wé, si tu connais pas la chanson bah tant pis…

  • Donc j'ai fait le plus précisément possible un quadrillage de 25 mm et percé des trous de 4 mm de diamètre sur une chute d'isorel, qui m'a servis de gabarit de perçage pour trouer la grande plaque.

dsc03412.jpg dsc03417.jpg dsc03418.jpg dsc03419.jpg

  • En calant le gabarit correctement avec des tiges pour augmenter la précision.

dsc03420.jpg dsc03421.jpg

  • Ensuite pour quelques sous de plus, découpage - collage - clouage de petits tasseaux de 9 x 13 mm pour encadrer le panneau.

dsc03422.jpg dsc03426.jpg

  • Voilà, terminé ?

dsc03427.jpg dsc03429.jpg
dsc03430.jpg

  • Non, j'ai limé les clous qui dépassaient un peu de l'autre côté, histoire de pas abîmer le mur, et hop, 4 chevilles molly et c'est mis en place !




dsc03434.jpg dsc03435.jpg

  • Maintenant on colle du papier peint pour mieux intégrer le pegboard au mur… Hé oui, faut jamais jeter le dernier rouleau de papier entamé !

dsc03436.jpg dsc03437.jpg dsc03438.jpg dsc03440.jpg

  • Bon les photos ne sont pas terribles, car prise en lumière hivernale, et je communiquerais plus tard sur l'avancement de l'affaire, car je modélise et imprime mes crochets au fur et à mesure, que je partagerais alors ici et sur ma page Thingiverses.

Bien-évidemment je perce les trous dans le papier au besoin…
Pour le moment, à part mon crochet de base décliné en différentes tailles, j'ai fait notamment un support pour le pied à coulisse, outil ô combien utile, le support pour mon ordiphone, un support de webcam ainsi que pour la lampe qui me servent à streamer des trucs sur ma page twitch.
dsc03718.jpg dsc03711.jpg
dsc03712.jpg dsc03713.jpg
dsc03714.jpg dsc03715.jpg

À suivre !!

Vendredi, mars 30 2018

Assurance temporaire auto : Pas cher et en ligne !

L’assurance temporaire auto s’adresse aux conducteurs recherchant une couverture dont la durée de validité reste précise et courte et offrant les garanties minimales en termes de couverture auto. Elle couvre généralement sur une période de 1 à 90 jours et ne peut être souscrite que par un conducteur attestant au moins de 2 ans d’expérience sur la route. Généralement, le souscripteur doit être âgé d’au moins 21 ans. L’assurance temporaire auto offre la possibilité de couvrir les risques pour une durée courte et déterminée. Même si elle offre une couverture limitée comparée à l’assurance classique, ses garanties suffisent largement au vu des circonstances.

Prix de l’assurance temporaire

Les tarifs pratiqués par les assureurs sont libres et diffèrent souvent de par les conditions d’accès et les couvertures de l’assurance temporaire auto. C’est la raison pour laquelle, il est nécessaire de faire un travail préalable de prospection avant de choisir son assureur. Cette initiative assurera du bon choix du prestataire tant au niveau budget qu’au niveau de l’adéquation besoin/offre. Concrètement et à titre d’exemple, une assurance temporaire auto d’une journée coûtera 11€, 7jours coûtera 50€ et 1 mois sera taxé 200€. Ces prix sont approximatifs mais représentent néanmoins une moyenne.

L’assurance temporaire auto est intéressante pour les cas suivant :véhicule peu utilisé ou mobile de manière exceptionnelle et placé dans un local sécurisé et privatif, dans le cadre d’un déplacement à l’étranger pour lequel le contrat d’assurance classique ne couvre pas les risques, dans l’attente d’un nouveau contrat d’assurance auto classique, dans le cadre de l’importation d’un véhicule provenant de l’étranger doté donc d’une immatriculation temporaire et en attendant le certificat d’immatriculation définitif, en cas de suspension ou résiliation d’un contrat d’assurance auto classique et dans l’attente de pouvoir en souscrire un nouveau et dans l’attente de souscription d’un contrat classique pour une quelconque raison.

Samedi, mars 3 2018

WebRadioRéveilWifi -5-

Suite de l'étude précédente :

L'Horloge/Réveil étant fin prête, il est temps de réviser la configuration de la WebRadio.
J'ai tout repris de zero… C'est qu'il s'est passé pas mal de temps depuis les premières expérimentations, et pas mal de version de Raspbian sont passées sous les ponts !

Pour rappel, j'ai décidé d'articuler la WebRadio autour d'un Raspberry Pi 1 (où Rpi zeroW car le 1 n'est plus en vente), de quelques boutons d'interactions, d'une cellule infrarouge et d'un écran LCD (facultatif) bon marché type radar de recul.

  • On va ici étudier la partie software, la partie hardware concernant le câblage des GPIO, relais et interfaçage horloge, pilotée par le programme mpc.py venant au prochain billet.

1 - Installer et configurer Raspbian Lite :

  • Déployer l'image sur une carte SD depuis un système GNU/Linux, avec la commande DD

(attention, of=/dev/sdx à adapter pour la cible de votre carte SD, en cas d'erreur risque d'effacement d'un disque dur non désiré)

dd bs=4M if=2017-11-29-raspbian-stretch-lite.img of=/dev/sdx; sync
  • Placer la carte SD dans le Raspberry, et le mettre sous tension.

Exécuter raspi-config, et configurer tous les trucs comme on veut, notamment les variables locales (time zone, clavier, etc), et surtout le login automatique de l'utilisateur.

sudo raspi-config

raspi-config01.png
raspi-config02.png
raspi-config03.png

Après le reboot, pour rappel :

Login : pi
Pass : raspberry

  • Effectuer les mises à jour :
sudo apt update
sudo apt upgrade
  • Mettre les fichiers temporaires en ram pour économiser sur la durée de vie la la carte SD.
sudo nano /etc/fstab
tmpfs      /tmp		tmpfs	defaults,size=256M	0    0
tmpfs      /var/tmp	tmpfs	defaults,size=256M	0    0
tmpfs      /var/log	tmpfs	defaults,size=256M	0    0
  • Pour configurer le wifi, éditer le fichier /etc/wpa_supplicant/wpa_supplicant.conf et modifier comme suit la section wlan0 : (ou par raspi-config)
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=FR

network={
        ssid="le nom du réseau wi-fi"
        psk="le mot de passe du réseau wi-fi"
}
  • Relancer ensuite le réseau avec la commande :
sudo service networking restart
  • Pour régler la résolution d'écran afin de l'adapter au petit écran type radar de recul :
sudo nano /boot/config.txt
framebuffer_width=320 
framebuffer_height=240
  • Configurer la sortie sonore sur le jack plutôt que le HDMI (par défaut) :
amixer cset numid=3 1
  • Régler le niveau sonore, puis sauvegarder les modifications :
alsamixer
sudo alsactl store 0



2 - Les logiciels pour la WebRadio :

  • Installer le lecteur de musique, le pilotage GPIO et la synthèse vocale :
sudo apt install mpd mpc wiringpi espeak
  • Configuration du lecteur mpc/mpd, éditer :
sudo nano /etc/mpd.conf

Indiquer les chemins où seront stockés les playlists et les fichiers mp3 :

music_directory         "/home/pi/music"
playlist_directory              "/home/pi/playlists"

Puis relancer le service mpd

sudo service mpd restart
  • Écriture d'une playlist de station de radio :

Créer un fichier portant l’extension .m3u avec simplement la liste des URL des stations radio

nano /home/pi/playlists/radio.m3u
# StahlRadio - Metal - http://stahlradio.de/
http://streamplus52.leonex.de:22810/;
# Radio Metal - http://www.radiometal.com/
http://stream.radiometal.com:8010
# EBM Radio - Industrial, Futurepop, Synthipop, Dark Wave, Gothic, ... et Depeche Mode
http://ebm-radio.org:9000/ebm.ogg
# japanfm
http://radio.japanfm.fr/japan
# TSF Jazz
http://tsfjazz.ice.infomaniak.ch:80/tsfjazz-high
# Radio Neo - Français
http://stream.radioneo.org:8000/;chat.mp3
# Radio Equinoxe - Electo - http://radioequinoxe.com/radio/liens-decoute/
http://www.radioking.com/play/radio-equinoxe/76118
  • Écriture d'une playlist de fichier mp3 :

Créer un fichier portant l’extension .m3u avec simplement la liste des fichiers mp3 (stockés dans le dossier /home/pi/music)

nano /home/pi/playlists/FarCryBloodDragon.m3u
01. Rex Colt.mp3
02. Blood Dragon Theme.mp3
03. HELO-73.mp3
04. Warzone.mp3
05. Moment of Calm.mp3
06. Dr Elizabeth Darling.mp3
07. Power Core.mp3
08. Protektor.mp3
09. Sloan.mp3
10. Sloan's Assault.mp3
11. Blood Scope.mp3
12. Combat I.mp3
13. Combat II.mp3
14. Combat III.mp3
15. Katana.mp3
16. Omega Force.mp3
17. Nest.mp3
18. Rex's Escape.mp3
19. Love Theme.mp3
20. Sleeping Dragon.mp3
  • Et attention, pour que les fichiers mp3 soient pris en compte, il est nécessaire de scanner le dossier « music », sinon les mp3 ne fonctionneront pas !!
mpc update
  • La config est prête, voici le programme python mpc.py qui exploite tout ça pour fournir le service :
#!/usr/bin/env python2.7
# coding: utf-8
# on importe les modules nécessaires

import time
import os, sys
import RPi.GPIO as GPIO
import subprocess
import socket
# on met RPi.GPIO en mode notation BCM (numéro des pins)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# on initialise les GPIO en mode "écoute" (GPIO1 sur la nappe)
GPIO.setup(17, GPIO.OUT, initial = GPIO.LOW)        # GPIO0 - pin11 - Relais Ampli
#GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # GPIO1 - pin12 - LIRC
GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO2 - pin13 - Station suivante
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO3 - pin15 - PowerOFF
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO4 - pin16 - Station précédente
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO5 - pin18 - LCD ON/OFF
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO6 - pin22 - Play/pause/stop   ne fonctionne plus à cause de la tempo 1H
GPIO.setup(4, GPIO.OUT, initial = GPIO.LOW)     # GPIO7 - pin7  - Relais LCD

long_press = 1
very_long_press = 3
site = 'www.google.fr'

# Nettoyage lecteur média
os.system('mpc clear')

def is_connected(REMOTE_SERVER):
        try:
                # see if we can resolve the host name -- tells us if there is a DNS listening
                host = socket.gethostbyname(REMOTE_SERVER)
                # connect to the host -- tells us if the host is actually reachable
                s = socket.create_connection((host, 80), 2)
                return True
        except:
                pass
                return False

# Chargement de la playlist
if is_connected(site):
#     print "Site disponible"
     os.system('mpc load radio')
else:
#     print "Site indisponible"
     os.system('mpc load foo')

# au bout de QUelques minutes, stopper la lecture
heure=0
fin=9999999999

# fonction qui sera appelée quand on appuiera sur le bouton 25
def bouton25(a):
    global fin
    button_press_timer = 0
    GPIO.remove_event_detect(25) # empéche le bouton d'etre détecté x fois de plus
    while True:
        if(GPIO.input(a) == GPIO.LOW ): # bouton appuyé
            button_press_timer += 0.2 # incrémente tant que le bouton est maintenu

        else: # bouton relaché
            if (button_press_timer > very_long_press):
                # Arret du lecteur media
                os.system("espeak 'Arrêt de la wéb-radio !' -v fr+f5 -s150 -p 75 -a 300") # Voix synthétique
                subprocess.call(["mpc stop"], shell=True)
                GPIO.output(17, GPIO.LOW) # relais ampli OFF
            elif (button_press_timer > long_press):
                # Pause du lecteur media
                os.system("espeak 'playlist Far Cry Blood Dragon' -v en+f5 -s150 -p 75 -a 300")
                os.system('mpc clear')
                os.system('mpc load FarCryBloodDragon')
                os.system('mpc play')
            elif (button_press_timer > 0):
                # Lecture du lecteur media
                GPIO.output(17, GPIO.HIGH) # relais ampli ON
                os.system('mpc clear')
                   # Chargement de la playlist
                if is_connected(site):
                   # print "Site disponible"
                    os.system('mpc load radio')
                    os.system("espeak 'lecture' -v fr+f5 -s150 -p 75 -a 300")
                    os.system('mpc play 2')
                    fin=time.time()+3600	# attend 1h - 3600
                    fin=round(fin)
                else:
                    #print "Site indisponible"
                    os.system('mpc load foo')
                    os.system("espeak 'lecture' -v fr+f5 -s150 -p 75 -a 300")
                    os.system('mpc play')
                    fin=time.time()+3600	# attend 1h - 3600
                    fin=round(fin)

            button_press_timer = 0
        time.sleep(0.2)

# fonction qui sera appelée quand on appuiera sur le bouton 27
def bouton27(channel):
    # entrée suivante du lecteur media
    os.system("espeak 'station suivante' -v fr+f5 -s150 -p 75 -a 300")
    os.system("mpc next")

# fonction qui sera appelée quand on appuiera sur le bouton 23
def bouton23(channel):
    # entrée précédente du lecteur media
    os.system("espeak 'station précédente' -v fr+f5 -s150 -p 75 -a 300")
    os.system("mpc prev")

# fonction qui sera appelée quand on appuiera sur le bouton 22
def bouton22(channel):
    os.system("sudo poweroff")

# fonction qui sera appelée quand on appuiera sur le bouton 24
def bouton24(a):
    global fin
    button_press_timer = 0
    GPIO.remove_event_detect(24) # empéche le bouton d'etre détecté x fois de plus
    while True:
        if(GPIO.input(a) == GPIO.LOW ): # bouton appuyé
            button_press_timer += 0.2 # incrémente tant que le bouton est maintenu
        else: # bouton relaché
            if (button_press_timer > long_press):
                GPIO.output(4, GPIO.LOW) # relais LCD OFF
                os.system("espeak 'Éteindre lécran LCD' -v fr+f5 -s150 -p 75 -a 300")
                GPIO.output(17, GPIO.LOW) # relais ampli OFF
            elif (button_press_timer > 0):
                os.system('mpc stop')   # stop la radio
                GPIO.output(4, GPIO.HIGH) # relais LCD ON
                GPIO.output(17, GPIO.HIGH) # relais ampli ON
                os.system("espeak 'Allumage de lécran LCD' -v fr+f5 -s150 -p 75 -a 300")
                fin=time.time()+3600       # attend 1h - 3600
                fin=round(fin)

            button_press_timer = 0
        time.sleep(0.2)


# on met le bouton en écoute
GPIO.add_event_detect(27, GPIO.FALLING, callback=bouton27, bouncetime=200)
GPIO.add_event_detect(22, GPIO.FALLING, callback=bouton22, bouncetime=200)
GPIO.add_event_detect(23, GPIO.FALLING, callback=bouton23, bouncetime=100)
GPIO.add_event_detect(24, GPIO.FALLING, callback=bouton24, bouncetime=200)
GPIO.add_event_detect(25, GPIO.FALLING, callback=bouton25, bouncetime=200)

# on lance une boucle infinie, pour garder le script actif
while True:

    if (heure>=fin):
        os.system("mpc stop")
        GPIO.output(17, GPIO.LOW) # relais ampli OFF
        GPIO.output(4, GPIO.LOW) # relais LCD OFF
        fin=9999999999
    else:
        heure=time.time()
        heure=round(heure)

    # une petite pause entre chaque boucle, afin de réduire la charge sur le CPU
    time.sleep(2)

# on réinitialise les ports GPIO en sortie de script
GPIO.cleanup()
  • Le fonctionnement est simple :

- Le bouton 25 pour allumer et éteindre la radio, ou lancer une playlist mp3, par des appuies plus ou moins long (l'ampli audio est géré automatiquement).
- Le bouton 27 pour passer à la station radio suivante.
- Le bouton 23 pour passer à la station radio précédente.
- Et enfin, le bouton 24 pour allumer et éteindre l'écran LCD (et l'ampli audio).
- Lorsque la radio est allumée, soit par l'alarme de l'horloge, ou par le bouton 25, elle fonctionne durant 1h avant de s'éteindre. Idem pour l'écran LCD.
- Si internet n'est pas disponible, la radio bascule sur une playlist mp3 de secours.

  • Pour démarrer automatiquement le programme python dés le démarrage du Raspberry, créer un service pistart.service :
sudo nano /etc/systemd/system/RadioReveil.service
[Unit]
Description=Démarre le script de la webradio
[Service]
ExecStart=/usr/bin/python /home/pi/mpc.py
[Install]
WantedBy=multi-user.target
  • Installer le service :
sudo systemctl --system daemon-reload
sudo systemctl enable RadioReveil.service
  • Pour manipuler le service :
sudo systemctl status RadioReveil.service
sudo systemctl start RadioReveil.service



3 - Installer et configurer Kodi :

Le médiacenter est facultatif, il ouvre cependant sur une galaxie de possibilités…

sudo apt-get install kodi
  • Pour lancer Kodi automatiquement après l'autologin, éditer le fichier .profile :
nano ~/.profile

Et ajouter les lignes suivantes à la fin :

tty=`tty`
# Start Kodi only if login in tty1
if [ $tty = '/dev/tty1' ]; then
        kodi
fi


  • On prendra soins de configurer Kodi dans la résolution vidéo minimale (640x480), mais au vu de la faible résolution de l'écran LCD, il s'avère nécessaire d'afficher de grande police de caractère.

Pour cela éditer :

nano .kodi/addons/skin.confluence/720p/Font.xml

À la sous section <Name> font13, augmenter la valeur <Size> à 50 (initialement réglée à 20).

<name>font13</name>
<filename>Roboto-Regular.ttf</filename>
<size>50</size>

À la sous section <Name> fontContextMenu', augmenter la valeur <Size>'' à 50 (initialement réglée à 18).

<name>fontContextMenu</name>
<filename>Roboto-Regular.ttf</filename>
<size>50</size>

À la sous section <Name> font12_title, augmenter la valeur <Size> à 50 (initialement réglée à 17).

<name>font12_title</name>
<filename>Roboto-Bold.ttf</filename>
<size>50</size>



4 - La télécommande infra-rouge :

Utile au médiacenter, cette partie est donc également facultative !

  • Installer le soft de gestion de l'infrarouge :
sudo apt-get install lirc
  • Éditer hardware.conf pour régler les paramètres de LIRC :
sudo nano /etc/lirc/hardware.conf
########################################################
# /etc/lirc/hardware.conf
#
# Arguments which will be used when launching lircd
LIRCD_ARGS="--uinput"
# Don't start lircmd even if there seems to be a good config file
# START_LIRCMD=false
# Don't start irexec, even if a good config file seems to exist.
# START_IREXEC=false
#Try to load appropriate kernel modules
LOAD_MODULES=true
# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="default"
# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"
# Default configuration files for your hardware if any
LIRCD_CONF=""
LIRCMD_CONF=""
########################################################
  • Activer le module sur le RpiPi en éditant config.txt
sudo nano /boot/config.txt

Dé-commenter la ligne (sans autre argument, c'est le GPIO18 qui sera écouté par le module, sinon pour par exemple le GPIO23, on indiquera dtoverlay=lirc-rpi,gpio_in_pin=23) et redémarrer le RpiPi.

dtoverlay=lirc-rpi
  • Pour tester si les commandes infrarouge sont bien reçues :
sudo killall lircd
sudo mode2 -d /dev/lirc0

Si jamais le programme ça répond ceci :

Using driver devinput on device /dev/lirc0
Trying device: /dev/lirc0
Using device: /dev/lirc0
Partial read 8 bytes on /dev/lirc0

Alors on est en présence d'une Raspbian stretch (9), lircd buggée, pour corriger le problème, lancer le script :

sudo /usr/share/lirc/lirc-old2new
  • À chaque appuie sur une touche de la télécommande, devrait s'afficher ce genre de truc :
space 1223
pulse 281
space 1193
pulse 350
space 1199
pulse 264
space 1901
  • Bien, maintenant on va identifier la télécommande et associer chacun de ses boutons à une touche du clavier. Le programme va demander d'appuyer anarchiquement sur toutes les touches, puis de nommer les touches une à une. La syntaxe à respecter pour les noms est disponible en exécutant :
irrecord --list-namespace

Il est temps de procéder :

sudo irrecord -d /dev/lirc0 telecommande

Suivre la procédure indiquée par le programme…
J'ai choisis ces touches du clavier, qui correspondent aux raccourcis clavier les plus utile de Kodi, pour la simple raison que ça fonctionnera directement ! Pas la peine de configurer quoi que ce soit dans Kodi !

KEY_Up
KEY_Down
KEY_Right
KEY_Left
KEY_Enter
KEY_C (click droit)
KEY_PageUp
KEY_Esc (retour menu principal)
KEY_Back (retour menu précédent)
KEY_Rewind
KEY_Stop
KEY_PlayPause
KEY_FastForward

  • Voici le contenu de telecommande.lircd.conf' qui a été créé, le déplacer dans /etc/lirc/lircd.conf.d/ pour qu'il soit pris en compte par lirc''
begin remote

  name  remoteLongue
  bits           16
  flags SPACE_ENC|CONST_LENGTH
  eps            30
  aeps          100

  header       9053  4449
  one           609  1642
  zero          609   514
  ptrail        608
  repeat       9051  2202
  pre_data_bits   16
  pre_data       0x807F
  gap          108017
  toggle_bit_mask 0x0

      begin codes
          KEY_Up                   0x10EF
          KEY_Down                 0x08F7
          KEY_Right                0x807F
          KEY_Left                 0x30CF
          KEY_C                    0xA05F
          KEY_PageUp               0xB04F
          KEY_Back                 0x20DF
          KEY_Rewind               0x708F
          KEY_Stop                 0x8877
          KEY_PlayPause            0x50AF
          KEY_FastForward          0x48B7
          KEY_Enter                0x00FF
      end codes

end remote
  • Reste à redémarrer le service LIRC
sudo service lircd restart
  • Un moyen simple de savoir si ça marche, c'est de simplement appuyer sur les touches de la télécommande, ça devrait agir dans la console GNU/Linux ![1]

Par exemple la touche correspondant à KEY_C affichera le caractère C, normal quoi, puisque LIRC permet ainsi d'assigner l'entièreté des touches du clavier, et plus encore.

  • Au lancement de Kodi la télécommande devrait fonctionner

Si ce n'est pas le cas, ressortir et vérifier que le processus lircd tourne bien.

ps -A | grep lirc



À suivre…

Note

[1] La console tty de votre choix connecté en HDMI, ça ne fonctionne pas depuis ssh !

WebRadioRéveilWifi -5-

Suite de l'étude précédente :

L'Horloge/Réveil étant fin prête, il est temps de réviser la configuration de la WebRadio.
J'ai tout repris de zero… C'est qu'il s'est passé pas mal de temps depuis les premières expérimentations, et pas mal de version de Raspbian sont passées sous les ponts !

Pour rappel, j'ai décidé d'articuler la WebRadio autour d'un Raspberry Pi 1 (où Rpi zeroW car le 1 n'est plus en vente), de quelques boutons d'interactions, d'une cellule infrarouge et d'un écran LCD (facultatif) bon marché type radar de recul.

  • On va ici étudier la partie software, la partie hardware concernant le câblage des GPIO, relais et interfaçage horloge, pilotée par le programme mpc.py venant au prochain billet.

1 - Installer et configurer Raspbian Lite :

  • Déployer l'image sur une carte SD depuis un système GNU/Linux, avec la commande DD

(attention, of=/dev/sdx à adapter pour la cible de votre carte SD, en cas d'erreur risque d'effacement d'un disque dur non désiré)

dd bs=4M if=2017-11-29-raspbian-stretch-lite.img of=/dev/sdx; sync
  • Placer la carte SD dans le Raspberry, et le mettre sous tension.

Exécuter raspi-config, et configurer tous les trucs comme on veut, notamment les variables locales (time zone, clavier, etc), et surtout le login automatique de l'utilisateur.

sudo raspi-config

raspi-config01.png
raspi-config02.png
raspi-config03.png

Après le reboot, pour rappel :

Login : pi
Pass : raspberry

  • Effectuer les mises à jour :
sudo apt update
sudo apt upgrade
  • Mettre les fichiers temporaires en ram pour économiser sur la durée de vie la la carte SD.
sudo nano /etc/fstab
tmpfs      /tmp		tmpfs	defaults,size=256M	0    0
tmpfs      /var/tmp	tmpfs	defaults,size=256M	0    0
tmpfs      /var/log	tmpfs	defaults,size=256M	0    0
  • Pour configurer le wifi, éditer le fichier /etc/wpa_supplicant/wpa_supplicant.conf et modifier comme suit la section wlan0 : (ou par raspi-config)
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=FR

network={
        ssid="le nom du réseau wi-fi"
        psk="le mot de passe du réseau wi-fi"
}
  • Relancer ensuite le réseau avec la commande :
sudo service networking restart
  • Pour régler la résolution d'écran afin de l'adapter au petit écran type radar de recul :
sudo nano /boot/config.txt
framebuffer_width=320 
framebuffer_height=240
  • Configurer la sortie sonore sur le jack plutôt que le HDMI (par défaut) :
amixer cset numid=3 1
  • Régler le niveau sonore, puis sauvegarder les modifications :
alsamixer
sudo alsactl store 0



2 - Les logiciels pour la WebRadio :

  • Installer le lecteur de musique, le pilotage GPIO et la synthèse vocale :
sudo apt install mpd mpc wiringpi espeak
  • Configuration du lecteur mpc/mpd, éditer :
sudo nano /etc/mpd.conf

Indiquer les chemins où seront stockés les playlists et les fichiers mp3 :

music_directory         "/home/pi/music"
playlist_directory              "/home/pi/playlists"

Puis relancer le service mpd

sudo service mpd restart
  • Écriture d'une playlist de station de radio :

Créer un fichier portant l’extension .m3u avec simplement la liste des URL des stations radio

nano /home/pi/playlists/radio.m3u
# StahlRadio - Metal - http://stahlradio.de/
http://streamplus52.leonex.de:22810/;
# Radio Metal - http://www.radiometal.com/
http://stream.radiometal.com:8010
# EBM Radio - Industrial, Futurepop, Synthipop, Dark Wave, Gothic, ... et Depeche Mode
http://ebm-radio.org:9000/ebm.ogg
# japanfm
http://radio.japanfm.fr/japan
# TSF Jazz
http://tsfjazz.ice.infomaniak.ch:80/tsfjazz-high
# Radio Neo - Français
http://stream.radioneo.org:8000/;chat.mp3
# Radio Equinoxe - Electo - http://radioequinoxe.com/radio/liens-decoute/
http://www.radioking.com/play/radio-equinoxe/76118
  • Écriture d'une playlist de fichier mp3 :

Créer un fichier portant l’extension .m3u avec simplement la liste des fichiers mp3 (stockés dans le dossier /home/pi/music)

nano /home/pi/playlists/FarCryBloodDragon.m3u
01. Rex Colt.mp3
02. Blood Dragon Theme.mp3
03. HELO-73.mp3
04. Warzone.mp3
05. Moment of Calm.mp3
06. Dr Elizabeth Darling.mp3
07. Power Core.mp3
08. Protektor.mp3
09. Sloan.mp3
10. Sloan's Assault.mp3
11. Blood Scope.mp3
12. Combat I.mp3
13. Combat II.mp3
14. Combat III.mp3
15. Katana.mp3
16. Omega Force.mp3
17. Nest.mp3
18. Rex's Escape.mp3
19. Love Theme.mp3
20. Sleeping Dragon.mp3
  • Et attention, pour que les fichiers mp3 soient pris en compte, il est nécessaire de scanner le dossier « music », sinon les mp3 ne fonctionneront pas !!
mpc update
  • La config est prête, voici le programme python mpc.py qui exploite tout ça pour fournir le service :
#!/usr/bin/env python2.7
# coding: utf-8
# on importe les modules nécessaires

import time
import os, sys
import RPi.GPIO as GPIO
import subprocess
import socket
# on met RPi.GPIO en mode notation BCM (numéro des pins)
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
# on initialise les GPIO en mode "écoute" (GPIO1 sur la nappe)
GPIO.setup(17, GPIO.OUT, initial = GPIO.LOW)        # GPIO0 - pin11 - Relais Ampli
#GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)  # GPIO1 - pin12 - LIRC
GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO2 - pin13 - Station suivante
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO3 - pin15 - PowerOFF
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO4 - pin16 - Station précédente
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO5 - pin18 - LCD ON/OFF
GPIO.setup(25, GPIO.IN, pull_up_down=GPIO.PUD_UP)   # GPIO6 - pin22 - Play/pause/stop   ne fonctionne plus à cause de la tempo 1H
GPIO.setup(4, GPIO.OUT, initial = GPIO.LOW)     # GPIO7 - pin7  - Relais LCD

long_press = 1
very_long_press = 3
site = 'www.google.fr'

# Nettoyage lecteur média
os.system('mpc clear')

def is_connected(REMOTE_SERVER):
        try:
                # see if we can resolve the host name -- tells us if there is a DNS listening
                host = socket.gethostbyname(REMOTE_SERVER)
                # connect to the host -- tells us if the host is actually reachable
                s = socket.create_connection((host, 80), 2)
                return True
        except:
                pass
                return False

# Chargement de la playlist
if is_connected(site):
#     print "Site disponible"
     os.system('mpc load radio')
else:
#     print "Site indisponible"
     os.system('mpc load foo')

# au bout de QUelques minutes, stopper la lecture
heure=0
fin=9999999999

# fonction qui sera appelée quand on appuiera sur le bouton 25
def bouton25(a):
    global fin
    button_press_timer = 0
    GPIO.remove_event_detect(25) # empéche le bouton d'etre détecté x fois de plus
    while True:
        if(GPIO.input(a) == GPIO.LOW ): # bouton appuyé
            button_press_timer += 0.2 # incrémente tant que le bouton est maintenu

        else: # bouton relaché
            if (button_press_timer > very_long_press):
                # Arret du lecteur media
                os.system("espeak 'Arrêt de la wéb-radio !' -v fr+f5 -s150 -p 75 -a 300") # Voix synthétique
                subprocess.call(["mpc stop"], shell=True)
                GPIO.output(17, GPIO.LOW) # relais ampli OFF
            elif (button_press_timer > long_press):
                # Pause du lecteur media
                os.system("espeak 'playlist Far Cry Blood Dragon' -v en+f5 -s150 -p 75 -a 300")
                os.system('mpc clear')
                os.system('mpc load FarCryBloodDragon')
                os.system('mpc play')
            elif (button_press_timer > 0):
                # Lecture du lecteur media
                GPIO.output(17, GPIO.HIGH) # relais ampli ON
                os.system('mpc clear')
                   # Chargement de la playlist
                if is_connected(site):
                   # print "Site disponible"
                    os.system('mpc load radio')
                    os.system("espeak 'lecture' -v fr+f5 -s150 -p 75 -a 300")
                    os.system('mpc play 2')
                    fin=time.time()+3600	# attend 1h - 3600
                    fin=round(fin)
                else:
                    #print "Site indisponible"
                    os.system('mpc load foo')
                    os.system("espeak 'lecture' -v fr+f5 -s150 -p 75 -a 300")
                    os.system('mpc play')
                    fin=time.time()+3600	# attend 1h - 3600
                    fin=round(fin)

            button_press_timer = 0
        time.sleep(0.2)

# fonction qui sera appelée quand on appuiera sur le bouton 27
def bouton27(channel):
    # entrée suivante du lecteur media
    os.system("espeak 'station suivante' -v fr+f5 -s150 -p 75 -a 300")
    os.system("mpc next")

# fonction qui sera appelée quand on appuiera sur le bouton 23
def bouton23(channel):
    # entrée précédente du lecteur media
    os.system("espeak 'station précédente' -v fr+f5 -s150 -p 75 -a 300")
    os.system("mpc prev")

# fonction qui sera appelée quand on appuiera sur le bouton 22
def bouton22(channel):
    os.system("sudo poweroff")

# fonction qui sera appelée quand on appuiera sur le bouton 24
def bouton24(a):
    global fin
    button_press_timer = 0
    GPIO.remove_event_detect(24) # empéche le bouton d'etre détecté x fois de plus
    while True:
        if(GPIO.input(a) == GPIO.LOW ): # bouton appuyé
            button_press_timer += 0.2 # incrémente tant que le bouton est maintenu
        else: # bouton relaché
            if (button_press_timer > long_press):
                GPIO.output(4, GPIO.LOW) # relais LCD OFF
                os.system("espeak 'Éteindre lécran LCD' -v fr+f5 -s150 -p 75 -a 300")
                GPIO.output(17, GPIO.LOW) # relais ampli OFF
            elif (button_press_timer > 0):
                os.system('mpc stop')   # stop la radio
                GPIO.output(4, GPIO.HIGH) # relais LCD ON
                GPIO.output(17, GPIO.HIGH) # relais ampli ON
                os.system("espeak 'Allumage de lécran LCD' -v fr+f5 -s150 -p 75 -a 300")
                fin=time.time()+3600       # attend 1h - 3600
                fin=round(fin)

            button_press_timer = 0
        time.sleep(0.2)


# on met le bouton en écoute
GPIO.add_event_detect(27, GPIO.FALLING, callback=bouton27, bouncetime=200)
GPIO.add_event_detect(22, GPIO.FALLING, callback=bouton22, bouncetime=200)
GPIO.add_event_detect(23, GPIO.FALLING, callback=bouton23, bouncetime=100)
GPIO.add_event_detect(24, GPIO.FALLING, callback=bouton24, bouncetime=200)
GPIO.add_event_detect(25, GPIO.FALLING, callback=bouton25, bouncetime=200)

# on lance une boucle infinie, pour garder le script actif
while True:

    if (heure>=fin):
        os.system("mpc stop")
        GPIO.output(17, GPIO.LOW) # relais ampli OFF
        GPIO.output(4, GPIO.LOW) # relais LCD OFF
        fin=9999999999
    else:
        heure=time.time()
        heure=round(heure)

    # une petite pause entre chaque boucle, afin de réduire la charge sur le CPU
    time.sleep(2)

# on réinitialise les ports GPIO en sortie de script
GPIO.cleanup()
  • Le fonctionnement est simple :

- Le bouton 25 pour allumer et éteindre la radio, ou lancer une playlist mp3, par des appuies plus ou moins long (l'ampli audio est géré automatiquement).
- Le bouton 27 pour passer à la station radio suivante.
- Le bouton 23 pour passer à la station radio précédente.
- Et enfin, le bouton 24 pour allumer et éteindre l'écran LCD (et l'ampli audio).
- Lorsque la radio est allumée, soit par l'alarme de l'horloge, ou par le bouton 25, elle fonctionne durant 1h avant de s'éteindre. Idem pour l'écran LCD.
- Si internet n'est pas disponible, la radio bascule sur une playlist mp3 de secours.

  • Pour démarrer automatiquement le programme python dés le démarrage du Raspberry, créer un service pistart.service :
sudo nano /etc/systemd/system/RadioReveil.service
[Unit]
Description=Démarre le script de la webradio
[Service]
ExecStart=/usr/bin/python /home/pi/mpc.py
[Install]
WantedBy=multi-user.target
  • Installer le service :
sudo systemctl --system daemon-reload
sudo systemctl enable RadioReveil.service
  • Pour manipuler le service :
sudo systemctl status RadioReveil.service
sudo systemctl start RadioReveil.service



3 - Installer et configurer Kodi :

Le médiacenter est facultatif, il ouvre cependant sur une galaxie de possibilités…

sudo apt-get install kodi
  • Pour lancer Kodi automatiquement après l'autologin, éditer le fichier .profile :
nano ~/.profile

Et ajouter les lignes suivantes à la fin :

tty=`tty`
# Start Kodi only if login in tty1
if [ $tty = '/dev/tty1' ]; then
        kodi
fi


  • On prendra soins de configurer Kodi dans la résolution vidéo minimale (640x480), mais au vu de la faible résolution de l'écran LCD, il s'avère nécessaire d'afficher de grande police de caractère.

Pour cela éditer :

nano .kodi/addons/skin.confluence/720p/Font.xml

À la sous section <Name> font13, augmenter la valeur <Size> à 50 (initialement réglée à 20).

<name>font13</name>
<filename>Roboto-Regular.ttf</filename>
<size>50</size>

À la sous section <Name> fontContextMenu', augmenter la valeur <Size>'' à 50 (initialement réglée à 18).

<name>fontContextMenu</name>
<filename>Roboto-Regular.ttf</filename>
<size>50</size>

À la sous section <Name> font12_title, augmenter la valeur <Size> à 50 (initialement réglée à 17).

<name>font12_title</name>
<filename>Roboto-Bold.ttf</filename>
<size>50</size>



4 - La télécommande infra-rouge :

Utile au médiacenter, cette partie est donc également facultative !

  • Installer le soft de gestion de l'infrarouge :
sudo apt-get install lirc
  • Éditer hardware.conf pour régler les paramètres de LIRC :
sudo nano /etc/lirc/hardware.conf
########################################################
# /etc/lirc/hardware.conf
#
# Arguments which will be used when launching lircd
LIRCD_ARGS="--uinput"
# Don't start lircmd even if there seems to be a good config file
# START_LIRCMD=false
# Don't start irexec, even if a good config file seems to exist.
# START_IREXEC=false
#Try to load appropriate kernel modules
LOAD_MODULES=true
# Run "lircd --driver=help" for a list of supported drivers.
DRIVER="default"
# usually /dev/lirc0 is the correct setting for systems using udev
DEVICE="/dev/lirc0"
MODULES="lirc_rpi"
# Default configuration files for your hardware if any
LIRCD_CONF=""
LIRCMD_CONF=""
########################################################
  • Activer le module sur le RpiPi en éditant config.txt
sudo nano /boot/config.txt

Dé-commenter la ligne (sans autre argument, c'est le GPIO18 qui sera écouté par le module, sinon pour par exemple le GPIO23, on indiquera dtoverlay=lirc-rpi,gpio_in_pin=23) et redémarrer le RpiPi.

dtoverlay=lirc-rpi
  • Pour tester si les commandes infrarouge sont bien reçues :
sudo killall lircd
sudo mode2 -d /dev/lirc0

Si jamais le programme ça répond ceci :

Using driver devinput on device /dev/lirc0
Trying device: /dev/lirc0
Using device: /dev/lirc0
Partial read 8 bytes on /dev/lirc0

Alors on est en présence d'une Raspbian stretch (9), lircd buggée, pour corriger le problème, lancer le script :

sudo /usr/share/lirc/lirc-old2new
  • À chaque appuie sur une touche de la télécommande, devrait s'afficher ce genre de truc :
space 1223
pulse 281
space 1193
pulse 350
space 1199
pulse 264
space 1901
  • Bien, maintenant on va identifier la télécommande et associer chacun de ses boutons à une touche du clavier. Le programme va demander d'appuyer anarchiquement sur toutes les touches, puis de nommer les touches une à une. La syntaxe à respecter pour les noms est disponible en exécutant :
irrecord --list-namespace

Il est temps de procéder :

sudo irrecord -d /dev/lirc0 telecommande

Suivre la procédure indiquée par le programme…
J'ai choisis ces touches du clavier, qui correspondent aux raccourcis clavier les plus utile de Kodi, pour la simple raison que ça fonctionnera directement ! Pas la peine de configurer quoi que ce soit dans Kodi !

KEY_Up
KEY_Down
KEY_Right
KEY_Left
KEY_Enter
KEY_C (click droit)
KEY_PageUp
KEY_Esc (retour menu principal)
KEY_Back (retour menu précédent)
KEY_Rewind
KEY_Stop
KEY_PlayPause
KEY_FastForward

  • Voici le contenu de telecommande.lircd.conf' qui a été créé, le déplacer dans /etc/lirc/lircd.conf.d/ pour qu'il soit pris en compte par lirc''
begin remote

  name  remoteLongue
  bits           16
  flags SPACE_ENC|CONST_LENGTH
  eps            30
  aeps          100

  header       9053  4449
  one           609  1642
  zero          609   514
  ptrail        608
  repeat       9051  2202
  pre_data_bits   16
  pre_data       0x807F
  gap          108017
  toggle_bit_mask 0x0

      begin codes
          KEY_Up                   0x10EF
          KEY_Down                 0x08F7
          KEY_Right                0x807F
          KEY_Left                 0x30CF
          KEY_C                    0xA05F
          KEY_PageUp               0xB04F
          KEY_Back                 0x20DF
          KEY_Rewind               0x708F
          KEY_Stop                 0x8877
          KEY_PlayPause            0x50AF
          KEY_FastForward          0x48B7
          KEY_Enter                0x00FF
      end codes

end remote
  • Reste à redémarrer le service LIRC
sudo service lircd restart
  • Un moyen simple de savoir si ça marche, c'est de simplement appuyer sur les touches de la télécommande, ça devrait agir dans la console GNU/Linux ![1]

Par exemple la touche correspondant à KEY_C affichera le caractère C, normal quoi, puisque LIRC permet ainsi d'assigner l'entièreté des touches du clavier, et plus encore.

  • Au lancement de Kodi la télécommande devrait fonctionner

Si ce n'est pas le cas, ressortir et vérifier que le processus lircd tourne bien.

ps -A | grep lirc



À suivre…

Note

[1] La console tty de votre choix connecté en HDMI, ça ne fonctionne pas depuis ssh !

Mardi, février 6 2018

WebRadioRéveilWifi -4-

Suite de l'étude précédente :

Je vais (enfin !!) reprendre la conception de mon WebRadioReveilWifi, après que tant de temps ait passé…
Il est désormais fonctionnel et me réveille correctement tous les matins, et c'est dans une suite de plusieurs billets que je vais détailler la réalisation étape par étape.


L'horloge :

Cette maquette m'a pas mal servi à apprendre Arduino et voir où les expérimentations me menaient, afin de bien dimensionner la suite.
C'est ainsi que j'ai pu router un circuit imprimé, puis graver percer et souder la plaque…
Cependant même si on croit avoir toujours tout prévu, j'ai tout de même dû modifier certaines choses sur mon circuit, une erreur fâcheuse et des modifications de dernières minutes.
C'est donc le circuit final réalisé sur Kicad que je vais livrer ici (en annexe du billet), il ne correspondra pas aux photos, sur lesquelles apparaissent donc les modifications et bricolage de rattrapages.

  • Le Schéma structurel de la carte principale :

horlogeStructurel.png

  • Le circuit de la carte principale :

horloge.png

horlogeSerigraphie.png horlogeCuivreDessous.png horlogeCuivreDessus.png

  • Liste des composants:
Nom                 Type et valeur

Shield1             Arduino Pro Mini 5V
P1, P6              Pin header x3
P2                  Pin header x6
P5                  Pin header x2
P3                  Pin header HE10-10
P4                  Bornier 2 vis
D1, D2              Led Verte
D3, D4              Led Rouge
D5                  Photodiode LSL100 ou Photorésistance 5516
R6, R7              Résistances  1kΩ
R11                 Résistances  2,2kΩ
R12 à R18           Résistances  39Ω
R19                 Résistances  150Ω
R20 à R26           Résistances  39Ω
R27                 Résistances  150Ω
R28 à R34           Résistances  39Ω
R35                 Résistances  150Ω
R36 à R42           Résistances  39Ω
R43                 Résistances  150Ω
Afficheur1, 2, 3, 4 Afficheur 7 segments SA10-21GWA-Kingbright 25,4 mm Vert
Q1, Q2, Q3, Q4, Q5  BC547
C7, C8, C9,C10      Condensateur 100nF
U1, U2, U3, U4      74HC595


  • Le Schéma structurel de la carte des boutons :

boutons_horlogeStructurel.png

  • Le circuit de la carte des boutons :

boutons_horloge.png
boutons_horlogeSerigraphie.png boutons_horlogeCuivreDessous.png

  • Liste des composants:
Nom                             Type et valeur

C1, C2, C3, C4, C5, C6          Condensateur 100nF
SW1, SW2, SW3, SW4, SW5, SW6    Petit bouton poussoir
R1, R2, R3, R4, R5, R6          Résistances  10kΩ
P1                              Pin header HE10-10


Une petit video !

dsc03253.jpg dsc03257.jpg

  • Voici les cartes et les composants parés pour la soudure.

dsc03266.jpg dsc03271.jpg

  • Mais avant, car réalisé en simple face, je n'ai pu faire autrement que de passer quelques liaisons sur l'autre face, et donc ici de devoir souder quelques fils en lieu et place.

dsc03268.jpg dsc03273.jpg

  • Pour plier les pattes des résistances, je me suis aidé d'un plioir imprimé3D… Étant donné le grand nombre de résistances, c'était pas du luxe !

dsc03275.jpg dsc03278.jpg

  • Je pense que la suite se passe de trop de commentaire, avec la soudure progressive les composants, des plus maigres aux plus épais.

dsc03276.jpg dsc03277.jpg dsc03279.jpg dsc03280.jpg

dsc02385b.jpg

  • Le module RTC (Real Time Clock) à base de DS3231 peut se trouver tout fait, mais ici je disposait seulement du composant, voulant rester compatible avec le concept du module enfichable, j'ai tout simplement réalisé une petite carte qui fait le même job, avec sa pile de sauvegarde !

dsc03282.jpg dsc03283.jpg

ChronodotStructurel.png Chronodot.png ChronodotSerigraphie.png ChronodotCuivreDessus.png

  • Liste des composants:
Nom      Type et valeur

C6       Condensateur 100nF
R9, R10  Résistances  10kΩ
U5       DS3231N
BT1      Support de pile Bouton 3V (CR2032)
P1       Pin header x6
  • Voilà donc tout est prêt, avec la carte principale qui accueillera (en haut) les 4 afficheurs 7 segments, les quatre 74HC595, (à droite) l'Arduino, (à gauche) la plaquette de boutons reliée au centre de la carte principale par une nappe de connecteur, (en bas) le capteur de mouvement (PIR) et le module RTC.

dsc03285.jpg

L'ampli audio :

  • Dans l'épisode précédent, j'avais donc câblé un petit ampli à base de LM386 sur une plaquette labo afin d'en valider le fonctionnement, puis j'en ai dessiné un circuit sur Kicad qui a été réalisé en simple face et que l'on va voir ci-après.

Cependant, comme pour l'horloge, j'ai un moment perdu de vue mes desiderata, et en rajoutant une source audio, je me suis plus tard rendu compte que j'avais oublié une partie du circuit pour le mélange des signaux entrants.
Et ce n'est pas tout… En intégrant l'ampli dans le boîtier du WebRadioRéveil que nous verrons dans un autre billet, j'ai vite compris que j'allais devoir retirer un certains nombre de connecteurs. Le circuit final réalisé sur Kicad (en annexe du billet), contient donc toutes les modifications et ne correspondra donc pas tout à fait aux photos.

  • Le schéma structurel de l'ampli :

AmpliAudioStructurel.png

  • Le circuit de l'ampli :

AmpliAudio.png
AmpliAudioSerigraphie.png AmpliAudioCuivreDessous.png

  • Liste des composants:
Nom                   Type et valeur

C13, C14, C15, C16    Condensateur électrochimique polarisé 47µF 16V
C2, C5, C8, C11       Condensateur électrochimique polarisé 10µF 16V
C3, C9                Condensateur électrochimique polarisé 470µF 16V
C4, C10               Condensateur 33nF
C6, C12               Condensateur 100nF
C1, C7                Condensateur 1µF
R4, R5, R6, R7        Résistances  2,2kΩ
R8, R9                Résistance  100Ω
R1, R3                Résistances  1,2kΩ
R2                    Résistances  1,5kΩ
RV1, RV2              Potentiomètre  Double 10kΩ
U1, U2                LM386N-3
D1                    Led Jaune 3 mm
SP1, SP2              Petit Haut Parleur
  • Une petit video !

dsc03262.jpg dsc03264.jpg

  • Tous les composants parés pour la soudure !

dsc03287.jpg
On verra donc plus tard que ce sont les deux jacks audio, le jack alim et le bornier que j'ai dû retirer. Et de rajouter une petite carte intégrant le mélangeur audio.

Le code :

  • Une fois le hardware terminé, il reste à revoir et améliorer le code commencé la dernière fois.

dsc03289.jpg
Tout le système assemblé proprement sur table pour coder sereinement.
À gauche de Raspberry Pi et sa carte de boutons pour piloter manuellement la radio, au dessus l'ampli audio relié au Raspberry Pi , et donc à droite l'horloge avec son Arduino, son module RTC et sa carte de boutons.

  • Le code et les deux librairies nécessaire pour Arduino sont disponible en annexe du billet.

Ce code est à utiliser avec Arduino 1.5.5

/****** Domaine publique, youpi ! ******/
/****** Ce code est à utiliser avec Arduino 1.5.5 *****/
#include <Wire.h>       // Communication avec le RTC
#include <Tone.h>       // Sonnerie ChipTune, voir Librairie
#include "Chronodot.h"  // Fonctions du Chronodot, voir Librairie modifiée

/****************/
/* Déclarations */
/****************/
#define CHRONODOT_ADDRESS 0x68

/****** Signaux ******/
#define datapin 10   // pin 10 pour les données vers les registres à décallages 74HC595
#define clockpin 11  // pin 11 pour l'horloge qui coordonne les registres à décallages
#define latchpin 8   // pin 8 pour le déclencheur des registres à décallages

/****** Boutons poussoir ******/
#define BoutonMinutes 12    // pin 12 pour le bouton poussoir d'incrément des minutes
#define BoutonHeures 13     // pin 13 pour le bouton poussoir d'incrément des heures
#define BoutonAlarme1 6     // pin 6 pour le bouton poussoir Alarme1
#define BoutonAlarme2 2     // pin 2 pour le bouton poussoir Alarme2, alias « interruption 0 »
#define BoutonHorloge 7     // pin 7 pour le bouton poussoir Horloge
#define BoutonSupp 1        // pin TX1 pour le bouton supplémentaire
#define relais A2           // pin analogique 2 pour le pilotage du relais ON/OFF AmpliAudio
#define Radio A3            // pin analogique 3 pour le déclenchement de la radio (relié par la carte d'interface 5V -> 3V) à l'un des GPIO du Rpi

/****** LED ******/
#define LedAlarm1 4       // pin 4 pour la led de l'alarme1
#define LedAlarm2 3       // pin 3 pour la led de l'alarme2

/****** Alimentation des 7 segments en PWM ******/
#define ledPin 9          // pin 9 pour le signal PWM de cadencement des afficheurs et leds
#define photodiodepin A0  // pin A0 pour la photodiode

/****** Variables d'état ******/
int EtatBoutonMinutes = 1;  // pour stocker l'état du bouton aprés sa lecture
int EtatBoutonHeures = 1;   // idem
int EtatBoutonAlarme1 = 1;  // idem
int EtatBoutonAlarme2 = 1;  // idem
int EtatBoutonHorloge = 1;  // idem
int EtatBoutonSupp = 1;     // idem
unsigned int ValeurPhotoDiode = 0;  // pour stocker l'état de la photodiode aprés sa lecture
volatile int change = 0;    // pour mémoriser l'état de l'interruption 0

/****** Variables temporelles ******/
unsigned int heuresHorloge;    // pour stocker les heures
unsigned int heuresHorlogeINC; // pour stocker l'incrément des heures
unsigned int minutesHorloge;   // pour stocker les minutes
unsigned int minutesHorlogeINC;// pour stocker l'incrément des minutes
unsigned int secondes;  // pour stocker les secondes
unsigned int annee;     // pour stocker l'annee
unsigned int mois;      // pour stocker le mois
unsigned int jour;      // pour stocker le jour
unsigned int heuresAlarme;    // pour stocker les heures
unsigned int heuresAlarmeINC; // pour stocker l'incrément des heures
unsigned int minutesAlarme;   // pour stocker les minutes
unsigned int minutesAlarmeINC;// pour stocker l'incrément des minutes

/****** Variables d'affichage ******/ 
int dizH = 0;          // pour stocker les dizaine des heures
int unitH = 0;         // pour stocker les unités des heures
int dizM = 0;          // pour stocker les dizaine des minutes
int unitM = 0;         // pour stocker les unités des minutes
byte AfficheurUN;      // données binaire pour l'afficheur UN, situé le plus à droite
byte AfficheurDEUX;    // données binaire pour l'afficheur DEUX
byte AfficheurTROIS;   // données binaire pour l'afficheur TROIS
byte AfficheurQUATRE;  // données binaire pour l'afficheur QUATRE, situé le plus à gauche
byte dataArray[10];    // Tableau de données

/****** Référenciel librairies ******/ 
Chronodot HORLOGE;      // HORLOGE, nom choisi arbitrairement, référence à la librairie Chronodot
ChronodotAlarm1 RADIO;
ChronodotAlarm2 REVEIL;

/**** Variable de construction des sonneries *****/
Tone tone1;

#define OCTAVE_OFFSET 0
#define isdigit(n) (n >= '0' && n <= '9')

int notes[] = { 0,
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
};

char *songA = "A-Team:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#";
char *songB = "Hallowee:d=4,o=5,b=140:32p,8d6,8g,8g,8d6,8g,8g,8d6,8g,8d#6,8g,8d6,8g,8g,8d6,8g,8g,8d6,8g,8d#6,8g,8c#6,8f#,8f#,8c#6,8f#,8f#,8c#6,8f#,8d6,8f#,8c#6,8f#,8f#,8c#6,8f#,8f#,8c#6,8f#,8d6,8f#";
char *songC = "Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c";
char *songD = "TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5";
char *songE = "Gadget:d=16,o=5,b=50:32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,32d#,32f,32f#,32g#,a#,d#6,4d6,32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,8d#";
char *songF = "MahnaMahna:d=16,o=6,b=125:c#,c.,b5,8a#.5,8f.,4g#,a#,g.,4d#,8p,c#,c.,b5,8a#.5,8f.,g#.,8a#.,4g,8p,c#,c.,b5,8a#.5,8f.,4g#,f,g.,8d#.,f,g.,8d#.,f,8g,8d#.,f,8g,d#,8c,a#5,8d#.,8d#.,4d#,8d#.";
int song = 1;   // variable pour changer de sonnerie aprés chaque utilisation de la sonnerie

/*******************/
/* Initialisations */
/*******************/
void setup ()      // Fonction d'initialisation obligatoire
{

//  Serial.begin(9600);                         // uncomment to debug
//  Serial.println("Initializing Chronodot.");  // uncomment to debug
  
  dataArray[0] = B00000011;  // Case du tableau qui contient la valeur binaire pour afficher zero sur un afficheur 7 segments
  dataArray[1] = B10011111;  // Case du tableau qui contient la valeur binaire pour afficher un sur un afficheur 7 segments
  dataArray[2] = B00100101;  // Case du tableau qui contient la valeur binaire pour afficher deux sur un afficheur 7 segments
  dataArray[3] = B00001101;  // Case du tableau qui contient la valeur binaire pour afficher trois sur un afficheur 7 segments
  dataArray[4] = B10011001;  // Case du tableau qui contient la valeur binaire pour afficher quatre sur un afficheur 7 segments
  dataArray[5] = B01001001;  // Case du tableau qui contient la valeur binaire pour afficher cinq sur un afficheur 7 segments
  dataArray[6] = B01000001;  // Case du tableau qui contient la valeur binaire pour afficher six sur un afficheur 7 segments
  dataArray[7] = B00011111;  // Case du tableau qui contient la valeur binaire pour afficher sept sur un afficheur 7 segments
  dataArray[8] = B00000001;  // Case du tableau qui contient la valeur binaire pour afficher huit sur un afficheur 7 segments 
  dataArray[9] = B00001001;  // Case du tableau qui contient la valeur binaire pour afficher neuf sur un afficheur 7 segments

  pinMode(clockpin, OUTPUT);     // pin correspondant à "clockpin" initialisée en sortie
  pinMode(datapin, OUTPUT);      // pin correspondant à "datakpin" initialisée en sortie
  pinMode(latchpin, OUTPUT);     // pin correspondant à "latchpin" initialisée en sortie
  pinMode(BoutonMinutes, INPUT); // pin correspondant à "BoutonMinutes" initialisée en entrée 
  pinMode(BoutonHeures, INPUT);  // pin correspondant à "BoutonHeures" initialisée en entrée  
  pinMode(BoutonAlarme1, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée  
  pinMode(BoutonAlarme2, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée   
  pinMode(BoutonHorloge, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée
  pinMode(BoutonSupp, INPUT);    // pin correspondant à "BoutonSupp" initialisée en entrée  
  pinMode(LedAlarm1, OUTPUT);    // pin correspondant à "LedAlarm1" initialisée en sortie
  pinMode(LedAlarm2, OUTPUT);    // pin correspondant à "LedAlarm2" initialisée en sortie 
  pinMode(relais, OUTPUT);       // pin correspondant à "relais" initialisée en sortie 
  pinMode(Radio, OUTPUT);        // pin correspondant à "Radio" initialisée en sortie 
  tone1.begin(A1);               // pin A1 pour le jack sonnerie
   
  Wire.begin();     // initialisation du chronodot, référence à la librairie wire
  HORLOGE.begin();  // initialisation du chronodot, référence à la librairie Chronodot

//************ MISE à L'heure manuelle du module RTC DS3231 ************
//  HORLOGE.adjust(DateTime(2014,12,25,10,30,12));  // années, mois, jour, heures, minutes, secondes
//  RADIO.adjust(AlarmTime1(6,30,0));
//  REVEIL.adjust(AlarmTime2(7,30));  

  attachInterrupt(0, stop2, FALLING); // attache l'interruption externe n°0 (pin2 soit bouton Alarm2) à la fonction stop2
  digitalWrite(Radio, HIGH);  // Coupe la radio au démarrage
  RADIO.Alarm1SetON();        // au démarrage, l'alarme Radio est forcée ON (en cas de coupure de courant)
  digitalWrite (LedAlarm1, HIGH);
  REVEIL.Alarm2SetON();      // au démarrage, l'alarme Réveil est forcée ON (en cas de coupure de courant)
  digitalWrite (LedAlarm2, HIGH);
}


/*************/
/* Programme */
/*************/
void loop ()      // boucle du programme !
{
  horloge ();                // appelle la fct "horloge", récupération des données temporelles
  AfficheHorloge ();         // appelle la fct "affiche", transfert des données temporelles sur les afficheurs 7 segments
  AjusteLuminosite();        // appelle la fct "AjusteLuminosite", plus il fait sombre, plus la lumière des afficheurs baisse  
  SurveilleBouton_Horloge_Heures_Minutes ();  // Pour permettre de mettre l'horloge à l'heure
//  SurveilleBouton_Supp ();
  RadioON(); // envoie d'ordre au rpi
  FaireSonnerSonnerie();
  EtatBoutonAlarme1 = digitalRead(BoutonAlarme1);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme1"
  EtatBoutonAlarme2 = digitalRead(BoutonAlarme2);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme2"  
  
 if (EtatBoutonAlarme1 == LOW)  // sinon, si bouton alarme 1 appuyé
  {
    for (int i=0; i <= 800; i++) //  faire durant 3 sec
    {
      alarme1();    
      AfficheAlarme();   // affiche l'alarme
      SurveilleBouton_Alarme1_Heures_Minutes ();  // régler l'alarme
      SurveilleBouton_Alarme1_Horloge ();
    }
  }
  
 if (EtatBoutonAlarme2 == LOW)  // sinon, si bouton alarme 2 appuyé
  {
 //   Stopper();
    for (int j=0; j <= 800; j++) //  faire durant 3 sec
    {
      alarme2();    
      AfficheAlarme();   // affiche l'alarme
      SurveilleBouton_Alarme2_Heures_Minutes ();  // régler l'alarme
      SurveilleBouton_Alarme2_Horloge ();
    }
  }  

 if(change == 1) {    // Si change = 1, stopper la sonnerie
    change = 0;
 //     Serial.print(change); //
    RADIO.Alarm1Stop();    
    REVEIL.Alarm2Stop();
    song = song + 1;  // pour une sonnerie différente la prochaine fois
    if(song == 7) {
      song = 1;
    }
 //     Serial.print(", song:"); //
 //     Serial.print(song); //
  //    Serial.println();
  }
}

/****************************************/   
/***** Les Fonctions du programme *******/   
/****************************************/   

/***** Fonction d'horloge *******/   
void horloge ()
{
  DateTime now = HORLOGE.now();  // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot
  heuresHorloge = now.hour(), DEC;      // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot
  minutesHorloge = now.minute(), DEC;   // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot
  secondes = now.second(), DEC;  // stocke les secondes en décimale dans la variable "secondes" grace à la fct "second" de la lib chronodot
  annee = now.year(), DEC;       // stocke l'année en décimale dans la variable "annee" grace à la fct "year" de la lib chronodot
  mois = now.month(), DEC;       // stocke le mois en décimale dans la variable "mois" grace à la fct "month" de la lib chronodot 
  jour = now.day(), DEC;         // stocke le jour en décimale dans la variable "jour" grace à la fct "day" de la lib chronodot
//  Serial.print(annee); //
//  Serial.print(':'); //
//  Serial.print(mois); //
//  Serial.print(':'); //
//  Serial.print(jour); //
//  Serial.print(':');   //
//  Serial.print(heures);   //décommenter pour débug
//  Serial.print(':');   //
//  Serial.print(minutes); //
//  Serial.println();  //
}

/***** Fonction d'alarme 1 *******/   
void alarme1 ()
{
  AlarmTime1 now = RADIO.now();  // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot
  heuresAlarme = now.hourA1(), DEC;      // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot
  minutesAlarme = now.minuteA1(), DEC;   // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot
 // Serial.print(heuresAlarme);   //décommenter pour débug
//  Serial.print(':');   //
 // Serial.print(minutesAlarme); //
 // Serial.println();  //
}

/***** Fonction d'alarme 2 *******/   
void alarme2 ()
{
  AlarmTime2 now = REVEIL.now();  // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot
  heuresAlarme = now.hourA2(), DEC;      // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot
  minutesAlarme = now.minuteA2(), DEC;   // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot
 // Serial.print(heuresAlarme);   //décommenter pour débug
//  Serial.print(':');   //
 // Serial.print(minutesAlarme); //
 // Serial.println();  //
}

/***** Fonction d'affichage horloge sur les 7 segments *******/  
void AfficheHorloge ()
{
  dizH = heuresHorloge / 10;   // par calcul, extrait la dizaine de "heures" et stocke le résultat dans "dizH" 
  unitH = heuresHorloge % 10;  // par calcul, extrait l'unités de "heures" et stocke le résultat dans "unitH" 
  dizM = minutesHorloge / 10;  // par calcul, extrait la dizaine de "minutes" et stocke le résultat dans "dizM"   
  unitM = minutesHorloge % 10; // par calcul, extrait l'unité de "minutes" et stocke le résultat dans "dizM" 
        
  AfficheurUN = dataArray[unitM];    // stocke la valeur binaire 7 segments de l'unité de minutes dans "AfficheurUN"
//  AfficheurUN &= ~(1<<1);
  AfficheurDEUX = dataArray[dizM];   // stocke la valeur binaire 7 segments de la dizaine de minutes dans "AfficheurDEUX"
  AfficheurTROIS = dataArray[unitH]; // stocke la valeur binaire 7 segments de l'unité d'heures dans "AfficheurTROIS"
  AfficheurQUATRE = dataArray[dizH]; // stocke la valeur binaire 7 segments de la dizaine d'heures dans "AfficheurQUATRE"
//  AfficheurQUATRE &= ~(1<<1);  
  digitalWrite(latchpin, 1);                              // latch à l'état HAUT pour autoriser le transfert des données série   
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurUN);     // envoi l'unités minute au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurDEUX);   // envoi la dizaine minute au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurTROIS);  // envoi l'unités heure au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurQUATRE); // envoi la dizaine heure au registre à décallage  
  digitalWrite(latchpin, 0);                              // latch à l'état BAS pour arreter le transfert des données série  
}

/***** Fonction d'affichage alarmes sur les 7 segments *******/  
void AfficheAlarme ()
{
  dizH = heuresAlarme / 10;   // par calcul, extrait la dizaine de "heures" et stocke le résultat dans "dizH" 
  unitH = heuresAlarme % 10;  // par calcul, extrait l'unités de "heures" et stocke le résultat dans "unitH" 
  dizM = minutesAlarme / 10;  // par calcul, extrait la dizaine de "minutes" et stocke le résultat dans "dizM"   
  unitM = minutesAlarme % 10; // par calcul, extrait l'unité de "minutes" et stocke le résultat dans "dizM" 
        
  AfficheurUN = dataArray[unitM];    // stocke la valeur binaire 7 segments de l'unité de minutes dans "AfficheurUN"
  AfficheurDEUX = dataArray[dizM];   // stocke la valeur binaire 7 segments de la dizaine de minutes dans "AfficheurDEUX"
  AfficheurTROIS = dataArray[unitH]; // stocke la valeur binaire 7 segments de l'unité d'heures dans "AfficheurTROIS"
  AfficheurQUATRE = dataArray[dizH]; // stocke la valeur binaire 7 segments de la dizaine d'heures dans "AfficheurQUATRE"
  
  digitalWrite(latchpin, 1);                              // latch à l'état HAUT pour autoriser le transfert des données série   
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurUN);     // envoi l'unités minute au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurDEUX);   // envoi la dizaine minute au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurTROIS);  // envoi l'unités heure au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurQUATRE); // envoi la dizaine heure au registre à décallage  
  digitalWrite(latchpin, 0);                              // latch à l'état BAS pour arreter le transfert des données série  
}


/***** Régler l'Horloge : Fonction Surveillance des BoutonHorloge, BoutonMinutes et BoutonHeures *******/    
void SurveilleBouton_Horloge_Heures_Minutes ()
{ 
  EtatBoutonHorloge = digitalRead(BoutonHorloge);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge"
  EtatBoutonHeures = digitalRead(BoutonHeures);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures"
  EtatBoutonMinutes = digitalRead(BoutonMinutes);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  if ((EtatBoutonHorloge == LOW) && (EtatBoutonHeures == LOW))  // si le bouton est appuyé
    {  
    delay(170);                  // alors, attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleHorlogeHeures ();       // et appeller la fonction "RegleHeures"
    } 
  if ((EtatBoutonHorloge == LOW) && (EtatBoutonMinutes == LOW))  // si le bouton est appuyé 
    {  
    delay(170);                    // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleHorlogeMinutes ();        // et appeller la fonction "RegleMinutes"
    } 
}

/***** Fonction d'incrément Heures *******/ 
void RegleHorlogeHeures ()
{ 
  heuresHorlogeINC = heuresHorloge + 1;  // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC"
  if (heuresHorlogeINC > 23)      // si la valeur de "heuresHorlogeINC" dépasse 23 (23h)
  {
    heuresHorlogeINC = 0;         // alors, et la variable "heuresHorlogeINC" à zero (minuit)
  }
//    Serial.print(heuresHorlogeINC);
//    Serial.println(); 
    HORLOGE.adjust(DateTime(annee,mois,jour,heuresHorlogeINC,minutesHorloge,0));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
}

/***** Fonction d'incrément minutes *******/ 
void RegleHorlogeMinutes ()
{ 
  minutesHorlogeINC = minutesHorloge + 1;  // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC"
  if (minutesHorlogeINC > 59)      // si la valeur de "minutesHorlogeINC" dépasse 59 (59min)
  {
    minutesHorlogeINC = 0;         // alors, met la variable "minutesHorlogeINC" à zero
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    HORLOGE.adjust(DateTime(annee,mois,jour,heuresHorloge,minutesHorlogeINC,0));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
 }

/***** Régler l'Alarme 1 : Fonction Surveillance des BoutonAlarme1, BoutonMinutes et BoutonHeures *******/        
void SurveilleBouton_Alarme1_Heures_Minutes ()
{ 
  EtatBoutonHeures = digitalRead(BoutonHeures);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures"  
  EtatBoutonMinutes = digitalRead(BoutonMinutes);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  EtatBoutonAlarme1 = digitalRead(BoutonAlarme1);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonHeures == LOW))  // si le bouton est appuyé
    {
    delay(170);                     // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleAlarm1Heures ();           // et appeller la fonction "RegleMinutes"
    }  
  if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonMinutes == LOW))  // si le bouton est appuyé
    {  
    delay(170);                    // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleAlarm1Minutes ();         // et appeller la fonction "RegleMinutes"
   }    
}

/***** Fonction d'incrément Alarme 1, Heures *******/ 
void RegleAlarm1Heures ()
{ 
  heuresAlarmeINC = heuresAlarme + 1;  // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC"
  if (heuresAlarmeINC > 23)      // si la valeur de "heuresHorlogeINC" dépasse 23 (23h)
  {
    heuresAlarmeINC = 0;         // alors, et la variable "heuresHorlogeINC" à zero (minuit)
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    RADIO.adjust(AlarmTime1(heuresAlarmeINC,minutesAlarme,0));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
} 
 
/***** Fonction d'incrément Alarme 1, Minutes *******/ 
void RegleAlarm1Minutes ()
{ 
  minutesAlarmeINC = minutesAlarme + 1;  // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC"
  if (minutesAlarmeINC > 59)      // si la valeur de "minutesHorlogeINC" dépasse 59 (59min)
  {
    minutesAlarmeINC = 0;         // alors, met la variable "minutesHorlogeINC" à zero
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    RADIO.adjust(AlarmTime1(heuresAlarme,minutesAlarmeINC,0));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
}  

/***** Régler l'Alarme 2 : Fonction Surveillance des BoutonAlarme2, BoutonMinutes et BoutonHeures *******/  
void SurveilleBouton_Alarme2_Heures_Minutes ()
{ 
  EtatBoutonHeures = digitalRead(BoutonHeures);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures"  
  EtatBoutonMinutes = digitalRead(BoutonMinutes);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  EtatBoutonAlarme2 = digitalRead(BoutonAlarme2);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonHeures == LOW))  // si le bouton est appuyé
    {
    delay(170);                     // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleAlarm2Heures ();           // et appeller la fonction "RegleMinutes"
    }  
  if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonMinutes == LOW))  // si le bouton est appuyé
    {  
    delay(170);                    // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleAlarm2Minutes ();         // et appeller la fonction "RegleMinutes"
   }    
}

/***** Fonction d'incrément Alarme 2, Heures *******/ 
void RegleAlarm2Heures ()
{ 
  heuresAlarmeINC = heuresAlarme + 1;  // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC"
  if (heuresAlarmeINC > 23)      // si la valeur de "heuresHorlogeINC" dépasse 23 (23h)
  {
    heuresAlarmeINC = 0;         // alors, et la variable "heuresHorlogeINC" à zero (minuit)
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    REVEIL.adjust(AlarmTime2(heuresAlarmeINC,minutesAlarme));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
} 
 
/***** Fonction d'incrément Alarme 2, Minutes *******/ 
void RegleAlarm2Minutes ()
{ 
  minutesAlarmeINC = minutesAlarme + 1;  // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC"
  if (minutesAlarmeINC > 59)      // si la valeur de "minutesHorlogeINC" dépasse 59 (59min)
  {
    minutesAlarmeINC = 0;         // alors, met la variable "minutesHorlogeINC" à zero
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    REVEIL.adjust(AlarmTime2(heuresAlarme,minutesAlarmeINC));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
}  
  
 
/***** Fonction Surveillance des BoutonAlarme1 et Horloge *******/ 
void SurveilleBouton_Alarme1_Horloge ()
{ 
  EtatBoutonAlarme1 = digitalRead(BoutonAlarme1);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme1"
  EtatBoutonHorloge = digitalRead(BoutonHorloge);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge"

  if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonHorloge == LOW))  // si les boutons sont appuyé
  {
    delay(600);                     // alors, attendre 600 ms, permet un appuie bref pour activer ou désactiver l'alarme1 (radio)

      switch (RADIO.Alarm1Flag())    
     {
       case 0:  //  désactivée     // 0AH = 0xxxxxxx
         RADIO.Alarm1SetON();
         digitalWrite (LedAlarm1, HIGH);
         break;
       case 1:  // alarme activée     
        RADIO.Alarm1SetOFF();
        digitalWrite (LedAlarm1, LOW);     // 0AH = 1xxxxxxx
        break;
     }
  }
}

/***** Fonction Surveillance des BoutonAlarme2 et Horloge *******/ 
void SurveilleBouton_Alarme2_Horloge ()
{ 
  EtatBoutonAlarme2 = digitalRead(BoutonAlarme2);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme2"
  EtatBoutonHorloge = digitalRead(BoutonHorloge);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge"

  if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonHorloge == LOW))  // si le bouton est appuyé  
  {
    delay(600);                     // alors, attendre 600 ms, permet un appuie bref pour activer ou désactiver l'alarme2 (sonnerie)

      switch (REVEIL.Alarm2Flag())    
     {
       case 0:  // alarme désactivée     // 0AH = 0xxxxxxx
         REVEIL.Alarm2SetON();
         digitalWrite (LedAlarm2, HIGH);
         break;
  
      case 1:  // alarme activée     
        REVEIL.Alarm2SetOFF();
        digitalWrite (LedAlarm2, LOW);     // 0AH = 1xxxxxxx
        break;
     }
   }
}

/***** Fonction d'envoie d'ordre au GPIO du Rpi *******/ 
void RadioON()
{
  if (RADIO.Alarm1Status()==1)
  {
 //   digitalWrite(relais, HIGH);  # fait now par le RPI lui meme
    digitalWrite(Radio, LOW);
    delay(300);   // appuie bref
    digitalWrite(Radio, HIGH);
  //  delay(10000);
    change = 1;
  }
}

/***** Fonction d'activation de la sonnerie ChipTune *******/ 
void FaireSonnerSonnerie()
{
  
  if (REVEIL.Alarm2Status()==1)
  {
    digitalWrite(relais, HIGH);   // AmpliAudio alimenté
    delay(500);  // attendre quelques millisec entre chaque bouctle de sonnerie
    switch (song) {
    case 1:    // A-Team
      sonnerie(songA);
 //     song = song + 1;
      break;
    case 2:    // Hallowee
      sonnerie(songB);
 //     song = song + 1;
      break;
    case 3:    // Muppets
      sonnerie(songC);
 //     song = song + 1;
      break;
    case 4:    // TakeOnMe
      sonnerie(songD);
 //     song = song + 1;
      break;
    case 5:    // Gadget
      sonnerie(songE);
 //     song = song + 1;
      break;
   case 6:    // MahnaMahna
      sonnerie(songF);
 //     song = 1;
      break; 
   default: // cas par défaut 
      sonnerie(songA);
      break;     */
    }
  }
}

/***** Fonction pour stopper la sonneie  *******/ 
void stop2 ()  //appelée directement via l'interruption 0 lorsqu'on appuie sur le bouton alarm2
{
  change = 1;
  digitalWrite(relais, LOW);  // coupe l'alimentation de l'AmpliAudio
  // Serial.print(change); //
}

/***** Fonction d'ajustement de la luminosité via la photodiode *******/ 
void AjusteLuminosite()
{
  ValeurPhotoDiode = analogRead(photodiodepin);  // Lit la valeur renvoyée par la photodiode, et stocke la valeur dans la variable "ValeurPhotoDiode"
  if (ValeurPhotoDiode > 495)       // si la valeur est supérieure à 495 (beaucoup de lumière reçue, genre en plein jour)
  {
     analogWrite(ledPin, 255);      // alors, illumination des afficheurs et leds à 100% (PWM de 0 à 255)
  }
  else if (ValeurPhotoDiode > 462)  // sinon, si la valeur est supérieure à 462
  {
    analogWrite(ledPin, 238);       // alors, illumination des afficheurs et leds moins forte    
  }
  else if (ValeurPhotoDiode > 429)
  {
    analogWrite(ledPin, 221);
  }
  else if (ValeurPhotoDiode > 396)
  {
    analogWrite(ledPin, 204);
  }
  else if (ValeurPhotoDiode > 363)
  {
    analogWrite(ledPin, 187);
  }
    else if (ValeurPhotoDiode > 330)
  {
    analogWrite(ledPin, 170);
  }
    else if (ValeurPhotoDiode > 297)
  {
    analogWrite(ledPin, 153); 
  }
    else if (ValeurPhotoDiode > 264) 
  {
    analogWrite(ledPin, 136);
  }
    else if (ValeurPhotoDiode > 231)
  {
    analogWrite(ledPin, 119);
  }
    else if (ValeurPhotoDiode > 198)
  {
    analogWrite(ledPin, 102);
  }
    else if (ValeurPhotoDiode > 165)
  {
    analogWrite(ledPin, 85); 
  }
    else if (ValeurPhotoDiode > 132)
  {
    analogWrite(ledPin, 68);
  }
    else if (ValeurPhotoDiode > 99)
  {
    analogWrite(ledPin, 51); 
  }
    else if (ValeurPhotoDiode > 66)
  {
    analogWrite(ledPin, 34);
  }
    else if (ValeurPhotoDiode > 33)
  {
    analogWrite(ledPin, 17); 
  }
  else                             // sinon,  (très peu voire pas du tout de lumière reçue, genre dans la nuit)
  {
    analogWrite(ledPin, 8);        // alors, illumination des afficheurs et leds aux minimum 8
  } 
}

/***** Fonction Sonnerie *****/
void sonnerie(char *p)
{
  // Absolutely no error checking in here

  byte default_dur = 4;
  byte default_oct = 6;
  int bpm = 63;
  int num;
  long wholenote;
  long duration;
  byte note;
  byte scale;

  // format: d=N,o=N,b=NNN:
  // find the start (skip name, etc)

  while(*p != ':') p++;    // ignore name
  p++;                     // skip ':'

  // get default duration
  if(*p == 'd')
  {
    p++; p++;              // skip "d="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    if(num > 0) default_dur = num;
    p++;                   // skip comma
  }

//  Serial.print("ddur: "); Serial.println(default_dur, 10);

  // get default octave
  if(*p == 'o')
  {
    p++; p++;              // skip "o="
    num = *p++ - '0';
    if(num >= 3 && num <=7) default_oct = num;
    p++;                   // skip comma
  }

//  Serial.print("doct: "); Serial.println(default_oct, 10);

  // get BPM
  if(*p == 'b')
  {
    p++; p++;              // skip "b="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    bpm = num;
    p++;                   // skip colon
  }

//  Serial.print("bpm: "); Serial.println(bpm, 10);

  // BPM usually expresses the number of quarter notes per minute
  wholenote = (60 * 1000L / bpm) * 4;  // this is the time for whole note (in milliseconds)

//  Serial.print("wn: "); Serial.println(wholenote, 10);


  // now begin note loop
  while(*p)
  {
    // first, get note duration, if available
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    
    if(num) duration = wholenote / num;
    else duration = wholenote / default_dur;  // we will need to check if we are a dotted note after

    // now get the note
    note = 0;

    switch(*p)
    {
      case 'c':
        note = 1;
        break;
      case 'd':
        note = 3;
        break;
      case 'e':
        note = 5;
        break;
      case 'f':
        note = 6;
        break;
      case 'g':
        note = 8;
        break;
      case 'a':
        note = 10;
        break;
      case 'b':
        note = 12;
        break;
      case 'p':
      default:
        note = 0;
    }
    p++;

    // now, get optional '#' sharp
    if(*p == '#')
    {
      note++;
      p++;
    }

    // now, get optional '.' dotted note
    if(*p == '.')
    {
      duration += duration/2;
      p++;
    }
  
    // now, get scale
    if(isdigit(*p))
    {
      scale = *p - '0';
      p++;
    }
    else
    {
      scale = default_oct;
    }

    scale += OCTAVE_OFFSET;

    if(*p == ',')
      p++;       // skip comma for next note (or we may be at the end)

    // now play the note

    if(note)
    {
//      Serial.print("Playing: ");
//      Serial.print(scale, 10); Serial.print(' ');
//      Serial.print(note, 10); Serial.print(" (");
//      Serial.print(notes[(scale - 4) * 12 + note], 10);
//      Serial.print(") ");
//      Serial.println(duration, 10);
      tone1.play(notes[(scale - 4) * 12 + note]);
      delay(duration);
      tone1.stop();
    }
    else
    {
//      Serial.print("Pausing: ");
//      Serial.println(duration, 10);
      delay(duration);
    }
  }
}
  • Pour faire l'interface entre l'horloge et la radio, les signaux de commande de l'Arduino opérants en 5 Volts et ceux du Raspberry en 3 Volts, il manque ici une carte d'interface. Elle sera étudié au prochain billet sur le sujet.

Mode l'emploi de l'horloge :

De gauche à droite, les boutons : [Alarme 2] [Alarme 1] [Horloge] [Heures] [Minutes]

  • Pour régler l'heure :

Appuyer (bref ou long) sur [Horloge] + [Heures] , et sur [Horloge] + [Minutes]

  • Pour régler l'alarme 1 :

Appuyer (bref ou long) sur [Alarme 1] + [Heures] , et sur [Alarme 1] + [Minutes]

  • Pour régler l'alarme 2 :

Appuyer (bref ou long) sur [Alarme 2] + [Heures] , et sur [Alarme 2] + [Minutes]

  • Pour afficher l'alarme 1 :

Appuyer (bref) sur [Alarme 1]

  • Pour afficher l'alarme 2 :

Appuyer (bref) sur [Alarme 2]

  • Pour stopper la sonnerie :

Appuyer (bref) sur [Alarme 2]


À suivre…

WebRadioRéveilWifi -4-

Suite de l'étude précédente :

Je vais (enfin !!) reprendre la conception de mon WebRadioReveilWifi, après que tant de temps ait passé…
Il est désormais fonctionnel et me réveille correctement tous les matins, et c'est dans une suite de plusieurs billets que je vais détailler la réalisation étape par étape.


L'horloge :

Cette maquette m'a pas mal servi à apprendre Arduino et voir où les expérimentations me menaient, afin de bien dimensionner la suite.
C'est ainsi que j'ai pu router un circuit imprimé, puis graver percer et souder la plaque…
Cependant même si on croit avoir toujours tout prévu, j'ai tout de même dû modifier certaines choses sur mon circuit, une erreur fâcheuse et des modifications de dernières minutes.
C'est donc le circuit final réalisé sur Kicad que je vais livrer ici (en annexe du billet), il ne correspondra pas aux photos, sur lesquelles apparaissent donc les modifications et bricolage de rattrapages.

  • Le Schéma structurel de la carte principale :

horlogeStructurel.png

  • Le circuit de la carte principale :

horloge.png

horlogeSerigraphie.png horlogeCuivreDessous.png horlogeCuivreDessus.png

  • Liste des composants:
Nom                 Type et valeur

Shield1             Arduino Pro Mini 5V
P1, P6              Pin header x3
P2                  Pin header x6
P5                  Pin header x2
P3                  Pin header HE10-10
P4                  Bornier 2 vis
D1, D2              Led Verte
D3, D4              Led Rouge
D5                  Photodiode LSL100 ou Photorésistance 5516
R6, R7              Résistances  1kΩ
R11                 Résistances  2,2kΩ
R12 à R18           Résistances  39Ω
R19                 Résistances  150Ω
R20 à R26           Résistances  39Ω
R27                 Résistances  150Ω
R28 à R34           Résistances  39Ω
R35                 Résistances  150Ω
R36 à R42           Résistances  39Ω
R43                 Résistances  150Ω
Afficheur1, 2, 3, 4 Afficheur 7 segments SA10-21GWA-Kingbright 25,4 mm Vert
Q1, Q2, Q3, Q4, Q5  BC547
C7, C8, C9,C10      Condensateur 100nF
U1, U2, U3, U4      74HC595


  • Le Schéma structurel de la carte des boutons :

boutons_horlogeStructurel.png

  • Le circuit de la carte des boutons :

boutons_horloge.png
boutons_horlogeSerigraphie.png boutons_horlogeCuivreDessous.png

  • Liste des composants:
Nom                             Type et valeur

C1, C2, C3, C4, C5, C6          Condensateur 100nF
SW1, SW2, SW3, SW4, SW5, SW6    Petit bouton poussoir
R1, R2, R3, R4, R5, R6          Résistances  10kΩ
P1                              Pin header HE10-10


Une petit video !

dsc03253.jpg dsc03257.jpg

  • Voici les cartes et les composants parés pour la soudure.

dsc03266.jpg dsc03271.jpg

  • Mais avant, car réalisé en simple face, je n'ai pu faire autrement que de passer quelques liaisons sur l'autre face, et donc ici de devoir souder quelques fils en lieu et place.

dsc03268.jpg dsc03273.jpg

  • Pour plier les pattes des résistances, je me suis aidé d'un plioir imprimé3D… Étant donné le grand nombre de résistances, c'était pas du luxe !

dsc03275.jpg dsc03278.jpg

  • Je pense que la suite se passe de trop de commentaire, avec la soudure progressive les composants, des plus maigres aux plus épais.

dsc03276.jpg dsc03277.jpg dsc03279.jpg dsc03280.jpg

dsc02385b.jpg

  • Le module RTC (Real Time Clock) à base de DS3231 peut se trouver tout fait, mais ici je disposait seulement du composant, voulant rester compatible avec le concept du module enfichable, j'ai tout simplement réalisé une petite carte qui fait le même job, avec sa pile de sauvegarde !

dsc03282.jpg dsc03283.jpg

ChronodotStructurel.png Chronodot.png ChronodotSerigraphie.png ChronodotCuivreDessus.png

  • Liste des composants:
Nom      Type et valeur

C6       Condensateur 100nF
R9, R10  Résistances  10kΩ
U5       DS3231N
BT1      Support de pile Bouton 3V (CR2032)
P1       Pin header x6
  • Voilà donc tout est prêt, avec la carte principale qui accueillera (en haut) les 4 afficheurs 7 segments, les quatre 74HC595, (à droite) l'Arduino, (à gauche) la plaquette de boutons reliée au centre de la carte principale par une nappe de connecteur, (en bas) le capteur de mouvement (PIR) et le module RTC.

dsc03285.jpg

L'ampli audio :

  • Dans l'épisode précédent, j'avais donc câblé un petit ampli à base de LM386 sur une plaquette labo afin d'en valider le fonctionnement, puis j'en ai dessiné un circuit sur Kicad qui a été réalisé en simple face et que l'on va voir ci-après.

Cependant, comme pour l'horloge, j'ai un moment perdu de vue mes desiderata, et en rajoutant une source audio, je me suis plus tard rendu compte que j'avais oublié une partie du circuit pour le mélange des signaux entrants.
Et ce n'est pas tout… En intégrant l'ampli dans le boîtier du WebRadioRéveil que nous verrons dans un autre billet, j'ai vite compris que j'allais devoir retirer un certains nombre de connecteurs. Le circuit final réalisé sur Kicad (en annexe du billet), contient donc toutes les modifications et ne correspondra donc pas tout à fait aux photos.

  • Le schéma structurel de l'ampli :

AmpliAudioStructurel.png

  • Le circuit de l'ampli :

AmpliAudio.png
AmpliAudioSerigraphie.png AmpliAudioCuivreDessous.png

  • Liste des composants:
Nom                   Type et valeur

C13, C14, C15, C16    Condensateur électrochimique polarisé 47µF 16V
C2, C5, C8, C11       Condensateur électrochimique polarisé 10µF 16V
C3, C9                Condensateur électrochimique polarisé 470µF 16V
C4, C10               Condensateur 33nF
C6, C12               Condensateur 100nF
C1, C7                Condensateur 1µF
R4, R5, R6, R7        Résistances  2,2kΩ
R8, R9                Résistance  100Ω
R1, R3                Résistances  1,2kΩ
R2                    Résistances  1,5kΩ
RV1, RV2              Potentiomètre  Double 10kΩ
U1, U2                LM386N-3
D1                    Led Jaune 3 mm
SP1, SP2              Petit Haut Parleur
  • Une petit video !

dsc03262.jpg dsc03264.jpg

  • Tous les composants parés pour la soudure !

dsc03287.jpg
On verra donc plus tard que ce sont les deux jacks audio, le jack alim et le bornier que j'ai dû retirer. Et de rajouter une petite carte intégrant le mélangeur audio.

Le code :

  • Une fois le hardware terminé, il reste à revoir et améliorer le code commencé la dernière fois.

dsc03289.jpg
Tout le système assemblé proprement sur table pour coder sereinement.
À gauche de Raspberry Pi et sa carte de boutons pour piloter manuellement la radio, au dessus l'ampli audio relié au Raspberry Pi , et donc à droite l'horloge avec son Arduino, son module RTC et sa carte de boutons.

  • Le code et les deux librairies nécessaire pour Arduino sont disponible en annexe du billet.

Ce code est à utiliser avec Arduino 1.5.5

/****** Domaine publique, youpi ! ******/
/****** Ce code est à utiliser avec Arduino 1.5.5 *****/
#include <Wire.h>       // Communication avec le RTC
#include <Tone.h>       // Sonnerie ChipTune, voir Librairie
#include "Chronodot.h"  // Fonctions du Chronodot, voir Librairie modifiée

/****************/
/* Déclarations */
/****************/
#define CHRONODOT_ADDRESS 0x68

/****** Signaux ******/
#define datapin 10   // pin 10 pour les données vers les registres à décallages 74HC595
#define clockpin 11  // pin 11 pour l'horloge qui coordonne les registres à décallages
#define latchpin 8   // pin 8 pour le déclencheur des registres à décallages

/****** Boutons poussoir ******/
#define BoutonMinutes 12    // pin 12 pour le bouton poussoir d'incrément des minutes
#define BoutonHeures 13     // pin 13 pour le bouton poussoir d'incrément des heures
#define BoutonAlarme1 6     // pin 6 pour le bouton poussoir Alarme1
#define BoutonAlarme2 2     // pin 2 pour le bouton poussoir Alarme2, alias « interruption 0 »
#define BoutonHorloge 7     // pin 7 pour le bouton poussoir Horloge
#define BoutonSupp 1        // pin TX1 pour le bouton supplémentaire
#define relais A2           // pin analogique 2 pour le pilotage du relais ON/OFF AmpliAudio
#define Radio A3            // pin analogique 3 pour le déclenchement de la radio (relié par la carte d'interface 5V -> 3V) à l'un des GPIO du Rpi

/****** LED ******/
#define LedAlarm1 4       // pin 4 pour la led de l'alarme1
#define LedAlarm2 3       // pin 3 pour la led de l'alarme2

/****** Alimentation des 7 segments en PWM ******/
#define ledPin 9          // pin 9 pour le signal PWM de cadencement des afficheurs et leds
#define photodiodepin A0  // pin A0 pour la photodiode

/****** Variables d'état ******/
int EtatBoutonMinutes = 1;  // pour stocker l'état du bouton aprés sa lecture
int EtatBoutonHeures = 1;   // idem
int EtatBoutonAlarme1 = 1;  // idem
int EtatBoutonAlarme2 = 1;  // idem
int EtatBoutonHorloge = 1;  // idem
int EtatBoutonSupp = 1;     // idem
unsigned int ValeurPhotoDiode = 0;  // pour stocker l'état de la photodiode aprés sa lecture
volatile int change = 0;    // pour mémoriser l'état de l'interruption 0

/****** Variables temporelles ******/
unsigned int heuresHorloge;    // pour stocker les heures
unsigned int heuresHorlogeINC; // pour stocker l'incrément des heures
unsigned int minutesHorloge;   // pour stocker les minutes
unsigned int minutesHorlogeINC;// pour stocker l'incrément des minutes
unsigned int secondes;  // pour stocker les secondes
unsigned int annee;     // pour stocker l'annee
unsigned int mois;      // pour stocker le mois
unsigned int jour;      // pour stocker le jour
unsigned int heuresAlarme;    // pour stocker les heures
unsigned int heuresAlarmeINC; // pour stocker l'incrément des heures
unsigned int minutesAlarme;   // pour stocker les minutes
unsigned int minutesAlarmeINC;// pour stocker l'incrément des minutes

/****** Variables d'affichage ******/ 
int dizH = 0;          // pour stocker les dizaine des heures
int unitH = 0;         // pour stocker les unités des heures
int dizM = 0;          // pour stocker les dizaine des minutes
int unitM = 0;         // pour stocker les unités des minutes
byte AfficheurUN;      // données binaire pour l'afficheur UN, situé le plus à droite
byte AfficheurDEUX;    // données binaire pour l'afficheur DEUX
byte AfficheurTROIS;   // données binaire pour l'afficheur TROIS
byte AfficheurQUATRE;  // données binaire pour l'afficheur QUATRE, situé le plus à gauche
byte dataArray[10];    // Tableau de données

/****** Référenciel librairies ******/ 
Chronodot HORLOGE;      // HORLOGE, nom choisi arbitrairement, référence à la librairie Chronodot
ChronodotAlarm1 RADIO;
ChronodotAlarm2 REVEIL;

/**** Variable de construction des sonneries *****/
Tone tone1;

#define OCTAVE_OFFSET 0
#define isdigit(n) (n >= '0' && n <= '9')

int notes[] = { 0,
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
};

char *songA = "A-Team:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#";
char *songB = "Hallowee:d=4,o=5,b=140:32p,8d6,8g,8g,8d6,8g,8g,8d6,8g,8d#6,8g,8d6,8g,8g,8d6,8g,8g,8d6,8g,8d#6,8g,8c#6,8f#,8f#,8c#6,8f#,8f#,8c#6,8f#,8d6,8f#,8c#6,8f#,8f#,8c#6,8f#,8f#,8c#6,8f#,8d6,8f#";
char *songC = "Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c";
char *songD = "TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5";
char *songE = "Gadget:d=16,o=5,b=50:32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,32d#,32f,32f#,32g#,a#,d#6,4d6,32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,8d#";
char *songF = "MahnaMahna:d=16,o=6,b=125:c#,c.,b5,8a#.5,8f.,4g#,a#,g.,4d#,8p,c#,c.,b5,8a#.5,8f.,g#.,8a#.,4g,8p,c#,c.,b5,8a#.5,8f.,4g#,f,g.,8d#.,f,g.,8d#.,f,8g,8d#.,f,8g,d#,8c,a#5,8d#.,8d#.,4d#,8d#.";
int song = 1;   // variable pour changer de sonnerie aprés chaque utilisation de la sonnerie

/*******************/
/* Initialisations */
/*******************/
void setup ()      // Fonction d'initialisation obligatoire
{

//  Serial.begin(9600);                         // uncomment to debug
//  Serial.println("Initializing Chronodot.");  // uncomment to debug
  
  dataArray[0] = B00000011;  // Case du tableau qui contient la valeur binaire pour afficher zero sur un afficheur 7 segments
  dataArray[1] = B10011111;  // Case du tableau qui contient la valeur binaire pour afficher un sur un afficheur 7 segments
  dataArray[2] = B00100101;  // Case du tableau qui contient la valeur binaire pour afficher deux sur un afficheur 7 segments
  dataArray[3] = B00001101;  // Case du tableau qui contient la valeur binaire pour afficher trois sur un afficheur 7 segments
  dataArray[4] = B10011001;  // Case du tableau qui contient la valeur binaire pour afficher quatre sur un afficheur 7 segments
  dataArray[5] = B01001001;  // Case du tableau qui contient la valeur binaire pour afficher cinq sur un afficheur 7 segments
  dataArray[6] = B01000001;  // Case du tableau qui contient la valeur binaire pour afficher six sur un afficheur 7 segments
  dataArray[7] = B00011111;  // Case du tableau qui contient la valeur binaire pour afficher sept sur un afficheur 7 segments
  dataArray[8] = B00000001;  // Case du tableau qui contient la valeur binaire pour afficher huit sur un afficheur 7 segments 
  dataArray[9] = B00001001;  // Case du tableau qui contient la valeur binaire pour afficher neuf sur un afficheur 7 segments

  pinMode(clockpin, OUTPUT);     // pin correspondant à "clockpin" initialisée en sortie
  pinMode(datapin, OUTPUT);      // pin correspondant à "datakpin" initialisée en sortie
  pinMode(latchpin, OUTPUT);     // pin correspondant à "latchpin" initialisée en sortie
  pinMode(BoutonMinutes, INPUT); // pin correspondant à "BoutonMinutes" initialisée en entrée 
  pinMode(BoutonHeures, INPUT);  // pin correspondant à "BoutonHeures" initialisée en entrée  
  pinMode(BoutonAlarme1, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée  
  pinMode(BoutonAlarme2, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée   
  pinMode(BoutonHorloge, INPUT); // pin correspondant à "BoutonHeures" initialisée en entrée
  pinMode(BoutonSupp, INPUT);    // pin correspondant à "BoutonSupp" initialisée en entrée  
  pinMode(LedAlarm1, OUTPUT);    // pin correspondant à "LedAlarm1" initialisée en sortie
  pinMode(LedAlarm2, OUTPUT);    // pin correspondant à "LedAlarm2" initialisée en sortie 
  pinMode(relais, OUTPUT);       // pin correspondant à "relais" initialisée en sortie 
  pinMode(Radio, OUTPUT);        // pin correspondant à "Radio" initialisée en sortie 
  tone1.begin(A1);               // pin A1 pour le jack sonnerie
   
  Wire.begin();     // initialisation du chronodot, référence à la librairie wire
  HORLOGE.begin();  // initialisation du chronodot, référence à la librairie Chronodot

//************ MISE à L'heure manuelle du module RTC DS3231 ************
//  HORLOGE.adjust(DateTime(2014,12,25,10,30,12));  // années, mois, jour, heures, minutes, secondes
//  RADIO.adjust(AlarmTime1(6,30,0));
//  REVEIL.adjust(AlarmTime2(7,30));  

  attachInterrupt(0, stop2, FALLING); // attache l'interruption externe n°0 (pin2 soit bouton Alarm2) à la fonction stop2
  digitalWrite(Radio, HIGH);  // Coupe la radio au démarrage
  RADIO.Alarm1SetON();        // au démarrage, l'alarme Radio est forcée ON (en cas de coupure de courant)
  digitalWrite (LedAlarm1, HIGH);
  REVEIL.Alarm2SetON();      // au démarrage, l'alarme Réveil est forcée ON (en cas de coupure de courant)
  digitalWrite (LedAlarm2, HIGH);
}


/*************/
/* Programme */
/*************/
void loop ()      // boucle du programme !
{
  horloge ();                // appelle la fct "horloge", récupération des données temporelles
  AfficheHorloge ();         // appelle la fct "affiche", transfert des données temporelles sur les afficheurs 7 segments
  AjusteLuminosite();        // appelle la fct "AjusteLuminosite", plus il fait sombre, plus la lumière des afficheurs baisse  
  SurveilleBouton_Horloge_Heures_Minutes ();  // Pour permettre de mettre l'horloge à l'heure
//  SurveilleBouton_Supp ();
  RadioON(); // envoie d'ordre au rpi
  FaireSonnerSonnerie();
  EtatBoutonAlarme1 = digitalRead(BoutonAlarme1);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme1"
  EtatBoutonAlarme2 = digitalRead(BoutonAlarme2);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme2"  
  
 if (EtatBoutonAlarme1 == LOW)  // sinon, si bouton alarme 1 appuyé
  {
    for (int i=0; i <= 800; i++) //  faire durant 3 sec
    {
      alarme1();    
      AfficheAlarme();   // affiche l'alarme
      SurveilleBouton_Alarme1_Heures_Minutes ();  // régler l'alarme
      SurveilleBouton_Alarme1_Horloge ();
    }
  }
  
 if (EtatBoutonAlarme2 == LOW)  // sinon, si bouton alarme 2 appuyé
  {
 //   Stopper();
    for (int j=0; j <= 800; j++) //  faire durant 3 sec
    {
      alarme2();    
      AfficheAlarme();   // affiche l'alarme
      SurveilleBouton_Alarme2_Heures_Minutes ();  // régler l'alarme
      SurveilleBouton_Alarme2_Horloge ();
    }
  }  

 if(change == 1) {    // Si change = 1, stopper la sonnerie
    change = 0;
 //     Serial.print(change); //
    RADIO.Alarm1Stop();    
    REVEIL.Alarm2Stop();
    song = song + 1;  // pour une sonnerie différente la prochaine fois
    if(song == 7) {
      song = 1;
    }
 //     Serial.print(", song:"); //
 //     Serial.print(song); //
  //    Serial.println();
  }
}

/****************************************/   
/***** Les Fonctions du programme *******/   
/****************************************/   

/***** Fonction d'horloge *******/   
void horloge ()
{
  DateTime now = HORLOGE.now();  // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot
  heuresHorloge = now.hour(), DEC;      // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot
  minutesHorloge = now.minute(), DEC;   // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot
  secondes = now.second(), DEC;  // stocke les secondes en décimale dans la variable "secondes" grace à la fct "second" de la lib chronodot
  annee = now.year(), DEC;       // stocke l'année en décimale dans la variable "annee" grace à la fct "year" de la lib chronodot
  mois = now.month(), DEC;       // stocke le mois en décimale dans la variable "mois" grace à la fct "month" de la lib chronodot 
  jour = now.day(), DEC;         // stocke le jour en décimale dans la variable "jour" grace à la fct "day" de la lib chronodot
//  Serial.print(annee); //
//  Serial.print(':'); //
//  Serial.print(mois); //
//  Serial.print(':'); //
//  Serial.print(jour); //
//  Serial.print(':');   //
//  Serial.print(heures);   //décommenter pour débug
//  Serial.print(':');   //
//  Serial.print(minutes); //
//  Serial.println();  //
}

/***** Fonction d'alarme 1 *******/   
void alarme1 ()
{
  AlarmTime1 now = RADIO.now();  // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot
  heuresAlarme = now.hourA1(), DEC;      // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot
  minutesAlarme = now.minuteA1(), DEC;   // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot
 // Serial.print(heuresAlarme);   //décommenter pour débug
//  Serial.print(':');   //
 // Serial.print(minutesAlarme); //
 // Serial.println();  //
}

/***** Fonction d'alarme 2 *******/   
void alarme2 ()
{
  AlarmTime2 now = REVEIL.now();  // lecture de l'heure en cours dans la puce DS3231, référence à la librairie Chronodot
  heuresAlarme = now.hourA2(), DEC;      // stocke l'heure en décimale dans la variable "heures" grace à la fct "hour" de la lib chronodot
  minutesAlarme = now.minuteA2(), DEC;   // stocke les minutes en décimale dans la variable "minutes" grace à la fct "minute" de la lib chronodot
 // Serial.print(heuresAlarme);   //décommenter pour débug
//  Serial.print(':');   //
 // Serial.print(minutesAlarme); //
 // Serial.println();  //
}

/***** Fonction d'affichage horloge sur les 7 segments *******/  
void AfficheHorloge ()
{
  dizH = heuresHorloge / 10;   // par calcul, extrait la dizaine de "heures" et stocke le résultat dans "dizH" 
  unitH = heuresHorloge % 10;  // par calcul, extrait l'unités de "heures" et stocke le résultat dans "unitH" 
  dizM = minutesHorloge / 10;  // par calcul, extrait la dizaine de "minutes" et stocke le résultat dans "dizM"   
  unitM = minutesHorloge % 10; // par calcul, extrait l'unité de "minutes" et stocke le résultat dans "dizM" 
        
  AfficheurUN = dataArray[unitM];    // stocke la valeur binaire 7 segments de l'unité de minutes dans "AfficheurUN"
//  AfficheurUN &= ~(1<<1);
  AfficheurDEUX = dataArray[dizM];   // stocke la valeur binaire 7 segments de la dizaine de minutes dans "AfficheurDEUX"
  AfficheurTROIS = dataArray[unitH]; // stocke la valeur binaire 7 segments de l'unité d'heures dans "AfficheurTROIS"
  AfficheurQUATRE = dataArray[dizH]; // stocke la valeur binaire 7 segments de la dizaine d'heures dans "AfficheurQUATRE"
//  AfficheurQUATRE &= ~(1<<1);  
  digitalWrite(latchpin, 1);                              // latch à l'état HAUT pour autoriser le transfert des données série   
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurUN);     // envoi l'unités minute au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurDEUX);   // envoi la dizaine minute au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurTROIS);  // envoi l'unités heure au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurQUATRE); // envoi la dizaine heure au registre à décallage  
  digitalWrite(latchpin, 0);                              // latch à l'état BAS pour arreter le transfert des données série  
}

/***** Fonction d'affichage alarmes sur les 7 segments *******/  
void AfficheAlarme ()
{
  dizH = heuresAlarme / 10;   // par calcul, extrait la dizaine de "heures" et stocke le résultat dans "dizH" 
  unitH = heuresAlarme % 10;  // par calcul, extrait l'unités de "heures" et stocke le résultat dans "unitH" 
  dizM = minutesAlarme / 10;  // par calcul, extrait la dizaine de "minutes" et stocke le résultat dans "dizM"   
  unitM = minutesAlarme % 10; // par calcul, extrait l'unité de "minutes" et stocke le résultat dans "dizM" 
        
  AfficheurUN = dataArray[unitM];    // stocke la valeur binaire 7 segments de l'unité de minutes dans "AfficheurUN"
  AfficheurDEUX = dataArray[dizM];   // stocke la valeur binaire 7 segments de la dizaine de minutes dans "AfficheurDEUX"
  AfficheurTROIS = dataArray[unitH]; // stocke la valeur binaire 7 segments de l'unité d'heures dans "AfficheurTROIS"
  AfficheurQUATRE = dataArray[dizH]; // stocke la valeur binaire 7 segments de la dizaine d'heures dans "AfficheurQUATRE"
  
  digitalWrite(latchpin, 1);                              // latch à l'état HAUT pour autoriser le transfert des données série   
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurUN);     // envoi l'unités minute au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurDEUX);   // envoi la dizaine minute au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurTROIS);  // envoi l'unités heure au registre à décallage
  shiftOut(datapin, clockpin, LSBFIRST, AfficheurQUATRE); // envoi la dizaine heure au registre à décallage  
  digitalWrite(latchpin, 0);                              // latch à l'état BAS pour arreter le transfert des données série  
}


/***** Régler l'Horloge : Fonction Surveillance des BoutonHorloge, BoutonMinutes et BoutonHeures *******/    
void SurveilleBouton_Horloge_Heures_Minutes ()
{ 
  EtatBoutonHorloge = digitalRead(BoutonHorloge);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge"
  EtatBoutonHeures = digitalRead(BoutonHeures);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures"
  EtatBoutonMinutes = digitalRead(BoutonMinutes);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  if ((EtatBoutonHorloge == LOW) && (EtatBoutonHeures == LOW))  // si le bouton est appuyé
    {  
    delay(170);                  // alors, attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleHorlogeHeures ();       // et appeller la fonction "RegleHeures"
    } 
  if ((EtatBoutonHorloge == LOW) && (EtatBoutonMinutes == LOW))  // si le bouton est appuyé 
    {  
    delay(170);                    // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleHorlogeMinutes ();        // et appeller la fonction "RegleMinutes"
    } 
}

/***** Fonction d'incrément Heures *******/ 
void RegleHorlogeHeures ()
{ 
  heuresHorlogeINC = heuresHorloge + 1;  // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC"
  if (heuresHorlogeINC > 23)      // si la valeur de "heuresHorlogeINC" dépasse 23 (23h)
  {
    heuresHorlogeINC = 0;         // alors, et la variable "heuresHorlogeINC" à zero (minuit)
  }
//    Serial.print(heuresHorlogeINC);
//    Serial.println(); 
    HORLOGE.adjust(DateTime(annee,mois,jour,heuresHorlogeINC,minutesHorloge,0));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
}

/***** Fonction d'incrément minutes *******/ 
void RegleHorlogeMinutes ()
{ 
  minutesHorlogeINC = minutesHorloge + 1;  // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC"
  if (minutesHorlogeINC > 59)      // si la valeur de "minutesHorlogeINC" dépasse 59 (59min)
  {
    minutesHorlogeINC = 0;         // alors, met la variable "minutesHorlogeINC" à zero
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    HORLOGE.adjust(DateTime(annee,mois,jour,heuresHorloge,minutesHorlogeINC,0));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
 }

/***** Régler l'Alarme 1 : Fonction Surveillance des BoutonAlarme1, BoutonMinutes et BoutonHeures *******/        
void SurveilleBouton_Alarme1_Heures_Minutes ()
{ 
  EtatBoutonHeures = digitalRead(BoutonHeures);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures"  
  EtatBoutonMinutes = digitalRead(BoutonMinutes);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  EtatBoutonAlarme1 = digitalRead(BoutonAlarme1);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonHeures == LOW))  // si le bouton est appuyé
    {
    delay(170);                     // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleAlarm1Heures ();           // et appeller la fonction "RegleMinutes"
    }  
  if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonMinutes == LOW))  // si le bouton est appuyé
    {  
    delay(170);                    // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleAlarm1Minutes ();         // et appeller la fonction "RegleMinutes"
   }    
}

/***** Fonction d'incrément Alarme 1, Heures *******/ 
void RegleAlarm1Heures ()
{ 
  heuresAlarmeINC = heuresAlarme + 1;  // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC"
  if (heuresAlarmeINC > 23)      // si la valeur de "heuresHorlogeINC" dépasse 23 (23h)
  {
    heuresAlarmeINC = 0;         // alors, et la variable "heuresHorlogeINC" à zero (minuit)
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    RADIO.adjust(AlarmTime1(heuresAlarmeINC,minutesAlarme,0));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
} 
 
/***** Fonction d'incrément Alarme 1, Minutes *******/ 
void RegleAlarm1Minutes ()
{ 
  minutesAlarmeINC = minutesAlarme + 1;  // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC"
  if (minutesAlarmeINC > 59)      // si la valeur de "minutesHorlogeINC" dépasse 59 (59min)
  {
    minutesAlarmeINC = 0;         // alors, met la variable "minutesHorlogeINC" à zero
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    RADIO.adjust(AlarmTime1(heuresAlarme,minutesAlarmeINC,0));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
}  

/***** Régler l'Alarme 2 : Fonction Surveillance des BoutonAlarme2, BoutonMinutes et BoutonHeures *******/  
void SurveilleBouton_Alarme2_Heures_Minutes ()
{ 
  EtatBoutonHeures = digitalRead(BoutonHeures);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHeures"  
  EtatBoutonMinutes = digitalRead(BoutonMinutes);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  EtatBoutonAlarme2 = digitalRead(BoutonAlarme2);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonMinutes"
  if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonHeures == LOW))  // si le bouton est appuyé
    {
    delay(170);                     // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleAlarm2Heures ();           // et appeller la fonction "RegleMinutes"
    }  
  if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonMinutes == LOW))  // si le bouton est appuyé
    {  
    delay(170);                    // alors,  attendre 170 ms, permet un appuie bref pour incrémenter de 1, et un appuie long pour incrémenter rapidement d'autant qu'on veut
    RegleAlarm2Minutes ();         // et appeller la fonction "RegleMinutes"
   }    
}

/***** Fonction d'incrément Alarme 2, Heures *******/ 
void RegleAlarm2Heures ()
{ 
  heuresAlarmeINC = heuresAlarme + 1;  // additionne 1 à la valeur contenue dans la variable "heures" et stocke le résultat dans la variable "heuresHorlogeINC"
  if (heuresAlarmeINC > 23)      // si la valeur de "heuresHorlogeINC" dépasse 23 (23h)
  {
    heuresAlarmeINC = 0;         // alors, et la variable "heuresHorlogeINC" à zero (minuit)
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    REVEIL.adjust(AlarmTime2(heuresAlarmeINC,minutesAlarme));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
} 
 
/***** Fonction d'incrément Alarme 2, Minutes *******/ 
void RegleAlarm2Minutes ()
{ 
  minutesAlarmeINC = minutesAlarme + 1;  // additionne 1 à la valeur contenue dans la variable "minutes" et stocke le résultat dans la variable "minutesHorlogeINC"
  if (minutesAlarmeINC > 59)      // si la valeur de "minutesHorlogeINC" dépasse 59 (59min)
  {
    minutesAlarmeINC = 0;         // alors, met la variable "minutesHorlogeINC" à zero
  }
//    Serial.print(minutesHorlogeINC);
//    Serial.println(); 
    REVEIL.adjust(AlarmTime2(heuresAlarme,minutesAlarmeINC));  // récup des données temporelles depuis les différentes variables pour mise à l'heure la puce DS3231, secondes à zero
}  
  
 
/***** Fonction Surveillance des BoutonAlarme1 et Horloge *******/ 
void SurveilleBouton_Alarme1_Horloge ()
{ 
  EtatBoutonAlarme1 = digitalRead(BoutonAlarme1);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme1"
  EtatBoutonHorloge = digitalRead(BoutonHorloge);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge"

  if ((EtatBoutonAlarme1 == LOW) && (EtatBoutonHorloge == LOW))  // si les boutons sont appuyé
  {
    delay(600);                     // alors, attendre 600 ms, permet un appuie bref pour activer ou désactiver l'alarme1 (radio)

      switch (RADIO.Alarm1Flag())    
     {
       case 0:  //  désactivée     // 0AH = 0xxxxxxx
         RADIO.Alarm1SetON();
         digitalWrite (LedAlarm1, HIGH);
         break;
       case 1:  // alarme activée     
        RADIO.Alarm1SetOFF();
        digitalWrite (LedAlarm1, LOW);     // 0AH = 1xxxxxxx
        break;
     }
  }
}

/***** Fonction Surveillance des BoutonAlarme2 et Horloge *******/ 
void SurveilleBouton_Alarme2_Horloge ()
{ 
  EtatBoutonAlarme2 = digitalRead(BoutonAlarme2);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonAlarme2"
  EtatBoutonHorloge = digitalRead(BoutonHorloge);  // Lit l'état du bouton (appuyé ou relaché) et stocke la valeur dans la variable "EtatBoutonHorloge"

  if ((EtatBoutonAlarme2 == LOW) && (EtatBoutonHorloge == LOW))  // si le bouton est appuyé  
  {
    delay(600);                     // alors, attendre 600 ms, permet un appuie bref pour activer ou désactiver l'alarme2 (sonnerie)

      switch (REVEIL.Alarm2Flag())    
     {
       case 0:  // alarme désactivée     // 0AH = 0xxxxxxx
         REVEIL.Alarm2SetON();
         digitalWrite (LedAlarm2, HIGH);
         break;
  
      case 1:  // alarme activée     
        REVEIL.Alarm2SetOFF();
        digitalWrite (LedAlarm2, LOW);     // 0AH = 1xxxxxxx
        break;
     }
   }
}

/***** Fonction d'envoie d'ordre au GPIO du Rpi *******/ 
void RadioON()
{
  if (RADIO.Alarm1Status()==1)
  {
 //   digitalWrite(relais, HIGH);  # fait now par le RPI lui meme
    digitalWrite(Radio, LOW);
    delay(300);   // appuie bref
    digitalWrite(Radio, HIGH);
  //  delay(10000);
    change = 1;
  }
}

/***** Fonction d'activation de la sonnerie ChipTune *******/ 
void FaireSonnerSonnerie()
{
  
  if (REVEIL.Alarm2Status()==1)
  {
    digitalWrite(relais, HIGH);   // AmpliAudio alimenté
    delay(500);  // attendre quelques millisec entre chaque bouctle de sonnerie
    switch (song) {
    case 1:    // A-Team
      sonnerie(songA);
 //     song = song + 1;
      break;
    case 2:    // Hallowee
      sonnerie(songB);
 //     song = song + 1;
      break;
    case 3:    // Muppets
      sonnerie(songC);
 //     song = song + 1;
      break;
    case 4:    // TakeOnMe
      sonnerie(songD);
 //     song = song + 1;
      break;
    case 5:    // Gadget
      sonnerie(songE);
 //     song = song + 1;
      break;
   case 6:    // MahnaMahna
      sonnerie(songF);
 //     song = 1;
      break; 
   default: // cas par défaut 
      sonnerie(songA);
      break;     */
    }
  }
}

/***** Fonction pour stopper la sonneie  *******/ 
void stop2 ()  //appelée directement via l'interruption 0 lorsqu'on appuie sur le bouton alarm2
{
  change = 1;
  digitalWrite(relais, LOW);  // coupe l'alimentation de l'AmpliAudio
  // Serial.print(change); //
}

/***** Fonction d'ajustement de la luminosité via la photodiode *******/ 
void AjusteLuminosite()
{
  ValeurPhotoDiode = analogRead(photodiodepin);  // Lit la valeur renvoyée par la photodiode, et stocke la valeur dans la variable "ValeurPhotoDiode"
  if (ValeurPhotoDiode > 495)       // si la valeur est supérieure à 495 (beaucoup de lumière reçue, genre en plein jour)
  {
     analogWrite(ledPin, 255);      // alors, illumination des afficheurs et leds à 100% (PWM de 0 à 255)
  }
  else if (ValeurPhotoDiode > 462)  // sinon, si la valeur est supérieure à 462
  {
    analogWrite(ledPin, 238);       // alors, illumination des afficheurs et leds moins forte    
  }
  else if (ValeurPhotoDiode > 429)
  {
    analogWrite(ledPin, 221);
  }
  else if (ValeurPhotoDiode > 396)
  {
    analogWrite(ledPin, 204);
  }
  else if (ValeurPhotoDiode > 363)
  {
    analogWrite(ledPin, 187);
  }
    else if (ValeurPhotoDiode > 330)
  {
    analogWrite(ledPin, 170);
  }
    else if (ValeurPhotoDiode > 297)
  {
    analogWrite(ledPin, 153); 
  }
    else if (ValeurPhotoDiode > 264) 
  {
    analogWrite(ledPin, 136);
  }
    else if (ValeurPhotoDiode > 231)
  {
    analogWrite(ledPin, 119);
  }
    else if (ValeurPhotoDiode > 198)
  {
    analogWrite(ledPin, 102);
  }
    else if (ValeurPhotoDiode > 165)
  {
    analogWrite(ledPin, 85); 
  }
    else if (ValeurPhotoDiode > 132)
  {
    analogWrite(ledPin, 68);
  }
    else if (ValeurPhotoDiode > 99)
  {
    analogWrite(ledPin, 51); 
  }
    else if (ValeurPhotoDiode > 66)
  {
    analogWrite(ledPin, 34);
  }
    else if (ValeurPhotoDiode > 33)
  {
    analogWrite(ledPin, 17); 
  }
  else                             // sinon,  (très peu voire pas du tout de lumière reçue, genre dans la nuit)
  {
    analogWrite(ledPin, 8);        // alors, illumination des afficheurs et leds aux minimum 8
  } 
}

/***** Fonction Sonnerie *****/
void sonnerie(char *p)
{
  // Absolutely no error checking in here

  byte default_dur = 4;
  byte default_oct = 6;
  int bpm = 63;
  int num;
  long wholenote;
  long duration;
  byte note;
  byte scale;

  // format: d=N,o=N,b=NNN:
  // find the start (skip name, etc)

  while(*p != ':') p++;    // ignore name
  p++;                     // skip ':'

  // get default duration
  if(*p == 'd')
  {
    p++; p++;              // skip "d="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    if(num > 0) default_dur = num;
    p++;                   // skip comma
  }

//  Serial.print("ddur: "); Serial.println(default_dur, 10);

  // get default octave
  if(*p == 'o')
  {
    p++; p++;              // skip "o="
    num = *p++ - '0';
    if(num >= 3 && num <=7) default_oct = num;
    p++;                   // skip comma
  }

//  Serial.print("doct: "); Serial.println(default_oct, 10);

  // get BPM
  if(*p == 'b')
  {
    p++; p++;              // skip "b="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    bpm = num;
    p++;                   // skip colon
  }

//  Serial.print("bpm: "); Serial.println(bpm, 10);

  // BPM usually expresses the number of quarter notes per minute
  wholenote = (60 * 1000L / bpm) * 4;  // this is the time for whole note (in milliseconds)

//  Serial.print("wn: "); Serial.println(wholenote, 10);


  // now begin note loop
  while(*p)
  {
    // first, get note duration, if available
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    
    if(num) duration = wholenote / num;
    else duration = wholenote / default_dur;  // we will need to check if we are a dotted note after

    // now get the note
    note = 0;

    switch(*p)
    {
      case 'c':
        note = 1;
        break;
      case 'd':
        note = 3;
        break;
      case 'e':
        note = 5;
        break;
      case 'f':
        note = 6;
        break;
      case 'g':
        note = 8;
        break;
      case 'a':
        note = 10;
        break;
      case 'b':
        note = 12;
        break;
      case 'p':
      default:
        note = 0;
    }
    p++;

    // now, get optional '#' sharp
    if(*p == '#')
    {
      note++;
      p++;
    }

    // now, get optional '.' dotted note
    if(*p == '.')
    {
      duration += duration/2;
      p++;
    }
  
    // now, get scale
    if(isdigit(*p))
    {
      scale = *p - '0';
      p++;
    }
    else
    {
      scale = default_oct;
    }

    scale += OCTAVE_OFFSET;

    if(*p == ',')
      p++;       // skip comma for next note (or we may be at the end)

    // now play the note

    if(note)
    {
//      Serial.print("Playing: ");
//      Serial.print(scale, 10); Serial.print(' ');
//      Serial.print(note, 10); Serial.print(" (");
//      Serial.print(notes[(scale - 4) * 12 + note], 10);
//      Serial.print(") ");
//      Serial.println(duration, 10);
      tone1.play(notes[(scale - 4) * 12 + note]);
      delay(duration);
      tone1.stop();
    }
    else
    {
//      Serial.print("Pausing: ");
//      Serial.println(duration, 10);
      delay(duration);
    }
  }
}
  • Pour faire l'interface entre l'horloge et la radio, les signaux de commande de l'Arduino opérants en 5 Volts et ceux du Raspberry en 3 Volts, il manque ici une carte d'interface. Elle sera étudié au prochain billet sur le sujet.

Mode l'emploi de l'horloge :

De gauche à droite, les boutons : [Alarme 2] [Alarme 1] [Horloge] [Heures] [Minutes]

  • Pour régler l'heure :

Appuyer (bref ou long) sur [Horloge] + [Heures] , et sur [Horloge] + [Minutes]

  • Pour régler l'alarme 1 :

Appuyer (bref ou long) sur [Alarme 1] + [Heures] , et sur [Alarme 1] + [Minutes]

  • Pour régler l'alarme 2 :

Appuyer (bref ou long) sur [Alarme 2] + [Heures] , et sur [Alarme 2] + [Minutes]

  • Pour afficher l'alarme 1 :

Appuyer (bref) sur [Alarme 1]

  • Pour afficher l'alarme 2 :

Appuyer (bref) sur [Alarme 2]

  • Pour stopper la sonnerie :

Appuyer (bref) sur [Alarme 2]


À suivre…

Jeudi, février 1 2018

Assurance véhicule temporaire

L’assurance véhicule temporaire est un service destiné aux usagers voulant couvrir leurs biens en ayant des garanties en totale adéquation avec leurs besoins réels et immédiats, sans s’engager dans un contrat sur une longue durée ou avec des conditions peu flexibles. L’assurance véhicule temporaire est une couverture limitée dans le temps, portant sur un maximum de garantie, dépendamment de votre choix de couverture et d’options, et dont les conditions d’adhésion sont soupes, négociables, libres et facilitées. Souvent destinés aux conducteurs pas ou peu couverts, qui ne souhaitent pas s’engager sur une longue durée, elle s’adresse à tous conducteurs ayant un bien peu utilisé, immobilisé ou récemment acquis et qui a besoin d’une garantie pour une raison réelle et ponctuelle ( déménagement, export, compétition,…). Toutes sortes de motifs peuvent amener le futur souscripteur à préférer cette option.

Choisir l’offre d’assurance véhicule temporaire qui convient

Avant de choisir une compagnie d’assurance temporaire, il faut avoir faits des comparaisons afin de s’assurer de l’adéquation des services proposés, à ceux dont vous avez réellement besoin. Quelques étapes de base sont alors à respecter. En premier lieu, la prospection qui vous permet de comprendre les services, conditions et garanties que propose chaque compagnie d’assurances. La prospection permet au futur souscripteur de comparer et de décider en toute conscience de la meilleure offre à prendre. Ensuite, une demande de devis devra être faite aux différentes compagnies. Il est possible de demander un devis en ligne aux assureurs, compte tenu de vos besoins de couverture et de leurs conditions de calculs de couts et facteurs-risque qui dépendent notamment du véhicule (état, ancienneté, kilométrage) et du conducteur (ancienneté du permis, statistiques de conduite, objectif de la souscription). Là encore, une comparaison des différentes offres d’assurance est nécessaire. Enfin, comparer les offres vous assurera de faire le bon choix quant tenu des risques encourus. Il est à savoir qu’une partie du contrat est négociable, et cela grâce notamment à l’étape préalable de prospection que vous avez faite, qui vous aidera à faire jouer la carte de la concurrence auprès de la compagnie choisie. Dépendamment du pouvoir de négociation de chaque partie, il est possible d’obtenir rabais ou services optionnels dans le contrat. Comme ici

Les garanties de couverture assurance

L’assurance véhicule temporaire couvre obligatoirement par la responsabilité civile du conducteur/souscripteur. En cas d’accidents ou de sinistres, l’assurance couvre la responsabilité des dommages causés aux tiers. Elle n’est, en effet, effective que si le véhicule (s’il a été prêté) a été confié à un particulier connaissant personnellement le propriétaire du véhicule. Dans ce cas, l’assurance véhicule temporaire couvre les dommages corporels et matériels liés à la responsabilité civile, la défense et le recours, ainsi que la franchise.

Point sur l’assurance véhicule temporaire

L’assurance véhicule temporaire fait partie des offres-assureurs proposées notamment en service en ligne. Cette dernière a pour vocation d’offrir un service convenant aux clients, tout en essayant de trouver les intérêts communs des deux parties. Elle vise à couvrir des biens et personnes ayant un besoin immédiat et/ou urgent d’un service de couverture adéquat et adapté (voir personnalisé) sur le court terme à raison d’un maximum de 90 jours. La souscription d’une assurance véhicule temporaire peut être renouvelée sans conditions de durée ni de fréquence et peut être complétée par un contrat d’assurance auto classique. Les offres d’assurance véhicule temporaire ont leur place sur le marché tout d’abord car elles donnent l’occasion aux assureurs de cibler une population peu disponible et peu encline à investir par manque de besoins, de budget ou d’intérêts ; et d’un autre côté, l’offre d’assurance véhicule temporaire offre à cette même population, une couverture adaptée à leurs besoins et attente. De plus, l’assurance véhicule temporaire est renouvelable en ligne, autant de fois que besoin. Les garanties de couverture de l’assurance véhicule temporaire se rapprochent de celle du contrat classique, compte tenu de la durée et des besoins réels de couverture. Cette offre provisoire permet aux souscripteurs non-assurés d’obtenir certaines garanties de couverture accordées à leurs besoins. Grâce à ce type de démarche, les plus réticents à la souscription pourront faciliter leurs démarches de décision, pour une offre convenante et sans inconvénients majeurs. Les conditions de souscription ont été réadaptées, de même que les offres de service.

Lundi, janvier 22 2018

Des bricoles en 3D réelle -8-

Ce billet fait suite à cet autre, voici mes dernières impressions 3D :

Clitoris.
dsc02791.jpg dsc02789.jpg
À télécharger ici : https://www.thingiverse.com/thing:2403536

Boite pour les Dépliants antisexiste de mamanrodarde.
dsc03442.jpg dsc03443.jpg dsc03441.jpg
À télécharger ici : https://www.thingiverse.com/thing:2668519

Raspberry Pi 2/B+ Case with Jack and Switch Power.
Pratique pour ton Kodi Media Center ^^.
20171226_164701.jpg 20171226_125226.jpg 20171226_164215.jpg 20171226_124945.jpg
À télécharger ici : https://www.thingiverse.com/thing:2730874

3 USB Clips.
dsc03042.jpg dsc03043.jpg dsc03033.jpg
dsc03035.jpg dsc03036.jpg dsc03038.jpg dsc03040.jpg
À télécharger ici : https://www.thingiverse.com/thing:2580693

SQ-9 Camera glasses clip + Standard spare clip.
dsc03370.jpg dsc03372.jpg dsc03374.jpg
dsc03375.jpg dsc03376.jpg dsc03377.jpg dsc03383.jpg
À télécharger ici : https://www.thingiverse.com/thing:2759006

- page 2 de 98 -