Aller au contenu

Connecter un Arduino Uno à un Nas Synology par usb


aladec

Messages recommandés

Bonjour,

Pour éviter une perte de temps en recherche sur la façon de connecter un Arduino Uno à un Nas Synology, voici la façon de procéder :

Testé sur un Nas Synology (DS115j - DSM 6.0.2-8451 Update 5 - le 11/12/2016) et un Arduino Uno R3

L'Arduino Uno est considéré comme un périphérique ttyACM.
Sur le Nas, il est nécessaire de créer un nœud et de charger en mémoire un module (cdc-acm.ko présent dans /lib/modules).
On se connecte en ssh (via Putty.exe sous Windows 10) en tant qu'administrateur et on passe en Root via sudo -i.
On charge le module en mémoire par la commande

insmod /lib/modules/cdc-acm.ko

On crée le nœud par la commande

mknod /dev/ttyACM0 C 166 0

On vérifie que le module est bien en mémoire par la commande

lsmod

Pour communiquer via la connexion usb (une communication série), on doit mettre en place un script bash ou un script Python qui permettra de lire et de transmettre (écrire)  les données sur ce port.

Avant de passer à cette étape, il est nécessaire d'automatiser le chargement en mémoire du module cdc-acm.ko et de vérifier si le nœud /dev/ttyACM0 existe.
On réalise donc un script bash qui sera exécuté lors du boot du Nas. (je ne suis pas l'auteur de ce script, j'ai réalisé quelques adaptations mineures).
Il est nécessaire de créer un dossier /volume1/logs pour le fichier modules.log.
Le nom du script S50modules.sh avec le paramètre start ou stop est à enregistrer dans un dossier prévu à cet effet.
Il ne faut pas oublier de donner les droits d'exécution à ce script.
Pour l'exécuter lors du boot, on place dans le fichier /etc/rc.local une ligne de commande qui pointe vers ce script.
Il vaut mieux de placer cette ligne avec une certaine priorité par rapport à d'autres lignes présentent dans ce fichier.

sh [chemin vers ce script]/S50modules.sh start

Code du script S50modules.sh :

#!/bin/sh
MODULES_DIR="/lib/modules"
MAINMODULE="cdc-acm.ko"
heure=$(date +%Hh-%Mmin)
jour=$(date +%d-%m-%Y)
start_modules(){
        echo "--- Charge le module en mémoire ---"
        echo "Le module cdc-acm.ko est chargé à $heure, le $jour" >> "/volume1/logs/module.log"
  for i in $MAINMODULE; do
                echo "Chargement de $i"
                insmod $MODULES_DIR/$i
        done
        sleep 1
        # Create the ttyACM0
        if [ ! -c /dev/ttyACM0 ]; then
    echo "Création de /dev/ttyACM0"
                echo "Le noeud /dev/ttyACM0 est créé à $heure, le $jour" >> "/volume1/logs/module.log"
    mknod /dev/ttyACM0 c 166 0
        fi
        sleep 1
 stty -F /dev/ttyACM0 cs8 115200 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
 sleep 1
}
stop_modules(){
        echo "--- Décharge le module de la mémoire ---"
        echo "Le module cdc-acm.ko est déchargé à $heure, le $jour" >> "/volume1/logs/module.log"
  for i in $MAINMODULE; do
                echo "Décharge $i"
                rmmod $MODULES_DIR/$i
        done
  # supprime le ttyACM0
        if [ -c /dev/ttyACM0 ]; then
                echo "Le noeud /dev/ttyACM0 est supprimé à $heure, le $jour" >> "/volume1/logs/module.log"
    echo "/dev/ttyACM0 est supprimé"
    rm /dev/ttyACM0    
        fi
        sleep 1
}
case ${1:-start} in
start)
        start_modules
        ;;
stop)
        stop_modules
        ;;
*)
        echo "usage: $0 { start | stop }" >&2
        exit 1
        ;;
esac
 
