数码之家

 找回密码
 立即注册
搜索
查看: 4190|回复: 47

[软件] 偷懒成功了!给监控硬盘录相机建一个NTP时间服务器

[复制链接]
发表于 2023-5-9 11:31:16 | 显示全部楼层 |阅读模式
我工作的物业小区比较大,十二台监控硬盘录相机分布在二个监控机房。由于每台录相机的时间运行有偏差,导致查询录相时经常出现不同机子的时间衔接不上,很是麻烦。由此我被分配了一个任务,每周至少两次对这些录相机进行手工调整时间,但是如此操作最多也只能将机器的时间误差压缩到一分钟以内,工作量增加了不说效果也不很理想。由于监控网络并不连接外网,网络校时无法实现,此我想到了在局域网内建立一台NTP时间服务器的想法,让这些录相机自动校时,不仅减轻了我的工作而且时间精度也大大提高。于是找来了一台公司淘汰下来的电脑,重新安装上WIN7系统,按照网上找到的办法修改注册表、设置服务项及端口,成功将电脑改成了一台时间服务器,经实际运行使用效果来看,每台录像机的时间偏差都在1秒以内,而且不用再去人工校时了,算是偷懒成功了


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

打赏

参与人数 4家元 +130 收起 理由
亚历山大 + 10
家睦 + 100
wgm468 + 10 謝謝分享
yinjiudong + 10

查看全部打赏

发表于 2023-5-9 11:53:18 | 显示全部楼层
你倒是偷懒了,就不怕工作丢了吗?不要期望你就此会更轻松
回复 支持 1 反对 0

使用道具 举报

发表于 2023-5-9 11:53:39 | 显示全部楼层
牛的,想法才是最赚钱的
回复 支持 反对

使用道具 举报

发表于 2023-5-9 11:54:15 | 显示全部楼层
在很多应用中,建立标准时间源是必须的,包括数据库等应用系统都是需要的
回复 支持 反对

使用道具 举报

发表于 2023-5-9 11:59:15 来自手机浏览器 | 显示全部楼层
heju 发表于 2023-5-9 11:53
你倒是偷懒了,就不怕工作丢了吗?不要期望你就此会更轻松 ...

别说出去,继续坚持每周巡视
回复 支持 1 反对 0

使用道具 举报

发表于 2023-5-9 11:59:45 | 显示全部楼层
有些路由或设备会自带NTP
回复 支持 反对

使用道具 举报

发表于 2023-5-9 12:04:56 | 显示全部楼层
yinjiudong 发表于 2023-5-9 11:59
别说出去,继续坚持每周巡视

社会现实就是这样的,你打工的话,你凭自己的能力,把工作都搞成很方便轻松了,最后的结果就是你下岗。别问我怎么知道的,亲身体会,要学会给自己保留一点工作机会。
回复 支持 1 反对 0

使用道具 举报

发表于 2023-5-9 12:07:20 | 显示全部楼层
heju 发表于 2023-5-9 11:53
你倒是偷懒了,就不怕工作丢了吗?不要期望你就此会更轻松 ...

我想说的和你的一样!
回复 支持 反对

使用道具 举报

发表于 2023-5-9 12:08:33 | 显示全部楼层
heju 发表于 2023-5-9 12:04
社会现实就是这样的,你打工的话,你凭自己的能力,把工作都搞成很方便轻松了,最后的结果就是你下岗。别 ...

所以只能对自己偷懒,不要对别人说
回复 支持 1 反对 0

使用道具 举报

发表于 2023-5-9 12:14:10 | 显示全部楼层
偷懒成功??老板准备炒鱿鱼了,因为你的工作已经被电脑完成了。
回复 支持 反对

使用道具 举报

发表于 2023-5-9 12:31:20 | 显示全部楼层
调整时间如果是额外的工作,那算是偷懒了,如果是主要工作,你要去干别的活了
回复 支持 1 反对 0

使用道具 举报

发表于 2023-5-9 12:33:35 | 显示全部楼层
自己动手给老板炒鱿鱼的机会
回复 支持 反对

使用道具 举报

发表于 2023-5-9 12:37:21 | 显示全部楼层
本帖最后由 jpdd521 于 2023-5-9 13:02 编辑

直接GPS转成网络的NTP服务器,好像是很简单的。
然后,只要是你上班,你就让服务器工作,你不上班就让服务器不工作,这样,你就成了不可或缺的了

直接用8266就可以完成这个工作,然后加一个GPS模块就可以了,放到室外加一小块太阳能,完美了。

以下是偷懒代码


要使用ESP8266通过串口获取GPS时间并提供NTP服务,您可以使用以下步骤:
  • 首先,您需要将GPS模块连接到ESP8266的串口上。根据您的GPS模块和ESP8266板的引脚分配进行连接,确保将GPS模块的TX引脚连接到ESP8266的RX引脚上,将GPS模块的RX引脚连接到ESP8266的TX引脚上。
  • 接下来,您需要编写ESP8266的Arduino代码来解析GPS数据并提供NTP服务。以下是一个示例代码,它使用TinyGPS++库解析GPS数据,并使用WiFiUDP库提供NTP服务:

在这个例子中,我们使用了 SoftwareSerial 库来创建一个串口对象,以便将GPS模块连接到ESP8266的D1和D2引脚。在 setup() 函数中,我们启动了GPS串口通信和UDP。在 loop() 函数中,我们检查GPS数据是否有更新,并且如果有新的有效GPS数据,我们会使用 makeEpochTime() 函数将日期和时间转换为自1970年以来的秒数。然后,我们发送一个NTP请求到 ntpServerName,等待响应,并将系统时间设置为GPS时间和NTP时间的平均值。
请注意,此代码仅提供了一个基本的实现,并且可能需要根据您的具体需求进行修改和调整。此外,为了确保准确性,您需要使用可靠的GPS模块和可靠的NTP服务器。

复制代码
  1. #include <ESP8266WiFi.h>
  2. #include <WiFiUdp.h>
  3. #include <SoftwareSerial.h>
  4. #include <TinyGPS++.h>

  5. // 替换为您的网络凭据
  6. const char* ssid = "您的SSID";
  7. const char* password = "您的密码";

  8. // 替换为您的NTP服务器URL
  9. const char* ntpServerName = "pool.ntp.org";

  10. // NTP时间戳在消息的前48个字节中
  11. const int NTP_PACKET_SIZE = 48;

  12. byte packetBuffer[NTP_PACKET_SIZE]; // 用于保存传入和传出数据包的缓冲区
  13. WiFiUDP udp; // UDP实例

  14. // GPS模块
  15. SoftwareSerial gpsSerial(D1, D2); // RX, TX引脚
  16. TinyGPSPlus gps;

  17. void setup() {
  18.   // 连接到Wi-Fi网络
  19.   WiFi.begin(ssid, password);
  20.   while (WiFi.status() != WL_CONNECTED) {
  21.     delay(1000);
  22.     Serial.println("正在连接到WiFi...");
  23.   }
  24.   Serial.println("已连接到WiFi");

  25.   // 开始GPS串口通信
  26.   gpsSerial.begin(9600);
  27.   Serial.println("GPS串口通信已启动");

  28.   // 开始UDP
  29.   udp.begin(123);

  30.   Serial.println("正在等待GPS信号...");
  31. }

  32. void loop() {
  33.   // 检查是否有新的GPS数据
  34.   while (gpsSerial.available() > 0) {
  35.     gps.encode(gpsSerial.read());
  36.   }

  37.   // 如果有新的有效GPS数据,更新时间
  38.   if (gps.time.isValid() && gps.date.isValid()) {
  39.     Serial.println("收到有效的GPS数据");

  40.     // 从GPS模块获取时间
  41.     int year = gps.date.year();
  42.     byte month = gps.date.month();
  43.     byte day = gps.date.day();
  44.     byte hour = gps.time.hour();
  45.     byte minute = gps.time.minute();
  46.     byte second = gps.time.second();

  47.     // 将日期和时间转换为自1970年以来的秒数
  48.     unsigned long epoch = makeEpochTime(year, month, day, hour, minute, second);

  49.     // 发送NTP请求
  50.     sendNTPpacket(ntpServerName);

  51.     // 等待响应
  52.     delay(1000);

  53.     // 如果有可用数据,则读取数据
  54.     if (udp.parsePacket()) {
  55.       Serial.println("收到NTP响应");

  56.       // 将NTP数据读入缓冲区
  57.       udp.read(packetBuffer, NTP_PACKET_SIZE);

  58.       // 将4个时间戳字节组合成一个32位整数
  59.       unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
  60.       unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  61.       unsigned long ntpTime = highWord << 16 | lowWord;

  62.       // 将NTP时间转换为Unix时间(自1970年以来的秒数)
  63.       unsigned long unixTime = ntpTime - 2208988800UL;

  64.       // 使用GPS时间和NTP时间的平均值设置系统时间
  65.       setTime(epoch + (unixTime - epoch) / 2);
  66.     }
  67.   }
  68. }

  69. // 将日期和时间转换为自1970年以来的秒数
  70. unsigned long makeEpochTime(int year, byte month, byte day, byte hour, byte minute, byte second) {
  71.   // 1月和2月被计算为前一年的第13和14个月
  72.   if (month < 3) {
  73.     month += 12;
  74.     year--;
  75.   }

  76.   // 将年份转换为天数
  77.   unsigned long days = (year - 1970) * 365;

  78.   // 添加闰年天数
  79.   for (int i = 1972; i <= year; i += 4) {
  80.     if (i % 100 != 0 || i % 400 == 0) {
  81.       days++;
  82.     }
  83.   }

  84.   // 添加当前年份的天数
  85.   for (int i = 1; i < month; i++) {
  86.     switch (i) {
  87.       case 2:
  88.         if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
  89.           days += 29;
  90.         } else {
  91.           days += 28;
  92.         }
  93.         break;
  94.       case 4:
  95.       case 6:
  96.       case 9:
  97.       case 11:
  98.         days += 30;
  99.         break;
  100.       default:
  101.         days += 31;
  102.         break;
  103.     }
  104.   }

  105.   days += day - 1; // 减1是因为1月1日是第0天

  106.   // 将天数转换为秒数
  107.   unsigned long seconds = days * 86400;

  108.   // 添加小时、分钟和秒
  109.   seconds += hour * 3600;
  110.   seconds += minute * 60;
  111.   seconds += second;

  112.   return seconds;
  113. }

  114. // 向指定的服务器发送NTP请求
  115. void sendNTPpacket(const char* address) {
  116.   // 将缓冲区中的所有字节设置为0
  117.   memset(packetBuffer, 0, NTP_PACKET_SIZE);

  118.   // 初始化NTP请求所需的值
  119.   packetBuffer[0] = 0b11100011;   // LI、版本、模式
  120.   packetBuffer[1] = 0;     // Stratum或时钟类型
  121.   packetBuffer[2] = 6;     // 轮询间隔
  122.   packetBuffer[3] = 0xEC;  // 精度
  123.   // 8个0字节用于Root Delay和Root Dispersion
  124.   packetBuffer[12]  = 49;
  125.   packetBuffer[13]  = 0x4E;
  126.   packetBuffer[14]  = 49;
  127.   packetBuffer[15]  = 52;

  128.   // 发送请求
  129.   udp.beginPacket(address, 123); // NTP请求发送到端口123
  130.   udp.write(packetBuffer, NTP_PACKET_SIZE);
  131.   udp.endPacket();
  132. }
复制代码

中国人要用北斗,那么,再来个北斗的代码

  1. #include <ESP8266WiFi.h>
  2. #include <WiFiUdp.h>
  3. #include <SoftwareSerial.h>
  4. #include <TimeLib.h>

  5. // 替换为您的网络凭据
  6. const char* ssid = "您的SSID";
  7. const char* password = "您的密码";

  8. // 替换为您的NTP服务器URL
  9. const char* ntpServerName = "pool.ntp.org";

  10. // NTP时间戳在消息的前48个字节中
  11. const int NTP_PACKET_SIZE = 48;

  12. byte packetBuffer[NTP_PACKET_SIZE]; // 用于保存传入和传出数据包的缓冲区
  13. WiFiUDP udp; // UDP实例

  14. // 北斗模块
  15. SoftwareSerial bdSerial(D1, D2); // RX, TX引脚

  16. void setup() {
  17.   // 连接到Wi-Fi网络
  18.   WiFi.begin(ssid, password);
  19.   while (WiFi.status() != WL_CONNECTED) {
  20.     delay(1000);
  21.     Serial.println("正在连接到WiFi...");
  22.   }
  23.   Serial.println("已连接到WiFi");

  24.   // 开始北斗串口通信
  25.   bdSerial.begin(9600);
  26.   Serial.println("北斗串口通信已启动");

  27.   // 开始UDP
  28.   udp.begin(123);

  29.   Serial.println("正在等待北斗信号...");
  30. }

  31. void loop() {
  32.   // 检查是否有新的北斗数据
  33.   while (bdSerial.available() > 0) {
  34.     char c = bdSerial.read();

  35.     // 如果接收到的是'$',则表示开始接收北斗数据
  36.     if (c == '$') {
  37.       // 读取北斗数据
  38.       char buf[64] = {0};
  39.       int i = 0;

  40.       while (true) {
  41.         if (bdSerial.available() > 0) {
  42.           c = bdSerial.read();

  43.           if (c == '\r') {
  44.             break;
  45.           }

  46.           if (i < 63) {
  47.             buf[i++] = c;
  48.           }
  49.         }
  50.       }

  51.       // 分离数据
  52.       char* p = strtok(buf, ",");
  53.       int time[6];

  54.       for (int i = 0; i < 6; i++) {
  55.         time[i] = atoi(p);
  56.         p = strtok(NULL, ",");
  57.       }

  58.       // 将日期和时间转换为自1970年以来的秒数
  59.       unsigned long epoch = makeEpochTime(time[0], time[1], time[2], time[3], time[4], time[5]);

  60.       // 发送NTP请求
  61.       sendNTPpacket(ntpServerName);

  62.       // 等待响应
  63.       delay(1000);

  64.       // 如果有可用数据,则读取数据
  65.       if (udp.parsePacket()) {
  66.         Serial.println("收到NTP响应");

  67.         // 将NTP数据读入缓冲区
  68.         udp.read(packetBuffer, NTP_PACKET_SIZE);

  69.         // 将4个时间戳字节组合成一个32位整数
  70.         unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
  71.         unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
  72.         unsigned long ntpTime = highWord << 16 | lowWord;

  73.         // 将NTP时间转换为Unix时间(自1970年以来的秒数)
  74.         unsigned long unixTime = ntpTime - 2208988800UL;

  75.         // 使用北斗时间和NTP时间的平均值设置系统时间
  76.         setTime(epoch + (unixTime - epoch) / 2);
  77.       }
  78.     }
  79.   }
  80. }

  81. // 将日期和时间转换为自1970年以来的秒数
  82. unsigned long makeEpochTime(int year, int month, int day, int hour, int minute, int second) {
  83.   // 1月和2月被计算为前一年的第13和14个月
  84.   if (month < 3) {
  85.     month += 12;
  86.     year--;
  87.   }

  88.   // 将年份转换为天数
  89.   unsigned long days = (year - 1970) * 365;

  90.   // 添加闰年天数
  91.   for (int i = 1972; i <= year; i += 4) {
  92.     if (i % 100 != 0 || i % 400 == 0) {
  93.       days++;
  94.     }
  95.   }

  96.   // 添加当前年份的天数
  97.   for (int i = 1; i < month; i++) {
  98.     switch (i) {
  99.       case 2:
  100.         if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
  101.           days += 29;
  102.         } else {
  103.           days += 28;
  104.         }
  105.         break;
  106.       case 4:
  107.       case 6:
  108.       case 9:
  109.       case 11:
  110.         days += 30;
  111.         break;
  112.       default:
  113.         days += 31;
  114.         break;
  115.     }
  116.   }

  117.   days += day - 1; // 减1是因为1月1日是第0天

  118.   // 将天数转换为秒数
  119.   unsigned long seconds = days * 86400;

  120.   // 添加小时、分钟和秒
  121.   seconds += hour * 3600;
  122.   seconds += minute * 60;
  123.   seconds += second;

  124.   return seconds;
  125. }

  126. // 向指定的服务器发送NTP请求
  127. void sendNTPpacket(const char* address) {
  128.   // 将缓冲区中的所有字节设置为0
  129.   memset(packetBuffer, 0, NTP_PACKET_SIZE);

  130.   // 初始化NTP请求所需的值
  131.   packetBuffer[0] = 0b11100011;   // LI、版本、模式
  132.   packetBuffer[1] = 0;     // Stratum或时钟类型
  133.   packetBuffer[2] = 6;     // 轮询间隔
  134.   packetBuffer[3] = 0xEC;  // 精度
  135.   // 8个0字节用于Root Delay和Root Dispersion
  136.   packetBuffer[12]  = 49;
  137.   packetBuffer[13]  = 0x4E;
  138.   packetBuffer[14]  = 49;
  139.   packetBuffer[15]  = 52;

  140.   // 发送请求
  141.   udp.beginPacket(address, 123); // NTP请求发送到端口123
  142.   udp.write(packetBuffer, NTP_PACKET_SIZE);
  143.   udp.endPacket();
  144. }
