RadonEye BLE Interface

Glad to see so much work on this!! I don’t have a rPi so I’m still planning on developing an alternative that doesn’t rely on the Bluez stack, maybe on ESP32. No timeline…

Thanks a lot Carlos, your script works great!

To find your MAC, run bluetoothctl and issue “scan on”. You will soon see a device with the SN of your radoneye (which you can see when you launch the iPhone app - I assume android too), and the associated MAC.

1 Like

Great work on this as I just purchased a RD200 and tested the code with success. I too poked around last night in the code and started to implement MQTT upload as a command line option. Also I am starting to look at HACS to add it as a custom component in my install. skis4hire and Carlos great work on figuring this out and creating the code.

1 Like

Thanks skis4hire, great reverse engineering…

You can also log bluetooth packets on iPhone.
https://developer.apple.com/bug-reporting/profiles-and-logs/

In the RadonEye iPhone app, in addition to just displaying the current reading, there is another screen that will download all the the logged past readings from the device and plot it. I was trying to capture this process with bluetooth logging.

I think (?) when triggering the download, the app sends an \xE8 (instead of \x50 or \x51) and gets a 20-byte reply, then sends an \xE9 and gets a longer reply, maybe the log data (6 packets x 20 bytes = 120 bytes). I have ~55 data points logged (55 hours uptime) so if 2 bytes each I guess that would fit into 120 bytes. When the app plots the data, it is a kind of bare-bones plot, the x-axis is simply labeled “Time(1hour)” so I think it’s just the last X hours of data plotted. That would be consistent with no timestamps in the data, just the radon readings.

However, I wasn’t able to reproduce the above in python on my raspberry pi… I do get a 20-byte reply to the \xE8, but no response to the \xE9 message, which is weird. When I send the \xE9 I seem to get a repeat of the response to the last command, whatever it was. Maybe I don’t know how to read multi-packet messages in python? I have to read up on btle.Peripheral maybe.

(BTW this device is great, the measurement responds really quickly if you move it to a new part of your house, very nice for sorting out radon level in different areas… the competing device by Airthings gives only a 24 hour average reading.)

What is this for? can anyone eli5?

@mepster On Android app also have this options. But I hate that it has no timestamp. Because this I created this script. On RadonEye app plot, it shows only 1hour average, then you can’t see radon peak.
Btw, I’m not a home assistant user (lol), I use EmonCMS, then I use my script to write radon data to input feeds on EmonCMS and plot a graph with timestamps

My radon ploting with EmonCMS (one week):

So I hacked up the code a bit for some testing to start. It is currently logging in Home Assistant via MQTT. In doing so the following was added, -m option to export to mqtt. I then set the following as a cron job to run every 5 minutes.

./mqtt_radon.py -a E2:5A:90:00:00:00 -s -m

#!/usr/bin/python

""" radon_reader.py: RadonEye RD200 (Bluetooth/BLE) Reader """

__progname__    = "RadonEye RD200 (Bluetooth/BLE) Reader"
__version__     = "0.2"
__author__      = "Carlos Andre"
__email__       = "candrecn at hotmail dot com"
__date__        = "2019-07-17"

import argparse, struct, time, re
import paho.mqtt.client as mqtt
import time
import json

from bluepy import btle
from time import sleep
from random import *

broker_address="mqtt.broker.tld"

parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description=__progname__)
parser.add_argument('-a','--address',help='Bluetooth Address (AA:BB:CC:DD:EE:FF format)',required=True)
parser.add_argument('-b','--becquerel',action='store_true',help='Display radon value in Becquerel (Bq/m^3) unit', required=False)
parser.add_argument('-v','--verbose',action='store_true',help='Verbose mode', required=False)
parser.add_argument('-s','--silent',action='store_true',help='Only output radon value (without unit and timestamp)', required=False)
parser.add_argument('-m','--mqtt',action='store_true',help='Enable MQTT output (provide path to mqtt_config.ini)', required=False)
args = parser.parse_args()

if not re.match("[0-9a-f]{2}(:?)[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", args.address.lower()):
    parser.print_help()
    quit()

