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
@@ -0,0 +1,373 @@
1
+ # from http import client
2
+ import paho.mqtt.client as mqtt
3
+ import ssl
4
+ import time
5
+ import os
6
+ import json
7
+ import datetime
8
+ import base64
9
+ import copy
10
+ import traceback
11
+ import brg_certificate.wltPb_pb2 as wpb
12
+ from google.protobuf.message import DecodeError
13
+ from google.protobuf.json_format import MessageToDict
14
+
15
+ # Local imports
16
+ from brg_certificate.wlt_types import *
17
+ from brg_certificate.cert_data_sim import PIXEL_SIM_INDICATOR, TAG_ID_OFFSET
18
+ from brg_certificate.cert_prints import *
19
+ from brg_certificate.cert_defines import *
20
+
21
+
22
+ SENSORS_DATA_SI_DUP = 6
23
+
24
+ class WltMqttPkt:
25
+ def __init__(self, body, topic, userdata):
26
+ self.body = body
27
+ self.mqtt_topic = topic
28
+ self.mqtt_timestamp = datetime.datetime.now()
29
+ self.body_ex = {}
30
+ if "data" in self.mqtt_topic:
31
+ self.body_ex = copy.deepcopy(body)
32
+ self.body_ex['undecrypted'] = 0
33
+ for pkt in self.body_ex[PACKETS]:
34
+ # if packet is not a mgmt packet or a side info packet it is a data packet
35
+ wlt_pkt = WltPkt(pkt[PAYLOAD])
36
+ if wlt_pkt.pkt != None:
37
+ if wlt_pkt.hdr.group_id == ag.GROUP_ID_BRG2GW:
38
+ pkt[MGMT_PKT] = copy.deepcopy(wlt_pkt)
39
+ elif wlt_pkt.data_hdr.group_id_major in ag.UNIFIED_GROUP_ID_LIST:
40
+ pkt[UNIFIED_PKT] = copy.deepcopy(wlt_pkt)
41
+ if PIXEL_SIM_INDICATOR in pkt[PAYLOAD]:
42
+ pkt[DECODED_DATA] = {TAG_ID: pkt[PAYLOAD][TAG_ID_OFFSET:TAG_ID_OFFSET+8], PACKET_TYPE: wlt_pkt.data_hdr.pkt_type, PACKET_CNTR: 0}
43
+ elif userdata["data"] != DATA_SIMULATION:
44
+ pkt[DECODED_DATA] = self.handle_data_pkt(wlt_pkt.dump())
45
+ elif wlt_pkt.hdr.group_id == ag.GROUP_ID_SIDE_INFO_SENSOR:
46
+ pkt[SIDE_INFO_SENSOR_PKT] = copy.deepcopy(wlt_pkt)
47
+ elif wlt_pkt.hdr.uuid_lsb == ag.HDR_DEFAULT_BRG_SENSOR_UUID_LSB and wlt_pkt.hdr.uuid_msb == ag.HDR_DEFAULT_BRG_SENSOR_UUID_MSB:
48
+ pkt[SENSOR_PKT] = copy.deepcopy(wlt_pkt)
49
+ pkt[DECODED_DATA] = {TAG_ID: None, PACKET_CNTR: None, PACKET_TYPE: None}
50
+ else:
51
+ if userdata["data"] != DATA_SIMULATION:
52
+ pkt[DECODED_DATA] = self.handle_data_pkt(pkt)
53
+
54
+ def handle_data_pkt(self, pkt):
55
+ p, dec_data = "", {TAG_ID: None, PACKET_CNTR: None, PACKET_TYPE: None}
56
+ if type(pkt) == str:
57
+ p = pkt
58
+ else:
59
+ p = pkt[PAYLOAD]
60
+ resolve = local_resolve(p) if p else None
61
+ if resolve:
62
+ for key in dec_data:
63
+ if key in resolve[DECODED_DATA]:
64
+ dec_data[key] = resolve[DECODED_DATA][key]
65
+ else:
66
+ self.body_ex['undecrypted'] += 1
67
+ return dec_data
68
+
69
+ class WltMqttPkts:
70
+ def __init__(self):
71
+ self.data = []
72
+ self.status = []
73
+ self.update = []
74
+ self.all = []
75
+ def insert(self, pkt):
76
+ self.all.append(pkt)
77
+ if "data" in pkt.mqtt_topic:
78
+ self.data.append(pkt)
79
+ elif "status" in pkt.mqtt_topic:
80
+ self.status.append(pkt)
81
+ elif "update" in pkt.mqtt_topic:
82
+ self.update.append(pkt)
83
+ def flush(self):
84
+ self.all = []
85
+ self.data = []
86
+ self.status = []
87
+ self.update = []
88
+ def flush_data(self):
89
+ self.data = []
90
+ def flush_status(self):
91
+ self.status = []
92
+
93
+ def local_resolve(p):
94
+ import brg_certificate.ut.ut_resolve as ut_resolve
95
+ irresolvable_payloads = ["1E16C6FC0000EE", "1E16AFFD0000EC", "1E16C6FC0000EC"]
96
+ try:
97
+ if any(substring in p for substring in irresolvable_payloads):
98
+ # brg2gw mgmt pkt - skip
99
+ return None
100
+ elif p.startswith("1E16"):
101
+ payload = p
102
+ elif p.startswith("2916"):
103
+ payload = '26' + p[2:-6] # change 29 to 26 and remove side info
104
+ else:
105
+ payload = "1E16" + p
106
+ group_id_minor = int(p[8:10], 16)
107
+ if group_id_minor == 0x05 or group_id_minor == 0xFE: # BLE5 group id minor
108
+ version=3.0
109
+ else:
110
+ version=2.4
111
+ resolve = ut_resolve.DecryptedPacket(ut_resolve.convert_cloud_to_packet(payload), packet_version_by_user=version)
112
+ return {PACKET_DATA:resolve.packet_data, DECODED_DATA:resolve.decoded_data, GW_DATA:resolve.gw_data}
113
+ except Exception as e:
114
+ print(traceback.format_exc())
115
+ print(e)
116
+ print(f"Failed in local_resolve with packet: {p}\n")
117
+ return None
118
+
119
+ def is_json(msg):
120
+ is_utf = True
121
+ try:
122
+ json.loads(msg.decode("utf-8"))
123
+ except:
124
+ is_utf = False
125
+ return is_utf
126
+
127
+ def on_connect(mqttc, userdata, flags, rc):
128
+ print("python_mqtt_connect, rc: " + str(rc))
129
+
130
+ def on_disconnect(mqttc, userdata, rc):
131
+ txt = f"ERROR: python_mqtt_disconnect, rc: {rc} {mqtt.error_string(rc)}"
132
+ print(txt)
133
+ write_to_mqtt_log_file(txt)
134
+
135
+ def on_subscribe(mqttc, userdata, mid, granted_qos):
136
+ print("python_mqtt_subscribe, " + str(mid) + " " + str(granted_qos))
137
+
138
+ def on_unsubscribe(mqttc, userdata, mid):
139
+ print("ERROR: python_mqtt_unsubscribe, " + str(mid))
140
+
141
+ def on_message(mqttc, userdata, message):
142
+ if is_json(message.payload):
143
+ on_message_json(mqttc, userdata, message)
144
+ else:
145
+ on_message_protobuf(mqttc, userdata, message)
146
+
147
+ def on_message_json(mqttc, userdata, message):
148
+ wlt_mqtt_pkts = userdata[PKTS]
149
+ data = json.loads(message.payload.decode("utf-8"))
150
+ wlt_mqtt_pkts.insert(WltMqttPkt(data, message.topic, userdata))
151
+ write_to_mqtt_log_file("// JSON message received at {}, topic={}:\n{}\n".format(datetime.datetime.now().strftime("%d/%m/%Y, %H:%M:%S"), message.topic, str(message.payload.decode("utf-8"))))
152
+
153
+ def on_message_protobuf(mqttc, userdata, message):
154
+ pb_msg = None
155
+ pb_decoded = False
156
+
157
+ # Decode message according to the schema used on each topic
158
+ if 'status' in message.topic:
159
+ pb_msg = wpb.UplinkMessage()
160
+ elif 'data' in message.topic:
161
+ pb_msg = wpb.GatewayData()
162
+ elif 'update' in message.topic:
163
+ pb_msg = wpb.DownlinkMessage()
164
+ try:
165
+ pb_msg.ParseFromString(message.payload)
166
+ pb_decoded = True
167
+ except DecodeError as e:
168
+ print(f'ERROR: failed decoding {message.topic} message: \n{e}\n')
169
+
170
+ if pb_decoded is True:
171
+ pb_msg_dict = MessageToDict(pb_msg)
172
+ # Align formats with JSON (bytes to hex strings)
173
+ if 'data' in message.topic and PACKETS in pb_msg_dict.keys():
174
+ for idx, pkt in enumerate(pb_msg_dict[PACKETS]):
175
+ pb_msg_dict[PACKETS][idx][PAYLOAD] = base64.b64decode(pkt[PAYLOAD]).hex().upper()
176
+ pb_msg_dict[PACKETS][idx][TIMESTAMP] = int(pkt[TIMESTAMP])
177
+ if 'update' in message.topic:
178
+ if TX_PKT in pb_msg_dict.keys():
179
+ pb_msg_dict[TX_PKT][PAYLOAD] = base64.b64decode(pb_msg_dict[TX_PKT][PAYLOAD]).hex().upper()
180
+ elif BRG_UPGRADE in pb_msg_dict.keys():
181
+ pb_msg_dict[BRG_UPGRADE][REBOOT_PKT] = base64.b64decode(pb_msg_dict[BRG_UPGRADE][REBOOT_PKT]).hex().upper()
182
+
183
+ # Push & log
184
+ wlt_mqtt_pkts = userdata[PKTS]
185
+ wlt_mqtt_pkts.insert(WltMqttPkt(pb_msg_dict, message.topic, userdata))
186
+ write_to_mqtt_log_file("// Protobuf message {} at {}, topic={}:\n{}\n".format('published' if 'update' in message.topic else 'received',
187
+ datetime.datetime.now().strftime("%d/%m/%Y, %H:%M:%S"), message.topic, json.dumps(pb_msg_dict, indent=4)))
188
+
189
+ def pkts_to_log(pkts):
190
+ text = ""
191
+ for p in pkts:
192
+ text += "// {} topic={}".format(p.mqtt_timestamp.strftime("%d/%m/%Y, %H:%M:%S"), p.mqtt_topic)
193
+ text += "\n"+json.dumps(p.body, indent=4)+"\n"
194
+ return text
195
+
196
+ def write_to_log_file(file_name, pkts):
197
+ f = open(os.path.join(BASE_DIR, file_name), "w")
198
+ f.write(pkts_to_log(pkts))
199
+ f.close()
200
+
201
+ def write_to_mqtt_log_file(txt):
202
+ f = open(os.path.join(BASE_DIR, CERT_MQTT_LOG_FILE), "a")
203
+ f.write(txt)
204
+ f.close()
205
+
206
+ def load_custom_broker(gw, rel_path="."):
207
+ f = open(os.path.join(BASE_DIR, rel_path, "config", "eclipse.json"))
208
+ # f = open(os.path.join(BASE_DIR, rel_path, "config", "hivemq.json"))
209
+ # f = open(os.path.join(BASE_DIR, rel_path, "config", "mosquitto.json"))
210
+ # f = open(os.path.join(BASE_DIR, rel_path, "config", "wiliot-dev.json"))
211
+ data = json.load(f)
212
+ data[CUSTOM_BROKER_UPDATE_TOPIC] += gw
213
+ data[CUSTOM_BROKER_STATUS_TOPIC] += gw
214
+ data[CUSTOM_BROKER_DATA_TOPIC] += gw
215
+ return data
216
+
217
+ def mqttc_init(gw_id, userdata={PKTS: WltMqttPkts()}, rel_path=".", data=DATA_REAL_TAGS):
218
+
219
+ custom_broker = load_custom_broker(gw=gw_id, rel_path=rel_path)
220
+ client_id = '{}-republish'.format(gw_id)
221
+ userdata["data"] = data
222
+ mqttc = mqtt.Client(mqtt.CallbackAPIVersion.VERSION1, client_id, userdata=userdata)
223
+ mqttc.username_pw_set(custom_broker[CUSTOM_BROKER_USERNAME], custom_broker[CUSTOM_BROKER_PASSWORD])
224
+ mqttc.on_message = on_message
225
+ mqttc.on_connect = on_connect
226
+ mqttc.on_disconnect = on_disconnect
227
+ mqttc.on_subscribe = on_subscribe
228
+ mqttc.on_unsubscribe = on_unsubscribe
229
+ if not 1883 == custom_broker[CUSTOM_BROKER_PORT]:
230
+ mqttc.tls_set(tls_version=ssl.PROTOCOL_TLSv1_2)
231
+ mqttc.connect(custom_broker[CUSTOM_BROKER_BROKER_URL].replace("mqtts://", ""), port=custom_broker[CUSTOM_BROKER_PORT], keepalive=60)
232
+ mqttc.loop_start()
233
+
234
+ mqttc.update_topic = custom_broker[CUSTOM_BROKER_UPDATE_TOPIC]
235
+ mqttc.subscribe(mqttc.update_topic)
236
+ mqttc.data_topic = custom_broker[CUSTOM_BROKER_DATA_TOPIC]
237
+ mqttc.subscribe(mqttc.data_topic)
238
+ mqttc.status_topic = custom_broker[CUSTOM_BROKER_STATUS_TOPIC]
239
+ mqttc.subscribe(mqttc.status_topic)
240
+
241
+ mqttc.flush_pkts = mqttc._userdata[PKTS].flush
242
+ mqttc.flush_data_pkts = mqttc._userdata[PKTS].flush_data
243
+ mqttc.flush_status_pkts = mqttc._userdata[PKTS].flush_status
244
+ time.sleep(2)
245
+
246
+ return mqttc
247
+
248
+ def dump_pkts(test, log):
249
+ write_to_log_file(os.path.join(test.dir, MQTT_LOG_PRE_STR+log+"_all.json"), test.mqttc._userdata[PKTS].all)
250
+ write_to_log_file(os.path.join(test.dir, MQTT_LOG_PRE_STR+log+"_data.json"), test.mqttc._userdata[PKTS].data)
251
+ write_to_log_file(os.path.join(test.dir, MQTT_LOG_PRE_STR+log+"_status.json"), test.mqttc._userdata[PKTS].status)
252
+ write_to_log_file(os.path.join(test.dir, MQTT_LOG_PRE_STR+log+"_update.json"), test.mqttc._userdata[PKTS].update)
253
+
254
+ # Get data/tags functions
255
+ def get_all_data_pkts(mqttc):
256
+ data_pkts = []
257
+ for p in mqttc._userdata[PKTS].data:
258
+ gw_id = p.body_ex[GW_ID] if GW_ID in p.body_ex else ""
259
+ if PACKETS in p.body_ex:
260
+ for pkt in p.body_ex[PACKETS]:
261
+ pkt[GW_ID] = gw_id
262
+ data_pkts += [pkt]
263
+ return data_pkts
264
+
265
+ def get_all_sim_data_pkts(mqttc):
266
+ data_pkts = []
267
+ for p in mqttc._userdata[PKTS].data:
268
+ gw_id = p.body_ex[GW_ID] if GW_ID in p.body_ex else ""
269
+ if PACKETS in p.body_ex:
270
+ for pkt in p.body_ex[PACKETS]:
271
+ if PIXEL_SIM_INDICATOR in pkt[PAYLOAD]:
272
+ pkt[GW_ID] = gw_id
273
+ data_pkts += [pkt]
274
+ return data_pkts
275
+
276
+ def get_undecrypted_data_pkts_count(mqttc):
277
+ undecrypted = 0
278
+ for p in mqttc._userdata[PKTS].data:
279
+ if 'undecrypted' in p.body_ex:
280
+ undecrypted += p.body_ex['undecrypted']
281
+ return undecrypted
282
+
283
+ def get_all_sensor_pkts(mqttc, test, is_embedded=False):
284
+ all_sensor_pkts = couple_sensor_data_si_coupling(test)
285
+ all_sensor_pkts = [p for p in all_sensor_pkts if test.active_brg.id_str == p[BRIDGE_ID] and (p[IS_EMBEDDED] == is_embedded)]
286
+ return all_sensor_pkts
287
+
288
+ def couple_sensor_data_si_coupling(test):
289
+ all_pkts = get_all_data_pkts(test.mqttc)
290
+ all_sensor_data_pkts = [p for p in all_pkts if SENSOR_PKT in p]
291
+ all_sensor_side_info_pkts = [p for p in all_pkts if SIDE_INFO_SENSOR_PKT in p]
292
+ # Couple data and side info
293
+ coupled_sensor_pkts = []
294
+ for p_data in all_sensor_data_pkts:
295
+ for p_si in all_sensor_side_info_pkts:
296
+ data_pkt = p_data[SENSOR_PKT].pkt
297
+ si_pkt = p_si[SIDE_INFO_SENSOR_PKT].pkt
298
+ # Packet not coupled yet and (same pkt id & timestamp diff < 1 sec)
299
+ if (not coupled_pkt_exists(coupled_sensor_pkts, p_si) and
300
+ data_pkt.pkt_id == si_pkt.pkt_id and abs(p_data[TIMESTAMP] - p_si[TIMESTAMP]) < 1000):
301
+ p_coupled = {
302
+ TIMESTAMP : p_data[TIMESTAMP],
303
+ SEQUENCE_ID : str(p_data[SEQUENCE_ID]),
304
+ NFPKT : si_pkt.nfpkt,
305
+ RSSI : si_pkt.rssi,
306
+ IS_SENSOR : si_pkt.is_sensor,
307
+ IS_EMBEDDED : si_pkt.is_sensor_embedded,
308
+ IS_SCRAMBLED : si_pkt.is_scrambled,
309
+ SENSOR_ID : hex(si_pkt.sensor_mac)[2:].upper(),
310
+ SENSOR_UUID : "{:02X}{:02X}{:02X}".format(si_pkt.sensor_ad_type, si_pkt.sensor_uuid_msb, si_pkt.sensor_uuid_lsb),
311
+ BRIDGE_ID: "{:012X}".format(si_pkt.brg_mac),
312
+ PAYLOAD: p_data[PAYLOAD],
313
+ SENSOR_PKT: p_data[SENSOR_PKT],
314
+ }
315
+ coupled_sensor_pkts += [p_coupled]
316
+ # Count the number of packet duplications:
317
+ count_pkt_id_duplications(test, all_sensor_data_pkts, all_sensor_side_info_pkts, coupled_sensor_pkts)
318
+ return coupled_sensor_pkts
319
+
320
+ def coupled_pkt_exists(coupled_list, pkt):
321
+ for coupled_pkt in coupled_list:
322
+ if ((abs(coupled_pkt[TIMESTAMP] - pkt[TIMESTAMP]) < 1000) and
323
+ coupled_pkt[SENSOR_PKT].pkt.pkt_id == pkt[SIDE_INFO_SENSOR_PKT].pkt.pkt_id):
324
+ return True
325
+ return False
326
+
327
+ def count_pkt_id_duplications(test, all_sensor_data_pkts, all_sensor_side_info_pkts, all_coupled_pkts):
328
+ pkt_ids = [p_data[SENSOR_PKT].pkt.pkt_id for p_data in all_sensor_data_pkts]
329
+ pkt_ids += [p_si[SIDE_INFO_SENSOR_PKT].pkt.pkt_id for p_si in all_sensor_side_info_pkts]
330
+ for coupled_pkt in all_coupled_pkts:
331
+ _pkt_id = coupled_pkt[SENSOR_PKT].pkt.pkt_id
332
+ coupled_pkt[PKT_ID_CTR] = pkt_ids.count(_pkt_id)
333
+ if coupled_pkt[PKT_ID_CTR] > SENSORS_DATA_SI_DUP:
334
+ print(f"pkt_id {_pkt_id:08X}: {coupled_pkt[PKT_ID_CTR]} occurrences")
335
+ test.reason = f'Warning: {coupled_pkt[PKT_ID_CTR]} sensor data and si with pkt id 0x{_pkt_id:08X}'
336
+
337
+ def get_all_brg1_ext_sensor_pkts(mqttc, test=None):
338
+ test.active_brg = test.brg1
339
+ pkts = get_all_sensor_pkts(mqttc, test)
340
+ test.active_brg = test.brg0
341
+ return pkts
342
+
343
+ def get_all_custom_pkts(mqttc, test=None):
344
+ return get_all_sensor_pkts(mqttc, test, is_embedded=True)
345
+
346
+ def get_all_mgmt_pkts(mqttc):
347
+ all_data_pkts = get_all_data_pkts(mqttc)
348
+ return [p for p in all_data_pkts if MGMT_PKT in p]
349
+
350
+ def get_brg2gw_mgmt_pkts(mqttc, test=None, mgmt_types=[]):
351
+ brg2gw_mgmt_pkts = [p for p in get_all_mgmt_pkts(mqttc) if ((p[MGMT_PKT].hdr.group_id == ag.GROUP_ID_BRG2GW) and
352
+ (not mgmt_types or type(p[MGMT_PKT].pkt) in mgmt_types))]
353
+ pkts = [p for p in brg2gw_mgmt_pkts if test.active_brg.id_str in p[PAYLOAD]]
354
+ return pkts
355
+
356
+ def get_unified_data_pkts(test):
357
+ all_unified_pkts, pkts = [], get_all_sim_data_pkts(test.mqttc) if test.data == DATA_SIMULATION else get_all_data_pkts(test.mqttc)
358
+ for p in pkts:
359
+ if UNIFIED_PKT in p:
360
+ all_unified_pkts += [p]
361
+ pkts = all_unified_pkts
362
+ pkts = [p for p in all_unified_pkts if p[ALIAS_BRIDGE_ID] == test.active_brg.id_alias]
363
+ print(f"\nCollected {len(pkts)} unified data pkts")
364
+ return pkts
365
+
366
+ def get_internal_brg_unified_data_pkts(test):
367
+ all_unified_pkts, pkts = [], get_all_sim_data_pkts(test.mqttc) if test.data == DATA_SIMULATION else get_all_data_pkts(test.mqttc)
368
+ for p in pkts:
369
+ if UNIFIED_PKT in p:
370
+ all_unified_pkts += [p]
371
+ pkts = [p for p in all_unified_pkts if p[ALIAS_BRIDGE_ID] == test.internal_id_alias()]
372
+ print(f"\nCollected {len(pkts)} unified gw_tag_pkts")
373
+ return pkts
@@ -0,0 +1,181 @@
1
+ from brg_certificate.cert_defines import *
2
+ import time, datetime
3
+ import sys
4
+ import json
5
+ import brg_certificate.cert_mqtt as cert_mqtt
6
+ import brg_certificate.cert_data_sim as cert_data_sim
7
+ import os
8
+ import re
9
+
10
+ COLORS = {
11
+ "HEADER" : '\033[95m',
12
+ "BLUE" : '\033[94m',
13
+ "CYAN" : '\033[96m',
14
+ "GREEN" : '\033[92m',
15
+ "WARNING" : '\033[93m',
16
+ "RED" : '\033[91m',
17
+ "ENDC" : '\033[0m',
18
+ "BOLD" : '\033[1m',
19
+ "UNDERLINE" : '\033[4m',
20
+ }
21
+ color = lambda c, t : COLORS["BOLD"]+COLORS[c]+t+COLORS["ENDC"]
22
+ pipeline_running = lambda : True if 'BITBUCKET_BUILD_NUMBER' in os.environ else False
23
+ camelcase_to_title = lambda s: ' '.join(word.capitalize() for word in re.split('(?=[A-Z])', s))
24
+ SEP = '\n' + '#'*100 + '\n'
25
+ WIL_UT_TEXT = r'''
26
+ __ _____ _ ___ ___ _____ _ _ _____
27
+ \ \ / /_ _| | |_ _/ _ \_ _| | | | |_ _|
28
+ \ \/\/ / | || |__ | | (_) || | | |_| | | |
29
+ \_/\_/ |___|____|___\___/ |_| \___/ |_|
30
+ '''
31
+
32
+ hex_str2int = lambda s : int(s, 16)
33
+ print_brg = lambda brg: brg.__dict__ if brg else None
34
+
35
+ def print_pkt(p):
36
+ print(datetime.datetime.now().strftime("%d/%m/%Y, %H:%M:%S"))
37
+ print(json.dumps(p, indent=4, default=lambda o: o.__dict__, sort_keys=True))
38
+
39
+ def print_warn(txt):
40
+ if txt:
41
+ utPrint(f"WARNING: {txt}","WARNING")
42
+
43
+ def mqtt_scan_start(test, duration):
44
+ utPrint("Scanning mqtt packets on {} for {} seconds...".format(test.gw, duration), "WARNING")
45
+ sys.stdout.flush()
46
+
47
+ def mqtt_scan_wait(test, duration):
48
+ utPrint("Scanning mqtt packets on {} for {} seconds...".format(test.gw, duration), "WARNING")
49
+ sys.stdout.flush()
50
+ chars = ["|", "/", "-", "\\"]
51
+ start_time = datetime.datetime.now()
52
+ i = 0
53
+ while True:
54
+ cur_duration = (datetime.datetime.now() - start_time).seconds
55
+ if cur_duration >= duration:
56
+ break
57
+ if pipeline_running():
58
+ sys.stdout.write(".")
59
+ else:
60
+ sys.stdout.write("\r"+chars[i%4]*20+" "+str(cur_duration)+" "+chars[i%4]*20+" {} pkts captured".format(len(test.mqttc._userdata["pkts"].data)))
61
+ sys.stdout.flush()
62
+ time.sleep(0.25)
63
+ i += 1
64
+ print("\n")
65
+
66
+ def print_update_wait(secs=1):
67
+ sys.stdout.write(".")
68
+ sys.stdout.flush()
69
+ time.sleep(secs)
70
+
71
+ def field_functionality_pass_fail_print(test, field, value=""):
72
+ print_string = "{}={}".format(field, value)
73
+ if value == "":
74
+ print_string = str(field)
75
+ if test.rc == TEST_FAILED:
76
+ utPrint(print_string + " functionality failed!", "RED")
77
+ elif test.rc == TEST_SKIPPED:
78
+ utPrint(print_string + " functionality skipped!", "WARNING")
79
+ else:
80
+ utPrint(print_string + " functionality passed!", "GREEN")
81
+
82
+ def test_run_print(test):
83
+ brg_txt = ""
84
+ if test.params:
85
+ params = " (params: {})".format(test.params)
86
+ else:
87
+ params = " (without params)"
88
+ if test.active_brg:
89
+ brg_txt = " ({}: {}".format("INTERNAL BRG" if test.internal_brg else "BRG", test.active_brg.id_str)
90
+ if test.brg1 and test.multi_brg:
91
+ brg_txt += " & " + test.brg1.id_str
92
+ brg_txt += ")"
93
+ log_txt = f"{SEP}==>> Running {test.module_name}{params}{brg_txt}{SEP}"
94
+ utPrint(log_txt, "BLUE")
95
+ utPrint("Test Information:\n", "HEADER")
96
+ test_json_print(test)
97
+ utPrint("Test Configuration:", "HEADER")
98
+ params = [{'name':p.name, 'value':p.value} for p in test.params]
99
+ utPrint(f""" - internal_brg={test.internal_brg}\n - brg0={print_brg(test.brg0)}
100
+ - brg1={print_brg(test.brg1)}\n - active_brg={print_brg(test.active_brg)}
101
+ - params={params}\n""")
102
+ cert_mqtt.write_to_mqtt_log_file(log_txt)
103
+ cert_data_sim.write_to_data_sim_log_file(log_txt)
104
+
105
+ def test_json_print(test):
106
+ for key, value in test.test_json.items():
107
+ if key == 'procedure':
108
+ print(f" {camelcase_to_title(key)}:")
109
+ for i in range(len(value)):
110
+ print(f" ({i}) {value[i]}")
111
+ else:
112
+ print(f" {camelcase_to_title(key)}: {value}")
113
+
114
+ def test_epilog_print(test):
115
+ if any([phase.rc == TEST_FAILED for phase in test.phases]):
116
+ utPrint(test.reason, "RED")
117
+ utPrint("==>> Test {} failed!".format(test.module_name), "RED")
118
+ else:
119
+ utPrint(test.reason, "GREEN")
120
+ utPrint("==>> Test {} passed!".format(test.module_name), "GREEN")
121
+
122
+ def functionality_run_print(func):
123
+ txt = "{0}==>> Running {1}\n".format(SEP, func)
124
+ utPrint(txt, "CYAN")
125
+ cert_mqtt.write_to_mqtt_log_file(txt)
126
+ cert_data_sim.write_to_data_sim_log_file(txt)
127
+
128
+
129
+ def generate_print_string(fields_and_values):
130
+ list_to_print = []
131
+ for f in fields_and_values:
132
+ list_to_print.append(str(f) + "=" + str(fields_and_values[f]))
133
+ return " & ".join(list_to_print)
134
+
135
+ def generate_log_file(test, val):
136
+ if type(val) == int or type(val) == str:
137
+ log_string = str(val)
138
+ else:
139
+ log_string = str(val[0])
140
+ for i in range(1,len(val)):
141
+ log_string += ","+ str(val[i])
142
+ if test.internal_brg:
143
+ log_string += "_internal_brg"
144
+
145
+ cert_mqtt.dump_pkts(test, log=log_string)
146
+
147
+ ENERGY_GRAPH_HTML = """
148
+ <h1 style="color:blue;text-align:center;">{}</h1>
149
+ <div style="width:80%;margin:auto;"><canvas id="myChart"></canvas></div>
150
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
151
+ <script>
152
+ const labels = {};
153
+ const data = {{labels: labels, datasets: [{}]}};
154
+ const config = {{type: 'line', data: data, options: {{}}}};
155
+ const myChart = new Chart(document.getElementById('myChart'), config);
156
+ </script>\n"""
157
+
158
+ def print_pass_or_fail(rc, text):
159
+ if rc:
160
+ utPrint(text+" PASSED!", "GREEN")
161
+ else:
162
+ utPrint(text+" FAILED!", "RED")
163
+
164
+ def utPrint(text, chosenColor="none"):
165
+ if chosenColor == "none":
166
+ print("\n"+text)
167
+ else:
168
+ print("\n"+(color(chosenColor.upper(), text)))
169
+
170
+ def format_for_table(string, width):
171
+ while len(string) < width:
172
+ if len(string) == width-1:
173
+ string+="_"
174
+ else:
175
+ string="_"+string+"_"
176
+ return string
177
+
178
+ def print_duration(test):
179
+ duration = str(datetime.datetime.now() - test.start_time).split(".")[0]
180
+ print(f"## Duration of the test until now is {duration}")
181
+ return test
@@ -0,0 +1,88 @@
1
+
2
+ from brg_certificate.cert_defines import *
3
+
4
+ import brg_certificate.wltPb_pb2 as wpb
5
+
6
+ def action_pb(msg: dict):
7
+ pb_msg = wpb.DownlinkMessage()
8
+ pb_msg.gatewayAction.action = msg[ACTION]
9
+ return pb_msg.SerializeToString()
10
+
11
+ def tx_pkt_pb(msg: dict):
12
+ pb_msg = wpb.DownlinkMessage()
13
+ pb_msg.txPacket.payload = bytes.fromhex(msg[TX_PKT])
14
+ pb_msg.txPacket.maxDurationMs = msg[TX_MAX_DURATION_MS]
15
+ pb_msg.txPacket.maxRetries = int(msg[TX_MAX_RETRIES])
16
+ return pb_msg.SerializeToString()
17
+
18
+ def brg_ota_pb(msg: dict):
19
+ pb_msg = wpb.DownlinkMessage()
20
+ pb_msg.bridgeUpgrade.bridgeId = msg[BRIDGE_ID]
21
+ pb_msg.bridgeUpgrade.imageDirUrl = msg[IMG_DIR_URL]
22
+ pb_msg.bridgeUpgrade.versionUuid = msg[VER_UUID_STR]
23
+ pb_msg.bridgeUpgrade.upgradeBlSd = msg[UPGRADE_BLSD]
24
+ pb_msg.bridgeUpgrade.rebootPacket = bytes.fromhex(msg[TX_PKT])
25
+ pb_msg.bridgeUpgrade.txMaxDurationMs = msg[TX_MAX_DURATION_MS]
26
+ pb_msg.bridgeUpgrade.txMaxRetries = msg[TX_MAX_RETRIES]
27
+ return pb_msg.SerializeToString()
28
+
29
+ def gw_cfg_pb(msg: dict):
30
+ pb_msg = wpb.DownlinkMessage()
31
+ pb_msg.gatewayConfig.location.lat = msg[LAT]
32
+ pb_msg.gatewayConfig.location.lng = msg[LNG]
33
+ if WIFI_VERSION in msg.keys():
34
+ pb_msg.gatewayConfig.interfaceSwVersion = msg[WIFI_VERSION]
35
+ if BLE_VERSION in msg.keys():
36
+ pb_msg.gatewayConfig.bleSwVersion = msg[BLE_VERSION]
37
+
38
+ for key, val in msg[ADDITIONAL].items():
39
+ # Skip GW_MODE since it doesn't exist today and harm the parsing in PB
40
+ if GW_MODE == key:
41
+ continue
42
+ pb_value = wpb.Value()
43
+ if isinstance(val, int):
44
+ pb_value.integerValue = val
45
+ elif isinstance(val, float):
46
+ pb_value.numberValue = val
47
+ elif isinstance(val, str):
48
+ pb_value.stringValue = val
49
+ elif isinstance(val, bool):
50
+ pb_value.boolValue = val
51
+ else:
52
+ raise ValueError(f"Unsupported value type for key '{key}': {type(val)}")
53
+ pb_msg.gatewayConfig.config[key].CopyFrom(pb_value)
54
+
55
+ return pb_msg.SerializeToString()
56
+
57
+ def custom_message_pb(msg: dict):
58
+ pb_msg = wpb.DownlinkMessage()
59
+
60
+ for key, val in msg.items():
61
+ pb_value = wpb.Value()
62
+ if isinstance(val, int):
63
+ pb_value.integerValue = val
64
+ elif isinstance(val, float):
65
+ pb_value.numberValue = val
66
+ elif isinstance(val, str):
67
+ pb_value.stringValue = val
68
+ elif isinstance(val, bool):
69
+ pb_value.boolValue = val
70
+ else:
71
+ raise ValueError(f"Unsupported value type for key '{key}': {type(val)}")
72
+ pb_msg.customMessage.entries[key].CopyFrom(pb_value)
73
+
74
+ return pb_msg.SerializeToString()
75
+
76
+ def downlink_to_pb(msg: dict):
77
+ if ACTION in msg.keys():
78
+ if msg[ACTION] == 0:
79
+ return tx_pkt_pb(msg)
80
+ elif msg[ACTION] == 1:
81
+ return brg_ota_pb(msg)
82
+ else:
83
+ return action_pb(msg)
84
+ elif GW_CONF in msg.keys():
85
+ return gw_cfg_pb(msg[GW_CONF])
86
+ else:
87
+ print("Can't find the message type to convert to protobuf. Using customMessage..")
88
+ return custom_message_pb(msg)