SMA Energy Meter

Selbes Problem hier, letzter Datenempfang heute direkt vor dem Update…
Noch keine echte Idee leider. Aber Workaround: In den Network Settings des EM die Adresse von IPS als Target definiert bringt Werte.

Hi,

ich hier jemand von euch weitergekommen?

Gruß
hardlog

Die Targetadresse im EnergyMeter zu ändern, führt leider zu negativen Effekten z.B. beim Batteriewechselrichter - der sieht dann die Waage nicht mehr und kann nicht mehr einspeisebezogen regeln. Also Target wieder resettet und neu geschaut:

Lösung scheint zu sein: Empfangshost auf „alle“ setzen, zumindest kommen dann bei mir wieder Werte an. Siehe Bild.

Habe das hier gefunden: https://www.symcon.de/forum/threads/42255-5-3-Multicast-Socket-funktioniert-nicht-mehr

Hallo zusammen

Ich hab mal wieder etwas Zeit gefunden um mit der integration von SMA Homemanager 2 weiterzukommen.
Ich habe das Skript wie im post #45 benutzt. Die meisten Werte werden auch richtig angezeigt. Ausser Bezug - L2. Der ist komplett falsch. Wenn ich dazu im Skript nachschaue ist nur dort auch eine Art Formel drin (bin nicht sicher ob ich das richtig verstehe):

SetValue(21046 /[Energie Zähler\SMA Home Manager\Bezug - L2]/,(float)hexdec(substr($HexData,608, 8 ))/10-(float)hexdec(substr($HexData,648, 8 ))/10);

Muss das so sein? Wo liegt mein Fehler.

Danke und Gruss
Robert

hat das hier jemand zum laufen bekommen mit Symcon 5.3?

Aufbauend auf dem Skript habe ich mir ein eigenes geschrieben.

Vielleicht hilft es dir als Beispiel weiter:

<?php

declare(strict_types=1);

// Hier die LogIn Daten für das SunnyPortal eintragen:
$login_email = 'xxxx@yyyyy';
$login_pass = 'zzzzz';

define ('COOKIE_FILE_NAME', 'cookie_sma.txt');

$ch = curl_init();

// Versuch sich mit Cookie an der Webseite anzumelden
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_URL,'https://www.sunnyportal.com/FixedPages/HoManLive.aspx');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_COOKIEFILE, COOKIE_FILE_NAME);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36');
$curlData = curl_exec($ch);


// Prüfen, ob die Anmeldung mit Cookie erfolgreich war, wenn nicht, dann wird ein normaler Login durchgeführt
preg_match('|(Forgotten password)|', $curlData, $LoginFALSE);
if ($LoginFALSE){
    echo "Anmeldung mit Cookie war nicht erfolgreich - normaler Login wird durchgeführt!".PHP_EOL;

    curl_setopt($ch, CURLOPT_URL, 'https://www.sunnyportal.com/Templates/Start.aspx');
    curl_setopt($ch, CURLOPT_POSTFIELDS,'ctl00$ContentPlaceHolder1$Logincontrol1$txtUserName='.urlencode($login_email).'&ctl00$ContentPlaceHolder1$Logincontrol1$txtPassword='.urlencode($login_pass).'&__EVENTTARGET=ctl00$ContentPlaceHolder1$Logincontrol1$LoginBtn');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_COOKIEJAR, COOKIE_FILE_NAME);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    preg_match('|(Current Status and Forecast)|', curl_exec($ch), $LoginTRUE);

    if (!$LoginTRUE){
        echo 'Die Anmeldung war nicht erfolgreich - bitte User und Passwort überprüfen.' . PHP_EOL;
        return;
    }
}

// Abfragen der Live Daten
curl_setopt($ch, CURLOPT_URL,"https://www.sunnyportal.com/homemanager?t=" . time());
curl_setopt($ch, CURLOPT_POST, false);
$curlData = curl_exec($ch);

$LiveData = [];
foreach(json_decode($curlData, true) as $key=>$Data){
    switch ($key){
        case '__type':
            break;
        case 'Timestamp':
            $LiveData[$key] = strtotime($Data['DateTime']);
            break;
        default:
            $LiveData[$key] = $Data;            
    }
} 

