wiliot-certificate 1.3.0a1__py3-none-any.whl → 1.4.0a2__py3-none-any.whl

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.
Files changed (184) hide show
  1. brg_certificate/__init__.py +0 -0
  2. brg_certificate/ag/energous_v0_defines.py +925 -0
  3. brg_certificate/ag/energous_v1_defines.py +931 -0
  4. brg_certificate/ag/energous_v2_defines.py +925 -0
  5. brg_certificate/ag/energous_v3_defines.py +925 -0
  6. brg_certificate/ag/energous_v4_defines.py +925 -0
  7. brg_certificate/ag/fanstel_lan_v0_defines.py +925 -0
  8. brg_certificate/ag/fanstel_lte_v0_defines.py +925 -0
  9. brg_certificate/ag/fanstel_wifi_v0_defines.py +925 -0
  10. brg_certificate/ag/minew_lte_v0_defines.py +925 -0
  11. brg_certificate/ag/wlt_cmd_if.html +102 -0
  12. brg_certificate/ag/wlt_types.html +6114 -0
  13. brg_certificate/ag/wlt_types_ag.py +7840 -0
  14. brg_certificate/ag/wlt_types_ag_jsons/brg2brg_ota.json +142 -0
  15. brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb.json +785 -0
  16. brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb_sleep.json +139 -0
  17. brg_certificate/ag/wlt_types_ag_jsons/calibration.json +394 -0
  18. brg_certificate/ag/wlt_types_ag_jsons/custom.json +515 -0
  19. brg_certificate/ag/wlt_types_ag_jsons/datapath.json +672 -0
  20. brg_certificate/ag/wlt_types_ag_jsons/energy2400.json +550 -0
  21. brg_certificate/ag/wlt_types_ag_jsons/energySub1g.json +595 -0
  22. brg_certificate/ag/wlt_types_ag_jsons/externalSensor.json +598 -0
  23. brg_certificate/ag/wlt_types_ag_jsons/interface.json +938 -0
  24. brg_certificate/ag/wlt_types_ag_jsons/powerManagement.json +1234 -0
  25. brg_certificate/ag/wlt_types_ag_jsons/side_info_sensor.json +105 -0
  26. brg_certificate/ag/wlt_types_ag_jsons/signal_indicator_data.json +77 -0
  27. brg_certificate/ag/wlt_types_ag_jsons/unified_echo_ext_pkt.json +61 -0
  28. brg_certificate/ag/wlt_types_ag_jsons/unified_echo_pkt.json +110 -0
  29. brg_certificate/brg_certificate.py +191 -0
  30. brg_certificate/brg_certificate_cli.py +47 -0
  31. brg_certificate/cert_common.py +828 -0
  32. brg_certificate/cert_config.py +395 -0
  33. brg_certificate/cert_data_sim.py +188 -0
  34. brg_certificate/cert_defines.py +337 -0
  35. brg_certificate/cert_gw_sim.py +285 -0
  36. brg_certificate/cert_mqtt.py +373 -0
  37. brg_certificate/cert_prints.py +181 -0
  38. brg_certificate/cert_protobuf.py +88 -0
  39. brg_certificate/cert_results.py +300 -0
  40. brg_certificate/cert_utils.py +358 -0
  41. brg_certificate/certificate_sanity_test_list.txt +36 -0
  42. brg_certificate/certificate_test_list.txt +43 -0
  43. brg_certificate/config/eclipse.json +10 -0
  44. brg_certificate/config/hivemq.json +10 -0
  45. brg_certificate/config/mosquitto.json +10 -0
  46. brg_certificate/config/mosquitto.md +95 -0
  47. brg_certificate/config/wiliot-dev.json +10 -0
  48. brg_certificate/restore_brg.py +59 -0
  49. brg_certificate/tests/calibration/interval_test/interval_test.json +13 -0
  50. brg_certificate/tests/calibration/interval_test/interval_test.py +28 -0
  51. brg_certificate/tests/calibration/output_power_test/output_power_test.json +13 -0
  52. brg_certificate/tests/calibration/output_power_test/output_power_test.py +28 -0
  53. brg_certificate/tests/calibration/pattern_test/pattern_test.json +13 -0
  54. brg_certificate/tests/calibration/pattern_test/pattern_test.py +70 -0
  55. brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.json +13 -0
  56. brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.py +76 -0
  57. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.json +13 -0
  58. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.py +83 -0
  59. brg_certificate/tests/datapath/output_power_test/output_power_test.json +13 -0
  60. brg_certificate/tests/datapath/output_power_test/output_power_test.py +27 -0
  61. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +13 -0
  62. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +43 -0
  63. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.json +13 -0
  64. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +63 -0
  65. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.json +13 -0
  66. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.py +50 -0
  67. brg_certificate/tests/datapath/pattern_test/pattern_test.json +13 -0
  68. brg_certificate/tests/datapath/pattern_test/pattern_test.py +28 -0
  69. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +13 -0
  70. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +51 -0
  71. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +13 -0
  72. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +54 -0
  73. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.json +13 -0
  74. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.py +55 -0
  75. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +13 -0
  76. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +73 -0
  77. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.json +13 -0
  78. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.py +41 -0
  79. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.json +21 -0
  80. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +184 -0
  81. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.json +21 -0
  82. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +210 -0
  83. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.json +30 -0
  84. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.py +203 -0
  85. brg_certificate/tests/datapath/stress_test/stress_test.json +30 -0
  86. brg_certificate/tests/datapath/stress_test/stress_test.py +210 -0
  87. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.json +13 -0
  88. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +113 -0
  89. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.json +13 -0
  90. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.py +79 -0
  91. brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +13 -0
  92. brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +432 -0
  93. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.json +13 -0
  94. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +94 -0
  95. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.json +13 -0
  96. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.py +87 -0
  97. brg_certificate/tests/edge_mgmt/leds_test/leds_test.json +13 -0
  98. brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +210 -0
  99. brg_certificate/tests/edge_mgmt/ota_test/ota_test.json +13 -0
  100. brg_certificate/tests/edge_mgmt/ota_test/ota_test.py +83 -0
  101. brg_certificate/tests/edge_mgmt/stat_test/stat_test.json +13 -0
  102. brg_certificate/tests/edge_mgmt/stat_test/stat_test.py +48 -0
  103. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.json +13 -0
  104. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.py +26 -0
  105. brg_certificate/tests/energy2400/output_power_test/output_power_test.json +13 -0
  106. brg_certificate/tests/energy2400/output_power_test/output_power_test.py +27 -0
  107. brg_certificate/tests/energy2400/pattern_test/pattern_test.json +13 -0
  108. brg_certificate/tests/energy2400/pattern_test/pattern_test.py +28 -0
  109. brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.json +13 -0
  110. brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +398 -0
  111. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.json +13 -0
  112. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +153 -0
  113. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +13 -0
  114. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +264 -0
  115. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +13 -0
  116. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +27 -0
  117. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.json +13 -0
  118. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.py +26 -0
  119. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.json +13 -0
  120. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +397 -0
  121. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +13 -0
  122. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +27 -0
  123. brg_certificate/wltPb_pb2.py +72 -0
  124. brg_certificate/wltPb_pb2.pyi +227 -0
  125. brg_certificate/wlt_types.py +114 -0
  126. gw_certificate/api/extended_api.py +7 -1531
  127. gw_certificate/api_if/200/data.json +106 -0
  128. gw_certificate/api_if/200/logs.json +12 -0
  129. gw_certificate/api_if/200/status.json +47 -0
  130. gw_certificate/api_if/201/data.json +98 -0
  131. gw_certificate/api_if/201/logs.json +12 -0
  132. gw_certificate/api_if/201/status.json +53 -0
  133. gw_certificate/api_if/202/data.json +83 -0
  134. gw_certificate/api_if/202/logs.json +12 -0
  135. gw_certificate/api_if/202/status.json +60 -0
  136. gw_certificate/api_if/203/data.json +85 -0
  137. gw_certificate/api_if/203/logs.json +12 -0
  138. gw_certificate/api_if/203/status.json +63 -0
  139. gw_certificate/api_if/204/data.json +85 -0
  140. gw_certificate/api_if/204/logs.json +12 -0
  141. gw_certificate/api_if/204/status.json +63 -0
  142. gw_certificate/api_if/205/data.json +85 -0
  143. gw_certificate/api_if/205/logs.json +12 -0
  144. gw_certificate/api_if/205/status.json +63 -0
  145. gw_certificate/api_if/api_validation.py +0 -2
  146. gw_certificate/common/analysis_data_bricks.py +18 -1413
  147. gw_certificate/common/debug.py +0 -21
  148. gw_certificate/common/utils.py +1 -212
  149. gw_certificate/common/utils_defines.py +0 -87
  150. gw_certificate/gw_certificate.py +9 -7
  151. gw_certificate/gw_certificate_cli.py +39 -23
  152. gw_certificate/interface/4.4.52_app.zip +0 -0
  153. gw_certificate/interface/4.4.52_sd_bl_app.zip +0 -0
  154. gw_certificate/interface/ble_simulator.py +0 -32
  155. gw_certificate/interface/if_defines.py +1 -0
  156. gw_certificate/interface/mqtt.py +96 -19
  157. gw_certificate/interface/nrfutil-linux +0 -0
  158. gw_certificate/interface/nrfutil-mac +0 -0
  159. gw_certificate/interface/nrfutil.exe +0 -0
  160. gw_certificate/interface/pkt_generator.py +0 -82
  161. gw_certificate/interface/uart_if.py +73 -43
  162. gw_certificate/templates/results.html +1 -1
  163. gw_certificate/tests/__init__.py +1 -2
  164. gw_certificate/tests/actions.py +134 -9
  165. gw_certificate/tests/connection.py +10 -5
  166. gw_certificate/tests/downlink.py +2 -4
  167. gw_certificate/tests/generic.py +62 -12
  168. gw_certificate/tests/registration.py +78 -27
  169. gw_certificate/tests/static/generated_packet_table.py +12 -48
  170. gw_certificate/tests/static/packet_table.csv +10048 -10048
  171. gw_certificate/tests/static/references.py +2 -1
  172. gw_certificate/tests/static/uplink_defines.py +0 -7
  173. gw_certificate/tests/throughput.py +7 -12
  174. gw_certificate/tests/uplink.py +83 -43
  175. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a2.dist-info}/METADATA +59 -8
  176. wiliot_certificate-1.4.0a2.dist-info/RECORD +198 -0
  177. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a2.dist-info}/WHEEL +1 -1
  178. wiliot_certificate-1.4.0a2.dist-info/entry_points.txt +3 -0
  179. wiliot_certificate-1.4.0a2.dist-info/top_level.txt +2 -0
  180. gw_certificate/interface/packet_error.py +0 -22
  181. wiliot_certificate-1.3.0a1.dist-info/RECORD +0 -51
  182. wiliot_certificate-1.3.0a1.dist-info/entry_points.txt +0 -2
  183. wiliot_certificate-1.3.0a1.dist-info/top_level.txt +0 -1
  184. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a2.dist-info}/LICENSE +0 -0
