コード例 #1
0
class modem_listener:
    def __init__(self, name, port, rate, verbose):
        self.name = name
        self.port = port
        self.baudrate = rate
        self.verbose = verbose
        self.modem = None
        self.counter = 1
        self.pub = rospy.Publisher('dash7', dash7, queue_size=1)
        self.pubrate = rospy.Rate(10)
        self.location = []

    def set_location(self, x, y, z):
        self.location = [x, y, z]

    def location_broadcast(self, msg):
        br = tf.TransformBroadcaster()
        br.sendTransform((self.location[0], self.location[1], self.location[2]),
                         tf.transformations.quaternion_from_euler(0.0, 0.0, 0.0, ),
                         msg.header.stamp,
                         self.name,
                         "base_link")

    def received_command_callback(self, cmd):
        print cmd
        if cmd.interface_status != None:
            if cmd.interface_status.operand.interface_id == 215:  # 215 is the interface_id that corresponds to DASH7
                rospy.loginfo("Received Dash7 message")
                message = dash7()
                message = self.parse(message, cmd)
                self.pub.publish(message)
                self.location_broadcast(message)


    def parse(self, message, cmd):
        rospy.loginfo("Parse Dash7 message")
        message.header.stamp    = rospy.Time.now()
        message.header.frame_id = str(cmd.interface_status.operand.interface_status.addressee.id)
        message.rx_address      = str(self.modem.uid)
        message.tx_address      = str(cmd.interface_status.operand.interface_status.addressee.id)
        message.rx_level        = cmd.interface_status.operand.interface_status.rx_level
        message.link_budget     = cmd.interface_status.operand.interface_status.link_budget
        message.channel_band    = cmd.interface_status.operand.interface_status.channel_header.channel_band.name
        message.channel_class   = cmd.interface_status.operand.interface_status.channel_header.channel_class.name
        message.channel_index   = cmd.interface_status.operand.interface_status.channel_index
        message.counter         = self.counter
        self.counter += 1
        return message

    def listen(self):
        rospy.loginfo("Port %s with Baudrate %s", self.port, self.baudrate)
        while True:
            try:
		rospy.loginfo('make modem connection')
                self.modem = Modem(self.port, self.baudrate, receive_callback=self.received_command_callback, show_logging=self.verbose)
                self.modem.start_reading()
                while not rospy.is_shutdown():
                    pass
            except Exception, e:
                raise e            
コード例 #2
0
ファイル: modem2mqtt.py プロジェクト: KwintenSchram/pyd7a
 def setup_modem(self):
     # we use Modem here only for reading the modem information, not for parsing.
     # reading the bytes from serial (after initial connect) is not done using Modem but overridden here
     modem = Modem(self.config.device, self.config.rate, None)
     self.serial = modem.dev
     self.modem_uid = modem.uid
     modem.stop_reading()  # so we can read the serial stream ourself
コード例 #3
0
ファイル: throughput_test.py プロジェクト: MOSAIC-LoPoW/pyd7a
  def __init__(self):
    self.argparser = argparse.ArgumentParser(
      fromfile_prefix_chars="@",
      description="Test throughput over 2 serial D7 modems"
    )

    self.argparser.add_argument("-n", "--msg-count", help="number of messages to transmit", type=int, default=10)
    self.argparser.add_argument("-p", "--payload-size", help="number of bytes of (appl level) payload to transmit", type=int, default=50)
    self.argparser.add_argument("-sw", "--serial-transmitter", help="serial device /dev file transmitter node", default=None)
    self.argparser.add_argument("-sr", "--serial-receiver", help="serial device /dev file receiver node", default=None)
    self.argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
    self.argparser.add_argument("-uid", "--unicast-uid", help="UID to use for unicast transmission, "
                                                              "when not using receiver "
                                                              "(in hexstring, for example 0xb57000009151d)", default=None)
    self.argparser.add_argument("-to", "--receiver-timeout", help="timeout for the receiver (in seconds)", type=int, default=10)
    self.argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
    self.config = self.argparser.parse_args()

    if self.config.serial_transmitter == None and self.config.serial_receiver ==  None:
      self.argparser.error("At least a transmitter or receiver is required.")

    if self.config.serial_receiver == None and self.config.unicast_uid == None:
      self.argparser.error("When running without receiver a --unicast-uid parameter is required.")

    if self.config.serial_transmitter == None:
      self.transmitter_modem = None
      print("Running without transmitter")
    else:
      self.transmitter_modem = Modem(self.config.serial_transmitter, self.config.rate, None, show_logging=self.config.verbose)
      access_profile = AccessProfile(
        scan_type_is_foreground=True,
        csma_ca_mode=CsmaCaMode.UNC,
        subnet=03,
        scan_automation_period=CT(0),
        subbands=[Subband(
          channel_header=ChannelHeader(channel_band=ChannelBand.BAND_433,
                                       channel_coding=ChannelCoding.PN9,
                                       channel_class=ChannelClass.NORMAL_RATE),
          channel_index_start=16,
          channel_index_end=16,
          eirp=10,
          ccao=0 # TODO
        )
        ]
      )

      print("Write Access Profile")
      write_ap_cmd = Command.create_with_write_file_action_system_file(file=AccessProfileFile(access_profile=access_profile, access_specifier=0))
      self.transmitter_modem.send_command(write_ap_cmd)

    if self.config.serial_receiver == None:
      self.receiver_modem = None
      print("Running without receiver")
    else:
      self.receiver_modem = Modem(self.config.serial_receiver, self.config.rate, self.receiver_cmd_callback, show_logging=self.config.verbose)
      self.receiver_modem.send_command(Command.create_with_write_file_action_system_file(DllConfigFile(active_access_class=2)))
      print("Receiver scanning on Access Class = 2")
コード例 #4
0
  def __init__(self):
    self.argparser = argparse.ArgumentParser(
      fromfile_prefix_chars="@",
      description="Test throughput over 2 serial D7 modems"
    )

    self.argparser.add_argument("-n", "--msg-count", help="number of messages to transmit", type=int, default=10)
    self.argparser.add_argument("-p", "--payload-size", help="number of bytes of (appl level) payload to transmit", type=int, default=50)
    self.argparser.add_argument("-sw", "--serial-transmitter", help="serial device /dev file transmitter node", default=None)
    self.argparser.add_argument("-sr", "--serial-receiver", help="serial device /dev file receiver node", default=None)
    self.argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
    self.argparser.add_argument("-uid", "--unicast-uid", help="UID to use for unicast transmission, "
                                                              "when not using receiver "
                                                              "(in hexstring, for example 0xb57000009151d)", default=None)
    self.argparser.add_argument("-to", "--receiver-timeout", help="timeout for the receiver (in seconds)", type=int, default=10)
    self.argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
    self.config = self.argparser.parse_args()

    configure_default_logger(self.config.verbose)

    if self.config.serial_transmitter == None and self.config.serial_receiver == None:
      self.argparser.error("At least a transmitter or receiver is required.")

    if self.config.serial_receiver == None and self.config.unicast_uid == None:
      self.argparser.error("When running without receiver a --unicast-uid parameter is required.")

    if self.config.serial_transmitter == None:
      self.transmitter_modem = None
      print("Running without transmitter")
    else:
      self.transmitter_modem = Modem(self.config.serial_transmitter, self.config.rate, None)
      access_profile = AccessProfile(
        channel_header=ChannelHeader(channel_band=ChannelBand.BAND_868,
                                     channel_coding=ChannelCoding.PN9,
                                     channel_class=ChannelClass.NORMAL_RATE),
        sub_profiles=[SubProfile(subband_bitmap=0x01, scan_automation_period=CT(exp=0, mant=0)), SubProfile(), SubProfile(), SubProfile()],
        sub_bands=[SubBand(
          channel_index_start=0,
          channel_index_end=0,
          eirp=10,
          cca=86 # TODO
        )]
      )

      print("Write Access Profile")
      write_ap_cmd = Command.create_with_write_file_action_system_file(file=AccessProfileFile(access_profile=access_profile, access_specifier=0))
      self.transmitter_modem.execute_command(write_ap_cmd, timeout_seconds=1)

    if self.config.serial_receiver == None:
      self.receiver_modem = None
      print("Running without receiver")
    else:
      self.receiver_modem = Modem(self.config.serial_receiver, self.config.rate, self.receiver_cmd_callback)
      self.receiver_modem.execute_command(Command.create_with_write_file_action_system_file(DllConfigFile(active_access_class=0x01)), timeout_seconds=1)
      print("Receiver scanning on Access Class = 0x01")
コード例 #5
0
    def listen(self):
        rospy.loginfo("Port %s with Baudrate %s", self.port, self.baudrate)
        while True:
            try:
		rospy.loginfo('make modem connection')
                self.modem = Modem(self.port, self.baudrate, receive_callback=self.received_command_callback, show_logging=self.verbose)
                self.modem.start_reading()
                while not rospy.is_shutdown():
                    pass
            except Exception, e:
                raise e            
コード例 #6
0
ファイル: modem-webgui.py プロジェクト: MOSAIC-LoPoW/pyd7a
def on_connect():
  global modem
  if modem == None:
    modem = Modem(config.device, config.rate, command_received_callback)
    modem.start_reading()

  print("modem: " + str(modem.uid))
  emit('module_info', {
    'uid': hex(modem.uid),
    'application_name': modem.firmware_version.application_name,
    'git_sha1': modem.firmware_version.git_sha1,
    'd7ap_version': modem.firmware_version.d7ap_version
  }, broadcast=True)
コード例 #7
0
ファイル: modem-webgui.py プロジェクト: KwintenSchram/pyd7a
def on_connect():
    global modem
    if modem == None:
        modem = Modem(config.device, config.rate, command_received_callback)
        modem.connect()

    logging.info("modem: " + str(modem.uid))
    emit('module_info', {
        'uid': modem.uid,
        'application_name': modem.firmware_version.application_name,
        'git_sha1': modem.firmware_version.git_sha1,
        'd7ap_version': modem.firmware_version.d7ap_version
    },
         broadcast=True)
コード例 #8
0
    def __init__(self):
        self.logs = []
        self.command = ""
        self.counter = 0

        argparser = argparse.ArgumentParser()

        argparser.add_argument("-s",
                               "--serial",
                               help="serial device /dev file",
                               default="/dev/tty.usbserial-FTGCT0HY")
        argparser.add_argument("-b",
                               "--baudrate",
                               help="baudrate for serial device",
                               type=int,
                               default=115200)

        config = argparser.parse_args()
        self.modem = Modem(config.serial, config.baudrate, show_logging=False)

        self.setup_screen()
