{"id":15286953,"url":"https://github.com/andersonshatch/soma-ctrl","last_synced_at":"2025-06-15T20:18:29.362Z","repository":{"id":32291980,"uuid":"122253268","full_name":"andersonshatch/soma-ctrl","owner":"andersonshatch","description":"Node util for controlling SOMA smart shade via MQTT or HTTP","archived":false,"fork":false,"pushed_at":"2022-12-10T16:16:55.000Z","size":440,"stargazers_count":21,"open_issues_count":18,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-26T20:55:41.633Z","etag":null,"topics":["blind","bluetooth","bluetooth-le","btle","home-assistant","home-automation","http","mqtt","nodejs","soma"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/andersonshatch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://paypal.me/andersonshatch","https://monzo.me/joshanderson"]}},"created_at":"2018-02-20T20:38:38.000Z","updated_at":"2024-01-05T13:23:53.000Z","dependencies_parsed_at":"2023-01-14T20:55:09.014Z","dependency_job_id":null,"html_url":"https://github.com/andersonshatch/soma-ctrl","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andersonshatch%2Fsoma-ctrl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andersonshatch%2Fsoma-ctrl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andersonshatch%2Fsoma-ctrl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andersonshatch%2Fsoma-ctrl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andersonshatch","download_url":"https://codeload.github.com/andersonshatch/soma-ctrl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248657830,"owners_count":21140842,"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","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":["blind","bluetooth","bluetooth-le","btle","home-assistant","home-automation","http","mqtt","nodejs","soma"],"created_at":"2024-09-30T15:19:19.698Z","updated_at":"2025-04-13T02:33:01.475Z","avatar_url":"https://github.com/andersonshatch.png","language":"JavaScript","readme":"# SOMA Blind Controller Util [![npm version](https://badge.fury.io/js/soma-ctrl.svg)](https://badge.fury.io/js/soma-ctrl)\nUtil for controlling SOMA smart shade, either over MQTT or via a HTTP API\n\n# Requirements\n- SOMA smart shade device that has been configured with the SOMA app\n- Bluetooth 4.0 LE hardware\n- OS supported by [noble](https://github.com/abandonware/noble) (I've only tested on macOS and Raspbian)\n- Node 8.16.1 or higher (Tested on Node 12.10.0, 11.15.0, 10.15.2, 9.11.2, 8.16.1)\n- (Potentially a Bluetooth stick to itself, if you're using some other Bluetooth software, see [#59](https://github.com/andersonshatch/soma-ctrl/issues/59#issuecomment-497662843))\n\n# Installation\nRun `npm install -g soma-ctrl`\n\n# Usage\n`somactrl` by itself will print usage information\n\nBy default, device scanning will be active for 30 seconds, and any supported ones will be connected to.\nYou may optionally:\n- Alter the device scanning timeout, e.g. scan for 60 seconds: `somactrl -t 60`\n- Specify the number of devices you expect to connect to, e.g. 4 devices expected: `somactrl -e 4`\n- Manually specify a list of device IDs to connect to, e.g. connect to RISE108 and RISE117: `somactrl RISE108 RISE117`\n- Manually specify a list of MAC addresses to connect to, e.g.: `somactrl 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`somactrl -l 3000`\n\n## To use with MQTT\nSpecify a broker URL with `--url` option:\n`somactrl --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\nBase topic defaults to `homeassistant`, but may be configured with the `-topic` option\n\n\n# MQTT\nFor each device connected, data will be published to the following topics:\n`\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/position` - position\n\n`\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/connected` - `connected` or `disconnected`\n\n`\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/battery` - battery level\n\nTo issue commands:\nMove: `\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/move` - message: int position between 0 (closed) and 100 (open)\n\nStop: `\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/move` - message: 'stop'\n\nIdentify (beep device): `\u003cbaseTopic\u003e/cover/\u003cdeviceID/identify` - message is ignored\n\nIn addition, for use with [Home Assistant MQTT Discovery](https://www.home-assistant.io/docs/mqtt/discovery/):\n\nTo automatically setup the cover device:\n`\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/config` will be set to, e.g.:\n```\n{\n    \"name\": \"Living Room1\",\n    \"availability_topic\": \"homeassistant/cover/RISE148/connection\",\n    \"payload_available\": \"connected\",\n    \"payload_not_available\": \"disconnected\",\n    \"position_topic\": \"homeassistant/cover/RISE148/position\",\n    \"set_position_topic\": \"homeassistant/cover/RISE148/move\",\n    \"command_topic\": \"homeassistant/cover/RISE148/move\",\n    \"payload_open\": 100,\n    \"payload_close\": 0,\n    \"unique_id\": \"soma_RISE148_cover\",\n    \"device\": {\n        \"identifiers\": \"soma_RISE148\",\n        \"name\": \"RISE148\",\n        \"manufacturer\": \"Soma\",\n        \"model\": \"Smart Shade\"\n    }\n}\n```\nTo automatically setup a battery sensor:\n`\u003cbaseTopic\u003e/sensor/cover_\u003cdeviceName|slugified\u003e_battery/config` will be set to, e.g.:\n```\n{\n    \"name\": \"Cover \u003cdeviceID\u003e battery\",\n    \"state_topic\": \"\u003cbaseTopic\u003e/cover/\u003cdeviceID\u003e/battery\",\n    \"unit_of_measurement\": \"%\",\n    \"device_class\": \"battery\",\n    \"unique_id\": \"soma_\u003cdeviceID\u003e_battery\",\n    \"device\": {\n        \"identifiers\": \"soma_RISE148\",\n        \"name\": \"RISE148\",\n        \"manufacturer\": \"Soma\",\n        \"model\": \"Smart Shade\"\n    }\n}\n```\n\n## Parameters\n\n`\u003cdeviceID\u003e` has format `RISEnnn` or the device's MAC address in lowercase, with the colon's stripped out and cannot be changed\n\n`\u003cdeviceName|slugified\u003e` will be the device name (as configured in the app) with spaces replaced by underscores\n\n\n# HTTP Endpoints\n\n`GET /`: list devices.\nResponse type: `[String : Device]` - ID as String key, Device as value\n```\n{\n    \"RISE148\": {\n        \"id\": \"RISE148\",\n        \"battery\": 29,\n        \"batteryLevelLastChanged\": \"2018-05-03T17:14:10.590Z\",\n        \"position\": 0,\n        \"positionLastChanged\": \"2018-05-03T17:14:10.320Z\",\n        \"connectionState\": \"connected\",\n        \"state\": \"closed\",\n        \"group\": \"Living Room\",\n        \"name\": \"Living Room1\"\n    },\n    \"RISE236\": {\n        \"id\": \"RISE236\",\n        \"battery\": 28,\n        \"batteryLevelLastChanged\": \"2018-05-03T17:14:10.497Z\",\n        \"position\": 0,\n        \"positionLastChanged\": \"2018-05-03T17:14:10.198Z\",\n        \"connectionState\": \"connected\",\n        \"state\": \"closed\",\n        \"group\": \"Living Room\",\n        \"name\": \"Living Room2\"\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\": \"RISE148\",\n    \"battery\": 29,\n    \"batteryLevelLastChanged\": \"2018-05-03T17:14:10.590Z\",\n    \"position\": 0,\n    \"positionLastChanged\": \"2018-05-03T17:14:10.320Z\",\n    \"connectionState\": \"connected\",\n    \"state\": \"closed\",\n    \"group\": \"Living Room\",\n    \"name\": \"Living Room1\"\n}\n```\n\n`POST /\u003cdeviceID\u003e/identify`: Ask deviceID to identify itself (beep). Response type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/move?position=\u003cposition\u003e`: Ask deviceID to move to `\u003cposition\u003e`. Response type: `Device` or `404`\n\n`POST /\u003cdeviceID\u003e/stop`: Ask deviceID to stop moving. Response type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/calibrateModeStart`: Enable calibrate mode on deviceID. Response type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/moveUp`: Request device to move up. Beware that if calibration mode is enabled, the defined top position is not honoured. Response type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/stop`: Request device to stop moving. Response type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/moveDown`: Request device to move down. Beware that if calibration mode is enabled, the defined bottom position is not honoured. Response type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/calibrateTop`: When in calibrate mode, set the current position as the top-most position. Response Type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/calibrateBottom`: When in calibrate mode, set the current position as the bottom-most position. Response Type: `200 - OK` or `404 - Not Found`\n\n`POST /\u003cdeviceID\u003e/calibrateModeStop`: Disable calibrate mode on deviceID. Response type; `200 - OK` or `404 - Not Found`\n\n`POST /exit`: Quit somactrl (useful if you run with systemd and want to restart). Response type: `200 - OK`\n\n## Parameters\n\n`\u003cdeviceID\u003e` has format `RISEnnn` or the device's MAC address in lowercase, with the colon's stripped out and cannot be changed\n\n`\u003cposition\u003e` should be an integer between 0 (closed) and 100 (open)\n","funding_links":["https://paypal.me/andersonshatch","https://monzo.me/joshanderson"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandersonshatch%2Fsoma-ctrl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandersonshatch%2Fsoma-ctrl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandersonshatch%2Fsoma-ctrl/lists"}