Daten aus POLAR Flow-Portal auslesen

Moin,

mit diesem Skript lese ich die Daten (Kilometer, Gesamtzeit etc…) meiner Lauf- und Rad-Trainingseinheiten aus dem FLOW-Portal von Polar aus. Diese können anschl. in IPS visualisiert werden. Darüber hinaus werden zu jeder Einheit automatisch die dazu gehörenden TCX-Dateien heruntergeladen und gespeichert, was manuell mit sehr viel Klickerei und Zeitaufwand verbunden ist. Getestet habe ich mit einer M400 und normalem FlowSync.

  • Zunächst Variablen anlegen und IDs im Skript anpassen
  • Username und Passwort eintragen
  • das Skript zyklisch, nach Bedarf, laufen lassen
<?
// Trainigseinheiten des aktuellen Jahres aus POLAR Flow-Portal laden
// und Gesamtkilometer sowie Zeiten für RUNNING und CYCLING in SYMCON-Vars speichern
// Automatisches Runterladen der TCX-Dateien pro Einheit
//
// Die u.a. Variablen für die Summen müssen angelegt werden. Typ siehe Beschreibung.
// "%user_email" und "%password" müssen definiert werden.

$var_id_jkr=41992;   // Variablen-ID Jahreskilometer Laufen(Float)
$var_id_jzr=47111;   // Variablen-ID Gesamtzeit Jahr Laufen (String)
$var_id_mkr=58965;   // Variablen-ID Monatskilometer Laufen (Float)
$var_id_mzr=40851;   // Variablen-ID Gesamtzeit Monat Laufen (String)
$var_id_wkr=37147;   // Variablen-ID Wochenkilometer Laufen (Float)
$var_id_wzr=15683;   // Variablen-ID Gesamtzeit Woche Laufen (String)

$var_id_jkc=40989;  // Variablen-ID Jahreskilometer Radfahren (Float)
$var_id_jzc=55080;  // Variablen-ID Gesamtzeit Jahr Radfahren (String)
$var_id_mkc=37029;  // Variablen-ID Monatskilometer Radfahren (Float)
$var_id_mzc=18416;  // Variablen-ID Gesamtzeit Monat Radfahren (String)
$var_id_wkc=11328;  // Variablen-ID Wochenkilometer Radfahren (Float)
$var_id_wzc=57568;  // Variablen-ID Gesamtzeit Woche Radfahren (String)

$user_email = 'max@mustermann.de';  // E-Mail-Adresse für Anmeldung am FLOW-Portal
$user_pass = 'passwort';            // Das dazu gehörige Passwort

$start_date="01.01.".date('Y');     // Sollte in der Regel nicht geändert werden! Kann ggf. weiter zurückgesetzt werden. Skript-Laufzeit beachten!
$end_date = date('d.m.Y');

$local_file_dir="C:/ip-symcon/Laufen/";   // Hier werden die TCX-Dateien abgelegt
$sem_dat="C:/ip-symcon/Laufen/index.dat"; // Name der Indexdatei
$temp_pfad="C:/ip-symcon/temp";           // Pfad, in dem temporär die ZIP-Dateien abgelegt werden. Diese werden vom Skript anschl. wieder gelöscht


//****************************** und los... ************************************
$summe = array
(
	'Running' => array (0,0,0,0,0,0),
	'Cycling' => array(0,0,0,0,0,0)
);

$akt_mon=intval(date('m'));
$akt_wo=intval(date("W",time()));

