Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getters for aggregate report and dry food consumption #202

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from

Conversation

jdrews
Copy link

@jdrews jdrews commented Dec 17, 2023

This PR adds two GETs:

  • get_pet_aggregate_report
  • get_pet_food_consumption_report

Why this PR

I wanted to know how much food my pet was eating per day. With the above getters you can do the following to see how much food your pet ate on 2023-12-14.

consumed_food_grams = await surepy.get_pet_food_consumption_report(pet.household_id, pet.id, "2023-12-14", "2023-12-14")

How it works

get_pet_food_consumption_report actually calls get_pet_aggregate_report to get the raw data. The sure petcare app gets these datapoints on the frontend/client and then calculates total food consumption on the clientside. The get_pet_food_consumption_report performs that calculation.

One interesting oddity that took a while to figure out is how the client calculates total consumption. I've added an optional app_mode boolean parameter that lets you toggle between following the app's total consumption logic and raw summation.

You can also pass in a bowl_index to specify which bowl you want to get pet food consumption from. If you only have one bowl the bowl_index is 0 and defaults to such.

@pikim
Copy link

pikim commented Dec 29, 2023

I just tested this with multiple pets and dry and wet food and I have some comments and questions:

  • first and most important: it works, great job!
  • I wouldn't call it dry food or wet food, because the user can customize which bowl is used for what. Instead I would also pass the bowl index to the method. Or use the food_type_id to determine the type.
  • if you're only interested in food per day, why do you pass 2 dates? The only benefit is that you can also get the food per week/month/...

@jdrews
Copy link
Author

jdrews commented Dec 30, 2023

@pikim Thank you for trying out this PR and for the feedback. I'll push some updates here over the next few days.

@jdrews
Copy link
Author

jdrews commented Dec 30, 2023

Ah and about passing in a start and end date, I thought that was more flexible in case someone wanted the total over the past week or month. It'd be trivial to add a wrapper for just a day.

@jdrews jdrews marked this pull request as draft December 30, 2023 06:20
Document bowl_index and per day reports as well as minor doc cleanups
@jdrews jdrews marked this pull request as ready for review December 30, 2023 17:31
@jdrews
Copy link
Author

jdrews commented Dec 30, 2023

@pikim I've made updates to allow for selecting the bowl_index as well as documenting how a user requests a "per day" pet food consumption report. If you can try it out I'd appreciate it!

@pikim
Copy link

pikim commented Dec 31, 2023

@jdrews it works. After playing around a bit: what about extending it in a way to be able to retrieve the consumptions of all bowls in one request? The data is already there after calling get_pet_aggregate_report. It could look like:

    async def get_pet_food_consumption_report(self, household_id: int, pet_id: int, from_date: str, to_date: str, bowl_index: int = 0, app_mode: bool = True) -> int | float:
        """
        Retrieve the dry food consumed in grams per pet in given time range.
        from_date and to_date should be in format: YYYY-MM-DD
            If you only want food consumption per day just pass in the same day twice (e.g. "2024-01-01" and "2024-01-01")
        app_mode will add up food consumption how the app does it.
           Turning app_mode off may give more accurate results, but the results won't match the app.
        bowl_index can be 0, 1 or None. If you only have one bowl the index is 0. Pass None to return a list with the consumption of each bowl.
        """
        report = await self.get_pet_aggregate_report(household_id, pet_id, from_date, to_date)
        datapoints = report.get('data').get('feeding').get('datapoints')
        total_food_change_in_grams = [0, 0]
        if bowl_index is None:
            bowl_index = [0, 1]
        else:
            bowl_index = [bowl_index]
        for i in bowl_index:
            for datapoint in datapoints:
                if i < datapoint.get('bowl_count'):
                    change = datapoint.get('weights')[i].get('change')
                    if app_mode and change <= -1:
                        # The app only counts food changes less than or equal to -1 and rounds to nearest integer.
                        total_food_change_in_grams[i] += round(abs(change))
                    elif change < 0:
                        # Only counting changes that are negative as these represent feedings. Positive changes are presumed to be refills.
                        total_food_change_in_grams[i] += abs(change)
        if len(bowl_index) == 1:
            return total_food_change_in_grams[bowl_index[0]]
        else:
            return total_food_change_in_grams

@magicmega
Copy link

Thank you so much for adding this! I've done a lot of work to try to manually build aggregate feeding totals within Home Assistant using this integration, and there are a few things I've learned that might need to be incorporated for full accuracy here:

  • Sometimes, a negative change CAN be a refill. E.g. if there is 30g left in the bowl and then you throw that out and refill it with only 25g.
    My personal workaround for this was to say only if both bowls had 0 or minus values would it be a 'feeding'. If either bowl had a positive change (even if one negative) then it would be seen as a refill. This works for me as i always top up dry food, but refresh wet food by emptying it first. But won't work in all cases.

link

@jdrews
Copy link
Author

jdrews commented Mar 15, 2024

@pikim I have incorporated your changes to this PR to enable returning an array of pet food consumption per bowl.

@jdrews
Copy link
Author

jdrews commented Mar 15, 2024

@magicmega Thanks! It is hard to understand what is a feeding vs a refill. I'd welcome a code review with improvements to the pet food consumption algorithm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants