BCHydro component - where did it go?

When I was first new with HA, I set up my first config to include a bchydro custom component.
I’ve searched everywhere I can think of (and… don’t have it stored locally. sigh) and cannot find this… Help?

1 Like

I don’t recall seeing it and I keep a close watch of new components. If it was a custom component, should you not see it in your custom component folder?

My first install wasn’t preserved, or at least I don’t think it was. I haven’t found a backup of it anywhere.
I feel like I dreamed it, but I’m really sure I remember the data, and it being a bit of a funky setup…

I FOUND IT!!! @RobDYI if you’re interested?

import logging
import xml.etree.ElementTree as ET

import homeassistant.helpers.config_validation as cv
import requests
import voluptuous as vol
from homeassistant.const import (
   CONF_PASSWORD, CONF_USERNAME, CONF_TIMEOUT)
from homeassistant.helpers.entity import Entity

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'bchydro'

DEFAULT_TIMEOUT = 10
CONF_ACCOUNT_NUMBER = 'account_number'
CONF_SLID = 'slid'

CONFIG_SCHEMA = vol.Schema({
   DOMAIN: vol.Schema({
       vol.Required(CONF_USERNAME): cv.string,
       vol.Required(CONF_PASSWORD): cv.string,
       vol.Optional(CONF_ACCOUNT_NUMBER): cv.string,
       vol.Optional(CONF_SLID): cv.string,
       vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
   })
}, extra=vol.ALLOW_EXTRA)


def setup_platform(hass, config, add_devices, discovery_info=None):
   """Setup the sensor platform."""
   api = Api(config.get(CONF_USERNAME),
             config.get(CONF_PASSWORD),
             config.get(CONF_ACCOUNT_NUMBER),
             config.get(CONF_SLID),
             config.get(CONF_TIMEOUT))
   add_devices([BCHydroUsageSensor(api)], True)


class BCHydroUsageSensor(Entity):
   def __init__(self, api):
       """Initialize the sensor."""
       self._api = api
       self._state = None

   @property
   def name(self):
       """Return the name of the sensor."""
       return 'BC Hydro Usage'

   @property
   def state(self):
       """Return the state of the sensor."""
       return self._state

   @property
   def unit_of_measurement(self):
       return 'kWh'

   def update(self):
       """Fetch new state data for the sensor."""
       self._state = self._api.latest_usage()


URL_LOGIN = "https://app.bchydro.com/sso/UI/Login"
URL_GET_USAGE = "https://app.bchydro.com/evportlet/SystemServices/main?system:runTemplate=html/indicators/AccountProfile.xml"


class Api:
   def __init__(self, username, password, account_number, slid, timeout=10):
       """Initialize the sensor."""
       self._username = username
       self._password = password
       self._account_number = account_number
       self._slid = slid
       self._timeout = timeout

   def login(self):
       r = self._call_api(
           "post",
           URL_LOGIN,
           data={
               "realm": "bch-ps",
               'email': self._username,
               'password': self._password,
           }, allow_redirects=False)

       return r.cookies

   def latest_usage(self):
       """Fetch new state data for the sensor."""
       auth_cookies = self.login()
       r = self._call_api(
           "post",
           URL_GET_USAGE,
           data={
               "Slid": self._slid,
               "Account": self._account_number,
               "ValidityStart": '2015-09-03T00:00:00.000-07:00',
               "ValidityEnd": '9999-12-31T00:00:00.000-08:00'
           }, cookies=auth_cookies)

       latest_usage = None
       root = ET.fromstring(r.text)
       for point in root.findall('Series')[0].findall('Point'):
           if point.get('quality') != 'INVALID':
               latest_usage = point.get('value')

       return latest_usage

   def _call_api(self, method, url, **kwargs):
       payload = kwargs.get("params") or kwargs.get("data")

       _LOGGER.debug("About to call %s with payload=%s", url, payload)

       response = requests.request(method, url, timeout=self._timeout, **kwargs)

       _LOGGER.debug("Received API response: %s, %s",
                     response.status_code,
                     response.content)

       response.raise_for_status()
       return response

Thanks, I copied it to /.homeassistant/custom_components/bchydro/bchydro.py and put in configuration.yaml

bchydro:
  username: [email protected]
  password: xxx

but I get

Configuration invalidCHECK CONFIG

Integration not found: bchydro

I tried /.homeassistant/custom_components/bchydro/sensor.py

with

sensor:
  - platform: bchydro
    username: xxx
    password: xxx

but get

Integration bchydro not found when trying to verify its sensor platform.

I tried the two things you’ve described, and hosed my HA install, so you’re still doing better than me :wink:

Alright, I’ve got it working!

  - platform: bchydro
    scan_interval: 36
    username: !secret bchydro_username
    password: !secret bchydro_password
    account_number: !secret bchydro_account_number
    slid: !secret bchydro_slid

I need to look up how I found the slid again, but im excited it is working!!

Can you share what you put in your configuration.yaml and where you put the custom component?

Thank you

Where do you find the slid?

You can find it on your bill

I used HACS To install the custom component from my github: https://github.com/hdsheena/custom_components
And my config yaml entry is

  - platform: bchydro
    scan_interval: 36
    username: !secret bchydro_username
    password: !secret bchydro_password
    account_number: !secret bchydro_account_number
    slid: !secret bchydro_slid

I’d like to improve the way this gets data, I think it would be pretty easy to have it grab the hourly data rather than just the “Current usage” if anyone else is interested in this?

I’d definitely be interested in a “current usage” if someone can figure it out.

I think I’ve got the slid, does it look like this?

800000000XXXXXXX000023609000011578

I removed the extra spaces, and in the example I X’d out my account number

What information can you get from BC Hydro through this component? I know you can get daily consumption one day behind in your online account, and their smart speaker support function for Alexa and Google Home can tell you consumption to date this month and an approximate breakdown of power usage type. Is there any way to get real-time power usage, or is that data not communicated so often?

Hello all :wave:,

Can someone please tell me where to find the SLID, I’ve tried what @cariboo mentioned but I’m getting this error

bchydro: Error on device update!
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/entity_platform.py", line 291, in _async_add_entity
    await entity.async_device_update(warning=False)
  File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 419, in async_device_update
    await self.hass.async_add_executor_job(self.update)
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/bchydro/sensor.py", line 62, in update
    self._state = self._api.latest_usage()
  File "/config/custom_components/bchydro/sensor.py", line 127, in latest_usage
    for point in root.findall('Series')[0].findall('Point'):
IndexError: list index out of range

all my other credentials are correct. Any help would be appreciated :heart:

Thanks

This is just scraping from the web interface, and that’s not real-time, so this solution won’t offer real time tracking.
SLID:
Go to your bcHydro account page, and use “Inspect Element” in your browser.
Navigate to the detailed consupmtion page and go to “Network” in the inspector. Search “xml” to filter the list, and find consumption.xml
Look at the “Form Data” section in the headers tab for your SLID

2 Likes

IT WORKED!!! Using the SLID and “Account” from the xml file and my username and password.

Thank you so much :heart: :grinning:

1 Like

Hi, the BC hydro sensor was working perfectly! And then it broke…

Is this happening to anyone else?

Mine is just disappeared… maybe I need to make a change based on the newest updates?

1 Like