| layout | title | date | categories | description |
|---|---|---|---|---|
article |
Plugin API |
2025-11-19 12:00:00 +0300 |
bary install |
ΠΠΎΠ»Π½ΠΎΠ΅ ΡΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²ΠΎ ΠΏΠΎ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² Π΄Π»Ρ BARY Ρ ΠΏΡΠΎΠ΄Π²ΠΈΠ½ΡΡΡΠΌΠΈ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΡΠΌΠΈ |
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/ # Π‘ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ ΡΠ°ΠΉΠ»Ρ
{
"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"
}
}ΠΠ΅ΡΠ°Π΄Π°Π½Π½ΡΠ΅ ΠΈ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ ΠΏΠ»Π°Π³ΠΈΠ½Π° Π΄Π»Ρ 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 Π³Π΅Π½Π΅ΡΠΈΡΡΡΡΡΡ Π² runtimemac_addressβ ΡΡΠ΅Π±ΡΠ΅ΡΡΡ MAC-Π°Π΄ΡΠ΅Ρdisable_display_sortβ ΠΎΡΠΊΠ»ΡΡΠΈΡΡ ΡΠΎΡΡΠΈΡΠΎΠ²ΠΊΡ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡcapabilitiesβ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡΠΈ ΡΡΡΡΠΎΠΉΡΡΠ²Π°sub_devicesβ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ Π΄ΠΎΡΠ΅ΡΠ½ΠΈΡ ΡΡΡΡΠΎΠΉΡΡΠ²settingsβ ΡΡΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°commandsβ ΠΊΠΎΠΌΠ°Π½Π΄Ρ ΠΏΠ»Π°Π³ΠΈΠ½Π°displayβ ΠΊΠ°ΡΡΠΎΠΌΠΈΠ·Π°ΡΠΈΡ UI (ΠΎΠΏΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎ)dependenciesβ NPM-Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ (ΡΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°ΡΡΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ)
ΠΠ°Π·ΠΎΠ²ΡΠΉ ΠΊΠ»Π°ΡΡ Π΄Π»Ρ Π²ΡΠ΅Ρ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ², ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°Π΅Ρ IPC ΠΊΠΎΠΌΠΌΡΠ½ΠΈΠΊΠ°ΡΠΈΡ Ρ BARY.
ΠΡΠ½ΠΎΠ²Π½ΡΠ΅ ΡΠ²ΠΎΠΉΡΡΠ²Π°:
configβ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡipcβ IPC ΠΊΠ»ΠΈΠ΅Π½Ρ Π΄Π»Ρ ΡΠ²ΡΠ·ΠΈ Ρ BARYeventsβ ΠΌΠ°ΡΡΠΈΠ² Π·Π°ΡΠ΅Π³ΠΈΡΡΡΠΈΡΠΎΠ²Π°Π½Π½ΡΡ ΡΠΎΠ±ΡΡΠΈΠΉ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>Π Π°ΡΡΠΈΡΡΠ΅Ρ 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?): voidBARY ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΡ 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/:
my-plugin/
βββ templates/
βββ device1.json
βββ device2.json
βββ conditioner.json
{
"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
}
]
}// Π ΠΌΠ΅ΡΠΎΠ΄Π΅ ΠΏΠ»Π°Π³ΠΈΠ½Π°
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 ΠΌΠΎΠΆΠ½ΠΎ Π³Π΅Π½Π΅ΡΠΈΡΠΎΠ²Π°ΡΡ Π΄ΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈ Π² ΠΌΠ΅ΡΠΎΠ΄Π΅ connectEx() ΠΈΠ»ΠΈ ΠΏΡΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠ°ΡΠΈΠΈ.
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({});
}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_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({});
}keyβ ΠΊΠ»ΡΡ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈnameβ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅ΠΌΠΎΠ΅ ΠΈΠΌΡtypeβ ΡΠΈΠΏ ΠΏΠΎΠ»Ρ (text,select,checkbox,title)itemsβ ΡΠ»Π΅ΠΌΠ΅Π½ΡΡ Π΄Π»ΡselectdefaultValueβ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡrequiredβ ΠΎΠ±ΡΠ·Π°ΡΠ΅Π»ΡΠ½ΠΎΠ΅ ΠΏΠΎΠ»Π΅driver_supportβ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ ΡΡΡΡΠΎΠΉΡΡΠ² ΠΏΠΎ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠΌ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌdriver_typesβ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ ΡΡΡΡΠΎΠΉΡΡΠ² ΠΏΠΎ ΡΠΈΠΏΡmultiβ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²Π΅Π½Π½ΡΠΉ Π²ΡΠ±ΠΎΡ (Π΄Π»Ρselect)zone_supportβ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ Π·ΠΎΠ½ (['rooms']β ΡΠΎΠ»ΡΠΊΠΎ ΠΊΠΎΠΌΠ½Π°ΡΡ)visibleFieldβ ΠΏΠΎΠ»Π΅, ΠΎΡ ΠΊΠΎΡΠΎΡΠΎΠ³ΠΎ Π·Π°Π²ΠΈΡΠΈΡ Π²ΠΈΠ΄ΠΈΠΌΠΎΡΡΡvisibleFieldValueβ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ ΠΏΠΎΠ»Ρ Π΄Π»Ρ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡdescriptionβ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠΉΠΊΠΈgroupβ Π³ΡΡΠΏΠΏΠ° Π½Π°ΡΡΡΠΎΠ΅ΠΊ (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ,settingsDevice)
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(body: object): voidΠΡΠΈΠΌΠ΅Ρ:
// ΠΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΡΡΡΡΠΎΠΉΡΡΠ²Π°
this.sendNotifyEx({
system: true,
type: 'device-update',
ident: this.ident
});
// ΠΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠ΅ΠΊ
this.sendNotifyEx({
system: true,
type: 'settings-update',
ident: this.ident
});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>// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΎΡΠ΅ΡΠ΅Π΄ΠΈ Π·Π°ΠΏΡΠΎΡΠΎΠ²
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);DeviceCreateβ ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΡΡΡΠΎΠΉΡΡΠ²Π°DeviceUpdateβ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΡΡΡΡΠΎΠΉΡΡΠ²Π°DeviceDeleteβ ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ ΡΡΡΡΠΎΠΉΡΡΠ²Π°DeviceConnectβ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΡΡΡΠΎΠΉΡΡΠ²Π°DeviceDiscoverβ ΠΎΠ±Π½Π°ΡΡΠΆΠ΅Π½ΠΈΠ΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΡΡΡΡΠΎΠΉΡΡΠ²Π°
UpdateTemperatureβ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΡΠ΅ΠΌΠΏΠ΅ΡΠ°ΡΡΡΡUpdateThermostatTempβ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΡΠ΅ΠΌΠΏΠ΅ΡΠ°ΡΡΡΡ ΡΠ΅ΡΠΌΠΎΡΡΠ°ΡΠ°UpdatePowerβ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΌΠΎΡΠ½ΠΎΡΡΠΈUpdateAlertβ ΠΏΡΠ΅Π΄ΡΠΏΡΠ΅ΠΆΠ΄Π΅Π½ΠΈΠ΅
ChangedMotionβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π΄Π°ΡΡΠΈΠΊΠ° Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΡChangedMagnetβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π³Π΅ΡΠΊΠΎΠ½Π° (ΠΎΡΠΊΡΡΡΠΈΠ΅/Π·Π°ΠΊΡΡΡΠΈΠ΅)ChangedMagnetChangeβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π³Π΅ΡΠΊΠΎΠ½Π° Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠ΅ΠΉ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉChangedPowerβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΏΠΈΡΠ°Π½ΠΈΡChangedPowerChangeβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΡΠΎΡΡΠΎΡΠ½ΠΈΡ ΠΏΠΈΡΠ°Π½ΠΈΡ Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠ΅ΠΉ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉChangedPowerLoadβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π½Π°Π³ΡΡΠ·ΠΊΠΈChangedActionβ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΎΠ΅ Π΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ChangedLeakChangeβ ΠΎΠ±Π½Π°ΡΡΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡΠΎΡΠ΅ΡΠΊΠΈChangedInputChangeβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π²Ρ ΠΎΠ΄Π°ChangedCounterChangeβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΡΡΠ΅ΡΡΠΈΠΊΠ°ChangedChannelβ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠ°Π½Π°Π»Π°ChangedChannel0β ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠ°Π½Π°Π»Π° 0ChangedChannel1β ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ΠΊΠ°Π½Π°Π»Π° 1
MqttMessageβ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ MQTT
NewStatsβ Π½ΠΎΠ²Π°Ρ ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠ°NewStatsExβ ΡΠ°ΡΡΠΈΡΠ΅Π½Π½Π°Ρ ΡΡΠ°ΡΠΈΡΡΠΈΠΊΠ°
WiFiConnectβ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ Wi-FiWiFiConnectedβ 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β ΡΠ°ΡΡΠΈΡΠ΅Π½Π½ΠΎΠ΅ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π΄Π°ΡΡΠΈΠΊΠ°
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;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;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=8000commandEx(command, value, params, options, resolve, reject, status) {
try {
// ΠΠ°Ρ ΠΊΠΎΠ΄
resolve(result);
} catch (error) {
this.app.error('ΠΡΠΈΠ±ΠΊΠ° Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΊΠΎΠΌΠ°Π½Π΄Ρ:', error.message);
reject({message: error.message, ignore: false});
}
}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();
}// ΠΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ publishStatus Π΄Π»Ρ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΠΎΠΏΡΠΈΠΌΠΈΠ·Π°ΡΠΈΠΈ
this.publishStatus(EventTypes.UpdateTemperature, {
temperature: 22.5, // ΠΡΠΏΡΠ°Π²ΠΈΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ >10%
humidity: 45 // ΠΈΠ»ΠΈ ΡΠ°Π· Π² 15 ΡΠ΅ΠΊΡΠ½Π΄
});
// ΠΠ»Ρ Π²Π°ΠΆΠ½ΡΡ
ΡΠΎΠ±ΡΡΠΈΠΉ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ publish Π½Π°ΠΏΡΡΠΌΡΡ
this.publish(EventTypes.ChangedMotion, {
motion: true // ΠΡΠΏΡΠ°Π²ΠΈΡΡΡ ΡΡΠ°Π·Ρ
});// Π Π°Π·Π΄Π΅Π»ΡΠΉΡΠ΅ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΡ Π½Π° ΠΌΠΈΠΊΡΠΈΠ½Ρ
// mixins/params.ts β ΡΠ°Π±ΠΎΡΠ° Ρ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠ°ΠΌΠΈ
// mixins/ipc.ts β Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½Π°Ρ IPC Π»ΠΎΠ³ΠΈΠΊΠ°
// mixins/servo.ts β ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΠ΅ΡΠ²ΠΎΠΏΡΠΈΠ²ΠΎΠ΄Π°ΠΌΠΈ
class MyPlugin extends baseDriverModule.with(Params, IPC, Servo) {
// Π§ΠΈΡΡΡΠΉ ΠΈ ΠΌΠΎΠ΄ΡΠ»ΡΠ½ΡΠΉ ΠΊΠΎΠ΄
}Π 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
- ΠΡΠΈΡΠΈΠ°Π»ΡΠ½ΡΠΉ ΡΠ°ΠΉΡ: https://bary.io
- Email: support@bary.io
- Telegram: @bary_support
- ΠΡΠΈΠΌΠ΅ΡΡ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ²: https://github.com/bary-io/plugins
ΠΠ΅ΡΡΠΈΡ Π΄ΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΠΈ: 2.0 (2025-11-19)
ΠΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ: Mixins, Templates, ΠΠΈΠ½Π°ΠΌΠΈΡΠ΅ΡΠΊΠΈΠ΅ capabilities, Settings_ex, Better-queue, sendNotifyEx, eventTypeStatus, subscribeDevice, onSubscribeDevice