swift - 发送 UDP 数据包的问题(milight,limitlessled)

标签 swift macos sockets udp udpclient

我正在尝试编写一个菜单栏应用程序以通过 Mac 控制我的灯光。 我正在使用 milight (limitless, easybulbs...) 的系统. 他们有一个开放的系统,您可以通过 UDP 发送命令。

我可以通过 python-limitless 控制我的灯python 库,所以我知道 IP 和端口等网络信息是正确的。

所以我认为我对这些我从未使用过的 UDP 东西做错了什么。 我正在尝试使用 SwiftSocket库发送我的命令但没有任何反应,我已经尝试了 2 天。

这是我正在尝试的:

let host = "192.168.2.102"
let port = 5987

var client: UDPClient!

@IBAction func lightOn(_ sender: NSButton) {

    let bridgeon: [UInt8] = [0x31, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x01]
    let rgbwon: [UInt8] = [0x31, 0x00, 0x00, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0]

    print("Licht an")
    print(client.send(data: bridgeon))
    sleep(1)
    print(client.send(data: rgbwon))
    sleep(1)

}

@IBAction func lightOff(_ sender: NSButton) {
    print("Licht aus")
}

override func viewDidLoad() {
    super.viewDidLoad()

    client = UDPClient(address: host, port: Int32(port))
}

当我将它与 python 库的复杂性进行比较时,我确定我忘记了一些重要的事情。我还没有接触过网络,所以请宽容我。

谢谢和问候。

最佳答案

有点晚了,希望对你有帮助:

在发送您的 lighton 请求之前,您必须发送第一个请求以获取 wifi 桥接 session 。您还需要根据您的请求计算 Milight 所谓的“校验和”。

您还要确定您拥有的是哪种灯泡,是 WW 灯泡还是 CW?我被困了好几天,因为我发送了错误的请求..

我做了一个实现,它是用 php 编写的,但您可以在 Objective-C 中以相同的方式使用它。

查看:https://github.com/winosaure/MilightAPI

更新:

根据 limitlessled“文档”(http://www.limitlessled.com/dev/),这是请求的组成方式:

UDP Hex Send Format: 80 00 00 00 11 {WifiBridgeSessionID1} {WifiBridgeSessionID2} 00 {SequenceNumber} 00 {COMMAND} {ZONE NUMBER} 00 {Checksum}

这就是为什么您必须先获取 wifibridge session ,然后才需要计算校验和。

让我举一个关于如何开灯的例子。

文档说:

31 00 00 08 04 01 00 00 00 = Light ON

31 00 00 08 04 01 00 00 00 引用上面的{COMMAND}。

到目前为止,完整的请求必须是:

80 00 00 00 11 {WifiBridgeSessionID1} {WifiBridgeSessionID2} 00 {SequenceNumber} 00 31 00 00 08 04 01 00 00 00 {ZONE NUMBER} 00 {Checksum}

现在让我们获取 Wifibridge session 。文档说:

to get the WifiBridgeSessionID1 and WifiBridgeSessionID2 send this command UDP.

SEND hex bytes: 20 00 00 00 16 02 62 3A D5 ED A3 01 AE 08 2D 46 61 41 A7 F6 DC AF (D3 E6) 00 00 1E <-- Send this to the ip address of the wifi bridge v6

这就是我这样做的原因:

private function getWifiBridgeSession()
    {
        $command = array (
            0x20,0x00, 0x00,
            0x00, 0x16, 0x02,
            0x62, 0x3A, 0xD5,
            0xED, 0xA3, 0x01,
            0xAE, 0x08, 0x2D,
            0x46, 0x61, 0x41,
            0xA7, 0xF6, 0xDC,
            0xAF, 0xD3, 0xE6,
            0x00, 0x00, 0x1E);

        return $this->sendCommand($command);
    }

使用此命令发送 UDP 请求后,您将获得结果。 Wifi Bridge session1 指的是响应的第 20 个字节,WifiBridge Session2 指的是第 21 个字节的响应(别忘了我们是从 0 开始计数的,所以你必须取像“response[19]”和“response [20]").

比方说,在发送这个请求后我得到了这个响应:

28 00 00 00 11 00 02 AC CF 23 F5 7A D4 69 F0 3C 23 00 01 05 00

所以我的“WifiBridgesession1”是 0x05 而“Wifibridgesession2”是 0x00

所以现在我们“打开”灯的请求是:

80 00 00 00 11 0x05 0x00 00 {SequenceNumber} 00 31 00 00 08 04 01 00 00 00 {ZONE NUMBER} 00 {Checksum}

所以现在我们需要找出 {SequenceNumber} {Zone Number} 和 {Checksum}

什么是“序列号”?

文档说:

Sequential byte just helps with keeping commands in the correct order, and it helps to ignore duplicate packets already received. increment this byte for each new command by 1.

所以放上你想要的,并为每个请求将这个值增加到 1。 (我个人总是发送 0x01)。

“区域编号”指的是您同步灯光的区域。

Valid List for {ZONE NUMBER} 0x00 All 0x01 Zone1 0x02 Zone2 0x03 Zone3 0x04 Zone4

比方说,我们的“区域”是 0x01。

快完成了。我们现在只需要计算“校验和”。

文档说:

take the 9 bytes of the command, and 1 byte of the zone, and add the 0 = the checksum = (checksum & 0xFF) e.g. SUM((31 00 00 08 04 01 00 00 00)(command) 01(zone) 00) = 3F(chksum)

所以我们命令的校验和是: 31+00+00+08+04+01+00+00+00+01+00 = 0x54

我添加命令的所有字节(打开)+ 0x01 区域 + 0x00

所以现在我们拥有了一切,打开灯的完整请求是:

80 00 00 00 11 05 00 00 01 00 31 00 00 08 04 01 00 00 00 01 00 54

就是这样。

注意:不要只是复制和粘贴请求,我是根据示例计算的值,每次开灯的请求都会根据您的计算而变化。

也许你注意到我写了“00 31 00 00 08 04 01 00 00 00”来执行“打开”命令,这仅适用于 CW 灯泡。该文档没有指定...... WW 灯泡的相同命令是 00 31 00 00 07 03 01 00 00 00 所以 WW 灯泡的完整命令将是:

80 00 00 00 11 05 00 00 01 00 31 00 00 07 03 01 00 00 00 01 00 54

CW 和 WW 灯泡有什么区别? 我可以看出 CW 指的是“冷白”,WW 指的是“暖白”。但由于我不是“led bulb”方面的专家,我无法解释更多,我也不知道为什么我们需要为两者编写不同的请求。

无论如何,我希望我足够清楚。 让我知道事情是如何运作的。

关于swift - 发送 UDP 数据包的问题(milight,limitlessled),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42535502/

相关文章:

php - 使用 php 和 swift 创建托管 strip 帐户

ios - Swift 中不调用协议(protocol)委托(delegate)方法

macos - 如何在拖动过程中更改拖放图像?

macos - Microsoft RDP for mac 没有恢复,每次最小化后都会重新连接新 session

java - Java中的多线程服务器程序

ios - 数据值溢出

ios - NSURL "missing argument for parameter in call" swift

macos - Visual Studio代码: DesignHostManager failed

c# - tcp 服务器在第一次循环后失败

java - 什么是 "SocketTimeoutException connect time out"以及如何修复它?