Anbindung Miele T1 Trockner über WLAN ohne Gateway

Hallo zusammen,

leider hat meine Forumsuche kein konkretes Ergebnis gebracht.
Wir haben uns einen Miele T1 Trockner mit WLAN- Modul (XKM 3100 W) zugelegt.
Er kann per Smartphone bedient und überwacht werden. Nun möchte ich ihn natürlich in IPS anbinden.
Ein Gateway (XGW 3000) haben wir uns nicht zugelegt, da es bis dato ja auch ohne klappt.
Hat jemand seine Miele- Geräte ohne Gateway in IPS eingebunden, oder hat jemand eine Idee, wie es klappen könnte?
Liebe Grüße
Lieschen

Moin,
wurde auch hier schon vor ein paar Tagen unter :
Miele @home / WifiConn@ct / Mobile Control in IPS einbinden
eröffnet. :wink: Vielleicht kann man die beiden Beiträge ja zusammenführen.

Letzte Woche auch einen Miele Trockner mit WLAN-Modul XKM3100W bekommen.
Mit der Miele App für Android kann ich den Programmablauf verfolgen und den Trockner stoppen.

Mit einem Portscanner konnte ich bisher nur den Port 80 auf der Trockner-IP-Adresse erkennen, weitere Ports scheinen nicht offen zu sein. Es ist mir bisher nicht gelungen den Datenverkehr zu loggen, aber dazu fehlt mir auch die nötige Erfahrung.

In IPS habe ich einen Client-Socket mit der Trockner-IP und Port80 eingerichtet, die Schnittstelle ist Aktiv u. geöffnet, aber unter Debug sehe ich keinerlei Daten.
Wie kann man da weiter vorgehen ?

Wäre an einer Status-Darstellung im IPS-WebFront sehr interessiert, auch im Hinblick der Anschaffung einer Miele-Waschmaschine in der nächsten Zeit.
Gruß GMilf

Wenn eine Fritzbox im Haus sein sollte ist es das einfachste die Pakete von der App über die Fritzbox mitzuschneiden (siehe Punkt 2).
Fritzbox Paketmitschnitt-und-Support-Daten-erstellen
Die Datenpakte werden im Wireshark Format abgespeichert und können dann mit Wireshark analysiert werden.

Danke Fonzo für den Hinweis,
habe in der Fritzbox ein Datenstream beim Aufschalten der App über die WLAN-Schnittstelle aufgezeichnet.
Beim Öffnen in einem Editor taucht beim Suchen in dem Datenfile auch mehrfach „mieleathome“ auf .
Dann versucht mit Wireshark zu analysieren, aber bisher nirgends passende Datenpackete gefunden.
Muss ich, wenn ich mehr Zeit habe, mal versuchen ob man auf diesem Weg etwas raus bekommt.
Vielleicht hat ja jemand schon etwas gefunden.
Gruß GMilf

Hallo bin aktuell auch dabei herauszufinden wie das Abfragen der Daten funktioniert.

Im Wireshark habe ich dabei folgendes gefunden:

GET /Devices/00011975xxxx/State/ HTTP/1.1

Dies scheint eine HTTP Abfrage vom Telefon mit Miele App an das Gateway zu sein. Wenn ich dies im Browser mit der entsprehcenden IP Adresse aufrufe, kommt allerdings nichts…

Edit: Ich konnte nun bereits herausfinden, dass in diesem Packet im Header ein Authorization String drin steckt. Dieser setzt sich wie folgt zusammen:
"Authorization: MieleH256 [gleich bleibender Hex String]:[dynamischer Hex String]
"

Für Openhab gibt es hier ein Binding für Miele. Da sollte man auch entnehmen können wie die Kommunikation mit Miele funktioniert.

Aber das läuft ja wieder über das Gateway und Zigbee. Hier geht es um die direkte Kommunikation mit dem Gerät über WiFi

Hallo zusammen,

seid ihr weiter gekommen?

Ich brauche auch eine Anbindung eines Miele WiFiConn@ct Waschtrockners… bin aber leider genauso weit wie ihr:(

Schöne Grüße aus München:)

