Skip to content
This repository has been archived by the owner on Jun 30, 2021. It is now read-only.

Commit

Permalink
Support for making custom coffee
Browse files Browse the repository at this point in the history
  • Loading branch information
COM8 committed Oct 7, 2020
1 parent 2a17cd8 commit f774051
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 15 deletions.
74 changes: 73 additions & 1 deletion .vscode/settings.json
Expand Up @@ -29,6 +29,78 @@
],
"files.associations": {
"*.pyx": "python",
"string_view": "cpp"
"string_view": "cpp",
"array": "cpp",
"atomic": "cpp",
"strstream": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"cinttypes": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"netfwd": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"string": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"shared_mutex": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp"
}
}
5 changes: 3 additions & 2 deletions README.md
Expand Up @@ -210,11 +210,12 @@ The following list of commands has been tested on an `Jura E6 2019 platin (15326
* `FN:08` # Grind off
* `FN:22` # Brew group to brewing position
* `FN:0B` # Coffee press on
* Sleep 0.5 seconds # Compress the coffee
* `FN:0C` # Coffee press off
* `FN:03` # Turn on the coffee water heater
* `FN:01` # Coffee pump on
* `FN:01` # Coffee water pump on
* Sleep 40 seconds # 40 seconds of water result in 200 ml of coffee
* `FN:02` # Coffee pump off
* `FN:02` # Coffee water pump off
* `FN:04` # Turn off the coffee water heater
* `FN:0D` # Reset the brew group and throw out the old coffee grain

Expand Down
10 changes: 4 additions & 6 deletions esp32/main/Esp32Jura.hpp
@@ -1,8 +1,8 @@
#pragma once

// #define MODE_SNOOPER
// #define MODE_COFFEE_MAKER
#define MODE_BRIDGE
#define MODE_COFFEE_MAKER
// #define MODE_BRIDGE
// #define MODE_SERIAL
// #define MODE_XMPP

Expand All @@ -11,6 +11,7 @@
#include <memory>

#include "esp/Storage.hpp"
#include "esp/sensor/Button.hpp"

#ifdef MODE_SNOOPER
#include "jura/JuraSnooperTask.hpp"
Expand All @@ -19,7 +20,6 @@
#include "jura/CoffeeMakerTask.hpp"
#endif // MODE_COFFEE_MAKER
#ifdef MODE_BRIDGE
#include "esp/sensor/Button.hpp"
#include "utils/SerialJuraBridgeTask.hpp"
#endif // MODE_BRIDGE
#ifdef MODE_SERIAL
Expand All @@ -28,7 +28,6 @@
#ifdef MODE_XMPP
#include "esp/WifiTask.hpp"
#include "esp/actuator/RgbLed.hpp"
#include "esp/sensor/Button.hpp"
#include "xmpp/XmppTask.hpp"
#endif // MODE_XMPP

Expand All @@ -46,6 +45,7 @@ void app_main(void);
class Esp32Jura : public smooth::core::Application {
private:
std::shared_ptr<esp::Storage> storage;
esp::sensor::Button resetButton{GPIO_NUM_13};

#ifdef MODE_SNOOPER
jura::JuraSnooperTask snooper{};
Expand All @@ -55,7 +55,6 @@ class Esp32Jura : public smooth::core::Application {
#endif // MODE_COFFEE_MAKER
#ifdef MODE_BRIDGE
utils::SerialJuraBridgeTask bridge{};
esp::sensor::Button resetButton{GPIO_NUM_13};
#endif // MODE_BRIDGE
#ifdef MODE_SERIAL
serial::SerialConnectionTask serialConnection{};
Expand All @@ -64,7 +63,6 @@ class Esp32Jura : public smooth::core::Application {
std::shared_ptr<esp::actuator::RgbLed> rgbLed{};
std::unique_ptr<xmpp::XmppTask> xmpp{};
std::shared_ptr<esp::WifiTask> wifiTask{};
esp::sensor::Button resetButton{GPIO_NUM_13};
#endif // MODE_XMPP

public:
Expand Down
47 changes: 46 additions & 1 deletion esp32/main/jura/CoffeeMaker.cpp
Expand Up @@ -4,6 +4,7 @@
#include <iomanip>
#include <iostream>
#include <limits>
#include <string>
#include <thread>

#include "JuraCommands.hpp"
Expand Down Expand Up @@ -97,10 +98,54 @@ void CoffeeMaker::press_button(jura_button_t button) {
break;
}

// Give the coffee maker to to react:
// Give the coffee maker time to react:
std::this_thread::sleep_for(std::chrono::milliseconds{500});
}

void CoffeeMaker::brew_custom_coffee(const std::chrono::milliseconds grindTime, const std::chrono::milliseconds waterTime) {
std::cout << "Brewing custom coffee with " << std::to_string(grindTime.count()) << " ms grind time and " << std::to_string(waterTime.count()) << " ms water time...\n";

// Grind:
std::cout << "Custom coffee grinding...\n";
write_and_wait(JURA_GRINDER_ON);
std::this_thread::sleep_for(grindTime);
write_and_wait(JURA_GRINDER_OFF);
write_and_wait(JURA_BREW_GROUP_TO_BREWING_POSITION);

// Compress:
std::cout << "Custom coffee compressing...\n";
write_and_wait(JURA_COFFEE_PRESS_ON);
std::this_thread::sleep_for(std::chrono::milliseconds{500});
write_and_wait(JURA_COFFEE_PRESS_OFF);

// Brew step 1:
std::cout << "Custom coffee brewing...\n";
write_and_wait(JURA_COFFEE_WATER_HEATER_ON);
write_and_wait(JURA_COFFEE_WATER_PUMP_ON);
std::this_thread::sleep_for(std::chrono::milliseconds{2000});
write_and_wait(JURA_COFFEE_WATER_PUMP_OFF);
write_and_wait(JURA_COFFEE_WATER_HEATER_OFF);
std::this_thread::sleep_for(std::chrono::milliseconds{2000});

// Brew setp 2:
write_and_wait(JURA_COFFEE_WATER_HEATER_ON);
write_and_wait(JURA_COFFEE_WATER_PUMP_ON);
std::this_thread::sleep_for(waterTime);
write_and_wait(JURA_COFFEE_WATER_PUMP_OFF);
write_and_wait(JURA_COFFEE_WATER_HEATER_OFF);

// Reset:
std::cout << "Custom coffee finishing up...\n";
write_and_wait(JURA_BREW_GROUP_RESET);
std::cout << "Custom coffee done.\n";
}

bool CoffeeMaker::write_and_wait(const std::string s) {
connection.flush_read_buffer();
connection.write_decoded(s);
return connection.wait_for_ok();
}

//---------------------------------------------------------------------------
} // namespace esp32jura::jura
//---------------------------------------------------------------------------
11 changes: 11 additions & 0 deletions esp32/main/jura/CoffeeMaker.hpp
@@ -1,5 +1,6 @@
#pragma once

#include <chrono>
#include <map>
#include <string>
#include <vector>
Expand Down Expand Up @@ -74,6 +75,12 @@ class CoffeeMaker {
* Brews the given coffee and switches to the appropriate page for this.
**/
void brew_coffee(coffee_t coffee);
/**
* Brews a custom coffee with the given grind and water times.
* A default coffee on a JURA E6 (2019) grinds for 3 seconds and then lets the water run for 40 seconds (200 ml).
* This corresponds to a water flow rate of 5 ml/s.
**/
void brew_custom_coffee(const std::chrono::milliseconds grindTime = std::chrono::milliseconds{3000}, const std::chrono::milliseconds waterTime = std::chrono::milliseconds{40000});
/**
* Simulates a button press of the given button.
**/
Expand All @@ -89,6 +96,10 @@ class CoffeeMaker {
* Returns the button number for the given coffee type.
**/
jura_button_t get_button_num(coffee_t coffee);
/**
* Writes the given string to the coffee maker and waits for an "ok:\r\n"
**/
bool write_and_wait(const std::string s);
};
//---------------------------------------------------------------------------
} // namespace esp32jura::jura
Expand Down
9 changes: 5 additions & 4 deletions esp32/main/jura/CoffeeMakerTask.cpp
Expand Up @@ -11,9 +11,9 @@ namespace esp32jura::jura {
CoffeeMakerTask::CoffeeMakerTask() : Task("Coffee Task", 0, smooth::core::APPLICATION_BASE_PRIO, std::chrono::milliseconds(100), 1), button(BUTTON_SIGNAL) {}

void CoffeeMakerTask::init() {
std::cout << "Initializing coffee maker...\n";
std::cout << "Initializing coffee maker task...\n";
coffeeMaker.init();
std::cout << "Coffee maker initialized.\n";
std::cout << "Coffee maker task initialized.\n";
}

void CoffeeMakerTask::tick() {
Expand All @@ -30,7 +30,7 @@ void CoffeeMakerTask::write() {
if (!buttonPressed) {
buttonPressed = true;

std::stringstream stream;
/*std::stringstream stream;
stream << std::setfill('0') << std::setw(2) << std::uppercase;
stream << std::hex << buttonCounter;
// std::string msg = "RT:" + stream.str();
Expand All @@ -42,7 +42,8 @@ void CoffeeMakerTask::write() {
msg += +"\r\n";
coffeeMaker.connection.write_decoded(msg);
}
++buttonCounter;
++buttonCounter;*/
coffeeMaker.brew_custom_coffee();
}
} else {
buttonPressed = false;
Expand Down
12 changes: 12 additions & 0 deletions esp32/main/jura/JuraCommands.hpp
Expand Up @@ -17,6 +17,18 @@ const std::string JURA_BUTTON_3 = "FA:06\r\n";
const std::string JURA_BUTTON_4 = "FA:07\r\n";
const std::string JURA_BUTTON_5 = "FA:08\r\n";
const std::string JURA_BUTTON_6 = "FA:09\r\n";

const std::string JURA_BREW_GROUP_TO_BREWING_POSITION = "FN:22\r\n";
const std::string JURA_BREW_GROUP_RESET = "FN:0D\r\n";

const std::string JURA_GRINDER_ON = "FN:07\r\n";
const std::string JURA_GRINDER_OFF = "FN:08\r\n";
const std::string JURA_COFFEE_PRESS_ON = "FN:0B\r\n";
const std::string JURA_COFFEE_PRESS_OFF = "FN:0C\r\n";
const std::string JURA_COFFEE_WATER_HEATER_ON = "FN:03\r\n";
const std::string JURA_COFFEE_WATER_HEATER_OFF = "FN:04\r\n";
const std::string JURA_COFFEE_WATER_PUMP_ON = "FN:01\r\n";
const std::string JURA_COFFEE_WATER_PUMP_OFF = "FN:02\r\n";
//---------------------------------------------------------------------------
} // namespace esp32jura::jura
//---------------------------------------------------------------------------
21 changes: 20 additions & 1 deletion esp32/main/jura/JuraConnection.cpp
@@ -1,6 +1,5 @@
#include "JuraConnection.hpp"

#include <chrono>
#include <cstdio>
#include <iostream>
#include <string>
Expand Down Expand Up @@ -218,6 +217,26 @@ size_t JuraConnection::read_encoded(std::vector<std::array<uint8_t, 4>>& data) {
return read_encoded(data);
}

bool JuraConnection::wait_for_ok(const std::chrono::milliseconds timeout) {
std::vector<uint8_t> buffer;

std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
while ((timeout.count() <= 0) || ((std::chrono::steady_clock::now() - start) < timeout)) {
if (read_decoded(buffer)) {
for (size_t i = 0; (buffer.size() >= 5) && (i < buffer.size() - 4); i++) {
if (buffer[i] == 'o' && buffer[i + 1] == 'k' && buffer[i + 2] == ':' && buffer[i + 3] == '\r' && buffer[i + 4] == '\n') {
return true;
}
buffer.clear();
}
}
std::this_thread::sleep_for(std::chrono::milliseconds{250});
}
return false;
}

void JuraConnection::flush_read_buffer() { uart_flush(UART_PORT); }

//---------------------------------------------------------------------------
} // namespace esp32jura::jura
//---------------------------------------------------------------------------
13 changes: 13 additions & 0 deletions esp32/main/jura/JuraConnection.hpp
@@ -1,6 +1,7 @@
#pragma once

#include <array>
#include <chrono>
#include <string>
#include <vector>

Expand Down Expand Up @@ -65,6 +66,18 @@ class JuraConnection {
* Each data byte consists of 4 JURA bytes which will be decoded into a single data byte.
**/
bool read_decoded(std::vector<uint8_t>& data);
/**
* Waits until the coffee maker responded with a "ok:\r\n".
* The default timeout for this operation is 5 seconds.
* To disable the timeout, set the timeout to 0 seconds.
* Returns true on success.
* Returns false when a timeout occurred.
**/
bool wait_for_ok(const std::chrono::milliseconds timeout = std::chrono::milliseconds{5000});
/**
* Flushes the read buffer.
**/
void flush_read_buffer();

/**
* Encodes the given byte into 4 JURA bytes and writes them to the coffee maker.
Expand Down

0 comments on commit f774051

Please sign in to comment.