Optimisation de l'intégration des dispositifs dans les systèmes domotiques à l'aide de fichiers de configuration INI

Pour gérer efficacement les périphériques dans un environnement domotique, l'utilisation de fichiers de configuration INI offre une méthode modulaire. Cet approche permet d'ajouter ou de modifier des dispositifs sans recompiler le code source, simplifiant ainsi la maintenance et l'extensibilité du système.

Préparation de l'environnement

Intégrer les bibliothèques nécessaires pour la lecture des fichiers INI. Ajouter les fichiers d'en-tête et source correspondants dans le projet, par exemple ini.c dans le répertoire source et ini.h dans le répertoire d'en-têtes. Dans le fichier principal de gestion des réceptions, inclure les en-têtes requis et désactiver les anciennes définitions de périphériques en les commentant. Cela permet de supprimer les fichiers spécifiques aux périphériques qui ne sont plus nécessaires.

Définition des configurations des périphériques

Créer un fichier INI pour stocker les paramètres de chaque dispositif. Chaque section correspond à un périphérique, avec des clés décrivant ses propriétés, telles que l'identifiant, la broche GPIO, le mode, l'état initial et les options de contrôle.

[serrure]
cle=0x44
broche_gpio=8
mode_gpio=SORTIE
etat_gpio=HAUT
verification_visage=1
activation_voix=1

[signal_sonore]
cle=0x45
broche_gpio=9
mode_gpio=SORTIE
etat_gpio=HAUT
verification_visage=0
activation_voix=1

[led_salon]
cle=0x42
broche_gpio=5
mode_gpio=SORTIE
etat_gpio=HAUT
verification_visage=0
activation_voix=0

[led_chambre]
cle=0x41
broche_gpio=2
mode_gpio=SORTIE
etat_gpio=HAUT
verification_visage=0
activation_voix=0

[ventilateur]
cle=0x43
broche_gpio=7
mode_gpio=SORTIE
etat_gpio=HAUT
verification_visage=0
activation_voix=0

Déploiement du fichier de configuration

Copier le fichier INI dans un répertoire accessible sur l'appareil cible, par exemple sous /etc/ pour une configuration système globale. Utiliser une commande comme sudo cp gdevice.ini /etc/ pour effectuer cette opération.

Adaptation du code source

Modifier le fichier principle pour lire les configurations à partir du fichier INI au lieu d'utiliser des définitions codées en dur. Cela implique d'implémenter un analyseur INI et de créer une liste chaînée dynamique pour stocker les informations des périphériques.

#include <pthread.h>
#include <mqueue.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <wiringPi.h>

#include "receive_interface.h"
#include "control.h"
#include "mq_queue.h"
#include "global.h"
#include "face.h"
#include "myoled.h"
#include "gdevice.h"
#include "ini.h"

#define VERIFIER(section_attendue, nom_attendu) strcmp(section, section_attendue) == 0 && strcmp(name, nom_attendu) == 0

static int descripteur_oled = -1;
static struct gdevice *tete_peripheriques = NULL;

typedef struct {
    int longueur_message;
    unsigned char *tampon;
    ctrl_info_t *info_controle;
} message_recu_t;

static int traiter_configuration_peripherique(void *utilisateur, const char *section, const char *name, const char *value) {
    struct gdevice *nouveau_peripherique = NULL;
    if (tete_peripheriques == NULL) {
        tete_peripheriques = (struct gdevice *)malloc(sizeof(struct gdevice));
        memset(tete_peripheriques, 0, sizeof(struct gdevice));
        tete_peripheriques->suivant = NULL;
        strcpy(tete_peripheriques->nom_peripherique, section);
    } else if (strcmp(section, tete_peripheriques->nom_peripherique) != 0) {
        nouveau_peripherique = (struct gdevice *)malloc(sizeof(struct gdevice));
        memset(nouveau_peripherique, 0, sizeof(struct gdevice));
        strcpy(nouveau_peripherique->nom_peripherique, section);
        nouveau_peripherique->suivant = tete_peripheriques;
        tete_peripheriques = nouveau_peripherique;
    }

    if (tete_peripheriques != NULL) {
        if (VERIFIER(tete_peripheriques->nom_peripherique, "cle")) {
            sscanf(value, "%x", &tete_peripheriques->identifiant);
        } else if (VERIFIER(tete_peripheriques->nom_peripherique, "broche_gpio")) {
            tete_peripheriques->broche_gpio = atoi(value);
        } else if (VERIFIER(tete_peripheriques->nom_peripherique, "mode_gpio")) {
            if (strcmp(value, "SORTIE") == 0) {
                tete_peripheriques->mode_gpio = OUTPUT;
            } else if (strcmp(value, "ENTREE") == 0) {
                tete_peripheriques->mode_gpio = INPUT;
            }
        } else if (VERIFIER(tete_peripheriques->nom_peripherique, "etat_gpio")) {
            if (strcmp(value, "BAS") == 0) {
                tete_peripheriques->etat_gpio = LOW;
            } else if (strcmp(value, "HAUT") == 0) {
                tete_peripheriques->etat_gpio = HIGH;
            }
        } else if (VERIFIER(tete_peripheriques->nom_peripherique, "verification_visage")) {
            tete_peripheriques->activer_verification_visage = atoi(value);
        } else if (VERIFIER(tete_peripheriques->nom_peripherique, "activation_voix")) {
            tete_peripheriques->activer_voix = atoi(value);
        }
    }
    return 1;
}