Hallo Zusammen,
wie im anderen Miele Beitrag bereits geschrieben, habe ich mir die WMV963WPS inkl. kostenlosem XKM3100W WLAN-Modul gekauft und stehe vor dem gleichen Problem.

Habe hier gelesen, dass etwas mit JSON funktionieren soll:
Integration Miele WifiConn@ct / XKM 3100 W | QIVICON

Stimmt das?

Hallo,
ich habe jetzt auch ein XKM3100W.
Ich habe mir das ding mal genauer angesehen:
Das Wifi-Modul basiert auf einem Ti CC3200 Wifi SOC (mal unter EK037 Googeln). Von dort führt die serielle Schnittstelle über 2 langsame Optokoppler zur Schnittstelle der Maschine. Gleichzeitig führt die Schnittstelle noch über 2 schnelle Optokoppler zu einem (uC? siehe unten) von ST. Beschriftung: „GZBE“ und „MRC624“. Der Bus zur Maschine hat 6 Leitungen: Vcc, Gnd, Rxd, Txd und 2 weitere die mit dem uC verbunden sind. Das Wifi Modul kann mit Maschine und uC reden, Maschine und uC sehen sich nicht.
Leider findet die Kommunikation komplett über den Server von Miele statt.

P1080645.jpg

Thomas

ST „GZBE“ und „MRC624“ ist ein Operationsverstärker Type LM293

Ich habe einen XKM3100W auseinander genommen, um zu schauen, was eigentlich drauf ist.

Ohne jetzt den Layout zu analysieren, sieht es für mich so aus, dass
entweder der WiFi Module 2 von einander unahängige Varianten der UART-Schnittstelle unterstützt (RxD1+TxD1, RxD2+TxD2),
oder es handelt sich um eine UART mit hardwareflußkontrolle (RxD+TxD+CTS+RTS)

Hallo,

hat es jemand schon geschafft die Daten abzugreifen

Mit freundlichen Grüßen

Hi mir ist es gelungen, Daten mit einem ESP8266 Modul mitzuschneiden.

  • Serielle Kommunikation, 57600 Baud
  • crc16 mit 0x8408 als Polynom und 0xFFFF als Startwert
  • 0xA5 = Sysnc Byte, mit welchem Code man 0xA5 sendet weiss ich nicht
  • Aufbau: Sync, Adresse (Empfänger?), Adresse (Sender?), Länge, nxDaten, crc16 (Low/High -Byte)
    Die Message:
    0x01, 0x02, 0x05, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x01 …
    enthält an Position 15 (wenn man von 0 zählt) die Restlaufzeit.
    Diese übertrage ich an meine Haussteuerung.
    Das EPS-Modul versorge ich aus dem Modul. Geht auch ohne Internetverbindung! Ob es auch ohne Miele Modul geht weiss ich nicht.

Gruß Thomas


/*--------------------------------------------------
Telnet to Serial AccessPoint for ESP8266 
for ESP8266 adapted Arduino IDE

by Stefan Thesen 08/2015 - free for anyone
http://blog.thesen.eu

Creates an accesspoint or network client which can 
be connected by telnet; e.g. telnet 192.168.4.1
Telnet input is sent to serial and vice versa.

Serial output can e.g. be used to steer an attached
Arduino or other serial interfaces.
Please take care for levels of the serial lines.

Code inspired by a post of ghost on github:
https://github.com/esp8266/Arduino/issues/307
--------------------------------------------------*/

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <stdint.h>
#include "Timer.h"

/****************************************************************************
* Definitionen
****************************************************************************/
#define REC_BUF_SIZE 42U
#define CMD_BUF_SIZE     20   /* Groesse des Kommandopuffers */
#define MODE_HEX_ALL      0   /* Messages in HEX ausgeben */
#define MODE_HEX_OK       1   /* Messages in HEX ausgeben */
#define MODE_HEX_OK_DATA  2   /* Messages in HEX und Erklaerung ausgeben */ 
#define MODE_DATA         3   /* Audgew�hhlte Messwerte ausgeben */  
#define MODE_SILENT       4   /* nichts ausgeben */


