mirta 0.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/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <https://unlicense.org>
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # Mirta
2
+
3
+ [![en](https://img.shields.io/badge/lang-en-olivedrab.svg?style=flat-square)](https://github.com/wb-mirta/core/blob/latest/packages/mirta/README.md)
4
+ [![ru](https://img.shields.io/badge/lang-ru-dimgray.svg?style=flat-square)](https://github.com/wb-mirta/core/blob/latest/packages/mirta/README.ru.md)
5
+ [![NPM Version](https://img.shields.io/npm/v/mirta?style=flat-square)](https://npmjs.com/package/mirta)
6
+
7
+ Device helpers and wrappers, focused on developing your own wb-rules.
package/README.ru.md ADDED
@@ -0,0 +1,7 @@
1
+ # Mirta
2
+
3
+ [![en](https://img.shields.io/badge/lang-en-dimgray.svg?style=flat-square)](https://github.com/wb-mirta/core/blob/latest/packages/mirta/README.md)
4
+ [![ru](https://img.shields.io/badge/lang-ru-olivedrab.svg?style=flat-square)](https://github.com/wb-mirta/core/blob/latest/packages/mirta/README.ru.md)
5
+ [![NPM Version](https://img.shields.io/npm/v/mirta?style=flat-square)](https://npmjs.com/package/mirta)
6
+
7
+ Инструменты и обёртки для поддержки работы с устройствами, призванные помочь в разработке ваших собственных правил wb-rules.
@@ -0,0 +1,74 @@
1
+ export * from '@mirta/basics';
2
+
3
+ /** Контекст устройства. */
4
+ interface DeviceContext {
5
+ /** Идентификатор устройства. */
6
+ get id(): string;
7
+ /**
8
+ * Признак готовности к работе,
9
+ * значение меняется при смене статуса. */
10
+ get isReady(): boolean;
11
+ }
12
+ type TrackCallback = (controlId: string, callback: (value: WbRules.MqttValue) => void) => void;
13
+ /** Контекст плагина для привязки к устройству. */
14
+ interface PluginContext {
15
+ device: DeviceContext;
16
+ track: TrackCallback;
17
+ }
18
+ /** Плагин для расширения функциональности устройства. */
19
+ type DevicePlugin<TPlugin = unknown> = (context: PluginContext) => TPlugin;
20
+
21
+ interface DeviceSetupOptions {
22
+ context: DeviceContext;
23
+ setControl: (controlId: string, definition: WbRules.ControlOptions) => void;
24
+ }
25
+ /**
26
+ * Извлекает типы возвращаемых функциями в массиве значений
27
+ * в виде пересечения.
28
+ *
29
+ * */
30
+ type IntersectReturnTypes<TArray> = TArray extends [(...args: unknown[]) => infer TReturn, ...infer TRest] ? TReturn & IntersectReturnTypes<TRest> : object;
31
+ interface DefineDeviceOptions<TPlugins extends DevicePlugin[]> {
32
+ setup?: (options: DeviceSetupOptions) => void;
33
+ plugins?: [...TPlugins];
34
+ }
35
+ type DeviceWithPlugins<TPlugins extends DevicePlugin[]> = IntersectReturnTypes<[...TPlugins]>;
36
+ interface DeviceWithContext {
37
+ /** Контекст устройства. */
38
+ context: DeviceContext;
39
+ /** Метод для отслеживания изменений в топиках. */
40
+ track: (controlId: string, callback: (newValue: WbRules.MqttValue) => void) => void;
41
+ }
42
+ type Device<TPlugins extends DevicePlugin[]> = DeviceWithContext & DeviceWithPlugins<TPlugins>;
43
+ declare function defineZigbeeDevice<TPlugins extends DevicePlugin[]>(deviceId: string, options?: DefineDeviceOptions<TPlugins>): Device<TPlugins>;
44
+
45
+ /**
46
+ * Позволяет получить объект для работы с указанным устройством.
47
+ * @param deviceId Идентификатор устройства.
48
+ *
49
+ */
50
+ declare function getDeviceSafe(deviceId: string, isReadyFunc?: () => boolean): {
51
+ /** Возвращает существующий объект или пытается найти, если его ещё нет. */
52
+ readonly safe: WbRules.Device | undefined;
53
+ };
54
+
55
+ interface ControlSafe {
56
+ safe: WbRules.Control | undefined;
57
+ }
58
+ /**
59
+ * Позволяет получить объект для работы с указанным контролом устройства.
60
+ * @param context Контекст устройства, полученный из функций `tryConfigure`.
61
+ * @param controlId Идентификатор контрола.
62
+ *
63
+ **/
64
+ declare function getControlSafe(context: DeviceContext, controlId: string): ControlSafe;
65
+ /**
66
+ * Позволяет получить объект для работы с указанным контролом устройства.
67
+ * @param deviceId Идентификатор устройства.
68
+ * @param controlId Идентификатор контрола.
69
+ *
70
+ **/
71
+ declare function getControlSafe(deviceId: string, controlId: string, isReadyFunc: () => boolean): ControlSafe;
72
+
73
+ export { defineZigbeeDevice, getControlSafe, getDeviceSafe };
74
+ export type { ControlSafe, DeviceContext, DevicePlugin, PluginContext, TrackCallback };
package/dist/index.mjs ADDED
@@ -0,0 +1,124 @@
1
+ export * from '@mirta/basics';
2
+ import '@mirta/polyfills';
3
+
4
+ function getControlSafe(context, controlId, isReadyFunc = () => true) {
5
+ let control;
6
+ return {
7
+ /** Возвращает существующий объект или пытается найти, если его ещё нет. */
8
+ get safe() {
9
+ if (control)
10
+ return control;
11
+ if (typeof context === 'string') {
12
+ return isReadyFunc()
13
+ ? control = getControl(`${context}/${controlId}`)
14
+ : undefined;
15
+ }
16
+ else {
17
+ return context.isReady
18
+ ? control = getControl(`${context.id}/${controlId}`)
19
+ : undefined;
20
+ }
21
+ },
22
+ };
23
+ }
24
+
25
+ const { assign } = Object;
26
+ if ((process.env.NODE_ENV === 'test')) {
27
+ module.static = {};
28
+ }
29
+ const configured = (module.static.configured ??= {});
30
+ function createContext(deviceId, state) {
31
+ const context = {
32
+ get id() {
33
+ return deviceId;
34
+ },
35
+ get isReady() {
36
+ return state.isReady;
37
+ },
38
+ };
39
+ return context;
40
+ }
41
+ function configureContext(deviceId, setup) {
42
+ // Каждый юнит-тест должен проходить полный цикл построения.
43
+ if ((process.env.NODE_ENV === 'test'))
44
+ configured[deviceId] = undefined;
45
+ if (configured[deviceId])
46
+ return createContext(deviceId, configured[deviceId]);
47
+ const state = configured[deviceId] = {
48
+ isReady: false,
49
+ isConfigurable: true,
50
+ };
51
+ const context = createContext(deviceId, state);
52
+ trackMqtt(`zigbee2mqtt/${deviceId}`, () => {
53
+ // Предотвращает проверку каждого сообщения от zigbee2mqtt
54
+ if (state.isReady || !state.isConfigurable)
55
+ return;
56
+ const device = getDevice(deviceId);
57
+ if (setup && device?.isVirtual()) {
58
+ setup({
59
+ context,
60
+ setControl(controlId, description) {
61
+ if (device.isControlExists(controlId))
62
+ device.removeControl(controlId);
63
+ if ((process.env.NODE_ENV !== 'production'))
64
+ log.debug(`Replacing the control '${controlId}' on '${deviceId}'`);
65
+ device.addControl(controlId, description);
66
+ },
67
+ });
68
+ state.isReady = true;
69
+ }
70
+ else {
71
+ state.isConfigurable = false;
72
+ if ((process.env.NODE_ENV !== 'production'))
73
+ log.warning(`Can't configure '${deviceId}' as a zigbee-device`);
74
+ }
75
+ });
76
+ return context;
77
+ }
78
+ function defineZigbeeDevice(deviceId, options = {}) {
79
+ const context = configureContext(deviceId, options.setup);
80
+ const lastSeen = getControlSafe(context, 'last_seen');
81
+ const startupStamp = lastSeen.safe?.getValue();
82
+ function track(controlId, callback) {
83
+ trackMqtt(`/devices/${deviceId}/controls/${controlId}`, (payload) => {
84
+ const stamp = lastSeen.safe?.getValue();
85
+ if (stamp === startupStamp)
86
+ return;
87
+ callback(payload.value);
88
+ });
89
+ }
90
+ const device = {
91
+ context,
92
+ track,
93
+ };
94
+ const plugins = options.plugins;
95
+ if (plugins) {
96
+ const pluginContext = {
97
+ device: context,
98
+ track,
99
+ };
100
+ options.plugins?.forEach((plugin) => {
101
+ assign(device, plugin(pluginContext));
102
+ });
103
+ }
104
+ return device;
105
+ }
106
+
107
+ /**
108
+ * Позволяет получить объект для работы с указанным устройством.
109
+ * @param deviceId Идентификатор устройства.
110
+ *
111
+ */
112
+ function getDeviceSafe(deviceId, isReadyFunc = () => true) {
113
+ let device;
114
+ return {
115
+ /** Возвращает существующий объект или пытается найти, если его ещё нет. */
116
+ get safe() {
117
+ return device ?? (isReadyFunc()
118
+ ? device = getDevice(deviceId)
119
+ : undefined);
120
+ },
121
+ };
122
+ }
123
+
124
+ export { defineZigbeeDevice, getControlSafe, getDeviceSafe };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "mirta",
3
+ "version": "0.0.1",
4
+ "license": "Unlicense",
5
+ "keywords": [
6
+ "mirta",
7
+ "wb-rules"
8
+ ],
9
+ "type": "module",
10
+ "files": [
11
+ "dist",
12
+ "types",
13
+ "LICENSE",
14
+ "README.md"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "import": {
19
+ "types": "./dist/index.d.mts",
20
+ "default": "./dist/index.mjs"
21
+ }
22
+ }
23
+ },
24
+ "homepage": "https://github.com/wb-mirta/core/tree/latest/packages/mirta#readme",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/wb-mirta/core.git",
28
+ "directory": "packages/mirta"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/wb-mirta/core/issues"
32
+ },
33
+ "funding": {
34
+ "type": "individual",
35
+ "url": "https://pay.cloudtips.ru/p/58512cca"
36
+ },
37
+ "dependencies": {
38
+ "@mirta/basics": "0.0.1",
39
+ "@mirta/globals": "0.0.1",
40
+ "@mirta/polyfills": "0.0.1"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "scripts": {
46
+ "clean": "rimraf dist build",
47
+ "build": "pnpm clean && rollup -c ../../rollup.config.mjs"
48
+ }
49
+ }