@@ -1,4 +1,5 @@
1
1
 
2
2
  GW_ACTIONS_DOC = "https://community.wiliot.com/customers/s/article/Wiliot-Gateway-Actions"
3
3
  GW_REGISTER_DOC = "https://community.wiliot.com/customers/s/article/Registering-Third-Party-Gateways"
4
- GW_MQTT_DOC = "https://community.wiliot.com/customers/s/article/Sending-Wiliot-Packets-to-the-Wiliot-Cloud"
4
+ GW_MQTT_DOC = "https://community.wiliot.com/customers/s/article/Sending-Wiliot-Packets-to-the-Wiliot-Cloud"
5
+ GW_BRIDGE_OTA_DOC = "https://community.wiliot.com/customers/s/article/Bridge-OTA"
@@ -1,18 +1,11 @@
1
1
  from gw_certificate.interface.if_defines import *
2
2
  from gw_certificate.ag.ut_defines import *
3
3
 
4
- UPLINK_BRG_ID = 'FFFFFFFFFFFF'
5
4
  RECEIVED = 'received'
6
- SEQ_ID = "sequenceId"
7
5
  SHARED_COLUMNS = [PAYLOAD]
8
6
  INT64_COLUMNS = [RSSI]
9
7
  OBJECT_COLUMNS = [PAYLOAD]
