Skip to content

gapaus/bary_plugin_empty

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

layout title date categories description
article
Plugin API
2025-11-19 12:00:00 +0300
bary install
ПолноС руководство ΠΏΠΎ созданию ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² для BARY с ΠΏΡ€ΠΎΠ΄Π²ΠΈΠ½ΡƒΡ‚Ρ‹ΠΌΠΈ возмоТностями

Plugin API

Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅

Plugin API позволяСт Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ°ΠΌ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ собствСнныС ΠΏΠ»Π°Π³ΠΈΠ½Ρ‹ (Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€Ρ‹) для ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ Π½ΠΎΠ²Ρ‹Ρ… устройств с систСмой BARY. ΠŸΠ»Π°Π³ΠΈΠ½Ρ‹ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ ΠΊΠ°ΠΊ ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ процСссы ΠΈ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΡƒΡŽΡ‚ с основным ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ Ρ‡Π΅Ρ€Π΅Π· IPC (Inter-Process Communication).

ВозмоТности:

  • ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° Π»ΡŽΠ±Ρ‹Ρ… IoT устройств ΠΈ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»ΠΎΠ²
  • Π˜Π·ΠΎΠ»ΡΡ†ΠΈΡ Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€ΠΎΠ² Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… процСссах
  • АвтоматичСская установка зависимостСй
  • Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈ ΠΌΠΎΠ½ΠΈΡ‚ΠΎΡ€ΠΈΠ½Π³
  • ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ событий Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ
  • Mixins β€” ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½ΠΎΠ΅ Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ
  • Templates β€” ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ устройств
  • ДинамичСскиС capabilities β€” гСнСрация интСрфСйса Π² runtime
  • Settings_ex β€” динамичСскиС настройки с Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠ΅ΠΉ

Установка ΠΈ структура ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

Базовая структура ΠΏΠ»Π°Π³ΠΈΠ½Π°

my-plugin/
β”œβ”€β”€ package.json          # Зависимости ΠΈ ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Π΅
β”œβ”€β”€ tsconfig.json         # ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ TypeScript
β”œβ”€β”€ webpack.config.js     # Π‘Π±ΠΎΡ€ΠΊΠ° ΠΏΠ»Π°Π³ΠΈΠ½Π°
β”œβ”€β”€ compile.sh            # Π‘ΠΊΡ€ΠΈΠΏΡ‚ компиляции
β”œβ”€β”€ debug.sh              # Π‘ΠΊΡ€ΠΈΠΏΡ‚ ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ
β”œβ”€β”€ nodemon.json          # ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ dev-Ρ€Π΅ΠΆΠΈΠΌΠ°
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ mixins/           # ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠ΅ миксины (ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ)
β”‚   β”‚   β”œβ”€β”€ params.ts
β”‚   β”‚   └── ipc.ts
β”‚   β”œβ”€β”€ my-plugin.ts      # Основной Ρ„Π°ΠΉΠ» ΠΏΠ»Π°Π³ΠΈΠ½Π°
β”‚   └── my-plugin.json    # ΠœΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠ»Π°Π³ΠΈΠ½Π° для BARY
β”œβ”€β”€ core/                 # Π‘Π°Π·ΠΎΠ²Ρ‹Π΅ классы (Π½Π°ΡΠ»Π΅Π΄ΡƒΡŽΡ‚ΡΡ)
β”‚   β”œβ”€β”€ base-module.ts
β”‚   └── base-driver-module.ts
β”œβ”€β”€ enums/
β”‚   └── EventTypes.ts     # Π’ΠΈΠΏΡ‹ событий
β”œβ”€β”€ lib/                  # Π’ΡΠΏΠΎΠΌΠΎΠ³Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ
β”‚   β”œβ”€β”€ better-queue/     # БистСма ΠΎΡ‡Π΅Ρ€Π΅Π΄Π΅ΠΉ
β”‚   β”œβ”€β”€ foibles/          # БистСма миксинов
β”‚   β”œβ”€β”€ require-ex.ts     # АвтоматичСская установка зависимостСй
β”‚   └── shared.functions.ts
β”œβ”€β”€ templates/            # ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ устройств (ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ)
β”‚   └── device-config.json
└── dist/                 # Π‘ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹

package.json

{
  "name": "bary-plugin-mydevice",
  "version": "1.0.0",
  "main": "src/my-plugin.ts",
  "scripts": {
    "build": "webpack --display_modules",
    "debug": "nodemon --config nodemon.json"
  },
  "dependencies": {
    "async-mutex": "^0.5.0",
    "moment": "^2.27.0",
    "node-ipc": "^9.1.1",
    "winston": "^3.17.0",
    "uuid": "^8.3.2"
  },
  "devDependencies": {
    "@types/node": "^14.14.34",
    "ts-loader": "^8.0.14",
    "ts-node": "^10.3.0",
    "typescript": "^4.1.3",
    "webpack": "^4.46.0",
    "webpack-cli": "^3.2.3"
  }
}

my-plugin.json

ΠœΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ конфигурация ΠΏΠ»Π°Π³ΠΈΠ½Π° для BARY:

{
  "name": "My Device Plugin",
  "type": 1,
  "icon": "hub",
  "class_name": "my-plugin",
  "module": "my-plugin",
  "manufacturer": "Company Name",
  "cloud": false,
  "support_autoupdate": false,
  "dynamic_capabilities": true,
  "mac_address": false,
  "capabilities": [],
  "sort_index": 4,
  "sub_devices": [
    {
      "class_name": "my-plugin.subdevice",
      "name": "My SubDevice",
      "dynamic_capabilities": true,
      "mac_address": false,
      "support_autoupdate": true,
      "autoupdate_interval": 500,
      "selectable": true,
      "connect_config": true,
      "type": 39,
      "sort_index": 1,
      "settings": [
        {
          "key": "identifier",
          "name": "Device ID",
          "type": "text",
          "required": true
        }
      ],
      "commands": [
        {
          "command": "reset"
        }
      ]
    }
  ],
  "settings": [
    {
      "key": "port",
      "name": "Port",
      "type": "text",
      "required": true,
      "defaultValue": "/dev/ttyUSB0"
    },
    {
      "key": "baud_rate",
      "name": "Baud rate",
      "type": "select",
      "items": [
        {"id": 9600, "title": "9600"},
        {"id": 19200, "title": "19200"},
        {"id": 115200, "title": "115200"}
      ],
      "defaultValue": 9600
    },
    {
      "key": "enable_logging",
      "name": "Enable logging",
      "type": "checkbox"
    }
  ],
  "commands": [
    {
      "command": "scan_devices"
    },
    {
      "command": "reset"
    }
  ],
  "display": [
    {
      "functions": [
        {
          "title": "Scan Mode",
          "type": "scan_mode",
          "view": "buttons",
          "model": "device.:ident.status.scan_mode",
          "buttons": [
            {"value": "auto", "title": "Automatic"},
            {"value": "manual", "title": "Manual"}
          ],
          "data": {
            "ident": ":ident",
            "command": "scan_mode",
            "value": ":scan_mode"
          }
        }
      ]
    }
  ],
  "dependencies": {
    "my-device-sdk": "^2.0.0"
  }
}

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ поля:

  • name β€” ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π΅ΠΌΠΎΠ΅ имя ΠΏΠ»Π°Π³ΠΈΠ½Π°
  • type β€” ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ‚ΠΈΠΏ устройства (число)
  • icon β€” ΠΈΠΊΠΎΠ½ΠΊΠ° ΠΏΠ»Π°Π³ΠΈΠ½Π°
  • class_name β€” тСхничСскоС имя класса
  • module β€” имя модуля
  • manufacturer β€” ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ (ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ)
  • cloud β€” ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΎΠ±Π»Π°ΠΊΠ°
  • support_autoupdate β€” Π°Π²Ρ‚ΠΎΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ статуса
  • dynamic_capabilities β€” capabilities Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΡŽΡ‚ΡΡ Π² runtime
  • mac_address β€” трСбуСтся MAC-адрСс
  • disable_display_sort β€” ΠΎΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ сортировку отобраТСния
  • capabilities β€” статичСскиС возмоТности устройства
  • sub_devices β€” конфигурация Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… устройств
  • settings β€” статичСскиС настройки ΠΏΠ»Π°Π³ΠΈΠ½Π°
  • commands β€” ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ ΠΏΠ»Π°Π³ΠΈΠ½Π°
  • display β€” кастомизация UI (ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ)
  • dependencies β€” NPM-зависимости (ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°ΡŽΡ‚ΡΡ автоматичСски)

