1 """Support for non-delivered packages recorded in AfterShip."""
3 from __future__
import annotations
6 from typing
import Any, Final
8 from pyaftership
import AfterShip, AfterShipException
14 async_dispatcher_connect,
15 async_dispatcher_send,
20 from .
import AfterShipConfigEntry
22 ADD_TRACKING_SERVICE_SCHEMA,
30 MIN_TIME_BETWEEN_UPDATES,
31 REMOVE_TRACKING_SERVICE_SCHEMA,
33 SERVICE_REMOVE_TRACKING,
37 _LOGGER: Final = logging.getLogger(__name__)
39 PLATFORM_SCHEMA: Final = cv.removed(DOMAIN, raise_if_present=
False)
44 config_entry: AfterShipConfigEntry,
45 async_add_entities: AddEntitiesCallback,
47 """Set up AfterShip sensor entities based on a config entry."""
48 aftership = config_entry.runtime_data
52 async
def handle_add_tracking(call: ServiceCall) ->
None:
53 """Call when a user adds a new Aftership tracking from Home Assistant."""
54 await aftership.trackings.add(
55 tracking_number=call.data[CONF_TRACKING_NUMBER],
56 title=call.data.get(CONF_TITLE),
57 slug=call.data.get(CONF_SLUG),
61 hass.services.async_register(
65 schema=ADD_TRACKING_SERVICE_SCHEMA,
68 async
def handle_remove_tracking(call: ServiceCall) ->
None:
69 """Call when a user removes an Aftership tracking from Home Assistant."""
70 await aftership.trackings.remove(
71 tracking_number=call.data[CONF_TRACKING_NUMBER],
72 slug=call.data[CONF_SLUG],
76 hass.services.async_register(
78 SERVICE_REMOVE_TRACKING,
79 handle_remove_tracking,
80 schema=REMOVE_TRACKING_SERVICE_SCHEMA,
85 """Representation of a AfterShip sensor."""
87 _attr_attribution = ATTRIBUTION
88 _attr_native_unit_of_measurement: str =
"packages"
89 _attr_translation_key =
"packages"
91 def __init__(self, aftership: AfterShip, name: str) ->
None:
92 """Initialize the sensor."""
94 self.
_state_state: int |
None =
None
100 """Return the state of the sensor."""
105 """Return attributes for the sensor."""
109 """Register callbacks."""
115 """Force update of data."""
119 @Throttle(MIN_TIME_BETWEEN_UPDATES)
121 """Get the latest data from the AfterShip API."""
123 trackings = await self.
aftershipaftership.trackings.list()
124 except AfterShipException
as err:
125 _LOGGER.error(
"Errors when querying AfterShip - %s", err)
128 status_to_ignore = {
"delivered"}
129 status_counts: dict[str, int] = {}
130 parsed_trackings = []
131 not_delivered_count = 0
133 for track
in trackings[
"trackings"]:
134 status = track[
"tag"].lower()
136 track[
"tracking_number"]
if track[
"title"]
is None else track[
"title"]
139 f
"Shipment {track['tag'].lower()}"
140 if not track[
"checkpoints"]
141 else track[
"checkpoints"][-1]
143 status_counts[status] = status_counts.get(status, 0) + 1
144 parsed_trackings.append(
147 "tracking_number": track[
"tracking_number"],
148 "slug": track[
"slug"],
149 "link": f
"{BASE}{track['slug']}/{track['tracking_number']}",
150 "last_update": track[
"updated_at"],
151 "expected_delivery": track[
"expected_delivery"],
152 "status": track[
"tag"],
153 "last_checkpoint": last_checkpoint,
157 if status
not in status_to_ignore:
158 not_delivered_count += 1
160 _LOGGER.debug(
"Ignoring %s as it has status: %s", name, status)
164 ATTR_TRACKINGS: parsed_trackings,
int|None native_value(self)
None async_update(self, **Any kwargs)
dict[str, str] extra_state_attributes(self)
None __init__(self, AfterShip aftership, str name)
None async_added_to_hass(self)
None async_write_ha_state(self)
None async_on_remove(self, CALLBACK_TYPE func)
None async_setup_entry(HomeAssistant hass, AfterShipConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)