10
- INIT_STAGES_DUPLICATIONS = [i for i in range(2,9)]
11
8
  REPORT_COLUMNS = ['pkt_id', 'duplication', 'time_delay']
12
- INCREMENTAL_TIME_DELAYS = [10, 50, 100, 255]
13
- TAG_STAGE_ADVA = '0000000000C0'
14
- TAG_STAGE_PACKETS = range(40)
15
- INCREMENTAL_PACKETS = range(255)
16
9
 
17
10
  ADV_TIMESTAMP = 'adv_timestamp'
18
11
  TS_DEVIATION = 1500
@@ -14,7 +14,6 @@ from gw_certificate.tests.uplink import TimestampsHelper
14
14
  from gw_certificate.interface.mqtt import MqttClient
15
15
  from gw_certificate.tests.static.generated_packet_table import StressRunData
16
16
  from gw_certificate.tests.generic import PassCriteria, PERFECT_SCORE, GenericTest, GenericStage, INFORMATIVE
17
- from gw_certificate.interface.packet_error import PacketError
18
17
 
19
18
  # HELPER DEFINES
20
19
  ONE_SECOND_MS = 1000
@@ -28,7 +27,7 @@ TIME_PER_DELAY_FIRST = 50
28
27
  def process_payload(packet:dict):
29
28
  payload = packet[PAYLOAD]
30
29
  payload = payload.upper()
31
- if len(payload) == 62 and payload[:4] == '1E16':
30
+ if len(payload) == 62 and payload[2:4] == '16':
32
31
  payload = payload [4:]
33
32
  # big2little endian
34
33
  if payload[:4] == 'FCC6':
@@ -38,10 +37,6 @@ def process_payload(packet:dict):
38
37
 
39
38
 
40
39
  # TEST STAGES
41
-
42
- class StressTestError(Exception):
43
- pass
44
-
45
40
  class GenericStressStage(GenericStage):
46
41
  def __init__(self, mqttc:MqttClient, ble_sim:BLESimulator, gw_capabilities:GWCapabilities, stage_name,
47
42
  **kwargs):
@@ -61,9 +56,6 @@ class GenericStressStage(GenericStage):
61
56
 
62
57
  # GW Capabilities
63
58
  self.gw_capabilities = gw_capabilities
64
-
65
- # Packet Error
66
- self.packet_error = PacketError()
67
59
 
68
60
  #Run Data
69
61
  self.run_stress_data = StressRunData()
@@ -128,6 +120,9 @@ class StressTestStage(GenericStressStage):
128
120
  def run_full_stress_test(self, delay_idx, delay):
129
121
  self.prepare_stage()
130
122
  self.run_stress_test_with_delay(delay_idx, delay)
123
+ if self.aggregation_time > 0:
124
+ debug_print(f"Waiting {self.aggregation_time} seconds for packets to be uploaded before processing results..")
125
+ time.sleep(self.aggregation_time)
131
126
  self.generate_stage_report(delay_idx)
132
127
  self.teardown_stage()
133
128
 
@@ -202,8 +197,9 @@ class StressTestStage(GenericStressStage):
202
197
  self.add_report_header()
203
198
  self.add_to_stage_report(tabulate.tabulate(pd.DataFrame(report), showindex=False))
204
199
  for idx, delay in enumerate(self.delays):
205
- self.ts_records_arr[idx].add_ts_errs_to_report(self)
206
200
  if self.ts_records_arr[idx].is_ts_error():
201
+ self.add_to_stage_report(f"Timestamps errors during PPS {self.report_data[str(delay)]['pkts_per_sec_desired']}:")
202
+ self.ts_records_arr[idx].add_ts_errs_to_report(self)
207
203
  self.add_report_line_separator()
