Skip to content

Commit 38db0d0

Browse files
committed
hub: move hub info reducers to hub
Most of the hub state doesn't depend on the connection type. To make it generic, move it out of ble and into hub so that we can share it with usb.
1 parent 1fe01b5 commit 38db0d0

File tree

6 files changed

+177
-186
lines changed

6 files changed

+177
-186
lines changed

src/ble/reducers.test.ts

Lines changed: 0 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,6 @@
22
// Copyright (c) 2021-2025 The Pybricks Authors
33

44
import { AnyAction } from 'redux';
5-
import {
6-
bleDIServiceDidReceiveFirmwareRevision,
7-
bleDIServiceDidReceivePnPId,
8-
} from '../ble-device-info-service/actions';
9-
import { PnpIdVendorIdSource } from '../ble-device-info-service/protocol';
10-
import { HubType, LegoCompanyId } from '../ble-lwp3-service/protocol';
11-
import { didReceiveStatusReport } from '../ble-pybricks-service/actions';
12-
import { Status, statusToFlag } from '../ble-pybricks-service/protocol';
135
import {
146
bleConnectPybricks,
157
bleDidConnectPybricks,
@@ -26,11 +18,6 @@ test('initial state', () => {
2618
expect(reducers(undefined, {} as AnyAction)).toMatchInlineSnapshot(`
2719
{
2820
"connection": "ble.connection.state.disconnected",
29-
"deviceBatteryCharging": false,
30-
"deviceFirmwareVersion": "",
31-
"deviceLowBatteryWarning": false,
32-
"deviceName": "",
33-
"deviceType": "",
3421
}
3522
`);
3623
});
@@ -73,87 +60,3 @@ test('connection', () => {
7360
).connection,
7461
).toBe(BleConnectionState.Connected);
7562
});
76-
77-
test('deviceName', () => {
78-
const testId = 'test-id';
79-
const testName = 'Test Name';
80-
81-
expect(
82-
reducers({ deviceName: '' } as State, bleDidConnectPybricks(testId, testName))
83-
.deviceName,
84-
).toBe(testName);
85-
86-
expect(
87-
reducers({ deviceName: testName } as State, bleDidDisconnectPybricks())
88-
.deviceName,
89-
).toBe('');
90-
});
91-
92-
test('deviceType', () => {
93-
expect(
94-
reducers(
95-
{ deviceType: '' } as State,
96-
bleDIServiceDidReceivePnPId({
97-
vendorIdSource: PnpIdVendorIdSource.BluetoothSig,
98-
vendorId: LegoCompanyId,
99-
productId: HubType.MoveHub,
100-
productVersion: 0,
101-
}),
102-
).deviceType,
103-
).toBe('Move hub');
104-
105-
expect(
106-
reducers({ deviceType: 'Move hub' } as State, bleDidDisconnectPybricks())
107-
.deviceType,
108-
).toBe('');
109-
});
110-
111-
test('deviceFirmwareVersion', () => {
112-
const testVersion = '3.0.0';
113-
114-
expect(
115-
reducers(
116-
{ deviceFirmwareVersion: '' } as State,
117-
bleDIServiceDidReceiveFirmwareRevision(testVersion),
118-
).deviceFirmwareVersion,
119-
).toBe(testVersion);
120-
121-
expect(
122-
reducers(
123-
{ deviceFirmwareVersion: testVersion } as State,
124-
bleDidDisconnectPybricks(),
125-
).deviceFirmwareVersion,
126-
).toBe('');
127-
});
128-
129-
test('deviceLowBatteryWarning', () => {
130-
expect(
131-
reducers(
132-
{ deviceLowBatteryWarning: false } as State,
133-
didReceiveStatusReport(statusToFlag(Status.BatteryLowVoltageWarning), 0, 0),
134-
).deviceLowBatteryWarning,
135-
).toBeTruthy();
136-
137-
expect(
138-
reducers(
139-
{ deviceLowBatteryWarning: true } as State,
140-
didReceiveStatusReport(
141-
~statusToFlag(Status.BatteryLowVoltageWarning),
142-
0,
143-
0,
144-
),
145-
).deviceLowBatteryWarning,
146-
).toBeFalsy();
147-
148-
expect(
149-
reducers({ deviceLowBatteryWarning: true } as State, bleDidDisconnectPybricks())
150-
.deviceLowBatteryWarning,
151-
).toBeFalsy();
152-
});
153-
154-
test('deviceBatteryCharging', () => {
155-
expect(
156-
reducers({ deviceBatteryCharging: true } as State, bleDidDisconnectPybricks())
157-
.deviceBatteryCharging,
158-
).toBeFalsy();
159-
});