Π‘Π°Π·ΠΎΠ²Ρ‹Π΅ классы

baseModule

Π‘Π°Π·ΠΎΠ²Ρ‹ΠΉ класс для всСх ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ², обСспСчиваСт IPC ΠΊΠΎΠΌΠΌΡƒΠ½ΠΈΠΊΠ°Ρ†ΠΈΡŽ с BARY.

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ свойства:

  • config β€” конфигурация прилоТСния
  • ipc β€” IPC ΠΊΠ»ΠΈΠ΅Π½Ρ‚ для связи с BARY
  • events β€” массив зарСгистрированных событий
  • requestId β€” счСтчик запросов
  • external_driver β€” Ρ„Π»Π°Π³ внСшнСго Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€Π°

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹:

// ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° запроса с ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ΠΌ ΠΎΡ‚Π²Π΅Ρ‚Π°
request(eventName: string, params: object): Promise<any>

// ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° запроса Π±Π΅Π· оТидания ΠΎΡ‚Π²Π΅Ρ‚Π°
requestEx(eventName: string, params: object): void

// Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅
log(message: any): void
error(message: any): void

// ДинамичСская Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° npm ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ
require(ident: string, require: boolean): Promise<any>

baseDriverModule

Π Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ baseModule Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄Π°ΠΌΠΈ для Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€Π°ΠΌΠΈ устройств.

Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ свойства:

  • device_id β€” ID устройства
  • params β€” ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ устройства
  • config β€” конфигурация устройства
  • logger β€” Winston logger для записи Π»ΠΎΠ³ΠΎΠ²
  • ident β€” ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ устройства
  • appDevices β€” список устройств прилоТСния
  • statusCache β€” кэш статусов для ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ
  • pluginTemplate β€” ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠ»Π°Π³ΠΈΠ½Π° ΠΈΠ· JSON

Π–ΠΈΠ·Π½Π΅Π½Π½Ρ‹ΠΉ Ρ†ΠΈΠΊΠ»:

// 1. Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°
initDeviceEx(resolve, reject): void

// 2. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ устройству
connectEx(resolve, reject): void

// 3. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΊΠΎΠΌΠ°Π½Π΄
commandEx(command, value, params, options, resolve, reject, status): void

// 4. ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ списка Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… устройств
getSubDevicesEx(resolve, reject, zones): void

// 5. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° событий ΠΎΡ‚ подписанных устройств (ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ)
onSubscribeDevice(params: any): void

Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹:

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅/ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ устройства
checkSubDevice(model, key, name, params, zone_id): Promise<any>

// ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ событий
publish(eventType, ...params): void
publishStatus(eventType, status): void

// Π€ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠΌΠ΅Π½ΠΈ события для статуса
eventTypeStatus(className, identifier?, key?): string

// Подписка Π½Π° события Π΄Ρ€ΡƒΠ³ΠΎΠ³ΠΎ устройства
subscribeDevice(ident, eventType): void

// УвСдомлСния
sendNotify(message, options?): void
sendNotifyEx(body): void
sendPushNotification(message, email, title): void

// Π Π°Π±ΠΎΡ‚Π° с устройствами
getDevices(params?): Promise<Device[]>
deviceCommand(ident, command, data, value): Promise<any>
deviceEvent(ident, event, data): Promise<any>

// Π Π°Π±ΠΎΡ‚Π° с Π‘Π”
getTable(table, options): Promise<any[]>
createTable(table, options): Promise<any>
updateTable(table, options, where): Promise<any>
getConfig(): Promise<any>
getDeviceCustomData(ident, custom_data_id): Promise<any>

// Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° templates
loadTemplate(ident, name, options?): any

// ΠžΡ‡Π΅Ρ€Π΅Π΄ΠΈ
startQueue(ident): void
countQueue(ident): void
doneQueue(ident, resolve, reject, inc?, error?): void

Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Ρ‡Π΅Ρ€Π΅Π· Mixins

Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ Mixins?

BARY ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ foibles для создания миксинов β€” ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½ΠΎΠ³ΠΎ способа Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ классов.

БозданиС миксина

// src/mixins/params.ts
const {Mixin} = require('../../lib/foibles');

export const DEVICE_ID_INC = 10000;

export const Params = Mixin(parent => class Params extends parent {
  
  capabilities = [];
  settings_ex = [];
  
  get heater_list() {
    return this.params?.heater_list || [];
  }
  
  get heater_list_devices() {
    return this.heater_list 
      ? this.appDevices.filter(item => 
          this.heater_list.find(item1 => item1 === item.ident)
        ) 
      : [];
  }
  
  getDeviceParam(params, device, key, defaultValue) {
    return params[`${device.ident}_${key}`] !== undefined 
      ? params[`${device.ident}_${key}`] 
      : defaultValue;
  }
  
  updateCapabilities() {
    this.capabilities = [];
    
    this.heater_list_devices.forEach(device => {
      this.capabilities.push({
        ident: 'power',
        index: DEVICE_ID_INC + device.id,
        display_name: `${device.name} (${device.zone_name})`,
        options: {
          info: `info_${DEVICE_ID_INC + device.id}`,
          ignore_changes: true
        }
      });
    });
  }
  
});

ИспользованиС миксинов

import {baseDriverModule} from '../core/base-driver-module';
import {Params, DEVICE_ID_INC} from './mixins/params';
import {IPC} from './mixins/ipc';

// Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅ класса нСсколькими миксинами
class MyPlugin extends baseDriverModule.with(Params, IPC) {
  
  connectEx(resolve, reject) {
    this.getDevices({currentStatus: true}).then(devices => {
      this.appDevices = devices;
      
      // ИспользованиС ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΈΠ· миксина Params
      this.updateCapabilities();
      
      // Доступ ΠΊ Π³Π΅Ρ‚Ρ‚Π΅Ρ€Π°ΠΌ миксина
      this.heater_list_devices.forEach(device => {
        console.log(device.name);
      });
      
      // ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ capabilities
      this.publish(
        this.eventTypeStatus(this.pluginTemplate.class_name, this.id),
        {capabilities: this.capabilities, settings_ex: this.settings_ex}
      );
      
      resolve({});
    });
  }
  
}

const app = new MyPlugin();

Templates β€” ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ устройств

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ templates

ΠŸΠ»Π°Π³ΠΈΠ½Ρ‹ ΠΌΠΎΠ³ΡƒΡ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹ Π² ΠΏΠ°ΠΏΠΊΠ΅ /templates/:

my-plugin/
└── templates/
    β”œβ”€β”€ device1.json
    β”œβ”€β”€ device2.json
    └── conditioner.json

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ template

{
  "manufacturer": "Philio Technology Corp",
  "manufacturerId": "0x013c",
  "label": "PAR01",
  "description": "Conditioner",
  "devices": [
    {
      "productType": "0x0106",
      "productId": "0x8290"
    }
  ],
  "firmwareVersion": {
    "min": "0.0",
    "max": "255.255"
  },
  "paramInformation": [
    {
      "#": "25",
      "label": "Learn mode",
      "valueSize": 2,
      "minValue": 0,
      "maxValue": 2048,
      "defaultValue": 1
    },
    {
      "#": "27",
      "label": "Temperature",
      "valueSize": 2,
      "minValue": 16,
      "maxValue": 30,
      "defaultValue": 22
    }
  ]
}

Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° template

// Π’ ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅ ΠΏΠ»Π°Π³ΠΈΠ½Π°
const template = this.loadTemplate('my-plugin', 'conditioner.json');
console.log(template.manufacturer); // "Philio Technology Corp"

