Skip to content

Commit f4e7815

Browse files
Merge pull request #33 from OpenDTU-App/multi-device-preparations
2 parents b14d762 + a2e416e commit f4e7815

25 files changed

+306
-93
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"ios": "react-native run-ios",
1717
"lint": "eslint .",
1818
"lint:fix": "eslint . --fix",
19+
"typecheck": "tsc --noEmit",
1920
"start": "react-native start",
2021
"test": "jest --passWithNoTests",
2122
"postinstall": "yarn run npm-license-crawler -onlyDirectDependencies -json licenses.json && patch-package",

src/api/ApiHandler.tsx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,42 +52,52 @@ export const ApiProvider: FC<PropsWithChildren<unknown>> = ({ children }) => {
5252
console.log('new Api');
5353

5454
useEffect(() => {
55-
dispatch(setTriedToConnect({ triedToConnect: false }));
55+
if (configIndex === null) {
56+
console.log('ApiProvider - configIndex is null');
5657

57-
if (currentConfiguration && configIndex !== null) {
58+
return;
59+
}
60+
61+
dispatch(setTriedToConnect({ triedToConnect: false, index: configIndex }));
62+
63+
if (currentConfiguration) {
5864
console.info(
5965
'Initializing API Handler',
6066
currentConfiguration,
6167
configIndex,
6268
);
6369

6470
api.registerOnDisconnectedHandler(() => {
65-
dispatch(clearOpenDtuState());
71+
dispatch(clearOpenDtuState({ index: configIndex }));
6672
});
6773

6874
api.disconnect();
6975

7076
api.setConfig(currentConfiguration, configIndex);
7177

7278
api.registerOnConnectedHandler(index => {
73-
dispatch(setIsConnected({ isConnected: true }));
79+
dispatch(setIsConnected({ isConnected: true, index: configIndex }));
7480
dispatch(setDeviceState({ deviceState: DeviceState.Connected, index }));
7581
});
7682

7783
api.registerOnDisconnectedHandler(() => {
78-
dispatch(setIsConnected({ isConnected: false }));
84+
dispatch(setIsConnected({ isConnected: false, index: configIndex }));
7985
});
8086

8187
api.registerLiveDataHandler((data, valid, index) => {
82-
dispatch(setTriedToConnect({ triedToConnect: true }));
83-
dispatch(setLiveData({ data, valid }));
88+
dispatch(
89+
setTriedToConnect({ triedToConnect: true, index: configIndex }),
90+
);
91+
dispatch(setLiveData({ data, valid, index: configIndex }));
8492
dispatch(setDeviceState({ deviceState: DeviceState.Connected, index }));
8593
});
8694

8795
api.registerHttpStatusHandler(
8896
({ systemStatus, networkStatus, ntpStatus, mqttStatus }, index) => {
8997
if (systemStatus) {
90-
dispatch(setSystemStatus({ data: systemStatus }));
98+
dispatch(
99+
setSystemStatus({ data: systemStatus, index: configIndex }),
100+
);
91101
dispatch(
92102
updateDtuHostname({
93103
hostname: systemStatus.hostname,
@@ -103,15 +113,17 @@ export const ApiProvider: FC<PropsWithChildren<unknown>> = ({ children }) => {
103113
}
104114

105115
if (networkStatus) {
106-
dispatch(setNetworkStatus({ data: networkStatus }));
116+
dispatch(
117+
setNetworkStatus({ data: networkStatus, index: configIndex }),
118+
);
107119
}
108120

109121
if (ntpStatus) {
110-
dispatch(setNtpStatus({ data: ntpStatus }));
122+
dispatch(setNtpStatus({ data: ntpStatus, index: configIndex }));
111123
}
112124

113125
if (mqttStatus) {
114-
dispatch(setMqttStatus({ data: mqttStatus }));
126+
dispatch(setMqttStatus({ data: mqttStatus, index: configIndex }));
115127
}
116128

117129
setDeviceState({ deviceState: DeviceState.Connected, index });

src/api/opendtuapi.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class OpenDtuApi {
6969
this.baseUrl = baseUrl;
7070
}
7171

72-
public setUserString(userString: string): void {
72+
public setUserString(userString: string | null): void {
7373
this.userString = userString;
7474
}
7575

@@ -142,7 +142,7 @@ class OpenDtuApi {
142142
this.onDisconnectedHandler = null;
143143
}
144144

145-
private async getSystemStatusFromUrl(
145+
public async getSystemStatusFromUrl(
146146
url: URL,
147147
): Promise<GetSystemStatusReturn> {
148148
// GET <url>/api/system/status
@@ -288,13 +288,15 @@ class OpenDtuApi {
288288
return;
289289
}
290290

291-
if (this.baseUrl && this.userString) {
291+
if (this.baseUrl) {
292292
const urlObject = new URL(this.baseUrl);
293293
const authString = this.getAuthString();
294294
const protocol = urlObject.protocol === 'https:' ? 'wss' : 'ws';
295295
const host = urlObject.host;
296296

297-
const url = `${protocol}://${authString}${host}/livedata`;
297+
const url = `${protocol}://${authString ?? ''}${host}/livedata`;
298+
299+
console.log(`Connecting websocket to ${url}`);
298300

299301
this.ws = new WebSocket(url);
300302

@@ -466,9 +468,13 @@ class OpenDtuApi {
466468
);
467469
}
468470

469-
private getAuthString(): string {
471+
private getAuthString(): string | null {
470472
let user = null;
471473

474+
if (!this.userString) {
475+
return null;
476+
}
477+
472478
try {
473479
user = JSON.parse(this.userString || '');
474480
} catch {
@@ -492,6 +498,10 @@ class OpenDtuApi {
492498
'GET',
493499
);
494500

501+
if (!res) {
502+
return null;
503+
}
504+
495505
if (res.status === 200) {
496506
return await res.json();
497507
}
@@ -506,6 +516,10 @@ class OpenDtuApi {
506516

507517
const res = await this.makeAuthenticatedRequest('/api/ntp/status', 'GET');
508518

519+
if (!res) {
520+
return null;
521+
}
522+
509523
if (res.status === 200) {
510524
return await res.json();
511525
}
@@ -520,6 +534,10 @@ class OpenDtuApi {
520534

521535
const res = await this.makeAuthenticatedRequest('/api/mqtt/status', 'GET');
522536

537+
if (!res) {
538+
return null;
539+
}
540+
523541
if (res.status === 200) {
524542
return await res.json();
525543
}
@@ -531,7 +549,7 @@ class OpenDtuApi {
531549
route: string,
532550
method: string,
533551
body: string | null = null,
534-
): Promise<Response> {
552+
): Promise<Response | null> {
535553
const authString = this.getAuthString();
536554

537555
const controller = new AbortController();
@@ -546,8 +564,8 @@ class OpenDtuApi {
546564
signal: controller.signal,
547565
headers: {
548566
'X-Requested-With': 'XMLHttpRequest',
549-
Authorization: 'Basic ' + authString,
550567
'Content-Type': 'application/json',
568+
...(authString ? { Authorization: 'Basic ' + authString } : {}),
551569
},
552570
};
553571

@@ -558,12 +576,16 @@ class OpenDtuApi {
558576
const url = `${authString}${this.baseUrl}${route}`;
559577

560578
console.log('makeAuthenticatedRequest', url, requestOptions);
561-
const res = await fetch(url, requestOptions);
562-
if (res.status === 200) {
579+
580+
try {
581+
const res = await fetch(url, requestOptions);
563582
clearTimeout(abortTimeout);
564-
}
565583

566-
return res;
584+
return res;
585+
} catch (error) {
586+
console.log('makeAuthenticatedRequest error', error);
587+
return null;
588+
}
567589
}
568590
}
569591

src/components/OpenDTUValue.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Text, useTheme } from 'react-native-paper';
55
import type { ValueObject } from '@/types/opendtu/status';
66

77
export interface OpenDTUValueProps {
8-
statusValue?: ValueObject;
8+
statusValue?: ValueObject | null;
99
textWhenInvalid?: string;
1010
textProps?: Omit<TextProps<unknown>, 'children'>;
1111
}

src/database/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,8 @@ const DatabaseProvider: FC<PropsWithChildren<unknown>> = ({ children }) => {
244244
const inverters = useAppSelector(
245245
state =>
246246
state.settings.selectedDtuConfig !== null
247-
? state.opendtu.liveData?.inverters ?? null
247+
? state.opendtu.dtuStates[state.settings.selectedDtuConfig]?.liveData
248+
?.inverters ?? null
248249
: null,
249250
(left, right) =>
250251
left === null && right === null

src/github/FetchHandler.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
setReleases,
1010
} from '@/slices/github';
1111

12+
import useDeviceIndex from '@/hooks/useDeviceIndex';
13+
1214
import ago from '@/utils/ago';
1315

1416
import {
@@ -20,8 +22,11 @@ import { useAppDispatch, useAppSelector } from '@/store';
2022

2123
const FetchHandler: FC = () => {
2224
const dispatch = useAppDispatch();
25+
const index = useDeviceIndex();
2326

24-
const isConnected = useAppSelector(state => state.opendtu.isConnected);
27+
const isConnected = useAppSelector(state =>
28+
index === null ? undefined : state.opendtu.dtuStates[index]?.isConnected,
29+
);
2530
const latestReleaseRefetchOk = useAppSelector(state =>
2631
state.github.latestRelease.lastUpdate
2732
? ago(state.github.latestRelease.lastUpdate) > 1000 * 60 * 10 // 10 minutes

src/hooks/useDeviceIndex.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { useAppSelector } from '@/store';
2+
3+
const useDeviceIndex = (): number | null => {
4+
return useAppSelector(state => state.settings.selectedDtuConfig);
5+
};
6+
7+
export default useDeviceIndex;

src/hooks/useDtuState.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { EqualityFn } from 'react-redux';
2+
3+
import type { OpenDTUDeviceState } from '@/types/opendtu/state';
4+
5+
import useDeviceIndex from '@/hooks/useDeviceIndex';
6+
7+
import { useAppSelector } from '@/store';
8+
9+
const useDtuState = <T>(
10+
selector: (state: OpenDTUDeviceState | undefined) => T,
11+
equalityFn?: EqualityFn<T | undefined>,
12+
): T | undefined => {
13+
const index = useDeviceIndex();
14+
15+
return useAppSelector(
16+
state =>
17+
index === null ? undefined : selector(state.opendtu.dtuStates[index]),
18+
equalityFn,
19+
);
20+
};
21+
22+
export default useDtuState;

src/hooks/useHasLiveData.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,20 @@ const useHasLiveData = (): boolean => {
1313
);*/
1414

1515
return useAppSelector(state => {
16-
const liveData = state.opendtu.liveData;
16+
const index = state.settings.selectedDtuConfig;
17+
18+
if (index === null) {
19+
console.log('index is null');
20+
return false;
21+
}
22+
23+
const liveData = state.opendtu.dtuStates[index]?.liveData ?? null;
1724
if (liveData === null) {
1825
console.log('liveData is null');
1926
return false;
2027
}
2128

22-
const lastUpdate = liveData.lastUpdate;
29+
const lastUpdate = liveData?.lastUpdate ?? null;
2330
if (lastUpdate === null) {
2431
console.log('lastUpdate is null');
2532
return false;

src/hooks/useIsConnected.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1+
import useDeviceIndex from '@/hooks/useDeviceIndex';
2+
13
import { useAppSelector } from '@/store';
24

35
const useIsConnected = (): boolean => {
4-
return useAppSelector(state => state.opendtu.isConnected);
6+
const index = useDeviceIndex();
7+
8+
return useAppSelector(state =>
9+
index === null
10+
? false
11+
: state.opendtu.dtuStates[index]?.isConnected ?? false,
12+
);
513
};
614

715
export default useIsConnected;

0 commit comments

Comments
 (0)