lifx-emulator 2.3.0__tar.gz → 2.3.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 (138) hide show
  1. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/CLAUDE.md +5 -5
  2. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/PKG-INFO +1 -1
  3. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/advanced/device-management-api.md +2 -2
  4. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/advanced/scenario-api.md +2 -2
  5. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/api/device.md +2 -2
  6. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/api/products.md +2 -2
  7. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/api/protocol.md +2 -2
  8. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/architecture/overview.md +1 -1
  9. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/changelog.md +8 -0
  10. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/getting-started/cli.md +4 -4
  11. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/guide/device-types.md +1 -1
  12. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/guide/products-and-specs.md +10 -10
  13. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/guide/web-interface.md +3 -3
  14. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/index.md +1 -1
  15. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/tutorials/04-advanced-scenarios.md +1 -1
  16. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/pyproject.toml +3 -8
  17. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/__main__.py +2 -2
  18. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/models.py +2 -2
  19. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/templates/dashboard.html +8 -8
  20. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/devices/device.py +2 -2
  21. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/devices/states.py +2 -2
  22. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/factories/builder.py +2 -2
  23. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/factories/factory.py +4 -4
  24. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/handlers/light_handlers.py +155 -20
  25. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/handlers/tile_handlers.py +22 -24
  26. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/products/generator.py +2 -2
  27. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/products/specs.py +2 -2
  28. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/products/specs.yml +8 -8
  29. lifx_emulator-2.3.1/tests/test_backwards_compatibility.py +943 -0
  30. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_device.py +1 -1
  31. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_integration.py +2 -2
  32. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_tile_handlers_extended.py +2 -2
  33. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/uv.lock +1 -1
  34. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/.github/workflows/ci.yml +0 -0
  35. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/.github/workflows/docs.yml +0 -0
  36. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/.gitignore +0 -0
  37. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/.pre-commit-config.yaml +0 -0
  38. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/LICENSE +0 -0
  39. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/README.md +0 -0
  40. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/advanced/index.md +0 -0
  41. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/advanced/scenarios.md +0 -0
  42. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/advanced/storage.md +0 -0
  43. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/api/factories.md +0 -0
  44. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/api/index.md +0 -0
  45. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/api/server.md +0 -0
  46. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/api/storage.md +0 -0
  47. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/architecture/device-state.md +0 -0
  48. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/architecture/index.md +0 -0
  49. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/architecture/packet-flow.md +0 -0
  50. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/architecture/protocol.md +0 -0
  51. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/assets/favicon.png +0 -0
  52. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/faq.md +0 -0
  53. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/getting-started/index.md +0 -0
  54. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/getting-started/installation.md +0 -0
  55. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/getting-started/quickstart.md +0 -0
  56. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/guide/best-practices.md +0 -0
  57. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/guide/framebuffers.md +0 -0
  58. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/guide/index.md +0 -0
  59. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/guide/integration-testing.md +0 -0
  60. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/guide/testing-scenarios.md +0 -0
  61. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/reference/glossary.md +0 -0
  62. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/reference/troubleshooting.md +0 -0
  63. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/stylesheets/extra.css +0 -0
  64. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/tutorials/01-first-device.md +0 -0
  65. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/tutorials/02-basic.md +0 -0
  66. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/tutorials/03-integration.md +0 -0
  67. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/tutorials/05-cicd.md +0 -0
  68. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/docs/tutorials/index.md +0 -0
  69. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/mkdocs.yml +0 -0
  70. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/renovate.json +0 -0
  71. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/__init__.py +0 -0
  72. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/__init__.py +0 -0
  73. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/app.py +0 -0
  74. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/mappers/__init__.py +0 -0
  75. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/mappers/device_mapper.py +0 -0
  76. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/routers/__init__.py +0 -0
  77. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/routers/devices.py +0 -0
  78. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/routers/monitoring.py +0 -0
  79. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/routers/scenarios.py +0 -0
  80. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/services/__init__.py +0 -0
  81. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/api/services/device_service.py +0 -0
  82. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/constants.py +0 -0
  83. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/devices/__init__.py +0 -0
  84. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/devices/manager.py +0 -0
  85. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/devices/observers.py +0 -0
  86. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/devices/persistence.py +0 -0
  87. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/devices/state_restorer.py +0 -0
  88. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/devices/state_serializer.py +0 -0
  89. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/factories/__init__.py +0 -0
  90. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/factories/default_config.py +0 -0
  91. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/factories/firmware_config.py +0 -0
  92. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/factories/serial_generator.py +0 -0
  93. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/handlers/__init__.py +0 -0
  94. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/handlers/base.py +0 -0
  95. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/handlers/device_handlers.py +0 -0
  96. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/handlers/multizone_handlers.py +0 -0
  97. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/handlers/registry.py +0 -0
  98. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/products/__init__.py +0 -0
  99. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/products/registry.py +0 -0
  100. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/protocol/__init__.py +0 -0
  101. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/protocol/base.py +0 -0
  102. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/protocol/const.py +0 -0
  103. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/protocol/generator.py +0 -0
  104. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/protocol/header.py +0 -0
  105. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/protocol/packets.py +0 -0
  106. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/protocol/protocol_types.py +0 -0
  107. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/protocol/serializer.py +0 -0
  108. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/repositories/__init__.py +0 -0
  109. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/repositories/device_repository.py +0 -0
  110. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/repositories/storage_backend.py +0 -0
  111. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/scenarios/__init__.py +0 -0
  112. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/scenarios/manager.py +0 -0
  113. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/scenarios/models.py +0 -0
  114. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/scenarios/persistence.py +0 -0
  115. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/src/lifx_emulator/server.py +0 -0
  116. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/conftest.py +0 -0
  117. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_api.py +0 -0
  118. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_api_validation.py +0 -0
  119. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_async_storage.py +0 -0
  120. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_cli.py +0 -0
  121. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_cli_validation.py +0 -0
  122. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_device_edge_cases.py +0 -0
  123. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_device_handlers_extended.py +0 -0
  124. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_device_manager.py +0 -0
  125. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_handler_registry.py +0 -0
  126. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_light_handlers_extended.py +0 -0
  127. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_multizone_handlers_extended.py +0 -0
  128. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_observers.py +0 -0
  129. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_products_generator.py +0 -0
  130. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_products_specs.py +0 -0
  131. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_protocol_generator.py +0 -0
  132. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_protocol_types_coverage.py +0 -0
  133. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_repositories.py +0 -0
  134. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_scenario_manager.py +0 -0
  135. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_scenario_persistence.py +0 -0
  136. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_serializer.py +0 -0
  137. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_server.py +0 -0
  138. {lifx_emulator-2.3.0 → lifx_emulator-2.3.1}/tests/test_state_restorer.py +0 -0
