Skip to content

Instantly share code, notes, and snippets.

@beaufortfrancois
Created August 12, 2021 12:31
Show Gist options
  • Save beaufortfrancois/1323816074f7383cfa574811abd6ea9c to your computer and use it in GitHub Desktop.
Save beaufortfrancois/1323816074f7383cfa574811abd6ea9c to your computer and use it in GitHub Desktop.
Parse Bluetooth Assigned Numbers (Service, Characteristics, Descriptors)
const fs = require("fs");
const LEGACY_UUIDS = {
"0x180F": "battery_service",
"0x2900": "gatt.characteristic_extended_properties",
"0x2901": "gatt.characteristic_user_description",
"0x2902": "gatt.client_characteristic_configuration",
"0x2903": "gatt.server_characteristic_configuration",
"0x2904": "gatt.characteristic_presentation_format",
"0x2905": "gatt.characteristic_aggregate_format",
"0x290B": "es_configuration",
"0x290C": "es_measurement",
"0x290D": "es_trigger_setting",
"0x2A00": "gap.device_name",
"0x2A01": "gap.appearance",
"0x2A02": "gap.peripheral_privacy_flag",
"0x2A03": "gap.reconnection_address",
"0x2A04": "gap.peripheral_preferred_connection_parameters",
"0x2A05": "gatt.service_changed",
"0x2A2A": "ieee_11073-20601_regulatory_certification_data_list",
"0x2A95": "two_zone_heart_rate_limit",
"0x2AA0": "magnetic_flux_density_2D",
"0x2AA1": "magnetic_flux_density_3D",
"0x2AA6": "gap.central_address_resolution_support",
"0x2AB1": "local_east_coordinate.xml",
"0x2AC5": "object_action_control_point",
};
// Instructions:
// 1. Download https://btprodspecificationrefs.blob.core.windows.net/assigned-values/16-bit%20UUID%20Numbers%20Document.pdf
// 2. Convert it to txt.
// 3. Run `node read-assigned-numbers.js`
// 4. Copy/paste output in `third_party/blink/renderer/modules/bluetooth/bluetooth_uuid.cc`
fs.readFile("16-bit UUID Numbers Document.txt", "utf8", (err, data) => {
// Expect a txt file with this structure.
//
// GATT Service
//
// 0x1800
//
// Generic Access
//
// GATT Service
//
// 0x1801
//
// Generic Attribute
printAssignedNumbers(data, "GATT Service");
printAssignedNumbers(data, "GATT Characteristic");
printAssignedNumbers(data, "GATT Descriptor");
});
function printAssignedNumbers(data, filter) {
let uuids = [];
let names = [];
let saveUuid = false;
let saveName = false;
data
.split(/\r?\n/)
.filter((line) => line.length != 0)
.forEach((line) => {
if (saveName) {
names.push(line);
saveName = false;
}
if (saveUuid) {
uuids.push(line);
saveUuid = false;
saveName = true;
}
if (line.startsWith(filter)) {
saveUuid = true;
}
});
console.log(`${filter}:`);
for (let i = 0; i < uuids.length; i++) {
let name = names[i]
.toLowerCase()
.replace(/ - /g, "_")
.replace(/ /g, "_")
.replace(/-/g, "_");
let uuid = uuids[i].replace(/^0X/, "0x");
if (uuid in LEGACY_UUIDS) {
name = LEGACY_UUIDS[uuid];
}
console.log(` {"${name}", ${uuid}},`);
}
}
@beaufortfrancois
Copy link
Author

beaufortfrancois commented Aug 12, 2021

