mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
Move examples out (#6908)
* Remove examples from main repo * Simplify README * Point screenshot for components at dev branch for now
This commit is contained in:
parent
f0027e3cc1
commit
36e5878b2e
11
.gitignore
vendored
11
.gitignore
vendored
@ -1,15 +1,4 @@
|
|||||||
config/*
|
config/*
|
||||||
!config/home-assistant.conf.default
|
|
||||||
|
|
||||||
# There is not a better solution afaik..
|
|
||||||
!config/custom_components
|
|
||||||
config/custom_components/*
|
|
||||||
!config/custom_components/example.py
|
|
||||||
!config/custom_components/hello_world.py
|
|
||||||
!config/custom_components/mqtt_example.py
|
|
||||||
!config/panels
|
|
||||||
config/panels/*
|
|
||||||
!config/panels/react.html
|
|
||||||
|
|
||||||
tests/testing_config/deps
|
tests/testing_config/deps
|
||||||
tests/testing_config/home-assistant.log
|
tests/testing_config/home-assistant.log
|
||||||
|
82
README.rst
82
README.rst
@ -1,9 +1,7 @@
|
|||||||
Home Assistant |Build Status| |Coverage Status| |Join the chat at https://gitter.im/home-assistant/home-assistant| |Join the dev chat at https://gitter.im/home-assistant/home-assistant/devs|
|
Home Assistant |Build Status| |Coverage Status| |Join the chat at https://gitter.im/home-assistant/home-assistant| |Join the dev chat at https://gitter.im/home-assistant/home-assistant/devs|
|
||||||
==============================================================================================================================================================================================
|
==============================================================================================================================================================================================
|
||||||
|
|
||||||
Home Assistant is a home automation platform running on Python 3. The
|
Home Assistant is a home automation platform running on Python 3. It is to be able to track and control all devices at home and offer a platform for automating control.
|
||||||
goal of Home Assistant is to be able to track and control all devices at
|
|
||||||
home and offer a platform for automating control.
|
|
||||||
|
|
||||||
To get started:
|
To get started:
|
||||||
|
|
||||||
@ -12,83 +10,19 @@ To get started:
|
|||||||
python3 -m pip install homeassistant
|
python3 -m pip install homeassistant
|
||||||
hass --open-ui
|
hass --open-ui
|
||||||
|
|
||||||
Check out `the website <https://home-assistant.io>`__ for `a
|
Check out `home-assistant.io <https://home-assistant.io>`__ for `a
|
||||||
demo <https://home-assistant.io/demo/>`__, installation instructions,
|
demo <https://home-assistant.io/demo/>`__, `installation instructions <https://home-assistant.io/getting-started/>`__,
|
||||||
tutorials and documentation.
|
`tutorials <https://home-assistant.io/getting-started/automation-2/>`__ and `documentation <https://home-assistant.io/docs/>`__.
|
||||||
|
|
||||||
|screenshot-states|
|
|screenshot-states|
|
||||||
|
|
||||||
Examples of devices Home Assistant can interface with:
|
|screenshot-components|
|
||||||
|
|
||||||
- Monitoring connected devices to a wireless router:
|
The system is built using a modular approach so support for other devices or actions can be implemented easily. See also the `section on architecture <https://home-assistant.io/developers/architecture/>`__ and the `section on creating your own
|
||||||
`OpenWrt <https://openwrt.org/>`__,
|
|
||||||
`Tomato <http://www.polarcloud.com/tomato>`__,
|
|
||||||
`Netgear <http://netgear.com>`__,
|
|
||||||
`DD-WRT <http://www.dd-wrt.com/site/index>`__,
|
|
||||||
`TPLink <http://www.tp-link.us/>`__,
|
|
||||||
`ASUSWRT <http://event.asus.com/2013/nw/ASUSWRT/>`__,
|
|
||||||
`Xiaomi <http://miwifi.com/>`__ and any SNMP
|
|
||||||
capable Linksys WAP/WRT
|
|
||||||
- `Philips Hue <http://meethue.com>`__ lights,
|
|
||||||
`WeMo <http://www.belkin.com/us/Products/home-automation/c/wemo-home-automation/>`__
|
|
||||||
switches, `Edimax <http://www.edimax.com/>`__ switches,
|
|
||||||
`Efergy <https://efergy.com>`__ energy monitoring, and
|
|
||||||
`Tellstick <http://www.telldus.se/products/tellstick>`__ devices and
|
|
||||||
sensors
|
|
||||||
- `Google
|
|
||||||
Chromecasts <http://www.google.com/intl/en/chrome/devices/chromecast>`__,
|
|
||||||
`Music Player Daemon <http://www.musicpd.org/>`__, `Logitech
|
|
||||||
Squeezebox <https://en.wikipedia.org/wiki/Squeezebox_%28network_music_player%29>`__,
|
|
||||||
`Plex <https://plex.tv/>`__, `Kodi (XBMC) <http://kodi.tv/>`__,
|
|
||||||
iTunes (by way of
|
|
||||||
`itunes-api <https://github.com/maddox/itunes-api>`__), and Amazon
|
|
||||||
Fire TV (by way of
|
|
||||||
`python-firetv <https://github.com/happyleavesaoc/python-firetv>`__)
|
|
||||||
- Support for
|
|
||||||
`ISY994 <https://www.universal-devices.com/residential/isy994i-series/>`__
|
|
||||||
(Insteon and X10 devices), `Z-Wave <http://www.z-wave.com/>`__, `Nest
|
|
||||||
Thermostats <https://nest.com/>`__,
|
|
||||||
`RFXtrx <http://www.rfxcom.com/>`__,
|
|
||||||
`Arduino <https://www.arduino.cc/>`__, `Raspberry
|
|
||||||
Pi <https://www.raspberrypi.org/>`__, and
|
|
||||||
`Modbus <http://www.modbus.org/>`__
|
|
||||||
- Interaction with `IFTTT <https://ifttt.com/>`__
|
|
||||||
- Integrate data from the `Bitcoin <https://bitcoin.org>`__ network,
|
|
||||||
meteorological data from
|
|
||||||
`OpenWeatherMap <http://openweathermap.org/>`__ and
|
|
||||||
`Forecast.io <https://forecast.io/>`__,
|
|
||||||
`Transmission <http://www.transmissionbt.com/>`__, or
|
|
||||||
`SABnzbd <http://sabnzbd.org>`__.
|
|
||||||
- `See full list of supported
|
|
||||||
devices <https://home-assistant.io/components/>`__
|
|
||||||
|
|
||||||
Build home automation on top of your devices:
|
|
||||||
|
|
||||||
- Keep a precise history of every change to the state of your house
|
|
||||||
- Turn on the lights when people get home after sunset
|
|
||||||
- Turn on lights slowly during sunset to compensate for less light
|
|
||||||
- Turn off all lights and devices when everybody leaves the house
|
|
||||||
- Offers a `REST API <https://home-assistant.io/developers/rest_api/>`__
|
|
||||||
and can interface with MQTT for easy integration with other projects
|
|
||||||
like `OwnTracks <http://owntracks.org/>`__
|
|
||||||
- Allow sending notifications using
|
|
||||||
`Instapush <https://instapush.im>`__, `Notify My Android
|
|
||||||
(NMA) <http://www.notifymyandroid.com/>`__,
|
|
||||||
`PushBullet <https://www.pushbullet.com/>`__,
|
|
||||||
`PushOver <https://pushover.net/>`__,
|
|
||||||
`Slack <https://slack.com/>`__,
|
|
||||||
`Telegram <https://telegram.org/>`__, `Join <http://joaoapps.com/join/>`__, and `Jabber
|
|
||||||
(XMPP) <http://xmpp.org>`__
|
|
||||||
|
|
||||||
The system is built using a modular approach so support for other devices or actions can
|
|
||||||
be implemented easily. See also the `section on
|
|
||||||
architecture <https://home-assistant.io/developers/architecture/>`__
|
|
||||||
and the `section on creating your own
|
|
||||||
components <https://home-assistant.io/developers/creating_components/>`__.
|
components <https://home-assistant.io/developers/creating_components/>`__.
|
||||||
|
|
||||||
If you run into issues while using Home Assistant or during development
|
If you run into issues while using Home Assistant or during development
|
||||||
of a component, check the `Home Assistant help
|
of a component, check the `Home Assistant help section <https://home-assistant.io/help/>`__ of our website for further help and information.
|
||||||
section <https://home-assistant.io/help/>`__ of our website for further help and information.
|
|
||||||
|
|
||||||
.. |Build Status| image:: https://travis-ci.org/home-assistant/home-assistant.svg?branch=master
|
.. |Build Status| image:: https://travis-ci.org/home-assistant/home-assistant.svg?branch=master
|
||||||
:target: https://travis-ci.org/home-assistant/home-assistant
|
:target: https://travis-ci.org/home-assistant/home-assistant
|
||||||
@ -100,3 +34,5 @@ section <https://home-assistant.io/help/>`__ of our website for further help and
|
|||||||
:target: https://gitter.im/home-assistant/home-assistant/devs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
:target: https://gitter.im/home-assistant/home-assistant/devs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||||
.. |screenshot-states| image:: https://raw.github.com/home-assistant/home-assistant/master/docs/screenshots.png
|
.. |screenshot-states| image:: https://raw.github.com/home-assistant/home-assistant/master/docs/screenshots.png
|
||||||
:target: https://home-assistant.io/demo/
|
:target: https://home-assistant.io/demo/
|
||||||
|
.. |screenshot-components| image:: https://raw.github.com/home-assistant/home-assistant/dev/docs/screenshot-components.png
|
||||||
|
:target: https://home-assistant.io/components/
|
@ -1,158 +0,0 @@
|
|||||||
homeassistant:
|
|
||||||
# Omitted values in this section will be auto detected using freegeoip.io
|
|
||||||
|
|
||||||
# Location required to calculate the time the sun rises and sets.
|
|
||||||
# Coordinates are also used for location for weather related components.
|
|
||||||
# Google Maps can be used to determine more precise GPS coordinates.
|
|
||||||
latitude: 32.87336
|
|
||||||
longitude: 117.22743
|
|
||||||
|
|
||||||
# Impacts weather/sunrise data
|
|
||||||
elevation: 665
|
|
||||||
|
|
||||||
# 'metric' for Metric System, 'imperial' for imperial system
|
|
||||||
unit_system: metric
|
|
||||||
|
|
||||||
# Pick yours from here:
|
|
||||||
# http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
|
||||||
time_zone: America/Los_Angeles
|
|
||||||
|
|
||||||
# Name of the location where Home Assistant is running
|
|
||||||
name: Home
|
|
||||||
|
|
||||||
http:
|
|
||||||
api_password: mypass
|
|
||||||
# Set to 1 to enable development mode
|
|
||||||
# development: 1
|
|
||||||
|
|
||||||
# Enable the frontend
|
|
||||||
frontend:
|
|
||||||
|
|
||||||
light:
|
|
||||||
# platform: hue
|
|
||||||
|
|
||||||
wink:
|
|
||||||
# Get your token at https://winkbearertoken.appspot.com
|
|
||||||
access_token: 'YOUR_TOKEN'
|
|
||||||
|
|
||||||
device_tracker:
|
|
||||||
# The following tracker are available:
|
|
||||||
# https://home-assistant.io/components/#presence-detection
|
|
||||||
platform: netgear
|
|
||||||
host: 192.168.1.1
|
|
||||||
username: admin
|
|
||||||
password: PASSWORD
|
|
||||||
|
|
||||||
switch:
|
|
||||||
platform: wemo
|
|
||||||
|
|
||||||
climate:
|
|
||||||
platform: nest
|
|
||||||
# Required: username and password that are used to login to the Nest thermostat.
|
|
||||||
username: myemail@mydomain.com
|
|
||||||
password: mypassword
|
|
||||||
|
|
||||||
downloader:
|
|
||||||
download_dir: downloads
|
|
||||||
|
|
||||||
notify:
|
|
||||||
platform: pushbullet
|
|
||||||
api_key: ABCDEFGHJKLMNOPQRSTUVXYZ
|
|
||||||
|
|
||||||
device_sun_light_trigger:
|
|
||||||
# Optional: specify a specific light/group of lights that has to be turned on
|
|
||||||
light_group: group.living_room
|
|
||||||
# Optional: specify which light profile to use when turning lights on
|
|
||||||
light_profile: relax
|
|
||||||
# Optional: disable lights being turned off when everybody leaves the house
|
|
||||||
# disable_turn_off: 1
|
|
||||||
|
|
||||||
# A comma separated list of states that have to be tracked as a single group
|
|
||||||
# Grouped states should share the same type of states (ON/OFF or HOME/NOT_HOME)
|
|
||||||
# You can also have groups within groups.
|
|
||||||
# https://home-assistant.io/components/group/
|
|
||||||
group:
|
|
||||||
default_view:
|
|
||||||
view: yes
|
|
||||||
entities:
|
|
||||||
- group.awesome_people
|
|
||||||
- group.climate
|
|
||||||
kitchen:
|
|
||||||
name: Kitchen
|
|
||||||
entities:
|
|
||||||
- switch.kitchen_pin_3
|
|
||||||
upstairs:
|
|
||||||
name: Kids
|
|
||||||
icon: mdi:account-multiple
|
|
||||||
view: yes
|
|
||||||
entities:
|
|
||||||
- input_boolean.notify_home
|
|
||||||
- camera.demo_camera
|
|
||||||
|
|
||||||
browser:
|
|
||||||
keyboard:
|
|
||||||
|
|
||||||
# https://home-assistant.io/getting-started/automation/
|
|
||||||
automation:
|
|
||||||
- alias: Turn on light when sun sets
|
|
||||||
trigger:
|
|
||||||
platform: sun
|
|
||||||
event: sunset
|
|
||||||
offset: "-01:00:00"
|
|
||||||
condition:
|
|
||||||
condition: state
|
|
||||||
entity_id: group.all_devices
|
|
||||||
state: 'home'
|
|
||||||
action:
|
|
||||||
service: light.turn_on
|
|
||||||
|
|
||||||
# Another way to do is to collect all entries under one "sensor:"
|
|
||||||
# sensor:
|
|
||||||
# - platform: mqtt
|
|
||||||
# name: "MQTT Sensor 1"
|
|
||||||
# - platform: mqtt
|
|
||||||
# name: "MQTT Sensor 2"
|
|
||||||
#
|
|
||||||
# Details: https://home-assistant.io/getting-started/devices/
|
|
||||||
|
|
||||||
sensor:
|
|
||||||
platform: systemmonitor
|
|
||||||
resources:
|
|
||||||
- type: 'disk_use_percent'
|
|
||||||
arg: '/'
|
|
||||||
- type: 'disk_use_percent'
|
|
||||||
arg: '/home'
|
|
||||||
|
|
||||||
sensor 2:
|
|
||||||
platform: cpuspeed
|
|
||||||
|
|
||||||
script:
|
|
||||||
wakeup:
|
|
||||||
alias: Wake Up
|
|
||||||
sequence:
|
|
||||||
- event: LOGBOOK_ENTRY
|
|
||||||
event_data:
|
|
||||||
name: Paulus
|
|
||||||
message: is waking up
|
|
||||||
entity_id: device_tracker.paulus
|
|
||||||
domain: light
|
|
||||||
- alias: Bedroom lights on
|
|
||||||
service: light.turn_on
|
|
||||||
data:
|
|
||||||
entity_id: group.bedroom
|
|
||||||
brightness: 100
|
|
||||||
- delay:
|
|
||||||
minutes: 1
|
|
||||||
- alias: Living room lights on
|
|
||||||
service: light.turn_on
|
|
||||||
data:
|
|
||||||
entity_id: group.living_room
|
|
||||||
|
|
||||||
scene:
|
|
||||||
- name: Romantic
|
|
||||||
entities:
|
|
||||||
light.tv_back_light: on
|
|
||||||
light.ceiling:
|
|
||||||
state: on
|
|
||||||
xy_color: [0.33, 0.66]
|
|
||||||
brightness: 200
|
|
@ -1,149 +0,0 @@
|
|||||||
"""
|
|
||||||
Example of a custom component.
|
|
||||||
|
|
||||||
Example component to target an entity_id to:
|
|
||||||
- turn it on at 7AM in the morning
|
|
||||||
- turn it on if anyone comes home and it is off
|
|
||||||
- turn it off if all lights are turned off
|
|
||||||
- turn it off if all people leave the house
|
|
||||||
- offer a service to turn it on for 10 seconds
|
|
||||||
|
|
||||||
Configuration:
|
|
||||||
|
|
||||||
To use the Example custom component you will need to add the following to
|
|
||||||
your configuration.yaml file.
|
|
||||||
|
|
||||||
example:
|
|
||||||
target: TARGET_ENTITY
|
|
||||||
|
|
||||||
Variable:
|
|
||||||
|
|
||||||
target
|
|
||||||
*Required
|
|
||||||
TARGET_ENTITY should be one of your devices that can be turned on and off,
|
|
||||||
ie a light or a switch. Example value could be light.Ceiling or switch.AC
|
|
||||||
(if you have these devices with those names).
|
|
||||||
"""
|
|
||||||
import time
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from homeassistant.const import STATE_HOME, STATE_NOT_HOME, STATE_ON, STATE_OFF
|
|
||||||
from homeassistant.helpers import validate_config
|
|
||||||
from homeassistant.helpers.event_decorators import \
|
|
||||||
track_state_change, track_time_change
|
|
||||||
from homeassistant.helpers.service import service
|
|
||||||
import homeassistant.components as core
|
|
||||||
from homeassistant.components import device_tracker
|
|
||||||
from homeassistant.components import light
|
|
||||||
|
|
||||||
# The domain of your component. Should be equal to the name of your component.
|
|
||||||
DOMAIN = "example"
|
|
||||||
|
|
||||||
# List of component names (string) your component depends upon.
|
|
||||||
# We depend on group because group will be loaded after all the components that
|
|
||||||
# initialize devices have been setup.
|
|
||||||
DEPENDENCIES = ['group', 'device_tracker', 'light']
|
|
||||||
|
|
||||||
# Configuration key for the entity id we are targeting.
|
|
||||||
CONF_TARGET = 'target'
|
|
||||||
|
|
||||||
# Variable for storing configuration parameters.
|
|
||||||
TARGET_ID = None
|
|
||||||
|
|
||||||
# Name of the service that we expose.
|
|
||||||
SERVICE_FLASH = 'flash'
|
|
||||||
|
|
||||||
# Shortcut for the logger
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
|
||||||
"""Setup example component."""
|
|
||||||
global TARGET_ID
|
|
||||||
|
|
||||||
# Validate that all required config options are given.
|
|
||||||
if not validate_config(config, {DOMAIN: [CONF_TARGET]}, _LOGGER):
|
|
||||||
return False
|
|
||||||
|
|
||||||
TARGET_ID = config[DOMAIN][CONF_TARGET]
|
|
||||||
|
|
||||||
# Validate that the target entity id exists.
|
|
||||||
if hass.states.get(TARGET_ID) is None:
|
|
||||||
_LOGGER.error("Target entity id %s does not exist",
|
|
||||||
TARGET_ID)
|
|
||||||
|
|
||||||
# Tell the bootstrapper that we failed to initialize and clear the
|
|
||||||
# stored target id so our functions don't run.
|
|
||||||
TARGET_ID = None
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Tell the bootstrapper that we initialized successfully.
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
@track_state_change(device_tracker.ENTITY_ID_ALL_DEVICES)
|
|
||||||
def track_devices(hass, entity_id, old_state, new_state):
|
|
||||||
"""Called when the group.all devices change state."""
|
|
||||||
# If the target id is not set, return
|
|
||||||
if not TARGET_ID:
|
|
||||||
return
|
|
||||||
|
|
||||||
# If anyone comes home and the entity is not on, turn it on.
|
|
||||||
if new_state.state == STATE_HOME and not core.is_on(hass, TARGET_ID):
|
|
||||||
|
|
||||||
core.turn_on(hass, TARGET_ID)
|
|
||||||
|
|
||||||
# If all people leave the house and the entity is on, turn it off.
|
|
||||||
elif new_state.state == STATE_NOT_HOME and core.is_on(hass, TARGET_ID):
|
|
||||||
|
|
||||||
core.turn_off(hass, TARGET_ID)
|
|
||||||
|
|
||||||
|
|
||||||
@track_time_change(hour=7, minute=0, second=0)
|
|
||||||
def wake_up(hass, now):
|
|
||||||
"""Turn light on in the morning.
|
|
||||||
|
|
||||||
Turn the light on at 7 AM if there are people home and it is not already
|
|
||||||
on.
|
|
||||||
"""
|
|
||||||
if not TARGET_ID:
|
|
||||||
return
|
|
||||||
|
|
||||||
if device_tracker.is_on(hass) and not core.is_on(hass, TARGET_ID):
|
|
||||||
_LOGGER.info('People home at 7AM, turning it on')
|
|
||||||
core.turn_on(hass, TARGET_ID)
|
|
||||||
|
|
||||||
|
|
||||||
@track_state_change(light.ENTITY_ID_ALL_LIGHTS, STATE_ON, STATE_OFF)
|
|
||||||
def all_lights_off(hass, entity_id, old_state, new_state):
|
|
||||||
"""If all lights turn off, turn off."""
|
|
||||||
if not TARGET_ID:
|
|
||||||
return
|
|
||||||
|
|
||||||
if core.is_on(hass, TARGET_ID):
|
|
||||||
_LOGGER.info('All lights have been turned off, turning it off')
|
|
||||||
core.turn_off(hass, TARGET_ID)
|
|
||||||
|
|
||||||
|
|
||||||
@service(DOMAIN, SERVICE_FLASH)
|
|
||||||
def flash_service(hass, call):
|
|
||||||
"""Service that will toggle the target.
|
|
||||||
|
|
||||||
Set the light to off for 10 seconds if on and vice versa.
|
|
||||||
"""
|
|
||||||
if not TARGET_ID:
|
|
||||||
return
|
|
||||||
|
|
||||||
if core.is_on(hass, TARGET_ID):
|
|
||||||
core.turn_off(hass, TARGET_ID)
|
|
||||||
|
|
||||||
time.sleep(10)
|
|
||||||
|
|
||||||
core.turn_on(hass, TARGET_ID)
|
|
||||||
|
|
||||||
else:
|
|
||||||
core.turn_on(hass, TARGET_ID)
|
|
||||||
|
|
||||||
time.sleep(10)
|
|
||||||
|
|
||||||
core.turn_off(hass, TARGET_ID)
|
|
@ -1,27 +0,0 @@
|
|||||||
"""
|
|
||||||
The "hello world" custom component.
|
|
||||||
|
|
||||||
This component implements the bare minimum that a component should implement.
|
|
||||||
|
|
||||||
Configuration:
|
|
||||||
|
|
||||||
To use the hello_word component you will need to add the following to your
|
|
||||||
configuration.yaml file.
|
|
||||||
|
|
||||||
hello_world:
|
|
||||||
"""
|
|
||||||
|
|
||||||
# The domain of your component. Should be equal to the name of your component.
|
|
||||||
DOMAIN = "hello_world"
|
|
||||||
|
|
||||||
# List of component names (string) your component depends upon.
|
|
||||||
DEPENDENCIES = []
|
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
|
||||||
"""Setup our skeleton component."""
|
|
||||||
# States are in the format DOMAIN.OBJECT_ID.
|
|
||||||
hass.states.set('hello_world.Hello_World', 'Works!')
|
|
||||||
|
|
||||||
# Return boolean to indicate that initialization was successfully.
|
|
||||||
return True
|
|
@ -1,55 +0,0 @@
|
|||||||
"""
|
|
||||||
Example of a custom MQTT component.
|
|
||||||
|
|
||||||
Shows how to communicate with MQTT. Follows a topic on MQTT and updates the
|
|
||||||
state of an entity to the last message received on that topic.
|
|
||||||
|
|
||||||
Also offers a service 'set_state' that will publish a message on the topic that
|
|
||||||
will be passed via MQTT to our message received listener. Call the service with
|
|
||||||
example payload {"new_state": "some new state"}.
|
|
||||||
|
|
||||||
Configuration:
|
|
||||||
|
|
||||||
To use the mqtt_example component you will need to add the following to your
|
|
||||||
configuration.yaml file.
|
|
||||||
|
|
||||||
mqtt_example:
|
|
||||||
topic: "home-assistant/mqtt_example"
|
|
||||||
"""
|
|
||||||
import homeassistant.loader as loader
|
|
||||||
|
|
||||||
# The domain of your component. Should be equal to the name of your component.
|
|
||||||
DOMAIN = "mqtt_example"
|
|
||||||
|
|
||||||
# List of component names (string) your component depends upon.
|
|
||||||
DEPENDENCIES = ['mqtt']
|
|
||||||
|
|
||||||
CONF_TOPIC = 'topic'
|
|
||||||
DEFAULT_TOPIC = 'home-assistant/mqtt_example'
|
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
|
||||||
"""Setup the MQTT example component."""
|
|
||||||
mqtt = loader.get_component('mqtt')
|
|
||||||
topic = config[DOMAIN].get('topic', DEFAULT_TOPIC)
|
|
||||||
entity_id = 'mqtt_example.last_message'
|
|
||||||
|
|
||||||
# Listen to a message on MQTT.
|
|
||||||
def message_received(topic, payload, qos):
|
|
||||||
"""A new MQTT message has been received."""
|
|
||||||
hass.states.set(entity_id, payload)
|
|
||||||
|
|
||||||
mqtt.subscribe(hass, topic, message_received)
|
|
||||||
|
|
||||||
hass.states.set(entity_id, 'No messages')
|
|
||||||
|
|
||||||
# Service to publish a message on MQTT.
|
|
||||||
def set_state_service(call):
|
|
||||||
"""Service to send a message."""
|
|
||||||
mqtt.publish(hass, topic, call.data.get('new_state'))
|
|
||||||
|
|
||||||
# Register our service with Home Assistant.
|
|
||||||
hass.services.register(DOMAIN, 'set_state', set_state_service)
|
|
||||||
|
|
||||||
# Return boolean to indicate that initialization was successfully.
|
|
||||||
return True
|
|
@ -1,432 +0,0 @@
|
|||||||
<!--
|
|
||||||
Custom Home Assistant panel example.
|
|
||||||
|
|
||||||
Currently only works in Firefox and Chrome because it uses ES6.
|
|
||||||
|
|
||||||
Make sure this file is in <config>/panels/react.html
|
|
||||||
|
|
||||||
Add to your configuration.yaml:
|
|
||||||
|
|
||||||
panel_custom:
|
|
||||||
- name: react
|
|
||||||
sidebar_title: TodoMVC
|
|
||||||
sidebar_icon: mdi:checkbox-marked-outline
|
|
||||||
config:
|
|
||||||
title: Wow hello!
|
|
||||||
-->
|
|
||||||
|
|
||||||
<script src="https://fb.me/react-15.2.1.min.js"></script>
|
|
||||||
<script src="https://fb.me/react-dom-15.2.1.min.js"></script>
|
|
||||||
|
|
||||||
<!-- for development, replace with:
|
|
||||||
<script src="https://fb.me/react-15.2.1.js"></script>
|
|
||||||
<script src="https://fb.me/react-dom-15.2.1.js"></script>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<!--
|
|
||||||
CSS taken from ReactJS TodoMVC example by Pete Hunt
|
|
||||||
http://todomvc.com/examples/react/
|
|
||||||
-->
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.todoapp input[type="checkbox"] {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp {
|
|
||||||
background: #fff;
|
|
||||||
margin: 130px 0 40px 0;
|
|
||||||
position: relative;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
|
|
||||||
0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp h1 {
|
|
||||||
position: absolute;
|
|
||||||
top: -155px;
|
|
||||||
width: 100%;
|
|
||||||
font-size: 100px;
|
|
||||||
font-weight: 100;
|
|
||||||
text-align: center;
|
|
||||||
color: rgba(175, 47, 47, 0.15);
|
|
||||||
-webkit-text-rendering: optimizeLegibility;
|
|
||||||
-moz-text-rendering: optimizeLegibility;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .main {
|
|
||||||
position: relative;
|
|
||||||
border-top: 1px solid #e6e6e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li {
|
|
||||||
position: relative;
|
|
||||||
font-size: 24px;
|
|
||||||
border-bottom: 1px solid #ededed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li .toggle {
|
|
||||||
text-align: center;
|
|
||||||
width: 40px;
|
|
||||||
/* auto, since non-WebKit browsers doesn't support input styling */
|
|
||||||
height: auto;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
margin: auto 0;
|
|
||||||
border: none; /* Mobile Safari */
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li .toggle:focus {
|
|
||||||
border-left: 3px solid rgba(175, 47, 47, 0.35);
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li .toggle:after {
|
|
||||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li .toggle:checked:after {
|
|
||||||
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li label {
|
|
||||||
white-space: pre-line;
|
|
||||||
word-break: break-all;
|
|
||||||
padding: 15px 60px 15px 15px;
|
|
||||||
margin-left: 45px;
|
|
||||||
display: block;
|
|
||||||
line-height: 1.2;
|
|
||||||
transition: color 0.4s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li.completed label {
|
|
||||||
color: #d9d9d9;
|
|
||||||
text-decoration: line-through;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .footer {
|
|
||||||
color: #777;
|
|
||||||
padding: 10px 15px;
|
|
||||||
height: 20px;
|
|
||||||
text-align: center;
|
|
||||||
border-top: 1px solid #e6e6e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .footer:before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 50px;
|
|
||||||
overflow: hidden;
|
|
||||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
|
|
||||||
0 8px 0 -3px #f6f6f6,
|
|
||||||
0 9px 1px -3px rgba(0, 0, 0, 0.2),
|
|
||||||
0 16px 0 -6px #f6f6f6,
|
|
||||||
0 17px 2px -6px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-count {
|
|
||||||
float: left;
|
|
||||||
text-align: left;
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .toggle-menu {
|
|
||||||
position: absolute;
|
|
||||||
right: 15px;
|
|
||||||
font-weight: 300;
|
|
||||||
color: rgba(175, 47, 47, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .filters {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .filters li {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .filters li a {
|
|
||||||
color: inherit;
|
|
||||||
margin: 3px;
|
|
||||||
padding: 3px 7px;
|
|
||||||
text-decoration: none;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .filters li a.selected,
|
|
||||||
.filters li a:hover {
|
|
||||||
border-color: rgba(175, 47, 47, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .filters li a.selected {
|
|
||||||
border-color: rgba(175, 47, 47, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Hack to remove background from Mobile Safari.
|
|
||||||
Can't use it globally since it destroys checkboxes in Firefox
|
|
||||||
*/
|
|
||||||
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
|
||||||
.todoapp .toggle-all,
|
|
||||||
.todoapp .todo-list li .toggle {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .todo-list li .toggle {
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .toggle-all {
|
|
||||||
-webkit-transform: rotate(90deg);
|
|
||||||
transform: rotate(90deg);
|
|
||||||
-webkit-appearance: none;
|
|
||||||
appearance: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 430px) {
|
|
||||||
.todoapp .footer {
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.todoapp .filters {
|
|
||||||
bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<dom-module id='ha-panel-react'>
|
|
||||||
<template>
|
|
||||||
<style>
|
|
||||||
:host {
|
|
||||||
background: #f5f5f5;
|
|
||||||
display: block;
|
|
||||||
height: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.mount {
|
|
||||||
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
||||||
line-height: 1.4em;
|
|
||||||
color: #4d4d4d;
|
|
||||||
min-width: 230px;
|
|
||||||
max-width: 550px;
|
|
||||||
margin: 0 auto;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-font-smoothing: antialiased;
|
|
||||||
font-smoothing: antialiased;
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<div id='mount' class='mount'></div>
|
|
||||||
</template>
|
|
||||||
</dom-module>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Example uses ES6. Will only work in modern browsers
|
|
||||||
class TodoMVC extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
filter: 'all',
|
|
||||||
// load initial value of entities
|
|
||||||
entities: this.props.hass.reactor.evaluate(
|
|
||||||
this.props.hass.entityGetters.visibleEntityMap),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
// register to entity updates
|
|
||||||
this._unwatchHass = this.props.hass.reactor.observe(
|
|
||||||
this.props.hass.entityGetters.visibleEntityMap,
|
|
||||||
entities => this.setState({entities}))
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
// unregister to entity updates
|
|
||||||
this._unwatchHass();
|
|
||||||
}
|
|
||||||
|
|
||||||
handlePickFilter(filter, ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
this.setState({filter});
|
|
||||||
}
|
|
||||||
|
|
||||||
handleEntityToggle(entity, ev) {
|
|
||||||
this.props.hass.serviceActions.callService(
|
|
||||||
entity.domain, 'toggle', { entity_id: entity.entityId });
|
|
||||||
}
|
|
||||||
|
|
||||||
handleToggleMenu(ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
Polymer.Base.fire('open-menu', null, {node: ev.target});
|
|
||||||
}
|
|
||||||
|
|
||||||
entityRow(entity) {
|
|
||||||
const completed = entity.state === 'on';
|
|
||||||
|
|
||||||
return React.createElement(
|
|
||||||
'li', {
|
|
||||||
className: completed && 'completed',
|
|
||||||
key: entity.entityId,
|
|
||||||
},
|
|
||||||
React.createElement(
|
|
||||||
"div", { className: "view" },
|
|
||||||
React.createElement(
|
|
||||||
"input", {
|
|
||||||
checked: completed,
|
|
||||||
className: "toggle",
|
|
||||||
type: "checkbox",
|
|
||||||
onChange: ev => this.handleEntityToggle(entity, ev),
|
|
||||||
}),
|
|
||||||
React.createElement("label", null, entity.entityDisplay)));
|
|
||||||
}
|
|
||||||
|
|
||||||
filterRow(filter) {
|
|
||||||
return React.createElement(
|
|
||||||
"li", { key: filter },
|
|
||||||
React.createElement(
|
|
||||||
"a", {
|
|
||||||
href: "#",
|
|
||||||
className: this.state.filter === filter && "selected",
|
|
||||||
onClick: ev => this.handlePickFilter(filter, ev),
|
|
||||||
},
|
|
||||||
filter.substring(0, 1).toUpperCase() + filter.substring(1)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { entities, filter } = this.state;
|
|
||||||
|
|
||||||
if (!entities) return null;
|
|
||||||
|
|
||||||
const filters = ['all', 'light', 'switch'];
|
|
||||||
|
|
||||||
const showEntities = filter === 'all' ?
|
|
||||||
entities.filter(ent => filters.includes(ent.domain)) :
|
|
||||||
entities.filter(ent => ent.domain == filter);
|
|
||||||
|
|
||||||
return React.createElement(
|
|
||||||
'div', { className: 'todoapp-wrapper' },
|
|
||||||
React.createElement(
|
|
||||||
"section", { className: "todoapp" },
|
|
||||||
React.createElement(
|
|
||||||
"div", null,
|
|
||||||
React.createElement(
|
|
||||||
"header", { className: "header" },
|
|
||||||
React.createElement("h1", null, this.props.title || "todos")
|
|
||||||
),
|
|
||||||
React.createElement(
|
|
||||||
"section", { className: "main" },
|
|
||||||
React.createElement(
|
|
||||||
"ul", { className: "todo-list" },
|
|
||||||
showEntities.valueSeq().map(ent => this.entityRow(ent)))
|
|
||||||
)
|
|
||||||
),
|
|
||||||
React.createElement(
|
|
||||||
"footer", { className: "footer" },
|
|
||||||
React.createElement(
|
|
||||||
"span", { className: "todo-count" },
|
|
||||||
showEntities.filter(ent => ent.state === 'off').size + " items left"
|
|
||||||
),
|
|
||||||
React.createElement(
|
|
||||||
"ul", { className: "filters" },
|
|
||||||
filters.map(filter => this.filterRow(filter))
|
|
||||||
),
|
|
||||||
!this.props.showMenu && React.createElement(
|
|
||||||
"a", {
|
|
||||||
className: "toggle-menu",
|
|
||||||
href: '#',
|
|
||||||
onClick: ev => this.handleToggleMenu(ev),
|
|
||||||
},
|
|
||||||
"Show menu"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Polymer({
|
|
||||||
is: 'ha-panel-react',
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
// Home Assistant object
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
// If should render in narrow mode
|
|
||||||
narrow: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
// If sidebar is currently shown
|
|
||||||
showMenu: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Home Assistant panel info
|
|
||||||
// panel.config contains config passed to register_panel serverside
|
|
||||||
panel: {
|
|
||||||
type: Object,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// This will make sure we forward changed properties to React
|
|
||||||
observers: [
|
|
||||||
'propsChanged(hass, narrow, showMenu, panel)',
|
|
||||||
],
|
|
||||||
|
|
||||||
// Mount React when element attached
|
|
||||||
attached: function () {
|
|
||||||
this.mount(this.hass, this.narrow, this.showMenu, this.panel);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Called when properties change
|
|
||||||
propsChanged: function (hass, narrow, showMenu, panel) {
|
|
||||||
this.mount(hass, narrow, showMenu, panel);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Render React. Debounce in case multiple properties change.
|
|
||||||
mount: function (hass, narrow, showMenu, panel) {
|
|
||||||
this.debounce('mount', function () {
|
|
||||||
ReactDOM.render(React.createElement(TodoMVC, {
|
|
||||||
hass: hass,
|
|
||||||
narrow: narrow,
|
|
||||||
showMenu: showMenu,
|
|
||||||
title: panel.config ? panel.config.title : null
|
|
||||||
}), this.$.mount);
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
|
|
||||||
// Unmount React node when panel no longer in use.
|
|
||||||
detached: function () {
|
|
||||||
ReactDOM.unmountComponentAtNode(this.$.mount);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
BIN
docs/screenshot-components.png
Executable file
BIN
docs/screenshot-components.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
Loading…
x
Reference in New Issue
Block a user