Summer update 😎

This commit is contained in:
ludeeus
2019-07-17 13:03:42 +00:00
parent 45617d8515
commit 8457aefc77
22 changed files with 1012 additions and 737 deletions

View File

@ -1,160 +1,159 @@
"""
Component to integrate with blueprint.
For more details about this component, please refer to
https://github.com/custom-components/blueprint
"""
import os
from datetime import timedelta
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import discovery
from homeassistant.util import Throttle
from .const import (
CONF_BINARY_SENSOR,
CONF_ENABLED,
CONF_NAME,
CONF_PASSWORD,
CONF_SENSOR,
CONF_SWITCH,
CONF_USERNAME,
DEFAULT_NAME,
DOMAIN_DATA,
DOMAIN,
ISSUE_URL,
PLATFORMS,
REQUIRED_FILES,
STARTUP,
VERSION,
)
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
_LOGGER = logging.getLogger(__name__)
BINARY_SENSOR_SCHEMA = vol.Schema(
{
vol.Optional(CONF_ENABLED, default=True): cv.boolean,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
)
SENSOR_SCHEMA = vol.Schema(
{
vol.Optional(CONF_ENABLED, default=True): cv.boolean,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
)
SWITCH_SCHEMA = vol.Schema(
{
vol.Optional(CONF_ENABLED, default=True): cv.boolean,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
)
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_BINARY_SENSOR): vol.All(
cv.ensure_list, [BINARY_SENSOR_SCHEMA]
),
vol.Optional(CONF_SENSOR): vol.All(cv.ensure_list, [SENSOR_SCHEMA]),
vol.Optional(CONF_SWITCH): vol.All(cv.ensure_list, [SWITCH_SCHEMA]),
}
)
},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass, config):
"""Set up this component."""
# Import client from a external python package hosted on PyPi
from sampleclient.client import Client
# Print startup message
startup = STARTUP.format(name=DOMAIN, version=VERSION, issueurl=ISSUE_URL)
_LOGGER.info(startup)
# Check that all required files are present
file_check = await check_files(hass)
if not file_check:
return False
# Create DATA dict
hass.data[DOMAIN_DATA] = {}
# Get "global" configuration.
username = config[DOMAIN].get(CONF_USERNAME)
password = config[DOMAIN].get(CONF_PASSWORD)
# Configure the client.
client = Client(username, password)
hass.data[DOMAIN_DATA]["client"] = BlueprintData(hass, client)
# Load platforms
for platform in PLATFORMS:
# Get platform specific configuration
platform_config = config[DOMAIN].get(platform, {})
# If platform is not enabled, skip.
if not platform_config:
continue
for entry in platform_config:
entry_config = entry
_LOGGER.critical(entry_config)
# If entry is not enabled, skip.
if not entry_config[CONF_ENABLED]:
continue
hass.async_create_task(
discovery.async_load_platform(
hass, platform, DOMAIN, entry_config, config
)
)
return True
class BlueprintData:
"""This class handle communication and stores the data."""
def __init__(self, hass, client):
"""Initialize the class."""
self.hass = hass
self.client = client
@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def update_data(self):
"""Update data."""
# This is where the main logic to update platform data goes.
try:
data = self.client.get_data()
self.hass.data[DOMAIN_DATA]["data"] = data
except Exception as error: # pylint: disable=broad-except
_LOGGER.error("Could not update data - %s", error)
async def check_files(hass):
"""Return bool that indicates if all files are present."""
# Verify that the user downloaded all files.
base = "{}/custom_components/{}/".format(hass.config.path(), DOMAIN)
missing = []
for file in REQUIRED_FILES:
fullpath = "{}{}".format(base, file)
if not os.path.exists(fullpath):
missing.append(file)
if missing:
_LOGGER.critical("The following files are missing: %s", str(missing))
returnvalue = False
else:
returnvalue = True
return returnvalue
"""
Component to integrate with blueprint.
For more details about this component, please refer to
https://github.com/custom-components/blueprint
"""
import os
from datetime import timedelta
import logging
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import discovery
from homeassistant.util import Throttle
from .const import (
CONF_BINARY_SENSOR,
CONF_ENABLED,
CONF_NAME,
CONF_PASSWORD,
CONF_SENSOR,
CONF_SWITCH,
CONF_USERNAME,
DEFAULT_NAME,
DOMAIN_DATA,
DOMAIN,
ISSUE_URL,
PLATFORMS,
REQUIRED_FILES,
STARTUP,
VERSION,
)
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=30)
_LOGGER = logging.getLogger(__name__)
BINARY_SENSOR_SCHEMA = vol.Schema(
{
vol.Optional(CONF_ENABLED, default=True): cv.boolean,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
)
SENSOR_SCHEMA = vol.Schema(
{
vol.Optional(CONF_ENABLED, default=True): cv.boolean,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
)
SWITCH_SCHEMA = vol.Schema(
{
vol.Optional(CONF_ENABLED, default=True): cv.boolean,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
}
)
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_BINARY_SENSOR): vol.All(
cv.ensure_list, [BINARY_SENSOR_SCHEMA]
),
vol.Optional(CONF_SENSOR): vol.All(cv.ensure_list, [SENSOR_SCHEMA]),
vol.Optional(CONF_SWITCH): vol.All(cv.ensure_list, [SWITCH_SCHEMA]),
}
)
},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass, config):
"""Set up this component."""
# Import client from a external python package hosted on PyPi
from sampleclient.client import Client
# Print startup message
startup = STARTUP.format(name=DOMAIN, version=VERSION, issueurl=ISSUE_URL)
_LOGGER.info(startup)
# Check that all required files are present
file_check = await check_files(hass)
if not file_check:
return False
# Create DATA dict
hass.data[DOMAIN_DATA] = {}
# Get "global" configuration.
username = config[DOMAIN].get(CONF_USERNAME)
password = config[DOMAIN].get(CONF_PASSWORD)
# Configure the client.
client = Client(username, password)
hass.data[DOMAIN_DATA]["client"] = BlueprintData(hass, client)
# Load platforms
for platform in PLATFORMS:
# Get platform specific configuration
platform_config = config[DOMAIN].get(platform, {})
# If platform is not enabled, skip.
if not platform_config:
continue
for entry in platform_config:
entry_config = entry
# If entry is not enabled, skip.
if not entry_config[CONF_ENABLED]:
continue
hass.async_create_task(
discovery.async_load_platform(
hass, platform, DOMAIN, entry_config, config
)
)
return True
class BlueprintData:
"""This class handle communication and stores the data."""
def __init__(self, hass, client):
"""Initialize the class."""
self.hass = hass
self.client = client
@Throttle(MIN_TIME_BETWEEN_UPDATES)
async def update_data(self):
"""Update data."""
# This is where the main logic to update platform data goes.
try:
data = self.client.get_data()
self.hass.data[DOMAIN_DATA]["data"] = data
except Exception as error: # pylint: disable=broad-except
_LOGGER.error("Could not update data - %s", error)
async def check_files(hass):
"""Return bool that indicates if all files are present."""
# Verify that the user downloaded all files.
base = "{}/custom_components/{}/".format(hass.config.path(), DOMAIN)
missing = []
for file in REQUIRED_FILES:
fullpath = "{}{}".format(base, file)
if not os.path.exists(fullpath):
missing.append(file)
if missing:
_LOGGER.critical("The following files are missing: %s", str(missing))
returnvalue = False
else:
returnvalue = True
return returnvalue

