如何擴(kuò)展Shifu的西門(mén)子PLC驅(qū)動(dòng)能力

在上篇中我們分享了《如何利用Shifu接入私有驅(qū)動(dòng)的設(shè)備》。Shifu內(nèi)置了幾個(gè)常用的驅(qū)動(dòng),像是西門(mén)子S7系列的PLC,RTSP協(xié)議的攝像頭等。物聯(lián)網(wǎng)上的需求因人而異。在這次的文章中我們將介紹如何擴(kuò)展Shifu自帶驅(qū)動(dòng)的能力。

簡(jiǎn)介
本文是一個(gè)使用Shifu Framework的西門(mén)子PLC驅(qū)動(dòng)的擴(kuò)展指南,其中包含Linux, Python, Shifu Framework, Docker, Kubernetes的基本操作,任何開(kāi)發(fā)者都可以閱讀本文來(lái)學(xué)習(xí)Shifu Framework的開(kāi)發(fā)方法。
本文中的Shifu Framework架構(gòu)如下

file

北向通過(guò)"deviceshifu-http-http”容器向上開(kāi)放HTTP API接口,南向通過(guò)"siemens-plc-driver”容器來(lái)和實(shí)際設(shè)備交互

目標(biāo)

  1. 在本地運(yùn)行K8s集群并安裝Shifu Framework
  2. 修改西門(mén)子PLC的驅(qū)動(dòng)添加一個(gè)功能
  3. 打包驅(qū)動(dòng),生成容器鏡像
  4. 在Shifu中部署PLC的數(shù)字孿生
  5. 實(shí)現(xiàn)擴(kuò)展西門(mén)子PLC的能力

本次分享中用到的設(shè)備

  1. 開(kāi)發(fā)環(huán)境(本文中為運(yùn)行在Windows 11 Pro下面的WSL子系統(tǒng),系統(tǒng)為Ubuntu 20.04)
  2. 西門(mén)子PLC(支持S7協(xié)議即可,本文中用到的型號(hào)為西門(mén)子S7-1200系列)

需要的基本知識(shí)
-基本的Python
-Linux命令行基本操作(創(chuàng)建文件,安裝應(yīng)用,運(yùn)行程序)
-Docker/containerd基本操作
-K8s基本操作

步驟
第一步:在本地運(yùn)行Kubernetes(如果已安裝Shifu Framework,請(qǐng)直接跳到第三步)
為了運(yùn)行Shifu,我們需要一個(gè)Kubernetes的集群,這里不限制用戶使用的版本,本文中使用的是利用kind建立的測(cè)試Kubernetes集群。如果資源受限的話也可以考慮使用k3d或者microk8s。
kind的安裝教程:
https://kind.sigs.k8s.io/docs/user/quick-start/#installation
具體安裝步驟本文將不再贅述。
kind安裝完畢后可以通過(guò)“kind version”來(lái)查看當(dāng)前版本,本文中的版本為”v0.12.0”:

$ kind version 
kind v0.12.0 go1.17.8 linux/amd64

接下來(lái)使用“kind create cluster”創(chuàng)建集群,整個(gè)過(guò)程會(huì)持續(xù)幾分鐘,因網(wǎng)速而異:

$ kind create cluster 
Creating cluster "kind" ... 
 ? Ensuring node image (kindest/node:v1.23.4) ?? 
 ? Preparing nodes ?? 
 ? Writing configuration ?? 
 ? Starting control-plane ??? 
 ? Installing CNI ?? 
 ? Installing StorageClass ?? 
Set kubectl context to "kind-kind" 
You can now use your cluster with: 
 kubectl cluster-info --context kind-kind 
Not sure what to do next? ??  Check out https://kind.sigs.k8s.io/docs/user/quick-start/

創(chuàng)建完成后我們可以通過(guò)“kubectl get nodes”查看集群狀態(tài),當(dāng)顯示“Ready”即可:

$ kubectl get nodes 
NAME                 STATUS   ROLES                  AGE    VERSION 
kind-control-plane   Ready    control-plane,master   119s   v1.23.4 

至此,運(yùn)行K8s步驟完畢。

第二步:安裝Shifu
首先將Shifu項(xiàng)目克隆到本地,項(xiàng)目地址為:
https://github.com/Edgenesis/shifu.git
執(zhí)行命令為:
git clone https://github.com/Edgenesis/shifu.git

下面通過(guò)“kubectl apply -f shifu/k8s/crd/install/shifu_install.yml”即可一鍵將Shifu部署到k3s集群中:

$ kubectl apply -f k8s/crd/install/shifu_install.yml 
namespace/shifu-crd-system created 
customresourcedefinition.apiextensions.k8s.io/edgedevices.shifu.edgenesis.io created 
serviceaccount/shifu-crd-controller-manager created 
role.rbac.authorization.k8s.io/shifu-crd-leader-election-role created 
clusterrole.rbac.authorization.k8s.io/shifu-crd-manager-role created 
clusterrole.rbac.authorization.k8s.io/shifu-crd-metrics-reader created 
clusterrole.rbac.authorization.k8s.io/shifu-crd-proxy-role created 
rolebinding.rbac.authorization.k8s.io/shifu-crd-leader-election-rolebinding created 
clusterrolebinding.rbac.authorization.k8s.io/shifu-crd-manager-rolebinding created 
clusterrolebinding.rbac.authorization.k8s.io/shifu-crd-proxy-rolebinding created 
configmap/shifu-crd-manager-config created 
service/shifu-crd-controller-manager-metrics-service created 
deployment.apps/shifu-crd-controller-manager created 
namespace/devices created 
serviceaccount/edgedevice-sa created 
clusterrole.rbac.authorization.k8s.io/edgedevice-clusterrole created 
clusterrolebinding.rbac.authorization.k8s.io/edgedevice-clusterrolebinding created

至此,Shifu安裝完畢。

第三步:修改西門(mén)子PLC驅(qū)動(dòng)來(lái)添加新的功能

在IDE中打開(kāi)Shifu文件夾,本文使用的是VS Code。在"examples/siemensPLCDeviceShifu”目錄下打開(kāi)"siemens-plc.py”:
file

驅(qū)動(dòng)內(nèi)容如下(因長(zhǎng)度問(wèn)題只截取了一部分):

import os 
import sys 
import snap7 
from flask import Flask, request 
client = snap7.client.Client() 
app = Flask(__name__) 
ip = os.environ.get("PLC_ADDRESS") 
port = os.environ.get("PLC_CONTAINER_PORT") 
rack = os.environ.get("PLC_RACK") 
slot = os.environ.get("PLC_SLOT") 
def edit_single_bit(originalbyte, digitvalue, isset): 
? ? if digitvalue > 7: 
? ? ? ? digitvalue -= 8 
? ? ? ? changebyte = originalbyte[1] 
? ? ? ? if isset == 0: 
? ? ? ? ? ? return bytes([originalbyte[0]]) + bytes([changebyte & ~(1 << digitvalue)]) 
? ? ? ? else: 
? ? ? ? ? ? return bytes([originalbyte[0]]) + bytes([changebyte | (1 << digitvalue)])
? ? else: 
? ? ? ? changebyte = originalbyte[0] 
? ? ? ? if isset == 0: 
? ? ? ? ? ? return bytes([changebyte & ~(1 << digitvalue)]) + bytes([originalbyte[1]]) 
? ? ? ? else: 
? ? ? ? ? ? return bytes([changebyte | (1 << digitvalue)]) + bytes([originalbyte[1]]) 
@app.route('/sendsinglebit') 
def send_single_bit(): 
print("Changing single bit...") 

可以看到這個(gè)西門(mén)子PLC驅(qū)動(dòng)是一個(gè)Python程序,通過(guò)調(diào)用”snap7”這個(gè)API來(lái)實(shí)現(xiàn)和西門(mén)子PLC的通信,向上通過(guò)Flask開(kāi)放了若干個(gè)HTTP接口來(lái)供Shifu調(diào)用。

