示例#1
0
    def __init__(self, data: bytes):
        """Init."""
        try:
            self._address = data[3:9]
            self.mac = reverse_mac(self._address)
            self.rssi = rssi_from_byte(data[-1])
            self.raw_data = data[10:-1]
            self.flags = 6
            self.name = None
            self.packet = None
            self.temperature = None
            self.humidity = None
            self.battery = None

            pos = 10
            while pos < len(data) - 1:
                _LOGGER.debug("POS={}".format(pos))
                length = data[pos]
                payload_offset = pos + 2
                gap_type = data[pos + 1]
                payload_end = payload_offset + length - 1
                payload = data[payload_offset:payload_end]
                _LOGGER.debug("Pos={} Type=0x{:02x} Len={} Payload={}".format(
                    pos, gap_type, length, hex_string(payload)))
                if GAP_FLAGS == gap_type:
                    self.flags = payload[0]
                    _LOGGER.debug("Flags={:02x}".format(self.flags))
                elif GAP_NAME_COMPLETE == gap_type:
                    self.name = str(payload)
                    _LOGGER.debug("Complete Name={}".format(self.name))
                elif GAP_MFG_DATA == gap_type:
                    # unit8
                    self.mfg_data = payload
                    msg = "Manufacturer Data={}"
                    _LOGGER.debug(msg.format(str(self.mfg_data)))
                pos += length + 1

            if self.check_is_gvh5075_gvh5072():
                mfg_data_5075 = hex_string(self.mfg_data[3:6]).replace(" ", "")
                self.packet = int(mfg_data_5075, 16)
                self.temperature = float(self.packet / 10000)
                self.humidity = float((self.packet % 1000) / 10)
                self.battery = int(self.mfg_data[6])
            elif self.check_is_gvh5074():
                mfg_data_5074 = hex_string(self.mfg_data[3:7]).replace(" ", "")
                temp_lsb = mfg_data_5074[2:4] + mfg_data_5074[0:2]
                hum_lsb = mfg_data_5074[6:8] + mfg_data_5074[4:6]
                self.packet = temp_lsb + hum_lsb
                self.humidity = float(int(hum_lsb, 16) / 100)
                # Negative temperature stored an two's complement
                temp_lsb_int = int(temp_lsb, 16)
                self.temperature = float(twos_complement(temp_lsb_int) / 100)
                self.battery = int(self.mfg_data[7])
        except (ValueError, IndexError):
            pass
    def __init__(self, data: bytes):
        """ init from ble advertising data

        preamble: 3
        Access Address: 6
        GAP Packet: N
        GAP Packet[1]: N
        GAP_Packet[2]: N

        GAP Packet:
            length: 1 (length of packet not including the length byte)
            type: 1
            Payload: N
        """

        self.rssi = rssi_from_byte(data[-1])
        self.mac = BDAddress(data[3:9])
        self.name = None
        self._raw_mfg_data = None

        gap_data = data[10:-1]  # trim the data to just the ad data
        offset = 0
        # parse the GAP reports in a loop
        while offset < len(gap_data):
            length = gap_data[offset]
            # process gap data starting with type byte (first byte after size)
            self._process_gap(gap_data[offset + 1:offset + 1 + length])
            offset += 1 + length

        if len(gap_data) < 1:
            # catch packets that have no GAP data as
            # the mopeka sensor does send these and they
            # should not be considered an error.
            raise NoGapDataException("No GAP data")

        if self._raw_mfg_data is None:
            # Make sure we found the required MFG_DATA for Mopeka Sensor
            raise Exception("Incomplete Sensor Data")
