مراقبة درجة الحرارة في المؤسسة


جاءت المهمة للتوصل إلى "شيء" لعرض والتحكم في درجات الحرارة في المصنع. تم بالفعل تثبيت جهاز التحكم PLC 160 وتوصيل أجهزة استشعار درجة الحرارة عبر واجهة RS-485 ( ويكيبيديا ).

تم تثبيت وحدة التحكم وأجهزة الاستشعار قبلي.

كان هناك مثال على مخطط اتصال:


تستخدم CoDeSys ( ويكيبيديا ) لعرضها.

لم يكن هناك تاريخ من درجات الحرارة وليس من المعروف متى وقع الحادث.

بداية


جاءت الفكرة بهذه الطريقة - لإنشاء موقع ويب بالاشتراك مع قاعدة بيانات MySQL وتخزين المعلومات حول درجات الحرارة والحوادث هناك.

المهام الأولية:

  • عرض البيانات من أي جهاز كمبيوتر في المؤسسة
  • عرض حوادث وحوادث الحالية
  • عرض على الانترنت من القيم الحالية
  • تغيير الحد الأقصى والحد الأدنى للقيم لتسجيل التنبيه

فيما بعد اتضح ما يلي:

الحد الأدنى والحد الأقصى لا يكفي للسيطرة على الحوادث.

تمت إضافة الحد الأقصى الحرج والحد الأدنى الحرج ، وكذلك الوقت الذي يمكن أن تعود درجة الحرارة إلى وضعها الطبيعي.

  1. إذا تجاوزت درجة الحرارة الحد الأدنى أو الحد الأقصى ، لكنها عادت إلى وضعها الطبيعي خلال فترة T ، فهذا يعد حادثًا بسيطًا (ولكن تم تسجيل هذا الحادث على أنه غير مهم).

    صورة
  2. إذا تجاوزت درجة الحرارة الحد الأدنى أو الحد الأقصى الحرج ، فهذا يعد حادثًا خطيرًا على الفور.

    صورة

كان مطلوبًا للتمييز بين الوصول:

  • المسؤول - فقط بالنسبة لي)))
  • التكنولوجيون - تغيير 5 المعلمات لكل جهاز استشعار

    صورة
    اضطررت إلى إضافة تغييرات في معلمات الحادث في الوقت المناسب. هذا هو ، على سبيل المثال ، من 00:00 حتي 09:00 الحوادث لا يتم تسجيلها.

    صورة
  • المهندسين - المعايرة

    بشكل صحيح ، تحتاج إلى استخدام كمبيوتر محمول مع منفذ COM للتشبث بالوحدة للمعايرة. قررت تنفيذ نفس الشيء عبر WEB ، أي يأتي الشخص المعني بالمعايرة إلى المستشعر بواسطة مقياس الحرارة الخاص به ويعرض القيمة الفعلية على الموقع.

    صورة
  • كل شخص آخر - الرأي

جزء البرمجيات


تم إنشاء جهاز افتراضي مع مجموعة من PLC 160 عبر الشبكة المحلية.
تثبيت CoDeSys.

يتم تكوين عناوين IP بحيث يرى الكمبيوتر وحدة التحكم.

صورة

يقع المشروع على المسار c: \ project \ pro \ ويسمى my_work.pro .

يتم إطلاق المشروع نفسه من خلال ملف run.cmd

"C:\Program Files\3S Software\CoDeSys V2.3\Codesys.exe" "C:\project\pro\my_work.pro" /userlevel 0 /password 157999 /online 

يقوم التطبيق بتشغيل ملف run.cmd

 WinExec(Pchar(“c:\run.cmd”), SW_HIDE); 

لقد استخدمت DDE للحصول على قيم درجة الحرارة ( ويكيبيديا )

config.ini

 [CoDeSys] service=CoDeSys topic=C:\project\pro\my_work.pro item=C:\Program Files\3S Software\CoDeSys V2.3\ cmd=C:\run.cmd [db] host=127.0.0.1 port=3306 user=root key=keypassword db=workdb 

بدء البرنامج:

  1. قم بتنزيل معلمات تهيئة CoDeSys من "config.ini"

    تحميل معلمات التكوين MySQL من "config.ini"

    بواسطة Timer (تقرر أنه يكفي قراءة البيانات مرة واحدة في الدقيقة):

    • الحصول على عدد من أجهزة الاستشعار مع الخلية
    • لكل مستشعر ، قم بإنشاء مكون DDE.DDEConv :

       DDE.DDEConv[…]:= TDdeClientConv.Create(Self) DDE.DDEConv[…].ServiceApplication:=”patchcodesys” DDE.DDEConv[…].SetLink(“name”,”patchdde”) 

      نقوم بإنشاء المكون DDE.DDEItem وربطه بمكون DDE.DDEConv :

       DDE.DDEItem[…]:=TDdeClientItem.Create(Self) DDE.DDEItem[…].DdeConv:=DDE.DDEConv[…] 

      نمرر اسم المستشعر مع MySQL :

       DDE.DDEItem[…].DdeItem:=MySQL.GetSensorName(…) 

      نتيجة لذلك ، نحصل على قيمة درجة الحرارة:

       DDE.DDEItem[…].Text 

      نحفظ قيمة درجة الحرارة الحالية ومعلماتها لكل جهاز استشعار.

       MySQL.InsertTemp(MySQL.GetSensorName(...),””,INSQL(UMin[...]),INSQL(UMax[...]),INSQL(CRMin[...]),INSQL(CRMax[...])) 

    • نحصل عليها من MySQL في التاريخ والوقت الحاليين:

      الحد الأدنى

       UMin[I…]:=OUTSQL(MySQL.GetMin(MySQL.GetSensorName(…))) 

      كحد أقصى.

       UMax[…]:=OUTSQL(MySQL.GetMax(MySQL.GetSensorName(...))) 

      الحد الأدنى الحرج

       CRMin[…]:=OUTSQL(MySQL.GetCriticalMin(MySQL.GetSensorName(…))) 

      الحد الأقصى الحرج

       CRMax[…]:=OUTSQL(MySQL.GetCriticalMax(MySQL.GetSensorName(…))) 

      وقت

       CRTime[…]:=MySQL.GetCriticalTime(MySQL.GetSensorName(…)) 

      ملاحظة: "الحماية من الخداع " - إذا كان الحد الأدنى أكبر من الحد الأقصى أو العكس - فنحن نغير هذه القيم في الأماكن.

       if (UMin[…]>=UMax[…]) then begin UM[…]:=UMin[…]; UMin[…]:=UMax[…]; UMax[…]:=UM[…]; end; 

    • الحادث:

      إذا لم يكن هناك أي حادث ، قم بإنشاء سجل

       MySQL.InsertCrash(FormatDateTime('yyyy-mm-dd hh:nn:ss', dt),FormatDateTime('yyyy-mm-dd hh:nn:ss', dt),MySQL.GetSensorName(...),…) 

      إذا كان هناك حادث نقوم بتحديث

       MySQL.UpdateCrash(MySQL.GetCrashID(MySQL.GetSensorName(...)),FormatDateTime('yyyy-mm-dd hh:nn:ss', dt),…) 

      انتهى الحادث.

    موقع الويب


    كتب الصفحات في PHP .

    الصفحة الرئيسية (جزء من الكود ، لا ترفس كثيرًا):

     <?php require 'config.php'; session_start(); $page = isset( $_GET['page'] ) ? $_GET['page'] : ""; switch ( $page ) { case 'login': login(); break; case 'logout': logout(); break; case 'list': listpage(); break; ………………….. ?> 

    الصفحات المتبقية هي تقريبا من نفس النوع. كل صفحة تعالج بياناتها.

    ما تم القيام به:

    • قائمة أجهزة الاستشعار. الأسماء ، اسم المستشعر للبرنامج ، نوع المستشعر.

      صورة
    • تم تجميع مجسات حسب الغرض.

      صورة
    • "حالات الحوادث" المضافة: في عملية وقوع حادث ، أكمل حادث ، حادث خطير.
    • نفذت مضيفا المستخدمين وأدوارهم.
    • تسجيل من فعل ما.
    • أرشيف جميع الحوادث.
    • الرسومات.

    ركائز


    1. عند بدء تشغيل برنامج CoDeSys ، تظهر نافذة:

      صورة
      نحن إغلاقها برمجيا.

       W_WND_Button_Run: HWND: W_WND_RUN: HWND; C_Button_Message='Button'; C_CoDeSys_Message='CoDeSys'; W_WND_RUN := FindWindow(nil,C_CoDeSys_Message); if W_WND_RUN<>0 then begin W_WND_Button_Run:=FindWindowEx(W_WND_RUN, 0,C_Button_Message, nil); if W_WND_Button_Run<>0 then begin SendMessage(W_WND_Button_Run, WM_LBUTTONDOWN, 10, 10); SendMessage(W_WND_Button_Run, WM_LBUTTONUP, 10, 10); SendMessage(W_WND_Button_Run, WM_LBUTTONDOWN, 10, 10); SendMessage(W_WND_Button_Run, WM_LBUTTONUP, 10, 10); end; end; 

    2. فجأة تم إيقاف تشغيل وحدة التحكم.

      صورة

       W_WND_Error:=FindWindow(nil,''); if W_WND_Error<>0 then begin W_WND_Button_Error:=FindWindowEx(W_WND_Error,0,'Button', nil); if W_WND_Button_Error<>0 then begin SendMessage(W_WND_Button_Error, WM_LBUTTONDOWN, 10, 10); SendMessage(W_WND_Button_Error, WM_LBUTTONUP, 10, 10); SendMessage(W_WND_Button_Error, WM_LBUTTONDOWN, 10, 10); SendMessage(W_WND_Button_Error, WM_LBUTTONUP, 10, 10); PostMessage(FindWindow(PChar(C_CoDeSys),nil), WM_QUIT, 0, 0); end; end; 

    3. شنق غير مفهومة.

      صورة

      نعيد تشغيل التطبيق.

       C_CLOSE_DEBUG='CoDeSys for Automation Alliance (debug)'; W_WND_CLOSE:=FindWindow(nil,C_CLOSE_DEBUG); if W_WND_CLOSE<>0 then begin KillProcess('Codesys.exe'); KillProcess('WerFault.exe'); PostMessage(FindWindow(PChar(C_Close_DEBUG),nil), WM_QUIT, 0, 0); PostMessage(FindWindow(PChar(C_CoDeSys),nil), WM_QUIT, 0, 0); MySQL.InsertLog('Error debug.. Kill process - codesys.exe and WerFault.exe'); MySQL.InsertLog('Restart programm'); RestartThisApp; end; //  function KillProcess(ExeName: string): LongBool; var B: BOOL; ProcList: THandle; PE: TProcessEntry32; begin Result := False; ProcList := CreateToolHelp32Snapshot(TH32CS_SNAPPROCESS, 0); PE.dwSize := SizeOf(PE); B := Process32First(ProcList, PE); while B do begin if (UpperCase(PE.szExeFile) = UpperCase(ExtractFileName(ExeName))) then Result := TerminateProcess(OpenProcess($0001, False, PE.th32ProcessID), 0); B:= Process32Next(ProcList, PE); end; CloseHandle(ProcList); end; //  procedure TForm1.RestartThisApp; begin ShellExecute(Handle, nil, PChar(Application.ExeName), nil, nil, SW_SHOWNORMAL); Application.Terminate; // or, if this is the main form, simply Close; end; 

    ZABBIX


    أنشئ مضيفًا بعنوان 127.0.0.1 .

    لديها قاعدة الكشف المسمى "مجسات".

    صورة

    صورة

    النماذج الأولية لعناصر البيانات.

    صورة

    مشغلات النموذج الأولي.

    صورة

    أضف إلى zabbix_agentd.conf

     UserParameter=sensors[*],/usr/lib/zabbix/alertscripts/sensors.sh UserParameter=crash[*],/usr/lib/zabbix/alertscripts/crash.sh $1 

    النصوص نفسها:

    sensors.sh

     #!/bin/sh unset id unset res id=(`echo "select id FROM sensor WHERE type='1'" | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null`) echo '{ "data": [' for (( count=1; count<${#id[@]}; count++ )) do res=(`echo "select name FROM sensor WHERE (type='1' and id='${id[$count]}') " | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null `) r={${res[@]} l=${#r} res1=(`echo "select param FROM sensor WHERE (type='1' and id='${id[$count]}') " | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null `) r1={${res1[@]} l1=${#r1} res2=(`echo "select ddename FROM sensor WHERE (type='1' and id='${id[$count]}') " | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null `) r2={${res2[@]} l2=${#r2} res3=(`echo "select min FROM temp_${r2:17:l2} ORDER BY id DESC LIMIT 1 " | mysql -uroot -ps -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null`) r3={${res3[@]} l3=${#r3} res4=(`echo "select max FROM temp_${r2:17:l2} ORDER BY id DESC LIMIT 1 " | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null`) r4={${res4[@]} l4=${#r4} res5=(`echo "select cmin FROM temp_${r2:17:l2} ORDER BY id DESC LIMIT 1 " | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null`) r5={${res5[@]} l5=${#r5}2>/dev/null res6=(`echo "select cmax FROM temp_${r2:17:l2} ORDER BY id DESC LIMIT 1 " | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null`) r6={${res6[@]} l6=${#r6} res7=(`echo "select param FROM temp_${r2:17:l2} ORDER BY id DESC LIMIT 1 " | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null`) r7={${res7[@]} l7=${#r7} s=$s'{ "{#SID}": "'${id[$count]}'", "{#SNAME}": "'${r:5:l}'", "{#SDDENAME}": "'${r2:17:l2}'" , "{#SPARAM}": "'${r7:7:l7}'", "{#SMIN}": "'${r3:5:l3}'", "{#SMAX}": "'${r4:5:l4}'", "{#SCMIN}": "'${r5:6:l5}'", "{#SCMAX}": "'${r6:6:l6}'" },' done a=${#s} b=${s: 0: $a-1} c=${#b} d=$b echo $d']}' 

    crash.sh

     #!/bin/sh a=$1 unset res res=(`echo "select flag, id_status FROM crash WHERE id_sensor='$a' ORDER BY id DESC LIMIT 1 " | mysql -uroot -p -D workdb -h 0.0.0.0 --default-character-set=utf8 2>/dev/null `) for (( count=2; count<${#res[@]}; count++ )) do s=$s' '${res[$count]} done b=${s:0:2} c=${s:3:4} if [ $b = 0 -a $c = 1 ] then echo 0 else echo 1 fi 

    ثم من خلال zabbix ، يمكنك إرسالها إلى البريد والرسائل النصية وغير ذلك الكثير.

    يؤدي


    وكانت النتيجة نظام مراقبة درجة الحرارة في المؤسسة مع مراجعة الحوادث الحالية والسابقة.

    صورة

    اقرأ المزيد عن الحادث.

    صورة

    في الوقت الحالي ، يتم إضافة أجهزة استشعار لفتح / إغلاق الأبواب.

    الايجابيات:

    • الحد الأدنى من التكاليف ( النسبية ).
    • بالإضافة إلى الكرمة (؟).
    • تم تشغيل المراقبة لمدة 3 سنوات.

    سلبيات:

    • العديد من نقاط الفشل: التحكم ، الشبكة ، برنامج CoDeSys ، الجهاز الظاهري ، MySQL ، IIS .

    PS

    لا ترفس كثيرا. هذا هو مقالي الأول.

Source: https://habr.com/ru/post/ar470822/


All Articles