نحوه اتصال ASUS Tinker Board 2S به ThingsConnect

مقدمه

تینکر برد 2S از شرکت ASUS یک رایانه تک برد قدرتمند و چند منظوره است. این برد دارای یک پردازنده Rockchip RK3399، 2 گیگابایت حافظه RAM و یک GPU Mali-T860MP4 می‌باشد. همچنین این برد از اتصالات شبکه از جمله Ethernet گیگابیت، Wi-Fi، بلوتوث و USB پشتیبانی می‌کند که به راحتی می‌توانید آن را به اینترنت یا سایر دستگاه‌ها متصل کنید. همچنین تینکر برد 2S یک اسلات PCIe نیز دارد که به شما امکان اضافه کردن سخت‌افزارهای دیگر مانند کنترلر SATA یا کارت شبکه را می‌دهد. در این راهنما، ما خواهیم آموخت که چگونه یک دستگاه را در Thingsboard ایجاد کنیم و کتابخانه‌ها و ابزارهای مورد نیاز را نصب کنیم. پس از آن، کد خود را تغییر داده و بر روی دستگاه بارگذاری کرده و نتایج برنامه‌نویسی خود را بررسی کرده و از طریق داشبورد وارد شده، داده‌ها را در ThingsBoard بررسی خواهیم کرد. دستگاه ما با استفاده از قابلیت درخواست‌های ویژگی‌های مشترک مشترک و کلاینت با ThingsBoard همگام می‌شود. البته، ما دستگاه خود را با استفاده از قابلیت‌های ارائه شده مانند ویژگی‌های مشترک یا درخواست‌های RPC کنترل خواهیم کرد.

پیشنیازها:

برای ادامه کار با این راهنما، موارد زیر را نیاز خواهیم داشت:

  • تینکر برد 2S از ASUS
  • کتابخانه tb-mqtt-client
  • پایتون ≥ 3.7
  • کتابخانه Adafruit-Blinka
  • حساب کاربری ThingsBoard

ایجاد دستگاه در ThingsBoard

برای سادگی، ما دستگاه را به صورت دستی با استفاده از رابط کاربری فراهم می کنیم.

  • وارد پنل ThingsBoard خود شوید و به بخش “موجودیت‌ها” مراجعه کنید. سپس صفحه “دستگاه‌ها” را انتخاب کنید.
  • روی نماد “+” در گوشه بالا و سمت راست جدول کلیک کنید و سپس “افزودن دستگاه جدید” را انتخاب کنید.
  • نام دستگاه را وارد کنید. به عنوان مثال، “دستگاه من”. در این مرحله تغییرات دیگری لازم نیست. برای اضافه کردن دستگاه، روی “افزودن” کلیک کنید.
  • دستگاه شما اضافه شده است.

//img

نصب کتابخانه‌ها و ابزارهای مورد نیاز

شما باید کتابخانه thingsboard-python-client-sdk را نصب کرده باشید که با استفاده از دستور زیر قابل نصب است. با این حال، توصیه می‌کنیم که بسته‌ها را در خارج از محیط جهانی نصب کنید:

pip3 install tb-mqtt-client

علاوه بر این، باید ابزارهایی داشته باشید که امکان ویرایش کد را فراهم کنند؛ به عنوان مثال، می‌توانید از ویرایشگر Nano استفاده کنید که به صورت پیشفرض در دسترس است یا هر ویرایشگر کد دیگری که با آن آشنایی دارید را نصب کنید.

اتصال دستگاه به ThingsBoard

برای اتصال دستگاه، ابتدا باید اطلاعات اعتبارهای دستگاه را دریافت کنید. ThingsBoard از انواع مختلف اعتبارهای دستگاه پشتیبانی می‌کند. ما توصیه می‌کنیم از اعتبارهای پیش‌فرض و خودکار تولید شده استفاده کنید که یک رمز امنیتی (Access Token) برای این راهنما است.

  • روی سطر دستگاه در جدول کلیک کنید تا جزئیات دستگاه باز شود.
  • روی “رونوشت کردن رمز امنیتی” کلیک کنید. رمز امنیتی در کلیپ‌بورد شما کپی می‌شود. لطفاً آن را در یک مکان امن ذخیره کنید.