示例#3
0
    def __init__(self, data: bytes):
        """Init."""
        try:
            self._address = data[3:9]
            self.mac = reverse_mac(self._address)
            self.rssi = rssi_from_byte(data[-1])
            self.raw_data = data[10:-1]
            self.flags = 6
            self.name = None
            self.packet = None
            self.temperature = None
            self.humidity = None
            self.battery = None
            self.model = None

            pos = 10
            while pos < len(data) - 1:
                _LOGGER.debug("POS={}".format(pos))
                length = data[pos]
                payload_offset = pos + 2
                gap_type = data[pos + 1]
                payload_end = payload_offset + length - 1
                payload = data[payload_offset:payload_end]
                _LOGGER.debug(
                    "Pos={} Type=0x{:02x} Len={} Payload={}".format(
                        pos, gap_type, length, hex_string(payload)
                    )
                )
                if GAP_FLAGS == gap_type:
                    self.flags = payload[0]
                    _LOGGER.debug("Flags={:02x}".format(self.flags))
                elif GAP_NAME_COMPLETE == gap_type:
                    self.name = payload.decode("ascii")
                    _LOGGER.debug("Complete Name={}".format(self.name))
                elif GAP_MFG_DATA == gap_type:
                    # unit8
                    self.mfg_data = payload
                    msg = "Manufacturer Data={}"
                    _LOGGER.debug(msg.format(str(self.mfg_data)))
                pos += length + 1

            if self.check_is_gvh5075_gvh5072():
                mfg_data_5075 = hex_string(self.mfg_data[3:6]).replace(" ", "")
                self.packet = int(mfg_data_5075, 16)
                self.temperature = decode_temps(self.packet)
                self.humidity = float((self.packet % 1000) / 10)
                self.battery = int(self.mfg_data[6])
                self.model = "Govee H5072/H5075"
            elif self.check_is_gvh5102():
                mfg_data_5075 = hex_string(self.mfg_data[4:7]).replace(" ", "")
                self.packet = int(mfg_data_5075, 16)
                self.temperature = decode_temps(self.packet)
                self.humidity = float((self.packet % 1000) / 10)
                self.battery = int(self.mfg_data[7])
                self.model = "Govee H5101/H5102"
            elif self.check_is_gvh5179():
                temp, hum, batt = unpack_from("<HHB", self.mfg_data, 6)
                self.packet = hex(temp)[2:] + hex(hum)[2:]
                # Negative temperature stored an two's complement
                self.temperature = float(twos_complement(temp) / 100.0)
                self.humidity = float(hum / 100.0)
                self.battery = int(batt)
                self.model = "Govee H5179"
            elif self.check_is_gvh5074() or self.check_is_gvh5051():
                temp, hum, batt = unpack_from("<HHB", self.mfg_data, 3)
                self.packet = hex(temp)[2:] + hex(hum)[2:]
                # Negative temperature stored an two's complement
                self.temperature = float(twos_complement(temp) / 100.0)
                self.humidity = float(hum / 100.0)
                self.battery = int(batt)
                self.model = "Govee H5074/H5051"
        except (ValueError, IndexError):
            pass
示例#4
0
    def __init__(self, data: bytes, brand: DeviceBrand):
        """Init."""
        try:
            #  Byte 0: Num reports to follow (we only expect 01)
            #  Byte 1: GAP (Generic Access Profile) ADV type (can be 00=ADV_IND or
            #      04=SCAN_RSP)
            #  Byte 2: GAP Addr type (Govees send 00=LE_PUBLIC_ADDRESS, Moats send
            #      01=LE_RANDOM_ADDRESS)
            #  Bytes 3-8: MAC address (reverse byte order)
            self.mac = reverse_mac(data[3:9])
            #  Byte 9: Length (not counting header or final RSSI byte, so should be 11
            #      less than len(data)).
            #  Bytes 10-[len(data)-1]: List of GAP Data
            #    Byte 0: GAP Data length
            #    Byte 1: GAP Data type
            #    Bytes 2-[(GAP Data length)-2]: GAP Data payload
            #  Byte [len(data)-1]: Signal Power (RSSI)
            self.rssi = rssi_from_byte(data[-1])

            self.flags = 6
            self.name = None
            self.packet = None
            self.temperature = None
            self.humidity = None
            self.battery = None
            self.battery_millivolts = None
            self.model = None

            pos = 10
            while pos < len(data) - 1:
                #    Byte 0: GAP Data length
                length = data[pos]
                #    Byte 1: GAP Data Type
                gap_type = data[pos + 1]
                #    Bytes 2-[GAP length - 2]: GAP Data payload
                payload_offset = pos + 2
                payload_end = payload_offset + length - 1
                payload = data[payload_offset:payload_end]
                _LOGGER.debug(
                    "Pos=%d Type=%02x Len=%d Payload=%s",
                    pos,
                    gap_type,
                    length,
                    hex_string(payload),
                )
                if GAP_FLAGS == gap_type:
                    self.flags = payload[0]
                    _LOGGER.debug("Flags=%02x", self.flags)
                elif GAP_NAME_COMPLETE == gap_type:
                    self.name = payload.decode("ascii")
                    _LOGGER.debug("Complete Name=%s", self.name)
                elif GAP_SERVICE_DATA == gap_type:
                    self.mfg_data = payload
                    _LOGGER.debug("Service Data=%s", hex_string(self.mfg_data))
                elif GAP_MFG_DATA == gap_type:
                    self.mfg_data = payload
                    _LOGGER.debug("Manufacturer Data=%s", hex_string(self.mfg_data))
                pos += length + 1

            # Not all advertisements contain the measurement data.
            if (brand is DeviceBrand.MOAT) and self.check_is_moat_s2():
                # Packet format (including temperature and humidity conversions) were
                # kindly provided by the Moat developer, Erik Laybourne.

                # timestamp = little_endian_to_unsigned_int(self.mfg_data[8:12])
                self.temperature = -46.85 + 175.72 * (
                    little_endian_to_unsigned_int(self.mfg_data[12:14]) / 65536.0
                )
                self.humidity = -6.0 + 125.0 * (
                    little_endian_to_unsigned_int(self.mfg_data[14:16]) / 65536.0
                )
                self.battery_millivolts = little_endian_to_unsigned_int(
                    self.mfg_data[16:18]
                )
                self.battery = int(
                    moat_s2_battery_voltage_to_percentage(self.battery_millivolts)
                )
                self.packet = hex_string(self.mfg_data[8:18]).replace(" ", "")
                self.model = "Moat S2"
            elif brand is DeviceBrand.GOVEE:
                if self.check_is_gvh5075_gvh5072():
                    mfg_data_5075 = hex_string(self.mfg_data[3:6]).replace(" ", "")
                    self.packet = int(mfg_data_5075, 16)
                    self.temperature = decode_govee_temp(self.packet)
                    self.humidity = (self.packet % 1000) / 10.0
                    self.battery = int(self.mfg_data[6])
                    self.model = "Govee H5072/H5075"
                elif self.check_is_gvh5102():
                    mfg_data_5075 = hex_string(self.mfg_data[4:7]).replace(" ", "")
                    self.packet = int(mfg_data_5075, 16)
                    self.temperature = decode_govee_temp(self.packet)
                    self.humidity = (self.packet % 1000) / 10.0
                    self.battery = int(self.mfg_data[7])
                    self.model = "Govee H5101/H5102"
                else:
                    is_5074_or_5051 = False
                    if self.check_is_gvh5074():
                        self.model = "Govee H5074"
                        is_5074_or_5051 = True
                    elif self.check_is_gvh5051():
                        self.model = "Govee H5051"
                        is_5074_or_5051 = True

                    if is_5074_or_5051:
                        mfg_data_5074 = hex_string(self.mfg_data[3:7]).replace(" ", "")
                        temp_lsb = mfg_data_5074[2:4] + mfg_data_5074[0:2]
                        hum_lsb = mfg_data_5074[6:8] + mfg_data_5074[4:6]
                        self.packet = temp_lsb + hum_lsb
                        self.humidity = float(int(hum_lsb, 16) / 100)
                        # Negative temperature stored an two's complement
                        temp_lsb_int = int(temp_lsb, 16)
                        self.temperature = float(twos_complement(temp_lsb_int) / 100)
                        self.battery = int(self.mfg_data[7])
            else:
                return
            _LOGGER.debug(
                "Read=%s %f %f %d (%s) %r (%s)",
                self.mac,
                self.temperature,
                self.humidity,
                self.battery,
                self.packet,
                self.rssi,
                self.model,
            )
        except (ValueError, IndexError):
            pass
    def __init__(self, data: bytes):
        """Init."""
        try:
            self._address = data[3:9]
            self.mac = reverse_mac(self._address)
            self.rssi = rssi_from_byte(data[-1])
            self.raw_data = data[10:-1]
            self.flags = 6
            self.name = None
            self.packet = None
            self.temperature = None
            self.humidity = None
            self.battery = None
            self.model = None

            pos = 10
            while pos < len(data) - 1:
                _LOGGER.debug("POS={}".format(pos))
                length = data[pos]
                payload_offset = pos + 2
                gap_type = data[pos + 1]
                payload_end = payload_offset + length - 1
                payload = data[payload_offset:payload_end]
                _LOGGER.debug("Pos={} Type=0x{:02x} Len={} Payload={}".format(
                    pos, gap_type, length, hex_string(payload)))
                if GAP_FLAGS == gap_type:
                    self.flags = payload[0]
                    _LOGGER.debug("Flags={:02x}".format(self.flags))
                elif GAP_NAME_COMPLETE == gap_type:
                    self.name = payload.decode("ascii")
                    _LOGGER.debug("Complete Name={}".format(self.name))
                elif GAP_MFG_DATA == gap_type:
                    # unit8
                    self.mfg_data = payload
                    msg = "Manufacturer Data={}"
                    _LOGGER.debug(msg.format(str(self.mfg_data)))
                pos += length + 1

            if self.check_is_gvh5075_gvh5072():
                mfg_data_5075 = hex_string(self.mfg_data[3:6]).replace(" ", "")
                self.packet = int(mfg_data_5075, 16)
                self.temperature = decode_temps(self.packet)
                self.humidity = float((self.packet % 1000) / 10)
                self.battery = int(self.mfg_data[6])
                self.model = "Govee H5072/H5075"
            elif self.check_is_gvh5102():
                mfg_data_5075 = hex_string(self.mfg_data[4:7]).replace(" ", "")
                self.packet = int(mfg_data_5075, 16)
                self.temperature = decode_temps(self.packet)
                self.humidity = float((self.packet % 1000) / 10)
                self.battery = int(self.mfg_data[7])
                self.model = "Govee H5101/H5102"
            elif self.check_is_gvh5179():
                temp, hum, batt = unpack_from("<HHB", self.mfg_data, 6)
                self.packet = hex(temp)[2:] + hex(hum)[2:]
                # Negative temperature stored an two's complement
                self.temperature = float(twos_complement(temp) / 100.0)
                self.humidity = float(hum / 100.0)
                self.battery = int(batt)
                self.model = "Govee H5179"
            elif self.check_is_gvh5074() or self.check_is_gvh5051():
                temp, hum, batt = unpack_from("<HHB", self.mfg_data, 3)
                self.packet = hex(temp)[2:] + hex(hum)[2:]
                # Negative temperature stored an two's complement
                self.temperature = float(twos_complement(temp) / 100.0)
                self.humidity = float(hum / 100.0)
                self.battery = int(batt)
                self.model = "Govee H5074/H5051"
            elif self.check_is_ThermoBeacon():
                # .. .. .. ID ID ID ID ID ID ID ID ID .. .. TEMPE HUMID .. .. .. ..
                # 15 ff 11 00 00 00 fe 01 00 00 e1 00 3b 0c 6e 01 a0 03 e2 30 01 00 bc
                self.name = "Thermobeacon"
                self.packet = hex_string(self.mfg_data)
                # Temperature (-20 to +65)
                # Temperate hex stored reversed. Multiply second byte by 256 then add to first
                # Negative temperature stored an two's complement
                temp_temp = twos_complement(
                    (int(self.mfg_data[12]) + (int(self.mfg_data[13]) * 256)))
                # Data is actual value multiplied by 16
                self.temperature = float(temp_temp / 16)
                # Humidity
                # Humidity hex stored reversed. Multiply second byte by 256 then add to first
                # Data is actual value multiplied by 16
                self.humidity = float((int(self.mfg_data[14]) +
                                       (int(self.mfg_data[15]) * 256)) / 16)
                # Not identified battery data
                self.battery = 100
                self.model = "ThermoBeacon"
        except (ValueError, IndexError):
            pass