Ahsoka.Extensions.Bluetooth
5.5.0
See the version list below for details.
dotnet add package Ahsoka.Extensions.Bluetooth --version 5.5.0
NuGet\Install-Package Ahsoka.Extensions.Bluetooth -Version 5.5.0
<PackageReference Include="Ahsoka.Extensions.Bluetooth" Version="5.5.0" />
<PackageVersion Include="Ahsoka.Extensions.Bluetooth" Version="5.5.0" />
<PackageReference Include="Ahsoka.Extensions.Bluetooth" />
paket add Ahsoka.Extensions.Bluetooth --version 5.5.0
#r "nuget: Ahsoka.Extensions.Bluetooth, 5.5.0"
#:package Ahsoka.Extensions.Bluetooth@5.5.0
#addin nuget:?package=Ahsoka.Extensions.Bluetooth&version=5.5.0
#tool nuget:?package=Ahsoka.Extensions.Bluetooth&version=5.5.0
OpenPV – Ahsoka.Extensions.Bluetooth
This extension provides two distinct Bluetooth services:
- BLEService – Supports Bluetooth Low Energy (BLE) communication
- BluetoothService – Enables Bluetooth Classic functionality
Bluetooth Low Energy (BLE)
The BLE service is a comprehensive Bluetooth Low Energy (BLE) implementation designed for embedded Linux systems.
Bluetooth Low Energy Fundamentals
What is Bluetooth Low Energy?
Bluetooth Low Energy (BLE) is a wireless communication technology designed for low-power applications. It operates in the 2.4 GHz ISM band and uses a packet-based communication protocol optimized for minimal energy consumption.
Key BLE Concepts
1. Services
A BLE service is a collection of related functionality exposed by a device. Services are identified by UUIDs (Universally Unique Identifiers) and group together related characteristics.
2. Characteristics
Characteristics are the actual data points within a service. They can be:
- Read: Client can read the value
- Write: Client can write a value
- Notify: Server can push updates to subscribed clients
- Indicate: Similar to notify but requires acknowledgment
3. Descriptors
Descriptors provide additional information about characteristics, such as units of measurement or user descriptions.
4. Advertisements
Advertisements are periodic broadcasts that allow devices to announce their presence and services to potential clients.
5. GATT (Generic Attribute Profile)
GATT defines the structure of services, characteristics, and descriptors, providing a standardized way to organize and access BLE data.
Architecture Overview
The project follows a layered architecture approach:
┌─────────────────────────────────────────┐
│ Application Layer │
│ (BLEServiceViewModelBase) │
├─────────────────────────────────────────┤
│ Service Layer │
│ (BLEService) │
├─────────────────────────────────────────┤
│ Platform Abstraction │
│ (LinuxImplementation/Windows) │
├─────────────────────────────────────────┤
│ BlueZ Integration │
│ (GATT, Advertisements, DBus) │
└─────────────────────────────────────────┘
Core Components
1. BLEService - Main Service Class
The BLEService class serves as the central orchestrator for all BLE operations. Located in /Services/BLEService.cs, it inherits from AhsokaServiceBase and provides platform-agnostic BLE functionality.
[AhsokaService(Name)]
public class BLEService : AhsokaServiceBase<BLEMessageTypes.Ids>
{
public const string Name = "BLEService";
readonly ImplementationBase bluetoothImplementation;
public BLEService() : this(ConfigurationLoader.GetServiceConfig(Name)) { }
}
Key responsibilities:
- Stack Management: Start/stop BLE stack (
/Services/BLEService.cs) - Advertisement Control: Create and manage BLE advertisements (
/Services/BLEService.cs) - Service Management: Register and unregister GATT services (
/Services/BLEService.cs) - Characteristic Operations: Handle read/write/notify operations (
/Services/BLEService.cs) - Pairing Management: Handle device pairing requests (
/Services/BLEService.cs)
2. Platform Implementations
Linux Implementation
The LinuxImplementation class (/Services/Platform/LinuxImplementation.cs) provides the Linux-specific BLE functionality using BlueZ (the official Linux Bluetooth stack).
Key features:
- BlueZ Integration: Uses D-Bus to communicate with BlueZ daemon
- Adapter Management: Controls Bluetooth adapter power state
- Connection Handling: Manages D-Bus connections and state changes
- Application Manager: Registers GATT applications with BlueZ
protected override void OnStartStack(BLEStackRequest adapterInfo)
{
localName = adapterInfo.LocalName;
if (!SystemInfo.IsDesktop())
adapterInterfacePath = "/org/bluez/hci0";
// Set Bluetooth Local Name using bluetoothctl
ProcessUtility.RunProcess("bluetoothctl", $"system-alias {adapterInfo.LocalName}",
null, out string result, out string error);
connection = new Connection(Address.System);
connection.ConnectAsync();
}
3. GATT Implementation
GattService Class
The GattService class (/Services/Bluez/Gatt/Model/GattService.cs) represents a BLE service within the GATT hierarchy:
internal class GattService : PropertiesBase<GattService1Properties>, IGattService1
{
private readonly IList<GattCharacteristic> _Characteristics = new List<GattCharacteristic>();
public IEnumerable<GattCharacteristic> Characteristics => _Characteristics;
public string UUID => Properties.UUID;
public GattCharacteristic AddCharacteristic(GattCharacteristic1Properties characteristic,
BLECharacteristicProperties properties,
LinuxImplementation service)
{
characteristic.Service = ObjectPath;
var gattCharacteristic = new GattCharacteristic(NextCharacteristicPath(),
properties, characteristic, service);
_Characteristics.Add(gattCharacteristic);
return gattCharacteristic;
}
}
GattCharacteristic Class
The GattCharacteristic class (/Services/Bluez/Gatt/Model/GattCharacteristic.cs) implements individual BLE characteristics with full read/write/notify support:
internal class GattCharacteristic : PropertiesBase<GattCharacteristic1Properties>, IGattCharacteristic1
{
public Task<byte[]> ReadValueAsync(IDictionary<string, object> Options)
{
ushort offsetValue = 0;
if (Options.ContainsKey(ReadWriteUtility.ReadOffsetKeyString))
offsetValue = (ushort)Options[ReadWriteUtility.ReadOffsetKeyString];
if (useNotifyForRead)
{
// Send notification to get read value
serviceImplementation.Service.SendNotification(BLEMessageTypes.Ids.CharacteristicValueRead,
new BLECharacteristicValue()
{
Uuid = UUID,
Offset = offsetValue,
Handled = false
});
var result = readResults.Take();
return Task.FromResult(result);
}
else
{
var value = ReadWriteUtility.GetValueAtOffset(Value, offsetValue);
return Task.FromResult(value);
}
}
}
4. Advertisement Management
The AdvertisingManager class handles BLE advertisements, allowing devices to broadcast their presence and available services. Located in the BlueZ integration layer, it manages:
- Advertisement creation and configuration
- Service UUID broadcasting
- Manufacturer data inclusion
- Advertisement lifecycle management
5. ViewModel Framework
BLEServiceViewModelBase
The BLEServiceViewModelBase class (/Services/ViewModel/BLEServiceViewModelBase.cs) provides a high-level abstraction for creating BLE services using attributes:
public abstract class BLEServiceViewModelBase : ViewModelBase
{
public void EnableService(BLEServiceClient client, BLEAdvertisementProperties advertInfo)
{
this.client = client;
// Get Service Info and Register with Service
GetServiceInfo(out BLEServiceProperties props, advertInfo);
this.client.CreateService(props);
serviceEnabled = true;
// Listen to Model Updates
this.client.NotificationReceived += NotificationReceived;
}
}
Service Attributes
The framework provides several attributes for declarative BLE service definition:
BLEServiceAttribute: Defines service properties
[BLEService(UUID = "12345678-1234-1234-1234-123456789abc",
Name = "My Service",
IsPrimary = true,
Advertise = true)]
public class MyBLEService : BLEServiceViewModelBase
BLECharacteristicAttribute: Defines characteristic properties
[BLECharacteristic(UUID = "12345678-1234-1234-1234-123456789abd",
Name = "Temperature",
Flags = new[] { BLECharacteristicFlag.Read, BLECharacteristicFlag.Notify })]
public int Temperature { get; set; }
BLEManufactureDataAttribute: Defines manufacturer-specific advertisement data
[BLEManufactureData(Key = 0x1234, Data = new byte[] { 0x01, 0x02, 0x03 })]
Ahsoka Messages
Request/Response Messages
- StartStack/StopStack: Control BLE adapter power state
- IsStackRunning: Query adapter status
- CreateService/RemoveService: Manage GATT services
- CreateAdvertisement/RemoveAdvertisement: Control advertisements
- SetCharacteristicValue: Update characteristic values
- SendCharacteristicNotification: Trigger notifications
Notification Messages
- StackStarted/StackStopped: Adapter state changes
- CharacteristicValueRead/Write: Characteristic access events
- PairingRequested: Security pairing events
Data Flow
Service Registration Flow
- Application creates
BLEServiceViewModelBasesubclass with attributes EnableService()called with client and advertisement properties- Service attributes parsed to create
BLEServiceProperties - Service registered with BlueZ through
GattApplicationManager - Characteristics and descriptors created in GATT hierarchy
- Advertisement started to broadcast service availability
Read Operation Flow
- Remote client initiates read on characteristic
- BlueZ calls
ReadValueAsync()onGattCharacteristic - If
useNotifyForReadis true, notification sent to application - Application provides read result via
CharacteristicValueReadResult - Data returned to remote client through BlueZ
Write Operation Flow
- Remote client writes data to characteristic
- BlueZ calls
WriteValueAsync()onGattCharacteristic CharacteristicValueWritenotification sent to application- Application property updated automatically via attribute binding
OnHandleWriteRequest()called for custom processing
Notification Flow
- Application property changes (monitored via
OnSetValue()) - Characteristic value updated via
SetCharacteristicValue() - If characteristic has Notify flag,
SendCharacteristicNotification()called - BlueZ triggers property change notification to subscribed clients
Security and Pairing
The PairingAgent class handles secure pairing:
- Pairing Request Handling: Automatic pairing request notifications
- Confirmation Support: Application can confirm/deny pairing attempts
- Security Level Management: Configurable security requirements
Usage Examples
Basic Service Implementation
[BLEService(UUID = "180F", Name = "Battery Service", IsPrimary = true, Advertise = true)]
public class BatteryService : BLEServiceViewModelBase
{
private byte batteryLevel = 100;
[BLECharacteristic(UUID = "2A19", Name = "Battery Level",
Flags = new[] { BLECharacteristicFlag.Read, BLECharacteristicFlag.Notify })]
public byte BatteryLevel
{
get => batteryLevel;
set => SetValue(ref batteryLevel, value);
}
}
Service Registration
var client = new BLEServiceClient();
var batteryService = new BatteryService();
var advertProps = new BLEAdvertisementProperties
{
Type = BLEAdvertisementType.Peripheral,
ServiceUuids = new List<string>(),
ManufactureDatas = new Dictionary<int, byte[]>()
};
// Start BLE stack
client.StartStack(new BLEStackRequest { LocalName = "My Device" });
// Enable service
batteryService.EnableService(client, advertProps);
Dependencies
The project relies on several key dependencies:
- Tmds.DBus: D-Bus communication library for Linux BlueZ integration
- Protobuf-net: Message serialization for inter-process communication
- Ahsoka.Core: Base framework providing service infrastructure
- System.Reflection: Attribute-based service definition
File Structure Summary
Ahsoka.Extensions.Bluetooth.LE/
├── Services/
│ ├── BLEService.cs # Main service orchestrator
│ ├── BLEServiceClient.cs # Client interface
│ ├── BLEServiceMessages.cs # Message definitions
│ ├── Platform/
│ │ ├── ImplementationBase.cs # Platform abstraction
│ │ ├── LinuxImplementation.cs # BlueZ implementation
│ │ └── WindowsImplementation.cs # Windows implementation
│ ├── Bluez/ # BlueZ-specific implementations
│ │ ├── Advertisements/ # Advertisement management
│ │ ├── Core/ # D-Bus interfaces
│ │ ├── Gatt/ # GATT implementation
│ │ │ └── Model/ # GATT model classes
│ │ └── PairingAgent/ # Security/pairing
│ └── ViewModel/
│ ├── BLEServiceViewModelBase.cs # High-level service framework
│ └── Attributes/ # Attribute definitions
├── Installer/
│ └── BluetoothConfigurationPlugin.cs # Installation support
└── Resources/
└── dbus-org.bluez.service.sh # D-Bus service configuration
Bluetooth Classic
The Bluetooth Classic services provides comprehensive Bluetooth Classic Profile implementations. Along with discovery, pairing, and connection functionality, these profiles also provide Audio / Music, Phone calls, and data-based capabilities. For Linux platforms, an ESP32 chip module handles the low-level Bluetooth radio operations and, further up the stack, our BluetoothService communicates with the native Bluetooth system, Bluez, via DBus.
Architecture Overview
System Architecture
The Bluetooth Classic extension layers:
- Service Layer (
BluetoothService.cs) - Main service entry point that handles client requests - Module Layer (
BluetoothModuleBase.cs) - Abstract base for platform-specific initialization of Bluetooth Adapters - Platform Layer - Concrete implementations for different stacks (Bluez, Desktop)
- Profile Layer - Individual Bluetooth profile implementations
- Transport Layer - DBus communication with Bluez5
Project Structure
Ahsoka.Extensions.Bluetooth.Classic/
├── Services/Bluetooth/
│ ├── BluetoothService.cs # Main service implementation
│ ├── BluetoothModuleBase.cs # Abstract module base
│ ├── Platform/
│ │ ├── BluezBluetoothModule.cs # Bluez5 module implementation
│ │ └── DesktopBluetoothModule.cs # Windows desktop implementation
│ ├── Behavior/
│ │ ├── BluetoothConnection.cs # Connection management
│ │ ├── BluetoothDiscovery.cs # Device discovery logic
│ │ └── BluetoothPairing.cs # Device pairing logic
│ └── Profiles/ # Bluetooth profile implementations
├── Proto/ # Protocol buffer definitions
Core Service Implementation
BluetoothService
The BluetoothService class (BluetoothService.cs) serves as the main entry point for all Bluetooth operations. It manages multiple adapter configurations and handles various Bluetooth operations:
Key Features:
- Multi-adapter support through module abstraction
- Thread-safe operation with synchronization primitives
- Configuration-driven setup via Protocol Buffers
- Asynchronous operation support for discovery and pairing
Primary Operations:
- Adapter management (enable/disable, state management)
- Device discovery and pairing
- Profile service lifecycle management
- Configuration management
Module Architecture
The BluetoothModuleBase class (BluetoothModuleBase.cs) provides an abstract foundation for different Bluetooth stack implementations:
Factory Pattern Implementation:
public static BluetoothModuleBase GetModule(BluetoothAdapterSetup adapter)
{
return adapter.Stack switch
{
SupportedBluetoothStack.StackBluez => new BluezBluetoothModule(adapter),
SupportedBluetoothStack.StackDesktop => new DesktopBluetoothModule(adapter),
_ => throw new NotImplementedException()
};
}
Bluez5 Integration
BluetoothModule - GAPProfile - PairingAgent
The BluezBluetoothModule class implements the primary interface for enabling and disabling bluetooth hardware as well as profile creation.
The BluezGAPProfile class Implements concrete discovery, pairing orchestration, and connection to an external bluetooth device.
The BluezPairingAgent class implements the logic for secure pairing.
Key Integration Points:
DBus Connection Setup (
BluezBluetoothModule.cs):systemBus.ConnectAsync().GetAwaiter().GetResult(); // connect to DBus adapter = systemBus.CreateProxy<IAdapter1>("org.bluez", $"{adapterConfiguration.DeviceInterfacePath}");Profile Creation (
BluezBluetoothModule.cs):if (serviceType == BluetoothProfileServiceType.AudioSinkProfileService) return new BluezAudioSinkService();Discovery (
BluezGapProfile.cs):adapter.StartDiscoveryAsync();Pairing (
BluezGapProfile.cs):device = systemBus.CreateProxy<IDevice1>("org.bluez", $"/org/bluez/hci{deviceInfo.AdapterIndex}/dev_{deviceInfo.DeviceMacAddress.Replace(":", "_").ToUpper()}"); if (!device.GetPairedAsync().GetAwaiter().GetResult()) device.PairAsync().GetAwaiter().GetResult();
Bluetooth Classic Profile Implementations
Audio Sink Service (A2DP/AVRCP)
Implementation: BluezAudioSinkService.cs
The Audio Sink service implements the Advanced Audio Distribution Profile (A2DP) and Audio/Video Remote Control Profile (AVRCP) from the Bluetooth Classic specification.
Bluez5 Protocol Implementation:
- A2DP: Streams high-quality audio from source devices (smartphones, tablets)
- AVRCP: Provides remote control functionality for media playback
Key Features:
- Media player control through
IMediaPlayer1DBus interface (BluezAudioSinkService.cs) - Real-time track information extraction (
BluezAudioSinkService.cs) - Transport controls (play, pause, next, previous, fast-forward, rewind)
- Metadata support (title, artist, album, genre, track numbers, duration)
- Shuffle and repeat mode management with state tracking
AVRCP Command Mapping:
switch (command.Command)
{
case AvrcpMusic.Play: player.PlayAsync(); break;
case AvrcpMusic.Pause: player.PauseAsync(); break;
case AvrcpMusic.Next: player.NextAsync(); break;
case AvrcpMusic.Previous: player.PreviousAsync(); break;
}
Hands-Free Service (HFP)
Implementation: BluezHandsFreeService.cs
The Hands-Free service implements the Hands-Free Profile (HFP) for voice call functionality.
Bluez5 Protocol Implementation:
- Integrates with oFono telephony stack for call management
- Implements HFP Audio Gateway (AG) role
- Supports voice call operations through DBus interfaces
Key Features:
- oFono integration for telephony services (
BluezHandsFreeService.cs) - Voice call management (answer, hangup, dial)
- Modem discovery and management
- Call state notifications
oFono Integration:
ofonoManager = systemBus.CreateProxy<IManager>("org.ofono", "/");
modems = ofonoManager.GetModemsAsync().GetAwaiter().GetResult();
Data Service (SPP/iAP)
Implementation: BluezDataService.cs
The Data service implements Serial Port Profile (SPP) and iPod Accessory Protocol (iAP) for data communication.
Bluez5 Protocol Implementation:
- SPP: Provides serial-like data communication over Bluetooth
- iAP: Enables communication with Apple devices
Key Features:
- RFCOMM channel setup for SPP (
BluezDataService.cs) - Profile registration with Bluez5 profile manager
- Bidirectional data transmission
- Connection state management
SPP Profile Configuration:
bluezSppAcceptor = new(sppPath)
{
Options = new ProfileOptions()
{
Name = "OpenPV Serial Port",
Service = "00001101-0000-1000-8000-00805f9b34fb", // SPP UUID
Role = "server",
Channel = 1, // RFCOMM channel
RequireAuthentication = false,
RequireAuthorization = false
}
};
Phonebook Service (PBAP)
Implementation: BluezPhonebookService.cs
The Phonebook service implements the Phone Book Access Profile (PBAP) for contact synchronization.
Bluez5 Protocol Implementation:
- OBEX (Object Exchange) protocol over Bluetooth
- vCard format support for contact data
- Persistent storage with SQLite database
Key Features:
- Contact synchronization from paired devices
- Multiple phonebook support (contacts, call history)
- Progress reporting during sync operations
- Local storage with SQLite backend (
SQLiteDbHelper.cs)
Message Access Service (MAP)
Implementation: BluezMessageAccessService.cs
The Message Access service implements the Message Access Profile (MAP) for SMS/MMS access.
Bluez5 Protocol Implementation:
- OBEX Message Access protocol
- bMessage format parsing for message content
- Message folder navigation (inbox, outbox, sent, draft)
Key Features:
- SMS/MMS message access from paired devices
- Message composition and sending
- Message status management (read/unread)
- Message history loading and caching
bMessage Format Handling:
var tempFile = messageParser.CreateMessageFile(textMessage.Name, textMessage.Number, textMessage.Content, Encoding.UTF8);
profile.PushMessage(tempFile, "/telecom/msg/outbox", new Dictionary<string, object>() { { "Retry", false }, { "Transparent", false } });
Configuration System
Bluetooth Configuration
The system uses a JSON-based configuration system that gets compiled into Protocol Buffer format for runtime efficiency.
Configuration Structure (BluetoothConfig.json):
{
"adapterConfigurations": [
{
"stack": "StackBluez",
"deviceInterfacePath": "/org/bluez/hci0",
"adapterIndex": 0,
"localName": "OpenViewDisplay1",
"reportedClassOfDevice": {
"serviceClass": "Audio",
"majorDeviceClass": "DeviceClassAudioVideo",
"audioService": true,
"telephonyService": false
},
"supportedProfileServiceTypes": [
"AudioSinkProfileService"
]
}
]
}
Configuration Plugin (BluetoothConfigurationPlugin.cs:13):
- Processes JSON configuration during build
- Generates Protocol Buffer binary for runtime
- Platform-specific file deployment
Embedded Linux Integration
Platform Requirements
Embedded Linux platforms require the following components:
- Bluez5 Bluetooth Stack: Provides the core Bluetooth functionality
- DBus System Bus: Enables inter-process communication
- PulseAudio: Required for audio profile support
- oFono: Telephony stack for hands-free functionality
- OBEX: Object exchange / transfer
Startup Environment
Example for pulseaudio in case it's not enabled by default bluetooth_classic_startup_env.sh:
#!/bin/sh
# Environment setup for Audio functionality in Bluetooth Classic running on OpenPV Select
. /etc/profile.d/weston_profile.sh
. /etc/profile.d/pulse_profile.sh
systemctl start pulseaudio.service
Hardware Abstraction
The system abstracts hardware differences through:
- Adapter Configuration: Device-specific interface paths and capabilities
- Class of Device: Configurable device identification
- Profile Support: Selective profile enablement based on hardware capabilities
Development and Testing
Testing Framework
Test Structure (Ahsoka.Test.Bluetooth/):
- Unit tests for Bluetooth Classic functionality
- Integration tests with mock devices
- Configuration validation tests
UX Components
User Interface (Ahsoka.Extensions.Bluetooth.UX/):
- Avalonia-based UI components
- Adapter management interface
- Device pairing and connection UI
- Class of Device configuration
Key Design Patterns
Factory Pattern
BluetoothModuleBase.GetModule()creates platform-specific modules- Profile service creation through
CreateProfileService()
Observer Pattern
- Connection state notifications
- Discovery and pairing event handling
- Profile-specific event broadcasting
Strategy Pattern
- Platform-specific implementations (Bluez vs Desktop)
- Profile-specific behavior encapsulation
Service Locator
- Configuration-driven service instantiation
- Dynamic profile service loading
Error Handling and Logging
Logging Framework
- Ahsoka logging system integration
- Verbosity levels (High, Low, Developer)
- Exception stack trace logging for debugging
Error Recovery
- Connection state management
- Automatic reconnection logic
- Graceful service degradation
Performance Considerations
Threading Model
- Asynchronous operations for all I/O
- Thread-safe state management
- Background task management for continuous operations
Memory Management
- Protocol Buffer serialization for efficiency
- Connection pooling and resource cleanup
- Event handler cleanup on disconnection
Security Considerations
Bluetooth Security
- Configurable authentication requirements
- Authorization control per profile
- Secure pairing support
System Security Recommendations
- DBus security policy integration
- Service permission management
- Configuration file protection
Useful Links:
DBUS and Bluez:
C# library for DBus interfaces:
DBUS interfaces provided by Bluez:
DBUS interfaces provided by Ofono (HFP):
SQLite, how we store Phone Book info:
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Ahsoka.Core (>= 5.7.1-zzz-develop.1)
- Microsoft.Data.Sqlite (>= 9.0.10)
- MixERP.Net.VCards (>= 1.0.7)
- protobuf-net (>= 3.2.45)
- Tmds.DBus (>= 0.20.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Ahsoka.Extensions.Bluetooth:
| Package | Downloads |
|---|---|
|
Ahsoka.Extensions.Bluetooth.UX
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.5.1-zzz-develop.3 | 147 | 12/22/2025 |
| 5.5.1-zzz-develop.2 | 239 | 12/15/2025 |
| 5.5.1-zzz-develop.1 | 630 | 12/1/2025 |
| 5.5.0 | 288 | 11/10/2025 |
| 5.4.1-zzz-develop.1 | 220 | 11/10/2025 |
| 5.4.0 | 290 | 11/10/2025 |
| 5.3.1-zzz-develop.2 | 221 | 11/10/2025 |
| 5.3.1-zzz-develop.1 | 160 | 11/6/2025 |
| 5.3.0 | 173 | 10/31/2025 |
| 5.2.1-zzz-develop.1 | 78 | 10/31/2025 |
| 5.2.0 | 209 | 10/31/2025 |
| 5.1.1-zzz-develop.1 | 139 | 10/31/2025 |
| 5.1.0 | 216 | 10/30/2025 |
| 5.0.1-zzz-develop.31 | 154 | 10/30/2025 |
| 5.0.1-zzz-develop.30 | 157 | 10/29/2025 |
| 5.0.1-zzz-develop.29 | 155 | 10/28/2025 |
| 5.0.1-zzz-develop.28 | 76 | 10/24/2025 |
| 5.0.1-zzz-develop.27 | 136 | 10/21/2025 |
| 5.0.1-zzz-develop.26 | 137 | 10/16/2025 |
| 5.0.1-zzz-develop.25 | 143 | 10/15/2025 |
| 5.0.1-zzz-develop.24 | 135 | 10/15/2025 |