Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
a87653e
add webserver
tadelv Oct 27, 2024
fe08e88
wip
tadelv Oct 27, 2024
c5ce807
Merge branch 'main' into develop
tadelv Jan 18, 2025
51e18b6
add moving average to RoR
tadelv Jan 18, 2025
c367a22
conditionally include wifi credentials
tadelv Jan 18, 2025
8365991
add wifi api
tadelv Jan 18, 2025
c0aa38f
wifi setup
tadelv Jan 19, 2025
4f590e6
add wifi to main page
tadelv Jan 19, 2025
fa36c2f
cleanup
tadelv Jan 19, 2025
fdbee2b
replace Kalman with moving average and increase temp sampling rate
tadelv Jan 20, 2025
89b6374
figure out time scale
tadelv Jan 20, 2025
437352c
tooltip improvements
tadelv Jan 20, 2025
ba77e36
Added BOM for PCB population
dlisec Jan 24, 2025
2e43e9d
additional handling when setting wifi settings
tadelv Jan 20, 2025
0111128
ramp to target fan value
tadelv Jan 24, 2025
6c7455d
add build script
tadelv Jan 25, 2025
6e8d828
minimum readme update
tadelv Jan 25, 2025
7292ea9
replace ET with BT for RoR calculation
tadelv Jan 26, 2025
77410b7
fix BT RoR
tadelv Jan 27, 2025
5e8c6cd
fix wifi switch from STA to AP
tadelv Jan 28, 2025
3c58fee
Added PCB files for ESP-S3, rounded corners for both boards, addition…
dlisec Feb 23, 2025
cfc96e5
wip
tadelv Mar 6, 2025
91c43b6
add pid
tadelv Mar 7, 2025
8b291a1
add setpoint to chart
tadelv Mar 8, 2025
cc2de55
add pid target picker
tadelv Mar 8, 2025
763c707
storing pid data for each measurement
tadelv Mar 8, 2025
8e91e67
wip
tadelv Mar 15, 2025
ac310e0
wip
tadelv Mar 15, 2025
96e6ff9
Merge pull request #6 from tadelv/chore/ror-qol-improvements
tadelv Mar 15, 2025
a50d1a2
Added instructions to .ini
matthew73210 Mar 16, 2025
dec77fe
Added usage comments to build sh
matthew73210 Mar 16, 2025
17ad37f
Added to readme and fixed linting
matthew73210 Mar 16, 2025
b84a773
Redid script
matthew73210 Mar 16, 2025
2078894
Added comments to script and removed commenting from ini
matthew73210 Mar 16, 2025
8ba829d
added grin to readme
matthew73210 Mar 16, 2025
46abb6a
added to gitignore
matthew73210 Mar 16, 2025
fec2357
Merge pull request #8 from matthew73210/docs
tadelv Mar 16, 2025
58fce60
Added fig gen and example .json file for render
matthew73210 Mar 16, 2025
853b8b9
Moved stuff arround and add pdm stuff
matthew73210 Mar 16, 2025
1cd0ba8
Added guide
matthew73210 Mar 16, 2025
fbc380b
Linting
matthew73210 Mar 16, 2025
d403eb7
Merge pull request #2 from matthew73210/fig_gen
matthew73210 Mar 16, 2025
eaab18d
Merge pull request #9 from matthew73210/develop
tadelv Mar 16, 2025
bafc48f
wip profile following
tadelv Mar 15, 2025
ede4547
wip
tadelv Mar 15, 2025
3e4e8cd
add profile upload and state var
tadelv Mar 15, 2025
78602f0
add toggle for following profile
tadelv Mar 16, 2025
034637a
add ease-in-out profile interpolation
tadelv Mar 16, 2025
fa9e4ed
show profile name, check json is actually profile
tadelv Mar 16, 2025
33fb9e7
Merge pull request #10 from tadelv/feature/profile
tadelv Mar 16, 2025
beba6ed
add profile example to readme
tadelv Mar 16, 2025
e324aa4
"gui" improvements
tadelv Mar 17, 2025
93004ac
increase sampling window duration
tadelv Apr 3, 2025
f29c611
only log msg type for unhandled event
tadelv Apr 5, 2025
5e9765c
fix typo in platformio
tadelv Apr 5, 2025
011a29d
minor cleanup
tadelv Apr 6, 2025
72dc254
Merge pull request #12 from tadelv/feature/firmware-hardening
tadelv Apr 6, 2025
bd588f3
Merge branch 'main' into develop
tadelv Apr 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ node_modules
**/.DS_Store
local.config.ts
data/
Credentials.h
Binary file added PCB/YaegerS3.zip
Binary file not shown.
Binary file added PCB/YaegerS3Mini.zip
Binary file not shown.
21 changes: 21 additions & 0 deletions PCB/YaegerV01BOM_FULL.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Reference,Manufacturer part number,Description,Qty
"J1,J13",61300411121,"Male vertical header 4 position, used for LCD and PWM",2
"J2,J5,J6,J7,J8,J9",2376591-2,Terminals for high voltage,6
"J3,J4",PPTC061LFBN-RC,"Female header 6 position, used for thermocouple boards",2
PS1,IRM-10-3.3,AC DC converter 3.3V,1
J10,22035025,"2 Pin header for SSR connection, Molex",1
,2196762125,"Cable with crimped ends for 50375023 housing, 450mm",2
,50375023,Connector housing for 2196762125,1
,PPTC041LFBN-RC,"Female header 4 position, used for PWM ",1
,,,
,MAX31855 K Type Thermocouple Breakout Board,https://www.aliexpress.com/item/1005006381598473.html,2
,PWM for fan control,https://www.aliexpress.com/item/1005006457613501.html,1
,SSR for heater control,https://www.aliexpress.com/item/4000045425145.html,1
,,,
,,,
,ESP32-S3 Mini,https://www.aliexpress.com/item/1005006177646698.html,1
"J11,J12",PPPC102LFBN-RC,"Female header 20 position, used for S3 Mini",2
,,,
,,,
,ESP32-S3,https://www.aliexpress.com/item/1005006266375800.html,1
U1,PPTC221LFBN-RC,"Female header 22 position, used for S3",2
74 changes: 59 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,72 +1,116 @@
# Yaeger

