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

مقدمه

تینکر بورد اس یک کامپیوتر تک برد (SBC) است که برای علاقمندان و سازندگان DIY در سراسر جهان ارتقاء داده شده است و دارای دوام بیشتر، پایداری بهتر و تجربه کاربری بهبود یافته است. دارای حافظه داخلی eMMC با ظرفیت 16 گیگابایت برای افزایش عملکرد و پایداری است، همچنین یک شیار میکرواس‌دی برای انعطاف‌پذیری بیشتر. دارای پین روشن شدن خودکار برای سازندگان است که آزادی بیشتری را در زمان به واقعیت پیوستن ایده‌های خود به آن‌ها می‌دهد. تشخیص ورودی ولتاژ پایین برای جلوگیری از مشکلات برق و تضمین پایداری سیستم در صورت استفاده از منبع تغذیه غیر مورد تأیید. پین I2S بهبود یافته با حالت اسلیو و رابط برنامه نویسی نرم‌افزاری بهبود یافته برای سازگاری بهتر.

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

البته، ما قادر خواهیم بود دستگاه خود را با استفاده از قابلیت‌های ارائه شده مانند ویژگی‌های به اشتراک گذاشته شده یا درخواست‌های RPC کنترل کنیم.

پیشنیازها

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

  • Asus Tinker Board S
  •  کتابخانه 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” استفاده خواهیم کرد. بیایید پروژه‌ی خود را راه‌اندازی کنیم:

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 مشاهده کنید:

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

//img

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

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

 

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

//img

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

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

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

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

//img

 

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

 

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

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

//img

افزودن Entity Alias

 

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

  • حالت ویرایش را وارد کنید. بر روی دکمه‌ی مداد در گوشه‌ی پایین و سمت راست کلیک کنید.
  • روی آیکون “Entity Aliases” در بخش بالا و سمت راست صفحه کلیک کنید. لیست خالی از Entity aliases را خواهید دید.
  • بر روی “Add alias” کلیک کنید.
  • نام alias را وارد کنید، به عنوان مثال “OrangePI”. نوع فیلتر را به “Single entity” تنظیم کنید. نوع را “Device” وارد کرده و “My New” را تایپ کنید تا فعال شود. از میان گزینه‌های پیشنهادی دستگاه خود را انتخاب کرده و بر روی آن کلیک کنید.
  • بر روی “Add” و سپس “Save” کلیک کنید.
  • در نهایت، برای ذخیره کردن تغییرات، در ویرایشگر داشبورد بر روی “Apply changes” کلیک کنید. سپس باید به حالت ویرایش دوباره برگردید.

//img

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

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

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

فراموش نکنید ویژگی مشترک 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 خود را به مشترک در تابع اصلی متصل می‌کنیم.

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

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

//img

اگر یک داشبورد جدید ایجاد کنید، می‌توانید از ویجت “دکمه RPC” برای فراخوانی دوطرفه RPC استفاده کنید که در بسته “ویجت‌های کنترل” قرار دارد.

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

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

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

نتیجه

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

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

عناوین هر بخش