// Π‘ опциями (Ссли template β€” это функция)
const template = this.loadTemplate('my-plugin', 'device-template', {
  deviceId: 123
});

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π°

ΠœΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€

import {baseDriverModule} from '../core/base-driver-module';
import {EventTypes} from '../enums/EventTypes';

class MyPlugin extends baseDriverModule {

  /**
   * Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΠ»Π°Π³ΠΈΠ½Π°
   */
  initDeviceEx(resolve, reject) {
    super.initDeviceEx(() => {
      this.app.log('Плагин ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½');
      
      // Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΈΠΌΠ΅Π½ΠΈ события для статуса
      this.eventName = this.eventTypeStatus(
        this.pluginTemplate.class_name, 
        this.id
      );
      
      resolve({});
    }, reject);
  }

  /**
   * ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ устройству
   */
  connectEx(resolve, reject) {
    this.app.log('ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ устройству...');
    
    // ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ списка устройств
    this.getDevices({currentStatus: true}).then(devices => {
      this.appDevices = devices;
      
      // Подписка Π½Π° события устройств
      this.appDevices.forEach(device => {
        this.subscribeDevice(device.ident, 'changed_power');
      });
      
      // ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ динамичСских capabilities
      const capabilities = [];
      capabilities.push({
        ident: 'power',
        index: 1,
        display_name: 'Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ/Π²Ρ‹ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ',
        options: {
          hideTitle: false
        }
      });
      
      this.publish(this.eventName, {capabilities});
    });
    
    resolve({});
  }

  /**
   * ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΊΠΎΠΌΠ°Π½Π΄
   */
  commandEx(command, value, params, options, resolve, reject, status) {
    this.app.log('Команда:', command, 'Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅:', value);
    
    // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΏΡ€Π°Π² администратора (Ссли Π½ΡƒΠΆΠ½ΠΎ)
    if (command === 'admin_action' && options && !options.is_admin) {
      return reject({message: 'Access Denied!'});
    }
    
    switch(command) {
      case 'on':
        // Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ устройство
        resolve({state: 'on'});
        break;
      case 'off':
        // Π’Ρ‹ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ устройство
        resolve({state: 'off'});
        break;
      case 'status':
        // ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ статус
        resolve({connected: true, state: 'on'});
        break;
      default:
        reject({message: 'НСизвСстная ΠΊΠΎΠΌΠ°Π½Π΄Π°'});
    }
  }
  
  /**
   * ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° событий ΠΎΡ‚ подписанных устройств
   */
  onSubscribeDevice(params: any) {
    const device = this.appDevices.find(item => item.ident === params.ident);
    if (device) {
      device.currentStatus = params.currentStatus;
      // РСакция Π½Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ статуса
      this.handleDeviceUpdate(device);
    }
  }
}

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ экзСмпляра ΠΏΠ»Π°Π³ΠΈΠ½Π°
const app = new MyPlugin();
app.logging = true;

ДинамичСскиС Capabilities

Capabilities ΠΌΠΎΠΆΠ½ΠΎ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ динамичСски Π² ΠΌΠ΅Ρ‚ΠΎΠ΄Π΅ connectEx() ΠΈΠ»ΠΈ ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ.

ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ capabilities

connectEx(resolve, reject) {
  const capabilities = [];
  
  // ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚Π΅Π»ΡŒ
  capabilities.push({
    ident: 'power',
    index: 1,
    display_name: 'Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΡ‚ΠΎΠΏΠ»Π΅Π½ΠΈΠ΅ΠΌ',
    options: {
      hideTitle: false,
      hideSeparator: false,
      hideBottomPadding: false,
      ignore_changes: false,
      read_only: false
    }
  });
  
  // ВСкстовоС ΠΏΠΎΠ»Π΅ с ΠΈΠ·ΠΌΠ΅Ρ€Π΅Π½ΠΈΠ΅ΠΌ
  capabilities.push({
    ident: 'text',
    index: 2,
    display_name: 'Π’Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Π°',
    options: {
      measure: 'Β°C',
      read_only: true
    }
  });
  
  // ΠŸΠΎΠ»Π·ΡƒΠ½ΠΎΠΊ (range)
  capabilities.push({
    ident: 'target_temperature',
    index: 3,
    display_name: 'ЖСлаСмая Ρ‚Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Π°',
    options: {
      minValue: 5,
      maxValue: 30,
      stepValue: 0.5,
      hideTitle: true
    }
  });
  
  // Capability с ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΎΠ½Π½Ρ‹ΠΌ ΠΏΠΎΠ»Π΅ΠΌ
  capabilities.push({
    ident: 'power',
    index: 10,
    display_name: 'Насос 1',
    options: {
      info: 'info_10',        // Бвязано с status.info_10
      ignore_changes: true
    }
  });
  
  // Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ
  capabilities.push({
    ident: 'title',
    index: 100,
    options: {
      title_only: 'ΠšΠ»ΠΈΠΌΠ°Ρ‚-ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒ'
    },
    hide_background: true,
    hide_bottom_padding: true,
    hide_separator: true
  });
  
  // Capability для добавлСния/удалСния устройств
  capabilities.push({
    ident: 'power',
    index: 1,
    display_name: 'Add Z-Wave device',
    options: {
      link_devices: true
    }
  });
  
  capabilities.push({
    ident: 'power',
    index: 2,
    display_name: 'Remove Z-Wave device',
    options: {
      unlink_devices: true
    }
  });
  
  // ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ
  this.publish(
    this.eventTypeStatus(this.pluginTemplate.class_name, this.id),
    {capabilities}
  );
  
  resolve({});
}

ДоступныС ΠΎΠΏΡ†ΠΈΠΈ capabilities

  • hideTitle β€” ΡΠΊΡ€Ρ‹Ρ‚ΡŒ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ
  • hideSeparator β€” ΡΠΊΡ€Ρ‹Ρ‚ΡŒ Ρ€Π°Π·Π΄Π΅Π»ΠΈΡ‚Π΅Π»ΡŒ
  • hideBottomPadding β€” ΡΠΊΡ€Ρ‹Ρ‚ΡŒ отступ снизу
  • ignore_changes β€” ΠΈΠ³Π½ΠΎΡ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ измСнСния
  • read_only β€” Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для чтСния
  • info β€” связь с ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΎΠ½Π½Ρ‹ΠΌ ΠΏΠΎΠ»Π΅ΠΌ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, info_10 связано с status.info_10)
  • measure β€” Π΅Π΄ΠΈΠ½ΠΈΡ†Π° измСрСния (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Β°C, %, W)
  • minValue, maxValue, stepValue β€” для ΠΏΠΎΠ»Π·ΡƒΠ½ΠΊΠΎΠ² (range)
  • value_on, value_off β€” значСния для ΠΏΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡Π°Ρ‚Π΅Π»Π΅ΠΉ
  • title_only β€” Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π±Π΅Π· Ρ„ΠΎΠ½Π° (для ident: 'title')
  • link_devices, unlink_devices β€” для добавлСния/удалСния устройств

ДинамичСскиС Settings (settings_ex)

Settings_ex ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ настройки с Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠ΅ΠΉ устройств ΠΏΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌ ΠΈ Ρ‚ΠΈΠΏΠ°ΠΌ.

ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ settings_ex

