diff --git a/config-default.yaml b/config-default.yaml
index 7e94fed..eed4aad 100644
--- a/config-default.yaml
+++ b/config-default.yaml
@@ -1,220 +1,220 @@
######################################################################
# 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://192.168.1.X/data-xml.php # N'utilisez pas 127.0.0.1 mais plutôt l'ip local si vous restez en local (192.168.1.2 ? commande "ip a s" pour l'obtenir, vous ne pouvez pas être en DHCP, mais en IP fixe donc), ou un nom de domain résolu en local et à l'exterieur si c'est publié sur internet
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
checkUpdate: 43200 # false for disable, or seconds checks
# 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 # Check du XML
dbFile: /tmp/PvMonit_domo.sqlite3
i2c:
adress: 0x04
device: 1
heartbeatTime: 4 # Fréquence du bâtement de coeur (en seconde)
fileExpir: 180 # Age en seconde après laquel le fichier n'est plus considéré comme ok
fileCheckError: 5 # nombre d'erreurs sur le xml
xmlDataExpir: 500 # Age en seconde avant expiration des données XML (et donc arrêt du heartbeat)
valueUse:
SOC: ^-?[0-9]+\.?[0-9]+?$|^[0-9]$
P: ^-?[0-9]+\.?[0-9]+?$|^[0-9]$
PPVT: ^-?[0-9]+\.?[0-9]+?$|^[0-9]$
CS: ^Off$|Fault$|Bulk|Faible|Abs|Float|On$
relay:
nb: 5 # 14 max !
- dataFreq: 180 # Délais de récupération des données depuis l'arduino (en secondes)
+ dataFreq: 30 # Délais de récupération des données depuis l'arduino (en secondes)
scriptDir: /opt/PvMonit/domo/relay.script.d
- scriptExecInterval: 180 # Interval d'execution des script de relais
- 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
+ scriptExecInterval: 120 # Interval d'execution des script de relais
+ #~ 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/doc/VE.Direct-Protocol.pdf b/doc/VE.Direct-Protocol.pdf
new file mode 100644
index 0000000..258aaea
Binary files /dev/null and b/doc/VE.Direct-Protocol.pdf differ
diff --git a/function.php b/function.php
index 5d2cedb..9a86b6f 100644
--- a/function.php
+++ b/function.php
@@ -1,744 +1,760 @@
$perso1) {
if ($key1 == 'deviceCorrespondance') {
$config[$key1]=$perso1;
} elseif (is_array($perso1)) {
foreach($perso1 as $key2=>$perso2) {
if (is_array($perso2)) {
foreach($perso2 as $key3=>$perso3) {
if (isset($config[$key1][$key2][$key3])) {
$config[$key1][$key2][$key3]=$perso3;
}
}
}elseif (isset($config[$key1][$key2])) {
$config[$key1][$key2]=$perso2;
}
}
} elseif (isset($config[$key1])) {
$config[$key1]=$perso1;
}
}
return $config;
}
# Victron : détermine le type d'appareil
# Source doc Victron "VE.Direct Protocol"
function ve_type($ve_pid) {
if (substr($ve_pid, 0, -1) == '0x20') {
$ve_type_retour='BMV';
} else if (substr($ve_pid, 0, -2) == '0xA0' || $ve_pid == '0x300') {
$ve_type_retour='MPTT';
} else if (substr($ve_pid, 0, -2) == '0xA2') {
$ve_type_retour='PhoenixInverter';
} else {
$ve_type_retour='Inconnu';
}
return $ve_type_retour;
}
# Victron : détermine le modèle de l'appareil
# Source doc Victron "VE.Direct Protocol"
function ve_modele($ve_pid) {
switch ($ve_pid) {
case '0x203': $ve_modele_retour='BMV-700'; break;
case '0x204': $ve_modele_retour='BMV-702'; break;
case '0x205': $ve_modele_retour='BMV-700H'; break;
case '0xA381': $ve_modele_retour='BMV-712 Smart'; break;
case '0xA04C': $ve_modele_retour='BlueSolar MPPT 75/10'; break;
case '0x300': $ve_modele_retour='BlueSolar MPPT 70/15'; break;
case '0xA042': $ve_modele_retour='BlueSolar MPPT 75/15'; break;
case '0xA043': $ve_modele_retour='BlueSolar MPPT 100/15'; break;
case '0xA044': $ve_modele_retour='BlueSolar MPPT 100/30 rev1'; break;
case '0xA04A': $ve_modele_retour='BlueSolar MPPT 100/30 rev2'; break;
case '0xA041': $ve_modele_retour='BlueSolar MPPT 150/35 rev1'; break;
case '0xA04B': $ve_modele_retour='BlueSolar MPPT 150/35 rev2'; break;
case '0xA04D': $ve_modele_retour='BlueSolar MPPT 150/45'; break;
case '0xA040': $ve_modele_retour='BlueSolar MPPT 75/50'; break;
case '0xA045': $ve_modele_retour='BlueSolar MPPT 100/50 rev1'; break;
case '0xA049': $ve_modele_retour='BlueSolar MPPT 100/50 rev2'; break;
case '0xA04E': $ve_modele_retour='BlueSolar MPPT 150/60'; break;
case '0xA046': $ve_modele_retour='BlueSolar MPPT 150/70'; break;
case '0xA04F': $ve_modele_retour='BlueSolar MPPT 150/85'; break;
case '0xA047': $ve_modele_retour='BlueSolar MPPT 150/100'; break;
case '0xA050': $ve_modele_retour='SmartSolar MPPT 250/100'; break;
case '0xA051': $ve_modele_retour='SmartSolar MPPT 150/100'; break;
case '0xA052': $ve_modele_retour='SmartSolar MPPT 150/85'; break;
case '0xA053': $ve_modele_retour='SmartSolar MPPT 75/15'; break;
case '0xA054': $ve_modele_retour='SmartSolar MPPT 75/10'; break;
case '0xA055': $ve_modele_retour='SmartSolar MPPT 100/15'; break;
case '0xA056': $ve_modele_retour='SmartSolar MPPT 100/30'; break;
case '0xA057': $ve_modele_retour='SmartSolar MPPT 100/50'; break;
case '0xA058': $ve_modele_retour='SmartSolar MPPT 150/35'; break;
case '0xA059': $ve_modele_retour='SmartSolar MPPT 150/100 rev2'; break;
case '0xA05A': $ve_modele_retour='SmartSolar MPPT 150/85 rev2'; break;
case '0xA05B': $ve_modele_retour='SmartSolar MPPT 250/70'; break;
case '0xA05C': $ve_modele_retour='SmartSolar MPPT 250/85'; break;
case '0xA05D': $ve_modele_retour='SmartSolar MPPT 250/60'; break;
case '0xA05E': $ve_modele_retour='SmartSolar MPPT 250/45'; break;
case '0xA05F': $ve_modele_retour='SmartSolar MPPT 100/20'; break;
case '0xA060': $ve_modele_retour='SmartSolar MPPT 100/20 48V'; break;
case '0xA061': $ve_modele_retour='SmartSolar MPPT 150/45'; break;
case '0xA062': $ve_modele_retour='SmartSolar MPPT 150/60'; break;
case '0xA063': $ve_modele_retour='SmartSolar MPPT 150/70'; break;
case '0xA064': $ve_modele_retour='SmartSolar MPPT 250/85 rev2'; break;
case '0xA065': $ve_modele_retour='SmartSolar MPPT 250/100 rev2'; break;
case '0xA201': $ve_modele_retour='Phoenix Inverter 12V 250VA 230V'; break;
case '0xA202': $ve_modele_retour='Phoenix Inverter 24V 250VA 230V'; break;
case '0xA204': $ve_modele_retour='Phoenix Inverter 48V 250VA 230V'; break;
case '0xA211': $ve_modele_retour='Phoenix Inverter 12V 375VA 230V'; break;
case '0xA212': $ve_modele_retour='Phoenix Inverter 24V 375VA 230V'; break;
case '0xA214': $ve_modele_retour='Phoenix Inverter 48V 375VA 230V'; break;
case '0xA221': $ve_modele_retour='Phoenix Inverter 12V 500VA 230V'; break;
case '0xA222': $ve_modele_retour='Phoenix Inverter 24V 500VA 230V'; break;
case '0xA224': $ve_modele_retour='Phoenix Inverter 48V 500VA 230V'; break;
case '0xA231': $ve_modele_retour='Phoenix Inverter 12V 250VA 230V'; break;
case '0xA232': $ve_modele_retour='Phoenix Inverter 24V 250VA 230V'; break;
case '0xA234': $ve_modele_retour='Phoenix Inverter 48V 250VA 230V'; break;
case '0xA239': $ve_modele_retour='Phoenix Inverter 12V 250VA 120V'; break;
case '0xA23A': $ve_modele_retour='Phoenix Inverter 24V 250VA 120V'; break;
case '0xA23C': $ve_modele_retour='Phoenix Inverter 48V 250VA 120V'; break;
case '0xA241': $ve_modele_retour='Phoenix Inverter 12V 375VA 230V'; break;
case '0xA242': $ve_modele_retour='Phoenix Inverter 24V 375VA 230V'; break;
case '0xA244': $ve_modele_retour='Phoenix Inverter 48V 375VA 230V'; break;
case '0xA249': $ve_modele_retour='Phoenix Inverter 12V 375VA 120V'; break;
case '0xA24A': $ve_modele_retour='Phoenix Inverter 24V 375VA 120V'; break;
case '0xA24C': $ve_modele_retour='Phoenix Inverter 48V 375VA 120V'; break;
case '0xA251': $ve_modele_retour='Phoenix Inverter 12V 500VA 230V'; break;
case '0xA252': $ve_modele_retour='Phoenix Inverter 24V 500VA 230V'; break;
case '0xA254': $ve_modele_retour='Phoenix Inverter 48V 500VA 230V'; break;
case '0xA259': $ve_modele_retour='Phoenix Inverter 12V 500VA 120V'; break;
case '0xA25A': $ve_modele_retour='Phoenix Inverter 24V 500VA 120V'; break;
case '0xA25C': $ve_modele_retour='Phoenix Inverter 48V 500VA 120V'; break;
case '0xA261': $ve_modele_retour='Phoenix Inverter 12V 800VA 230V'; break;
case '0xA262': $ve_modele_retour='Phoenix Inverter 24V 800VA 230V'; break;
case '0xA264': $ve_modele_retour='Phoenix Inverter 48V 800VA 230V'; break;
case '0xA269': $ve_modele_retour='Phoenix Inverter 12V 800VA 120V'; break;
case '0xA26A': $ve_modele_retour='Phoenix Inverter 24V 800VA 120V'; break;
case '0xA26C': $ve_modele_retour='Phoenix Inverter 48V 800VA 120V'; break;
case '0xA271': $ve_modele_retour='Phoenix Inverter 12V 1200VA 230V'; break;
case '0xA272': $ve_modele_retour='Phoenix Inverter 24V 1200VA 230V'; break;
case '0xA274': $ve_modele_retour='Phoenix Inverter 48V 1200VA 230V'; break;
case '0xA279': $ve_modele_retour='Phoenix Inverter 12V 1200VA 120V'; break;
case '0xA27A': $ve_modele_retour='Phoenix Inverter 24V 1200VA 120V'; break;
case '0xA27C': $ve_modele_retour='Phoenix Inverter 48V 1200VA 120V'; break;
default; $ve_modele_retour = 'Inconnu'; break;
}
return $ve_modele_retour;
}
# Victron : détermine plein de trucs en fonction du label
# Source doc Victron "VE.Direct Protocol"
function ve_label2($label, $valeur) {
global $config;
$veData['label']=$label;
$veData['desc']=$label;
$veData['value']=$valeur;
$veData['units']='';
$veData['screen']=0;
$veData['smallScreen']=0;
if (in_array($label, $config['www']['dataPrimaire'])) {
$veData['screen']=1;
}
if (in_array($label, $config['www']['dataPrimaireSmallScreen'])) {
$veData['smallScreen']=1;
}
switch ($label) {
case 'V':
$veData['value']=round($valeur*0.001, 2);
$veData['desc']='Tension de la batterie';
$veData['units']='V';
break;
- case 'I':
+ case 'VS':
+ $veData['desc']='Auxiliary (starter) voltage';
$veData['value']=$valeur*0.001;
- $veData['desc']='Courant de la batterie';
- $veData['units']='A';
+ $veData['units']='V';
break;
- case 'PPV':
- $veData['desc']='Production des panneaux';
- $veData['descShort']='PV';
- $veData['units']='W';
+ case 'VM':
+ $veData['desc']='Mid-point voltage of the battery bank';
+ $veData['value']=$valeur*0.001;
+ $veData['units']='V';
break;
- case 'ERR':
- $veData['desc']='Présence d\'erreur';
- if ($valeur == 0) {
- $veData['value']='Aucune';
- } else {
- switch ($veData['value']) {
- case 2: $veData['value'] = 'Battery voltage too high'; break;
- case 17: $veData['value'] = 'Charger temperature too high'; break;
- case 18: $veData['value'] = 'Charger over current'; break;
- case 19: $veData['value'] = 'Charger current reversed'; break;
- case 20: $veData['value'] = 'Bulk time limit exceeded'; break;
- case 21: $veData['value'] = 'Current sensor issue (sensor bias/sensor broken)'; break;
- case 26: $veData['value'] = 'Terminals overheated'; break;
- case 33: $veData['value'] = 'Input voltage too high (solar panel)'; break;
- case 34: $veData['value'] = 'Input current too high (solar panel)'; break;
- case 38: $veData['value'] = 'Input shutdown (due to excessive battery voltage)'; break;
- case 116: $veData['value'] = 'Factory calibration data lost'; break;
- case 117: $veData['value'] = 'Invalid/incompatible firmware'; break;
- case 119: $veData['value'] = 'User settings invalid'; break;
- default: $veData['value'] = $dataSplit[1]; break;
- }
- }
+ case 'DM':
+ $veData['desc']='Mid-point deviation of the battery bank';
+ $veData['units']='%';
break;
case 'VPV':
$veData['desc']='Voltage des panneaux';
$veData['units']='mV';
break;
- case 'H19':
- $veData['value']=$valeur*0.01;
- $veData['desc']='Le rendement total';
- $veData['units']='kWh';
- break;
- case 'H20':
- $veData['value']=$valeur*0.01;
- $veData['desc']='Rendement aujourd\'hui';
- $veData['units']='kWh';
- break;
- case 'H21':
- $veData['desc']='Puissance maximum ce jour';
- $veData['units']='W';
- break;
- case 'H22':
- $veData['value']=$valeur*0.01;
- $veData['desc']='Rendement hier';
- $veData['units']='kWh';
- break;
- case 'H23':
- $veData['desc']='Puissance maximum hier';
+ case 'PPV':
+ $veData['desc']='Production des panneaux';
+ $veData['descShort']='PV';
$veData['units']='W';
break;
- case 'AR':
- $veData['desc']='Raison de l\'alarme';
- switch ($veData['value']) {
- case 0: $veData['value']= 'Aucune'; break;
- case 1: $veData['value']= 'Low Voltage'; break;
- case 2: $veData['value']= 'High Voltage'; break;
- case 4: $veData['value']= 'Low SOC'; break;
- case 8: $veData['value']= 'Low Starter Voltage'; break;
- case 16: $veData['value']= 'High Starter Voltage'; break;
- case 32: $veData['value']= 'Low Temperature'; break;
- case 64: $veData['value']= 'High Temperature'; break;
- case 128: $veData['value']= 'Mid Voltage'; break;
- case 256: $veData['value']= 'Overload'; break;
- case 512: $veData['value']= 'DC-ripple'; break;
- case 1024: $veData['value']= 'Low V AC out'; break;
- case 2048: $veData['value']= 'High V AC out'; break;
- }
+ case 'I':
+ $veData['value']=$valeur*0.001;
+ $veData['desc']='Courant de la batterie';
+ $veData['units']='A';
break;
- case 'CS':
- $veData['desc']='Status de charge';
- switch ($veData['value']) {
- case 0: $veData['value']= 'Off'; break;
- case 1: $veData['value']= 'Faible puissance'; break;
- case 2: $veData['value']= 'Fault'; break;
- case 3: $veData['value']= 'Bulk (en charge)'; break;
- case 4: $veData['value']= 'Absorption'; break;
- case 5: $veData['value']= 'Float (maintient la charge pleine)'; break;
- case 9: $veData['value']= 'On'; break;
- }
+ case 'IL':
+ $veData['value']=$valeur*0.001;
+ $veData['desc']='Courant de charge';
+ $veData['units']='A';
break;
- case 'P':
- $veData['desc']='Puissance instantané';
- $veData['units']='W';
+ case 'LOAD':
+ $veData['value']=$valeur;
+ $veData['desc']='Charge sortie status';
break;
case 'T':
$veData['desc']='Température de la batterie';
$veData['units']='°C';
break;
- case 'VM':
- $veData['desc']='Mid-point voltage of the battery bank';
- $veData['value']=$valeur*0.001;
- $veData['units']='V';
- break;
- case 'DM':
- $veData['desc']='Mid-point deviation of the battery bank';
- $veData['units']='%';
- break;
- case 'H17':
- $veData['desc']='Quantité d\'énergie déchargée';
- $veData['value']=$valeur*0.01;
- $veData['units']='kWh';
- break;
- case 'H18':
- $veData['desc']='Quantité d\'énergie chargée';
- $veData['value']=$valeur*0.01;
- $veData['units']='kWh';
- break;
- case 'H13':
- $veData['desc']='Number of low auxiliary voltage alarms';
- break;
- case 'H14':
- $veData['desc']='Number of high auxiliary voltage alarms';
- break;
- case 'VS':
- $veData['desc']='Auxiliary (starter) voltage';
- $veData['value']=$valeur*0.001;
- $veData['units']='V';
+ case 'P':
+ $veData['desc']='Puissance instantané';
+ $veData['units']='W';
break;
case 'CE':
$veData['desc']='Ampères heures consommées';
$veData['value']=$valeur*0.001;
$veData['units']='Ah';
break;
case 'SOC':
$veData['desc']='État de charge';
$veData['value']=$valeur/10;
$veData['units']='%';
break;
case 'TTG':
if ($veData['value'] == '-1') {
$veData['value'] = '∞';
} else {
$total=$veData['value']*60;
$jours=floor($total/86400);
$reste=$total%86400;
$heures=floor($reste/3600);
$reste=$reste%3600;
$minutes=floor($reste/60);
$secondes=$reste%60;
if ($veData['value'] > 1440) {
$veData['value'] = $jours . 'j '. $heures. 'h ' . $minutes .'m';
} else {
$veData['value'] = '.'.$heures. 'h ' . $minutes .'m';
}
}
$veData['desc']='Temps restant';
break;
case 'Alarm':
$veData['desc']='Condition d\'alarme active';
break;
+ case 'Relay':
+ $veData['desc']='Etat du relai';
+ break;
+ case 'AR':
+ $veData['desc']='Raison de l\'alarme';
+ switch ($veData['value']) {
+ case 0: $veData['value']= 'Aucune'; break;
+ case 1: $veData['value']= 'Low Voltage'; break;
+ case 2: $veData['value']= 'High Voltage'; break;
+ case 4: $veData['value']= 'Low SOC'; break;
+ case 8: $veData['value']= 'Low Starter Voltage'; break;
+ case 16: $veData['value']= 'High Starter Voltage'; break;
+ case 32: $veData['value']= 'Low Temperature'; break;
+ case 64: $veData['value']= 'High Temperature'; break;
+ case 128: $veData['value']= 'Mid Voltage'; break;
+ case 256: $veData['value']= 'Overload'; break;
+ case 512: $veData['value']= 'DC-ripple'; break;
+ case 1024: $veData['value']= 'Low V AC out'; break;
+ case 2048: $veData['value']= 'High V AC out'; break;
+ }
+ break;
case 'H1':
$veData['desc']='Profondeur de la décharge la plus profonde';
$veData['value']=$valeur*0.001;
$veData['units']='Ah';
break;
case 'H2':
$veData['desc']='Profondeur de la dernière décharge';
$veData['value']=$valeur*0.001;
$veData['units']='Ah';
break;
case 'H3':
$veData['desc']='Profondeur de la décharge moyenne';
$veData['value']=$valeur*0.001;
$veData['units']='Ah';
break;
case 'H4':
$veData['desc']='Nombre de cycles de charge';
break;
case 'H5':
$veData['desc']='Nombre de cycles de décharge';
break;
case 'H6':
$veData['desc']='Cumulative Amp Hours drawn';
$veData['value']=$valeur*0.001;
$veData['units']='Ah';
break;
case 'H7':
$veData['desc']='Tension minimale batterie';
$veData['value']=$valeur*0.001;
$veData['units']='V';
break;
case 'H8':
$veData['desc']='Tension maximale de la batterie';
$veData['value']=$valeur*0.001;
$veData['units']='V';
break;
case 'H9':
$veData['desc']='Nombre de secondes depuis la dernière charge complète';
$veData['units']='s';
break;
case 'H10':
$veData['desc']='Nombre de synchronisations automatiques';
break;
case 'H11':
$veData['desc']='Nombre d\'alarmes de tension faible';
break;
case 'H12':
$veData['desc']='Nombre d\'alarmes de tension élevée';
break;
case 'H13':
- $veData['desc']='Minimum auxiliary (battery) voltage';
+ $veData['desc']='Nombre d\'alarmes de tension faible sur l`auxiliaire';
+ break;
+ case 'H14':
+ $veData['desc']='Nombre d\'alarmes de tension élevée sur l`auxiliaire';
+ break;
+ case 'H15':
+ $veData['desc']='Tension minimale batterie auxiliaire';
$veData['value']=$valeur*0.001;
$veData['units']='V';
break;
- case 'H13':
- $veData['desc']='Maximum auxiliary (battery) voltage';
+ case 'H16':
+ $veData['desc']='Tension maximale de la batterie auxiliaire';
$veData['value']=$valeur*0.001;
$veData['units']='V';
break;
+ case 'H17':
+ $veData['desc']='Quantité d\'énergie déchargée';
+ $veData['value']=$valeur*0.01;
+ $veData['units']='kWh';
+ break;
+ case 'H18':
+ $veData['desc']='Quantité d\'énergie chargée';
+ $veData['value']=$valeur*0.01;
+ $veData['units']='kWh';
+ break;
+ case 'H19':
+ $veData['value']=$valeur*0.01;
+ $veData['desc']='Le rendement total';
+ $veData['units']='kWh';
+ break;
+ case 'H20':
+ $veData['value']=$valeur*0.01;
+ $veData['desc']='Rendement aujourd\'hui';
+ $veData['units']='kWh';
+ break;
+ case 'H21':
+ $veData['desc']='Puissance maximum ce jour';
+ $veData['units']='W';
+ break;
+ case 'H22':
+ $veData['value']=$valeur*0.01;
+ $veData['desc']='Rendement hier';
+ $veData['units']='kWh';
+ break;
+ case 'H23':
+ $veData['desc']='Puissance maximum hier';
+ $veData['units']='W';
+ break;
+
+ case 'ERR':
+ $veData['desc']='Présence d\'erreur';
+ if ($valeur == 0) {
+ $veData['value']='Aucune';
+ } else {
+ switch ($veData['value']) {
+ case 2: $veData['value'] = 'Battery voltage too high'; break;
+ case 17: $veData['value'] = 'Charger temperature too high'; break;
+ case 18: $veData['value'] = 'Charger over current'; break;
+ case 19: $veData['value'] = 'Charger current reversed'; break;
+ case 20: $veData['value'] = 'Bulk time limit exceeded'; break;
+ case 21: $veData['value'] = 'Current sensor issue (sensor bias/sensor broken)'; break;
+ case 26: $veData['value'] = 'Terminals overheated'; break;
+ case 33: $veData['value'] = 'Input voltage too high (solar panel)'; break;
+ case 34: $veData['value'] = 'Input current too high (solar panel)'; break;
+ case 38: $veData['value'] = 'Input shutdown (due to excessive battery voltage)'; break;
+ case 116: $veData['value'] = 'Factory calibration data lost'; break;
+ case 117: $veData['value'] = 'Invalid/incompatible firmware'; break;
+ case 119: $veData['value'] = 'User settings invalid'; break;
+ default: $veData['value'] = $dataSplit[1]; break;
+ }
+ }
+ break;
+ case 'CS':
+ $veData['desc']='Status de charge';
+ switch ($veData['value']) {
+ case 0: $veData['value']= 'Off'; break;
+ case 1: $veData['value']= 'Faible puissance'; break;
+ case 2: $veData['value']= 'Fault'; break;
+ case 3: $veData['value']= 'Bulk (en charge)'; break;
+ case 4: $veData['value']= 'Absorption'; break;
+ case 5: $veData['value']= 'Float (maintient la charge pleine)'; break;
+ case 9: $veData['value']= 'On'; break;
+ }
+ break;
+ case 'HSDS':
+ $veData['desc']='Numéro de séquence du jour';
+ break;
case 'MODE':
$veData['desc']='Device mode';
switch ($veData['value']) {
case 2: $veData['value']= 'Inverter'; break;
case 4: $veData['value']= 'Off'; break;
case 5: $veData['value']= 'Eco'; break;
}
break;
case 'AC_OUT_V':
$veData['value']=$valeur*0.01;
$veData['desc']='AC output voltage';
$veData['units']='V';
break;
case 'AC_OUT_I':
$veData['desc']='AC output current';
$veData['value']=$valeur*0.1;
$veData['units']='A';
break;
case 'WARN':
$veData['desc']='Warning reason';
break;
}
return $veData;
}
function ve_nom($ve_serial) {
global $config;
$ve_nom=$ve_serial;
foreach ($config['deviceCorrespondance'] as $serialName => $nom) {
if ($ve_serial == $serialName) {
$ve_nom=$nom;
}
}
return $ve_nom;
}
# Fonction vedirect MPTT / BMV
function vedirect_scan() {
global $config;
trucAdir(4, 'Recherche de périphérique vedirect');
$idDevice=0;
foreach (scandir('/dev') as $unDev) {
if (substr($unDev, 0, 6) == 'ttyUSB') {
trucAdir(4, 'Un périphérique TTY à été trouvé : '.$unDev);
unset($vedirect_sortie);
unset($vedirect_retour);
exec($config['vedirect']['usb']['bin'].' /dev/'.$unDev, $vedirect_sortie, $vedirect_retour);
if ($vedirect_retour != 0){
trucAdir(1, 'Erreur à l\'exécution du script '.VEDIRECT_BIN.' sur le '.$unDev);
} else {
// Pour gérer le BMV-600
$BMV600=false;
$ve_nom=null;
$ve_type='Inconnu';
$ve_modele='Inconnu';
foreach ($vedirect_sortie as $vedirect_ligne) {
$vedirect_data = explode(':', $vedirect_ligne);
switch ($vedirect_data[0]) {
case 'PID':
$ve_type=ve_type($vedirect_data[1]);
$ve_modele=ve_modele($vedirect_data[1]);
break;
case 'SER#':
$ve_serial=$vedirect_data[1];
$ve_nom=ve_nom($vedirect_data[1]);
break;
case 'BMV':
$ve_type='BMV';
$ve_nom=str_replace(' ', '', $vedirect_data[1]);
break;
}
}
trucAdir(3, 'C\'est un '.$ve_type.', modèle "'.$ve_modele.'" du nom de '.$ve_nom);
$vedirect_data_formate='';
foreach ($vedirect_sortie as $vedirect_ligne) {
$vedirect_data = explode(':', $vedirect_ligne);
switch ($ve_type) {
case 'MPTT':
if (in_array($vedirect_data[0], $config['vedirect']['data_ok']['mppt'])) {
# éviter les doublons
if (!stristr($vedirect_data_formate, $vedirect_data[0].':')) {
trucAdir(5, 'Valeur trouvé : '.$vedirect_data[0].':'.$vedirect_data[1]);
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$vedirect_data[0].':'.$vedirect_data[1];
} else {
trucAdir(5, 'Doublon, on passe');
}
}
break;
case 'BMV':
if (in_array($vedirect_data[0], $config['vedirect']['data_ok']['bmv'])) {
# éviter les doublons
if (!stristr($vedirect_data_formate, $vedirect_data[0].':')) {
trucAdir(5, 'Valeur trouvé : '.$vedirect_data[0].':'.$vedirect_data[1]);
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$vedirect_data[0].':'.$vedirect_data[1];
} else {
trucAdir(5, 'Doublon, on passe');
}
}
break;
case 'PhoenixInverter':
if (in_array($key, $config['vedirect']['data_ok']['phoenix'])) {
# éviter les doublons
if (!stristr($vedirect_data_formate, $vedirect_data[0].':')) {
trucAdir(5, 'Valeur trouvé : '.$vedirect_data[0].':'.$vedirect_data[1]);
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$key.':'.$value;
} else {
trucAdir(5, 'Doublon, on passe');
}
}
break;
default:
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$key.':'.$value;
}
}
trucAdir(3, 'Les données sont formatées comme ceci : '.$vedirect_data_formate );
$vedirect_scan_return[$idDevice]['nom']=$ve_nom;
$vedirect_scan_return[$idDevice]['type']=$ve_type;
$vedirect_scan_return[$idDevice]['serial']=$ve_serial;
$vedirect_scan_return[$idDevice]['modele']=$ve_modele;
$vedirect_scan_return[$idDevice]['data']=$vedirect_data_formate;
$idDevice++;
}
}
}
return $vedirect_scan_return;
}
function vedirect_parse_arduino($data) {
global $config;
// Pour gérer le BMV-600
$BMV600=false;
$ve_nom=null;
$ve_type='Inconnu';
$ve_modele='Inconnu';
$ve_serial='Inconnu';
foreach ($data as $key => $value) {
switch ($key) {
case 'PID':
$ve_type=ve_type($value);
$ve_modele=ve_modele($value);
break;
case 'SER#':
$ve_serial=$value;
$ve_nom=ve_nom($value);
break;
case 'BMV':
$ve_type='BMV';
$ve_nom=$value;
break;
}
}
trucAdir(3, 'C\'est un '.$ve_type.', modèle "'.$ve_modele.'" du nom de '.$ve_nom);
$vedirect_data_formate='';
krsort($data);
foreach ($data as $key => $value) {
switch ($ve_type) {
case 'MPTT':
if (in_array($key, $config['vedirect']['data_ok']['mppt'])) {
# éviter les doublons
if (!stristr($vedirect_data_formate, "$key:$value")) {
trucAdir(5, 'Valeur trouvé : '.$key.':'.$value);
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$key.':'.$value;
} else {
trucAdir(5, 'Doublon, on passe');
}
}
break;
case 'BMV':
if (in_array($key, $config['vedirect']['data_ok']['bmv'])) {
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$key.':'.$value;
}
break;
case 'PhoenixInverter':
if (in_array($key, $config['vedirect']['data_ok']['phoenix'])) {
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$key.':'.$value;
}
break;
default:
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$key.':'.$value;
}
}
trucAdir(3, 'Les données sont formatées comme ceci : '.$vedirect_data_formate );
$vedirect_scan_return['nom']=$ve_nom;
$vedirect_scan_return['type']=$ve_type;
$vedirect_scan_return['serial']=$ve_serial;
$vedirect_scan_return['modele']=$ve_modele;
$vedirect_scan_return['data']=$vedirect_data_formate;
return $vedirect_scan_return;
}
# Fonction de debug
function trucAdir($niveau, $msg) {
global $config;
if ($config['printMessage'] >= $niveau) {
if (isset($_SERVER['SERVER_NAME'])) {
echo '';
} else {
echo date('c') . ' - ' . $msg."\n";
}
}
if ($config['printMessageLogfile'] != false) {
if (! is_file($config['printMessageLogfile'])) {
touch($config['printMessageLogfile']);
if (substr(sprintf('%o', fileperms($config['printMessageLogfile'])), -3) != '777') {
chmod($config['printMessageLogfile'], 0777);
}
}
file_put_contents($config['printMessageLogfile'], date('c') . ' - ' . $_SERVER['SCRIPT_NAME']. ' - ' . $msg . "\n", FILE_APPEND);
}
}
# Récupérer les informations de la sonde de température
function Temperature_USB($TEMPERV14_BIN) {
global $config;
# Exécussion du programme pour récupérer les inforamtions de la sonde de température
exec($TEMPERV14_BIN, $temperv14_sortie, $temperv14_retour);
if ($temperv14_retour != 0){
trucAdir(3, 'La sonde de température n\'est probablement pas connecté.');
trucAdir(5, 'Erreur '.$temperv14_retour.' à l\'exécussion du programme .'.$TEMPERV14_BIN);
$temperature_retour='NODATA';
} else {
trucAdir(4, 'La sonde de température indique '.$temperv14_sortie[0].'°C, il y aura peut être correction.');
$temperature_retour=$temperv14_sortie[0];
}
return $temperature_retour;
}
function Amp_USB($bin) {
global $config;
$consommation_retour='NODATA';
for ($i = 1; $i <= 3; $i++) {
trucAdir(3, 'Tentative '.$i.' de récupération de la sonde ');
exec($bin.' | sed "s/A//" 2>/dev/null', $exec_consommation_sortie, $exec_consommation_retour);
if ($exec_consommation_retour != 0){
trucAdir(3, 'L\'amphèrmètre n\'est probablement pas connecté.');
trucAdir(5, 'Erreur '.$exec_consommation_retour.' avec pour sortie .'.$exec_consommation_sortie);
} else {
if ($exec_consommation_sortie[0] != '') {
trucAdir(3, 'Trouvé à la tentative '.$i.' : la La consommation trouvé est '.$exec_consommation_sortie[0].'A');
$re = '/^[0-9][0-9]+.[0-9]$/';
if (!preg_match_all($re, $exec_consommation_sortie[0])) {
trucAdir(5, 'La vérification par expression régulière à échoué ('.$re.')');
} else {
$conso_en_w=$exec_consommation_sortie[0]*230;
trucAdir(1, 'La consommation est de '.$exec_consommation_sortie[0].'A soit '.$conso_en_w.'W');
if ($conso_en_w > $config['consoPlafond']) {
trucAdir(1, 'C`est certainement une erreur, le plafond possible est atteind');
} else {
$consommation_retour=$exec_consommation_sortie[0];
}
}
break;
} else {
trucAdir(5, 'Echec à la tentative '.$i.' : la La consommation trouvé est null');
sleep(1);
}
}
}
return $consommation_retour;
}
// Class source : http://abhinavsingh.com/how-to-use-locks-in-php-cron-jobs-to-avoid-cron-overlaps/
class cronHelper {
private static $pid;
function __construct() {}
function __clone() {}
private static function isrunning() {
$pids = explode(PHP_EOL, `ps -e | awk '{print $1}'`);
if(in_array(self::$pid, $pids))
return TRUE;
return FALSE;
}
public static function lock() {
global $config;
global $argv;
$lock_file = $config['emoncms']['lockFile'];
if(file_exists($lock_file)) {
//return FALSE;
// Is running?
self::$pid = file_get_contents($lock_file);
if(self::isrunning()) {
error_log("==".self::$pid."== Already in progress...");
return FALSE;
}
else {
error_log("==".self::$pid."== Previous job died abruptly...");
}
}
self::$pid = getmypid();
file_put_contents($lock_file, self::$pid);
//error_log("==".self::$pid."== Lock acquired, processing the job...");
return self::$pid;
}
public static function unlock() {
global $argv;
global $config;
$lock_file = $config['emoncms']['lockFile'];
if(file_exists($lock_file))
unlink($lock_file);
//error_log("==".self::$pid."== Releasing lock...");
return TRUE;
}
}
// Check cache expire
function checkCacheTime($file) {
global $config;
if (!is_dir($config['cache']['dir'])) {
mkdir($config['cache']['dir'], 0777);
chmod($config['cache']['dir'], 0777);
}
if (!is_file($file)) {
return false;
} else if (filemtime($file)+$config['cache']['time'] < time()) {
return false;
} else if (isset($_GET['nocache'])) {
return false;
} else {
return true;
}
}
?>