208
204
  self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
209
205
 
@@ -235,10 +231,9 @@ class StressTest(GenericTest):
235
231
 
236
232
  def run(self):
237
233
  super().run()
238
- self.test_pass = PERFECT_SCORE
239
234
  for stage in self.stages:
240
235
  stage.prepare_stage()
241
236
  stage.run()
242
- self.test_pass = PassCriteria.calc_for_test(self.test_pass, stage)
237
+ self.test_pass = PassCriteria.calc_for_test(self, stage)
243
238
  self.all_messages_in_test.extend(self.mqttc.get_all_messages_from_topic('data'))
244
239
 
@@ -14,9 +14,8 @@ from gw_certificate.interface.if_defines import DEFAULT_DELAY, LOCATION
14
14
  from gw_certificate.tests.static.uplink_defines import *
15
15
  from gw_certificate.interface.mqtt import MqttClient, Serialization
16
16
  from gw_certificate.interface.pkt_generator import BrgPktGenerator, apply_adva_bitmask
17
- from gw_certificate.tests.static.generated_packet_table import UplinkRunData, UnifiedRunData, SensorRunData, MgmtRunData, PacketTableHelper
18
- from gw_certificate.tests.generic import PassCriteria, PERFECT_SCORE, MINIMUM_SCORE, INCONCLUSIVE_MINIMUM, INIT_INCONCLUSIVE_MINIMUM, GenericTest, GenericStage
19
- from gw_certificate.interface.packet_error import PacketError
17
+ from gw_certificate.tests.static.generated_packet_table import UnifiedRunData, SensorRunData, MgmtRunData, PacketTableHelper
18
+ from gw_certificate.tests.generic import PassCriteria, PERFECT_SCORE, MINIMUM_SCORE, GenericTest, GenericStage, ERR_SUMMARY_DEFAULT
20
19
  from gw_certificate.api_if.api_validation import MESSAGE_TYPES, validate_message
21
20
  from gw_certificate.tests.static.generated_packet_table import CSV_NAME
22
21
 
@@ -25,13 +24,13 @@ from gw_certificate.tests.static.generated_packet_table import CSV_NAME
25
24
  TABLE_SUFFIX = "Table"
26
25
  ERR_SUM_MISSING_PKTS = "Insufficient amount of packets were scanned & uploaded by the gateway. "
27
26
  ERR_SUM_INVALID_TS = "Invalid timestamps were uploaded by the gateway. "
27
+ ERR_SUM_ONLY_1E = "Packets with length != '1E' were not uploaded. "
28
28
 
29
29
  # HELPER FUNCTIONS
30
-
31
30
  def process_payload(packet:dict):
32
31
  payload = packet[PAYLOAD]
33
32
  payload = payload.upper()
34
- if len(payload) == 62 and payload[:4] == '1E16':
33
+ if len(payload) == 62 and payload[2:4] == '16':
35
34
  payload = payload [4:]
36
35
  # big2little endian
37
36
  if payload[:4] == 'FCC6':
@@ -43,6 +42,8 @@ def process_payload(packet:dict):
43
42
  class TimestampsHelper(PacketTableHelper):
44
43
  def __init__(self):
45
44
  self.ts_errors = []
45
+ self.has_out_of_range_ts = False
46
+ self.has_identical_ts = False
46
47
  super().__init__()
47
48
 
48
49
  def set_adv_timestamp(self, data_payload, timestamp):
@@ -64,8 +65,10 @@ class TimestampsHelper(PacketTableHelper):
64
65
  def validate_timestamps(self, received_pkts:list):
65
66
  packets_sent_df = self.get_advertised_entries().copy()
66
67
 
67
- # Convert received packets into a DataFrame for vectorized processing
68
68
  received_df = pd.DataFrame(received_pkts)
69
+ if PAYLOAD not in received_df.columns or TIMESTAMP not in received_df.columns:
70
+ debug_print(f"Can't find payload/timestamp columns, skipping timestamp validation")
71
+ return
69
72
  received_df = received_df[[PAYLOAD, TIMESTAMP]]
70
73
  received_df[TIMESTAMP] = pd.to_numeric(received_df[TIMESTAMP], errors='coerce')
71
74
 
@@ -95,6 +98,7 @@ class TimestampsHelper(PacketTableHelper):
95
98
  f"Timestamp {received_ts} is too far off the accepted range "
96
99
  f"{min_accepted_ts}-{max_accepted_ts} for payload: {row[PAYLOAD]}"
97
100
  )
101
+ self.has_out_of_range_ts = True
98
102
  return received_ts
99
103
  return None
100
104
 
@@ -107,23 +111,20 @@ class TimestampsHelper(PacketTableHelper):
107
111
 
108
112
  for ts in duplicated_ts:
109
113
  self.ts_errors.append(f"Multiple packets were uploaded with identical timestamp (ts = {int(ts)})")
114
+ self.has_identical_ts = True
110
115
 
111
116
  def add_ts_errs_to_report(self, stage:GenericStage):
112
117
  for idx, ts_err in enumerate(self.ts_errors):
113
118
  stage.add_to_stage_report(ts_err)
114
- if idx == 3 and (len(self.ts_errors) - 1) > idx:
119
+ if idx == 2 and (len(self.ts_errors) - 1) > idx:
115
120
  stage.add_to_stage_report(f'Additional errors ({len(self.ts_errors) - 1 - idx}) are suppressed to avoid clutter')
