zewelor / bt-mqtt-gateway

A simple Python script which provides a Bluetooth to MQTT gateway, easily extensible via custom workers. See https://github.com/zewelor/bt-mqtt-gateway/wiki for more information.
MIT License
549 stars 116 forks source link

New device Inkbird IBS-TH1 (plus) #179

Open gigaphreak opened 4 years ago

gigaphreak commented 4 years ago

Hi there,

I modified the toothbrush.py to work with Inkbird IBS-TH1 (plus) Smart Sensor. https://www.ink-bird.com/products-smart-sensor-ibsth1.html

Just put the following code in a new file workers/ibsth1.py and complete your configuration in config.yaml (see below):


import time

from mqtt import MqttMessage

from workers.base import BaseWorker
import logger

REQUIREMENTS = ["bluepy"]
_LOGGER = logger.get(__name__)

class Ibsth1Worker(BaseWorker):
    def searchmac(self, devices, mac):
        for dev in devices:
            if dev.addr == mac.lower():
                return dev

        return None

    def status_update(self):
        from bluepy.btle import Scanner, DefaultDelegate

        class ScanDelegate(DefaultDelegate):
            def __init__(self):
                DefaultDelegate.__init__(self)

            def handleDiscovery(self, dev, isNewDev, isNewData):
                if isNewDev:
                    _LOGGER.debug("Discovered new device: %s" % dev.addr)

        scanner = Scanner().withDelegate(ScanDelegate())
        devices = scanner.scan(5.0)
        ret = []

        for name, mac in self.devices.items():
            device = self.searchmac(devices, mac)
            if device is None:
                ret.append(
                    MqttMessage(
                        topic=self.format_topic(name + "/presence"), payload="0"
                    )
                )
            else:
                ret.append(
                    MqttMessage(
                        topic=self.format_topic(name + "/presence/rssi"),
                        payload=device.rssi,
                    )
                )
                ret.append(
                    MqttMessage(
                        topic=self.format_topic(name + "/presence"), payload="1"
                    )
                )
                readBuffer=device.getValueText(255)
                _LOGGER.debug("text: %s" % readBuffer)
                if readBuffer is not None:
                  bytes_ = bytearray(bytes.fromhex(readBuffer))
                  temperature_raw_value = bytes_[1] * 256 + bytes_[0]
                  if temperature_raw_value >= 0x8000:
                     temperature_ibsth1=(temperature_raw_value - 0x10000) / 100
                  else:
                     temperature_ibsth1=temperature_raw_value / 100
                  ret.append(
                      MqttMessage(
                          topic=self.format_topic(name + "/externalSensor"), payload=bytes_[4]
                      )
                  )
                  ret.append(
                      MqttMessage(
                          topic=self.format_topic(name + "/battery"), payload=bytes_[7]
                      )
                  )
                  ret.append(
                      MqttMessage(
                          topic=self.format_topic(name + "/temperature"),
                          payload=temperature_ibsth1,
                      )
                  )
                  ret.append(
                      MqttMessage(
                          topic=self.format_topic(name + "/humidity"),
                          payload=(bytes_[3] * 256 + bytes_[2])/100,
                      )
                  )
            yield ret

Example configuration in config.yaml:

    ibsth1:
      args:
        devices:
          ibsth1: xx:xx:xx:xx:xx:xx
        topic_prefix: inkbird
      update_interval: 60

Best regards and feel free to add to the repository.

Best, Chris

kayaozalp commented 3 years ago

Hi @gigaphreak , I've been trying this on a Pi Zero and now on Pi4, and on both cases getting the below error. Is this something you have observed?

