예제 #1
0
    def __init__(self,
                 directory,
                 proto_obj,
                 send_retries,
                 msg_size_max,
                 msg_send_limit=5):
        if msg_size_max > proto_obj.Mtu:
            raise MessageExchangeExceptionMessageSize(msg_size_max,
                                                      proto_obj.Mtu)

        # Initialize the MessageExchangeService class.
        super().__init__()

        # Configure the max size of a single message. Determines buffer sizes.
        MessageTemplate.Configure(msg_size_max)

        # Configure the MessageBuffer and Message classes.
        MessageBuffer.Configure(directory)

        # Create a generic send buffer for all outgoing messages.
        self.SendMessageBuffer = MessageBuffer(
            'send', -1, -1, MessageExchange.SEND_BUFFER_SIZE)
        self.MessageMappings = set()
        self.Protocol = proto_obj
        self.SendRetries = send_retries
        self.SendLimit = msg_send_limit
        self.ConnectionState = Subject()
        self.ConnectionState.State = False
        self.ServiceInit = False
        self.NewMessage = False  # Set to True by the receive callback on a received message.
        self.Log = ExtLogging.Create("MsgEx")

        MessageExchange._Instance = self
예제 #2
0
class Message:

    Msg = None
    _StreamBuffer = None
    _Parser = None
    Log = ExtLogging.Create("Msg")

    @staticmethod
    def SetParser(parser_obj):
        Message._Parser = parser_obj
        Message.Log.debug("Parser set: {}".format(Message._Parser))

    @staticmethod
    def Message():
        return Message.Msg

    @staticmethod
    def Stream():
        return Message._StreamBuffer

    @staticmethod
    def Serialize(data_dict, meta_dict=None):
        # Create a message from the template.
        Message.Msg = MessageTemplate()
        Message.Msg = Message.Msg.Msg
        Message.Log.debug(
            "Serializing message with metadata: {} | data: {}".format(
                meta_dict, data_dict))
        # Close the previous stream if there is one.
        if Message._StreamBuffer is not None:
            Message._StreamBuffer.close()
        Message._StreamBuffer = uio.BytesIO(MessageTemplate.MsgSizeMax)
        # If metadata was given, check for matching keys and copy the values.
        if meta_dict is not None:
            for key in Message.Msg[MessageTemplate.MSG_SECTION_META].keys():
                if key in meta_dict.keys():
                    Message.Msg[
                        MessageTemplate.MSG_SECTION_META][key] = meta_dict[key]
        # Copy the data dictionary.
        Message.Msg[MessageTemplate.MSG_SECTION_DATA] = data_dict
        # Serialize the message using the parser.
        Message._Parser.Dumps(Message.Msg, Message._StreamBuffer)
        return Message._StreamBuffer

    @staticmethod
    def Deserialize(msg_str):
        try:
            Message.Msg = Message._Parser.Loads(msg_str)
        except ValueError:
            Message.Log.error("Invalid format: {}".format(msg_str))
        return Message.Msg

    @staticmethod
    def Print():
        Message.Log.info(Message.Msg)
예제 #3
0
 def __init__(self, msg_ex_obj, reg_info_spec):
     """
     Registration object, implements the RegistrationService and Observer classes.
     :param msg_ex_obj: MessageExchange object
     :type msg_ex_obj: <MessageExchange>
     :param reg_info_spec: Registration info specification
     :type reg_info_spec: <<MessageSpecification>RegistrationInfo>
     """
     super().__init__()
     self.MsgEx = msg_ex_obj
     self.RegInfoSpec = reg_info_spec
     self.Version = Version.Instance()
     self.Log = ExtLogging.Create("Reg")
     return