/img

حالا شما آماده هستید تا داده‌های تلمتری را به نمایندگی از دستگاهتان منتشر کنید. همانطور که قبلاً اشاره شد، از کتابخانه “thingsboard-python-client-sdk” استفاده خواهیم کرد. بیایید پروژه‌ی خود را تنظیم کنیم:

1.ایجاد پوشه پروژه:

mkdir thingsboard_example && cd thingsboard_example

2.نصب بسته‌ها:

pip install tb-mqtt-client

3.ایجاد اسکریپت اصلی:

nano main.py

4. کد زیر را کپی و درج کنید:

import logging.handlers
import time
import os
   
from tb_gateway_mqtt import TBDeviceMqttClient
   
ACCESS_TOKEN = "TEST_TOKEN"
THINGSBOARD_SERVER = 'demo.thingsboard.io'
THINGSBOARD_PORT = 1883

logging.basicConfig(level=logging.DEBUG)
   
client = None
   
# default blinking period
period = 1.0
   
   
# callback function that will call when we will change value of our Shared Attribute
def attribute_callback(result, _):
     print(result)
     # make sure that you paste YOUR shared attribute name
     period = result.get('blinkingPeriod', 1.0)

# callback function that will call when we will send RPC
def rpc_callback(id, request_body):
    # request body contains method and other parameters
    print(request_body)
    method = request_body.get('method')
    if method == 'getTelemetry':
        attributes, telemetry = get_data()
        client.send_attributes(attributes)
        client.send_telemetry(telemetry)
    else:
        print('Unknown method: ' + method)
   
   
def get_data():
    cpu_usage = round(float(os.popen('''grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage }' ''').readline().replace('\n', '').replace(',', '.')), 2)
    ip_address = os.popen('''hostname -I''').readline().replace('\n', '').replace(',', '.')[:-1]
    mac_address = os.popen('''cat /sys/class/net/*/address''').readline().replace('\n', '').replace(',', '.')
    processes_count = os.popen('''ps -Al | grep -c bash''').readline().replace('\n', '').replace(',', '.')[:-1]
    swap_memory_usage = os.popen("free -m | grep Swap | awk '{print ($3/$2)*100}'").readline().replace('\n', '').replace(',', '.')[:-1]
    ram_usage = float(os.popen("free -m | grep Mem | awk '{print ($3/$2) * 100}'").readline().replace('\n', '').replace(',', '.')[:-1])
    st = os.statvfs('/')
    used = (st.f_blocks - st.f_bfree) * st.f_frsize
    boot_time = os.popen('uptime -p').read()[:-1]
    avg_load = (cpu_usage + ram_usage) / 2
   
    attributes = {
        'ip_address': ip_address,
        'macaddress': mac_address
    }
    telemetry = {
        'cpu_usage': cpu_usage,
        'processes_count': processes_count,
        'disk_usage': used,
        'RAM_usage': ram_usage,
        'swap_memory_usage': swap_memory_usage,
        'boot_time': boot_time,
        'avg_load': avg_load
    }
    print(attributes, telemetry)
    return attributes, telemetry
   
# request attribute callback
def sync_state(result, exception=None):
     global period
     if exception is not None:
         print("Exception: " + str(exception))
     else:
         period = result.get('shared', {'blinkingPeriod': 1.0})['blinkingPeriod']

def main():
     global client
     client = TBDeviceMqttClient(THINGSBOARD_SERVER, THINGSBOARD_PORT, ACCESS_TOKEN)
     client.connect()
     client.request_attributes(shared_keys=['blinkingPeriod'], callback=sync_state)
        
     # now attribute_callback will process shared attribute request from server
     sub_id_1 = client.subscribe_to_attribute("blinkingPeriod", attribute_callback)
     sub_id_2 = client.subscribe_to_all_attributes(attribute_callback)

     # now rpc_callback will process rpc requests from server
     client.set_server_side_rpc_request_handler(rpc_callback)

     while not client.stopped:
         attributes, telemetry = get_data()
         client.send_attributes(attributes)
         client.send_telemetry(telemetry)
         time.sleep(60)
   
