Helpers API - Developer Guide
This guide explains the architecture and usage of the LCARdS helper management system for developers extending or maintaining the codebase.
Architecture Overview
The helper system consists of three main components:
┌─────────────────────────────────────┐
│ Helper Registry (Schema) │
│ - Authoritative definitions │
│ - YAML templates │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Helper Manager (Service) │
│ - Lifecycle management │
│ - State monitoring │
│ - Value access │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ Helper API (WebSocket Wrapper) │
│ - Create/delete operations │
│ - Entity registry updates │
└─────────────────────────────────────┘Core Components
1. Helper API (lcards-helper-api.js)
Low-level WebSocket API wrapper for Home Assistant helper operations.
Functions:
// Create a new helper
await createHelper(hass, domain, name, attributes);
// Delete a helper
await deleteHelper(hass, domain, helperId);
// Rename helper entity_id
await updateHelperEntityId(hass, currentEntityId, newEntityId);
// Idempotent creation (check + create if missing)
await ensureHelper(hass, definition);
// Check existence
const exists = helperExists(hass, entityId);
// Get value
const value = getHelperValue(hass, entityId, defaultValue);
// Set value (public API)
await setHelperValue(hass, entityId, value);WebSocket API Notes:
The HA WebSocket API for helpers is undocumented and may change:
// Create input_number
await hass.callWS({
type: 'input_number/create',
name: 'Helper Name',
min: 0,
max: 100,
step: 1,
mode: 'slider',
icon: 'mdi:icon'
});
// Rename entity
await hass.callWS({
type: 'config/entity_registry/update',
entity_id: 'input_number.old_id',
new_entity_id: 'input_number.new_id'
});Supported Domains:
input_number- Sliders and number inputsinput_select- Dropdownsinput_boolean- Togglesinput_text- Free-text storage (e.g. JSON config blobs)
Error Handling:
All functions throw errors with meaningful messages. Always wrap in try/catch:
try {
await createHelper(hass, 'input_number', 'My Helper', {
min: 0,
max: 100,
step: 1
});
} catch (error) {
console.error('Failed to create helper:', error.message);
}2. Helper Registry (lcards-helper-registry.js)
Authoritative schema defining all LCARdS helpers.
Registry Structure:
export const HELPER_REGISTRY = {
helper_key: {
entity_id: 'input_select.lcards_helper_name',
domain: 'input_select',
name: 'Human Readable Name',
description: 'Purpose and usage',
icon: 'mdi:icon-name',
category: 'category_name',
ws_create_params: {
// Domain-specific parameters
options: ['option1', 'option2']
},
default_value: 'option1',
yaml_config: `input_select:
lcards_helper_name:
name: Human Readable Name
options:
- option1
- option2
icon: mdi:icon-name`
}
};Key Fields:
entity_id: Desired entity ID in Home Assistantdomain: Helper type (input_number,input_select,input_boolean,input_text)ws_create_params: Parameters for WebSocket creationdefault_value: Fallback value if helper doesn't existyaml_config: Valid YAML for manual creation
Utility Functions:
// Get helpers by category
const alertHelpers = getHelpersByCategory('alert_system');
// Get all categories
const categories = getCategories();
// Lookup by key
const definition = getHelperDefinition('alert_mode');
// Get all helpers
const all = getAllHelpers();
// Generate YAML
const yaml = generateHelpersYAML();
const categoryYaml = generateHelpersYAML('alert_system');
// Find by entity_id
const helper = findHelperByEntityId('input_select.lcards_alert_mode');3. Helper Manager (lcards-helper-manager.js)
Service class managing helper lifecycle and state.
Initialization:
import { LCARdSHelperManager } from './core/helpers/lcards-helper-manager.js';
const helperManager = new LCARdSHelperManager(hass);
// Integrated in core
window.lcards.core.helperManagerLifecycle Methods:
// Get missing helpers
const missing = helperManager.getMissingHelpers();
// Create all missing helpers
const results = await helperManager.ensureAllHelpers();
// Returns: { total, existing, created, failed, errors }
// Create single helper
await helperManager.ensureHelper('alert_mode');State Access:
// Get current value (or default)
const mode = helperManager.getHelperValue('alert_mode');
// Set value (calls HA service)
await helperManager.setHelperValue('alert_mode', 'red_alert');
// Check existence
if (helperManager.helperExists('alert_mode')) {
// Helper exists
}Reactivity:
// Subscribe to changes
const unsubscribe = helperManager.subscribeToHelper(
'alert_mode',
(newValue, oldValue) => {
console.log(`Alert mode changed: ${oldValue} → ${newValue}`);
}
);
// Cleanup
unsubscribe();
// Or unsubscribe by key
helperManager.unsubscribeFromHelper('alert_mode');Helper Bindings (Future):
// Resolve helper bindings in card config
const config = {
alertMode: null,
threshold: null
};
const bindings = {
alertMode: 'alert_mode',
threshold: 'alert_threshold'
};
const resolved = helperManager.resolveHelperBindings(config, bindings);
// Returns config with values from helpersExport:
// Generate YAML
const yaml = helperManager.generateYAML();
const alertYaml = helperManager.generateYAML('alert_system');
// Get helpers by category
const helpers = helperManager.getHelpersByCategory('alert_system');Adding New Helpers
Step 1: Define in Registry
Add to HELPER_REGISTRY in lcards-helper-registry.js:
export const HELPER_REGISTRY = {
// ... existing helpers
my_new_helper: {
entity_id: 'input_boolean.lcards_my_feature_enabled',
domain: 'input_boolean',
name: 'My Feature Enabled',
description: 'Enable or disable my cool feature',
icon: 'mdi:feature-search',
category: 'features',
ws_create_params: {}, // input_boolean has no extra params
default_value: false,
yaml_config: `input_boolean:
lcards_my_feature_enabled:
name: My Feature Enabled
icon: mdi:feature-search`
}
};Step 2: Use in Code
Access via Helper Manager:
// Check if feature is enabled
const isEnabled = window.lcards.core.helperManager.getHelperValue('my_new_helper');
if (isEnabled) {
// Feature logic
}
// Subscribe to changes
window.lcards.core.helperManager.subscribeToHelper(
'my_new_helper',
(enabled) => {
// React to changes
this.featureEnabled = enabled;
this.requestUpdate();
}
);Step 3: Document
Update user documentation with:
- Purpose of the helper
- Expected values
- Usage examples
- Automation integration
Integration Points
Core System
The Helper Manager is initialized in lcards-core.js:
// Initialize HelperManager (Phase 2f)
this.helperManager = new LCARdSHelperManager(hass);
// Update HASS
if (this.helperManager) {
this.helperManager.updateHass(hass);
}Access globally:
window.lcards.core.helperManagerAlert Lab & Configuration Panel
Both consumers use the same Helper Manager API already documented above — no new methods. The Alert Lab reads/writes alert_lab_{mode}_{hue,saturation,lightness} keys via getHelperValue()/setHelperValue() on open/save; the Config Panel lists helper status via getAllHelpers() + helperExists() + getHelperValue(), and bulk-creates missing ones via ensureAllHelpers().
Best Practices
- Naming: prefix all helpers with
lcards_, snake_case entity IDs, group by category in the registry. - Error handling: wrap
createHelper()/setHelperValue()calls in try/catch — see the Error Handling notes under Helper API above. - State: subscribe to changes for reactive updates instead of polling, and unsubscribe on component cleanup (
unsubscribeFromHelper()or the function returned bysubscribeToHelper()). - Performance: batch helper creation via
ensureAllHelpers()rather than loopingensureHelper()calls; avoid excessive subscriptions.
There is no automated test suite for this project — validate helper changes manually: create via the Config Panel, confirm the entity appears in HA, exercise Alert Lab save/reload, and trigger a value change from an automation.