예제 #4
0
    def test_LoggingToFileMaxLines(self):
        file = "extlog"
        name = "test"
        text = "hi"
        file_limit = 2
        line_limit = 10

        ExtLogging.ConfigGlobal(level=ExtLogging.INFO,
                                stream=TestStream(),
                                dir=self.DIR,
                                file_prefix=file,
                                line_limit=line_limit,
                                file_limit=file_limit,
                                print_enabled=True,
                                timestamp_enabled=True)

        log = ExtLogging.Create(name)
        print(log)

        for f in range(0, file_limit):
            for l in range(0, line_limit):
                log.info(text + str(l))

        ExtLogging.Mngr.PrintList()

        file_list = ExtLogging.Mngr.List()
        print(file_list)

        count = ExtLogging.Mngr.Count()
        self.assertEqual(count, file_limit)
        for i in range(0, count):
            print("[UT] Checking file: {}".format(file_list[i]))
            f = open(file_list[i], 'r')
            for l in range(0, line_limit):
                exc_occurred = False
                try:
                    line = f.readline()
                    print("[UT] Read line: {}".format(line))
                except OSError:
                    exc_occurred = True

                self.assertFalse(exc_occurred)
                self.assertTrue(text in line)
                self.assertTrue(name in line)
                self.assertTrue("[" in line)

            f.close()
예제 #5
0
    def __init__(self,
                 directory: str,
                 name: str,
                 filter_depth: int,
                 sensor_driver_obj,
                 samples_per_update: int = 1,
                 dec_round: bool = True,
                 store_data: bool = True):
        """

        :param directory:
        :type directory:
        :param name:
        :type name:
        :param filter_depth:
        :type filter_depth:
        :param sensor_driver_obj:
        :type sensor_driver_obj:
        :param samples_per_update:
        :type samples_per_update:
        :param dec_round:
        :type dec_round:
        :param store_data:
        :type store_data:
        """
        if samples_per_update > 1 and store_data is False:
            raise SensorExceptionInvalidConfig(
                "store_data must be True if samples_per_update > 1")

        # Initialize the SensorService class
        super().__init__(name)

        self.SensorDriver = sensor_driver_obj
        self.SamplesPerUpdate = samples_per_update
        self.Filter = AvgFilter.AvgFilter(filter_depth, dec_round)
        if store_data is True:
            self.SampleQueue = NvQueue.NvQueue(directory + '/' + name,
                                               Sensor.SAMPLE_FMT,
                                               Sensor.FILE_SAMPLES_MAX)
        self.NewSample = Subject()
        self.NewSample.State = list()
        self.StoreData = store_data
        self.Log = ExtLogging.Create("Sensor-{}".format(name))
예제 #6
0
from upyiot.system.Service.Service import Service
from upyiot.system.Service.Service import ServiceExceptionSuspend
from upyiot.system.Service.Service import ServiceException
from upyiot.middleware.StructFile.StructFile import StructFile
from upyiot.system.ExtLogging import ExtLogging

import utime
from micropython import const

Log = ExtLogging.Create("Scheduler")


class SchedulerException(Exception):
    def __init__(self):
        return


class SchedulerExceptionStopped(SchedulerException):
    def __init__(self):
        return


class SchedulerExceptionDeepSleepFailed(SchedulerException):
    def __init__(self):
        return


class SchedulerMemory:

    FILE_SCHEDULER_MEMORY = "/sched_mem"
    SVC_NAME_LEN = const(20)
예제 #7
0
from upyiot.middleware.NvQueue import NvQueue
from upyiot.system.ExtLogging import ExtLogging
from upyiot.comm.Messaging.MessageTemplate import MessageTemplate

Log = ExtLogging.Create("MsgBuf")


class MessageBuffer:

    MSG_STRUCT_TYPE = const(0)
    MSG_STRUCT_SUBTYPE = const(1)
    MSG_STRUCT_LEN = const(2)
    MSG_STRUCT_DATA = const(3)

    MsgDataLen = 0
    MsgStructFmt = ""
    Directory = ""

    _UnPackBuffer = None
    Configured = False

    @staticmethod
    def Configure(directory):
        MessageBuffer.MsgDataLen = MessageTemplate.MsgSizeMax
        MessageBuffer.MsgStructFmt = "<iiI" + \
                                     str(MessageBuffer.MsgDataLen) + "s"
        Log.debug("FMT: {}".format(MessageBuffer.MsgStructFmt))
        MessageBuffer.Directory = directory + "/"
        Log.debug(directory)
        # MessageBuffer._UnPackBuffer = bytearray(msg_len_max + msg_len_max)
        MessageBuffer.Configured = True
