Jura Kaffeevollautomat per NewAskSin und Arduino fernsteuerbar

Begonnen von Actronx, 07 Dezember 2015, 22:11:33

Vorheriges Thema - Nächstes Thema

Actronx

Hallo zusammen,

das ist mein erstes Thema und ich wüsste gerne ob Interesse an meinem kleinen Projekt hier im Forum besteht.

Ich habe meinen Jura Z5 Kaffeevollautomaten per Arduino in meine FHEM / SelbstbauCUL Konfiguration eingebunden. Folgende Funktionen funktionieren dabei bisher:
-Pairen an den CUL (peeren sollte auch gehen)
-Maschine ein- und ausschalten per FHEM webcmd
-Kaffee beziehen per FHEM webcmd

Das ganze läuft per Arduino Nano mit ATmega328 , dem normalen CC1101 und der NewAskSin Libary
Als Basis hab ich das Beispiel HM_LC_SW1_BA_PCB aus der Libary genommen und auf 4 Kanäle erweitert.
Die Kommunikation mit der Kaffee-Maschine läuft über den Diagnoseport von Jura, da haben findige Leute die entsprechende Kommunikation entschlüsselt, so dass sie per RS232 ansteuerbar ist. Stromversorgung läuft praktischerweise auch direkt über den Diagnoseport.

Da an der Libary keine Veränderungen vorgenommen worden sind müssten die Channels auch normal mit allen anderen Geräten gepeered werden können, das kann ich aber leider nicht testen.

Ich würde gerne wissen wie das Interesse hier besteht, dann dokumentiere ich auch mehr :)

Mein herzlichen Dank geht an alle findigen Köpfe hier und da draußen im Internet ohne die das Projekt nicht möglich gewesen wäre!!

VG
Tris

Wuppi68

die Jura API wäre bestimmt super cool :-)

nen ESP8266 dran und der Drops ist gelutscht :-)
Jetzt auf nem I3 und primär Homematic - kein Support für cfg Editierer

Support heißt nicht wenn die Frau zu Ihrem Mann sagt: Geh mal bitte zum Frauenarzt, ich habe Bauchschmerzen

Actronx

Hey,
jo! Leider sind die Maschinen etwas unterschiedlich was die Befehle angeht...
Unter https://github.com/oliverk71/Coffeemaker-Payment-System (vielen Dank an OliverK71!) sind ganz viele Infos.

Für die Z5 gelten folgende Pinouts an dem Diagnoseport:
Jura 7-pin interface
(pin 8 - not used)
pin 7 - not used
pin 6 - +5V
pin 5 - not used
pin 4 - RX
pin 3 - GND
pin 2 - TX
pin 1 - not used
(pin 0 - not used)

Allerdings muss man ein bischen Bits schieben, weil Jura quasi ne Verschlüsselung eingebaut hat.
Mit den beiden Funktionen hier kann man aber mit der Jura kommunizieren:

Die Funktion übersetzt in das Jura Protokoll:

