Skip to content

Commit

Permalink
iCloud3 v3.0.5.6
Browse files Browse the repository at this point in the history
  • Loading branch information
gcobb321 committed Jul 29, 2024
1 parent 4b6f376 commit d00d8b8
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 25 deletions.
11 changes: 10 additions & 1 deletion custom_components/icloud3/ChangeLog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@
**Installing for the first time_** - See [here](https://gcobb321.github.io/icloud3_v3_docs/#/chapters/3.2-installing-and-configuring) for instructions on installing as a New Installation
**iCloud3 v3 Documentation** - iCloud3 User Guide can be found [here](https://gcobb321.github.io/icloud3_v3_docs/#/)

3.0.5.6
.......................
### Change Log - v3.0.5.6 (7/15/2024)
1. ICLOUD3 BUG FIXES - Fixes the following errors:
```AttributeError: 'NoneType' object has no attribute 'init_step_complete'```
```AttributeError: module 'custom_components.icloud3.sensor' has no attribute _setup_recorder_exclude_sensor_filter'```
2. HA ERROR/WARNING MESSAGES - Fixed a problem where some I/O getting directory and filename list for the Update Devices configuration screen was being done outside of the HA Event Loop


3.0.5.5
.......................
### Change Log - v3.0.5.5 (7/15/2024)
1. ICLOUD3 FAILED TO LOAD (Fix) - iCloud3 injected special code into the HA history recorder to exclude various sensor entities with large text fields from being added to the history recorder. This caused problems with HA in the 2024.7 release. The HA 2024.7.2 included special code that blocked iCloud3 from loading. A temporary patch was posted on the iCloud3 GitHub repository to disable the recorder injection. This update is a permant fix.
1. ICLOUD3 FAILED TO LOAD (Fix) - iCloud3 injected special code into the HA history recorder to exclude various sensor entities with large text fields from being added to the history recorder. This caused problems with HA in the 2024.7 release. The HA 2024.7.2 included special code that blocked iCloud3 from loading. A temporary patch was posted on the iCloud3 GitHub repository to disable the recorder injection. This update is a permant fix.

All sensor attributes not related to the battery, distance and timer sensors are being added to the HA recorder history database. Text base sensor attributes are not being added (info sensors, Event Log sensor, badge, tracking update, zone, etc.)..

Expand Down
102 changes: 91 additions & 11 deletions custom_components/icloud3/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
from .const_sensor import (SENSOR_GROUPS )
from .helpers.common import (instr, isnumber, obscure_field, list_to_str, str_to_list,
is_statzone, zone_dname, isbetween, list_del, list_add,
get_file_list, get_directory_list,
sort_dict_by_values, )
from .helpers.messaging import (log_exception, log_debug_msg, log_info_msg,
_traceha, _trace,
Expand Down Expand Up @@ -1428,12 +1429,36 @@ def _dzf_set_example_zone_name_text(self, key, example_text, real_text):
if key in DISPLAY_ZONE_FORMAT_ITEMS_KEY_TEXT:
DISPLAY_ZONE_FORMAT_ITEMS_KEY_TEXT[key] = \
DISPLAY_ZONE_FORMAT_ITEMS_KEY_TEXT[key].replace(example_text, real_text)

#-------------------------------------------------------------------------------------------
async def async_step_tracking_parameters(self, user_input=None, errors=None):
self.step_id = 'tracking_parameters'
user_input, action_item = self._action_text_to_item(user_input)

if self.www_directory_list == []:
directory_list, start_dir, file_filter = [True, 'www', []]
self.www_directory_list = await Gb.hass.async_add_executor_job(
get_directory_list,
start_dir)

if self.common_form_handler(user_input, action_item, errors):
if action_item == 'save':
Gb.picture_www_dirs = Gb.conf_profile[CONF_PICTURE_WWW_DIRS].copy()
self.picture_by_filename = {}
return await self.async_step_menu()


if self._any_errors():
self.errors['action_items'] = 'update_aborted'

return self.async_show_form(step_id=self.step_id,
data_schema=self.form_schema(self.step_id),
errors=self.errors)

#-------------------------------------------------------------------------------------------
async def xasync_step_tracking_parameters(self, user_input=None, errors=None):
self.step_id = 'tracking_parameters'
user_input, action_item = self._action_text_to_item(user_input)

if self.www_directory_list == []:
dir_filters = ['/.', 'deleted', '/x-']
path_config_base = f"{Gb.ha_config_directory}/"
Expand Down Expand Up @@ -2283,7 +2308,7 @@ async def async_step_icloud_account(self, user_input=None, errors=None, called_f
or self.errors.get('base', '') == 'icloud_acct_logged_into')
or self.errors.get('base', '') == 'icloud_acct_not_logged_into'):

await self._build_update_device_selection_lists()
# await self._build_update_device_selection_lists()
self._prepare_device_selection_list()

user_input[CONF_ICLOUD_SERVER_ENDPOINT_SUFFIX] = self.endpoint_suffix
Expand Down Expand Up @@ -2543,7 +2568,7 @@ async def _log_into_icloud_account(self, user_input, called_from_step_id=None, r
data_schema=self.form_schema(called_from_step_id),
errors=self.errors)

await self._build_update_device_selection_lists()
# await self._build_update_device_selection_lists()

self.obscure_username = obscure_field(self.username) or 'NoUsername'
self.obscure_password = obscure_field(self.password) or 'NoPassword'
Expand Down Expand Up @@ -2628,13 +2653,13 @@ async def async_step_device_list(self, user_input=None, errors=None):
called_from_step_id='device_list')

device_cnt = len(Gb.conf_devices)
if user_input is None:
await self._build_update_device_selection_lists()
# if user_input is None:
# await self._build_update_device_selection_lists()

if user_input is not None:
if (action_item in ['update_device', 'delete_device']
and CONF_DEVICES not in user_input):
await self._build_update_device_selection_lists()
# await self._build_update_device_selection_lists()
action_item = ''

if action_item == 'return':
Expand Down Expand Up @@ -2892,6 +2917,7 @@ async def async_step_update_device(self, user_input=None, errors=None):
self.step_id = 'update_device'
self.errors = errors or {}
self.errors_user_input = {}
await self._build_update_device_selection_lists()

if user_input is None:
return self.async_show_form(step_id=self.step_id,
Expand Down Expand Up @@ -3244,7 +3270,7 @@ def _update_changed_sensor_entities(self):
async def _build_update_device_selection_lists(self):
""" Setup the option lists used to select device parameters """

self._build_picture_filename_list()
await self._build_picture_filename_list()
self._build_mobapp_entity_list()
self._build_zone_list()

Expand Down Expand Up @@ -3506,8 +3532,63 @@ def _format_device_list_item(self, conf_device_data):

return device_info


#-------------------------------------------------------------------------------------------
async def _build_picture_filename_list(self):

try:
if self.picture_by_filename != {}:
return

directory_list, start_dir, file_filter = [False, 'www', ['png', 'jpg', 'jpeg']]
image_filenames = await Gb.hass.async_add_executor_job(
get_file_list,
start_dir,
file_filter)
# image_filenames = await Gb.hass.async_add_executor_job(
# self.get_file_or_directory_list,
# directory_list,
# start_dir,
# file_filter)

sorted_image_filenames = []
over_25_warning_msgs = []
for image_filename in image_filenames:
if image_filename.startswith('⛔'):
over_25_warning_msgs.append(image_filename)
else:
sorted_image_filenames.append(f"{image_filename.rsplit('/', 1)[1]}:{image_filename}")
sorted_image_filenames.sort()
self.picture_by_filename = {}
self.picture_by_filename['www_dirs'] = "Source Directories:"
www_dir_idx = 0

if Gb.picture_www_dirs:
while www_dir_idx < len(Gb.picture_www_dirs):
self.picture_by_filename[f"www_dirs{www_dir_idx}"] = \
f"{DOT}{list_to_str(Gb.picture_www_dirs[www_dir_idx:www_dir_idx+3])}"
www_dir_idx += 3
else:
self.picture_by_filename["www_dirs0"] = f"{DOT}All `www/*` directories are scaned"

for over_25_warning_msg in over_25_warning_msgs:
www_dir_idx += 1
self.picture_by_filename[f"www_dirs{www_dir_idx}"] = over_25_warning_msg

#self.picture_by_filename.extend(sorted_image_filenames)
self.picture_by_filename['www_dirs998'] = "Set filter on `Tracking and Other Parameters` screen"
self.picture_by_filename['www_dirs999'] = f"{'-'*85}"
self.picture_by_filename.update(self.picture_by_filename_base)

for sorted_image_filename in sorted_image_filenames:
image_filename, image_filename_path = sorted_image_filename.split(':')
self.picture_by_filename[image_filename_path] = \
f"{image_filename}{RARROW}{image_filename_path.replace(image_filename, '')}"

except Exception as err:
log_exception(err)
#-------------------------------------------------------------------------------------------
def _build_picture_filename_list(self):
def x_build_picture_filename_list(self):

try:
if self.picture_by_filename != {}:
Expand Down Expand Up @@ -3863,7 +3944,6 @@ def _create_sensor_entity(self, devicename, conf_device, new_sensors_list):
return

Gb.async_add_entities_sensor(NewSensors, True)
ic3_sensor._setup_recorder_exclude_sensor_filter(NewSensors)

#-------------------------------------------------------------------------------------------
def _get_all_sensors_list(self):
Expand Down Expand Up @@ -4507,8 +4587,8 @@ def form_schema(self, step_id, actions_list=None, actions_list_default=None):

#------------------------------------------------------------------------
elif step_id == 'update_device':
self._build_picture_filename_list()
self._build_devicename_by_famshr_fmf(self.conf_device_selected[CONF_IC3_DEVICENAME])
# self._build_picture_filename_list()
# self._build_devicename_by_famshr_fmf(self.conf_device_selected[CONF_IC3_DEVICENAME])
error_key = ''
self.errors = self.errors or {}

Expand Down
2 changes: 1 addition & 1 deletion custom_components/icloud3/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

VERSION = '3.0.5.5'
VERSION = '3.0.5.6'
VERSION_BETA = ''
#-----------------------------------------
DOMAIN = 'icloud3'
Expand Down
71 changes: 70 additions & 1 deletion custom_components/icloud3/helpers/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,11 @@ def format_list(arg_list):
def format_cnt(desc, n):
return f", {desc}(#{n})" if n > 1 else ''

#--------------------------------------------------------------------
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#
# PYTHON OS. FILE I/O AND OTHER UTILITIES
#
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
async def async_load_json_file(filename):
if os.path.exists(filename) is False:
return {}
Expand Down Expand Up @@ -413,6 +417,71 @@ def delete_file(file_desc, directory, filename, backup_extn=None, delete_old_sv_
Gb.HALogger.exception(err)
return "Delete error"

#--------------------------------------------------------------------
def get_file_list(start_dir=None, file_extn_filter=[]):
return get_file_or_directory_list( directory_list=False,
start_dir=start_dir,
file_extn_filter=file_extn_filter)

def get_directory_list(start_dir=None):
return get_file_or_directory_list( directory_list=True,
start_dir=start_dir,
file_extn_filter=[])

#--------------------------------------------------------------------
def get_file_or_directory_list(directory_list=False, start_dir=None, file_extn_filter=[]):
'''
Return a list of directories or files in a given path
Parameters:
- directory_list = True (List of directories), False (List of files)
- start_dir = Top level directory to start searching from ('www')
-file_extn_filter = List of files witn extensions to include (['png' 'jpg'], [])
Can call from executor function:
directory_list, start_dir, file_filter = [False, 'www', ['png', 'jpg', 'jpeg']]
image_filenames = await Gb.hass.async_add_executor_job(
self.get_file_or_directory_list,
directory_list,
start_dir,
file_filter)
'''

directory_filter = ['/.', 'deleted', '/x-']
filename_or_directory_list = []
path_config_base = f"{Gb.ha_config_directory}/"
back_slash = '\\'
if start_dir is None: start_dir = ''

for path, dirs, files in os.walk(f"{path_config_base}{start_dir}"):
www_sub_directory = path.replace(path_config_base, '')
in_filter_cnt = len([filter for filter in directory_filter if instr(www_sub_directory, filter)])
if in_filter_cnt > 0 or www_sub_directory.count('/') > 4 or www_sub_directory.count(back_slash):
continue

if directory_list:
filename_or_directory_list.append(www_sub_directory)
continue

# Filter unwanted directories - std dirs are www/icloud3, www/cummunity, www/images
if Gb.picture_www_dirs:
valid_dir = [dir for dir in Gb.picture_www_dirs if www_sub_directory.startswith(dir)]
if valid_dir == []:
continue

dir_filenames = [f"{www_sub_directory}/{file}"
for file in files
if (file_extn_filter
and file.rsplit('.', 1)[-1] in file_extn_filter)]

filename_or_directory_list.extend(dir_filenames[:25])
if len(dir_filenames) > 25:
filename_or_directory_list.append(
f"⛔ {www_sub_directory} > The first 25 files out of "
f"{len(dir_filenames)} are listed")

return filename_or_directory_list

#--------------------------------------------------------------------
def encode_password(password):
'''
Expand Down
2 changes: 1 addition & 1 deletion custom_components/icloud3/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
"issue_tracker": "https://github.com/gcobb321/icloud3_v3/issues",
"loggers": ["icloud3"],
"requirements": [],
"version": "3.0.5.5"
"version": "3.0.5.6"
}
5 changes: 0 additions & 5 deletions custom_components/icloud3/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e

NewSensors = []
Gb.EvLogSensor = Sensor_EventLog(SENSOR_EVENT_LOG_NAME)
# Gb.EvLogSensor = Sensor_EventLog_ExcludeFromRecorder(SENSOR_EVENT_LOG_NAME)
_traceha(f"EVLOG SENSOR {Gb.EvLogSensor=}")
if Gb.EvLogSensor:
NewSensors.append(Gb.EvLogSensor)
else:
Expand Down Expand Up @@ -1133,14 +1131,11 @@ def _format_devices_distance_extra_attrs(self):
# '''
# try:
# if isnumber(number) is False:
# _trace(f"zz {self.sensor} {number=} {um=}")
# return number

# um = um if um else Gb.um
# precision = 5 if um in ['km', 'mi'] else 2 if um in ['m', 'ft'] else 4
# _trace(f"aa {self.sensor} {number=} {um=} {precision=}")
# number = round(float(number), precision)
# _trace(f"bb {self.sensor} {number=} {um=} {precision=}")

# except Exception as err:
# pass
Expand Down
4 changes: 4 additions & 0 deletions custom_components/icloud3/support/mobapp_data_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,10 @@ def get_mobapp_device_trkr_entity_attrs(Device):
None - error or no data is available
'''
try:
if (Device.mobapp_monitor_flag is False
or Gb.conf_data_source_MOBAPP is False):
return None

entity_id = Device.mobapp[DEVICE_TRACKER]
device_trkr_attrs = {}
device_trkr_attrs[DEVICE_TRACKER] = entity_io.get_state(entity_id)
Expand Down
1 change: 0 additions & 1 deletion custom_components/icloud3/support/pyicloud_ic3.py
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,6 @@ def _authenticate_with_token(self):
self.data = req.json()

if 'dsInfo' in self.data:
_traceha(f"{self.account_name=} {self.data['dsInfo']=}")
if 'fullName' in self.data['dsInfo']:
self.account_name = self.data['dsInfo']['fullName']
self.account_locked = self.data['dsInfo']['locked']
Expand Down
3 changes: 2 additions & 1 deletion custom_components/icloud3/support/pyicloud_ic3_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def verify_pyicloud_setup_status():
create_PyiCloudService(Gb.PyiCloud, instance='startup')

Gb.PyiCloud = Gb.PyiCloud or Gb.PyiCloudInit
if 'Authenticate' not in Gb.PyiCloud.init_step_complete:
if (Gb.PyiCloud is None
or 'Authenticate' not in Gb.PyiCloud.init_step_complete):
create_PyiCloudService(Gb.PyiCloud, instance='startup')
Gb.PyiCloud = Gb.PyiCloud or Gb.PyiCloudInit
if Gb.PyiCloud is None:
Expand Down
3 changes: 0 additions & 3 deletions custom_components/icloud3/support/start_ic3.py
Original file line number Diff line number Diff line change
Expand Up @@ -1802,7 +1802,6 @@ def setup_tracked_devices_for_fmf(PyiCloud=None):
return

broadcast_info_msg(f"Stage 3 > Set up Find-my-Friends Devices")
_trace(f"Stage 3 > Set up Find-my-Friends Devices")

# devices_desc = get_fmf_devices(PyiCloud)
# device_id_by_fmf_email = devices_desc[0]
Expand All @@ -1815,13 +1814,11 @@ def setup_tracked_devices_for_fmf(PyiCloud=None):
return

PyiCloud = Gb.PyiCloud
_trace(f"{PyiCloud.FindMyFriends=}")
PyiCloud.create_FindMyFriends_object()
_FmF = PyiCloud.FindMyFriends
# _Fmf._set_service_available(True)
Gb.conf_data_source_FMF = True
_FmF.refresh_client()
_trace(f"{PyiCloud.FindMyFriends=}")

event_msg = "Find-My-Friends Devices > "
# if Gb.conf_data_source_FMF is False:
Expand Down

0 comments on commit d00d8b8

Please sign in to comment.