static int initialiser_reception(void) {
    if (ini_parse("/etc/gdevice.ini", traiter_configuration_peripherique, NULL) < 0) {
        printf("Échec du chargement du fichier 'gdevice.ini'\n");
        return 1;
    }
    struct gdevice *peripherique_courant = tete_peripheriques;
    while (peripherique_courant != NULL) {
        printf("Périphérique: %s\n", peripherique_courant->nom_peripherique);
        printf("Identifiant: 0x%x\n", peripherique_courant->identifiant);
        printf("Broche GPIO: %d\n", peripherique_courant->broche_gpio);
        peripherique_courant = peripherique_courant->suivant;
    }
    descripteur_oled = myoled_init();
    face_init();
    return descripteur_oled;
}

static void finaliser_reception(void) {
    face_final();
    if (descripteur_oled != -1) {
        close(descripteur_oled);
        descripteur_oled = -1;
    }
}

static void *gerer_peripherique(void *argument) {
    pthread_detach(pthread_self());
    message_recu_t *message = (message_recu_t *)argument;
    struct gdevice *peripherique_trouve = NULL;
    char resultat_action[20] = "succes";
    double score_visage = 0.0;
    int code_retour = -1;

    if (message != NULL && message->tampon != NULL) {
        peripherique_trouve = rechercher_peripherique_par_identifiant(tete_peripheriques, message->tampon[2]);
    }

    if (peripherique_trouve != NULL) {
        peripherique_trouve->etat_gpio = (message->tampon[3] == 0) ? LOW : HIGH;
        if (peripherique_trouve->activer_verification_visage == 1) {
            score_visage = obtenir_statut_visage();
            if (score_visage > 0.6) {
                code_retour = configurer_etat_gpio(peripherique_trouve);
                message->tampon[2] = 0x47;
            } else {
                message->tampon[2] = 0x46;
            }
        } else {
            code_retour = configurer_etat_gpio(peripherique_trouve);
        }

        if (peripherique_trouve->activer_voix == 1 && message->info_controle != NULL) {
            struct control *controle_courant = message->info_controle->tete_controles;
            while (controle_courant != NULL) {
                if (strstr(controle_courant->nom_controle, "voix")) {
                    pthread_t id_thread;
                    pthread_create(&id_thread, NULL, controle_courant->fonction_appliquer, (void *)message->tampon);
                    break;
                }
                controle_courant = controle_courant->suivant;
            }
        }

        if (code_retour == -1) {
            strncpy(resultat_action, "echec", 6);
        }

        char message_oled[512];
        sprintf(message_oled, "%s %s %s!\n", 
                (peripherique_trouve->etat_gpio == LOW) ? "Ouvrir" : "Fermer", 
                peripherique_trouve->nom_peripherique, resultat_action);
        myoled_afficher(message_oled);

        if (peripherique_trouve->activer_verification_visage == 1 && code_retour == 0 && score_visage > 0.6) {
            sleep(5);
            peripherique_trouve->etat_gpio = HIGH;
            configurer_etat_gpio(peripherique_trouve);
        }
    }
    pthread_exit(0);
}

static void *recevoir_messages(void *argument) {
    message_recu_t *message_recu = NULL;
    unsigned char *tampon = NULL;
    struct mq_attr attributs;
    ssize_t longueur_lue = -1;

    if (argument != NULL) {
        message_recu = (message_recu_t *)malloc(sizeof(message_recu_t));
        message_recu->info_controle = (ctrl_info_t *)argument;
        message_recu->longueur_message = 0;
        message_recu->tampon = NULL;
    } else {
        pthread_exit(0);
    }

    if (mq_getattr(message_recu->info_controle->descripteur_mq, &attributs) == -1) {
        pthread_exit(0);
    }

    message_recu->tampon = (unsigned char *)malloc(attributs.mq_msgsize);
    tampon = (unsigned char *)malloc(attributs.mq_msgsize);
    memset(message_recu->tampon, 0, attributs.mq_msgsize);
    memset(tampon, 0, attributs.mq_msgsize);

    pthread_detach(pthread_self());

    while (1) {
        longueur_lue = mq_receive(message_recu->info_controle->descripteur_mq, tampon, attributs.mq_msgsize, NULL);
        if (longueur_lue == -1) {
            if (errno == EAGAIN) {
                printf("File d'attente vide\n");
            } else {
                break;
            }
        } else if (tampon[0] == 0xAA && tampon[1] == 0x55 && tampon[4] == 0x55 && tampon[5] == 0xAA) {
            message_recu->longueur_message = longueur_lue;
            memcpy(message_recu->tampon, tampon, longueur_lue);
            pthread_t id_thread;
            pthread_create(&id_thread, NULL, gerer_peripherique, (void *)message_recu);
        }
    }

    free(message_recu);
    free(tampon);
    pthread_exit(0);
}

struct control controle_reception = {
    .nom_controle = "reception",
    .fonction_initialiser = initialiser_reception,
    .fonction_finaliser = finaliser_reception,
    .fonction_obtenir = recevoir_messages,
    .fonction_appliquer = NULL,
    .suivant = NULL
};

struct control *ajouter_reception_a_la_liste_controles(struct control *tete) {
    return ajouter_interface_a_la_liste_controles(tete, &controle_reception);
}

Cette approche centralise la gestion des périphériques dans un fichier INI, permettant des modifications rapides sans intervention sur le code source. Pour ajouter un nouveau dispositif, il suffit d'étendre le fichier de configuration avec une nouvelle section et les attributs appropriés.

Étiquettes: C INI GPIO domotique multithreading

Publié le 9 juin à 21h41