前段时间买了一个智能插座,功能很简单就是手动app开关插座和定时器开关插座两个功能,对于后面那种功能,我当时挺好奇的,因为可以设置某年某月某日某时某分对插座进行开关机,说到这里,可能大伙觉得挺简单的,不就是服务器那边同步下时间,到时推送个控制信息就搞定了
,重点不在于这里,那款插座还有一个功能就是即使没有网络也可以定时开关,说道这里,大伙可能想到需要一个时钟芯片本地保存下时间,那问题是时间哪里来的呢(首先申明我的插座没有输入功能,可以看我之前发的帖子)?可能搞过网络时间同步的朋友应该知道,SNTP,是的,今天的话题就是如何在ESP8266里面实现SNTP功能,首先来个简单介绍:
在一些特定的场景中,经常需要整个网络中的计算机保持时间同步。例如,空中管制系统或者轨道交通控制系统中的计算机的时间需要保持精确同步。在大型计算机系统中,往往由很多台计算机共同执行某个计算,也需要各台计算机保持时间同步。那么,我们通过什么方法来同步这些计算机的时间呢?
科学家发明了一种叫做NTP的网络时间协议。网络时间协议是一种在网络计算机上同步计算机时间的的协议,它具有高度的精确性(能精确到几十毫秒),但是算法非常复杂。实际上,在很多应用场景中,并不需要这么高的精确度,通常只要达到秒级的精确度就足够了。于是,科学家在NTP的基础上推出了SNTP(简单网络时间协议,Simple Network Time Protocol)。SNTP大大简化了NTP协议,同时也能保证时间达到一定的精确度。在实际应用中,SNTP协议主要被用来同步因特网上计算机的时间。
实现SNTP功能,首先需要找到SNTP服务器,这方面百度下就可以找到,我搞了两个服务器,一个国外,一个是上海交大的:us.pool.ntp.org,ntp.sjtu.edu.cn,找到了这个,我们就可以调用官方的API来实现,对于官方文档,我只能说是鸡肋,我不是黑他们,主要是太糙了,给的文档例子,调用后会导致芯片重启,我都无语了,每次遇到这种情况咨询他们都叫我自己去DEBUG,又不给我提供全部的错误信息说明,每次都是经过大量的失败测试才找到正确的方法,就像上次的JSON解析一样。对于SNTP,我设置了一个定时器来实现(具体API说明看官方文档,可能说明有些简单,我写的文档只对那些有基础,但被几个技术问题困惑的人,我加过三四个ESP8266的群,但是对于我来说就是吹牛逼扯淡的地方,里面是不会出现帮你解答技术问题的,更别说有些价值的问题),关键代码如下:
void ICACHE_FLASH_ATTR sntp_cb()
{
uint32 current_stamp;
#if 1//for sntp test
/*
需要判断该函数sntp_get_current_timestamp返回值
如果该返回值为非0的数表示已经接收到服务器的数据了
*/
current_stamp = sntp_get_current_timestamp();
os_printf("###sntp: %d, %s \n",current_stamp, sntp_get_real_time(current_stamp));
if(current_stamp)
{
os_printf("###sntp:timezone=%d\n",sntp_get_timezone());
os_timer_disarm(&sntp_timer);
}
#endif
}
sntp_setservername(0,"us.pool.ntp.org"); // set server 0 by domain name 96.126.105.86
sntp_setservername(1,"ntp.sjtu.edu.cn"); // set server 1 by domain name 202.120.2.100
ip_addr_t *addr = (ip_addr_t *)os_zalloc(sizeof(ip_addr_t));
if(addr)
{
addr->addr = 0xC0A801CA;
sntp_setserver(2, addr); // set server 2 by IP address
}
sntp_init();
os_free(addr);
os_timer_disarm(&sntp_timer);
os_timer_setfn(&sntp_timer,sntp_cb,NULL);
os_timer_arm(&sntp_timer,30*1000,1);
就上面这个功能就可以让你做一款网络时钟,加个蜂鸣器,想什么时候响就什么响。,最后上个我从SNTP服务器获得的时间,有了准确的时间,你想干嘛就干嘛,网上那些定时功能也就是这样来的,技术永远都是一个样,会的永远觉得太简单,不会的在简单也会觉得很难~~~~~~~~~~~~~~~~~~