def GetRadonValue():
    if args.verbose and not args.silent:
        print ("Connecting...")
    DevBT = btle.Peripheral(args.address.upper(), "random")
    RadonEye = btle.UUID("00001523-1212-efde-1523-785feabcd123")
    RadonEyeService = DevBT.getServiceByUUID(RadonEye)

    # Write 0x50 to 00001524-1212-efde-1523-785feabcd123
    if args.verbose and not args.silent:
        print ("Writing...")
    uuidWrite  = btle.UUID("00001524-1212-efde-1523-785feabcd123")
    RadonEyeWrite = RadonEyeService.getCharacteristics(uuidWrite)[0]
    RadonEyeWrite.write(bytes("\x50"))

    # Read from 3rd to 6th byte of 00001525-1212-efde-1523-785feabcd123
    if args.verbose and not args.silent:
        print ("Reading...")
    uuidRead  = btle.UUID("00001525-1212-efde-1523-785feabcd123")
    RadonEyeValue = RadonEyeService.getCharacteristics(uuidRead)[0]
    RadonValue = RadonEyeValue.read()
    RadonValue = struct.unpack('<f',RadonValue[2:6])[0]
   
    if args.becquerel:
        Unit="Bq/m^3"
        RadonValue = ( RadonValue * 37 )
    else:
        Unit="pCi/L"
 
    if args.mqtt:
        client = mqtt.Client("FR_R20_SN|%s" % randint(1, 2300), clean_session=True)
        client.username_pw_set("anonymous", "password")
        client.connect(broker_address, 1883, 30)
        client.subscribe("enviroment/radoneye")
        mqttval=json.dumps({"radonvalue": "%0.2f" % (RadonValue)});
        client.publish("enviroment/radoneye", mqttval, qos=1, retain=True)
        time.sleep(4)
        client.disconnect()
    else:
        print("")
    if args.silent:
        print ("%0.2f" % (RadonValue))
    else: 
        print ("%s - %s - Radon Value: %0.2f %s" % (time.strftime("%Y-%m-%d [%H:%M:%S]"),args.address.upper(),RadonValue,Unit))
    
try:
    GetRadonValue()
except:
    for i in range(1,4):
        try:
            if args.verbose and not args.silent:
                print ("Connection failed, trying again (%s)..." % i)
            sleep(5)
            GetRadonValue()
        except:
            if i < 3:
                continue
            else:
                print ("Connection failed.")
        break

configuration.yaml in Home Assistant

sensor:
  - platform: mqtt
    name: 'Radon Level'
    unit_of_measurement: 'pCi/L'
    value_template: '{{ value_json.radonvalue }}'
    force_update: true
    state_topic: 'enviroment/radoneye'
1 Like

Hi ppl!
I’ve just upped to my repo new version with MQTT support.

Since I’m using EmonCMS I implemented it to use MQTT EmonCMS format and I created a key to register each RadonEye individually using last octets of bluetooth address (useful if you have more than one RadonEye).

Since I’m just noticed @TheDoC mqtt version to Home Assistent I’m tried to append his idea to my code, but since I not Home Assistent user I cannot test it if the idea works on HA (including a key associated to bluetooth address).
Then, please test and give me feedback.

@mepster @Djow @stogs

Thanks :smiley:

2 Likes

Nice! Great job

1 Like

I will test the new code out tonight. The only suggestion I have is for the client to have an identifier with a randomized number appended to the end. I was having issues with connection errors before I added it as it seemed that it was not closing out the session after issuing the client.disconnect()

client = mqtt.Client("FR_R20_SN|%s" % randint(1, 2300), clean_session=True)

And then for HA the state topic will need updated to reflect the last 3 octets appened to the topic as client identifier.

sensor:
  - platform: mqtt
    name: 'Radon Level'
    unit_of_measurement: 'pCi/L'
    value_template: '{{ value_json.radonvalue }}'
    force_update: true
    state_topic: 'enviroment/radoneye/A1B2C3'

Thank you for your hard work in developing this.

@TheDoC Hi. Thanks for reply.

Ok, I added the random ID generator. Anyway, explicity ‘clean_session=True’ isn’t needed, it’s already the default.

