@blueyerobotics/blueye-ts 1.5.0 → 2.0.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 +12 -6
- package/dist/example.js +11 -6
- package/dist/src/client.d.ts +7 -8
- package/dist/src/client.js +51 -50
- package/dist/src/schema.d.ts +4 -7
- package/dist/src/schema.js +2 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -15,13 +15,19 @@ import { BlueyeClient } from "@blueyerobotics/blueye-ts";
|
|
|
15
15
|
|
|
16
16
|
const client = new BlueyeClient();
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
const
|
|
18
|
+
// request battery information
|
|
19
|
+
const batteryRep = await client.sendRequest("GetBatteryReq");
|
|
20
|
+
console.log("batteryRep:", batteryRep);
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
// get latest battery telemetry
|
|
23
|
+
const batteryTel = await client.getTelemetry("BatteryTel");
|
|
24
|
+
console.log("batteryTel:", batteryTel);
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
// send a control message to turn on the lights
|
|
27
|
+
await client.sendControl("LightsCtrl", { lights: { value: 1 } });
|
|
28
|
+
|
|
29
|
+
// subscribe to battery telemetry updates
|
|
30
|
+
client.on("BatteryTel", data => {
|
|
31
|
+
console.log("received BatteryTel:", data);
|
|
26
32
|
});
|
|
27
33
|
```
|
package/dist/example.js
CHANGED
|
@@ -3,12 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const index_1 = require("./index");
|
|
4
4
|
const main = async () => {
|
|
5
5
|
const client = new index_1.BlueyeClient();
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
console.log("
|
|
9
|
-
|
|
10
|
-
client.
|
|
11
|
-
|
|
6
|
+
// request battery information
|
|
7
|
+
const batteryRep = await client.sendRequest("GetBatteryReq");
|
|
8
|
+
console.log("batteryRep:", batteryRep);
|
|
9
|
+
// get latest battery telemetry
|
|
10
|
+
const batteryTel = await client.getTelemetry("BatteryTel");
|
|
11
|
+
console.log("batteryTel:", batteryTel);
|
|
12
|
+
// send a control message to turn on the lights
|
|
13
|
+
await client.sendControl("LightsCtrl", { lights: { value: 1 } });
|
|
14
|
+
// subscribe to battery telemetry updates
|
|
15
|
+
client.on("BatteryTel", data => {
|
|
16
|
+
console.log("received BatteryTel:", data);
|
|
12
17
|
});
|
|
13
18
|
};
|
|
14
19
|
main();
|
package/dist/src/client.d.ts
CHANGED
|
@@ -9,23 +9,22 @@ export type Rep = keyof Pick<Protocol, Extract<ProtocolKey, `${string}Rep`>>;
|
|
|
9
9
|
export type Tel = keyof Pick<Protocol, Extract<ProtocolKey, `${string}Tel`>>;
|
|
10
10
|
export type Ctrl = keyof Pick<Protocol, Extract<ProtocolKey, `${string}Ctrl`>>;
|
|
11
11
|
export type ReqToRep<T extends Req> = T extends `${infer Prefix}Req` ? `${Prefix}Rep` extends ProtocolKey ? Protocol[`${Prefix}Rep`] : never : never;
|
|
12
|
-
export type MsgHandler<T extends Req> = Protocol[T];
|
|
13
|
-
export type CreateArgs<T extends Req> = Parameters<MsgHandler<T>["create"]>[0];
|
|
12
|
+
export type MsgHandler<T extends Req | Ctrl> = Protocol[T];
|
|
13
|
+
export type CreateArgs<T extends Req | Ctrl> = Parameters<MsgHandler<T>["create"]>[0];
|
|
14
14
|
export type DecodedOutput<T extends Req> = ReturnType<ReqToRep<T>["decode"]>;
|
|
15
15
|
export type DecodedTelOutput<T extends Tel> = ReturnType<Protocol[T]["decode"]>;
|
|
16
16
|
export type Events = {
|
|
17
17
|
[K in Tel]: [DecodedTelOutput<K>];
|
|
18
18
|
};
|
|
19
19
|
export declare const isInProtocol: (key: string) => key is keyof typeof blueye.protocol;
|
|
20
|
-
export declare class BlueyeClient {
|
|
20
|
+
export declare class BlueyeClient extends Emitter<Events> {
|
|
21
21
|
timeout: number;
|
|
22
|
-
private
|
|
23
|
-
private
|
|
24
|
-
private
|
|
22
|
+
private sub;
|
|
23
|
+
private rpc;
|
|
24
|
+
private pub;
|
|
25
25
|
private logger;
|
|
26
|
-
private pendingRequests;
|
|
27
|
-
sub: Emitter<Events>;
|
|
28
26
|
constructor(timeout?: number, logLevel?: LogLevel);
|
|
29
27
|
sendRequest<T extends Req>(req: T, opts?: CreateArgs<T>): Promise<DecodedOutput<T> | null>;
|
|
30
28
|
getTelemetry<T extends Tel>(type: T): Promise<DecodedTelOutput<T>>;
|
|
29
|
+
sendControl<T extends Ctrl>(ctrl: T, opts?: CreateArgs<T>): Promise<void>;
|
|
31
30
|
}
|
package/dist/src/client.js
CHANGED
|
@@ -4,93 +4,94 @@ exports.BlueyeClient = exports.isInProtocol = void 0;
|
|
|
4
4
|
const protocol_definitions_1 = require("@blueyerobotics/protocol-definitions");
|
|
5
5
|
const buffer_1 = require("buffer");
|
|
6
6
|
const consola_1 = require("consola");
|
|
7
|
+
const jszmq_1 = require("jszmq");
|
|
7
8
|
const strict_event_emitter_1 = require("strict-event-emitter");
|
|
8
|
-
const uuid_1 = require("uuid");
|
|
9
9
|
const schema_1 = require("./schema");
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
const SUB_URL = "ws://192.168.1.101:9985";
|
|
11
|
+
const RPC_URL = "ws://192.168.1.101:9986";
|
|
12
|
+
const PUB_URL = "ws://192.168.1.101:9987";
|
|
12
13
|
const isInProtocol = (key) => {
|
|
13
14
|
return key in protocol_definitions_1.blueye.protocol;
|
|
14
15
|
};
|
|
15
16
|
exports.isInProtocol = isInProtocol;
|
|
16
|
-
class BlueyeClient {
|
|
17
|
+
class BlueyeClient extends strict_event_emitter_1.Emitter {
|
|
17
18
|
timeout;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
sub;
|
|
20
|
+
rpc;
|
|
21
|
+
pub;
|
|
21
22
|
logger;
|
|
22
|
-
pendingRequests = new Map();
|
|
23
|
-
sub = new strict_event_emitter_1.Emitter();
|
|
24
23
|
constructor(timeout = 2000, logLevel = consola_1.LogLevels.info) {
|
|
24
|
+
super();
|
|
25
25
|
this.timeout = timeout;
|
|
26
26
|
this.logger = (0, consola_1.createConsola)({ level: logLevel, formatOptions: { colors: true, compact: false } });
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
29
|
-
this.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
this.sub = new jszmq_1.Sub();
|
|
28
|
+
this.rpc = new jszmq_1.Req();
|
|
29
|
+
this.pub = new jszmq_1.Pub();
|
|
30
|
+
this.sub.subscribe("");
|
|
31
|
+
this.sub.connect(SUB_URL);
|
|
32
|
+
this.rpc.connect(RPC_URL);
|
|
33
|
+
this.pub.connect(PUB_URL);
|
|
34
|
+
// @ts-ignore
|
|
35
|
+
this.sub.on("message", (topic, msg) => {
|
|
36
|
+
const { key, data } = schema_1.responseSchema.parse({ key: topic, data: msg });
|
|
37
|
+
if (!(0, exports.isInProtocol)(key) || !key.endsWith("Tel")) {
|
|
38
|
+
this.logger.warn("[sub] unknown protocol:", key);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
38
41
|
const protocol = protocol_definitions_1.blueye.protocol[key];
|
|
39
42
|
const message = protocol.decode(data);
|
|
40
|
-
this.logger.verbose("[
|
|
41
|
-
this.
|
|
42
|
-
});
|
|
43
|
-
this.wsReqRep.addEventListener("message", event => {
|
|
44
|
-
this.logger.debug("Response:", event.data);
|
|
45
|
-
const { id, key, data } = schema_1.responseSchema.parse(JSON.parse(event.data));
|
|
46
|
-
if (!id)
|
|
47
|
-
throw new Error("Response id is missing");
|
|
48
|
-
this.pendingRequests.get(id)?.({ key, data });
|
|
43
|
+
this.logger.verbose("[sub] message:", key, message);
|
|
44
|
+
this.emit(key, message);
|
|
49
45
|
});
|
|
50
46
|
}
|
|
51
47
|
async sendRequest(req, opts = {}) {
|
|
48
|
+
if (!(0, exports.isInProtocol)(req) || !req.endsWith("Req")) {
|
|
49
|
+
throw new Error(`[rpc] unknown protocol: ${req}`);
|
|
50
|
+
}
|
|
52
51
|
const protocol = protocol_definitions_1.blueye.protocol[req];
|
|
53
52
|
const message = protocol.create(opts);
|
|
54
53
|
const encoded = protocol.encode(message).finish();
|
|
55
|
-
while (!this.isReqRepConnected) {
|
|
56
|
-
this.logger.debug("Waiting...");
|
|
57
|
-
await new Promise(res => setTimeout(res, 50));
|
|
58
|
-
}
|
|
59
|
-
const id = (0, uuid_1.v4)();
|
|
60
54
|
const { key, data } = await Promise.race([
|
|
61
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("
|
|
55
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("[rpc] request timed out")), this.timeout)),
|
|
62
56
|
new Promise(resolve => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
key:
|
|
66
|
-
data: buffer_1.Buffer.from(encoded).toString("base64")
|
|
57
|
+
// @ts-ignore
|
|
58
|
+
this.rpc.once("message", (topic, msg) => {
|
|
59
|
+
resolve({ key: topic.toString().split(".").at(-1), data: msg });
|
|
67
60
|
});
|
|
68
|
-
this.
|
|
69
|
-
this.wsReqRep.send(request);
|
|
61
|
+
this.rpc.send([buffer_1.Buffer.from(`blueye.protocol.${req}`), buffer_1.Buffer.from(encoded)]);
|
|
70
62
|
})
|
|
71
63
|
]);
|
|
72
|
-
this.pendingRequests.delete(id);
|
|
73
64
|
if (key === "Empty") {
|
|
74
65
|
return null;
|
|
75
66
|
}
|
|
67
|
+
if (!(0, exports.isInProtocol)(key) || !key.endsWith("Rep")) {
|
|
68
|
+
throw new Error(`[rpc] unknown response protocol: ${key}`);
|
|
69
|
+
}
|
|
76
70
|
const rep = protocol_definitions_1.blueye.protocol[key];
|
|
77
71
|
const result = rep.decode(data);
|
|
78
|
-
this.logger.debug("
|
|
72
|
+
this.logger.debug("[rpc] decoded:", result);
|
|
79
73
|
return result;
|
|
80
74
|
}
|
|
81
75
|
async getTelemetry(type) {
|
|
82
76
|
const response = await this.sendRequest("GetTelemetryReq", { messageType: type });
|
|
83
77
|
const { payload } = schema_1.telemetrySchema.parse(response);
|
|
84
78
|
const { typeUrl, value } = payload;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const result = protocol_definitions_1.blueye.protocol[typeUrl].decode(value);
|
|
88
|
-
this.logger.debug("Result:", result);
|
|
89
|
-
return result;
|
|
79
|
+
if (!(0, exports.isInProtocol)(typeUrl) || !typeUrl.endsWith("Tel")) {
|
|
80
|
+
throw new Error(`[rpc] unknown telemetry typeUrl: ${typeUrl}`);
|
|
90
81
|
}
|
|
91
|
-
|
|
92
|
-
|
|
82
|
+
const result = protocol_definitions_1.blueye.protocol[typeUrl].decode(value);
|
|
83
|
+
this.logger.debug("[rpc] result:", result);
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
async sendControl(ctrl, opts = {}) {
|
|
87
|
+
if (!(0, exports.isInProtocol)(ctrl) || !ctrl.endsWith("Ctrl")) {
|
|
88
|
+
throw new Error(`[pub] unknown protocol: ${ctrl}`);
|
|
93
89
|
}
|
|
90
|
+
const protocol = protocol_definitions_1.blueye.protocol[ctrl];
|
|
91
|
+
const message = protocol.create(opts);
|
|
92
|
+
const encoded = protocol.encode(message).finish();
|
|
93
|
+
this.logger.debug("[pub] sending control:", ctrl, message);
|
|
94
|
+
this.pub.send([buffer_1.Buffer.from(`blueye.protocol.${ctrl}`), buffer_1.Buffer.from(encoded)]);
|
|
94
95
|
}
|
|
95
96
|
}
|
|
96
97
|
exports.BlueyeClient = BlueyeClient;
|
package/dist/src/schema.d.ts
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import { Buffer } from "buffer";
|
|
2
2
|
import z from "zod";
|
|
3
3
|
export declare const responseSchema: z.ZodObject<{
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
data: z.ZodEffects<z.ZodString, Buffer, string>;
|
|
4
|
+
key: z.ZodEffects<z.ZodType<Buffer, z.ZodTypeDef, Buffer>, string, Buffer>;
|
|
5
|
+
data: z.ZodType<Buffer, z.ZodTypeDef, Buffer>;
|
|
7
6
|
}, "strip", z.ZodTypeAny, {
|
|
8
7
|
key: string;
|
|
9
8
|
data: Buffer;
|
|
10
|
-
id?: string | undefined;
|
|
11
9
|
}, {
|
|
12
|
-
key:
|
|
13
|
-
data:
|
|
14
|
-
id?: string | undefined;
|
|
10
|
+
key: Buffer;
|
|
11
|
+
data: Buffer;
|
|
15
12
|
}>;
|
|
16
13
|
export declare const telemetrySchema: z.ZodObject<{
|
|
17
14
|
payload: z.ZodObject<{
|
package/dist/src/schema.js
CHANGED
|
@@ -7,12 +7,8 @@ exports.telemetrySchema = exports.responseSchema = void 0;
|
|
|
7
7
|
const buffer_1 = require("buffer");
|
|
8
8
|
const zod_1 = __importDefault(require("zod"));
|
|
9
9
|
exports.responseSchema = zod_1.default.object({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
data: zod_1.default
|
|
13
|
-
.string()
|
|
14
|
-
.base64()
|
|
15
|
-
.transform(val => buffer_1.Buffer.from(val, "base64"))
|
|
10
|
+
key: zod_1.default.instanceof(buffer_1.Buffer).transform(val => val.toString().split(".").at(-1)),
|
|
11
|
+
data: zod_1.default.instanceof(buffer_1.Buffer)
|
|
16
12
|
});
|
|
17
13
|
exports.telemetrySchema = zod_1.default.object({
|
|
18
14
|
payload: zod_1.default.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blueyerobotics/blueye-ts",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A TypeScript client for interacting with Blueye underwater drones.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"@blueyerobotics/protocol-definitions": "3.2.0-0f78a956",
|
|
23
23
|
"buffer": "^6.0.3",
|
|
24
24
|
"consola": "^3.4.2",
|
|
25
|
+
"jszmq": "^0.1.2",
|
|
25
26
|
"strict-event-emitter": "^0.5.1",
|
|
26
|
-
"uuid": "^11.1.0",
|
|
27
27
|
"zod": "^3.25.67"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|