diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 96a65c05b..c776c1e1c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -687,6 +687,10 @@
android:name=".devices.um25.Activity.DataActivity"
android:exported="true" />
+
+
createBLEScanFilters() {
+ return Collections.singletonList(
+ new ScanFilter.Builder()
+ .setServiceUuid(ParcelUuid.fromString(BinarySensorSupport.BINARY_SENSOR_SERVICE_UUID))
+ .build()
+ );
+ }
+
+ @NonNull
+ @Override
+ public DeviceType getSupportedType(GBDeviceCandidate candidate) {
+ Log.d("coordinator", "candidate name: " + candidate.getName());
+ for(ParcelUuid service : candidate.getServiceUuids()){
+ if(service.getUuid().toString().equals(BinarySensorSupport.BINARY_SENSOR_SERVICE_UUID)){
+ return getDeviceType();
+ };
+ }
+ return DeviceType.UNKNOWN;
+ }
+
+ @Override
+ public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
+ return new int[0];
+ }
+
+ @Override
+ public DeviceType getDeviceType() {
+ return DeviceType.BINARY_SENSOR;
+ }
+
+ @Nullable
+ @Override
+ public Class extends Activity> getPairingActivity() {
+ return null;
+ }
+
+ @Override
+ public boolean supportsActivityDataFetching() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsActivityTracking() {
+ return false;
+ }
+
+ @Override
+ public SampleProvider extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
+ return null;
+ }
+
+ @Override
+ public boolean supportsFindDevice() {
+ return false;
+ }
+
+ @Override
+ public InstallHandler findInstallHandler(Uri uri, Context context) {
+ return null;
+ }
+
+ @Override
+ public boolean supportsScreenshots() {
+ return false;
+ }
+
+ @Override
+ public int getAlarmSlotCount() {
+ return 0;
+ }
+
+ @Override
+ public boolean supportsSmartWakeup(GBDevice device) {
+ return false;
+ }
+
+ @Override
+ public boolean supportsHeartRateMeasurement(GBDevice device) {
+ return false;
+ }
+
+ @Override
+ public String getManufacturer() {
+ return "DIY";
+ }
+
+ @Override
+ public boolean supportsAppsManagement() {
+ return true;
+ }
+
+ @Override
+ public Class extends Activity> getAppsManagementActivity() {
+ return DataActivity.class;
+ }
+
+ @Override
+ public boolean supportsCalendarEvents() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsRealtimeData() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsWeather() {
+ return false;
+ }
+
+ @Override
+ public int getBatteryCount() {
+ return 0;
+ }
+
+ @Override
+ public int getBondingStyle() {
+ return BONDING_STYLE_NONE;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
index fed1569e4..e35906031 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceType.java
@@ -113,6 +113,7 @@ public enum DeviceType {
BOSE_QC35(440, R.drawable.ic_device_headphones, R.drawable.ic_device_headphones_disabled, R.string.devicetype_bose_qc35),
VESC_NRF(500, R.drawable.ic_device_vesc, R.drawable.ic_device_vesc_disabled, R.string.devicetype_vesc),
VESC_HM10(501, R.drawable.ic_device_vesc, R.drawable.ic_device_vesc_disabled, R.string.devicetype_vesc),
+ BINARY_SENSOR(510, R.drawable.ic_device_unknown, R.drawable.ic_device_unknown_disabled, R.string.devicetype_binary_sensor),
TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_test);
private final int key;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
index 164669ec3..a9eb794a1 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
@@ -33,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.BinarySensorSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.fitpro.FitProDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.banglejs.BangleJSDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.casio.CasioGB6900DeviceSupport;
@@ -318,6 +319,8 @@ public class DeviceSupportFactory {
return new ServiceDeviceSupport(new VescDeviceSupport(device.getType()));
case BOSE_QC35:
return new ServiceDeviceSupport(new QC35BaseSupport());
+ case BINARY_SENSOR:
+ return new ServiceDeviceSupport(new BinarySensorSupport());
}
return null;
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/BinarySensorBaseSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/BinarySensorBaseSupport.java
new file mode 100644
index 000000000..df2e80405
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/BinarySensorBaseSupport.java
@@ -0,0 +1,179 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor;
+
+import android.net.Uri;
+
+import org.slf4j.Logger;
+
+import java.util.ArrayList;
+import java.util.UUID;
+
+import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
+import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
+import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
+
+public class BinarySensorBaseSupport extends AbstractBTLEDeviceSupport {
+ public BinarySensorBaseSupport(Logger logger) {
+ super(logger);
+ }
+
+ @Override
+ public void onNotification(NotificationSpec notificationSpec) {
+
+ }
+
+ @Override
+ public void onDeleteNotification(int id) {
+
+ }
+
+ @Override
+ public void onSetTime() {
+
+ }
+
+ @Override
+ public void onSetAlarms(ArrayList extends Alarm> alarms) {
+
+ }
+
+ @Override
+ public void onSetCallState(CallSpec callSpec) {
+
+ }
+
+ @Override
+ public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) {
+
+ }
+
+ @Override
+ public void onSetMusicState(MusicStateSpec stateSpec) {
+
+ }
+
+ @Override
+ public void onSetMusicInfo(MusicSpec musicSpec) {
+
+ }
+
+ @Override
+ public void onEnableRealtimeSteps(boolean enable) {
+
+ }
+
+ @Override
+ public void onInstallApp(Uri uri) {
+
+ }
+
+ @Override
+ public void onAppInfoReq() {
+
+ }
+
+ @Override
+ public void onAppStart(UUID uuid, boolean start) {
+
+ }
+
+ @Override
+ public void onAppDelete(UUID uuid) {
+
+ }
+
+ @Override
+ public void onAppConfiguration(UUID appUuid, String config, Integer id) {
+
+ }
+
+ @Override
+ public void onAppReorder(UUID[] uuids) {
+
+ }
+
+ @Override
+ public void onFetchRecordedData(int dataTypes) {
+
+ }
+
+ @Override
+ public void onReset(int flags) {
+
+ }
+
+ @Override
+ public void onHeartRateTest() {
+
+ }
+
+ @Override
+ public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
+
+ }
+
+ @Override
+ public void onFindDevice(boolean start) {
+
+ }
+
+ @Override
+ public void onSetConstantVibration(int integer) {
+
+ }
+
+ @Override
+ public void onScreenshotReq() {
+
+ }
+
+ @Override
+ public void onEnableHeartRateSleepSupport(boolean enable) {
+
+ }
+
+ @Override
+ public void onSetHeartRateMeasurementInterval(int seconds) {
+
+ }
+
+ @Override
+ public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) {
+
+ }
+
+ @Override
+ public void onDeleteCalendarEvent(byte type, long id) {
+
+ }
+
+ @Override
+ public void onSendConfiguration(String config) {
+
+ }
+
+ @Override
+ public void onReadConfiguration(String config) {
+
+ }
+
+ @Override
+ public void onTestNewFunction() {
+
+ }
+
+ @Override
+ public void onSendWeather(WeatherSpec weatherSpec) {
+
+ }
+
+ @Override
+ public boolean useAutoConnect() {
+ return false;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/BinarySensorSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/BinarySensorSupport.java
new file mode 100644
index 000000000..bd176451a
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/BinarySensorSupport.java
@@ -0,0 +1,187 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor;
+
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.widget.Toast;
+
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.MessageId;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ParameterId;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ReportState;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorType;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.message.GetSensorRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.message.Response;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.message.SetSensorRequest;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.Parameter;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.SensorState;
+import nodomain.freeyourgadget.gadgetbridge.util.GB;
+
+public class BinarySensorSupport extends BinarySensorBaseSupport {
+ final public static String BINARY_SENSOR_SERVICE_UUID = "0000183b-0000-1000-8000-00805f9b34fb";
+ final public static String BINARY_SENSOR_CONTROL_CHARACTERISTIC_UUID = "00002b2b-0000-1000-8000-00805f9b34fb";
+ final public static String BINARY_SENSOR_RESPONSE_CHARACTERISTIC_UUID = "00002b2c-0000-1000-8000-00805f9b34fb";
+
+ final public static String ACTION_SENSOR_STATE_CHANGED = "nodomain.freeyourgadget.gadgetbridge.binary_sensor.STATE_CHANGED";
+ final public static String ACTION_SENSOR_STATE_REQUEST = "nodomain.freeyourgadget.gadgetbridge.binary_sensor.STATE_REQUEST";
+
+ private static final Logger logger = LoggerFactory.getLogger(BinarySensorSupport.class);
+
+ private nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorState sensorState = null;
+ private int sensorCount = -1;
+
+ public BinarySensorSupport() {
+ super(logger);
+ addSupportedService(UUID.fromString(BINARY_SENSOR_SERVICE_UUID));
+
+ LocalBroadcastManager.getInstance(getContext())
+ .registerReceiver(
+ stateRequestReceiver,
+ new IntentFilter(ACTION_SENSOR_STATE_REQUEST)
+ );
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ LocalBroadcastManager.getInstance(getContext())
+ .unregisterReceiver(stateRequestReceiver);
+ }
+
+ BroadcastReceiver stateRequestReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ sendStateChangeIntent(false);
+ }
+ };
+
+ @Override
+ public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ if (characteristic.getUuid().toString().equals(BINARY_SENSOR_RESPONSE_CHARACTERISTIC_UUID)) {
+ handleResponseValue(characteristic.getValue());
+ return true;
+ }
+
+ return false;
+ }
+
+ Response decodeResponse(byte[] value) {
+ ByteBuffer buffer = ByteBuffer.wrap(value);
+ buffer.get(); // split packet header
+ buffer.get(); // RFU
+ byte messageIdByte = buffer.get();
+ buffer.get(); // RFU
+ int parameterCount = buffer.get();
+
+ Parameter[] parameters = new Parameter[parameterCount];
+
+ MessageId messageId = MessageId.fromMessageIdByte(messageIdByte);
+ for (int i = 0; i < parameterCount; i++) {
+ byte parameterIdByte = buffer.get();
+ byte payloadLength = buffer.get();
+ buffer.get(); // RFU
+ buffer.get(); // RFU
+
+ ParameterId parameterId = ParameterId.fromParameterIdByte(parameterIdByte);
+
+ byte[] payload = new byte[payloadLength];
+ buffer.get(payload);
+
+ parameters[i] = Parameter.decode(parameterId, payload);
+ }
+
+ return new Response(
+ messageId,
+ parameters
+ );
+ }
+
+ void sendStateChangeIntent(boolean sendGlobally){
+ Intent intent = new Intent(ACTION_SENSOR_STATE_CHANGED);
+
+ intent.putExtra("EXTRA_SENSOR_CLOSED", sensorState == nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorState.SENSOR_STATE_CLOSED);
+ intent.putExtra("EXTRA_SENSOR_COUNT", sensorCount);
+
+ LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
+ if(sendGlobally) {
+ getContext().sendBroadcast(intent);
+ }
+ }
+
+ void handleResponseValue(byte[] value) {
+ Response response = decodeResponse(value);
+
+ for (Parameter parameter : response.getParameters()) {
+ if (parameter instanceof SensorState) {
+ if(getDevice().getState() != GBDevice.State.INITIALIZED){
+ new TransactionBuilder("set device state")
+ .add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()))
+ .queue(getQueue());
+ }
+
+ SensorState stateParameter = (SensorState) parameter;
+ logger.debug("sensor state: " + stateParameter.getSensorState() + " count: " + stateParameter.getCount());
+
+ this.sensorState = stateParameter.getSensorState();
+ this.sensorCount = stateParameter.getCount();
+
+ sendStateChangeIntent(true);
+ }
+ }
+ }
+
+ private void sendPacketToDevice(byte[] data, TransactionBuilder builder) {
+ byte[] fullData = new byte[data.length + 1];
+ fullData[0] = 0x00;
+ System.arraycopy(data, 0, fullData, 1, data.length);
+
+ builder.write(getCharacteristic(UUID.fromString(BINARY_SENSOR_CONTROL_CHARACTERISTIC_UUID)), fullData);
+ }
+
+ private void sendPacketToDevice(byte[] data) {
+ TransactionBuilder builder = new TransactionBuilder("BSS control");
+ sendPacketToDevice(data, builder);
+ builder.queue(getQueue());
+ }
+
+ @Override
+ public boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ if (status != BluetoothGatt.GATT_SUCCESS) {
+ GB.toast("error setting indication", Toast.LENGTH_LONG, GB.ERROR);
+ }
+ return true;
+ }
+
+ @Override
+ protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
+ logger.debug("initializing device");
+
+ builder
+ .add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()))
+ .notify(getCharacteristic(UUID.fromString(BINARY_SENSOR_RESPONSE_CHARACTERISTIC_UUID)), true)
+ ;
+
+ SetSensorRequest setSensorRequest = new SetSensorRequest(SensorType.SENSOR_TYPE_OPENING_CLOSING, ReportState.REPORT_STATUS_ENABLED);
+ GetSensorRequest getSensorRequest = new GetSensorRequest(SensorType.SENSOR_TYPE_OPENING_CLOSING);
+
+ sendPacketToDevice(getSensorRequest.encode(), builder);
+ sendPacketToDevice(setSensorRequest.encode(), builder);
+
+ return builder;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/MessageId.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/MessageId.java
new file mode 100644
index 000000000..f3e1ef104
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/MessageId.java
@@ -0,0 +1,22 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants;
+
+public enum MessageId {
+ MESSAGE_ID_GET_SENSOR_REQUEST,
+ MESSAGE_ID_GET_SENSOR_RESPONSE,
+ MESSAGE_ID_SET_SENSOR_REQUEST,
+ MESSAGE_ID_SET_SENSOR_RESPONSE,
+ MESSAGE_ID_SENSOR_STATUS_EVENT;
+
+ public byte getMessageIdByte(){
+ return (byte) ordinal();
+ }
+
+ public static MessageId fromMessageIdByte(byte messageIdByte){
+ for(MessageId value:MessageId.values()){
+ if(value.getMessageIdByte() == messageIdByte){
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ParameterId.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ParameterId.java
new file mode 100644
index 000000000..7559b2b9e
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ParameterId.java
@@ -0,0 +1,30 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants;
+
+public enum ParameterId {
+ PARAMETER_ID_RESULT_CODE((byte) 0x00),
+ PARAMETER_ID_CANCEL((byte) 0x01),
+ PARAMETER_ID_SENSOR_TYPE((byte) 0x02),
+ PARAMETER_ID_REPORT_STATUS((byte) 0x03),
+ PARAMETER_ID_SENSOR_STATUS((byte) 0x0A),
+ PARAMETER_ID_MULTIPLE_SENSOR_STATUS((byte) 0x0B),
+ PARAMETER_ID_NAME((byte) 0x0C);
+
+ private byte id;
+
+ ParameterId(byte id){
+ this.id = id;
+ }
+
+ public byte getParameterIdByte(){
+ return this.id;
+ }
+
+ public static ParameterId fromParameterIdByte(byte parameterId){
+ for(ParameterId id:ParameterId.values()){
+ if(id.getParameterIdByte() == parameterId){
+ return id;
+ }
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ReportState.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ReportState.java
new file mode 100644
index 000000000..cb3af1a5b
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ReportState.java
@@ -0,0 +1,19 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants;
+
+public enum ReportState {
+ REPORT_STATUS_DISABLED,
+ REPORT_STATUS_ENABLED;
+
+ public byte getReportStateByte(){
+ return (byte) ordinal();
+ }
+
+ public static ReportState fromReportStateByte(byte reportState){
+ for(ReportState value:ReportState.values()){
+ if(value.getReportStateByte() == reportState){
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ResultCode.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ResultCode.java
new file mode 100644
index 000000000..f59d4525a
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/ResultCode.java
@@ -0,0 +1,19 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants;
+
+public enum ResultCode {
+ RESULT_CODE_SUCCESS,
+ RESULT_CODE_FAILURE;
+
+ public byte getResultCodeByte(){
+ return (byte) ordinal();
+ }
+
+ public static ResultCode fromResultCodeByte(byte resultCode){
+ for(ResultCode value:ResultCode.values()){
+ if(value.getResultCodeByte() == resultCode){
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/SensorState.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/SensorState.java
new file mode 100644
index 000000000..5bf67c1a3
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/SensorState.java
@@ -0,0 +1,19 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants;
+
+public enum SensorState {
+ SENSOR_STATE_CLOSED,
+ SENSOR_STATE_OPEN;
+
+ public byte getSensorStateByte(){
+ return (byte) ordinal();
+ }
+
+ public static SensorState fromSensorStateByte(byte sensorState){
+ for(SensorState value:SensorState.values()){
+ if(value.getSensorStateByte() == sensorState){
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/SensorType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/SensorType.java
new file mode 100644
index 000000000..0e66a545e
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/constants/SensorType.java
@@ -0,0 +1,20 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants;
+
+public enum SensorType {
+ SENSOR_TYPE_OPENING_CLOSING,
+ SENSOR_TYPE_VIBRATION_DETECTION,
+ SENSOR_TYPE_HUMAN_DETECTION;
+
+ public byte getSensorTypeByte(){
+ return (byte) ordinal();
+ }
+
+ public static SensorType fromSensorTypeByte(byte sensorType){
+ for(SensorType value:SensorType.values()){
+ if(value.getSensorTypeByte() == sensorType){
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/GetSensorRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/GetSensorRequest.java
new file mode 100644
index 000000000..6d79c1bd9
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/GetSensorRequest.java
@@ -0,0 +1,16 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.message;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.MessageId;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorType;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.Parameter;
+
+public class GetSensorRequest extends Message{
+ public GetSensorRequest(SensorType sensorType) {
+ super(
+ MessageId.MESSAGE_ID_GET_SENSOR_REQUEST,
+ new Parameter[]{
+ new nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.SensorType(sensorType)
+ }
+ );
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/Message.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/Message.java
new file mode 100644
index 000000000..a75d25ae4
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/Message.java
@@ -0,0 +1,33 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.message;
+
+import java.nio.ByteBuffer;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.MessageId;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.Parameter;
+
+public class Message {
+ MessageId messageId;
+ Parameter[] parameters;
+
+ public Message(MessageId messageId, Parameter[] parameters) {
+ this.messageId = messageId;
+ this.parameters = parameters;
+ }
+
+ public byte[] encode(){
+ int dataLength = 4;
+ for(Parameter parameter : parameters){
+ dataLength += parameter.getPayloadLength() + 4;
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(dataLength);
+ buffer
+ .put((byte) 0x00) // RFU
+ .put(messageId.getMessageIdByte()) // RFU
+ .put((byte) 0x00) // RFU
+ .put((byte) parameters.length);
+ for(Parameter parameter : parameters){
+ buffer.put(parameter.encode());
+ }
+ return buffer.array();
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/Response.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/Response.java
new file mode 100644
index 000000000..074663740
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/Response.java
@@ -0,0 +1,22 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.message;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.MessageId;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.Parameter;
+
+public class Response {
+ MessageId messageId;
+ Parameter[] parameters;
+
+ public MessageId getMessageId() {
+ return messageId;
+ }
+
+ public Parameter[] getParameters() {
+ return parameters;
+ }
+
+ public Response(MessageId messageId, Parameter[] parameters) {
+ this.messageId = messageId;
+ this.parameters = parameters;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/SetSensorRequest.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/SetSensorRequest.java
new file mode 100644
index 000000000..676760a4f
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/message/SetSensorRequest.java
@@ -0,0 +1,18 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.message;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.MessageId;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ReportState;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorType;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.Parameter;
+
+public class SetSensorRequest extends Message{
+ public SetSensorRequest(SensorType sensorType, ReportState reportState) {
+ super(
+ MessageId.MESSAGE_ID_SET_SENSOR_REQUEST,
+ new Parameter[]{
+ new nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.SensorType(sensorType),
+ new nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter.ReportStatus(reportState)
+ }
+ );
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/Parameter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/Parameter.java
new file mode 100644
index 000000000..2cd9fd445
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/Parameter.java
@@ -0,0 +1,49 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter;
+
+import java.nio.ByteBuffer;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ParameterId;
+
+public class Parameter {
+ ParameterId parameterId;
+ byte[] payload;
+
+ public Parameter(ParameterId parameterId, byte... payload) {
+ this.parameterId = parameterId;
+ this.payload = payload;
+ }
+
+ public ParameterId getParameterId() {
+ return parameterId;
+ }
+
+ public int getPayloadLength(){
+ return payload.length;
+ }
+
+ public byte[] encode(){
+ ByteBuffer buffer = ByteBuffer.allocate(payload.length + 4);
+ buffer
+ .put(parameterId.getParameterIdByte())
+ .put((byte) payload.length)
+ .put((byte) 0x00) // RFU
+ .put((byte) 0x00) // RFU
+ .put(payload);
+
+ return buffer.array();
+ }
+
+ public static Parameter decode(ParameterId parameterId, byte[] payload){
+ if(parameterId == ParameterId.PARAMETER_ID_RESULT_CODE){
+ return ResultCode.decode(payload);
+ }else if(parameterId == ParameterId.PARAMETER_ID_REPORT_STATUS){
+ return ReportStatus.decode(payload);
+ }else if(parameterId == ParameterId.PARAMETER_ID_SENSOR_STATUS){
+ return SensorState.decode(payload);
+ }else if(parameterId == ParameterId.PARAMETER_ID_SENSOR_TYPE){
+ return SensorType.decode(payload);
+ }
+
+ return null;
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/ReportStatus.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/ReportStatus.java
new file mode 100644
index 000000000..bcae3994d
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/ReportStatus.java
@@ -0,0 +1,18 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ParameterId;
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ReportState;
+
+public class ReportStatus extends Parameter{
+ ReportState reportState;
+ public ReportStatus(nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ReportState reportState) {
+ super(ParameterId.PARAMETER_ID_REPORT_STATUS, reportState.getReportStateByte());
+ this.reportState = reportState;
+ }
+
+ public static ReportStatus decode(byte[] data){
+ return new ReportStatus(
+ nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ReportState.fromReportStateByte(data[0])
+ );
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/ResultCode.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/ResultCode.java
new file mode 100644
index 000000000..66630249f
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/ResultCode.java
@@ -0,0 +1,17 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ParameterId;
+
+public class ResultCode extends Parameter{
+ nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ResultCode resultCode;
+ public ResultCode(nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ResultCode resultCode) {
+ super(ParameterId.PARAMETER_ID_RESULT_CODE, resultCode.getResultCodeByte());
+ this.resultCode = resultCode;
+ }
+
+ public static ResultCode decode(byte[] data){
+ return new ResultCode(
+ nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ResultCode.fromResultCodeByte(data[0])
+ );
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/SensorState.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/SensorState.java
new file mode 100644
index 000000000..fcf36f9e8
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/SensorState.java
@@ -0,0 +1,32 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ParameterId;
+
+public class SensorState extends Parameter{
+ nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorState sensorState;
+ int count;
+
+ public SensorState(nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorState sensorState, int count) {
+ super(ParameterId.PARAMETER_ID_SENSOR_STATUS, sensorState.getSensorStateByte());
+ this.sensorState = sensorState;
+ this.count = count;
+ }
+
+ public nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorState getSensorState() {
+ return sensorState;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public static SensorState decode(byte[] data){
+ int dataInt = (data[1] << 8) | data[0];
+ byte stateByte = (byte)((dataInt >> 11) & 0x01);
+ int count = dataInt & 0b11111111111;
+ return new SensorState(
+ nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorState.fromSensorStateByte(stateByte),
+ count
+ );
+ }
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/SensorType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/SensorType.java
new file mode 100644
index 000000000..62b1d7ef1
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/binary_sensor/protocol/parameter/SensorType.java
@@ -0,0 +1,18 @@
+package nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.parameter;
+
+import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.ParameterId;
+
+public class SensorType extends Parameter{
+ nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorType sensorType;
+ public SensorType(nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorType sensorType) {
+ super(ParameterId.PARAMETER_ID_SENSOR_TYPE, sensorType.getSensorTypeByte());
+ this.sensorType = sensorType;
+ }
+
+ public static SensorType decode(byte[] data){
+ return new SensorType(
+ nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorType.fromSensorTypeByte(data[0])
+ );
+ }
+
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java
index af571ba89..d7d2fe3f5 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java
@@ -114,6 +114,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.smaq2oss.SMAQ2OSSCoordinator
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWH1000XM4Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.sonyswr12.SonySWR12DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.tlw64.TLW64Coordinator;
+import nodomain.freeyourgadget.gadgetbridge.devices.um25.Coordinator.BinarySensorCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.um25.Coordinator.UM25Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.vesc.VescCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.vibratissimo.VibratissimoCoordinator;
@@ -331,6 +332,7 @@ public class DeviceHelper {
result.add(new SonyWFSP800NCoordinator());
result.add(new SonyWF1000XM3Coordinator());
result.add(new QC35Coordinator());
+ result.add(new BinarySensorCoordinator());
return result;
}
diff --git a/app/src/main/res/layout/activity_binary_sensor_data.xml b/app/src/main/res/layout/activity_binary_sensor_data.xml
new file mode 100644
index 000000000..5c690b85e
--- /dev/null
+++ b/app/src/main/res/layout/activity_binary_sensor_data.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b979cd076..9898c2567 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1754,4 +1754,5 @@
Total number of steps in the whole streak
Total average %d steps per day
+ Binary sensor