Comparing version 0.1.16 to 0.1.17
@@ -25,7 +25,4 @@ /* | ||
var Debug = require("../lib/_Debug"); | ||
var Device = require('../lib/_TcpClient'); // in this cas a device is a feed | ||
var net = require('net'); | ||
var url = require("url"); | ||
var util = require("util"); | ||
var Debug = require("../lib/_Debug"); | ||
var dgram = require('dgram'); | ||
@@ -38,9 +35,3 @@ // use localdev tree if available | ||
// Map Tracker EMEI on Vessel MMSI [Warning: do not use fake MMSI with AISHUB, MarineTraffic,...] | ||
var IMEI_MMSI_MAPPING = { | ||
359710045733004: {mmsi: "227417480", callsign: "FGE6445", shipname: "Choari Tadig", shiptype: 30}, | ||
123456789 : {mmsi: "000000000", callsign: "FG00000", shipname: "Choari Dummy" , shiptype: 0} | ||
}; | ||
// hook user event handler to receive a copy of messages | ||
@@ -50,6 +41,9 @@ function HookBackendEvent (adapter, backend, socket) { | ||
function EventDevAuth (device){ | ||
device.aisproxy=0; // special counter to repost full device every 20 positions | ||
var msg = {type : 1, devid: device.devid}; | ||
adapter.BroadcastJson (msg); | ||
device.mmsi = parseInt (device.model); | ||
adapter.BroadcastStatic (device); | ||
if (device.stamp) adapter.BroadcastPos (device); | ||
}; | ||
function EventDevQuit (device){ | ||
}; | ||
@@ -59,17 +53,5 @@ // Events successful process by tracker adapter | ||
// force push of full device info every 20 positions update | ||
device.aisproxy= device.aisproxy++ % 20; | ||
if (device.aisproxy === 0) { | ||
EventDevAuth (device); | ||
} | ||
var msg = | ||
{type : 2 | ||
,devid: device.devid | ||
,lat : device.stamp.lat | ||
,lon : device.stamp.lon | ||
,sog : device.stamp.sog | ||
,cog : device.stamp.cog | ||
}; | ||
adapter.BroadcastJson (msg); | ||
// force push of full device info every 20 positions update | ||
if (device.aisproxy >= 20) adapter.BroadcastStatic (device); | ||
adapter.BroadcastPos (device); | ||
}; | ||
@@ -80,2 +62,3 @@ | ||
backend.event.on("dev-alrm",EventDevPos); | ||
backend.event.on("dev-quit",EventDevQuit); | ||
}; | ||
@@ -92,4 +75,9 @@ | ||
this.count = 0; // index for incomming client | ||
this.Debug (1,"%s", this.uid); | ||
this.uport = controller.svcopts.uport; | ||
this.uhost = controller.svcopts.uhost || "127.0.0.1"; | ||
this.Debug (1,"%s", this.uid); | ||
// create UDP port to push packet out | ||
if (this.uport) this.usock = dgram.createSocket('udp4'); | ||
HookBackendEvent(this, controller.gateway.backend); | ||
@@ -101,70 +89,109 @@ }; | ||
DevAdapter.prototype.BroadcastJson = function (jsonobj) { | ||
this.Debug (5, "%j", jsonobj); | ||
DevAdapter.prototype.BroadcastPos = function (device) { | ||
var aisOut; | ||
// push back anything we got to client [if any] | ||
device.aisproxy++; // update counter for AIS static renewal | ||
// push back anything we got to AIS clients [if any] | ||
var msg18= { // standard class B Position report | ||
aistype : 18, | ||
cog : device.stamp.cog, | ||
sog : device.stamp.sog, | ||
dsc : false, | ||
repeat : false, | ||
accuracy : true, | ||
lon : device.stamp.lon, | ||
lat : device.stamp.lat, | ||
second : 1, | ||
mmsi : device.mmsi | ||
}; | ||
this.Debug (4, "AIS Position=%j", msg18); | ||
//var message=util.format ("\n18b %j\n", msg18); | ||
//this.clients[sock].write (message); | ||
aisOut = new AisEncode (msg18); | ||
if (! aisOut.valid) { | ||
this.Debug (1, "Invalid msg18=%j", msg18); | ||
return; | ||
} | ||
// transform AIS string into a buffer linefeed ended | ||
var msgbuf = new Buffer (aisOut.nmea + "\n"); | ||
// if UDP is defined send AISpos onto it | ||
if (this.usock) { | ||
this.usock.send(msgbuf, 0, msgbuf.length, this.uport, this.uhost, function(err, bytes) { | ||
if (err) console.log ('### Hoops BroadcastPos : UDP Msg18 [err=%s]', err); | ||
}); | ||
} | ||
// if we have AIS TCP client let's send a copy of AISpos to each of them | ||
for (var sock in this.clients) { | ||
try { | ||
if (jsonobj.type === 2) { | ||
var msg18= { // standard class B Position report | ||
aistype : 18, | ||
cog : jsonobj.cog, | ||
sog : jsonobj.sog, | ||
dsc : false, | ||
repeat : false, | ||
accuracy : true, | ||
lon : jsonobj.lon, | ||
lat : jsonobj.lat, | ||
second : 1, | ||
mmsi : IMEI_MMSI_MAPPING [jsonobj.devid].mmsi | ||
}; | ||
//var message=util.format ("\n18b %j\n", msg18); | ||
//this.clients[sock].write (message); | ||
aisOut = new AisEncode (msg18); | ||
if (aisOut.valid) this.clients[sock].write (aisOut.nmea +'\n'); | ||
} | ||
if (++IMEI_MMSI_MAPPING [jsonobj.devid].count > 20 || jsonobj.type === 1) this.BroadcastStatic(jsonobj.devid, this.clients[sock]); | ||
this.clients[sock].write (msgbuf); | ||
} catch (err) { | ||
this.Debug (0, '### HOOPS lost a aisproxy client: %s [err=%s]', this.clients[sock].uid, err); | ||
this.Debug (1, '### Hoops BroadcastPos lost aisclient: %s [err=%s]', this.clients[sock].uid, err); | ||
delete this.clients[sock]; | ||
} | ||
} | ||
} | ||
}; | ||
DevAdapter.prototype.BroadcastStatic = function (devid, socket) { | ||
IMEI_MMSI_MAPPING [devid].count =0; // reset counter | ||
var aisOut; | ||
DevAdapter.prototype.BroadcastStatic = function (device) { | ||
var msg24a= {// class B static info | ||
aistype : 24, | ||
part : 0, | ||
cargo : IMEI_MMSI_MAPPING [devid].shiptype, | ||
callsign : IMEI_MMSI_MAPPING [devid].callsign, | ||
mmsi : IMEI_MMSI_MAPPING [devid].mmsi, | ||
shipname : IMEI_MMSI_MAPPING [devid].shipname | ||
}; | ||
//var message=util.format ("\n24a %j\n", msg24a); | ||
//socket.write (message); | ||
aisOut = new AisEncode (msg24a); | ||
if (aisOut.valid) socket.write (aisOut.nmea + '\n'); | ||
var aisOutA, aisOutB; | ||
device.aisproxy= 0; // reset counter to renew AIS static info | ||
var msg24a= {// class B static info | ||
aistype : 24, | ||
part : 0, | ||
mmsi : device.mmsi, | ||
shipname : device.name | ||
}; | ||
this.Debug (4, "AIS Statics=%j", msg24a); | ||
aisOutA = new AisEncode (msg24a); | ||
var msg24b= {// class AB static info | ||
aistype : 24, | ||
part : 1, | ||
mmsi : device.mmsi, | ||
cargo : 37, // map to pleasure boat | ||
callsign : device.callsign, | ||
dimA : 0, | ||
dimB : 7, | ||
dimC : 0, | ||
dimD : 2 | ||
}; | ||
aisOutB = new AisEncode (msg24b); | ||
var msg24b= {// class AB static info | ||
aistype : 24, | ||
part : 1, | ||
mmsi : IMEI_MMSI_MAPPING [devid].mmsi, | ||
cargo : IMEI_MMSI_MAPPING [devid].shiptype, | ||
callsign : IMEI_MMSI_MAPPING [devid].callsign, | ||
dimA : 0, | ||
dimB : IMEI_MMSI_MAPPING [devid].lenght || 10, | ||
dimC : 0, | ||
dimD : IMEI_MMSI_MAPPING [devid].width || 3 | ||
}; | ||
//var message=util.format ("\n24b %j\n", msg24b); | ||
if (!aisOutA.valid || !aisOutB.valid) { | ||
this.Debug (1, "Invalid msg24a=%j msg24b=%j", msg24a, msg24b); | ||
return; | ||
} | ||
// transform AIS string into a buffer linefeed ended | ||
var msgbufA = new Buffer (aisOutA.nmea + "\n"); | ||
var msgbufB = new Buffer (aisOutB.nmea + "\n"); | ||
// if UDP is defined send AISpos onto it | ||
if (this.usock) { | ||
this.usock.send(msgbufA, 0, msgbufA.length, this.uport, this.uhost, function(err, bytes) { | ||
if (err) console.log ('### Hoops BroadcastPos : UDP msg24a send [err=%s]', err); | ||
}); | ||
this.usock.send(msgbufB, 0, msgbufB.length, this.uport, this.uhost, function(err, bytes) { | ||
if (err) console.log ('### Hoops BroadcastPos : UDP msg24b send [err=%s]', err); | ||
}); | ||
} | ||
// send statics to every connected AIS clients | ||
for (var sock in this.clients) { | ||
try { | ||
//socket.write (message); | ||
aisOut = new AisEncode (msg24b); | ||
if (aisOut.valid) socket.write (aisOut.nmea +'\n'); | ||
this.clients[sock].write (msgbufA); | ||
this.clients[sock].write (msgbufB); | ||
} catch (err) { | ||
this.Debug (0, '### HOOPS BroadcastStatic lost aisclient: %s [err=%s]', this.clients[sock].uid, err); | ||
delete this.clients[sock]; | ||
} | ||
} | ||
}; | ||
@@ -174,37 +201,6 @@ | ||
DevAdapter.prototype.ClientConnect = function (socket) { | ||
var aisOut; | ||
socket.id=this.count ++; | ||
var gateway=this.controller.gateway; | ||
socket.uid="aisproxy://" + socket.remoteAddress +':'+ socket.remotePort; | ||
this.Debug (4, "New client [%s]=%s", socket.id, socket.uid); | ||
this.clients[socket.id] = socket; | ||
// each new client get a list of logged device at connection time | ||
for (var devId in gateway.activeClients) { | ||
var device= gateway.activeClients[devId]; | ||
if (device.logged && IMEI_MMSI_MAPPING [device.devid]) { | ||
this.BroadcastStatic (device.devid, socket); | ||
if (device.stamp !== undefined) { | ||
var msg18= { // standard class B Position report | ||
aistype : 18, | ||
cog : device.stamp.cog, | ||
sog : device.stamp.sog, | ||
dsc : false, | ||
repeat : false, | ||
accuracy : true, | ||
lon : device.stamp.lon, | ||
lat : device.stamp.lat, | ||
second : 1, | ||
mmsi : IMEI_MMSI_MAPPING [device.devid].mmsi | ||
}; | ||
//var message=util.format ("\n18x %j\n", msg18); | ||
//socket.write (message); | ||
aisOut = new AisEncode (msg18); | ||
if (aisOut.valid) socket.write (aisOut.nmea +'\n'); | ||
} | ||
} | ||
} | ||
}; | ||
@@ -220,3 +216,4 @@ | ||
DevAdapter.prototype.ParseBuffer = function(socket, buffer) { | ||
this.Debug (4, 'Talk AisTcpClient: %s data=%s', socket.uid, buffer); | ||
this.Debug (4, '%s data=%s', socket.uid, buffer); | ||
socket.write ("Adapter: [" + this.info + "] invalid--> " + buffer); | ||
}; | ||
@@ -223,0 +220,0 @@ |
@@ -15,2 +15,3 @@ /* | ||
* limitations under the License. | ||
* | ||
*/ | ||
@@ -68,3 +69,3 @@ | ||
function CheckArg (arg) { | ||
if (arg !== undefined) if (arg.length > 1) return (arg) | ||
if (arg !== undefined) if (arg.length > 1) return (arg); | ||
else return 0; | ||
@@ -109,3 +110,3 @@ } | ||
alt: -1 | ||
} | ||
}; | ||
break; | ||
@@ -140,3 +141,3 @@ case 19: // new protocol [sms protocol123456 18] | ||
return (data); | ||
} | ||
}; | ||
// tracker-command, 141111061820,,F,221824.000,A,4737.1076,N,00245.6550,W,0.04,0.00,,1,0,0.0%,,;" | ||
@@ -146,3 +147,3 @@ DevAdapter.prototype.ParseTrackerObd = function (cmd, args) { | ||
function CheckArg (arg) { | ||
if (arg.length > 1) return (arg) | ||
if (arg.length > 1) return (arg); | ||
else return ''; | ||
@@ -169,3 +170,3 @@ } | ||
return (data); | ||
} | ||
}; | ||
@@ -293,3 +294,3 @@ DevAdapter.prototype.ParseData = function (line) { | ||
return (data); | ||
} | ||
}; | ||
@@ -427,4 +428,2 @@ // Import debug method | ||
// Sharing one unique parser for all clients looks OK | ||
// socket.parser = this.GetParser(); | ||
}; | ||
@@ -431,0 +430,0 @@ |
@@ -21,2 +21,3 @@ /* | ||
* iphone://GerGTSTracker; etc.... | ||
* https://play.google.com/store/apps/details?id=org.opengts.client.android.cgtsfre | ||
* | ||
@@ -54,132 +55,6 @@ * Reference: http://fr.wikipedia.org/wiki/NMEA_0183 | ||
// send a commant to activate GPS tracker | ||
DevAdapter.prototype.SendCommand = function(httpclient, action, arg1) { | ||
switch (action) { | ||
case TrackerCmd.SendTo.WELLCOME: break; | ||
case TrackerCmd.SendTo.LOGOUT: | ||
httpclient.LogoutDev (); | ||
break; // active client is update at HttpClient level | ||
case TrackerCmd.SendTo.HELP: // return supported commands by this adapter | ||
var listcmd=["LOGOUT", "HELP"]; | ||
// push a notice HELP action event to gateway | ||
this.gateway.event.emit ("notice", "HELP", listcmd, this.uid, socket.uid); | ||
break; | ||
default: | ||
this.Debug (1,"Hoops GtcFree has no command=[%s]", action); | ||
return (-1); | ||
}; | ||
// return OK status | ||
this.Debug (5,"buffer=[%s]", this.packet); | ||
return (0); | ||
}; | ||
// CellTrack Free does not accept commands. | ||
DevAdapter.prototype.SendCommand = function(httpclient) {}; | ||
// return a json object with device name and position | ||
DevAdapter.prototype.QueryDevList = function(query, response) { | ||
var account = query['a']; | ||
var group = query['g']; | ||
// start with response header | ||
var jsonresponse= | ||
{Account: account | ||
,Account_desc: "Gpsd-" + account | ||
//,"TimeZone": "UTS" | ||
,DeviceList: [] | ||
}; | ||
// loop on device list | ||
for (var devid in this.gateway.activeClients) { | ||
var device= this.gateway.activeClients [devid]; | ||
// if device is valid and log then doit | ||
// if (device !== undefined && device.logged) { | ||
if (device !== undefined && device.stamp !== undefined) { | ||
jsonresponse.DeviceList.push ( | ||
{Device : device.devid | ||
,Device_desc: device.name.replace(/ /g,'-') | ||
,group : group | ||
,EventData: [ | ||
{Device: devid | ||
,Timestamp : device.stamp.acquired_at | ||
,StatusCode : 0 | ||
,Speed : device.stamp.sog | ||
,GPSPoint_lat : device.stamp.lat | ||
,GPSPoint_lon : device.stamp.lon | ||
}] | ||
}); | ||
} | ||
}; | ||
//console.log ("****JSON=%s", JSON.stringify(jsonresponse)) | ||
response.writeHeader(200, {"Content-Type": "text/plain"}); | ||
response.write(JSON.stringify(jsonresponse)); | ||
response.end(); | ||
}; | ||
/* respoonse dev track sample | ||
var test={"Account":"fulup-bzh","Account_desc":"Gpsd-fulup-bzh" | ||
,"DeviceList":[ | ||
{"Device":123456789,"Device_desc":"Fulup-HR37" | ||
,"EventData": | ||
[{"Device":123456789,"Timestamp":1413548858,"StatusCode":3,"Speed":6.8,"GPSPoint_lat":47.30231124565022,"GPSPoint_lon":-2.849232474089085} | ||
,{"Device":123456789,"Timestamp":1413548907,"StatusCode":2,"Speed":5.3,"GPSPoint_lat":47.29901180590435,"GPSPoint_lon":-2.8442291685556724} | ||
,{"Device":123456789,"Timestamp":1413548956,"StatusCode":1,"Speed":5.2,"GPSPoint_lat":47.29610186222867,"GPSPoint_lon":-2.8386510988197435} | ||
,{"Device":123456789,"Timestamp":1413549037,"StatusCode":0,"Speed":7.1,"GPSPoint_lat":47.29757485673534,"GPSPoint_lon":-2.8316258978899578} | ||
]}]} | ||
*/ | ||
// return a json object with device name and possition | ||
DevAdapter.prototype.QueryDevTrack = function(query, response) { | ||
var account = query['a']; | ||
var list = parseInt (query['l']); | ||
var devid = query['d']; | ||
var device = this.gateway.activeClients [devid]; | ||
if (device === undefined) { | ||
this.Debug (1,"Device %s Quit", devid); | ||
response.writeHeader(200, {"Content-Type": "text/plain"}); | ||
response.write("DEV_QUIT"); | ||
response.end(); | ||
return; | ||
} | ||
// DB callback return a json object with device name and possition | ||
var DBcallback = function(dbresult) { | ||
// start with response header | ||
var jsonresponse= | ||
{Account: account | ||
,Account_desc: "Gpsd-" + account | ||
//"TimeZone": "UTS" | ||
,DeviceList: [ | ||
{Device : device.devid | ||
,Device_desc: device.name.replace(/ /g,'-') | ||
,EventData: [] | ||
}]}; | ||
// for Celltrack loop is GeoJson reverse order | ||
var nnres = dbresult.length-1; | ||
if (nnres >= list-1) nnres=list-1; | ||
for (var i = nnres; i >= 0; i--) { | ||
var pos = dbresult [i]; | ||
jsonresponse.DeviceList[0].EventData.push ( | ||
{Device : device.devid | ||
,Timestamp : pos.date.getTime()/1000 | ||
,StatusCode : i | ||
,Speed : pos.speed | ||
,GPSPoint_lat : pos.lat | ||
,GPSPoint_lon : pos.lon | ||
}); | ||
}; | ||
// call back take care of returning response to device in async mode | ||
response.writeHeader(200, {"Content-Type": "text/plain"}); | ||
response.write(JSON.stringify(jsonresponse)); | ||
response.end(); | ||
}; // end callback | ||
// loop on device last postion [warning: async mode] | ||
this.gateway.backend.LookupDev (DBcallback, devid, list); | ||
}; | ||
// This routine is called from Controller each time a new http request popup | ||
@@ -199,63 +74,51 @@ DevAdapter.prototype.ProcessData = function(request, response) { | ||
// Device: http://localhost:4020/events/dev.json?a=fulup-bzh&u=demo-id&p=MyPasswd&d=123456789&l=4 | ||
if (query.id === undefined) { | ||
this.Debug (2,"Hoops: query:id not found in Http Request"); | ||
response.writeHeader(400, {"Content-Type": "text/plain"}); | ||
response.write('ERR: This is not a valid CellTracGTS request'); | ||
response.end(); | ||
return; | ||
} | ||
// for json request celltrack does not provide query.id !!!! | ||
// nasty but fast check for /events/dev.json pathname | ||
if (question.pathname.length === 16) { | ||
// group/dev {"?a":"fulup-bzh","u":"demo-id","p":"MyPasswd","g":"all","l":"1"} | ||
// devices query={"?a":"fulup-bzh","u":"demo-id","p":"MyPasswd","d":"1","l":"20"} | ||
// query={"?a":"fulup-bzh","u":"demo-id","p":"MyPasswd","d":"demo1","l":"20"} | ||
// this is a device query [at least this is how I hunderstant it !!! | ||
if (query.g !== undefined) result = JSON.stringify(this.QueryDevList (query, response)); | ||
if (query.d !== undefined) result = JSON.stringify(this.QueryDevTrack(query, response)); | ||
// Warning: previous call might be asynchronous and result to device appen after this return | ||
} else { | ||
// at this point we need a query ID | ||
if (query.id === undefined) { | ||
this.Debug (2,"Hoops: query:id not found in Http Request"); | ||
response.writeHeader(400, {"Content-Type": "text/plain"}); | ||
response.write('ERR: Invalid IMEI in Http Request'); | ||
response.end(); | ||
return; | ||
} | ||
// is user is logged try it now | ||
var device = this.gateway.activeClients [query.id]; | ||
if (device === undefined) { | ||
device= new HttpClient(this, query.id); | ||
// force authent [due to DB delay we may refuse first NMEA packets] | ||
device.LoginDev ({devid: query.id}); | ||
} | ||
// make sure the ID is an interger | ||
var devid = parseInt (query.id); | ||
if (isNaN (devid)) devid = parseInt (query.id,16)/1000; | ||
if (isNaN (devid)) { | ||
this.Debug (2,"Hoops: query:id invalid id=%s", devid); | ||
response.writeHeader(400, {"Content-Type": "text/plain"}); | ||
response.write('ERR: This is not a valid CellTracGTS request'); | ||
response.end(); | ||
return; | ||
} | ||
// we refuse packet from device until it is not log by DB backend | ||
if (device.logged !== true) { | ||
// leave 1s for DB to authenticate device before closing request | ||
this.Debug (4,"Device not login: EMEI=%s", query.id); | ||
setTimeout(function(){response.end()}, 1000); | ||
return; | ||
} | ||
// is user is logged try it now | ||
var device = this.gateway.activeClients [devid]; | ||
if (device === undefined) { | ||
Debug (5,"New CellTrac Device id=%s devid=%d", query.id, devid); | ||
device= new HttpClient(this, devid); | ||
// force authent [due to DB delay we may refuse first NMEA packets] | ||
device.LoginDev ({devid: devid}); | ||
} | ||
// this is a position update and a synchronous call | ||
switch (query.cmd) { | ||
case 'version': | ||
result = 'OK'; | ||
break; | ||
default: | ||
// if parsing abort then force line as invalid | ||
var data = new NmeaDecode(query.gprmc); | ||
if (!data.valid) { | ||
this.Debug (5,'GPRMC invalid nmeadata=%s', query.gprmc); | ||
result = "ERR-GPRMC"; | ||
} else { | ||
this.Debug (7,"--> NMEA Lat:%s Lon:%s Sog:%d Cog:%d Alt:%d Date:%s" | ||
, data.lat, data.lon, data.sog, data.cog, data.alt, data.date); | ||
device.ProcessData (data); | ||
result = "OK"; | ||
} | ||
} | ||
response.writeHeader(200, {"Content-Type": "text/plain"}); | ||
response.write(result); | ||
response.end(); | ||
// we refuse packet from device until it is not log by DB backend | ||
if (device.logged !== true) { | ||
// leave 1s for DB to authenticate device before closing request | ||
this.Debug (4,"Device not login: EMEI=%s", devid); | ||
setTimeout(function(){response.end();}, 1000); | ||
return; | ||
} | ||
// if parsing abort then force line as invalid | ||
var data = new NmeaDecode(query.gprmc); | ||
if (data.valid) { | ||
this.Debug (7,"--> NMEA Lat:%s Lon:%s Sog:%d Cog:%d Alt:%d Date:%s" | ||
, data.lat, data.lon, data.sog, data.cog, data.alt, data.date); | ||
data.cmd = TrackerCmd.GetFrom.TRACK; | ||
device.ProcessData (data); | ||
} | ||
result = "OK"; | ||
response.writeHeader(200, {"Content-Type": "text/plain"}); | ||
response.write(result); | ||
response.end(); | ||
}; | ||
@@ -262,0 +125,0 @@ |
@@ -52,4 +52,6 @@ Under GeoGate adapters take care of: | ||
Reference for GPS protocols https://www.traccar.org/protocols/ | ||
@@ -39,3 +39,2 @@ /* | ||
var QJhandle; | ||
var SockPause; | ||
var CLsockid; | ||
@@ -45,36 +44,7 @@ | ||
var FakeVesselBase = { | ||
//MMSI should fit with Simulator file name | ||
123456789: {id:00, name:'Elen Backy' ,type:01} | ||
,456789012: {id:02, name:'Dominig Oceanis31',type:01} | ||
,789123456: {id:03, name:'Lionel Ar Pesketour',type:02} | ||
,147258369: {id:03, name:'Momo Rich Man',type:02} | ||
,258369147: {id:04, name:'Mael Ferry',type:04} | ||
,741852963: {id:05, name:'Lena Miss Match',type:03} | ||
,852963741: {id:06 ,name:'Erwan Speedy',type:06} | ||
,321654987: {id:07 ,name:'Vero Cargo',type:05} | ||
,963741852: {id:08 ,name:'Nanar Gazelle',type:07} | ||
,159847387: {id:09 ,name:'Xavier Ground Ferry',type:05} | ||
,535798321: {id:10 ,name:'Remy The Racer',type:01} | ||
,179346827: {id:11 ,name:'Sinagot ar re Gozh',type:07} | ||
,785412369: {id:12 ,name:'Ky Dour',type:07} | ||
,865328021048227: {id:13, name:'Fulup 407', type:03} | ||
}; | ||
var VESSELCLASS= | ||
{01: "Sail" | ||
,02: "Fish" | ||
,03: "Car" | ||
,04: "Ferry" | ||
,05: "Cargo" | ||
,06: "Speed" | ||
,07: "Trad" | ||
}; | ||
function BackendStorage (gpsd, opts){ | ||
function BackendStorage (gateway, opts){ | ||
// prepare ourself to make debug possible | ||
this.uid="Dummy@nothing"; | ||
this.gpsd =gpsd; | ||
this.gateway =gateway; | ||
this.debug=opts.debug; | ||
@@ -84,19 +54,2 @@ this.count=0; | ||
this.storesize= 20 +1; // number of position slot/devices | ||
SockPause = opts.sockpause; | ||
// fill up Fake Vessel base with some demo values | ||
for (mmsi in FakeVesselBase) { | ||
var vessel= FakeVesselBase[mmsi]; | ||
vessel.call = (vessel.type + '-' + mmsi).toUpperCase() ; | ||
vessel.class = VESSELCLASS[vessel.type]; | ||
vessel.img = opts.rootdir + 'images/' +(vessel.name.replace(/ /g,'-') + "x250.jpg").toLowerCase(); | ||
vessel.url = opts.rootdir + 'devices/'+(vessel.name.replace(/ /g,'-') + ".html").toLowerCase(); | ||
} | ||
// default for unknown vessel | ||
this.unknown = { | ||
img: opts.rootdir + "images/unknown-devicex250.jpg", | ||
url: opts.rootdir + "devices/unknown-device.html" | ||
}; | ||
this.event = new EventEmitter(); | ||
@@ -156,26 +109,16 @@ }; | ||
BackendStorage.prototype.DummyName = function (devid) { | ||
var devname = devid.toString(); | ||
return devname.substring(devname.length-5); | ||
}; | ||
BackendStorage.prototype.LoginDev = function (device) { | ||
this.Debug (4,"Authentication accepted for device=%s", device.uid); | ||
var emeifix = this.DummyName (device.devid); | ||
device.logged = true; | ||
device.callsign = "FX-" + emeifix; | ||
device.model = device.devid; | ||
device.name = "Droid-" + emeifix; | ||
// extract vessel details from DB if exit | ||
if (FakeVesselBase[device.devid] !== undefined) { | ||
device.name = FakeVesselBase[device.devid].name; | ||
device.class= FakeVesselBase[device.devid].class; | ||
device.type = FakeVesselBase[device.devid].type; | ||
device.call = FakeVesselBase[device.devid].call; | ||
device.img = FakeVesselBase[device.devid].img; | ||
device.url = FakeVesselBase[device.devid].url; | ||
} else { | ||
device.class= 0; | ||
device.type = 0; | ||
device.call = "NoCall"; | ||
device.img = this.unknown.img; | ||
device.url = this.unknown.url; | ||
} | ||
// If default name not provided by the adapter, create one now | ||
if (device.name === undefined || device.name === false || device.name === null) device.name = "Test-Dev-" + this.count; | ||
// Create Ram storage array for tracking this.storesize positions | ||
@@ -202,3 +145,3 @@ if (device.posIdx === undefined) { | ||
this.Debug(4, "Obd Device:%s", device.uid); | ||
} | ||
}; | ||
@@ -205,0 +148,0 @@ BackendStorage.prototype.UpdatePosDev = function (device) { |
@@ -242,11 +242,14 @@ /* | ||
sqlQuery.on("result", function (result) { | ||
self.Debug(9, "sqlQuery %j", result); | ||
self.event.emit ("dev-auth", device); | ||
self.Debug(9, "sqlResponse %j", result); | ||
// update active device pool [note device.devid is set by GpsdClient before SQL login] | ||
device.name = result.devname; // friendly name extracted from database | ||
device.sqlid = result.id; // this is MySQL unique ID and not device's DEVID | ||
device.track = result.track; | ||
device.obd = result.obd; | ||
device.logged = true; // marked device as knowned from database | ||
device.name = result.devname; // friendly name extracted from database | ||
device.callsign= result.callsign; | ||
device.model = result.model; | ||
device.sqlid = result.id; // this is MySQL unique ID and not device's DEVID | ||
device.track = result.track; | ||
device.obd = result.obd; | ||
device.logged = true; // marked device as knowned from database | ||
self.event.emit ("dev-auth", device); | ||
}); | ||
@@ -253,0 +256,0 @@ |
#!/usr/bin/env node | ||
/* | ||
* Copyright 2014 Fulup Ar Foll | ||
* Copyright 2015 Fulup Ar Foll | ||
* | ||
@@ -21,6 +21,6 @@ * Licensed under the Apache License, Version 2.0 (the "License"); | ||
/* | ||
* Tracker2Json is a small debug tool. It wait on a given TCP port for incoming connection. | ||
* Transforms received packet with a given adapter and display result on console. | ||
* Json2AIS waits on a given TCP port for incoming connection. | ||
* Transforms received JSON/AIS packet in NMEA binary Packet and push then on UDP | ||
* | ||
* Tracker2Json | ||
* Json2AIS | ||
* --adapter=xxxx // adapter file | ||
@@ -31,3 +31,3 @@ * --verbose=1 // display incoming binary NMEA paquet | ||
* Examples: | ||
* Tracker2Json --adapter=./conf/DummyBackend.conf | ||
* Json2AIS --adapter=./conf/DummyBackend.conf | ||
* | ||
@@ -34,0 +34,0 @@ */ |
@@ -26,3 +26,3 @@ /* | ||
,inactivity : 900 // remove device from active list after xxxs inactivity [default 600s] | ||
,sockpause : 250 // delay in ms in beetween each replay data [0=nowait] | ||
,sockpause : 250 // delay in ms in beetween each reply data [0=nowait] | ||
,storesize : 50 // size of postition/device kept in ram for "db search" command | ||
@@ -29,0 +29,0 @@ ,debug : 1 // debug level 0=none 9=everything |
@@ -28,11 +28,13 @@ /* | ||
function PositionObj (data) { | ||
this.lat = parseFloat(data.lat); | ||
this.lon = parseFloat(data.lon); | ||
this.sog = parseFloat(data.sog); | ||
this.cog = parseFloat(data.cog); | ||
this.alt = parseFloat(data.alt); | ||
this.moved = parseInt(data.moved); | ||
this.elapsed= parseInt(data.elapsed); | ||
this.valid = parseInt(+data.valid); | ||
this.msg = parseInt (data.cmd); | ||
this.lat = parseFloat(data.lat); | ||
this.lon = parseFloat(data.lon); | ||
this.sog = parseFloat(data.sog) || 0; | ||
this.cog = parseFloat(data.cog) || 0; | ||
this.alt = parseFloat(data.alt) || 0; | ||
this.moved = parseInt(data.moved) || -1; | ||
this.elapsed= parseInt(data.elapsed) || -1; | ||
this.valid = parseInt(+data.valid); | ||
this.acquired_at = data.acquired_at; | ||
this.gpsdate= data.date; | ||
} | ||
@@ -50,7 +52,8 @@ | ||
this.socket = null; // we cannot rely on socket to talk to device | ||
this.devid = false; // we get uid directly from device | ||
this.name = false; | ||
this.logged = false; | ||
this.devid = false; // we get uid directly from device | ||
this.name = false; | ||
this.logged = false; | ||
this.alarm = 0; // count alarm messages | ||
this.count = 0; // generic counter used by file backend | ||
this.errorcount = 0; // number of ignore messages | ||
}; | ||
@@ -61,3 +64,2 @@ | ||
// This method is fast but very approximative for close points | ||
@@ -91,4 +93,2 @@ // User may expect 50% of error for distance of few 100m | ||
this.class = controller.adapter.info; | ||
this.model = data.model; | ||
this.call = data.call; | ||
@@ -112,3 +112,2 @@ //Update/Create device socket store by uid at gateway level | ||
// Action depending on data parsed by the adapter | ||
@@ -125,2 +124,3 @@ GpsdHttpClient.prototype.ProcessData = function(data) { | ||
switch (data.cmd) { | ||
@@ -143,32 +143,36 @@ // This device is not register inside GpsdHttpClient Object | ||
if (this.stamp !== undefined) { | ||
var moved = parseInt (this.Distance (this.stamp, data)); | ||
var moved = parseInt (this.Distance (this.stamp, data)); | ||
//console.log ("**** pos= %s,%s Stamp=%s,%s Moved=%s", data.lat, data.lon, this.stamp.lon, this.stamp.lat, moved); | ||
// compute elapsed time since last update | ||
var elapsed = parseInt ((data.acquired_at - this.stamp.date) / 1000); // in seconds | ||
var sogms = parseInt (moved/elapsed); // NEED TO BE KNOWN: with short tic sog is quicky overestimated by 100% !!! | ||
var elapsed = parseInt((data.acquired_at - this.stamp.acquired_at)/1000) ; // in seconds | ||
var speedms = parseInt (moved/elapsed); // NEED TO BE KNOWN: with short tic speed is quicky overestimated by 100% !!! | ||
// usefull human readable info for control console | ||
data.moved = moved; | ||
data.elapsed = elapsed; | ||
data.moved = moved; | ||
data.elapsed = elapsed; | ||
// if moved less than mindist or faster than maxsog check maxtime value | ||
if (moved < this.controller.svcopts.mindist || sogms > controller.svcopts.maxsog) { | ||
this.Debug(2,"%s Dev %s Data ignored moved %dm<%dm ?", this.count, this.devid, moved, this.controller.svcopts.mindist); | ||
// if moved less than mindist or faster than maxspeed check maxtime value | ||
if (moved < this.controller.svcopts.mindist) { | ||
this.Debug(2,"%d Dev=%s Data ignored moved %dm<%dm ?", this.errorcount, this.devid, moved, this.controller.svcopts.mindist); | ||
// should we force a DB update because maxtime ? | ||
if (elapsed < controller.svcopts.maxtime) update = false; | ||
if (elapsed < this.controller.svcopts.maxtime) update = false; | ||
} | ||
// if moved less than mindist or faster than maxspeed check maxtime value | ||
if (speedms > this.controller.svcopts.maxspeed) { | ||
this.Debug(2,"%d Dev %s Data ignored speed %dm/s >%dm/s ?", this.errorcount, this.devid, speedms, this.controller.svcopts.maxspeed); | ||
// we only ignore maxErrorCount message, then we restart data acquisition | ||
if (this.errorcount++ < this.controller.svcopts.maxerrors) update = false; | ||
} | ||
} else { | ||
// usefull human readable info for control console | ||
data.moved = 0; | ||
data.elapsed = 0; | ||
data.moved = 0; | ||
data.elapsed = 0; | ||
} | ||
// update database and store current device location in object for mindist computation | ||
if (update) { // update device last position in Ram/Database | ||
this.stamp = new PositionObj(this.devid, data); | ||
this.stamp = new PositionObj(data); | ||
gateway.backend.UpdatePosDev (this, this.stamp); | ||
} else { | ||
this.Debug(6,"%s Dev %s Data %s ignored moved %dm<%dm ?", this.count, this.devid, moved, this.controller.svcopts.mindist); | ||
this.Debug(6,"%s Dev=%s ignored moved %dm<%dm ?", this.count, this.devid, moved, this.controller.svcopts.mindist); | ||
} | ||
@@ -175,0 +179,0 @@ break; |
{ | ||
"name" : "ggserver", | ||
"description" : "GeoGate is an opensource GPS tracking server framework", | ||
"version" : "0.1.16", | ||
"version" : "0.1.17", | ||
"author" : { | ||
@@ -6,0 +6,0 @@ "name" : "Fulup Ar Foll", |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
252043
37
5033
16
6