elke27 0.1.2__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 (271) hide show
  1. elke27-0.1.2/.copier-answers.yml +9 -0
  2. elke27-0.1.2/.github/workflows/ci.yml +66 -0
  3. elke27-0.1.2/.github/workflows/publish.yml +47 -0
  4. elke27-0.1.2/.gitignore +188 -0
  5. elke27-0.1.2/.lock +0 -0
  6. elke27-0.1.2/CACHEDIR.TAG +1 -0
  7. elke27-0.1.2/LICENSE +21 -0
  8. elke27-0.1.2/Makefile +32 -0
  9. elke27-0.1.2/PKG-INFO +285 -0
  10. elke27-0.1.2/README.md +262 -0
  11. elke27-0.1.2/devtools/lint.py +53 -0
  12. elke27-0.1.2/docs/CHANGES.md +65 -0
  13. elke27-0.1.2/docs/CLIENT_CONTRACT.md +114 -0
  14. elke27-0.1.2/docs/Data-Update-Coordinator-Refactor.md +109 -0
  15. elke27-0.1.2/docs/Entity-Mapping-Checklist +61 -0
  16. elke27-0.1.2/docs/HA_LIBRARY_CONTRACT.md +247 -0
  17. elke27-0.1.2/docs/PERMISSIONS.md +136 -0
  18. elke27-0.1.2/docs/PUBLIC_API.md +84 -0
  19. elke27-0.1.2/docs/adr/ADR-0001.md +49 -0
  20. elke27-0.1.2/docs/adr/ADR-0002.md +47 -0
  21. elke27-0.1.2/docs/adr/ADR-0003.md +44 -0
  22. elke27-0.1.2/docs/adr/ADR-0004.md +35 -0
  23. elke27-0.1.2/docs/adr/ADR-0005.md +37 -0
  24. elke27-0.1.2/docs/adr/ADR-0006.md +39 -0
  25. elke27-0.1.2/docs/adr/ADR-0007.md +45 -0
  26. elke27-0.1.2/docs/adr/ADR-0008.md +36 -0
  27. elke27-0.1.2/docs/adr/ADR-0009.md +38 -0
  28. elke27-0.1.2/docs/adr/ADR-0010.md +41 -0
  29. elke27-0.1.2/docs/adr/ADR-0011.md +66 -0
  30. elke27-0.1.2/docs/adr/ADR-0012.md +53 -0
  31. elke27-0.1.2/docs/adr/ADR-0013.md +227 -0
  32. elke27-0.1.2/docs/adr/ADR-0013.md.old +80 -0
  33. elke27-0.1.2/docs/adr/ADR-0013.md.old2 +180 -0
  34. elke27-0.1.2/docs/adr/ADR-0100.md +59 -0
  35. elke27-0.1.2/docs/adr/ADR-0101.md +57 -0
  36. elke27-0.1.2/docs/adr/ADR-0102.md +64 -0
  37. elke27-0.1.2/docs/adr/ADR-0103.md +75 -0
  38. elke27-0.1.2/docs/adr/ADR-0104.md +82 -0
  39. elke27-0.1.2/docs/adr/ADR-0105.md +114 -0
  40. elke27-0.1.2/docs/adr/ADR-0106.md +81 -0
  41. elke27-0.1.2/docs/adr/ADR-0107.md +376 -0
  42. elke27-0.1.2/docs/adr/ADR-0108.md +72 -0
  43. elke27-0.1.2/docs/adr/ADR-0109.md +75 -0
  44. elke27-0.1.2/docs/adr/ADR-0110.md +96 -0
  45. elke27-0.1.2/docs/adr/ADR-0111.md +147 -0
  46. elke27-0.1.2/docs/adr/ADR-0112.md +125 -0
  47. elke27-0.1.2/docs/adr/ADR-0113.md +111 -0
  48. elke27-0.1.2/docs/adr/ADR-0114.md +133 -0
  49. elke27-0.1.2/docs/adr/ADR-0115.md +76 -0
  50. elke27-0.1.2/docs/adr/ADR-0116.md +70 -0
  51. elke27-0.1.2/docs/adr/ADR-0117.md +65 -0
  52. elke27-0.1.2/docs/adr/ADR-0118.md +75 -0
  53. elke27-0.1.2/docs/adr/ADR-0119.md +74 -0
  54. elke27-0.1.2/docs/adr/ADR-0120.md +83 -0
  55. elke27-0.1.2/docs/adr/ADR-0121.md +90 -0
  56. elke27-0.1.2/docs/adr/ADR-0122.md +122 -0
  57. elke27-0.1.2/docs/adr/ADR-0123.md +86 -0
  58. elke27-0.1.2/docs/adr/README.md +167 -0
  59. elke27-0.1.2/docs/client_contract_summary.md +63 -0
  60. elke27-0.1.2/docs/ddr/DDR-0001.md +42 -0
  61. elke27-0.1.2/docs/ddr/DDR-0002.md +35 -0
  62. elke27-0.1.2/docs/ddr/DDR-0003.md +46 -0
  63. elke27-0.1.2/docs/ddr/DDR-0004.md +37 -0
  64. elke27-0.1.2/docs/ddr/DDR-0005.md +32 -0
  65. elke27-0.1.2/docs/ddr/DDR-0006.md +33 -0
  66. elke27-0.1.2/docs/ddr/DDR-0007.md +37 -0
  67. elke27-0.1.2/docs/ddr/DDR-0008.md +37 -0
  68. elke27-0.1.2/docs/ddr/DDR-0009.md +43 -0
  69. elke27-0.1.2/docs/ddr/DDR-0010.md +44 -0
  70. elke27-0.1.2/docs/ddr/DDR-0011.md +44 -0
  71. elke27-0.1.2/docs/ddr/DDR-0012.md +46 -0
  72. elke27-0.1.2/docs/ddr/DDR-0013.md +38 -0
  73. elke27-0.1.2/docs/ddr/DDR-0014.md +48 -0
  74. elke27-0.1.2/docs/ddr/DDR-0015.md +53 -0
  75. elke27-0.1.2/docs/ddr/DDR-0016.md +52 -0
  76. elke27-0.1.2/docs/ddr/DDR-0017.md +51 -0
  77. elke27-0.1.2/docs/ddr/DDR-0018.md +44 -0
  78. elke27-0.1.2/docs/ddr/DDR-0019.md +72 -0
  79. elke27-0.1.2/docs/ddr/DDR-0020.md +53 -0
  80. elke27-0.1.2/docs/ddr/DDR-0021.md +63 -0
  81. elke27-0.1.2/docs/ddr/DDR-0022.md +141 -0
  82. elke27-0.1.2/docs/ddr/DDR-0023.md +84 -0
  83. elke27-0.1.2/docs/ddr/DDR-0024.md +87 -0
  84. elke27-0.1.2/docs/ddr/DDR-0025.md +129 -0
  85. elke27-0.1.2/docs/ddr/DDR-0026.md +27 -0
  86. elke27-0.1.2/docs/ddr/DDR-0027.md +145 -0
  87. elke27-0.1.2/docs/ddr/DDR-0028.md +178 -0
  88. elke27-0.1.2/docs/ddr/DDR-0029.md +45 -0
  89. elke27-0.1.2/docs/ddr/DDR-0030.md +48 -0
  90. elke27-0.1.2/docs/ddr/DDR-0031.md +43 -0
  91. elke27-0.1.2/docs/ddr/DDR-0032.md +55 -0
  92. elke27-0.1.2/docs/ddr/DDR-0033.md +74 -0
  93. elke27-0.1.2/docs/ddr/DDR-0034.md +113 -0
  94. elke27-0.1.2/docs/ddr/DDR-0035.md +77 -0
  95. elke27-0.1.2/docs/ddr/DDR-0036.md +166 -0
  96. elke27-0.1.2/docs/ddr/DDR-0037.md +223 -0
  97. elke27-0.1.2/docs/ddr/DDR-0038.md +55 -0
  98. elke27-0.1.2/docs/ddr/DDR-0039.md +56 -0
  99. elke27-0.1.2/docs/ddr/DDR-0040.md +51 -0
  100. elke27-0.1.2/docs/ddr/DDR-0041.md +69 -0
  101. elke27-0.1.2/docs/ddr/README.md +49 -0
  102. elke27-0.1.2/docs/development.md +94 -0
  103. elke27-0.1.2/docs/installation.md +27 -0
  104. elke27-0.1.2/docs/publishing.md +205 -0
  105. elke27-0.1.2/docs/tdr/README.md +78 -0
  106. elke27-0.1.2/docs/tdr/TDR0001.md +76 -0
  107. elke27-0.1.2/docs/tdr/TDR0002.md +54 -0
  108. elke27-0.1.2/docs/tdr/TDR0003.md +54 -0
  109. elke27-0.1.2/docs/tdr/TDR0004.md +58 -0
  110. elke27-0.1.2/examples/e27_aioscanner.py +49 -0
  111. elke27-0.1.2/examples/e27_api_link.py +146 -0
  112. elke27-0.1.2/examples/e27_client_contract.py +150 -0
  113. elke27-0.1.2/examples/e27_client_contract_example.py +231 -0
  114. elke27-0.1.2/examples/e27_live_version_info.py +206 -0
  115. elke27-0.1.2/examples/e27_network_param_live.py +227 -0
  116. elke27-0.1.2/examples/e27_simple_program.py +138 -0
  117. elke27-0.1.2/examples/e27_unsolicited_monitor.py +133 -0
  118. elke27-0.1.2/examples/elk-e27-env-vars.sh +17 -0
  119. elke27-0.1.2/pyproject.toml +182 -0
  120. elke27-0.1.2/src/elke27_lib/__init__.py +76 -0
  121. elke27-0.1.2/src/elke27_lib/client.py +2179 -0
  122. elke27-0.1.2/src/elke27_lib/const.py +52 -0
  123. elke27-0.1.2/src/elke27_lib/discovery.py +205 -0
  124. elke27-0.1.2/src/elke27_lib/dispatcher.py +767 -0
  125. elke27-0.1.2/src/elke27_lib/encryption.py +280 -0
  126. elke27-0.1.2/src/elke27_lib/errors.py +651 -0
  127. elke27-0.1.2/src/elke27_lib/events.py +455 -0
  128. elke27-0.1.2/src/elke27_lib/features/area.py +165 -0
  129. elke27-0.1.2/src/elke27_lib/features/bus_ios.py +37 -0
  130. elke27-0.1.2/src/elke27_lib/features/control.py +82 -0
  131. elke27-0.1.2/src/elke27_lib/features/keypad.py +70 -0
  132. elke27-0.1.2/src/elke27_lib/features/log.py +131 -0
  133. elke27-0.1.2/src/elke27_lib/features/network_param.py +55 -0
  134. elke27-0.1.2/src/elke27_lib/features/output.py +124 -0
  135. elke27-0.1.2/src/elke27_lib/features/rule.py +35 -0
  136. elke27-0.1.2/src/elke27_lib/features/system.py +385 -0
  137. elke27-0.1.2/src/elke27_lib/features/tstat.py +57 -0
  138. elke27-0.1.2/src/elke27_lib/features/user.py +56 -0
  139. elke27-0.1.2/src/elke27_lib/features/zone.py +187 -0
  140. elke27-0.1.2/src/elke27_lib/framing.py +269 -0
  141. elke27-0.1.2/src/elke27_lib/generators/__init__.py +23 -0
  142. elke27-0.1.2/src/elke27_lib/generators/all_generators.py +73 -0
  143. elke27-0.1.2/src/elke27_lib/generators/area.py +52 -0
  144. elke27-0.1.2/src/elke27_lib/generators/bus_ios.py +9 -0
  145. elke27-0.1.2/src/elke27_lib/generators/control.py +23 -0
  146. elke27-0.1.2/src/elke27_lib/generators/keypad.py +21 -0
  147. elke27-0.1.2/src/elke27_lib/generators/log.py +50 -0
  148. elke27-0.1.2/src/elke27_lib/generators/network_param.py +13 -0
  149. elke27-0.1.2/src/elke27_lib/generators/output.py +45 -0
  150. elke27-0.1.2/src/elke27_lib/generators/registry.py +160 -0
  151. elke27-0.1.2/src/elke27_lib/generators/rule.py +11 -0
  152. elke27-0.1.2/src/elke27_lib/generators/system.py +158 -0
  153. elke27-0.1.2/src/elke27_lib/generators/tstat.py +15 -0
  154. elke27-0.1.2/src/elke27_lib/generators/user.py +17 -0
  155. elke27-0.1.2/src/elke27_lib/generators/zone.py +51 -0
  156. elke27-0.1.2/src/elke27_lib/handlers/all_handlers.py +73 -0
  157. elke27-0.1.2/src/elke27_lib/handlers/area.py +1176 -0
  158. elke27-0.1.2/src/elke27_lib/handlers/bus_ios.py +96 -0
  159. elke27-0.1.2/src/elke27_lib/handlers/control.py +484 -0
  160. elke27-0.1.2/src/elke27_lib/handlers/keypad.py +352 -0
  161. elke27-0.1.2/src/elke27_lib/handlers/log.py +346 -0
  162. elke27-0.1.2/src/elke27_lib/handlers/network_param.py +308 -0
  163. elke27-0.1.2/src/elke27_lib/handlers/output.py +556 -0
  164. elke27-0.1.2/src/elke27_lib/handlers/rule.py +102 -0
  165. elke27-0.1.2/src/elke27_lib/handlers/system.py +552 -0
  166. elke27-0.1.2/src/elke27_lib/handlers/tstat.py +299 -0
  167. elke27-0.1.2/src/elke27_lib/handlers/user.py +238 -0
  168. elke27-0.1.2/src/elke27_lib/handlers/zone.py +1291 -0
  169. elke27-0.1.2/src/elke27_lib/hello.py +244 -0
  170. elke27-0.1.2/src/elke27_lib/kernel.py +1602 -0
  171. elke27-0.1.2/src/elke27_lib/linking.py +497 -0
  172. elke27-0.1.2/src/elke27_lib/message.py +41 -0
  173. elke27-0.1.2/src/elke27_lib/outbound.py +208 -0
  174. elke27-0.1.2/src/elke27_lib/pending.py +100 -0
  175. elke27-0.1.2/src/elke27_lib/permissions.py +512 -0
  176. elke27-0.1.2/src/elke27_lib/presentation.py +369 -0
  177. elke27-0.1.2/src/elke27_lib/provisioning.py +51 -0
  178. elke27-0.1.2/src/elke27_lib/redact.py +105 -0
  179. elke27-0.1.2/src/elke27_lib/session.py +721 -0
  180. elke27-0.1.2/src/elke27_lib/states.py +369 -0
  181. elke27-0.1.2/src/elke27_lib/types.py +255 -0
  182. elke27-0.1.2/src/elke27_lib/util.py +111 -0
  183. elke27-0.1.2/test/__init__.py +0 -0
  184. elke27-0.1.2/test/conftest.py +309 -0
  185. elke27-0.1.2/test/helpers/__init__.py +0 -0
  186. elke27-0.1.2/test/helpers/dispatch.py +20 -0
  187. elke27-0.1.2/test/helpers/error_codes.py +36 -0
  188. elke27-0.1.2/test/helpers/internal.py +15 -0
  189. elke27-0.1.2/test/helpers/live.py +23 -0
  190. elke27-0.1.2/test/helpers/payload_validation.py +227 -0
  191. elke27-0.1.2/test/helpers/redaction.py +95 -0
  192. elke27-0.1.2/test/helpers/reporter.py +200 -0
  193. elke27-0.1.2/test/helpers/trace.py +114 -0
  194. elke27-0.1.2/test/test_area_attribs_names.py +33 -0
  195. elke27-0.1.2/test/test_area_get_configured_block_id.py +26 -0
  196. elke27-0.1.2/test/test_area_get_trouble_route.py +26 -0
  197. elke27-0.1.2/test/test_bootstrap_readiness.py +197 -0
  198. elke27-0.1.2/test/test_csm_snapshot.py +87 -0
  199. elke27-0.1.2/test/test_dispatcher_paged_missing_block_id.py +33 -0
  200. elke27-0.1.2/test/test_e27_area_get_status.py +55 -0
  201. elke27-0.1.2/test/test_e27_area_get_status_live.py +86 -0
  202. elke27-0.1.2/test/test_e27_area_info_live.py +112 -0
  203. elke27-0.1.2/test/test_e27_area_set_arm_state_async_execute.py +176 -0
  204. elke27-0.1.2/test/test_e27_area_set_status_async_execute.py +95 -0
  205. elke27-0.1.2/test/test_e27_async_execute_paged.py +128 -0
  206. elke27-0.1.2/test/test_e27_async_execute_permissions.py +92 -0
  207. elke27-0.1.2/test/test_e27_async_execute_seq.py +109 -0
  208. elke27-0.1.2/test/test_e27_configured_inventory.py +315 -0
  209. elke27-0.1.2/test/test_e27_configured_names_live.py +237 -0
  210. elke27-0.1.2/test/test_e27_conftest.save +15 -0
  211. elke27-0.1.2/test/test_e27_discovery_local_parse.py +13 -0
  212. elke27-0.1.2/test/test_e27_dispatcher.py +369 -0
  213. elke27-0.1.2/test/test_e27_framing.py +476 -0
  214. elke27-0.1.2/test/test_e27_framing_presentation_roundtrip.py +52 -0
  215. elke27-0.1.2/test/test_e27_hello_concat_json.py +78 -0
  216. elke27-0.1.2/test/test_e27_hello_roundtrip.py +79 -0
  217. elke27-0.1.2/test/test_e27_link_raw_buffers.py +115 -0
  218. elke27-0.1.2/test/test_e27_network_param_live.py +93 -0
  219. elke27-0.1.2/test/test_e27_output_tstat_live.py +110 -0
  220. elke27-0.1.2/test/test_e27_presentation.py +195 -0
  221. elke27-0.1.2/test/test_e27_retry_seq.py +49 -0
  222. elke27-0.1.2/test/test_e27_roundtrip.py +157 -0
  223. elke27-0.1.2/test/test_e27_seq.py +13 -0
  224. elke27-0.1.2/test/test_e27_session.py +642 -0
  225. elke27-0.1.2/test/test_e27_table_info_live.py +116 -0
  226. elke27-0.1.2/test/test_e27_util.py +117 -0
  227. elke27-0.1.2/test/test_e27_zone_defs_live.py +102 -0
  228. elke27-0.1.2/test/test_e27_zone_live.py +83 -0
  229. elke27-0.1.2/test/test_e27_zone_status_string.py +46 -0
  230. elke27-0.1.2/test/test_generators_registry.py +150 -0
  231. elke27-0.1.2/test/test_handler_naming.py +8 -0
  232. elke27-0.1.2/test/test_kernel_close_noise.py +40 -0
  233. elke27-0.1.2/test/test_kernel_request_state.py +209 -0
  234. elke27-0.1.2/test/test_keypad_enumeration.py +72 -0
  235. elke27-0.1.2/test/test_live_e27_area_names.py +59 -0
  236. elke27-0.1.2/test/test_live_e27_arm_stay_then_disarm.py +94 -0
  237. elke27-0.1.2/test/test_live_e27_authenticate.py +65 -0
  238. elke27-0.1.2/test/test_live_e27_bypass_events.py +60 -0
  239. elke27-0.1.2/test/test_live_e27_chime.py +121 -0
  240. elke27-0.1.2/test/test_live_e27_keepalive.py +39 -0
  241. elke27-0.1.2/test/test_live_e27_keypads_download.py +79 -0
  242. elke27-0.1.2/test/test_live_e27_link.py +47 -0
  243. elke27-0.1.2/test/test_live_e27_log.py +140 -0
  244. elke27-0.1.2/test/test_live_e27_output_names.py +62 -0
  245. elke27-0.1.2/test/test_live_e27_paged_readonly.py +41 -0
  246. elke27-0.1.2/test/test_live_e27_rules_download.py +33 -0
  247. elke27-0.1.2/test/test_live_e27_system_status.py +62 -0
  248. elke27-0.1.2/test/test_live_e27_users_download.py +134 -0
  249. elke27-0.1.2/test/test_live_e27_zone_bypass.py +80 -0
  250. elke27-0.1.2/test/test_live_e27_zone_names.py +63 -0
  251. elke27-0.1.2/test/test_live_e27_zone_status_flags.py +50 -0
  252. elke27-0.1.2/test/test_log_domain.py +184 -0
  253. elke27-0.1.2/test/test_outbound_queue.py +137 -0
  254. elke27-0.1.2/test/test_output_attribs_names.py +33 -0
  255. elke27-0.1.2/test/test_permissions.py +83 -0
  256. elke27-0.1.2/test/test_placeholder.py +3 -0
  257. elke27-0.1.2/test/test_public_api_imports.py +226 -0
  258. elke27-0.1.2/test/test_root_error_envelope.py +20 -0
  259. elke27-0.1.2/test/test_rule_get_rules_paging.py +149 -0
  260. elke27-0.1.2/test/test_system_status_snapshot.py +49 -0
  261. elke27-0.1.2/test/test_timeout_start_on_send.py +163 -0
  262. elke27-0.1.2/test/test_trouble_handlers_generators.py +77 -0
  263. elke27-0.1.2/test/test_user_enumeration.py +72 -0
  264. elke27-0.1.2/test/test_v2_commands.py +136 -0
  265. elke27-0.1.2/test/test_v2_events_snapshot.py +496 -0
  266. elke27-0.1.2/test/test_v2_wait_ready.py +86 -0
  267. elke27-0.1.2/test/test_zone_attribs_names.py +42 -0
  268. elke27-0.1.2/test/test_zone_bulk_status_configured.py +35 -0
  269. elke27-0.1.2/test/test_zone_get_configured_paging_merge.py +51 -0
  270. elke27-0.1.2/test/test_zone_status_flags.py +76 -0
  271. elke27-0.1.2/uv.lock +447 -0
