@iobroker/dm-utils 1.0.16 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -7
- package/build/DeviceManagement.d.ts +5 -2
- package/build/DeviceManagement.js +41 -2
- package/build/types/base.d.ts +39 -10
- package/build/types/common.d.ts +18 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,6 +73,14 @@ the `DeviceManagement` implementation's `handleXxxAction()` is called, and the a
|
|
|
73
73
|
The communication between the `ioBroker.device-manager` tab and the adapter happens through `sendTo`.
|
|
74
74
|
|
|
75
75
|
**IMPORTANT:** make sure your adapter doesn't handle `sendTo` messages starting with `dm:`, otherwise the communication will not work.
|
|
76
|
+
- Use for Example this on the top of your onMessage Methode:
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
if (obj.command?.startsWith('dm:')) {
|
|
80
|
+
// Handled by Device Manager class itself, so ignored here
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
76
84
|
|
|
77
85
|
### Access adapter methods
|
|
78
86
|
|
|
@@ -116,12 +124,11 @@ Every array entry is an object of type `DeviceInfo` which has the following prop
|
|
|
116
124
|
|
|
117
125
|
- `id` (string): a unique (human-readable) identifier of the device (it must be unique for your adapter instance only)
|
|
118
126
|
- `name` (string or translations): the human-readable name of this device
|
|
119
|
-
- `status` (optional): the current status of the device, which
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
- `
|
|
124
|
-
- `description` (string, optional): a text that will be shown as a tooltip on the status
|
|
127
|
+
- `status` (optional): the current status of the device, which has to be an object containing:
|
|
128
|
+
- `connection` (string): alowed values are: `"connected"` / `"disconnected"`
|
|
129
|
+
- `rssi` (number): rssi value of the connection
|
|
130
|
+
- `battery` (boolean / number): if boolean: false: Battery empty. If number: battery level of the device (shows also a battery symbol at card)
|
|
131
|
+
- `warning` (boolean / string): if boolean: true indicates a warning. If string: shows also the warning with mouseover
|
|
125
132
|
- `actions` (array, optional): an array of actions that can be performed on the device; each object contains:
|
|
126
133
|
- `id` (string): unique identifier to recognize an action (never shown to the user)
|
|
127
134
|
- `icon` (string): an icon shown on the button (see below for details)
|
|
@@ -129,19 +136,26 @@ Every array entry is an object of type `DeviceInfo` which has the following prop
|
|
|
129
136
|
- `disabled` (boolean, optional): if set to `true`, the button can't be clicked but is shown to the user
|
|
130
137
|
- `hasDetails` (boolean, optional): if set to `true`, the row of the device can be expanded and details are shown below
|
|
131
138
|
|
|
139
|
+
Possible strings for device icons are here: [TYPE ICONS](https://github.com/ioBroker/adapter-react-v5/blob/main/src/Components/DeviceType/DeviceTypeIcon.tsx#L68)
|
|
140
|
+
<br/>
|
|
141
|
+
Possible strings for action icons are here: [ACTION NAMES](https://github.com/ioBroker/dm-gui-components/blob/main/src/Utils.tsx#L128)
|
|
142
|
+
<br/>
|
|
143
|
+
Possible strings for configuration icons are here: [CONFIGURATION TYPES](https://github.com/ioBroker/dm-utils/blob/b3e54ecfaedd6a239beec59c5deb8117d1d59d7f/src/types/common.ts#L110)
|
|
144
|
+
<br/>
|
|
132
145
|
### `getInstanceInfo()`
|
|
133
146
|
|
|
134
147
|
This method allows the device manager tab to gather some general information about the instance. It is called when the user opens the tab.
|
|
135
148
|
|
|
136
149
|
If you override this method, the returned object must contain:
|
|
137
150
|
|
|
138
|
-
- `apiVersion` (string): the supported API version; must
|
|
151
|
+
- `apiVersion` (string): the supported API version; must be `"v1"` or `"v2"` (if "backend to GUI communication" is used or IDs instead of values)
|
|
139
152
|
- `actions` (array, optional): an array of actions that can be performed on the instance; each object contains:
|
|
140
153
|
- `id` (string): unique identifier to recognize an action (never shown to the user)
|
|
141
154
|
- `icon` (string): an icon shown on the button (see below for details)
|
|
142
155
|
- `title` (string): the title shown next to the icon on the button
|
|
143
156
|
- `description` (string, optional): a text that will be shown as a tooltip on the button
|
|
144
157
|
- `disabled` (boolean, optional): if set to `true`, the button can't be clicked but is shown to the user
|
|
158
|
+
- `communicationStateId` (string) (optional): the ID of the state that is used by backend for communication with front-end (only API v2)
|
|
145
159
|
|
|
146
160
|
### `getDeviceDetails(id: string)`
|
|
147
161
|
|
|
@@ -295,12 +309,45 @@ This method returns a promise that resolves to a `ProgressDialog` object.
|
|
|
295
309
|
- `label` (string, optional): change the label to the right of the progress bar
|
|
296
310
|
- `close()`
|
|
297
311
|
- Closes the progress dialog (and allows you to open other dialogs)
|
|
312
|
+
|
|
313
|
+
### `sendCommandToGui(command: BackendToGuiCommand)`
|
|
314
|
+
|
|
315
|
+
Sends command to GUI to add/update/delete devices or to update the status of device.
|
|
316
|
+
|
|
317
|
+
**It is suggested** to use the state's ID directly in DeviceInfo structure instead of sending the command every time to GUI on status update.
|
|
318
|
+
|
|
319
|
+
See example below:
|
|
320
|
+
```ts
|
|
321
|
+
class MyAdapterDeviceManagement extends DeviceManagement<MyAdapter> {
|
|
322
|
+
protected listDevices(): RetVal<DeviceInfo[]>{
|
|
323
|
+
const deviceInfo: DeviceInfo = {
|
|
324
|
+
id: 'uniqieID',
|
|
325
|
+
name: 'My device',
|
|
326
|
+
icon: 'node', // find possible icons here: https://github.com/ioBroker/adapter-react-v5/blob/main/src/Components/DeviceType/DeviceTypeIcon.tsx#L68
|
|
327
|
+
manufacturer: { objectId: 'uniqieID', property: 'native.manufacturer' },
|
|
328
|
+
model: { objectId: 'uniqieID', property: 'native.model' },
|
|
329
|
+
status: {
|
|
330
|
+
battery: { stateId: 'uniqieID.DevicePower0.BatteryPercent' },
|
|
331
|
+
connection: { stateId: 'uniqieID.online', mapping: {'true': 'connected', 'false': 'disconnected'} },
|
|
332
|
+
rssi: { stateId: 'uniqieID.rssi' },
|
|
333
|
+
},
|
|
334
|
+
hasDetails: true,
|
|
335
|
+
};
|
|
336
|
+
return [deviceInfo];
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
298
340
|
|
|
299
341
|
<!--
|
|
300
342
|
Placeholder for the next version (at the beginning of the line):
|
|
301
343
|
### **WORK IN PROGRESS**
|
|
302
344
|
-->
|
|
303
345
|
## Changelog
|
|
346
|
+
### 2.0.1 (2026-01-28)
|
|
347
|
+
* (@GermanBluefox) BREAKING: Admin/GUI must have version 9 (or higher) of `dm-gui-components`
|
|
348
|
+
* (@GermanBluefox) Added types to update status of device directly from state
|
|
349
|
+
* (@GermanBluefox) Added backend to GUI communication possibility
|
|
350
|
+
|
|
304
351
|
### 1.0.16 (2026-01-02)
|
|
305
352
|
* (@GermanBluefox) Added `ignoreApplyDisabled` flag
|
|
306
353
|
* (@GermanBluefox) Added `update` icon
|
|
@@ -2,13 +2,16 @@ import type { AdapterInstance } from '@iobroker/adapter-core';
|
|
|
2
2
|
import type { ActionContext } from './ActionContext';
|
|
3
3
|
import type { ProgressDialog } from './ProgressDialog';
|
|
4
4
|
import { type DeviceDetails, type DeviceInfo, type ErrorResponse, type InstanceDetails, type JsonFormData, type JsonFormSchema, type RefreshResponse, type RetVal, type ActionButton } from './types';
|
|
5
|
-
import type { ControlState } from './types/base';
|
|
5
|
+
import type { BackendToGuiCommand, ControlState } from './types/base';
|
|
6
6
|
export declare abstract class DeviceManagement<T extends AdapterInstance = AdapterInstance> {
|
|
7
7
|
protected readonly adapter: T;
|
|
8
8
|
private instanceInfo?;
|
|
9
9
|
private devices?;
|
|
10
|
+
private readonly communicationStateId;
|
|
10
11
|
private readonly contexts;
|
|
11
|
-
constructor(adapter: T);
|
|
12
|
+
constructor(adapter: T, communicationStateId?: string | boolean);
|
|
13
|
+
private ensureCommunicationState;
|
|
14
|
+
protected sendCommandToGui(command: BackendToGuiCommand): Promise<void>;
|
|
12
15
|
protected get log(): ioBroker.Log;
|
|
13
16
|
protected getInstanceInfo(): RetVal<InstanceDetails>;
|
|
14
17
|
protected abstract listDevices(): RetVal<DeviceInfo[]>;
|
|
@@ -3,16 +3,55 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.MessageContext = exports.DeviceManagement = void 0;
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
class DeviceManagement {
|
|
6
|
-
constructor(adapter) {
|
|
6
|
+
constructor(adapter, communicationStateId) {
|
|
7
7
|
this.adapter = adapter;
|
|
8
8
|
this.contexts = new Map();
|
|
9
9
|
adapter.on('message', this.onMessage.bind(this));
|
|
10
|
+
if (communicationStateId === true) {
|
|
11
|
+
// use standard ID `info.deviceManager`
|
|
12
|
+
this.communicationStateId = 'info.deviceManager';
|
|
13
|
+
}
|
|
14
|
+
else if (communicationStateId) {
|
|
15
|
+
this.communicationStateId = communicationStateId;
|
|
16
|
+
}
|
|
17
|
+
if (this.communicationStateId) {
|
|
18
|
+
this.ensureCommunicationState().catch(e => this.log().error(`Cannot initialize communication state: ${e}`));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async ensureCommunicationState() {
|
|
22
|
+
let stateObj = await this.adapter.getObjectAsync(this.communicationStateId);
|
|
23
|
+
if (!stateObj) {
|
|
24
|
+
stateObj = {
|
|
25
|
+
_id: this.communicationStateId,
|
|
26
|
+
type: 'state',
|
|
27
|
+
common: {
|
|
28
|
+
expert: true,
|
|
29
|
+
name: 'Communication with GUI for device manager',
|
|
30
|
+
type: 'string',
|
|
31
|
+
role: 'state',
|
|
32
|
+
def: '',
|
|
33
|
+
read: true,
|
|
34
|
+
write: false,
|
|
35
|
+
},
|
|
36
|
+
native: {},
|
|
37
|
+
};
|
|
38
|
+
await this.adapter.setObjectAsync(this.communicationStateId, stateObj);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
async sendCommandToGui(command) {
|
|
42
|
+
if (this.communicationStateId) {
|
|
43
|
+
await this.adapter.setStateAsync(this.communicationStateId, JSON.stringify(command), true);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
throw new Error('Communication state not found');
|
|
47
|
+
}
|
|
10
48
|
}
|
|
11
49
|
get log() {
|
|
12
50
|
return this.adapter.log;
|
|
13
51
|
}
|
|
14
52
|
getInstanceInfo() {
|
|
15
|
-
|
|
53
|
+
// Overload this method if your adapter does not use BackendToGui communication and States/Objects in DeviceInfo
|
|
54
|
+
return { apiVersion: 'v2', communicationStateId: this.communicationStateId || undefined };
|
|
16
55
|
}
|
|
17
56
|
getDeviceDetails(id) {
|
|
18
57
|
return { id, schema: {} };
|
package/build/types/base.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ActionContext, ConfigConnectionType, ErrorResponse, MessageContext } from '..';
|
|
1
|
+
import type { ActionContext, ConfigConnectionType, ErrorResponse, MessageContext, ValueOrObject, ValueOrState, ValueOrStateOrObject } from '..';
|
|
2
2
|
import type { ApiVersion, DeviceRefresh, DeviceStatus, RetVal } from './common';
|
|
3
3
|
type ActionType = 'api' | 'adapter';
|
|
4
4
|
export type Color = 'primary' | 'secondary' | (string & {});
|
|
@@ -97,33 +97,36 @@ export interface DeviceAction<T extends ActionType = 'api'> extends ActionBase<T
|
|
|
97
97
|
}>;
|
|
98
98
|
}
|
|
99
99
|
export interface InstanceDetails<T extends ActionType = 'api'> {
|
|
100
|
+
/** API Version: 1 - till 2025 (including), 2 - from 2026 */
|
|
100
101
|
apiVersion: ApiVersion;
|
|
101
102
|
actions?: InstanceAction<T>[];
|
|
103
|
+
/** ID of state used for communication with GUI */
|
|
104
|
+
communicationStateId?: string;
|
|
102
105
|
}
|
|
103
106
|
export interface DeviceInfo<T extends ActionType = 'api'> {
|
|
104
107
|
/** ID of the action. Should be unique only in one adapter. Other adapters could have same names */
|
|
105
108
|
id: string;
|
|
106
109
|
/** Name of the device. It will be shown in the card header */
|
|
107
|
-
name: ioBroker.StringOrTranslated
|
|
110
|
+
name: ValueOrObject<ioBroker.StringOrTranslated>;
|
|
108
111
|
/** base64 or url icon for device card */
|
|
109
|
-
icon?: string
|
|
110
|
-
manufacturer?: ioBroker.StringOrTranslated
|
|
111
|
-
model?: ioBroker.StringOrTranslated
|
|
112
|
+
icon?: ValueOrState<string>;
|
|
113
|
+
manufacturer?: ValueOrStateOrObject<ioBroker.StringOrTranslated>;
|
|
114
|
+
model?: ValueOrStateOrObject<ioBroker.StringOrTranslated>;
|
|
112
115
|
/** Color or 'primary', 'secondary' for the text in the card header */
|
|
113
|
-
color?: Color
|
|
116
|
+
color?: ValueOrState<Color>;
|
|
114
117
|
/** Background color of card header (you can use primary, secondary or color rgb value or hex) */
|
|
115
|
-
backgroundColor?: Color
|
|
118
|
+
backgroundColor?: ValueOrState<Color>;
|
|
116
119
|
status?: DeviceStatus | DeviceStatus[];
|
|
117
120
|
/** Connection type, how the device is connected */
|
|
118
|
-
connectionType?: ConfigConnectionType
|
|
121
|
+
connectionType?: ValueOrStateOrObject<ConfigConnectionType>;
|
|
119
122
|
/** If this flag is true or false, the according indication will be shown. Additionally, if ACTIONS.ENABLE_DISABLE is implemented, this action will be sent to backend by clicking on this indication */
|
|
120
|
-
enabled?: boolean
|
|
123
|
+
enabled?: ValueOrState<boolean>;
|
|
121
124
|
/** List of actions on the card */
|
|
122
125
|
actions?: DeviceAction<T>[];
|
|
123
126
|
/** List of controls on the card. The difference of controls and actions is that the controls can show status (e.g. on/off) and can work directly with states */
|
|
124
127
|
controls?: DeviceControl<T>[];
|
|
125
128
|
/** If true, the button `more` will be shown on the card and called `dm:deviceDetails` action to get the details */
|
|
126
|
-
hasDetails?: boolean
|
|
129
|
+
hasDetails?: ValueOrStateOrObject<boolean>;
|
|
127
130
|
/** Device type for grouping */
|
|
128
131
|
group?: {
|
|
129
132
|
key: string;
|
|
@@ -131,4 +134,30 @@ export interface DeviceInfo<T extends ActionType = 'api'> {
|
|
|
131
134
|
icon?: string;
|
|
132
135
|
};
|
|
133
136
|
}
|
|
137
|
+
export interface BackendToGuiCommandDeviceInfoUpdate {
|
|
138
|
+
/** Used for updating and for adding new device */
|
|
139
|
+
command: 'infoUpdate';
|
|
140
|
+
/** Device ID */
|
|
141
|
+
deviceId: string;
|
|
142
|
+
/** Backend can send directly new information about device to avoid extra request from GUI */
|
|
143
|
+
info?: DeviceInfo;
|
|
144
|
+
}
|
|
145
|
+
export interface BackendToGuiCommandDeviceStatusUpdate {
|
|
146
|
+
/** Status of device was updated */
|
|
147
|
+
command: 'statusUpdate';
|
|
148
|
+
/** Device ID */
|
|
149
|
+
deviceId: string;
|
|
150
|
+
/** Backend can send directly new status to avoid extra request from GUI */
|
|
151
|
+
status?: DeviceStatus;
|
|
152
|
+
}
|
|
153
|
+
export interface BackendToGuiCommandDeviceDelete {
|
|
154
|
+
/** Device was deleted */
|
|
155
|
+
command: 'delete';
|
|
156
|
+
deviceId: string;
|
|
157
|
+
}
|
|
158
|
+
export interface BackendToGuiCommandAllUpdate {
|
|
159
|
+
/** Read ALL information about all devices anew */
|
|
160
|
+
command: 'all';
|
|
161
|
+
}
|
|
162
|
+
export type BackendToGuiCommand = BackendToGuiCommandDeviceInfoUpdate | BackendToGuiCommandDeviceStatusUpdate | BackendToGuiCommandDeviceDelete | BackendToGuiCommandAllUpdate;
|
|
134
163
|
export {};
|
package/build/types/common.d.ts
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
export type ApiVersion = 'v1';
|
|
1
|
+
export type ApiVersion = 'v1' | 'v2';
|
|
2
2
|
export type ConfigConnectionType = 'lan' | 'wifi' | 'bluetooth' | 'thread' | 'z-wave' | 'zigbee' | 'other';
|
|
3
|
+
export type ValueOrObject<T> = T | {
|
|
4
|
+
objectId: string;
|
|
5
|
+
property: string;
|
|
6
|
+
};
|
|
7
|
+
export type ValueOrState<T, M = {
|
|
8
|
+
[value: string | number]: string;
|
|
9
|
+
}> = T | {
|
|
10
|
+
stateId: string;
|
|
11
|
+
mapping?: M;
|
|
12
|
+
};
|
|
13
|
+
export type ValueOrStateOrObject<T> = T | ValueOrObject<T> | ValueOrState<T>;
|
|
3
14
|
export type DeviceStatus = 'connected' | 'disconnected' | {
|
|
4
|
-
battery?: number | boolean | 'charging' | string
|
|
5
|
-
connection?: 'connected' | 'disconnected'
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
battery?: ValueOrState<number | boolean | 'charging' | string>;
|
|
16
|
+
connection?: ValueOrState<'connected' | 'disconnected', {
|
|
17
|
+
[value: string]: 'connected' | 'disconnected';
|
|
18
|
+
}>;
|
|
19
|
+
rssi?: ValueOrState<number>;
|
|
20
|
+
warning?: ValueOrState<ioBroker.StringOrTranslated | boolean>;
|
|
8
21
|
};
|
|
9
22
|
export type DeviceRefresh = 'device' | 'instance' | false | true;
|
|
10
23
|
export type RefreshResponse = {
|