发送 UDP 数据包的问题(milight,limitlessled)
Problems with sending UDP packets (milight, limitlessled)
我正在尝试编写一个菜单栏应用程序以通过 Mac 控制我的灯光。
我用的是milight (limitless, easybulbs...)的系统。
他们有一个开放的系统,你可以通过 UDP 发送命令。
我可以通过 python 中的 python-limitless 库来控制我的灯,所以我知道 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 桥接会话。您还需要根据您的要求计算 Milight 所谓的 "checksum"。
你还要确定你有什么样的灯泡,是WW灯泡还是CW灯泡?由于发送错误的请求,我被困了好几天..
我做了一个实现,它在 php 中,但你可以在 Objective-C 中以同样的方式使用它。
检查一下:https://github.com/winosaure/MilightAPI
更新:
根据 limitlessled "documentation" (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 会话然后计算校验和的原因。
举个例子,开灯
文档说:
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 会话。文档说:
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
所以现在我们对 "turn on" 灯的请求是:
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}
什么是 "Sequence Number"?
文档说:
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)。
"Zone number" 指的是您同步灯光的区域。
Valid List for {ZONE NUMBER} 0x00 All 0x01 Zone1 0x02 Zone2 0x03
Zone3 0x04 Zone4
比方说,我们的"zone"是0x01。
快完成了。我们现在只需要计算 "checksum".
文档说:
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”来执行 "turn on" 命令,这仅适用于 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 指的是 "Cold White",WW 指的是 "Warm White"。但由于我不是 "led bulb" 方面的专家,我无法解释更多,我也不知道为什么我们需要为两者编写不同的请求。
无论如何,我希望我足够清楚。
让我知道事情进展如何。
我正在尝试编写一个菜单栏应用程序以通过 Mac 控制我的灯光。 我用的是milight (limitless, easybulbs...)的系统。 他们有一个开放的系统,你可以通过 UDP 发送命令。
我可以通过 python 中的 python-limitless 库来控制我的灯,所以我知道 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 桥接会话。您还需要根据您的要求计算 Milight 所谓的 "checksum"。
你还要确定你有什么样的灯泡,是WW灯泡还是CW灯泡?由于发送错误的请求,我被困了好几天..
我做了一个实现,它在 php 中,但你可以在 Objective-C 中以同样的方式使用它。
检查一下:https://github.com/winosaure/MilightAPI
更新:
根据 limitlessled "documentation" (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 会话然后计算校验和的原因。
举个例子,开灯
文档说:
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 会话。文档说:
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
所以现在我们对 "turn on" 灯的请求是:
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}
什么是 "Sequence Number"?
文档说:
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)。
"Zone number" 指的是您同步灯光的区域。
Valid List for {ZONE NUMBER} 0x00 All 0x01 Zone1 0x02 Zone2 0x03 Zone3 0x04 Zone4
比方说,我们的"zone"是0x01。
快完成了。我们现在只需要计算 "checksum".
文档说:
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”来执行 "turn on" 命令,这仅适用于 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 指的是 "Cold White",WW 指的是 "Warm White"。但由于我不是 "led bulb" 方面的专家,我无法解释更多,我也不知道为什么我们需要为两者编写不同的请求。
无论如何,我希望我足够清楚。 让我知道事情进展如何。