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

Allow for separate Opower costs and consumption data #132133

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from

Conversation

PseudoResonance
Copy link

Proposed change

I'm unsure about other utilities, but PSE only reports costs in the billing view, not in the daily or hourly views. Previously, the finer windows overrode the billing view windows, and costs were set back to 0. This PR attempts to check if the utility has this behavior (fine views have 0 cost), and then fetches and stores the cost data in a separate set of statistics.

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

Additional information

This PR fixes or closes issue: fixes tronikos/opower#56
This PR is related to issue: #99674

Due to the way HomeAssistant handles cost/usage data with mismatched time windows, the energy dashboard will only show costs on the first day of the billing period. The cost shown is the full cost of the entire billing period, despite only showing on that day. All other days show a cost of $0.

Unlike #128964, the data here is presented exactly as returned by the Opower API, with no interpolation. However this may require additional work on the HomeAssistant energy dashboard side to present the data in a meaningful way to the user.

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:

@home-assistant
Copy link

home-assistant bot commented Dec 3, 2024

Hey there @tronikos, mind taking a look at this pull request as it has been labeled with an integration (opower) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of opower can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign opower Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the pull request.

@tronikos
Copy link
Member

Do you see this https://github.com/tronikos/opower/blob/d3a76537984cf02784c366e3004354f577aeb6eb/src/opower/opower.py#L411 in the logs? If yes, should we change the library code to indicate to the caller this happened to avoid inferring this here?

@@ -245,6 +329,31 @@ def _update_with_finer_cost_reads(
break
cost_reads += finer_cost_reads

def _check_is_cost_missing(
Copy link
Member

Choose a reason for hiding this comment

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

Can this just be:

        def _check_is_cost_missing(cost_reads: list[CostRead]) -> bool:
            if not cost_reads:
                return False
            return sum(cost_read.provided_cost for cost_read in cost_reads) == 0

And only call it with daily_cost_reads and hourly_cost_reads?

You will also set: cost_reads_billing = cost_reads.copy() right after we fetch bill data.

@@ -218,7 +302,7 @@ async def _insert_statistics(self) -> None:

async def _async_get_cost_reads(
self, account: Account, time_zone_str: str, start_time: float | None = None
) -> list[CostRead]:
) -> tuple[list[CostRead], list[CostRead] | None]:
Copy link
Member

Choose a reason for hiding this comment

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

Update function doc

@@ -156,32 +169,100 @@ async def _insert_statistics(self) -> None:
cost_sum = cast(float, stats[cost_statistic_id][0]["sum"])
consumption_sum = cast(float, stats[consumption_statistic_id][0]["sum"])
last_stats_time = stats[consumption_statistic_id][0]["start"]
if cost_reads_billing:
Copy link
Member

Choose a reason for hiding this comment

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

The code below is very similar to the code above. Can you avoid duplicate code by extracting it to a function?

consumption_sum,
last_stats_time,
cost_reads,
[StatisticType.COST, StatisticType.CONSUMPTION]
Copy link
Member

Choose a reason for hiding this comment

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

The code is now hard to maintain with all the branching. I feel like it could be simplified if you have 2 lists of cost reads: one for usage, one for cost. For accounts like mine the 2 lists will be the same. For accounts like yours the second list will have the monthly data. Then you can fetch and update statistics in the recorder separately. This unfortunately means for accounts like mine the recorder interactions will now be slower but I think it's better to have less complex code. Could you try that in a separate PR to see how the code would look like?

@home-assistant
Copy link

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 January 13, 2025 10:41
@PseudoResonance
Copy link
Author

Do you see this https://github.com/tronikos/opower/blob/d3a76537984cf02784c366e3004354f577aeb6eb/src/opower/opower.py#L411 in the logs? If yes, should we change the library code to indicate to the caller this happened to avoid inferring this here?

No, PSE doesn't seem to properly return that the cost is missing. It's just 0 unfortunately...

@tronikos
Copy link
Member

tronikos commented Jan 13, 2025

Do you see this https://github.com/tronikos/opower/blob/d3a76537984cf02784c366e3004354f577aeb6eb/src/opower/opower.py#L411 in the logs? If yes, should we change the library code to indicate to the caller this happened to avoid inferring this here?

No, PSE doesn't seem to properly return that the cost is missing. It's just 0 unfortunately...

To clarify, the linked code re-fetches data hitting the usage only endpoint if it gets no data from the cost endpoint and fills in 0 for cost. Can you confirm with a debugger you aren't hitting that code path? Or can you run python -m opower -v and post the output after removing any personal data.

@PseudoResonance
Copy link
Author

Do you see this https://github.com/tronikos/opower/blob/d3a76537984cf02784c366e3004354f577aeb6eb/src/opower/opower.py#L411 in the logs? If yes, should we change the library code to indicate to the caller this happened to avoid inferring this here?

No, PSE doesn't seem to properly return that the cost is missing. It's just 0 unfortunately...

To clarify, the linked code re-fetches data hitting the usage only endpoint if it gets no data from the cost endpoint and fills in 0 for cost. Can you confirm with a debugger you aren't hitting that code path? Or can you run python -m opower -v and post the output after removing any personal data.

Yup, I just checked it again to be sure, and it's running that if statement, but not entering it. The cost is just being returned as 0 from Opower I believe.

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

Successfully merging this pull request may close these issues.

PSE Unable to Supply Daily/Hourly Bill Cost
2 participants