diff --git a/firmware/README-API.md b/firmware/README-API.md index 90b83ef..f5c6ab1 100644 --- a/firmware/README-API.md +++ b/firmware/README-API.md @@ -5,6 +5,7 @@ This document describes all REST API endpoints and WebSocket messages required f ## Table of Contents - [REST API Endpoints](#rest-api-endpoints) + - [Capabilities](#capabilities) - [WiFi](#wifi) - [Light Control](#light-control) - [LED Configuration](#led-configuration) @@ -20,6 +21,33 @@ This document describes all REST API endpoints and WebSocket messages required f ## REST API Endpoints +### Capabilities + +#### Get Device Capabilities + +Returns the device capabilities. Used to determine which features are available. + +- **URL:** `/api/capabilities` +- **Method:** `GET` +- **Response:** + +```json +{ + "thread": true +} +``` + +| Field | Type | Description | +|--------|---------|-------------------------------------------------------| +| thread | boolean | Whether Thread/Matter features are enabled | + +**Notes:** +- If `thread` is `true`, the UI shows Matter device management and Scenes +- If `thread` is `false` or the endpoint is unavailable, these features are hidden +- The client can also force-enable features via URL parameter `?thread=true` + +--- + ### WiFi #### Scan Networks diff --git a/firmware/storage/www/index.html b/firmware/storage/www/index.html index 88a9812..85415bd 100644 --- a/firmware/storage/www/index.html +++ b/firmware/storage/www/index.html @@ -137,8 +137,10 @@ - - + + @@ -449,6 +451,7 @@ + diff --git a/firmware/storage/www/js/app.js b/firmware/storage/www/js/app.js index ae12198..7a81dc7 100644 --- a/firmware/storage/www/js/app.js +++ b/firmware/storage/www/js/app.js @@ -41,13 +41,18 @@ document.addEventListener('touchend', (e) => { }, false); // Initialization -document.addEventListener('DOMContentLoaded', () => { +document.addEventListener('DOMContentLoaded', async () => { initI18n(); initTheme(); + await initCapabilities(); initWebSocket(); updateConnectionStatus(); - loadScenes(); - loadPairedDevices(); + + // Only load scenes and devices if thread is enabled + if (isThreadEnabled()) { + loadScenes(); + loadPairedDevices(); + } // WiFi status polling (less frequent) setInterval(updateConnectionStatus, 30000); }); diff --git a/firmware/storage/www/js/capabilities.js b/firmware/storage/www/js/capabilities.js new file mode 100644 index 0000000..1ffa677 --- /dev/null +++ b/firmware/storage/www/js/capabilities.js @@ -0,0 +1,94 @@ +// Capabilities Module +// Checks device capabilities and controls feature visibility + +let capabilities = { + thread: false +}; + +/** + * Initialize capabilities module + * Fetches from server, falls back to URL parameter for offline testing + */ +async function initCapabilities() { + // Try to fetch from server first + const success = await fetchCapabilities(); + + // If server not available, check URL parameter (for offline testing) + if (!success) { + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.get('thread') === 'true') { + capabilities.thread = true; + } + } + + // Apply visibility based on capabilities + applyCapabilities(); +} + +/** + * Fetch capabilities from server + * @returns {boolean} true if successful + */ +async function fetchCapabilities() { + try { + const response = await fetch('/api/capabilities'); + if (response.ok) { + const data = await response.json(); + capabilities = { ...capabilities, ...data }; + return true; + } + return false; + } catch (error) { + console.log('Capabilities not available, using defaults'); + return false; + } +} + +/** + * Check if thread/Matter is enabled + * @returns {boolean} + */ +function isThreadEnabled() { + return capabilities.thread === true; +} + +/** + * Apply capabilities to UI - show/hide elements + */ +function applyCapabilities() { + const threadEnabled = isThreadEnabled(); + + // Elements to show/hide based on thread capability + const threadElements = [ + // Control tab elements + 'scenes-control-card', + 'devices-control-card', + // Config sub-tabs + 'subtab-btn-devices', + 'subtab-btn-scenes', + // Config sub-tab contents + 'subtab-devices', + 'subtab-scenes' + ]; + + threadElements.forEach(id => { + const element = document.getElementById(id); + if (element) { + element.style.display = threadEnabled ? '' : 'none'; + } + }); + + // Also hide scene devices section in scene modal if thread disabled + const sceneDevicesSection = document.querySelector('#scene-modal .form-group:has(#scene-devices-list)'); + if (sceneDevicesSection) { + sceneDevicesSection.style.display = threadEnabled ? '' : 'none'; + } +} + +/** + * Get all capabilities + * @returns {object} + */ +function getCapabilities() { + return { ...capabilities }; +}