@eohjsc/react-native-smart-city 0.3.60 → 0.3.61

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.60",
4
+ "version": "0.3.61",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -14,6 +14,7 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
14
14
  const [isOn, setIsOn] = useState(false);
15
15
 
16
16
  const sendRemoteCommand = useRemoteControl();
17
+ const [processing, setProcessing] = useState(false);
17
18
 
18
19
  useEffect(() => {
19
20
  if (!(sensor.quick_action?.config_id in configValues)) {
@@ -38,7 +39,11 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
38
39
  }, [isOn, setStatus, sensor.quick_action]);
39
40
 
40
41
  const userId = useSCContextSelector((state) => state?.auth.account.user.id);
41
- const onActionPress = useCallback(() => {
42
+ const onActionPress = useCallback(async () => {
43
+ if (processing) {
44
+ return;
45
+ }
46
+ setProcessing(true);
42
47
  let data = null;
43
48
  if (
44
49
  action?.allow_config_store_value_id === sensor?.quick_action?.config_id
@@ -56,7 +61,7 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
56
61
  }
57
62
  data = JSON.stringify(data);
58
63
  }
59
- sendRemoteCommand(sensor, action, data, userId);
64
+ await sendRemoteCommand(sensor, action, data, userId);
60
65
  setIsSendingCommand(true);
61
66
 
62
67
  if (!sensor.quick_action.will_auto_update_status) {
@@ -64,7 +69,8 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
64
69
  setIsOn(action.id === sensor.quick_action.on_action.id);
65
70
  }, sensor.quick_action.interval);
66
71
  }
67
- }, [sensor, action, userId, sendRemoteCommand]);
72
+ setProcessing(false);
73
+ }, [processing, action, sensor, sendRemoteCommand, userId]);
68
74
 
