<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Shifu | Kubernetes native, open-source IoT development framework Blog</title>
        <link>https://shifu.dev/zh-Hans/technical-blogs</link>
        <description>Shifu | Kubernetes native, open-source IoT development framework Blog</description>
        <lastBuildDate>Tue, 18 Oct 2022 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-Hans</language>
        <item>
            <title><![CDATA[Shifu Cloud 初面演示]]></title>
            <link>https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud</link>
            <guid>https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud</guid>
            <pubDate>Tue, 18 Oct 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[在 2022.10.18，Shifu Cloud 正式公测，Shifu 的用户可以方便的通过可视化的方式选择需要接入的设备，即可快速完成设备接入 Shifu 的流程。]]></description>
            <content:encoded><![CDATA[<p>在 2022.10.18，<a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a> 正式公测，<em><strong>Shifu</strong></em> 的用户可以方便的通过可视化的方式选择需要接入的设备，即可快速完成设备接入 <em><strong>Shifu</strong></em> 的流程。</p>
<p>在这一天的线上直播展示中，来自边无际的杨希杰演示使用 <a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a> 接入三个实际的设备，并在其基础上进行应用开发。下面让我们一起来回顾这一过程吧——</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="创建集群-安装shifu">创建集群 安装shifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud#%E5%88%9B%E5%BB%BA%E9%9B%86%E7%BE%A4-%E5%AE%89%E8%A3%85shifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>在使用 <a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a> 前，我们需要先确保已有一台安装了 <em><strong>Shifu</strong></em> 的电脑。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 在本地使用kind启动k8s集群</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind create cluster --image="kindest/node:v1.24.0"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 克隆shifu仓库并进行安装</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ git clone https://github.com/Edgenesis/shifu.git</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ cd shifu</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl apply -f pkg/k8s/crd/install/shifu_install.yml</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-221018/00.png" width="100%">
<img src="https://shifu.dev/blog-221018/01.png" width="100%">
<p>如果你还不了解 <em><strong>Shifu</strong></em> 的安装和本地测试的方式，你可能需要查阅 <a href="https://shifu.dev/zh-Hans/docs/tutorials/demo-install" target="_blank" rel="noopener noreferrer" class="">下载安装</a> 和 <a href="https://shifu.dev/zh-Hans/docs/guides/install-shifu-dev" target="_blank" rel="noopener noreferrer" class="">本机安装测试</a> 这两篇文档。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="本机连接温湿度计和led">本机连接温湿度计和LED<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud#%E6%9C%AC%E6%9C%BA%E8%BF%9E%E6%8E%A5%E6%B8%A9%E6%B9%BF%E5%BA%A6%E8%AE%A1%E5%92%8Cled" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<img src="https://shifu.dev/blog-221018/02.png" width="60%">
<p>我们要连接的设备为一个RS485的温湿度计和一个RS485的LED显示屏。温湿度计通过串口服务器连接至上位机（电脑），LED显示屏则通过RS485转USB的芯片连接至上位机。具体细节不做展开，在上位机开启HTTP服务之后：</p>
<ul>
<li class="">访问<code>localhost:23330/temperature</code>即可得到温湿度计的温度</li>
<li class="">访问<code>localhost:23330/humidity</code>即可得到温湿度计的湿度</li>
<li class="">访问<code>localhost:23331/setfloat\?value=123.4</code>value填入需要显示的数字即可在LED上显示</li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">curl localhost:23330/temperature</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">curl localhost:23330/humidity</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">curl localhost:23331/setfloat\?value=123.4</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-221018/03.png" width="100%">
<p>接下来我们要将这两个设备接入 <em><strong>Shifu</strong></em>，也即将两个实际的设备（<em><strong>edgeDevice</strong></em>s）转为k8s集群中的数字孪生（<em><strong>deviceShifu</strong></em>s）。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="一键生成配置文件">一键生成配置文件<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud#%E4%B8%80%E9%94%AE%E7%94%9F%E6%88%90%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6" class="hash-link" aria-label="标题的直接��链接" title="标题的直接链接" translate="no">​</a></h2>
<p><a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a>可以轻松生成 <em><strong>deviceShifu</strong></em> 的配置文件。</p>
<p>登录之后点击所有项目，即可添加设备。对于上面的两个设备，采用的都是HTTP协议，所以选择「公有协议 &gt; HTTP」。「基础信息 &gt; 设备名称」中分别填入<code>my_thermometer</code>和<code>my_led</code>。设备的IP地址不能填写<code>localhost</code>，而是需要在电脑的网络设置中找到本机IP：如演示时使用的是<code>192.168.0.123:23330</code>和<code>192.168.0.123:23331</code>。</p>
<img src="https://shifu.dev/blog-221018/04-1.png" width="50%">
<img src="https://shifu.dev/blog-221018/04-2.png" width="50%">
<img src="https://shifu.dev/blog-221018/04-3.png" width="50%">
<img src="https://shifu.dev/blog-221018/04-4.png" width="50%">
<p>信息填写完毕后，网站会弹出一条命令，点击右侧按钮复制到终端执行，即可将设备部署到本机的k8s集群。这省去了手动编写YAML配置文件的时间，也更加直观。</p>
<img src="https://shifu.dev/blog-221018/04-5.png" width="70%">
<img src="https://shifu.dev/blog-221018/04-6.png" width="70%">
<img src="https://shifu.dev/blog-221018/04-7.png" width="100%">
<img src="https://shifu.dev/blog-221018/04-8.png" width="70%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="测试设备正常接入">测试设备正常接入<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud#%E6%B5%8B%E8%AF%95%E8%AE%BE%E5%A4%87%E6%AD%A3%E5%B8%B8%E6%8E%A5%E5%85%A5" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>我们进入到集群中查看是否可以使用集群内的网络地址访问到两个设备的数字孪生：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 运行一个nginx容器</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl run --image=nginx:1.21 nginx</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 进入nginx容器</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl exec -it nginx -- bash</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 与设备进行交互</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://deviceshifu-mythermometer-service.deviceshifu.svc.cluster.local/humidity</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://deviceshifu-mythermometer-service.deviceshifu.svc.cluster.local/temperature</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://deviceshifu-myled-service.deviceshifu.svc.cluster.local/setfloat?value=321</span><br></span></code></pre></div></div>
<p>可以看到温湿度计的读数与LED的示数设置都没有问题，这说明设备已成功接入转为数字孪生。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="打包应用镜像">打包应用镜像<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud#%E6%89%93%E5%8C%85%E5%BA%94%E7%94%A8%E9%95%9C%E5%83%8F" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>我们希望在有温湿度计和LED的基础上进行应用开发，因此我们写出如下的Python程序：</p>
<p><code>main.py</code></p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> time</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> requests</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> json</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">isLocal </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">localIp </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"192.168.0.123"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">flag </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">while</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">True</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    flag </span><span class="token operator" style="color:rgb(137, 221, 255)">+=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># [拿到数据]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> flag </span><span class="token operator" style="color:rgb(137, 221, 255)">%</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># 拿到温度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"http://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">localIp</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">:23330/temperature"</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> isLocal </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"http://deviceshifu-mythermometer-service.deviceshifu.svc.cluster.local/temperature"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># 拿到湿度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"http://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">localIp</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">:23330/humidity"</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> isLocal </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"http://deviceshifu-mythermometer-service.deviceshifu.svc.cluster.local/humidity"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    res </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> requests</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># [转换数据]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        value </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">loads</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'value'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"DEBUG"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># [显示数据]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        led_url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"http://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">localIp</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">:23331/setfloat?value=</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">value</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> isLocal </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"http://deviceshifu-myled-service.deviceshifu.svc.cluster.local/setfloat?value=</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">value</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        requests</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">led_url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">except</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"DEBUG"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>该程序每2秒交替读取温湿度计的温度和湿度，并将读到的数据显示到LED上。</p>
<p>接下来我们希望将这个程序打包为一个镜像，之后就可以导入集群运行了：</p>
<p><code>requirements.txt</code></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">requests</span><br></span></code></pre></div></div>
<p><code>Dockerfile</code></p>
<div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">FROM python:3.9-slim-bullseye</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY requirements.txt .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">RUN pip install --no-cache-dir -r requirements.txt</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY main.py .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">CMD ["python3", "main.py"]</span><br></span></code></pre></div></div>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 构建镜像</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker build -t xxx/connection:v0.0.1 .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 确认镜像已构建</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker images | grep connection</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">xxx/connection  v0.0.1  a9526147ddad  2 minutes ago  125MB</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 将镜像载入集群</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind load docker-image xxx/connection:v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 将镜像实例化为容器运行</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl run --image=xxx/connection:v0.0.1 connection-name</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-221018/05.png" width="60%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="接入摄像头">接入摄像头<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud#%E6%8E%A5%E5%85%A5%E6%91%84%E5%83%8F%E5%A4%B4" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>接下来我们希望接入海康威视摄像头进行监控的操控。该摄像头并没有在笔者的手边，而是通过Wi-Fi的方式无线连接。</p>
<p>可以看到 <a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a> 支持了海康威视这个模块，点击后配置摄像头ip地址、用户名和密码即可一键接入。演示中的设备名称为 <code>mycamera</code>。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 进入nginx容器</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl exec -it nginx -- bash</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 查看摄像头信息</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://deviceshifu-mycamera-service.deviceshifu.svc.cluster.local/info</span><br></span></code></pre></div></div>
<p>这说明海康威视的摄像头已经接入了 <em><strong>Shifu</strong></em> 并转为了一个数字孪生。</p>
<img src="https://shifu.dev/blog-221018/06-0.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="控制摄像头位置">控制摄像头位置<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud#%E6%8E%A7%E5%88%B6%E6%91%84%E5%83%8F%E5%A4%B4%E4%BD%8D%E7%BD%AE" class="hash-link" aria-label="标题的直接链接" title="标题的��直接链接" translate="no">​</a></h2>
<p>紧接着，我们希望调整摄像头的拍摄位置，使用<code>move/up</code> <code>move/down</code> <code>move/left</code> <code>move/right</code>这样的API即可控制摄像头的朝向：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://deviceshifu-mycamera-service.deviceshifu.svc.cluster.local/move/up</span><br></span></code></pre></div></div>
<p>为了查看效果，我们在电脑开启视频播放器，打开该串流地址：<code>rtsp://&lt;user_name&gt;:&lt;password&gt;@&lt;ip_address&gt;</code>。在 <code>macOS</code> 中，我们可以打开 <code>IINA.app</code>，菜单栏 &gt; Open Url... &gt; paste and enter，即可打开实时的监控视频码流。</p>
<p>可以看到，摄像头的位置确实发生了变化，我们成功的将实际摄像头的位置调整到了需要查看的朝向（右上角的相机从朝向天花板到朝向桌面上的显示器背侧）。</p>
<img src="https://shifu.dev/blog-221018/06-1.png" width="100%">
<img src="https://shifu.dev/blog-221018/06-2.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/10/18/shifu-cloud#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>在此次展示中，我们使用 <a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a> 接入了三个设备，如果您与Meetup线下接入做对比，您会发现接入速度和门槛明显降低。</p>
<p><a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a> 还加入了啊哈时刻，在您初步熟悉整个网站的过程中提供帮助。</p>
<img src="https://shifu.dev/blog-221018/07-1.png" width="100%">
<img src="https://shifu.dev/blog-221018/07-2.png" width="100%">
<p>此外，<a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a> 还在不断发展，后续将逐渐支持：</p>
<ul>
<li class="">更多的协议支持（边无际与开源社区都会不断增加支持的协议，提高快速接入的覆盖率）</li>
<li class="">应用开发的支持（此次我们开发应用还是在本地进行应用打包，但是之后我们也可以直接在 <a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">shifu.cloud</a> 进行便捷的应用开发）</li>
<li class="">应用商店支持（其中包含开发者上传的自己开发的应用或者第三方插件，使用者可以一键安装）</li>
</ul>
<p>感谢您看到这里，让我们一起期待 <a href="https://shifu.cloud/" target="_blank" rel="noopener noreferrer" class="">Shifu Cloud</a> 的未来吧！</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Meetup技术回顾]]></title>
            <link>https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup</link>
            <guid>https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup</guid>
            <pubDate>Fri, 30 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[在 2022.9.29 举办的线下 Shifu Meetup 活动中，来自边无际的杨希杰在现场展示用 Shifu 接入多个实际物联网设备，通过这种直观的接入方式展示了 Shifu 框架接入设备迅速、无单点故障、隔离性好、应用开发便捷等优点。]]></description>
            <content:encoded><![CDATA[<p>在 2022.9.29 举办的线下 <code>Shifu Meetup</code> 活动中，来自边无际的杨希杰在现场展示用 <em><strong>Shifu</strong></em> 接入多个实际物联网设备，通过这种直观的接入方式展示了 <em><strong>Shifu</strong></em> 框架接入设备迅速、无单点故障、隔离性好、应用开发便捷等优点。</p>
<p>这次活动总共接入了五个设备，分别是 MQTT服务器、RS485的温湿度计 和 RS485的LED、西门子 S7 PLC、海康威视摄像头——这些都是比较常见的物联网设备。下面来让我们回忆一下接入过程吧。</p>
<img src="https://shifu.dev/blog-220930/device-camera-thermometer.png" width="48%">
<img src="https://shifu.dev/blog-220930/device-plc.png" width="50%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="创建集群并安装shifu">创建集群并安装Shifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E5%88%9B%E5%BB%BA%E9%9B%86%E7%BE%A4%E5%B9%B6%E5%AE%89%E8%A3%85shifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>首先我们需要在本地开启 <code>Docker</code>。使用 <code>Windows</code> 或 <code>macOS</code> 的搜索打开 <code>Docker Desktop</code>，最小化到后台即可。</p>
<img src="https://shifu.dev/blog-220930/docker-start.png" width="80%">
<p>之后我们需要用 <code>kind</code> 创建一个k8s集群。后续 <em><strong>Shifu</strong></em> 和物联网设备的数字孪生都会以 <code>Pod</code> 的形式存在于这个集群中：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 创建集群</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind create cluster --image="kindest/node:v1.24.0"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 提前准备镜像导入集群</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull bitnami/kube-rbac-proxy:0.13.1 </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull edgehub/shifu-controller:v0.1.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull nginx:1.21</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind load docker-image bitnami/kube-rbac-proxy:0.13.1 edgehub/shifu-controller:v0.1.1 nginx:1.21</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220930/kind-create-cluster.png" width="60%">
<p><em><strong>Shifu</strong></em> 支持一键安装，只需要先克隆<a href="https://github.com/Edgenesis/shifu" target="_blank" rel="noopener noreferrer" class=""><em><strong>Shifu</strong></em>仓库</a>，之后用一条命令部署即可：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 安装shifu</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ git clone https://github.com/Edgenesis/shifu.git</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ cd shifu</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl apply -f pkg/k8s/crd/install/shifu_install.yml</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 跑一个应用程序 之后会用到</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl run --image=nginx:1.21 nginx</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220930/shifu-install.png" width="60%">
<p>您也可以查看<a href="https://shifu.dev/docs/guides/install-shifu-dev" target="_blank" rel="noopener noreferrer" class="">更详细的本地安装Shifu教程</a>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="设备接入">设备接入<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="mqtt">MQTT<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#mqtt" class="hash-link" aria-label="标题的��直接链接" title="标题的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="测试mqtt服务器">测试MQTT服务器<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%B5%8B%E8%AF%95mqtt%E6%9C%8D%E5%8A%A1%E5%99%A8" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>我们已经部署了一个MQTT服务器，可以先打开两个shell进行测试：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># shellA</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ mosquitto_sub -h 82.157.170.202 -t topic0</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># shellB</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ mosquitto_pub -h 82.157.170.202 -t topic0 -m "哈哈哈"</span><br></span></code></pre></div></div>
<p>可以看到发送的信息可以被正确接收。</p>
<img src="https://shifu.dev/blog-220930/mqtt-test.png" width="80%">
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="接入设备">接入设备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%8E%A5%E5%85%A5%E8%AE%BE%E5%A4%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>接下来我们可以先修改对应的配置，下载对应的镜像，然后用 <code>kubectl apply</code> 命令一键将MQTT服务器作为一个数字孪生接入 <em><strong>Shifu</strong></em>。</p>
<p>修改<code>examples/my_mqtt/mqtt_deploy</code>中的<code>spec.address</code>为<code>82.157.170.202:1883</code>，<code>spec.protocolSettings.MQTTSetting.MQTTTopic</code>为<code>topic0</code>。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull edgehub/deviceshifu-http-mqtt:v0.1.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind load docker-image edgehub/deviceshifu-http-mqtt:v0.1.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl apply -f examples/my_mqtt/mqtt_deploy</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220930/mqtt-apply.png" width="60%">
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="读取数据">读取数据<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E8%AF%BB%E5%8F%96%E6%95%B0%E6%8D%AE" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>我们可以通过在集群中启动一个 <code>nginx</code> 应用来与数字孪生交互。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl exec -it nginx -- bash</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://deviceshifu-mqtt.deviceshifu.svc.cluster.local/mqtt_data</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220930/mqtt-result.png" width="60%">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="连接温度计和led">连接温度计和LED<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E8%BF%9E%E6%8E%A5%E6%B8%A9%E5%BA%A6%E8%AE%A1%E5%92%8Cled" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="连接设备至电脑">连接设备至电脑<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E8%BF%9E%E6%8E%A5%E8%AE%BE%E5%A4%87%E8%87%B3%E7%94%B5%E8%84%91" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<ul>
<li class="">温度计使用串口服务器通过网线连接至电脑</li>
<li class="">LED使用RS485转USB的芯片连接至电脑</li>
</ul>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="本地启动http服务">本地启动HTTP服务<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%9C%AC%E5%9C%B0%E5%90%AF%E5%8A%A8http%E6%9C%8D%E5%8A%A1" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>因为目前 <em><strong>Shifu</strong></em> 还不支持 <code>Modbus</code>协议，所以我们需要将<code>Modbus</code>读取的数据转为HTTP数据。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ cd api_thermometer</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ uvicorn --host 0.0.0.0 --port 23330 main:app</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ cd api_led</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ uvicorn --host 0.0.0.0 --port 23331 main:app</span><br></span></code></pre></div></div>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="api_thermometer文件夹内容">api_thermometer文件夹内容<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#api_thermometer%E6%96%87%E4%BB%B6%E5%A4%B9%E5%86%85%E5%AE%B9" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h5>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> main.py </summary><div><div class="collapsibleContent_i85q"><div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> fastapi </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> FastAPI</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> typing </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> List</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> pymodbus</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sync </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> ModbusTcpClient</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">app </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> FastAPI</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getHumidityAndTemperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> List</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token builtin" style="color:rgb(130, 170, 255)">float</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">    返回从TAS-LAN-460得到的温度和湿度</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">    """</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> ModbusTcpClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">host</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'192.168.0.80'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> port</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">10123</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># TAS-LAN-460的端口</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    SLAVE </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x01</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    r </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">read_holding_registers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">0x0000</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> count</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unit</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">SLAVE</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"自己拿到的数据"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> r</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">registers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    result </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">r</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">registers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> r</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">registers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">/</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> result</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">@app</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">root</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"message"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Hello World"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">@app</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/temperature"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getTemperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    temperature </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> getHumidityAndTemperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"value"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">temperature</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">@app</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/humidity"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">getHumidity</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    humidity </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> getHumidityAndTemperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"value"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">humidity</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre></div></div></div></div></details>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> requirements.txt </summary><div><div class="collapsibleContent_i85q"><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">fastapi</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">pymodbus</span><br></span></code></pre></div></div></div></div></details>
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="api_led文件夹内容">api_led文件夹内容<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#api_led%E6%96%87%E4%BB%B6%E5%A4%B9%E5%86%85%E5%AE%B9" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h5>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> main.py </summary><div><div class="collapsibleContent_i85q"><div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> fastapi </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> FastAPI</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> pymodbus</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sync </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> ModbusSerialClient</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">from</span><span class="token plain"> typing </span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> List</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> Dict</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">app </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> FastAPI</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">ZhongshengLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">    DEVICE_NAME = "中盛数码管显示屏"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">    """</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">__init__</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> device_address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x01</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> port</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">str</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">'/dev/tty.usbserial-14120'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token operator" style="color:rgb(137, 221, 255)">&gt;</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">device_address </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> device_address</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> ModbusSerialClient</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">method</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'rtu'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> port</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">port</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain">  stopbits</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> bytesize</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">8</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> parity</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">'N'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> baudrate</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">9600</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> timeout</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">2.0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setLedCharacter</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> position</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> character</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">str</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setLedAscii</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">position</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">position</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ascii_value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ZhongshengLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">character2ascii</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">character</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setLedAscii</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> position</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ascii_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">write_register</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">position</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ascii_value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unit</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">device_address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setFourLedsString</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">str</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setFourLedsAsciis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">ascii_values</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">ZhongshengLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">character2ascii</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ZhongshengLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">character2ascii</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ZhongshengLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">character2ascii</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ZhongshengLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">character2ascii</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token plain">string</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token number" style="color:rgb(247, 140, 108)">3</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setFourLedsAsciis</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> ascii_values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> List</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">write_registers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ZhongshengLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">LedPosition</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">one</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> values</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">ascii_values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unit</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">device_address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(255, 203, 107)">LedPosition</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        one </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        two </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        three </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        four </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">3</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    character2ascii</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Dict</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token builtin" style="color:rgb(130, 170, 255)">str</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"0"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x30</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"1"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x31</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"2"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x32</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"3"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x33</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"4"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x34</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"5"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x35</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"6"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x36</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"7"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x37</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"8"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x38</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"9"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x39</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token string" style="color:rgb(195, 232, 141)">"."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x2e</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"-"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x2d</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">" "</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0x20</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setDot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> count</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">write_register</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">16</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">count</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unit</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">device_address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setNegative</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> isNegative</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">bool</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">write_register</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">17</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> isNegative </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unit</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">device_address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setFloat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">float</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">"""</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">        显示一位的小数</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token triple-quoted-string string" style="color:rgb(195, 232, 141)">        """</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setDot</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">count</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> value </span><span class="token operator" style="color:rgb(137, 221, 255)">&lt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setNegative</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token boolean" style="color:rgb(255, 88, 116)">True</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setNegative</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        data </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token builtin" style="color:rgb(130, 170, 255)">abs</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">*</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">10</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">write_register</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">7</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unit</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">device_address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># self.client.write_register(address=16, value=value, unit=self.device_address)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setBrightness</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> brightness</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">7</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">write_register</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">address</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token number" style="color:rgb(247, 140, 108)">14</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">brightness</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> unit</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">device_address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">client</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">device </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> ZhongshengLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">@app</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">root</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"message"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"Hello World"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">@app</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/setfloat/{value}"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setTemperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">float</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setFloat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"OK"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"OK"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">@app</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/setfloat/{value}"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setTemperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">float</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setFloat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"OK"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"OK"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">@app</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token decorator annotation punctuation" style="color:rgb(199, 146, 234)">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"/setfloat"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(130, 170, 255)">setTemperature</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">float</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0.0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    device</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">setFloat</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">value</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"OK"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"OK"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">}</span><br></span></code></pre></div></div></div></div></details>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> requirements.txt </summary><div><div class="collapsibleContent_i85q"><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">fastapi</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">pymodbus</span><br></span></code></pre></div></div></div></div></details>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="本地验证">本地验证<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%9C%AC%E5%9C%B0%E9%AA%8C%E8%AF%81" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://localhost:23330/temperature</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://localhost:23330/humidity</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://localhost:23331/setfloat\?value\=123.4</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220930/http-test.png" width="100%">
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="接入设备-1">接入设备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%8E%A5%E5%85%A5%E8%AE%BE%E5%A4%87-1" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<ul>
<li class="">修改<code>http_thermometer/deployment/http_edgedevice.yaml</code>中的ip地址。</li>
<li class="">修改<code>http_led/deployment/http_edgedevice.yaml</code>中的ip地址。</li>
</ul>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull edgehub/deviceshifu-http-http:v0.1.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind load docker-image edgehub/deviceshifu-http-http:v0.1.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl apply -f examples/my_http_led/deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl apply -f examples/my_http_thermometer/deployment</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="与设备交互">与设备交互<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E4%B8%8E%E8%AE%BE%E5%A4%87%E4%BA%A4%E4%BA%92" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>打开 <code>nginx</code> 与温湿度计交互：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl exec -it nginx -- bash</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://my-thermometer.deviceshifu.svc.cluster.local/temperature</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://my-thermometer.deviceshifu.svc.cluster.local/humidity</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://my-led.deviceshifu.svc.cluster.local/setfloat?value=23.4</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="应用开发">应用开发<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>将温度和湿度读取，然后在LED上面间歇显示出来。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker build -t yangxijie/connection:v0.0.1 .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker images | grep connection</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">yangxijie/connection  v0.0.1  a9526147ddad  2 minutes ago  125MB</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind load docker-image yangxijie/connection:v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl run --image=yangxijie/connection:v0.0.1 connection-name</span><br></span></code></pre></div></div>
<p>该应用的图解如下：</p>
<img src="https://shifu.dev/blog-220930/application-illustration.png" width="60%">
<p>可以看到应用跑起来之后，LED显示屏上交替显示</p>
<img src="https://shifu.dev/blog-220930/application-flash.png" width="100%">
<h5 class="anchor anchorTargetStickyNavbar_Vzrq" id="当前文件夹文件">当前文件夹文件<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E5%BD%93%E5%89%8D%E6%96%87%E4%BB%B6%E5%A4%B9%E6%96%87%E4%BB%B6" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h5>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> main.py </summary><div><div class="collapsibleContent_i85q"><div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> time</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> requests</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">import</span><span class="token plain"> json</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">isLocal </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">False</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">localIp </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"192.168.31.138"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">flag </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">-</span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">while</span><span class="token plain"> </span><span class="token boolean" style="color:rgb(255, 88, 116)">True</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    flag </span><span class="token operator" style="color:rgb(137, 221, 255)">+=</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># [拿到数据]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> flag </span><span class="token operator" style="color:rgb(137, 221, 255)">%</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token plain"> </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># 拿到温度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"http://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">localIp</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">:23330/temperature"</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> isLocal </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"http://my-thermometer.deviceshifu.svc.cluster.local/temperature"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># 拿到湿度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"http://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">localIp</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">:23330/humidity"</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> isLocal </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"http://my-thermometer.deviceshifu.svc.cluster.local/humidity"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    res </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> requests</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># [转换数据]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">try</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        value </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> json</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">loads</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token punctuation" style="color:rgb(199, 146, 234)">[</span><span class="token string" style="color:rgb(195, 232, 141)">'value'</span><span class="token punctuation" style="color:rgb(199, 146, 234)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"DEBUG"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># [显示数据]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        led_url </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"http://</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">localIp</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">:23331/setfloat?value=</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">value</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token plain"> </span><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> isLocal </span><span class="token keyword" style="font-style:italic">else</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">f"http://my-led.deviceshifu.svc.cluster.local/setfloat?value=</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">{</span><span class="token string-interpolation interpolation">value</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(199, 146, 234)">}</span><span class="token string-interpolation string" style="color:rgb(195, 232, 141)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        requests</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">led_url</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">except</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"DEBUG"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> res</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    time</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token number" style="color:rgb(247, 140, 108)">2</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div></div></div></details>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> requirements.txt </summary><div><div class="collapsibleContent_i85q"><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">requests</span><br></span></code></pre></div></div></div></div></details>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>Dockerfile </summary><div><div class="collapsibleContent_i85q"><div class="language-Dockerfile language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">FROM python:3.9-slim-bullseye</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY requirements.txt .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">RUN pip install --no-cache-dir -r requirements.txt</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY main.py .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">CMD ["python3", "main.py"]</span><br></span></code></pre></div></div></div></div></details>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="西门子plc">西门子PLC<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E8%A5%BF%E9%97%A8%E5%AD%90plc" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="接入设备-2">接入设备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%8E%A5%E5%85%A5%E8%AE%BE%E5%A4%87-2" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>需要先修改IP地址为PLC的地址。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull edgehub/deviceshifu-http-http:v0.1.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull edgehub/plc-device:v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind load docker-image edgehub/deviceshifu-http-http:v0.1.1 edgehub/plc-device:v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl apply -f examples/my_plc/plc-deployment</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="与设备交互-1">与设备交互<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E4%B8%8E%E8%AE%BE%E5%A4%87%E4%BA%A4%E4%BA%92-1" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>这里我们修改PLC上的一个比特，可以看到PLC的上的指示灯亮起来。在实际场景中，PLC会控制机械臂等大型设备进行操作。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl run nginx --image=nginx:1.21 -n deviceshifu </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl exec -it nginx -n deviceshifu -- bash</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl "deviceshifu-plc/sendsinglebit?rootaddress=Q&amp;address=0&amp;start=0&amp;digit=1&amp;value=1"; echo</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220930/plc-light.png" width="100%">
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="海康威视摄像头">海康威视摄像头<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%B5%B7%E5%BA%B7%E5%A8%81%E8%A7%86%E6%91%84%E5%83%8F%E5%A4%B4" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="接入设备-3">接入设备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%8E%A5%E5%85%A5%E8%AE%BE%E5%A4%87-3" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>获取摄像头ip地址，修改<code>rtsp/camera-deployment/deviceshifu-camera-deployment.yaml</code>中的ip地址</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull edgehub/deviceshifu-http-http:v0.1.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo docker pull edgehub/camera-python:v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kind load docker-image edgehub/deviceshifu-http-http:v0.1.1 edgehub/camera-python:v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl apply -f examples/my_rtsp/camera-deployment</span><br></span></code></pre></div></div>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="与设备交互-2">与设备交互<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E4%B8%8E%E8%AE%BE%E5%A4%87%E4%BA%A4%E4%BA%92-2" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>在集群中可以使用nginx查看设备信息：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 集群中使用curl交互</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl exec -it nginx -- bash</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl http://deviceshifu-camera.deviceshifu.svc.cluster.local/info</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220930/camera-info.png" width="60%">
<p>可以看到摄像头的数字孪生支持的指令为：</p>
<img src="https://shifu.dev/blog-220930/camera-instructions.png" width="70%">
<p>查看摄像头捕获的图片，我们需要将端口转发到本机，在浏览器上访问。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 本机浏览器访问</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo kubectl port-forward svc/deviceshifu-camera -n deviceshifu 8080:80</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 输入`localhost:8080/info`查看信息</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 输入`localhost:8080/capture`获取图片</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 输入`localhost:8080/move/{up|down|left|right}`操控相机位置</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># 输入`localhost:8080/stream?timeout=0`获取实时视频流</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/30/meetup#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>此次 <code>Shifu Meetup</code> 活动的顺利举办。可以看到 <em><strong>Shifu</strong></em> 能够让开发者快速接入设备、将各种协议统一转为HTTP方便管理和后续应用开发。<em><strong>Shifu</strong></em> 也有无单点故障、隔离性好等多种优势。</p>
<p>如果您对 <em><strong>Shifu</strong></em> 产生兴趣，欢迎访问 <a href="https://shifu.dev/zh-Hans/" target="_blank" rel="noopener noreferrer" class=""><em><strong>Shifu</strong></em>官网</a> 了解更多。也欢迎您在 <a href="https://github.com/Edgenesis/shifu" target="_blank" rel="noopener noreferrer" class=""><em><strong>Shifu</strong></em>的GitHub仓库</a> 给项目一个star！</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Shifu+WasmEdge实现物联网数据轻松“瘦身”]]></title>
            <link>https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge</link>
            <guid>https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge</guid>
            <pubDate>Thu, 15 Sep 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[本文将简单介绍如何将 WasmEdge 集成到 Shifu 中，从而实现从IoT设备上采集的数据的清洗。]]></description>
            <content:encoded><![CDATA[<p>本文将简单介绍如何将 <code>WasmEdge</code> 集成到 <em><strong>Shifu</strong></em> 中，从而实现从IoT设备上采集的数据的清洗。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="背景-">背景 🌇<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E8%83%8C%E6%99%AF-" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>当我们在使用 <em><strong>Shifu</strong></em> 采集数据的时候，通常会出现从设备所采集到的数据，与我们所需要的数据格式不同的情况。为解决此问题，我们可以使用 <em><strong>Shifu</strong></em> + <code>WasmEdge</code> 实现把 <em><strong>Shifu</strong></em> 采集到的数据通过 <code>WasmEdge</code> 进行处理后再返回给我们的应用程序。</p>
<p>以下为简单逻辑：</p>
<!-- -->
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span><code>WasmEdge</code> 简介 🏬</div><div class="admonitionContent_BuS1"><p><code>WasmEdge</code> 是一个轻量级高性能 <code>WebAssembly(WASM)</code> 虚拟机，为边缘进行了优化。<code>WasmEdge</code> 可以应用于severless云函数、SaaS、区块链智能合约、物联网、汽车实时软件应用等多种场景。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="准备-">准备 🗂<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E5%87%86%E5%A4%87-" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<ol>
<li class=""><code>kubectl</code> v1.24.2</li>
<li class=""><code>docker</code> 20.10.16</li>
<li class=""><code>kind</code> v0.14.0</li>
<li class=""><code>git</code> 2.36.1</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="部署-">部署 🔨<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E9%83%A8%E7%BD%B2-" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>为了方便您更快的了解本篇文章，您可以通过以下命令从Github上下载程序。🚀</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone https://github.com/Edgenesis/wasm-shifu-demo.git</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cd wasm-shifu-demo</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="创建k8s集群-">创建k8s集群 🐝<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E5%88%9B%E5%BB%BAk8s%E9%9B%86%E7%BE%A4-" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>使用以下命令创建 <code>k8s</code> 集群。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kind delete cluster &amp;&amp; kind create cluster</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Creating cluster "kind" ...</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> ✓ Ensuring node image (kindest/node:v1.24.0) 🖼</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> ✓ Preparing nodes 📦  </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> ✓ Writing configuration 📜 </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> ✓ Starting control-plane 🕹️ </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> ✓ Installing CNI 🔌 </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> ✓ Installing StorageClass 💾 </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Set kubectl context to "kind-kind"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">You can now use your cluster with:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl cluster-info --context kind-kind</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="构建shifu镜像--">构建Shifu镜像  🪞<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E6%9E%84%E5%BB%BAshifu%E9%95%9C%E5%83%8F--" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>构建 <em><strong>Shifu</strong></em> 镜像。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ make -f shifu/Makefile build-image-deviceshifu</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kind load docker-image edgehub/deviceshifu-http-http:v0.0.6</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ docker images | grep edgehub/deviceshifu-http-http </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">edgehub/deviceshifu-http-http                v0.0.6    1d6b3544b8ad   54 minutes ago   36.1MB</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行虚拟设备-">运行虚拟设备 🔌<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E8%BF%90%E8%A1%8C%E8%99%9A%E6%8B%9F%E8%AE%BE%E5%A4%87-" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>为了方便您的体验，这里我们使用虚拟设备进行模拟。</p>
<p>安装并运行虚拟设备，设备的端口号为<code>8099</code>。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ docker build -f mockDevice/dockerfile -t mockdevice:v0.0.1 .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ docker run -p 8099:8099 -itd mockdevice:v0.0.1 </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">bdfd2b1323be   mockdevice:v0.0.1      "./mockDevice"           19 seconds ago      Up 18 seconds      0.0.0.0:8099-&gt;8099/tcp      admiring_feistel</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="编写规则编译wasm">编写规则&amp;编译wasm<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E7%BC%96%E5%86%99%E8%A7%84%E5%88%99%E7%BC%96%E8%AF%91wasm" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>您可以通过使用 <code>JavaScript</code> 编写规则。如果您不熟悉 <code>JavaScript</code>，您可以直接使用默认规则。🥮</p>
<p>规则文件路径: <code>wasmEdge/js-func/src/js/run.js</code> 您可以通过修改该规则实现不同的功能。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ docker build -t wasm:v0.0.1 -f wasmEdge/js.dockerfile  .</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kind load docker-image wasm:v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl apply -f wasmEdge/k8s</span><br></span></code></pre></div></div>
<p>您可以通过以下命令检查 <code>WasmEdge</code> 的 <code>pod</code> 运行情况。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl get pod -n wasmedge</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">NAME                              READY   STATUS    RESTARTS   AGE</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">wasm-deployment-fbc9564d8-td428   1/1     Running   0          1s</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="安装并运行shifu">安装并运行Shifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E5%AE%89%E8%A3%85%E5%B9%B6%E8%BF%90%E8%A1%8Cshifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>安装 <em><strong>Shifu</strong></em>。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl apply -f shifuConfig/shifu_install.yml</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl get pod -n shifu-crd-system</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">NAME                                            READY   STATUS    RESTARTS   AGE</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">shifu-crd-controller-manager-5bbdb4d786-s6h4m   2/2     Running   0          1s</span><br></span></code></pre></div></div>
<p>安装 <em><strong>deviceShifu</strong></em> 与 <em><strong>mockDeivce</strong></em> 进行连接。在此之前，请先将<code>shifuConfig/task3/task3.yaml</code> 文件中的<code>address</code>修改成您电脑的IP。</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">sku</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"E93"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">connection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Ethernet</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"192.168.14.163:8099"</span><br></span></code></pre></div></div>
<p>通过以下命令，部署运行 <em><strong>deviceShifu</strong></em>。🏖</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl apply -f shifuConfig/task3</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl get pod -n deviceshifu</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">NAME                                                 READY   STATUS    RESTARTS   AGE</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">deviceshifu-demodevice-deployment-5589b55569-l5nb2   1/1     Running   0          4s</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="体验-">体验 🕹<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/09/15/wasmedge#%E4%BD%93%E9%AA%8C-" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>您可以启动一个 <code>nginx</code> 与 <em><strong>deviceShifu</strong></em> 进行通信。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl run nginx --image=nginx:1.21</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl get pod </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">NAME    READY   STATUS    RESTARTS   AGE</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">nginx   1/1     Running   0          3s</span><br></span></code></pre></div></div>
<p>通过以下命令，您即可与 <em><strong>Shifu</strong></em> 进行交互，从而实现从IoT设备上采集的数据的清洗。🛁</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ kubectl exec -it nginx -- curl -v  http://deviceshifu-demodevice-service.deviceshifu.svc.cluster.local/get_info;echo</span><br></span></code></pre></div></div>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">[</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "code":375287,</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "name":"大气温度",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "val":"24.56",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "unit":"℃",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "exception":"温度过高"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   },</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "code":375287,</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "name":"大气湿度",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "val":"81.63",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "unit":"%RH",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      "exception":"湿度过高"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   }</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">]</span><br></span></code></pre></div></div>
<p>同时我们可以使用以下命令查看IoT设备所产生的数据。</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl localhost:8099/getInfo</span><br></span></code></pre></div></div>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">{</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   "statusCode":"200",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   "message":"success",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   "entity":[</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "dateTime":"2022-09-09 09:46:45",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eUnit":"℃",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eValue":"23.87",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eKey":"e1",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eName":"大气温度",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eNum":"101"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      },</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      {</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "dateTime":"2022-09-09 09:46:45",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eUnit":"%RH",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eValue":"80.62",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eKey":"e2",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eName":"大气湿度",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">         "eNum":"102"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      }</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   ],</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   "deviceId":950920,</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   "deviceName":"950920",</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">   "deviceRemark":"2022-09-09 09:46:45"</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">}</span><br></span></code></pre></div></div>
<p>比较两个输出，我们成功地将数据采集并进行清洗，从而得到我们想要的数据。对比图如下:</p>
<p><img decoding="async" loading="lazy" alt="对比图" src="https://shifu.dev/zh-Hans/assets/images/data-zh-41bebe80d47ed9f3ebfe5019805b0c49.png" width="2457" height="1367" class="img_ev3q"></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[使用Shifu在OpenYurt集群中接入RTSP协议摄像头]]></title>
            <link>https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt</link>
            <guid>https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt</guid>
            <pubDate>Fri, 17 Jun 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[OpenYurt 是一个云边计端算平台，借助 OpenYurt 的能力，可以将现有的 Kubernetes 集群转换成 OpenYurt 集群，并将 Kubernetes 的能力延伸到边缘侧。 OpenYurt 为云边端协同开发提供了多样化的功能，如打通云边通信的 YurtTunnel，为了方便管理节点单元应用部署/运维的 Yurt-App-Manager 以及提供了边缘自治的 YurtHub。]]></description>
            <content:encoded><![CDATA[<p><code>OpenYurt</code> 是一个云边计端算平台，借助 <code>OpenYurt</code> 的能力，可以将现有的 <code>Kubernetes</code> 集群转换成 <code>OpenYurt</code> 集群，并将 <code>Kubernetes</code> 的能力延伸到边缘侧。 <code>OpenYurt</code> 为云边端协同开发提供了多样化的功能，如打通云边通信的 <code>YurtTunnel</code>，为了方便管理节点单元应用部署/运维的 <code>Yurt-App-Manager</code> 以及提供了边缘自治的 <code>YurtHub</code>。</p>
<p>开发者可以专注于云边端产品上的应用开发而不用担心底层架构的运维。<em><strong>Shifu</strong></em> 作为 <code>Kubernetes</code> 原生的开源物联网开发架构，可以兼容各种物联网设备的协议并将其抽象成一个为微服务软件对象。二者的能力有非常好的互补性。尤其是在 <code>OpenYurt</code> 中加入了 <code>YurtDeviceController</code> 以后，<em><strong>Shifu</strong></em> 可以用 <code>OpenYurt</code> 原生的方式来将设备进行抽象，大大提高物联网开发者的开发效率。</p>
<p>使用 <code>OpenYurt</code> 和 <em><strong>Shifu</strong></em> 以后，我们可以将原本复杂的 <code>IoT</code>，云边协同开发转化为简单的Web式开发。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="简介">简介<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E7%AE%80%E4%BB%8B" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本文是一个在 <code>OpenYurt</code> 集群中使用 <em><strong>Shifu</strong></em> 接入 <code>RTSP</code> 协议摄像头的指南，其中包含 <em><strong>Shifu</strong></em>, <code>Docker</code>, <code>Linux</code>, <code>Kubernetes</code>, <code>OpenYurt</code> 的基本操作，任何开发者都可以阅读本文来学习 <em><strong>Shifu</strong></em> 的开发方法。</p>
<p>本文中的 <em><strong>Shifu</strong></em> 架构如下：</p>
<img src="https://shifu.dev/blog-220617/1.png" width="100%">
<p>北向通过 <code>deviceshifu-http-http</code> 向上开放 <code>HTTP API</code> 接口，南向通过 <code>rtsp-driver</code> 来和实际设备交互。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="目标">目标<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E7%9B%AE%E6%A0%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<ol>
<li class="">在Server端和Edge端通过 <code>yurtctl</code> 部署 <code>OpenYurt</code>, 并将Edge端加入Server端的集群</li>
<li class="">在Edge端部署网络摄像头的数字孪生</li>
<li class="">实现通过HTTP对网络摄像头的远程自动化管控</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="所需设备">所需设备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E6%89%80%E9%9C%80%E8%AE%BE%E5%A4%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<ol>
<li class="">两台运行 <code>Linux</code> 的虚拟机，Server和Edge的配置分别为4核16G内存和2核8G内存</li>
<li class="">一个 <code>RTSP</code> 协议的网络摄像头，本文中用到的摄像头型号为海康威视的  <code>DS-2DE3Q140CN-W</code></li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="软件环境">软件环境<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E8%BD%AF%E4%BB%B6%E7%8E%AF%E5%A2%83" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><code>CentOS</code> 7.9.2009</li>
<li class=""><code>Go</code> v1.17.1</li>
<li class=""><code>yurtctl</code> v0.6.1</li>
<li class=""><code>kubectl</code>: v1.19.8 (installed by <code>yurtctl</code>)</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一步-安装并部署openyurt集群">第一步 安装并部署OpenYurt集群<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E7%AC%AC%E4%B8%80%E6%AD%A5-%E5%AE%89%E8%A3%85%E5%B9%B6%E9%83%A8%E7%BD%B2openyurt%E9%9B%86%E7%BE%A4" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<blockquote>
<p>本文参考了 <a href="https://openyurt.io/docs/v0.6.0/installation/yurtctl-init-join" target="_blank" rel="noopener noreferrer" class=""><code>OpenYurt</code> 的官方教程</a></p>
</blockquote>
<p>首先让我们来下载 <code>OpenYurt</code>，从官方的GitHub直接克隆项目：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone https://github.com/openyurtio/openyurt.git</span><br></span></code></pre></div></div>
<p>接着让我们下载v0.6.1版本的 <code>yurtctl</code>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">curl -LO https://github.com/openyurtio/openyurt/releases/download/v0.6.1/yurtctl </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">chmod +x yurtctl</span><br></span></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="server端的部署">Server端的部署<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#server%E7%AB%AF%E7%9A%84%E9%83%A8%E7%BD%B2" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>在Server端创建 <code>OpenYurt</code> 集群:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">./yurtctl init --apiserver-advertise-address &lt;SERVER_IP&gt; --openyurt-version latest --passwd 123 </span><br></span></code></pre></div></div>
<p>看见如下信息即表示集群创建完成，这里的 <code>--token</code> 要记录一下用来将Edge节点加入到集群中</p>
<img src="https://shifu.dev/blog-220617/2.png" width="100%">
<p>接下来看一下各个 <code>Pod</code> 的运行状况，通过 <code>kubectl get pods -A</code>:</p>
<img src="https://shifu.dev/blog-220617/3.png" width="100%">
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="遇到的几个问题">遇到的几个问题<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E9%81%87%E5%88%B0%E7%9A%84%E5%87%A0%E4%B8%AA%E9%97%AE%E9%A2%98" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h4>
<p>如果在 <code>kubectl logs yurt-hub-server -n kube-system</code> 里遇到:</p>
<img src="https://shifu.dev/blog-220617/4.png" width="100%">
<p>请尝试 <code>kubectl apply -f config/setup/yurt-controller-manager.yaml</code> （方法来自 <a href="https://github.com/openyurtio/openyurt/issues/872#issuecomment-1148167419" target="_blank" rel="noopener noreferrer" class="">https://github.com/openyurtio/openyurt/issues/872#issuecomment-1148167419</a>  ）</p>
<p>除此之外，还有几个问题，如在 <code>kubectl logs yurt-hub-server -n kube-system</code> 里遇到如下输出：</p>
<img src="https://shifu.dev/blog-220617/5.png" width="100%">
<p>请尝试 <code>kubectl apply -f config/setup/ yurthub-cfg.yaml</code></p>
<img src="https://shifu.dev/blog-220617/6.png" width="100%">
<p>如果在 <code>yurt-tunnel-server</code> 和 <code>yurt-tunnel-agent</code> 也遇到了类似的log，通过以下命令来修复 <code>yurt-tunnel</code> 的 <code>RBAC</code> 问题：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply -f config/setup/yurt-tunnel-agent.yaml </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply -f config/setup/yurt-tunnel-server.yaml</span><br></span></code></pre></div></div>
<p><code>untaint</code> master节点来运行 <em><strong>Shifu</strong></em> 的 <code>controller</code>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl taint nodes server node-role.kubernetes.io/master-</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/7.png" width="100%">
<p>至此，Server端部署完毕。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="edge-端的部署">Edge 端的部署<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#edge-%E7%AB%AF%E7%9A%84%E9%83%A8%E7%BD%B2" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>首先利用刚才Server端初始化得到的 <code>token</code>，执行：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">./yurtctl join &lt;MASTER_IP&gt;:6443 --token &lt;MASTER_INIT_TOKEN&gt;  --node-type=edge --discovery-token-unsafe-skip-ca-verification --v=5 </span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/8.png" width="100%">
<p>确认Node状态，通过 <code>kubectl get nodes</code>：</p>
<img src="https://shifu.dev/blog-220617/9.png" width="100%">
<p>至此，一个Server端+一个Edge端的集群建立完毕。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二步-在集群中部署shifu">第二步 在集群中部署Shifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E7%AC%AC%E4%BA%8C%E6%AD%A5-%E5%9C%A8%E9%9B%86%E7%BE%A4%E4%B8%AD%E9%83%A8%E7%BD%B2shifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>接下来让我们把 <em><strong>Shifu</strong></em> 部署到 <code>OpenYurt</code> 集群中</p>
<p>在Server端，克隆 <code>Shifu</code> 项目到本地：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone https://github.com/Edgenesis/shifu.git </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cd shifu/</span><br></span></code></pre></div></div>
<p>接下来，安装 <code>Shifu</code>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply -f pkg/k8s/crd/install/shifu_install.yml</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/10.png" width="100%">
<p>通过 <code>kubectl get pods -A</code> 检查Pod状态：</p>
<img src="https://shifu.dev/blog-220617/11.png" width="100%">
<p>看到 <code>shifu-crd-system</code> namespace中的Pod运行即可。</p>
<p>至此，<em><strong>Shifu</strong></em> 安装完毕。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三步-部署摄像头的数字孪生deviceshifu">第三步 部署摄像头的数字孪生deviceShifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E7%AC%AC%E4%B8%89%E6%AD%A5-%E9%83%A8%E7%BD%B2%E6%91%84%E5%83%8F%E5%A4%B4%E7%9A%84%E6%95%B0%E5%AD%97%E5%AD%AA%E7%94%9Fdeviceshifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p><em><strong>OpenYurt</strong></em> 提供了非常方便的节点池(<code>NodePool</code>)功能，可以让我们管理节点集群，对集群进行部署。</p>
<p>创建 <code>beijing</code> 节点池：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">export WORKER_NODEPOOL="beijing" </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">export EDGE_NODE="edge" </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cat &lt;&lt;EOF | kubectl apply -f - </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">apiVersion: apps.openyurt.io/v1alpha1 </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">kind: NodePool </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">metadata: </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  name: $WORKER_NODEPOOL </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">spec: </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  type: Edge </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">EOF</span><br></span></code></pre></div></div>
<p>输出如下：</p>
<img src="https://shifu.dev/blog-220617/12.png" width="100%">
<p>接着将Edge服务器 <code>label</code> 到 <code>beijing</code> 的 <code>NodePool</code>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl label node $EDGE_NODE apps.openyurt.io/desired-nodepool=beijing</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/13.png" width="100%">
<p>查看一下 <code>NodePool</code> 的状况，应该有一个 <code>READYNODES</code>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl get nodepool</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/14.png" width="100%">
<p>因为物联网的边缘节点通常是分布式在同一场景内的，这里可以使用 <code>OpenYurt</code> 的<code>UnitedDeployment</code> 功能根据 <code>NodePool</code> 来自动部署 。</p>
<p>安装 <code>Yurt-app-manager</code>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone https://github.com/openyurtio/yurt-app-manager.git</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">cd yurt-app-manager</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply -f config/setup/all_in_one.yaml</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/15.png" width="100%">
<p>使用 <code>UnitedDeployment</code> 来部署虚拟的海康摄像头，YAML文件如下：</p>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> deviceshifu-camera-unitedDeployment.yaml </summary><div><div class="collapsibleContent_i85q"><div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> apps.openyurt.io/v1alpha1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> UnitedDeployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">labels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">controller-tools.k8s.io</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"1.0"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">selector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">matchLabels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">workloadTemplate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">deploymentTemplate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">labels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> default</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">selector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">matchLabels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">template</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">labels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">containers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgehub/deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">http</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">containerPort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8080</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">volumeMounts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">config</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">mountPath</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"/etc/edgedevice/config"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">readOnly</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_NAME</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"deviceshifu-hikvision-camera"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_NAMESPACE</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"devices"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgenesis/camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">python</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">python</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">containerPort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">11112</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">volumeMounts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">config</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">mountPath</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"/etc/edgedevice/config"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">readOnly</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_NAME</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"deviceshifu-hikvision-camera"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_NAMESPACE</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"devices"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> IP_CAMERA_ADDRESS</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"&lt;CAMERA_IP&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> IP_CAMERA_USERNAME</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"&lt;CAMERA_USERNAME&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> IP_CAMERA_PASSWORD</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"&lt;CAMERA_PASSWORD&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> IP_CAMERA_CONTAINER_PORT</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"11112"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> PYTHONUNBUFFERED</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"1"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">volumes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">config</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">            </span><span class="token key atrule">configMap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">              </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">configmap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">serviceAccountName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">sa</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">topology</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">pools</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> beijing</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">nodeSelectorTerm</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">matchExpressions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">key</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> apps.openyurt.io/nodepool</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">operator</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> In</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">values</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> beijing</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">replicas</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">revisionHistoryLimit</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">5</span><br></span></code></pre></div></div></div></div></details>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> deviceshifu-camera-service.yaml </summary><div><div class="collapsibleContent_i85q"><div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Service</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">labels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> default</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">port</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">80</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">protocol</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> TCP</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">targetPort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8080</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">selector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> LoadBalancer</span><br></span></code></pre></div></div></div></div></details>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> deviceshifu-camera-unitedDeployment.yaml </summary><div><div class="collapsibleContent_i85q"><div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> shifu.edgenesis.io/v1alpha1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EdgeDevice</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> devices</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">sku</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"HikVision Camera"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">connection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Ethernet</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> 0.0.0.0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token number" style="color:rgb(247, 140, 108)">11112</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">protocol</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> HTTP</span><br></span></code></pre></div></div></div></div></details>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> deviceshifu-camera-configmap.yaml </summary><div><div class="collapsibleContent_i85q"><div class="language-yml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> ConfigMap</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">hikvision</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">camera</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">configmap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> default</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">driverProperties</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">|</span><span class="token scalar string" style="color:rgb(195, 232, 141)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  driverSku: HikVision</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  driverImage: edgenesis/camera-python:v0.0.1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">instructions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">|</span><span class="token scalar string" style="color:rgb(195, 232, 141)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  capture:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  info:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  stream:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  move/up:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  move/down:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  move/left:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  move/right:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">telemetries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">|</span><span class="token scalar string" style="color:rgb(195, 232, 141)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">  device_health:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">    properties:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">      instruction: info</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">      initialDelayMs: 1000</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">      intervalMs: 1000</span><br></span></code></pre></div></div></div></div></details>
<p>将这四个文件放到一个目录，如下：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">camera-unitedDeployment/ </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── camera-edgedevice.yaml </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── deviceshifu-camera-configmap.yaml </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── deviceshifu-camera-service.yaml </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">└── deviceshifu-camera-unitedDeployment.yaml</span><br></span></code></pre></div></div>
<p>接下来部署:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply -f camera-unitedDeployment/</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/16.png" width="100%">
<p>通过 <code>kubectl get ud</code> 查看 <code>UnitedDeployment</code> 状态：</p>
<img src="https://shifu.dev/blog-220617/17.png" width="100%">
<p>通过 <code>kubectl get pods -owide</code> 来确认 <code>Pod</code> 部署在了 <code>beijing</code> <code>NodePool</code> 里的Edge服务器中：</p>
<img src="https://shifu.dev/blog-220617/18.png" width="100%">
<p>我们可以在集群中通过 <code>kubectl get edgedevices -n devices</code> 查看 <em><strong>Shifu</strong></em> 的虚拟设备：</p>
<img src="https://shifu.dev/blog-220617/19.png" width="100%">
<p>再通过 <code>kubectl describe edgedevices -n devices</code> 查看设备的详细信息如配置，状态等：</p>
<img src="https://shifu.dev/blog-220617/20.png" width="100%">
<p>至此，摄像头孪生部署完毕。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行效果">运行效果<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E8%BF%90%E8%A1%8C%E6%95%88%E6%9E%9C" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>接下来我们来控制摄像头，这里使用一个 <code>nginx</code> 的 <code>Pod</code> 来代表应用：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl run nginx --image=nginx</span><br></span></code></pre></div></div>
<p>待 <code>nginx</code> 开始运行时，通过 <code>kubectl exec -it nginx -- bash</code> 来进入 <code>nginx</code> 的命令行：</p>
<img src="https://shifu.dev/blog-220617/21.png" width="100%">
<p>通过以下命令可以直接控制摄像头：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">curl deviceshifu-hikvision-camera/move/{up/down/left/right}</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/22.gif" width="100%">
<p>如果我们想查看摄像头当前拍摄以及当前视频流，需要将摄像头的service通过 <code>kubectl port-forward service/deviceshifu-hikvision-camera 30080:80 --address='0.0.0.0'</code> 代理到本地。</p>
<p>在浏览器中输入服务器的IP加端口号，可以直接查看图像/视频流：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">&lt;SERVER_IP&gt;:30080/capture</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">&lt;SERVER_IP&gt;:30080/stream</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220617/23.gif" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/17/openyurt#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>在此篇文章中，我们讲述了如何将 <em><strong>Shifu</strong></em> 部署在 <code>OpenYurt</code> 集群中来增加 <code>RTSP</code> 摄像头的支持。</p>
<p>在将来的文章中，我们也会尝试将 <em><strong>Shifu</strong></em> 与 <code>OpenYurt</code> 的 <a href="https://openyurt.io/zh/docs/core-concepts/yurt-device-controller" target="_blank" rel="noopener noreferrer" class="">YurtDeviceController</a> 进行整合，通过 <code>OpenYurt</code> 原生的方式延申 <code>OpenYurt</code> 的能力到更多物联网设备的管理中。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[使用EMQX与Shifu实现设备联动]]></title>
            <link>https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx</link>
            <guid>https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx</guid>
            <pubDate>Fri, 10 Jun 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[EMQX 是一个在世界范围内非常受欢迎的 MQTT Broker。它拥有基于 Kubernetes 的云原生架构，使得自身能力极为适合当今越来越复杂的物联网场景，让设备消息的传输更为高效。因此，Shifu 作为 Kubernetes 原生的框架，可以与 EMQX 完美结合，为 EMQX 提供智能的多协议设备联动的能力。]]></description>
            <content:encoded><![CDATA[<blockquote>
<p><code>EMQX</code> 是一个在世界范围内非常受欢迎的 <code>MQTT Broker</code>。它拥有基于 <code>Kubernetes</code> 的云原生架构，使得自身能力极为适合当今越来越复杂的物联网场景，让设备消息的传输更为高效。因此，<em><strong>Shifu</strong></em> 作为 <code>Kubernetes</code> 原生的框架，可以与 <code>EMQX</code> 完美结合，为 <code>EMQX</code> 提供智能的多协议设备联动的能力。</p>
</blockquote>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="简介">简介<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx#%E7%AE%80%E4%BB%8B" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本文将介绍如何在集群内部署 <code>EMQX</code> 和 <em><strong>Shifu</strong></em>，接入一个以 <code>MQTT</code> 为通信方式的温度计和一个以 <code>RTSP</code> 为传输协议的海康威视摄像头，并加入一个应用与 <em><strong>Shifu</strong></em> 进行交互，使得每次温度计检测到超过37度的体温就会让摄像头拍下一张当前照片。</p>
<p>本文使用的简单架构如下：</p>
<img src="https://shifu.dev/blog-220610/0.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="准备">准备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx#%E5%87%86%E5%A4%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本文使用了如下服务和工具：</p>
<ol>
<li class=""><code>Kubernetes</code>: 1.20.10<!-- -->
<ul>
<li class=""><code>kubectl</code></li>
<li class=""><code>kubeadm</code></li>
<li class=""><code>kubelet</code></li>
</ul>
</li>
<li class=""><code>Golang</code>: 1.16.10</li>
<li class=""><code>Docker</code>: 19.03.9</li>
<li class=""><code>EMQX</code>: 4.1-rc1</li>
</ol>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一步-部署kubernetes">第一步 部署Kubernetes<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx#%E7%AC%AC%E4%B8%80%E6%AD%A5-%E9%83%A8%E7%BD%B2kubernetes" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本步可以参考 <code>Kubernetes</code> 的官方教程进行部署：</p>
<p><a href="https://kubernetes.io/docs/setup/" target="_blank" rel="noopener noreferrer" class="">https://kubernetes.io/docs/setup/</a></p>
<p>在部署完成后我们应当看到终端打印出如下信息：</p>
<img src="https://shifu.dev/blog-220610/1.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二步-部署shifu">第二步 部署Shifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx#%E7%AC%AC%E4%BA%8C%E6%AD%A5-%E9%83%A8%E7%BD%B2shifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>将 <em><strong>Shifu</strong></em> 的 GitHub仓库 克隆到本地：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone https://github.com/Edgenesis/shifu.git</span><br></span></code></pre></div></div>
<p>然后可以通过下列命令部署 <em><strong>Shifu</strong></em>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply -f shifu/pkg/k8s/crd/install/shifu_install.yml</span><br></span></code></pre></div></div>
<p>部署完成后我们应当看到 <em><strong>Shifu</strong></em> 的 <code>CRD controller</code> 已经完成部署：</p>
<img src="https://shifu.dev/blog-220610/2.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三步-部署emqx">第三步 部署EMQX<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx#%E7%AC%AC%E4%B8%89%E6%AD%A5-%E9%83%A8%E7%BD%B2emqx" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>首先需要安装 <code>EMQX</code> <code>Operator Controller</code>：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ curl -f -L "https://github.com/emqx/emqx-operator/releases/download/1.1.6/emqx-operator-controller.yaml" | kubectl apply -f -</span><br></span></code></pre></div></div>
<p>接着我们写一个最简单的 <code>deployment.yaml</code>：</p>
<img src="https://shifu.dev/blog-220610/3.png" width="100%">
<p>然后就可以部署一个 <code>EMQX</code> 了：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply –f deployment.yaml</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220610/4.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第四步-接入设备">第四步 接入设备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx#%E7%AC%AC%E5%9B%9B%E6%AD%A5-%E6%8E%A5%E5%85%A5%E8%AE%BE%E5%A4%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>对于温度计，我们只需要调整它的 <code>MQTT</code> 设置，让其可以向 <code>EMQX</code> 发布 <code>MQTT</code> 信息即可。</p>
<p>（如果是集群外的温度计，我们可以通过 <code>Kubernetes Service</code> 来开放 <code>External IP</code> 供访问）</p>
<img src="https://shifu.dev/blog-220610/5.png" width="100%">
<p>对于摄像头，<em><strong>Shifu</strong></em> 的仓库已经包括一个<a href="https://github.com/Edgenesis/shifu/tree/main/examples/rtspDeviceShifu/" target="_blank" rel="noopener noreferrer" class="">使用 <code>RTSP</code> 的海康威视摄像头的配置文件</a>，我们可以轻松更改配置文件中的IP、用户名、密码，将它接入 <em><strong>Shifu</strong></em>：</p>
<img src="https://shifu.dev/blog-220610/6.png" width="100%">
<img src="https://shifu.dev/blog-220610/7.png" width="100%">
<p>至此，我们的设备已经连接完毕，下面就可以开始联动了。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="联动应用">联动应用<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx#%E8%81%94%E5%8A%A8%E5%BA%94%E7%94%A8" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>我们简单写一个 <code>Python</code> 应用，用来实现下面的逻辑：</p>
<p>该应用向 <code>EMQX</code> 订阅 <code>temperature-shifu-mqtt</code> 的消息，每次消息都只包括一个表示当前温度的数字；如果当前温度大于37度，则操作摄像头拍摄一张照片并保存在本地。</p>
<p>以下是应用代码：</p>
<img src="https://shifu.dev/blog-220610/8.png" width="100%">
<p>加个 <code>capture function</code> 封装所有摄像头的动作。接着我们就可以将其部署到集群中，开始监视了：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">python3 app.py 10.244.0.33</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220610/9.gif" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="总结">总结<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/10/emqx#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本文描述了如何让 <code>EMQX</code> 为 <em><strong>Shifu</strong></em> 赋予更高效的 <code>MQTT Broker</code> 能力，<em><strong>同时让Shifu</strong></em> 与 <code>MQTT</code> 合作为设备提供联动能力。在现实的应用场景之中，我们可以使用一个仅需一百余元的的红外温度计+摄像头组合，来代替数千元且表现并不稳定的测温摄像头，在大规模部署的情况下节省巨额成本。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[在KubeEdge上部署Shifu]]></title>
            <link>https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge</link>
            <guid>https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge</guid>
            <pubDate>Wed, 08 Jun 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[如今十分流行的开源项目 KubeEdge 给开发者提供了一个基于 Kubernetes 的云边协同方案。它成功地将 Kubernetes 的集群编排能力融合到了物联网的边缘场景之中，使得对边缘算力的调度和管理更加轻量、也更加高效。]]></description>
            <content:encoded><![CDATA[<p>如今十分流行的开源项目 <code>KubeEdge</code> 给开发者提供了一个基于 <code>Kubernetes</code> 的云边协同方案。它成功地将 <code>Kubernetes</code> 的集群编排能力融合到了物联网的边缘场景之中，使得对边缘算力的调度和管理更加轻量、也更加高效。</p>
<p><em><strong>Shifu</strong></em> 作为同样基于 <code>Kubernetes</code> 的开源物联网开发框架，它对于多种设备的兼容和虚拟化将为 <code>KubeEdge</code> 在边缘端的应用提供助力。事实上，二者在能力上拥有非常好的互补性，在多设备兼容的同时，运行在 <code>KubeEdge</code> 上的 <code>Shifu</code> 可以轻松管理边缘端运行的轻量 <code>Pod</code>。</p>
<p>有了 <code>KubeEdge</code> + <em><strong>Shifu</strong></em> 的强强联手，我们就可以把IoT设备抽象成 <code>API</code>，把原本复杂的传统物联网开发模式转化为简单的Web开发模式！</p>
<p>下面就让我们来看一下如何让 <em><strong>Shifu</strong></em> 运行在 <code>KubeEdge</code> 上，并且给开发者们提供价值吧！</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="简介">简介<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E7%AE%80%E4%BB%8B" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本文将简单介绍在 <code>KubeEdge</code> 上部署 <em><strong>Shifu</strong></em> 的步骤，并接入一个海康威视的摄像头（使用 <code>RTSP</code> 进行视频流传输）的实例，为 <code>KubeEdge</code> 的架构加入海康威视摄像头支持。</p>
<p>本文使用的架构如下：</p>
<img src="https://shifu.dev/blog-220608/1.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="准备">准备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E5%87%86%E5%A4%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本文使用了如下服务和工具：</p>
<ol>
<li class=""><code>Kubernetes</code>: 1.21.5<!-- -->
<ul>
<li class=""><code>kubectl</code></li>
<li class=""><code>kubeadm</code></li>
<li class=""><code>kubelet</code></li>
</ul>
</li>
<li class=""><code>Golang</code>: 1.16.10</li>
<li class=""><code>Docker</code>: 19.03.9</li>
<li class=""><code>KubeEdge</code>: 1.7.2</li>
</ol>
<p>同时，<code>KubeEdge</code> 的 <code>Cloud端</code> 和 <code>Edge端</code> 分别运行在不同的 <code>Linux</code> 实例上，环境均为 <code>Ubuntu Server 20.04</code>。</p>
<p>上述服务和工具中，<code>Cloud端</code> 需要安装全部上述服务和工具，而 <code>Edge端</code> 只需要安装 <code>Docker</code> 和 <code>KubeEdge</code>。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一步-在cloud端部署kubernetes">第一步 在Cloud端部署Kubernetes<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E7%AC%AC%E4%B8%80%E6%AD%A5-%E5%9C%A8cloud%E7%AB%AF%E9%83%A8%E7%BD%B2kubernetes" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本步可以参考<a href="https://kubernetes.io/docs/setup/" target="_blank" rel="noopener noreferrer" class="">Kubernetes的官方教程</a>进行部署。</p>
<p>在部署完成后我们应当看到终端打印出如下信息：</p>
<img src="https://shifu.dev/blog-220608/2.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二步-在cloud端部署shifu">第二步 在Cloud端部署Shifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E7%AC%AC%E4%BA%8C%E6%AD%A5-%E5%9C%A8cloud%E7%AB%AF%E9%83%A8%E7%BD%B2shifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>将 <em><strong>Shifu</strong></em> 的 <code>Github</code> 仓库克隆到本地：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">git clone https://github.com/Edgenesis/shifu.git</span><br></span></code></pre></div></div>
<p>然后可以通过下列命令部署 <em><strong>Shifu</strong></em>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply -f shifu/pkg/k8s/crd/install/shifu_install.yml</span><br></span></code></pre></div></div>
<p>部署完成后我们应当看到 <em><strong>Shifu</strong></em> 的 <code>CRD controller</code> 已经完成部署：</p>
<img src="https://shifu.dev/blog-220608/3.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三步-在cloud端部署kubeedge">第三步 在Cloud端部署KubeEdge<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E7%AC%AC%E4%B8%89%E6%AD%A5-%E5%9C%A8cloud%E7%AB%AF%E9%83%A8%EF%BF%BD%EF%BF%BD%E7%BD%B2kubeedge" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>本步可以参考 <a href="https://kubeedge.io/zh/docs/setup/keadm/" target="_blank" rel="noopener noreferrer" class=""><code>KubeEdge</code> 的官方教程</a>，使用 <code>keadm</code> 进行部署。</p>
<p>在部署完成后我们应当看到终端打印出如下信息：</p>
<img src="https://shifu.dev/blog-220608/4.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第四步-在cloud端获取token">第四步 在Cloud端获取token<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E7%AC%AC%E5%9B%9B%E6%AD%A5-%E5%9C%A8cloud%E7%AB%AF%E8%8E%B7%E5%8F%96token" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>运行如下命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">keadm gettoken</span><br></span></code></pre></div></div>
<p>请保存获得的<code>token</code>以便Edge端使用。</p>
<p>现在Cloud端的配置告一段落，我们现在切换到Edge端的机器，让它加入集群。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第五步-在edge端加入集群">第五步 在Edge端加入集群<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E7%AC%AC%E4%BA%94%E6%AD%A5-%E5%9C%A8edge%E7%AB%AF%E5%8A%A0%E5%85%A5%E9%9B%86%E7%BE%A4" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>在Edge端运行如下命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">keadm join --cloudcore-ipport="&lt;Cloud端advertise-address&gt;:10000" --token=&lt;第四步获得的token&gt;</span><br></span></code></pre></div></div>
<p>在部署完成后我们应当看到终端打印出如下信息：</p>
<img src="https://shifu.dev/blog-220608/5.png" width="100%">
<p>此时切换回到Cloud端，查看nodes：</p>
<img src="https://shifu.dev/blog-220608/6.png" width="100%">
<p>我们可以看到Cloud端和Edge端都已经部署完毕了。</p>
<p>现在我们可以开始部署设备了。</p>
<p>通过 <code>KubeEdge</code>，我们可以做到只在Cloud端进行 <code>Kubernetes</code> 操作并且部署到Edge端，同时保持Edge端无需安装 <code>Kubernetes</code> 组件，保证轻量化。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第六步-在cloud端修改海康威视摄像头的配置文件">第六步 在Cloud端修改海康威视摄像头的配置文件<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E7%AC%AC%E5%85%AD%E6%AD%A5-%E5%9C%A8cloud%E7%AB%AF%E4%BF%AE%E6%94%B9%E6%B5%B7%E5%BA%B7%E5%A8%81%E8%A7%86%E6%91%84%E5%83%8F%E5%A4%B4%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p><em><strong>Shifu</strong></em> 需要简单的配置文件来实现数字孪生的生成。在 <em><strong>Shifu</strong></em> 中，数字孪生被称为 <em><strong>deviceShifu</strong></em>，以 <code>Pod</code> 的形式运行在集群里。</p>
<p><em><strong>Shifu</strong></em> 提供了接入海康威视摄像头的配置文件，其路径为 <code>https://github.com/Edgenesis/shifu/tree/main/examples/rtspDeviceShifu/</code>。</p>
<p><em><strong>Shifu</strong></em> 默认将 <em><strong>deviceShifu</strong></em> 部署在拥有完整 <code>Kubernetes</code> 实例的机器上。在 <code>KubeEdge</code> 的环境下，边缘端无需运行完整的 <code>Kubernetes</code>，因此 <em><strong>Shifu</strong></em> 也准备了针对云边协同环境的轻量的 <em><strong>deviceShifu</strong></em> 供使用。我们可以更改 <code>deviceshifu-camera-deployment.yaml</code>，让它使用边缘侧的 <em><strong>deviceShifu</strong></em>，并添加 <code>nodeName</code> 将其部署在 <code>edge node</code>:</p>
<img src="https://shifu.dev/blog-220608/7.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="第七步-部署海康威视摄像头pod">第七步 部署海康威视摄像头Pod<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E7%AC%AC%E4%B8%83%E6%AD%A5-%E9%83%A8%E7%BD%B2%E6%B5%B7%E5%BA%B7%E5%A8%81%E8%A7%86%E6%91%84%E5%83%8F%E5%A4%B4pod" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>在Cloud端，运行下列命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">kubectl apply -f shifu/examples/rtspDeviceShifu/camera-deployment</span><br></span></code></pre></div></div>
<p>此时，我们可以查看camera相关的 <code>Pod</code>：</p>
<img src="https://shifu.dev/blog-220608/8.png" width="100%">
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="最后一步-在edge端进行确认">最后一步 在Edge端进行确认<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/06/08/kubeedge#%E6%9C%80%E5%90%8E%E4%B8%80%E6%AD%A5-%E5%9C%A8edge%E7%AB%AF%E8%BF%9B%E8%A1%8C%E7%A1%AE%E8%AE%A4" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>在Edge端，我们可以看到camera相关的Docker容器已经在运行了：</p>
<img src="https://shifu.dev/blog-220608/9.png" width="100%">
<p>我们可以非常简单地调用 <em><strong>deviceShifu</strong></em> 提供的 <code>capture</code>/<code>stream</code>/<code>info</code>/<code>move</code> 等一系列 <code>HTTP API</code>，对摄像头进行操作，比如下面的动图：</p>
<p>相关命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">curl edgedevice-camera/move</span><br></span></code></pre></div></div>
<img src="https://shifu.dev/blog-220608/10.gif" width="100%">
<p>至此，我们就完成了在 <code>KubeEdge</code> 上运行 <em><strong>Shifu</strong></em> 的全部步骤。</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[接入私有驱动]]></title>
            <link>https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver</link>
            <guid>https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver</guid>
            <pubDate>Sat, 07 May 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[在这一篇文章中，我们会先使用 Python 编写一个 GPIO 的驱动控制 LED，之后将其接入 Shifu 进行交互和管理。]]></description>
            <content:encoded><![CDATA[<p>在这一篇文章中，我们会先使用 <code>Python</code> 编写一个 <code>GPIO</code> 的驱动控制 <code>LED</code>，之后将其接入 <em><strong>Shifu</strong></em> 进行交互和管理。</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="创建驱动">创建驱动<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E5%88%9B%E5%BB%BA%E9%A9%B1%E5%8A%A8" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="目标">目标<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%9B%AE%E6%A0%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<ul>
<li class="">完成简单LED电路连接</li>
<li class="">基本的树莓派/SSH配置</li>
<li class="">基本的Python语法以及GPIO库知识</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="所用设备">所用设备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E6%89%80%E7%94%A8%E8%AE%BE%E5%A4%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<ul>
<li class="">树莓派 <code>Raspberry Pi 3B+</code> 运行64位 <code>Raspberry Pi OS</code></li>
<li class="">1个面包板</li>
<li class="">3个LED灯泡（红 黄 绿）</li>
<li class="">1个330欧姆的电阻</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="需要的基本知识">需要的基本知识<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%9F%A5%E8%AF%86" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<ul>
<li class="">简单的Python语法</li>
<li class="">Linux命令行基本操作（创建文件 安装应用 SSH 运行程序）</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一步-电路设计">第一步 电路设计<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%AC%AC%E4%B8%80%E6%AD%A5-%E7%94%B5%E8%B7%AF%E8%AE%BE%E8%AE%A1" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>首先我们来设计一下电路，我们需要设计一个电路，可以让树莓派的<code>GPIO</code>输出来控制单个LED灯泡的开/关。本文采用了最直接的办法，即直接使用<code>GPIO</code>来对LED灯泡进行供电。</p>
<p>电路图如下：</p>
<img src="https://shifu.dev/blog-220507/1.png" width="50%">
<p>图中<code>GPIO</code>的22，23，19针分别控制了红，绿，黄三个LED。最后串联的330欧电阻是为了防止LED电流过大烧毁。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二步-电路实施">第二步 电路实施<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%AC%AC%E4%BA%8C%E6%AD%A5-%E7%94%B5%E8%B7%AF%E5%AE%9E%E6%96%BD" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>根据<code>Raspberry Pi</code>官方文档中的针脚布局（Pin Layout），我们可以看到针脚的具体位置，这里用到了第15，16，35，39号针脚：</p>
<img src="https://shifu.dev/blog-220507/2.png" width="100%">
<p>将这四个针脚接上线缆的母口，然后在面包板上将剩余的电路连接好：</p>
<img src="https://shifu.dev/blog-220507/3.png" width="100%">
<p>图中红，绿，黄，灰线缆分别对应了<code>GPIO22</code> <code>GPIO23</code> <code>GPIO19</code>和地（ground）。</p>
<img src="https://shifu.dev/blog-220507/4.png" width="50%">
<img src="https://shifu.dev/blog-220507/5.png" width="50%">
<p>至此，电路设计与连接部分结束。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三步-树莓派准备">第三步 树莓派准备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%AC%AC%E4%B8%89%E6%AD%A5-%E6%A0%91%E8%8E%93%E6%B4%BE%E5%87%86%E5%A4%87" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>首先在树莓派中安装一个操作系统，本文中用到的是 <code>Raspberry Pi OS (64-bit)</code>。<a href="https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit" target="_blank" rel="noopener noreferrer" class="">下载链接</a></p>
<p>将SD卡插入读卡器，连接到电脑的USB端口中，再将下载后的压缩包通过 <code>balenaEtcher</code> 刷入SD卡即可。<a href="https://www.balena.io/etcher/" target="_blank" rel="noopener noreferrer" class="">balenaEtcher链接</a></p>
<p>将SD卡放入树莓派，插入电源，显示器即可开始配置。</p>
<p>首先，为了方便开发/调试我们需要开启SSH，从桌面上开启终端，然后输入 <code>sudo raspi-config</code> 来进入配置界面，选择 <code>Interface Options</code>：</p>
<img src="https://shifu.dev/blog-220507/6.png" width="100%">
<p>选择 <code>SSH</code>:</p>
<img src="https://shifu.dev/blog-220507/7.png" width="100%">
<p>按回车，接着按左键选择<code>Yes</code>来开启SSH服务：</p>
<img src="https://shifu.dev/blog-220507/8.png" width="100%">
<p>之后按右选择<code>Finish</code>，再回车退出即可：</p>
<img src="https://shifu.dev/blog-220507/9.png" width="100%">
<p>这时，SSH服务已经开启了，但是我们需要知道树莓派的IP才可以SSH，这里我们通过系统自带的 <code>ip addr</code> 来查看：</p>
<img src="https://shifu.dev/blog-220507/10.png" width="100%">
<p>可以看到，IP地址为 <code>192.168.15.122</code>。</p>
<p>回到电脑中，通过 <code>ssh pi@192.168.15.122</code> 即可以远程进入到树莓派的命令行中</p>
<img src="https://shifu.dev/blog-220507/11.png" width="100%">
<p>至此，树莓派以及硬件的准备就结束了。</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>备注</div><div class="admonitionContent_BuS1"><p>早些版本的树莓派OS可能需要手动开启GPIO</p></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第四步-驱动编写">第四步 驱动编写<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%AC%AC%E5%9B%9B%E6%AD%A5-%E9%A9%B1%E5%8A%A8%E7%BC%96%E5%86%99" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>一切就绪，现在我们来编写第一个驱动！</p>
<p>首先先确保系统中安装了 <code>Python</code>，如果没有的话可以运行如下命令：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ sudo apt-get update &amp;&amp; sudo apt install python3 -y</span><br></span></code></pre></div></div>
<p>安装完毕后可以通过 <code>python -V</code> 来检查安装状态，如显示版本则成功：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ python -V</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">Python 3.9.2</span><br></span></code></pre></div></div>
<p>接下来让我们先从一个LED灯泡控制开始，我们要控制红色LED的亮/灭，使用以下代码：</p>
<img src="https://shifu.dev/blog-220507/12.png" width="100%">
<p>驱动中用到的模块有：</p>
<ul>
<li class=""><code>RPi.GPIO</code> 用来控制树莓派的GPIO</li>
<li class=""><code>argparse</code> 用来解析命令行输入</li>
</ul>
<p>先将GPIO的模式置到<code>GPIO.BCM</code>模式，在这个模式下针脚的数字为GPIO的数字，非树莓派板上的针脚顺序。</p>
<p><code>GPIO.setmode(GPIO.BCM)</code></p>
<p>然后将警告关闭，本文中树莓派只会被这一个驱动程序控制</p>
<p><code>GPIO.setwarnings(False)</code></p>
<p>接下来处理一下程序输入，本驱动程序会接受两个输入：</p>
<ol>
<li class=""><code>-p</code>, <code>--port</code>, 代表程序操控的GPIO针</li>
<li class=""><code>-o</code>, <code>--operate</code>, 代表程序对于GPIO针的操作，<code>on</code> 代表电路中的 <code>1</code>, 即 <code>3.3V</code>，<code>off</code> 代表电路中的 <code>0</code>, 即 <code>0V</code></li>
</ol>
<p>这段代码为：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> argparse</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">ArgumentParser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"-p"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"--pin"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">type</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token builtin" style="color:rgb(130, 170, 255)">int</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> default</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">help</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"Specify the GPIO pin to operate, e.g.: '17'"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">parser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"-o"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"--operate"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">type</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token builtin" style="color:rgb(130, 170, 255)">str</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> default</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token boolean" style="color:rgb(255, 88, 116)">None</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(130, 170, 255)">help</span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token string" style="color:rgb(195, 232, 141)">"Specify the GPIO output, e.g.: 'on/off'"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">args </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> parser</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">parse_args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>接下来是一些错误处理，当针脚数和操作不为空时，将参数传入函数 <code>turnOnLed</code> 进行操作，否则打印出警告：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">pin </span><span class="token keyword" style="font-style:italic">and</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">operate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    turnOnLed</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token plain">args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">pin</span><span class="token punctuation" style="color:rgb(199, 146, 234)">,</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">operate</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"need to specify both pin and operate arguments, type --help for more information"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><br></span></code></pre></div></div>
<p>主程序部分结束，下面我们看一下控制LED灯泡的函数 <code>turnOnLed</code>。</p>
<p>首先是对传参的判断，确定 <code>operate</code> 变量为 <code>on</code> 或者 <code>off</code> ，否则返回。当变量为 <code>on</code> 的时候，将输出变量 <code>gpio_out</code> 设为 <code>GPIO.HIGH</code>，<code>off</code> 时则设为 <code>GPIO.LOW</code>。</p>
<p>这两个值分别代表了开或者关：</p>
<div class="language-py codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-py codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token keyword" style="font-style:italic">if</span><span class="token plain"> operate </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"on"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    gpio_out </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> GPIO</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">HIGH</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">elif</span><span class="token plain"> operate </span><span class="token operator" style="color:rgb(137, 221, 255)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"off"</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    gpio_out </span><span class="token operator" style="color:rgb(137, 221, 255)">=</span><span class="token plain"> GPIO</span><span class="token punctuation" style="color:rgb(199, 146, 234)">.</span><span class="token plain">LOW</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token keyword" style="font-style:italic">else</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">print</span><span class="token punctuation" style="color:rgb(199, 146, 234)">(</span><span class="token string" style="color:rgb(195, 232, 141)">"operate is neither on/off, quitting..."</span><span class="token punctuation" style="color:rgb(199, 146, 234)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token keyword" style="font-style:italic">return</span><br></span></code></pre></div></div>
<p>最后，就是将该针脚的模式设为输出：<code>GPIO.setup(pin, GPIO.OUT)</code></p>
<p>并将针脚的输出切换到开/关：<code>GPIO.output(pin, gpio_out)</code></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行效果">运行效果<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E8%BF%90%E8%A1%8C%E6%95%88%E6%9E%9C" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>程序通过 <code>python led_driver.py -p {pin #} -o {operate}</code> 来操控</p>
<p>如果想让红色灯泡亮，我们执行 <code>python led_driver.py -p 22 -o on</code></p>
<img src="https://shifu.dev/blog-220507/13.gif" width="100%">
<p>至此，给树莓派编写的简单控制LED灯泡驱动就编写完成了！</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>备注</div><div class="admonitionContent_BuS1"><p>本质上这个驱动实现了树莓派GPIO针的操控，所以我们也可以使用这个驱动来操控任意可以被3.3V控制的电路，针脚也不仅限于本文中的22，23和19。大家可以自行发挥想象力制作各式各样的测试电路。</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="接入shifu">接入Shifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E6%8E%A5%E5%85%A5shifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h2>
<p>接下来我们使用刚刚编写的驱动接入 <em><strong>Shifu</strong></em> 框架进行交互和管理。</p>
<p>本文中的 <em><strong>Shifu</strong></em> 架构如下：</p>
<img src="https://shifu.dev/blog-220507/connect-0.jpeg" width="100%">
<p>北向通过 <code>deviceshifu-http-http</code> 向上开放 <code>HTTP</code> API接口，南向通过 <code>rpio-gpio-driver</code> 来和实际设备交互。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="目标-1">目标<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%9B%AE%E6%A0%87-1" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<ol>
<li class="">在树莓派上安装k3s集群并安装Shifu Framework</li>
<li class="">打包树莓派LED驱动到一个容器镜像</li>
<li class="">在Shifu中部署树莓派LED的数字孪生</li>
<li class="">实现对树莓派LED的远程自动化管控</li>
</ol>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="所用设备-1">所用设备<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E6%89%80%E7%94%A8%E8%AE%BE%E5%A4%87-1" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<ul>
<li class="">树莓派 <code>Raspberry Pi 3B+</code> 运行64位 <code>Raspberry Pi OS</code></li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="需要的基本知识-1">需要的基本知识<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E9%9C%80%E8%A6%81%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%9F%A5%E8%AF%86-1" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<ul>
<li class="">Docker/containerd基本操作</li>
<li class="">K8s/K3s基本操作</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第一步-安装k3s">第一步 安装k3s<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%AC%AC%E4%B8%80%E6%AD%A5-%E5%AE%89%E8%A3%85k3s" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>首先我们要在树莓派中运行一个 <code>Kubernetes集群</code>，这里并不限制用户使用的版本，但是为了节省资源本文中使用的是<code>k3s</code>。<a href="https://rancher.com/docs/k3s/latest/en/quick-start/" target="_blank" rel="noopener noreferrer" class="">安装教程</a></p>
<p>安装完毕后，执行 <code>kubectl version</code> 查看当前 <code>Kubernetes</code>版本：</p>
<img src="https://shifu.dev/blog-220507/connect-1.png" width="100%">
<p>利用 <code>kubectl get nodes</code> 查看当前集群的状态，显示 <code>Ready</code> 即表示集群可以使用:</p>
<img src="https://shifu.dev/blog-220507/connect-2.png" width="100%">
<p>至此，<code>k3s</code>安装结束。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第二步-安装shifu">第二步 安装Shifu<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%AC%AC%E4%BA%8C%E6%AD%A5-%E5%AE%89%E8%A3%85shifu" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>首先将 <em><strong>Shifu</strong></em> 项目仓库克隆到本地，项目地址为:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">$ git clone https://github.com/Edgenesis/shifu.git</span><br></span></code></pre></div></div>
<p>下面通过 <code>kubectl apply -f shifu/pkg/k8s/crd/install/shifu_install.yml</code> 即可一键将 <em><strong>Shifu</strong></em> 部署到 <code>k3s</code>集群中：</p>
<img src="https://shifu.dev/blog-220507/connect-3.png" width="100%">
<p>再次执行 <code>kubectl get pods -A</code>，即可看到 <code>Shifu Framework</code> 的控制器被部署到集群中：</p>
<img src="https://shifu.dev/blog-220507/connect-4.png" width="100%">
<p>我们也可以通过 <code>edgedevices</code> 这个<code>CRD</code>来管理设备资源（当前没有设备）：</p>
<img src="https://shifu.dev/blog-220507/connect-5.png" width="100%">
<p>至此，<em><strong>Shifu</strong></em> 安装完毕。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第三步-打包驱动">第三步 打包驱动<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%AC%AC%E4%B8%89%E6%AD%A5-%E6%89%93%E5%8C%85%E9%A9%B1%E5%8A%A8" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>我们需要利用 <em><strong>Shifu</strong></em> 提供的一个小工具来实现可以远程操纵本地驱动，详细的教程请看：</p>
<ul>
<li class="">新版本：<a href="https://github.com/Edgenesis/shifu/tree/main/cmd/httpstub/sshstub" target="_blank" rel="noopener noreferrer" class="">https://github.com/Edgenesis/shifu/tree/main/cmd/httpstub/sshstub</a></li>
<li class="">老版本：<a href="https://github.com/Edgenesis/shifu/tree/c0cab1ce98870eb470ddc9e01e1d99c13b611411/driver_util" target="_blank" rel="noopener noreferrer" class="">https://github.com/Edgenesis/shifu/tree/c0cab1ce98870eb470ddc9e01e1d99c13b611411/driver_util</a></li>
</ul>
<p>这个小工具实现了将用户/程序发送来的HTTP请求转换到本地命令行来执行。</p>
<p>教程里面提供了一个驱动示例，路径为 <a href="https://github.com/Edgenesis/shifu/blob/main/examples/driver_utils/simple-alpine/Dockerfile.sample" target="_blank" rel="noopener noreferrer" class="">https://github.com/Edgenesis/shifu/blob/main/examples/driver_utils/simple-alpine/Dockerfile.sample</a></p>
<p>内容如下：</p>
<img src="https://shifu.dev/blog-220507/connect-6.png" width="100%">
<p>可以看到实例 <code>Dockerfile</code> 分两部分，首先是用 <code>golang</code> 这个镜像来编译 <em><strong>Shifu</strong></em> 提供的 <code>http_to_ssh_stub.go</code> 来实现HTTP到SSH命令行的转换。接着是利用一个空的 <code>alpine</code> 镜像，配置SSH来供演示。</p>
<p>接下来让我们来正式操作。</p>
<p>考虑到树莓派的性能局限，本次编译将从电脑端执行，将编译好的镜像推送到<code>Docker Hub</code>来供远程调用即可。</p>
<p>首先，我们建立一个新的文件夹，这里用的是 <code>dev</code>，然后将创建的树莓派LED驱动保存到该目录：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">dev/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">└── led_driver.py</span><br></span></code></pre></div></div>
<p>驱动内容不变</p>
<img src="https://shifu.dev/blog-220507/connect-7.png" width="100%">
<p>从 <em><strong>Shifu</strong></em> 项目的 <code>driver_util/examples/simple-alpine/</code> 目录下将 <code>Dockerfile.sample</code> 复制到 <code>dev</code> 目录下：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">dev/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├── Dockerfile.sample</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">└── led_driver.py</span><br></span></code></pre></div></div>
<p>更改以下字段将第二部的镜像从 <code>alpine</code> 改为 <code>python:alpine</code>，安装 <code>RPi.GPIO</code> 的 <code>Python</code> 库</p>
<p>最后将 <code>Python驱动</code> 拷贝到运行容器中，新的 <code>Dockerfile</code> 如下，改动的地方已用注释标记出来：</p>
<div class="language-Dockerfile language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">FROM golang:1.17.1 as builder</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">WORKDIR /</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">ENV GOPROXY=https://goproxy.cn,direct</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">ENV GO111MODULE=on</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">ENV GOPRIVATE=github.com/Edgenesis</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY driver_util driver_util</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">WORKDIR /driver_util</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">RUN go mod download</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Build the Go app</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">RUN CGO_ENABLED=0 GOOS=$(go env GOOS) GOARCH=$(go env GOARCH) gobuild -a -o /output/http2ssh-stub http_to_ssh_stub.go</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">FROM python:alpine # modified</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">RUN apk add --no-cache --update openrc openssh \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; mkdir -p /run/openrc \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; touch /run/openrc/softlevel \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; sed -ie "s/#PubkeyAuthentication/PubkeyAuthentication/g"/etc/ssh/sshd_config \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; sed -ie "s/#PasswordAuthenticationyes/PasswordAuthentication no/g" /etc/ssh/sshd_config \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; sed -ie "s/AllowTcpForwardingno/AllowTcpForwarding yes/g" /etc/ssh/sshd_config \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; echo"PubkeyAcceptedKeyTypes=+ssh-rsa" &gt;&gt;  /etc/ssh/ sshd_config\  # modified</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; ssh-keygen -A \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; passwd -d root \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; mkdir ~/.ssh \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; while ! [ -e/etc/ssh/ssh_host_rsa_key.pub ]; do sleep 1; done \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; cp /etc/ssh/ssh_host_rsa_key.pub~/.ssh/authorized_keys</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">RUN apk add --no-cache -Uu --virtual .build-dependencies libffi-devopenssl-dev build-base musl \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; pip3 install --no-cache --upgrade RPi.GPIO\</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; apk del --purge .build-dependencies \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; apk add --no-cache --purge curlca-certificates musl \</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    &amp;&amp; rm -rf /var/cache/apk/* /tmp/*  # modified</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">WORKDIR /root/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY --from=builder /output/http2ssh-stub http2ssh-stub</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY --from=builder/driver_util/examples/simple-alpine/docker-entrypoint.sh docker-entrypoint.sh</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">COPY dev/led_driver.py led_driver.py  # modified</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">RUN chmod +x docker-entrypoint.sh</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"> </span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"># Command to run the executable</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">ENTRYPOINT ["./docker-entrypoint.sh"]</span><br></span></code></pre></div></div>
<p>接下来我们来打包封装Docker镜像，因为树莓派的CPU是 <code>ARM64</code>的处理器，本文中编译使用的电脑为 <code>x86-64</code>，所以我们需要使用 <code>Docker</code> 的 <code>buildx</code> 功能来进行镜像构建，有关buildx的教程本文就不再叙述，需要的话可以移步 <a href="https://docs.docker.com/buildx/working-with-buildx/" target="_blank" rel="noopener noreferrer" class="">https://docs.docker.com/buildx/working-with-buildx/</a></p>
<p>利用 <code>docker buildx build --platform=linux/arm64 -f dev/Dockerfile.sample . -t edgehub/rpi-gpio-driver:v0.0.1 --push</code> 来构建镜像并推送到 <code>Docker Hub</code> 中。</p>
<p>至此，镜像打包部分完成。</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="第四步-部署设备孪生到树莓派中">第四步 部署设备孪生到树莓派中<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E7%AC%AC%E5%9B%9B%E6%AD%A5-%E9%83%A8%E7%BD%B2%E8%AE%BE%E5%A4%87%E5%AD%AA%E7%94%9F%E5%88%B0%E6%A0%91%E8%8E%93%E6%B4%BE%E4%B8%AD" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>有了镜像以后，我们可以将数字孪生部署到集群中，下面我们来准备部署所需要的文件。</p>
<p>首先是一个 <code>Kuberenetes Deployment YAML</code> 文件，用来运行 <em><strong>deviceShifu</strong></em> 和驱动的 <code>Pod</code>：</p>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> deviceshifu-rpi-gpio-deployment.yaml </summary><div><div class="collapsibleContent_i85q"><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> apps/v1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">labels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> default</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">replicas</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">selector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">matchLabels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">template</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">labels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">containers</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgehub/deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> deviceshifu</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">http</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">containerPort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8080</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">volumeMounts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">config</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">mountPath</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"/etc/edgedevice/config"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">readOnly</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_NAME</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"edgedevice-rpi-gpio"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_NAMESPACE</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"devices"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgehub/rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain">v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> driver</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">volumeMounts</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">mountPath</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> /dev/gpiomem</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> gpiomem</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">securityContext</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">privileged</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token boolean important" style="color:rgb(255, 88, 116)">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">containerPort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">11112</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">env</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_DRIVER_SSH_KEY_PATH</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"/etc/ssh/ssh_host_rsa_key"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_DRIVER_HTTP_PORT</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"11112"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_DRIVER_EXEC_TIMEOUT_SECOND</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"5"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EDGEDEVICE_DRIVER_SSH_USER</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">value</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"root"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">volumes</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">config</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">configMap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">configmap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> gpiomem</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">        </span><span class="token key atrule">hostPath</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">          </span><span class="token key atrule">path</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> /dev/gpiomem</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">      </span><span class="token key atrule">serviceAccountName</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">sa</span><br></span></code></pre></div></div></div></div></details>
<p>请注意在Deployment文件中我们为了在容器中使用树莓派的GPIO，需要在容器的 <code>securityContext</code> 中加入 <code>privileged: true</code> 再通过volume的形式将树莓派的 <code>/dev/gpiomem</code> 挂载到容器中。</p>
<p>一个 <code>Kubernetes Service YAML</code> 文件，用来将 <em><strong>deviceShifu</strong></em> 的请求从域名代理到真正的 <code>Pod</code>：</p>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> deviceshifu-rpi-gpio-service.yaml </summary><div><div class="collapsibleContent_i85q"><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Service</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">labels</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> default</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">ports</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain"> </span><span class="token key atrule">port</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">80</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">protocol</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> TCP</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">targetPort</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(247, 140, 108)">8080</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">selector</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">    </span><span class="token key atrule">app</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">deployment</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">type</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> LoadBalancer</span><br></span></code></pre></div></div></div></div></details>
<p>一个 <code>Kubernetes ConfigMap YAML</code> 文件，用来配置 <em><strong>deviceShifu</strong></em>：</p>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> deviceshifu-rpi-gpio-configmap.yaml </summary><div><div class="collapsibleContent_i85q"><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> ConfigMap</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">configmap</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> default</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">data</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">driverProperties</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">|</span><span class="token scalar string" style="color:rgb(195, 232, 141)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">    driverSku: RaspberryPiB+</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">    driverImage: edgenesis/rpi-gpio-python:v0.0.1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">    driverExecution: "python led_driver.py"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">instructions</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">|</span><span class="token scalar string" style="color:rgb(195, 232, 141)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">    pin:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">    operate:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">    help:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Telemetries are configurable health checks of the EdgeDevice</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># Developer/user can configure certain instructions to be usedas health check</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># of the device. In this example, the device_health telemetry ismapped to</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token comment" style="color:rgb(105, 112, 152);font-style:italic"># "get_status" instruction, executed every 1000 ms</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">telemetries</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(199, 146, 234)">|</span><span class="token scalar string" style="color:rgb(195, 232, 141)"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">    device_health:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">      properties:</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">        instruction: help</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">        initialDelayMs: 1000</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token scalar string" style="color:rgb(195, 232, 141)">        intervalMs: 1000</span><br></span></code></pre></div></div></div></div></details>
<p>在 <code>ConfigMap</code> 中我们需要配置驱动的执行路径，因为在生成镜像时我们将Python文件直接放到了默认路径下，在这里填写 <code>python led_driver.py</code> 即可。如果驱动是一个二进制文件的话这里直接填写二进制的目录即可。</p>
<p>一个 <code>Shifu EdgeDevice YAML</code> 文件，用来生成设备孪生：</p>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary> edgedevice-rpi-gpio-edgedevice.yaml </summary><div><div class="collapsibleContent_i85q"><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> shifu.edgenesis.io/v1alpha1</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> EdgeDevice</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> edgedevice</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">rpi</span><span class="token punctuation" style="color:rgb(199, 146, 234)">-</span><span class="token plain">gpio</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">namespace</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> devices</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">sku</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(195, 232, 141)">"RaspberryPi 3B+"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">connection</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> Ethernet</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">address</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> 0.0.0.0</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token number" style="color:rgb(247, 140, 108)">11112</span><span class="token plain"></span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">  </span><span class="token key atrule">protocol</span><span class="token punctuation" style="color:rgb(199, 146, 234)">:</span><span class="token plain"> HTTPCommandline</span><br></span></code></pre></div></div></div></div></details>
<p>将这四个文件放到树莓派中，目录内容如下：</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#bfc7d5;--prism-background-color:#292d3e"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#bfc7d5;background-color:#292d3e"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#bfc7d5"><span class="token plain">led-deploy/</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├──deviceshifu-rpi-gpio-configmap.yaml</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├──deviceshifu-rpi-gpio-deployment.yaml</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">├──deviceshifu-rpi-gpio-service.yaml</span><br></span><span class="token-line" style="color:#bfc7d5"><span class="token plain">└──edgedevice-rpi-gpio-edgedevice.yaml</span><br></span></code></pre></div></div>
<p>利用 <code>kubectl apply -f &lt;dir&gt;</code> 即可将 <em><strong>deviceShifu</strong></em> 部署到 <code>k3s</code> 集群中:</p>
<img src="https://shifu.dev/blog-220507/connect-8.png" width="100%">
<p>接着通过 <code>kubectl get pods</code> 来查看运行状态：</p>
<img src="https://shifu.dev/blog-220507/connect-9.png" width="100%">
<p>通过 <code>kubectl  get edgedevices -n devices</code> 来查看集群中的所有设备孪生：</p>
<img src="https://shifu.dev/blog-220507/connect-10.png" width="100%">
<p>再通过 <code>describe</code>，即可查看数字孪生的详细信息：</p>
<img src="https://shifu.dev/blog-220507/connect-11.png" width="100%">
<p>接下来我们就可以和设备互动了，在这里我们部署一个 <code>nginx</code> 容器来代表实际场景中的应用
部署命令为 <code>kubectl run nginx --image=nginx</code></p>
<p>接着执行 <code>kubectl exec -it nginx -- bash</code> 进入 <code>nginx</code> 的命令行：</p>
<img src="https://shifu.dev/blog-220507/connect-12.png" width="100%">
<p>最后，利用 <code>curl</code> 来给设备发送命令，驱动接受的命令格式为: <code>python led_driver --pin &lt;x&gt; --operate &lt;on/off&gt;</code></p>
<p>利用 <em><strong>Shifu</strong></em> 来发送命令的话将由HTTP转换到命令行，请求地址写法为: <code>http://edgedevice-rpi-gpio/pin?flags_no_parameter=&lt;pin&gt;,--operate,&lt;on/off&gt;</code></p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="运行效果-1">运行效果<a href="https://shifu.dev/zh-Hans/technical-blogs/2022/05/07/connect-private-driver#%E8%BF%90%E8%A1%8C%E6%95%88%E6%9E%9C-1" class="hash-link" aria-label="标题的直接链接" title="标题的直接链接" translate="no">​</a></h3>
<p>程序通过直接给设备的域名发送HTTP请求，即可操控LED灯泡的亮/灭：</p>
<img src="https://shifu.dev/blog-220507/connect-13.gif" width="100%">
<p>至此，将树莓派驱动接入 <em><strong>Shifu</strong></em> 完成</p>]]></content:encoded>
        </item>
    </channel>
</rss>