lifx-emulator 2.3.1__tar.gz → 3.0.1__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.
Files changed (145) hide show
  1. lifx_emulator-3.0.1/CHANGELOG.md +27 -0
  2. lifx_emulator-3.0.1/PKG-INFO +102 -0
  3. lifx_emulator-3.0.1/README.md +74 -0
  4. {lifx_emulator-2.3.1 → lifx_emulator-3.0.1}/pyproject.toml +22 -82
  5. lifx_emulator-3.0.1/src/lifx_emulator_app/__init__.py +10 -0
  6. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/__main__.py +13 -5
  7. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/__init__.py +1 -1
  8. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/app.py +3 -3
  9. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/mappers/__init__.py +1 -1
  10. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/mappers/device_mapper.py +1 -1
  11. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/models.py +1 -2
  12. lifx_emulator-3.0.1/src/lifx_emulator_app/api/routers/__init__.py +11 -0
  13. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/routers/devices.py +2 -2
  14. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/routers/monitoring.py +1 -1
  15. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/routers/scenarios.py +1 -1
  16. lifx_emulator-3.0.1/src/lifx_emulator_app/api/services/__init__.py +8 -0
  17. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/services/device_service.py +3 -2
  18. lifx_emulator-3.0.1/tests/conftest.py +9 -0
  19. {lifx_emulator-2.3.1 → lifx_emulator-3.0.1}/tests/test_api.py +3 -4
  20. {lifx_emulator-2.3.1 → lifx_emulator-3.0.1}/tests/test_api_validation.py +1 -2
  21. {lifx_emulator-2.3.1 → lifx_emulator-3.0.1}/tests/test_cli.py +45 -46
  22. {lifx_emulator-2.3.1 → lifx_emulator-3.0.1}/tests/test_cli_validation.py +1 -2
  23. lifx_emulator-2.3.1/.github/workflows/ci.yml +0 -188
  24. lifx_emulator-2.3.1/.github/workflows/docs.yml +0 -111
  25. lifx_emulator-2.3.1/.pre-commit-config.yaml +0 -101
  26. lifx_emulator-2.3.1/CLAUDE.md +0 -940
  27. lifx_emulator-2.3.1/LICENSE +0 -35
  28. lifx_emulator-2.3.1/PKG-INFO +0 -107
  29. lifx_emulator-2.3.1/README.md +0 -79
  30. lifx_emulator-2.3.1/docs/advanced/device-management-api.md +0 -658
  31. lifx_emulator-2.3.1/docs/advanced/index.md +0 -145
  32. lifx_emulator-2.3.1/docs/advanced/scenario-api.md +0 -809
  33. lifx_emulator-2.3.1/docs/advanced/scenarios.md +0 -406
  34. lifx_emulator-2.3.1/docs/advanced/storage.md +0 -291
  35. lifx_emulator-2.3.1/docs/api/device.md +0 -489
  36. lifx_emulator-2.3.1/docs/api/factories.md +0 -340
  37. lifx_emulator-2.3.1/docs/api/index.md +0 -265
  38. lifx_emulator-2.3.1/docs/api/products.md +0 -539
  39. lifx_emulator-2.3.1/docs/api/protocol.md +0 -718
  40. lifx_emulator-2.3.1/docs/api/server.md +0 -437
  41. lifx_emulator-2.3.1/docs/api/storage.md +0 -680
  42. lifx_emulator-2.3.1/docs/architecture/device-state.md +0 -3
  43. lifx_emulator-2.3.1/docs/architecture/index.md +0 -76
  44. lifx_emulator-2.3.1/docs/architecture/overview.md +0 -373
  45. lifx_emulator-2.3.1/docs/architecture/packet-flow.md +0 -3
  46. lifx_emulator-2.3.1/docs/architecture/protocol.md +0 -3
  47. lifx_emulator-2.3.1/docs/assets/favicon.png +0 -1
  48. lifx_emulator-2.3.1/docs/changelog.md +0 -91
  49. lifx_emulator-2.3.1/docs/faq.md +0 -574
  50. lifx_emulator-2.3.1/docs/getting-started/cli.md +0 -473
  51. lifx_emulator-2.3.1/docs/getting-started/index.md +0 -83
  52. lifx_emulator-2.3.1/docs/getting-started/installation.md +0 -165
  53. lifx_emulator-2.3.1/docs/getting-started/quickstart.md +0 -182
  54. lifx_emulator-2.3.1/docs/guide/best-practices.md +0 -696
  55. lifx_emulator-2.3.1/docs/guide/device-types.md +0 -366
  56. lifx_emulator-2.3.1/docs/guide/framebuffers.md +0 -209
  57. lifx_emulator-2.3.1/docs/guide/index.md +0 -90
  58. lifx_emulator-2.3.1/docs/guide/integration-testing.md +0 -788
  59. lifx_emulator-2.3.1/docs/guide/products-and-specs.md +0 -229
  60. lifx_emulator-2.3.1/docs/guide/testing-scenarios.md +0 -673
  61. lifx_emulator-2.3.1/docs/guide/web-interface.md +0 -490
  62. lifx_emulator-2.3.1/docs/index.md +0 -169
  63. lifx_emulator-2.3.1/docs/reference/glossary.md +0 -352
  64. lifx_emulator-2.3.1/docs/reference/troubleshooting.md +0 -845
  65. lifx_emulator-2.3.1/docs/stylesheets/extra.css +0 -37
  66. lifx_emulator-2.3.1/docs/tutorials/01-first-device.md +0 -261
  67. lifx_emulator-2.3.1/docs/tutorials/02-basic.md +0 -345
  68. lifx_emulator-2.3.1/docs/tutorials/03-integration.md +0 -642
  69. lifx_emulator-2.3.1/docs/tutorials/04-advanced-scenarios.md +0 -583
  70. lifx_emulator-2.3.1/docs/tutorials/05-cicd.md +0 -696
  71. lifx_emulator-2.3.1/docs/tutorials/index.md +0 -108
  72. lifx_emulator-2.3.1/mkdocs.yml +0 -266
  73. lifx_emulator-2.3.1/renovate.json +0 -161
  74. lifx_emulator-2.3.1/src/lifx_emulator/__init__.py +0 -31
  75. lifx_emulator-2.3.1/src/lifx_emulator/api/routers/__init__.py +0 -11
  76. lifx_emulator-2.3.1/src/lifx_emulator/api/services/__init__.py +0 -8
  77. lifx_emulator-2.3.1/src/lifx_emulator/constants.py +0 -33
  78. lifx_emulator-2.3.1/src/lifx_emulator/devices/__init__.py +0 -37
  79. lifx_emulator-2.3.1/src/lifx_emulator/devices/device.py +0 -339
  80. lifx_emulator-2.3.1/src/lifx_emulator/devices/manager.py +0 -256
  81. lifx_emulator-2.3.1/src/lifx_emulator/devices/observers.py +0 -139
  82. lifx_emulator-2.3.1/src/lifx_emulator/devices/persistence.py +0 -308
  83. lifx_emulator-2.3.1/src/lifx_emulator/devices/state_restorer.py +0 -259
  84. lifx_emulator-2.3.1/src/lifx_emulator/devices/state_serializer.py +0 -157
  85. lifx_emulator-2.3.1/src/lifx_emulator/devices/states.py +0 -377
  86. lifx_emulator-2.3.1/src/lifx_emulator/factories/__init__.py +0 -37
  87. lifx_emulator-2.3.1/src/lifx_emulator/factories/builder.py +0 -373
  88. lifx_emulator-2.3.1/src/lifx_emulator/factories/default_config.py +0 -158
  89. lifx_emulator-2.3.1/src/lifx_emulator/factories/factory.py +0 -221
  90. lifx_emulator-2.3.1/src/lifx_emulator/factories/firmware_config.py +0 -77
  91. lifx_emulator-2.3.1/src/lifx_emulator/factories/serial_generator.py +0 -82
  92. lifx_emulator-2.3.1/src/lifx_emulator/handlers/__init__.py +0 -39
  93. lifx_emulator-2.3.1/src/lifx_emulator/handlers/base.py +0 -49
  94. lifx_emulator-2.3.1/src/lifx_emulator/handlers/device_handlers.py +0 -322
  95. lifx_emulator-2.3.1/src/lifx_emulator/handlers/light_handlers.py +0 -503
  96. lifx_emulator-2.3.1/src/lifx_emulator/handlers/multizone_handlers.py +0 -249
  97. lifx_emulator-2.3.1/src/lifx_emulator/handlers/registry.py +0 -110
  98. lifx_emulator-2.3.1/src/lifx_emulator/handlers/tile_handlers.py +0 -488
  99. lifx_emulator-2.3.1/src/lifx_emulator/products/__init__.py +0 -28
  100. lifx_emulator-2.3.1/src/lifx_emulator/products/generator.py +0 -1037
  101. lifx_emulator-2.3.1/src/lifx_emulator/products/registry.py +0 -1496
  102. lifx_emulator-2.3.1/src/lifx_emulator/products/specs.py +0 -284
  103. lifx_emulator-2.3.1/src/lifx_emulator/products/specs.yml +0 -352
  104. lifx_emulator-2.3.1/src/lifx_emulator/protocol/__init__.py +0 -1
  105. lifx_emulator-2.3.1/src/lifx_emulator/protocol/base.py +0 -446
  106. lifx_emulator-2.3.1/src/lifx_emulator/protocol/const.py +0 -8
  107. lifx_emulator-2.3.1/src/lifx_emulator/protocol/generator.py +0 -1384
  108. lifx_emulator-2.3.1/src/lifx_emulator/protocol/header.py +0 -159
  109. lifx_emulator-2.3.1/src/lifx_emulator/protocol/packets.py +0 -1351
  110. lifx_emulator-2.3.1/src/lifx_emulator/protocol/protocol_types.py +0 -817
  111. lifx_emulator-2.3.1/src/lifx_emulator/protocol/serializer.py +0 -379
  112. lifx_emulator-2.3.1/src/lifx_emulator/repositories/__init__.py +0 -22
  113. lifx_emulator-2.3.1/src/lifx_emulator/repositories/device_repository.py +0 -155
  114. lifx_emulator-2.3.1/src/lifx_emulator/repositories/storage_backend.py +0 -107
  115. lifx_emulator-2.3.1/src/lifx_emulator/scenarios/__init__.py +0 -22
  116. lifx_emulator-2.3.1/src/lifx_emulator/scenarios/manager.py +0 -322
  117. lifx_emulator-2.3.1/src/lifx_emulator/scenarios/models.py +0 -112
  118. lifx_emulator-2.3.1/src/lifx_emulator/scenarios/persistence.py +0 -241
  119. lifx_emulator-2.3.1/src/lifx_emulator/server.py +0 -464
  120. lifx_emulator-2.3.1/tests/conftest.py +0 -239
  121. lifx_emulator-2.3.1/tests/test_async_storage.py +0 -246
  122. lifx_emulator-2.3.1/tests/test_backwards_compatibility.py +0 -943
  123. lifx_emulator-2.3.1/tests/test_device.py +0 -541
  124. lifx_emulator-2.3.1/tests/test_device_edge_cases.py +0 -231
  125. lifx_emulator-2.3.1/tests/test_device_handlers_extended.py +0 -723
  126. lifx_emulator-2.3.1/tests/test_device_manager.py +0 -288
  127. lifx_emulator-2.3.1/tests/test_handler_registry.py +0 -103
  128. lifx_emulator-2.3.1/tests/test_integration.py +0 -463
  129. lifx_emulator-2.3.1/tests/test_light_handlers_extended.py +0 -788
  130. lifx_emulator-2.3.1/tests/test_multizone_handlers_extended.py +0 -560
  131. lifx_emulator-2.3.1/tests/test_observers.py +0 -164
  132. lifx_emulator-2.3.1/tests/test_products_generator.py +0 -1121
  133. lifx_emulator-2.3.1/tests/test_products_specs.py +0 -366
  134. lifx_emulator-2.3.1/tests/test_protocol_generator.py +0 -815
  135. lifx_emulator-2.3.1/tests/test_protocol_types_coverage.py +0 -118
  136. lifx_emulator-2.3.1/tests/test_repositories.py +0 -131
  137. lifx_emulator-2.3.1/tests/test_scenario_manager.py +0 -431
  138. lifx_emulator-2.3.1/tests/test_scenario_persistence.py +0 -271
  139. lifx_emulator-2.3.1/tests/test_serializer.py +0 -460
  140. lifx_emulator-2.3.1/tests/test_server.py +0 -545
  141. lifx_emulator-2.3.1/tests/test_state_restorer.py +0 -270
  142. lifx_emulator-2.3.1/tests/test_tile_handlers_extended.py +0 -1265
  143. lifx_emulator-2.3.1/uv.lock +0 -1411
  144. {lifx_emulator-2.3.1 → lifx_emulator-3.0.1}/.gitignore +0 -0
  145. {lifx_emulator-2.3.1/src/lifx_emulator → lifx_emulator-3.0.1/src/lifx_emulator_app}/api/templates/dashboard.html +0 -0
@@ -0,0 +1,27 @@
1
+ # CHANGELOG
2
+
3
+ <!-- version list -->
4
+
5
+ ## v3.0.1 (2025-11-26)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Adjust uv build for new monorepo layout
10
+ ([`a0d5b7c`](https://github.com/Djelibeybi/lifx-emulator/commit/a0d5b7c1c1ab5659acc8554931f6c441654add05))
11
+
12
+
13
+ ## v3.0.0 (2025-11-26)
14
+
15
+ ### Refactoring
16
+
17
+ - Split into monorepo with separate library and CLI packages
18
+ ([`402fe6e`](https://github.com/Djelibeybi/lifx-emulator/commit/402fe6e6c42e4fb730d076cd4dd0bfe7743b2c57))
19
+
20
+ ### Breaking Changes
21
+
22
+ - The project is now split into two packages:
23
+
24
+
25
+ ## v2.4.0 (2025-11-26)
26
+
27
+ - Initial Release
@@ -0,0 +1,102 @@
1
+ Metadata-Version: 2.4
2
+ Name: lifx-emulator
3
+ Version: 3.0.1
4
+ Summary: Standalone LIFX Emulator with CLI and HTTP management API
5
+ Author-email: Avi Miller <me@dje.li>
6
+ Maintainer-email: Avi Miller <me@dje.li>
7
+ License-Expression: UPL-1.0
8
+ Classifier: Environment :: Console
9
+ Classifier: Framework :: AsyncIO
10
+ Classifier: Framework :: FastAPI
11
+ Classifier: Framework :: Pytest
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Natural Language :: English
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Testing
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: cyclopts>=4.2.0
23
+ Requires-Dist: fastapi>=0.115.0
24
+ Requires-Dist: lifx-emulator-core>=2.4.0
25
+ Requires-Dist: rich>=14.2.0
26
+ Requires-Dist: uvicorn>=0.34.0
27
+ Description-Content-Type: text/markdown
28
+
29
+ # lifx-emulator
30
+
31
+ Standalone LIFX device emulator with CLI and HTTP management API.
32
+
33
+ This package provides a ready-to-run emulator for testing LIFX LAN protocol libraries. It includes a command-line interface and an optional HTTP API for runtime device management.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install lifx-emulator
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```bash
44
+ # Start with default configuration (1 color light)
45
+ lifx-emulator
46
+
47
+ # Create multiple device types
48
+ lifx-emulator --color 2 --multizone 1 --tile 1
49
+
50
+ # Enable HTTP management API
51
+ lifx-emulator --api
52
+
53
+ # List available LIFX products
54
+ lifx-emulator list-products
55
+
56
+ # Create devices by product ID
57
+ lifx-emulator --product 27 --product 38 --product 55
58
+ ```
59
+
60
+ ## Features
61
+
62
+ - Command-line interface for quick emulator setup
63
+ - HTTP management API with web dashboard
64
+ - Real-time device monitoring and management
65
+ - Support for all LIFX device types (color, multizone, tile, infrared, HEV, switch)
66
+ - Persistent device state across restarts
67
+ - Testing scenarios for protocol edge cases
68
+
69
+ ## HTTP Management API
70
+
71
+ Enable with `--api` to get:
72
+
73
+ - **Web Dashboard**: `http://localhost:8080` - Real-time monitoring UI
74
+ - **REST API**: Device management, statistics, and scenario control
75
+ - **OpenAPI Docs**: `http://localhost:8080/docs` - Interactive API documentation
76
+
77
+ ```bash
78
+ # Start with API server
79
+ lifx-emulator --color 2 --api --api-port 9090
80
+
81
+ # Add a device via API
82
+ curl -X POST http://localhost:9090/api/devices \
83
+ -H "Content-Type: application/json" \
84
+ -d '{"product_id": 27}'
85
+ ```
86
+
87
+ ## Documentation
88
+
89
+ Full documentation is available at: **https://djelibeybi.github.io/lifx-emulator**
90
+
91
+ - [Installation Guide](https://djelibeybi.github.io/lifx-emulator/getting-started/installation/)
92
+ - [CLI Reference](https://djelibeybi.github.io/lifx-emulator/cli/cli-reference/)
93
+ - [Web Interface](https://djelibeybi.github.io/lifx-emulator/cli/web-interface/)
94
+ - [REST API](https://djelibeybi.github.io/lifx-emulator/cli/device-management-api/)
95
+
96
+ ## Related Packages
97
+
98
+ - **[lifx-emulator-core](https://pypi.org/project/lifx-emulator-core/)**: Core library for embedding the emulator in your own projects
99
+
100
+ ## License
101
+
102
+ [UPL-1.0](https://opensource.org/licenses/UPL)
@@ -0,0 +1,74 @@
1
+ # lifx-emulator
2
+
3
+ Standalone LIFX device emulator with CLI and HTTP management API.
4
+
5
+ This package provides a ready-to-run emulator for testing LIFX LAN protocol libraries. It includes a command-line interface and an optional HTTP API for runtime device management.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install lifx-emulator
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ # Start with default configuration (1 color light)
17
+ lifx-emulator
18
+
19
+ # Create multiple device types
20
+ lifx-emulator --color 2 --multizone 1 --tile 1
21
+
22
+ # Enable HTTP management API
23
+ lifx-emulator --api
24
+
25
+ # List available LIFX products
26
+ lifx-emulator list-products
27
+
28
+ # Create devices by product ID
29
+ lifx-emulator --product 27 --product 38 --product 55
30
+ ```
31
+
32
+ ## Features
33
+
34
+ - Command-line interface for quick emulator setup
35
+ - HTTP management API with web dashboard
36
+ - Real-time device monitoring and management
37
+ - Support for all LIFX device types (color, multizone, tile, infrared, HEV, switch)
38
+ - Persistent device state across restarts
39
+ - Testing scenarios for protocol edge cases
40
+
41
+ ## HTTP Management API
42
+
43
+ Enable with `--api` to get:
44
+
45
+ - **Web Dashboard**: `http://localhost:8080` - Real-time monitoring UI
46
+ - **REST API**: Device management, statistics, and scenario control
47
+ - **OpenAPI Docs**: `http://localhost:8080/docs` - Interactive API documentation
48
+
49
+ ```bash
50
+ # Start with API server
51
+ lifx-emulator --color 2 --api --api-port 9090
52
+
53
+ # Add a device via API
54
+ curl -X POST http://localhost:9090/api/devices \
55
+ -H "Content-Type: application/json" \
56
+ -d '{"product_id": 27}'
57
+ ```
58
+
59
+ ## Documentation
60
+
61
+ Full documentation is available at: **https://djelibeybi.github.io/lifx-emulator**
62
+
63
+ - [Installation Guide](https://djelibeybi.github.io/lifx-emulator/getting-started/installation/)
64
+ - [CLI Reference](https://djelibeybi.github.io/lifx-emulator/cli/cli-reference/)
65
+ - [Web Interface](https://djelibeybi.github.io/lifx-emulator/cli/web-interface/)
66
+ - [REST API](https://djelibeybi.github.io/lifx-emulator/cli/device-management-api/)
67
+
68
+ ## Related Packages
69
+
70
+ - **[lifx-emulator-core](https://pypi.org/project/lifx-emulator-core/)**: Core library for embedding the emulator in your own projects
71
+
72
+ ## License
73
+
74
+ [UPL-1.0](https://opensource.org/licenses/UPL)
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "lifx-emulator"
3
- version = "2.3.1"
4
- description = "LIFX Emulator for testing LIFX LAN protocol libraries"
3
+ version = "3.0.1"
4
+ description = "Standalone LIFX Emulator with CLI and HTTP management API"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
7
  dependencies = [
8
+ "lifx-emulator-core>=2.4.0",
8
9
  "cyclopts>=4.2.0",
9
10
  "fastapi>=0.115.0",
10
- "pyyaml>=6.0.3",
11
11
  "rich>=14.2.0",
12
12
  "uvicorn>=0.34.0",
13
13
  ]
@@ -20,7 +20,9 @@ maintainers = [
20
20
  {name = "Avi Miller", email = "me@dje.li"}
21
21
  ]
22
22
  classifiers = [
23
+ "Environment :: Console",
23
24
  "Framework :: AsyncIO",
25
+ "Framework :: FastAPI",
24
26
  "Framework :: Pytest",
25
27
  "Intended Audience :: Developers",
26
28
  "Natural Language :: English",
@@ -29,66 +31,19 @@ classifiers = [
29
31
  "Programming Language :: Python :: 3.12",
30
32
  "Programming Language :: Python :: 3.13",
31
33
  "Programming Language :: Python :: 3.14",
32
- "Topic :: Software Development :: Libraries",
33
- "Topic :: Software Development :: Libraries :: Python Modules",
34
+ "Topic :: Software Development :: Testing",
34
35
  "Typing :: Typed"
35
36
  ]
36
37
 
37
38
  [project.scripts]
38
- lifx-emulator = "lifx_emulator.__main__:main"
39
-
40
- [dependency-groups]
41
- dev = [
42
- "hatchling>=1.27.0",
43
- "httpx>=0.28.0",
44
- "pyright>=1.1.407",
45
- "pytest>=8.4.2",
46
- "pytest-asyncio>=0.24.0",
47
- "pytest-cov>=7.0.0",
48
- "pytest-sugar>=1.1.1",
49
- "ruff>=0.14.2",
50
- "mkdocs>=1.6.0",
51
- "mkdocs-material>=9.6.0",
52
- "mkdocstrings[python]>=0.27.0",
53
- "mkdocs-git-revision-date-localized-plugin>=1.4.0",
54
- "mkdocs-llmstxt>=0.3.0",
55
- ]
39
+ lifx-emulator = "lifx_emulator_app.__main__:main"
56
40
 
57
41
  [build-system]
58
42
  requires = ["hatchling"]
59
43
  build-backend = "hatchling.build"
60
44
 
61
45
  [tool.hatch.build.targets.wheel]
62
- packages = ["src/lifx_emulator"]
63
-
64
- [tool.ruff]
65
- line-length = 88
66
- indent-width = 4
67
- target-version = "py311"
68
-
69
- [tool.ruff.format]
70
- quote-style = "double"
71
- indent-style = "space"
72
- docstring-code-format = true
73
- docstring-code-line-length = "dynamic"
74
-
75
- [tool.ruff.lint]
76
- select = ["E", "F", "I", "N", "W", "UP"]
77
- ignore = []
78
-
79
- # Complexity and code quality limits
80
- [tool.ruff.lint.mccabe]
81
- max-complexity = 10
82
-
83
- [tool.ruff.lint.pylint]
84
- max-args = 5
85
- max-branches = 12
86
- max-statements = 50
87
-
88
- [tool.ruff.lint.per-file-ignores]
89
- "src/lifx_emulator/protocol/generator.py" = ["E501"]
90
- "src/lifx_emulator/protocol/packets.py" = ["E501"]
91
-
46
+ packages = ["src/lifx_emulator_app"]
92
47
 
93
48
  [tool.pyright]
94
49
  typeCheckingMode = "standard"
@@ -102,43 +57,28 @@ pythonpath = ["src"]
102
57
  python_files = ["test_*.py"]
103
58
  python_classes = ["Test*"]
104
59
  python_functions = ["test_*"]
105
- addopts = """\
106
- -v
107
- -Wdefault
108
- --cov=lifx_emulator
109
- --cov-branch
110
- --cov-report=xml
111
- --cov-report=term-missing:skip-covered
112
- --junitxml=junit.xml -o junit_family=legacy
113
- """
114
60
  asyncio_mode = "auto"
115
61
  asyncio_default_fixture_loop_scope = "function"
116
62
 
117
- [tool.coverage.run]
118
- omit = [
119
- "src/lifx_emulator/protocol/generator.py",
120
- "src/lifx_emulator/protocol/protocol_types.py",
121
- "src/lifx_emulator/products/generator.py",
122
- "src/lifx_emulator/products/registry.py",
123
- ]
124
-
125
- [tool.coverage.report]
126
- exclude_lines = [
127
- "pragma: no cover",
128
- "@overload",
129
- "if TYPE_CHECKING",
130
- "raise NotImplementedError",
131
- 'if __name__ == "__main__":',
132
- ]
133
-
134
63
  [tool.semantic_release]
64
+ commit_parser = "conventional-monorepo"
65
+ commit_message = """\
66
+ chore(release): lifx-emulator@{version}`
67
+
68
+ Automatically generated by python-semantic-release
69
+ """
70
+ tag_format = "app-v{version}"
135
71
  version_toml = ["pyproject.toml:project.version"]
136
72
  build_command = """
137
73
  uv lock --upgrade-package "$PACKAGE_NAME"
138
- git add uv.lock
139
- uv build
74
+ git add ../../uv.lock
75
+ uv build --package lifx-emulator --out-dir dist/
140
76
  """
141
77
 
78
+ [tool.semantic_release.commit_parser_options]
79
+ path_filters = ["."]
80
+ scope_prefix = "app-"
81
+
142
82
  [tool.semantic_release.branches.main]
143
83
  match = "main"
144
84
  prerelease = false
@@ -161,7 +101,7 @@ exclude_commit_patterns = [
161
101
  ]
162
102
 
163
103
  [tool.semantic_release.changelog.default_templates]
164
- changelog_file = "docs/changelog.md"
104
+ changelog_file = "CHANGELOG.md"
165
105
  output_format = "md"
166
106
 
167
107
  [tool.semantic_release.remote]
@@ -0,0 +1,10 @@
1
+ """LIFX Emulator Application
2
+
3
+ Standalone CLI and HTTP management API for the LIFX Emulator.
4
+ """
5
+
6
+ from importlib.metadata import version as get_version
7
+
8
+ __version__ = get_version("lifx-emulator")
9
+
10
+ __all__ = ["__version__"]
@@ -6,8 +6,6 @@ import signal
6
6
  from typing import Annotated
7
7
 
8
8
  import cyclopts
9
- from rich.logging import RichHandler
10
-
11
9
  from lifx_emulator.constants import LIFX_UDP_PORT
12
10
  from lifx_emulator.devices import (
13
11
  DEFAULT_STORAGE_DIR,
@@ -21,12 +19,14 @@ from lifx_emulator.factories import (
21
19
  create_hev_light,
22
20
  create_infrared_light,
23
21
  create_multizone_light,
22
+ create_switch,
24
23
  create_tile_device,
25
24
  )
26
25
  from lifx_emulator.products.registry import get_registry
27
26
  from lifx_emulator.repositories import DeviceRepository
28
27
  from lifx_emulator.scenarios import ScenarioPersistenceAsyncFile
29
28
  from lifx_emulator.server import EmulatedLifxServer
29
+ from rich.logging import RichHandler
30
30
 
31
31
  app = cyclopts.App(
32
32
  name="lifx-emulator",
@@ -239,6 +239,7 @@ async def run(
239
239
  hev: Annotated[int, cyclopts.Parameter(group=device_group)] = 0,
240
240
  multizone: Annotated[int, cyclopts.Parameter(group=device_group)] = 0,
241
241
  tile: Annotated[int, cyclopts.Parameter(group=device_group)] = 0,
242
+ switch: Annotated[int, cyclopts.Parameter(group=device_group)] = 0,
242
243
  # Multizone Options
243
244
  multizone_zones: Annotated[
244
245
  int | None, cyclopts.Parameter(group=multizone_group)
@@ -284,6 +285,7 @@ async def run(
284
285
  multizone_extended: Enable extended multizone support (Beam).
285
286
  Set --no-multizone-extended for basic multizone (Z) devices.
286
287
  tile: Number of tile/matrix chain devices.
288
+ switch: Number of LIFX Switch devices (relays, no lighting).
287
289
  tile_count: Number of tiles per device. Uses product defaults if not
288
290
  specified (5 for Tile, 1 for Candle/Ceiling).
289
291
  tile_width: Width of each tile in zones. Uses product defaults if not
@@ -310,7 +312,7 @@ async def run(
310
312
  lifx-emulator --color 2 --multizone 1 --tile 1 --api --verbose
311
313
 
312
314
  Create only specific device types:
313
- lifx-emulator --color 0 --infrared 3 --hev 2
315
+ lifx-emulator --color 0 --infrared 3 --hev 2 --switch 2
314
316
 
315
317
  Custom serial prefix:
316
318
  lifx-emulator --serial-prefix cafe00 --color 5
@@ -410,6 +412,7 @@ async def run(
410
412
  and infrared == 0
411
413
  and hev == 0
412
414
  and multizone == 0
415
+ and switch == 0
413
416
  ):
414
417
  color = 0
415
418
 
@@ -423,6 +426,7 @@ async def run(
423
426
  and hev == 0
424
427
  and multizone == 0
425
428
  and tile == 0
429
+ and switch == 0
426
430
  ):
427
431
  color = 0
428
432
 
@@ -467,13 +471,17 @@ async def run(
467
471
  )
468
472
  )
469
473
 
474
+ # Create switch devices
475
+ for _ in range(switch):
476
+ devices.append(create_switch(get_serial(), storage=storage))
477
+
470
478
  if not devices:
471
479
  if persistent:
472
480
  logger.warning("No devices configured. Server will run with no devices.")
473
481
  logger.info("Use API (--api) or restart with device flags to add devices.")
474
482
  else:
475
483
  logger.error(
476
- "No devices configured. Use --color, --multizone, --tile, "
484
+ "No devices configured. Use --color, --multizone, --tile, --switch, "
477
485
  "etc. to add devices."
478
486
  )
479
487
  return
@@ -520,7 +528,7 @@ async def run(
520
528
  # Start API server if enabled
521
529
  api_task = None
522
530
  if api:
523
- from lifx_emulator.api import run_api_server
531
+ from lifx_emulator_app.api import run_api_server
524
532
 
525
533
  logger.info("Starting HTTP API server on http://%s:%s", api_host, api_port)
526
534
  api_task = asyncio.create_task(run_api_server(server, api_host, api_port))
@@ -10,7 +10,7 @@ of concerns.
10
10
  """
11
11
 
12
12
  # Import from new refactored structure
13
- from lifx_emulator.api.app import create_api_app, run_api_server
13
+ from lifx_emulator_app.api.app import create_api_app, run_api_server
14
14
 
15
15
  # Note: HTML_UI remains in the old lifx_emulator/api.py file temporarily
16
16
  # TODO: Phase 1.1d - extract HTML template to separate file
@@ -19,9 +19,9 @@ from fastapi.templating import Jinja2Templates
19
19
  if TYPE_CHECKING:
20
20
  from lifx_emulator.server import EmulatedLifxServer
21
21
 
22
- from lifx_emulator.api.routers.devices import create_devices_router
23
- from lifx_emulator.api.routers.monitoring import create_monitoring_router
24
- from lifx_emulator.api.routers.scenarios import create_scenarios_router
22
+ from lifx_emulator_app.api.routers.devices import create_devices_router
23
+ from lifx_emulator_app.api.routers.monitoring import create_monitoring_router
24
+ from lifx_emulator_app.api.routers.scenarios import create_scenarios_router
25
25
 
26
26
  logger = logging.getLogger(__name__)
27
27
 
@@ -1,5 +1,5 @@
1
1
  """Mappers for converting domain models to API models."""
2
2
 
3
- from lifx_emulator.api.mappers.device_mapper import DeviceMapper
3
+ from lifx_emulator_app.api.mappers.device_mapper import DeviceMapper
4
4
 
5
5
  __all__ = ["DeviceMapper"]
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
7
7
  if TYPE_CHECKING:
8
8
  from lifx_emulator.devices import EmulatedLifxDevice
9
9
 
10
- from lifx_emulator.api.models import ColorHsbk, DeviceInfo
10
+ from lifx_emulator_app.api.models import ColorHsbk, DeviceInfo
11
11
 
12
12
 
13
13
  class DeviceMapper:
@@ -1,9 +1,8 @@
1
1
  """Pydantic models for API requests and responses."""
2
2
 
3
- from pydantic import BaseModel, Field, field_validator
4
-
5
3
  # Import shared domain models
6
4
  from lifx_emulator.scenarios import ScenarioConfig
5
+ from pydantic import BaseModel, Field, field_validator
7
6
 
8
7
 
9
8
  class DeviceCreateRequest(BaseModel):
@@ -0,0 +1,11 @@
1
+ """API routers for LIFX emulator endpoints."""
2
+
3
+ from lifx_emulator_app.api.routers.devices import create_devices_router
4
+ from lifx_emulator_app.api.routers.monitoring import create_monitoring_router
5
+ from lifx_emulator_app.api.routers.scenarios import create_scenarios_router
6
+
7
+ __all__ = [
8
+ "create_monitoring_router",
9
+ "create_devices_router",
10
+ "create_scenarios_router",
11
+ ]
@@ -9,8 +9,8 @@ from fastapi import APIRouter, HTTPException
9
9
  if TYPE_CHECKING:
10
10
  from lifx_emulator.server import EmulatedLifxServer
11
11
 
12
- from lifx_emulator.api.models import DeviceCreateRequest, DeviceInfo
13
- from lifx_emulator.api.services.device_service import (
12
+ from lifx_emulator_app.api.models import DeviceCreateRequest, DeviceInfo
13
+ from lifx_emulator_app.api.services.device_service import (
14
14
  DeviceAlreadyExistsError,
15
15
  DeviceCreationError,
16
16
  DeviceNotFoundError,
@@ -9,7 +9,7 @@ from fastapi import APIRouter
9
9
  if TYPE_CHECKING:
10
10
  from lifx_emulator.server import EmulatedLifxServer
11
11
 
12
- from lifx_emulator.api.models import ActivityEvent, ServerStats
12
+ from lifx_emulator_app.api.models import ActivityEvent, ServerStats
13
13
 
14
14
 
15
15
  def create_monitoring_router(server: EmulatedLifxServer) -> APIRouter:
@@ -9,7 +9,7 @@ from fastapi import APIRouter, HTTPException
9
9
  if TYPE_CHECKING:
10
10
  from lifx_emulator.server import EmulatedLifxServer
11
11
 
12
- from lifx_emulator.api.models import ScenarioConfig, ScenarioResponse
12
+ from lifx_emulator_app.api.models import ScenarioConfig, ScenarioResponse
13
13
 
14
14
 
15
15
  def _validate_device_serial(serial: str) -> bool:
@@ -0,0 +1,8 @@
1
+ """Business logic services for API endpoints."""
2
+
3
+ from lifx_emulator_app.api.services.device_service import DeviceService
4
+
5
+ # TODO: Create ScenarioService (Phase 1.1b completion)
6
+ # from lifx_emulator_app.api.services.scenario_service import ScenarioService
7
+
8
+ __all__ = ["DeviceService"]
@@ -13,10 +13,11 @@ from typing import TYPE_CHECKING
13
13
  if TYPE_CHECKING:
14
14
  from lifx_emulator.server import EmulatedLifxServer
15
15
 
16
- from lifx_emulator.api.mappers import DeviceMapper
17
- from lifx_emulator.api.models import DeviceCreateRequest, DeviceInfo
18
16
  from lifx_emulator.factories import create_device
19
17
 
18
+ from lifx_emulator_app.api.mappers import DeviceMapper
19
+ from lifx_emulator_app.api.models import DeviceCreateRequest, DeviceInfo
20
+
20
21
  logger = logging.getLogger(__name__)
21
22
 
22
23
 
@@ -0,0 +1,9 @@
1
+ """Pytest configuration for LIFX Emulator App tests."""
2
+
3
+ import pytest
4
+
5
+
6
+ @pytest.fixture
7
+ def anyio_backend():
8
+ """Use asyncio for async tests."""
9
+ return "asyncio"
@@ -2,12 +2,11 @@
2
2
 
3
3
  import pytest
4
4
  from fastapi.testclient import TestClient
5
-
6
- from lifx_emulator.api import create_api_app
7
5
  from lifx_emulator.devices.manager import DeviceManager
8
6
  from lifx_emulator.factories import create_color_light, create_multizone_light
9
7
  from lifx_emulator.repositories import DeviceRepository
10
8
  from lifx_emulator.server import EmulatedLifxServer
9
+ from lifx_emulator_app.api import create_api_app
11
10
 
12
11
 
13
12
  @pytest.fixture
@@ -725,7 +724,7 @@ class TestRunAPIServer:
725
724
  """Test that run_api_server creates uvicorn server with correct config."""
726
725
  from unittest.mock import AsyncMock, Mock
727
726
 
728
- from lifx_emulator.api.app import run_api_server
727
+ from lifx_emulator_app.api.app import run_api_server
729
728
 
730
729
  # Mock uvicorn components
731
730
  mock_server_instance = Mock()
@@ -768,7 +767,7 @@ class TestRunAPIServer:
768
767
  """Test that run_api_server uses default host and port."""
769
768
  from unittest.mock import AsyncMock, Mock
770
769
 
771
- from lifx_emulator.api.app import run_api_server
770
+ from lifx_emulator_app.api.app import run_api_server
772
771
 
773
772
  # Mock uvicorn components
774
773
  mock_server_instance = Mock()
@@ -1,10 +1,9 @@
1
1
  """Tests for API input validation using Pydantic models."""
2
2
 
3
3
  import pytest
4
+ from lifx_emulator_app.api.models import ColorHsbk, DeviceCreateRequest
4
5
  from pydantic import ValidationError
5
6
 
6
- from lifx_emulator.api.models import ColorHsbk, DeviceCreateRequest
7
-
8
7
 
9
8
  class TestDeviceCreateRequestValidation:
10
9
  """Test DeviceCreateRequest validation."""