void ByteToJuraByte(char input) {
  byte maske = B01011011;
  byte tmp;
  boolean bitx,bity = 0;

  for (int i = 0; i <=3; i++) {
      bitx = (input & (1 << i*2))!=0; // test if lsb of input is 1
      bity = (input & (1 << 1+i*2))!=0; // test if lsb+1 of input is 1
     
      tmp = (maske | (bitx << 2) | (bity << 5) );
      //printbyte_msbfirst(tmp); //inserted for debugging purpose
      Serial.write(tmp);
  }
  _delay_ms(8); // after each 4 bytes send wait at least 8ms



Und mit der hier kriegt man die Rückantwort übersetzt:
char translatejurareturn(char input[4]) {
char tmp = 0;
  // 11011011 , 00100100 als Masken
  tmp = tmp | (input[3] & B00100000) << 2 ;
  tmp = tmp | (input[3] & B00000100) << 4 ;
  tmp = tmp | (input[2] & B00100000) << 0 ;
  tmp = tmp | (input[2] & B00000100) << 2 ; 
  tmp = tmp | (input[1] & B00100000) >> 2 ;
  tmp = tmp | (input[1] & B00000100) << 0 ;
  tmp = tmp | (input[0] & B00100000) >> 4 ;
  tmp = tmp | (input[0] & B00000100) >> 2 ;
  //Serial.println(tmp);
  return tmp;
}


Anschalten zB ist AN:01\r\n
Ausschalten: AN:02\r\n
Einen Spezialkaffee beziehen: FA:06\r\n

Die Befehler für die Kaffeesorten muss man aber per Maschinentyp herausfinden....

Was ich gerne noch hätte, woran ich aber im Moment scheitere ist eine vernünftige Statusabfrage.
Mir IC:\r\n kriegt man die Register oder Eingänge von der Maschine zurück. Ich erkenne aber kein richtiges Muster um etwa: Eingeschaltet und alles ok oder Kaffee wird gebrüht zu erkennnen :(

VG
Tris

hoods

Hallo Tris,

ich habe ne Z5 allerdings keine Ahnung wie ich die Jura Register ausgelesen und in Fhem dargestellt bekomme.

Nutzt Du diese Integration noch und könntest Du mir in Stichpunkten sagen was zu tun ist?

Danke & Gruss Sven
Odroid C2, FHEM 5.8, HMUSB, Jeelink, Rademacher DuoFern Stick, Benning WR über HTTPMOD

thorschtn

Auch wenn sich hier schon eine Weile nichts mehr tut, ich fand das Thema schon immer interessant - alleine um Morgens an meiner S90 gleich meinen Kaffee ziehen zu können, ohne zu warten auf "Kaffeekreislauf heizen", "Spülen", "Dampfkreislauf heizen".

Drei Tastendrücke und Wartezeiten, das macht ab sofort FHEM!

- einfach nach der Anleitung von "wintermute" aus dem KNX-Forum (https://knx-user-forum.de/forum/projektforen/edomi/1010532-kaffeeautomaten-jura-bremer-aehnliche) einen Wemos D1 Mini mit nem Pegelwandler versehen und den Sketch von wintermute draufgespielt
- das ganze gemäß der Belegung aus http://protocoljura.wiki-site.com/index.php/Serial_interfaces#four-pin_interface an die Service-Schnittstelle angeschlossen, damit hat dann jede alte Jura Maschine ein Webinterface über welches sie über WLAN gesteuert werden kann und Statusinfos ausgibt
- in FHEM ein Notify angelegt, welches nacheinander einschaltet, spült und den Dampfkreislauf aufheizt.

"Alexa schalte die Kaffeemaschine ein" - und bis ich in der Küche bin ist die gute alte Jura S90 aufgeheizt und ich kann meinen Kaffee ziehen. Materialaufwand: 1 Wemos D1 mini, 1 Pegelwandler, d.h. nicht viel mehr als 5€!

NUC - FHEM & HA
MapleCUN, Homematic, 433MHz, AB440, 1-Wire Bewässerung & Pool, Jarolift (Signalduino), Signal Messenger, Denon AVR, LG WebOS, AmazonEcho, Jura S90 (ESP8266), Sonoff, Xiaomi Mii Sauger, Worx SO500i

warcraft123

Hallo,

habe den Thread endeckt und gleich meine Jura s90 angeschlossen.
Das hat soweit geklappt, per Web ist sie erreichbar,
aber wie kann ich die per Fhem ansprechen?
Könntest du mir das bitte genauer erklären, bzw. dein Notify hier posten? Danke

Gruss Marcus

thorschtn

AN (Kaffeekreislauf heizen, Milchkreislauf heizen, spülen):
defmod on_Jura notify du_JURA_Control:on {GetFileFromURL("http://192.168.178.66/power?param=1") };; { sleep 2 };; {GetFileFromURL("http://192.168.178.66/proffer?param=8") } ;; { sleep 120 };; {GetFileFromURL("http://192.168.178.66/proffer?param=2") }
attr on_Jura room Kaffeemaschine


AUS:
defmod off_Jura notify du_JURA_Control:off {GetFileFromURL("http://192.168.178.66/power?param=0") }
attr off_Jura room Kaffeemaschine
NUC - FHEM & HA
MapleCUN, Homematic, 433MHz, AB440, 1-Wire Bewässerung & Pool, Jarolift (Signalduino), Signal Messenger, Denon AVR, LG WebOS, AmazonEcho, Jura S90 (ESP8266), Sonoff, Xiaomi Mii Sauger, Worx SO500i

killah78

Hi thorschtn,
habe mal kurzerhand nachgebaut und in eine Jura S9 eingebaut. Funktioniert auf anhieb. Danke für diesen Tip.
Kannst du mir vielleicht mit deinem notify helfen? Wenn ich diesen so einbaue, blockiert der Notify für die zwei Minuten das komplette FHEM-Webinterface. Wie kann ich das non-blocking aufrufen?
Danke und Gruss
killah78

thorschtn

Ich nutz den nicht über das Webinterface, daher ist mir das bislang noch nicht aufgefallen.

Grundsätzlich sind die HttpUtils wohl nicht vollständig nonblocking, wenn ich https://wiki.fhem.de/wiki/HttpUtils richtig verstehe - da kenn ich mich aber auch nicht wirklich gut aus. Rufst Du die Kaffeemaschine über die IP oder über den Hostnamen auf?

Vielleicht versuchst Du statt GetFileFromURL auch mal HttpUtils_NonblockingGet?

Viele Grüße

Thorsten
NUC - FHEM & HA
MapleCUN, Homematic, 433MHz, AB440, 1-Wire Bewässerung & Pool, Jarolift (Signalduino), Signal Messenger, Denon AVR, LG WebOS, AmazonEcho, Jura S90 (ESP8266), Sonoff, Xiaomi Mii Sauger, Worx SO500i

killah78

Hi thorschtn,
ja, habe jetzt mal auf HttpUtils_NonblockingGet umgebaut, aber auch das blockiert. Denke, das sleep blockiert. Ich nutze das auch nicht über die Weboberfläche, sondern extern über Alexa per Sprache. Aber trotzdem friert FHEM da komplett ein und verarbeitet keine weiteren Events.
Werde das demnächst mal mit einem (non-)BlockingCall versuchen, das sollte ja dann funktionieren.
Gruss
killah78

det.

Hallo,
Hänge mich hier mal mit rein. Das Blockieren bekommt Ihr weg, wenn Ihr die Befehle zeitgesteuert absetzt, wie in meinem Beispiel zum Start vom Sonosplayer nach Strom einschalten:
SONOS:on.* {
fhem "define SonosStart at +00:01:00 set Sonos_Wohnzimmer LoadRadio Radioc%20Paradise";
fhem "define SonosStart1 at +00:01:01 set Sonos_Wohnzimmer Volume 15";
fhem "define SonosStart2 at +00:01:02 set Sonos_Wohnzimmer AddMember Sonos_Fernseher";
fhem "define SonosStart3 at +00:01:03 set Sonos_Wohnzimmer Play";
fhem "define SonosStart8 at +00:01:04 set Sonos_Wohnzimmer Mute 0"
}

Ich habe bisher vergeblich versucht den Sketch aus dem Link auf einen ESP8266 zu spielen. Da kommen immer Fehler bei D1 ,2,5 und 6? Liegt das daran, das der Sketch von einem Wemos D1 mini ausgeht?
LG
det.

eszych

Hallo Zusammen,
die Feiertage haben mir etwas Zeit beschert und ich habe mich mal daran gemacht die Anleitung von hier
1. https://knx-user-forum.de/forum/projektforen/edomi/1010532-kaffeeautomaten-jura-bremer-aehnliche/page2
und von hier
2. http://www.instructables.com/id/IoT-Enabled-Coffee-Machine/ umzusetzen.

Ich habe die Webseite von 1. und die Möglichkeiten von 2. alles auch per MQTT zu schalten umgesetzt.

Was ich aber gar nicht hinbekomme ist, meine Impressa F50 classic zu schalten...
Außer "Ausschalten" geht gar nichts und ich habe keine Idee, was nicht stimmen könnte.

Hier ist der Code vom Sketch:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
#include <PubSubClient.h>
#include <Nextion.h>
// used for UDP communication
#include <WiFiUdp.h>
// used for general time related stuff
#include <Time.h>
// used to schedule actions at specific times
#include <TimeAlarms.h>
// SoftwareSerial for communicating with the machine
#include <SoftwareSerial.h>
enum machine {NONE,UNSUPPORTED,S90,E50,C5};

/*
* Configuration START
*/

// set machine type, or set to "NONE" to disable communication with machine (for test mode)
// set to "UNSUPPORTED" if your machine is not listed and not compatible with listed types
machine type=UNSUPPORTED;
// Hostname
const char* host="hostname";
// mDNS name (leave empty if not needed)
const char* mdns="jura";
// SSID
const char* ssid="WLANSSID";
// Passphrase
const char* passphrase="WLANPW";
// IP (leave empty if DHCP is used)
// IPAddress ip(192,168,100,200);
IPAddress ip;
// Netmask (can be ignored if DHCP is used)
IPAddress mask(255,255,255,0);
// Gateway (set to (0,0,0,0) if no gateway should be configured or DHCP is used)
IPAddress gateway(0,0,0,0);
// DNS (can be ignored if DHCP is used)
IPAddress dns;
// TimeServer IP (leave empty to use hostname, defined below)
IPAddress NTPserverIP;
// TimeServer Hostname (will be overriden by above configuration)
const char* NTPserverName="1.de.pool.ntp.org";
// username and password for web access (leave at least one empty if no authentication should be used)
const char* user="admin";
const char* pass="password";
/* UDP receiver IP and port, if both is provided, status messages of the machine will be send to that host */
const char* udpRemoteAddress="";
const unsigned int udpRemotePort=0;
int i;
// machine gets queried every "cycle" seconds
unsigned int cycle=60;

const char *mqtt_server = "192.168.1.123";
const int   mqtt_port   = 1883;
const char *mqtt_client_name = "JuraF50"; // Client connections cant have the same connection name

WiFiClient espClient;                //Declares a WifiClient Object using ESP8266WiFi
PubSubClient MQTTClient(espClient);  //instanciates client object

/*
* Configuration END
*/

/*
* Variables & constants
*/
// Version
const String fw_version="0.1 - 2016112801";
// connection to machine
SoftwareSerial mySerial(D5,D6);
// Webserver & Update
ESP8266WebServer server(80);
ESP8266HTTPUpdateServer httpUpdater;
// NTP stuff
const int NTP_PACKET_SIZE=48;
byte packetBuffer[NTP_PACKET_SIZE];
const int timeZone=1; // CET
// UDP instance for NTP communication
WiFiUDP udp;
// UDP instance for state updates
WiFiUDP Sudp;
// web response
String html="";
String head_main="<html>\
<head>\
<link rel='shortcut icon' type='image/x-icon' href='data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEREDwAAAAAmJiYtR0lJgCYmJi1AREQPAAAAAAAAAAAAAAAAAAAAAEBERA8AAAAAQEREDwAAAABNTU3/TU1N/01NTf9MTEz/TU1N/01NTf9NTU3/TU1N/0xMTP9NTU3/TU1N/wAAAAAAAAAAQEREDwAAAABMTEz/TU1N/01NTf9NTU3/AAAAAEBERA8nJyd/AAAAAAAAAABNTU3/TExM/01NTf9NTU3/AAAAAAAAAAAAAAAAAAAAAEBERA9NTU3/AAAAAE1NTf9NTU3/TExM/01NTf9NTU3/AAAAAE1NTf9AREQPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQERED01NTf9LTExwTU1N/01NTf9MTEz/TU1N/01NTf8AAAAAAAAAAEBERA8AAAAAAAAAAAAAAAAAAAAAAAAAAE1NTf9AREQPTU1N/01NTf9NTU3/TU1N/0xMTP9NTU3/TU1N/01NTf9NTU3/QEREDwAAAABAREQPAAAAAAAAAABNTU3/AAAAAExMTP9NTU3/TU1N/01NTf9NTU3/TExM/01NTf8AAAAATU1N/wAAAABAREQPAAAAAEBERA8AAAAATU1N/wAAAABNTU3/TExM/01NTf9NTU3/TU1N/01NTf9MTEz/AAAAAExMTIxGSEh5AAAAAAAAAAAAAAAARkhIPU1NTf9NTU3/TU1N/01NTf9MTEz/TU1N/01NTf9NTU3/TU1N/0xMTP9NTU3/AAAAAAAAAAAAAAAAAAAAACcnJxVMTEz/AAAAAAAAAAAAAAAAAAAAAEBERA8AAAAAAAAAAE1NTf8mJiYmQEREDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAExMTP9NTU3/TU1N/01NTf9NTU3/TExM/01NTf8AAAAAAAAAAAAAAABAREQPAAAAAEBERA8AAAAAAAAAAAAAAAAAAAAAQEREDwAAAAAAAAAAAAAAAAAAAABAREQPAAAAAAAAAAAAAAAAAAAAAEBERA8AAAAAQEREDwAAAAAAAAAAAAAAAE1NTf9AREQPTU1NpwAAAABNTU3/AAAAAEBERA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAREQPAAAAAAAAAABNTU3/AAAAAExMTP8AAAAATU1N/wAAAAAAAAAAQEREDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBERA8AAAAAAAAAAAAAAAAAAAAAQEREDwAAAAAAAAAAAAAAAAAAAABAREQPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEREDwAAAAAAAAAAAAAAAAAAAABAREQPAAAAAAAAAAAAAAAAAAAAAEBERA8AAAAA/v8AAMAHAACHwwAA6C8AAPQfAADoAwAA6AsAAOgLAADgAwAA7+8AAPAfAAD//wAA+r8AAPq/AAD//wAA//8AAA=='/> \
<title>"+String(host)+"</title>\
<meta http-equiv='refresh' content='60'>\
<style>\
  body,a { background-color: #000000; font-family: Arial, Helvetica, Sans-Serif; Color: #d0d0d0; }\
  a:link { text-decoration: none; }\
  a:visited { text-decoration: none; }\
  a:hover { text-decoration: underline; }\
  a:active { text-decoration: underline; }\
</style>\
</head>\
<body>\
";
String head="<html>\
<head>\
<link rel='shortcut icon' type='image/x-icon' href='data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEREDwAAAAAmJiYtR0lJgCYmJi1AREQPAAAAAAAAAAAAAAAAAAAAAEBERA8AAAAAQEREDwAAAABNTU3/TU1N/01NTf9MTEz/TU1N/01NTf9NTU3/TU1N/0xMTP9NTU3/TU1N/wAAAAAAAAAAQEREDwAAAABMTEz/TU1N/01NTf9NTU3/AAAAAEBERA8nJyd/AAAAAAAAAABNTU3/TExM/01NTf9NTU3/AAAAAAAAAAAAAAAAAAAAAEBERA9NTU3/AAAAAE1NTf9NTU3/TExM/01NTf9NTU3/AAAAAE1NTf9AREQPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQERED01NTf9LTExwTU1N/01NTf9MTEz/TU1N/01NTf8AAAAAAAAAAEBERA8AAAAAAAAAAAAAAAAAAAAAAAAAAE1NTf9AREQPTU1N/01NTf9NTU3/TU1N/0xMTP9NTU3/TU1N/01NTf9NTU3/QEREDwAAAABAREQPAAAAAAAAAABNTU3/AAAAAExMTP9NTU3/TU1N/01NTf9NTU3/TExM/01NTf8AAAAATU1N/wAAAABAREQPAAAAAEBERA8AAAAATU1N/wAAAABNTU3/TExM/01NTf9NTU3/TU1N/01NTf9MTEz/AAAAAExMTIxGSEh5AAAAAAAAAAAAAAAARkhIPU1NTf9NTU3/TU1N/01NTf9MTEz/TU1N/01NTf9NTU3/TU1N/0xMTP9NTU3/AAAAAAAAAAAAAAAAAAAAACcnJxVMTEz/AAAAAAAAAAAAAAAAAAAAAEBERA8AAAAAAAAAAE1NTf8mJiYmQEREDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAExMTP9NTU3/TU1N/01NTf9NTU3/TExM/01NTf8AAAAAAAAAAAAAAABAREQPAAAAAEBERA8AAAAAAAAAAAAAAAAAAAAAQEREDwAAAAAAAAAAAAAAAAAAAABAREQPAAAAAAAAAAAAAAAAAAAAAEBERA8AAAAAQEREDwAAAAAAAAAAAAAAAE1NTf9AREQPTU1NpwAAAABNTU3/AAAAAEBERA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAREQPAAAAAAAAAABNTU3/AAAAAExMTP8AAAAATU1N/wAAAAAAAAAAQEREDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBERA8AAAAAAAAAAAAAAAAAAAAAQEREDwAAAAAAAAAAAAAAAAAAAABAREQPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEREDwAAAAAAAAAAAAAAAAAAAABAREQPAAAAAAAAAAAAAAAAAAAAAEBERA8AAAAA/v8AAMAHAACHwwAA6C8AAPQfAADoAwAA6AsAAOgLAADgAwAA7+8AAPAfAAD//wAA+r8AAPq/AAD//wAA//8AAA=='/> \
<title>"+String(host)+"</title>\
<style>\
  body,a { background-color: #000000; font-family: Arial, Helvetica, Sans-Serif; Color: #d0d0d0; }\
  a:link { text-decoration: none; }\
  a:visited { text-decoration: none; }\
  a:hover { text-decoration: underline; }\
  a:active { text-decoration: underline; }\
</style>\
</head>\
<body>\
";
// machine stuff
String mState="";
// misc stuff
unsigned long lastRun=0;
const int led = LED_BUILTIN;
// Debug stuff
unsigned int debug_pointer=0;
char debug_0[100]="";
char debug_1[100]="";
char debug_2[100]="";
char debug_3[100]="";
char debug_4[100]="";
char debug_5[100]="";
char debug_6[100]="";
char debug_7[100]="";
char debug_8[100]="";
char debug_9[100]="";
char debug_10[100]="";
char debug_11[100]="";
char debug_12[100]="";
char debug_13[100]="";
char debug_14[100]="";
char debug_15[100]="";
char debug_16[100]="";
char debug_17[100]="";
char debug_18[100]="";
char debug_19[100]="";
String debug_table[]={
  debug_0,
  debug_1,
  debug_2,
  debug_3,
  debug_4,
  debug_5,
  debug_6,
  debug_7,
  debug_8,
  debug_9,
  debug_10,
  debug_11,
  debug_12,
  debug_13,
  debug_14,
  debug_15,
  debug_16,
  debug_17,
  debug_18,
  debug_19
};
unsigned int debug_count=20;
char debug_buffer[100];
boolean debug_lastnewline=false;
const char* pubchar = "";

bool valueChanged = false;

// Pins for 2-Way-RELAY
int relay_IN1 = D1;
int relay_IN2 = D2;

// Time settings
String date2text() {
  char buf[11]="";
  if (timeStatus()==timeSet) sprintf(buf,"%02d.%02d.%04d",day(),month(),year());
  return String(buf);
}

String time2text() {
  char buf[8]="";
  if (timeStatus()==timeSet) sprintf(buf, "%02d:%02d:%02d",hour(),minute(),second());
  return String(buf);
}

void mqttConnect() {
  if (!MQTTClient.connected()) {
    //Serial.println("Connecting to broker");
    if (MQTTClient.connect("mqtt_client_name")){
      //Serial.print("Subscribing to :");
      //Serial.println(subPath);
      // MQTTClient.subscribe(subPath);
      MQTTClient.subscribe("/FHEM/Kaffeemaschine/Power");
      MQTTClient.subscribe("/FHEM/Kaffeemaschine/Action");
    }else{
      //Serial.println("Failed to connect!");
    }
  }
}

void debug(String text="", boolean newline=true) {
  if (debug_lastnewline && timeStatus()==timeSet && text.length()) text=time2text()+" :: "+text;
  Serial.print(text);
  pubchar = text.c_str();
  MQTTClient.publish("/Kaffee/Debug/Text/", pubchar);
  if (debug_lastnewline) {
    if (text.length()) {
      debug_pointer++;
      if (debug_pointer>=debug_count) debug_pointer=0;
    }
  } else {
    text=debug_table[debug_pointer]+text;
  }

  if (newline) {
    Serial.println();
  }
  debug_lastnewline=newline;
  // add debug message to debug array
  if (text.length()) {
    text.toCharArray(debug_buffer,100);
    debug_table[debug_pointer]=debug_buffer;
  }
}

void http_debug(String txt, boolean newline=true) {
  debug(txt + String(" [") + server.client().remoteIP().toString() + String("]"), newline);
}

void restart() {
  ESP.restart();
}

void reset() {
  ESP.reset();
}

/*
* NTP Functions BEGIN
*/
unsigned long sendNTPpacket(IPAddress& ip) {
  // build and send a NTP query packet
  memset(packetBuffer,0,NTP_PACKET_SIZE);
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;            // Stratum, or type of clock
  packetBuffer[2] = 6;            // Polling Interval
  packetBuffer[3] = 0xEC;         // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]= 49;
  packetBuffer[13]= 0x4E;
  packetBuffer[14]= 49;
  packetBuffer[15]= 52;
  udp.beginPacket(ip, 123);
  udp.write(packetBuffer,NTP_PACKET_SIZE);
  udp.endPacket();
}

time_t getNTPtime() {
  int pp=0;
  while (pp==0) {
    sendNTPpacket(NTPserverIP);
    delay(1000);
    pp=udp.parsePacket();
    delay(1000);
  }

  udp.read(packetBuffer,NTP_PACKET_SIZE);
  unsigned long secsSince1900;
  // convert four bytes starting at location 40 to a long integer
  secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
  secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
  secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
  secsSince1900 |= (unsigned long)packetBuffer[43];
  return secsSince1900-2208988800UL+timeZone*SECS_PER_HOUR;
}

/*
* NTP functions END
*/

/*
* Webserver functions BEGIN
*/
void auth() {
  digitalWrite(led,LOW);
  if(user!="" && pass!="") {
    if (!server.authenticate(user,pass)) server.requestAuthentication();
  }
  delay(50);
  digitalWrite(led,HIGH);
}

boolean ARGplain() {
  for (uint8_t i=0; i<server.args(); i++) {
    if (server.argName(i)=="plain") return true;
  }
  return false;
}

String ARGcommand() {
  for (uint8_t i=0; i<server.args(); i++) {
    if (server.argName(i)=="cmd") return server.arg(i);
  }
  return "";
}

String ARGparam() {
  for (uint8_t i=0; i<server.args(); i++) {
    if (server.argName(i)=="param") return server.arg(i);
  }
  return("");
}

void web_root() {
  auth();
  http_debug("/ accessed");
  int s=WiFi.RSSI();
  if (ARGplain()) {
    html ="Status: "+readState()+"\n";
    switch (type) {
      case NONE:
        html+="Machine: none\n";
        break;
      case UNSUPPORTED:
        html+="Machine: unsupported\n";
        break;
      case C5:
        html+="Machine: C5\n";
        break;
      case S90:
        html+="Machine: S90\n";
        break;
      case E50:
        html+="Machine: E50\n";
        break;
      default:
        html+="Machine: none\n";
        break;
    }
    html+="Controller uptime: "+String(millis())+"\n";
    html+="SSID: "+String(ssid)+"\n";
    html+="Signal: "+String(s)+"\n";
    html+="Time: "+time2text()+"\n";
    html+="Date: "+date2text()+"\n";
    html+="Firmware: "+fw_version+"\n";
    server.send(200,"text/plain",html);
  } else {
    html=head_main;
    html+="<h3>Status: "+readState()+"</h3>";
    html+="<a href='/power?param=0'>Abschalten</a><br/>";
    html+="<a href='/power?param=1'>Anschalten</a><br/>";
    html+="<a href='/flush'>Sp&uuml;len</a><br/>";
    html+="<hr/>";
    html+="<a href='/proffer?param=1'>Produkt 1 beziehen</a><br/>";
    html+="<a href='/proffer?param=2'>Produkt 2 beziehen (Ger&auml;t sp&uuml;len)</a><br/>";
    html+="<a href='/proffer?param=3'>Produkt 3 beziehen (Pulverkaffee)</a><br/>";
    html+="<a href='/proffer?param=4'>Produkt 4 beziehen (1 kleine Tasse)</a><br/>";
    html+="<a href='/proffer?param=5'>Produkt 5 beziehen (2 kleine Tassen)</a><br/>";
    html+="<a href='/proffer?param=6'>Produkt 6 beziehen (1 gro&szlig;e Tasse)</a><br/>";
    html+="<a href='/proffer?param=7'>Produkt 7 beziehen (2 gro&szlig;e Tassen)</a><br/>";
    html+="<a href='/proffer?param=8'>Produkt 8 beziehen (Dampf Portion)</a><br/>";
    html+="<a href='/proffer?param=9'>Produkt 9 beziehen (Dampf)</a><br/>";
    html+="<a href='/proffer?param=10'>Produkt 10 beziehen</a><br/>";
    html+="<a href='/proffer?param=11'>Produkt 11 beziehen</a><br/>";
    html+="<a href='/proffer?param=12'>Produkt 12 beziehen (Kaffee Spezial)</a><br/>";
    html+="<a href='/proffer?param=13'>Produkt 13 beziehen</a><br/>";
    html+="<hr/>";
    html+="<a href='/reset'>Controller Reset</a><br/>";
    html+="<a href='/restart'>Controller Restart</a><br/>";
    html+="<a href='/update'>Controller Update</a><br/>";
    html+="<a href='/debug'>Debug Log</a><br/>";
    html+="<hr/>";
    html+=String(host)+", verbunden mit "+String(ssid)+", Signalst&auml;rke "+String(s)+"dBm&nbsp;-&nbsp;";
    html+="Systemzeit "+date2text()+", "+time2text()+"<br/>";
    html+="<small>Controller uptime "+String(millis())+"ms&nbsp;-&nbsp;";
    html+="Firmwareversion "+fw_version;
    html+="</small></body></html>";
    server.send(200,"text/html",html);
  }
  delay(100);
}

void web_reset() {
  auth();
  http_debug("/reset accessed");
  debug("Reset requested");
  if (ARGplain()) {
    server.send(200,"text/plain","ok");
  } else {
    html=head;
    html+="<h3>Controller is resetting</h3><a href='/'>back</a></body</html>";
    server.send(200,"text/html",html);
  }
  reset();
}

void web_restart() {
  auth();
  http_debug("/restart accessed");
  debug("Restart requested");
  if (ARGplain()) {
    server.send(200,"text/plain","ok");
  } else {
    html=head;
    html+="<h3>Controller is restarting</h3><a href='/'>back</a></body</html>";
    server.send(200,"text/html",html);
  }
  restart();
}

void web_send() {
  auth();
  if (ARGplain()) {
    server.send(200,"text/plain","ok");
  } else {
    html=head;
    html+="<h3>Controller is resetting</h3><a href='/'>back</a></body</html>";
    server.send(200,"text/html",html);
  }
  restart();
}

void web_power() {
  auth();
  http_debug("/power accessed");
  unsigned int p=ARGparam().toInt();
  if (ARGparam()=="") {
    if (mState=="off") {
      server.send(200,"text/plain","0");
    } else {
      server.send(200,"text/plain","1");
    }
    return;
  }
  String command="AN:02";
  String answer="";
  switch (p) {
    case 1:
      MQTTClient.publish("/Kaffee/Power/PowerOnOff/", "ON");
      digitalWrite(relay_IN1, LOW);
      digitalWrite(relay_IN2, LOW);

      debug("Power On");
      command="AN:01";
      break;
    default:
      MQTTClient.publish("/Kaffee/Power/PowerOnOff/", "OFF");
      debug("Power Off");
      command="AN:02";
      digitalWrite(relay_IN1, HIGH);
      digitalWrite(relay_IN2, HIGH);
      break;
  }
  toMachine(command);
  delay(10);
  answer=fromMachine();
  if (ARGplain()) {
    server.send(200,"text/plain","Answer: "+answer);
  } else {
    html=head;
    html+="<h3>Maschine an/abschalten</h3>R&uuml;ckmeldung: "+answer+"<hr/><a href='/'>back</a></body</html>";
    server.send(200,"text/html",html);
  }
}

void web_flush() {
  auth();
  http_debug("/flush accessed");
  String answer="";
  toMachine("FA:0B");
  delay(10);
  answer=fromMachine();
  if (ARGplain()) {
    server.send(200,"text/plain","Answer: "+answer);
  } else {
    html=head;
    html+="<h3>Sp&uuml;len</h3>R&uuml;ckmeldung: "+answer+"<hr/><a href='/'>back</a></body</html>";
    server.send(200,"text/html",html);
  }

}

void web_proffer() {
  auth();
  http_debug("/proffer accessed");
  unsigned int p=ARGparam().toInt();
  String command="";
  String answer="";
  switch (p) {
    case 1:
      debug("Product 1 requested"); command="FA:01"; break;
    case 2:
      debug("Product 2 requested"); command="FA:02"; break;
    case 3:
      debug("Product 3 requested"); command="FA:03"; break;
    case 4:
      debug("Product 4 requested - small cup???"); command="FA:04"; break;
    case 5:
      debug("Product 5 requested - two small cups???"); command="FA:05"; break;
    case 6:
      debug("Product 6 requested - large cup???"); command="FA:06"; break;
    case 7:
      debug("Product 7 requested - two large cups???"); command="FA:07"; break;
    case 8:
      debug("Product 8 requested - hot water???"); command="FA:08"; break;
    case 9:
      debug("Product 9 requested - steam???"); command="FA:09"; break;
    case 10:
      debug("Product 10 requested - steam???"); command="FA:0A"; break;
    case 11:
      debug("Product 11 requested - steam???"); command="FA:0B"; break;
    case 12:
      debug("Product 12 requested - XXL"); command="FA:0C"; break;
    case 13:
      debug("Product 13 requested - steam???"); command="FA:0D"; break;
    default:
      debug("Unknown product "+String(p)+" requested, aborting"); return;
  }
  toMachine(command);
  delay(10);
  answer=fromMachine();
  if (ARGplain()) {
    server.send(200,"text/plain","Answer: "+answer);
  } else {
    html=head;
    html+="<h3>Produkt "+String(p)+" angefordert</h3>R&uuml;ckmeldung: "+answer+"<hr/><a href='/'>back</a></body</html>";
    server.send(200,"text/html",html);
  }
}

void web_debug() {
  auth();
  //http_debug("/debug accessed");
  uint8_t p=debug_pointer;
  if (ARGplain()) {
    html="";
    for (uint8_t i=1; i<=debug_count; i++) p++;
    if (p>=debug_count) p-=debug_count;
    html+=String(debug_table[p]) + String("\n");
    server.send(200,"text/plain",html);
  } else {
    html=head+String("<h3>Debug Ausgaben</h3><pre>");
    for (uint8_t i=1; i<=debug_count; i++) {
      p++;
      if (p>=debug_count) p-=debug_count;
      html+=String(debug_table[p]) + String("\n");
    }
    html+=String("</pre><hr/><a href='/'>back</a></body></html>");
    server.send(200,"text/html",html);
  }
}

/*
* Webserver functions END
*/

/*
* Communication with machine BEGIN
* Parts of this code (especially the essential communicaton with the machine) are taken from
* or are inspired by code published by Oliver Krohn and the c't sharepresso project
*/

String fromMachine() {
  if (type==NONE) {
    debug("FROM machine: N/A - no machine type set");
    return("");
  }
  delay(10);
  String inputString="";
  char d4=255;
  while (mySerial.available()) {
    byte d0=mySerial.read();
    delay(1);
    byte d1=mySerial.read();
    delay(1);
    byte d2=mySerial.read();
    delay(1);
    byte d3=mySerial.read();
    delay(1);
    bitWrite(d4,0,bitRead(d0,2));
    bitWrite(d4,1,bitRead(d0,5));
    bitWrite(d4,2,bitRead(d1,2));
    bitWrite(d4,3,bitRead(d1,5));
    bitWrite(d4,4,bitRead(d2,2));
    bitWrite(d4,5,bitRead(d2,5));
    bitWrite(d4,6,bitRead(d3,2));
    bitWrite(d4,7,bitRead(d3,5));
    if (d4!=10) inputString+=d4;
    yield();
  }
  inputString.trim();
  debug("FROM machine: "+inputString);
  pubchar = inputString.c_str();
  MQTTClient.publish("/Kaffee/FromMachine/RAW/", pubchar);
  return(inputString);
}

void toMachine(String outputString) {
  outputString.toUpperCase();
  if (type==NONE) {
    debug("TO machine: "+outputString+" - nothing sent, machine type not set");
    return;
  }
  debug("TO machine: "+outputString);
  pubchar = outputString.c_str();
  MQTTClient.publish("/Kaffee/ToMachine/RAW/", pubchar);
  outputString+="\r\n";
  for (byte a=0; a<outputString.length(); a++) {
    byte d0=255;
    byte d1=255;
    byte d2=255;
    byte d3=255;
    bitWrite(d0,2,bitRead(outputString.charAt(a),0));
    bitWrite(d0,5,bitRead(outputString.charAt(a),1));
    bitWrite(d1,2,bitRead(outputString.charAt(a),2));
    bitWrite(d1,5,bitRead(outputString.charAt(a),3));
    bitWrite(d2,2,bitRead(outputString.charAt(a),4));
    bitWrite(d2,5,bitRead(outputString.charAt(a),5));
    bitWrite(d3,2,bitRead(outputString.charAt(a),6));
    bitWrite(d3,5,bitRead(outputString.charAt(a),7));
    mySerial.write(d0);
    delay(1);
    mySerial.write(d1);
    delay(1);
    mySerial.write(d2);
    delay(1);
    mySerial.write(d3);
    delay(1);
  }
}

String readState() {
  String answer="";
  String power="";
  String state="";
  switch (type) {
    case NONE:
      return("unknown");
      break;
    case UNSUPPORTED:
      toMachine("RE:31");
      delay(10);
      answer=fromMachine();
      debug("Answer from Machine: " + answer);
      mState="unknown :: "+state+"/" + answer;
      return(answer);
      break;
    case C5:
      toMachine("RR:BB");
      delay(10);
      answer=fromMachine().substring(3,7);
      if (answer=="0104") {
        debug("STATE: on");
        mState="on";
        /* sendState(); */
        return(mState);
      } else if (answer=="0100") {
        debug("STATE: off");
        mState="off";
        /* sendState(); */
        return(mState);
      } else {
        debug("STATE UNKNOWN: "+state+"/"+answer);
        mState="unknown :: "+state+"/"+answer;
        /* sendState(); */
        return(mState);
      }
      break;
    case S90:
      toMachine("RR:03");
      delay(10);
      answer=fromMachine();
      power=answer.substring(4,5);
      state=answer.substring(6,7)+answer.substring(25,28);
      if (power=="0") {
        debug("STATE: off");
        mState="off";
        /* sendState(); */
        return(mState);
      } else if (state=="C404") {
        debug("STATE: out of water");
        mState="no_water";
        /* sendState(); */
        return(mState);
      } else if (state=="4805") {
        debug("STATE: out of beans");
        mState="no_beans";
        /* sendState(); */
        return(mState);
      } else if (state=="C045") {
        debug("STATE: tray is missing");
        mState="no_tray";
        /* sendState(); */
        return(mState);
      } else if (state=="C444") {
        debug("STATE: tray is missing, out of water");
        mState="no_tray|no_water";
        /* sendState(); */
        return(mState);
      } else if (state=="4205") {
        debug("STATE: pomace full");
        mState="pomace_full";
        /* sendState(); */
        return(mState);
      } else if (state=="C105") {
        debug("STATE: tray is full");
        mState="tray_full";
        /* sendState(); */
        return(mState);
      } else if (state=="4005") {
        debug("STATE: on");
        mState="on";
        /* sendState(); */
        return(mState);
      } else {
        debug("STATE UNKNOWN: "+state+"/"+answer);
        mState="unknown :: "+state+"/"+answer;
        /* sendState(); */
        return(mState);
      }
      break;
    case E50:
      toMachine("RR:20");
      delay(10);
      answer=fromMachine().substring(3,11);
      state=answer.substring(0,2)+answer.substring(6,8);
      if (state=="0000") {
        debug("STATE: off");
        return("off");
      } else if (state=="0101") {
        debug("STATE: ready");
        return("ready");
      } else if (state=="1111") {
        debug("STATE: cleaning");
        return("cleaning");
      } else if (state=="4000") {
        debug("STATE: flushing");
        return("flushing");
      } else if (state=="8180") {
        debug("STATE: out of water");
        return("no_water");
      } else if (state=="9190") {
        debug("STATE: out of water");
        return("no_water");
      } else if (state=="4040") {
        debug("STATE: need flushing");
        return("need_flushing");
      } else if (state=="0505") {
        debug("STATE: need powder");
        return("no_powder");
      } else if (state=="2120") {
        debug("STATE: ??? full (2120)");
        return("??2_full");
      } else if (state=="3130") {
        debug("STATE: ??? full (3130)");
        return("??3_full");
       } else {
        debug("STATE UNKNOWN: "+state+"/"+answer);
        return("unknown");
      }
      break;
    default:
      return("unknown");
      break;
  }
}

void testCommand() {
  String outputString = server.arg(0);
  toMachine(outputString);
  delay(50);  // wait for answer?
  String inputString = fromMachine();
  delay(100);
  server.send(200, "text/plain", inputString);//a html_message);
}


/*
* Communication with machine END
*/

void ConfigureWifi() {
  // establish WLAN connection
  if (ip!=0) {
    debug("Static IP configuration");
    if (dns!=0) {
      WiFi.config(ip,gateway,mask,dns);
    } else {
      WiFi.config(ip,gateway,mask);
    }
  } else {
    debug("DHCP configured");
  }
  debug("Connecting to " + String(ssid),false);
  WiFi.begin(ssid,passphrase);
  while (WiFi.status()!=WL_CONNECTED) {
    delay(100);
    debug(".",false);
  }
  debug();
  debug("Connected...");

  ip=WiFi.localIP();
  mask=WiFi.subnetMask();
  gateway=WiFi.gatewayIP();
  debug();
  debug("IP     : " + ip.toString());
  debug("Netmask: " + mask.toString());
  debug("Gateway: " + gateway.toString());

}

void mqttcallback(char* topic, byte* payload, unsigned int length) {
  String sTopic = String(topic);
 
  // Workaround to get int from payload
  payload[length] = '\0';
  String payloadchar = String((char*)payload);

  uint32_t payloadvalue = String((char*)payload).toInt();

  unsigned int p=ARGparam().toInt();
  String command="";
  String answer="";

  // MQTTClient.subscribe("/FHEM/Kaffeemaschine/Power");
  // MQTTClient.subscribe("/FHEM/Kaffeemaschine/Action");

  if (sTopic == "/FHEM/Kaffeemaschine/Power") {
    if (payloadchar == "IN1ON") {
      debug("Received Power IN1 ON via MQTT");
      digitalWrite(relay_IN1, LOW);
    } else if (payloadchar == "IN2ON") {
      debug("Received Power IN2 ON via MQTT");
      digitalWrite(relay_IN2, LOW);
    } else if (payloadchar == "IN1OFF") {
      debug("Received Power IN1 OFF via MQTT");
      digitalWrite(relay_IN1, HIGH);
    } else if (payloadchar == "IN2OFF") {
      debug("Received Power IN2 OFF via MQTT");
      digitalWrite(relay_IN2, HIGH);
    }
  } else if (sTopic == "/FHEM/Kaffeemaschine/Action") {
    debug("Received Action "+ payloadchar +" via MQTT");
    if (payloadchar == "SPUELEN") {
      debug("Product 2 requested");
      command="FA:02";
    } else if (payloadchar == "1xESPRESSO") {
      debug("Product 4 - 1 x Espresso requested");
      command="FA:04";
    } else if (payloadchar == "2xESPRESSO") {
      debug("Product 5 - 2 x Espresso requested");
      command="FA:05";
    } else if (payloadchar == "1xKAFFEE") {
      debug("Product 6 - 1 x Kaffee requested");
      command="FA:06";
    } else if (payloadchar == "2xKAFFEE") {
      debug("Product 7 - 2 x Kaffee requested");
      command="FA:07";
    }
  }
  if (command != "") {
    toMachine(command);
    delay(100);
    answer=fromMachine();
    pubchar = answer.c_str();
    MQTTClient.publish("/Kaffee/Kaffemaschine/ProductReply/", pubchar);
  }

  valueChanged = true;
}

void setup() {
  // serial communication with the machine
  mySerial.begin(9600);
  // serial communication for debugging
  Serial.begin(115200);

  debug("Controller is starting...");
  debug("ChipID is "+String(ESP.getChipId()));

  //Init the relay pins
  debug("Initializing relay pins...");
  pinMode(relay_IN1, OUTPUT);
  delay(200);
  pinMode(relay_IN2, OUTPUT);
  delay(200);
  digitalWrite(relay_IN1, HIGH); // HIGH = AUS
  delay(200);
  digitalWrite(relay_IN2, HIGH); // HIGH = AUS
  delay(200);

  WiFi.mode(WIFI_STA); // Client Mode
  ConfigureWifi();

  if (NTPserverIP.toString()=="0.0.0.0") {
    debug("NTPname: " + String(NTPserverName) + " (resolving)");
    WiFi.hostByName(NTPserverName,NTPserverIP);
  }
  debug("NTP IP : " + NTPserverIP.toString());
  debug();
  debug("Establishing UDP socket for NTP communication, syncing time");
  udp.begin(1230);
  setSyncProvider(getNTPtime);
  // debug("Will perform a new NTP query every hour/2");
  // setSyncInterval(1800000); SYNC Intervall auf 4h gesetzt EJS
  debug("Will perform a new NTP query every 4h");
  setSyncInterval(14400000);
  debug("Local time is now: ",false);
  debug(date2text()+String(", ")+time2text());

  debug();
  if (mdns!="" && MDNS.begin(mdns)) {
    debug("Established mDNS responder for ("+String(mdns)+")");
    MDNS.addService("http","tcp",80);
  } else {
    debug("mDNS responder not established");
  }

  debug("Establishing connection to MQTT broker");
  MQTTClient.setServer(mqtt_server, 1883);
  MQTTClient.setCallback(mqttcallback);
  mqttConnect();
  if (!MQTTClient.connected()) {
    debug("Not connected to MQTT broker");
  }else{
    debug("Connected to MQTT broker");
  }
 
  debug("Starting Web server");
  httpUpdater.setup(&server);
  server.begin();
  server.on("/",web_root);
  server.on("/reset",web_reset);
  server.on("/restart",web_restart);
  server.on("/debug",web_debug);
  server.on("/proffer",web_proffer);
  server.on("/flush",web_flush);
  server.on("/power",web_power);
  server.on("/command",testCommand);

  debug();
  if (udpRemotePort==0 || udpRemoteAddress=="") {
    debug("No UDP listener configured");
  } else {
    debug("Establishing socket for UDP listener");
    Sudp.begin(1231);
  }

  debug();
  debug("Restarting controller every night at 01:30");
  Alarm.alarmRepeat(01,30,0,restart);

  pinMode(led,OUTPUT);
  debug();
  debug("Setup done...");

  switch (type) {
    case NONE:
      debug("CONTROLLER IS CURRENTLY RUNNING IN TESTMODE - communication with machine disabled");
      for(uint8_t i=0; i<10; i++) {
        digitalWrite(led,LOW); // Turn ON internal LED
        delay(50);
        digitalWrite(led,HIGH); // Turn OFF internal LED
        delay(50);
      }
      break;
    case UNSUPPORTED:
      debug("Unsupported machine type, won't read machine status");
      break;
    case C5:
      debug("Machine type set to C5");
      break;
    case S90:
      debug("Machine type set to S90");
      break;
    case E50:
      debug("Machine type set to E50");
      break;
  }
}

void loop() {
  //status=fromMachine();
  if (millis()-lastRun>cycle*1000) {
    lastRun=millis();
    // debug(String(lastRun));
    readState();

    // Make sure we are connected
    if (WiFi.status() != WL_CONNECTED) {
      ConfigureWifi();
    }
    mqttConnect();
  }
  server.handleClient();
  Alarm.delay(0);
  MQTTClient.loop();
}



Falls jemand eine Idee hat - ich bin für jeden Vorschlag dankbar!

Gruss
Elmar
Raspberry Pi 2 - FHEM 5.7
HM-LAN, HM-CFG-USB-2
HM-Sec-SCo, HM-Sec-SC-2, HM-TC-IT-WM-W-EU,
HM-LC-SW4-DR, HM-LC-Sw1-DR, HM-ES-PMSw1-DR,    
HM-ES-PMSw1-Pl - Rademacher Hompilot DuoFern

irqnet

#12
Ich versuche das Ganze gerade mit meiner Jura Ena Micro 90 und bekomme sie überhaupt nicht überredet irgendwas zu machen. Habe den Sketch mit diversen ESP8266 Modulen getestet, aber die Maschine reagiert auf keinen einzigen "Befehl".

Gibt es eine Möglichkeit den Serviceport der Maschine irgendwie zu debuggen? Oder kann ich im Sketch sehen ob da überhaupt was an Infos an die Maschine geht oder von der Maschine kommt?

@eszych: Habe versucht die mqtt Integration zu konfigurieren, nutze bei meinem lokalen mqtt server allerdings eine authentifzierung. Seltsamerweise funktioniert die Übergabe von User und Passwort beim Connect nicht. Hast Du evtl. einen Tipp?


@det. Du musst bei einem "normalen" ESP die GPIO Ports angeben. D5 / D6 usw. kennt der aus der Bibliothek dann nicht. Die PINOUTs für die ESPs sind leider nicht immer identisch, aber hier hast Du einen Anhaltspunkt:

http://www.mikrocontroller-elektronik.de/nodemcu-esp8266-tutorial-wlan-board-arduino-ide/

Tausch also einfach mal D5 gegen 14 und D6 gegen 12 etc. gemäß dem Pinout für dein entsprechendes ESP Modul.

det.

Hallo irqnet,

hatte es hinbekommen indem ich einfach einen Wemos mini gekauft habe. Mit dem ging es (Sketch aufspielen, Web Oberfläche sehen), allerdings meine F70 macht über den Service Port nichts weiter als den Wemos mit 5V zu versorgen. Schalten konnte ich nichts, nicht mal nur aus. Da habe ich es aufgegeben und beobachte hier ob jemand mehr Erfolg hat.
LG
det.

irqnet

Zitat von: det. am 14 Februar 2018, 17:35:44
Hallo irqnet,

hatte es hinbekommen indem ich einfach einen Wemos mini gekauft habe. Mit dem ging es (Sketch aufspielen, Web Oberfläche sehen), allerdings meine F70 macht über den Service Port nichts weiter als den Wemos mit 5V zu versorgen. Schalten konnte ich nichts, nicht mal nur aus. Da habe ich es aufgegeben und beobachte hier ob jemand mehr Erfolg hat.

Schade. Ich vermute das es vielleicht eine Änderung im Protokoll gab, oder aber die Ports doch nicht voll belegt sind. +5V und GND konnte ich auch identifzieren. Ob die beiden anderen Ports für RX TX wirklich was tun intern, weiß ich nicht.