connectEx(resolve, reject) {
  const settings_ex = [];
  
  // Π’Ρ‹Π±ΠΎΡ€ устройства с Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠ΅ΠΉ ΠΏΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌ
  settings_ex.push({
    key: 'temperature_sensor',
    name: 'Π”Π°Ρ‚Ρ‡ΠΈΠΊ Ρ‚Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Ρ‹',
    type: 'select',
    items: [],
    driver_support: [                    // Π€ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΡ‹ΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌ
      'supportTemperature',
      'supportTemperatureEx'
    ],
    multi: false                         // ΠžΠ΄ΠΈΠ½ΠΎΡ‡Π½Ρ‹ΠΉ Π²Ρ‹Π±ΠΎΡ€
  });
  
  // ΠœΠ½ΠΎΠΆΠ΅ΡΡ‚Π²Π΅Π½Π½Ρ‹ΠΉ Π²Ρ‹Π±ΠΎΡ€ устройств
  settings_ex.push({
    key: 'heater_list',
    name: 'Бписок ΠΎΠ±ΠΎΠ³Ρ€Π΅Π²Π°Ρ‚Π΅Π»Π΅ΠΉ',
    type: 'select',
    items: [],
    driver_support: ['supportPower', 'supportPowerEx'],
    driver_types: [5],                   // Π€ΠΈΠ»ΡŒΡ‚Ρ€ ΠΏΠΎ Ρ‚ΠΈΠΏΡƒ Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€Π°
    multi: true                          // ΠœΠ½ΠΎΠΆΠ΅ΡΡ‚Π²Π΅Π½Π½Ρ‹ΠΉ Π²Ρ‹Π±ΠΎΡ€
  });
  
  // Π’Ρ‹Π±ΠΎΡ€ ΠΊΠΎΠΌΠ½Π°Ρ‚Ρ‹
  settings_ex.push({
    key: 'zone_id',
    name: 'ΠšΠΎΠΌΠ½Π°Ρ‚Π°',
    type: 'select',
    items: [],
    zone_support: ['rooms']              // ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊΠΎΠΌΠ½Π°Ρ‚Ρ‹
  });
  
  // Условная Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ
  settings_ex.push({
    key: 'advanced_options',
    name: 'Π”ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΎΠΏΡ†ΠΈΠΈ',
    type: 'text',
    visibleField: 'enable_advanced',     // ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ссли
    visibleFieldValue: true              // enable_advanced = true
  });
  
  // ВСкстовоС ΠΏΠΎΠ»Π΅ с Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
  settings_ex.push({
    key: 'interval',
    name: 'Π˜Π½Ρ‚Π΅Ρ€Π²Π°Π» обновлСния (ΠΌΠΈΠ½)',
    type: 'text',
    defaultValue: 5
  });
  
  // Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ (Π³Ρ€ΡƒΠΏΠΏΠΈΡ€ΠΎΠ²ΠΊΠ° настроСк)
  settings_ex.push({
    key: 'group_heating',
    name: 'Настройки отоплСния',
    type: 'title'
  });
  
  // ДинамичСскоС созданиС настроСк для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ устройства
  this.heater_list_devices.forEach(device => {
    settings_ex.push({
      key: `${device.ident}_kp`,
      name: `${device.name} - ΠŸΡ€ΠΎΠΏΠΎΡ€Ρ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½Π°Ρ ΡΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‰Π°Ρ`,
      type: 'text',
      defaultValue: 0.5
    });
  });
  
  // ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ вмСстС с capabilities
  this.publish(
    this.eventTypeStatus(this.pluginTemplate.class_name, this.id),
    {capabilities, settings_ex}
  );
  
  resolve({});
}

ДоступныС ΠΎΠΏΡ†ΠΈΠΈ settings_ex

  • key β€” ΠΊΠ»ΡŽΡ‡ настройки
  • name β€” ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π΅ΠΌΠΎΠ΅ имя
  • type β€” Ρ‚ΠΈΠΏ поля (text, select, checkbox, title)
  • items β€” элСмСнты для select
  • defaultValue β€” Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ
  • required β€” ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ ΠΏΠΎΠ»Π΅
  • driver_support β€” Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΡ устройств ΠΏΠΎ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΡ‹ΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌ
  • driver_types β€” Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΡ устройств ΠΏΠΎ Ρ‚ΠΈΠΏΡƒ
  • multi β€” мноТСствСнный Π²Ρ‹Π±ΠΎΡ€ (для select)
  • zone_support β€” Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΡ Π·ΠΎΠ½ (['rooms'] β€” Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊΠΎΠΌΠ½Π°Ρ‚Ρ‹)
  • visibleField β€” ΠΏΠΎΠ»Π΅, ΠΎΡ‚ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ зависит Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡ‚ΡŒ
  • visibleFieldValue β€” Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ поля для отобраТСния
  • description β€” описаниС настройки
  • group β€” Π³Ρ€ΡƒΠΏΠΏΠ° настроСк (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, settingsDevice)

API ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹

Π Π°Π±ΠΎΡ‚Π° с устройствами

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ устройства

checkSubDevice(
  model: string,      // МодСль устройства (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, 'zigbee2mqtt.light')
  key: string,        // Π£Π½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΊΠ»ΡŽΡ‡
  name: string,       // НазваниС устройства
  params: object,     // ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ устройства
  zone_id: number     // ID Π·ΠΎΠ½Ρ‹ (null для автоматичСского опрСдСлСния)
): Promise<any>

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ устройства:

{
  icon: 'light',           // Иконка устройства
  identifier: 'unique_id', // Π£Π½ΠΈΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€
  capabilities: [          // ВозмоТности устройства
    {
      index: 0,
      property: 'state',
      ident: 'state',
      display_name: 'БостояниС',
      access: 'rw',        // r=read, w=write, rw=read+write
      homekit: true,       // ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° HomeKit
      yandex: true,        // ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° ЯндСкс Алиса
      sber: true,          // ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° Π‘Π±Π΅Ρ€
      options: {
        value_on: true,
        value_off: false,
        minValue: 0,
        maxValue: 100,
        stepValue: 1
      }
    }
  ],
  settings_ex: [           // ДинамичСскиС настройки устройства
    {
      key: 'parameter_1',
      name: 'Parameter 1',
      type: 'text',
      defaultValue: 10
    }
  ],
  parent_identifier: 123   // ID Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ устройства
}

ДоступныС ΠΈΠΊΠΎΠ½ΠΊΠΈ:

  • ΠžΡΠ²Π΅Ρ‰Π΅Π½ΠΈΠ΅: light, chandelier, rgb_lamp, rgb_strip, rgb_led, table_lamp, spotlight, sconce, facade_light
  • РазвлСчСния: tv, gamepad, music_note, speaker
  • Π‘Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ: camera, security, intercom, doorlock, night, smoke, gas_leak, leak
  • Π”ΠΎΠΌ: home, gates, gate1, gate2, gate3, gate4, socket, infrared, faucet, valve, pump, hub
  • Π¨Ρ‚ΠΎΡ€Ρ‹/Талюзи: view_column, louvers, marquise
  • ΠšΠ»ΠΈΠΌΠ°Ρ‚: floor_heater, heater, heater1, convector, humidifier, ac_unit, fan, dryer, cooling, anti-icing
  • Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ: co2, voc, p2, multisensor, temp_sensor, humidity_sensor, door_sensor, counter, motion
  • Бытовая Ρ‚Π΅Ρ…Π½ΠΈΠΊΠ°: kettle, exhaust_hood, fridge, washing_machine, microwave, dish_washer, oven, stove, vacuum_cleaner, pool, squirt

Π’ΠΈΠΏΡ‹ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² (driver_types):