if ($_IPS['SENDER'] === 'Execute'){
    print_r($LiveData);
}


// Abfragen der Prognose Daten
curl_setopt($ch, CURLOPT_URL,"https://www.sunnyportal.com/HoMan/Forecast/LoadRecommendationData");
curl_setopt($ch, CURLOPT_POST, false);
$curlData = curl_exec($ch);

$ForecastSeries = json_decode($curlData, true)['ForecastSeries'];

$DataPoints = [];
foreach($ForecastSeries as $Serie){
    $PvMeanPower = round($Serie['PvMeanPower']['Amount']/1000, 2);
    $ConsumptionForecast = round($Serie['ConsumptionForecast']['Amount']/3600000, 2);
    $DataPoints[] = ['TimeStamp' => $Serie['TimeStamp']['DateTime'], 'WeatherId' => $Serie['WeatherId'], 'PvMeanPower' => $PvMeanPower, 'PvEnergy' => $Serie['PvEnergy']['Amount'], 'ConsumptionForecast' => $ConsumptionForecast, 'IsConsumptionRecommended' => $Serie['IsConsumptionRecommended']];
} 

if ($_IPS['SENDER'] === 'Execute'){
    print_r($DataPoints);
}

curl_close($ch);

Es erfolgt hier nur eine Anzeige der Daten bei Direktausführung. Um die Speicherung der Daten muss man sich noch selber kümmern.

Burkhard

cool vielen dank damit kann man arbeiten :slight_smile:

Aber irgendwie kommen oft keine Daten, kann es sein dass wenn man alle 10sec die Daten holt der Server sich sperrt oder woran liegt es dass dann die daten leer sind beim auslesen? Ist das bei dir auch so?

Gesendet von meinem SM-G975F mit Tapatalk

Kann ich dir leider nicht beantworten. Ich lese alle 15 Minuten, habe es aber auch schon mal gesehen, dass die Daten leer waren. Ich ignoriere das einfach.

leider werden sehr oft keine Daten abgeholt. kann man dies vielleicht nicht noch irgendwie verbessern? :wink:

[InfoMessages] => Array
(
[0] => The current consumption could not be determined. The current purchased electricity is unknown.
)

Das beobachte ich bei mir auch:

    [InfoMessages] => Array
        (
            [0] => The current consumption could not be determined. The current purchased electricity is unknown. 
        )

    [WarningMessages] => Array
        (
            [0] => The current PV generation could not be fully determined. An inverter did not respond in time.
        )

    [ErrorMessages] => Array
        (
            [0] => The current data cannot be retrieved from the PV system. Check the cabling and configuration of the following energy meters:<div class="liveModeErrorSub"><ul><li class="faultingCounter"><span>Feed-in meter</span></il><li class="faultingCounter"><span>External consumption meter</span></il></ul></div>
        )

    [Info] => Array
        (
        )

Ich habe aber noch keine Ahnung, woran das liegt.

Auf jedenfall geht mit ips 5.3 jetzt das abholen per multicast direkt vom homemanager 2.0 auch wieder. Nur die phasen L1-L3 werden noch falsch dargestellt.

Dann kann man die kurzfristigen werte direkt vom HM abholen und Autarkiequote usw. vom sunnyportal

Gesendet von meinem SM-G975F mit Tapatalk

Hab den SMA HM 2.0 im Einsatz und hatte zuerst auch falsche Bezugswerte für L1-L3

Nach folgender Anleitung, schaut mein Skript jetzt so aus. Werte scheinen jetzt richtig zu sein.

http://www.eb-systeme.de/?page_id=1240

