mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2024-11-16 15:16:34 +01:00
163 lines
6.9 KiB
C#
163 lines
6.9 KiB
C#
|
using System.Collections.Generic;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using Plugin.BLE;
|
|||
|
using Plugin.BLE.Abstractions.Contracts;
|
|||
|
using Plugin.BLE.Abstractions;
|
|||
|
using System.Linq;
|
|||
|
using TINK.Services.BluetoothLock.Tdo;
|
|||
|
using TINK.Model.Connector;
|
|||
|
using Serilog;
|
|||
|
using System.Threading;
|
|||
|
using System;
|
|||
|
using TINK.Services.BluetoothLock.Exception;
|
|||
|
using Xamarin.Essentials;
|
|||
|
using TINK.Model.Device;
|
|||
|
using LockItShared.Services.BluetoothLock;
|
|||
|
|
|||
|
namespace TINK.Services.BluetoothLock.BLE
|
|||
|
{
|
|||
|
public class LockItByGuidService : LockItServiceBase, ILocksService
|
|||
|
{
|
|||
|
/// <summary> Constructs a LockItByGuidService object.</summary>
|
|||
|
/// <param name="cipher">Encrpyting/ decrypting object.</param>
|
|||
|
public LockItByGuidService(ICipher cipher) : base(cipher)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
/// <summary> Checks for locks which have not yet been discoverted and connects them. </summary>
|
|||
|
/// <remarks> Consists of a bluetooth connect plus invocation of an authentication sequence. </remarks>
|
|||
|
/// <param name="locksInfo">Locks to reconnect.</param>
|
|||
|
/// <param name="connectTimeout">Timeout for connect operation of a single lock.</param>
|
|||
|
protected override async Task<IEnumerable<ILockService>> CheckConnectMissing(IEnumerable<LockInfoAuthTdo> locksInfo, TimeSpan connectTimeout)
|
|||
|
{
|
|||
|
if (DeviceInfo.Platform != DevicePlatform.Unknown && MainThread.IsMainThread == false)
|
|||
|
{
|
|||
|
throw new System.Exception("Can not connect to locks by guid. Bluetooth code must be run on main thread");
|
|||
|
}
|
|||
|
|
|||
|
// Get list of target locks without invalid entries.
|
|||
|
var validLocksInfo = locksInfo
|
|||
|
.Where(x => x.IsGuidValid)
|
|||
|
.Where(x => x.K_seed.Length > 0 && x.K_u.Length > 0)
|
|||
|
.ToList();
|
|||
|
|
|||
|
var locksList = new List<ILockService>();
|
|||
|
|
|||
|
// Connect to
|
|||
|
foreach (var lockInfo in validLocksInfo)
|
|||
|
{
|
|||
|
if (DeviceList.Any(x => x.Name.GetBluetoothLockId() == lockInfo.Id || x.Guid == lockInfo.Guid))
|
|||
|
{
|
|||
|
// Device is already connected.
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
// Connect to device and authenticate.
|
|||
|
ILockService lockIt = null;
|
|||
|
try
|
|||
|
{
|
|||
|
lockIt = await ConnectByGuid(lockInfo, connectTimeout);
|
|||
|
}
|
|||
|
catch (System.Exception exception)
|
|||
|
{
|
|||
|
// Member is called for background update of missing devices.
|
|||
|
// Do not display any error messages.
|
|||
|
Log.ForContext<LockItByGuidService>().Error($"Authentication failed. {exception.Message}");
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (lockIt == null)
|
|||
|
{
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
locksList.Add(lockIt);
|
|||
|
}
|
|||
|
|
|||
|
return locksList;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary> Connects to lock.</summary>
|
|||
|
/// <remarks> Consists of a bluetooth connect plus invocation of an authentication sequence. </remarks>
|
|||
|
/// <param name="authInfo"> Info required to connect to lock.</param>
|
|||
|
/// <param name="connectTimeout">Timeout for connect operation.</param>
|
|||
|
public async Task<LockInfoTdo> ConnectAsync(LockInfoAuthTdo authInfo, TimeSpan connectTimeout)
|
|||
|
{
|
|||
|
if (DeviceInfo.Platform != DevicePlatform.Unknown && MainThread.IsMainThread == false)
|
|||
|
{
|
|||
|
throw new System.Exception("Can not connect to lock by guid. Bluetooth code must be run on main thread");
|
|||
|
}
|
|||
|
|
|||
|
// Connect to device and authenticate.
|
|||
|
var lockIt = await ConnectByGuid(authInfo, connectTimeout);
|
|||
|
|
|||
|
if (lockIt == null)
|
|||
|
{
|
|||
|
return new LockInfoTdo.Builder { Id = authInfo.Id, Guid = authInfo.Guid, State = null }.Build();
|
|||
|
}
|
|||
|
|
|||
|
DeviceList.Add(lockIt);
|
|||
|
|
|||
|
return await lockIt.GetLockStateAsync();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary> Connects to lock.</summary>
|
|||
|
/// <remarks> Consists of a bluetooth connect plus invocation of an authentication sequence. </remarks>
|
|||
|
/// <param name="authInfo"> Info required to connect to lock.</param>
|
|||
|
/// <param name="connectTimeout">Timeout for connect operation.</param>
|
|||
|
private async Task<ILockService> ConnectByGuid(LockInfoAuthTdo authInfo, TimeSpan connectTimeout)
|
|||
|
{
|
|||
|
if (authInfo.Guid == TextToLockItTypeHelper.INVALIDLOCKGUID)
|
|||
|
{
|
|||
|
Log.ForContext<LockItByGuidService>().Error($"Can not connect to lock {authInfo.Id}. Guid is unknown.");
|
|||
|
throw new GuidUnknownException();
|
|||
|
}
|
|||
|
|
|||
|
var lockIt = DeviceList.FirstOrDefault(x => x.Name.GetBluetoothLockId() == authInfo.Id || x.Guid == authInfo.Guid);
|
|||
|
if (lockIt != null && lockIt.GetDeviceState() == DeviceState.Connected)
|
|||
|
{
|
|||
|
// Device is already connected.
|
|||
|
return lockIt;
|
|||
|
}
|
|||
|
|
|||
|
var adapter = CrossBluetoothLE.Current.Adapter;
|
|||
|
Log.ForContext<LockItByGuidService>().Debug($"Request connect to device {authInfo.Id}.");
|
|||
|
|
|||
|
if (LockItByGuidServiceHelper.DevelGuids.ContainsKey(authInfo.Id) && LockItByGuidServiceHelper.DevelGuids[authInfo.Id] != authInfo.Guid)
|
|||
|
throw new System.Exception($"Invalid Guid {authInfo.Guid} for lock with id {authInfo.Id} detected. Guid should be {LockItByGuidServiceHelper.DevelGuids[authInfo.Id]}.");
|
|||
|
|
|||
|
IDevice device;
|
|||
|
var cts = new CancellationTokenSource(connectTimeout);
|
|||
|
// Step 1: Perform bluetooth connect.
|
|||
|
try
|
|||
|
{
|
|||
|
device = await adapter.ConnectToKnownDeviceAsync(
|
|||
|
authInfo.Guid,
|
|||
|
new ConnectParameters(forceBleTransport: true), // Force BLE transport
|
|||
|
cts.Token);
|
|||
|
}
|
|||
|
catch (System.Exception exception)
|
|||
|
{
|
|||
|
if (exception is TaskCanceledException)
|
|||
|
{
|
|||
|
// A timeout occurred.
|
|||
|
throw new System.Exception($"Can not connect to lock by guid.\r\nTimeout of {connectTimeout.TotalMilliseconds} [ms] elapsed.", exception);
|
|||
|
}
|
|||
|
|
|||
|
Log.ForContext<LockItByGuidService>().Error("Bluetooth connect to known device request failed. {Exception}", exception);
|
|||
|
throw new System.Exception($"Can not connect to lock by guid.\r\n{exception.Message}", exception);
|
|||
|
}
|
|||
|
|
|||
|
// Step 2: Authenticate.
|
|||
|
lockIt = await LockItEventBased.Authenticate(device, authInfo, CrossBluetoothLE.Current.Adapter, Cipher);
|
|||
|
|
|||
|
if (lockIt == null)
|
|||
|
{
|
|||
|
Log.ForContext<LockItByGuidService>().Error("Connect to device failed.");
|
|||
|
return null;
|
|||
|
}
|
|||
|
|
|||
|
return lockIt;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|