jdeath / rd200v2

RadonEye RD200 Version 2 Integration for Home Assistant
MIT License
73 stars 17 forks source link

Add full support for V1 #21

Closed stleusc closed 11 months ago

stleusc commented 12 months ago

Wondering if you are willing to add support for V1? I do have the spec that is needed to support the same data for V1 and V2.

When writing 0x50 the data is:

  current = extractFloat(data, 2);
  avg_1d = extractFloat(data, 6);
  avg_30d = extractFloat(data, 10);

You already have those 3 values.

When writing 0x51 the data is:

  runtime_min = extractInt(data, 4, 4);
  peak = extractFloat(data, 12);

I believe it should be very easy with that info. I never use python for my coding or else I would offer to do it.

stleusc commented 11 months ago

I never use python but it looked easy enough...

    async def _get_radon_peak_uptime_oldVersion(
        self, client: BleakClient, device: RD200Device
    ) -> RD200Device:

        self._event = asyncio.Event()
        await client.start_notify(
            RADON_CHARACTERISTIC_UUID_READ_OLDVERSION, self.notification_handler
        )
        await client.write_gatt_char(
            RADON_CHARACTERISTIC_UUID_WRITE_OLDVERSION, b"\x51"
        )

        # Wait for up to fice seconds to see if a
        # callback comes in.
        try:
            await asyncio.wait_for(self._event.wait(), 5)
        except asyncio.TimeoutError:
            self.logger.warn("Timeout getting command data.")

        await client.stop_notify(RADON_CHARACTERISTIC_UUID_READ_OLDVERSION)

        if self._command_data is not None and len(self._command_data) >= 13:
            RadonValuePCI = struct.unpack("<f", self._command_data[12:16])[0]
            device.sensors["radon_peak"] = round(float(RadonValuePCI),2)
            if self.is_metric:
                device.sensors["radon_peak"] = round(float(RadonValuePCI) / BQ_TO_PCI_MULTIPLIER,2)

            uptimeMinutes = struct.unpack("<I", self._command_data[4:8])[0]
            device.sensors["radon_uptime"] = (
                int(uptimeMinutes)
            )
            day = int (uptimeMinutes // 1440)
            hours = int (uptimeMinutes % 1440) // 60
            mins = int (uptimeMinutes % 1440) % 60
            sec = 0

            device.sensors["radon_uptime_string"] = (
                str(day) + "d " + str(hours).zfill(2) + ":" + str(mins).zfill(2) + ":" + str(sec).zfill(2)
            )
        else:
            device.sensors["radon_peak"] = None
            device.sensors["radon_uptime"] = None
            device.sensors["radon_uptime_string"] = None

        self._command_data = None
        return device

Works like a charm... I had a java lib that was reading this before. I never had an issue to get uptime or peak, even on my first read.

I am simply calling this here:

        if ble_device.name.startswith("FR:R2"):
            device = await self._get_radon_oldVersion(client, device)
            device = await self._get_radon_peak_uptime_oldVersion(client, device)
        else:

It might need so better review since I basically just copied some of your code fragments and adjusted them. But I confirmed, the data is exactly what I am reading in the official app.

jdeath commented 11 months ago

Sure. I'll add it. Thanks for figuring it out.

stleusc commented 11 months ago

This should probably be adjusted:

  if self._command_data is not None and len(self._command_data) >= 13:

That was copy/paste. I am using data beyond 13.

I also noticed that on the V2 code you have

@disconnect_on_missing_services

Which is not on the V1 code. I honestly don't know what it does so you need to decide if that is needed or not.

stleusc commented 11 months ago

And I throw in another question for you...

Where is it configured how often new data is being polled. Right now I only see it being done once?! But I only spent like 10 min in your code, so I probably just missed it.

jdeath commented 11 months ago

the @disconnect thing does nothing. It was supposed to help with connection errors, but I did not implement it right. The >13 was just a check to see if get good data. Leaving that way will probably be fine. I'll make the change. After this, please do a PR. I cannot test V1 anyways. const.py sets DEFAULT_SCAN_INTERVAL = 600 (which is seconds)

stleusc commented 11 months ago

DEFAULT_SCAN_INTERVAL does not seem to do much. My data does not get updated.... Also, V1 apparently does not support 30day AVG anymore. It is gone in the official app! And the data I read is a 0.

stleusc commented 11 months ago

Why did you close it?

jdeath commented 11 months ago

I closed because it is now added in. The device only updates itself every 10 minutes, so might not get updates. You may not get 30 days, if it has not been on for 30 days. That is how the V2 works.

stleusc commented 11 months ago

Yes, I unplugged it 2 weeks ago. That could be true! Sorry man, I had no idea you were that quick hahaha. I was confused why you closed it. Most guys need weeks to add a change like that.

Thanks so much!