diff --git a/config-default.yaml b/config-default.yaml
index 0c38eee..af6cc0d 100644
--- a/config-default.yaml
+++ b/config-default.yaml
@@ -1,222 +1,222 @@
######################################################################
# PvMonit - By David Mercereau : http://david.mercereau.info/contact/
# Licence BEERWARE
# Version 1.0
######################################################################
##############################
#
# NE MODIFIER PAS CE FICHIER !
# copier config-default.yaml dans config.yaml et modifier config.yaml (supprimer tout ce qui ne vous intéresse pas de modifier)
#
##############################
# Niveau d'affichage des messages
printMessage: 0 # 0=0 5=debug
printMessageLogfile: false # path or fase
# URL data
urlDataXml: http://pvmonit.chezvous/data-xml.php # Utiliser un domaine qui pointe vers l'ip, not localhost or 127.0.0.1
tmpFileDataXml: /tmp/PvMonit_data-xml.php.tmp
dir:
bin: /opt/PvMonit/bin/
bin_enabled: /opt/PvMonit/bin-enabled/
lcd: /opt/PvMonit/lcd/
domo: /opt/PvMonit/domo/
data:
ppv_total: false # production total des régulateurs (utilisé si vous avez plusieurs régulateur)
conso_calc: false # Calculé avec : la puissance instantané (P du BMV) - ppv_total ppv_total at true for use this
cache:
dir: /tmp/PvMonit_cache # in tmpfs
file_prefix:
time: 60 # in second
# Methode de récupération des données VE DIRECT (par USB - vedirect OU serial par Arduino)
vedirect:
by: usb # usb OR arduino
usb:
# Binaire de vedirect.py USB
bin: /usr/bin/sudo /usr/bin/python /opt/PvMonit/bin/vedirect.py
arduino:
# Fichier de data YAML enregistré par le script vedirectOnArduinoRemote.py cohérence avec config-vedirectOnArduinoRemote.yaml
data_file: /tmp/PvMonit_getSerialArduino.data.yaml
data_file_expir: 300 # Expiration
serial:
port: /dev/ttyAMA0 # ttyAMA0 pour le serial via GPIO, ttyUSB0 pour le port USB...
timeout: 0
# Débit du serial 0 qui va vers l'Arduino (doit être cohérent entre les 2, diffère selon la distance de câble)
# Débit Longueur (m)
# 2400 60
# 4 800 30
# 9 600 15
# 19 200 7,6
# https://fr.wikipedia.org/wiki/RS-232#Limites
baudRate: 4800
whileSleep: 0.001
whileSleepAfterStop: 3
# donnée récolté (voir la doc victron sur le protocole VE.Direct)
data_ok:
mppt:
- CS
- PPV
- V
- ERR
- I
- VPV
- H19
- H20
- H21
- H22
- H23
bmv:
- V
- VS
- VM
- DM
- I
- T
- P
- CE
- SOC
- TTG
- AR
- H1
- H2
- H3
- H4
- H5
- H6
- H7
- H8
- H9
- H10
- H11
- H12
- H13
- h14
- H15
- H16
- H17
- H18
phoenix:
- P
- CS
- MODE
- AC_OUT_V
- AC_OUT_I
- WARN
# Numéro de série (champs SER#) en correspondance avec des nom buvables
deviceCorrespondance:
HQXXXXXXXX: MpttGarage
HQYYYYYYYY: MpttToit
# Plafont de consommation en W impossible à dépasser (techniquement, sinon c'est une erreur de sonde)
consoPlafond: 1500
# Tension standard du réseau (110V ou 230V)
tensionNorme: 230
### Export vers Emoncms
emoncms:
# Test la connexion internet
testInternetHost: emoncms.org
testInternetPort: 80
# emoncms URL du post.json & API key
urlInputJsonPost: https://emoncms.org/input/post.json
apiKey: XXXXXXXXXXXXXXXXXXXXXXXX
# Répertoire de collecte de données
dataCollecte: /tmp/PvMonit_collecteData
# Dossier ou ranger les erreurs
dataCollecteError: /tmp/PvMonit_collecteDataError
# Attente entre deux requête OK
sleepOk: 1
# Attente entre deux requête échoué
sleepNok: 3
# Fichier de lock pour éviter les doublons
lockFile: /tmp/PvMonit_sendToEmoncms.lock
### Page Web :
www:
# Délais de raffraichissement de la page (en seconde) 300000 = 5 minutes
refreshTime: 300000
# Max de la jauge voltage batterie (en V)
vbatMax: 30
# Max de la jauge puissance PV (en W)
PpvMax: 500 # max Jauge puissance PV (en W)
# Max de la jauge puissance PV total (si plusieurs régulateur) (en W)
PpvtMax: 500 # max Jauge puissance PV (en W)
dataPrimaire:
- V
- PPV
- ERR
- CS
- SOC
- AR
- P
- TTG
- MODE
- AC_OUT_V
- AC_OUT_I
- WARN
- PPVT
- CONSO
dataPrimaireSmallScreen:
- SOC
- P
- PPVT
menu:
-
EmonCMS (historique)
- PvMonit projet
- Soutenir l'auteur
# Ecran LCD (avec script PvMonit/lcd
lcd:
rafraichissement: 0.1 # en seconde pour les boutons
dataUpdate: 45 # en seconde pour le rafraichissement des données
onTimer: 60 # en seconde le temps que l'écran reste allumé si par défaut éteind
estCeLaNuitTimer: 600 # détection de la nuit tout les x secondes
dataPrint:
- SOC
- P
- PPVT
onAt: 8 # heure d'allumage du LCD
offAt: 21 # heure d'extinction du LCD
# Domotique (avec script PvMonit/domo)
domo:
dataCheckTime: 30
i2c:
adress: 0x04
device: 1
heartbeatTime: 1 # Fréquence du bâtement de coeur (en seconde)
fileExpir: 40 # Age en seconde après laquel le fichier n'est plus considéré comme ok
fileCheckTime: 10 # Fréquece de la vérificatio du XML (en seconde)
fileCheckError: 3 # nombre d'erreurs sur le xml avant de sortir du mode automatique / stopper le heartbeat
# temps avant erreur = $checkTime * $checkError
fileDownloadRetry: 3
valueUse:
- SOC
- P
- PPVT
- CS
#- CONSO
relay:
- dataFreq: 3 # Délais de récupération des données depuis l'arduino (en secondes)
- nb: 5
+ dataFreq: 30 # Délais de récupération des données depuis l'arduino (en secondes)
+ nb: 5 # 14 max !
scriptDir: /opt/PvMonit/domo/relay.script.d/
- scriptExecInterval: 5 # Interval d'execution des script de relais
+ scriptExecInterval: 40 # Interval d'execution des script de relais
spoolTimeout: 10 # timeout sur un ordre dans la file d'attente
- relayCorrespondance: # A commencer par 0
+ relayCorrespondance: # A commencer par 0
0: Pompe de relevage
1: Box Internet
2: Téléphone
3: Disque dur externe
4: Chargeur outil électroportatif # Sonde courant !
#5: Chauffe eau
#6: Batterie de vélo életrique
#7: Surpresseur
diff --git a/domo/INSTALL.md b/domo/INSTALL.md
new file mode 100644
index 0000000..1be7aaf
--- /dev/null
+++ b/domo/INSTALL.md
@@ -0,0 +1,3 @@
+pip3 install smbus2 wget
+
+14 relay max pour cette version
diff --git a/domo/domo.py b/domo/domo.py
index d7bd013..f1b85fa 100644
--- a/domo/domo.py
+++ b/domo/domo.py
@@ -1,177 +1,208 @@
import yaml
import time
from smbus2 import SMBus
import os
from lxml import etree
from urllib.request import urlopen
import wget
from past.builtins import execfile
import re
import time
## for debug :
import pprint
with open('../config-default.yaml') as f1:
config = yaml.load(f1, Loader=yaml.FullLoader)
with open('../config.yaml') as f2:
config_perso = yaml.load(f2, Loader=yaml.FullLoader)
def configGet(key1, key2=None, key3=None, key4=None):
if key4 != None:
try:
return config_perso[key1][key2][key3][key4]
except:
return config[key1][key2][key3][key4]
elif key3 != None:
try:
return config_perso[key1][key2][key3]
except:
return config[key1][key2][key3]
elif key2 != None:
try:
return config_perso[key1][key2]
except:
return config[key1][key2]
else:
try:
return config_perso[key1]
except:
return config[key1]
# Cherche a savoir si le MPPT est en Absorption ou en Float (en fin de charge)
def MpptAbsOrFlo(cs):
patternAbsFlo = re.compile(r"Absorption|Float")
if patternAbsFlo.match(cs):
return True;
else :
return False;
# Function for log
def logMsg(level, msg):
if level <= configGet('printMessage') :
print(time.strftime ('%m/%d/%Y %H:%M') ," - ",msg)
return -1
# i2c write
def writeNumber(value):
bus.write_byte(configGet('domo', 'i2c', 'adress'), value)
return -1
def download_data():
# téléchargement des données
logMsg(3, 'Download data')
with open(configGet('tmpFileDataXml'), 'wb') as tmpxml:
tmpxml.write(urlopen(configGet('urlDataXml')).read())
return time.time()
logMsg(1, 'Lancement du script domo.py')
heartLastCheck=0
relayDataLastCheck=0
scriptExecLast=0
xmlLastCheck=0
xmlfileCheckError=0
xmlData = {}
spoolAction=None
spoolActionSend=False
+
+bus=SMBus(configGet('domo', 'i2c', 'device'));
+
logMsg(5, "Début de la boucle")
while 1:
# XML data recup
t=int(time.time())
if xmlLastCheck+configGet('domo', 'dataCheckTime') < t:
if not os.path.isfile(configGet('tmpFileDataXml')):
logMsg(1, "Le fichier XML de donnée " + configGet('tmpFileDataXml') + " n'existe pas.")
download_data()
xmlfileCheckError=xmlfileCheckError+1
elif os.path.getmtime(configGet('tmpFileDataXml'))+configGet('domo', 'fileExpir') < t :
logMsg(1, "Le fichier data est périmé !")
download_data()
xmlfileCheckError=xmlfileCheckError+1
else:
logMsg(3, "Récupération des données XML (état de l'installation solaire")
xmlfileCheckError=0
tree = etree.parse(configGet('tmpFileDataXml'))
datacount=0
for datas in tree.xpath("/devices/device/datas/data"):
if datas.get("id") in configGet('domo', 'valueUse'):
datacount = datacount + 1
for data in datas.getchildren():
if data.tag == "value":
xmlData[datas.get("id")]=data.text
logMsg(5, pprint.pprint(xmlData))
xmlLastCheck=t
# S'il y a trop d'erreur :
if xmlfileCheckError >= configGet('domo', 'fileCheckError'):
logMsg(1, 'Trop d\'erreur, on patiente 10 secondes')
time.sleep(10)
xmlfileCheckError=0
else:
+ #########################
# Le heartbeat
+ #########################
if heartLastCheck+configGet('domo', 'heartbeatTime') < t:
- #DEVSMBSTOP bus=SMBus(configGet('domo', 'i2c', 'device'));
- #DEVSMBSTOP writeNumber(int(ord("H")))
+ writeNumber(int(ord("H")))
logMsg(5, 'Heardbeat envoyé')
heartLastCheck=t
+ #########################
# Data Relay
+ #########################
if relayDataLastCheck+configGet('domo', 'relay', 'dataFreq') < t:
logMsg(4, 'On récupère les données des relay (via i2c arduino)')
# A FAIRE
# Simulation monsieur l'arbitre
#// Etat :
#// - 0 : off force
#// - 1 : off auto
#// - 2 : on auto
#// - 3 : on force
#// Mode
#// - 0 : Null
#// - 1 : Off
#// - 2 : Auto
#// - 3 : On
- relayEtat = [1, 1, 0, 3, 1]
- relayMod = [2, 2, 1, 3, 2]
- #logMsg(5, pprint.pprint(relayEtat))
+
+ time.sleep(0.3)
+ # Requête i2c pour demande de data (état et mode des relay)
+ i2cResults = bus.read_i2c_block_data(configGet('domo', 'i2c', 'adress'), int(ord('D')), configGet('domo', 'relay', 'nb')*2+1)
+ # Remise à 0
+ relayEtat=[]
+ relayMod=[]
+ x=0
+ dataOrdre=1
+ logEtat=""
+ logMod=""
+ for i2cDatas in i2cResults:
+ # Si les données sont présentes
+ if i2cDatas != 255:
+ if i2cDatas == 29: # C'est le sépartateur : https://fr.wikibooks.org/wiki/Les_ASCII_de_0_%C3%A0_127/La_table_ASCII
+ dataOrdre=2
+ x=0
+ elif dataOrdre == 1:
+ relayEtat.insert(x,i2cDatas)
+ logEtat=logEtat+","+str(i2cDatas)
+ else:
+ relayMod.insert(x,i2cDatas)
+ logMod=logMod+","+str(i2cDatas)
+ x=x+1
+ logMsg(5, "DATA reçu : Etat " + logEtat)
+ logMsg(5, "DATA reçu : Mod " + logMod)
relayDataLastCheck=t
+ #########################
# On joue les scripts
+ #########################
if scriptExecLast+configGet('domo', 'relay', 'scriptExecInterval') < t:
logMsg(4, 'On joue les script des relay en mode auto')
relayId=0
print(relayEtat[0])
for mod in relayMod:
# Si la file d'attente des actions est vide on que le relay est en automatique
if spoolAction == None and mod == 2:
scriptFile=configGet('dir','domo') + configGet('domo','relay', 'scriptDir') + "/" + str(relayId) + ".py"
logMsg(4, 'Lecture du script ' + scriptFile)
if not os.path.isfile(scriptFile):
logMsg(2, 'Erreur, pas de script ' + scriptFile)
else:
returnEtat=None
execfile(scriptFile)
if returnEtat != None and returnEtat != relayEtat[relayId]:
logMsg(2, 'Un changement d\'état vers ' + str(returnEtat) + ' de est demandé pour le relay ' + str(relayId))
spoolAction=[relayId, returnEtat, t]
else:
logMsg(4, 'Pas de changement d\'état demandé pour le relay ' + str(relayId))
relayId=relayId+1
scriptExecLast=t
# Traitement de la file d'attente
if spoolAction != None and spoolActionSend == False:
logMsg(3, 'Traitement du spool, envoi de l\'ordre')
logMsg(5, pprint.pprint(spoolAction))
spoolActionSend=t
# A FAIRE
# Lancer l'ordre sur l'aduino
# Vérifier que l'arduino a bien exécuté l'ordre
if spoolAction != None and spoolActionSend != False:
# Est-ce que le relay est dans l'état attendu par l'ordre
if relayEtat[spoolAction[0]] == spoolAction[1]:
logMsg(5, 'Le relay ' + spoolAction[0] + ' n\'est pas encore dans l\'état attendu ' + spoolAction[1])
#if spoolAction != None and spoolActionSend+configGet('domo', 'spoolTimeout') < t:
# spoolAction=
# !! Faut faire un truc vide le spoolAction quand c'est fait... hummmm ...
# Pour être gentil avec le système
time.sleep(0.01)
diff --git a/firmware/arduinoRelayi2c.ino b/firmware/arduinoRelayi2c.ino
new file mode 100644
index 0000000..817d7c0
--- /dev/null
+++ b/firmware/arduinoRelayi2c.ino
@@ -0,0 +1,356 @@
+
+#include // bibliothèque de rjbatista
+#include
+
+// Documentation afficheur + bouton
+// http://electroniqueamateur.blogspot.com/2017/07/afficheur-8-chiffres-8-leds-8-boutons.html
+
+// Documentation module relais :
+// http://wiki.mchobby.be/index.php?title=Module_Relais
+
+#define DEBUG 1
+//#define MASTERSIMU 1
+
+//Slave Address for the Communication
+#define SLAVE_ADDRESS 0x04
+
+// Config :
+
+// Afficheur TM1638 lib :
+// DIO 3, CLK 2 , STB 4:
+TM1638 afficheur(3, 2, 4);
+
+// Relay number
+byte relayNb=8;
+// Relay pin number
+byte relayPin[] = {5, 6, 7, 8, 9, 10, 11, 12};
+// ####### Relay
+// Etat :
+// - 0 : off force
+// - 1 : off auto
+// - 2 : on auto
+// - 3 : on force
+byte relayEtat[] = {0, 0, 0, 0, 0, 0, 0, 0};
+// Mode
+// - 0 : Null
+// - 1 : Off
+// - 2 : Auto
+// - 3 : On
+byte relayMod[] = {0, 0, 0, 0, 0, 0, 0, 0};
+
+// Police d'afficheur
+const byte MES_FONTS[] = {
+ 0b00000000, // 0 null
+ 0b00001000, // 1 Down for off force
+ 0b01000000, // 2 Middle for on/off auto
+ 0b00000001 // 3 UP for on force
+};
+
+
+String RelayOrderCode = "RO";
+bool MasterPresent = false;
+bool RelayChange = true;
+int HeartbeatCheckFreq=40;
+int HeartbeatCheckCount=0;
+int RelayChangeFreq=120;
+int RelayChangeCount=0;
+
+int changeEtat(int id) {
+ switch (relayMod[id]) {
+ // Null
+ case 0:
+ afficheur.setLED(TM1638_COLOR_NONE, id);
+ digitalWrite(relayPin[id],HIGH);
+ relayEtat[id]=0;
+ break;
+ // Off
+ case 1:
+ afficheur.setLED(TM1638_COLOR_NONE, id);
+ digitalWrite(relayPin[id],HIGH);
+ relayEtat[id]=0;
+ break;
+ // Auto
+ case 2:
+ afficheur.setLED(TM1638_COLOR_NONE, id);
+ digitalWrite(relayPin[id],HIGH);
+ relayEtat[id]=1;
+ break;
+ // On
+ case 3:
+ afficheur.setLED(TM1638_COLOR_RED, id);
+ digitalWrite(relayPin[id],LOW);
+ relayEtat[id]=3;
+ break;
+ }
+ #ifdef DEBUG
+ Serial.println((String)"Etat pass to "+relayEtat[id]+" for "+id+" relay");
+ #endif
+}
+
+
+
+
+
+int changeMod(int id, int newMod) {
+ switch (newMod) {
+ case 0:
+ afficheur.setDisplayDigit(0, id, false, MES_FONTS);
+ break;
+ case 1:
+ afficheur.setDisplayDigit(1, id, false, MES_FONTS);
+ break;
+ case 2:
+ afficheur.setDisplayDigit(2, id, false, MES_FONTS);
+ break;
+ case 3:
+ afficheur.setDisplayDigit(3, id, false, MES_FONTS);
+ break;
+ }
+ #ifdef DEBUG
+ Serial.println((String)"Mod change to "+newMod+" for "+id+" relay");
+ #endif
+ relayMod[id]=newMod;
+}
+
+int i2cReceiveData[50];
+
+// callback for received data
+void receiveData(int byteCount) {
+ int i = 0;
+ #ifdef DEBUG
+ Serial.print("Donnée Reçu :");
+ #endif
+ while (Wire.available()) {
+ Serial.print(" ");
+ i2cReceiveData[i] = Wire.read();
+ #ifdef DEBUG
+ Serial.print(i2cReceiveData[i]);
+ #endif
+ i++;
+ }
+ #ifdef DEBUG
+ Serial.println();
+ #endif
+ /*
+ #ifdef DEBUG
+ Serial.print("Conséquence : ");
+ Serial.println(i2cReceiveData[0]);
+ #endif
+ */
+ // Heartbeat
+ if(i2cReceiveData[0]=='H') {
+ #ifdef DEBUG
+ Serial.println("Hearbeat de nouveau reçu !");
+ #endif
+ HeartbeatCheckCount=0;
+ // Si on récupère le master : On remet les relay en auto off (1) s'il sont à 0
+ if (MasterPresent == false) {
+ for (int i = 0; i < relayNb; i++) {
+ if (relayMod[i] == 0) {
+ changeMod(i, 2);
+ }
+ }
+ RelayChange = true;
+ MasterPresent = true;
+ }
+ }
+ if(i2cReceiveData[0]== 79) { // Réception d'un O (pour Ordre)
+ #ifdef DEBUG
+ Serial.println("Ordre du Pi de changement d'état pour le relay " + String(i2cReceiveData[1]) + " à " + String(i2cReceiveData[2]));
+ #endif
+ relayEtat[i2cReceiveData[1]] = i2cReceiveData[2];
+ // Passer l'état à Auto On
+ if (i2cReceiveData[2] == 2) {
+ afficheur.setLED(TM1638_COLOR_RED, i2cReceiveData[1]);
+ digitalWrite(relayPin[i2cReceiveData[1]],LOW);
+ // Passer l'état à Auto Off
+ } else if (i2cReceiveData[2] == 1) {
+ afficheur.setLED(TM1638_COLOR_NONE, i2cReceiveData[1]);
+ digitalWrite(relayPin[i2cReceiveData[1]],HIGH);
+ } else {
+ Serial.println("Erreur, ordre incorrect");
+ }
+ }
+}
+
+// callback for sending data
+void sendData() {
+ // ------------------ Data Send
+ if(i2cReceiveData[0] = "D") {
+ Serial.println("Data send : ");
+ // Relay etat
+ for (byte i = 0; i < relayNb; i = i + 1) {
+ Wire.write(relayEtat[i]);
+ Serial.print(relayEtat[i]);
+ }
+ Serial.print(" - ");
+ Wire.write(29); // Séparrateur de groupe : https://fr.wikibooks.org/wiki/Les_ASCII_de_0_%C3%A0_127/La_table_ASCII
+ // Relay mode
+ for (byte i = 0; i < relayNb; i = i + 1) {
+ Wire.write(relayMod[i]);
+ Serial.print(relayMod[i]);
+ }
+ Serial.println();
+ }
+}
+
+// Setup :
+void setup() {
+ #ifdef DEBUG
+ // Mise en route du serial
+ Serial.begin(9600);
+ Serial.println("Debug Actif sur le serial");
+ #endif
+ // Déclaration des PIN pour les relays
+ for (byte i = 0; i < relayNb; i = i + 1) {
+ pinMode(relayPin[i], OUTPUT);
+ digitalWrite(relayPin[i],HIGH);
+ }
+
+ Wire.begin(SLAVE_ADDRESS);
+ // define callbacks for i2c communication
+ Wire.onReceive(receiveData);
+ Wire.onRequest(sendData);
+
+ // Pour le debug :
+ #ifdef DEBUG
+ #ifdef MASTERSIMU
+ for (int i = 0; i < relayNb; i++) {
+ if (relayEtat[i] != 3 || relayEtat[i] != 0) {
+ changeMod(i, 2);
+ }
+ }
+ #endif
+ #endif
+
+}
+
+
+int relayOrdreId;
+int relayOrdreEtat;
+
+
+// Loop :
+void loop() {
+
+ // pour le debug
+ #ifdef DEBUG
+ #ifdef MASTERSIMU
+ MasterPresent = true;
+ HeartbeatCheckCount=0;
+ #endif
+ #endif
+
+ // Lecture / réception données
+ HeartbeatCheckCount=HeartbeatCheckCount+1;
+ if ( Serial.available() ) {
+
+ String lu = Serial.readStringUntil('\n');
+
+ // Ordre sur les relay
+ if(lu.substring(0,2) == RelayOrderCode) {
+ if (relayNb <= 10) {
+ relayOrdreId=lu.substring(3,4).toInt();
+ relayOrdreEtat=lu.substring(5,6).toInt();
+ } else {
+ relayOrdreId=lu.substring(3,5).toInt();
+ relayOrdreEtat=lu.substring(6,7).toInt();
+ }
+ #ifdef DEBUG
+ // Exemple d'ordre : RO:2=1 (le relay 2 passe à l'état 1)
+ Serial.print("Reception d'un ordre pour les relay : ");
+ Serial.print(relayOrdreId);
+ Serial.print(" à passer en état ");
+ Serial.print(relayOrdreEtat);
+ #endif
+ switch (relayOrdreEtat) {
+ // Auto Off
+ case 1:
+ afficheur.setLED(TM1638_COLOR_NONE, relayOrdreId);
+ digitalWrite(relayPin[relayOrdreId],HIGH);
+ relayEtat[relayOrdreId]=1;
+ break;
+ // Auto On
+ case 2:
+ afficheur.setLED(TM1638_COLOR_RED, relayOrdreId);
+ digitalWrite(relayPin[relayOrdreId],LOW);
+ relayEtat[relayOrdreId]=2;
+ break;
+ }
+ }
+
+
+
+
+ }
+
+ if (HeartbeatCheckCount > HeartbeatCheckFreq && MasterPresent == true) {
+ #ifdef DEBUG
+ Serial.println("Hearbeat non reçu, l'arduino est débranché");
+ #endif
+ HeartbeatCheckCount=0;
+ MasterPresent = false;
+ // Si on pert le master : On éteind les relays qui était en auto
+ for (int i = 0; i < relayNb; i++) {
+ if (relayMod[i] == 2) {
+ changeMod(i, 0);
+ }
+ }
+ RelayChange = true;
+ }
+
+ // Bouton Action
+ byte etatBoutons;
+ etatBoutons = afficheur.getButtons();
+ for (int i = 0; i < relayNb; i++) {
+ if (bitRead(etatBoutons, i)) {
+ #ifdef DEBUG
+ Serial.print("Action button : ");
+ Serial.println(i);
+ #endif
+ switch (relayMod[i]) {
+ case 0:
+ changeMod(i, 1);
+ break;
+ case 1:
+ if (MasterPresent == true) {
+ changeMod(i, 2);
+ } else {
+ changeMod(i, 3);
+ }
+ break;
+ case 2:
+ changeMod(i, 3);
+ break;
+ case 3:
+ if (MasterPresent == true) {
+ changeMod(i, 1);
+ } else {
+ changeMod(i, 0);
+ }
+ break;
+ }
+ RelayChange = true;
+ delay(500); // Evite le rebond des bouttons
+ }
+
+ }
+
+ // Changement d'etat des relay
+ RelayChangeCount=RelayChangeCount+1;
+ if (RelayChangeCount > RelayChangeFreq) {
+ if (RelayChange == true) {
+ RelayChangeCount=0;
+ #ifdef DEBUG
+ Serial.println((String)"Change relay etat");
+ #endif
+ for (int i = 0; i < relayNb; i++) {
+ changeEtat(i);
+ }
+ RelayChange = false;
+ } else {
+ RelayChangeCount=0;
+ }
+ }
+ delay(50);
+}