Following thing types are supported by this extension:
-| Thing Type ID | Description |
-| ------------------- | ------------------------- |
-| airthings_wave_plus | Airthings Wave Plus |
-| airthings_wave_mini | Airthings Wave Mini |
-
+| Thing Type ID | Description |
+| ------------------- | -------------------------------------- |
+| airthings_wave_plus | Airthings Wave Plus |
+| airthings_wave_mini | Airthings Wave Mini |
+| airthings_wave_gen1 | Airthings Wave 1st Gen (SN 2900xxxxxx) |
## Discovery
| radon_st_avg | Number:Density | The measured radon short term average level |
| radon_lt_avg | Number:Density | The measured radon long term average level |
+The `Airthings Wave Gen 1` thing has the following channels:
+
+| Channel ID | Item Type | Description |
+| ------------------ | ------------------------ | ------------------------------------------- |
+| radon_st_avg | Number:Density | The measured radon short term average level |
+| radon_lt_avg | Number:Density | The measured radon long term average level |
+| temperature | Number:Temperature | The measured temperature |
+| humidity | Number:Dimensionless | The measured humidity |
+
+Note: For the `Airthings Wave Gen 1`, only one channel can be updated at each refreshInterval, so it will take refreshInterval x 4 cycles to sequentially update all 4 channels
## Example
*
* @author Pauli Anttila - Initial contribution
* @author Kai Kreuzer - Added Airthings Wave Mini support
+ * @author Davy Wong - Added Airthings Wave Gen 1 support
*
*/
@NonNullByDefault
private static final String WAVE_PLUS_MODEL = "2930";
private static final String WAVE_MINI_MODEL = "2920";
+ private static final String WAVE_GEN1_MODEL = "2900"; // Wave 1st Gen SN 2900xxxxxx
@Override
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
return new ThingUID(AirthingsBindingConstants.THING_TYPE_AIRTHINGS_WAVE_MINI,
device.getAdapter().getUID(), device.getAddress().toString().toLowerCase().replace(":", ""));
}
+ if (WAVE_GEN1_MODEL.equals(device.getModel())) {
+ return new ThingUID(AirthingsBindingConstants.THING_TYPE_AIRTHINGS_WAVE_GEN1,
+ device.getAdapter().getUID(), device.getAddress().toString().toLowerCase().replace(":", ""));
+ }
}
return null;
}
if (WAVE_MINI_MODEL.equals(device.getModel())) {
return createResult(device, thingUID, "Airthings Wave Mini");
}
+ if (WAVE_GEN1_MODEL.equals(device.getModel())) {
+ return createResult(device, thingUID, "Airthings Wave Gen 1");
+ }
return null;
}
--- /dev/null
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.bluetooth.airthings.internal;
+
+import static org.openhab.binding.bluetooth.airthings.internal.AirthingsBindingConstants.*;
+
+import java.util.UUID;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.library.types.QuantityType;
+import org.openhab.core.library.unit.SIUnits;
+import org.openhab.core.library.unit.Units;
+import org.openhab.core.thing.Thing;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link AirthingsWaveGen1Handler} is responsible for handling commands, which are
+ * sent to one of the channels.
+ *
+ * @author Davy Wong - Added Airthings Wave Gen 1 support
+ */
+@NonNullByDefault
+public class AirthingsWaveGen1Handler extends AbstractAirthingsHandler {
+
+ private static final String HUMIDITY_UUID = "00002a6f-0000-1000-8000-00805f9b34fb"; // 0x2A6F
+ private static final String TEMPERATURE_UUID = "00002a6e-0000-1000-8000-00805f9b34fb"; // 0x2A6E
+ private static final String RADON_STA_UUID = "b42e01aa-ade7-11e4-89d3-123b93f75cba";
+ private static final String RADON_LTA_UUID = "b42e0a4c-ade7-11e4-89d3-123b93f75cba";
+
+ private int intResult;
+ private double dblResult;
+ private volatile ReadSensor readSensor = ReadSensor.RADON_STA;
+
+ private enum ReadSensor {
+ TEMPERATURE,
+ HUMIDITY,
+ RADON_STA,
+ RADON_LTA,
+ }
+
+ public AirthingsWaveGen1Handler(Thing thing) {
+ super(thing);
+ }
+
+ private final Logger logger = LoggerFactory.getLogger(AirthingsWaveGen1Handler.class);
+
+ @Override
+ protected void updateChannels(int[] is) {
+ int[] rawdata;
+ rawdata = is;
+ if (rawdata.length == 2) {
+ switch (readSensor) {
+ case TEMPERATURE:
+ dblResult = intFromBytes(rawdata[0], rawdata[1]) / 100D;
+ logger.debug("Parsed data 1: {}", String.format("[temperature=%.1f °C]", dblResult));
+ readSensor = ReadSensor.HUMIDITY;
+ logger.debug("Change next readSensor to: {}", readSensor);
+ logger.debug("Update channel 1");
+ updateState(CHANNEL_ID_TEMPERATURE,
+ QuantityType.valueOf(Double.valueOf(dblResult), SIUnits.CELSIUS));
+ logger.debug("Update channel 1 done");
+ break;
+ case HUMIDITY:
+ dblResult = intFromBytes(rawdata[0], rawdata[1]) / 100D;
+ logger.debug("Parsed data 2: {}", String.format("[humidity=%.1f %%rH]", dblResult));
+ readSensor = ReadSensor.RADON_STA;
+ logger.debug("Change next readSensor to: {}", readSensor);
+ logger.debug("Update channel 2");
+ updateState(CHANNEL_ID_HUMIDITY, QuantityType.valueOf(Double.valueOf(dblResult), Units.PERCENT));
+ logger.debug("Update channel 2 done");
+ break;
+ case RADON_STA:
+ intResult = intFromBytes(rawdata[0], rawdata[1]);
+ logger.debug("Parsed data 3: {}", String.format("[radonShortTermAvg=%d Bq/m3]", intResult));
+ readSensor = ReadSensor.RADON_LTA;
+ logger.debug("Change next readSensor to: {}", readSensor);
+ logger.debug("Update channel 3");
+ updateState(CHANNEL_ID_RADON_ST_AVG,
+ QuantityType.valueOf(Double.valueOf(intResult), BECQUEREL_PER_CUBIC_METRE));
+ logger.debug("Update channel 3 done");
+ break;
+ case RADON_LTA:
+ intResult = intFromBytes(rawdata[0], rawdata[1]);
+ logger.debug("Parsed data 4: {}", String.format("[radonLongTermAvg=%d Bq/m3]", intResult));
+ readSensor = ReadSensor.TEMPERATURE;
+ logger.debug("Change next readSensor to: {}", readSensor);
+ logger.debug("Update channel 4");
+ updateState(CHANNEL_ID_RADON_LT_AVG,
+ QuantityType.valueOf(Double.valueOf(intResult), BECQUEREL_PER_CUBIC_METRE));
+ logger.debug("Update channel 4 done");
+ break;
+ }
+ } else {
+ logger.debug("Illegal data structure length '%d'", String.valueOf(rawdata).length());
+ }
+ }
+
+ @Override
+ protected UUID getDataUUID() {
+ switch (readSensor) {
+ case TEMPERATURE:
+ logger.debug("Return UUID Temperature");
+ return UUID.fromString(TEMPERATURE_UUID);
+ case HUMIDITY:
+ logger.debug("Return UUID Humidity");
+ return UUID.fromString(HUMIDITY_UUID);
+ case RADON_STA:
+ logger.debug("Return UUID Radon STA");
+ return UUID.fromString(RADON_STA_UUID);
+ case RADON_LTA:
+ logger.debug("Return UUID Radon LTA");
+ return UUID.fromString(RADON_LTA_UUID);
+ default:
+ logger.debug("Return UUID Default");
+ return UUID.fromString(RADON_STA_UUID);
+ }
+ }
+
+ private int intFromBytes(int lowByte, int highByte) {
+ return (highByte & 0xFF) << 8 | (lowByte & 0xFF);
+ }
+
+}
</parameter>
</config-description>
</thing-type>
+ <thing-type id="airthings_wave_gen1">
+ <supported-bridge-type-refs>
+ <bridge-type-ref id="roaming" />
+ <bridge-type-ref id="bluegiga" />
+ <bridge-type-ref id="bluez" />
+ </supported-bridge-type-refs>
+
+ <label>Airthings Wave Gen 1</label>
+ <description>Smart Radon Monitor</description>
+
+ <channels>
+ <channel id="rssi" typeId="rssi" />
+
+ <channel id="humidity" typeId="airthings_humidity" />
+ <channel id="temperature" typeId="airthings_temperature" />
+ <channel id="radon_st_avg" typeId="airthings_radon_st_avg" />
+ <channel id="radon_lt_avg" typeId="airthings_radon_lt_avg" />
+ </channels>
+
+ <config-description>
+ <parameter name="address" type="text">
+ <label>Address</label>
+ <description>Bluetooth address in XX:XX:XX:XX:XX:XX format</description>
+ </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>
+ <default>300</default>
+ </parameter>
+ </config-description>
+ </thing-type>
<channel-type id="airthings_humidity">
<item-type>Number:Dimensionless</item-type>