116
121
  break
117
122
 
118
123
  def is_ts_error(self) -> bool:
119
124
  return len(self.ts_errors) > 0
120
-
125
+
121
126
 
122
127
  # TEST STAGES
123
-
124
- class UplinkTestError(Exception):
125
- pass
126
-
127
128
  class GenericUplinkStage(GenericStage):
128
129
  def __init__(self, mqttc:MqttClient, ble_sim:BLESimulator, gw_capabilities:GWCapabilities, stage_name,
129
130
  **kwargs):
@@ -141,12 +142,8 @@ class GenericUplinkStage(GenericStage):
141
142
  # GW Capabilities
142
143
  self.gw_capabilities = gw_capabilities
143
144
 
144
- # Packet Error / Run data
145
- self.packet_error = PacketError()
146
- self.run_data = UplinkRunData
147
-
148
- # Unified stage
149
- self.run_data_unified = UnifiedRunData
145
+ # Run data
146
+ self.run_data = None
150
147
 
151
148
  self.ts_records = TimestampsHelper()
152
149
 
@@ -161,7 +158,6 @@ class GenericUplinkStage(GenericStage):
161
158
  # self.mqtt_packets is a list of pkt jsons: [{timestamp:..., aliasbr.. payload...}, {...}]
162
159
  self.mqtt_pkts = list(map(lambda p: process_payload(p), mqtt_pkts))
163
160
 
164
- ## TODO - REWRITE
165
161
  def compare_local_mqtt(self):
166
162
  self.fetch_mqtt_from_stage()
167
163
  local_pkts_df = pd.DataFrame(self.local_pkts, columns=[PAYLOAD, 'duplication', 'time_delay', 'aliasBridgeId'])
@@ -195,8 +191,11 @@ class GenericUplinkStage(GenericStage):
195
191
  if self.stage_pass < self.pass_min:
196
192
  self.error_summary = ERR_SUM_MISSING_PKTS
197
193
  if self.ts_records.is_ts_error():
198
- self.stage_pass = min(self.stage_pass, self.inconclusive_min)
199
- self.error_summary += ERR_SUM_INVALID_TS
194
+ if self.stage_pass > self.inconclusive_min:
195
+ self.stage_pass = self.inconclusive_min
196
+ self.error_summary = ERR_SUM_INVALID_TS
197
+ else:
198
+ self.error_summary += ERR_SUM_INVALID_TS
200
199
 
201
200
  self.add_report_header()
202
201
  self.add_to_stage_report(f'Number of unique packets sent: {num_pkts_sent}')
@@ -211,6 +210,9 @@ class GenericUplinkStage(GenericStage):
211
210
 
212
211
  self.ts_records.add_ts_errs_to_report(self)
213
212
 
213
+ if num_pkts_received > 0:
214
+ self.add_report_topic_validation('data')
215
+
214
216
  self.comparison.to_csv(self.csv_path)
215
217
  self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
216
218
  debug_print(self.report)
@@ -229,12 +231,13 @@ class ManagementPacketStage(GenericUplinkStage):
229
231
  self.__dict__.update(kwargs)
230
232
  super().__init__(**self.__dict__, stage_name=type(self).__name__)
231
233
  self.run_data = MgmtRunData().data
234
+ self.pass_min = 40
235
+ self.inconclusive_min = 30
232
236
 
233
237
  def run(self):
234
238
  super().run()
235
239
  for index, row in self.run_data.iterrows():
236
240
  data = row[ADVA_PAYLOAD]
237
- # cur_ts = time.time_ns() // 1_000_000
238
241
  self.local_pkts.append((row[PAYLOAD], row['duplication'], row['time_delay'], row['adva']))
239
242
  self.ble_sim.send_packet(raw_packet=data, duplicates=row['duplication'], delay=row['time_delay'])
240
243
  self.ts_records.set_adv_timestamp_current(data)
@@ -250,8 +253,11 @@ class ManagementPacketStage(GenericUplinkStage):
250
253
  if self.stage_pass < self.pass_min:
251
254
  self.error_summary = ERR_SUM_MISSING_PKTS
252
255
  if self.ts_records.is_ts_error():
253
- self.stage_pass = min(self.stage_pass, self.inconclusive_min)
254
- self.error_summary += ERR_SUM_INVALID_TS
256
+ if self.stage_pass > self.inconclusive_min:
257
+ self.stage_pass = self.inconclusive_min
258
+ self.error_summary = ERR_SUM_INVALID_TS
259
+ else:
260
+ self.error_summary += ERR_SUM_INVALID_TS
255
261
 
256
262
  self.add_report_header()
257
263
  self.add_to_stage_report(f'Number of unique packets sent: {num_pkts_sent}')
@@ -263,6 +269,9 @@ class ManagementPacketStage(GenericUplinkStage):
263
269
  self.add_to_stage_report(tabulate.tabulate(not_received, headers='keys', showindex=False))
264
270
  self.add_to_stage_report('Check the CSV for more info')
265
271
 
272
+ if num_pkts_received > 0:
273
+ self.add_report_topic_validation('data')
274
+
266
275
  self.ts_records.add_ts_errs_to_report(self)
267
276
 
268
277
  self.comparison.to_csv(self.csv_path)
@@ -294,7 +303,6 @@ class DataPacketStage(GenericUplinkStage):
294
303
  time.sleep(5)
295
304
 
296
305
 