예제 #8
0
    def __init__(
            self,
            spi,
            pins,
            ttn_config,
            channel=0,  # compatibility with Dragino LG02, set to None otherwise
            fport=1,
            lora_parameters=_default_parameters):

        self._spi = spi
        self._pins = pins
        self._parameters = lora_parameters
        self._lock = False
        self._log = ExtLogging.Create("SX127x")

        # setting pins
        if "dio_0" in self._pins:
            self._pin_rx_done = Pin(self._pins["dio_0"], Pin.IN)
            self._irq = Pin(self._pins["dio_0"], Pin.IN)
        if "ss" in self._pins:
            self._pin_ss = Pin(self._pins["ss"], Pin.OUT)
        if "led" in self._pins:
            self._led_status = Pin(self._pins["led"], Pin.OUT)

        # check hardware version
        init_try = True
        re_try = 0
        while init_try and re_try < 5:
            version = self.read_register(REG_VERSION)
            re_try = re_try + 1

            self._log.info("SX version: {}".format(version))

            if version == 0x12:
                init_try = False
            else:
                utime.sleep_ms(1000)

        if version != 0x12:
            raise Exception('Invalid version.')

        # Set frequency registers
        self._rfm_msb = None
        self._rfm_mid = None
        self._rfm_lsb = None
        # init framecounter
        self.frame_counter = 0
        self._fport = fport

        # Set datarate registers
        self._sf = None
        self._bw = None
        self._modemcfg = None

        # ttn configuration
        if "US" in ttn_config.country:
            from ttn.ttn_usa import TTN_FREQS
            self._frequencies = TTN_FREQS
        elif ttn_config.country == "AS":
            from ttn.ttn_as import TTN_FREQS
            self._frequencies = TTN_FREQS
        elif ttn_config.country == "AU":
            from ttn.ttn_au import TTN_FREQS
            self._frequencies = TTN_FREQS
        elif ttn_config.country == "EU":
            from ttn.ttn_eu import TTN_FREQS
            self._frequencies = TTN_FREQS
        else:
            raise TypeError("Country Code Incorrect/Unsupported")
        # Give the uLoRa object ttn configuration
        self._ttn_config = ttn_config

        # put in LoRa and sleep mode
        self.sleep()

        # set channel number
        self._channel = channel
        self._actual_channel = channel
        if self._channel is not None:
            self.set_frequency(self._channel)

        # set data rate and bandwidth
        self.set_bandwidth(self._parameters["signal_bandwidth"])

        # set LNA boost
        self.write_register(REG_LNA, self.read_register(REG_LNA) | 0x03)

        # set auto AGC
        self.write_register(REG_MODEM_CONFIG, 0x04)
        self.implicit_header_mode(self._parameters['implicit_header'])
        self.set_tx_power(self._parameters['tx_power_level'])
        self.set_coding_rate(self._parameters['coding_rate'])
        self.set_sync_word(self._parameters['sync_word'])
        self.enable_CRC(self._parameters['enable_CRC'])
        #self.invert_IQ(self._parameters["invert_IQ"])
        self.set_preamble_length(self._parameters['preamble_length'])
        self.set_spreading_factor(self._parameters['spreading_factor'])
        # set LowDataRateOptimize flag if symbol time > 16ms (default disable on reset)
        # self.write_register(REG_MODEM_CONFIG, self.read_register(REG_MODEM_CONFIG) & 0xF7)  # default disable on reset

        #bw_parameter = self._parameters["signal_bandwidth"]
        #sf_parameter = self._parameters["spreading_factor"]

        #if 1000 / (bw_parameter / 2**sf_parameter) > 16:
        #    self.write_register(
        #        REG_MODEM_CONFIG,
        #        self.read_register(REG_MODEM_CONFIG) | 0x08
        #    )

        # set base addresses
        self.write_register(REG_FIFO_TX_BASE_ADDR, FifoTxBaseAddr)
        self.write_register(REG_FIFO_RX_BASE_ADDR, FifoRxBaseAddr)

        self.standby()
