Skip to content

Instantly share code, notes, and snippets.

@ayn
Last active October 29, 2026 00:03
Show Gist options
  • Select an option

  • Save ayn/a8b9a344197ed235a4ac2719d2203340 to your computer and use it in GitHub Desktop.

Select an option

Save ayn/a8b9a344197ed235a4ac2719d2203340 to your computer and use it in GitHub Desktop.
brew by weight automation (micra x lunar x homeasistant)
# Micra + Acaia Lunar brew by weight, exported from the current automation.
# Replace binary_sensor.micra_brewing_active and switch.micra with your entities.
# switch.micra must be the machine power control, not a pump-only switch.
# Required scale entities: sensor.lunar_weight (g),
# sensor.lunar_volume_flow_rate (HA reports mL/s; treated as approximately g/s).
# Required helpers: input_number.spro_target_weight (g),
# input_number.spro_cutoff_offset (SECONDS of lead time, not grams).
# Required mode helper: input_boolean.micra_soup_mode (on = Soup, off = Spro).
# Set target yield separately, e.g. 80g for Soup or 45g for Spro.
# Current lead time is 2.5 seconds, configured in spro_cutoff_offset.
# Compensation = flow x lead time, with a 1.5g minimum and mode-dependent cap:
# Soup: 24g maximum; Spro: 12g maximum. These caps are not fixed offsets.
# Tune the lead time against actual final yield for your setup.
# No input_number.spro_cutoff_seconds helper is used by this version.
# IMPORTANT: The 2-minute timeout aborts without switching the machine off.
# This is not a safety shutoff; supervise brewing and stop manually if needed.
#
# HOW IT WORKS
# 1. The Micra brewing-active sensor starts this automation.
# 2. While brewing, weight and flow updates re-evaluate the cutoff condition.
# Flow estimates how much more liquid will arrive during the stopping delay.
#
# predicted_extra_g = flow_g_per_second * lead_seconds
# cap_g = 24 if Soup mode is on, otherwise 12
# compensation_g = min(max(predicted_extra_g, 1.5), cap_g)
# cutoff_weight_g = target_weight_g - compensation_g
#
# Send the power-off command when current_weight_g >= cutoff_weight_g.
# Compensation is recalculated as flow changes; it is not a fixed subtraction.
# The 1.5g floor reserves a little room even when measured flow is low.
# The cap limits how far ahead the automation can request a stop.
#
# Soup example: target 80g, flow 7.28g/s, lead 2.5s
# predicted extra = 7.28 * 2.5 = 18.2g
# compensation = min(max(18.2, 1.5), 24) = 18.2g
# request cutoff at 80 - 18.2 = 61.8g
# Spro example: target 45g, flow 3g/s, lead 2.5s
# compensation = min(max(3 * 2.5, 1.5), 12) = 7.5g
# request cutoff at 45 - 7.5 = 37.5g
#
# 3. Power off stops the pump; the automation waits 1.5s, then restores power.
# That 1.5s off period is separate from the predictive lead time above.
# Returning the brew paddle to its normal position is still a manual step.
#
# Lead time approximates scale/BLE updates, command latency, and residual flow.
# It predicts final yield, rather than guaranteeing it, especially with cloud
# latency or rapidly changing flow. Increase lead for overshoot; decrease for
# undershoot, provided compensation is not already limited by its floor or cap.
# No automatic calibration or learning is performed.
# Invalid/unavailable weight or flow readings currently fall back to zero.
# If the scale is disconnected, this does NOT provide a reliable automatic stop.
# Tare the cup before brewing so the target refers to beverage weight.
#
alias: Brew by Weight
description: >-
Cuts power to the Micra when the Lunar scale weight reaches the target,
predicting cutoff via current flow rate to absorb BLE/relay latency and
residual pressure flow. Soup mode allows up to 24g of predictive compensation;
Spro retains a 12g cap. Restores power after 1.5 seconds.
triggers:
- trigger: state
entity_id: binary_sensor.micra_brewing_active
to: "on"
actions:
- action: logbook.log
data:
name: Brew by Weight
message: >-
Brew started - target {{ states('input_number.spro_target_weight') }}g,
lead {{ states('input_number.spro_cutoff_offset') }}s
entity_id: binary_sensor.micra_brewing_active
- wait_for_trigger:
- platform: template
value_template: >-
{% set w = states('sensor.lunar_weight') | float(0) %}
{% set f = states('sensor.lunar_volume_flow_rate') | float(0) %}
{% set target = states('input_number.spro_target_weight') | float(38) %}
{% set lead = states('input_number.spro_cutoff_offset') | float(2.0) %}
{% set cap = 24.0 if is_state('input_boolean.micra_soup_mode', 'on') else 12.0 %}
{% set offset = [[f * lead, 1.5] | max, cap] | min %}
{{ w >= (target - offset) }}
timeout: "00:02:00"
continue_on_timeout: false
- action: logbook.log
data:
name: Brew by Weight
message: >-
Cutting pump @ {{ states('sensor.lunar_weight') }}g
(target {{ states('input_number.spro_target_weight') }}g,
flow {{ states('sensor.lunar_volume_flow_rate') | float(0) | round(2) }}g/s,
lead {{ states('input_number.spro_cutoff_offset') }}s)
entity_id: sensor.lunar_weight
- action: switch.turn_off
target:
entity_id: switch.micra
- delay: "00:00:01.5"
- action: switch.turn_on
target:
entity_id: switch.micra
mode: restart
@ayn

ayn commented Apr 9, 2025

Copy link
Copy Markdown
Author

the brewing_active condition has been disabled as that sensor is unavailable since new LM app/gw firmware.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment