#include #include #include #include #include /************** * PARAMETRES * **************/ // Declaration des lignes, boutons, IO et enums associés #include "io_declarations.h" // Doit etre dans un fichier séparé car les prototypes des fonctions du fichier .ino // sont générés automatiquement et placés au dessus des déclarations des enums sinon. // Activation debug (1 = oui, 0 = non) #define DEBUG_VIA_SYSLOG 0 #define DEBUG_VIA_SERIAL 0 // Définition de la sortie pour la LED de statut (13 = LED soudée sur l'arduino) #define STATUS_LED 13 // Paramètres Syslog (ip/port du serveur syslog-ng) static uint8_t ip_debug[] = { 192, 168, 1, 10 }; static uint16_t port_debug = 514; // Paramètres Ethernet (mac et ip locales pour serveur web) static uint8_t mac[] = { 0xFE, 0xED, 0xDE, 0xAD, 0xBE, 0xEF }; static uint8_t ip[] = { 192, 168, 1, 178 }; // Paramètres détection alea #define ALEA_NB_APPELS_MAX 20 #define ALEA_FENETRE_MILLIS 10000 // 5 secondes #define ALEA_BLOQUAGE_MILLIS 60000 // 1 minute // Pamètres détection entrées #define DUREE_MIN_BOUTON_PRESSE 50 // millisecondes // Paramètres WebServer #define PREFIX "" #define NAMELEN 32 #define VALUELEN 32 // Paramètres persistance #define EEPROM_BASE_ADDR_DATA 15 #define CHECKSUM_INIT 10 #define CHECKSUM_INVALID 0xFF #define CONSIGNE_PAR_DEFAUT HIGH /****************** * OBJETS GLOBAUX * *****************/ WebServer webserver(PREFIX, 80); // Serveur Web EthernetUDP Udp; // Socket UDP pour debug Syslog static uint8_t etat_entrees[NUM_ENTREES]; // Etat actuel des entrées static unsigned long millis_precedent_front_descendant[NUM_ENTREES]; // Stockage timing pour filtrage des entrées static uint8_t consigne_sorties[NUM_SORTIES]; // Consignes à appliquer sur les sorties /************************ * ROUTINES PRINCIPALES * ************************/ // Initialisation de l'ensemble des composants void setup(){ Ethernet.begin(mac, ip); log_init(); webserver_setup(); // Restaurer de l'EEPROM les consignes et positionner les bascules D des pins de sortie // N'applique pas la tension de sortie immédiatement car le paramètrage des pin en OUTPUT n'est pas encore fait charger_consignes(); appliquer_consignes(false); // Paramétrer le mode de toutes les pins utilisées en entrée for (int i=0; i inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; } // Code gérant la réponse à la requête HTTP permettant d'afficher l'état des consignes void servlet_list(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { server.httpSuccess(); server << ""; server << ""; server << "Domotique étage"; server << ""; server << ""; server << ""; server << "

Domotique étage