<?

    if ($_IPS["SENDER"] == "RegisterVariable")                               // über Register Var ausgeführt
{
    $Data  = RegVar_GetBuffer($_IPS["INSTANCE"]);                 // im Puffer der Instanz vorhandene Daten in $data kopieren
    $Data .= $_IPS["VALUE"];                                                        // neu empfangene Daten an $data anhängen
    $CRLF  = ",
";
    $HexData = bin2hex($Data);
    SetValue(17741 /*[Energie Zähler\SMA Home Manager	xt]*/, substr($HexData,417, 16 ));
    //SetValue(17741 /*[Energie Zähler\SMA Home Manager	xt]*/, $HexData);
    SetValue(40340/*[Energie Zähler\SMA Home Manager\Bezug - Summe]*/,(float)hexdec(substr($HexData,64, 8 ))/10);
    SetValue(57868/*[Energie Zähler\SMA Home Manager\Einspeisung - Summe]*/,(float)hexdec(substr($HexData,104, 8 ))/10);

    SetValue(54931 /*[Energie Zähler\SMA Home Manager\Bezug - L1]*/,(float)hexdec(substr($HexData,336, 8 ))/10);
    SetValue(23803 /*[Energie Zähler\SMA Home Manager\Bezug - L2]*/,(float)hexdec(substr($HexData,624, 8 ))/10);
    SetValue(53613 /*[Energie Zähler\SMA Home Manager\Bezug - L3]*/,(float)hexdec(substr($HexData,912, 8 ))/10);
    SetValue(19875 /*[Energie Zähler\SMA Home Manager\Einspeisung - L1]*/,(float)hexdec(substr($HexData,376, 8 ))/10);
    SetValue(15525 /*[Energie Zähler\SMA Home Manager\Einspeisung - L2]*/,(float)hexdec(substr($HexData,664, 8 ))/10);
    SetValue(37841 /*[Energie Zähler\SMA Home Manager\Einspeisung - L3]*/,(float)hexdec(substr($HexData,952, 8 ))/10);


    SetValue(33808 /*[Energie Zähler\SMA Home Manager\Bezogene Energie]*/,(float)hexdec(substr($HexData,80, 16 ))/3600000);
    SetValue(21006/*[Energie Zähler\SMA Home Manager\Eingespeiste Energie]*/,(float)hexdec(substr($HexData,120, 16 ))/3600000);

}
?>

Ich bekomme keine Einspeisung Summe?

Jetzt ist Abend…daher.

Bei mir funktioniert es bestens.

Danke

Hallo,

leider klappt es immer noch nicht,
ich bekomme keine plausiblen Werte zurück.

Vielleicht hilft euch meine Umsetzung weiter:


<?PHP
declare(strict_types=1);

// OBIS Parameter
$list_sum   = []; //Summen
$list_sum['00010400'] = ['OBIS' => '0140', 'divisor' => 10, 'name' => 'Real Power +'];
$list_sum['00010800'] = ['OBIS' => '0180', 'divisor' => 3600000, 'name' => 'Counter Real Power +'];
$list_sum['00020400'] = ['OBIS' => '0240', 'divisor' => 10, 'name' => 'Real Power -'];
$list_sum['00020800'] = ['OBIS' => '0280', 'divisor' => 3600000, 'name' => 'Counter Real Power -'];
$list_sum['00030400'] = ['OBIS' => '0340', 'divisor' => 10, 'name' => 'Reactive Power +'];
$list_sum['00030800'] = ['OBIS' => '0380', 'divisor' => 3600000, 'name' => 'Counter ReReactive Power +'];
$list_sum['00040400'] = ['OBIS' => '0440', 'divisor' => 10, 'name' => 'Reactive Power -'];
$list_sum['00040800'] = ['OBIS' => '0480', 'divisor' => 3600000, 'name' => 'Counter ReReactive Power -'];
$list_sum['00090400'] = ['OBIS' => '0940', 'divisor' => 10, 'name' => 'Apparent Power +'];
$list_sum['00090800'] = ['OBIS' => '0980', 'divisor' => 3600000, 'name' => 'Counter Apparent Power +'];
$list_sum['000a0400'] = ['OBIS' => '1040', 'divisor' => 10, 'name' => 'Apparent Power -'];
$list_sum['000a0800'] = ['OBIS' => '1080', 'divisor' => 3600000, 'name' => 'Counter Apparent Power -'];
$list_sum['000d0400'] = ['OBIS' => '1340', 'divisor' => 1000, 'name' => 'Power Faktor'];
$list_sum['000e0400'] = ['OBIS' => '1440', 'divisor' => 1000, 'name' => 'Network Frequency'];