@@ -0,0 +1,9 @@
1
+ # Changes here will be overwritten by Copier. Do not edit manually.
2
+ _commit: v0.2.21
3
+ _src_path: gh:jlevy/simple-modern-uv
4
+ package_author_email: mitchmitchell1616@msn.com
5
+ package_author_name: mitchmitchell
6
+ package_description: Library for interfacing with the Elk Products E27 Alarm Engine
7
+ package_github_org: mitchmitchell
8
+ package_module: elke27_lib
9
+ package_name: elke27
@@ -0,0 +1,66 @@
1
+ # This workflow will install Python dependencies, run tests and lint with a single version of Python
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
3
+
4
+ name: CI
5
+
6
+ on:
7
+ push:
8
+ # Use ["main", "master"] for CI only on the default branch.
9
+ # Use ["**"] for CI on all branches.
10
+ branches: ["main", "master"]
11
+ pull_request:
12
+ branches: ["main", "master"]
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ build:
19
+ strategy:
20
+ matrix:
21
+ # Update this as needed:
22
+ # Common platforms: ["ubuntu-latest", "macos-latest", "windows-latest"]
23
+ os: ["ubuntu-latest"]
24
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
25
+
26
+ # Linux only by default. Use ${{ matrix.os }} for other OSes.
27
+ runs-on: ${{ matrix.os }}
28
+
29
+ steps:
30
+ # Generally following uv docs:
31
+ # https://docs.astral.sh/uv/guides/integration/github/
32
+
33
+ - name: Checkout (official GitHub action)
34
+ uses: actions/checkout@v6
35
+ with:
36
+ # Important for versioning plugins:
37
+ fetch-depth: 0
38
+
39
+ - name: Remove accidental venv checked into repo
40
+ run: rm -rf bin include pyvenv.cfg lib lib64 .venv
41
+
42
+ - name: Install uv (official Astral action)
43
+ uses: astral-sh/setup-uv@v7
44
+ with:
45
+ # Update this as needed:
46
+ version: "0.9.25"
47
+ enable-cache: true
48
+ python-version: ${{ matrix.python-version }}
49
+
50
+ - name: Set up Python (using uv)
51
+ run: uv python install
52
+
53
+ # Alternately can use the official Python action:
54
+ # - name: Set up Python (using actions/setup-python)
55
+ # uses: actions/setup-python@v5
56
+ # with:
57
+ # python-version: ${{ matrix.python-version }}
58
+
59
+ - name: Install all dependencies
60
+ run: uv sync --all-extras
61
+
62
+ - name: Run linting
63
+ run: uv run python devtools/lint.py
64
+
65
+ - name: Run tests
66
+ run: uv run pytest
@@ -0,0 +1,47 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch: # Enable manual trigger.
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ id-token: write # Mandatory for OIDC.
13
+ contents: read
14
+ steps:
15
+ - name: Checkout (official GitHub action)
16
+ uses: actions/checkout@v6
17
+ with:
18
+ # Important for versioning plugins:
19
+ fetch-depth: 0
20
+
21
+ - name: Remove accidental venv checked into repo
22
+ run: rm -rf bin include pyvenv.cfg lib lib64 .venv
23
+
24
+ - name: Install uv (official Astral action)
25
+ uses: astral-sh/setup-uv@v7
26
+ with:
27
+ version: "0.9.25"
28
+ enable-cache: true
29
+ python-version: "3.12"
30
+
31
+ - name: Set up Python (using uv)
32
+ run: uv python install
33
+
34
+ - name: Install all dependencies
35
+ run: uv sync --all-extras
36
+
37
+ - name: Run tests
38
+ run: uv run pytest
39
+
40
+ - name: Build package
41
+ run: uv build
42
+
43
+ - name: Publish to PyPI
44
+ run: uv publish --trusted-publishing always
45
+ # Although uv is newer and faster, the "official" publishing option is the one from PyPA,
46
+ # which uses twine. If desired, replace `uv publish` with:
47
+ # uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,188 @@
1
+ # Additions to standard GitHub .gitignore:
2
+ *.bak
3
+ *.orig
4
+ tmp/
5
+ trash/
6
+ attic/
7
+ .kash/
8
+
9
+ # test run logs
10
+ artifacts/test_runs/*.jsonl
11
+ test/artifacts/test_runs/*.jsonl
12
+
13
+ # Byte-compiled / optimized / DLL files
14
+ __pycache__/
15
+ *.py[cod]
16
+ *$py.class
17
+
18
+ # C extensions
19
+ *.so
20
+
21
+ # Distribution / packaging
22
+ .Python
23
+ build/
24
+ develop-eggs/
25
+ dist/
26
+ downloads/
27
+ eggs/
28
+ .eggs/
29
+ lib/
30
+ lib64/
31
+ parts/
32
+ sdist/
33
+ var/
34
+ wheels/
35
+ share/python-wheels/
36
+ *.egg-info/
37
+ .installed.cfg
38
+ *.egg
39
+ MANIFEST
40
+
41
+ # PyInstaller
42
+ # Usually these files are written by a python script from a template
43
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
44
+ *.manifest
45
+ *.spec
46
+
47
+ # Installer logs
48
+ pip-log.txt
49
+ pip-delete-this-directory.txt
50
+
51
+ # Unit test / coverage reports
52
+ htmlcov/
53
+ .tox/
54
+ .nox/
55
+ .coverage
56
+ .coverage.*
57
+ .cache
58
+ nosetests.xml
59
+ coverage.xml
60
+ *.cover
61
+ *.py,cover
62
+ .hypothesis/
63
+ .pytest_cache/
64
+ cover/
65
+
66
+ # Translations
67
+ *.mo
68
+ *.pot
69
+
70
+ # Django stuff:
71
+ *.log
72
+ local_settings.py
73
+ db.sqlite3
74
+ db.sqlite3-journal
75
+
76
+ # Flask stuff:
77
+ instance/
78
+ .webassets-cache
79
+
80
+ # Scrapy stuff:
81
+ .scrapy
82
+
83
+ # Sphinx documentation
84
+ docs/_build/
85
+
86
+ # PyBuilder
87
+ .pybuilder/
88
+ target/
89
+
90
+ # Jupyter Notebook
91
+ .ipynb_checkpoints
92
+
93
+ # IPython
94
+ profile_default/
95
+ ipython_config.py
96
+
97
+ # pyenv
98
+ # For a library or package, you might want to ignore these files since the code is
99
+ # intended to run in multiple environments; otherwise, check them in:
100
+ # .python-version
101
+
102
+ # pipenv
103
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
104
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
105
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
106
+ # install all needed dependencies.
107
+ #Pipfile.lock
108
+
109
+ # UV
110
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
111
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
112
+ # commonly ignored for libraries.
113
+ #uv.lock
114
+
115
+ # poetry
116
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
117
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
118
+ # commonly ignored for libraries.
119
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
120
+ #poetry.lock
121
+
122
+ # pdm
123
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
124
+ #pdm.lock
125
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
126
+ # in version control.
127
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
128
+ .pdm.toml
129
+ .pdm-python
130
+ .pdm-build/
131
+
132
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
133
+ __pypackages__/
134
+
135
+ # Celery stuff
136
+ celerybeat-schedule
137
+ celerybeat.pid
138
+
139
+ # SageMath parsed files
140
+ *.sage.py
141
+
142
+ # Environments
143
+ .env
144
+ .venv
145
+ env/
146
+ venv/
147
+ ENV/
148
+ env.bak/
149
+ venv.bak/
150
+
151
+ # Virtualenvs created directly in the repo root (critical for uv / CI)
152
+ bin/
153
+ include/
154
+ pyvenv.cfg
155
+
156
+ # Spyder project settings
157
+ .spyderproject
158
+ .spyproject
159
+
160
+ # Rope project settings
161
+ .ropeproject
162
+
163
+ # mkdocs documentation
164
+ /site
165
+
166
+ # mypy
167
+ .mypy_cache/
168
+ .dmypy.json
169
+ dmypy.json
170
+
171
+ # Pyre type checker
172
+ .pyre/
173
+
174
+ # pytype static type analyzer
175
+ .pytype/
176
+
177
+ # Cython debug symbols
178
+ cython_debug/
179
+
180
+ # PyCharm
181
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
182
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
183
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
184
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
185
+ #.idea/
186
+
187
+ # PyPI configuration file
188
+ .pypirc
elke27-0.1.2/.lock ADDED
File without changes
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
elke27-0.1.2/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 mitchmitchell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
elke27-0.1.2/Makefile ADDED
@@ -0,0 +1,32 @@
1
+ # Makefile for easy development workflows.
2
+ # See docs/development.md for docs.
3
+ # Note GitHub Actions call uv directly, not this Makefile.
4
+
5
+ .DEFAULT_GOAL := default
6
+
7
+ .PHONY: default install lint test upgrade build clean
8
+
9
+ default: install lint test
10
+
11
+ install:
12
+ uv sync --all-extras
13
+
14
+ lint:
15
+ uv run python devtools/lint.py
16
+
17
+ test:
18
+ uv run pytest
19
+
20
+ upgrade:
21
+ uv sync --upgrade --all-extras --dev
22
+
23
+ build:
24
+ uv build
25
+
26
+ clean:
27
+ -rm -rf dist/
28
+ -rm -rf *.egg-info/
29
+ -rm -rf .pytest_cache/
30
+ -rm -rf .mypy_cache/
31
+ -rm -rf .venv/
32
+ -find . -type d -name "__pycache__" -exec rm -rf {} +
elke27-0.1.2/PKG-INFO ADDED
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.4
2
+ Name: elke27
3
+ Version: 0.1.2
4
+ Summary: Library for interfacing with the Elk Products E27 Alarm Engine
5
+ Project-URL: Repository, https://github.com/mitchmitchell/elke27
6
+ Author-email: mitchmitchell <mitchmitchell1616@msn.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: <4.0,>=3.11
20
+ Requires-Dist: cryptography>=42.0.0
21
+ Requires-Dist: typing-extensions>=4.9.0
22
+ Description-Content-Type: text/markdown
23
+
24
+ # elke27
25
+
26
+ # elke27_lib
27
+
28
+ `elke27_lib` is a Python 3.11+ library for interfacing with the **Elk Products E27 Alarm Engine** over the E27 IP protocol. It is designed to be consumed by **Home Assistant** (and standalone tools) while keeping the protocol implementation encapsulated behind a stable client API.
29
+
30
+ This repository also includes:
31
+ - a comprehensive pytest suite (unit + live-on-panel tests)
32
+ - example programs for discovery, linking, connecting, event monitoring, and basic API usage
33
+ - ADRs and protocol notes used to guide implementation
34
+
35
+ ---
36
+
37
+ ## What this library does
38
+
39
+ ### Core capabilities
40
+ - **Discovery**: Find E27 panels on the LAN and return identity details (panel name, MAC, serial, host/port, etc.).
41
+ - **Linking (provisioning)**: Perform the E27 *API_LINK* flow to obtain long-lived link keys (encryption + HMAC keys) used to establish trusted sessions.
42
+ - **Session establishment**: Connect to a panel, perform HELLO + session bootstrap, and transition to a ready state.
43
+ - **Event-driven updates**: Receive unsolicited panel messages and dispatch them as structured events.
44
+ - **Command execution**: Send API requests and receive responses using a strict one-in-flight model (request/response sequencing).
45
+ - **Snapshots**: Provide read-only state “snapshots” for Home Assistant (or other clients) to read stable views of current panel state.
46
+
47
+ ### Stable public surface for Home Assistant
48
+ Home Assistant is intended to import and use **only** the public client API defined in:
49
+
50
+ - `docs/CLIENT_CONTRACT.md`
51
+
52
+ As described there:
53
+ - Home Assistant imports only:
54
+ - `from elke27_lib.client import Elke27Client, Result`
55
+ - Home Assistant must **not** import internal modules (session, dispatcher, features, handlers, etc.).
56
+ - The contract is treated as stable during refactors.
57
+
58
+ If you are building a Home Assistant integration, start by reading:
59
+ - `docs/CLIENT_CONTRACT.md`
60
+ - `docs/PERMISSIONS.md`
61
+ - `docs/adr/*`
62
+
63
+ ---
64
+
65
+ ## High-level architecture (mental model)
66
+
67
+ ### 1) Discovery
68
+ Discovery is used to locate panels and present them to the user by **panel name**, while binding identity definitively by **MAC address**.
69
+
70
+ Implementation entry points:
71
+ - `elke27_lib.discovery`
72
+ - `Elk.discover()` (facade used in examples)
73
+
74
+ ### 2) Linking (API_LINK provisioning)
75
+ Linking is a provisioning-time operation that produces long-lived keys. These keys are persisted externally (for example, by Home Assistant) and reused on subsequent connections.
76
+
77
+ Implementation entry points:
78
+ - `Elke27Client.async_link(...)`
79
+ - `Elk.link(...)` (facade used in examples)
80
+
81
+ ### 3) Session connect + readiness
82
+ Connecting establishes a framed/encrypted session, performs session bootstrap, and transitions the client to “ready”.
83
+
84
+ Per the client contract, readiness is defined by:
85
+ - Session ACTIVE, AND
86
+ - `panel_info.session_id` present, AND
87
+ - `table_info` present
88
+
89
+ Implementation entry points:
90
+ - `Elke27Client.async_connect(host, port, link_keys)`
91
+ - `Elke27Client.wait_ready(timeout_s=...)`
92
+
93
+ ### 4) Features (domain APIs)
94
+ The library exposes “feature” modules (domains) that implement E27 API handlers such as:
95
+ - areas, zones, outputs, thermostats, keypads, control/system, network parameters, rules, logs, users, etc.
96
+
97
+ These are internal to the library; Home Assistant should not import them directly and should rely on the client contract and snapshots/events.
98
+
99
+ ---
100
+
101
+ ## Installation / Development setup
102
+
103
+ The project is packaged via `pyproject.toml` and requires Python >=3.11.
104
+
105
+ Typical development setup (example):
106
+ - create a virtual environment
107
+ - install with development extras
108
+ - run pytest
109
+
110
+ (Exact tooling choice is up to you; the repository includes standard pyproject-based metadata and pytest configuration.)
111
+
112
+ ---
113
+
114
+ ## Example programs
115
+
116
+ Examples live under `examples/` and are intended to be runnable against a real panel on your LAN.
117
+
118
+ ### Environment setup (required)
119
+
120
+ Before running any example programs **or live tests**, you should:
121
+
122
+ 1. Edit the file:
123
+ - `elk-e27-env-vars.sh`
124
+
125
+ 2. Set the appropriate values for your environment, such as:
126
+ - panel host / port
127
+ - access code
128
+ - passphrase
129
+ - optional identity fields
130
+
131
+ 3. Source the file into your shell:
132
+ - `source elk-e27-env-vars.sh`
133
+
134
+ This ensures all required environment variables are defined consistently for
135
+ example programs and pytest live tests.
136
+
137
+ ### 1) Discover panels (no linking, no connect)
138
+ - `examples/e27_aioscanner.py`
139
+ - Scans the LAN and prints discovered panels.
140
+
141
+ ### 2) Provisioning (link only)
142
+ - `examples/e27_api_link.py`
143
+ - Performs API_LINK and prints the resulting link credentials.
144
+ - Does not start a full session or send operational requests.
145
+
146
+ ### 3) Minimal “hello world” connect + version info
147
+ - `examples/e27_simple_program.py`
148
+ - Discover → link → connect → request `control.get_version_info` → pump events until results arrive.
149
+
150
+ ### 4) Monitor unsolicited messages/events
151
+ - `examples/e27_unsolicited_monitor.py`
152
+ - Link → connect → print unsolicited messages/events.
153
+
154
+ ### 5) Client contract examples (Home Assistant–style usage)
155
+ - `examples/e27_client_contract.py`
156
+ - `examples/e27_client_contract_example.py`
157
+ - Demonstrate the “stable client contract” flow:
158
+ - create client → connect → wait_ready → subscribe → receive event → read a snapshot
159
+
160
+ ### 6) Network parameter example with authorization retry
161
+ - `examples/e27_network_param_live.py`
162
+ - Demonstrates a privileged call path that may require PIN authorization.
163
+
164
+ ### 7) Live version info printout
165
+ - `examples/e27_live_version_info.py`
166
+ - End-to-end link/connect/version info with PanelState printing.
167
+
168
+ ### Common environment variables used by examples
169
+ Examples rely on environment variables typically defined via
170
+ `elk-e27-env-vars.sh`, including:
171
+ - `ELKE27_HOST`, `ELKE27_PORT`
172
+ - `ELKE27_ACCESS_CODE`, `ELKE27_PASSPHRASE`
173
+ - Identity fields (optional): `ELKE27_MN`, `ELKE27_SN`, `ELKE27_FWVER`,
174
+ `ELKE27_HWVER`, `ELKE27_OSVER`
175
+
176
+ Many examples also accept command-line arguments (for example, `--host`,
177
+ `--port`) which override environment defaults.
178
+
179
+ ---
180
+
181
+ ## Tests
182
+
183
+ Tests live under `test/` and are split into:
184
+ - **unit tests** (run without a live panel)
185
+ - **live tests** (require a real E27 panel and credentials)
186
+
187
+ ### Running unit tests
188
+ Unit tests should run with a normal pytest invocation.
189
+
190
+ ### Running live tests
191
+ Live tests are gated and will skip unless enabled. In addition to sourcing
192
+ `elk-e27-env-vars.sh`, live tests must be explicitly enabled via environment
193
+ configuration.
194
+
195
+ If required environment values are missing, tests are skipped with a message
196
+ indicating what is needed.
197
+
198
+ ### Test artifacts / reporting
199
+ The test harness supports writing artifacts for each pytest invocation, typically
200
+ in JSONL and optionally YAML.
201
+
202
+ Relevant pytest options:
203
+ - `--e27-report` : `jsonl` (default), `yaml`, `both`, or `none`
204
+ - `--e27-artifacts-dir` : output directory (default: `artifacts/test_runs`)
205
+
206
+ You can also set:
207
+ - `ELK_E27_REPORT_FORMAT`
208
+ - `ELK_E27_ARTIFACTS_DIR`
209
+
210
+ Artifacts are designed to support debugging and regression tracking across
211
+ protocol changes.
212
+
213
+ ### Notable test coverage areas
214
+ The test suite includes coverage for:
215
+ - framing and presentation layer behavior
216
+ - sequence handling and request/response correlation
217
+ - bootstrap readiness
218
+ - configured inventory enumeration
219
+ - paging behavior and dispatcher correctness
220
+ - keepalive and reconnect-adjacent behaviors
221
+ - permissions and authorization flows (including live tests)
222
+
223
+ ---
224
+
225
+ ## Documentation
226
+
227
+ Key documents:
228
+ - `docs/CLIENT_CONTRACT.md` — the stable Home Assistant–facing API contract
229
+ - `docs/PERMISSIONS.md` — permission and authorization semantics
230
+ - `docs/adr/` — architecture decision records guiding behavior and boundaries
231
+
232
+ If you are working on a Home Assistant integration:
233
+ - follow the import boundary rules in `CLIENT_CONTRACT.md`
234
+ - prefer consuming snapshots and events rather than internal protocol details
235
+
236
+ ---
237
+
238
+ ## Notes for Home Assistant integration authors
239
+
240
+ - This library is event-driven and designed for a “hub” style Home Assistant
241
+ integration.
242
+ - Linking keys are long-lived and should be persisted by Home Assistant.
243
+ - Session keys and `session_id` are ephemeral and should not be persisted.
244
+ - Privileged authorization is temporary (vendor-defined behavior); Home Assistant
245
+ should be prepared to re-authorize as needed and should not assume privilege
246
+ persists indefinitely.
247
+ - Request concurrency should remain conservative (one request at a time per
248
+ panel session) to avoid exhausting panel resources.
249
+
250
+ ---
251
+
252
+ ## Repository layout (high level)
253
+
254
+ - `src/elke27_lib/` — library implementation
255
+ - `docs/` — client contract, permissions, and ADRs
256
+ - `examples/` — runnable sample programs
257
+ - `test/` — pytest suite (unit + live)
258
+
259
+ ---
260
+
261
+ ## Support / Contributing
262
+
263
+ - Keep Home Assistant–facing changes aligned with `docs/CLIENT_CONTRACT.md`.
264
+ - Prefer small, testable changes.
265
+ - When adding new feature coverage, consider:
266
+ - unit tests for parsing, dispatch, and mapping
267
+ - live tests for end-to-end behavior (when hardware is available)
268
+ - updating documentation or ADRs if behavior changes
269
+
270
+ ---
271
+
272
+ * * *
273
+
274
+ ## Project Docs
275
+
276
+ For how to install uv and Python, see [installation.md](docs/installation.md).
277
+
278
+ For development workflows, see [development.md](docs/development.md).
279
+
280
+ For instructions on publishing to PyPI, see [publishing.md](docs/publishing.md).
281
+
282
+ * * *
283
+
284
+ *This project was built from
285
+ [simple-modern-uv](https://github.com/jlevy/simple-modern-uv).*