Fatal error while executing worker command: BTLEManagementError
Traceback (most recent call last):
  File "./gateway.py", line 107, in <module>
    raise e
  File "./gateway.py", line 89, in <module>
    mqtt.publish(_WORKERS_QUEUE.get(timeout=10).execute())
  File "/application/workers_manager.py", line 55, in execute
    for message in self._callback(*self._args):
  File "/application/workers/ibsth1.py", line 32, in status_update
    devices = scanner.scan(5.0)
  File "/usr/local/lib/python3.8/site-packages/bluepy/btle.py", line 854, in scan
    self.stop()
  File "/usr/local/lib/python3.8/site-packages/bluepy/btle.py", line 803, in stop
    self._mgmtCmd(self._cmd()+"end")
  File "/usr/local/lib/python3.8/site-packages/bluepy/btle.py", line 312, in _mgmtCmd
    raise BTLEManagementError("Failed to execute management command '%s'" % (cmd), rsp)
bluepy.btle.BTLEManagementError: Failed to execute management command 'scanend' (code: 11, error: Rejected)
mike0xt commented 3 years ago

Thanks @gigaphreak!! This seems to work well as-is.

However, for two devices, I found that while this script outputs the expected return, the workers_manager doubles the first device in the message.

For example, I added a debug to print out the payload returned by this worker:

DEBUG bt-mqtt-gw.workers.ibsth1 ibsth1.py:96:status_update - ret: [{'topic': 'inkbird/ibs1/presence/rssi', 'payload': '-86'}, {'topic': 'inkbird/ibs1/presence', 'payload': '1'}, {'topic': 'inkbird/ibs1/externalSensor', 'payload': '0'}, {'topic': 'inkbird/ibs1/battery', 'payload': '28'}, {'topic': 'inkbird/ibs1/temperature', 'payload': '11.74'}, {'topic': 'inkbird/ibs1/humidity', 'payload': '55.99'}, {'topic': 'inkbird/ibs2/presence/rssi', 'payload': '-74'}, {'topic': 'inkbird/ibs2/presence', 'payload': '1'}, {'topic': 'inkbird/ibs2/externalSensor', 'payload': '0'}, {'topic': 'inkbird/ibs2/battery', 'payload': '98'}, {'topic': 'inkbird/ibs2/temperature', 'payload': '16.82'}, {'topic': 'inkbird/ibs2/humidity', 'payload': '66.5'}]```

But in the standard debug output, note that device 1 (ibs1) is duplicated twice:

DEBUG bt-mqtt-gw.workers_manager workers_manager.py:57:execute - Execution result of command Ibsth1Worker.status_update: [{'topic': 'inkbird/ibs1/presence/rssi', 'payload': '-86'}, {'topic': 'inkbird/ibs1/presence', 'payload': '1'}, {'topic': 'inkbird/ibs1/externalSensor', 'payload': '0'}, {'topic': 'inkbird/ibs1/battery', 'payload': '28'}, {'topic': 'inkbird/ibs1/temperature', 'payload': '11.74'}, {'topic': 'inkbird/ibs1/humidity', 'payload': '55.99'}, {'topic': 'inkbird/ibs1/presence/rssi', 'payload': '-86'}, {'topic': 'inkbird/ibs1/presence', 'payload': '1'}, {'topic': 'inkbird/ibs1/externalSensor', 'payload': '0'}, {'topic': 'inkbird/ibs1/battery', 'payload': '28'}, {'topic': 'inkbird/ibs1/temperature', 'payload': '11.74'}, {'topic': 'inkbird/ibs1/humidity', 'payload': '55.99'}, {'topic': 'inkbird/ibs2/presence/rssi', 'payload': '-74'}, {'topic': 'inkbird/ibs2/presence', 'payload': '1'}, {'topic': 'inkbird/ibs2/externalSensor', 'payload': '0'}, {'topic': 'inkbird/ibs2/battery', 'payload': '98'}, {'topic': 'inkbird/ibs2/temperature', 'payload': '16.82'}, {'topic': 'inkbird/ibs2/humidity', 'payload': '66.5'}]

@zewelor is this expected?

zewelor commented 3 years ago

Maybe you have duplicated ibs1 in config ? I don't see other reason for now.

Pauligrinder commented 11 months ago

Thanks for this, this also works with the Inkbird IBS-P01B pool thermometer which I'm using in my hot tub. Thanks to this I can now see it's temperature in home-assistant 🙂