@ray-js/lock-sdk 1.2.0-beta.25 → 1.2.0-beta.27
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/lib/entries/fit/exports/binding.d.ts +1 -0
- package/lib/entries/fit/exports/binding.js +4 -1
- package/lib/feature/fit/bind-lock-to-fit.d.ts +1 -0
- package/lib/feature/fit/bind-lock-to-fit.js +34 -21
- package/lib/feature/fit/list.d.ts +1 -0
- package/lib/feature/fit/list.js +12 -2
- package/lib/feature/fit/method/add-flow.js +2 -2
- package/lib/feature/fit/method/add-password.js +2 -2
- package/lib/feature/fit/security-channel.d.ts +1 -0
- package/lib/feature/fit/security-channel.js +28 -0
- package/lib/feature/fit/shared.d.ts +8 -0
- package/lib/feature/fit/shared.js +40 -1
- package/lib/feature/fit/sync.js +7 -0
- package/lib/feature/log/log.js +14 -1
- package/lib/feature/misc/capability.js +7 -1
- package/lib/feature/misc/is-use-near-channel-for-runtime.js +8 -1
- package/lib/feature/state/device-status.js +15 -4
- package/lib/feature/state/init-state.js +6 -4
- package/lib/feature/state/platform-routing.js +0 -1
- package/lib/feature/unlock/method/add-flow.js +2 -2
- package/lib/feature/unlock/method/add-password.js +2 -2
- package/lib/feature/user/sync-user.js +4 -2
- package/lib/interface.d.ts +2 -0
- package/lib/runtime/lock-config.js +2 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +1 -0
- package/package.json +1 -1
|
@@ -7,3 +7,4 @@ export declare function bindLockToFit(lock: UnbindLockItem): Promise<unknown>;
|
|
|
7
7
|
export declare function unbindLockToFit(lock: BoundFitLockItem & {
|
|
8
8
|
bindingId: string;
|
|
9
9
|
}): Promise<unknown>;
|
|
10
|
+
export declare function activateLockToFit(lock: BoundFitLockItem): Promise<void>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getBoundLockListForRuntime, getUnbindLockListForRuntime, } from "../../../feature/fit/list";
|
|
2
|
-
import { bindLockToFitForRuntime, unbindLockToFitForRuntime, } from "../../../feature/fit/bind-lock-to-fit";
|
|
2
|
+
import { activateLockToFitForRuntime, bindLockToFitForRuntime, unbindLockToFitForRuntime, } from "../../../feature/fit/bind-lock-to-fit";
|
|
3
3
|
import { resolveRuntimeFromExportThis } from "../bootstrap/resolve-runtime-from-export-this";
|
|
4
4
|
export function getBoundLockList() {
|
|
5
5
|
return getBoundLockListForRuntime(resolveRuntimeFromExportThis(this));
|
|
@@ -13,3 +13,6 @@ export function bindLockToFit(lock) {
|
|
|
13
13
|
export function unbindLockToFit(lock) {
|
|
14
14
|
return unbindLockToFitForRuntime(resolveRuntimeFromExportThis(this), lock);
|
|
15
15
|
}
|
|
16
|
+
export function activateLockToFit(lock) {
|
|
17
|
+
return activateLockToFitForRuntime(resolveRuntimeFromExportThis(this), lock);
|
|
18
|
+
}
|
|
@@ -2,3 +2,4 @@ import { BoundFitLockItem, LockFitItemBase } from "../../api/fit";
|
|
|
2
2
|
import type { LockDeviceRuntime } from "../../runtime/LockDeviceRuntime";
|
|
3
3
|
export declare function bindLockToFitForRuntime(runtime: LockDeviceRuntime, lock: LockFitItemBase): Promise<unknown>;
|
|
4
4
|
export declare function unbindLockToFitForRuntime(runtime: LockDeviceRuntime, lock: BoundFitLockItem): Promise<unknown>;
|
|
5
|
+
export declare function activateLockToFitForRuntime(runtime: LockDeviceRuntime, lock: LockFitItemBase): Promise<void>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { bindLockAndFit, unbindFitFromLockCloud, unbindLockFromFitCloud, } from "../../api/fit";
|
|
2
|
+
import { setDeviceProperties } from "../../api/setting";
|
|
2
3
|
import { getUsersSyncLockData } from "../../api/user";
|
|
3
|
-
import {
|
|
4
|
+
import { offDpDataChange, onDpDataChange, publishDeviceDps, } from "../../platform/device";
|
|
4
5
|
import { getError } from "../../utils/errors";
|
|
5
6
|
import { sdkLog } from "../../utils/sdk-log";
|
|
6
|
-
import { isFitSecurityChannelEnabledForRuntime } from "./security-channel";
|
|
7
|
+
import { getSecurityUpdatedLockIds, isFitSecurityChannelEnabledForRuntime, } from "./security-channel";
|
|
7
8
|
import { FIT_BIND_TIMEOUT_MS, FIT_OPERATION_CODE, normalizeHex, buildLockCheckCodeTemplate, publishFitTransparentFlow, } from "./shared";
|
|
8
9
|
const markSecurityUpdated = async (runtime, lock) => {
|
|
9
10
|
if (!lock.isSupportScy || !isFitSecurityChannelEnabledForRuntime(runtime)) {
|
|
@@ -11,28 +12,15 @@ const markSecurityUpdated = async (runtime, lock) => {
|
|
|
11
12
|
}
|
|
12
13
|
const fittingId = runtime.devId;
|
|
13
14
|
try {
|
|
14
|
-
const
|
|
15
|
-
const raw = props?.["SECURITY_UPDATED"];
|
|
16
|
-
let list = [];
|
|
17
|
-
if (typeof raw === "string") {
|
|
18
|
-
try {
|
|
19
|
-
list = JSON.parse(raw).value || [];
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
list = [];
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
else if (raw && typeof raw === "object") {
|
|
26
|
-
list =
|
|
27
|
-
raw.value ||
|
|
28
|
-
(Array.isArray(raw) ? raw : []);
|
|
29
|
-
}
|
|
15
|
+
const list = await getSecurityUpdatedLockIds(fittingId);
|
|
30
16
|
if (list.includes(lock.devId)) {
|
|
31
17
|
return;
|
|
32
18
|
}
|
|
33
|
-
await
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
await setDeviceProperties(fittingId, {
|
|
20
|
+
SECURITY_UPDATED: JSON.stringify({
|
|
21
|
+
key: fittingId,
|
|
22
|
+
value: [...list, lock.devId],
|
|
23
|
+
}),
|
|
36
24
|
});
|
|
37
25
|
}
|
|
38
26
|
catch (e) {
|
|
@@ -205,3 +193,28 @@ export async function unbindLockToFitForRuntime(runtime, lock) {
|
|
|
205
193
|
throw error;
|
|
206
194
|
}
|
|
207
195
|
}
|
|
196
|
+
export async function activateLockToFitForRuntime(runtime, lock) {
|
|
197
|
+
const startedAt = Date.now();
|
|
198
|
+
sdkLog("info", "fit", "activateLockToFitStart", {
|
|
199
|
+
devId: runtime.devId,
|
|
200
|
+
data: { lockDevId: lock.devId },
|
|
201
|
+
});
|
|
202
|
+
try {
|
|
203
|
+
await publishToFitting(runtime, "bind", lock);
|
|
204
|
+
await markSecurityUpdated(runtime, lock);
|
|
205
|
+
sdkLog("info", "fit", "activateLockToFitSuccess", {
|
|
206
|
+
devId: runtime.devId,
|
|
207
|
+
duration: Date.now() - startedAt,
|
|
208
|
+
data: { lockDevId: lock.devId },
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
sdkLog("error", "fit", "activateLockToFitFail", {
|
|
213
|
+
devId: runtime.devId,
|
|
214
|
+
duration: Date.now() - startedAt,
|
|
215
|
+
data: { lockDevId: lock.devId },
|
|
216
|
+
error,
|
|
217
|
+
});
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -7,6 +7,7 @@ export interface UnbindLockListItem extends UnbindLockItem {
|
|
|
7
7
|
}
|
|
8
8
|
export interface BoundLockListItem extends BoundFitLockItem {
|
|
9
9
|
securityVersionMismatch: boolean;
|
|
10
|
+
securityNeedUpdate: boolean;
|
|
10
11
|
}
|
|
11
12
|
export declare function getBoundLockListForRuntime(runtime: LockDeviceRuntime): Promise<BoundLockListItem[]>;
|
|
12
13
|
export declare function getUnbindLockListForRuntime(runtime: LockDeviceRuntime): Promise<UnbindLockListItem[]>;
|
package/lib/feature/fit/list.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getBoundLockListApi, getUnbindLockListApi, } from "../../api/fit";
|
|
2
2
|
import { sdkLog } from "../../utils/sdk-log";
|
|
3
3
|
import { getFitDeviceBvForRuntime } from "./device-bv";
|
|
4
|
-
import { isFitSecurityChannelEnabledForRuntime } from "./security-channel";
|
|
4
|
+
import { getSecurityUpdatedLockIds, isFitSecurityChannelEnabledForRuntime, } from "./security-channel";
|
|
5
5
|
const isSecurityVersionMismatch = (runtime, lock) => !!lock.isSupportScy && !isFitSecurityChannelEnabledForRuntime(runtime);
|
|
6
6
|
const resolveUnbindableReason = (runtime, lock, fitBv) => {
|
|
7
7
|
const lockBv = Number(lock.protocolVersion) || 0;
|
|
@@ -19,9 +19,17 @@ export async function getBoundLockListForRuntime(runtime) {
|
|
|
19
19
|
devId: runtime.devId,
|
|
20
20
|
});
|
|
21
21
|
const list = await getBoundLockListApi(runtime.devId);
|
|
22
|
-
const
|
|
22
|
+
const rawItems = Array.isArray(list) ? list : [];
|
|
23
|
+
const securityEnabled = isFitSecurityChannelEnabledForRuntime(runtime);
|
|
24
|
+
const securityUpdatedIds = securityEnabled && rawItems.some((lock) => lock.isSupportScy)
|
|
25
|
+
? await getSecurityUpdatedLockIds(runtime.devId)
|
|
26
|
+
: [];
|
|
27
|
+
const items = rawItems.map((lock) => ({
|
|
23
28
|
...lock,
|
|
24
29
|
securityVersionMismatch: isSecurityVersionMismatch(runtime, lock),
|
|
30
|
+
securityNeedUpdate: securityEnabled &&
|
|
31
|
+
!!lock.isSupportScy &&
|
|
32
|
+
!securityUpdatedIds.includes(lock.devId),
|
|
25
33
|
}));
|
|
26
34
|
sdkLog("info", "fit", "getBoundLockListSuccess", {
|
|
27
35
|
devId: runtime.devId,
|
|
@@ -29,6 +37,8 @@ export async function getBoundLockListForRuntime(runtime) {
|
|
|
29
37
|
data: {
|
|
30
38
|
count: items.length,
|
|
31
39
|
securityMismatchCount: items.filter((item) => item.securityVersionMismatch).length,
|
|
40
|
+
securityNeedUpdateCount: items.filter((item) => item.securityNeedUpdate)
|
|
41
|
+
.length,
|
|
32
42
|
},
|
|
33
43
|
});
|
|
34
44
|
return items;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import dpUtils from "@ray-js/tuya-dp-transform";
|
|
2
2
|
import { addFitOpenMode } from "../../../api/fit";
|
|
3
|
-
import { sleep } from "../../../utils";
|
|
3
|
+
import { formatCloudUnlockId, sleep } from "../../../utils";
|
|
4
4
|
import { DPCHANGE } from "../../../utils/constant";
|
|
5
5
|
import { getError } from "../../../utils/errors";
|
|
6
6
|
import emitter from "../../../utils/event";
|
|
@@ -195,7 +195,7 @@ const handleAddReport = async (dps) => {
|
|
|
195
195
|
await addFitOpenMode({
|
|
196
196
|
devIdList: [addUnlockMethodData.lockDevId],
|
|
197
197
|
fittingId: rt.devId,
|
|
198
|
-
unlockId:
|
|
198
|
+
unlockId: formatCloudUnlockId(addUnlockMethodData.unlockDpId, result.unlockId),
|
|
199
199
|
unlockName: "",
|
|
200
200
|
userId: addUnlockMethodData.userId,
|
|
201
201
|
hijack: false,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import dpUtils from "@ray-js/tuya-dp-transform";
|
|
2
2
|
import { addFitOpenMode } from "../../../api/fit";
|
|
3
|
-
import { sleep } from "../../../utils";
|
|
3
|
+
import { formatCloudUnlockId, sleep } from "../../../utils";
|
|
4
4
|
import { getError, handleCloudError } from "../../../utils/errors";
|
|
5
5
|
import { publishDpsForRuntime } from "../../dp/publish-dps";
|
|
6
6
|
import { getFitUnlockMethodBase } from "./internal/base";
|
|
@@ -75,7 +75,7 @@ export async function fitAddPasswordForRuntime(rt, params) {
|
|
|
75
75
|
await addFitOpenMode({
|
|
76
76
|
devIdList: [lockDevId],
|
|
77
77
|
fittingId,
|
|
78
|
-
unlockId:
|
|
78
|
+
unlockId: formatCloudUnlockId(dpId, res.unlockId),
|
|
79
79
|
unlockName: params.name,
|
|
80
80
|
userId: params.userId,
|
|
81
81
|
hijack: !!params.hijack,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getDeviceProperties } from "../../api/setting";
|
|
2
|
+
import { sdkLog } from "../../utils/sdk-log";
|
|
1
3
|
export const isFitSecurityChannelEnabledForRuntime = (rt) => {
|
|
2
4
|
const raw = rt.config.devInfo?.meta?.["btScyChannel"];
|
|
3
5
|
if (!raw) {
|
|
@@ -13,3 +15,29 @@ export const isFitSecurityChannelEnabledForRuntime = (rt) => {
|
|
|
13
15
|
return false;
|
|
14
16
|
}
|
|
15
17
|
};
|
|
18
|
+
export const getSecurityUpdatedLockIds = async (fittingId) => {
|
|
19
|
+
try {
|
|
20
|
+
const props = await getDeviceProperties(fittingId, ["SECURITY_UPDATED"]);
|
|
21
|
+
const raw = props?.["SECURITY_UPDATED"];
|
|
22
|
+
if (typeof raw === "string") {
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(raw).value || [];
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (raw && typeof raw === "object") {
|
|
31
|
+
return (raw.value ||
|
|
32
|
+
(Array.isArray(raw) ? raw : []));
|
|
33
|
+
}
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
sdkLog("warn", "fit", "getSecurityUpdatedError", {
|
|
38
|
+
devId: fittingId,
|
|
39
|
+
error: e,
|
|
40
|
+
});
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -2,6 +2,14 @@ export type FitBindOperation = "bind" | "unbind";
|
|
|
2
2
|
export declare const FIT_BIND_TIMEOUT_MS = 12000;
|
|
3
3
|
export declare const FIT_OPERATION_CODE: Record<FitBindOperation, "00" | "01">;
|
|
4
4
|
export declare const normalizeHex: (value: string) => string;
|
|
5
|
+
export declare function markPrecautionaryUnbindPublished(fittingId: string, fit: {
|
|
6
|
+
fittingUnlockId: string;
|
|
7
|
+
randomStr: string;
|
|
8
|
+
devUnlockId: string;
|
|
9
|
+
}): void;
|
|
10
|
+
export declare function clearPrecautionaryUnbindSuppression(fittingId: string): void;
|
|
11
|
+
export declare function shouldSuppressFitSyncReportFrame(fittingId: string, data: string): boolean;
|
|
12
|
+
export declare function normalizeDevUuidHex(devUuid: string): string;
|
|
5
13
|
export declare function buildTransparentData(operation: FitBindOperation, fit: {
|
|
6
14
|
fittingUnlockId: string;
|
|
7
15
|
randomStr: string;
|
|
@@ -7,8 +7,43 @@ export const FIT_OPERATION_CODE = {
|
|
|
7
7
|
unbind: "01",
|
|
8
8
|
};
|
|
9
9
|
export const normalizeHex = (value) => value.replace(/\s/g, "");
|
|
10
|
+
const PRECAUTIONARY_UNBIND_SUPPRESS_MS = 60_000;
|
|
11
|
+
const pendingPrecautionaryUnbindAcks = new Map();
|
|
12
|
+
const buildUnbindAckPrefix = (fit) => `01${fit.fittingUnlockId}${fit.randomStr}${fit.devUnlockId}`.toLowerCase();
|
|
13
|
+
export function markPrecautionaryUnbindPublished(fittingId, fit) {
|
|
14
|
+
pendingPrecautionaryUnbindAcks.set(fittingId, {
|
|
15
|
+
prefix: buildUnbindAckPrefix(fit),
|
|
16
|
+
expiresAt: Date.now() + PRECAUTIONARY_UNBIND_SUPPRESS_MS,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export function clearPrecautionaryUnbindSuppression(fittingId) {
|
|
20
|
+
pendingPrecautionaryUnbindAcks.delete(fittingId);
|
|
21
|
+
}
|
|
22
|
+
export function shouldSuppressFitSyncReportFrame(fittingId, data) {
|
|
23
|
+
const entry = pendingPrecautionaryUnbindAcks.get(fittingId);
|
|
24
|
+
if (!entry) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
if (Date.now() > entry.expiresAt) {
|
|
28
|
+
pendingPrecautionaryUnbindAcks.delete(fittingId);
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return normalizeHex(data).toLowerCase().startsWith(entry.prefix);
|
|
32
|
+
}
|
|
33
|
+
export function normalizeDevUuidHex(devUuid) {
|
|
34
|
+
if (devUuid.length >= 32 &&
|
|
35
|
+
devUuid.length % 2 === 0 &&
|
|
36
|
+
/^[0-9a-fA-F]+$/.test(devUuid)) {
|
|
37
|
+
return devUuid;
|
|
38
|
+
}
|
|
39
|
+
let hex = "";
|
|
40
|
+
for (let i = 0; i < devUuid.length; i += 1) {
|
|
41
|
+
hex += devUuid.charCodeAt(i).toString(16);
|
|
42
|
+
}
|
|
43
|
+
return hex;
|
|
44
|
+
}
|
|
10
45
|
export function buildTransparentData(operation, fit, loginKey) {
|
|
11
|
-
return `${FIT_OPERATION_CODE[operation]}${fit.fittingUnlockId}${fit.randomStr}${fit.devUnlockId}${fit.devUuid}${loginKey}`;
|
|
46
|
+
return `${FIT_OPERATION_CODE[operation]}${fit.fittingUnlockId}${fit.randomStr}${fit.devUnlockId}${normalizeDevUuidHex(fit.devUuid)}${loginKey}`;
|
|
12
47
|
}
|
|
13
48
|
export function buildLockCheckCodeTemplate(operation, fit) {
|
|
14
49
|
return `ffff${fit.devUnlockId}${FIT_OPERATION_CODE[operation]}${fit.fittingUnlockId}${fit.randomStr}`;
|
|
@@ -106,8 +141,12 @@ export async function publishFitTransparentFlow(fittingId, keyDeviceId, operatio
|
|
|
106
141
|
expectedOperation: FIT_OPERATION_CODE[operation],
|
|
107
142
|
});
|
|
108
143
|
if (operation === "bind") {
|
|
144
|
+
markPrecautionaryUnbindPublished(fittingId, fit);
|
|
109
145
|
await publishBLETransparentData(fittingId, buildTransparentData("unbind", fit, loginKey));
|
|
110
146
|
}
|
|
147
|
+
else {
|
|
148
|
+
clearPrecautionaryUnbindSuppression(fittingId);
|
|
149
|
+
}
|
|
111
150
|
await publishBLETransparentData(fittingId, buildTransparentData(operation, fit, loginKey));
|
|
112
151
|
await waitResult;
|
|
113
152
|
sdkLog("info", "fit", "transparentFlowSuccess", {
|
package/lib/feature/fit/sync.js
CHANGED
|
@@ -2,6 +2,7 @@ import { syncFitToLockRise, syncFitReport as syncFitReportApi, syncOpenModeRise
|
|
|
2
2
|
import { unlockMethodDpCodes } from "../utils";
|
|
3
3
|
import { offBLETransparentDataReport, onBLETransparentDataReport, publishBLETransparentData, subscribeBLETransparentDataReport, } from "../../platform/device";
|
|
4
4
|
import { sdkLog } from "../../utils/sdk-log";
|
|
5
|
+
import { shouldSuppressFitSyncReportFrame } from "./shared";
|
|
5
6
|
export async function syncFitBindingsForRuntime(runtime) {
|
|
6
7
|
const startedAt = Date.now();
|
|
7
8
|
const fittingId = runtime.devId;
|
|
@@ -57,6 +58,12 @@ export function startFitSyncReportForRuntime(runtime) {
|
|
|
57
58
|
if (params?.deviceId !== devId || !params?.data) {
|
|
58
59
|
return;
|
|
59
60
|
}
|
|
61
|
+
if (shouldSuppressFitSyncReportFrame(devId, params.data)) {
|
|
62
|
+
sdkLog("info", "fit", "syncReportSuppressPrecautionaryUnbindAck", {
|
|
63
|
+
devId,
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
60
67
|
syncFitReportApi(devId, params.data).catch((e) => {
|
|
61
68
|
sdkLog("warn", "fit", "syncReportAutoError", {
|
|
62
69
|
devId,
|
package/lib/feature/log/log.js
CHANGED
|
@@ -391,7 +391,20 @@ export async function getAlarmsForRuntime(rt, params) {
|
|
|
391
391
|
dpCode,
|
|
392
392
|
userName: record.userName,
|
|
393
393
|
unlockName: record.unlockName,
|
|
394
|
-
mediaInfo: record.mediaInfoList
|
|
394
|
+
mediaInfo: record.mediaInfoList?.map?.(item => {
|
|
395
|
+
return {
|
|
396
|
+
mediaPath: item.mediaPath,
|
|
397
|
+
fileKey: item.fileKey,
|
|
398
|
+
fileUrl: item.fileUrl,
|
|
399
|
+
mediaBucket: item.mediaBucket,
|
|
400
|
+
mediaKey: item.mediaKey,
|
|
401
|
+
width: item.positionWidth,
|
|
402
|
+
height: item.positionHeight,
|
|
403
|
+
angle: item.positionAngle,
|
|
404
|
+
isVR: !!item.positionVr,
|
|
405
|
+
position: item.position,
|
|
406
|
+
};
|
|
407
|
+
}),
|
|
395
408
|
time: record.gmtCreate,
|
|
396
409
|
currentUser: +record.userId === +currentUser.userId,
|
|
397
410
|
bindable: false,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getDeviceAdvancedAbility, getProductAbilities } from "../../api";
|
|
2
|
-
import { ProductCommunicationType } from "../../constant";
|
|
2
|
+
import { CommunicationType, ProductCommunicationType } from "../../constant";
|
|
3
3
|
import { checkShowMatterMutilpleShare } from "../../platform/device";
|
|
4
4
|
import { ipc } from "../../platform";
|
|
5
5
|
import { getWithLocalCache } from "../storage/swr-cache";
|
|
@@ -17,11 +17,17 @@ export const isActiveThreadForRuntime = async (rt) => {
|
|
|
17
17
|
if (hasThread) {
|
|
18
18
|
if (rt.deviceStatus.onlineTypes.includes("cloud") ||
|
|
19
19
|
rt.config.communication.length === 1) {
|
|
20
|
+
rt.cache.isActiveThreadCache = true;
|
|
20
21
|
return true;
|
|
21
22
|
}
|
|
22
23
|
const hasBle = hasCapabilityForRuntime(rt, ProductCommunicationType.BLUETOOTH);
|
|
24
|
+
if (rt.config.capabilities?.communicationType === CommunicationType.THREAD) {
|
|
25
|
+
rt.cache.isActiveThreadCache = true;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
23
28
|
if (hasBle) {
|
|
24
29
|
if (rt.cache.isActiveThreadCache) {
|
|
30
|
+
rt.cache.isActiveThreadCache = true;
|
|
25
31
|
return true;
|
|
26
32
|
}
|
|
27
33
|
try {
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
+
import dpCodes from "src/config/dp-code";
|
|
1
2
|
import { ProductCommunicationType } from "../../constant";
|
|
2
3
|
import { isOnlineByType } from "../../utils";
|
|
4
|
+
import { hasDpForRuntime } from "../dp/has-dp";
|
|
3
5
|
import { hasCapabilityForRuntime } from "./capability";
|
|
4
6
|
export const isUseNearChannelForRuntime = (rt) => {
|
|
5
7
|
const { onlineType, devInfo } = rt.config;
|
|
6
8
|
const isBleOnline = isOnlineByType(onlineType, 2);
|
|
7
9
|
const isSupportWifi = hasCapabilityForRuntime(rt, ProductCommunicationType.WIFI);
|
|
8
10
|
const isSupportBle = hasCapabilityForRuntime(rt, ProductCommunicationType.BLUETOOTH);
|
|
11
|
+
if (isSupportWifi &&
|
|
12
|
+
isSupportBle &&
|
|
13
|
+
!hasDpForRuntime(rt, dpCodes.unlockBle)) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
9
16
|
const isSupportThread = hasCapabilityForRuntime(rt, ProductCommunicationType.THREAD);
|
|
10
17
|
if (isSupportWifi && isSupportBle) {
|
|
11
18
|
return isBleOnline;
|
|
12
19
|
}
|
|
13
20
|
if (isSupportThread && isSupportBle) {
|
|
14
|
-
return isBleOnline && !devInfo.isCloudOnline
|
|
21
|
+
return isBleOnline && !devInfo.isCloudOnline;
|
|
15
22
|
}
|
|
16
23
|
return isBleOnline;
|
|
17
24
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { hasCapabilityForRuntime } from "../misc/capability";
|
|
1
|
+
import { hasCapabilityForRuntime, isActiveThreadForRuntime, } from "../misc/capability";
|
|
2
2
|
import { hasDpForRuntime } from "../dp/has-dp";
|
|
3
3
|
import dpCodes from "../../config/dp-code";
|
|
4
4
|
import { ProductCommunicationType } from "../../constant";
|
|
@@ -13,9 +13,14 @@ import { getDpValueForRuntime } from "../dp/get-dp-value";
|
|
|
13
13
|
import { readIsSleepForRuntime } from "./internal/read-is-sleep";
|
|
14
14
|
import { isShareThreadRuntimeLocal } from "./internal/share-thread-local";
|
|
15
15
|
export const updateOnlineType = async (runtime) => {
|
|
16
|
+
const hasThreadBle = hasCapabilityForRuntime(runtime, ProductCommunicationType.THREAD) &&
|
|
17
|
+
hasCapabilityForRuntime(runtime, ProductCommunicationType.BLUETOOTH);
|
|
16
18
|
const [devInfo, onlineType] = await Promise.all([
|
|
17
19
|
getDeviceInfo(runtime.config.devInfo.devId),
|
|
18
20
|
getDeviceOnlineType(runtime.config.devInfo.devId),
|
|
21
|
+
hasThreadBle && runtime.cache.isActiveThreadCache !== true
|
|
22
|
+
? isActiveThreadForRuntime(runtime)
|
|
23
|
+
: Promise.resolve(false),
|
|
19
24
|
]);
|
|
20
25
|
runtime.config.onlineType = onlineType;
|
|
21
26
|
runtime.config.devInfo = devInfo;
|
|
@@ -34,10 +39,17 @@ export const getDeviceStatusForRuntime = (runtime) => {
|
|
|
34
39
|
onlineTypes: [],
|
|
35
40
|
isWifiActive: wifiEnableState !== 1,
|
|
36
41
|
isWifiMatter: !!isMatter && supportWifi,
|
|
42
|
+
isActiveThread: runtime.cache.isActiveThreadCache ?? false,
|
|
43
|
+
isShareThread: isShareThreadRuntimeLocal(runtime),
|
|
37
44
|
};
|
|
38
45
|
const isMatterLocal = isOnlineByType(onlineType, 8);
|
|
39
46
|
const isBleOnline = isOnlineByType(onlineType, 2);
|
|
40
|
-
|
|
47
|
+
let isLocalOnline = !isCloudOnline && isOnlineByType(onlineType, 1);
|
|
48
|
+
if (isLocalOnline &&
|
|
49
|
+
runtime.cache.isActiveThreadCache !== true &&
|
|
50
|
+
supportThread) {
|
|
51
|
+
isLocalOnline = false;
|
|
52
|
+
}
|
|
41
53
|
const hasWirelessAwakeDp = !notSupportWake && hasDpForRuntime(runtime, dpCodes.wirelessAwake);
|
|
42
54
|
const wirelessAwake = getDpValueForRuntime(runtime, dpCodes.wirelessAwake);
|
|
43
55
|
status.connectEnable = isSupportBleControlForRuntime(runtime) && !isOnline;
|
|
@@ -76,8 +88,7 @@ export const getDeviceStatusForRuntime = (runtime) => {
|
|
|
76
88
|
}
|
|
77
89
|
}
|
|
78
90
|
if (supportThread && supportBle) {
|
|
79
|
-
|
|
80
|
-
if (isShareThread && isOnline) {
|
|
91
|
+
if (status.isShareThread && isOnline) {
|
|
81
92
|
if (!status.onlineTypes.includes("local")) {
|
|
82
93
|
status.onlineTypes = ["local"];
|
|
83
94
|
}
|
|
@@ -2,7 +2,7 @@ import dpCodes from "../../config/dp-code";
|
|
|
2
2
|
import { getDeviceSkill, getIPCConfig, getRotateInfo } from "../../api/video";
|
|
3
3
|
import { getDataWithPreFetchForRuntime } from "../utils";
|
|
4
4
|
import { getWithLocalCache } from "../storage/swr-cache";
|
|
5
|
-
import { getDeviceAdvancedAbilitiesForRuntime, } from "../misc/capability";
|
|
5
|
+
import { getDeviceAdvancedAbilitiesForRuntime, hasCapabilityForRuntime, isActiveThreadForRuntime, } from "../misc/capability";
|
|
6
6
|
import { getCurrentUserForRuntime } from "../user/current-user";
|
|
7
7
|
import { checkOfflineDpUpdateForRuntime } from "../offline-dps";
|
|
8
8
|
import { autoSyncTemp } from "../password/sync-temp";
|
|
@@ -14,9 +14,9 @@ import syncT0 from "./sync/t0";
|
|
|
14
14
|
import { getDeviceStatusForRuntime, updateOnlineType } from "./device-status";
|
|
15
15
|
import { handleDpChange } from "./dp-change";
|
|
16
16
|
import { fetchDeviceProperties } from "./remote-permissions";
|
|
17
|
-
import { ipc, yuChannelSyncSingleSync } from "../../platform";
|
|
17
|
+
import { ipc, yuChannelSyncSingleSync, } from "../../platform";
|
|
18
18
|
import { sdkLog } from "../../utils/sdk-log";
|
|
19
|
-
import { RotateType } from "../../constant";
|
|
19
|
+
import { ProductCommunicationType, RotateType } from "../../constant";
|
|
20
20
|
import { isHarmony } from "../../utils";
|
|
21
21
|
export const initState = async (runtime) => {
|
|
22
22
|
const { devInfo: { dps, devId, yuNetState }, dpSchema, } = runtime.config;
|
|
@@ -31,6 +31,7 @@ export const initState = async (runtime) => {
|
|
|
31
31
|
try {
|
|
32
32
|
handleDpChange(runtime, dps, true);
|
|
33
33
|
const isSupportVideo = !!dpSchema[dpCodes.initiativeMessage];
|
|
34
|
+
const hasThread = hasCapabilityForRuntime(runtime, ProductCommunicationType.THREAD);
|
|
34
35
|
runtime.deviceStatus = getDeviceStatusForRuntime(runtime);
|
|
35
36
|
sdkLog("debug", "initState", "baseStateReady", {
|
|
36
37
|
devId,
|
|
@@ -40,11 +41,12 @@ export const initState = async (runtime) => {
|
|
|
40
41
|
isSupportVideo,
|
|
41
42
|
},
|
|
42
43
|
});
|
|
43
|
-
const [, , , advanceAbilities, rotateInfo, deviceSkill, ipcConfig] = await Promise.allSettled([
|
|
44
|
+
const [, , , advanceAbilities, isActiveThread, rotateInfo, deviceSkill, ipcConfig,] = await Promise.allSettled([
|
|
44
45
|
updateOnlineType(runtime),
|
|
45
46
|
getCurrentUserForRuntime(runtime),
|
|
46
47
|
fetchDeviceProperties(runtime),
|
|
47
48
|
getDeviceAdvancedAbilitiesForRuntime(runtime),
|
|
49
|
+
hasThread ? isActiveThreadForRuntime(runtime) : Promise.resolve(false),
|
|
48
50
|
isSupportVideo
|
|
49
51
|
?
|
|
50
52
|
getDataWithPreFetchForRuntime(runtime, "getRotate", () => getWithLocalCache(runtime, "rotateInfo", () => getRotateInfo(devId), {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import dpUtils from "@ray-js/tuya-dp-transform";
|
|
2
2
|
import { createUnlockMethod } from "../../../api/lock";
|
|
3
3
|
import { parallelOnlyForRuntime } from "../../utils";
|
|
4
|
-
import { sleep } from "../../../utils";
|
|
4
|
+
import { formatCloudUnlockId, sleep } from "../../../utils";
|
|
5
5
|
import { getError } from "../../../utils/errors";
|
|
6
6
|
import { publishDpsForRuntime } from "../../dp/publish-dps";
|
|
7
7
|
import emitter from "../../../utils/event";
|
|
@@ -207,7 +207,7 @@ const handleAddReport = async (dps) => {
|
|
|
207
207
|
const res = await createUnlockMethod({
|
|
208
208
|
devId: cfg.devInfo.devId,
|
|
209
209
|
userId: addUnlockMethodData.userId,
|
|
210
|
-
unlockId:
|
|
210
|
+
unlockId: formatCloudUnlockId(addUnlockMethodData.unlockDpId, result.unlockId),
|
|
211
211
|
unlockName: "",
|
|
212
212
|
unlockAttr: 0,
|
|
213
213
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import dpUtils from "@ray-js/tuya-dp-transform";
|
|
2
2
|
import { createUnlockMethod } from "../../../api/lock";
|
|
3
3
|
import { encrypt } from "../../../platform/device";
|
|
4
|
-
import { sleep } from "../../../utils";
|
|
4
|
+
import { formatCloudUnlockId, sleep } from "../../../utils";
|
|
5
5
|
import { getError, handleCloudError } from "../../../utils/errors";
|
|
6
6
|
import { publishDpsForRuntime } from "../../dp/publish-dps";
|
|
7
7
|
import { getUnlockMethodBase } from "./internal/base";
|
|
@@ -76,7 +76,7 @@ export async function addPasswordForRuntime(rt, params) {
|
|
|
76
76
|
const result = await createUnlockMethod({
|
|
77
77
|
devId: devId,
|
|
78
78
|
userId: params.userId,
|
|
79
|
-
unlockId:
|
|
79
|
+
unlockId: formatCloudUnlockId(dpId, res.unlockId),
|
|
80
80
|
unlockName: params.name,
|
|
81
81
|
unlockDetail: aesPwd,
|
|
82
82
|
...specialInfo,
|
|
@@ -3,10 +3,12 @@ import { deleteUserForRuntime } from "./delete-user-dp";
|
|
|
3
3
|
import { isUseNearChannelForRuntime } from "../misc/is-use-near-channel-for-runtime";
|
|
4
4
|
import { publishDpsOnlyWithRuntime, } from "../dp/publish-dps";
|
|
5
5
|
import dpCodes from "../../config/dp-code";
|
|
6
|
-
import { isBlePureDeviceForRuntime } from "../misc/capability";
|
|
6
|
+
import { hasCapabilityForRuntime, isBlePureDeviceForRuntime } from "../misc/capability";
|
|
7
7
|
import { sdkLog } from "../../utils/sdk-log";
|
|
8
|
+
import { ProductCommunicationType } from "src/constant";
|
|
8
9
|
export async function syncDeleteUsersWithRuntime(runtime) {
|
|
9
|
-
|
|
10
|
+
const hasWifi = hasCapabilityForRuntime(runtime, ProductCommunicationType.WIFI);
|
|
11
|
+
if (hasWifi && runtime.config.devInfo.wifiEnableState !== 1) {
|
|
10
12
|
sdkLog("debug", "syncUser", "deleteUsersSkipped", {
|
|
11
13
|
devId: runtime.devId,
|
|
12
14
|
data: { reason: "wifiActive" },
|
package/lib/interface.d.ts
CHANGED
package/lib/utils/index.d.ts
CHANGED
|
@@ -121,6 +121,7 @@ export declare function getCapabilities(capability: number): ({
|
|
|
121
121
|
readonly short: "thread";
|
|
122
122
|
})[];
|
|
123
123
|
export declare const formatWeek: (value: number[]) => number;
|
|
124
|
+
export declare const formatCloudUnlockId: (dpId: number | string, sn: number) => string;
|
|
124
125
|
export declare const parseWeek: (value: number) => Week;
|
|
125
126
|
export declare const getPermanentSetting: () => {
|
|
126
127
|
startTime: number;
|
package/lib/utils/index.js
CHANGED
|
@@ -56,6 +56,7 @@ export const formatWeek = (value) => {
|
|
|
56
56
|
const temp = value.slice(0, 7);
|
|
57
57
|
return parseInt(temp.reverse().join(""), 2);
|
|
58
58
|
};
|
|
59
|
+
export const formatCloudUnlockId = (dpId, sn) => `${dpId}-${sn.toString(16).padStart(2, "0")}`;
|
|
59
60
|
export const parseWeek = (value) => {
|
|
60
61
|
return Number(value)
|
|
61
62
|
.toString(2)
|