diff --git a/meshcentral.js b/meshcentral.js
index 10c88b2c..eec53f63 100644
--- a/meshcentral.js
+++ b/meshcentral.js
@@ -2203,9 +2203,9 @@ function CreateMeshCentralServer(config, args) {
// nodeId: node identifier of format node/domain/nodeidhex
// connectTime: time of connection, milliseconds elapsed since the UNIX epoch.
// connectType: Bitmask, 1 = MeshAgent, 2 = Intel AMT CIRA, 4 = Intel AMT local, 8 = Intel AMT Relay, 16 = MQTT
- // 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
+ // 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
//var connectTypeStrings = ['', 'MeshAgent', 'Intel AMT CIRA', '', 'Intel AMT local', '', '', '', 'Intel AMT Relay', '', '', '', '', '', '', '', 'MQTT'];
- //var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present'];
+ //var powerStateStrings = ['Unknown', 'Powered', 'Sleep', 'Sleep', 'Deep Sleep', 'Hibernating', 'Soft-Off', 'Present', 'Off'];
obj.SetConnectivityState = function (meshid, nodeid, connectTime, connectType, powerState, serverid, extraInfo) {
//console.log('SetConnectivity for ' + nodeid.substring(0, 16) + ', Type: ' + connectTypeStrings[connectType] + ', Power: ' + powerStateStrings[powerState] + (serverid == null ? ('') : (', ServerId: ' + serverid)));
if ((serverid == null) && (obj.multiServer != null)) { obj.multiServer.DispatchMessage({ action: 'SetConnectivityState', meshid: meshid, nodeid: nodeid, connectTime: connectTime, connectType: connectType, powerState: powerState, extraInfo: extraInfo }); }
diff --git a/meshipkvm.js b/meshipkvm.js
index 518eb94e..bac2bd62 100644
--- a/meshipkvm.js
+++ b/meshipkvm.js
@@ -37,14 +37,19 @@ function CreateIPKVMManager(parent) {
const MESHRIGHT_ADMIN = 0xFFFFFFFF;
// Subscribe for mesh creation events
- parent.AddEventDispatch(['server-createmesh', 'server-deletemesh'], obj);
+ parent.AddEventDispatch(['server-createmesh', 'server-deletemesh', 'devport-operation'], obj);
obj.HandleEvent = function (source, event, ids, id) {
- if ((event != null) && (event.action == 'createmesh') && (event.mtype == 4)) {
+ if ((event == null) || (event.mtype != 4)) return;
+ if (event.action == 'createmesh') {
// Start managing this new device group
startManagement(parent.webserver.meshes[event.meshid]);
- } else if ((event != null) && (event.action == 'deletemesh') && (event.mtype == 4)) {
+ } else if (event.action == 'deletemesh') {
// Stop managing this device group
stopManagement(event.meshid);
+ } else if ((event.action == 'turnon') || (event.action == 'turnoff')) {
+ // Perform power operation
+ const manager = obj.managedGroups[event.meshid];
+ if ((manager) && (manager.powerOperation)) { manager.powerOperation(event); }
}
}
@@ -120,7 +125,7 @@ function CreateIPKVMManager(parent) {
const mesh = parent.webserver.meshes[sender.meshid];
if (nodes.length == 0) {
// The device does not exist, create it
- 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 };
+ 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' };
parent.db.Set(device);
// Event the new node
@@ -140,13 +145,13 @@ function CreateIPKVMManager(parent) {
// Set the connectivity state if needed
if (obj.managedPorts[nodeid] == null) {
- parent.SetConnectivityState(sender.meshid, nodeid, Date.now(), 1, port.State?1:6, null, null);
+ parent.SetConnectivityState(sender.meshid, nodeid, Date.now(), 1, port.State ? 1 : 8, null, null);
obj.managedPorts[nodeid] = { name: port.Name, meshid: sender.meshid, portid: port.PortId, portType: port.PortType, portNo: port.PortIndex };
}
});
} else {
// Update connectivity state
- parent.SetConnectivityState(sender.meshid, nodeid, Date.now(), 1, port.State ? 1 : 6, null, null);
+ parent.SetConnectivityState(sender.meshid, nodeid, Date.now(), 1, port.State ? 1 : 8, null, null);
}
} else if ((port.Status == 1) && (port.Class == 'KVM')) {
//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) {
obj.update();
}
- obj.update = function() {
+ obj.update = function () {
obj.fetch('/restapi/relay/outlets/all;/=name,physical_state/', 'GET', null, null, function (sender, tag, rdata, res) {
if (res.statusCode == 207) {
var rdata2 = null;
@@ -780,7 +785,7 @@ function CreateWebPowerSwitch(parent, hostname, port, username, password) {
var portchanged = false;
if (obj.ports[i] == null) {
// Add the port
- obj.ports[i] = { PortNumber: i, PortId: 'p' + i, Name: portname, Status: 1, State: portstate, Class: 'PDU' };
+ obj.ports[i] = { PortNumber: i + 1, PortId: 'p' + i, Name: portname, Status: 1, State: portstate, Class: 'PDU' };
portchanged = true;
} else {
// Update the port
@@ -800,9 +805,15 @@ function CreateWebPowerSwitch(parent, hostname, port, username, password) {
});
}
+ obj.powerOperation = function (event) {
+ if (typeof event.portnum != 'number') return;
+ if (event.action == 'turnon') { setPowerState(event.portnum - 1, true); }
+ else if (event.action == 'turnoff') { setPowerState(event.portnum - 1, false); }
+ }
+
function setPowerState(port, state, func) {
obj.fetch('/restapi/relay/outlets/' + port + '/state/', 'PUT', 'value=' + state, null, function (sender, tag, rdata, res) {
- console.log('DATA:', res.statusCode, rdata.toString());
+ if (res.statusCode == 204) { obj.update(); }
});
}
diff --git a/meshuser.js b/meshuser.js
index be1224de..9ba6d6ab 100644
--- a/meshuser.js
+++ b/meshuser.js
@@ -2889,7 +2889,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// Get the node and the rights for this node
parent.GetNodeWithRights(domain, user, nodeid, function (node, rights, visible) {
- // Check we have the rights to delete this device
+ // Check we have the rights to wake this device
if ((node == null) || (visible == false) || (rights & MESHRIGHT_WAKEDEVICE) == 0) {
if (command.nodeids.length == 1) { try { ws.send(JSON.stringify({ action: 'wakedevices', responseid: command.responseid, result: 'Invalid nodeid' })); } catch (ex) { } }
return;
@@ -2898,6 +2898,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// If this device is connected on MQTT, send a wake action.
if (parent.parent.mqttbroker != null) { parent.parent.mqttbroker.publish(node._id, 'powerAction', 'wake'); }
+ // If this is a IP-KVM or Power Distribution Unit (PDU), dispatch an action event
+ if (node.mtype == 4) {
+ // Send out an event to perform turn off command on the port
+ //var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['devport-operation', 'server-users', user._id]);
+ 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 };
+ parent.parent.DispatchEvent([ 'devport-operation' ], obj, event);
+ return;
+ }
+
// Get the device interface information
db.Get('if' + node._id, function (err, nodeifs) {
if ((nodeifs != null) && (nodeifs.length == 1)) {
@@ -3054,11 +3063,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
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); }
} else {
// Check we have the rights to delete this device
- if ((rights & MESHRIGHT_RESETOFF) == 0) return;
+ if ((rights & MESHRIGHT_RESETOFF) == 0) return;
// If this device is connected on MQTT, send a power action.
if ((parent.parent.mqttbroker != null) && (command.actiontype >= 0) && (command.actiontype <= 4)) { parent.parent.mqttbroker.publish(node._id, 'powerAction', ['', '', 'poweroff', 'reset', 'sleep'][command.actiontype]); }
+ // If this is a IP-KVM or Power Distribution Unit (PDU), dispatch an action event
+ if (node.mtype == 4) {
+ // Send out an event to perform turn off command on the port
+ //var targets = parent.CreateNodeDispatchTargets(node.meshid, node._id, ['devport-operation', 'server-users', user._id]);
+ 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 };
+ parent.parent.DispatchEvent([ 'devport-operation' ], obj, event);
+ return;
+ }
+
if ((command.actiontype >= 300) && (command.actiontype < 400)) {
if ((command.actiontype != 302) && (command.actiontype != 308) && (command.actiontype != 310)) return; // Invalid action type.
// Intel AMT power command, actiontype: 2 = Power on, 8 = Power down, 10 = reset
diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars
index 19a1224a..904817c3 100644
--- a/views/default-mobile.handlebars
+++ b/views/default-mobile.handlebars
@@ -3214,15 +3214,15 @@
return false;
}
- var powerStatetable = ['', "Powered", "Sleep", "Sleep", "Sleep", "Hibernating", "Power off", "Present"];
- var powerStateStrings = ['', "Powered", "Sleeping", "Sleeping", "Deep Sleep", "Hibernating", "Soft-Off", "Present"];
- 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"];
+ var powerStatetable = ['', "Powered", "Sleep", "Sleep", "Sleep", "Hibernating", "Power off", "Present", "Off"];
+ var powerStateStrings = ['', "Powered", "Sleeping", "Sleeping", "Deep Sleep", "Hibernating", "Soft-Off", "Present", "Off"];
+ 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"];
var powerColorTable = ['#00000000', 'black', 'blue', 'blue', 'lightblue', 'blueviolet', 'darkgreen', 'lightseagreen', 'lightseagreen'];
function NodeStateStr(node) {
var states = [];
if (node.state > 0 && node.state < powerStatetable.length) state.push(powerStatetable[node.state]);
if (node.conn) {
- if ((node.conn & 1) != 0) { states.push('' + ((node.mtype == 4)?"IP-KVM":"Agent") + ''); }
+ if ((node.conn & 1) != 0) { states.push('' + ((node.mtype == 4) ? ((node.porttype == 'PDU') ? "Switch" : "IP-KVM") : "Agent") + ''); }
if ((node.conn & 2) != 0) { states.push('' + "CIRA" + ''); }
else if ((node.conn & 4) != 0) { states.push('' + "Intel® AMT" + ''); }
if ((node.conn & 8) != 0) { states.push('' + "Relay" + ''); }
@@ -3382,8 +3382,8 @@
// IP-KVM information
if (node.mtype == 4) {
- if (node.portnum) { x += addDeviceAttribute("Port Number", node.portnum); }
- if (node.porttype) { x += addDeviceAttribute("Port Type", node.porttype); }
+ if (node.portnum != null) { x += addDeviceAttribute("Port Number", node.portnum); }
+ if (node.porttype != null) { x += addDeviceAttribute("Port Type", node.porttype); }
}
// Attribute: Mesh Agent
@@ -3486,7 +3486,7 @@
var connectivity = node.conn;
if (connectivity && connectivity > 1) {
var cstate = [];
- if ((node.conn & 1) != 0) cstate.push('' + ((node.mtype == 4) ? "IP-KVM" : "Agent") + '');
+ if ((node.conn & 1) != 0) cstate.push('' + ((node.mtype == 4) ? ((node.porttype == 'PDU') ? "Switch" : "IP-KVM") : "Agent") + '');
if ((node.conn & 2) != 0) cstate.push('' + "Intel® AMT CIRA" + '');
else if ((node.conn & 4) != 0) cstate.push('' + "Intel® AMT" + '');
if ((node.conn & 8) != 0) cstate.push('' + "Agent Relay" + '');
@@ -3519,9 +3519,21 @@
x += '
';
// Show action button, only show if we have permissions 4, 8, 64
if (((meshrights & (4 + 8 + 64)) != 0) && (node.mtype < 3)) { x += ''; }
- x += '';
+ x += '';
//if ((connectivity & 1) && (meshrights & 8) && (node.agent.id < 5)) { x += ''; }
+ if ((node.mtype == 4) && (meshrights & 8) && (connectivity & 1)) {
+ if (node.porttype == 'PDU') {
+ if (node.pwr == 1) {
+ x += '';
+ } else if (node.pwr == 8) {
+ x += '';
+ }
+ } else {
+ x += '';
+ }
+ }
+
QH('p10html', x);
// If we are looking at a local non-windows device, enable terminal and files capability.
@@ -3546,11 +3558,11 @@
// Set the node power state
var powerstate = PowerStateStr(node.state);
//if (node.state == 0) { powerstate = 'Unknown State'; }
- if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += ((node.mtype == 4) ? "IP-KVM" : "Mesh Agent"); }
+ if ((connectivity & 1) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += ((node.mtype == 4) ? ((node.porttype == 'PDU') ? "Switch" : "IP-KVM") : "Mesh Agent"); }
if ((connectivity & 2) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += "Intel® AMT connected"; }
else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += "Intel® AMT detected"; }
if ((connectivity & 16) != 0) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += "MQTT channel connected"; }
- if ((node.pwr > 1) && (node.pwr != 7)) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += powerStateStrings[node.pwr]; }
+ if ((node.porttype == 'PDU') || ((node.pwr > 1) && (node.pwr != 7))) { if (powerstate.length > 0) { powerstate += ', '; } powerstate += powerStateStrings[node.pwr]; }
QH('MainComputerState', '' + powerstate + '');
// Set the node icon
@@ -3585,6 +3597,20 @@
if (xxcurrentView == 10) { setupDeviceMenu(); }
}
+ function setIpPduState(op) {
+ if (op == 0) {
+ setDialogMode(2, "Power Operation", 3, function () { meshserver.send({ action: 'poweraction', nodeids: [currentNode._id], actiontype: 2 }); }, "Perform power off?"); // Turn off
+ } else {
+ setDialogMode(2, "Power Operation", 3, function () { meshserver.send({ action: 'wakedevices', nodeids: [currentNode._id] }); }, "Perform power on?"); // Turn on
+ }
+ }
+
+ function openIpKvmRemoteControl(nodeid) {
+ if (xxdialogMode) return;
+ var nid = decodeURIComponent(nodeid).split('/')[2];
+ safeNewWindow('/ipkvm.ashx/' + nid + '/', 'ipkvm:' + nid);
+ }
+
function deviceToastFunction() {
if (xxdialogMode) return;
setDialogMode(2, "Device Toast", 3, deviceToastFunctionEx, '');
@@ -5956,7 +5982,7 @@
x += addHtmlValue("Username", currentMesh.kvm.user);
}
- x += '
';
+ x += '
';
x += '
';
var currentMeshLinks = currentMesh.links[userinfo._id];
diff --git a/views/default.handlebars b/views/default.handlebars
index 3715902d..52ebdfd7 100644
--- a/views/default.handlebars
+++ b/views/default.handlebars
@@ -4367,10 +4367,16 @@
} else if (view == 2) {
var states = [];
if (node.conn) {
- if (node.mtype == 4) {
- if ((node.conn & 1) != 0) { states.push('' + "IP-KVM" + ''); }
- } else {
- if ((node.conn & 1) != 0) { states.push('' + "Agent" + ''); }
+ if ((node.conn & 1) != 0) {
+ if (node.mtype == 4) {
+ if (node.porttype == 'PDU') {
+ states.push('' + "Switch" + '');
+ } else {
+ states.push('' + "IP-KVM" + '');
+ }
+ } else {
+ states.push('' + "Agent" + '');
+ }
}
if ((node.conn & 2) != 0) { states.push('' + "CIRA" + ''); }
else if ((node.conn & 4) != 0) { states.push('' + "AMT" + ''); }
@@ -5132,8 +5138,8 @@
deviceHeaderTotal = 0;
}
- var powerStateStrings = ['', '' + "Powered" + '', '' + "Sleeping" + '', '' + "Sleeping" + '', '' + "Deep Sleep" + '', '' + "Hibernating" + '', '' + "Soft-Off" + '', '' + "Present" + ''];
- 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"];
+ var powerStateStrings = ['', '' + "Powered" + '', '' + "Sleeping" + '', '' + "Sleeping" + '', '' + "Deep Sleep" + '', '' + "Hibernating" + '', '' + "Soft-Off" + '', '' + "Present" + '', '' + "Off" + ''];
+ 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"];
var powerColorTable = ['pwsTransparent', 'pwsBlack', 'pwsBlue', 'pwsBlue2', 'pwsLightblue', 'pwsBlueviolet', 'pwsDarkgreen', 'pwsLightseagreen', 'pwsLightseagreen2'];
function NodeStateStr(node) {
var states = [];
@@ -5141,7 +5147,11 @@
if (node.conn) {
if ((node.conn & 1) != 0) {
if (node.mtype == 4) {
- states.push('' + "IP-KVM" + '');
+ if (node.porttype == 'PDU') {
+ states.push('' + "Switch" + '');
+ } else {
+ states.push('' + "IP-KVM" + '');
+ }
} else {
states.push('' + "Agent" + '');
}
@@ -6686,10 +6696,10 @@
x += addDeviceAttribute("Description", description);
}
- // IP-KVM information
+ // IP-KVM / PDU information
if (node.mtype == 4) {
- if (node.portnum) { x += addDeviceAttribute("Port Number", node.portnum); }
- if (node.porttype) { x += addDeviceAttribute("Port Type", node.porttype); }
+ if (node.portnum != null) { x += addDeviceAttribute("Port Number", node.portnum); }
+ if (node.porttype != null) { x += addDeviceAttribute("Port Type", node.porttype); }
}
// Attribute: Mesh Agent
@@ -6893,7 +6903,15 @@
}
}
if ((node.mtype == 4) && (meshrights & 8) && (connectivity & 1)) {
- x += '';
+ if (node.porttype == 'PDU') {
+ if (node.pwr == 1) {
+ x += '';
+ } else if (node.pwr == 8) {
+ x += '';
+ }
+ } else {
+ x += '';
+ }
}
// Custom UI
@@ -7007,7 +7025,11 @@
if ((connectivity & 1) != 0) {
if (powerstate.length > 0) { powerstate += '
'; }
if (node.mtype == 4) {
- powerstate += '' + "IP-KVM port connected" + '' + agentPrivilages;
+ if (node.porttype == 'PDU') {
+ powerstate += '' + "Switch port connected" + '' + agentPrivilages;
+ } else {
+ powerstate += '' + "IP-KVM port connected" + '' + agentPrivilages;
+ }
} else {
powerstate += '' + "Agent connected" + '' + agentPrivilages;
}
@@ -7016,7 +7038,10 @@
else if ((connectivity & 4) != 0) { if (powerstate.length > 0) { powerstate += '
'; } powerstate += '' + "Intel® AMT detected" + ''; }
if ((connectivity & 16) != 0) { if (powerstate.length > 0) { powerstate += '
'; } powerstate += '' + "MQTT channel connected" + ''; }
if ((powerstate == '') && node.lastconnect) { powerstate = '' + "Last seen:" + '
' + printDateTime(new Date(node.lastconnect)) + ''; }
- else { if ((node.pwr > 1) && (node.pwr != 7)) { powerstate += ('
' + powerStateStrings[node.pwr]); } }
+ else {
+ if (node.porttype == 'PDU') { powerstate += ('
' + powerStateStrings[node.pwr]); }
+ else if ((node.pwr > 1) && (node.pwr != 7)) { powerstate += ('
' + powerStateStrings[node.pwr]); }
+ }
QH('MainComputerState', powerstate);
// Set the node icon
@@ -7193,6 +7218,14 @@
go(panel);
}
+ function setIpPduState(op) {
+ if (op == 0) {
+ setDialogMode(2, "Power Operation", 3, function() { meshserver.send({ action: 'poweraction', nodeids: [ currentNode._id ], actiontype: 2 }); }, "Perform power off?"); // Turn off
+ } else {
+ setDialogMode(2, "Power Operation", 3, function() { meshserver.send({ action: 'wakedevices', nodeids: [ currentNode._id ] }); }, "Perform power on?"); // Turn on
+ }
+ }
+
function p20editDeviceNotify() {
if (xxdialogMode) return false;
var devNotify = 0, fx = ((features2 & 0x00004000) && (userinfo.emailVerified))?1:0;