node-red-contrib-tractive 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,38 +1,112 @@
1
1
  # node-red-contrib-tractive
2
2
 
3
- A Node-RED palette for integrating [Tractive](https://tractive.com) GPS trackers into your flows.
3
+ A Node-RED palette for the [Tractive](https://tractive.com) GPS tracker API. Monitor your pet's battery level, location, and history — and control LED and buzzer — directly from your flows.
4
4
 
5
5
  ## Installation
6
6
 
7
+ Install via the Node-RED Palette Manager (search for `node-red-contrib-tractive`), or from the command line in your Node-RED data directory:
8
+
7
9
  ```bash
8
- cd ~/.node-red
9
10
  npm install node-red-contrib-tractive
10
11
  ```
11
12
 
12
- Or install directly from the Node-RED palette manager by searching for `node-red-contrib-tractive`.
13
-
14
13
  ## Nodes
15
14
 
16
- | Node | Description |
17
- |------|-------------|
18
- | `tractive-config` | Shared credentials node — stores your Tractive email/password securely |
19
- | `tractive-location` | Get the current GPS location of a tracker |
20
- | `tractive-tracker` | Get tracker info or hardware status (battery level, signal) |
21
- | `tractive-history` | Get location history for a tracker over a time window |
22
- | `tractive-pets` | Get all pets or a specific pet on the account |
23
- | `tractive-control` | Send commands to a tracker (live tracking on/off) |
15
+ ### tractive-config
16
+
17
+ A configuration node that stores your Tractive account credentials. One config node per account shared across all `tractive-tracker` nodes in your flow.
18
+
19
+ | Field | Description |
20
+ |----------|-------------------------------------|
21
+ | Email | Your Tractive account email |
22
+ | Password | Your Tractive account password |
23
+
24
+ Authentication is performed automatically when the first operation runs.
25
+
26
+ ---
27
+
28
+ ### tractive-tracker
24
29
 
25
- ## Usage
30
+ Calls the Tractive API for a specific tracker. Configure the **Tracker ID** once (find it in the Tractive app under **Settings → Device → Device ID**) and select the operation.
26
31
 
27
- 1. Add a **tractive-config** node and enter your Tractive account credentials.
28
- 2. Connect any other Tractive node to the config node.
29
- 3. Pass a `trackerID` in `msg.payload` or configure it directly on the node.
30
- 4. Results are returned in `msg.payload`.
32
+ #### Operations
31
33
 
32
- ## Attribution
34
+ | Operation | Description |
35
+ |-------------------------|----------------------------------------------------------|
36
+ | Get hardware | Battery level and charging state |
37
+ | Get location | Latest GPS fix with coordinates and address |
38
+ | Get history | Location history (requires `msg.from` and `msg.to`) |
39
+ | Live tracking ON / OFF | Enable or disable 2.5-second position updates |
40
+ | LED ON / OFF | Trigger the tracker's LED light |
41
+ | Buzzer ON / OFF | Trigger the tracker's buzzer |
42
+ | Get pets | List all pets on the account |
43
+ | Get all trackers | List all trackers on the account |
33
44
 
34
- Built on [tractive](https://github.com/FAXES/tractive) by [FAXES](https://github.com/FAXES) — ISC licence.
45
+ #### Runtime overrides
46
+
47
+ | Property | Description |
48
+ |-----------------|------------------------------------------------|
49
+ | `msg.trackerID` | Overrides the Tracker ID set in the node |
50
+ | `msg.operation` | Overrides the operation set in the node |
51
+ | `msg.from` | Start timestamp in ms (Get history only) |
52
+ | `msg.to` | End timestamp in ms (Get history only) |
53
+
54
+ #### Output
55
+
56
+ `msg.payload` contains the raw API response object.
57
+
58
+ #### Example — battery monitor
59
+
60
+ ```
61
+ [inject every 5 min] → [tractive-tracker: getTrackerHardware] → [msg.payload.battery_level] → [display]
62
+ ```
63
+
64
+ ## JavaScript library
65
+
66
+ The package also works as a standalone ESM library:
67
+
68
+ ```js
69
+ import tractive from 'node-red-contrib-tractive';
70
+
71
+ await tractive.connect('email@example.com', 'password');
72
+
73
+ const hw = await tractive.getTrackerHardware('YOUR_TRACKER_ID');
74
+ console.log(hw.battery_level); // e.g. 85
75
+
76
+ const location = await tractive.getTrackerLocation('YOUR_TRACKER_ID');
77
+ console.log(location.latlong); // e.g. [-33.86, 151.20]
78
+ ```
79
+
80
+ ### All functions
81
+
82
+ ```js
83
+ // Account
84
+ getAccountInfo()
85
+ getAccountSubscriptions()
86
+ getAccountSubscription(subscriptionID)
87
+ getAccountShares()
88
+
89
+ // Pet
90
+ getPets()
91
+ getPet(petID)
92
+
93
+ // Tracker
94
+ getAllTrackers()
95
+ getTracker(trackerID)
96
+ getTrackerLocation(trackerID)
97
+ getTrackerHardware(trackerID) // includes battery_level, charging_state
98
+ getTrackerHistory(trackerID, from, to) // from/to are timestamps in ms
99
+
100
+ // Commands
101
+ liveOn(trackerID)
102
+ liveOff(trackerID)
103
+ LEDOn(trackerID)
104
+ LEDOff(trackerID)
105
+ buzzerOn(trackerID)
106
+ buzzerOff(trackerID)
107
+ ```
35
108
 
36
- ## Licence
109
+ ## Notes
37
110
 
38
- MIT
111
+ - Rate-limited requests (HTTP 4006) are automatically retried up to 3 times with a 2-second delay.
112
+ - This package is not affiliated with or maintained by Tractive. Tractive is a registered trademark of Tractive GmbH.
package/index.js CHANGED
@@ -1 +1,116 @@
1
- // Nodes registered here once built
1
+ import * as tAccount from './src/account.js';
2
+ import * as tPet from './src/pet.js';
3
+ import * as tTracker from './src/tracker.js';
4
+ import * as tCommands from './src/commands.js';
5
+
6
+ const TractiveClient = "6536c228870a3c8857d452e8";
7
+
8
+ globalThis.accountDetails = {
9
+ email: "",
10
+ password: ""
11
+ };
12
+
13
+ globalThis.gloOpts = {
14
+ method: "GET",
15
+ hostname: "graph.tractive.com",
16
+ path: ``,
17
+ headers: {
18
+ "X-Tractive-Client": TractiveClient,
19
+ "Authorization": `Bearer ${accountDetails.token}`,
20
+ "content-type": "application/json"
21
+ }
22
+ };
23
+
24
+ globalThis.isAuthenticated = function() {
25
+ if(accountDetails?.token) return true;
26
+ return false;
27
+ }
28
+
29
+ async function authenticate() {
30
+ const options = {
31
+ method: "POST",
32
+ headers: {
33
+ 'X-Tractive-Client': TractiveClient,
34
+ 'Content-Type': "application/json"
35
+ }
36
+ };
37
+
38
+ const url = `https://graph.tractive.com/4/auth/token?grant_type=tractive&platform_email=${encodeURIComponent(accountDetails.email)}&platform_token=${encodeURIComponent(accountDetails.password)}`;
39
+
40
+ try {
41
+ const res = await fetch(url, options);
42
+ const data = await res.json();
43
+ accountDetails.token = data.access_token;
44
+ accountDetails.uid = data.user_id;
45
+ globalThis.gloOpts = {
46
+ method: "GET",
47
+ hostname: "graph.tractive.com",
48
+ path: ``,
49
+ headers: {
50
+ "X-Tractive-Client": TractiveClient,
51
+ "Authorization": `Bearer ${accountDetails.token}`,
52
+ "content-type": "application/json"
53
+ }
54
+ };
55
+ return true;
56
+ } catch (err) {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ async function connect(email, password) {
62
+ accountDetails.email = email;
63
+ accountDetails.password = password;
64
+ await authenticate();
65
+ return isAuthenticated() ? true : false;
66
+ }
67
+
68
+ async function getTrackerGeofences(trackerID) {
69
+ if(!isAuthenticated()) return console.log('Not authenticated.');
70
+ const url = `https://graph.tractive.com/4/tracker/${trackerID}/geofences`;
71
+ const res = await fetch(url, {
72
+ method: gloOpts.method,
73
+ headers: gloOpts.headers
74
+ });
75
+ const data = await res.json();
76
+ return data;
77
+ }
78
+
79
+ async function getGeofence(fenceID) {
80
+ if(!isAuthenticated()) return console.log('Not authenticated.');
81
+ const url = `https://graph.tractive.com/4/geofence/${fenceID}`;
82
+ const res = await fetch(url, {
83
+ method: gloOpts.method,
84
+ headers: gloOpts.headers
85
+ });
86
+ const data = await res.json();
87
+ return data;
88
+ }
89
+
90
+ export default {
91
+ connect,
92
+ isAuthenticated,
93
+ getTrackerGeofences,
94
+ getGeofence,
95
+ // Account
96
+ getAccountInfo: tAccount.getAccountInfo,
97
+ getAccountSubscriptions: tAccount.getAccountSubscriptions,
98
+ getAccountSubscription: tAccount.getAccountSubscription,
99
+ getAccountShares: tAccount.getAccountShares,
100
+ // Pet
101
+ getPets: tPet.getPets,
102
+ getPet: tPet.getPet,
103
+ // Tracker
104
+ getAllTrackers: tTracker.getAllTrackers,
105
+ getTracker: tTracker.getTracker,
106
+ getTrackerHistory: tTracker.getTrackerHistory,
107
+ getTrackerLocation: tTracker.getTrackerLocation,
108
+ getTrackerHardware: tTracker.getTrackerHardware,
109
+ // Commands
110
+ liveOn: tCommands.liveOn,
111
+ liveOff: tCommands.liveOff,
112
+ LEDOn: tCommands.LEDOn,
113
+ LEDOff: tCommands.LEDOff,
114
+ buzzerOn: tCommands.BuzzerOn,
115
+ buzzerOff: tCommands.BuzzerOff
116
+ };
@@ -0,0 +1,25 @@
1
+ module.exports = function (RED) {
2
+ // Import the ESM tractive module once at load time
3
+ let tractivePromise = import('../index.js').then(m => m.default);
4
+
5
+ function TractiveConfigNode(config) {
6
+ RED.nodes.createNode(this, config);
7
+ const node = this;
8
+ node.email = config.email;
9
+
10
+ node.getClient = async function () {
11
+ const tractive = await tractivePromise;
12
+ if (!tractive.isAuthenticated()) {
13
+ const ok = await tractive.connect(node.email, node.credentials.password);
14
+ if (!ok) throw new Error('Tractive authentication failed');
15
+ }
16
+ return tractive;
17
+ };
18
+ }
19
+
20
+ RED.nodes.registerType('tractive-config', TractiveConfigNode, {
21
+ credentials: {
22
+ password: { type: 'password' }
23
+ }
24
+ });
25
+ };
@@ -0,0 +1,25 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('tractive-config', {
3
+ category: 'config',
4
+ defaults: {
5
+ email: { value: '', required: true }
6
+ },
7
+ credentials: {
8
+ password: { type: 'password' }
9
+ },
10
+ label: function () {
11
+ return this.email || 'Tractive Account';
12
+ }
13
+ });
14
+ </script>
15
+
16
+ <script type="text/html" data-template-name="tractive-config">
17
+ <div class="form-row">
18
+ <label for="node-config-input-email"><i class="fa fa-envelope"></i> Email</label>
19
+ <input type="email" id="node-config-input-email" placeholder="your@email.com" style="width:70%">
20
+ </div>
21
+ <div class="form-row">
22
+ <label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
23
+ <input type="password" id="node-config-input-password" style="width:70%">
24
+ </div>
25
+ </script>
@@ -0,0 +1,74 @@
1
+ module.exports = function (RED) {
2
+ function TractiveTrackerNode(config) {
3
+ RED.nodes.createNode(this, config);
4
+ const node = this;
5
+ node.configNode = RED.nodes.getNode(config.config);
6
+ node.operation = config.operation;
7
+ node.trackerID = config.trackerID;
8
+
9
+ node.on('input', async function (msg) {
10
+ if (!node.configNode) {
11
+ node.error('No Tractive config selected', msg);
12
+ return;
13
+ }
14
+
15
+ const operation = msg.operation || node.operation;
16
+ const trackerID = msg.trackerID || node.trackerID;
17
+
18
+ try {
19
+ node.status({ fill: 'blue', shape: 'dot', text: operation });
20
+ const tractive = await node.configNode.getClient();
21
+
22
+ let result;
23
+ switch (operation) {
24
+ case 'getAllTrackers':
25
+ result = await tractive.getAllTrackers();
26
+ break;
27
+ case 'getTrackerLocation':
28
+ result = await tractive.getTrackerLocation(trackerID);
29
+ break;
30
+ case 'getTrackerHardware':
31
+ result = await tractive.getTrackerHardware(trackerID);
32
+ break;
33
+ case 'getTrackerHistory':
34
+ result = await tractive.getTrackerHistory(trackerID, msg.from, msg.to);
35
+ break;
36
+ case 'getPets':
37
+ result = await tractive.getPets();
38
+ break;
39
+ case 'liveOn':
40
+ result = await tractive.liveOn(trackerID);
41
+ break;
42
+ case 'liveOff':
43
+ result = await tractive.liveOff(trackerID);
44
+ break;
45
+ case 'LEDOn':
46
+ result = await tractive.LEDOn(trackerID);
47
+ break;
48
+ case 'LEDOff':
49
+ result = await tractive.LEDOff(trackerID);
50
+ break;
51
+ case 'buzzerOn':
52
+ result = await tractive.buzzerOn(trackerID);
53
+ break;
54
+ case 'buzzerOff':
55
+ result = await tractive.buzzerOff(trackerID);
56
+ break;
57
+ default:
58
+ node.error(`Unknown operation: ${operation}`, msg);
59
+ node.status({ fill: 'red', shape: 'ring', text: 'unknown operation' });
60
+ return;
61
+ }
62
+
63
+ node.status({ fill: 'green', shape: 'dot', text: 'ok' });
64
+ msg.payload = result;
65
+ node.send(msg);
66
+ } catch (err) {
67
+ node.status({ fill: 'red', shape: 'ring', text: err.message });
68
+ node.error(err, msg);
69
+ }
70
+ });
71
+ }
72
+
73
+ RED.nodes.registerType('tractive-tracker', TractiveTrackerNode);
74
+ };
@@ -0,0 +1,80 @@
1
+ <script type="text/javascript">
2
+ const TRACKER_OPS = [
3
+ 'getTrackerLocation', 'getTrackerHardware', 'getTrackerHistory',
4
+ 'liveOn', 'liveOff', 'LEDOn', 'LEDOff', 'buzzerOn', 'buzzerOff'
5
+ ];
6
+
7
+ RED.nodes.registerType('tractive-tracker', {
8
+ category: 'Tractive',
9
+ color: '#6dbfde',
10
+ defaults: {
11
+ name: { value: '' },
12
+ config: { value: '', type: 'tractive-config', required: true },
13
+ operation: { value: 'getTrackerHardware', required: true },
14
+ trackerID: { value: '', validate: function(v) {
15
+ const op = document.getElementById('node-input-operation');
16
+ if (op && TRACKER_OPS.includes(op.value)) return v && v.trim().length > 0;
17
+ return true;
18
+ }}
19
+ },
20
+ inputs: 1,
21
+ outputs: 1,
22
+ icon: 'font-awesome/fa-paw',
23
+ label: function () {
24
+ return this.name || this.operation || 'tractive';
25
+ },
26
+ oneditprepare: function () {
27
+ function toggleTrackerID() {
28
+ const op = document.getElementById('node-input-operation').value;
29
+ const row = document.getElementById('row-trackerID');
30
+ row.style.display = TRACKER_OPS.includes(op) ? '' : 'none';
31
+ }
32
+ document.getElementById('node-input-operation').addEventListener('change', toggleTrackerID);
33
+ toggleTrackerID();
34
+ }
35
+ });
36
+ </script>
37
+
38
+ <script type="text/html" data-template-name="tractive-tracker">
39
+ <div class="form-row">
40
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
41
+ <input type="text" id="node-input-name" placeholder="Name">
42
+ </div>
43
+ <div class="form-row">
44
+ <label for="node-input-config"><i class="fa fa-user"></i> Account</label>
45
+ <input type="text" id="node-input-config">
46
+ </div>
47
+ <div class="form-row" id="row-trackerID">
48
+ <label for="node-input-trackerID"><i class="fa fa-map-marker"></i> Tracker ID</label>
49
+ <input type="text" id="node-input-trackerID" placeholder="Find in Tractive app → Settings → Device">
50
+ </div>
51
+ <div class="form-row">
52
+ <label for="node-input-operation"><i class="fa fa-cog"></i> Operation</label>
53
+ <select id="node-input-operation" style="width:70%">
54
+ <optgroup label="Tracker">
55
+ <option value="getTrackerHardware">Get hardware (battery, charging)</option>
56
+ <option value="getTrackerLocation">Get location</option>
57
+ <option value="getTrackerHistory">Get history</option>
58
+ </optgroup>
59
+ <optgroup label="Commands">
60
+ <option value="liveOn">Live tracking ON</option>
61
+ <option value="liveOff">Live tracking OFF</option>
62
+ <option value="LEDOn">LED ON</option>
63
+ <option value="LEDOff">LED OFF</option>
64
+ <option value="buzzerOn">Buzzer ON</option>
65
+ <option value="buzzerOff">Buzzer OFF</option>
66
+ </optgroup>
67
+ <optgroup label="Account">
68
+ <option value="getPets">Get pets</option>
69
+ <option value="getAllTrackers">Get all trackers</option>
70
+ </optgroup>
71
+ </select>
72
+ </div>
73
+ </script>
74
+
75
+ <script type="text/html" data-help-name="tractive-tracker">
76
+ <p>Calls the Tractive API for a configured tracker.</p>
77
+ <p><b>Tracker ID:</b> find it in the Tractive app under Settings → Device → Device ID.
78
+ Can be overridden at runtime with <code>msg.trackerID</code>.</p>
79
+ <p>For <b>Get history</b>, set <code>msg.from</code> and <code>msg.to</code> (Unix timestamps in ms).</p>
80
+ </script>
package/package.json CHANGED
@@ -1,21 +1,41 @@
1
1
  {
2
2
  "name": "node-red-contrib-tractive",
3
- "version": "0.1.0",
4
- "description": "Node-RED palette for Tractive GPS tracker integration",
3
+ "version": "1.0.0",
4
+ "description": "Node-RED palette for the Tractive GPS tracker API — monitor battery, location, and control LED/buzzer.",
5
5
  "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "node --test"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/elarochejoubert/tractive.git"
13
+ },
6
14
  "keywords": [
7
15
  "node-red",
8
16
  "tractive",
9
17
  "GPS",
10
18
  "tracker",
11
- "pet"
19
+ "pet",
20
+ "tracking"
12
21
  ],
13
22
  "node-red": {
14
- "nodes": {}
23
+ "version": ">=3.0.0",
24
+ "nodes": {
25
+ "tractive-config": "nodes/tractive-config.cjs",
26
+ "tractive-tracker": "nodes/tractive-tracker.cjs"
27
+ }
28
+ },
29
+ "author": "Edouard Laroche-Joubert",
30
+ "license": "ISC",
31
+ "bugs": {
32
+ "url": "https://github.com/elarochejoubert/tractive/issues"
33
+ },
34
+ "homepage": "https://github.com/elarochejoubert/tractive#readme",
35
+ "engines": {
36
+ "node": ">=18"
15
37
  },
16
- "author": "Edouard",
17
- "license": "MIT",
18
- "dependencies": {
19
- "tractive": "^1.2.1"
38
+ "devDependencies": {
39
+ "undici": "^7.0.0"
20
40
  }
21
41
  }
package/src/account.js ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Gets Tractive account information.
3
+ * @returns {Object} Object
4
+ */
5
+ export async function getAccountInfo() {
6
+ if(!isAuthenticated()) return console.log('Not authenticated.');
7
+ const url = `https://graph.tractive.com/4/user/${accountDetails.uid}`;
8
+ const res = await fetch(url, {
9
+ method: gloOpts.method,
10
+ headers: gloOpts.headers
11
+ });
12
+ const data = await res.json();
13
+ return data;
14
+ }
15
+
16
+ /**
17
+ * Get all account subscriptions
18
+ * @returns {Array} Array
19
+ */
20
+ export async function getAccountSubscriptions() {
21
+ if(!isAuthenticated()) return console.log('Not authenticated.');
22
+ const url = `https://graph.tractive.com/4/user/${accountDetails.uid}/subscriptions`;
23
+ const res = await fetch(url, {
24
+ method: gloOpts.method,
25
+ headers: gloOpts.headers
26
+ });
27
+ const data = await res.json();
28
+ return data;
29
+ }
30
+
31
+ /**
32
+ * Get a subscription
33
+ * @param {String} subscriptionID
34
+ * @returns {Object} Object
35
+ */
36
+ export async function getAccountSubscription(subscriptionID) {
37
+ if(!isAuthenticated()) return console.log('Not authenticated.');
38
+ const url = `https://graph.tractive.com/4/subscription/${subscriptionID}`;
39
+ const res = await fetch(url, {
40
+ method: gloOpts.method,
41
+ headers: gloOpts.headers
42
+ });
43
+ const data = await res.json();
44
+ return data;
45
+ }
46
+
47
+ /**
48
+ * Get a list of accounts you share trackers with
49
+ * @returns {Array} Array
50
+ */
51
+ export async function getAccountShares() {
52
+ if(!isAuthenticated()) return console.log('Not authenticated.');
53
+ const url = `https://graph.tractive.com/4/user/${accountDetails.uid}/shares`;
54
+ const res = await fetch(url, {
55
+ method: gloOpts.method,
56
+ headers: gloOpts.headers
57
+ });
58
+ const data = await res.json();
59
+ return data;
60
+ }
@@ -0,0 +1,76 @@
1
+ const RATE_LIMIT_CODE = 4006;
2
+ const RATE_LIMIT_DELAY_MS = 2000;
3
+ const MAX_RETRIES = 3;
4
+
5
+ async function commandFetch(url, retries = MAX_RETRIES) {
6
+ const res = await fetch(url, {
7
+ method: gloOpts.method,
8
+ headers: gloOpts.headers
9
+ });
10
+ const data = await res.json();
11
+ if (data?.code === RATE_LIMIT_CODE && retries > 0) {
12
+ await new Promise(resolve => setTimeout(resolve, RATE_LIMIT_DELAY_MS));
13
+ return commandFetch(url, retries - 1);
14
+ }
15
+ return data;
16
+ }
17
+
18
+ /**
19
+ * Toggle live tracking mode on for a tracker.
20
+ * @param {String} trackerID
21
+ * @returns {Object} Object
22
+ */
23
+ export async function liveOn(trackerID) {
24
+ if(!isAuthenticated()) return console.log('Not authenticated.');
25
+ return commandFetch(`https://graph.tractive.com/4/tracker/${trackerID}/command/live_tracking/on`);
26
+ }
27
+
28
+ /**
29
+ * Toggle live tracking mode off for a tracker.
30
+ * @param {String} trackerID
31
+ * @returns {Object} Object
32
+ */
33
+ export async function liveOff(trackerID) {
34
+ if(!isAuthenticated()) return console.log('Not authenticated.');
35
+ return commandFetch(`https://graph.tractive.com/4/tracker/${trackerID}/command/live_tracking/off`);
36
+ }
37
+
38
+ /**
39
+ * Turn the trackers LED light on for the specified tracker.
40
+ * @param {String} trackerID
41
+ * @returns {Object} Object
42
+ */
43
+ export async function LEDOn(trackerID) {
44
+ if(!isAuthenticated()) return console.log('Not authenticated.');
45
+ return commandFetch(`https://graph.tractive.com/4/tracker/${trackerID}/command/led_control/on`);
46
+ }
47
+
48
+ /**
49
+ * Turn the trackers LED light off for the specified tracker.
50
+ * @param {String} trackerID
51
+ * @returns {Object} Object
52
+ */
53
+ export async function LEDOff(trackerID) {
54
+ if(!isAuthenticated()) return console.log('Not authenticated.');
55
+ return commandFetch(`https://graph.tractive.com/4/tracker/${trackerID}/command/led_control/off`);
56
+ }
57
+
58
+ /**
59
+ * Turn the trackers buzzer sound on for the specified tracker.
60
+ * @param {String} trackerID
61
+ * @returns {Object} Object
62
+ */
63
+ export async function BuzzerOn(trackerID) {
64
+ if(!isAuthenticated()) return console.log('Not authenticated.');
65
+ return commandFetch(`https://graph.tractive.com/4/tracker/${trackerID}/command/buzzer_control/on`);
66
+ }
67
+
68
+ /**
69
+ * Turn the trackers buzzer sound off for the specified tracker.
70
+ * @param {String} trackerID
71
+ * @returns {Object} Object
72
+ */
73
+ export async function BuzzerOff(trackerID) {
74
+ if(!isAuthenticated()) return console.log('Not authenticated.');
75
+ return commandFetch(`https://graph.tractive.com/4/tracker/${trackerID}/command/buzzer_control/off`);
76
+ }
package/src/pet.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Get a pet and it's data, includes attached tracker, type of animal, and other pet details.
3
+ * @param {String} petID
4
+ * @returns {Object} Object
5
+ */
6
+ export async function getPet(petID) {
7
+ if(!isAuthenticated()) return console.log('Not authenticated.');
8
+ const url = `https://graph.tractive.com/4/trackable_object/${petID}`;
9
+ const res = await fetch(url, {
10
+ method: gloOpts.method,
11
+ headers: gloOpts.headers
12
+ });
13
+ const parsedData = await res.json();
14
+ parsedData.details.profile_picture_link = `https://graph.tractive.com/4/media/resource/${parsedData.details.profile_picture_id}.jpg`;
15
+ parsedData.details.cover_picture_link = `https://graph.tractive.com/4/media/resource/${parsedData.details.cover_picture_id}.jpg`;
16
+ return parsedData;
17
+ }
18
+
19
+ /**
20
+ * Get a list of all pets on the account
21
+ * @returns {Array} Array
22
+ */
23
+ export async function getPets() {
24
+ if(!isAuthenticated()) return console.log('Not authenticated.');
25
+ const url = `https://graph.tractive.com/4/user/${accountDetails.uid}/trackable_objects`;
26
+ const res = await fetch(url, {
27
+ method: gloOpts.method,
28
+ headers: gloOpts.headers
29
+ });
30
+ const data = await res.json();
31
+ return data;
32
+ }
package/src/tracker.js ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Get an array of all trackers on the account
3
+ * @returns {Array}
4
+ */
5
+ export async function getAllTrackers() {
6
+ if(!isAuthenticated()) return console.log('Not authenticated.');
7
+ const url = `https://graph.tractive.com/4/user/${accountDetails.uid}/trackers`;
8
+ const res = await fetch(url, {
9
+ method: gloOpts.method,
10
+ headers: gloOpts.headers
11
+ });
12
+ const trackers = await res.json();
13
+ return trackers;
14
+ }
15
+
16
+ /**
17
+ * Get the specified tracker
18
+ * @param {String} trackerID
19
+ * @returns {Object} Object
20
+ */
21
+ export async function getTracker(trackerID) {
22
+ if(!isAuthenticated()) return console.log('Not authenticated.');
23
+ const url = `https://graph.tractive.com/4/tracker/${trackerID}`;
24
+ const res = await fetch(url, {
25
+ method: gloOpts.method,
26
+ headers: gloOpts.headers
27
+ });
28
+ const tracker = await res.json();
29
+ return tracker;
30
+ }
31
+
32
+ /**
33
+ * Get the history of locations for a specified tracker
34
+ * @param {String} trackerID
35
+ * @param {Number} from
36
+ * @param {Number} to
37
+ * @returns {Array} Array
38
+ */
39
+ export async function getTrackerHistory(trackerID, from, to) {
40
+ if(!isAuthenticated()) return console.log('Not authenticated.');
41
+ let calcFrom = typeof from == "object" ? (from.getTime() / 1000).toFixed(0) : from;
42
+ let calcTo = typeof to == "object" ? (to.getTime() / 1000).toFixed(0) : to;
43
+ const url = `https://graph.tractive.com/4/tracker/${encodeURIComponent(trackerID)}/positions?time_from=${encodeURIComponent(calcFrom)}&time_to=${encodeURIComponent(calcTo)}&format=json_segments`;
44
+ const res = await fetch(url, {
45
+ method: gloOpts.method,
46
+ headers: gloOpts.headers
47
+ });
48
+ const parsedData = await res.json();
49
+ return parsedData[0];
50
+ }
51
+
52
+ /**
53
+ * Get the latest position report for the tracker.
54
+ * @param {String} trackerID
55
+ * @returns {Object} Object
56
+ */
57
+ export async function getTrackerLocation(trackerID) {
58
+ if(!isAuthenticated()) return console.log('Not authenticated.');
59
+ const url = `https://graph.tractive.com/4/device_pos_report/${trackerID}`;
60
+ const res = await fetch(url, {
61
+ method: gloOpts.method,
62
+ headers: gloOpts.headers
63
+ });
64
+ const data = await res.json();
65
+ const addressUrl = `https://graph.tractive.com/4/platform/geo/address/location?latitude=${encodeURIComponent(data.latlong[0])}&longitude=${encodeURIComponent(data.latlong[1])}`;
66
+ try {
67
+ const addressRes = await fetch(addressUrl, {
68
+ method: gloOpts.method,
69
+ headers: gloOpts.headers
70
+ });
71
+ const address = await addressRes.json();
72
+ data.address = address;
73
+ } catch (err) {
74
+ // ignore address fetch error
75
+ }
76
+ return data;
77
+ }
78
+
79
+ /**
80
+ * Get the latest hardware report for the tracker.
81
+ * @param {String} trackerID
82
+ * @returns {Object} Object
83
+ */
84
+ export async function getTrackerHardware(trackerID) {
85
+ if(!isAuthenticated()) return console.log('Not authenticated.');
86
+ const url = `https://graph.tractive.com/4/device_hw_report/${trackerID}`;
87
+ const res = await fetch(url, {
88
+ method: gloOpts.method,
89
+ headers: gloOpts.headers
90
+ });
91
+ const data = await res.json();
92
+ return data;
93
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Edouard
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.