راهنمای توسعه گره قاعده

بررسی کلی

در این آموزش، نحوه ایجاد گره‌های قاعده سفارشی و افزودن آن‌ها به نمونه سرور ThingsConnect خود را خواهید آموخت. ما به بررسی گره‌های قاعده در سه دسته مختلف: فیلتر، غنی‌سازی و تبدیل خواهیم پرداخت.

پیش‌نیازها

فرض بر این است که شما راهنماهای زیر را تکمیل کرده و مقالات ذکر شده را مرور کرده‌اید:

  • راهنمای شروع کار.
  • مقاله مروری بر موتور قواعد.

همچنین فرض بر این است که نرم‌افزارهای جانبی زیر را نصب کرده‌اید:

  • OpenJDK 17

  • Maven 3.6.0+

  • هر IDE مدرن جاوا، هرچند IntelliJ IDEA توصیه می‌شود

  • [اختیاری] نصب افزونه Lombok برای IDE مورد علاقه شما.

گام ۱. دانلود و ساخت پروژه نمونه

مخزن را کلون کرده و به پوشه مخزن بروید:

				
					git clone -b release-3.7 https://github.com/thingsboard/rule-node-examples
cd rule-node-examples
				
			

به طور پیش‌فرض، پروژه نمونه به گونه‌ای پیکربندی شده که از API‌های نسخه Community از ThingsConnect استفاده می‌کند. این امر گره‌های قاعده شما را با هر دو نسخه Community و Professional پلتفرم سازگار می‌سازد.

در صورتی که بخواهید از برخی API‌های انحصاری نسخه Professional (مانند کار با گروه‌های موجودیت و غیره) استفاده کنید، باید پارامتر "ThingsConnect.version" را در فایل ThingsConnect.yml تغییر دهید:

				
					nano pom.xml
				
			

برای مثال، ویژگی زیر به نسخه 3.7.0PE از نسخه Professional Edition تنظیم شده است:

				
					...
    <properties>
        ...
        <thingsboard.version>3.7.0PE</thingsboard.version>
        ...
    </properties>
...
				
			

در نهایت، پروژه را بسازید:

				
					mvn clean install
				
			

خروجی مورد انتظار:

				
					...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.431 s
[INFO] Finished at: 2020-08-18T11:01:40+03:00
[INFO] ------------------------------------------------------------------------
				
			

گام ۲. وارد کردن پروژه به IDE

اطمینان حاصل کنید که افزونه Lombok به IDE مورد علاقه شما نصب شده است. پروژه را به عنوان یک پروژه Maven به IDE خود وارد کنید.

گام ۳. ایجاد گره قاعده

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

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

				
					@RuleNode(
        type = ComponentType.FILTER,
        name = "check key",
        relationTypes = {"True", "False"},
        configClazz = TbKeyFilterNodeConfiguration.class,
        nodeDescription = "Checks the existence of the selected key in the message payload.",
        nodeDetails = "If the selected key exists - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
        uiResources = {"static/rulenode/custom-nodes-config.js"},
        configDirective = "tbFilterNodeCheckKeyConfig")
public class TbKeyFilterNode implements TbNode {

    private static final ObjectMapper mapper = new ObjectMapper();

    private TbKeyFilterNodeConfiguration config;
    private String key;


    @Override
    public void init(TbContext tbContext, TbNodeConfiguration configuration) throws TbNodeException {
        this.config = TbNodeUtils.convert(configuration, TbKeyFilterNodeConfiguration.class);
        key = config.getKey();
    }

    @Override
    public void onMsg(TbContext ctx, TbMsg msg) {
        try {
            ctx.tellNext(msg, mapper.readTree(msg.getData()).has(key) ? "True" : "False");
        } catch (IOException e) {
            ctx.tellFailure(msg, e);
        }
    }

    @Override
    public void destroy() {
    }
}
				
			

چند نکته قابل توجه در کد منبع ذکر شده در بالا:

