How to display a Fullscreen schedule view as a Dashboard?

OK guys, I have created my own solution. It creates a new side bar menu item called “Schedule Editor”. When you select the Schedule Editor it opens the schedule file from the HA “homeassistant/.storage” folder (thanx to @boheme61 for pointing me in the right file direction) and you can easily edit the schedule, add additional slots, delete slots etc… On saving the changes you will get a prompt that HA s about to restart and you can accept or decline that restart. The restart is required to correctly reload the new edited schedule, it was the only way that I have found which sets the changes. I tried several other methods such as opening the clunky back end schedule editor and then using the “Update” button but that will over write your edited changes with the original version as that it the one currently “loaded” in the HA system until after a restart. I also tried out the other reload options found in the Developer section but none worked.

Its a Custom_Component so to manually install this, follow these steps.

Use the FileBrowser or File Editor tools to create folders and files as follows:

  1. Navigate to the “custom_components” folder within the Config folder.
  2. Create a new folder called “schedule_editor”.
  3. Inside the new folder create a new file called “init.py” and paste in the following code:
"""Schedule Editor Integration."""
import logging
import json
import os
from aiohttp import web

from homeassistant.core import HomeAssistant
from homeassistant.components.http import HomeAssistantView
from homeassistant.components import frontend

_LOGGER = logging.getLogger(__name__)

DOMAIN = "schedule_editor"


async def async_setup(hass: HomeAssistant, config: dict):
    """Set up the Schedule Editor component."""
    
    _LOGGER.info("Setting up Schedule Editor")
    
    # Register API endpoints first
    hass.http.register_view(ScheduleGetView(hass))
    hass.http.register_view(ScheduleSaveView(hass))
    hass.http.register_view(SchedulePanelView(hass))
    hass.http.register_view(ScheduleRestartView(hass))
    
    # Register as iframe panel (not async)
    frontend.async_register_built_in_panel(
        hass,
        component_name="iframe",
        sidebar_title="Schedule Editor",
        sidebar_icon="mdi:calendar-clock",
        frontend_url_path="schedule-editor",
        config={
            "url": "/api/schedule_editor/panel",
        },
        require_admin=False,
    )
    
    _LOGGER.info("Schedule Editor setup complete")
    
    return True