297
-
298
306
  class SensorPacketStage(GenericUplinkStage):
299
307
  def __init__(self, **kwargs):
300
308
  self.__dict__.update(kwargs)
@@ -315,15 +323,16 @@ class SensorPacketStage(GenericUplinkStage):
315
323
  data = row[ADVA_PAYLOAD]
316
324
  si = row['si']
317
325
  # Save to local_pkts once for data and once for side info. Each with corresponding adva.
318
- self.local_pkts.append((row[PAYLOAD], row['duplication'], row['time_delay'], apply_adva_bitmask(row['bridge_id'], 'random_static')))
319
- self.local_pkts.append((remove_pre_uuid(row['si']), row['duplication'], row['time_delay'], row['adva']))
326
+ self.local_pkts.append((row[ADVA_PAYLOAD], row[PAYLOAD], row['duplication'], row['time_delay'], apply_adva_bitmask(row['bridge_id'], 'random_static')))
327
+ self.local_pkts.append((row['si'], remove_pre_uuid(row['si']), row['duplication'], row['time_delay'], row['adva']))
320
328
  self.ble_sim.send_data_si_pair(data_packet=data, si_packet=si, duplicates=row['duplication'], delay=row['time_delay'])
321
329
  self.ts_records.set_adv_timestamp_current(data)
322
330
  time.sleep(5)
323
331
 
324
332
  def compare_local_mqtt(self):
325
333
  self.fetch_mqtt_from_stage()
326
- local_pkts_df = pd.DataFrame(self.local_pkts, columns=[PAYLOAD, 'duplication', 'time_delay', 'aliasBridgeId'])
334
+ # 'columns' must correspond to number of columns appended previously
335
+ local_pkts_df = pd.DataFrame(self.local_pkts, columns=[ADVA_PAYLOAD, PAYLOAD, 'duplication', 'time_delay', 'aliasBridgeId'])
327
336
  mqtt_pkts_df = pd.DataFrame(self.mqtt_pkts)
328
337
  comparison = local_pkts_df
329
338
 
@@ -348,8 +357,7 @@ class SensorPacketStage(GenericUplinkStage):
348
357
 
349
358
  def generate_stage_report(self):
350
359
  self.compare_local_mqtt()
351
- print(self.comparison)
352
- report = []
360
+ self.ts_records.validate_timestamps(self.mqtt_pkts)
353
361
  num_pkts_sent = len(self.comparison)
354
362
  num_pkts_received = self.comparison['received'].eq(True).sum()
355
363
  pkt_id_pairs = self.comparison.groupby('pkt_id').filter(lambda x: x['received'].all() and len(x) == 2)
@@ -360,15 +368,43 @@ class SensorPacketStage(GenericUplinkStage):
360
368
  self.stage_pass = PERFECT_SCORE
361
369
  else:
362
370
  self.stage_pass = MINIMUM_SCORE
371
+
372
+ if self.ts_records.is_ts_error():
373
+ if self.stage_pass > self.inconclusive_min:
374
+ self.stage_pass = self.inconclusive_min
375
+ self.error_summary = ERR_SUM_INVALID_TS
376
+ else:
377
+ self.error_summary += ERR_SUM_INVALID_TS
363
378
 
364
379
  self.add_report_header()
365
380
  self.add_to_stage_report((f'Number of sensor packets sent: {int(num_pkts_sent / 2)}'))
366
381
  self.add_to_stage_report((f'Number of sensor packets received correctly: {num_pairs}\n'))
367
382
 
368
- not_received = self.comparison[self.comparison[RECEIVED]==False][REPORT_COLUMNS]
383
+ not_received = self.comparison[self.comparison[RECEIVED]==False]
384
+ not_received_rep_cols = not_received[REPORT_COLUMNS]
369
385
  if len(not_received) > 0:
370
386
  self.add_to_stage_report('Packets not received:')
371
- self.add_to_stage_report(tabulate.tabulate(not_received, headers='keys', showindex=False))
387
+ self.add_to_stage_report(tabulate.tabulate(not_received_rep_cols, headers='keys', showindex=False))
388
+
389
+ def only_varying_len_sensors_missed(not_received_df):
390
+ for index, line in not_received_df.iterrows():
391
+ if line[ADVA_PAYLOAD][12:14] == '1E':
392
+ return False
393
+ return True
394
+
395
+ if only_varying_len_sensors_missed(not_received):
396
+ self.add_to_stage_report(f"Warning {ERR_SUM_ONLY_1E}")
397
+ if self.score_pass():
398
+ self.stage_pass = self.inconclusive_min
399
+ self.error_summary = ERR_SUM_ONLY_1E
400
+ else:
401
+ self.error_summary += ERR_SUM_ONLY_1E
402
+
403
+ self.ts_records.add_ts_errs_to_report(self)
404
+
405
+ if num_pkts_received > 0:
406
+ self.add_report_topic_validation('data')
407
+
372
408
  self.comparison.to_csv(self.csv_path)
373
409
  self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
374
410
  debug_print(self.report)
@@ -515,9 +551,10 @@ class AliasBridgeIDStage(GenericUplinkStage):
515
551
  relative_path = 'static/' + CSV_NAME
516
552
  csv_path = pkg_resources.resource_filename(__name__, relative_path)
517
553
  df = pd.read_csv(csv_path)
554
+ uplink_tests_df = df[(df['test'] == 'unified') | (df['test'] == 'mgmt') | (df['test'] == 'sensor')].copy()
518
555
 
