www.ghislain.fr

Kit Velleman K5056 en IP

Objectif :

 

  • Gestion d'équipements divers :
  •  - Reboot Freebox.
  •  - Ouverture Porte de garage.
  •  - Allumage projecteurs extérieurs.
  •  
Materiel :

 

1 kit Velleman k8056

 

Problématique :

 

Je dispose de 2 machines. L'une sous OpenBSD gère la sécurité du réseaux grâce à Packet Filter, et héberge les interfaces Web.

L'autre gére le réseau 1-wire, et la carte k8056 via le port série.

 

L'idée étant d'envoyer les commandes de gestions de la k8056 via le web, vers le serveur domotique.

 

J'ai donc repris les sources linux, et je les aient adaptées afin de créer un client server.

Au passage, j'ai ajouté la fonction de log pour le serveur, et activé la fonction pulse (non documentée).

 

Sources :

 

Client : 

 

 
/* K8056 Client By FG 2011 v1.3c*/
/* Lecture des parametres
Usage k8056net [-i IP] [-p PORT] [-h] [-v] [-V] [-a card_address] [-S|-C|-P|-T relay#] [-B relay_status] [-A new_address] [-E|-D|-F]
parametres emis:
- instuction (A.B.C.E.D.F.S.T.P.)
- relais (1..8)
 
recupere parametre
convertion parametre
transmission vers adresse et port
sortie*/
// Includes
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdio.h>  /* Standard input/output definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <string.h>  /* String function definitions */
#include <math.h>
#include <fcntl.h>
#include <errno.h>   /* Error number definitions */
 
// define
#define MSGSIZE 500
// Variables
struct  termios oldtio, newtio ;
unsigned char  k8056_instruction = 'E';
unsigned char  k8056_addr = 1 ;
unsigned char k8056_relay_address = '0'  ;
int  k8056_trame_number = 5 ;  /*  Increase value with a long serial cable or in wireless operation. */
int  verbose = 0 ;
int  debug = 0 ;
char  cmd[6] ;
int  Taillecmd ;
u_short portnum = 12345;
char *msg, *htoname = "192.168.0.1";
 
