Support for RadonEye with v2.x.x firmware (#14549)

Signed-off-by: Jörg Sautter <joerg.sautter@gmx.net>
This commit is contained in:
joerg1985
2023-03-12 10:48:45 +01:00
committed by GitHub
parent 59b3ed33df
commit 709dc49fbe
8 changed files with 122 additions and 44 deletions

View File

@@ -12,7 +12,6 @@
*/
package org.openhab.binding.bluetooth.radoneye.internal;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
@@ -45,10 +44,9 @@ abstract public class AbstractRadoneyeHandler extends BeaconBluetoothHandler {
private final Logger logger = LoggerFactory.getLogger(AbstractRadoneyeHandler.class);
private AtomicInteger sinceLastReadSec = new AtomicInteger();
private Optional<RadoneyeConfiguration> configuration = Optional.empty();
private RadoneyeConfiguration configuration = new RadoneyeConfiguration();
private @Nullable ScheduledFuture<?> scheduledTask;
private volatile int refreshInterval;
private volatile int errorConnectCounter;
private volatile int errorReadCounter;
private volatile int errorWriteCounter;
@@ -78,16 +76,14 @@ abstract public class AbstractRadoneyeHandler extends BeaconBluetoothHandler {
public void initialize() {
logger.debug("Initialize");
super.initialize();
configuration = Optional.of(getConfigAs(RadoneyeConfiguration.class));
logger.debug("Using configuration: {}", configuration.get());
configuration = getConfigAs(RadoneyeConfiguration.class);
logger.debug("Using configuration: {}", configuration);
cancelScheduledTask();
configuration.ifPresent(cfg -> {
refreshInterval = cfg.refreshInterval;
logger.debug("Start scheduled task to read device in every {} seconds", refreshInterval);
scheduledTask = scheduler.scheduleWithFixedDelay(this::executePeridioc, CHECK_PERIOD_SEC, CHECK_PERIOD_SEC,
TimeUnit.SECONDS);
});
sinceLastReadSec.set(refreshInterval); // update immediately
logger.debug("Start scheduled task to read device in every {} seconds", configuration.refreshInterval);
scheduledTask = scheduler.scheduleWithFixedDelay(this::executePeridioc, CHECK_PERIOD_SEC, CHECK_PERIOD_SEC,
TimeUnit.SECONDS);
sinceLastReadSec.set(configuration.refreshInterval); // update immediately
}
@Override
@@ -293,7 +289,16 @@ abstract public class AbstractRadoneyeHandler extends BeaconBluetoothHandler {
private boolean isTimeToRead() {
int sinceLastRead = sinceLastReadSec.get();
logger.debug("Time since last update: {} sec", sinceLastRead);
return sinceLastRead >= refreshInterval;
return sinceLastRead >= configuration.refreshInterval;
}
/**
* Provides the configured major firmware version
*
* @return the major firmware version configured
*/
protected int getFwVersion() {
return configuration.fwVersion;
}
/**

View File

@@ -22,10 +22,11 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
@NonNullByDefault
public class RadoneyeConfiguration {
public String address = "";
public int refreshInterval;
public int fwVersion = 1;
public int refreshInterval = 300;
@Override
public String toString() {
return "[address=" + address + ", refreshInterval=" + refreshInterval + "]";
return "[address=" + address + ", fwVersion=" + fwVersion + ", refreshInterval=" + refreshInterval + "]";
}
}

View File

@@ -30,7 +30,8 @@ import org.slf4j.LoggerFactory;
public class RadoneyeDataParser {
public static final String RADON = "radon";
private static final int EXPECTED_DATA_LEN = 20;
private static final int EXPECTED_DATA_LEN_V1 = 20;
private static final int EXPECTED_DATA_LEN_V2 = 12;
private static final int EXPECTED_VER_PLUS = 1;
private static final Logger logger = LoggerFactory.getLogger(RadoneyeDataParser.class);
@@ -38,18 +39,32 @@ public class RadoneyeDataParser {
private RadoneyeDataParser() {
}
public static Map<String, Number> parseRd200Data(int[] data) throws RadoneyeParserException {
public static Map<String, Number> parseRd200Data(int fwVersion, int[] data) throws RadoneyeParserException {
logger.debug("Parsed data length: {}", data.length);
logger.debug("Parsed data: {}", data);
if (data.length == EXPECTED_DATA_LEN) {
final Map<String, Number> result = new HashMap<>();
int[] radonArray = subArray(data, 2, 6);
result.put(RADON, new BigDecimal(readFloat(radonArray) * 37));
return result;
} else {
throw new RadoneyeParserException(String.format("Illegal data structure length '%d'", data.length));
final Map<String, Number> result = new HashMap<>();
switch (fwVersion) {
case 1:
if (data.length != EXPECTED_DATA_LEN_V1) {
throw new RadoneyeParserException(String.format("Illegal data structure length '%d'", data.length));
}
int[] radonArray = subArray(data, 2, 6);
result.put(RADON, new BigDecimal(readFloat(radonArray) * 37));
break;
case 2:
if (data.length != EXPECTED_DATA_LEN_V2) {
throw new RadoneyeParserException(String.format("Illegal data structure length '%d'", data.length));
}
result.put(RADON, intFromBytes(data[2], data[3]));
break;
default:
throw new UnsupportedOperationException("fwVersion: " + fwVersion + " is not implemented");
}
return result;
}
private static int intFromBytes(int lowByte, int highByte) {

View File

@@ -33,9 +33,14 @@ import org.slf4j.LoggerFactory;
@NonNullByDefault
public class RadoneyeHandler extends AbstractRadoneyeHandler {
private static final String SERVICE_UUID = "00001523-1212-efde-1523-785feabcd123";
private static final String TRIGGER_UID = "00001524-1212-efde-1523-785feabcd123";
private static final String DATA_UUID = "00001525-1212-efde-1523-785feabcd123";
private static final UUID SERVICE_UUID_V1 = UUID.fromString("00001523-1212-efde-1523-785feabcd123");
private static final UUID SERVICE_UUID_V2 = UUID.fromString("00001524-0000-1000-8000-00805f9b34fb");
private static final UUID TRIGGER_UID_V1 = UUID.fromString("00001524-1212-efde-1523-785feabcd123");
private static final UUID TRIGGER_UID_V2 = UUID.fromString("00001524-0000-1000-8000-00805f9b34fb");
private static final UUID DATA_UUID_V1 = UUID.fromString("00001525-1212-efde-1523-785feabcd123");
private static final UUID DATA_UUID_V2 = UUID.fromString("00001525-0000-1000-8000-00805f9b34fb");
private static final byte[] DATA_TRIGGER_V1 = new byte[] { 0x50 };
private static final byte[] DATA_TRIGGER_V2 = new byte[] { 0x50 };
public RadoneyeHandler(Thing thing) {
super(thing);
@@ -43,15 +48,11 @@ public class RadoneyeHandler extends AbstractRadoneyeHandler {
private final Logger logger = LoggerFactory.getLogger(RadoneyeHandler.class);
private final UUID dataUuid = UUID.fromString(DATA_UUID);
private final UUID triggerUuid = UUID.fromString(TRIGGER_UID);
private final byte[] triggerData = new byte[] { 0x50 };
@Override
protected void updateChannels(int[] is) {
Map<String, Number> data;
try {
data = RadoneyeDataParser.parseRd200Data(is);
data = RadoneyeDataParser.parseRd200Data(getFwVersion(), is);
logger.debug("Parsed data: {}", data);
Number radon = data.get(RadoneyeDataParser.RADON);
logger.debug("Parsed data radon number: {}", radon);
@@ -65,16 +66,40 @@ public class RadoneyeHandler extends AbstractRadoneyeHandler {
@Override
protected UUID getDataUUID() {
return dataUuid;
int fwVersion = getFwVersion();
switch (fwVersion) {
case 1:
return DATA_UUID_V1;
case 2:
return DATA_UUID_V2;
default:
throw new UnsupportedOperationException("fwVersion: " + fwVersion + " is not implemented");
}
}
@Override
protected UUID getTriggerUUID() {
return triggerUuid;
int fwVersion = getFwVersion();
switch (fwVersion) {
case 1:
return TRIGGER_UID_V1;
case 2:
return TRIGGER_UID_V2;
default:
throw new UnsupportedOperationException("fwVersion: " + fwVersion + " is not implemented");
}
}
@Override
protected byte[] getTriggerData() {
return triggerData;
int fwVersion = getFwVersion();
switch (fwVersion) {
case 1:
return DATA_TRIGGER_V1;
case 2:
return DATA_TRIGGER_V2;
default:
throw new UnsupportedOperationException("fwVersion: " + fwVersion + " is not implemented");
}
}
}

View File

@@ -0,0 +1,18 @@
# thing types
thing-type.bluetooth.radoneye_rd200.label = RadonEye RD200
thing-type.bluetooth.radoneye_rd200.description = Indoor radon monitor
# thing types config
thing-type.config.bluetooth.radoneye_rd200.address.label = Address
thing-type.config.bluetooth.radoneye_rd200.address.description = Bluetooth address in XX:XX:XX:XX:XX:XX format
thing-type.config.bluetooth.radoneye_rd200.fwVersion.label = Firmware Version
thing-type.config.bluetooth.radoneye_rd200.fwVersion.description = The major version of the firmware on the device.
thing-type.config.bluetooth.radoneye_rd200.refreshInterval.label = Refresh Interval
thing-type.config.bluetooth.radoneye_rd200.refreshInterval.description = States how often a refresh shall occur in seconds.
# channel types
channel-type.bluetooth.radoneye_radon.label = Radon Current Level
channel-type.bluetooth.radoneye_radon.description = Radon gas level

View File

@@ -24,9 +24,14 @@
<label>Address</label>
<description>Bluetooth address in XX:XX:XX:XX:XX:XX format</description>
</parameter>
<parameter name="fwVersion" type="integer" min="1" max="2">
<label>Firmware Version</label>
<description>The major version of the firmware on the device.</description>
<default>1</default>
</parameter>
<parameter name="refreshInterval" type="integer" min="10">
<label>Refresh Interval</label>
<description>States how often a refresh shall occur in seconds. This could have impact to battery lifetime</description>
<description>States how often a refresh shall occur in seconds.</description>
<default>300</default>
</parameter>
</config-description>