La suite consiste à tester la communication entre un script sur l'Arduino et un script sur le Nas.
On aura besoin de remplacer le Nas par un pc tournant sous Linux et de connecter l'Arduino Uno à cette machine via ttyACM afin de procéder au développement des scripts.
En effet, le Nas est considéré comme une machine de production et on ne dispose pas de l'IDE Arduino qui permet la réalisation des sketchs (scripts).
Lorsque les tests seront concluants, on migrera les scripts vers le Nas.
 
Pour ma part, j'utilise une version Ubuntu 16.04 LTS, présente sur un disque usb. L'avantage est de disposer du paquet Arduino qu'il suffit d'installer via un terminal.
sudo apt-get install arduino
On dispose alors de l'IDE Arduino qui permet la réalisation des sketchs. Avant la 1ère utilisation, un reboot est nécessaire pour la mise en place.
L'Arduino Uno est connecté sur un port usb (en ttyACM0). Le module cdc_acm est chargé automatiquement en mémoire sur Ubuntu. Pour vérifier :
lsmod | grep cdc_acm
Au niveau des scripts qui seront placés sur le Nas, il faut choisir entre Bash et Python afin de gérer les données sur le /dev/ttyACM0.
Sur le Nas, il est possible d'installer le paquet Python 2.7.12. Sur le pc Ubuntu, on dispose aussi de la version Python 2.7.12 .
Je choisis donc Python bien que je sois un néophyte de ce langage. Les scripts seront simples à développer.
 
A partir du moment où on sait gérer les communications entre l'Arduino Uno et le Nas via le port usb (port série), plusieurs projets seront possibles éventuellement en domotique.
L'inconvénient est la distance entre le Nas et l'Arduino Uno qui dépend de la longueur du câble usb. L'Arduino Uno est également alimenté via cette liaison (une autre possibilité existe).
 
Exemple : l'Arduino Uno servira d'interface entre mon système d'alarme et les caméras de surveillance gérées via Surveillance Station présent sur le Nas.
J'ai déjà réalisé ce projet mais en utilisant un Arduino Yun doté d'une liaison Ethernet qui communique via le réseau interne avec le Nas (protocole TCP/IP).
Je trouve dommage d'utiliser un Arduino Yun pour ce genre de projet, de plus le Yun est connecté au Nas par usb afin d'être alimenté.
Je vais donc tenter de remplacer le Yun par le Uno (3 x moins cher) et communiquer via la connexion usb.
 
Réalisation du script Python chargé sur le Nas et responsable de la gestion des données envoyées par l'Arduino sur le port usb (série) :
Avant de programmer, on récupère la librairie "pyserial-master.zip". Cette archive est décompressée dans un dossier du Nas prévu dans /volume1 (on peut le faire sous Windows).
On se connecte au Syno en ssh via Putty.exe et on installe cette librairie qui permettra de gérer le port usb du Nas.
Pour l'installation, on se déplace dans le dossier "pyserial-master" et on exécute le fichier "setup.py" par la commande
python setup.py install  - (la librairie est alors disponible pour Python 2.7.12)
Le script devra réagir en fonction des données en provenance de l'Arduino Uno.
Il y aura 5 données possibles '0', '1', '2', '3' ou '' (vide - pas de donnée). Chaque donnée correspond à une action précise exécutée par un script Bash (déjà opérationnel).
 
Voici le code (attention aux indentations ! Python oblige ...) :
 

#!/usr/bin/env python
# -*-coding:UTF-8 -*
import subprocess
import serial
import time
import serial.tools.list_ports
import sys
import os

################# Les fonctions ###################################################
def serial_ports(vid_pid):
 # recherche du port sur lequel se trouve Arduino Uno identifié par son VID:PID
 portList = list(serial.tools.list_ports.comports())
 for info in portList:
  #print(info[2])
  if (vid_pid in info[2]):
   #print(info[2])
   #print "retourne : " + info[0]
   return info[0]
 return False
 
def verif_connexion(device):
 #verification du port de connexion avec Arduino
 try:
  print "Tentative de connexion à ..." + device
  arduino_usb = serial.Serial(device, 9600,timeout=None) # attention aux réglages avec l'Arduino ! Le timeout=None est obligatoire pour rester à l'écoute sur le port
  print "La connexion est établie avec " + arduino_usb.name
  #print arduino_usb
  return(arduino_usb)
 except:
  print "La connexion a échoué sur " + device
  return False
 
