.
*/
require_once dirname(__FILE__) . '/../../../../core/php/core.inc.php';
class meteofrance extends eqLogic {
public static $_widgetPossibility = array('custom' => true);
public static $_vigilanceType = array (
1 => array("txt" => "Vent","icon" => "wi-strong-wind"),
2 => array("txt" => "Pluie","icon" => "wi-rain-wind"),
3 => array("txt" => "Orages","icon" => "wi-lightning"),
4 => array("txt" => "Crues","icon" => "wi-flood"),
5 => array("txt" => "Neige-verglas","icon" => "wi-snow"),
6 => array("txt" => "Canicule","icon" => "wi-hot"),
7 => array("txt" => "Grand-froid","icon" => "wi-thermometer-exterior"),
8 => array("txt" => "Avalanches","icon" => "wi-na"),
9 => array("txt" => "Vagues-submersion","icon" => "wi-tsunami"),
// 10 => array("txt" => "Incendie","icon" => "wi-fire")
);
public static $_vigilanceColors = array (
0 => array("desc" => "Non défini","color" => "#888888"),
array("desc" => "Vert","color" => "#31AA35"),
array("desc" => "Jaune","color" => "#FFF600"),
array("desc" => "Orange","color" => "#FFB82B"),
array("desc" => "Rouge","color" => "#CC0000"),
);
public static function backupExclude() { return(array('data/*.json')); }
public function checkAndUpdateCmd($_logicalId, $_value, $_updateTime = null) {
$cmd = $this->getCmd('info', $_logicalId);
if (!is_object($cmd)) {
log::add(__CLASS__, 'debug', "Equipment: " .$this->getName() ." Unexistant command $_logicalId");
}
parent::checkAndUpdateCmd($_logicalId, $_value, $_updateTime);
}
public static function getJsonInfo($cmd_id, $request) {
$id = cmd::humanReadableToCmd('#' .$cmd_id .'#');
$cmd = cmd::byId(trim(str_replace('#', '', $id)));
if(is_object($cmd)) {
$cmdJson = str_replace('"','"',$cmd->execCmd());
$json =json_decode($cmdJson,true);
if($json === null)
log::add(__CLASS__, 'debug', "Unable to decode JSON: " .substr($cmdJson,0,50));
else {
$tags = explode('>', $request);
foreach ($tags as $tag) {
$tag = trim($tag);
if (isset($json[$tag])) {
$json = $json[$tag];
} elseif (is_numeric(intval($tag)) && isset($json[intval($tag)])) {
$json = $json[intval($tag)];
} elseif (is_numeric(intval($tag)) && intval($tag) < 0 && isset($json[count($json) + intval($tag)])) {
$json = $json[count($json) + intval($tag)];
} else {
$json = "Request error: tag[$tag] not found in " .json_encode($json);
break;
}
}
return (is_array($json)) ? json_encode($json) : $json;
}
}
else log::add(__CLASS__, 'debug', "Command not found: $cmd");
return(null);
}
public static function cron5() {
if(date('i') == 0) return; // will be executed by cronHourly
foreach (eqLogic::byType(__CLASS__, true) as $meteofrance) {
$meteofrance->getRain();
$meteofrance->getHourlyDailyForecasts();
$meteofrance->refreshWidget();
}
}
/* comments because vigilance has its own cron task
public static function cron15() {
if(date('i') == 0) return; // will be executed by cronHourly
foreach (eqLogic::byType(__CLASS__, true) as $meteofrance) {
$meteofrance->getVigilance();
$meteofrance->refreshWidget();
}
}
*/
public static function cronHourly() {
foreach (eqLogic::byType(__CLASS__, true) as $meteofrance) {
$meteofrance->getInformations();
}
}
public static function pullDataVigilance($updatePlugin=0) {
$recup = 1; $ret = 0;
foreach (eqLogic::byType(__CLASS__, true) as $meteofrance) {
if($recup) $ret = $meteofrance->getVigilanceDataApiCloudMF();
if($updatePlugin == 1) break; // Update data only
$recup = 0;
if($ret == 0) $meteofrance->getVigilance();
}
}
public static function setCronDataVigilance($create) {
if($create == 1) {
$cron = cron::byClassAndFunction(__CLASS__, 'pullDataVigilance');
if(!is_object($cron)) {
$cron = new cron();
$cron->setClass(__CLASS__);
$cron->setFunction('pullDataVigilance');
$cron->setEnable(1);
$cron->setDeamon(0);
}
$cron->setSchedule(rand(5,25) .' 6-23 * * *');
$cron->save();
meteofrance::pullDataVigilance(1); // update data
}
else {
$cron = cron::byClassAndFunction(__CLASS__, 'pullDataVigilance');
if(is_object($cron)) {
$cron->remove();
}
}
}
public function preSave() {
$args = $this->getInsee();
$this->getLocationDetails($args);
$this->getBulletinDetails($args);
}
public function postSave() {
$cron = cron::byClassAndFunction('meteofrance', 'cronTrigger', array('meteofrance_id' => $this->getId()));
if (!is_object($cron)) {
$cron = new cron();
$cron->setClass('meteofrance');
$cron->setFunction('cronTrigger');
$cron->setOption(array('meteofrance_id' => $this->getId()));
}
$cron->setOnce(1);
$time = time() + 90;
$cron->setSchedule(date('i', $time) . ' ' . date('H', $time) . ' ' . date('d', $time) . ' ' . date('m', $time) . ' * ' . date('Y', $time));
$cron->save();
}
public static function cronTrigger($_options) {
$meteofrance = meteofrance::byId($_options['meteofrance_id']);
log::add(__CLASS__, 'debug', "Starting cronTrigger for " .$meteofrance->getName());
$meteofrance->loadCmdFromConf('bulletin');
$meteofrance->loadCmdFromConf('bulletinville');
$meteofrance->loadCmdFromConf('ephemeris');
if ($meteofrance->getConfiguration('bulletinCote')) {
$meteofrance->loadCmdFromConf('marine');
}
$meteofrance->loadCmdFromConf('meteo');
$meteofrance->loadCmdFromConf('rain');
$meteofrance->loadCmdFromConf('vigilance');
$eqLogicId = $meteofrance->getId();
$mfCmd = meteofranceCmd::byEqLogicIdAndLogicalId($eqLogicId, 'refresh'); // L'existance de cette commande est testée dans toHtml
if (!is_object($mfCmd)) {
$mfCmd = new meteofranceCmd();
$mfCmd->setName(__('Rafraichir', __FILE__));
$mfCmd->setEqLogic_id($eqLogicId);
$mfCmd->setLogicalId('refresh');
$mfCmd->setType('action');
$mfCmd->setSubType('other');
$mfCmd->save();
}
log::add(__CLASS__, 'debug', "End of commands creation. Memory_usage: ".memory_get_usage());
$meteofrance->getInformations();
}
public function getInformations() {
$this->getRain();
$this->getVigilance();
if($this->getConfiguration('bulletinCote')) {
$this->getMarine();
$this->getTide();
}
$this->getAlerts();
$this->getEphemeris();
$this->getBulletinFrance();
$this->getBulletinSemaine();
$this->getInstantsValues();
$this->getBulletinVille();
$this->getHourlyDailyForecasts();
$this->refreshWidget();
}
public function getInsee() {
$array = array();
$array['insee'] = ''; $array['ville'] = ''; $array['zip'] = '';
$array['lon'] = ''; $array['lat'] = '';
$geoloc = $this->getConfiguration('geoloc', 'none');
if ($geoloc == 'none') {
log::add(__CLASS__, 'debug', 'Localisation non configurée.');
return $array;
}
if ($geoloc == "jeedom") {
$array['zip'] = config::byKey('info::postalCode');
$array['ville'] = config::byKey('info::city');
} else {
$geotrav = eqLogic::byId($geoloc);
if (is_object($geotrav) && $geotrav->getEqType_name() == 'geotrav') {
$geotravCmd = geotravCmd::byEqLogicIdAndLogicalId($geoloc,'location:zip');
if(is_object($geotravCmd))
$array['zip'] = $geotravCmd->execCmd();
$geotravCmd = geotravCmd::byEqLogicIdAndLogicalId($geoloc,'location:city');
if(is_object($geotravCmd))
$array['ville'] = $geotravCmd->execCmd();
else {
log::add(__CLASS__, 'error', 'Eqlogic geotravCmd object not found');
return $array;
}
}
else {
log::add(__CLASS__, 'error', 'Eqlogic geotrav object not found');
return $array;
}
}
if($array['ville'] == '' || $array['zip'] == '') {
log::add(__CLASS__, 'error', 'Localisation incorrectement configurée. Ville: '.$array['ville'] .'Code postal: '.$array['zip']);
return $array;
}
$url = 'https://api-adresse.data.gouv.fr/search/?q=' .urlencode($array['ville']) .'&postcode=' .$array['zip'] .'&limit=1';
$return = self::callURL($url);
$loglevel = log::convertLogLevel(log::getLogLevel(__CLASS__));
if($loglevel == 'debug') {
$hdle = fopen(__DIR__ ."/../../data/" .__FUNCTION__ .'-' .$array['ville'] .'_' .$array['zip'] .".json","wb");
if($hdle !== FALSE) { fwrite($hdle, json_encode($return)); fclose($hdle); }
}
if(!isset($return['features'][0]['properties'])) {
log::add(__CLASS__, 'error', 'Ville [' .$array['ville'] .'] non trouvée. ' .__FUNCTION__ .'() ' . print_r($return,true));
return $array;
}
log::add(__CLASS__, 'debug', 'Insee ' . print_r($return['features'][0]['properties'],true));
$array['ville'] = $return['features'][0]['properties']['name'];
$array['insee'] = $return['features'][0]['properties']['citycode'];
$array['lon'] = $return['features'][0]['geometry']['coordinates'][0];
$array['lat'] = $return['features'][0]['geometry']['coordinates'][1];
log::add(__CLASS__, 'debug', 'Insee:' .$array['insee'] .' Ville:' .$array['ville'] .' Code postal:' .$array['zip'] .' Latitude:' .$array['lat'] .' Longitude:' .$array['lon']);
return $array;
}
public function getLocationDetails($_array = array()) {
$lat = $_array['lat']; $lon = $_array['lon'];
if($lat != '' && $lon != '') {
$url = "https://rpcache-aa.meteofrance.com/internet2018client/2.0/forecast?lat=$lat&lon=$lon&id=&instants=morning,afternoon,evening,night";
$ville = $_array['ville'];
$return = self::callMeteoWS($url,false,true,__FUNCTION__ ."-$ville.json");
if(isset($return['properties']['bulletin_cote'])) $bulletin_cote = $return['properties']['bulletin_cote'];
else $bulletin_cote = 0;
$this->setConfiguration('bulletinCote', $bulletin_cote);
if(isset($return['properties']['timezone'])) $timezone = $return['properties']['timezone'];
else $timezone = 'Europe/Paris';
$this->setConfiguration('numDept', $return['properties']['french_department']);
}
else {
log::add(__CLASS__, 'debug', __FUNCTION__ ." Invalid latitude/longitude: $lat/$lon");
$this->setConfiguration('bulletinCote', 0);
$this->setConfiguration('numDept', '');
}
$this->setConfiguration('insee', $_array['insee']);
$this->setConfiguration('lat', $_array['lat']);
$this->setConfiguration('lon', $_array['lon']);
$this->setConfiguration('zip', $_array['zip']);
$this->setConfiguration('ville', $_array['ville']);
}
public function getBulletinDetails($_array = array()) {
// $ville = $_array['ville'];
$ville = str_replace("'",'-',$_array['ville']);
$zip = $_array['zip'];
if($ville != '' && $zip != '') {
$url = "http://meteofrance.com/previsions-meteo-france/" . urlencode($ville) . "/" . $_array['zip'];
log::add(__CLASS__, 'debug', __FUNCTION__ ." URL: $url");
$dom = new DOMDocument;
if(@$dom->loadHTMLFile($url,LIBXML_NOERROR) === true ) {
// $dom->saveHTMLFile(__DIR__ .'/' .$_array['zip'] .'.html');
$xpath = new DomXPath($dom);
log::add(__CLASS__, 'debug', ' ' . $xpath->query("//html/body/script[1]")[0]->nodeValue);
$json = json_decode($xpath->query("//html/body/script[1]")[0]->nodeValue, true);
$loglevel = log::convertLogLevel(log::getLogLevel(__CLASS__));
if($loglevel == 'debug') {
$hdle = fopen(__DIR__ ."/../../data/" .__FUNCTION__ ."-${ville}_$zip.json", "wb");
if($hdle !== FALSE) { fwrite($hdle, json_encode($json)); fclose($hdle); }
}
log::add(__CLASS__, 'debug', 'Bulletin Ville Result ' . $json['id_bulletin_ville']);
$this->setConfiguration('bulletinVille', ((is_null($json['id_bulletin_ville']))?'':$json['id_bulletin_ville']));
}
else {
log::add(__CLASS__, 'warning', __FUNCTION__ ." loadHTMLFile failed. getBulletinVille will not be called.");
$this->setConfiguration('bulletinVille', '');
}
}
else {
log::add(__CLASS__, 'debug', __FUNCTION__ ." Invalid ville/zipcode: $ville/$zip");
}
}
public function getBulletinVille() {
$bulletinVille = $this->getConfiguration('bulletinVille','');
if ($bulletinVille == '') {
return;
}
$url = "https://rpcache-aa.meteofrance.com/wsft/files/agat/ville/bulvillefr_$bulletinVille.xml";
log::add(__CLASS__, 'debug', __FUNCTION__ ." BulletinVille: $bulletinVille URL: $url");
$return = self::callMeteoWS($url,true,false,__FUNCTION__ ."-$bulletinVille.json");
$this->checkAndUpdateCmd('BulletinvilletitreEcheance1', $return['echeance'][0]['titreEcheance']);
$this->checkAndUpdateCmd('Bulletinvillepression1', $return['echeance'][0]['pression']);
$this->checkAndUpdateCmd('BulletinvilleTS1', $return['echeance'][0]['TS']);
$this->checkAndUpdateCmd('Bulletinvilletemperature1', $return['echeance'][0]['temperature']);
$this->checkAndUpdateCmd('Bulletinvillevent1', $return['echeance'][0]['vent']);
$this->checkAndUpdateCmd('BulletinvilletitreEcheance2', $return['echeance'][1]['titreEcheance']);
if(isset($return['echeance'][1]['pression']))
$this->checkAndUpdateCmd('Bulletinvillepression2', $return['echeance'][1]['pression']);
else $this->checkAndUpdateCmd('Bulletinvillepression2', '');
$this->checkAndUpdateCmd('BulletinvilleTS2', $return['echeance'][1]['TS']);
$this->checkAndUpdateCmd('Bulletinvilletemperature2', $return['echeance'][1]['temperature']);
$this->checkAndUpdateCmd('Bulletinvillevent2', $return['echeance'][1]['vent']);
$this->checkAndUpdateCmd('BulletinvilletitreEcheance3', $return['echeance'][2]['titreEcheance']);
if(isset($return['echeance'][2]['pression']))
$this->checkAndUpdateCmd('Bulletinvillepression3', $return['echeance'][2]['pression']);
else $this->checkAndUpdateCmd('Bulletinvillepression3', '');
$this->checkAndUpdateCmd('BulletinvilleTS3', $return['echeance'][2]['TS']);
$this->checkAndUpdateCmd('Bulletinvilletemperature3', $return['echeance'][2]['temperature']);
$this->checkAndUpdateCmd('Bulletinvillevent3', $return['echeance'][2]['vent']);
}
public function getHourlyDailyForecasts() { // hourly and daily forecast
$lat = $this->getConfiguration('lat'); $lon = $this->getConfiguration('lon');
if($lat == '' || $lon == '') {
log::add(__CLASS__, 'debug', __FUNCTION__ ." " .$this->getName() ." Invalid latitude/longitude: $lat/$lon");
return;
}
$ville = $this->getConfiguration('ville');
log::add(__CLASS__, 'debug', __FUNCTION__ ." $ville $lat/$lon");
$url = "https://webservice.meteofrance.com/forecast?lat=$lat&lon=$lon&id=&instants=&day=5";
$return = self::callMeteoWS($url,false,true,__FUNCTION__ ."-$ville.json");
$timezone = $return['position']['timezone'];
$nb = count($return['forecast']);
$updated_on = $return['updated_on'];
log::add(__CLASS__, 'debug', " updated_on: " .date('d-m-Y H:i:s', $updated_on) ." Nbforecast: $nb Timezone: $timezone");
$now = time();
$found = 0; $j = 0;
// Prévisions par heure
for($i=0;$i<$nb-1;$i++) {
$forecastTS = $return['forecast'][$i]['dt'];
$forecastNextTS = $return['forecast'][$i+1]['dt'];
log::add(__CLASS__, 'debug', " $i forecast:" .date('d-m-Y H:i:s', $forecastTS) ." Desc: " .$return['forecast'][$i]['weather']['desc']);
if($found || ($now >= $forecastTS && $now < $forecastNextTS)) {
$value= $return['forecast'][$i];
$found = 1;
if($j == 0 ) {
log::add(__CLASS__, 'debug', " Now forecast found: (" .date("H:i:s",$forecastTS) .") Icon: " .$value['weather']['icon']);
$this->checkAndUpdateCmd('MeteonowTemperature', $value['T']['value']);
$this->checkAndUpdateCmd('MeteonowTemperatureRes', $value['T']['windchill']);
$this->checkAndUpdateCmd('MeteonowHumidity', $value['humidity']);
$this->checkAndUpdateCmd('MeteonowPression', $value['sea_level']);
$this->checkAndUpdateCmd('MeteonowWindSpeed', round($value['wind']['speed']*3.6));
$this->checkAndUpdateCmd('MeteonowWindGust', round($value['wind']['gust']*3.6));
$this->checkAndUpdateCmd('MeteonowWindDirection', $value['wind']['direction']);
$this->checkAndUpdateCmd('MeteonowRain1h', (isset($value['rain']['1h']) ? $value['rain']['1h'] : -1));
$this->checkAndUpdateCmd('MeteonowSnow1h', (isset($value['snow']['1h']) ? $value['snow']['1h'] : -1));
$this->checkAndUpdateCmd('MeteonowCloud', $value['clouds']);
$this->checkAndUpdateCmd('MeteonowIcon', $value['weather']['icon']);
$this->checkAndUpdateCmd('MeteonowDescription', $value['weather']['desc']);
}
else if($j == 1 ) {
// H+1
log::add(__CLASS__, 'debug', " 1h forecast Desc: " .$value['weather']['desc'] ." Icon: " .$value['weather']['icon']);
$this->checkAndUpdateCmd('Meteodayh1description', $value['weather']['desc'].' '.date('d-m H:i', $forecastTS));
$this->checkAndUpdateCmd('Meteodayh1temperature', $value['T']['value']);
$this->checkAndUpdateCmd('Meteodayh1temperatureRes', $value['T']['windchill']);
$this->checkAndUpdateCmd('hourly1icon', $value['weather']['icon']);
}
// message::add(__FUNCTION__, "I=$i J=$j DT: " .$value['dt'] ." ==> $forecastTS");
// $value['dt'] = $forecastTS;
$this->checkAndUpdateCmd("MeteoHour${j}Json", str_replace('"','"',json_encode($value,JSON_UNESCAPED_UNICODE)));
$j++;
if($j == 10) break;
}
}
if($found == 0) {
$this->checkAndUpdateCmd('MeteonowTemperature', -666);
$this->checkAndUpdateCmd('MeteonowTemperatureRes', -666);
$this->checkAndUpdateCmd('MeteonowHumidity', -666);
$this->checkAndUpdateCmd('MeteonowPression', -666);
$this->checkAndUpdateCmd('MeteonowWindSpeed', -666);
$this->checkAndUpdateCmd('MeteonowWindGust', -666);
$this->checkAndUpdateCmd('MeteonowWindSpeed', -666);
$this->checkAndUpdateCmd('MeteonowRain1h', -666);
$this->checkAndUpdateCmd('MeteonowSnow1h', -666);
$this->checkAndUpdateCmd('MeteonowCloud', -666);
$this->checkAndUpdateCmd('MeteonowIcon', "0");
$this->checkAndUpdateCmd('MeteonowDescription', "Hour not found");
$this->checkAndUpdateCmd('Meteodayh1description', "Hour not found");
$this->checkAndUpdateCmd('Meteodayh1temperature', -666);
$this->checkAndUpdateCmd('Meteodayh1temperatureRes', -666);
$this->checkAndUpdateCmd('hourly1icon', "0");
}
// Update the daily_forecast commands
$nbD = count($return['daily_forecast']);
log::add(__CLASS__, 'debug', " NbDaily_forecast: $nbD");
for($i=0;$i<$nbD;$i++) {
$value= $return['daily_forecast'][$i];
$forecastTS = $value['dt'];
$value['dt12H'] = mktime(12,0,0,date('m',$forecastTS),date('d',$forecastTS),date('Y',$forecastTS));
log::add(__CLASS__, 'debug', " $i daily_forecast:" .date('d-m-Y H:i:s', $forecastTS));
if($i < 4) {
$this->checkAndUpdateCmd('Meteoday' .$i .'PluieCumul', $value['precipitation']['24h']);
/* n'existe pas dans les daily_forecast
$this->checkAndUpdateCmd('Meteoday' .$i .'directionVent', $value['wind_direction']);
$this->checkAndUpdateCmd('Meteoday' .$i .'vitesseVent', $value['wind_speed']);
$this->checkAndUpdateCmd('Meteoday' .$i .'forceRafales', $value['wind_speed_gust']);
*/
$this->checkAndUpdateCmd("Meteoday${i}indiceUV", $value['uv']);
$this->checkAndUpdateCmd("Meteoday${i}description", $value['weather12H']['desc']);
$this->checkAndUpdateCmd("Meteoday${i}icon", $value['weather12H']['icon']);
$this->checkAndUpdateCmd("Meteoday${i}temperatureMin", $value['T']['min']);
$this->checkAndUpdateCmd("Meteoday${i}temperatureMax", $value['T']['max']);
}
/* JSON structure
{ "dt":1686096000,
"T":{"min":12.1,"max":26.1,"sea":null},
"humidity":{"min":40,"max":75},
"precipitation":{"24h":0},
"uv":8,
"weather12H":{"icon":"p1j","desc":"Ensoleill\u00e9"},
"sun":{"rise":1686108819,"set":1686166464},
"dt12H":1686132000
}
*/
// $this->checkAndUpdateCmd("MeteoDay${i}Json", json_encode($value));
$this->checkAndUpdateCmd("MeteoDay${i}Json", str_replace('"','"',json_encode($value,JSON_UNESCAPED_UNICODE)));
}
}
public function getInstantsValues() { // Instant forecast (morning,afternoon,evening,night)
$lat = $this->getConfiguration('lat'); $lon = $this->getConfiguration('lon');
$ville = $this->getConfiguration('ville');
log::add(__CLASS__, 'debug', __FUNCTION__ ." $ville $lat/$lon");
if($lat == '' || $lon == '') {
log::add(__CLASS__, 'debug', " Invalid latitude/longitude: $lat/$lon");
return;
}
$url = "https://webservice.meteofrance.com/forecast?lat=$lat&lon=$lon&id=&instants=morning,afternoon,evening,night";
$return = self::callMeteoWS($url,false,true,__FUNCTION__ ."-$ville.json");
$nb = count($return['forecast']);
$updated_on = $return['updated_on'];
log::add(__CLASS__, 'debug', " updated_on: " .date('d-m-Y H:i:s', $updated_on) ." Nbforecast: $nb");
// add moment_day in json
for($i=0;$i<$nb-1;$i++) {
switch(date('H',$return['forecast'][$i]['dt'])) {
case 0: case 1: case 2: case 3: case 4: case 5:
$return['forecast'][$i]['moment_day'] = "Nuit";
break;
case 6: case 7: case 8: case 9: case 10: case 11:
$return['forecast'][$i]['moment_day'] = "Matin";
break;
case 12: case 13: case 14: case 15: case 16: case 17:
$return['forecast'][$i]['moment_day'] = "Après-midi";
break;
case 18: case 19: case 20: case 21: case 22: case 23:
$return['forecast'][$i]['moment_day'] = "Soirée";
break;
}
}
$now = time();
$found = 0; $j=0;
for($i=0;$i<$nb;$i++) {
$forecastTS = $return['forecast'][$i]['dt'] - 3*3600;
$forecastNextTS = $return['forecast'][$i+1]['dt'] - 3*3600;
$value = $return['forecast'][$i];
log::add(__CLASS__, 'debug', " $i forecast:" .date('d-m-Y H:i:s', $forecastTS) ." Desc: " .$value['weather']['desc']);
if(($now >= $forecastTS && $now < $forecastNextTS) || ($i==0 && $now < $forecastTS)) {
$found = 1;
for($j=0;$j<8;$j++) {
$value = $return['forecast'][$i+$j];
log::add(__CLASS__, 'debug', " Filling: $j forecast:" .date('d-m-Y H:i:s', $value['dt']) ." Moment: " .$value['moment_day']." Json: " .json_encode($value));
// $this->checkAndUpdateCmd("MeteoInstant${j}Json", json_encode($value));
$this->checkAndUpdateCmd("MeteoInstant${j}Json", str_replace('"','"',json_encode($value,JSON_UNESCAPED_UNICODE)));
}
break;
}
}
if(!$found) {
for($i=0;$i<8;$i++) {
$this->checkAndUpdateCmd("MeteoInstant${i}Json", '');
}
}
if(isset($return['probability_forecast'])) {
$this->checkAndUpdateCmd('MeteoprobaPluie', $return['probability_forecast'][0]['rain']['3h']);
$this->checkAndUpdateCmd('MeteoprobaNeige', $return['probability_forecast'][0]['snow']['3h']);
$this->checkAndUpdateCmd('MeteoprobaGel', $return['probability_forecast'][0]['freezing']);
/*
if($ville == 'Brest') {
log::add(__CLASS__, 'error', " Brest DT0: " .date('d-m H:i',$return['probability_forecast'][0]['dt']) ." Pluie3h: " .$return['probability_forecast'][0]['rain']['3h'] ." Neige3h: " .$return['probability_forecast'][0]['snow']['3h'] ." Gel: " .$return['probability_forecast'][0]['freezing']);
log::add(__CLASS__, 'error', " Brest DT1: " .date('d-m H:i',$return['probability_forecast'][1]['dt']) ." Pluie3h: " .$return['probability_forecast'][1]['rain']['3h'] ." Neige3h: " .$return['probability_forecast'][1]['snow']['3h'] ." Gel: " .$return['probability_forecast'][1]['freezing']);
}
*/
}
else {
$this->checkAndUpdateCmd('MeteoprobaPluie', -1);
$this->checkAndUpdateCmd('MeteoprobaNeige', -1);
$this->checkAndUpdateCmd('MeteoprobaGel', -1);
}
$this->checkAndUpdateCmd('MeteoprobaStorm', -666); // Obsolete
// Init des commandes obsoletes si elles existent
$cmd = $this->getCmd(null, 'Meteonuit0description');
if(is_object($cmd)) { // Si les commandes Meteoxxxx ont été créées
$moments = array('nuit', 'matin', 'midi', 'soir');
$cmds = array('description', 'directionVent', 'vitessVent', 'forceRafales', 'temperatureMin', 'temperatureMax');
foreach($moments as $moment) {
for($i=0;$i<2;$i++) {
foreach($cmds as $cmd) {
$logicalId = "Meteo$moment$i$cmd";
if($cmd == 'description')
$this->checkAndUpdateCmd($logicalId, 'Obsolete command');
else
$this->checkAndUpdateCmd($logicalId, -666); // Obsolete
}
}
}
}
}
public function getRain() {
$lat = $this->getConfiguration('lat'); $lon = $this->getConfiguration('lon');
$ville = $this->getConfiguration('ville');
log::add(__CLASS__, 'debug', __FUNCTION__ ." $ville $lat/$lon");
if($lat == '' || $lon == '') {
log::add(__CLASS__, 'debug', " Invalid latitude/longitude: $lat/$lon");
return;
}
$url = "https://webservice.meteofrance.com/rain?lat=$lat&lon=$lon";
$return = self::callMeteoWS($url,false,true,__FUNCTION__ ."-$ville.json");
$i = 0; $cumul = 0; $next = 0; $type = '';
if(isset($return['forecast'])) {
// $timezone = $return['position']['timezone'];
// $updated_on = self::convertMFdt2UnixTS($return['updated_on'],$timezone);
$updated_on = $return['updated_on'];
log::add(__CLASS__, 'debug', " Updated_on: " .date('d-m-Y H:i:s', $updated_on));
foreach ($return['forecast'] as $id => $rain) {
$i++;
$this->checkAndUpdateCmd('Rainrain' . $i, $rain['rain']);
$this->checkAndUpdateCmd('Raindesc' . $i, $rain['desc']);
if (($rain['rain'] > 1) && ($next == 0)) {
$next = $i * 5;
if ($i > 6) {
$next += ($i - 6) * 5;
//after 30 mn, steps are for 10mn
}
$type = $rain['desc'];
}
$cumul += $rain['rain'];
}
// $dt = self::convertMFdt2UnixTS($return['forecast'][0]['dt'],$timezone);
$dt = $return['forecast'][0]['dt'];
$this->checkAndUpdateCmd('Rainheure', date('Hi',$dt));
}
else {
for($i=1;$i<10;$i++) {
$this->checkAndUpdateCmd('Rainrain' . $i, 0);
$this->checkAndUpdateCmd('Raindesc' . $i, "Absence de prévision");
}
$this->checkAndUpdateCmd('Rainheure', date('Hi'));
}
$this->checkAndUpdateCmd('Raincumul', $cumul);
$this->checkAndUpdateCmd('Rainnext', $next);
$this->checkAndUpdateCmd('Raintype', $type);
}
public function getMarine() {
$lat = $this->getConfiguration('lat'); $lon = $this->getConfiguration('lon');
if($lat == '' || $lon == '') {
log::add(__CLASS__, 'debug', __FUNCTION__ ." Invalid latitude/longitude: $lat/$lon");
return;
}
log::add(__CLASS__, 'debug', __FUNCTION__ ." $lat/$lon");
$url = "https://rpcache-aa.meteofrance.com/internet2018client/2.0/forecast/marine?lat=$lat&lon=$lon";
$return = self::callMeteoWS($url,false,true,__FUNCTION__ ."-2-${lat}_$lon.json");
$t = time();
foreach ($return['properties']['marine'] as $id => $marine) {
$id = 0; // Pas d'autre commande que 0 TODO to be checked
$marineTS = strtotime($marine['time']);
if($t < $marineTS) continue;
if($t >= $marineTS) {
$this->checkAndUpdateCmd('Marinewind_speed_kt' . $id, $marine['wind_speed_kt']);
$this->checkAndUpdateCmd('Marinewind_direction' . $id, $marine['wind_direction']);
$this->checkAndUpdateCmd('Marinebeaufort_scale' . $id, $marine['beaufort_scale']);
$this->checkAndUpdateCmd('Marinewave_height' . $id, $marine['wave_height']);
$this->checkAndUpdateCmd('Marinemax_wave_height' . $id, $marine['max_wave_height']);
$this->checkAndUpdateCmd('Marinewind_waves_height' . $id, $marine['wind_waves_height']);
$this->checkAndUpdateCmd('Marineprimary_swell_direction' . $id, $marine['primary_swell_direction']);
$this->checkAndUpdateCmd('Marineprimary_swell_height' . $id, $marine['primary_swell_height']);
$this->checkAndUpdateCmd('Marineprimary_swell_period' . $id, $marine['primary_swell_period']);
$this->checkAndUpdateCmd('MarineT_sea' . $id, $marine['T_sea']);
$this->checkAndUpdateCmd('Marinesea_condition' . $id, $marine['sea_condition']);
$this->checkAndUpdateCmd('Marinesea_condition_description' . $id, $marine['sea_condition_description']);
break;
}
}
}
public function getTide() {
$insee = $this->getConfiguration('insee');
$ville = $this->getConfiguration('ville');
log::add(__CLASS__, 'debug', __FUNCTION__ ." Insee: $insee Ville $ville");
$url = 'https://rpcache-aa.meteofrance.com/internet2018client/2.0/tide?id=' .$insee .'52';
$return = self::callMeteoWS($url,false,true,__FUNCTION__ ."-${insee}-$ville.json");
if(isset($return['properties']['tide'])) {
$this->checkAndUpdateCmd('Tidehigh_tide0time', date('Hi',strtotime($return['properties']['tide']['high_tide'][0]['time'])));
$this->checkAndUpdateCmd('Tidehigh_tide0tidal_coefficient', $return['properties']['tide']['high_tide'][0]['tidal_coefficient']);
$this->checkAndUpdateCmd('Tidehigh_tide0tidal_height', $return['properties']['tide']['high_tide'][0]['tidal_height']);
if(isset($return['properties']['tide']['high_tide'][1]['time']))
$this->checkAndUpdateCmd('Tidehigh_tide1time', date('Hi',strtotime($return['properties']['tide']['high_tide'][1]['time'])));
else $this->checkAndUpdateCmd('Tidehigh_tide1time', -1);
if(isset($return['properties']['tide']['high_tide'][1]['tidal_coefficient']))
$this->checkAndUpdateCmd('Tidehigh_tide1tidal_coefficient', $return['properties']['tide']['high_tide'][1]['tidal_coefficient']);
else $this->checkAndUpdateCmd('Tidehigh_tide1tidal_coefficient', -1);
if(isset($return['properties']['tide']['high_tide'][1]['tidal_height']))
$this->checkAndUpdateCmd('Tidehigh_tide1tidal_height', $return['properties']['tide']['high_tide'][1]['tidal_height']);
else $this->checkAndUpdateCmd('Tidehigh_tide1tidal_height', -1);
$this->checkAndUpdateCmd('Tidelow_tide0time', date('Hi',strtotime($return['properties']['tide']['low_tide'][0]['time'])));
if(isset($return['properties']['tide']['low_tide'][0]['tidal_coefficient']))
$coef = $return['properties']['tide']['low_tide'][0]['tidal_coefficient'];
else $coef = 0;
$this->checkAndUpdateCmd('Tidelow_tide0tidal_coefficient', $coef);
$this->checkAndUpdateCmd('Tidelow_tide0tidal_height', $return['properties']['tide']['low_tide'][0]['tidal_height']);
$this->checkAndUpdateCmd('Tidelow_tide1time', date('Hi',strtotime($return['properties']['tide']['low_tide'][1]['time'])));
if(isset($return['properties']['tide']['low_tide'][1]['tidal_coefficient']))
$coef = $return['properties']['tide']['low_tide'][1]['tidal_coefficient'];
else $coef = 0;
$this->checkAndUpdateCmd('Tidelow_tide1tidal_coefficient', $coef);
$this->checkAndUpdateCmd('Tidelow_tide1tidal_height', $return['properties']['tide']['low_tide'][1]['tidal_height']);
}
}
function getVigilanceToken($alertPublicKey,$alertPrivateKey) {
$applicationId = base64_encode("$alertPublicKey:$alertPrivateKey");
$alertToken = config::byKey('alertToken', __CLASS__, '');
$alertTokenTS = config::byKey('alertTokenTS', __CLASS__, 0);
if($alertToken == '' || $alertTokenTS-30 < time()) { // create token / renew token
log::add(__CLASS__, 'debug', ' Create new or renew the token');
$url = "https://portail-api.meteofrance.fr/token";
$header = array("Authorization: Basic $applicationId");
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url, CURLOPT_HTTPHEADER => $header,
CURLOPT_SSL_VERIFYPEER => false, CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true, CURLOPT_POSTFIELDS => 'grant_type=client_credentials'));
$return = curl_exec($curl);
$curl_error = curl_error($curl);
curl_close($curl);
if($return === false) {
log::add(__CLASS__, 'error', " Unable to get token. curl_error: $curl_error");
return '';
}
$dec = json_decode($return,true);
if(isset($dec['access_token'])) {
$alertToken = $dec['access_token'];
config::save('alertToken', $alertToken, __CLASS__);
config::save('alertTokenTS', time()+ $dec['expires_in'], __CLASS__);
}
else {
$alertToken = '';
log::add(__CLASS__, 'debug', " Token was not set in MF answer: $return");
}
}
return $alertToken;
}
public function downloadVigDataApi($file,$token,$json,$fileResu) {
$url = "https://public-api.meteofrance.fr/public/DPVigilance/v1/$file";
log::add(__CLASS__, 'debug', " " .__FUNCTION__ ." Fetching data $file Url API: $url");
$header = array("Authorization: Bearer $token");
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url, CURLOPT_HTTPHEADER => $header,
CURLOPT_SSL_VERIFYPEER => false, CURLOPT_RETURNTRANSFER => true));
$resu = curl_exec($curl);
$curl_error = curl_error($curl);
curl_close($curl);
if($resu !== false) {
if($json) {
$dec = json_decode($resu,true);
$jsonError = json_last_error();
if($jsonError != JSON_ERROR_NONE) {
log::add(__CLASS__, 'warning', " Unable to get data from MeteoFrance. Json error: ($jsonError) ".json_last_error_msg());
return 0;
}
}
// writing result
$hdle = fopen($fileResu, "wb");
if($hdle !== FALSE) { fwrite($hdle, $resu); fclose($hdle); }
else {
log::add(__CLASS__, 'warning', " Unable to open file $fileResu for writing.");
return 0;
}
}
else {
log::add(__CLASS__, 'warning', " Unable to fetch $file. curl_error: $curl_error");
return 0;
}
return 1; // OK
}
public function downloadVigDataArchive($fileUrl,$json,$fileResu) {
log::add(__CLASS__, 'debug', " " .__FUNCTION__ ." Fetching archive data Url: $fileUrl");
// $contents = @file_get_contents($fileUrl);
$curl = curl_init();
curl_setopt_array($curl, array( CURLOPT_URL => $fileUrl,
CURLOPT_SSL_VERIFYPEER => false, CURLOPT_RETURNTRANSFER => true));
$contents = curl_exec($curl);
$curl_error = curl_error($curl);
curl_close($curl);
if($contents !== false) {
if($json) {
$dec = json_decode($contents,true);
$jsonError = json_last_error();
if($jsonError != JSON_ERROR_NONE) {
log::add(__CLASS__, 'warning', " Unable to get data from MeteoFrance. Json error: ($jsonError) ".json_last_error_msg());
return 1;
}
}
$hdle = fopen($fileResu, "wb");
if($hdle !== FALSE) { fwrite($hdle, $contents); fclose($hdle); }
else {
log::add(__CLASS__, 'warning', " Unable to open file for writing: $fileResu");
return 1;
}
}
else {
// log::add(__CLASS__, 'warning', " Unable to download $fileUrl");
log::add(__CLASS__, 'warning', " Unable to fetch $fileUrl. curl_error: $curl_error");
return 1;
}
return 0;
}
public function getVigilanceDataApiCloudMF() {
log::add(__CLASS__, 'debug', __FUNCTION__);
$alertPublicKey = trim(config::byKey('alertPublicKey', __CLASS__));
$alertPrivateKey = trim(config::byKey('alertPrivateKey', __CLASS__));
$fileAlert = __DIR__ ."/../../data/CDP_CARTE_EXTERNE.json";
$fileVignetteJ = __DIR__ ."/../../data/VIGNETTE_NATIONAL_J_500X500.png";
$fileVignetteJ1 = __DIR__ ."/../../data/VIGNETTE_NATIONAL_J1_500X500.png";
$recupAPI = 0;
$useVigilanceAPI = config::byKey('useVigilanceAPI', __CLASS__, 0);
// Vigilances avec l'API
if( $useVigilanceAPI == 1 && $alertPublicKey != '' && $alertPrivateKey != '') {
$token = self::getVigilanceToken($alertPublicKey,$alertPrivateKey);
if($token != '') {
// Json des vigilances
$file = "cartevigilance/encours";
$recupAPI += $this->downloadVigDataApi($file,$token,1,$fileAlert);
// Vignette du jour
$file = "vignettenationale-J/encours";
$recupAPI += $this->downloadVigDataApi($file,$token,0,$fileVignetteJ);
// Vignette de demain
$file = "vignettenationale-J1/encours";
$recupAPI += $this->downloadVigDataApi($file,$token,0,$fileVignetteJ1);
if($recupAPI == 3) // Recover vigilance with MF archives
log::add(__CLASS__, 'debug', " Data successfully downloaded using MF API");
}
}
if($recupAPI < 3) { // Recover vigilance with MF archives
if(date('H') < 6) $timeRecup = strtotime("yesterday");
else $timeRecup = time();
$dateRecup = date('Y/m/d',$timeRecup);
$url = "http://storage.gra.cloud.ovh.net/v1/AUTH_555bdc85997f4552914346d4550c421e/gra-vigi6-archive_public/$dateRecup/";
// log::add(__CLASS__, 'debug', " Fetching MF archives $url");
$doc = new DOMDocument();
libxml_use_internal_errors(true); // disable warning
$doc->preserveWhiteSpace = false;
if(@$doc->loadHTMLFile($url) !== false ) {
$xpath = new DOMXpath($doc);
$subdir = $xpath->query('//html/body/table/tr[@class="item subdir"]/td/a');
$nb = count($subdir);
$prevRecup = trim(config::byKey('prevVigilanceRecovery', __CLASS__));
$prevRecup = substr($prevRecup,0,-1);
// echo "Found: $nb PrevRecup: $prevRecup Daterecup: $dateRecup
";
$latest = '0';
$latestFileAlert = ''; $latestFileVignetteJ = ''; $latestFileVignetteJ1 = '';
$filesOK = file_exists($fileAlert) && file_exists($fileVignetteJ) && file_exists($fileVignetteJ1);
for($i=0;$i<$nb;$i++) {
$val = $subdir[$i]->getAttribute('href');
$val2 = substr($val,0,-1);
$url2 = $url .$val2;
$currRecup = date('Ymd',$timeRecup);
$newRecup = $currRecup.$val2;
if($prevRecup >= $newRecup && $filesOK) {
log::add(__CLASS__, 'debug', " Data already processed: $dateRecup/$val2");
continue;
}
$latest = $val2;
// echo "New Data Recup: $dateRecup/$val2
";
// log::add(__CLASS__, 'debug', " Fetching MF archives $url2");
$doc2 = new DOMDocument();
libxml_use_internal_errors(true); // disable warning
$doc2->preserveWhiteSpace = false;
if(@$doc2->loadHTMLFile($url2) !== false ) {
$xpath2 = new DOMXpath($doc2);
$subdir2 = $xpath2->query('//html/body/table/tr/td[@class="colname"]/a');
$nb2 = count($subdir2);
for($i2=0;$i2<$nb2;$i2++) {
$val3 = $subdir2[$i2]->getAttribute('href');
if($val3 == "CDP_CARTE_EXTERNE.json") {
$latestFileAlert = "$url2/$val3";
}
else if($val3 == "VIGNETTE_NATIONAL_J_500X500.png") {
$latestFileVignetteJ = "$url2/$val3";
}
else if($val3 == "VIGNETTE_NATIONAL_J1_500X500.png") {
$latestFileVignetteJ1 = "$url2/$val3";
}
}
}
else {
log::add(__CLASS__, 'warning', " Unable to fetch $url2");
return 1; // erreur
}
// log::add(__CLASS__, 'debug', " Val: [$val] Latest: $latest");
}
$err = 0;
if($latestFileAlert != '') {
$err += $this->downloadVigDataArchive($latestFileAlert,1,$fileAlert);
/*
$contents = @file_get_contents($latestFileAlert);
if($contents !== false) {
$hdle = fopen($fileAlert, "wb");
if($hdle !== FALSE) { fwrite($hdle, $contents); fclose($hdle); }
else {
log::add(__CLASS__, 'warning', " Unable to open file for writing: $fileAlert");
$err++;
}
}
else {
log::add(__CLASS__, 'warning', " Unable to download $latestFileAlert");
$err++;
}
*/
}
if($latestFileVignetteJ != '') {
$err += $this->downloadVigDataArchive($latestFileVignetteJ,0,$fileVignetteJ);
/*
$contents = @file_get_contents($latestFileVignetteJ);
if($contents !== false) {
$hdle = fopen($fileVignetteJ, "wb");
if($hdle !== FALSE) { fwrite($hdle, $contents); fclose($hdle); }
else {
log::add(__CLASS__, 'warning', " Unable to open file for writing: $fileVignetteJ");
$err++;
}
}
else {
log::add(__CLASS__, 'warning', " Unable to download $latestFileVignetteJ");
$err++;
}
*/
}
if($latestFileVignetteJ1 != '') {
$err += $this->downloadVigDataArchive($latestFileVignetteJ1,0,$fileVignetteJ1);
/*
$contents = @file_get_contents($latestFileVignetteJ1);
if($contents !== false) {
$hdle = fopen($fileVignetteJ1, "wb");
if($hdle !== FALSE) { fwrite($hdle, $contents); fclose($hdle); }
else {
log::add(__CLASS__, 'warning', " Unable to open file for writing: $fileVignetteJ1");
$err++;
}
}
else {
log::add(__CLASS__, 'warning', " Unable to download $latestFileVignetteJ1");
$err++;
}
*/
}
if($err == 0 && $latest != 0) {
$latestFull = date('Ymd',$timeRecup) .$latest .'Z';
config::save('prevVigilanceRecovery', $latestFull, __CLASS__);
}
}
else {
log::add(__CLASS__, 'debug', " Unable to fetch $url");
return 1; // erreur
}
}
return 0; // OK
}
public function getVigilance() {
$numDept = $this->getConfiguration('numDept');
if($numDept == '') {
log::add(__CLASS__, 'debug', __FUNCTION__ ." Département non défini.");
return;
}
log::add(__CLASS__, 'debug', __FUNCTION__ ." Département: $numDept");
$fileData = __DIR__ ."/../../data/CDP_CARTE_EXTERNE.json";
$contents = @file_get_contents($fileData);
if($contents === false) {
log::add(__CLASS__, 'warning', " Unable to load data from $fileData");
// TODO clean des cmds ou pas ?
return;
}
$return = json_decode($contents,true);
if($return === false) {
@unlink($fileData);
// TODO clean des cmds ou pas ?
return;
}
$txtTsAlerts = array(); $phenomColor = array();
// init all values
foreach(self::$_vigilanceType as $i => $vig) {
$txtTsAlerts[$i] = ''; $phenomColor[$i] = 0;
}
$maxColor = 0; $now = time();
// $numDept = '06';
$vigJson = array();
foreach($return['product']['periods'] as $period) {
$startPeriod = strtotime($period['begin_validity_time']);
$endPeriod = strtotime($period['end_validity_time']);
if($now > $endPeriod || $now < $startPeriod) continue; // just one day
$vigJson['begin_validity_time'] = $period['begin_validity_time'];
$vigJson['end_validity_time'] = $period['end_validity_time'];
$vigJson['domain_id'] = "none";
$prevVigRecup = trim(config::byKey('prevVigilanceRecovery', __CLASS__));
if(date('Ymd') != substr($prevVigRecup,0,8)) $img = 'VIGNETTE_NATIONAL_J1_500X500.png';
else $img = 'VIGNETTE_NATIONAL_J_500X500.png';
$vigJson['image'] = $img;
// log::add(__CLASS__, 'debug', " Validity period start: " .date("d-m-Y H:i",$startPeriod) ." end: " .date("d-m-Y H:i",$endPeriod));
foreach($period['timelaps']['domain_ids'] as $domain_id) {
$dept = $domain_id['domain_id'];
if($dept == $numDept || $dept == $numDept .'10') { // concat 10 si departement bord de mer
log::add(__CLASS__, 'debug', " Domain: $dept JSON: " .json_encode($domain_id));
if(strlen($dept) == 2 ) $txt = 'dept';
else $txt = 'littoral';
$vigJson[$txt] = $domain_id;
foreach($domain_id['phenomenon_items'] as $phenomenonItem) {
$phenId = $phenomenonItem['phenomenon_id'];
$color = $phenomenonItem['phenomenon_max_color_id'];
if($color > $maxColor) $maxColor = $color;
$phenomColor[$phenId] = $color;
if($color > 1) {
foreach($phenomenonItem['timelaps_items'] as $timelapsItem) {
$colorTs = $timelapsItem['color_id'];
if($colorTs != 0) {
$begin = strtotime($timelapsItem['begin_time']);
$end = strtotime($timelapsItem['end_time']);
if($now < $end) {
$txtTsAlerts[$phenId] .= "
" .date('H:i',$begin) ." - " .date('H:i',$end);
log::add(__CLASS__, 'debug', " PhenomId: $phenId Color: $color start:" .date("d-m-Y H:i:s",$begin)." End:" .date("d-m-Y H:i:s",$end) ." MaxColor: $maxColor");
}
}
}
}
}
}
}
}
$this->checkAndUpdateCmd('Vigilancecolor_max', $maxColor);
// save departement file
$fileDept = __DIR__ ."/../template/images/dept_fr_$numDept-grey.svg";
$contents = @file_get_contents($fileDept);
if($contents !== false) {
$val = str_replace('#888888',self::$_vigilanceColors[$maxColor]['color'],$contents);
$fileNewDept = __DIR__ ."/../../data/dept_fr_$numDept.svg";
$res = file_put_contents($fileNewDept,$val);
if($res === false) log::add(__CLASS__,'debug',"Unable to save file: $fileNewDept");
else $vigJson['domain_id'] = $numDept;
}
else log::add(__CLASS__, 'debug', " File $fileDept not found");
// Save Json command
if(count($vigJson)) {
$contents = str_replace('"','"',json_encode($vigJson,JSON_UNESCAPED_UNICODE));
$this->checkAndUpdateCmd("VigilanceJson", $contents);
/*
$file = __DIR__ ."/../../data/" .__FUNCTION__ ."-$numDept.json";
$hdle = fopen($file, "wb");
if($hdle !== FALSE) { fwrite($hdle, $contents); fclose($hdle); }
*/
}
// Other commands
foreach(self::$_vigilanceType as $i => $vig) {
// if($phenomColor[$i] > 1) message::add(__CLASS__, "Vigilance $i " .$phenomColor[$i] .$txtTsAlerts[$i]);
$this->checkAndUpdateCmd("Vigilancephases$i",
self::$_vigilanceColors[$phenomColor[$i]]['desc'] .$txtTsAlerts[$i]);
$this->checkAndUpdateCmd("Vigilancephenomenon_max_color_id$i", $phenomColor[$i]);
}
/*
* $listVigilance = array(); TODO command not updated
$value[0]=''; $value[1]="Vert"; $value[2]="Jaune"; $value[3]="Orange"; $value[4]="Rouge";
foreach ($return['phenomenons_items'] as $id => $vigilance) {
$this->checkAndUpdateCmd('Vigilancephenomenon_max_color_id' . $vigilance['phenomenon_id'], $vigilance['phenomenon_max_color_id']);
if ($vigilance['phenomenon_max_color_id'] > 1) {
$cmd = meteofranceCmd::byEqLogicIdAndLogicalId($this->getId(),'Vigilancephases' . $vigilance['phenomenon_id']);
$listVigilance[] = $type[$vigilance['phenomenon_id']] . ' : ' . $value[$vigilance['phenomenon_max_color_id']] . ', ' . $cmd->execCmd();
}
}
$this->checkAndUpdateCmd('Vigilancelist', implode(', ',$listVigilance));
*/
$this->checkAndUpdateCmd('Vigilancelist', "Obsolete command");
}
public function getAlerts() {
log::add(__CLASS__, 'debug', __FUNCTION__);
$url = 'https://webservice.meteofrance.com//report?domain=france&report_type=message&report_subtype=infospe&format=';
$return = self::callMeteoWS($url,false,true,__FUNCTION__ .".json");
if (isset($return['Com'][0]['titre'])) {
$this->checkAndUpdateCmd('Alerttitre', $return['Com'][0]['titre']);
$this->checkAndUpdateCmd('Alerttexte', $return['Com'][0]['texte']);
$this->checkAndUpdateCmd('AlertdateDeFin', $return['Com'][0]['dateDeFin']);
$this->checkAndUpdateCmd('AlertdateProduction', $return['Com'][0]['dateProduction']);
}
}
public function getEphemeris() {
date_default_timezone_set(config::byKey('timezone'));
$lat = $this->getConfiguration('lat'); $lon = $this->getConfiguration('lon');
if($lat == '' || $lon == '') {
log::add(__CLASS__, 'debug', __FUNCTION__ ." Invalid latitude/longitude: $lat/$lon");
return;
}
log::add(__CLASS__, 'debug', __FUNCTION__ ." $lat/$lon");
$url = "https://webservice.meteofrance.com/ephemeris?lat=$lat&lon=$lon";
$ville = $this->getConfiguration('ville');
$return = self::callMeteoWS($url,false,true,__FUNCTION__ ."-$ville.json");
$this->checkAndUpdateCmd('Ephemerismoon_phase', $return['properties']['ephemeris']['moon_phase']);
$this->checkAndUpdateCmd('Ephemerismoon_phase_description', $return['properties']['ephemeris']['moon_phase_description']);
$this->checkAndUpdateCmd('Ephemerissaint', $return['properties']['ephemeris']['saint']);
//log::add(__CLASS__, 'debug', 'Date ' . $return['properties']['ephemeris']['sunrise_time'] . ', ' . strtotime($return['properties']['ephemeris']['sunrise_time']));
$this->checkAndUpdateCmd('Ephemerissunrise_time', date('Hi',strtotime($return['properties']['ephemeris']['sunrise_time'])));
$this->checkAndUpdateCmd('Ephemerissunset_time', date('Hi',strtotime($return['properties']['ephemeris']['sunset_time'])));
$this->checkAndUpdateCmd('Ephemerismoonrise_time', date('Hi',strtotime($return['properties']['ephemeris']['moonrise_time'])));
$this->checkAndUpdateCmd('Ephemerismoonset_time', date('Hi',strtotime($return['properties']['ephemeris']['moonset_time'])));
}
public function getBulletinFrance() {
log::add(__CLASS__, 'debug', __FUNCTION__);
$url = 'https://webservice.meteofrance.com/report?domain=france&report_type=forecast&report_subtype=BGP';
$return = self::callMeteoWS($url,true,true,__FUNCTION__ .".json");
if(isset($return['groupe'][0])) {
$this->checkAndUpdateCmd('Bulletinfrdate0', $return['groupe'][0]['date']);
$this->checkAndUpdateCmd('Bulletinfrtitre0', $return['groupe'][0]['titre']);
$this->checkAndUpdateCmd('Bulletinfrtemps0', $return['groupe'][0]['temps']);
$this->checkAndUpdateCmd('Bulletinfrdate1', $return['groupe'][1]['date']);
$this->checkAndUpdateCmd('Bulletinfrtitre1', $return['groupe'][1]['titre']);
$this->checkAndUpdateCmd('Bulletinfrtemps1', $return['groupe'][1]['temps']);
}
else {
$this->checkAndUpdateCmd('Bulletinfrdate0', $return['groupe']['date']);
$this->checkAndUpdateCmd('Bulletinfrtitre0', $return['groupe']['titre']);
$this->checkAndUpdateCmd('Bulletinfrtemps0', $return['groupe']['temps']);
$this->checkAndUpdateCmd('Bulletinfrdate1', '');
$this->checkAndUpdateCmd('Bulletinfrtitre1', '');
$this->checkAndUpdateCmd('Bulletinfrtemps1', '');
}
}
public function getBulletinSemaine() {
log::add(__CLASS__, 'debug', __FUNCTION__);
$url = 'https://rpcache-aa.meteofrance.com/internet2018client/2.0/report?domain=france&report_type=forecast&report_subtype=BGP_mensuel';
// $return = self::callMeteoWS($url, true);
$return = self::callMeteoWS($url,true,true,__FUNCTION__ .".json");
$this->checkAndUpdateCmd('Bulletindatesem', $return['groupe'][0]['date']);
if(isset($return['groupe'][0]['temps'])) {
$this->checkAndUpdateCmd('Bulletintempssem', $return['groupe'][0]['temps']);
}
}
public static function lowerAccent($_var) {
$return = str_replace(' ','_',strtolower($_var));
$return = preg_replace('#Ç#', 'C', $return);
$return = preg_replace('#ç#', 'c', $return);
$return = preg_replace('#è|é|ê|ë#', 'e', $return);
$return = preg_replace('#à|á|â|ã|ä|å#', 'a', $return);
$return = preg_replace('#ì|í|î|ï#', 'i', $return);
$return = preg_replace('#ð|ò|ó|ô|õ|ö#', 'o', $return);
$return = preg_replace('#ù|ú|û|ü#', 'u', $return);
$return = preg_replace('#ý|ÿ#', 'y', $return);
$return = preg_replace('#Ý#', 'Y', $return);
$return = str_replace('_', '-', $return);
$return = str_replace('\'', '', $return);
return $return;
}
public static function getIcones($_var) {
$return = array();
$return['nuit claire'] = 'night-clear';
$return['tres nuageux'] = 'cloudy';
$return['couvert'] = 'cloudy';
$return['brume'] = 'fog';
$return['brume ou bancs de brouillard'] = 'fog';
$return['brouillard'] = 'fog';
$return['brouillard givrant'] = 'fog';
$return['risque de grele'] = 'hail';
$return['orages'] = 'lightning';
$return['risque d\'orages'] = 'lightning';
$return['pluie orageuses'] = 'thunderstorm';
$return['pluies orageuses'] = 'thunderstorm';
$return['averses orageuses'] = 'thunderstorm';
$return['ciel voile'] = 'cloud';
$return['ciel voile nuit'] = 'cloud';
$return['eclaircies'] = 'cloud';
$return['peu nuageux'] = 'cloud';
$return['pluie forte'] = 'rain';
$return['bruine / pluie faible'] = 'showers';
$return['bruine'] = 'showers';
$return['pluie faible'] = 'showers';
$return['pluies eparses / rares averses'] = 'showers';
$return['pluies eparses'] = 'showers';
$return['rares averses'] = 'showers';
$return['pluie moderee'] = 'rain';
$return['pluie / averses'] = 'rain';
$return['pluie faible'] = 'showers';
$return['averses'] = 'rain';
$return['pluie'] = 'rain';
$return['neige'] = 'snow';
$return['neige forte'] = 'snow';
$return['quelques flocons'] = 'snow';
$return['averses de neige'] = 'snow';
$return['neige / averses de neige'] = 'snow';
$return['pluie et neige'] = 'snow';
$return['pluie verglacante'] = 'sleet';
$return['ensoleille'] = 'day-sunny';
return $return[self::lowerAccent($_var)];
}
public static function callMeteoWS($_url, $_xml = false, $_token = true,$debugFile='') {
//$token = config::byKey('token', 'meteofrance');
if ($_token) {
$token = '&token=__Wj7dVSTjV9YGu1guveLyDq0g7S7TfTjaHBTPTpO0kj8__';
} else {
$token = '';
}
log::add(__CLASS__, 'debug', " Get: $_url$token");
$request_http = new com_http($_url . $token);
$request_http->setNoSslCheck(true);
$request_http->setNoReportError(true);
$return = $request_http->exec(15,1);
if ($return === false) {
log::add(__CLASS__, 'debug', " Unable to fetch $_url");
return;
}
if ($_xml) {
$xml = simplexml_load_string($return, 'SimpleXMLElement', LIBXML_NOCDATA);
$return = json_encode($xml);
}
// log result in file or with log class
$loglevel = log::convertLogLevel(log::getLogLevel(__CLASS__));
if($loglevel == 'debug') {
if($debugFile != '') {
$file = __DIR__ ."/../../data/$debugFile";
$hdle = fopen($file,"wb");
if($hdle !== FALSE) {
fwrite($hdle, $return);
fclose($hdle);
log::add(__CLASS__, 'debug', " Result saved in file: " .realpath($file));
}
}
else log::add(__CLASS__, 'debug', " Result $return");
}
return json_decode($return, true);
}
public static function callURL($_url) {
$request_http = new com_http($_url);
$request_http->setNoSslCheck(true);
$request_http->setNoReportError(true);
$return = $request_http->exec(15,2);
if ($return === false) {
log::add(__CLASS__, 'debug', 'Unable to fetch ' . $_url);
return;
} else {
log::add(__CLASS__, 'debug', ' Get ' . $_url);
log::add(__CLASS__, 'debug', ' Result ' . $return);
}
return json_decode($return, true);
}
public function loadCmdFromConf($type) {
/*create commands based on template*/
if (!is_file(__DIR__ . '/../config/devices/' . $type . '.json')) {
return;
}
$content = file_get_contents(__DIR__ . '/../config/devices/' . $type . '.json');
if (!is_json($content)) {
return;
}
$device = json_decode($content, true);
if (!is_array($device) || !isset($device['commands'])) {
return true;
}
foreach ($device['commands'] as $command) {
$cmd = null;
foreach ($this->getCmd() as $liste_cmd) {
if ((isset($command['logicalId']) && $liste_cmd->getLogicalId() == $command['logicalId'])
|| (isset($command['name']) && $liste_cmd->getName() == $command['name'])) {
$cmd = $liste_cmd;
break;
}
}
if ($cmd == null || !is_object($cmd)) {
$cmd = new meteofranceCmd();
$cmd->setEqLogic_id($this->getId());
utils::a2o($cmd, $command);
log::add(__CLASS__, 'debug', " Command creation: " .$command['name']);
$cmd->save();
}
}
}
public function getMFimg($filename) {
$url = 'https://meteofrance.com/modules/custom/mf_tools_common_theme_public/svg/weather';
$localdir = __DIR__ ."/../../data/icones";
if(strlen($filename) < 5) // 0.svg .svg ...
return("plugins/" .__CLASS__ ."/data/icones/0.svg");
if(!file_exists("$localdir/$filename")) {
$content = @file_get_contents("$url/$filename");
if($content === false) {
log::add(__CLASS__,'debug',"Unable to get file: $url/$filename");
return("$url/$filename");
}
if(!is_dir($localdir)) @mkdir($localdir,0777,true);
$res = file_put_contents("$localdir/$filename",$content);
if($res === false) {
log::add(__CLASS__,'debug',"Unable to save file: $localdir/$filename");
return("$url/$filename");
}
}
return("plugins/" .__CLASS__ ."/data/icones/$filename");
}
public function convertMFdt2UnixTS($dt,$timezone) {
$dateTZ = date_create('now', timezone_open($timezone));
$offset = date_offset_get($dateTZ);
// log::add(__CLASS__, 'debug', " TZ=$timezone Offset=$offset Gmdate:".gmdate('d-m H:i',$dt) ." Date:".date('d-m H:i',$dt-$offset));
return($dt - $offset);
}
public function convertDegrees2Compass($degrees,$deg=0) {
$sector = array("Nord","NNE","NE","ENE","Est","ESE","SE","SSE","Sud","SSO","SO","OSO","Ouest","ONO","NO","NNO","Nord");
$degrees %= 360;
$idx = round($degrees/22.5);
if($deg) {
return($sector[$idx] ." $degrees" ."°");
}
else return($sector[$idx]);
}
public function toHtml($_version = 'dashboard') {
$replace = $this->preToHtml($_version);
if (!is_array($replace)) {
return $replace;
}
$version = jeedom::versionAlias($_version);
if ($this->getDisplay('hideOn' . $version) == 1) {
return '';
}
$lat = $this->getConfiguration('lat'); $lon = $this->getConfiguration('lon');
$ville = $this->getConfiguration('ville'); $zip = $this->getConfiguration('zip');
$insee = $this->getConfiguration('insee'); $timezone = $this->getConfiguration('timezone');
if($ville == '' || $lon == '' || $lat == '' || $zip == '') {
$replace['#cmd#'] = '