Skip to content

Commit

Permalink
iCloud3 v3.0.rc8
Browse files Browse the repository at this point in the history
  • Loading branch information
gcobb321 committed Oct 25, 2023
1 parent 44e1362 commit 91d89d4
Show file tree
Hide file tree
Showing 23 changed files with 673 additions and 355 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

------

### Prerelease Version - v3.0-pr1.4 (9/22/2023)
###Release Candidate 8 - v3.0.rc8 (10/25/2023)

------

Expand Down
28 changes: 28 additions & 0 deletions custom_components/icloud3/ChangeLog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
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 - 10/15/2023
...............................
1. yaml Zones - Fixed a problem where zones configured using yaml were not being loaded when iCloud3 started.
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)_


rc6 - Release Candidate 6 (10/7/2023)
...............................
1. Bug Fix - Fixed the error causing the "AttributeError: 'iCloud3_Device' object has no attribute 'interval_secs' message at line 680, in determine_interval_after_error" error.
Expand Down
293 changes: 203 additions & 90 deletions custom_components/icloud3/config_flow.py

Large diffs are not rendered by default.

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

VERSION = '3.0.rc6'
VERSION = '3.0.rc8'

DOMAIN = 'icloud3'
ICLOUD3 = 'iCloud3'
Expand Down Expand Up @@ -328,6 +328,7 @@
'Not_Home': 'Away',
'not_set': '──',
'Not_Set': '──',
'──': 'NotSet',
# 'stationary': 'Stationary',
# 'Stationary': 'Stationary',
STATIONARY: STATIONARY_FNAME,
Expand Down
17 changes: 9 additions & 8 deletions custom_components/icloud3/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,15 @@ 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
#self.stationary_zonename = (f"{self.devicename}_{STATIONARY}")

self.FromZones_by_zone = {} # DeviceFmZones objects for the track_from_zones parameter for this Device
self.FromZone_Home = None # DeviceFmZone object for the Home zone
self.from_zone_names = [] # List of the from_zones in the FromZones_by_zone dictionary
self.FromZones_by_zone = {} # DeviceFmZones objects for the track_from_zones parameter for this Device
self.FromZone_Home = None # DeviceFmZone object for the Home zone
self.from_zone_names = [] # List of the from_zones in the FromZones_by_zone dictionary
self.only_track_from_home = True # Track from only Home (True) or also track from other zones (False)
self.FromZone_BeingUpdated = None # DeviceFmZone object being updated in determine_interval for EvLog TfZ info
self.FromZone_NextToUpdate = None # Set to the DeviceFmZone when it's next_update_time is reached
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -247,7 +249,7 @@ def initialize(self):
self.last_iosapp_trigger = ''

# iCloud data update control variables
# self.icloud_update_needed_flag = False
self.icloud_force_update_flag = False # Bypass all update needed checks and force an iCloud update
self.icloud_devdata_useable_flag = False
self.icloud_acct_error_flag = False # An error occured from the iCloud account update request
self.icloud_update_reason = 'Trigger > Initial Locate'
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -1308,7 +1310,6 @@ def calculate_distance_moved(self):
self.loc_data_time_moved_from = self.sensors[LAST_LOCATED_DATETIME]
self.loc_data_time_moved_to = self.loc_data_datetime


#--------------------------------------------------------------------
def distance_m(self, to_latitude, to_longitude):
to_gps = (to_latitude, to_longitude)
Expand Down
54 changes: 27 additions & 27 deletions custom_components/icloud3/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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:
Expand All @@ -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")
Expand All @@ -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]
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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}, "
Expand Down Expand Up @@ -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):
Expand Down
Binary file not shown.
7 changes: 4 additions & 3 deletions custom_components/icloud3/global_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ''
Expand Down Expand Up @@ -234,7 +234,7 @@ class GlobalVariables(object):
device_trackers_cnt = 0 # Number of device_trackers that will be creted (__init__.py)
device_trackers_created_cnt = 0 # Number of device_trackers that have been set up (incremented in device_tracker.py)
area_id_personal_device = None

# restore_state file
restore_state_file_data = {}
restore_state_profile = {}
Expand Down Expand Up @@ -312,6 +312,7 @@ class GlobalVariables(object):
used_data_source_FAMSHR = False
used_data_source_FMF = False
used_data_source_IOSAPP = False
iosapp_monitor_any_devices_false_flag = False

# Primary data source being used that can be turned off if errors
primary_data_source_ICLOUD = conf_data_source_ICLOUD
Expand Down
11 changes: 11 additions & 0 deletions custom_components/icloud3/helpers/time_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 """
Expand Down Expand Up @@ -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:
Expand Down
Loading

0 comments on commit 91d89d4

Please sign in to comment.