View File

@ -1,59 +1,59 @@
"""Binary sensor platform for blueprint."""
from homeassistant.components.binary_sensor import BinarySensorDevice
from .const import ATTRIBUTION, BINARY_SENSOR_DEVICE_CLASS, DEFAULT_NAME, DOMAIN_DATA
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None
): # pylint: disable=unused-argument
"""Setup binary_sensor platform."""
async_add_entities([BlueprintBinarySensor(hass, discovery_info)], True)
class BlueprintBinarySensor(BinarySensorDevice):
"""blueprint binary_sensor class."""
def __init__(self, hass, config):
self.hass = hass
self.attr = {}
self._status = False
self._name = config.get("name", DEFAULT_NAME)
async def async_update(self):
"""Update the binary_sensor."""
# Send update "signal" to the component
await self.hass.data[DOMAIN_DATA]["client"].update_data()
# Get new data (if any)
updated = self.hass.data[DOMAIN_DATA]["data"].get("data", {})
# Check the data and update the value.
if updated.get("bool_on") is None:
self._status = self._status
else:
self._status = updated.get("bool_on")
# Set/update attributes
self.attr["attribution"] = ATTRIBUTION
self.attr["time"] = str(updated.get("time"))
self.attr["static"] = updated.get("static")
@property
def name(self):
"""Return the name of the binary_sensor."""
return self._name
@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._status
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self.attr
"""Binary sensor platform for blueprint."""
from homeassistant.components.binary_sensor import BinarySensorDevice
from .const import ATTRIBUTION, BINARY_SENSOR_DEVICE_CLASS, DEFAULT_NAME, DOMAIN_DATA
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None
): # pylint: disable=unused-argument
"""Setup binary_sensor platform."""
async_add_entities([BlueprintBinarySensor(hass, discovery_info)], True)
class BlueprintBinarySensor(BinarySensorDevice):
"""blueprint binary_sensor class."""
def __init__(self, hass, config):
self.hass = hass
self.attr = {}
self._status = False
self._name = config.get("name", DEFAULT_NAME)
async def async_update(self):
"""Update the binary_sensor."""
# Send update "signal" to the component
await self.hass.data[DOMAIN_DATA]["client"].update_data()
# Get new data (if any)
updated = self.hass.data[DOMAIN_DATA]["data"].get("data", {})
# Check the data and update the value.
if updated.get("bool_on") is None:
self._status = self._status
else:
self._status = updated.get("bool_on")
# Set/update attributes
self.attr["attribution"] = ATTRIBUTION
self.attr["time"] = str(updated.get("time"))
self.attr["static"] = updated.get("static")
@property
def name(self):
"""Return the name of the binary_sensor."""
return self._name
@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._status
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self.attr

