python-casahome 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- casahome/__init__.py +30 -0
- casahome/_base_http.py +21 -0
- casahome/api.py +1135 -0
- casahome/auth.py +199 -0
- casahome/client.py +168 -0
- casahome/const.py +34 -0
- casahome/exceptions.py +52 -0
- casahome/models/__init__.py +477 -0
- casahome/models/_base.py +25 -0
- casahome/models/ai.py +58 -0
- casahome/models/assets.py +123 -0
- casahome/models/availability.py +39 -0
- casahome/models/bootstrap.py +134 -0
- casahome/models/calendar.py +33 -0
- casahome/models/catalogs.py +73 -0
- casahome/models/credits.py +29 -0
- casahome/models/documents.py +127 -0
- casahome/models/enums.py +183 -0
- casahome/models/feed.py +30 -0
- casahome/models/help_center.py +45 -0
- casahome/models/home.py +175 -0
- casahome/models/images.py +48 -0
- casahome/models/mailbox.py +160 -0
- casahome/models/maintenance.py +200 -0
- casahome/models/membership.py +65 -0
- casahome/models/paint.py +56 -0
- casahome/models/preferences.py +104 -0
- casahome/models/purchases.py +106 -0
- casahome/models/read_todos.py +22 -0
- casahome/models/referral.py +21 -0
- casahome/models/requests.py +149 -0
- casahome/models/tasks.py +77 -0
- casahome/models/taxes.py +47 -0
- casahome/models/todos.py +52 -0
- casahome/models/visits.py +158 -0
- casahome/models/write_contracts.py +147 -0
- casahome/py.typed +0 -0
- casahome/streaming.py +278 -0
- python_casahome-0.2.0.dist-info/METADATA +272 -0
- python_casahome-0.2.0.dist-info/RECORD +42 -0
- python_casahome-0.2.0.dist-info/WHEEL +4 -0
- python_casahome-0.2.0.dist-info/licenses/LICENSE +21 -0
casahome/models/home.py
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""Home inventory and weather models.
|
|
2
|
+
|
|
3
|
+
Inventory entity fields are live-verified against ``inventory/v3`` (2026-10).
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from pydantic import Field
|
|
12
|
+
|
|
13
|
+
from ._base import CasaModel, epoch_to_dt
|
|
14
|
+
from .enums import WeatherConditionField
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SimpleEntityProp(CasaModel):
|
|
18
|
+
id: str
|
|
19
|
+
definition_id: str
|
|
20
|
+
title: str
|
|
21
|
+
key: str
|
|
22
|
+
value: Any = None
|
|
23
|
+
data_type: str | None = None
|
|
24
|
+
is_required_to_publish: bool = False
|
|
25
|
+
is_readonly: bool = False
|
|
26
|
+
format: str | None = None
|
|
27
|
+
enum_details: Any | None = None # TODO: unresolved type SimpleEntityEnumProp
|
|
28
|
+
multi_enums: list[Any] = Field(default_factory=list)
|
|
29
|
+
enum_type: str | None = None
|
|
30
|
+
symbol_name: str | None = None
|
|
31
|
+
help_center_article_id: str | None = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class HomeRoom(CasaModel):
|
|
35
|
+
id: str
|
|
36
|
+
name: str
|
|
37
|
+
is_removable: bool = False
|
|
38
|
+
room_type_id: str | None = None
|
|
39
|
+
image_url: str | None = None
|
|
40
|
+
image_url_cache_key: str | None = None
|
|
41
|
+
room_properties: list[SimpleEntityProp] = Field(default_factory=list)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class HomeStory(CasaModel):
|
|
45
|
+
id: str
|
|
46
|
+
floor_number: int
|
|
47
|
+
name: str
|
|
48
|
+
window_count: int | None = None
|
|
49
|
+
rooms: list[HomeRoom] = Field(default_factory=list)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class HomeDetails(CasaModel):
|
|
53
|
+
id: str
|
|
54
|
+
display_address: str
|
|
55
|
+
stories: list[HomeStory] = Field(default_factory=list)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
PropertyValue = str | int | float | bool | None
|
|
59
|
+
"""Scalar value carried by entity and catalog model properties (live-verified)."""
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class EntityProperty(SimpleEntityProp):
|
|
63
|
+
"""A typed property on an inventory entity, e.g. ``serial_number``.
|
|
64
|
+
|
|
65
|
+
Same wire shape as :class:`SimpleEntityProp`, but the value is narrowed to
|
|
66
|
+
the scalar types observed live on ``inventory/v3``.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
value: PropertyValue = None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class EntityMake(CasaModel):
|
|
73
|
+
id: str
|
|
74
|
+
name: str
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ModelProperty(CasaModel):
|
|
78
|
+
"""A catalog property on a make/model, e.g. key ``summary``."""
|
|
79
|
+
|
|
80
|
+
id: str
|
|
81
|
+
key: str
|
|
82
|
+
caption: str | None = None
|
|
83
|
+
value: PropertyValue = None
|
|
84
|
+
data_type: str | None = None
|
|
85
|
+
format: str | None = None
|
|
86
|
+
symbol_name: str | None = None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class EntityModel(CasaModel):
|
|
90
|
+
id: str
|
|
91
|
+
name: str
|
|
92
|
+
properties: list[ModelProperty] = Field(default_factory=list)
|
|
93
|
+
|
|
94
|
+
def property_value(self, key: str) -> PropertyValue:
|
|
95
|
+
"""Return the value of the first catalog property with ``key``, else None."""
|
|
96
|
+
return next((p.value for p in self.properties if p.key == key), None)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class EntityIdentity(CasaModel):
|
|
100
|
+
"""How confidently Casa has identified the make and model."""
|
|
101
|
+
|
|
102
|
+
state: str | None = None
|
|
103
|
+
unverified_make: str | None = None
|
|
104
|
+
unverified_model: str | None = None
|
|
105
|
+
candidates: list[Any] = Field(default_factory=list)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class EntityImage(CasaModel):
|
|
109
|
+
"""Image metadata. URL and cache-key fields ride along in ``model_extra``."""
|
|
110
|
+
|
|
111
|
+
id: str
|
|
112
|
+
name: str | None = None
|
|
113
|
+
role: str | None = None
|
|
114
|
+
is_hero: bool = False
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class SimpleEntity(CasaModel):
|
|
118
|
+
"""An inventory item (appliance, fixture, etc.) from ``inventory/v3``."""
|
|
119
|
+
|
|
120
|
+
id: str
|
|
121
|
+
category_id: str
|
|
122
|
+
category: str
|
|
123
|
+
status: str
|
|
124
|
+
type_id: str | None = None
|
|
125
|
+
type: str | None = None
|
|
126
|
+
type_symbol_name: str | None = None
|
|
127
|
+
created_at: int | None = None
|
|
128
|
+
inventoried_by: str | None = None
|
|
129
|
+
failure_reason: str | None = None
|
|
130
|
+
failure_item_label: str | None = None
|
|
131
|
+
issues: list[Any] = Field(default_factory=list)
|
|
132
|
+
rooms: list[str] = Field(default_factory=list)
|
|
133
|
+
stories: list[str] = Field(default_factory=list)
|
|
134
|
+
images: list[EntityImage] = Field(default_factory=list)
|
|
135
|
+
manuals: list[Any] = Field(default_factory=list)
|
|
136
|
+
thumbnail_url: str | None = None
|
|
137
|
+
thumbnail_url_cache_key: str | None = None
|
|
138
|
+
catalog_make_requirement: str | None = None
|
|
139
|
+
catalog_model_requirement: str | None = None
|
|
140
|
+
catalog_model_required: bool | None = None
|
|
141
|
+
make: EntityMake | None = None
|
|
142
|
+
model: EntityModel | None = None
|
|
143
|
+
identity: EntityIdentity | None = None
|
|
144
|
+
entity_properties: list[EntityProperty] = Field(default_factory=list)
|
|
145
|
+
associated_entity_ids: list[str] | None = None
|
|
146
|
+
is_removable: bool = False
|
|
147
|
+
is_retypable: bool | None = None
|
|
148
|
+
removal_blocked_reason: str | None = None
|
|
149
|
+
paint_match: Any | None = None
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def created_at_dt(self) -> datetime | None:
|
|
153
|
+
return epoch_to_dt(self.created_at)
|
|
154
|
+
|
|
155
|
+
def property_value(self, key: str) -> PropertyValue:
|
|
156
|
+
"""Return the value of the first entity property with ``key``, else None.
|
|
157
|
+
|
|
158
|
+
Example: ``entity.property_value("serial_number")``.
|
|
159
|
+
"""
|
|
160
|
+
return next((p.value for p in self.entity_properties if p.key == key), None)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class HomeDetailsResponse(CasaModel):
|
|
164
|
+
home: HomeDetails
|
|
165
|
+
entities: list[SimpleEntity] = Field(default_factory=list)
|
|
166
|
+
room_entity_map: dict[str, list[str]] = Field(default_factory=dict)
|
|
167
|
+
associated_entities: dict[str, list[str]] = Field(default_factory=dict)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
class WeatherResponse(CasaModel):
|
|
171
|
+
temperature_degrees: float
|
|
172
|
+
temperature_units: str
|
|
173
|
+
condition_type: WeatherConditionField
|
|
174
|
+
sunrise_at: int | None = None
|
|
175
|
+
sunset_at: int | None = None
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""Photo metadata only. These models never fetch their URL strings."""
|
|
2
|
+
|
|
3
|
+
from pydantic import RootModel
|
|
4
|
+
|
|
5
|
+
from casahome.models._base import CasaModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RoomImageCandidate(CasaModel):
|
|
9
|
+
id: str
|
|
10
|
+
image_url: str
|
|
11
|
+
cache_key: str
|
|
12
|
+
is_current: bool
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RoomMemberImage(CasaModel):
|
|
16
|
+
"""UNVERIFIED populated member image. Static Codable fields."""
|
|
17
|
+
|
|
18
|
+
image_url: str | None = None
|
|
19
|
+
cache_key: str | None = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class RoomImageOptionsResponse(CasaModel):
|
|
23
|
+
matterport_images: list[RoomImageCandidate]
|
|
24
|
+
member_image: RoomMemberImage | None = None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MatterportImage(CasaModel):
|
|
28
|
+
id: str
|
|
29
|
+
image_url: str
|
|
30
|
+
cache_key: str
|
|
31
|
+
is_home_hero_image: bool
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class MatterportImagesResponse(RootModel[list[MatterportImage]]):
|
|
35
|
+
"""Bare list of populated image metadata."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class MediaAttachment(CasaModel):
|
|
39
|
+
"""Observed on to-dos. created_at is static and wasn't present there."""
|
|
40
|
+
|
|
41
|
+
id: str
|
|
42
|
+
name: str
|
|
43
|
+
mimetype: str
|
|
44
|
+
size: int
|
|
45
|
+
url: str
|
|
46
|
+
cache_key: str
|
|
47
|
+
thumbnail_url: str | None = None
|
|
48
|
+
created_at: int | None = None
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Mailbox and package models (UNVERIFIED endpoints).
|
|
2
|
+
|
|
3
|
+
Mailbox models use ISO 8601 string timestamps. Packages use epoch seconds.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from pydantic import Field
|
|
11
|
+
|
|
12
|
+
from ._base import CasaModel
|
|
13
|
+
from .enums import PackageDirectionField, PackagePickupStatusField
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MailboxAddress(CasaModel):
|
|
17
|
+
line1: str
|
|
18
|
+
city: str
|
|
19
|
+
state: str
|
|
20
|
+
postal_code: str
|
|
21
|
+
line2: str | None = None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class MailboxQuota(CasaModel):
|
|
25
|
+
month: str
|
|
26
|
+
used: int
|
|
27
|
+
included: int
|
|
28
|
+
overage_rate_usd_cents: int
|
|
29
|
+
resets_on: str | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class MailboxRecipient(CasaModel):
|
|
33
|
+
id: str
|
|
34
|
+
kind: str
|
|
35
|
+
always_included: bool = False
|
|
36
|
+
first_name: str | None = None
|
|
37
|
+
last_name: str | None = None
|
|
38
|
+
business_name: str | None = None
|
|
39
|
+
is_primary: bool | None = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class MemberMailbox(CasaModel):
|
|
43
|
+
id: str
|
|
44
|
+
status: str
|
|
45
|
+
onboarding_status: str
|
|
46
|
+
address: MailboxAddress
|
|
47
|
+
quota: MailboxQuota
|
|
48
|
+
claimed_at: str
|
|
49
|
+
recipients: list[MailboxRecipient] = Field(default_factory=list)
|
|
50
|
+
auto_archive_days: int | None = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class MailboxPlan(CasaModel):
|
|
54
|
+
monthly_piece_quota: int
|
|
55
|
+
overage_rate_usd_cents: int
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class MailboxOverviewResponse(CasaModel):
|
|
59
|
+
mailbox: MemberMailbox | None = None
|
|
60
|
+
plan: MailboxPlan | None = None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class MailboxMailItem(CasaModel):
|
|
64
|
+
id: str
|
|
65
|
+
scan_status: str
|
|
66
|
+
received_at: str
|
|
67
|
+
is_returned_to_sender: bool = False
|
|
68
|
+
check_detected: bool = False
|
|
69
|
+
sender: str | None = None
|
|
70
|
+
addressed_to: str | None = None
|
|
71
|
+
summary: str | None = None
|
|
72
|
+
scan_notice_type: str | None = None
|
|
73
|
+
clear_at: str | None = None
|
|
74
|
+
forward_status: str | None = None
|
|
75
|
+
forward_tracking_number: str | None = None
|
|
76
|
+
shred_status: str | None = None
|
|
77
|
+
deposit_status: str | None = None
|
|
78
|
+
archived_at: str | None = None
|
|
79
|
+
read_at: str | None = None
|
|
80
|
+
envelope_image_url: str | None = None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class MailboxMailItemsResponse(CasaModel):
|
|
84
|
+
mail_items: list[MailboxMailItem] = Field(default_factory=list)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class TrackingHistoryData(CasaModel):
|
|
88
|
+
id: str
|
|
89
|
+
source: str
|
|
90
|
+
message: str
|
|
91
|
+
timestamp: int
|
|
92
|
+
status_display_name: str
|
|
93
|
+
status_detail_display_name: str
|
|
94
|
+
city: str | None = None
|
|
95
|
+
state: str | None = None
|
|
96
|
+
country: str | None = None
|
|
97
|
+
zip: str | None = None
|
|
98
|
+
timezone: str | None = None
|
|
99
|
+
latitude: float | None = None
|
|
100
|
+
longitude: float | None = None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class PackageCarrierInfo(CasaModel):
|
|
104
|
+
carrier_id: str
|
|
105
|
+
display_name: str
|
|
106
|
+
logo_url: str
|
|
107
|
+
primary_color: str
|
|
108
|
+
pickup_eligible: bool = False
|
|
109
|
+
trackable: bool = False
|
|
110
|
+
secondary_color: str | None = None
|
|
111
|
+
pickup_requirements: list[Any] | None = None
|
|
112
|
+
pickup_qr_regex: str | None = None
|
|
113
|
+
pickup_category: str | None = None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class PackageItem(CasaModel):
|
|
117
|
+
id: str
|
|
118
|
+
carrier_id: str
|
|
119
|
+
created_at: int
|
|
120
|
+
updated_at: int
|
|
121
|
+
status: str
|
|
122
|
+
status_detail: str
|
|
123
|
+
direction: PackageDirectionField
|
|
124
|
+
archived: bool = False
|
|
125
|
+
is_pickup: bool = False
|
|
126
|
+
can_archive: bool = False
|
|
127
|
+
suggest_archive: bool = False
|
|
128
|
+
tracking_number: str | None = None
|
|
129
|
+
weight: float | None = None
|
|
130
|
+
est_delivery_date: int | None = None
|
|
131
|
+
signed_by: str | None = None
|
|
132
|
+
service: str | None = None
|
|
133
|
+
container_type: str | None = None
|
|
134
|
+
origin_city: str | None = None
|
|
135
|
+
origin_state: str | None = None
|
|
136
|
+
origin_zip: str | None = None
|
|
137
|
+
origin_country: str | None = None
|
|
138
|
+
name: str | None = None
|
|
139
|
+
tracking_history: list[TrackingHistoryData] = Field(default_factory=list)
|
|
140
|
+
pickup_amazon_location: Any | None = None
|
|
141
|
+
pickup_qr_code: str | None = None
|
|
142
|
+
pickup_image_url: str | None = None
|
|
143
|
+
pickup_image_url_cache_key: str | None = None
|
|
144
|
+
pickup_status: PackagePickupStatusField | None = None
|
|
145
|
+
purchased_item: Any | None = None
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class PackagesResponse(CasaModel):
|
|
149
|
+
next_pickup_lockdown: int
|
|
150
|
+
next_pickup_start: int
|
|
151
|
+
next_pickup_end: int
|
|
152
|
+
current_pickup_lockdown: int | None = None
|
|
153
|
+
current_pickup_start: int | None = None
|
|
154
|
+
current_pickup_end: int | None = None
|
|
155
|
+
carriers: list[PackageCarrierInfo] = Field(default_factory=list)
|
|
156
|
+
packages: list[PackageItem] = Field(default_factory=list)
|
|
157
|
+
next_pickup_item_ids: list[str] = Field(default_factory=list)
|
|
158
|
+
current_pickup_item_ids: list[str] = Field(default_factory=list)
|
|
159
|
+
package_auto_archive_days: int | None = None
|
|
160
|
+
package_tracking_inbound_email: str | None = None
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Autopilot and inventory service history.
|
|
2
|
+
|
|
3
|
+
Autopilot's populated variants were observed in the saved follow-up response.
|
|
4
|
+
Service history lists were empty. Their item fields come from static Codable data.
|
|
5
|
+
String discriminators stay open to future server values.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pydantic import RootModel
|
|
9
|
+
|
|
10
|
+
from casahome.models._base import CasaModel
|
|
11
|
+
from casahome.models.requests import Pagination, RequestCard
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class AutopilotRequirementOption(CasaModel):
|
|
15
|
+
type_id: str
|
|
16
|
+
name: str
|
|
17
|
+
symbol_name: str | None = None
|
|
18
|
+
help_center_article_id: str | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AutopilotRequirementProperty(CasaModel):
|
|
22
|
+
definition_id: str
|
|
23
|
+
entity_type_id: str
|
|
24
|
+
title: str
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AutopilotRequirementRoomProperty(CasaModel):
|
|
28
|
+
definition_id: str
|
|
29
|
+
title: str
|
|
30
|
+
data_type: str
|
|
31
|
+
symbol_name: str | None = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AutopilotRequirementRoomCandidate(CasaModel):
|
|
35
|
+
room_id: str
|
|
36
|
+
name: str
|
|
37
|
+
story_name: str
|
|
38
|
+
story_floor_number: int
|
|
39
|
+
duration_minutes: int
|
|
40
|
+
image_url: str | None = None
|
|
41
|
+
image_url_cache_key: str | None = None
|
|
42
|
+
price_usd_cents: int | None = None
|
|
43
|
+
property_value: bool | None = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AutopilotPlanRequirement(CasaModel):
|
|
47
|
+
kind: str
|
|
48
|
+
options: list[AutopilotRequirementOption]
|
|
49
|
+
noun_with_article: str | None = None
|
|
50
|
+
property: AutopilotRequirementProperty | None = None
|
|
51
|
+
room_property: AutopilotRequirementRoomProperty | None = None
|
|
52
|
+
room_candidates: list[AutopilotRequirementRoomCandidate] | None = None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class AutopilotIllustration(CasaModel):
|
|
56
|
+
bg_color: str
|
|
57
|
+
url: str | None = None
|
|
58
|
+
url_cache_key: str | None = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class AutopilotPricingPolicy(CasaModel):
|
|
62
|
+
symbol_name: str
|
|
63
|
+
title: str
|
|
64
|
+
description: str
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AutopilotHomeAssociation(CasaModel):
|
|
68
|
+
id: str
|
|
69
|
+
duration_minutes: int
|
|
70
|
+
enabled: bool | None = None
|
|
71
|
+
price_usd_cents: int | None = None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class AutopilotRoomAssociation(CasaModel):
|
|
75
|
+
id: str
|
|
76
|
+
room_id: str
|
|
77
|
+
room_name: str
|
|
78
|
+
room_story_name: str
|
|
79
|
+
duration_minutes: int
|
|
80
|
+
enabled: bool | None = None
|
|
81
|
+
room_image_url: str | None = None
|
|
82
|
+
room_image_cache_key: str | None = None
|
|
83
|
+
price_usd_cents: int | None = None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
class AutopilotEntityAssociation(CasaModel):
|
|
87
|
+
id: str
|
|
88
|
+
entity_id: str
|
|
89
|
+
entity_make: str
|
|
90
|
+
entity_model: str
|
|
91
|
+
duration_minutes: int
|
|
92
|
+
enabled: bool | None = None
|
|
93
|
+
entity_display_name: str | None = None
|
|
94
|
+
entity_location: str | None = None
|
|
95
|
+
entity_image_url: str | None = None
|
|
96
|
+
entity_image_cache_key: str | None = None
|
|
97
|
+
price_usd_cents: int | None = None
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class AutopilotPlan(CasaModel):
|
|
101
|
+
plan_id: str
|
|
102
|
+
plan_template_id: str
|
|
103
|
+
title: str
|
|
104
|
+
subtitle: str
|
|
105
|
+
description: str
|
|
106
|
+
applies_to: str
|
|
107
|
+
type: str
|
|
108
|
+
enabled: bool
|
|
109
|
+
illustration: AutopilotIllustration
|
|
110
|
+
asap_schedule_description: str
|
|
111
|
+
pricing_policies: list[AutopilotPricingPolicy]
|
|
112
|
+
fulfillment_policy: str
|
|
113
|
+
savings_percentage: int
|
|
114
|
+
cadence_options: list[str]
|
|
115
|
+
default_cadence: str
|
|
116
|
+
next_projected_occurrence_range_start: str
|
|
117
|
+
next_projected_occurrence_range_end: str
|
|
118
|
+
room_associations: list[AutopilotRoomAssociation]
|
|
119
|
+
entity_associations: list[AutopilotEntityAssociation]
|
|
120
|
+
requirement: AutopilotPlanRequirement | None = None
|
|
121
|
+
handyman_credit_policy: str | None = None
|
|
122
|
+
selected_cadence: str | None = None
|
|
123
|
+
next_desired_occurrence_date: str | None = None
|
|
124
|
+
next_calendar_event_start_at: int | None = None
|
|
125
|
+
home_association: AutopilotHomeAssociation | None = None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class AutopilotIneligiblePlan(CasaModel):
|
|
129
|
+
plan_template_id: str
|
|
130
|
+
title: str
|
|
131
|
+
subtitle: str
|
|
132
|
+
description: str
|
|
133
|
+
type: str
|
|
134
|
+
fulfillment_policy: str
|
|
135
|
+
illustration: AutopilotIllustration
|
|
136
|
+
requirement: AutopilotPlanRequirement
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class AutopilotCategory(CasaModel):
|
|
140
|
+
category_id: str
|
|
141
|
+
category_title: str
|
|
142
|
+
category_description: str
|
|
143
|
+
category_rendering_type: str
|
|
144
|
+
plans: list[AutopilotPlan]
|
|
145
|
+
ineligible_plans: list[AutopilotIneligiblePlan]
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class AutopilotCategoriesResponse(RootModel[list[AutopilotCategory]]):
|
|
149
|
+
"""The wire response is a bare list, not a plans envelope."""
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class ServiceHistoryPlan(CasaModel):
|
|
153
|
+
"""UNVERIFIED item. Known static fields are optional to tolerate drift."""
|
|
154
|
+
|
|
155
|
+
id: str | None = None
|
|
156
|
+
enabled: bool | None = None
|
|
157
|
+
title: str | None = None
|
|
158
|
+
selected_cadence: str | None = None
|
|
159
|
+
next_service_at: int | None = None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class ServiceHistoryItem(CasaModel):
|
|
163
|
+
"""UNVERIFIED item from static Codable metadata."""
|
|
164
|
+
|
|
165
|
+
task_id: str | None = None
|
|
166
|
+
task_type: str | None = None
|
|
167
|
+
task_title: str | None = None
|
|
168
|
+
task_emoji: str | None = None
|
|
169
|
+
serviced_at: int | None = None
|
|
170
|
+
task_hero_image_url: str | None = None
|
|
171
|
+
task_hero_image_cache_key: str | None = None
|
|
172
|
+
handyman_job_id: str | None = None
|
|
173
|
+
vendor_visit_id: str | None = None
|
|
174
|
+
autopilot_plan_id: str | None = None
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class InventoryServiceHistoryResponse(CasaModel):
|
|
178
|
+
autopilot_plans: list[ServiceHistoryPlan]
|
|
179
|
+
history_items: list[ServiceHistoryItem]
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class CalendarBusyBlock(CasaModel):
|
|
183
|
+
"""UNVERIFIED block from static Codable metadata."""
|
|
184
|
+
|
|
185
|
+
start_time: int | None = None
|
|
186
|
+
end_time: int | None = None
|
|
187
|
+
title: str | None = None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class CalendarBusyResponse(CasaModel):
|
|
191
|
+
blocks: list[CalendarBusyBlock]
|
|
192
|
+
google_status: str
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
class CompletedRequestsResponse(CasaModel):
|
|
196
|
+
"""Empty list observed. RequestCard is the existing static item model."""
|
|
197
|
+
|
|
198
|
+
kind: str
|
|
199
|
+
items: list[RequestCard]
|
|
200
|
+
pagination: Pagination
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Static membership summaries, not billing or lifecycle action contracts.
|
|
2
|
+
|
|
3
|
+
Fields inferred from the app.
|
|
4
|
+
All fields and response linkage remain UNVERIFIED. Cents/seconds are retained
|
|
5
|
+
as named, without inventing a reporting period, currency or timezone.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pydantic import JsonValue
|
|
9
|
+
|
|
10
|
+
from casahome.models._base import CasaModel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MembershipBenefit(CasaModel):
|
|
14
|
+
# The app's id type isn't known to be a String, so keep it as JSON.
|
|
15
|
+
id: JsonValue
|
|
16
|
+
title: str
|
|
17
|
+
emoji: str
|
|
18
|
+
symbol: str
|
|
19
|
+
description: str
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MembershipDetails(CasaModel):
|
|
23
|
+
name: str
|
|
24
|
+
amount: str
|
|
25
|
+
amount_cents: int | None = None
|
|
26
|
+
interval: str
|
|
27
|
+
next_billing_date: int | None = None
|
|
28
|
+
member_since: int | None = None
|
|
29
|
+
benefits: list[MembershipBenefit] | None = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class MembershipSavingsSummary(CasaModel):
|
|
33
|
+
total_time_saved_seconds: int
|
|
34
|
+
total_money_saved_cents: int
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class MembershipSavingsBreakdown(CasaModel):
|
|
38
|
+
title: str
|
|
39
|
+
value: str
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class MembershipSavingsCategory(CasaModel):
|
|
43
|
+
type: str
|
|
44
|
+
label: str
|
|
45
|
+
color: str
|
|
46
|
+
preview: str | None = None
|
|
47
|
+
is_visible: bool
|
|
48
|
+
time_saved_seconds: int
|
|
49
|
+
money_saved_cents: int
|
|
50
|
+
breakdown: list[MembershipSavingsBreakdown]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class MembershipSavingsMetadata(CasaModel):
|
|
54
|
+
id: str
|
|
55
|
+
created_at: str
|
|
56
|
+
updated_at: str
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MembershipSavings(CasaModel):
|
|
60
|
+
home_id: str
|
|
61
|
+
calculated_at: str
|
|
62
|
+
should_promote: bool
|
|
63
|
+
summary: MembershipSavingsSummary
|
|
64
|
+
categories: list[MembershipSavingsCategory]
|
|
65
|
+
metadata: MembershipSavingsMetadata
|
casahome/models/paint.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Paint library models. Populated integer IDs were observed, not UUIDs."""
|
|
2
|
+
|
|
3
|
+
from casahome.models._base import CasaModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PaintBrand(CasaModel):
|
|
7
|
+
id: int | str
|
|
8
|
+
color_count: int
|
|
9
|
+
name: str | None = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PaintCollection(CasaModel):
|
|
13
|
+
id: int | str
|
|
14
|
+
color_count: int
|
|
15
|
+
name: str | None = None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PaintColor(CasaModel):
|
|
19
|
+
id: int | str
|
|
20
|
+
color_name: str | None = None
|
|
21
|
+
collection_name: str | None = None
|
|
22
|
+
brand_name: str | None = None
|
|
23
|
+
color_hex: str | None = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PaintBrandsResponse(CasaModel):
|
|
27
|
+
brands: list[PaintBrand]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class PaintCollectionsResponse(CasaModel):
|
|
31
|
+
collections: list[PaintCollection]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PaintColorsResponse(CasaModel):
|
|
35
|
+
colors: list[PaintColor]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class PaintSearchResponse(CasaModel):
|
|
39
|
+
results: list[PaintColor]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class InventoryPaintMatch(CasaModel):
|
|
43
|
+
"""One paint match. VERIFIED populated (live GET, 2026-10)."""
|
|
44
|
+
|
|
45
|
+
id: int
|
|
46
|
+
color_name: str
|
|
47
|
+
brand_name: str
|
|
48
|
+
color_hex: str
|
|
49
|
+
closeness_percentage: float
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class InventoryPaintMatchesResponse(CasaModel):
|
|
53
|
+
"""Paint matches. VERIFIED envelope (live GET, 2026-10). No match application."""
|
|
54
|
+
|
|
55
|
+
matches: list[InventoryPaintMatch]
|
|
56
|
+
is_manually_added: bool
|