BARY ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ 52 Ρ‚ΠΈΠΏΠ° ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² для Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Ρ… устройств ΠΈ сСрвисов:

  • Π¨Π»ΡŽΠ·Ρ‹ ΠΈ сСрвисы: Π¨Π»ΡŽΠ·Ρ‹ (1), ΠžΠ±Π»Π°Ρ‡Π½Ρ‹Π΅ сСрвисы (2), ΠŸΡ€ΠΎΠ²Π°ΠΉΠ΄Π΅Ρ€Ρ‹ услуг (19), БистСма (39), Π’Π½Π΅ΡˆΠ½ΠΈΠ΅ API для ΠΊΠ°ΠΌΠ΅Ρ€Ρ‹ (43), ΠœΡƒΠ·Ρ‹ΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ сСрвисы (45)
  • МСдиа устройства: Π˜Π³Ρ€ΠΎΠ²Ρ‹Π΅ приставки (7), РСсивСры (8), Π’Π΅Π»Π΅Π²ΠΈΠ·ΠΎΡ€Ρ‹ (9), Π’Π’-приставки (18), Π£ΠΌΠ½Ρ‹Π΅ ΠΊΠΎΠ»ΠΎΠ½ΠΊΠΈ (37), Π˜Π½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΏΠ°Π½Π΅Π»ΠΈ (50)
  • Π£ΠΌΠ½Ρ‹ΠΉ Π΄ΠΎΠΌ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ: Π£ΠΌΠ½Ρ‹Π΅ Ρ€ΠΎΠ·Π΅Ρ‚ΠΊΠΈ (3), Π’Ρ‹ΠΊΠ»ΡŽΡ‡Π°Ρ‚Π΅Π»ΠΈ (12), Π Π΅Π»Π΅ΠΉΠ½Ρ‹Π΅ ΠΌΠΎΠ΄ΡƒΠ»ΠΈ (14), Эмуляторы IR/RF (16), Π£ΠΌΠ½Ρ‹Π΅ Π»Π°ΠΌΠΏΠΎΡ‡ΠΊΠΈ (22), ΠžΡΠ²Π΅Ρ‰Π΅Π½ΠΈΠ΅ (25), RGB ΠšΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Ρ‹ (40), Π”ΠΈΠΌΠΌΠ΅Ρ€Ρ‹ (44)
  • ΠšΠ»ΠΈΠΌΠ°Ρ‚-ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒ: ВСрмостаты (13), ΠšΠΎΠ½Π΄ΠΈΡ†ΠΈΠΎΠ½Π΅Ρ€Ρ‹ (17), БистСмы вСнтиляции (33), Π£ΠΌΠ½Ρ‹Π΅ вСнтиляторы (41), ΠšΠ»ΠΈΠΌΠ°Ρ‚-ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»ΡŒ (47), Π£Π²Π»Π°ΠΆΠ½ΠΈΡ‚Π΅Π»ΠΈ (6)
  • Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ: Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ Ρ‚Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Ρ‹ (11), Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ влаТности (23), Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ освСщСнности (24), Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ ΠΏΡ€ΠΎΡ‚Π΅Ρ‡ΠΊΠΈ (26), Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ двиТСния (27), Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ напряТСния (28), Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ Π£Π€ (29), Π”Π°Ρ‚Ρ‡ΠΈΠΊΠΈ открытия ΠΎΠΊΠΎΠ½ ΠΈ Π΄Π²Π΅Ρ€Π΅ΠΉ (30), ΠšΠΎΠΌΠ±ΠΈΠ½ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠΈ (31), Π”Π΅Ρ‚Π΅ΠΊΡ‚ΠΎΡ€Ρ‹ Π΄Ρ‹ΠΌΠ° (36), ΠœΠΎΠ½ΠΈΡ‚ΠΎΡ€Ρ‹ качСства Π²ΠΎΠ·Π΄ΡƒΡ…Π° (21)
  • Π‘Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ: ΠšΠ°ΠΌΠ΅Ρ€Ρ‹ (5), Π”Π²Π΅Ρ€Π½Ρ‹Π΅ Π·Π°ΠΌΠΊΠΈ (32), Π”ΠΎΠΌΠΎΡ„ΠΎΠ½Ρ‹ (42), РаспознаваниС Π“Π Π— (48), Π‘ΠšΠ£Π” (49)
  • Бытовая Ρ‚Π΅Ρ…Π½ΠΈΠΊΠ°: ΠŸΡ‹Π»Π΅ΡΠΎΡΡ‹ (4), ΠŸΡ€ΠΈΠ²ΠΎΠ΄Ρ‹ ΡˆΡ‚ΠΎΡ€ (38), Π£Ρ…ΠΎΠ΄ Π·Π° растСниями (20)
  • Π˜Π½ΠΆΠ΅Π½Π΅Ρ€Π½Ρ‹Π΅ систСмы: Π‘Ρ‡Π΅Ρ‚Ρ‡ΠΈΠΊΠΈ элСктроэнСргии (15), ВодосчСтчики (35), Π£ΠΌΠ½Ρ‹Π΅ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Ρ‹ (34), ΠœΠΎΠ΄ΡƒΠ»ΠΈ Π²Π²ΠΎΠ΄Π°-Π²Ρ‹Π²ΠΎΠ΄Π° (46), ΠœΠΎΠ΄ΡƒΠ»ΠΈ управлСния устройствами (51)
  • ГолосовоС ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅: ГолосовыС ассистСнты (52), Погода (10)

ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ списка устройств

getDevices(params?: object): Promise<Device[]>

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

const devices = await this.getDevices({currentStatus: true});
devices.forEach(device => {
  this.app.log('Устройство:', device.name, 'Бтатус:', device.currentStatus);
});

Подписка Π½Π° события устройства

subscribeDevice(ident: string, eventType: string): void

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

// Подписка Π½Π° ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ питания
this.subscribeDevice('device-001', 'changed_power');

// ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Π² onSubscribeDevice()
onSubscribeDevice(params: any) {
  const device = this.appDevices.find(item => item.ident === params.ident);
  if (device) {
    device.currentStatus = params.currentStatus;
    this.app.log('Бтатус измСнился:', device.name, params.currentStatus);
  }
}

ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Π΄Ρ€ΡƒΠ³ΠΎΠΌΡƒ устройству

deviceCommand(
  ident: string,    // Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ устройства
  command: string,  // Команда
  data: object,     // Π”Π°Π½Π½Ρ‹Π΅
  value: any        // Π—Π½Π°Ρ‡Π΅Π½ΠΈΠ΅
): Promise<any>

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

await this.deviceCommand('light_bedroom', 'on', {}, true);

ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ событий

Π€ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠΌΠ΅Π½ΠΈ события

eventTypeStatus(
  className: string,
  identifier?: string,
  key?: string
): string

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

const eventName = this.eventTypeStatus('my-plugin', 'device-001', 'temperature');
// Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚: "status->my-plugin->device-001->temperature"

// Для ΠΏΠ»Π°Π³ΠΈΠ½Π°
const eventName = this.eventTypeStatus(this.pluginTemplate.class_name, this.id);
// Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚: "status->my-plugin->driver-123"

ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ статуса устройства

publishStatus(eventType: EventTypes, status: object): void

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

// ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° Π΄Π°Π½Π½Ρ‹Ρ… с Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠ°
this.publishStatus(EventTypes.UpdateTemperature, {
  temperature_living_room: 22.5,
  humidity_living_room: 45,
  connected: true
});

ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ:

ΠœΠ΅Ρ‚ΠΎΠ΄ publishStatus автоматичСски:

  • ΠŸΡƒΠ±Π»ΠΈΠΊΡƒΠ΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅
  • ΠžΡ‚ΠΏΡ€Π°Π²Π»ΡΠ΅Ρ‚ числовыС Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ >10% ΠΈΠ»ΠΈ Ρ€Π°Π· Π² 15 сСкунд
  • ВсСгда отправляСт события Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠΎΠ² двиТСния, открытия ΠΈ Ρ‚.Π΄.

ΠŸΡ€ΡΠΌΠ°Ρ публикация событий

publish(eventType: EventTypes | string, ...params: any[]): void

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

this.publish(EventTypes.ChangedMotion, {
  parent_identifier: this.device_id,
  motion_sensor_1: true
});

// ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ capabilities ΠΈ settings_ex
this.publish(
  this.eventTypeStatus(this.pluginTemplate.class_name, this.id),
  {capabilities, settings_ex, displays: [...]}
);

УвСдомлСния

ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° увСдомлСния ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ

sendNotify(message: string, options?: object): void

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

this.sendNotify('Устройство ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΎ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ!');

БистСмныС увСдомлСния (sendNotifyEx)

sendNotifyEx(body: object): void

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

// ОбновлСниС устройства
this.sendNotifyEx({
  system: true,
  type: 'device-update',
  ident: this.ident
});

// ОбновлСниС настроСк
this.sendNotifyEx({
  system: true,
  type: 'settings-update',
  ident: this.ident
});

Push-ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅

sendPushNotification(
  message: string,
  email: string,
  title: string
): void

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

this.sendPushNotification(
  'ΠžΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½ΠΎ Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠ΅ Π² гостиной',
  'user@example.com',
  'Π”Π°Ρ‚Ρ‡ΠΈΠΊ двиТСния'
);

