Skip to content

Commit 5eabe52

Browse files
authored
Add support for Gen4 devices (#724)
* Add support for Gen4 devices * Fix test * Fix the leftovers
1 parent e2350e3 commit 5eabe52

File tree

6 files changed

+37
-21
lines changed

6 files changed

+37
-21
lines changed

aioshelly/const.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
GEN1 = 1
127127
GEN2 = 2
128128
GEN3 = 3
129+
GEN4 = 4
129130

130131

131132
# Firmware 1.9.0 release date
@@ -142,12 +143,16 @@
142143
# Firmware 1.0.99 release date
143144
GEN3_MIN_FIRMWARE_DATE = 20231102
144145

146+
# Firmware 1.4.x release date
147+
GEN4_MIN_FIRMWARE_DATE = 20240902
148+
145149

146150
# Fallback for unknown devices
147151
MIN_FIRMWARE_DATES = {
148152
GEN1: GEN1_MIN_FIRMWARE_DATE,
149153
GEN2: GEN2_MIN_FIRMWARE_DATE,
150154
GEN3: GEN3_MIN_FIRMWARE_DATE,
155+
GEN4: GEN4_MIN_FIRMWARE_DATE,
151156
}
152157

153158

@@ -952,7 +957,7 @@ class UndefinedType(Enum):
952957
NOTIFY_WS_CLOSED = "NotifyWebSocketClosed"
953958

954959
BLOCK_GENERATIONS = {GEN1}
955-
RPC_GENERATIONS = {GEN2, GEN3}
960+
RPC_GENERATIONS = {GEN2, GEN3, GEN4}
956961

957962
DEFAULT_HTTP_PORT = 80
958963
PERIODIC_COAP_TYPE_CODE = 30

aioshelly/rpc_device/device.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ def shelly(self) -> dict[str, Any]:
457457

458458
@property
459459
def gen(self) -> int:
460-
"""Device generation: GEN2/3 - RPC."""
460+
"""Device generation: GEN2/3/4 - RPC."""
461461
if self._shelly is None:
462462
raise NotInitialized
463463

tests/test_common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
@pytest.mark.parametrize(
2727
("gen", "model", "firmware_version", "expected"),
2828
[
29-
(4, "XYZ-G4", "20240913-112054/v1.0.0-gcb84623", False),
29+
(5, "XYZ-G5", "20250913-112054/v1.0.0-gcb84623", False),
30+
(4, "XYZ-G4", "20240913-112054/v1.0.0-gcb84623", True),
3031
(1, "SHSW-44", "20230913-112054/v1.14.0-gcb84623", False),
3132
(1, "SHSW-1", "20230913-112054/v1.14.0-gcb84623", True),
3233
(2, "SNDC-0D4P10WW", "20230703-112054/0.99.0-gcb84623", False),

tools/common/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ async def create_device(
4242
options: ConnectionOptions,
4343
gen: int | None,
4444
) -> Any:
45-
"""Create a Gen1/Gen2/Gen3 device."""
45+
"""Create a device."""
4646
if gen is None:
4747
if info := await get_info(
4848
aiohttp_session, options.ip_address, port=options.port
@@ -170,7 +170,7 @@ def print_block_device(device: BlockDevice) -> None:
170170

171171

172172
def print_rpc_device(device: RpcDevice) -> None:
173-
"""Print RPC (GEN2/3) device data."""
173+
"""Print RPC (GEN2/3/4) device data."""
174174
print(f"Status: {device.status}")
175175
print(f"Event: {device.event}")
176176
print(f"Connected: {device.connected}")

tools/example.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ def get_arguments() -> tuple[argparse.ArgumentParser, argparse.Namespace]:
135135
parser.add_argument(
136136
"--gen3", "-g3", action="store_true", help="Force Gen 3 (RPC) device"
137137
)
138+
parser.add_argument(
139+
"--gen4", "-g4", action="store_true", help="Force Gen 4 (RPC) device"
140+
)
138141
parser.add_argument(
139142
"--debug", "-deb", action="store_true", help="Enable debug level for logging"
140143
)
@@ -145,7 +148,7 @@ def get_arguments() -> tuple[argparse.ArgumentParser, argparse.Namespace]:
145148
"--update_ws",
146149
"-uw",
147150
type=str,
148-
help="Update outbound WebSocket (Gen2/3) and exit",
151+
help="Update outbound WebSocket (for RPC device) and exit",
149152
)
150153
parser.add_argument(
151154
"--listen_ip_address",
@@ -168,14 +171,14 @@ async def main() -> None:
168171
await coap_context.initialize(args.coap_port, args.listen_ip_address)
169172
await ws_context.initialize(args.ws_port, args.ws_api_url)
170173

171-
if not args.init and not (args.gen1 or args.gen2 or args.gen3):
174+
if not args.init and not (args.gen1 or args.gen2 or args.gen3 or args.gen4):
172175
parser.error("specify gen if no device init at startup")
173-
if args.gen1 and args.gen2:
174-
parser.error("--gen1 and --gen2 can't be used together")
175-
elif args.gen1 and args.gen3:
176-
parser.error("--gen1 and --gen3 can't be used together")
177-
elif args.gen2 and args.gen3:
178-
parser.error("--gen2 and --gen3 can't be used together")
176+
177+
gen_list = (args.gen1, args.gen2, args.gen3, args.gen4)
178+
if len([gen for gen in gen_list if gen]) > 1:
179+
parser.error(
180+
"You can only use one of --gen1, --gen2, --gen3 or --gen4 at a time"
181+
)
179182

180183
gen = None
181184
if args.gen1:
@@ -184,13 +187,15 @@ async def main() -> None:
184187
gen = 2
185188
elif args.gen3:
186189
gen = 3
190+
elif args.gen4:
191+
gen = 4
187192

188193
if args.debug:
189194
logging.basicConfig(level=logging.DEBUG)
190195
# if gen is in args reduce logging for other gens
191196
if args.gen1:
192197
logging.getLogger("aioshelly.rpc_device").setLevel(logging.INFO)
193-
elif args.gen2 or args.gen3:
198+
elif args.gen2 or args.gen3 or args.gen4:
194199
logging.getLogger("aioshelly.block_device").setLevel(logging.INFO)
195200

196201
if args.devices:

tools/fixture.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ def get_arguments() -> tuple[argparse.ArgumentParser, argparse.Namespace]:
287287
parser.add_argument(
288288
"--gen3", "-g3", action="store_true", help="Force Gen 3 (RPC) device"
289289
)
290+
parser.add_argument(
291+
"--gen4", "-g4", action="store_true", help="Force Gen 4 (RPC) device"
292+
)
290293
parser.add_argument(
291294
"--debug", "-deb", action="store_true", help="Enable debug level for logging"
292295
)
@@ -306,14 +309,14 @@ async def main() -> None:
306309
await coap_context.initialize(args.coap_port)
307310
await ws_context.initialize(args.ws_port, args.ws_api_url)
308311

309-
if not args.init and not (args.gen1 or args.gen2 or args.gen3):
312+
if not args.init and not (args.gen1 or args.gen2 or args.gen3 or args.gen4):
310313
parser.error("specify gen if no device init at startup")
311-
if args.gen1 and args.gen2:
312-
parser.error("--gen1 and --gen2 can't be used together")
313-
elif args.gen1 and args.gen3:
314-
parser.error("--gen1 and --gen3 can't be used together")
315-
elif args.gen2 and args.gen3:
316-
parser.error("--gen2 and --gen3 can't be used together")
314+
315+
gen_list = (args.gen1, args.gen2, args.gen3, args.gen4)
316+
if len([gen for gen in gen_list if gen]) > 1:
317+
parser.error(
318+
"You can only use one of --gen1, --gen2, --gen3 or --gen4 at a time"
319+
)
317320

318321
gen = None
319322
if args.gen1:
@@ -322,6 +325,8 @@ async def main() -> None:
322325
gen = 2
323326
elif args.gen3:
324327
gen = 3
328+
elif args.gen4:
329+
gen = 4
325330

326331
if args.debug:
327332
logging.basicConfig(level="DEBUG", force=True)

0 commit comments

Comments
 (0)