import OldMoofKit
let bike = try await Bike(username: "Johnny Mnemonic", password: "swordfish") // queries the vanmoof web api
try await bike.connect()
try await bike.playSound(.bell)
try await bike.set(lock: .unlocked)
bike.disconnect()
OldMoofKit 不是 VanMoof B.V. 的官方库。此 Swift 包尚未达到官方稳定版本,因此某些功能可能无法按预期工作。您需要自行承担使用此库的风险。
型号 | 支持 | 已测试 | 替代方案 |
---|---|---|---|
SmartBike | ✅ | ❌ | vanbike-lib |
SmartS/X | ✅ | ✅ | vanbike-lib |
Electrified S/X | ✅ | ❌ | vanbike-lib |
S/X 2 | ✅ | ✅ | vanbike-lib |
S/X 3 | ❌ | ❌ | VanMoofKit, PyMoof |
未测试 意味着理论上应该可以工作,但由于我无法接触到这样的自行车,这仍然是一个未知的领域。如果您拥有 SmartBike 或 Electrified S/X,我将不胜感激您能确认 OldMoofKit 是否工作,或者帮助我调试问题。
要使用 Apple 的 Swift Package Manager 进行集成,请将以下内容作为依赖项添加到您的 Package.swift
文件中
dependencies: [
.package(url: "https://github.com/Jegge/OldMoofKit.git", from: "0.0.3")
]
或者导航到您的 Xcode 项目,然后选择 Swift Packages
,点击“+”图标并搜索 OldMoofKit
。
由于 OldMoofKit 使用 CoreBluetooth
框架来建立与自行车的 BLE 连接,因此需要将 NSBluetoothAlwaysUsageDescription
键添加到您的应用程序的 Info.plist 文件中。
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Establishing a bluetooth connection to your VanMoof Bike.</string>
要首次获取自行车,请连接到 VanMoof Web API 并检索第一辆自行车。
let bike = try await Bike(username: "Johnny Mnemonic", password: "swordfish")
如果您拥有多辆自行车,则需要单独下载详细信息。然后,您可以通过蓝牙扫描周围环境,查找与这些详细信息匹配的自行车。
var api = VanMoof(apiUrl: VanMoof.Api.url, apiKey: VanMoof.Api.key)
try await api.authenticate(username: "Johnny Mnemonic", password: "swordfish")
let allDetails = try await api.bikeDetails()
let details = allDetails.first! // select one element from allDetails
let bike = try await Bike(scanningForBikeMatchingDetails: details)
如果您已经拥有自行车的详细信息,例如因为您之前已从 VanMoof 网站下载了它们,则可以手动构建自行车详细信息。然后,您可以通过蓝牙扫描周围环境,查找与这些详细信息匹配的自行车。
let details = try BikeDetails(bleProfile: .smartbike2016, macAddress: "12:34:56:78:9A:BC", encryptionKey: "00112233445566778899aabbccddeeff")
let bike = try await Bike(scanningForBikeMatchingDetails: details)
注意:请确保您的
bleProfile
、macAddress
和encryptionKey
正确,否则将无法建立连接。其他参数仅为描述性文本。
注意:MAC 地址必须以 MAC-48 格式输入。
注意:加密密钥必须正好是 16 个字节长,并且必须以十六进制字符串形式输入。
Bikes 实现了 Codable
,因此可以在需要时进行序列化/反序列化。
// store a bike as data
let data = try? JSONEncoder().encode(bike)
// read another bike back from data
let otherBike = JSONDecoder().decode(Bike.self, from: data)
连接自行车非常简单,只需调用 connect
方法即可。
try await bike.connect()
只要您不手动断开连接,自行车将保持连接状态(实际上会自动重新建立断开的连接)。
bike.disconnect()
要检索当前连接状态,请查询自行车的 state
let state = bike.state
switch state {
case .connected:
// do something when connection get (re-)established
case .disconnected:
// do something when connection drops or closes
}
您还可以订阅 statePublisher
,并在当前状态更改时收到通知。
let subscription: AnyCancellable = bike.statePublisher.receive(on: RunLoop.main).sink { state in
// react to state ...
}
subscription.cancel()
注意:请确保在正确的线程上接收状态更改。
注意:断开连接时,请不要忘记取消您的订阅。
自行车有一个专用的 errorPublisher
,您可以订阅它以获取错误消息。
let subscription: AnyCancellable = bike.errorPublisher.receive(on: RunLoop.main).sink { error in
// react to the error
print("Error: \(error))
}
subscription.cancel()
注意:请确保在正确的线程上接收状态更改。
注意:断开连接时,请不要忘记取消您的订阅。
自行车具有各种属性,代表自行车的当前已知状态,例如
lock
(已锁定、已解锁)alarm
(开启、关闭、自动)lighting
(始终开启、自动、关闭)batteryLevel
和 batteryState
(充电百分比以及充电或放电状态)moduleState
(休眠、关闭、开启)errorCode
(原始数据,取决于自行车型号)motorAssistance
(关闭、一级、二级、三级、四级)mutedSounds
(唤醒声音、关机声音、锁定声音、解锁声音)speed
(当前速度,单位为公里/小时)distance
(距离,单位为公里)region
(欧盟、美国、日本、越野)unit
(公制、英制)let lighting = bike.lighting
注意:如果您的自行车不支持某个属性,则其值将为
nil
。
对于每个属性,都有一个关联的 Publisher
,允许监视值的变化。
let subscription: AnyCancellable = bike.lightingPublisher.receive(on: RunLoop.main).sink { state in
// do something when lighting changed ...
}
subscription.cancel()
注意:请确保在正确的线程上接收状态更改。
注意:断开连接时,请不要忘记取消您的订阅。
每个属性都辅以一个 setter。调用此 setter 会将值直接传输到自行车。然后,自行车将发送通知,并且在收到该通知后,相应的属性将得到更新。如果您的自行车不支持某个属性,则调用 setter 将被忽略。
try await bike.set(lighting: .alwaysOn)
注意:将您的电动自行车的区域设置为与您所在国家/地区不符的值在某些司法管辖区可能是非法的。使用风险自负。
try await bike.playSound(.bell, 3) // play the bell sound thrice
try await bike.set(backupCode: 123) // sets 123 as new backup code
有时,自行车可能不会立即对配置更改做出反应,因为它的智能模块处于休眠状态。为了确保您的命令即使在自行车进入休眠状态后也能执行,您可以再次唤醒它。当 wakeup
返回时,命令已发送到自行车。此时它可能仍处于 .standby
状态。为了确保自行车已唤醒,请考虑监听 moduleStatePublisher
。
try await bike.wakeup()
MIT 许可证
版权所有 (c) 2023 Sebastian Boettcher
特此授予任何人免费复制和分发本软件和相关文档文件(以下简称“软件”)的许可,包括但不限于使用、复制、修改、合并、发布、发行、再许可和/或销售软件副本的权利,并允许向已获得软件的人员提供软件,但须遵守以下条件:
上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。
本软件按“现状”提供,不提供任何形式的明示或暗示保证,包括但不限于适销性、特定用途适用性和非侵权保证。在任何情况下,作者或版权持有者均不对任何索赔、损害或其他责任负责,无论是在合同诉讼、侵权诉讼或其他诉讼中,由软件或软件的使用或其他交易引起、产生或与之相关的责任。