View File

@ -1,42 +1,42 @@
"""Constants for blueprint."""
# Base component constants
DOMAIN = "blueprint"
DOMAIN_DATA = "{}_data".format(DOMAIN)
VERSION = "0.0.1"
PLATFORMS = ["binary_sensor", "sensor", "switch"]
REQUIRED_FILES = [
"binary_sensor.py",
"const.py",
"manifest.json",
"sensor.py",
"switch.py",
]
ISSUE_URL = "https://github.com/custom-components/blueprint/issues"
ATTRIBUTION = "Data from this is provided by blueprint."
STARTUP = """
-------------------------------------------------------------------
{name}
Version: {version}
This is a custom component
If you have any issues with this you need to open an issue here:
{issueurl}
-------------------------------------------------------------------
"""
# Icons
ICON = "mdi:format-quote-close"
# Device classes
BINARY_SENSOR_DEVICE_CLASS = "connectivity"
# Configuration
CONF_BINARY_SENSOR = "binary_sensor"
CONF_SENSOR = "sensor"
CONF_SWITCH = "switch"
CONF_ENABLED = "enabled"
CONF_NAME = "name"
CONF_USERNAME = "username"
CONF_PASSWORD = "password"
# Defaults
DEFAULT_NAME = DOMAIN
"""Constants for blueprint."""
# Base component constants
DOMAIN = "blueprint"
DOMAIN_DATA = "{}_data".format(DOMAIN)
VERSION = "0.0.1"
PLATFORMS = ["binary_sensor", "sensor", "switch"]
REQUIRED_FILES = [
"binary_sensor.py",
"const.py",
"manifest.json",
"sensor.py",
"switch.py",
]
ISSUE_URL = "https://github.com/custom-components/blueprint/issues"
ATTRIBUTION = "Data from this is provided by blueprint."
STARTUP = """
-------------------------------------------------------------------
{name}
Version: {version}
This is a custom component
If you have any issues with this you need to open an issue here:
{issueurl}
-------------------------------------------------------------------
"""
# Icons
ICON = "mdi:format-quote-close"
# Device classes
BINARY_SENSOR_DEVICE_CLASS = "connectivity"
# Configuration
CONF_BINARY_SENSOR = "binary_sensor"
CONF_SENSOR = "sensor"
CONF_SWITCH = "switch"
CONF_ENABLED = "enabled"
CONF_NAME = "name"
CONF_USERNAME = "username"
CONF_PASSWORD = "password"
# Defaults
DEFAULT_NAME = DOMAIN

View File

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

View File