$list_l1   = []; //Phase 1
$list_l1['00150400'] = ['OBIS' => '2140', 'divisor' => 10, 'name' => 'Real Power +'];
$list_l1['00150800'] = ['OBIS' => '2180', 'divisor' => 3600000, 'name' => 'Counter Real Power +'];
$list_l1['00160400'] = ['OBIS' => '2240', 'divisor' => 10, 'name' => 'Real Power -'];
$list_l1['00160800'] = ['OBIS' => '2280', 'divisor' => 3600000, 'name' => 'Counter Real Power -'];
$list_l1['00170400'] = ['OBIS' => '2340', 'divisor' => 10, 'name' => 'Reactive Power +'];
$list_l1['00170800'] = ['OBIS' => '2380', 'divisor' => 3600000, 'name' => 'Counter ReReactive Power +'];
$list_l1['00180400'] = ['OBIS' => '2440', 'divisor' => 10, 'name' => 'Reactive Power -'];
$list_l1['00180800'] = ['OBIS' => '2480', 'divisor' => 3600000, 'name' => 'Counter ReReactive Power -'];
$list_l1['001d0400'] = ['OBIS' => '2940', 'divisor' => 10, 'name' => 'Apparent Power +'];
$list_l1['001d0800'] = ['OBIS' => '2980', 'divisor' => 3600000, 'name' => 'Counter Apparent Power +'];
$list_l1['001e0400'] = ['OBIS' => '3040', 'divisor' => 10, 'name' => 'Apparent Power -'];
$list_l1['001e0800'] = ['OBIS' => '3080', 'divisor' => 3600000, 'name' => 'Counter Apparent Power -'];
$list_l1['001f0400'] = ['OBIS' => '3140', 'divisor' => 1, 'name' => 'Power'];
$list_l1['00200400'] = ['OBIS' => '3240', 'divisor' => 1000, 'name' => 'Voltage'];
$list_l1['00210400'] = ['OBIS' => '3340', 'divisor' => 1000, 'name' => 'Network Frequency'];

$list_l2   = []; //Phase 2
$list_l2['00290400'] = ['OBIS' => '4140', 'divisor' => 10, 'name' => 'Real Power +'];
$list_l2['00290800'] = ['OBIS' => '4180', 'divisor' => 3600000, 'name' => 'Counter Real Power +'];
$list_l2['002a0400'] = ['OBIS' => '4240', 'divisor' => 10, 'name' => 'Real Power -'];
$list_l2['002a0800'] = ['OBIS' => '4280', 'divisor' => 3600000, 'name' => 'Counter Real Power -'];
$list_l2['002b0400'] = ['OBIS' => '4340', 'divisor' => 10, 'name' => 'Reactive Power +'];
$list_l2['002b0800'] = ['OBIS' => '4380', 'divisor' => 3600000, 'name' => 'Counter ReReactive Power +'];
$list_l2['002c0400'] = ['OBIS' => '4440', 'divisor' => 10, 'name' => 'Reactive Power -'];
$list_l2['002c0800'] = ['OBIS' => '4480', 'divisor' => 3600000, 'name' => 'Counter ReReactive Power -'];
$list_l2['00310400'] = ['OBIS' => '4940', 'divisor' => 10, 'name' => 'Apparent Power +'];
$list_l2['00310800'] = ['OBIS' => '4980', 'divisor' => 3600000, 'name' => 'Counter Apparent Power +'];
$list_l2['00320400'] = ['OBIS' => '5040', 'divisor' => 10, 'name' => 'Apparent Power -'];
$list_l2['00320800'] = ['OBIS' => '5080', 'divisor' => 3600000, 'name' => 'Counter Apparent Power -'];
$list_l2['00330400'] = ['OBIS' => '5140', 'divisor' => 1, 'name' => 'Power'];
$list_l2['00340400'] = ['OBIS' => '5240', 'divisor' => 1000, 'name' => 'Voltage'];
$list_l2['00350400'] = ['OBIS' => '5340', 'divisor' => 1000, 'name' => 'Network Frequency'];

