Esempio n. 1
0
class FppSettings:
    def __init__(self,
                 fpp_mode,
                 status=None,
                 xbee_com="/dev/ttyAMA0",
                 xbee_baud=9600):
        # Light.__init__(self, 15, 16, 18)
        # Define a mode so we know if we are the master or slave
        self.fpp_mode = fpp_mode
        self.status = self.get_fppd_status()
        # Check if the fpp player is up and running so we don't issue commands before its ready that may cause a crash.
        while self.status is None:
            print("Waiting for FPPD to start...")
            time.sleep(1)
            self.status = self.get_fppd_status()
        self.local_xbee = DigiMeshDevice(xbee_com, xbee_baud)
        while True:
            """ Attempt to connect to an xbee device that is plugged in. 
            Currently this will loop infinitely if no device is connected. 
            Needs to be updated with a timeout feature.
            Should finish loading the script then try and connect to a xbee device periodically. 
            """
            try:
                self.local_xbee.open()
                break
            except InvalidPacketException:
                print("Bad API packet try again")
            except InvalidOperatingModeException:
                print("Something went wrong lets try again.")
                self.local_xbee.close()
            except XBeeException:
                print("Check the device is connected!")

        self.xbee_network = self.local_xbee.get_network()
        # Save all the network devices in a list so we can find who to talk to.
        self.network_devices = self.get_devices()
        if self.fpp_mode == "slave":
            self.playlist_updated = False
            self.master_device = self.get_master_device()

    hostname = "http://" + socket.gethostname()
    playlists = requests.get(hostname + "/api/playlists").json()
    playlists.sort()
    number_of_playlist = {"number_of_playlist": len(playlists)}

    def get_master_device(self):
        for device in self.network_devices:
            if "master" in device.get_node_id():
                print("Found the master")
                return device

    def play_first_available_playlist(self):
        # print(self.get_playlist(self.playlists[0])["name"])
        playlist_name = self.get_playlist(self.playlists[0])["name"]
        subprocess.run(["/opt/fpp/src/fpp", "-p", playlist_name],
                       stdout=subprocess.DEVNULL)

    @staticmethod
    def convert_str_to_int(item):
        if item.isdigit():
            return int(item)
        else:
            return item

    def get_fppd_status(self):
        status = (subprocess.run(
            ["/opt/fpp/src/fpp", "-s"],
            stdout=subprocess.PIPE).stdout.decode("utf-8").strip("\n"))
        if "false" in status:
            return None
        status_list = status.split(",")
        if "" in status_list:
            status_list.remove("")
            status_list = list(map(self.convert_str_to_int, status_list))
            if not status_list[1]:
                self.play_first_available_playlist()
            status_list = dict(zip(key_list, status_list))
            return status_list

    # Incoming message from another FPP device. Try to call the command from the class methods.
    def get_command(self, command, address):
        if hasattr(self, command):
            print(command)
            method = getattr(self, command, lambda: "nothing")
            return method(address)
        elif command == "quit":
            pass
        elif "{" in command and command.endswith("}"):
            print(json.loads(command.replace("'", '"')))
        else:
            print("Unhandled Command: " + command)

    def get_devices(self):
        """" Method to discover all the xbees in the current network this method is blocking."""
        self.xbee_network.start_discovery_process()
        while self.xbee_network.is_discovery_running():
            time.sleep(0.5)
        return self.xbee_network.get_devices()

    def list_devices(self):
        for device in self.network_devices:
            print(device.get_64bit_addr())

    def get_playlist(self, playlist):
        # GET /playlist/:PlaylistName
        r = requests.get(self.hostname + "/api/playlist/" + playlist).json()
        # print(r)
        return r

    @staticmethod
    def define_playlist_values(playlist_json):
        """ Dictionary of only the values we need to transmit to slave players
            'playlistInfo': dict{
                total_duration: int*
                total_items: int*
            }

            'mainPlaylist': list of dicts [{
                sequenceName: str*
            }]
            'name': str
        """
        values_to_send = [
            {
                "total_duration":
                playlist_json["playlistInfo"]["total_duration"]
            },
            {
                "total_items": playlist_json["playlistInfo"]["total_items"]
            },
        ]
        for i, value in enumerate(playlist_json["mainPlaylist"]):
            values_to_send.append(
                {"sequenceName" + str(i): value["sequenceName"]})

        return values_to_send

    def send_playlists(self, address):
        # Ignore playlist request if we are a slave controller.
        if self.fpp_mode == "slave":
            return
        number_of_playlist_sent = 0
        for item in self.playlists:
            # Loop through the list of items in the playlists api.
            # Grab a json value from the specified playlist for sending
            values_to_send = self.define_playlist_values(
                self.get_playlist(item))
            # If we haven't send anything send out the total number of playlist.
            # So the reciever knows how many to expect.
            if number_of_playlist_sent == 0:
                self.send_message_to(str(self.number_of_playlist), address)
            # Send values and append which playlist number the belong too so we don't have repeating keys.
            for value in values_to_send:
                if type(value) == int:
                    self.send_message_to(str(value), address)
                elif type(value) == dict:
                    key = list(value)[0]
                    value[key + "_" +
                          str(number_of_playlist_sent)] = value.pop(key)
                    self.send_message_to(str(value), address)
                else:
                    self.send_message_to(value, address)
            number_of_playlist_sent += 1
        # Let the receiver know the transmission has finished.
        self.send_message_to('{"end_transmit": 1}', address)

    def send_message_all(self, message):
        for device in self.network_devices:
            self.local_xbee.send_data_async_64(device.get_64bit_addr(),
                                               message)

    def send_message_to(self, message, address):
        self.local_xbee.send_data_async_64(address, message)

    def restart_playlist(self, command_from):
        run = subprocess.run(["/opt/fpp/src/fpp", "-p", "play_0"],
                             stdout=subprocess.PIPE)
        print(run.stdout)

    def update_playlist(self):
        xbee_messages = []
        if not self.playlist_updated:
            self.send_message_to("send_playlists",
                                 self.master_device.get_64bit_addr())
            while not self.playlist_updated:
                xbee_message = self.local_xbee.read_data()
                if xbee_message and xbee_message != "restart_playlist":
                    xbee_message = xbee_message.data.decode()
                    print(xbee_message)
                    xbee_messages.append(ast.literal_eval(xbee_message))
                    # items = ["total_items", "sequence_name"]
                    if any("end_transmit" in key for key in xbee_messages):
                        xbee_messages = dict(ChainMap(*xbee_messages))
                        if self.post_playlist(xbee_messages):
                            break

    def post_playlist(self, playlist_data):
        playlist_name = "play_"
        for i in range(playlist_data["number_of_playlist"]):
            playlist_name += str(i)
            playlist_data_key = "_" + str(i)
            playlist_dict = {
                "name": playlist_name,
                "mainPlaylist": [],
                "playlistInfo": {
                    "total_duration":
                    playlist_data["total_duration" + playlist_data_key],
                    "total_items":
                    playlist_data["total_items" + playlist_data_key],
                },
            }
            for j in range(0,
                           playlist_data["total_items" + playlist_data_key]):
                sequence_dict = {
                    "type":
                    "sequence",
                    "enabled":
                    1,
                    "playOnce":
                    0,
                    "sequenceName":
                    playlist_data["sequenceName" + str(j) + playlist_data_key],
                }

                playlist_dict["mainPlaylist"].append(sequence_dict.copy())
            r = requests.post(
                self.hostname + "/api/playlist/" + playlist_dict["name"],
                json=playlist_dict,
            )
            if r.status_code:
                self.playlist_updated = True
            else:
                self.playlist_updated = False
        return True
Esempio n. 2
0
class NCDEnterprise:
    def __init__(self, serial_port, baud_rate, callback, kwargs={}):
        self.serial_port = serial_port
        self.baud_rate = baud_rate
        self.sensor_types = sensor_types()
        self.payload_type = {
            '122': 'power_up',
            '124': 'config_ack',
            '125': 'config_error',
            '127': 'sensor_data'
        }
        self.data = {}
        self.device = DigiMeshDevice(serial_port, baud_rate)
        self.device.open()
        self.callback = callback
        self.device.add_packet_received_callback(self.parse)
        self.error_callback = None
        if kwargs.get('error_handler'):
            self.error_callback = kwargs.get('error_handler')
        self.mems_buffer = {}

    def send_data_to_address(self, address, data):
        remote_device = RemoteDigiMeshDevice(
            self.device, XBee64BitAddress.from_hex_string(address))
        self.device.send_data(remote_device, data)

    def parse(self, xbee_packet):
        if not isinstance(xbee_packet, ATCommResponsePacket):
            data = xbee_packet.rf_data
            packet_type = self.payload_type[str(data[0])]
            # if the length is exactly 180, assume it is a mems data packet
            if (len(data) == 180):
                self.buffer_mems(data[1:], xbee_packet.x64bit_source_addr)
                return

            type = self.payload_type[str(data[0])]
            if (callable(getattr(self, packet_type))):
                getattr(self, packet_type)(data[1:],
                                           xbee_packet.x64bit_source_addr)
        else:
            print(xbee_packet)

    def buffer_mems(self, payload, source_address):
        source_address = str(source_address)
        if not self.mems_buffer.get(source_address, False):
            self.mems_buffer[source_address] = {}

        # If there is an ongoing error, process it. This is primarily to reduce
        # multiple instances of data corruption errors for the same dataset from
        # the sensor
        # If the dict has an error key
        if self.mems_buffer.get(source_address).get('timeout_exception_start'):
            # self.mems_buffer[source_address][payload[1]] = payload[5:]
            # if 500 millis have passed or this is a last packet (packet 12)
            if (self.get_current_millis() -
                    self.mems_buffer.get(source_address).get(
                        'timeout_exception_start')) > 500 or payload[1] == 12:
                self.mems_buffer[source_address][payload[1]] = payload[5:]
                # set error
                self.parse_error_callback(self.mems_buffer.get(source_address))
                # clear buffer
                self.mems_buffer[source_address] = {}
                # if the current payload is not a new dataset, do not process further
                if payload[1] != 1:
                    return

        if payload[1] not in self.mems_buffer.get(source_address):
            if len(self.mems_buffer.get(source_address)) == (int(payload[1]) -
                                                             1):
                # packet has been shifted left one, therefore data will start at byte 5.
                self.mems_buffer[source_address][payload[1]] = payload[5:]
            else:
                self.mems_buffer[source_address][payload[1]] = payload[5:]
                self.mems_buffer[source_address][
                    'timeout_exception_start'] = self.get_current_millis()
                return
        else:
            print('Duplicate keys error reported in V2 Mems Buffer')

        if (len(self.mems_buffer.get(source_address)) == 12):
            # packet from intercept has first byte trimmed. Shift expected position left.
            # i.e. node_id is byte 0 instead of documented one.
            self.parse_mems(self.mems_buffer.get(source_address),
                            source_address, payload)
            self.mems_buffer[source_address] = {}

    # TODO configuration commands put on hiatus. Need to import struct lib to ensure
    # packet compatibility. AKA sleep_time needs to be 3 bytes, if a single int is passed
    # it won't be. extensive testing needed.
    # def sensor_set_node_id_sleep(self, target_address, node_id, sleep_time, log = True):
    #     node_id = bytearray(node_id)
    #     sleep_time = bytearray(node_id)
    #     self.send_data_to_address(target_address, bytearray.fromhex('f702000000')+node_id+sleep_time)

    def parse_error_callback(self, message):
        if (callable(self.error_callback)):
            self.error_callback(message)

    def get_current_millis(self):
        return int(round(time.time() * 1000))

    def parse_mems(self, mems_dict, source_address, last_payload):
        readings = 29
        bytes_in_single = 6
        reading_array = {}
        for index, packet in enumerate(mems_dict):
            packet_data = mems_dict.get(packet)
            packet_array = {}
            for reading in range(1, readings + 1):
                if packet == 12 and reading >= 22:
                    break
                reading_array[((index * readings) +
                               reading)] = packet_data[(
                                   (reading - 1) *
                                   (bytes_in_single)):(reading - 1) *
                                                       (bytes_in_single) +
                                                       bytes_in_single]
        for sample in reading_array:
            sample_data = reading_array.get(sample)
            reading_array[sample] = {
                'rms_x': signInt(reduce(msbLsb, sample_data[0:2]), 16),
                'rms_y': signInt(reduce(msbLsb, sample_data[2:4]), 16),
                'rms_z': signInt(reduce(msbLsb, sample_data[4:6]), 16)
            }
        reading_array['temperature'] = msbLsb(last_payload[-6],
                                              last_payload[-5])
        parsed = {
            'nodeId':
            last_payload[0],
            'odr':
            last_payload[4],
            'firmware':
            last_payload[-4],
            'battery':
            msbLsb(last_payload[-3], last_payload[-2]) * 0.00322,
            'battery_percent':
            str((
                (msbLsb(last_payload[-3], last_payload[-2]) * 0.00322) - 1.3) /
                2.03 * 100) + "%",
            'counter':
            'NA',
            'sensor_type_id':
            40,
            'source_address':
            str(source_address),
            'sensor_type_string':
            'Vibration Time Series',
            'sensor_data':
            reading_array
        }
        self.callback(parsed)

    def sensor_data(self, payload, source_address):
        parsed = {
            'nodeId':
            payload[0],
            'firmware':
            payload[1],
            'battery':
            msbLsb(payload[2], payload[3]) * 0.00322,
            'battery_percent':
            str(((msbLsb(payload[2], payload[3]) * 0.00322) - 1.3) / 2.03 *
                100) + "%",
            'counter':
            payload[4],
            'sensor_type_id':
            msbLsb(payload[5], payload[6]),
            'source_address':
            str(source_address),
        }
        try:
            if (parsed['sensor_type_id'] == 80):
                parsed['sensor_type_string'] = 'One Channel Vibration Plus'
                parsed['sensor_data'] = type80(payload, parsed, source_address)

            else:
                parsed['sensor_type_string'] = self.sensor_types[str(
                    parsed['sensor_type_id'])]['name']
                parsed['sensor_data'] = self.sensor_types[str(
                    parsed['sensor_type_id'])]['parse'](payload[8:])

        except:
            parsed['sensor_type_string'] = 'Unsupported Sensor'
            parsed['sensor_data'] = payload
            self.callback(parsed)
        self.callback(parsed)

    def power_up(self, payload, source_address):
        return {
            'nodeId': payload[0],
            'sensor_type': msbLsb(payload[2], payload[3]),
            'source_address': str(source_address)
        }

    def config_ack(self, payload, source_address):
        return {
            'nodeId': payload[0],
            'counter': payload[1],
            'sensor_type': msbLsb(payload[2], payload[3]),
            'source_address': str(source_address)
        }

    def stop(self):
        self.device.close()

    def start(self):
        self.device.start()

    def config_error(self, payload):
        errors = [
            'Unknown', 'Invalid Command', 'Sensor Type Mismatch',
            'Node ID Mismatch', 'Apply change command failed',
            'Invalid API Packet Command Response Received After Apply Change Command',
            'Write command failed',
            'Invalid API Packet Command Response Received After Write Command',
            'Parameter Change Command Failed',
            'Invalid Parameter Change Command Response Received After Write Command',
            'Invalid/Incomplete Packet Received', 'Unknown', 'Unknown',
            'Unknown', 'Unknown', 'Invalid Parameter for Setup/Saving'
        ]
        return {
            'nodeId': payload[0],
            'sensor_type': msbLsb(payload[2], payload[3]),
            'error': payload[6],
            'error_message': errors[payload[6]],
            # last_sent: this.digi.lastSent
        }