$ node read-assigned-numbers.js
GATT Service:
          {"generic_access", 0x1800},
          {"generic_attribute", 0x1801},
          {"immediate_alert", 0x1802},
          {"link_loss", 0x1803},
          {"tx_power", 0x1804},
          {"current_time", 0x1805},
          {"reference_time_update", 0x1806},
          {"next_dst_change", 0x1807},
          {"glucose", 0x1808},
          {"health_thermometer", 0x1809},
          {"device_information", 0x180A},
          {"heart_rate", 0x180D},
          {"phone_alert_status", 0x180E},
          {"battery_service", 0x180F},
          {"blood_pressure", 0x1810},
          {"alert_notification", 0x1811},
          {"human_interface_device", 0x1812},
          {"scan_parameters", 0x1813},
          {"running_speed_and_cadence", 0x1814},
          {"automation_io", 0x1815},
          {"cycling_speed_and_cadence", 0x1816},
          {"cycling_power", 0x1818},
          {"location_and_navigation", 0x1819},
          {"environmental_sensing", 0x181A},
          {"body_composition", 0x181B},
          {"user_data", 0x181C},
          {"weight_scale", 0x181D},
          {"bond_management", 0x181E},
          {"continuous_glucose_monitoring", 0x181F},
          {"internet_protocol_support", 0x1820},
          {"indoor_positioning", 0x1821},
          {"pulse_oximeter", 0x1822},
          {"http_proxy", 0x1823},
          {"transport_discovery", 0x1824},
          {"object_transfer", 0x1825},
          {"fitness_machine", 0x1826},
          {"mesh_provisioning", 0x1827},
          {"mesh_proxy", 0x1828},
          {"reconnection_configuration", 0x1829},
          {"insulin_delivery", 0x183A},
          {"binary_sensor", 0x183B},
          {"emergency_configuration", 0x183C},
          {"physical_activity_monitor", 0x183E},
          {"audio_input_control", 0x1843},
          {"volume_control", 0x1844},
          {"volume_offset_control", 0x1845},
          {"coordinated_set_identification_service", 0x1846},
          {"device_time", 0x1847},
          {"media_control_service", 0x1848},
          {"generic_media_control_service", 0x1849},
          {"constant_tone_extension", 0x184A},
          {"telephone_bearer_service", 0x184B},
          {"generic_telephone_bearer_service", 0x184C},
          {"microphone_control", 0x184D},