我們主要看一下關(guān)于修改PLC內(nèi)存值的“send_single_bit”這個(gè)函數(shù),首先,是這個(gè)API接收的參數(shù):

 rootaddress = request.args.get('rootaddress') 
 address = request.args.get('address', default=0, type=int) 
?start = request.args.get('start', default=0, type=int) 
?digit = request.args.get('digit', default=0, type=int) 
?value = request.args.get('value', default=0, type=int)

“rootaddress”定義了驅(qū)動(dòng)寫(xiě)入的類型,目前接受的類型如下:

if rootaddress == 'M': 
? ? ? ? area = snap7.types.Areas.MK 
elif rootaddress == 'Q': 
? ? ? ? area = snap7.types.Areas.PA 
elif rootaddress == 'C': 
? ? ? ? area = snap7.types.Areas.CT 
elif rootaddress == 'T': 
? ? ? ? area = snap7.types.Areas.TM

可以看到目前支持的”M”, “Q”, “C”, “T”四種類型,除了這四種以外,S7還支持”P(pán)E”, “DB”這兩種。今天我們就來(lái)添加”DB”的支持。

首先添加一個(gè)新的”rootaddress”的檢查,當(dāng)值為”DB”的時(shí)候?qū)ⅰ盿rea”變量設(shè)為”snap7.types.Areas.DB”:

代碼如下:


 elif rootaddress == 'DB': 
? ? ? ? area = snap7.types.Areas.DB

至此,驅(qū)動(dòng)修改完畢

第四步:打包驅(qū)動(dòng)并運(yùn)行PLC的數(shù)字孿生(deviceShifu)

接下來(lái)我們對(duì)這個(gè)驅(qū)動(dòng)進(jìn)行打包,在“siemensPLCDeviceShifu”中有一個(gè)現(xiàn)成的Dockerfile,我們直接利用它來(lái)對(duì)驅(qū)動(dòng)進(jìn)行打包,只需執(zhí)行“docker build . -t edgenesis/plc-device:v0.0.1”即可:

shifu/examples/siemensPLCDeviceShifu$ docker build . -t edgenesis/plc-device:v0.0.1 
[+] Building 65.0s (10/10) FINISHED                                                                                                                                                             
 => [internal] load build definition from Dockerfile                                                                                                                                      0.0s 
 => => transferring dockerfile: 298B                                                                                                                                                      0.0s 
 => [internal] load .dockerignore                                                                                                                                                         0.0s 
 => => transferring context: 2B                                                                                                                                                           0.0s 
 => [internal] load metadata for docker.io/library/python:3.9-slim-bullseye                                                                                                              11.4s 
 => [auth] library/python:pull token for registry-1.docker.io                                                                                                                             0.0s 
 => [1/4] FROM docker.io/library/python:3.9-slim-bullseye@sha256:dea558731860898a00ac0d004fcd67fff6a0a0d420af15d7ec4289fac5ab3df5                                                         8.5s 
 => => resolve docker.io/library/python:3.9-slim-bullseye@sha256:dea558731860898a00ac0d004fcd67fff6a0a0d420af15d7ec4289fac5ab3df5                                                         0.0s 
 => => sha256:1078a59cbb2c5273b0f18e6ad6b78aa01298be2b3a54365ed7ddf3b5d68f5c54 1.37kB / 1.37kB                                                                                            0.0s 
………………………………………. 
 => => extracting sha256:8c7a905e65a9f4baafcf16861113440e68c6144d7c3a7e701482086992492f70                                                                                                 0.2s 
 => [internal] load build context                                                                                                                                                         0.0s 
 => => transferring context: 3.91kB                                                                                                                                                       0.0s 
 => [2/4] COPY requirements.txt .                                                                                                                                                         0.2s 
 => [3/4] RUN pip install --no-cache-dir -r requirements.txt                                                                                                                             44.5s 
 => [4/4] COPY siemens-plc.py .                                                                                                                                                           0.0s 
 => exporting to image                                                                                                                                                                    0.2s 
 => => exporting layers                                                                                                                                                                   0.2s 
 => => writing image sha256:9c5802b3e55e0b9b498dc05be642b4aff1c60098531156af747469cc795a7120                                                                                              0.0s 
 => => naming to docker.io/edgenesis/plc-device:v0.0.1 

因?yàn)槭窃诒镜貓?zhí)行的,所以讓我們將這個(gè)驅(qū)動(dòng)的鏡像載入到kind集群中,命令為“kind load docker-image edgenesis/plc-device:v0.0.1”:

$ kind load docker-image edgenesis/plc-device:v0.0.1 
Image: "edgenesis/plc-device:v0.0.1" with ID "sha256:9c5802b3e55e0b9b498dc05be642b4aff1c60098531156af747469cc795a7120" not yet present on node "kind-control-plane", loading

在“examples/siemensPLCDeviceShifu/plc-deployment”文件夾中我們提供了四個(gè)文件,可以將PLC的數(shù)字孿生一鍵部署到Kubernetes集群中:

├── plc-deviceshifu-configmap.yaml 
├── plc-deviceshifu-deployment.yaml 
├── plc-deviceshifu-service.yaml 
└── plc-edgedevice.yaml

首先我們要修改PLC設(shè)備的地址,本教程中的PLC設(shè)備地址在“192.168.0.1”,我們需要修改“plc-deviceshifu-deployment.yaml”中的”P(pán)LC_ADDR”環(huán)境變量來(lái)讓我們的容器使用這個(gè)IP來(lái)進(jìn)行連接:

- name: PLC_ADDR 
 value: "192.168.0.1" 

改好后,我們就可以通過(guò)“Kubectl apply -f examples/siemensPLCDeviceShifu/plc-deployment”來(lái)部署

$ kubectl apply -f examples/siemensPLCDeviceShifu/plc-deployment/ 
configmap/plc-configmap-0.0.1 created 
deployment.apps/edgedevice-plc-deployment created 
service/edgedevice-plc created 
edgedevice.shifu.edgenesis.io/edgedevice-plc created

接下來(lái)讓我們運(yùn)行一個(gè)nginx應(yīng)用來(lái)演示如何與PLC進(jìn)行交互,命令為:

curl "edgedevice-plc/sendsinglebit?rootaddress=DB&address=<address>&start=<start>&digit=<digit>&value=<0/1>" 

最后一步:運(yùn)行效果

root@nginx:/# curl "edgedevice-plc/sendsinglebit?rootaddress=DB&address=0&start=0&digit=0&value=1";echo 
Changed from bytearray(b’\x00\x00’) to bytearray(b’\x01x00’) 
root@nginx:/# curl edgedevice-plc/getcontent?rootaddress=Q;echo 
0b0000000000000001 

至此,教程結(jié)束

總結(jié)

在此篇文章中,我們通過(guò)擴(kuò)展Shifu的西門(mén)子PLC驅(qū)動(dòng)的能力,實(shí)現(xiàn)了遠(yuǎn)程操縱改寫(xiě)PLC中DB的值。

可以看到,通過(guò)對(duì)驅(qū)動(dòng)能力的增加也增加了Shifu的能力。

本文中的更改并沒(méi)有提交到GitHub中,如果是您需要的需求,或者您剛好看到,不妨來(lái)我們的GitHub提交一個(gè)PR??第一個(gè)提交的人我們將會(huì)給您準(zhǔn)備一份小禮物以示感謝

非常感謝您看到了這里,我們期待您的反饋,如果覺(jué)得文章寫(xiě)得不錯(cuò)或者有任何建議請(qǐng)毫不猶豫地留言。

本文由博客群發(fā)一文多發(fā)等運(yùn)營(yíng)工具平臺(tái) OpenWrite 發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容