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 - - - - - - - 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"); ?> - + +