Skip to content

Commit

Permalink
start of HACS component
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Arthur committed Mar 10, 2023
1 parent 291a0a2 commit 765a439
Show file tree
Hide file tree
Showing 11 changed files with 635 additions and 102 deletions.
211 changes: 109 additions & 102 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,129 +1,136 @@
# Byte-compiled / optimized / DLL files
__pycache__/
/config
config2/*

tests/testing_config/deps
tests/testing_config/home-assistant.log*

# hass-release
data/
.token

# Translations
custom_components/*/translations

# Hide sublime text stuff
*.sublime-project
*.sublime-workspace

# Hide some OS X stuff
.DS_Store
.AppleDouble
.LSOverride
Icon

# Thumbnails
._*

# IntelliJ IDEA
.idea
*.iml

# pytest
.pytest_cache
.cache

# GITHUB Proposed Python stuff:
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
# Packages
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
*.egg-info
dist
build
eggs
.eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib
lib64
pip-wheel-metadata

# Installer logs
# Logs
*.log
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
nosetests.xml
htmlcov/
test-reports/
test-results.xml
test-output.xml

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py
# Mr Developer
.mr.developer.cfg
.project
.pydevproject

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# emacs auto backups
*~
*#
*.orig

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid
# venv stuff
pyvenv.cfg
pip-selfcheck.json
venv
.venv
Pipfile*
share/*
/Scripts/

# vimmy stuff
*.swp
*.swo
tags
ctags.tmp

# vagrant stuff
virtualization/vagrant/setup_done
virtualization/vagrant/.vagrant
virtualization/vagrant/config

# Visual Studio Code
.vscode/*
!.vscode/cSpell.json
!.vscode/extensions.json
!.vscode/tasks.json
.env

# SageMath parsed files
*.sage.py
# Built docs
docs/build

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Windows Explorer
desktop.ini
/home-assistant.pyproj
/home-assistant.sln
/.vs/*

# Spyder project settings
.spyderproject
.spyproject
# mypy
/.mypy_cache/*
/.dmypy.json

# Rope project settings
.ropeproject
# Secrets
.lokalise_token

# mkdocs documentation
/site
# monkeytype
monkeytype.sqlite3

# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# This is left behind by Azure Restore Cache
tmp_cache

# Pyre type checker
.pyre/
# python-language-server / Rope
.ropeproject
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
# ha-electric-kiwi
HACS compatible version of the electric kiwi integration

[![hacs_badge](https://img.shields.io/badge/HACS-Custom-41BDF5.svg?style=for-the-badge)](https://github.com/hacs/integration)


Requires a valid Electric Kiwi account
credentials have been given to Nabu Casa so nothing needs to be obtained, just install and use it.


59 changes: 59 additions & 0 deletions custom_components/electric_kiwi/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""The Electric Kiwi integration."""
from __future__ import annotations

import aiohttp
from electrickiwi_api import ElectricKiwiApi
from electrickiwi_api.exceptions import AuthException

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers import aiohttp_client, config_entry_oauth2_flow

from . import api
from .const import DOMAIN

PLATFORMS: list[Platform] = [Platform.SENSOR]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Electric Kiwi from a config entry."""
implementation = (
await config_entry_oauth2_flow.async_get_config_entry_implementation(
hass, entry
)
)

session = config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation)

try:
await session.async_ensure_token_valid()
except aiohttp.ClientResponseError as err:
if 400 <= err.status < 500:
raise ConfigEntryAuthFailed(err) from err
raise ConfigEntryNotReady from err
except aiohttp.ClientError as err:
raise ConfigEntryNotReady from err

hass.data.setdefault(DOMAIN, {})[entry.entry_id] = ElectricKiwiApi(
api.AsyncConfigEntryAuth(aiohttp_client.async_get_clientsession(hass), session)
)

# we need to set the client number and connection id
try:
await hass.data[DOMAIN][entry.entry_id].set_active_session()
except AuthException as err:
raise ConfigEntryAuthFailed(err) from err

await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
hass.data[DOMAIN].pop(entry.entry_id)

return unload_ok
29 changes: 29 additions & 0 deletions custom_components/electric_kiwi/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""API for Electric Kiwi bound to Home Assistant OAuth."""

from aiohttp import ClientSession
from electrickiwi_api import AbstractAuth

from homeassistant.helpers import config_entry_oauth2_flow

from .const import API_BASE_URL


class AsyncConfigEntryAuth(AbstractAuth):
"""Provide Electric Kiwi authentication tied to an OAuth2 based config entry."""

def __init__(
self,
websession: ClientSession,
oauth_session: config_entry_oauth2_flow.OAuth2Session,
) -> None:
"""Initialize Electric Kiwi auth."""
# add host when ready for production "https://api.electrickiwi.co.nz" defaults to dev
super().__init__(websession, API_BASE_URL)
self._oauth_session = oauth_session

async def async_get_access_token(self) -> str:
"""Return a valid access token."""
if not self._oauth_session.valid_token:
await self._oauth_session.async_ensure_token_valid()

return self._oauth_session.token["access_token"]
38 changes: 38 additions & 0 deletions custom_components/electric_kiwi/application_credentials.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""application_credentials platform the Electric Kiwi integration."""

from homeassistant.components.application_credentials import (
AuthorizationServer,
ClientCredential,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_entry_oauth2_flow

from .const import OAUTH2_AUTHORIZE, OAUTH2_TOKEN
from .oauth2 import ElectricKiwiLocalOAuth2Implementation


async def async_get_auth_implementation(
hass: HomeAssistant, auth_domain: str, credential: ClientCredential
) -> config_entry_oauth2_flow.AbstractOAuth2Implementation:
"""Return auth implementation."""
return ElectricKiwiLocalOAuth2Implementation(
hass,
auth_domain,
credential,
authorization_server=await async_get_authorization_server(hass),
)


async def async_get_authorization_server(hass: HomeAssistant) -> AuthorizationServer:
"""Return authorization server."""
return AuthorizationServer(
authorize_url=OAUTH2_AUTHORIZE,
token_url=OAUTH2_TOKEN,
)


async def async_get_description_placeholders(hass: HomeAssistant) -> dict[str, str]:
"""Return description placeholders for the credentials dialog."""
return {
"more_info_url": "https://www.home-assistant.io/integrations/electric_kiwi/"
}
Loading

0 comments on commit 765a439

Please sign in to comment.