sesame-kit 0.4.0
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 +26 -0
- package/LICENSE.biz3 +21 -0
- package/README.ja.md +225 -0
- package/README.md +222 -0
- package/bin/sesame.js +8 -0
- package/clients/js/sesame-client.mjs +208 -0
- package/clients/python/pyproject.toml +5 -0
- package/clients/python/sesame_client.py +323 -0
- package/clients/python/setup.cfg +11 -0
- package/docs/architecture.ja.md +132 -0
- package/docs/architecture.md +105 -0
- package/docs/commands.ja.md +316 -0
- package/docs/commands.md +308 -0
- package/docs/library.ja.md +152 -0
- package/docs/library.md +152 -0
- package/docs/migration.ja.md +13 -0
- package/docs/migration.md +13 -0
- package/package.json +114 -0
- package/src/access.js +375 -0
- package/src/account.js +36 -0
- package/src/auth.js +248 -0
- package/src/ble/devicemodel.js +164 -0
- package/src/ble/index.js +185 -0
- package/src/ble/protocol.js +319 -0
- package/src/ble/session.js +235 -0
- package/src/ble/transport.js +279 -0
- package/src/cli/access.js +373 -0
- package/src/cli/company.js +104 -0
- package/src/cli/iot.js +400 -0
- package/src/cli/org.js +788 -0
- package/src/cli/presetir.js +188 -0
- package/src/cli/schedule.js +83 -0
- package/src/cli/serve.js +308 -0
- package/src/cli.js +1815 -0
- package/src/client.js +957 -0
- package/src/company.js +147 -0
- package/src/config.js +575 -0
- package/src/crypto.js +162 -0
- package/src/devices.js +228 -0
- package/src/index.js +55 -0
- package/src/iot.js +513 -0
- package/src/ir.js +341 -0
- package/src/itemcodes.js +29 -0
- package/src/lock.js +194 -0
- package/src/org.js +803 -0
- package/src/paths.js +30 -0
- package/src/presetir.js +525 -0
- package/src/prompts.js +74 -0
- package/src/schedule.js +108 -0
- package/src/serve/daemon.js +251 -0
- package/src/serve/framing/grpc.js +145 -0
- package/src/serve/framing/http.js +144 -0
- package/src/serve/framing/ndjson.js +75 -0
- package/src/serve/framing/socket.js +73 -0
- package/src/serve/framing/stdio.js +28 -0
- package/src/serve/framing/token.js +36 -0
- package/src/serve/framing/ws.js +56 -0
- package/src/serve/grpc-methods.generated.json +378 -0
- package/src/serve/jsonrpc.js +164 -0
- package/src/serve/registry.js +226 -0
- package/src/serve/rpc-params.generated.json +1746 -0
- package/src/serve/sesame.proto +470 -0
- package/src/session-ui.js +181 -0
- package/src/sharekey.js +130 -0
- package/src/tokens.js +53 -0
- package/src/transport.js +634 -0
- package/src/util.js +26 -0
- package/types/access.d.ts +193 -0
- package/types/access.d.ts.map +1 -0
- package/types/account.d.ts +13 -0
- package/types/account.d.ts.map +1 -0
- package/types/auth.d.ts +80 -0
- package/types/auth.d.ts.map +1 -0
- package/types/ble/devicemodel.d.ts +212 -0
- package/types/ble/devicemodel.d.ts.map +1 -0
- package/types/ble/index.d.ts +160 -0
- package/types/ble/index.d.ts.map +1 -0
- package/types/ble/protocol.d.ts +201 -0
- package/types/ble/protocol.d.ts.map +1 -0
- package/types/ble/session.d.ts +129 -0
- package/types/ble/session.d.ts.map +1 -0
- package/types/ble/transport.d.ts +67 -0
- package/types/ble/transport.d.ts.map +1 -0
- package/types/cli/access.d.ts +6 -0
- package/types/cli/access.d.ts.map +1 -0
- package/types/cli/company.d.ts +6 -0
- package/types/cli/company.d.ts.map +1 -0
- package/types/cli/iot.d.ts +6 -0
- package/types/cli/iot.d.ts.map +1 -0
- package/types/cli/org.d.ts +6 -0
- package/types/cli/org.d.ts.map +1 -0
- package/types/cli/presetir.d.ts +6 -0
- package/types/cli/presetir.d.ts.map +1 -0
- package/types/cli/schedule.d.ts +6 -0
- package/types/cli/schedule.d.ts.map +1 -0
- package/types/cli/serve.d.ts +2 -0
- package/types/cli/serve.d.ts.map +1 -0
- package/types/cli.d.ts +2 -0
- package/types/cli.d.ts.map +1 -0
- package/types/client.d.ts +463 -0
- package/types/client.d.ts.map +1 -0
- package/types/company.d.ts +94 -0
- package/types/company.d.ts.map +1 -0
- package/types/config.d.ts +111 -0
- package/types/config.d.ts.map +1 -0
- package/types/crypto.d.ts +61 -0
- package/types/crypto.d.ts.map +1 -0
- package/types/devices.d.ts +116 -0
- package/types/devices.d.ts.map +1 -0
- package/types/index.d.ts +23 -0
- package/types/index.d.ts.map +1 -0
- package/types/iot.d.ts +312 -0
- package/types/iot.d.ts.map +1 -0
- package/types/ir.d.ts +147 -0
- package/types/ir.d.ts.map +1 -0
- package/types/itemcodes.d.ts +21 -0
- package/types/itemcodes.d.ts.map +1 -0
- package/types/lock.d.ts +89 -0
- package/types/lock.d.ts.map +1 -0
- package/types/org.d.ts +468 -0
- package/types/org.d.ts.map +1 -0
- package/types/paths.d.ts +10 -0
- package/types/paths.d.ts.map +1 -0
- package/types/presetir.d.ts +286 -0
- package/types/presetir.d.ts.map +1 -0
- package/types/prompts.d.ts +39 -0
- package/types/prompts.d.ts.map +1 -0
- package/types/schedule.d.ts +71 -0
- package/types/schedule.d.ts.map +1 -0
- package/types/serve/daemon.d.ts +133 -0
- package/types/serve/daemon.d.ts.map +1 -0
- package/types/serve/framing/grpc.d.ts +14 -0
- package/types/serve/framing/grpc.d.ts.map +1 -0
- package/types/serve/framing/http.d.ts +14 -0
- package/types/serve/framing/http.d.ts.map +1 -0
- package/types/serve/framing/ndjson.d.ts +19 -0
- package/types/serve/framing/ndjson.d.ts.map +1 -0
- package/types/serve/framing/socket.d.ts +14 -0
- package/types/serve/framing/socket.d.ts.map +1 -0
- package/types/serve/framing/stdio.d.ts +11 -0
- package/types/serve/framing/stdio.d.ts.map +1 -0
- package/types/serve/framing/token.d.ts +11 -0
- package/types/serve/framing/token.d.ts.map +1 -0
- package/types/serve/framing/ws.d.ts +13 -0
- package/types/serve/framing/ws.d.ts.map +1 -0
- package/types/serve/jsonrpc.d.ts +118 -0
- package/types/serve/jsonrpc.d.ts.map +1 -0
- package/types/serve/registry.d.ts +41 -0
- package/types/serve/registry.d.ts.map +1 -0
- package/types/session-ui.d.ts +36 -0
- package/types/session-ui.d.ts.map +1 -0
- package/types/sharekey.d.ts +35 -0
- package/types/sharekey.d.ts.map +1 -0
- package/types/tokens.d.ts +20 -0
- package/types/tokens.d.ts.map +1 -0
- package/types/transport.d.ts +138 -0
- package/types/transport.d.ts.map +1 -0
- package/types/util.d.ts +20 -0
- package/types/util.d.ts.map +1 -0
- package/vendor/biz3/README.md +37 -0
- package/vendor/biz3/constants/cmdCode.d.ts +48 -0
- package/vendor/biz3/constants/cmdCode.d.ts.map +1 -0
- package/vendor/biz3/constants/cmdCode.js +92 -0
- package/vendor/biz3/constants/messageConstants.d.ts +28 -0
- package/vendor/biz3/constants/messageConstants.d.ts.map +1 -0
- package/vendor/biz3/constants/messageConstants.js +30 -0
- package/vendor/biz3/constants/sesameDeviceModel.d.ts +75 -0
- package/vendor/biz3/constants/sesameDeviceModel.d.ts.map +1 -0
- package/vendor/biz3/constants/sesameDeviceModel.js +77 -0
- package/vendor/biz3/package.json +5 -0
package/src/crypto.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// SESAME デバイス制御で使う暗号 / バイナリ helpers。
|
|
2
|
+
//
|
|
3
|
+
// Ported from biz3 (CANDY-HOUSE/biz3, MIT):
|
|
4
|
+
// - vendor reference: references_web/src/utils/Cmac.js (CMAC-AES-128)
|
|
5
|
+
// - vendor reference: references_web/src/utils/biz3utils.js (uuidBuffer 等)
|
|
6
|
+
// - vendor reference: references_web/src/constants/cmdCode.js (item code)
|
|
7
|
+
// - vendor reference: references_web/src/constants/sesameDeviceModel.js (productType)
|
|
8
|
+
//
|
|
9
|
+
// biz3 Web は Web Crypto API + 自前 CMAC 実装、Node では node-aes-cmac (RFC 4493) を使用。
|
|
10
|
+
// 公式 BLE 実装と同じ AES-CMAC で、用途のみ異なる (biz3 は時刻署名 / BLE は session key 派生)。
|
|
11
|
+
|
|
12
|
+
import { aesCmac } from "node-aes-cmac";
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
// 公式 biz3 の純定数を直接 import (手書き複製を排除 = 推測ズレ原理的になし)。
|
|
15
|
+
// vendor/biz3/constants/ は biz3 原文のコピー (vendor/biz3/README.md 参照)。
|
|
16
|
+
import { modelNameByProductType } from "../vendor/biz3/constants/sesameDeviceModel.js";
|
|
17
|
+
|
|
18
|
+
// ---------- UUID ----------
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* v4 UUID を生成。biz3 biz3utils.generateUUID:269-280 と一致させる。
|
|
22
|
+
* 学習リモコンのキーは **クライアントが keyUUID を発番**してサーバに渡す
|
|
23
|
+
* (learn/index.js:222)。サーバ発番ではない。
|
|
24
|
+
*
|
|
25
|
+
* ★重要: biz3 は `randomUUID().toUpperCase()` で **大文字** UUID を返す。
|
|
26
|
+
* Node の randomUUID は既定で小文字なので toUpperCase() で揃える。
|
|
27
|
+
* (biz3 アプリと同一アカウント併用時に keyUUID 形式を一致させるため)
|
|
28
|
+
*/
|
|
29
|
+
export function generateUUID() {
|
|
30
|
+
return randomUUID().toUpperCase();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ---------- AES-CMAC ----------
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 時刻ベースの CMAC 署名。
|
|
37
|
+
* biz3 Cmac.cmacTime() と同じ:
|
|
38
|
+
* 1. UNIX 秒を 4B LE にパック
|
|
39
|
+
* 2. 上位 3B (index 1-3) だけを取る → 256 秒粒度の時刻
|
|
40
|
+
* 3. AES-CMAC(secretKey, message) → 16B MAC
|
|
41
|
+
* 4. hex 化して先頭 8 文字 (= 4B) を返す
|
|
42
|
+
*
|
|
43
|
+
* `node-aes-cmac` は RFC 4493 標準実装。RFC 4493 §4 の Test Vector 2
|
|
44
|
+
* (key=2b7e1516..., msg=6bc1bee2..., expected=070a16b4...) で動作検証済み
|
|
45
|
+
* (リポルートで `node _crypto_test.mjs` 実行時 PASS。biz3 Cmac.js も同じ
|
|
46
|
+
* RFC 4493 標準を Web Crypto 上で自前実装しているため出力は一致する)。
|
|
47
|
+
*
|
|
48
|
+
* @param {string} hexKey 16B (32hex) の secretKey
|
|
49
|
+
* @returns {string} 4B hex (8 文字)
|
|
50
|
+
*/
|
|
51
|
+
export function cmacTime(hexKey) {
|
|
52
|
+
if (typeof hexKey !== "string") {
|
|
53
|
+
throw new Error(`secretKey must be a 32-char hex string (got ${typeof hexKey})`);
|
|
54
|
+
}
|
|
55
|
+
if (hexKey.length !== 32) {
|
|
56
|
+
throw new Error(`secretKey must be a 32-char hex string (got length ${hexKey.length})`);
|
|
57
|
+
}
|
|
58
|
+
if (!/^[0-9a-fA-F]{32}$/.test(hexKey)) {
|
|
59
|
+
throw new Error("secretKey must be a 32-char hex string (non-hex characters found)");
|
|
60
|
+
}
|
|
61
|
+
const key = Buffer.from(hexKey, "hex");
|
|
62
|
+
const ts = Math.floor(Date.now() / 1000);
|
|
63
|
+
const buf = Buffer.alloc(4);
|
|
64
|
+
buf.writeUInt32LE(ts, 0);
|
|
65
|
+
const msg = buf.subarray(1, 4); // 上位 3B
|
|
66
|
+
const mac = aesCmac(key, msg); // node-aes-cmac は Buffer を返す
|
|
67
|
+
const macBuf = Buffer.isBuffer(mac) ? mac : Buffer.from(mac, "hex");
|
|
68
|
+
return macBuf.toString("hex").slice(0, 8);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------- binary helpers ----------
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* UUID (32hex with hyphens) → 18B base64 (prefix '000c' 付き)。
|
|
75
|
+
* biz3 utils.uuidBuffer() と同じ。`biz3TriggerLocker` の `history` フィールドに乗せる。
|
|
76
|
+
*
|
|
77
|
+
* @param {string} uuid 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' or 32hex
|
|
78
|
+
* @param {string} prefix デフォルト '000c'
|
|
79
|
+
* @returns {string} base64 (24 文字)
|
|
80
|
+
*/
|
|
81
|
+
export function uuidToHistoryBase64(uuid, prefix = "000c") {
|
|
82
|
+
if (typeof uuid !== "string") throw new Error("uuid required (string)");
|
|
83
|
+
const cleanHex = uuid.replace(/-/g, "");
|
|
84
|
+
if (cleanHex.length !== 32) {
|
|
85
|
+
throw new Error(`uuid must be 32 hex chars (got len=${cleanHex.length})`);
|
|
86
|
+
}
|
|
87
|
+
return Buffer.from(prefix + cleanHex, "hex").toString("base64");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ---------- cmd codes ----------
|
|
91
|
+
// クラウドと BLE は同一の SesameItemCode を送る (梱包だけが違う)。コード表は src/itemcodes.js に一本化し、
|
|
92
|
+
// クラウド側ではそれを CMD という別名で参照する (歴史的な名前)。biz3 web が施錠/解錠 UI で送るのは
|
|
93
|
+
// TOGGLE=88 / CLICK(=BOT_CLICK)=89 (useIotCtrl.js:37, VIotSwitch.js:35)。LOCK=82/UNLOCK=83 も
|
|
94
|
+
// サーバ API が解釈する正当値。
|
|
95
|
+
export { ITEM_CODES as CMD } from "./itemcodes.js";
|
|
96
|
+
|
|
97
|
+
// ---------- IR type (リモコンの wire 値: remote.type / sendIR の irType) ----------
|
|
98
|
+
//
|
|
99
|
+
// これらは「実デバイス (remote.type) に乗る wire 値」。biz3 一次資料で確認:
|
|
100
|
+
//
|
|
101
|
+
// プリセットリモコン (operation: "remoteEmit"):
|
|
102
|
+
// ac=0xc000 / tv=0x2000 / light=0xe000 / fan=0x8000
|
|
103
|
+
// vendor: ir-type-list/index.js — 種別を選ぶとその値がそのまま remote.type になり
|
|
104
|
+
// sendIR(..., remote.type) に乗る (remote-list/index.js:322, remote-air/index.js:370)。
|
|
105
|
+
//
|
|
106
|
+
// 自己学習リモコン (operation: "learnEmit", カテゴリ情報なし):
|
|
107
|
+
// learn = 0xFE00 (65024)
|
|
108
|
+
// vendor: learn/index.js:142 — 学習で作るリモコンは {model:'Learn', type:0xfe00}。
|
|
109
|
+
// useRemoteCtrl.js:228 も `remoteDevice.type === 0xfe00` を「自己学習」と判定。
|
|
110
|
+
// ※ ir-type-list の learn メニューは 0xFEFF だが、これは「UI の種別選択メニュー識別子」
|
|
111
|
+
// であって実 remote.type ではない (選ぶと学習画面へ遷移するだけ)。
|
|
112
|
+
// プリセットは「メニュー値=実type」だが学習だけ非対称。旧実装の実機実測 65024(0xFE00)
|
|
113
|
+
// が正しく、UI 値 0xFEFF を実 type と取り違えてはいけない。
|
|
114
|
+
//
|
|
115
|
+
// 通常 sesame は device の stateInfo.remoteList から irType を自動取得するので、
|
|
116
|
+
// これらの定数はフォールバックと `ir search`/`remote-list` の引数用。
|
|
117
|
+
|
|
118
|
+
export const IR_TYPE = Object.freeze({
|
|
119
|
+
ac: 0xc000, // 49152 エアコン (プリセット)
|
|
120
|
+
tv: 0x2000, // 8192 テレビ (プリセット)
|
|
121
|
+
light: 0xe000, // 57344 照明 (プリセット)
|
|
122
|
+
fan: 0x8000, // 32768 扇風機 (プリセット)
|
|
123
|
+
learn: 0xfe00, // 65024 自己学習リモコンの実 type (learn/index.js:142 で確証)
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* irType が不明な場合の保険値。
|
|
128
|
+
* このツールは自己学習リモコン (learnEmit) を主対象とするため learn (0xFE00) を既定とする。
|
|
129
|
+
* (フォールバックが実際に使われるのは server が type を報告しない異常時のみ)
|
|
130
|
+
*/
|
|
131
|
+
export const DEFAULT_IR_TYPE = IR_TYPE.learn; // 0xFE00 (65024)
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* irType を文字列エイリアス (ac/tv/...) または数値文字列から数値に解決する。
|
|
135
|
+
* @param {string|number} v "ac" | "49152" | 0xc000 等
|
|
136
|
+
* @returns {number}
|
|
137
|
+
*/
|
|
138
|
+
export function parseIrType(v) {
|
|
139
|
+
if (typeof v === "number") return v;
|
|
140
|
+
if (typeof v !== "string") throw new Error(`irType must be a string or number (got ${typeof v})`);
|
|
141
|
+
const key = v.trim().toLowerCase();
|
|
142
|
+
if (key in IR_TYPE) return IR_TYPE[key];
|
|
143
|
+
const n = Number(key);
|
|
144
|
+
if (Number.isFinite(n)) return n;
|
|
145
|
+
const aliases = Object.keys(IR_TYPE).join(", ");
|
|
146
|
+
throw new Error(`Unknown irType "${v}". 数値 (例 49152) かエイリアス (${aliases}) を指定してください。`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ---------- productType (model name → byte value) ----------
|
|
150
|
+
// 手書きせず、biz3 の sesameDeviceModel.js を直接逆引きして生成する。
|
|
151
|
+
// biz3 は modelNameByProductType = { <productType>: "<model名>" }。これを反転して
|
|
152
|
+
// PRODUCT_TYPE = { "<model名>": <productType> } を作る。欠番 (12,34) も自動で反映され、
|
|
153
|
+
// biz3 が機種を追加/変更しても vendor を更新すればそのまま追従する。
|
|
154
|
+
export const PRODUCT_TYPE = Object.freeze(
|
|
155
|
+
Object.fromEntries(
|
|
156
|
+
Object.entries(modelNameByProductType).map(([pt, model]) => [model, Number(pt)]),
|
|
157
|
+
),
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
export function productTypeFromModelName(modelName) {
|
|
161
|
+
return PRODUCT_TYPE[modelName];
|
|
162
|
+
}
|
package/src/devices.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// SESAME デバイス管理 (history / battery / status / firmware / webapi proxy)。
|
|
2
|
+
//
|
|
3
|
+
// Ported from biz3 (CANDY-HOUSE/biz3, MIT):
|
|
4
|
+
// - vendor reference: references_web/src/api/useManageDevice.js
|
|
5
|
+
// - vendor reference: references_web/src/api/useManageGroup.js (getHistory)
|
|
6
|
+
// - vendor reference: references_web/src/api/useDeveloper.js (firmware, invokeAPI)
|
|
7
|
+
// - vendor reference: references_web/src/components/MobileBatteryChart.js (battery)
|
|
8
|
+
//
|
|
9
|
+
// 既存 client.js の listDevices() (getCompanyDevice) はそのまま残し、
|
|
10
|
+
// 個人ユーザ向けの getUserDevice、CRUD、履歴系をここに集める。
|
|
11
|
+
|
|
12
|
+
import { ACTION_TYPES } from "../vendor/biz3/constants/messageConstants.js";
|
|
13
|
+
import { assertSuccess } from "./util.js";
|
|
14
|
+
|
|
15
|
+
// action 文字列は vendor (biz3 messageConstants) から引く (手書きしない)。
|
|
16
|
+
const ACT_MANAGE = ACTION_TYPES.BIZ3_MANAGE_DEVICE; // "biz3ManageDevice"
|
|
17
|
+
const ACT_HISTORY = ACTION_TYPES.BIZ3_GET_DEVICEHISTORY; // "biz3GetDeviceHistory"
|
|
18
|
+
const ACT_BATTERY = ACTION_TYPES.BIZ3_GET_BATTERY_RECORD; // "biz3GetDeviceBatteryRecord"
|
|
19
|
+
const ACT_FIRMWARE = ACTION_TYPES.BIZ3_LIST_FIRMWARE; // "biz3ListFirmware"
|
|
20
|
+
const ACT_WEBAPI = ACTION_TYPES.BIZ3_INVOKE_WEBAPI; // "biz3InvokeWebAPIs"
|
|
21
|
+
const ACT_TRIGGER = ACTION_TYPES.BIZ3_TRIGGER_LOCKER; // "biz3TriggerLocker" (state push)
|
|
22
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
23
|
+
|
|
24
|
+
// ---------- device CRUD (biz3ManageDevice) ----------
|
|
25
|
+
|
|
26
|
+
/** 個人ユーザのデバイス一覧。companyID 不要。 */
|
|
27
|
+
export async function getUserDevices(client, { timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
|
|
28
|
+
// 応答は PubedUserDevice 系で来る可能性 (catalog より)。pending 単純解決を試み、
|
|
29
|
+
// 失敗時は listener fallback を用意する。
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
let done = false;
|
|
32
|
+
const to = setTimeout(() => {
|
|
33
|
+
if (done) return;
|
|
34
|
+
done = true;
|
|
35
|
+
unsub();
|
|
36
|
+
reject(new Error("getUserDevice timeout"));
|
|
37
|
+
}, timeoutMs);
|
|
38
|
+
const unsub = client.subscribe(`${ACT_MANAGE}:PubedUserDevice`, (msg) => {
|
|
39
|
+
if (done) return;
|
|
40
|
+
done = true;
|
|
41
|
+
clearTimeout(to);
|
|
42
|
+
unsub();
|
|
43
|
+
resolve(msg?.data?.data?.list || msg?.data?.list || msg?.data || []);
|
|
44
|
+
});
|
|
45
|
+
client.send({ action: ACT_MANAGE, op: "getUserDevice" });
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 単機の現在状態 (ロック開閉、電池等)。biz3 では isFromApp=true 限定だが CLI でも投げてみる価値あり。 */
|
|
50
|
+
export async function getDeviceStatus(client, { deviceUUID }) {
|
|
51
|
+
const resp = await client.request(
|
|
52
|
+
{ action: ACT_MANAGE, op: "getDeviceStatus", deviceUUID },
|
|
53
|
+
DEFAULT_TIMEOUT_MS,
|
|
54
|
+
);
|
|
55
|
+
assertSuccess(resp, "getDeviceStatus", { strict: true });
|
|
56
|
+
return resp.data;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** デバイス名変更。subUUID は呼び出し側 (client.js) が持つ。 */
|
|
60
|
+
export async function updateDeviceName(client, { subUUID, deviceUUID, deviceName }) {
|
|
61
|
+
const resp = await client.request(
|
|
62
|
+
{
|
|
63
|
+
action: ACT_MANAGE,
|
|
64
|
+
op: "updateName",
|
|
65
|
+
obj: { subUUID, deviceUUID, deviceName },
|
|
66
|
+
},
|
|
67
|
+
DEFAULT_TIMEOUT_MS,
|
|
68
|
+
);
|
|
69
|
+
assertSuccess(resp, "updateDeviceName", { strict: true });
|
|
70
|
+
return resp;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** デバイスを company から削除。items=[{deviceUUID,...}] */
|
|
74
|
+
export async function deleteDevices(client, { companyID, items }) {
|
|
75
|
+
const resp = await client.request(
|
|
76
|
+
{ action: ACT_MANAGE, op: "del", companyID, items },
|
|
77
|
+
DEFAULT_TIMEOUT_MS,
|
|
78
|
+
);
|
|
79
|
+
assertSuccess(resp, "deleteDevices", { strict: true });
|
|
80
|
+
return resp;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* デバイス state push を購読。subscribeDevicesUpdate (biz3ManageDevice) を投げて購読要求し、
|
|
85
|
+
* 実際の state push は **`biz3TriggerLocker:pubDeviceStateChange`** で届く。
|
|
86
|
+
*
|
|
87
|
+
* 注 (監査で修正): 購読要求の op は biz3ManageDevice/subscribeDevicesUpdate
|
|
88
|
+
* (useManageDevice.js:325) だが、**応答の push は別 action/op** で来る:
|
|
89
|
+
* biz3 は `biz3TriggerLocker` action の `pubDeviceStateChange` (小文字, useIotCtrl.js:11,21)
|
|
90
|
+
* として state 変化を流す。push 本体は `data = {deviceUUID, stateInfo}`。
|
|
91
|
+
* 旧実装は `biz3ManageDevice:PubedDeviceStateChange` (大文字 P・別 action) を購読しており
|
|
92
|
+
* push を1件も受信できなかった。
|
|
93
|
+
*
|
|
94
|
+
* **既知の制限**: biz3 プロトコルに `unsubscribeDevicesUpdate` op は無いため、
|
|
95
|
+
* unsubscribe()/close() 後もサーバ側 push は止まらない (ローカルで無視するだけ)。
|
|
96
|
+
*/
|
|
97
|
+
export function subscribeDevicesUpdate(client, { companyID, items, onUpdate }) {
|
|
98
|
+
client.send({ action: ACT_MANAGE, op: "subscribeDevicesUpdate", items, companyID });
|
|
99
|
+
return client.subscribe(`biz3TriggerLocker:pubDeviceStateChange`, (msg) => {
|
|
100
|
+
try { onUpdate(msg); } catch { /* ignore */ }
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---------- history ----------
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* ロックの開閉履歴を取得。`list` はデバイス指定の配列。
|
|
108
|
+
* @param {{companyID:string, list:any[], pageSize?:number}} p
|
|
109
|
+
*/
|
|
110
|
+
export async function getDeviceHistory(client, { companyID, list, pageSize = null }) {
|
|
111
|
+
const resp = await client.request(
|
|
112
|
+
{ action: ACT_HISTORY, op: "getHistory", companyID, list, pageSize },
|
|
113
|
+
DEFAULT_TIMEOUT_MS,
|
|
114
|
+
);
|
|
115
|
+
assertSuccess(resp, "getDeviceHistory", { strict: true });
|
|
116
|
+
return resp.data;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 開閉履歴の1エントリを非表示化 (論理削除)。
|
|
121
|
+
* biz3 useManageGroup.js makeInvisibleHistory: フラット {action, deviceUUID, timestamp, op}。
|
|
122
|
+
* @param {{deviceUUID:string, timestamp:number}} p
|
|
123
|
+
*/
|
|
124
|
+
export async function makeHistoryInvisible(client, { deviceUUID, timestamp }) {
|
|
125
|
+
const resp = await client.request(
|
|
126
|
+
{ action: ACT_HISTORY, op: "makeInvisible", deviceUUID, timestamp },
|
|
127
|
+
DEFAULT_TIMEOUT_MS,
|
|
128
|
+
);
|
|
129
|
+
assertSuccess(resp, "makeHistoryInvisible");
|
|
130
|
+
return resp;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ---------- battery ----------
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* 電池履歴を取得。DynamoDB の lastEvaluatedKey でページング。
|
|
137
|
+
* 1 回呼ぶごとに 1 ページ分。null → 最新ページ。
|
|
138
|
+
* 戻り値: { records: [{ts, light, heavy, lightPercentage, heavyPercentage}], lastEvaluatedKey }
|
|
139
|
+
*/
|
|
140
|
+
export async function getBatteryRecord(client, { deviceUUID, lastEvaluatedKey = null, pageSize = 100 }) {
|
|
141
|
+
const resp = await client.request(
|
|
142
|
+
{ action: ACT_BATTERY, op: "batch-get", deviceUUID, lastEvaluatedKey, pageSize },
|
|
143
|
+
DEFAULT_TIMEOUT_MS,
|
|
144
|
+
);
|
|
145
|
+
assertSuccess(resp, "getBatteryRecord", { strict: true });
|
|
146
|
+
return resp.data || { records: [], lastEvaluatedKey: null };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 電池履歴の1エントリを非表示化 (論理削除)。
|
|
151
|
+
* biz3 MobileBatteryChart.js makeInvisibleRecord: フラット {action, deviceUUID, timestamp_second, op}。
|
|
152
|
+
* @param {{deviceUUID:string, timestampSecond:number}} p
|
|
153
|
+
*/
|
|
154
|
+
export async function makeBatteryRecordInvisible(client, { deviceUUID, timestampSecond }) {
|
|
155
|
+
const resp = await client.request(
|
|
156
|
+
{ action: ACT_BATTERY, op: "makeInvisible", deviceUUID, timestamp_second: timestampSecond },
|
|
157
|
+
DEFAULT_TIMEOUT_MS,
|
|
158
|
+
);
|
|
159
|
+
assertSuccess(resp, "makeBatteryRecordInvisible");
|
|
160
|
+
return resp;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ---------- firmware ----------
|
|
164
|
+
|
|
165
|
+
/** 配信中ファームウェア一覧。 */
|
|
166
|
+
export async function listFirmware(client) {
|
|
167
|
+
// この op は op フィールド無し (action のみ)
|
|
168
|
+
return new Promise((resolve, reject) => {
|
|
169
|
+
const to = setTimeout(() => { unsub(); reject(new Error("listFirmware timeout")); }, DEFAULT_TIMEOUT_MS);
|
|
170
|
+
const unsub = client.subscribe(`${ACT_FIRMWARE}:`, (msg) => {
|
|
171
|
+
clearTimeout(to);
|
|
172
|
+
unsub();
|
|
173
|
+
resolve(msg?.data || []);
|
|
174
|
+
});
|
|
175
|
+
client.send({ action: ACT_FIRMWARE });
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ---------- webapi proxy ----------
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* biz3InvokeWebAPIs 経由で REST WebAPI を呼ぶ。
|
|
183
|
+
* func 例: 'webapi_ssm_shadow_get', 'webapi_history_get', 'webapi_cmd_send'。
|
|
184
|
+
* apiKeyId は別途 biz3 の dev console で発行されたもの。
|
|
185
|
+
*
|
|
186
|
+
* @param {{func:string, apiKeyId:string, query?:object, body?:object}} p
|
|
187
|
+
*/
|
|
188
|
+
export async function invokeWebAPI(client, { func, apiKeyId, query = {}, body = {} }) {
|
|
189
|
+
const resp = await client.request(
|
|
190
|
+
{ action: ACT_WEBAPI, op: func, apiKeyId, query, body },
|
|
191
|
+
DEFAULT_TIMEOUT_MS,
|
|
192
|
+
);
|
|
193
|
+
assertSuccess(resp, `invokeWebAPI(${func})`, { strict: true });
|
|
194
|
+
return resp.data;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// ---------- 便利ラッパ (WebAPI 経由の高頻度ユースケース) ----------
|
|
198
|
+
|
|
199
|
+
/** WebAPI 経由で 単機の shadow state を取得。 */
|
|
200
|
+
export function webapiDeviceState(client, { apiKeyId, deviceId }) {
|
|
201
|
+
return invokeWebAPI(client, {
|
|
202
|
+
func: "webapi_ssm_shadow_get",
|
|
203
|
+
apiKeyId,
|
|
204
|
+
query: { device_id: deviceId },
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* WebAPI 経由で履歴を取得。
|
|
210
|
+
* biz3 useDeveloper.js:67-80: query = {device_id, page:0, lg:5, isBiz:true}。
|
|
211
|
+
* lg は言語コードの**数値 ID** (biz3 は 5 を渡す)。旧実装は "ja" (文字列) で誤り。
|
|
212
|
+
*/
|
|
213
|
+
export function webapiDeviceHistory(client, { apiKeyId, deviceId, page = 0, lg = 5, isBiz = true }) {
|
|
214
|
+
return invokeWebAPI(client, {
|
|
215
|
+
func: "webapi_history_get",
|
|
216
|
+
apiKeyId,
|
|
217
|
+
query: { device_id: deviceId, page, lg, isBiz },
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** WebAPI 経由でロック cmd 送信 (sign/history は呼び出し側で組み立て)。 */
|
|
222
|
+
export function webapiSendCmd(client, { apiKeyId, deviceId, cmd, sign, history }) {
|
|
223
|
+
return invokeWebAPI(client, {
|
|
224
|
+
func: "webapi_cmd_send",
|
|
225
|
+
apiKeyId,
|
|
226
|
+
body: { device_id: deviceId, cmd, sign, history },
|
|
227
|
+
});
|
|
228
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// 公開ライブラリエントリ。
|
|
2
|
+
//
|
|
3
|
+
// パッケージ名は "sesame-kit" (package.json の "name")。
|
|
4
|
+
// 注: このパッケージは `"private": true` のため npm publish されていません。
|
|
5
|
+
// 他プロジェクトから使うには `npm link sesame-kit` か
|
|
6
|
+
// `npm install /path/to/sesame-kit` で取り込んでください。
|
|
7
|
+
//
|
|
8
|
+
// 高レベル:
|
|
9
|
+
// import { SesameHub3 } from "sesame-kit";
|
|
10
|
+
// await SesameHub3.use(async (hub) => {
|
|
11
|
+
// await hub.send("ac", "停止");
|
|
12
|
+
// });
|
|
13
|
+
// // または手動で connect/close:
|
|
14
|
+
// const hub = await SesameHub3.fromConfig();
|
|
15
|
+
// await hub.connect();
|
|
16
|
+
// try { await hub.send("ac", "停止"); } finally { await hub.close(); }
|
|
17
|
+
//
|
|
18
|
+
// 低レベル (自前で WS / トークン管理する場合):
|
|
19
|
+
// import { Hub3WsClient, sendIR, getIRCodes, FileTokenStore } from "sesame-kit";
|
|
20
|
+
// import { lock } from "sesame-kit"; // lock.* namespace も利用可
|
|
21
|
+
|
|
22
|
+
export { SesameHub3 } from "./client.js";
|
|
23
|
+
export { Hub3WsClient, sendIR, getIRCodes } from "./transport.js";
|
|
24
|
+
export { FileTokenStore } from "./tokens.js";
|
|
25
|
+
export { ConfigStore } from "./config.js";
|
|
26
|
+
export { configPaths, resolveConfigDir } from "./paths.js";
|
|
27
|
+
export * as auth from "./auth.js";
|
|
28
|
+
export * as crypto from "./crypto.js";
|
|
29
|
+
export * as ir from "./ir.js";
|
|
30
|
+
export * as devices from "./devices.js";
|
|
31
|
+
export * as account from "./account.js";
|
|
32
|
+
export * as schedule from "./schedule.js";
|
|
33
|
+
export * as org from "./org.js";
|
|
34
|
+
export * as company from "./company.js";
|
|
35
|
+
export * as access from "./access.js";
|
|
36
|
+
export * as iot from "./iot.js";
|
|
37
|
+
export * as presetir from "./presetir.js";
|
|
38
|
+
export * as sharekey from "./sharekey.js";
|
|
39
|
+
export * as lock from "./lock.js";
|
|
40
|
+
// BLE 直接制御 (クラウド非経由)。SesameBle.use({secretKey, deviceUUID}, fn) で利用。
|
|
41
|
+
export * as ble from "./ble/index.js";
|
|
42
|
+
export { SesameBle } from "./ble/index.js";
|
|
43
|
+
// WS 応答 success 判定の共通 helper (低レベル import で op を直叩きする消費者向け)。
|
|
44
|
+
export { assertSuccess } from "./util.js";
|
|
45
|
+
// lock.* の主要関数は個別 named export でも提供 (後方互換 + 利便性)。
|
|
46
|
+
// 注: `botClick` は低レベル関数 (client, params) → SesameHub3#botClick(name) とは別物。
|
|
47
|
+
export {
|
|
48
|
+
triggerLock,
|
|
49
|
+
lockLock,
|
|
50
|
+
lockUnlock,
|
|
51
|
+
lockToggle,
|
|
52
|
+
botClick,
|
|
53
|
+
triggerItemCommand,
|
|
54
|
+
setAutolock,
|
|
55
|
+
} from "./lock.js";
|