node-red-contrib-padavan 2.1.0 → 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,23 +9,29 @@ 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
- - `msg.payload`: The result of the operation.
19
- - For `status`, the object is enhanced with:
20
- - `uptimeStr` (`string`): A formatted uptime string (e.g., "5d 12h 30m").
21
- - `cpuPercent` (`number` | `null`): Calculated CPU usage.
22
- - `ramPercent` (`number`): Calculated RAM usage.
23
- - For `scan`, an array of networks.
24
- - For `doctor`, an analysis object.
25
- - For `log`, a string.
27
+ - `msg.payload`: The raw result object from the library.
28
+ - For the `status` action, the message is also enriched with properties:
29
+ - `msg.uptimeStr` (`string`): A formatted uptime string (e.g., "5d 12h 30m").
30
+ - `msg.cpuPercent` (`number` | `null`): Calculated CPU usage.
31
+ - `msg.ramPercent` (`number`): Calculated RAM usage.
26
32
 
27
33
  ### Details
28
34
 
29
- The **Wi-Fi Doctor** action analyzes all visible networks, calculates
30
- interference scores, and suggests the optimal channel for your router.
35
+ For an accurate `cpuPercent`, the `status` action should be triggered
36
+ regularly (e.g., every 5-10 seconds).
31
37
  </script>
@@ -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,24 +9,30 @@
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
- - `msg.payload`: Результат операции.
19
- - Для `status`, объект дополняется полями:
20
- - `uptimeStr` (`string`): Отформатированная строка времени работы
21
- (например, "5d 12h 30m").
22
- - `cpuPercent` (`number` | `null`): Рассчитанная загрузка CPU.
23
- - `ramPercent` (`number`): Рассчитанное использование RAM.
24
- - Для `scan` — массив сетей.
25
- - для `doctor` — объект с анализом.
26
- - Для `log` — строка.
27
+ - `msg.payload`: "Сырой" объект с результатом от библиотеки.
28
+ - Для действия `status`, сообщение также дополняется свойствами:
29
+ - `msg.uptimeStr` (`string`): Отформатированная строка времени работы
30
+ (например, "5d 12h 30m").
31
+ - `msg.cpuPercent` (`number` | `null`): Рассчитанная загрузка CPU.
32
+ - `msg.ramPercent` (`number`): Рассчитанное использование RAM.
27
33
 
28
34
  ### Детали
29
35
 
30
- Действие **Wi-Fi Доктор** анализирует все видимые сети, рассчитывает уровень
31
- интерференции и предлагает оптимальный канал для вашего роутера.
36
+ Для корректного расчета `cpuPercent` действие `status` необходимо
37
+ вызывать регулярно (например, каждые 5-10 секунд).
32
38
  </script>
@@ -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":{let G=Date.now();if(h=await this.client.getStatus(),h.ram?.total>0)h.ramPercent=Math.round(h.ram.used/h.ram.total*100);if(h.uptime)h.uptimeStr=O(h.uptime);if(h.cpu){if(h.cpuPercent=null,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)h.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.0",
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.0"
30
+ "padavan": "2.2.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/bun": "^1.2.17",