حاشیه‌نویسی @RuleNode

حاشیه‌نویسی @RuleNode نوع گره، نام، توضیحات، فرم رابط کاربری و [ارتباطات] خروجی را تعریف می‌کند.

بیایید به بررسی پارامترهای موجود بپردازیم:

  • type: یکی از انواع گره‌های قاعده موجود است. این پارامتر تعیین می‌کند که کدام بخش از ویرایشگر زنجیره قاعده شامل گره قاعده شما خواهد بود.

  • name: نامی معقول برای گره قاعده شما که در ویرایشگر زنجیره قاعده و پیام‌های اشکال‌زدایی استفاده خواهد شد.

  • nodeDescription: توضیح کوتاهی از گره شما. در ویرایشگر زنجیره قاعده قابل مشاهده است.

  • nodeDetails: توضیح کامل گره شما با پشتیبانی از تگ‌های HTML. در ویرایشگر زنجیره قاعده قابل مشاهده است.

  • configClazz: نام کامل کلاس که توصیف‌کننده JSON پیکربندی است.

  • relationTypes: آرایه‌ای از رشته‌ها با نوع‌های ارتباط از پیش‌تعریف‌شده؛ این مقادیر باید با آن‌هایی که در متد TbContext.tellNext استفاده می‌شود، مطابقت داشته باشد.

  • customRelations: مقدار boolean که نشان‌دهنده این است که قصد دارید از هرگونه ارتباط سفارشی در متد TbContext.tellNext استفاده کنید.

  • configDirective: نام دستورالعمل رابط کاربری مبتنی بر Angular که به کاربر این امکان را می‌دهد تا پیکربندی گره قاعده را ویرایش کند. این پارامتر اختیاری است و ممکن است خالی باشد. در این صورت، کاربر ویرایشگر JSON خام را مشاهده خواهد کرد.

  • uiResources: مسیر فایل Angular UI شما که حاوی دستورالعمل پیکربندی است. این پارامتر اختیاری است و ممکن است خالی باشد. در این صورت، کاربر ویرایشگر JSON خام را مشاهده خواهد کرد.

  • icon: نام آیکن از بسته Angular Material.

  • iconUrl: URL کامل به آیکنی که برای نمایش گره قاعده در لیست گره‌ها در ویرایشگر زنجیره قاعده استفاده خواهد شد.

  • docUrl: لینک به صفحه مستندات گره قاعده جاری که در ویرایشگر زنجیره قاعده در دسترس خواهد بود.

چرخه حیات گره قاعده

متد “init” توسط موتور قاعده هنگامی که گره قاعده جدیدی ایجاد می‌شود، فراخوانی می‌شود. این ممکن است زمانی اتفاق بیفتد که کسی گره قاعده را به زنجیره قاعده اضافه کند یا سیستم متوقف شود. این متد عمدتاً برای تجزیه پیکربندی که یک شیء JSON است یا برای به‌دست‌آوردن یک کپی محلی از TbContext استفاده می‌شود. متد “TbNodeUtils.convert” پیکربندی خام را به شیء جاوای کلاس مشخص‌شده تجزیه می‌کند.

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

زمانی که کاربر تصمیم به تغییر پیکربندی گره قاعده موجود می‌گیرد، موتور قاعده متدهای “destroy” و “init” را به ترتیب فراخوانی خواهد کرد.

پردازش پیام‌های ورودی

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

				
					/**
 * Indicates that message was successfully processed by the rule node.
 * Sends message to all Rule Nodes in the Rule Chain
 * that are connected to the current Rule Node using "Success" relationType.
 *
 * @param msg
 */
void tellSuccess(TbMsg msg);

/**
 * Sends message to all Rule Nodes in the Rule Chain
 * that are connected to the current Rule Node using specified relationType.
 *
 * @param msg
 * @param relationType
 */
void tellNext(TbMsg msg, String relationType);

/**
 * Sends message to all Rule Nodes in the Rule Chain
 * that are connected to the current Rule Node using one of specified relationTypes.
 *
 * @param msg
 * @param relationTypes
 */
void tellNext(TbMsg msg, Set<String> relationTypes);
				
			

اگر پردازش پیام ناموفق باشد، پیاده‌سازی گره قاعده باید متد “tellFailure” را فراخوانی کند:

				
					/**
 * Notifies Rule Engine about failure to process current message.
 *
 * @param msg - message
 * @param th  - exception
 */
void tellFailure(TbMsg msg, Throwable th);

				
			

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

استفاده از سرویس‌های Thingsconnect

TbContext شامل "getter"هایی برای بسیاری از سرویس‌های مفید است. لطفاً فراموش نکنید که در IDE مورد علاقه خود روی "Download Sources" کلیک کنید تا مرور رابط‌های این سرویس‌ها آسان‌تر شود؛ فهرستی کوتاه از getter‌های سرویس‌های موجود در زیر آورده شده است:

				
					// Allows to work with entity attributes: get and save them;
AttributesService getAttributesService();

// Allows CRUD (Create, Read, Updat, Delete) operations over the customer entities;
CustomerService getCustomerService();

// Allows CRUD operations over users;
UserService getUserService();

// Allows CRUD operations over assets;
AssetService getAssetService();

// Allows CRUD operations over devices;
DeviceService getDeviceService();

// Allows CRUD operations over entity views;
EntityViewService getEntityViewService();

// Allows to programmatically create and manage dashboards;
DashboardService getDashboardService();

// Allows to create and clear alarms;
RuleEngineAlarmService getAlarmService();

// Allows to programmatically create and manage rule chains;
RuleChainService getRuleChainService();

// Allows to send RPC commands to devices;
RuleEngineRpcService getRpcService();

// Allows to store telemetry to the database and push notifications to the dashbaords via WebSockets;
RuleEngineTelemetryService getTelemetryService();

// Allows to find telemetry and save it to the database without notifications to the dashboards;
TimeseriesService getTimeseriesService();

// Allows to programmatically query and manage entity relations;
RelationService getRelationService();

				
			

کاربران نسخه Thingsconnect PE می‌توانند از طریق متد TbContext.getPeContext() به سرویس‌های اضافی دسترسی پیدا کنند. TbPeContext دسترسی به سرویس‌های زیر را فراهم می‌کند:

				
					// Allows to programmatically create and manage integrations;
IntegrationService getIntegrationService();

// Allows to programmatically create and manage entity groups;
EntityGroupService getEntityGroupService();

// Allows to programmatically create reports;
ReportService getReportService();

// Allows to programmatically manage blob entities;
BlobEntityService getBlobEntityService();

// Allows to programmatically manage group permissions;
GroupPermissionService getGroupPermissionService();

// Allows to programmatically manage roles;
RoleService getRoleService();

// Get entity owner (TenantId or CustomerId)
EntityId getOwner(TenantId tenantId, EntityId entityId);

// Clear entity owners cache
void clearOwners(EntityId entityId);

// Get all sub-customers of the current entity
Set<EntityId> getChildOwners(TenantId tenantId, EntityId parentOwnerId);

// Allows to change entity owner. Expects TenantId or CustomerId as targetOwnerId
void changeDashboardOwner(TenantId tenantId, EntityId targetOwnerId, Dashboard dashboard) throws ThingsboardException;

void changeUserOwner(TenantId tenantId, EntityId targetOwnerId, User user) throws ThingsboardException;

void changeCustomerOwner(TenantId tenantId, EntityId targetOwnerId, Customer customer) throws ThingsboardException;

void changeEntityViewOwner(TenantId tenantId, EntityId targetOwnerId, EntityView entityView) throws ThingsboardException;

void changeAssetOwner(TenantId tenantId, EntityId targetOwnerId, Asset asset) throws ThingsboardException;