/****************************************************************************
* Globale Variablen
****************************************************************************/
static uint16_t uc_crc = 0xFFFF;                       /* Berechnete CRC */

static uint8_t Buffer[ REC_BUF_SIZE ];           /* Message Buffer EBus */
static char    CmdBuf[ CMD_BUF_SIZE ];           /* Puffer für Commandos über USB */
static uint8_t BufPos = 0;                       /* Zeiger auf Puffer */ 
static uint8_t MesEnd;                           /* Errechnetes Ende der Message */
static uint8_t Mode = MODE_HEX_OK;
static uint8_t Restzeit;
static uint16_t ZyklusZeit;

////////////////////////////////////
// settings for Telnet2Serial Bridge
////////////////////////////////////

// max number of clients that can connect
#define MAX_NO_CLIENTS 1
const WiFiMode wifi_mode = WIFI_STA;    // set WIFI_AP for access-point or WIFI_STA for WIFI client
const char* ssid = "------------------------------";
const char* password = "------------";
const int iSerialSpeed = 57600;         // speed of the serial connection
const bool bSuppressLocalEcho = true;   // shall local echo in telnet be suppressed (usually yes)
const char* CCU_Ip = "192.168.178.23";


// Create an instance of the server on Port 23
WiFiServer server(23);
WiFiClient pClient; 


/*--------------------------------------------------------------------------*
* toHexByte - Wert in HExadezimal (ASCII) wandeln
* Parameter: Data - Wert
*            len  - Zahl der Zeichen
* Ergebnis:  pStr - Zeiger auf Ergebnis
*--------------------------------------------------------------------------*/

#define OUTBUFLEN 40
static char OutBuf[ OUTBUFLEN ];

static char *toHexByte( uint16_t Data, uint8_t len )

  {
  char *pBuf = OutBuf + OUTBUFLEN;
  char ch;

  *(--pBuf) = 0;
  if( len & 1 )
    {
    *(--pBuf) = ' ';
    len--;
    }
    
  while( len-- > 0 )
    {
    ch = (Data & 0x000F) + '0';
    if( ch > '9' )
      ch += 'A' - '0' - 10;
    *(--pBuf) = ch;
    Data >>= 4;
    }

  return( pBuf );
  }

  
/*--------------------------------------------------------------------------
* ExecCommand - Befehl ausführen
* Parameter: pBuf - Zeiger auf den Befehl
* Ergebnis:  keins
*--------------------------------------------------------------------------*/

void ExecCommand( char *pBuf )

  {
  uint8_t i, ch;
  uint16_t Slave, ParaAdr;
  int16_t ParaVal;

  if( *pBuf == '!' )
    {
    ch = pBuf[ 2 ];
    
    switch( pBuf[1] )
      {
      case 'w':           /* Modus einstellen */
      case 'W':
        pClient.print( F("!M") );
        if( (ch >= '0') && (ch <= '9') )
          {
          MeldeWert( "WaschmaschineRestzeit", ch - '0');
          pClient.println( (char)ch );
          }
        else
          {
          pClient.print( ch );
          pClient.println( '?' );
          }
        break;

      case 'm':           /* Modus einstellen */
      case 'M':
        pClient.print( F("!M") );
        if( (ch >= '0') && (ch <= '4') )
          {
          Mode = ch - '0';
          pClient.println( (char)ch );
          }
        else
          {
          pClient.print( ch );
          pClient.println( '?' );
          }
        break;

      case 't':           /* Zykluszeit einstellen */
      case 'T':
        ZyklusZeit = 0;
        for( i = 2; (pBuf[i] >= '0') && (pBuf[i] <= '9'); i++)
          ZyklusZeit = ZyklusZeit * 10 + (pBuf[i] - '0');
        ZyklusZeit = (ZyklusZeit > 10 ? 10 : ZyklusZeit) * (1000 / MSEC_PER_TICKS);
        pClient.print( F("!T") );
        pClient.print( ZyklusZeit / (1000 / MSEC_PER_TICKS) );
        pClient.println( 's' );
        break;

      default:
        pClient.print( '!' );
        pClient.print( pBuf[ 1 ] );
        pClient.println( '?' );
      }      
    }
  else if( *pBuf == '?' )
    {
    switch( pBuf[1] )
      {
      case 'm':               /* Modus abfragen */
      case 'M':
        pClient.print( F("?M") );
        pClient.println( (char)(Mode + '0') );
        break;

      case 't':               /* Zykluszeit abfragen */
      case 'T':
        pClient.print( F("?T") );
        pClient.print( ZyklusZeit / (1000 / MSEC_PER_TICKS) );
        pClient.println( 's' );
        break;

      default:
        pClient.print( '?' );
        pClient.print( pBuf[ 1 ] );
        pClient.println( '?' );
      }
    }
  }


