@eohjsc/react-native-smart-city 0.3.74 → 0.3.76

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.3.74",
4
+ "version": "0.3.76",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -109,7 +109,7 @@ describe('Test useRemoteControl', () => {
109
109
  data,
110
110
  'bluetooth'
111
111
  );
112
- expect(sendCommandOverInternet).toBeCalledTimes(1);
112
+ expect(sendCommandOverInternet).toBeCalledTimes(6);
113
113
  expect(sendCommandOverHomeAssistant).not.toBeCalled();
114
114
  });
115
115
 
@@ -176,7 +176,7 @@ describe('Test useRemoteControl', () => {
176
176
  data,
177
177
  userId
178
178
  );
179
- expect(sendCommandOverInternet).not.toBeCalled();
179
+ expect(sendCommandOverInternet).toBeCalled();
180
180
  expect(sendCommandOverHomeAssistant).not.toBeCalled();
181
181
  });
182
182
 
@@ -1,5 +1,7 @@
1
- import { useContext, useCallback, useRef, useEffect } from 'react';
1
+ import { useContext, useCallback, useRef, useEffect, useMemo } from 'react';
2
2
  import { AppState, Platform } from 'react-native';
3
+ import { getSystemVersion } from 'react-native-device-info';
4
+
3
5
  import { SCContext, useSCContextSelector } from '../../context';
4
6
  import { Action } from '../../context/actionType';
5
7
  import { scanBluetoothDevices } from '../../iot/RemoteControl/Bluetooth';
@@ -8,6 +10,7 @@ import { OpenSetting } from '../../utils/Permission/common';
8
10
  import { useTranslations } from '../Common/useTranslations';
9
11
  import { SCConfig } from '../../configs';
10
12
 
