pyvesync 3.0.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.
- pyvesync/__init__.py +5 -0
- pyvesync/base_devices/__init__.py +35 -0
- pyvesync/base_devices/bulb_base.py +330 -0
- pyvesync/base_devices/fan_base.py +392 -0
- pyvesync/base_devices/fryer_base.py +68 -0
- pyvesync/base_devices/humidifier_base.py +462 -0
- pyvesync/base_devices/outlet_base.py +327 -0
- pyvesync/base_devices/purifier_base.py +525 -0
- pyvesync/base_devices/switch_base.py +271 -0
- pyvesync/base_devices/thermostat_base.py +283 -0
- pyvesync/base_devices/vesyncbasedevice.py +572 -0
- pyvesync/const.py +825 -0
- pyvesync/device_container.py +373 -0
- pyvesync/device_map.py +1172 -0
- pyvesync/devices/__init__.py +1 -0
- pyvesync/devices/vesyncbulb.py +1126 -0
- pyvesync/devices/vesyncfan.py +233 -0
- pyvesync/devices/vesynchumidifier.py +808 -0
- pyvesync/devices/vesynckitchen.py +651 -0
- pyvesync/devices/vesyncoutlet.py +954 -0
- pyvesync/devices/vesyncpurifier.py +990 -0
- pyvesync/devices/vesyncswitch.py +415 -0
- pyvesync/devices/vesyncthermostat.py +171 -0
- pyvesync/models/__init__.py +11 -0
- pyvesync/models/base_models.py +129 -0
- pyvesync/models/bulb_models.py +197 -0
- pyvesync/models/bypass_models.py +289 -0
- pyvesync/models/fan_models.py +47 -0
- pyvesync/models/fryer_models.py +34 -0
- pyvesync/models/home_models.py +169 -0
- pyvesync/models/humidifier_models.py +202 -0
- pyvesync/models/outlet_models.py +220 -0
- pyvesync/models/purifier_models.py +261 -0
- pyvesync/models/switch_models.py +101 -0
- pyvesync/models/thermostat_models.py +134 -0
- pyvesync/models/vesync_models.py +439 -0
- pyvesync/utils/__init__.py +1 -0
- pyvesync/utils/colors.py +250 -0
- pyvesync/utils/device_mixins.py +362 -0
- pyvesync/utils/enum_utils.py +26 -0
- pyvesync/utils/errors.py +867 -0
- pyvesync/utils/helpers.py +700 -0
- pyvesync/utils/logs.py +525 -0
- pyvesync/vesync.py +638 -0
- pyvesync/vesynchome.py +152 -0
- pyvesync-3.0.0.dist-info/METADATA +567 -0
- pyvesync-3.0.0.dist-info/RECORD +50 -0
- pyvesync-3.0.0.dist-info/WHEEL +5 -0
- pyvesync-3.0.0.dist-info/licenses/LICENSE +21 -0
- pyvesync-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Base data models for API requests and response.
|
|
2
|
+
|
|
3
|
+
These models are used to define the structure of the requests and
|
|
4
|
+
responses from the API. They use Mashumaro for serialization and
|
|
5
|
+
deserialization. The `DataClassConfigMixin` class sets default options
|
|
6
|
+
for `orjson` and `Mashumaro`.
|
|
7
|
+
|
|
8
|
+
Note:
|
|
9
|
+
Dataclasses should follow the naming convention of
|
|
10
|
+
Request/Response + API Name. Internal models can have any descriptive
|
|
11
|
+
name.
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
All models should inherit `ResponseBaseModel` or `RequestBaseModel`. Use
|
|
15
|
+
[pyvesync.const][pyvesync.const] to set default values and import here.
|
|
16
|
+
|
|
17
|
+
Attributes are inherited from the [const][pyvesync.const] module for
|
|
18
|
+
default values.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from dataclasses import dataclass
|
|
24
|
+
from time import time
|
|
25
|
+
from typing import ClassVar
|
|
26
|
+
|
|
27
|
+
import orjson
|
|
28
|
+
from mashumaro.config import BaseConfig
|
|
29
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
30
|
+
|
|
31
|
+
from pyvesync.const import (
|
|
32
|
+
APP_ID,
|
|
33
|
+
APP_VERSION,
|
|
34
|
+
BYPASS_HEADER_UA,
|
|
35
|
+
CLIENT_TYPE,
|
|
36
|
+
DEFAULT_LANGUAGE,
|
|
37
|
+
DEFAULT_REGION,
|
|
38
|
+
DEFAULT_TZ,
|
|
39
|
+
MOBILE_ID,
|
|
40
|
+
PHONE_BRAND,
|
|
41
|
+
PHONE_OS,
|
|
42
|
+
TERMINAL_ID,
|
|
43
|
+
USER_TYPE,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
RequestHeaders = {
|
|
47
|
+
'User-Agent': BYPASS_HEADER_UA,
|
|
48
|
+
'Content-Type': 'application/json; charset=UTF-8',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class BaseModelConfig(BaseConfig):
|
|
53
|
+
"""Base config for dataclasses."""
|
|
54
|
+
|
|
55
|
+
orjson_options = orjson.OPT_NON_STR_KEYS
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass
|
|
59
|
+
class RequestBaseModel(DataClassORJSONMixin):
|
|
60
|
+
"""Base request model for API requests.
|
|
61
|
+
|
|
62
|
+
Forbids extra keys in the request JSON.
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
class Config(BaseModelConfig):
|
|
66
|
+
"""orjson config for dataclasses."""
|
|
67
|
+
|
|
68
|
+
forbid_extra_keys = True
|
|
69
|
+
orjson_options = orjson.OPT_NON_STR_KEYS
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dataclass
|
|
73
|
+
class ResponseBaseModel(DataClassORJSONMixin):
|
|
74
|
+
"""Base response model for API responses.
|
|
75
|
+
|
|
76
|
+
Allows extra keys in the response model and
|
|
77
|
+
non-string keys in the JSON.
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
class Config(BaseConfig):
|
|
81
|
+
"""Config for dataclasses."""
|
|
82
|
+
|
|
83
|
+
orjson_options = orjson.OPT_NON_STR_KEYS
|
|
84
|
+
forbid_extra_keys = False
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class DefaultValues:
|
|
89
|
+
"""Default request fields.
|
|
90
|
+
|
|
91
|
+
Attributes for the default values of the request fields
|
|
92
|
+
and static methods for preparing calculated fields.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
_call_number: ClassVar[int] = 0
|
|
96
|
+
userType: str = USER_TYPE
|
|
97
|
+
appVersion: str = APP_VERSION
|
|
98
|
+
clientType: str = CLIENT_TYPE
|
|
99
|
+
appId: str = APP_ID
|
|
100
|
+
phoneBrand: str = PHONE_BRAND
|
|
101
|
+
phoneOS: str = PHONE_OS
|
|
102
|
+
mobileId: str = MOBILE_ID
|
|
103
|
+
deviceRegion: str = DEFAULT_REGION
|
|
104
|
+
countryCode: str = DEFAULT_REGION
|
|
105
|
+
userCountryCode: str = DEFAULT_REGION
|
|
106
|
+
acceptLanguage: str = DEFAULT_LANGUAGE
|
|
107
|
+
timeZone: str = DEFAULT_TZ
|
|
108
|
+
terminalId: str = TERMINAL_ID
|
|
109
|
+
debugMode: bool = False
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def traceId() -> str:
|
|
113
|
+
"""Trace ID CSRF token."""
|
|
114
|
+
return str(int(time()))
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
def newTraceId() -> str:
|
|
118
|
+
"""Generate a new trace ID."""
|
|
119
|
+
DefaultValues._call_number += 1
|
|
120
|
+
return f'APP{TERMINAL_ID[-5:-1]}{int(time())}-{DefaultValues._call_number:0>5}'
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@dataclass
|
|
124
|
+
class ResponseCodeModel(ResponseBaseModel):
|
|
125
|
+
"""Model for the 'result' field in response."""
|
|
126
|
+
|
|
127
|
+
traceId: str
|
|
128
|
+
code: int
|
|
129
|
+
msg: str | None
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""Models for VeSync Bulb API responses and requests.
|
|
2
|
+
|
|
3
|
+
These models are used to serialize and deserialize the JSON responses from the
|
|
4
|
+
VeSync API. The models are used in the VeSync API class methods to provide
|
|
5
|
+
type hints and data validation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Self, TypedDict
|
|
12
|
+
|
|
13
|
+
from mashumaro import field_options
|
|
14
|
+
from mashumaro.config import BaseConfig
|
|
15
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
16
|
+
|
|
17
|
+
from pyvesync.models.base_models import ResponseBaseModel, ResponseCodeModel
|
|
18
|
+
from pyvesync.models.bypass_models import BypassV2InnerResult, RequestBypassV1
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class JSONCMD(DataClassORJSONMixin):
|
|
23
|
+
"""Tunable Bulb JSON CMD dict."""
|
|
24
|
+
|
|
25
|
+
light: None | JSONCMDLight = None
|
|
26
|
+
getLightStatus: None | str = None
|
|
27
|
+
|
|
28
|
+
class Config(BaseConfig):
|
|
29
|
+
"""Configure the JSONCMD model."""
|
|
30
|
+
|
|
31
|
+
omit_none = True
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class JSONCMDLight(DataClassORJSONMixin):
|
|
36
|
+
"""Light JSON CMD dict."""
|
|
37
|
+
|
|
38
|
+
action: str
|
|
39
|
+
brightness: int | None = None
|
|
40
|
+
colorTempe: int | None = None
|
|
41
|
+
|
|
42
|
+
class Config(BaseConfig):
|
|
43
|
+
"""Configure the JSONCMDLight model."""
|
|
44
|
+
|
|
45
|
+
omit_none = True
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass
|
|
49
|
+
class RequestESL100Detail(RequestBypassV1):
|
|
50
|
+
"""Request model for Etekcity bulb details."""
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class RequestESL100Status(RequestBypassV1):
|
|
55
|
+
"""Request model for Etekcity bulb details."""
|
|
56
|
+
|
|
57
|
+
status: str
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class RequestESL100Brightness(RequestBypassV1):
|
|
62
|
+
"""Request model for Etekcity bulb details."""
|
|
63
|
+
|
|
64
|
+
status: str
|
|
65
|
+
brightNess: int
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class RequestESL100CWBase(RequestBypassV1):
|
|
70
|
+
"""Request model for ESL100CW bulb."""
|
|
71
|
+
|
|
72
|
+
jsonCmd: JSONCMD
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass
|
|
76
|
+
class ResponseESL100Detail(ResponseCodeModel):
|
|
77
|
+
"""Response model for Etekcity bulb details."""
|
|
78
|
+
|
|
79
|
+
traceId: str
|
|
80
|
+
code: int
|
|
81
|
+
msg: str | None
|
|
82
|
+
result: ResponseESL100DetailResult
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class ResponseESL100DetailResult(ResponseBaseModel):
|
|
87
|
+
"""ESL100 Dimmable Bulb Device Detail Response."""
|
|
88
|
+
|
|
89
|
+
deviceName: str | None
|
|
90
|
+
name: str | None
|
|
91
|
+
brightness: int | None = field(metadata=field_options(alias='brightNess'))
|
|
92
|
+
activeTime: int | None
|
|
93
|
+
deviceStatus: str = 'off'
|
|
94
|
+
connectionStatus: str = 'offline'
|
|
95
|
+
|
|
96
|
+
@classmethod
|
|
97
|
+
def __post_deserialize__( # type: ignore[override]
|
|
98
|
+
cls, obj: Self
|
|
99
|
+
) -> Self:
|
|
100
|
+
"""Set values depending on color or white mode."""
|
|
101
|
+
if obj.brightness is None:
|
|
102
|
+
obj.brightness = 0
|
|
103
|
+
if obj.activeTime is None:
|
|
104
|
+
obj.activeTime = 0
|
|
105
|
+
return obj
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass
|
|
109
|
+
class ResponseESL100CWDetail(ResponseCodeModel):
|
|
110
|
+
"""Response model for Etekcity bulb details."""
|
|
111
|
+
|
|
112
|
+
result: ResponseESL100CWDetailResult
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@dataclass
|
|
116
|
+
class ResponseESL100CWLight(ResponseBaseModel):
|
|
117
|
+
"""ESL100CW Tunable Bulb Device Detail Response."""
|
|
118
|
+
|
|
119
|
+
brightness: int | None
|
|
120
|
+
action: str = 'on'
|
|
121
|
+
colorTempe: int = 0
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class ResponseESL100CWDetailResult(ResponseBaseModel):
|
|
126
|
+
"""Result model for ESL100CW Tunable bulb details."""
|
|
127
|
+
|
|
128
|
+
light: ResponseESL100CWLight
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@dataclass
|
|
132
|
+
class ResponseESL100MCStatus(ResponseCodeModel):
|
|
133
|
+
"""Response model for Etekcity bulb status."""
|
|
134
|
+
|
|
135
|
+
result: ResponseESL100MCOuterResult
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@dataclass
|
|
139
|
+
class ResponseESL100MCOuterResult:
|
|
140
|
+
"""ESL100MC Multi-Color Bulb Status Response."""
|
|
141
|
+
|
|
142
|
+
traceId: str
|
|
143
|
+
code: int
|
|
144
|
+
result: ResponseESL100MCResult
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@dataclass
|
|
148
|
+
class ResponseESL100MCResult(BypassV2InnerResult):
|
|
149
|
+
"""ESL100MC Multi-Color Bulb Status Response."""
|
|
150
|
+
|
|
151
|
+
colorMode: str
|
|
152
|
+
action: str
|
|
153
|
+
brightness: int = 0
|
|
154
|
+
red: int = 0
|
|
155
|
+
green: int = 0
|
|
156
|
+
blue: int = 0
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@dataclass
|
|
160
|
+
class ResponseValcenoStatus(ResponseCodeModel):
|
|
161
|
+
"""Response model for Valceno bulb status."""
|
|
162
|
+
|
|
163
|
+
result: ResponseValcenoOuterResult
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@dataclass
|
|
167
|
+
class ResponseValcenoOuterResult(ResponseBaseModel):
|
|
168
|
+
"""Valceno Bulb Status Response."""
|
|
169
|
+
|
|
170
|
+
result: ResponseValcenoStatusResult
|
|
171
|
+
traceId: str = ''
|
|
172
|
+
code: int = 0
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
@dataclass
|
|
176
|
+
class ResponseValcenoStatusResult(ResponseBaseModel):
|
|
177
|
+
"""Valceno Bulb Status Result."""
|
|
178
|
+
|
|
179
|
+
colorMode: str = ''
|
|
180
|
+
colorTemp: int = 0
|
|
181
|
+
brightness: int = 0
|
|
182
|
+
hue: int = 0
|
|
183
|
+
saturation: int = 0
|
|
184
|
+
value: int = 0
|
|
185
|
+
enabled: str = 'off'
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class ValcenoStatusPayload(TypedDict):
|
|
189
|
+
"""Typed Dict for setting Valceno bulb status."""
|
|
190
|
+
|
|
191
|
+
colorMode: str
|
|
192
|
+
colorTemp: int | str
|
|
193
|
+
brightness: int | str
|
|
194
|
+
hue: int | str
|
|
195
|
+
saturation: int | str
|
|
196
|
+
value: int | str
|
|
197
|
+
force: int
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""Request Models for Bypass V2 Endpoints.
|
|
2
|
+
|
|
3
|
+
API calls to bypassV2 endpoints have similar request structures. These models are used
|
|
4
|
+
to serialize and deserialize the JSON requests for the bypassV2 endpoints.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
|
|
11
|
+
import orjson
|
|
12
|
+
from mashumaro import pass_through
|
|
13
|
+
from mashumaro.config import BaseConfig
|
|
14
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
15
|
+
|
|
16
|
+
from pyvesync.models.base_models import (
|
|
17
|
+
BaseModelConfig,
|
|
18
|
+
RequestBaseModel,
|
|
19
|
+
ResponseBaseModel,
|
|
20
|
+
ResponseCodeModel,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class RequestBypassV2(RequestBaseModel):
|
|
26
|
+
"""Bypass V2 Status Request Dict.
|
|
27
|
+
|
|
28
|
+
This is the bypassV2 request model for API calls
|
|
29
|
+
that use the `configModel` and `deviceId` fields.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
acceptLanguage: str
|
|
33
|
+
accountID: str
|
|
34
|
+
appVersion: str
|
|
35
|
+
cid: str
|
|
36
|
+
configModule: str
|
|
37
|
+
debugMode: bool
|
|
38
|
+
method: str
|
|
39
|
+
phoneBrand: str
|
|
40
|
+
phoneOS: str
|
|
41
|
+
traceId: str
|
|
42
|
+
timeZone: str
|
|
43
|
+
token: str
|
|
44
|
+
userCountryCode: str
|
|
45
|
+
deviceId: str
|
|
46
|
+
configModel: str
|
|
47
|
+
payload: BypassV2RequestPayload
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class BypassV2RequestPayload(RequestBaseModel):
|
|
52
|
+
"""Generic Bypass V2 Payload Request model."""
|
|
53
|
+
|
|
54
|
+
data: dict
|
|
55
|
+
method: str
|
|
56
|
+
source: str = 'APP'
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass
|
|
60
|
+
class RequestBypassV1(RequestBaseModel):
|
|
61
|
+
"""Bypass V1 Status Request Dict.
|
|
62
|
+
|
|
63
|
+
This is the bypassV1 request model for API calls
|
|
64
|
+
that use the `configModel` and `deviceId` fields.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
acceptLanguage: str
|
|
68
|
+
accountID: str
|
|
69
|
+
appVersion: str
|
|
70
|
+
cid: str
|
|
71
|
+
configModule: str
|
|
72
|
+
debugMode: bool
|
|
73
|
+
method: str
|
|
74
|
+
phoneBrand: str
|
|
75
|
+
phoneOS: str
|
|
76
|
+
traceId: str
|
|
77
|
+
timeZone: str
|
|
78
|
+
token: str
|
|
79
|
+
userCountryCode: str
|
|
80
|
+
uuid: str
|
|
81
|
+
deviceId: str
|
|
82
|
+
configModel: str
|
|
83
|
+
|
|
84
|
+
class Config(BaseConfig): # type: ignore[override]
|
|
85
|
+
"""Configure omit None value keys."""
|
|
86
|
+
|
|
87
|
+
omit_none = True
|
|
88
|
+
orjson_options = orjson.OPT_NON_STR_KEYS
|
|
89
|
+
forbid_extra_keys = True
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class ResponseBypassV1(ResponseCodeModel):
|
|
94
|
+
"""Bypass V1 Response Dict."""
|
|
95
|
+
|
|
96
|
+
result: BypassV1Result | None = field(
|
|
97
|
+
default=None,
|
|
98
|
+
metadata={
|
|
99
|
+
'serialize': pass_through,
|
|
100
|
+
'deserialize': pass_through,
|
|
101
|
+
},
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@dataclass
|
|
106
|
+
class BypassV1Result(DataClassORJSONMixin):
|
|
107
|
+
"""Bypass V1 Response Dict."""
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@dataclass
|
|
111
|
+
class ResponseBypassV2(ResponseCodeModel):
|
|
112
|
+
"""Bypass V2 Response Dict.
|
|
113
|
+
|
|
114
|
+
This is the bypassV2 response model for API calls
|
|
115
|
+
that use the `configModel` and `deviceId` fields.
|
|
116
|
+
"""
|
|
117
|
+
|
|
118
|
+
result: BypassV2OuterResult | None = None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass
|
|
122
|
+
class BypassV2InnerResult(DataClassORJSONMixin):
|
|
123
|
+
"""Inner Bypass V2 Result Data Model."""
|
|
124
|
+
|
|
125
|
+
class Config(BaseModelConfig):
|
|
126
|
+
"""Configure the Outer Result model."""
|
|
127
|
+
|
|
128
|
+
allow_deserialization_not_by_alias = True
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@dataclass
|
|
132
|
+
class BypassV2OuterResult(DataClassORJSONMixin):
|
|
133
|
+
"""Bypass V2 Outer Result Data Model."""
|
|
134
|
+
|
|
135
|
+
code: int
|
|
136
|
+
result: BypassV2InnerResult | None = field(
|
|
137
|
+
default=None,
|
|
138
|
+
metadata={
|
|
139
|
+
'serialize': pass_through,
|
|
140
|
+
'deserialize': pass_through,
|
|
141
|
+
},
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
class Config(BaseModelConfig):
|
|
145
|
+
"""Configure the Outer Result model."""
|
|
146
|
+
|
|
147
|
+
allow_deserialization_not_by_alias = True
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@dataclass
|
|
151
|
+
class BypassV2ResultError(DataClassORJSONMixin):
|
|
152
|
+
"""Bypass V2 Result Error Data Model."""
|
|
153
|
+
|
|
154
|
+
msg: str
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@dataclass
|
|
158
|
+
class ResultV2GetTimer(BypassV2InnerResult):
|
|
159
|
+
"""Inner result for Bypass V2 GetTimer method."""
|
|
160
|
+
|
|
161
|
+
timers: list[TimerItemV2] | None = None
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@dataclass
|
|
165
|
+
class ResultV2SetTimer(BypassV2InnerResult):
|
|
166
|
+
"""Result for Bypass V2 SetTimer method."""
|
|
167
|
+
|
|
168
|
+
id: int
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# Bypass V1 Timer Models
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@dataclass
|
|
175
|
+
class TimeItemV1(ResponseBaseModel):
|
|
176
|
+
"""Data model for Bypass V1 Timers."""
|
|
177
|
+
|
|
178
|
+
timerID: str
|
|
179
|
+
counterTime: str
|
|
180
|
+
action: str
|
|
181
|
+
status: str
|
|
182
|
+
resetTime: str
|
|
183
|
+
uuid: str
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@dataclass
|
|
187
|
+
class TimerItemV1(ResponseBaseModel):
|
|
188
|
+
"""Data model for Bypass V1 Timers."""
|
|
189
|
+
|
|
190
|
+
timerID: str
|
|
191
|
+
counterTimer: str
|
|
192
|
+
action: str
|
|
193
|
+
status: str
|
|
194
|
+
resetTime: str
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@dataclass
|
|
198
|
+
class TimerItemV2(ResponseBaseModel):
|
|
199
|
+
"""Data model for Bypass V2 Timers."""
|
|
200
|
+
|
|
201
|
+
id: int
|
|
202
|
+
remain: int
|
|
203
|
+
action: str
|
|
204
|
+
total: int
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@dataclass
|
|
208
|
+
class ResultV1SetTimer(BypassV1Result):
|
|
209
|
+
"""Result model for setting Bypass V1 API timer."""
|
|
210
|
+
|
|
211
|
+
timerID: str
|
|
212
|
+
conflictTimerIds: list[str] | None = None
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@dataclass
|
|
216
|
+
class RequestV1ClearTimer(RequestBypassV1):
|
|
217
|
+
"""Request model for clearing Bypass V1 API outlet timer."""
|
|
218
|
+
|
|
219
|
+
timerId: str
|
|
220
|
+
status: str | None = None
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@dataclass
|
|
224
|
+
class ResultV1GetTimerList(BypassV1Result):
|
|
225
|
+
"""Get timers result for v1 API."""
|
|
226
|
+
|
|
227
|
+
timers: list[TimeItemV1] | list[TimerItemV1] | TimerItemV1 | None = None
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@dataclass
|
|
231
|
+
class RequestV1SetTime(RequestBypassV1):
|
|
232
|
+
"""Request model for setting timer with counterTime."""
|
|
233
|
+
|
|
234
|
+
counterTime: str
|
|
235
|
+
action: str
|
|
236
|
+
status: str | None = None
|
|
237
|
+
switchNo: int | None = None
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@dataclass
|
|
241
|
+
class RequestV1GetTimer(RequestBypassV1):
|
|
242
|
+
"""Request model for getting timers from v1 API."""
|
|
243
|
+
|
|
244
|
+
switchNo: str | None = None
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
@dataclass
|
|
248
|
+
class RequestV1SetTimer(RequestBypassV1):
|
|
249
|
+
"""Request model for timer with counterTimer key.
|
|
250
|
+
|
|
251
|
+
Attributes:
|
|
252
|
+
counterTimer (str): The timer value in seconds.
|
|
253
|
+
action (str): The action to perform (e.g., "on", "off").
|
|
254
|
+
switchNo (int | None): The switch number for the timer.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
counterTimer: str
|
|
258
|
+
action: str
|
|
259
|
+
switchNo: int | None = None
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class TimerModels:
|
|
263
|
+
"""Class holding all common timer models.
|
|
264
|
+
|
|
265
|
+
Attributes:
|
|
266
|
+
ResultV2GetTimer (ResultV2GetTimer): Result model for Bypass V2 GetTimer method.
|
|
267
|
+
ResultV2SetTimer (ResultV2SetTimer): Result model for Bypass V2 SetTimer method.
|
|
268
|
+
ResultV1SetTimer (ResultV1SetTimer): Result model V1 API for setting timer.
|
|
269
|
+
ResultV1GetTimer (ResultV1GetTimerList): Get timers result for v1 API.
|
|
270
|
+
TimeItemV1 (TimeItemV1): Data model for Bypass V1 Timers.
|
|
271
|
+
TimerItemV1 (TimerItemV1): Data model for Bypass V1 Timers.
|
|
272
|
+
TimerItemV2 (TimerItemV2): Data model for Bypass V2 Timers.
|
|
273
|
+
RequestV1ClearTimer (RequestV1ClearTimer): Model for deleting timer.
|
|
274
|
+
RequestV1SetTimer (RequestV1SetTimer): Model for timer with counterTimer key.
|
|
275
|
+
RequestV1GetTimer (RequestV1GetTimer): Model for getting timers from v1 API.
|
|
276
|
+
RequestV1SetTime (RequestV1SetTime): Model for setting timer with counterTime key.
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
ResultV2GetTimer = ResultV2GetTimer
|
|
280
|
+
ResultV2SetTimer = ResultV2SetTimer
|
|
281
|
+
ResultV1SetTimer = ResultV1SetTimer
|
|
282
|
+
ResultV1GetTimer = ResultV1GetTimerList
|
|
283
|
+
TimeItemV1 = TimeItemV1
|
|
284
|
+
TimerItemV1 = TimerItemV1
|
|
285
|
+
TimerItemV2 = TimerItemV2
|
|
286
|
+
RequestV1ClearTimer = RequestV1ClearTimer
|
|
287
|
+
RequestV1SetTimer = RequestV1SetTimer
|
|
288
|
+
RequestV1GetTimer = RequestV1GetTimer
|
|
289
|
+
RequestV1SetTime = RequestV1SetTime
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Data models for VeSync Fans.
|
|
2
|
+
|
|
3
|
+
These models inherit from `ResponseBaseModel` and `RequestBaseModel` from the
|
|
4
|
+
`base_models` module.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
from mashumaro.mixins.orjson import DataClassORJSONMixin
|
|
12
|
+
|
|
13
|
+
from pyvesync.models.bypass_models import (
|
|
14
|
+
BypassV2InnerResult,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class TowerFanResult(BypassV2InnerResult):
|
|
20
|
+
"""Tower Fan Result Model."""
|
|
21
|
+
|
|
22
|
+
powerSwitch: int
|
|
23
|
+
workMode: str
|
|
24
|
+
manualSpeedLevel: int
|
|
25
|
+
fanSpeedLevel: int
|
|
26
|
+
screenState: int
|
|
27
|
+
screenSwitch: int
|
|
28
|
+
oscillationSwitch: int
|
|
29
|
+
oscillationState: int
|
|
30
|
+
muteSwitch: int
|
|
31
|
+
muteState: int
|
|
32
|
+
timerRemain: int
|
|
33
|
+
temperature: int
|
|
34
|
+
errorCode: int
|
|
35
|
+
scheduleCount: int
|
|
36
|
+
displayingType: int | None = None
|
|
37
|
+
sleepPreference: FanSleepPreferences | None = None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class FanSleepPreferences(DataClassORJSONMixin):
|
|
42
|
+
"""Fan Sleep Preferences."""
|
|
43
|
+
|
|
44
|
+
sleepPreferenceType: str
|
|
45
|
+
oscillationSwitch: int
|
|
46
|
+
fallAsleepRemain: int
|
|
47
|
+
autoChangeFanLevelSwitch: int
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Data models for VeSync air fryers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
from pyvesync.models.base_models import ResponseBaseModel
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class ResultFryerDetails(ResponseBaseModel):
|
|
12
|
+
"""Result model for air fryer details."""
|
|
13
|
+
|
|
14
|
+
returnStatus: FryerCookingReturnStatus | FryerBaseReturnStatus | None = None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class FryerCookingReturnStatus(ResponseBaseModel):
|
|
19
|
+
"""Result returnStatus model for air fryer status."""
|
|
20
|
+
|
|
21
|
+
currentTemp: int
|
|
22
|
+
cookSetTemp: int
|
|
23
|
+
mode: str
|
|
24
|
+
cookSetTime: int
|
|
25
|
+
cookLastTime: int
|
|
26
|
+
cookStatus: str
|
|
27
|
+
tempUnit: str
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class FryerBaseReturnStatus(ResponseBaseModel):
|
|
32
|
+
"""Result returnStatus model for air fryer status."""
|
|
33
|
+
|
|
34
|
+
cookStatus: str
|