if __name__=='__main__':
    if ACCESS_TOKEN != "TEST_TOKEN":
        main()
    else:
        print("Please change the ACCESS_TOKEN variable to match your device access token and run script again.")

در کد بالا، مقادیر متغیرهای زیر را به مشخصات خود تغییر دهید – THINGSBOARD_SERVER، ACCESS_TOKEN.

متغیرهای ضروری برای اتصال عبارتند از:

//جدول

5. برای ذخیره کردن فایل، کلیدهای Ctrl+X و سپس Ctrl+O را فشار دهید.
6. و در نهایت، بیایید اسکریپت خود را اجرا کنیم.

python3 main.py

اگر همه چیز را به درستی انجام داده باشید، باید خروجی کنسول زیر را مشاهده کنید:

> INFO:tb_device_mqtt:connection SUCCESS
> 
> 
> {'ip_address': '192.168.1.198', 'macaddress': '3c:06:30:44:e0:24'} {'cpu_usage': 6.6, 'processes_count': 8, 'disk_usage': 70.0, 'RAM_usage': 73.9, 'swap_memory_usage': 69.4, 'battery': 29, 'boot_time': 1675154176.0}
>

بیایید مروری داشته باشیم و توضیحی برای کدمان بدهیم. در این مرحله، علاقه‌مندی ما به تابع get_data است. در این تابع، داده‌ها بسته‌بندی شده و در نهایت برگشت داده می‌شوند، بنابراین اگر می‌خواهید مقادیر دیگری را نظارت کنید، به راحتی می‌توانید تلمتریها یا ویژگی‌های جدید را به دیکشنری اضافه کنید.

...
def get_data():
       cpu_usage = round(float(os.popen('''grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage }' ''').readline().replace('\n', '').replace(',', '.')), 2)
       ip_address = os.popen('''hostname -I''').readline().replace('\n', '').replace(',', '.')[:-1]
       mac_address = os.popen('''cat /sys/class/net/*/address''').readline().replace('\n', '').replace(',', '.')
       processes_count = os.popen('''ps -Al | grep -c bash''').readline().replace('\n', '').replace(',', '.')[:-1]
       swap_memory_usage = os.popen("free -m | grep Swap | awk '{print ($3/$2)*100}'").readline().replace('\n', '').replace(',', '.')[:-1]
       ram_usage = float(os.popen("free -m | grep Mem | awk '{print ($3/$2) * 100}'").readline().replace('\n', '').replace(',', '.')[:-1])
       st = os.statvfs('/')
       used = (st.f_blocks - st.f_bfree) * st.f_frsize
       boot_time = os.popen('uptime -p').read()[:-1]
       avg_load = (cpu_usage + ram_usage) / 2
   
       attributes = {
           'ip_address': ip_address,
           'macaddress': mac_address
       }
       telemetry = {
           'cpu_usage': cpu_usage,
           'processes_count': processes_count,
           'disk_usage': used,
           'RAM_usage': ram_usage,
           'swap_memory_usage': swap_memory_usage,
           'boot_time': boot_time,
           'avg_load': avg_load
       }
       print(attributes, telemetry)
       return attributes, telemetry
...

بخش ارسال داده، همانطور که در زیر مشاهده می‌کنید، ما ویژگی‌ها و داده‌های تلمتری را هر 60 ثانیه ارسال می‌کنیم (اگر می‌خواهید به‌طور متداول‌تر داده‌ها بروزرسانی شوند، لطفاً آن را تغییر دهید):

...		
    while not client.stopped:
        attributes, telemetry = get_data()
        client.send_attributes(attributes)
        client.send_telemetry(telemetry)
        time.sleep(60)
...

همگام‌سازی وضعیت دستگاه با استفاده از درخواست‌های کلاینت و ویژگی مشترک:

فراموش نکنید ویژگی مشترک “blinkingPeriod” را در دستگاه خود ایجاد کنید.

برای دریافت وضعیت دستگاه از ThingsBoard در زمان بوت کردن، قابلیتی در کد وجود دارد که این کار را انجام می‌دهد. بخش‌های مسئول در کد نمونه عبارتند از:

  • تابع بازخوانی ویژگی (Attribute callback):
def sync_state(result, exception=None):
    global period
    if exception is not None:
        print("Exception: " + str(exception))
    else:
        period = result.get('shared', {'blinkingPeriod': 1.0})['blinkingPeriod']
  • درخواست ویژگی (Attribute request):
def main():
    client = TBDeviceMqttClient("thingsboard.cloud", 1883, "ACCESS_TOKEN")
    client.connect()
    client.request_attributes(shared_keys=['blinkingPeriod'], callback=sync_state)
    ...

برای امکان دریافت داده‌ها توسط تابع‌های بازخوانی، بایستی یک درخواست به ThingsBoard ارسال کنیم. این قابلیت به ما اجازه می‌دهد تا پس از راه‌اندازی مجدد، وضعیت واقعی را حفظ کنیم.

بررسی داده‌ها در ThingsBoard

بعد از موفقیت‌آمیزی در انتشار ویژگی‌ها و داده‌های تلمتری، باید به سرعت آنها را در برگه “Device Telemetry” در پنل ThingsBoard مشاهده کنید:

  • روی ردیف دستگاه در جدول کلیک کنید تا جزئیات دستگاه باز شود.
  • به برگه تلمتری هدایت شوید.

//img

همچنین، بیایید ویژگی‌ها و داده‌های تلمتری را بر روی داشبورد نشان دهیم. برای این کار، شما می‌توانید یک داشبورد سفارشی با ابزارهای دلخواه خود ایجاد کنید یا از یک داشبورد آماده استفاده کنید و آن را به سادگی وارد کنید.

وارد کردن داشبورد

 

شما قادر به وارد کردن یک داشبورد به فرمت JSON هستید. برای وارد کردن یک داشبورد، باید به گروه داشبوردها بروید و روی دکمه “+” در گوشه بالا و سمت راست صفحه کلیک کنید و “وارد کردن داشبورد” را انتخاب کنید. پنجره وارد کردن داشبورد باید ظاهر شود و شما به آپلود کردن فایل JSON و کلیک بر روی “وارد کردن” دعوت خواهید شد.

//Img

در زیر میتوانید فایل JSON داشبورد را بیابید:

داشبورد بررسی و کنترل داده‌های دستگاه

پس از وارد کردن، باید برای دستگاهمان نام نماینده (entity alias) را انتخاب کنیم.
برای این کار – باید روی آیکون خودکار قلم بزنیم و “Entity Aliases” را انتخاب کنیم، نماینده “دستگاه من” را انتخاب کنیم و با فشردن آیکون خودکار قلم آن را برای ویرایش باز کنیم.
سپس یک دستگاه با نام “دستگاه من” را از لیست کشویی انتخاب کنید و نماینده را ذخیره کنید، حالا باید بتوانید داده‌ها را از دستگاه مشاهده کنید.

اگر همه چیز را به درستی انجام داده‌اید، باید داشبورد زیر را مشاهده کنید:

//img

 

ایجاد داشبورد جدید

 

ما یک داشبورد ایجاد خواهیم کرد و ابزارک‌های محبوب را اضافه خواهیم کرد. دستورالعمل‌های زیر را مشاهده کنید.

صفحه داشبوردها را باز کنید. روی نماد “+” در گوشه بالا و راست کلیک کنید. “ایجاد داشبورد جدید” را انتخاب کنید.
نام داشبورد را وارد کنید. به عنوان مثال، “داشبورد جدید من”. روی “اضافه کردن” کلیک کنید تا داشبورد را اضافه کنید.
اکنون داشبورد شما باید به عنوان اولین مورد لیست شود زیرا جدول داشبوردها را به طور پیش فرض بر اساس زمان ایجاد مرتب می‌کند. روی نماد “باز کردن داشبورد” کلیک کنید.

//img

افزودن نام مستعار موجودیت

 

