mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-01-07 16:35:50 +01:00
0b731611b9
The Redmi Watch 4 reports both an unsupported widget type and layout style: - The firmware supports a screen layout for a single full screens widget, which is defined by layout ID 128; - A full screen widget is a single 2x2 part, which is not supported. This commit adds support for both the new layout and the new widget type. Furthermore, this commit refactors the XiaomiWidgetManager. Previously, the supported layouts were determined by the types of parts supported by the device. However, the supported layouts are reported by the device through a bitfield in the widget capabilities message of which the purpose was unknown, which is now used to determine the supported layouts.
975 lines
23 KiB
Protocol Buffer
975 lines
23 KiB
Protocol Buffer
syntax = "proto2"; // we must use proto2 to serialize default values on the wire
|
|
|
|
package xiaomi;
|
|
|
|
// FIXME: The generated class is very large, so Android Studio stops recognizing it
|
|
// set idea.max.intellisense.filesize=5000 in idea.properties
|
|
// by clicking Help -> Edit Custom Properties
|
|
|
|
option java_package = "nodomain.freeyourgadget.gadgetbridge.proto.xiaomi";
|
|
option java_outer_classname = "XiaomiProto";
|
|
|
|
message Command {
|
|
required uint32 type = 1;
|
|
optional uint32 subtype = 2;
|
|
|
|
optional Auth auth = 3;
|
|
optional System system = 4;
|
|
optional Watchface watchface = 6;
|
|
optional Health health = 10;
|
|
optional Calendar calendar = 14;
|
|
optional Music music = 20;
|
|
optional Notification notification = 9;
|
|
optional Weather weather = 12;
|
|
optional Schedule schedule = 19;
|
|
|
|
// command type 21
|
|
optional Phonebook phonebook = 23;
|
|
|
|
// type 22
|
|
optional DataUpload dataUpload = 24;
|
|
|
|
optional uint32 status = 100; // 0 on success on some
|
|
}
|
|
|
|
//
|
|
// Auth
|
|
//
|
|
|
|
message Auth {
|
|
optional string userId = 7;
|
|
optional uint32 status = 8;
|
|
// 1, 26
|
|
optional PhoneNonce phoneNonce = 30;
|
|
optional WatchNonce watchNonce = 31;
|
|
// 1, 27
|
|
optional AuthStep3 authStep3 = 32;
|
|
optional AuthStep4 authStep4 = 33;
|
|
}
|
|
|
|
message PhoneNonce {
|
|
required bytes nonce = 1;
|
|
}
|
|
|
|
message WatchNonce {
|
|
required bytes nonce = 1;
|
|
required bytes hmac = 2;
|
|
}
|
|
|
|
message AuthStep3 {
|
|
required bytes encryptedNonces = 1;
|
|
required bytes encryptedDeviceInfo = 2; // AuthDeviceInfo
|
|
}
|
|
|
|
message AuthStep4 {
|
|
required uint32 unknown1 = 1;
|
|
optional uint32 unknown2 = 2;
|
|
}
|
|
|
|
message AuthDeviceInfo {
|
|
required uint32 unknown1 = 1; // 0 - needs to be serialized explicitly
|
|
required float phoneApiLevel = 2;
|
|
required string phoneName = 3; // phone model
|
|
required uint32 unknown3 = 4; // 224
|
|
required string region = 5; // 2-letter, upper case
|
|
}
|
|
|
|
//
|
|
// System
|
|
//
|
|
|
|
message System {
|
|
// 2, 1
|
|
optional Power power = 2;
|
|
// 2, 2
|
|
optional DeviceInfo deviceInfo = 3;
|
|
// 2, 3
|
|
optional Clock clock = 4;
|
|
|
|
// 2, 18
|
|
optional uint32 findDevice = 5; // 0
|
|
|
|
// 2, 29 get | 2, 39 set
|
|
optional DisplayItems displayItems = 10;
|
|
|
|
// 2, 34
|
|
optional DoNotDisturb dndStatus = 11;
|
|
|
|
// 2, 39
|
|
optional WorkoutTypes workoutTypes = 14;
|
|
|
|
// 2, 5
|
|
optional FirmwareInstallRequest firmwareInstallRequest = 16;
|
|
optional FirmwareInstallResponse firmwareInstallResponse = 17;
|
|
|
|
// 2, 9 get | 2, 21 set
|
|
optional Password password = 19;
|
|
|
|
// 2, 7 get | 2, 8 set
|
|
optional Camera camera = 15;
|
|
|
|
// 2, 6
|
|
optional Language language = 20;
|
|
|
|
// 2, 51 get | 2, 52 create
|
|
optional WidgetScreens widgetScreens = 28;
|
|
// 2, 53
|
|
optional WidgetParts widgetParts = 29;
|
|
|
|
// 2, 14
|
|
optional MiscSettingGet miscSettingGet = 34;
|
|
// 2, 15
|
|
optional MiscSettingSet miscSettingSet = 35;
|
|
|
|
// 2, 43
|
|
optional PhoneSilentModeGet phoneSilentModeGet = 36;
|
|
|
|
// 2, 44 returning to watch, 2, 45 setting from watch
|
|
optional PhoneSilentModeSet phoneSilentModeSet = 37;
|
|
|
|
// 2, 46
|
|
optional VibrationPatterns vibrationPatterns = 38;
|
|
|
|
// 2, 47
|
|
optional VibrationNotificationType vibrationSetPreset = 39;
|
|
|
|
// 2, 58
|
|
optional CustomVibrationPattern vibrationPatternCreate = 40;
|
|
|
|
// 2, 59
|
|
optional VibrationTest vibrationTestCustom = 41;
|
|
|
|
// 2, 47
|
|
optional VibrationPatternAck vibrationPatternAck = 43;
|
|
|
|
// 2, 78
|
|
optional BasicDeviceState basicDeviceState = 48;
|
|
|
|
// 2, 79
|
|
optional DeviceState deviceState = 49;
|
|
}
|
|
|
|
message Power {
|
|
optional Battery battery = 1;
|
|
}
|
|
|
|
message Battery {
|
|
optional uint32 level = 1;
|
|
optional uint32 state = 2;
|
|
optional LastCharge lastCharge = 3;
|
|
}
|
|
|
|
message LastCharge {
|
|
optional uint32 state = 1; // 2
|
|
optional uint32 timestampSeconds = 2;
|
|
}
|
|
|
|
message DeviceInfo {
|
|
required string serialNumber = 1;
|
|
required string firmware = 2;
|
|
optional string unknown3 = 3; // "" ?
|
|
required string model = 4;
|
|
}
|
|
|
|
message Clock {
|
|
required Date date = 1;
|
|
required Time time = 2;
|
|
required TimeZone timezone = 3;
|
|
optional bool isNot24hour = 4;
|
|
}
|
|
|
|
message Date {
|
|
required uint32 year = 1;
|
|
required uint32 month = 2;
|
|
required uint32 day = 3;
|
|
}
|
|
|
|
message Time {
|
|
required uint32 hour = 1;
|
|
required uint32 minute = 2;
|
|
optional uint32 second = 3;
|
|
optional uint32 millisecond = 4;
|
|
}
|
|
|
|
message TimeZone {
|
|
// offsets are in blocks of 15 min
|
|
optional sint32 zoneOffset = 1;
|
|
optional sint32 dstOffset = 2;
|
|
required string name = 3;
|
|
}
|
|
|
|
message DisplayItems {
|
|
repeated DisplayItem displayItem = 1;
|
|
}
|
|
|
|
message DisplayItem {
|
|
optional string code = 1;
|
|
optional string name = 2;
|
|
optional bool disabled = 3;
|
|
optional uint32 isSettings = 4;
|
|
optional uint32 unknown5 = 5; // 1
|
|
optional bool inMoreSection = 6; // rarely used in official app
|
|
}
|
|
|
|
message Camera {
|
|
required bool enabled = 1;
|
|
}
|
|
|
|
message Language {
|
|
optional string code = 1; // pt_pt, en_us
|
|
}
|
|
|
|
message WorkoutTypes {
|
|
repeated WorkoutType workoutType = 1;
|
|
optional uint32 unknown2 = 2; // 1
|
|
}
|
|
|
|
message WorkoutType {
|
|
optional uint32 type = 1;
|
|
optional uint32 unknown2 = 2; // 1
|
|
}
|
|
|
|
message WidgetScreens {
|
|
repeated WidgetScreen widgetScreen = 1;
|
|
optional uint32 isFullList = 2; // 1 to overwrite the full list
|
|
optional WidgetsCapabilities widgetsCapabilities = 3; // only in response
|
|
}
|
|
|
|
message WidgetsCapabilities {
|
|
optional uint32 minWidgets = 1; // 1
|
|
optional uint32 maxWidgets = 2; // 7
|
|
|
|
// bitmap:
|
|
// - 0b0000_0011_0000_0000 (768) on bands
|
|
// - 0b0000_0000_0000_0111 (7) on some square/round devices (Watch S1 Active)
|
|
// - 0b0000_0000_1000_0111 (135) on some square/round devices (Redmi Watch 4)
|
|
// - 0b0111_1100_0000_0000 (31744) on portrait devices (Band 8 Pro)
|
|
optional uint32 supportedLayoutStyles = 3;
|
|
}
|
|
|
|
message WidgetScreen {
|
|
optional uint32 id = 1; // starts at 1
|
|
optional uint32 layout = 2; // 256 for split, 512 for tall
|
|
repeated WidgetPart widgetPart = 3;
|
|
}
|
|
|
|
message WidgetParts {
|
|
repeated WidgetPart widgetPart = 1;
|
|
}
|
|
|
|
message WidgetPart {
|
|
optional uint32 type = 1; // 1 for small 1x1, 2 for wide 2x1, 3 for tall 1x2
|
|
optional uint32 function = 2; // matches command type
|
|
optional uint32 id = 3; // they all seem unique
|
|
optional string title = 4; // not set on create
|
|
optional uint32 subType = 5; // usually 0 if no subtype
|
|
optional string appId = 6; // "" on get
|
|
optional string unknown7 = 7; // "" on get
|
|
}
|
|
|
|
message DoNotDisturb {
|
|
optional uint32 status = 1; // 0 enabled, 2 disabled
|
|
}
|
|
|
|
message MiscSettingGet {
|
|
optional uint32 setting = 1; // 2 dndSync
|
|
}
|
|
|
|
message MiscSettingSet {
|
|
optional MiscNotificationSettings miscNotificationSettings = 1;
|
|
optional DndSync dndSync = 2;
|
|
optional WearingMode wearingMode = 3;
|
|
}
|
|
|
|
message MiscNotificationSettings {
|
|
optional uint32 wakeScreen = 1; // 0 ignore 1 enable 2 disable
|
|
optional uint32 onlyWhenPhoneLocked = 2; // 0 ignore 1 enable 2 disable
|
|
}
|
|
|
|
message DndSync {
|
|
optional uint32 enabled = 1; // 0/1
|
|
}
|
|
|
|
message WearingMode {
|
|
// 0 Band Mode (wristband)
|
|
// 1 Pebble Mode (show buckle)
|
|
// 2 Necklace mode (neck strap)
|
|
optional uint32 mode = 1;
|
|
}
|
|
|
|
message FirmwareInstallRequest {
|
|
optional uint32 unknown1 = 1; // 0
|
|
optional uint32 unknown2 = 2; // 0
|
|
optional string version = 3;
|
|
optional string md5 = 4;
|
|
}
|
|
|
|
message FirmwareInstallResponse {
|
|
optional uint32 status = 1; // 0
|
|
}
|
|
|
|
message Password {
|
|
optional uint32 state = 1; // 1 disabled, 2 enabled
|
|
optional string password = 2;
|
|
optional uint32 unknown3 = 3; // 0 when set on ret
|
|
}
|
|
|
|
message PhoneSilentModeGet {
|
|
optional uint32 unknown1 = 1; // 1
|
|
}
|
|
|
|
message PhoneSilentModeSet {
|
|
optional PhoneSilentMode phoneSilentMode = 1;
|
|
}
|
|
|
|
message PhoneSilentMode {
|
|
optional bool silent = 1;
|
|
}
|
|
|
|
message VibrationPatterns {
|
|
repeated VibrationNotificationType notificationType = 1;
|
|
optional uint32 unknown2 = 2; // 50, max patterns?
|
|
repeated CustomVibrationPattern customVibrationPattern = 3;
|
|
}
|
|
|
|
message CustomVibrationPattern {
|
|
optional uint32 id = 1;
|
|
optional string name = 2;
|
|
repeated Vibration vibration = 3;
|
|
optional uint32 unknown4 = 4; // 1 on creation
|
|
}
|
|
|
|
message VibrationNotificationType {
|
|
// 1 incoming calls
|
|
// 2 events // TODO confirm which one is events, which one is schedule
|
|
// 3 alarms
|
|
// 4 notifications
|
|
// 5 standing reminder
|
|
// 6 sms
|
|
// 7 goal
|
|
// 8 events // TODO confirm which one is events, which one is schedule
|
|
optional uint32 notificationType = 1;
|
|
optional uint32 preset = 2;
|
|
}
|
|
|
|
message VibrationTest {
|
|
repeated Vibration vibration = 1;
|
|
}
|
|
|
|
message VibrationPatternAck {
|
|
optional uint32 status = 1; // 0
|
|
}
|
|
|
|
message Vibration {
|
|
optional uint32 vibrate = 1; // 0/1
|
|
optional uint32 ms = 2;
|
|
}
|
|
|
|
message DeviceActivityState {
|
|
optional uint32 activityType = 1;
|
|
optional uint32 currentActivityState = 2;
|
|
}
|
|
|
|
message BasicDeviceState {
|
|
required bool isCharging = 1; // true when connected to charger
|
|
optional uint32 batteryLevel = 2;
|
|
required bool isWorn = 3; // true when the device detects it's being worn
|
|
required bool isUserAsleep = 4; // true when the device detected its user is asleep
|
|
optional DeviceActivityState activityState = 5;
|
|
}
|
|
|
|
message DeviceState {
|
|
optional uint32 chargingState = 1; // 1 charging, 2 not charging
|
|
optional uint32 wearingState = 2; // 1 wearing, 2 not wearing
|
|
optional uint32 sleepState = 3; // 1 sleep detected, 2 no sleep detected
|
|
optional uint32 warningState = 4; // ?
|
|
optional DeviceActivityState activityState = 5;
|
|
}
|
|
|
|
//
|
|
// Watchface
|
|
//
|
|
|
|
message Watchface {
|
|
optional WatchfaceList watchfaceList = 1;
|
|
|
|
// 4, 2 delete | 4, 1 set
|
|
optional string watchfaceId = 2;
|
|
optional uint32 ack = 4; // 1
|
|
|
|
// 4, 4
|
|
optional uint32 installStatus = 5; // 0 not installed, 2 already installed
|
|
optional WatchfaceInstallStart watchfaceInstallStart = 6;
|
|
optional WatchfaceInstallFinish watchfaceInstallFinish = 7;
|
|
}
|
|
|
|
message WatchfaceList {
|
|
repeated WatchfaceInfo watchface = 1;
|
|
}
|
|
|
|
message WatchfaceInfo {
|
|
optional string id = 1;
|
|
optional string name = 2;
|
|
optional bool active = 3;
|
|
optional bool canDelete = 4;
|
|
optional uint32 unknown5 = 5; // 0
|
|
optional uint32 unknown6 = 6; // 0
|
|
optional uint32 unknown11 = 11; // 0
|
|
}
|
|
|
|
message WatchfaceInstallStart {
|
|
optional string id = 1;
|
|
optional uint32 size = 2;
|
|
}
|
|
|
|
message WatchfaceInstallFinish {
|
|
optional string id = 1;
|
|
optional uint32 unknown2 = 2; // 2
|
|
optional uint32 unknown3 = 3; // 0
|
|
optional uint32 unknown4 = 4; // 0
|
|
}
|
|
|
|
//
|
|
// Health
|
|
//
|
|
|
|
message Health {
|
|
optional UserInfo userInfo = 1;
|
|
|
|
// 8, 2 get today | 8, 3 get past
|
|
optional bytes activityRequestFileIds = 2;
|
|
//
|
|
optional bytes activitySyncAckFileIds = 3;
|
|
optional ActivitySyncRequestToday activitySyncRequestToday = 5;
|
|
|
|
optional SpO2 spo2 = 7;
|
|
optional HeartRate heartRate = 8;
|
|
// 8, 12 get | 8, 13 set
|
|
optional StandingReminder standingReminder = 9;
|
|
optional Stress stress = 10;
|
|
optional GoalNotification goalNotification = 13;
|
|
|
|
// 8, 35 get | 8, 36 set
|
|
optional VitalityScore vitalityScore = 14;
|
|
|
|
// 8, 26
|
|
optional WorkoutStatusWatch workoutStatusWatch = 20;
|
|
|
|
// 8, 30
|
|
optional WorkoutOpenWatch workoutOpenWatch = 25;
|
|
optional WorkoutOpenReply workoutOpenReply = 26;
|
|
|
|
// 7, 43
|
|
optional GoalsConfig goalsConfig = 38;
|
|
|
|
// 7, 48
|
|
optional WorkoutLocation workoutLocation = 40;
|
|
|
|
// 8,45 enable | 8, 46 disable | 8, 47 periodic
|
|
optional RealTimeStats realTimeStats = 39;
|
|
}
|
|
|
|
message UserInfo {
|
|
optional uint32 height = 1; // cm
|
|
optional float weight = 2; // kg
|
|
optional uint32 birthday = 3; // YYYYMMDD
|
|
optional uint32 gender = 4; // 1 male, 2 female
|
|
optional uint32 maxHeartRate = 5;
|
|
optional uint32 goalCalories = 6;
|
|
optional uint32 goalSteps = 7;
|
|
optional uint32 goalStanding = 9; // hours
|
|
optional uint32 goalMoving = 11; // minutes
|
|
}
|
|
|
|
message ActivitySyncRequestToday {
|
|
optional uint32 unknown1 = 1; // 0 most of the time, sometimes 1
|
|
}
|
|
|
|
message SpO2 {
|
|
optional uint32 unknown1 = 1; // 1
|
|
optional bool allDayTracking = 2;
|
|
optional Spo2AlarmLow alarmLow = 4;
|
|
}
|
|
|
|
message Spo2AlarmLow {
|
|
optional bool alarmLowEnabled = 1;
|
|
optional uint32 alarmLowThreshold = 2; // 90, 85, 80
|
|
}
|
|
|
|
message HeartRate {
|
|
optional bool disabled = 1; // 0 enabled 1 disabled
|
|
optional uint32 interval = 2; // 0 smart 1 10 30
|
|
optional bool alarmHighEnabled = 3;
|
|
optional uint32 alarmHighThreshold = 4; // 100, 110, ... 150
|
|
optional AdvancedMonitoring advancedMonitoring = 5;
|
|
optional uint32 unknown7 = 7; // 1
|
|
optional HeartRateAlarmLow heartRateAlarmLow = 8;
|
|
optional uint32 breathingScore = 9; // 1 on, 2 off
|
|
}
|
|
|
|
message AdvancedMonitoring {
|
|
required bool enabled = 1;
|
|
}
|
|
|
|
message HeartRateAlarmLow {
|
|
optional bool alarmLowEnabled = 1;
|
|
optional uint32 alarmLowThreshold = 2; // 40, 45, 50
|
|
}
|
|
|
|
message StandingReminder {
|
|
optional bool enabled = 1;
|
|
optional HourMinute start = 2;
|
|
optional HourMinute end = 3;
|
|
optional bool dnd = 4;
|
|
optional HourMinute dndStart = 6;
|
|
optional HourMinute dndEnd = 7;
|
|
}
|
|
|
|
message Stress {
|
|
optional bool allDayTracking = 1;
|
|
optional RelaxReminder relaxReminder = 2;
|
|
}
|
|
|
|
message GoalNotification {
|
|
optional bool enabled = 1;
|
|
optional uint32 unknown2 = 2; // 1
|
|
}
|
|
|
|
message RelaxReminder {
|
|
optional bool enabled = 1;
|
|
optional uint32 unknown2 = 2; // 0
|
|
}
|
|
|
|
message VitalityScore {
|
|
optional bool sevenDay = 1;
|
|
optional bool dailyProgress = 2;
|
|
}
|
|
|
|
message WorkoutStatusWatch {
|
|
optional uint32 timestamp = 1; // seconds
|
|
optional uint32 sport = 3;
|
|
optional uint32 status = 4; // 0 started, 1 resumed, 2 paused, 3 finished
|
|
optional bytes activityFileIds = 5;
|
|
optional uint32 unknown6 = 6; // 2
|
|
optional uint32 unknown10 = 10; // 0
|
|
}
|
|
|
|
message WorkoutOpenWatch {
|
|
// This is only called when gps is needed?
|
|
// 1 outdoor running, 2 walking, 3 hiking, 4 trekking, 5 trail run, 6 outdoor cycling
|
|
optional uint32 sport = 1;
|
|
optional uint32 unknown2 = 2; // 2
|
|
}
|
|
|
|
message WorkoutOpenReply {
|
|
// 3 2 10 when no gps permissions at all
|
|
// 5 2 10 when no all time gps permission
|
|
// ...
|
|
// 0 * * when phone gps is working fine
|
|
// 0 2 10
|
|
// 0 2 2
|
|
optional uint32 unknown1 = 1;
|
|
optional uint32 unknown2 = 2; // always 2?
|
|
optional uint32 unknown3 = 3;
|
|
}
|
|
|
|
message GoalsConfig {
|
|
repeated Goal currentGoals = 1;
|
|
repeated Goal supportedGoals = 2;
|
|
}
|
|
|
|
message Goal {
|
|
// 1 steps?
|
|
// 2 calories?
|
|
// 3 moving time
|
|
// 4 standing time
|
|
optional uint32 id = 1;
|
|
}
|
|
|
|
message WorkoutLocation {
|
|
optional uint32 unknown1 = 1; // 10, sometimes 2?
|
|
optional uint32 timestamp = 2; // seconds
|
|
optional double longitude = 3;
|
|
optional double latitude = 4;
|
|
optional double altitude = 5;
|
|
optional float speed = 6;
|
|
optional float bearing = 7;
|
|
optional float horizontalAccuracy = 8;
|
|
optional float verticalAccuracy = 9;
|
|
}
|
|
|
|
message RealTimeStats {
|
|
optional uint32 steps = 1;
|
|
optional uint32 calories = 2;
|
|
optional uint32 unknown3 = 3; // increases during activity
|
|
optional uint32 heartRate = 4;
|
|
optional uint32 unknown5 = 5; // 0 probably moving time
|
|
optional uint32 standingHours = 6;
|
|
}
|
|
|
|
//
|
|
// Calendar
|
|
//
|
|
|
|
message Calendar {
|
|
optional CalendarSync calendarSync = 2;
|
|
}
|
|
|
|
message CalendarSync {
|
|
repeated CalendarEvent event = 1;
|
|
optional bool disabled = 2;
|
|
}
|
|
|
|
message CalendarEvent {
|
|
optional string title = 1;
|
|
optional string description = 2;
|
|
optional string location = 3;
|
|
optional uint32 start = 4; // unix epoch sec
|
|
optional uint32 end = 5; // unix epoch sec
|
|
optional bool allDay = 6;
|
|
optional uint32 notifyMinutesBefore = 7;
|
|
}
|
|
|
|
//
|
|
// Music
|
|
//
|
|
|
|
message Music {
|
|
// 18, 1
|
|
optional MusicInfo musicInfo = 1;
|
|
// 18, 2
|
|
optional MediaKey mediaKey = 2;
|
|
}
|
|
|
|
message MusicInfo {
|
|
required uint32 state = 1; // 0 not playing, 1 playing, 2 paused
|
|
optional uint32 volume = 2;
|
|
optional string track = 4;
|
|
optional string artist = 5;
|
|
optional uint32 position = 6;
|
|
optional uint32 duration = 7;
|
|
}
|
|
|
|
message MediaKey {
|
|
required uint32 key = 1; // 0 play, 1 pause, 3 prev, 4 next, 5 vol
|
|
optional uint32 volume = 2; // 100 vol+, 0 vol-
|
|
}
|
|
|
|
//
|
|
// Notification
|
|
//
|
|
|
|
message Notification {
|
|
// 7, 8
|
|
optional NotificationId openOnPhone = 2;
|
|
optional Notification2 notification2 = 3;
|
|
optional NotificationDismiss notificationDismiss = 4;
|
|
|
|
optional bool screenOnOnNotifications = 7;
|
|
optional uint32 unknown8 = 8; // 1 on canned replies request?
|
|
// 7, 9 get | 7, 12 set
|
|
optional CannedMessages cannedMessages = 9;
|
|
|
|
// 7, 13
|
|
optional NotificationReply notificationReply = 12;
|
|
// 7, 14
|
|
optional uint32 notificationReplyStatus = 13; // 0 on success, 1 on failure
|
|
|
|
// 7, 15
|
|
optional NotificationIconPackage notificationIconReply = 14;
|
|
// 7, 15
|
|
optional NotificationIconRequest notificationIconRequest = 15;
|
|
// 7, 16
|
|
optional NotificationIconPackage notificationIconQuery = 16;
|
|
}
|
|
|
|
message Notification2 {
|
|
optional Notification3 notification3 = 1;
|
|
}
|
|
|
|
message Notification3 {
|
|
optional string package = 1;
|
|
optional string appName = 2;
|
|
optional string title = 3;
|
|
optional string unknown4 = 4;
|
|
optional string body = 5;
|
|
optional string timestamp = 6;
|
|
optional uint32 id = 7;
|
|
optional bool isCall = 8;
|
|
optional bool repliesAllowed = 11; // only for calls?
|
|
optional string key = 12; // "0|<package>|<id 2 complement>|null|12345"
|
|
optional bool openOnPhone = 13; // 1 to show "Open on phone", needs key
|
|
}
|
|
|
|
message NotificationDismiss {
|
|
repeated NotificationId notificationId = 1;
|
|
}
|
|
|
|
message NotificationId {
|
|
optional uint32 id = 1;
|
|
optional string package = 2; // truncated
|
|
optional string key = 4; // sometimes ""
|
|
}
|
|
|
|
message CannedMessages {
|
|
optional uint32 minReplies = 1;
|
|
repeated string reply = 2;
|
|
optional uint32 maxReplies = 3;
|
|
}
|
|
|
|
message NotificationIconRequest {
|
|
optional uint32 unknown1 = 1; // 0 probably format
|
|
optional uint32 unknown2 = 2; // 3 probably format
|
|
optional uint32 size = 3;
|
|
}
|
|
|
|
message NotificationReply {
|
|
optional uint32 unknown1 = 1; // 1
|
|
optional string message = 2;
|
|
optional uint32 unknown3 = 3; // 1
|
|
optional string number = 4;
|
|
}
|
|
|
|
message NotificationIconPackage {
|
|
optional string package = 1;
|
|
}
|
|
|
|
//
|
|
// Weather
|
|
//
|
|
|
|
message Weather {
|
|
optional WeatherCurrent current = 1;
|
|
optional WeatherForecast forecast = 2;
|
|
|
|
// response to 10, 5 (get location list) | payload of 10, 6 (set, update location list) | payload of 10, 8 (remove)
|
|
optional WeatherLocations locations = 4;
|
|
|
|
// indication payload of 10, 3 (requested update) | payload of 10, 7 (set current, add to list)
|
|
optional WeatherLocation location = 5;
|
|
|
|
// 10, 10
|
|
optional WeatherPrefs prefs = 6;
|
|
}
|
|
|
|
message WeatherCurrent {
|
|
optional WeatherMetadata metadata = 1;
|
|
required uint32 weatherCondition = 2;
|
|
optional WeatherUnitValue temperature = 3;
|
|
optional WeatherUnitValue humidity = 4;
|
|
optional WeatherUnitValue wind = 5;
|
|
optional WeatherUnitValue uv = 6;
|
|
optional WeatherUnitValue aqi = 7;
|
|
optional WeatherWarnings warning = 8; // Seems to be an array?
|
|
optional float pressure = 9;
|
|
}
|
|
|
|
message WeatherMetadata {
|
|
required string publicationTimestamp = 1;
|
|
required string cityName = 2;
|
|
required string locationName = 3;
|
|
optional string locationKey = 4;
|
|
optional bool isCurrentLocation = 5; // default location?
|
|
}
|
|
|
|
message WeatherUnitValue {
|
|
required string unit = 1;
|
|
required sint32 value = 2;
|
|
}
|
|
|
|
message WeatherWarnings {
|
|
repeated WeatherWarning warning = 1;
|
|
}
|
|
|
|
message WeatherWarning {
|
|
required string type = 1;
|
|
required string level = 2;
|
|
optional string title = 3;
|
|
optional string description = 4;
|
|
optional string id = 5;
|
|
}
|
|
|
|
message WeatherLocations {
|
|
repeated WeatherLocation location = 1;
|
|
}
|
|
|
|
message WeatherForecast {
|
|
required WeatherMetadata metadata = 1;
|
|
required ForecastEntries entries = 2;
|
|
}
|
|
|
|
message ForecastEntries {
|
|
repeated ForecastEntry entry = 1;
|
|
}
|
|
|
|
message ForecastEntry {
|
|
optional WeatherUnitValue aqi = 1;
|
|
optional WeatherRange conditionRange = 2;
|
|
optional WeatherRange temperatureRange = 3;
|
|
optional string temperatureSymbol = 4;
|
|
optional WeatherSunriseSunset sunriseSunset = 5;
|
|
optional WeatherUnitValue wind = 6;
|
|
}
|
|
|
|
message WeatherRange {
|
|
required sint32 from = 1;
|
|
required sint32 to = 2;
|
|
}
|
|
|
|
message WeatherSunriseSunset {
|
|
required string sunrise = 1;
|
|
required string sunset = 2;
|
|
}
|
|
|
|
message WeatherLocation {
|
|
required string code = 1;
|
|
optional string name = 2;
|
|
}
|
|
|
|
message WeatherPrefs {
|
|
optional uint32 temperatureScale = 1; // 1 celsius 2 fahrenheit
|
|
optional uint32 weatherWarningsEnabled = 2; // 0 = unsupported, 1 = enabled, 2 = disabled
|
|
}
|
|
|
|
//
|
|
// Schedule
|
|
//
|
|
|
|
message Schedule {
|
|
// 17, 0 get
|
|
optional Alarms alarms = 1;
|
|
// 17, 1
|
|
optional AlarmDetails createAlarm = 2;
|
|
// 17, 3 -> returns 17, 5
|
|
optional Alarm editAlarm = 3;
|
|
|
|
optional uint32 ackId = 4; // id of created or edited alarm and reminder
|
|
|
|
// 17, 4
|
|
optional AlarmDelete deleteAlarm = 5;
|
|
|
|
// 17, 8 get | 17, 9 set
|
|
optional SleepMode sleepMode = 9;
|
|
|
|
// 17, 14 get: 10 -> 2: 50 // max reminders?
|
|
optional Reminders reminders = 10;
|
|
|
|
// 17,10 get/ret | 17,11 create | 17,13 delete
|
|
optional WorldClocks worldClocks = 11;
|
|
|
|
optional uint32 worldClockStatus = 13; // 0 on edit and create
|
|
|
|
// 17, 15
|
|
optional ReminderDetails createReminder = 14;
|
|
|
|
// 17, 17
|
|
optional Reminder editReminder = 15;
|
|
|
|
// 17, 18
|
|
optional ReminderDelete deleteReminder = 17;
|
|
}
|
|
|
|
message Alarms {
|
|
optional uint32 maxAlarms = 2; // 10
|
|
optional uint32 unknown3 = 3; // 0
|
|
optional uint32 unknown4 = 4; // 1
|
|
repeated Alarm alarm = 1;
|
|
}
|
|
|
|
message Alarm {
|
|
optional uint32 id = 1; // starts at 1
|
|
optional AlarmDetails alarmDetails = 2;
|
|
}
|
|
|
|
message AlarmDetails {
|
|
optional HourMinute time = 2;
|
|
optional uint32 repeatMode = 3; // 0 once, 1 daily, 5 weekly
|
|
optional uint32 repeatFlags = 4; // only if weekly: 31 during week, 1 monday, 2 tuesday, 3 mon tue
|
|
optional bool enabled = 5;
|
|
optional uint32 smart = 7; // 1 smart, 2 normal
|
|
}
|
|
|
|
message AlarmDelete {
|
|
repeated uint32 id = 1;
|
|
}
|
|
|
|
message SleepMode {
|
|
required bool enabled = 1;
|
|
optional SleepModeSchedule schedule = 2;
|
|
}
|
|
|
|
message SleepModeSchedule {
|
|
optional HourMinute start = 1;
|
|
optional HourMinute end = 2;
|
|
optional uint32 unknown3 = 3; // 0
|
|
}
|
|
|
|
message Reminders {
|
|
repeated Reminder reminder = 1;
|
|
optional uint32 maxReminders = 2;
|
|
}
|
|
|
|
message Reminder {
|
|
optional uint32 id = 1;
|
|
optional ReminderDetails reminderDetails = 2;
|
|
}
|
|
|
|
message ReminderDetails {
|
|
optional Date date = 1;
|
|
optional Time time = 2;
|
|
optional uint32 repeatMode = 3; // 0 once, 1 daily, weekly (every monday), 7 monthly, 8 yearly
|
|
optional uint32 repeatFlags = 4; // 64 for unset, day flags on weekly
|
|
optional string title = 5;
|
|
}
|
|
|
|
message ReminderDelete {
|
|
repeated uint32 id = 1;
|
|
}
|
|
|
|
message WorldClocks {
|
|
repeated string worldClock = 1;
|
|
}
|
|
|
|
message HourMinute {
|
|
required uint32 hour = 1;
|
|
required uint32 minute = 2;
|
|
}
|
|
|
|
//
|
|
// Data Upload (watchface, notification icons, firmware)
|
|
//
|
|
|
|
message DataUpload {
|
|
// 22, 0
|
|
optional DataUploadRequest dataUploadRequest = 1;
|
|
optional DataUploadAck dataUploadAck = 2;
|
|
}
|
|
|
|
message DataUploadRequest {
|
|
optional uint32 type = 1; // 16 for watchface, 50 for notification icons, 32 for firmware?
|
|
optional bytes md5sum = 2;
|
|
optional uint32 size = 3;
|
|
}
|
|
|
|
message DataUploadAck {
|
|
optional bytes md5sum = 1;
|
|
optional uint32 unknown2 = 2; // 0
|
|
optional uint32 resumePosition = 4;
|
|
optional uint32 chunkSize = 5; // 4096 on Redmi Watch 3 Active, Nonexistent on Mi Band 8
|
|
}
|
|
|
|
message ContactInfo {
|
|
optional string displayName = 1;
|
|
optional string phoneNumber = 2;
|
|
}
|
|
|
|
message ContactList {
|
|
repeated ContactInfo contactInfo = 1;
|
|
}
|
|
|
|
message Phonebook {
|
|
optional string requestedPhoneNumber = 2;
|
|
optional ContactInfo contactInfo = 3;
|
|
optional ContactList contactList = 4;
|
|
}
|