0%

how to control Yeelight

其实 Yeelight 官方描述已经足够,但是对于入门的人来说并不够详细,官方对于 Yeelight 产品的局域网控制功能在这里有说明 https://www.yeelight.com/zh_CN/developer,同样也有详细的文档。本文只是略微做一些说明。

Yeelight 产品的局域网控制分为两步

  • 发送 ssdp 消息,获取产品的信息;(这里是通过udp发送一个特定字符串,接收yeelight发回的消息,其内包含这个设备的IP地址和TCP端口)
  • 根据信息,发送控制信息。(通过上一个步骤拿到的地址和端口使用tcp连接到yeelight设备,然后通过tcp连接发送控制消息,控制消息的具体格式在官方文档中有说明)

向239.255.255.250:1982 发送一条消息

1
M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1982\r\nMAN: "ssdp:discover"\r\nST: wifi_bulb

在本例中,米家智能台灯会返回一下消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HTTP/1.1 200 OK
Cache-Control: max-age=3600
Date:
Ext:
Location: yeelight://192.168.100.100:55443
Server: POSIX UPnP/1.0 YGLC/1
id: 0x0000000002c5343e
model: desklamp
fw_ver: 58
support: get_prop set_default set_power toggle set_ct_abx set_bright start_cf stop_cf set_scene cron_add cron_get cron_del set_adjust adjust_bright adjust_ct set_name
power: on
bright: 60
color_mode: 2
ct: 4000
rgb: 0
hue: 0
sat: 0
name:

以上信息中,”Location: yeelight://192.168.100.100:55443”是比较关键的信息,这里包含了米家智能台灯的IP地址和tcp控制端口,通过tcp连接台灯之后,向台灯发送控制消息即可。下面是一些示范。

扫描 Yeelight 设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <winsock2.h>
#include <WS2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

int main(int argc, char* argv[])
{
WORD socketVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(socketVersion, &wsaData) != 0)
{
return 0;
}
SOCKET sclient = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(1982);
inet_pton(AF_INET, "239.255.255.250" ,&sin.sin_addr.S_un.S_addr);
int len = sizeof(sin);

const char * sendData = "M-SEARCH * HTTP/1.1\r\nHOST: 239.255.255.250:1982\r\nMAN: \"ssdp:discover\"\r\nST: wifi_bulb";
int result = sendto(sclient, sendData, strlen(sendData), 0, (sockaddr *)&sin, len);
printf("send data size: %d\n", result);

char recvData[1024];
int ret = recvfrom(sclient, recvData, 1024, 0, (sockaddr *)&sin, &len);
if (ret > 0)
{
recvData[ret] = 0x00;
printf(recvData);
}

closesocket(sclient);
WSACleanup();
return 0;
}

需要注意的是,发送扫描信息需要使用udp方式,并且发送扫描信息和接收响应信息需要通过同一个sockt。

控制 Yeelight 设备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

#define REMOTE_IP "127.0.0.1"
#define REMOTE_PORT 8080

int main()
{
//初始化winsock服务
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);

//创建socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

struct sockaddr_in svraddr;
svraddr.sin_family = AF_INET;
svraddr.sin_port = htons(55443);
svraddr.sin_addr.s_addr = inet_addr("192.168.100.100");

//连接socket
if (connect(sock, (struct sockaddr*)&svraddr, sizeof(svraddr)) != -1)
{
//发送数据给服务端
Sleep(1000);

//printf("%s", sendbuf);
int sw = 0;
char sendbuf1[] = "{\"id\":1,\"method\":\"set_bright\",\"params\":[100,\"smooth\",500]}\r\n";
char sendbuf2[] = "{\"id\":1,\"method\":\"set_bright\",\"params\":[10,\"smooth\",500]}\r\n";
char buf[1024] = { 0 };
while (scanf("%d",&sw)!=0)
{
switch (sw) {
case 1:

printf("%s", sendbuf1);
if (send(sock, sendbuf1, strlen(sendbuf1), 0) != -1)
{
//接收服务端数据
//Sleep(1000);

if (recv(sock, buf, 1024, 0) > 0)
{
printf("recv server: \r\n %s\r\n", buf);
}
memset(buf, 0, 1024);
}
break;
case 2:

printf("%s", sendbuf2);
if (send(sock, sendbuf2, strlen(sendbuf2), 0) != -1)
{
//接收服务端数据
//Sleep(1000);
//char buf[1024] = { 0 };
if (recv(sock, buf, 1024, 0) > 0)
{
printf("recv server: \n %s\n", buf);
}
memset(buf, 0, 1024);
}
break;

}
if (sw == 3)
break;
}

}
else
{
printf("can not connect server\n");
}

//关闭socket
closesocket(sock);

//关闭winsock服务
WSACleanup();
getchar();
return 0;
}

在台灯开启的情况下,输入1或者2进行亮度调节,输入3退出。

更多更详细的控制信息可以阅读官方文档