Skip to content

Enhance Snoo integration to support logging diaper changes#149599

Closed
kevin-david wants to merge 3 commits intohome-assistant:devfrom
kevin-david:snoo-diapers
Closed

Enhance Snoo integration to support logging diaper changes#149599
kevin-david wants to merge 3 commits intohome-assistant:devfrom
kevin-david:snoo-diapers

Conversation

@kevin-david
Copy link
Copy Markdown
Contributor

@kevin-david kevin-david commented Jul 29, 2025

There are many other things that could be logged as well, but this is a start! Totally open to feedback here, this is my first home assistant core PR.

Proposed change

Introduce functionality via a service call to make calls to log data via the Happiest Baby / Snoo backend, available via the phone app.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.

To help with the load of incoming pull requests:

Copy link
Copy Markdown

@home-assistant home-assistant bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @kevin-david

It seems you haven't yet signed a CLA. Please do so here.

Once you do that we will be able to review and accept this pull request.

Thanks!

Comment thread .devcontainer/devcontainer.json Outdated
"--security-opt",
"label=disable"
],
"mounts": [
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will remove this before finalizing the PR, but wondering - is there a better way to do this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still interested in knowing but removed now

Comment thread homeassistant/components/snoo/manifest.json Outdated
_raise_baby_not_found_error(baby_id, available_babies)

start_time = call.data.get("start_time")
if start_time is not None and start_time.tzinfo is None:
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is the best approach, but got the timezone data working for me locally

@@ -0,0 +1,72 @@
"""Test services for the Snoo integration."""
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure on optimal test patterns, but these seemed like OK cases.

@kevin-david kevin-david force-pushed the snoo-diapers branch 3 times, most recently from 0ef2805 to 81785a3 Compare August 11, 2025 04:25
@kevin-david kevin-david marked this pull request as ready for review August 11, 2025 04:45
@kevin-david
Copy link
Copy Markdown
Contributor Author

@Lash-L ready for a review here when you are, I think!

Also added docs here: home-assistant/home-assistant.io#40371

Comment thread homeassistant/components/snoo/services.py Outdated
"Diaper change logged for baby %s: %s", baby_id, call.data["diaper_types"]
)

return result.to_dict()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's in the result?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a DiaperActivity - mainly thought it could be useful to get the ID back (plus any sent info, server time, etc.) in case it was going to be used for something else. happy to remove this (and/or the logging) if it's too much noise

Comment on lines +55 to +87
def _raise_no_config_error() -> None:
"""Raise error when no Snoo configuration is found."""
raise HomeAssistantError("No Snoo configuration found")

def _raise_baby_not_found_error(baby_id: str, available_babies: str) -> None:
"""Raise error when baby ID is not found."""
raise HomeAssistantError(
f"Baby ID '{baby_id}' not found. Available baby IDs: {available_babies}"
)

config_entries = call.hass.config_entries.async_entries(DOMAIN)
if not config_entries:
_raise_no_config_error()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can one snoo integration handle multiple babies? Is there possible data that we can show for a baby so we can make it a Device? (this is a weird thing to say lol). Because then we can use a device selector and we don't have to iterate over all the entries

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking something similar. I think a device per baby would be helpful.

You'd have one device for the actual snoo and then one device for the baby. The baby part of the api is not a part that I have touched much - but I think that would be helpful for future improvements.

Copy link
Copy Markdown
Contributor Author

@kevin-david kevin-david Aug 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well this was fun, but now it supports baby... Devices 😄

Got pretty large because of it, but contained to the most recent commit. I can split that out as a separate PR if need be

Comment thread homeassistant/components/snoo/services.py Outdated
Comment on lines +15 to +17
options:
- "Wet"
- "Dirty"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make the values lowercase and use a translation key to translate these

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So - tried to use a translation key here, e.g. [%key:component::snoo::services::log_diaper_change::fields::diaper_types::options::dirty%] but was showing up as that literal string. Was I doing that wrong or did you mean something else?

Also in strings.json when trying to add wet/dirty... * [ERROR] [TRANSLATIONS] Invalid strings.json: extra keys not allowed @ data['services']['log_diaper_change']['fields']['diaper_types']['options']. Got {'wet': 'Wet', 'dirty': 'Dirty'}