$post_fields = 'returnUrl=https%3A%2F%2Fflow.polar.com%2F&email=' . $user_email . '&password=' . $user_pass;
$ch = curl_init();
curl_setopt($ch, CURLOPT_COOKIEJAR, $ch);
curl_setopt($ch, CURLOPT_COOKIEFILE, $ch);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_URL, 'https://flow.polar.com/training/getCalendarEvents?start=' . $start_date . '&end=' . $end_date);
$arr = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200)
 {
    curl_setopt($ch, CURLOPT_POST, 0);
    curl_setopt($ch, CURLOPT_URL, 'https://flow.polar.com/ajaxLogin');
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    $arr = curl_exec($ch); //Login Seite

    curl_setopt($ch, CURLOPT_URL, 'https://flow.polar.com/login');
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
    $arr = curl_exec($ch); //Zugangsdaten übermitteln
    curl_setopt($ch, CURLOPT_POST, 0);
    curl_setopt($ch, CURLOPT_URL, 'https://flow.polar.com/training/getCalendarEvents?start=' . $start_date . '&end=' . $end_date);
    curl_setopt($ch,CURLOPT_FAILONERROR,1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    $arr = curl_exec($ch); //Aktivitätenliste
	}
$activity_arr = json_decode($arr);

// Acitivity-Datensätze checken, ob alle TCX-Dateien schon da sind, oder
// ob es Updates gibt.
//
foreach ($activity_arr as $activity)
{
 if ($activity->type == 'EXERCISE')
 	{

			// Schauen, ob TCX-Dateien schon da sind....
			//
		  $index= $activity->listItemId;
   	  IF (IstVorhanden($sem_dat,$index) <> "error" )
		  {
				$t=IstVorhanden($sem_dat,$index);
				$arr_index=substr($t,strpos($t,"_")+1,strlen($t)-strpos($t,"_")-6);
		  }
		  ELSE
		  {
		      // falls nicht vorhanden, ZIP-Archiv runterladen, auspacken und speichern
            $tcxzipurl = 'https://flow.polar.com' . $activity->url . '/export/tcx/true';
            curl_setopt($ch, CURLOPT_URL, $tcxzipurl); //fetch TCX
            $tcxzip = curl_exec($ch);
            $zipfilename = tempnam($temp_pfad, 'polarsync');
            file_put_contents($zipfilename, $tcxzip);
            $zip = new ZipArchive();
            if (!$zip->open($zipfilename)) echo 'ERROR beim Öffenen der Zip-Datei!!';
            for ($i = 0; $i < $zip->numFiles; $i++) {
	             $tcxname = $zip->getNameIndex($i);
	             $arr_index=substr($tcxname,strpos($tcxname,"_")+1,strlen($tcxname)-strpos($tcxname,"_")-5);
            	 $zip->extractTo($local_file_dir);
                $zip->close();
                echo "$index nicht vorhanden...wird angelegt mit Dateiname: $tcxname";
 				    $handler=fOpen($sem_dat,"a");
					 $datensatz=TRIM($index).";".$tcxname."
";
					 fWrite($handler,$datensatz);
					 fClose($handler);
                }
            echo PHP_EOL;
            unlink($zipfilename); //Temporäres ZIP-Archiv löschen
		  }
		   // ************* Kilometer und Zeiten addieren ************************
 	      $dat=$activity->datetime;
 	      $datum=substr($dat,8,2).".".substr($dat,5,2).".".substr($dat,0,4);
			$monat=intval(substr($dat,5,2));
			$sekunden=$activity->duration/1000;
			$km=$activity->distance*0.001;
			$km=round ( $km,2);

  			$summe[$arr_index] [0] = $summe[$arr_index] [0] + $km;
			$summe[$arr_index] [3] = $summe[$arr_index] [3] + $sekunden;

			IF ($monat==$akt_mon)
			{
			   $summe[$arr_index] [1] = $summe[$arr_index] [1] + $km;
				$summe[$arr_index] [4] = $summe[$arr_index] [4] + $sekunden;
			}
			$d=strtotime($datum);
			$woe=date("W",$d);
			IF ($woe== $akt_wo )
			{
   			$summe[$arr_index] [2] = $summe[$arr_index] [2] + $km;
    			$summe[$arr_index] [5] = $summe[$arr_index] [5] + $sekunden;
			}

    }
}

// Update der Variablen (Running)
Setvalue($var_id_jkr ,$summe['Running'] [0]);
Setvalue($var_id_jzr ,sek2zeit($summe['Running'] [3] ));
Setvalue($var_id_mkr ,$summe['Running'] [1]);
Setvalue($var_id_mzr ,sek2zeit($summe['Running'] [4]));
Setvalue($var_id_wkr ,$summe['Running'] [2]);
Setvalue($var_id_wzr ,sek2zeit($summe['Running'] [5]));

// Update der Variablen (Cycling)
Setvalue($var_id_jkc ,$summe['Cycling'] [0]);
Setvalue($var_id_jzc ,sek2zeit($summe['Cycling'] [3] ));
Setvalue($var_id_mkc ,$summe['Cycling'] [1]);
Setvalue($var_id_mzc ,sek2zeit($summe['Cycling'] [4]));
Setvalue($var_id_wkc ,$summe['Cycling'] [2]);
Setvalue($var_id_wzc ,sek2zeit($summe['Cycling'] [5]));


//********************* Ab hier Funktionen *************************************
function IstVorhanden($datei,$suchbegriff)
 {
		@$dat=File($datei);
		$ret="error";
		for ($index=0; $index <count($dat);$index++)
		 {
			$vergl=substr($dat[$index],0,10);
			IF ( $vergl == TRIM($suchbegriff) )
			   {
				   $v=strpos($dat[$index],";");
					$ret=Substr($dat[$index],$v+1,strlen($vergl)-$v-1);
					$index=count($dat);
				}
			ELSE
			   {
			      $ret="error";
			   }

	    }
      return($ret);
}
function vornull($w)
{
	$w=STRVAL($w);
	IF (strlen(trim($w)) >=2)
		{
	  	return($w);
		}
	return("0".TRIM($w));
}
function wochenanfang($dat)
{
	$diff= date("N",$dat)-1;
	$start=$dat-$diff*24*60*60;
	return( date("d.m.Y",$start));
}
function sek2zeit($ges_sek)
{
	$s=intval ($ges_sek/3600);
	$m=intval( (($ges_sek/3600)-$s)*60);
	$i= intval(((($ges_sek/3600-$s)*60)-$m)*60);
	$ges_zeit= vornull($s).":".vornull($m).":".vornull($i);
	return($ges_zeit);
}
?>


Vielleicht kann’s jemand gebrauchen. In diesem Fall würde ich mich über Feedback freuen!

Gruß
Walter

Hallo Walter,

vielen Dank für dein Skript, welches ich mir nun so umbauen werde, dass es die Daten vom Polar Personaltrainer, die ich dann nach Polar Flow übergeben werde, verarbeiten kann :slight_smile:

Ich hatte schon vor längerer Zeit mal versucht Daten direkt aus dem Personaltrainer auszulesen bin aber letztendlich gescheitert :mad: Mit deinem Skript ist die Tür nun offen :wink:

Gruß
Hans

Moin,

wie hier Übernahme von älteren externen Daten ins Archiv mit dem Origirnal Zeitstempel beschrieben ist es mir gelungen, die Polar Daten seit 2012 in IPS so zu übernehmen, dass ich mittels IPSView nun die gewünschten Charts erhalte :slight_smile:

Derzeit erzeuge ich ausgehend vom Polar Personal Trainer mittels Übergabe nach Polar Flow CSV-Dateien für folgende Felder:

  • Dauer in Minuten
  • Kalorienverbrauch
  • km sofern diese Daten bei der Sportart anfallen
  • durchschnittliche Herzfrequenz
  • maximale Herzfrequenz

Hier noch ein optischer Eindruck, wobei jeder Graph einzeln an- und abgeschaltet werden kann. Ausserdem werden noch Summen über alle Sportarten gebildet, so dass man für jedes Jahr gut erkennen kann, welche Aktivitäten man unternommen hat :wink:

Sollte Interesse an dem Skript bestehen, so würde ich einen separaten Thread anlegen.

Nochmals vielen Dank an Walter der mit seinem Skript mir diesen Weg eröffnet hat :slight_smile:

Gruß
Hans