@@ -128,8 +128,8 @@ lifx-emulator --help
128
128
  - `--multizone-extended`: Enable extended multizone support (default: True, use --no-multizone-extended to disable)
129
129
  - `--tile`: Number of tile devices
130
130
  - `--tile-count`: Tiles per device (uses product default if not specified)
131
- - `--tile-width`: Width of each tile in pixels (uses product default if not specified)
132
- - `--tile-height`: Height of each tile in pixels (uses product default if not specified)
131
+ - `--tile-width`: Width of each tile in zones (uses product default if not specified)
132
+ - `--tile-height`: Height of each tile in zones (uses product default if not specified)
133
133
  - `--serial-prefix`: serial prefix (6 hex chars, default: d073d5)
134
134
  - `--serial-start`: Starting serial suffix (default: 1)
135
135
  - `--api`: Enable HTTP API server for monitoring and management (default: False)
@@ -140,9 +140,9 @@ lifx-emulator --help
140
140
  **Product Defaults:**
141
141
  Device parameters like `--multizone-zones` and `--tile-count` automatically use product-specific defaults from the specs system when not specified:
142
142
  - LIFX Beam: Extended multizone support enabled and 80 zones by default
143
- - LIFX Tile: 5 tiles of 8x8 pixels by default
144
- - LIFX Candle: 1 tile of 5x6 pixels by default
145
- - LIFX Ceiling: 1 tile of 8x8 pixels by default
143
+ - LIFX Tile: 5 tiles of 8x8 zones by default
144
+ - LIFX Candle: 1 tile of 5x6 zones by default
145
+ - LIFX Ceiling: 1 tile of 8x8 zones by default
146
146
  - These defaults can be overridden with command-line parameters
