Skip to content

Commit 8e493db

Browse files
carlosz1986systemcrash
authored andcommitted
luci-base: poe and PSE details & configuration
Adds PoE/PSE configuration support for modern linux (PSE-PD). This change is based on the PSE-PD backport (from 6.17) and netifd|ubus changes. * Add getPSE() [receive all status information] and hasPSE() [has the device PSE hardware?] * Changes ACL permissions to query network.device status information * Add two new PoE icons (PoE active with link up + link down) for the port status page * Changes port status to show PoE information, next to link information and data transfer. * Add a new tab for PoE/PSE to the device configuration, which will only be displayed if the device supports PSE Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
1 parent 77f8596 commit 8e493db

File tree

7 files changed

+249
-25
lines changed

7 files changed

+249
-25
lines changed
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

modules/luci-base/htdocs/luci-static/resources/network.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3240,6 +3240,50 @@ Device = baseclass.extend(/** @lends LuCI.network.Device.prototype */ {
32403240
return (duplex != 'unknown') ? duplex : null;
32413241
},
32423242

3243+
/**
3244+
* Get the PSE (Power Sourcing Equipment / PoE) status of the device.
3245+
*
3246+
* @returns {Object|null}
3247+
* Returns an object containing PSE status information or null if
3248+
* PSE is not available on this device. The object may contain:
3249+
* - c33AdminState: "enabled" or "disabled" (C33 PoE admin state)
3250+
* - c33PowerStatus: "disabled", "searching", "delivering", "test", "fault", "otherfault"
3251+
* - c33PowerClass: Power class number (1-8)
3252+
* - c33ActualPower: Actual power consumption in mW
3253+
* - c33AvailablePowerLimit: Available power limit in mW
3254+
* - podlAdminState: "enabled" or "disabled" (PoDL admin state)
3255+
* - podlPowerStatus: "disabled", "searching", "delivering", "sleep", "idle", "error"
3256+
* - priority: Current priority level
3257+
* - priorityMax: Maximum priority level
3258+
*/
3259+
getPSE: function() {
3260+
const pse = this._devstate('pse');
3261+
if (!pse)
3262+
return null;
3263+
3264+
return {
3265+
c33AdminState: pse['c33-admin-state'] || null,
3266+
c33PowerStatus: pse['c33-power-status'] || null,
3267+
c33PowerClass: pse['c33-power-class'] || null,
3268+
c33ActualPower: pse['c33-actual-power'] || null,
3269+
c33AvailablePowerLimit: pse['c33-available-power-limit'] || null,
3270+
podlAdminState: pse['podl-admin-state'] || null,
3271+
podlPowerStatus: pse['podl-power-status'] || null,
3272+
priority: pse['priority'] || null,
3273+
priorityMax: pse['priority-max'] || null
3274+
};
3275+
},
3276+
3277+
/**
3278+
* Check if PSE (PoE) is available on this device.
3279+
*
3280+
* @returns {boolean}
3281+
* Returns true if PSE hardware is available on this device.
3282+
*/
3283+
hasPSE: function() {
3284+
return this._devstate('pse') != null;
3285+
},
3286+
32433287
/**
32443288
* Get the primary logical interface this device is assigned to.
32453289
*

modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"ubus": {
4040
"luci-rpc": [ "getBoardJSON", "getHostHints", "getNetworkDevices", "getWirelessDevices" ],
4141
"network": [ "get_proto_handlers" ],
42+
"network.device": [ "status" ],
4243
"network.interface": [ "dump" ]
4344
},
4445
"uci": [ "luci", "network", "wireless" ]

modules/luci-mod-network/htdocs/luci-static/resources/tools/network.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ return baseclass.extend({
440440
return s.taboption(tabName, optionClass, optionName, optionTitle, optionDescription);
441441
},
442442

443-
addDeviceOptions: function(s, dev, isNew, rtTables) {
443+
addDeviceOptions: function(s, dev, isNew, rtTables, hasPSE) {
444444
var parent_dev = dev ? dev.getParent() : null,
445445
devname = dev ? dev.getName() : null,
446446
o, ss;
@@ -449,6 +449,8 @@ return baseclass.extend({
449449
s.tab('devadvanced', _('Advanced device options'));
450450
s.tab('brport', _('Bridge port specific options'));
451451
s.tab('bridgevlan', _('Bridge VLAN filtering'));
452+
if (hasPSE)
453+
s.tab('devpse', _('PoE / PSE options'));
452454

453455
o = this.replaceOption(s, 'devgeneral', form.ListValue, 'type', _('Device type'),
454456
(!L.hasSystemFeature('bonding') && isNew ? '<a href="' + L.url("admin", "system", "package-manager", "?query=kmod-bonding") + '">'+
@@ -1139,6 +1141,34 @@ return baseclass.extend({
11391141
o.placeholder = dev ? dev._devstate('qlen') : '';
11401142
o.datatype = 'uinteger';
11411143

1144+
/* PSE / PoE options */
1145+
if (hasPSE) {
1146+
o = this.replaceOption(s, 'devpse', form.ListValue, 'pse', _('PoE (C33)'),
1147+
_('Power over Ethernet (IEEE 802.3af/at/bt) control for this port. Requires PSE hardware support.'));
1148+
o.value('', _('Default'));
1149+
o.value('1', _('Enabled'));
1150+
o.value('0', _('Disabled'));
1151+
1152+
o = this.replaceOption(s, 'devpse', form.ListValue, 'pse_podl', _('PoDL'),
1153+
_('Power over Data Lines (IEEE 802.3bu/cg) for single-pair Ethernet.'));
1154+
o.value('', _('Default'));
1155+
o.value('1', _('Enabled'));
1156+
o.value('0', _('Disabled'));
1157+
1158+
o = this.replaceOption(s, 'devpse', form.Value, 'pse_power_limit', _('Power limit (mW)'),
1159+
_('Maximum power budget for this port in milliwatts. Leave empty for default/maximum.'));
1160+
o.datatype = 'uinteger';
1161+
o.placeholder = _('auto');
1162+
o.rmempty = true;
1163+
1164+
o = this.replaceOption(s, 'devpse', form.ListValue, 'pse_priority', _('Port priority'),
1165+
_('Priority level for power allocation when total power budget is exceeded.'));
1166+
o.value('', _('Default'));
1167+
o.value('1', _('Critical'));
1168+
o.value('2', _('High'));
1169+
o.value('3', _('Low'));
1170+
}
1171+
11421172
o = this.replaceOption(s, 'devadvanced', cbiFlagTristate, 'promisc', _('Enable promiscuous mode'));
11431173
o.sysfs_default = (dev && dev.dev && dev.dev.flags) ? dev.dev.flags.promisc : null;
11441174

modules/luci-mod-network/htdocs/luci-static/resources/view/network/interfaces.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@
55
'require fs';
66
'require ui';
77
'require uci';
8+
'require rpc';
89
'require form';
910
'require network';
1011
'require firewall';
1112
'require tools.widgets as widgets';
1213
'require tools.network as nettools';
1314

15+
const callNetworkDeviceStatus = rpc.declare({
16+
object: 'network.device',
17+
method: 'status',
18+
params: [ 'name' ],
19+
expect: { '': {} }
20+
});
21+
1422
var isReadonlyView = !L.hasViewPermission() || null;
1523

1624
function count_changes(section_id) {
@@ -1570,10 +1578,20 @@ return view.extend({
15701578
};
15711579

15721580
s.addModalOptions = function(s) {
1573-
var isNew = (uci.get('network', s.section, 'name') == null),
1574-
dev = getDevice(s.section);
1575-
1576-
nettools.addDeviceOptions(s, dev, isNew, rtTables);
1581+
const isNew = (uci.get('network', s.section, 'name') == null),
1582+
dev = getDevice(s.section),
1583+
devName = dev ? dev.getName() : null;
1584+
1585+
/* Query PSE status from netifd to determine if device has PSE capability */
1586+
if (devName) {
1587+
return L.resolveDefault(callNetworkDeviceStatus(devName), {}).then((status) => {
1588+
const hasPSE = (status.pse != null);
1589+
nettools.addDeviceOptions(s, dev, isNew, rtTables, hasPSE);
1590+
});
1591+
} else {
1592+
nettools.addDeviceOptions(s, dev, isNew, rtTables, false);
1593+
return Promise.resolve();
1594+
}
15771595
};
15781596

15791597
s.handleModalCancel = function(map /*, ... */) {

0 commit comments

Comments
 (0)