/*------------------------------------------------------------------------------*/
/*  Fonctions Usage et Aides                                                    */
/*------------------------------------------------------------------------------*/
void usage (void) {
printf("\nk8056    Usage k8056net [-i IP] [-p PORT] [-h] [-v] [-V] [-a card_address] [-S|-C|-P|-T relay#] [-B relay_status] [-A new_address] [-E|-D|-F]\n");
printf("      Pour plus de details utiliser l'aide: k8056 -h\n\n");
printf("      Version 1.3c\n\n");
}
void help (void) {
printf("\nk8056  est un programme qui controle la carte 'Velleman K8056' via udp (Version Francaise par FOURNIER Ghislain - 2011 \n\n");
printf("Usage k8056net [-i IP] [-p PORT] [-h] [-v] [-V] [-a card_address] [-S|-C|-T relay#] [-B relay_status] [-A new_address] [-E|-D|-F]\n\n");
printf("      Version 1.3c\n\n");
printf("        -h                : Aide\n");
printf("        -v                : Mode verbeux\n");
printf("        -V                : Debug\n");
printf("        -i addresse IP    : Adresse IP du serveur\n");
printf("        -p port           : Port UDP, par defaut 180472 \n");
printf("        -a addresse_carte : Adresse de la carte (1..255) en decimal\n");
printf("        -S|-C|-P|-T relay# : Instructions to Active/Relache/Impulsion/Basculer le relais numero ('1'..'9')\n");
printf("        -A new_address    : Regler la nouvelle adresse de la carte (1..255)\n");
printf("        -B status_relais  : Reglez le relais huit avec octet status_relais (1..255)\n");
printf("        -E|-D|-F          : Stop d'Urgence / Afficher l'adresse / Forcer l'adresse à \n\n");
printf(" ** Command examples **\n");
printf("        k8056 -i 192.168.0.1 -v -E       : Arrêd'urgence toutes les cartes relais (mode verbeux).\n");
printf("        k8056 -i 192.168.0.1 -v -S6      : Active relais #6 (mode verbeux).\n");
printf("        k8056 -i 192.168.0.1 -v -C5      : Relache relais #5 (mode verbeux).\n");
printf("        k8056 -i 192.168.0.1 -v -P3      : Impulsion relais #5 (mode verbeux).\n");
printf("        k8056 -i 192.168.0.1 -v -T5      : Basculer le relais#5 => Active relay #5 (mode verbeux).\n");
printf("        k8056 -i 192.168.0.1 -B 127      : Relache relay #1, Active relais #2..8\n");
printf("        k8056 -i 192.168.0.1 -p 1000 -S1 : Active relais #1 sur le port udp 1000.\n\n");
}
/*------------------------------------------------------------------------------*/
/* Parse the command line to find additionnal arguments                         */
/*------------------------------------------------------------------------------*/
char parse_cmdline(int argc,char *argv[]) {
   int helpflg=0;
   int errflg=0;
   int c;
   while ((c = getopt(argc, argv, "S:C:P:T:A:B:a:d:i:p:EDFhvV")) != EOF)
   {
      switch (c)
      {
         case 'S':
         case 'C':
         case 'P':
         case 'T':
   k8056_instruction = c ;
             k8056_relay_address = optarg[0] ;
             break;
         case 'A':
         case 'B':
   k8056_instruction = c ;
             k8056_relay_address = atoi(optarg);
             break;
         case 'E':
         case 'D':
         case 'F':
   k8056_instruction = c ;   /* The 3rd byte = 0 (k8056_relay_address) */
             break;
  case 'a':
             k8056_addr = atoi(optarg);
             break;
  case 'i':
             //strlcpy(htoname, optarg, sizeof(htoname));
  htoname = optarg;
             break;
  case 'p':
                portnum = atoi(optarg);
             break;
         case 'v':
             verbose = 1;
             break;
         case 'V':
             debug = 1;
             break;
         case 'h':
             helpflg++;
          break;
         case '?':
             errflg++;
          break;
      }
        if (helpflg)
 {
           help();
           exit (1);
        }
     }
     if (optind < 2 || errflg)   /* if optind = 1, option missing. */
    {
         usage();
         exit (1);
    }
     return 1;
}
/*------------------------------------------------------------------------------*/
/* MAIN                         */
/*------------------------------------------------------------------------------*/
int main(int argc, char *argv[]) {
  parse_cmdline(argc,argv) ;
   int sockfd, ok, addr_in_size;
  struct sockaddr_in *to;
  struct hostent *toinfo;
  u_long toaddr;
  msg = (char *)malloc(MSGSIZE);
  to = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));
 msg[0] = k8056_instruction ;    /* Instruction    */
 msg[1] = k8056_relay_address ;    /* # relais, address or status  */
  if (verbose) printf("Envoi commande vers la carte k8056:\n Port ip: %u, Addresse ip: %s, Instruction: %c, Relais #%c\n"
  , portnum, htoname, msg[0], msg[1]) ;
  if((toinfo = gethostbyname(htoname)) == NULL){
    fprintf(stderr,"Error %d in gethostbyname: %s\n",
      errno,sys_errlist[errno]);
    exit(errno);
  };
  toaddr = *(u_long *)toinfo->h_addr_list[0];
  addr_in_size = sizeof(struct sockaddr_in);
  memset((char *)to,(char)0,addr_in_size);
  to->sin_family = AF_INET;
  to->sin_addr.s_addr = toaddr;
  to->sin_port = htons(portnum);
  if((sockfd = socket (PF_INET, SOCK_DGRAM, 0)) == -1){
    fprintf(stderr,"Error %d in socket: %s\n",errno,sys_errlist[errno]);
    exit(errno);
  };
    ok = 1;
    if(sendto(sockfd,msg,strlen(msg),0,(struct sockaddr *)to,
        addr_in_size) == -1){
      fprintf(stderr,"Error %d in sendto: %s\n",errno,sys_errlist[errno]);
      exit(errno);
    }
        /* Quitt... */
        exit(0);
}
            /*------------------------------------------------------------------------------*/        
             
 Serveur : 
 

 

 
 /* k8056ned UDP SERVER By FG 2011 v1.3d */