147
147
 
148
148
  **Firmware Version:**
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lifx-emulator
3
- Version: 2.3.0
3
+ Version: 2.3.1
4
4
  Summary: LIFX Emulator for testing LIFX LAN protocol libraries
5
5
  Author-email: Avi Miller <me@dje.li>
6
6
  Maintainer-email: Avi Miller <me@dje.li>
@@ -266,8 +266,8 @@ Creates a new emulated device by product ID. The device will be added to the emu
266
266
  - `serial` (optional): Device serial (auto-generated if not provided)
267
267
  - `zone_count` (optional): Number of zones for multizone devices
268
268
  - `tile_count` (optional): Number of tiles for matrix devices
269
- - `tile_width` (optional): Width of each tile in pixels
270
- - `tile_height` (optional): Height of each tile in pixels
269
+ - `tile_width` (optional): Width of each tile in zones
270
+ - `tile_height` (optional): Height of each tile in zones
271
271
  - `firmware_major` (optional): Firmware major version
272
272
  - `firmware_minor` (optional): Firmware minor version
273
273
 
@@ -788,8 +788,8 @@ jobs:
788
788
  | 506 | StateMultiZone | Response with zone colors |
789
789
  | 512 | ExtendedStateMultiZone | Response with extended zones |
790
790
  | 701 | GetDeviceChain | Get tile chain info |
791
- | 707 | Get64 | Get tile pixel data |
792
- | 715 | Set64 | Set tile pixel data |
791
+ | 707 | Get64 | Get tile zone data |
792
+ | 715 | Set64 | Set tile zone data |
793
793
 
794
794
  ## Tips and Best Practices
795
795
 
@@ -90,8 +90,8 @@ Dataclass holding all stateful information for an emulated LIFX device.
90
90
 
91
91
  - **`tile_count`** (`int` = `0`) - Number of tiles in chain
92
92
  - **`tile_devices`** (`list[dict]` = `[]`) - Per-tile state (position, colors)
93
- - **`tile_width`** (`int` = `8`) - Width of each tile in pixels
94
- - **`tile_height`** (`int` = `8`) - Height of each tile in pixels
93
+ - **`tile_width`** (`int` = `8`) - Width of each tile in zones
94
+ - **`tile_height`** (`int` = `8`) - Height of each tile in zones
95
95
 
96
96
  #### Effects (Waveforms & Animations)
97
97
 
@@ -239,8 +239,8 @@ Get detailed specifications for a product.
239
239
  - `zone_count`: Number of zones (multizone devices)
240
240
  - `extended_multizone`: Extended multizone support flag
241
241
  - `tile_count`: Default number of tiles (matrix devices)
242
- - `tile_width`: Tile width in pixels (matrix devices)
243
- - `tile_height`: Tile height in pixels (matrix devices)
242
+ - `tile_width`: Tile width in zones (matrix devices)
243
+ - `tile_height`: Tile height in zones (matrix devices)
244
244
 
245
245
  **Example:**
