UNPKG

webbluetooth

Version:

Node.js implementation of the Web Bluetooth Specification

313 lines (301 loc) 10.9 kB
/* * Node Web Bluetooth * Copyright (c) 2017 Rob Moran * * The MIT License (MIT) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Known services enum */ enum bluetoothServices { 'alert_notification' = 0x1811, 'automation_io' = 0x1815, 'battery_service' = 0x180F, 'blood_pressure' = 0x1810, 'body_composition' = 0x181B, 'bond_management' = 0x181E, 'continuous_glucose_monitoring' = 0x181F, 'current_time' = 0x1805, 'cycling_power' = 0x1818, 'cycling_speed_and_cadence' = 0x1816, 'device_information' = 0x180A, 'environmental_sensing' = 0x181A, 'generic_access' = 0x1800, 'generic_attribute' = 0x1801, 'glucose' = 0x1808, 'health_thermometer' = 0x1809, 'heart_rate' = 0x180D, 'human_interface_device' = 0x1812, 'immediate_alert' = 0x1802, 'indoor_positioning' = 0x1821, 'internet_protocol_support' = 0x1820, 'link_loss' = 0x1803, 'location_and_navigation' = 0x1819, 'next_dst_change' = 0x1807, 'phone_alert_status' = 0x180E, 'pulse_oximeter' = 0x1822, 'reference_time_update' = 0x1806, 'running_speed_and_cadence' = 0x1814, 'scan_parameters' = 0x1813, 'tx_power' = 0x1804, 'user_data' = 0x181C, 'weight_scale' = 0x181D } /** * Known characteristics enum */ enum bluetoothCharacteristics { 'aerobic_heart_rate_lower_limit' = 0x2A7E, 'aerobic_heart_rate_upper_limit' = 0x2A84, 'aerobic_threshold' = 0x2A7F, 'age' = 0x2A80, 'aggregate' = 0x2A5A, 'alert_category_id' = 0x2A43, 'alert_category_id_bit_mask' = 0x2A42, 'alert_level' = 0x2A06, 'alert_notification_control_point' = 0x2A44, 'alert_status' = 0x2A3F, 'altitude' = 0x2AB3, 'anaerobic_heart_rate_lower_limit' = 0x2A81, 'anaerobic_heart_rate_upper_limit' = 0x2A82, 'anaerobic_threshold' = 0x2A83, 'analog' = 0x2A58, 'apparent_wind_direction' = 0x2A73, 'apparent_wind_speed' = 0x2A72, 'gap.appearance' = 0x2A01, 'barometric_pressure_trend' = 0x2AA3, 'battery_level' = 0x2A19, 'blood_pressure_feature' = 0x2A49, 'blood_pressure_measurement' = 0x2A35, 'body_composition_feature' = 0x2A9B, 'body_composition_measurement' = 0x2A9C, 'body_sensor_location' = 0x2A38, 'bond_management_control_point' = 0x2AA4, 'bond_management_feature' = 0x2AA5, 'boot_keyboard_input_report' = 0x2A22, 'boot_keyboard_output_report' = 0x2A32, 'boot_mouse_input_report' = 0x2A33, 'gap.central_address_resolution_support' = 0x2AA6, 'cgm_feature' = 0x2AA8, 'cgm_measurement' = 0x2AA7, 'cgm_session_run_time' = 0x2AAB, 'cgm_session_start_time' = 0x2AAA, 'cgm_specific_ops_control_point' = 0x2AAC, 'cgm_status' = 0x2AA9, 'csc_feature' = 0x2A5C, 'csc_measurement' = 0x2A5B, 'current_time' = 0x2A2B, 'cycling_power_control_point' = 0x2A66, 'cycling_power_feature' = 0x2A65, 'cycling_power_measurement' = 0x2A63, 'cycling_power_vector' = 0x2A64, 'database_change_increment' = 0x2A99, 'date_of_birth' = 0x2A85, 'date_of_threshold_assessment' = 0x2A86, 'date_time' = 0x2A08, 'day_date_time' = 0x2A0A, 'day_of_week' = 0x2A09, 'descriptor_value_changed' = 0x2A7D, 'gap.device_name' = 0x2A00, 'dew_point' = 0x2A7B, 'digital' = 0x2A56, 'dst_offset' = 0x2A0D, 'elevation' = 0x2A6C, 'email_address' = 0x2A87, 'exact_time_256' = 0x2A0C, 'fat_burn_heart_rate_lower_limit' = 0x2A88, 'fat_burn_heart_rate_upper_limit' = 0x2A89, 'firmware_revision_string' = 0x2A26, 'first_name' = 0x2A8A, 'five_zone_heart_rate_limits' = 0x2A8B, 'floor_number' = 0x2AB2, 'gender' = 0x2A8C, 'glucose_feature' = 0x2A51, 'glucose_measurement' = 0x2A18, 'glucose_measurement_context' = 0x2A34, 'gust_factor' = 0x2A74, 'hardware_revision_string' = 0x2A27, 'heart_rate_control_point' = 0x2A39, 'heart_rate_max' = 0x2A8D, 'heart_rate_measurement' = 0x2A37, 'heat_index' = 0x2A7A, 'height' = 0x2A8E, 'hid_control_point' = 0x2A4C, 'hid_information' = 0x2A4A, 'hip_circumference' = 0x2A8F, 'humidity' = 0x2A6F, 'ieee_11073-20601_regulatory_certification_data_list' = 0x2A2A, 'indoor_positioning_configuration' = 0x2AAD, 'intermediate_blood_pressure' = 0x2A36, 'intermediate_temperature' = 0x2A1E, 'irradiance' = 0x2A77, 'language' = 0x2AA2, 'last_name' = 0x2A90, 'latitude' = 0x2AAE, 'ln_control_point' = 0x2A6B, 'ln_feature' = 0x2A6A, 'local_east_coordinate.xml' = 0x2AB1, 'local_north_coordinate' = 0x2AB0, 'local_time_information' = 0x2A0F, 'location_and_speed' = 0x2A67, 'location_name' = 0x2AB5, 'longitude' = 0x2AAF, 'magnetic_declination' = 0x2A2C, 'magnetic_flux_density_2D' = 0x2AA0, 'magnetic_flux_density_3D' = 0x2AA1, 'manufacturer_name_string' = 0x2A29, 'maximum_recommended_heart_rate' = 0x2A91, 'measurement_interval' = 0x2A21, 'model_number_string' = 0x2A24, 'navigation' = 0x2A68, 'new_alert' = 0x2A46, 'gap.peripheral_preferred_connection_parameters' = 0x2A04, 'gap.peripheral_privacy_flag' = 0x2A02, 'plx_continuous_measurement' = 0x2A5F, 'plx_features' = 0x2A60, 'plx_spot_check_measurement' = 0x2A5E, 'pnp_id' = 0x2A50, 'pollen_concentration' = 0x2A75, 'position_quality' = 0x2A69, 'pressure' = 0x2A6D, 'protocol_mode' = 0x2A4E, 'rainfall' = 0x2A78, 'gap.reconnection_address' = 0x2A03, 'record_access_control_point' = 0x2A52, 'reference_time_information' = 0x2A14, 'report' = 0x2A4D, 'report_map' = 0x2A4B, 'resting_heart_rate' = 0x2A92, 'ringer_control_point' = 0x2A40, 'ringer_setting' = 0x2A41, 'rsc_feature' = 0x2A54, 'rsc_measurement' = 0x2A53, 'sc_control_point' = 0x2A55, 'scan_interval_window' = 0x2A4F, 'scan_refresh' = 0x2A31, 'sensor_location' = 0x2A5D, 'serial_number_string' = 0x2A25, 'gatt.service_changed' = 0x2A05, 'software_revision_string' = 0x2A28, 'sport_type_for_aerobic_and_anaerobic_thresholds' = 0x2A93, 'supported_new_alert_category' = 0x2A47, 'supported_unread_alert_category' = 0x2A48, 'system_id' = 0x2A23, 'temperature' = 0x2A6E, 'temperature_measurement' = 0x2A1C, 'temperature_type' = 0x2A1D, 'three_zone_heart_rate_limits' = 0x2A94, 'time_accuracy' = 0x2A12, 'time_source' = 0x2A13, 'time_update_control_point' = 0x2A16, 'time_update_state' = 0x2A17, 'time_with_dst' = 0x2A11, 'time_zone' = 0x2A0E, 'true_wind_direction' = 0x2A71, 'true_wind_speed' = 0x2A70, 'two_zone_heart_rate_limit' = 0x2A95, 'tx_power_level' = 0x2A07, 'uncertainty' = 0x2AB4, 'unread_alert_status' = 0x2A45, 'user_control_point' = 0x2A9F, 'user_index' = 0x2A9A, 'uv_index' = 0x2A76, 'vo2_max' = 0x2A96, 'waist_circumference' = 0x2A97, 'weight' = 0x2A98, 'weight_measurement' = 0x2A9D, 'weight_scale_feature' = 0x2A9E, 'wind_chill' = 0x2A79 } /** * Known descriptors enum */ enum bluetoothDescriptors { '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 } /** * Gets a canonical UUID from a partial UUID in string or hex format * @param alias The partial UUID * @returns canonical UUID */ const canonicalUUID = (alias: string | number): string => { if (typeof alias === 'number') alias = alias.toString(16); alias = alias.toLowerCase(); if (alias.length <= 8) alias = ('00000000' + alias).slice(-8) + '-0000-1000-8000-00805f9b34fb'; if (alias.length === 32) alias = alias.match(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12})$/).splice(1).join('-'); return alias; }; /** * Gets a canonical service UUID from a known service name or partial UUID in string or hex format * @param name The known service name * @returns canonical UUID */ const getService = (name: string | number): string => { // Check for string as enums also allow a reverse lookup which will match any numbers passed in if (typeof name === 'string' && bluetoothServices[name]) { name = bluetoothServices[name]; } return canonicalUUID(name); }; /** * Gets a canonical characteristic UUID from a known characteristic name or partial UUID in string or hex format * @param name The known characteristic name * @returns canonical UUID */ const getCharacteristic = (name: string | number): string => { // Check for string as enums also allow a reverse lookup which will match any numbers passed in if (typeof name === 'string' && bluetoothCharacteristics[name]) { name = bluetoothCharacteristics[name]; } return canonicalUUID(name); }; /** * Gets a canonical descriptor UUID from a known descriptor name or partial UUID in string or hex format * @param name The known descriptor name * @returns canonical UUID */ const getDescriptor = (name: string | number): string => { // Check for string as enums also allow a reverse lookup which will match any numbers passed in if (typeof name === 'string' && bluetoothDescriptors[name]) { name = bluetoothDescriptors[name]; } return canonicalUUID(name); }; export const BluetoothUUID = { getService, getCharacteristic, getDescriptor, canonicalUUID };