Files
JIMRI/web/js/jquery.jmriConnect.js
2026-06-17 14:00:51 +02:00

255 lines
14 KiB
JavaScript

/**********************************************************************************************
*
* JMRI JSON WebSockets and Ajax communication javascript
* File version 1.0 (old): script 'ThrottleMonitor.py' must be loaded for throttle support
* File version 2.0: native JSON throttle support - doesn't need script 'ThrottleMonitor.py' anymore
*
* >>> This file version: 2.1 - from original 'jquery.jmri.js' modified by Oscar Moutinho (oscar.moutinho@gmail.com)
*
* Using HTML5 and jQuery 2...
* Note that this JMRI extension relies on the jquery-websocket v.0.0.4 extension.
*
**********************************************************************************************/
//----------------------------------------- Manage JMRI WebSockets
(function($) {
$.extend({
JMRI: function(url, bindings) {
var jmri = {};
if (typeof(url) === 'string') {
jmri.url = url;
} else {
jmri.url = document.URL.split('/')[0] + '//' + document.URL.split('/')[2] + '/json/';
bindings = url;
}
// Default event handlers that do nothing
jmri.toSend = function(data) {};
jmri.fullData = function(data) {};
jmri.error = function(code, message) {};
jmri.end = function() {};
jmri.ready = function(jsonVersion, jmriVersion, railroadName) {};
jmri.throttle = function(name, address, speed, forward, fs) {};
jmri.light = function(name, userName, comment, state) {};
jmri.reporter = function(name, userName, state, comment, report, lastReport) {};
jmri.sensor = function(name, userName, comment, inverted, state) {};
jmri.turnout = function(name, userName, comment, inverted, state) {};
jmri.signalHead = function(name, userName, comment, lit, appearance, held, state, appearanceName) {};
jmri.signalMast = function(name, userName, aspect, lit, held, state) {};
jmri.route = function(name, userName, comment, state) {};
jmri.memory = function(name, userName, comment, value) {};
jmri.power = function(state) {};
// Add user-defined handlers to the settings object
$.extend(jmri, bindings);
// Constants
jmri.powerUNKNOWN = 0;
jmri.powerON = 2;
jmri.powerOFF = 4;
jmri.turnoutUNDEFINED = 0;
jmri.turnoutUNKNOWN = 1;
jmri.turnoutCLOSED = 2;
jmri.turnoutTHROWN = 4;
jmri.routeDISABLED = 0;
jmri.routeUNDEFINED = 1;
jmri.routeACTIVE = 2;
jmri.routeINACTIVE = 4;
jmri.TRUE = true;
jmri.FALSE = false;
jmri.YES = 1;
jmri.NO = 0;
jmri.EMERGENCY_STOP = '-1.0';
jmri.STOP = '0.0';
jmri.FULL_SPEED = '1.0';
// Getters and Setters
var roster = null;
jmri.getRosterGroups = function() {
if (!roster) roster = loadRoster();
var rosterGroupsList = [];
if (roster) {
roster.find('roster-config roster locomotive').each(function() {
$(this).find('attributepairs keyvaluepair').each(function() {
var key = $(this).find('key').text();
if (key.split(':')[0] == 'RosterGroup') {
var rosterGroup = key.split(':')[1];
var value = $(this).find('value').text();
if (value == 'yes' && rosterGroupsList.indexOf(rosterGroup) == -1) rosterGroupsList.push(rosterGroup);
}
});
});
}
return rosterGroupsList.sort();
};
jmri.getRoster = function(group) {
if (!roster) roster = loadRoster();
var locoList = [];
if (roster) {
roster.find('roster-config roster locomotive').each(function() {
var inGroup = false;
if (group) {
$(this).find('attributepairs keyvaluepair').each(function() {
var key = $(this).find('key').text();
if (key.split(':')[0] == 'RosterGroup') {
key = key.split(':')[1];
var value = $(this).find('value').text();
if (key == group && value == 'yes') inGroup = true;
}
});
} else inGroup = true;
if (inGroup) {
var loco = {
name: $(this).attr('id'),
roadNumber: $(this).attr('roadNumber'),
roadName: $(this).attr('roadName'),
mfg: $(this).attr('mfg'),
owner: $(this).attr('owner'),
model: $(this).attr('model'),
dccAddress: parseInt($(this).attr('dccAddress'), 10),
imageFilePath: $.trim($(this).attr('imageFilePath')),
iconFilePath: $.trim($(this).attr('iconFilePath'))
};
locoList.push(loco);
}
});
}
return locoList;
};
jmri.getRosterItem = function(name) {
if (!roster) roster = loadRoster();
var loco = null;
if (roster) {
roster.find('roster-config roster locomotive').each(function() {
if ($(this).attr('id') == name) {
loco = {
name: $(this).attr('id'),
fileName: $(this).attr('fileName'),
roadNumber: $(this).attr('roadNumber'),
roadName: $(this).attr('roadName'),
mfg: $(this).attr('mfg'),
owner: $(this).attr('owner'),
model: $(this).attr('model'),
dccAddress: parseInt($(this).attr('dccAddress'), 10),
comment: $(this).attr('comment'),
maxSpeed: parseInt($(this).attr('maxSpeed'), 10),
imageFilePath: $.trim($(this).attr('imageFilePath')),
iconFilePath: $.trim($(this).attr('iconFilePath')),
URL: $.trim($(this).attr('URL')),
IsShuntingOn: $.trim($(this).attr('IsShuntingOn')).toUpperCase(),
f: new Array(29)
};
for (var i = 0; i < 29; i++) loco.f[i] = null;
$(this).find('functionlabels functionlabel').each(function() {
var n = parseInt($(this).attr('num'), 10);
var f = {
lockable: ($(this).attr('lockable') == 'true'),
functionlabel: $(this).text(),
functionImage: $.trim($(this).attr('functionImage')),
functionImageSelected: $.trim($(this).attr('functionImageSelected'))
};
loco.f[n] = f;
});
}
});
}
return loco;
};
var loadRoster = function() { //Retrieve roster
var roster = null;
$.ajax({
url: '/roster?format=xml',
async: false,
cache: false,
type: 'GET',
dataType: 'xml',
error: function(jqXHR, textStatus, errorThrown) {
if(jqXHR.status == 404) jmri.error(jqXHR.status, 'Roster empty.\nNo locos defined in JMRI.');
else jmri.error(jqXHR.status, 'Response:\n' + jqXHR.responseText + '\n\nError:\n' + errorThrown);
},
success: function(xmlReturned, status, jqXHR) {
roster = $(xmlReturned);
if (xmlReturned === null) {
jmri.error(200, 'Roster empty.\nNo locos defined in JMRI.');
}
}
});
return roster;
};
jmri.getObjectList = function(listType) { //Retrieve a JSON list of objects
var list = [];
$.ajax({
url: jmri.url + listType,
async: false,
cache: false,
type: 'GET',
dataType: 'json',
error: function(jqXHR, textStatus, errorThrown) {
jmri.error(jqXHR.status, 'Response:\n' + jqXHR.responseText + '\n\nError:\n' + errorThrown);
},
success: function(listReturned, status, jqXHR) {list = listReturned;}
});
return list;
};
var heartbeatDelay; // Heartbeat timer delay
var heartbeat = null; // Heartbeat timer
jmri.closeSocket = function() {jmri.socket.close();};
jmri.getJMRI = function(type, name) {
if (!heartbeat) {jmri.error(0, 'The JMRI WebSocket service is not ready.\nSolve the problem and refresh web page.'); return;}
var lp = (name) ? {"name":name} : {};
jmri.toSend(JSON.stringify({"type":type,"data":lp}));
jmri.socket.send(type, lp);
};
jmri.setJMRI = function(type, name, args, method) {
if (!heartbeat) {jmri.error(0, 'The JMRI WebSocket service is not ready.\nSolve the problem and refresh web page.'); return;}
var lp = (name) ? {"name":name} : {};
jmri.toSend(JSON.stringify({"type":type, "data":jmri.jsonConcat(lp, args)}));
jmri.socket.send(type, jmri.jsonConcat(lp, args), method);
};
jmri.jsonConcat = function(o1, o2) { // Concatenate JSON name-value pair lists
var o = {};
var key;
for (key in o1) o[key] = o1[key];
for (key in o2) o[key] = o2[key];
return o;
};
// WebSocket
jmri.socket = $.websocket(jmri.url.replace(/^http/, 'ws'), {
close: function() { // Stop the heartbeat when the socket closes
if (heartbeat) {
clearInterval(heartbeat);
heartbeat = null;
}
},
message: function(e) {jmri.fullData(e.originalEvent.data);},
events: {
error: function(e) {jmri.error(e.data.code, e.data.message);},
pong: function(e) {},
goodbye: function(e) {
jmri.socket.close();
jmri.end();
},
hello: function(e) { // Handle the initial handshake response from the server
heartbeatDelay = e.data.heartbeat;
heartbeat = setInterval(function() {jmri.toSend(JSON.stringify({"type":"ping"})); jmri.socket.send('ping');}, heartbeatDelay);
jmri.ready(e.data.json, e.data.JMRI, e.data.railroad);
},
throttle: function(e) {
var functions = new Array(29);
for (var i = 0; i < 29; i++) functions[i] = e.data['F' + i];
jmri.throttle(e.data.throttle, e.data.address, e.data.speed, e.data.forward, functions);
},
light: function(e) {jmri.light(e.data.name, e.data.userName, e.data.comment, e.data.state);},
reporter: function(e) {jmri.reporter(e.data.name, e.data.userName, e.data.state, e.data.comment, e.data.report, e.data.lastReport);},
sensor: function(e) {jmri.sensor(e.data.name, e.data.userName, e.data.comment, e.data.inverted, e.data.state);},
turnout: function(e) {jmri.turnout(e.data.name, e.data.userName, e.data.comment, e.data.inverted, e.data.state);},
signalHead: function(e) {jmri.signalHead(e.data.name, e.data.userName, e.data.comment, e.data.lit, e.data.appearance, e.data.held, e.data.state, e.data.appearanceName);},
signalMast: function(e) {jmri.signalMast(e.data.name, e.data.userName, e.data.aspect, e.data.lit, e.data.held, e.data.state);},
route: function(e) {jmri.route(e.data.name, e.data.userName, e.data.comment, e.data.state);},
memory: function(e) {jmri.memory(e.data.name, e.data.userName, e.data.comment, e.data.value);},
power: function(e) {jmri.power(e.data.state);}
}
});
return jmri;
}
});
})(jQuery);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ End of file