Getting Started
| GitHub | |
| Downloads |
Operating Systems
Android
iOS
Windows
Shiny.Obd is a .NET library for communicating with vehicles through OBD-II (On-Board Diagnostics) adapters. It uses a command-object pattern with generic return types, pluggable transports, and adapter auto-detection.
Features
Section titled “Features”| Feature | Description |
|---|---|
| Command-object pattern | OBD commands are objects, not methods. Pass built-in commands or create your own for custom PIDs. |
| Generic return types | each command declares its return type (int, double, string, TimeSpan, etc.) with compile-time safety. |
| Pluggable transports | IObdTransport abstracts the communication channel. BLE, classic Bluetooth (SPP), WiFi and serial (USB/UART) ship in the box; add anything else with one interface. |
| Classic Bluetooth adapters | the ELM327 v1.5 “Bluetooth” clones and OBDLink LX speak SPP, not BLE. Shiny.Obd.Bluetooth reaches them on Android, Windows, macOS and Linux, picking a paired adapter by address or name. |
| WiFi works everywhere | a WiFi adapter is a plain TCP socket, so Shiny.Obd.Wifi behaves identically on iOS, Android, Windows, Linux and macOS. No platform package, no pairing, no BLE stack. |
| Device discovery | IObdDeviceScanner finds available adapters before connecting, over any transport that supports it. BLE, classic Bluetooth, WiFi and serial scanners included. |
| Adapter auto-detection | detects ELM327 vs OBDLink (STN) adapters via ATI and runs the appropriate initialization sequence. |
| Task-based async | fully async/await throughout, no Reactive Extensions required in consuming code. |
| 30+ standard commands included | speed, RPM, temperatures, pressures, throttle and pedal position, fuel level, trims, rate and system status, timing advance, engine load, odometer, distances and timers, VIN, calibration IDs, hybrid battery life and more. |
| Supported-PID discovery | SupportedPidsCommand reads the mode 01 bitmask blocks so you only ever query readings the vehicle in front of you actually reports. |
| Oxygen sensors, narrowband and wideband | the measurement behind the fuel trim, with the bank/sensor layout decoded so a reading is never labelled from the wrong one. |
| EGR and EVAP | commanded position and error, purge command, and all three vapour-pressure encodings kept distinct. |
| Torque and power | EnginePower turns the percentage PIDs into newton-metres, kilowatts and horsepower. |
| Mode 06 on-board test results | the measurement each monitor took and the limits it was judged against, fully scaled, with BandPosition showing how close a passing test is to failing. |
| Diagnostic trouble codes | read stored, pending and permanent codes (modes 03/07/0A) as SAE J2012 strings, and clear them (mode 04). CAN and pre-CAN response framing are both handled. |
| Emissions monitor readiness | the full mode 01 PID 01/41 bit layout decoded for both spark and compression ignition, with IsReadyForInspection answering the question an emissions test actually asks. |
| Freeze frames | AsFreezeFrame() on any mode 01 command reads the same PID out of the snapshot the ECU stored when a code was set, so you get the conditions at the moment of the fault rather than the conditions now. |
| Test without a car | Shiny.Obd.Emulator is an adapter. It hosts an ELM327-compatible OBD-II bus over TCP (and BLE, with one more package), with every PID, trouble code and readiness flag settable, eight vehicles whose VINs decode for real, and a looping city, highway or commute scenario to drive them — headless in a test, or behind the sample app’s UI. |
Packages
Section titled “Packages”| Package | Target | Description |
|---|---|---|
Shiny.Obd |
net10.0 |
Core library — commands, connection, transport abstraction |
Shiny.Obd.Ble |
net10.0 |
BLE transport using Shiny.BluetoothLE |
Shiny.Obd.Bluetooth |
net10.0, net10.0-android |
Classic Bluetooth (RFCOMM/SPP) transport using Shiny.Bluetooth — Android, Windows, macOS, Linux (not iOS) |
Shiny.Obd.Wifi |
net10.0 |
WiFi (TCP) transport — every platform, including iOS and Android |
Shiny.Obd.Serial |
net10.0 |
Serial (USB/UART) transport — Windows, Linux, macOS, Mac Catalyst |
Shiny.Obd.Emulator |
net10.0 |
Adapter emulator — be a vehicle instead of reading one, over TCP |
Shiny.Obd.Emulator.Ble |
net10.0 |
BLE peripheral front-end for the emulator |
Changed files
- MyApp/
Platforms/Android/AndroidManifest.xml
AndroidManifest.xml
1<?xml version="1.0" encoding="utf-8"?>2<manifest xmlns:android="http://schemas.android.com/apk/res/android">3 <application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true">4 </application>5 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>6 <uses-permission android:name="android.permission.BATTERY_STATS" />7 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />8 <uses-permission android:name="android.permission.INTERNET" />9 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />10 <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />11 <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />12 <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />13</manifest>Quick Start
Section titled “Quick Start”using Shiny.Obd;using Shiny.Obd.Ble;using Shiny.Obd.Commands;
// Scan for an adaptervar scanner = new BleObdDeviceScanner(bleManager, new BleObdConfiguration{ DeviceNameFilter = "OBDLink"});var cts = new CancellationTokenSource();ObdDiscoveredDevice? selected = null;await scanner.Scan(device =>{ selected = device; cts.Cancel();}, cts.Token);
// Connect using the discovered devicevar transport = new BleObdTransport(selected!, new BleObdConfiguration());var connection = new ObdConnection(transport);await connection.Connect();
// Execute commandsvar speed = await connection.Execute(StandardCommands.VehicleSpeed); // int (km/h)var rpm = await connection.Execute(StandardCommands.EngineRpm); // intvar vin = await connection.Execute(StandardCommands.Vin); // stringAI Coding Assistant
Section titled “AI Coding Assistant”Step 1 — Add the marketplace:
claude plugin marketplace add shinyorg/skillsStep 2 — Install the plugin:
claude plugin install shiny@shinyOne plugin installs all 48 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.
Step 1 — Add the marketplace:
copilot plugin marketplace add https://github.com/shinyorg/skillsStep 2 — Install the plugin:
copilot plugin install shiny@shinyOne plugin installs all 48 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.
Architecture
Section titled “Architecture”┌─────────────────────────────────────────────────┐│ Your App ││ await connection.Execute(StandardCommands.*) │└──────────────────────┬──────────────────────────┘ │┌──────────────────────▼──────────────────────────┐│ ObdConnection ││ • Adapter detection (ATI probe) ││ • Profile-based initialization ││ • ELM327 response parsing (hex → bytes) ││ • Error handling (NO DATA, UNABLE TO CONNECT) │└──────────────────────┬──────────────────────────┘ │┌──────────────────────▼──────────────────────────┐│ IObdDeviceScanner ──▶ IObdTransport ││ Discover adapters Pluggable transport layer ││ ┌────────────────┐ ┌──────────┐ ┌──────────┐ ││ │ BleObdTransport│ │ WifiObd │ │SerialObd │ ││ │ (Shiny BLE) │ │ (TCP) │ │(USB/UART)│ ││ └────────────────┘ └──────────┘ └──────────┘ │└─────────────────────────────────────────────────┘

