Initial commit

This commit is contained in:
Brian Berg 2020-06-14 15:01:07 -04:00
commit e86e5b5183
29 changed files with 1075 additions and 0 deletions

43
.devcontainer/README.md Normal file
View File

@ -0,0 +1,43 @@
## Developing with Visual Studio Code + devcontainer
The easiest way to get started with custom integration development is to use Visual Studio Code with devcontainers. This approach will create a preconfigured development environment with all the tools you need.
In the container you will have a dedicated Home Assistant core instance running with your custom compnent code. You can configure this instance by updating the `./devcontainer/configuration.yaml` file.
**Prerequisites**
- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
- Docker
- For Linux, macOS, or Windows 10 Pro/Enterprise/Education use the [current release version of Docker](https://docs.docker.com/install/)
- Windows 10 Home requires [WSL 2](https://docs.microsoft.com/windows/wsl/wsl2-install) and the current Edge version of Docker Desktop (see instructions [here](https://docs.docker.com/docker-for-windows/wsl-tech-preview/)). This can also be used for Windows Pro/Enterprise/Education.
- [Visual Studio code](https://code.visualstudio.com/)
- [Remote - Containers (VSC Extension)][extension-link]
[More info about requirements and devcontainer in general](https://code.visualstudio.com/docs/remote/containers#_getting-started)
[extension-link]: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers
**Getting started:**
1. Fork the repository.
2. Clone the repository to your computer.
3. Open the repository using Visual Studio code.
When you open this repository with Visual Studio code you are asked to "Reopen in Container", this will start the build of the container.
_If you don't see this notification, open the command palette and select `Remote-Containers: Reopen Folder in Container`._
### Tasks
The devcontainter comes with some useful tasks to help you with development, you can start these tasks by opening the command palette and select `Tasks: Run Task` then select the task you want to run.
When a task is currently running (like `Run Home Assistant on port 9123` for the docs), it can be restarted by opening the command palette and selecting `Tasks: Restart Running Task`, then select the task you want to restart.
The available tasks are:
Task | Description
-- | --
Run Home Assistant on port 9123 | Launch Home assistant with your custom compnent code and the configuration defined in `.devcontainer/configuration.yaml`.
Run Home Assistant configuration against /config | Check the configuration.
Upgrade Home Assistant to latest dev | Upgrade the Home Assitant core version in the container to the latest version of the `dev` branch.
Install a spesific version of Home Assistant | Install a specific version of Home Assistant core in the container.

View File

@ -0,0 +1,9 @@
default_config:
automation: !include automations.yaml
logger:
default: error
logs:
custom_components.blueprint: debug

View File

@ -0,0 +1,31 @@
// See https://aka.ms/vscode-remote/devcontainer.json for format details.
{
"image": "ludeeus/container:integration",
"context": "..",
"appPort": [
"9123:8123"
],
"postCreateCommand": "container install",
"runArgs": [
"-v",
"${env:HOME}${env:USERPROFILE}/.ssh:/tmp/.ssh"
],
"extensions": [
"ms-python.python",
"github.vscode-pull-request-github",
"tabnine.tabnine-vscode"
],
"settings": {
"files.eol": "\n",
"editor.tabSize": 4,
"terminal.integrated.shell.linux": "/bin/bash",
"python.pythonPath": "/usr/bin/python3",
"python.linting.pylintEnabled": true,
"python.linting.enabled": true,
"python.formatting.provider": "black",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true
}
}

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto eol=lf

View File

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

42
.github/ISSUE_TEMPLATE/issue.md vendored Normal file
View File

@ -0,0 +1,42 @@
---
name: Issue
about: Create a report to help us improve
---
<!-- Before you open a new issue, search through the existing issues to see if others have had the same problem.
Issues not containing the minimum requirements will be closed:
- Issues without a description (using the header is not good enough) will be closed.
- Issues without debug logging will be closed.
- Issues without configuration will be closed
-->
## Version of the custom_component
<!-- If you are not using the newest version, download and try that before opening an issue
If you are unsure about the version check the const.py file.
-->
## Configuration
```yaml
Add your logs here.
```
## Describe the bug
A clear and concise description of what the bug is.
## Debug log
<!-- To enable debug logs check this https://www.home-assistant.io/components/logger/ -->
```text
Add your logs here.
```

21
.github/workflows/cron.yaml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Cron actions
on:
schedule:
- cron: '0 0 * * *'
jobs:
validate:
runs-on: "ubuntu-latest"
name: Validate
steps:
- uses: "actions/checkout@v2"
- name: HACS validation
uses: "hacs/integration/action@master"
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CATEGORY: "integration"
- name: Hassfest validation
uses: "home-assistant/actions/hassfest@master"

31
.github/workflows/pull.yml vendored Normal file
View File

@ -0,0 +1,31 @@
name: Pull actions
on:
pull_request:
jobs:
validate:
runs-on: "ubuntu-latest"
name: Validate
steps:
- uses: "actions/checkout@v2"
- name: HACS validation
uses: "hacs/integration/action@master"
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CATEGORY: "integration"
- name: Hassfest validation
uses: "home-assistant/actions/hassfest@master"
style:
runs-on: "ubuntu-latest"
name: Check style formatting
steps:
- uses: "actions/checkout@v2"
- uses: "actions/setup-python@v1"
with:
python-version: "3.x"
- run: python3 -m pip install black
- run: black .

34
.github/workflows/push.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Push actions
on:
push:
branches:
- master
- dev
jobs:
validate:
runs-on: "ubuntu-latest"
name: Validate
steps:
- uses: "actions/checkout@v2"
- name: HACS validation
uses: "hacs/integration/action@master"
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CATEGORY: "integration"
- name: Hassfest validation
uses: "home-assistant/actions/hassfest@master"
style:
runs-on: "ubuntu-latest"
name: Check style formatting
steps:
- uses: "actions/checkout@v2"
- uses: "actions/setup-python@v1"
with:
python-version: "3.x"
- run: python3 -m pip install black
- run: black .

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__

29
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Run Home Assistant on port 9123",
"type": "shell",
"command": "container start",
"problemMatcher": []
},
{
"label": "Run Home Assistant configuration against /config",
"type": "shell",
"command": "container check",
"problemMatcher": []
},
{
"label": "Upgrade Home Assistant to latest dev",
"type": "shell",
"command": "container install",
"problemMatcher": []
},
{
"label": "Install a spesific version of Home Assistant",
"type": "shell",
"command": "container set-version",
"problemMatcher": []
}
]
}

61
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,61 @@
# Contribution guidelines
Contributing to this project should be as easy and transparent as possible, whether it's:
- Reporting a bug
- Discussing the current state of the code
- Submitting a fix
- Proposing new features
## Github is used for everything
Github is used to host code, to track issues and feature requests, as well as accept pull requests.
Pull requests are the best way to propose changes to the codebase.
1. Fork the repo and create your branch from `master`.
2. If you've changed something, update the documentation.
3. Make sure your code lints (using black).
4. Test you contribution.
5. Issue that pull request!
## Any contributions you make will be under the MIT Software License
In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern.
## Report bugs using Github's [issues](../../issues)
GitHub issues are used to track public bugs.
Report a bug by [opening a new issue](../../issues/new/choose); it's that easy!
## Write bug reports with detail, background, and sample code
**Great Bug Reports** tend to have:
- A quick summary and/or background
- Steps to reproduce
- Be specific!
- Give sample code if you can.
- What you expected would happen
- What actually happens
- Notes (possibly including why you think this might be happening, or stuff you tried that didn't work)
People *love* thorough bug reports. I'm not even kidding.
## Use a Consistent Coding Style
Use [black](https://github.com/ambv/black) to make sure the code follows the style.
## Test your code modification
This custom component is based on [blueprint template](https://github.com/custom-components/blueprint).
It comes with development environement in a container, easy to launch
if you use Visual Studio Code. With this container you will have a stand alone
Home Assistant instance running and already configured with the included
[`.devcontainer/configuration.yaml`](https://github.com/oncleben31/ha-pool_pump/blob/master/.devcontainer/configuration.yaml)
file.
## License
By contributing, you agree that your contributions will be licensed under its MIT License.

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Joakim Sørensen @ludeeus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

144
README.md Normal file
View File

@ -0,0 +1,144 @@
# Notice
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?
This is simple, by having custom_components look (README + structure) the same
it is easier for developers to help each other and for users to start using them.
If you are a developer and you want to add things to this "blueprint" that you think more
developers will have use for, please open a PR to add it :)
## What?
This repository contains multiple files, here is a overview:
File | Purpose
-- | --
`.devcontainer/*` | Used for development/testing with VSCODE, more info in the readme file in that dir.
`.github/ISSUE_TEMPLATE/feature_request.md` | Template for Feature Requests
`.github/ISSUE_TEMPLATE/issue.md` | Template for issues
`.github/settings.yml` | Probot settings to control the repository settings.
`.vscode/tasks.json` | Tasks for the devcontainer.
`custom_components/blueprint/.translations/*` | [Translation files.](https://developers.home-assistant.io/docs/en/next/internationalization_custom_component_localization.html#translation-strings)
`custom_components/blueprint/__init__.py` | The component file for the integration.
`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.
`custom_components/blueprint/manifest.json` | A [manifest file](https://developers.home-assistant.io/docs/en/creating_integration_manifest.html) for Home Assistant.
`custom_components/blueprint/sensor.py` | Sensor platform for the integration.
`custom_components/blueprint/switch.py` | Switch sensor platform for the integration.
`CONTRIBUTING.md` | Guidelines on how to contribute.
`example.png` | Screenshot that demonstrate how it might look in the UI.
`info.md` | An example on a info file (used by [hacs][hacs]).
`LICENSE` | The license file for the project.
`README.md` | The file you are reading now, should contain info about the integration, installation and configuration instructions.
`requirements.txt` | Python packages used by this integration.
## How?
If you want to use all the potential and features of this blueprint tempalte you
should use Visual Studio Code to develop in a container. In this container you
will have all the tools to ease your python development and a dedicated Home
Assistant core instance to run your integration. See `.devcontainer/README.md` for more information.
If you need to work on the python library in parallel of this integration
(`sampleclient` in this example) there are different options. The following one seems
easy to implement:
- Create a dedicated branch for your python library on a public git repository (example: branch
`dev` on `https://github.com/ludeeus/sampleclient`)
- Update in the `manifest.json` file the `requirements` key to point on your development branch
( example: `"requirements": ["git+https://github.com/ludeeus/sampleclient.git@dev#devp==0.0.1beta1"]`)
- Each time you need to make a modification to your python library, push it to your
development branch and increase the number of the python library version in `manifest.json` file
to ensure Home Assistant update the code of the python library. (example `"requirements": ["git+https://...==0.0.1beta2"]`).
***
README content if this was a published component:
***
# blueprint
[![GitHub Release][releases-shield]][releases]
[![GitHub Activity][commits-shield]][commits]
[![License][license-shield]](LICENSE)
[![hacs][hacsbadge]][hacs]
![Project Maintenance][maintenance-shield]
[![BuyMeCoffee][buymecoffeebadge]][buymecoffee]
[![Discord][discord-shield]][discord]
[![Community Forum][forum-shield]][forum]
_Component to integrate with [blueprint][blueprint]._
**This component will set up the following platforms.**
Platform | Description
-- | --
`binary_sensor` | Show something `True` or `False`.
`sensor` | Show info from blueprint API.
`switch` | Switch something `True` or `False`.
![example][exampleimg]
## Installation
1. Using the tool of choice open the directory (folder) for your HA configuration (where you find `configuration.yaml`).
2. If you do not have a `custom_components` directory (folder) there, you need to create it.
3. In the `custom_components` directory (folder) create a new folder called `blueprint`.
4. Download _all_ the files from the `custom_components/blueprint/` directory (folder) in this repository.
5. Place the files you downloaded in the new directory (folder) you created.
6. Restart Home Assistant
7. In the HA UI go to "Configuration" -> "Integrations" click "+" and search for "Blueprint"
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/__init__.py
custom_components/blueprint/binary_sensor.py
custom_components/blueprint/config_flow.py
custom_components/blueprint/const.py
custom_components/blueprint/manifest.json
custom_components/blueprint/sensor.py
custom_components/blueprint/switch.py
```
## Configuration is done in the UI
<!---->
## Contributions are welcome!
If you want to contribute to this please read the [Contribution guidelines](CONTRIBUTING.md)
***
[blueprint]: https://github.com/custom-components/blueprint
[buymecoffee]: https://www.buymeacoffee.com/ludeeus
[buymecoffeebadge]: https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?style=for-the-badge
[commits-shield]: https://img.shields.io/github/commit-activity/y/custom-components/blueprint.svg?style=for-the-badge
[commits]: https://github.com/custom-components/blueprint/commits/master
[hacs]: https://github.com/custom-components/hacs
[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge
[discord]: https://discord.gg/Qa5fW2R
[discord-shield]: https://img.shields.io/discord/330944238910963714.svg?style=for-the-badge
[exampleimg]: example.png
[forum-shield]: https://img.shields.io/badge/community-forum-brightgreen.svg?style=for-the-badge
[forum]: https://community.home-assistant.io/
[license-shield]: https://img.shields.io/github/license/custom-components/blueprint.svg?style=for-the-badge
[maintenance-shield]: https://img.shields.io/badge/maintainer-Joakim%20Sørensen%20%40ludeeus-blue.svg?style=for-the-badge
[releases-shield]: https://img.shields.io/github/release/custom-components/blueprint.svg?style=for-the-badge
[releases]: https://github.com/custom-components/blueprint/releases

View File

@ -0,0 +1,32 @@
{
"config": {
"title": "Blueprint",
"step": {
"user": {
"title": "Blueprint",
"description": "If you need help with the configuration have a look here: https://github.com/custom-components/blueprint",
"data": {
"username": "Username",
"password": "Password"
}
}
},
"error": {
"auth": "Username/Password is wrong."
},
"abort": {
"single_instance_allowed": "Only a single configuration of Blueprint is allowed."
}
},
"options": {
"step": {
"user": {
"data": {
"binary_sensor": "Binary sensor enabled",
"sensor": "Sensor enabled",
"switch": "Switch enabled"
}
}
}
}
}

View File

@ -0,0 +1,32 @@
{
"config": {
"title": "Blueprint",
"step": {
"user": {
"title": "Blueprint",
"description": "Hvis du trenger hjep til konfigurasjon ta en titt her: https://github.com/custom-components/blueprint",
"data": {
"username": "Brukernavn",
"password": "Passord"
}
}
},
"error": {
"auth": "Brukernavn/Passord er feil."
},
"abort": {
"single_instance_allowed": "Du kan konfigurere Blueprint kun en gang."
}
},
"options": {
"step": {
"user": {
"data": {
"binary_sensor": "Binær sensor aktivert",
"sensor": "Sensor aktivert",
"switch": "Bryter aktivert"
}
}
}
}
}

View File

@ -0,0 +1,5 @@
{
"state": {
"Some sample static text.": "Eksempel tekst."
}
}

View File

@ -0,0 +1,105 @@
"""
Custom integration to integrate blueprint with Home Assistant.
For more details about this integration, please refer to
https://github.com/custom-components/blueprint
"""
import asyncio
from datetime import timedelta
import logging
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import Config, HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from sampleclient.client import Client
from custom_components.blueprint.const import (
CONF_PASSWORD,
CONF_USERNAME,
DOMAIN,
PLATFORMS,
STARTUP_MESSAGE,
)
SCAN_INTERVAL = timedelta(seconds=30)
_LOGGER = logging.getLogger(__name__)
async def async_setup(hass: HomeAssistant, config: Config):
"""Set up this integration using YAML is not supported."""
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Set up this integration using UI."""
if hass.data.get(DOMAIN) is None:
hass.data.setdefault(DOMAIN, {})
_LOGGER.info(STARTUP_MESSAGE)
username = entry.data.get(CONF_USERNAME)
password = entry.data.get(CONF_PASSWORD)
coordinator = BlueprintDataUpdateCoordinator(
hass, username=username, password=password
)
await coordinator.async_refresh()
if not coordinator.last_update_success:
raise ConfigEntryNotReady
hass.data[DOMAIN][entry.entry_id] = coordinator
for platform in PLATFORMS:
if entry.options.get(platform, True):
coordinator.platforms.append(platform)
hass.async_add_job(
hass.config_entries.async_forward_entry_setup(entry, platform)
)
entry.add_update_listener(async_reload_entry)
return True
class BlueprintDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the API."""
def __init__(self, hass, username, password):
"""Initialize."""
self.api = Client(username, password)
self.platforms = []
super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)
async def _async_update_data(self):
"""Update data via library."""
try:
data = await self.api.async_get_data()
return data.get("data", {})
except Exception as exception:
raise UpdateFailed(exception)
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Handle removal of an entry."""
coordinator = hass.data[DOMAIN][entry.entry_id]
unloaded = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(entry, platform)
for platform in PLATFORMS
if platform in coordinator.platforms
]
)
)
if unloaded:
hass.data[DOMAIN].pop(entry.entry_id)
return unloaded
async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry):
"""Reload config entry."""
await async_unload_entry(hass, entry)
await async_setup_entry(hass, entry)

View File

@ -0,0 +1,35 @@
"""Binary sensor platform for blueprint."""
from homeassistant.components.binary_sensor import BinarySensorDevice
from custom_components.blueprint.const import (
BINARY_SENSOR,
BINARY_SENSOR_DEVICE_CLASS,
DEFAULT_NAME,
DOMAIN,
)
from custom_components.blueprint.entity import BlueprintEntity
async def async_setup_entry(hass, entry, async_add_devices):
"""Setup binary_sensor platform."""
coordinator = hass.data[DOMAIN][entry.entry_id]
async_add_devices([BlueprintBinarySensor(coordinator, entry)])
class BlueprintBinarySensor(BlueprintEntity, BinarySensorDevice):
"""blueprint binary_sensor class."""
@property
def name(self):
"""Return the name of the binary_sensor."""
return f"{DEFAULT_NAME}_{BINARY_SENSOR}"
@property
def device_class(self):
"""Return the class of this binary_sensor."""
return BINARY_SENSOR_DEVICE_CLASS
@property
def is_on(self):
"""Return true if the binary_sensor is on."""
return self.coordinator.data.get("bool_on", False)

View File

@ -0,0 +1,108 @@
"""Adds config flow for Blueprint."""
from homeassistant import config_entries
from homeassistant.core import callback
from sampleclient.client import Client
import voluptuous as vol
from custom_components.blueprint.const import ( # pylint: disable=unused-import
CONF_PASSWORD,
CONF_USERNAME,
DOMAIN,
PLATFORMS,
)
class BlueprintFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Config flow for Blueprint."""
VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL
def __init__(self):
"""Initialize."""
self._errors = {}
async def async_step_user(
self, user_input=None # pylint: disable=bad-continuation
):
"""Handle a flow initialized by the user."""
self._errors = {}
# Uncomment the next 2 lines if only a single instance of the integration is allowed:
# if self._async_current_entries():
# return self.async_abort(reason="single_instance_allowed")
if user_input is not None:
valid = await self._test_credentials(
user_input[CONF_USERNAME], user_input[CONF_PASSWORD]
)
if valid:
return self.async_create_entry(
title=user_input[CONF_USERNAME], data=user_input
)
else:
self._errors["base"] = "auth"
return await self._show_config_form(user_input)
return await self._show_config_form(user_input)
@staticmethod
@callback
def async_get_options_flow(config_entry):
return BlueprintOptionsFlowHandler(config_entry)
async def _show_config_form(self, user_input): # pylint: disable=unused-argument
"""Show the configuration form to edit location data."""
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{vol.Required(CONF_USERNAME): str, vol.Required(CONF_PASSWORD): str}
),
errors=self._errors,
)
async def _test_credentials(self, username, password):
"""Return true if credentials is valid."""
try:
client = Client(username, password)
await client.async_get_data()
return True
except Exception: # pylint: disable=broad-except
pass
return False
class BlueprintOptionsFlowHandler(config_entries.OptionsFlow):
"""Blueprint config flow options handler."""
def __init__(self, config_entry):
"""Initialize HACS options flow."""
self.config_entry = config_entry
self.options = dict(config_entry.options)
async def async_step_init(self, user_input=None): # pylint: disable=unused-argument
"""Manage the options."""
return await self.async_step_user()
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
if user_input is not None:
self.options.update(user_input)
return await self._update_options()
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(x, default=self.options.get(x, True)): bool
for x in sorted(PLATFORMS)
}
),
)
async def _update_options(self):
"""Update config entry options."""
return self.async_create_entry(
title=self.config_entry.data.get(CONF_USERNAME), data=self.options
)

View File

@ -0,0 +1,40 @@
"""Constants for blueprint."""
# Base component constants
NAME = "Blueprint"
DOMAIN = "blueprint"
DOMAIN_DATA = f"{DOMAIN}_data"
VERSION = "0.0.1"
ISSUE_URL = "https://github.com/custom-components/blueprint/issues"
# Icons
ICON = "mdi:format-quote-close"
# Device classes
BINARY_SENSOR_DEVICE_CLASS = "connectivity"
# Platforms
BINARY_SENSOR = "binary_sensor"
SENSOR = "sensor"
SWITCH = "switch"
PLATFORMS = [BINARY_SENSOR, SENSOR, SWITCH]
# Configuration and options
CONF_ENABLED = "enabled"
CONF_USERNAME = "username"
CONF_PASSWORD = "password"
# Defaults
DEFAULT_NAME = DOMAIN
STARTUP_MESSAGE = f"""
-------------------------------------------------------------------
{NAME}
Version: {VERSION}
This is a custom integration!
If you have any issues with this you need to open an issue here:
{ISSUE_URL}
-------------------------------------------------------------------
"""

View File

@ -0,0 +1,52 @@
"""BlueprintEntity class"""
from homeassistant.helpers import entity
from custom_components.blueprint.const import DOMAIN, NAME, VERSION
class BlueprintEntity(entity.Entity):
def __init__(self, coordinator, config_entry):
self.coordinator = coordinator
self.config_entry = config_entry
@property
def should_poll(self):
"""No need to poll. Coordinator notifies entity of updates."""
return False
@property
def available(self):
"""Return if entity is available."""
return self.coordinator.last_update_success
@property
def unique_id(self):
"""Return a unique ID to use for this entity."""
return self.config_entry.entry_id
@property
def device_info(self):
return {
"identifiers": {(DOMAIN, self.unique_id)},
"name": NAME,
"model": VERSION,
"manufacturer": NAME,
}
@property
def device_state_attributes(self):
"""Return the state attributes."""
return {
"time": str(self.coordinator.data.get("time")),
"static": self.coordinator.data.get("static"),
}
async def async_added_to_hass(self):
"""Connect to dispatcher listening for entity data notifications."""
self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
async def async_update(self):
"""Update Brother entity."""
await self.coordinator.async_request_refresh()

View File

@ -0,0 +1,13 @@
{
"domain": "blueprint",
"name": "Blueprint",
"documentation": "https://github.com/custom-components/blueprint",
"dependencies": [],
"config_flow": true,
"codeowners": [
"@ludeeus"
],
"requirements": [
"sampleclient"
]
}

View File

@ -0,0 +1,28 @@
"""Sensor platform for blueprint."""
from custom_components.blueprint.const import DEFAULT_NAME, DOMAIN, ICON, SENSOR
from custom_components.blueprint.entity import BlueprintEntity
async def async_setup_entry(hass, entry, async_add_devices):
"""Setup sensor platform."""
coordinator = hass.data[DOMAIN][entry.entry_id]
async_add_devices([BlueprintSensor(coordinator, entry)])
class BlueprintSensor(BlueprintEntity):
"""blueprint Sensor class."""
@property
def name(self):
"""Return the name of the sensor."""
return f"{DEFAULT_NAME}_{SENSOR}"
@property
def state(self):
"""Return the state of the sensor."""
return self.coordinator.data.get("static")
@property
def icon(self):
"""Return the icon of the sensor."""
return ICON

View File

@ -0,0 +1,40 @@
"""Switch platform for blueprint."""
from homeassistant.components.switch import SwitchDevice
from custom_components.blueprint.const import DEFAULT_NAME, DOMAIN, ICON, SWITCH
from custom_components.blueprint.entity import BlueprintEntity
async def async_setup_entry(hass, entry, async_add_devices):
"""Setup sensor platform."""
coordinator = hass.data[DOMAIN][entry.entry_id]
async_add_devices([BlueprintBinarySwitch(coordinator, entry)])
class BlueprintBinarySwitch(BlueprintEntity, SwitchDevice):
"""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.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.async_request_refresh()
@property
def name(self):
"""Return the name of the switch."""
return f"{DEFAULT_NAME}_{SWITCH}"
@property
def icon(self):
"""Return the icon of this switch."""
return ICON
@property
def is_on(self):
"""Return true if the switch is on."""
return self.coordinator.api.something

BIN
example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

11
hacs.json Normal file
View File

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

54
info.md Normal file
View File

@ -0,0 +1,54 @@
[![GitHub Release][releases-shield]][releases]
[![GitHub Activity][commits-shield]][commits]
[![License][license-shield]](LICENSE)
[![hacs][hacsbadge]](hacs)
![Project Maintenance][maintenance-shield]
[![BuyMeCoffee][buymecoffeebadge]][buymecoffee]
[![Discord][discord-shield]][discord]
[![Community Forum][forum-shield]][forum]
_Component to integrate with [blueprint][blueprint]._
**This component will set up the following platforms.**
Platform | Description
-- | --
`binary_sensor` | Show something `True` or `False`.
`sensor` | Show info from blueprint API.
`switch` | Switch something `True` or `False`.
![example][exampleimg]
{% if not installed %}
## Installation
1. Click install.
1. In the HA UI go to "Configuration" -> "Integrations" click "+" and search for "Blueprint".
{% endif %}
## Configuration is done in the UI
<!---->
***
[blueprint]: https://github.com/custom-components/blueprint
[buymecoffee]: https://www.buymeacoffee.com/ludeeus
[buymecoffeebadge]: https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?style=for-the-badge
[commits-shield]: https://img.shields.io/github/commit-activity/y/custom-components/blueprint.svg?style=for-the-badge
[commits]: https://github.com/custom-components/blueprint/commits/master
[hacs]: https://github.com/custom-components/hacs
[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge
[discord]: https://discord.gg/Qa5fW2R
[discord-shield]: https://img.shields.io/discord/330944238910963714.svg?style=for-the-badge
[exampleimg]: example.png
[forum-shield]: https://img.shields.io/badge/community-forum-brightgreen.svg?style=for-the-badge
[forum]: https://community.home-assistant.io/
[license-shield]: https://img.shields.io/github/license/custom-components/blueprint.svg?style=for-the-badge
[maintenance-shield]: https://img.shields.io/badge/maintainer-Joakim%20Sørensen%20%40ludeeus-blue.svg?style=for-the-badge
[releases-shield]: https://img.shields.io/github/release/custom-components/blueprint.svg?style=for-the-badge
[releases]: https://github.com/custom-components/blueprint/releases

35
setup.cfg Normal file
View File

@ -0,0 +1,35 @@
[flake8]
exclude = .venv,.git,.tox,docs,venv,bin,lib,deps,build
doctests = True
# To work with Black
max-line-length = 88
# E501: line too long
# W503: Line break occurred before a binary operator
# E203: Whitespace before ':'
# D202 No blank lines allowed after function docstring
# W504 line break after binary operator
ignore =
E501,
W503,
E203,
D202,
W504
[isort]
# https://github.com/timothycrosley/isort
# https://github.com/timothycrosley/isort/wiki/isort-Settings
# splits long import on multiple lines indented by 4 spaces
multi_line_output = 3
include_trailing_comma=True
force_grid_wrap=0
use_parentheses=True
line_length=88
indent = " "
# by default isort don't check module indexes
not_skip = __init__.py
# will group `import x` and `from x import` of the same module.
force_sort_within_sections = true
sections = FUTURE,STDLIB,INBETWEENS,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
default_section = THIRDPARTY
known_first_party = custom_components.blueprint
combine_as_imports = true