Π Π°Π±ΠΎΡ‚Π° с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ

ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ

getConfig(): Promise<any>

Π Π°Π±ΠΎΡ‚Π° с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ…

// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ записСй
getTable(table: string, options: object): Promise<any[]>

// БозданиС записи
createTable(table: string, options: object): Promise<any>

// ОбновлСниС записСй
updateTable(table: string, options: object, where: object): Promise<any>

ΠŸΡ€ΠΈΠΌΠ΅Ρ€:

// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ всСх устройств Ρ‚ΠΈΠΏΠ° 'light'
const lights = await this.getTable('devices', {
  where: {type: 'light'}
});

// БозданиС записи
await this.createTable('custom_data', {
  device_id: 123,
  key: 'last_seen',
  value: new Date().toISOString()
});

// ОбновлСниС
await this.updateTable(
  'devices',
  {name: 'Updated Name'},
  {where: {id: 123}}
);

ΠžΠ±Π»Π°Ρ‡Π½Ρ‹Π΅ запросы

cloudRequest(params: object): Promise<any>

Π Π°Π±ΠΎΡ‚Π° с очСрСдями (Better-queue)

// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ запросов
const Queue = require('../lib/better-queue/queue');

this.requestQueue = new Queue((task, callback) => {
  this.deviceCommand(
    task.ident,
    task.command,
    {},
    task.value
  ).then(() => {
    callback(null, {});
  }).catch(error => {
    callback(error);
  });
}, {
  concurrent: 1,        // ΠŸΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°
  maxRetries: 3
});

// Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π·Π°Π΄Π°Ρ‡ΠΈ Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ
this.requestQueue.push({
  ident: 'device-001',
  command: 'set_power',
  value: true
}, (error, result) => {
  if (error) {
    console.error('Error:', error);
  } else {
    console.log('Success:', result);
  }
});

// ВстроСнныС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ для простых ΠΎΡ‡Π΅Ρ€Π΅Π΄Π΅ΠΉ
this.startQueue('commands');
this.countQueue('commands');
this.doneQueue('commands', resolve, reject);

Π’ΠΈΠΏΡ‹ событий (EventTypes)

Устройства

  • DeviceCreate β€” созданиС устройства
  • DeviceUpdate β€” ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ устройства
  • DeviceDelete β€” ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ устройства
  • DeviceConnect β€” ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ устройства
  • DeviceDiscover β€” ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ устройства

ОбновлСния Π΄Π°Π½Π½Ρ‹Ρ…

  • UpdateTemperature β€” ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Ρ‹
  • UpdateThermostatTemp β€” ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Ρ‚Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Ρ‹ тСрмостата
  • UpdatePower β€” ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ мощности
  • UpdateAlert β€” ΠΏΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠ΅

Бобытия Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠΎΠ²

  • ChangedMotion β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠ° двиТСния
  • ChangedMagnet β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π³Π΅Ρ€ΠΊΠΎΠ½Π° (ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅/Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅)
  • ChangedMagnetChange β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π³Π΅Ρ€ΠΊΠΎΠ½Π° с ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ΠΉ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ
  • ChangedPower β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ состояния питания
  • ChangedPowerChange β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ состояния питания с ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ΠΉ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ
  • ChangedPowerLoad β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ
  • ChangedAction β€” ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ΅ дСйствиС
  • ChangedLeakChange β€” ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΡ‚Π΅Ρ‡ΠΊΠΈ
  • ChangedInputChange β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π²Ρ…ΠΎΠ΄Π°
  • ChangedCounterChange β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ счСтчика
  • ChangedChannel β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠ°Π½Π°Π»Π°
  • ChangedChannel0 β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠ°Π½Π°Π»Π° 0
  • ChangedChannel1 β€” ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠ°Π½Π°Π»Π° 1

MQTT

  • MqttMessage β€” сообщСниС MQTT

Бтатистика

  • NewStats β€” новая статистика
  • NewStatsEx β€” Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½Π½Π°Ρ статистика

Wi-Fi

  • WiFiConnect β€” ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ Wi-Fi
  • WiFiConnected β€” Wi-Fi ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½
  • WiFiNetworkFound β€” ΡΠ΅Ρ‚ΡŒ Wi-Fi Π½Π°ΠΉΠ΄Π΅Π½Π°

ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

  • ApplicationReady β€” ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π³ΠΎΡ‚ΠΎΠ²ΠΎ
  • ApplicationCreated β€” ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ создано
  • ApplicationGetDevices β€” ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ устройств прилоТСния
  • ApplicationDeviceCommand β€” ΠΊΠΎΠΌΠ°Π½Π΄Π° устройству
  • ApplicationAddDeviceQueue β€” Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ устройства Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ
  • ApplicationAddScanQueue β€” Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ сканирования Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ
  • ApplicationDriverReady β€” Π΄Ρ€Π°ΠΉΠ²Π΅Ρ€ Π³ΠΎΡ‚ΠΎΠ²
  • NewEvent β€” Π½ΠΎΠ²ΠΎΠ΅ событиС

Π‘Π°Π·Π° Π΄Π°Π½Π½Ρ‹Ρ…

  • DatabaseReady β€” Π‘Π” Π³ΠΎΡ‚ΠΎΠ²Π°
  • DatabaseConnected β€” Π‘Π” ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½Π°
  • DatabaseGetAllItems β€” ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ всСх элСмСнтов
  • DatabaseUpdateItem β€” ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ элСмСнта
  • DatabaseUpdateDeviceParams β€” ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² устройства
  • DatabaseCreateItem β€” созданиС элСмСнта
  • DatabaseQuery β€” запрос ΠΊ Π‘Π”
  • DatabaseUpdate β€” ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π‘Π”
  • DatabaseQueueQuery β€” запрос Π² ΠΎΡ‡Π΅Ρ€Π΅Π΄ΠΈ Π‘Π”

ΠŸΡ€ΠΎΡ‡Π΅Π΅

  • CheckSubDevice β€” ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅Π³ΠΎ устройства
  • Publish β€” публикация
  • Notify β€” ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅
  • UpdateSensor β€” ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠ°
  • RemoveSensor β€” ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅ Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠ°
  • UpdateSensorEx β€” Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π΄Π°Ρ‚Ρ‡ΠΈΠΊΠ°

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ²

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 1: Плагин для HTTP устройств

import {baseDriverModule} from '../core/base-driver-module';
import {EventTypes} from '../enums/EventTypes';
import axios from 'axios';

class HttpDevicePlugin extends baseDriverModule {
  
  private baseUrl: string;

  initDeviceEx(resolve, reject) {
    super.initDeviceEx(() => {
      // ΠŸΠΎΠ»ΡƒΡ‡Π°Π΅ΠΌ URL ΠΈΠ· ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²
      this.baseUrl = this.params.url || 'http://192.168.1.100';
      this.app.log('HTTP устройство:', this.baseUrl);
      resolve({});
    }, reject);
  }

  connectEx(resolve, reject) {
    // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡΠ΅ΠΌ Π΄ΠΎΡΡ‚ΡƒΠΏΠ½ΠΎΡΡ‚ΡŒ устройства
    axios.get(`${this.baseUrl}/status`)
      .then(response => {
        this.app.log('Устройство ΠΎΠ½Π»Π°ΠΉΠ½');
        this.startPolling();
        resolve({});
      })
      .catch(error => {
        reject({message: 'Устройство нСдоступно'});
      });
  }

  startPolling() {
    setInterval(() => {
      axios.get(`${this.baseUrl}/sensors`)
        .then(response => {
          this.publishStatus(EventTypes.UpdateTemperature, {
            temperature_sensor: response.data.temperature,
            humidity_sensor: response.data.humidity,
            connected: true
          });
        })
        .catch(error => {
          this.app.error('Ошибка получСния Π΄Π°Π½Π½Ρ‹Ρ…:', error.message);
        });
    }, 10000); // ΠšΠ°ΠΆΠ΄Ρ‹Π΅ 10 сСкунд
  }