@ -1,59 +1,59 @@
"""Sensor platform for blueprint."""
from homeassistant.helpers.entity import Entity
from .const import ATTRIBUTION, DEFAULT_NAME, DOMAIN_DATA, ICON
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None
): # pylint: disable=unused-argument
"""Setup sensor platform."""
async_add_entities([BlueprintSensor(hass, discovery_info)], True)
class BlueprintSensor(Entity):
"""blueprint Sensor class."""
def __init__(self, hass, config):
self.hass = hass
self.attr = {}
self._state = None
self._name = config.get("name", DEFAULT_NAME)
async def async_update(self):
"""Update the sensor."""
# Send update "signal" to the component
await self.hass.data[DOMAIN_DATA]["client"].update_data()
# Get new data (if any)
updated = self.hass.data[DOMAIN_DATA]["data"].get("data", {})
# Check the data and update the value.
if updated.get("static") is None:
self._state = self._status
else:
self._state = updated.get("static")
# Set/update attributes
self.attr["attribution"] = ATTRIBUTION
self.attr["time"] = str(updated.get("time"))
self.attr["none"] = updated.get("none")
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def icon(self):
"""Return the icon of the sensor."""
return ICON
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self.attr
"""Sensor platform for blueprint."""
from homeassistant.helpers.entity import Entity
from .const import ATTRIBUTION, DEFAULT_NAME, DOMAIN_DATA, ICON
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None
): # pylint: disable=unused-argument
"""Setup sensor platform."""
async_add_entities([BlueprintSensor(hass, discovery_info)], True)
class BlueprintSensor(Entity):
"""blueprint Sensor class."""
def __init__(self, hass, config):
self.hass = hass
self.attr = {}
self._state = None
self._name = config.get("name", DEFAULT_NAME)
async def async_update(self):
"""Update the sensor."""
# Send update "signal" to the component
await self.hass.data[DOMAIN_DATA]["client"].update_data()
# Get new data (if any)
updated = self.hass.data[DOMAIN_DATA]["data"].get("data", {})
# Check the data and update the value.
if updated.get("static") is None:
self._state = self._status
else:
self._state = updated.get("static")
# Set/update attributes
self.attr["attribution"] = ATTRIBUTION
self.attr["time"] = str(updated.get("time"))
self.attr["none"] = updated.get("none")
@property
def name(self):
"""Return the name of the sensor."""
return self._name
@property
def state(self):
"""Return the state of the sensor."""
return self._state
@property
def icon(self):
"""Return the icon of the sensor."""
return ICON
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self.attr

View File

@ -1,64 +1,64 @@
"""Switch platform for blueprint."""
from homeassistant.components.switch import SwitchDevice
from .const import ATTRIBUTION, DEFAULT_NAME, DOMAIN_DATA, ICON
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None
): # pylint: disable=unused-argument
"""Setup switch platform."""
async_add_entities([BlueprintBinarySwitch(hass, discovery_info)], True)
class BlueprintBinarySwitch(SwitchDevice):
"""blueprint switch class."""
def __init__(self, hass, config):
self.hass = hass
self.attr = {}
self._status = False
self._name = config.get("name", DEFAULT_NAME)
async def async_update(self):
"""Update the switch."""
# Send update "signal" to the component
await self.hass.data[DOMAIN_DATA]["client"].update_data()
# Get new data (if any)
updated = self.hass.data[DOMAIN_DATA]["data"].get("data", {})
# Check the data and update the value.
self._status = self.hass.data[DOMAIN_DATA]["client"].client.something
# Set/update attributes
self.attr["attribution"] = ATTRIBUTION
self.attr["time"] = str(updated.get("time"))
self.attr["static"] = updated.get("static")
async def async_turn_on(self, **kwargs): # pylint: disable=unused-argument
"""Turn on the switch."""
await self.hass.data[DOMAIN_DATA]["client"].client.change_something(True)
async def async_turn_off(self, **kwargs): # pylint: disable=unused-argument
"""Turn off the switch."""
await self.hass.data[DOMAIN_DATA]["client"].client.change_something(False)
@property
def name(self):
"""Return the name of the switch."""
return self._name
@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._status
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self.attr
"""Switch platform for blueprint."""
from homeassistant.components.switch import SwitchDevice
from .const import ATTRIBUTION, DEFAULT_NAME, DOMAIN_DATA, ICON
async def async_setup_platform(
hass, config, async_add_entities, discovery_info=None
): # pylint: disable=unused-argument
"""Setup switch platform."""
async_add_entities([BlueprintBinarySwitch(hass, discovery_info)], True)
class BlueprintBinarySwitch(SwitchDevice):
"""blueprint switch class."""
def __init__(self, hass, config):
self.hass = hass
self.attr = {}
self._status = False
self._name = config.get("name", DEFAULT_NAME)
async def async_update(self):
"""Update the switch."""
# Send update "signal" to the component
await self.hass.data[DOMAIN_DATA]["client"].update_data()
# Get new data (if any)
updated = self.hass.data[DOMAIN_DATA]["data"].get("data", {})
# Check the data and update the value.
self._status = self.hass.data[DOMAIN_DATA]["client"].client.something
# Set/update attributes
self.attr["attribution"] = ATTRIBUTION
self.attr["time"] = str(updated.get("time"))
self.attr["static"] = updated.get("static")
async def async_turn_on(self, **kwargs): # pylint: disable=unused-argument
"""Turn on the switch."""
await self.hass.data[DOMAIN_DATA]["client"].client.change_something(True)
async def async_turn_off(self, **kwargs): # pylint: disable=unused-argument
"""Turn off the switch."""
await self.hass.data[DOMAIN_DATA]["client"].client.change_something(False)
@property
def name(self):
"""Return the name of the switch."""
return self._name
@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._status
@property
def device_state_attributes(self):
"""Return the state attributes."""
return self.attr