예제 #9
0
from upyiot.comm.Messaging.Protocol.MessagingProtocol import MessagingProtocol
from upyiot.comm.Messaging.MessageExchange import MessageExchange
from upyiot.system.ExtLogging import ExtLogging
from micropython import const
import urequests

Log = ExtLogging.Create("HttpProto")


class HttpProtocol(MessagingProtocol):

    HTTP_MTU = const(1400)

    _Instance = None

    def __init__(self):
        super().__init__(None, self.HTTP_MTU)
        HttpProtocol._Instance = self
        return

    def Setup(self, recv_callback, msg_mappings):
        MessagingProtocol.Setup(self, recv_callback, msg_mappings)
        return

    def Send(self, msg_map, payload, size):
        route = msg_map[MessageExchange.MSG_MAP_ROUTING]
        decoded = payload.decode("utf-8")
        print(type(payload), type(decoded))
        Log.info("POST to {}: {}".format(route, decoded))
        headers = {
            'Content-type': 'application/json',
예제 #10
0
from upyiot.comm.Messaging.Protocol.MessagingProtocol import MessagingProtocol
from upyiot.comm.Messaging.MessageExchange import MessageExchange
from upyiot.comm.Network import LoRaWAN
from upyiot.comm.Network.LoRaWAN.MHDR import MHDR
from upyiot.middleware.StructFile import StructFile
from upyiot.drivers.Modems.SX127x.LoRa import *
from upyiot.drivers.Modems.SX127x.board_config import BOARD
from upyiot.system.ExtLogging import ExtLogging

from time import sleep
from random import randrange
import machine
from micropython import const

Log = ExtLogging.Create("LoraProto")

ADDR_SIZE = const(4)
EUI_SIZE = const(8)
KEY_SIZE = const(16)

TX_TIMEOUT_SEC = const(10)
RX_TIMEOUT_SEC = const(30)
TIMEOUT_POLL_SEC = const(1)


class LoRaWANParams:

    SESSION_DATA_FMT = "<4s16s16s"  # DevAddr, AppSKey, NwkSKey
    FCNT_DATA_FMT = "<I"

    def __init__(self, dir: str, dev_eui: str):
예제 #11
0
from upyiot.middleware.StructFile import StructFile
from micropython import const
from upyiot.system.ExtLogging import ExtLogging

Log = ExtLogging.Create("NvQueue")


class NvQueueIterator(object):
    def __init__(self, nvqueue_obj):
        print(nvqueue_obj)
        nvqueue_obj.Queue.IteratorConfig(nvqueue_obj.ReadOffset,
                                         nvqueue_obj.WriteOffset,
                                         nvqueue_obj.Count)
        self.Iterator = iter(nvqueue_obj.Queue)

    def __next__(self):
        return self.Iterator.__next__()


class NvQueue:

    # Capacity, count, read offset, write offset.
    META_FMT = "<HHHH"
    META_STRUCT_CAP = const(0)
    META_STRUCT_CNT = const(1)
    META_STRUCT_R_OFF = const(2)
    META_STRUCT_W_OFF = const(3)

    def __init__(self, file, data_fmt, capacity):
        Log.info(
            "Creating NvQueue with path: {}, capacity: {}, format: {}".format(
예제 #12
0
from micropython import const
from upyiot.middleware.SubjectObserver.SubjectObserver import Observer
from upyiot.system.ExtLogging import ExtLogging

Log = ExtLogging.Create("MsgFmt")


class MessagePartSource:
    def __init__(self, msg_formatter_obj, key, complete_count):
        self.MsgFormatter = msg_formatter_obj
        self.Key = key
        self.Count = 0
        self.CompleteCount = complete_count

    def Put(self, data):
        if self.Count is 0:
            self.MsgFormatter.MessagePartAdd(self.Key, data)
        else:
            self.MsgFormatter.MessagePartAppend(self.Key, data)
        self._CountInc()

    def _CountInc(self):
        self.Count += 1
        if self.Count is self.CompleteCount:
            self.Count = 0
            self.MsgFormatter.MessagePartFinalize()


class MessagePartSink:
    def __init__(self, msg_formatter_obj, key, complete_count):
        self.MsgFormatter = msg_formatter_obj
예제 #13
0
    def Setup(self):

        for dir in self.DIR_TREE.values():
            try:
                uos.mkdir(dir)
            except OSError:
                print("Cannot create directory '{}'".format(dir))

        # Configure the ExtLogging class.
        ExtLogging.ConfigGlobal(level=ExtLogging.DEBUG,
                                stream=None,
                                dir=self.DIR_TREE[self.DIR_LOG],
                                file_prefix="log_",
                                line_limit=1000,
                                file_limit=10)

        StructFile.SetLogger(ExtLogging.Create("SFile"))

        self.Log = ExtLogging.Create("Main")

        self.Log.info("Device ID: {}".format(DeviceId.DeviceId()))

        Version(self.DIR_TREE[self.DIR_SYS], self.VER_MAJOR, self.VER_MINOR,
                self.VER_PATCH)

        rst_reason = ResetReason.ResetReason()
        self.Log.debug("Reset reason: {}".format(
            ResetReason.ResetReasonToString(rst_reason)))

        # Create driver instances.
        self.DummySensorDriver = DummySensor(self.DummySamples)

        self.InternalTemp = InternalTemp()

        # TODO: Enable actual sensor drivers.
        # self.TempSensorDriver = Mcp9700Temp(temp_pin_nr=Pins.CFG_HW_PIN_TEMP,
        #                                     en_supply_obj=Supply(Pins.CFG_HW_PIN_TEMP_EN, 3.3, 300))
        #
        # self.VBatSensorDriver = VoltageSensor(pin_nr=Pins.CFG_HW_PIN_VBAT_LVL,
        #                                       en_supply_obj=Supply(Pins.CFG_HW_PIN_VBAT_LVL_EN, 3.3, 300))

        if self.NETWORK is self.KPN:
            self.LoraProtocol = LoraProtocol(
                self.KpnLoraConfig, directory=self.DIR_TREE[self.DIR_LORA])
        elif self.NETWORK is self.TTN:
            self.LoraProtocol = LoraProtocol(
                self.TtnLoraConfig, directory=self.DIR_TREE[self.DIR_LORA])
            if self.NETWORK_REG is self.ABP:
                self.LoraProtocol.Params.StoreSession(self.DevAddr,
                                                      self.AppSKey,
                                                      self.NwkSKey)
        else:
            raise Exception("No valid network LoRa selected.")

        self.DummySensor = Sensor.Sensor(self.DIR_TREE[self.DIR_SENSOR],
                                         "Dummy",
                                         self.FILTER_DEPTH,
                                         self.DummySensorDriver,
                                         samples_per_update=3,
                                         dec_round=True,
                                         store_data=True)

        self.TempSensor = Sensor.Sensor(
            self.DIR_TREE[self.DIR_SENSOR],
            "Temp",
            self.FILTER_DEPTH,
            self.
            InternalTemp,  # TODO: Replace InternalTemp driver with TempSensorDriver
            samples_per_update=2,
            dec_round=True,
            store_data=True)

        # self.BatteryVoltageSensor = Sensor.Sensor(self.DIR_TREE[self.DIR_SENSOR],
        #                                           "BatLvl",
        #                                           self.FILTER_DEPTH,
        #                                           self.VBatSensorDriver,
        #                                           samples_per_update=2,
        #                                           dec_round=False,
        #                                           store_data=True)

        self.MsgEx = MessageExchange(directory=self.DIR_TREE[self.DIR_MSG],
                                     proto_obj=self.LoraProtocol,
                                     send_retries=self.RETRIES,
                                     msg_size_max=self.LoraProtocol.Mtu,
                                     msg_send_limit=self.SEND_LIMIT)

        # Create the registration info spec and Registration service.
        # Link the Registration service to the Message Exchange service. The Message Exchange
        # service will activate the Registration service when it connects to the LoRa network.
        self.RegistrationInfo = RegistrationInfo()
        self.Registration = Registration(self.MsgEx, self.RegistrationInfo)
        self.MsgEx.AttachConnectionStateObserver(self.Registration)

        self.Scheduler = ServiceScheduler(
            deepsleep_threshold_sec=self.DEEPSLEEP_THRESHOLD_SEC,
            # deep_sleep_obj=PowerManager.PowerManager(),
            directory=self.DIR_TREE[self.DIR_SYS])

        # Set service dependencies.
        # There are no hard dependencies between the services.

        # Register all services to the scheduler.
        self.Scheduler.ServiceRegister(self.DummySensor)
        self.Scheduler.ServiceRegister(self.TempSensor)
        # self.Scheduler.ServiceRegister(self.BatteryVoltageSensor)
        self.Scheduler.ServiceRegister(self.MsgEx)
        self.Scheduler.ServiceRegister(self.Registration)

        Message.SetParser(CborParser())
        MessageTemplate.SectionsSet(Metadata.MSG_SECTION_META,
                                    Metadata.MSG_SECTION_DATA)
        MessageTemplate.MetadataTemplateSet(Metadata.Metadata,
                                            Metadata.MetadataFuncs)

        # Create message specifications.
        self.MoistReport = MoistureSensorReport()
        self.BatteryReport = BatterySensorReport()
        self.TempReport = TemperatureSensorReport()

        # Create MessageFormatters and couple them with their message specs.
        moist_report_meta = {
            Metadata.MSG_META_TYPE: self.MoistReport.Type,
            Metadata.MSG_META_SUBTYPE: self.MoistReport.Subtype,
        }
        self.MoistFmt = MessageFormatter(self.MsgEx,
                                         MessageFormatter.SEND_ON_CHANGE,
                                         self.MoistReport, moist_report_meta)

        battery_report_meta = {
            Metadata.MSG_META_TYPE: self.BatteryReport.Type,
            Metadata.MSG_META_SUBTYPE: self.BatteryReport.Subtype,
        }
        self.BatteryFmt = MessageFormatter(self.MsgEx,
                                           MessageFormatter.SEND_ON_CHANGE,
                                           self.BatteryReport,
                                           battery_report_meta)

        temp_report_meta = {
            Metadata.MSG_META_TYPE: self.TempReport.Type,
            Metadata.MSG_META_SUBTYPE: self.TempReport.Subtype,
        }
        self.TempFmt = MessageFormatter(self.MsgEx,
                                        MessageFormatter.SEND_ON_CHANGE,
                                        self.TempReport, temp_report_meta)

        # Register message specs for exchange.
        self.MsgEx.RegisterMessageType(self.MoistReport)
        self.MsgEx.RegisterMessageType(self.BatteryReport)
        self.MsgEx.RegisterMessageType(self.TempReport)
        self.MsgEx.RegisterMessageType(self.RegistrationInfo)

        # Create observers for the sensor data.
        self.MoistObserver = self.MoistFmt.CreateObserver(
            MoistureSensorReport.DATA_KEY_MEASUREMENTS)
        self.BatteryObserver = self.BatteryFmt.CreateObserver(
            BatterySensorReport.DATA_KEY_MEASUREMENTS)
        self.TempObserver = self.TempFmt.CreateObserver(
            TemperatureSensorReport.DATA_KEY_MEASUREMENTS)

        # Link the observers to the sensors.
        self.DummySensor.ObserverAttachNewSample(self.MoistObserver)
        self.TempSensor.ObserverAttachNewSample(self.TempObserver)

        self.Scheduler.RegisterCallbackBeforeDeepSleep(MainApp.BeforeSleep)

        # Set intervals for all services.
        self.MsgEx.SvcIntervalSet(self.MsgExInterval)
        self.MsgEx.DefaultIntervalSet(self.MsgExInterval)
        self.DummySensor.SvcIntervalSet(self.MoistReadInterval)
        self.TempSensor.SvcIntervalSet(self.SensorReadInterval)

        # Activate the Message Exchange to attempt to connect to the LoRa network
        # if no LoRaWAN session exists yet.
        if self.LoraProtocol.HasSession() is False:
            self.MsgEx.SvcActivate()

        # self.BatteryObserver.Update(100)

        self.Log.info("Finished initialization.")