void changeDeviceOwner(TenantId tenantId, EntityId targetOwnerId, Device device) throws ThingsboardException;

void changeEntityOwner(TenantId tenantId, EntityId targetOwnerId, EntityId entityId, EntityType entityType) throws ThingsboardException;

// Allows to push custom downlink message to the integration
void pushToIntegration(IntegrationId integrationId, TbMsg tbMsg, FutureCallback<Void> callback);
				
			

ایجاد پیام‌های جدید از گره قاعده

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

				
					@Override
public void onMsg(TbContext ctx, TbMsg msg) {
    EntityId msgOriginator = msg.getOriginator();
    // Checking that the message originator is a Customer;
    if (EntityType.CUSTOMER.equals(msgOriginator.getEntityType())) {
        CustomerId customerId = new CustomerId(msgOriginator.getId());
        boolean hasNext = true;
        // Creating the page link to iterate through the devices;
        PageLink pageLink = new PageLink(1024);
        while (hasNext) {
            // Using the Device Service to get devices from the database;
            PageData<Device> devices = ctx.getDeviceService().findDevicesByTenantIdAndCustomerId(ctx.getTenantId(), customerId, pageLink);
            hasNext = devices.hasNext();
            pageLink = pageLink.nextPageLink();
            for (Device device : devices.getData()) {
                // Creating new message with different originator
                TbMsg newMsg = TbMsg.newMsg(msg.getQueueName(), msg.getType(), device.getId(), msg.getMetaData(), msg.getData());
                // Pushing new message to the queue instead of tellNext to make sure that the message will be persisted;
                ctx.enqueueForTellNext(newMsg, "Success");
            }
        }
        // Don't forget to acknowledge original message or use ctx.tellSuccess(msg);
        ctx.ack(msg);
    } else {
        ctx.tellFailure(msg, new IllegalArgumentException("Msg originator is not Customer!"));
    }
}
				
			

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

				
					void enqueue(TbMsg msg, String queueName, Runnable onSuccess, Consumer<Throwable> onFailure);
				
			

همچنین می‌توانید از یک متد کمی متفاوت استفاده کنید که به شما این امکان را می‌دهد تا تأییدی دریافت کنید که پیام جدید با موفقیت به صف ارسال شده است:

				
					void enqueueForTellNext(TbMsg msg, String queueName, String relationType, Runnable onSuccess, Consumer<Throwable> onFailure);
				
			

چند نخی (Multithreading)

موتور قاعده یک پیاده‌سازی از مدل بازیگر (Actor Model) است که متد TbNode.onMsg را برای هر پیام جدید در صندوق پیام‌های گره قاعده به صورت ترتیبی فراخوانی می‌کند. بنابراین، اگر پیام را در همان رشته (Thread) پردازش کنید، پیاده‌سازی شما ایمن از نظر رشته‌ای خواهد بود.

با این حال، به دلایل عملکردی، اکثر فراخوانی‌های API در رشته‌های جداگانه اجرا می‌شوند. برای مثال، بیایید بررسی کنیم که چگونه می‌توان اطلاعات تله‌متری را از پیام ورودی ذخیره کرد:

				
					@Override
public void onMsg(TbContext ctx, TbMsg msg) {
    try {
        // Parsing the incoming message;
        ObjectNode json = (ObjectNode) mapper.readTree(msg.getData());
        // Converting temperature from °F to °C
        double temperatureF = json.get("temperature").asDouble();
        double temperatureC = (temperatureF - 32) * 5 / 9;
        // Creating the telemetry data point
        TsKvEntry tsKvEntry = new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry("temperature", temperatureC));
        // Using async API call to save telemetry with the callback
        ctx.getTelemetryService().saveAndNotify(ctx.getTenantId(), msg.getOriginator(), Collections.singletonList(tsKvEntry), new FutureCallback<Void>() {
            @Override
            public void onSuccess(@Nullable Void aVoid) {
                // Telemetry is saved, now we can acknowledge the message; 
                ctx.tellSuccess(msg);
            }

            @Override
            public void onFailure(Throwable throwable) {
                // Telemetry is not saved, we need rule engine to reprocess the message;
                ctx.tellFailure(msg, throwable);
            }
        });
    } catch (JsonProcessingException e) {
        ctx.tellFailure(msg, e);
    }
}
				
			

