gshock-api 2.0.32__tar.gz → 2.0.35__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.
- {gshock_api-2.0.32 → gshock_api-2.0.35}/PKG-INFO +11 -10
- {gshock_api-2.0.32 → gshock_api-2.0.35}/README.rst +7 -7
- {gshock_api-2.0.32 → gshock_api-2.0.35}/pyproject.toml +3 -2
- {gshock_api-2.0.32 → gshock_api-2.0.35}/setup.cfg +5 -4
- {gshock_api-2.0.32 → gshock_api-2.0.35}/setup.py +1 -1
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/examples/api_tests.py +7 -8
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/cancelable_result.py +1 -1
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/connection.py +5 -5
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/event.py +2 -1
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/gshock_api.py +23 -54
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/alarms_io.py +3 -2
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/events_io.py +2 -2
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/time_io.py +1 -1
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/world_cities_io.py +2 -2
- gshock_api-2.0.35/src/gshock_api/logger.py +46 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/scanner.py +3 -4
- gshock_api-2.0.35/src/gshock_api/watch_info.py +248 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api.egg-info/PKG-INFO +11 -10
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api.egg-info/requires.txt +1 -0
- gshock_api-2.0.32/src/gshock_api/logger.py +0 -45
- gshock_api-2.0.32/src/gshock_api/watch_info.py +0 -344
- {gshock_api-2.0.32 → gshock_api-2.0.35}/LICENSE.txt +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/examples/app_notifications_tests.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/examples/args.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/examples/gshock_server.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/examples/health_test.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/__init__.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/alarms.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/always_connected_watch_filter.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/app_notification.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/casio_constants.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/exceptions.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/__init__.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/app_info_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/app_notification_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/button_pressed_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/connection_protocol.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/dst_for_world_cities_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/dst_watch_state_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/error_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/settings_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/time_adjustement_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/timer_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/unknown_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/watch_condition_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/iolib/watch_name_io.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/message_dispatcher.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/settings.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api/utils.py +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api.egg-info/SOURCES.txt +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api.egg-info/dependency_links.txt +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api.egg-info/entry_points.txt +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api.egg-info/not-zip-safe +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/src/gshock_api.egg-info/top_level.txt +0 -0
- {gshock_api-2.0.32 → gshock_api-2.0.35}/tests/test_code.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gshock_api
|
|
3
|
-
Version: 2.0.
|
|
4
|
-
Summary:
|
|
5
|
-
Home-page: https://github.com/
|
|
3
|
+
Version: 2.0.35
|
|
4
|
+
Summary: Python API for GShock Watches using BLE
|
|
5
|
+
Home-page: https://github.com/izivkov/gshock_api/
|
|
6
6
|
Author: Ivo Zivkov
|
|
7
7
|
Author-email: Ivo Zivkov <izivkov@gmail.com>
|
|
8
8
|
License-Expression: MIT
|
|
@@ -17,6 +17,7 @@ Requires-Dist: pydantic>=2.0.0
|
|
|
17
17
|
Requires-Dist: types-requests
|
|
18
18
|
Requires-Dist: python-dotenv
|
|
19
19
|
Requires-Dist: typing-extensions>=4.12
|
|
20
|
+
Requires-Dist: twine>=6.2.0
|
|
20
21
|
Provides-Extra: dev
|
|
21
22
|
Requires-Dist: basedpyright>=1.31.7; extra == "dev"
|
|
22
23
|
Requires-Dist: ruff; extra == "dev"
|
|
@@ -109,14 +110,14 @@ It is recommended that you create a virtual environment to run the tests:
|
|
|
109
110
|
|
|
110
111
|
.. code-block:: sh
|
|
111
112
|
|
|
112
|
-
|
|
113
|
+
uv run src/examples/api_tests.py
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
the library will try to connect to the last connected watch only. If you have multiple watches, you should use this parameter.
|
|
116
|
-
|
|
117
|
-
The optional **`--multi-watch`** parameter forces the library to scan for watches every time it tries to connect to a watch. If not provided,
|
|
118
|
-
the library will try to connect to the last connected watch only. If you have multiple watches, you should use this parameter.
|
|
115
|
+
or activate `venv`` first and then run using python:
|
|
119
116
|
|
|
117
|
+
.. code-block:: sh
|
|
118
|
+
|
|
119
|
+
source .venv/bin/activate
|
|
120
|
+
python src/examples/api_tests.py
|
|
120
121
|
|
|
121
122
|
Installing the library for your project:
|
|
122
123
|
========================================
|
|
@@ -127,7 +128,7 @@ Installing the library for your project:
|
|
|
127
128
|
|
|
128
129
|
See `this project <https://github.com/izivkov/GShockTimeServer>`_ using this library to run a time server for G-Shock watches.
|
|
129
130
|
|
|
130
|
-
See also `this blog <https://digitalsober.wordpress.com/
|
|
131
|
+
See also `this blog <https://digitalsober.wordpress.com/2024/05/05/g-shock-watch-integration-with-sxmo/>`_ for using the library in the `SXMO <https://sxmo.org/>`_ mobile environment.
|
|
131
132
|
|
|
132
133
|
Troubleshooting:
|
|
133
134
|
================
|
|
@@ -81,14 +81,14 @@ It is recommended that you create a virtual environment to run the tests:
|
|
|
81
81
|
|
|
82
82
|
.. code-block:: sh
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
uv run src/examples/api_tests.py
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
the library will try to connect to the last connected watch only. If you have multiple watches, you should use this parameter.
|
|
88
|
-
|
|
89
|
-
The optional **`--multi-watch`** parameter forces the library to scan for watches every time it tries to connect to a watch. If not provided,
|
|
90
|
-
the library will try to connect to the last connected watch only. If you have multiple watches, you should use this parameter.
|
|
86
|
+
or activate `venv`` first and then run using python:
|
|
91
87
|
|
|
88
|
+
.. code-block:: sh
|
|
89
|
+
|
|
90
|
+
source .venv/bin/activate
|
|
91
|
+
python src/examples/api_tests.py
|
|
92
92
|
|
|
93
93
|
Installing the library for your project:
|
|
94
94
|
========================================
|
|
@@ -99,7 +99,7 @@ Installing the library for your project:
|
|
|
99
99
|
|
|
100
100
|
See `this project <https://github.com/izivkov/GShockTimeServer>`_ using this library to run a time server for G-Shock watches.
|
|
101
101
|
|
|
102
|
-
See also `this blog <https://digitalsober.wordpress.com/
|
|
102
|
+
See also `this blog <https://digitalsober.wordpress.com/2024/05/05/g-shock-watch-integration-with-sxmo/>`_ for using the library in the `SXMO <https://sxmo.org/>`_ mobile environment.
|
|
103
103
|
|
|
104
104
|
Troubleshooting:
|
|
105
105
|
================
|
|
@@ -11,8 +11,8 @@ build-backend = "setuptools.build_meta"
|
|
|
11
11
|
|
|
12
12
|
[project]
|
|
13
13
|
name = "gshock_api" # Change to your project name
|
|
14
|
-
version = "2.0.
|
|
15
|
-
description = "
|
|
14
|
+
version = "2.0.35"
|
|
15
|
+
description = "Python API for GShock Watches using BLE"
|
|
16
16
|
authors = [{ name = "Ivo Zivkov", email = "izivkov@gmail.com" }]
|
|
17
17
|
|
|
18
18
|
license = "MIT"
|
|
@@ -25,6 +25,7 @@ dependencies = [
|
|
|
25
25
|
"types-requests",
|
|
26
26
|
"python-dotenv",
|
|
27
27
|
"typing-extensions>=4.12",
|
|
28
|
+
"twine>=6.2.0",
|
|
28
29
|
]
|
|
29
30
|
classifiers = [
|
|
30
31
|
"Development Status :: 4 - Beta",
|
|
@@ -6,10 +6,11 @@ author_email = izivkov@gmail.com
|
|
|
6
6
|
license = MIT
|
|
7
7
|
license_files = LICENSE.txt
|
|
8
8
|
long_description = file: README.rst
|
|
9
|
-
long_description_content_type = text/x-rst
|
|
10
|
-
url = https://github.com/
|
|
9
|
+
long_description_content_type = text/x-rst
|
|
10
|
+
url = https://github.com/izivkov/gshock_api/
|
|
11
11
|
project_urls =
|
|
12
|
-
Documentation = https://
|
|
12
|
+
Documentation = https://github.com/izivkov/gshock_api/
|
|
13
|
+
Source = https://github.com/izivkov/gshock_api/
|
|
13
14
|
platforms = any
|
|
14
15
|
classifiers =
|
|
15
16
|
Development Status :: 4 - Beta
|
|
@@ -63,7 +64,7 @@ exclude =
|
|
|
63
64
|
|
|
64
65
|
[pyscaffold]
|
|
65
66
|
version = 4.4
|
|
66
|
-
package =
|
|
67
|
+
package = gshock_api
|
|
67
68
|
|
|
68
69
|
[egg_info]
|
|
69
70
|
tag_build =
|
|
@@ -2,9 +2,9 @@ import asyncio
|
|
|
2
2
|
from collections.abc import Sequence
|
|
3
3
|
from datetime import datetime
|
|
4
4
|
import json
|
|
5
|
+
from pprint import pformat
|
|
5
6
|
import sys
|
|
6
7
|
import time
|
|
7
|
-
from typing import Optional
|
|
8
8
|
|
|
9
9
|
import pytz
|
|
10
10
|
|
|
@@ -58,7 +58,7 @@ async def run_api_tests(argv: Sequence[str]) -> None: # noqa: PLR0915
|
|
|
58
58
|
await api.set_time(time.time() + 10 * 60)
|
|
59
59
|
|
|
60
60
|
alarms = await api.get_alarms()
|
|
61
|
-
logger.info(f"alarms: {alarms}")
|
|
61
|
+
logger.info(f"alarms: {pformat(alarms)}")
|
|
62
62
|
|
|
63
63
|
alarms[3]["enabled"] = True
|
|
64
64
|
alarms[3]["hour"] = 7
|
|
@@ -79,7 +79,7 @@ async def run_api_tests(argv: Sequence[str]) -> None: # noqa: PLR0915
|
|
|
79
79
|
logger.info(f"condition: {condition}")
|
|
80
80
|
|
|
81
81
|
settings_local = await api.get_basic_settings()
|
|
82
|
-
logger.info(f"settings: {settings_local}")
|
|
82
|
+
logger.info(f"settings: {pformat(settings_local)}")
|
|
83
83
|
|
|
84
84
|
settings_local["button_tone"] = True
|
|
85
85
|
settings_local["language"] = "Russian"
|
|
@@ -111,11 +111,11 @@ async def run_api_tests(argv: Sequence[str]) -> None: # noqa: PLR0915
|
|
|
111
111
|
+ """}}"""
|
|
112
112
|
)
|
|
113
113
|
Event().create_event(json.loads(event_json_str))
|
|
114
|
-
logger.info(f"Created event: {event_json_str}")
|
|
114
|
+
logger.info(f"Created event: {pformat(json.loads(event_json_str))}")
|
|
115
115
|
|
|
116
116
|
reminders = await api.get_reminders()
|
|
117
117
|
for reminder in reminders:
|
|
118
|
-
logger.info(f"reminder: {reminder}")
|
|
118
|
+
logger.info (f"reminder: {pformat(reminder)}")
|
|
119
119
|
|
|
120
120
|
reminders[3]["title"] = "Test Event"
|
|
121
121
|
|
|
@@ -204,11 +204,10 @@ async def app_notifications(api: GshockAPI) -> None:
|
|
|
204
204
|
await api.send_app_notification(email_notification2)
|
|
205
205
|
|
|
206
206
|
|
|
207
|
-
def convert_time_string_to_epoch(time_string: str) ->
|
|
207
|
+
def convert_time_string_to_epoch(time_string: str) -> float | None:
|
|
208
208
|
try:
|
|
209
209
|
time_object = datetime.strptime(time_string, "%H:%M:%S")
|
|
210
|
-
|
|
211
|
-
return timestamp
|
|
210
|
+
return time_object.timestamp()
|
|
212
211
|
except ValueError:
|
|
213
212
|
logger.info("Invalid time format. Please use the format HH:MM:SS.")
|
|
214
213
|
return None
|
|
@@ -100,8 +100,7 @@ class Connection:
|
|
|
100
100
|
def is_service_supported(self, handle: int) -> bool:
|
|
101
101
|
"""Checks if a characteristic UUID mapped to a handle is present in the discovered characteristics."""
|
|
102
102
|
uuid: str | None = self.handles_map.get(handle)
|
|
103
|
-
|
|
104
|
-
return uuid not in self.characteristics_map
|
|
103
|
+
return uuid is not None and uuid in self.characteristics_map
|
|
105
104
|
|
|
106
105
|
async def write(self, handle: int, data: bytes) -> None:
|
|
107
106
|
"""Writes data to a characteristic identified by its handle."""
|
|
@@ -118,13 +117,14 @@ class Connection:
|
|
|
118
117
|
)
|
|
119
118
|
return
|
|
120
119
|
|
|
121
|
-
|
|
120
|
+
# 0x0E is CASIO_ALL_FEATURES_CHARACTERISTIC_UUID (requires response)
|
|
121
|
+
response_type: bool = handle == 0x0E
|
|
122
122
|
|
|
123
123
|
cmd_data: bytes = to_casio_cmd(data)
|
|
124
124
|
|
|
125
125
|
if self.client:
|
|
126
126
|
await self.client.write_gatt_char(
|
|
127
|
-
uuid, cmd_data, response=
|
|
127
|
+
uuid, cmd_data, response=response_type
|
|
128
128
|
)
|
|
129
129
|
|
|
130
130
|
except Exception as e:
|
|
@@ -155,6 +155,6 @@ class Connection:
|
|
|
155
155
|
return handles_map
|
|
156
156
|
|
|
157
157
|
# Replaced Any with TypeVar T
|
|
158
|
-
async def
|
|
158
|
+
async def send_message(self, message: T) -> None:
|
|
159
159
|
"""Sends a message to the watch using the message dispatcher."""
|
|
160
160
|
await message_dispatcher.MessageDispatcher.send_to_watch(message)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations # Enables forward references like 'Event'
|
|
2
2
|
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from datetime import
|
|
4
|
+
from datetime import datetime
|
|
5
5
|
import json
|
|
6
6
|
import types
|
|
7
7
|
from typing import TYPE_CHECKING, Final, TypeVar
|
|
@@ -10,6 +10,7 @@ if TYPE_CHECKING:
|
|
|
10
10
|
from collections.abc import ( # Using Mapping for dict types where object values are complex
|
|
11
11
|
Mapping,
|
|
12
12
|
)
|
|
13
|
+
from datetime import date, tzinfo
|
|
13
14
|
|
|
14
15
|
# Define a Type Variable T for generic message objects
|
|
15
16
|
T = TypeVar("T")
|
|
@@ -54,23 +54,23 @@ class GshockAPI:
|
|
|
54
54
|
result: WatchButton = await message_dispatcher.ButtonPressedIO.request(self.connection)
|
|
55
55
|
return result
|
|
56
56
|
|
|
57
|
-
async def get_world_cities(self,
|
|
57
|
+
async def get_world_cities(self, city_number: int) -> str:
|
|
58
58
|
"""Get the name for a particular World City set on the watch."""
|
|
59
|
-
return await self._get_world_cities(
|
|
59
|
+
return await self._get_world_cities(city_number)
|
|
60
60
|
|
|
61
|
-
async def _get_world_cities(self,
|
|
61
|
+
async def _get_world_cities(self, city_number: int) -> str:
|
|
62
62
|
# Assuming WorldCitiesIO.request returns a string
|
|
63
|
-
result: str = await message_dispatcher.WorldCitiesIO.request(self.connection,
|
|
63
|
+
result: str = await message_dispatcher.WorldCitiesIO.request(self.connection, city_number)
|
|
64
64
|
return result
|
|
65
65
|
|
|
66
|
-
async def get_dst_for_world_cities(self,
|
|
66
|
+
async def get_dst_for_world_cities(self, city_number: int) -> str:
|
|
67
67
|
"""Get the **Daylight Saving Time** for a particular World City set on the watch."""
|
|
68
|
-
return await self._get_dst_for_world_cities(
|
|
68
|
+
return await self._get_dst_for_world_cities(city_number)
|
|
69
69
|
|
|
70
|
-
async def _get_dst_for_world_cities(self,
|
|
70
|
+
async def _get_dst_for_world_cities(self, city_number: int) -> str:
|
|
71
71
|
# Assuming DstForWorldCitiesIO.request returns a string
|
|
72
72
|
result: str = await message_dispatcher.DstForWorldCitiesIO.request(
|
|
73
|
-
self.connection,
|
|
73
|
+
self.connection, city_number
|
|
74
74
|
)
|
|
75
75
|
return result
|
|
76
76
|
|
|
@@ -124,38 +124,16 @@ class GshockAPI:
|
|
|
124
124
|
await self.read_and_write(function, state)
|
|
125
125
|
|
|
126
126
|
async def read_write_dst_for_world_cities(self) -> None:
|
|
127
|
-
|
|
128
|
-
array_of_get_dst_for_world_cities: list[dict[str, RequestFunction | int]] = [ # noqa: F821 # type: ignore
|
|
129
|
-
{"function": self.get_dst_for_world_cities, "city_number": 0},
|
|
130
|
-
{"function": self.get_dst_for_world_cities, "city_number": 1},
|
|
131
|
-
{"function": self.get_dst_for_world_cities, "city_number": 2},
|
|
132
|
-
{"function": self.get_dst_for_world_cities, "city_number": 3},
|
|
133
|
-
{"function": self.get_dst_for_world_cities, "city_number": 4},
|
|
134
|
-
{"function": self.get_dst_for_world_cities, "city_number": 5},
|
|
135
|
-
]
|
|
127
|
+
fn = self.get_dst_for_world_cities
|
|
136
128
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
function: RequestFunction = item["function"] # type: ignore[assignment] # noqa: F821
|
|
140
|
-
city_number: int = item["city_number"] # type: ignore[assignment]
|
|
141
|
-
await self.read_and_write(function, city_number)
|
|
129
|
+
for city_number in range(watch_info.worldCitiesCount):
|
|
130
|
+
await self.read_and_write(fn, city_number)
|
|
142
131
|
|
|
143
132
|
async def read_write_world_cities(self) -> None:
|
|
144
|
-
|
|
145
|
-
array_of_world_cities: list[dict[str, RequestFunction | int]] = [ # noqa: F821 # type: ignore
|
|
146
|
-
{"function": self.get_world_cities, "city_number": 0},
|
|
147
|
-
{"function": self.get_world_cities, "city_number": 1},
|
|
148
|
-
{"function": self.get_world_cities, "city_number": 2},
|
|
149
|
-
{"function": self.get_world_cities, "city_number": 3},
|
|
150
|
-
{"function": self.get_world_cities, "city_number": 4},
|
|
151
|
-
{"function": self.get_world_cities, "city_number": 5},
|
|
152
|
-
]
|
|
133
|
+
fn = self.get_world_cities
|
|
153
134
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
function: RequestFunction = item["function"] # noqa: F821 # type: ignore
|
|
157
|
-
city_number: int = item["city_number"] # type: ignore[assignment]
|
|
158
|
-
await self.read_and_write(function, city_number)
|
|
135
|
+
for city_number in range(watch_info.worldCitiesCount):
|
|
136
|
+
await self.read_and_write(fn, city_number)
|
|
159
137
|
|
|
160
138
|
# current_time is unknown type, using object | None
|
|
161
139
|
async def set_time(
|
|
@@ -191,8 +169,8 @@ class GshockAPI:
|
|
|
191
169
|
# Assuming T objects are JSON serializable
|
|
192
170
|
alarms_str: str = json.dumps(alarms)
|
|
193
171
|
set_action_cmd: str = f'{{"action":"SET_ALARMS", "value":{alarms_str} }}'
|
|
194
|
-
# connection.
|
|
195
|
-
await self.connection.
|
|
172
|
+
# connection.send_message expects T, which must be convertible to a watch message
|
|
173
|
+
await self.connection.send_message(set_action_cmd)
|
|
196
174
|
|
|
197
175
|
async def get_timer(self) -> int:
|
|
198
176
|
"""Get Timer value in seconds."""
|
|
@@ -203,10 +181,10 @@ class GshockAPI:
|
|
|
203
181
|
result: int = await message_dispatcher.TimerIO.request(self.connection)
|
|
204
182
|
return result
|
|
205
183
|
|
|
206
|
-
async def set_timer(self,
|
|
184
|
+
async def set_timer(self, timer_value: int) -> None:
|
|
207
185
|
"""Set Timer value in seconds."""
|
|
208
|
-
message: str = f'{{"action": "SET_TIMER", "value": {
|
|
209
|
-
await self.connection.
|
|
186
|
+
message: str = f'{{"action": "SET_TIMER", "value": {timer_value} }}'
|
|
187
|
+
await self.connection.send_message(message)
|
|
210
188
|
|
|
211
189
|
# Watch condition request returns an unknown object (object)
|
|
212
190
|
async def get_watch_condition(self) -> object:
|
|
@@ -224,7 +202,7 @@ class GshockAPI:
|
|
|
224
202
|
) -> None:
|
|
225
203
|
"""Sets auto-tame adjustment for the watch"""
|
|
226
204
|
message: str = f"""{{"action": "SET_TIME_ADJUSTMENT", "timeAdjustment": "{time_adjustement}", "minutesAfterHour": "{minutes_after_hour}" }}"""
|
|
227
|
-
await self.connection.
|
|
205
|
+
await self.connection.send_message(message)
|
|
228
206
|
|
|
229
207
|
# SettingsIO returns a list of unknown Setting objects (list[T])
|
|
230
208
|
async def get_basic_settings(self) -> list[T]:
|
|
@@ -237,20 +215,11 @@ class GshockAPI:
|
|
|
237
215
|
"""Set settings to the watch."""
|
|
238
216
|
setting_json: str = json.dumps(settings)
|
|
239
217
|
message: str = f'{{"action": "SET_SETTINGS", "value": {setting_json} }}'
|
|
240
|
-
await self.connection.
|
|
218
|
+
await self.connection.send_message(message)
|
|
241
219
|
|
|
242
220
|
# get_reminders returns a list of unknown Event objects (list[T])
|
|
243
221
|
async def get_reminders(self) -> list[T]:
|
|
244
|
-
|
|
245
|
-
reminders: list[T] = [] # type: ignore[assignment]
|
|
246
|
-
|
|
247
|
-
reminders.append(await self.get_event_from_watch(1)) # type: ignore[arg-type]
|
|
248
|
-
reminders.append(await self.get_event_from_watch(2)) # type: ignore[arg-type]
|
|
249
|
-
reminders.append(await self.get_event_from_watch(3)) # type: ignore[arg-type]
|
|
250
|
-
reminders.append(await self.get_event_from_watch(4)) # type: ignore[arg-type]
|
|
251
|
-
reminders.append(await self.get_event_from_watch(5)) # type: ignore[arg-type]
|
|
252
|
-
|
|
253
|
-
return reminders
|
|
222
|
+
return [await self.get_event_from_watch(i) for i in range(1, 6)]
|
|
254
223
|
|
|
255
224
|
# get_event_from_watch returns an unknown Event object (T)
|
|
256
225
|
async def get_event_from_watch(self, event_number: int) -> T:
|
|
@@ -284,7 +253,7 @@ class GshockAPI:
|
|
|
284
253
|
events_as_json: list[Mapping[str, object]] = to_json(events)
|
|
285
254
|
enabled: list[Mapping[str, object]] = get_enabled_events(events_as_json)
|
|
286
255
|
|
|
287
|
-
await self.connection.
|
|
256
|
+
await self.connection.send_message(
|
|
288
257
|
f"""{{"action": "SET_REMINDERS", "value": {json.dumps(enabled)}}}"""
|
|
289
258
|
)
|
|
290
259
|
|
|
@@ -45,12 +45,13 @@ class AlarmsIO:
|
|
|
45
45
|
AlarmsIO.connection = connection
|
|
46
46
|
alarms_inst_typed.clear()
|
|
47
47
|
await AlarmsIO._get_alarms(connection)
|
|
48
|
-
|
|
48
|
+
if AlarmsIO.result is None:
|
|
49
|
+
raise RuntimeError("AlarmsIO.result must not be None after _get_alarms")
|
|
49
50
|
return AlarmsIO.result
|
|
50
51
|
|
|
51
52
|
@staticmethod
|
|
52
53
|
async def _get_alarms(connection: ConnectionProtocol) -> CancelableResult[list[dict[str, object]]]:
|
|
53
|
-
await connection.
|
|
54
|
+
await connection.send_message('{ "action": "GET_ALARMS"}')
|
|
54
55
|
AlarmsIO.result = CancelableResult[list[dict[str, object]]]()
|
|
55
56
|
return await AlarmsIO.result.get_result()
|
|
56
57
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import TypedDict
|
|
3
3
|
|
|
4
4
|
from gshock_api.cancelable_result import CancelableResult
|
|
5
5
|
from gshock_api.casio_constants import CasioConstants
|
|
@@ -45,7 +45,7 @@ class ReminderTimeDict(TypedDict):
|
|
|
45
45
|
repeat_period: str
|
|
46
46
|
start_date: DateDict
|
|
47
47
|
end_date: DateDict
|
|
48
|
-
days_of_week:
|
|
48
|
+
days_of_week: list[str]
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
class EventsIO:
|
|
@@ -10,9 +10,9 @@ class WorldCitiesIO:
|
|
|
10
10
|
connection: ConnectionProtocol | None = None
|
|
11
11
|
|
|
12
12
|
@staticmethod
|
|
13
|
-
async def request(connection: ConnectionProtocol,
|
|
13
|
+
async def request(connection: ConnectionProtocol, city_number: int) -> CancelableResult[bytes]:
|
|
14
14
|
WorldCitiesIO.connection = connection
|
|
15
|
-
key = f"1f0{
|
|
15
|
+
key = f"1f0{city_number}"
|
|
16
16
|
await connection.request(key)
|
|
17
17
|
|
|
18
18
|
WorldCitiesIO.result = CancelableResult[bytes]()
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Final
|
|
3
|
+
|
|
4
|
+
LogLevel: Final[int] = int
|
|
5
|
+
|
|
6
|
+
_logger: logging.Logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Logger:
|
|
10
|
+
"""
|
|
11
|
+
A simple wrapper around the standard Python logging module for consistent configuration.
|
|
12
|
+
"""
|
|
13
|
+
DEFAULT_LOG_LEVEL: Final[LogLevel] = logging.INFO
|
|
14
|
+
|
|
15
|
+
def __init__(self, log_level: LogLevel = DEFAULT_LOG_LEVEL) -> None:
|
|
16
|
+
self.log_level = log_level
|
|
17
|
+
|
|
18
|
+
logging.basicConfig(
|
|
19
|
+
level=self.log_level,
|
|
20
|
+
handlers=[logging.StreamHandler()],
|
|
21
|
+
format="%(asctime)-15s %(name)-15s %(levelname)s: %(message)s",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
def _join(self, *args: object) -> str:
|
|
25
|
+
"""Join args like print() does."""
|
|
26
|
+
return " ".join(str(a) for a in args)
|
|
27
|
+
|
|
28
|
+
# Logging methods -----------
|
|
29
|
+
|
|
30
|
+
def error(self, *args: object) -> None:
|
|
31
|
+
_logger.error(self._join(*args))
|
|
32
|
+
|
|
33
|
+
def info(self, *args: object) -> None:
|
|
34
|
+
_logger.info(self._join(*args))
|
|
35
|
+
|
|
36
|
+
def debug(self, *args: object) -> None:
|
|
37
|
+
_logger.debug(self._join(*args))
|
|
38
|
+
|
|
39
|
+
def warn(self, *args: object) -> None:
|
|
40
|
+
_logger.warning(self._join(*args))
|
|
41
|
+
|
|
42
|
+
def warning(self, *args: object) -> None:
|
|
43
|
+
_logger.warning(self._join(*args))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
logger: Logger = Logger()
|
|
@@ -24,10 +24,10 @@ MAX_SCAN_RETRIES: Final[int] = 60
|
|
|
24
24
|
# --- Type Aliases ---
|
|
25
25
|
|
|
26
26
|
# WatchFilter is a function that takes a BLEDevice name (str) and returns a boolean.
|
|
27
|
-
WatchFilter
|
|
27
|
+
type WatchFilter = Callable[[str], bool] | None
|
|
28
28
|
|
|
29
29
|
# Type for the filter used in find_device_by_filter (takes device and ad data, returns bool)
|
|
30
|
-
BleakDeviceFilter
|
|
30
|
+
type BleakDeviceFilter = Callable[[BLEDevice, AdvertisementData], bool]
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class Scanner:
|
|
@@ -38,8 +38,7 @@ class Scanner:
|
|
|
38
38
|
async def scan(
|
|
39
39
|
self,
|
|
40
40
|
device_address: str | None = None,
|
|
41
|
-
|
|
42
|
-
watch_filter: WatchFilter | None = None, # type: ignore
|
|
41
|
+
watch_filter: WatchFilter = None,
|
|
43
42
|
max_retries: int = MAX_SCAN_RETRIES
|
|
44
43
|
) -> BLEDevice | None:
|
|
45
44
|
|