/* Usage : k8056netd [-h] [-v] [-V] [-d device] [-p PORT] */
/* -- Synoptique -- */
/* On Demonize */
/* Ecoute Port */
/* Si données */
/* Appel le fils */
/*  Verification */
/*  Mise en forme */
/*  transmission vers k8056 */
/* tue le fils */
/* retour ecoute */
/* modif 369 et 373 pf_net par af_net + IPPROTO_UDP + verbose dans la console debug dans le syslog */
/*------------------------------------------------------------------------------*/
/*  Includes                                                     */
/*------------------------------------------------------------------------------*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <termios.h>
#include <math.h>
#include <fcntl.h>
#include <pwd.h>
#include <signal.h>
#include <syslog.h>
 

/*------------------------------------------------------------------------------*/
/*  Definitions                                                     */
/*------------------------------------------------------------------------------*/
#define MSGSIZE 2
#define BAUDRATE B2400
#define NPACK 10
/* Change this to whatever your daemon is called */
#define DAEMON_NAME "k8056netd"

 
/* Change this to the user under which to run */
#define RUN_AS_USER "root"
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
/*------------------------------------------------------------------------------*/
/*  Variables                                                       */
/*------------------------------------------------------------------------------*/
struct  termios oldtio, newtio ;
int      k8056_port ;
char  k8056_device[16] = "/dev/k8056" ; /*  default device. */
unsigned char  k8056_instruction = 'E';
unsigned char  k8056_addr = 1 ;
unsigned char k8056_relay_address = '0'  ;
int  k8056_trame_number = 5 ;  /* Increase value with a long serial cable or in wireless operation. */
int  verbose = 0 ;
int  debug = 0 ;
char   cmd[6] ;
int  Taillecmd ;
int sockfd, cc;
unsigned int addr_in_size;
u_short portnum = 12345;
struct sockaddr_in *my_addr, *from;
char *msg;
u_long fromaddr;
/*------------------------------------------------------------------------------*/
/*  Affiche l'aide                                                              */
/*------------------------------------------------------------------------------*/
void usage (void) {
 printf("\nk8056ned   Usage:    k8056netd [-h] [-v] [-V] [-d device] [-p PORT] \n");
 printf("      Pour plus de details utiliser l'aide: k8056netd -h\n\n");
printf("      Version 1.3c\n\n");
}
void help (void) {
 printf("\nk8056netd controle la carte 'Velleman K8056' via UDP (Version Francaise par FOURNIER Ghislain - 2011 \n\n");
 printf("Usage:   k8056netd [-h] [-v] [-d device] [-p PORT] \n\n");
 printf("        -h                : Aide\n");
 printf("        -v                : Mode verbeux\n");
 printf("        -V                : Debug\n");
 printf("        -d device         : Rs232 port, par defaut /dev/k8056 (A faire: : ln -s /dev/ttyS0 /dev/k8056 par exemple)\n");
 printf("        -p port           : UDP port, par defaut 180472 \n");
 printf("  ** Command examples **\n");
 printf("  k8056netd -d /dev/ttyS14 -p 1234  : Controle la carte  sur port série /dev/ttyS14, recoie les données sur le port udp 1234.\n\n");
printf("      Version 1.3c\n\n");
}
/*------------------------------------------------------------------------------*/
/*  Ouverture port serie                                               */
/*------------------------------------------------------------------------------*/
void initserie (void) {
 if (verbose) printf("Ouverture du port\n");
 if (debug) syslog( LOG_INFO, "Ouverture du port serie" );
 k8056_port = open(k8056_device, O_RDWR | O_NOCTTY );
 if (k8056_port < 0) {
   if (verbose) { fprintf(stderr, "Erreur d'ouverture du peripherique %s !\n", k8056_device) ; }
  exit(-1);
 }
  tcgetattr(k8056_port,&oldtio);   /* Sauvegarde des parametres courants du port  */
  newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
  newtio.c_oflag = 0;
  tcflush(k8056_port, TCOFLUSH);  /* Flushes written but not transmitted. */
  tcsetattr(k8056_port, TCSANOW, &newtio);
}
 