ممکن است متوجه شده باشید که ما پیام را از طریق متد `TbContext.tellSuccess` در **رشته‌ی بازگشتی** (callback thread) و نه در رشته اصلی، "تأیید" (acknowledge) یا "ارسال" (forward) می‌کنیم.

حالت خوشه‌بندی (Clustering Mode)

برای هر سرویس کوچک (microservice) موتور قاعده، یک نمونه از گره قاعده اجرا می‌شود. به عنوان مثال، اگر سه نمونه از موتور قاعده داشته باشید، هر یک از آن‌ها یک نمونه از RuleNode را اجرا می‌کنند. پیام‌های موتور قاعده بر اساس شناسه منشاء (شناسه دستگاه یا دارایی) تقسیم‌بندی می‌شوند. بنابراین، پیام‌های یک دستگاه همیشه به یک نمونه گره قاعده در یک سرویس کوچک مشخص ارسال می‌شوند. تنها استثنا زمانی است که گره‌های قاعده اضافه یا حذف شوند. در چنین حالتی، رویداد "تقسیم‌بندی مجدد" (repartition) رخ می‌دهد.

به‌عنوان یک توسعه‌دهنده گره قاعده، می‌توانید متد پیش‌فرض TbNode.onPartitionChangeMsg را لغو کنید تا به تغییرات توپولوژی خوشه واکنش نشان دهید. این برای گره‌های دارای حالت (stateful) که تصمیم می‌گیرند اطلاعات را بر اساس شناسه منشاء (دستگاه/دارایی) پیام ذخیره کنند، مفید است. برای تعیین اینکه آیا شناسه موجودیت فعلی به لیست پارتیشن‌های اختصاص‌یافته تعلق دارد یا خیر، می‌توانید از متد TbContext.isLocalEntity استفاده کنید. به مثال کامل زیر مراجعه کنید:

				
					package org.thingsboard.rule.engine.node.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.rule.engine.api.EmptyNodeConfiguration;
import org.thingsboard.rule.engine.api.RuleNode;
import org.thingsboard.rule.engine.api.TbContext;
import org.thingsboard.rule.engine.api.TbNode;
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
import org.thingsboard.rule.engine.api.TbNodeException;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.kv.AttributeKvEntry;
import org.thingsboard.server.common.data.plugin.ComponentType;
import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;

import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;


@Slf4j
@RuleNode(
        type = ComponentType.FILTER,
        name = "Cache example",
        relationTypes = {"True", "False"},
        configClazz = EmptyNodeConfiguration.class,
        nodeDescription = "Checks that the incoming value exceeds certain threshold",
        nodeDetails = "If temperature is too high - send Message via <b>True</b> chain, otherwise <b>False</b> chain is used.",
        uiResources = {"static/rulenode/rulenode-core-config.js"},
        configDirective = "tbNodeEmptyConfig")
public class TbCacheExampleNode implements TbNode {

    private static final ObjectMapper mapper = new ObjectMapper();
    private ConcurrentMap<EntityId, Double> cache;

    @Override
    public void init(TbContext tbContext, TbNodeConfiguration configuration) throws TbNodeException {
        this.cache = new ConcurrentHashMap<>();
    }