"; server << ""; sortie_t empty = (sortie_t) -1; // Salon html_tr_6_sorties(server, led_arduino, rl_ecl_ext_jardin, empty, empty, empty, empty); //html_tr_6_sorties(server, rl_sal_spot_left, empty, rl_sal_ecl_plaf, empty, rl_sal_spot_right, empty); //html_tr_6_sorties(server, empty, rl_sam_gu10_1, rl_sam_gu10_3, rl_sam_gu10_5, empty, empty); //html_tr_6_sorties(server, empty, empty, rl_sam_gu10_2, rl_sam_gu10_4, empty, empty); //html_tr_6_sorties(server, empty, empty, empty, empty, rl_sas_gu10_left, empty); //html_tr_6_sorties(server, rl_sam_pc_left, empty, empty, empty, rl_sas_gu10_right, rl_sas_ecl_plaf); //html_tr_6_sorties(server, empty, empty, rl_cuis_gu10_2, rl_cuis_gu10_1, empty, rl_coul_plaf); //html_tr_6_sorties(server, empty, rl_cuis_ecl_evier, empty, rl_cuis_ecl_plaf, empty, empty); server << "
"; server << ""; server << ""; } // Formattage d'une case de tableau void html_td_sortie(Print &p, sortie_t s) { if ( s == -1 ) { p << " "; } else { p << ""; p << ""; p << ""; } } // Formattage d'une ligne de tableau à 6 colonnes void html_tr_6_sorties(Print &p, sortie_t s1, sortie_t s2, sortie_t s3, sortie_t s4, sortie_t s5, sortie_t s6) { p << ""; html_td_sortie(p, s1); html_td_sortie(p, s2); html_td_sortie(p, s3); html_td_sortie(p, s4); html_td_sortie(p, s5); html_td_sortie(p, s6); p << ""; } // Code gérant la réponse à la requête HTTP permettant de modifier l'état d'une consigne void servlet_set(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete) { URLPARAM_RESULT rc; char name[NAMELEN]; int name_len; char value[VALUELEN]; int value_len; if (type == WebServer::HEAD) return; while (strlen(url_tail)) { rc = server.nextURLparam(&url_tail, name, NAMELEN, value, VALUELEN); if (rc != URLPARAM_EOS) { int key = strtoul(name, NULL, 10); int val = strtoul(value, NULL, 10); if ( key >= 0 && key < NUM_SORTIES ) { consigne_sorties[key] = (val==1)?HIGH:LOW; } } } appliquer_consignes(true); server.httpSeeOther(PREFIX "/"); } // Initialisation et paramétrage du serveur Web void webserver_setup() { webserver.begin(); webserver.setDefaultCommand(&servlet_list); webserver.addCommand("set", &servlet_set); } /********************** * I/O ET PERSISTENCE * **********************/ /* Lit les valeurs de consigne_sorties[] et : - met à jour l'état des bascules de la sortie (pin) correspondante - écrit cet état dans l'EEPROM forcer : permet d'outrepasser le temps de pause en cas d'une précédente détection d'aléa (cf protection_alea()) */ void appliquer_consignes(boolean forcer) { uint8_t checksum ; int i; if (!protection_alea() && !forcer) return; // Invalide les infos stockées dans l'EEPROM EEPROM.write(EEPROM_BASE_ADDR_DATA, CHECKSUM_INVALID); log_begin_line(); log_print("appliquer_consignes() : Sorties "); checksum = CHECKSUM_INIT; for (i=0; i DUREE_MIN_BOUTON_PRESSE ) { // L'entrée est restées assez longtemps en front bas evenement_entree = (entree_t) i; millis_precedent_front_descendant[i] = 0; log_print("!"); } else { log_print("w"); } } else { log_print("r"); } } } log_print(" retour "); log_printInt(evenement_entree); log_end_line(); return (entree_t)evenement_entree; } /************ * SECURITE * ************/ /* Comptabilise le nombre d'évènements qui se produit sur les sorties ( = nbre d'appels de protection_alea() par appliquer_consignes() ) - retourne false si un trop grand nombre de changements d'état à été détecté il y a moins de ALEA_BLOQUAGE_MILLIS ms - retourne true si on est en situation normale */ boolean protection_alea() { static uint8_t curseur_appels = 0; static unsigned long millis_precedents_appels[ALEA_NB_APPELS_MAX]; static unsigned long millis_debut_blocage; unsigned long millis_oldest, maintenant; maintenant = millis(); // Ajout de cet appel ) protection_alea() dans le buffer rotatif millis_precedents_appels millis_precedents_appels[curseur_appels] = maintenant; curseur_appels = (curseur_appels + 1) % ALEA_NB_APPELS_MAX; // Si on est en période de blocage, retourner false tout de suite. Si en fin de période, oublier le blocage if ( millis_debut_blocage > 0 ) { if ( maintenant - millis_debut_blocage < ALEA_BLOQUAGE_MILLIS ) { return false; } else { millis_debut_blocage = 0; log_begin_line(); log_print("protection_alea() : Fin de blocage"); log_end_line(); } } // Si le plus viel appel enregistré est moins vieux que (maintenant - ALEA_FENETRE_MILLIS) // Alors c'est qu'on a une trop grande fréquence d'évènements, bloquer le système pdt ALEA_BLOQUAGE_MILLIS millis_oldest = millis_precedents_appels[curseur_appels]; if ( millis_oldest > (maintenant - ALEA_FENETRE_MILLIS) ) { millis_debut_blocage = maintenant; log_begin_line(); log_print("protection_alea() : "); log_printInt(ALEA_NB_APPELS_MAX); log_print(" appels en moins de "); log_printInt(ALEA_FENETRE_MILLIS); log_print(" millisecondes. Blocage pendant "); log_printInt(ALEA_BLOQUAGE_MILLIS / 1000); log_print(" secondes"); log_end_line(); } return true; } /************* * DEBUGGING * *************/ void log_init() { #if DEBUG_VIA_SYSLOG == 1 Udp.begin(port_debug); // port local comme le port de destination (rsyslog) #endif #if DEBUG_VIA_SERIAL == 1 Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } #endif log_begin_line(); log_print("log_init() : Mode debug initialisé"); log_end_line(); } void log_begin_line() { #if DEBUG_VIA_SYSLOG == 1 Udp.beginPacket(ip_debug, port_debug); Udp.print("<15> "); // Syslog header : facility * 8 (1 == user) + severity (7 == debug) Udp.print("millis()=="); Udp.print(millis()); Udp.print(" "); #endif #if DEBUG_VIA_SERIAL == 1 Serial.print("millis()=="); Serial.print(millis()); Serial.print(" "); #endif } void log_print(const char *str) { #if DEBUG_VIA_SYSLOG == 1 Udp.print(str); #endif #if DEBUG_VIA_SERIAL == 1 Serial.print(str); #endif } void log_printInt(long val) { #if DEBUG_VIA_SYSLOG == 1 Udp.print(val); #endif #if DEBUG_VIA_SERIAL == 1 Serial.print(val); #endif } void log_end_line() { #if DEBUG_VIA_SYSLOG == 1 Udp.endPacket(); #endif #if DEBUG_VIA_SERIAL == 1 Serial.println(""); #endif }