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();
}
}