REkey var is created with octets separated by dash. Unless if it’s isn’t supported by Home Assistant (it’s not?).

sensor:
  - platform: mqtt
    name: 'Radon Level'
    unit_of_measurement: 'pCi/L'
    value_template: '{{ value_json.radonvalue }}'
    force_update: true
    state_topic: 'enviroment/radoneye/A1-B2-C3'

Upped to repo the changes.

Thanks for feedback :slight_smile:

1 Like

@ceandre The dash in the REkey should be fine. I must have overlooked the the replace “:”,"-" portion and thought it was stripping the : out completely. That was my bad.

Also I had the ‘clean_session=True’ in there as I was throwing args at it to fix the connection issue before stumbling on the random number generation in the client id.

Thank you again for diving right in.

2 Likes

Hi all,

thanks to the first post getting all the information about the BT-Proto of the radoneye sensor. I have spent some time to programm a custom_sensor.h with radoeye for esp32 boards using esphome-Software. It is not done yet, but maybe a good start.

Best Michi

‘file: my_custom_sensor.h’

#include "esphome.h"
#include "BLEDevice.h"
//#include "BLEScan.h"


// The remote service we wish to connect to.
static BLEUUID serviceUUID("00001523-1212-efde-1523-785feabcd123");
//service = dev.getServiceByUUID(btle.UUID('00001523-1212-efde-1523-785feabcd123'))
// The characteristic of the remote service we are interested in.
static BLEUUID    charUUID("00001525-1212-efde-1523-785feabcd123");
static BLEUUID    char24UUID("00001524-1212-efde-1523-785feabcd123");
//character = dev.getCharacteristics(startHnd=1, endHnd=0xFFFF, uuid=btle.UUID('00001525-1212-efde-1523-785feabcd123'))

static union { char c[4]; uint32_t b; float f; } radonval;
static union { char c[2]; uint16_t b; } pulsval;
static float radonnow; 
static float radonday;
static float radonmonth;
static int puls;
static int puls10; 

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLERemoteCharacteristic* p2RemoteCharacteristic;
static BLERemoteService* pRemoteService;
static BLEAdvertisedDevice* myDevice;
static String My_BLE_Address = "C1:96:0D:53:E9:A6";
//radon1 DA:B9:2C:5A:A9:75
//radon2 C1:96:0D:53:E9:A6
static BLEAddress *Server_BLE_Address;
static String Scanned_BLE_Address;
static boolean foundDevice = false; // Flag verifying if we found our device


static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    ESP_LOGD("custom","Callback");
    //ESP_LOGD("custom","Notify callback for characteristic %s", pBLERemoteCharacteristic->getUUID().toString().c_str());
    //ESP_LOGD("custom"," of data length %i", length);
    //ESP_LOGD("custom","data: %s",(char*)pData);
    // Read the value of the characteristic.
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
       ESP_LOGD("custom","onConnect");
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    ESP_LOGD("custom","onDisconnect");
  }
};

