node-red-contrib-padavan 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,17 +9,22 @@ Performs system diagnostics and control operations.
9
9
  - `reboot`: Reboot the router.
10
10
  - `scan`: Scan for Wi-Fi networks (Site Survey).
11
11
  - `doctor`: Analyze Wi-Fi environment and recommend the best channel.
12
+ - `call`: Execute a low-level system action.
12
13
  - **Band** (`msg.band`):
13
14
  - Used for `scan` and `doctor`.
14
15
  - Values: `'2.4'` or `'5'`.
16
+ - **System Action** (`msg.action`):
17
+ - Used for `call`.
18
+ - Values: `Reboot`, `ClearLog`, `FreeMemory`, `CommitFlash`, etc.
19
+ - `msg.payload` (for `call` action):
20
+ - If the action is `SystemCmd` and payload is a **string**,
21
+ it is executed as a console command.
22
+ - If payload is an **object**, it is sent as POST parameters
23
+ (e.g. `{ action: 'genkey' }` for `wg_action`).
15
24
 
16
25
  ### Outputs
17
26
 
18
27
  - `msg.payload`: The raw result object from the library.
19
- - For `status`: A JSON object with raw system data.
20
- - For `scan`: An array of networks.
21
- - For `doctor`: An analysis object.
22
- - For `log`: A string.
23
28
  - For the `status` action, the message is also enriched with properties:
24
29
  - `msg.uptimeStr` (`string`): A formatted uptime string (e.g., "5d 12h 30m").
25
30
  - `msg.cpuPercent` (`number` | `null`): Calculated CPU usage.
@@ -4,7 +4,8 @@
4
4
  "settings": "Config",
5
5
  "name": "Name",
6
6
  "topic": "Action",
7
- "band": "Band"
7
+ "band": "Band",
8
+ "action": "System Action"
8
9
  },
9
10
  "placeholder": {
10
11
  "name": "System"
@@ -14,7 +15,8 @@
14
15
  "log": "Get Log",
15
16
  "reboot": "Reboot",
16
17
  "scan": "Scan Wi-Fi",
17
- "doctor": "Wi-Fi Doctor"
18
+ "doctor": "Wi-Fi Doctor",
19
+ "call": "Execute Command"
18
20
  }
19
21
  }
20
22
  }
@@ -9,17 +9,22 @@
9
9
  - `reboot`: Перезагрузить роутер.
10
10
  - `scan`: Сканировать эфир Wi-Fi (Site Survey).
11
11
  - `doctor`: Анализ Wi-Fi окружения и подбор лучшего канала.
12
+ - `call`: Выполнить низкоуровневую системную команду.
12
13
  - **Диапазон** (`msg.band`):
13
14
  - Используется для `scan` и `doctor`.
14
15
  - Значения: `'2.4'` или `'5'`.
16
+ - **Системное действие** (`msg.action`):
17
+ - Используется для `call`.
18
+ - Значения: `Reboot`, `ClearLog`, `FreeMemory`, `CommitFlash` и др.
19
+ - `msg.payload` (для действия `call`):
20
+ - Если выбрано `SystemCmd` и payload — **строка**,
21
+ она выполняется как консольная команда.
22
+ - Если payload — **объект**, он отправляется как параметры POST запроса
23
+ (например `{ action: 'genkey' }` для `wg_action`).
15
24
 
16
25
  ### Выходы
17
26
 
18
27
  - `msg.payload`: "Сырой" объект с результатом от библиотеки.
19
- - Для `status`: JSON-объект с системными данными.
20
- - Для `scan`: Массив сетей.
21
- - Для `doctor`: Объект с анализом.
22
- - Для `log`: Строка.
23
28
  - Для действия `status`, сообщение также дополняется свойствами:
24
29
  - `msg.uptimeStr` (`string`): Отформатированная строка времени работы
25
30
  (например, "5d 12h 30m").
@@ -4,7 +4,8 @@
4
4
  "settings": "Конфигурация",
5
5
  "name": "Имя",
6
6
  "topic": "Действие",
7
- "band": "Диапазон"
7
+ "band": "Диапазон",
8
+ "action": "Системное действие"
8
9
  },
9
10
  "placeholder": {
10
11
  "name": "Система"
@@ -14,7 +15,8 @@
14
15
  "log": "Получить лог",
15
16
  "reboot": "Перезагрузить",
16
17
  "scan": "Сканировать Wi-Fi",
17
- "doctor": "Wi-Fi Доктор"
18
+ "doctor": "Wi-Fi Доктор",
19
+ "call": "Выполнить команду"
18
20
  }
