Util for controlling SOMA smart shade, either over MQTT or via a HTTP API
- SOMA smart shade device that has been configured with the SOMA app
- Bluetooth 4.0 LE hardware
- OS supported by noble (I've only tested on macOS and Raspbian)
- Node 8.16.1 or higher (Tested on Node 12.10.0, 11.15.0, 10.15.2, 9.11.2, 8.16.1)
- (Potentially a Bluetooth stick to itself, if you're using some other Bluetooth software, see #59)
Run npm install -g soma-ctrl
somactrl
by itself will print usage information
By default, device scanning will be active for 30 seconds, and any supported ones will be connected to. You may optionally:
- Alter the device scanning timeout, e.g. scan for 60 seconds:
somactrl -t 60
- Specify the number of devices you expect to connect to, e.g. 4 devices expected:
somactrl -e 4
- Manually specify a list of device IDs to connect to, e.g. connect to RISE108 and RISE117:
somactrl RISE108 RISE117
- Manually specify a list of MAC addresses to connect to, e.g.:
somactrl f5:11:7b:ee:f3:43
You must then specify options to use either MQTT, HTTP or both
Specify a port for the API to listen on with -l
:
somactrl -l 3000
Specify a broker URL with --url
option:
somactrl --url mqtt://yourbroker
(mqtt/mqtts/ws/wss accepted)
Username and password for MQTT may be specified with -u
and -p
option
If no password argument is supplied, you can enter it interactively
Base topic defaults to homeassistant
, but may be configured with the -topic
option
For each device connected, data will be published to the following topics:
<baseTopic>/cover/<deviceID>/position
- position
<baseTopic>/cover/<deviceID>/connected
- connected
or disconnected
<baseTopic>/cover/<deviceID>/battery
- battery level
To issue commands:
Move: <baseTopic>/cover/<deviceID>/move
- message: int position between 0 (closed) and 100 (open)
Stop: <baseTopic>/cover/<deviceID>/move
- message: 'stop'
Identify (beep device): <baseTopic>/cover/<deviceID/identify
- message is ignored
In addition, for use with Home Assistant MQTT Discovery:
To automatically setup the cover device:
<baseTopic>/cover/<deviceID>/config
will be set to, e.g.:
{
"name": "Living Room1",
"availability_topic": "homeassistant/cover/RISE148/connection",
"payload_available": "connected",
"payload_not_available": "disconnected",
"position_topic": "homeassistant/cover/RISE148/position",
"set_position_topic": "homeassistant/cover/RISE148/move",
"command_topic": "homeassistant/cover/RISE148/move",
"payload_open": 100,
"payload_close": 0,
"unique_id": "soma_RISE148_cover",
"device": {
"identifiers": "soma_RISE148",
"name": "RISE148",
"manufacturer": "Soma",
"model": "Smart Shade"
}
}
To automatically setup a battery sensor:
<baseTopic>/sensor/cover_<deviceName|slugified>_battery/config
will be set to, e.g.:
{
"name": "Cover <deviceID> battery",
"state_topic": "<baseTopic>/cover/<deviceID>/battery",
"unit_of_measurement": "%",
"device_class": "battery",
"unique_id": "soma_<deviceID>_battery",
"device": {
"identifiers": "soma_RISE148",
"name": "RISE148",
"manufacturer": "Soma",
"model": "Smart Shade"
}
}
<deviceID>
has format RISEnnn
or the device's MAC address in lowercase, with the colon's stripped out and cannot be changed
<deviceName|slugified>
will be the device name (as configured in the app) with spaces replaced by underscores
GET /
: list devices.
Response type: [String : Device]
- ID as String key, Device as value
{
"RISE148": {
"id": "RISE148",
"battery": 29,
"batteryLevelLastChanged": "2018-05-03T17:14:10.590Z",
"position": 0,
"positionLastChanged": "2018-05-03T17:14:10.320Z",
"connectionState": "connected",
"state": "closed",
"group": "Living Room",
"name": "Living Room1"
},
"RISE236": {
"id": "RISE236",
"battery": 28,
"batteryLevelLastChanged": "2018-05-03T17:14:10.497Z",
"position": 0,
"positionLastChanged": "2018-05-03T17:14:10.198Z",
"connectionState": "connected",
"state": "closed",
"group": "Living Room",
"name": "Living Room2"
}
}
GET /<deviceID>
: Get individual device data (or 404 if no device by that ID).
Response type: Device
example:
{
"id": "RISE148",
"battery": 29,
"batteryLevelLastChanged": "2018-05-03T17:14:10.590Z",
"position": 0,
"positionLastChanged": "2018-05-03T17:14:10.320Z",
"connectionState": "connected",
"state": "closed",
"group": "Living Room",
"name": "Living Room1"
}
POST /<deviceID>/identify
: Ask deviceID to identify itself (beep). Response type: 200 - OK
or 404 - Not Found
POST /<deviceID>/move?position=<position>
: Ask deviceID to move to <position>
. Response type: Device
or 404
POST /<deviceID>/stop
: Ask deviceID to stop moving. Response type: 200 - OK
or 404 - Not Found
POST /<deviceID>/calibrateModeStart
: Enable calibrate mode on deviceID. Response type: 200 - OK
or 404 - Not Found
POST /<deviceID>/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
POST /<deviceID>/stop
: Request device to stop moving. Response type: 200 - OK
or 404 - Not Found
POST /<deviceID>/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
POST /<deviceID>/calibrateTop
: When in calibrate mode, set the current position as the top-most position. Response Type: 200 - OK
or 404 - Not Found
POST /<deviceID>/calibrateBottom
: When in calibrate mode, set the current position as the bottom-most position. Response Type: 200 - OK
or 404 - Not Found
POST /<deviceID>/calibrateModeStop
: Disable calibrate mode on deviceID. Response type; 200 - OK
or 404 - Not Found
POST /exit
: Quit somactrl (useful if you run with systemd and want to restart). Response type: 200 - OK
<deviceID>
has format RISEnnn
or the device's MAC address in lowercase, with the colon's stripped out and cannot be changed
<position>
should be an integer between 0 (closed) and 100 (open)