diff --git a/CHANGELOG.md b/CHANGELOG.md
index ada391e..f37bb97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,21 +1,23 @@
# Changelog
-
+ * V3.2 (05/2020)
+ * Amélioration à la génération du fichier XML (système de cache et de vérification des données minimum) pour limiter les risques d'erreurs de génération dû a l'interface Serial vers les appareils solaires
+
* V3.1 (04/2020)
* Support des WKS (via USB)
* V3.0 (04/2020)
* Intégration de [Blockly](https://developers.google.com/blockly/) pour la conception des scripts de gestion du surplus électrique / domotique
* Service de cloud permet un export de vos données temps réel sur une interface accessible depuis internet (même si vous êtes derrière un routeur xG)
* V2.1 (03/2020)
* Changement structurelle pour le passage par un daemon
* Prise de main à distance possible
* V2.0 (01/2020)
* Domotique pour gérer le surplus d'énergie via des relais
* https://vimeo.com/385514728
* V1.0 (08/2019)
* Collecte des informations via un XML tout les scripts (page web & getForEmoncms le récupère)
* Chargement de la page en ajax, récupération des infos via le XML
* Support d'un LCD adafruit 16*2 pour l'affichage des informations
* V0.X
* Affichage dans interface web en temps réel
* Support câble Ve.direct USB
* Export vers EmonCMS
diff --git a/config-default.yaml b/config-default.yaml
index 207fa4c..3770a4c 100644
--- a/config-default.yaml
+++ b/config-default.yaml
@@ -1,541 +1,556 @@
######################################################################
# PvMonit - By David Mercereau : http://david.mercereau.info/contact/
# Licence BEERWARE
######################################################################
##############################
#
# 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.local/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
+
+#~ dataCheck: # Donnée minimum pour que l'XML soit considéré comme valide
+ #~ PPV: # Production des MPPT
+ #~ regex: (^[0-9]+\.?[0-9]+?$)|(^[0-9]$)
+ #~ number: 2 # Si vous avez 2 MPPT il faut le préciser
+ #~ SOC:
+ #~ regex: (^[0-9]+\.?[0-9]+?$)|(^[0-9]$) # BMV : % SOC
+ #~ P:
+ #~ regex: (^-?[0-9]+\.?[0-9]+?$)|(^-?[0-9]$) # BMV : P
+ #~ PPVT: # Total des PPVT (si plusieurs MPPT
+ #~ regex: (^[0-9]+\.?[0-9]+?$)|(^[0-9]$)
+ #~ CS: # MPPT etat (float, bulk...)
+ #~ regex: ^Off$|Fault$|Bulk|Faible|Abs|Float|On$
+ #~ Relay: # SmartSolar MPPT Relay ou BMV
+ #~ Si aucun regex n'est précisé alors la vérification ne ce fait pas sur la valeur mais uniquement sur la présence de la donnée
cache:
dir: /tmp/PvMonit_cache # in tmpfs
- file_prefix:
- time: 60 # in second
+ expir: 15 # in second
+ expirLimit: 60 # If dataCheck error...
# 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
- Relay
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
- Relay
phoenix:
- P
- CS
- MODE
- AC_OUT_V
- AC_OUT_I
- WARN
wks:
enable: false # Passer a true pour activer
bin: "/usr/bin/sudo /usr/bin/python3 /opt/PvMonit/bin/wks.py" # Script qui récupère les informations du WKS
data:
printAll: true # Afficher toutes les valeurs mêmes si elles n'ont pas de libellé
QPIRI: # Ordre
name: "Paramètre" # Le nom
#~ 1: # La position de 1 à X
#~ id: ConfGirdRatV # Id : doit être unique, sans caractères spéciaux ni espace, ni accent...
#~ desc: "Grid rating voltage" # Description
#~ units: "V" # Unité de messur (V / % / A...)
#~ regex: /^[0-9]+.[0-9]$/ # Regex a valider sinon la valeur ne s'affiche pas, Si pas de regex, pas de validation
#~ hide: true # true = caché, false or null = affiché
1:
id: ConfGirdRatV
desc: "Grid rating voltage"
units: "V"
regex: /^[0-9]+.[0-9]$/
2:
id: GirdRatA
desc: "Grid rating current"
units: "A"
#~ regex: false
#~ hide: true
3:
id: ConfAcOutRV
desc: "AC output rating voltage"
units: "V"
4:
id: ConfAcOutRF
desc: "AC output rating frequency"
units: "Hz"
5:
id: ConfAcOutRI
desc: "AC output rating current"
units: "A"
6:
id: ConfAcOutVA
desc: "AC output rating apparent power"
units: "VA"
7:
id: ConfAcOutRP
desc: "AC output rating active power"
units: "W"
8:
id: ConfBatRV
desc: "Battery rating voltage"
units: "V"
9:
id: ConfBatReCV
desc: "Battery re-charge voltage"
units: "V"
10:
id: ConfBatUV
desc: "Battery under voltage"
units: "V"
11:
id: ConfBatBV
desc: "Battery bulk voltage "
units: "V"
12:
id: ConfBatFV
desc: "Battery float voltage"
units: "V"
13:
id: ConfBatT
desc: "Battery type"
value2text:
0: "AGM"
1: "Flooded"
2: "User"
14:
id: ConfCurMaxACcharge
desc: "Current max AC charging current"
units: "A"
15:
id: ConfCurMaxCharge
desc: "Current max charging current"
units: "A"
16:
id: ConfInputVR
desc: "Input voltage range"
value2text:
0: "Appliance (From 90V to 280V AC)"
1: "UPS (From 170V to 280V AC)"
17:
id: ConfOutputSP
desc: "Output source priority"
value2text:
0: "Utility first"
1: "Solar first"
2: "SBU first"
18:
id: ConfChargeSP
desc: "Charger source priority"
value2text:
0: "Utility first"
1: "Solar first"
2: "Solar + Utility"
3: "Only solar charging permitted"
19:
id: ConfBatReDV
desc: "Battery re-discharge voltage"
units: "V"
QPIGS:
name: "Donnée"
1:
id: GirdV
desc: "Grid voltage"
units: "V"
regex: /^[0-9]+.[0-9]$/
2:
id: GirdF
desc: "Grid frequency"
units: "Hz"
3:
id: ACoutV
desc: "AC output voltage"
units: "V"
4:
id: ACoutF
desc: "AC output frequency"
units: "Hz"
5:
id: ACoutP
desc: "AC output apparent power"
units: "VA"
6:
id: CONSO
desc: "AC output active power"
units: "W"
7:
id: LOAD
desc: "AC output load percent"
units: "%"
8:
id: BusV
desc: "BUS voltage"
units: "V"
9:
id: V
desc: "Battery voltage"
units: "V"
10:
id: Ic
desc: "Battery charging current"
units: "A"
11:
id: SOC
desc: "Battery capacity"
units: "%"
12:
id: BatFloatV
desc: "Battery float voltage"
units: "V"
13:
id: BatVsoc
desc: "Battery voltage from SCC 1"
units: "V"
14:
id: Id
desc: "Battery discharge current"
units: "A"
15:
id: T
desc: "Inverter heat sink temperature"
units: "°C"
16:
id: IPV
desc: "PV Input current 1"
units: "A"
17:
id: VPV
desc: "PV Input voltage 1 "
units: "A"
18:
id: PPV
desc: "PV Charging power 1 "
units: "W"
19:
id: Status
desc: "Device status"
QPIWS:
name: "Alarme"
1:
id: ERR_OC
desc: "Over charge current"
2:
id: ERR_T
desc: "Over temperature"
3:
id: ERR_BVU
desc: "Battery voltage under"
4:
id: ERR_BVH
desc: "Battery voltage high"
5:
id: ERR_PVHL
desc: "PV high loss"
6:
id: ERR_BT
desc: "Battery temperature too low"
7:
id: ERR_BTH
desc: "Battery temperature too high"
8:
id: ERR_PVLL
desc: "PV low loss"
9:
id: ERR_PVHD
desc: "PV high derating"
10:
id: ERR_THD
desc: "Temperature high derating"
11:
id: ERR_BTA
desc: "Battery temperature low alarm"
# 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:
daemon: false
# Interval entre 2 récupération de donnée (en minute)
getInterval: 5
# Interval entre 2 envoi à emoncms
sendInterval: 30
# 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:
# Mot de passe d'accès à la page web
password: false # http://www.passwordtool.hu/md5-password-hash-generator
passwordLife: 86400 # Durée de vie du mot de passe en seconde
# Délais de raffraichissement de la page (en seconde) 300 = 5 minutes
refreshTime: 300
# Max de la jauge voltage batterie (en V)
vbatMax: 17
# 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
- PPV
menu:
-
EmonCMS (historique)
- PvMonit projet
- Soutenir l'auteur
checkUpdate: 43200 # false for disable, or seconds checks
domo: false # Enable domo on web interface ?
domoRefreshTime: 5 # Refresh time domo in second
domoPassword: false # Domo password in MD5 - http://www.passwordtool.hu/md5-password-hash-generator
domoEdit: true # Script edit on web /domo-edit-script.php page
domoEditPassword: false # DomoEdit password in MD5 - http://www.passwordtool.hu/md5-password-hash-generator
help: false # Active l'assistance
domoEditExampleDir: /opt/PvMonit/domo/relay.script.d/example
# Ecran LCD (avec script PvMonit/lcd
lcd:
daemon: false
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:
daemon: false
dataCheckTime: 60 # Check du XML
dbFile: /tmp/PvMonit_domo.sqlite3
jsonFile:
modPath: /tmp/PvMonit_domo_mod
etatPath: /tmp/PvMonit_domo_etat
prefixFileData: /tmp/PvMonit_domo_data_
binGpio: /usr/bin/sudo /usr/bin/gpio
fileExpir: 500 # Age en seconde après laquel le fichier n'est plus considéré comme ok
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]$) # BMV : % SOC
- P: (^-?[0-9]+\.?[0-9]+?$)|(^-?[0-9]$) # BMV : P
- #PPVT: (^[0-9]+\.?[0-9]+?$)|(^[0-9]$) # Total des PPVT (si plusieurs MPPT
- #PPV: (^[0-9]+\.?[0-9]+?$)|(^[0-9]$) # Production des MPPT
- #CS: ^Off$|Fault$|Bulk|Faible|Abs|Float|On$ # MPPT etat (float, bulk...)
- #Relay: ^ON|OFF|on|off|Off|On|0|1$ # SmartSolar MPPT Relay ou BMV
- valueSimu: # Les valeurs pour la simulation blockly des "valueUse"
+ - SOC # BMV : % SOC
+ #~ - P # BMV : P
+ #~ - PPVT # Total des PPVT (si plusieurs MPPT
+ #~ - PPV # Production des MPPT
+ #~ - CS # MPPT etat (float, bulk...)
+ #~ - Relay # SmartSolar MPPT Relay ou BMV
+ valueSimu: # Les valeurs pour la simulation blockly des "valueUse"
SOC:
- type:number
- value:90
- min:0
- max:100
- output:Number
- tooltip:"% des batteries"
Relay:
- type:dropdown
- value:0|1
- output:Number
- tooltip:"Etat du relai (sur le victron)"
CS:
- type:dropdown
- value:Float|Absorption|Bulk|Off|Fault
- output:String
- tooltip:"Statut du régulateur"
P:
- type:number
- value:200
- min:-5000
- max:5000
- output:Number
- tooltip:"Puissance (BMV)"
PPV:
- type:number
- value:400
- min:0
- max:5000
- output:Number
- tooltip:"Puissance des panneaux"
PPVT:
- type:number
- value:400
- min:0
- max:5000
- output:Number
- tooltip:"Puissance total des panneaux"
EXEMPLEINPUT:
- type:input
- value:Test
- output:String
- tooltip:"Juste un exemple d'input"
relay:
scriptDir: /opt/PvMonit/domo/relay.script.d
scriptExecInterval: 60 # Interval d'execution des script de relais
secuDownNoData: 600 # Temps (en seconde) après lequel on coupe tout les relay s'il n'y a pas eu de nouvelle données
relayNb: 8
relayName: # A commencer par 1
1: aDefinir
2: aDefinir
3: aDefinir
4: aDefinir
5: aDefinir
6: aDefinir
7: aDefinir
8: aDefinir
relayWiringPi: # WiringPI is no GPIO number : https://fr.pinout.xyz/pinout/
1: 4
2: 5
3: 10
4: 21
5: 22
6: 27
7: 28
8: 29
relayActionRefresh: 2 # delay (in second) to refresh etat relay (script relay-action.php)
tm1638:
daemon: false
refresh: 0.3
actionButtonDelay: 2 # délais (en seconde) avant que les actions boutton n'est un effet
cloud: # Cloud service, visit http://pvmonit.zici.fr
daemon: false
url: http://pvmonit.zici.fr/id/
api: XXXXXXXXXXXXXXX
sendDelay: 300 # Délai d'envoi de donnée (en seconde)
#~ user: # Ok for text/number/password...
#~ startTime: # name in form
#~ id: startTime
#~ label: "Heure de début"
#~ type: number
#~ value: 1
#~ min: 0
#~ max: 23
#~ step: 1
#~ endTime:
#~ id: startTime
#~ label: "Heure de début"
#~ type: number
#~ value: 6
#~ min: 0
#~ max: 23
#~ step: 1
diff --git a/domo/domo.php b/domo/domo.php
index d7c42b5..690786c 100644
--- a/domo/domo.php
+++ b/domo/domo.php
@@ -1,465 +1,459 @@
timerefresh+$config['domo']['xmlDataExpir'] > time()) {
foreach ($device->datas->data as $data) {
- foreach ($config['domo']['valueUse'] as $id => $regexCheck) {
- if ($data['id'] == $id) {
- $xmlDataTemp = json_decode(json_encode($data->value), true);
- trucAdir(5, 'XML parse : la valeur pour '.$data['id'].' à été trouvé à '.$xmlDataTemp[0]);
- if (preg_match_all('/'.$regexCheck.'/', $xmlDataTemp[0])) {
- $xmlData[$id] = $xmlDataTemp[0];
- } else {
- trucAdir(5, 'XML parse ERROR : La vérification regex pour '.$data['id'].' n\'est pas correct pour la valeur '.$xmlDataTemp[0].' ('.$regexCheck.')');
- $xmlData[$id] = false;
- }
- }
+ $id= (string) $data['id'];
+ $dataString = (string) $data->value;
+ if (in_array($id, $config['domo']['valueUse'])) {
+ trucAdir(5, 'XML parse : la valeur pour '.$id.' à été trouvé à '.$dataString);
+ $xmlData[$id] = $dataString;
}
}
} else {
$xmlData = false;
trucAdir(2, 'Les données sont périmées');
}
}
// On vérifie si toutes les données sont là
if (count($xmlData) < count($config['domo']['valueUse'])) {
trucAdir(5, count($xmlData).' éléments sont trouvés alors que '.count($config['domo']['valueUse']).' éléments sont attendu dans la configuration');
trucAdir(2, 'Toutes les données requisent ne sont pas présentes dans le XML donc on passe notre chemin (vérifier domo/valueUse dans le fichier config.yaml)');
$xmlData = false;
}
} catch (Exception $e ) {
$xmlData = false;
trucAdir(2, 'Impossible de lire l\'XML : '.$e);
}
return $xmlData;
}
function MpptAbsOrFlo($cs, $timeUpNoBago = 10) {
global $config;
if ($timeUpNoBago == 0) {
if (preg_match_all('/^Absorption|^Float/', $cs)) {
return true;
} else {
return false;
}
} else {
$fileCS=$config['domo']['prefixFileData'].'MpptFlo_NoBago'.'_CS_AoF';
$fileTimerNoBago=$config['domo']['prefixFileData'].'MpptFlo_NoBago'.'_timer';
if (preg_match_all('/^Absorption|^Float/', $cs)) {
touch($fileCS);
//~ echo "abs ou float";
return true;
} else {
// Si j'étais en abs ou float j'allume le timer
if (is_file($fileCS)) {
$timer=time();
file_put_contents($fileTimerNoBago, $timer);
unlink($fileCS);
//~ echo "création du timer/suppression du float abs";
return true;
// Si le timer est déjà en route on récupère l'info
} else if (is_file($fileTimerNoBago)) {
$timer=file_get_contents($fileTimerNoBago);
// Le timer à été dépassé
if (time() > $timer+$timeUpNoBago) {
//~ echo "timer dépassé";
unlink($fileTimerNoBago);
return false;
} else {
//~ echo "timer NON dépassé";
return true;
}
// Sinon c'est que le régulateur n'est pas encore passé en abs/float
} else {
//~ echo "régulateur pas encore été en float abs";
return false;
}
}
}
}
function MpptFlo($cs, $timeUpNoBago = 10) {
global $config;
if ($timeUpNoBago == 0) {
if (preg_match_all('/^Float/', $cs)) {
return true;
} else {
return false;
}
} else {
$fileCS=$config['domo']['prefixFileData'].'MpptFlo_NoBago'.'_CS_AoF';
$fileTimerNoBago=$config['domo']['prefixFileData'].'MpptFlo_NoBago'.'_timer';
if (preg_match_all('/^Float/', $cs)) {
touch($fileCS);
//~ echo "abs ou float";
return true;
} else {
// Si j'étais en abs ou float j'allume le timer
if (is_file($fileCS)) {
$timer=time();
file_put_contents($fileTimerNoBago, $timer);
unlink($fileCS);
//~ echo "création du timer/suppression du float abs";
return true;
// Si le timer est déjà en route on récupère l'info
} else if (is_file($fileTimerNoBago)) {
$timer=file_get_contents($fileTimerNoBago);
// Le timer à été dépassé
if (time() > $timer+$timeUpNoBago) {
//~ echo "timer dépassé";
unlink($fileTimerNoBago);
return false;
} else {
//~ echo "timer NON dépassé";
return true;
}
// Sinon c'est que le régulateur n'est pas encore passé en abs/float
} else {
//~ echo "régulateur pas encore été en float abs";
return false;
}
}
}
}
trucAdir(4, 'Lancement du script');
if (!is_file($config['domo']['jsonFile']['etatPath'])) {
genDefaultJsonFile('etat');
}
if (!is_file($config['domo']['jsonFile']['modPath'])) {
genDefaultJsonFile('mod');
}
$initDb=false;
if (!is_file($config['domo']['dbFile'])) {
$initDb=true;
}
// Connect DB
try {
$dbco = new PDO('sqlite:'.$config['domo']['dbFile']);
$dbco->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch ( PDOException $e ) {
die('Connexion à la base : '.$e->getMessage());
}
// Create DB if not exists
if ($initDb==true) {
try {
$create = $dbco->query("CREATE TABLE relay (id INTEGER PRIMARY KEY,
relay_number INTEGER,
info VARCHAR(2),
valeur INTEFER,
date INTEGER,
event TEXT)");
} catch ( PDOException $e ) {
echo 'Error initializing tables. Please contact the admin';
die();
}
}
function logInDb($relay, $info, $valeur, $event) {
global $dbco;
try {
$insertcmd = $dbco->prepare("INSERT INTO relay (relay_number, info, valeur, date, event)
VALUES (:relay, :info, :valeur, ".time().", :event)");
$insertcmd->bindParam('relay', $relay, PDO::PARAM_INT);
$insertcmd->bindParam('info', $info, PDO::PARAM_STR);
$insertcmd->bindParam('valeur', $valeur, PDO::PARAM_INT);
$insertcmd->bindParam('event', $event, PDO::PARAM_STR);
$insertcmd->execute();
} catch ( PDOException $e ) {
echo "DB error : ", $e->getMessage();
die();
}
}
function relayLastUp($relay) {
global $dbco;
return $dbco->query("SELECT date FROM relay WHERE relay_number = ".$relay." AND info = 'E' AND valeur = 1 ORDER BY date DESC LIMIT 1")->fetchColumn();
}
function relayLastUpAuto($relay) {
global $dbco;
return $dbco->query("SELECT date FROM relay WHERE relay_number = ".$relay." AND info = 'M' AND valeur = 2 ORDER BY date DESC LIMIT 1")->fetchColumn();
}
function relayLastDown($relay) {
global $dbco;
return $dbco->query("SELECT date FROM relay WHERE relay_number = ".$relay." AND info = 'E' AND valeur = 0 ORDER BY date DESC LIMIT 1")->fetchColumn();
}
# Est-ce que le relay c'est allumé puis est maintenant éteind aujourd'hui ? (dans les 12 heures)
function relayUpDownToday($relay) {
global $dbco;
$result = $dbco->query("SELECT count(date) FROM relay WHERE relay_number = ".$relay." AND info = 'M' AND (valeur = 1 OR valeur = 2) AND date > ".(time()-43200)." ORDER BY date DESC LIMIT 2")->fetchColumn();
if ($result == 2) {
return true;
} else {
return false;
}
}
# Est-ce que le relay c'est allumé aujourd'hui ? (dans les 12 heures)
function relayUpToday($relay) {
global $dbco;
$result = $dbco->query("SELECT count(date) FROM relay WHERE relay_number = ".$relay." AND info = 'E' AND valeur = 1 AND date > ".(time()-43200)." ORDER BY date DESC LIMIT 1")->fetchColumn();
if ($result >= 1) {
return true;
} else {
return false;
}
}
function timeUpMax($relay, $timeUp) {
if (relayLastUpAuto($relay)+$timeUp < time()) {
return true;
} else {
return false;
}
}
function timeUpMin($relay, $timeUp) {
if (relayLastUpAuto($relay)+$timeUp > time()) {
return true;
} else {
return false;
}
}
# Fonctions Timer
# Contrib @akoirium
function timerStart($name, $time) {
global $config;
trucAdir(3, 'Début du timer '.$name.' pour '.$time.'s');
file_put_contents($config['domo']['prefixFileData'].'timer_'.$name, time()+$time);
}
function timerOn($name) {
global $config;
if (!is_file($config['domo']['prefixFileData'].'timer_'.$name)) {
// Le timer n'a pas été lancé, donc est pas terminé....
trucAdir(2, 'Timer '.$name.' inconnu, on envoi TRUE pour dire que c\'est terminé...');
return true;
} else {
$endTime=file_get_contents($config['domo']['prefixFileData'].'timer_'.$name);
if ($endTime < time()) {
// Timer On
trucAdir(3, 'Timer '.$name.' pas terminé, on envoi FALSE');
return false;
} else {
// Timer Off
trucAdir(3, 'Timer '.$name.' terminé, on envoi TRUE et on supprime le fichier');
@unlink($config['domo']['prefixFileData'].'timer_'.$name);
return true;
}
}
}
$dataCheckTime=0;
$xml_check_error=0;
$downloadNow=false;
$dataRefresh=false;
$relay_script_last_exec = 0;
$lastRefreshMod = 0;
$lastRefreshEtat = 0;
$dernierScriptJoue = 0;
while(true) {
// Gestion du XML
if (!is_file($config['tmpFileDataXml'])) {
trucAdir(2, "Fichier inexistant");
$downloadNow=true;
} else if (filemtime($config['tmpFileDataXml'])+$config['domo']['fileExpir'] < time()) {
trucAdir(2, "Le fichier data est périmé !");
$downloadNow=true;
} elseif ($dataCheckTime+$config['domo']['dataCheckTime'] < time()) {
trucAdir(4, "Préparation du rafraichissement des données");
if (filemtime($config['tmpFileDataXml'])+$config['domo']['dataCheckTime'] > time()) {
trucAdir(5, "Pas de téléchargement, le fichier semble très résent (peut être téléchargé par un autre script... lcd.py ?)");
$dataRefresh=true;
} else {
$downloadNow=true;
}
} else {
if ($xml_check_error == 0) {
$downloadNow=false;
}
}
// Téléchargement
if ($downloadNow == true) {
trucAdir(2, "Téléchargement du fichier xml");
if ($xml_check_error != 0) {
trucAdir(2, "C'est suite à une erreur, on patiente un peu...");
sleep(10);
}
$opts = array('http' =>
array(
'method' => 'GET',
'timeout' => 60
)
);
$context = stream_context_create($opts);
$result = file_get_contents($config['urlDataXml'], false, $context);
file_put_contents($config['tmpFileDataXml'], $result);
$dataRefresh=true;
$downloadNow=false;
}
if ($dataRefresh==true) {
trucAdir(4, "Rafraichissement des données");
$xml_data_get=xml_data_get($config['tmpFileDataXml']);
if ($xml_data_get == null || $xml_data_get == false) {
trucAdir(2, 'Données XML invalide');
$xml_check_error++;
$downloadNow=true;
} else {
$xml_data_error=0;
foreach ($xml_data_get as $id => $xml_data) {
if ($xml_data === false) {
trucAdir(5, 'ERROR donnée '.$id.' est à false');
$xml_data_error++;
}
}
if ($xml_data_error != 0) {
trucAdir(4, 'ERROR Certaine données (dans config.yaml : valueUse) ne sont pas conforme ou pas présente.');
$xml_check_error++;
$downloadNow=true;
} else {
trucAdir(4, 'Les données sont bonnes !');
$xml_check_error=0;
$dataCheckTime=time();
}
}
$dataRefresh=false;
}
// Sécurité, si pas de data pendant trop de temps, on éteind les relay en mod haut
if ($dataCheckTime+$config['domo']['relay']['secuDownNoData'] < time()) {
trucAdir(5, "SECURITE, trop de temps c'est écoulé sans donnée, on passe les relays en mode 2 (auto on) à 1 (auto off)");
$relayModSecu = json_decode(file_get_contents($config['domo']['jsonFile']['modPath']), true);
foreach ($relayModSecu as $relay => $Mod) {
if ($Mod == 2) {
$relayModSecu[$relay] = 1;
}
}
file_put_contents($config['domo']['jsonFile']['modPath'], json_encode($relayModSecu));
}
// Récupération et enregistrement des données de mod
if (filemtime($config['domo']['jsonFile']['modPath']) > $lastRefreshMod) {
trucAdir(4, "Récupération des mods des relay");
$relayMod_New = json_decode(file_get_contents($config['domo']['jsonFile']['modPath']), true);
if (isset($relayMod)) {
foreach (array_diff_assoc($relayMod_New,$relayMod) as $relayIdDiff => $relayModDiff) {
trucAdir(4, "Enregistrement du changement sur le relay ".$relayIdDiff." vers le mod ".$relayModDiff);
if (isset($saveInDb[$relayIdDiff]) && !is_null($saveInDb[$relayIdDiff])) {
trucAdir(4, "Avec le log ".$saveInDb[$relayIdDiff]['log']);
logInDb($relayIdDiff, 'M', $relayModDiff, $saveInDb[$relayIdDiff]['log']);
$saveInDb[$relayIdDiff]=null;
} else {
logInDb($relayIdDiff, 'M', $relayModDiff, '');
}
}
}
$relayMod = $relayMod_New;
$lastRefreshMod=time();
}
// Récupération et enregistrement des données d'état
if (filemtime($config['domo']['jsonFile']['etatPath']) > $lastRefreshEtat) {
trucAdir(4, "Récupération de l'état des relay");
$relayEtat_New = json_decode(file_get_contents($config['domo']['jsonFile']['etatPath']), true);
if (isset($relayEtat)) {
foreach (array_diff_assoc($relayEtat_New,$relayEtat) as $relayIdDiff => $relayEtatDiff) {
trucAdir(4, "Enregistrement du changement sur le relay ".$relayIdDiff." vers l'état ".$relayEtatDiff);
logInDb($relayIdDiff, 'E', $relayEtatDiff, '');
}
}
$relayEtat = $relayEtat_New;
$lastRefreshEtat=time();
}
//
// Traitement, ordre...
//
if ($xml_check_error == 0) {
if ($relay_script_last_exec+$config['domo']['relay']['scriptExecInterval'] < time()) {
if ($config['md5sum'] != md5_file('/opt/PvMonit/config.yaml')) {
trucAdir(1, "Changement dans la configuration, relecture !");
$config = getConfigYaml('/opt/PvMonit');
}
trucAdir(3, "Traitement des ordres");
if (is_array($relayMod) && is_array($relayEtat)) {
foreach ($relayMod as $relay => $Mod) {
//~ if ($relay > $dernierScriptJoue) {
// On s'occupe uniquement de ceux qui sont en mode auto
if ($Mod == 1 || $Mod == 2) {
if (is_file($config['domo']['relay']['scriptDir'].'/'.$relay.'.php')) {
$thisId=$relay;
$thisEtat=$relayEtat[$relay];
$thisMod=$relayMod[$relay];
$data=$xml_data_get;
$script_return = (include $config['domo']['relay']['scriptDir'].'/'.$relay.'.php');
if ($relay == 7) {
//~ var_dump($relayMod[$relay]);
//~ var_dump($script_return);
trucAdir(2, "7 debug : ".$relayMod[$relay]."!=".$script_return['mod']);
}
if ($relayMod[$relay] != $script_return['mod'] && $script_return != null) {
trucAdir(1, "Changement de mod pour le relay ".$relay." (".$thisMod." vers ".$script_return['mod'].")");
trucAdir(2, "Pourquoi ? : ".$script_return['log']);
$relayModPut=$relayMod;
$relayModPut[$relay] = $script_return['mod'];
file_put_contents($config['domo']['jsonFile']['modPath'], json_encode($relayModPut));
$saveInDb[$relay]['mod'] = $script_return['mod'];
$saveInDb[$relay]['log'] = $script_return['log'];
$dernierScriptJoue = $relay;
break;
} else {
trucAdir(3, "Aucun changement d'état pour le relay ".$relay);
if ($script_return['log'] != null) {
trucAdir(3, '['.$thisId.']'.$script_return['log']);
}
}
} else {
trucAdir(5, "Pas de script pour le relay ".$relay);
}
} else {
trucAdir(5, "Le relay ".$relay." n'est pas en mod automatique");
}
//~ }
//~ $dernierScriptJoue = $relay;
}
//~ if ($dernierScriptJoue >= $config['domo']['relayNb']) {
//~ $dernierScriptJoue = 0;
//~ }
} else {
trucAdir(3, "Aucune donnée sur les relay exploitable pour pouvoir lancer des actions");
}
$relay_script_last_exec=time();
}
}
sleep(1);
}
?>
diff --git a/function.php b/function.php
index 9323968..becc207 100644
--- a/function.php
+++ b/function.php
@@ -1,806 +1,806 @@
$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_perso[$key1][$key2][$key3])) {
$config[$key1][$key2][$key3]=$perso3;
}
}
}elseif (isset($config[$key1][$key2])) {
$config[$key1][$key2]=$perso2;
}
}
} elseif (isset($config[$key1])) {
$config[$key1]=$perso1;
}
}
$config['md5sum']=md5_file($config_dir.'/config.yaml');
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';
+ $ve_type_retour='MPPT';
} 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 'VS':
$veData['desc']='Auxiliary (starter) voltage';
$veData['value']=$valeur*0.001;
$veData['units']='V';
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 'VPV':
$veData['desc']='Voltage des panneaux';
$veData['units']='mV';
break;
case 'PPV':
$veData['desc']='Production des panneaux';
$veData['descShort']='PV';
$veData['units']='W';
break;
case 'I':
$veData['value']=$valeur*0.001;
$veData['desc']='Courant de la batterie';
$veData['units']='A';
break;
case 'IL':
$veData['value']=$valeur*0.001;
$veData['desc']='Courant de charge';
$veData['units']='A';
break;
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 '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']='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 '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'; break;
case 4: $veData['value']= 'Absorption'; break;
case 5: $veData['value']= 'Float'; 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;
}
# Hack value
function ve_value($label, $value) {
switch ($label) {
case 'Relay':
if ($value == 'ON') {
$retour = 1;
} else {
$retour = 0;
}
break;
default;
$retour = $value;
break;
}
return $retour;
}
-# Fonction vedirect MPTT / BMV
+# Fonction vedirect MPPT / 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 '.$config['vedirect']['usb']['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':
+ case 'MPPT':
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].':'.ve_value($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].':'.ve_value($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.':'.ve_value($vedirect_data[0], $vedirect_data[1]);
} 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.':'.ve_value($vedirect_data[0], $vedirect_data[1]);
}
}
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':
+ case 'MPPT':
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.':'.ve_value($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.':'.ve_value($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.':'.ve_value($key, $value);
}
break;
default:
if ($vedirect_data_formate != '') {
$vedirect_data_formate = $vedirect_data_formate.',';
}
$vedirect_data_formate = $vedirect_data_formate.$key.':'.ve_value($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";
+ echo date('c') . ' [' . $niveau . '] - ' . $msg."\n";
}
}
if ($config['printMessageLogfile'] != false) {
if (is_file($config['printMessageLogfile']) && filesize($config['printMessageLogfile']) > 10000000) {
unlink($config['printMessageLogfile']);
}
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);
+ file_put_contents($config['printMessageLogfile'], date('c') . ' [' . $niveau . '] - ' . $_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()) {
+ } else if (filemtime($file)+$config['cache']['expir'] < time()) {
return false;
} else if (isset($_GET['nocache'])) {
return false;
} else {
return true;
}
}
# Domo gen json file
function genDefaultJsonFile($type) {
global $config;
if ($type == 'etat') {
$filePath = $config['domo']['jsonFile']['etatPath'];
} elseif ($type == 'mod') {
$filePath = $config['domo']['jsonFile']['modPath'];
}
$relay[] = null;
for ($i = 1; $i <= $config['domo']['relayNb']; $i++) {
if ($type == 'etat') {
$relay[$type][$i] = 0;
} else {
$relay[$type][$i] = 1;
}
}
file_put_contents($filePath, json_encode($relay[$type]));
}
?>
diff --git a/www/data-xml-test.xml b/www/data-xml-test.xml
index d73a58c..5289737 100644
--- a/www/data-xml-test.xml
+++ b/www/data-xml-test.xml
@@ -1,348 +1,348 @@
-
MpttBlanc
1584830098
- MPTT
+ MPPT
BlueSolar MPPT 100/30 rev2
HQ1544WMX65
Voltage des panneaux
10
mV
Tension de la batterie
24.82
V
Production des panneaux
0
W
Courant de la batterie
0
A
Puissance maximum hier
242
W
Rendement hier
0.4
kWh
Puissance maximum ce jour
479
W
Rendement aujourd'hui
0.57
kWh
Le rendement total
370.48
kWh
Présence d'erreur
Aucune
Status de charge
Off
MpttBleu
1584830098
- MPTT
+ MPPT
BlueSolar MPPT 100/30 rev2
HQ16129A5J2
Voltage des panneaux
10
mV
Tension de la batterie
24.8
V
Production des panneaux
0
W
Courant de la batterie
0
A
Puissance maximum hier
341
W
Rendement hier
1.52
kWh
Puissance maximum ce jour
485
W
Rendement aujourd'hui
1.41
kWh
Le rendement total
931.24
kWh
Présence d'erreur
Aucune
Status de charge
Off
700
1584830098
BMV
BMV-700
700
Tension de la batterie
24.77
V
Temps restant
3j 1h 49m
État de charge
94.2
%
Etat du relai
0
Puissance instantané
-54
W
Courant de la batterie
-2.174
A
Nombre de secondes depuis la dernière charge complète
25933
s
Tension maximale de la batterie
29.442
V
Tension minimale batterie
21.238
V
Cumulative Amp Hours drawn
-25246.778
Ah
Nombre de cycles de décharge
0
Nombre de cycles de charge
1
Profondeur de la décharge moyenne
-102.738
Ah
Profondeur de la dernière décharge
-17.731
Ah
Quantité d'énergie chargée
736.05
kWh
Quantité d'énergie déchargée
625.36
kWh
Nombre d'alarmes de tension élevée
0
Nombre d'alarmes de tension faible
0
Nombre de synchronisations automatiques
126
Profondeur de la décharge la plus profonde
-102.738
Ah
Ampères heures consommées
-17.731
Ah
Raison de l'alarme
Aucune
Divers
1584830098
Production total des panneaux
0
W
Consommation du foyer
54
W
1584830023
Humidité TExt
99.90
%
Température TExt
9.60
°C
Température ressentie TExt
9.22
°C
1584830101
Humidité THome
61.8
%
Température THome
20.8
°C
1584830028
Humidité TSol
52.10
%
Température TSol
17.60
°C
Température ressentie TSol
16.78
°C
1584830101
Co2 dans la maison
1546
ppm
-
+
+
diff --git a/www/data-xml.php b/www/data-xml.php
index b098ac9..38783fd 100755
--- a/www/data-xml.php
+++ b/www/data-xml.php
@@ -1,277 +1,341 @@
-
-
-
+';
+
###################################
# Script sous licence BEERWARE
# Version 1.0 2019
###################################
include('/opt/PvMonit/function.php');
+function xmlPrintError($msg) {
+ return '
+
+
+ Erreur
+
+
+
+
+
+
+ Erreur
+ '.$msg.'
+
+
+
+ ';
+}
+
// Chargement de la config
$config = getConfigYaml('/opt/PvMonit');
$config['printMessage']=0;
trucAdir(2, "Appel du data-xml.php");
-function onScreenPrint($name) {
- global $config;
- if (in_array($name, $config['www']['dataPrimaire'])) {
- $screenVal=' screen="1"';
- } else {
- $screenVal= ' screen="0"';
- }
- if (in_array($name, $config['www']['dataPrimaireSmallScreen'])) {
- $screenVal.= ' smallScreen="1"';
- } else {
- $screenVal.= ' smallScreen="0"';
- }
- return $screenVal;
-}
+if (checkCacheTime($config['cache']['dir'].'/data.xml')) {
+ trucAdir(3, 'XML on sert le fichier de cache car il n\'est pas périmé');
+ echo file_get_contents($config['cache']['dir'].'/data.xml');
+} else {
-$ppv_total=null;
-$bmv_p=null;
-$nb_ppv_total=0;
-if ($config['vedirect']['by'] == 'usb') {
- $cache_file=$config['cache']['dir'].'/'.$config['cache']['file_prefix'].'vedirect_scan';
- if(!checkCacheTime($cache_file)) {
- file_put_contents($cache_file, json_encode(vedirect_scan()));
- if (substr(sprintf('%o', fileperms($cache_file)), -3) != '777') {
- chmod($cache_file, 0777);
- }
- }
- $timerefresh=filemtime($cache_file);
- $vedirect_data_ready = json_decode(file_get_contents($cache_file), true);
-} elseif ($config['vedirect']['by'] == 'arduino') {
- if (! is_file($config['vedirect']['arduino']['data_file'])) {
- $vedirect_data_ready[0]['id'] = 'Vedirect serial get by arduino';
- $vedirect_data_ready[0]['nom'] = 'Vedirect erreur';
- $vedirect_data_ready[0]['serial'] = 'vedirect';
- $vedirect_data_ready[0]['data']= 'Fichier de donnée:Introuvable';
- } else if (filemtime($config['vedirect']['arduino']['data_file'])+$config['vedirect']['arduino']['data_file_expir'] < time()) {
- $vedirect_data_ready[0]['id'] = 'Vedirect serial get by arduino';
- $vedirect_data_ready[0]['nom'] = 'Vedirect erreur';
- $vedirect_data_ready[0]['serial'] = 'vedirect';
- $vedirect_data_ready[0]['data']= 'Fichier de donnée :Périmé';
- } else {
- $arduino_data=yaml_parse_file($config['vedirect']['arduino']['data_file']);
- $idDevice=0;
- foreach ($arduino_data as $device_id => $device_data) {
- if (preg_match_all('/^Serial[0-9]$/m', $device_id)) {
- $device_vedirect_data[$idDevice]=vedirect_parse_arduino($device_data);
- $idDevice++;
- }
- }
- $vedirect_data_ready = $device_vedirect_data;
- }
-}
-if ($config['vedirect']['by'] != false) {
- foreach ($vedirect_data_ready as $device) {
- if ($device['serial'] == 'Inconnu' || $device['serial'] == '') {
- $device['serial'] = $device['nom'];
+ function onScreenPrint($name) {
+ global $config;
+ if (in_array($name, $config['www']['dataPrimaire'])) {
+ $screenVal=' screen="1"';
+ } else {
+ $screenVal= ' screen="0"';
}
- echo "\n\t".'';
- echo "\n\t\t".''.$device['nom'].'';
- echo "\n\t\t".''.time().'';
- echo "\n\t\t".''.$device['type'].'';
- echo "\n\t\t".''.$device['modele'].'';
- echo "\n\t\t".''.$device['serial'].'';
- echo "\n\t\t".'';
- sort($device['data']);
- foreach (explode(',', $device['data']) as $data) {
- $dataSplit = explode(':', $data);
- $veData=ve_label2($dataSplit[0], $dataSplit[1]);
- echo "\n\t\t\t".'';
- echo "\n\t\t\t\t".''.$veData['desc'].'';
- echo "\n\t\t\t\t".''.$veData['value'].'';
- echo "\n\t\t\t\t".''.$veData['units'].'';
- echo "\n\t\t\t".'';
- if ($dataSplit[0] == 'PPV'){
- $ppv_total=$ppv_total+$dataSplit[1];
- $nb_ppv_total++;
- }
- if ($device['type'] == "BMV" && $dataSplit[0] == 'P'){
- $bmv_p=$dataSplit[1];
- }
+ if (in_array($name, $config['www']['dataPrimaireSmallScreen'])) {
+ $screenVal.= ' smallScreen="1"';
+ } else {
+ $screenVal.= ' smallScreen="0"';
}
- echo "\n\t\t".'';
- echo "\n\t".'';
+ return $screenVal;
}
-}
-# WKS
-if ($config['wks']['enable'] == true) {
- trucAdir(1, "WKS enable");
- exec($config['wks']['bin'], $wks_sortie, $wks_retour);
- if ($wks_retour != 0){
- trucAdir(1, 'Erreur à l\'exécution du script '.$config['wks']['bin']);
- } else {
- $datas = json_decode($wks_sortie[0]);
- $execTime=time();
- foreach ($datas as $command=>$reponses) {
- if (empty($config['wks']['data'][$command]['hide']) || $config['wks']['data'][$command]['hide'] != true) {
- echo "\n\t".'';
- if (isset($config['wks']['data'][$command]['name'])) {
- echo "\n\t\t".'WKS '.$config['wks']['data'][$command]['name'].'';
- } else {
- echo "\n\t\t".'WKS '.$command.'';
+
+ $ppv_total=null;
+ $bmv_p=null;
+ $nb_ppv_total=0;
+ if ($config['vedirect']['by'] == 'usb') {
+ $timerefresh=time();
+ $vedirect_data_ready = vedirect_scan();
+ } elseif ($config['vedirect']['by'] == 'arduino') {
+ if (! is_file($config['vedirect']['arduino']['data_file'])) {
+ $vedirect_data_ready[0]['id'] = 'Vedirect serial get by arduino';
+ $vedirect_data_ready[0]['nom'] = 'Vedirect erreur';
+ $vedirect_data_ready[0]['serial'] = 'vedirect';
+ $vedirect_data_ready[0]['data']= 'Fichier de donnée:Introuvable';
+ } else if (filemtime($config['vedirect']['arduino']['data_file'])+$config['vedirect']['arduino']['data_file_expir'] < time()) {
+ $vedirect_data_ready[0]['id'] = 'Vedirect serial get by arduino';
+ $vedirect_data_ready[0]['nom'] = 'Vedirect erreur';
+ $vedirect_data_ready[0]['serial'] = 'vedirect';
+ $vedirect_data_ready[0]['data']= 'Fichier de donnée :Périmé';
+ } else {
+ $arduino_data=yaml_parse_file($config['vedirect']['arduino']['data_file']);
+ $idDevice=0;
+ foreach ($arduino_data as $device_id => $device_data) {
+ if (preg_match_all('/^Serial[0-9]$/m', $device_id)) {
+ $device_vedirect_data[$idDevice]=vedirect_parse_arduino($device_data);
+ $idDevice++;
+ }
+ }
+ $vedirect_data_ready = $device_vedirect_data;
+ }
+ }
+ if ($config['vedirect']['by'] != false) {
+ foreach ($vedirect_data_ready as $device) {
+ if ($device['serial'] == 'Inconnu' || $device['serial'] == '') {
+ $device['serial'] = $device['nom'];
}
- echo "\n\t\t".''.$execTime.'';
- echo "\n\t\t".'inverter';
- echo "\n\t\t".'';
- echo "\n\t\t".'';
- echo "\n\t\t".'';
- $numReponse=1;
- foreach ($reponses as $reponse) {
- # Check regex :
- if (isset($config['wks']['data'][$command][$numReponse]['regex'])
- && $config['wks']['data'][$command][$numReponse]['regex'] != false) {
- if (! preg_match($config['wks']['data'][$command][$numReponse]['regex'], $reponse)) {
- trucAdir(3, "[WKS] Erreur ".$command.$numReponse." regex ".$config['wks']['data'][$command][$numReponse]['regex']." ne correspond pas à l'item ".$reponse);
- $numReponse++;
- continue;
+ $xmlPrint.= "\n\t".'';
+ $xmlPrint.= "\n\t\t".''.$device['nom'].'';
+ $xmlPrint.= "\n\t\t".''.time().'';
+ $xmlPrint.= "\n\t\t".''.$device['type'].'';
+ $xmlPrint.= "\n\t\t".''.$device['modele'].'';
+ $xmlPrint.= "\n\t\t".''.$device['serial'].'';
+ $xmlPrint.= "\n\t\t".'';
+ sort($device['data']);
+ foreach (explode(',', $device['data']) as $data) {
+ $dataSplit = explode(':', $data);
+ $veData=ve_label2($dataSplit[0], $dataSplit[1]);
+ $xmlPrint.= "\n\t\t\t".'';
+ $xmlPrint.= "\n\t\t\t\t".''.$veData['desc'].'';
+ $xmlPrint.= "\n\t\t\t\t".''.$veData['value'].'';
+ $xmlPrint.= "\n\t\t\t\t".''.$veData['units'].'';
+ $xmlPrint.= "\n\t\t\t".'';
+ if ($dataSplit[0] == 'PPV'){
+ $ppv_total=$ppv_total+$dataSplit[1];
+ $nb_ppv_total++;
+ }
+ if ($device['type'] == "BMV" && $dataSplit[0] == 'P'){
+ $bmv_p=$dataSplit[1];
}
+ }
+ $xmlPrint.= "\n\t\t".'';
+ $xmlPrint.= "\n\t".'';
+ }
+ }
+ # WKS
+ if ($config['wks']['enable'] == true) {
+ trucAdir(1, "WKS enable");
+ exec($config['wks']['bin'], $wks_sortie, $wks_retour);
+ if ($wks_retour != 0){
+ trucAdir(1, 'Erreur à l\'exécution du script '.$config['wks']['bin']);
+ } else {
+ $datas = json_decode($wks_sortie[0]);
+ $execTime=time();
+ foreach ($datas as $command=>$reponses) {
+ if (empty($config['wks']['data'][$command]['hide']) || $config['wks']['data'][$command]['hide'] != true) {
+ $xmlPrint.= "\n\t".'';
+ if (isset($config['wks']['data'][$command]['name'])) {
+ $xmlPrint.= "\n\t\t".'WKS '.$config['wks']['data'][$command]['name'].'';
+ } else {
+ $xmlPrint.= "\n\t\t".'WKS '.$command.'';
}
- # Si l'ordre est présent
- if (isset($config['wks']['data'][$command][$numReponse])) {
- if (empty($config['wks']['data'][$command][$numReponse]['hide']) || $config['wks']['data'][$command][$numReponse]['hide'] != true) {
- trucAdir(5, "[WKS] Config trouvé, on affiche ".$command.$numReponse);
- echo "\n\t\t\t".'';
- echo "\n\t\t\t\t".''.$config['wks']['data'][$command][$numReponse]['desc'].'';
- if (isset($config['wks']['data'][$command][$numReponse]['value2text'])) {
- $find = false;
- foreach($config['wks']['data'][$command][$numReponse]['value2text'] as $value=>$text) {
- if ($reponse == $value) {
- echo "\n\t\t\t\t".''.$text.'';
- $find = true;
+ $xmlPrint.= "\n\t\t".''.$execTime.'';
+ $xmlPrint.= "\n\t\t".'inverter';
+ $xmlPrint.= "\n\t\t".'';
+ $xmlPrint.= "\n\t\t".'';
+ $xmlPrint.= "\n\t\t".'';
+ $numReponse=1;
+ foreach ($reponses as $reponse) {
+ # Check regex :
+ if (isset($config['wks']['data'][$command][$numReponse]['regex'])
+ && $config['wks']['data'][$command][$numReponse]['regex'] != false) {
+ if (! preg_match($config['wks']['data'][$command][$numReponse]['regex'], $reponse)) {
+ trucAdir(3, "[WKS] Erreur ".$command.$numReponse." regex ".$config['wks']['data'][$command][$numReponse]['regex']." ne correspond pas à l'item ".$reponse);
+ $numReponse++;
+ continue;
+ }
+ }
+ # Si l'ordre est présent
+ if (isset($config['wks']['data'][$command][$numReponse])) {
+ if (empty($config['wks']['data'][$command][$numReponse]['hide']) || $config['wks']['data'][$command][$numReponse]['hide'] != true) {
+ trucAdir(5, "[WKS] Config trouvé, on affiche ".$command.$numReponse);
+ $xmlPrint.= "\n\t\t\t".'';
+ $xmlPrint.= "\n\t\t\t\t".''.$config['wks']['data'][$command][$numReponse]['desc'].'';
+ if (isset($config['wks']['data'][$command][$numReponse]['value2text'])) {
+ $find = false;
+ foreach($config['wks']['data'][$command][$numReponse]['value2text'] as $value=>$text) {
+ if ($reponse == $value) {
+ $xmlPrint.= "\n\t\t\t\t".''.$text.'';
+ $find = true;
+ }
}
+ if ($find == false) {
+ $xmlPrint.= "\n\t\t\t\t".''.$reponse.'';
+ }
+ } else {
+ $xmlPrint.= "\n\t\t\t\t".''.$reponse.'';
}
- if ($find == false) {
- echo "\n\t\t\t\t".''.$reponse.'';
- }
- } else {
- echo "\n\t\t\t\t".''.$reponse.'';
- }
- echo "\n\t\t\t\t".''.$config['wks']['data'][$command][$numReponse]['units'].'';
- echo "\n\t\t\t".'';
- } else {
- # Caché
- trucAdir(5, "[WKS] idem caché : ".$command.$numReponse);
+ $xmlPrint.= "\n\t\t\t\t".''.$config['wks']['data'][$command][$numReponse]['units'].'';
+ $xmlPrint.= "\n\t\t\t".'';
+ } else {
+ # Caché
+ trucAdir(5, "[WKS] idem caché : ".$command.$numReponse);
+ }
+ } elseif ($config['wks']['data']['printAll'] == true) {
+ # Sinon c'est par défaut
+ trucAdir(5, "[WKS] pas de config, item par défaut : ".$command.$numReponse);
+ $xmlPrint.= "\n\t\t\t".'';
+ $xmlPrint.= "\n\t\t\t\t".''.$command.$numReponse.'';
+ $xmlPrint.= "\n\t\t\t\t".''.$reponse.'';
+ $xmlPrint.= "\n\t\t\t\t".'';
+ $xmlPrint.= "\n\t\t\t".'';
}
- } elseif ($config['wks']['data']['printAll'] == true) {
- # Sinon c'est par défaut
- trucAdir(5, "[WKS] pas de config, item par défaut : ".$command.$numReponse);
- echo "\n\t\t\t".'';
- echo "\n\t\t\t\t".''.$command.$numReponse.'';
- echo "\n\t\t\t\t".''.$reponse.'';
- echo "\n\t\t\t\t".'';
- echo "\n\t\t\t".'';
+ $numReponse++;
}
- $numReponse++;
+ $xmlPrint.= "\n\t\t".'';
+ $xmlPrint.= "\n\t".'';
}
- echo "\n\t\t".'';
- echo "\n\t".'';
}
}
}
-}
-# Divers
-$bin_enabled_data = scandir($config['dir']['bin_enabled']);
-$printDivers=false;
-foreach ($bin_enabled_data as $bin_script_enabled) {
- $bin_script_info = pathinfo($config['dir']['bin_enabled'].'/'.$bin_script_enabled);
- if ($bin_script_info['extension'] == 'php') {
- $printDivers=true;
- }
-}
-if($printDivers == true || $config['data']['ppv_total'] || $config['data']['ppv_total']) {
-?>
-
- Divers
- = time() ?>
-
-
-
-
-
- Production total des panneaux
- '.$ppv_total.'
- W
- ';
- }
- ?>
-
- Consommation du foyer
- '.abs($conso).'
- W
- ';
- }
- ?>
-
-
- $value) {
- unset($array_data[$i]);
- }
- trucAdir(3, "Lecture du script ".$bin_script_enabled);
- $script_return = (include $config['dir']['bin_enabled'].'/'.$bin_script_enabled);
- file_put_contents($cache_file_script, json_encode($script_return));
- if (substr(sprintf('%o', fileperms($cache_file)), -3) != '777') {
- chmod($cache_file, 0777);
- }
- }
- $timerefresh=filemtime($cache_file_script);
-
- $script_return_datas = json_decode(file_get_contents($cache_file_script), true) ;
- //trucAdir(4, print_r($script_return_datas));
- echo "\n\t";
- echo "\n\t\t";
- echo "\n\t\t".$timerefresh."";
- echo "\n\t\t";
- echo "\n\t\t";
- echo "\n\t\t";
- echo "\n\t\t";
- sort($script_return_datas);
-
- foreach ($script_return_datas as $script_return_data) {
- if (isset($script_return_data['id'])) {
- $id_data=$script_return_data['id'];
- } else {
- $id_data=$id;
- }
- echo "\n\t\t\t";
- echo "\n\t\t\t\t".$script_return_data['desc']."";
- echo "\n\t\t\t\t".$script_return_data['value']."";
- echo "\n\t\t\t\t".$script_return_data['units']."";
- echo "\n\t\t\t";
- }
- echo "\n\t\t";
- echo "\n\t";
- }
+ # Divers
+ $bin_enabled_data = scandir($config['dir']['bin_enabled']);
+ $printDivers=false;
+ foreach ($bin_enabled_data as $bin_script_enabled) {
+ $bin_script_info = pathinfo($config['dir']['bin_enabled'].'/'.$bin_script_enabled);
+ if ($bin_script_info['extension'] == 'php') {
+ $printDivers=true;
+ }
+ }
+ if($printDivers == true || $config['data']['ppv_total'] || $config['data']['ppv_total']) {
+ $xmlPrint.= '
+ Divers
+ '.time().'
+
+
+
+ ';
+ // Production totale
+ if ($config['data']['ppv_total'] && $ppv_total !== null) {
+ $xmlPrint.= '
+ Production total des panneaux
+ '.$ppv_total.'
+ W
+ ';
+ }
+ // Calcul consommation foyer
+ if ($config['data']['ppv_total'] && $config['data']['conso_calc'] && $ppv_total !== null && $bmv_p != null) {
+ $conso=$ppv_total-$bmv_p;
+ $xmlPrint.= '
+ Consommation du foyer
+ '.abs($conso).'
+ W
+ ';
+ }
+ $xmlPrint.= '
+ ';
+ trucAdir(3, "Scan du répertoire bin-enable");
+ // Scan du répertoire bin-enabled
+ foreach ($bin_enabled_data as $bin_script_enabled) {
+ $bin_script_info = pathinfo($config['dir']['bin_enabled'].'/'.$bin_script_enabled);
+ if ($bin_script_info['extension'] == 'php') {
+ $filenameSplit = explode("-", $bin_script_info['filename']);
+ $idParent=$filenameSplit[0];
+ $id=$filenameSplit[1];
+
+ // Ménage
+ foreach ($array_data as $i => $value) {
+ unset($array_data[$i]);
+ }
+ trucAdir(3, "Lecture du script ".$bin_script_enabled);
+ $script_return = (include $config['dir']['bin_enabled'].'/'.$bin_script_enabled);
+ $timerefresh=time();
+ $script_return_datas = $script_return;
+
+ $xmlPrint.= "\n\t";
+ $xmlPrint.= "\n\t\t";
+ $xmlPrint.= "\n\t\t".$timerefresh."";
+ $xmlPrint.= "\n\t\t";
+ $xmlPrint.= "\n\t\t";
+ $xmlPrint.= "\n\t\t";
+ $xmlPrint.= "\n\t\t";
+ sort($script_return_datas);
+
+ foreach ($script_return_datas as $script_return_data) {
+ if (isset($script_return_data['id'])) {
+ $id_data=$script_return_data['id'];
+ } else {
+ $id_data=$id;
+ }
+ $xmlPrint.= "\n\t\t\t";
+ $xmlPrint.= "\n\t\t\t\t".$script_return_data['desc']."";
+ $xmlPrint.= "\n\t\t\t\t".$script_return_data['value']."";
+ $xmlPrint.= "\n\t\t\t\t".$script_return_data['units']."";
+ $xmlPrint.= "\n\t\t\t";
+ }
+ $xmlPrint.= "\n\t\t";
+ $xmlPrint.= "\n\t";
+ }
+ }
+ }
+ $xmlPrint.= "";
+ trucAdir(5, "Fin de la génération du fichier data-xml");
+
+ $xmlValid=true;
+ if (isset($config['dataCheck'])) {
+ trucAdir(5, "Vérification des donnéesdata-xml");
+ // Count data check
+ $nbDataCheck=0;
+ foreach ($config['dataCheck'] as $dataCheck) {
+ if (isset($dataCheck['number'])) {
+ $nbDataCheck=$nbDataCheck+$dataCheck['number'];
+ } else {
+ $nbDataCheck++;
+ }
}
+ trucAdir(5, "On recherche $nbDataCheck data pour valider l'XML");
+ //~ $devices = simplexml_load_string($xmlPrint);
+ $devices = simplexml_load_file('data-xml-test.xml');
+ foreach ($devices as $device) {
+ foreach ($device->datas->data as $data) {
+ $id= (string) $data['id'];
+ $data = (string) $data->value;
+ if (isset($config['dataCheck'][$id])) {
+ // Trouvé, on soustrait 1
+ $nbDataCheck=$nbDataCheck-1;
+ trucAdir(5, 'XML parse : '.$id.' à été trouvé');
+ if (isset($config['dataCheck'][$id]['regex']) && !preg_match_all('/'.$config['dataCheck'][$id]['regex'].'/', $data)) {
+ trucAdir(1, 'XML parse : '.$id.' est invalide par rapport au regex recherché');
+ $nbDataCheck=$nbDataCheck-2;
+ }
+ }
+ }
+ }
+ if ($nbDataCheck == 0) {
+ trucAdir(5, 'XML parse : tout trouvé, tout validé !');
+ } else {
+ trucAdir(1, 'XML parse : erreur dans le XML');
+ $xmlValid=false;
+ }
+ }
+
+ if ($xmlValid == true) {
+ file_put_contents($config['cache']['dir'].'/data.xml', $xmlPrint);
+ echo $xmlPrint;
+ } else {
+ if (is_file($config['cache']['dir'].'/data.xml')) {
+ if (filemtime($config['cache']['dir'].'/data.xml')+$config['cache']['expirLimit'] < time()) {
+ echo xmlPrintError("Le cache est expiré sans que de bonne données ne soient récupéré...");
+ trucAdir(1, 'XML Le cache est expiré sans que de bonne données ne soient récupéré...');
+ } else {
+ trucAdir(3, 'XML on sert le fichier de cache MEME s\'il est périmé en attendant...');
+ echo file_get_contents($config['cache']['dir'].'/data.xml');
+ }
+ } else {
+ echo xmlPrintError("Aucune donnée valide a afficher (voir config.yaml / dataCheck)");
+ trucAdir(1, "Aucune donnée valide a afficher (voir config.yaml / dataCheck)");
+ }
+ }
}
-trucAdir(5, "Fin du data-xml.php");
?>
-
+
+