diff --git a/backend/crx_uuid_name_map.py b/backend/crx_uuid_name_map.py index eee744a0..1449df33 100644 --- a/backend/crx_uuid_name_map.py +++ b/backend/crx_uuid_name_map.py @@ -49,12 +49,56 @@ def reduce_idx(idx: str) -> str: parts = idx.split("-") first_group_as_number = int(parts[0],16) - # 0xffff ensures -1 becomes 0x0000ffff: + # '& 0xffff' makes int unsigned (ensures -1 becomes 0x0000ffff): new_first_group_as_hex = f"{first_group_as_number-1 & 0xffff:08x}" return '-'.join([new_first_group_as_hex] + parts[1:]) -names_v221 = { +names_v221beta1 = { **{reduce_idx(k): v for k, v in names_v220.items()}, "00000025-0000-1000-8000-00805f9b34fb": "BLEEnabled", "0000fffe-0000-1000-8000-00805f9b34fb": "SettingsReset", } + +names_v221beta2 = { +'f6d75001-5a10-4eba-aa55-33e27f9bc533': 'save_to_flash', +'f6d75002-5a10-4eba-aa55-33e27f9bc533': 'SettingsReset', +'f6d75003-5a10-4eba-aa55-33e27f9bc533': 'SetTemperature', +'f6d75004-5a10-4eba-aa55-33e27f9bc533': 'SleepTemperature', +'f6d75005-5a10-4eba-aa55-33e27f9bc533': 'SleepTimeout', +'f6d75006-5a10-4eba-aa55-33e27f9bc533': 'DCInCutoff', +'f6d75007-5a10-4eba-aa55-33e27f9bc533': 'MinVolCell', +'f6d75008-5a10-4eba-aa55-33e27f9bc533': 'QCMaxVoltage', +'f6d75009-5a10-4eba-aa55-33e27f9bc533': 'DisplayRotation', +'f6d7500a-5a10-4eba-aa55-33e27f9bc533': 'MotionSensitivity', +'f6d7500b-5a10-4eba-aa55-33e27f9bc533': 'AnimLoop', +'f6d7500c-5a10-4eba-aa55-33e27f9bc533': 'AnimSpeed', +'f6d7500d-5a10-4eba-aa55-33e27f9bc533': 'AutoStart', +'f6d7500e-5a10-4eba-aa55-33e27f9bc533': 'ShutdownTimeout', +'f6d7500f-5a10-4eba-aa55-33e27f9bc533': 'CooldownBlink', +'f6d75010-5a10-4eba-aa55-33e27f9bc533': 'AdvancedIdle', +'f6d75011-5a10-4eba-aa55-33e27f9bc533': 'AdvancedSoldering', +'f6d75012-5a10-4eba-aa55-33e27f9bc533': 'TemperatureUnit', +'f6d75013-5a10-4eba-aa55-33e27f9bc533': 'ScrollingSpeed', +'f6d75014-5a10-4eba-aa55-33e27f9bc533': 'LockingMode', +'f6d75015-5a10-4eba-aa55-33e27f9bc533': 'PowerPulsePower', +'f6d75016-5a10-4eba-aa55-33e27f9bc533': 'PowerPulseWait', +'f6d75017-5a10-4eba-aa55-33e27f9bc533': 'PowerPulseDuration', +'f6d75018-5a10-4eba-aa55-33e27f9bc533': 'VoltageCalibration', +'f6d75019-5a10-4eba-aa55-33e27f9bc533': 'BoostTemperature', +'f6d7501a-5a10-4eba-aa55-33e27f9bc533': 'CalibrationOffset', +'f6d7501b-5a10-4eba-aa55-33e27f9bc533': 'PowerLimit', +'f6d7501c-5a10-4eba-aa55-33e27f9bc533': 'ReverseButtonTempChange', +'f6d7501d-5a10-4eba-aa55-33e27f9bc533': 'TempChangeLongStep', +'f6d7501e-5a10-4eba-aa55-33e27f9bc533': 'TempChangeShortStep', +'f6d7501f-5a10-4eba-aa55-33e27f9bc533': 'HallEffectSensitivity', +'f6d75020-5a10-4eba-aa55-33e27f9bc533': 'AccelMissingWarningCounter', +'f6d75021-5a10-4eba-aa55-33e27f9bc533': 'PDMissingWarningCounter', +'f6d75022-5a10-4eba-aa55-33e27f9bc533': 'UILanguage', +'f6d75023-5a10-4eba-aa55-33e27f9bc533': 'PDNegTimeout', +'f6d75024-5a10-4eba-aa55-33e27f9bc533': 'ColourInversion', +'f6d75025-5a10-4eba-aa55-33e27f9bc533': 'Brightness', +'f6d75026-5a10-4eba-aa55-33e27f9bc533': 'LOGOTime', +'f6d75027-5a10-4eba-aa55-33e27f9bc533': 'CalibrateCJC', +'f6d75029-5a10-4eba-aa55-33e27f9bc533': 'BLEEnabled', +'f6d7502a-5a10-4eba-aa55-33e27f9bc533': 'PDVpdoEnabled', +} diff --git a/backend/pinecil_ble.py b/backend/pinecil_ble.py index 4d66db75..5d98ddf6 100644 --- a/backend/pinecil_ble.py +++ b/backend/pinecil_ble.py @@ -4,7 +4,7 @@ import asyncio from pinecil_setting_limits import value_limits from pinecil_setting_limits import temperature_limits -from crx_uuid_name_map import names_v220, names_v221, bulk_data_names +from crx_uuid_name_map import names_v220, names_v221beta1, names_v221beta2, bulk_data_names from ble import BleakGATTCharacteristic from ble import BLE import time @@ -21,8 +21,13 @@ def __init__(self): self.names = names_v220 def set_version(self, version: str): - self.names = names_v220 if version == '2.20' else names_v221 - + names = { + '2.20': names_v220, + '2.21beta1': names_v221beta1, + '2.21beta2': names_v221beta2, + } + self.names = names.get(version, names_v220) + def get_name(self, uuid: str) -> str: return self.names.get(uuid, uuid) @@ -47,9 +52,8 @@ class Pinecil: def __init__(self): self.ble = BLE(name='pinecil') - self.settings_uuid: str = 'f6d75f91-5a10-4eba-a233-47d3f26a907f' - self.bulk_data_uuid: str = '9eae1adb-9d0d-48c5-a6e7-ae93f0ea37b0' - # self.live_data_uuid: str = 'd85efab4-168e-4a71-affd-33e27f9bc533' + self.settings_uuid: str + self.bulk_data_uuid: str self.temp_unit_crx: str = 'TemperatureUnit' self.settings_map = SettingNameToUUIDMap() self.bulk_data_map = BulkDataToUUIDMap() @@ -65,22 +69,38 @@ def __init__(self): def is_connected(self): return self.ble.is_connected and self.is_initialized - def __get_version(self, crxs: List[BleakGATTCharacteristic]): + async def __set_ble_uuids_based_on_version(self): # this is just a hack until the version is exposed in the settings - for crx in crxs: + uuid_settings_pre_221 = 'f6d75f91-5a10-4eba-a233-47d3f26a907f' + uuid_settings_221beta2 = 'f6d75000-5a10-4eba-aa55-33e27f9bc533' + uuid_bulk_data_pre_221 = '9eae1adb-9d0d-48c5-a6e7-ae93f0ea37b0' + uuid_bulk_data_221beta2 = '9eae1000-9d0d-48c5-aa55-33e27f9bc533' + services = await self.ble.get_services() + if uuid_settings_221beta2 in services: + self.settings_uuid = uuid_settings_221beta2 + self.bulk_data_uuid = uuid_bulk_data_221beta2 + self.settings_map.set_version('2.21beta2') + return + crx_settings = await self.ble.get_characteristics(uuid_settings_pre_221) + for crx in crx_settings: if crx.uuid == '0000ffff-0000-1000-8000-00805f9b34fb': - return '2.21' - return '2.20' - + self.settings_map.set_version('2.21beta1') + break + else: + self.settings_map.set_version('2.20') + self.settings_uuid = uuid_settings_pre_221 + self.bulk_data_uuid = uuid_bulk_data_pre_221 + async def connect(self): await self.ble.ensure_connected() + await self.__set_ble_uuids_based_on_version() + self.crx_settings = await self.ble.get_characteristics(self.settings_uuid) bulk_crx = await self.ble.get_characteristics(self.bulk_data_uuid) for crx in bulk_crx: if crx.uuid == self.bulk_data_map.get_uuid(self.bulk_data_to_read): self.crx_bulk_data = crx break - self.settings_map.set_version(self.__get_version(self.crx_settings)) self.unique_id = await self.__get_pinecil_id() self.is_initialized = True @@ -164,6 +184,7 @@ async def get_info(self): 'name': f'Pinecil-{self.unique_id}', 'id': self.unique_id, } + async def __read_live_data(self, crx: BleakGATTCharacteristic) -> Dict[str, int]: raw_value = await self.ble.read_characteristic(crx) num_of_values = len(raw_value) >> 2 # divide by 4 @@ -196,7 +217,7 @@ async def get_live_data(self) -> Dict[str, int]: def ensure_setting_exists(name: str): - if name not in names_v220.values() and name not in names_v221.values(): + if name not in names_v220.values() and name not in names_v221beta1.values(): logging.warning(f'Setting {name} does not exist') raise InvalidSettingException diff --git a/backend/test_pinecil.py b/backend/test_pinecil.py index acaace1b..5e12cc87 100644 --- a/backend/test_pinecil.py +++ b/backend/test_pinecil.py @@ -24,10 +24,14 @@ async def get_characteristics(uuid): return [] async def read_crx(a): return a.raw_value - + mock_services = [ + MagicMock(uuid='f6d75f91-5a10-4eba-a233-47d3f26a907f'), + MagicMock(uuid='9eae1adb-9d0d-48c5-a6e7-ae93f0ea37b0'), + ] ble = MagicMock() ble.is_connected = False ble.get_characteristics = AsyncMock(side_effect=get_characteristics) + ble.get_services = AsyncMock(return_value=mock_services) ble.ensure_connected = AsyncMock() ble.read_characteristic = read_crx return ble @@ -45,7 +49,7 @@ async def test_after_connecting_device_loads_settings_ble_characteristics(mock_b assert Method(mock_ble.get_characteristics).was_called_with('f6d75f91-5a10-4eba-a233-47d3f26a907f') @pytest.mark.asyncio -async def test_read_all_settings_from_v2_21(mock_ble, mocked_settings): +async def test_read_all_settings_from_v2_21beta1(mock_ble, mocked_settings): with patch('pinecil_ble.BLE', return_value=mock_ble): pinecil = Pinecil() await pinecil.connect() @@ -124,6 +128,9 @@ async def test_reading_live_data_while_disconnected_reconnects(mock_ble): def test_read_all_settings_from_v2_20(): pass +def test_read_all_settings_from_v2_21beta2(): + pass + def test_update_one_setting_at_a_time(): pass