69
75
  if (!action) {
70
76
  return <View />;
@@ -9,6 +9,7 @@ import { sendCommandOverHomeAssistant } from '../../../iot/RemoteControl/HomeAss
9
9
  import { sendCommandOverInternet } from '../../../iot/RemoteControl/Internet';
10
10
  import { SCProvider } from '../../../context';
11
11
  import { mockSCStore } from '../../../context/mockStore';
12
+ import { ToastBottomHelper } from '../../../utils/Utils';
12
13
 
13
14
  jest.mock('../../../iot/RemoteControl/Bluetooth');
14
15
  jest.mock('../../../iot/RemoteControl/HomeAssistant');
@@ -112,6 +113,47 @@ describe('Test useRemoteControl', () => {
112
113
  expect(sendCommandOverHomeAssistant).not.toBeCalled();
113
114
  });
114
115
 
116
+ const testCommandViaBluetooth = async (
117
+ command_prefer_over_bluetooth,
118
+ command_prefer_over_internet
119
+ ) => {
120
+ action.command_prefer_over_bluetooth = command_prefer_over_bluetooth;
121
+ action.command_prefer_over_internet = command_prefer_over_internet;
122
+ action.is_only_bluetooth = true;
123
+ const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
124
+
125
+ const { result: sendRemoteCommand } = renderHook(() => useRemoteControl(), {
126
+ wrapper,
127
+ });
128
+
129
+ sendCommandOverBluetooth.mockImplementation(() => {
130
+ throw SEND_COMMAND_OVER_BLUETOOTH_FAIL;
131
+ });
132
+ sendCommandOverInternet.mockImplementation(async () => true);
133
+ await act(async () => {
134
+ await sendRemoteCommand.current(sensor, action, data, userId);
135
+ });
136
+ expect(sendCommandOverBluetooth).toBeCalledWith(
137
+ sensor,
138
+ action,
139
+ data,
140
+ userId
141
+ );
142
+ expect(sendCommandOverInternet).not.toBeCalled();
143
+ expect(sendCommandOverHomeAssistant).not.toBeCalled();
144
+ expect(spyToastError).toBeCalled();
145
+ };
146
+
147
+ // eslint-disable-next-line max-len
148
+ it('test send remote command via bluetooth failed then not send via internet, action is only bluetooth, not prefer internet', async () => {
149
+ testCommandViaBluetooth(true, false);
150
+ });
151
+
152
+ // eslint-disable-next-line max-len
153
+ it('test send remote command via bluetooth failed then not send via internet, action is only bluetooth, prefer internet', async () => {
154
+ testCommandViaBluetooth(false, true);
155
+ });
156
+
115
157
  it('test send remote command via bluetooth failed throw unhandled error', async () => {
116
158
  const { result: sendRemoteCommand } = renderHook(() => useRemoteControl(), {
117
159
  wrapper,
@@ -8,6 +8,7 @@ import {
8
8
  } from '../../iot/RemoteControl/Bluetooth';
9
9
  import { ToastBottomHelper } from '../../utils/Utils';
10
10
  import { t } from 'i18n-js';
11
+ import NetInfo from '@react-native-community/netinfo';
11
12
 
12
13
  const useRemoteControl = () => {
13
14
  const homeAssistantConnections = useSCContextSelector(
@@ -29,20 +30,38 @@ const useRemoteControl = () => {
29
30
  try {
30
31
  return await sendCommandOverBluetooth(device, action, data, userId);
31
32
  } catch (err) {
32
- if (err === SEND_COMMAND_OVER_BLUETOOTH_FAIL) {
33
- result = await sendCommandOverInternet(
34
- device,
35
- action,
36
- data,
37
- 'bluetooth'
38
- );
39
- return result;
33
+ const netState = await NetInfo.fetch();
34
+ if (netState.isConnected) {
35
+ result = false;
36
+
37
+ if (err === SEND_COMMAND_OVER_BLUETOOTH_FAIL) {
38
+ // Checking only bluetooth: not force internet
39
+ if (!action.is_only_bluetooth) {
40
+ result = await sendCommandOverInternet(
41
+ device,
42
+ action,
43
+ data,
44
+ 'bluetooth'
45
+ );
46
+ }
47
+ return result;
48
+ } else {
49
+ throw err;
50
+ }
40
51
  } else {
41
- throw err;
52
+ return false;
42
53
  }
43
54
  }
44
55
  }
45
56
 
57
+ // Checking only bluetooth: not other options
58
+ if (action.is_only_bluetooth) {
59
+ ToastBottomHelper.error(
60
+ t('this_command_is_just_support_bluetooth_only')
61
+ );
62
+ return result;
63
+ }
64
+
46
65
  if (action.command_prefer_over_internet) {
47
66
  return await sendCommandOverInternet(
48
67
  device,
@@ -140,7 +140,7 @@ export const sendDataOverBluetooth = async (
140
140
  let connectedDevice = null;
141
141
  let fullDataDevice = null;
142
142
  let result = true;
143
- const responseTime = 2000;
143
+
144
144
  try {
145
145
  connectedDevice = await device.connect();
146
146
  fullDataDevice =
@@ -148,15 +148,15 @@ export const sendDataOverBluetooth = async (
148
148
  await fullDataDevice.monitorCharacteristicForService(
149
149
  BLE.BLE_REMOTE_SERVICE_UUID,
150
150
  BLE.BLE_REMOTE_CHARACTERISTIC_UUID_TX,
151
- (error, characteristic) => {
151
+ async (error, characteristic) => {
152
152
  const notify = error ? '' : base64.decode(characteristic.value);
153
153
  if (notify === BLE.BLE_RESPONSE_OK) {
154
154
  ToastBottomHelper.success(
155
155
  t('control_device_via_bluetooth_successfully')
156
156
  );
157
157
  if (!keepConnect) {
158
- bleManager.cancelTransaction(BLE.BLE_LISTER_RESPONSE_CONTROL);
159
- device.cancelConnection();
158
+ await bleManager.cancelTransaction(BLE.BLE_LISTER_RESPONSE_CONTROL);
159
+ await bleManager.cancelDeviceConnection(device.id);
160
160
  }
161
161
  } else if (notify === BLE.BLE_RESPONSE_FAILED) {
162
162
  ToastBottomHelper.error(t('control_device_via_bluetooth_failed'));
@@ -179,10 +179,6 @@ export const sendDataOverBluetooth = async (
179
179
  return result;
180
180
  }
181
181
 
182
- const timeout = setTimeout(() => {
183
- device.cancelConnection();
184
- clearTimeout(timeout);
185
- }, responseTime);
186
182
  return result;
187
183
  };
188
184
 
@@ -1,4 +1,4 @@
1
- import React, { useCallback } from 'react';
1
+ import React, { useCallback, useState } from 'react';
2
2
  import { View } from 'react-native';
3
3
  import ActionGroup from '../../../commons/ActionGroup';
4
4
  import { CardDevMode } from '../../../commons/DevMode';
@@ -46,17 +46,23 @@ export const SensorDisplayItem = ({
46
46
  const { isEditingTemplate } = useSCContextSelector((state) => state.devMode);
47
47
 
48
48
  const sendRemoteCommand = useRemoteControl();
49
+ const [processing, setProcessing] = useState(false);
49
50
 
50
51
  const doAction = useCallback(
51
- (action, data) => {
52
- sendRemoteCommand(
52
+ async (action, data) => {
53
+ if (processing) {
54
+ return;
55
+ }
56
+ setProcessing(true);
57
+ await sendRemoteCommand(
53
58
  isEditingTemplate ? action?.end_device : sensor,
54
59
  action,
55
60
  data,
56
61
  userId
57
62
  );
63
+ setProcessing(false);
58
64
  },
59
- [isEditingTemplate, sensor, sendRemoteCommand, userId]
65
+ [processing, sendRemoteCommand, isEditingTemplate, sensor, userId]
60
66
  );
61
67
 
62
68
  if (type === 'compass') {
@@ -1106,5 +1106,6 @@
1106
1106
  "text_alert_modal_popup_ct": "It’s a critical action and cannot be undone.",
1107
1107
  "text_understand_modal_popup_ct": "I fully understand that this action is critical and will lead to data loss.",
1108
1108
  "cannot_find_device_wifi": "Cannot find Device's Wifi",
1109
+ "this_command_is_just_support_bluetooth_only": "This command is just support bluetooth only",
1109
1110
  "photo_request_permission_des": "To select photo from gallery, please unlock access photo permission"
1110
1111
  }
@@ -1105,5 +1105,6 @@
1105
1105
  "text_working_hard": "Chúng tôi đang làm việc chăm chỉ để làm cho điều này hoạt động",
1106
1106
  "photo_request_permission": "Quyền yêu cầu ảnh",
1107
1107
  "cannot_find_device_wifi": "Không thể tìm thấy Wifi của thiết bị",
1108
+ "this_command_is_just_support_bluetooth_only": "Lệnh gửi này chỉ hỗ trợ bluetooth",
1108
1109
  "photo_request_permission_des": "Để chọn ảnh từ thư viện, vui lòng mở khóa quyền truy cập ảnh"
1109
1110
  }