Example #1
0
    def __init__(self, MAC: str = "autoscan", **kwargs):

        # Load the parent class values
        DMM.__init__(self, MAC)

        # Local meter values below here.
        self.MAC = MAC
        self.output_to_console = False
        self.model = "Multicomp Pro MP730026"

        self.__connected = False

        self.obs_scene = kwargs["obs_scene"] if kwargs.get("obs_scene",
                                                           False) else None
        self.obs_source = kwargs["obs_source"] if kwargs.get(
            "obs_source", False) else None
        if self.obs_scene and self.obs_source:
            from obs import OBS

            self.obs_instance = OBS()
        else:
            self.obs_instance = None

        self.ol_count = 0
        self.ol_count_limit = 60  # A 60 count equates to approximately 30 seconds
        self.ol_hide_enable = kwargs["ol_hide_enable"] if kwargs.get(
            "ol_hide_enable", False) else False
 def setUp(self):
     """
     Initialize the configuration
     """
     self.obs = OBS()
     Config('openSUSE:Factory')
     self.api = StagingAPI(APIURL, 'openSUSE:Factory')
Example #3
0
    def setUp(self):
        """Initialize the configuration."""

        self.obs = OBS()
        Config(APIURL, 'openSUSE:Factory')
        self.stagingapi = StagingAPI(APIURL, 'openSUSE:Factory')
        self.checkcommand = CheckCommand(self.stagingapi)
    def setUp(self):
        """Initialize the configuration."""

        self.obs = OBS()
        Config('openSUSE:Factory')
        self.checkrepo = CheckRepo(APIURL,
                                   project='openSUSE:Factory',
                                   force_clean=True)
        # Des-memoize some functions
        self.checkrepo.build = self.checkrepo._build
        self.checkrepo.last_build_success = self.checkrepo._last_build_success
 def setUp(self):
     self.obs = OBS()
     Config(PROJECT)
Example #6
0
 def setUp(self):
     self.obs = OBS()
     self.load_config()
     self.api = StagingAPI(APIURL, PROJECT)