Comment thread homeassistant/components/snoo/services.yaml Outdated
@home-assistant
Copy link
Copy Markdown

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@home-assistant home-assistant bot marked this pull request as draft August 11, 2025 10:04
Comment thread homeassistant/components/snoo/manifest.json Outdated
There are many other things that could be logged as well, but this is a start!
]


BABY_BINARY_SENSOR_DESCRIPTIONS: list[SnooBabyBinarySensorEntityDescription] = [
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably these are changable, but to keep this simple(r) I just left these as (binary in this case) sensors for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do note that once this is released you would have to deprecate it, so it's probably easier to find out if it is changable, as it will probably save you time in the end

Copy link
Copy Markdown
Contributor Author

@kevin-david kevin-david Aug 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I didn't realize that, which seems obvious now. Since the original intent of this PR was the service, I'm thinking I go back to that, add the device, but none of the sensors. What do you think?

_LOGGER.warning("No coordinators found for config entry %s", entry.entry_id)
continue

for coordinator in coordinators.values():
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically we could require the parent/Snoo device ID as well, but that seemed redundant when we can just filter down to Baby devices via services.yaml for one less input, and I suspect this loop will be a 1-2 iterations for most people

device: dr.DeviceEntry | None = device_registry.async_get(baby_device_id)
if not device:
_raise_device_not_found_error(baby_device_id)
assert device is not None
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is right, but got mypy happy b/c the _raise_* methods are the ones doing the blowing up

@kevin-david kevin-david marked this pull request as ready for review August 15, 2025 03:05
@home-assistant home-assistant bot requested a review from joostlek August 15, 2025 03:05
@kevin-david kevin-david requested a review from Lash-L August 15, 2025 03:05
Comment on lines +74 to +75
if update_interval is None:
update_interval = timedelta(minutes=5)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's always None

Comment on lines +89 to +92
async def _async_update_data(self) -> None:
"""Fetch baby data."""
status = await self.baby.get_status()
self.data = status
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return the new baby status instead of assigning it to self.data

super().__init__(coordinator)
self.baby = coordinator.baby
self.entity_description = description
self._attr_unique_id = f"snoo_baby_{coordinator.baby.baby_id}_{description.key}"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove snoo here

]


BABY_BINARY_SENSOR_DESCRIPTIONS: list[SnooBabyBinarySensorEntityDescription] = [
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do note that once this is released you would have to deprecate it, so it's probably easier to find out if it is changable, as it will probably save you time in the end

Comment on lines +60 to +72
icon="mdi:minus",
value_fn=lambda data: data.settings.minimalLevel,
),
SnooBabySensorEntityDescription(
key="minimal_level_volume",
translation_key="minimal_level_volume",
icon="mdi:volume-low",
value_fn=lambda data: data.settings.minimalLevelVolume,
),
SnooBabySensorEntityDescription(
key="responsiveness_level",
translation_key="responsiveness_level",
icon="mdi:knob",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use icon translations instead

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep this for a followup then :)

@home-assistant home-assistant bot marked this pull request as draft August 15, 2025 13:45
@github-actions
Copy link
Copy Markdown

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
If you are the author of this PR, please leave a comment if you want to keep it open. Also, please rebase your PR onto the latest dev branch to ensure that it's up to date with the latest changes.
Thank you for your contribution!

@github-actions github-actions bot added the stale label Oct 14, 2025
@emontnemery
Copy link
Copy Markdown
Contributor

@kevin-david Please address or reply to the open review comments, and mark your PR as "ready for review", it won't be merged otherwise.

@github-actions github-actions bot removed the stale label Oct 15, 2025
@mpross512
Copy link
Copy Markdown

Wow I had the same idea to work on this! We must both have new kiddos!

I created this PR for the python_snoo library to just get a list of babies (and not have to go through a snoo device's list of baby IDs) since babies shouldn't be tied to a specific device. (Parents may sell device or use it for another kid after their baby is past 6 months, but may want to continue tracking diapers/feedings.)

So this may have an impact on your PR, hopefully it can make it easier/more logical.

@github-actions
Copy link
Copy Markdown

There hasn't been any activity on this pull request recently. This pull request has been automatically marked as stale because of that and will be closed if no further activity occurs within 7 days.
If you are the author of this PR, please leave a comment if you want to keep it open. Also, please rebase your PR onto the latest dev branch to ensure that it's up to date with the latest changes.
Thank you for your contribution!

@github-actions github-actions bot added the stale label Dec 24, 2025
@github-actions github-actions bot closed this Dec 31, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Jan 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants