core/homeassistant/components/spaceapi/__init__.py

199 lines
5.8 KiB
Python

"""Support for the SpaceAPI."""
import logging
import voluptuous as vol
from homeassistant.components.http import HomeAssistantView
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_ICON,
ATTR_LATITUDE,
ATTR_LOCATION,
ATTR_LONGITUDE,
ATTR_STATE,
ATTR_UNIT_OF_MEASUREMENT,
CONF_ADDRESS,
CONF_EMAIL,
CONF_ENTITY_ID,
CONF_SENSORS,
CONF_STATE,
CONF_URL,
)
import homeassistant.core as ha
import homeassistant.helpers.config_validation as cv
import homeassistant.util.dt as dt_util
_LOGGER = logging.getLogger(__name__)
ATTR_ADDRESS = "address"
ATTR_API = "api"
ATTR_CLOSE = "close"
ATTR_CONTACT = "contact"
ATTR_ISSUE_REPORT_CHANNELS = "issue_report_channels"
ATTR_LASTCHANGE = "lastchange"
ATTR_LOGO = "logo"
ATTR_NAME = "name"
ATTR_OPEN = "open"
ATTR_SENSORS = "sensors"
ATTR_SPACE = "space"
ATTR_UNIT = "unit"
ATTR_URL = "url"
ATTR_VALUE = "value"
ATTR_SENSOR_LOCATION = "location"
CONF_CONTACT = "contact"
CONF_HUMIDITY = "humidity"
CONF_ICON_CLOSED = "icon_closed"
CONF_ICON_OPEN = "icon_open"
CONF_ICONS = "icons"
CONF_IRC = "irc"
CONF_ISSUE_REPORT_CHANNELS = "issue_report_channels"
CONF_LOCATION = "location"
CONF_LOGO = "logo"
CONF_MAILING_LIST = "mailing_list"
CONF_PHONE = "phone"
CONF_SPACE = "space"
CONF_TEMPERATURE = "temperature"
CONF_TWITTER = "twitter"
DATA_SPACEAPI = "data_spaceapi"
DOMAIN = "spaceapi"
ISSUE_REPORT_CHANNELS = [CONF_EMAIL, CONF_IRC, CONF_MAILING_LIST, CONF_TWITTER]
SENSOR_TYPES = [CONF_HUMIDITY, CONF_TEMPERATURE]
SPACEAPI_VERSION = 0.13
URL_API_SPACEAPI = "/api/spaceapi"
LOCATION_SCHEMA = vol.Schema({vol.Optional(CONF_ADDRESS): cv.string}, required=True)
CONTACT_SCHEMA = vol.Schema(
{
vol.Optional(CONF_EMAIL): cv.string,
vol.Optional(CONF_IRC): cv.string,
vol.Optional(CONF_MAILING_LIST): cv.string,
vol.Optional(CONF_PHONE): cv.string,
vol.Optional(CONF_TWITTER): cv.string,
},
required=False,
)
STATE_SCHEMA = vol.Schema(
{
vol.Required(CONF_ENTITY_ID): cv.entity_id,
vol.Inclusive(CONF_ICON_CLOSED, CONF_ICONS): cv.url,
vol.Inclusive(CONF_ICON_OPEN, CONF_ICONS): cv.url,
},
required=False,
)
SENSOR_SCHEMA = vol.Schema(
{vol.In(SENSOR_TYPES): [cv.entity_id], cv.string: [cv.entity_id]}
)
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.Schema(
{
vol.Required(CONF_CONTACT): CONTACT_SCHEMA,
vol.Required(CONF_ISSUE_REPORT_CHANNELS): vol.All(
cv.ensure_list, [vol.In(ISSUE_REPORT_CHANNELS)]
),
vol.Required(CONF_LOCATION): LOCATION_SCHEMA,
vol.Required(CONF_LOGO): cv.url,
vol.Required(CONF_SPACE): cv.string,
vol.Required(CONF_STATE): STATE_SCHEMA,
vol.Required(CONF_URL): cv.string,
vol.Optional(CONF_SENSORS): SENSOR_SCHEMA,
}
)
},
extra=vol.ALLOW_EXTRA,
)
def setup(hass, config):
"""Register the SpaceAPI with the HTTP interface."""
hass.data[DATA_SPACEAPI] = config[DOMAIN]
hass.http.register_view(APISpaceApiView)
return True
class APISpaceApiView(HomeAssistantView):
"""View to provide details according to the SpaceAPI."""
url = URL_API_SPACEAPI
name = "api:spaceapi"
@staticmethod
def get_sensor_data(hass, spaceapi, sensor):
"""Get data from a sensor."""
sensor_state = hass.states.get(sensor)
if not sensor_state:
return None
sensor_data = {ATTR_NAME: sensor_state.name, ATTR_VALUE: sensor_state.state}
if ATTR_SENSOR_LOCATION in sensor_state.attributes:
sensor_data[ATTR_LOCATION] = sensor_state.attributes[ATTR_SENSOR_LOCATION]
else:
sensor_data[ATTR_LOCATION] = spaceapi[CONF_SPACE]
# Some sensors don't have a unit of measurement
if ATTR_UNIT_OF_MEASUREMENT in sensor_state.attributes:
sensor_data[ATTR_UNIT] = sensor_state.attributes[ATTR_UNIT_OF_MEASUREMENT]
return sensor_data
@ha.callback
def get(self, request):
"""Get SpaceAPI data."""
hass = request.app["hass"]
spaceapi = dict(hass.data[DATA_SPACEAPI])
is_sensors = spaceapi.get("sensors")
location = {
ATTR_ADDRESS: spaceapi[ATTR_LOCATION][CONF_ADDRESS],
ATTR_LATITUDE: hass.config.latitude,
ATTR_LONGITUDE: hass.config.longitude,
}
state_entity = spaceapi["state"][ATTR_ENTITY_ID]
space_state = hass.states.get(state_entity)
if space_state is not None:
state = {
ATTR_OPEN: space_state.state != "off",
ATTR_LASTCHANGE: dt_util.as_timestamp(space_state.last_updated),
}
else:
state = {ATTR_OPEN: "null", ATTR_LASTCHANGE: 0}
try:
state[ATTR_ICON] = {
ATTR_OPEN: spaceapi["state"][CONF_ICON_OPEN],
ATTR_CLOSE: spaceapi["state"][CONF_ICON_CLOSED],
}
except KeyError:
pass
data = {
ATTR_API: SPACEAPI_VERSION,
ATTR_CONTACT: spaceapi[CONF_CONTACT],
ATTR_ISSUE_REPORT_CHANNELS: spaceapi[CONF_ISSUE_REPORT_CHANNELS],
ATTR_LOCATION: location,
ATTR_LOGO: spaceapi[CONF_LOGO],
ATTR_SPACE: spaceapi[CONF_SPACE],
ATTR_STATE: state,
ATTR_URL: spaceapi[CONF_URL],
}
if is_sensors is not None:
sensors = {}
for sensor_type in is_sensors:
sensors[sensor_type] = []
for sensor in spaceapi["sensors"][sensor_type]:
sensor_data = self.get_sensor_data(hass, spaceapi, sensor)
sensors[sensor_type].append(sensor_data)
data[ATTR_SENSORS] = sensors
return self.json(data)