  commandEx(command, value, params, options, resolve, reject, status) {
    switch(command) {
      case 'on':
        axios.post(`${this.baseUrl}/control`, {power: 'on'})
          .then(() => resolve({state: 'on'}))
          .catch(error => reject({message: error.message}));
        break;
      
      case 'off':
        axios.post(`${this.baseUrl}/control`, {power: 'off'})
          .then(() => resolve({state: 'off'}))
          .catch(error => reject({message: error.message}));
        break;
      
      case 'status':
        axios.get(`${this.baseUrl}/status`)
          .then(response => resolve(response.data))
          .catch(error => reject({message: error.message}));
        break;
      
      default:
        reject({message: 'НСизвСстная ΠΊΠΎΠΌΠ°Π½Π΄Π°'});
    }
  }
}

const app = new HttpDevicePlugin();
app.logging = true;

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 2: Плагин с динамичСскими capabilities ΠΈ миксинами

import {baseDriverModule} from '../core/base-driver-module';
import {EventTypes} from '../enums/EventTypes';
import {Params} from './mixins/params';

class DashboardPlugin extends baseDriverModule.with(Params) {
  
  appDevices = [];
  
  initDeviceEx(resolve, reject) {
    super.initDeviceEx(() => {
      this.app.log('Dashboard plugin initialized');
      this.eventName = this.eventTypeStatus(
        this.pluginTemplate.class_name,
        this.id
      );
      resolve({});
    }, reject);
  }
  
  connectEx(resolve, reject) {
    this.getDevices({currentStatus: true}).then(devices => {
      this.appDevices = devices;
      
      // Подписка Π½Π° события устройств
      this.appDevices.forEach(device => {
        this.subscribeDevice(device.ident, 'changed_power');
      });
      
      // ДинамичСскоС созданиС capabilities
      this.updateCapabilities();
      this.updateSettingsEx();
      
      // ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ capabilities ΠΈ settings_ex
      this.publish(this.eventName, {
        capabilities: this.capabilities,
        settings_ex: this.settings_ex
      });
      
      resolve({});
    });
  }
  
  updateCapabilities() {
    this.capabilities = [];
    const deviceCount = this.params.device_count || 0;
    
    // Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ capabilities для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ устройства
    for (let i = 0; i < deviceCount; i++) {
      const deviceIdent = this.params[`device_ident_${i}`];
      const deviceType = this.params[`device_type_${i}`];
      
      if (deviceIdent) {
        this.capabilities.push({
          ident: 'power',
          index: i + 1,
          display_name: `Device ${i + 1}`,
          options: {
            hideTitle: false,
            info: `info_${i}`,
            ignore_changes: false
          }
        });
      }
    }
  }
  
  updateSettingsEx() {
    this.settings_ex = [];
    const deviceCount = this.params.device_count || 4;
    
    // Π—Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ
    this.settings_ex.push({
      key: 'devices_group',
      name: 'Devices Configuration',
      type: 'title'
    });
    
    // Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ настроСк для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ устройства
    for (let i = 0; i < deviceCount; i++) {
      // Π’ΠΈΠΏ устройства
      this.settings_ex.push({
        key: `device_type_${i}`,
        name: `Device ${i + 1} Type`,
        type: 'select',
        items: [
          {id: 'switch', title: 'Switch'},
          {id: 'sensor', title: 'Sensor'},
          {id: 'light', title: 'Light'}
        ],
        defaultValue: 'switch'
      });
      
      // Π’Ρ‹Π±ΠΎΡ€ устройства с Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠ΅ΠΉ
      this.settings_ex.push({
        key: `device_ident_${i}`,
        name: `Device ${i + 1}`,
        type: 'select',
        items: [],
        driver_support: ['supportPower'],
        multi: false
      });
    }
  }
  
  onSubscribeDevice(params: any) {
    // ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° событий ΠΎΡ‚ подписанных устройств
    const device = this.appDevices.find(item => item.ident === params.ident);
    if (device) {
      device.currentStatus = params.currentStatus;
      this.app.log('Device status updated:', device.name, params.currentStatus);
      
      // ΠŸΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΡ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π½ΠΎΠ³ΠΎ статуса
      this.publishStatus(EventTypes.UpdatePower, {
        [`status_${device.ident}`]: params.currentStatus.power
      });
    }
  }
  
  commandEx(command, value, params, options, resolve, reject, status) {
    // ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° ΠΏΡ€Π°Π² администратора
    if (command === 'reset' && options && !options.is_admin) {
      return reject({message: 'Access Denied!'});
    }
    
    switch(command) {
      case 'update_config':
        // ОбновлСниС ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ
        this.updateCapabilities();
        this.updateSettingsEx();
        
        this.publish(this.eventName, {
          capabilities: this.capabilities,
          settings_ex: this.settings_ex
        });
        
        // БистСмноС ΡƒΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ ΠΎΠ± ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ настроСк
        this.sendNotifyEx({
          system: true,
          type: 'settings-update',
          ident: this.ident
        });
        
        resolve({success: true});
        break;
      
      case 'status':
        resolve({
          connected: true,
          devices_count: this.capabilities.length
        });
        break;
      
      default:
        reject({message: 'НСизвСстная ΠΊΠΎΠΌΠ°Π½Π΄Π°'});
    }
  }
}

const app = new DashboardPlugin();
app.logging = true;

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ 3: Плагин-шлюз с Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΠΌΠΈ устройствами

import {baseDriverModule} from '../core/base-driver-module';
import {EventTypes} from '../enums/EventTypes';

class GatewayPlugin extends baseDriverModule {

  private devices: Map<string, any> = new Map();

  initDeviceEx(resolve, reject) {
    super.initDeviceEx(() => {
      this.app.log('Шлюз ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½');
      resolve({});
    }, reject);
  }

  connectEx(resolve, reject) {
    // Π‘ΠΊΠ°Π½ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ устройств
    this.scanDevices().then(() => {
      resolve({});
    });
  }

  async scanDevices() {
    // ΠžΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ устройств (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ‡Π΅Ρ€Π΅Π· Zigbee, Z-Wave ΠΈ Ρ‚.Π΄.)
    const foundDevices = [
      {id: '0x123', type: 'light', name: 'Π‘Π²Π΅Ρ‚ Π² гостиной'},
      {id: '0x456', type: 'sensor', name: 'Π”Π°Ρ‚Ρ‡ΠΈΠΊ Ρ‚Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Ρ‹'}
    ];

    for (const device of foundDevices) {
      await this.registerDevice(device);
    }
  }

  async registerDevice(device: any) {
    let model, icon, capabilities;

    if (device.type === 'light') {
      model = 'gateway.light';
      icon = 'light';
      capabilities = [
        {
          property: 'state',
          ident: 'state',
          display_name: 'Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΎ',
          access: 'rw',
          homekit: true,
          yandex: true,
          options: {value_on: true, value_off: false}
        },
        {
          property: 'brightness',
          ident: 'brightness',
          display_name: 'Π―Ρ€ΠΊΠΎΡΡ‚ΡŒ',
          access: 'rw',
          homekit: true,
          options: {minValue: 0, maxValue: 100, stepValue: 1}
        }
      ];
    } else if (device.type === 'sensor') {
      model = 'gateway.temperature';
      icon = 'temp_sensor';
      capabilities = [
        {
          property: 'temperature',
          ident: 'temperature',
          display_name: 'Π’Π΅ΠΌΠΏΠ΅Ρ€Π°Ρ‚ΡƒΡ€Π°',
          access: 'r',
          scale: 'Β°C'
        }
      ];
    }

    const result = await this.checkSubDevice(
      model,
      device.id,
      device.name,
      {icon, identifier: device.id, capabilities},
      null
    );

    this.devices.set(device.id, device);
    this.app.log('ЗарСгистрировано устройство:', device.name);
  }