246
246
  ```python
@@ -322,8 +322,8 @@ class TileStateDevice:
322
322
  accel_meas_z: int
323
323
  user_x: float # User-configured X position
324
324
  user_y: float # User-configured Y position
325
- width: int # Tile width in pixels (e.g., 8)
326
- height: int # Tile height in pixels (e.g., 8)
325
+ width: int # Tile width in zones (e.g., 8)
326
+ height: int # Tile height in zones (e.g., 8)
327
327
  device_version_vendor: int
328
328
  device_version_product: int
329
329
  device_version_version: int
@@ -253,7 +253,7 @@ Devices advertise capabilities through boolean flags:
253
253
  | `has_infrared` | IR brightness | LIFX A19 Night Vision |
254
254
  | `has_multizone` | Linear zones | LIFX Z, LIFX Beam |
255
255
  | `has_extended_multizone` | >16 zones | LIFX Beam |
256
- | `has_matrix` | 2D pixel grid | LIFX Tile, LIFX Candle |
256
+ | `has_matrix` | 2D zone grid | LIFX Tile, LIFX Candle |
257
257
  | `has_hev` | HEV cleaning | LIFX Clean |
258
258
 
259
259
  ## Packet Types
@@ -2,6 +2,14 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v2.3.1 (2025-11-18)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **tile**: Implement backwards compatibility on tile and multizone devices
10
+ ([`be473f7`](https://github.com/Djelibeybi/lifx-emulator/commit/be473f74f9a49be7f07082d5bfba16f5d74f46f6))
11
+
12
+
5
13
  ## v2.3.0 (2025-11-18)
6
14
 
7
15
  ### Features
@@ -197,16 +197,16 @@ Number of tiles per tile device. If not specified, uses product default (5 for L
197
197
  - **Default:** `None` (uses product defaults)
198
198
  - **Example:** `--tile-count 10`
199
199
 
200
- ### `--tile-width <PIXELS>`
200
+ ### `--tile-width <zones>`
201
201
 
202
- Width of each tile in pixels. If not specified, uses product default (typically 8).
202
+ Width of each tile in zones. If not specified, uses product default (typically 8).
203
203
 
204
204
  - **Default:** `None` (uses product defaults)
205
205
  - **Example:** `--tile-width 16`
206
206
 
207
- ### `--tile-height <PIXELS>`
207
+ ### `--tile-height <zones>`
208
208
 
209
- Height of each tile in pixels. If not specified, uses product default (typically 8).
209
+ Height of each tile in zones. If not specified, uses product default (typically 8).
210
210
 
211
211
  - **Default:** `None` (uses product defaults)
212
212
  - **Example:** `--tile-height 8`
@@ -297,7 +297,7 @@ print(f"Tile height: {device.state.tile_height}") # 8
297
297
 
298
298
  # Access tile devices
299
299
  for i, tile in enumerate(device.state.tile_devices):
300
- print(f"Tile {i}: {tile.width}x{tile.height} pixels")
300
+ print(f"Tile {i}: {tile.width}x{tile.height} zones")
301
301
  ```
302
302
 
303
303
  ### Matrix Packet Types
@@ -31,7 +31,7 @@ Contains product-specific details not available in the upstream catalog:
31
31
  - Min/max zone counts
32
32
  - Default tile counts for matrix devices
33
33
  - Min/max tile counts
34
- - Tile dimensions (width x height in pixels)
34
+ - Tile dimensions (width x height in zones)
35
35
  - Product-specific notes
36
36
 
37
37
  ### `specs.py`
@@ -81,8 +81,8 @@ products:
81
81
  default_tile_count: <number> # Typical number of tiles in chain
82
82
  min_tile_count: <number> # Minimum tiles supported
83
83
  max_tile_count: <number> # Maximum tiles supported
84
- tile_width: <pixels> # Width of each tile
85
- tile_height: <pixels> # Height of each tile
84
+ tile_width: <zones> # Width of each tile
85
+ tile_height: <zones> # Height of each tile
86
86
  notes: "<description>"
87
87
  ```
88
88
 
@@ -95,7 +95,7 @@ products:
95
95
  max_tile_count: 5
96
96
  tile_width: 8
97
97
  tile_height: 8
98
- notes: "LIFX Tile, 8x8 pixel matrix, chainable up to 5"
98
+ notes: "LIFX Tile, 8x8 zone matrix, chainable up to 5"
99
99
  ```
