ratcashdev / mitemp

Xiaomi MI Temperature and Humidity Sensor with BLE and LCD
MIT License
106 stars 27 forks source link

Fix for single digit values thank to @rmiddlet #5

Closed f-bader closed 5 years ago

f-bader commented 5 years ago

Original thanks to @rmiddlet Fix for issue #2 and #4

Tested on a raspberry pi

sjol commented 5 years ago

I can confirm this is working as my sensor is outside and it's winter.

dseifert commented 5 years ago

I also confirm that this fixes this issue for single digit as well as negative values.

@f-bader you should update the comment in the commit regarding length of the string. For single digit temperature and single digit humidity this would be only 12 characters, and in case of temperatures at -10°C or below it would be 15 characters. For reference, I put the sensor in the freezer and got "0x54 0x3d 0x2d 0x31 0x31 0x2e 0x34 0x20 0x48 0x3d 0x37 0x30 0x2e 0x39 0x00" (T=-11.4 H=70.9).

@ratcashdev it would be great if this could be merged to support the sensor in temperatures below 10°C.

ratcashdev commented 5 years ago

Thank you, will have a look.

ratcashdev commented 5 years ago

@f-bader thanks for the submission. Could you possibly add also tests for this change?

f-bader commented 5 years ago

Sure. Will take a look at the tests later today

f-bader commented 5 years ago

@ratcashdev Please check my changes to test_parse.py

ratcashdev commented 5 years ago

@f-bader tests are failing (run tox)

>           for dataitem in data.strip('\0').split(' '):
E           TypeError: a bytes-like object is required, not 'str'

Keep in mind, that that _cache field during normal operations stores str not bytes - see handleNotification(). In this way the test needs to be enhanced with data = bytes([0x54, 0x3d, 0x32, 0x35, 0x2e, 0x36, 0x20, 0x48, 0x3d, 0x32, 0x33, 0x2e, 0x36, 0x00]).decode("utf-8").strip(' \n\t') for example.

Apparently, the previous implementation relied on the polymorphism of float()'s constructor, however, this is not the case with the new imlementation.

ratcashdev commented 5 years ago

There are also some pylint errors.

f-bader commented 5 years ago

Hi @ratcashdev

I tried to fix the tests but encounter an erro with python 2.7 This example code works fine with python 3.6 but not with 2.7

MI_TEMPERATURE = "temperature"
MI_HUMIDITY = "humidity"
MI_BATTERY = "battery"

data = bytes([0x54, 0x3d, 0x32, 0x35, 0x2e, 0x36, 0x20, 0x48, 0x3d, 0x32, 0x33, 0x2e, 0x36, 0x00]).decode("utf-8").strip(' \n\t')

res = dict()
for dataitem in data.strip('\0').split(' '):
  dataparts = dataitem.split('=')
  if dataparts[0] == 'T':
    res[MI_TEMPERATURE] = float(dataparts[1])
  elif dataparts[0] == 'H':
    res[MI_HUMIDITY] = float(dataparts[1])
res
data.strip('\0').split(' ')

Python 2.7.15rc1

{} [u'[84,', u'61,', u'50,', u'53,', u'46,', u'54,', u'32,', u'72,', u'61,', u'50,', u'51,', u'46,', u'54,', u'0]'] Python 3.6.7 {'temperature': 25.6, 'humidity': 23.6} ['T=25.6', 'H=23.6']

If i replace the test data with data = str("T=25.6 H=23.6") instead of the hex values it works just fine

Would that be fine for the unit tests as well? Will commit these changes if you give green light.

ratcashdev commented 5 years ago

@f-bader It's important that we fill-in such data that are received from the device, actually, with the same type. During real operation handleNotification is the method, that populsates the _cache field, and it is doing so using self._cache = raw_data.decode("utf-8").strip(' \n\t') It would be nice if the tests could use the same sequence of processing instructions as handleNotification. Thus I propose to do the tests like this:

 def test_parsing(self):
        """Does the Mi TEMP BT data parser works correctly?"""
        poller = MiTempBtPoller(None, MockBackend)
        data = bytes([0x54, 0x3d, 0x32, 0x35, 0x2e, 0x36, 0x20,
                      0x48, 0x3d, 0x32, 0x33, 0x2e, 0x36, 0x00]).decode("utf-8").strip(' \n\t')
        poller._cache = data
        poller._last_read = datetime.now()
        self.assertEqual(poller._parse_data()[MI_TEMPERATURE], 25.6)
        self.assertEqual(poller._parse_data()[MI_HUMIDITY], 23.6)
f-bader commented 5 years ago

@ratcashdev I understand. But sadly this does not work with python 2.7 as described in my last post. So there seems to be a difference between the rawdata and the used bytes I check if I can find a solution that work for both Python versions.

ratcashdev commented 5 years ago

@f-bader Python 2.7 is not supposed to work. See test/unit_tests/test_versioncheck.py Also since TOX does not throw errors for Python 2.7, it is ok.

f-bader commented 5 years ago

@ratcashdev Changed the code to use bytearray instead of bytes and now tox is fine with the tests bytes is interpreted as string which result in the error

ratcashdev commented 5 years ago

Checked your latest commit. There are still some errors by tox. tox -e py27,py35,py36,flake8