نحوه اتصال BeagleBone Green Wireless به ThingsConnect

مقدمه

BeagleBone Green Wireless یک کامپیوتر تک برد بازمتن بر پایه طراحی BeagleBone Black است که با هزینه کم تولید شده است.
این کامپیوتر شامل اتصال Wi-Fi و بلوتوث است و برای برنامه‌های اینترنت اشیا (IoT) و پروژه‌های دیگری که نیازمند ارتباط بی‌سیم هستند، ایده‌آل است.

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

پیشنیازها

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

  • BeagleBone Green Wireless
  • کتابخانه tb-mqtt-client
  • پایتون ≥ 3.7
  • Adafruit-Blinka
  • حساب کاربری 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 علاقه‌مند هستیم. در تابع 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
...

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

...		
    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

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

 

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

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

//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” استفاده می‌کنیم که هنگام تغییر مقدار ویژگی مشترک ما فراخوانی می‌شود. و در نهایت، تابع callback خود را به مشترک (subscriber) در تابع اصلی متصل می‌کنیم.

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 را برای دریافت داده‌های تلمتری OrangePI فوراً پیکربندی خواهیم کرد. اگر از داشبورد وارد شده استفاده می‌کنید، شما نیازی به پیکربندی هیچ چیزی ندارید، زیرا در داشبورد شما می‌توانید ویجت زیر را مشاهده کنید:

//img

اگر یک داشبورد جدید ایجاد کنید، می‌توانید از ویجت “دکمه RPC” برای RPC یکطرفه استفاده کنید که در مجموعه “ابزارهای کنترل” قرار دارد.
در حال حاضر، آماده هستیم کد خود را بنویسیم. ابتدا نیاز داریم به تابع “rpc_callback” که هنگام دریافت RPC از سرور فراخوانی می‌شود. و مانند مثال با ویژگی‌های مشترک، نیاز داریم تا تابع فراخوانی 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’: {}}

نتیجه‌گیری

با دانشی که در این راهنما بررسی شد، می‌توانید به راحتی دستگاه BeagleBone Green Wireless خود را به ThingsBoard متصل کرده و داده‌ها را ارسال کنید.

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

عناوین هر بخش