diff --git a/custom_components/icloud3/ChangeLog.txt b/custom_components/icloud3/ChangeLog.txt index 9195333..e00e084 100644 --- a/custom_components/icloud3/ChangeLog.txt +++ b/custom_components/icloud3/ChangeLog.txt @@ -1,20 +1,30 @@ -rc7.1 - Release Candidate 7.1 (10/15/2023) +rc8 - 10/25/2023 +............................... +1. Configure Settings - Made the following changes: + 1. Minor text changes to field names and screens. + 2. Improved the error messages when experiencing a problem logging into the iCloud Account. + 3. Fixed a bug when selecting the Enter Verification Code screen before logging into the iCloud account. +2. Old Location Error Notifications - Fixed a problem where Old Location notifications were constantly being sent to a phone when the maximum number of old location errors (20) had been encountered. +3. iOSApp Location Time - If the location time is older than 3-hours, it's age is displayed (4.5 hrs ago) instead of the time (6:15:00p). + +rc7.1/rc7.1.1 - 10/15/2023 ............................... 1. Zone-Device Count bug fix - Fixed a bug where the device counts were not being displayed correctly. 2. Exit Zone for Devices without the iOSApp (Watch) - When a Device exits a zone, all other devices that were in the same zone that do not have the iOS App installed will be updated immediately. They were being updated when their next update timer was reached. Hopefully, this will make Watch zone exit updates to be done when they happen. 3. Apple account password - When iCloud3 starts, the password is checked to see if it is encoded in the configuration parameter file. If it is not and it should be, it will be encoded and the configuration file will be updated. Previously, there were times when the file was not being updated. 4. iCloud Account username/password changes - When the username/password is changed, the Apple account is logged into. If you select 'Save' the configuration file is updated. If you select 'Return', the updated username/password is not saved and the menu is displayed. This can lead to login problems the next time iCloud3 starts if you really wanted to save them but didn't. An additional Confirmation Screen is now displayed that lets you save them or not save them. -rc7 - Release Candidate 7 (10/15/2023) + +rc7 - 10/15/2023 ............................... 1. yaml Zones - Fixed a problem where zones configured using yaml were not being loaded when iCloud3 started. -2. Zone-Devices Count - New feature - The number of the devices within a zone is displayed with the tracking results on the Event Log. The counts are the numbers (x) after the zone name. For Example: +2. Stationary Zones - Minor changes to the handling of deleting a stationary zone when all devices had exited from it. +3. Zone-Devices Count - New feature - The number of the devices within a zone is displayed with the tracking results on the Event Log. The counts are the numbers (x) after the zone name. For Example: _Zone > Away (2) > Home-2.45km, IndRivShores-6.53km, School-8.47km (1), Publix-10.3km, ThePoint-11.0km, Quail-12.0km, Warehouse-16.5km (1), GPS-(/±47m)_ An item is also posted to the Event Log when another device changes it's zone: _Zone-Device Counts > Home (4), School (1), Warehouse (1)_ -3. Stationary Zones - Minor changes to the handling of deleting a stationary zone when all devices had exited from it. rc6 - Release Candidate 6 (10/7/2023) ............................... diff --git a/custom_components/icloud3/config_flow.py b/custom_components/icloud3/config_flow.py index 5e689c7..8eeaa67 100644 --- a/custom_components/icloud3/config_flow.py +++ b/custom_components/icloud3/config_flow.py @@ -106,23 +106,25 @@ def dict_value_to_list(key_value_dict): return value_list #----------------------------------------------------------------------------------------- MENU_KEY_TEXT = { - 'icloud_account': 'iCLOUD ACCOUNT & iOS APP ᐳ –Set iCloud Account Username/Password, –Set Location Data Sources', - 'device_list': 'ICLOUD3 DEVICES ᐳ –Add, Change and Delete tracked and monitored devices', - 'verification_code': 'ENTER/REQUEST AN APPLE ID VERIFICATION CODE ᐳ –Enter or Request the 6-digit Apple ID Verification Code', - 'change_device_order': 'CHANGE DEVICE ORDER ᐳ –Change the tracking order of the Devices and their display sequence on the Event Log', - 'sensors': 'SENSORS ᐳ –Set Sensors created by iCloud3, –Exclude Specific Sensors from being created', - 'actions': 'ACTION COMMANDS ᐳ –Restart/Pause/Resume Polling, –Debug Logging, –Export Event Log, –Waze Utilities', - - 'format_settings': 'FORMAT SETTINGS ᐳ –Log Level, –Zones Display Format, –DeviceTracker State, –Unit of Measure, –Time & Distance, Display GPS Coordinates', - 'display_text_as': 'DISPLAY TEXT AS ᐳ –Event Log Custom Card Text Replacement', - 'waze': 'WAZE ROUTE DISTANCE, TIME & HISTORY ᐳ –Set Route Server Location, Min/Max Intervals, etc. –Set Waze History Database Parameters and Controls', - 'inzone_intervals': 'INZONE DEFAULT INTERVALS ᐳ –Default inZone intervals for different device types and the iOS App, –Other inZone Controls ', - 'special_zones': 'SPECIAL ZONES ᐳ –Enter Zone Delay, –Stationary Zone, –Track From Zone', - 'tracking_parameters': 'TRACKING & OTHER PARAMETERS ᐳ –Set Nearby Device Info, Accuracy Thresholds & Other Location Request Intervals, –Set Event Log Custom Card Directory, etc.', + 'icloud_account': 'iCLOUD ACCOUNT & iOS APP ᐳ •Set iCloud Account Username/Password, •Set Location Data Sources', + # 'icloud_account': 'iCLOUD ACCOUNT & iOS APP ᐳ •Set iCloud Account Username/Password, •Set Location Data Sources', + 'device_list': 'ICLOUD3 DEVICES ᐳ •Add, Change and Delete tracked and monitored devices', + # 'device_list': 'ICLOUD3 DEVICES ᐳ •Add, Change and Delete tracked and monitored devices', + 'verification_code': 'ENTER/REQUEST AN APPLE ID VERIFICATION CODE ᐳ •Enter or Request the 6-digit Apple ID Verification Code', + 'change_device_order': 'CHANGE DEVICE ORDER ᐳ •Change the tracking order of the Devices and their display sequence on the Event Log', + 'sensors': 'SENSORS ᐳ •Set Sensors created by iCloud3, •Exclude Specific Sensors from being created', + 'actions': 'ACTION COMMANDS ᐳ •Restart/Pause/Resume Polling, •Debug Logging, •Export Event Log, •Waze Utilities', + + 'format_settings': 'FORMAT SETTINGS ᐳ •Log Level, •Zones Display Format, •DeviceTracker State, •Unit of Measure, •Time & Distance, Display GPS Coordinates', + 'display_text_as': 'DISPLAY TEXT AS ᐳ •Event Log Custom Card Text Replacement', + 'waze': 'WAZE ROUTE DISTANCE, TIME & HISTORY ᐳ •Set Route Server Location, Min/Max Intervals, etc. •Set Waze History Database Parameters and Controls', + 'inzone_intervals': 'INZONE DEFAULT INTERVALS ᐳ •Default inZone intervals for different device types and the iOS App, •Other inZone Controls ', + 'special_zones': 'SPECIAL ZONES ᐳ •Enter Zone Delay, •Stationary Zone, •Track From Zone', + 'tracking_parameters': 'TRACKING & OTHER PARAMETERS ᐳ •Set Nearby Device Info, Accuracy Thresholds & Other Location Request Intervals, •Set Event Log Custom Card Directory, etc.', 'select': 'SELECT ᐳ Select the parameter update form', - 'next_page_0': 'PAGE 1, DEVICES & SENSORS ᐳ –iCloud Account & iOS App, –iCloud3 Devices, –Enter & Request Verification Code, –Change Device Order, –Sensors, –Action Commands', - 'next_page_1': 'PAGE 2, GENERAL PARAMETERS ᐳ –Format Parameters, –Display Text As, –Waze Route Distance, Time & History, –inZone Intervals, –Special Zones, – Other Parameters', + 'next_page_0': 'PAGE 1, DEVICES & SENSORS ᐳ •iCloud Account & iOS App, •iCloud3 Devices, •Enter & Request Verification Code, •Change Device Order, •Sensors, •Action Commands', + 'next_page_1': 'PAGE 2, GENERAL PARAMETERS ᐳ •Format Parameters, •Display Text As, •Waze Route Distance, Time & History, •inZone Intervals, •Special Zones, • Other Parameters', 'exit': f'EXIT AND RESTART ICLOUD3 {".. "*22}(Version: {Gb.version})' } MENU_PAGE_0_INITIAL_ITEM = 1 @@ -169,9 +171,9 @@ def dict_value_to_list(key_value_dict): 'delete_device': 'DELETE DEVICE(S), OTHER DEVICE MAINTENANCE ᐳ Delete the device(s) from the tracked device list, clear the FamShr/FmF/iOS App selection fields', 'change_device_order': 'CHANGE DEVICE ORDER ᐳ Change the tracking order of the Devices and their display sequence on the Event Log', - 'delete_this_device': 'DELETE THIS DEVICE ᐳ Delete this device from the iCloud3 tracked devices list', + 'delete_this_device': 'DELETE THIS DEVICE ᐳ Delete this device → ', 'delete_all_devices': 'DELETE ALL DEVICES ᐳ Delete all devices from the iCloud3 tracked devices list', - 'delete_icloud_iosapp_info':'CLEAR FAMSHR/FMF/IOSAPP INFO ᐳ Reset the FamShr/FmF/iOS App seletion fields on all devices', + 'delete_icloud_iosapp_info':'CLEAR FAMSHR/IOSAPP INFO ᐳ Reset the FamShr/iOS App seletion fields on all devices', 'delete_device_cancel': 'CANCEL ᐳ Return to the Device List screen', 'inactive_to_track': 'TRACK ALL OR SELECTED ᐳ Change the \'Tracking Mode\' of all of the devices (or the selected devices) from \'Inactive\' to \Tracked\'', @@ -193,7 +195,7 @@ def dict_value_to_list(key_value_dict): 'move_down': 'MOVE DOWN ᐳ Move the Device down in the list', 'save': 'SAVE ᐳ Update Configuration File, Return to the menu screen', - 'cancel': 'RETURN ᐳ Return to the previous screen. Cancel any changes that are not already saved', + 'cancel': 'RETURN ᐳ Return to the previous screen. Cancel any unsaved changes', 'exit': 'EXIT ᐳ Exit the iCloud3 Configurator', 'return': 'RETURN ᐳ Return to the Main Menu', @@ -410,6 +412,29 @@ def dict_value_to_list(key_value_dict): for key, text in ACTIONS_SCREEN_ITEMS_KEY_TEXT.items() if key.startswith('divider') is False} +ACTIONS_IC3_ITEMS = { + "restart": "RESTART ᐳ Restart iCloud3", + "pause": "PAUSE ᐳ Pause polling on all devices", + "resume": "RESUME ᐳ Resume Polling on all devices, Refresh all locations", +} +ACTIONS_DEBUG_ITEMS = { + "debug_start": "START DEBUG LOGGING ᐳ Start or stop debug logging", + "debug_stop": "STOP DEBUG LOGGING ᐳ Start or stop debug logging", + "rawdata_start": "START RAWDATA LOGGING ᐳ Start or stop debug rawdata logging", + "rawdata_stop": "STOP RAWDATA LOGGING ᐳ Start or stop debug rawdata logging", + "commit": "COMMIT DEBUG LOG RECORDS ᐳ Verify all debug log file records are written", +} +ACTIONS_OTHER_ITEMS = { + "evlog_export": "EXPORT EVENT LOG ᐳ Export Event Log data", + "wazehist_maint": "WAZE HIST DATABASE ᐳ Recalc time/distance data at midnight", + "wazehist_track": "WAZE HIST MAP TRACK ᐳ Load route locations for map display", +} +ACTIONS_ACTION_ITEMS = { + "restart_ha": "RESTART HA, RELOAD ICLOUD3 ᐳ Restart HA or Reload iCloud3", + "return": "MAIN MENU ᐳ Return to the Main Menu" +} + + WAZE_USED_HEADER = ("The Waze Route Service provides the travel time and distance information from your " "current location to the Home or another tracked from zone. This information is used to determine " "when the next location request should be made") @@ -1558,40 +1583,41 @@ async def async_step_actions(self, user_input=None, errors=None): # Get key for item selected ("RESTART" --> "restart") and then # process the requested action - if instr(user_input.get('action_items'), ' >'): - action_item_text = user_input['action_items'] - action_item = ACTIONS_SCREEN_ITEMS_KEY_BY_TEXT[action_item_text] - user_input.pop('action_items') - - # await self._process_action_request(action_item) - if action_item == 'return': - return await self.async_step_menu() + if user_input['action_items']: + action_item =user_input['action_items'][0] + elif user_input['ic3_actions']: + action_item = user_input['ic3_actions'][0] + elif user_input['debug_actions']: + action_item = user_input['debug_actions'][0] + elif user_input['other_actions']: + action_item = user_input['other_actions'][0] + else: + action_item = 'return' - elif action_item in [ 'restart', 'pause', 'resume', - 'wazehist_maint', 'wazehist_track', - 'evlog_export', ]: - service_handler.update_service_handler(action_item) + if action_item == 'return': + return await self.async_step_menu() - elif action_item.startswith('debug'): - service_handler.handle_action_log_level('debug', change_conf_log_level=False) + elif action_item in [ 'restart', 'pause', 'resume', + 'wazehist_maint', 'wazehist_track', + 'evlog_export', ]: + service_handler.update_service_handler(action_item) - elif action_item.startswith('rawdata'): - service_handler.handle_action_log_level('rawdata', change_conf_log_level=False) + elif action_item.startswith('debug'): + service_handler.handle_action_log_level('debug', change_conf_log_level=False) - elif action_item == 'commit': - close_reopen_ic3_log_file(closed_by='Configurator') + elif action_item.startswith('rawdata'): + service_handler.handle_action_log_level('rawdata', change_conf_log_level=False) - elif action_item == 'restart_ha': - return await self.async_step_restart_ha_ic3() + elif action_item == 'commit': + close_reopen_ic3_log_file(closed_by='Configurator') - if self.header_msg is None: - self.header_msg = 'action_completed' + elif action_item == 'restart_ha': + return await self.async_step_restart_ha_ic3() - return await self.async_step_menu() + if self.header_msg is None: + self.header_msg = 'action_completed' - return self.async_show_form(step_id=self.step_id, - data_schema=self.form_schema(self.step_id), - errors=self.errors) + return await self.async_step_menu() #-------------------------------------------------------------------------------- async def _process_action_request(self, action_item): @@ -1653,7 +1679,7 @@ async def async_restart_ha_ic3(self, user_input, errors): await Gb.hass.services.async_call( "homeassistant", "reload_config_entry", - {'device_id': Gb.dr_device_id_by_devicename[ICLOUD3]}, + {'device_id': Gb.ha_device_id_by_devicename[ICLOUD3]}, ) # {"entry_id": Gb.entry_id} @@ -1961,6 +1987,7 @@ async def async_step_icloud_account(self, user_input=None, errors=None, called_f user_input, action_item = self._action_text_to_item(user_input) user_input = self._strip_spaces(user_input, [CONF_USERNAME, CONF_PASSWORD]) user_input = self._strip_spaces(user_input) + user_input['endpoint_suffix'] = 'cn' if user_input['url_suffix_china'] is True else 'None' log_user_input = user_input.copy() if CONF_USERNAME in log_user_input: log_user_input[CONF_USERNAME] = obscure_field(log_user_input[CONF_USERNAME]) @@ -1968,7 +1995,6 @@ async def async_step_icloud_account(self, user_input=None, errors=None, called_f log_debug_msg(f"{self.step_id} ({action_item}) > UserInput-{log_user_input}, Errors-{errors}") if action_item == 'confirm_save': - # user_input = self.user_input_multi_form action_item = 'save' elif action_item == 'confirm_return': @@ -1977,11 +2003,11 @@ async def async_step_icloud_account(self, user_input=None, errors=None, called_f elif action_item == 'cancel': if (Gb.username != user_input[CONF_USERNAME] or Gb.password != user_input[CONF_PASSWORD] - or Gb.icloud_server_endpoint_suffix != user_input['url_suffix_china']): + or Gb.icloud_server_endpoint_suffix != user_input['endpoint_suffix']): self.user_input_multi_form = user_input.copy() return await self.async_step_confirm_action(user_input, - action_items = ['confirm_return','confirm_save'], + action_items = ['confirm_save', 'confirm_return'], called_from_step_id='icloud_account') return await self.async_step_menu() @@ -1992,7 +2018,10 @@ async def async_step_icloud_account(self, user_input=None, errors=None, called_f return await self.async_step_menu() if action_item == 'verification_code': - return await self.async_step_reauth(called_from_step_id='icloud_account') + if self.PyiCloud or Gb.PyiCloud: + return await self.async_step_reauth(called_from_step_id='icloud_account') + else: + action_item = 'login_icloud_account' if user_input[CONF_USERNAME] == '': self.errors[CONF_USERNAME] = 'required_field' @@ -2011,8 +2040,6 @@ async def async_step_icloud_account(self, user_input=None, errors=None, called_f Gb.conf_data_source_FMF = instr(user_input[CONF_DATA_SOURCE], FMF) Gb.primary_data_source_ICLOUD = Gb.conf_data_source_FAMSHR or Gb.conf_data_source_FMF - user_input['endpoint_suffix'] = 'cn' if user_input['url_suffix_china'] is True else 'None' - # Action Login or Save will login into the account if the username changed if (action_item in ['login_icloud_account', 'save']): @@ -2095,10 +2122,13 @@ async def async_step_reauth(self, user_input=None, errors=None, called_from_step user_input, action_item = self._action_text_to_item(user_input) log_debug_msg(f"{self.step_id} ({action_item}) > UserInput-{user_input}, Errors-{errors}") - if self.username == Gb.PyiCloud.username and self.password == Gb.PyiCloud.password: + if Gb.PyiCloud and self.username == Gb.PyiCloud.username and self.password == Gb.PyiCloud.password: PyiCloud = Gb.PyiCloud - else: + elif self.PyiCloud: PyiCloud = self.PyiCloud + else: + self.errors = 'icloud_acct_not_logged_into' + action_item = 'cancel' if action_item == 'send_verification_code' and user_input.get(CONF_VERIFICATION_CODE, '') == '': action_item = 'cancel' @@ -2218,8 +2248,10 @@ async def _log_into_icloud_account(self, user_input, called_from_step_id=None, r event_msg = f"{EVLOG_NOTICE}Requesting Apple ID Verification Code" else: event_msg =(f"{EVLOG_NOTICE}Logging into iCloud Account with Configure Settings, " - f"{CRLF_DOT}New iCloud Account > {obscure_field(self.username)}, " - f"{CRLF_DOT}iCloud Account Currently Used > {obscure_field(Gb.username)}") + f"{CRLF_DOT}iCloud Account Currently Used > {obscure_field(Gb.username)}" + f"{CRLF_DOT}New iCloud Account > {obscure_field(self.username)}") + if self.endpoint_suffix != 'None': + event_msg += f", AppleServerURLSuffix-{self.endpoint_suffix}" post_event(event_msg) try: @@ -2234,13 +2266,20 @@ async def _log_into_icloud_account(self, user_input, called_from_step_id=None, r except (PyiCloudFailedLoginException) as err: + err = str(err) + self.PyiCloud = None self.endpoint_suffix = Gb.icloud_server_endpoint_suffix = \ Gb.conf_tracking[CONF_ICLOUD_SERVER_ENDPOINT_SUFFIX] if called_from_step_id == 'icloud_account': - error_msg = 'icloud_acct_login_error' + if err.endswith('302'): + error_msg = 'icloud_acct_login_error_connection' + elif err.endswith('400'): + error_msg = 'icloud_acct_login_error_user_pw' + else: + error_msg = 'icloud_acct_login_error_other' else: - error_msg = 'icloud_acct_not_available' + error_msg = 'icloud_acct_login_error_other' self.errors = {'base': error_msg} _CF_LOGGER.error(f"Error logging into iCloud service: {err}") @@ -3534,14 +3573,15 @@ def _action_text_to_item(self, user_input): elif 'action_items' in user_input: action_text = user_input['action_items'] - if action_text.startswith('NEXT PAGE ITEMS > '): + + if action_text.startswith('NEXT PAGE ITEMS'): action_item = 'next_page_items' else: action_text_len = 25 if len(action_text) > 25 else len(action_text) action_item = [k for k, v in ACTION_LIST_ITEMS_KEY_TEXT.items() if v.startswith(action_text[:action_text_len])][0] - user_input.pop('action_items') - + if 'actions_items' in user_input: + user_input.pop('action_items') else: action_item = None @@ -3882,7 +3922,7 @@ def form_schema(self, step_id, actions_list=None, actions_list_default=None): #------------------------------------------------------------------------ elif step_id.startswith('confirm_action'): - actions_list_default = actions_list_default or self.actions_list[-1] + actions_list_default = actions_list_default or self.actions_list[0] return vol.Schema({ vol.Required('action_items', @@ -4184,12 +4224,11 @@ def form_schema(self, step_id, actions_list=None, actions_list_default=None): #------------------------------------------------------------------------ elif step_id == 'delete_device': self.actions_list = DELETE_DEVICE_ACTIONS.copy() - device_info = ( f"Delete this device (" - f"{self.conf_device_selected[CONF_IC3_DEVICENAME]}, " - f"{self.conf_device_selected[CONF_FNAME]})") + device_info = ( f"{self.conf_device_selected[CONF_IC3_DEVICENAME]}, " + f"{self.conf_device_selected[CONF_FNAME]}") # The first item is 'Delete this device, add the selected device's info - self.actions_list[0] = self.actions_list[0].replace('Delete this device', device_info) + self.actions_list[0] = f"{self.actions_list[0]}{device_info}" return vol.Schema({ vol.Required('action_items', @@ -4200,28 +4239,36 @@ def form_schema(self, step_id, actions_list=None, actions_list_default=None): #------------------------------------------------------------------------ elif step_id == 'actions': - action_screen_items_key_text = ACTIONS_SCREEN_ITEMS_KEY_TEXT.copy() + debug_items_key_text = ACTIONS_DEBUG_ITEMS.copy() if Gb.log_debug_flag: - action_screen_items_key_text.pop('debug_start') + debug_items_key_text.pop('debug_start') else: - action_screen_items_key_text.pop('debug_stop') + debug_items_key_text.pop('debug_stop') if Gb.log_rawdata_flag: - action_screen_items_key_text.pop('rawdata_start') + debug_items_key_text.pop('rawdata_start') else: - action_screen_items_key_text.pop('rawdata_stop') - self.actions_list = [text for text in action_screen_items_key_text.values()] + debug_items_key_text.pop('rawdata_stop') return vol.Schema({ - vol.Required('action_items', - default=self.action_default_text('return', action_itemss_key_text=action_screen_items_key_text)): - selector.SelectSelector(selector.SelectSelectorConfig( - options=self.actions_list, mode='list')), + vol.Optional('ic3_actions', default=[]): + cv.multi_select(ACTIONS_IC3_ITEMS), + # selector.SelectSelector(selector.SelectSelectorConfig( + # options=dict_value_to_list(ACTIONS_IC3_ITEMS), mode='list')), + vol.Optional('debug_actions', default=[]): + cv.multi_select(debug_items_key_text), + # selector.SelectSelector(selector.SelectSelectorConfig( + # options=dict_value_to_list(debug_items_key_text), mode='list')), + vol.Optional('other_actions', default=[]): + cv.multi_select(ACTIONS_OTHER_ITEMS), + # selector.SelectSelector(selector.SelectSelectorConfig( + # options=dict_value_to_list(ACTIONS_OTHER_ITEMS), mode='list')), + vol.Optional('action_items', default=[]): + cv.multi_select(ACTIONS_ACTION_ITEMS), + # selector.SelectSelector(selector.SelectSelectorConfig( + # options=dict_value_to_list(ACTIONS_ACTION_ITEMS), mode='list')), }) #------------------------------------------------------------------------ elif step_id == 'format_settings': - # self.actions_list = [ACTION_LIST_ITEMS_KEY_TEXT['change_device_order']] - # self.actions_list.extend(ACTION_LIST_ITEMS_BASE) - self._set_example_zone_name() return vol.Schema({ vol.Required(CONF_LOG_LEVEL, diff --git a/custom_components/icloud3/const.py b/custom_components/icloud3/const.py index 81737ff..6a7c6b3 100644 --- a/custom_components/icloud3/const.py +++ b/custom_components/icloud3/const.py @@ -4,7 +4,7 @@ # #<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -VERSION = '3.0.rc7.1' +VERSION = '3.0.rc8' DOMAIN = 'icloud3' ICLOUD3 = 'iCloud3' diff --git a/custom_components/icloud3/device.py b/custom_components/icloud3/device.py index 18076e2..ab1f53f 100644 --- a/custom_components/icloud3/device.py +++ b/custom_components/icloud3/device.py @@ -79,7 +79,7 @@ class iCloud3_Device(TrackerEntity): def __init__(self, devicename, conf_device): self.conf_device = conf_device self.devicename = devicename - self.dr_device_id = '' # ha device_registry device_id + self.ha_device_id = '' # ha device_registry device_id self.fname = devicename.title() self.StatZone = None # The StatZone this Device is in or None if not in a StatZone @@ -149,6 +149,8 @@ def initialize(self): # Trigger & Update variables self.trigger = 'iCloud3' + self.interval_secs = 0 + self.interval_str = '' self.next_update_secs = 0 self.seen_this_device_flag = False self.iosapp_zone_enter_secs = 0 @@ -430,8 +432,8 @@ def _link_device_entities_sensor_device_tracker(self): self.DeviceTracker = Gb.DeviceTrackers_by_devicename[self.devicename] self.DeviceTracker.Device = self try: - self.DeviceTracker.device_id = Gb.dr_device_id_by_devicename[self.devicename] - self.DeviceTracker.area_id = Gb.dr_area_id_by_devicename[self.devicename] + self.DeviceTracker.device_id = Gb.ha_device_id_by_devicename[self.devicename] + self.DeviceTracker.area_id = Gb.ha_area_id_by_devicename[self.devicename] except: pass diff --git a/custom_components/icloud3/device_tracker.py b/custom_components/icloud3/device_tracker.py index 8ac7b69..2161cb6 100644 --- a/custom_components/icloud3/device_tracker.py +++ b/custom_components/icloud3/device_tracker.py @@ -78,10 +78,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e area_reg = ar.async_get(hass) Gb.area_id_personal_device = area_reg.async_get_or_create('Personal Device').id - _get_dr_device_ids_from_device_registry(hass) + _get_ha_device_ids_from_device_registry(hass) - if (ICLOUD3 in Gb.dr_area_id_by_devicename - and Gb.dr_area_id_by_devicename[ICLOUD3] in [None, 'unknown', '']): + if (ICLOUD3 in Gb.ha_area_id_by_devicename + and Gb.ha_area_id_by_devicename[ICLOUD3] in [None, 'unknown', '']): _update_icloud3_integration_area_id() except Exception as err: @@ -111,11 +111,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e if NewDeviceTrackers != []: async_add_entities(NewDeviceTrackers, True) - _get_dr_device_ids_from_device_registry(hass) + _get_ha_device_ids_from_device_registry(hass) _HA_LOGGER.info(f"iCloud3 Device Tracker entities: {Gb.device_trackers_cnt}") Devices_no_area = [Device for Device in Gb.DeviceTrackers_by_devicename.values() \ - if Device.dr_area_id in [None, 'unknown', '']] + if Device.ha_area_id in [None, 'unknown', '']] if Devices_no_area != []: for Device in Devices_no_area: @@ -131,7 +131,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e log_error_msg(log_msg) #------------------------------------------------------------------------------------------- -def _get_dr_device_ids_from_device_registry(hass): +def _get_ha_device_ids_from_device_registry(hass): ''' Cycle thru the ha device registry, extract the iCloud3 entries and associate the ha device_id with the ic3_devicename parameters @@ -144,12 +144,12 @@ def _get_dr_device_ids_from_device_registry(hass): icloud3_dev_reg = {device: device_entry for device, device_entry in dev_reg.deleted_devices.items() if _icloud3_dev_reg_item(device_entry)} for device, device_entry in icloud3_dev_reg.items(): - _get_dr_device_id_from_device_entry(hass, device, device_entry) + _get_ha_device_id_from_device_entry(hass, device, device_entry) icloud3_dev_reg = {device: device_entry for device, device_entry in dev_reg.devices.items() if _icloud3_dev_reg_item(device_entry)} for device, device_entry in icloud3_dev_reg.items(): - _get_dr_device_id_from_device_entry(hass, device, device_entry) + _get_ha_device_id_from_device_entry(hass, device, device_entry) except Exception as err: log_exception(err) @@ -167,7 +167,7 @@ def _icloud3_dev_reg_item(device_entry): return False #------------------------------------------------------------------------------------------- -def _get_dr_device_id_from_device_entry(hass, device, device_entry): +def _get_ha_device_id_from_device_entry(hass, device, device_entry): ''' For each entry in the device registry, determine if it is an iCloud3 entry (iCloud3 is in the device_entry.identifiers field. If so, check the other items, determine if one is a @@ -188,8 +188,8 @@ def _get_dr_device_id_from_device_entry(hass, device, device_entry): ''' try: if device_entry.name in [DOMAIN, ICLOUD3, 'iCloud3 Integration']: - Gb.dr_device_id_by_devicename[ICLOUD3] = device_entry.id - Gb.dr_area_id_by_devicename[ICLOUD3] = device_entry.area_id + Gb.ha_device_id_by_devicename[ICLOUD3] = device_entry.id + Gb.ha_area_id_by_devicename[ICLOUD3] = device_entry.area_id return except: pass @@ -200,8 +200,8 @@ def _get_dr_device_id_from_device_entry(hass, device, device_entry): for item in de_identifiers: if item in Gb.conf_devicenames: - Gb.dr_device_id_by_devicename[item] = device_entry.id - Gb.dr_area_id_by_devicename[item] = device_entry.area_id + Gb.ha_device_id_by_devicename[item] = device_entry.id + Gb.ha_area_id_by_devicename[item] = device_entry.area_id return except Exception as err: @@ -214,11 +214,11 @@ def _update_icloud3_integration_area_id(): try: kwargs = {} kwargs['area_id'] = Gb.area_id_personal_device - Gb.dr_area_id_by_devicename[ICLOUD3] = Gb.area_id_personal_device + Gb.ha_area_id_by_devicename[ICLOUD3] = Gb.area_id_personal_device - device_id = Gb.dr_device_id_by_devicename[ICLOUD3] + ha_device_id = Gb.ha_device_id_by_devicename[ICLOUD3] device_registry = dr.async_get(Gb.hass) - dr_entry = device_registry.async_update_device(device_id, **kwargs) + dr_entry = device_registry.async_update_device(ha_device_id, **kwargs) log_debug_msg( "Device Tracker entity changed: device_tracker.icloud3, " "iCloud3, Personal Device") @@ -238,9 +238,9 @@ def __init__(self, devicename, conf_device, data=None): self.devicename = devicename self.Device = None # Filled in after Device object has been created in start_ic3 self.entity_id = f"device_tracker.{devicename}" - self.dr_device_id = Gb.dr_device_id_by_devicename.get(self.devicename) - self.dr_area_id = Gb.dr_area_id_by_devicename.get(self.devicename) - # if self.dr_area_id in ['unknown', '']: self_area_id = None + self.ha_device_id = Gb.ha_device_id_by_devicename.get(self.devicename) + self.ha_area_id = Gb.ha_area_id_by_devicename.get(self.devicename) + # if self.ha_area_id in ['unknown', '']: self_area_id = None self.device_fname = conf_device[FNAME] self.device_type = conf_device[CONF_DEVICE_TYPE] @@ -298,8 +298,8 @@ def get_device_id(self): @property def get_area_id(self): """Return the area_id of the device.""" - # if self.dr_area_id is None: - # self.dr_area_id = Gb.dr_area_id_by_devicename[self.devicename] = \ + # if self.ha_area_id is None: + # self.ha_area_id = Gb.ha_area_id_by_devicename[self.devicename] = \ # Gb.area_id_personal_device return self.area_id @@ -479,22 +479,22 @@ def _get_attribute_value(self, attribute): def update_entity_attribute(self, new_fname=None, area_id=None): """ Update entity definition attributes """ - device_id = Gb.dr_device_id_by_devicename.get(self.devicename) - if device_id is None: + ha_device_id = Gb.ha_device_id_by_devicename.get(self.devicename) + if ha_device_id is None: return if new_fname is None and area_id is None: return try: - area_id = area_id or self.dr_area_id or Gb.area_id_personal_device + area_id = area_id or self.ha_area_id or Gb.area_id_personal_device area_reg = ar.async_get(Gb.hass) area_name = area_reg.async_get_area(area_id).name except: area_id = area_name = None self.device_fname = new_fname or self.device_fname - self.dr_area_id = Gb.dr_area_id_by_devicename[self.devicename] = \ + self.ha_area_id = Gb.ha_area_id_by_devicename[self.devicename] = \ area_id log_debug_msg(f"Device Tracker entity changed: device_tracker.{self.devicename}, " @@ -533,10 +533,10 @@ def update_entity_attribute(self, new_fname=None, area_id=None): kwargs = {} kwargs['name'] = f"{self.device_fname} ({self.devicename})" kwargs['name_by_user'] = "" - kwargs['area_id'] = self.dr_area_id + kwargs['area_id'] = self.ha_area_id device_registry = dr.async_get(Gb.hass) - dr_entry = device_registry.async_update_device(self.dr_device_id, **kwargs) + dr_entry = device_registry.async_update_device(self.ha_device_id, **kwargs) #------------------------------------------------------------------------------------------- def remove_device_tracker(self): diff --git a/custom_components/icloud3/global_variables.py b/custom_components/icloud3/global_variables.py index 933363f..7eb0d1c 100644 --- a/custom_components/icloud3/global_variables.py +++ b/custom_components/icloud3/global_variables.py @@ -147,8 +147,8 @@ class GlobalVariables(object): Sensors_by_devicename = {} # HA sensor.[devicename]_[sensor_name]_[from_zone] objects Sensors_by_devicename_from_zone = {} # HA sensor.[devicename]_[sensor_name]_[from_zone] objects Sensor_EventLog = None # Event Log sensor object - dr_device_id_by_devicename = {} # HA device_registry device_id - dr_area_id_by_devicename = {} # HA device_registry area_id + ha_device_id_by_devicename = {} # HA device_registry device_id + ha_area_id_by_devicename = {} # HA device_registry area_id # Event Log operational fields evlog_card_directory = '' diff --git a/custom_components/icloud3/helpers/time_util.py b/custom_components/icloud3/helpers/time_util.py index f4fcbe3..124288f 100644 --- a/custom_components/icloud3/helpers/time_util.py +++ b/custom_components/icloud3/helpers/time_util.py @@ -72,6 +72,13 @@ def secs_to_time_str(secs): return time_str +#-------------------------------------------------------------------- +def secs_to_hrs_str(secs): + if secs < 1: + return '0 hrs' + else: + return f"{secs/3600:.1f} hrs" + #-------------------------------------------------------------------- def mins_to_time_str(mins): """ Create the time string from seconds """ @@ -446,6 +453,10 @@ def format_age(secs): return f"{secs_to_time_str(secs)} ago" +#-------------------------------------------------------------------- +def format_age_hrs(secs): + return f"{secs_to_hrs_str(secs_since(secs))} ago" + #-------------------------------------------------------------------- def format_age_ts(time_secs): if time_secs < 1: diff --git a/custom_components/icloud3/icloud3_main.py b/custom_components/icloud3/icloud3_main.py index c600be4..68c1730 100644 --- a/custom_components/icloud3/icloud3_main.py +++ b/custom_components/icloud3/icloud3_main.py @@ -371,7 +371,7 @@ def _main_5sec_loop_update_tracked_devices_iosapp(self, Device): post_event(devicename, event_msg) return - # If the iOS App is the primary data source next_update time is reached, get the + # If the iOS App is the primary and data source next_update time is reached, get the # old location threshold. Send a location request to the iosapp device if the # data is older than the threshold, the next_update is newer than the iosapp data # and the next_update and data time is after the last request was sent. @@ -407,7 +407,9 @@ def _main_5sec_loop_update_tracked_devices_iosapp(self, Device): event_msg = f"Trigger > {Device.iosapp_data_change_reason}" post_event(devicename, event_msg) - # If entering a zone, check the passthru time, exit if it is now set + # If using the passthru zone delay: + # If entering a zone, set it if it is not set + # If exiting, reset it if Gb.is_passthru_zone_used: if instr(Device.iosapp_data_change_reason, ENTER_ZONE): if Device.set_passthru_zone_delay(IOSAPP, diff --git a/custom_components/icloud3/sensor.py b/custom_components/icloud3/sensor.py index 0c57a85..920b6dd 100644 --- a/custom_components/icloud3/sensor.py +++ b/custom_components/icloud3/sensor.py @@ -410,7 +410,7 @@ def __init__(self, devicename, sensor_base, conf_device, from_zone=None): self.entity_name = f"{devicename}_{self.sensor}" self.entity_id = f"sensor.{self.entity_name}" - self.device_id = Gb.dr_device_id_by_devicename.get(ICLOUD3) + self.device_id = Gb.ha_device_id_by_devicename.get(ICLOUD3) self.Device = Gb.Devices_by_devicename.get(devicename) if self.Device and from_zone: @@ -1158,7 +1158,7 @@ def __init__(self, fname, entity_name): self.entity_id = f"sensor.{self.entity_name}" self._unsub_dispatcher = None self._device = DOMAIN - # self.ic3_device_id = Gb.ic3_device_id = Gb.dr_device_id_by_devicename.get(DOMAIN) + # self.ic3_device_id = Gb.ic3_device_id = Gb.ha_device_id_by_devicename.get(DOMAIN) self.current_state_value = '' self.history_exclude_flag = True diff --git a/custom_components/icloud3/strings.json b/custom_components/icloud3/strings.json index 0776d81..ecaec50 100644 --- a/custom_components/icloud3/strings.json +++ b/custom_components/icloud3/strings.json @@ -34,7 +34,7 @@ "description": "Enter the 6-digit verification code you just received from Apple", "data": { "verification_code": "ICLOUD ACCOUNT VERIFICATION CODE", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════" } }, "restart_ha": { @@ -62,10 +62,12 @@ "icloud_acct_logging_into": "Logging into iCloud Account", "icloud_acct_logged_into": "Successfully Logged into the iCloud Account", "icloud_acct_already_logged_into": "Already Logged into the iCloud Account", - "icloud_acct_login_error": "iCloud Account Login Failed - Review Username/Password (or China '.cn' suffix)", - "icloud_acct_not_available": "iCloud Account is not Available, Login Unsuccessful", + "icloud_acct_login_error_user_pw": "Login Failed, Invalid Username or Password (err-400)", + "icloud_acct_login_error_other": "Login Failed, Other Error or iCloud is not Available", + "icloud_acct_login_error_connection": "Login Error, Failed to Connect to iCloud Server (err-302)", + "icloud_acct_not_available": "Login Error, iCloud Account is not Available", "icloud_acct_not_logged_into": "iCloud Account is not Logged Into", - "icloud_acct_not_set_up": "The iCloud Account Username or Password needs to be entered", + "icloud_acct_not_set_up": "iCloud Account Username or Password needs to be entered", "icloud_acct_no_data_source": "No Data Source has been selected", "verification_code_requested": "The Apple ID Verification Code was requested, BROWSER REFRESH MAY BE NEEDED", @@ -131,7 +133,7 @@ "title": "iCloud3 Configure Settings", "data": { "menu_items": "", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════" } }, "restart_icloud3": { @@ -165,12 +167,12 @@ "title": "iCloud Account & iOS App Data Sources", "description": "The data sources (iCloud Account Web Services and the iOS App) are selected on this screen. The Apple iCloud Account Username/Password must be specified here to access the iCloud Account. The HA Companion App (iOS App) must be installed on the iDevice to use is as a data source for that device. Each iDevice you are tracking is associated with the iCloud3 device on the Update Devices screen.", "data": { - "data_source_icloud": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ ICLOUD ACCOUNT - Location data is provided by the Apple iCloud account", + "data_source_icloud": "═════════════════════════════════════════════════════ ICLOUD ACCOUNT - Location data is provided by the Apple iCloud account", "username": "APPLE ID (USERNAME) - The email address used to sign in to the iCloud Account", "password": "PASSWORD - The iCloud Account Password", "url_suffix_china": "CHINA USERS - Add '.cn' to use the Apple iCloud Web Servers located in China", - "data_source_iosapp": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ iOS APP - Location data is provided by the HA iOS App", - "action_items": "═══════════════════════════════════════════════════" + "data_source_iosapp": "═════════════════════════════════════════════════════ iOS APP - Location data is provided by the HA iOS App", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { } @@ -180,15 +182,15 @@ "description": "Enter the 6-digit verification code you just received from Apple", "data": { "verification_code": "ICLOUD ACCOUNT VERIFICATION CODE", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "device_list": { "title": "iCloud3 Device Tracker Entities", "description": "All of the devices that are tracked or monitored by iCloud3 are listed on this screen. You can add new devices and update or delete existing devices.", "data": { - "devices": "", - "action_items": "═══════════════════════════════════════════════════" + "devices": "═════════════════════════════════════════════════════ ICLOUD3 DEVICES", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "add_device": { @@ -199,7 +201,7 @@ "device_type": "DEVICE TYPE - iPhone, iPad, Watch, etc.", "tracking_mode": "TRACKING MODE - How location requests should be done (Full tracking, Monitor, Inactive)", "iosapp": "iOS APP INSTALLED - The HA iOS App is installed on this device ", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { } @@ -219,7 +221,7 @@ "track_from_base_zone": "PRIMARY HOME ZONE - Use another zone if you are away from Home for an extended period", "picture": "PICTURE - Photo image of the person normally using this device (40x40 pixels is best size)", "inzone_interval": "INZONE INTERVAL", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "inzone_interval": "Time between location requests when in a zone", @@ -229,22 +231,23 @@ "delete_device": { "title": "Delete Device(s), Other Device Maintenance", "data": { - "action_items": "" + "action_items": "═════════════════════════════════════════════════════ DELETE OPTIONS" } }, "review_inactive_devices": { "title": "Review Untracked (Inactive) Devices", "description": "The 'Tracking Mode' of devices are set to 'Inactive' and will not be located or tracked.", "data": { - "inactive_devices": "", - "action_items": "═══════════════════════════════════════════════════" + "inactive_devices": "═════════════════════════════════════════════════════ INACTIVE ICLOUD3 DEVICES", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "change_device_order": { "title": "Event Log Device Display Sequence", + "description": "The devices are displayed in the Event Log heading area and in various Event Log messages in the sequence below. This screen lets you change the order of the devices.", "data": { - "device_desc": "DEVICES - The devices are displayed in the Event Log heading area and in various Event Log messages in this sequence", - "action_items": "═══════════════════════════════════════════════════" + "device_desc": "═════════════════════════════════════════════════════ ICLOUD3 DEVICES", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "format_settings": { @@ -258,7 +261,7 @@ "unit_of_measurement": "UNIT OF MEASUREMENT - How distance fieldsare displayed in sensors and in the Event Log", "display_gps_lat_long": "DISPLAY GPS COORDINATES - Display the GPS (Latitude, Longitude/±Accuracy) or only the GPS (/±Accuracy) in the Event Log", "display_gps_lat_long2": "DISPLAY GPS COORDINATES - Display the GPS Latitude/Longitude/Accuracy (22.32771, -76.33073/±35m) or only the GPS accuracy (/±35m) in the Event Log", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "device_tracker_state_source": "HA uses the device's gps coordinates to determine the zone. The gps accuracy is not considered so the zone may be exited when the gps wanders out of the zone. iCloud3 does consider the gps accuracy and will not exit the zone when this occurs. iCloud3 will display the Zone's Friendly Name or zone name displayed on the Event Log." @@ -268,8 +271,8 @@ "title": "Event Log 'Display Text As'", "description": "There may be some text fields that are displayed on the Event Log screen that may be sensitive in nature. Some examples include email addresses or phone numbers. With this screen, you can select the Original Text and what should be displayed instead. For example, you can replace 'geekstergary@apple.com' with 'gary@email.com'", "data": { - "display_text_as": "Text Replacement Fields", - "action_items": "═══════════════════════════════════════════════════" + "display_text_as": "═════════════════════════════════════════════════════ TEXT REPLACEMENT FIELDS - [Actual text > Displayed text]", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "display_text_as_update": { @@ -277,7 +280,7 @@ "data": { "text_from": "ORIGINAL TEXT - Text to be replaced (example: gary_real_email@gmail.com)", "text_to": "DISPLAYED TEXT- Text to be displayed (display: gary@email.com)", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { } @@ -285,7 +288,10 @@ "actions": { "title": "iCloud3 Action Commands", "data": { - "action_items": "" + "ic3_actions": "═════════════════════════════════════════════════════ ICLOUD3 GENERAL CONTROL ACTIONS", + "debug_actions": "═════════════════════════════════════════════════════ DEBUG LOG ACTIONS", + "other_actions": "═════════════════════════════════════════════════════ OTHER ACTIONS", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "tracking_parameters": { @@ -305,12 +311,12 @@ "travel_time_factor": "TRAVEL TIME INTERVAL MULTIPLIER", "event_log_card_directory": "EVENT LOG CARD LOVELACE RESOURCES DIRECTORY - Event Log custom card .js file directory", "event_log_btnconfig_url": "EVENT LOG CONFIGURE BUTTON (GEAR) URL > Special URL that display's the HA Configure Settings screen", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "old_location_threshold": "Locations older than this value will be discarded", "old_location_adjustment": "Add this to the time that determines if a location is old", - "distance_between_devices": "See if there are any other devices that are near the device being updated. If there is, use that device's location results instead of going through the calculation process. This can speed up the update since Waze travel time and distance information does not have to be requested", + "distance_between_devices": "When tracking results are updated, any nearby devices are identified. When tracking results for those devices are updated, the tracking results of the one originally updated can be used instead. This improves performance since the Waze route time and distance are not requested again", "gps_accuracy_threshold": "Locations with GPS Accuracy above this value will be discarded", "tfz_tracking_max_distance": "Normally the Home zone's time and distance data is displayed on the Device's device_tracker and sensor entities. Display the Track-from-Zone instead when the Device is within this distance of the Track-from-Zone", "max_interval": "The maximum time between location requests", @@ -334,7 +340,7 @@ "discard_poor_gps_inzone": "Discard Location Updates with Poor GPS Accuracy when in a Zone", "distance_between_devices": "Determine the distance between devices. Use a near by device's tracking results", "center_in_zone": "Change Device's Location to the Zone's Center when in a Zone", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "no_iosapp": "Default interval if the iOS App is not used for location monitoring and zone enter/exit triggers", @@ -344,15 +350,15 @@ "waze_main": { "title": "Waze - Route Service Travel Time/Distance", "data": { - "waze_used": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ WAZE ROUTE SERVICE", + "waze_used": "═════════════════════════════════════════════════════ WAZE ROUTE SERVICE", "waze_region": "ROUTE SERVER LOCATION - Location of the Waze Route Server for your area", "waze_realtime": "USE REAL TIME DATA - Waze should consider traffic delays when determining travel time", "waze_min_distance": "WAZE MINIMUM DISTANCE", "waze_max_distance": "WAZE MAXIMUM DISTANCE", - "waze_history_database_used": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ WAZE HISTORY DATABASE", + "waze_history_database_used": "═════════════════════════════════════════════════════ WAZE HISTORY DATABASE", "waze_history_track_direction": "GENERAL TRAVEL DIRECTION - Used to display 'Map Trace Lines' between saved locations", "waze_history_max_distance": "HISTORY MAX DISTANCE", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "waze_min_distance": "Use the Waze Route Service when the zone distance is greater than this value", @@ -362,17 +368,18 @@ }, "special_zones": { "title": "Special Zones - Enter Zone Delay, Stationary Zone, Primay Home Base Zone", + "description": "This screen lets you configure an enter zone delay time, stationary zones and set up a temporary 'home' zone at another location", "data": { - "passthru_zone_header": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ ENTER ZONE DELAY", + "passthru_zone_header": "═════════════════════════════════════════════════════ ENTER ZONE DELAY", "passthru_zone_time": "ENTER ZONE DELAY TIME ", - "stat_zone_header": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ STATIONARY ZONE", + "stat_zone_header": "═════════════════════════════════════════════════════ STATIONARY ZONE", "stat_zone_still_time": "NO MOVEMENT TIME ", "stat_zone_inzone_interval": "INZONE INTERVAL ", "stat_zone_fname": "FRIENDLY NAME BASE - Name to display when in a Stationary Zone (StatZone)", - "track_from_zone_header": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ PRIMARY BASE ZONE = HOME", + "track_from_zone_header": "═════════════════════════════════════════════════════ PRIMARY BASE ZONE = HOME", "track_from_base_zone": "PRIMARY 'HOME' ZONE - Use another zone if you are away from Home for an extended period (Global Override)", "track_from_home_zone": "ALSO TRACK FROM HOME ZONE - Continue to track from the Home zone when the Primary Home Zone is not Home", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "passthru_zone_time": "Delay processing an Enter Zone Trigger that you may be driving through and not actually entering", @@ -385,17 +392,17 @@ "title": "Device and Tracking Sensors created by iCloud3", "description": "Many sensors are used to display tracking results and other information for a device. This screen is used to select the sensors that should be created.", "data": { - "monitored_devices": "MONITORED DEVICE SENSORS - Select the type of sensors to create for a Monitored Device", - "device": "DEVICE SENSORS - Device status and information", - "tracking_update": "LOCATION UPDATE SENSORS - Device location update times", - "tracking_time": "TIME SENSORS - Device tracking timers", - "tracking_distance": "DISTANCE SENSORS - Device tracking distances", - "track_from_zones": "TRACK FROM MULTIPLE ZONE SENSORS - Used when tracking from more than one zone (not needed for tracking only from the Home zone)", - "tracking_other": "OTHER TRACKING SENSORS - Not normally used but available", - "zone": "ZONE SENSORS - Device zone status and information", - "other": "OTHER SENSORS - Sensors not in the above areas", - "excluded_sensors": "EXCLUDED SENSORS - Sensors that will not be created when iCloud3 starts", - "action_items": "═══════════════════════════════════════════════════" + "monitored_devices": "═════════════════════════════════════════════════════ MONITORED DEVICE SENSORS - Select the type of sensors to create for a Monitored Device", + "device": "═════════════════════════════════════════════════════ DEVICE SENSORS - Device status and information", + "tracking_update": "═════════════════════════════════════════════════════ LOCATION UPDATE SENSORS - Device location update times", + "tracking_time": "═════════════════════════════════════════════════════ TIME SENSORS - Device tracking timers", + "tracking_distance": "═════════════════════════════════════════════════════ DISTANCE SENSORS - Device tracking distances", + "track_from_zones": "═════════════════════════════════════════════════════ TRACK FROM MULTIPLE ZONE SENSORS - Used when tracking from more than one zone (not needed for tracking only from the Home zone)", + "tracking_other": "═════════════════════════════════════════════════════ OTHER TRACKING SENSORS - Not normally used but available", + "zone": "═════════════════════════════════════════════════════ ZONE SENSORS - Device zone status and information", + "other": "═════════════════════════════════════════════════════ OTHER SENSORS - Sensors not in the above areas", + "excluded_sensors": "═════════════════════════════════════════════════════ EXCLUDED SENSORS - Sensors that will not be created when iCloud3 starts", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "exclude_sensors": { @@ -405,7 +412,7 @@ "excluded_sensors": "EXCLUDED SENSORS - Sensors that will not be created when iCloud3 starts", "filter": "FILTER DISPLAYED SENSORS - Select the Sensors that should be displayed", "filtered_sensors": "ICLOUD3 SENSORS - A list of Sensors that are created when iCloud3 starts", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } } } diff --git a/custom_components/icloud3/support/determine_interval.py b/custom_components/icloud3/support/determine_interval.py index 3dfb13e..c4d575c 100644 --- a/custom_components/icloud3/support/determine_interval.py +++ b/custom_components/icloud3/support/determine_interval.py @@ -654,15 +654,15 @@ def determine_interval_after_error(Device, counter=OLD_LOC_POOR_GPS_CNT): interval_secs, error_cnt, max_error_cnt = get_error_retry_interval(Device, counter) # Pause tracking when the max count is exceeded, send paused msg when the cnt is reached - if error_cnt >= max_error_cnt: + if error_cnt >= max_error_cnt and Device.is_tracking_paused is False: Device.pause_tracking() if error_cnt == max_error_cnt: message = { "title": "iCloud3 Tracking Exception", - "message": (f"Old Location or Poor GPS Accuracy Error " - f"Count exceeded (#{error_cnt}). Event Log > Actions > " - f"Resume to restart tracking."), + "message": (f"Old Location Count exceeded (#{error_cnt}). " + f"iCloud Web Services is Paused. " + f"Event Log > Actions > Resume to restart tracking."), "data": {"subtitle": "Tracking has been Paused"}} iosapp_interface.send_message_to_device(Device, message) diff --git a/custom_components/icloud3/support/iosapp_data_handler.py b/custom_components/icloud3/support/iosapp_data_handler.py index eeef20c..b6c97c9 100644 --- a/custom_components/icloud3/support/iosapp_data_handler.py +++ b/custom_components/icloud3/support/iosapp_data_handler.py @@ -15,7 +15,7 @@ from ..helpers.messaging import (post_event, post_monitor_msg, log_debug_msg, log_exception, log_error_msg, log_rawdata, _trace, _traceha, ) -from ..helpers.time_util import (secs_to_time, secs_since, format_time_age, format_age, ) +from ..helpers.time_util import (secs_to_time, secs_since, format_time_age, format_age, format_age_hrs, ) from ..helpers.dist_util import (format_dist_km, format_dist_m, ) from ..helpers import entity_io from ..support import iosapp_interface @@ -63,12 +63,19 @@ def check_iosapp_state_trigger_change(Device): iosapp_data_trigger_time = device_trkr_attrs[f"trigger_{TIMESTAMP_TIME}"] = secs_to_time(iosapp_data_trigger_secs) # Get the latest of the state time or trigger time for the new data + # if iosapp_data_state_secs > iosapp_data_trigger_secs: + # iosapp_data_secs = device_trkr_attrs[TIMESTAMP_SECS] = iosapp_data_trigger_secs + # iosapp_data_time = device_trkr_attrs[TIMESTAMP_TIME] = iosapp_data_trigger_time + # else: + # iosapp_data_secs = device_trkr_attrs[TIMESTAMP_SECS] = iosapp_data_state_secs + # iosapp_data_time = device_trkr_attrs[TIMESTAMP_TIME] = iosapp_data_state_time + if iosapp_data_state_secs > iosapp_data_trigger_secs: - iosapp_data_secs = device_trkr_attrs[TIMESTAMP_SECS] = iosapp_data_trigger_secs - iosapp_data_time = device_trkr_attrs[TIMESTAMP_TIME] = iosapp_data_trigger_time - else: iosapp_data_secs = device_trkr_attrs[TIMESTAMP_SECS] = iosapp_data_state_secs iosapp_data_time = device_trkr_attrs[TIMESTAMP_TIME] = iosapp_data_state_time + else: + iosapp_data_secs = device_trkr_attrs[TIMESTAMP_SECS] = iosapp_data_trigger_secs + iosapp_data_time = device_trkr_attrs[TIMESTAMP_TIME] = iosapp_data_trigger_time if Gb.log_rawdata_flag: change_msg = '' @@ -248,6 +255,11 @@ def check_iosapp_state_trigger_change(Device): else: Device.iosapp_data_reject_reason = "Failed Update Tests" + # If data time is very old, change it to it's age + if secs_since(Device.iosapp_data_secs) >= 10800: + Device.iosapp_data_time = device_trkr_attrs[TIMESTAMP_TIME] = \ + format_age_hrs(Device.iosapp_data_secs) + # Display iOSApp Monitor info message if the state or trigger changed if (Gb.this_update_time.endswith('00:00') or iosapp_msg != Device.last_iosapp_msg): diff --git a/custom_components/icloud3/support/pyicloud_ic3.py b/custom_components/icloud3/support/pyicloud_ic3.py index e430f80..0745c2a 100644 --- a/custom_components/icloud3/support/pyicloud_ic3.py +++ b/custom_components/icloud3/support/pyicloud_ic3.py @@ -580,13 +580,13 @@ def authenticate(self, refresh_session=False, service=None): self.authenticate_method += ", Password" else: login_successful = False - msg = "Login Error (Invalid username/password)/593" + msg = f"Login Error (Invalid username/password)/593, err={self.response_code}" raise PyiCloudFailedLoginException(msg) except PyiCloudAPIResponseException as error: login_successful = False - msg = "Login Error (Invalid username/password)/599" + msg = f"Login Error (Invalid username/password)/599, err={self.response_code}" raise PyiCloudFailedLoginException(msg) if self._authenticate_with_token(): @@ -595,7 +595,10 @@ def authenticate(self, refresh_session=False, service=None): if login_successful == False: self.authenticate_method += ", ERROR-Invalid username/password" - msg = "Login Error (Invalid username/password)/609" + if self.response_code == 302: + msg = f"Login Error, iCloud Server Connection Error/606, err={self.response_code}" + else: + msg = f"Login Error, Invalid username/password)/609, err={self.response_code}" raise PyiCloudFailedLoginException(msg) self.requires_2fa = self.requires_2fa or self._check_2fa_needed @@ -996,6 +999,10 @@ def trusted_devices(self): def new_log_in_needed(self, username): return username != self.apple_id + @property + def response_code(self): + return self.Session.response_status_code + #---------------------------------------------------------------------------- def send_verification_code(self, device): '''Requests that a verification code is sent to the given device.''' diff --git a/custom_components/icloud3/support/pyicloud_ic3_interface.py b/custom_components/icloud3/support/pyicloud_ic3_interface.py index 6b1287b..41d1df1 100644 --- a/custom_components/icloud3/support/pyicloud_ic3_interface.py +++ b/custom_components/icloud3/support/pyicloud_ic3_interface.py @@ -225,7 +225,11 @@ def display_authentication_msg(PyiCloud): if instr(authentication_method, 'Password') is False: event_msg += f" ({format_age(last_authenticated_age)})" - post_monitor_msg(event_msg) + + if instr(authentication_method, 'Password'): + post_event(event_msg) + else: + post_monitor_msg(event_msg) #-------------------------------------------------------------------- def is_authentication_2fa_code_needed(PyiCloud, initial_setup=False): @@ -395,7 +399,7 @@ def delete_pyicloud_cookies_session_files(cookie_filename=None): post_monitor_msg(delete_msg) #-------------------------------------------------------------------- -def create_PyiCloudService_secondary(username, password, +def create_PyiCloudService_secondary(username, password, endpoint_suffix, called_from, verify_password, request_verification_code=False): ''' diff --git a/custom_components/icloud3/translations/en.json b/custom_components/icloud3/translations/en.json index 0776d81..ecaec50 100644 --- a/custom_components/icloud3/translations/en.json +++ b/custom_components/icloud3/translations/en.json @@ -34,7 +34,7 @@ "description": "Enter the 6-digit verification code you just received from Apple", "data": { "verification_code": "ICLOUD ACCOUNT VERIFICATION CODE", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════" } }, "restart_ha": { @@ -62,10 +62,12 @@ "icloud_acct_logging_into": "Logging into iCloud Account", "icloud_acct_logged_into": "Successfully Logged into the iCloud Account", "icloud_acct_already_logged_into": "Already Logged into the iCloud Account", - "icloud_acct_login_error": "iCloud Account Login Failed - Review Username/Password (or China '.cn' suffix)", - "icloud_acct_not_available": "iCloud Account is not Available, Login Unsuccessful", + "icloud_acct_login_error_user_pw": "Login Failed, Invalid Username or Password (err-400)", + "icloud_acct_login_error_other": "Login Failed, Other Error or iCloud is not Available", + "icloud_acct_login_error_connection": "Login Error, Failed to Connect to iCloud Server (err-302)", + "icloud_acct_not_available": "Login Error, iCloud Account is not Available", "icloud_acct_not_logged_into": "iCloud Account is not Logged Into", - "icloud_acct_not_set_up": "The iCloud Account Username or Password needs to be entered", + "icloud_acct_not_set_up": "iCloud Account Username or Password needs to be entered", "icloud_acct_no_data_source": "No Data Source has been selected", "verification_code_requested": "The Apple ID Verification Code was requested, BROWSER REFRESH MAY BE NEEDED", @@ -131,7 +133,7 @@ "title": "iCloud3 Configure Settings", "data": { "menu_items": "", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════" } }, "restart_icloud3": { @@ -165,12 +167,12 @@ "title": "iCloud Account & iOS App Data Sources", "description": "The data sources (iCloud Account Web Services and the iOS App) are selected on this screen. The Apple iCloud Account Username/Password must be specified here to access the iCloud Account. The HA Companion App (iOS App) must be installed on the iDevice to use is as a data source for that device. Each iDevice you are tracking is associated with the iCloud3 device on the Update Devices screen.", "data": { - "data_source_icloud": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ ICLOUD ACCOUNT - Location data is provided by the Apple iCloud account", + "data_source_icloud": "═════════════════════════════════════════════════════ ICLOUD ACCOUNT - Location data is provided by the Apple iCloud account", "username": "APPLE ID (USERNAME) - The email address used to sign in to the iCloud Account", "password": "PASSWORD - The iCloud Account Password", "url_suffix_china": "CHINA USERS - Add '.cn' to use the Apple iCloud Web Servers located in China", - "data_source_iosapp": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ iOS APP - Location data is provided by the HA iOS App", - "action_items": "═══════════════════════════════════════════════════" + "data_source_iosapp": "═════════════════════════════════════════════════════ iOS APP - Location data is provided by the HA iOS App", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { } @@ -180,15 +182,15 @@ "description": "Enter the 6-digit verification code you just received from Apple", "data": { "verification_code": "ICLOUD ACCOUNT VERIFICATION CODE", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "device_list": { "title": "iCloud3 Device Tracker Entities", "description": "All of the devices that are tracked or monitored by iCloud3 are listed on this screen. You can add new devices and update or delete existing devices.", "data": { - "devices": "", - "action_items": "═══════════════════════════════════════════════════" + "devices": "═════════════════════════════════════════════════════ ICLOUD3 DEVICES", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "add_device": { @@ -199,7 +201,7 @@ "device_type": "DEVICE TYPE - iPhone, iPad, Watch, etc.", "tracking_mode": "TRACKING MODE - How location requests should be done (Full tracking, Monitor, Inactive)", "iosapp": "iOS APP INSTALLED - The HA iOS App is installed on this device ", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { } @@ -219,7 +221,7 @@ "track_from_base_zone": "PRIMARY HOME ZONE - Use another zone if you are away from Home for an extended period", "picture": "PICTURE - Photo image of the person normally using this device (40x40 pixels is best size)", "inzone_interval": "INZONE INTERVAL", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "inzone_interval": "Time between location requests when in a zone", @@ -229,22 +231,23 @@ "delete_device": { "title": "Delete Device(s), Other Device Maintenance", "data": { - "action_items": "" + "action_items": "═════════════════════════════════════════════════════ DELETE OPTIONS" } }, "review_inactive_devices": { "title": "Review Untracked (Inactive) Devices", "description": "The 'Tracking Mode' of devices are set to 'Inactive' and will not be located or tracked.", "data": { - "inactive_devices": "", - "action_items": "═══════════════════════════════════════════════════" + "inactive_devices": "═════════════════════════════════════════════════════ INACTIVE ICLOUD3 DEVICES", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "change_device_order": { "title": "Event Log Device Display Sequence", + "description": "The devices are displayed in the Event Log heading area and in various Event Log messages in the sequence below. This screen lets you change the order of the devices.", "data": { - "device_desc": "DEVICES - The devices are displayed in the Event Log heading area and in various Event Log messages in this sequence", - "action_items": "═══════════════════════════════════════════════════" + "device_desc": "═════════════════════════════════════════════════════ ICLOUD3 DEVICES", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "format_settings": { @@ -258,7 +261,7 @@ "unit_of_measurement": "UNIT OF MEASUREMENT - How distance fieldsare displayed in sensors and in the Event Log", "display_gps_lat_long": "DISPLAY GPS COORDINATES - Display the GPS (Latitude, Longitude/±Accuracy) or only the GPS (/±Accuracy) in the Event Log", "display_gps_lat_long2": "DISPLAY GPS COORDINATES - Display the GPS Latitude/Longitude/Accuracy (22.32771, -76.33073/±35m) or only the GPS accuracy (/±35m) in the Event Log", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "device_tracker_state_source": "HA uses the device's gps coordinates to determine the zone. The gps accuracy is not considered so the zone may be exited when the gps wanders out of the zone. iCloud3 does consider the gps accuracy and will not exit the zone when this occurs. iCloud3 will display the Zone's Friendly Name or zone name displayed on the Event Log." @@ -268,8 +271,8 @@ "title": "Event Log 'Display Text As'", "description": "There may be some text fields that are displayed on the Event Log screen that may be sensitive in nature. Some examples include email addresses or phone numbers. With this screen, you can select the Original Text and what should be displayed instead. For example, you can replace 'geekstergary@apple.com' with 'gary@email.com'", "data": { - "display_text_as": "Text Replacement Fields", - "action_items": "═══════════════════════════════════════════════════" + "display_text_as": "═════════════════════════════════════════════════════ TEXT REPLACEMENT FIELDS - [Actual text > Displayed text]", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "display_text_as_update": { @@ -277,7 +280,7 @@ "data": { "text_from": "ORIGINAL TEXT - Text to be replaced (example: gary_real_email@gmail.com)", "text_to": "DISPLAYED TEXT- Text to be displayed (display: gary@email.com)", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { } @@ -285,7 +288,10 @@ "actions": { "title": "iCloud3 Action Commands", "data": { - "action_items": "" + "ic3_actions": "═════════════════════════════════════════════════════ ICLOUD3 GENERAL CONTROL ACTIONS", + "debug_actions": "═════════════════════════════════════════════════════ DEBUG LOG ACTIONS", + "other_actions": "═════════════════════════════════════════════════════ OTHER ACTIONS", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "tracking_parameters": { @@ -305,12 +311,12 @@ "travel_time_factor": "TRAVEL TIME INTERVAL MULTIPLIER", "event_log_card_directory": "EVENT LOG CARD LOVELACE RESOURCES DIRECTORY - Event Log custom card .js file directory", "event_log_btnconfig_url": "EVENT LOG CONFIGURE BUTTON (GEAR) URL > Special URL that display's the HA Configure Settings screen", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "old_location_threshold": "Locations older than this value will be discarded", "old_location_adjustment": "Add this to the time that determines if a location is old", - "distance_between_devices": "See if there are any other devices that are near the device being updated. If there is, use that device's location results instead of going through the calculation process. This can speed up the update since Waze travel time and distance information does not have to be requested", + "distance_between_devices": "When tracking results are updated, any nearby devices are identified. When tracking results for those devices are updated, the tracking results of the one originally updated can be used instead. This improves performance since the Waze route time and distance are not requested again", "gps_accuracy_threshold": "Locations with GPS Accuracy above this value will be discarded", "tfz_tracking_max_distance": "Normally the Home zone's time and distance data is displayed on the Device's device_tracker and sensor entities. Display the Track-from-Zone instead when the Device is within this distance of the Track-from-Zone", "max_interval": "The maximum time between location requests", @@ -334,7 +340,7 @@ "discard_poor_gps_inzone": "Discard Location Updates with Poor GPS Accuracy when in a Zone", "distance_between_devices": "Determine the distance between devices. Use a near by device's tracking results", "center_in_zone": "Change Device's Location to the Zone's Center when in a Zone", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "no_iosapp": "Default interval if the iOS App is not used for location monitoring and zone enter/exit triggers", @@ -344,15 +350,15 @@ "waze_main": { "title": "Waze - Route Service Travel Time/Distance", "data": { - "waze_used": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ WAZE ROUTE SERVICE", + "waze_used": "═════════════════════════════════════════════════════ WAZE ROUTE SERVICE", "waze_region": "ROUTE SERVER LOCATION - Location of the Waze Route Server for your area", "waze_realtime": "USE REAL TIME DATA - Waze should consider traffic delays when determining travel time", "waze_min_distance": "WAZE MINIMUM DISTANCE", "waze_max_distance": "WAZE MAXIMUM DISTANCE", - "waze_history_database_used": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ WAZE HISTORY DATABASE", + "waze_history_database_used": "═════════════════════════════════════════════════════ WAZE HISTORY DATABASE", "waze_history_track_direction": "GENERAL TRAVEL DIRECTION - Used to display 'Map Trace Lines' between saved locations", "waze_history_max_distance": "HISTORY MAX DISTANCE", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "waze_min_distance": "Use the Waze Route Service when the zone distance is greater than this value", @@ -362,17 +368,18 @@ }, "special_zones": { "title": "Special Zones - Enter Zone Delay, Stationary Zone, Primay Home Base Zone", + "description": "This screen lets you configure an enter zone delay time, stationary zones and set up a temporary 'home' zone at another location", "data": { - "passthru_zone_header": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ ENTER ZONE DELAY", + "passthru_zone_header": "═════════════════════════════════════════════════════ ENTER ZONE DELAY", "passthru_zone_time": "ENTER ZONE DELAY TIME ", - "stat_zone_header": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ STATIONARY ZONE", + "stat_zone_header": "═════════════════════════════════════════════════════ STATIONARY ZONE", "stat_zone_still_time": "NO MOVEMENT TIME ", "stat_zone_inzone_interval": "INZONE INTERVAL ", "stat_zone_fname": "FRIENDLY NAME BASE - Name to display when in a Stationary Zone (StatZone)", - "track_from_zone_header": "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ PRIMARY BASE ZONE = HOME", + "track_from_zone_header": "═════════════════════════════════════════════════════ PRIMARY BASE ZONE = HOME", "track_from_base_zone": "PRIMARY 'HOME' ZONE - Use another zone if you are away from Home for an extended period (Global Override)", "track_from_home_zone": "ALSO TRACK FROM HOME ZONE - Continue to track from the Home zone when the Primary Home Zone is not Home", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" }, "data_description": { "passthru_zone_time": "Delay processing an Enter Zone Trigger that you may be driving through and not actually entering", @@ -385,17 +392,17 @@ "title": "Device and Tracking Sensors created by iCloud3", "description": "Many sensors are used to display tracking results and other information for a device. This screen is used to select the sensors that should be created.", "data": { - "monitored_devices": "MONITORED DEVICE SENSORS - Select the type of sensors to create for a Monitored Device", - "device": "DEVICE SENSORS - Device status and information", - "tracking_update": "LOCATION UPDATE SENSORS - Device location update times", - "tracking_time": "TIME SENSORS - Device tracking timers", - "tracking_distance": "DISTANCE SENSORS - Device tracking distances", - "track_from_zones": "TRACK FROM MULTIPLE ZONE SENSORS - Used when tracking from more than one zone (not needed for tracking only from the Home zone)", - "tracking_other": "OTHER TRACKING SENSORS - Not normally used but available", - "zone": "ZONE SENSORS - Device zone status and information", - "other": "OTHER SENSORS - Sensors not in the above areas", - "excluded_sensors": "EXCLUDED SENSORS - Sensors that will not be created when iCloud3 starts", - "action_items": "═══════════════════════════════════════════════════" + "monitored_devices": "═════════════════════════════════════════════════════ MONITORED DEVICE SENSORS - Select the type of sensors to create for a Monitored Device", + "device": "═════════════════════════════════════════════════════ DEVICE SENSORS - Device status and information", + "tracking_update": "═════════════════════════════════════════════════════ LOCATION UPDATE SENSORS - Device location update times", + "tracking_time": "═════════════════════════════════════════════════════ TIME SENSORS - Device tracking timers", + "tracking_distance": "═════════════════════════════════════════════════════ DISTANCE SENSORS - Device tracking distances", + "track_from_zones": "═════════════════════════════════════════════════════ TRACK FROM MULTIPLE ZONE SENSORS - Used when tracking from more than one zone (not needed for tracking only from the Home zone)", + "tracking_other": "═════════════════════════════════════════════════════ OTHER TRACKING SENSORS - Not normally used but available", + "zone": "═════════════════════════════════════════════════════ ZONE SENSORS - Device zone status and information", + "other": "═════════════════════════════════════════════════════ OTHER SENSORS - Sensors not in the above areas", + "excluded_sensors": "═════════════════════════════════════════════════════ EXCLUDED SENSORS - Sensors that will not be created when iCloud3 starts", + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } }, "exclude_sensors": { @@ -405,7 +412,7 @@ "excluded_sensors": "EXCLUDED SENSORS - Sensors that will not be created when iCloud3 starts", "filter": "FILTER DISPLAYED SENSORS - Select the Sensors that should be displayed", "filtered_sensors": "ICLOUD3 SENSORS - A list of Sensors that are created when iCloud3 starts", - "action_items": "═══════════════════════════════════════════════════" + "action_items": "═════════════════════════════════════════════════════ ACTION COMMANDS" } } }