$list_l3   = []; //Phase 3
$list_l3['003d0400'] = ['OBIS' => '4140', 'divisor' => 10, 'name' => 'Real Power +'];
$list_l3['003d0800'] = ['OBIS' => '4180', 'divisor' => 3600000, 'name' => 'Counter Real Power +'];
$list_l3['003e0400'] = ['OBIS' => '4240', 'divisor' => 10, 'name' => 'Real Power -'];
$list_l3['003e0800'] = ['OBIS' => '4280', 'divisor' => 3600000, 'name' => 'Counter Real Power -'];
$list_l3['003f0400'] = ['OBIS' => '4340', 'divisor' => 10, 'name' => 'Reactive Power +'];
$list_l3['003f0800'] = ['OBIS' => '4380', 'divisor' => 3600000, 'name' => 'Counter ReReactive Power +'];
$list_l3['00400400'] = ['OBIS' => '4440', 'divisor' => 10, 'name' => 'Reactive Power -'];
$list_l3['00400800'] = ['OBIS' => '4480', 'divisor' => 3600000, 'name' => 'Counter ReReactive Power -'];
$list_l3['00450400'] = ['OBIS' => '4940', 'divisor' => 10, 'name' => 'Apparent Power +'];
$list_l3['00450800'] = ['OBIS' => '4980', 'divisor' => 3600000, 'name' => 'Counter Apparent Power +'];
$list_l3['00460400'] = ['OBIS' => '5040', 'divisor' => 10, 'name' => 'Apparent Power -'];
$list_l3['00460800'] = ['OBIS' => '5080', 'divisor' => 3600000, 'name' => 'Counter Apparent Power -'];
$list_l3['00470400'] = ['OBIS' => '5140', 'divisor' => 1, 'name' => 'Power'];
$list_l3['00480400'] = ['OBIS' => '5240', 'divisor' => 1000, 'name' => 'Voltage'];
$list_l3['00490400'] = ['OBIS' => '5340', 'divisor' => 1000, 'name' => 'Network Frequency'];

if ($_IPS['SENDER'] === 'Execute'){
    //zum Testen
    $hraw = '534d4100000402a000000001024c001060690174b33a68d524a6a271000104000000000000010800000000005628897000020400000075be00020800000000037a39805000030400000000000003080000000000657b04c0000404000000093d0004080000000000436dbad00009040000000000000908000000000065e92c48000a04000000761b000a08000000000388d3e3f8000d0400000003e5000e04000000c359001504000000000000150800000000000deb6e9800160400000029d8001608000000000145ab1fd00017040000000000001708000000000020aa986000180400000003c700180800000000001e3635d0001d040000000000001d08000000000017db2560001e040000002a04001e0800000000014b33af58001f0400000012710020040000037ecc00210400000003e4002904000000000000290800000000003c4ae980002a040000002524002a0800000000010e795978002b040000000000002b0800000000002cedd9c0002c04000000023f002c08000000000012d341d800310400000000000031080000000000407691a80032040000002535003208000000000115096da0003304000000109a0034040000037fbc00350400000003e6003d040000000000003d0800000000001747a358003e0400000026c3003e080000000001316a7908003f040000000000003f0800000000002142e340004004000000033700400800000000001bc49530004504000000000000450800000000001fa4e6a000460400000026e5004608000000000136d71f6800470400000011340048040000037b7200490400000003e5900000000203055200000000';
} else {
    // Prepare data
    $hraw = bin2hex(RegVar_GetBuffer($_IPS['INSTANCE']) . $_IPS['VALUE']); // im Puffer der Instanz vorhandene Daten holen und um die letzten Werte ergänzen
}

//Zählerkennung
$offset = 0;
$len = 4;
//echo hexToStr(substr($hraw, $offset * 2, $len * 2)) . PHP_EOL;

//ProtokollID
$offset = 16;
$len = 2;
//echo (substr($hraw, $offset * 2, $len * 2)) . PHP_EOL;

//gruppe
$offset = 8;
$len = 2;
//echo (substr($hraw, $offset * 2, $len * 2)) . PHP_EOL;

//zaehlerkennung
$offset = 18;
$len = 6;
//echo (substr($hraw, $offset * 2, $len * 2)) . PHP_EOL;

//Messzeitpunkt
$offset = 24;
$len = 4;
//echo (substr($hraw, $offset * 2, $len * 2)) . PHP_EOL;

