diff --git a/config-default.yaml b/config-default.yaml
index 44ab97c..2f5594d 100644
--- a/config-default.yaml
+++ b/config-default.yaml
@@ -1,591 +1,594 @@
######################################################################
# 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
scriptDataXml: /opt/PvMonit/www/data-xml.php
dir:
bin: /opt/PvMonit/bin/
bin_enabled: /opt/PvMonit/bin-enabled/
lcd: /opt/PvMonit/lcd/
domo: /opt/PvMonit/domo/
bin:
php-cli: /usr/bin/php
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
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
OTHER: Divers
# 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
weatherForcast: false # Prévision météo a afficher dans l'interface web
weatherForcastNbDayPrint: 1 # Nombre de jour a afficher pour les prévisions météos
weatherProdForcast: false # Prévision de productoin a afficher dans l'interface web
# 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 # 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)
weather:
enable: false
cache: 3600 # in seconde
openweathermapCityId: XXXXXXX # OpenWeatherMap city ID
# Tout les city id sont là : http://bulk.openweathermap.org/sample/city.list.json.gz
# Sinon tu peux faire un recherche https://openweathermap.org/city et l'ID se trouve dans l'URL (exemple pour Paris FR : https://openweathermap.org/city/2988507 l'ID est 2988507 )
openweathermapAppId: XXXXXXXXXXXXXXXXXXXXXXXX # Creat account on openweathermap.org for APP ID (api key)
forecastDay: 5 # Nombre de jour de prévision au delà de ce jour (min 1, max 5)
prod: 1000 # Wc panel installed
dalyConsumption: 1000 # Wh/d need (calculé pour le dimmensionnement
prod_yield_global: 0.80 # Rendement global de l'installation ($prod * 0.80)
prod_mini: 0.03 # Production minimum (%)
abatementSurise: # Abattement sur la production au levé du soleil
0: 0 # Exemple : à l'heure du levé du soleil on applique un coef de 0.1 sur la prod
1: 0.1
2: 0.3
3: 0.6
4: 0.8
5: 0.9
abatementSunset: # Abattement sur la production au couché du soleil
5: 0.9 # Exemple : 5 h avant le couché du soleil on applique un abattement de 0.6
4: 0.8
3: 0.6
2: 0.3
1: 0.1
0: 0
-
+ abatementHour: # Abattement / h (UTC)
+ #~ 8: 0.2 # Exemple Si vous avez un masque solaire entre 10 et 12h en été à Paris c'est 8-10h UTC (Paris l'été c'est GTM +2)
+ #~ 9: 0.2
+
#~ 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/www/weatherForcast.php b/www/weatherForcast.php
new file mode 100644
index 0000000..236eae0
--- /dev/null
+++ b/www/weatherForcast.php
@@ -0,0 +1,34 @@
+
+
diff --git a/www/weatherProdForcast.php b/www/weatherProdForcast.php
new file mode 100644
index 0000000..9675742
--- /dev/null
+++ b/www/weatherProdForcast.php
@@ -0,0 +1,157 @@
+\n";
+ //~ echo "sunset : " ;
+ //~ echo date('H:m:s', $resultArray['city']['sunset']);
+ //~ $sunsetSecond = timeHms2s($resultArray['city']['sunset']);
+ //~ }
+ $forecast['sunset']=$resultArray['city']['sunset'];
+ $forecast['surise']=$resultArray['city']['sunrise'];
+ //~ echo "
\n";
+ //~ echo "H : comprendre H-3h";
+ //~ echo "
\n";
+ foreach($resultArray as $key=>$weather) {
+ global $config;
+ if ($key == 'list') {
+ foreach($weather as $no=>$weatherDay) {
+ // On cherche l'interval de date
+ $dateNow = new DateTime(date('Y-m-d', time()));
+ $datePrevision = new DateTime(date('Y-m-d', $weatherDay['dt']));
+ $interval = date_diff($dateNow, $datePrevision);
+ $diffIntervalOperation = $interval->format('%R%a');
+ $diffDay = $interval->format('%a');
+ // On s'arrête à J+2 en prévision
+ if ($diffDay > $config['weather']['forecastDay']){
+ continue;
+ }
+ // Moyenne des nuages duprant la journée
+ //~ average cloud during the day
+ //~ if (date('G', $weatherDay['dt']) >= date('G', $forecast['surise']) && date('G', $weatherDay['dt']) <= date('G', $forecast['sunset'])) {
+ //~ if (isset($avenage[$diffDay]))
+ //~ echo date('G', $weatherDay['dt']);
+ //~ }
+ $forecast[$diffDay][date('G', $weatherDay['dt']-3600-3600)]=$weatherDay['clouds']['all'];
+ $forecast[$diffDay][date('G', $weatherDay['dt']-3600)]=$weatherDay['clouds']['all'];
+ $forecast[$diffDay][date('G', $weatherDay['dt'])]=$weatherDay['clouds']['all'];
+ }
+ }
+ }
+ //~ echo json_encode($forecast);
+ //~ exit();
+ function prodForecast($forecast) {
+ global $config;
+ global $include;
+ # On cherche la différence entre l'heure configuré (time zone) et l'UTC
+ $dateTimeZoneUTC = new DateTimeZone("UTC");
+ $dateTimeZoneGet = new DateTimeZone(date_default_timezone_get());
+ $dateTimeUTC = new DateTime("now", $dateTimeZoneUTC);
+ //~ $dateTimeGet = new DateTime("now", $dateTimeZoneGet);
+ $diffUTC = round($dateTimeZoneGet->getOffset($dateTimeUTC)/3600);
+ trucAdir(5, "La timezone ".date_default_timezone_get()." est à $diffUTC h d'UTC");
+ for ($day = 0; $day <= $config['weather']['forecastDay']; $day++) {
+ if (empty($forecast[$day])) {
+ continue;
+ }
+ foreach ($forecast[$day] as $hour=>$cloud) {
+ trucAdir(5, "Day $day, $hour H - Cloud : $cloud % ");
+ $abatementCloud=(100-$cloud)/100+$config['weather']['prod_mini'];
+ if ($hour >= date('G', $forecast['surise']) && $hour <= date('G', $forecast['sunset'])) {
+ $diffSunrise=$hour-date('G', $forecast['surise']);
+ $diffSunset=date('G', $forecast['sunset'])-$hour;
+ if (isset($config['weather']['abatementSurise'][$diffSunrise])) {
+ $abatement=$config['weather']['abatementSurise'][$diffSunrise];
+ } elseif (isset($config['weather']['abatementSunset'][$diffSunset])) {
+ $abatement=$config['weather']['abatementSunset'][$diffSunset];
+ } else {
+ $abatement=1;
+ }
+ //~ exit();
+ $hourUtc=$hour-$diffUTC;
+ $abatementHour=1;
+ if (isset($config['weather']['abatementHour'][$hourUtc])) {
+ $abatementHour=$config['weather']['abatementHour'][$hourUtc];
+ trucAdir(5, "Un abattement horraire de $abatementHour s'applique à $hour H ($hourUtc H UTC))");
+ }
+ $prodForcast[$day]['byHour'][$hour]['prod']=round($config['weather']['prod']*$abatementCloud*$config['weather']['prod_yield_global']*$abatement*$abatementHour, 0);
+ $prodForcast[$day]['byHour'][$hour]['cloud']=$cloud;
+ $prodForcast[$day]['byHour'][$hour]['sun']=1;
+ trucAdir(5, "Prod estimé : ".$prodForcast[$day]['byHour'][$hour]['prod']."W - Abatement config $abatement - ");
+ } else {
+ $prodForcast[$day]['byHour'][$hour]['prod']=0;
+ $prodForcast[$day]['byHour'][$hour]['cloud']=$cloud;
+ $prodForcast[$day]['byHour'][$hour]['sun']=0;
+ trucAdir(5, "Prod estimé : ".$prodForcast[$day]['byHour'][$hour]['prod']);
+ }
+ }
+ $prodCumul=0;
+ $cloudAvg=0;
+ $cloudAvgNb=0;
+ foreach ($prodForcast[$day]['byHour'] as $byHour) {
+ $prodCumul=$prodCumul+$byHour['prod'];
+ if ($byHour['sun'] == 1) {
+ $cloudAvg=$cloudAvg+$byHour['cloud'];
+ $cloudAvgNb++;
+ }
+ }
+ $prodForcast[$day]['prodCumul']=round($prodCumul, 0);
+ $prodForcast[$day]['cloudAvg']=round($cloudAvg/$cloudAvgNb, 0);
+ ksort($prodForcast[$day]['byHour']);
+ }
+ return $prodForcast;
+ }
+ file_put_contents($cacheFileProd, json_encode(prodForecast($forecast)));
+} else {
+ trucAdir(5, "Le cache est service pour la prod forcast");
+}
+echo file_get_contents($cacheFileProd);
+
+?>
+