19
21
  }
20
22
  }
@@ -1,5 +1,5 @@
1
1
  <script type="text/javascript">
2
- var ACTION_MODE=[" Apply "," Restart "," Reboot "," Shutdown "," Add "," Del "," ClearLog "," SystemCmd "," CommitFlash "," RestoreNVRAM "," RestoreStorage "," FreeMemory "," NTPSyncNow "," CreateCertHTTPS "," CheckCertHTTPS "," CreateCertOVPNS "," ExportConfOVPNC "," ExportWGConf "," wg_action ","Update"],SERVICE_ID=["General","LANHostConfig","IPConnection","PPPConnection","FirewallConfig","RouterConfig","WLANConfig11a","WLANConfig11b","WLANAuthentication11a","WLANAuthentication11b","Storage","IP6Connection","Layer3Forwarding"],GROUP_ID=["ManualDHCPList","VSList","GWStatic","UrlList","MFList","ACLList","rt_ACLList","RBRList","rt_RBRList","LWFilterList","VPNSACLList"];function createTypedInputOptions(list){return list.map((value)=>({value,label:value.trim()}))}var RED=window.RED;RED.nodes.registerType("padavan-params",{category:"Padavan",defaults:{settings:{value:"",type:"padavan-config",required:!0},name:{value:""},topic:{value:"topic"},topicType:{value:"msg"},payload:{value:"payload"},payloadType:{value:"msg"},page:{value:""},pageType:{value:"str"},sid:{value:""},sidType:{value:"str"},group:{value:""},groupType:{value:"str"},script:{value:""},scriptType:{value:"str"},action:{value:" Apply "},actionType:{value:"str"}},icon:"font-awesome/fa-cogs",inputs:1,outputs:1,color:"#49AFCD",paletteLabel:"Params",label:function(){return this.name||"Params"},oneditprepare:function(){$("#node-input-topic").typedInput({types:["msg",{value:"action",options:[{value:"list",label:this._("params.action.list")},{value:"get",label:this._("params.action.get")},{value:"set",label:this._("params.action.set")}]}],typeField:"#node-input-topicType"}),$("#node-input-payload").typedInput({types:["msg","json","str","jsonata"],typeField:"#node-input-payloadType"}),$("#node-input-page").typedInput({types:["str","msg"],typeField:"#node-input-pageType"}),$("#node-input-sid").typedInput({types:["str","json","msg",{value:"sid",options:createTypedInputOptions(SERVICE_ID)}],typeField:"#node-input-sidType"}),$("#node-input-group").typedInput({types:["str","msg",{value:"group",options:createTypedInputOptions(GROUP_ID)}],typeField:"#node-input-groupType"}),$("#node-input-script").typedInput({types:["str","msg"],typeField:"#node-input-scriptType"}),$("#node-input-action").typedInput({types:[{value:"mode",options:createTypedInputOptions(ACTION_MODE)},"str","msg"],typeField:"#node-input-actionType"}),$("#node-input-topic").on("change",function(){let type=$("#node-input-topicType").val(),value=$("#node-input-topic").val(),isSet=type==="action"&&value==="set"||type==="msg",isList=type==="action"&&value==="list";$("#node-row-payload").toggle(!isList),$("#node-row-page").toggle(!isList),$("#node-row-sid").toggle(isSet),$("#node-row-group").toggle(isSet),$("#node-row-script").toggle(isSet),$("#node-row-action").toggle(isSet)})}});
2
+ var CONFIG_ACTION={APPLY:" Apply ",RESTART:" Restart ",ADD:" Add ",DEL:" Del ",UPDATE:"Update"},SERVICE_ID=["General","LANHostConfig","IPConnection","PPPConnection","FirewallConfig","RouterConfig","WLANConfig11a","WLANConfig11b","WLANAuthentication11a","WLANAuthentication11b","Storage","IP6Connection","Layer3Forwarding"],GROUP_ID=["ManualDHCPList","VSList","GWStatic","UrlList","MFList","ACLList","rt_ACLList","RBRList","rt_RBRList","LWFilterList","VPNSACLList"];function createTypedInputOptions(list){return list.map((value)=>({value,label:value.trim()}))}var RED=window.RED;RED.nodes.registerType("padavan-params",{category:"Padavan",defaults:{settings:{value:"",type:"padavan-config",required:!0},name:{value:""},topic:{value:"topic"},topicType:{value:"msg"},payload:{value:"payload"},payloadType:{value:"msg"},page:{value:""},pageType:{value:"str"},sid:{value:""},sidType:{value:"str"},group:{value:""},groupType:{value:"str"},script:{value:""},scriptType:{value:"str"},action:{value:CONFIG_ACTION.APPLY},actionType:{value:"mode"}},icon:"font-awesome/fa-cogs",inputs:1,outputs:1,color:"#49AFCD",paletteLabel:"Params",label:function(){return this.name||"Params"},oneditprepare:function(){$("#node-input-topic").typedInput({types:["msg",{value:"action",options:[{value:"list",label:this._("params.action.list")},{value:"get",label:this._("params.action.get")},{value:"set",label:this._("params.action.set")}]}],typeField:"#node-input-topicType"}).on("change",function(){let type=$("#node-input-topicType").val(),value=$("#node-input-topic").val(),isSet=type==="action"&&value==="set"||type==="msg",isList=type==="action"&&value==="list";$("#node-row-payload").toggle(!isList),$("#node-row-page").toggle(!isList),$("#node-row-sid").toggle(isSet),$("#node-row-group").toggle(isSet),$("#node-row-script").toggle(isSet),$("#node-row-action").toggle(isSet)}),$("#node-input-payload").typedInput({types:["msg","json","str","jsonata"],typeField:"#node-input-payloadType"}),$("#node-input-page").typedInput({types:["str","msg"],typeField:"#node-input-pageType"}),$("#node-input-sid").typedInput({types:["str","json","msg",{value:"sid",options:createTypedInputOptions(SERVICE_ID)}],typeField:"#node-input-sidType"}),$("#node-input-group").typedInput({types:["str","msg",{value:"group",options:createTypedInputOptions(GROUP_ID)}],typeField:"#node-input-groupType"}),$("#node-input-script").typedInput({types:["str","msg"],typeField:"#node-input-scriptType"}),$("#node-input-action").typedInput({types:[{value:"mode",options:createTypedInputOptions(Object.values(CONFIG_ACTION))},"str","msg"],typeField:"#node-input-actionType"})}});
3
3
  </script>