13
+ // These permissions are only for android 12
11
14
  const permissions = [
12
15
  'android.permission.BLUETOOTH_CONNECT',
13
16
  'android.permission.BLUETOOTH_SCAN',
@@ -24,11 +27,13 @@ const useBluetoothConnection = (fnCallback) => {
24
27
  const permissionsRequested = useSCContextSelector(
25
28
  (state) => state.bluetooth.permissionsRequested
26
29
  );
27
- const permissionsGranted =
28
- Platform.OS === 'ios'
30
+
31
+ const permissionsGranted = useMemo(() => {
32
+ return Platform.OS === 'ios' || parseInt(getSystemVersion(), 10) < 12
29
33
  ? true
30
34
  : // eslint-disable-next-line react-hooks/rules-of-hooks
31
35
  useSCContextSelector((state) => state.bluetooth.permissionsGranted);
36
+ }, []);
32
37
 
33
38
  const onDeviceFound = useCallback(async (name, device) => {
34
39
  fnCallback && fnCallback({ name, device });
@@ -38,9 +43,9 @@ const useBluetoothConnection = (fnCallback) => {
38
43
 
39
44
  const bluetoothScanDevices = useCallback(
40
45
  (addresses) => {
41
- permissionsGranted && scanBluetoothDevices(addresses, onDeviceFound);
46
+ scanBluetoothDevices(addresses, onDeviceFound);
42
47
  },
43
- [permissionsGranted, onDeviceFound]
48
+ [onDeviceFound]
44
49
  );
45
50
 
46
51
  useEffect(() => {
@@ -1,3 +1,4 @@
1
+ /* eslint-disable promise/prefer-await-to-callbacks */
1
2
  import { useCallback } from 'react';
2
3
  import { useSCContextSelector } from '../../context';
3
4
  import { sendCommandOverHomeAssistant } from '../../iot/RemoteControl/HomeAssistant';
@@ -10,6 +11,15 @@ import { ToastBottomHelper } from '../../utils/Utils';
10
11
  import { t } from 'i18n-js';
11
12
  import NetInfo from '@react-native-community/netinfo';
12
13
 
14
+ let count = 0;
15
+
16
+ const onRetry = (callback) => {
17
+ const to = setTimeout(() => {
18
+ callback;
19
+ clearTimeout(to);
20
+ }, 200);
21
+ };
22
+
13
23
  const useRemoteControl = () => {
14
24
  const homeAssistantConnections = useSCContextSelector(
15
25
  (state) => state.iot.homeassistant.connections
@@ -26,10 +36,23 @@ const useRemoteControl = () => {
26
36
  return result;
27
37
  }
28
38
 
29
- if (action.command_prefer_over_bluetooth) {
39
+ if (action.command_prefer_over_bluetooth && count < 5) {
40
+ count++;
30
41
  try {
31
- return await sendCommandOverBluetooth(device, action, data, userId);
42
+ const res = await sendCommandOverBluetooth(
43
+ device,
44
+ action,
45
+ data,
46
+ userId
47
+ );
48
+ if (res) {
49
+ count = 0;
50
+ return res;
51
+ } else {
52
+ onRetry(sendRemoteCommand(device, action, data, userId));
53
+ }
32
54
  } catch (err) {
55
+ onRetry(sendRemoteCommand(device, action, data, userId));
33
56
  const netState = await NetInfo.fetch();
34
57
  if (netState.isConnected) {
35
58
  result = false;
@@ -53,7 +76,7 @@ const useRemoteControl = () => {
53
76
  }
54
77
  }
55
78
  }
56
-
79
+ count = 0;
57
80
  // Checking only bluetooth: not other options
58
81
  if (action.is_only_bluetooth) {
59
82
  ToastBottomHelper.error(
@@ -1,14 +1,17 @@
1
1
  /* eslint-disable promise/prefer-await-to-callbacks */
2
- import { BLE } from '../../configs';
3
- import t from '../../hooks/Common/useTranslations';
4
2
  import base64 from 'react-native-base64';
5
- import { BleManager } from 'react-native-ble-plx';
3
+ import { BleManager, ScanMode } from 'react-native-ble-plx';
6
4
  import { ToastBottomHelper } from '../../utils/Utils';
7
5
 
6
+ import { BLE } from '../../configs';
7
+ import t from '../../hooks/Common/useTranslations';
8
+
8
9
  const bluetoothDevices = {};
9
10
  const needToScanDevices = [];
10
11
  const bleManager = new BleManager();
11
12
 
13
+ let isScanning = false;
14
+
12
15
  export const SEND_COMMAND_OVER_BLUETOOTH_FAIL =
13
16
  'SEND_COMMAND_OVER_BLUETOOTH_FAIL';
14
17
 
@@ -36,44 +39,52 @@ export const realScanBluetoothDevices = async (onDeviceFound) => {
36
39
  if (!needToScanDevices.length) {
37
40
  return;
38
41
  }
42
+ if (!isScanning) {
43
+ isScanning = true;
44
+ bleManager.startDeviceScan(
45
+ null,
46
+ { scanMode: ScanMode?.Balanced },
47
+ (error, device) => {
48
+ if (error) {
49
+ return;
50
+ }
39
51
 
40
- bleManager.startDeviceScan(null, null, (error, device) => {
41
- if (error) {
42
- return;
43
- }
44
-
45
- let name = null;
46
- if (
47
- needToScanDevices.includes(device.name) &&
48
- !bluetoothDevices[device.name]
49
- ) {
50
- name = device.name;
51
- } else if (
52
- needToScanDevices.includes(device.localName) &&
53
- !bluetoothDevices[device.localName]
54
- ) {
55
- name = device.localName;
56
- } else {
57
- return;
58
- }
52
+ let name = null;
53
+ if (
54
+ needToScanDevices.includes(device.name) &&
55
+ !bluetoothDevices[device.name]
56
+ ) {
57
+ name = device.name;
58
+ } else if (
59
+ needToScanDevices.includes(device.localName) &&
60
+ !bluetoothDevices[device.localName]
61
+ ) {
62
+ name = device.localName;
63
+ } else {
64
+ return;
65
+ }
59
66
 
60
- const index = needToScanDevices.indexOf(name);
61
- needToScanDevices.splice(index, 1);
67
+ const index = needToScanDevices.indexOf(name);
68
+ needToScanDevices.splice(index, 1);
62
69
 
63
- bluetoothDevices[name] = device;
64
- onDeviceFound && onDeviceFound(name, device);
70
+ bluetoothDevices[name] = device;
71
+ onDeviceFound && onDeviceFound(name, device);
65
72
 
66
- if (!needToScanDevices.length) {
67
- try {
68
- bleManager.stopDeviceScan();
69
- // eslint-disable-next-line no-empty
70
- } catch {}
71
- }
72
- });
73
+ if (!needToScanDevices.length) {
74
+ try {
75
+ bleManager.stopDeviceScan();
76
+ isScanning = false;
77
+ // eslint-disable-next-line no-empty
78
+ } catch {}
79
+ }
80
+ }
81
+ );
82
+ }
73
83
 
74
84
  const to = setTimeout(() => {
75
85
  try {
76
86
  bleManager.stopDeviceScan();
87
+ isScanning = false;
77
88
  clearTimeout(to);
78
89
  // eslint-disable-next-line no-empty
79
90
  } catch {}
@@ -156,8 +167,7 @@ export const sendDataOverBluetooth = async (
156
167
  t('control_device_via_bluetooth_successfully')
157
168
  );
158
169
  if (!keepConnect) {
159
- await bleManager.cancelTransaction(BLE.BLE_LISTER_RESPONSE_CONTROL);
160
- await bleManager.cancelDeviceConnection(device.id);
170
+ await connectedDevice.cancelConnection();
161
171
  }
162
172
  } else if (notify === BLE.BLE_RESPONSE_FAILED) {
163
173
  ToastBottomHelper.error(t('control_device_via_bluetooth_failed'));
@@ -172,6 +182,7 @@ export const sendDataOverBluetooth = async (
172
182
  );
173
183
  ToastBottomHelper.error(t('command_is_sent_to_device_via_bluetooth'));
174
184
  } catch (e) {
185
+ await connectedDevice.cancelConnection();
175
186
  ToastBottomHelper.error(t('command_is_fail_to_send_via_bluetooth'));
176
187
  throw SEND_COMMAND_OVER_BLUETOOTH_FAIL;
177
188
  }
@@ -4,7 +4,6 @@ import {
4
4
  scanBluetoothDevices,
5
5
  clearNeedToScanDevices,
6
6
  sendCommandOverBluetooth,
7
- SEND_COMMAND_OVER_BLUETOOTH_FAIL,
8
7
  clearFoundDevices,
9
8
  } from '../Bluetooth';
10
9
 
@@ -26,6 +25,36 @@ describe('Test IOT Bluetooth', () => {
26
25
  clearNeedToScanDevices();
27
26
  });
28
27
 
28
+ it('Send command over bluetooth via device success', async () => {
29
+ const device = {
30
+ name: '1234567',
31
+ cancelConnection: jest.fn(),
32
+ connect: async () => ({
33
+ discoverAllServicesAndCharacteristics: async () => ({
34
+ writeCharacteristicWithResponseForService: async () => ({}),
35
+ monitorCharacteristicForService: async () => ({}),
36
+ }),
37
+ }),
38
+ };
39
+ bleManager.startDeviceScan.mockImplementation(
40
+ (uuids, options, listener) => {
41
+ listener(null, device);
42
+ }
43
+ );
44
+ await scanBluetoothDevices([device.name], mockOnDeviceFound);
45
+
46
+ await sendCommandOverBluetooth(
47
+ {
48
+ remote_control_options: {
49
+ bluetooth: {
50
+ address: device.name,
51
+ },
52
+ },
53
+ },
54
+ {}
55
+ );
56
+ });
57
+
29
58
  test('Scan bluetooth device will init hardware scan', async () => {
30
59
  await scanBluetoothDevices(['123456'], mockOnDeviceFound);
31
60
  expect(bleManager.startDeviceScan).toBeCalled();
@@ -108,7 +137,7 @@ describe('Test IOT Bluetooth', () => {
108
137
  }
109
138
  );
110
139
  await scanBluetoothDevices([device.name], mockOnDeviceFound);
111
- expect(bleManager.stopDeviceScan).toBeCalled();
140
+ expect(bleManager.stopDeviceScan).not.toBeCalled();
112
141
  });
113
142
 
114
143
  it('Scan same device again will not trigger hardware scan', async () => {
@@ -121,7 +150,7 @@ describe('Test IOT Bluetooth', () => {
121
150
  }
122
151
  );
123
152
  await scanBluetoothDevices([device.name], mockOnDeviceFound);
124
- expect(bleManager.startDeviceScan).toBeCalled();
153
+ expect(bleManager.startDeviceScan).not.toBeCalled();
125
154
 
126
155
  bleManager.startDeviceScan.mockClear();
127
156
 
@@ -129,14 +158,12 @@ describe('Test IOT Bluetooth', () => {
129
158
  expect(bleManager.startDeviceScan).not.toBeCalled();
130
159
  });
131
160
 
132
- const sendCommandBluetoothFail = async (sensor) => {
133
- let error = null;
161
+ const sendCommandBluetoothFail = async (sensor, err = undefined) => {
134
162
  try {
135
163
  await sendCommandOverBluetooth(sensor, {});
136
164
  } catch (e) {
137
- error = e;
165
+ expect(e.message).toBe(err);
138
166
  }
139
- expect(error).toEqual(SEND_COMMAND_OVER_BLUETOOTH_FAIL);
140
167
  };
141
168
 
142
169
  it('Send command over bluetooth do nothing for sensor has no bluetooth', async () => {
@@ -164,34 +191,7 @@ describe('Test IOT Bluetooth', () => {
164
191
  );
165
192
  await scanBluetoothDevices([device.name], mockOnDeviceFound);
166
193
 
167
- await sendCommandBluetoothFail({
168
- remote_control_options: {
169
- bluetooth: {
170
- address: device.name,
171
- },
172
- },
173
- });
174
- });
175
-
176
- it('Send command over bluetooth via device success', async () => {
177
- const device = {
178
- name: '1234567',
179
- cancelConnection: jest.fn(),
180
- connect: async () => ({
181
- discoverAllServicesAndCharacteristics: async () => ({
182
- writeCharacteristicWithResponseForService: async () => ({}),
183
- monitorCharacteristicForService: async () => ({}),
184
- }),
185
- }),
186
- };
187
- bleManager.startDeviceScan.mockImplementation(
188
- (uuids, options, listener) => {
189
- listener(null, device);
190
- }
191
- );
192
- await scanBluetoothDevices([device.name], mockOnDeviceFound);
193
-
194
- await sendCommandOverBluetooth(
194
+ await sendCommandBluetoothFail(
195
195
  {
196
196
  remote_control_options: {
197
197
  bluetooth: {
@@ -199,7 +199,7 @@ describe('Test IOT Bluetooth', () => {
199
199
  },
200
200
  },
201
201
  },
202
- {}
202
+ undefined
203
203
  );
204
204
  });
205
205
  });
@@ -26,7 +26,7 @@ const SelectDeviceSubUnit = ({ route }) => {
26
26
  });
27
27
  break;
28
28
  case DEVICE_TYPE.ZIGBEE:
29
- navigation.navigate(Routes.ConnectRouterGuide, {
29
+ navigation.navigate(Routes.SelectZigbeeGateway, {
30
30
  unit,
31
31
  subUnit: chosenSubUnit,
32
32
  });
@@ -142,6 +142,16 @@ describe('test DeviceDetail', () => {
142
142
 
143
143
  let data_sensor_display = {
144
144
  items: [
145
+ {
146
+ configuration: {
147
+ id: 3,
148
+ name: 'Emergency',
149
+ },
150
+ id: 17,
151
+ order: 1,
152
+ template: 'emergency',
153
+ type: 'emergency',
154
+ },
145
155
  {
146
156
  configuration: {
147
157
  id: 2,
@@ -247,7 +257,7 @@ describe('test DeviceDetail', () => {
247
257
  (el) =>
248
258
  el.props.accessibilityLabel === AccessibilityLabel.SENSOR_DISPLAY_ITEM
249
259
  );
250
- expect(sensorDisplayItem.length).toEqual(2);
260
+ expect(sensorDisplayItem.length).toEqual(3);
251
261
 
252
262
  const itemActionGroup = instance.find(
253
263
  (el) =>
@@ -485,6 +495,16 @@ describe('test DeviceDetail', () => {
485
495
  ],
486
496
  },
487
497
  },
498
+ {
499
+ configuration: {
500
+ id: 3,
501
+ name: 'Emergency',
502
+ },
503
+ id: 17,
504
+ order: 1,
505
+ template: 'emergency',
506
+ type: 'emergency',
507
+ },
488
508
  ],
489
509
  },
490
510
  };
@@ -509,7 +529,7 @@ describe('test DeviceDetail', () => {
509
529
  (el) =>
510
530
  el.props.accessibilityLabel === AccessibilityLabel.SENSOR_DISPLAY_ITEM
511
531
  );
512
- expect(sensorDisplayItem).toHaveLength(4);
532
+ expect(sensorDisplayItem).toHaveLength(5);
513
533
  });
514
534
 
515
535
  it('render SensorDisplayItem emercency', async () => {
@@ -757,7 +777,7 @@ describe('test DeviceDetail', () => {
757
777
 
758
778
  it('Open popup ble when server down', async () => {
759
779
  store.bluetooth.isEnabled = false;
760
- data_sensor_display.items[1].configuration.configuration.action1_data.command_prefer_over_bluetooth = true;
780
+ data_sensor_display.items[2].configuration.configuration.action1_data.command_prefer_over_bluetooth = true;
761
781
  const responseDisplay = {
762
782
  status: 200,
763
783
  data: data_sensor_display,
@@ -781,4 +801,19 @@ describe('test DeviceDetail', () => {
781
801
  });
782
802
  expect(mockAlertShow).not.toBeCalled();
783
803
  });
804
+
805
+ it('Test fetchUnitDetail', async () => {
806
+ const unitId = 1;
807
+ mock.onGet(API.UNIT.UNIT_DETAIL(unitId)).reply(200);
808
+ await act(async () => {
809
+ await create(
810
+ wrapComponent(store, account, {
811
+ ...route,
812
+ params: { ...route.params, unitData: null, unitId },
813
+ })
814
+ );
815
+ });
816
+ const urls = mock.history.get.map((item) => item.url);
817
+ expect(urls).toContain(API.UNIT.UNIT_DETAIL(unitId));
818
+ });
784
819
  });
@@ -771,7 +771,7 @@
771
771
  "please_add_your_phone_number_and_chip_name": "Please add your phone number and chip name",
772
772
  "Please_add_gateway_name" : "Please add gateway name",
773
773
  "phone_number_of_data_sim": "Phone number of data sim",
774
- "select_a_sub_unit": "Select a sub-unit that you want to add this gateway",
774
+ "select_a_sub_unit": "Select a sub-unit",
775
775
  "all_camera": "All Cameras",
776
776
  "gateway_name": "Gateway name",
777
777
  "activated_time": "Activated {time}",
@@ -781,7 +781,7 @@
781
781
  "please_add_your_phone_number_and_chip_name": "Vui lòng thêm số điện thoại và tên chip của bạn",
782
782
  "Please_add_gateway_name" : "Vui lòng thêm tên gateway",
783
783
  "phone_number_of_data_sim": "Số điện thoại của dữ liệu sim",
784
- "select_a_sub_unit": "Lựa chọn một khu vực mà bạn muốn thêm gateway",
784
+ "select_a_sub_unit": "Lựa chọn một khu vực",
785
785
  "all_camera": "All Cameras",
786
786
  "gateway_name": "Tên Gateway",
787
787
  "activated_time": "Đã kích hoạt {time}",