mirror of
https://github.com/usetrmnl/byos_laravel.git
synced 2026-01-14 15:37:53 +00:00
Compare commits
No commits in common. "51af95da2c88c8916415d71af485b240cdec3a4f" and "4e3b47e4eb39763ef96db08fcb4b31b9c27bc701" have entirely different histories.
51af95da2c
...
4e3b47e4eb
5 changed files with 11 additions and 207 deletions
|
|
@ -353,27 +353,20 @@ class ImageGenerationService
|
||||||
public static function resetIfNotCacheable(?Plugin $plugin): void
|
public static function resetIfNotCacheable(?Plugin $plugin): void
|
||||||
{
|
{
|
||||||
if ($plugin?->id) {
|
if ($plugin?->id) {
|
||||||
// Check if any devices have custom dimensions or use non-standard DeviceModels
|
// Check if any devices have custom dimensions or use DeviceModels
|
||||||
$hasCustomDimensions = Device::query()
|
$hasCustomDimensions = Device::query()
|
||||||
->where(function ($query) {
|
->where(function ($query) {
|
||||||
$query->where('width', '!=', 800)
|
$query->where('width', '!=', 800)
|
||||||
->orWhere('height', '!=', 480)
|
->orWhere('height', '!=', 480)
|
||||||
->orWhere('rotate', '!=', 0);
|
->orWhere('rotate', '!=', 0);
|
||||||
})
|
})
|
||||||
->orWhereHas('deviceModel', function ($query) {
|
->orWhereNotNull('device_model_id')
|
||||||
// Only allow caching if all device models have standard dimensions (800x480, rotation=0)
|
|
||||||
$query->where(function ($subQuery) {
|
|
||||||
$subQuery->where('width', '!=', 800)
|
|
||||||
->orWhere('height', '!=', 480)
|
|
||||||
->orWhere('rotation', '!=', 0);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
if ($hasCustomDimensions) {
|
if ($hasCustomDimensions) {
|
||||||
// TODO cache image per device
|
// TODO cache image per device
|
||||||
$plugin->update(['current_image' => null]);
|
$plugin->update(['current_image' => null]);
|
||||||
Log::debug('Skip cache as devices with custom dimensions or non-standard DeviceModels exist');
|
Log::debug('Skip cache as devices with custom dimensions or DeviceModels exist');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,25 +126,10 @@ 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 {
|
||||||
// Determine image format based on device settings
|
|
||||||
$preferred_format = 'png'; // Default to PNG for newer firmware
|
|
||||||
|
|
||||||
if (! $device->device_model_id) {
|
|
||||||
// No device model, use device's image_format setting
|
|
||||||
if (str_contains($device->image_format, 'bmp')) {
|
|
||||||
$preferred_format = 'bmp';
|
|
||||||
}
|
|
||||||
// For 'auto' or unknown formats, fall back to firmware version logic
|
|
||||||
if (isset($device->last_firmware_version)
|
if (isset($device->last_firmware_version)
|
||||||
&& version_compare($device->last_firmware_version, '1.5.2', '<')
|
&& version_compare($device->last_firmware_version, '1.5.2', '<')
|
||||||
&& Storage::disk('public')->exists('images/generated/'.$image_uuid.'.bmp')) {
|
&& Storage::disk('public')->exists('images/generated/'.$image_uuid.'.bmp')) {
|
||||||
$preferred_format = 'bmp';
|
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if a preferred format exists, otherwise fall back
|
|
||||||
if (Storage::disk('public')->exists('images/generated/'.$image_uuid.'.'.$preferred_format)) {
|
|
||||||
$image_path = 'images/generated/'.$image_uuid.'.'.$preferred_format;
|
|
||||||
} elseif (Storage::disk('public')->exists('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 {
|
||||||
|
|
@ -437,25 +422,10 @@ 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 {
|
||||||
// Determine image format based on device settings
|
|
||||||
$preferred_format = 'png'; // Default to PNG for newer firmware
|
|
||||||
|
|
||||||
if (! $device->device_model_id) {
|
|
||||||
// No device model, use device's image_format setting
|
|
||||||
if (str_contains($device->image_format, 'bmp')) {
|
|
||||||
$preferred_format = 'bmp';
|
|
||||||
}
|
|
||||||
// For 'auto' or unknown formats, fall back to firmware version logic
|
|
||||||
if (isset($device->last_firmware_version)
|
if (isset($device->last_firmware_version)
|
||||||
&& version_compare($device->last_firmware_version, '1.5.2', '<')
|
&& version_compare($device->last_firmware_version, '1.5.2', '<')
|
||||||
&& Storage::disk('public')->exists('images/generated/'.$image_uuid.'.bmp')) {
|
&& Storage::disk('public')->exists('images/generated/'.$image_uuid.'.bmp')) {
|
||||||
$preferred_format = 'bmp';
|
$image_path = 'images/generated/'.$image_uuid.'.bmp';
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if preferred format exists, otherwise fall back
|
|
||||||
if (Storage::disk('public')->exists('images/generated/'.$image_uuid.'.'.$preferred_format)) {
|
|
||||||
$image_path = 'images/generated/'.$image_uuid.'.'.$preferred_format;
|
|
||||||
} elseif (Storage::disk('public')->exists('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 {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Enums\ImageFormat;
|
|
||||||
use App\Models\Device;
|
use App\Models\Device;
|
||||||
use App\Models\Playlist;
|
|
||||||
use App\Models\PlaylistItem;
|
|
||||||
use App\Models\Plugin;
|
|
||||||
use App\Models\User;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
uses(Illuminate\Foundation\Testing\RefreshDatabase::class);
|
uses(Illuminate\Foundation\Testing\RefreshDatabase::class);
|
||||||
|
|
@ -123,72 +118,3 @@ test('device falls back to bmp when png does not exist', function () {
|
||||||
'filename' => 'test-image.bmp',
|
'filename' => 'test-image.bmp',
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('device without device_model_id and image_format bmp3_1bit_srgb returns bmp when plugin is rendered', function () {
|
|
||||||
// Create a user with auto-assign enabled
|
|
||||||
$user = User::factory()->create([
|
|
||||||
'assign_new_devices' => true,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Create a device without device_model_id and with bmp3_1bit_srgb format
|
|
||||||
$device = Device::factory()->create([
|
|
||||||
'user_id' => $user->id,
|
|
||||||
'mac_address' => '00:11:22:33:44:55',
|
|
||||||
'api_key' => 'test-api-key',
|
|
||||||
'device_model_id' => null, // Explicitly set to null
|
|
||||||
'image_format' => ImageFormat::BMP3_1BIT_SRGB->value,
|
|
||||||
'last_firmware_version' => '1.5.2',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Create a plugin
|
|
||||||
$plugin = Plugin::factory()->create([
|
|
||||||
'user_id' => $user->id,
|
|
||||||
'name' => 'Test Plugin',
|
|
||||||
'render_markup' => '<div>Test Content</div>',
|
|
||||||
'data_strategy' => 'static',
|
|
||||||
'markup_language' => 'blade',
|
|
||||||
'current_image' => 'test-generated-image', // Set current image directly
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Create a playlist for the device
|
|
||||||
$playlist = Playlist::factory()->create([
|
|
||||||
'device_id' => $device->id,
|
|
||||||
'is_active' => true,
|
|
||||||
'refresh_time' => 900,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Create a playlist item with the plugin
|
|
||||||
$playlistItem = PlaylistItem::factory()->create([
|
|
||||||
'playlist_id' => $playlist->id,
|
|
||||||
'plugin_id' => $plugin->id,
|
|
||||||
'is_active' => true,
|
|
||||||
'order' => 1,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Mock the image generation to create both bmp and png files
|
|
||||||
$imageUuid = 'test-generated-image';
|
|
||||||
Storage::disk('public')->put('images/generated/'.$imageUuid.'.bmp', 'fake bmp content');
|
|
||||||
Storage::disk('public')->put('images/generated/'.$imageUuid.'.png', 'fake png content');
|
|
||||||
|
|
||||||
// Set the device's current screen image to the plugin's image
|
|
||||||
$device->update(['current_screen_image' => $imageUuid]);
|
|
||||||
|
|
||||||
// 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/current_screen');
|
|
||||||
|
|
||||||
$displayResponse->assertOk();
|
|
||||||
$displayResponse->assertJson([
|
|
||||||
'filename' => $imageUuid.'.bmp',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Verify that the device's image_format is correctly set
|
|
||||||
$device->refresh();
|
|
||||||
expect($device->image_format)->toBe(ImageFormat::BMP3_1BIT_SRGB->value)
|
|
||||||
->and($device->device_model_id)->toBeNull();
|
|
||||||
});
|
|
||||||
|
|
|
||||||
|
|
@ -423,35 +423,3 @@ it('determines correct image format from device model', function (): void {
|
||||||
expect($device3->current_screen_image)->toBe($uuid3);
|
expect($device3->current_screen_image)->toBe($uuid3);
|
||||||
Storage::disk('public')->assertExists("/images/generated/{$uuid3}.png");
|
Storage::disk('public')->assertExists("/images/generated/{$uuid3}.png");
|
||||||
})->skipOnGitHubActions();
|
})->skipOnGitHubActions();
|
||||||
|
|
||||||
it('generates BMP for legacy device with bmp3_1bit_srgb format', function (): void {
|
|
||||||
// Create a device with BMP format but no DeviceModel (legacy behavior)
|
|
||||||
$device = Device::factory()->create([
|
|
||||||
'width' => 800,
|
|
||||||
'height' => 480,
|
|
||||||
'rotate' => 0,
|
|
||||||
'image_format' => ImageFormat::BMP3_1BIT_SRGB->value,
|
|
||||||
'device_model_id' => null, // Explicitly no DeviceModel
|
|
||||||
]);
|
|
||||||
|
|
||||||
$markup = '<div style="background: white; color: black; padding: 20px;">Test Content</div>';
|
|
||||||
$uuid = ImageGenerationService::generateImage($markup, $device->id);
|
|
||||||
|
|
||||||
// Assert the device was updated with a new image UUID
|
|
||||||
$device->refresh();
|
|
||||||
expect($device->current_screen_image)->toBe($uuid);
|
|
||||||
|
|
||||||
// Assert BMP file was created
|
|
||||||
Storage::disk('public')->assertExists("/images/generated/{$uuid}.bmp");
|
|
||||||
|
|
||||||
// Verify the BMP file has content and isn't blank
|
|
||||||
$imagePath = Storage::disk('public')->path("/images/generated/{$uuid}.bmp");
|
|
||||||
$imageSize = filesize($imagePath);
|
|
||||||
expect($imageSize)->toBeGreaterThan(100); // Should be at least 100 bytes for a BMP
|
|
||||||
|
|
||||||
// Verify it's a valid BMP file
|
|
||||||
$imageInfo = getimagesize($imagePath);
|
|
||||||
expect($imageInfo[0])->toBe(800); // Width
|
|
||||||
expect($imageInfo[1])->toBe(480); // Height
|
|
||||||
expect($imageInfo[2])->toBe(IMAGETYPE_BMP); // BMP type
|
|
||||||
})->skipOnGitHubActions();
|
|
||||||
|
|
|
||||||
|
|
@ -226,59 +226,6 @@ it('reset_if_not_cacheable preserves cache for standard devices', function (): v
|
||||||
expect($plugin->current_image)->toBe('test-uuid');
|
expect($plugin->current_image)->toBe('test-uuid');
|
||||||
})->skipOnGitHubActions();
|
})->skipOnGitHubActions();
|
||||||
|
|
||||||
it('reset_if_not_cacheable preserves cache for og_png and og_plus device models', function (): void {
|
|
||||||
// Create a plugin
|
|
||||||
$plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid']);
|
|
||||||
|
|
||||||
// Create og_png device model
|
|
||||||
$ogPngModel = DeviceModel::factory()->create([
|
|
||||||
'name' => 'test_og_png',
|
|
||||||
'width' => 800,
|
|
||||||
'height' => 480,
|
|
||||||
'rotation' => 0,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Create og_plus device model
|
|
||||||
$ogPlusModel = DeviceModel::factory()->create([
|
|
||||||
'name' => 'test_og_plus',
|
|
||||||
'width' => 800,
|
|
||||||
'height' => 480,
|
|
||||||
'rotation' => 0,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Create devices with og_png and og_plus device models
|
|
||||||
Device::factory()->create(['device_model_id' => $ogPngModel->id]);
|
|
||||||
Device::factory()->create(['device_model_id' => $ogPlusModel->id]);
|
|
||||||
|
|
||||||
// Test that the method preserves cache for standard device models
|
|
||||||
ImageGenerationService::resetIfNotCacheable($plugin);
|
|
||||||
|
|
||||||
$plugin->refresh();
|
|
||||||
expect($plugin->current_image)->toBe('test-uuid');
|
|
||||||
})->skipOnGitHubActions();
|
|
||||||
|
|
||||||
it('reset_if_not_cacheable resets cache for non-standard device models', function (): void {
|
|
||||||
// Create a plugin
|
|
||||||
$plugin = App\Models\Plugin::factory()->create(['current_image' => 'test-uuid']);
|
|
||||||
|
|
||||||
// Create a non-standard device model (e.g., kindle)
|
|
||||||
$kindleModel = DeviceModel::factory()->create([
|
|
||||||
'name' => 'test_amazon_kindle_2024',
|
|
||||||
'width' => 1400,
|
|
||||||
'height' => 840,
|
|
||||||
'rotation' => 90,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Create a device with the non-standard device model
|
|
||||||
Device::factory()->create(['device_model_id' => $kindleModel->id]);
|
|
||||||
|
|
||||||
// Test that the method resets cache for non-standard device models
|
|
||||||
ImageGenerationService::resetIfNotCacheable($plugin);
|
|
||||||
|
|
||||||
$plugin->refresh();
|
|
||||||
expect($plugin->current_image)->toBeNull();
|
|
||||||
})->skipOnGitHubActions();
|
|
||||||
|
|
||||||
it('reset_if_not_cacheable handles null plugin', function (): void {
|
it('reset_if_not_cacheable handles null plugin', function (): void {
|
||||||
// Test that the method handles null plugin gracefully
|
// Test that the method handles null plugin gracefully
|
||||||
expect(fn () => ImageGenerationService::resetIfNotCacheable(null))->not->toThrow(Exception::class);
|
expect(fn () => ImageGenerationService::resetIfNotCacheable(null))->not->toThrow(Exception::class);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue