def createReceivingReport(): try: devicesToSend = [] strToSend = [] gps_stats = 66 bat = tools.getBatteryPercentage() st_bat = struct.pack(">I", bat) st_gps_stats = struct.pack(">I", gps_stats) whiteLen = struct.pack(">I", len(globalVars.devices_whitelist)) blackLen = struct.pack(">I", len(globalVars.devices_blacklist)) strToSend.append(struct.pack(">I", 173)[3]) # Protocol # strToSend.append(struct.pack(">I", 0)) # Command ID strToSend.append(globalVars.longitude[3]) # Gateway Longitude strToSend.append(globalVars.longitude[2]) # Gateway Longitude strToSend.append(globalVars.longitude[1]) # Gateway Longitude strToSend.append(globalVars.longitude[0]) # Gateway Longitude strToSend.append(globalVars.latitude[3]) # Gateway Latitude strToSend.append(globalVars.latitude[2]) # Gateway Latitude strToSend.append(globalVars.latitude[1]) # Gateway Latitude strToSend.append(globalVars.latitude[0]) # Gateway Latitude strToSend.append(st_gps_stats[3]) # Gateway GPS Status & Report type HARDCODE strToSend.append(st_bat[3]) strToSend.append(whiteLen[2]) strToSend.append(whiteLen[3]) strToSend.append(blackLen[2]) strToSend.append(blackLen[3]) tools.debug("Step 8 - Creating ack report: " + str(strToSend),'v') globalVars.lora_sent_acks.append(Device(addr="ackresp",raw=strToSend)) # tools.manage_devices_send(devicesToSend) except BaseException as e1: checkError("Step 5 - Error creating ack report", e1) return []
def joinLoRaWANModule(lora): try: # if reset_cause == machine.DEEPSLEEP_RESET and lora.has_joined(): if lora.has_joined(): print('Step 0.1 - Skipping LoRaWAN join, previously joined') else: ddd0 = '0000' + str(ubinascii.hexlify(machine.unique_id()).decode('utf-8')) # ddd = str(ubinascii.hexlify(lora.mac()).decode('utf-8')) print("DEV EUI: " + str(ddd0) + " - LoRa MAC: " + str(ubinascii.hexlify(lora.mac()).decode('utf-8'))) if globalVars.REGION == 'EU868': ddd = str(ubinascii.hexlify(lora.mac()).decode('utf-8')) elif globalVars.REGION == 'AS923': ddd = str(ubinascii.hexlify(b'\x70\xb3\xd5\x49\x90\x2c\x01\xba').decode('utf-8')) dev_eui = binascii.unhexlify(ddd) app_key = binascii.unhexlify('a926e5bb85271f2d') # not used leave empty loraserver.io nwk_key = binascii.unhexlify('a926e5bb85271f2da0440f2f4200afe3') lora.join(activation=LoRa.OTAA, auth=(dev_eui, app_key, nwk_key), timeout=0, dr=2) # AS923 always joins at DR2 if globalVars.REGION == 'AS923': prepare_channels_as923(lora, globalVars.LORA_CHANNEL, globalVars.LORA_NODE_DR) elif globalVars.REGION == 'EU868': prepare_channels_eu868(lora, globalVars.LORA_CHANNEL, globalVars.LORA_NODE_DR) print('Step 0.1 - Over the air network activation ... ' + str(globalVars.REGION), end='') while not lora.has_joined(): utime.sleep(2.5) print('.', end='') print('Joined to ' + str(globalVars.REGION) + '!!') globalVars.indicatorFrequencyOn = 100 lora.nvram_save() except BaseException as e: checkError("Step 0.1 - Error initializaing LoRaWAN module",e)
def getBatteryPercentage(): try: battery_offset = 375 if (globalVars.deviceID == 0): return 0 acc_bat = 0 counter = 0 for a in range(10): val = int(round(py.read_battery_voltage() * 1000)) if val > 0: acc_bat = acc_bat + val counter = counter + 1 time.sleep(0.2) level = int(round(acc_bat / counter)) + battery_offset max = 4200 min = 3400 if level > max: batt = 100 elif level < min: batt = 0 else: batt = int(round(100 - (((max - level) * 100) / (max - min)))) debug( "Step 5 - Battery level: " + str(batt) + " - Volts: " + str(level), 'v') return batt except BaseException as e: checkError("Step BAT - Error converting percentage battery level", e) return 0
def send_MQTT_message(device): global client try: tools.debug("MQTT Sending message", "v") mac_pos = [ str(device.addr)[i:i + 2] for i in range(0, len(str(device.addr)), 2) ] dev_addr = "" for num, a in enumerate(mac_pos): dev_addr = dev_addr + a if num < (len(mac_pos) - 1): dev_addr = dev_addr + ":" msg_to = { "gpsQuality": 10, "lastEventDate": int(utime.time()) * 1000, "latitude": 40.34155561314692, "login": "", "longitude": -3.8205912308152103, "numSerie": str(dev_addr).upper() } client.publish(topic=globalVars.mqtt_topic, msg=ujson.dumps(msg_to), retain=False, qos=1) return 1 except BaseException as e: checkError("Error sending POST - ", e) client.disconnect() check_connectivity(e) return 0
def mqtt_disconnect(): global client try: tools.debug("Disconnecting MQTT", "v") client.disconnect() except BaseException as e: checkError("Error connecting to MQTT", e)
def getResetCause(): try: reset_cause = machine.reset_cause() debug( "Reset cause: " + str(reset_cause) + " - Sleeping secs: " + str(globalVars.deepSleepSec), "v") try: globalVars.deepSleepSec = pycom.nvs_get('deepSleepSecs') except BaseException as ea: checkError("Error getting flash value of", ea) if globalVars.deepSleepSec == 0: debug("Coming from other reasons", "v") BeepBuzzer(1) elif globalVars.deepSleepSec > 0: pycom.nvs_set('deepSleepSecs', 0) globalVars.deepSleepSec = 0 if synchronizeRTC(): globalVars.flag_rtc_syncro = True BeepBuzzer(0.2) else: debug("Another reason for the reset", "v") BeepBuzzer(1) except BaseException as e: checkError("Error getting reset cause", e)
def forceRTC(dt, type_dt): global rtc try: # dt = pycom.nvs_get('rtc') if type_dt == "tuple": print("Step RTC - Forcing Tuple RTC to " + str(dt)) rtc.init(dt) elif type_dt == "epoch": print("Step RTC - Forcing Epoch RTC to " + str(int(dt))) rtc.init(utime.gmtime(int(dt))) utime.sleep(3) tools.debug("Setting time: " + str(int(utime.time())), "v") try: pycom.nvs_set('clock', str(int(utime.time()))) except OSError as err: tools.debug("Error setting RTC: " + str(err), "v") utime.sleep(5) try: dt_current = pycom.nvs_get('clock') except OSError as err: dt_current = -1 tools.debug("Error getting RTC: " + str(err), "v") tools.debug( "Current time: " + str(int(dt_current)) + " - RTC: " + str(getDatetime()), "v") except Exception as e1: checkError("Step RTC - Error initializing parametetr", e1)
def getAccelerometer(): try: if (globalVars.deviceID == 0): return [0, 0, 0] return acc.acceleration() except BaseException as e: checkError("Error gettion accelerometer", e)
def join_lora(): global lora global lora_socket try: joinLoRaWANModule(lora) initLoRaWANSocket(lora_socket, lora) utime.sleep(1) except BaseException as e: checkError("Error joining LoRa Network",e)
def initRTC(): global rtc try: dt = pycom.nvs_get('clock') print("Step RTC - Initializing RTC to " + str(int(dt))) rtc.init(utime.gmtime(int(dt))) utime.sleep(2) except Exception as e1: checkError("Step RTC - Error initializing parametetr", e1)
def sleepWiloc(period): try: #debug("In sleep method: " + str(globalVars.stop_sleep_flag) + " - LoRaSending: " + str(globalVars.flag_sent),'vv') gc.collect() if globalVars.stop_sleep_flag == False and globalVars.flag_sent == False: utime.sleep(period) except BaseException as e: checkError("Step BAT - Error getting battery level", e)
def random(): try: result = round( int(''.join(map(hex, uos.urandom(2))).replace('0x', ''), 16) / 100) # tools.debug("Scheduler - Random number: " + str(result), "v") return result except BaseException as e: checkError("Error getting random number", e)
def initLoRaWANSocket(lora_socket, lora): try: print("Step 0.2 - LoRa socket setup") # lora_socket = socket.socket(socket.AF_LORA, socket.SOCK_RAW) lora_socket.setsockopt(socket.SOL_LORA, socket.SO_DR, globalVars.LORA_NODE_DR) lora_socket.setsockopt(socket.SOL_LORA, socket.SO_CONFIRMED, 1) lora.callback(trigger=( LoRa.RX_PACKET_EVENT | LoRa.TX_PACKET_EVENT | LoRa.TX_FAILED_EVENT ), handler=lora_cb) lora_socket.setblocking(True) except BaseException as e: checkError("Step 0.2 - Error initializaing LoRaWAN Sockets", e)
def sleepProcess(): global gc try: debug("Step 8 - Going to sleep", 'v') feedWatchdog() gc.collect() globalVars.mac_scanned[:] = [] globalVars.scanned_frames[:] = [] sleepWiloc(int(globalVars.STANDBY_PERIOD)) except BaseException as e: checkError("Error going to light sleep", e)
def isInList(device, dmList): try: for dev in dmList: #debug("isinlist, device: " + str(device.addr) + " - compare: " + str(dev) + " - " + str(dev.addr), "vvv") if device.addr in dev.addr: return dev return None except BaseException as e: debug("Device: " + str(device.addr) + " - DmList: " + str(len(dmList)), "v") checkError("Error checking isinList", e)
def sendLoRaWANMessage(): global lora_socket try: if lora.has_joined(): sendAckMessageThread(lora_socket) else: tools.debug("Impossible to send because device is not joined", 'v') join_lora() if lora.has_joined(): sendAckMessageThread(lora_socket) except BaseException as eee: checkError("Error sending LoRaWAN message",eee)
def start(self): try: tools.debug("Scheduler - Daily Reset: " + globalVars.dailyreset, "v") tools.debug( "Scheduler - Start Downlink: " + globalVars.startDownlink, "v") tools.debug("Scheduler - End Downlink: " + globalVars.endDownlink, "v") tools.debug( "Scheduler - Starting scheduler, Time: " + str(utime.gmtime()), "v") except BaseException as e: checkError("Error on scheduler", e)
def checkDutyCycle(self): try: dt = utime.gmtime() if globalVars.flag_rtc_syncro == False: tools.debug( "Scheduler - RTC is not syncronized, so not possible to check the DutyCycle properly", "v") return dt_dm = str(dt[6]) + " " + str(dt[2]) + "-" + str( dt[1]) + "-" + str(dt[0]) + " " + str(dt[3]) + ":" + str( dt[4]) + ":" + str(dt[5]) tools.debug( "Scheduler - Current date: " + str(dt_dm) + " - Daily ends at: " + globalVars.dailyStandBy + "- Downlinks begin at: " + globalVars.startDownlink, "v") # --------- S1 (Sleep Cycle 1) - From End of the day to first Downlink message --------------- if dt[3] == int( globalVars.dailyStandBy.split(":") [0]) and dt[4] == int( globalVars.dailyStandBy.split(":")[1]) and dt[5] > int( globalVars.dailyStandBy.split(":")[2]) and dt[5] < ( int(globalVars.dailyStandBy.split(":")[2]) + 60): rnd_tmp_1 = tools.calculateSleepTime(globalVars.dailyStandBy, globalVars.startDownlink) tools.debug( "Scheduler - DutyCycle - Going to sleep because the day ends and until the downlinks begin: " + str(rnd_tmp_1), "v") tools.deepSleepWiloc(rnd_tmp_1) # --------- S2 - Backup sleeping process in case the device is still on when passing the maximum downlink time --------------- if dt[3] == int( globalVars.endDownlink.split(":")[0]) and dt[4] == int( globalVars.endDownlink.split(":")[1]) and dt[5] > int( globalVars.endDownlink.split(":")[2]) and dt[5] < ( int(globalVars.endDownlink.split(":")[2]) + 60): rnm_tmp = tools.calculateSleepTime(globalVars.endDownlink, globalVars.dailyStart) tools.debug( "Scheduler - DutyCycle - Going to sleep until the day begins: " + str(rnm_tmp), "v") tools.deepSleepWiloc(rnm_tmp) # ---------- Check if today is the day OFF -------------- if dt[6] in globalVars.dayOff: tools.debug( "Scheduler - Going to sleep because is the day OFF", "v") tools.deepSleepWiloc(86460) except BaseException as e: checkError("Error on scheduler", e)
def uart_task(): global uart try: # init with given baudrate while True: data = uart.read(1024) if data != None: debug("Serial received: " + str(data.decode('utf-8')), "v") checkFrameConfiguration(data, "Serial-0") except BaseException as e: checkError("Error thread UART Task", e) finally: checkWarning("Finally thread UART Task") _thread.start_new_thread(uart_task, ())
def mqtt_connect(): global client try: tools.debug("Connecting MQTT", "v") client = MQTTClient("gtw001_" + str(int(utime.time())), globalVars.mqtt_url, user=globalVars.mqtt_user, password=globalVars.mqtt_psw, port=1883) client.set_callback(response_callback) client.connect() client.subscribe(topic=globalVars.mqtt_topic) return client except BaseException as e: checkError("Error connecting to MQTT", e)
def bluetooth_scanner(): global ble_thread try: while True: try: tools.debug('BLE - Starting BLE scanner, RSSI: ' + str(int(globalVars.RSSI_NEAR_THRESHOLD,16) - 256) + " - RTC: " + str(int(utime.time())) + " - REFRESH: " + str(globalVars.MAX_REFRESH_TIME) + " - SCAN: " + str(int(globalVars.BLE_SCAN_PERIOD)) + " - SLEEP: " + str(int(globalVars.STANDBY_PERIOD)) + " - DEBUG: " + str(globalVars.debug_cc) ,'v') ble_thread = True bluetooth = Bluetooth() bluetooth.tx_power(Bluetooth.TX_PWR_SCAN, Bluetooth.TX_PWR_P9) bluetooth.start_scan(int(globalVars.BLE_SCAN_PERIOD)) while bluetooth.isscanning(): adv = bluetooth.get_adv() if adv: if 'WILOC_01' in str(bluetooth.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL)): data_raw = str(ubinascii.hexlify(adv.data).decode('utf-8')) if globalVars.MAC_TYPE == "LORA": mac_proc = data_raw[34:50] # LoRa MAC elif globalVars.MAC_TYPE == "BLE": mac_proc = str(ubinascii.hexlify(adv.mac).decode('utf-8')) # MAC BLE tools.debug('Name: '+ str(bluetooth.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL)) +' MAC: '+ str(mac_proc)+ ' RSSI: ' + str(adv.rssi) + ' DT: '+ str(int(utime.time())) +' RAW: ' + data_raw,'vvv') if mac_proc not in globalVars.mac_scanned: tools.debug('Step 1 - New device detected: ' + str(mac_proc),'vv') globalVars.mac_scanned.append(mac_proc) if adv.rssi >= (int(globalVars.RSSI_NEAR_THRESHOLD,16) - 256): wilocMain.checkListType(str(mac_proc), globalVars.ALARM_LIST_TYPE) globalVars.scanned_frames.append(Device(addr=mac_proc,rssi=adv.rssi, raw=data_raw)) elif 'WIL_C01' in str(bluetooth.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL)): data_raw = str(ubinascii.hexlify(adv.data).decode('utf-8')) mac_proc = str(ubinascii.hexlify(adv.mac).decode('utf-8')) # MAC BLE #tools.debug('BLE Name: '+ str(bluetooth.resolve_adv_data(adv.data, Bluetooth.ADV_NAME_CMPL)) +' - BLE MAC: '+ str(mac_proc)+ ' - RSSI: ' + str(adv.rssi) + ' - DT: '+ str(int(utime.time())) +' - RAW: ' + data_raw,'vvv') if mac_proc not in globalVars.mac_scanned: tools.debug('Step 1 - BLE New device detected: ' + str(mac_proc),'vv') globalVars.mac_scanned.append(mac_proc) if adv.rssi >= (int(globalVars.RSSI_NEAR_THRESHOLD,16) - 256): wilocMain.checkListType(str(mac_proc), globalVars.ALARM_LIST_TYPE) globalVars.scanned_frames.append(Device(addr=mac_proc,rssi=adv.rssi, raw=data_raw)) tools.debug('BLE - Stopping BLE scanner ' + str(int(utime.time())),'v') tools.sleepWiloc(int(globalVars.STANDBY_PERIOD)) except BaseException as ee1: checkError("Error scanning Bluetooth",ee1) tools.sleepWiloc(int(globalVars.STANDBY_PERIOD)) except BaseException as e: checkError("Error thread Bluetooth", e) ble_thread = False finally: ble_thread = False _thread.start_new_thread(bluetooth_scanner,())
def calculateDistance(latitude_init, longitude_init, latitude_end, longitude_end): try: debug("Input coordinates of two points:", "vv") slat = radians(float(latitude_init)) slon = radians(float(longitude_init)) elat = radians(float(latitude_end)) elon = radians(float(longitude_end)) dist = 6371.01 * acos( sin(slat) * sin(elat) + cos(slat) * cos(elat) * cos(slon - elon)) debug("The distance is %.2f meters." % dist, "vv") return dist except BaseException as e: checkError("Error calculating distance", e) return 0
def getGPS(): global py try: l76 = L76GNSS(py) coord = dict(latitude='', longitude='', HDOP=0.0) loop_counter = 5 if globalVars.gps_enabled == True: while coord['latitude'] == '' and coord[ 'longitude'] == '' and loop_counter > 0: debug("GPS Acquisition, loop: " + str(loop_counter), "v") loop_counter = loop_counter - 1 coord = l76.get_location(debug=False, tout=globalVars.gps_timeout) debug( "HDOP: " + str(coord['HDOP']) + "Latitude: " + str(coord['latitude']) + " - Longitude: " + str(coord['longitude']), 'v') if coord['latitude'] != '' and coord['longitude'] != '': haversine(coord['latitude'], coord['longitude'], globalVars.last_lat_tmp, globalVars.last_lon_tmp) big_endian_latitude = bytearray( struct.pack(">I", int(coord['latitude'] * 1000000))) big_endian_longitude = bytearray( struct.pack(">I", int(coord['longitude'] * 1000000))) dt = l76.getUTCDateTimeTuple(debug=False) if dt is not None: forceRTC(dt, "tuple") debug( "Updating timestamp from GPS - " + str(utime.time()) + " - GMT: " + str(utime.gmtime()), "v") globalVars.flag_rtc_syncro = True if (coord['latitude'] == '') or (coord['longitude'] == '') or (float( str(coord['HDOP'])) > float(globalVars.min_hdop)): return None, None else: globalVars.last_lat_tmp = coord['latitude'] globalVars.last_lon_tmp = coord['longitude'] return big_endian_latitude, big_endian_longitude except BaseException as e: checkError("Error getting GPS", e) return None, None
def deepSleepWiloc(period): global py try: pycom.nvs_set('deepSleepSecs', int(period)) dd = int(utime.time()) forceRTC(dd, 'epoch') debug( "Forcing DeepSleep for " + str(period) + " seconds" + " - Current dt: " + str(pycom.nvs_get('clock')) + " - RawDT: " + str(dd), "v") BuzzerTurnOff() utime.sleep(2) py.setup_sleep(period) utime.sleep(2) py.go_to_sleep(True) utime.sleep(2) except BaseException as e: checkError("Error going to light sleep", e)
def haversine(lat1, lon1, lat2, lon2): try: R = 6372800 # Earth radius in meters # lat1, lon1 = coord1 # lat2, lon2 = coord2 phi1, phi2 = math.radians(lat1), math.radians(lat2) dphi = math.radians(lat2 - lat1) dlambda = math.radians(lon2 - lon1) a = math.sin(dphi/2)**2 + \ math.cos(phi1)*math.cos(phi2)*math.sin(dlambda/2)**2 dist = 2 * R * math.atan2(math.sqrt(a), math.sqrt(1 - a)) debug("The distance is %s meters" % str(dist), "vv") return dist except BaseException as e: checkError("Error haversine method to calculate distance", e)
def checkCriticalBattery(): try: level = getBatteryPercentage() if (level <= globalVars.MIN_BATTERY_ACCEPTED): deepSleepWiloc(int(globalVars.LOW_BATTERY_SLEEPTIME)) return 2 if (level <= globalVars.LOW_BATTERY_VOLTAGE): if globalVars.BATT_EVENT_SENT == False: globalVars.BATT_EVENT_SENT = True return 1 else: # Loop to control hysteresis if globalVars.BATT_EVENT_SENT == True and level > ( globalVars.LOW_BATTERY_VOLTAGE + 5): globalVars.BATT_EVENT_SENT = False return 0 except BaseException as e: checkError("Step BAT - Error getting critical battery level", e)
def synchronizeRTC(): try: tools.debug("Synching RTC to " + str(int(utime.time())), "v") last_valid_time = 0 offset = 15 sleepTime = 0 try: sleepTime = pycom.nvs_get('deepSleepSecs') last_valid_time = pycom.nvs_get('clock') except Exception as e: checkError("Error getting DT", e) return False utime.sleep(2) current_dt = int(last_valid_time) + int(sleepTime) + offset forceRTC(int(current_dt), "epoch") return True except Exception as e: checkError("Error updating RTC", e) return False
def calculateSleepTime(start, end): try: # tools.debug("CalculateSleepTime", "v") diff_hour = int(end.split(':')[0]) - int(start.split(':')[0]) diff_min = int(end.split(':')[1]) - int(start.split(':')[1]) diff_sec = int(end.split(':')[2]) - int(start.split(':')[2]) total_diff = (diff_hour * 3600) + (diff_min * 60) + diff_sec if total_diff < 0: diff_hour__ref = int(globalVars.refDay.split(':')[0]) - int( start.split(':')[0]) diff_min__ref = int(globalVars.refDay.split(':')[1]) - int( start.split(':')[1]) diff_sec__ref = int(globalVars.refDay.split(':')[2]) - int( start.split(':')[2]) total_diff_ref = (diff_hour__ref * 3600) + (diff_min__ref * 60) + diff_sec__ref total_diff_end = (int(end.split(':')[0]) * 3600) + ( int(end.split(':')[1]) * 60) + int(end.split(':')[2]) total_diff = total_diff_ref + total_diff_end return total_diff except BaseException as e: checkError("Error on scheduler CalculatingSleepTime", e)
def checkOvernightCycle(self, frameid, framescounter): try: dt = utime.gmtime() if globalVars.flag_rtc_syncro == False: tools.debug( "Scheduler - RTC is not syncronized, so not possible to check the DutyCycle properly", "v") return current_wiloc_dt = str(dt[3]) + ":" + str(dt[4]) + ":" + str(dt[5]) slp_tm_day = tools.calculateSleepTime(current_wiloc_dt, globalVars.dailyStandBy) tools.debug( "Scheduler - Overnight start: " + globalVars.startDownlink + "- Overnight end: " + globalVars.endDownlink, "v") if slp_tm_day < 0: if frameid == framescounter: #------ Sleep cycle 3 (S3) --------- slp_tm = tools.calculateSleepTime(current_wiloc_dt, globalVars.dailyStart) tools.debug( "Overnight Scheduler - Going to sleep until day begins: " + str(slp_tm), "v") tools.deepSleepWiloc(slp_tm) else: #------ Sleep cycle 2 (S2) --------- rnd_secs = tools.random() tools.debug( "Overnight Scheduler - Going to sleep until next downlink: " + str(rnd_secs), "v") tools.deepSleepWiloc(rnd_secs) else: tools.debug( "Overnight Scheduler - Message received during the day, not going to sleep, current date: " + str(current_wiloc_dt) + " - Remaining day: " + str(slp_tm_day), "v") except BaseException as e: checkError("Error on scheduler OvernightCycle", e)
def lora_cb(lora): global lora_socket try: events = lora.events() if events & LoRa.RX_PACKET_EVENT: if lora_socket is not None: print("##### LoRa Rx Event Callback") lora_socket.settimeout(5) port = 0 try: frame, port = lora_socket.recvfrom(256) # longuest frame is +-220 except Exception as e2: print("Error downlink: " + str(e2)) checkFrameConfiguration(frame, "LoRaWAN") if events & LoRa.TX_PACKET_EVENT: print("tx_time_on_air: " + str(lora.stats().tx_time_on_air) + " ms @dr: " + str(lora.stats().sftx)) # BeepBuzzer(0.5) if events & LoRa.TX_FAILED_EVENT: print("#### Error TxEvent ####") except BaseException as e: checkError("Step DL - Error managing downlink", e)