├── MC7710-enable-gps.txt ├── README.md ├── gps-to-email ├── gps-to-url ├── mikrotik_genxml.php ├── mikrotikgps.php ├── mikrotiklocation.html ├── phpsqlajax_dbinfo.php ├── schedule-command └── usb-reset /MC7710-enable-gps.txt: -------------------------------------------------------------------------------- 1 | 1 - Turn off "DirectiIP" mode. 2 | /port firmware set ignore-directip-modem=yes 3 | 4 | 2 - Restart RouterOS. 5 | /system reboot 6 | 7 | 3 - Open a terminal to the modem on the 3 channel. 8 | /system serial-terminal usb1 channel=3 9 | 10 | 4 - Run the following AT commands. 11 | AT!ENTERCND="A710" 12 | AT!GPSAUTOSTART=1,1,255,1000,1 13 | 14 | 5 - Close the terminal session 15 | > Ctrl+A >>>> Q 16 | 17 | 6 - Turn on "DirectiIP" mode. 18 | /port firmware set ignore-directip-modem=no 19 | 20 | 7 - Restart RouterOS. 21 | /system reboot 22 | 23 | 8 - Enable GPS. 24 | /system gps set port=usb1 channel=0 enabled=yes 25 | 26 | 9 - Test the GPS is working. 27 | /system gps monitor 28 | 29 | [admin@MikroTik] > system gps monitor 30 | date-and-time: jan/01/2015 23:24:54 31 | latitude: N XX XX' XX.XXX'' 32 | longitude: E XX XX' XX.XXX'' 33 | altitude: 20.600000m 34 | speed: 0.000000 km/h 35 | destination-bearing: none 36 | true-bearing: 180.699997 deg. True 37 | magnetic-bearing: 180.699997 deg. Mag 38 | valid: yes 39 | satellites: 7 40 | -- [Q quit|D dump|C-z pause] 41 | 42 | If you see the above with latitude and longitude coordinates then GPS is working. 43 | Copy and paste these to Google maps to check the accuracy. 44 | 45 | NOTE: You will need a GPS antenna connected to the middle "GPS" u.fl connector and the GPS antenna will need to be outside 46 | (with a clear view of the sky) to work. 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mikrotik-gps 2 | ============ 3 | 4 | Scripts for tracking Mikrotik Routers by sending GPS coordinates to an e-mail address. 5 | 6 | Requires a Mikrotik RoutherBoard + USB GPS device or LTE modem with built-in GPS receiver. 7 | 8 | gps-to-email script originally from the Mikrotik Wiki:- 9 | http://wiki.mikrotik.com/wiki/GPS_text_file_converter_to_Google_Earth/Maps 10 | 11 | Testing done using a RB912UAG-2HPnD with Sierra Wireless MC7710 (FW version needs to be "03.05.24" and GPS autostart NMEA output needs to be enabled. See "MC7710-enable-gps.txt" for instructions. 12 | 13 | /!\ PLEASE NOTE /!\ 14 | ------------- 15 | 16 | The GPS package doesn't work correctly in the current firmware release (RouterOS v6.24) you'll need to upgrade to "RouterOS v6.25rc" once available and the final release as soon as that is available. 17 | 18 | gps-to-email 19 | ------------ 20 | 21 | Script to send the GPS coordinated to an e-mail address. 22 | E-Mails are only sent when the position has changed. 23 | The script has to be scheduled to run using "system scheduler". Depending on your requirements this could be scheduled to run the gps-to-email script every 20 seconds, 5 minutes, 30 minutes, hour or daily. 24 | 25 | gps-to-url 26 | ---------- 27 | 28 | This script is a modified version of the above gps-to-email script. Instead of sending an e-mail it uses fetch to request a URL. This URL is the "mikrotikgps.php" file which uses php GET to get the data from the URL and push it into a database. This makes it possible to then use this data to build a map using the coordinates and other data. 29 | -------------------------------------------------------------------------------- /gps-to-email: -------------------------------------------------------------------------------- 1 | # CHANGE BELOW E-MAIL ADDRESS 2 | :local email "myuser@mydomain.com"; 3 | 4 | :system gps monitor file="gps.txt"; 5 | :global gpstext [/file get gps.txt contents]; 6 | :local longstart [:find $gpstext "longitude" -1]; 7 | :local longend [:find $gpstext "\n" $longstart]; 8 | :local latstart [:find $gpstext "latitude" -1]; 9 | :local latend [:find $gpstext "\n" $latstart]; 10 | :local validstart [:find $gpstext "valid" -1]; 11 | :local validend [:find $gpstext "\n" $validstart]; 12 | :local valid false; 13 | :local zeros ""; 14 | 15 | :if ([:find $gpstext "yes" $validstart] > 0) do={:set valid true;}; 16 | 17 | :global longitude [:pick $gpstext ($longstart + 11) $longend]; 18 | :local degreestart [:find $longitude " " -1]; 19 | :local minutestart [:find $longitude " " $degreestart]; 20 | :local secondstart [:find $longitude "'" $minutestart]; 21 | 22 | :local secondend; 23 | :local secfract; 24 | 25 | :if ([:len [:find $longitude "." 0]] < 1) do={ 26 | :set secondend [:find $longitude "'" $secondstart]; 27 | :set secfract "0"; 28 | } else={ 29 | :set secondend [:find $longitude "." $secondstart]; 30 | :set secfract [:pick $longitude ($secondend + 1) ($secondend + 2)]; 31 | }; 32 | 33 | :local longdegree; 34 | :local longdegreelink; 35 | 36 | :if ([:pick $longitude 0 1] = "W") do={ 37 | :set longdegree "-"; 38 | :set longdegreelink "W"; 39 | } else={ 40 | :set longdegree "+"; 41 | :set longdegreelink "E"; 42 | }; 43 | 44 | :set longdegree ($longdegree . [:pick $longitude 2 $minutestart]); 45 | :set longdegreelink ($longdegreelink . [:pick $longitude 2 $minutestart]); 46 | :local longmin [:pick $longitude ($minutestart + 1) $secondstart]; 47 | :local longsec [:pick $longitude ($secondstart + 2) $secondend]; 48 | :local longfract ((([:tonum $longmin] * 6000) + ([:tonum $longsec] * 100) + ([:tonum $secfract] * 10) ) / 36); 49 | 50 | :while (([:len $zeros] + [:len $longfract]) < 4) do={ 51 | :set zeros ($zeros . "0"); 52 | }; 53 | 54 | :global newlong ($longdegree . "." . $zeros . $longfract); 55 | :global newlonglink ($longdegreelink . "." . $zeros . $longfract); 56 | 57 | :global latitude [:pick $gpstext (latstart + 10) $latend]; 58 | :set degreestart [:find $latitude " " -1]; 59 | :set minutestart [:find $latitude " " $degreestart]; 60 | :set secondstart [:find $latitude "'" $minutestart]; 61 | 62 | :if ([:len [:find $latitude "." 0]] < 1) do={ 63 | :set secondend [:find $latitude "'" $secondstart]; 64 | :set secfract "0"; 65 | } else={ 66 | :set secondend [:find $latitude "." $secondstart]; 67 | :set secfract [:pick $latitude ($secondend + 1) ($secondend +2)]; 68 | }; 69 | 70 | :local latdegree; 71 | :local latdegreelink; 72 | 73 | :if ([:pick $latitude 0 1] = "N") do={ 74 | :set latdegree "+"; 75 | :set latdegreelink "N"; 76 | } else={ 77 | :set latdegree "-"; 78 | :set latdegreelink "S"; 79 | }; 80 | 81 | :set latdegree ($latdegree . [:pick $latitude 2 $minutestart]); 82 | :set latdegreelink ($latdegreelink . [:pick $latitude 2 $minutestart]); 83 | :local latmin [:pick $latitude ($minutestart + 1) $secondstart]; 84 | :local latsec [:pick $latitude ($secondstart + 2) $secondend]; 85 | :local latfract ((([:tonum $latmin] * 6000) + ([:tonum $latsec] * 100) +([:tonum $secfract] * 10)) / 36); 86 | 87 | :set zeros ""; 88 | 89 | :while (([:len $zeros] + [:len $latfract]) < 4) do={ 90 | :set zeros ($zeros . "0"); 91 | }; 92 | 93 | :global newlat ($latdegree . "." . $zeros . $latfract); 94 | :global newlatlink ($latdegreelink . "." . $zeros . $latfract); 95 | 96 | :global coordinates ($newlong . "," . $newlat); 97 | 98 | :global linkout "http://maps.google.com?q=$newlatlink+$newlonglink"; 99 | :global SMlinkout "http://www.openstreetmap.org/?lat=$newlat&lon=$newlong&zoom=8&layers=M"; 100 | 101 | :global kmlout " 102 | 103 | 104 | My router 105 | My router's location 106 | 107 | $coordinates 108 | 109 | 110 | 111 | "; 112 | 113 | :if (valid) do={ 114 | :global oldpos; 115 | 116 | :if ($oldpos != $coordinates) do={ 117 | /file set [/file find name=gps.kml] contents=$kmlout 118 | /tool e-mail 119 | send to=$email subject="Router move" body="Moved to $latitude $longitude\r\n$linkout\r\n$SMlinkout" file=gps.kml 120 | :set oldpos $coordinates; 121 | }; 122 | } else={ 123 | /tool e-mail 124 | send to=$email subject="Router gps position invalid" body="Router gps position invalid" 125 | }; 126 | -------------------------------------------------------------------------------- /gps-to-url: -------------------------------------------------------------------------------- 1 | # CHANGE BELOW SERVER BELOW TO YOUR SERVERS DOMAIN OR IP ADDRESS 2 | :local server "change.me.com"; 3 | 4 | # Get GPS info and find variables 5 | :system gps monitor file="gps.txt"; 6 | :global gpstext [/file get gps.txt contents]; 7 | :local datestart [:find $gpstext "time: "]; 8 | :local dateend [:find $gpstext "latitude"]; 9 | :local date [:pick $gpstext ($datestart +6) ($dateend -14)] 10 | :local longstart [:find $gpstext "longitude" -1]; 11 | :local longend [:find $gpstext "\n" $longstart]; 12 | :local latstart [:find $gpstext "latitude" -1]; 13 | :local latend [:find $gpstext "\n" $latstart]; 14 | :local validstart [:find $gpstext "valid" -1]; 15 | :local validend [:find $gpstext "\n" $validstart]; 16 | :local speedstart [:find $gpstext "speed"]; 17 | :local speedend [:find $gpstext "." $speedstart]; 18 | :local speed [;pick $gpstext ($speedstart +7) ($speedend +3)]; 19 | :local altitudestart [:find $gpstext "altitude"]; 20 | :local altitudeend [:find $gpstext "." $altitudestart]; 21 | :local altitude [;pick $gpstext ($altitudestart +10) ($altitudeend +3)]; 22 | :local satellitesstart [:find $gpstext "satellites"]; 23 | :local satellitesend [:find $gpstext "\n" $satellitesstart]; 24 | :local satellites [;pick $gpstext ($satellitesstart +12) ($satellitesend)]; 25 | :local valid false; 26 | :local zeros ""; 27 | 28 | # Get Ethernet details and set mac variable 29 | :interface ethernet print detail from=ether1 file=eth1details.txt 30 | :global eth1details [/file get "eth1details.txt" contents]; 31 | :local macstart [:find $eth1details "orig"]; 32 | :local mac [:pick $eth1details ($macstart +17) ($macstart +34)]; 33 | 34 | # Get identity variable 35 | :local identity [:system identity get value-name=name]; 36 | 37 | # Get LTE1 info, set signal and technology variables 38 | :interface lte info lte1 file="lte1info.txt" 39 | :local lte1info [:file get lte1info.txt contents]; 40 | :local sigstart [:find $lte1info "signal"]; 41 | :local sigend [:find $lte1info "dBm" $sigstart]; 42 | :local signal [:pick $lte1info ($sigstart +16) ($sigend -1)]; 43 | :local techstart [:find $lte1info "access"]; 44 | :local techend [:find $lte1info "\n" $techstart]; 45 | :local techno [:pick $lte1info ($techstart +19) ($techend)]; 46 | 47 | :local technology; 48 | :if ($techno ="GSM compact") do={[:set technology "GSM";]} 49 | :if ($techno ="3G") do={:set technology "UMTS";} 50 | :if ($techno ="Evolved 3G (LTE)") do={[:set technology "LTE";]} 51 | 52 | :if ([:find $gpstext "yes" $validstart] > 0) do={:set valid true;}; 53 | 54 | :global longitude [:pick $gpstext ($longstart + 11) $longend]; 55 | :local degreestart [:find $longitude " " -1]; 56 | :local minutestart [:find $longitude " " $degreestart]; 57 | :local secondstart [:find $longitude "'" $minutestart]; 58 | 59 | :local secondend; 60 | :local secfract; 61 | 62 | :if ([:len [:find $longitude "." 0]] < 1) do={ 63 | :set secondend [:find $longitude "'" $secondstart]; 64 | :set secfract "0"; 65 | } else={ 66 | :set secondend [:find $longitude "." $secondstart]; 67 | :set secfract [:pick $longitude ($secondend + 1) ($secondend + 2)]; 68 | }; 69 | 70 | :local longdegree; 71 | :local longdegreelink; 72 | 73 | :if ([:pick $longitude 0 1] = "W") do={ 74 | :set longdegree "-"; 75 | :set longdegreelink "W"; 76 | } else={ 77 | :set longdegree "+"; 78 | :set longdegreelink "E"; 79 | }; 80 | 81 | :set longdegree ($longdegree . [:pick $longitude 2 $minutestart]); 82 | :set longdegreelink ($longdegreelink . [:pick $longitude 2 $minutestart]); 83 | :local longmin [:pick $longitude ($minutestart + 1) $secondstart]; 84 | :local longsec [:pick $longitude ($secondstart + 2) $secondend]; 85 | :local longfract ((([:tonum $longmin] * 6000) + ([:tonum $longsec] * 100) + ([:tonum $secfract] * 10) ) / 36); 86 | 87 | :while (([:len $zeros] + [:len $longfract]) < 4) do={ 88 | :set zeros ($zeros . "0"); 89 | }; 90 | 91 | :global newlong ($longdegree . "." . $zeros . $longfract); 92 | :global newlonglink ($longdegreelink . "." . $zeros . $longfract); 93 | 94 | :global latitude [:pick $gpstext (latstart + 10) $latend]; 95 | :set degreestart [:find $latitude " " -1]; 96 | :set minutestart [:find $latitude " " $degreestart]; 97 | :set secondstart [:find $latitude "'" $minutestart]; 98 | 99 | :if ([:len [:find $latitude "." 0]] < 1) do={ 100 | :set secondend [:find $latitude "'" $secondstart]; 101 | :set secfract "0"; 102 | } else={ 103 | :set secondend [:find $latitude "." $secondstart]; 104 | :set secfract [:pick $latitude ($secondend + 1) ($secondend +2)]; 105 | }; 106 | 107 | :local latdegree; 108 | :local latdegreelink; 109 | 110 | :if ([:pick $latitude 0 1] = "N") do={ 111 | :set latdegree "+"; 112 | :set latdegreelink "N"; 113 | } else={ 114 | :set latdegree "-"; 115 | :set latdegreelink "S"; 116 | }; 117 | 118 | :set latdegree ($latdegree . [:pick $latitude 2 $minutestart]); 119 | :set latdegreelink ($latdegreelink . [:pick $latitude 2 $minutestart]); 120 | :local latmin [:pick $latitude ($minutestart + 1) $secondstart]; 121 | :local latsec [:pick $latitude ($secondstart + 2) $secondend]; 122 | :local latfract ((([:tonum $latmin] * 6000) + ([:tonum $latsec] * 100) +([:tonum $secfract] * 10)) / 36); 123 | 124 | :set zeros ""; 125 | 126 | :while (([:len $zeros] + [:len $latfract]) < 4) do={ 127 | :set zeros ($zeros . "0"); 128 | }; 129 | 130 | :global newlat ($latdegree . "." . $zeros . $latfract); 131 | :global newlatlink ($latdegreelink . "." . $zeros . $latfract); 132 | 133 | :global coordinates ($newlong . "," . $newlat); 134 | 135 | # SEND TO SERVER IF THE COORDINATES HAVE CHANGED 136 | :if (valid) do={ 137 | :global oldpos; 138 | 139 | :if ($oldpos != $coordinates) do={ 140 | { 141 | :local urlstring "http://$server/mikrotikgps.php\?identity=$identity&mac=$mac&latitude=$latitude&longitude=$longitude&lat=$newlat&lng=$newlong&date=$date&dbm=$signal&technology=$technology&speed=$speed&altitude=$altitude&satellites=$satellites"; 142 | :local urlEncoded; 143 | :for i from=0 to=([:len $urlstring] - 1) do={ 144 | :local char [:pick $urlstring $i] 145 | :if ($char = " ") do={ 146 | :set $char "%20" 147 | } 148 | :if ($char = "-") do={ 149 | :set $char "%2D" 150 | } 151 | :if ($char = "+") do={ 152 | :set $char "%2B" 153 | } 154 | :set urlEncoded ($urlEncoded . $char) 155 | } 156 | :tool fetch url="$urlEncoded" mode=http dst-path=gps-to-url; 157 | } 158 | :set oldpos $coordinates; 159 | :global counter; 160 | :set counter 0; 161 | }; 162 | } else={ 163 | :global counter; 164 | :set counter ($counter + 1); 165 | :log info "GPS not valid, count = $counter"; 166 | :if ($counter = 12) do={ 167 | :system routerboard usb power-reset duration=1; 168 | :set counter 0; 169 | }; 170 | -------------------------------------------------------------------------------- /mikrotik_genxml.php: -------------------------------------------------------------------------------- 1 | createElement("markers"); 9 | $parnode = $dom->appendChild($node); 10 | 11 | // Opens a connection to a MySQL server 12 | 13 | $connection=mysql_connect ('localhost', $username, $password); 14 | if (!$connection) { die('Not connected : ' . mysql_error());} 15 | 16 | // Set the active MySQL database 17 | 18 | $db_selected = mysql_select_db($database, $connection); 19 | if (!$db_selected) { 20 | die ('Can\'t use db : ' . mysql_error()); 21 | } 22 | 23 | // Select only markers that are less than a day old 24 | $query = "SELECT * FROM `gps` WHERE `datetime` >= NOW() - INTERVAL 1 DAY"; 25 | 26 | $result = mysql_query($query); 27 | if (!$result) { 28 | die('Invalid query: ' . mysql_error()); 29 | } 30 | 31 | header("Content-type: text/xml"); 32 | 33 | // Iterate through the rows, adding XML nodes for each 34 | 35 | while ($row = @mysql_fetch_assoc($result)){ 36 | // ADD TO XML DOCUMENT NODE 37 | $node = $dom->createElement("marker"); 38 | $newnode = $parnode->appendChild($node); 39 | $newnode->setAttribute("identity",$row['identity']); 40 | $newnode->setAttribute("mac", $row['mac']); 41 | $newnode->setAttribute("date", $row['datetime']); 42 | $newnode->setAttribute("lat", $row['lat']); 43 | $newnode->setAttribute("lng", $row['lng']); 44 | $newnode->setAttribute("dbm", $row['dbm']); 45 | $newnode->setAttribute("technology", $row['technology']); 46 | $newnode->setAttribute("speed", $row['speed']); 47 | $newnode->setAttribute("altitude", $row['altitude']); 48 | $newnode->setAttribute("satellites", $row['satellites']); 49 | } 50 | 51 | echo $dom->saveXML(); 52 | 53 | ?> 54 | -------------------------------------------------------------------------------- /mikrotikgps.php: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /mikrotiklocation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mikrotik Location 6 | 7 | 86 | 87 | 88 | 89 | 90 |
91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /phpsqlajax_dbinfo.php: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /schedule-command: -------------------------------------------------------------------------------- 1 | system script run gps-to-email; 2 | -------------------------------------------------------------------------------- /usb-reset: -------------------------------------------------------------------------------- 1 | system routerboard usb power-reset duration=1; 2 | --------------------------------------------------------------------------------