Good evening,
I started making my Jura coffeemaker “smart”, but stumbled upon some problems.
As it will work properly, I can post that whole project in the Tutorials page. But for now I have to figure out what my problem is.
I’m using the ESP8266 (Wemos D1 board). Reading serial messages from the coffeemachine and communicating with openhab through MQTT.
I have also some problems with the timing for the communication with the coffeemaker, but my main problem is the MQTT connection. It loses the connection almost every 2-3 minutes and wont send updates after a few hours. At this point it also won’t accept all commands.
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <SoftwareSerial.h>
const char* wifi_ssid = "SSID";
const char* wifi_key = "WIFIPASSWORD";
const char* mqtt_client = "JURAF90";
const char* mqtt_server = "1.2.3.4";
const char* mqtt_user = "user";
const char* mqtt_password = "password";
WiFiClient espClient;
PubSubClient client(espClient);
SoftwareSerial jura(12, 13);
unsigned long previousMillis = 0; // will store last time loop ran
unsigned int interval = 500; // interval at which to limit loop
unsigned int loopCount = 0; // resets loop
byte intra = 1;
byte inter = 10;
String power_state;
char size_state;
char aroma_state;
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // set onboard LED as output
Serial.begin(115200); // Set connection to debugging
jura.begin(9600); // Set connection to Jura
setup_wifi(); // wifi configuration
client.setServer(mqtt_server, 1883);
client.setCallback(mqttcallback);
}
void setup_wifi() {
Serial.print(F("[INFO][WIFI] Connecting to "));
Serial.println(wifi_ssid);
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.hostname("JURAF90");
WiFi.begin(wifi_ssid, wifi_key);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(F("[INFO][WIFI] Connected"));
Serial.print(F("[INFO][WIFI] IP address: "));
Serial.println(WiFi.localIP());
}
boolean reconnect() {
if(WiFi.status() != WL_CONNECTED){
Serial.println(F("[INFO][WIFI] Reconnecting..."));
while (WiFi.status() != WL_CONNECTED){
WiFi.begin(wifi_ssid, wifi_key);
uint8_t timeout = 8;
while (timeout && (WiFi.status() != WL_CONNECTED)) {
timeout--;
delay(100);
}
}
}
if(!client.connected()){
Serial.println(F("[INFO][MQTT] Connecting..."));
while(!client.connected()){
client.connect(mqtt_client, mqtt_user, mqtt_password);
uint8_t timeout = 8;
while (timeout && (!client.connected())){
timeout--;
delay(1000);
}
if(client.connected()){
Serial.println(F("[INFO][MQTT] Subscribing started..."));
client.subscribe("JURAF90/power/cmd"); // Subscription
client.subscribe("JURAF90/size/cmd"); // Subscription
client.subscribe("JURAF90/aroma/cmd"); // Subscription
client.subscribe("JURAF90/function/cmd"); // Subscription
client.subscribe("JURAF90/debug/cmd"); // Subscription
}
}
}
}
void mqttcallback(char* topic, byte* payload, unsigned int length) {
payload[length] = '\0';
// Serial.print(F("[DEBUG][MQTT][cmd]"));
// Serial.println((char*)payload);
if (strcmp(topic, "JURAF90/power/cmd") == 0) {
if(strcmp((char*)payload, "ON") == 0){
toCoffeemaker("AN:01");
Serial.println(F("[INFO][MQTT][cmd] ON"));
}
else if (strcmp((char*)payload, "OFF") == 0) {
toCoffeemaker("AN:02");
Serial.println(F("[INFO][MQTT][cmd] OFF"));
}
}
else if (strcmp(topic, "JURAF90/size/cmd") == 0) {
if(strcmp((char*)payload, "ESPRESSO") == 0){
toCoffeemaker("FA:0F");
Serial.println(F("[INFO][MQTT][cmd] ESPRESSO"));
}
else if(strcmp((char*)payload, "COFFEE") == 0){
toCoffeemaker("FA:0E");
Serial.println(F("[INFO][MQTT][cmd] COFFEE"));
}
else if(strcmp((char*)payload, "BIGCUP") == 0){
toCoffeemaker("FA:0D");
Serial.println(F("[INFO][MQTT][cmd] BIGCUP"));
}
}
else if (strcmp(topic, "JURAF90/aroma/cmd") == 0) {
if(strcmp((char*)payload, "MILD") == 0){
toCoffeemaker("FA:10");
Serial.println(F("[INFO][MQTT][cmd] MILD"));
}
else if(strcmp((char*)payload, "NORMAL") == 0){
toCoffeemaker("FA:11");
Serial.println(F("[INFO][MQTT][cmd] NORMAL"));
}
else if(strcmp((char*)payload, "STRONG") == 0){
toCoffeemaker("FA:12");
Serial.println(F("[INFO][MQTT][cmd] STRONG"));
}
}
else if (strcmp(topic, "JURAF90/function/cmd") == 0) {
if(strcmp((char*)payload, "START") == 0){
toCoffeemaker("FA:19");
Serial.println(F("[INFO][MQTT][cmd] START"));
}
else if(strcmp((char*)payload, "WATER") == 0){
toCoffeemaker("FA:0A");
Serial.println(F("[INFO][MQTT][cmd] WATER"));
}
else if(strcmp((char*)payload, "STEAM") == 0){
toCoffeemaker("FA:09");
Serial.println(F("[INFO][MQTT][cmd] STEAM"));
}
else if (strcmp((char*)payload, "RINSE") == 0) {
toCoffeemaker("FA:02");
Serial.println(F("[INFO][MQTT][cmd] RINSE"));
}
else if (strcmp((char*)payload, "LIGHT") == 0) {
toCoffeemaker("FA:08");
Serial.println(F("[INFO][MQTT][cmd] LIGHT"));
}
//else{
// Serial.print(F("[INFO][MQTT][cmd] "));
// Serial.println((char*)payload);
//}
}
else if (strcmp(topic, "JURAF90/debug/cmd") == 0) {
if(strcmp((char*)payload, "SCAN_RR") == 0){
Serial.println(F("[MQTT-DEBUG] Scan RR:"));
int i;
String result;
for (int i = 0; i < 256; i++){
char textBuf[256];
sprintf(textBuf, "RR:%02X", i);
toCoffeemaker(textBuf);
delay(200);
Serial.print(textBuf);
Serial.print(F(" : "));
Serial.println(fromCoffeemaker());
delay(50);
}
}
else if(strcmp((char*)payload, "SCAN_RE") == 0){
Serial.println(F("[MQTT-DEBUG] Scan RE:"));
int i;
String result;
for (int i = 0; i < 256; i++){
char textBuf[256];
sprintf(textBuf, "RE:%02X", i);
toCoffeemaker(textBuf);
delay(200);
Serial.print(textBuf);
Serial.print(F(" : "));
Serial.println(fromCoffeemaker());
delay(100);
}
}
else{
Serial.println(F("[MQTT-DEBUG] Received command: "));
toCoffeemaker((char*)payload);
Serial.print((char*)payload);
Serial.print(F(" : "));
Serial.println(fromCoffeemaker());
}
}
}
void loop() {
if(millis() - previousMillis > interval) {
loopCount ++;
previousMillis = millis();
}
reconnect();
if (loopCount == 7) { // Check the status every 7 seconds
loopCount = 0;
readState();
}
delay(100);
client.loop();
}
char toCoffeemaker(String outbytes) {
while (jura.available()) {
jura.read();
}
byte z0, z1, z2, z3;
outbytes += "\r\n";
for (int i = 0; i < outbytes.length(); i++) {
z0 = 255;
z1 = 255;
z2 = 255;
z3 = 255;
// Reads bits of ASCII byte and writes it into coding bits of 4 UART bytes
bitWrite(z0, 2, bitRead(outbytes[i],0));
bitWrite(z0, 5, bitRead(outbytes[i],1));
bitWrite(z1, 2, bitRead(outbytes[i],2));
bitWrite(z1, 5, bitRead(outbytes[i],3));
bitWrite(z2, 2, bitRead(outbytes[i],4));
bitWrite(z2, 5, bitRead(outbytes[i],5));
bitWrite(z3, 2, bitRead(outbytes[i],6));
bitWrite(z3, 5, bitRead(outbytes[i],7));
// Sends a 4 byte package to the coffeemaker
delay (intra); jura.write(z0);
delay (intra); jura.write(z1);
delay (intra); jura.write(z2);
delay (intra); jura.write(z3);
delay(inter);
}
delay(300);
}
String fromCoffeemaker(){
char inbyte;
String inbytes;
unsigned int w = 0;
unsigned int s = 0;
while (!inbytes.endsWith("\r\n")) {
if (jura.available()) {
byte rawbyte = jura.read();
bitWrite(inbyte, s + 0, bitRead(rawbyte, 2));
bitWrite(inbyte, s + 1, bitRead(rawbyte, 5));
if ((s += 2) >= 8) {
s = 0;
inbytes += inbyte;
}
}
else {
delay(inter);
}
if (w++ > 500) {
return "";
}
}
return inbytes.substring(0, inbytes.length() - 2);
}
void readState() {
String resultState;
toCoffeemaker("RR:1B");
resultState = fromCoffeemaker();
// Serial.print("Ergebnis: ");
// Serial.println(result);
if(resultState != power_state && resultState != ""){
if(resultState == "rr:0000"){
Serial.println(F("[INFO][JURA] OFF"));
client.publish("JURAF90/power/state", "OFF");
power_state = "rr:0000";
}
else if(resultState == "rr:1000"){
Serial.println(F("[INFO][JURA] ON"));
client.publish("JURAF90/power/state", "ON");
client.publish("JURAF90/state", "Bitte wählen");
power_state = "rr:1000";
}
else if(resultState == "rr:1001"){
Serial.println(F("[INFO][JURA] Flushing..."));
client.publish("JURAF90/state", "Gerät spült");
power_state = "rr:1001";
}
else if(resultState == "rr:1002"){
Serial.println(F("[INFO][JURA] Cleaning..."));
client.publish("JURAF90/state", "Gerät reinigt");
power_state = "rr:1002";
}
else if(resultState == "rr:1008"){
Serial.println(F("[INFO][JURA] Making Coffee..."));
client.publish("JURAF90/state", "Brüht Kaffee");
power_state = "rr:1008";
}
//else{
// Serial.println(F("[INFO][JURA] Bitte die Verbindung zur JURA prüfen"));
// client.publish("JURAF90/state", "Verbindung unterbrochen");
// Serial.println(result);
// power_state = "";
//}
}
if(power_state == "rr:1000"){
String resultProduct;
toCoffeemaker("RR:64");
resultProduct = fromCoffeemaker();
if(resultProduct != "" && resultProduct[3] != aroma_state){
if (resultProduct[3] == 51){
client.publish("JURAF90/aroma/state", "MILD");
Serial.println(F("[INFO][JURA] Mildes Aroma"));
aroma_state = 51;
}
else if (resultProduct[3] == 53){
client.publish("JURAF90/aroma/state", "NORMAL");
Serial.println(F("[INFO][JURA] Normales Aroma"));
aroma_state = 53;
}
else if (resultProduct[3] == 57){
client.publish("JURAF90/aroma/state", "STRONG");
Serial.println(F("[INFO][JURA] Starkes Aroma"));
aroma_state = 57;
}
}
if(resultProduct != "" && resultProduct[4] != size_state){
if (resultProduct[4] == 56){
client.publish("JURAF90/size/state", "ESPRESSO");
Serial.println(F("[INFO][JURA] Espresso"));
size_state = 56;
}
else if (resultProduct[4] == 52){
Serial.println(F("[INFO][JURA] Kaffee"));
client.publish("JURAF90/size/state", "COFFEE");
size_state = 52;
}
else if (resultProduct[4] == 50){
Serial.println(F("[INFO][JURA] Big Cup"));
client.publish("JURAF90/size/state", "BIGCUP");
size_state = 50;
}
}
}
}
Btw: my source was this project in the beginning, but it wasn’t maintained anymore, so I started to do my own development. There are also different other github links I checked when started