class SchedulePanelView(HomeAssistantView):
    """View to serve the schedule editor HTML."""
    
    url = "/api/schedule_editor/panel"
    name = "api:schedule_editor:panel"
    requires_auth = False
    
    def __init__(self, hass):
        """Initialize."""
        self.hass = hass
    
    async def get(self, request):
        """Serve the editor HTML."""
        html_content = """
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Schedule Editor</title>
    <style>
        * { box-sizing: border-box; margin: 0; padding: 0; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            background: #111;
            color: #fff;
            padding: 12px;
        }
        .container { max-width: 1200px; margin: 0 auto; }
        .header {
            display: flex;
            flex-direction: column;
            gap: 12px;
            margin-bottom: 16px;
            padding: 16px;
            background: #1a1a1a;
            border-radius: 8px;
        }
        h1 { 
            font-size: 20px;
            text-align: center;
        }
        .file-selector {
            display: flex;
            align-items: center;
            gap: 8px;
            flex-wrap: wrap;
        }
        .file-selector label {
            color: #999;
            font-size: 14px;
            white-space: nowrap;
        }
        .file-selector select {
            flex: 1;
            min-width: 150px;
            padding: 8px 12px;
            background: #2a2a2a;
            border: 1px solid #444;
            border-radius: 4px;
            color: #fff;
            font-size: 14px;
            cursor: pointer;
        }
        @media (min-width: 768px) {
            body { padding: 20px; }
            .header { padding: 20px; }
            h1 { 
                font-size: 24px;
                text-align: left;
            }
        }
        .btn-small {
            padding: 8px 12px;
            background: #555;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            flex-shrink: 0;
        }
        .btn-small:hover {
            background: #666;
        }
        .btn {
            padding: 12px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            width: 100%;
        }
        .btn-primary { background: #03a9f4; color: white; }
        .btn-primary:hover { background: #0288d1; }
        @media (min-width: 768px) {
            .btn {
                width: auto;
            }
        }
        .message {
            padding: 12px;
            border-radius: 4px;
            margin-bottom: 12px;
            text-align: center;
            display: none;
            font-size: 14px;
        }
        .message.show { display: block; }
        .message.success { background: #4caf50; }
        .message.error { background: #f44336; }
        .day-card {
            background: #1a1a1a;
            border-radius: 8px;
            padding: 12px;
            margin-bottom: 12px;
        }
        .day-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 12px;
        }
        .day-header h3 {
            font-size: 16px;
            text-transform: capitalize;
        }
        .btn-add {
            padding: 6px 10px;
            background: #03a9f4;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 11px;
            white-space: nowrap;
        }
        @media (min-width: 768px) {
            .day-card {
                padding: 16px;
                margin-bottom: 16px;
            }
            .day-header h3 {
                font-size: 18px;
            }
            .btn-add {
                padding: 6px 12px;
                font-size: 12px;
            }
        }
        .time-slot {
            display: flex;
            align-items: center;
            gap: 6px;
            padding: 8px;
            background: #2a2a2a;
            border-radius: 4px;
            margin-bottom: 8px;
            flex-wrap: wrap;
        }
        .time-slot label {
            color: #999;
            font-size: 11px;
        }
        .time-input {
            padding: 8px 6px;
            border: 1px solid #444;
            border-radius: 4px;
            background: #333;
            color: #fff;
            font-size: 14px;
            min-width: 90px;
        }
        .btn-delete {
            padding: 6px 10px;
            background: #f44336;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin-left: auto;
            font-size: 16px;
        }
        @media (min-width: 768px) {
            .time-slot {
                gap: 8px;
                flex-wrap: nowrap;
            }
            .time-slot label {
                font-size: 12px;
            }
            .time-input {
                padding: 6px;
            }
            .btn-delete {
                padding: 6px 12px;
            }
        }
        .no-slots {
            color: #666;
            font-style: italic;
            font-size: 13px;
        }
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: rgba(0, 0, 0, 0.8);
            align-items: center;
            justify-content: center;
            z-index: 1000;
            padding: 20px;
        }
        .modal.show {
            display: flex;
        }
        .modal-content {
            background: #1a1a1a;
            border-radius: 8px;
            padding: 20px;
            max-width: 500px;
            width: 100%;
            border: 1px solid #333;
        }
        .modal-content h2 {
            margin-bottom: 12px;
            color: #fff;
            font-size: 18px;
        }
        .modal-content p {
            margin-bottom: 16px;
            color: #ccc;
            line-height: 1.5;
            font-size: 14px;
        }
        @media (min-width: 768px) {
            .modal-content {
                padding: 24px;
            }
            .modal-content h2 {
                margin-bottom: 16px;
                font-size: 20px;
            }
            .modal-content p {
                margin-bottom: 24px;
                font-size: 15px;
            }
        }
        .modal-buttons {
            display: flex;
            gap: 10px;
            justify-content: flex-end;
            flex-direction: column;
        }
        @media (min-width: 480px) {
            .modal-buttons {
                flex-direction: row;
                gap: 12px;
            }
        }
        .btn-secondary {
            background: #555;
            color: white;
            padding: 12px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        }
        .btn-secondary:hover {
            background: #666;
        }
        .btn-danger {
            background: #f44336;
            color: white;
            padding: 12px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
        }
        .btn-danger:hover {
            background: #d32f2f;
        }
        .quick-actions {
            background: #1a1a1a;
            border-radius: 8px;
            padding: 12px;
            margin-bottom: 16px;
        }
        .quick-actions h3 {
            margin-bottom: 12px;
            color: #fff;
            font-size: 16px;
        }
        .quick-actions-buttons {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
        }
        .btn-copy {
            padding: 10px 14px;
            background: #673ab7;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            white-space: nowrap;
        }
        .btn-copy:hover {
            background: #7e57c2;
        }
        .btn-delete-schedule {
            padding: 10px 14px;
            background: #f44336;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            white-space: nowrap;
        }
        .btn-delete-schedule:hover {
            background: #d32f2f;
        }
        @media (min-width: 768px) {
            .quick-actions {
                padding: 16px;
                margin-bottom: 24px;
            }
            .btn-copy, .btn-delete-schedule {
                padding: 8px 16px;
                font-size: 13px;
            }
            .btn-delete-schedule {
                margin-left: auto;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>Schedule Editor</h1>
            <button class="btn btn-primary" onclick="saveSchedule()">Save Schedule</button>
            <div class="file-selector">
                <label for="schedule-select">Schedule:</label>
                <select id="schedule-select" onchange="loadSelectedSchedule()">
                    <option value="schedule">Default Schedule</option>
                </select>
                <button class="btn btn-small" onclick="refreshScheduleList()">↻</button>
            </div>
        </div>
        <div id="message" class="message"></div>
        
        <!-- Quick Copy Buttons -->
        <div class="quick-actions">
            <h3>Quick Copy</h3>
            <div class="quick-actions-buttons">
                <button class="btn btn-copy" onclick="copyMondayToWeekdays()">Copy Mon → Tue-Fri</button>
                <button class="btn btn-copy" onclick="copyFridayToSaturday()">Copy Fri → Sat</button>
                <button class="btn btn-copy" onclick="copySaturdayToSunday()">Copy Sat → Sun</button>
                <button class="btn btn-delete-schedule" onclick="confirmDeleteSchedule()">Delete Schedule</button>
            </div>
        </div>
        
        <!-- Delete Confirmation Modal -->
        <div id="delete-modal" class="modal">
            <div class="modal-content">
                <h2>Delete Schedule?</h2>
                <p id="delete-message">Are you sure you want to delete this schedule?</p>
                <p style="color: #f44336; font-weight: bold; margin-top: 12px;" id="delete-name"></p>
                <div class="modal-buttons">
                    <button class="btn btn-secondary" onclick="closeDeleteModal()">Cancel</button>
                    <button class="btn btn-danger" onclick="deleteSchedule()">Delete</button>
                </div>
            </div>
        </div>
        
        <!-- Restart Warning Modal -->
        <div id="restart-modal" class="modal">
            <div class="modal-content">
                <h2>Restart Home Assistant?</h2>
                <p>The schedule has been saved successfully. Would you like to restart Home Assistant now to apply the changes?</p>
                <div class="modal-buttons">
                    <button class="btn btn-secondary" onclick="closeRestartModal()">Not Now</button>
                    <button class="btn btn-danger" onclick="restartHomeAssistant()">Restart Now</button>
                </div>
            </div>
        </div>
        
        <div id="schedule-container"></div>
    </div>

    <script>
        let scheduleData = null;
        let currentScheduleIndex = 0;
        const days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];

        async function loadSchedule() {
            try {
                const response = await fetch('/api/schedule_editor/get');
                if (!response.ok) {
                    throw new Error('HTTP ' + response.status);
                }
                scheduleData = await response.json();
                updateScheduleList();
                renderSchedule();
            } catch (error) {
                console.error('Load error:', error);
                showMessage('Error loading schedule: ' + error.message, 'error');
            }
        }

        function updateScheduleList() {
            const select = document.getElementById('schedule-select');
            select.innerHTML = '';
            
            scheduleData.data.items.forEach((item, index) => {
                const option = document.createElement('option');
                option.value = index;
                option.textContent = item.name || item.id;
                if (index === currentScheduleIndex) {
                    option.selected = true;
                }
                select.appendChild(option);
            });
        }

        function loadSelectedSchedule() {
            const select = document.getElementById('schedule-select');
            currentScheduleIndex = parseInt(select.value);
            renderSchedule();
            const scheduleName = scheduleData.data.items[currentScheduleIndex].name;
            showMessage('Loaded: ' + scheduleName, 'success');
        }

        function refreshScheduleList() {
            loadSchedule();
        }

        function getAuthToken() {
            // Try to get token from parent window (Home Assistant)
            try {
                if (window.parent && window.parent !== window) {
                    const haAuth = window.parent.localStorage.getItem('hassTokens');
                    if (haAuth) {
                        const tokens = JSON.parse(haAuth);
                        return tokens.access_token;
                    }
                }
            } catch (e) {
                console.error('Could not access parent auth:', e);
            }
            
            // Fallback: try local storage
            try {
                const haAuth = localStorage.getItem('hassTokens');
                if (haAuth) {
                    const tokens = JSON.parse(haAuth);
                    return tokens.access_token;
                }
            } catch (e) {
                console.error('Could not access local auth:', e);
            }
            
            return '';
        }

        function renderSchedule() {
            const container = document.getElementById('schedule-container');
            container.innerHTML = '';
            
            const schedule = scheduleData.data.items[currentScheduleIndex];
            
            days.forEach(day => {
                const dayCard = document.createElement('div');
                dayCard.className = 'day-card';
                
                const header = document.createElement('div');
                header.className = 'day-header';
                header.innerHTML = `
                    <h3>${day}</h3>
                    <button class="btn-add" onclick="addTimeSlot('${day}')">+ Add Slot</button>
                `;
                dayCard.appendChild(header);
                
                const slots = schedule[day] || [];
                if (slots.length > 0) {
                    slots.forEach((slot, index) => {
                        const slotDiv = document.createElement('div');
                        slotDiv.className = 'time-slot';
                        slotDiv.innerHTML = `
                            <label>From:</label>
                            <input type="time" class="time-input" value="${slot.from.substring(0, 5)}" 
                                   onchange="updateTimeSlot('${day}', ${index}, 'from', this.value)">
                            <label>To:</label>
                            <input type="time" class="time-input" value="${slot.to.substring(0, 5)}" 
                                   onchange="updateTimeSlot('${day}', ${index}, 'to', this.value)">
                            <button class="btn-delete" onclick="removeTimeSlot('${day}', ${index})">×</button>
                        `;
                        dayCard.appendChild(slotDiv);
                    });
                } else {
                    const noSlots = document.createElement('p');
                    noSlots.className = 'no-slots';
                    noSlots.textContent = 'No time slots';
                    dayCard.appendChild(noSlots);
                }
                
                container.appendChild(dayCard);
            });
        }

        function addTimeSlot(day) {
            const schedule = scheduleData.data.items[currentScheduleIndex];
            if (!schedule[day]) schedule[day] = [];
            schedule[day].push({ from: "09:00:00", to: "17:00:00" });
            renderSchedule();
        }

        function removeTimeSlot(day, index) {
            scheduleData.data.items[currentScheduleIndex][day].splice(index, 1);
            renderSchedule();
        }

        function updateTimeSlot(day, index, field, value) {
            scheduleData.data.items[currentScheduleIndex][day][index][field] = value + ":00";
        }

        function copyMondayToWeekdays() {
            const schedule = scheduleData.data.items[currentScheduleIndex];
            const mondaySlots = schedule.monday ? JSON.parse(JSON.stringify(schedule.monday)) : [];
            
            ['tuesday', 'wednesday', 'thursday', 'friday'].forEach(day => {
                schedule[day] = JSON.parse(JSON.stringify(mondaySlots));
            });
            
            renderSchedule();
            showMessage('Monday schedule copied to Tuesday-Friday', 'success');
        }

        function copyFridayToSaturday() {
            const schedule = scheduleData.data.items[currentScheduleIndex];
            const fridaySlots = schedule.friday ? JSON.parse(JSON.stringify(schedule.friday)) : [];
            
            schedule.saturday = JSON.parse(JSON.stringify(fridaySlots));
            
            renderSchedule();
            showMessage('Friday schedule copied to Saturday', 'success');
        }

        function copySaturdayToSunday() {
            const schedule = scheduleData.data.items[currentScheduleIndex];
            const saturdaySlots = schedule.saturday ? JSON.parse(JSON.stringify(schedule.saturday)) : [];
            
            schedule.sunday = JSON.parse(JSON.stringify(saturdaySlots));
            
            renderSchedule();
            showMessage('Saturday schedule copied to Sunday', 'success');
        }

        async function saveSchedule() {
            try {
                const response = await fetch('/api/schedule_editor/save', {
                    method: 'POST',
                    headers: { 
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(scheduleData)
                });
                
                if (response.ok) {
                    const scheduleName = scheduleData.data.items[currentScheduleIndex].name;
                    showMessage('Schedule "' + scheduleName + '" saved successfully!', 'success');
                    // Show restart modal after successful save
                    setTimeout(() => {
                        showRestartModal();
                    }, 1000);
                } else {
                    const errorText = await response.text();
                    showMessage('Error saving schedule: ' + response.status, 'error');
                }
            } catch (error) {
                console.error('Save error:', error);
                showMessage('Error saving schedule: ' + error.message, 'error');
            }
        }

        function showRestartModal() {
            document.getElementById('restart-modal').classList.add('show');
        }

        function closeRestartModal() {
            document.getElementById('restart-modal').classList.remove('show');
        }

        function confirmDeleteSchedule() {
            const schedule = scheduleData.data.items[currentScheduleIndex];
            const scheduleName = schedule.name || schedule.id;
            
            document.getElementById('delete-name').textContent = scheduleName;
            document.getElementById('delete-modal').classList.add('show');
        }

        function closeDeleteModal() {
            document.getElementById('delete-modal').classList.remove('show');
        }

        function deleteSchedule() {
            const scheduleName = scheduleData.data.items[currentScheduleIndex].name;
            
            // Remove the schedule from the array
            scheduleData.data.items.splice(currentScheduleIndex, 1);
            
            // Check if there are any schedules left
            if (scheduleData.data.items.length === 0) {
                showMessage('Cannot delete the last schedule!', 'error');
                closeDeleteModal();
                // Reload to restore the schedule
                loadSchedule();
                return;
            }
            
            // Reset to first schedule if we deleted the current one
            if (currentScheduleIndex >= scheduleData.data.items.length) {
                currentScheduleIndex = 0;
            }
            
            closeDeleteModal();
            updateScheduleList();
            renderSchedule();
            showMessage('Schedule "' + scheduleName + '" deleted. Click Save to confirm.', 'success');
        }

        async function restartHomeAssistant() {
            closeRestartModal();
            showMessage('Restarting Home Assistant...', 'success');
            
            try {
                const response = await fetch('/api/schedule_editor/restart', {
                    method: 'POST'
                });
                
                if (response.ok) {
                    showMessage('Home Assistant is restarting. Please wait...', 'success');
                } else {
                    showMessage('Could not restart Home Assistant', 'error');
                }
            } catch (error) {
                // This is expected as HA will disconnect during restart
                showMessage('Home Assistant is restarting. This page will reload automatically...', 'success');
                
                // Try to reload the page after 30 seconds
                setTimeout(() => {
                    window.location.reload();
                }, 30000);
            }
        }

        function showMessage(text, type) {
            const msg = document.getElementById('message');
            msg.textContent = text;
            msg.className = `message ${type} show`;
            setTimeout(() => {
                msg.className = 'message';
            }, 3000);
        }

        loadSchedule();
    </script>
</body>
</html>
        """
        return web.Response(text=html_content, content_type='text/html')


