UNPKG

node-red-contrib-domotz

Version:

A collection of Node-Red nodes to access the Domotz public API

536 lines (474 loc) 20.8 kB
<script type="text/javascript"> var clone = function (v) { try { return JSON.parse(JSON.stringify(v)); } catch (e) { return null; } }; var PARAMS_OP_MAP = { 'agent_id': 'agent.listAgents', 'device_id': 'device.listDevices', 'sensor_id': 'eyes.listEyesSNMP', }; var PARAMETER_OPTIONS = Object.freeze({ IDS: 'IDS', INPUT_PARAMS: 'INPUT_PARAMS', BROWSE: 'BROWSE', }); var cache = { 'agent_id': {}, 'device_id': {}, 'sensor_id': {}, }; function capitalizeFirstLetter (string) { return string.charAt(0).toUpperCase() + string.slice(1); } var BROWSABLE_IDs = Object.keys(PARAMS_OP_MAP); RED.nodes.registerType('domotz-api', { category: 'Domotz', color: '#a6bbcf', defaults: { name: {value: ''}, api: {value: '', type: 'domotz-api-conf'}, operation: { value: '', required: true, }, endpointsMap: {}, parameters: { validate: function (v) { var node = this; if (!node.operation || !node.endpointsMap) { return false; } if (node.useinputparams || node.parameterOptions === PARAMETER_OPTIONS.INPUT_PARAMS) { return true; } var op = node.endpointsMap[node.operation]; if (!op) { return false; } var missingRequiredParams = false; $.each(op.parameters || [], function (idx, param) { if (!missingRequiredParams && param.required && !v[param.name]) { missingRequiredParams = true; } }); return !missingRequiredParams; }, }, body: { validate: function (v) { var node = this; if (!node.operation || !node.endpointsMap) { return false; } if (node.useinputparams || node.parameterOptions === PARAMETER_OPTIONS.INPUT_PARAMS) { return true; } var op = node.endpointsMap[node.operation]; if (!op) { return false; } if (!op.requestBody || !op.requestBody.required) { return true; } if (!v) { return false; } try { JSON.parse(v) return true; } catch (e) { return false; } } }, useinputparams: {}, parameterOptions: {}, availableEndpoints: [], oldOperation: {}, oldName: {}, oldParameters: {}, oldUseinputparams: {}, oldParameterOptions: {}, hidden: { value: 0, }, }, inputs: 1, outputs: 2, icon: 'domotz.png', label: function () { return this.name || 'domotz-api'; }, inputLabels: 'input parameters', outputLabels: ['result', 'errors'], oneditprepare: function () { var node = this; if (!node.parameters) { node.parameters = {}; } if (!node.parameterOptions) { node.parameterOptions = PARAMETER_OPTIONS.BROWSE; } node.oldOperation = clone(node.operation); node.oldName = clone(node.name); node.oldParameters = clone(node.parameters); node.oldBody = clone(node.body); node.oldUseinputparams = clone(node.useinputparams); node.oldParameterOptions = clone(node.parameterOptions); if (node.useinputparams === true || node.useinputparams === false) { node.parameterOptions = node.useinputparams ? 'INPUT_PARAMS' : 'IDS'; node.useinputparams = null; } var confSelect = $('#node-input-api'); var confIDVal = confSelect.val(); var selectOperation = $('#node-input-operation'); var operationSummary = $('#operation-summary'); var apiSummary = $('#api-summary'); var username = $('#username'); var operationParams = $('#operation-params'); var operationParamsCheckbox = $('#operation-params-checkbox'); var operationParamsSelector = $('#operation-params-selector'); var operationParamsOptions = $('#operation-params-options'); function disableInputParams (val) { operationParams.children().each(function () { $($(this).children('input')).prop('disabled', val); }); } function createParametersSelector () { operationParamsOptions.show(); operationParamsSelector.val(node.parameterOptions); operationParamsSelector.off('change'); operationParamsSelector.change(function () { node.parameterOptions = operationParamsSelector.val(); setOperationSummary(); if (node.parameterOptions === PARAMETER_OPTIONS.INPUT_PARAMS) { disableInputParams(true); return; } else if (node.parameterOptions === PARAMETER_OPTIONS.BROWSE) { node.useinputparams = null; } disableInputParams(false); }); } selectOperation.off('change'); selectOperation.change(function () { var currentSelection = $('#node-input-operation option:selected').text(); if (currentSelection && currentSelection !== node.operation) { node.operation = currentSelection; setOperationSummary(); } }); function initOperationSelector () { if (!node.endpointsMap || !node.availableEndpoints) { return; } $('op-container').show(); selectOperation.empty(); selectOperation.append($('<option></option>') .attr('disabled', 'true') .attr('selected', 'true') .text('-- select a method --')); $.each(node.availableEndpoints, function (index, endpoint) { selectOperation.append( $('<option></option>').attr('value', endpoint).attr('selected', node.operation === endpoint) .text(endpoint)); if (node.operation && node.operation === endpoint) { setOperationSummary(); } }); } var fillBrowsableParams = function (param, formRow, label) { label.text(capitalizeFirstLetter(param.name.replace('_id', '')) + (param.required ? '*' : '')); var op = PARAMS_OP_MAP[param.name]; var ep = node.endpointsMap[op].path; var opParams = node.endpointsMap[op].parameters; opParams = opParams.filter(function (p) { return BROWSABLE_IDs.indexOf(p.name) > -1; }); var allParamsConverted = opParams.length === 0; $.each(opParams, function (j, p) { if (node.parameters[p.name]) { ep = ep.replace('{' + p.name + '}', node.parameters[p.name]); allParamsConverted = true; } else { allParamsConverted = false; } }); if (allParamsConverted) { var cached = cache[param.name][ep]; var process = function (res) { if (!res) { return; } cache[param.name][ep] = res; var input = $('<select>'); input.append($('<option></option>') .attr('disabled', 'true') .attr('selected', 'true') .text(' -- ')); $(res).each(function () { input.append( $('<option>').attr('value', this.id).text(this.display_name || this.name)); }); var ids = res ? res.map(function (item) { return item.id; }) : []; formRow.append(label); formRow.append(input); if (node.parameters && node.parameters[param.name] && ids.indexOf(parseInt(node.parameters[param.name])) > -1) { input.val(node.parameters[param.name]); } else if (res && res.length > 0) { input.val(res[0].id); node.parameters[param.name] = res[0].id; } input.off('change'); input.change(function () { node.parameters[param.name] = input.val(); setOperationSummary(); }); }; if (cached) { process(cached); } else { getResource(ep, process); } } }; var fillIDParams = function (param, formRow, label) { label.text(param.name + (param.required ? '*' : '')); var input = $('<input type="text">'); input.attr('placeholder', param.description); input.attr('id', param.name); if (node.parameters) { var val = node.parameters[param.name] || null; if (val !== null) { input.val(val); } } formRow.append(label); formRow.append(input); }; var setOperationSummary = function () { if (!node.endpointsMap || !node.operation) { return; } operationParams.empty(); operationSummary.html(node.endpointsMap[node.operation]['summary']); var parameters = node.endpointsMap[node.operation]['parameters']; operationParamsCheckbox.text(''); if (parameters) { createParametersSelector(); $.each(parameters, function (idx, param) { var formRow = $('<div class="form-row"></div>'); var label = $('<label></label>'); if (node.parameterOptions === PARAMETER_OPTIONS.BROWSE && BROWSABLE_IDs.indexOf(param.name) > -1) { fillBrowsableParams(param, formRow, label); } else { fillIDParams(param, formRow, label); } formRow.attr('title', param.description); formRow.attr('id', param.name); operationParams.append(formRow); }); var requestBody = node.endpointsMap[node.operation].requestBody; if (requestBody) { var formRow = $('<div class="form-row"></div>'); var label = $('<label></label>'); label.text("Body" + (requestBody.required ? '*' : '')); var input = $('<input type="text">'); input.attr('placeholder', "Body"); input.attr('id', 'operation-body'); if (node.body) { input.val(node.body); } formRow.append(label); operationParams.append(formRow); formRow.append(input); } if (node.useinputparams || node.parameterOptions === PARAMETER_OPTIONS.INPUT_PARAMS) { disableInputParams(true); } } else { operationParamsOptions.hide(); } }; loadAvailableEndpoints(); function resetInterface () { apiSummary.empty(); username.empty(); selectOperation.empty(); operationParamsCheckbox.empty(); operationParams.empty(); operationSummary.empty(); } function prepareQueryParams () { var configNodeId = confSelect.val(); if (configNodeId && configNodeId !== '_ADD_') { node.configNodeId = configNodeId; var configNode = RED.nodes.node(configNodeId); var qs = '?'; if (configNode.credentials) { qs += 'endpoint=' + configNode.endpoint + '&key=' + configNode.credentials.key; } else { qs += 'conf_node=' + configNodeId; } return qs; } } function loadAvailableEndpoints () { var qs = prepareQueryParams(); if (!qs) { resetInterface(); return; } $.getJSON('domotz-api-info' + qs, function (apiInfo) { apiSummary.text(apiInfo.title + ' - v' + apiInfo.version); node.endpointsMap = apiInfo.endpointsMap; node.availableEndpoints = apiInfo.availableEndpoints; initOperationSelector(); }).fail(function () { resetInterface(); apiSummary.text('Unable to retrieve API description'); }); } function getResource (path, cb) { var qs = prepareQueryParams(); if (!qs) { return cb(); } qs += '&path=' + path; $.getJSON('domotz-api-call' + qs, function (apiRes) { cb(apiRes); }).fail(function () { apiSummary.text('Unable to retrieve API description'); }); } confSelect.off('change'); confSelect.change(function () { var currentSelection = confSelect.val(); if (confIDVal !== currentSelection) { confIDVal = currentSelection; loadAvailableEndpoints(); } }); }, oneditsave: function () { var node = this; node.parameters = {}; node.hidden = !node.hidden; var operationParams = $('#operation-params'); operationParams.children().each(function () { if ($($(this).children('input')).val()) { node.parameters[this.id] = $($(this).children('input')).val(); } else { node.parameters[this.id] = $($(this).children('select')).val(); } }); var operationBody = $('#operation-body'); if (!operationBody) { return; } node.body = operationBody.val(); }, oneditcancel: function () { var node = this; node.operation = clone(node.oldOperation); node.name = clone(node.oldName); node.parameters = clone(node.oldParameters); node.useinputparams = clone(node.oldUseinputparams); node.parameterOptions = clone(node.oldParameterOptions); node.body = clone(node.oldBody); }, }); </script> <script type="text/x-red" data-template-name="domotz-api"> <div> <h4 id="api-summary"></h4> <p id="username"></p> </div> <div class="form-row"> <label for="node-input-api"><i class="fa fa-wrench"></i> Conf</label> <input type="text" id="node-input-api" placeholder=""> </div> <div class="form-row"> <label for="node-input-name"><i class="icon-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="Name"> </div> <div class="form-row"> <label for="node-input-operation"><i class="fa fa-list"></i> API</label> <select id="node-input-operation"></select> </div> <div id="op-container" style="visible: false" ></div> <h4 id="operation-summary" style="max-width: 400px;"></h4> <div id="operation-params-options" style="visible: false" class="form-row"> <label for="other-options">Parameters</label> <select name="other-options" id="operation-params-selector"> <option value="IDS">Use IDs</option> <option value="INPUT_PARAMS">Use node input params</option> <option value="BROWSE">Browse</option> </select> </div> <div id="operation-params"></div> </script> <script type="text/x-red" data-help-name="domotz-api"> <p>Domotz Public API</p> <h3>Details</h3> This node helps performing API calls to the Domotz Public API. API parameters can be set in the configuration section or via node's input. The node automatically converts url and query parameters. <h3>Inputs</h3> An optional payload with the operation's parameters, e.g.: <code>{"params": {"agent_id": "xyz"}}</code> Static parameters can be alternatively defined in the configuration of the node. Required parameters are marked with an *. Using the "Browse" option you can select agents, devices and sensors by name (note that this feature will use some of your API budged to retrieve the necessary resources). <h3>Outputs</h3> <ol class="node-ports"> <li>Output <dl class="message-properties"> <dt>payload.code <span class="property-type">string</span></dt> <dd>The HTTP code</dd> </dl> <dl class="message-properties"> <dt>payload.message <span class="property-type">string</span></dt> <dd>the payload of the HTTP response</dd> </dl> <dl class="message-properties"> <dt>payload.headers <span class="property-type">string</span></dt> <dd>the HTTP response headers</dd> </dl> <dl class="message-properties"> <dt>payload.inputParams <span class="property-type">string</span></dt> <dd>the input parameters</dd> </dl> <dl class="message-properties"> <dt>payload.configParams <span class="property-type">string</span></dt> <dd>the configuration parameters</dd> </dl> </li> <li>Errors <dl class="message-properties"> <dt>payload.code <span class="property-type">string</span></dt> <dd>The HTTP error code</dd> </dl> <dl class="message-properties"> <dt>payload.message <span class="property-type">string</span></dt> <dd>The HTTP response content</dd> </dl> </li> </ol> <h3>References</h3> <ul> <li><a href="https://portal.domotz.com/developers">Domotz Developers</a> - for more details on the Domotz API</li> <li><a href="https://portal.domotz.com">Domotz Portal</a> - subscribe and get an API-Key</li> <li><a href="https://www.domotz.com">Domotz</a></li> </ul> </script>