Esempio n. 3
0
def main():

    DevList = {}
    FormedAll = []  # Ana Dig values after passing through Format()
    FormedAnalog = []  # Ana values after passing through Format()
    FormedDigital = []  # Dig values after passing through Format()

    example_text = '''Example usage:

    # Run discovery process on nework to find XBEE-IO devices
    ./xbeeio.py --port ttyUSB1 --discover
     
    # Readback all IO in default format and output style
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --readall

    # Read all IO and format analogue readings as rounded up voltages
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --readall --format volts

    # Read ADC inputs 0,1 & 3 and format readings as rounded up (TMP36) temperatures 
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --readadc 031 --format temp

    # Read ADC input 2 and format reading as rounded up 4-20mA 
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --readadc 2  --format 420

    # Read Dig Ins 0,1,2 & 3 
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --readdigin 0321

    # Read Dig In 0 
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --readdigin 0

    # Set Dig Out 0,1 & 3 Enabled
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --setdigouts 1101

    # Set Dig out 1 & 3 Enabled
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --setdigouts 0101

    # Set Dig Out 0 = Enabled
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --setdigouts 1000

    # Read all inputs and output in a logline format with analog voltage formatted as rounded up volts
    ./xbeeio.py --port ttyUSB1 --remote XBEE1 --readall --outputlogline --format volts

    '''
    ap = ArgParser(description='XBEE-IO Communication Script',
                   epilog=example_text,
                   formatter_class=argparse.RawDescriptionHelpFormatter)
    ap.add_argument("--port",
                    action='store',
                    dest='port',
                    help="serial port to connect to",
                    required=True)
    ap.add_argument("--discover",
                    action='store_true',
                    dest='show',
                    help="discover the digimesh network devices")
    ap.add_argument("--remote",
                    action='store',
                    dest='remote',
                    help="specify the target XBee NI identifier to talk to")
    ap.add_argument("--readall",
                    action='store_true',
                    dest='readall',
                    help="read back all input/output states")
    ap.add_argument("--format",
                    action='store',
                    dest='format',
                    help="printable format : volts|420|temp")
    ap.add_argument("--readadc",
                    action='store',
                    dest='anapins',
                    help="read back on or more analog inputs")
    ap.add_argument("--readdigin",
                    action='store',
                    dest='digipins',
                    help="read back one or more digital inputs")
    ap.add_argument("--outputstd",
                    action='store_true',
                    dest='std',
                    help="display the output in human readable form (default)")
    ap.add_argument("--outputlogline",
                    action='store_true',
                    dest='log',
                    help="display output in single data log format")
    ap.add_argument("--outputjson",
                    action='store_true',
                    dest='json',
                    help="display output in JSON format")
    ap.add_argument("--setdigouts",
                    action='store',
                    dest='setdigout',
                    help="set digouts as 4bit state <0123>")
    ap.add_argument("--quiet",
                    action='store_true',
                    dest='quiet',
                    help="suppress extra output")

    if len(sys.argv) == 1:
        ap.print_help(sys.stderr)
        sys.exit(1)
    args = ap.parse_args()

    PORT = '/dev/' + args.port

    try:

        if args.show:
            # Instatiate RPi Main Hub
            RPi = DigiMeshDevice(PORT, BAUD_RATE)
            RPi.open()

            DevList = ShowRemote(RPi, args.quiet)

            # Export network devices to file
            with open('network.conf', 'w+') as f:
                f.truncate(0)  # Reset file contents
                for node, address in DevList.items():
                    f.write(node + '|' + address + '\n')

        elif args.remote:

            # Instatiate RPi Main Hub
            RPi = DigiMeshDevice(PORT, BAUD_RATE)
            RPi.open()

            # Scan and save network if it does not exist
            if not os.path.exists('network.conf'):

                DevList = NetworkDiscovery(RPi, args.quiet)
                with open('network.conf', 'w+') as f:
                    for node, address in DevList.items():
                        f.write(node + '|' + address + '\n')

            # Repopulate dictionary for practicality
            with open("network.conf") as f:
                for line in f:
                    (node, address) = line.strip().split('|')
                    DevList.update({node: address})

            # Make sure target NodeID exists in network
            if args.remote in DevList.keys():
                RemoteXBee = RemoteDigiMeshDevice(
                    RPi,
                    XBee64BitAddress.from_hex_string(
                        str(DevList.get(args.remote))))
                #print("\n")
            else:
                print("Target NodeID: " + args.remote +
                      " not found in network.conf, try rescan first.")
                exit()

        if args.setdigout:
            SetDigitalOut(RemoteXBee, args.setdigout, args.quiet)

        # Either --readall
        if args.readall:
            args.anapins = '0,1,2,3'
            args.digipins = '0,1,2,3'
            readall = '0,1,2,3'

            ReadInputs = ReadAnalog(RemoteXBee, readall,
                                    args.quiet) + ReadDigital(
                                        RemoteXBee, readall, args.quiet)
            FormedAll = Format(RemoteXBee, ReadInputs, args.format,
                               args.anapins, args.digipins)

        # Or read specific
        else:
            if args.anapins:

                ReadInputs = ReadAnalog(RemoteXBee, args.anapins, args.quiet)
                FormedAnalog = Format(RemoteXBee, ReadInputs, args.format,
                                      args.anapins, '')  # No digital ''

            if args.digipins:

                ReadInputs = ReadDigital(RemoteXBee, args.digipins, args.quiet)
                FormedDigital = Format(RemoteXBee, ReadInputs, args.format, '',
                                       args.digipins)  # No analog ''

        if args.std:

            if FormedAll:
                Output(RemoteXBee, FormedAll, args.format, args.remote, 'std',
                       args.anapins, args.digipins, args.quiet)
            else:
                Output(RemoteXBee, FormedAnalog + FormedDigital, args.format,
                       args.remote, 'std', args.anapins, args.digipins,
                       args.quiet)

        elif args.json:

            if FormedAll:
                Output(RemoteXBee, FormedAll, args.format, args.remote, 'json',
                       args.anapins, args.digipins, args.quiet)
            else:
                Output(RemoteXBee, FormedAnalog + FormedDigital, args.format,
                       args.remote, 'json', args.anapins, args.digipins,
                       args.quiet)

        elif args.log:

            if FormedAll:
                Output(RemoteXBee, FormedAll, args.format, args.remote, 'log',
                       args.anapins, args.digipins, args.quiet)
            else:
                Output(RemoteXBee, FormedAnalog + FormedDigital, args.format,
                       args.remote, 'log', args.anapins, args.digipins,
                       args.quiet)

        else:

            if not args.show:
                if FormedAll:
                    Output(RemoteXBee, FormedAll, args.format, args.remote,
                           'default', args.anapins, args.digipins, args.quiet)
                else:
                    Output(RemoteXBee, FormedAnalog + FormedDigital,
                           args.format, args.remote, 'default', args.anapins,
                           args.digipins, args.quiet)

    finally:
        if RPi is not None and RPi.is_open():
            RPi.close()