![yaeger logo](./assets/logo.webp)

## Yet another embedded gourmet experience roaster
### or something like that

### or something like that

## The gist

Yaeger is an embedded computer that takes control of your "coffee roaster" via Artisan-Scope.
It currently supports reading data from two temperature probes as well as controlling a fan and pulsing a heater.

### Primary goal

Is to use an old popcorn popper you have gathering dust in your basement and modifying it into a sample roaster for
roasting small batches of coffee at a time.

### Suported hardware:
### Suported hardware

Comment on lines +19 to 20
Copy link

Copilot AI Apr 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct 'Suported' to 'Supported' to fix the typo.

Suggested change
### Suported hardware
### Supported hardware

Copilot uses AI. Check for mistakes.
* [ESP32-S3 (devkit-1)](https://www.aliexpress.com/item/1005006266375800.html) or an [S3-mini](https://www.aliexpress.com/item/1005006177646698.html)
* 1 or 2 [MAX31855](https://www.aliexpress.com/item/1005006381598473.html) thermocouple chips
* 1 [DC pwm capable dimmer](https://www.aliexpress.com/item/1005006457613501.html) for the fan (must support 3.3v control)
* 1 DC controlled [AC SSR](https://www.aliexpress.com/item/4000045425145.html) for controling the heating element (same as above)


### Other required hardware for the build:
### Other required hardware for the build

* 18V DC PSU for driving the fan (be careful how you wire this)
* regular wire K-type thermocouple probe (the one that comes with your multimeter)
* flexible K-type thermocouple probe, 1x50/1.5x50 (sometimes difficult to source, they come and go on aliexpress, search for
flexible thermocouple 1x100 - this usually works)
flexible thermocouple 1x100 - this usually works).

### NOTE

**NOTE**
We don't have enough data if there is enough difference between ET and BT to justify two thermocouples. You might use
just one.
just one.

#### Optional upgrades:
#### Optional upgrades

* 24V DC PSU for more fan power

### Command and control


Upon first launch, Yaeger will set up its own access point. You can then configure the preferred wifi for Yaeger to
connect to from the Web UI (see below). After setting up the preffered Wifi, Yaeger will try to connect to it on every
boot. If it can't connect to the preffered Wifi, Yaeger will fallback to its own access point (so you can set up Wifi
again).
This repo also includes a sample config for Artisan-Scope.
This repo also includes a sample config for Artisan-Scope.

#### Artisan Scope
Load the config, found in `./artisan-settings.aset` into Artisan-Scope, change the server ip to match yours and click the on button.

Load the config, found in `./artisan-settings.aset` into Artisan-Scope, change the server ip to match yours and click the on button.

#### Web interface

You can also control Yaeger from its own web interface without an app. Just point your browser to `yaeger.local` when on
your home wifi, or `192.168.4.1` if Yaeger creates its own access point.
![yaeger webui](./assets/yaeger-webui.png)

#### Using Yaeger on the go
If Yaeger can't connect to your preferred Wifi, it will create its own access point. Perfect for when out and about :)

If Yaeger can't connect to your preferred Wifi, it will create its own access point. Perfect for when out and about :grin:

## Build guide (WIP)

### Schema

![schema](./schema/Schematic_Yaeger_2024-12-24.svg)

Additional info for the v1 pcb can be found in the schema folder, along with a BOM for the pcb. Courtesy of [@dlisec](https://github.com/dlisec)
Kicad projects for the S3 and S3 mini versions of the PCB, can be found in the PCB folder, along with a BOM for the pcb.

Courtesy of [@dlisec](https://github.com/dlisec)

### Building and flashing

A build script has been provided by [@matthew73210](https://github.com/matthew73210), so to get up and running on the
ESP, just run `./build_and_flash.sh`.
ESP, just run `./build_and_flash.sh`. Make sure to read the comments in the script. But also in the platformio.ini and choose the right board

## Latest features

### PID

PID temp follower, set the temperature setpoint and the PID controller will try and follow. You'll need to find your own PID values

### Profile

Still in the works, but there is now a profile follower, it follows a simple .json format. You can have a go at [Gaggiuino web profiler](https://matthew73210.github.io/Gaggiuino-web-profiler/) under the _pun_ "Yägermeister Mode"


#### An example of a roast profile

```
{
"steps": [
{
"duration": 10,
"setpoint": 40,
"interpolation": "linear"
},
{
"duration": 360,
"setpoint": 217,
"interpolation": "ease-out"
}
]
}
```

## Disclaimer

# Disclaimer
Be careful when messing about with electronics and high voltage. I can not and will not take any responsibility for any
sort of damage or injury caused by Yaeger, either directly or indirectly.
**You do this at your own risk**
### You have been warned!

## You have been warned
41 changes: 36 additions & 5 deletions build_and_flash.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
#!/bin/bash

# The script will build and flash Yaeger to your ESP device.
# Ensure this script is executable (`chmod +x build_and_flash.sh`) and has the correct permissions.
#
# Usage:
# ./build_and_flash.sh <s3 | s3-mini>
#
# Example:
# ./build_and_flash.sh s3 # For ESP32-S3
# ./build_and_flash.sh s3-mini # For ESP32-S3 Mini
#
# If you cloned the project from GitHub, ensure all folders have the correct permissions:
# chmod -R u+rwX .
# The SPIFFS filesystem might fail if permissions are incorrect.

# Step 0: Check for required parameter (s3 or s3-mini)
if [[ -z "$1" ]]; then
echo "Usage: $0 <s3 | s3-mini>"
exit 1
fi

PIO_ENV="esp32-$1"

# Validate the provided environment
if [[ "$PIO_ENV" != "esp32-s3" && "$PIO_ENV" != "esp32-s3-mini" ]]; then
echo "Invalid argument: '$1'. Use 's3' or 's3-mini'."
exit 1
fi

echo "Using PlatformIO environment: $PIO_ENV"

# Step 1: Navigate to the miniweb directory
echo "Navigating to miniweb..."
cd miniweb || { echo "miniweb folder not found!"; exit 1; }
Expand All @@ -14,18 +44,19 @@ npm run build || { echo "npm build failed!"; exit 1; }

# Step 4: Return to the project root
echo "Returning to the project root..."
cd .. || exit

# Step 5: Erase the device memory (optional, but recommended)
cd .. || exit 1

# Step 5: Erase the device memory (optional but recommended)
echo "Erasing the device memory..."
pio run -t erase || { echo "Memory erase failed!"; exit 1; }
pio run -e "$PIO_ENV" -t erase || { echo "Memory erase failed!"; exit 1; }

# Step 6: Build and upload the SPIFFS filesystem
echo "Building and uploading SPIFFS filesystem..."
pio run -t buildfs -t uploadfs || { echo "SPIFFS upload failed!"; exit 1; }
pio run -e "$PIO_ENV" -t buildfs -t uploadfs || { echo "SPIFFS upload failed!"; exit 1; }

# Step 7: Build and upload the firmware
echo "Building and uploading the firmware..."
pio run -t upload || { echo "Firmware build or upload failed!"; exit 1; }
pio run -e "$PIO_ENV" -t upload || { echo "Firmware build or upload failed!"; exit 1; }

echo "All tasks completed successfully!"
23 changes: 16 additions & 7 deletions miniweb/src/chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ export function initializeChart(ctx: CanvasRenderingContext2D): Chart {
},
y3: {
min: 0,
max: 10,
type: "logarithmic",
max: 60,
//type: "logarithmic",
},
},
responsive: true,
Expand All @@ -133,7 +133,7 @@ export function updateChart(chart: Chart, roast: RoastState) {
const beanTemps = measurements.map((el) => el.message.BT);
const envTemps = measurements.map((el) => el.message.ET);

const windowSize = 20;
const windowSize = 30;

// Helper to calculate rate of rise (RoR)
const calculateRoR = (temps: number[], times: number[]) =>
Expand All @@ -149,7 +149,7 @@ export function updateChart(chart: Chart, roast: RoastState) {
return values.map((val, i, arr) => {
if (val === null || i < size - 1) return val; // Skip if insufficient data
const window = arr.slice(i - size + 1, i + 1) as number[];
return window.reduce((sum, v) => sum + v, 0) / size;
return window.reduce((sum, v) => sum + v * 60, 0) / size;
});
};

Expand All @@ -165,7 +165,7 @@ export function updateChart(chart: Chart, roast: RoastState) {

// Add datasets to chart
chart.data.datasets[4] = {
label: "BT Rate of Rise (°C/s)",
label: "BT Rate of Rise (°C/min)",
borderColor: "green",
pointStyle: false,
data: btRor,
Expand All @@ -174,14 +174,24 @@ export function updateChart(chart: Chart, roast: RoastState) {
};

chart.data.datasets[5] = {
label: "ET Rate of Rise (°C/s)",
label: "ET Rate of Rise (°C/min)",
borderColor: "purple",
pointStyle: false,
data: etRor,
yAxisID: "y3",
tension: 0.2,
};

chart.data.datasets[6] = {
label: "Setpoint (°C)",
borderColor: "#03fc7b",
pointStyle: false,
data: roast.measurements.map((el) => el.extra?.setpoint ?? 0),
yAxisID: "y1",
tension: 0.1,

};

chart.data.datasets[3].data = roast.measurements.map(
(el) => el.message.BurnerVal,
);
Expand Down Expand Up @@ -234,7 +244,6 @@ const verticalLinePlugin = {

beforeDatasetsDraw: function (chart, easing) {
if (chart.config._config.lineAtIndex) {
console.log("doing ", chart.config._config.lineAtIndex);
chart.config._config.lineAtIndex.forEach((pointIndex) => {
this.renderVerticalLine(chart, pointIndex);
});
Expand Down
Loading