A comprehensive Home Assistant integration for Beeminder that enables goal tracking, voice control, and automation.
- 📊 Real-time Goal Tracking: Monitor all your Beeminder goals as Home Assistant sensors
- 🎯 Derailment Alerts: Track days/hours until goal derailment with automatic warnings
- 🎙️ Voice Control: Add datapoints using natural language through your voice assistant
- 🔔 Smart Notifications: Automated announcements for goals due today
- 📈 Rich Data: Access complete goal statistics, history, and metadata
- 🏠 Full Integration: Create automations based on goal status
- Current Value - Track your goal's current cumulative value
- Goal Target - Monitor the dynamic target value
- Days Until Derailment - See how many days you have left
Each sensor exposes 60+ attributes including:
- Complete datapoint history (last 100 entries)
- Goal metadata (title, type, pledge amount, etc.)
- Progress tracking (rate, safebuffer, urgency)
- Status flags (won, lost, frozen)
- Graph URLs for visualization
Copy the beeminder
folder to your custom_components
directory:
custom_components/
└── beeminder/
├── __init__.py
├── sensor.py
├── config_flow.py
├── const.py
└── manifest.json
Add to your configuration.yaml
:
beeminder:
username: !secret beeminder_username
auth_token: !secret beeminder_token
Add to your secrets.yaml
:
beeminder_username: YOUR_USERNAME
beeminder_token: YOUR_AUTH_TOKEN
Get your auth token from: https://www.beeminder.com/api/v1/auth_token.json
- Install Extended OpenAI Conversation via HACS
- Configure it with your preferred AI provider (OpenAI, OpenRouter for Claude, etc.)
For complete configuration details, see VOICE_ASSISTANT_SETUP.md.
Create file packages/beeminder_templates.yaml
with sensors for different time periods:
template:
sensor:
- name: "Beeminder Goals Derailing Today"
state: >
{% set goals = states.sensor | selectattr('entity_id', 'match', 'sensor.beeminder_.*_days_until_derailment') | selectattr('state', 'eq', '0') | list %}
{% if goals | length > 0 %}
{{ goals | map(attribute='attributes.title') | list | join(', ') }}
{% else %}
No goals derailing today
{% endif %}
Add to scripts.yaml
:
add_beeminder_datapoint:
alias: Add Beeminder Datapoint
description: 'Add a datapoint to a Beeminder goal via voice'
mode: single
fields:
value:
description: The numeric value to add
required: true
goal:
description: The Beeminder goal name
required: true
date:
description: Date for the datapoint (YYYY-MM-DD)
required: false
comment:
description: Optional comment
required: false
sequence:
- variables:
username: !secret beeminder_username
auth_token: !secret beeminder_token
goal_slug: >
{% set g = goal | lower | replace(' ', '-') | replace('beeminder', '') | trim %}
{% if g in ['push-ups', 'push ups', 'pushup'] %}
pushups
{% elif g in ['code', 'programming'] %}
coding
{% else %}
{{ g }}
{% endif %}
daystamp: >
{% if date is defined and date %}
{{ date }}
{% else %}
{{ now().strftime('%Y-%m-%d') }}
{% endif %}
comment_text: "{{ comment | default('Added via Home Assistant') }}"
- service: rest_command.beeminder_add_datapoint
data:
goal: "{{ goal_slug }}"
value: "{{ value }}"
daystamp: "{{ daystamp }}"
comment: "{{ comment_text }}"
auth_token: "{{ auth_token }}"
Add these functions to Extended OpenAI Conversation:
Add Data Function:
- spec:
name: add_beeminder_data
description: Add data to a Beeminder goal. The script will map common goal names (like triceps->tricepdips, pushups variations, etc.)
parameters:
type: object
properties:
goal:
type: string
description: The Beeminder goal name like pushups, coding, weight, triceps
value:
type: number
description: The numeric value to add
required:
- goal
- value
function:
type: script
sequence:
- service: script.add_beeminder_datapoint
data:
goal: "{{ goal }}"
value: "{{ value }}"
comment: "Added via voice AI"
continue_on_error: false
response_variable: script_result
- stop: >
{% if script_result is defined and script_result.result is defined %}
{{ script_result.result }}
{% else %}
I've sent {{ value }} to your {{ goal }} goal. Please check Beeminder to confirm it was added successfully.
{% endif %}
Check Status Function:
- spec:
name: get_beeminder_status
description: Get information about Beeminder goals status
parameters:
type: object
properties:
time_period:
type: string
description: Time period to check
enum: [today, tomorrow, soon, week, safe, most_urgent, count, all]
default: today
function:
type: template
value_template: >
{% if time_period == 'today' %}
{{ states('sensor.beeminder_goals_derailing_today') }}
{% elif time_period == 'tomorrow' %}
{{ states('sensor.beeminder_goals_derailing_tomorrow') }}
{% elif time_period == 'week' %}
{{ states('sensor.beeminder_goals_derailing_this_week') }}
{% else %}
{{ states('sensor.beeminder_goals_derailing_today') }}
{% endif %}
Adding Data:
- "Add 10 pushups to Beeminder"
- "Log 30 minutes of coding"
- "Record 5000 steps"
- "I did 2 floss"
Checking Status:
- "What Beeminder goals am I derailing on today?"
- "What goals are due tomorrow?"
- "What goals are derailing this week?"
- "What's my most urgent Beeminder goal?"
automation:
- alias: "Beeminder 6PM Derailment Alert"
trigger:
- platform: time
at: "18:00:00"
action:
- variables:
urgent_goals: >
{% set goals = states.sensor
| selectattr('entity_id', 'match', 'sensor.beeminder_.*_days_until_derailment')
| selectattr('state', 'lt', '1')
| list %}
{% if goals | length > 0 %}
{{ goals | map(attribute='attributes.title') | list | join(', ') }}
{% else %}
none
{% endif %}
- condition: template
value_template: "{{ urgent_goals != 'none' }}"
- service: tts.speak
data:
message: "Attention! These Beeminder goals are due today: {{ urgent_goals }}"
automation:
- alias: "Log Toothbrushing"
trigger:
- platform: state
entity_id: binary_sensor.bathroom_motion
to: "on"
for: "00:02:00"
condition:
- condition: time
after: "21:00:00"
before: "23:59:00"
action:
- service: script.add_beeminder_datapoint
data:
goal: "toothbrush"
value: 1
comment: "Auto-logged by motion sensor"
The integration includes comprehensive template sensors for tracking goal urgency across different time periods. These are especially useful for voice assistant queries and dashboard cards.
Create these in packages/beeminder_templates.yaml
:
- Goals Derailing Today - Lists all goals with 0 days until derailment
- Goals Derailing Tomorrow - Lists all goals with 1 day until derailment
- Goals Derailing Soon - Lists goals derailing in 2-3 days
- Goals Derailing This Week - Lists all goals derailing within 7 days
- Safe Goals - Lists goals with more than 7 days buffer
- Most Urgent Goal - Shows your single most urgent goal
- Goals Count by Urgency - Shows counts for today, tomorrow, and this week
template:
sensor:
- name: "Beeminder Goals Derailing This Week"
state: >
{% set goals = states.sensor
| selectattr('entity_id', 'match', 'sensor.beeminder_.*_days_until_derailment')
| selectattr('state', 'le', '7')
| list %}
{% if goals | length > 0 %}
{% set ns = namespace(names=[]) %}
{% for goal in goals %}
{% set title = goal.attributes.get('title', '') %}
{% set goal_name = title if title else goal.entity_id.replace('sensor.beeminder_', '').replace('_days_until_derailment', '').replace('_', ' ').title() %}
{% set ns.names = ns.names + [goal_name + ': ' + goal.state + ' days'] %}
{% endfor %}
{{ ns.names | join(', ') }}
{% else %}
No goals derailing this week
{% endif %}
automation:
- alias: "Morning Goal Report"
trigger:
- platform: time
at: "08:00:00"
condition:
- condition: template
value_template: "{{ states('sensor.beeminder_goals_derailing_today') != 'No goals derailing today' }}"
action:
- service: notify.mobile_app
data:
title: "Beeminder Goals Due Today"
message: "{{ states('sensor.beeminder_goals_derailing_today') }}"
type: custom:mushroom-template-card
icon: mdi:bee
icon_color: >-
{% set min_days = states.sensor
| selectattr('entity_id', 'match', 'sensor.beeminder_.*_days_until_derailment')
| map(attribute='state')
| map('float', default=999)
| min %}
{% if min_days < 1 %} red
{% elif min_days < 2 %} orange
{% elif min_days < 4 %} yellow
{% else %} green
{% endif %}
primary: Beeminder
secondary: >-
{% set urgent = states.sensor
| selectattr('entity_id', 'match', 'sensor.beeminder_.*_days_until_derailment')
| selectattr('state', 'lt', '1')
| list | length %}
{% if urgent > 0 %} 🚨 {{ urgent }} due today
{% else %} ✅ All good
{% endif %}
type: custom:auto-entities
card:
type: entities
title: ⚠️ Beeminder Goals Due Today
filter:
include:
- entity_id: sensor.beeminder_*_days_until_derailment
state: < 1
- Check your auth token is valid
- Ensure your username is correct
- Default update interval is 5 minutes
- Verify Extended OpenAI Conversation is installed
- Check the function is properly configured
- Ensure your voice pipeline uses the Extended OpenAI agent
- Check Home Assistant logs for API errors
- Verify goal slugs match exactly (case-sensitive)
- Test manually via Developer Tools → Services
Every sensor includes complete goal data as attributes:
{{ state_attr('sensor.beeminder_pushups_current_value', 'pledge') }}
{{ state_attr('sensor.beeminder_weight_days_until_derailment', 'hours_until_derailment') }}
{{ state_attr('sensor.beeminder_coding_current_value', 'datapoints') | length }}
# Check if any goal is urgent
{{ states.sensor
| selectattr('entity_id', 'match', 'sensor.beeminder_.*_days_until_derailment')
| selectattr('state', 'lt', '1')
| list | length > 0 }}
# Get total pledged amount
{{ states.sensor
| selectattr('entity_id', 'match', 'sensor.beeminder_.*_current_value')
| map(attribute='attributes.pledge')
| sum }}
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License.
- Beeminder for the API and goal tracking platform
- Home Assistant community for the amazing automation platform
- Extended OpenAI Conversation for enabling natural voice control