Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

node-red-contrib-deconz

Package Overview
Dependencies
Maintainers
2
Versions
146
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-red-contrib-deconz - npm Package Compare versions

Comparing version 2.3.1 to 2.3.2

104

CHANGELOG.md

@@ -10,2 +10,16 @@ # Changelog

## [2.3.2] - 2022-01-29 ![Relative date](https://img.shields.io/date/1643459917?label=)
### Added
- Added HomeKit attribute Position State for windows cover. @Zehir
### Changed
- Removed invalid HomeKit attributes ContactSensorState and On for windows cover. @Zehir
### Fixed
- Fix loading of default values for api node. @Zehir
## [2.3.1] - 2022-01-10 ![Relative date](https://img.shields.io/date/1642253886?label=)

@@ -15,3 +29,3 @@

- Add missing HomeKit conversion for Windows cover attributes. Fix #196.
- Add missing HomeKit conversion for Windows cover attributes. (#196) @Zehir

@@ -22,8 +36,8 @@ ## [2.3.0] - 2022-01-10 ![Relative date](https://img.shields.io/date/1641848273?label=)

- Scenes call target for Custom commands. Implement #184.
- Api node for sending commands to the bridge. Implement #193.
- Scenes call target for Custom commands. (#184) @Zehir
- Api node for sending commands to the bridge. (#193) @Zehir
### Fixed
- Do not display websocket errors on server stop. Fix #165 and #192.
- Do not display websocket errors on server stop. (#165) (#192) @Zehir

@@ -34,5 +48,5 @@ ## [2.2.1] - 2021-12-26 ![Relative date](https://img.shields.io/date/1640557627?label=)

- Display error when trying to load a device list with an undeployed server configuration node.
- Make sure that the default scene call mode is single. #190.
- Fix scene picker loading on undeployed server node. #190.
- Display error when trying to load a device list with an undeployed server configuration node. @Zehir
- Make sure that the default scene call mode is single. (#190) @Zehir
- Fix scene picker loading on undeployed server node. (#190) @Zehir

@@ -43,8 +57,8 @@ ## [2.2.0] - 2021-12-26 ![Relative date](https://img.shields.io/date/1640544039?label=)

- Dynamic scene call, you can now call a scene from the device selection and the scene name. Implement #184.
- Dynamic scene call, you can now call a scene from the device selection and the scene name. (#184) @Zehir
### Fixed
- Cleanup status on requests errors. Fix #185
- Do not display device not set if commands have only scene call. Fix #186
- Cleanup status on requests errors. (#185) @Zehir
- Do not display device not set if commands have only scene call. (#186) @Zehir

@@ -55,4 +69,4 @@ ## [2.1.3] - 2021-12-06 ![Relative date](https://img.shields.io/date/1638803271?label=)

- Fix error msg for device with no color. Fix #182.
- Fix input node displaying incorrect status.
- Fix error msg for device with no color. (#182) @Zehir
- Fix input node displaying incorrect status. @Zehir

@@ -63,3 +77,3 @@ ## [2.1.2] - 2021-11-26 ![Relative date](https://img.shields.io/date/1637939322?label=)

- Fix formatting value of ContactSensorState for HomeKit. (@WildPhilippAppeared - #180)
- Fix formatting value of ContactSensorState for HomeKit. (#180) @WildPhilippAppeared

@@ -70,3 +84,3 @@ ## [2.1.1] - 2021-11-25 ![Relative date](https://img.shields.io/date/1637877535?label=)

- Fix tests of configuration migration.
- Fix tests of configuration migration. @Zehir

@@ -79,4 +93,4 @@ ## [2.1.0] - 2021-11-25 ![Relative date](https://img.shields.io/date/1637870587?label=)

- You can now select which characteristics you want in the payload.
- Initial support for ZHAThermostat. Can be used with Heater Cooler or Thermostat.
- You can now select which characteristics you want in the payload. @Zehir
- Initial support for ZHAThermostat. Can be used with Heater Cooler or Thermostat. @Zehir

@@ -87,9 +101,9 @@ ### Changed

- Rework HomeKit attributes handling.
- Rework HomeKit attributes handling. @Zehir
- The characteristics 'Hue', 'Saturation' and 'ColorTemperature' are now only added if the colormode of the light is '
hs' or 'ct'.
hs' or 'ct'. @Zehir
### Fixed
- Fix add button now showing up in NR 1.2.9 on the Output rules and Commands.
- Fix add button now showing up in NR 1.2.9 on the Output rules and Commands. @Zehir

@@ -100,7 +114,7 @@ ## [2.0.8] - 2021-10-22 ![Relative date](https://img.shields.io/date/1634857494?label=)

- Backward compatibility for Node-Red 1.2.9.
- Backward compatibility for Node-Red 1.2.9. @Zehir
### Fixed
- Migration of device when undefined.
- Migration of device when undefined. @Zehir

@@ -111,6 +125,6 @@ ## [2.0.7] - 2021-10-17 ![Relative date](https://img.shields.io/date/1634484549?label=)

- Ignore group 0 if he doesn’t exist instead of staying stuck.
- Fix toggle values for windows cover.
- Discard empty numeric values instead of convert them to 0.
- Fix device type detection for windows cover.
- Ignore group 0 if he doesn’t exist instead of staying stuck. @Zehir
- Fix toggle values for windows cover. @Zehir
- Discard empty numeric values instead of convert them to 0. @Zehir
- Fix device type detection for windows cover. @Zehir

@@ -121,5 +135,5 @@ ## [2.0.6] - 2021-10-13 ![Relative date](https://img.shields.io/date/1634158098?label=)

- Selecting an other server update the device list.
- Duplicate gateways in discovery are ignored.
- HomeKit format now send battery data only from the battery node.
- Selecting an other server update the device list. @Zehir
- Duplicate gateways in discovery are ignored. @Zehir
- HomeKit format now send battery data only from the battery node. @Zehir

@@ -130,4 +144,4 @@ ## [2.0.5] - 2021-10-13 ![Relative date](https://img.shields.io/date/1634079545?label=)

- Fix HomeKit loop detection.
- Fix node error on partial deploy.
- Fix HomeKit loop detection. @Zehir
- Fix node error on partial deploy. @Zehir

@@ -138,3 +152,3 @@ ## [2.0.4] - 2021-10-11 ![Relative date](https://img.shields.io/date/1633986241?label=)

- Cleanup old files.
- Cleanup old files. @Zehir

@@ -145,9 +159,9 @@ ## [2.0.3] - 2021-10-11 ![Relative date](https://img.shields.io/date/1633985783?label=)

- Magic 'All' group is not displayed in the groups list with the id 0.
- Display an error message if a device is not found on output nodes and continue processing.
- Magic 'All' group is not displayed in the groups list with the id 0. @Zehir
- Display an error message if a device is not found on output nodes and continue processing. @Zehir
### Fixed
- The msg that go through HomeKit and back to an output node are now discarded with a warning message.
- Attribute requests was not updating if there was no config.
- The msg that go through HomeKit and back to an output node are now discarded with a warning message. @Zehir
- Attribute requests was not updating if there was no config. @Zehir

@@ -158,3 +172,3 @@ ## [2.0.2] - 2021-10-10 ![Relative date](https://img.shields.io/date/1633881662?label=)

- Update read me image url.
- Update read me image url. @Zehir

@@ -165,3 +179,3 @@ ## [2.0.1] - 2021-10-10 ![Relative date](https://img.shields.io/date/1633879095?label=)

- Update npm deployment workflow.
- Update npm deployment workflow. @Zehir

@@ -237,2 +251,4 @@ ## [2.0.0] - 2021-10-10 ![Relative date](https://img.shields.io/date/1633877978?label=)

This big update was brought to you by @Zehir
## [1.3.4] - 2021-09-28 ![Relative date](https://img.shields.io/date/1632782604?label=)

@@ -242,3 +258,3 @@

- Update readme for 2.0 version.
- Update readme for 2.0 version. @Zehir

@@ -249,3 +265,3 @@ ## [1.3.3] - 2021-06-20 ![Relative date](https://img.shields.io/date/1624190689?label=)

- Update multi-select to 1.15.2 for monaco-editor compatibility in node-red 2.0. #140
- Update multi-select to 1.15.2 for monaco-editor compatibility in node-red 2.0. (#140) @Zehir

@@ -256,3 +272,3 @@ ## [1.3.2] - 2021-03-06 ![Relative date](https://img.shields.io/date/1615059740?label=)

- Device list was empty. #89
- Device list was empty. (#89) @Zehir

@@ -263,3 +279,3 @@ ## [1.3.1] - 2021-02-20 ![Relative date](https://img.shields.io/date/1613827429?label=)

- Removed unwanted transition time on out node when the transition time is not set. #118
- Removed unwanted transition time on out node when the transition time is not set. (#118) @Zehir

@@ -270,3 +286,3 @@ ## [1.3.0] - 2021-02-19 ![Relative date](https://img.shields.io/date/1613738128?label=)

- Adding the possibility to change progamatically the "Transition Time". #107
- Adding the possibility to change progamatically the "Transition Time". (#107) @Zehir

@@ -277,6 +293,6 @@ ### Security

- API Key is now stored in node-red credentials. #94
- API Key is now stored in node-red credentials. (#94) @Zehir
## [1.2.0] - 2020-07-12 ![Relative date](https://img.shields.io/date/1594559914?label=)
- Lastest version from [@andreypopov](https://github.com/andreypopov).
- Lastest version from @andreypopov.

@@ -12,13 +12,5 @@ const OutputMsgFormatter = require("../src/runtime/OutputMsgFormatter");

specific: {
value: {
method: {
value: {type: 'GET'}
},
endpoint: {
value: {type: 'str', value: '/'}
},
payload: {
value: {type: 'json', value: '{}'}
}
}
method: {type: 'GET'},
endpoint: {type: 'str', value: '/'},
payload: {type: 'json', value: '{}'}
}

@@ -25,0 +17,0 @@ };

{
"name": "node-red-contrib-deconz",
"version": "2.3.1",
"version": "2.3.2",
"description": "deCONZ connectivity nodes for node-red",

@@ -5,0 +5,0 @@ "keywords": [

@@ -1,2 +0,2 @@

class DeconzEditor{constructor(node,options={}){this.node=node,this.options=options}get elements(){return{}}get NRCD(){return"node-red-contrib-deconz"}findElements(){this.$elements={},Object.keys(this.elements).forEach(k=>{this.$elements[k]=this.findElement(this.elements[k])})}findElement(identifier){return"#"!==identifier.charAt(0)&&"."!==identifier.charAt(0)&&(identifier="#"+identifier),$(identifier)}async init(){this.findElements()}async connect(){}sendError(msg,timeout=1e4){let myNotification=RED.notify(msg,{timeout:timeout,type:"error",buttons:[{text:"Ok",class:"primary",click:()=>myNotification.close()}]})}getIcon(icon,includeClass=!1){return"deconz"===icon?"icons/node-red-contrib-deconz/icon-color.png":"homekit"===icon?"icons/node-red-contrib-deconz/homekit-logo.png":RED.nodes.fontAwesome.getIconList().includes("fa-"+icon)?`${includeClass?"fa ":""}fa-`+icon:icon}createIconElement(icon,container,isLarge=!1){if("fa-"===icon.substr(0,3)){if(RED.nodes.fontAwesome.getIconUnicode(icon)){let faIconElement=$("<i/>").appendTo(container);return void faIconElement.addClass("fa "+icon+(isLarge?" fa-lg":""))}icon=RED.settings.apiRootUrl+"icons/node-red/arrow-in.svg"}let imageIconElement=$("<div/>").appendTo(container);imageIconElement.css("backgroundImage","url("+icon+")")}getI18n(prefix,suffix,value={}){let _path=prefix;suffix&&(_path+="."+suffix),value.defaultValue="_deconz_undefined_";value=RED._(_path,value);if("_deconz_undefined_"!==value)return value}async generateSimpleListField(container,options){let input=$("<select/>",{id:options.id});if(options.choices)for(var[key,value]of options.choices)input.append($("<option/>").attr("value",key).html(RED._(value)));var row=await this.generateInputWithLabel(input,options);return container.append(row),void 0!==options.currentValue&&input.val(options.currentValue),input}async generateTypedInput(container,inputType){let input=$("<input/>",{id:inputType.id,placeholder:RED._(inputType.placeholder)});inputType=$("<input/>",{id:inputType.id+"_type",type:"hidden"});return input.append(inputType),input}async initTypedInput(input,options){options=$.extend({addDefaultTypes:!0,displayOnlyIcon:!1,value:{},width:"200px"},options);let typedInputOptions=$.extend({types:["msg","flow","global"]},options.typedInput);if(typedInputOptions.typeField=options.typeId,options.addDefaultTypes)for(var type of["msg","flow","global","jsonata"])typedInputOptions.types.includes(type)||typedInputOptions.types.push(type);if(options.displayOnlyIcon){let that=this;function valueLabel(a,b){let typeDefinition;for(const type of this.typeList)"object"==typeof type&&type.value===this.propertyType&&(typeDefinition=type);void 0!==typeDefinition&&void 0!==typeDefinition.icon&&(this.oldValue=this.input.val(),this.input.val(""),this.valueLabelContainer.hide(),that.createIconElement(typeDefinition.icon,this.selectLabel),this.selectTrigger.addClass("red-ui-typedInput-full-width"),this.selectLabel.show())}for(let type of typedInputOptions.types)"string"!=typeof type&&(type.hasValue=!0,type.valueLabel=valueLabel)}input.typedInput(typedInputOptions),void 0!==options.width&&input.typedInput("width",options.width),options.value&&(void 0!==options.value.type&&input.typedInput("type",options.value.type),void 0!==options.value.value&&input.typedInput("value",options.value.value))}async generateTypedInputField(container,options){var input=await this.generateTypedInput(container,{id:options.id,placeholder:this.getI18n(options.i18n,"placeholder")}),row=await this.generateInputWithLabel(input,options);return container.append(row),await this.initTypedInput(input,options),input}async generateDoubleTypedInputField(container,optionsFirst,optionsSecond){var inputFirst=await this.generateTypedInput(container,optionsFirst);let row=await this.generateInputWithLabel(inputFirst,optionsFirst);var inputSecond=await this.generateTypedInput(container,optionsSecond);row.append(inputSecond),container.append(row),optionsFirst.displayOnlyIcon=!0,optionsFirst.width="50px",optionsSecond.width="150px",await this.initTypedInput(inputFirst,optionsFirst),await this.initTypedInput(inputSecond,optionsSecond)}generateTypedInputType(i18n,name,data={}){if(data.value=name,void 0===data.label&&(data.label=this.getI18n(i18n,`options.${name}.label`,{})||name),!1!==data.icon&&void 0===data.icon&&(data.icon=this.getIcon(this.getI18n(i18n,`options.${name}.icon`))),data.icon&&"fa-"===data.icon.substr(0,3)&&(data.icon="fa "+data.icon),Array.isArray(data.subOptions)){Array.isArray(data.options)||(data.options=[]);for(const opt of data.subOptions)data.options.push(this.generateTypedInputType(i18n+".options."+name,"string"==typeof opt?opt:opt.name,{icon:!1}))}return data}async generateCheckboxField(container,options){var input=$("<input/>",{id:options.id,type:"checkbox",style:"display: table-cell; width: 14px;vertical-align: top;margin-right: 5px",checked:options.currentValue});let row=await this.generateInputWithLabel(input,options);row.append($("<span/>").html(RED._(options.descText)).css("display","table-cell")),container.append(row)}async generateInputWithLabel(input,options={}){let row=$("<div/>",{class:"form-row",style:"padding:5px;margin:0;display:table;min-width:420px;"});var inputID=input.attr("id");if(inputID){let labelElement=$("<label/>");labelElement.attr("for",inputID),labelElement.attr("class","l-width"),labelElement.attr("style","display:table-cell;"),void 0===options.title&&(options.title=this.getI18n(options.i18n,"title")),options.title&&labelElement.attr("title",this.getI18n(options.i18n,"title")),void 0===options.icon&&(options.icon=this.getI18n(options.i18n,"icon")),options.icon&&(this.createIconElement(this.getIcon(options.icon),labelElement),labelElement.append("&nbsp;")),void 0===options.label&&(options.label=this.getI18n(options.i18n,"label")),options.label&&labelElement.append(`<span>${options.label}</span>`),row.append(labelElement)}return input.css("display","table-cell"),row.append(input),row}async generateHR(container,topBottom="5px",leftRight="50px"){container.append(`<hr style="margin: ${topBottom} ${leftRight};">`)}async generateSeparator(container,label){container.append(`<div class="separator">${RED._(label)}</div>`)}static versionCompare(v1,v2,zeroExtend={}){const lexicographical=zeroExtend&&zeroExtend.lexicographical;zeroExtend=zeroExtend&&zeroExtend.zeroExtend;let v1parts=v1.split("."),v2parts=v2.split(".");function isValidPart(x){return(lexicographical?/^\d+[A-Za-z]*$/:/^\d+$/).test(x)}if(!v1parts.every(isValidPart)||!v2parts.every(isValidPart))return NaN;if(zeroExtend){for(;v1parts.length<v2parts.length;)v1parts.push("0");for(;v2parts.length<v1parts.length;)v2parts.push("0")}lexicographical||(v1parts=v1parts.map(Number),v2parts=v2parts.map(Number));for(let i=0;i<v1parts.length;++i){if(v2parts.length===i)return 1;if(v1parts[i]!==v2parts[i])return v1parts[i]>v2parts[i]?1:-1}return v1parts.length!==v2parts.length?-1:0}}class DeconzMainEditor extends DeconzEditor{constructor(node,options={}){if(super(node,$.extend(!0,{have:{statustext:!0,query:!0,device:!0,output_rules:!1,commands:!1,specific:!1},device:{batteryFilter:!1},output_rules:{format:{single:!0,array:!1,sum:!1,average:!1,min:!1,max:!1},type:{attribute:!0,state:!0,config:!0,homekit:!1,scene_call:!1}},commands:{type:{deconz_state:!0,homekit:!0,custom:!0,pause:!0}},specific:{api:{},output:{},server:{}}},options)),this.subEditor={},this.initDone=!1,this.options.have.statustext&&(this.subEditor.statustext=new DeconzStatusTextEditor(this.node,this.options.statustext)),this.options.have.device&&(this.subEditor.device=new DeconzDeviceEditor(this.node,this.options.device)),this.options.have.query&&(this.subEditor.query=new DeconzQueryEditor(this.node,this.options.query)),this.options.have.specific)switch(this.node.type){case"deconz-api":this.subEditor.specific=new DeconzSpecificApiEditor(this.node,this.options.specific.api);break;case"deconz-output":this.subEditor.specific=new DeconzSpecificOutputEditor(this.node,this.options.specific.output);break;case"deconz-server":this.subEditor.specific=new DeconzSpecificServerEditor(this.node,this.options.specific.server)}this.options.have.output_rules&&(this.subEditor.output_rules=new DeconzOutputRuleListEditor(this.node,this.options.output_rules)),this.options.have.commands&&(this.subEditor.commands=new DeconzCommandListEditor(this.node,this.options.commands))}get elements(){return{tipBox:"node-input-tip-box",server:"node-input-server"}}async configurationMigration(){if(!((this.node.config_version||0)>=this.node._def.defaults.config_version.value)){let config={};for(const key of Object.keys(this.node._def.defaults))config[key]=this.node[key];var mapI18N={id:this.node.id,type:this.node.type,config:JSON.stringify(config)};let errorMsg="Error while migrating the configuration of the node from version "+(this.node.config_version||0)+" to version "+this.node._def.defaults.config_version.value+".",result=await $.getJSON(this.NRCD+"/configurationMigration",mapI18N).catch((t,u)=>{this.$elements.tipBox.append(`<div class="form-tips form-warning"><p>Migration errors:</p><p>${errorMsg}</p></div>`)});if(result&&!result.notNeeded){if(result.new)for(var[key,value]of Object.entries(result.new))this.node[key]=value;if(result.delete&&Array.isArray(result.delete))for(const key of result.delete)delete this.node[key];mapI18N=msg=>"node-red-contrib-deconz"===msg.substr(0,23)?RED._(msg):msg;result.errors&&Array.isArray(result.errors)&&0<result.errors.length&&this.$elements.tipBox.append('<div class="form-tips form-warning"><p>Migration errors:</p><ul>'+`<li>${result.errors.map(mapI18N).join("</li><li>")}</li>`+"</ul></div>"),result.info&&Array.isArray(result.info)&&0<result.info.length&&this.$elements.tipBox.append('<div class="form-tips"><p>Migration info:</p><ul>'+`<li>${result.info.map(mapI18N).join("</li><li>")}</li>`+"</ul></div>")}}}async init(){await new Promise(resolve=>setTimeout(resolve,100)),await super.init(),await this.configurationMigration(),this.initPromises=[];for(const editor of Object.values(this.subEditor))this.initPromises.push(editor.init(this));await Promise.all(this.initPromises),this.initDone=!0,delete this.initPromises;let connectPromises=[];for(const editor of Object.values(this.subEditor))connectPromises.push(editor.connect());await Promise.all(connectPromises)}get serverNode(){return"deconz-server"===this.node.type?this.node:RED.nodes.node(this.$elements.server.val())}async isInitialized(){this.initDone||await Promise.all(this.initPromises)}async updateQueryDeviceDisplay(options){var type=this.subEditor.query.$elements.select.typedInput("type");switch(type){case"device":await this.subEditor.device.updateList(options);break;case"json":case"jsonata":this.subEditor.query.$elements.select.typedInput("validate")&&await this.subEditor.query.updateList(options)}await this.subEditor.device.display("device"===type),await this.subEditor.query.display("device"!==type)}oneditsave(){var newRules;this.options.have.output_rules&&(newRules=this.subEditor.output_rules.value,this.node.outputs=newRules.length,this.node.output_rules=newRules),this.options.have.commands&&(this.node.commands=this.subEditor.commands.value),this.options.have.specific&&(this.node.specific=this.subEditor.specific.value)}}class DeconzStatusTextEditor extends DeconzEditor{constructor(node,options={}){super(node,$.extend({allowedTypes:["msg","jsonata"]},options))}get elements(){return{statustext:"node-input-statustext"}}async init(mainEditor){await super.init(),this.mainEditor=mainEditor,this.initTypedInput()}initTypedInput(){let options=[];this.mainEditor.options.have.statustext&&options.push({value:"auto",label:RED._(this.NRCD+"/server:editor.inputs.statustext.options.auto"),icon:`icons/${this.NRCD}/icon-color.png`,hasValue:!1}),this.$elements.statustext.typedInput({type:"auto",types:options.concat(this.options.allowedTypes),typeField:`#${this.elements.statustext}_type`})}}class DeconzDeviceListEditor extends DeconzEditor{constructor(node,options={}){super(node,options)}get xhrURL(){return this.NRCD+"/itemlist"}get xhrParams(){return{controllerID:this.mainEditor.serverNode.id,forceRefresh:this.options.refresh}}async display(display=!0){if(this.$elements.showHide)return display?this.$elements.showHide.show():this.$elements.showHide.hide(),this.$elements.showHide.promise()}async getItems(options,result){result.forceRefresh=options.refresh;result=await $.getJSON(this.xhrURL,result).catch((t,u)=>{this.sendError(400===t.status&&t.responseText?t.responseText:u.toString())});return result&&result.error_message?(console.warn(result.error_message),void RED.notify("Warning : "+result.error_message,{type:"warning",timeout:1e4})):this.formatItemList(result.items,options.keepOnlyMatched)}async updateList(devices){if(devices=$.extend({refresh:!0},devices),this.mainEditor.serverNode){let list=this.$elements.list,params=this.xhrParams;!0===this.options.batteryFilter&&(devices.keepOnlyMatched=!0,params.query=JSON.stringify({type:"match",match:{"config.battery":{type:"complex",operator:"!==",value:void 0}}}));devices=await this.getItems(devices,params);list.children().remove(),devices&&this.generateHtmlItemList(devices,this.$elements.list),list.multipleSelect("refresh"),devices&&list.multipleSelect("enable")}}formatItemList(items,keepOnlyMatched=!1){let itemList={};var injectItems=(part,matched)=>{part.forEach(item=>{var device_type=item.type;void 0===itemList[device_type]&&(itemList[device_type]=[]),item.query_match=matched,itemList[device_type].push(item)})};return injectItems(items.matched,!0),!1===keepOnlyMatched&&injectItems(items.rejected,!1),itemList}generateHtmlItemList(items,htmlContainer){var group_key,item_list,queryMode=this.constructor===DeconzQueryEditor;for([group_key,item_list]of Object.entries(items).sort((x,y)=>{x=x[0].toLowerCase(),y=y[0].toLowerCase();return x<y?-1:y<x?1:0})){let groupHtml=$("<optgroup/>").attr("label",group_key);for(const item of item_list.sort((x,y)=>{x=x.name.toLowerCase(),y=y.name.toLowerCase();return x<y?-1:y<x?1:0})){let label=item.name;"groups"===item.device_type&&(label+=" (lights: "+item.lights.length,item.scenes.length&&(label+=", scenes: "+item.scenes.length),label+=")");let opt=$("<option>"+label+"</option>").attr("value",item.device_path);queryMode&&item.query_match&&opt.attr("selected",""),opt.appendTo(groupHtml)}groupHtml.appendTo(htmlContainer)}}}class DeconzQueryEditor extends DeconzDeviceListEditor{constructor(node,options={}){super(node,$.extend({allowedTypes:["json","jsonata"]},options))}get elements(){return{select:"node-input-query",list:"node-input-query_result",showHide:".deconz-query-selector",refreshButton:"#force-refresh-query-result"}}get type(){return this.$elements.select.typedInput("type")}set type(val){this.$elements.list.typedInput("type",val)}get value(){return this.$elements.select.typedInput("value")}set value(val){this.$elements.list.typedInput("value",val)}get xhrParams(){let params=super.xhrParams;return params.query=this.value,params.queryType=this.type,params.nodeID=this.node.id,params}async init(mainEditor){await super.init(),this.mainEditor=mainEditor,this.initTypedInput(),this.$elements.list.multipleSelect({maxHeight:300,dropWidth:320,width:320,single:!1,selectAll:!1,filter:!0,filterPlaceholder:RED._(this.NRCD+"/server:editor.inputs.device.device.filter"),placeholder:RED._(this.NRCD+"/server:editor.multiselect.none_selected"),numberDisplayed:1,disableIfEmpty:!0,showClear:!1,hideOptgroupCheckboxes:!0,filterGroup:!0,onClick:view=>{this.$elements.list.multipleSelect(view.selected?"uncheck":"check",view.value)}}),await this.mainEditor.updateQueryDeviceDisplay({useSavedData:!0})}initTypedInput(){let options=[];this.mainEditor.options.have.device&&options.push({value:"device",label:RED._(this.NRCD+"/server:editor.inputs.device.query.options.device"),icon:`icons/${this.NRCD}/icon-color.png`,hasValue:!1}),this.$elements.select.typedInput({type:"text",types:options.concat(this.options.allowedTypes),typeField:"#node-input-search_type"})}async connect(){await super.connect(),this.$elements.select.on("change",()=>{this.mainEditor.updateQueryDeviceDisplay({useSavedData:!0}),this.mainEditor.options.have.output_rules&&this.mainEditor.subEditor.output_rules.refresh()}),this.$elements.refreshButton.on("click",()=>{this.updateList(),this.mainEditor.options.have.output_rules&&this.mainEditor.subEditor.output_rules.refresh()})}}class DeconzDeviceEditor extends DeconzDeviceListEditor{constructor(node,options={}){super(node,$.extend({batteryFilter:!1},options))}get elements(){return{list:"node-input-device_list",showHide:".deconz-device-selector",refreshButton:"#force-refresh"}}get value(){return this.$elements.list.multipleSelect("getSelects")}set value(val){this.$elements.list.multipleSelect("setSelects",val)}async init(mainEditor){await super.init(),this.mainEditor=mainEditor,this.$elements.list.multipleSelect({maxHeight:300,dropWidth:320,width:320,single:"multiple"!==this.$elements.list.attr("multiple"),filter:!0,filterPlaceholder:RED._(this.NRCD+"/server:editor.inputs.device.device.filter"),placeholder:RED._(this.NRCD+"/server:editor.multiselect.none_selected"),showClear:!0})}async connect(){await super.connect();var refreshDeviceList=()=>{this.updateList($.extend(this.options,{useSelectedData:!0})),this.mainEditor.options.have.output_rules&&this.mainEditor.subEditor.output_rules.refresh()};this.mainEditor.$elements.server.on("change",refreshDeviceList),this.$elements.refreshButton.on("click",refreshDeviceList),this.mainEditor.options.have.output_rules&&this.$elements.list.on("change",()=>{this.mainEditor.subEditor.output_rules.refresh()})}async updateList(options){let itemsSelected;(options=$.extend({useSavedData:!1,useSelectedData:!1},options)).useSelectedData&&(itemsSelected=this.$elements.list.multipleSelect("getSelects")),await super.updateList(options),options.useSavedData&&Array.isArray(this.node.device_list)?this.$elements.list.multipleSelect("setSelects",this.node.device_list):options.useSelectedData&&Array.isArray(itemsSelected)&&this.$elements.list.multipleSelect("setSelects",itemsSelected)}}class DeconzSpecificApiEditor extends DeconzEditor{constructor(node,options={}){super(node,$.extend({},options))}get elements(){return{container:"deconz-api-form",name:"node-config-input-name",method:"node-config-input-method",endpoint:"node-config-input-endpoint",payload:"node-config-input-payload"}}get default(){return{name:"",method:{type:"GET"},endpoint:{type:"str",value:"/"},payload:{type:"json",value:"{}"}}}async init(){this.node.specific=$.extend(!0,this.default.specific,this.node.specific);var container=this.findElement(this.elements.container);await this.generateMethodField(container,this.node.specific.method),await this.generateEndpointField(container,this.node.specific.endpoint),await this.generatePayloadField(container,this.node.specific.payload),await super.init()}async connect(){await super.connect()}get value(){return{method:{type:this.$elements.method.typedInput("type"),value:this.$elements.method.typedInput("value")},endpoint:{type:this.$elements.endpoint.typedInput("type"),value:this.$elements.endpoint.typedInput("value")},payload:{type:this.$elements.payload.typedInput("type"),value:this.$elements.payload.typedInput("value")}}}set value(newValues){this.$elements.name.val(newValues.name);for(var field of["method","endpoint","payload"])this.$elements[field].typedInput("type",newValues[field].type),this.$elements[field].typedInput("value",newValues[field].value);for(const element of Object.values(this.$elements))element.trigger("change")}async generateMethodField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.api.method";await this.generateTypedInputField(container,{id:this.elements.method,i18n:i18n,value:value,width:"250px",typedInput:{types:[this.generateTypedInputType(i18n,"GET",{hasValue:!1}),this.generateTypedInputType(i18n,"POST",{hasValue:!1}),this.generateTypedInputType(i18n,"PUT",{hasValue:!1}),this.generateTypedInputType(i18n,"DELETE",{hasValue:!1})]}})}async generateEndpointField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.api.endpoint";await this.generateTypedInputField(container,{id:this.elements.endpoint,i18n:i18n,value:value,width:"250px",typedInput:{types:["str"]}})}async generatePayloadField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.api.payload";await this.generateTypedInputField(container,{id:this.elements.payload,i18n:i18n,value:value,width:"250px",typedInput:{types:["json","jsonata"]}})}}class DeconzSpecificOutputEditor extends DeconzEditor{constructor(node,options={}){super(node,$.extend({},options))}get elements(){return{container:"specific-container",delay:"node-input-delay",result:"node-input-result"}}get default(){return{delay:{type:"num",value:50},result:{type:"at_end"}}}async init(){this.node.specific=$.extend(!0,this.default,this.node.specific);var container=this.findElement(this.elements.container);await this.generateSeparator(container,this.NRCD+"/server:editor.inputs.separator.specific"),await this.generateDelayField(container,this.node.specific.delay),await this.generateResultField(container,this.node.specific.result),await super.init()}async generateDelayField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.output.delay";await this.generateTypedInputField(container,{id:this.elements.delay,i18n:i18n,value:value,width:"250px",typedInput:{types:["num"]}})}async generateResultField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.output.result";await this.generateTypedInputField(container,{id:this.elements.result,i18n:i18n,value:value,width:"250px",typedInput:{types:[this.generateTypedInputType(i18n,"never",{hasValue:!1}),this.generateTypedInputType(i18n,"after_command",{hasValue:!1}),this.generateTypedInputType(i18n,"at_end",{hasValue:!1})]}})}async connect(){await super.connect()}get value(){return{delay:{type:this.$elements.delay.typedInput("type"),value:this.$elements.delay.typedInput("value")},result:{type:this.$elements.result.typedInput("type"),value:this.$elements.result.typedInput("value")}}}}class DeconzSpecificServerEditor extends DeconzEditor{constructor(node,options={}){super(node,$.extend({},options))}get elements(){return{name:"node-config-input-name",ip:"node-config-input-ip",port:"node-config-input-port",apikey:"node-config-input-secured_apikey",ws_port:"node-config-input-ws_port",secure:"node-config-input-secure",polling:"node-config-input-polling",getSettingsButton:"node-contrib-deconz-get-settings"}}get default(){return{name:"",ip:"",port:"",apikey:"",ws_port:"",secure:!1,polling:15}}get xhrURL(){return this.NRCD+"/serverAutoconfig"}async init(){this.node.specific=$.extend(!0,this.default,this.node.specific),await super.init(),this.node.migration_secured_apikey&&(this.$elements.apikey.val(this.node.migration_secured_apikey),this.$elements.apikey.trigger("change"))}async connect(){await super.connect(),this.$elements.getSettingsButton.on("click",()=>this.discoverParams())}async discoverParams(overrideSettings){void 0===overrideSettings&&(overrideSettings={});let myNotification,stop=!1,closeNotification=()=>{myNotification&&"function"==typeof myNotification.close&&myNotification.close(),stop=!0};myNotification=RED.notify("<p>Trying to find the server settings, please wait...<br>This can take up to 15 seconds.</p>",{modal:!0,fixed:!0,type:"info",buttons:[{text:"Cancel",class:"primary",click:closeNotification}]});try{let params=Object.assign({},this.value,overrideSettings);void 0===params.discoverParam&&(params.discoverParam={}),params.discoverParam.devicetype="Node-Red Deconz Plugin"+(this.node?" id:"+this.node.id:"");let request=await $.getJSON(this.xhrURL,{config:JSON.stringify(params)}).catch((t,u)=>{this.sendError(400===t.status&&t.responseText?t.responseText:u.toString())});if(stop)return;if(request.error){let html=`<p>Error ${request.error.code}: ${request.error.description}</p>`,buttons=[{text:"Cancel",click:closeNotification}];switch(request.error.code){case"GATEWAY_CHOICE":html+="<p>There is multiple Deconz device in you network, please select the one you want to configure.</p>";let node=this;for(const[index,gateway]of request.error.gateway_list.entries())buttons.push({text:`#${index+1}: `+gateway.name,id:"node-red-contrib-deconz-gateway-id-"+index,class:"primary",click:()=>function(gateway_id){closeNotification(),gateway_id&&(request.currentSettings.discoverParam.targetGatewayID=gateway_id),node.discoverParams(request.currentSettings)}(gateway.bridge_id)});buttons.push(buttons.shift());break;case"DECONZ_ERROR":101===request.error.type&&(buttons.unshift({text:"I pressed the link button",class:"primary",click:()=>{closeNotification(),this.discoverParams(request.currentSettings)}}),html+="<p>The reason why the request failed is that the gateway was not unlocked. This mechanism is needed to prevent anybody from access to the gateway without being permitted to do so.</p>",html+="<ul><li>In a new browser tab open the <a href='http://phoscon.de/pwa/' target='_blank'>Phoscon App</a></li><li>Click on Menu -> Settings -> Gateway</li><li>Click on \"Advanced\" button</li><li>Click on the \"Authenticate app\" button</li></ul>",html+=`<p>Within 60 seconds after unlocking the gateway, click on the button "${buttons[0].text}".</p>`);break;default:buttons[buttons.length-1].text="Cancel"}html+=`<p>Logs:</p><pre>${request.log.join("\n")}</pre>`,closeNotification(),myNotification=RED.notify(html,{modal:!0,fixed:!0,type:"error",buttons:buttons})}else request.success?(closeNotification(),myNotification=RED.notify("<p>Settings fetched successfully !</p>",{modal:!1,fixed:!1,type:"success"}),this.value=request.currentSettings):(closeNotification(),myNotification=RED.notify(`<p>Unknown error : ${JSON.stringify(request)}</p>`,{modal:!0,fixed:!0,type:"error",buttons:[{text:"Ok",class:"primary",click:closeNotification}]}))}catch(error){closeNotification(),myNotification=RED.notify(`<p>Error while processing request: ${error.toString()}</p>`,{type:"error"})}}get value(){return{name:this.$elements.name.val(),ip:this.$elements.ip.val(),port:this.$elements.port.val(),apikey:this.$elements.apikey.val(),ws_port:this.$elements.ws_port.val(),secure:this.$elements.secure.prop("checked"),polling:this.$elements.polling.val()}}set value(newValues){this.$elements.name.val(newValues.name),this.$elements.ip.val(newValues.ip),this.$elements.port.val(newValues.port),this.$elements.apikey.val(newValues.apikey),this.$elements.ws_port.val(newValues.ws_port),this.$elements.secure.prop("checked",newValues.secure),this.$elements.polling.val(newValues.polling);for(const element of Object.values(this.$elements))element.trigger("change")}}class DeconzListItemEditor extends DeconzEditor{constructor(node,listEditor,container,options={}){super(node,options),this.listEditor=listEditor,container.uniqueId(),this.uniqueId=container.attr("id"),this.container=container}set index(value){void 0!==value&&this.$elements&&this.$elements.outputButton&&this.$elements.outputButton.find(".node-input-rule-index").html(value+1),this._index=value}get index(){return this._index}async init(){await this.generateOutputButton(this.container.children().first()),await super.init()}async generateOutputButton(container){$("<a/>",{id:this.elements.outputButton,class:"red-ui-button top-right-badge",title:RED._(this.options.button_title)}).append(`&nbsp;&#8594;&nbsp;<span class="node-input-rule-index">${this.index+1}</span>&nbsp;`).appendTo(container)}}class DeconzListItemListEditor extends DeconzEditor{constructor(node,options={}){super(node,options),this.items={}}get listType(){return"item"}get buttons(){return[]}async init(mainEditor){await super.init(),this.mainEditor=mainEditor}async initList(itemEditorClass,items=[]){var buttons=this.buttons,addButton=0===buttons.length||DeconzEditor.versionCompare(RED.settings.version,"1.3.0")<0;this.$elements.list.editableList({sortable:!0,removable:!0,height:"auto",addButton:addButton,buttons:buttons,addItem:(row,index,item)=>{let itemEditor=new itemEditorClass(this.node,this,row,this.options);item.uniqueId=itemEditor.uniqueId,this.items[item.uniqueId]=itemEditor,itemEditor.init(item,index)},removeItem:item=>{if(!item.uniqueId||!this.items[item.uniqueId])throw new Error(`Error while removing the ${this.listType}, the ${this.listType} ${item.uniqueId} does not exist.`);var deletedIndex=this.items[item.uniqueId].index;delete this.items[item.uniqueId];for(const item of Object.values(this.items))item.index>deletedIndex&&item.index--},sortItems:items=>{items.each((index,item)=>{if(!this.items[item.attr("id")])throw new Error(`Error while moving the ${this.listType}, the ${this.listType} ${index+1} does not exist.`);this.items[item.attr("id")].index=index})}}),0<items.length&&this.$elements.list.editableList("addItems",items)}get value(){let result=[];for(const rule of Object.values(this.items).sort((a,b)=>a.index-b.index))result.push(rule.value);return result}refresh(){}}class DeconzOutputRuleEditor extends DeconzListItemEditor{constructor(node,listEditor,container,options={}){super(node,listEditor,container,options=$.extend({enableEachState:!0},options))}get elements(){let elements={};for(const key of["format","type","payload","output","onstart","onerror","outputButton"])elements[key]=`node-input-output-rule-${this.uniqueId}-`+key;return elements}get value(){let value={};switch(value.type=this.$elements.type.val(),value.format=this.$elements.format.val(),value.type){case"attribute":case"state":case"config":"deconz-input"===this.node.type&&(value.output=this.$elements.output.val()),["deconz-input","deconz-battery"].includes(this.node.type)&&(value.onstart=this.$elements.onstart.is(":checked")),["deconz-input","deconz-get"].includes(this.node.type)&&(value.payload=this.$elements.payload.multipleSelect("getSelects"));break;case"homekit":["deconz-input","deconz-battery"].includes(this.node.type)&&(value.onstart=this.$elements.onstart.is(":checked")),"deconz-input"===this.node.type&&(value.onerror=this.$elements.onerror.is(":checked")),["deconz-input","deconz-get"].includes(this.node.type)&&(value.payload=this.$elements.payload.multipleSelect("getSelects"))}return value}get defaultRule(){let rule={type:"state",payload:["__complete__"],format:"single"};return"deconz-input"===this.node.type&&(rule.output="always",rule.onstart=!0,rule.onerror=!0),"deconz-battery"===this.node.type&&(rule.onstart=!0),rule}async init(rule,index){this._index=index,rule=$.extend(!0,this.defaultRule,rule),await this.generatePayloadTypeField(this.container,rule.type),["deconz-input","deconz-get"].includes(this.node.type)&&await this.generatePayloadField(this.container),await this.generatePayloadFormatField(this.container,rule.format),"deconz-input"===this.node.type&&await this.generateOutputField(this.container,(void 0!==rule.output?rule:this.defaultRule).output),["deconz-input","deconz-battery"].includes(this.node.type)&&await this.generateOnStartField(this.container,(void 0!==rule.onstart?rule:this.defaultRule).onstart),"deconz-input"===this.node.type&&await this.generateOnErrorField(this.container,(void 0!==rule.onerror?rule:this.defaultRule).onerror),await super.init(),await this.listEditor.mainEditor.isInitialized(),await this.initPayloadList(rule.payload),await this.updateShowHide(rule.type),await this.connect()}async connect(){await super.connect(),this.$elements.type.on("change",()=>{var type=this.$elements.type.val();["attribute","state","config","homekit"].includes(type)&&this.updatePayloadList(),this.updateShowHide(type)}),this.$elements.outputButton.on("click",()=>{try{let nodes=RED.nodes.filterLinks({source:this.node,sourcePort:this.index}).map(l=>{var result=l.target.type;return""!==l.target.name?result+":"+l.target.name:void 0!==l.target._def.label?result+":"+l.target._def.label():result}),myNotification=RED.notify(`The output ${this.index+1} is sending message to ${nodes.length} nodes :<br>`+nodes.join("<br>"),{modal:!0,timeout:5e3,buttons:[{text:"okay",class:"primary",click:()=>myNotification.close()}]})}catch(e){this.sendError("This is using not documented API so can be broken at anytime.<br>Error while getting connected nodes: "+e.toString())}})}async updateShowHide(type){switch(type){case"attribute":case"state":case"config":this.$elements.payload.closest(".form-row").show(),this.$elements.output.closest(".form-row").show(),this.$elements.onstart.closest(".form-row").show(),this.$elements.onerror.closest(".form-row").hide();break;case"homekit":this.$elements.payload.closest(".form-row").show(),this.$elements.output.closest(".form-row").hide(),this.$elements.onstart.closest(".form-row").show(),this.$elements.onerror.closest(".form-row").show();break;case"scene_call":this.$elements.payload.closest(".form-row").hide(),this.$elements.output.closest(".form-row").hide(),this.$elements.onstart.closest(".form-row").hide(),this.$elements.onerror.closest(".form-row").hide()}}async updatePayloadList(){if(this.listEditor.mainEditor.serverNode){this.$elements.payload.multipleSelect("disable"),this.$elements.payload.children().remove();var queryType=this.listEditor.mainEditor.subEditor.query.type,devices=this.listEditor.mainEditor.subEditor.device.value,type=this.$elements.type.val();if(["attribute","state","config","homekit"].includes(type)){var i18n=this.NRCD+"/server:editor.inputs.outputs.payload";let html="";if("homekit"===type?html+='<option value="__auto__">'+RED._(i18n+".options.auto")+"</option>":(html+='<option value="__complete__">'+RED._(i18n+".options.complete")+"</option>",!0===this.options.enableEachState&&(html+='<option value="__each__">'+RED._(i18n+".options.each")+"</option>")),this.$elements.payload.html(html),"device"===queryType){var data=await $.getJSON(this.NRCD+`/${type}list`,{controllerID:this.listEditor.mainEditor.serverNode.id,devices:JSON.stringify(this.listEditor.mainEditor.subEditor.device.value)});for(const _type of"attribute"===type?["attribute","state","config"]:[type]){let label=this.getI18n(i18n+".group_label."+_type);void 0===label&&(label=_type);let groupHtml=$("<optgroup/>",{label:label});for(const item of Object.keys(data.count[_type]).sort()){let sample=data.sample[_type][item];sample="string"==typeof sample?`"${sample}"`:Array.isArray(sample)?`[${sample.toString()}]`:null===sample||void 0===sample?"NULL":sample.toString();let label;var count=data.count[_type][item];label=count===devices.length?RED._(i18n+".item_list",{name:item,sample:sample}):RED._(i18n+".item_list_mix",{name:item,sample:sample,item_count:count,device_count:devices.length}),$("<option>"+label+"</option>").attr("value","attribute"===type&&"attribute"!==_type?_type+"."+item:item).appendTo(groupHtml)}$.isEmptyObject(data.count[_type])||groupHtml.appendTo(this.$elements.payload)}}this.$elements.payload.multipleSelect("refresh").multipleSelect("enable")}}}async initPayloadList(value){let list=this.$elements.payload;list.addClass("multiple-select"),list.multipleSelect({maxHeight:300,dropWidth:300,width:200,numberDisplayed:1,single:!1,selectAll:!1,container:".node-input-output-container-row",filter:!0,filterPlaceholder:RED._(this.NRCD+"/server:editor.inputs.device.device.filter"),placeholder:RED._(this.NRCD+"/server:editor.multiselect.none_selected"),onClick:view=>{if(view.selected)switch(view.value){case"__complete__":case"__each__":case"__auto__":list.multipleSelect("setSelects",[view.value]);break;default:list.multipleSelect("uncheck","__complete__"),list.multipleSelect("uncheck","__each__"),list.multipleSelect("uncheck","__auto__")}},onUncheckAll:()=>{list.multipleSelect("setSelects",["__complete__","__auto__"])},onOptgroupClick:view=>{view.selected&&(list.multipleSelect("uncheck","__complete__"),list.multipleSelect("uncheck","__each__"),list.multipleSelect("uncheck","__auto__"))}}),await this.updatePayloadList(),value&&list.multipleSelect("setSelects",value)}async generatePayloadTypeField(container,value){var type,enabled,i18n=this.NRCD+"/server:editor.inputs.outputs.type";let choices=[];for([type,enabled]of Object.entries(this.listEditor.options.type))enabled&&choices.push([type,i18n+".options."+type]);await this.generateSimpleListField(container,{id:this.elements.type,i18n:i18n,choices:choices,currentValue:value})}async generatePayloadField(container){var i18n=this.NRCD+"/server:editor.inputs.outputs.payload";await this.generateSimpleListField(container,{id:this.elements.payload,i18n:i18n})}async generatePayloadFormatField(container,value){var format,enabled,i18n=this.NRCD+"/server:editor.inputs.outputs.format";let choices=[];for([format,enabled]of Object.entries(this.listEditor.options.format))enabled&&choices.push([format,i18n+".options."+format]);await this.generateSimpleListField(container,{id:this.elements.format,i18n:i18n,choices:choices,currentValue:value})}async generateOutputField(container,value){var i18n=this.NRCD+"/server:editor.inputs.outputs.output";await this.generateSimpleListField(container,{id:this.elements.output,i18n:i18n,choices:[["always",i18n+".options.always"],["onchange",i18n+".options.onchange"],["onupdate",i18n+".options.onupdate"]],currentValue:value})}async generateOnStartField(container,value){var i18n=this.NRCD+"/server:editor.inputs.outputs.on_start";await this.generateCheckboxField(container,{id:this.elements.onstart,i18n:i18n,currentValue:value})}async generateOnErrorField(container,value){var i18n=this.NRCD+"/server:editor.inputs.outputs.on_error";await this.generateCheckboxField(container,{id:this.elements.onerror,i18n:i18n,currentValue:value})}}class DeconzOutputRuleListEditor extends DeconzListItemListEditor{get elements(){return{list:"node-input-output-container"}}get listType(){return"rule"}get buttons(){let buttons=[];var type_name,i18n=this.NRCD+"/server:editor.inputs.outputs.type";for(const[type,enabled]of Object.entries(this.options.type))enabled&&(type_name=this.getI18n(i18n+".options."+type),buttons.push({label:this.getI18n(i18n+".add_button","label",{type:type_name}),icon:this.getIcon(this.getI18n(i18n+".add_button","icon"),!0),title:this.getI18n(i18n+".add_button","title",{type:type_name}),click:()=>this.$elements.list.editableList("addItem",{type:type})}));return buttons}async init(mainEditor){await super.init(mainEditor),await this.initList(DeconzOutputRuleEditor,this.node.output_rules)}refresh(){for(const rule of Object.values(this.items))rule.updatePayloadList()}}class DeconzCommandEditor extends DeconzListItemEditor{constructor(node,listEditor,container,options={}){super(node,listEditor,container,options=$.extend({},options)),this.containers={}}get lightKeys(){return["bri","sat","hue","ct","xy"]}get argKeys(){return["on","alert","effect","colorloopspeed","open","stop","lift","tilt","scene_mode","group","scene","scene_name","target","command","payload","delay","transitiontime","retryonerror","aftererror"]}get elements(){let keys=this.argKeys;keys.push("typedomain"),keys.push("outputButton"),keys.push("scene_picker"),keys.push("scene_picker_refresh");for(const lightKey of this.lightKeys)keys.push(lightKey),keys.push(lightKey+"_direction");let elements={};for(const key of keys)elements[key]=`node-input-output-rule-${this.uniqueId}-`+key;return elements}set value(command){}get value(){let value={arg:{}};value.type=this.$elements.typedomain.typedInput("type"),value.domain=this.$elements.typedomain.typedInput("value");for(const key of this.argKeys)this.$elements[key].parent(".form-row").is(":visible")&&(value.arg[key]={type:this.$elements[key].typedInput("type"),value:this.$elements[key].typedInput("value")});for(const key of this.lightKeys)this.$elements[key].parent(".form-row").is(":visible")&&(value.arg[key]={direction:this.$elements[key+"_direction"].typedInput("type"),type:this.$elements[key].typedInput("type"),value:this.$elements[key].typedInput("value")});return value}get defaultCommand(){return{type:"deconz_state",domain:"lights",target:"state",arg:{on:{type:"keep"},bri:{direction:"set",type:"num"},sat:{direction:"set",type:"num"},hue:{direction:"set",type:"num"},ct:{direction:"set",type:"num"},xy:{direction:"set",type:"num"},alert:{type:"str"},effect:{type:"str"},colorloopspeed:{type:"num"},transitiontime:{type:"num"},command:{type:"str",value:"on"},payload:{type:"msg",value:"payload"},delay:{type:"num",value:2e3},target:{type:"state"},group:{type:"num"},scene_mode:{type:"single"},scene_call:{type:"num"},scene_name:{type:"str"},retryonerror:{type:"num",value:0},aftererror:{type:"continue"}}}}async init(command,index){this._index=index,command=$.extend(!0,this.defaultCommand,command),await this.generateTypeDomainField(this.container,{type:command.type,value:command.domain}),this.containers.light=$("<div>").appendTo(this.container),await this.generateLightOnField(this.containers.light,command.arg.on);for(const lightType of["bri","sat","hue","ct","xy"])await this.generateLightColorField(this.containers.light,lightType,command.arg[lightType]),"bri"===lightType&&await this.generateHR(this.containers.light);await this.generateHR(this.containers.light),await this.generateLightAlertField(this.containers.light,command.arg.alert),await this.generateLightEffectField(this.containers.light,command.arg.effect),await this.generateLightColorLoopSpeedField(this.containers.light,command.arg.colorloopspeed),this.containers.windows_cover=$("<div>").appendTo(this.container),await this.generateCoverOpenField(this.containers.windows_cover,command.arg.open),await this.generateCoverStopField(this.containers.windows_cover,command.arg.stop),await this.generateCoverLiftField(this.containers.windows_cover,command.arg.lift),await this.generateCoverTiltField(this.containers.windows_cover,command.arg.tilt),this.containers.scene_call=$("<div>").appendTo(this.container),await this.generateSceneModeField(this.containers.scene_call,command.arg.scene_mode),this.containers.scene_call_single=$("<div>").appendTo(this.containers.scene_call),await this.generateScenePickerField(this.containers.scene_call_single,command.arg.group+"."+command.arg.scene),await this.generateSceneGroupField(this.containers.scene_call_single,command.arg.group),await this.generateSceneSceneField(this.containers.scene_call_single,command.arg.scene),this.containers.scene_call_dynamic=$("<div>").appendTo(this.containers.scene_call),await this.generateSceneNameField(this.containers.scene_call_dynamic,command.arg.scene_name),this.containers.target=$("<div>").appendTo(this.container),await this.generateTargetField(this.containers.target,command.arg.target),this.containers.command=$("<div>").appendTo(this.container),await this.generateCommandField(this.containers.command,command.arg.command),this.containers.payload=$("<div>").appendTo(this.container),await this.generatePayloadField(this.containers.payload,command.arg.payload),this.containers.pause=$("<div>").appendTo(this.container),await this.generatePauseDelayField(this.containers.pause,command.arg.delay),this.containers.transition=$("<div>").appendTo(this.container),await this.generateHR(this.containers.transition),await this.generateCommonTransitionTimeField(this.containers.transition,command.arg.transitiontime),this.containers.common=$("<div>").appendTo(this.container),await this.generateHR(this.containers.common),await this.generateCommonOnErrorRetryField(this.containers.common,command.arg.retryonerror),await this.generateCommonOnErrorAfterField(this.containers.common,command.arg.aftererror),await super.init(),await this.listEditor.mainEditor.isInitialized(),await this.updateShowHide(command.type,command.domain),await this.connect()}async connect(){await super.connect(),this.$elements.typedomain.on("change",(event,type,value)=>{this.updateShowHide(type,value)}),this.$elements.outputButton.on("click",async()=>{try{if("device"!==this.listEditor.mainEditor.subEditor.query.type)return void this.sendError("Error : The run command can only work with device list.",5e3);var name,value,command=this.value,devices=this.listEditor.mainEditor.subEditor.device.value;if(0===devices.length&&!("deconz_state"===command.type&&"scene_call"===command.domain||"custom"===command.type&&"scene_call"===command.arg.target.type))return void this.sendError("Error : No device selected.",5e3);if("pause"===command.type)return void this.sendError("Error : Can't test pause command.",5e3);for([name,value]of Object.entries(command.arg))if(["msg","flow","global","jsonata"].includes(value.type))return void this.sendError(`Error : Cant run this command because the value "${name}" is type "${value.type}".`,5e3);let myNotification=RED.notify("Sending request...",{type:"info"});await $.post(this.NRCD+"/testCommand",{controllerID:this.listEditor.mainEditor.serverNode.id,device_list:devices,command:command,delay:this.listEditor.mainEditor.subEditor.specific.value.delay}).catch((t,u)=>{this.sendError(400===t.status&&t.responseText?t.responseText:u.toString())});myNotification.close(),myNotification=RED.notify("Ok",{timeout:1e3,type:"success"})}catch(e){let myNotification=RED.notify(e.toString(),{type:"error",buttons:[{class:"error",click:()=>myNotification.close()}]})}});const updateSceneGroupSelection=()=>{let value=this.$elements.scene_picker.multipleSelect("getSelects");var parts;1===value.length&&(this.$elements.group.off("change",updateScenePickerSelection),this.$elements.scene.off("change",updateScenePickerSelection),parts=value[0].split("."),this.$elements.group.typedInput("type","num"),this.$elements.group.typedInput("value",parts[0]),this.$elements.scene.typedInput("type","num"),this.$elements.scene.typedInput("value",parts[1]),this.$elements.group.on("change",updateScenePickerSelection),this.$elements.scene.on("change",updateScenePickerSelection))},updateScenePickerSelection=()=>{this.$elements.scene_picker.off("change",updateSceneGroupSelection),this.$elements.scene_picker.multipleSelect("setSelects","num"!==this.$elements.group.typedInput("type")||"num"!==this.$elements.group.typedInput("type")?[]:[this.$elements.group.typedInput("value")+"."+this.$elements.scene.typedInput("value")]),this.$elements.scene_picker.on("change",updateSceneGroupSelection)};this.$elements.scene_mode.on("change",()=>{var isSingle="single"===this.$elements.scene_mode.typedInput("type");this.containers.scene_call_single.toggle(isSingle),this.containers.scene_call_dynamic.toggle(!isSingle)}),this.$elements.scene_picker.on("change",updateSceneGroupSelection),this.$elements.group.on("change",updateScenePickerSelection),this.$elements.scene.on("change",updateScenePickerSelection),this.$elements.scene_picker_refresh.on("click",()=>this.updateSceneList()),this.$elements.target.on("change",(event,type,value)=>{this.containers.command.toggle("scene_call"!==type)})}async updateShowHide(type,domain){let containers=[];switch(type){case"deconz_state":switch(domain){case"lights":case"groups":containers.push("light"),containers.push("transition");break;case"covers":containers.push("windows_cover");break;case"scene_call":containers.push("scene_call"),await this.updateSceneList(),containers.push("scene_call_"+("single"===this.$elements.scene_mode.typedInput("type")?"single":"dynamic"))}containers.push("common");break;case"homekit":this.$elements.payload.typedInput("types",["msg","flow","global","json","jsonata"]),containers.push("payload"),containers.push("transition"),containers.push("common");break;case"custom":containers.push("target"),"scene_call"!==this.$elements.target.typedInput("type")&&containers.push("command"),this.$elements.payload.typedInput("types",["msg","flow","global","str","num","bool","json","jsonata","date"]),containers.push("payload"),containers.push("transition"),containers.push("common");break;case"pause":containers.push("pause")}for(var[key,value]of Object.entries(this.containers))value.toggle(containers.includes(key))}async updateSceneList(){this.$elements.scene_picker.multipleSelect("disable"),this.$elements.scene_picker.children().remove();let queryEditor=this.listEditor.mainEditor.subEditor.query;if(void 0!==queryEditor){let params=queryEditor.xhrParams;params.queryType="json",params.query=JSON.stringify({match:{device_type:"groups"}});var groups=await queryEditor.getItems({refresh:!0,keepOnlyMatched:!0},params);if(void 0!==groups&&void 0!==groups.LightGroup){for(const group of groups.LightGroup){let groupHtml=$("<optgroup/>",{label:group.id+" - "+group.name});if(group.scenes&&0<group.scenes.length){for(const scene of group.scenes)$(`<option>${scene.id} - ${scene.name}</option>`).attr("value",group.id+"."+scene.id).appendTo(groupHtml);groupHtml.appendTo(this.$elements.scene_picker)}}this.$elements.scene_picker.multipleSelect("refresh").multipleSelect("enable"),this.$elements.scene_picker.multipleSelect("setSelects","num"!==this.$elements.group.typedInput("type")||"num"!==this.$elements.group.typedInput("type")?[]:[this.$elements.group.typedInput("value")+"."+this.$elements.scene.typedInput("value")])}}}async generateTypeDomainField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type";await this.generateTypedInputField(container,{id:this.elements.typedomain,i18n:i18n,value:value,addDefaultTypes:!1,typedInput:{default:"deconz_state",types:[this.generateTypedInputType(i18n,"deconz_state",{subOptions:["lights","covers","groups","scene_call"]}),this.generateTypedInputType(i18n,"homekit",{hasValue:!1}),this.generateTypedInputType(i18n,"custom",{hasValue:!1}),this.generateTypedInputType(i18n,"pause",{hasValue:!1})]}})}async generateLightOnField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields.on";await this.generateTypedInputField(container,{id:this.elements.on,i18n:i18n,value:value,typedInput:{default:"keep",types:[this.generateTypedInputType(i18n,"keep",{hasValue:!1}),this.generateTypedInputType(i18n,"set",{subOptions:["true","false"]}),this.generateTypedInputType(i18n,"toggle",{hasValue:!1})]}})}async generateLightColorField(container,fieldName,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields";let fieldFormat=["num"],directionsFormat=[this.generateTypedInputType(i18n+".lightFields","set",{hasValue:!1})];switch(fieldName){case"bri":fieldFormat.push("str"),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","inc",{hasValue:!1})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","dec",{hasValue:!1})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","detect_from_value",{hasValue:!1}));break;case"ct":fieldFormat.push("str"),fieldFormat.push(this.generateTypedInputType(i18n+".ct","deconz",{subOptions:["cold","white","warm"]})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","inc",{hasValue:!1})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","dec",{hasValue:!1})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","detect_from_value",{hasValue:!1}));break;case"xy":fieldFormat=["json"]}await this.generateDoubleTypedInputField(container,{id:this.elements[fieldName+"_direction"],i18n:i18n+"."+fieldName,addDefaultTypes:!1,value:{type:value.direction},typedInput:{types:directionsFormat}},{id:this.elements[fieldName],value:{type:value.type,value:["xy"===fieldName&&void 0===value.value?"[]":value.value]},typedInput:{types:fieldFormat}})}async generateLightAlertField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields.alert";await this.generateTypedInputField(container,{id:this.elements.alert,i18n:i18n,value:value,typedInput:{types:["str",this.generateTypedInputType(i18n,"deconz",{subOptions:["none","select","lselect"]})]}})}async generateLightEffectField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields.effect";await this.generateTypedInputField(container,{id:this.elements.effect,i18n:i18n,value:value,typedInput:{types:["str",this.generateTypedInputType(i18n,"deconz",{subOptions:["none","colorloop"]})]}})}async generateLightColorLoopSpeedField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields.colorloopspeed";await this.generateTypedInputField(container,{id:this.elements.colorloopspeed,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateCoverOpenField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.covers.fields.open";await this.generateTypedInputField(container,{id:this.elements.open,i18n:i18n,value:value,typedInput:{types:[this.generateTypedInputType(i18n,"keep",{hasValue:!1}),this.generateTypedInputType(i18n,"set",{subOptions:["true","false"]}),this.generateTypedInputType(i18n,"toggle",{hasValue:!1})]}})}async generateCoverStopField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.covers.fields.stop";await this.generateTypedInputField(container,{id:this.elements.stop,i18n:i18n,value:value,typedInput:{types:[this.generateTypedInputType(i18n,"keep",{hasValue:!1}),this.generateTypedInputType(i18n,"set",{subOptions:["true","false"]})]}})}async generateCoverLiftField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.covers.fields.lift";await this.generateTypedInputField(container,{id:this.elements.lift,i18n:i18n,value:value,typedInput:{types:["num","str",this.generateTypedInputType(i18n,"stop",{hasValue:!1})]}})}async generateCoverTiltField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.covers.fields.tilt";await this.generateTypedInputField(container,{id:this.elements.tilt,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateSceneModeField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.mode";await this.generateTypedInputField(container,{id:this.elements.scene_mode,i18n:i18n,value:value,addDefaultTypes:!1,typedInput:{types:[this.generateTypedInputType(i18n,"single",{hasValue:!1}),this.generateTypedInputType(i18n,"dynamic",{hasValue:!1})]}})}async generateScenePickerField(container,value=0){var buttonElement=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.picker";let list=await this.generateSimpleListField(container,{id:this.elements.scene_picker,i18n:buttonElement});list.addClass("multiple-select"),list.multipleSelect({maxHeight:300,dropWidth:300,width:200,numberDisplayed:1,single:!0,singleRadio:!0,hideOptgroupCheckboxes:!0,showClear:!0,selectAll:!1,filter:!0,filterPlaceholder:this.getI18n(buttonElement,"filter_place_holder"),placeholder:RED._(this.NRCD+"/server:editor.multiselect.none_selected"),container:".node-input-output-container-row"});buttonElement=$("<a/>",{id:this.elements.scene_picker_refresh,class:"red-ui-button",style:"margin-left:10px;"});this.createIconElement(this.getIcon("refresh"),buttonElement),list.closest(".form-row").append(buttonElement)}async generateSceneGroupField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.group";await this.generateTypedInputField(container,{id:this.elements.group,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateSceneSceneField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.scene";await this.generateTypedInputField(container,{id:this.elements.scene,i18n:i18n,value:value,typedInput:{types:["num","str",this.generateTypedInputType(i18n,"deconz",{subOptions:["next","prev"]})]}})}async generateSceneNameField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.scene_name";await this.generateTypedInputField(container,{id:this.elements.scene_name,i18n:i18n,value:value,typedInput:{types:["str","re"]}})}async generateTargetField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.common.fields.target";await this.generateTypedInputField(container,{id:this.elements.target,i18n:i18n,value:value,typedInput:{types:[this.generateTypedInputType(i18n,"attribute",{hasValue:!1}),this.generateTypedInputType(i18n,"state",{hasValue:!1}),this.generateTypedInputType(i18n,"config",{hasValue:!1}),this.generateTypedInputType(i18n,"scene_call",{hasValue:!1})]}})}async generateCommandField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.common.fields.command";await this.generateTypedInputField(container,{id:this.elements.command,i18n:i18n,value:value,typedInput:{types:["str",this.generateTypedInputType(i18n,"object",{hasValue:!1})]}})}async generatePayloadField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.common.fields.payload";await this.generateTypedInputField(container,{id:this.elements.payload,i18n:i18n,value:value,addDefaultTypes:!1,typedInput:{types:["msg","flow","global","str","num","bool","json","jsonata","date"]}})}async generatePauseDelayField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.pause.fields.delay";await this.generateTypedInputField(container,{id:this.elements.delay,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateCommonTransitionTimeField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.common.fields.transitiontime";await this.generateTypedInputField(container,{id:this.elements.transitiontime,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateCommonOnErrorRetryField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.common.fields.retryonerror";await this.generateTypedInputField(container,{id:this.elements.retryonerror,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateCommonOnErrorAfterField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.common.fields.aftererror";await this.generateTypedInputField(container,{id:this.elements.aftererror,i18n:i18n,value:value,typedInput:{types:[this.generateTypedInputType(i18n,"continue",{hasValue:!1}),this.generateTypedInputType(i18n,"stop",{hasValue:!1})]}})}}class DeconzCommandListEditor extends DeconzListItemListEditor{get elements(){return{list:"node-input-output-container"}}get listType(){return"command"}get buttons(){let buttons=[];var type_name,i18n=this.NRCD+"/server:editor.inputs.commands.type";for(const[type,enabled]of Object.entries(this.options.type))enabled&&(type_name=this.getI18n(i18n+".options."+type,"label"),buttons.push({label:this.getI18n(i18n+".add_button","label",{type:type_name}),icon:this.getIcon(this.getI18n(i18n+".add_button","icon"),!0),title:this.getI18n(i18n+".add_button","title",{type:type_name}),click:()=>this.$elements.list.editableList("addItem",{type:type})}));return buttons}async init(mainEditor){await super.init(mainEditor),await this.initList(DeconzCommandEditor,this.node.commands)}}
class DeconzEditor{constructor(node,options={}){this.node=node,this.options=options}get elements(){return{}}get NRCD(){return"node-red-contrib-deconz"}findElements(){this.$elements={},Object.keys(this.elements).forEach(k=>{this.$elements[k]=this.findElement(this.elements[k])})}findElement(identifier){return"#"!==identifier.charAt(0)&&"."!==identifier.charAt(0)&&(identifier="#"+identifier),$(identifier)}async init(){this.findElements()}async connect(){}sendError(msg,timeout=1e4){let myNotification=RED.notify(msg,{timeout:timeout,type:"error",buttons:[{text:"Ok",class:"primary",click:()=>myNotification.close()}]})}getIcon(icon,includeClass=!1){return"deconz"===icon?"icons/node-red-contrib-deconz/icon-color.png":"homekit"===icon?"icons/node-red-contrib-deconz/homekit-logo.png":RED.nodes.fontAwesome.getIconList().includes("fa-"+icon)?`${includeClass?"fa ":""}fa-`+icon:icon}createIconElement(icon,container,isLarge=!1){if("fa-"===icon.substr(0,3)){if(RED.nodes.fontAwesome.getIconUnicode(icon)){let faIconElement=$("<i/>").appendTo(container);return void faIconElement.addClass("fa "+icon+(isLarge?" fa-lg":""))}icon=RED.settings.apiRootUrl+"icons/node-red/arrow-in.svg"}let imageIconElement=$("<div/>").appendTo(container);imageIconElement.css("backgroundImage","url("+icon+")")}getI18n(prefix,suffix,data={}){let _path=prefix;suffix&&(_path+="."+suffix),data.defaultValue="_deconz_undefined_";prefix=RED._(_path,data);if("_deconz_undefined_"!==prefix)return prefix}async generateSimpleListField(container,options){let input=$("<select/>",{id:options.id});if(options.choices)for(var[key,value]of options.choices)input.append($("<option/>").attr("value",key).html(RED._(value)));var row=await this.generateInputWithLabel(input,options);return container.append(row),void 0!==options.currentValue&&input.val(options.currentValue),input}async generateTypedInput(container,options){let input=$("<input/>",{id:options.id,placeholder:RED._(options.placeholder)});options=$("<input/>",{id:options.id+"_type",type:"hidden"});return input.append(options),input}async initTypedInput(input,options){options=$.extend({addDefaultTypes:!0,displayOnlyIcon:!1,value:{},width:"200px"},options);let typedInputOptions=$.extend({types:["msg","flow","global"]},options.typedInput);if(typedInputOptions.typeField=options.typeId,options.addDefaultTypes)for(var type of["msg","flow","global","jsonata"])typedInputOptions.types.includes(type)||typedInputOptions.types.push(type);if(options.displayOnlyIcon){let that=this;function valueLabel(a,b){let typeDefinition;for(const type of this.typeList)"object"==typeof type&&type.value===this.propertyType&&(typeDefinition=type);void 0!==typeDefinition&&void 0!==typeDefinition.icon&&(this.oldValue=this.input.val(),this.input.val(""),this.valueLabelContainer.hide(),that.createIconElement(typeDefinition.icon,this.selectLabel),this.selectTrigger.addClass("red-ui-typedInput-full-width"),this.selectLabel.show())}for(let type of typedInputOptions.types)"string"!=typeof type&&(type.hasValue=!0,type.valueLabel=valueLabel)}input.typedInput(typedInputOptions),void 0!==options.width&&input.typedInput("width",options.width),options.value&&(void 0!==options.value.type&&input.typedInput("type",options.value.type),void 0!==options.value.value&&input.typedInput("value",options.value.value))}async generateTypedInputField(container,options){var input=await this.generateTypedInput(container,{id:options.id,placeholder:this.getI18n(options.i18n,"placeholder")}),row=await this.generateInputWithLabel(input,options);return container.append(row),await this.initTypedInput(input,options),input}async generateDoubleTypedInputField(container,optionsFirst,optionsSecond){var inputFirst=await this.generateTypedInput(container,optionsFirst);let row=await this.generateInputWithLabel(inputFirst,optionsFirst);var inputSecond=await this.generateTypedInput(container,optionsSecond);row.append(inputSecond),container.append(row),optionsFirst.displayOnlyIcon=!0,optionsFirst.width="50px",optionsSecond.width="150px",await this.initTypedInput(inputFirst,optionsFirst),await this.initTypedInput(inputSecond,optionsSecond)}generateTypedInputType(i18n,name,data={}){if(data.value=name,void 0===data.label&&(data.label=this.getI18n(i18n,`options.${name}.label`,{})||name),!1!==data.icon&&void 0===data.icon&&(data.icon=this.getIcon(this.getI18n(i18n,`options.${name}.icon`))),data.icon&&"fa-"===data.icon.substr(0,3)&&(data.icon="fa "+data.icon),Array.isArray(data.subOptions)){Array.isArray(data.options)||(data.options=[]);for(const opt of data.subOptions)data.options.push(this.generateTypedInputType(i18n+".options."+name,"string"==typeof opt?opt:opt.name,{icon:!1}))}return data}async generateCheckboxField(container,options){var input=$("<input/>",{id:options.id,type:"checkbox",style:"display: table-cell; width: 14px;vertical-align: top;margin-right: 5px",checked:options.currentValue});let row=await this.generateInputWithLabel(input,options);row.append($("<span/>").html(RED._(options.descText)).css("display","table-cell")),container.append(row)}async generateInputWithLabel(input,options={}){let row=$("<div/>",{class:"form-row",style:"padding:5px;margin:0;display:table;min-width:420px;"});var inputID=input.attr("id");if(inputID){let labelElement=$("<label/>");labelElement.attr("for",inputID),labelElement.attr("class","l-width"),labelElement.attr("style","display:table-cell;"),void 0===options.title&&(options.title=this.getI18n(options.i18n,"title")),options.title&&labelElement.attr("title",this.getI18n(options.i18n,"title")),void 0===options.icon&&(options.icon=this.getI18n(options.i18n,"icon")),options.icon&&(this.createIconElement(this.getIcon(options.icon),labelElement),labelElement.append("&nbsp;")),void 0===options.label&&(options.label=this.getI18n(options.i18n,"label")),options.label&&labelElement.append(`<span>${options.label}</span>`),row.append(labelElement)}return input.css("display","table-cell"),row.append(input),row}async generateHR(container,topBottom="5px",leftRight="50px"){container.append(`<hr style="margin: ${topBottom} ${leftRight};">`)}async generateSeparator(container,label){container.append(`<div class="separator">${RED._(label)}</div>`)}static versionCompare(v1,v2,options={}){const lexicographical=options&&options.lexicographical;options=options&&options.zeroExtend;let v1parts=v1.split("."),v2parts=v2.split(".");function isValidPart(x){return(lexicographical?/^\d+[A-Za-z]*$/:/^\d+$/).test(x)}if(!v1parts.every(isValidPart)||!v2parts.every(isValidPart))return NaN;if(options){for(;v1parts.length<v2parts.length;)v1parts.push("0");for(;v2parts.length<v1parts.length;)v2parts.push("0")}lexicographical||(v1parts=v1parts.map(Number),v2parts=v2parts.map(Number));for(let i=0;i<v1parts.length;++i){if(v2parts.length===i)return 1;if(v1parts[i]!==v2parts[i])return v1parts[i]>v2parts[i]?1:-1}return v1parts.length!==v2parts.length?-1:0}}class DeconzMainEditor extends DeconzEditor{constructor(node,options={}){if(super(node,$.extend(!0,{have:{statustext:!0,query:!0,device:!0,output_rules:!1,commands:!1,specific:!1},device:{batteryFilter:!1},output_rules:{format:{single:!0,array:!1,sum:!1,average:!1,min:!1,max:!1},type:{attribute:!0,state:!0,config:!0,homekit:!1,scene_call:!1}},commands:{type:{deconz_state:!0,homekit:!0,custom:!0,pause:!0}},specific:{api:{},output:{},server:{}}},options)),this.subEditor={},this.initDone=!1,this.options.have.statustext&&(this.subEditor.statustext=new DeconzStatusTextEditor(this.node,this.options.statustext)),this.options.have.device&&(this.subEditor.device=new DeconzDeviceEditor(this.node,this.options.device)),this.options.have.query&&(this.subEditor.query=new DeconzQueryEditor(this.node,this.options.query)),this.options.have.specific)switch(this.node.type){case"deconz-api":this.subEditor.specific=new DeconzSpecificApiEditor(this.node,this.options.specific.api);break;case"deconz-output":this.subEditor.specific=new DeconzSpecificOutputEditor(this.node,this.options.specific.output);break;case"deconz-server":this.subEditor.specific=new DeconzSpecificServerEditor(this.node,this.options.specific.server)}this.options.have.output_rules&&(this.subEditor.output_rules=new DeconzOutputRuleListEditor(this.node,this.options.output_rules)),this.options.have.commands&&(this.subEditor.commands=new DeconzCommandListEditor(this.node,this.options.commands))}get elements(){return{tipBox:"node-input-tip-box",server:"node-input-server"}}async configurationMigration(){if(!((this.node.config_version||0)>=this.node._def.defaults.config_version.value)){let config={};for(const key of Object.keys(this.node._def.defaults))config[key]=this.node[key];var data={id:this.node.id,type:this.node.type,config:JSON.stringify(config)};let errorMsg="Error while migrating the configuration of the node from version "+(this.node.config_version||0)+" to version "+this.node._def.defaults.config_version.value+".",result=await $.getJSON(this.NRCD+"/configurationMigration",data).catch((t,u)=>{this.$elements.tipBox.append(`<div class="form-tips form-warning"><p>Migration errors:</p><p>${errorMsg}</p></div>`)});if(result&&!result.notNeeded){if(result.new)for(var[key,value]of Object.entries(result.new))this.node[key]=value;if(result.delete&&Array.isArray(result.delete))for(const key of result.delete)delete this.node[key];data=msg=>"node-red-contrib-deconz"===msg.substr(0,23)?RED._(msg):msg;result.errors&&Array.isArray(result.errors)&&0<result.errors.length&&this.$elements.tipBox.append('<div class="form-tips form-warning"><p>Migration errors:</p><ul>'+`<li>${result.errors.map(data).join("</li><li>")}</li>`+"</ul></div>"),result.info&&Array.isArray(result.info)&&0<result.info.length&&this.$elements.tipBox.append('<div class="form-tips"><p>Migration info:</p><ul>'+`<li>${result.info.map(data).join("</li><li>")}</li>`+"</ul></div>")}}}async init(){await new Promise(resolve=>setTimeout(resolve,100)),await super.init(),await this.configurationMigration(),this.initPromises=[];for(const editor of Object.values(this.subEditor))this.initPromises.push(editor.init(this));await Promise.all(this.initPromises),this.initDone=!0,delete this.initPromises;let connectPromises=[];for(const editor of Object.values(this.subEditor))connectPromises.push(editor.connect());await Promise.all(connectPromises)}get serverNode(){return"deconz-server"===this.node.type?this.node:RED.nodes.node(this.$elements.server.val())}async isInitialized(){this.initDone||await Promise.all(this.initPromises)}async updateQueryDeviceDisplay(options){var type=this.subEditor.query.$elements.select.typedInput("type");switch(type){case"device":await this.subEditor.device.updateList(options);break;case"json":case"jsonata":this.subEditor.query.$elements.select.typedInput("validate")&&await this.subEditor.query.updateList(options)}await this.subEditor.device.display("device"===type),await this.subEditor.query.display("device"!==type)}oneditsave(){var newRules;this.options.have.output_rules&&(newRules=this.subEditor.output_rules.value,this.node.outputs=newRules.length,this.node.output_rules=newRules),this.options.have.commands&&(this.node.commands=this.subEditor.commands.value),this.options.have.specific&&(this.node.specific=this.subEditor.specific.value)}}class DeconzStatusTextEditor extends DeconzEditor{constructor(node,options={}){super(node,$.extend({allowedTypes:["msg","jsonata"]},options))}get elements(){return{statustext:"node-input-statustext"}}async init(mainEditor){await super.init(),this.mainEditor=mainEditor,this.initTypedInput()}initTypedInput(){let options=[];this.mainEditor.options.have.statustext&&options.push({value:"auto",label:RED._(this.NRCD+"/server:editor.inputs.statustext.options.auto"),icon:`icons/${this.NRCD}/icon-color.png`,hasValue:!1}),this.$elements.statustext.typedInput({type:"auto",types:options.concat(this.options.allowedTypes),typeField:`#${this.elements.statustext}_type`})}}class DeconzDeviceListEditor extends DeconzEditor{constructor(node,options={}){super(node,options)}get xhrURL(){return this.NRCD+"/itemlist"}get xhrParams(){return{controllerID:this.mainEditor.serverNode.id,forceRefresh:this.options.refresh}}async display(display=!0){if(this.$elements.showHide)return display?this.$elements.showHide.show():this.$elements.showHide.hide(),this.$elements.showHide.promise()}async getItems(options,xhrParams){xhrParams.forceRefresh=options.refresh;xhrParams=await $.getJSON(this.xhrURL,xhrParams).catch((t,u)=>{this.sendError(400===t.status&&t.responseText?t.responseText:u.toString())});return xhrParams&&xhrParams.error_message?(console.warn(xhrParams.error_message),void RED.notify("Warning : "+xhrParams.error_message,{type:"warning",timeout:1e4})):this.formatItemList(xhrParams.items,options.keepOnlyMatched)}async updateList(options){if(options=$.extend({refresh:!0},options),this.mainEditor.serverNode){let list=this.$elements.list,params=this.xhrParams;!0===this.options.batteryFilter&&(options.keepOnlyMatched=!0,params.query=JSON.stringify({type:"match",match:{"config.battery":{type:"complex",operator:"!==",value:void 0}}}));options=await this.getItems(options,params);list.children().remove(),options&&this.generateHtmlItemList(options,this.$elements.list),list.multipleSelect("refresh"),options&&list.multipleSelect("enable")}}formatItemList(items,keepOnlyMatched=!1){let itemList={};var injectItems=(part,matched)=>{part.forEach(item=>{var device_type=item.type;void 0===itemList[device_type]&&(itemList[device_type]=[]),item.query_match=matched,itemList[device_type].push(item)})};return injectItems(items.matched,!0),!1===keepOnlyMatched&&injectItems(items.rejected,!1),itemList}generateHtmlItemList(items,htmlContainer){var group_key,item_list,queryMode=this.constructor===DeconzQueryEditor;for([group_key,item_list]of Object.entries(items).sort((a,b)=>{a=a[0].toLowerCase(),b=b[0].toLowerCase();return a<b?-1:b<a?1:0})){let groupHtml=$("<optgroup/>").attr("label",group_key);for(const item of item_list.sort((a,b)=>{a=a.name.toLowerCase(),b=b.name.toLowerCase();return a<b?-1:b<a?1:0})){let label=item.name,opt=("groups"===item.device_type&&(label+=" (lights: "+item.lights.length,item.scenes.length&&(label+=", scenes: "+item.scenes.length),label+=")"),$("<option>"+label+"</option>").attr("value",item.device_path));queryMode&&item.query_match&&opt.attr("selected",""),opt.appendTo(groupHtml)}groupHtml.appendTo(htmlContainer)}}}class DeconzQueryEditor extends DeconzDeviceListEditor{constructor(node,options={}){super(node,$.extend({allowedTypes:["json","jsonata"]},options))}get elements(){return{select:"node-input-query",list:"node-input-query_result",showHide:".deconz-query-selector",refreshButton:"#force-refresh-query-result"}}get type(){return this.$elements.select.typedInput("type")}set type(val){this.$elements.list.typedInput("type",val)}get value(){return this.$elements.select.typedInput("value")}set value(val){this.$elements.list.typedInput("value",val)}get xhrParams(){let params=super.xhrParams;return params.query=this.value,params.queryType=this.type,params.nodeID=this.node.id,params}async init(mainEditor){await super.init(),this.mainEditor=mainEditor,this.initTypedInput(),this.$elements.list.multipleSelect({maxHeight:300,dropWidth:320,width:320,single:!1,selectAll:!1,filter:!0,filterPlaceholder:RED._(this.NRCD+"/server:editor.inputs.device.device.filter"),placeholder:RED._(this.NRCD+"/server:editor.multiselect.none_selected"),numberDisplayed:1,disableIfEmpty:!0,showClear:!1,hideOptgroupCheckboxes:!0,filterGroup:!0,onClick:view=>{this.$elements.list.multipleSelect(view.selected?"uncheck":"check",view.value)}}),await this.mainEditor.updateQueryDeviceDisplay({useSavedData:!0})}initTypedInput(){let options=[];this.mainEditor.options.have.device&&options.push({value:"device",label:RED._(this.NRCD+"/server:editor.inputs.device.query.options.device"),icon:`icons/${this.NRCD}/icon-color.png`,hasValue:!1}),this.$elements.select.typedInput({type:"text",types:options.concat(this.options.allowedTypes),typeField:"#node-input-search_type"})}async connect(){await super.connect(),this.$elements.select.on("change",()=>{this.mainEditor.updateQueryDeviceDisplay({useSavedData:!0}),this.mainEditor.options.have.output_rules&&this.mainEditor.subEditor.output_rules.refresh()}),this.$elements.refreshButton.on("click",()=>{this.updateList(),this.mainEditor.options.have.output_rules&&this.mainEditor.subEditor.output_rules.refresh()})}}class DeconzDeviceEditor extends DeconzDeviceListEditor{constructor(node,options={}){super(node,$.extend({batteryFilter:!1},options))}get elements(){return{list:"node-input-device_list",showHide:".deconz-device-selector",refreshButton:"#force-refresh"}}get value(){return this.$elements.list.multipleSelect("getSelects")}set value(val){this.$elements.list.multipleSelect("setSelects",val)}async init(mainEditor){await super.init(),this.mainEditor=mainEditor,this.$elements.list.multipleSelect({maxHeight:300,dropWidth:320,width:320,single:"multiple"!==this.$elements.list.attr("multiple"),filter:!0,filterPlaceholder:RED._(this.NRCD+"/server:editor.inputs.device.device.filter"),placeholder:RED._(this.NRCD+"/server:editor.multiselect.none_selected"),showClear:!0})}async connect(){await super.connect();var refreshDeviceList=()=>{this.updateList($.extend(this.options,{useSelectedData:!0})),this.mainEditor.options.have.output_rules&&this.mainEditor.subEditor.output_rules.refresh()};this.mainEditor.$elements.server.on("change",refreshDeviceList),this.$elements.refreshButton.on("click",refreshDeviceList),this.mainEditor.options.have.output_rules&&this.$elements.list.on("change",()=>{this.mainEditor.subEditor.output_rules.refresh()})}async updateList(options){let itemsSelected;(options=$.extend({useSavedData:!1,useSelectedData:!1},options)).useSelectedData&&(itemsSelected=this.$elements.list.multipleSelect("getSelects")),await super.updateList(options),options.useSavedData&&Array.isArray(this.node.device_list)?this.$elements.list.multipleSelect("setSelects",this.node.device_list):options.useSelectedData&&Array.isArray(itemsSelected)&&this.$elements.list.multipleSelect("setSelects",itemsSelected)}}class DeconzSpecificApiEditor extends DeconzEditor{constructor(node,options={}){super(node,$.extend({},options))}get elements(){return{container:"deconz-api-form",name:"node-config-input-name",method:"node-config-input-method",endpoint:"node-config-input-endpoint",payload:"node-config-input-payload"}}get default(){return{name:"",method:{type:"GET"},endpoint:{type:"str",value:"/"},payload:{type:"json",value:"{}"}}}async init(){this.node.specific=$.extend(!0,this.default.specific,this.node.specific);var container=this.findElement(this.elements.container);await this.generateMethodField(container,this.node.specific.method),await this.generateEndpointField(container,this.node.specific.endpoint),await this.generatePayloadField(container,this.node.specific.payload),await super.init()}async connect(){await super.connect()}get value(){return{method:{type:this.$elements.method.typedInput("type"),value:this.$elements.method.typedInput("value")},endpoint:{type:this.$elements.endpoint.typedInput("type"),value:this.$elements.endpoint.typedInput("value")},payload:{type:this.$elements.payload.typedInput("type"),value:this.$elements.payload.typedInput("value")}}}set value(newValues){this.$elements.name.val(newValues.name);for(var field of["method","endpoint","payload"])this.$elements[field].typedInput("type",newValues[field].type),this.$elements[field].typedInput("value",newValues[field].value);for(const element of Object.values(this.$elements))element.trigger("change")}async generateMethodField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.api.method";await this.generateTypedInputField(container,{id:this.elements.method,i18n:i18n,value:value,width:"250px",typedInput:{types:[this.generateTypedInputType(i18n,"GET",{hasValue:!1}),this.generateTypedInputType(i18n,"POST",{hasValue:!1}),this.generateTypedInputType(i18n,"PUT",{hasValue:!1}),this.generateTypedInputType(i18n,"DELETE",{hasValue:!1})]}})}async generateEndpointField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.api.endpoint";await this.generateTypedInputField(container,{id:this.elements.endpoint,i18n:i18n,value:value,width:"250px",typedInput:{types:["str"]}})}async generatePayloadField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.api.payload";await this.generateTypedInputField(container,{id:this.elements.payload,i18n:i18n,value:value,width:"250px",typedInput:{types:["json","jsonata"]}})}}class DeconzSpecificOutputEditor extends DeconzEditor{constructor(node,options={}){super(node,$.extend({},options))}get elements(){return{container:"specific-container",delay:"node-input-delay",result:"node-input-result"}}get default(){return{delay:{type:"num",value:50},result:{type:"at_end"}}}async init(){this.node.specific=$.extend(!0,this.default,this.node.specific);var container=this.findElement(this.elements.container);await this.generateSeparator(container,this.NRCD+"/server:editor.inputs.separator.specific"),await this.generateDelayField(container,this.node.specific.delay),await this.generateResultField(container,this.node.specific.result),await super.init()}async generateDelayField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.output.delay";await this.generateTypedInputField(container,{id:this.elements.delay,i18n:i18n,value:value,width:"250px",typedInput:{types:["num"]}})}async generateResultField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.specific.output.result";await this.generateTypedInputField(container,{id:this.elements.result,i18n:i18n,value:value,width:"250px",typedInput:{types:[this.generateTypedInputType(i18n,"never",{hasValue:!1}),this.generateTypedInputType(i18n,"after_command",{hasValue:!1}),this.generateTypedInputType(i18n,"at_end",{hasValue:!1})]}})}async connect(){await super.connect()}get value(){return{delay:{type:this.$elements.delay.typedInput("type"),value:this.$elements.delay.typedInput("value")},result:{type:this.$elements.result.typedInput("type"),value:this.$elements.result.typedInput("value")}}}}class DeconzSpecificServerEditor extends DeconzEditor{constructor(node,options={}){super(node,$.extend({},options))}get elements(){return{name:"node-config-input-name",ip:"node-config-input-ip",port:"node-config-input-port",apikey:"node-config-input-secured_apikey",ws_port:"node-config-input-ws_port",secure:"node-config-input-secure",polling:"node-config-input-polling",getSettingsButton:"node-contrib-deconz-get-settings"}}get default(){return{name:"",ip:"",port:"",apikey:"",ws_port:"",secure:!1,polling:15}}get xhrURL(){return this.NRCD+"/serverAutoconfig"}async init(){this.node.specific=$.extend(!0,this.default,this.node.specific),await super.init(),this.node.migration_secured_apikey&&(this.$elements.apikey.val(this.node.migration_secured_apikey),this.$elements.apikey.trigger("change"))}async connect(){await super.connect(),this.$elements.getSettingsButton.on("click",()=>this.discoverParams())}async discoverParams(overrideSettings){void 0===overrideSettings&&(overrideSettings={});let myNotification,stop=!1,closeNotification=()=>{myNotification&&"function"==typeof myNotification.close&&myNotification.close(),stop=!0};myNotification=RED.notify("<p>Trying to find the server settings, please wait...<br>This can take up to 15 seconds.</p>",{modal:!0,fixed:!0,type:"info",buttons:[{text:"Cancel",class:"primary",click:closeNotification}]});try{let params=Object.assign({},this.value,overrideSettings),request=(void 0===params.discoverParam&&(params.discoverParam={}),params.discoverParam.devicetype="Node-Red Deconz Plugin"+(this.node?" id:"+this.node.id:""),await $.getJSON(this.xhrURL,{config:JSON.stringify(params)}).catch((t,u)=>{this.sendError(400===t.status&&t.responseText?t.responseText:u.toString())}));if(stop)return;if(request.error){let html=`<p>Error ${request.error.code}: ${request.error.description}</p>`,buttons=[{text:"Cancel",click:closeNotification}];switch(request.error.code){case"GATEWAY_CHOICE":html+="<p>There is multiple Deconz device in you network, please select the one you want to configure.</p>";let node=this;for(const[index,gateway]of request.error.gateway_list.entries())buttons.push({text:`#${index+1}: `+gateway.name,id:"node-red-contrib-deconz-gateway-id-"+index,class:"primary",click:()=>{var gateway_id=gateway.bridge_id;closeNotification(),gateway_id&&(request.currentSettings.discoverParam.targetGatewayID=gateway_id),node.discoverParams(request.currentSettings)}});buttons.push(buttons.shift());break;case"DECONZ_ERROR":101===request.error.type&&(buttons.unshift({text:"I pressed the link button",class:"primary",click:()=>{closeNotification(),this.discoverParams(request.currentSettings)}}),html+="<p>The reason why the request failed is that the gateway was not unlocked. This mechanism is needed to prevent anybody from access to the gateway without being permitted to do so.</p>",html+="<ul><li>In a new browser tab open the <a href='http://phoscon.de/pwa/' target='_blank'>Phoscon App</a></li><li>Click on Menu -> Settings -> Gateway</li><li>Click on \"Advanced\" button</li><li>Click on the \"Authenticate app\" button</li></ul>",html+=`<p>Within 60 seconds after unlocking the gateway, click on the button "${buttons[0].text}".</p>`);break;default:buttons[buttons.length-1].text="Cancel"}html+=`<p>Logs:</p><pre>${request.log.join("\n")}</pre>`,closeNotification(),myNotification=RED.notify(html,{modal:!0,fixed:!0,type:"error",buttons:buttons})}else request.success?(closeNotification(),myNotification=RED.notify("<p>Settings fetched successfully !</p>",{modal:!1,fixed:!1,type:"success"}),this.value=request.currentSettings):(closeNotification(),myNotification=RED.notify(`<p>Unknown error : ${JSON.stringify(request)}</p>`,{modal:!0,fixed:!0,type:"error",buttons:[{text:"Ok",class:"primary",click:closeNotification}]}))}catch(error){closeNotification(),myNotification=RED.notify(`<p>Error while processing request: ${error.toString()}</p>`,{type:"error"})}}get value(){return{name:this.$elements.name.val(),ip:this.$elements.ip.val(),port:this.$elements.port.val(),apikey:this.$elements.apikey.val(),ws_port:this.$elements.ws_port.val(),secure:this.$elements.secure.prop("checked"),polling:this.$elements.polling.val()}}set value(newValues){this.$elements.name.val(newValues.name),this.$elements.ip.val(newValues.ip),this.$elements.port.val(newValues.port),this.$elements.apikey.val(newValues.apikey),this.$elements.ws_port.val(newValues.ws_port),this.$elements.secure.prop("checked",newValues.secure),this.$elements.polling.val(newValues.polling);for(const element of Object.values(this.$elements))element.trigger("change")}}class DeconzListItemEditor extends DeconzEditor{constructor(node,listEditor,container,options={}){super(node,options),this.listEditor=listEditor,container.uniqueId(),this.uniqueId=container.attr("id"),this.container=container}set index(value){void 0!==value&&this.$elements&&this.$elements.outputButton&&this.$elements.outputButton.find(".node-input-rule-index").html(value+1),this._index=value}get index(){return this._index}async init(){await this.generateOutputButton(this.container.children().first()),await super.init()}async generateOutputButton(container){$("<a/>",{id:this.elements.outputButton,class:"red-ui-button top-right-badge",title:RED._(this.options.button_title)}).append(`&nbsp;&#8594;&nbsp;<span class="node-input-rule-index">${this.index+1}</span>&nbsp;`).appendTo(container)}}class DeconzListItemListEditor extends DeconzEditor{constructor(node,options={}){super(node,options),this.items={}}get listType(){return"item"}get buttons(){return[]}async init(mainEditor){await super.init(),this.mainEditor=mainEditor}async initList(itemEditorClass,items=[]){var buttons=this.buttons,addButton=0===buttons.length||DeconzEditor.versionCompare(RED.settings.version,"1.3.0")<0;this.$elements.list.editableList({sortable:!0,removable:!0,height:"auto",addButton:addButton,buttons:buttons,addItem:(row,index,item)=>{let itemEditor=new itemEditorClass(this.node,this,row,this.options);item.uniqueId=itemEditor.uniqueId,this.items[item.uniqueId]=itemEditor,itemEditor.init(item,index)},removeItem:item=>{if(!item.uniqueId||!this.items[item.uniqueId])throw new Error(`Error while removing the ${this.listType}, the ${this.listType} ${item.uniqueId} does not exist.`);var deletedIndex=this.items[item.uniqueId].index;delete this.items[item.uniqueId];for(const item of Object.values(this.items))item.index>deletedIndex&&item.index--},sortItems:items=>{items.each((index,item)=>{if(!this.items[item.attr("id")])throw new Error(`Error while moving the ${this.listType}, the ${this.listType} ${index+1} does not exist.`);this.items[item.attr("id")].index=index})}}),0<items.length&&this.$elements.list.editableList("addItems",items)}get value(){let result=[];for(const rule of Object.values(this.items).sort((a,b)=>a.index-b.index))result.push(rule.value);return result}refresh(){}}class DeconzOutputRuleEditor extends DeconzListItemEditor{constructor(node,listEditor,container,options={}){super(node,listEditor,container,options=$.extend({enableEachState:!0},options))}get elements(){let elements={};for(const key of["format","type","payload","output","onstart","onerror","outputButton"])elements[key]=`node-input-output-rule-${this.uniqueId}-`+key;return elements}get value(){let value={};switch(value.type=this.$elements.type.val(),value.format=this.$elements.format.val(),value.type){case"attribute":case"state":case"config":"deconz-input"===this.node.type&&(value.output=this.$elements.output.val()),["deconz-input","deconz-battery"].includes(this.node.type)&&(value.onstart=this.$elements.onstart.is(":checked")),["deconz-input","deconz-get"].includes(this.node.type)&&(value.payload=this.$elements.payload.multipleSelect("getSelects"));break;case"homekit":["deconz-input","deconz-battery"].includes(this.node.type)&&(value.onstart=this.$elements.onstart.is(":checked")),"deconz-input"===this.node.type&&(value.onerror=this.$elements.onerror.is(":checked")),["deconz-input","deconz-get"].includes(this.node.type)&&(value.payload=this.$elements.payload.multipleSelect("getSelects"))}return value}get defaultRule(){let rule={type:"state",payload:["__complete__"],format:"single"};return"deconz-input"===this.node.type&&(rule.output="always",rule.onstart=!0,rule.onerror=!0),"deconz-battery"===this.node.type&&(rule.onstart=!0),rule}async init(rule,index){this._index=index,rule=$.extend(!0,this.defaultRule,rule),await this.generatePayloadTypeField(this.container,rule.type),["deconz-input","deconz-get"].includes(this.node.type)&&await this.generatePayloadField(this.container),await this.generatePayloadFormatField(this.container,rule.format),"deconz-input"===this.node.type&&await this.generateOutputField(this.container,(void 0!==rule.output?rule:this.defaultRule).output),["deconz-input","deconz-battery"].includes(this.node.type)&&await this.generateOnStartField(this.container,(void 0!==rule.onstart?rule:this.defaultRule).onstart),"deconz-input"===this.node.type&&await this.generateOnErrorField(this.container,(void 0!==rule.onerror?rule:this.defaultRule).onerror),await super.init(),await this.listEditor.mainEditor.isInitialized(),await this.initPayloadList(rule.payload),await this.updateShowHide(rule.type),await this.connect()}async connect(){await super.connect(),this.$elements.type.on("change",()=>{var type=this.$elements.type.val();["attribute","state","config","homekit"].includes(type)&&this.updatePayloadList(),this.updateShowHide(type)}),this.$elements.outputButton.on("click",()=>{try{let nodes=RED.nodes.filterLinks({source:this.node,sourcePort:this.index}).map(l=>{var result=l.target.type;return""!==l.target.name?result+":"+l.target.name:void 0!==l.target._def.label?result+":"+l.target._def.label():result}),myNotification=RED.notify(`The output ${this.index+1} is sending message to ${nodes.length} nodes :<br>`+nodes.join("<br>"),{modal:!0,timeout:5e3,buttons:[{text:"okay",class:"primary",click:()=>myNotification.close()}]})}catch(e){this.sendError("This is using not documented API so can be broken at anytime.<br>Error while getting connected nodes: "+e.toString())}})}async updateShowHide(type){switch(type){case"attribute":case"state":case"config":this.$elements.payload.closest(".form-row").show(),this.$elements.output.closest(".form-row").show(),this.$elements.onstart.closest(".form-row").show(),this.$elements.onerror.closest(".form-row").hide();break;case"homekit":this.$elements.payload.closest(".form-row").show(),this.$elements.output.closest(".form-row").hide(),this.$elements.onstart.closest(".form-row").show(),this.$elements.onerror.closest(".form-row").show();break;case"scene_call":this.$elements.payload.closest(".form-row").hide(),this.$elements.output.closest(".form-row").hide(),this.$elements.onstart.closest(".form-row").hide(),this.$elements.onerror.closest(".form-row").hide()}}async updatePayloadList(){if(this.listEditor.mainEditor.serverNode){this.$elements.payload.multipleSelect("disable"),this.$elements.payload.children().remove();var queryType=this.listEditor.mainEditor.subEditor.query.type,devices=this.listEditor.mainEditor.subEditor.device.value,type=this.$elements.type.val();if(["attribute","state","config","homekit"].includes(type)){var i18n=this.NRCD+"/server:editor.inputs.outputs.payload";let html="";if("homekit"===type?html+='<option value="__auto__">'+RED._(i18n+".options.auto")+"</option>":(html+='<option value="__complete__">'+RED._(i18n+".options.complete")+"</option>",!0===this.options.enableEachState&&(html+='<option value="__each__">'+RED._(i18n+".options.each")+"</option>")),this.$elements.payload.html(html),"device"===queryType){var data=await $.getJSON(this.NRCD+`/${type}list`,{controllerID:this.listEditor.mainEditor.serverNode.id,devices:JSON.stringify(this.listEditor.mainEditor.subEditor.device.value)});for(const _type of"attribute"===type?["attribute","state","config"]:[type]){let label=this.getI18n(i18n+".group_label."+_type),groupHtml=(void 0===label&&(label=_type),$("<optgroup/>",{label:label}));for(const item of Object.keys(data.count[_type]).sort()){let sample=data.sample[_type][item];sample="string"==typeof sample?`"${sample}"`:Array.isArray(sample)?`[${sample.toString()}]`:null===sample||void 0===sample?"NULL":sample.toString();let label;var count=data.count[_type][item];label=count===devices.length?RED._(i18n+".item_list",{name:item,sample:sample}):RED._(i18n+".item_list_mix",{name:item,sample:sample,item_count:count,device_count:devices.length}),$("<option>"+label+"</option>").attr("value","attribute"===type&&"attribute"!==_type?_type+"."+item:item).appendTo(groupHtml)}$.isEmptyObject(data.count[_type])||groupHtml.appendTo(this.$elements.payload)}}this.$elements.payload.multipleSelect("refresh").multipleSelect("enable")}}}async initPayloadList(value){let list=this.$elements.payload;list.addClass("multiple-select"),list.multipleSelect({maxHeight:300,dropWidth:300,width:200,numberDisplayed:1,single:!1,selectAll:!1,container:".node-input-output-container-row",filter:!0,filterPlaceholder:RED._(this.NRCD+"/server:editor.inputs.device.device.filter"),placeholder:RED._(this.NRCD+"/server:editor.multiselect.none_selected"),onClick:view=>{if(view.selected)switch(view.value){case"__complete__":case"__each__":case"__auto__":list.multipleSelect("setSelects",[view.value]);break;default:list.multipleSelect("uncheck","__complete__"),list.multipleSelect("uncheck","__each__"),list.multipleSelect("uncheck","__auto__")}},onUncheckAll:()=>{list.multipleSelect("setSelects",["__complete__","__auto__"])},onOptgroupClick:view=>{view.selected&&(list.multipleSelect("uncheck","__complete__"),list.multipleSelect("uncheck","__each__"),list.multipleSelect("uncheck","__auto__"))}}),await this.updatePayloadList(),value&&list.multipleSelect("setSelects",value)}async generatePayloadTypeField(container,value){var type,enabled,i18n=this.NRCD+"/server:editor.inputs.outputs.type";let choices=[];for([type,enabled]of Object.entries(this.listEditor.options.type))enabled&&choices.push([type,i18n+".options."+type]);await this.generateSimpleListField(container,{id:this.elements.type,i18n:i18n,choices:choices,currentValue:value})}async generatePayloadField(container){var i18n=this.NRCD+"/server:editor.inputs.outputs.payload";await this.generateSimpleListField(container,{id:this.elements.payload,i18n:i18n})}async generatePayloadFormatField(container,value){var format,enabled,i18n=this.NRCD+"/server:editor.inputs.outputs.format";let choices=[];for([format,enabled]of Object.entries(this.listEditor.options.format))enabled&&choices.push([format,i18n+".options."+format]);await this.generateSimpleListField(container,{id:this.elements.format,i18n:i18n,choices:choices,currentValue:value})}async generateOutputField(container,value){var i18n=this.NRCD+"/server:editor.inputs.outputs.output";await this.generateSimpleListField(container,{id:this.elements.output,i18n:i18n,choices:[["always",i18n+".options.always"],["onchange",i18n+".options.onchange"],["onupdate",i18n+".options.onupdate"]],currentValue:value})}async generateOnStartField(container,value){var i18n=this.NRCD+"/server:editor.inputs.outputs.on_start";await this.generateCheckboxField(container,{id:this.elements.onstart,i18n:i18n,currentValue:value})}async generateOnErrorField(container,value){var i18n=this.NRCD+"/server:editor.inputs.outputs.on_error";await this.generateCheckboxField(container,{id:this.elements.onerror,i18n:i18n,currentValue:value})}}class DeconzOutputRuleListEditor extends DeconzListItemListEditor{get elements(){return{list:"node-input-output-container"}}get listType(){return"rule"}get buttons(){let buttons=[];var type_name,i18n=this.NRCD+"/server:editor.inputs.outputs.type";for(const[type,enabled]of Object.entries(this.options.type))enabled&&(type_name=this.getI18n(i18n+".options."+type),buttons.push({label:this.getI18n(i18n+".add_button","label",{type:type_name}),icon:this.getIcon(this.getI18n(i18n+".add_button","icon"),!0),title:this.getI18n(i18n+".add_button","title",{type:type_name}),click:()=>this.$elements.list.editableList("addItem",{type:type})}));return buttons}async init(mainEditor){await super.init(mainEditor),await this.initList(DeconzOutputRuleEditor,this.node.output_rules)}refresh(){for(const rule of Object.values(this.items))rule.updatePayloadList()}}class DeconzCommandEditor extends DeconzListItemEditor{constructor(node,listEditor,container,options={}){super(node,listEditor,container,options=$.extend({},options)),this.containers={}}get lightKeys(){return["bri","sat","hue","ct","xy"]}get argKeys(){return["on","alert","effect","colorloopspeed","open","stop","lift","tilt","scene_mode","group","scene","scene_name","target","command","payload","delay","transitiontime","retryonerror","aftererror"]}get elements(){let keys=this.argKeys;keys.push("typedomain"),keys.push("outputButton"),keys.push("scene_picker"),keys.push("scene_picker_refresh");for(const lightKey of this.lightKeys)keys.push(lightKey),keys.push(lightKey+"_direction");let elements={};for(const key of keys)elements[key]=`node-input-output-rule-${this.uniqueId}-`+key;return elements}set value(command){}get value(){let value={arg:{}};value.type=this.$elements.typedomain.typedInput("type"),value.domain=this.$elements.typedomain.typedInput("value");for(const key of this.argKeys)this.$elements[key].parent(".form-row").is(":visible")&&(value.arg[key]={type:this.$elements[key].typedInput("type"),value:this.$elements[key].typedInput("value")});for(const key of this.lightKeys)this.$elements[key].parent(".form-row").is(":visible")&&(value.arg[key]={direction:this.$elements[key+"_direction"].typedInput("type"),type:this.$elements[key].typedInput("type"),value:this.$elements[key].typedInput("value")});return value}get defaultCommand(){return{type:"deconz_state",domain:"lights",target:"state",arg:{on:{type:"keep"},bri:{direction:"set",type:"num"},sat:{direction:"set",type:"num"},hue:{direction:"set",type:"num"},ct:{direction:"set",type:"num"},xy:{direction:"set",type:"num"},alert:{type:"str"},effect:{type:"str"},colorloopspeed:{type:"num"},transitiontime:{type:"num"},command:{type:"str",value:"on"},payload:{type:"msg",value:"payload"},delay:{type:"num",value:2e3},target:{type:"state"},group:{type:"num"},scene_mode:{type:"single"},scene_call:{type:"num"},scene_name:{type:"str"},retryonerror:{type:"num",value:0},aftererror:{type:"continue"}}}}async init(command,index){this._index=index,command=$.extend(!0,this.defaultCommand,command),await this.generateTypeDomainField(this.container,{type:command.type,value:command.domain}),this.containers.light=$("<div>").appendTo(this.container),await this.generateLightOnField(this.containers.light,command.arg.on);for(const lightType of["bri","sat","hue","ct","xy"])await this.generateLightColorField(this.containers.light,lightType,command.arg[lightType]),"bri"===lightType&&await this.generateHR(this.containers.light);await this.generateHR(this.containers.light),await this.generateLightAlertField(this.containers.light,command.arg.alert),await this.generateLightEffectField(this.containers.light,command.arg.effect),await this.generateLightColorLoopSpeedField(this.containers.light,command.arg.colorloopspeed),this.containers.windows_cover=$("<div>").appendTo(this.container),await this.generateCoverOpenField(this.containers.windows_cover,command.arg.open),await this.generateCoverStopField(this.containers.windows_cover,command.arg.stop),await this.generateCoverLiftField(this.containers.windows_cover,command.arg.lift),await this.generateCoverTiltField(this.containers.windows_cover,command.arg.tilt),this.containers.scene_call=$("<div>").appendTo(this.container),await this.generateSceneModeField(this.containers.scene_call,command.arg.scene_mode),this.containers.scene_call_single=$("<div>").appendTo(this.containers.scene_call),await this.generateScenePickerField(this.containers.scene_call_single,command.arg.group+"."+command.arg.scene),await this.generateSceneGroupField(this.containers.scene_call_single,command.arg.group),await this.generateSceneSceneField(this.containers.scene_call_single,command.arg.scene),this.containers.scene_call_dynamic=$("<div>").appendTo(this.containers.scene_call),await this.generateSceneNameField(this.containers.scene_call_dynamic,command.arg.scene_name),this.containers.target=$("<div>").appendTo(this.container),await this.generateTargetField(this.containers.target,command.arg.target),this.containers.command=$("<div>").appendTo(this.container),await this.generateCommandField(this.containers.command,command.arg.command),this.containers.payload=$("<div>").appendTo(this.container),await this.generatePayloadField(this.containers.payload,command.arg.payload),this.containers.pause=$("<div>").appendTo(this.container),await this.generatePauseDelayField(this.containers.pause,command.arg.delay),this.containers.transition=$("<div>").appendTo(this.container),await this.generateHR(this.containers.transition),await this.generateCommonTransitionTimeField(this.containers.transition,command.arg.transitiontime),this.containers.common=$("<div>").appendTo(this.container),await this.generateHR(this.containers.common),await this.generateCommonOnErrorRetryField(this.containers.common,command.arg.retryonerror),await this.generateCommonOnErrorAfterField(this.containers.common,command.arg.aftererror),await super.init(),await this.listEditor.mainEditor.isInitialized(),await this.updateShowHide(command.type,command.domain),await this.connect()}async connect(){await super.connect(),this.$elements.typedomain.on("change",(event,type,value)=>{this.updateShowHide(type,value)}),this.$elements.outputButton.on("click",async()=>{try{if("device"!==this.listEditor.mainEditor.subEditor.query.type)return void this.sendError("Error : The run command can only work with device list.",5e3);var name,value,command=this.value,devices=this.listEditor.mainEditor.subEditor.device.value;if(0===devices.length&&!("deconz_state"===command.type&&"scene_call"===command.domain||"custom"===command.type&&"scene_call"===command.arg.target.type))return void this.sendError("Error : No device selected.",5e3);if("pause"===command.type)return void this.sendError("Error : Can't test pause command.",5e3);for([name,value]of Object.entries(command.arg))if(["msg","flow","global","jsonata"].includes(value.type))return void this.sendError(`Error : Cant run this command because the value "${name}" is type "${value.type}".`,5e3);let myNotification=RED.notify("Sending request...",{type:"info"});await $.post(this.NRCD+"/testCommand",{controllerID:this.listEditor.mainEditor.serverNode.id,device_list:devices,command:command,delay:this.listEditor.mainEditor.subEditor.specific.value.delay}).catch((t,u)=>{this.sendError(400===t.status&&t.responseText?t.responseText:u.toString())});myNotification.close(),myNotification=RED.notify("Ok",{timeout:1e3,type:"success"})}catch(e){let myNotification=RED.notify(e.toString(),{type:"error",buttons:[{class:"error",click:()=>myNotification.close()}]})}});const updateSceneGroupSelection=()=>{let value=this.$elements.scene_picker.multipleSelect("getSelects");var parts;1===value.length&&(this.$elements.group.off("change",updateScenePickerSelection),this.$elements.scene.off("change",updateScenePickerSelection),parts=value[0].split("."),this.$elements.group.typedInput("type","num"),this.$elements.group.typedInput("value",parts[0]),this.$elements.scene.typedInput("type","num"),this.$elements.scene.typedInput("value",parts[1]),this.$elements.group.on("change",updateScenePickerSelection),this.$elements.scene.on("change",updateScenePickerSelection))},updateScenePickerSelection=()=>{this.$elements.scene_picker.off("change",updateSceneGroupSelection),this.$elements.scene_picker.multipleSelect("setSelects","num"!==this.$elements.group.typedInput("type")||"num"!==this.$elements.group.typedInput("type")?[]:[this.$elements.group.typedInput("value")+"."+this.$elements.scene.typedInput("value")]),this.$elements.scene_picker.on("change",updateSceneGroupSelection)};this.$elements.scene_mode.on("change",()=>{var isSingle="single"===this.$elements.scene_mode.typedInput("type");this.containers.scene_call_single.toggle(isSingle),this.containers.scene_call_dynamic.toggle(!isSingle)}),this.$elements.scene_picker.on("change",updateSceneGroupSelection),this.$elements.group.on("change",updateScenePickerSelection),this.$elements.scene.on("change",updateScenePickerSelection),this.$elements.scene_picker_refresh.on("click",()=>this.updateSceneList()),this.$elements.target.on("change",(event,type,value)=>{this.containers.command.toggle("scene_call"!==type)})}async updateShowHide(type,domain){let containers=[];switch(type){case"deconz_state":switch(domain){case"lights":case"groups":containers.push("light"),containers.push("transition");break;case"covers":containers.push("windows_cover");break;case"scene_call":containers.push("scene_call"),await this.updateSceneList(),containers.push("scene_call_"+("single"===this.$elements.scene_mode.typedInput("type")?"single":"dynamic"))}containers.push("common");break;case"homekit":this.$elements.payload.typedInput("types",["msg","flow","global","json","jsonata"]),containers.push("payload"),containers.push("transition"),containers.push("common");break;case"custom":containers.push("target"),"scene_call"!==this.$elements.target.typedInput("type")&&containers.push("command"),this.$elements.payload.typedInput("types",["msg","flow","global","str","num","bool","json","jsonata","date"]),containers.push("payload"),containers.push("transition"),containers.push("common");break;case"pause":containers.push("pause")}for(var[key,value]of Object.entries(this.containers))value.toggle(containers.includes(key))}async updateSceneList(){this.$elements.scene_picker.multipleSelect("disable"),this.$elements.scene_picker.children().remove();let queryEditor=this.listEditor.mainEditor.subEditor.query;if(void 0!==queryEditor){let params=queryEditor.xhrParams;params.queryType="json",params.query=JSON.stringify({match:{device_type:"groups"}});var groups=await queryEditor.getItems({refresh:!0,keepOnlyMatched:!0},params);if(void 0!==groups&&void 0!==groups.LightGroup){for(const group of groups.LightGroup){let groupHtml=$("<optgroup/>",{label:group.id+" - "+group.name});if(group.scenes&&0<group.scenes.length){for(const scene of group.scenes)$(`<option>${scene.id} - ${scene.name}</option>`).attr("value",group.id+"."+scene.id).appendTo(groupHtml);groupHtml.appendTo(this.$elements.scene_picker)}}this.$elements.scene_picker.multipleSelect("refresh").multipleSelect("enable"),this.$elements.scene_picker.multipleSelect("setSelects","num"!==this.$elements.group.typedInput("type")||"num"!==this.$elements.group.typedInput("type")?[]:[this.$elements.group.typedInput("value")+"."+this.$elements.scene.typedInput("value")])}}}async generateTypeDomainField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type";await this.generateTypedInputField(container,{id:this.elements.typedomain,i18n:i18n,value:value,addDefaultTypes:!1,typedInput:{default:"deconz_state",types:[this.generateTypedInputType(i18n,"deconz_state",{subOptions:["lights","covers","groups","scene_call"]}),this.generateTypedInputType(i18n,"homekit",{hasValue:!1}),this.generateTypedInputType(i18n,"custom",{hasValue:!1}),this.generateTypedInputType(i18n,"pause",{hasValue:!1})]}})}async generateLightOnField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields.on";await this.generateTypedInputField(container,{id:this.elements.on,i18n:i18n,value:value,typedInput:{default:"keep",types:[this.generateTypedInputType(i18n,"keep",{hasValue:!1}),this.generateTypedInputType(i18n,"set",{subOptions:["true","false"]}),this.generateTypedInputType(i18n,"toggle",{hasValue:!1})]}})}async generateLightColorField(container,fieldName,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields";let fieldFormat=["num"],directionsFormat=[this.generateTypedInputType(i18n+".lightFields","set",{hasValue:!1})];switch(fieldName){case"bri":fieldFormat.push("str"),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","inc",{hasValue:!1})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","dec",{hasValue:!1})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","detect_from_value",{hasValue:!1}));break;case"ct":fieldFormat.push("str"),fieldFormat.push(this.generateTypedInputType(i18n+".ct","deconz",{subOptions:["cold","white","warm"]})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","inc",{hasValue:!1})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","dec",{hasValue:!1})),directionsFormat.push(this.generateTypedInputType(i18n+".lightFields","detect_from_value",{hasValue:!1}));break;case"xy":fieldFormat=["json"]}await this.generateDoubleTypedInputField(container,{id:this.elements[fieldName+"_direction"],i18n:i18n+"."+fieldName,addDefaultTypes:!1,value:{type:value.direction},typedInput:{types:directionsFormat}},{id:this.elements[fieldName],value:{type:value.type,value:["xy"===fieldName&&void 0===value.value?"[]":value.value]},typedInput:{types:fieldFormat}})}async generateLightAlertField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields.alert";await this.generateTypedInputField(container,{id:this.elements.alert,i18n:i18n,value:value,typedInput:{types:["str",this.generateTypedInputType(i18n,"deconz",{subOptions:["none","select","lselect"]})]}})}async generateLightEffectField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields.effect";await this.generateTypedInputField(container,{id:this.elements.effect,i18n:i18n,value:value,typedInput:{types:["str",this.generateTypedInputType(i18n,"deconz",{subOptions:["none","colorloop"]})]}})}async generateLightColorLoopSpeedField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.lights.fields.colorloopspeed";await this.generateTypedInputField(container,{id:this.elements.colorloopspeed,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateCoverOpenField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.covers.fields.open";await this.generateTypedInputField(container,{id:this.elements.open,i18n:i18n,value:value,typedInput:{types:[this.generateTypedInputType(i18n,"keep",{hasValue:!1}),this.generateTypedInputType(i18n,"set",{subOptions:["true","false"]}),this.generateTypedInputType(i18n,"toggle",{hasValue:!1})]}})}async generateCoverStopField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.covers.fields.stop";await this.generateTypedInputField(container,{id:this.elements.stop,i18n:i18n,value:value,typedInput:{types:[this.generateTypedInputType(i18n,"keep",{hasValue:!1}),this.generateTypedInputType(i18n,"set",{subOptions:["true","false"]})]}})}async generateCoverLiftField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.covers.fields.lift";await this.generateTypedInputField(container,{id:this.elements.lift,i18n:i18n,value:value,typedInput:{types:["num","str",this.generateTypedInputType(i18n,"stop",{hasValue:!1})]}})}async generateCoverTiltField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.covers.fields.tilt";await this.generateTypedInputField(container,{id:this.elements.tilt,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateSceneModeField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.mode";await this.generateTypedInputField(container,{id:this.elements.scene_mode,i18n:i18n,value:value,addDefaultTypes:!1,typedInput:{types:[this.generateTypedInputType(i18n,"single",{hasValue:!1}),this.generateTypedInputType(i18n,"dynamic",{hasValue:!1})]}})}async generateScenePickerField(container,value=0){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.picker";let list=await this.generateSimpleListField(container,{id:this.elements.scene_picker,i18n:i18n});list.addClass("multiple-select"),list.multipleSelect({maxHeight:300,dropWidth:300,width:200,numberDisplayed:1,single:!0,singleRadio:!0,hideOptgroupCheckboxes:!0,showClear:!0,selectAll:!1,filter:!0,filterPlaceholder:this.getI18n(i18n,"filter_place_holder"),placeholder:RED._(this.NRCD+"/server:editor.multiselect.none_selected"),container:".node-input-output-container-row"});container=$("<a/>",{id:this.elements.scene_picker_refresh,class:"red-ui-button",style:"margin-left:10px;"});this.createIconElement(this.getIcon("refresh"),container),list.closest(".form-row").append(container)}async generateSceneGroupField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.group";await this.generateTypedInputField(container,{id:this.elements.group,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateSceneSceneField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.scene";await this.generateTypedInputField(container,{id:this.elements.scene,i18n:i18n,value:value,typedInput:{types:["num","str",this.generateTypedInputType(i18n,"deconz",{subOptions:["next","prev"]})]}})}async generateSceneNameField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.scene_call.fields.scene_name";await this.generateTypedInputField(container,{id:this.elements.scene_name,i18n:i18n,value:value,typedInput:{types:["str","re"]}})}async generateTargetField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.common.fields.target";await this.generateTypedInputField(container,{id:this.elements.target,i18n:i18n,value:value,typedInput:{types:[this.generateTypedInputType(i18n,"attribute",{hasValue:!1}),this.generateTypedInputType(i18n,"state",{hasValue:!1}),this.generateTypedInputType(i18n,"config",{hasValue:!1}),this.generateTypedInputType(i18n,"scene_call",{hasValue:!1})]}})}async generateCommandField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.common.fields.command";await this.generateTypedInputField(container,{id:this.elements.command,i18n:i18n,value:value,typedInput:{types:["str",this.generateTypedInputType(i18n,"object",{hasValue:!1})]}})}async generatePayloadField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.common.fields.payload";await this.generateTypedInputField(container,{id:this.elements.payload,i18n:i18n,value:value,addDefaultTypes:!1,typedInput:{types:["msg","flow","global","str","num","bool","json","jsonata","date"]}})}async generatePauseDelayField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.pause.fields.delay";await this.generateTypedInputField(container,{id:this.elements.delay,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateCommonTransitionTimeField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.common.fields.transitiontime";await this.generateTypedInputField(container,{id:this.elements.transitiontime,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateCommonOnErrorRetryField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.common.fields.retryonerror";await this.generateTypedInputField(container,{id:this.elements.retryonerror,i18n:i18n,value:value,typedInput:{types:["num"]}})}async generateCommonOnErrorAfterField(container,value={}){var i18n=this.NRCD+"/server:editor.inputs.commands.type.options.deconz_state.options.common.fields.aftererror";await this.generateTypedInputField(container,{id:this.elements.aftererror,i18n:i18n,value:value,typedInput:{types:[this.generateTypedInputType(i18n,"continue",{hasValue:!1}),this.generateTypedInputType(i18n,"stop",{hasValue:!1})]}})}}class DeconzCommandListEditor extends DeconzListItemListEditor{get elements(){return{list:"node-input-output-container"}}get listType(){return"command"}get buttons(){let buttons=[];var type_name,i18n=this.NRCD+"/server:editor.inputs.commands.type";for(const[type,enabled]of Object.entries(this.options.type))enabled&&(type_name=this.getI18n(i18n+".options."+type,"label"),buttons.push({label:this.getI18n(i18n+".add_button","label",{type:type_name}),icon:this.getIcon(this.getI18n(i18n+".add_button","icon"),!0),title:this.getI18n(i18n+".add_button","title",{type:type_name}),click:()=>this.$elements.list.editableList("addItem",{type:type})}));return buttons}async init(mainEditor){await super.init(mainEditor),await this.initList(DeconzCommandEditor,this.node.commands)}}
//# sourceMappingURL=deconz-editor.js.map

@@ -137,3 +137,2 @@ const dotProp = require("dot-prop");

.needEventMeta('state.buttonevent')
//.needDeviceMeta({type:['Window covering controller', 'Window covering device']})
.to((rawEvent, deviceMeta) => {

@@ -183,2 +182,5 @@ switch (dotProp.get(rawEvent, 'state.buttonevent') % 1000) {

.services('Contact Sensor')
.needDeviceMeta((deviceMeta) => {
return !['Window covering controller', 'Window covering device'].includes(deviceMeta.type);
})
.needEventMeta((rawEvent, deviceMeta) =>

@@ -336,3 +338,6 @@ dotProp.has(rawEvent, 'state.open') ||

HKF.On = directMap(['to', 'from'], 'state.on')
.services(['Lightbulb', 'Outlet']);
.services(['Lightbulb', 'Outlet'])
.needDeviceMeta((deviceMeta) => {
return !['Window covering controller', 'Window covering device'].includes(deviceMeta.type);
});
HKF.Brightness = new Attribute()

@@ -396,2 +401,3 @@ .services('Lightbulb')

.services('Window Covering')
.needDeviceMeta({type: ['Window covering controller', 'Window covering device']})
.needEventMeta('state.tilt')

@@ -406,2 +412,6 @@ .to((rawEvent, deviceMeta) =>

HKF.TargetVerticalTiltAngle = HKF.CurrentHorizontalTiltAngle;
HKF.PositionState = new Attribute()
.services('Window Covering')
.needDeviceMeta({type: ['Window covering controller', 'Window covering device']})
.to((rawEvent, deviceMeta) => 2); // Stopped
//#endregion

@@ -408,0 +418,0 @@ //#region Battery

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc