yeelink探究

对yeelink服务器上的相应数据进行改写,并用上位机查看。




#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
// 请求缓冲区和响应缓冲区
char http_request[1024] = { 0, };
char http_response[1024] = { 0, };
// 主机IP地址,也可以是主机域名
char remote_server[] = "api.yeelink.net";
// 文件地址 RESTFUL形式
char remote_path[] = "/v1.0/device/写自己的/sensor/写自己的/datapoints";//需要相应更改
// 用户密码
char apikey[] = "写自己的";//需要相应更改
int main(int argc, char **argv)
{
	WSADATA wsaData;
	int result;
	int socket_id;
	// 传感器检测结果
	double value = 5.9;
	// Http属性
	char http_attribute[64] = { 0, };
	// Http内容,表单内容
	char http_content[64] = { 0, };
	// 确定HTTP表单提交内容 {"value":20}
	sprintf_s(http_content, "{\"value\":%.2f}", value);
	// 确定 HTTP请求首部
	// 例如POST /v1.0/device/1949/sensor/2510/datapoints HTTP/1.1\r\n
	char http_header[64] = { 0, };
	sprintf_s(http_header, "POST %s HTTP/1.1\r\n", remote_path);
	strcpy_s(http_request, http_header); // 复制到请求缓冲区中
	// 增加属性 例如 Host: api.yeelink.net\r\n
	sprintf_s(http_attribute, "Host:%s\r\n", remote_server);
	strcat_s(http_request, http_attribute);
	memset(http_attribute, 0, sizeof(http_attribute));
	// 增加密码 例如 U-ApiKey: ffa3826972d6cc7ba5b17e104ec59fa3
	sprintf_s(http_attribute, "U-ApiKey:%s\r\n", apikey);
	strcat_s(http_request, http_attribute);
	memset(http_attribute, 0, sizeof(http_attribute));
	// 增加提交表单内容的长度 例如 Content-Length:12\r\n
	sprintf_s(http_attribute, "Content-Length:%d\r\n", strlen(http_content));
	strcat_s(http_request, http_attribute);
	memset(http_attribute, 0, sizeof(http_attribute));
	// 增加表单编码格式 Content-Type:application/x-www-form-urlencoded\r\n
	// 该步骤可省略
	strcat_s(http_request, "Content-Type:application/x-www-form-urlencoded\r\n");
	memset(http_attribute, 0, sizeof(http_attribute));
	// HTTP首部和HTTP内容 分隔部分
	strcat_s(http_request, "\r\n");
	// HTTP负载内容
	strcat_s(http_request, http_content);
	// Winsows下启用socket
	result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) {
		printf("WSAStartup failed: %d\n", result);
		return 1;
	}
	// DNS解析 获得远程IP地址
	struct hostent *remote_host;
	remote_host = gethostbyname(remote_server);
	if (remote_host == NULL)
	{
		printf("DNS failed\r\n");
		return 1;
	}
	// 创建套接字
	socket_id = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in remote_sockaddr;
	remote_sockaddr.sin_family = AF_INET;
	remote_sockaddr.sin_port = htons(80);
	remote_sockaddr.sin_addr.s_addr = *(u_long *)remote_host->h_addr_list[0];
	memset(&(remote_sockaddr.sin_zero), 0, sizeof(remote_sockaddr.sin_zero));
	// 连接远程主机
	result = connect(socket_id, (struct sockaddr *)&remote_sockaddr, sizeof(struct sockaddr));
	if (result == SOCKET_ERROR)
	{
		printf("connect ok\r\n");
	}
	// 发送请求
	printf("Http request:\r\n%s\r\n", http_request);
	printf("--------------------\r\n");
	send(socket_id, http_request, strlen(http_request), 0);
	// 获得响应
	int bytes_received = 0;
	bytes_received = recv(socket_id, http_response, 1024, 0);
	http_response[bytes_received] = '\0';
	printf("Receive Message:\r\n%s\r\n", http_response);
	printf("--------------------\r\n");
	// 判断是否收到HTTP OK
	char* presult = strstr(http_response, "200 OK\r\n");
	if (presult != NULL) printf("Http response OK\r\n");
	// 关闭套接字
	closesocket(socket_id);
	WSACleanup();

	// 输入任何字符则关闭程序
	printf("Finish\r\n"); getchar();
	return 0;
}

上述代码为数据改写代码,在vs2013c/c++上运行可更改yeelink服务器其上相应数据。


#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <windows.h>
#pragma comment(lib, "ws2_32.lib")
// 请求缓冲区和响应缓冲区
char http_request[1024] = { 0, };
char http_response[1024] = { 0, };
// 主机IP地址,也可以是主机域名
char remote_server[] = "api.yeelink.net";
// 文件地址 RESTFUL形式
char remote_path[] = "/v1.0/device/写自己的/sensor/写自己的/datapoints";
// 用户密码
char apikey[] = "写自己的";