519
556
  # Store all test payloads
520
- all_payloads = df[ADVA_PAYLOAD].str[12:]
557
+ all_payloads = uplink_tests_df[PAYLOAD]
521
558
  self.all_test_payloads = all_payloads.tolist()
522
559
 
523
560
  def _parser(row, desired:Literal['adva', 'without_adva']):
@@ -530,10 +567,9 @@ class AliasBridgeIDStage(GenericUplinkStage):
530
567
  return output_string
531
568
 
532
569
  # Create data set for alias bridge verification
533
- alias_bridge_id_df = df[(df['test'] == 'unified') | (df['test'] == 'mgmt')].copy()
534
- alias_bridge_id_df['payload'] = alias_bridge_id_df.apply(lambda row: _parser(row, 'without_adva'), axis=1)
570
+ alias_bridge_id_df = uplink_tests_df.copy()
535
571
  # Take the adva from the payload
536
- alias_bridge_id_df['alias_bridge_id'] = alias_bridge_id_df.apply(lambda row: _parser(row, 'adva'), axis=1)
572
+ alias_bridge_id_df['alias_bridge_id'] = alias_bridge_id_df['adva']
537
573
  # Convert bridge_id to little endian
538
574
  alias_bridge_id_df['alias_bridge_id'] = alias_bridge_id_df['alias_bridge_id'].apply(lambda x: ''.join(format(byte, '02X') for byte in bytes.fromhex(x)[::-1]))
539
575
  self.alias_bridge_id_df = alias_bridge_id_df
@@ -563,7 +599,10 @@ class AliasBridgeIDStage(GenericUplinkStage):
563
599
  pkt_payload = pkt['payload']
564
600
  pkt_alias_bridge_id = pkt['aliasBridgeId']
565
601
  validation_data = self.alias_bridge_id_df[self.alias_bridge_id_df['payload'].str.contains(pkt_payload, case=False)]
566
- required_bridge_id = validation_data['alias_bridge_id'].iat[0]
602
+ if len(validation_data) != 1:
603
+ debug_print(f"validation_data unexpected len:{len(validation_data)}, for payload:{pkt_payload}")
604
+ return
605
+ required_bridge_id = validation_data.iloc[0]['alias_bridge_id']
567
606
  if required_bridge_id != pkt_alias_bridge_id.upper():
568
607
  report.append(f"Alias bridge ID of the packet does not match. The required alias bridge ID is {required_bridge_id} but the packet alias bridge ID is {pkt_alias_bridge_id}")
569
608
  self.stage_pass = MINIMUM_SCORE
@@ -652,7 +691,7 @@ class GeolocationStage(GenericUplinkStage):
652
691
  # TEST CLASS
653
692
  TX_STAGES = [ManagementPacketStage, DataPacketStage, SensorPacketStage]
654
693
  UNCOUPLED_STAGES = [ManagementPacketStage, DataPacketStage, SensorPacketStage,
655
- SequentialSequenceIdStage, AliasBridgeIDStage]
694
+ SequentialSequenceIdStage, AliasBridgeIDStage, GeolocationStage]
656
695
 
657
696
  class UplinkTest(GenericTest):
658
697
  def __init__(self, **kwargs):
@@ -660,17 +699,18 @@ class UplinkTest(GenericTest):
660
699
  self.__dict__.update(kwargs)
661
700
  super().__init__(**self.__dict__, test_name=type(self).__name__)
662
701
  self.all_messages_in_test = []
702
+
703
+ def prepare_test(self):
704
+ super().prepare_test()
663
705
  stages = UNCOUPLED_STAGES
664
706
  if self.mqttc.get_serialization() == Serialization.JSON:
665
707
  stages = stages + [ApiValidationStage]
666
- if self.gw_capabilities.geoLocationSupport:
667
- stages.append(GeolocationStage)
708
+ # if self.gw_capabilities.geoLocationSupport:
709
+ # stages.append(GeolocationStage)
668
710
  self.stages = [stage(**self.__dict__) for stage in stages]
669
-
670
711
 
671
712
  def run(self):
672
713
  super().run()
673
- self.test_pass = PERFECT_SCORE
674
714
  for stage in self.stages:
675
715
  stage.prepare_stage()
676
716
  stage.run()
@@ -678,6 +718,6 @@ class UplinkTest(GenericTest):
678
718
  debug_print(f"Waiting {self.aggregation_time} seconds for packets to be uploaded before processing results..")
679
719
  time.sleep(self.aggregation_time)
680
720
  self.add_to_test_report(stage.generate_stage_report())
681
- self.test_pass = PassCriteria.calc_for_test(self.test_pass, stage)
721
+ self.test_pass = PassCriteria.calc_for_test(self, stage)
682
722
  self.all_messages_in_test.extend(self.mqttc.get_all_messages_from_topic('data'))
683
723
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: wiliot_certificate
3
- Version: 1.3.0a1
3
+ Version: 1.4.0a2
4
4
  Summary: A library for certifying Wiliot-compliant boards
5
5
  Author-email: Wiliot <support@wiliot.com>
6
6
  License: MIT License
@@ -30,7 +30,7 @@ Project-URL: Certified, https://www.wiliot.com/product/ambient-iot-network#partn
30
30
  Classifier: Programming Language :: Python :: 3
31
31
  Classifier: License :: OSI Approved :: MIT License
32
32
  Classifier: Operating System :: OS Independent
