aranea-sdk-cli 0.1.4 → 0.3.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/README.md +281 -13
- package/dist/commands/knowledge.d.ts +14 -0
- package/dist/commands/knowledge.js +374 -0
- package/dist/commands/metatron.d.ts +12 -0
- package/dist/commands/metatron.js +255 -0
- package/dist/commands/mqtt.d.ts +16 -0
- package/dist/commands/mqtt.js +436 -0
- package/dist/commands/schema.d.ts +4 -0
- package/dist/commands/schema.js +446 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -0
- package/dist/index.js +10 -1
- package/package.json +9 -1
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* mqtt コマンド - MQTT/Pub/Sub コマンド発行・モニタリング
|
|
4
|
+
*
|
|
5
|
+
* P0 機能 (v0.2.x):
|
|
6
|
+
* aranea-sdk mqtt send-command --lacis-id <id> --type relay --params '{"channel":1,"state":true}'
|
|
7
|
+
* aranea-sdk mqtt monitor --lacis-id <id> --timeout 30
|
|
8
|
+
* aranea-sdk mqtt periodic --lacis-id <id> --type ping --interval 5 --count 10
|
|
9
|
+
*
|
|
10
|
+
* Cloud Pub/Sub経由でaraneaDeviceCommandエンドポイントを呼び出す
|
|
11
|
+
*
|
|
12
|
+
* @see doc/APPS/araneaSDK/headDesign/20_ARANEA_METATRON_ARCHITECTURE.md Section 12
|
|
13
|
+
* @see functions/src/araneaDevice/araneaDeviceCommand.ts
|
|
14
|
+
*/
|
|
15
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
16
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
17
|
+
};
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.mqttCommand = void 0;
|
|
20
|
+
const commander_1 = require("commander");
|
|
21
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
22
|
+
const ora_1 = __importDefault(require("ora"));
|
|
23
|
+
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
24
|
+
const config_1 = require("../config");
|
|
25
|
+
// Firebase Admin SDK (optional, for Firestore monitoring)
|
|
26
|
+
let admin;
|
|
27
|
+
try {
|
|
28
|
+
admin = require('firebase-admin');
|
|
29
|
+
if (!admin.apps.length) {
|
|
30
|
+
admin.initializeApp({
|
|
31
|
+
projectId: 'mobesorder',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
// Firebase Admin not available
|
|
37
|
+
}
|
|
38
|
+
// ========== Helper Functions ==========
|
|
39
|
+
/**
|
|
40
|
+
* Firebase Auth トークンを取得(サービスアカウント経由)
|
|
41
|
+
*/
|
|
42
|
+
async function getAuthToken() {
|
|
43
|
+
// 環境変数からサービスアカウントが設定されている場合
|
|
44
|
+
if (process.env.GOOGLE_APPLICATION_CREDENTIALS && admin) {
|
|
45
|
+
try {
|
|
46
|
+
// カスタムトークンを生成してIDトークンに交換
|
|
47
|
+
// 注意: これは開発/テスト用途のみ
|
|
48
|
+
const customToken = await admin.auth().createCustomToken('cli-user', {
|
|
49
|
+
permission: 100, // System Authority
|
|
50
|
+
tid: config_1.TEST_TENANT.tid,
|
|
51
|
+
fid: [],
|
|
52
|
+
});
|
|
53
|
+
// カスタムトークンをIDトークンに交換(REST API経由)
|
|
54
|
+
const response = await (0, node_fetch_1.default)(`https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=${process.env.FIREBASE_API_KEY || 'AIzaSyDoL_mG-p-u4wUPfdLN5tL8x5nM8LYEHPM'}`, {
|
|
55
|
+
method: 'POST',
|
|
56
|
+
headers: { 'Content-Type': 'application/json' },
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
token: customToken,
|
|
59
|
+
returnSecureToken: true,
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
const data = (await response.json());
|
|
63
|
+
if (data.idToken) {
|
|
64
|
+
return data.idToken;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.warn(chalk_1.default.yellow(`⚠ 自動認証失敗: ${error.message}`));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* コマンド送信
|
|
75
|
+
*/
|
|
76
|
+
async function sendCommand(endpoint, lacisId, command, authToken) {
|
|
77
|
+
const url = `${endpoint}/${lacisId}`;
|
|
78
|
+
const response = await (0, node_fetch_1.default)(url, {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: {
|
|
81
|
+
'Content-Type': 'application/json',
|
|
82
|
+
Authorization: `Bearer ${authToken}`,
|
|
83
|
+
},
|
|
84
|
+
body: JSON.stringify(command),
|
|
85
|
+
});
|
|
86
|
+
return (await response.json());
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* コマンドステータス取得(Firestore経由)
|
|
90
|
+
*/
|
|
91
|
+
async function getCommandStatus(cmdId) {
|
|
92
|
+
if (!admin) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const db = admin.firestore();
|
|
97
|
+
const doc = await db.collection('araneaDeviceCommands').doc(cmdId).get();
|
|
98
|
+
if (!doc.exists) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const data = doc.data();
|
|
102
|
+
return {
|
|
103
|
+
cmdId: data.cmdId,
|
|
104
|
+
status: data.status,
|
|
105
|
+
ackAt: data.ackAt?.toDate?.()?.toISOString(),
|
|
106
|
+
ackResult: data.ackResult,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* コマンドステータス監視(ポーリング)
|
|
115
|
+
*/
|
|
116
|
+
async function monitorCommandStatus(cmdId, timeoutSec, onUpdate) {
|
|
117
|
+
const startTime = Date.now();
|
|
118
|
+
const pollInterval = 1000; // 1秒ごとにポーリング
|
|
119
|
+
while (Date.now() - startTime < timeoutSec * 1000) {
|
|
120
|
+
const status = await getCommandStatus(cmdId);
|
|
121
|
+
if (status) {
|
|
122
|
+
onUpdate(status);
|
|
123
|
+
if (status.status !== 'pending') {
|
|
124
|
+
return status;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
128
|
+
}
|
|
129
|
+
return null; // タイムアウト
|
|
130
|
+
}
|
|
131
|
+
// ========== Commands ==========
|
|
132
|
+
exports.mqttCommand = new commander_1.Command('mqtt').description('MQTT/Pub/Sub コマンド発行・モニタリング (P0)');
|
|
133
|
+
// mqtt send-command
|
|
134
|
+
exports.mqttCommand
|
|
135
|
+
.command('send-command')
|
|
136
|
+
.description('デバイスへコマンド送信')
|
|
137
|
+
.requiredOption('-l, --lacis-id <lacisId>', 'デバイスLacisID')
|
|
138
|
+
.requiredOption('-t, --type <type>', 'コマンドタイプ (relay, pwm, macro等)')
|
|
139
|
+
.option('-p, --params <json>', 'パラメータ (JSON文字列)', '{}')
|
|
140
|
+
.option('--ttl <seconds>', 'TTL秒数', '30')
|
|
141
|
+
.option('--group-id <groupId>', 'グループID')
|
|
142
|
+
.option('--token <token>', 'Firebase Auth IDトークン')
|
|
143
|
+
.option('-e, --endpoint <env>', '環境 (production/staging)', 'production')
|
|
144
|
+
.option('-w, --wait', 'ACK待機 (デフォルト: false)')
|
|
145
|
+
.option('--wait-timeout <seconds>', 'ACK待機タイムアウト', '30')
|
|
146
|
+
.option('-d, --dry-run', 'リクエスト内容を表示のみ')
|
|
147
|
+
.action(async (options) => {
|
|
148
|
+
try {
|
|
149
|
+
console.log(chalk_1.default.bold('\n=== MQTT Send Command ===\n'));
|
|
150
|
+
// パラメータ解析
|
|
151
|
+
let params;
|
|
152
|
+
try {
|
|
153
|
+
params = JSON.parse(options.params);
|
|
154
|
+
}
|
|
155
|
+
catch (e) {
|
|
156
|
+
console.error(chalk_1.default.red('❌ --params のJSON解析に失敗しました'));
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
const command = {
|
|
160
|
+
type: options.type,
|
|
161
|
+
parameters: params,
|
|
162
|
+
ttlSec: parseInt(options.ttl, 10),
|
|
163
|
+
groupId: options.groupId,
|
|
164
|
+
};
|
|
165
|
+
console.log(chalk_1.default.cyan('ターゲット:'));
|
|
166
|
+
console.log(` LacisID: ${options.lacisId}`);
|
|
167
|
+
console.log(` Type: ${command.type}`);
|
|
168
|
+
console.log(` Parameters: ${JSON.stringify(command.parameters)}`);
|
|
169
|
+
console.log(` TTL: ${command.ttlSec}秒`);
|
|
170
|
+
if (command.groupId) {
|
|
171
|
+
console.log(` GroupID: ${command.groupId}`);
|
|
172
|
+
}
|
|
173
|
+
console.log('');
|
|
174
|
+
if (options.dryRun) {
|
|
175
|
+
console.log(chalk_1.default.yellow('(dry-run モード: 実際には送信されません)'));
|
|
176
|
+
console.log(chalk_1.default.cyan('\nリクエストボディ:'));
|
|
177
|
+
console.log(JSON.stringify(command, null, 2));
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
// 認証トークン取得
|
|
181
|
+
let authToken = options.token;
|
|
182
|
+
if (!authToken) {
|
|
183
|
+
const spinner = (0, ora_1.default)('認証トークン取得中...').start();
|
|
184
|
+
authToken = await getAuthToken();
|
|
185
|
+
spinner.stop();
|
|
186
|
+
if (!authToken) {
|
|
187
|
+
console.error(chalk_1.default.red('❌ 認証トークンが必要です。--token オプションを指定してください'));
|
|
188
|
+
console.log(chalk_1.default.gray(' または GOOGLE_APPLICATION_CREDENTIALS 環境変数を設定'));
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// コマンド送信
|
|
193
|
+
const spinner = (0, ora_1.default)('コマンド送信中...').start();
|
|
194
|
+
const endpoint = (0, config_1.getEndpoint)(options.endpoint);
|
|
195
|
+
const result = await sendCommand(endpoint.command, options.lacisId, command, authToken);
|
|
196
|
+
spinner.stop();
|
|
197
|
+
console.log(chalk_1.default.cyan('レスポンス:'));
|
|
198
|
+
console.log(JSON.stringify(result, null, 2));
|
|
199
|
+
console.log('');
|
|
200
|
+
if (result.ok) {
|
|
201
|
+
console.log(chalk_1.default.green(`✓ コマンド送信成功: ${result.cmdId}`));
|
|
202
|
+
// ACK待機
|
|
203
|
+
if (options.wait && result.cmdId) {
|
|
204
|
+
console.log('');
|
|
205
|
+
const waitSpinner = (0, ora_1.default)('ACK待機中...').start();
|
|
206
|
+
const timeout = parseInt(options.waitTimeout, 10);
|
|
207
|
+
const finalStatus = await monitorCommandStatus(result.cmdId, timeout, (status) => {
|
|
208
|
+
waitSpinner.text = `ACK待機中... (status: ${status.status})`;
|
|
209
|
+
});
|
|
210
|
+
waitSpinner.stop();
|
|
211
|
+
if (finalStatus) {
|
|
212
|
+
if (finalStatus.status === 'acked') {
|
|
213
|
+
console.log(chalk_1.default.green(`✓ ACK受信: ${finalStatus.ackAt}`));
|
|
214
|
+
if (finalStatus.ackResult) {
|
|
215
|
+
console.log(chalk_1.default.cyan('ACK結果:'));
|
|
216
|
+
console.log(JSON.stringify(finalStatus.ackResult, null, 2));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
else if (finalStatus.status === 'expired') {
|
|
220
|
+
console.log(chalk_1.default.yellow('⚠ コマンドがTTL切れで期限切れになりました'));
|
|
221
|
+
}
|
|
222
|
+
else if (finalStatus.status === 'failed') {
|
|
223
|
+
console.log(chalk_1.default.red('✗ コマンド実行失敗'));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
console.log(chalk_1.default.yellow(`⚠ タイムアウト (${timeout}秒)`));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
console.log(chalk_1.default.red(`✗ コマンド送信失敗: ${result.error}`));
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
console.log('');
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
console.error(chalk_1.default.red(`エラー: ${error.message}`));
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
// mqtt monitor
|
|
243
|
+
exports.mqttCommand
|
|
244
|
+
.command('monitor')
|
|
245
|
+
.description('コマンドACKのリアルタイムモニタリング')
|
|
246
|
+
.option('-l, --lacis-id <lacisId>', 'フィルタ: デバイスLacisID')
|
|
247
|
+
.option('-c, --cmd-id <cmdId>', 'フィルタ: コマンドID')
|
|
248
|
+
.option('-t, --timeout <seconds>', 'タイムアウト秒数', '60')
|
|
249
|
+
.option('-e, --endpoint <env>', '環境 (production/staging)', 'production')
|
|
250
|
+
.action(async (options) => {
|
|
251
|
+
try {
|
|
252
|
+
console.log(chalk_1.default.bold('\n=== MQTT Monitor ===\n'));
|
|
253
|
+
if (!admin) {
|
|
254
|
+
console.error(chalk_1.default.red('❌ Firebase Admin SDK が必要です。GOOGLE_APPLICATION_CREDENTIALS を設定してください'));
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
const timeout = parseInt(options.timeout, 10);
|
|
258
|
+
console.log(chalk_1.default.cyan('監視設定:'));
|
|
259
|
+
if (options.lacisId) {
|
|
260
|
+
console.log(` LacisID: ${options.lacisId}`);
|
|
261
|
+
}
|
|
262
|
+
if (options.cmdId) {
|
|
263
|
+
console.log(` CmdID: ${options.cmdId}`);
|
|
264
|
+
}
|
|
265
|
+
console.log(` タイムアウト: ${timeout}秒`);
|
|
266
|
+
console.log('');
|
|
267
|
+
console.log(chalk_1.default.gray('Ctrl+C で終了'));
|
|
268
|
+
console.log('');
|
|
269
|
+
// 特定のコマンドIDを監視
|
|
270
|
+
if (options.cmdId) {
|
|
271
|
+
const spinner = (0, ora_1.default)('コマンドステータス監視中...').start();
|
|
272
|
+
const finalStatus = await monitorCommandStatus(options.cmdId, timeout, (status) => {
|
|
273
|
+
spinner.text = `監視中... (status: ${status.status})`;
|
|
274
|
+
});
|
|
275
|
+
spinner.stop();
|
|
276
|
+
if (finalStatus) {
|
|
277
|
+
console.log(chalk_1.default.cyan('最終ステータス:'));
|
|
278
|
+
console.log(JSON.stringify(finalStatus, null, 2));
|
|
279
|
+
if (finalStatus.status === 'acked') {
|
|
280
|
+
console.log(chalk_1.default.green('\n✓ ACK受信'));
|
|
281
|
+
}
|
|
282
|
+
else if (finalStatus.status === 'expired') {
|
|
283
|
+
console.log(chalk_1.default.yellow('\n⚠ 期限切れ'));
|
|
284
|
+
}
|
|
285
|
+
else if (finalStatus.status === 'failed') {
|
|
286
|
+
console.log(chalk_1.default.red('\n✗ 失敗'));
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
console.log(chalk_1.default.yellow(`\n⚠ タイムアウト (${timeout}秒)`));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
// リアルタイムリスナー(Firestoreの変更を監視)
|
|
295
|
+
const db = admin.firestore();
|
|
296
|
+
let query = db
|
|
297
|
+
.collection('araneaDeviceCommands')
|
|
298
|
+
.orderBy('issuedAt', 'desc')
|
|
299
|
+
.limit(20);
|
|
300
|
+
if (options.lacisId) {
|
|
301
|
+
query = db
|
|
302
|
+
.collection('araneaDeviceCommands')
|
|
303
|
+
.where('lacisId', '==', options.lacisId)
|
|
304
|
+
.orderBy('issuedAt', 'desc')
|
|
305
|
+
.limit(20);
|
|
306
|
+
}
|
|
307
|
+
console.log(chalk_1.default.cyan('最近のコマンド (リアルタイム更新):'));
|
|
308
|
+
console.log(chalk_1.default.gray('─'.repeat(80)));
|
|
309
|
+
const unsubscribe = query.onSnapshot((snapshot) => {
|
|
310
|
+
console.log(chalk_1.default.gray(`\n[${new Date().toISOString()}] スナップショット更新`));
|
|
311
|
+
snapshot.docChanges().forEach((change) => {
|
|
312
|
+
const data = change.doc.data();
|
|
313
|
+
const icon = data.status === 'acked'
|
|
314
|
+
? chalk_1.default.green('✓')
|
|
315
|
+
: data.status === 'pending'
|
|
316
|
+
? chalk_1.default.yellow('○')
|
|
317
|
+
: data.status === 'expired'
|
|
318
|
+
? chalk_1.default.gray('⏱')
|
|
319
|
+
: chalk_1.default.red('✗');
|
|
320
|
+
console.log(`${icon} ${data.cmdId?.substring(0, 20)}... | ${data.type} | ${data.status} | ${data.lacisId?.substring(0, 12)}...`);
|
|
321
|
+
});
|
|
322
|
+
}, (error) => {
|
|
323
|
+
console.error(chalk_1.default.red(`監視エラー: ${error.message}`));
|
|
324
|
+
});
|
|
325
|
+
// タイムアウト後に終了
|
|
326
|
+
await new Promise((resolve) => setTimeout(resolve, timeout * 1000));
|
|
327
|
+
unsubscribe();
|
|
328
|
+
console.log(chalk_1.default.gray('\n監視終了'));
|
|
329
|
+
}
|
|
330
|
+
console.log('');
|
|
331
|
+
}
|
|
332
|
+
catch (error) {
|
|
333
|
+
console.error(chalk_1.default.red(`エラー: ${error.message}`));
|
|
334
|
+
process.exit(1);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
// mqtt periodic
|
|
338
|
+
exports.mqttCommand
|
|
339
|
+
.command('periodic')
|
|
340
|
+
.description('定期的なコマンド送信(負荷テスト用)')
|
|
341
|
+
.requiredOption('-l, --lacis-id <lacisId>', 'デバイスLacisID')
|
|
342
|
+
.requiredOption('-t, --type <type>', 'コマンドタイプ')
|
|
343
|
+
.option('-p, --params <json>', 'パラメータ (JSON文字列)', '{}')
|
|
344
|
+
.option('-i, --interval <seconds>', '送信間隔秒数', '5')
|
|
345
|
+
.option('-n, --count <count>', '送信回数 (0=無限)', '10')
|
|
346
|
+
.option('--token <token>', 'Firebase Auth IDトークン')
|
|
347
|
+
.option('-e, --endpoint <env>', '環境 (production/staging)', 'production')
|
|
348
|
+
.option('-d, --dry-run', 'リクエスト内容を表示のみ')
|
|
349
|
+
.action(async (options) => {
|
|
350
|
+
try {
|
|
351
|
+
console.log(chalk_1.default.bold('\n=== MQTT Periodic Test ===\n'));
|
|
352
|
+
// パラメータ解析
|
|
353
|
+
let params;
|
|
354
|
+
try {
|
|
355
|
+
params = JSON.parse(options.params);
|
|
356
|
+
}
|
|
357
|
+
catch (e) {
|
|
358
|
+
console.error(chalk_1.default.red('❌ --params のJSON解析に失敗しました'));
|
|
359
|
+
process.exit(1);
|
|
360
|
+
}
|
|
361
|
+
const interval = parseInt(options.interval, 10);
|
|
362
|
+
const count = parseInt(options.count, 10);
|
|
363
|
+
console.log(chalk_1.default.cyan('定期送信設定:'));
|
|
364
|
+
console.log(` LacisID: ${options.lacisId}`);
|
|
365
|
+
console.log(` Type: ${options.type}`);
|
|
366
|
+
console.log(` Parameters: ${JSON.stringify(params)}`);
|
|
367
|
+
console.log(` 間隔: ${interval}秒`);
|
|
368
|
+
console.log(` 回数: ${count === 0 ? '無限' : count}`);
|
|
369
|
+
console.log('');
|
|
370
|
+
if (options.dryRun) {
|
|
371
|
+
console.log(chalk_1.default.yellow('(dry-run モード: 実際には送信されません)'));
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
// 認証トークン取得
|
|
375
|
+
let authToken = options.token;
|
|
376
|
+
if (!authToken) {
|
|
377
|
+
const spinner = (0, ora_1.default)('認証トークン取得中...').start();
|
|
378
|
+
authToken = await getAuthToken();
|
|
379
|
+
spinner.stop();
|
|
380
|
+
if (!authToken) {
|
|
381
|
+
console.error(chalk_1.default.red('❌ 認証トークンが必要です。--token オプションを指定してください'));
|
|
382
|
+
process.exit(1);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const endpoint = (0, config_1.getEndpoint)(options.endpoint);
|
|
386
|
+
let sent = 0;
|
|
387
|
+
let success = 0;
|
|
388
|
+
let failed = 0;
|
|
389
|
+
console.log(chalk_1.default.gray('Ctrl+C で中断'));
|
|
390
|
+
console.log('');
|
|
391
|
+
// Ctrl+C ハンドリング
|
|
392
|
+
let running = true;
|
|
393
|
+
process.on('SIGINT', () => {
|
|
394
|
+
running = false;
|
|
395
|
+
console.log(chalk_1.default.yellow('\n中断されました'));
|
|
396
|
+
});
|
|
397
|
+
while (running && (count === 0 || sent < count)) {
|
|
398
|
+
sent++;
|
|
399
|
+
const command = {
|
|
400
|
+
type: options.type,
|
|
401
|
+
parameters: { ...params, sequenceNumber: sent },
|
|
402
|
+
ttlSec: 30,
|
|
403
|
+
};
|
|
404
|
+
try {
|
|
405
|
+
const result = await sendCommand(endpoint.command, options.lacisId, command, authToken);
|
|
406
|
+
if (result.ok) {
|
|
407
|
+
success++;
|
|
408
|
+
console.log(chalk_1.default.green(`[${sent}/${count || '∞'}] ✓ ${result.cmdId?.substring(0, 24)}...`));
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
failed++;
|
|
412
|
+
console.log(chalk_1.default.red(`[${sent}/${count || '∞'}] ✗ ${result.error}`));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
failed++;
|
|
417
|
+
console.log(chalk_1.default.red(`[${sent}/${count || '∞'}] ✗ ${error.message}`));
|
|
418
|
+
}
|
|
419
|
+
if (running && (count === 0 || sent < count)) {
|
|
420
|
+
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
console.log('');
|
|
424
|
+
console.log(chalk_1.default.bold('=== 結果サマリー ==='));
|
|
425
|
+
console.log(` 送信: ${sent}`);
|
|
426
|
+
console.log(chalk_1.default.green(` 成功: ${success}`));
|
|
427
|
+
console.log(chalk_1.default.red(` 失敗: ${failed}`));
|
|
428
|
+
console.log(` 成功率: ${((success / sent) * 100).toFixed(1)}%`);
|
|
429
|
+
console.log('');
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
console.error(chalk_1.default.red(`エラー: ${error.message}`));
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
exports.default = exports.mqttCommand;
|
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* aranea-sdk schema get --type "aranea_ar-is04a"
|
|
6
6
|
* aranea-sdk schema list
|
|
7
7
|
* aranea-sdk schema validate --type "aranea_ar-is04a" --file state.json
|
|
8
|
+
* aranea-sdk schema validate-schema --file schema.json
|
|
9
|
+
* aranea-sdk schema push --file schema.json [--token TOKEN]
|
|
10
|
+
* aranea-sdk schema promote --type "aranea_ar-is04a" [--token TOKEN]
|
|
11
|
+
* aranea-sdk schema info --type "aranea_ar-is04a"
|
|
8
12
|
*/
|
|
9
13
|
import { Command } from 'commander';
|
|
10
14
|
export declare const schemaCommand: Command;
|