/*------------------------------------------------------------------------------*/
/* Checksum (complement à 2 de la somme de 4 octets + 1)                        */
/*------------------------------------------------------------------------------*/
unsigned char checksum(char cmd[]) {
        unsigned char checksum ;
        /*  Ex. VB: checksum = ( 255 - ( ( ( (a+b+c+d / 256 ) - Int( (13 + cmd[1] + cmd[2] + cmd[3]) / 256 ) ) * 256 ) ) + 1 ; */
        /* ( 255 - ((a+b+c+d) modulo 256) ) + 1  Calcul de checkum (complement à 2 de la somme de 4 octets + 1).   */
 if (verbose) printf("Calcul Checksum\n");
 checksum = ~((13 + cmd[1] + cmd[2] + cmd[3]) & 0xFF) + 1 ;
        return checksum ;
}
/*------------------------------------------------------------------------------*/
/* SendCommand Send command to k8056 card                                      */
/*------------------------------------------------------------------------------*/
void SendCommand(char cmd[]) {
 if (debug) syslog( LOG_INFO, "Send command to k8056" );
 int i ;
 tcflush(k8056_port, TCOFLUSH) ;  /* Flushes written but not transmitted. */
 for (i=0 ; i < k8056_trame_number ; i++) {
  write(k8056_port, cmd, 5) ;
  if (verbose) printf(". %d \n",i) ;
  if (verbose) {
   printf(" Donnees envoyer = %s \n",cmd) ;
   Taillecmd = strlen (cmd);
   printf(" Taille Donnees  = %d \n",Taillecmd) ;
  }
  if (verbose) printf("Ecriture sur le port\n");
  if (verbose) printf("Pause entre deux Ecriture\n");
  usleep(5000) ;
 }
}
/*------------------------------------------------------------------------------*/
/* Parse de la ligne de commande pour les arguments otionnels               */
/*------------------------------------------------------------------------------*/
char parse_cmdline(int argc,char *argv[]) {
   int helpflg=0;
   int errflg=0;
   int c;
   while ((c = getopt(argc, argv, "d:p:hvV")) != EOF)
   {
      switch (c)
      {
         case 'd':
             strcpy(k8056_device, optarg) ;
             break;
    case 'p':
             portnum = atoi(optarg);
             break;
  case 'v':
             verbose = 1;
             break;
         case 'V':
             debug = 1;
             break;
         case 'h':
             helpflg++;
          break;
         case '?':
             errflg++;
          break;
      }
        if (helpflg) /* Aide */
 {
           help();
           exit (1);
        }
     }
  //if (optind < 2 || errflg)  /* Usage */
  if (errflg)  /* Usage */
    {
         usage();
         exit (1);
    }
     return 1;
}
 