class ScheduleGetView(HomeAssistantView):
    """View to get the schedule data."""
    
    url = "/api/schedule_editor/get"
    name = "api:schedule_editor:get"
    requires_auth = False
    
    def __init__(self, hass):
        """Initialize."""
        self.hass = hass
    
    async def get(self, request):
        """Get schedule data."""
        schedule_path = self.hass.config.path(".storage/schedule")
        
        try:
            if os.path.exists(schedule_path):
                with open(schedule_path, 'r') as f:
                    data = json.load(f)
                return web.json_response(data)
            else:
                # Return default schedule if file doesn't exist
                default_schedule = {
                    "version": 1,
                    "minor_version": 1,
                    "key": "schedule",
                    "data": {
                        "items": [{
                            "id": "central_heating_2",
                            "name": "Central Heating Schedule",
                            "icon": "mdi:home-clock-outline",
                            "monday": [],
                            "tuesday": [],
                            "wednesday": [],
                            "thursday": [],
                            "friday": [],
                            "saturday": [],
                            "sunday": []
                        }]
                    }
                }
                return web.json_response(default_schedule)
        except Exception as e:
            _LOGGER.error(f"Error loading schedule: {e}")
            return web.json_response({"error": str(e)}, status=500)


class ScheduleSaveView(HomeAssistantView):
    """View to save the schedule data."""
    
    url = "/api/schedule_editor/save"
    name = "api:schedule_editor:save"
    requires_auth = False
    
    def __init__(self, hass):
        """Initialize."""
        self.hass = hass
    
    async def post(self, request):
        """Save schedule data."""
        schedule_path = self.hass.config.path(".storage/schedule")
        
        try:
            data = await request.json()
            
            # Create backup of existing file
            if os.path.exists(schedule_path):
                backup_path = f"{schedule_path}.backup"
                with open(schedule_path, 'r') as f:
                    backup_data = f.read()
                with open(backup_path, 'w') as f:
                    f.write(backup_data)
                _LOGGER.info("Created backup of schedule")
            
            # Save new data
            with open(schedule_path, 'w') as f:
                json.dump(data, f, indent=2)
            
            _LOGGER.info("Schedule saved successfully")
            
            # Reload the schedule integration
            try:
                await self.hass.services.async_call(
                    "homeassistant",
                    "reload_config_entry",
                    {"entry_id": "schedule"},
                    blocking=True
                )
                _LOGGER.info("Schedule integration reloaded")
            except Exception as reload_error:
                _LOGGER.warning(f"Could not reload schedule automatically: {reload_error}")
                # Try alternative reload method
                try:
                    # Fire an event to trigger schedule reload
                    self.hass.bus.async_fire("schedule_updated")
                    _LOGGER.info("Fired schedule_updated event")
                except Exception as e:
                    _LOGGER.warning(f"Could not fire reload event: {e}")
            
            return web.json_response({"success": True, "message": "Schedule saved and reloaded successfully"})
        except Exception as e:
            _LOGGER.error(f"Error saving schedule: {e}")
            return web.json_response({"error": str(e)}, status=500)


