mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-13 23:18:10 +00:00
feat: prefer png format on firmware versions >=1.5.2
This commit is contained in:
parent
cc63c8cce2
commit
ad5ff5d2c9
12 changed files with 215 additions and 27 deletions
|
|
@ -29,10 +29,9 @@ class GenerateScreenJob implements ShouldQueue
|
||||||
*/
|
*/
|
||||||
public function handle(): void
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$newImageUuid = ImageGenerationService::generateImage($this->markup);
|
$newImageUuid = ImageGenerationService::generateImage($this->markup, $this->deviceId);
|
||||||
|
|
||||||
Device::find($this->deviceId)->update(['current_screen_image' => $newImageUuid]);
|
Device::find($this->deviceId)->update(['current_screen_image' => $newImageUuid]);
|
||||||
\Log::info("Device $this->deviceId: updated with new image: $newImageUuid");
|
|
||||||
|
|
||||||
if ($this->pluginId) {
|
if ($this->pluginId) {
|
||||||
// cache current image
|
// cache current image
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ class Device extends Model
|
||||||
'proxy_cloud' => 'boolean',
|
'proxy_cloud' => 'boolean',
|
||||||
'last_log_request' => 'json',
|
'last_log_request' => 'json',
|
||||||
'proxy_cloud_response' => 'json',
|
'proxy_cloud_response' => 'json',
|
||||||
|
'width' => 'integer',
|
||||||
|
'height' => 'integer',
|
||||||
|
'rotate' => 'integer',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function getBatteryPercentAttribute()
|
public function getBatteryPercentAttribute()
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ class User extends Authenticatable // implements MustVerifyEmail
|
||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
'assign_new_devices',
|
'assign_new_devices',
|
||||||
'assign_new_device_id'
|
'assign_new_device_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,16 @@ namespace App\Services;
|
||||||
use App\Models\Device;
|
use App\Models\Device;
|
||||||
use App\Models\Plugin;
|
use App\Models\Plugin;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use ImagickPixel;
|
||||||
use Ramsey\Uuid\Uuid;
|
use Ramsey\Uuid\Uuid;
|
||||||
use Spatie\Browsershot\Browsershot;
|
use Spatie\Browsershot\Browsershot;
|
||||||
use Wnx\SidecarBrowsershot\BrowsershotLambda;
|
use Wnx\SidecarBrowsershot\BrowsershotLambda;
|
||||||
|
|
||||||
class ImageGenerationService
|
class ImageGenerationService
|
||||||
{
|
{
|
||||||
public static function generateImage(string $markup): string {
|
public static function generateImage(string $markup, $deviceId): string
|
||||||
|
{
|
||||||
|
$device = Device::find($deviceId);
|
||||||
$uuid = Uuid::uuid4()->toString();
|
$uuid = Uuid::uuid4()->toString();
|
||||||
$pngPath = Storage::disk('public')->path('/images/generated/'.$uuid.'.png');
|
$pngPath = Storage::disk('public')->path('/images/generated/'.$uuid.'.png');
|
||||||
$bmpPath = Storage::disk('public')->path('/images/generated/'.$uuid.'.bmp');
|
$bmpPath = Storage::disk('public')->path('/images/generated/'.$uuid.'.bmp');
|
||||||
|
|
@ -20,7 +23,7 @@ class ImageGenerationService
|
||||||
if (config('app.puppeteer_mode') === 'sidecar-aws') {
|
if (config('app.puppeteer_mode') === 'sidecar-aws') {
|
||||||
try {
|
try {
|
||||||
BrowsershotLambda::html($markup)
|
BrowsershotLambda::html($markup)
|
||||||
->windowSize($device->width ?? 800, $device->height ?? 480)
|
->windowSize(800, 480)
|
||||||
->save($pngPath);
|
->save($pngPath);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
throw new \RuntimeException('Failed to generate PNG: '.$e->getMessage(), 0, $e);
|
throw new \RuntimeException('Failed to generate PNG: '.$e->getMessage(), 0, $e);
|
||||||
|
|
@ -29,18 +32,30 @@ class ImageGenerationService
|
||||||
try {
|
try {
|
||||||
Browsershot::html($markup)
|
Browsershot::html($markup)
|
||||||
->setOption('args', config('app.puppeteer_docker') ? ['--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu'] : [])
|
->setOption('args', config('app.puppeteer_docker') ? ['--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu'] : [])
|
||||||
->windowSize($device->width ?? 800, $device->height ?? 480)
|
->windowSize(800, 480)
|
||||||
->save($pngPath);
|
->save($pngPath);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
throw new \RuntimeException('Failed to generate PNG: '.$e->getMessage(), 0, $e);
|
throw new \RuntimeException('Failed to generate PNG: '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($device->last_firmware_version)
|
||||||
|
&& version_compare($device->last_firmware_version, '1.5.2', '<')) {
|
||||||
try {
|
try {
|
||||||
ImageGenerationService::convertToBmpImageMagick($pngPath, $bmpPath);
|
ImageGenerationService::convertToBmpImageMagick($pngPath, $bmpPath);
|
||||||
} catch (\ImagickException $e) {
|
} catch (\ImagickException $e) {
|
||||||
throw new \RuntimeException('Failed to convert image to BMP: '.$e->getMessage(), 0, $e);
|
throw new \RuntimeException('Failed to convert image to BMP: '.$e->getMessage(), 0, $e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
ImageGenerationService::convertToPngImageMagick($pngPath, $device->width, $device->height, $device->rotate);
|
||||||
|
} catch (\ImagickException $e) {
|
||||||
|
throw new \RuntimeException('Failed to convert image to PNG: '.$e->getMessage(), 0, $e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$device->update(['current_screen_image' => $uuid]);
|
||||||
|
\Log::info("Device $device->id: updated with new image: $uuid");
|
||||||
|
|
||||||
return $uuid;
|
return $uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,6 +74,28 @@ class ImageGenerationService
|
||||||
$imagick->clear();
|
$imagick->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \ImagickException
|
||||||
|
*/
|
||||||
|
private static function convertToPngImageMagick(string $pngPath, ?int $width, ?int $height, ?int $rotate): void
|
||||||
|
{
|
||||||
|
$imagick = new \Imagick($pngPath);
|
||||||
|
if ($width !== 800 || $height !== 480) {
|
||||||
|
$imagick->resizeImage($width, $height, \Imagick::FILTER_LANCZOS, 1, true);
|
||||||
|
}
|
||||||
|
if ($rotate !== null && $rotate !== 0) {
|
||||||
|
$imagick->rotateImage(new ImagickPixel('black'), $rotate);
|
||||||
|
}
|
||||||
|
$imagick->setImageType(\Imagick::IMGTYPE_GRAYSCALE);
|
||||||
|
$imagick->quantizeImage(2, \Imagick::COLORSPACE_GRAY, 0, true, false);
|
||||||
|
$imagick->setImageDepth(8);
|
||||||
|
$imagick->stripImage();
|
||||||
|
|
||||||
|
$imagick->setFormat('png');
|
||||||
|
$imagick->writeImage($pngPath);
|
||||||
|
$imagick->clear();
|
||||||
|
}
|
||||||
|
|
||||||
public static function cleanupFolder(): void
|
public static function cleanupFolder(): void
|
||||||
{
|
{
|
||||||
$activeDeviceImageUuids = Device::pluck('current_screen_image')->filter()->toArray();
|
$activeDeviceImageUuids = Device::pluck('current_screen_image')->filter()->toArray();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('devices', function (Blueprint $table) {
|
||||||
|
$table->integer('rotate')->nullable()->default(0)->after('width');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('devices', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('rotate');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -59,7 +59,7 @@ new class extends Component {
|
||||||
</flux:callout>
|
</flux:callout>
|
||||||
@elseif($current_image_path)
|
@elseif($current_image_path)
|
||||||
<flux:separator class="mt-2 mb-4"/>
|
<flux:separator class="mt-2 mb-4"/>
|
||||||
<img src="{{ asset($current_image_path) }}" alt="Current Image"/>
|
<img src="{{ asset($current_image_path) }}" class="max-h-[480px]" alt="Current Image"/>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ new class extends Component {
|
||||||
public $default_refresh_interval;
|
public $default_refresh_interval;
|
||||||
public $width;
|
public $width;
|
||||||
public $height;
|
public $height;
|
||||||
|
public $rotate;
|
||||||
|
|
||||||
// Playlist properties
|
// Playlist properties
|
||||||
public $playlists;
|
public $playlists;
|
||||||
|
|
@ -39,6 +40,7 @@ new class extends Component {
|
||||||
$this->default_refresh_interval = $device->default_refresh_interval;
|
$this->default_refresh_interval = $device->default_refresh_interval;
|
||||||
$this->width = $device->width;
|
$this->width = $device->width;
|
||||||
$this->height = $device->height;
|
$this->height = $device->height;
|
||||||
|
$this->rotate = $device->rotate;
|
||||||
$this->playlists = $device->playlists()->with('items.plugin')->orderBy('created_at')->get();
|
$this->playlists = $device->playlists()->with('items.plugin')->orderBy('created_at')->get();
|
||||||
|
|
||||||
return view('livewire.devices.configure', [
|
return view('livewire.devices.configure', [
|
||||||
|
|
@ -65,6 +67,7 @@ new class extends Component {
|
||||||
'default_refresh_interval' => 'required|integer|min:1',
|
'default_refresh_interval' => 'required|integer|min:1',
|
||||||
'width' => 'required|integer|min:1',
|
'width' => 'required|integer|min:1',
|
||||||
'height' => 'required|integer|min:1',
|
'height' => 'required|integer|min:1',
|
||||||
|
'rotate' => 'required|integer|min:0|max:359',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->device->update([
|
$this->device->update([
|
||||||
|
|
@ -74,6 +77,7 @@ new class extends Component {
|
||||||
'default_refresh_interval' => $this->default_refresh_interval,
|
'default_refresh_interval' => $this->default_refresh_interval,
|
||||||
'width' => $this->width,
|
'width' => $this->width,
|
||||||
'height' => $this->height,
|
'height' => $this->height,
|
||||||
|
'rotate' => $this->rotate,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Flux::modal('edit-device')->close();
|
Flux::modal('edit-device')->close();
|
||||||
|
|
@ -215,7 +219,7 @@ new class extends Component {
|
||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-6">
|
||||||
<div
|
<div
|
||||||
class="rounded-xl border bg-white dark:bg-stone-950 dark:border-stone-800 text-stone-800 shadow-xs">
|
class="rounded-xl border bg-white dark:bg-stone-950 dark:border-stone-800 text-stone-800 shadow-xs">
|
||||||
<div class="px-10 py-8 min-w-lg">
|
<div class="px-10 py-8">
|
||||||
@php
|
@php
|
||||||
$current_image_uuid =$device->current_screen_image;
|
$current_image_uuid =$device->current_screen_image;
|
||||||
if($current_image_uuid) {
|
if($current_image_uuid) {
|
||||||
|
|
@ -226,7 +230,7 @@ new class extends Component {
|
||||||
}
|
}
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between gap-4">
|
||||||
<flux:tooltip content="Friendly ID: {{$device->friendly_id}}" position="bottom">
|
<flux:tooltip content="Friendly ID: {{$device->friendly_id}}" position="bottom">
|
||||||
<h1 class="text-xl font-medium dark:text-zinc-200">{{ $device->name }}</h1>
|
<h1 class="text-xl font-medium dark:text-zinc-200">{{ $device->name }}</h1>
|
||||||
</flux:tooltip>
|
</flux:tooltip>
|
||||||
|
|
@ -282,6 +286,7 @@ new class extends Component {
|
||||||
<div class="flex gap-4">
|
<div class="flex gap-4">
|
||||||
<flux:input label="Width (px)" wire:model="width" type="number" />
|
<flux:input label="Width (px)" wire:model="width" type="number" />
|
||||||
<flux:input label="Height (px)" wire:model="height" type="number"/>
|
<flux:input label="Height (px)" wire:model="height" type="number"/>
|
||||||
|
<flux:input label="Rotate °" wire:model="rotate" type="number"/>
|
||||||
</div>
|
</div>
|
||||||
<flux:input label="Default Refresh Interval (seconds)" wire:model="default_refresh_interval"
|
<flux:input label="Default Refresh Interval (seconds)" wire:model="default_refresh_interval"
|
||||||
type="number"/>
|
type="number"/>
|
||||||
|
|
@ -315,7 +320,7 @@ new class extends Component {
|
||||||
@if(!$device->mirror_device_id)
|
@if(!$device->mirror_device_id)
|
||||||
@if($current_image_path)
|
@if($current_image_path)
|
||||||
<flux:separator class="mt-6 mb-6" text="Next Screen"/>
|
<flux:separator class="mt-6 mb-6" text="Next Screen"/>
|
||||||
<img src="{{ asset($current_image_path) }}" alt="Next Image"/>
|
<img src="{{ asset($current_image_path) }}" class="max-h-[480px]" alt="Next Image"/>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<flux:separator class="mt-6 mb-6" text="Playlists"/>
|
<flux:separator class="mt-6 mb-6" text="Playlists"/>
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,11 @@ Route::get('/display', function (Request $request) {
|
||||||
$image_path = 'images/setup-logo.bmp';
|
$image_path = 'images/setup-logo.bmp';
|
||||||
$filename = 'setup-logo.bmp';
|
$filename = 'setup-logo.bmp';
|
||||||
} else {
|
} else {
|
||||||
if (file_exists(storage_path('app/public/images/generated/'.$image_uuid.'.bmp'))) {
|
if (isset($device->last_firmware_version)
|
||||||
|
&& version_compare($device->last_firmware_version, '1.5.2', '<')
|
||||||
|
&& Storage::disk('public')->exists('images/generated/'.$image_uuid.'.bmp')) {
|
||||||
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
||||||
} elseif (file_exists(storage_path('app/public/images/generated/'.$image_uuid.'.png'))) {
|
} elseif (Storage::disk('public')->exists('images/generated/'.$image_uuid.'.png')) {
|
||||||
$image_path = 'images/generated/'.$image_uuid.'.png';
|
$image_path = 'images/generated/'.$image_uuid.'.png';
|
||||||
} else {
|
} else {
|
||||||
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
||||||
|
|
@ -106,7 +108,6 @@ Route::get('/display', function (Request $request) {
|
||||||
if (config('services.trmnl.image_url_timeout')) {
|
if (config('services.trmnl.image_url_timeout')) {
|
||||||
$response['image_url_timeout'] = config('services.trmnl.image_url_timeout');
|
$response['image_url_timeout'] = config('services.trmnl.image_url_timeout');
|
||||||
}
|
}
|
||||||
|
|
||||||
// If update_firmware is true, reset it after returning it, to avoid upgrade loop
|
// If update_firmware is true, reset it after returning it, to avoid upgrade loop
|
||||||
if ($device->update_firmware) {
|
if ($device->update_firmware) {
|
||||||
$device->resetUpdateFirmwareFlag();
|
$device->resetUpdateFirmwareFlag();
|
||||||
|
|
@ -271,9 +272,11 @@ Route::get('/current_screen', function (Request $request) {
|
||||||
$image_path = 'images/setup-logo.bmp';
|
$image_path = 'images/setup-logo.bmp';
|
||||||
$filename = 'setup-logo.bmp';
|
$filename = 'setup-logo.bmp';
|
||||||
} else {
|
} else {
|
||||||
if (file_exists(storage_path('app/public/images/generated/'.$image_uuid.'.bmp'))) {
|
if (isset($device->last_firmware_version)
|
||||||
|
&& version_compare($device->last_firmware_version, '1.5.2', '<')
|
||||||
|
&& Storage::disk('public')->exists('images/generated/'.$image_uuid.'.bmp')) {
|
||||||
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
||||||
} elseif (file_exists(storage_path('app/public/images/generated/'.$image_uuid.'.png'))) {
|
} elseif (Storage::disk('public')->exists('images/generated/'.$image_uuid.'.png')) {
|
||||||
$image_path = 'images/generated/'.$image_uuid.'.png';
|
$image_path = 'images/generated/'.$image_uuid.'.png';
|
||||||
} else {
|
} else {
|
||||||
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
||||||
|
|
|
||||||
|
|
@ -448,9 +448,9 @@ test('authenticated user can fetch their devices', function () {
|
||||||
'friendly_id',
|
'friendly_id',
|
||||||
'mac_address',
|
'mac_address',
|
||||||
'battery_voltage',
|
'battery_voltage',
|
||||||
'rssi'
|
'rssi',
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
])
|
])
|
||||||
->assertJsonCount(2, 'data');
|
->assertJsonCount(2, 'data');
|
||||||
|
|
||||||
|
|
@ -463,9 +463,9 @@ test('authenticated user can fetch their devices', function () {
|
||||||
'friendly_id' => $devices[0]->friendly_id,
|
'friendly_id' => $devices[0]->friendly_id,
|
||||||
'mac_address' => $devices[0]->mac_address,
|
'mac_address' => $devices[0]->mac_address,
|
||||||
'battery_voltage' => 3.72,
|
'battery_voltage' => 3.72,
|
||||||
'rssi' => -63
|
'rssi' => -63,
|
||||||
]
|
],
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
120
tests/Feature/Api/DeviceImageFormatTest.php
Normal file
120
tests/Feature/Api/DeviceImageFormatTest.php
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Device;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
uses(\Illuminate\Foundation\Testing\RefreshDatabase::class);
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
Storage::fake('public');
|
||||||
|
Storage::disk('public')->makeDirectory('/images/generated');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('device with firmware version 1.5.1 gets bmp format', function () {
|
||||||
|
$device = Device::factory()->create([
|
||||||
|
'mac_address' => '00:11:22:33:44:55',
|
||||||
|
'api_key' => 'test-api-key',
|
||||||
|
'current_screen_image' => 'test-image',
|
||||||
|
'last_firmware_version' => '1.5.1',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create both bmp and png files
|
||||||
|
Storage::disk('public')->put('images/generated/test-image.bmp', 'fake bmp content');
|
||||||
|
Storage::disk('public')->put('images/generated/test-image.png', 'fake png content');
|
||||||
|
|
||||||
|
// Test /api/display endpoint
|
||||||
|
$displayResponse = $this->withHeaders([
|
||||||
|
'id' => $device->mac_address,
|
||||||
|
'access-token' => $device->api_key,
|
||||||
|
'rssi' => -70,
|
||||||
|
'battery_voltage' => 3.8,
|
||||||
|
'fw-version' => '1.5.1',
|
||||||
|
])->get('/api/display');
|
||||||
|
|
||||||
|
$displayResponse->assertOk()
|
||||||
|
->assertJson([
|
||||||
|
'filename' => 'test-image.bmp',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Test /api/current_screen endpoint
|
||||||
|
$currentScreenResponse = $this->withHeaders([
|
||||||
|
'access-token' => $device->api_key,
|
||||||
|
])->get('/api/current_screen');
|
||||||
|
|
||||||
|
$currentScreenResponse->assertOk()
|
||||||
|
->assertJson([
|
||||||
|
'filename' => 'test-image.bmp',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('device with firmware version 1.5.2 gets png format', function () {
|
||||||
|
$device = Device::factory()->create([
|
||||||
|
'mac_address' => '00:11:22:33:44:55',
|
||||||
|
'api_key' => 'test-api-key',
|
||||||
|
'current_screen_image' => 'test-image',
|
||||||
|
'last_firmware_version' => '1.5.2',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create both bmp and png files
|
||||||
|
Storage::disk('public')->put('images/generated/test-image.png', 'fake bmp content');
|
||||||
|
|
||||||
|
// Test /api/display endpoint
|
||||||
|
$displayResponse = $this->withHeaders([
|
||||||
|
'id' => $device->mac_address,
|
||||||
|
'access-token' => $device->api_key,
|
||||||
|
'rssi' => -70,
|
||||||
|
'battery_voltage' => 3.8,
|
||||||
|
'fw-version' => '1.5.2',
|
||||||
|
])->get('/api/display');
|
||||||
|
|
||||||
|
$displayResponse->assertOk()
|
||||||
|
->assertJson([
|
||||||
|
'filename' => 'test-image.png',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Test /api/current_screen endpoint
|
||||||
|
$currentScreenResponse = $this->withHeaders([
|
||||||
|
'access-token' => $device->api_key,
|
||||||
|
])->get('/api/current_screen');
|
||||||
|
|
||||||
|
$currentScreenResponse->assertOk()
|
||||||
|
->assertJson([
|
||||||
|
'filename' => 'test-image.png',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('device falls back to bmp when png does not exist', function () {
|
||||||
|
$device = Device::factory()->create([
|
||||||
|
'mac_address' => '00:11:22:33:44:55',
|
||||||
|
'api_key' => 'test-api-key',
|
||||||
|
'current_screen_image' => 'test-image',
|
||||||
|
'last_firmware_version' => '1.5.2',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create only bmp file
|
||||||
|
Storage::disk('public')->put('images/generated/test-image.bmp', 'fake bmp content');
|
||||||
|
|
||||||
|
// Test /api/display endpoint
|
||||||
|
$displayResponse = $this->withHeaders([
|
||||||
|
'id' => $device->mac_address,
|
||||||
|
'access-token' => $device->api_key,
|
||||||
|
'rssi' => -70,
|
||||||
|
'battery_voltage' => 3.8,
|
||||||
|
'fw-version' => '1.5.2',
|
||||||
|
])->get('/api/display');
|
||||||
|
|
||||||
|
$displayResponse->assertOk()
|
||||||
|
->assertJson([
|
||||||
|
'filename' => 'test-image.bmp',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Test /api/current_screen endpoint
|
||||||
|
$currentScreenResponse = $this->withHeaders([
|
||||||
|
'access-token' => $device->api_key,
|
||||||
|
])->get('/api/current_screen');
|
||||||
|
|
||||||
|
$currentScreenResponse->assertOk()
|
||||||
|
->assertJson([
|
||||||
|
'filename' => 'test-image.bmp',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
@ -23,7 +23,6 @@ test('it generates screen images and updates device', function () {
|
||||||
// Assert both PNG and BMP files were created
|
// Assert both PNG and BMP files were created
|
||||||
$uuid = $device->current_screen_image;
|
$uuid = $device->current_screen_image;
|
||||||
Storage::disk('public')->assertExists("/images/generated/{$uuid}.png");
|
Storage::disk('public')->assertExists("/images/generated/{$uuid}.png");
|
||||||
Storage::disk('public')->assertExists("/images/generated/{$uuid}.bmp");
|
|
||||||
})->skipOnGitHubActions();
|
})->skipOnGitHubActions();
|
||||||
|
|
||||||
test('it cleans up unused images', function () {
|
test('it cleans up unused images', function () {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue