You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

957 lines
54 KiB

<!DOCTYPE html>
<html lang="">
<head><meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<meta name="theme-color" content="#f8f5ec" />
<meta name="msapplication-navbutton-color" content="#f8f5ec">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="#f8f5ec">
<meta name="description" content="2019 SURF SmartFarming Proj 架构说明"/><meta name="keywords" content="iotcat,yimian,blog" /><link rel="alternate" href="/atom.xml" title="EEE.DOG"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=1.0.0" /><script type="text/javascript" src="https://cdn.yimian.xyz/ushio-js/ushio-head.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.yimian.xyz/kayo/lib/iziModal/iziModal.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.yimian.xyz/kayo/lib/iziToast/iziToast.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.yimian.xyz/shaky/shaky.css">
<link rel="canonical" href="https://www.eee.dog/tech/smartfarming-surf.html"/>
<link rel="stylesheet" type="text/css" href="https://cdn.yimian.xyz/kayo/lib/fancybox/jquery.fancybox.css" /><script type="text/x-mathjax-config">
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ['\\(','\\)']] } });
</script>
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.yimian.xyz/kayo/css/style.css?v=1.0.0" />
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-169276192-1" data-pjax></script>
<script>
pjax_google_analytics = () => {
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-169276192-1');
}
</script><script id="baidu_push">
(function(){
var bp = document.createElement('script');
var curProtocol = window.location.protocol.split(':')[0];
if (curProtocol === 'https') {
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
}
else {
bp.src = 'http://push.zhanzhang.baidu.com/push.js';
}
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(bp, s);
})();
</script>
<script>
window.config = {"leancloud":"","toc":true,"fancybox":true,"pjax":{"enable":true,"loadingbar":true},"latex":true};
</script>
<title>2019 SURF SmartFarming Proj 架构说明 - EEE.DOG</title>
<meta name="generator" content="Hexo 4.2.1"><link rel="alternate" href="/atom.xml" title="EEE.DOG" type="application/atom+xml">
</head>
<body><div id="mobile-navbar" class="mobile-navbar">
<div class="mobile-header-logo">
<a href="/." class="logo">EEE.DOG</a>
</div>
<div class="mobile-navbar-icon">
<span></span>
<span></span>
<span></span>
</div>
<div class="loading-bar">
<div class="progress"></div>
</div>
</div>
<nav id="mobile-menu" class="mobile-menu slideout-menu">
<ul class="mobile-menu-list"><div id="mobile-menu-Archives">
<a href="/archives/">
<li class="mobile-menu-item">Archives
</li>
</a></div><div id="mobile-menu-Categories">
<a href="/categories/">
<li class="mobile-menu-item">Categories
</li>
</a></div><div id="mobile-menu-Projects">
<a href="#">
<li class="mobile-menu-item">Projects
</li>
</a><ul class="sub-menu" style="display: none;">
<li>
<a href="https://fp.yimian.xyz/" target="_blank" rel="noopener">
fp
</a>
</li>
<li>
<a href="https://wiot.yimian.xyz/" target="_blank" rel="noopener">
wiot
</a>
</li>
</ul>
<script>$('#mobile-menu-Projects').click(function(){
$("#mobile-menu-Projects ul").toggle();
})</script>
</div><div id="mobile-menu-Map">
<a href="#">
<li class="mobile-menu-item">Map
</li>
</a><ul class="sub-menu" style="display: none;">
<li>
<a href="https://api.yimian.xyz/" target="_blank" rel="noopener">
APIs
</a>
</li>
<li>
<a href="https://img.yimian.xyz/" target="_blank" rel="noopener">
Imgs
</a>
</li>
<li>
<a href="/">
Imgbed
</a>
</li>
<li>
<a href="https://share.yimian.xyz/" target="_blank" rel="noopener">
Fileshare
</a>
</li>
<li>
<a href="https://monitor.yimian.xyz/" target="_blank" rel="noopener">
Monitor
</a>
</li>
<li>
<a href="https://acg.watch/" target="_blank" rel="noopener">
ACG.WATCH
</a>
</li>
<li>
<a href="https://onedrive.yimian.xyz/" target="_blank" rel="noopener">
Oneindex
</a>
</li>
<li>
<a href="https://proxy.yimian.xyz/" target="_blank" rel="noopener">
Proxy
</a>
</li>
<li>
<a href="https://shorturl.yimian.xyz/" target="_blank" rel="noopener">
ShortenURL
</a>
</li>
</ul>
<script>$('#mobile-menu-Map').click(function(){
$("#mobile-menu-Map ul").toggle();
})</script>
</div><div id="mobile-menu-About">
<a href="#">
<li class="mobile-menu-item">About
</li>
</a><ul class="sub-menu" style="display: none;">
<li>
<a href="/links/">
links
</a>
</li>
<li>
<a href="https://iotcat.me/" target="_blank" rel="noopener">
Me
</a>
</li>
</ul>
<script>$('#mobile-menu-About').click(function(){
$("#mobile-menu-About ul").toggle();
})</script>
</div></ul>
</nav>
<div class="container" id="mobile-panel">
<header id="header" class="header"><div class="logo-wrapper">
<a href="/." class="logo">EEE.DOG</a>
</div>
<nav class="site-navbar"><ul id="menu" class="menu"><li class="menu-item">
<a id="menu-Archives" class="menu-item-link" href="/archives/">
Archives
</a>
</li>
<li class="menu-item">
<a id="menu-Categories" class="menu-item-link" href="/categories/">
Categories
</a>
</li>
<li class="menu-item">
<a id="menu-Projects" class="menu-item-link" href="#">
Projects
</a>
<script>
$("#menu-Projects").click(function(){
iziToast.question({
timeout: 20000,
close: false,
overlay: true,
displayMode: 'once',
//id: 'question',
zindex: 999,
title: 'Projects',
message: '',
position: 'center',
buttons: [
['<button><b>fp</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://fp.yimian.xyz/");
else
window.location.href="https://fp.yimian.xyz/";
}, true],
['<button><b>wiot</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://wiot.yimian.xyz/");
else
window.location.href="https://wiot.yimian.xyz/";
}, true],
['<button><b>close</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}, true],
]
});
});
</script>
</li>
<li class="menu-item">
<a id="menu-Map" class="menu-item-link" href="#">
Map
</a>
<script>
$("#menu-Map").click(function(){
iziToast.question({
timeout: 20000,
close: false,
overlay: true,
displayMode: 'once',
//id: 'question',
zindex: 999,
title: 'Map',
message: '',
position: 'center',
buttons: [
['<button><b>APIs</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://api.yimian.xyz/");
else
window.location.href="https://api.yimian.xyz/";
}, true],
['<button><b>Imgs</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://img.yimian.xyz/");
else
window.location.href="https://img.yimian.xyz/";
}, true],
['<button><b>Imgbed</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("/");
else
window.location.href="undefined";
}, true],
['<button><b>Fileshare</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://share.yimian.xyz/");
else
window.location.href="https://share.yimian.xyz/";
}, true],
['<button><b>Monitor</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://monitor.yimian.xyz/");
else
window.location.href="https://monitor.yimian.xyz/";
}, true],
['<button><b>ACG.WATCH</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://acg.watch/");
else
window.location.href="https://acg.watch/";
}, true],
['<button><b>Oneindex</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://onedrive.yimian.xyz/");
else
window.location.href="https://onedrive.yimian.xyz/";
}, true],
['<button><b>Proxy</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://proxy.yimian.xyz/");
else
window.location.href="https://proxy.yimian.xyz/";
}, true],
['<button><b>ShortenURL</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://shorturl.yimian.xyz/");
else
window.location.href="https://shorturl.yimian.xyz/";
}, true],
['<button><b>close</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}, true],
]
});
});
</script>
</li>
<li class="menu-item">
<a id="menu-About" class="menu-item-link" href="#">
About
</a>
<script>
$("#menu-About").click(function(){
iziToast.question({
timeout: 20000,
close: false,
overlay: true,
displayMode: 'once',
//id: 'question',
zindex: 999,
title: 'About',
message: '',
position: 'center',
buttons: [
['<button><b>links</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("true" == "true")
pjax.loadUrl("/links/");
else
window.location.href="/links/";
}, true],
['<button><b>Me</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
if("undefined" == "true")
pjax.loadUrl("https://iotcat.me/");
else
window.location.href="https://iotcat.me/";
}, true],
['<button><b>close</b></button>', function (instance, toast) {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}, true],
]
});
});
</script>
</li>
</ul></nav>
</header>
<main id="main" class="main">
<div class="content-wrapper">
<div id="content" class="content"><article class="post">
<header class="post-header">
<h1 class="post-title">2019 SURF SmartFarming Proj 架构说明
</h1>
<div class="post-meta">
<span class="post-time">
2019-07-26
</span><span class="post-category">
<a href="/categories/tech/">tech</a>
</span>
</div>
</header>
<div class="post-toc" id="post-toc">
<h2 class="post-toc-title">Contents</h2>
<div class="post-toc-content">
<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-背景"><span class="toc-text">1 背景</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-需求"><span class="toc-text">1.1 需求</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-定位"><span class="toc-text">1.2 定位</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-名词解释"><span class="toc-text">2 名词解释</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-设计目标"><span class="toc-text">3 设计目标</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-1-实现功能"><span class="toc-text">3.1 实现功能</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-2-性能指标"><span class="toc-text">3.2 性能指标</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-系统环境"><span class="toc-text">4 系统环境</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-相关软件及硬件"><span class="toc-text">4.1 相关软件及硬件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-数据规模预估"><span class="toc-text">4.2 数据规模预估</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-设计思路"><span class="toc-text">5 设计思路</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-理念"><span class="toc-text">5.1 理念</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-2-关键问题"><span class="toc-text">5.2 关键问题</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-方案选择"><span class="toc-text">5.3 方案选择</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-架构设计"><span class="toc-text">6 架构设计</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#6-1-基础介绍"><span class="toc-text">6.1 基础介绍</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-2-系统层级图"><span class="toc-text">6.2 系统层级图</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-3-系统拓扑图"><span class="toc-text">6.3 系统拓扑图</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-模块说明"><span class="toc-text">7 模块说明</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#7-1-LoRa通信模块"><span class="toc-text">7.1 LoRa通信模块</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-2-MQTT-Proxy代理模块"><span class="toc-text">7.2 MQTT-Proxy代理模块</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-3-水泵控制模块"><span class="toc-text">7.3 水泵控制模块</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-4-mqtt-数据处理模块"><span class="toc-text">7.4 mqtt+数据处理模块</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-5-web接口模块"><span class="toc-text">7.5 web接口模块</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8-开发文档"><span class="toc-text">8 开发文档</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#8-1-mqtt主题"><span class="toc-text">8.1 mqtt主题</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-2-http接口"><span class="toc-text">8.2 http接口</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-3-websocket接口"><span class="toc-text">8.3 websocket接口</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9-运行状态"><span class="toc-text">9 运行状态</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#9-1-系统延时"><span class="toc-text">9.1 系统延时</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-2-传感器数据"><span class="toc-text">9.2 传感器数据</span></a></li></ol></li></ol>
</div>
</div><div class="post-content"><p>本文详细介绍了XJTLU大学2019暑期科研SmartFarming Proj物联网架构的设计思路,实施情况以及缺陷反思。</p>
<a id="more"></a>
<h2 id="1-背景"><a href="#1-背景" class="headerlink" title="1 背景"></a>1 背景</h2><h3 id="1-1-需求"><a href="#1-1-需求" class="headerlink" title="1.1 需求"></a>1.1 需求</h3><p>为了探究农业物联网技术的可行性,Alam Mohammed导师希望我们能够提供一个<strong>稳定(Available)</strong><strong>可靠(Reliable)</strong>的物联网系统,以实现对农田的智能监控和管理。这个系统将能够适时地探测土壤以及空气中与植物健康相关的参数,处理并存储这些数据(由Alam提出)。同时,自动化控制的灌溉功能(由Caleb提出)以及一些数据展示方法(由Alam提出的可选需求)也被期待由本系统提供。</p>
<h3 id="1-2-定位"><a href="#1-2-定位" class="headerlink" title="1.2 定位"></a>1.2 定位</h3><p>由于是针对农业物联网设计的小型科研项目,项目的目标是对农业物联网的可行性进行探究,愿景是模拟最普遍的小型农业物联网应用场景。因此本架构的定位是<strong>适用于大部分具备感知,控制和展示功能的小型农业物联网工程</strong></p>
<h2 id="2-名词解释"><a href="#2-名词解释" class="headerlink" title="2 名词解释"></a>2 名词解释</h2><blockquote>
<ul>
<li><code>MQTT</code>: MQTT消息队列遥测传输(Message Queuing Telemetry Transport)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在 TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而设计的发布/订阅型消息协议[1]。</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li><code>LoRa</code>: LoRa是当前市场上的一种新兴技术,其在1 GHz以下的公共频段中运行,用于远距离低功耗通信[2]。</li>
</ul>
</blockquote>
<h2 id="3-设计目标"><a href="#3-设计目标" class="headerlink" title="3 设计目标"></a>3 设计目标</h2><h3 id="3-1-实现功能"><a href="#3-1-实现功能" class="headerlink" title="3.1 实现功能"></a>3.1 实现功能</h3><p>本架构功能性需求主要包括土地数据采集,气象数据采集,灌溉系统控制,与无人机小组系统进行交互,网页控制台(可查看实时和历史传感数据,指标数据;能够控制系统)。</p>
<h3 id="3-2-性能指标"><a href="#3-2-性能指标" class="headerlink" title="3.2 性能指标"></a>3.2 性能指标</h3><ul>
<li><code>通信范围(测试)</code>:半径不低于1km</li>
<li><code>通信范围(生产)</code>:半径不低于3km</li>
<li><code>延时</code>:平均小于1s</li>
<li><code>超时率</code>:不超过5%</li>
<li><code>资源占用</code>:节点RAM不超过2k</li>
<li><code>运行周期</code>:1分 (测试) | 15分 (生产)</li>
</ul>
<h2 id="4-系统环境"><a href="#4-系统环境" class="headerlink" title="4 系统环境"></a>4 系统环境</h2><h3 id="4-1-相关软件及硬件"><a href="#4-1-相关软件及硬件" class="headerlink" title="4.1 相关软件及硬件"></a>4.1 相关软件及硬件</h3><p>!!!</p>
<table>
<tr>
<td style="vertical-align: middle;text-align: center;"><strong>节点名称</strong></td>
<td style="vertical-align: middle;text-align: center;"><strong>硬件设施</strong></td>
<td style="vertical-align: middle;text-align: center;"><strong>软件集群</strong></td>
</tr>
<tr>
<td rowspan="6" style="vertical-align: middle;text-align: center;">土地节点<br/>Ground Nodes</td>
<td>Arduino Nano</td>
<td>Arduino.h</td>
</tr>
<tr>
<td><a href="https://item.taobao.com/item.htm?spm=a230r.1.14.11.58a54915TdUHKS&id=556174103413&ns=1&abbucket=14#detail" target="_blank" rel="noopener">SX1278 LORA模块</a></td>
<td>SPI.h</td>
</tr>
<tr>
<td><a href="https://detail.tmall.com/item.htm?spm=a230r.1.14.20.161f53ed47xg5U&id=41414863412&ns=1&abbucket=10" target="_blank" rel="noopener">LM35DZ 温度传感</a></td>
<td><a href="https://github.com/sandeepmistry/arduino-LoRa" target="_blank" rel="noopener">LoRa.h</a></td>
</tr>
<tr>
<td><a href="https://detail.tmall.com/item.htm?spm=a1z10.3-b-s.w4011-21581912015.41.6c425535FUUqU7&id=37365775741&rn=b1c1a8a7f17260619669f001aa3241bf&abbucket=14&skuId=4138700612305" target="_blank" rel="noopener">土壤湿度传感</a></td>
<td><a href="https://github.com/IoTcat/LoRa-socket" target="_blank" rel="noopener">LoRa-Socket.h</a></td>
</tr>
<tr>
<td><a href="https://item.taobao.com/item.htm?spm=a230r.1.14.16.21461532U3rUws&id=541730394024&ns=1&abbucket=14#detail" target="_blank" rel="noopener">四分电磁阀</a></td>
<td><a href="https://github.com/IoTcat/LoRa-mqtt" target="_blank" rel="noopener">LoRa-mqtt.h</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://github.com/tomstewart89/Vector" target="_blank" rel="noopener">vector.h</a></td>
</tr>
<tr>
<td rowspan="7" style="vertical-align: middle;text-align: center;">气象站节点<br/>Air Station</td>
<td>Arduino Nano</td>
<td>Arduino.h</td>
</tr>
<tr>
<td><a href="https://item.taobao.com/item.htm?spm=a230r.1.14.11.58a54915TdUHKS&id=556174103413&ns=1&abbucket=14#detail" target="_blank" rel="noopener">SX1278 LORA模块</a></td>
<td>SPI.h</td>
</tr>
<tr>
<td><a href="https://detail.tmall.com/item.htm?spm=a220m.1000858.1000725.1.1b456f1dTRXYJd&id=576191025158&areaId=320500&user_id=738263294&cat_id=2&is_b=1&rn=14dcb16f28668aa5ca15c5be0f88d092" target="_blank" rel="noopener">BME280 温度,湿度,大气压强传感</a></td>
<td><a href="https://github.com/sandeepmistry/arduino-LoRa" target="_blank" rel="noopener">LoRa.h</a></td>
</tr>
<tr>
<td><a href="https://detail.tmall.com/item.htm?spm=a1z10.3-b-s.w4011-21581912015.32.2fe555358wswJr&id=521238059334&rn=233756c78897999fd97ca2dd4f649071&abbucket=14" target="_blank" rel="noopener">GY-30 光强传感</a></td>
<td><a href="https://github.com/IoTcat/LoRa-socket" target="_blank" rel="noopener">LoRa-Socket.h</a></td>
</tr>
<tr>
<td><a href="https://detail.tmall.com/item.htm?spm=a1z10.3-b-s.w4011-21581912015.52.23e05535hDDYEB&id=13302081252&rn=ced14f01f4a9179e7b090c544cf5836a&abbucket=14" target="_blank" rel="noopener">MQ-135 空气质量传感</a></td>
<td><a href="https://github.com/IoTcat/LoRa-mqtt" target="_blank" rel="noopener">LoRa-mqtt.h</a></td>
</tr>
<tr>
<td><a href="https://detail.tmall.com/item.htm?spm=a1z10.3-b-s.w4011-21581912015.52.270b5535itNYUg&id=13673403530&rn=418dfd01fe7ae4ce8b775fc271d9886a&abbucket=14" target="_blank" rel="noopener">MQ-7 一氧化碳传感</a></td>
<td><a href="https://github.com/tomstewart89/Vector" target="_blank" rel="noopener">vector.h</a></td>
</tr>
<tr>
<td><a href="https://detail.tmall.com/item.htm?spm=a1z10.5-b-s.w4011-21581825912.37.16ca535042HtRT&id=41536690942&rn=a0912ce05addd045044d65bc796797e8&abbucket=14" target="_blank" rel="noopener">雨量传感</a></td>
<td></td>
</tr>
<tr>
<td rowspan="8" style="vertical-align: middle;text-align: center;">LoRa 网关<br/>LoRa Gateway</td>
<td><a href="https://item.taobao.com/item.htm?spm=a230r.1.14.58.6c20435c9AhMz2&id=555750159003&ns=1&abbucket=14#detail" target="_blank" rel="noopener">SX1278</a></td>
<td>Arduino.h</td>
</tr>
<tr>
<td></td>
<td>SPI.h</td>
</tr>
<tr>
<td></td>
<td>WiFi.h</td>
</tr>
<tr>
<td></td>
<td><a href="https://github.com/sandeepmistry/arduino-LoRa" target="_blank" rel="noopener">LoRa.h</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://github.com/IoTcat/LoRa-socket" target="_blank" rel="noopener">LoRa-Socket.h</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://github.com/IoTcat/LoRa-mqtt" target="_blank" rel="noopener">LoRa-mqtt.h</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://github.com/tomstewart89/Vector" target="_blank" rel="noopener">vector.h</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://github.com/knolleary/pubsubclient" target="_blank" rel="noopener">PubSubClient.h</a></td>
</tr>
<tr>
<td rowspan="5" style="vertical-align: middle;text-align: center;">内网控制器/MQTT代理<br/>Controler/MQTT Proxy</td>
<td>树莓派3B - RASPBIAN</td>
<td>Python3.7</td>
</tr>
<tr>
<td><a href="https://detail.tmall.com/item.htm?spm=a230r.1.14.9.791b1000Beu0tp&id=555610012670&cm_id=140105335569ed55e27b&abbucket=14" target="_blank" rel="noopener">直流变频水泵</a></td>
<td>NodeJS</td>
</tr>
<tr>
<td></td>
<td><a href="https://www.npmjs.com/package/sf-mqtt-proxy" target="_blank" rel="noopener">sf-mqtt-proxy@npm</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://www.npmjs.com/package/sf-pump" target="_blank" rel="noopener">sf-pump@npm</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://www.npmjs.com/package/forever" target="_blank" rel="noopener">forever@npm</a></td>
</tr>
<tr>
<td rowspan="6" style="vertical-align: middle;text-align: center;">云服务器<br/>Cloud Server</td>
<td>华为云主机 - Centos7.4</td>
<td>Nginx/1.12.2</td>
</tr>
<tr>
<td></td>
<td>NodeJS/12.4.0</td>
</tr>
<tr>
<td></td>
<td>Redis/3.2.12</td>
</tr>
<tr>
<td></td>
<td><a href="https://www.npmjs.com/package/sf-mqtt-broker" target="_blank" rel="noopener">sf-mqtt-broker@npm</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://www.npmjs.com/package/sf-web-api" target="_blank" rel="noopener">sf-web-api@npm</a></td>
</tr>
<tr>
<td></td>
<td><a href="https://www.npmjs.com/package/forever" target="_blank" rel="noopener">forever@npm</a></td>
</tr>
<tr>
<td rowspan="1" style="vertical-align: middle;text-align: center;">数据库<br/>Database</td>
<td>华为云数据库</td>
<td>MySQL 5.7.23</td>
</tr>
</table>
!!!
<h3 id="4-2-数据规模预估"><a href="#4-2-数据规模预估" class="headerlink" title="4.2 数据规模预估"></a>4.2 数据规模预估</h3><p>按照生产场景预估,每15分钟产生一组数据集合,一组数据集合约占用253-291字节。按照291计算,每天将新增27.93KB数据。</p>
<h2 id="5-设计思路"><a href="#5-设计思路" class="headerlink" title="5 设计思路"></a>5 设计思路</h2><h3 id="5-1-理念"><a href="#5-1-理念" class="headerlink" title="5.1 理念"></a>5.1 理念</h3><ul>
<li>面向文档</li>
<li>面向接口</li>
<li>面向测试</li>
</ul>
<h3 id="5-2-关键问题"><a href="#5-2-关键问题" class="headerlink" title="5.2 关键问题"></a>5.2 关键问题</h3><ul>
<li>土地节点RAM资源稀缺,只有2K</li>
<li>LoRa通信采用433MHz,单信道收发,干扰多</li>
<li>服务器需要采集聚合来自多节点的散列数据</li>
<li>预留与无人机AI小组的交互方法</li>
<li>实时消息向前端浏览器推送</li>
</ul>
<h3 id="5-3-方案选择"><a href="#5-3-方案选择" class="headerlink" title="5.3 方案选择"></a>5.3 方案选择</h3><p>为了<strong>优先</strong>确保通信以及服务的<strong>稳定性</strong><strong>可拓展性</strong>,我们选取<strong>分层模型</strong>作为架构的设计模式。整个系统分成多个层级,层级之间具备必要的交互行为。每个层级都独立运行,崩溃时会迅速重启,具备高度的可靠性。</p>
<p>安全上,采取<strong>内外网隔离</strong>的方法。内网中考虑到部分设备计算资源稀缺,与内网服务器的交互采用不加密的通信模式。内网服务器通过SSL加密的方式与云服务器进行交互。为了确保客户端的资料安全,云服务器API只接受具备SSL加密的HTTP和WebSocket请求。</p>
<h2 id="6-架构设计"><a href="#6-架构设计" class="headerlink" title="6 架构设计"></a>6 架构设计</h2><h3 id="6-1-基础介绍"><a href="#6-1-基础介绍" class="headerlink" title="6.1 基础介绍"></a>6.1 基础介绍</h3><p>本架构的主要目的是提供一个<strong>稳定(Available)</strong><strong>可靠(Reliable)</strong>的物联网系统,通过采集农田中的实时数据,结合通过无人机采集的图片以及CNN判断的植物健康情况,实现对灌溉系统以及植物健康状况的智能管理。本架构理论上适用于大部分农场环境。测试环境半径2~5km(取决于天线)以内,风力3级以下。本系统通过传感器获取农田数据,通过晶体管电路,继电器等控制灌溉系统,通过网页与API与管理者进行交互。</p>
<h3 id="6-2-系统层级图"><a href="#6-2-系统层级图" class="headerlink" title="6.2 系统层级图"></a>6.2 系统层级图</h3><p><img src="https://api.yimian.xyz/img/?path=imgbed/img_c46f5639_577x906_8_null_normal.jpeg" alt="Smart Farm 系统分层结构图"></p>
<p>此图展示了此架构的抽象层级结构。正如其所指出的,此分层架构可明确为<strong>感知层</strong><strong>网络层</strong><strong>应用层</strong>三个横向操作层以及一个纵向<strong>错误处理层</strong></p>
<p>其中,<strong>感知层</strong>又可细化为<strong>环境层</strong>以及<strong>硬件层</strong>。环境层中包含植物,土壤,空气,水流等我们要检测和控制的自然物体,硬件层通过传感器、控制器等人造电气设备为系统对自然要素的交互行为(检测,控制)提供了底层技术可行性。当感知层实现对自然信息的交互后,相应的数字信息被传往网络层进行通信。相应的,感知层也会从网络层接受相应的控制信息,并根据这些指令做出相应的控制行为。</p>
<p><strong>网络层</strong>分为三层。其中最低一层为<strong>预处理层</strong>,它的主要任务是对感知层采集的数据进行打包处理,转变成网络流通所适合的形式,如套接字。因此,预处理层需要少量的计算存储资源,比如单片机,EEPROM等。经过预处理层的封装后,数据被传往<strong>物理层</strong>。基于物理层中的网关、路由器等设备,这些数据包得以被有秩序的分发和传递。<strong>通信层</strong>中的MQTT协议的应用,使得这些数据包分发的管理更加高效与便利。此外,通信层中QoS服务质量检测体系的实施也使得网络层的性能更加的容错和可靠。</p>
<p><strong>应用层</strong>主要负责一些应用层面的服务于业务逻辑,比如数据分析,事件处理等。在应用层的最底端,<strong>服务层</strong>在长期的运转着。服务层是应用层中最近接网络层的部分,它的主要目的是实时处理从网络层传入的数据,并对相应的请求及错误事件进行快速响应。同时,服务层也负责将传感器采集的数据进行整理分析并传递到<strong>数据库</strong>层进行存储。为了保证服务的可靠性,服务层的实现程序被注册为系统服务并由专门的守护进程进行守护。与服务层的长期运行不同,<strong>业务层</strong>则是按需唤起。当界面层有新的请求传入或服务层发生特定的事件时,业务层将会被调用并处理它们。除了一些基础的数据分析外,业务层也有权限向AI层进行分析请求。<strong>AI层</strong>通过分析从无人机传回的图像数据后,会传回一个判断结果给业务层。根据请求的具体内容,业务层会将图像识别结果,历史传感器数据等进行整理,并传递到界面层。<strong>界面层</strong>则主要用来提供不同形式的接口,比如HTTP接口和WebSocket接口,以方便客户端调用。</p>
<h3 id="6-3-系统拓扑图"><a href="#6-3-系统拓扑图" class="headerlink" title="6.3 系统拓扑图"></a>6.3 系统拓扑图</h3><p><img src="https://api.yimian.xyz/img/?path=imgbed/img_27df1756_1426x710_8_null_normal.png" alt="Smart Farm 系统拓扑图"></p>
<p>从拓扑结构来看,如上图所示,整个系统物理上可划分为土地节点,气象节点,LoRa网关,内网服务器,云服务器,数据库和用户终端。</p>
<p>从功能机制上看,整个系统包含:传感器模块,LoRa通信模块,LoRa网关模块,MQTT-Proxy代理模块,水泵控制模块,MQTT+数据处理模块,web接口模块,守护进程模块和数据库模块。</p>
<p><strong><em>土地节点</em></strong><br>土地节点部署于不同区域的农田中,用于探测土壤温度,湿度参数,并能够提供对相应位置水流电磁阀的控制。土地节点使用Arduino Nano作为计算单元,使用LoRa作为通信方式连接LoRa网关(和其它节点),使用电池供电。其数量较多,工作环境恶劣,无线通信不稳定,是系统中最大的不确定性来源。</p>
<p><strong><em>气象节点</em></strong><br>气象节点部署于农田特定位置,用于探测空气温度,湿度,大气压,降雨量,光照,NH3浓度,CO浓度等气象参数。气象节点使用Arduino Nano作为计算单元,使用LoRa作为通信方式连接LoRa网关(和土地节点),使用电池或有线供电。其工作环境较为恶劣,无线通信质量一般。</p>
<p><strong><em>LoRa网关</em></strong><br>LoRa网关部署于室内,为扩大有效通信半径,其天线可延伸至室外。LoRa网关通过LoRa连接各土地节点和气象节点,通过WiFi连接内网服务器。LoRa网关能够将通过LoRa传入的socket包转换为mqtt消息并传递给内网服务器,以及将内网服务器传来的mqtt消息转换为socket包通过LoRa发送至指定节点。</p>
<p><strong><em>内网服务器</em></strong><br>内网服务器是一个树莓派3B,它包含三个功能模块:MQTT-Proxy代理模块,水泵控制模块以及守护进程模块。</p>
<p><em>MQTT-Proxy代理模块</em>能够接收由LoRa网关通过WiFi发送的mqtt消息,对其进行SSL加密并转发至云服务器。同时,MQTT-Proxy代理模块也将接受指定的来自云服务器的mqtt消息,将其解密并转发至LoRa网关。</p>
<p><em>水泵控制模块</em>通过树莓派的GPIO通过继电器控制水泵的状态。与水泵控制模块直接与云服务器进行mqtt通信,不经过MQTT-Proxy代理。</p>
<p><em>守护进程模块</em>运行在Linux上,用于监视MQTT-Proxy代理模块和水泵控制模块。当探测到模块停止运行时,守护进程模块会及时重启这些模块,以确保服务的稳定性和连续性。</p>
<p><strong><em>云服务器</em></strong><br>云服务器运行在位于北京的华为云上,包含MQTT+数据处理模块,web接口模块和守护进程模块。</p>
<p><em>MQTT+数据处理模块</em>包含了层级结构中的Service层和Business层。这个模块通过mqtt与内网进行通信,通过mqtt, redis与web接口模块(和AI模块)进行交互。当收到来自内网的各种散列的数据后,本模块会自动对它们进行聚合,整理成一条一条的数据,存入数据库,并通过redis推送给web接口模块。此外,本模块会定时向各节点发送请求以获取它们的数据,这些请求将被追踪以计算延时。</p>
<p><em>web接口模块</em>提供一系列的HTTP和WebSocket接口。这些接口可用于获取数据,发送指令,刷新数据以及获取推送消息。</p>
<p><em>守护进程模块</em>运行在Linux上,用于监视MQTT+数据处理模块和web接口模块。当探测到模块停止运行时,守护进程模块会及时重启这些模块,以确保服务的稳定性和连续性。</p>
<h2 id="7-模块说明"><a href="#7-模块说明" class="headerlink" title="7 模块说明"></a>7 模块说明</h2><h3 id="7-1-LoRa通信模块"><a href="#7-1-LoRa通信模块" class="headerlink" title="7.1 LoRa通信模块"></a>7.1 LoRa通信模块</h3><p>LoRa通信模块用于在单信道情况下实现稳定可靠的socket通信。本模块包含LoRa-socket和LoRa-mqtt。</p>
<p>LoRa-socket是在LoRa-Arduino的基础上进行了数据包的封装,实现了简单的udp和tcp通信,让传统的LoRa通信更加可靠。通过在数据包的head添加收发ip地址,以及在数据包的最后添加hash校验值,LoRa-socket支持点对点通信和广播通信,并且具有强大的噪音处理能力和数据防篡改能力。<br><strong><em>项目地址</em></strong><a href="https://github.com/IoTcat/LoRa-socket" target="_blank" rel="noopener">iotcat/LoRa-socket</a></p>
<p>LoRa-mqtt是在LoRa-socket基础上对mqtt协议进行的一个简单再现。基于udp和tcp,LoRa-mqtt支持qos为0和1的mqtt通信。<br><strong><em>项目地址</em></strong><a href="https://github.com/IoTcat/LoRa-mqtt" target="_blank" rel="noopener">iotcat/LoRa-mqtt</a></p>
<h3 id="7-2-MQTT-Proxy代理模块"><a href="#7-2-MQTT-Proxy代理模块" class="headerlink" title="7.2 MQTT-Proxy代理模块"></a>7.2 MQTT-Proxy代理模块</h3><p>本模块运行在内网服务器,实现了对内网mqtt的加密转发。<br><strong><em>项目地址</em></strong><a href="https://www.npmjs.com/package/sf-mqtt-broker" target="_blank" rel="noopener">iotcat/sf-mqtt-proxy</a></p>
<h3 id="7-3-水泵控制模块"><a href="#7-3-水泵控制模块" class="headerlink" title="7.3 水泵控制模块"></a>7.3 水泵控制模块</h3><p>本模块运行在内网服务器,实现了通过GPIO对继电器水泵的控制。<br><strong><em>项目地址</em></strong><a href="https://www.npmjs.com/package/sf-pump" target="_blank" rel="noopener">iotcat/sf-pump</a></p>
<h3 id="7-4-mqtt-数据处理模块"><a href="#7-4-mqtt-数据处理模块" class="headerlink" title="7.4 mqtt+数据处理模块"></a>7.4 mqtt+数据处理模块</h3><p>本模块运行在云服务器,实现了对来自底层mqtt消息的数据聚合,处理和存储。<br><strong><em>项目地址</em></strong><a href="https://www.npmjs.com/package/sf-mqtt-broker" target="_blank" rel="noopener">iotcat/sf-mqtt-broker</a></p>
<h3 id="7-5-web接口模块"><a href="#7-5-web接口模块" class="headerlink" title="7.5 web接口模块"></a>7.5 web接口模块</h3><p>本模块运行在云服务器,实现了功能性接口的提供。<br><strong><em>项目地址</em></strong><a href="https://www.npmjs.com/package/sf-web-api" target="_blank" rel="noopener">iotcat/sf-web-api</a></p>
<h2 id="8-开发文档"><a href="#8-开发文档" class="headerlink" title="8 开发文档"></a>8 开发文档</h2><h3 id="8-1-mqtt主题"><a href="#8-1-mqtt主题" class="headerlink" title="8.1 mqtt主题"></a>8.1 mqtt主题</h3><ul>
<li><a href="https://doc.smartfarm.yimian.xyz/#/home?id=mqtt" target="_blank" rel="noopener">mqtt主题列表</a></li>
</ul>
<h3 id="8-2-http接口"><a href="#8-2-http接口" class="headerlink" title="8.2 http接口"></a>8.2 http接口</h3><ul>
<li><a href="https://doc.smartfarm.yimian.xyz/#/home?id=api-http" target="_blank" rel="noopener">http接口文档</a></li>
</ul>
<h3 id="8-3-websocket接口"><a href="#8-3-websocket接口" class="headerlink" title="8.3 websocket接口"></a>8.3 websocket接口</h3><ul>
<li><a href="https://doc.smartfarm.yimian.xyz/#/home?id=api-websocket" target="_blank" rel="noopener">websocket接口文档</a></li>
</ul>
<h2 id="9-运行状态"><a href="#9-运行状态" class="headerlink" title="9 运行状态"></a>9 运行状态</h2><h3 id="9-1-系统延时"><a href="#9-1-系统延时" class="headerlink" title="9.1 系统延时"></a>9.1 系统延时</h3><p><img src="https://api.yimian.xyz/img/?path=imgbed/img_b36d5030_1806x546_8_null_normal.png" alt="qos"></p>
<p>上图展示了土地节点(左),气象节点(右),水泵(下)的延时统计折线图。由图可以看出,土地节点的平均延时在730ms左右,气象节点延时在900ms左右,水泵的延时较低,在45ms左右。</p>
<h3 id="9-2-传感器数据"><a href="#9-2-传感器数据" class="headerlink" title="9.2 传感器数据"></a>9.2 传感器数据</h3><p><a href="https://smartfarm.yimian.xyz/chart-station.html?f=1564484461&t=1564570861" target="_blank" rel="noopener">点击这里查看2019-7-31的气象传感器数据</a></p>
<br>
-------------------------------
**Reference List:**
<p>[1] OASIS, (2015,12.10). MQTT Version 3.1.1 Plus Errata 01 [Online]. Available: <a href="https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html" target="_blank" rel="noopener">https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html</a></p>
<p>[2] Sinha, R.S., Wei, Y. and Hwang, S.H., “A survey on LPWA technology: LoRa and NB-IoT”, in Ict Express, 3(1), pp.14-21, 2017.</p>
</div>
<div class="post-copyright">
<p class="copyright-item">
<span>Author: </span>
<a href="https://iotcat.me/" target="_blank" rel="noopener">IoTcat</a>
</p>
<p class="copyright-item">
<span>Link: </span>
<a href="https://www.eee.dog/tech/smartfarming-surf.html">https://www.eee.dog/tech/smartfarming-surf.html</a>
</p>
<p class="copyright-item">
<span>License: </span><a rel="license" href="http://creativecommons.org/licenses/by-nc/4.0/" target="_blank">知识共享署名-非商业性使用 4.0 国际许可协议</a>
</p>
</div>
<footer class="post-footer">
<div class="post-tags">
<a href="/tags/Arduino/">Arduino</a>
<a href="/tags/iot/">iot</a>
<a href="/tags/LoRa/">LoRa</a>
<a href="/tags/MQTT/">MQTT</a>
<a href="/tags/smart-farming/">smart-farming</a>
</div>
<nav class="post-nav"><a class="prev" href="/tech/smart-home.html">
<i class="iconfont icon-left"></i>
<span class="prev-text nav-default">在家中部署智慧家庭系统</span>
<span class="prev-text nav-mobile">Prev</span>
</a>
<a class="next" href="/tech/arduino-operator-string-issue.html">
<span class="next-text nav-default">Arduino中[]=重载导致的String调用问题</span>
<span class="prev-text nav-mobile">Next</span>
<i class="iconfont icon-right"></i>
</a>
</nav></footer>
</article><script>$(()=>{setTimeout(()=>{iziToast.show({
title: 'tips',
position: 'topRight',
message: "此文章预计阅读 25 分钟哦~"
})}, 3000)})</script>
</div><div class="comments" id="comments"><div id="vcomments"></div>
</div></div>
</main>
<footer id="footer" class="footer">
<script>
page_obj = {
layout: "post",
comments: "true"
};
</script><div class="social-links"><a href="mailto:i@iotcat.me" class="iconfont icon-email" title="email"></a>
<a href="https://github.com/iotcat" target="_blank" rel="noopener" class="iconfont icon-github" title="github"></a>
<a href="/atom.xml" class="iconfont icon-rss" title="rss"></a>
</div><div class="copyright"><span id="/tech/smartfarming-surf.html" class="statistic leancloud_visitors">
<em>Visitors </em> <i class="leancloud-visitors-count">??</i>
<span class="division"> |</span>
<em>Reading </em> 25 min
</span>
<br>
<span class="power-by">
Powered by <a class="hexo-link" href="https://hexo.io/" target="_blank" rel="noopener">Hexo</a>
</span>
<span class="division">|</span>
<span class="theme-info">
Theme -
<a class="theme-link" href="https://github.com/iotcat/kayo" target="_blank" rel="noopener">Kayo</a>
</span>
<span class="copyright-year">&copy;2018 - 2020<span class="heart shaky">
<i class="iconfont icon-heart"></i>
</span>
<span class="author">IoTcat</span>
</span>
</div>
</footer>
<div class="back-to-top" id="back-to-top">
<i class="iconfont icon-up"></i>
</div>
</div>
<script src="https://cdn.yimian.xyz/kayo/lib/valine/valine.min.js" data-pjax></script>
<style>
/* 背景图片 */
#veditor {
background-image: url(https://cdn.jsdelivr.net/gh/drew233/cdn/20200409110727.webp);
background-size: contain;
background-repeat: no-repeat;
background-position: right;
background-color: rgba(255, 255, 255, 0);
resize: vertical
}
/* 头像旋转 */
img.vimg {
transition: all 1s /* 旋转时间为 1s */
}
img.vimg:hover {
transform: rotate(360deg);
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-o-transform: rotate(360deg);
-ms-transform: rotate(360deg);
}
/* 盒子模式 */
#vcomments .vcards .vcard {
padding: 15px 20px 0 20px;
border-radius: 10px;
margin-bottom: 15px;
box-shadow: 0 0 4px 1px rgba(0, 0, 0, .12);
transition: all .3s
}
#vcomments .vcards .vcard:hover {
box-shadow: 0 0 8px 3px rgba(0, 0, 0, .12)
}
#vcomments .vcards .vcard .vh .vcard {
border: none;
box-shadow: none;
}
</style>
<script>
pjax_valine = () => {
new Valine({
el: '#vcomments',
appId: 'eVzpK7EyT6OafJvXWIRminWT-gzGzoHsz',
appKey: '2qjuEBgVE0BscTQnTmoS9roU',
master: '9b616ff4cd6c305e5970bee7b1bd9b1f', //博主邮箱md5
tagMeta: ["博主","小伙伴","访客"], //标识字段名
friends: ["b6ddef7c7e1c647e7767afeacdfb7b64","46dd4e6fef4f9591736c4723a965ca2e","6132d77f9f0ae060bc733090991acecb","3e00e104b79d7c6e866c6b23c6ba6dfc"], //小伙伴邮箱Md5
metaPlaceholder: {"nick":"昵称/QQ号","mail":"邮箱(完全保密)"},
placeholder: "填写邮箱可以及时收到回复哦(●'◡'●)",
path: window.location.pathname,
enableQQ: true,
visitor: true,
emojiCDN: '//i0.hdslb.com/bfs/emote/',
emojiMaps: {
"tv_doge": "6ea59c827c414b4a2955fe79e0f6fd3dcd515e24.png",
"tv_亲亲": "a8111ad55953ef5e3be3327ef94eb4a39d535d06.png",
"tv_偷笑": "bb690d4107620f1c15cff29509db529a73aee261.png",
"tv_再见": "180129b8ea851044ce71caf55cc8ce44bd4a4fc8.png",
"tv_冷漠": "b9cbc755c2b3ee43be07ca13de84e5b699a3f101.png",
"tv_发怒": "34ba3cd204d5b05fec70ce08fa9fa0dd612409ff.png",
"tv_发财": "34db290afd2963723c6eb3c4560667db7253a21a.png",
"tv_可爱": "9e55fd9b500ac4b96613539f1ce2f9499e314ed9.png",
"tv_吐血": "09dd16a7aa59b77baa1155d47484409624470c77.png",
"tv_呆": "fe1179ebaa191569b0d31cecafe7a2cd1c951c9d.png",
"tv_呕吐": "9f996894a39e282ccf5e66856af49483f81870f3.png",
"tv_困": "241ee304e44c0af029adceb294399391e4737ef2.png",
"tv_坏笑": "1f0b87f731a671079842116e0991c91c2c88645a.png",
"tv_大佬": "093c1e2c490161aca397afc45573c877cdead616.png",
"tv_大哭": "23269aeb35f99daee28dda129676f6e9ea87934f.png",
"tv_委屈": "d04dba7b5465779e9755d2ab6f0a897b9b33bb77.png",
"tv_害羞": "a37683fb5642fa3ddfc7f4e5525fd13e42a2bdb1.png",
"tv_尴尬": "7cfa62dafc59798a3d3fb262d421eeeff166cfa4.png",
"tv_微笑": "70dc5c7b56f93eb61bddba11e28fb1d18fddcd4c.png",
"tv_思考": "90cf159733e558137ed20aa04d09964436f618a1.png",
"tv_惊吓": "0d15c7e2ee58e935adc6a7193ee042388adc22af.png",
"tv_打脸": "56ab10b624063e966bfcb76ea5dc4794d87dfd47.png",
"tv_抓狂": "fe31c08edad661d63762b04e17b8d5ae3c71a757.png",
"tv_抠鼻": "c666f55e88d471e51bbd9fab9bb308110824a6eb.png",
"tv_斜眼笑": "911f987aa8bc1bee12d52aafe62bc41ef4474e6c.png",
"tv_无奈": "ea8ed89ee9878f2fece2dda0ea8a5dbfe21b5751.png",
"tv_晕": "5443c22b4d07fb1907ccc610c8e6db254f2461b7.png",
"tv_流汗": "cead1c351ab8d79e9f369605beb90148db0fbed3.png",
"tv_流泪": "7e71cde7858f0cd50d74b0264aa26db612a8a167.png",
"tv_流鼻血": "c32d39db2737f89b904ca32700d140a9241b0767.png",
"tv_点赞": "f85c354995bd99e28fc76c869bfe42ba6438eff4.png",
"tv_生气": "26702dcafdab5e8225b43ffd23c94ac1ff932654.png",
"tv_生病": "8b0ec90e6b86771092a498c54f09fc94621c1900.png",
"tv_疑问": "0793d949b18d7be716078349c202c15ff166f314.png",
"tv_白眼": "c1d59f439e379ee50eef488bcb5e5378e5044ea4.png",
"tv_皱眉": "72ccad6679fea0d14cce648b4d818e09b8ffea2d.png",
"tv_目瞪口呆": "0b8cb81a68de5d5365212c99375e7ace3e7891b7.png",
"tv_睡着": "8b196675b53af58264f383c50ad0945048290b33.png",
"tv_笑哭": "1abc628f6d4f4caf9d0e7800878f4697abbc8273.png",
"tv_腼腆": "89712c0d4af73e67f89e35cbc518420380a7f6f4.png",
"tv_色": "61822c7e9aae5da76475e7892534545336b23a6f.png",
"tv_调侃": "4bc022533ef31544ca0d72c12c808cf4a1cce3e3.png",
"tv_调皮": "b9c41de8e82dd7a8515ae5e3cb63e898bf245186.png",
"tv_鄙视": "6e72339f346a692a495b123174b49e4e8e781303.png",
"tv_闭嘴": "c9e990da7f6e93975e25fd8b70e2e290aa4086ef.png",
"tv_难过": "87f46748d3f142ebc6586ff58860d0e2fc8263ba.png",
"tv_馋": "fc7e829b845c43c623c8b490ee3602b7f0e76a31.png",
"tv_鬼脸": "0ffbbddf8a94d124ca2f54b360bbc04feb6bbfea.png",
"tv_黑人问号": "45821a01f51bc867da9edbaa2e070410819a95b2.png",
"tv_鼓掌": "1d21793f96ef4e6f48b23e53e3b9e42da833a0f6.png"
// ... 更多表情
}
});
};
</script><script type="text/javascript" src="https://cdn.yimian.xyz/ushio-js/ushio-footer.min.js"></script>
<script>
session.onload(function(){
if(session.get('group') != 'anonymous'){
function insertNick(){
if($('.vnick').length){
$('.vnick').val(session.get('nickname'));
}else{
setTimeout(insertNick, 500);
}
}
function insertMail(){
if($('.vmail').length){
$('.vmail').val(session.get('email'));
}else{
setTimeout(insertMail, 500);
}
}
if(session.get('nickname')){
insertNick();
}
if(session.get('email')){
insertMail();
}
}
});
</script>
<script type="text/javascript" src="https://cdn.yimian.xyz/kayo/lib/slideout/slideout.js"></script>
<script type="text/javascript" src="https://cdn.yimian.xyz/kayo/lib/fancybox/jquery.fancybox.pack.js"></script>
<script type="text/javascript" src="https://cdn.yimian.xyz/kayo/lib/iziToast/iziToast.min.js"></script>
<script type="text/javascript" src="https://cdn.yimian.xyz/kayo/lib/iziModal/iziModal.min.js"></script>
<script type="text/javascript" src="https://cdn.yimian.xyz/kayo/lib/mermaid/mermaid.min.js"></script>
<script type="text/javascript" src="https://cdn.yimian.xyz/kayo/js/src/kayo.js?v=1.0.0" data-pjax></script>
<script type="text/javascript" src="https://cdn.yimian.xyz/kayo/js/src/kayo-no-pjax.js?v=1.0.0"></script>
<script src="https://cdn.yimian.xyz/kayo/lib/pjax/pjax.min.js"></script>
<script>window.pjax = new Pjax({
elements: 'a[href]:not([href^="#"]):not([href="javascript:void(0)"])',
selectors: ["head title, #main", "#footer"],
});/* 第一次载入页面加载的函数 */
pjax_ini = () => {
/* 关闭侧边栏 */
window.slideout.close();
if(page_obj.comments == "true"){pjax_valine();}pjax_google_analytics();mermaid.init(undefined, $(".mermaid"));};
/* 第一次 执行 */
pjax_ini();var loadingBar = document.querySelector(".loading-bar");
var progress = document.querySelector(".loading-bar .progress");
var timer = null;
// Pjax 开始时执行的函数
var loadingbarStart = function () {
// 进度条默认已经加载 20%
var loadingBarWidth = 20;
// 进度条的最大增加宽度
var MAX_LOADING_WIDTH = 95;
// 显示进度条
loadingBar.classList.add("loading");
// 初始化进度条的宽度
progress.style.width = loadingBarWidth + "%";
clearInterval(timer);
timer = setInterval(function () {
// 进度条的增加速度(可以改为一个随机值,显得更加真实)
loadingBarWidth += 3;
// 当进度条到达 95% 后停止增加
if (loadingBarWidth > MAX_LOADING_WIDTH) {
loadingBarWidth = MAX_LOADING_WIDTH;
}
progress.style.width = loadingBarWidth + "%";
}, 500);
};
// Pjax 完成之后执行的函数
var loadingbarStop = function () {
clearInterval(timer);
progress.style.width = "100%";
loadingBar.classList.remove("loading");
setTimeout(function () {
progress.style.width = 0;
}, 400);
};/* Pjax 开始时,重新加载的函数 */
document.addEventListener("pjax:send", function () {loadingbarStart();
});
/* Pjax 完成后,重新加载的函数 */
document.addEventListener("pjax:complete", function () {
/* 重载带data-pjax的script,或者.pjax-reload属性内容的script */
$("script[data-pjax], .pjax-reload script").each(function () {
$(this).parent().append($(this).remove());
});
pjax_ini();loadingbarStop();
});
/* Pjax 出错,执行的函数 */
document.addEventListener("pjax:error", function () {
});</script>
</body>
</html>