mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-01-13 03:07:32 +01:00
Binary sensor: initial support for devices using Binary Sensor Service
This commit is contained in:
parent
efbafedfd6
commit
b29a8cefd2
@ -687,6 +687,10 @@
|
||||
android:name=".devices.um25.Activity.DataActivity"
|
||||
android:exported="true" />
|
||||
|
||||
<activity
|
||||
android:name=".devices.binary_sensor.activity.DataActivity"
|
||||
android:exported="true" />
|
||||
|
||||
<activity
|
||||
android:name=".activities.GpxReceiverActivity"
|
||||
android:label="@string/gpx_receiver_activity_title"
|
||||
|
@ -0,0 +1,70 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.binary_sensor.activity;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.BinarySensorSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.protocol.constants.SensorState;
|
||||
|
||||
public class DataActivity extends AbstractGBActivity {
|
||||
TextView stateView, countView;
|
||||
|
||||
BroadcastReceiver stateReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (stateView == null) {
|
||||
return;
|
||||
}
|
||||
if (countView == null) {
|
||||
return;
|
||||
}
|
||||
boolean is_closed = intent.getBooleanExtra("EXTRA_SENSOR_CLOSED", false);
|
||||
int count = intent.getIntExtra("EXTRA_SENSOR_COUNT", -1);
|
||||
|
||||
stateView.setText(is_closed ? "CLOSED" : "OPEN");
|
||||
stateView.setBackgroundResource(is_closed ? android.R.color.holo_green_light : android.R.color.holo_red_light);
|
||||
countView.setText("Count: " + count);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_binary_sensor_data);
|
||||
|
||||
stateView = findViewById(R.id.text_sensor_state);
|
||||
countView = findViewById(R.id.text_sensor_count);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(BinarySensorSupport.ACTION_SENSOR_STATE_CHANGED);
|
||||
LocalBroadcastManager.getInstance(getApplicationContext())
|
||||
.registerReceiver(
|
||||
stateReceiver,
|
||||
filter
|
||||
);
|
||||
|
||||
LocalBroadcastManager.getInstance(getApplicationContext())
|
||||
.sendBroadcast(new Intent(BinarySensorSupport.ACTION_SENSOR_STATE_REQUEST));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
LocalBroadcastManager.getInstance(getApplicationContext())
|
||||
.unregisterReceiver(
|
||||
stateReceiver
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.um25.Coordinator;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.le.ScanFilter;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelUuid;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.binary_sensor.activity.DataActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.binary_sensor.BinarySensorSupport;
|
||||
|
||||
public class BinarySensorCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<? extends ScanFilter> 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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])
|
||||
);
|
||||
}
|
||||
}
|
@ -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])
|
||||
);
|
||||
}
|
||||
}
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
@ -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])
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
38
app/src/main/res/layout/activity_binary_sensor_data.xml
Normal file
38
app/src/main/res/layout/activity_binary_sensor_data.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center_horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_sensor_state"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="250dp"
|
||||
android:background="@android:color/holo_red_light"
|
||||
android:text="unknown"
|
||||
android:textSize="50dp"
|
||||
android:gravity="center"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="unknown"
|
||||
android:textSize="50dp"
|
||||
android:id="@+id/text_sensor_count"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1754,4 +1754,5 @@
|
||||
<string name="steps_streaks_total_steps_hint">Total number of steps in the whole streak</string>
|
||||
<string name="steps_streaks_total_steps_average_hint">Total average %d steps per day</string>
|
||||
|
||||
<string name="devicetype_binary_sensor">Binary sensor</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user