Remove sampleclient (#45)

This commit is contained in:
Joakim Sørensen 2020-11-14 15:27:54 +01:00 committed by GitHub
parent bf76923975
commit 668bd9d0bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 129 additions and 47 deletions

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.pythonPath": "/usr/local/bin/python"
}

View File

@ -4,8 +4,6 @@ The component and platforms in this repository are not meant to be used by a
user, but as a "blueprint" that custom component developers can build
upon, to make more awesome stuff.
This blueprint uses ['sampleclient'](https://github.com/ludeeus/sampleclient) to simulate what you actually might use in your integration.
HAVE FUN! 😎
## Why?
@ -29,6 +27,7 @@ File | Purpose
`.vscode/tasks.json` | Tasks for the devcontainer.
`custom_components/blueprint/translations/*` | [Translation files.](https://developers.home-assistant.io/docs/internationalization/custom_integration)
`custom_components/blueprint/__init__.py` | The component file for the integration.
`custom_components/blueprint/api.py` | This is a sample API client.
`custom_components/blueprint/binary_sensor.py` | Binary sensor platform for the integration.
`custom_components/blueprint/config_flow.py` | Config flow file, this adds the UI configuration possibilities.
`custom_components/blueprint/const.py` | A file to hold shared variables/constants for the entire integration.
@ -104,10 +103,11 @@ Platform | Description
Using your HA configuration directory (folder) as a starting point you should now also have this:
```text
custom_components/blueprint/.translations/en.json
custom_components/blueprint/.translations/nb.json
custom_components/blueprint/.translations/sensor.nb.json
custom_components/blueprint/translations/en.json
custom_components/blueprint/translations/nb.json
custom_components/blueprint/translations/sensor.nb.json
custom_components/blueprint/__init__.py
custom_components/blueprint/api.py
custom_components/blueprint/binary_sensor.py
custom_components/blueprint/config_flow.py
custom_components/blueprint/const.py

View File

@ -11,10 +11,12 @@ import logging
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import Config, HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from sampleclient.client import Client
from custom_components.blueprint.const import (
from .api import BlueprintApiClient
from .const import (
CONF_PASSWORD,
CONF_USERNAME,
DOMAIN,
@ -24,7 +26,7 @@ from custom_components.blueprint.const import (
SCAN_INTERVAL = timedelta(seconds=30)
_LOGGER = logging.getLogger(__name__)
_LOGGER: logging.Logger = logging.getLogger(__package__)
async def async_setup(hass: HomeAssistant, config: Config):
@ -41,9 +43,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
username = entry.data.get(CONF_USERNAME)
password = entry.data.get(CONF_PASSWORD)
coordinator = BlueprintDataUpdateCoordinator(
hass, username=username, password=password
)
session = async_get_clientsession(hass)
client = BlueprintApiClient(username, password, session)
coordinator = BlueprintDataUpdateCoordinator(hass, client=client)
await coordinator.async_refresh()
if not coordinator.last_update_success:
@ -65,9 +68,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
class BlueprintDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the API."""
def __init__(self, hass, username, password):
def __init__(self, hass: HomeAssistant, client: BlueprintApiClient) -> None:
"""Initialize."""
self.api = Client(username, password)
self.api: BlueprintApiClient = client
self.platforms = []
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)
@ -75,13 +78,12 @@ class BlueprintDataUpdateCoordinator(DataUpdateCoordinator):
async def _async_update_data(self):
"""Update data via library."""
try:
data = await self.api.async_get_data()
return data.get("data", {})
return await self.api.async_get_data()
except Exception as exception:
raise UpdateFailed(exception)
raise UpdateFailed() from exception
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Handle removal of an entry."""
coordinator = hass.data[DOMAIN][entry.entry_id]
unloaded = all(
@ -99,7 +101,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
return unloaded
async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry):
async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Reload config entry."""
await async_unload_entry(hass, entry)
await async_setup_entry(hass, entry)

View File

@ -0,0 +1,75 @@
"""Sample API Client."""
import logging
import asyncio
import socket
from typing import Optional
import aiohttp
import async_timeout
TIMEOUT = 10
_LOGGER: logging.Logger = logging.getLogger(__package__)
HEADERS = {"Content-type": "application/json; charset=UTF-8"}
class BlueprintApiClient:
def __init__(
self, username: str, password: str, session: aiohttp.ClientSession
) -> None:
"""Sample API Client."""
self._username = username
self._passeword = password
self._session = session
async def async_get_data(self) -> dict:
"""Get data from the API."""
url = "https://jsonplaceholder.typicode.com/posts/1"
return await self.api_wrapper("get", url)
async def async_set_title(self, value: str) -> None:
"""Get data from the API."""
url = "https://jsonplaceholder.typicode.com/posts/1"
await self.api_wrapper("patch", url, data={"title": value}, headers=HEADERS)
async def api_wrapper(
self, method: str, url: str, data: dict = {}, headers: dict = {}
) -> dict:
"""Get information from the API."""
try:
async with async_timeout.timeout(TIMEOUT, loop=asyncio.get_event_loop()):
if method == "get":
response = await self._session.get(url, headers=headers)
return await response.json()
elif method == "put":
await self._session.put(url, headers=headers, json=data)
elif method == "patch":
await self._session.patch(url, headers=headers, json=data)
elif method == "post":
await self._session.post(url, headers=headers, json=data)
except asyncio.TimeoutError as exception:
_LOGGER.error(
"Timeout error fetching information from %s - %s",
url,
exception,
)
except (KeyError, TypeError) as exception:
_LOGGER.error(
"Error parsing information from %s - %s",
url,
exception,
)
except (aiohttp.ClientError, socket.gaierror) as exception:
_LOGGER.error(
"Error fetching information from %s - %s",
url,
exception,
)
except Exception as exception: # pylint: disable=broad-except
_LOGGER.error("Something really wrong happend! - %s", exception)

View File

@ -1,13 +1,13 @@
"""Binary sensor platform for blueprint."""
from homeassistant.components.binary_sensor import BinarySensorDevice
from custom_components.blueprint.const import (
from .const import (
BINARY_SENSOR,
BINARY_SENSOR_DEVICE_CLASS,
DEFAULT_NAME,
DOMAIN,
)
from custom_components.blueprint.entity import BlueprintEntity
from .entity import BlueprintEntity
async def async_setup_entry(hass, entry, async_add_devices):
@ -32,4 +32,4 @@ class BlueprintBinarySensor(BlueprintEntity, BinarySensorDevice):
@property
def is_on(self):
"""Return true if the binary_sensor is on."""
return self.coordinator.data.get("bool_on", False)
return self.coordinator.data.get("title", "") == "foo"

View File

@ -1,10 +1,11 @@
"""Adds config flow for Blueprint."""
from homeassistant import config_entries
from homeassistant.core import callback
from sampleclient.client import Client
from homeassistant.helpers.aiohttp_client import async_create_clientsession
import voluptuous as vol
from custom_components.blueprint.const import ( # pylint: disable=unused-import
from .api import BlueprintApiClient
from .const import (
CONF_PASSWORD,
CONF_USERNAME,
DOMAIN,
@ -22,9 +23,7 @@ class BlueprintFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Initialize."""
self._errors = {}
async def async_step_user(
self, user_input=None # pylint: disable=bad-continuation
):
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
self._errors = {}
@ -65,7 +64,8 @@ class BlueprintFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
async def _test_credentials(self, username, password):
"""Return true if credentials is valid."""
try:
client = Client(username, password)
session = async_create_clientsession(self.hass)
client = BlueprintApiClient(username, password, session)
await client.async_get_data()
return True
except Exception: # pylint: disable=broad-except

View File

@ -4,7 +4,7 @@ NAME = "Blueprint"
DOMAIN = "blueprint"
DOMAIN_DATA = f"{DOMAIN}_data"
VERSION = "0.0.1"
ATTRIBUTION = "Data provided by http://jsonplaceholder.typicode.com/"
ISSUE_URL = "https://github.com/custom-components/blueprint/issues"
# Icons

View File

@ -1,7 +1,7 @@
"""BlueprintEntity class"""
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from custom_components.blueprint.const import DOMAIN, NAME, VERSION
from .const import DOMAIN, NAME, VERSION, ATTRIBUTION
class BlueprintEntity(CoordinatorEntity):
@ -27,6 +27,7 @@ class BlueprintEntity(CoordinatorEntity):
def device_state_attributes(self):
"""Return the state attributes."""
return {
"time": str(self.coordinator.data.get("time")),
"static": self.coordinator.data.get("static"),
"attribution": ATTRIBUTION,
"id": str(self.coordinator.data.get("id")),
"integration": DOMAIN,
}

View File

@ -2,12 +2,11 @@
"domain": "blueprint",
"name": "Blueprint",
"documentation": "https://github.com/custom-components/blueprint",
"issue_tracker": "https://github.com/custom-components/blueprint/issues",
"dependencies": [],
"config_flow": true,
"codeowners": [
"@ludeeus"
],
"requirements": [
"sampleclient"
]
"requirements": []
}

View File

@ -1,6 +1,6 @@
"""Sensor platform for blueprint."""
from custom_components.blueprint.const import DEFAULT_NAME, DOMAIN, ICON, SENSOR
from custom_components.blueprint.entity import BlueprintEntity
from .const import DEFAULT_NAME, DOMAIN, ICON, SENSOR
from .entity import BlueprintEntity
async def async_setup_entry(hass, entry, async_add_devices):
@ -20,7 +20,7 @@ class BlueprintSensor(BlueprintEntity):
@property
def state(self):
"""Return the state of the sensor."""
return self.coordinator.data.get("static")
return self.coordinator.data.get("body")
@property
def icon(self):

View File

@ -1,8 +1,8 @@
"""Switch platform for blueprint."""
from homeassistant.components.switch import SwitchDevice
from homeassistant.components.switch import SwitchEntity
from custom_components.blueprint.const import DEFAULT_NAME, DOMAIN, ICON, SWITCH
from custom_components.blueprint.entity import BlueprintEntity
from .const import DEFAULT_NAME, DOMAIN, ICON, SWITCH
from .entity import BlueprintEntity
async def async_setup_entry(hass, entry, async_add_devices):
@ -11,17 +11,17 @@ async def async_setup_entry(hass, entry, async_add_devices):
async_add_devices([BlueprintBinarySwitch(coordinator, entry)])
class BlueprintBinarySwitch(BlueprintEntity, SwitchDevice):
class BlueprintBinarySwitch(BlueprintEntity, SwitchEntity):
"""blueprint switch class."""
async def async_turn_on(self, **kwargs): # pylint: disable=unused-argument
"""Turn on the switch."""
await self.coordinator.api.async_change_something(True)
await self.coordinator.api.async_set_title("bar")
await self.coordinator.async_request_refresh()
async def async_turn_off(self, **kwargs): # pylint: disable=unused-argument
"""Turn off the switch."""
await self.coordinator.api.async_change_something(False)
await self.coordinator.api.async_set_title("foo")
await self.coordinator.async_request_refresh()
@property
@ -37,4 +37,4 @@ class BlueprintBinarySwitch(BlueprintEntity, SwitchDevice):
@property
def is_on(self):
"""Return true if the switch is on."""
return self.coordinator.api.something
return self.coordinator.data.get("title", "") == "foo"

View File

@ -1,11 +1,11 @@
{
"name": "Blueprint",
"hacs": "0.24.0",
"hacs": "1.6.0",
"domains": [
"binary_sensor",
"sensor",
"switch"
],
"iot_class": "Cloud Polling",
"homeassistant": "0.115.0"
"homeassistant": "0.118.0"
}

View File

@ -16,7 +16,7 @@ _Component to integrate with [blueprint][blueprint]._
Platform | Description
-- | --
`binary_sensor` | Show something `True` or `False`.
`sensor` | Show info from blueprint API.
`sensor` | Show info from API.
`switch` | Switch something `True` or `False`.
![example][exampleimg]