From 68d6e7f3891f63d8746a2c620205a5f8b18f96f4 Mon Sep 17 00:00:00 2001 From: martha-johnston <106617924+martha-johnston@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:17:03 -0500 Subject: [PATCH] RSDK-4790: Add Readings to TypeScript SDK (#191) --- buf.lock | 4 +- package-lock.json | 14 +++--- package.json | 2 +- src/components/movement-sensor/client.test.ts | 46 ++++++++----------- src/components/movement-sensor/client.ts | 43 ++++++++--------- .../movement-sensor/movement-sensor.ts | 19 ++------ src/components/movementsensor.ts | 1 - src/components/power-sensor/client.test.ts | 40 ++++++++-------- src/components/power-sensor/client.ts | 46 +++++++++---------- src/components/power-sensor/power-sensor.ts | 9 +--- src/components/powersensor.ts | 5 +- src/main.ts | 7 +-- 12 files changed, 101 insertions(+), 135 deletions(-) diff --git a/buf.lock b/buf.lock index 0b62e85d3..c18702d6b 100644 --- a/buf.lock +++ b/buf.lock @@ -14,8 +14,8 @@ deps: - remote: buf.build owner: viamrobotics repository: api - commit: 9196e89cb02f40d6b38344d637fdb3fc - digest: shake256:45153f9922a876347f1b3cf7db9d35a76ff045e5a72b83fc7d6e89d1e899ff53b2d3930c36f7ce8aac704fb57f60dd9cbdba61224c8df51b1044a1ff9882ba15 + commit: db4372e839fc4ddab817a38a397686fb + digest: shake256:7983589dddbde5534f0f04a4c43e1cb94f185b11f1ff6d0fe8ba50fa5fdb22711a60c009b5d428b20fd251b497e2259605a065556013a4fb9daa1f2ce6b10168 - remote: buf.build owner: viamrobotics repository: goutils diff --git a/package-lock.json b/package-lock.json index 27c3bcf24..f63b3b778 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "grpc-web": "^1.4.2", "happy-dom": "^8.2.6", "npm-check": "^6.0.1", - "prettier": "^2.8.1", + "prettier": "^2.8.8", "prettier-plugin-jsdoc": "^0.4.2", "protoc-gen-js": "^3.21.2", "ts-protoc-gen": "^0.15.0", @@ -7572,9 +7572,9 @@ } }, "node_modules/prettier": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", - "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "bin": { "prettier": "bin-prettier.js" @@ -15319,9 +15319,9 @@ "dev": true }, "prettier": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", - "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true }, "prettier-plugin-jsdoc": { diff --git a/package.json b/package.json index b31344353..5a6cffef7 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "grpc-web": "^1.4.2", "happy-dom": "^8.2.6", "npm-check": "^6.0.1", - "prettier": "^2.8.1", + "prettier": "^2.8.8", "prettier-plugin-jsdoc": "^0.4.2", "protoc-gen-js": "^3.21.2", "ts-protoc-gen": "^0.15.0", diff --git a/src/components/movement-sensor/client.test.ts b/src/components/movement-sensor/client.test.ts index 92148e78c..1596356cc 100644 --- a/src/components/movement-sensor/client.test.ts +++ b/src/components/movement-sensor/client.test.ts @@ -8,11 +8,29 @@ import { MovementSensorClient } from './client'; let sensor: MovementSensorClient; +const mapVals = { + toJavaScript: () => { + return 'readings'; + }, +}; + beforeEach(() => { RobotClient.prototype.createServiceClient = vi .fn() .mockImplementation(() => new MovementSensorServiceClient('mysensor')); + MovementSensorServiceClient.prototype.getReadings = vi + .fn() + .mockImplementation((_req, _md, cb) => { + cb(null, { + getReadingsMap: () => { + return { + entries: () => new Map([['readings', mapVals]]), + }; + }, + }); + }); + MovementSensorServiceClient.prototype.getPosition = vi .fn() .mockImplementation((_req, _md, cb) => { @@ -88,12 +106,7 @@ test('individual readings', async () => { test('get readings', async () => { await expect(sensor.getReadings()).resolves.toStrictEqual({ - position: 'pos', - linearVelocity: 'vel', - linearAcceleration: 'acc', - angularVelocity: 'ang', - compassHeading: 'comp', - orientation: 'ori', + readings: 'readings', }); }); @@ -110,25 +123,6 @@ test('get readings returns without unimplemented fields', async () => { unimplementedError ); await expect(sensor.getReadings()).resolves.toStrictEqual({ - position: 'pos', - linearAcceleration: 'acc', - angularVelocity: 'ang', - compassHeading: 'comp', - orientation: 'ori', + readings: 'readings', }); }); - -test('get readings fails on other errors', async () => { - const unexpectedError = new Error('Jank!'); - - MovementSensorServiceClient.prototype.getLinearVelocity = vi - .fn() - .mockImplementation((_req, _md, cb) => { - cb(unexpectedError, null); - }); - - await expect(sensor.getLinearVelocity()).rejects.toStrictEqual( - unexpectedError - ); - await expect(sensor.getReadings()).rejects.toStrictEqual(unexpectedError); -}); diff --git a/src/components/movement-sensor/client.ts b/src/components/movement-sensor/client.ts index a5cedcd9e..a7956c061 100644 --- a/src/components/movement-sensor/client.ts +++ b/src/components/movement-sensor/client.ts @@ -4,7 +4,11 @@ import { MovementSensorServiceClient } from '../../gen/component/movementsensor/ import type { Options, StructType } from '../../types'; import pb from '../../gen/component/movementsensor/v1/movementsensor_pb'; import { promisify, doCommandFromClient } from '../../utils'; -import type { MovementSensor, MovementSensorReadings } from './movement-sensor'; +import { + GetReadingsRequest, + GetReadingsResponse, +} from '../../gen/common/v1/common_pb'; +import type { MovementSensor } from './movement-sensor'; /** * A gRPC-web client for the MovementSensor component. @@ -195,30 +199,23 @@ export class MovementSensorClient implements MovementSensor { } async getReadings(extra = {}) { - const readingFunctions = { - position: this.getPosition.bind(this), - linearVelocity: this.getLinearVelocity.bind(this), - angularVelocity: this.getAngularVelocity.bind(this), - linearAcceleration: this.getLinearAcceleration.bind(this), - compassHeading: this.getCompassHeading.bind(this), - orientation: this.getOrientation.bind(this), - }; - - const tasks = Object.entries(readingFunctions).flatMap(([field, func]) => - (async () => { - try { - return [[field, await func(extra)]]; - } catch (error) { - if (!(error as Error).message.includes('Unimplemented')) { - throw error; - } - return []; - } - })() + const { movementsensorService } = this; + const request = new GetReadingsRequest(); + request.setName(this.name); + request.setExtra(Struct.fromJavaScript(extra)); + + this.options.requestLogger?.(request); + + const response = await promisify( + movementsensorService.getReadings.bind(movementsensorService), + request ); - const entries = await Promise.all(tasks); - return Object.fromEntries(entries.flat()) as MovementSensorReadings; + const result: Record = {}; + for (const [key, value] of response.getReadingsMap().entries()) { + result[key] = value.toJavaScript(); + } + return result; } async doCommand(command: StructType): Promise { diff --git a/src/components/movement-sensor/movement-sensor.ts b/src/components/movement-sensor/movement-sensor.ts index 0ba6c985d..a126bdf46 100644 --- a/src/components/movement-sensor/movement-sensor.ts +++ b/src/components/movement-sensor/movement-sensor.ts @@ -1,26 +1,14 @@ -import type { Orientation, StructType, Vector3 } from '../../types'; -import type { Sensor } from '../sensor'; +import type { Resource, Orientation, StructType, Vector3 } from '../../types'; import pb from '../../gen/component/movementsensor/v1/movementsensor_pb'; export type MovementSensorPosition = pb.GetPositionResponse.AsObject; export type MovementSensorProperties = pb.GetPropertiesResponse.AsObject; -// https://github.com/microsoft/TypeScript/issues/15300 -// eslint-disable-next-line @typescript-eslint/consistent-type-definitions -export type MovementSensorReadings = { - position?: MovementSensorPosition; - linearVelocity?: Vector3; - angularVelocity?: Vector3; - linearAcceleration?: Vector3; - compassHeading?: number; - orientation?: Orientation; -}; - /** * Represents any sensor that reports information about the robot's direction, * position, and/or speed. */ -export interface MovementSensor extends Sensor { +export interface MovementSensor extends Resource { /** Get linear velocity across x/y/z axes */ getLinearVelocity(extra?: StructType): Promise; @@ -50,4 +38,7 @@ export interface MovementSensor extends Sensor { /** Get linear acceleration across x/y/z axes */ getLinearAcceleration(extra?: StructType): Promise; + + /** Return the readings of a sensor. */ + getReadings(extra?: StructType): Promise>; } diff --git a/src/components/movementsensor.ts b/src/components/movementsensor.ts index de6c56369..42cb8cdda 100644 --- a/src/components/movementsensor.ts +++ b/src/components/movementsensor.ts @@ -1,7 +1,6 @@ export type { MovementSensorPosition, MovementSensorProperties, - MovementSensorReadings, MovementSensor, } from './movement-sensor/movement-sensor'; export { MovementSensorClient } from './movement-sensor/client'; diff --git a/src/components/power-sensor/client.test.ts b/src/components/power-sensor/client.test.ts index 0b6e6e05c..864f39fdb 100644 --- a/src/components/power-sensor/client.test.ts +++ b/src/components/power-sensor/client.test.ts @@ -12,6 +12,12 @@ const testVoltage = 1.5; const testCurrent = 1; const testIsAc = true; +const mapVals = { + toJavaScript: () => { + return 'readings'; + }, +}; + beforeEach(() => { RobotClient.prototype.createServiceClient = vi .fn() @@ -42,6 +48,18 @@ beforeEach(() => { }); }); + PowerSensorServiceClient.prototype.getReadings = vi + .fn() + .mockImplementation((_req, _md, cb) => { + cb(null, { + getReadingsMap: () => { + return { + entries: () => new Map([['readings', mapVals]]), + }; + }, + }); + }); + sensor = new PowerSensorClient(new RobotClient('host'), 'test-sensor'); }); @@ -63,10 +81,7 @@ test('individual readings', async () => { test('get readings', async () => { await expect(sensor.getReadings()).resolves.toStrictEqual({ - voltage: testVoltage, - current: testCurrent, - isAc: testIsAc, - power: testPower, + readings: 'readings', }); }); @@ -81,21 +96,6 @@ test('get readings returns without unimplemented fields', async () => { await expect(sensor.getVoltage()).rejects.toStrictEqual(unimplementedError); await expect(sensor.getReadings()).resolves.toStrictEqual({ - current: testCurrent, - isAc: testIsAc, - power: testPower, + readings: 'readings', }); }); - -test('get readings fails on other errors', async () => { - const unexpectedError = new Error('Jank!'); - - PowerSensorServiceClient.prototype.getPower = vi - .fn() - .mockImplementation((_req, _md, cb) => { - cb(unexpectedError, null); - }); - - await expect(sensor.getPower()).rejects.toStrictEqual(unexpectedError); - await expect(sensor.getReadings()).rejects.toStrictEqual(unexpectedError); -}); diff --git a/src/components/power-sensor/client.ts b/src/components/power-sensor/client.ts index bb585eec8..c5a130d63 100644 --- a/src/components/power-sensor/client.ts +++ b/src/components/power-sensor/client.ts @@ -4,10 +4,14 @@ import { PowerSensorServiceClient } from '../../gen/component/powersensor/v1/pow import type { Options, StructType } from '../../types'; import pb from '../../gen/component/powersensor/v1/powersensor_pb'; import { promisify, doCommandFromClient } from '../../utils'; -import type { PowerSensor, PowerSensorReadings } from './power-sensor'; +import { + GetReadingsRequest, + GetReadingsResponse, +} from '../../gen/common/v1/common_pb'; +import type { PowerSensor } from './power-sensor'; /** - * A gRPC-web client for the MovementSensor component. + * A gRPC-web client for the PowerSensor component. * * @group Clients */ @@ -76,29 +80,23 @@ export class PowerSensorClient implements PowerSensor { } async getReadings(extra = {}) { - const readings: Record = {}; - try { - [readings['voltage'], readings['isAc']] = await this.getVoltage(extra); - } catch (error) { - if (!(error as Error).message.includes('Unimplemented')) { - throw error; - } - } - try { - [readings['current'], readings['isAc']] = await this.getCurrent(extra); - } catch (error) { - if (!(error as Error).message.includes('Unimplemented')) { - throw error; - } - } - try { - readings['power'] = await this.getPower(extra); - } catch (error) { - if (!(error as Error).message.includes('Unimplemented')) { - throw error; - } + const { powersensorService } = this; + const request = new GetReadingsRequest(); + request.setName(this.name); + request.setExtra(Struct.fromJavaScript(extra)); + + this.options.requestLogger?.(request); + + const response = await promisify( + powersensorService.getReadings.bind(powersensorService), + request + ); + + const result: Record = {}; + for (const [key, value] of response.getReadingsMap().entries()) { + result[key] = value.toJavaScript(); } - return readings as PowerSensorReadings; + return result; } async doCommand(command: StructType): Promise { diff --git a/src/components/power-sensor/power-sensor.ts b/src/components/power-sensor/power-sensor.ts index 57119863c..cc727c74c 100644 --- a/src/components/power-sensor/power-sensor.ts +++ b/src/components/power-sensor/power-sensor.ts @@ -1,13 +1,6 @@ import type { StructType } from '../../types'; import type { Sensor } from '../sensor'; -export type PowerSensorReadings = { - voltage?: number; - current?: number; - isAc?: boolean; - power?: number; -}; - /** Represents any sensor that reports voltage, current, and/or power */ export interface PowerSensor extends Sensor { /** Get Voltage in volts and a boolean that returns true if AC */ @@ -16,4 +9,6 @@ export interface PowerSensor extends Sensor { getCurrent(extra?: StructType): Promise; /** Get Power in watts */ getPower(extra?: StructType): Promise; + /** Return the readings of a sensor. */ + getReadings(extra?: StructType): Promise>; } diff --git a/src/components/powersensor.ts b/src/components/powersensor.ts index e1b22605b..8dc84bb6f 100644 --- a/src/components/powersensor.ts +++ b/src/components/powersensor.ts @@ -1,5 +1,2 @@ -export type { - PowerSensorReadings, - PowerSensor, -} from './power-sensor/power-sensor'; +export type { PowerSensor } from './power-sensor/power-sensor'; export { PowerSensorClient } from './power-sensor/client'; diff --git a/src/main.ts b/src/main.ts index ebca0440d..5391c7a88 100644 --- a/src/main.ts +++ b/src/main.ts @@ -152,7 +152,6 @@ export { type MovementSensor, type MovementSensorProperties, type MovementSensorPosition, - type MovementSensorReadings, MovementSensorClient, } from './components/movementsensor'; @@ -166,11 +165,7 @@ export { * @group Raw Protobufs */ export { default as powerSensorApi } from './gen/component/powersensor/v1/powersensor_pb'; -export { - type PowerSensor, - type PowerSensorReadings, - PowerSensorClient, -} from './components/powersensor'; +export { type PowerSensor, PowerSensorClient } from './components/powersensor'; /** * Raw Protobuf interfaces generated with