Custom Home Assistant integration for Grainfather cloud data, including brew sessions, fermentation devices, recipe images, and session controls.
If this project helps your brewing workflow, you can support development here:
- Config flow with Grainfather email and password
- Brew session entities with batch, gravity, style, recipe image, and batch variant data
- Recipe metric sensors per brew session: target ABV, IBU, color (SRM), calories, batch size, and boil time
- Extra brew-session sensors: pre-boil gravity, conditioning temperature/duration, fermentation volume, and priming sugar
- Recipe ingredients (fermentables, hops, yeasts, mash steps) exposed as attributes on a per-session recipe sensor
- Brew session attributes including
condition_date,fermentation_start_date, andcreated_at - Fermentation device temperature and gravity sensors, plus a target-temperature sensor for fermentation controllers
- History data exposed on brew session attributes
- Service actions for changing brew session status and fermentation steps
- Button and select helpers for common brew session actions
- Local integration branding assets for Home Assistant
2026.3+
- Open HACS.
- Add this repository as a custom repository of type
Integrationif it is not already listed. - Install
Grainfather. - Restart Home Assistant.
- Go to Settings > Devices & Services > Add Integration.
- Search for
Grainfatherand enter your Grainfather credentials.
- Copy custom_components/grainfather into your Home Assistant
custom_componentsdirectory. - Restart Home Assistant.
- Add the
Grainfatherintegration from Settings > Devices & Services.
The integration polls the Grainfather cloud API (with a state-aware adaptive interval, see Adaptive Polling) and exposes:
- Brew sessions
- Fermentation devices
- Fermentation history linked to devices and sessions
- Recipe images
The implementation is based on the API shape described in docs/api.md, including:
/api/auth/login/api/2/brew-sessions/api/equipment/fermentation-devices
See docs/api.md for the full Grainfather cloud API reference.
On every integration load, Grainfather history is imported into Home Assistant
Recorder as hourly external statistics. The import covers active and completed
batches and is repaired on later reloads; it does not depend on the
include_completed_sessions entity option.
Each batch with measurements can produce these statistic IDs:
grainfather:<entry_id>_batch_<batch_id>_temperature(°C)grainfather:<entry_id>_batch_<batch_id>_specific_gravity(SG)grainfather:<entry_id>_batch_<batch_id>_plato(°P)
<entry_id> is Home Assistant's slugged config-entry ID and <batch_id> is
the Grainfather brew-session ID. Use Developer Tools → Statistics to find
the exact IDs. Temperature, specific gravity, and Plato are stored as hourly
mean, minimum, and maximum values. Plato is calculated from SG using the same
one-decimal conversion as the live sensors.
A brew-session Batch Number entity is the canonical batch anchor. Its
status is fermenting and is_current_batch is true only for a current
charge. Its fermentation_devices attribute lists the currently linked
fermentation devices, while fermentation_device_ids preserves the API's
reported membership. The anchor exposes immutable temperature_statistic_id,
specific_gravity_statistic_id, and plato_statistic_id attributes for
history graphs.
Fermentation-device sensors represent live hardware only: temperature, gravity,
Plato, and controller target temperature where available. Each device also has
an Active Charge reference sensor while it is linked to a fermenting
session. Its state is the session or recipe name; brew_session_unique_id
always identifies the canonical Batch Number anchor and
brew_session_entity_id is provided when its Home Assistant entity ID is
available. It does not copy batch data. Multiple sessions may ferment
concurrently; each has its own canonical batch anchor.
Use a statistics-graph card to chart a completed fermentation:
type: statistics-graph
title: Batch fermentation
chart_type: line
period: hour
entities:
- "grainfather:<entry_id>_batch_<batch_id>_temperature"
- "grainfather:<entry_id>_batch_<batch_id>_plato"Replace the example statistic IDs with the values returned by the Statistics developer tool.
The Grainfather cloud API is REST-only, so the integration polls it on a schedule. Instead of a single fixed cadence, it uses state-aware adaptive polling:
- While a brew session is brewing or fermenting (or a fermentation controller is linked and was heard from recently), it polls at the faster active interval (default 60 s).
- Otherwise it polls at the slower idle interval (the
scan_intervaloption, default 300 s), which keeps load on the Grainfather cloud and Home Assistant low. - Right after you make a change (a service call or a number/select write), it performs an immediate refresh and briefly stays on the active interval so the change — and any device-side follow-up — shows up quickly.
Both intervals are clamped to 60–3600 s and are configurable under Settings > Devices & Services > Grainfather > Configure (the Idle update interval and Active update interval options). Entities update within Home Assistant as soon as a poll completes.
Each brew session becomes a Home Assistant device with the following sensors. Entity IDs
follow the pattern sensor.grainfather_<session>_<key>, where <session> is the slug Home
Assistant generates from the device name (for example sensor.grainfather_batch_01_ibu).
Look up the exact slugs under Settings > Devices & Services > Grainfather or in
Developer Tools > States (filter for grainfather).
Recipe metric sensors:
| Sensor key | Meaning | Unit |
|---|---|---|
target_abv |
Recipe target ABV | %vol |
ibu |
Bitterness | IBU |
color_srm |
Beer color | SRM |
calories |
Estimated calories | kcal |
batch_size |
Recipe batch size | litres |
boil_time |
Boil time | minutes |
Extra brew-session sensors:
| Sensor key | Meaning | Unit |
|---|---|---|
pre_boil_gravity |
Pre-boil gravity | (gravity) |
conditioning_temperature |
Conditioning temperature | °C |
conditioning_duration |
Conditioning duration | days |
ferment_volume |
Fermentation volume | litres |
priming_sugar |
Priming sugar amount, with priming_sugar_type / priming_sugar_amount attributes |
(amount) |
A sensor reports unknown when the underlying field is not present for that session or
recipe yet (for example target_abv needs recipe data, and the conditioning_* sensors
need those raw fields).
Each brew session also exposes a recipe_info sensor
(sensor.grainfather_<session>_recipe_info). Its state is the recipe name, and the recipe
details are exposed as attributes:
abv,ibu,srm,og,fgfermentables,hops,yeasts,mash_steps— ingredient lists (each capped at 30 items)
Because these are attributes, a normal card only shows the count/name. Use a Markdown card
with a Jinja template to render them (see the example below). The exact keys inside each
ingredient entry come straight from the Grainfather payload, so inspect one in
Developer Tools > States to see fields like name and amount.
For fermentation controllers (devices where fermentation_device_type_id == 30), an extra
sensor.grainfather_<device>_target_temperature (°C) is created. It pairs with the existing
temperature and gravity sensors on the controller.
Show one brew session's metrics on an Entities card:
type: entities
title: Batch 01 – Recipe & Metrics
entities:
- sensor.grainfather_batch_01_target_abv
- sensor.grainfather_batch_01_ibu
- sensor.grainfather_batch_01_color_srm
- sensor.grainfather_batch_01_calories
- sensor.grainfather_batch_01_batch_size
- sensor.grainfather_batch_01_boil_time
- sensor.grainfather_batch_01_pre_boil_gravity
- sensor.grainfather_batch_01_conditioning_temperature
- sensor.grainfather_batch_01_conditioning_duration
- sensor.grainfather_batch_01_ferment_volume
- sensor.grainfather_batch_01_priming_sugarShow a single metric as a Gauge:
type: gauge
name: ABV
entity: sensor.grainfather_batch_01_target_abv
min: 0
max: 12Render recipe ingredients with a Markdown card (attributes are read via state_attr):
type: markdown
content: |
## {{ states('sensor.grainfather_batch_01_recipe_info') }}
**ABV** {{ state_attr('sensor.grainfather_batch_01_recipe_info','abv') }} %
**IBU** {{ state_attr('sensor.grainfather_batch_01_recipe_info','ibu') }}
### Hops
{% for h in state_attr('sensor.grainfather_batch_01_recipe_info','hops') %}
- {{ h.name }} {{ h.amount if h.amount is defined else '' }}
{% endfor %}
### Fermentables
{% for f in state_attr('sensor.grainfather_batch_01_recipe_info','fermentables') %}
- {{ f.name }}
{% endfor %}Plot the controller target temperature next to its measured temperature with a history-graph:
type: history-graph
title: Fermentation Controller
hours_to_show: 48
entities:
- sensor.grainfather_conical_temperature
- sensor.grainfather_conical_target_temperatureAlert when the controller drifts away from its target temperature:
alias: Fermentation temp drift alert
trigger:
- platform: template
value_template: >
{{ (states('sensor.grainfather_conical_temperature') | float(0)
- states('sensor.grainfather_conical_target_temperature') | float(0)) | abs > 1.5 }}
action:
- service: notify.mobile_app_phone
data:
message: "Fermentation temp is off target!"The integration registers these service actions:
grainfather.set_brew_session_statusgrainfather.set_fermentation_stepsgrainfather.set_fermentation_step_durationgrainfather.clear_fermentation_step_finish_temperaturegrainfather.adjust_current_step_temperaturegrainfather.adjust_current_step_durationgrainfather.advance_to_next_fermentation_step
grainfather.set_brew_session_status accepts a status as either a numeric code or one of:
planningbrewingfermentingconditioningservingcompleted
This repository includes local branding assets in custom_components/grainfather/brand.
icon.pngis used for compact integration surfaceslogo.pngis used where Home Assistant shows a wider brand image
Home Assistant only uses local custom integration branding from brand/ starting with version 2026.3.
- custom_components/grainfather contains the integration source
- tests contains API, config-flow, Home Assistant runtime, coordinator, control, and history-importer tests
- pyproject.toml contains local tooling configuration
- docs/api.md documents the Grainfather cloud API used by the integration
The repository includes several custom JavaScript cards in custom_components/grainfather/www.
grainfather-brew-collection-card.js displays multiple brew sessions in a responsive grid with advanced filtering and deduplication.
Features:
- Display multiple brew sessions at once (V2 Detailed or V3 Compact layout)
- Filter by status (fermenting, conditioning, serving, brewing, planning, completed)
- Optional deduplication: show only one card per unique batch_number + session name pair
- Optional grouping by status in separate sections
- Responsive grid with configurable layout:
- fixed cards per row (
cards_per_row) - auto-fit mode with minimum card width (
card_min_width)
- fixed cards per row (
Custom-card resources are registered automatically when the integration loads.
Example configuration:
type: custom:grainfather-brew-collection-card
title: Active Brews
entities:
- sensor.grainfather_batch_01_batch_number
- sensor.grainfather_batch_02_batch_number
- sensor.grainfather_batch_03_batch_number
card_type: brew-session-detailed
statuses: [fermenting, conditioning, serving]
deduplicate: false
group_by_status: trueConfiguration Options:
title(string): Display name for the collectionentities(list): Grainfather batch_number sensors to displaycard_type(string): Card layout —brew-session-detailed(V2) orbrew-session-compact(V3)statuses(list): Filter by these statuses (default: all available)deduplicate(boolean): Show only one card per batch_number + name pairgroup_by_status(boolean): Group sessions by status in separate sectionscards_per_row(number): Fixed number of cards per row (0= auto-fit mode)card_min_width(number): Minimum card width in px used by auto-fit mode
Display individual brew session details. Cards support density_unit: default|sg|plato|brix where default uses the integration-wide option.
- Detailed card (V2) includes fermentation steps, current-step highlighting (only while
fermenting), and step duration formatting (1d 7h). - Compact card (V3) provides a denser summary layout for large dashboards.
grainfather-fermentation-device-card.js shows live fermentation-device telemetry and active session controls.
Key capabilities:
- Immediate UI response (optimistic updates) for temperature/duration step changes
- Debounced batching of rapid adjustments
- Absolute-value backend updates for safer multi-dashboard use
- Linked recipe name in the card title
- Optional fermentation steps list (
show_fermentation_steps) - Optional temperature, duration, and next-step control panel (
show_controls) - Enabled-by-default batch-anchored temperature and Plato history graphs
(
show_graphs: falsekeeps the compact live-telemetry card) - Current-step highlighting only when status is
fermenting
The graphs query the linked fermenting brew-session Batch Number entity's immutable Recorder statistic IDs, not the stable live sensor histories. They clear when the device is unlinked or the linked session stops fermenting.
grainfather-on-tap-card.js renders a pub-style blackboard list of beers currently in status serving.
- Shows only: batch number, style, ABV, original gravity
- Filters sessions to
status = serving - If a batch appears in multiple variants, only the first variant is shown
- Supports
density_unit: default|sg|plato|brixon all included brew session cards and the On Tap card - Mobile-friendly layout: ABV and gravity move to a second line to keep full beer names visible
Custom-card resources are registered automatically when the integration loads.
type: custom:grainfather-on-tap-card
max_items: 12
density_unit: sgRecent dashboard views include:
Shows all custom Grainfather cards available in Lovelace.
Shows serving and coming-soon beers using the blackboard layout.
Shows active sessions with the compact brew session layout.
Shows grouped fermentation-device cards for chambers, controllers, and pill sensors.
Shows a detailed active fermentation session with live measurements, history charts, fermentation steps, and controls.
These examples reflect the current card behavior and layout options documented above.
- The Grainfather cloud API is not officially documented, so some payload assumptions are based on observed responses.
- The Grainfather cloud API is REST-only and exposes no push channel (no websocket, MQTT, or webhook) to third parties, so the integration is
cloud_polling. It compensates with state-aware adaptive polling rather than true server-side push.
- Add fixture-based tests from captured real API responses.
- Expand entity coverage once more Grainfather API fields and workflows are confirmed.




