diff --git a/app/Models/Device.php b/app/Models/Device.php index 2d6cc1c..5c72ae8 100644 --- a/app/Models/Device.php +++ b/app/Models/Device.php @@ -71,6 +71,14 @@ class Device extends Model return null; } + public function resetUpdateFirmwareFlag(): void + { + if ($this->proxy_cloud_response) { + $this->proxy_cloud_response = array_merge($this->proxy_cloud_response, ['update_firmware' => false]); + $this->save(); + } + } + public function playlists(): HasMany { return $this->hasMany(Playlist::class); diff --git a/config/services.php b/config/services.php index 7c579cb..9b1a9e7 100644 --- a/config/services.php +++ b/config/services.php @@ -42,5 +42,5 @@ return [ 'override_orig_icon' => env('TRMNL_OVERRIDE_ORIG_ICON', false), 'image_url_timeout' => env('TRMNL_IMAGE_URL_TIMEOUT', null), ], - + ]; diff --git a/routes/api.php b/routes/api.php index ebc4fb9..f8942d0 100644 --- a/routes/api.php +++ b/routes/api.php @@ -92,6 +92,11 @@ Route::get('/display', function (Request $request) { $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 ($device->update_firmware) { + $device->resetUpdateFirmwareFlag(); + } + return response()->json($response); }); diff --git a/tests/Feature/Api/DeviceEndpointsTest.php b/tests/Feature/Api/DeviceEndpointsTest.php index 0fa1bbf..b10c2f6 100644 --- a/tests/Feature/Api/DeviceEndpointsTest.php +++ b/tests/Feature/Api/DeviceEndpointsTest.php @@ -198,3 +198,48 @@ test('log endpoint requires valid device credentials', function () { $response->assertNotFound() ->assertJson(['message' => 'Device not found or invalid access token']); }); + +test('update_firmware flag is only returned once', function () { + $device = Device::factory()->create([ + 'mac_address' => '00:11:22:33:44:55', + 'api_key' => 'test-api-key', + 'proxy_cloud_response' => [ + 'update_firmware' => true, + 'firmware_url' => 'https://example.com/firmware.bin', + ], + ]); + + // First request should return update_firmware as true + $response = $this->withHeaders([ + 'id' => $device->mac_address, + 'access-token' => $device->api_key, + 'rssi' => -70, + 'battery_voltage' => 3.8, + 'fw-version' => '1.0.0', + ])->get('/api/display'); + + $response->assertOk() + ->assertJson([ + 'update_firmware' => true, + 'firmware_url' => 'https://example.com/firmware.bin', + ]); + + // Second request should return update_firmware as false + $response = $this->withHeaders([ + 'id' => $device->mac_address, + 'access-token' => $device->api_key, + 'rssi' => -70, + 'battery_voltage' => 3.8, + 'fw-version' => '1.0.0', + ])->get('/api/display'); + + $response->assertOk() + ->assertJson([ + 'update_firmware' => false, + 'firmware_url' => 'https://example.com/firmware.bin', + ]); + + // Verify the proxy_cloud_response was updated + $device->refresh(); + expect($device->proxy_cloud_response['update_firmware'])->toBeFalse(); +});