نام مستعار یک ارجاع به یک موجودیت یا گروهی از موجودیت‌ها است که در ابزارک‌ها استفاده می‌شوند. یک نام مستعار می‌تواند ثابت یا پویا باشد. برای سادگی، ما از نام مستعار “موجودیت تکی” استفاده خواهیم کرد که به موجودیت یکتا (“OrangePI” در این مورد) ارجاع می‌دهد. ممکن است یک نام مستعار تنظیم شود که به چندین دستگاه ارجاع دهد. به عنوان مثال، دستگاه‌هایی از یک نوع خاص یا مرتبط با یک دارایی خاص. می‌توانید بیشتر در مورد نام مستعارهای مختلف اینجا بیاموزید.

  • حالت ویرایش را فعال کنید. روی دکمه مداد در گوشه پایین و راست کلیک کنید.
  • روی نماد “نام مستعار موجودیت” در بالای سمت راست صفحه کلیک کنید. لیست خالیی از نام مستعارهای موجودیت را خواهید دید.
  • روی “افزودن نام مستعار” کلیک کنید.
  • نام مستعار را وارد کنید، به عنوان مثال “OrangePI”. نوع فیلتر را “موجودیت تکی” انتخاب کنید. “دستگاه” را به عنوان نوع انتخاب کرده و “My New” را تایپ کنید تا قابلیت تکمیل خودکار فعال شود. از فهرست تکمیل خودکار دستگاه خود را انتخاب کنید و روی آن کلیک کنید.
  • روی “افزودن” و سپس “ذخیره” کلیک کنید.
  • در نهایت، برای ذخیره تغییرات روی “اعمال تغییرات” در ویرایشگر داشبورد کلیک کنید. سپس باید دوباره وارد حالت ویرایش شوید.

//img

برای اضافه کردن ویجت جدید، باید آن را از کتابخانه ویجت انتخاب کنیم. ویجت‌ها به بسته‌های ویجت تقسیم می‌شوند. هر ویجت دارای یک منبع داده است. این است که ویجت “می‌داند” کدام داده‌ها را نمایش دهد. برای دیدن آخرین مقدار داده “cpu_usage” که در مرحله ۲ ارسال کردیم، باید منبع داده را پیکربندی کنیم.

  • وارد حالت ویرایش شوید. روی دکمه “افزودن ویجت جدید” کلیک کنید.
  • بسته ویجت “نمودارها” را انتخاب کنید. روی سربرگ ویجت موجودیت‌ها کلیک کنید. پنجره “افزودن ویجت” ظاهر می‌شود.
  • روی “افزودن” کلیک کنید تا منبع داده را اضافه کنید. یک ویجت ممکن است دارای چندین منبع داده باشد، اما در این مورد فقط یک منبع داده را استفاده خواهیم کرد.
  • منبع داده “OrangePI” را انتخاب کنید. سپس روی فیلد ورودی در سمت راست کلیک کنید. تکمیل خودکار با نقاط داده موجود ظاهر خواهد شد. نقطه داده “cpu_usage” را انتخاب کنید و روی “افزودن” کلیک کنید.
  • اندازه ویجت را تغییر دهید تا کمی بزرگتر شود. فقط گوشه پایین و راست ویجت را بکشید. همچنین، اگر می‌خواهید ویجت را ویرایش کنید، می‌توانید با تنظیمات پیشرفته بازی کنید.

کنترل دستگاه با استفاده از ویژگی‌های مشترک:

فراموش نکنید ویژگی مشترک “blinkingPeriod” را در دستگاه خود ایجاد کنید.

همچنین، می‌توانیم با استفاده از قابلیت به‌روزرسانی ویژگی مشترک، دوره چشمک زنی را تغییر دهیم.

این نوع ویژگی فقط برای دستگاه‌ها در دسترس است. این شبیه ویژگی‌های سمت سرور است اما یک تفاوت مهم دارد. نرم‌افزار/برنامه دستگاه ممکن است درخواست مقدار ویژگی‌های مشترک را داشته باشد یا به به‌روزرسانی ویژگی‌ها مشترک شود. مورد استفاده رایج ویژگی‌های مشترک، ذخیره تنظیمات دستگاه است.

برای اجرای کد این بخش از راهنما، توصیه می‌کنیم از Python 3.9 یا بالاتر استفاده کنید.

اگر Python را نصب نکرده‌اید، لطفاً مراحل زیر را دنبال کنید:

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt install python3.9
sudo apt-get install -y python3 git python3-pip

همچنین، به کتابخانه Adafruit-Blinka نیاز خواهیم داشت. لطفاً از دستور زیر برای نصب آن استفاده کنید:

pip3 install Adafruit-Blinka