Example #7
0
class MP730026(DMM):
    """
    Connect to a MP730026 Digital Multi-meter.
    Pass the MAC address if known, otherwise autoscan will run.
    """
    def __init__(self, MAC: str = "autoscan", **kwargs):

        # Load the parent class values
        DMM.__init__(self, MAC)

        # Local meter values below here.
        self.MAC = MAC
        self.output_to_console = False
        self.model = "Multicomp Pro MP730026"

        self.__connected = False

        self.obs_scene = kwargs["obs_scene"] if kwargs.get("obs_scene",
                                                           False) else None
        self.obs_source = kwargs["obs_source"] if kwargs.get(
            "obs_source", False) else None
        if self.obs_scene and self.obs_source:
            from obs import OBS

            self.obs_instance = OBS()
        else:
            self.obs_instance = None

        self.ol_count = 0
        self.ol_count_limit = 60  # A 60 count equates to approximately 30 seconds
        self.ol_hide_enable = kwargs["ol_hide_enable"] if kwargs.get(
            "ol_hide_enable", False) else False

    @property
    def connected(self):
        return self.__connected

    @connected.setter
    def connected(self, connected: bool):

        try:
            # Check if the scene and source have been defined
            if self.obs_scene and self.obs_source:
                # If so, tell OBS to toggle it based on the value
                self.obs_instance.send(connected, self.obs_scene,
                                       self.obs_source)
        except AttributeError:
            # Happens on startup because the variables haven't been created yet
            ...

        self.__connected = connected

    async def scan(self):
        logger.warning("Scanning for devices with the name BDM")
        try:
            devices = await discover()
        except RemoteError:
            print("Bluetooth Permissions error. See Readme.md")
            _exit(0)

        for d in devices:
            if d.name == "BDM":  # BDM is the default name of this type of meter
                self.MAC = d.address

        return self.MAC

    def __decode_indicators(self, data: bytearray):
        indicators = data[1]

        hold_indicator_state = bool(indicators & 256)
        rel_indicator_state = bool(indicators & 512)
        auto_range_indicator_state = bool(indicators & 1024)
        low_battery = bool(indicators & 2048)

        return [
            hold_indicator_state,
            rel_indicator_state,
            auto_range_indicator_state,
            low_battery,
        ]

    def __decode_mode_and_range(self, data: bytearray):
        """
        Decodes the Mode and Range from the data bytearray received from the meter
        """

        # First element of the data array is the mode
        mode = data[0]

        try:
            mode_str = self.mode_strings[values[mode][0]]
            units_str = self.unit_strings[values[mode][1]]
            range_decimal_pos = values[mode][2]

        except KeyError:
            # New mode
            mode_str = str(hex(mode))  # its a new mode, so display it
            units_str = "?"
            range_decimal_pos = 5
            logger.error(
                f"Unknown Values - MP730026.__decode_mode_and_range.mode={hex(mode)}"
            )

        value = [mode, mode_str, units_str, range_decimal_pos]
        logger.debug("	decode_mode: " + str(value))
        logger.debug("decode str: " + str(hex(mode)))

        if units_str == "?":
            logger.debug("Unknown: " + str(hex(mode)))

        return value

    def __decode_reading_into_hex(self, data: tuple, mode_data: list):
        """Decodes the reading into hex format"""

        decimal_position = mode_data[3]

        # get the reading nibbles and create a word
        readingMSB = np.int16(data[3])
        logger.debug("5: " + str(hex(readingMSB)))

        readingLSB = np.int16(data[2])
        logger.debug("4: " + str(hex(readingLSB)))

        # shift MSB over and add the LSB, creates a 16-bit word
        value = np.int16((readingMSB << 8) | readingLSB)

        # did we overload?
        if value < 32676:
            # there is a valid display value
            # check if we have a negative value and handle it with bit masking
            # later in the code, at the negative sign
            if readingMSB > 0x7F:
                value = value & 0x7FFF
            # convert the integer to a string
            final_value = "{:04d}".format(value)

            if decimal_position < 5:
                # only process decimal if valid, 5 isn't a valid position
                final_value = final_value[:
                                          decimal_position] + "." + final_value[
                                              decimal_position:]
                if readingMSB > 0x7F:
                    final_value = "-" + final_value
                    self.negative = True
                else:
                    self.negative = False
        else:
            # there is not a valid display
            final_value = "O.L"  # TODO The decimal shouldn't be hard coded

        return final_value

    def print_DMM(self):
        """ Send status to logger.info"""

        if debug:
            logger.debug("	mode_desc: " + self.mode)

        string_to_print = f"Reading [{self.mode}]: {self.value} {self.suffix}"

        # is hold on?
        if self.hold:
            string_to_print = string_to_print + ", HOLD"
        if self.rel:
            string_to_print = string_to_print + ", REL"

        return string_to_print

    def parse(self, data: bytearray) -> None:
        """
        Update instance with new data
        """
        try:
            unpacked = struct.unpack(">HHBB", data)
        except struct.error as e:
            # Happens most often when powering off the meter.
            logger.error(e)
            logger.error(
                "If you just powered off the meter, ignore the above error.")
            return None

        # show what the raw values were, in decimal
        logger.debug(f"	Received: {str(unpacked)}")

        mode_range = self.__decode_mode_and_range(unpacked)
        self.hex, self.mode, self.suffix, self.decimal = mode_range

        logger.debug("	mode_desc: " + str(mode_range[2]))

        # Save our values
        self.value = self.__decode_reading_into_hex(unpacked, mode_range)

        # If we sit in O.L for too long, hide the meter.. if enabled
        if self.ol_hide_enable:
            if self.value == "O.L":
                self.ol_count += 1
                if self.ol_count > self.ol_count_limit:
                    # Even though we are modifying self.connected, the main
                    # loop doesn't check that to maintain connectivity.
                    # Only modify self.connected once, so it's not hammering OBS
                    if self.connected:
                        self.connected = False
            else:
                # We got any value other than O.L so reset the whole process
                self.ol_count = 0
                self.connected = True

        (
            self.hold,
            self.rel,
            self.autorange,
            self.low_battery,
        ) = self.__decode_indicators(unpacked)

    def __notification_handler(self, sender: str, data: bytearray):
        self.parse(data)
        if self.output_to_console:
            print(self.print_DMM())

    async def run(self):

        logger.warning(f"{self.model} running as {self.__class__.__name__}.")
        loop = asyncio.get_event_loop()

        # If a MAC was not specified, run autoscan until we find one that matches
        while self.MAC == "autoscan":
            self.MAC = await self.scan()

        logger.warning(f"Connecting to {self.MAC}")
        while True:
            try:
                if re_match("^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$", self.MAC):
                    client = BleakClient(self.MAC, loop=loop)
                else:
                    raise ValueError

            except TypeError:
                logger.error("Invalid data type passed for MAC")
                break
            except ValueError:
                logger.error("Invalid MAC address")
                break

            try:
                while not await client.connect():
                    pass

                x = await client.is_connected()
                logger.warning(f"Connected: {x}")

                self.connected = True

                await client.start_notify(CHARACTERISTIC_UUID,
                                          self.__notification_handler)

                while await client.is_connected():
                    pass

                self.value = False
                self.autorange = False
                self.hold = False
                self.rel = False
                self.decimal = False
                self.suffix = False
                self.connected = False
                logger.warning(f"Disconnected: {x}")
                del client

            except RemoteError:
                print("Bluetooth Permissions error. See Readme.md")
                _exit(0)

            except exc.BleakError:
                continue
Example #8
0
 def setUp(self):
     self.obs = OBS()
     Config(APIURL, PROJECT)
     self.api = StagingAPI(APIURL, PROJECT)
Example #9
0
 def setUp(self):
     self.obs = OBS()
     Config(APIURL, PROJECT)