After searching lots and finding little, I figured that there is value in sharing my project here for others to use and hopefully, help develop.
The driver for this project is that I wanted a yoghurt / yogurt maker that met the criteria for making some large batches of probiotic yoghurt. For those interested in the health and science, read the book ‘Super Gut’ by Dr. William Davis.
- Must be able to run continuously, unattended, for up to 48 hours,
- Must be able to heat as low as 95F
- Must be able to handle a single batch of 2 quarts
- Must not be expensive
I found zero products that were available and fit the requirements so I figured I’d set about building one as a prototype. I looked at what was available and as with most first-cut prototypes, I wanted it as cheap as possible. I bought the Euro Cuisine YM80 yoghurt maker from Amazon along with the additional tier to raise capacity. It comes with tiny jars for making different flavours of ‘normal’ yoghurt but they are no use to me. The additional tier has a moulded holder for more jars that I may need to cut out. I will be just using a single Ziplock tub or maybe mason jars in there.
The device has what I needed but couldn’t easily make; a housing and a heater. The device as received has a switch, a power light and a heater plate. There is no temperature control or timer control so I needed to add those.
I pulled off the rubber feet and used an S2 T20 security Torx bit to remove the 4 screws. The inner plastic pan then comes off to reveal the heat plate and wiring. Now for the interesting stuff…
I used a Wemos D1 esp8266 as the controller, a Dallas DS18B20 temperature sensor, a dual 5v relay board and an SH1106 128x64 (ssd1306_i2c) OLED screen I had in my parts bin.
I added a generic thermostat component to my Home Assistant configuration.yaml and also added an automation helper timer entity. The timer is used in an automation routine to trigger the timer relay as that was the first way that I figured out how to get it to work. The thermostat function works to read the Dallas temperature, set the desired temperature for the unit and control the units heater relay depending on the difference between the two.
Challenges I had:
Screen and display code:-
The first issue I has was that I hadn’t used an OLED before so I needed to figure that out. I determined that it was an ssd1306 driver and i2c as it only had vcc, gnd, slk and sda pins. I just got noise on the screen until I figured out that I needed to set the model, which in my case was sh1106. Once I set that, the screen noise was gone and I could play with the text and font stuff. Again, I couldn’t work out how to make the fonts work and a lot of the forum posts seem to assume knowledge of this. In short, I learned by grabbing a simple font like Arial.ttf, getting the .ttf download and putting it in /config/esphome. Once there, the code will reference it and it is then just about playing with screen position and font size to make it look right for you. I posted here and got some solid help that allowed me to make progress. I was struggling to format the code to get the HA set temperature value to display on the screen.
Power:-
There isn’t a practical way to convert 110v to 5v in a small form factor that will fit inside the YM80. The heat plate is 110v (or 240v for the EU models) so I chose to just run a microUSB cable from the Wemos. At first, I was going to use a power cable but instead went with a microUSB to USB-A cable so that I could reflash the Wemos in the event that it wouldn’t OTA flash. I have Unifi wifi hardware and there seems to be a bug in later ESPhome firmware that causes issues with connecting.
Display mounting:-
Its a prototype so it can look clunky but, there isn’t a flat surface that the screen can be mounted on to look nice. I just hot-glued the screen to the outside to cover over the power switch hole.
Issues and work still remaining:
I noticed that the temperature swing is a lot wider than I can accept. Ideally, I want the internal temperature of the unit to remain within 1F. The climate code handles this and I need to look further into why I am getting the deep cooling swings.
Any suggestions welcome.
I also think that the code can be cleaned up. I’m not a natural dev so my code ends up being what works from the snippets I can find when I search for solutions to problems that I’m having. In particular, I appreciate that there may be several ways to achieve the same goal and I’m not certain that I’m using the most efficient solution.
The timer function isn’t as stylish as I want it to be. It works but in the same way that red tuck tape works for that broken back light on your truck.
ESP Code:
esphome:
name: esp8266-yoghurtmaker
comment: ESPhome comment here
esp8266:
board: d1_mini
framework:
version: recommended
logger:
wifi:
manual_ip:
static_ip: 192.168.10.XXX
gateway: 192.168.10.1
subnet: 255.255.255.0
dns1: 192.168.10.1
dns2: 0.0.0.0
ap:
ssid: "Fallback-yoghurtmaker"
password: ""
ap_timeout: 1min
domain: .local
reboot_timeout: 15min
power_save_mode: NONE
fast_connect: false
output_power: 20.0
networks:
- ssid: !secret wifi_iot_ssid
password: !secret wifi_iot_password
priority: 0.0
use_address: 192.168.10.XXX
captive_portal:
api:
password: !secret api_password
port: 6053
reboot_timeout: 15min
ota:
password: !secret ota_password
safe_mode: true
port: 8266
font:
- file: 'arlrdbd.ttf'
id: font1
size: 30
dallas:
- pin: D5 #GPIO14
update_interval: 15s
i2c:
sda: D2
scl: D1
display:
- platform: ssd1306_i2c
model: "SH1106 128x64"
reset_pin: D0 #GPIO16
address: 0x3C
lambda: |-
it.printf(0, 0, id(font1), "T: %.1f F", id(yoghurt_maker_temperature).state);
it.printf(0, 30, id(font1), "S: %.0f F", id(ym_settemp).state);
switch:
- platform: restart
name: Yoghurt Maker Restart
- platform: gpio
pin:
number: D6 #GPIO12
inverted: yes
restore_mode: Restore_Default_Off
name: "Yoghurt Maker Heater"
id: yoghurt_maker_heater
- platform: gpio
pin:
number: D7 #GPIO13
inverted: yes
restore_mode: Restore_Default_Off
name: "Yoghurt Maker Timer"
id: yoghurt_maker_timer
sensor:
- platform: dallas
address: 0x773c01b5567fxxxx
name: "Yoghurt Maker Temperature"
id: yoghurt_maker_temperature
device_class: "temperature"
state_class: "measurement"
unit_of_measurement: "ºF"
accuracy_decimals: 1
filters:
- filter_out: nan
- lambda: return x * (9.0/5.0) + 32.0;
- platform: homeassistant
id: ym_settemp
entity_id: climate.ha_ym_interface
attribute: temperature
binary_sensor:
- platform: status
name: "Yoghurt Maker Status"
HA configuration.yaml code:
climate:
- platform: generic_thermostat
name: "HA YM Interface"
unique_id: ha_ym_interface
heater: switch.yoghurt_maker_heater
target_sensor: sensor.yoghurt_maker_temperature
min_temp: 50
max_temp: 150
hot_tolerance: 1
min_cycle_duration:
seconds: 5
keep_alive:
seconds: 30
initial_hvac_mode: "off"
precision: 1.0
Dashboard code:
type: vertical-stack
cards:
- type: thermostat
entity: climate.ha_ym_interface
name: Yoghurt Maker
- type: entities
entities:
- entity: sensor.ym_settemp
name: Set Temp
icon: mdi:thermometer-lines
- entity: sensor.yoghurt_maker_temperature
name: Internal Temp
- entity: timer.ym_timer
name: Timer Status
- entity: switch.yoghurt_maker_heater
name: Heater Switch
icon: mdi:radiator
- entity: switch.yoghurt_maker_timer
name: Timer Switch
icon: mdi:timer-sand-complete
- entity: binary_sensor.yoghurt_maker_status
name: Status
state_color: true
I might post some pics of the unit later once I clear up my workspace. If anyone has improvement suggestions for the device or the code, let 'er rip!