Set the manifest's links and code owner to git.asw.io/arne/ha-babytracker. HACS can only install from GitHub, so the README now leads with a by-hand install and describes a GitHub mirror for HACS users. Drop the HACS check from the workflow because it cannot pass on Gitea. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Baby Tracker for Home Assistant
An unofficial integration that connects Home Assistant to the
sync group of the Baby Tracker app (com.nighp.babytracker_android). You can see your
baby's log in Home Assistant and add to it, and entries sync with the app on your other
devices.
It also contains a Python client for the sync API, which was reverse engineered from version 4.53 of the Android app.
Unofficial and partly unverified. Nothing here comes from the app's developer, and the server could change without notice. Reading has been checked against the real server, but uploading has not. See Your first test, and back up your data first.
Requirements
- Home Assistant 2025.1 or newer.
- A sync group, set up in the app's sync settings. Its email and password are what you sign in with.
Install
By hand
From a terminal on the Home Assistant machine, in your configuration folder (usually
/config), run this and then restart Home Assistant. Run it again to update.
mkdir -p custom_components && rm -rf custom_components/babytracker && curl -fsSL https://git.asw.io/arne/ha-babytracker/archive/main.tar.gz | tar xz --strip-components=2 -C custom_components ha-babytracker/custom_components/babytracker
You can also copy custom_components/babytracker over yourself, for example with the
Samba or File editor add-ons.
With HACS
HACS can only install from GitHub, so it can't use the repository at git.asw.io directly.
To use HACS, mirror this repository to a public GitHub repository, which Gitea can do
automatically under Settings → Repository → Mirror settings. Then:
- In HACS, open the menu and choose Custom repositories.
- Add the GitHub URL, with the type Integration.
- Find Baby Tracker in HACS, download it, and restart Home Assistant.
Set it up
Go to Settings → Devices & services → Add integration → Baby Tracker and sign in.
Home Assistant joins the group as one more device, named "Home Assistant". Remove the integration and that device stays listed on the account, because the app has no call that removes a device.
Your first test
The first upload is the one thing that has never been tried against the real server, so start with something easy to remove:
- Go to Developer tools → Actions and run Baby Tracker: Log journal entry with
the text
Home Assistant test. - Check that it appears in the app on your phone, after the app has synced.
- Restart Home Assistant and check that it still appears, once, on
sensor.<baby>_recent_activity. - Delete it in the app. Within about five minutes it should disappear from Home Assistant.
If any step fails, stop uploading and open an issue with what you saw.
What you get
Each baby becomes a device with these entities.
| Entity | Shows |
|---|---|
calendar.<baby>_log |
The whole log, for the calendar view |
sensor.<baby>_recent_activity |
Time of the latest entry, with the last 20 in its entries attribute |
sensor.<baby>_last_diaper |
Time of the last diaper, with status and amount as attributes |
sensor.<baby>_last_feeding |
Start of the last feed of any type, with its details |
sensor.<baby>_last_sleep |
Start of the last sleep, with end and duration attributes |
sensor.<baby>_diapers_today |
Count |
sensor.<baby>_feedings_today |
Count |
sensor.<baby>_sleep_today |
Minutes |
sensor.<baby>_bottle_volume_today |
Formula and pumped milk |
sensor.<baby>_temperature |
Latest reading |
sensor.<baby>_weight |
Latest measurement |
sensor.<baby>_length |
Latest measurement |
sensor.<baby>_head_circumference |
Latest measurement |
Entries count towards the day they started on, so a sleep that runs past midnight counts for the day it began. Entries made on other devices appear within about five minutes.
Adding entries
Each of these actions takes optional baby, time and note fields.
| Action | Fields |
|---|---|
babytracker.log_diaper |
status (wet, poopy, mixed, dry), amount (light, normal, heavy, overflow) |
babytracker.log_sleep |
duration in minutes |
babytracker.log_bottle |
amount, kind (formula, pumped), unit (ml, oz) |
babytracker.log_nursing |
left_minutes, right_minutes, both_minutes, finish_side (left, right) |
babytracker.log_temperature |
value, unit (C, F) |
babytracker.log_growth |
weight, length, head, units (metric, english) |
babytracker.log_bath |
none |
babytracker.log_joy |
none |
babytracker.log_journal |
note is the entry's text, and is required |
baby: the baby's device or their name. Leave it out if the account has one baby.time: when the activity started. Leave it out and the activity is taken to have just finished, so a 30-minute sleep is logged as starting 30 minutes ago.- Units: these default to your Home Assistant unit system.
- Failures: if the upload fails, for example with no internet, the action reports an error and nothing is saved or retried.
- Response: each action can return the new entry's
id.
Dashboard examples
Buttons to log a diaper in one tap:
type: horizontal-stack
cards:
- type: button
name: Wet
icon: mdi:water
tap_action:
action: perform-action
perform_action: babytracker.log_diaper
data:
status: wet
- type: button
name: Poopy
icon: mdi:emoticon-poop
tap_action:
action: perform-action
perform_action: babytracker.log_diaper
data:
status: poopy
The log as a list, using a Markdown card. Replace sam with your baby's name:
type: markdown
title: Recent activity
content: >
{% for entry in state_attr('sensor.sam_recent_activity', 'entries') or [] %}
- **{{ as_timestamp(entry.time) | timestamp_custom('%H:%M') }}** {{ entry.summary }}{{ ' — ' ~ entry.note if entry.note }}
{% endfor %}
A reminder when the last feed was over three hours ago:
triggers:
- trigger: template
value_template: >
{{ now() - states('sensor.sam_last_feeding') | as_datetime > timedelta(hours=3) }}
actions:
- action: notify.notify
data:
message: "Last feed was over three hours ago"
Limitations
- Shown but not addable: medication, vaccines, milestones, solid foods and other activities. These pick from lists kept in the app. They do appear on the calendar and in recent activity.
- Not shown: pumping sessions, because they don't belong to a baby. Photos too.
- No editing or deleting from Home Assistant. Use the app.
- Startup: the integration keeps the log in memory and downloads it again each time it starts, so large accounts take longer to load.
- Group resets: if you reset the group in the app, reload the integration.
- Password: Home Assistant stores it unencrypted in its
.storagefolder, as it does for most integrations. The server has no separate tokens.
Python client
The library works without Home Assistant, and lives inside the integration folder because HACS installs only that folder.
pip install -e .
The server has no way to query records. It stores a database snapshot (the seed) and
an append-only log per device. Replica combines them into a local copy.
from babytracker_api import (
BabyTrackerClient, DiaperStatus, Replica, diaper, extract_seed_db,
formula, open_seed_db, read_cursors, sleep,
)
# Keep device_uuid stable between runs. A new value is a new device on the account.
client = BabyTrackerClient("you@example.com", "password", device_uuid="<a saved uuid4>")
client.login()
# Build a local copy from the seed.
extract_seed_db(client.download_seed("seed.zip"), "seed.db")
db = open_seed_db("seed.db")
replica = Replica.from_seed(db)
cursors = read_cursors(db)
# Add what happened since. Save `cursors` to continue from there next time.
# include_own is needed here because the seed predates this device's own uploads.
for device, item in client.pull(cursors, include_own=True):
replica.apply(item.op, item.object)
baby = next(iter(replica.babies.values()))
for entry in replica.entries(baby.id):
print(entry.time, entry.summary)
# Add records. These need the baby's full record.
client.add(diaper(baby.record, DiaperStatus.POOPY))
client.add(formula(baby.record, 120)) # ml; english=True for fl oz
client.add(sleep(baby.record, minutes=45, note="nap"))
# Change or remove a record. Records are plain dicts.
record = sleep(baby.record, minutes=30)
client.add(record)
client.update({**record, "duration": 40})
client.delete(record)
To check it against your account without changing anything:
BABYTRACKER_EMAIL=you@example.com BABYTRACKER_PASSWORD=... python3 examples/smoke_test.py
See docs/API.md for endpoints, record formats and open questions.
Development
python3 -m unittest discover -s tests
The tests use a mock server written from the same analysis of the app. The integration's
tests run against small stand-ins for Home Assistant's APIs in tests/ha_stubs, so they
don't show that it works in real Home Assistant. The workflow in .github/workflows, which
Gitea Actions also reads, adds Home Assistant's hassfest.