1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-27 04:16:49 +01:00

Moyoung: Implement sending calendar items

This commit is contained in:
Arjan Schrijver 2024-09-07 21:39:57 +02:00
parent b5b4727564
commit cb2b216dde
2 changed files with 121 additions and 10 deletions

View File

@ -208,6 +208,19 @@ public class MoyoungConstants {
public static final byte CMD_QUERY_ALARM_CLOCK = 33; // (?) {} -> a list of entries like below public static final byte CMD_QUERY_ALARM_CLOCK = 33; // (?) {} -> a list of entries like below
public static final byte CMD_SET_ALARM_CLOCK = 17; // (?) {id, enable ? 1 : 0, repeat, hour, minute, i >> 8, i, repeatMode}, repeatMode is 0(SINGLE), 127(EVERYDAY), or bitmask of 1,2,4,8,16,32,64(SUNDAY-SATURDAY) is 0,1,2, i is ((year << 12) + (month << 8) + day) where year is 2015-based, month and day start at 1 for repeatMode=SINGLE and 0 otherwise, repeat is 0(SINGLE),1(EVERYDAY),2(OTHER) public static final byte CMD_SET_ALARM_CLOCK = 17; // (?) {id, enable ? 1 : 0, repeat, hour, minute, i >> 8, i, repeatMode}, repeatMode is 0(SINGLE), 127(EVERYDAY), or bitmask of 1,2,4,8,16,32,64(SUNDAY-SATURDAY) is 0,1,2, i is ((year << 12) + (month << 8) + day) where year is 2015-based, month and day start at 1 for repeatMode=SINGLE and 0 otherwise, repeat is 0(SINGLE),1(EVERYDAY),2(OTHER)
public static final byte CMD_ADVANCED_QUERY = (byte) 0xb9;
public static final byte CMD_DAGPT = (byte) 0xbb;
public static final byte ARG_ADVANCED_SET_CALENDAR = 0x08;
public static final byte ARG_ADVANCED_QUERY_STOCKS = 0x0e;
public static final byte ARG_CALENDAR_ADD_ITEM = 0x00;
public static final byte ARG_CALENDAR_DISABLE = 0x04;
public static final byte ARG_CALENDAR_FINISHED = 0x05;
public static final byte ARG_CALENDAR_CLEAR = 0x06;
public static final int MAX_CALENDAR_ITEMS = 12; // Tested only on Colmi i28 Ultra, move to coordinator if different on other devices
// Settings // Settings
public static final byte CMD_SET_USER_INFO = 18; // (?) {height, weight, age, gender}, MALE = 0, FEMALE = 1 public static final byte CMD_SET_USER_INFO = 18; // (?) {height, weight, age, gender}, MALE = 0, FEMALE = 1
@ -280,9 +293,6 @@ public class MoyoungConstants {
public static final byte CMD_QUERY_BREATHING_LIGHT = -120; // {} -> {value} public static final byte CMD_QUERY_BREATHING_LIGHT = -120; // {} -> {value}
public static final byte CMD_SET_BREATHING_LIGHT = 120; // {enabled ? 1 : 0} public static final byte CMD_SET_BREATHING_LIGHT = 120; // {enabled ? 1 : 0}
public static final byte CMD_QUERY_STOCKS = (byte) 0xb9;
public static final byte CMD_DAGPT = (byte) 0xbb;
public static final byte TRAINING_TYPE_WALK = 0; public static final byte TRAINING_TYPE_WALK = 0;
public static final byte TRAINING_TYPE_RUN = 1; public static final byte TRAINING_TYPE_RUN = 1;
public static final byte TRAINING_TYPE_BIKING = 2; public static final byte TRAINING_TYPE_BIKING = 2;

View File

@ -19,9 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.moyoung;
import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler; import android.os.Handler;
import android.util.ArrayMap;
import android.util.Pair; import android.util.Pair;
import android.widget.Toast; import android.widget.Toast;
@ -37,10 +35,11 @@ import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -74,7 +73,6 @@ import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungEnum
import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungEnumTimeSystem; import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungEnumTimeSystem;
import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungSetting; import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungSetting;
import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungSettingEnum; import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungSettingEnum;
import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungSettingLanguage;
import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungSettingRemindersToMove; import nodomain.freeyourgadget.gadgetbridge.devices.moyoung.settings.MoyoungSettingRemindersToMove;
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao; import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao;
@ -116,6 +114,8 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils; import nodomain.freeyourgadget.gadgetbridge.util.NotificationUtils;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs; import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport { public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(MoyoungDeviceSupport.class); private static final Logger LOG = LoggerFactory.getLogger(MoyoungDeviceSupport.class);
@ -143,6 +143,7 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
private boolean realTimeHeartRate; private boolean realTimeHeartRate;
private boolean findMyPhoneActive = false; private boolean findMyPhoneActive = false;
private final Set<CalendarEvent> lastSync = new HashSet<>();
public int getMtu() { public int getMtu() {
return this.mtu; return this.mtu;
@ -451,7 +452,7 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
return true; return true;
} }
if (packetType == MoyoungConstants.CMD_QUERY_STOCKS) if (packetType == MoyoungConstants.CMD_ADVANCED_QUERY && payload[0] == MoyoungConstants.ARG_ADVANCED_QUERY_STOCKS)
{ {
LOG.info("Stocks queried from watch"); LOG.info("Stocks queried from watch");
return true; return true;
@ -744,12 +745,104 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
@Override @Override
public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) { public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) {
// TODO syncCalendar();
} }
@Override @Override
public void onDeleteCalendarEvent(byte type, long id) { public void onDeleteCalendarEvent(byte type, long id) {
// TODO syncCalendar();
}
private void syncCalendar() {
if (!getDevicePrefs().getBoolean("sync_calendar", false)) {
LOG.debug("Ignoring calendar sync request, sync is disabled");
return;
}
final CalendarManager upcomingEvents = new CalendarManager(getContext(), getDevice().getAddress());
final List<CalendarEvent> calendarEvents = upcomingEvents.getCalendarEventList();
final Set<CalendarEvent> thisSync = new HashSet<>();
int nEvents = 0;
for (final CalendarEvent calendarEvent : calendarEvents) {
if (++nEvents > MoyoungConstants.MAX_CALENDAR_ITEMS) {
LOG.warn("Syncing only first {} events of {}", MoyoungConstants.MAX_CALENDAR_ITEMS, calendarEvents.size());
break;
}
thisSync.add(calendarEvent);
}
if (thisSync.equals(lastSync)) {
LOG.debug("Already synced this set of events, won't send to device");
return;
}
lastSync.clear();
lastSync.addAll(thisSync);
List<CalendarEvent> sortedEventList = new ArrayList<>(thisSync);
Collections.sort(sortedEventList, Comparator.comparingLong(CalendarEvent::getBegin));
LOG.debug("Syncing {} calendar events", sortedEventList.size());
try {
TransactionBuilder builder = performInitialized("sendCalendar");
byte[] payload = new byte[]{
MoyoungConstants.ARG_ADVANCED_SET_CALENDAR,
MoyoungConstants.ARG_CALENDAR_CLEAR
};
sendPacket(builder, MoyoungPacketOut.buildPacket(mtu, MoyoungConstants.CMD_ADVANCED_QUERY, payload));
int itemNr = 0;
for(CalendarEvent event : sortedEventList) {
byte[] title = event.getTitle().getBytes();
Calendar start = Calendar.getInstance();
start.setTimeInMillis(event.getBegin());
Calendar end = Calendar.getInstance();
end.setTimeInMillis(event.getEnd());
ByteBuffer packet = ByteBuffer.allocate(title.length + 12);
packet.order(ByteOrder.LITTLE_ENDIAN);
packet.put(MoyoungConstants.ARG_ADVANCED_SET_CALENDAR);
packet.put(MoyoungConstants.ARG_CALENDAR_ADD_ITEM);
packet.put((byte) itemNr);
packet.put((byte) title.length);
packet.put(title);
packet.put((byte) start.get(Calendar.HOUR_OF_DAY));
packet.put((byte) start.get(Calendar.MINUTE));
packet.put((byte) end.get(Calendar.HOUR_OF_DAY));
packet.put((byte) end.get(Calendar.MINUTE));
packet.putInt(MoyoungConstants.LocalTimeToWatchTime(start.getTime()));
sendPacket(builder, MoyoungPacketOut.buildPacket(mtu, MoyoungConstants.CMD_ADVANCED_QUERY, packet.array()));
itemNr++;
}
payload = new byte[]{
MoyoungConstants.ARG_ADVANCED_SET_CALENDAR,
MoyoungConstants.ARG_CALENDAR_FINISHED
};
sendPacket(builder, MoyoungPacketOut.buildPacket(mtu, MoyoungConstants.CMD_ADVANCED_QUERY, payload));
builder.queue(getQueue());
} catch (IOException e) {
LOG.error("Error sending notification: ", e);
}
}
private void disableCalendar() {
try {
TransactionBuilder builder = performInitialized("disableCalendar");
byte[] payload = new byte[]{
MoyoungConstants.ARG_ADVANCED_SET_CALENDAR,
MoyoungConstants.ARG_CALENDAR_CLEAR
};
sendPacket(builder, MoyoungPacketOut.buildPacket(mtu, MoyoungConstants.CMD_ADVANCED_QUERY, payload));
payload = new byte[]{
MoyoungConstants.ARG_ADVANCED_SET_CALENDAR,
MoyoungConstants.ARG_CALENDAR_DISABLE
};
sendPacket(builder, MoyoungPacketOut.buildPacket(mtu, MoyoungConstants.CMD_ADVANCED_QUERY, payload));
builder.queue(getQueue());
} catch (IOException e) {
LOG.error("Error while disabling calendar: ", e);
}
} }
@Override @Override
@ -1478,6 +1571,14 @@ public class MoyoungDeviceSupport extends AbstractBTLEDeviceSupport {
sendSetting(getSetting("REMINDERS_TO_MOVE_PERIOD"), sendSetting(getSetting("REMINDERS_TO_MOVE_PERIOD"),
new MoyoungSettingRemindersToMove.RemindersToMove(sedentaryPeriod, sedentarySteps, sedentaryStart, sedentaryEnd)); new MoyoungSettingRemindersToMove.RemindersToMove(sedentaryPeriod, sedentarySteps, sedentaryStart, sedentaryEnd));
break; break;
case "sync_calendar":
if (prefs.getBoolean("sync_calendar", false)) {
syncCalendar();
} else {
disableCalendar();
}
break;
} }
// Query the setting to make sure the configuration got actually applied // Query the setting to make sure the configuration got actually applied