def connexion_usb(arduino_usb,boo_shell):
 
 chemin_bash="" # variable à introduire !!!
 
 while (True):
  
   print "En attente ..."
   arduino_usb.inWaiting()  # s'utilise si le timeout=None !!! - écoute infinie sur le port usb en attente de données reçues
   reception = arduino_usb.read(size=1)
   print "Réception de : '" + reception +"'"
 
   if (reception == '0'):
    print "L'Arduino demande un arrêt des caméras"
    subprocess.call(chemin_bash, shell=boo_shell)
    info_cameras = "Les caméras sont arrêtées"
   
   if (reception == '1'):
    print "L'Arduino demande un démarrage des caméras"
    subprocess.call(chemin_bash, shell=boo_shell)
    info_cameras = "Les caméras sont activées"
  
   if (reception == '2'):
    print "L'Arduino a détecté un déclenchement d'alarme"
    subprocess.call(chemin_bash, shell=boo_shell)
    info_cameras = "Le signal d'alarme est déclenché"
  
   if (reception == '3'):
    print "L'Arduino demande une vérification des enregistrements vidéos"
    subprocess.call(chemin_bash, shell=boo_shell)
    info_cameras = "Vérification des enregistrements vidéos"
  
   # renvoi vers arduino
   print "Le Syno envoie '"+reception+"'"
   arduino_usb.write(reception)
   print info_cameras
   time.sleep(2)
   arduino_usb.flushInput()
   arduino_usb.flushOutput()   
 
 print "Reprise de l'écoute sur " + arduino_usb.name
 return

###########################################################################################
#                      Ossature du script - boucle principale de lancement                #
###########################################################################################
if __name__ == '__main__':
 # Introduire la valeur du VID:PID de l'Arduino (commande lsusb pour l'obtenir) 
 # Attention à la casse, les lettres doivent être en majuscules !!!

 vid_pid="VID:PID=....:...." # variable à introduire  !!!
 

# enregistre le pid de ce processus dans un fichier afin de pouvoir l'arrêter
 #print os.getpid()
 chemin="" # variable à introduire !!!
 fichier_pid=open(chemin+"arduino_usb.pid","w")
 fichier_pid.write(str(os.getpid()))
 fichier_pid.close()

 tentative=1

 while True:
  print "Récupération des données en provenance de l'Arduino avec " + vid_pid
  if (serial_ports(vid_pid) != False):
   device = serial_ports(vid_pid)
   connecte=True
  else:
   connecte=False
   if (tentative > 5):
    print "Le nombre de tentatives est dépassé - FIN"
    sys.exit(0)
   
   print "L'Arduino n'est pas connecté !"
   print str(tentative) + " - Tentative de reconnection dans 30 secondes (maximum de tentatives = 5)"
   time.sleep(30)
   tentative+=1
 
  while connecte:
   try:
    if (verif_connexion(device).is_open == True):
     connexion_usb(verif_connexion(device), True)
   
   except:
    print "connexion interrompue"
    print "Attente de 5 secondes avant de reprendre l'écoute sur le port"
    time.sleep(5)
    tentative=1
    connecte=False
   
# nom du script : "arduino_usb.py" (se lance en tâche de fond comme un service via "script bash start/stop à réaliser !")
sys.exit(0)

 
Remarques :
Le script est enregistré sous le nom "arduino_usb.py" et se lance (pour les tests)  via une session Putty.exe sous Windows, par la commande 
python usb_arduino.py
Il tourne dans une boucle infinie et lors d'une déconnexion de l'Arduino, il tente de se reconnecter, après 5 tentatives espacées de 30 secondes, il s'arrête.
Il serait également nécessaire de vérifier si le périphérique connecté est bien l'Arduino Uno. (On utilise le VID:PID de l'Arduino)
En utilisation réelle (après les tests), il faudra démarrer ce script au boot du Syno.(On peut tester avec le planificateur de tâches du Syno - exécuter "à la main" le script)
 