Esempio n. 4
0
def main():
    print(" +----------------------------------------+")
    print(" | XBee Python discovery time chronometer |")
    print(" +----------------------------------------+\n")

    device = DigiMeshDevice(PORT, BAUD_RATE)

    try:
        device.open()

        protocolo = device.get_protocol()

        print(protocolo)

        funcao = device.get_role()

        print("Funcao: %s" % funcao)

        xbee_network = device.get_network()

        xbee_network.set_discovery_timeout(15)  # 15 seconds.

        xbee_network.clear()

        def callback_device_discovered(remote):
            print("Device discovered: %s" % remote)

        def callback_discovery_finished(status):
            if status == NetworkDiscoveryStatus.SUCCESS:
                print("Discovery process finished successfully.")
            else:
                print("There was an error discovering devices: %s" %
                      status.description)

        xbee_network.add_device_discovered_callback(callback_device_discovered)

        xbee_network.add_discovery_process_finished_callback(
            callback_discovery_finished)

        options = xbee_network.get_discovery_options()
        print(utils.hex_to_string(options))

        xbee_network.start_discovery_process()

        print("Discovering remote XBee devices...")

        while xbee_network.is_discovery_running():
            time.sleep(0.1)

        devices = xbee_network.get_devices()
        remote = devices[0]
        print(remote.get_protocol())
        print("Dispositivo %s " % devices[0].get_node_id())

        sourceAddres = device.get_64bit_addr()
        print("Endereco Local: %s" % sourceAddres)
        destAddress = device.get_dest_address()
        print("Endereco Destino: %s" % destAddress)

        modoDeOperacao = device.operating_mode
        print("Mode de Operacao: %s" % modoDeOperacao)

    finally:
        if device is not None and device.is_open():
            device.close()
Esempio n. 5
0
    info.start_timer()

    xbee_network.set_discovery_timeout(25)  # 25 seconds.
    xbee_network.clear()

    xbee_network.add_device_discovered_callback(callback_device_discovered)

    xbee_network.add_discovery_process_finished_callback(
        callback_discovery_finished)

    print("\t=-------- Starting Device discover process --------=\n")

    xbee_network.start_discovery_process()

    while xbee_network.is_discovery_running():
        sleep(0.1)

    print("\nNumber of devices found on the network:", info.n_devices)
    print("Discovery time of each device:", info.discovery_time)

finally:
    if device is not None and device.is_open():
        device.close()
        print("\n\t--------- Device Closed Successfully ---------\n")

print("*discovery time order to be printed in the csv file:",
      order_device_list(info))

send_data_to_csv(order_device_list(info))