コード例 #9
0
ファイル: modem2mqtt.py プロジェクト: Conaras/pyd7a
  def __init__(self):
    argparser = argparse.ArgumentParser()
    argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                           default="/dev/ttyACM0")
    argparser.add_argument("-di", "--device-id", help="gateway device-id", required=True)
    argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
    argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
    argparser.add_argument("-b", "--broker", help="mqtt broker hostname",
                             default="localhost")
    argparser.add_argument("-t", "--topic", help="mqtt topic",
                             default="/gw/{}")

    self.serial = None
    self.modem_uid = None
    self.bridge_count = 0
    self.next_report = 0

    self.config = argparser.parse_args()
    configure_default_logger(self.config.verbose)

    self.modem = Modem(self.config.device, self.config.rate, self.on_command_received, skip_alp_parsing=True)
    self.modem.connect()
    self.connect_to_mqtt()
コード例 #10
0
ファイル: chat.py プロジェクト: MOSAIC-LoPoW/pyd7a
  def __init__(self):
    self.logs = []
    self.command = ""
    self.counter = 0

    argparser = argparse.ArgumentParser()

    argparser.add_argument("-s", "--serial", help="serial device /dev file", 
                           default="/dev/tty.usbserial-FTGCT0HY")
    argparser.add_argument("-b", "--baudrate", help="baudrate for serial device", 
                           type=int, default=115200)

    config = argparser.parse_args()
    self.modem = Modem(config.serial, config.baudrate, show_logging=False)

    self.setup_screen()
コード例 #11
0
ファイル: modem_example.py プロジェクト: christophevg/pyd7a
from d7a.alp.command import Command
from d7a.alp.interface import InterfaceType
from d7a.d7anp.addressee import Addressee, IdType
from d7a.sp.configuration import Configuration
from d7a.sp.qos import QoS
from d7a.system_files.uid import UidFile
from modem.modem import Modem

argparser = argparse.ArgumentParser()
argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                            default="/dev/ttyUSB0")
argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
config = argparser.parse_args()

modem = Modem(config.device, config.rate)
modem.d7asp_fifo_flush(
  alp_command=Command.create_with_read_file_action_system_file(
    file=UidFile(),
    interface_type=InterfaceType.D7ASP,
    interface_configuration=Configuration(
      qos=QoS(resp_mod=QoS.RESP_MODE_NO),
      addressee=Addressee(
        access_class=0,
        id_type=IdType.BCAST
      )
    )
  )
)

コード例 #12
0
argparser = argparse.ArgumentParser()
argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                            default="/dev/ttyUSB0")
argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
argparser.add_argument("-c", "--channel-id", help="for example 868LP000 ; format FFFRCIII where FFF={433, 868, 915}, R={L, N, H, R (LORA)}, C={P (PN9), F (FEC), C (CW)} III=000...280", default="868LP000")
argparser.add_argument("-e", "--eirp", help="EIRP in dBm", type=int, default=14)
argparser.add_argument("-s", "--specifier", help="specifier for access profile. Default 0 is continuous scan, 1 is bg scan, 2+ is no scan", type=int, default=0)
argparser.add_argument("-sp", "--scan_automation_period", help="period in ms of scanning (786 ~ total 1 sec), 0 is continuous scan ", type=int, default=0)
argparser.add_argument("-sb", "--subband_bitmap", help="subband bitmap of subprofiles, 0 is default, 1 is scanning", type=int, default=0)
config = argparser.parse_args()
configure_default_logger(config.verbose)

ch = ChannelID.from_string(config.channel_id)

modem = Modem(config.device, config.rate, unsolicited_response_received_callback=received_command_callback)
modem.connect()

channel_header = ChannelHeader(
  channel_class=ch.channel_header.channel_class,
  channel_coding=ch.channel_header.channel_coding,
  channel_band=ch.channel_header.channel_band
)

access_profile = AccessProfile(
  channel_header=channel_header,
  sub_profiles=[SubProfile(subband_bitmap=config.subband_bitmap, scan_automation_period=CT.compress(config.scan_automation_period))] * 4,
  sub_bands=[SubBand(eirp=config.eirp, channel_index_start=ch.channel_index, channel_index_end=ch.channel_index)] * 8
)

