diff --git a/LibreHardwareMonitor.Windows.WinUI/Services/HardwareMonitorService.cs b/LibreHardwareMonitor.Windows.WinUI/Services/HardwareMonitorService.cs
index ecc246a..95df3cb 100644
--- a/LibreHardwareMonitor.Windows.WinUI/Services/HardwareMonitorService.cs
+++ b/LibreHardwareMonitor.Windows.WinUI/Services/HardwareMonitorService.cs
@@ -12,7 +12,7 @@ using LibreHardwareMonitor.Windows.WinUI.ViewModels;
namespace LibreHardwareMonitor.Windows.WinUI.Services;
-public sealed class HardwareMonitorService : IDisposable
+public sealed class HardwareMonitorService : IHardwareMonitorService
{
private const string DeferDimmDetectionSetting = "memory.deferDimmDetection";
private const string DeferCpuInitialUpdateSetting = "cpu.deferInitialUpdate";
diff --git a/LibreHardwareMonitor.Windows.WinUI/Services/IHardwareMonitorService.cs b/LibreHardwareMonitor.Windows.WinUI/Services/IHardwareMonitorService.cs
new file mode 100644
index 0000000..7bb8441
--- /dev/null
+++ b/LibreHardwareMonitor.Windows.WinUI/Services/IHardwareMonitorService.cs
@@ -0,0 +1,58 @@
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+// Copyright (C) LibreHardwareMonitor and Contributors.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using LibreHardwareMonitor.Hardware;
+using LibreHardwareMonitor.Windows.WinUI.ViewModels;
+
+namespace LibreHardwareMonitor.Windows.WinUI.Services;
+
+///
+/// Owns the lifecycle and the sensor tree, exposing the surface the
+/// view model needs. Extracted as an interface so the view model can be unit-tested with a fake.
+///
+public interface IHardwareMonitorService : IDisposable
+{
+ event EventHandler? TreeRebuilt;
+
+ Computer Computer { get; }
+
+ object SensorReadLock { get; }
+
+ SensorTreeItemViewModel Root { get; }
+
+ bool IsMotherboardEnabled { get; set; }
+
+ bool IsCpuEnabled { get; set; }
+
+ bool IsMemoryEnabled { get; set; }
+
+ bool IsGpuEnabled { get; set; }
+
+ bool IsPowerMonitorEnabled { get; set; }
+
+ bool IsControllerEnabled { get; set; }
+
+ bool IsStorageEnabled { get; set; }
+
+ bool IsNetworkEnabled { get; set; }
+
+ bool IsPsuEnabled { get; set; }
+
+ bool IsBatteryEnabled { get; set; }
+
+ bool ForceDriveWakeup { get; set; }
+
+ Task OpenAsync(bool raiseTreeRebuilt = true, CancellationToken cancellationToken = default);
+
+ void Reset();
+
+ Task UpdateAsync();
+
+ void ResetMinMax();
+
+ void ClearSensorValues();
+}
diff --git a/LibreHardwareMonitor.Windows.WinUI/Services/ILogger.cs b/LibreHardwareMonitor.Windows.WinUI/Services/ILogger.cs
new file mode 100644
index 0000000..6018bc7
--- /dev/null
+++ b/LibreHardwareMonitor.Windows.WinUI/Services/ILogger.cs
@@ -0,0 +1,19 @@
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+// Copyright (C) LibreHardwareMonitor and Contributors.
+
+using System;
+
+namespace LibreHardwareMonitor.Windows.WinUI.Services;
+
+///
+/// CSV sensor logger. Extracted as an interface so the view model can be unit-tested with a fake.
+///
+public interface ILogger
+{
+ LoggerFileRotation FileRotationMethod { get; set; }
+
+ TimeSpan LoggingInterval { get; set; }
+
+ void Log();
+}
diff --git a/LibreHardwareMonitor.Windows.WinUI/Services/IRemoteWebServer.cs b/LibreHardwareMonitor.Windows.WinUI/Services/IRemoteWebServer.cs
new file mode 100644
index 0000000..8c72254
--- /dev/null
+++ b/LibreHardwareMonitor.Windows.WinUI/Services/IRemoteWebServer.cs
@@ -0,0 +1,34 @@
+// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+// Copyright (C) LibreHardwareMonitor and Contributors.
+
+using System;
+
+namespace LibreHardwareMonitor.Windows.WinUI.Services;
+
+///
+/// Optional HTTP server exposing sensor data. Extracted as an interface so the view model can be
+/// unit-tested with a fake (and so the real server's network resources stay out of tests).
+///
+public interface IRemoteWebServer : IDisposable
+{
+ bool AuthEnabled { get; set; }
+
+ string ListenerIp { get; set; }
+
+ int ListenerPort { get; set; }
+
+ string PasswordHash { get; }
+
+ bool PlatformNotSupported { get; }
+
+ string UserName { get; set; }
+
+ void SetPassword(string plainPassword);
+
+ bool Start();
+
+ bool Stop();
+
+ void Quit();
+}
diff --git a/LibreHardwareMonitor.Windows.WinUI/Services/Logger.cs b/LibreHardwareMonitor.Windows.WinUI/Services/Logger.cs
index 5d0f56d..06a915a 100644
--- a/LibreHardwareMonitor.Windows.WinUI/Services/Logger.cs
+++ b/LibreHardwareMonitor.Windows.WinUI/Services/Logger.cs
@@ -11,7 +11,7 @@ using LibreHardwareMonitor.Hardware;
namespace LibreHardwareMonitor.Windows.WinUI.Services;
-public sealed class Logger
+public sealed class Logger : ILogger
{
private const string FileNameFormat = "LibreHardwareMonitorLog-{0:yyyy-MM-dd}{1}.csv";
diff --git a/LibreHardwareMonitor.Windows.WinUI/Services/RemoteWebServer.cs b/LibreHardwareMonitor.Windows.WinUI/Services/RemoteWebServer.cs
index a92ac3f..49e8a86 100644
--- a/LibreHardwareMonitor.Windows.WinUI/Services/RemoteWebServer.cs
+++ b/LibreHardwareMonitor.Windows.WinUI/Services/RemoteWebServer.cs
@@ -22,7 +22,7 @@ using LibreHardwareMonitor.Windows.WinUI.ViewModels;
namespace LibreHardwareMonitor.Windows.WinUI.Services;
-public sealed class RemoteWebServer : IDisposable
+public sealed class RemoteWebServer : IRemoteWebServer
{
private readonly IComputer _computer;
private readonly object _sensorReadLock;