复制代码


打赏

参与人数 4家元 +55 收起 理由
zto中通快递 + 18
jf201006 + 16 精彩回帖
亚历山大 + 10
家睦 + 11

查看全部打赏

回复 支持 10 反对 0

使用道具 举报

发表于 2023-5-9 13:00:08 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2023-5-9 13:11:46 | 显示全部楼层
省时省力的好办法。
回复 支持 反对

使用道具 举报

发表于 2023-5-9 13:54:11 | 显示全部楼层
jpdd521 发表于 2023-5-9 12:37
直接GPS转成网络的NTP服务器,好像是很简单的。
然后,只要是你上班,你就让服务器工作,你不上班就让服务 ...

没错,大型机房的NTP服务器就是利用北斗或者GPS进行报时,相比走网络的延时小很多。
时间同步对于分布式系统是至关重要的,甚至要毫秒级的单位。
回复 支持 反对

使用道具 举报

发表于 2023-5-9 14:10:16 | 显示全部楼层
本帖最后由 free2_citiz 于 2023-5-9 14:20 编辑
  1. win98 时代可以命令行net time同步时间(内网)……现在都是海康威视
复制代码


手动校时

配置网页校时,与计算机时间同步配置-系统-系统设置-时间配置,选择手动校时-与计算机时间同步。

定位校时  仅部分GPS的设备支持

管理平台(4200),iVMS-4200客户端校时

自动校时 进入系统配置-常用-开启自动校时 (外网)

批量校时,右上角工具-批量校时,勾选需要校时的设备

NTP校时  ,内网搭建校时服务器。
回复 支持 反对

使用道具 举报

发表于 2023-5-9 14:19:30 | 显示全部楼层
自由巡视才好划水,如果是定时就麻烦点。
回复 支持 1 反对 0

使用道具 举报

发表于 2023-5-9 15:30:11 | 显示全部楼层
请问有具体方法吗?我也干着相同的工作,还望指点一下,谢谢.
手里有台运行着的WIN2008的服务器
回复 支持 反对

使用道具 举报

发表于 2023-5-9 16:00:14 | 显示全部楼层
恭喜楼主摸鱼成功。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-3 05:19 , Processed in 0.390001 second(s), 16 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表