Skip to content

Instantly share code, notes, and snippets.

@Intyre
Last active August 3, 2023 11:34
Show Gist options
  • Select an option

  • Save Intyre/05957b64b3fb1306361ca9e79ca01ac1 to your computer and use it in GitHub Desktop.

Select an option

Save Intyre/05957b64b3fb1306361ca9e79ca01ac1 to your computer and use it in GitHub Desktop.

Revisions

  1. Intyre revised this gist Aug 2, 2023. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions 1.md
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,8 @@ The .zip contains bolt-65535.cfg, comp.cfg poi.cfg and routes.cfg

    Create a directory with the name `config_backup` on the device, a elemnt_config.zip should appear. If not then reboot the device.

    [How to connect an ELEMNT, BOLT, or ROAM to a desktop or laptop computer](https://support.wahoofitness.com/hc/en-us/articles/115000127910)

    ## Create
    ```sh
    # create special directory
  2. Intyre renamed this gist Jun 25, 2023. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. Intyre revised this gist Jun 25, 2023. 1 changed file with 25 additions and 0 deletions.
    25 changes: 25 additions & 0 deletions 1.
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,25 @@
    # Config backup
    The .zip contains bolt-65535.cfg, comp.cfg poi.cfg and routes.cfg

    Create a directory with the name `config_backup` on the device, a elemnt_config.zip should appear. If not then reboot the device.

    ## Create
    ```sh
    # create special directory
    adb shell mkdir /sdcard/config_backup

    # save to pc
    adb pull /sdcard/config_backup/elemnt_config.zip .
    ```

    ## Restore
    ```sh
    # create special directory
    adb shell mkdir /sdcard/config_restore

    # save to pc
    adb push elemnt_config.zip /sdcard/config_restore/elemnt_config.zip

    # reboot device
    adb shell reboot
    ```
  4. Intyre revised this gist Jun 25, 2023. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions elemnt-config.py
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,7 @@
    "PLAN_SYNC_STATUS", "RACE_RUNNING_CFG", "WORKOUT_PINNED_PAGE_ID", "CUSTOM_ALERTS_ENABLED",
    "CUSTOM_ALERTS_PLANNED_WORKOUT_ENABLED", "LEDS_MASK", "SUPERSAPIENS_ALLOWED", "SUPERSAPIENS_STATE",
    "ROUTE_SYNC_STATUS", "INVALID", "INVALID", "SYNC_REQ_MASK",
    "CLIMB_CFG", "NEXT"
    "CLIMB_CFG", "CONNECTION_INFO", "ACTIVITY_FEEDBACK_ENABLED", "NEXT"
    ]

    compFieldNames = [
    @@ -88,9 +88,9 @@ def main(name):
    config = readfile(name)

    fieldNames = []
    if name.startswith('comp'):
    if 'comp' in name:
    fieldNames = compFieldNames
    elif name.startswith('bolt'):
    elif 'bolt' in name:
    fieldNames = boltFieldNames

    print(f'Version: {config["version"]}')
    @@ -100,7 +100,7 @@ def main(name):


    if __name__ == "__main__":
    if len(sys.argv) != 2 or sys.argv[1][:4] not in ['comp', 'bolt']:
    if len(sys.argv) != 2 or ('comp' not in sys.argv[1] and 'bolt' not in sys.argv[1]):
    print('Usage: python elemnt-config.py comp.cfg or bolt-65535.cfg')
    sys.exit(0)

  5. Intyre created this gist Dec 30, 2022.
    107 changes: 107 additions & 0 deletions elemnt-config.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,107 @@
    #!/usr/bin/python

    import sys

    boltFieldNames = [
    "BACKLIGHT", "AUTO_UPLOAD_ENABLED", "BOLT_BATTERY", "INVALID",
    "LED_MODE", "TOP_LED_WORKOUT", "TOP_LED_NOTIF", "TOP_LED_NAV",
    "BUZZ_WORKOUT", "BUZZ_NOTIF", "BUZZ_NAV", "BUZZ_MARIO",
    "AUTO_PAUSE_SPEED", "ALERT_PHONE", "ALERT_MSG", "ALERT_EMAIL",
    "DND_END_TIME_OLD", "AUTO_SHUTDOWN_DURATION", "MUTE", "BOLTAPP_VERSION",
    "KICKR_MODE_OVERRIDE_ALLOWED", "LED_MODE_OVERRIDE", "ZOOM_MIN_LEVEL",
    "FIRST_RUN_STATE", "AUTO_LAP_MODE", "AUTO_LAP_DISTANCE_M", "AUTO_LAP_DURATION_SEC",
    "BACKLIGHT_DURATION_SEC", "UPGRADE_STATE", "UPGRADE_DOWNLOAD_PERCENT", "DND_END_TIME",
    "DND_INTERVAL", "FOLLOW_WITH_HEADING", "SEGMENTS_ENABLED", "SEGMENTS_AUTO_PAGE_CHANGE",
    "SEGMENTS_NOTIF_ON_OTHER_PAGES", "SEGMENTS_LEDS", "SEGMENTS_MUTED", "WORKOUT_TYPE",
    "USER_OUTDOOR_MODE", "INVALID", "PAGE_DEFN", "WIFI_NW_COUNT",
    "INCLUDE_ZERO_IN_AVG_CADENCE", "PLANS_NOTIF_ON_OTHER_PAGES", "PLANS_BUZZER", "PLANS_LEDS",
    "SEGMENTS_DURING_PLAN", "PLAN_AUTO_LAP_ON_INTERVAL", "INCLUDE_ZERO_IN_AVG_POWER", "CFG_PROFILE_IDS",
    "CURRENT_CFG_PROFILE_ID", "CFG_PROFILE_NAME", "CFG_DISPLAY_CFG", "THEME",
    "INVALID", "AUTO_UPDATE", "WATCHFACE_CFG", "POOL_LENGTH_CM",
    "THEME_TINT_COLOR", "LOCATION_LAT", "LOCATION_LON", "INVALID",
    "CFG_PROFILE_ID_NEXT", "GPS_OVERRIDE", "ENABLE_OPTICAL_HR", "APP_PROFILE",
    "RUNNING_MODE", "RACE_LENGTH", "TRACK_LENGTH", "LAST_INTERACTION_TIME_SEC",
    "POOL_LENGTH_CUSTOM_CM", "AUTO_INT_ENABLED", "POOL_LENGTH_CUSTOM_METRIC", "BOLT_BATTERY_STATUS",
    "BOLT_SERIAL_NUMBER", "AUTO_RE_ROUT", "INVALID", "INVALID",
    "SOUNDS_CFG", "VIBRATIONS_CFG", "DND_SCHEDULE_START_TIME_MIN", "DND_SCHEDULE_END_TIME_MIN",
    "DND_CFG", "RADAR_CFG", "PMS_CFG", "PMS_SESSION_INDEX",
    "BODY_POSITION", "SPECIALIZED_AUTH_KEY", "SPECIALIZED_STAGING_URL", "GPS_POS_ASSIST_VALID",
    "UPGRADE_STATE_ROM", "BOLTAPP_WSM_ENABLED", "LOG_LEVEL", "RELEASE_CHANNEL",
    "247_MASK", "GPS_POS_ASSIST_DATA_REQ", "WORKOUT_PAGE_COLOUR_MODE", "ENABLED_CLM_TYPES",
    "BUTTON_SQUEEZE_CFG", "DISPLAY_CFG_HIDE_TITLES", "WORK_REST_CFG", "WORK_REST_AUTO_LAP_ON_INTERVAL",
    "PLAN_SYNC_STATUS", "RACE_RUNNING_CFG", "WORKOUT_PINNED_PAGE_ID", "CUSTOM_ALERTS_ENABLED",
    "CUSTOM_ALERTS_PLANNED_WORKOUT_ENABLED", "LEDS_MASK", "SUPERSAPIENS_ALLOWED", "SUPERSAPIENS_STATE",
    "ROUTE_SYNC_STATUS", "INVALID", "INVALID", "SYNC_REQ_MASK",
    "CLIMB_CFG", "NEXT"
    ]

    compFieldNames = [
    "INVALID", "HEIGHT_CM", "WEIGHT_HG", "DOB",
    "MALE", "METRIC_SPEED_DISTANCE", "LOCALE", "POWER_FTP",
    "HR_RESTING", "HR_ZONE_1_CEIL", "HR_ZONE_2_CEIL", "HR_ZONE_3_CEIL",
    "HR_ZONE_4_CEIL", "HR_MAX", "INVALID", "LIFESTYLE",
    "INVALID", "TIME_FMT", "INVALID", "HR_BURN_RATE",
    "HR_BURST_RATE", "INVALID", "PHONE_BATTERY", "BOLT_TIME",
    "BOLT_TIME_ZONE", "SPD_ZONE_1_CEIL", "SPD_ZONE_2_CEIL", "SPD_ZONE_3_CEIL",
    "SPD_ZONE_4_CEIL", "PWR_ZONE_1_CEIL", "PWR_ZONE_2_CEIL", "PWR_ZONE_3_CEIL",
    "PWR_ZONE_4_CEIL", "INVALID", "USER_PROFILE", "METRIC_ELEVATION",
    "METRIC_TEMPERATURE", "METRIC_WEIGHT", "PWR_ZONE_5_CEIL", "PWR_ZONE_6_CEIL",
    "PWR_ZONE_7_CEIL", "INVALID", "PWR_ZONE_COUNT", "BOLT_TIME_INFO",
    "LOG_LEVEL", "FIRST_DAY_OF_WEEK", "AUTO_UPLOAD_MASK", "TARGET_DAILY_STEPS",
    "TARGET_WEEKLY_BIKE_DISTANCE", "TARGET_DAILY_CALORIES", "TARGET_WEEKLY_RUN_DISTANCE", "TARGET_WEEKLY_SWIM_DISTANCE",
    "TARGET_WEEKLY_CALORIES", "TARGET_WEEKLY_ACTIVE_TIME","CALIBRATION_RUN", "LOCATION_LAT",
    "LOCATION_LON", "PAIRED_ELEMNT_CFG", "247_WEEK_SUMMARY", "INVALID",
    "GENDER", "AUTO_RIVAL_DATA_BROADCAST", "LOCATION", "INVALID",
    "POWER_RUN_CRITICAL_POWER", "CLOUD_USER_ID", "CLOUD_SERVER_TYPE", "WAHOO_CLOUD_SUBSCRIPTION_STAT", "NEXT"
    ]


    def readfile(name):
    version = 0x00
    profileID = 0xFFFF
    dataFields = {}
    timestampFields = {}

    with open(name, 'rb') as f:
    version = int.from_bytes(f.read(1), byteorder='little')
    profileID = int.from_bytes(f.read(2), byteorder='little')
    fieldCount = int.from_bytes(f.read(2), byteorder='little')

    for _ in range(fieldCount):
    fieldID = None
    if version == 0x00:
    fieldID = int.from_bytes(f.read(2), byteorder='little')
    elif version == 0x01:
    fieldID = int.from_bytes(f.read(4), byteorder='little')

    dataSize = int.from_bytes(f.read(2), byteorder='little')
    dataFields[fieldID] = f.read(dataSize)

    return {
    "version": version,
    "profileID": profileID,
    "dataFields": dataFields,
    "timestampFields":timestampFields
    }

    def main(name):
    config = readfile(name)

    fieldNames = []
    if name.startswith('comp'):
    fieldNames = compFieldNames
    elif name.startswith('bolt'):
    fieldNames = boltFieldNames

    print(f'Version: {config["version"]}')
    print(f'Profile ID: {config["profileID"]}')
    for fieldID, fieldData in config["dataFields"].items():
    print(f'{fieldID:3d} {fieldNames[fieldID]:32s} => {fieldData}')


    if __name__ == "__main__":
    if len(sys.argv) != 2 or sys.argv[1][:4] not in ['comp', 'bolt']:
    print('Usage: python elemnt-config.py comp.cfg or bolt-65535.cfg')
    sys.exit(0)

    main(sys.argv[1])