GATT Characteristic:
          {"gap.device_name", 0x2A00},
          {"gap.appearance", 0x2A01},
          {"gap.peripheral_privacy_flag", 0x2A02},
          {"gap.reconnection_address", 0x2A03},
          {"gap.peripheral_preferred_connection_parameters", 0x2A04},
          {"gatt.service_changed", 0x2A05},
          {"alert_level", 0x2A06},
          {"tx_power_level", 0x2A07},
          {"date_time", 0x2A08},
          {"day_of_week", 0x2A09},
          {"day_date_time", 0x2A0A},
          {"exact_time_256", 0x2A0C},
          {"dst_offset", 0x2A0D},
          {"time_zone", 0x2A0E},
          {"local_time_information", 0x2A0F},
          {"time_with_dst", 0x2A11},
          {"time_accuracy", 0x2A12},
          {"time_source", 0x2A13},
          {"reference_time_information", 0x2A14},
          {"time_update_control_point", 0x2A16},
          {"time_update_state", 0x2A17},
          {"glucose_measurement", 0x2A18},
          {"battery_level", 0x2A19},
          {"temperature_measurement", 0x2A1C},
          {"temperature_type", 0x2A1D},
          {"intermediate_temperature", 0x2A1E},
          {"measurement_interval", 0x2A21},
          {"boot_keyboard_input_report", 0x2A22},
          {"system_id", 0x2A23},
          {"model_number_string", 0x2A24},
          {"serial_number_string", 0x2A25},
          {"firmware_revision_string", 0x2A26},
          {"hardware_revision_string", 0x2A27},
          {"software_revision_string", 0x2A28},
          {"manufacturer_name_string", 0x2A29},
          {"ieee_11073-20601_regulatory_certification_data_list", 0x2A2A},
          {"current_time", 0x2A2B},
          {"scan_refresh", 0x2A31},
          {"boot_keyboard_output_report", 0x2A32},
          {"boot_mouse_input_report", 0x2A33},
          {"glucose_measurement_context", 0x2A34},
          {"blood_pressure_measurement", 0x2A35},
          {"intermediate_cuff_pressure", 0x2A36},
          {"heart_rate_measurement", 0x2A37},
          {"body_sensor_location", 0x2A38},
          {"heart_rate_control_point", 0x2A39},
          {"alert_status", 0x2A3F},
          {"ringer_control_point", 0x2A40},
          {"ringer_setting", 0x2A41},
          {"alert_category_id_bit_mask", 0x2A42},
          {"alert_category_id", 0x2A43},
          {"alert_notification_control_point", 0x2A44},
          {"unread_alert_status", 0x2A45},
          {"new_alert", 0x2A46},
          {"supported_new_alert_category", 0x2A47},
          {"supported_unread_alert_category", 0x2A48},
          {"blood_pressure_feature", 0x2A49},
          {"hid_information", 0x2A4A},
          {"report_map", 0x2A4B},
          {"hid_control_point", 0x2A4C},
          {"report", 0x2A4D},
          {"protocol_mode", 0x2A4E},
          {"scan_interval_window", 0x2A4F},
          {"pnp_id", 0x2A50},
          {"glucose_feature", 0x2A51},
          {"record_access_control_point", 0x2A52},
          {"rsc_measurement", 0x2A53},
          {"rsc_feature", 0x2A54},
          {"sc_control_point", 0x2A55},
          {"aggregate", 0x2A5A},
          {"csc_measurement", 0x2A5B},
          {"csc_feature", 0x2A5C},
          {"sensor_location", 0x2A5D},
          {"plx_spot_check_measurement", 0x2A5E},
          {"plx_continuous_measurement", 0x2A5F},
          {"plx_features", 0x2A60},
          {"cycling_power_measurement", 0x2A63},
          {"cycling_power_vector", 0x2A64},
          {"cycling_power_feature", 0x2A65},
          {"cycling_power_control_point", 0x2A66},
          {"location_and_speed", 0x2A67},
          {"navigation", 0x2A68},
          {"position_quality", 0x2A69},
          {"ln_feature", 0x2A6A},
          {"ln_control_point", 0x2A6B},
          {"elevation", 0x2A6C},
          {"pressure", 0x2A6D},
          {"temperature", 0x2A6E},
          {"humidity", 0x2A6F},
          {"true_wind_speed", 0x2A70},
          {"true_wind_direction", 0x2A71},
          {"apparent_wind_speed", 0x2A72},
          {"apparent_wind_direction", 0x2A73},
          {"gust_factor", 0x2A74},
          {"pollen_concentration", 0x2A75},
          {"uv_index", 0x2A76},
          {"irradiance", 0x2A77},
          {"rainfall", 0x2A78},
          {"wind_chill", 0x2A79},
          {"heat_index", 0x2A7A},
          {"dew_point", 0x2A7B},
          {"descriptor_value_changed", 0x2A7D},
          {"aerobic_heart_rate_lower_limit", 0x2A7E},
          {"aerobic_threshold", 0x2A7F},
          {"age", 0x2A80},
          {"anaerobic_heart_rate_lower_limit", 0x2A81},
          {"anaerobic_heart_rate_upper_limit", 0x2A82},
          {"anaerobic_threshold", 0x2A83},
          {"aerobic_heart_rate_upper_limit", 0x2A84},
          {"date_of_birth", 0x2A85},
          {"date_of_threshold_assessment", 0x2A86},
          {"email_address", 0x2A87},
          {"fat_burn_heart_rate_lower_limit", 0x2A88},
          {"fat_burn_heart_rate_upper_limit", 0x2A89},
          {"first_name", 0x2A8A},
          {"five_zone_heart_rate_limits", 0x2A8B},
          {"gender", 0x2A8C},
          {"heart_rate_max", 0x2A8D},
          {"height", 0x2A8E},
          {"hip_circumference", 0x2A8F},
          {"last_name", 0x2A90},
          {"maximum_recommended_heart_rate", 0x2A91},
          {"resting_heart_rate", 0x2A92},
          {"sport_type_for_aerobic_and_anaerobic_thresholds", 0x2A93},
          {"three_zone_heart_rate_limits", 0x2A94},
          {"two_zone_heart_rate_limit", 0x2A95},
          {"vo2_max", 0x2A96},
          {"waist_circumference", 0x2A97},
          {"weight", 0x2A98},
          {"database_change_increment", 0x2A99},
          {"user_index", 0x2A9A},
          {"body_composition_feature", 0x2A9B},
          {"body_composition_measurement", 0x2A9C},
          {"weight_measurement", 0x2A9D},
          {"weight_scale_feature", 0x2A9E},
          {"user_control_point", 0x2A9F},
          {"magnetic_flux_density_2D", 0x2AA0},
          {"magnetic_flux_density_3D", 0x2AA1},
          {"language", 0x2AA2},
          {"barometric_pressure_trend", 0x2AA3},
          {"bond_management_control_point", 0x2AA4},
          {"bond_management_feature", 0x2AA5},
          {"gap.central_address_resolution_support", 0x2AA6},
          {"cgm_measurement", 0x2AA7},
          {"cgm_feature", 0x2AA8},
          {"cgm_status", 0x2AA9},
          {"cgm_session_start_time", 0x2AAA},
          {"cgm_session_run_time", 0x2AAB},
          {"cgm_specific_ops_control_point", 0x2AAC},
          {"indoor_positioning_configuration", 0x2AAD},
          {"latitude", 0x2AAE},
          {"longitude", 0x2AAF},
          {"local_north_coordinate", 0x2AB0},
          {"local_east_coordinate.xml", 0x2AB1},
          {"floor_number", 0x2AB2},
          {"altitude", 0x2AB3},
          {"uncertainty", 0x2AB4},
          {"location_name", 0x2AB5},
          {"uri", 0x2AB6},
          {"http_headers", 0x2AB7},
          {"http_status_code", 0x2AB8},
          {"http_entity_body", 0x2AB9},
          {"http_control_point", 0x2ABA},
          {"https_security", 0x2ABB},
          {"tds_control_point", 0x2ABC},
          {"ots_feature", 0x2ABD},
          {"object_name", 0x2ABE},
          {"object_type", 0x2ABF},
          {"object_size", 0x2AC0},
          {"object_first_created", 0x2AC1},
          {"object_last_modified", 0x2AC2},
          {"object_id", 0x2AC3},
          {"object_properties", 0x2AC4},
          {"object_action_control_point", 0x2AC5},
          {"object_list_control_point", 0x2AC6},
          {"object_list_filter", 0x2AC7},
          {"object_changed", 0x2AC8},
          {"resolvable_private_address_only", 0x2AC9},
          {"unspecified", 0x2ACA},
          {"directory_listing", 0x2ACB},
          {"fitness_machine_feature", 0x2ACC},
          {"treadmill_data", 0x2ACD},
          {"cross_trainer_data", 0x2ACE},
          {"step_climber_data", 0x2ACF},
          {"stair_climber_data", 0x2AD0},
          {"rower_data", 0x2AD1},
          {"indoor_bike_data", 0x2AD2},
          {"training_status", 0x2AD3},
          {"supported_speed_range", 0x2AD4},
          {"supported_inclination_range", 0x2AD5},
          {"supported_resistance_level_range", 0x2AD6},
          {"supported_heart_rate_range", 0x2AD7},
          {"supported_power_range", 0x2AD8},
          {"fitness_machine_control_point", 0x2AD9},
          {"fitness_machine_status", 0x2ADA},
          {"mesh_provisioning_data_in", 0x2ADB},
          {"mesh_provisioning_data_out", 0x2ADC},
          {"mesh_proxy_data_in", 0x2ADD},
          {"mesh_proxy_data_out", 0x2ADE},
          {"average_current", 0x2AE0},
          {"average_voltage", 0x2AE1},
          {"boolean", 0x2AE2},
          {"chromatic_distance_from_planckian", 0x2AE3},
          {"chromaticity_coordinates", 0x2AE4},
          {"chromaticity_in_cct_and_duv_values", 0x2AE5},
          {"chromaticity_tolerance", 0x2AE6},
          {"cie_13.3_1995_color_rendering_index", 0x2AE7},
          {"coefficient", 0x2AE8},
          {"correlated_color_temperature", 0x2AE9},
          {"count_16", 0x2AEA},
          {"count_24", 0x2AEB},
          {"country_code", 0x2AEC},
          {"date_utc", 0x2AED},
          {"electric_current", 0x2AEE},
          {"electric_current_range", 0x2AEF},
          {"electric_current_specification", 0x2AF0},
          {"electric_current_statistics", 0x2AF1},
          {"energy", 0x2AF2},
          {"energy_in_a_period_of_day", 0x2AF3},
          {"event_statistics", 0x2AF4},
          {"fixed_string_16", 0x2AF5},
          {"fixed_string_24", 0x2AF6},
          {"fixed_string_36", 0x2AF7},
          {"fixed_string_8", 0x2AF8},
          {"generic_level", 0x2AF9},
          {"global_trade_item_number", 0x2AFA},
          {"illuminance", 0x2AFB},
          {"luminous_efficacy", 0x2AFC},
          {"luminous_energy", 0x2AFD},
          {"luminous_exposure", 0x2AFE},
          {"luminous_flux", 0x2AFF},
          {"luminous_flux_range", 0x2B00},
          {"luminous_intensity", 0x2B01},
          {"mass_flow", 0x2B02},
          {"perceived_lightness", 0x2B03},
          {"percentage_8", 0x2B04},
          {"power", 0x2B05},
          {"power_specification", 0x2B06},
          {"relative_runtime_in_a_current_range", 0x2B07},
          {"relative_runtime_in_a_generic_level_range", 0x2B08},
          {"relative_value_in_a_voltage_range", 0x2B09},
          {"relative_value_in_an_illuminance_range", 0x2B0A},
          {"relative_value_in_a_period_of_day", 0x2B0B},
          {"relative_value_in_a_temperature_range", 0x2B0C},
          {"temperature_8", 0x2B0D},
          {"temperature_8_in_a_period_of_day", 0x2B0E},
          {"temperature_8_statistics", 0x2B0F},
          {"temperature_range", 0x2B10},
          {"temperature_statistics", 0x2B11},
          {"time_decihour_8", 0x2B12},
          {"time_exponential_8", 0x2B13},
          {"time_hour_24", 0x2B14},
          {"time_millisecond_24", 0x2B15},
          {"time_second_16", 0x2B16},
          {"time_second_8", 0x2B17},
          {"voltage", 0x2B18},
          {"voltage_specification", 0x2B19},
          {"voltage_statistics", 0x2B1A},
          {"volume_flow", 0x2B1B},
          {"chromaticity_coordinate", 0x2B1C},
          {"rc_feature", 0x2B1D},
          {"rc_settings", 0x2B1E},
          {"reconnection_configuration_control_point", 0x2B1F},
          {"idd_status_changed", 0x2B20},
          {"idd_status", 0x2B21},
          {"idd_annunciation_status", 0x2B22},
          {"idd_features", 0x2B23},
          {"idd_status_reader_control_point", 0x2B24},
          {"idd_command_control_point", 0x2B25},
          {"idd_command_data", 0x2B26},
          {"idd_record_access_control_point", 0x2B27},
          {"idd_history_data", 0x2B28},
          {"client_supported_features", 0x2B29},
          {"database_hash", 0x2B2A},
          {"bss_control_point", 0x2B2B},
          {"bss_response", 0x2B2C},
          {"emergency_id", 0x2B2D},
          {"emergency_text", 0x2B2E},
          {"enhanced_blood_pressure_measurement", 0x2B34},
          {"enhanced_intermediate_cuff_pressure", 0x2B35},
          {"blood_pressure_record", 0x2B36},
          {"br_edr_handover_data", 0x2B38},
          {"bluetooth_sig_data", 0x2B39},
          {"server_supported_features", 0x2B3A},
          {"physical_activity_monitor_features", 0x2B3B},
          {"general_activity_instantaneous_data", 0x2B3C},
          {"general_activity_summary_data", 0x2B3D},
          {"cardiorespiratory_activity_instantaneous_data", 0x2B3E},
          {"cardiorespiratory_activity_summary_data", 0x2B3F},
          {"step_counter_activity_summary_data", 0x2B40},
          {"sleep_activity_instantaneous_data", 0x2B41},
          {"sleep_activity_summary_data", 0x2B42},
          {"physical_activity_monitor_control_point", 0x2B43},
          {"current_session", 0x2B44},
          {"session", 0x2B45},
          {"preferred_units", 0x2B46},
          {"high_resolution_height", 0x2B47},
          {"middle_name", 0x2B48},
          {"stride_length", 0x2B49},
          {"handedness", 0x2B4A},
          {"device_wearing_position", 0x2B4B},
          {"four_zone_heart_rate_limits", 0x2B4C},
          {"high_intensity_exercise_threshold", 0x2B4D},
          {"activity_goal", 0x2B4E},
          {"sedentary_interval_notification", 0x2B4F},
          {"caloric_intake", 0x2B50},
          {"audio_input_state", 0x2B77},
          {"gain_settings_attribute", 0x2B78},
          {"audio_input_type", 0x2B79},
          {"audio_input_status", 0x2B7A},
          {"audio_input_control_point", 0x2B7B},
          {"audio_input_description", 0x2B7C},
          {"volume_state", 0x2B7D},
          {"volume_control_point", 0x2B7E},
          {"volume_flags", 0x2B7F},
          {"offset_state", 0x2B80},
          {"audio_location", 0x2B81},
          {"volume_offset_control_point", 0x2B82},
          {"audio_output_description", 0x2B83},
          {"set_identity_resolving_key_characteristic", 0x2B84},
          {"size_characteristic", 0x2B85},
          {"lock_characteristic", 0x2B86},
          {"rank_characteristic", 0x2B87},
          {"device_time_feature", 0x2B8E},
          {"device_time_parameters", 0x2B8F},
          {"device_time", 0x2B90},
          {"device_time_control_point", 0x2B91},
          {"time_change_log_data", 0x2B92},
          {"media_player_name", 0x2B93},
          {"media_player_icon_object_id", 0x2B94},
          {"media_player_icon_url", 0x2B95},
          {"track_changed", 0x2B96},
          {"track_title", 0x2B97},
          {"track_duration", 0x2B98},
          {"track_position", 0x2B99},
          {"playback_speed", 0x2B9A},
          {"seeking_speed", 0x2B9B},
          {"current_track_segments_object_id", 0x2B9C},
          {"current_track_object_id", 0x2B9D},
          {"next_track_object_id", 0x2B9E},
          {"parent_group_object_id", 0x2B9F},
          {"current_group_object_id", 0x2BA0},
          {"playing_order", 0x2BA1},
          {"playing_orders_supported", 0x2BA2},
          {"media_state", 0x2BA3},
          {"media_control_point", 0x2BA4},
          {"media_control_point_opcodes_supported", 0x2BA5},
          {"search_results_object_id", 0x2BA6},
          {"search_control_point", 0x2BA7},
          {"media_player_icon_object_type", 0x2BA9},
          {"track_segments_object_type", 0x2BAA},
          {"track_object_type", 0x2BAB},
          {"gatt_characteristic_and_object_type", 0x2BAC},
          {"group_object_type", 0x2BAD},
          {"advertising_constant_tone_extension_minimum_length", 0x2BAE},
          {"advertising_constant_tone_extension_minimum_transmit_count", 0x2BAF},
          {"advertising_constant_tone_extension_transmit_duration", 0x2BB0},
          {"advertising_constant_tone_extension_interval", 0x2BB1},
          {"advertising_constant_tone_extension_phy", 0x2BB2},
          {"bearer_provider_name", 0x2BB3},
          {"bearer_uci", 0x2BB4},
          {"bearer_technology", 0x2BB5},
          {"bearer_uri_schemes_supported_list", 0x2BB6},
          {"bearer_signal_strength", 0x2BB7},
          {"bearer_signal_strength_reporting_interval", 0x2BB8},
          {"bearer_list_current_calls", 0x2BB9},
          {"content_control_id", 0x2BBA},
          {"status_flags", 0x2BBB},
          {"incoming_call_target_bearer_uri", 0x2BBC},
          {"call_state", 0x2BBD},
          {"call_control_point", 0x2BBE},
          {"call_control_point_optional_opcodes", 0x2BBF},
          {"termination_reason", 0x2BC0},
          {"incoming_call", 0x2BC1},
          {"call_friendly_name", 0x2BC2},
          {"mute", 0x2BC3},
GATT Descriptor:
          {"gatt.characteristic_extended_properties", 0x2900},
          {"gatt.characteristic_user_description", 0x2901},
          {"gatt.client_characteristic_configuration", 0x2902},
          {"gatt.server_characteristic_configuration", 0x2903},
          {"gatt.characteristic_presentation_format", 0x2904},
          {"gatt.characteristic_aggregate_format", 0x2905},
          {"valid_range", 0x2906},
          {"external_report_reference", 0x2907},
          {"report_reference", 0x2908},
          {"number_of_digitals", 0x2909},
          {"value_trigger_setting", 0x290A},
          {"es_configuration", 0x290B},
          {"es_measurement", 0x290C},
          {"es_trigger_setting", 0x290D},
          {"time_trigger_setting", 0x290E},
          {"complete_br_edr_transport_block_data", 0x290F},

@ariccio
Copy link

ariccio commented Dec 19, 2021

It's kinda wild that nobody else maintains something like this, right? When devices don't have good documentation, it's super useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment