A connected-equipment diagnostics and service platform built with .NET 10, Avalonia UI, ASP.NET Core, TCP/IP, Entity Framework Core, and SQLite.
Machine Service Lab demonstrates how a traditional desktop diagnostics application can evolve into a modern connected-device architecture while preserving a clean separation between the user interface, device communication, cloud services, and persistence.
The project models realistic industrial service workflows including machine discovery, diagnostics, configuration, firmware programming, telemetry collection, and cloud registration.
This project was inspired by the types of connected equipment service and diagnostics workflows publicly described by Tennant Company, including desktop based machine diagnostics, configuration, firmware/service workflows, telemetry, and the evolution toward network-connected equipment.
Machine Service Lab is an independent learning and architecture project. It is not affiliated with, endorsed by, or derived from Tennant Company's proprietary software, source code, internal architecture, or device protocols. All machine models, commands, telemetry values, fault codes, and communication protocols in this repository are simulated and created specifically for engineering practice.
flowchart LR
Technician[Service Technician]
Desktop[Avalonia Desktop App]
VM[MVVM / MainViewModel]
Transport[IDeviceTransport]
TCP[TcpDeviceTransport]
Simulator[Machine Simulator]
Cloud[CloudApiClient]
API[ASP.NET Core API]
DB[(SQLite / EF Core)]
Technician --> Desktop
Desktop --> VM
VM --> Transport
Transport --> TCP
TCP -->|TCP/IP :7001| Simulator
VM --> Cloud
Cloud -->|HTTP :5163| API
API --> DB
Simulator -->|Machine Info| TCP
Simulator -->|Diagnostics| TCP
Simulator -->|Configuration| TCP
Simulator -->|Firmware Progress| TCP
API -->|Machine Registration| DB
API -->|Diagnostics History| DB
API -->|Telemetry| DB
Desktop UI
↓
MainViewModel
↓
IDeviceTransport
↓
TcpDeviceTransport
↓
TCP/IP
↓
Machine Simulator
Desktop UI
↓
MainViewModel
↓
CloudApiClient
↓
ASP.NET Core API
↓
Entity Framework Core
↓
SQLite
The ViewModel depends on the IDeviceTransport abstraction rather than a specific communication mechanism. This allows device communication to evolve independently from the desktop UI—for example from local USB/HID-style communication to TCP/IP-connected equipment.
- Connect to an industrial machine over TCP/IP
- Read machine model
- Read serial number
- Read firmware version
- Disconnect and reset application state
- Prevent device operations while disconnected
- Battery percentage
- Battery voltage
- Controller temperature
- Machine operating hours
- Fault-code retrieval
- Diagnostics history uploaded to the backend
Example simulated faults:
F102 - Brush Motor Overcurrent
F208 - Battery Voltage Low
Service technicians can retrieve and modify machine configuration.
Current configuration includes:
- Eco Mode
- Brush Pressure Level
- Maximum Speed %
Configuration changes are sent to the connected machine and can be retrieved again from the device.
The desktop client supports a simulated firmware-programming workflow including:
Ready
↓
Programming
↓
Progress 10% ... 100%
↓
Completed
Firmware updates support:
- asynchronous execution
- progress reporting
- cancellation
- connection validation
- failure handling
- firmware-version refresh after completion
Diagnostics produce telemetry measurements that are uploaded independently to the backend.
Current telemetry includes:
- battery voltage
- controller temperature
- machine hours
Telemetry is persisted and can be queried by machine serial number.
When a technician connects to a machine, the desktop client registers it with the backend.
Stored machine information includes:
- serial number
- model
- firmware version
- registration timestamp
MachineServiceLab
│
├── src
│ │
│ ├── MachineServiceLab.Desktop
│ │ │
│ │ ├── Models
│ │ ├── Services
│ │ │ ├── CloudApiClient
│ │ │ ├── IDeviceTransport
│ │ │ ├── SimulatedDeviceTransport
│ │ │ └── TcpDeviceTransport
│ │ │
│ │ ├── ViewModels
│ │ └── Views
│ │
│ ├── MachineServiceLab.Api
│ │ │
│ │ ├── Data
│ │ └── Migrations
│ │
│ └── MachineServiceLab.DeviceSimulator
│
└── MachineServiceLab.slnx
| Area | Technology |
|---|---|
| Runtime | .NET 10 |
| Language | C# |
| Desktop | Avalonia UI |
| UI Pattern | MVVM |
| MVVM Toolkit | CommunityToolkit.Mvvm |
| Device Communication | TCP/IP |
| Backend | ASP.NET Core Minimal API |
| Data Access | Entity Framework Core |
| Database | SQLite |
| Serialization | JSON |
| Device Protocol | TCP line-based command protocol |
| Async Processing | Task / async-await / CancellationToken |
The simulated machine exposes a simple command protocol over TCP port 7001.
Examples:
INFO
DIAGNOSTICS
GET_CONFIG
SET_CONFIG|true|3|80
FIRMWARE
DISCONNECT
Example machine-information response:
INFO|Scrubber-X1|MSL-100001|1.0.0
Example diagnostics response:
DIAGNOSTICS|81|37.8|42.5|1432.7|F102 - Brush Motor Overcurrent;F208 - Battery Voltage Low
Firmware programming streams progress messages:
PROGRESS|10
PROGRESS|20
PROGRESS|30
...
PROGRESS|100
FIRMWARE_COMPLETE|1.1.0
Three processes are used during local development.
dotnet run --project src/MachineServiceLab.DeviceSimulatorThe simulator listens on:
localhost:7001
Open another terminal:
dotnet run --project src/MachineServiceLab.ApiThe local API currently runs on:
localhost:5163
Open a third terminal:
dotnet run --project src/MachineServiceLab.DesktopThen:
- Connect to the machine.
- Run diagnostics.
- Load or update configuration.
- Run a firmware update.
- Inspect diagnostics and telemetry persisted by the API.
The desktop application does not communicate directly with TCP from the ViewModel.
Instead:
MainViewModel
↓
IDeviceTransport
↓
TcpDeviceTransport
This keeps device protocol concerns outside the UI layer and provides a path for additional transports such as USB/HID, CAN, Bluetooth, or other network protocols.
Device communication uses asynchronous APIs so long-running operations do not block the desktop UI.
Firmware programming additionally uses:
CancellationTokenIProgress<T>- asynchronous stream reads
Connecting to equipment and communicating with cloud services are independent responsibilities.
Device communication → IDeviceTransport
Cloud communication → CloudApiClient
A local equipment connection therefore does not dictate how machine data is stored or distributed to other applications.
The architecture represents an incremental modernization path:
Desktop + directly connected device
↓
transport abstraction
↓
network-connected equipment
↓
cloud APIs and persistent telemetry
↓
future browser/device-agnostic clients
The existing desktop workflow can continue operating while backend capabilities and network-connected device support evolve independently.
This project intentionally focuses on engineering problems common in connected industrial applications:
- desktop application architecture
- MVVM
- dependency boundaries
- device communication abstractions
- TCP/IP networking
- asynchronous I/O
- cancellation
- progress reporting
- connection lifecycle management
- firmware-update workflows
- device configuration
- diagnostics
- telemetry
- REST APIs
- relational persistence
- database migrations
- cloud/device separation
- incremental application modernization
Planned enhancements:
- device disconnect and reconnect recovery
- TCP timeouts and retry policies
- protocol validation
- structured logging
- firmware integrity validation
- authentication and role-based access
- audit history
- cloud-hosted API
- browser-based service experience
- automated tests
- CI/CD pipeline
- monitoring and health diagnostics
Machine Service Lab is a learning and architecture project focused on connected industrial equipment software.
It does not implement or reproduce any proprietary equipment protocol. The machine, protocol, telemetry, configuration values, fault codes, and firmware workflows in this repository are simulated specifically for engineering practice.

