@eohjsc/react-native-smart-city 0.7.24 → 0.7.25

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/src/iot/mqtt.js CHANGED
@@ -1,8 +1,11 @@
1
1
  import moment from 'moment';
2
+ import { getObject, storeObject } from '../utils/Storage';
2
3
  import { updateGlobalValue } from './Monitor';
3
4
  import { Buffer } from 'buffer';
4
5
 
5
- const int_all = (bytes_str, config_data = null) => {
6
+ const struct = require('python-struct');
7
+
8
+ const int_all = (bytes_str) => {
6
9
  let val;
7
10
  val = Number.parseInt(bytes_str, 16);
8
11
 
@@ -13,44 +16,75 @@ const int_all = (bytes_str, config_data = null) => {
13
16
  return val;
14
17
  };
15
18
 
16
- const int_first4 = (bytes_str, config_data = null) => {
17
- return Number.parseInt(bytes_str.slice(0, 4), 16);
19
+ const int_first4 = (bytes_str) => {
20
+ return Number.parseInt(bytes_str?.slice(0, 4), 16);
18
21
  };
19
22
 
20
- const int_last4 = (bytes_str, config_data = null) => {
21
- return Number.parseInt(bytes_str.slice(4), 16);
23
+ const int_last4 = (bytes_str) => {
24
+ return Number.parseInt(bytes_str?.slice(4), 16);
22
25
  };
23
26
 
24
- const uint_32 = (bytes_str, config_data = null) => {
25
- let bits = 32;
26
- let value = Number.parseInt(bytes_str, 16);
27
-
28
- // eslint-disable-next-line no-bitwise
29
- if (value & (1 << (bits - 1))) {
30
- // eslint-disable-next-line no-bitwise
31
- value -= 1 << bits;
32
- }
33
-
34
- return value;
35
- };
36
-
37
- const float_convert = (bytes_str) => {
38
- const struct = require('python-struct');
27
+ const value_unpacked = (format, bytes_str) => {
39
28
  let value = null;
40
29
  try {
41
- value = struct.unpack('>f', Buffer.from(bytes_str, 'hex'))[0];
30
+ value = struct.unpack(format, Buffer.from(bytes_str, 'hex'))[0];
42
31
  // eslint-disable-next-line no-empty
43
32
  } catch {}
44
33
  return value;
45
34
  };
46
35
 
47
- const float_cdba = (bytes_str, config_data = null) => {
48
- const bytes_cdba = bytes_str?.slice(4) + bytes_str?.slice(0, 4);
49
- return float_convert(bytes_cdba);
36
+ const uint_32_abcd = (bytes_str) => {
37
+ return value_unpacked('>I', bytes_str?.slice(0, 8));
38
+ };
39
+
40
+ const uint_32_dcba = (bytes_str) => {
41
+ return value_unpacked('<I', bytes_str?.slice(0, 8));
42
+ };
43
+
44
+ const uint_32_badc = (bytes_str) => {
45
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
46
+ return value_unpacked('<I', swapped);
47
+ };
48
+
49
+ const uint_32_cdab = (bytes_str) => {
50
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
51
+ return value_unpacked('>I', swapped);
52
+ };
53
+
54
+ const int_32_abcd = (bytes_str) => {
55
+ return value_unpacked('>i', bytes_str?.slice(0, 8));
56
+ };
57
+
58
+ const int_32_dcba = (bytes_str) => {
59
+ return value_unpacked('<i', bytes_str?.slice(0, 8));
50
60
  };
51
61
 
52
- const float_abcd = (bytes_str, config_data = null) => {
53
- return float_convert(bytes_str);
62
+ const int_32_badc = (bytes_str) => {
63
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
64
+ return value_unpacked('<i', swapped);
65
+ };
66
+
67
+ const int_32_cdab = (bytes_str) => {
68
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
69
+ return value_unpacked('>i', swapped);
70
+ };
71
+
72
+ const float_abcd = (bytes_str) => {
73
+ return value_unpacked('>f', bytes_str?.slice(0, 8));
74
+ };
75
+
76
+ const float_dcba = (bytes_str) => {
77
+ return value_unpacked('<f', bytes_str?.slice(0, 8));
78
+ };
79
+
80
+ const float_badc = (bytes_str) => {
81
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
82
+ return value_unpacked('<f', swapped);
83
+ };
84
+
85
+ const float_cdab = (bytes_str) => {
86
+ const swapped = bytes_str?.slice(4, 8) + bytes_str?.slice(0, 4);
87
+ return value_unpacked('>f', swapped);
54
88
  };
55
89
 
56
90
  const range_value_converting = (
@@ -84,12 +118,21 @@ const convert_ai = (bytes_str, config_data = null) => {
84
118
 
85
119
  const mappingTransformer = {
86
120
  int_all: int_all,
87
- int_first4: int_first4,
88
- int_last4: int_last4,
89
- uint_32: uint_32,
90
- float_cdba: float_cdba,
91
121
  float_abcd: float_abcd,
122
+ float_dcba: float_dcba,
123
+ float_badc: float_badc,
124
+ float_cdab: float_cdab,
125
+ uint_32_abcd: uint_32_abcd,
126
+ uint_32_dcba: uint_32_dcba,
127
+ uint_32_badc: uint_32_badc,
128
+ uint_32_cdab: uint_32_cdab,
129
+ int_32_abcd: int_32_abcd,
130
+ int_32_dcba: int_32_dcba,
131
+ int_32_badc: int_32_badc,
132
+ int_32_cdab: int_32_cdab,
92
133
  convert_ai: convert_ai,
134
+ int_first4: int_first4,
135
+ int_last4: int_last4,
93
136
  };
94
137
 
95
138
  const extract_config_value = (register, value_bytes) => {
@@ -135,19 +178,56 @@ const get_sensor_data = (sensor, data) => {
135
178
  };
136
179
 
137
180
  const get_scale_value = (value, config) => {
138
- if (!value || typeof value === 'string') {
181
+ if (!value) {
139
182
  return value;
140
183
  }
141
- const { decimal_behind, scale } = config;
142
- let scaledValue = value * (scale || 1);
184
+ const scale = config?.scale || 1;
185
+ return value * scale;
186
+ };
187
+
188
+ const get_decimal_value = (value, config) => {
189
+ if (config?.decimal_behind || config?.decimal_behind === 0) {
190
+ value = value.toFixed(config.decimal_behind);
191
+ }
192
+ return value;
193
+ };
143
194
 
144
- if (decimal_behind || decimal_behind === 0) {
145
- scaledValue = scaledValue.toFixed(decimal_behind);
195
+ const get_offset_sample_value = async (value, config) => {
196
+ const offset = parseFloat(config?.ai_trans_offset_value) || 0;
197
+ const sample = config?.ai_trans_average_sample || 1;
198
+ value += offset;
199
+ if (sample <= 1) {
200
+ return Number(get_decimal_value(value, config));
146
201
  }
147
- return Number(scaledValue);
202
+
203
+ const cacheKey = `last_values_${config?.id}`;
204
+ let values = await getObject(cacheKey, []);
205
+
206
+ values = [value, ...values];
207
+ values = values.slice(0, sample);
208
+
209
+ value = values.reduce((a, b) => a + b) / values.length;
210
+ value = Number(get_decimal_value(value, config));
211
+
212
+ values[0] = value;
213
+ await storeObject(cacheKey, values);
214
+ return value;
148
215
  };
149
216
 
150
- const updateGlobalValueMqtt = (config, value) => {
217
+ const check_filter = (value, config) => {
218
+ if (!config?.active_filter) {
219
+ return false;
220
+ }
221
+ if (config?.active_filter === 'zero') {
222
+ return !value;
223
+ }
224
+
225
+ const low = config?.low_level || 0;
226
+ const high = config?.high_level || 0;
227
+ return value < low || value > high;
228
+ };
229
+
230
+ const updateGlobalValueMqtt = async (config, value) => {
151
231
  if (!config?.id) {
152
232
  return;
153
233
  }
@@ -155,13 +235,20 @@ const updateGlobalValueMqtt = (config, value) => {
155
235
  return;
156
236
  }
157
237
 
158
- value = get_scale_value(value, config);
159
- updateGlobalValue(config.id, { value: value });
160
- };
238
+ const last_updated = moment().format('YYYY-MM-DDTHH:mm:ss.SSSSSS');
239
+ if (typeof value === 'string') {
240
+ updateGlobalValue(config.id, { value, last_updated });
241
+ return;
242
+ }
161
243
 
162
- const arduinoUpdateGlobalValueMqtt = (config, value, last_updated) => {
163
244
  value = get_scale_value(value, config);
164
- updateGlobalValue(config.id, { value: value, last_updated: last_updated });
245
+ value = await get_offset_sample_value(value, config);
246
+
247
+ if (check_filter(value, config)) {
248
+ return;
249
+ }
250
+
251
+ updateGlobalValue(config.id, { value, last_updated });
165
252
  };
166
253
 
167
254
  export const handleModbusData = (chip, configById, data) => {
@@ -188,11 +275,7 @@ export const handleModbusData = (chip, configById, data) => {
188
275
  };
189
276
 
190
277
  export const handleChipData = (configById, configId, data) => {
191
- arduinoUpdateGlobalValueMqtt(
192
- configById[configId],
193
- data?.v,
194
- moment().format('YYYY-MM-DDTHH:mm:ss.SSSSSS')
195
- );
278
+ updateGlobalValueMqtt(configById[configId], data?.v);
196
279
  };
197
280
 
198
281
  export const handleZigbeeData = (chip, configById, ieee_address, data) => {
@@ -217,6 +300,26 @@ export const handleZigbeeData = (chip, configById, ieee_address, data) => {
217
300
  }
218
301
  };
219
302
 
303
+ export const handleThirdPartyData = (chip, configById, device_uid, data) => {
304
+ const third_party_gateway = chip?.third_party_gateway;
305
+ if (!third_party_gateway) {
306
+ return;
307
+ }
308
+
309
+ const third_party_device_by_uid = {};
310
+
311
+ third_party_gateway?.sensors?.forEach((device) => {
312
+ third_party_device_by_uid[device.device_uid] = device;
313
+ });
314
+
315
+ const device = third_party_device_by_uid[device_uid];
316
+ device?.configs?.forEach((config_map) => {
317
+ const value = data[config_map?.key];
318
+ const configId = config_map?.config;
319
+ updateGlobalValueMqtt(configById[configId], value);
320
+ });
321
+ };
322
+
220
323
  export const handleMqttMessage = (
221
324
  topic,
222
325
  payloadData,
@@ -246,4 +349,17 @@ export const handleMqttMessage = (
246
349
  // payload: {zigbee_data: 'aaa', 'data': {state: 1, state_0: 0}}
247
350
  handleZigbeeData(chip, configById, matchZigbeeConfigValue[1], payloadData);
248
351
  }
352
+
353
+ const matchThirdPartyConfigValue = topic.match(/third_party\/(.+)\/data/);
354
+ if (matchThirdPartyConfigValue) {
355
+ // ThirdParty
356
+ // topic: eoh/chip/code-123/third_party/UID-123/data
357
+ // payload: {state: 1, temperature: 27.6}
358
+ handleThirdPartyData(
359
+ chip,
360
+ configById,
361
+ matchThirdPartyConfigValue[1],
362
+ payloadData
363
+ );
364
+ }
249
365
  };
@@ -124,6 +124,19 @@ export const UnitStack = memo((props) => {
124
124
  }, [isBluetoothEnabled, bluetoothPermGranted, onDeviceFound]);
125
125
 
126
126
  useEffect(() => {
127
+ const fetchDashboardDevices = async () => {
128
+ const id = unitId || unitData?.id;
129
+ if (!id) {
130
+ return;
131
+ }
132
+ await fetchWithCache(
133
+ API.UNIT.DASHBOARD_DEVICES(id),
134
+ {},
135
+ ({ success, data }) => {
136
+ success && setAction(Action.SET_DASHBOARD_DEVICES, data);
137
+ }
138
+ );
139
+ };
127
140
  const fetchFavoriteDevices = async () => {
128
141
  const id = unitId || unitData?.id;
129
142
  if (!id) {
@@ -137,6 +150,7 @@ export const UnitStack = memo((props) => {
137
150
  }
138
151
  );
139
152
  };
153
+ fetchDashboardDevices();
140
154
  fetchFavoriteDevices();
141
155
  // eslint-disable-next-line react-hooks/exhaustive-deps
142
156
  }, []);
@@ -661,6 +661,47 @@ describe('test DeviceDetail', () => {
661
661
  expect(menu.props.isVisible).toBe(true);
662
662
  });
663
663
 
664
+ it('Add device to Dashboard', async () => {
665
+ const sensor = route?.params?.sensorData;
666
+ mock.onPost(API.DEVICE.ADD_TO_DASHBOARD(sensor.id)).reply(200);
667
+
668
+ await act(async () => {
669
+ tree = await create(wrapComponent(store, account, route));
670
+ });
671
+ const instance = tree.root;
672
+ const buttonPin = instance.find(
673
+ (el) =>
674
+ el.props.accessibilityLabel ===
675
+ AccessibilityLabel.HEADER_DEVICE_BUTTON_PIN
676
+ );
677
+ await act(async () => {
678
+ await buttonPin.props.onPress();
679
+ });
680
+ const urls = mock.history.post.map(({ url }) => url);
681
+ expect(urls).toContain(API.DEVICE.ADD_TO_DASHBOARD(sensor.id));
682
+ });
683
+
684
+ it('Remove device from Dashboard', async () => {
685
+ const sensor = route?.params?.sensorData;
686
+ store.unit.dashboardDeviceIds = [sensor.id];
687
+ mock.onPost(API.DEVICE.REMOVE_FROM_DASHBOARD(sensor.id)).reply(200);
688
+
689
+ await act(async () => {
690
+ tree = await create(wrapComponent(store, account, route));
691
+ });
692
+ const instance = tree.root;
693
+ const buttonPin = instance.find(
694
+ (el) =>
695
+ el.props.accessibilityLabel ===
696
+ AccessibilityLabel.HEADER_DEVICE_BUTTON_PIN
697
+ );
698
+ await act(async () => {
699
+ await buttonPin.props.onPress();
700
+ });
701
+ const urls = mock.history.post.map(({ url }) => url);
702
+ expect(urls).toContain(API.DEVICE.REMOVE_FROM_DASHBOARD(sensor.id));
703
+ });
704
+
664
705
  it('Add device to Favourites', async () => {
665
706
  const sensor = route?.params?.sensorData;
666
707
  sensor.is_favourite = false;
@@ -733,7 +774,7 @@ describe('test DeviceDetail', () => {
733
774
  });
734
775
  const instance = tree.root;
735
776
  const menu = instance.findByType(MenuActionMore);
736
- const gotoActivityLog = menu.props.listMenuItem[1];
777
+ const gotoActivityLog = menu.props.listMenuItem[2];
737
778
 
738
779
  await act(async () => {
739
780
  await menu.props.onItemClick(gotoActivityLog);