Réalisation du sketch à placer sur l'Arduino Uno pour tester la connexion avec le Syno.
La fonction suivante est à placer dans le sketch afin de se connecter
 
// fonction appelée pour connexion au syno, renvoie true si la connexion est ok
// la variable cas peut prendre les valeurs '0', '1', '2' ou '3'
boolean connexion_syno(char cas)
{
  boolean reponse = true;
  while(reponse)
  {
    Serial.print(cas);// écrit la valeur de cas sur le port série (usb)
    delay(1000);// attente 1 seconde
 
    // attente de la réponse du Syno :
    // vérifie si présence dans le tampon série
    if (Serial.available() > 0)
    {
      if (Serial.read() == cas) // réponse du syno qui renvoi la valeur de cas
      {
        reponse=false;// passe à false pour sortir de la boucle while
      }
    }
  }
  return true;// renvoi true
}
 
L'appel de cette fonction s'effectue dans la boucle principale void loop() par
if (connexion_syno('3') == true) // ici cas='3'
        {
            ......
        }
 
Il s'agit ici d'un exemple où l'Arduino Uno pilote le Syno via une connexion usb (série). On peut évidemment envisager l'inverse. 
 
Après quelques tests (Arduino connecté au Syno par usb) sur la durée, j'ai remarqué une demande intempestive du démarrage des caméras.
Cela provient certainement d'une certaine instabilité de la connexion, il suffit de recevoir '1' pour démarrer.
J'ai donc modifié les 2 scripts de gestion sur le Syno et l'Arduino afin d'envoyer des chaînes de commande entre les 2 machines.
Actuellement (30/12/2016), je suis en période de test.

 

 

Modifié par aladec
ajout
Lien vers le commentaire
Partager sur d’autres sites

  • 6 ans après...

 La dernière 6.2: DSM 6.2.4-25556 Update 6 

Pour commencer je fais uniquement: insmod /lib/modules/cdc-acm.ko et mknod /dev/ttyACM0 c 166 0

Normalement ca doit suffire pour faire un "cat /dev/ttyACM0" (ca marche sur un raspberry PI)

mais ca donne ttyACM0: No such file or directory

 

 

 

Lien vers le commentaire
Partager sur d’autres sites

avec sudo dmesg -T j'ai

[Mon Jan  9 07:14:13 2023] usb 3-1: USB disconnect, device number 3
[Mon Jan  9 07:14:17 2023] usb 3-1: new full-speed USB device number 4 using xhci-hcd

Ca veut dire qu'il utilise sttUSB4 ?? avec le module xhci-hcd ? Ca ne devrait  pas être  ftdi_sio ? 

xhci-hcd c'est pour du high speed ?

Quand j'essaye d'ajouter ftdi_sio.ko j'ai des erreurs

[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_handle_sysrq_char (err 0)
[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_generic_open (err 0)
[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_deregister_drivers (err 0)
[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_generic_unthrottle (err 0)
[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_handle_break (err 0)
[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_generic_get_icount (err 0)
[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_generic_tiocmiwait (err 0)
[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_generic_throttle (err 0)
[Mon Jan  9 07:27:47 2023] ftdi_sio: Unknown symbol usb_serial_register_drivers (err 0)

 

J'utilise  la commande "mknod /dev/ttyUSB4 c 188 0"  pour ajouter ttyUSB4

Est ce que je peux utiliser xhci-hcd  en changeant la commande "mknod /dev/ttyUSB4 c 188 0 " ( par quoi ?)

 

J'espère que quelqu'un pourra m'aider 

Merci

 

Lien vers le commentaire
Partager sur d’autres sites

Voila, finalement ca marche

Pour info, ca intéressera peut être quelqu'un.

1-   il faut installer le paquet "SynoKernel USB Seriel drivers" pour récupéré le driver ch341.ko en fonction du CPU (voir centre info dans le panneau de configuration)

Apres l'intall il est dans  /volume1/@appstore/synokernel-usbserial/lib/modules/......

le copier dans /lib/modules

2-  passer les commandes suivantes dans cet ordre

sudo insmod /lib/modules/usbserial.ko
sudo insmod /lib/modules/ch341.ko 
sudo insmod /lib/modules/ftdi_sio.ko

 

3- l'Arduino apparait  comme /dev/ttyUSB0

il n'est pas nécessaire de faire: mknod /dev/ttyUSB0 c 188 0

 

 

Lien vers le commentaire
Partager sur d’autres sites

  • 8 mois après...

Bonjour,

Je redécouvre ce sujet que j'avais publié en 2016.
Merci à Chegui pour les avancées concernant la recherche des modules de connexion usb pour un Arduino Uno.
J'utilise toujours le système entre un Syno et le Uno. Avec toutes les mises à jour sur le Syno (passage à Python 3), j'ai été obligé de rénover mes scripts.
Je compte les publier dès que j'ai le temps.

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

Tout simplement parce que je dispose d'un Arduino Uno et que le but de ce post est de connecter un Uno au Syno par usb.

Le Uno sert donc d'interface entre un signal d'alarme et l'activation des caméras de surveillance gérées sur le Syno par SurveillanceStation.
Le Uno est connecté à 3 diodes led pour surveiller les différents états possibles, un interrupteur simple pour activer ou désactiver les caméras et un relais qui se ferme ou s'ouvre en fonction du branchement de l'alarme.
Trois caméras sont gérées par SurveillanceStation, 3 caméras sont gérées directement par le script python et 1 caméra est gérée par ZoneMinder installé sur un Raspberry Pi 3 B. Le script Python qui réceptionne les commandes du Uno, gère donc l'activation de 7 caméras.

Exemple de script en Python 3 de gestion des caméras (activer ou désactiver) 1 ou plusieurs caméras du Syno en fonction de la documentation de l'API SurveillanceStation version 9 avec DSM version 7.

 

#!/usr/bin/env python

import requests
from urllib3.exceptions import InsecureRequestWarning

IP_nas =  '###.###.###.###'
PORT_nas = '####'
dsm_url = 'https://'+IP_nas+':'+PORT_nas
username = '##########'
password = '##########'
num_camera = '#' # séparer par , si plusieurs caméras à activer ou désactiver

# désactive warning pour certificat en https 
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

params={"api":"SYNO.API.Auth","method":"login","version":"6","account":username,"passwd":password,"session":"SurveillanceStation","format":"sid"}
rep=requests.get(dsm_url+"/webapi/auth.cgi",params=params,verify=False)
obj=rep.json()
#print (obj)
sid = obj['data']['sid']
#print(sid)
succes=obj['success']
#print (succes)
if succes==True:
    print ("Entrée en session acceptée")
else:
    print ("Entrée en session refusée")

# active/désactive caméra  "method":"Enable" ou "method":"Disable"
# il est parfois nécessaire de changer la valeur de "version" en fonction de la documentation de l'API
params={"api":"SYNO.SurveillanceStation.Camera","method":"Disable","version":"9","idList":num_camera,"_sid":sid}
rep=requests.get(dsm_url+"/webapi/entry.cgi",params=params,verify=False)
obj=rep.json()
succes=obj['success']
#print (succes)
if succes==True:
    print ("Caméra "+num_camera+" désactivée(s)")
else:
    print ("Caméra "+num_camera+" impossible à désactiver")

#Infos
params={"api":"SYNO.SurveillanceStation.Info","method":"GetInfo","version":"7"}
rep=requests.get(dsm_url+"/webapi/entry.cgi",params=params,verify=False)
obj=rep.json()
print (obj)

#fin de session
params={"api":"SYNO.API.Auth","method":"logout","version":"2","session":"SurveillanceStation","_sid":sid}
rep=requests.get(dsm_url+"/webapi/auth.cgi",params=params,verify=False)
obj=rep.json()
succes=obj['success']
#print (obj)
if succes==True:
    print ("Fin de session")
else:
    print ("Fin de session impossible")

 

Modifié par aladec
Lien vers le commentaire
Partager sur d’autres sites

Rejoindre la conversation

Vous pouvez publier maintenant et vous inscrire plus tard. Si vous avez un compte, connectez-vous maintenant pour publier avec votre compte.

Invité
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer.