Robomow-BLE 1.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.
@@ -0,0 +1,43 @@
1
+ """Robomow-BLE provides a reusable Bluetooth Low Energy protocol layer for
2
+ communicating with Robomow mowers.
3
+
4
+ The package exposes a small top-level API intended for direct use:
5
+
6
+ - ``RobomowDevice``: main client used to connect, read state, and send commands.
7
+ - ``RobomowUpdate``: callback payload for state changes.
8
+ - ``RobomowAuthenticationError`` and ``RobomowProtocolError``: protocol errors.
9
+ - Enums: ``MowerFamily``, ``MowerModel``, ``MowerOperatingState``,
10
+ ``EntityKey``, ``WireSignalType``, ``Zone``.
11
+ - Datatypes: ``MowerSchedule``, ``MowerSchedule.Day``, ``MowerOperation``,
12
+ ``Message``.
13
+ """
14
+
15
+ from .const import (
16
+ EntityKey,
17
+ Message,
18
+ MowerFamily,
19
+ MowerModel,
20
+ MowerOperation,
21
+ MowerOperatingState,
22
+ MowerSchedule,
23
+ WireSignalType,
24
+ Zone,
25
+ )
26
+ from .exceptions import RobomowAuthenticationError, RobomowProtocolError
27
+ from .mower import RobomowDevice, RobomowUpdate
28
+
29
+ __all__ = [
30
+ "RobomowDevice",
31
+ "RobomowUpdate",
32
+ "RobomowProtocolError",
33
+ "RobomowAuthenticationError",
34
+ "Message",
35
+ "MowerOperation",
36
+ "MowerFamily",
37
+ "MowerModel",
38
+ "MowerSchedule",
39
+ "MowerOperatingState",
40
+ "EntityKey",
41
+ "WireSignalType",
42
+ "Zone",
43
+ ]
robomow_ble/const.py ADDED
@@ -0,0 +1,205 @@
1
+ """Shared constants and enums for the Robomow BLE package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import datetime
6
+ import logging
7
+ from enum import IntEnum, StrEnum
8
+
9
+ from attr import dataclass, field
10
+
11
+ LOGGER: logging.Logger = logging.getLogger(__package__)
12
+
13
+ MAINBOARD_SERIAL_LENGTH = 14
14
+ AUTH_RESPONSE_LENGTH = 15
15
+
16
+ MINIMUM_MESSAGE_LENGTH = 4
17
+ MESSAGE_START_BYTE = 0xAA
18
+ MESSAGE_SEND_BYTE = 0x1F
19
+ MESSAGE_RECEIVE_BYTE = 0x1E
20
+
21
+ UUID_SERVICE = "ff00a501-d020-913c-1234-56d97200a6a6"
22
+ UUID_CHAR_AUTHENTICATE = "ff00a502-d020-913c-1234-56d97200a6a6"
23
+ UUID_CHAR_DATA_OUT = "ff00a503-d020-913c-1234-56d97200a6a6"
24
+ UUID_CHAR_DATA_IN = "ff00a506-d020-913c-1234-56d97200a6a6"
25
+
26
+ UNKNOWN_FIELD_VALUE = 0xFFFF
27
+
28
+ class MessageType(IntEnum):
29
+ """Basic message types used in packet payloads."""
30
+
31
+ ACKNOWLEDGE = 0x04
32
+ CLEAR_USER_MESSAGE = 0x0E
33
+ GET_CONFIG = 0x0F
34
+ COMMAND = 0x15
35
+ MISCELLANEOUS = 0x16
36
+ GET_MESSAGE = 0x1B
37
+ UPDATE_DATE_TIME = 0x1D
38
+ WRITE_EEPROM = 0x1F
39
+ READ_EEPROM = 0x20
40
+
41
+
42
+ class WireSignalType(IntEnum):
43
+ """Wire signal types used in EEPROM parameters."""
44
+
45
+ TYPE_A = 0x00
46
+ TYPE_B = 0x01
47
+ TYPE_C = 0x02
48
+
49
+
50
+ class Zone(IntEnum):
51
+ """Robomow mower zones."""
52
+
53
+ MAIN = 0
54
+ STARTING_POINT_A = 1
55
+ STARTING_POINT_B = 2
56
+ SUB_1 = 3
57
+ SUB_2 = 4
58
+ SUB_3 = 5
59
+ SUB_4 = 6
60
+
61
+
62
+ class MowerFamily(IntEnum):
63
+ """Robomow mower types."""
64
+
65
+ Unknown = -1
66
+ RS = 1
67
+ RC = 2
68
+ RX = 3
69
+ RK = 4
70
+ RT = 5
71
+
72
+
73
+ class MowerModel(IntEnum):
74
+ """Robomow mower models."""
75
+
76
+ Unknown = -1
77
+ RT300 = 5
78
+ RT500 = 6
79
+ RT700 = 7
80
+
81
+
82
+ @dataclass
83
+ class MowerSchedule:
84
+ """Data class representing a Robomow mowing schedule.
85
+
86
+ Attributes:
87
+ start_time: Start of the daily mowing window.
88
+ end_time: End of the daily mowing window.
89
+ day: Seven-day schedule entries, ordered Monday to Sunday.
90
+ """
91
+
92
+ @dataclass
93
+ class Day:
94
+ """Data class representing a day in the mowing schedule.
95
+
96
+ Attributes:
97
+ enabled: Whether mowing is enabled for the day.
98
+ cycles: Number of mowing cycles scheduled for the day.
99
+ zone: Zone to mow during the schedule entry.
100
+ duration: Mowing duration in minutes.
101
+ """
102
+
103
+ enabled: bool = True
104
+ cycles: int = 1
105
+ zone: Zone = Zone.MAIN
106
+ duration: int = 30
107
+
108
+ start_time: datetime.time = datetime.time(hour=9, minute=0)
109
+ end_time: datetime.time = datetime.time(hour=21, minute=0)
110
+ day: tuple[Day, ...] = field(
111
+ factory=lambda: tuple(MowerSchedule.Day() for _ in range(7))
112
+ )
113
+
114
+
115
+ class MowerOperatingState(StrEnum):
116
+ """Human-readable Robomow operating states."""
117
+
118
+ WARMING_UP = "Warming up"
119
+ MOWING = "Mowing"
120
+ EDGE_MOWING = "Edge Mowing"
121
+ RETURNING_HOME_FOLLOWING_EDGE = "Following edge home"
122
+ RETURNING_HOME_WARMING_UP = "Warming up to return home"
123
+ RETURNING_HOME_SEARCHING_EDGE = "Searching edge"
124
+
125
+ GOING_TO_START = "Going to starting point"
126
+ LEARNING_ENTRY_POINT = "Learning entry point"
127
+ IDLE = "Idle"
128
+ CHARGING = "Charging"
129
+ AUTOMATIC = "Automatic"
130
+ REMOTE_CONTROL = "Remote control"
131
+ BIT = "Bit"
132
+
133
+
134
+ class EntityKey(StrEnum):
135
+ """Entity keys for Robomow entities."""
136
+
137
+ LAWN_MOWER = "lawn_mower"
138
+ BATTERY_LEVEL = "battery_level"
139
+ FAMILY = "family"
140
+ MODEL = "model"
141
+ SOFTWARE_VERSION = "software_version"
142
+ SOFTWARE_RELEASE = "software_release"
143
+ MAINBOARD_VERSION = "mainboard_version"
144
+ STATE = "state"
145
+ MESSAGE = "message"
146
+ SIGNAL_STRENGTH = "signal_strength"
147
+ START_MOWING = "async_start_mowing"
148
+ STOP_MOWING = "async_stop_mowing"
149
+ RETURN_HOME = "return_home"
150
+ EDGE_MOWING = "edge_mowing"
151
+ SCHEDULE_ENABLED = "schedule_enabled"
152
+ SCHEDULE = "schedule"
153
+ SERVICE_INFO = "service_info"
154
+ NEXT_DEPARTURE = "next_departure"
155
+ PREVIOUS_DEPARTURE = "previous_departure"
156
+ EXPECTED_DURATION = "expected_duration"
157
+ NO_DEPART_REASON = "no_depart_reason"
158
+ ANTI_THEFT_ENABLED = "anti_theft_enabled"
159
+ CHILD_LOCK_ENABLED = "child_lock_enabled"
160
+ ANTI_THEFT_ACTIVE = "anti_theft_active"
161
+ MOWER_HOME = "mower_home"
162
+ CHARGING_ACTIVE = "charging_active"
163
+ DISABLING_DEVICE_REMOVED = "disabling_device_removed"
164
+ WIRE_SIGNAL_TYPE = "wire_signal_type"
165
+ STARTING_POINT_A = "starting_point_a"
166
+ STARTING_POINT_B = "starting_point_b"
167
+ LAST_OPERATIONS = "last_operations"
168
+
169
+
170
+ @dataclass
171
+ class MowerOperation:
172
+ """A single parsed mower operation history entry.
173
+
174
+ Attributes:
175
+ id: Operation record identifier.
176
+ start_time: Start time of the operation.
177
+ duration: Operation duration in minutes.
178
+ zone: Zone used for the operation.
179
+ error: Message describing the operation result.
180
+ """
181
+
182
+ id: int
183
+ start_time: datetime.datetime
184
+ duration: int
185
+ zone: Zone
186
+ error: Message
187
+
188
+
189
+ @dataclass(frozen=True)
190
+ class Message:
191
+ """Base class for user-facing messages with optional title and text.
192
+
193
+ Attributes:
194
+ title: Short human-readable message title.
195
+ text: Optional longer explanatory text.
196
+ number: Optional numeric code used by the mower protocol.
197
+ """
198
+
199
+ title: str
200
+ text: str | None = None
201
+ number: int | None = None
202
+
203
+ def __str__(self) -> str:
204
+ """Return a user-friendly string representation of the message."""
205
+ return f"{self.title} - {self.text}" if self.text else self.title