{"id":15286942,"url":"https://github.com/binsentsu/am43-ctrl","last_synced_at":"2026-03-07T05:33:03.295Z","repository":{"id":49183297,"uuid":"230264538","full_name":"binsentsu/am43-ctrl","owner":"binsentsu","description":"Node Util for controlling an AM43 Blinds Drive Cover, either over MQTT or via a HTTP API","archived":false,"fork":false,"pushed_at":"2024-01-03T22:47:37.000Z","size":28,"stargazers_count":44,"open_issues_count":21,"forks_count":25,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-11-29T21:13:01.751Z","etag":null,"topics":["a-ok","am43","blindengine","bluetooth","btle","home-assistant","mqtt","zemismart"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/binsentsu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2019-12-26T12:57:48.000Z","updated_at":"2024-12-22T11:14:42.000Z","dependencies_parsed_at":"2024-11-07T18:03:59.581Z","dependency_job_id":null,"html_url":"https://github.com/binsentsu/am43-ctrl","commit_stats":{"total_commits":31,"total_committers":4,"mean_commits":7.75,"dds":0.4193548387096774,"last_synced_commit":"0bc2e419241a4be66dff951bf16ffe557fdd06ad"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/binsentsu/am43-ctrl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binsentsu%2Fam43-ctrl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binsentsu%2Fam43-ctrl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binsentsu%2Fam43-ctrl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binsentsu%2Fam43-ctrl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/binsentsu","download_url":"https://codeload.github.com/binsentsu/am43-ctrl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/binsentsu%2Fam43-ctrl/sbom","scorecard":{"id":238992,"data":{"date":"2025-08-11","repo":{"name":"github.com/binsentsu/am43-ctrl","commit":"c8f86fb1c96e98c66e1cb200e100b0e0e400200b"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"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":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"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":"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":"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":"Dangerous-Workflow","score":-1,"reason":"no workflows found","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":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"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":"Code-Review","score":3,"reason":"Found 5/16 approved changesets -- score normalized to 3","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":"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":"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":"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":"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":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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 19 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-17T06:17:49.382Z","repository_id":49183297,"created_at":"2025-08-17T06:17:49.382Z","updated_at":"2025-08-17T06:17:49.382Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30208731,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T05:23:27.321Z","status":"ssl_error","status_checked_at":"2026-03-07T05:00:17.256Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["a-ok","am43","blindengine","bluetooth","btle","home-assistant","mqtt","zemismart"],"created_at":"2024-09-30T15:19:14.193Z","updated_at":"2026-03-07T05:33:03.273Z","avatar_url":"https://github.com/binsentsu.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AM43 Blinds Drive Controller Util\nUtil for controlling a am43 Cover, either over MQTT or via a HTTP API. When used over MQTT it works together with home-assistant and performs auto disovery configuration of the cover component.\n(Eg. https://nl.aliexpress.com/item/4000106179323.html)\nThis util should work with all blind drives which make use of the Blind Engine App. (A-OK, Zemismart,...)\n\n# Hardware Installation\nInstall the blinds and configure top and bottom positions through the BlindsEngine App.\nRetrieve the MacAddress of the device (for example by using nRF Connect app for android or `sudo bluetoothctl` and `scan on`)\n\n# Requirements\n`sudo apt install libudev-dev`\n\n# Installation\nRun `npm install https://github.com/binsentsu/am43-ctrl`\n\nFor making the application persistent across device reboots a possibility is to use pm2:\nhttps://www.npmjs.com/package/pm2\n\nOr by using native systemd:\n\n- create file am43ctrl.service in /etc/systemd/system :\n```\n[Unit]\nDescription=AM43-ctrl\nAfter=multi-user.target\n\n[Service]\nExecStart=/AM43DIRECTORY/node_modules/.bin/am43ctrl MAC1 MAC12 -l 3001 -d --url mqtt://BROKERIP -u BROKERUSER -p BROKERPASS -d\nRestart=always\nUser=root\nEnvironment=PATH=/usr/bin:/usr/local/bin\nEnvironment=NODE_ENV=production\nWorkingDirectory=/AM43DIRECTORY\n\n[Install]\nWantedBy=multi-user.target\n```\nThen use following commands to persist:\n\n```\nsudo systemctl daemon-reload\nsudo systemctl enable am43ctrl\nsudo systemctl start am43ctrl\n```\n\nYou can obtain logging through:\n`sudo journalctl -u am43ctrl.service`\n\n# Usage\n`sudo am43ctrl` by itself will print usage information\n\nYou need to manually specify a list of MAC addresses to connect to, e.g.: `sudo am43ctrl f5:11:7b:ee:f3:43`\n\n\nYou must then specify options to use either MQTT, HTTP or both\n\n## To use with HTTP\nSpecify a port for the API to listen on with `-l`:\n`sudo am43ctrl MACx MACy -l 3000`\n\n## To use with MQTT\nSpecify a broker URL with `--url` option:\n`sudo am43ctrl --url mqtt://yourbroker` (mqtt/mqtts/ws/wss accepted)\n\nUsername and password for MQTT may be specified with `-u` and `-p` option\n\nIf no password argument is supplied, you can enter it interactively\n\nBluetooth polling interval is randomly selected at startup (10-20 minutes), but can be defined with `-i` option:\n`sudo am43ctrl MACx MACy -l 3000 -i 10`\n\nA minimum successfull connection 'fail-time' can be defined with `-f` option:\n`sudo am43ctrl MACx MACy -l 3000 -f 120000`\nIf no valid connection with a device occurs during \u003cfail-time\u003e seconds, the program will exit. Disabled by default.\n\nBase topic defaults to `homeassistant`, but may be configured with the `--topic` option\n\n\n# MQTT\nTo issue commands:\n\nOPEN: `\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/set` - message: 'OPEN'\n\nCLOSE: `\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/set` - message: 'CLOSE'\n\nSTOP: `\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/set` - message: 'STOP'\n\nSET_POSITION: \n100 is closed\n0 is open\n`\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/setposition` - message: '21'\n\nIn addition, for use with [Home Assistant MQTT Discovery](https://www.home-assistant.io/docs/mqtt/discovery/):\n\nThree entities will be pubished to homeassistant discovery topic:\n\n```\nCover: \n\n{\n    \"name\": \"MAC\",\n    \"availability_topic\": \"homeassistant/cover/MACx/connection\",\n    \"payload_available\": \"Online\",\n    \"payload_not_available\": \"Offline\",\n    \"command_topic\": \"homeassistant/cover/MACx/set\",\n    \"position_topic\": \"homeassistant/cover/MACx/state\",\n    \"set_position_topic\" : \"homeassistant/cover/MACx/setposition\",\n    \"position_open\": 0,\n    \"position_closed\": 100,\n    \"payload_open\": \"OPEN\",\n    \"payload_close\": \"CLOSE\",\n    \"payload_stop\": \"STOP\",\n    \"unique_id\": \"am43_MACx_cover\",\n    \"position_template\": '{{value_json[\\'position\\']}}',\n    \"device\": {\n        \"identifiers\": \"am43_MACx\",\n        \"name\": \"MACx\",\n        \"manufacturer\": \"Generic AM43\"\n    }\n}\n\nBattery Sensor:\n\n{\n    \"name\": \"MAC Battery\",\n    \"availability_topic\": \"homeassistant/cover/MACx/connection\",\n    \"state_topic\": \"homeassistant/cover/MACx/state\n    \"payload_available\": \"Online\",\n    \"payload_not_available\": \"Offline\",\n    \"device_class\" : \"battery\",\n    \"unit_of_measurement\": \"%\",\n    \"unique_id\": \"am43_MACx_battery_sensor\",\n    \"value_template\": '{{value_json[\\'battery\\']}}',\n    \"device\": {\n        \"identifiers\": \"am43_MACx\",\n        \"name\": \"MACx\",\n        \"manufacturer\": \"Generic AM43\"\n    }\n}\n\nLight Sensor:\n\n{\n    \"name\": \"MAC Battery\",\n    \"availability_topic\": \"homeassistant/cover/MACx/connection\",\n    \"state_topic\": \"homeassistant/cover/MACx/state\n    \"payload_available\": \"Online\",\n    \"payload_not_available\": \"Offline\",\n    \"unit_of_measurement\": \"%\",\n    \"unique_id\": \"am43_MACx_light_sensor\",\n    \"value_template\": '{{value_json[\\'light\\']}}',\n    \"device\": {\n        \"identifiers\": \"am43_MACx\",\n        \"name\": \"MACx\",\n        \"manufacturer\": \"Generic AM43\"\n    }\n}\n\n```\n\n## Parameters\n\n`\u003cdeviceID\u003e` has format of the device's MAC address in lowercase, with the colon's stripped out and cannot be changed\n\n\n# HTTP Endpoints\n\n`GET /`: list devices.\nResponse type: `[String : Device]` - ID as String key, Device as value\n```\n{\n   \"c03dc8105277\":{\n      \"id\":\"c03dc8105277\",\n      \"lastconnect\":\"2019-11-23T17:39:48.949Z\",\n      \"lastaction\":\"OPEN\",\n      \"state\":\"OPEN\",\n      \"battery\":42,\n      \"light\":0,\n      \"position\":0\n   }\n}\n```\n\n`GET /\u003cdeviceID\u003e`: Get individual device data (or 404 if no device by that ID).\n\nResponse type: `Device` example:\n```\n{\n   \"id\":\"c03dc8105277\",\n   \"lastconnect\":\"2019-11-23T17:39:48.949Z\",\n   \"lastaction\":\"OPEN\",\n   \"state\":\"OPEN\",\n   \"battery\":42,\n   \"light\":0,\n   \"position\":0\n}\n```\n\n`POST /\u003cdeviceID\u003e/open`: Send OPEN command to am43. Response type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/close`: Send CLOSE command to am43. Response type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/stop`: Send STOP command to am43. Response type: `200 - OK` or `404 - Not Found`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinsentsu%2Fam43-ctrl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbinsentsu%2Fam43-ctrl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbinsentsu%2Fam43-ctrl/lists"}