mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-28 11:35:48 +01:00
Add device support for the IKEA desk controller
All the required functionality is included: - Move the desk up and down manually - See the current height and speed - Store three desk positions - Move to any of those desk positions
This commit is contained in:
parent
25dc3f972b
commit
f3b4f0ed26
@ -211,6 +211,10 @@
|
||||
android:name=".devices.vesc.VescControlActivity"
|
||||
android:label="@string/devicetype_vesc"
|
||||
android:parentActivityName=".activities.ControlCenterv2" />
|
||||
<activity
|
||||
android:name=".devices.idasen.IdasenControlActivity"
|
||||
android:label="@string/devicetype_idasen"
|
||||
android:parentActivityName=".activities.ControlCenterv2" />
|
||||
<activity
|
||||
android:name=".activities.FwAppInstallerActivity"
|
||||
android:label="@string/title_activity_fw_app_insaller"
|
||||
@ -908,4 +912,4 @@
|
||||
android:exported="true" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
@ -482,6 +482,10 @@ public class DeviceSettingsPreferenceConst {
|
||||
public static final String PREF_VESC_MINIMUM_VOLTAGE = "vesc_minimum_battery_voltage";
|
||||
public static final String PREF_VESC_MAXIMUM_VOLTAGE = "vesc_maximum_battery_voltage";
|
||||
|
||||
public static final String PREF_IDASEN_SIT_HEIGHT = "idasen_sit_height";
|
||||
public static final String PREF_IDASEN_MID_HEIGHT = "idasen_mid_height";
|
||||
public static final String PREF_IDASEN_STAND_HEIGHT = "idasen_stand_height";
|
||||
|
||||
public static final String PREF_SOUNDS = "sounds";
|
||||
public static final String PREF_AUTH_KEY = "authkey";
|
||||
public static final String PREF_USER_FITNESS_GOAL = "fitness_goal";
|
||||
|
@ -0,0 +1,30 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.idasen;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class IdasenConstants {
|
||||
public static final UUID CHARACTERISTIC_SVC_HEIGHT = UUID.fromString("99fa0020-338a-1024-8a49-009c0215f78a");
|
||||
public static final UUID CHARACTERISTIC_SVC_COMMAND = UUID.fromString("99fa0001-338a-1024-8a49-009c0215f78a");
|
||||
public static final UUID CHARACTERISTIC_COMMAND = UUID.fromString("99fa0002-338a-1024-8a49-009c0215f78a");
|
||||
public static final UUID CHARACTERISTIC_SVC_REF_HEIGHT = UUID.fromString("99fa0030-338a-1024-8a49-009c0215f78a");
|
||||
public static final UUID CHARACTERISTIC_SVC_DPG = UUID.fromString("99fa0010-338a-1024-8a49-009c0215f78a");
|
||||
public static final UUID CHARACTERISTIC_REF_HEIGHT = UUID.fromString("99fa0031-338a-1024-8a49-009c0215f78a");
|
||||
public static final UUID CHARACTERISTIC_HEIGHT = UUID.fromString("99fa0021-338a-1024-8a49-009c0215f78a");
|
||||
public static final UUID CHARACTERISTIC_DPG = UUID.fromString("99fa0011-338a-1024-8a49-009c0215f78a");
|
||||
public static final String ACTION_REALTIME_DESK_VALUES = ".action.realtime_desk_values";
|
||||
public static final String EXTRA_DESK_HEIGHT = "EXTRA_DESK_HEIGHT";
|
||||
public static final String EXTRA_DESK_SPEED = "EXTRA_DESK_SPEED";
|
||||
|
||||
public static final double MIN_HEIGHT = 0.62;
|
||||
public static final double MAX_HEIGHT = 1.27;
|
||||
|
||||
public static final byte[] CMD_UP = new byte[]{0x47, 0x00};
|
||||
public static final byte[] CMD_DOWN = new byte[]{0x46, 0x00};
|
||||
public static final byte[] CMD_STOP = new byte[]{(byte)0xFF, 0x00};
|
||||
public static final byte[] CMD_WAKEUP = new byte[]{(byte)0xFE, 0x00};
|
||||
public static final byte[] CMD_REF_INPUT_STOP = new byte[]{0x01, (byte)0x80};
|
||||
public static final byte[] CMD_DPG_WAKEUP_PREP = new byte[]{0x7F, (byte)0x86, 0x00};
|
||||
public static final byte[] CMD_DPG_WAKEUP = new byte[]{0x7F, (byte)0x86, (byte)0x80, 0x01,
|
||||
0x02, 0x03, 0x04, 0x05, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
|
||||
0x0E, 0x0F, 0x10, 0x11};
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.idasen;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.WorkoutValueFormatter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.idasen.IdasenDeviceSupport;
|
||||
|
||||
public class IdasenControlActivity extends AbstractGBActivity {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
public TextView mDeskHeight, mDeskSpeed;
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (Objects.requireNonNull(action).equals(IdasenConstants.ACTION_REALTIME_DESK_VALUES)){
|
||||
final WorkoutValueFormatter formatter = new WorkoutValueFormatter();
|
||||
float height = (float) intent.getSerializableExtra(IdasenConstants.EXTRA_DESK_HEIGHT);
|
||||
float speed = (float) intent.getSerializableExtra(IdasenConstants.EXTRA_DESK_SPEED);
|
||||
logger.debug("Received desk values: {} {}", speed, height);
|
||||
mDeskHeight.setText(formatter.formatValue(height * 100F, "cm"));
|
||||
mDeskSpeed.setText(formatter.formatValue(speed * 1000F, "mm/s"));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
LocalBroadcastManager localBroadcastManager;
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_idasen_control);
|
||||
|
||||
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
||||
|
||||
mDeskHeight = findViewById(R.id.idasen_desk_height);
|
||||
mDeskSpeed = findViewById(R.id.idasen_desk_speed);
|
||||
|
||||
IntentFilter filterLocal = new IntentFilter();
|
||||
filterLocal.addAction(IdasenConstants.ACTION_REALTIME_DESK_VALUES);
|
||||
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mReceiver, filterLocal);
|
||||
Intent intent = new Intent(IdasenDeviceSupport.COMMAND_GET_DESK_VALUES);
|
||||
sendLocalBroadcast(intent);
|
||||
|
||||
View.OnTouchListener controlTouchListener = new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
Intent intent = null;
|
||||
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
if (v.getId() == R.id.idasen_control_button_up) {
|
||||
intent = new Intent(IdasenDeviceSupport.COMMAND_UP);
|
||||
} else if (v.getId() == R.id.idasen_control_button_down) {
|
||||
intent = new Intent(IdasenDeviceSupport.COMMAND_DOWN);
|
||||
} else if (v.getId() == R.id.idasen_control_button_sit) {
|
||||
intent = new Intent(IdasenDeviceSupport.COMMAND_SET_HEIGHT);
|
||||
intent.putExtra(IdasenDeviceSupport.TARGET_HEIGHT, IdasenDeviceSupport.TARGET_POS_SIT);
|
||||
} else if (v.getId() == R.id.idasen_control_button_stand) {
|
||||
intent = new Intent(IdasenDeviceSupport.COMMAND_SET_HEIGHT);
|
||||
intent.putExtra(IdasenDeviceSupport.TARGET_HEIGHT, IdasenDeviceSupport.TARGET_POS_STAND);
|
||||
} else if (v.getId() == R.id.idasen_control_button_mid) {
|
||||
intent = new Intent(IdasenDeviceSupport.COMMAND_SET_HEIGHT);
|
||||
intent.putExtra(IdasenDeviceSupport.TARGET_HEIGHT, IdasenDeviceSupport.TARGET_POS_MID);
|
||||
}
|
||||
sendLocalBroadcast(intent);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
findViewById(R.id.idasen_control_button_up).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.idasen_control_button_down).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.idasen_control_button_sit).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.idasen_control_button_mid).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.idasen_control_button_stand).setOnTouchListener(controlTouchListener);
|
||||
}
|
||||
|
||||
private void sendLocalBroadcast(Intent intent) {
|
||||
localBroadcastManager.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
localBroadcastManager.unregisterReceiver(mReceiver);
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.idasen;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.idasen.IdasenDeviceSupport;
|
||||
|
||||
public class IdasenCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
|
||||
}
|
||||
@Override
|
||||
public String getManufacturer() {
|
||||
return "IKEA";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pattern getSupportedDeviceName() {
|
||||
return Pattern.compile("Desk 1000", Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
@Override
|
||||
public int getDeviceNameResource() {
|
||||
return R.string.devicetype_idasen;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<? extends DeviceSupport> getDeviceSupportClass() {
|
||||
return IdasenDeviceSupport.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(final GBDevice device) {
|
||||
return new IdasenSettingsCustomizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBondingStyle() {
|
||||
return BONDING_STYLE_BOND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAppsManagement(final GBDevice device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Activity> getAppsManagementActivity() {
|
||||
return IdasenControlActivity.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
|
||||
return new int[]{
|
||||
R.xml.devicesettings_idasen
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.idasen;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.text.InputType;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.util.GB.toast;
|
||||
|
||||
public class IdasenSettingsCustomizer implements DeviceSpecificSettingsCustomizer {
|
||||
public static final Creator<IdasenSettingsCustomizer> CREATOR = new Creator<IdasenSettingsCustomizer>() {
|
||||
@Override
|
||||
public IdasenSettingsCustomizer createFromParcel(final Parcel in) {
|
||||
return new IdasenSettingsCustomizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdasenSettingsCustomizer[] newArray(final int size) {
|
||||
return new IdasenSettingsCustomizer[size];
|
||||
}
|
||||
};
|
||||
private static final Logger LOG = LoggerFactory.getLogger(IdasenSettingsCustomizer.class);
|
||||
|
||||
@Override
|
||||
public void onPreferenceChange(final Preference preference, final DeviceSpecificSettingsHandler handler) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeSettings(final DeviceSpecificSettingsHandler handler, final Prefs prefs, final String rootKey) {
|
||||
final EditTextPreference prefMidHeight = handler.findPreference(DeviceSettingsPreferenceConst.PREF_IDASEN_MID_HEIGHT);
|
||||
final EditTextPreference prefSitHeight = handler.findPreference(DeviceSettingsPreferenceConst.PREF_IDASEN_SIT_HEIGHT);
|
||||
final EditTextPreference prefStandHeight = handler.findPreference(DeviceSettingsPreferenceConst.PREF_IDASEN_STAND_HEIGHT);
|
||||
if (prefSitHeight == null || prefMidHeight == null || prefStandHeight == null) {
|
||||
return;
|
||||
}
|
||||
Preference.OnPreferenceChangeListener prefListener = (preference, newValue) -> {
|
||||
final double val = Double.parseDouble(newValue.toString());
|
||||
if (val > IdasenConstants.MAX_HEIGHT * 100F || val < IdasenConstants.MIN_HEIGHT * 100F) {
|
||||
toast(handler.getContext(), R.string.idasen_pref_value_warning, Toast.LENGTH_SHORT, 0);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
for (EditTextPreference pref: List.of(prefMidHeight, prefSitHeight, prefStandHeight)){
|
||||
pref.setOnBindEditTextListener(p -> {
|
||||
p.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
|
||||
p.setSelection(p.getText().length());
|
||||
});
|
||||
pref.setOnPreferenceChangeListener(prefListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPreferenceKeysWithSummary() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
}
|
||||
}
|
@ -195,6 +195,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchgtrunner.H
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchultimate.HuaweiWatchUltimateCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.id115.ID115Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.itag.ITagCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.idasen.IdasenCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.BFH16DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.TeclastH30.TeclastH30Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.jyou.y5.Y5Coordinator;
|
||||
@ -406,6 +407,7 @@ public enum DeviceType {
|
||||
COLACAO21(ColaCao21Coordinator.class),
|
||||
COLACAO23(ColaCao23Coordinator.class),
|
||||
ITAG(ITagCoordinator.class),
|
||||
IKEA_IDASEN(IdasenCoordinator.class),
|
||||
NUTMINI(NutCoordinator.class),
|
||||
VIVOMOVE_HR(GarminVivomoveHrCoordinator.class),
|
||||
GARMIN_ENDURO_3(GarminEnduro3Coordinator.class),
|
||||
|
@ -0,0 +1,208 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.idasen;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BLETypeConversions;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.idasen.IdasenConstants;
|
||||
|
||||
public class IdasenDeviceSupport extends AbstractBTLEDeviceSupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(IdasenDeviceSupport.class);
|
||||
|
||||
public static final String COMMAND_UP = "nodomain.freeyourgadget.gadgetbridge.idasen.command.UP";
|
||||
public static final String COMMAND_DOWN = "nodomain.freeyourgadget.gadgetbridge.idasen.command.DOWN";
|
||||
public static final String COMMAND_SET_HEIGHT = "nodomain.freeyourgadget.gadgetbridge.idasen.command.SET_HEIGHT";
|
||||
public static final String COMMAND_GET_DESK_VALUES = "nodomain.freeyourgadget.gadgetbridge.idasen.command.GET_DESK_VALUES";
|
||||
public static final String TARGET_HEIGHT = "TARGET_HEIGHT";
|
||||
public static final String TARGET_POS_SIT = "TARGET_POS_SIT";
|
||||
public static final String TARGET_POS_STAND = "TARGET_POS_STAND";
|
||||
public static final String TARGET_POS_MID = "TARGET_POS_MID";
|
||||
public float sit_height, stand_height, mid_height;
|
||||
public float deskSpeed, deskHeight;
|
||||
|
||||
public IdasenDeviceSupport() {
|
||||
super(LOG);
|
||||
addSupportedService(IdasenConstants.CHARACTERISTIC_SVC_HEIGHT);
|
||||
addSupportedService(IdasenConstants.CHARACTERISTIC_SVC_COMMAND);
|
||||
addSupportedService(IdasenConstants.CHARACTERISTIC_SVC_REF_HEIGHT);
|
||||
addSupportedService(IdasenConstants.CHARACTERISTIC_SVC_DPG);
|
||||
}
|
||||
|
||||
BroadcastReceiver commandReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String act = intent.getAction();
|
||||
|
||||
switch(Objects.requireNonNull(act)){
|
||||
case COMMAND_UP:
|
||||
sendCommand("cmd", IdasenConstants.CHARACTERISTIC_COMMAND, IdasenConstants.CMD_UP);
|
||||
break;
|
||||
case COMMAND_DOWN:
|
||||
sendCommand("cmd", IdasenConstants.CHARACTERISTIC_COMMAND, IdasenConstants.CMD_DOWN);
|
||||
break;
|
||||
case COMMAND_GET_DESK_VALUES:
|
||||
readCharacteristic("IdasenGetHeight", IdasenConstants.CHARACTERISTIC_HEIGHT);
|
||||
break;
|
||||
case COMMAND_SET_HEIGHT:
|
||||
HashMap<String, Float> mPositionsMap = new HashMap<>();
|
||||
|
||||
SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
|
||||
stand_height = Float.parseFloat(prefs.getString(DeviceSettingsPreferenceConst.PREF_IDASEN_STAND_HEIGHT, "0.0")) / 100F;
|
||||
mid_height = Float.parseFloat(prefs.getString(DeviceSettingsPreferenceConst.PREF_IDASEN_MID_HEIGHT, "0.0")) / 100F;
|
||||
sit_height = Float.parseFloat(prefs.getString(DeviceSettingsPreferenceConst.PREF_IDASEN_SIT_HEIGHT, "0.0")) / 100F;
|
||||
mPositionsMap.put(TARGET_POS_SIT, sit_height);
|
||||
mPositionsMap.put(TARGET_POS_STAND, stand_height);
|
||||
mPositionsMap.put(TARGET_POS_MID, mid_height);
|
||||
|
||||
sendCommand("cmd", IdasenConstants.CHARACTERISTIC_COMMAND, IdasenConstants.CMD_WAKEUP);
|
||||
sendCommand("cmd", IdasenConstants.CHARACTERISTIC_COMMAND, IdasenConstants.CMD_STOP);
|
||||
|
||||
BluetoothGattCharacteristic characteristic = getCharacteristic(IdasenConstants.CHARACTERISTIC_REF_HEIGHT);
|
||||
String targetHeightKey = intent.getStringExtra(TARGET_HEIGHT);
|
||||
float targetHeight = mPositionsMap.get(targetHeightKey);
|
||||
|
||||
ByteBuffer setHeightBB = ByteBuffer.allocate(2);
|
||||
setHeightBB.order(ByteOrder.LITTLE_ENDIAN);
|
||||
setHeightBB.putShort(0, (short) ((targetHeight - IdasenConstants.MIN_HEIGHT) * 10000F));
|
||||
byte[] setHeightRequest = setHeightBB.array();
|
||||
new Thread(() -> {
|
||||
// This acts as a fail-safe, in case deskSpeed never goes to 0
|
||||
// for whatever reason. It's based on the time the desk controller
|
||||
// needs to get from the lowest to the highest point.
|
||||
int cutOff = 100;
|
||||
do {
|
||||
TransactionBuilder builder = new TransactionBuilder("height");
|
||||
|
||||
builder.write(characteristic, setHeightRequest);
|
||||
builder.queue(getQueue());
|
||||
try {
|
||||
Thread.sleep(300);
|
||||
} catch (InterruptedException e) {
|
||||
GB.log("error", GB.ERROR, e);
|
||||
}
|
||||
cutOff--;
|
||||
} while (deskSpeed != 0F && cutOff != 0);
|
||||
|
||||
if (cutOff == 0) {
|
||||
LOG.warn("desk controller did not reach the desired height in time");
|
||||
}
|
||||
}).start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean useAutoConnect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(commandReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
|
||||
builder.notify(getCharacteristic(IdasenConstants.CHARACTERISTIC_HEIGHT), true);
|
||||
sendCommand("dpg", IdasenConstants.CHARACTERISTIC_DPG, IdasenConstants.CMD_DPG_WAKEUP_PREP);
|
||||
sendCommand("dpg", IdasenConstants.CHARACTERISTIC_DPG, IdasenConstants.CMD_DPG_WAKEUP);
|
||||
sendCommand("dpg", IdasenConstants.CHARACTERISTIC_COMMAND, IdasenConstants.CMD_WAKEUP);
|
||||
initBroadcast();
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicRead(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic,
|
||||
int status) {
|
||||
|
||||
if (characteristic.getUuid().equals(IdasenConstants.CHARACTERISTIC_HEIGHT)) {
|
||||
getDeskValues(characteristic);
|
||||
announceDeskValues();
|
||||
return true;
|
||||
}
|
||||
return super.onCharacteristicRead(gatt, characteristic, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
|
||||
|
||||
if (characteristic.getUuid().equals(IdasenConstants.CHARACTERISTIC_HEIGHT)) {
|
||||
getDeskValues(characteristic);
|
||||
announceDeskValues();
|
||||
return true;
|
||||
}
|
||||
return super.onCharacteristicChanged(gatt, characteristic);
|
||||
}
|
||||
|
||||
private void readCharacteristic(String taskName, UUID charac) {
|
||||
BluetoothGattCharacteristic characteristic = getCharacteristic(charac);
|
||||
|
||||
TransactionBuilder builder = new TransactionBuilder(taskName);
|
||||
builder.read(characteristic);
|
||||
builder.queue(getQueue());
|
||||
}
|
||||
|
||||
private void initBroadcast() {
|
||||
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(COMMAND_UP);
|
||||
filter.addAction(COMMAND_DOWN);
|
||||
filter.addAction(COMMAND_SET_HEIGHT);
|
||||
filter.addAction(COMMAND_GET_DESK_VALUES);
|
||||
|
||||
broadcastManager.registerReceiver(commandReceiver, filter);
|
||||
}
|
||||
|
||||
private void getDeskValues(BluetoothGattCharacteristic characteristic) {
|
||||
byte[] value = characteristic.getValue();
|
||||
final ByteBuffer buf = ByteBuffer.wrap(value).order(ByteOrder.LITTLE_ENDIAN);
|
||||
int hh = BLETypeConversions.toUnsigned(buf.getShort());
|
||||
deskHeight = (float) IdasenConstants.MIN_HEIGHT + hh / 10000F;
|
||||
deskSpeed = buf.getShort() / 10000F;
|
||||
}
|
||||
|
||||
private void announceDeskValues() {
|
||||
final Intent intent = new Intent(IdasenConstants.ACTION_REALTIME_DESK_VALUES)
|
||||
.putExtra(IdasenConstants.EXTRA_DESK_HEIGHT, deskHeight)
|
||||
.putExtra(IdasenConstants.EXTRA_DESK_SPEED, deskSpeed);
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
}
|
||||
|
||||
private void sendCommand(String taskName, UUID charac, byte[] contents) {
|
||||
TransactionBuilder builder = new TransactionBuilder(taskName);
|
||||
BluetoothGattCharacteristic characteristic = getCharacteristic(charac);
|
||||
if (characteristic != null) {
|
||||
builder.write(characteristic, contents);
|
||||
builder.queue(getQueue());
|
||||
}
|
||||
}
|
||||
}
|
41
app/src/main/res/drawable/arrow_autofit_height.xml
Normal file
41
app/src/main/res/drawable/arrow_autofit_height.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,20h-6a2,2 0,0 1,-2 -2v-12a2,2 0,0 1,2 -2h6"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M18,14v7"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M18,3v7"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M15,18l3,3l3,-3"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M15,6l3,-3l3,3"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
20
app/src/main/res/drawable/brand_speedtest.xml
Normal file
20
app/src/main/res/drawable/brand_speedtest.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M5.636,19.364a9,9 0,1 1,12.728 0"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M16,9l-4,4"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
122
app/src/main/res/layout/activity_idasen_control.xml
Normal file
122
app/src/main/res/layout/activity_idasen_control.xml
Normal file
@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/idasen_control_button_sit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/idasen_control_button_sit"
|
||||
app:icon="@drawable/ic_activity_yoga"
|
||||
app:iconPadding="0dp"
|
||||
app:iconSize="35dp"
|
||||
app:iconTint="#FFFFFF" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/idasen_control_button_mid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/idasen_control_button_mid"
|
||||
app:icon="@drawable/ic_activity_bike_trainer"
|
||||
app:iconSize="35dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/idasen_control_button_stand"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/idasen_control_button_stand"
|
||||
app:icon="@drawable/ic_activity_exercise"
|
||||
app:iconSize="35dp"
|
||||
app:iconTint="#FFFFFF" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/idasen_control_button_up"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:background="@drawable/ic_arrow_upward" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/idasen_control_button_down"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:background="@drawable/ic_arrow_upward"
|
||||
android:drawable="@drawable/ic_arrow_upward"
|
||||
android:rotation="180" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/idasen_desk_height_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:background="@drawable/arrow_autofit_height"
|
||||
android:backgroundTint="#FF0000"
|
||||
android:contentDescription="@string/icon_placeholder"
|
||||
android:padding="0dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/idasen_desk_height"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.5"
|
||||
android:textIsSelectable="true"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/idasen_desk_speed_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="start|center_vertical"
|
||||
android:background="@drawable/brand_speedtest"
|
||||
android:backgroundTint="#FF0000"
|
||||
android:contentDescription="@string/icon_placeholder"
|
||||
android:padding="0dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/idasen_desk_speed"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.5"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="24sp"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
@ -1792,6 +1792,7 @@
|
||||
<string name="devicetype_mismartscale">Mi Smart Scale 2</string>
|
||||
<string name="devicetype_micompositionscale">Mi Body Composition Scale 2</string>
|
||||
<string name="devicetype_itag">iTag</string>
|
||||
<string name="devicetype_idasen">IKEA Idasen Desk</string>
|
||||
<string name="devicetype_bfh16">BFH-16</string>
|
||||
<string name="devicetype_mijia_lywsd02">Mijia Smart Clock</string>
|
||||
<string name="devicetype_mijia_lywsd03">Mijia Temperature and Humidity Sensor 2</string>
|
||||
@ -2798,6 +2799,13 @@
|
||||
<!-- Translators: the ### indicate number of digits, keep intact -->
|
||||
<string name="distance_format_feet">###ft</string>
|
||||
|
||||
<string name="idasen_control_button_mid">MID</string>
|
||||
<string name="idasen_control_button_sit">SIT</string>
|
||||
<string name="idasen_control_button_stand">STAND</string>
|
||||
<string name="idasen_pref_mid_height">Middle position height (in centimeters)</string>
|
||||
<string name="idasen_pref_sit_height">Sit position height (in centimeters)</string>
|
||||
<string name="idasen_pref_stand_height">Stand position height (in centimeters)</string>
|
||||
<string name="idasen_pref_value_warning">The value must be between 62 - 126 cm</string>
|
||||
<string name="prefs_workmode">Work Mode</string>
|
||||
<string name="huawei_alarm_smart_description">Do not uncheck smart wakeup checkbox.</string>
|
||||
<string name="huawei_alarm_event_description">Do not check smart wakeup checkbox.</string>
|
||||
|
27
app/src/main/res/xml/devicesettings_idasen.xml
Normal file
27
app/src/main/res/xml/devicesettings_idasen.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<EditTextPreference
|
||||
android:title="@string/idasen_pref_sit_height"
|
||||
android:key="idasen_sit_height"
|
||||
android:inputType="number"
|
||||
android:icon="@drawable/ic_activity_yoga"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<EditTextPreference
|
||||
android:title="@string/idasen_pref_mid_height"
|
||||
android:key="idasen_mid_height"
|
||||
android:inputType="number"
|
||||
android:icon="@drawable/ic_activity_bike_trainer"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<EditTextPreference
|
||||
android:title="@string/idasen_pref_stand_height"
|
||||
android:key="idasen_stand_height"
|
||||
android:inputType="number"
|
||||
android:icon="@drawable/ic_activity_exercise"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
</PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user