Skip to content

Added support for Duke Energy smart meters#15165

Merged
pvizeli merged 8 commits into
home-assistant:devfrom
w1ll1am23:duke_energy
Jul 2, 2018
Merged

Added support for Duke Energy smart meters#15165
pvizeli merged 8 commits into
home-assistant:devfrom
w1ll1am23:duke_energy

Conversation

@w1ll1am23
Copy link
Copy Markdown
Contributor

@w1ll1am23 w1ll1am23 commented Jun 26, 2018

Description:

This adds support for reading previous days smart meter readings, both gas and electric. Each meter will be represented as a sensor sensor.duke_energy_123456 where 123456 is the meter ID.

Each meter will also include attributes for total usage for last bill, average usage for last bill, and total number of days billed.

This will only work for users who have a smart meter installed and actively reporting data here https://www.duke-energy.com/my-account/usage-analysis

The only issue I have seen while testing this (only happened once) is that the API took really long to respond but didn't timeout or get any errors. The entity never showed up in HA. It showed up after doing another reboot. Is there something that is needed to let HA know setup can take a long time?

Couple of notes:

  • This isn't an official API
  • beautiful soup is used to parse the site to obtain the meter ID which is need to call the API for usage
  • Previous days usage isn't available exactly at 00:00:01 and in my experience it isn't available prior to 00:07:30 I assume this time is different for everyone/every day. The update is only pulled from the API approximately every 2 hours.
  • The previous days usage is reported as 0 until Duke updates the information.
  • The service doesn't return any useful information if the username/password are bad so a generic error will occur.

Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.io#5644

Example entry for configuration.yaml (if applicable):

sensor:
  - platform: duke_energy
    username: !secret duke_username
    password: !secret duke_password

Checklist:

  • The code change is tested and works locally.
  • Local tests pass with tox. Your PR cannot be merged unless tests pass

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

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

  • New dependencies have been added to the REQUIREMENTS variable (example).
  • New dependencies are only imported inside functions that use them (example).
  • New or updated dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
  • New files were added to .coveragerc.

def update(self):
"""Update meter."""
self.duke_meter.update()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

blank line at end of file


try:
duke = DukeEnergy(config.get(CONF_USERNAME),
config.get(CONF_PASSWORD),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

continuation line under-indented for visual indent

from homeassistant.const import CONF_USERNAME, CONF_PASSWORD
from homeassistant.helpers.entity import Entity
import homeassistant.helpers.config_validation as cv
import homeassistant.util as util
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

'homeassistant.util' imported but unused

@frenck
Copy link
Copy Markdown
Member

frenck commented Jun 27, 2018

Note: The docs seem to be missing. Added label.

@w1ll1am23
Copy link
Copy Markdown
Contributor Author

@frenck correct, I haven't created the .io PR yet. I'll try to do that later today.

@blinkwise
Copy link
Copy Markdown

Have been using this for almost a month now with great success. Thank you w1ll1iam23 for the hard work and effort.

Copy link
Copy Markdown
Contributor

@dgomes dgomes left a comment

Choose a reason for hiding this comment

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

Looking good

@property
def name(self):
"""Return the name."""
return "duke_energy_" + self.duke_meter.id
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'm betting the meter id to be unique.

Why not implement unique_id ?

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 has been awhile since I added a new platform forgot that was even a thing. I'll add it.

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 new style string formatting instead of string concatenation. That's what @pvizeli meant. But unique id is the way to go.

def device_state_attributes(self):
"""Return the state attributes."""
attributes = {
"lastBillsUsage": self.duke_meter.get_total(),
Copy link
Copy Markdown
Contributor

@dgomes dgomes Jun 27, 2018

Choose a reason for hiding this comment

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

its common to move any string from the body of the class to the beginning of the file and use a constant, eg.

ATTR_LAST_BILLS_USAGE = 'lastBillsUsage'

meters = duke.get_meters()
sensors = []
for meter in meters:
sensors.append(DukeEnergyMeter(meter))
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.

add_devices([DukeEnergyMeter(meter) for meter in duke.get_meters()])

sensors.append(DukeEnergyMeter(meter))
add_devices(sensors)

return True
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.

don't need to return anything (no one is checking)

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 thought you had to return False if setup failed? Is that not true anymore?


@property
def unique_id(self):
"""Return the unique ID."
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

SyntaxError: invalid syntax

@@ -0,0 +1,84 @@
"""
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

TokenError: EOF in multi-line string

Copy link
Copy Markdown
Member

@pvizeli pvizeli left a comment

Choose a reason for hiding this comment

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

Please use formated strings...

@w1ll1am23
Copy link
Copy Markdown
Contributor Author

@pvizeli not sure what you mean? I also just found a bug in the pydukeenergy library and I am testing the fix now. I am going to run with the new version for a day or two and then update the version. Moving this to a WIP.

@w1ll1am23 w1ll1am23 changed the title Added support for Duke Energy smart meters [WIP] Added support for Duke Energy smart meters Jun 29, 2018
Support for Duke Energy Gas and Electric meters.

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/sensor/duke_energy/
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.

Wrong url format.

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.

Good catch

from pydukeenergy.api import DukeEnergy, DukeEnergyException

try:
duke = DukeEnergy(config.get(CONF_USERNAME),
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.

Don't use dict.get for required keys.

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.

Okay

update_interval=500)
except DukeEnergyException:
_LOGGER.error("Failed to setup Duke Energy")
return False
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.

Just return.

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.

Okay

@property
def name(self):
"""Return the name."""
return "duke_energy_" + self.duke_meter.id
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 new style string formatting instead of string concatenation. That's what @pvizeli meant. But unique id is the way to go.

@property
def state(self):
"""Return yesterdays usage."""
return self.duke_meter.get_usage()
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.

Is this doing I/O? No I/O in properties is allowed.

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.

No all of the values are stored in a dict in the library and are only updated when update is called.

vol.Required(CONF_PASSWORD): cv.string,
})

LAST_BILL_USAGE = "lastBillsUsage"
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.

Please use lowercase snakecase for state attribute strings.

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.

Okay

@w1ll1am23 w1ll1am23 changed the title [WIP] Added support for Duke Energy smart meters Added support for Duke Energy smart meters Jul 1, 2018
@pvizeli pvizeli merged commit 2145ac5 into home-assistant:dev Jul 2, 2018
@ghost ghost removed the in progress label Jul 2, 2018
awarecan pushed a commit to awarecan/home-assistant that referenced this pull request Jul 16, 2018
* Added support for Duke Energy smart meters

* Fixed hound

* Added function docstring

* Moved strings to constants, implemented unique_id, and cleaned up setup.

* Added doc string.

* Fixed review issues.

* Updated pydukenergy to 0.0.6 and set update interval to 2 hours

* Updated requirements_all
@balloob balloob mentioned this pull request Jul 20, 2018
girlpunk pushed a commit to girlpunk/home-assistant that referenced this pull request Sep 4, 2018
* Added support for Duke Energy smart meters

* Fixed hound

* Added function docstring

* Moved strings to constants, implemented unique_id, and cleaned up setup.

* Added doc string.

* Fixed review issues.

* Updated pydukenergy to 0.0.6 and set update interval to 2 hours

* Updated requirements_all
@home-assistant home-assistant locked and limited conversation to collaborators Dec 10, 2018
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.

8 participants