273 lines
8.6 KiB
Python
273 lines
8.6 KiB
Python
import logging
|
|
|
|
import voluptuous as vol
|
|
from homeassistant.helpers import config_validation as cv
|
|
from homeassistant.components import websocket_api
|
|
from homeassistant.components.http import HomeAssistantView
|
|
from homeassistant.components.http.data_validator import RequestDataValidator
|
|
from homeassistant.core import callback
|
|
from homeassistant.components.websocket_api import decorators, async_register_command
|
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|
from . import const
|
|
from .store import ScheduleEntry
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
class SchedulesListView(HomeAssistantView):
|
|
"""Login to Home Assistant cloud."""
|
|
|
|
url = "/api/{}/list".format(const.DOMAIN)
|
|
name = "api:{}:list".format(const.DOMAIN)
|
|
|
|
async def get(self, request):
|
|
hass = request.app["hass"]
|
|
coordinator = hass.data[const.DOMAIN]["coordinator"]
|
|
schedules = coordinator.async_get_schedules()
|
|
return self.json(schedules)
|
|
|
|
|
|
class SchedulesAddView(HomeAssistantView):
|
|
"""Login to Home Assistant cloud."""
|
|
|
|
url = "/api/{}/add".format(const.DOMAIN)
|
|
name = "api:{}:add".format(const.DOMAIN)
|
|
|
|
@RequestDataValidator(const.ADD_SCHEDULE_SCHEMA)
|
|
async def post(self, request, data):
|
|
"""Handle config update request."""
|
|
hass = request.app["hass"]
|
|
coordinator = hass.data[const.DOMAIN]["coordinator"]
|
|
coordinator.async_create_schedule(data)
|
|
return self.json({"success": True})
|
|
|
|
|
|
class SchedulesEditView(HomeAssistantView):
|
|
"""Login to Home Assistant cloud."""
|
|
|
|
url = "/api/{}/edit".format(const.DOMAIN)
|
|
name = "api:{}:edit".format(const.DOMAIN)
|
|
|
|
@RequestDataValidator(
|
|
const.EDIT_SCHEDULE_SCHEMA.extend(
|
|
{vol.Required(const.ATTR_SCHEDULE_ID): cv.string}
|
|
)
|
|
)
|
|
async def post(self, request, data):
|
|
"""Handle config update request."""
|
|
hass = request.app["hass"]
|
|
coordinator = hass.data[const.DOMAIN]["coordinator"]
|
|
schedule_id = data[const.ATTR_SCHEDULE_ID]
|
|
del data[const.ATTR_SCHEDULE_ID]
|
|
coordinator.async_edit_schedule(schedule_id, data)
|
|
return self.json({"success": True})
|
|
|
|
|
|
class SchedulesRemoveView(HomeAssistantView):
|
|
"""Login to Home Assistant cloud."""
|
|
|
|
url = "/api/{}/remove".format(const.DOMAIN)
|
|
name = "api:{}:remove".format(const.DOMAIN)
|
|
|
|
@RequestDataValidator(vol.Schema({vol.Required(const.ATTR_SCHEDULE_ID): cv.string}))
|
|
async def post(self, request, data):
|
|
"""Handle config update request."""
|
|
hass = request.app["hass"]
|
|
coordinator = hass.data[const.DOMAIN]["coordinator"]
|
|
coordinator.async_delete_schedule(data[const.ATTR_SCHEDULE_ID])
|
|
return self.json({"success": True})
|
|
|
|
|
|
@callback
|
|
def websocket_get_schedules(hass, connection, msg):
|
|
"""Publish scheduler list data."""
|
|
coordinator = hass.data[const.DOMAIN]["coordinator"]
|
|
schedules = coordinator.async_get_schedules()
|
|
connection.send_result(msg["id"], schedules)
|
|
|
|
|
|
@callback
|
|
def websocket_get_schedule_item(hass, connection, msg):
|
|
"""Publish scheduler list data."""
|
|
coordinator = hass.data[const.DOMAIN]["coordinator"]
|
|
item = msg[const.ATTR_SCHEDULE_ID]
|
|
data = coordinator.async_get_schedule(item)
|
|
connection.send_result(msg["id"], data)
|
|
|
|
|
|
@callback
|
|
def websocket_get_tags(hass, connection, msg):
|
|
"""Publish tag list data."""
|
|
coordinator = hass.data[const.DOMAIN]["coordinator"]
|
|
tags = coordinator.async_get_tags()
|
|
connection.send_result(msg["id"], tags)
|
|
|
|
|
|
@callback
|
|
@decorators.websocket_command(
|
|
{
|
|
vol.Required("type"): const.EVENT,
|
|
}
|
|
)
|
|
@decorators.async_response
|
|
async def handle_subscribe_updates(hass, connection, msg):
|
|
"""subscribe listeners when frontend connection is opened"""
|
|
|
|
listeners = []
|
|
|
|
@callback
|
|
def async_handle_event_item_created(schedule: ScheduleEntry):
|
|
"""pass data to frontend when backend changes"""
|
|
connection.send_message(
|
|
{
|
|
"id": msg["id"],
|
|
"type": "event",
|
|
"event": { # data to pass with event
|
|
"event": const.EVENT_ITEM_CREATED,
|
|
"schedule_id": schedule.schedule_id,
|
|
},
|
|
}
|
|
)
|
|
|
|
listeners.append(
|
|
async_dispatcher_connect(
|
|
hass, const.EVENT_ITEM_CREATED, async_handle_event_item_created
|
|
)
|
|
)
|
|
|
|
@callback
|
|
def async_handle_event_item_updated(schedule_id: str):
|
|
"""pass data to frontend when backend changes"""
|
|
connection.send_message(
|
|
{
|
|
"id": msg["id"],
|
|
"type": "event",
|
|
"event": { # data to pass with event
|
|
"event": const.EVENT_ITEM_UPDATED,
|
|
"schedule_id": schedule_id,
|
|
},
|
|
}
|
|
)
|
|
|
|
listeners.append(
|
|
async_dispatcher_connect(
|
|
hass, const.EVENT_ITEM_UPDATED, async_handle_event_item_updated
|
|
)
|
|
)
|
|
|
|
@callback
|
|
def async_handle_event_item_removed(schedule_id: str):
|
|
"""pass data to frontend when backend changes"""
|
|
connection.send_message(
|
|
{
|
|
"id": msg["id"],
|
|
"type": "event",
|
|
"event": { # data to pass with event
|
|
"event": const.EVENT_ITEM_REMOVED,
|
|
"schedule_id": schedule_id,
|
|
},
|
|
}
|
|
)
|
|
|
|
listeners.append(
|
|
async_dispatcher_connect(
|
|
hass, const.EVENT_ITEM_REMOVED, async_handle_event_item_removed
|
|
)
|
|
)
|
|
|
|
@callback
|
|
def async_handle_event_timer_updated(schedule_id: str):
|
|
"""pass data to frontend when backend changes"""
|
|
connection.send_message(
|
|
{
|
|
"id": msg["id"],
|
|
"type": "event",
|
|
"event": { # data to pass with event
|
|
"event": const.EVENT_TIMER_UPDATED,
|
|
"schedule_id": schedule_id,
|
|
},
|
|
}
|
|
)
|
|
|
|
listeners.append(
|
|
async_dispatcher_connect(
|
|
hass, const.EVENT_TIMER_UPDATED, async_handle_event_timer_updated
|
|
)
|
|
)
|
|
|
|
@callback
|
|
def async_handle_event_timer_finished(schedule_id: str):
|
|
"""pass data to frontend when backend changes"""
|
|
connection.send_message(
|
|
{
|
|
"id": msg["id"],
|
|
"type": "event",
|
|
"event": { # data to pass with event
|
|
"event": const.EVENT_TIMER_FINISHED,
|
|
"schedule_id": schedule_id,
|
|
},
|
|
}
|
|
)
|
|
|
|
listeners.append(
|
|
async_dispatcher_connect(
|
|
hass, const.EVENT_TIMER_FINISHED, async_handle_event_timer_finished
|
|
)
|
|
)
|
|
|
|
def unsubscribe_listeners():
|
|
"""unsubscribe listeners when frontend connection closes"""
|
|
while len(listeners):
|
|
listeners.pop()()
|
|
|
|
connection.subscriptions[msg["id"]] = unsubscribe_listeners
|
|
connection.send_result(msg["id"])
|
|
|
|
|
|
async def async_register_websockets(hass):
|
|
|
|
# expose services
|
|
hass.http.register_view(SchedulesAddView)
|
|
hass.http.register_view(SchedulesEditView)
|
|
hass.http.register_view(SchedulesRemoveView)
|
|
hass.http.register_view(SchedulesListView)
|
|
|
|
# pass list of schedules to frontend
|
|
websocket_api.async_register_command(
|
|
hass,
|
|
const.DOMAIN,
|
|
websocket_get_schedules,
|
|
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
|
{
|
|
vol.Required("type"): const.DOMAIN,
|
|
}
|
|
),
|
|
)
|
|
|
|
# pass single schedule to frontend
|
|
websocket_api.async_register_command(
|
|
hass,
|
|
"{}/item".format(const.DOMAIN),
|
|
websocket_get_schedule_item,
|
|
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
|
{
|
|
vol.Required("type"): "{}/item".format(const.DOMAIN),
|
|
vol.Required(const.ATTR_SCHEDULE_ID): cv.string,
|
|
}
|
|
),
|
|
)
|
|
|
|
# pass list of tags to frontend
|
|
websocket_api.async_register_command(
|
|
hass,
|
|
"{}/tags".format(const.DOMAIN),
|
|
websocket_get_tags,
|
|
websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend(
|
|
{
|
|
vol.Required("type"): "{}/tags".format(const.DOMAIN),
|
|
}
|
|
),
|
|
)
|
|
|
|
# instantiate listener for sending event to frontend on backend change
|
|
async_register_command(hass, handle_subscribe_updates)
|