نحوه اتصال Banana Pi BPI-M5 به ThingsConnect

مقدمه

بانانا پای BPI-M5 یک کامپیوتر تک‌برد قدرتمند است که با پردازنده Realtek RTD 7682DD یا Rockchip RK3328 عرضه می‌شود.
این برد دارای گزینه‌های اتصال متنوعی از جمله اترنت، وای‌فای و بلوتوث است.
این برد برای مجموعه‌ای از کاربردهای مختلف از جمله مراکز رسانه‌ای، بازی‌ها و پروژه‌های هوش مصنوعی طراحی شده است.
با پردازنده قدرتمند و گزینه‌های اتصال گسترده‌ای که دارد، بانانا پای BPI-M5 یک انتخاب عالی برای توسعه‌دهندگان و علاقمندان به ساخت و ساز است.

در این راهنما، خواهیم آموخت که چگونه دستگاهی را در Thingsboard ایجاد کنیم، کتابخانه‌ها و ابزارهای مورد نیاز را نصب کنیم.
پس از آن، کد خود را تغییر داده و بر روی دستگاه آپلود کرده و نتایج برنامه‌نویسی خود را بررسی کنیم و با استفاده از داشبورد وارد شده، داده‌های خود را در ThingsBoard بررسی کنیم. دستگاه ما با استفاده از قابلیت درخواست‌های ویژگی‌های مشترک و مشتری همگام می‌شود.
البته، خواهیم توانست دستگاه خود را با استفاده از قابلیت‌های ارائه شده مانند ویژگی‌های مشترک یا درخواست‌های RPC کنترل کنیم.

پیشنیازها

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

  • Banana Pi BPI-M5
  • کتابخانه tb-mqtt-client
  • پایتون ≥ 3.7
  • Adafruit-Blinka
  • حساب ThingsBoard

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

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

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

//img

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

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

pip3 install tb-mqtt-client

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

برقراری ارتباط دستگاه با ThingsBoard

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

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

//Img

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

  • ایجاد پوشه پروژه:
mkdir thingsboard_example && cd thingsboard_example
  • نصب بسته‌ها:
pip install tb-mqtt-client
  • ایجاد اسکریپت اصلی:
nano main.py
  • لطفاً کد زیر را کپی و درج کنید:
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.

متغیرهای ضروری برای اتصال:

//جدول

  • برای ذخیره فایل، دکمه Ctrl+X را فشار داده و سپس کلید Ctrl+O را فشار دهید.
  • در نهایت، دستورات اسکریپت را شروع کنیم.
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” مشاهده کنید:

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

//img

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

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

 

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

//img

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

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

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

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

//img

 

 

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

 

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

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

//image

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

 

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

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

//img

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

  • وارد حالت ویرایش شوید. بر روی دکمه “اضافه کردن ویجت جدید” کلیک کنید.
  • بسته ویجت “نمودارها” را انتخاب کنید. بر روی سرآیند ویجت موجودیت‌ها کلیک کنید. پنجره “اضافه کردن ویجت” ظاهر می‌شود.
  • برای اضافه کردن منبع داده، بر روی “اضافه کردن” کلیک کنید. یک ویجت می‌تواند چندین منبع داده داشته باشد، اما در این حالت فقط از یک منبع استفاده خواهیم کرد.
  • مستعار موجودیت “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 استفاده می‌کنیم که هنگام تغییر مقدار ویژگی مشترک، فراخوانی می‌شود. و در نهایت، callback خود را به سابسکرایبر در تابع اصلی bind می‌کنیم.

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) را از برنامه‌های سمت سرور به دستگاه‌ها و برعکس ارسال کنید. در واقع، این ویژگی به شما امکان می‌دهد تا دستورها را به دستگاه‌ها ارسال و نتایج اجرای دستور را دریافت کنید.

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

//img

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

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’: {}}

نتیجه‌گیری

با دانشی که در این راهنما بیان شده است، شما به راحتی می‌توانید Banana Pi BPI-M5 خود را متصل کرده و داده‌ها را به ThingsBoard ارسال کنید.

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

عناوین هر بخش