  commandEx(command, value, params, options, resolve, reject, status) {
    const deviceId = options.ident;
    
    // ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌΡƒ Π΄ΠΎΡ‡Π΅Ρ€Π½Π΅ΠΌΡƒ устройству
    if (this.devices.has(deviceId)) {
      // Π—Π΄Π΅ΡΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΊΠ° ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Ρ‡Π΅Ρ€Π΅Π· ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ» шлюза
      this.app.log('Команда для устройства', deviceId, ':', command, value);
      resolve({success: true});
    } else {
      reject({message: 'Устройство Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ'});
    }
  }

  getSubDevicesEx(resolve, reject, zones) {
    // Π’ΠΎΠ·Π²Ρ€Π°Ρ‚ списка всСх Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… устройств
    const devices = Array.from(this.devices.values()).map(device => ({
      class_name: 'GatewayDevice',
      identifier: device.id,
      name: device.name,
      params: {
        icon: device.type === 'light' ? 'light' : 'temp_sensor',
        identifier: device.id
      }
    }));

    resolve(devices);
  }
}

const app = new GatewayPlugin();
app.logging = true;

ΠžΡ‚Π»Π°Π΄ΠΊΠ° ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ²

Π›ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ запуск

Для Ρ€ΡƒΡ‡Π½ΠΎΠ³ΠΎ тСстирования ΠΏΠ»Π°Π³ΠΈΠ½Π°:

const app = new MyPlugin();
app.logging = true;

// Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΡ с тСстовыми ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ
app.initDevice({
  params: {
    url: 'http://192.168.1.100',
    port: 80
  }
}).then(() => {
  // ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅
  app.connect({id: 1}).then(() => {
    // ВСстовая ΠΊΠΎΠΌΠ°Π½Π΄Π°
    app.command({
      command: 'status',
      id: 1
    }).then(result => {
      console.log('Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚:', result);
    });
  });
});

Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

// Π Π°Π·Π½Ρ‹Π΅ ΡƒΡ€ΠΎΠ²Π½ΠΈ логирования
this.app.log('Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ');         // INFO
this.app.error('Ошибка');           // ERROR
this.app.debug('ΠžΡ‚Π»Π°Π΄ΠΊΠ°');          // DEBUG
this.app.info('Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ');        // INFO

// Π›ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ с автоматичСским таймстампом ΠΈ использованиСм памяти
// Π€ΠΎΡ€ΠΌΠ°Ρ‚: HH:mm:ss [memory] сообщСниС

Π›ΠΎΠ³ΠΈ ΡΠΎΡ…Ρ€Π°Π½ΡΡŽΡ‚ΡΡ Π² ${params.log_path}/${module}-${id}.log с Ρ€ΠΎΡ‚Π°Ρ†ΠΈΠ΅ΠΉ:

  • ΠœΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ€Π°Π·ΠΌΠ΅Ρ€ Ρ„Π°ΠΉΠ»Π°: 10 ΠœΠ‘
  • ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Ρ„Π°ΠΉΠ»ΠΎΠ²: 5

ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ запуска

# Запуск с Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ
node dist/my-plugin.js 123 logging=true

# Π£Π΄Π°Π»Π΅Π½Π½ΠΎΠ΅ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ BARY
node dist/my-plugin.js 123 host=192.168.1.100 port=8000

Π›ΡƒΡ‡ΡˆΠΈΠ΅ ΠΏΡ€Π°ΠΊΡ‚ΠΈΠΊΠΈ

1. ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок

commandEx(command, value, params, options, resolve, reject, status) {
  try {
    // Π’Π°Ρˆ ΠΊΠΎΠ΄
    resolve(result);
  } catch (error) {
    this.app.error('Ошибка выполнСния ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹:', error.message);
    reject({message: error.message, ignore: false});
  }
}

2. ΠŸΠ΅Ρ€Π΅ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€ΠΈ ΠΎΡˆΠΈΠ±ΠΊΠ°Ρ…

connectEx(resolve, reject) {
  const tryConnect = (attempts = 0) => {
    this.connectToDevice()
      .then(() => resolve({}))
      .catch(error => {
        if (attempts < 3) {
          this.app.log(`ΠŸΠΎΠΏΡ‹Ρ‚ΠΊΠ° ΠΏΠ΅Ρ€Π΅ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ${attempts + 1}/3`);
          setTimeout(() => tryConnect(attempts + 1), 5000);
        } else {
          reject({message: 'НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ'});
        }
      });
  };
  
  tryConnect();
}

3. ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΡ ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ…

// Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ publishStatus для автоматичСской ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ
this.publishStatus(EventTypes.UpdateTemperature, {
  temperature: 22.5,  // ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ >10%
  humidity: 45        // ΠΈΠ»ΠΈ Ρ€Π°Π· Π² 15 сСкунд
});

// Для Π²Π°ΠΆΠ½Ρ‹Ρ… событий ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ publish Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ
this.publish(EventTypes.ChangedMotion, {
  motion: true  // ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡΡ сразу
});

4. ИспользованиС миксинов для ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½ΠΎΡΡ‚ΠΈ

// РаздСляйтС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Π½Π° миксины
// mixins/params.ts β€” Ρ€Π°Π±ΠΎΡ‚Π° с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ
// mixins/ipc.ts β€” Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Π°Ρ IPC Π»ΠΎΠ³ΠΈΠΊΠ°
// mixins/servo.ts β€” ΡƒΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ сСрвоприводами

class MyPlugin extends baseDriverModule.with(Params, IPC, Servo) {
  // Чистый ΠΈ ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½Ρ‹ΠΉ ΠΊΠΎΠ΄
}

5. Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ зависимостями

Π’ my-plugin.json ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΠΉΡ‚Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ спСцифичныС для вашСго ΠΏΠ»Π°Π³ΠΈΠ½Π° зависимости:

{
  "dependencies": {
    "my-device-sdk": "^2.0.0",
    "zwave-js": "^9.2.2"
  }
}

BARY автоматичСски установит ΠΈΡ… ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΌ запускС ΠΏΠ»Π°Π³ΠΈΠ½Π° Ρ‡Π΅Ρ€Π΅Π· RequireEx.

6. ИспользованиС ΠΎΡ‡Π΅Ρ€Π΅Π΄Π΅ΠΉ для ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ

// Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ для ΠΊΠΎΠΌΠ°Π½Π΄ устройству
const Queue = require('../lib/better-queue/queue');

this.requestQueue = new Queue((task, callback) => {
  this.deviceCommand(task.ident, task.command, {}, task.value)
    .then(() => callback(null, {}))
    .catch(error => callback(error));
}, {
  concurrent: 1,
  maxRetries: 3
});

// Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ вмСсто прямых Π²Ρ‹Π·ΠΎΠ²ΠΎΠ²
this.requestQueue.push({
  ident: device.ident,
  command: 'set_power',
  value: true
});

Π‘Π±ΠΎΡ€ΠΊΠ° ΠΈ Ρ€Π°Π·Π²Π΅Ρ€Ρ‚Ρ‹Π²Π°Π½ΠΈΠ΅

ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡ

# Установка зависимостСй
npm install

# Π‘Π±ΠΎΡ€ΠΊΠ°
npm run build

# ΠžΡ‚Π»Π°Π΄ΠΊΠ° с Π°Π²Ρ‚ΠΎΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΎΠΉ
npm run debug

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Ρ€Π΅Π»ΠΈΠ·Π°

# ΠšΠΎΠΌΠΏΠΈΠ»ΡΡ†ΠΈΡ ΠΈ ΡƒΠΏΠ°ΠΊΠΎΠ²ΠΊΠ° Π² ZIP
./compile.sh 1.0.0

# Π‘ ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Π½Π° сСрвСр
./compile.sh 1.0.0 user@server:/path/to/plugins

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ β€” ZIP-Π°Ρ€Ρ…ΠΈΠ² Π² ΠΏΠ°ΠΏΠΊΠ΅ release/ с структурой:

plugins/
β”œβ”€β”€ my-plugin.js
└── my-plugin.json

ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° ΠΈ докумСнтация


ВСрсия Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ: 2.0 (2025-11-19)
ДополнСния: Mixins, Templates, ДинамичСскиС capabilities, Settings_ex, Better-queue, sendNotifyEx, eventTypeStatus, subscribeDevice, onSubscribeDevice

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published