UNPKG

@lahoco/node-red-contrib-lahoco-core

Version:

Node-RED LAHOCO nodes bundle

221 lines (196 loc) 7.37 kB
/* * Copyright (c) 2025. KYMO SA * All rights reserved. */ (function () { if (!RED.nodes.lahocoUtils) { RED.nodes.lahocoUtils = {}; } // Only define it if it hasn't already been defined if (!RED.nodes.lahocoUtils.defaultNode) { RED.nodes.lahocoUtils.defaultNode = { category: 'LAHOCO', color: '#ffd740', defaults: { name: {value: ''}, config: {required: true, type: 'lahoco-server'}, deviceId: {required: true}, deviceType: {}, deviceGatewayId: {} }, outputs: 1 }; } })(); /** * Initializes the event listeners for the device search and device/server dropdowns. * * Adds an event listener to the device search button that calls the provided search function * with the ID of the currently selected server. * Adds an event listener to the device dropdown that calls the changeNameFromSelectedDevice * function to change the name of the node when the device is selected. * Adds an event listener to the server dropdown that calls the provided search function * with the ID of the currently selected server. * * @param {(serverId: string) => void} onSearch - The function to call for searching devices with the server ID. * @param {(deviceId: string) => void} onChangeDevice - The function to call when the device is changed. */ function init(onSearch, onChangeDevice) { let changeTimeout; // device search on click $('#node-input-scan-devices').click(() => { clearTimeout(changeTimeout); changeTimeout = setTimeout(() => { search((serverId) => onSearch(serverId)); }, 200); // wait 200ms to see if another change occurs }); // on change device $('#node-input-deviceId').change(() => { changeNameFromSelectedDevice(); onChangeDevice(parseInt($('#node-input-deviceId').val())); }); // on change config $('#node-input-config').change(() => { clearTimeout(changeTimeout); changeTimeout = setTimeout(() => { search((serverId) => onSearch(serverId)); }, 200); // wait 200ms to see if another change occurs }); } /** * Initiates a search for devices associated with the selected server. * * Retrieves the server ID from the server dropdown, verifies the server exists, * and calls the provided search function to search for devices. * If the server is not set, notifies the user to set and deploy the server. * * @param {(serverId: string) => void} onSearch - The function to call for searching devices with the server ID. */ function search(onSearch) { const serverId = $('#node-input-config').val(); $('#node-input-scan-devices').prop('disabled', false); $('#node-input-deviceId').empty(); if (serverId !== '_ADD_') { const searchIcon = $('#node-input-scan-devices').find('i'); searchIcon.removeClass('fa-search'); searchIcon.addClass('fa-refresh'); searchIcon.addClass('fa-spin'); onSearch(serverId); } } /** * Changes the name of the node to the name of the selected device. */ function changeNameFromSelectedDevice() { let name = $('#node-input-deviceId option:selected').text(); if (name.includes('(')) { name = name.split(' (')[0]; if (name.includes('] ')) { name = name.split('] ')[1]; } } $('#node-input-name').val(name); } /** * Called when a device search fails. * * Notifies the user of the failure and resets the UI elements to the initial state. */ function searchDevicesError() { RED.notify('No devices could be recovered', {type: 'error', timeout: 2000}); changeSearchToInitial(); } /** * Called when a scene search fails. * * Notifies the user of the failure and resets the UI elements to the initial state. */ function searchScenesError() { RED.notify('No scenes could be recovered', {type: 'error', timeout: 2000}); changeSearchToInitial(); } /** * Resets the UI elements to the initial state before a device search. * * If `server` is true, clears the server dropdown. * Otherwise, clears the device ID dropdown. * * @param {boolean} [server=false] - Whether to reset the server dropdown (`true`) or the device ID dropdown (`false`). */ function changeSearchToInitial(server = false) { server ? $('#node-input-config').empty() : $('#node-input-deviceId').empty(); const searchIcon = $('#node-input-scan-devices').find('i'); searchIcon.removeClass('fa-refresh'); searchIcon.removeClass('fa-spin'); searchIcon.addClass('fa-search'); } /** * Updates the UI to reflect a successful device search. * * @param {{ id: string }[]} devices - Array of devices with at least an `id` field. * @param {string} currentDeviceId - The ID of the currently selected device. */ function changeSearchToSuccess(devices, currentDeviceId) { const deviceSelect = $('#node-input-deviceId'); // select current device const device = devices?.find(device => device?.id?.toString() === currentDeviceId); if (device) { deviceSelect.val(device.id).change(); } deviceSelect.removeAttr('disabled') const searchIcon = $('#node-input-scan-devices').find('i'); searchIcon.removeClass('fa-search'); searchIcon.removeClass('fa-spin'); searchIcon.addClass('fa-refresh'); } /** * Updates the UI to indicate that no devices or scenes are available. * * @param {{ id: string }[]} devices devices - The array of devices to display. This is not used when showing no devices. * @param {boolean} [isScene=false] - Determines whether the message should refer to scenes or devices. */ function showNoDevices(devices, isScene = false) { const select = $('#node-input-deviceId'); select.html( $('<option>', { value: '', text: isScene ? 'No scenes found' : 'No devices found', selected: true, disabled: true }) ); select.prop('disabled', true); const searchIcon = $('#node-input-scan-devices').find('i'); searchIcon.removeClass('fa-refresh'); searchIcon.removeClass('fa-spin'); searchIcon.addClass('fa-search'); } /** * Displays the result based on the provided devices and current device ID. * * @param {{ id: string }[]} devices devices - List of devices to evaluate. * @param {string} currentDeviceId - Identifier of the current device. * @param {boolean} [isScene=false] - Indicates if the result is for a scene. */ function showResult(devices, currentDeviceId, isScene = false) { if (!devices || devices.length === 0) { showNoDevices(devices, isScene); } else { changeSearchToSuccess(devices, currentDeviceId); } } /** * Adds a device option to a dropdown menu. * * @param {object} RED - The RED runtime object to manage context and utilities. * @param {{id: number|string, deviceType: string|number, name: string, uname?: string}} device - The device object containing details about the device to be added. * @param {{id: string|number, translation: string}[]} types - An array of type objects used to determine the device type translation. * @return {void} This method does not return any value. */ function addDeviceOption(RED, device, types) { const typeTranslation = types.find(type => type.id === device.deviceType)?.translation; $('#node-input-deviceId').append($('<option>', { value: `${device.id}`, text: `[${RED._('@lahoco/node-red-contrib-lahoco-core/lahoco-server:commons.' + typeTranslation)}] ${device.name} ${device.uname ? '(' + device.uname + ')' : ''}` })).change(); }