33
- Requires-Python: >=3.9
33
+ Requires-Python: >=3.13
34
34
  Description-Content-Type: text/markdown
35
35
  License-File: LICENSE
36
36
  Requires-Dist: jinja2>=3.1.5
@@ -42,18 +42,22 @@ Requires-Dist: colorama>=0.4.6
42
42
  Requires-Dist: tabulate>=0.9.0
43
43
  Requires-Dist: wiliot-core>=5.9.1
44
44
  Requires-Dist: paho-mqtt>=2.1.0
45
- Requires-Dist: bitstruct>=8.19.0
45
+ Requires-Dist: bitstruct>=8.20.0
46
46
  Requires-Dist: protobuf>=5.29.3
47
47
  Requires-Dist: wiliot-api>=4.10.8
48
48
  Requires-Dist: jsonschema>=4.23.0
49
49
  Requires-Dist: statsmodels>=0.14.4
50
+ Requires-Dist: pyserial>=3.5
51
+ Requires-Dist: reportlab>=4.3.1
52
+ Requires-Dist: google-api-python-client>=2.162.0
50
53
 
51
- # wiliot-certificate #
54
+ # wiliot-certificate
52
55
 
53
56
  <!-- Description -->
54
57
  wiliot-certificate is a python library with tools used to test & certify boards and their compatibility with Wiliot's echosystem.
55
58
  This python package includes the following CLI utilities:
56
59
  - Gateway Certificate (`wlt-gw-certificate`)
60
+ - Bridge Certificate (`wlt-cert-brg`)
57
61
 
58
62
  ## Installing wiliot-certificate
59
63
  ````commandline
@@ -87,11 +91,12 @@ Sends advertising actions (txPacket) via MQTT to the GW and validates their adve
87
91
  Increments time delays between packets to evaluate GW's capability in handling increasing packets per second rates.
88
92
 
89
93
  #### GW Certificate Release Notes:
90
- 1.3.0:
94
+ 1.4.0:
91
95
  - Released in a standalone wiliot-certificate package
92
- - Python 3.13 support
96
+ - Python 3.12 support
93
97
  - Gw API version 205 support
94
98
  - Registration Test
99
+ - Aggregation flag supported by StressTest
95
100
 
96
101
 
97
102
  ```
@@ -101,13 +106,59 @@ Gateway Certificate - CLI Tool to test Wiliot GWs
101
106
 
102
107
  required arguments:
103
108
  -gw GW Gateway ID
104
- -owner OWNER Owner ID (optional when running only the registration test)
105
109
 
106
110
  optional arguments:
107
- -suffix Allow for different suffixes after the GW ID in MQTT topics
111
+ -owner OWNER Owner ID (Required for non-registration tests)
108
112
  -tests Pick specific tests to run
113
+ -actions Pick specific actions to test during the ActionsTest
109
114
  -update Update the firmware of the test board
110
115
  -pps Pick specific PPS rate for the stress test
111
116
  -agg Time the uplink stages should wait before processing packets
117
+ -suffix Allow for different suffixes after the GW ID in MQTT topics
118
+ -env Wiliot envrionment for Registration and bridgeOTA tests
112
119
  -h, --help show this help message and exit
113
120
  ```
121
+
122
+ ### Bridge Certificate
123
+ Test Wiliot BRGs capabilities.
124
+ The BRG Certificate includes different tests that run sequentially to test each capability reported by the BRG.
125
+ The BRG Certificate tool uses a public MQTT Broker (Eclipse):
126
+
127
+ Host: mqtt.eclipseprojects.io
128
+ TLS TCP Port: 8883
129
+ TLS Websocket Port: 443
130
+ TCP Port: 1883
131
+ Websocket Port: 80
132
+
133
+ More information can be found at https://mqtt.eclipseprojects.io/.
134
+
135
+ #### XXX Test
136
+ TEST EXPLANATION
137
+
138
+ #### BRG Certificate Release Notes:
139
+ 1.3.0:
140
+ - FIRST VERSION
141
+
142
+
143
+ ```
144
+ usage: wlt-cert-brg [-h] [-h] [-b BRG] [-b1 BRG1] --gw GW [--data {tags,sim}] [--port PORT] [--clean] [--tl TL] [--run RUN] [--drun DRUN] [--exit_on_test_failure] [--exit_on_param_failure] [--analyze_interference]
145
+
146
+ Gateway Certificate - CLI Tool to test Wiliot BRGs
147
+
148
+ required arguments:
149
+ --gw, -g GW Gateway ID
150
+ --port, -p PORT COM Port
151
+ --brg, -b BRG Bridge ID
152
+
153
+ optional arguments:
154
+ --brg1, -b1 BRG1 Second bridge id to run on tests two bridges needed
155
+ --data, -d {tags,sim} Choose if data generated from real tags or by simulation
156
+ --port, -p PORT Enable UT using UART connection for Gateway Simulation or Data Simulation
157
+ --clean Clean all logs
158
+ --tl TL Test list file to use
159
+ --run RUN String to filter tests to run
160
+ --drun DRUN String to filter tests not to run
161
+ --exit_on_test_failure Stop running the tests if a test failed
162
+ --exit_on_param_failure Sets exit_on_param_failure mode to true in order to prevent tests from continuing iteration over all possibilities in case of failure
163
+ --analyze_interference, -ai Analyze interference before tests start (relevant only for Gateway Simulator)
164
+ ```