class ScheduleRestartView(HomeAssistantView):
    """View to restart Home Assistant."""
    
    url = "/api/schedule_editor/restart"
    name = "api:schedule_editor:restart"
    requires_auth = False
    
    def __init__(self, hass):
        """Initialize."""
        self.hass = hass
    
    async def post(self, request):
        """Restart Home Assistant."""
        try:
            _LOGGER.info("Restarting Home Assistant via Schedule Editor")
            
            # Call the homeassistant.restart service
            await self.hass.services.async_call(
                "homeassistant",
                "restart",
                blocking=False
            )
            
            return web.json_response({"success": True, "message": "Home Assistant is restarting"})
        except Exception as e:
            _LOGGER.error(f"Error restarting Home Assistant: {e}")
            return web.json_response({"error": str(e)}, status=500)
  1. Create another new file and name it “manifest.json” and paste in the following:
{
  "domain": "schedule_editor",
  "name": "Schedule Editor",
  "version": "1.0.0",
  "documentation": "https://github.com/yourusername/ha-schedule-editor",
  "requirements": [],
  "dependencies": [],
  "codeowners": ["@yourusername"],
  "iot_class": "local_polling"
}
  1. go to your “configuration.yaml” file and below the “homeassistant:” section (no indentation) add the following:
schedule_editor:

Restart HA and then in your menu bar on the left you will find the “Schedule Editor”.
(Note that you will first see a non fatal error, which does not prevent Home Assistant from restarting, this is because you added the schedule_editor: to your configuration file, however until you restart and load the new initi.py file it is not available to HA. The error only occurs on first installation).

Use and enjoy!!

1 Like