src/ble/reducers.ts

Lines changed: 1 addition & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
// SPDX-License-Identifier: MIT
2-
// Copyright (c) 2020-2022 The Pybricks Authors
2+
// Copyright (c) 2020-2025 The Pybricks Authors
33
//
44
// Manages state for the Bluetooth Low Energy connection.
55
// This assumes that there is only one global connection to a single device.
66

77
import { Reducer, combineReducers } from 'redux';
8-
import {
9-
bleDIServiceDidReceiveFirmwareRevision,
10-
bleDIServiceDidReceivePnPId,
11-
} from '../ble-device-info-service/actions';
12-
import { getHubTypeName } from '../ble-device-info-service/protocol';
13-
import { didReceiveStatusReport } from '../ble-pybricks-service/actions';
14-
import { Status, statusToFlag } from '../ble-pybricks-service/protocol';
158
import {
169
bleConnectPybricks,
1710
bleDidConnectPybricks,
@@ -72,71 +65,6 @@ const connection: Reducer<BleConnectionState> = (
7265
return state;
7366
};
7467

75-
const deviceName: Reducer<string> = (state = '', action) => {
76-
if (bleDidDisconnectPybricks.matches(action)) {
77-
return '';
78-
}
79-
80-
if (bleDidConnectPybricks.matches(action)) {
81-
return action.name;
82-
}
83-
84-
return state;
85-
};
86-
87-
const deviceType: Reducer<string> = (state = '', action) => {
88-
if (bleDidDisconnectPybricks.matches(action)) {
89-
return '';
90-
}
91-
92-
if (bleDIServiceDidReceivePnPId.matches(action)) {
93-
return getHubTypeName(action.pnpId);
94-
}
95-
96-
return state;
97-
};
98-
99-
const deviceFirmwareVersion: Reducer<string> = (state = '', action) => {
100-
if (bleDidDisconnectPybricks.matches(action)) {
101-
return '';
102-
}
103-
104-
if (bleDIServiceDidReceiveFirmwareRevision.matches(action)) {
105-
return action.version;
106-
}
107-
108-
return state;
109-
};
110-
111-
const deviceLowBatteryWarning: Reducer<boolean> = (state = false, action) => {
112-
if (bleDidDisconnectPybricks.matches(action)) {
113-
return false;
114-
}
115-
116-
if (didReceiveStatusReport.matches(action)) {
117-
return Boolean(
118-
action.statusFlags & statusToFlag(Status.BatteryLowVoltageWarning),
119-
);
120-
}
121-
122-
return state;
123-
};
124-
125-
const deviceBatteryCharging: Reducer<boolean> = (state = false, action) => {
126-
if (bleDidDisconnectPybricks.matches(action)) {
127-
return false;
128-
}
129-
130-
// TODO: hub does not currently have a status flag for this
131-
132-
return state;
133-
};
134-
13568
export default combineReducers({
13669
connection,
137-
deviceName,
138-
deviceType,
139-
deviceFirmwareVersion,
140-
deviceLowBatteryWarning,
141-
deviceBatteryCharging,
14270
});

src/hub/reducers.test.ts

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ import {
77
bleDidDisconnectPybricks,
88
bleDisconnectPybricks,
99
} from '../ble/actions';
10-
import { bleDIServiceDidReceiveSoftwareRevision } from '../ble-device-info-service/actions';
11-
import { PnpId } from '../ble-device-info-service/protocol';
12-
import { HubType } from '../ble-lwp3-service/protocol';
10+
import {
11+
bleDIServiceDidReceiveFirmwareRevision,
12+
bleDIServiceDidReceivePnPId,
13+
bleDIServiceDidReceiveSoftwareRevision,
14+
} from '../ble-device-info-service/actions';
15+
import { PnpId, PnpIdVendorIdSource } from '../ble-device-info-service/protocol';
16+
import { HubType, LegoCompanyId } from '../ble-lwp3-service/protocol';
1317
import {
1418
blePybricksServiceDidNotReceiveHubCapabilities,
1519
blePybricksServiceDidReceiveHubCapabilities,
@@ -40,6 +44,11 @@ type State = ReturnType<typeof reducers>;
4044
test('initial state', () => {
4145
expect(reducers(undefined, {} as AnyAction)).toMatchInlineSnapshot(`
4246
{
47+
"deviceBatteryCharging": false,
48+
"deviceFirmwareVersion": "",
49+
"deviceLowBatteryWarning": false,
50+
"deviceName": "",
51+
"deviceType": "",
4352
"downloadProgress": null,
4453
"hasRepl": false,
4554
"maxBleWriteSize": 0,
@@ -298,6 +307,90 @@ describe('runtime', () => {
298307
});
299308
});
300309

310+
test('deviceName', () => {
311+
const testId = 'test-id';
312+
const testName = 'Test Name';
313+
314+
expect(
315+
reducers({ deviceName: '' } as State, bleDidConnectPybricks(testId, testName))
316+
.deviceName,
317+
).toBe(testName);
318+
319+
expect(
320+
reducers({ deviceName: testName } as State, bleDidDisconnectPybricks())
321+
.deviceName,
322+
).toBe('');
323+
});
324+
325+
test('deviceType', () => {
326+
expect(
327+
reducers(
328+
{ deviceType: '' } as State,
329+
bleDIServiceDidReceivePnPId({
330+
vendorIdSource: PnpIdVendorIdSource.BluetoothSig,
331+
vendorId: LegoCompanyId,
332+
productId: HubType.MoveHub,
333+
productVersion: 0,
334+
}),
335+
).deviceType,
336+
).toBe('Move hub');
337+
338+
expect(
339+
reducers({ deviceType: 'Move hub' } as State, bleDidDisconnectPybricks())
340+
.deviceType,
341+
).toBe('');
342+
});
343+
344+
test('deviceFirmwareVersion', () => {
345+
const testVersion = '3.0.0';
346+
347+
expect(
348+
reducers(
349+
{ deviceFirmwareVersion: '' } as State,
350+
bleDIServiceDidReceiveFirmwareRevision(testVersion),
351+
).deviceFirmwareVersion,
352+
).toBe(testVersion);
353+
354+
expect(
355+
reducers(
356+
{ deviceFirmwareVersion: testVersion } as State,
357+
bleDidDisconnectPybricks(),
358+
).deviceFirmwareVersion,
359+
).toBe('');
360+
});
361+
362+
test('deviceLowBatteryWarning', () => {
363+
expect(
364+
reducers(
365+
{ deviceLowBatteryWarning: false } as State,
366+
didReceiveStatusReport(statusToFlag(Status.BatteryLowVoltageWarning), 0, 0),
367+
).deviceLowBatteryWarning,
368+
).toBeTruthy();
369+
370+
expect(
371+
reducers(
372+
{ deviceLowBatteryWarning: true } as State,
373+
didReceiveStatusReport(
374+
~statusToFlag(Status.BatteryLowVoltageWarning),
375+
0,
376+
0,
377+
),
378+
).deviceLowBatteryWarning,
379+
).toBeFalsy();
380+
381+
expect(
382+
reducers({ deviceLowBatteryWarning: true } as State, bleDidDisconnectPybricks())
383+
.deviceLowBatteryWarning,
384+
).toBeFalsy();
385+
});
386+
387+
test('deviceBatteryCharging', () => {
388+
expect(
389+
reducers({ deviceBatteryCharging: true } as State, bleDidDisconnectPybricks())
390+
.deviceBatteryCharging,
391+
).toBeFalsy();
392+
});
393+
301394
describe('maxBleWriteSize', () => {
302395
test.each([100, 1000])('Pybricks Profile >= v1.2.0: %s', (size) => {
303396
expect(

0 commit comments

Comments
 (0)