/*--------------------------------------------------------------------------
* DoCommand - Befehl holen und ausführen
* Parameter: keine
* Ergebnis:  keins
*--------------------------------------------------------------------------*/

void DoCommand( void )

  {
  static uint8_t CmdBufPos = 0;
  uint8_t NewBytes;


  NewBytes = pClient.available();
  while( NewBytes-- > 0 )
    {
    CmdBuf[ CmdBufPos ] = pClient.read();
    if( (CmdBuf[ CmdBufPos ] == 0) || (CmdBuf[ CmdBufPos ] == 0xFF)  )
      CmdBufPos = 0; 
    else if( (CmdBuf[ CmdBufPos ] == '\r') || (CmdBuf[ CmdBufPos ] == '
') || (CmdBuf[ CmdBufPos ] == '/') )
      {
      CmdBuf[ CmdBufPos+1 ] = 0;
      ExecCommand( &CmdBuf[0] );
      }
    else if( ++CmdBufPos == CMD_BUF_SIZE )     /* Overflow */
      CmdBufPos = 0; 
    }
  }


/*--------------------------------------------------------------------------
* CalcCRC - CSC Pr?uesumme eines Datenpaketes berechnen
* Parameter: data - Wert
*            crc  - letzte Pruefsumme
*            GenPolynome - Polynom fuer die CRC, bei EBus 0x9B
* Ergebnis:  Pruefsumme
*--------------------------------------------------------------------------*/

uint16_t crc16_calc( uint8_t data, uint16_t crc, uint16_t GenPolynom )

  {
  uint8_t i;

  crc ^= data;
  for ( i = 0; i < 8; i++ )
    {
    if( crc & 1 )
      crc = (crc >> 1) ^ GenPolynom;
    else 
      crc >>= 1;
    }

  return( crc );
  }

  
/*--------------------------------------------------------------------------
* CalcCheckSum - Checksumme berechnen
* Parameter: pdata - Zeiger auf Daten
*            len   - Zahl der Zeichen
* Ergebnis:  Pruefsumme
*--------------------------------------------------------------------------*/

uint16_t CalcCheckSum16( uint8_t *pdata, uint8_t len )

  {
  uint16_t crc = 0xFFFF;
  
  while( len-- != 0 )
    crc = crc16_calc( *(pdata++), crc, 0x8408 );

  return( crc );
  }


/*--------------------------------------------------------------------------
* MeldeWert - Daten an CCU2 senden
* Parameter: Name - Name der CCU2 - Variablen
*            Wert - neuer Wert für die Variabl
* Ergebnis:  keins
*--------------------------------------------------------------------------*/

void MeldeWert( String Name, float Wert)

  {
  uint16_t timeout;
  String meldung;
  WiFiClient client;                    /* Webclient initialisieren */

  if( !client.connect( CCU_Ip, 8181 ))    /* mit dem CCU-Port 8181 verbinden */
    {
    Serial.println("  Fehler: Verbindung zur CCU konnte nicht aufgebaut werden");
    delay(50);
    return;
    }
               
  meldung = "/test.exe?befehl=dom.GetObject('" + Name + "').State('" + Wert + "')";
  client.print(String("GET ") + meldung + " HTTP/1.1
" +
               "Host: " + CCU_Ip + "
" + 
               "Connection: close

");
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
      Serial.println(">>> Client Timeout !");
      client.stop();
      return;
    }
  }
  
  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }
  
  Serial.println();
  Serial.println("closing connection");
  }