bool connectToServer() {
    ESP_LOGD("custom","Forming a connection to %s", myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    ESP_LOGD("custom"," - Created client");

    pClient->setClientCallbacks(new MyClientCallback());
    //myDevice->setAddress(BLEAddress("DA:B9:2C:5A:A9:75"))
    // Connect to the remote BLE Server.
    pClient->connect(myDevice);  // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
    ESP_LOGD("custom"," - Connected to server");
   
    // Obtain a reference to the service we are after in the remote BLE server.
    //BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService == nullptr) {
      ESP_LOGD("custom","Failed to find our service UUID: %s", serviceUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    ESP_LOGD("custom"," - Found our service");

    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      ESP_LOGD("custom","Failed to find our characteristic UUID: %s", charUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    ESP_LOGD("custom"," - Found our 1525 characteristic");
	
    // Obtain a reference to the characteristic to write to in the service of the remote BLE server.
    //dev.writeCharacteristic(11,b'\x50')
    p2RemoteCharacteristic = pRemoteService->getCharacteristic(char24UUID);
    if (p2RemoteCharacteristic == nullptr) {
      ESP_LOGD("custom","Failed to find our characteristic 1524 UUID: %s", charUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    if(p2RemoteCharacteristic->canWrite()) {
      p2RemoteCharacteristic->writeValue(0x50);
      ESP_LOGD("custom","write Value 0x50");
    }

    if(pRemoteCharacteristic->canNotify())
      pRemoteCharacteristic->registerForNotify(notifyCallback);

    connected = true;
	return true;
}
/**
 * Scan for BLE servers and find the first one that advertises the service we are looking for.
 */
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    //ESP_LOGD("custom","BLE Advertised Device found");

      if(foundDevice == false){   // Flag verifying if we found our device
         Server_BLE_Address = new BLEAddress(advertisedDevice.getAddress()); // Update Server_BLE_Address if we didn't
         Scanned_BLE_Address = Server_BLE_Address->toString().c_str();
         if(Scanned_BLE_Address == My_BLE_Address) // Compares the scanned adress to what we are looking for
        {
           foundDevice = true; // Found our device
           ESP_LOGD("custom","Found my MAC ");
         }      
     }
    // We have found a device, let us now see if it contains the service we are looking for.
    //foundDevice == true &&
    if ( advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {

      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
  } // onResult
}; // MyAdvertisedDeviceCallbacks


class MyCustomSensor : public PollingComponent, public Sensor {
 public:
   Sensor *radon_now = new Sensor();
   Sensor *radon_day = new Sensor();
   Sensor *radon_month = new Sensor();
  // constructor
  MyCustomSensor() : PollingComponent(300000) {}

  void setup() override {
    // This will be called by App.setup()
	  Serial.begin(115200);
	  ESP_LOGD("custom","Starting BLE Client for radoneye sensor.");
	  BLEDevice::init("");

	  // Retrieve a Scanner and set the callback we want to use to be informed when we
	  // have detected a new device.  Specify that we want active scanning and start the
	  // scan to run for 5 seconds.
	  BLEScan* pBLEScan = BLEDevice::getScan();
	  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
	  pBLEScan->setInterval(1349);
	  pBLEScan->setWindow(449);
	  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
	  pBLEScan->start(5, false);
  }
  
  void update() override {
	  // This will be called every "update_interval" milliseconds.
	  // If the flag "doConnect" is true then we have scanned for and found the desired
	  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
	  // connected we set the connected flag to be true.
	  if (doConnect == true) {
		if (connectToServer()) {
		  ESP_LOGD("custom","We are now connected to the BLE Server.");
		} else {
		  ESP_LOGD("custom","We have failed to connect to the server; there is nothin more we will do.");
		}
		doConnect = false;
	  }

	  // If we are connected to a peer BLE Server, update the characteristic each time we are reached
	  // with the current time since boot.
	  if (connected) {
		ESP_LOGD("custom","time %i", (int)millis()/1000);
        //p2RemoteCharacteristic = pRemoteService->getCharacteristic(char24UUID);
        if(p2RemoteCharacteristic->canWrite()) {
          p2RemoteCharacteristic->writeValue(0x50);
          ESP_LOGD("custom","Requested new values from sensor (write Value 0x50)");
        } else{
            ESP_LOGD("custom","Requested new values from sensor failed");
        }

        // Read the value of the characteristic.
        if(pRemoteCharacteristic->canRead()) {
            std::string value = pRemoteCharacteristic->readValue();
            ESP_LOGD("custom","read results");
            //ESP_LOGD("custom","byte0-7: %02X %02X %02X %02X %02X %02X %02X",value[0],value[1],value[2],value[3],value[4],value[5],value[6]);
            //z.B. 50 10 8F C2 05 40 7B
            radonval.c[0] = value[2];
            radonval.c[1] = value[3];
            radonval.c[2] = value[4];
            radonval.c[3] = value[5];
            radonnow = radonval.f * 37.0;
            radonval.c[0] = value[6];
            radonval.c[1] = value[7];
            radonval.c[2] = value[8];
            radonval.c[3] = value[9];
            radonday = radonval.f * 37.0;
            radonval.c[0] = value[10];
            radonval.c[1] = value[11];
            radonval.c[2] = value[12];
            radonval.c[3] = value[13];
            radonmonth = radonval.f * 37.0;
            pulsval.c[0] = value[14];
            pulsval.c[1] = value[15];
            puls = pulsval.b;
            pulsval.c[0] = value[16];
            pulsval.c[1] = value[17];
            puls10 = pulsval.b;
            //ESP_LOGD("custom","Radon %X", radonval.b);
            ESP_LOGD("custom","Radonnow %.0f Day %.0f Month %.0f Pulse %i Puls10min %i ", radonnow, radonday,radonmonth, puls, puls10);
        }
        //Publish Values to frontend
        radon_now->publish_state(radonnow);
        radon_day->publish_state(radonday);
        radon_month->publish_state(radonmonth);
        ESP_LOGD("custom","Publish new values to frontend");
		
		// Set the characteristic's value to be the array of bytes that is actually a string.
		//pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
	  }else if(doScan){
          ESP_LOGD("custom","Not connected anymore");
		  setup();
          //BLEDevice::getScan()->start(0);  // this is just eample to start scan after disconnect, most likely there is better way to do it in arduino
	  }
  
  }
};

and here the radon1.yaml:

esphome:
  name: radon1
  platform: ESP32
  board: nodemcu-32s
  includes:
    - my_custom_sensor.h

wifi:
  ssid: "yourssid"
  password: "yourpasswd"

api:
    
logger:

ota:

sensor:
  - platform: custom
    lambda: |-
      auto my_radon = new MyCustomSensor();
      App.register_component(my_radon);
      return {my_radon->radon_now, my_radon->radon_day, my_radon->radon_month};
    sensors:
      - name: "Radon now"
        unit_of_measurement: Bq
        accuracy_decimals: 0
      - name: "Radon day"
        unit_of_measurement: Bq
        accuracy_decimals: 0
      - name: "Radon month"
        unit_of_measurement: Bq
        accuracy_decimals: 0
2 Likes

Hi all, find attached the updated and cleaned version. It now connects directly to your BT-Mac address. You need to provide the adress in the h-file.

Best Michi

#include "esphome.h"
#include "BLEDevice.h"

/************************************************************/
//put here your MAC Adress from the radoneye sensor
static String My_BLE_Address = "c1:96:0d:53:e9:a6";
/************************************************************/
//radon1 da:b9:2c:5a:a9:75 lowercase!!!!


// The remote service we wish to connect to.
static BLEUUID serviceUUID("00001523-1212-efde-1523-785feabcd123");
// The characteristic of the remote service we are interested in.
static BLEUUID    charUUID("00001525-1212-efde-1523-785feabcd123");
static BLEUUID    char24UUID("00001524-1212-efde-1523-785feabcd123");
static BLEUUID    char23UUID("00001523-1212-efde-1523-785feabcd123");

static union { char c[4]; uint32_t b; float f; } radonval;
static union { char c[2]; uint16_t b; } pulsval;
static float radonnow; 
static float radonday;
static float radonmonth;
static int puls;
static int puls10; 

static BLERemoteService* pRemoteService;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLERemoteCharacteristic* p2RemoteCharacteristic;
static BLEClient*  pClient;

class MyCustomSensor : public PollingComponent, public Sensor {
 public:
   Sensor *radon_now = new Sensor();
   Sensor *radon_day = new Sensor();
   Sensor *radon_month = new Sensor();
   Sensor *radon_puls = new Sensor();
   Sensor *radon_puls10 = new Sensor();
  // constructor
  MyCustomSensor() : PollingComponent(60000) {}

  void setup() override {
    // This will be called by App.setup()
	ESP_LOGD("custom","setup start");
	Serial.begin(115200);
	BLEDevice::init("");
    //Convert Mac Adress in correct format
    BLEAddress bleadr = BLEAddress(My_BLE_Address.c_str());//"c1:96:0d:53:e9:a6");
    ESP_LOGD("custom"," - setup connect to mac %s", My_BLE_Address.c_str());
    pClient  = BLEDevice::createClient();
    ESP_LOGD("custom"," - setup- Created client");
    // Connect to the Radoneye  BLE Server.
    pClient->connect(bleadr, BLE_ADDR_TYPE_RANDOM);
    if(pClient->isConnected()) ESP_LOGD("custom"," - setup- Connected to Radoneye");
    else  ESP_LOGD("custom"," - setup- Connect Failed!!!");
}
  
  void update() override {
    // This will be called every "update_interval" milliseconds.
    ESP_LOGD("custom","update - time %i", (int)millis()/1000);
    if(!pClient->isConnected()) setup();
    
    if(pClient->isConnected())
    {
        // Obtain a reference to the service we are after in the remote BLE server.
        pRemoteService = pClient->getService(serviceUUID);
        if (pRemoteService == nullptr) {
            ESP_LOGD("custom","Failed to find our service UUID: %s", serviceUUID.toString().c_str());
        }

        // Obtain a reference to the characteristic in the service of the remote BLE server.
        pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
        if (pRemoteCharacteristic == nullptr) {
            ESP_LOGD("custom","Failed to find our characteristic UUID: %s", charUUID.toString().c_str());
        }
        
        // Obtain a reference to the characteristic to write to in the service of the remote BLE server.
        p2RemoteCharacteristic = pRemoteService->getCharacteristic(char24UUID);
        if (p2RemoteCharacteristic == nullptr) {
            ESP_LOGD("custom","Failed to find our characteristic 1524 UUID: %s", charUUID.toString().c_str());
        }
        //write 0x50 to request new data from sensor
        if(p2RemoteCharacteristic->canWrite()) {
            p2RemoteCharacteristic->writeValue(0x50);
            ESP_LOGD("custom","write Value to our characteristic 1524 with 0x50");
        }
        if(pRemoteCharacteristic->canRead()) {
            std::string value = pRemoteCharacteristic->readValue();
            ESP_LOGD("custom","result bytes: %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X %02X%02X %02X%02X", value[0],value[1],value[2],value[3], value[4],value[5],value[6],value[7], value[8],value[9],value[10],value[11], value[12],value[13],value[14],value[15], value[16],value[17],value[18],value[19]);
            //on 0x50: 50100AD7 63406666 46400000 00000100 15000000
            //on 0x51: 510E0200 1D400000 0C4A0800 71595341 15000000 (Peakvalue12-15, Time since start 4-8)?
            //11tage 9h 37min 44s =985064 Peak 488 
            //30s entspricht Byte[4] +1 
            radonval.c[0] = value[2];
            radonval.c[1] = value[3];
            radonval.c[2] = value[4];
            radonval.c[3] = value[5];
            radonnow = radonval.f * 37.0;
            radonval.c[0] = value[6];
            radonval.c[1] = value[7];
            radonval.c[2] = value[8];
            radonval.c[3] = value[9];
            radonday = radonval.f * 37.0;
            radonval.c[0] = value[10];
            radonval.c[1] = value[11];
            radonval.c[2] = value[12];
            radonval.c[3] = value[13];
            radonmonth = radonval.f * 37.0;
            pulsval.c[0] = value[14];
            pulsval.c[1] = value[15];
            puls = pulsval.b;
            pulsval.c[0] = value[16];
            pulsval.c[1] = value[17];
            puls10 = pulsval.b;
            ESP_LOGD("custom","Radonnow %.0f Day %.0f Month %.0f Pulse %i Puls10min %i ", radonnow, radonday, radonmonth, puls, puls10);
        }
        radon_now->publish_state(radonnow);
        radon_day->publish_state(radonday);
        radon_month->publish_state(radonmonth);
        radon_puls->publish_state(puls);
        radon_puls10->publish_state(puls10);
        ESP_LOGD("custom","Published new values to frontend");
    } else {
        ESP_LOGD("custom","Not connected to sensor");
    }
  }
};

4 Likes

Nice bit of code. Do you have a github link to a sample project so we can see all the parts in play?

Also:

  1. What’s a decent update/query frequency?
  2. Do you keep the connection open all the time? If so, what’s the impact on the sensor battery life?

thanks for your amazing esphome custom codes…

I don’t have radonEye, but I’ll buy one for your help.

I’ll attach with my esp32 nodes which already integrated with Xiaomi Sensors.

thx again

Hi all,

thanks for the radoneye component and the background info of the community.

Try to get it work but it seems to be that I am missing some bits.

I am runniung HA on a NUC / docker / hassio environment.

Managed to activate bluetooth on the NUC and got the MAC of RadonEye.

What I have done:

copied radon_reader.py to config/python_scripts in my HA config

chmod -X

tried to run

./config/python_scripts/radon_reader.py -a XX:YY:ZZ:AA:BB:CC -b -v -m -ma -ms 192.168.2.100 -mu my_username -mw mypassword’

in hassio terminal console.

Traceback (most recent call last):
File “./config/python_scripts/radon_reader.py”, line 12, in
import paho.mqtt.client as mqtt
ImportError: No module named paho.mqtt.client

seems to be the environment paho.mqtt.client is not accessible in terminal console within hassio.

tried than within HA as a script which I executed via developer_console / states for testing

script:

radon_readout_script:
alias: ‘radon readout script’
sequence:
- service: shell_command.read_radon_value

in configuration.yaml

sensor:

  • platform: mqtt
    name: ‘Radon Level’
    unit_of_measurement: ‘pCi/L’
    value_template: ‘{{ value_json.radonvalue }}’
    force_update: true
    state_topic: ‘enviroment/radoneye’

python_script:

shell_command:
read_radon_value: ‘python /config/python_scripts/radon_reader.py -a XX:YY:ZZ:AA:BB:CC -b -v -m -ma -ms 192.168.2.100 -mu my_username -mw mypassword’

tried also:
shell_command:
read_radon_value: ‘curl /config/python_scripts/radon_reader.py -a XX:YY:ZZ:AA:BB:CC -b -v -m -ma -ms 192.168.2.100 -mu my_username -mw mypassword’
read_radon_value1: curl /config/python_scripts/radon_reader.py -a XX:YY:ZZ:AA:BB:CC -b -v -m -ma -ms 192.168.2.100 -mu my_username -mw mypassword
read_radon_value2: ‘curl ./config/python_scripts/radon_reader.py -a XX:YY:ZZ:AA:BB:CC -b -v -m -ma -ms 192.168.2.100 -mu my_username -mw mypasswordl’
read_radon_value3: curl ./config/python_scripts/radon_reader.py -a XX:YY:ZZ:AA:BB:CC -b -v -m -ma -ms 192.168.2.100 -mu my_username -mw mypassword

What am I missing?

tnx

fregatte

" No module named paho.mqtt.client"
You need install paho-mqtt

Try:

sudo pip install paho-mqtt

Thanks for coming back that quickly; unfortunately within hassio I can`t install via sudo pip install paho-mqtt; I can do that just on the host but that does not help to get paho-mqtt available on HA hassio.

Is there a way to circumvent this requirement as I have a mosquito broker running as a hassio addon.

Or might it be possible to use your script within AppDaemon
(AppDaemon is a loosely coupled, multithreaded, sandboxed python execution
environment for writing automation apps for Home Assistant home automation
software. It also provides a configurable dashboard (HADashboard) suitable
for wall mounted tablets.)?

Thanks

fregatte

got it installed after reboot, but I think in this environment it is nonvolatile.

Also getting the next error:
File “./config/python_scripts/radon_reader.py”, line 14, in
from bluepy import btle
ImportError: No module named bluepy

tried to install:
sudo pip install bluepy

Installing collected packages: bluepy
Running setup.py install for bluepy … error
Complete output from command /usr/bin/python2 -u -c “import setuptools, tokenize;file=’/tmp/pip-install-KKKIjf/bluepy/setup.py’;f=getatt
r(tokenize, ‘open’, open)(file);code=f.read().replace(’\r\n’, ‘\n’);f.close();exec(compile(code, file, ‘exec’))” install --record /tmp/p
ip-record-K8ar4q/install-record.txt --single-version-externally-managed --compile:
running install
running build
running build_py
Working dir is /tmp/pip-install-KKKIjf/bluepy
execute make -C ./bluepy clean
error: [Errno 2] No such file or directory

So I think in hassio I have to go the appdaemon route. Therefore the script needs additional code but I am lacking knowledge to code this.

Thanks

fregatte