{"id":16710259,"url":"https://github.com/majamassarini/knx-stack","last_synced_at":"2026-02-25T22:02:27.142Z","repository":{"id":43737774,"uuid":"292843057","full_name":"majamassarini/knx-stack","owner":"majamassarini","description":"A Python 3 KNX stack, not complete but easily extensible. Able to encode/decode messages both for USB HID and KNXnet IP.","archived":false,"fork":false,"pushed_at":"2025-01-06T20:20:12.000Z","size":196,"stargazers_count":7,"open_issues_count":8,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-20T03:43:15.269Z","etag":null,"topics":["automate-home","eib","home-automation","knx","knxnet","knxnetip","library","python","python3","stack","usbhid"],"latest_commit_sha":null,"homepage":"https://maja-massarini-knx-stack.readthedocs-hosted.com/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/majamassarini.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.txt","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-04T12:31:28.000Z","updated_at":"2025-02-13T01:48:07.000Z","dependencies_parsed_at":"2024-01-26T11:26:02.629Z","dependency_job_id":"40395a03-c5ac-49a6-8d8f-39d237b0f08a","html_url":"https://github.com/majamassarini/knx-stack","commit_stats":{"total_commits":21,"total_committers":2,"mean_commits":10.5,"dds":0.04761904761904767,"last_synced_commit":"136d3ce9b7e044136f807f42083033af55d392ac"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/majamassarini/knx-stack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/majamassarini%2Fknx-stack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/majamassarini%2Fknx-stack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/majamassarini%2Fknx-stack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/majamassarini%2Fknx-stack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/majamassarini","download_url":"https://codeload.github.com/majamassarini/knx-stack/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/majamassarini%2Fknx-stack/sbom","scorecard":{"id":613121,"data":{"date":"2025-08-11","repo":{"name":"github.com/majamassarini/knx-stack","commit":"136d3ce9b7e044136f807f42083033af55d392ac"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/21 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/majamassarini/knx-stack/build.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/majamassarini/knx-stack/build.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/majamassarini/knx-stack/build.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/build.yml:22","Warn: pipCommand not pinned by hash: .github/workflows/build.yml:23","Warn: pipCommand not pinned by hash: .github/workflows/build.yml:24","Info:   0 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: COPYING:0","Info: FSF or OSI recognized license: MIT License: COPYING:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T03:08:48.625Z","repository_id":43737774,"created_at":"2025-08-21T03:08:48.626Z","updated_at":"2025-08-21T03:08:48.626Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273982891,"owners_count":25202090,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-06T02:00:13.247Z","response_time":2576,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automate-home","eib","home-automation","knx","knxnet","knxnetip","library","python","python3","stack","usbhid"],"created_at":"2024-10-12T20:07:40.736Z","updated_at":"2026-02-25T22:02:27.089Z","avatar_url":"https://github.com/majamassarini.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# knx-stack\n\n[![Build Status](https://travis-ci.com/majamassarini/knx-stack.svg?branch=master)](https://travis-ci.com/majamassarini/knx-stack)\n[![codecov](https://codecov.io/gh/majamassarini/knx-stack/branch/master/graph/badge.svg?token=HQ27JK26MT)](https://codecov.io/gh/majamassarini/knx-stack)\n[![Documentation Status](https://readthedocs.org/projects/knx-stack/badge/?version=latest)](https://knx-stack.readthedocs.io/en/latest/?badge=latest)\n\nA Python 3 KNX stack, not complete but easily extensible.\n\nIt is able to *encode/decode* knx messages for both **USB HID** and **KNXnet IP**.\n\nIt can be used with an **asynchronous** or **synchronous** client.\n\n## Examples\n\n### Setup \n```python\n    \u003e\u003e\u003e import knx_stack\n    \u003e\u003e\u003e individual_address = knx_stack.Address(0x0001)\n    \u003e\u003e\u003e abcd = knx_stack.GroupAddress(free_style=0xABCD)\n    \u003e\u003e\u003e abce = knx_stack.GroupAddress(three_level_style=knx_stack.address.ThreeLevelStyle(main=21, middle=3, sub=206))\n    \u003e\u003e\u003e abcf = knx_stack.GroupAddress(two_level_style=knx_stack.address.TwoLevelStyle(main=21, sub=975))\n\n    \u003e\u003e\u003e asap_1 = knx_stack.ASAP(1, \"on/off light\")\n    \u003e\u003e\u003e asap_2 = knx_stack.ASAP(2, \"info on/off light\")\n    \u003e\u003e\u003e asap_3 = knx_stack.ASAP(3, \"two temperature sensors (together)\")\n\n    \u003e\u003e\u003e address_table = knx_stack.AddressTable(individual_address, [], 255)\n    \u003e\u003e\u003e association_table = knx_stack.AssociationTable(address_table, [])\n    \u003e\u003e\u003e association_table.associate(asap_1, [abcd])\n    \u003e\u003e\u003e association_table.associate(asap_2, [abcd])\n    \u003e\u003e\u003e association_table.associate(asap_3, [abce, abcf])\n\n    \u003e\u003e\u003e group_object_table = knx_stack.GroupObjectTable({asap_1: knx_stack.datapointtypes.DPT_Switch,\n    ...                                                  asap_2: knx_stack.datapointtypes.DPT_Switch,\n    ...                                                  asap_3: knx_stack.datapointtypes.DPT_Value_Temp,\n    ...                                                  })\n\n    \u003e\u003e\u003e association_table\n    AssociationTable: asap -\u003e addresses\n        0 (individual address) -\u003e [0x0001]\n        1 (on/off light) -\u003e [(0xABCD 21/973 21/3/205)]\n        2 (info on/off light) -\u003e [(0xABCD 21/973 21/3/205)]\n        3 (two temperature sensors (together)) -\u003e [(0xABCE 21/974 21/3/206), (0xABCF 21/975 21/3/207)]\n    AddressTable: individual address: 0x0001, max_size=255\n    \u003cBLANKLINE\u003e\n        tsap -\u003e individual address\n        0 -\u003e 0x0001\n        tsap -\u003e group address (hex_free_style two_level_style three_level_style)\n        1 -\u003e (0xABCD 21/973 21/3/205)\n        2 -\u003e (0xABCE 21/974 21/3/206)\n        3 -\u003e (0xABCF 21/975 21/3/207)\n    \u003cBLANKLINE\u003e\n\n    \u003e\u003e\u003e group_object_table\n    GroupObjectTable: ASAP -\u003e datapointtype\n        1 (on/off light) -\u003e DPT_Switch\n        2 (info on/off light) -\u003e DPT_Switch\n        3 (two temperature sensors (together)) -\u003e DPT_Value_Temp\n    \u003cBLANKLINE\u003e\n```\n\n### USB HID decode/encode\n\n```python\n    \u003e\u003e\u003e state = knx_stack.State(knx_stack.state.Medium.usb_hid, association_table, group_object_table)\n\n    \u003e\u003e\u003e msg = knx_stack.Msg.make_from_str(\"0113130008000B010300002900BCE00001ABCD010080\")\n    \u003e\u003e\u003e knx_stack.decode_msg(state, msg)\n    [GroupValueWriteInd (DPT_Switch {'action': 'off'} for asap 1 (on/off light)), GroupValueWriteInd (DPT_Switch {'action': 'off'} for asap 2 (info on/off light))]\n    \u003e\u003e\u003e msg = knx_stack.Msg.make_from_str(\"0113130008000B010300002900BCE00001ABCC010081\")\n    \u003e\u003e\u003e knx_stack.decode_msg(state, msg)\n    []\n\n    \u003e\u003e\u003e msg = knx_stack.Msg.make_from_str(\"0113140008000C010300002900B4E00001ABCE02008005\")\n    \u003e\u003e\u003e knx_stack.decode_msg(state, msg)\n    [GroupValueWriteInd (DPT_Value_Temp: {'decoded_value': 0.05} for asap 3 (two temperature sensors (together)))]\n\n    \u003e\u003e\u003e req = knx_stack.layer.application.a_group_value_read.req.Msg(asap=asap_3)\n    \u003e\u003e\u003e knx_stack.encode_msg(state, req)\n    0113130008000B01030000110096E00000ABCE010000\n\n    \u003e\u003e\u003e dpt = knx_stack.datapointtypes.DPT_Value_Temp()\n    \u003e\u003e\u003e dpt.encode(0.05)\n    \u003e\u003e\u003e req = knx_stack.layer.application.a_group_value_write.req.Msg(asap=asap_3, dpt=dpt)\n    \u003e\u003e\u003e knx_stack.encode_msg(state, req)\n    0113150008000D01030000110096E00000ABCE0300800005\n```\n\n### KNXnet IP decode/encode\n\n```python\n    \u003e\u003e\u003e state = knx_stack.knxnet_ip.State(knx_stack.state.Medium.knxnet_ip, association_table, group_object_table)\n\n    \u003e\u003e\u003e state.sequence_counter_remote = 1\n    \u003e\u003e\u003e msg = knx_stack.knxnet_ip.Msg.make_from_str(\"061004200015047401002900BCE00001ABCD010080\")\n    \u003e\u003e\u003e knx_stack.decode_msg(state, msg)\n    [TunnelingReq(sequence counter=1, status=\u003cErrorCodes.E_NO_ERROR: 0\u003e), GroupValueWriteInd (DPT_Switch {'action': 'off'} for asap 1 (on/off light)), GroupValueWriteInd (DPT_Switch {'action': 'off'} for asap 2 (info on/off light))]\n    \u003e\u003e\u003e msg = knx_stack.knxnet_ip.Msg.make_from_str(\"061004200016047401002900B4E00001ABCE02008005\")\n    \u003e\u003e\u003e knx_stack.decode_msg(state, msg)\n    [TunnelingReq(sequence counter=1, status=\u003cErrorCodes.E_NO_ERROR: 0\u003e), GroupValueWriteInd (DPT_Value_Temp: {'decoded_value': 0.05} for asap 3 (two temperature sensors (together)))]\n    \u003e\u003e\u003e req = knx_stack.layer.application.a_group_value_read.req.Msg(asap=asap_3)\n    \u003e\u003e\u003e knx_stack.encode_msg(state, req)\n    06100420001504000000110096E00000ABCE010000\n\n    \u003e\u003e\u003e dpt = knx_stack.datapointtypes.DPT_Value_Temp()\n    \u003e\u003e\u003e dpt.encode(0.05)\n    \u003e\u003e\u003e req = knx_stack.layer.application.a_group_value_write.req.Msg(asap=asap_3, dpt=dpt)\n    \u003e\u003e\u003e knx_stack.encode_msg(state, req)\n    06100420001704000000110096E00000ABCE0300800005\n```\n\n### Encode from a dictionary\n\n```python\n    \u003e\u003e\u003e state = knx_stack.State(knx_stack.state.Medium.usb_hid, association_table, group_object_table)\n\n    \u003e\u003e\u003e factory = knx_stack.datapointtypes.DPT_Factory()\n    \u003e\u003e\u003e dpt = factory.make(\"DPT_Switch\", {\"action\": \"off\"})\n    \u003e\u003e\u003e req = knx_stack.layer.application.a_group_value_write.req.Msg(asap=asap_1, dpt=dpt)\n    \u003e\u003e\u003e req\n    GroupValueWriteReq (DPT_Switch {'action': 'off'} for asap 1 (on/off light))\n    \u003e\u003e\u003e knx_stack.encode_msg(state, req)\n    0113130008000B01030000110096E00000ABCD010080\n```\n\n### Decode to a dictionary\n\n```python\n    \u003e\u003e\u003e state = knx_stack.State(knx_stack.state.Medium.usb_hid, association_table, group_object_table)\n\n    \u003e\u003e\u003e msg = knx_stack.knxnet_ip.Msg.make_from_str(\"0113130008000B01030000290096E00000ABCD010080\")\n    \u003e\u003e\u003e msgs = knx_stack.decode_msg(state, msg)\n    \u003e\u003e\u003e msgs\n    [GroupValueWriteInd (DPT_Switch {'action': 'off'} for asap 1 (on/off light)), GroupValueWriteInd (DPT_Switch {'action': 'off'} for asap 2 (info on/off light))]\n    \u003e\u003e\u003e factory = knx_stack.datapointtypes.Description_Factory()\n    \u003e\u003e\u003e factory.make(msgs[0].dpt)\n    ('DPT_Switch', {'action': 'off'})\n```\n\n\n## Installation\n\n```\npip install knx-stack\n```\n\n## Diving In\n\n[Documentation](https://knx-stack.readthedocs.io/en/latest/?badge=latest)\n\n## Contributing\n\nPull requests are welcome.\n\n## License\n\nknx-stack is licensed under the MIT license.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmajamassarini%2Fknx-stack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmajamassarini%2Fknx-stack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmajamassarini%2Fknx-stack/lists"}