/*--------------------------------------------------------------------------
* DataFromMes - Daten aus Messages lesen 
* Parameter: pBuf - Zeiger auf Puffer
*            len - Zahl der Bytes im Puffer
* Ergebnis:  keins
*--------------------------------------------------------------------------*/

void DataFromMes( uint8_t *pBuf, uint8_t len )
  {
  const uint8_t T_Mes[12] = { 0x01, 0x02, 0x05, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x01 }; 
  uint8_t i;
  
  for( i=0; i<12; i++ )
    if( T_Mes[i] != pBuf[i] )
      return;
      
    Restzeit = pBuf[15];
    pClient.printf("Restzeit: %d Minuten
\r", Restzeit );
    MeldeWert( "WaschmaschineRestzeit", Restzeit );
    StartTimer( TIMER_MOFF, 10*60*TICKS_PER_SEC );
  }

/*--------------------------------------------------------------------------
* MessageEnd - Ende einer Message erreicht
* Parameter: keine
* Ergebnis:  keins
*--------------------------------------------------------------------------*/

static void MessageEnd( bool MesOk )

  {
  uint8_t i;

  if( BufPos >= 7 )             /* Puffer leer -> Ende */
    {
    if( MesOk )
      {
      if( (Mode == MODE_HEX_OK) || (Mode == MODE_HEX_OK_DATA) )
        {
        for( i = 0; i < BufPos; i++ )
          pClient.write( toHexByte( Buffer[ i ] , 3), 3);
        pClient.println( F(" ") );
        }
      DataFromMes( Buffer, BufPos ); /* Message auslesen */
      }
    }

  BufPos = 0;
  uc_crc = 0xFFFF;               /* Variablen neu initialisieren */
  }


/*--------------------------------------------------------------------------
* ReciveMess - Nachrichten empfangen
* Parameter: keine
* Ergebnis:  keins
*--------------------------------------------------------------------------*/

void ReceiveMess( void )

  {
  uint8_t ch, i;
  static uint16_t lastCRC;

  ch = Serial.read();

/*** 0xA5 -> Sync Byte ***/
  if( ch == 0xA5 ) 
    {
    MessageEnd( false );                           /* Hier ist der Bus frei fuer eigene Messages */
    return;
    }

/*** Checksumme berechnen ***/
  if( (ch == 0) && (BufPos == 0) )
    return;

   uc_crc = crc16_calc( ch, uc_crc, 0x8408 );


/*** Zeichen im Puffer ablegen ***/
  if( BufPos < REC_BUF_SIZE )                   /* Noch Platz im Puffer -> dann speichern */
    Buffer[ BufPos ] = ch; 
  else                                           /* Overflow */
    {
    if( Mode == MODE_HEX_ALL )
       pClient.println( F("- Error: overflow") );
    MessageEnd( false );
    return;
    }
    
/*** Zeichen ausgeben ***/
    if( Mode == MODE_HEX_ALL )
      {
      if( BufPos == 4 ) 
        {
        pClient.println( F(" ") );
        for( i = 0; i <= 4; i++ )
          pClient.write( toHexByte( Buffer[ i ] , 3), 3);
        }

      if( BufPos > 4 ) 
        pClient.write( toHexByte( ch, 3), 3);
      }

/*** Pruefungen je nach Position ***/
    if( BufPos == 3 )                             /* 1. Laengenbyte empfangen */
      {
      if( Buffer[3] > 32 )
        {
        Buffer[3] = 32;
        if( Mode == MODE_HEX_ALL )
          pClient.println( F("
\rError: Laenge1") );
        }
      MesEnd = Buffer[3] + 5;
      }
    else if( BufPos >= 3 )                        /* 1. L�ngenbyte empfangen */
      {
      if( BufPos == (MesEnd - 2) )                  /* Letztes Byte f�r Checksumme */
        lastCRC = uc_crc;                         /* Checksumme merken */
      if( BufPos == MesEnd )                      /* Checksumme */ 
        {
        if( (Buffer[ MesEnd-1 ] != (lastCRC & 0xFF)) || (Buffer[ MesEnd ] != ((lastCRC >> 8) & 0xFF)))
          {
          if( Mode == MODE_HEX_ALL )
            pClient.printf( " - Error: Checksumme %x %x", lastCRC & 0xFF, lastCRC >> 8 );
          MessageEnd( false );
          }
        else
          MessageEnd( true );
        }
      }

    BufPos++;
    StartTimer( TIMER_EOC, TICKS_PER_SEC );

/*** Timeout pr�fen ***/
  if( !TimerRunning( TIMER_EOC) )
    {
    MessageEnd( false );
    return;
    }
  }



void setup() 
{
  InitTimer();                    /* Software Timer initialisieren */
  // start serial
  Serial.begin(iSerialSpeed);

  if (wifi_mode == WIFI_AP)
  {
    // AP mode
    WiFi.mode(wifi_mode);
    WiFi.softAP(ssid, password);
    server.begin();
    server.setNoDelay(true);
  }
  else
  {
    // network cient - inital connect
    WiFi.mode(WIFI_STA);
    WiFiStart();
  }
}


void WiFiStart()
{ 
  // Connect to WiFi network
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(5000);
  }
  
  // Start the server
  server.begin();
  server.setNoDelay(true);
}


void loop() 
  { 
  
  ////////////////////////////////////////////////
  // if network client: check if WLAN is connected
  ////////////////////////////////////////////////
  if ((wifi_mode == WIFI_STA) && (WiFi.status() != WL_CONNECTED))
    {
    WiFiStart();
    }

  /////////////////////
  // handle new clients
  /////////////////////
  if (server.hasClient())
    {
    bool bFoundPlace=false;
    

    // search a free spot
    if (!pClient || !pClient.connected())
      {
      // remove old connections
      if( pClient ) 
        {
        pClient.stop();
        }

      // new client
      pClient = server.available();
      if (bSuppressLocalEcho) 
        { 
        pClient.write("\xFF\xFB\x01", 3); 
        }
      pClient.write("Welcome to Telnet2Serial Adapter - S. Thesen 08/2015 - https://blog.thesen.eu
"); 
      pClient.println( "Test" );
      Serial.println( "Hallo" );
      bFoundPlace=true;
      }

    //no free spot --> sorry
    if (!bFoundPlace)
      {
      WiFiClient client = server.available();
      client.stop();
      }
    }
    
/*** From Terminal ***/  
  DoCommand();
  if( ! TimerRunning( TIMER_MOFF ) )
    {
    StartTimer( TIMER_MOFF, 10*60*TICKS_PER_SEC );
    MeldeWert( "WaschmaschineRestzeit", 65535 );
    }


  /////////////////////
  // Serial --> Telnet
  /////////////////////
  while( Serial.available() )
    {
    ReceiveMess();
    }
  }

Sehr interessant, Du schickst die Daten an eine CCU ?

Mir fehlt die timer.h kann es nicht übersetzen, aber sehr interessant :wink:
Kannst Du mir mal die passende Datei timer.h mal zippen und ranhängen Ardunio1.8.3?
Gruß Helmut

Hier noch ein Bild:


Das komplette Projekt
ESP_Telnet2Serial.zip (8.34 KB)
Alles eher alpha Stadium.

Gruss Thomas

Eine CCU2 um genau zu sein.

Thomas

Ohne Modul? dazu müßte man die Schnittstelle vor den Optokopplern genauer untersuchen, ob es ein Schnittstellenwandler oder ein µProzessor ist, rechts unten
Vielen Dank für das Zip-File
Gruß Helmut

Das ist der Operationsverstärker nach dem ich weiter oben gefragt hatte!
Thomas

…das wird ja immer spannender bei Euch!
Kann man es eingrenzen bei welchen Typen das funktionieren könnte?
Ich hatte mal irgendwo gelesen, dass ein mehrzeiliges Display ein Indiz sein könnte?

Joachim

Habe ich gar nicht gesehen… wäre relativ einfach die Schaltung nach zubauen, wenn die Abfrage und oder Antworten bekannt sind. Sind Die das und lohnt es, sind die Module beim Kauf dabei ?
Gruß Helmut