char test_http[1024] = { 0, };
char test_str[32];
int main(int argc, char **argv)
{
	WSADATA wsaData;
	int result;
	int socket_id;
	result = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (result != 0) {
		printf("WSAStartup failed: %d\n", result);
		return 1;
	}
	// DNS解析 获得远程IP地址
	struct hostent *remote_host;
	remote_host = gethostbyname(remote_server);
	if (remote_host == NULL)
	{
		printf("DNS failed\r\n");
		return 1;
	}
	//printf("yeelink address: %s\n", inet_ntop(remote_host->h_addrtype, remote_host->h_addr_list, test_str, sizeof(test_str)));
	//test_http = "POST / v1.0 / device / 写自己的/ sensor / 写自己的 / datapoints HTTP / 1.1\r\nHost:api.yeelink.net\r\nU - ApiKey:写自己的\r\nContent - Length:14\r\nContent - Type:application / x - www - form - urlencoded\r\n\r\n{ \"value\":5.90}"
	sprintf_s(test_http, "POST /v1.0/device/写自己的/sensor/写自己的/datapoints HTTP/1.1\r\nHost:api.yeelink.net\r\nU-ApiKey:写自己的\r\nContent-Length:14\r\nContent-Type:application/x-www-form-urlencoded\r\n\r\n{\"value\":3.90}");
	// 创建套接字
	socket_id = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in remote_sockaddr;
	remote_sockaddr.sin_family = AF_INET;
	remote_sockaddr.sin_port = htons(80);
	remote_sockaddr.sin_addr.s_addr = *(u_long *)remote_host->h_addr_list[0];
	memset(&(remote_sockaddr.sin_zero), 0, sizeof(remote_sockaddr.sin_zero));
	// 连接远程主机
	result = connect(socket_id, (struct sockaddr *)&remote_sockaddr, sizeof(struct sockaddr));
	if (result == SOCKET_ERROR)
	{
		printf("connect ok\r\n");
	}
	// 发送请求
	//printf("Http request:\r\n%s\r\n", http_request);
	//printf("--------------------\r\n");
	printf("test_http:\r\n%s\r\n", test_http);//自定义,需要修改
	printf("--------------------\r\n");
	send(socket_id, test_http, strlen(test_http), 0);////////////////////////////////////////////
	// 获得响应
	int bytes_received = 0;
	bytes_received = recv(socket_id, http_response, 1024, 0);
	http_response[bytes_received] = '\0';
	printf("Receive Message:\r\n%s\r\n", http_response);
	printf("--------------------\r\n");
	// 判断是否收到HTTP OK
	char* presult = strstr(http_response, "200 OK\r\n");
	if (presult != NULL) printf("Http response OK\r\n");
	// 关闭套接字
	closesocket(socket_id);
	WSACleanup();

	// 输入任何字符则关闭程序
	printf("Finish\r\n"); getchar();
	return 0;
}

第二段代码是对于第一段代码的改写。对比可以发现,整个程序的主要分以下几步



result = WSAStartup(MAKEWORD(2, 2), &wsaData);

1 开启windows自带的功能,固定格式。



remote_host = gethostbyname(remote_server);

2 将域名解析成ip,其中解析的ip地址可以用以下的方式打印出来

printf("yeelink address: %s\n", inet_ntop(remote_host->h_addrtype, remote_host->h_addr_list, test_str, sizeof(test_str)));




3 创建套接字,通过这步,我们得到了两个比较重要的东西:socket_id(不知道干啥) remote_sockaddr(remote_sockaddr.sin_addr.s_addr = *(u_long *)remote_host->h_addr_list[0]; 含有刚才解析的域名的ip)

// 创建套接字
	socket_id = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in remote_sockaddr;
	remote_sockaddr.sin_family = AF_INET;
	remote_sockaddr.sin_port = htons(80);
	remote_sockaddr.sin_addr.s_addr = *(u_long *)remote_host->h_addr_list[0];
	memset(&(remote_sockaddr.sin_zero), 0, sizeof(remote_sockaddr.sin_zero));



4 连接远程主机。利用上面已经得到的socket_id 和 remote_sockaddr连接主机

result = connect(socket_id, (struct sockaddr *)&remote_sockaddr, sizeof(struct sockaddr));


5 发送请求。

send(socket_id, test_http, strlen(test_http), 0);

这个请求是有一定格式的,控制相应变量的格式如下

POST /v1.0/device/写自己的/sensor/写自己的/datapoints HTTP/1.1
Host:api.yeelink.net
U-ApiKey:写自己的
Content-Length:14//根据设定的数据长度进行改变
Content-Type:application/x-www-form-urlencoded

{"value":5.90}

获取相应变量的格式为

GET /v1.0/device/写自己的/sensor/写自己的/datapoints HTTP/1.1
Host:api.yeelink.net
U-ApiKey:写自己的
Accept: */*
Content-Type:application/x-www-form-urlencoded
Connection: close

只要在连接后,通过send函数将相应格式发送到yeelink服务器上,就能得到相应。


6 获得响应

	bytes_received = recv(socket_id, http_response, 1024, 0);
	http_response[bytes_received] = '\0';

运行之后http_reponse这个变量里面就包含了相应结果。对于获取数据,返回字符串里面就包含数据;对于设定数据,返回字符串里面包含数据设定的成功与否。




7 关闭套接字

closesocket(socket_id);


8 关闭第一步是运行的那个玩意儿

WSACleanup();





运行成功后显示如下

改写后yeelink平台也会有相应变化,这里就不展示了。


以上工程详见:控制yeelink服务器变量;控制yeelink服务器变量(原版)


下面是上位机的制作。上位机的主要功能是没一秒刷新一次结果(yeelink平台上的显示需要手动刷新,恨不爽)。下面是一个网上大神发布的上位机(无刷新)的截图,亲测好使。




以上工程详见:查看yeelink服务器变量


下图是我的上位机


我的上位机是自动刷新,每秒刷新一次。


以上工程详见:查看yeelink服务器变量(刷新)







猜你喜欢

转载自blog.csdn.net/m1f2c3/article/details/72582991
今日推荐