Примеры драйверов
Пример, который можно проверить без оборудования, — драйвер для Local-транспорта (loopback). Local не выходит в сеть: всё, что драйвер «отправил», сразу возвращается к нему как полученное. Поэтому на нём можно учиться: написать драйвер, нажать «Развернуть» (кнопка U-Logic, которая запускает правки программы в работу) и сразу увидеть результат без устройства, адреса и порта. Так же проверяют логику драйвера до выезда на объект.
Как писать драйвер для настоящего устройства — на странице Как написать драйвер. Если нужен драйвер по описанию протокола, начните с наброска от ИИ — AI-Driver.
Драйвер для Local-транспорта
Драйвер умеет пять команд: вернуть сообщение, посчитать, увеличить счётчик, прочитать счётчик и показать, сколько он работает. Счётчик хранится в общей памяти U-Logic, в контексте global. Откуда берётся контекст в драйвере, описано на странице Расширенные возможности.
const BaseDriver = require('base-driver');
class LoopbackDemoDriver extends BaseDriver {
static metadata = {
name: 'Loopback Demo',
manufacturer: 'Dynamic Driver',
version: '1.0.0',
description: 'Драйвер для проверки без устройства (Local-транспорт)',
parameters: [
{ name: 'counterKey', default: 'demoCounter' }
]
};
static commands = {
Echo: {
description: 'Вернуть переданное сообщение',
parameters: [
{ name: 'message', type: 'string', description: 'Сообщение', default: 'Привет!' }
]
},
Calculate: {
description: 'Выполнить арифметическое действие',
parameters: [
{ name: 'a', type: 'number', required: true },
{ name: 'b', type: 'number', required: true },
{ name: 'operation', type: 'string', enum: ['add', 'sub', 'mul', 'div'], default: 'add' }
]
},
IncrementCounter: {
description: 'Увеличить счётчик',
parameters: [
{ name: 'step', type: 'number', default: 1 }
]
},
GetCounter: {
description: 'Прочитать счётчик'
},
GetStatus: {
description: 'Сколько секунд работает драйвер'
}
};
constructor(options) {
super(options);
this.startTime = Date.now();
}
// Команда возвращает строку JSON. Local сразу отдаёт её обратно как «полученные данные».
Echo(params) {
return JSON.stringify({
command: 'Echo',
message: params.message || 'Привет!',
time: new Date().toISOString()
});
}
Calculate(params) {
const a = Number(params.a) || 0;
const b = Number(params.b) || 0;
const operation = params.operation || 'add';
let result = null;
let error = null;
switch (operation) {
case 'add': result = a + b; break;
case 'sub': result = a - b; break;
case 'mul': result = a * b; break;
case 'div':
if (b === 0) error = 'Деление на ноль';
else result = a / b;
break;
default:
error = `Неизвестная операция: ${operation}`;
}
return JSON.stringify({ command: 'Calculate', a, b, operation, result, error });
}
IncrementCounter(params) {
const key = this.config.counterKey || 'demoCounter';
const step = Number(params.step) || 1;
const previous = global.get(key) || 0;
global.set(key, previous + step);
return JSON.stringify({
command: 'IncrementCounter',
previousValue: previous,
step,
newValue: previous + step
});
}
GetCounter() {
const key = this.config.counterKey || 'demoCounter';
return JSON.stringify({ command: 'GetCounter', value: global.get(key) || 0 });
}
GetStatus() {
return JSON.stringify({
command: 'GetStatus',
uptimeSeconds: Math.floor((Date.now() - this.startTime) / 1000)
});
}
// Ответ приходит как обёртка: текст лежит в data.data
parseResponse(data) {
const text = String(data.data);
try {
return JSON.parse(text);
} catch (e) {
return { error: 'Ответ не удалось разобрать', raw: text };
}
}
}
module.exports = LoopbackDemoDriver;
Что показывает этот пример:
Что |
Где в коде |
|---|---|
параметр подключения со значением по умолчанию |
|
параметры команд: число, строка, список значений, значение по умолчанию |
|
команда без параметров |
|
команда возвращает строку, а не |
любой метод команды — см. Методы команд |
разбор ответа вручную |
|
Разбор устроен так: ответа в static responses у драйвера нет, поэтому каждый ответ достаётся parseResponse. Он возвращает объект без поля type, а ответ без типа device - response - listener отдаёт на первый выход. О типах ответов и о выборе выхода — на странице Ответы устройства.
Как проверить
Откройте редактор драйверов (Редактор драйверов). Создайте новый драйвер с именем
LoopbackDemo, вставьте код выше и сохраните. Должно появиться зелёное сообщение «Сохранено».Добавьте на рабочую область узлы Inject,
device - command,device - response - listenerи Debug и соедините их: Inject —device - command, выходdevice - response - listener— Debug.Откройте
device - commandи рядом с полем «Соединение» создайте новое соединение: узел Device Connection (драйвер плюс транспорт к одному конкретному устройству, см. Device Connection: подключение драйвера к транспорту):«Драйвер» —
LoopbackDemo;«Транспорт» —
Local (loopback);в поле «Local Config» создайте новый узел и сохраните его, не меняя поля (в нём только название и отладка; см. Local (loopback)).
В
device - commandвыберите командуCalculateи заполните параметры:a— 10,b— 5,operation—mul.Откройте
device - response - listener, выберите то же соединение, в «Выходы» оставьте 1.Нажмите «Развернуть», затем кнопку на узле Inject.
Что вы увидите: в панели отладки появится сообщение, в msg.payload которого — объект:
{
command: 'Calculate',
a: 10,
b: 5,
operation: 'mul',
result: 50,
error: null
}
Проверьте остальное:
Измените
operationнаdivиbна 0, снова разверните поток и запустите: вresultбудетnull, вerror— «Деление на ноль».Выберите
IncrementCounterи запустите дважды:newValueвырастет на шаг при каждом запуске, потому что счётчик хранится в общей памяти.Включите «Driver Debug» в Device Connection: в панель отладки попадут отправленная команда и «сырой» ответ до разбора.
Частые ошибки:
Ничего не пришло. Проверьте, что в
device - response - listenerвыбрано то же соединение, а поток развёрнут после последней правки.Сохранение отказало с «Синтаксические ошибки, сохранение отменено». В коде драйвера пропущена скобка или запятая — исправьте и сохраните снова.
Драйвер не виден в списке. Закройте окно узла и откройте его заново: список читается при открытии.
Пришёл объект с полем
error: 'Ответ не удалось разобрать'. Ответ оказался не JSON — например, команда вернула неJSON.stringify(...).