Completed work on WebPowerSwitch support.

Ylian Saint-Hilaire committed Dec 14, 2021 at 14:42 UTC ad3dc5fbeda7cff8df6483693b68abf7c27c29de
5 files changed +125 -37
meshcentral.js
+2 -2
@@ -2203,9 +2203,9 @@ function CreateMeshCentralServer(config, args) {
2203 // nodeId: node identifier of format node/domain/nodeidhex
2204 // connectTime: time of connection, milliseconds elapsed since the UNIX epoch.
2205 // connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
2206 - // powerState: Value, 0 = Unknown, 1 = S0 power on, 2 = S1 Sleep, 3 = S2 Sleep, 4 = S3 Sleep, 5 = S4 Hibernate, 6 = S5 Soft-Off, 7 = Present
2206 + // powerState: Value, 0 = Unknown, 1 = S0 power on, 2 = S1 Sleep, 3 = S2 Sleep, 4 = S3 Sleep, 5 = S4 Hibernate, 6 = S5 Soft-Off, 7 = Present, 8 = Off
2207 //var connectTypeStrings = ['', 'MeshAgent', 'Intel AMT CIRA', '', 'Intel AMT local', '', '', '', 'Intel AMT Relay', '', '', '', '', '', '', '', 'MQTT'];
2208 - //var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present'];
2208 + //var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present', 'Off'];
2209 obj.SetConnectivityState = function (meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo) {
2210 //console.log('SetConnectivity for ' + nodeid.substring(0, 16) + ', Type: ' + connectTypeStrings[connectType] + ', Power: ' + powerStateStrings[powerState] + (serverid == null ? ('') : (', ServerId: ' + serverid)));
2211 if ((serverid == null) && (obj.multiServer != null)) { obj.multiServer.DispatchMessage({ action: 'SetConnectivityState', meshid: meshid, nodeid: nodeid, connectTime: connectTime, connectType: connectType, powerState: powerState, extraInfo: extraInfo }); }
meshipkvm.js
+20 -9
@@ -37,14 +37,19 @@ function CreateIPKVMManager(parent) {
37 const MESHRIGHT_ADMIN = 0xFFFFFFFF;
38
39 // Subscribe for mesh creation events
40 - parent.AddEventDispatch(['server-createmesh', 'server-deletemesh'], obj);
40 + parent.AddEventDispatch(['server-createmesh', 'server-deletemesh', 'devport-operation'], obj);
41 obj.HandleEvent = function (source, event, ids, id) {
42 - if ((event != null) && (event.action == 'createmesh') && (event.mtype == 4)) {
42 + if ((event == null) || (event.mtype != 4)) return;
43 + if (event.action == 'createmesh') {
44 // Start managing this new device group
45 startManagement(parent.webserver.meshes[event.meshid]);
45 - } else if ((event != null) && (event.action == 'deletemesh') && (event.mtype == 4)) {
46 + } else if (event.action == 'deletemesh') {
47 // Stop managing this device group
48 stopManagement(event.meshid);
49 + } else if ((event.action == 'turnon') || (event.action == 'turnoff')) {
50 + // Perform power operation
51 + const manager = obj.managedGroups[event.meshid];
52 + if ((manager) && (manager.powerOperation)) { manager.powerOperation(event); }
53 }
54 }
55
@@ -120,7 +125,7 @@ function CreateIPKVMManager(parent) {
125 const mesh = parent.webserver.meshes[sender.meshid];
126 if (nodes.length == 0) {
127 // The device does not exist, create it
123 - const device = { type: 'node', mtype: 4, _id: nodeid, icon: 1, meshid: sender.meshid, name: port.Name, rname: port.Name, domain: sender.domainid, portid: port.PortId, portnum: port.PortNumber };
128 + const device = { type: 'node', mtype: 4, _id: nodeid, icon: 4, meshid: sender.meshid, name: port.Name, rname: port.Name, domain: sender.domainid, portid: port.PortId, portnum: port.PortNumber, porttype: 'PDU' };
129 parent.db.Set(device);
130
131 // Event the new node
@@ -140,13 +145,13 @@ function CreateIPKVMManager(parent) {
145
146 // Set the connectivity state if needed
147 if (obj.managedPorts[nodeid] == null) {
143 - parent.SetConnectivityState(sender.meshid, nodeid, Date.now(), 1, port.State?1:6, null, null);
148 + parent.SetConnectivityState(sender.meshid, nodeid, Date.now(), 1, port.State ? 1 : 8, null, null);
149 obj.managedPorts[nodeid] = { name: port.Name, meshid: sender.meshid, portid: port.PortId, portType: port.PortType, portNo: port.PortIndex };
150 }
151 });
152 } else {
153 // Update connectivity state
149 - parent.SetConnectivityState(sender.meshid, nodeid, Date.now(), 1, port.State ? 1 : 6, null, null);
154 + parent.SetConnectivityState(sender.meshid, nodeid, Date.now(), 1, port.State ? 1 : 8, null, null);
155 }
156 } else if ((port.Status == 1) && (port.Class == 'KVM')) {
157 //console.log(port.PortNumber + ', ' + port.PortId + ', ' + port.Name + ', ' + port.Type + ', ' + ((port.StatAvailable == 0) ? 'Idle' : 'Connected'));
@@ -765,7 +770,7 @@ function CreateWebPowerSwitch(parent, hostname, port, username, password) {
770 obj.update();
771 }
772
768 - obj.update = function() {
773 + obj.update = function () {
774 obj.fetch('/restapi/relay/outlets/all;/=name,physical_state/', 'GET', null, null, function (sender, tag, rdata, res) {
775 if (res.statusCode == 207) {
776 var rdata2 = null;
@@ -780,7 +785,7 @@ function CreateWebPowerSwitch(parent, hostname, port, username, password) {
785 var portchanged = false;
786 if (obj.ports[i] == null) {
787 // Add the port
783 - obj.ports[i] = { PortNumber: i, PortId: 'p' + i, Name: portname, Status: 1, State: portstate, Class: 'PDU' };
788 + obj.ports[i] = { PortNumber: i + 1, PortId: 'p' + i, Name: portname, Status: 1, State: portstate, Class: 'PDU' };
789 portchanged = true;
790 } else {
791 // Update the port
@@ -800,9 +805,15 @@ function CreateWebPowerSwitch(parent, hostname, port, username, password) {
805 });
806 }
807
808 + obj.powerOperation = function (event) {
809 + if (typeof event.portnum != 'number') return;
810 + if (event.action == 'turnon') { setPowerState(event.portnum - 1, true); }
811 + else if (event.action == 'turnoff') { setPowerState(event.portnum - 1, false); }
812 + }
813 +
814 function setPowerState(port, state, func) {
815 obj.fetch('/restapi/relay/outlets/' + port + '/state/', 'PUT', 'value=' + state, null, function (sender, tag, rdata, res) {
805 - console.log('DATA:', res.statusCode, rdata.toString());
816 + if (res.statusCode == 204) { obj.update(); }
817 });
818 }
819
meshuser.js
+20 -2
@@ -2889,7 +2889,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2889
2890 // Get the node and the rights for this node
2891 parent.GetNodeWithRights(domain, user, nodeid, function (node, rights, visible) {
2892 - // Check we have the rights to delete this device
2892 + // Check we have the rights to wake this device
2893 if ((node == null) || (visible == false) || (rights & MESHRIGHT_WAKEDEVICE) == 0) {
2894 if (command.nodeids.length == 1) { try { ws.send(JSON.stringify({ action: 'wakedevices', responseid: command.responseid, result: 'Invalid nodeid' })); } catch (ex) { } }
2895 return;
@@ -2898,6 +2898,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2898 // If this device is connected on MQTT, send a wake action.
2899 if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.publish(node._id, 'powerAction', 'wake'); }
2900
2901 + // If this is a IP-KVM or Power Distribution Unit (PDU), dispatch an action event
2902 + if (node.mtype == 4) {
2903 + // Send out an event to perform turn off command on the port
2904 + //var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['devport-operation', 'server-users', user._id]);
2905 + var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'turnon', domain: domain.id, nolog: 1, portid: node.portid, porttype: node.porttype, portnum: node.portnum, meshid: node.meshid, mtype: node.mtype };
2906 + parent.parent.DispatchEvent([ 'devport-operation' ], obj, event);
2907 + return;
2908 + }
2909 +
2910 // Get the device interface information
2911 db.Get('if' + node._id, function (err, nodeifs) {
2912 if ((nodeifs != null) && (nodeifs.length == 1)) {
@@ -3054,11 +3063,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3063 if ((command.actiontype == 401) && common.validateInt(command.time, 1, 30000)) { routeCommandToNode({ action: 'msg', type: 'console', nodeid: node._id, value: 'vibrate ' + command.time }, MESHRIGHT_ADMIN, 0); }
3064 } else {
3065 // Check we have the rights to delete this device
3057 - if ((rights & MESHRIGHT_RESETOFF) == 0) return;
3066 + if ((rights & MESHRIGHT_RESETOFF) == 0) return;
3067
3068 // If this device is connected on MQTT, send a power action.
3069 if ((parent.parent.mqttbroker != null) && (command.actiontype >= 0) && (command.actiontype <= 4)) { parent.parent.mqttbroker.publish(node._id, 'powerAction', ['', '', 'poweroff', 'reset', 'sleep'][command.actiontype]); }
3070
3071 + // If this is a IP-KVM or Power Distribution Unit (PDU), dispatch an action event
3072 + if (node.mtype == 4) {
3073 + // Send out an event to perform turn off command on the port
3074 + //var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['devport-operation', 'server-users', user._id]);
3075 + var event = { etype: 'node', userid: user._id, username: user.name, nodeid: node._id, action: 'turnoff', domain: domain.id, nolog: 1, portid: node.portid, porttype: node.porttype, portnum: node.portnum, meshid: node.meshid, mtype: node.mtype };
3076 + parent.parent.DispatchEvent([ 'devport-operation' ], obj, event);
3077 + return;
3078 + }
3079 +
3080 if ((command.actiontype >= 300) && (command.actiontype < 400)) {
3081 if ((command.actiontype != 302) && (command.actiontype != 308) && (command.actiontype != 310)) return; // Invalid action type.
3082 // Intel AMT power command, actiontype: 2 = Power on, 8 = Power down, 10 = reset
views/default-mobile.handlebars
+37 -11
@@ -3214,15 +3214,15 @@
3214 return false;
3215 }
3216
3217 - var powerStatetable = ['', "Powered", "Sleep", "Sleep", "Sleep", "Hibernating", "Power off", "Present"];
3218 - var powerStateStrings = ['', "Powered", "Sleeping", "Sleeping", "Deep Sleep", "Hibernating", "Soft-Off", "Present"];
3219 - var powerStateStrings2 = ['', "Device is powered", "Device is in sleep state (S1)", "Device is in sleep state (S2)", "Device is in deep sleep state (S3)", "Device is hibernating (S4)", "Device is in soft-off state (S5)", "Device is present, but power state cannot be determined"];
3217 + var powerStatetable = ['', "Powered", "Sleep", "Sleep", "Sleep", "Hibernating", "Power off", "Present", "Off"];
3218 + var powerStateStrings = ['', "Powered", "Sleeping", "Sleeping", "Deep Sleep", "Hibernating", "Soft-Off", "Present", "Off"];
3219 + var powerStateStrings2 = ['', "Device is powered", "Device is in sleep state (S1)", "Device is in sleep state (S2)", "Device is in deep sleep state (S3)", "Device is hibernating (S4)", "Device is in soft-off state (S5)", "Device is present, but power state cannot be determined", "The device is powered off"];
3220 var powerColorTable = ['#00000000', 'black', 'blue', 'blue', 'lightblue', 'blueviolet', 'darkgreen', 'lightseagreen', 'lightseagreen'];
3221 function NodeStateStr(node) {
3222 var states = [];
3223 if (node.state > 0 && node.state < powerStatetable.length) state.push(powerStatetable[node.state]);
3224 if (node.conn) {
3225 - if ((node.conn & 1) != 0) { states.push('<span>' + ((node.mtype == 4)?"IP-KVM":"Agent") + '</span>'); }
3225 + if ((node.conn & 1) != 0) { states.push('<span>' + ((node.mtype == 4) ? ((node.porttype == 'PDU') ? "Switch" : "IP-KVM") : "Agent") + '</span>'); }
3226 if ((node.conn & 2) != 0) { states.push('<span>' + "CIRA" + '</span>'); }
3227 else if ((node.conn & 4) != 0) { states.push('<span>' + "Intel&reg; AMT" + '</span>'); }
3228 if ((node.conn & 8) != 0) { states.push('<span>' + "Relay" + '</span>'); }
@@ -3382,8 +3382,8 @@
3382
3383 // IP-KVM information
3384 if (node.mtype == 4) {
3385 - if (node.portnum) { x += addDeviceAttribute("Port Number", node.portnum); }
3386 - if (node.porttype) { x += addDeviceAttribute("Port Type", node.porttype); }
3385 + if (node.portnum != null) { x += addDeviceAttribute("Port Number", node.portnum); }
3386 + if (node.porttype != null) { x += addDeviceAttribute("Port Type", node.porttype); }
3387 }
3388
3389 // Attribute: Mesh Agent
@@ -3486,7 +3486,7 @@
3486 var connectivity = node.conn;
3487 if (connectivity && connectivity > 1) {
3488 var cstate = [];
3489 - if ((node.conn & 1) != 0) cstate.push('<span>' + ((node.mtype == 4) ? "IP-KVM" : "Agent") + '</span>');
3489 + if ((node.conn & 1) != 0) cstate.push('<span>' + ((node.mtype == 4) ? ((node.porttype == 'PDU') ? "Switch" : "IP-KVM") : "Agent") + '</span>');
3490 if ((node.conn & 2) != 0) cstate.push('<span>' + "Intel&reg; AMT CIRA" + '</span>');
3491 else if ((node.conn & 4) != 0) cstate.push('<span>' + "Intel&reg; AMT" + '</span>');
3492 if ((node.conn & 8) != 0) cstate.push('<span>' + "Agent Relay" + '</span>');
@@ -3519,9 +3519,21 @@
3519 x += '</table><br />';
3520 // Show action button, only show if we have permissions 4, 8, 64
3521 if (((meshrights & (4 + 8 + 64)) != 0) && (node.mtype < 3)) { x += '<input type=button value="' + "Actions" + '" onclick=deviceActionFunction() />'; }
3522 - x += '<input type=button value=Notes onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
3522 + x += '<input type=button value="' + "Notes" + '" onclick=showNotes(' + ((meshrights & 128) == 0) + ',"' + encodeURIComponent(node._id) + '") />';
3523 //if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += '<input type=button value=Toast onclick=deviceToastFunction() />'; }
3524
3525 + if ((node.mtype == 4) && (meshrights & 8) && (connectivity & 1)) {
3526 + if (node.porttype == 'PDU') {
3527 + if (node.pwr == 1) {
3528 + x += '<input type=button value="' + "Turn off" + '" title="' + "Turn off" + '" onclick=setIpPduState(0) />';
3529 + } else if (node.pwr == 8) {
3530 + x += '<input type=button value="' + "Turn on" + '" title="' + "Turn on" + '" onclick=setIpPduState(1) />';
3531 + }
3532 + } else {
3533 + x += '<input type=button value="' + "Remote Control" + '" title="' + "Remote Control" + '" onclick=openIpKvmRemoteControl("' + encodeURIComponentEx(node._id) + '") />';
3534 + }
3535 + }
3536 +
3537 QH('p10html', x);
3538
3539 // If we are looking at a local non-windows device, enable terminal and files capability.
@@ -3546,11 +3558,11 @@
3558 // Set the node power state
3559 var powerstate = PowerStateStr(node.state);
3560 //if (node.state == 0) { powerstate = 'Unknown State'; }
3549 - if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += ((node.mtype == 4) ? "IP-KVM" : "Mesh Agent"); }
3561 + if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += ((node.mtype == 4) ? ((node.porttype == 'PDU') ? "Switch" : "IP-KVM") : "Mesh Agent"); }
3562 if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += "Intel&reg; AMT connected"; }
3563 else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += "Intel&reg; AMT detected"; }
3564 if ((connectivity & 16) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += "MQTT channel connected"; }
3553 - if ((node.pwr > 1) && (node.pwr != 7)) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += powerStateStrings[node.pwr]; }
3565 + if ((node.porttype == 'PDU') || ((node.pwr > 1) && (node.pwr != 7))) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += powerStateStrings[node.pwr]; }
3566 QH('MainComputerState', '<span style=font-size:12px>' + powerstate + '</span>');
3567
3568 // Set the node icon
@@ -3585,6 +3597,20 @@
3597 if (xxcurrentView == 10) { setupDeviceMenu(); }
3598 }
3599
3600 + function setIpPduState(op) {
3601 + if (op == 0) {
3602 + setDialogMode(2, "Power Operation", 3, function () { meshserver.send({ action: 'poweraction', nodeids: [currentNode._id], actiontype: 2 }); }, "Perform power off?"); // Turn off
3603 + } else {
3604 + setDialogMode(2, "Power Operation", 3, function () { meshserver.send({ action: 'wakedevices', nodeids: [currentNode._id] }); }, "Perform power on?"); // Turn on
3605 + }
3606 + }
3607 +
3608 + function openIpKvmRemoteControl(nodeid) {
3609 + if (xxdialogMode) return;
3610 + var nid = decodeURIComponent(nodeid).split('/')[2];
3611 + safeNewWindow('/ipkvm.ashx/' + nid + '/', 'ipkvm:' + nid);
3612 + }
3613 +
3614 function deviceToastFunction() {
3615 if (xxdialogMode) return;
3616 setDialogMode(2, "Device Toast", 3, deviceToastFunctionEx, '<textarea id=d2devToast style=width:100%;height:80px;resize:none;overflow-y:scroll></textarea>');
@@ -5956,7 +5982,7 @@
5982 x += addHtmlValue("Username", currentMesh.kvm.user);
5983 }
5984
5959 - x += '<br><input type=button value=Notes onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
5985 + x += '<br><input type=button value="' + "Notes" + '" onclick=showNotes(false,"' + encodeURIComponent(currentMesh._id) + '") />';
5986
5987 x += '<br style=clear:both><br>';
5988 var currentMeshLinks = currentMesh.links[userinfo._id];
views/default.handlebars
+46 -13
@@ -4367,10 +4367,16 @@
4367 } else if (view == 2) {
4368 var states = [];
4369 if (node.conn) {
4370 - if (node.mtype == 4) {
4371 - if ((node.conn & 1) != 0) { states.push('<span title="' + "IP-KVM port is connected and ready for use." + '">' + "IP-KVM" + '</span>'); }
4372 - } else {
4373 - if ((node.conn & 1) != 0) { states.push('<span title="' + "Mesh agent is connected and ready for use." + '">' + "Agent" + '</span>'); }
4370 + if ((node.conn & 1) != 0) {
4371 + if (node.mtype == 4) {
4372 + if (node.porttype == 'PDU') {
4373 + states.push('<span title="' + "Switch port is ready for use." + '">' + "Switch" + '</span>');
4374 + } else {
4375 + states.push('<span title="' + "IP-KVM port is connected and ready for use." + '">' + "IP-KVM" + '</span>');
4376 + }
4377 + } else {
4378 + states.push('<span title="' + "Mesh agent is connected and ready for use." + '">' + "Agent" + '</span>');
4379 + }
4380 }
4381 if ((node.conn & 2) != 0) { states.push('<span title="' + "Intel&reg; AMT CIRA is connected and ready for use." + '">' + "CIRA" + '</span>'); }
4382 else if ((node.conn & 4) != 0) { states.push('<span title="' + "Intel&reg; AMT is routable." + '">' + "AMT" + '</span>'); }
@@ -5132,8 +5138,8 @@
5138 deviceHeaderTotal = 0;
5139 }
5140
5135 - var powerStateStrings = ['', '<span title="' + "Device is powered on." + '">' + "Powered" + '</span>', '<span title="' + "Device is in sleep state (S1)." + '">' + "Sleeping" + '</span>', '<span title="' + "Device is in sleep state (S2)." + '">' + "Sleeping" + '</span>', '<span title="' + "Device is in deep sleep state (S3)." + '">' + "Deep Sleep" + '</span>', '<span title="' + "Device is in hibernating state (S4)." + '">' + "Hibernating" + '</span>', '<span title="' + "Device is in powered off state (S5)." + '">' + "Soft-Off" + '</span>', '<span title="' + "Device is detected but power state could not be obtained." + '">' + "Present" + '</span>'];
5136 - var powerStateStrings2 = ['', "Device is powered", "Device is in sleep state (S1)", "Device is in sleep state (S2)", "Device is in deep sleep state (S3)", "Device is hibernating (S4)", "Device is in soft-off state (S5)", "Device is present, but power state cannot be determined"];
5141 + var powerStateStrings = ['', '<span title="' + "Device is powered on." + '">' + "Powered" + '</span>', '<span title="' + "Device is in sleep state (S1)." + '">' + "Sleeping" + '</span>', '<span title="' + "Device is in sleep state (S2)." + '">' + "Sleeping" + '</span>', '<span title="' + "Device is in deep sleep state (S3)." + '">' + "Deep Sleep" + '</span>', '<span title="' + "Device is in hibernating state (S4)." + '">' + "Hibernating" + '</span>', '<span title="' + "Device is in powered off state (S5)." + '">' + "Soft-Off" + '</span>', '<span title="' + "Device is detected but power state could not be obtained." + '">' + "Present" + '</span>', '<span title="' + "Device is powered off." + '">' + "Off" + '</span>'];
5142 + var powerStateStrings2 = ['', "Device is powered", "Device is in sleep state (S1)", "Device is in sleep state (S2)", "Device is in deep sleep state (S3)", "Device is hibernating (S4)", "Device is in soft-off state (S5)", "Device is present, but power state cannot be determined", "The device is powered off"];
5143 var powerColorTable = ['pwsTransparent', 'pwsBlack', 'pwsBlue', 'pwsBlue2', 'pwsLightblue', 'pwsBlueviolet', 'pwsDarkgreen', 'pwsLightseagreen', 'pwsLightseagreen2'];
5144 function NodeStateStr(node) {
5145 var states = [];
@@ -5141,7 +5147,11 @@
5147 if (node.conn) {
5148 if ((node.conn & 1) != 0) {
5149 if (node.mtype == 4) {
5144 - states.push('<span title="' + "IP KVM port is up and ready for use." + '">' + "IP-KVM" + '</span>');
5150 + if (node.porttype == 'PDU') {
5151 + states.push('<span title="' + "Power switch is ready for use." + '">' + "Switch" + '</span>');
5152 + } else {
5153 + states.push('<span title="' + "IP KVM port is up and ready for use." + '">' + "IP-KVM" + '</span>');
5154 + }
5155 } else {
5156 states.push('<span title="' + "Mesh agent is connected and ready for use." + '">' + "Agent" + '</span>');
5157 }
@@ -6686,10 +6696,10 @@
6696 x += addDeviceAttribute("Description", description);
6697 }
6698
6689 - // IP-KVM information
6699 + // IP-KVM / PDU information
6700 if (node.mtype == 4) {
6691 - if (node.portnum) { x += addDeviceAttribute("Port Number", node.portnum); }
6692 - if (node.porttype) { x += addDeviceAttribute("Port Type", node.porttype); }
6701 + if (node.portnum != null) { x += addDeviceAttribute("Port Number", node.portnum); }
6702 + if (node.porttype != null) { x += addDeviceAttribute("Port Type", node.porttype); }
6703 }
6704
6705 // Attribute: Mesh Agent
@@ -6893,7 +6903,15 @@
6903 }
6904 }
6905 if ((node.mtype == 4) && (meshrights & 8) && (connectivity & 1)) {
6896 - x += '<input type=button value="' + "Remote Control" + '" title="' + "Remote Control" + '" onclick=openIpKvmRemoteControl("' + encodeURIComponentEx(node._id) + '") />';
6906 + if (node.porttype == 'PDU') {
6907 + if (node.pwr == 1) {
6908 + x += '<input type=button value="' + "Turn off" + '" title="' + "Turn off" + '" onclick=setIpPduState(0) />';
6909 + } else if (node.pwr == 8) {
6910 + x += '<input type=button value="' + "Turn on" + '" title="' + "Turn on" + '" onclick=setIpPduState(1) />';
6911 + }
6912 + } else {
6913 + x += '<input type=button value="' + "Remote Control" + '" title="' + "Remote Control" + '" onclick=openIpKvmRemoteControl("' + encodeURIComponentEx(node._id) + '") />';
6914 + }
6915 }
6916
6917 // Custom UI
@@ -7007,7 +7025,11 @@
7025 if ((connectivity & 1) != 0) {
7026 if (powerstate.length > 0) { powerstate += '<br/>'; }
7027 if (node.mtype == 4) {
7010 - powerstate += '<span style=font-size:12px title="' + "IP-KVM port connected" + '">' + "IP-KVM port connected" + '</span>' + agentPrivilages;
7028 + if (node.porttype == 'PDU') {
7029 + powerstate += '<span style=font-size:12px title="' + "Switch port connected" + '">' + "Switch port connected" + '</span>' + agentPrivilages;
7030 + } else {
7031 + powerstate += '<span style=font-size:12px title="' + "IP-KVM port connected" + '">' + "IP-KVM port connected" + '</span>' + agentPrivilages;
7032 + }
7033 } else {
7034 powerstate += '<span style=font-size:12px title="' + "Agent connected" + '">' + "Agent connected" + '</span>' + agentPrivilages;
7035 }
@@ -7016,7 +7038,10 @@
7038 else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="' + "Intel&reg; AMT detected" + '">' + "Intel&reg; AMT detected" + '</span>'; }
7039 if ((connectivity & 16) != 0) { if (powerstate.length > 0) { powerstate += '<br/>'; } powerstate += '<span style=font-size:12px title="' + "MQTT connected" + '">' + "MQTT channel connected" + '</span>'; }
7040 if ((powerstate == '') && node.lastconnect) { powerstate = '<span style=font-size:12px>' + "Last seen:" + '<br />' + printDateTime(new Date(node.lastconnect)) + '</span>'; }
7019 - else { if ((node.pwr > 1) && (node.pwr != 7)) { powerstate += ('<br/>' + powerStateStrings[node.pwr]); } }
7041 + else {
7042 + if (node.porttype == 'PDU') { powerstate += ('<br/>' + powerStateStrings[node.pwr]); }
7043 + else if ((node.pwr > 1) && (node.pwr != 7)) { powerstate += ('<br/>' + powerStateStrings[node.pwr]); }
7044 + }
7045 QH('MainComputerState', powerstate);
7046
7047 // Set the node icon
@@ -7193,6 +7218,14 @@
7218 go(panel);
7219 }
7220
7221 + function setIpPduState(op) {
7222 + if (op == 0) {
7223 + setDialogMode(2, "Power Operation", 3, function() { meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: 2 }); }, "Perform power off?"); // Turn off
7224 + } else {
7225 + setDialogMode(2, "Power Operation", 3, function() { meshserver.send({ action: 'wakedevices', nodeids: [ currentNode._id ] }); }, "Perform power on?"); // Turn on
7226 + }
7227 + }
7228 +
7229 function p20editDeviceNotify() {
7230 if (xxdialogMode) return false;
7231 var devNotify = 0, fx = ((features2 & 0x00004000) && (userinfo.emailVerified))?1:0;