4
4
 
5
5
  <script type="text/html" data-template-name="padavan-params">
@@ -1,5 +1,5 @@
1
1
  <script type="text/javascript">
2
- var RED=window.RED;RED.nodes.registerType("padavan-system",{category:"Padavan",defaults:{settings:{value:"",type:"padavan-config",required:!0},name:{value:""},topic:{value:"topic"},topicType:{value:"msg"},band:{value:"2.4"},bandType:{value:"band"}},icon:"font-awesome/fa-server",inputs:1,outputs:1,color:"#49AFCD",paletteLabel:"System",label:function(){return this.name||"System"},oneditprepare:function(){$("#node-input-topic").typedInput({types:["msg",{value:"action",options:[{value:"status",label:this._("system.action.status")},{value:"log",label:this._("system.action.log")},{value:"reboot",label:this._("system.action.reboot")},{value:"scan",label:this._("system.action.scan")},{value:"doctor",label:this._("system.action.doctor")}]}],typeField:"#node-input-topicType"}).on("change",function(){let type=$("#node-input-topicType").val(),value=$("#node-input-topic").val(),showBand=type==="action"&&(value==="scan"||value==="doctor")||type==="msg";$("#node-input-band-row").toggle(showBand)}),$("#node-input-band").typedInput({types:[{value:"band",options:[{value:"2.4",label:"2.4 GHz"},{value:"5",label:"5 GHz"}]},"msg"],typeField:"#node-input-bandType"})}});
2
+ var SYSTEM_ACTION={REBOOT:" Reboot ",SHUTDOWN:" Shutdown ",CLEAR_LOG:" ClearLog ",SYSTEM_CMD:" SystemCmd ",COMMIT_FLASH:" CommitFlash ",RESTORE_NVRAM:" RestoreNVRAM ",RESTORE_STORAGE:" RestoreStorage ",FREE_MEMORY:" FreeMemory ",NTP_SYNC_NOW:" NTPSyncNow ",CREATE_CERT_HTTPS:" CreateCertHTTPS ",CHECK_CERT_HTTPS:" CheckCertHTTPS ",CREATE_CERT_OVPNS:" CreateCertOVPNS ",EXPORT_CONF_OVPNC:" ExportConfOVPNC ",EXPORT_WG_CONF:" ExportWGConf ",WG_ACTION:" wg_action "};var WIFI_BANDS=["2.4","5"];function createTypedInputOptions(list){return list.map((value)=>({value,label:value.trim()}))}var RED=window.RED;RED.nodes.registerType("padavan-system",{category:"Padavan",defaults:{settings:{value:"",type:"padavan-config",required:!0},name:{value:""},topic:{value:"topic"},topicType:{value:"msg"},band:{value:WIFI_BANDS[0]},bandType:{value:"band"},action:{value:SYSTEM_ACTION.SYSTEM_CMD},actionType:{value:"mode"}},icon:"font-awesome/fa-server",inputs:1,outputs:1,color:"#49AFCD",paletteLabel:"System",label:function(){return this.name||"System"},oneditprepare:function(){$("#node-input-topic").typedInput({types:["msg",{value:"action",options:[{value:"status",label:this._("system.action.status")},{value:"log",label:this._("system.action.log")},{value:"reboot",label:this._("system.action.reboot")},{value:"scan",label:this._("system.action.scan")},{value:"doctor",label:this._("system.action.doctor")},{value:"call",label:this._("system.action.call")}]}],typeField:"#node-input-topicType"}).on("change",function(){let type=$("#node-input-topicType").val(),value=$("#node-input-topic").val(),showBand=type==="action"&&(value==="scan"||value==="doctor")||type==="msg",showAction=type==="action"&&value==="call"||type==="msg";$("#node-input-band-row").toggle(showBand),$("#node-input-action-row").toggle(showAction)}),$("#node-input-band").typedInput({types:[{value:"band",options:WIFI_BANDS.map((band)=>({value:band,label:`${band} GHz`}))},"msg"],typeField:"#node-input-bandType"}),$("#node-input-action").typedInput({types:[{value:"mode",options:createTypedInputOptions(Object.values(SYSTEM_ACTION))},"str","msg"],typeField:"#node-input-actionType"})}});
3
3
  </script>