modem.execute_command(
コード例 #13
0
argparser.add_argument("-v",
                       "--verbose",
                       help="verbose",
                       default=False,
                       action="store_true")
argparser.add_argument(
    "-f",
    "--file_id",
    help="File where we're writing the interface configuration",
    default=0x1D)
argparser.add_argument("-t", "--timeout", help="timeout", type=int, default=0)
config = argparser.parse_args()
configure_default_logger(config.verbose)

modem = Modem(config.device,
              config.rate,
              unsolicited_response_received_callback=received_command_callback)
modem.connect()

# D7 Example
interface_file = InterfaceConfigurationFile(
    interface_configuration=InterfaceConfiguration(
        interface_id=InterfaceType.D7ASP,
        interface_configuration=Configuration(
            qos=QoS(resp_mod=ResponseMode.RESP_MODE_PREFERRED,
                    retry_mod=RetryMode.RETRY_MODE_NO,
                    stop_on_err=False,
                    record=False),
            dorm_to=CT(),
            addressee=Addressee(nls_method=NlsMethod.NONE,
                                id_type=IdType.UID,
コード例 #14
0
ファイル: count.py プロジェクト: MOSAIC-LoPoW/pyd7a
from d7a.d7anp.addressee import Addressee, IdType
from d7a.sp.configuration import Configuration
from d7a.sp.qos import QoS
from d7a.system_files.uid import UidFile
from modem.modem import Modem

argparser = argparse.ArgumentParser()

argparser.add_argument("-s", "--serial", help="serial device /dev file", 
                       default="/dev/tty.usbserial-FTGCT0HY")
argparser.add_argument("-b", "--baudrate", help="baudrate for serial device", 
                       type=int, default=115200)

config = argparser.parse_args()

modem = Modem(config.serial, config.baudrate, show_logging=False)

cmd = Command.create_with_return_file_data_action(
    file_id=0x40,
    data=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    interface_type=InterfaceType.D7ASP,
    interface_configuration=Configuration(
      qos=QoS(resp_mod=QoS.RESP_MODE_NO),
      addressee=Addressee(
        access_class=0,
        id_type=IdType.BCAST
      )
    )
  )

last_message = 0
コード例 #15
0
    def __init__(self):
        argparser = argparse.ArgumentParser()
        argparser.add_argument("-d",
                               "--device",
                               help="serial device /dev file modem",
                               default="/dev/ttyACM0")
        argparser.add_argument("-r",
                               "--rate",
                               help="baudrate for serial device",
                               type=int,
                               default=115200)
        argparser.add_argument("-v",
                               "--verbose",
                               help="verbose",
                               default=False,
                               action="store_true")
        argparser.add_argument("-t",
                               "--token",
                               help="Access token for the TB gateway",
                               required=True)
        argparser.add_argument("-tb",
                               "--thingsboard",
                               help="Thingsboard hostname/IP",
                               default="localhost")
        argparser.add_argument("-p",
                               "--plugin-path",
                               help="path where plugins are stored",
                               default="")
        argparser.add_argument("-bp",
                               "--broker-port",
                               help="mqtt broker port",
                               default="1883")
        argparser.add_argument(
            "-l",
            "--logfile",
            help="specify path if you want to log to file instead of to stdout",
            default="")
        argparser.add_argument(
            "-k",
            "--keep-data",
            help=
            "Save data locally when Thingsboard is disconnected and send it when connection is restored.",
            default=True)
        argparser.add_argument(
            "-b",
            "--save-bandwidth",
            help="Send data in binary format to save bandwidth",
            action="store_true")
        argparser.add_argument("-sf",
                               "--skip-system-files",
                               help="Do not read system files on boot",
                               action="store_true")

        self.bridge_count = 0
        self.next_report = 0
        self.config = argparser.parse_args()
        self.log = logging.getLogger()

        formatter = logging.Formatter(
            '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
        if self.config.logfile == "":
            handler = logging.StreamHandler()
        else:
            handler = logging.FileHandler(self.config.logfile)

        handler.setFormatter(formatter)
        self.log.addHandler(handler)
        self.log.setLevel(logging.INFO)
        if self.config.verbose:
            self.log.setLevel(logging.DEBUG)

        self.tb = Thingsboard(self.config.thingsboard,
                              self.config.token,
                              self.on_mqtt_message,
                              persistData=self.config.keep_data)

        if self.config.plugin_path != "":
            self.load_plugins(self.config.plugin_path)

        self.modem = Modem(self.config.device, self.config.rate,
                           self.on_command_received,
                           self.config.save_bandwidth)
        connected = self.modem.connect()
        while not connected:
            try:
                self.log.warning("Not connected to modem, retrying ...")
                time.sleep(1)
                connected = self.modem.connect()
            except KeyboardInterrupt:
                self.log.info("received KeyboardInterrupt... stopping")
                self.tb.disconnect()
                exit(-1)
            except:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                lines = traceback.format_exception(exc_type, exc_value,
                                                   exc_traceback)
                trace = "".join(lines)
                self.log.error(
                    "Exception while connecting modem: \n{}".format(trace))

        # switch to continuous foreground scan access profile
        self.modem.execute_command(
            Command.create_with_write_file_action_system_file(
                DllConfigFile(active_access_class=0x01)),
            timeout_seconds=1)

        if self.config.save_bandwidth:
            self.log.info("Running in save bandwidth mode")
            if self.config.plugin_path is not "":
                self.log.warning(
                    "Save bandwidth mode is enabled, plugin files will not be used"
                )

        # update attribute containing git rev so we can track revision at TB platform
        git_sha = subprocess.check_output(["git", "describe",
                                           "--always"]).strip()
        ip = self.get_ip()
        self.tb.sendGwAttributes({
            'UID': self.modem.uid,
            'git-rev': git_sha,
            'IP': ip,
            'save bw': str(self.config.save_bandwidth)
        })

        self.log.info("Running on {} with git rev {} using modem {}".format(
            ip, git_sha, self.modem.uid))

        # read all system files on the local node to store as attributes on TB
        if not self.config.skip_system_files:
            self.log.info("Reading all system files ...")
            for file in SystemFiles().files.values():
                self.modem.execute_command_async(
                    Command.create_with_read_file_action_system_file(file))
コード例 #16
0
#!/usr/bin/env python3

import logging
# import signal
import sys

from challenge_status import ChallengeState
from modem import modem_io
from modem.modem import Modem

logging.basicConfig(level=logging.CRITICAL)

# s = signal.signal(signal.SIGINT, signal.SIG_IGN)

# Having the call here is only necessary for debug
ChallengeState.get()

print("Connected to /dev/ttyACM0")
sys.stdout.flush()

try:
    modem = Modem(modem_io.ConsoleIO())
    modem.run()
except KeyboardInterrupt:
    raise
except:
    sys.exit(1)

# signal.signal(signal.SIGINT, s)
コード例 #17
0
argparser.add_argument("-v",
                       "--verbose",
                       help="verbose",
                       default=False,
                       action="store_true")
argparser.add_argument("-t",
                       "--temperature",
                       help="temperature threshold value (in degrees C)",
                       type=float,
                       default=0)
config = argparser.parse_args()

configure_default_logger(config.verbose)

modem = Modem(config.device,
              config.rate,
              unsolicited_response_received_callback=received_command_callback)
modem.connect()

# command to be executed as an action: first do an arithmetic comparison of the sensor value with the supplied value...
query_sensor_file_cmd = Command(generate_tag_request_action=False)
query_sensor_file_cmd.add_action(
    RegularAction(operation=BreakQuery(operand=QueryOperand(
        type=QueryType.ARITH_COMP_WITH_VALUE,
        mask_present=False,
        params=ArithQueryParams(signed_data_type=False,
                                comp_type=ArithComparisonType.GREATER_THAN),
        compare_length=Length(2),
        compare_value=[
            ord(b) for b in struct.pack(">H", int(config.temperature * 10))
        ],
コード例 #18
0
import argparse

from d7a.alp.command import Command
from d7a.alp.interface import InterfaceType
from d7a.d7anp.addressee import Addressee, IdType
from d7a.sp.configuration import Configuration
from d7a.sp.qos import QoS, ResponseMode
from d7a.system_files.uid import UidFile
from modem.modem import Modem


# This example can be used with a node running the gateway app included in OSS-7.
# The gateway is continuously listening for foreground frames.
# Messages pushed by other nodes (running for example the sensor_push app) will be received by the gateway node,
# transmitted over serial and the received_command_callback() function below will be called.

def received_command_callback(cmd):
  print cmd

argparser = argparse.ArgumentParser()
argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                            default="/dev/ttyUSB0")
argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
config = argparser.parse_args()

modem = Modem(config.device, config.rate, unsolicited_response_received_callback=received_command_callback, show_logging=config.verbose)

while True:
  pass
コード例 #19
0
ファイル: chat.py プロジェクト: MOSAIC-LoPoW/pyd7a
class ChatClient(object):
  def __init__(self):
    self.logs = []
    self.command = ""
    self.counter = 0

    argparser = argparse.ArgumentParser()

    argparser.add_argument("-s", "--serial", help="serial device /dev file", 
                           default="/dev/tty.usbserial-FTGCT0HY")
    argparser.add_argument("-b", "--baudrate", help="baudrate for serial device", 
                           type=int, default=115200)

    config = argparser.parse_args()
    self.modem = Modem(config.serial, config.baudrate, show_logging=False)

    self.setup_screen()
  
  def setup_screen(self):
    self.screen = curses.initscr()
    curses.noecho()       # no echo, we will render it
    curses.cbreak()       #
    curses.curs_set(0)    # hide cursor, we will fake it with inverted space
    curses.halfdelay(1)   # wait for 1/10 second when waiting for input
    self.screen.keypad(1)
    self.setup()

  def setup(self):
    (self.height, self.width) = self.screen.getmaxyx()
    self.setup_viewer_window()
    self.setup_prompt()
    
    self.refresh_logger_window()
    self.refresh_prompt()

  def setup_viewer_window(self):
    # create a pad, taking up the entire window, but the last two lines
    self.logger = curses.newpad(self.height-1, self.width)

  def setup_prompt(self):
    # create a window, taking up the entire window, but the last two lines
    self.prompt = curses.newpad(2, self.width)
    name = "ChatClient"
    self.prompt.addstr(0, 0, name + " " * (self.width-len(name)), curses.A_REVERSE)
    self.prompt.addstr(1, 0, "> ")
    self.update_command()
  
  def update_command(self):
    w = len(self.command)
    self.prompt.addstr(1, 2, self.command)
    self.prompt.addstr(1, 2 + w, " ", curses.A_REVERSE) # cursor
    self.prompt.addstr(1, 3 + w, " " * (self.width - 4 - w))
    self.refresh_prompt()
  
  def clean_up(self, msg=""):
    self.clean_up_screen()

  def clean_up_screen(self):
    curses.nocbreak();
    self.screen.keypad(0);
    curses.echo()
    curses.endwin()

  def add(self, text, style=curses.A_NORMAL):
    text = text.replace('\0', '')
    self.logs.append({ "text": text, "style": style})
    self.refresh_logger_window()

  def log(self, *msg):
    string = " ".join(map(str, msg))
    for line in string.splitlines():
      self.add(line)
    
  def refresh_logger_window(self):
    (height, width) = self.screen.getmaxyx()
    self.logger.erase()
    for y, line in enumerate(self.logs[-height+2:]):
      self.logger.addstr(y, 0, line["text"], line["style"])
    self.logger.refresh(0, 0, 0, 0, height-3, width)

  def refresh_prompt(self):
    (height, width) = self.screen.getmaxyx()
    self.prompt.refresh(0, 0, height-2, 0, height, width)

  def process(self):
    while True:
      # handle input from user
      self.handle_input()
      # Read from D7 modem and decode packets/commands
      (cmds, info) = self.modem.read()
      if len(info["errors"]) < 1:
        if len(cmds) > 0:
          origin = cmds[0].interface_status.operation.operand.interface_status.addressee.id
          data   = cmds[0].actions[0].operation.operand.data
          self.add(str(origin) + ": " + ''.join(map(str, data)))

  def handle_input(self):
    c = self.prompt.getch()
    if c == curses.ERR: return
    elif c == curses.KEY_RESIZE:
      self.setup()
    elif c == curses.ascii.DEL or c == curses.ascii.BS:
      self.command = self.command[:-1]
    elif c == ord('\n'):
      self.send()
      self.command = ""
    else:
      self.command += chr(c)
    self.update_command()

  def send(self):
    cmd = Command.create_with_return_file_data_action(
      file_id=0x40,
      data=map(ord, list(self.command)),
      interface_type=InterfaceType.D7ASP,
      interface_configuration=Configuration(
        qos=QoS(resp_mod=QoS.RESP_MODE_NO),
        addressee=Addressee(
          access_class=0,
          id_type=IdType.BCAST
        )
      )
    )
    self.modem.d7asp_fifo_flush(alp_command=cmd)
    self.add("me: " + self.command, curses.A_REVERSE)
コード例 #20
0
ファイル: read_phy_status.py プロジェクト: Conaras/pyd7a
from util.logger import configure_default_logger


def received_command_callback(cmd):
  logging.info(cmd)
  if cmd.execution_completed:
      sys.exit(0)

argparser = argparse.ArgumentParser()
argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                            default="/dev/ttyUSB0")
argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
config = argparser.parse_args()
configure_default_logger(config.verbose)

modem = Modem(config.device, config.rate, unsolicited_response_received_callback=received_command_callback)
modem.connect()

answers = modem.execute_command(
  alp_command=Command.create_with_read_file_action_system_file(
    file=PhyStatusFile(channel_status_list_length=10)
  )
)

for answer in answers:
  logging.info("answer is {}".format(answer.__str__()))


コード例 #21
0
ファイル: modem2mqtt.py プロジェクト: Conaras/pyd7a
class Modem2Mqtt():

  def __init__(self):
    argparser = argparse.ArgumentParser()
    argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                           default="/dev/ttyACM0")
    argparser.add_argument("-di", "--device-id", help="gateway device-id", required=True)
    argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
    argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
    argparser.add_argument("-b", "--broker", help="mqtt broker hostname",
                             default="localhost")
    argparser.add_argument("-t", "--topic", help="mqtt topic",
                             default="/gw/{}")

    self.serial = None
    self.modem_uid = None
    self.bridge_count = 0
    self.next_report = 0

    self.config = argparser.parse_args()
    configure_default_logger(self.config.verbose)

    self.modem = Modem(self.config.device, self.config.rate, self.on_command_received, skip_alp_parsing=True)
    self.modem.connect()
    self.connect_to_mqtt()


  def connect_to_mqtt(self):
    self.connected_to_mqtt = False

    self.mq = mqtt.Client("", True, None, mqtt.MQTTv31)
    self.mq.on_connect = self.on_mqtt_connect
    self.mq.on_message = self.on_mqtt_message
    self.mqtt_topic_incoming = self.config.topic.format(self.config.device_id)
    #self.mqtt_topic_outgoing = self.config.topic.format(self.modem_uid)

    self.mq.connect(self.config.broker, 1883, 60)
    self.mq.loop_start()
    while not self.connected_to_mqtt: pass  # busy wait until connected
    logging.info("Connected to MQTT broker on {}, sending to topic {}".format(
      self.config.broker,
      self.mqtt_topic_incoming
    ))

  def on_mqtt_connect(self, client, config, flags, rc):
    #self.mq.subscribe(self.mqtt_topic_outgoing)
    self.connected_to_mqtt = True

  def on_mqtt_message(self, client, config, msg):
    logging.info("on_message") # TODO
    # try:    self.handle_msg(msg.topic, msg.payload)
    # except:
    #   exc_type, exc_value, exc_traceback = sys.exc_info()
    #   lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
    #   trace = "".join(lines)
    #   self.log("failed to handle incoming message:", msg.payload, trace)

  def publish_to_mqtt(self, msg):
    self.mq.publish(self.mqtt_topic_incoming, msg)

  def __del__(self): # pragma: no cover
    try:
      self.mq.loop_stop()
      self.mq.disconnect()
    except: pass

  def on_command_received(self, cmd):
    try:
      logging.info("Command received: binary ALP (size {})".format(len(cmd)))

      # publish raw ALP command to incoming ALP topic, we will not parse the file contents here (since we don't know how)
      # so pass it as an opaque BLOB for parsing in backend
      self.publish_to_mqtt(bytearray(cmd))
    except:
      exc_type, exc_value, exc_traceback = sys.exc_info()
      lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
      trace = "".join(lines)
      logging.error("Exception while processing command: \n{}".format(trace))

  def run(self):
    logging.info("Started")
    keep_running = True
    while keep_running:
      try:
        if platform.system() == "Windows":
          time.sleep(1)
        else:
          signal.pause()
      except KeyboardInterrupt:
        logging.info("received KeyboardInterrupt... stopping processing")
        keep_running = False

      self.report_stats()

  def keep_stats(self):
    self.bridge_count += 1

  def report_stats(self):
    if self.next_report < time.time():
      if self.bridge_count > 0:
        logging.info("bridged %s messages" % str(self.bridge_count))
        self.bridge_count = 0
      self.next_report = time.time() + 15 # report at most every 15 seconds
コード例 #22
0
                       help="serial device /dev file modem",
                       default="/dev/ttyACM1")
argparser.add_argument("-r",
                       "--rate",
                       help="baudrate for serial device",
                       type=int,
                       default=115200)
argparser.add_argument("-v",
                       "--verbose",
                       help="verbose",
                       default=False,
                       action="store_true")
config = argparser.parse_args()

modem = Modem(config.device,
              config.rate,
              receive_callback=received_command_callback,
              show_logging=config.verbose)

modem.d7asp_fifo_flush(
    alp_command=Command.create_with_read_file_action_system_file(
        file=UidFile(),
        interface_type=InterfaceType.D7ASP,
        interface_configuration=Configuration(
            qos=QoS(resp_mod=ResponseMode.RESP_MODE_ALL),
            addressee=Addressee(access_class=0x01, id_type=IdType.NOID))))

modem.start_reading()
while True:
    pass
コード例 #23
0
class Gateway:
    def __init__(self):
        argparser = argparse.ArgumentParser()
        argparser.add_argument("-d",
                               "--device",
                               help="serial device /dev file modem",
                               default="/dev/ttyACM0")
        argparser.add_argument("-r",
                               "--rate",
                               help="baudrate for serial device",
                               type=int,
                               default=115200)
        argparser.add_argument("-v",
                               "--verbose",
                               help="verbose",
                               default=False,
                               action="store_true")
        argparser.add_argument("-t",
                               "--token",
                               help="Access token for the TB gateway",
                               required=True)
        argparser.add_argument("-tb",
                               "--thingsboard",
                               help="Thingsboard hostname/IP",
                               default="localhost")
        argparser.add_argument("-p",
                               "--plugin-path",
                               help="path where plugins are stored",
                               default="")
        argparser.add_argument("-bp",
                               "--broker-port",
                               help="mqtt broker port",
                               default="1883")
        argparser.add_argument(
            "-l",
            "--logfile",
            help="specify path if you want to log to file instead of to stdout",
            default="")
        argparser.add_argument(
            "-k",
            "--keep-data",
            help=
            "Save data locally when Thingsboard is disconnected and send it when connection is restored.",
            default=True)
        argparser.add_argument(
            "-b",
            "--save-bandwidth",
            help="Send data in binary format to save bandwidth",
            action="store_true")
        argparser.add_argument("-sf",
                               "--skip-system-files",
                               help="Do not read system files on boot",
                               action="store_true")

        self.bridge_count = 0
        self.next_report = 0
        self.config = argparser.parse_args()
        self.log = logging.getLogger()

        formatter = logging.Formatter(
            '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
        if self.config.logfile == "":
            handler = logging.StreamHandler()
        else:
            handler = logging.FileHandler(self.config.logfile)

        handler.setFormatter(formatter)
        self.log.addHandler(handler)
        self.log.setLevel(logging.INFO)
        if self.config.verbose:
            self.log.setLevel(logging.DEBUG)

        self.tb = Thingsboard(self.config.thingsboard,
                              self.config.token,
                              self.on_mqtt_message,
                              persistData=self.config.keep_data)

        if self.config.plugin_path != "":
            self.load_plugins(self.config.plugin_path)

        self.modem = Modem(self.config.device, self.config.rate,
                           self.on_command_received,
                           self.config.save_bandwidth)
        connected = self.modem.connect()
        while not connected:
            try:
                self.log.warning("Not connected to modem, retrying ...")
                time.sleep(1)
                connected = self.modem.connect()
            except KeyboardInterrupt:
                self.log.info("received KeyboardInterrupt... stopping")
                self.tb.disconnect()
                exit(-1)
            except:
                exc_type, exc_value, exc_traceback = sys.exc_info()
                lines = traceback.format_exception(exc_type, exc_value,
                                                   exc_traceback)
                trace = "".join(lines)
                self.log.error(
                    "Exception while connecting modem: \n{}".format(trace))

        # switch to continuous foreground scan access profile
        self.modem.execute_command(
            Command.create_with_write_file_action_system_file(
                DllConfigFile(active_access_class=0x01)),
            timeout_seconds=1)

        if self.config.save_bandwidth:
            self.log.info("Running in save bandwidth mode")
            if self.config.plugin_path is not "":
                self.log.warning(
                    "Save bandwidth mode is enabled, plugin files will not be used"
                )

        # update attribute containing git rev so we can track revision at TB platform
        git_sha = subprocess.check_output(["git", "describe",
                                           "--always"]).strip()
        ip = self.get_ip()
        self.tb.sendGwAttributes({
            'UID': self.modem.uid,
            'git-rev': git_sha,
            'IP': ip,
            'save bw': str(self.config.save_bandwidth)
        })

        self.log.info("Running on {} with git rev {} using modem {}".format(
            ip, git_sha, self.modem.uid))

        # read all system files on the local node to store as attributes on TB
        if not self.config.skip_system_files:
            self.log.info("Reading all system files ...")
            for file in SystemFiles().files.values():
                self.modem.execute_command_async(
                    Command.create_with_read_file_action_system_file(file))

    def load_plugins(self, plugin_path):
        self.log.info("Searching for plugins in path %s" % plugin_path)
        manager = PluginManagerSingleton.get()
        manager.setPluginPlaces([plugin_path])
        manager.collectPlugins()

        for plugin in manager.getAllPlugins():
            self.log.info("Loading plugin '%s'" % plugin.name)

    def on_command_received(self, cmd):
        try:
            if self.config.save_bandwidth:
                self.log.info("Command received: binary ALP (size {})".format(
                    len(cmd)))
            else:
                self.log.info("Command received: {}".format(cmd))

            ts = int(round(time.time() * 1000))

            # publish raw ALP command to incoming ALP topic, we will not parse the file contents here (since we don't know how)
            # so pass it as an opaque BLOB for parsing in backend
            if self.config.save_bandwidth:
                self.tb.sendGwAttributes({
                    'alp':
                    binascii.hexlify(bytearray(cmd)),
                    'last_seen':
                    str(datetime.now().strftime("%y-%m-%d %H:%M:%S"))
                })
                return

            self.tb.sendGwAttributes({
                'alp':
                jsonpickle.encode(cmd),
                'last_seen':
                str(datetime.now().strftime("%y-%m-%d %H:%M:%S"))
            })

            node_id = self.modem.uid  # overwritten below with remote node ID when received over D7 interface
            # parse link budget (when this is received over D7 interface) and publish separately so we can visualize this in TB
            if cmd.interface_status != None and cmd.interface_status.operand.interface_id == 0xd7:
                interface_status = cmd.interface_status.operand.interface_status
                node_id = '{:x}'.format(interface_status.addressee.id)
                linkBudget = interface_status.link_budget
                rxLevel = interface_status.rx_level
                lastConnect = "D7-" + interface_status.get_short_channel_string(
                )
                self.tb.sendDeviceTelemetry(node_id, ts, {
                    'lb': linkBudget,
                    'rx': rxLevel
                })
                self.tb.sendDeviceAttributes(node_id, {
                    'last_conn': lastConnect,
                    'last_gw': self.modem.uid
                })

            # store returned file data as attribute on the device
            for action in cmd.actions:
                if type(action.operation) is ReturnFileData:
                    data = ""
                    if action.operation.file_data_parsed is not None:
                        if not self.config.save_bandwidth:
                            # for known system files we transmit the parsed data
                            data = jsonpickle.encode(
                                action.operation.file_data_parsed)
                            file_id = "File {}".format(
                                action.operand.offset.id)
                            self.tb.sendGwAttributes({file_id: data})
                    else:
                        # try if plugin can parse this file
                        parsed_by_plugin = False
                        if not self.config.save_bandwidth:
                            for plugin in PluginManagerSingleton.get(
                            ).getAllPlugins():
                                for name, value, datapoint_type in plugin.plugin_object.parse_file_data(
                                        action.operand.offset,
                                        action.operand.length,
                                        action.operand.data):
                                    parsed_by_plugin = True
                                    if isinstance(value, int) or isinstance(
                                            value, float):
                                        self.tb.sendDeviceTelemetry(
                                            node_id, ts, {name: value})
                                    else:
                                        self.tb.sendDeviceAttributes(
                                            node_id, {name: value})

                        if not parsed_by_plugin:
                            # unknown file content, just transmit raw data
                            data = jsonpickle.encode(action.operand)
                            filename = "File {}".format(
                                action.operand.offset.id)
                            if action.operation.systemfile_type != None:
                                filename = "File {} ({})".format(
                                    SystemFileIds(
                                        action.operand.offset.id).name,
                                    action.operand.offset.id)
                            self.tb.sendDeviceAttributes(
                                node_id, {filename: data})

        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)
            trace = "".join(lines)
            self.log.error(
                "Exception while processing command: \n{}".format(trace))

    def on_mqtt_message(self, client, config, msg):
        try:
            payload = json.loads(msg.payload)
            uid = payload['device']
            method = payload['data']['method']
            request_id = payload['data']['id']
            self.log.info(
                "Received RPC command of type {} for {} (request id {})".
                format(method, uid, request_id))
            # if uid != self.modem.uid:
            #   self.log.info("RPC command not for this modem ({}), skipping".format(self.modem.uid))
            #   return

            if method == "execute-alp-async":
                try:
                    cmd = payload['data']['params']
                    self.log.info("Received command through RPC: %s" % cmd)

                    self.modem.execute_command_async(cmd)
                    self.log.info("Executed ALP command through RPC")

                    # TODO when the command is writing local files we could read them again automatically afterwards, to make sure the digital twin is updated
                except Exception as e:
                    self.log.exception("Could not deserialize: %s" % e)
            elif method == "alert":
                # TODO needs refactoring so different methods can be supported in a plugin, for now this is very specific case as an example
                self.log.info("Alert (payload={})".format(msg.payload))
                if msg.payload != "true" and msg.payload != "false":
                    self.log.info("invalid payload, skipping")
                    return

                file_data = 0
                if msg.payload == "true":
                    file_data = 1

                self.log.info("writing alert file")
                self.modem.execute_command_async(
                    Command.create_with_write_file_action(
                        file_id=0x60,
                        offset=4,
                        data=[file_data],
                        interface_type=InterfaceType.D7ASP,
                        interface_configuration=Configuration(
                            qos=QoS(resp_mod=ResponseMode.RESP_MODE_ALL),
                            addressee=Addressee(access_class=0x11,
                                                id_type=IdType.NOID))))

            else:
                self.log.info("RPC method not supported, skipping")
                return
        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)
            trace = "".join(lines)
            msg_info = "no msg info (missing __dict__ attribute)"  # TODO because of out of date paho??
            if hasattr(msg, '__dict__'):
                msg_info = str(msg.__dict__)

            self.log.error(
                "Exception while processing MQTT message: {} callstack:\n{}".
                format(msg_info, trace))

    def run(self):
        self.log.info("Started")
        keep_running = True
        while keep_running:
            try:
                if platform.system() == "Windows":
                    time.sleep(1)
                else:
                    signal.pause()
            except KeyboardInterrupt:
                self.log.info(
                    "received KeyboardInterrupt... stopping processing")
                self.tb.disconnect()
                keep_running = False

            self.report_stats()

    def keep_stats(self):
        self.bridge_count += 1

    def report_stats(self):
        if self.next_report < time.time():
            if self.bridge_count > 0:
                self.log.info("bridged %s messages" % str(self.bridge_count))
                self.bridge_count = 0
            self.next_report = time.time(
            ) + 15  # report at most every 15 seconds

    def get_ip(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            # doesn't even have to be reachable
            s.connect(('10.255.255.255', 1))
            IP = s.getsockname()[0]
        except:
            IP = '127.0.0.1'
        finally:
            s.close()
        return IP
コード例 #24
0
ファイル: modem_example.py プロジェクト: MOSAIC-LoPoW/pyd7a
from d7a.sp.qos import QoS, ResponseMode
from d7a.system_files.uid import UidFile
from modem.modem import Modem


def received_command_callback(cmd):
  print cmd

argparser = argparse.ArgumentParser()
argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                            default="/dev/ttyUSB0")
argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
config = argparser.parse_args()

modem = Modem(config.device, config.rate, receive_callback=received_command_callback, show_logging=config.verbose)
modem.d7asp_fifo_flush(
  alp_command=Command.create_with_read_file_action_system_file(
    file=UidFile(),
    interface_type=InterfaceType.D7ASP,
    interface_configuration=Configuration(
      qos=QoS(resp_mod=ResponseMode.RESP_MODE_ALL),
      addressee=Addressee(
        access_class=0,
        id_type=IdType.NOID
      )
    )
  )
)

modem.start_reading()
コード例 #25
0
class ChatClient(object):
    def __init__(self):
        self.logs = []
        self.command = ""
        self.counter = 0

        argparser = argparse.ArgumentParser()

        argparser.add_argument("-s",
                               "--serial",
                               help="serial device /dev file",
                               default="/dev/tty.usbserial-FTGCT0HY")
        argparser.add_argument("-b",
                               "--baudrate",
                               help="baudrate for serial device",
                               type=int,
                               default=115200)

        config = argparser.parse_args()
        self.modem = Modem(config.serial, config.baudrate, show_logging=False)

        self.setup_screen()

    def setup_screen(self):
        self.screen = curses.initscr()
        curses.noecho()  # no echo, we will render it
        curses.cbreak()  #
        curses.curs_set(0)  # hide cursor, we will fake it with inverted space
        curses.halfdelay(1)  # wait for 1/10 second when waiting for input
        self.screen.keypad(1)
        self.setup()

    def setup(self):
        (self.height, self.width) = self.screen.getmaxyx()
        self.setup_viewer_window()
        self.setup_prompt()

        self.refresh_logger_window()
        self.refresh_prompt()

    def setup_viewer_window(self):
        # create a pad, taking up the entire window, but the last two lines
        self.logger = curses.newpad(self.height - 1, self.width)

    def setup_prompt(self):
        # create a window, taking up the entire window, but the last two lines
        self.prompt = curses.newpad(2, self.width)
        name = "ChatClient"
        self.prompt.addstr(0, 0, name + " " * (self.width - len(name)),
                           curses.A_REVERSE)
        self.prompt.addstr(1, 0, "> ")
        self.update_command()

    def update_command(self):
        w = len(self.command)
        self.prompt.addstr(1, 2, self.command)
        self.prompt.addstr(1, 2 + w, " ", curses.A_REVERSE)  # cursor
        self.prompt.addstr(1, 3 + w, " " * (self.width - 4 - w))
        self.refresh_prompt()

    def clean_up(self, msg=""):
        self.clean_up_screen()

    def clean_up_screen(self):
        curses.nocbreak()
        self.screen.keypad(0)
        curses.echo()
        curses.endwin()

    def add(self, text, style=curses.A_NORMAL):
        text = text.replace('\0', '')
        self.logs.append({"text": text, "style": style})
        self.refresh_logger_window()

    def log(self, *msg):
        string = " ".join(map(str, msg))
        for line in string.splitlines():
            self.add(line)

    def refresh_logger_window(self):
        (height, width) = self.screen.getmaxyx()
        self.logger.erase()
        for y, line in enumerate(self.logs[-height + 2:]):
            self.logger.addstr(y, 0, line["text"], line["style"])
        self.logger.refresh(0, 0, 0, 0, height - 3, width)

    def refresh_prompt(self):
        (height, width) = self.screen.getmaxyx()
        self.prompt.refresh(0, 0, height - 2, 0, height, width)

    def process(self):
        while True:
            # handle input from user
            self.handle_input()
            # Read from D7 modem and decode packets/commands
            (cmds, info) = self.modem.read()
            if len(info["errors"]) < 1:
                if len(cmds) > 0:
                    origin = cmds[
                        0].interface_status.operation.operand.interface_status.addressee.id
                    data = cmds[0].actions[0].operation.operand.data
                    self.add(str(origin) + ": " + ''.join(map(str, data)))

    def handle_input(self):
        c = self.prompt.getch()
        if c == curses.ERR: return
        elif c == curses.KEY_RESIZE:
            self.setup()
        elif c == curses.ascii.DEL or c == curses.ascii.BS:
            self.command = self.command[:-1]
        elif c == ord('\n'):
            self.send()
            self.command = ""
        else:
            self.command += chr(c)
        self.update_command()

    def send(self):
        cmd = Command.create_with_return_file_data_action(
            file_id=0x40,
            data=map(ord, list(self.command)),
            interface_type=InterfaceType.D7ASP,
            interface_configuration=Configuration(
                qos=QoS(resp_mod=QoS.RESP_MODE_NO),
                addressee=Addressee(access_class=0, id_type=IdType.BCAST)))
        self.modem.d7asp_fifo_flush(alp_command=cmd)
        self.add("me: " + self.command, curses.A_REVERSE)
コード例 #26
0
count = 0

argparser = argparse.ArgumentParser()
argparser.add_argument("-d",
                       "--device",
                       help="serial device /dev file modem",
                       default="/dev/ttyUSB0")
argparser.add_argument("-r",
                       "--rate",
                       help="baudrate for serial device",
                       type=int,
                       default=115200)
argparser.add_argument("-v",
                       "--verbose",
                       help="verbose",
                       default=False,
                       action="store_true")
config = argparser.parse_args()

modem = Modem(config.device,
              config.rate,
              receive_callback=received_command_callback,
              show_logging=config.verbose)

modem.start_reading()

# Program loop
while True:
    pass
コード例 #27
0
ファイル: engineering_mode.py プロジェクト: Conaras/pyd7a
print("Using mode {} for channel {} with TX EIRP {} dBm".format(config.mode, config.channel_id, config.eirp))
mode = EngineeringModeMode.from_string(config.mode)

if (mode == EngineeringModeMode.ENGINEERING_MODE_MODE_PER_TX) and (config.timeout == 0):
  config.timeout = 255

emFile = EngineeringModeFile(mode=mode, flags=0, timeout=config.timeout, channel_id=ch, eirp=config.eirp)

stop = False

signal.signal(signal.SIGINT, cleanup)

print(list(emFile))

if not config.not_exe:
  modem = Modem(config.device, config.rate, unsolicited_response_received_callback=received_command_callback,
                rebooted_callback=rebooted_callback)
  modem.connect()

  cmd = Command()

  if config.forward:
    cmd.add_forward_action(
      interface_type=InterfaceType.D7ASP,
      interface_configuration=Configuration(
        qos=QoS(resp_mod=ResponseMode.RESP_MODE_PREFERRED, retry_mod=RetryMode.RETRY_MODE_NO),
        addressee=Addressee(
          access_class=0x11,
          id_type=IdType.NBID,
          id=CT.compress(2)
        )
      )
コード例 #28
0
ファイル: throughput_test.py プロジェクト: MOSAIC-LoPoW/pyd7a
class ThroughtPutTest:
  def __init__(self):
    self.argparser = argparse.ArgumentParser(
      fromfile_prefix_chars="@",
      description="Test throughput over 2 serial D7 modems"
    )

    self.argparser.add_argument("-n", "--msg-count", help="number of messages to transmit", type=int, default=10)
    self.argparser.add_argument("-p", "--payload-size", help="number of bytes of (appl level) payload to transmit", type=int, default=50)
    self.argparser.add_argument("-sw", "--serial-transmitter", help="serial device /dev file transmitter node", default=None)
    self.argparser.add_argument("-sr", "--serial-receiver", help="serial device /dev file receiver node", default=None)
    self.argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
    self.argparser.add_argument("-uid", "--unicast-uid", help="UID to use for unicast transmission, "
                                                              "when not using receiver "
                                                              "(in hexstring, for example 0xb57000009151d)", default=None)
    self.argparser.add_argument("-to", "--receiver-timeout", help="timeout for the receiver (in seconds)", type=int, default=10)
    self.argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
    self.config = self.argparser.parse_args()

    if self.config.serial_transmitter == None and self.config.serial_receiver ==  None:
      self.argparser.error("At least a transmitter or receiver is required.")

    if self.config.serial_receiver == None and self.config.unicast_uid == None:
      self.argparser.error("When running without receiver a --unicast-uid parameter is required.")

    if self.config.serial_transmitter == None:
      self.transmitter_modem = None
      print("Running without transmitter")
    else:
      self.transmitter_modem = Modem(self.config.serial_transmitter, self.config.rate, None, show_logging=self.config.verbose)
      access_profile = AccessProfile(
        scan_type_is_foreground=True,
        csma_ca_mode=CsmaCaMode.UNC,
        subnet=03,
        scan_automation_period=CT(0),
        subbands=[Subband(
          channel_header=ChannelHeader(channel_band=ChannelBand.BAND_433,
                                       channel_coding=ChannelCoding.PN9,
                                       channel_class=ChannelClass.NORMAL_RATE),
          channel_index_start=16,
          channel_index_end=16,
          eirp=10,
          ccao=0 # TODO
        )
        ]
      )

      print("Write Access Profile")
      write_ap_cmd = Command.create_with_write_file_action_system_file(file=AccessProfileFile(access_profile=access_profile, access_specifier=0))
      self.transmitter_modem.send_command(write_ap_cmd)

    if self.config.serial_receiver == None:
      self.receiver_modem = None
      print("Running without receiver")
    else:
      self.receiver_modem = Modem(self.config.serial_receiver, self.config.rate, self.receiver_cmd_callback, show_logging=self.config.verbose)
      self.receiver_modem.send_command(Command.create_with_write_file_action_system_file(DllConfigFile(active_access_class=2)))
      print("Receiver scanning on Access Class = 2")



  def start(self):
    self.received_commands = defaultdict(list)
    payload = range(self.config.payload_size)

    if self.receiver_modem != None:
      addressee_id = self.receiver_modem.uid
    else:
      addressee_id = int(self.config.unicast_uid, 16)

    if self.transmitter_modem != None:

      print("\n==> broadcast, with QoS, transmitter active access class = 0 ====")
      self.transmitter_modem.send_command(Command.create_with_write_file_action_system_file(DllConfigFile(active_access_class=0)))
      interface_configuration = Configuration(
        qos=QoS(resp_mod=ResponseMode.RESP_MODE_ANY),
        addressee=Addressee(
          access_class=2,
          id_type=IdType.NOID
        )
      )

      self.start_transmitting(interface_configuration=interface_configuration, payload=payload)
      self.wait_for_receiver(payload)

      print("\n==> broadcast, no QoS, transmitter active access class = 0 ====")
      self.transmitter_modem.send_command(Command.create_with_write_file_action_system_file(DllConfigFile(active_access_class=0)))
      interface_configuration = Configuration(
        qos=QoS(resp_mod=ResponseMode.RESP_MODE_NO),
        addressee=Addressee(
          access_class=2,
          id_type=IdType.NOID
        )
      )

      self.start_transmitting(interface_configuration=interface_configuration, payload=payload)
      self.wait_for_receiver(payload)

      print("\n==> unicast, with QoS, transmitter active access class = 0")
      interface_configuration = Configuration(
        qos=QoS(resp_mod=ResponseMode.RESP_MODE_ANY),
        addressee=Addressee(
          access_class=2,
          id_type=IdType.UID,
          id=addressee_id
        )
      )

      self.start_transmitting(interface_configuration=interface_configuration, payload=payload)
      self.wait_for_receiver(payload)

      print("\n==> unicast, no QoS, transmitter active access class = 0")
      interface_configuration = Configuration(
        qos=QoS(resp_mod=ResponseMode.RESP_MODE_NO),
        addressee=Addressee(
          access_class=2,
          id_type=IdType.UID,
          id=addressee_id
        )
      )

      self.start_transmitting(interface_configuration=interface_configuration, payload=payload)
      self.wait_for_receiver(payload)
    else:
      # receive only
      self.receiver_modem.start_reading()
      self.wait_for_receiver(payload)

  def start_transmitting(self, interface_configuration, payload):
    print("Running throughput test with payload size {} and interface_configuration {}\n\nrunning ...\n".format(len(payload), interface_configuration))

    if self.receiver_modem != None:
      self.received_commands = defaultdict(list)
      self.receiver_modem.start_reading()

    command = Command.create_with_return_file_data_action(
      file_id=0x40,
      data=payload,
      interface_type=InterfaceType.D7ASP,
      interface_configuration=interface_configuration
    )

    start = time.time()

    for i in range(self.config.msg_count):
      sys.stdout.write("{}/{}\r".format(i + 1, self.config.msg_count))
      sys.stdout.flush()
      self.transmitter_modem.d7asp_fifo_flush(command)

    end = time.time()
    print("transmitter: sending {} messages completed in: {} s".format(self.config.msg_count, end - start))
    print("transmitter: throughput = {} bps with a payload size of {} bytes".format(
      (self.config.msg_count * self.config.payload_size * 8) / (end - start), self.config.payload_size)
    )

  def wait_for_receiver(self, payload):
    if self.receiver_modem == None:
      print("Running without receiver so we are not waiting for messages to be received ...")
    else:
      start = time.time()
      total_recv = 0
      while total_recv < self.config.msg_count and time.time() - start < self.config.receiver_timeout:
        total_recv = sum(len(v) for v in self.received_commands.values())
        time.sleep(2)
        print("waiting for receiver to finish ... (current nr of recv msgs: {})".format(total_recv))

      print("finished receiving or timeout")
      self.receiver_modem.cancel_read()
      payload_has_errors = False
      for sender_cmd in self.received_commands.values():
        for cmd in sender_cmd:
          if type(cmd.actions[0].op) != ReturnFileData and cmd.actions[0].operand.data != payload:
            payload_has_errors = True
            print ("receiver: received unexpected command: {}".format(cmd))

      if payload_has_errors == False and total_recv == self.config.msg_count:
        print("receiver: OK: received {} messages with correct payload:".format(total_recv))
        for sender, cmds in self.received_commands.items():
          print("\t{}: {}".format(sender, len(cmds)))
      else:
        print("receiver: NOK: received messages {}:".format(total_recv))
        for sender, cmds in self.received_commands.items():
          print("\t{}: {}".format(sender, len(cmds)))

  def receiver_cmd_callback(self, cmd):
    if cmd.interface_status != None:
      uid = cmd.interface_status.operand.interface_status.addressee.id
      self.received_commands[uid].append(cmd)
    else:
      print("Unexpected cmd received, reboot?\n\t{}".format(cmd))
コード例 #29
0
 def setup_modem(self):
   # we use Modem here only for reading the modem information, not for parsing.
   # reading the bytes from serial (after initial connect) is not done using Modem but overridden here
   modem = Modem(self.config.device, self.config.rate, None, show_logging=self.config.verbose)
   self.serial = modem.dev
   self.modem_uid = modem.uid
コード例 #30
0
class Gateway:
    def __init__(self):
        argparser = argparse.ArgumentParser()
        argparser.add_argument("-d",
                               "--device",
                               help="serial device /dev file modem",
                               default="/dev/ttyACM0")
        argparser.add_argument("-r",
                               "--rate",
                               help="baudrate for serial device",
                               type=int,
                               default=115200)
        argparser.add_argument("-v",
                               "--verbose",
                               help="verbose",
                               default=False,
                               action="store_true")
        argparser.add_argument("-b",
                               "--broker",
                               help="mqtt broker hostname",
                               default="localhost")
        argparser.add_argument("-bp",
                               "--broker-port",
                               help="mqtt broker port",
                               default="1883")
        argparser.add_argument("-p",
                               "--plugin-path",
                               help="path where plugins are stored",
                               default="")
        argparser.add_argument(
            "-l",
            "--logfile",
            help="specify path if you want to log to file instead of to stdout",
            default="")

        self.bridge_count = 0
        self.next_report = 0
        self.mq = None
        self.mqtt_topic_incoming_alp = ""
        self.connected_to_mqtt = False

        self.config = argparser.parse_args()

        self.log = logging.getLogger()
        formatter = logging.Formatter(
            '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
        if self.config.logfile == "":
            handler = logging.StreamHandler()
        else:
            handler = logging.FileHandler(self.config.logfile)

        handler.setFormatter(formatter)
        self.log.addHandler(handler)
        self.log.setLevel(logging.INFO)
        if self.config.verbose:
            self.log.setLevel(logging.DEBUG)

        if self.config.plugin_path != "":
            self.load_plugins(self.config.plugin_path)

        self.modem = Modem(self.config.device, self.config.rate,
                           self.on_command_received)
        self.connect_to_mqtt()

        # update attribute containing git rev so we can track revision at TB platform
        git_sha = subprocess.check_output(["git", "describe",
                                           "--always"]).strip()
        ip = self.get_ip()
        # TODO ideally this should be associated with the GW device itself, not with the modem in the GW
        # not clear how to do this using TB-GW
        self.publish_to_topic(
            "/gateway-info",
            jsonpickle.json.dumps({
                "git-rev": git_sha,
                "ip": ip,
                "device": self.modem.uid
            }))

        # make sure TB knows the modem device is connected. TB considers the device connected as well when there is regular
        # telemetry data. This is fine for remote nodes which will be auto connected an disconnected in this way. But for the
        # node in the gateway we do it explicitly to make sure it always is 'online' even when there is no telemetry to be transmitted,
        # so that we can reach it over RPC
        self.publish_to_topic(
            "sensors/connect",
            jsonpickle.json.dumps({"serialNumber": self.modem.uid}))

        self.log.info("Running on {} with git rev {} using modem {}".format(
            ip, git_sha, self.modem.uid))

        # read all system files on the local node to store as attributes on TB
        self.log.info("Reading all system files ...")
        for file in SystemFiles().files.values():
            self.modem.execute_command_async(
                Command.create_with_read_file_action_system_file(file))

    def load_plugins(self, plugin_path):
        self.log.info("Searching for plugins in path %s" % plugin_path)
        manager = PluginManagerSingleton.get()
        manager.setPluginPlaces([plugin_path])
        manager.collectPlugins()

        for plugin in manager.getAllPlugins():
            self.log.info("Loading plugin '%s'" % plugin.name)

    def on_command_received(self, cmd):
        try:
            self.log.info("Command received: {}".format(cmd))
            if not self.connected_to_mqtt:
                self.log.warning("Not connected to MQTT, skipping")
                return

            # publish raw ALP command to incoming ALP topic, we will not parse the file contents here (since we don't know how)
            # so pass it as an opaque BLOB for parsing in backend
            self.publish_to_topic(
                self.mqtt_topic_incoming_alp,
                jsonpickle.json.dumps({'alp_command': jsonpickle.encode(cmd)}))

            node_id = self.modem.uid  # overwritten below with remote node ID when received over D7 interface
            # parse link budget (when this is received over D7 interface) and publish separately so we can visualize this in TB
            if cmd.interface_status != None and cmd.interface_status.operand.interface_id == 0xd7:
                interface_status = cmd.interface_status.operand.interface_status
                node_id = '{:x}'.format(interface_status.addressee.id)
                self.publish_to_topic(
                    "/parsed/telemetry",
                    jsonpickle.json.dumps({
                        "gateway": self.modem.uid,
                        "device": node_id,
                        "name": "link_budget",
                        "value": interface_status.link_budget,
                        "timestamp": str(datetime.now())
                    }))

                self.publish_to_topic(
                    "/parsed/telemetry",
                    jsonpickle.json.dumps({
                        "gateway": self.modem.uid,
                        "device": node_id,
                        "name": "rx_level",
                        "value": -interface_status.rx_level,
                        "timestamp": str(datetime.now())
                    }))

                self.publish_to_topic(
                    "/parsed/attribute",
                    jsonpickle.json.dumps({
                        "device":
                        node_id,
                        "name":
                        "last_network_connection",
                        "value":
                        "D7-" + interface_status.get_short_channel_string(),
                    }))

            # store returned file data as attribute on the device
            for action in cmd.actions:
                if type(action.operation) is ReturnFileData:
                    data = ""
                    if action.operation.file_data_parsed is not None:
                        # for known system files we transmit the parsed data
                        data = jsonpickle.encode(
                            action.operation.file_data_parsed)
                    else:
                        # try if plugin can parse this file
                        parsed_by_plugin = False
                        for plugin in PluginManagerSingleton.get(
                        ).getAllPlugins():
                            for name, value, datapoint_type in plugin.plugin_object.parse_file_data(
                                    action.operand.offset,
                                    action.operand.data):
                                parsed_by_plugin = True
                                self.publish_to_topic(
                                    "/parsed/" + datapoint_type.name,
                                    jsonpickle.json.dumps({
                                        "device": node_id,
                                        "name": name,
                                        "value": value,
                                    }))
                        if not parsed_by_plugin:
                            # unknown file content, just transmit raw data
                            data = jsonpickle.encode(action.operand)
                            filename = "File {}".format(
                                action.operand.offset.id)
                            if action.operation.systemfile_type != None:
                                filename = "File {} ({})".format(
                                    SystemFileIds(
                                        action.operand.offset.id).name,
                                    action.operand.offset.id)

                            self.publish_to_topic(
                                "/filecontent",
                                jsonpickle.json.dumps({
                                    "device": node_id,
                                    "file-id": filename,
                                    "file-data": data
                                }))
        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)
            trace = "".join(lines)
            self.log.error(
                "Exception while processing command: \n{}".format(trace))

    def connect_to_mqtt(self):
        self.log.info("Connecting to MQTT broker on {}".format(
            self.config.broker))
        self.connected_to_mqtt = False
        self.mq = mqtt.Client("", True, None, mqtt.MQTTv31)
        self.mqtt_topic_incoming_alp = "/DASH7/incoming/{}".format(
            self.modem.uid)
        self.mq.on_connect = self.on_mqtt_connect
        self.mq.on_message = self.on_mqtt_message
        self.mq.connect(self.config.broker, self.config.broker_port, 60)
        self.mq.loop_start()
        while not self.connected_to_mqtt:
            pass  # busy wait until connected
        self.log.info("Connected to MQTT broker on {}".format(
            self.config.broker))

    def on_mqtt_connect(self, client, config, flags, rc):
        self.mq.subscribe("sensor/#")
        self.connected_to_mqtt = True

    def on_mqtt_message(self, client, config, msg):
        try:
            topic_parts = msg.topic.split('/')
            method = topic_parts[3]
            uid = topic_parts[1]
            request_id = topic_parts[4]
            self.log.info(
                "Received RPC command of type {} for {} (request id {})".
                format(method, uid, request_id))
            if uid != self.modem.uid:
                self.log.info(
                    "RPC command not for this modem ({}), skipping".format(
                        self.modem.uid))
                return

            if method == "execute-alp-async":
                try:
                    cmd = jsonpickle.decode(jsonpickle.json.loads(msg.payload))
                    self.log.info("Received command through RPC: %s" % cmd)

                    self.modem.execute_command_async(cmd)
                    self.log.info("Executed ALP command through RPC")

                    # TODO when the command is writing local files we could read them again automatically afterwards, to make sure the digital twin is updated
                except Exception as e:
                    self.log.exception("Could not deserialize: %s" % e)
            elif method == "alert":
                # TODO needs refactoring so different methods can be supported in a plugin, for now this is very specific case as an example
                self.log.info("Alert (payload={})".format(msg.payload))
                if msg.payload != "true" and msg.payload != "false":
                    self.log.info("invalid payload, skipping")
                    return

                file_data = 0
                if msg.payload == "true":
                    file_data = 1

                self.log.info("writing alert file")
                self.modem.execute_command_async(
                    Command.create_with_write_file_action(
                        file_id=0x60,
                        offset=4,
                        data=[file_data],
                        interface_type=InterfaceType.D7ASP,
                        interface_configuration=Configuration(
                            qos=QoS(resp_mod=ResponseMode.RESP_MODE_ALL),
                            addressee=Addressee(access_class=0x11,
                                                id_type=IdType.NOID))))

            else:
                self.log.info("RPC method not supported, skipping")
                return
        except:
            exc_type, exc_value, exc_traceback = sys.exc_info()
            lines = traceback.format_exception(exc_type, exc_value,
                                               exc_traceback)
            trace = "".join(lines)
            msg_info = "no msg info (missing __dict__ attribute)"  # TODO because of out of date paho??
            if hasattr(msg, '__dict__'):
                msg_info = str(msg.__dict__)

            self.log.error(
                "Exception while processing MQTT message: {} callstack:\n{}".
                format(msg_info, trace))

    def publish_to_topic(self, topic, msg):
        if not self.connected_to_mqtt:
            self.log.warning("not connected to MQTT, skipping")
            return

        self.mq.publish(topic, msg)

    def __del__(self):
        try:
            self.mq.loop_stop()
            self.mq.disconnect()
        except:
            pass

    def run(self):
        self.log.info("Started")
        keep_running = True
        while keep_running:
            try:
                if platform.system() == "Windows":
                    time.sleep(1)
                else:
                    signal.pause()
            except serial.SerialException:
                time.sleep(1)
                self.log.warning("resetting serial connection...")
                self.setup_modem()
                return
            except KeyboardInterrupt:
                self.log.info(
                    "received KeyboardInterrupt... stopping processing")
                keep_running = False

            self.report_stats()

    def keep_stats(self):
        self.bridge_count += 1

    def report_stats(self):
        if self.next_report < time.time():
            if self.bridge_count > 0:
                self.log.info("bridged %s messages" % str(self.bridge_count))
                self.bridge_count = 0
            self.next_report = time.time(
            ) + 15  # report at most every 15 seconds

    def get_ip(self):
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        try:
            # doesn't even have to be reachable
            s.connect(('10.255.255.255', 1))
            IP = s.getsockname()[0]
        except:
            IP = '127.0.0.1'
        finally:
            s.close()
        return IP
コード例 #31
0
from d7a.sp.configuration import Configuration
from d7a.sp.qos import QoS, ResponseMode
from d7a.system_files.uid import UidFile
from modem.modem import Modem


# This example can be used with a node running the gateway app included in OSS-7.
# The gateway is continuously listening for foreground frames.
# Messages pushed by other nodes (running for example the sensor_push app) will be received by the gateway node,
# transmitted over serial and the received_command_callback() function below will be called.
from util.logger import configure_default_logger


def received_command_callback(cmd):
  logging.info(cmd)

argparser = argparse.ArgumentParser()
argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                            default="/dev/ttyUSB0")
argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
config = argparser.parse_args()

configure_default_logger(config.verbose)

modem = Modem(config.device, config.rate, unsolicited_response_received_callback=received_command_callback)
modem.connect()

while True:
  pass
コード例 #32
0
    def __init__(self):
        argparser = argparse.ArgumentParser()
        argparser.add_argument("-d",
                               "--device",
                               help="serial device /dev file modem",
                               default="/dev/ttyACM0")
        argparser.add_argument("-r",
                               "--rate",
                               help="baudrate for serial device",
                               type=int,
                               default=115200)
        argparser.add_argument("-v",
                               "--verbose",
                               help="verbose",
                               default=False,
                               action="store_true")
        argparser.add_argument("-b",
                               "--broker",
                               help="mqtt broker hostname",
                               default="localhost")
        argparser.add_argument("-bp",
                               "--broker-port",
                               help="mqtt broker port",
                               default="1883")
        argparser.add_argument("-p",
                               "--plugin-path",
                               help="path where plugins are stored",
                               default="")
        argparser.add_argument(
            "-l",
            "--logfile",
            help="specify path if you want to log to file instead of to stdout",
            default="")

        self.bridge_count = 0
        self.next_report = 0
        self.mq = None
        self.mqtt_topic_incoming_alp = ""
        self.connected_to_mqtt = False

        self.config = argparser.parse_args()

        self.log = logging.getLogger()
        formatter = logging.Formatter(
            '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
        if self.config.logfile == "":
            handler = logging.StreamHandler()
        else:
            handler = logging.FileHandler(self.config.logfile)

        handler.setFormatter(formatter)
        self.log.addHandler(handler)
        self.log.setLevel(logging.INFO)
        if self.config.verbose:
            self.log.setLevel(logging.DEBUG)

        if self.config.plugin_path != "":
            self.load_plugins(self.config.plugin_path)

        self.modem = Modem(self.config.device, self.config.rate,
                           self.on_command_received)
        self.connect_to_mqtt()

        # update attribute containing git rev so we can track revision at TB platform
        git_sha = subprocess.check_output(["git", "describe",
                                           "--always"]).strip()
        ip = self.get_ip()
        # TODO ideally this should be associated with the GW device itself, not with the modem in the GW
        # not clear how to do this using TB-GW
        self.publish_to_topic(
            "/gateway-info",
            jsonpickle.json.dumps({
                "git-rev": git_sha,
                "ip": ip,
                "device": self.modem.uid
            }))

        # make sure TB knows the modem device is connected. TB considers the device connected as well when there is regular
        # telemetry data. This is fine for remote nodes which will be auto connected an disconnected in this way. But for the
        # node in the gateway we do it explicitly to make sure it always is 'online' even when there is no telemetry to be transmitted,
        # so that we can reach it over RPC
        self.publish_to_topic(
            "sensors/connect",
            jsonpickle.json.dumps({"serialNumber": self.modem.uid}))

        self.log.info("Running on {} with git rev {} using modem {}".format(
            ip, git_sha, self.modem.uid))

        # read all system files on the local node to store as attributes on TB
        self.log.info("Reading all system files ...")
        for file in SystemFiles().files.values():
            self.modem.execute_command_async(
                Command.create_with_read_file_action_system_file(file))
コード例 #33
0
def received_command_callback(cmd):
  logging.info(cmd)
  if cmd.execution_completed:
    os._exit(0)

argparser = argparse.ArgumentParser()
argparser.add_argument("-d", "--device", help="serial device /dev file modem",
                            default="/dev/ttyUSB0")
argparser.add_argument("-r", "--rate", help="baudrate for serial device", type=int, default=115200)
argparser.add_argument("-v", "--verbose", help="verbose", default=False, action="store_true")
config = argparser.parse_args()

configure_default_logger(config.verbose)

modem = Modem(config.device, config.rate, unsolicited_response_received_callback=received_command_callback)
modem.connect()
logging.info("Executing query...")
modem.execute_command_async(
  alp_command=Command.create_with_read_file_action(
    file_id=0x40,
    length=8,
    interface_type=InterfaceType.D7ASP,
    interface_configuration=Configuration(
      qos=QoS(resp_mod=ResponseMode.RESP_MODE_ALL),
      addressee=Addressee(
        access_class=0x11,
        id_type=IdType.NOID
      )
    )
  )
コード例 #34
0
argparser = argparse.ArgumentParser()

argparser.add_argument("-s",
                       "--serial",
                       help="serial device /dev file",
                       default="/dev/tty.usbserial-FTGCT0HY")
argparser.add_argument("-b",
                       "--baudrate",
                       help="baudrate for serial device",
                       type=int,
                       default=115200)

config = argparser.parse_args()

modem = Modem(config.serial, config.baudrate, show_logging=False)

cmd = Command.create_with_return_file_data_action(
    file_id=0x40,
    data=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    interface_type=InterfaceType.D7ASP,
    interface_configuration=Configuration(qos=QoS(resp_mod=QoS.RESP_MODE_NO),
                                          addressee=Addressee(
                                              access_class=0,
                                              id_type=IdType.BCAST)))

last_message = 0

sent = 0
received = 0
コード例 #35
0
class ThroughtPutTest:
    def __init__(self):
        self.argparser = argparse.ArgumentParser(
            fromfile_prefix_chars="@",
            description="Test throughput over 2 serial D7 modems")

        self.argparser.add_argument("-n",
                                    "--msg-count",
                                    help="number of messages to transmit",
                                    type=int,
                                    default=10)
        self.argparser.add_argument(
            "-p",
            "--payload-size",
            help="number of bytes of (appl level) payload to transmit",
            type=int,
            default=50)
        self.argparser.add_argument(
            "-sw",
            "--serial-transmitter",
            help="serial device /dev file transmitter node",
            default=None)
        self.argparser.add_argument(
            "-sr",
            "--serial-receiver",
            help="serial device /dev file receiver node",
            default=None)
        self.argparser.add_argument("-r",
                                    "--rate",
                                    help="baudrate for serial device",
                                    type=int,
                                    default=115200)
        self.argparser.add_argument(
            "-uid",
            "--unicast-uid",
            help="UID to use for unicast transmission, "
            "when not using receiver "
            "(in hexstring, for example 0xb57000009151d)",
            default=None)
        self.argparser.add_argument(
            "-to",
            "--receiver-timeout",
            help="timeout for the receiver (in seconds)",
            type=int,
            default=10)
        self.argparser.add_argument("-v",
                                    "--verbose",
                                    help="verbose",
                                    default=False,
                                    action="store_true")
        self.config = self.argparser.parse_args()

        if self.config.serial_transmitter == None and self.config.serial_receiver == None:
            self.argparser.error(
                "At least a transmitter or receiver is required.")

        if self.config.serial_receiver == None and self.config.unicast_uid == None:
            self.argparser.error(
                "When running without receiver a --unicast-uid parameter is required."
            )

        if self.config.serial_transmitter == None:
            self.transmitter_modem = None
            print("Running without transmitter")
        else:
            self.transmitter_modem = Modem(self.config.serial_transmitter,
                                           self.config.rate,
                                           None,
                                           show_logging=self.config.verbose)
            access_profile = AccessProfile(
                channel_header=ChannelHeader(
                    channel_band=ChannelBand.BAND_868,
                    channel_coding=ChannelCoding.PN9,
                    channel_class=ChannelClass.NORMAL_RATE),
                sub_profiles=[
                    SubProfile(subband_bitmap=0x01,
                               scan_automation_period=CT(exp=0, mant=0)),
                    SubProfile(),
                    SubProfile(),
                    SubProfile()
                ],
                sub_bands=[
                    SubBand(
                        channel_index_start=0,
                        channel_index_end=0,
                        eirp=10,
                        cca=86  # TODO
                    )
                ])

            print("Write Access Profile")
            write_ap_cmd = Command.create_with_write_file_action_system_file(
                file=AccessProfileFile(access_profile=access_profile,
                                       access_specifier=0))
            self.transmitter_modem.send_command(write_ap_cmd)

        if self.config.serial_receiver == None:
            self.receiver_modem = None
            print("Running without receiver")
        else:
            self.receiver_modem = Modem(self.config.serial_receiver,
                                        self.config.rate,
                                        self.receiver_cmd_callback,
                                        show_logging=self.config.verbose)
            self.receiver_modem.send_command(
                Command.create_with_write_file_action_system_file(
                    DllConfigFile(active_access_class=0x01)))
            print("Receiver scanning on Access Class = 0x01")

    def start(self):
        self.received_commands = defaultdict(list)
        payload = range(self.config.payload_size)

        if self.receiver_modem != None:
            addressee_id = int(self.receiver_modem.uid, 16)
        else:
            addressee_id = int(self.config.unicast_uid, 16)

        if self.transmitter_modem != None:

            print(
                "\n==> broadcast, with QoS, transmitter active access class = 0x01 ===="
            )
            self.transmitter_modem.send_command(
                Command.create_with_write_file_action_system_file(
                    DllConfigFile(active_access_class=0x01)))
            interface_configuration = Configuration(
                qos=QoS(resp_mod=ResponseMode.RESP_MODE_ANY),
                addressee=Addressee(
                    access_class=0x01,
                    id_type=IdType.NBID,
                    id=CT(exp=0, mant=1)  # we expect one responder
                ))

            self.start_transmitting(
                interface_configuration=interface_configuration,
                payload=payload)
            self.wait_for_receiver(payload)

            print(
                "\n==> broadcast, no QoS, transmitter active access class = 0x01 ===="
            )
            self.transmitter_modem.send_command(
                Command.create_with_write_file_action_system_file(
                    DllConfigFile(active_access_class=0x01)))
            interface_configuration = Configuration(
                qos=QoS(resp_mod=ResponseMode.RESP_MODE_NO),
                addressee=Addressee(access_class=0x01, id_type=IdType.NOID))

            self.start_transmitting(
                interface_configuration=interface_configuration,
                payload=payload)
            self.wait_for_receiver(payload)

            print(
                "\n==> unicast, with QoS, transmitter active access class = 0x01"
            )
            interface_configuration = Configuration(
                qos=QoS(resp_mod=ResponseMode.RESP_MODE_ANY),
                addressee=Addressee(access_class=0x01,
                                    id_type=IdType.UID,
                                    id=addressee_id))

            self.start_transmitting(
                interface_configuration=interface_configuration,
                payload=payload)
            self.wait_for_receiver(payload)

            print(
                "\n==> unicast, no QoS, transmitter active access class = 0x01"
            )
            interface_configuration = Configuration(
                qos=QoS(resp_mod=ResponseMode.RESP_MODE_NO),
                addressee=Addressee(access_class=0x01,
                                    id_type=IdType.UID,
                                    id=addressee_id))

            self.start_transmitting(
                interface_configuration=interface_configuration,
                payload=payload)
            self.wait_for_receiver(payload)
        else:
            # receive only
            self.receiver_modem.start_reading()
            self.wait_for_receiver(payload)

    def start_transmitting(self, interface_configuration, payload):
        print(
            "Running throughput test with payload size {} and interface_configuration {}\n\nrunning ...\n"
            .format(len(payload), interface_configuration))

        if self.receiver_modem != None:
            self.received_commands = defaultdict(list)
            self.receiver_modem.start_reading()

        command = Command.create_with_return_file_data_action(
            file_id=0x40,
            data=payload,
            interface_type=InterfaceType.D7ASP,
            interface_configuration=interface_configuration)

        start = time.time()

        for i in range(self.config.msg_count):
            sys.stdout.write("{}/{}\r".format(i + 1, self.config.msg_count))
            sys.stdout.flush()
            self.transmitter_modem.d7asp_fifo_flush(command)

        end = time.time()
        print("transmitter: sending {} messages completed in: {} s".format(
            self.config.msg_count, end - start))
        print(
            "transmitter: throughput = {} bps with a payload size of {} bytes".
            format((self.config.msg_count * self.config.payload_size * 8) /
                   (end - start), self.config.payload_size))

    def wait_for_receiver(self, payload):
        if self.receiver_modem == None:
            print(
                "Running without receiver so we are not waiting for messages to be received ..."
            )
        else:
            start = time.time()
            total_recv = 0
            while total_recv < self.config.msg_count and time.time(
            ) - start < self.config.receiver_timeout:
                total_recv = sum(
                    len(v) for v in self.received_commands.values())
                time.sleep(2)
                print(
                    "waiting for receiver to finish ... (current nr of recv msgs: {})"
                    .format(total_recv))

            print("finished receiving or timeout")
            self.receiver_modem.cancel_read()
            payload_has_errors = False
            for sender_cmd in self.received_commands.values():
                for cmd in sender_cmd:
                    if type(cmd.actions[0].op
                            ) != ReturnFileData and cmd.actions[
                                0].operand.data != payload:
                        payload_has_errors = True
                        print(
                            "receiver: received unexpected command: {}".format(
                                cmd))

            if payload_has_errors == False and total_recv == self.config.msg_count:
                print(
                    "receiver: OK: received {} messages with correct payload:".
                    format(total_recv))
                for sender, cmds in self.received_commands.items():
                    print("\t{}: {}".format(sender, len(cmds)))
            else:
                print(
                    "receiver: NOK: received messages {}:".format(total_recv))
                for sender, cmds in self.received_commands.items():
                    print("\t{}: {}".format(sender, len(cmds)))

    def receiver_cmd_callback(self, cmd):
        print("recv cmd: ".format(cmd))
        if cmd.interface_status != None:
            uid = cmd.interface_status.operand.interface_status.addressee.id
            self.received_commands[uid].append(cmd)
        else:
            print("Unexpected cmd received, reboot?\n\t{}".format(cmd))
コード例 #36
0
ファイル: send_lorawan.py プロジェクト: JitterCompany/pyd7a
argparser.add_argument("-v",
                       "--verbose",
                       help="verbose",
                       default=False,
                       action="store_true")
argparser.add_argument("-otaa",
                       "--over-the-air-activation",
                       help="Enable over the air activation",
                       default=False,
                       action="store_true")
config = argparser.parse_args()

configure_default_logger(config.verbose)

modem = Modem(
    config.device,
    config.rate,
)
modem.connect()
logging.info("Executing query...")
if (config.over_the_air_activation):
    result = modem.execute_command(
        alp_command=Command.create_with_read_file_action(
            file_id=0x40,
            length=8,
            interface_type=InterfaceType.LORAWAN_OTAA,
            interface_configuration=LoRaWANInterfaceConfigurationOTAA(
                request_ack=False,
                app_port=0x01,
                device_eui=[0xBE, 0X7A, 0X00, 0X00, 0X00, 0X00, 0X1B, 0X81],
                app_eui=[0xBE, 0X7A, 0X00, 0X00, 0X00, 0X00, 0X0D, 0X9F],
                app_key=[