/*------------------------------------------------------------------------------*/
/* Preparation a l'envoi des données                                      */
/*------------------------------------------------------------------------------*/
void sendserie(char msg[])
{
if (verbose) { printf(" Données reçues = %d \n",msg[0]) ; }
if (verbose) { fprintf(stdout,"Réception de %s port %d: %s\n",
      (gethostbyaddr((char *)&fromaddr,
         sizeof(fromaddr),
         PF_INET))->h_name,
       from->sin_port,msg); }
 if (verbose) printf("Envoi commande vers la carte k8056:\n Port: %s, Addresse carte: %d, Instruction: %c, Relais #%c\n"
  , k8056_device, k8056_addr, msg[0], msg[1]) ;
 
 cmd[0] = 13 ;     /* 13          */
 cmd[1] = k8056_addr ;   /* Adresse         */
 cmd[2] = msg[0] ;    /* Instruction        */
 cmd[3] = msg[1] ;    /* # relais, addresse ou status    */
 cmd[4] = checksum(cmd) ;  /* Checksum         */
 if (verbose) printf(" Checksum = %d\n", checksum(cmd)) ;
 SendCommand(cmd) ;
  if (debug) syslog( LOG_INFO, "Send command fait" );
        /* Fermeture port serie */
 tcsetattr(k8056_port, TCSANOW, &oldtio); /* Sauvegarde des anciens parametres du port  */
 if (verbose) printf("Fermeture du port\n");
        close(k8056_port);
 if (verbose) printf("Pause entre deux commandes\n");
 usleep(300000) ;     /* Pause entre 2 commandes. */
     if (verbose) printf("Fait\n");
 if (verbose) printf(".\n");
 
}
/*------------------------------------------------------------------------------*/
/* Gestion des zombies                                                          */
/*------------------------------------------------------------------------------*/
static void child_handler(int signum)
{
    switch(signum) {
    case SIGALRM: exit(EXIT_FAILURE); break;
    case SIGUSR1: exit(EXIT_SUCCESS); break;
    case SIGCHLD: exit(EXIT_FAILURE); break;
    }
}
/*------------------------------------------------------------------------------*/
/* Daemonization                                                                */
/*------------------------------------------------------------------------------*/
static void daemonize( const char *lockfile )
{
    pid_t pid, sid, parent;
    int lfp = -1;
    /* already a daemon */
    if ( getppid() == 1 ) return;
 
    /* Create the lock file as the current user */
    if ( lockfile && lockfile[0] ) {
        lfp = open(lockfile,O_RDWR|O_CREAT,0640);
        if ( lfp < 0 ) {
            syslog( LOG_ERR, "unable to create lock file %s, code=%d (%s)",
                    lockfile, errno, strerror(errno) );
            exit(EXIT_FAILURE);
        }
    }
    /* Drop user if there is one, and we were run as root */
    if ( getuid() == 0 || geteuid() == 0 ) {
        struct passwd *pw = getpwnam(RUN_AS_USER);
        if ( pw ) {
            syslog( LOG_NOTICE, "setting user to " RUN_AS_USER );
            setuid( pw->pw_uid );
        }
    }
    /* Trap signals that we expect to recieve */
    signal(SIGCHLD,child_handler);
    signal(SIGUSR1,child_handler);
    signal(SIGALRM,child_handler);
    /* Fork off the parent process */
    pid = fork();
    if (pid < 0) {
        syslog( LOG_ERR, "unable to fork daemon, code=%d (%s)",
                errno, strerror(errno) );
        exit(EXIT_FAILURE);
    }
    /* If we got a good PID, then we can exit the parent process. */
    if (pid > 0) {
 
        /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
           for two seconds to elapse (SIGALRM).  pause() should not return. */
        alarm(2);
        pause();
        exit(EXIT_FAILURE);
    }
    /* At this point we are executing as the child process */
    parent = getppid();
    /* Cancel certain signals */
    signal(SIGCHLD,SIG_DFL); /* A child process dies */
    signal(SIGTSTP,SIG_IGN); /* Various TTY signals */
    signal(SIGTTOU,SIG_IGN);
    signal(SIGTTIN,SIG_IGN);
    signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */
    signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */
 
    /* Change the file mode mask */
    umask(0222);
    /* Create a new SID for the child process */
    sid = setsid();
    if (sid < 0) {
        syslog( LOG_ERR, "unable to create a new session, code %d (%s)",
                errno, strerror(errno) );
        exit(EXIT_FAILURE);
    }
    /* Change the current working directory.  This prevents the current
       directory from being locked; hence not being able to remove it. */
    if ((chdir("/")) < 0) {
        syslog( LOG_ERR, "unable to change directory to %s, code %d (%s)",
                "/", errno, strerror(errno) );
        exit(EXIT_FAILURE);
    }
    /* Redirect standard files to /dev/null */
    freopen( "/dev/null", "r", stdin);
    freopen( "/dev/null", "w", stdout);
    freopen( "/dev/null", "w", stderr);
 
    /* Tell the parent process that we are A-okay */
    kill( parent, SIGUSR1 );
}
/*------------------------------------------------------------------------------*/
/* MAIN Ecoute reception données UDP                                            */
/*------------------------------------------------------------------------------*/
int main(int argc, char *argv[]) {
    /* Initialize the logging interface */
    openlog( DAEMON_NAME, LOG_PID, LOG_LOCAL5 );
    syslog( LOG_INFO, "starting k8056netd" );
    /* One may wish to process command line arguments here */
  parse_cmdline(argc,argv) ;
 addr_in_size = sizeof(struct sockaddr_in);
 
 // Détournement du signal émis à la mort du fils (il ne reste pas zombie)
// signal(SIGCHLD, SIG_IGN);
 msg = (char *)malloc(MSGSIZE);
 from = (struct sockaddr_in *)malloc(addr_in_size);
 my_addr = (struct sockaddr_in *)malloc(addr_in_size);
 memset((char *)my_addr,(char)0,addr_in_size);
 my_addr->sin_family = AF_INET;
 my_addr->sin_addr.s_addr = htonl(INADDR_ANY);
 my_addr->sin_port = htons(portnum);
 
 if((sockfd = socket (PF_INET, SOCK_DGRAM, 0)) < 0){
  if (verbose) fprintf(stderr,"Erreur %d dans socket: %s\n",errno,strerror(errno));
  exit(errno);
 };
 if(bind(sockfd, (struct sockaddr *)my_addr, addr_in_size) < 0){
  if (verbose)  fprintf(stderr,"Erreur %d dans bind: %s\n",errno,strerror(errno));
  if(errno != EADDRINUSE) exit(errno);
 };
 /* On daemonize */
 if (debug) syslog( LOG_INFO, "daemonize k8056netd" );
    daemonize( "/var/lock/" DAEMON_NAME );
 
    /* Now we are a daemon -- do the work for which we were paid */
 if (verbose)  fprintf(stdout,"Prêt a reçevoir\n");
 if (debug) syslog( LOG_INFO, "On ecoute le port UDP" );
   while(1){
    if (debug) syslog( LOG_INFO, "On est dans la boucle" );
  if((cc = recvfrom (sockfd,msg,MSGSIZE,0,(struct sockaddr *)from,
           &addr_in_size)) == -1){
   if (verbose)  fprintf(stderr,"Erreur %d dans recvfrom: %s\n",
    errno,strerror(errno));
   exit(errno);
  };
  fromaddr = from->sin_addr.s_addr;
  msg[cc] = '\0';
  if (verbose)  fprintf(stdout,"Reçue de  %s port %d: %s\n",
  (gethostbyaddr((char *)&fromaddr,
         sizeof(fromaddr),
         PF_INET))->h_name,
  from->sin_port,msg);
 
 if (debug) syslog( LOG_INFO, "Reçue de  %s port %d: %s\n",
  (gethostbyaddr((char *)&fromaddr,
         sizeof(fromaddr),
         PF_INET))->h_name,
  from->sin_port,msg);
  /* Ouverture port serie */
  initserie() ;
  if (debug) syslog( LOG_INFO, "init serie fait" );
  /* Formate msg vers cmd et envoie */
  sendserie(msg);
   if (debug) syslog( LOG_INFO, "Send serie fait" );
  /* on attend avant de revenir a l'ecoute */
  sleep(3);
  if (debug) syslog( LOG_INFO, "On repart" );
  // signal(SIGCHLD,SigCatcher);
       /* Finish up */
    if (debug) syslog( LOG_NOTICE, "terminated" );
    closelog();
 }
        /* Quitt... */
 if (verbose) printf("----- ICI ON SORT -----\n");
 
    return 0;
}
/*------------------------------------------------------------------------------*/
             
 
 
On activera le demon sur le serveur avec la commande : k8056netd -p 12345 /dev/ttyS0 .
ou, si on créé un lien symplolique : ln -s /dev/ttyS0 /dev/k8056 : k8056netd -p 12345
 
 
 

 

nach oben