4
4
 
5
5
  <script type="text/html" data-template-name="padavan-system">
@@ -21,4 +21,9 @@ var RED=window.RED;RED.nodes.registerType("padavan-system",{category:"Padavan",d
21
21
  <input type="text" id="node-input-band" style="width: 70%;" />
22
22
  <input type="hidden" id="node-input-bandType" />
23
23
  </div>
24
+ <div class="form-row" id="node-input-action-row">
25
+ <label for="node-input-action"><i class="fa fa-terminal"></i> <span data-i18n="system.label.action"></span></label>
26
+ <input type="text" id="node-input-action" style="width: 70%;" />
27
+ <input type="hidden" id="node-input-actionType" />
28
+ </div>
24
29
  </script>
@@ -1 +1 @@
1
- import{formatUptime as O}from"padavan/utils/formatting.js";function L(k,z,q,x,F){return new Promise((h,G)=>{if(q==="jsonata")k.util.evaluateNodeProperty(z,q,x,F,(B,H)=>{if(B)G(B);else h(H)});else try{let B=k.util.evaluateNodeProperty(z,q,x,F);h(B)}catch(B){G(B)}})}async function J(k,z,q,x){let F=x.map(({value:h,type:G})=>L(k,h,G,z,q));return Promise.all(F)}class K{#z;#h;#q;#x;#k=null;constructor(k,z,q){this.#h=k,this.#q=z,this.#z=q;let x=q.nodes.getNode(z.settings);if(x)this.#x=x.instance;else this.#h.warn("Config node not found or configured.");this.#h.on("input",this.#B.bind(this)),this.#h.on("close",()=>{this.#k=null})}get client(){if(!this.#x)throw Error("Client is not initialized. Check configuration.");return this.#x.client}async#B(k,z,q){try{let[x,F]=await J(this.#z,this.#h,k,[{value:this.#q.topic,type:this.#q.topicType},{value:this.#q.band,type:this.#q.bandType}]);this.#h.status({fill:"blue",shape:"dot",text:`Running ${x}...`});let h;switch(x){case"status":{if(h=await this.client.getStatus(),h.uptime)k.uptimeStr=O(h.uptime);if(h.ram?.total>0)k.ramPercent=Math.round(h.ram.used/h.ram.total*100);if(h.cpu){k.cpuPercent=null;let G=Date.now();if(this.#k&&G-this.#k.timestamp<30000){let B=h.cpu.busy-this.#k.state.busy,H=h.cpu.total-this.#k.state.total;if(H>0&&B>=0)k.cpuPercent=Math.round(B/H*100)}this.#k={state:h.cpu,timestamp:G}}break}case"log":{h=await this.client.getLog();break}case"reboot":{h=await this.client.startReboot();break}case"scan":{h=await this.client.startScan(F);break}case"doctor":{h=await this.client.getBestChannel(F);break}default:throw Error(`Invalid topic: "${x}".`)}if(h!==void 0){if(!k.topic)k.topic=x;k.payload=h,z(k)}this.#h.status({}),q()}catch(x){this.#h.status({fill:"red",shape:"ring",text:"Error"}),q(x)}}}function Q(k){k.nodes.registerType("padavan-system",function(z){k.nodes.createNode(this,z);let q=this;q.instance=new K(q,z,k)})}export{Q as default,K as SystemNode};
1
+ import{formatUptime as Q}from"padavan/utils/formatting.js";function O(h,B,q,x,G){return new Promise((F,k)=>{if(q==="jsonata")h.util.evaluateNodeProperty(B,q,x,G,(z,H)=>{if(z)k(z);else F(H)});else try{let z=h.util.evaluateNodeProperty(B,q,x,G);F(z)}catch(z){k(z)}})}async function K(h,B,q,x){let G=x.map(({value:F,type:k})=>O(h,F,k,B,q));return Promise.all(G)}class L{#z;#h;#k;#x;#q=null;constructor(h,B,q){this.#h=h,this.#k=B,this.#z=q;let x=q.nodes.getNode(B.settings);if(x)this.#x=x.instance;else this.#h.warn("Config node not found or configured.");this.#h.on("input",this.#B.bind(this)),this.#h.on("close",()=>{this.#q=null})}get client(){if(!this.#x)throw Error("Client is not initialized. Check configuration.");return this.#x.client}async#B(h,B,q){try{let[x,G,F]=await K(this.#z,this.#h,h,[{value:this.#k.topic,type:this.#k.topicType},{value:this.#k.band,type:this.#k.bandType},{value:this.#k.action,type:this.#k.actionType}]);this.#h.status({fill:"blue",shape:"dot",text:`Running ${x}...`});let k;switch(x){case"status":{if(k=await this.client.getStatus(),k.uptime)h.uptimeStr=Q(k.uptime);if(k.ram?.total>0)h.ramPercent=Math.round(k.ram.used/k.ram.total*100);if(k.cpu){h.cpuPercent=null;let z=Date.now();if(this.#q&&z-this.#q.timestamp<30000){let H=k.cpu.busy-this.#q.state.busy,J=k.cpu.total-this.#q.state.total;if(J>0&&H>=0)h.cpuPercent=Math.round(H/J*100)}this.#q={state:k.cpu,timestamp:z}}break}case"log":{k=await this.client.getLog();break}case"reboot":{k=await this.client.startReboot();break}case"scan":{k=await this.client.startScan(G);break}case"doctor":{k=await this.client.getBestChannel(G);break}case"call":{if(!F)throw Error('System Action is required for "call" operation');let z={};if(typeof h.payload==="object"&&h.payload!==null)z=h.payload;else if(typeof h.payload==="string"&&F.trim()==="SystemCmd")z={SystemCmd:h.payload};k=await this.client.sendAction(F,z);break}default:throw Error(`Invalid topic: "${x}".`)}if(k!==void 0){if(!h.topic)h.topic=x;h.payload=k,B(h)}this.#h.status({}),q()}catch(x){this.#h.status({fill:"red",shape:"ring",text:"Error"}),q(x)}}}function V(h){h.nodes.registerType("padavan-system",function(B){h.nodes.createNode(this,B);let q=this;q.instance=new L(q,B,h)})}export{V as default,L as SystemNode};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-padavan",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Node-RED nodes for managing routers with Padavan firmware.",
@@ -27,7 +27,7 @@
27
27
  }
28
28
  },
29
29
  "dependencies": {
30
- "padavan": "2.1.1"
30
+ "padavan": "2.2.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/bun": "^1.2.17",