در حال حاضر، آماده‌ایم کد خود را بنویسیم. در این بخش، از پکیج‌های جدید برای چشمک‌زنی LED در تابع blink استفاده می‌کنیم. همچنین، از تابع attribute_callback استفاده می‌کنیم که هنگام تغییر مقدار ویژگی مشترک، فراخوانی می‌شود. و در نهایت، با استفاده از تابع اصلی (main)، تابع بازخوانی را به سابسکرایبر متصل می‌کنیم.

import digitalio
import board

...

# default blinking period
period = 1.0

# callback function that will call when we will change value of our Shared Attribute
def attribute_callback(client, result):
    print(client, result)
    # make sure that you paste YOUR shared attribute name
    period = result.get('blinkingPeriod', 1.0)

def main():
    ...
    # make sure that you paste YOUR shared attribute name
    sub_id_1 = client.subscribe_to_attribute("blinkingPeriod", attribute_callback)
    sub_id_2 = client.subscribe_to_all_attributes(attribute_callback)
    led = digitalio.DigitalInOut(board.PD14)
    led.direction = digitalio.Direction.OUTPUT
    ...
    led.value = True
    time.sleep(period)
    led.value = False
    time.sleep(period)

همچنین، اگر از داشبورد وارد شده استفاده می‌کنید، می‌توانید دوره چشمک زنی را با استفاده از ویجت زیر تغییر دهید که در گوشه پایین سمت راست داشبورد قرار دارد:

//img

کنترل دستگاه با استفاده از RPC

ThingsBoard به شما امکان ارسال فراخوانی‌های روشنایی از برنامه‌های سمت سرور به دستگاه‌ها و بالعکس را می‌دهد. در واقع، این قابلیت به شما امکان ارسال دستورات به دستگاه‌ها و دریافت نتایج اجرای دستور را می‌دهد.

در این راهنما، ما فرمان RPC را برای دریافت داده‌های تلمتری دستگاه OrangePI فوراً پیکربندی می‌کنیم. اگر از داشبورد وارد شده استفاده می‌کنید، نیازی به پیکربندی چیزی ندارید، زیرا در داشبورد شما می‌توانید ویجت زیر را مشاهده کنید:

//img

اگر یک داشبورد جدید ایجاد کرده‌اید، می‌توانید از ویجت “دکمه RPC” برای ارسال RPC یکطرفه استفاده کنید که در باندل “ابزارهای کنترل” قرار دارد.
در حال حاضر، آماده‌ایم کد خود را بنویسیم. ابتدا نیاز داریم تا یک تابع rpc_callback ایجاد کنیم که هنگام دریافت RPC از سرور فراخوانی خواهد شد. و همانند مثال با ویژگی‌های مشترک، نیاز داریم تا تابع rpc callback خود را با سابسکرایبر در تابع اصلی (main) متصل کنیم.

client = None

...

# callback function that will call when we will send RPC
def rpc_callback(id, request_body):
    # request body contains method and other parameters
    print(request_body)
    method = request_body.get('method')
    if method == 'getTelemetry':
        attributes, telemetry = get_data()
        client.send_attributes(attributes)
        client.send_telemetry(telemetry)
    else:
        print('Unknown method: ' + method)

...

def main():
    ...

    # now rpc_request_response will process rpc requests from server
    client.set_server_side_rpc_request_handler(rpc_callback)

    ...

بالاخره، بیایید دکمه را فشار دهیم و سعی کنیم داده‌های OrangePI را دریافت کنیم.

//img

همچنین، اگر همه چیز را به درستی انجام داده باشید، باید خروجی کنسول زیر را مشاهده کنید:

{‘method’: ‘getTelemetry’, ‘params’: {}}

نتیجه‌گیری

با دانشی که در این راهنما شرح داده شد، به راحتی می‌توانید ASUS Tinker Board 2S خود را به ThingsBoard متصل کرده و داده‌ها را ارسال کنید.

برای یادگیری بیشتر درباره مفاهیم کلیدی و ویژگی‌های پلتفرم، از مستندات پلتفرم استفاده کنید. به عنوان مثال، قوانین هشدار یا داشبوردها را پیکربندی کنید.

عناوین هر بخش