100
100
 
101
101
  **Example - LIFX Candle:**
@@ -107,7 +107,7 @@ products:
107
107
  max_tile_count: 1
108
108
  tile_width: 5
109
109
  tile_height: 6
110
- notes: "LIFX Candle, 5x6 pixel matrix, single unit"
110
+ notes: "LIFX Candle, 5x6 zone matrix, single unit"
111
111
  ```
112
112
 
113
113
  **Example - LIFX Ceiling:**
@@ -119,7 +119,7 @@ products:
119
119
  max_tile_count: 1
120
120
  tile_width: 22
121
121
  tile_height: 22
122
- notes: "LIFX Ceiling, 22x22 pixel matrix"
122
+ notes: "LIFX Ceiling, 22x22 zone matrix"
123
123
  ```
124
124
 
125
125
  ## How Specifications Are Used
@@ -149,16 +149,16 @@ When creating a matrix device:
149
149
  2. **Tile count**: From `specs.yml` if not specified by user
150
150
 
151
151
  ```python
152
- # Uses specification: 5 tiles of 8x8 pixels
152
+ # Uses specification: 5 tiles of 8x8 zones
153
153
  device = create_device(55)
154
154
 
155
155
  # Custom tile count, specification dimensions
156
- device = create_device(55, tile_count=3) # 3 tiles of 8x8 pixels
156
+ device = create_device(55, tile_count=3) # 3 tiles of 8x8 zones
157
157
 
158
- # Candle: 1 tile of 5x5 pixels (from specification)
158
+ # Candle: 1 tile of 5x5 zones (from specification)
159
159
  device = create_device(57)
160
160
 
161
- # Ceiling: 1 tile of 22x22 pixels (from specification)
161
+ # Ceiling: 1 tile of 22x22 zones (from specification)
162
162
  device = create_device(176)
163
163
  ```
164
164
 
@@ -142,7 +142,7 @@ For matrix/tile devices:
142
142
  ```
143
143
  ▸ Show tiles (5) (click to expand)
144
144
  ┌──────────┐
145
- │ T1 │ (8×8 pixel grid)
145
+ │ T1 │ (8×8 zone grid)
146
146
  │ ████████ │
147
147
  │ ████████ │
148
148
  │ ████████ │
@@ -249,8 +249,8 @@ For matrix devices (tiles, candles, ceiling):
249
249
 
250
250
  1. Locate device in Devices section
251
251
  2. Click "▸ Show tiles" to expand
252
- 3. Grid display shows pixel colors
253
- 4. Each small square is one pixel
252
+ 3. Grid display shows zone colors
253
+ 4. Each small square is one zone
254
254
  5. Tiles labeled T1, T2, etc.
255
255
  6. Click again to collapse
256
256
 
@@ -71,7 +71,7 @@ LIFX Emulator is a Python library and CLI tool that creates virtual LIFX devices
71
71
  | Infrared | LIFX A19 Night Vision | IR brightness control |
72
72
  | HEV | LIFX Clean | HEV cleaning cycle |
73
73
  | Multizone | LIFX Z, LIFX Beam | Linear zones (up to 82) |
74
- | Matrix | LIFX Tile, LIFX Candle | 2D pixel arrays |
74
+ | Matrix | LIFX Tile, LIFX Candle | 2D zone arrays |
75
75
 
76
76
  ## Use Cases
77
77
 
@@ -84,7 +84,7 @@ async def main():
84
84
  # Create a LIFX Tile with 5 tiles in the chain
85
85
  device = create_tile_device("d073d9000001", tile_count=5)
86
86
 
87
- # Each tile is 8x8 pixels (64 zones)
87
+ # Each tile is 8x8 zones (64 zones)
88
88
  print(f"Tile device configuration:")
89
89
  print(f" Tiles: {len(device.state.tile_devices)}")
90
90
  for i, tile in enumerate(device.state.tile_devices):
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "lifx-emulator"
3
- version = "2.3.0"
3
+ version = "2.3.1"
4
4
  description = "LIFX Emulator for testing LIFX LAN protocol libraries"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -73,7 +73,7 @@ docstring-code-format = true
73
73
  docstring-code-line-length = "dynamic"
74
74
 
75
75
  [tool.ruff.lint]
76
- select = ["E", "F", "I", "N", "W", "UP", "C90"] # C90 = mccabe complexity
76
+ select = ["E", "F", "I", "N", "W", "UP"]
77
77
  ignore = []
78
78
 
79
79
  # Complexity and code quality limits
@@ -86,13 +86,8 @@ max-branches = 12
86
86
  max-statements = 50
87
87
 
88
88
  [tool.ruff.lint.per-file-ignores]
89
- "src/lifx_emulator/__main__.py" = ["C901"]
90
- "src/lifx_emulator/devices/state_restorer.py" = ["C901"]
91
- "src/lifx_emulator/handlers/tile_handlers.py" = ["C901"]
92
- "src/lifx_emulator/protocol/generator.py" = ["E501", "C901"]
89
+ "src/lifx_emulator/protocol/generator.py" = ["E501"]
93
90
  "src/lifx_emulator/protocol/packets.py" = ["E501"]
94
- "src/lifx_emulator/products/registry.py" = ["C901"]
95
- "src/lifx_emulator/scenarios/persistence.py" = ["C901"]
96
91
 
97
92
 
98
93
  [tool.pyright]
@@ -286,9 +286,9 @@ async def run(
286
286
  tile: Number of tile/matrix chain devices.
287
287
  tile_count: Number of tiles per device. Uses product defaults if not
288
288
  specified (5 for Tile, 1 for Candle/Ceiling).
289
- tile_width: Width of each tile in pixels. Uses product defaults if not
289
+ tile_width: Width of each tile in zones. Uses product defaults if not
290
290
  specified (8 for most devices).
291
- tile_height: Height of each tile in pixels. Uses product defaults if
291
+ tile_height: Height of each tile in zones. Uses product defaults if
292
292
  not specified (8 for most devices).
293
293
  serial_prefix: Serial number prefix as 6 hex characters.
294
294
  serial_start: Starting serial suffix for auto-incrementing device serials.
@@ -25,10 +25,10 @@ class DeviceCreateRequest(BaseModel):
25
25
  None, description="Number of tiles for matrix devices", ge=0, le=100
26
26
  )
27
27
  tile_width: int | None = Field(
28
- None, description="Width of each tile in pixels", ge=1, le=256
28
+ None, description="Width of each tile in zones", ge=1, le=256
29
29
  )
30
30
  tile_height: int | None = Field(
31
- None, description="Height of each tile in pixels", ge=1, le=256
31
+ None, description="Height of each tile in zones", ge=1, le=256
32
32
  )
33
33
  firmware_major: int | None = Field(
34
34
  None, description="Firmware major version", ge=0, le=255
@@ -163,7 +163,7 @@
163
163
  gap: 2px;
164
164
  margin-top: 4px;
165
165
  }
166
- .tile-pixel {
166
+ .tile-zone {
167
167
  width: 8px;
168
168
  height: 8px;
169
169
  border-radius: 1px;
@@ -644,7 +644,7 @@
644
644
  `;
645
645
  } else if (dev.has_matrix && dev.tile_devices &&
646
646
  dev.tile_devices.length > 0) {
647
- // Render actual tile pixels
647
+ // Render actual tile zones
648
648
  const tilesHtml = dev.tile_devices.map((tile, tileIndex) => {
649
649
  if (!tile.colors || tile.colors.length === 0) {
650
650
  return '<div style="color: #666;">No color data</div>';
@@ -652,14 +652,14 @@
652
652
 
653
653
  const width = tile.width || 8;
654
654
  const height = tile.height || 8;
655
- const totalPixels = width * height;
655
+ const totalzones = width * height;
656
656
 
657
- // Create grid of pixels
658
- const slicedColors = tile.colors.slice(0, totalPixels);
659
- const pixelsHtml = slicedColors.map(color => {
657
+ // Create grid of zones
658
+ const slicedColors = tile.colors.slice(0, totalzones);
659
+ const zonesHtml = slicedColors.map(color => {
660
660
  const rgb = hsbkToRgb(color);
661
661
  const bgStyle = `background: ${rgb};`;
662
- return `<div class="tile-pixel" style="${bgStyle}"></div>`;
662
+ return `<div class="tile-zone" style="${bgStyle}"></div>`;
663
663
  }).join('');
664
664
 
665
665
  const labelStyle = (
@@ -675,7 +675,7 @@
675
675
  T${tileIndex + 1}
676
676
  </div>
677
677
  <div class="tile-grid" style="${gridStyle}">
678
- ${pixelsHtml}
678
+ ${zonesHtml}
679
679
  </div>
680
680
  </div>
681
681
  `;
@@ -90,10 +90,10 @@ class EmulatedLifxDevice:
90
90
  if self.state.has_matrix and self.state.tile_count > 0:
91
91
  if not self.state.tile_devices:
92
92
  for i in range(self.state.tile_count):
93
- pixels = self.state.tile_width * self.state.tile_height
93
+ zones = self.state.tile_width * self.state.tile_height
94
94
  tile_colors = [
95
95
  LightHsbk(hue=0, saturation=0, brightness=32768, kelvin=3500)
96
- for _ in range(pixels)
96
+ for _ in range(zones)
97
97
  ]
98
98
 
99
99
  self.state.tile_devices.append(
@@ -100,10 +100,10 @@ class TileFramebuffers:
100
100
  """Get framebuffer by index, creating it if needed."""
101
101
  if fb_index not in self.framebuffers:
102
102
  # Initialize with default black color
103
- pixels = width * height
103
+ zones = width * height
104
104
  self.framebuffers[fb_index] = [
105
105
  LightHsbk(hue=0, saturation=0, brightness=0, kelvin=3500)
106
- for _ in range(pixels)
106
+ for _ in range(zones)
107
107
  ]
108
108
  return self.framebuffers[fb_index]
109
109
 
@@ -136,8 +136,8 @@ class DeviceBuilder:
136
136
  """Set tile dimensions for matrix devices.
137
137
 
138
138
  Args:
139
- width: Tile width in pixels
140
- height: Tile height in pixels
139
+ width: Tile width in zones
140
+ height: Tile height in zones
141
141
 
142
142
  Returns:
143
143
  Self for method chaining
@@ -104,8 +104,8 @@ def create_tile_device(
104
104
  Args:
105
105
  serial: Optional serial
106
106
  tile_count: Optional tile count (uses product default)
107
- tile_width: Optional tile width in pixels (uses product default)
108
- tile_height: Optional tile height in pixels (uses product default)
107
+ tile_width: Optional tile width in zones (uses product default)
108
+ tile_height: Optional tile height in zones (uses product default)
109
109
  firmware_version: Optional firmware version tuple (major, minor)
110
110
  storage: Optional storage for persistence
111
111
  scenario_manager: Optional scenario manager
@@ -164,8 +164,8 @@ def create_device(
164
164
  zone_count: Number of zones for multizone devices (auto-determined)
165
165
  extended_multizone: Enable extended multizone requests
166
166
  tile_count: Number of tiles for matrix devices (default: 5)
167
- tile_width: Width of each tile in pixels (default: 8)
168
- tile_height: Height of each tile in pixels (default: 8)
167
+ tile_width: Width of each tile in zones (default: 8)
168
+ tile_height: Height of each tile in zones (default: 8)
169
169
  firmware_version: Optional firmware version tuple (major, minor).
170
170
  If not specified, uses 3.70 for extended_multizone
171
171
  or 2.60 otherwise