    @Override
    public void onMsg(TbContext ctx, TbMsg msg) {
        try {
            // Parsing the incoming message;
            ObjectNode json = (ObjectNode) mapper.readTree(msg.getData());
            double temperature = json.get("temperature").asDouble();
            // Fetching temperatureThreshold attribute from cache or from the database
            Double temperatureThreshold = getCacheValue(ctx, msg.getOriginator(), "temperatureThreshold", 42);
            // Compare and do something with the result of comparison;
            ctx.tellNext(msg, temperature > temperatureThreshold ? "True" : "False");
        } catch (JsonProcessingException e) {
            ctx.tellFailure(msg, e);
        }
    }

    @Override
    public void onPartitionChangeMsg(TbContext ctx, PartitionChangeMsg msg) {
        // Cleanup the cache for all entities that are no longer assigned to current server partitions
        cache.entrySet().removeIf(entry -> !ctx.isLocalEntity(entry.getKey()));
    }

    private double getCacheValue(TbContext ctx, EntityId entityId, String attributeKey, double defaultValue) {
        // Get value from cache or from the database.
        return cache.computeIfAbsent(entityId, id -> {
            try {
                Optional<AttributeKvEntry> attr = ctx.getAttributesService().find(ctx.getTenantId(), entityId, DataConstants.SERVER_SCOPE, attributeKey).get();
                if (attr.isPresent()) {
                    return attr.get().getDoubleValue().orElse(defaultValue);
                } else {
                    return defaultValue;
                }
            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        });
    }


    @Override
    public void destroy() {
        // In case you have changed the configuration, it is good idea to clear the entire cache.
        cache.clear();
    }
}

				
			

مرحله ۴. وارد کردن گره‌های قانون سفارشی به نمونه Thingsconnect خود

پس از اتمام کدنویسی گره قانون، دستور ساخت را دوباره اجرا کنید:

				
					mvn clean install
				
			

سپس، فایل jar را به پروژه ThingsConnect خود به‌عنوان کتابخانه وابستگی اضافه کنید. نتیجه ساخت در اینجا قرار دارد:

				
					target/rule-engine-1.0.0-custom-nodes.jar
				
			

اکنون آماده‌اید تا فایل jar با گره‌های قانون خود را به نمونه ThingsConnect خود اضافه کنید:

  • از مرحله ۴.۱ استفاده کنید اگر ThingsConnect شما به‌عنوان یک سرویس نصب شده است.
  • از مرحله ۴.۲ استفاده کنید اگر ThingsConnect شما از منابع ساخته شده و به‌طور محلی از IDE شما اجرا می‌شود.

مرحله ۴.۱ افزودن فایل JAR به ThingsConnect نصب شده به‌عنوان یک سرویس

  • ابتدا، شما باید دستور زیر را برای کپی کردن فایل JAR به افزونه‌های ThingsConnect اجرا کنید:
				
