daybetter-services-python 1.0.0__tar.gz
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.
- daybetter_services_python-1.0.0/LICENSE +21 -0
- daybetter_services_python-1.0.0/PKG-INFO +98 -0
- daybetter_services_python-1.0.0/README.md +59 -0
- daybetter_services_python-1.0.0/daybetter_python/__init__.py +7 -0
- daybetter_services_python-1.0.0/daybetter_python/client.py +260 -0
- daybetter_services_python-1.0.0/daybetter_python/exceptions.py +13 -0
- daybetter_services_python-1.0.0/daybetter_services_python.egg-info/PKG-INFO +98 -0
- daybetter_services_python-1.0.0/daybetter_services_python.egg-info/SOURCES.txt +12 -0
- daybetter_services_python-1.0.0/daybetter_services_python.egg-info/dependency_links.txt +1 -0
- daybetter_services_python-1.0.0/daybetter_services_python.egg-info/requires.txt +9 -0
- daybetter_services_python-1.0.0/daybetter_services_python.egg-info/top_level.txt +1 -0
- daybetter_services_python-1.0.0/pyproject.toml +57 -0
- daybetter_services_python-1.0.0/setup.cfg +4 -0
- daybetter_services_python-1.0.0/setup.py +34 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 THDayBetter
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: daybetter-services-python
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python client for DayBetter devices and services
|
|
5
|
+
Home-page: https://github.com/THDayBetter/daybetter-python
|
|
6
|
+
Author: THDayBetter
|
|
7
|
+
Author-email: THDayBetter <chenp2368@163.com>
|
|
8
|
+
Maintainer-email: THDayBetter <chenp2368@163.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Project-URL: Homepage, https://github.com/THDayBetter/daybetter-python
|
|
11
|
+
Project-URL: Documentation, https://github.com/THDayBetter/daybetter-python#readme
|
|
12
|
+
Project-URL: Repository, https://github.com/THDayBetter/daybetter-python.git
|
|
13
|
+
Project-URL: Bug Tracker, https://github.com/THDayBetter/daybetter-python/issues
|
|
14
|
+
Keywords: daybetter,iot,home automation,mqtt
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
31
|
+
Requires-Dist: black; extra == "dev"
|
|
32
|
+
Requires-Dist: isort; extra == "dev"
|
|
33
|
+
Requires-Dist: flake8; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy; extra == "dev"
|
|
35
|
+
Dynamic: author
|
|
36
|
+
Dynamic: home-page
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
|
|
40
|
+
# DayBetter Python Client
|
|
41
|
+
|
|
42
|
+
A Python client library for interacting with DayBetter devices and services.
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- Device management and control
|
|
47
|
+
- MQTT configuration retrieval
|
|
48
|
+
- Authentication handling
|
|
49
|
+
- Async/await support
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install daybetter-services-python
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import asyncio
|
|
61
|
+
from daybetter_python import DayBetterClient
|
|
62
|
+
|
|
63
|
+
async def main():
|
|
64
|
+
async with DayBetterClient(token="your_token") as client:
|
|
65
|
+
# Fetch devices
|
|
66
|
+
devices = await client.fetch_devices()
|
|
67
|
+
print(f"Found {len(devices)} devices")
|
|
68
|
+
|
|
69
|
+
# Control a device
|
|
70
|
+
result = await client.control_device(
|
|
71
|
+
device_name="device_001",
|
|
72
|
+
action=True,
|
|
73
|
+
brightness=80
|
|
74
|
+
)
|
|
75
|
+
print(f"Control result: {result}")
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
asyncio.run(main())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## API Reference
|
|
82
|
+
|
|
83
|
+
### DayBetterClient
|
|
84
|
+
|
|
85
|
+
#### Methods
|
|
86
|
+
|
|
87
|
+
- `fetch_devices()`: Get list of devices
|
|
88
|
+
- `fetch_pids()`: Get device type PIDs
|
|
89
|
+
- `control_device(device_name, action, brightness, hs_color, color_temp)`: Control a device
|
|
90
|
+
- `fetch_mqtt_config()`: Get MQTT configuration
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT License
|
|
95
|
+
|
|
96
|
+
## Contributing
|
|
97
|
+
|
|
98
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# DayBetter Python Client
|
|
2
|
+
|
|
3
|
+
A Python client library for interacting with DayBetter devices and services.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Device management and control
|
|
8
|
+
- MQTT configuration retrieval
|
|
9
|
+
- Authentication handling
|
|
10
|
+
- Async/await support
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install daybetter-services-python
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
import asyncio
|
|
22
|
+
from daybetter_python import DayBetterClient
|
|
23
|
+
|
|
24
|
+
async def main():
|
|
25
|
+
async with DayBetterClient(token="your_token") as client:
|
|
26
|
+
# Fetch devices
|
|
27
|
+
devices = await client.fetch_devices()
|
|
28
|
+
print(f"Found {len(devices)} devices")
|
|
29
|
+
|
|
30
|
+
# Control a device
|
|
31
|
+
result = await client.control_device(
|
|
32
|
+
device_name="device_001",
|
|
33
|
+
action=True,
|
|
34
|
+
brightness=80
|
|
35
|
+
)
|
|
36
|
+
print(f"Control result: {result}")
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
asyncio.run(main())
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## API Reference
|
|
43
|
+
|
|
44
|
+
### DayBetterClient
|
|
45
|
+
|
|
46
|
+
#### Methods
|
|
47
|
+
|
|
48
|
+
- `fetch_devices()`: Get list of devices
|
|
49
|
+
- `fetch_pids()`: Get device type PIDs
|
|
50
|
+
- `control_device(device_name, action, brightness, hs_color, color_temp)`: Control a device
|
|
51
|
+
- `fetch_mqtt_config()`: Get MQTT configuration
|
|
52
|
+
|
|
53
|
+
## License
|
|
54
|
+
|
|
55
|
+
MIT License
|
|
56
|
+
|
|
57
|
+
## Contributing
|
|
58
|
+
|
|
59
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"""DayBetter API client."""
|
|
2
|
+
|
|
3
|
+
import aiohttp
|
|
4
|
+
import logging
|
|
5
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
from .exceptions import DayBetterError, AuthenticationError, APIError
|
|
8
|
+
|
|
9
|
+
_LOGGER = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DayBetterClient:
|
|
13
|
+
"""DayBetter API client."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
token: str,
|
|
18
|
+
base_url: str = "https://a.dbiot.org/daybetter/hass/api/v1.0/"
|
|
19
|
+
):
|
|
20
|
+
"""Initialize the client.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
token: Authentication token
|
|
24
|
+
base_url: Base URL for the API
|
|
25
|
+
"""
|
|
26
|
+
self.token = token
|
|
27
|
+
self.base_url = base_url
|
|
28
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
|
29
|
+
self._auth_valid = True
|
|
30
|
+
|
|
31
|
+
async def __aenter__(self):
|
|
32
|
+
"""Async context manager entry."""
|
|
33
|
+
self._session = aiohttp.ClientSession()
|
|
34
|
+
return self
|
|
35
|
+
|
|
36
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
37
|
+
"""Async context manager exit."""
|
|
38
|
+
if self._session:
|
|
39
|
+
await self._session.close()
|
|
40
|
+
self._session = None
|
|
41
|
+
|
|
42
|
+
def _get_session(self) -> aiohttp.ClientSession:
|
|
43
|
+
"""Get or create aiohttp session."""
|
|
44
|
+
if not self._session:
|
|
45
|
+
self._session = aiohttp.ClientSession()
|
|
46
|
+
return self._session
|
|
47
|
+
|
|
48
|
+
def _get_headers(self) -> Dict[str, str]:
|
|
49
|
+
"""Get request headers."""
|
|
50
|
+
return {"Authorization": f"Bearer {self.token}"}
|
|
51
|
+
|
|
52
|
+
async def fetch_devices(self) -> List[Dict[str, Any]]:
|
|
53
|
+
"""Fetch devices from API.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
List of device dictionaries
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
AuthenticationError: If authentication fails
|
|
60
|
+
APIError: If API request fails
|
|
61
|
+
"""
|
|
62
|
+
try:
|
|
63
|
+
session = self._get_session()
|
|
64
|
+
url = f"{self.base_url}hass/devices"
|
|
65
|
+
headers = self._get_headers()
|
|
66
|
+
|
|
67
|
+
async with session.post(url, headers=headers) as resp:
|
|
68
|
+
if resp.status == 200:
|
|
69
|
+
data = await resp.json()
|
|
70
|
+
devices = data.get("data", [])
|
|
71
|
+
_LOGGER.debug("Fetched devices: %s", devices)
|
|
72
|
+
self._auth_valid = True
|
|
73
|
+
return devices
|
|
74
|
+
elif resp.status == 401:
|
|
75
|
+
_LOGGER.error("Authentication failed - token may be expired")
|
|
76
|
+
self._auth_valid = False
|
|
77
|
+
raise AuthenticationError("Authentication failed - token may be expired")
|
|
78
|
+
else:
|
|
79
|
+
error_text = await resp.text()
|
|
80
|
+
_LOGGER.error("Failed to fetch devices: %s", error_text)
|
|
81
|
+
raise APIError(f"API error {resp.status}: {error_text}")
|
|
82
|
+
except aiohttp.ClientError as e:
|
|
83
|
+
_LOGGER.exception("Client error while fetching devices: %s", e)
|
|
84
|
+
raise APIError(f"Client error: {e}")
|
|
85
|
+
except Exception as e:
|
|
86
|
+
_LOGGER.exception("Exception while fetching devices: %s", e)
|
|
87
|
+
raise DayBetterError(f"Unexpected error: {e}")
|
|
88
|
+
|
|
89
|
+
async def fetch_pids(self) -> Dict[str, Any]:
|
|
90
|
+
"""Fetch device type PIDs.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Dictionary of device type PIDs
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
AuthenticationError: If authentication fails
|
|
97
|
+
APIError: If API request fails
|
|
98
|
+
"""
|
|
99
|
+
try:
|
|
100
|
+
session = self._get_session()
|
|
101
|
+
url = f"{self.base_url}hass/pids"
|
|
102
|
+
headers = self._get_headers()
|
|
103
|
+
|
|
104
|
+
async with session.post(url, headers=headers) as resp:
|
|
105
|
+
if resp.status == 200:
|
|
106
|
+
data = await resp.json()
|
|
107
|
+
self._auth_valid = True
|
|
108
|
+
return data.get("data", {})
|
|
109
|
+
elif resp.status == 401:
|
|
110
|
+
_LOGGER.error("Authentication failed - token may be expired")
|
|
111
|
+
self._auth_valid = False
|
|
112
|
+
raise AuthenticationError("Authentication failed - token may be expired")
|
|
113
|
+
else:
|
|
114
|
+
error_text = await resp.text()
|
|
115
|
+
_LOGGER.error("Failed to fetch PIDs: %s", error_text)
|
|
116
|
+
raise APIError(f"API error {resp.status}: {error_text}")
|
|
117
|
+
except aiohttp.ClientError as e:
|
|
118
|
+
_LOGGER.exception("Client error while fetching PIDs: %s", e)
|
|
119
|
+
raise APIError(f"Client error: {e}")
|
|
120
|
+
except Exception as e:
|
|
121
|
+
_LOGGER.exception("Exception while fetching PIDs: %s", e)
|
|
122
|
+
raise DayBetterError(f"Unexpected error: {e}")
|
|
123
|
+
|
|
124
|
+
async def control_device(
|
|
125
|
+
self,
|
|
126
|
+
device_name: str,
|
|
127
|
+
action: bool,
|
|
128
|
+
brightness: Optional[int] = None,
|
|
129
|
+
hs_color: Optional[Tuple[float, float]] = None,
|
|
130
|
+
color_temp: Optional[int] = None,
|
|
131
|
+
) -> Dict[str, Any]:
|
|
132
|
+
"""Control a device.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
device_name: Name of the device to control
|
|
136
|
+
action: Switch action (True/False)
|
|
137
|
+
brightness: Brightness value (0-255)
|
|
138
|
+
hs_color: Hue and saturation tuple (hue, saturation)
|
|
139
|
+
color_temp: Color temperature in mireds
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Control result dictionary
|
|
143
|
+
|
|
144
|
+
Raises:
|
|
145
|
+
AuthenticationError: If authentication fails
|
|
146
|
+
APIError: If API request fails
|
|
147
|
+
"""
|
|
148
|
+
session = self._get_session()
|
|
149
|
+
url = f"{self.base_url}hass/control"
|
|
150
|
+
headers = self._get_headers()
|
|
151
|
+
|
|
152
|
+
# Priority: color temperature > color > brightness > switch
|
|
153
|
+
if color_temp is not None:
|
|
154
|
+
# Convert mireds to Kelvin
|
|
155
|
+
kelvin = int(1000000 / color_temp)
|
|
156
|
+
payload = {
|
|
157
|
+
"deviceName": device_name,
|
|
158
|
+
"type": 4, # Type 4 is color temperature control
|
|
159
|
+
"kelvin": kelvin,
|
|
160
|
+
}
|
|
161
|
+
elif hs_color is not None:
|
|
162
|
+
h, s = hs_color
|
|
163
|
+
v = (brightness / 255) if brightness is not None else 1.0
|
|
164
|
+
payload = {
|
|
165
|
+
"deviceName": device_name,
|
|
166
|
+
"type": 3,
|
|
167
|
+
"hue": h,
|
|
168
|
+
"saturation": s / 100,
|
|
169
|
+
"brightness": v,
|
|
170
|
+
}
|
|
171
|
+
elif brightness is not None:
|
|
172
|
+
payload = {
|
|
173
|
+
"deviceName": device_name,
|
|
174
|
+
"type": 2,
|
|
175
|
+
"brightness": brightness
|
|
176
|
+
}
|
|
177
|
+
else:
|
|
178
|
+
# Type 1 control switch is used by default
|
|
179
|
+
payload = {
|
|
180
|
+
"deviceName": device_name,
|
|
181
|
+
"type": 1,
|
|
182
|
+
"on": action
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
async with session.post(url, headers=headers, json=payload) as resp:
|
|
187
|
+
if resp.status == 200:
|
|
188
|
+
self._auth_valid = True
|
|
189
|
+
return await resp.json()
|
|
190
|
+
elif resp.status == 401:
|
|
191
|
+
_LOGGER.error("Authentication failed - token may be expired")
|
|
192
|
+
self._auth_valid = False
|
|
193
|
+
raise AuthenticationError("Authentication failed - token may be expired")
|
|
194
|
+
else:
|
|
195
|
+
error_text = await resp.text()
|
|
196
|
+
_LOGGER.error(
|
|
197
|
+
"Failed to control device %s: HTTP %d - %s",
|
|
198
|
+
device_name, resp.status, error_text
|
|
199
|
+
)
|
|
200
|
+
raise APIError(f"API error {resp.status}: {error_text}")
|
|
201
|
+
except aiohttp.ClientError as e:
|
|
202
|
+
_LOGGER.exception(
|
|
203
|
+
"Client error while controlling device %s: %s", device_name, e
|
|
204
|
+
)
|
|
205
|
+
raise APIError(f"Client error: {e}")
|
|
206
|
+
except Exception as e:
|
|
207
|
+
_LOGGER.exception(
|
|
208
|
+
"Exception while controlling device %s: %s", device_name, e
|
|
209
|
+
)
|
|
210
|
+
raise DayBetterError(f"Unexpected error: {e}")
|
|
211
|
+
|
|
212
|
+
async def fetch_mqtt_config(self) -> Dict[str, Any]:
|
|
213
|
+
"""Fetch MQTT connection configuration.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
MQTT configuration dictionary
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
AuthenticationError: If authentication fails
|
|
220
|
+
APIError: If API request fails
|
|
221
|
+
"""
|
|
222
|
+
session = self._get_session()
|
|
223
|
+
url = f"{self.base_url}hass/cert"
|
|
224
|
+
headers = self._get_headers()
|
|
225
|
+
_LOGGER.debug("Requesting MQTT configuration URL: %s", url)
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
async with session.post(url, headers=headers) as resp:
|
|
229
|
+
_LOGGER.debug("MQTT configuration API response status: %d", resp.status)
|
|
230
|
+
|
|
231
|
+
if resp.status == 200:
|
|
232
|
+
data = await resp.json()
|
|
233
|
+
_LOGGER.debug("MQTT configuration API raw response: %s", data)
|
|
234
|
+
self._auth_valid = True
|
|
235
|
+
return data.get("data", {})
|
|
236
|
+
elif resp.status == 401:
|
|
237
|
+
_LOGGER.error("Authentication failed - token may be expired")
|
|
238
|
+
self._auth_valid = False
|
|
239
|
+
raise AuthenticationError("Authentication failed - token may be expired")
|
|
240
|
+
else:
|
|
241
|
+
error_text = await resp.text()
|
|
242
|
+
_LOGGER.error("Failed to fetch MQTT config: %s", error_text)
|
|
243
|
+
raise APIError(f"API error {resp.status}: {error_text}")
|
|
244
|
+
except aiohttp.ClientError as e:
|
|
245
|
+
_LOGGER.exception("Client error while fetching MQTT config: %s", e)
|
|
246
|
+
raise APIError(f"Client error: {e}")
|
|
247
|
+
except Exception as e:
|
|
248
|
+
_LOGGER.exception("Exception while fetching MQTT config: %s", e)
|
|
249
|
+
raise DayBetterError(f"Unexpected error: {e}")
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def is_authenticated(self) -> bool:
|
|
253
|
+
"""Check if the API client is authenticated."""
|
|
254
|
+
return self._auth_valid
|
|
255
|
+
|
|
256
|
+
async def close(self):
|
|
257
|
+
"""Close the client session."""
|
|
258
|
+
if self._session:
|
|
259
|
+
await self._session.close()
|
|
260
|
+
self._session = None
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""DayBetter client exceptions."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DayBetterError(Exception):
|
|
5
|
+
"""Base exception for DayBetter client."""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AuthenticationError(DayBetterError):
|
|
9
|
+
"""Authentication failed."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class APIError(DayBetterError):
|
|
13
|
+
"""API request failed."""
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: daybetter-services-python
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python client for DayBetter devices and services
|
|
5
|
+
Home-page: https://github.com/THDayBetter/daybetter-python
|
|
6
|
+
Author: THDayBetter
|
|
7
|
+
Author-email: THDayBetter <chenp2368@163.com>
|
|
8
|
+
Maintainer-email: THDayBetter <chenp2368@163.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Project-URL: Homepage, https://github.com/THDayBetter/daybetter-python
|
|
11
|
+
Project-URL: Documentation, https://github.com/THDayBetter/daybetter-python#readme
|
|
12
|
+
Project-URL: Repository, https://github.com/THDayBetter/daybetter-python.git
|
|
13
|
+
Project-URL: Bug Tracker, https://github.com/THDayBetter/daybetter-python/issues
|
|
14
|
+
Keywords: daybetter,iot,home automation,mqtt
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Requires-Python: >=3.8
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: aiohttp>=3.8.0
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
31
|
+
Requires-Dist: black; extra == "dev"
|
|
32
|
+
Requires-Dist: isort; extra == "dev"
|
|
33
|
+
Requires-Dist: flake8; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy; extra == "dev"
|
|
35
|
+
Dynamic: author
|
|
36
|
+
Dynamic: home-page
|
|
37
|
+
Dynamic: license-file
|
|
38
|
+
Dynamic: requires-python
|
|
39
|
+
|
|
40
|
+
# DayBetter Python Client
|
|
41
|
+
|
|
42
|
+
A Python client library for interacting with DayBetter devices and services.
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- Device management and control
|
|
47
|
+
- MQTT configuration retrieval
|
|
48
|
+
- Authentication handling
|
|
49
|
+
- Async/await support
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install daybetter-services-python
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import asyncio
|
|
61
|
+
from daybetter_python import DayBetterClient
|
|
62
|
+
|
|
63
|
+
async def main():
|
|
64
|
+
async with DayBetterClient(token="your_token") as client:
|
|
65
|
+
# Fetch devices
|
|
66
|
+
devices = await client.fetch_devices()
|
|
67
|
+
print(f"Found {len(devices)} devices")
|
|
68
|
+
|
|
69
|
+
# Control a device
|
|
70
|
+
result = await client.control_device(
|
|
71
|
+
device_name="device_001",
|
|
72
|
+
action=True,
|
|
73
|
+
brightness=80
|
|
74
|
+
)
|
|
75
|
+
print(f"Control result: {result}")
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
asyncio.run(main())
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## API Reference
|
|
82
|
+
|
|
83
|
+
### DayBetterClient
|
|
84
|
+
|
|
85
|
+
#### Methods
|
|
86
|
+
|
|
87
|
+
- `fetch_devices()`: Get list of devices
|
|
88
|
+
- `fetch_pids()`: Get device type PIDs
|
|
89
|
+
- `control_device(device_name, action, brightness, hs_color, color_temp)`: Control a device
|
|
90
|
+
- `fetch_mqtt_config()`: Get MQTT configuration
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT License
|
|
95
|
+
|
|
96
|
+
## Contributing
|
|
97
|
+
|
|
98
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
daybetter_python/__init__.py
|
|
6
|
+
daybetter_python/client.py
|
|
7
|
+
daybetter_python/exceptions.py
|
|
8
|
+
daybetter_services_python.egg-info/PKG-INFO
|
|
9
|
+
daybetter_services_python.egg-info/SOURCES.txt
|
|
10
|
+
daybetter_services_python.egg-info/dependency_links.txt
|
|
11
|
+
daybetter_services_python.egg-info/requires.txt
|
|
12
|
+
daybetter_services_python.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
daybetter_python
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=45", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "daybetter-services-python"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Python client for DayBetter devices and services"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [
|
|
12
|
+
{name = "THDayBetter", email = "chenp2368@163.com"}
|
|
13
|
+
]
|
|
14
|
+
maintainers = [
|
|
15
|
+
{name = "THDayBetter", email = "chenp2368@163.com"}
|
|
16
|
+
]
|
|
17
|
+
keywords = ["daybetter", "iot", "home automation", "mqtt"]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.8",
|
|
24
|
+
"Programming Language :: Python :: 3.9",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
]
|
|
29
|
+
requires-python = ">=3.8"
|
|
30
|
+
dependencies = [
|
|
31
|
+
"aiohttp>=3.8.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/THDayBetter/daybetter-python"
|
|
36
|
+
Documentation = "https://github.com/THDayBetter/daybetter-python#readme"
|
|
37
|
+
Repository = "https://github.com/THDayBetter/daybetter-python.git"
|
|
38
|
+
"Bug Tracker" = "https://github.com/THDayBetter/daybetter-python/issues"
|
|
39
|
+
|
|
40
|
+
[project.optional-dependencies]
|
|
41
|
+
dev = [
|
|
42
|
+
"pytest>=6.0",
|
|
43
|
+
"pytest-asyncio",
|
|
44
|
+
"black",
|
|
45
|
+
"isort",
|
|
46
|
+
"flake8",
|
|
47
|
+
"mypy",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
[tool.black]
|
|
52
|
+
line-length = 88
|
|
53
|
+
target-version = ['py38']
|
|
54
|
+
|
|
55
|
+
[tool.isort]
|
|
56
|
+
profile = "black"
|
|
57
|
+
line_length = 88
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="daybetter-services-python",
|
|
8
|
+
version="1.0.0",
|
|
9
|
+
author="THDayBetter",
|
|
10
|
+
author_email="chenp2368@163.com",
|
|
11
|
+
description="Python client for DayBetter devices and services",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/THDayBetter/daybetter-python",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.8",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
],
|
|
27
|
+
python_requires=">=3.8",
|
|
28
|
+
install_requires=["aiohttp>=3.8.0"],
|
|
29
|
+
keywords="daybetter, iot, home automation, mqtt",
|
|
30
|
+
project_urls={
|
|
31
|
+
"Bug Reports": "https://github.com/THDayBetter/daybetter-python/issues",
|
|
32
|
+
"Source": "https://github.com/THDayBetter/daybetter-python",
|
|
33
|
+
},
|
|
34
|
+
)
|