├── .styleci.yml ├── CHANGELOG.md ├── src ├── Enums │ ├── NotificatorType.php │ └── NotificationType.php ├── TraccarFacade.php ├── Models │ ├── Report.php │ ├── Position.php │ ├── Group.php │ ├── Driver.php │ ├── Geofence.php │ ├── Notification.php │ ├── Event.php │ ├── Server.php │ ├── User.php │ ├── Session.php │ └── Device.php ├── Exceptions │ └── TraccarException.php ├── Middleware │ └── TraccarSessionMiddleware.php ├── Trait │ ├── UrlQueryHelper.php │ └── ArrayToModel.php ├── Services │ ├── Concerns │ │ ├── CanSendGetRequest.php │ │ ├── CanSendPutRequest.php │ │ ├── CanSendDeleteRequest.php │ │ ├── CanSendPostRequest.php │ │ └── BuildBaseRequest.php │ ├── Resources │ │ ├── EventResources.php │ │ ├── BaseResource.php │ │ ├── ServerResources.php │ │ ├── SessionResources.php │ │ ├── GroupResources.php │ │ ├── DriverResources.php │ │ ├── GeofenceResources.php │ │ ├── PositionResources.php │ │ ├── ReportResources.php │ │ ├── NotificationResources.php │ │ ├── UserResources.php │ │ └── DeviceResources.php │ └── TraccarService.php ├── Support │ └── TraccarMigration.php ├── Commands │ ├── SyncDevicesCommand.php │ └── WsListenCommand.php └── TraccarServiceProvider.php ├── config └── config.php ├── phpstan.neon ├── LICENSE.md ├── database └── migrations │ └── 2024_01_01_111000_create_traccar_devices_table.php ├── composer.json ├── CONTRIBUTING.md └── README.md /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel 2 | 3 | disabled: 4 | - single_class_element_per_statement 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `traccar` will be documented in this file 4 | 5 | ## 1.0.1 - 2025-07-21 6 | 7 | fix 8 | 9 | ## v1.0.0 - 2024-02-28 10 | 11 | first release 12 | 13 | ## 1.0.0 14 | 15 | - initial release 16 | - support Traccar (5.12) 17 | -------------------------------------------------------------------------------- /src/Enums/NotificatorType.php: -------------------------------------------------------------------------------- 1 | env('TRACCAR_BASE_URL'), 13 | 'websocket_url' => env('TRACCAR_SOCKET_URL'), 14 | 15 | 'auth' => [ 16 | 'username' => env('TRACCAR_USERNAME'), 17 | 'password' => env('TRACCAR_PASSWORD'), 18 | 'token' => env('TRACCAR_TOKEN'), 19 | ], 20 | 'database' => [ 21 | 'connection' => env('TRACCAR_DB_CONNECTION', 'mysql'), 22 | 'chunk' => 1000, 23 | ], 24 | 'devices' => [ 25 | 'store_in_database' => env('TRACCAR_AUTO_SAVE_DEVICES', true) 26 | ] 27 | ]; 28 | -------------------------------------------------------------------------------- /src/Models/Report.php: -------------------------------------------------------------------------------- 1 | getMessage(), $exception->getCode(), $exception->getPrevious()); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Models/Position.php: -------------------------------------------------------------------------------- 1 | traccarService->sessionRepository()->getCookies(); 29 | View::share('traccarSessionId', explode('.', $cookies->getValue() ?? '')[0]); 30 | return $next($request); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Trait/UrlQueryHelper.php: -------------------------------------------------------------------------------- 1 | 1) { 19 | foreach ($array as $value) { 20 | if (array_values($array)[0] == $value) { 21 | $query .= "$value&"; 22 | } elseif (end($array) == $value) { 23 | $query .= "$key=$value"; 24 | } else { 25 | $query .= "$key=$value&"; 26 | } 27 | } 28 | } else { 29 | $query = array_values($array)[0]; 30 | } 31 | return $query; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Services/Concerns/CanSendGetRequest.php: -------------------------------------------------------------------------------- 1 | withoutVerifying()->get( 29 | url: $url, 30 | query: $query 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Services/Concerns/CanSendPutRequest.php: -------------------------------------------------------------------------------- 1 | withoutVerifying()->put( 30 | url: $url, 31 | data: [ 32 | ...$payload, 33 | ], 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Services/Concerns/CanSendDeleteRequest.php: -------------------------------------------------------------------------------- 1 | withoutVerifying()->delete( 29 | url: $url, 30 | data: [ 31 | ...$payload, 32 | ], 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Services/Resources/EventResources.php: -------------------------------------------------------------------------------- 1 | service->get( 27 | request: $this->service->buildRequestWithBasicAuth(), 28 | url: 'events/' . $eventID, 29 | ); 30 | if (!$response->ok()) { 31 | throw new TraccarException($response->toException()); 32 | } 33 | return Event::createFromValueArray($response->json()); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Models/Group.php: -------------------------------------------------------------------------------- 1 | 'array', 39 | ]; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/Models/Driver.php: -------------------------------------------------------------------------------- 1 | 'array', 39 | ]; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/Services/Resources/BaseResource.php: -------------------------------------------------------------------------------- 1 | '', 'token' => '', 'session' => '']; 34 | $cachedSession = Cache::get($this->service->getCacheKey()); 35 | if (!is_array($cachedSession)) return $emptyArray; 36 | if (!array_key_exists('session', $cachedSession)) return $emptyArray; 37 | return $cachedSession["session"]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Mr.WOLF 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. -------------------------------------------------------------------------------- /src/Models/Geofence.php: -------------------------------------------------------------------------------- 1 | 'array', 43 | ]; 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/Enums/NotificationType.php: -------------------------------------------------------------------------------- 1 | 'array', 45 | ]; 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/Models/Event.php: -------------------------------------------------------------------------------- 1 | 'datetime', // ISO 8601 format : Y-m-d\TH:i:s\Z 46 | 'attribs' => 'array', 47 | ]; 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/Services/Concerns/CanSendPostRequest.php: -------------------------------------------------------------------------------- 1 | withoutVerifying()->asForm() 27 | ->post( 28 | url: $url, 29 | data: [ 30 | 'email' => $this->email, 31 | 'password' => $this->password 32 | ] 33 | ); 34 | } 35 | 36 | /** 37 | * @param PendingRequest $request 38 | * @param string $url 39 | * @param array $payload 40 | * @return PromiseInterface|Response 41 | * @phpstan-ignore-next-line 42 | */ 43 | public function post(PendingRequest $request, string $url, array $payload = []): PromiseInterface|Response 44 | { 45 | return $request->withoutVerifying()->post( 46 | url: $url, 47 | data: [ 48 | ...$payload, 49 | ], 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /database/migrations/2024_01_01_111000_create_traccar_devices_table.php: -------------------------------------------------------------------------------- 1 | shouldRun()) { 24 | return; 25 | } 26 | Schema::create('traccar_devices', function (Blueprint $table) { 27 | $table->id(); 28 | $table->string('name'); 29 | $table->string('uniqueId'); 30 | $table->string('status')->nullable(); 31 | $table->boolean('disabled')->nullable(); 32 | $table->timestamp('lastUpdate')->nullable(); 33 | $table->integer('positionId')->nullable(); 34 | $table->integer('groupId')->nullable(); 35 | $table->string('phone')->nullable(); 36 | $table->string('model')->nullable(); 37 | $table->string('contact')->nullable(); 38 | $table->string('category')->nullable(); 39 | $table->json('attribs')->nullable(); 40 | $table->timestamps(); 41 | }); 42 | } 43 | 44 | /** 45 | * Reverse the migrations. 46 | * 47 | * @return void 48 | */ 49 | public function down(): void 50 | { 51 | Schema::dropIfExists('traccar_devices'); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /src/Models/Server.php: -------------------------------------------------------------------------------- 1 | 'boolean', 52 | 'readonly' => 'boolean', 53 | 'deviceReadonly' => 'boolean', 54 | 'limitCommands' => 'boolean', 55 | 'latitude' => 'float', 56 | 'longitude' => 'float', 57 | 'zoom' => 'integer', 58 | 'twelveHourFormat' => 'boolean', 59 | 'forceSettings' => 'boolean', 60 | 'openIdEnabled' => 'boolean', 61 | 'openIdForce' => 'boolean', 62 | 'attribs' => 'array', 63 | ]; 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/Support/TraccarMigration.php: -------------------------------------------------------------------------------- 1 | driver(), ['mysql', 'pgsql', 'sqlite'])) { 27 | return true; 28 | } 29 | 30 | if (!App::environment('testing')) { 31 | throw new RuntimeException("Traccar does not support the [{$this->driver()}] database driver."); 32 | } 33 | 34 | if (Config::get('traccar.devices.store_in_database')) { 35 | throw new RuntimeException("Traccar does not support the [{$this->driver()}] database driver. You can disable Traccar device store in your testsuite by adding `` to your project's `phpunit.xml` file."); 36 | } 37 | 38 | return false; 39 | } 40 | 41 | /** 42 | * Get the database connection driver. 43 | */ 44 | protected function driver(): string 45 | { 46 | return DB::connection($this->getConnection())->getDriverName(); 47 | } 48 | 49 | /** 50 | * Get the migration connection name. 51 | */ 52 | public function getConnection(): ?string 53 | { 54 | $res = Config::get('traccar.database.connection'); 55 | return is_string($res) ? $res : null; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/Services/Concerns/BuildBaseRequest.php: -------------------------------------------------------------------------------- 1 | getToken())) throw new TraccarException("No access token provided."); 26 | return $this->withBaseUrl()->withQueryParameters(["token" => $this->getToken()]); 27 | } 28 | 29 | public function withBaseUrl(bool $useAPI = true): PendingRequest 30 | { 31 | return Http::baseUrl( 32 | url: rtrim($this->baseUrl, "/") . ($useAPI ? "/api/" : ""), 33 | )->withHeaders($this->headers); 34 | } 35 | 36 | /** 37 | * @throws TraccarException 38 | */ 39 | public function buildRequestWithCookies(): PendingRequest 40 | { 41 | if (!Cache::has($this->getCacheKey())) throw new TraccarException("No cookies found for this session."); 42 | $cachedSession = Cache::get($this->getCacheKey()); 43 | if (!is_array($cachedSession)) throw new TraccarException("No cookies found for this session."); 44 | $session = $cachedSession["session"]; 45 | return $this->withBaseUrl()->withCookies([$session["Name"] => $session["Value"]], $session["Domain"]); 46 | } 47 | 48 | public function buildRequestWithBasicAuth(null|string $username = null, null|string $password = null): PendingRequest 49 | { 50 | return $this->withBaseUrl()->withBasicAuth($username ?? $this->email, $password ?? $this->password); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Commands/SyncDevicesCommand.php: -------------------------------------------------------------------------------- 1 | 47 | */ 48 | protected $aliases = ['traccar:sync']; 49 | 50 | /** 51 | * Handle the command. 52 | */ 53 | public function handle(TraccarService $service): int 54 | { 55 | if (!$this->confirmToProceed()) { 56 | return Command::FAILURE; 57 | } 58 | 59 | try { 60 | foreach ($service->deviceRepository()->fetchListDevices() as $key => $device) { 61 | if ($device instanceof Device) { 62 | $device->createOrUpdate(); 63 | } 64 | } 65 | } catch (TraccarException $e) { 66 | Log::critical($e->getMessage()); 67 | $this->error("Synchronization operation failed : " . $e->getMessage()); 68 | return Command::FAILURE; 69 | } 70 | $this->info("Synchronization operation successful : " . Device::count() . " Devices in database"); 71 | return Command::SUCCESS; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Services/Resources/ServerResources.php: -------------------------------------------------------------------------------- 1 | service->get( 25 | request: $this->service->buildRequestWithBasicAuth(), 26 | url: 'server' 27 | ); 28 | if (!$response->ok()) { 29 | throw new TraccarException($response->toException()); 30 | } 31 | return Server::createFromValueArray($response->json()); 32 | } 33 | 34 | /** 35 | * @param Server $server 36 | * @return Server 37 | * @throws TraccarException 38 | */ 39 | public function updateServerInformation(Server $server): Server 40 | { 41 | $putData = $server->only('id', 'registration', 'readonly', 'deviceReadonly', 'limitCommands', 'map', 42 | 'bingKey', 'mapUrl', 'poiLayer', 'latitude', 'longitude', 'zoom', 'twelveHourFormat', 'version', 'forceSettings', 43 | 'coordinateFormat', 'openIdEnabled', 'openIdForce', 'attribs'); 44 | $putData["attributes"] = empty($putData["attribs"]) ? null : $putData["attribs"]; 45 | unset($putData["attribs"]); 46 | $putData = array_map(function ($value) { 47 | if (is_bool($value)) { 48 | return $value ? 'true' : 'false'; 49 | } 50 | return $value; 51 | }, $putData); 52 | $response = $this->service->put( 53 | request: $this->service->buildRequestWithBasicAuth(), 54 | url: 'server', 55 | payload: $putData 56 | ); 57 | if (!$response->ok()) { 58 | throw new TraccarException($response->toException()); 59 | } 60 | return Server::createFromValueArray($response->json()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Models/User.php: -------------------------------------------------------------------------------- 1 | 'boolean', 67 | 'administrator' => 'boolean', 68 | 'latitude' => 'float', 69 | 'longitude' => 'float', 70 | 'zoom' => 'integer', 71 | 'twelveHourFormat' => 'boolean', 72 | 'disabled' => 'boolean', 73 | 'expirationTime' => 'datetime', 74 | 'deviceReadonly' => 'boolean', 75 | 'limitCommands' => 'boolean', 76 | 'fixedEmail' => 'boolean', 77 | 'attribs' => 'array', 78 | ]; 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/Models/Session.php: -------------------------------------------------------------------------------- 1 | 'boolean', 69 | 'administrator' => 'boolean', 70 | 'twelveHourFormat' => 'boolean', 71 | 'disabled' => 'boolean', 72 | 'deviceReadonly' => 'boolean', 73 | 'limitCommands' => 'boolean', 74 | 'fixedEmail' => 'boolean', 75 | 'expirationTime' => 'datetime', 76 | 'attribs' => 'array', 77 | ]; 78 | 79 | } 80 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mr-wolf-gb/traccar", 3 | "description": "Traccar GPS server", 4 | "keywords": [ 5 | "laravel", 6 | "gps", 7 | "traccar", 8 | "api" 9 | ], 10 | "homepage": "https://github.com/mr-wolf-gb/traccar", 11 | "license": "MIT", 12 | "support": { 13 | "issues": "https://github.com/mr-wolf-gb/traccar/issues", 14 | "source": "https://github.com/mr-wolf-gb/traccar" 15 | }, 16 | "type": "library", 17 | "authors": [ 18 | { 19 | "name": "Mr.WOLF", 20 | "email": "gaiththewolf@gmail.com", 21 | "role": "Developer" 22 | } 23 | ], 24 | "require": { 25 | "php": "^8.1", 26 | "guzzlehttp/guzzle": "^7.8", 27 | "guzzlehttp/promises": "^2.0" 28 | }, 29 | "require-dev": { 30 | "larastan/larastan": "^2.9", 31 | "laravel/pint": "^1.0", 32 | "laravel/prompts": "^0.1.15", 33 | "orchestra/testbench": "^8.21", 34 | "pestphp/pest": "^2.31", 35 | "phpstan/phpstan": "^1.10.56", 36 | "spatie/invade": "^2.0", 37 | "spatie/ray": "^1.40.1", 38 | "symfony/var-dumper": "^6.4" 39 | }, 40 | "autoload": { 41 | "psr-4": { 42 | "MrWolfGb\\Traccar\\": "src" 43 | } 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "MrWolfGb\\Traccar\\Tests\\": "tests" 48 | } 49 | }, 50 | "scripts": { 51 | "analyse": "vendor/bin/phpstan analyse", 52 | "baseline": "vendor/bin/phpstan analyse --generate-baseline", 53 | "test": "vendor/bin/pest --compact", 54 | "test-coverage": "vendor/bin/pest --coverage", 55 | "format": "vendor/bin/pint" 56 | }, 57 | "config": { 58 | "sort-packages": true, 59 | "allow-plugins": { 60 | "pestphp/pest-plugin": true, 61 | "phpstan/extension-installer": true 62 | } 63 | }, 64 | "extra": { 65 | "laravel": { 66 | "providers": [ 67 | "MrWolfGb\\Traccar\\TraccarServiceProvider" 68 | ], 69 | "aliases": { 70 | "Traccar": "MrWolfGb\\Traccar\\TraccarFacade" 71 | } 72 | } 73 | }, 74 | "minimum-stability": "dev", 75 | "prefer-stable": true 76 | } 77 | -------------------------------------------------------------------------------- /src/Trait/ArrayToModel.php: -------------------------------------------------------------------------------- 1 | $subValue) { 36 | if (is_scalar($subValue) || is_null($subValue)) { 37 | $model->{$subKey} = $subValue ? is_string($subValue) ? trim($subValue) : $subValue : $subValue; 38 | } elseif (is_array($subValue)) { 39 | $subKey = $subKey == 'attributes' ? 'attribs' : $subKey; 40 | $model->{$subKey} = $subValue; 41 | } else { 42 | $model->{$subKey} = "unknown data"; 43 | } 44 | } 45 | return $model; 46 | } 47 | 48 | /** 49 | * @param mixed $values 50 | * @return Collection 51 | */ 52 | protected static function createFromValueList(mixed $values): Collection 53 | { 54 | $collection = collect(); 55 | if (is_null($values)) return $collection; 56 | if (is_string($values)) $values = json_decode($values, true); 57 | if (!is_iterable($values)) return $collection; 58 | foreach ($values as $key => $value) { 59 | $model = self::getModel($value); 60 | $collection->push($model); 61 | } 62 | return $collection; 63 | } 64 | 65 | // /** 66 | // * @param $model 67 | // * @param array $data 68 | // * @return void 69 | // */ 70 | // private static function recursiveArrayValue(&$model, array $data): void 71 | // { 72 | // foreach ($data as $key => $value) { 73 | // if (is_scalar($value) || is_null($value)) { 74 | // $model->{$key} = $value; 75 | // } elseif (is_array($value)) { 76 | // self::recursiveArrayValue($model, $value); 77 | // } else { 78 | // $model->{$key} = "unknown data"; 79 | // } 80 | // } 81 | // } 82 | } 83 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | Please read and understand the contribution guide before creating an issue or pull request. 6 | 7 | ## Etiquette 8 | 9 | This project is open source, and as such, the maintainers give their free time to build and maintain the source code 10 | held within. They make the code freely available in the hope that it will be of use to other developers. It would be 11 | extremely unfair for them to suffer abuse or anger for their hard work. 12 | 13 | Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the 14 | world that developers are civilized and selfless people. 15 | 16 | It's the duty of the maintainer to ensure that all submissions to the project are of sufficient 17 | quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. 18 | 19 | ## Viability 20 | 21 | When requesting or submitting new features, first consider whether it might be useful to others. Open 22 | source projects are used by many developers, who may have entirely different needs to your own. Think about 23 | whether or not your feature is likely to be used by other users of the project. 24 | 25 | ## Procedure 26 | 27 | Before filing an issue: 28 | 29 | - Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. 30 | - Check to make sure your feature suggestion isn't already present within the project. 31 | - Check the pull requests tab to ensure that the bug doesn't have a fix in progress. 32 | - Check the pull requests tab to ensure that the feature isn't already in progress. 33 | 34 | Before submitting a pull request: 35 | 36 | - Check the codebase to ensure that your feature doesn't already exist. 37 | - Check the pull requests to ensure that another person hasn't already submitted the feature or fix. 38 | 39 | ## Requirements 40 | 41 | If the project maintainer has any additional requirements, you will find them listed here. 42 | 43 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). 44 | 45 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 46 | 47 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 48 | 49 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. 50 | 51 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 52 | 53 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 54 | 55 | **Happy coding**! 56 | -------------------------------------------------------------------------------- /src/Services/Resources/SessionResources.php: -------------------------------------------------------------------------------- 1 | checkSessionID(); 23 | $session = $this->getSessionCache(); 24 | return Cookie::create( 25 | name: $session["Name"], 26 | value: $session["Value"], 27 | domain: $session["Domain"], 28 | ); 29 | } 30 | 31 | 32 | private function checkSessionID(): void 33 | { 34 | $session = $this->getSessionCache(); 35 | $response = $this->service->get( 36 | request: $this->service->withBaseUrl(), 37 | url: 'session/check-sid', 38 | query: [ 39 | 'sid' => explode('.', $session["Value"])[0] 40 | ] 41 | ); 42 | try { 43 | if ($response->json("status") === false) { 44 | Cache::forget($this->service->getCacheKey()); 45 | $this->createNewSession(); 46 | } 47 | } catch (TraccarException $e) { 48 | } 49 | } 50 | 51 | /** 52 | * @return Session 53 | * @throws TraccarException 54 | */ 55 | public function createNewSession(): Session 56 | { 57 | $response = $this->service->session( 58 | request: $this->service->withBaseUrl(), 59 | url: 'session', 60 | ); 61 | if (!$response->ok()) { 62 | throw new TraccarException($response->toException()); 63 | } 64 | return Session::createFromValueArray(Cache::rememberForever($this->service->getCacheKey(), function () use ($response) { 65 | return [ 66 | 'data' => $response->json(), 67 | 'token' => $response->json("token"), 68 | 'session' => $response->cookies()->getCookieByName('JSESSIONID')->toArray() ?? null //@phpstan-ignore-line 69 | ]; 70 | })); 71 | } 72 | 73 | /** 74 | * @return Session 75 | * @throws TraccarException 76 | */ 77 | public function fetchSessionInformation(): Session 78 | { 79 | $response = $this->service->get( 80 | request: $this->service->buildRequestWithAccessToken(), 81 | url: 'session' 82 | ); 83 | if (!$response->ok()) { 84 | throw new TraccarException($response->body()); 85 | } 86 | return Session::createFromValueArray(Cache::rememberForever($this->service->getCacheKey(), function () use ($response) { 87 | return [ 88 | 'data' => $response->json(), 89 | 'token' => $response->json("token"), 90 | 'session' => $response->cookies()->getCookieByName('JSESSIONID')->toArray() ?? null //@phpstan-ignore-line 91 | ]; 92 | })); 93 | } 94 | 95 | /** 96 | * @throws TraccarException 97 | */ 98 | public function closeSession(): bool 99 | { 100 | $response = $this->service->delete( 101 | request: $this->service->buildRequestWithCookies(), 102 | url: 'session' 103 | ); 104 | if (!$response->noContent()) { 105 | throw new TraccarException($response->toException()); 106 | } 107 | Cache::forget($this->service->getCacheKey()); 108 | return true; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/Commands/WsListenCommand.php: -------------------------------------------------------------------------------- 1 | 51 | */ 52 | protected $aliases = ['traccar:ws-listen']; 53 | 54 | /** 55 | * Handle the command. 56 | */ 57 | public function handle(TraccarService $service): int 58 | { 59 | // $wsUrl = config('traccar.websocket_url'); 60 | // if ($this->option('ws')) { 61 | // $wsUrl = $this->option('ws'); 62 | // } 63 | // $sessionCookies = $service->sessionRepository()->getCookies(); 64 | // 65 | // if ($this->option('session-id')) { 66 | // $wsUrl .= '?session=' . $this->option('session-id'); 67 | // } elseif ($sessionCookies->getValue()) { 68 | // $sessionID = explode('.', $sessionCookies->getValue())[0]; 69 | // $wsUrl .= '?session=' . $sessionID; 70 | // } elseif ($this->option('token')) { 71 | // $wsUrl .= '?token=' . $this->option('token'); 72 | // } elseif (!empty($service->getToken())) { 73 | // $wsUrl .= '?token=' . $service->getToken(); 74 | // } else { 75 | // $this->error("No session or token provided"); 76 | // return self::FAILURE; 77 | // } 78 | // $this->info("Connecting to: " . $wsUrl); 79 | // 80 | // $client = new Client( 81 | // uri: $wsUrl, 82 | // options: [ 83 | // 'filter' => ['text'], 84 | // 'headers' => [ 85 | // "Cookie" => $sessionCookies->getName() . "=" . $sessionCookies->getValue() 86 | // ], 87 | // 'timeout' => 60, 88 | // ], 89 | // ); 90 | // while (true) { 91 | // try { 92 | // $data = $client->receive(); 93 | // if (strlen($data) > 2) { 94 | // $dataObject = json_decode($data, true); 95 | // if (array_key_exists('positions', $dataObject)) { 96 | // $this->info("dispatch Event positions"); 97 | // } elseif (array_key_exists('events', $dataObject)) { 98 | // $this->info("dispatch Event event"); 99 | // } else { 100 | // $this->info("dispatch Event unknown"); 101 | // } 102 | // if ($this->option('log')) { 103 | // $this->info($data); 104 | // } 105 | // } 106 | // } catch (ConnectionException $e) { 107 | // $this->error($e->getMessage()); 108 | // break; 109 | // } 110 | // } 111 | // $client->close(); 112 | return self::SUCCESS; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/TraccarServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadTranslationsFrom(__DIR__.'/../resources/lang', 'traccar'); 32 | // $this->loadViewsFrom(__DIR__.'/../resources/views', 'traccar'); 33 | // $this->loadMigrationsFrom(__DIR__.'/../database/migrations'); 34 | // $this->loadRoutesFrom(__DIR__.'/routes.php'); 35 | $this->app->singleton(TraccarSessionMiddleware::class, function (Application $app) { 36 | return new TraccarSessionMiddleware(app(TraccarService::class)); 37 | }); 38 | /** @var Router $router */ 39 | $router = $this->app->make('router'); 40 | $router->aliasMiddleware('TraccarSession', TraccarSessionMiddleware::class); 41 | 42 | if ($this->app->runningInConsole()) { 43 | $this->publishes([ 44 | __DIR__ . '/../config/config.php' => config_path('traccar.php'), 45 | ], 'config'); 46 | 47 | // Publishing the views. 48 | /*$this->publishes([ 49 | __DIR__.'/../resources/views' => resource_path('views/vendor/traccar'), 50 | ], 'views');*/ 51 | 52 | // Publishing assets. 53 | // $this->publishes([ 54 | // __DIR__ . '/../resources/assets' => public_path('vendor/traccar'), 55 | // ], 'assets'); 56 | 57 | // Publishing the translation files. 58 | /*$this->publishes([ 59 | __DIR__.'/../resources/lang' => resource_path('lang/vendor/traccar'), 60 | ], 'lang');*/ 61 | 62 | // Registering package commands. 63 | $this->commands([ 64 | Commands\SyncDevicesCommand::class, 65 | //Commands\WsListenCommand::class 66 | ]); 67 | 68 | AboutCommand::add('Traccar', fn() => [ 69 | 'Version' => InstalledVersions::getPrettyVersion('mr-wolf-gb/traccar'), 70 | 'Base Url' => AboutCommand::format(config('traccar.base_url'), console: fn($value) => "$value"), // @phpstan-ignore-line 71 | 'Sync Devices' => AboutCommand::format(config('traccar.devices.store_in_database'), console: fn($value) => $value ? 'ENABLED' : 'OFF'), 72 | ]); 73 | 74 | //$method = method_exists($this, 'publishesMigrations') ? 'publishesMigrations' : 'publishes'; 75 | 76 | $this->publishes([ 77 | __DIR__ . '/../database/migrations' => database_path('migrations'), 78 | ], 'migrations'); 79 | } 80 | } 81 | 82 | /** 83 | * Register the application services. 84 | */ 85 | public function register(): void 86 | { 87 | // Automatically apply the package configuration 88 | $this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'traccar'); 89 | // Register the main class to use with the facade 90 | $this->app->singleton( 91 | abstract: TraccarService::class, 92 | concrete: fn() => new TraccarService( 93 | baseUrl: config('traccar.base_url'), // @phpstan-ignore-line 94 | email: config('traccar.auth.username'), // @phpstan-ignore-line 95 | password: config('traccar.auth.password'), // @phpstan-ignore-line 96 | token: config('traccar.auth.token'), // @phpstan-ignore-line 97 | headers: [ 98 | 'Accept' => 'application/json' 99 | ] 100 | ) 101 | ); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/Models/Device.php: -------------------------------------------------------------------------------- 1 | 'boolean', 78 | 'lastUpdate' => 'datetime', // ISO 8601 format : Y-m-d\TH:i:s\Z 79 | 'attribs' => 'array', 80 | ]; 81 | 82 | /** @phpstan-ignore-next-line */ 83 | public function __construct(array $attributes = []) 84 | { 85 | if (!isset($this->connection)) { 86 | if (is_string(config('traccar.database.connection'))) 87 | $this->setConnection(config('traccar.database.connection')); 88 | } 89 | parent::__construct($attributes); 90 | } 91 | 92 | /** 93 | * @return Device 94 | */ 95 | public function createOrUpdate(): Device 96 | { 97 | $device = static::where('uniqueId', '=', $this->uniqueId)->first(); 98 | if ($device) { 99 | $device->update([ 100 | 'name' => $this->name, 101 | 'uniqueId' => $this->uniqueId, 102 | 'status' => $this->status, 103 | 'disabled' => $this->disabled, 104 | 'lastUpdate' => $this->lastUpdate, 105 | 'positionId' => $this->positionId, 106 | 'groupId' => $this->groupId, 107 | 'phone' => $this->phone, 108 | 'model' => $this->model, 109 | 'contact' => $this->contact, 110 | 'category' => $this->category, 111 | 'attribs' => $this->attribs, 112 | ]); 113 | } else { 114 | $device = Device::create([ 115 | 'name' => $this->name, 116 | 'uniqueId' => $this->uniqueId, 117 | 'status' => $this->status, 118 | 'disabled' => $this->disabled, 119 | 'lastUpdate' => $this->lastUpdate, 120 | 'positionId' => $this->positionId, 121 | 'groupId' => $this->groupId, 122 | 'phone' => $this->phone, 123 | 'model' => $this->model, 124 | 'contact' => $this->contact, 125 | 'category' => $this->category, 126 | 'attribs' => $this->attribs, 127 | ]); 128 | } 129 | return $device; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/Services/Resources/GroupResources.php: -------------------------------------------------------------------------------- 1 | $all]; 29 | if ($userId != null) { 30 | $query["userId"] = $userId; 31 | } 32 | $response = $this->service->get( 33 | request: $this->service->buildRequestWithBasicAuth(), 34 | url: 'groups', 35 | query: urldecode(http_build_query($query, '', '&')) 36 | ); 37 | if (!$response->ok()) { 38 | throw new TraccarException($response->toException()); 39 | } 40 | return Group::createFromValueList($response->json()); 41 | } 42 | 43 | /** 44 | * @param string $name 45 | * @param int $groupId 46 | * @param array $attribs 47 | * @return Group 48 | * @throws TraccarException 49 | */ 50 | public function createGroup(string $name, int $groupId = 0, array $attribs = []): Group 51 | { 52 | if (empty($name)) { 53 | throw new TraccarException("Name cannot be empty !"); 54 | } 55 | $response = $this->service->post( 56 | request: $this->service->buildRequestWithBasicAuth(), 57 | url: 'groups', 58 | payload: [ 59 | "name" => $name, 60 | "groupId" => $groupId, 61 | "attributes" => empty($attribs) ? null : $attribs 62 | ] 63 | ); 64 | if (!$response->ok()) { 65 | if ($response->badRequest()) 66 | throw new TraccarException("No permission"); 67 | else 68 | throw new TraccarException($response->toException()); 69 | } 70 | return Group::createFromValueArray($response->json()); 71 | } 72 | 73 | /** 74 | * @param Group $group 75 | * @return Group 76 | * @throws TraccarException 77 | */ 78 | public function createNewGroup(Group $group): Group 79 | { 80 | if (empty($group->name)) { 81 | throw new TraccarException("Name cannot be empty !"); 82 | } 83 | $postData = $group->toArray(); 84 | $postData["attributes"] = empty($postData["attribs"]) ? null : $postData["attribs"]; 85 | unset($postData["attribs"]); 86 | $response = $this->service->post( 87 | request: $this->service->buildRequestWithBasicAuth(), 88 | url: 'groups', 89 | payload: $postData 90 | ); 91 | if (!$response->ok()) { 92 | if ($response->badRequest()) 93 | throw new TraccarException("No permission"); 94 | else 95 | throw new TraccarException($response->toException()); 96 | } 97 | return Group::createFromValueArray($response->json()); 98 | } 99 | 100 | /** 101 | * @param Group $group 102 | * @return Group 103 | * @throws TraccarException 104 | */ 105 | public function updateGroup(Group $group): Group 106 | { 107 | $putData = $group->toArray(); 108 | $putData["attributes"] = empty($putData["attribs"]) ? null : $putData["attribs"]; 109 | unset($putData["attribs"]); 110 | $response = $this->service->put( 111 | request: $this->service->buildRequestWithBasicAuth(), 112 | url: 'groups/' . $group->id, 113 | payload: $putData 114 | ); 115 | if (!$response->ok()) { 116 | throw new TraccarException($response->toException()); 117 | } 118 | return Group::createFromValueArray($response->json()); 119 | } 120 | 121 | /** 122 | * @param int|Group $group 123 | * @return bool 124 | * @throws TraccarException 125 | */ 126 | public function deleteGroup(int|Group $group): bool 127 | { 128 | $response = $this->service->delete( 129 | request: $this->service->buildRequestWithBasicAuth(), 130 | url: 'groups/' . ($group instanceof Group ? $group->id : $group) 131 | ); 132 | if (!$response->noContent()) { 133 | throw new TraccarException($response->toException()); 134 | } 135 | return true; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/Services/Resources/DriverResources.php: -------------------------------------------------------------------------------- 1 | $all, "refresh" => $refresh]; 32 | if ($userId != null) { 33 | $query["userId"] = $userId; 34 | } 35 | if ($deviceId != null) { 36 | $query["deviceId"] = $deviceId; 37 | } 38 | if ($groupId != null) { 39 | $query["groupId"] = $groupId; 40 | } 41 | $response = $this->service->get( 42 | request: $this->service->buildRequestWithBasicAuth(), 43 | url: 'drivers', 44 | query: urldecode(http_build_query($query, '', '&')) 45 | ); 46 | if (!$response->ok()) { 47 | throw new TraccarException($response->toException()); 48 | } 49 | return Driver::createFromValueList($response->json()); 50 | } 51 | 52 | /** 53 | * @param string $name 54 | * @param string $uniqueId 55 | * @param array $attribs 56 | * @return Driver 57 | * @throws TraccarException 58 | */ 59 | public function createDriver(string $name, string $uniqueId, array $attribs = []): Driver 60 | { 61 | $response = $this->service->post( 62 | request: $this->service->buildRequestWithBasicAuth(), 63 | url: 'drivers', 64 | payload: [ 65 | "name" => $name, 66 | "uniqueId" => $uniqueId, 67 | "attributes" => empty($attribs) ? null : $attribs 68 | ] 69 | ); 70 | if (!$response->ok()) { 71 | throw new TraccarException($response->toException()); 72 | } 73 | return Driver::createFromValueArray($response->json()); 74 | } 75 | 76 | /** 77 | * @param Driver $driver 78 | * @return Driver 79 | * @throws TraccarException 80 | */ 81 | public function createNewDriver(Driver $driver): Driver 82 | { 83 | if ($driver->uniqueId == '') { 84 | throw new TraccarException("Unique Id cannot be empty !"); 85 | } 86 | if ($driver->name == '') { 87 | throw new TraccarException("Name cannot be empty !"); 88 | } 89 | $postData = $driver->toArray(); 90 | $postData["attributes"] = empty($postData["attribs"]) ? null : $postData["attribs"]; 91 | unset($postData["attribs"]); 92 | $response = $this->service->post( 93 | request: $this->service->buildRequestWithBasicAuth(), 94 | url: 'drivers', 95 | payload: $postData 96 | ); 97 | if (!$response->ok()) { 98 | throw new TraccarException($response->toException()); 99 | } 100 | return Driver::createFromValueArray($response->json()); 101 | } 102 | 103 | /** 104 | * @param Driver $driver 105 | * @return Driver 106 | * @throws TraccarException 107 | */ 108 | public function updateDriver(Driver $driver): Driver 109 | { 110 | $putData = $driver->toArray(); 111 | $putData["attributes"] = empty($putData["attribs"]) ? null : $putData["attribs"]; 112 | unset($putData["attribs"]); 113 | $response = $this->service->put( 114 | request: $this->service->buildRequestWithBasicAuth(), 115 | url: 'drivers/' . $driver->id, 116 | payload: $putData 117 | ); 118 | if (!$response->ok()) { 119 | throw new TraccarException($response->toException()); 120 | } 121 | return Driver::createFromValueArray($response->json()); 122 | } 123 | 124 | /** 125 | * @param int|Driver $driver 126 | * @return bool 127 | * @throws TraccarException 128 | */ 129 | public function deleteDriver(int|Driver $driver): bool 130 | { 131 | $response = $this->service->delete( 132 | request: $this->service->buildRequestWithBasicAuth(), 133 | url: 'drivers/' . ($driver instanceof Driver ? $driver->id : $driver) 134 | ); 135 | if (!$response->noContent()) { 136 | throw new TraccarException($response->toException()); 137 | } 138 | return true; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/Services/Resources/GeofenceResources.php: -------------------------------------------------------------------------------- 1 | $all, "refresh" => $refresh]; 31 | if ($userId != null) { 32 | $query["userId"] = $userId; 33 | } 34 | if ($deviceId != null) { 35 | $query["deviceId"] = $deviceId; 36 | } 37 | if ($groupId != null) { 38 | $query["groupId"] = $groupId; 39 | } 40 | $response = $this->service->get( 41 | request: $this->service->buildRequestWithBasicAuth(), 42 | url: 'geofences', 43 | query: urldecode(http_build_query($query, '', '&')) 44 | ); 45 | if (!$response->ok()) { 46 | throw new TraccarException($response->toException()); 47 | } 48 | return Geofence::createFromValueList($response->json()); 49 | } 50 | 51 | /** 52 | * @param string $name 53 | * @param string $area 54 | * @param int $id 55 | * @param string|null $description 56 | * @param int|null $calendarId 57 | * @param array $attribs 58 | * @return Geofence 59 | * @throws TraccarException 60 | */ 61 | public function createGeofence(string $name, string $area, int $id = -1, string $description = null, int $calendarId = null, array $attribs = []): Geofence 62 | { 63 | if (empty($name)) { 64 | throw new TraccarException("Name cannot be empty !"); 65 | } 66 | $response = $this->service->post( 67 | request: $this->service->buildRequestWithBasicAuth(), 68 | url: 'geofences', 69 | payload: [ 70 | "name" => $name, 71 | "id" => $id, 72 | "description" => $description, 73 | "area" => $area, 74 | "calendarId" => $calendarId, 75 | "attributes" => empty($attribs) ? null : $attribs 76 | ] 77 | ); 78 | if (!$response->ok()) { 79 | throw new TraccarException($response->toException()); 80 | } 81 | return Geofence::createFromValueArray($response->json()); 82 | } 83 | 84 | /** 85 | * @param Geofence $geofence 86 | * @return Geofence 87 | * @throws TraccarException 88 | */ 89 | public function createNewGeofence(Geofence $geofence): Geofence 90 | { 91 | if ($geofence->area == '') { 92 | throw new TraccarException("Area cannot be empty !"); 93 | } 94 | if ($geofence->name == '') { 95 | throw new TraccarException("Name cannot be empty !"); 96 | } 97 | $postData = $geofence->toArray(); 98 | $postData["attributes"] = empty($postData["attribs"]) ? null : $postData["attribs"]; 99 | unset($postData["attribs"]); 100 | $response = $this->service->post( 101 | request: $this->service->buildRequestWithBasicAuth(), 102 | url: 'geofences', 103 | payload: $postData 104 | ); 105 | if (!$response->ok()) { 106 | throw new TraccarException($response->toException()); 107 | } 108 | return Geofence::createFromValueArray($response->json()); 109 | } 110 | 111 | /** 112 | * @param Geofence $geofence 113 | * @return Geofence 114 | * @throws TraccarException 115 | */ 116 | public function updateGeofence(Geofence $geofence): Geofence 117 | { 118 | $putData = $geofence->toArray(); 119 | $putData["attributes"] = empty($putData["attribs"]) ? null : $putData["attribs"]; 120 | unset($putData["attribs"]); 121 | $response = $this->service->put( 122 | request: $this->service->buildRequestWithBasicAuth(), 123 | url: 'geofences/' . $geofence->id, 124 | payload: $putData 125 | ); 126 | if (!$response->ok()) { 127 | throw new TraccarException($response->toException()); 128 | } 129 | return Geofence::createFromValueArray($response->json()); 130 | } 131 | 132 | /** 133 | * @param int|Geofence $geofence 134 | * @return bool 135 | * @throws TraccarException 136 | */ 137 | public function deleteGeofence(int|Geofence $geofence): bool 138 | { 139 | $response = $this->service->delete( 140 | request: $this->service->buildRequestWithBasicAuth(), 141 | url: 'geofences/' . ($geofence instanceof Geofence ? $geofence->id : $geofence) 142 | ); 143 | if (!$response->noContent()) { 144 | throw new TraccarException($response->toException()); 145 | } 146 | return true; 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/Services/Resources/PositionResources.php: -------------------------------------------------------------------------------- 1 | prepareMultipleQuery('id', $id); 38 | } else { 39 | $query["id"] = $id; 40 | } 41 | } 42 | $from = Carbon::parse($from); 43 | $to = Carbon::parse($to); 44 | if ($from->greaterThan($to)) { 45 | throw new TraccarException("The from date cannot be greater than the to date"); 46 | } 47 | $query["from"] = $from->format('Y-m-d\TH:i:s\Z'); 48 | $query["to"] = $to->format('Y-m-d\TH:i:s\Z'); 49 | $response = $this->service->get( 50 | request: $this->service->buildRequestWithBasicAuth(), 51 | url: 'positions', 52 | query: urldecode(http_build_query($query, '', '&')) 53 | ); 54 | if (!$response->ok()) { 55 | throw new TraccarException($response->toException()); 56 | } 57 | return Position::createFromValueList($response->json()); 58 | } 59 | 60 | /** 61 | * @param string $uniqueId The unique identifier for the device. This is a mandatory parameter. 62 | * @param bool $valid Indicates if the location is valid. Acceptable values are "true", "false", "1", and "0". 63 | * @param string $timestamp The timestamp of the position. It can be in seconds or milliseconds since epoch, ISO 8601 format, or "yyyy-MM-dd HH:mm:ss" format. 64 | * @param float $lat Latitude of the position. This should be a double value. 65 | * @param float $lon Longitude of the position. This should be a double value. 66 | * @param string|null $location A comma-separated string in the format "latitude,longitude". 67 | * @param string|null $cell Cell tower information in the format "mcc,mnc,lac,cellId,signalStrength" or "mcc,mnc,lac,cellId". 68 | * @param string|null $wifi WiFi access point information in the format "macAddress:signalStrength". 69 | * @param int $speed Speed of the device. Units are configurable with knots as a default. 70 | * @param string|null $bearing The direction in which the device is moving, in degrees. 71 | * @param float $altitude Altitude of the device in meters. 72 | * @param float|null $accuracy Accuracy of the position in meters. 73 | * @param string|null $hdop Horizontal dilution of precision. 74 | * @param string|null $batt Battery level of the device. 75 | * @param string|null $driverUniqueId Unique identifier for the driver. 76 | * @param bool|null $charge Indicates if the device is charging. Acceptable values are `true` and `false`. 77 | * @param ...$extra 78 | * @return void 79 | * @throws TraccarException 80 | * @link https://www.traccar.org/osmand/ 81 | * @phpstan-ignore-next-line 82 | */ 83 | public function OsmAnd(string $uniqueId, bool $valid = true, string $timestamp = '', 84 | float $lat = 0.0, float $lon = 0.0, string $location = null, string $cell = null, 85 | string $wifi = null, int $speed = 0, string $bearing = null, float $altitude = 0.0, 86 | float $accuracy = null, string $hdop = null, string $batt = null, string $driverUniqueId = null, 87 | bool $charge = null, ...$extra 88 | ): void 89 | { 90 | $timestamp = empty($timestamp) ? now() : Carbon::parse($timestamp); 91 | $params = array_merge([ 92 | "id" => $uniqueId, "valid" => $valid, "timestamp" => $timestamp->timestamp, "latitude" => $lat, 93 | "longitude" => $lon, "location" => $location, "cell" => $cell, "wifi" => $wifi, "speed" => $speed, 94 | "bearing" => $bearing, "altitude" => $altitude, "accuracy" => $accuracy, "hdop" => $hdop, 95 | "batt" => $batt, "driverUniqueId" => $driverUniqueId, "charge" => $charge 96 | ], $extra); 97 | $response = $this->service->post( 98 | request: $this->service->withBaseUrl(useAPI: false)->withQueryParameters($params), 99 | url: "", 100 | ); 101 | if (!$response->ok()) { 102 | throw new TraccarException($response->toException()); 103 | } 104 | } 105 | 106 | /** 107 | * @param int|Device $device 108 | * @param string $from 109 | * @param string $to 110 | * @return bool 111 | * @throws TraccarException 112 | */ 113 | public function deletePositions(int|Device $device, string $from, string $to): bool 114 | { 115 | $query = ["deviceId" => ($device instanceof Device ? $device->id : $device)]; 116 | $from = Carbon::parse($from); 117 | $to = Carbon::parse($to); 118 | if ($from->greaterThan($to)) { 119 | throw new TraccarException("The from date cannot be greater than the to date"); 120 | } 121 | $query["from"] = $from->format('Y-m-d\TH:i:s\Z'); 122 | $query["to"] = $to->format('Y-m-d\TH:i:s\Z'); 123 | $response = $this->service->delete( 124 | request: $this->service->buildRequestWithBasicAuth()->withQueryParameters($query), 125 | url: 'positions' 126 | ); 127 | if (!$response->noContent()) { 128 | throw new TraccarException($response->toException()); 129 | } 130 | return true; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Services/TraccarService.php: -------------------------------------------------------------------------------- 1 | cacheKey = Str::slug($email, '_') . '_traccar_auth'; 55 | if (!Cache::has($this->cacheKey) && !empty($this->baseUrl) && !empty($this->email) && !empty($this->password)) { 56 | $this->sessionRepository()->createNewSession(); 57 | } 58 | } 59 | 60 | /** 61 | * @return SessionResources 62 | */ 63 | public function sessionRepository(): SessionResources 64 | { 65 | return new SessionResources($this); 66 | } 67 | 68 | /** 69 | * @return string|null 70 | */ 71 | public function getToken(): ?string 72 | { 73 | return $this->token; 74 | } 75 | 76 | /** 77 | * @param string|null $token 78 | * @return void 79 | */ 80 | public function setToken(?string $token): void 81 | { 82 | $this->token = $token; 83 | } 84 | 85 | /** 86 | * @return string 87 | */ 88 | public function getBaseUrl(): string 89 | { 90 | return $this->baseUrl; 91 | } 92 | 93 | /** 94 | * @param string $baseUrl 95 | * @return $this 96 | */ 97 | public function setBaseUrl(string $baseUrl): TraccarService 98 | { 99 | $this->baseUrl = $baseUrl; 100 | return $this; 101 | } 102 | 103 | /** 104 | * @return string 105 | */ 106 | public function getEmail(): string 107 | { 108 | return $this->email; 109 | } 110 | 111 | /** 112 | * @param string $email 113 | * @return $this 114 | */ 115 | public function setEmail(string $email): TraccarService 116 | { 117 | $this->email = $email; 118 | return $this; 119 | } 120 | 121 | /** 122 | * @return string 123 | */ 124 | public function getPassword(): string 125 | { 126 | return $this->password; 127 | } 128 | 129 | /** 130 | * @param string $password 131 | * @return $this 132 | */ 133 | public function setPassword(string $password): TraccarService 134 | { 135 | $this->password = $password; 136 | return $this; 137 | } 138 | 139 | /** 140 | * @return array 141 | */ 142 | public function getHeaders(): array 143 | { 144 | return $this->headers; 145 | } 146 | 147 | /** 148 | * @param array $headers 149 | * @return $this 150 | */ 151 | public function setHeaders(array $headers): TraccarService 152 | { 153 | $this->headers = $headers; 154 | return $this; 155 | } 156 | 157 | /** 158 | * @return string 159 | */ 160 | public function getCacheKey(): string 161 | { 162 | return $this->cacheKey ?? Str::slug($this->email, '_') . '_traccar_auth'; 163 | } 164 | 165 | /** 166 | * @param string $cacheKey 167 | * @return $this 168 | */ 169 | public function setCacheKey(string $cacheKey): TraccarService 170 | { 171 | $this->cacheKey = $cacheKey; 172 | return $this; 173 | } 174 | 175 | /** 176 | * @return ServerResources 177 | */ 178 | public function serverRepository(): ServerResources 179 | { 180 | return new ServerResources($this); 181 | } 182 | 183 | /** 184 | * @return DeviceResources 185 | */ 186 | public function deviceRepository(): DeviceResources 187 | { 188 | return new DeviceResources($this); 189 | } 190 | 191 | /** 192 | * @return GroupResources 193 | */ 194 | public function groupRepository(): GroupResources 195 | { 196 | return new GroupResources($this); 197 | } 198 | 199 | /** 200 | * @return UserResources 201 | */ 202 | public function userRepository(): UserResources 203 | { 204 | return new UserResources($this); 205 | } 206 | 207 | /** 208 | * @return PositionResources 209 | */ 210 | public function positionRepository(): PositionResources 211 | { 212 | return new PositionResources($this); 213 | } 214 | 215 | /** 216 | * @return EventResources 217 | */ 218 | public function eventRepository(): EventResources 219 | { 220 | return new EventResources($this); 221 | } 222 | 223 | /** 224 | * @return NotificationResources 225 | */ 226 | public function notificationRepository(): NotificationResources 227 | { 228 | return new NotificationResources($this); 229 | } 230 | 231 | /** 232 | * @return GeofenceResources 233 | */ 234 | public function geofenceRepository(): GeofenceResources 235 | { 236 | return new GeofenceResources($this); 237 | } 238 | 239 | /** 240 | * @return DriverResources 241 | */ 242 | public function driverRepository(): DriverResources 243 | { 244 | return new DriverResources($this); 245 | } 246 | 247 | /** 248 | * @return ReportResources 249 | */ 250 | public function reportRepository(): ReportResources 251 | { 252 | return new ReportResources($this); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/Services/Resources/ReportResources.php: -------------------------------------------------------------------------------- 1 | getReportData($deviceId, $from, $to); 33 | $response = $this->service->get( 34 | request: $this->service->buildRequestWithBasicAuth(), 35 | url: 'reports/route', 36 | query: urldecode(http_build_query($query, '', '&')) 37 | ); 38 | if (!$response->ok()) { 39 | throw new TraccarException($response->toException()); 40 | } 41 | return Report::createFromValueList($response->json()); 42 | } 43 | 44 | /** 45 | * @param int|array|null $deviceId 46 | * @param string $from 47 | * @param string $to 48 | * @return array 49 | * @throws TraccarException 50 | */ 51 | protected function getReportData(int|array|null $deviceId, string $from, string $to): array 52 | { 53 | $query = []; 54 | if (!empty($deviceId)) { 55 | if (is_array($deviceId)) { 56 | $query["deviceId"] = $this->prepareMultipleQuery('deviceId', $deviceId); 57 | } else { 58 | $query["deviceId"] = $deviceId; 59 | } 60 | } 61 | $from = Carbon::parse($from); 62 | $to = Carbon::parse($to); 63 | if ($from->greaterThan($to)) { 64 | throw new TraccarException("The [from] date cannot be greater than the [to] date."); 65 | } 66 | $query["from"] = $from->format('Y-m-d\TH:i:s\Z'); 67 | $query["to"] = $to->format('Y-m-d\TH:i:s\Z'); 68 | return $query; 69 | } 70 | 71 | /** 72 | * @param string $from 73 | * @param string $to 74 | * @param int $deviceId 75 | * @param array|string|null $type 76 | * @return Collection 77 | * @throws TraccarException 78 | */ 79 | public function reportEvents(string $from, string $to, int $deviceId, null|array|string $type = 'allEvents'): Collection 80 | { 81 | $query = $this->getReportData($deviceId, $from, $to); 82 | if (!empty($type)) { 83 | if (is_array($type)) { 84 | $query["type"] = $this->prepareMultipleQuery('type', $type); 85 | } else { 86 | $query["type"] = $type; 87 | } 88 | } 89 | $response = $this->service->get( 90 | request: $this->service->buildRequestWithBasicAuth(), 91 | url: 'reports/events', 92 | query: urldecode(http_build_query($query, '', '&')) 93 | ); 94 | if (!$response->ok()) { 95 | throw new TraccarException($response->toException()); 96 | } 97 | return Report::createFromValueList($response->json()); 98 | } 99 | 100 | /** 101 | * @param string $from 102 | * @param string $to 103 | * @param array|int|null $deviceId 104 | * @param array|int|null $groupId 105 | * @param bool|null $daily 106 | * @return Collection 107 | * @throws TraccarException 108 | */ 109 | public function reportSummary(string $from, string $to, null|array|int $deviceId = null, null|array|int $groupId = null, bool|null $daily = null): Collection 110 | { 111 | $query = $this->getReportData($deviceId, $from, $to); 112 | if (!empty($groupId)) { 113 | if (is_array($groupId)) { 114 | $query["groupId"] = $this->prepareMultipleQuery('groupId', $groupId); 115 | } else { 116 | $query["groupId"] = $groupId; 117 | } 118 | } 119 | $query["daily"] = $daily ? 'true' : 'false'; 120 | $response = $this->service->get( 121 | request: $this->service->buildRequestWithBasicAuth(), 122 | url: 'reports/summary', 123 | query: urldecode(http_build_query($query, '', '&')) 124 | ); 125 | if (!$response->ok()) { 126 | throw new TraccarException($response->toException()); 127 | } 128 | return Report::createFromValueList($response->json()); 129 | } 130 | 131 | /** 132 | * @param string $from 133 | * @param string $to 134 | * @param int $deviceId 135 | * @return Collection 136 | * @throws TraccarException 137 | */ 138 | public function reportTrips(string $from, string $to, int $deviceId): Collection 139 | { 140 | $query = $this->getReportData($deviceId, $from, $to); 141 | $response = $this->service->get( 142 | request: $this->service->buildRequestWithBasicAuth(), 143 | url: 'reports/trips', 144 | query: urldecode(http_build_query($query, '', '&')) 145 | ); 146 | if (!$response->ok()) { 147 | throw new TraccarException($response->toException()); 148 | } 149 | return Report::createFromValueList($response->json()); 150 | } 151 | 152 | /** 153 | * @param string $from 154 | * @param string $to 155 | * @param int $deviceId 156 | * @return Collection 157 | * @throws TraccarException 158 | */ 159 | public function reportStops(string $from, string $to, int $deviceId): Collection 160 | { 161 | $query = $this->getReportData($deviceId, $from, $to); 162 | $response = $this->service->get( 163 | request: $this->service->buildRequestWithBasicAuth(), 164 | url: 'reports/stops', 165 | query: urldecode(http_build_query($query, '', '&')) 166 | ); 167 | if (!$response->ok()) { 168 | throw new TraccarException($response->toException()); 169 | } 170 | return Report::createFromValueList($response->json()); 171 | } 172 | 173 | /** 174 | * @param string $from 175 | * @param string $to 176 | * @param array|int|null $deviceId 177 | * @param array|int|null $groupId 178 | * @return Collection 179 | * @throws TraccarException 180 | */ 181 | public function reportCombined(string $from, string $to, null|array|int $deviceId = null, null|array|int $groupId = null): Collection 182 | { 183 | $query = $this->getReportData($deviceId, $from, $to); 184 | if (!empty($groupId)) { 185 | if (is_array($groupId)) { 186 | $query["groupId"] = $this->prepareMultipleQuery('groupId', $groupId); 187 | } else { 188 | $query["groupId"] = $groupId; 189 | } 190 | } 191 | $response = $this->service->get( 192 | request: $this->service->buildRequestWithBasicAuth(), 193 | url: 'reports/combined', 194 | query: urldecode(http_build_query($query, '', '&')) 195 | ); 196 | if (!$response->ok()) { 197 | throw new TraccarException($response->toException()); 198 | } 199 | return Report::createFromValueList($response->json()); 200 | } 201 | 202 | } 203 | -------------------------------------------------------------------------------- /src/Services/Resources/NotificationResources.php: -------------------------------------------------------------------------------- 1 | $all, "refresh" => $refresh]; 33 | if ($userId != null) { 34 | $query["userId"] = $userId; 35 | } 36 | if ($deviceId != null) { 37 | $query["deviceId"] = $deviceId; 38 | } 39 | if ($groupId != null) { 40 | $query["groupId"] = $groupId; 41 | } 42 | $response = $this->service->get( 43 | request: $this->service->buildRequestWithBasicAuth(), 44 | url: 'notifications', 45 | query: urldecode(http_build_query($query, '', '&')) 46 | ); 47 | if (!$response->ok()) { 48 | throw new TraccarException($response->toException()); 49 | } 50 | return Notification::createFromValueList($response->json()); 51 | } 52 | 53 | /** 54 | * @param string $type 55 | * @param array $notificators 56 | * @param bool $always 57 | * @param int|null $commandId 58 | * @param int|null $calendarId 59 | * @param array $attribs 60 | * @return Notification 61 | * @throws TraccarException 62 | */ 63 | public function createNotification(string $type, array $notificators, bool $always = false, int $commandId = null, int $calendarId = null, array $attribs = []): Notification 64 | { 65 | if (empty($type)) { 66 | throw new TraccarException("Type cannot be empty !"); 67 | } 68 | if (empty($notificators)) { 69 | throw new TraccarException("Notificators cannot be empty !"); 70 | } 71 | if (in_array(NotificatorType::COMMAND->value, $notificators, true)) { 72 | if (empty($commandId)) { 73 | throw new TraccarException("Command ID required !"); 74 | } 75 | } 76 | $response = $this->service->post( 77 | request: $this->service->buildRequestWithBasicAuth(), 78 | url: 'notifications', 79 | payload: [ 80 | "type" => $type, 81 | "notificators" => implode(',', $notificators), 82 | "always" => $always, 83 | "commandId" => $commandId, 84 | "calendarId" => $calendarId, 85 | "attributes" => empty($attribs) ? null : $attribs 86 | ] 87 | ); 88 | if (!$response->ok()) { 89 | throw new TraccarException($response->body()); 90 | } 91 | return Notification::createFromValueArray($response->json()); 92 | } 93 | 94 | /** 95 | * @param Notification $notification 96 | * @return Notification 97 | * @throws TraccarException 98 | */ 99 | public function createNewNotification(Notification $notification): Notification 100 | { 101 | if ($notification->type == '') { 102 | throw new TraccarException("Type cannot be empty !"); 103 | } 104 | if (empty($notification->notificators)) { 105 | throw new TraccarException("Notificators cannot be empty !"); 106 | } 107 | if (in_array(NotificatorType::COMMAND->value, explode(',', $notification->notificators), true)) { 108 | if (empty($notification->commandId)) { 109 | throw new TraccarException("Command ID required !"); 110 | } 111 | } 112 | $postData = $notification->toArray(); 113 | $postData["attributes"] = empty($postData["attribs"]) ? null : $postData["attribs"]; 114 | unset($postData["attribs"]); 115 | $response = $this->service->post( 116 | request: $this->service->buildRequestWithBasicAuth(), 117 | url: 'notifications', 118 | payload: $postData 119 | ); 120 | if (!$response->ok()) { 121 | throw new TraccarException($response->toException()); 122 | } 123 | return Notification::createFromValueArray($response->json()); 124 | } 125 | 126 | /** 127 | * @param Notification $notification 128 | * @return Notification 129 | * @throws TraccarException 130 | */ 131 | public function updateNotification(Notification $notification): Notification 132 | { 133 | $putData = $notification->toArray(); 134 | $putData["attributes"] = empty($putData["attribs"]) ? null : $putData["attribs"]; 135 | unset($putData["attribs"]); 136 | $response = $this->service->put( 137 | request: $this->service->buildRequestWithBasicAuth(), 138 | url: 'notifications/' . $notification->id, 139 | payload: $putData 140 | ); 141 | if (!$response->ok()) { 142 | throw new TraccarException($response->toException()); 143 | } 144 | return Notification::createFromValueArray($response->json()); 145 | } 146 | 147 | /** 148 | * @param int|Notification $notification 149 | * @return bool 150 | * @throws TraccarException 151 | */ 152 | public function deleteNotification(int|Notification $notification): bool 153 | { 154 | $response = $this->service->delete( 155 | request: $this->service->buildRequestWithBasicAuth(), 156 | url: 'notifications/' . ($notification instanceof Notification ? $notification->id : $notification) 157 | ); 158 | if (!$response->noContent()) { 159 | throw new TraccarException($response->toException()); 160 | } 161 | return true; 162 | } 163 | 164 | /** 165 | * @return array 166 | * @throws TraccarException 167 | */ 168 | public function fetchNotificationTypes(): array 169 | { 170 | $response = $this->service->get( 171 | request: $this->service->buildRequestWithBasicAuth(), 172 | url: 'notifications/types', 173 | ); 174 | if (!$response->ok()) { 175 | throw new TraccarException($response->toException()); 176 | } 177 | $res = $response->json(); 178 | return is_array($res) ? $res : []; 179 | } 180 | 181 | /** 182 | * @param string $type 183 | * @param string $notificator 184 | * @param bool $always 185 | * @param int|null $commandId 186 | * @return void 187 | * @throws TraccarException 188 | */ 189 | public function sendTestNotification(string $type, string $notificator, bool $always = false, int $commandId = null): void 190 | { 191 | $response = $this->service->post( 192 | request: $this->service->buildRequestWithBasicAuth(), 193 | url: 'notifications/test/' . $notificator, 194 | payload: [ 195 | "type" => $type, 196 | "notificators" => $notificator, 197 | "always" => $always, 198 | "commandId" => $commandId, 199 | ] 200 | ); 201 | if (!$response->noContent()) { 202 | throw new TraccarException($response->body()); 203 | } 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /src/Services/Resources/UserResources.php: -------------------------------------------------------------------------------- 1 | service->get( 32 | request: $this->service->buildRequestWithBasicAuth(), 33 | url: 'users', 34 | query: urldecode(http_build_query($query, '', '&')) 35 | ); 36 | if (!$response->ok()) { 37 | throw new TraccarException($response->toException()); 38 | } 39 | return User::createFromValueList($response->json()); 40 | } 41 | 42 | 43 | /** 44 | * @param string $name 45 | * @param string $email 46 | * @param string $password 47 | * @param int|null $id 48 | * @param string $phone 49 | * @param bool $readonly 50 | * @param bool $administrator 51 | * @param string $map 52 | * @param float $latitude 53 | * @param float $longitude 54 | * @param int $zoom 55 | * @param bool $twelveHourFormat 56 | * @param string $coordinateFormat 57 | * @param bool $disabled 58 | * @param string $expirationTime in IS0 8601 format. eg. 1963-11-22T18:30:00Z 59 | * @param int $deviceLimit 60 | * @param int $userLimit 61 | * @param bool $deviceReadonly 62 | * @param bool $limitCommands 63 | * @param bool $fixedEmail 64 | * @param string $poiLayer 65 | * @param array $attribs 66 | * @return User 67 | * @throws TraccarException 68 | */ 69 | public function createUser(string $name, string $email, string $password, int $id = null, string $phone = '', bool $readonly = false, 70 | bool $administrator = false, string $map = '', float $latitude = 0, float $longitude = 0, int $zoom = 0, 71 | bool $twelveHourFormat = false, string $coordinateFormat = '0', bool $disabled = false, 72 | string $expirationTime = '', int $deviceLimit = 0, int $userLimit = 0, bool $deviceReadonly = false, 73 | bool $limitCommands = false, bool $fixedEmail = false, string $poiLayer = '', array $attribs = [] 74 | ): User 75 | { 76 | if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { 77 | throw new TraccarException("Invalid email address !"); 78 | } 79 | $response = $this->service->post( 80 | request: $this->service->buildRequestWithBasicAuth(), 81 | url: 'users', 82 | payload: [ 83 | "name" => $name, "email" => $email, "password" => $password, 84 | "id" => $id, "phone" => $phone, "readonly" => $readonly, 85 | "administrator" => $administrator, "map" => $map, "latitude" => $latitude, 86 | "longitude" => $longitude, "zoom" => $zoom, "twelveHourFormat" => $twelveHourFormat, 87 | "coordinateFormat" => $coordinateFormat, "disabled" => $disabled, "expirationTime" => $expirationTime, 88 | "deviceLimit" => $deviceLimit, "userLimit" => $userLimit, "deviceReadonly" => $deviceReadonly, 89 | "limitCommands" => $limitCommands, "fixedEmail" => $fixedEmail, "poiLayer" => $poiLayer, 90 | "attributes" => empty($attribs) ? null : $attribs 91 | ] 92 | ); 93 | if (!$response->ok()) { 94 | throw new TraccarException($response->toException()); 95 | } 96 | return User::createFromValueArray($response->json()); 97 | } 98 | 99 | /** 100 | * @param User $user 101 | * @return User 102 | * @throws TraccarException 103 | */ 104 | public function createNewUser(User $user): User 105 | { 106 | if (!filter_var($user->email, FILTER_VALIDATE_EMAIL)) { 107 | throw new TraccarException("Invalid email address !"); 108 | } 109 | if ($user->password == '') { 110 | throw new TraccarException("Password cannot be empty !"); 111 | } 112 | if ($user->name == '') { 113 | throw new TraccarException("Name cannot be empty !"); 114 | } 115 | $postData = $user->toArray(); 116 | $postData["attributes"] = empty($postData["attribs"]) ? null : $postData["attribs"]; 117 | unset($postData["attribs"]); 118 | $response = $this->service->post( 119 | request: $this->service->buildRequestWithBasicAuth(), 120 | url: 'users', 121 | payload: $postData 122 | ); 123 | if (!$response->ok()) { 124 | throw new TraccarException($response->toException()); 125 | } 126 | return User::createFromValueArray($response->json()); 127 | } 128 | 129 | 130 | /** 131 | * @param User $user 132 | * @return User 133 | * @throws TraccarException 134 | */ 135 | public function updateUser(User $user): User 136 | { 137 | $putData = $user->toArray(); 138 | $putData["attributes"] = empty($putData["attribs"]) ? null : $putData["attribs"]; 139 | unset($putData["attribs"]); 140 | $response = $this->service->put( 141 | request: $this->service->buildRequestWithBasicAuth(), 142 | url: 'users/' . $user->id, 143 | payload: $putData 144 | ); 145 | if (!$response->ok()) { 146 | throw new TraccarException($response->toException()); 147 | } 148 | return User::createFromValueArray($response->json()); 149 | } 150 | 151 | /** 152 | * @param int|User $user to get user id 153 | * @return bool 154 | * @throws TraccarException 155 | */ 156 | public function deleteUser(int|User $user): bool 157 | { 158 | $response = $this->service->delete( 159 | request: $this->service->buildRequestWithBasicAuth(), 160 | url: 'users/' . ($user instanceof User ? $user->id : $user) 161 | ); 162 | if (!$response->noContent()) { 163 | throw new TraccarException($response->toException()); 164 | } 165 | return true; 166 | } 167 | 168 | /** 169 | * @param int|User $user 170 | * @param int|Device $device 171 | * @return bool 172 | * @throws TraccarException 173 | */ 174 | public function assignUserDevice(int|User $user, int|Device $device): bool 175 | { 176 | $deviceId = $device instanceof Device ? $device->id : $device; 177 | $userId = $user instanceof User ? $user->id : $user; 178 | $response = $this->service->post( 179 | request: $this->service->buildRequestWithBasicAuth(), 180 | url: "permissions", 181 | payload: [ 182 | 'deviceId' => $deviceId, 183 | 'userId' => $userId 184 | ] 185 | ); 186 | if (!$response->noContent()) { 187 | throw new TraccarException($response->toException()); 188 | } 189 | return true; 190 | } 191 | 192 | /** 193 | * @param int|User $user 194 | * @param int|Device $device 195 | * @return bool 196 | * @throws TraccarException 197 | */ 198 | public function removeUserDevice(int|User $user, int|Device $device): bool 199 | { 200 | $deviceId = $device instanceof Device ? $device->id : $device; 201 | $userId = $user instanceof User ? $user->id : $user; 202 | $response = $this->service->delete( 203 | request: $this->service->buildRequestWithBasicAuth(), 204 | url: "permissions", 205 | payload: [ 206 | 'deviceId' => $deviceId, 207 | 'userId' => $userId 208 | ] 209 | ); 210 | if (!$response->noContent()) { 211 | throw new TraccarException($response->toException()); 212 | } 213 | return true; 214 | } 215 | 216 | } 217 | -------------------------------------------------------------------------------- /src/Services/Resources/DeviceResources.php: -------------------------------------------------------------------------------- 1 | fetchListDevices(all: false, id: $deviceId)->first(); 30 | return $d instanceof Device ? $d : null; 31 | } 32 | 33 | /** 34 | * @param bool $all 35 | * @param int|null $userId 36 | * @param array|int|null $id // device id 37 | * @param array|string|null $uniqueId // device unique id 38 | * @return Collection 39 | * @throws TraccarException 40 | */ 41 | public function fetchListDevices(bool $all = true, ?int $userId = null, null|array|int $id = null, null|array|string $uniqueId = null): Collection 42 | { 43 | $query = ["all" => $all]; 44 | if ($userId != null) { 45 | $query["userId"] = $userId; 46 | } 47 | if ($id != null) { 48 | if (is_array($id)) { 49 | $query["id"] = $this->prepareMultipleQuery('id', $id); 50 | } else { 51 | $query["id"] = $id; 52 | } 53 | } elseif ($uniqueId != null) { 54 | if (is_array($uniqueId)) { 55 | $query["uniqueId"] = $this->prepareMultipleQuery('uniqueId', $uniqueId); 56 | } else { 57 | $query["uniqueId"] = $uniqueId; 58 | } 59 | } 60 | $response = $this->service->get( 61 | request: $this->service->buildRequestWithBasicAuth(), 62 | url: 'devices', 63 | query: urldecode(http_build_query($query, '', '&')) 64 | ); 65 | if (!$response->ok()) { 66 | throw new TraccarException($response->toException()); 67 | } 68 | return Device::createFromValueList($response->json()); 69 | } 70 | 71 | /** 72 | * @param int $userId 73 | * @return Collection 74 | * @throws TraccarException 75 | */ 76 | public function getUserDevices(int $userId): Collection 77 | { 78 | return $this->fetchListDevices(all: false, userId: $userId); 79 | } 80 | 81 | /** 82 | * @param string $uniqueId 83 | * @return Device|null 84 | * @throws TraccarException 85 | */ 86 | public function getDeviceByUniqueId(string $uniqueId): null|Device 87 | { 88 | $d = $this->fetchListDevices(all: false, uniqueId: $uniqueId)->first(); 89 | return $d instanceof Device ? $d : null; 90 | } 91 | 92 | /** 93 | * @param string $name 94 | * @param string $uniqueId 95 | * @param int $id 96 | * @param string $status 97 | * @param bool $disabled 98 | * @param string|null $lastUpdate 99 | * @param int $positionId 100 | * @param int $groupId 101 | * @param string $phone 102 | * @param string $model 103 | * @param string $contact 104 | * @param string $category 105 | * @param array $attribs 106 | * @return Device 107 | * @throws TraccarException 108 | */ 109 | public function createDevice(string $name, string $uniqueId, int $id = -1, string $status = "", 110 | bool $disabled = false, ?string $lastUpdate = null, int $positionId = 0, 111 | int $groupId = 0, string $phone = "", string $model = "", string $contact = "", 112 | string $category = "", array $attribs = [] 113 | ): Device 114 | { 115 | $response = $this->service->post( 116 | request: $this->service->buildRequestWithBasicAuth(), 117 | url: 'devices', 118 | payload: [ 119 | 'id' => $id, 120 | 'name' => $name, 121 | 'uniqueId' => $uniqueId, 122 | 'status' => $status, 123 | 'disabled' => $disabled, 124 | 'lastUpdate' => $lastUpdate, 125 | 'positionId' => $positionId, 126 | 'groupId' => $groupId, 127 | 'phone' => $phone, 128 | 'model' => $model, 129 | 'contact' => $contact, 130 | 'category' => $category, 131 | 'attributes' => empty($attribs) ? null : $attribs 132 | ] 133 | ); 134 | if (!$response->ok()) { 135 | throw new TraccarException($response->toException()); 136 | } 137 | return Device::createFromValueArray($response->json()); 138 | } 139 | 140 | /** 141 | * @param Device $device 142 | * @return Device 143 | * @throws TraccarException 144 | */ 145 | public function createNewDevice(Device $device): Device 146 | { 147 | if ($device->uniqueId == '') { 148 | throw new TraccarException("UniqueId cannot be empty !"); 149 | } 150 | if ($device->name == '') { 151 | throw new TraccarException("Name cannot be empty !"); 152 | } 153 | $postData = $device->toArray(); 154 | $postData["attributes"] = empty($postData["attribs"]) ? null : $postData["attribs"]; 155 | unset($postData["attribs"]); 156 | $response = $this->service->post( 157 | request: $this->service->buildRequestWithBasicAuth(), 158 | url: 'devices', 159 | payload: $postData 160 | ); 161 | if (!$response->ok()) { 162 | throw new TraccarException($response->toException()); 163 | } 164 | return Device::createFromValueArray($response->json()); 165 | } 166 | 167 | /** 168 | * @param Device $device 169 | * @return Device 170 | * @throws TraccarException 171 | */ 172 | public function updateDevice(Device $device): Device 173 | { 174 | $putData = $device->toArray(); 175 | $putData["attributes"] = empty($putData["attribs"]) ? null : $putData["attribs"]; 176 | unset($putData["attribs"]); 177 | $response = $this->service->put( 178 | request: $this->service->buildRequestWithBasicAuth(), 179 | url: 'devices/' . $device->id, 180 | payload: $putData 181 | ); 182 | if (!$response->ok()) { 183 | throw new TraccarException($response->toException()); 184 | } 185 | return Device::createFromValueArray($response->json()); 186 | } 187 | 188 | /** 189 | * @param int|Device $device 190 | * @return bool 191 | * @throws TraccarException 192 | */ 193 | public function deleteDevice(int|Device $device): bool 194 | { 195 | $response = $this->service->delete( 196 | request: $this->service->buildRequestWithBasicAuth(), 197 | url: 'devices/' . ($device instanceof Device ? $device->id : $device) 198 | ); 199 | if (!$response->noContent()) { 200 | throw new TraccarException($response->toException()); 201 | } 202 | return true; 203 | } 204 | 205 | /** 206 | * @param int|Device $device 207 | * @param int $totalDistance 208 | * @param int $hours 209 | * @return bool 210 | * @throws TraccarException 211 | */ 212 | public function updateTotalDistanceAndHoursOfDevice(int|Device $device, int $totalDistance = 0, int $hours = 0): bool 213 | { 214 | $deviceId = $device instanceof Device ? $device->id : $device; 215 | $response = $this->service->put( 216 | request: $this->service->buildRequestWithBasicAuth(), 217 | url: "devices/$deviceId/accumulators", 218 | payload: [ 219 | 'deviceId' => $deviceId, 220 | 'totalDistance' => $totalDistance, 221 | 'hours' => $hours 222 | ] 223 | ); 224 | if (!$response->noContent()) { 225 | throw new TraccarException($response->toException()); 226 | } 227 | return true; 228 | } 229 | 230 | /** 231 | * @param int|Device $device 232 | * @param int|Geofence $geofence 233 | * @return bool 234 | * @throws TraccarException 235 | */ 236 | public function assignDeviceGeofence(int|Device $device, int|Geofence $geofence): bool 237 | { 238 | $deviceId = $device instanceof Device ? $device->id : $device; 239 | $geofenceId = $geofence instanceof Geofence ? $geofence->id : $geofence; 240 | $response = $this->service->post( 241 | request: $this->service->buildRequestWithBasicAuth(), 242 | url: "permissions", 243 | payload: [ 244 | 'deviceId' => $deviceId, 245 | 'geofenceId' => $geofenceId 246 | ] 247 | ); 248 | if (!$response->noContent()) { 249 | throw new TraccarException($response->toException()); 250 | } 251 | return true; 252 | } 253 | 254 | /** 255 | * @param int|Device $device 256 | * @param int|Geofence $geofence 257 | * @return bool 258 | * @throws TraccarException 259 | */ 260 | public function removeDeviceGeofence(int|Device $device, int|Geofence $geofence): bool 261 | { 262 | $deviceId = $device instanceof Device ? $device->id : $device; 263 | $geofenceId = $geofence instanceof Geofence ? $geofence->id : $geofence; 264 | $response = $this->service->delete( 265 | request: $this->service->buildRequestWithBasicAuth(), 266 | url: "permissions", 267 | payload: [ 268 | 'deviceId' => $deviceId, 269 | 'geofenceId' => $geofenceId 270 | ] 271 | ); 272 | if (!$response->noContent()) { 273 | throw new TraccarException($response->toException()); 274 | } 275 | return true; 276 | } 277 | 278 | /** 279 | * @param int|Device $device 280 | * @param int|Notification $notification 281 | * @return bool 282 | * @throws TraccarException 283 | */ 284 | public function assignDeviceNotification(int|Device $device, int|Notification $notification): bool 285 | { 286 | $deviceId = $device instanceof Device ? $device->id : $device; 287 | $notificationId = $notification instanceof Notification ? $notification->id : $notification; 288 | $response = $this->service->post( 289 | request: $this->service->buildRequestWithBasicAuth(), 290 | url: "permissions", 291 | payload: [ 292 | 'deviceId' => $deviceId, 293 | 'notificationId' => $notificationId 294 | ] 295 | ); 296 | if (!$response->noContent()) { 297 | throw new TraccarException($response->toException()); 298 | } 299 | return true; 300 | } 301 | 302 | /** 303 | * @param int|Device $device 304 | * @param int|Notification $notification 305 | * @return bool 306 | * @throws TraccarException 307 | */ 308 | public function removeDeviceNotification(int|Device $device, int|Notification $notification): bool 309 | { 310 | $deviceId = $device instanceof Device ? $device->id : $device; 311 | $notificationId = $notification instanceof Notification ? $notification->id : $notification; 312 | $response = $this->service->delete( 313 | request: $this->service->buildRequestWithBasicAuth(), 314 | url: "permissions", 315 | payload: [ 316 | 'deviceId' => $deviceId, 317 | 'notificationId' => $notificationId 318 | ] 319 | ); 320 | if (!$response->noContent()) { 321 | throw new TraccarException($response->toException()); 322 | } 323 | return true; 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Traccar GPS server 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/mr-wolf-gb/traccar.svg?style=flat-square)](https://packagist.org/packages/mr-wolf-gb/traccar) 4 | [![Total Downloads](https://img.shields.io/packagist/dt/mr-wolf-gb/traccar.svg?style=flat-square)](https://packagist.org/packages/mr-wolf-gb/traccar) 5 | [![Latest Unstable Version](http://poser.pugx.org/mr-wolf-gb/traccar/v/unstable?style=flat-square)](https://packagist.org/packages/mr-wolf-gb/traccar) 6 | [![License](http://poser.pugx.org/mr-wolf-gb/traccar/license?style=flat-square)](https://packagist.org/packages/mr-wolf-gb/traccar) 7 | [![PHP Version Require](http://poser.pugx.org/mr-wolf-gb/traccar/require/php?style=flat-square)](https://packagist.org/packages/mr-wolf-gb/traccar) 8 | 9 | This Laravel package serves as a seamless integration tool, empowering developers to effortlessly interact with Traccar 10 | servers through their robust API. Traccar, a powerful GPS tracking platform, becomes more accessible than ever as this 11 | package streamlines communication between your Laravel application and the Traccar server, offering a wide range of 12 | functionalities and capabilities. Whether you're retrieving real-time location data, managing devices, or leveraging 13 | advanced tracking features, this package simplifies the process, enhancing the efficiency and extensibility of your 14 | Laravel projects. 15 | 16 | ## Table of Contents 17 | 18 | - Installation 19 | - Features and Usage 20 | - Multi-users and servers 21 | - Available ressources 22 | - Server 23 | - Session 24 | - User 25 | - Group 26 | - Device 27 | - Geofence 28 | - Notification 29 | - Position 30 | - Event 31 | - Driver 32 | - Report 33 | - Traccar Custom Server and Features 34 | - Testing 35 | - Changelog 36 | - Contributing 37 | - Credits 38 | - License 39 | 40 | ## :wrench: Required PHP version 41 | 42 | | Version | Php Version | 43 | |---------|-------------| 44 | | 1.0.0 | ^8.1 | 45 | 46 | ## Installation 47 | 48 | You can install the package via composer: 49 | 50 | ```bash 51 | composer require mr-wolf-gb/traccar 52 | ``` 53 | 54 | You can publish the config and migration: 55 | 56 | ```bash 57 | php artisan vendor:publish --provider="MrWolfGb\Traccar\TraccarServiceProvider" 58 | ``` 59 | 60 | Set traccar server information [.env file]: 61 | 62 | ```dotenv 63 | TRACCAR_BASE_URL="http://localhost:8082/" 64 | TRACCAR_SOCKET_URL="ws://localhost:8082/api/socket" 65 | TRACCAR_USERNAME="admin@traccar.local" 66 | TRACCAR_PASSWORD="password" 67 | TRACCAR_TOKEN="RzBFAiEA84hXSL6uV6FQyBX0_Ds1a6NMcSC..." 68 | # token required only when using fetch session informations 69 | ``` 70 | 71 | ## ✨ Features and Usage 72 | 73 | #### Multi-users and servers 74 | 75 | ```php 76 | // by default, it uses .env credentials else you can set it manually 77 | // Inject service as public variable in Controller 78 | public function __construct(public TraccarService $traccarService) 79 | { 80 | $this->traccarService->setEmail("user1@traccar.local"); 81 | $this->traccarService->setPassword("password"); 82 | $this->traccarService->setBaseUrl("http://localhost:8082/"); 83 | $this->traccarService->setToken("ws://localhost:8082/api/socket"); 84 | } 85 | // or inject directly in specific method 86 | public function index(TraccarService $traccarService) 87 | { 88 | //... 89 | } 90 | ``` 91 | 92 | #### Available ressources 93 | 94 | - #### *Server* 95 | 96 | Model : **[Server Model](src/Models/Server.php)** 97 | 98 | ```php 99 | public function index(TraccarService $traccarService) 100 | { 101 | $serverRepo = $traccarService->serverRepository(); 102 | // Get server information 103 | $srv = $serverRepo->fetchServerInformation(); 104 | // Update server information 105 | $serverRepo->updateServerInformation(server: $srv); 106 | } 107 | ``` 108 | 109 | - #### *Session* 110 | 111 | Model : **[Session Model](src/Models/Session.php)** 112 | 113 | ```php 114 | public function index(TraccarService $traccarService) 115 | { 116 | $sessionRepo = $traccarService->sessionRepository(); 117 | // Create new session 118 | $session = $sessionRepo->createNewSession(); 119 | // Get connected session [Require user Token in configuration] 120 | $session = $sessionRepo->fetchSessionInformation(); 121 | // Close session 122 | $sessionRepo->closeSession(); 123 | } 124 | ``` 125 | 126 | - #### *User* 127 | 128 | Model : **[User Model](src/Models/User.php)** 129 | 130 | ```php 131 | public function index(TraccarService $traccarService) 132 | { 133 | $userRepo = $traccarService->userRepository(); 134 | // Get list of users 135 | $list = $userRepo->fetchListUsers(); 136 | // Create new user 137 | $user = $userRepo->createUser( 138 | name: 'test', 139 | email: 'test@test.local', 140 | password: 'test' 141 | ); 142 | // Create new user with Model : MrWolfGb\Traccar\Models\User 143 | $user = $userRepo->createNewUser(new User([ 144 | 'name' => 'test', 145 | 'email' => 'test@test.local', 146 | 'password' => 'test', 147 | ])); 148 | // Update user 149 | $user = $userRepo->updateUser(user: $user); 150 | // Delete user : int|User $user 151 | $userRepo->deleteUser(user: $user); 152 | // Assign user to device : int|User $user, int|Device $device 153 | $userRepo->assignUserDevice(user: 1, device: 1); 154 | // Remove user from device : int|User $user, int|Device $device 155 | $userRepo->removeUserDevice(user: 1, device: 1); 156 | } 157 | ``` 158 | 159 | - #### *Group* 160 | 161 | Model : **[Group Model](src/Models/Group.php)** 162 | 163 | ```php 164 | public function index(TraccarService $traccarService) 165 | { 166 | $groupRepo = $traccarService->groupRepository(); 167 | // Get list of groups 168 | $list = $groupRepo->fetchListGroups(); 169 | // Create new group 170 | $group = $groupRepo->createGroup(name: 'test-group'); 171 | // Create new group with Model : MrWolfGb\Traccar\Models\Group 172 | $group = $groupRepo->createNewGroup(group: new Group(['name' => 'test'])); 173 | // Update group 174 | $user = $groupRepo->updateGroup(group: $group); 175 | // Delete group : int|Group $group 176 | $groupRepo->deleteGroup(group: $group); 177 | } 178 | ``` 179 | 180 | - #### *Device* 181 | 182 | Model : **[Device Model](src/Models/Device.php)** 183 | 184 | ```php 185 | public function index(TraccarService $traccarService) 186 | { 187 | $deviceRepo = $traccarService->deviceRepository(); 188 | // Get list of devices 189 | $list = $deviceRepo->fetchListDevices(); 190 | // Get user devices 191 | $list = $deviceRepo->getUserDevices(userId: 1); 192 | // Get device by id 193 | $device = $deviceRepo->getDeviceById(deviceId: 1); 194 | // Get device by uniqueId 195 | $device = $deviceRepo->getDeviceByUniqueId(uniqueId: 123456); 196 | // Create new device 197 | $device = $deviceRepo->createDevice(name: 'test', uniqueId: '123456789'); 198 | // Create new device with Model : MrWolfGb\Traccar\Models\Device 199 | $device = $deviceRepo->createNewDevice(device: new Device([ 200 | 'name' => 'test-device', 201 | 'uniqueId' => '123456789-d1-device', 202 | ])); 203 | // Update device 204 | $device = $deviceRepo->updateDevice(device: $device); 205 | // Delete device : int|Device $device 206 | $deviceRepo->deleteDevice(device: $device); 207 | // Update total distance and hours 208 | $deviceRepo->updateTotalDistanceAndHoursOfDevice(device: $device, totalDistance: 100, hours: 10); 209 | // Assign device to geofence : int|Device $device, int|Geofence $geofence 210 | $deviceRepo->assignDeviceGeofence(device: $device, geofence: $geofence); 211 | // Remove device from geofence : int|Device $device, int|Geofence $geofence 212 | $deviceRepo->removeDeviceGeofence(device: $device, geofence: $geofence); 213 | // Assign device to notification : int|Device $device, int|Notification $notification 214 | $deviceRepo->assignDeviceNotification(device: $device, notification: $notification); 215 | // Remove device from notification : int|Device $device, int|Notification $notification 216 | $deviceRepo->removeDeviceNotification(device: $device, notification: $notification); 217 | } 218 | ``` 219 | 220 | - #### *Geofence* 221 | 222 | Model : **[Geofence Model](src/Models/Geofence.php)** 223 | 224 | ```php 225 | public function index(TraccarService $traccarService) 226 | { 227 | $geofenceRepo = $traccarService->geofenceRepository(); 228 | // Get list of geofences 229 | $list = $geofenceRepo->fetchListGeofences(); 230 | // Get geofence 231 | $geofence = $geofenceRepo->createGeofence( 232 | name: 'test-geofence', 233 | area: 'POLYGON ((34.55602185173028 -18.455295134508617, 37.67183427726626 -18.13110040602976, 34.98211925933252 -14.500119447061167, 34.55602185173028 -18.455295134508617))', 234 | description: 'test' 235 | ); 236 | // Create new geofence with Model : MrWolfGb\Traccar\Models\Geofence 237 | $geofence = $geofenceRepo->createNewGeofence( geofence: new Geofence([ 238 | 'name' => 'test-geofence', 239 | 'area' => 'LINESTRING (38.06472440318089 -26.49821693459276, 38.4968396008517 -24.64860674974679, 37.297972401178825 -23.72380165732423, 38.099388220592346 -23.37149495544884)', 240 | 'description' => 'test' 241 | ])); 242 | // Update geofence 243 | $geofence = $geofenceRepo->updateGeofence(geofence: $geofence); 244 | // Delete geofence : int|Geofence $geofence 245 | $geofenceRepo->deleteGeofence(geofence: $geofence); 246 | } 247 | ``` 248 | 249 | - #### *Notification* 250 | 251 | Model : **[Notification Model](src/Models/Notification.php)** 252 | 253 | ```php 254 | public function index(TraccarService $traccarService) 255 | { 256 | $notificationRepo = $traccarService->notificationRepository(); 257 | // Get list of notifications 258 | $list = $notificationRepo->fetchListNotifications(); 259 | // Create new notification 260 | $notification = $notificationRepo->createNotification( 261 | type: 'alarm', 262 | notificators: ['web'], 263 | always: true 264 | ); 265 | // Create new notification with Model : MrWolfGb\Traccar\Models\Notification 266 | $notification = $notificationRepo->createNewNotification(new Notification([ 267 | 'type' => NotificationType::ALARM->value, 268 | 'notificator' => implode(',', [ 269 | NotificatorType::WEB->value, 270 | NotificatorType::COMMAND->value 271 | ]), 272 | 'always' => false, 273 | 'commandId' => 1, // required if notificator is/contains command 274 | ])); 275 | // Update notification 276 | $notification = $notificationRepo->updateNotification(notification: $notification); 277 | // Delete notification : int|Notification $notification 278 | $notificationRepo->deleteNotification(notification: $notification); 279 | // Get notification types from Traccar server 280 | $list = $notificationRepo->fetchNotificationTypes(); 281 | // Send test notification 282 | $notificationRepo->sendTestNotification( 283 | type: NotificationType::MEDIA->value, 284 | notificator: NotificatorType::WEB->value 285 | ); 286 | } 287 | ``` 288 | 289 | - #### *Position* 290 | 291 | Model : **[Position Model](src/Models/Position.php)** 292 | 293 | ```php 294 | public function index(TraccarService $traccarService) 295 | { 296 | $positionRepo = $traccarService->positionRepository(); 297 | // Get list of positions 298 | $list = $positionRepo->fetchListPositions( 299 | from: now()->subHours(1), 300 | to: now(), 301 | id: [1, 2, 3] // optional 302 | ); 303 | // Delete positions of device : int|Device $device 304 | $positionRepo->deletePositions( 305 | device: 1, 306 | from: now()->subHours(1), 307 | to: now() 308 | ); 309 | // OsmAnd 310 | $positionRepo->OsmAnd(uniqueId: "1234-d1", temperature: "21.5", abc: "def"); 311 | } 312 | ``` 313 | 314 | - #### *Event* 315 | 316 | Model : **[Event Model](src/Models/Event.php)** 317 | 318 | ```php 319 | public function index(TraccarService $traccarService) 320 | { 321 | // Get specific event details 322 | $event = $traccarService->eventRepository()->fetchEventInformation(eventID: 1); 323 | } 324 | ``` 325 | 326 | - #### *Driver* 327 | 328 | Model : **[Driver Model](src/Models/Driver.php)** 329 | 330 | ```php 331 | public function index(TraccarService $traccarService) 332 | { 333 | $driverRepo = $traccarService->driverRepository(); 334 | // Get list of drivers 335 | $list = $driverRepo->fetchListDrivers(); 336 | // Create new driver 337 | $driver = $driverRepo->createDriver( 338 | name: 'test-driver', 339 | uniqueId: '123456789-d1-driver' 340 | ); 341 | // Create new driver with Model : MrWolfGb\Traccar\Models\Driver 342 | $driver = $driverRepo->createNewDriver( new Driver([ 343 | 'name' => 'test-driver', 344 | 'uniqueId' => '123456789-d1-driver' 345 | ])); 346 | // Update driver 347 | $driver = $driverRepo->updateDriver(driver: $driver); 348 | // Delete driver : int|Driver $driver 349 | $driverRepo->deleteDriver(driver: $driver); 350 | } 351 | ``` 352 | 353 | - #### *Report* 354 | 355 | Model : **[Report Model](src/Models/Report.php)** 356 | 357 | ```php 358 | public function index(TraccarService $traccarService) 359 | { 360 | $reportRepo = $traccarService->reportRepository(); 361 | // Get route report for specific device 362 | $list = $reportRepo->reportRoute( 363 | from: now()->subHours(value: 3), 364 | to: now(), 365 | deviceId: 1 366 | ); 367 | // Get events report 368 | $list = $reportRepo->reportEvents( 369 | from: now()->subHours(value: 3), 370 | to: now(), 371 | deviceId: 1, 372 | type: 'engine' // optional, by default 'allEvents' 373 | ); 374 | // Get summary report 375 | $list = $reportRepo->reportSummary( 376 | from: now()->subHours(value: 3), 377 | to: now(), 378 | deviceId: [1,2], 379 | //groupId: [1,2], // optional 380 | //daily: true // optional 381 | ); 382 | // Get trips report 383 | $list = $reportRepo->reportTrips( 384 | from: now()->subHours(value: 3), 385 | to: now(), 386 | deviceId: 1 387 | ); 388 | // Get stops report 389 | $list = $reportRepo->reportStops( 390 | from: now()->subHours(value: 3), 391 | to: now(), 392 | deviceId: 1 393 | ); 394 | // Get combined report 395 | $list = $reportRepo->reportCombined( 396 | from: now()->subHours(value: 3), 397 | to: now(), 398 | deviceId: [1,2], 399 | //groupId: [1,2], // optional 400 | ); 401 | } 402 | ``` 403 | 404 | ### Commands 405 | 406 | This command store devices in the local database using the published migration. 407 | 408 | ```bash 409 | php artisan traccar:sync 410 | ``` 411 | 412 | Or 413 | 414 | ```bash 415 | php artisan traccar:sync-devices 416 | ``` 417 | 418 | ### Listen Traccar websocket with php 419 | 420 | if you want to listen Traccar websocket with php you can check example in 421 | file : [WsListenCommand](src/Commands/WsListenCommand.php) 422 | 423 | ## Traccar Custom Server 424 | 425 | - **[Repository link](https://github.com/mr-wolf-gb/traccar-custom)** 426 | 427 | This version is a fork of the original [TRACCAR](https://github.com/traccar/traccar) repository aimed at adding some 428 | useful features like : 429 | 430 | 1. **_`Websocket` can be accessed from external Hosts (App):_** 431 | 2. **_`api/session/check-sid?sid=[SESSION_ID]` to check if the session is still active or not_** 432 | 433 | ## Features for this version of Traccar 434 | 435 | #### Middleware 436 | 437 | `TraccarSession` is a middleware that adds the session ID of traccar user to the View. 438 | 439 | ```php 440 | // route web.php 441 | Route::get('/', [HomeController::class, 'index'])->middleware('TraccarSession'); 442 | ``` 443 | 444 | ```php 445 | // blade view 446 | const socket = new WebSocket("{{config('traccar.websocket_url')}}?session={{$traccarSessionId}}"); 447 | socket.onerror = (error) => { 448 | console.log('socket error: ', error) 449 | } 450 | socket.onmessage = function (event) { 451 | var data = JSON.parse(event.data); 452 | console.log('socket message : ', data) 453 | } 454 | ``` 455 | 456 | ### Testing 457 | 458 | ```bash 459 | composer test 460 | ``` 461 | 462 | ### Changelog 463 | 464 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed recently. 465 | 466 | ## Contributing 467 | 468 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 469 | 470 | ## Credits 471 | 472 | - [Mr.WOLF](https://github.com/mr-wolf-gb) 473 | - [All Contributors](../../contributors) 474 | 475 | ## License 476 | 477 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 478 | --------------------------------------------------------------------------------