					sudo cp rule-engine-1.0.0-custom-nodes.jar /usr/share/thingsboard/extensions/
				
			

سپس، دستور زیر را برای تغییر مالکیت به ThingsConnect اجرا کنید:

				
					sudo chown thingsboard:thingsboard /usr/share/thingsboard/extensions/*
				
			

سرویس ThingsConnect را مجدداً راه‌اندازی کنید:

				
					sudo service thingsboard restart
				
			

پس از راه‌اندازی مجدد ThingsConnect، نیاز است که کش مرورگر را پاک کنید و صفحه وب را تازه‌سازی کنید تا رابط کاربری گره‌های قانون بارگذاری شود.

مرحله ۴.۲ افزودن فایل JAR به ThingsConnect محلی که با استفاده از IDE راه‌اندازی شده است

  • برای IDEA و Eclipse دستورالعمل‌های جداگانه‌ای مشاهده کنید.

سپس، کانتینر سمت سرور ThingsConnect را مجدداً راه‌اندازی کنید. لطفاً به لینک زیر مراجعه کنید تا نحوه انجام این کار را مشاهده کنید: اجرای کانتینر سمت سرور.

پس از راه‌اندازی مجدد ThingsConnect، نیاز است که کش مرورگر را پاک کنید و صفحه وب را تازه‌سازی کنید تا رابط کاربری گره‌های قانون بارگذاری شود.

مرحله ۵. افزودن نام بسته سفارشی خود به فایل ThingsConnect.yml

توجه: اگر نام بسته را از org.ThingsConnect.rule.engine به نام بسته شرکت خود، مثلاً com.example.rule.engine تغییر داده‌اید، باید نام بسته خود را نیز در بخش پلاگین‌ها در فایل ThingsConnect.yml اضافه کنید:

				
					# Plugins configuration parameters
plugins:
  # Comma separated package list used during classpath scanning for plugins
  scan_packages: "${PLUGINS_SCAN_PACKAGES:org.thingsboard.server.extensions,org.thingsboard.rule.engine,com.example.rule.engine}"
				
			

مرحله ۶. عیب‌یابی گره قانون خود

ساده‌ترین روش برای اعتبارسنجی گره قانون سفارشی شما، ایجاد یک گره قانون تولیدکننده و اتصال آن به گره قانون سفارشی شماست. این کار یک جریان پیکربندی‌پذیر از پیام‌های ورودی تولید خواهد کرد. پس از انجام این کار، باید اشکال‌زدایی (debug) را برای گره قانون سفارشی خود فعال کنید تا خروجی گره را اعتبارسنجی کرده و آن‌ها را برای خطاها بررسی کنید.

مرحله ۷. سفارشی‌سازی رابط کاربری گره قانون (اختیاری)

رابط کاربری گره‌های قانون ThingsConnect با یک پروژه دیگر در مخزن رسمی GitHub پیکربندی شده است. لطفاً به لینک زیر مراجعه کنید تا دستورالعمل‌های ساخت را مشاهده کنید.

برای اجرای کانتینر رابط کاربری گره قانون در حالت بازسازی داغ (hot redeploy):

  • ابتدا باید مقدار ثابت ruleNodeUiforwardPort را از 8080 به 5000 در فایل proxy.conf.js که باید در اینجا قرار داشته باشد، تغییر دهید:
				
					nano ${TB_WORK_DIR}/ui-ngx/proxy.conf.js
				
			

دوم، شما باید کانتینر رابط کاربری را در حالت بازسازی داغ (hot redeploy) اجرا کنید. لطفاً به لینک زیر مراجعه کنید تا نحوه انجام این کار را مشاهده کنید: اجرای کانتینر رابط کاربری در حالت بازسازی داغ.

آخرین مرحله این است که دستور زیر را از دایرکتوری محلی خود با نام TB_RULE_NODE_UI_WORK_DIR اجرا کنید:

				
					 npm start
				
			

مراحل بعدی

  • راهنمای شروع سریع - این راهنماها نمای کلی سریعی از ویژگی‌های اصلی ThingsConnect ارائه می‌دهند و برای تکمیل آن‌ها به ۱۵-۳۰ دقیقه زمان نیاز است.
  • اتصال دستگاه‌های شما - یاد بگیرید چگونه دستگاه‌ها را بر اساس فناوری یا راه‌حل اتصال خود متصل کنید.
  • تصویربرداری داده‌ها - این راهنماها شامل دستورالعمل‌هایی برای پیکربندی داشبوردهای پیچیده ThingsConnect هستند.
  • پردازش و اقدامات داده‌ها - یاد بگیرید چگونه از موتور قوانین ThingsConnect استفاده کنید.
  • تحلیل داده‌های IoT - یاد بگیرید چگونه از موتور قوانین برای انجام وظایف تحلیل پایه استفاده کنید.
  • نمونه‌های سخت‌افزاری - یاد بگیرید چگونه پلتفرم‌های سخت‌افزاری مختلف را به ThingsConnect متصل کنید.
  • ویژگی‌های پیشرفته - با ویژگی‌های پیشرفته ThingsConnect آشنا شوید.

عناوین هر بخش