PHPackages                             track-any-device/drivers - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. track-any-device/drivers

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

track-any-device/drivers
========================

Device drivers and connectors for the Track Any Device platform.

0119↓100%[7 issues](https://github.com/track-any-device/package-drivers/issues)1PHPCI passing

Since May 26Pushed 6d agoCompare

[ Source](https://github.com/track-any-device/package-drivers)[ Packagist](https://packagist.org/packages/track-any-device/drivers)[ RSS](/packages/track-any-device-drivers/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (1)

track-any-device/drivers
========================

[](#track-any-devicedrivers)

Device drivers and connectors for the Track Any Device platform.

Each driver encapsulates all protocol knowledge for a specific GPS tracker model — parsing incoming telemetry (stream or SMS), building outgoing commands, and managing device onboarding. The rest of the platform talks to every device through a single uniform interface.

---

Requirements
------------

[](#requirements)

- PHP 8.3+
- Laravel 13.7+
- `track-any-device/core` ^0.0.2

---

Installation
------------

[](#installation)

```
composer require track-any-device/drivers
```

The service provider is auto-discovered by Laravel.

---

Included drivers
----------------

[](#included-drivers)

Driver classDeviceStream channelSMS fallback`GF07Driver`GF-07 Mini GPS Tracker— (SMS only)yes`AOT120Driver`AOT120 Vehicle GPS TrackerJT/T 808 TCPyes`P901Driver`Cantrack P901 Smart ID CardJT/T 808 TCPyes---

Core concepts
-------------

[](#core-concepts)

### `DeviceDriverInterface`

[](#devicedriverinterface)

Every driver implements `TrackAnyDevice\Drivers\Contracts\DeviceDriverInterface`. You interact with any device through this contract without needing to know which driver is underneath.

```
use TrackAnyDevice\Drivers\Contracts\DeviceDriverInterface;

class HandleIncomingSignal
{
    public function __construct(private DeviceDriverInterface $driver) {}

    public function handle(array $rawEvent, Device $device): void
    {
        $signal = $this->driver->parseEventToSignal($rawEvent, $device);

        // $signal is a normalised SignalObject regardless of device model
    }
}
```

### `SignalObject`

[](#signalobject)

A readonly value object that carries normalised telemetry. Drivers populate whatever fields they can parse and leave the rest `null`.

```
$signal->eventType;       // SignalEventType enum
$signal->source;          // SignalSource enum (stream_jt808 | gsm_sms | …)
$signal->latitude;        // ?float
$signal->longitude;       // ?float
$signal->speed;           // ?float  km/h
$signal->direction;       // ?int    degrees
$signal->gpsFixed;        // bool
$signal->batteryPercent;  // ?int
$signal->gsmSignal;       // ?int
$signal->workingMode;     // ?string
$signal->alarmFlags;      // ?int    bitmask
$signal->deviceTime;      // ?CarbonImmutable (UTC)
$signal->rawPayload;      // ?string original frame / SMS body
```

Check for a usable position:

```
if ($signal->hasLocation()) {
    // $signal->latitude and $signal->longitude are both non-null
}
```

Stamp with server receive time (done by `SignalService`):

```
$signal = $signal->withServerTime(CarbonImmutable::now());
```

Serialise / deserialise:

```
$array  = $signal->toArray();
$signal = SignalObject::fromArray($array);
```

---

Parsing incoming telemetry
--------------------------

[](#parsing-incoming-telemetry)

### Stream events (JT808)

[](#stream-events-jt808)

The JT808 TCP server decodes binary frames and publishes a decoded array. Pass it straight to the driver:

```
$signal = $driver->parseEventToSignal([
    'source'       => 'stream_jt808',
    'msg_id'       => 0x0200,
    'latitude'     => 51.5074,
    'longitude'    => -0.1278,
    'speed'        => 32.5,
    'direction'    => 270,
    'gps_fixed'    => true,
    'alarm_flags'  => 0,
    'status_flags' => 0,
    'device_time'  => '2025-06-01 12:00:00',
], $device);
```

### SMS replies

[](#sms-replies)

Pass the raw SMS body as received from the gateway:

```
$signal = $driver->parseSmsToSignal(
    'Lat:51.5074 Lon:-0.1278 Speed:32km/h Battery:78% Signal:4 GPS:Fixed',
    $device
);
```

For drivers that only receive SMS (e.g. GF-07), you can also pass an event array with a `raw` key:

```
$signal = $driver->parseEventToSignal(['raw' => $smsBody], $device);
```

---

Sending commands
----------------

[](#sending-commands)

### Request a location fix

[](#request-a-location-fix)

```
$driver->requestSignal('location', $device);
```

JT808 drivers send a `0x8201` query over the live socket when the device is online (last signal within 10 minutes), falling back to an SMS command when it is not.

### Set tracking mode

[](#set-tracking-mode)

```
$driver->setMode('3', $device, ['interval' => '30S']);
```

### Add-on commands

[](#add-on-commands)

Each driver declares its full command catalogue via `addOnCommands()`, which the Filament UI uses to render the command panel:

```
/** @var list */
$commands = $driver->addOnCommands();

foreach ($commands as $cmd) {
    $cmd->name;        // string  machine name
    $cmd->label;       // string  human label
    $cmd->params;      // array   JSON-schema-like param descriptors
    $cmd->category;    // string  'tracking' | 'network' | 'alarm' | 'utility' | …
    $cmd->requiresGsm; // bool    UI hint: command cannot use the stream channel
}
```

Execute a named command:

```
$driver->addOnCommand('set_apn', ['apn' => 'internet'], $device);
$driver->addOnCommand('engine_cut', [], $device);
$driver->addOnCommand('set_volume', ['level' => 6], $device);
```

---

Onboarding a new device
-----------------------

[](#onboarding-a-new-device)

Call `onboardingAction` once after a device is provisioned. It queues the full setup sequence (server IP, APN, timezone, default tracking mode) as SMS commands via `DeviceCommandObserver`:

```
$driver->onboardingAction($device);
```

Commands are dispatched asynchronously — the observer picks up each `DeviceCommand` row and routes it through `SMSConnector`.

---

Stream routing
--------------

[](#stream-routing)

JT808 drivers (`AOT120Driver`, `P901Driver`) determine whether the device is reachable over the live socket by checking `last_signal_at`:

```
// true when device has reported within the last 10 minutes
$driver->supportsStream($device);

// 'jt808' | 'none'
$driver->getStreamChannel();
```

When the stream is available, commands are published to a Redis pub/sub channel:

```
jt808:cmd:{gsm_number}

```

The JT808 TCP server subscribes to this channel and writes the encoded frame to the open socket.

---

Adding a new driver
-------------------

[](#adding-a-new-driver)

1. Create a class in `src/` that implements `DeviceDriverInterface`.
2. Use the `QueuesSmsCommands` trait if the driver sends SMS commands.
3. Implement `buildSmsBody(string $commandType, array $params): ?string` — return the raw SMS string for each command type, or `null` to skip.
4. Register the driver in your application's `DriverRegistry` (provided by `track-any-device/core`).

```
use TrackAnyDevice\Drivers\Concerns\QueuesSmsCommands;
use TrackAnyDevice\Drivers\Contracts\DeviceDriverInterface;
use TrackAnyDevice\Drivers\ValueObjects\AddOnCommand;
use TrackAnyDevice\Drivers\ValueObjects\SignalObject;
use TrackAnyDevice\Core\Models\Device;

class MyTrackerDriver implements DeviceDriverInterface
{
    use QueuesSmsCommands;

    public function getStreamChannel(): string { return 'none'; }
    public function supportsStream(Device $device): bool { return false; }

    public function parseEventToSignal(array $rawEvent, Device $device): SignalObject
    {
        return $this->parseSmsToSignal((string) ($rawEvent['raw'] ?? ''), $device);
    }

    public function parseSmsToSignal(string $rawSms, Device $device): SignalObject
    {
        // parse $rawSms and return a SignalObject — never throw
        return new SignalObject(
            eventType: SignalEventType::Update,
            source: SignalSource::GsmSms,
            rawPayload: $rawSms,
        );
    }

    public function requestSignal(string $signalType, Device $device): void
    {
        $this->queueSms('query_location', [], $device);
    }

    public function setMode(string $mode, Device $device, array $params = []): void {}
    public function getMode(Device $device): ?string { return null; }
    public function onboardingAction(Device $device): void {}

    public function addOnCommands(): array { return []; }
    public function addOnCommand(string $commandName, array $parameters, Device $device): void
    {
        $this->queueSms($commandName, $parameters, $device);
    }

    public function buildSmsBody(string $commandType, array $params): ?string
    {
        return match ($commandType) {
            'query_location' => 'WHERE#',
            default          => null,
        };
    }
}
```

---

SMSConnector
------------

[](#smsconnector)

`TrackAnyDevice\Drivers\Connectors\SMSConnector` implements `DeviceConnectorInterface` and dispatches outgoing messages through `SmsGatewayService`. It is resolved from the container automatically when bound:

```
// In a service provider
$this->app->bind(DeviceConnectorInterface::class, SMSConnector::class);
```

The connector updates the `DeviceCommand` status to `Queued` → `Sent` (or `Failed`) as the message progresses.

---

Changelog
---------

[](#changelog)

See [GitHub Releases](https://github.com/track-any-device/package-drivers/releases).

Licence
-------

[](#licence)

MIT

###  Health Score

25

—

LowBetter than 36% of packages

Maintenance64

Regular maintenance activity

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/83275f3144d4cc4092e54dd8d5acf6a048536f6d7e454d741ae82a61f904c737?d=identicon)[ahmadkokab](/maintainers/ahmadkokab)

---

Top Contributors

[![afaryab](https://avatars.githubusercontent.com/u/68786248?v=4)](https://github.com/afaryab "afaryab (10 commits)")

### Embed Badge

![Health badge](/badges/track-any-device-drivers/health.svg)

```
[![Health](https://phpackages.com/badges/track-any-device-drivers/health.svg)](https://phpackages.com/packages/track-any-device-drivers)
```

###  Alternatives

[spaze/csp-config

Build Content Security Policy from a config file

143.4k](/packages/spaze-csp-config)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
