class XBeeRadio(Node): def __init__(self): super().__init__('xbee_radio') self.declare_parameter('xbee_port', '/dev/xbee') self.declare_parameter('xbee_baud', 9600) self.declare_parameter('is_gsu', False) port = self.get_parameter('xbee_port').value baud = self.get_parameter('xbee_baud').value is_gsu = self.get_parameter('is_gsu').value # setup XBee radio and add callback to publish self.device = DigiMeshDevice(port, baud) self.device.open() self.device.add_data_received_callback(self.rx_callback) self.xnet = self.device.get_network() # if is_gsu: # self.set_aggregator() self._publisher = self.create_publisher(Packet, 'received', 10) self._subscription = self.create_subscription(Packet, 'transmit', self.tx_callback, 10) self._subscription def set_aggregator(self): ''' Call this if the device is connected to a groundstation ''' self.device.build_aggregate_routes() def tx_callback(self, msg): ''' ROS: callback for data wanting to be transmitted by the XBee radio ''' self.get_logger().info(f"Transmitting: {msg.data}") dev_addr = XBee64BitAddress.from_hex_string(msg.dev_addr) self.device.send_data_async_64( dev_addr, bytearray(struct.pack(str(len(msg.data)) + 'c', *msg.data))) def rx_callback(self, msg): ''' XBEE: callback for data received by the XBee radio ''' data = list(struct.unpack(str(len(msg.data)) + 'c', msg.data)) dev_addr = str(msg.remote_device.get_64bit_addr()) self.get_logger().info( f"Received: {data} from {dev_addr} at time: {msg.timestamp}") packet = Packet() packet.data = data packet.dev_addr = dev_addr packet.timestamp = msg.timestamp packet.is_broadcast = msg.is_broadcast self._publisher.publish(packet)
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
import time from digi.xbee.devices import DigiMeshDevice import xbee from xbee import ToERU, ToMAC, ToGCS, Orientation, LatLng, ManualControl, Geofence, SearchArea import threading import struct comm_port = "/dev/ttyUSB0" # can be swapped out for "/dev/ttyUSB0" for serial connection baud_rate = "9600" device = DigiMeshDevice(port=comm_port, baud_rate=baud_rate) device.open() network = device.get_network() network.start_discovery_process() while network.is_discovery_running(): time.sleep(.01) devices = {dev.get_node_id():dev._64bit_addr for dev in network.get_devices()} devices[device.get_node_id()] = device._64bit_addr print("This device's name: ", device.get_node_id()) print("Discovered ", devices) geo_bounds = [Geofence(True, [LatLng(1,0),LatLng(0,1),LatLng(-1,0),LatLng(0,-1)])] geo_bounds.append(Geofence(False, [LatLng(1,1),LatLng(2,1),LatLng(2,-1),LatLng(1,-1)])) area = SearchArea([LatLng(1,0),LatLng(0,1),LatLng(-1,0),LatLng(0,-1)]) hiker_pos = LatLng(35.083519, -120.534821)
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()