$offset += $len;
$finished = false;

while (!$finished){

    //obis Id
    $len = 4;
    $id = substr($hraw, $offset * 2, $len * 2);
    if ($id === '00000000'){
        $finished = true;
        continue;
    }
    $offset += $len;


    //obis Messwert
    $len = (int) substr($id, 2 * 2, 2); //die Länge entspricht der Messart (Byte 2)

    if (isset($list_sum[$id])){
        $value = substr($hraw, $offset * 2, $len * 2);
        $res_sum[$list_sum[$id]['name']] = base_convert(substr($hraw, $offset * 2, $len * 2), 16, 10) / $list_sum[$id]['divisor'];
    } elseif (isset($list_l1[$id])) {
        $value = substr($hraw, $offset * 2, $len * 2);
        $res_l1[$list_l1[$id]['name']] = base_convert(substr($hraw, $offset * 2, $len * 2), 16, 10) / $list_l1[$id]['divisor'];
    } elseif (isset($list_l2[$id])) {
        $value = substr($hraw, $offset * 2, $len * 2);
        $res_l2[$list_l2[$id]['name']] = base_convert(substr($hraw, $offset * 2, $len * 2), 16, 10) / $list_l2[$id]['divisor'];
    } elseif (isset($list_l3[$id])) {
        $value = substr($hraw, $offset * 2, $len * 2);
        $res_l3[$list_l3[$id]['name']] = base_convert(substr($hraw, $offset * 2, $len * 2), 16, 10) / $list_l3[$id]['divisor'];
    } elseif($id = '90000000') {
        $len = 4;
        $value = substr($hraw, $offset * 2, $len * 2);
        //echo sprintf('%s Softwareversion: %s', $id, $value) . PHP_EOL;
    } else {
        trigger_error ("$id unbekannt");
        $finished = true;
    }
    $offset += $len;

}

// zum Testen
if ($_IPS['SENDER'] === 'Execute'){

    print_r($res_sum);
    print_r($res_l1);
    print_r($res_l2);
    print_r($res_l3);
    return;
}

SetChangedValueFloat(20807, $res_l1['Real Power +']); //Bezug L1
SetChangedValueFloat(35978, $res_l2['Real Power +']); //Bezug L2
SetChangedValueFloat(49204, $res_l1['Real Power +']); //Bezug L3
SetChangedValueFloat(24942, $res_sum['Real Power +']); //Bezug gesamt
SetChangedValueFloat(43989, $res_sum['Counter Real Power +']); //Bezug Zähler

SetChangedValueFloat(44961, $res_l1['Real Power -']); //Einspeisung L1
SetChangedValueFloat(58571, $res_l2['Real Power -']); //Einspeisung L2
SetChangedValueFloat(31960, $res_l3['Real Power -']); //Einspeisung L3
SetChangedValueFloat(35568, $res_sum['Real Power -']); //Einspeisung gesamt
SetChangedValueFloat(47491, $res_sum['Counter Real Power -']); //Einspeisung Zähler

SetChangedValueFloat(32048, max(GetValueFloat(21200) - $res_sum['Real Power -'], 0)); //Eigenversorgung
SetChangedValueFloat(34179, max(GetValueFloat(21200) + $res_sum['Real Power +'] - $res_sum['Real Power -'], 0)); //Verbrauch

function SetChangedValueFloat(int $id, float $value){
    if (GetValueFloat($id) !== $value){
        SetValueFloat($id, $value);
    }
}


function hexToStr($hex){
    $string='';
    for ($i=0; $i < strlen($hex)-1; $i+=2){
        $string .= chr(hexdec($hex[$i].$hex[$i+1]));
    }
    return $string;
}

Burkhard

Kann man das Daten abholen etwas entschleunigen?

Danke

Gesendet von iPhone XS mit Tapatalk

Ja du kannst die Instanz für den Multicast immer wieder für z.B. 10sec deaktieren und dann wieder kurz aktivieren. So mach ich das, funktioniert super

Gesendet von meinem SM-G975F mit Tapatalk

1 „Gefällt mir“

Danke

Gesendet von iPhone XS mit Tapatalk