diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 159ef24..7ce5e78 --- a/README.md +++ b/README.md @@ -1,230 +1,380 @@ -[![License][licensing-shield]](LICENSE) -All rights to the [API][switchbot-api-repo] belong to [OpenWonderLabs][OpenWonderLabs-lnk]. - -# SwitchBot API Script Caller (v 0.2.1) - -This (Py)Script allows you to control all (WIP) your SwitchBot devices via API calls (1.1). - -‼️‼️At the moment we have implemented all the devices that we can test, so if you want to be a tester please open an [issue][issues] with "test" in the title or if you are also able to develop go ahead and do a [PR][pr]‼️‼️ - -For more info click [here][switchbot-api-repo] - -- [Requirements](#requirements) -- [Installation](#installation) -- [How To Use](#how-to-use) - - [Refresh Devices](#switchbot-refresh-devices) - - [Turn On](#switchbot-turn-on) - - [Turn Off](#switchbot-turn-off) - - [HVAC](#switchbot-ir-hvac-control) - - [Light](#switchbot-ir-light-control) - - [Generic Command](#switchbot-generic-command) -- [Work in Progress](#work-in-progress) -- [Changelog](#changelog) - -## Requirements - -- HACS ([docs][hacs-docs]) - - PyScript Integration ([docs][pyscript-docs]) - -## Installation -⚠️ **If you update from one of the following versions there have been breaking changes:** -
-Versions - -- [Unnumbered (2023.01.14)][unnum] - -
- - -### Procedure -1. **Clone this repository in your config folder** - ```sh - cd /config - git clone https://github.com/SiriosDev/SwitchBot-API-Script-Caller.git - ``` -2. **Include [`pyscript/switchbot.yaml`](./pyscript/switchbot.yaml) in your `pyscript/config.yaml` under the `switchbot` section** - ```yaml - # /config/pyscript/config.yaml - allow_all_imports: true - apps: - # (...) - # ↓↓↓ attention indentation - switchbot: !include /config/SwitchBot-API-Script-Caller/pyscript/switchbot.yaml - # (...) - ``` -3. **Set the authentication secrets in `secrets.yaml` homeassistant file** - - Random Value (`switchbot_nonc`) (I suggest using an UUID generator, but any unique alphanumeric string is fine) - ```yaml - # secrets.yaml - # (...) - # Token and Secret Key : from `Developer Option` in the SwitchBot App (version ≥6.14) - switchbot_token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - switchbot_sec: xxxxxxxxxxxx - # Random Value: you can use a UUID generator, but any unique alphanumeric string is OK - switchbot_nonc: xxxxxxxxxx - ``` -4. **Link the files in the `pyscript` directory** - ```sh - # use `mkdir -p /config/pyscript/apps/` if the directory doesn't exist - cd /config/pyscript/apps/ - - # Create a symbolic link to the apps directory named switchbot - ln -s /config/SwitchBot-API-Script-Caller/pyscript/apps/switchbot.py switchbot.py - ``` - -### Further Update -By following this procedure, the script can then be updated with newer version using git. -```sh -cd SwitchBot-API-Script-Caller -git pull -``` -⚠️ **See changelog before updating.** -The project is still in developpement and breaking changes may occurs. - -### Installation Notes -- In order to see the `Developper options` in the Switchbot app (version ≥6.14), click repetively on the version number in the App's settings. -
- Click here for detailed procedure - - ![SwitchBot](https://user-images.githubusercontent.com/26876994/210898538-5d07a304-3446-48e0-b020-69140ba89b45.png) - -
-- A symbolic link is symbolic and represent the exact path you enter, if you move the targeted file or if the target is outside of the container (e.g. when using docker) the link will not work. Make sure that you are using a relative path that is accessible for the host reading the link. -- Ensure that `pyscript` is operational before to install this script. -- Except dirs strictly related to pyscript, all others dir are recommended, so organize them as you like, keeping in mind that changing the contents of the "`clone`", could cause the update via `git pull` to fail. - -## How To Use -This script (for now) provides the following services in home assisant. -It is important to execute [`SwitchBot Refresh Devices`](#switchbot-refresh-devices) first in order to be able to use the other features, as it will generate the required Home Assistant entities for your devices. - -### Summary -- [SwitchBot Refresh Devices (`pyscript.switchbot_refresh_devices`)](#switchbot-refresh-devices) -- [SwitchBot Turn ON (`pyscript.switchbot_turn_on`)](#switchbot-turn-on) -- [SwitchBot Turn OFF (`pyscript.switchbot_turn_off`)](#switchbot-turn-off) -- [SwitchBot IR HVAC Control (`pyscript.switchbot_hvac`)](#switchbot-ir-hvac-control) -- [SwitchBot IR Light Control (`pyscript.switchbot_ir_light_control`)](#switchbot-ir-light-control) -- [SwitchBot Generic Command (`pyscript.switchbot_generic_command`)](#switchbot-generic-command) - -### 🔸SwitchBot Refresh Devices -_Create Home Assistant `switch` entity for each IR Device connected with your SwitchBot Hubs. Devices are stored as `switch.switchbot_remote_`._ -_`` correspond to the name of the device in the SwitchBot app._ -_if `` doesn't contains Alphanum characters (e.g is written in another alphabet), it is replaced by `_` (e.g. `switch.switchbot_remote_light_0D62`)_ -_The entities can then be used for sending commands using other functions of this pyscript. ⚠️ Not working stand alone ⚠️_ -_In case the device doesn't exist in the future, you will be notified on your devices._ - -Parameters: ***None*** - -### 🔸SwitchBot Turn On -_Turn a device ON_ - -Parameters: -- `device` - - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). - -### 🔸SwitchBot Turn Off -_Turn a device OFF_ - -Parameters: -- `device` - - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). - -### 🔸SwitchBot IR HVAC Control -_Interface for infrared HVAC (heating, ventilation and air conditioning) device._ - -**Parameters:** -- `device` - - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). -- `temperature:` - - int value from `16` to `30` -- `mode:` - - int value between `1` (auto), `2` (cool), `3` (dry), `4` (fan), `5` (heat) -- `fan_speed:` - - int value between `1` (auto), `2` (low), `3` (medium), `4` (high) -- `state:` - - string value between `on` and `off` - - -### 🔸SwitchBot IR Light Control -_Interface for infrared Light (turnOn, turnOff, brightnessUp and brightnessDown) device._ - -**Parameters:** -- `device` - - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). -- `command:` - - string value between `turnOn`, `turnOff`, `brightnessUp` and `brightnessDown` -- `steps:` - - int value from `1` to `10`, _only works with `brightnessUp/Down`_, iterates the command as many times as selected. - - -### 🔸SwitchBot Generic Command -_Allows you to send any request to the API. (See [documentation][generic-cmd-link])_ - -**Parameters:** -- `device` - - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). -- `command:` - - One of the command supported by the device. (see [documentation][generic-cmd-link]) -- `parameter:` (optional) - - Parameter for the command, if required (e.g. `SetChannel`) - - use `default` if not used -- `commandType:` - - `command` for standard commands - - `customize` for custom commands - - -## Work in Progress -The script works fine, but everything is still WIP, including this file. -For any problems open an Issue, (soon I will insert a template for that). - -## Changelog -### 2023.02.19 v0.2.1 (🛠️ Some Fixes) - -**Fixed ([#15][i15]) `commandType` parameters in `Generic Command`**.
-*Suggest updating if you need to control custom remotes created in the mobile app*. - - - -### 2023.01.16 v0.2.0 (🟢 New Features and 🛠️ Some Fixes) -**Add service `SwitchBot IR Light Control`**:
- Send command via infrared to light device. - -**Corrected some descriptions**. - -**Reworked the way `Refresh Devices` assigns `Friendly Names`**. - -**Removed notifications to all channels in case of errors during `Refresh Devices`**. - -**Now HVAC will have a dedicated icon once the dummy switch is created (`Refresh Devices`)**. - -**Renamed `SwitchBot HVAC API Interface` in `SwitchBot IR HVAC Control`**: _it doesn't affect function it's just a visual thing_. - -**Renamed `SwitchBot Generic Command API Interface` in `SwitchBot Generic Command`**: _it doesn't affect function it's just a visual thing_. - - -### 2023.01.14 v0.1.0 (⚠️ Breaking changes) -**Add service `SwitchBot Refresh Devices`**:
-Retrieves your IR devices from the API. Services now requires `device` instead of `deviceId`. No need to copy paste the id manually anymore. - -Previously: - - Services param was `deviceId` - -Now: - - Services Param is `device` (home assistant ID for sensor, e.g. `switch.switchbot_remote_my_light`) - -Make sure to run `SwitchBot Refresh Devices` before configuring anything else. - -[Full Changelog History here][Changelog] - - -[licensing-shield]: https://img.shields.io/github/license/SiriosDev/SwitchBot-API-Script-Caller?style=flat-square -[hacs-docs]: https://hacs.xyz/docs/setup/prerequisites -[pyscript-docs]: https://hacs-pyscript.readthedocs.io/en/latest/installation.html -[switchbot-api-repo]: https://github.com/OpenWonderLabs/SwitchBotAPI -[OpenWonderLabs-lnk]: https://github.com/OpenWonderLabs -[generic-cmd-link]: https://github.com/OpenWonderLabs/SwitchBotAPI#send-device-control-commands -[deviceid-link]: https://github.com/OpenWonderLabs/SwitchBotAPI#get-device-list -[issues]: https://github.com/SiriosDev/SwitchBot-API-Script-Caller/issues/new -[pr]: https://github.com/SiriosDev/SwitchBot-API-Script-Caller/pulls -[Changelog]: CHANGELOG.md -[i15]: https://github.com/SiriosDev/SwitchBot-API-Script-Caller/issues/15 -[unnum]: #20230114-v010-%EF%B8%8F-breaking-changes +[![License][licensing-shield-this]](LICENSE) ![Maintenance][maintenance-shield] ![Activity][comActivity-shield] [![Donation][donation-shield]](https://ko-fi.com/siriosdev)
+ +# SwitchBot API Script Caller (v 0.3) + +This (Py)Script allows you to control all (WIP) your SwitchBot devices via API calls (1.1). + +> **Warning**
+> **At the moment not all API-compatible models are implemented, if you have the capability do a [fork][fork] and implement it (and request a [PR][pr]), otherwise open an [issue][issues] with "TEST|`Model_Name`" in the title.** + +For more info click [here][switchbot-api-repo] + +- [Requirements](#requirements) +- [Installation](#installation) + - [Procedure](#procedure) + - [Further Updates](#further-updates) + - [Installation Notes](#installation-notes) +- [How To Use](#how-to-use) + - [Summary](#summary) + - [Refresh Devices](#switchbot-refresh-devices) + - [Get Status](#switchbot-get-status) + - [Turn On](#switchbot-turn-on) + - [Turn Off](#switchbot-turn-off) + - [Bot](#switchbot-bot-control) + - [Curtain](#switchbot-curtain-control) + - [HVAC](#switchbot-ir-hvac-control) + - [Light](#switchbot-ir-light-control) + - [Generic Command](#switchbot-generic-command) +- [Work in Progress](#work-in-progress) +- [Changelog](#changelog) + +## Requirements + +- HACS ([docs][hacs-docs]) + - PyScript Integration ([docs][pyscript-docs]) + +## Installation +### Procedure + +1. **Clone this repository in your config folder** + ```sh + cd /config + git clone https://github.com/SiriosDev/SwitchBot-API-Script-Caller.git + ``` +2. **Check if you have a `pyscript/config.yaml` file. If not, create one and then add the following in your main top-level configuration.yaml file.** + ```yaml + pyscript: !include pyscript/config.yaml + ``` +3. **Include [`pyscript/switchbot.yaml`](./pyscript/switchbot.yaml) in your `pyscript/config.yaml` under the `switchbot` section** + ```yaml + # /config/pyscript/config.yaml + allow_all_imports: true + apps: + # (...) + # ↓↓↓ attention indentation + switchbot: !include /config/SwitchBot-API-Script-Caller/pyscript/switchbot.yaml + # (...) + ``` +4. **Set the authentication secrets in `secrets.yaml` homeassistant file** + - Random Value (`switchbot_nonc`) (I suggest using an UUID generator, but any unique alphanumeric string is fine) + ```yaml + # secrets.yaml + # (...) + # Token and Secret Key : from `Developer Option` in the SwitchBot App (version ≥6.14) + switchbot_token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + switchbot_sec: xxxxxxxxxxxx + # Random Value: you can use a UUID generator, but any unique alphanumeric string is OK + switchbot_nonc: xxxxxxxxxx + ``` +5. **Link the files in the `pyscript` directory** + + ```sh + # use `mkdir -p /config/pyscript/apps/` if the directory doesn't exist + cd /config/pyscript/apps/ + + # Create a symbolic link to the apps directory named switchbot + ln -s /config/SwitchBot-API-Script-Caller/pyscript/apps/switchbot.py switchbot.py + ``` + +### Further Updates + +By following this procedure, the script can then be updated with newer version using git. + +```sh +cd SwitchBot-API-Script-Caller +git pull +``` + +> **Warning**
+> The project is still under development, and breaking changes may **frequently** occur. + +**If you update from one of the following versions there have been breaking changes:** + +
+Versions + +- [Unnumbered (2023.01.14)][unnum] + +
+ + +### Installation Notes + +- In order to see the `Developer options` in the Switchbot app (version ≥6.14), click repetively on the version number in the App's settings. +
+ Click here for detailed procedure + + ![SwitchBot](https://user-images.githubusercontent.com/26876994/210898538-5d07a304-3446-48e0-b020-69140ba89b45.png) + +
+ +- A symbolic link is symbolic and represent the exact path you enter, if you move the targeted file or if the target is outside of the container (e.g. when using docker) the link will not work. Make sure that you are using a relative path that is accessible for the host reading the link. +- Ensure that `pyscript` is operational before to install this script. +- Except dirs strictly related to pyscript, all others dir are recommended, so organize them as you like, keeping in mind that changing the contents of the "`clone`", could cause the update via `git pull` to fail. + +## How To Use + +This script (for now) provides the following services in home assisant. +It is important to execute [`SwitchBot Refresh Devices`](#switchbot-refresh-devices) first in order to be able to use the other features, as it will generate the required Home Assistant entities for your devices. + +### Summary + +- [SwitchBot Refresh Devices (`pyscript.switchbot_refresh_devices`)](#switchbot-refresh-devices) +- [SwitchBot Get Status (`pyscript.switchbot_get_status`)](#switchbot-get-status) +- [SwitchBot Turn ON (`pyscript.switchbot_turn_on`)](#switchbot-turn-on) +- [SwitchBot Turn OFF (`pyscript.switchbot_turn_off`)](#switchbot-turn-off) +- [SwitchBot Bot Control (`pyscript.switchbot_bot_command`)](#switchbot-bot-control) +- [SwitchBot Curtain Control (`pyscript.switchbot_curtain_command`)](#switchbot-curtain-control) +- [SwitchBot IR HVAC Control (`pyscript.switchbot_hvac`)](#switchbot-ir-hvac-control) +- [SwitchBot IR Light Control (`pyscript.switchbot_ir_light_control`)](#switchbot-ir-light-control) +- [SwitchBot Generic Command (`pyscript.switchbot_generic_command`)](#switchbot-generic-command) + +### SwitchBot Refresh Devices + +> **Warning**
+> (API call consumed: 1*execution) + +**This service lists all the devices registered in your Switchbot Hubs™ connected to your account.** + +The new entities will have a type corresponding to that of the switchbot app, following the best `type`-`domain` association, in case of mismatch will be assigned to the domain `switch`. + +> **Note**
+> _These devices are stored as `.switchbot_remote_`._
+> _e.g. A SwitchBot Curtain™ will become `cover.switchbot_remote_bedroom_curtains`_. + + + +> **Note**
+> _The `` corresponds to the name of the device in the SwitchBot app, (with `_` instead of ` `)._ +> _If it does not contains Alphanum characters, it is replaced by `_`
(e.g. `switch.switchbot_remote_light_0D62`)_ +> _The `` is an internal unique code._ + +> **Warning**
+> The entities can then be used for sending commands or getting status using other functions of this pyscript.
+> **Not working stand alone.**
+ +_If this service does not find all the devices it had previously found, it will alert you with a persistent notification in the HA WebUi._ + +#### Example +```yaml +service: pyscript.switchbot_refresh_devices +``` +#### Service Data +**_None_** + + +### Switchbot Get Status +``` +pyscript.switchbot_get_status +``` + +_Gets the state of Switchbot Bots, Contact Sensors, Curtains and Meters._ +Runs every five minutes generating 288 API calls per sensor per day. Switchbot limits API calls to 10,000 per day. So, this limits the number of devices to 34 (excluding IR devices.) See the [SwitchbotAPI API](<[url](https://github.com/OpenWonderLabs/SwitchBotAPI#get-device-status)>) for the data returned from a status call. + +Parameters: **_None_** + +### SwitchBot Turn On +``` +pyscript.switchbot_turn_on +``` + +_Turn a device ON._ + +Parameters: + +- `device` + - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). + +### SwitchBot Turn Off +``` +pyscript.switchbot_turn_off +``` + +_Turn a device OFF._ + +Parameters: + +- `device` + - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). + +### SwitchBot Bot Control +``` +pyscript.switchbot_bot_command +``` + +_Interface for "Classic" Bot (turnOn, turnOff, press) devices._ + +**Parameters:** + +- `device` + - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). +- `command:` + - string value between `turnOn`, `turnOff`, `press` +- `repetition:` + - int value from `1` to `10`, _only works with `press`_, iterates the command as many times as selected. + +### Switchbot Curtain Control +``` +pyscript.switchbot_curtain_command +``` + +_Interface for Curtain (turnOn, turnOff, setPosition) devices._ + +- `device` + - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). +- `command:` + - string value between `turnOn`, `turnOff`, `setPosition` +- `index:` + - [wip] int value between `?????` (required for "setPosition" command, otherwise it will be ignored) +- `mode:` + - string value between `Performance`, `Silent`, `Default` (required for "setPosition" command, otherwise it will be ignored) +- `position:` + - int value (in percentage) between `0` and `100` (required for "setPosition" command, otherwise it will be ignored) + +### SwitchBot IR HVAC Control +``` +pyscript.switchbot_hvac +``` + +_Interface for infrared HVAC (heating, ventilation and air conditioning) devices._ + +**Parameters:** + +- `device` + - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). +- `state:` + - string value between `on` and `off` +- `temperature:` + - int value from `16` to `30` +- `mode:` + - string value between `Auto`, `Cool`, `Dry`, `Fan`, `Heat` +- `fan_speed:` + - int value between `Auto`, `Low`, `Medium`, `High` + +### SwitchBot IR Light Control +``` +pyscript.switchbot_ir_light_control +``` + +_Interface for infrared Light (turnOn, turnOff, brightnessUp and brightnessDown) devices._ + +**Parameters:** + +- `device` + - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). +- `command:` + - string value between `turnOn`, `turnOff`, `brightnessUp` and `brightnessDown` +- `steps:` + - int value from `1` to `10`, _only works with `brightnessUp/Down`_, iterates the command as many times as selected. + +### SwitchBot Generic Command +``` +pyscript.switchbot_generic_command +``` + +_Allows you to send any request to the API. (See [documentation][generic-cmd-link])_ + +**Parameters:** + +- `device` + - See [`SwitchBot Refresh Devices`](#switchbot-refresh-devices). +- `command:` + - One of the commands supported by the device. (see [documentation][generic-cmd-link]) +- `parameter:` (optional) + - Parameter for the command, if required (e.g. `SetChannel`) + - use `default` if not used +- `commandType:` + - `command` for standard commands + - `customize` for custom commands + +## Work in Progress + +The script works fine, but everything is still WIP, including this file. +For any problems open an Issue, (soon I will insert a template for that). + +## Changelog + +### v? (🟢 New Features) + +**Add support for non-IR devices** : Bot, Contact Sensor, Curtain and Meter. + +**Add service 'Switchbot Curtains Command'** : Send command to Curtain device. + +**Add time trigger to get the status of Bots, Contact Sensors, Curtains and Meters every 5 minutes.** This will show in the Logbook even if you only have IR devices. However, the API calls will only be made for non-IR devices. + +**Add time trigger to run 'Refresh Devices' at startup.** + +### 2023.02.19 v0.2.1 (🛠️ Some Fixes) + +**Fixed ([#15][i15]) `commandType` parameters in `Generic Command`**.
+_Suggest updating if you need to control custom remotes created in the mobile app_. + +### 2023.01.16 v0.2.0 (🟢 New Features and 🛠️ Some Fixes) + +**Add service `SwitchBot IR Light Control`**:
+Send command via infrared to light device. + +**Corrected some descriptions**. + +**Reworked the way `Refresh Devices` assigns `Friendly Names`**. + +**Removed notifications to all channels in case of errors during `Refresh Devices`**. + +**Now HVAC will have a dedicated icon once the dummy switch is created (`Refresh Devices`)**. + +**Renamed `SwitchBot HVAC API Interface` in `SwitchBot IR HVAC Control`**: _it doesn't affect function it's just a visual thing_. + +**Renamed `SwitchBot Generic Command API Interface` in `SwitchBot Generic Command`**: _it doesn't affect function it's just a visual thing_. + +### 2023.01.14 v0.1.0 (⚠️ Breaking changes) + +**Add service `SwitchBot Refresh Devices`**:
+Retrieves your IR devices from the API. Services now requires `device` instead of `deviceId`. No need to copy paste the id manually anymore. + +Previously: + +- Services param was `deviceId` + +Now: + +- Services Param is `device` (home assistant ID for sensor, e.g. `switch.switchbot_remote_my_light`) + +Make sure to run `SwitchBot Refresh Devices` before configuring anything else. + +[Full Changelog History here][changelog] + +[licensing-shield-this]: https://img.shields.io/github/license/SiriosDev/SwitchBot-API-Script-Caller?style=flat-square +[maintenance-shield]: https://img.shields.io/maintenance/yes/2023?style=flat-square +[comActivity-shield]: https://img.shields.io/github/commit-activity/m/SiriosDev/SwitchBot-API-Script-Caller?style=flat-square +[donation-shield]: https://img.shields.io/badge/Buy%20Me%20A%20Ko--Fi-Donate-magenta +[licensing-shield-ps]: https://img.shields.io/github/license/custom-components/pyscript?style=flat-square +[licensing-shield-sbapi]: https://img.shields.io/github/license/OpenWonderLabs/SwitchBotAPI?style=flat-square +[licensing-shield-hass]: https://img.shields.io/github/license/home-assistant/core?style=flat-square +[hacs-docs]: https://hacs.xyz/docs/setup/prerequisites +[pyscript-docs]: https://hacs-pyscript.readthedocs.io/en/latest/installation.html +[switchbot-api-repo]: https://github.com/OpenWonderLabs/SwitchBotAPI +[openwonderlabs-lnk]: https://github.com/OpenWonderLabs +[generic-cmd-link]: https://github.com/OpenWonderLabs/SwitchBotAPI#send-device-control-commands +[deviceid-link]: https://github.com/OpenWonderLabs/SwitchBotAPI#get-device-list +[issues]: https://github.com/SiriosDev/SwitchBot-API-Script-Caller/issues/new +[pr]: https://github.com/SiriosDev/SwitchBot-API-Script-Caller/pulls +[fork]: https://github.com/SiriosDev/SwitchBot-API-Script-Caller/fork +[changelog]: CHANGELOG.md +[i15]: https://github.com/SiriosDev/SwitchBot-API-Script-Caller/issues/15 +[unnum]: #20230114-v010-%EF%B8%8F-breaking-changes + +--- + +**SwitchBot API Script Caller** is an unofficial, community-driven script NOT affiliated, endorsed or supported by **Wonderlabs, Inc.** Some images used in this app are copyrighted and are supported under fair use. **SwitchBot** and **SwitchBot model names** are trademarks of **Wonderlabs**. No copyright infringement intended.
+**© SwitchBot Global.**
+**© Wonderlabs.** + +--- + +PyScript is distributed under [![License][licensing-shield-ps]](https://github.com/custom-components/pyscript)license.
+The APIs are distributed under [![License][licensing-shield-sbapi]][switchbot-api-repo] license.
+HomeAssistant is distributed under [![License][licensing-shield-hass]](https://github.com/home-assistant/core) license.
+ +***The License at the top of this document refers only to the code in this repository*** + +--- \ No newline at end of file diff --git a/pyscript/apps/switchbot.py b/pyscript/apps/switchbot.py old mode 100644 new mode 100755 index 34fab12..5d3d953 --- a/pyscript/apps/switchbot.py +++ b/pyscript/apps/switchbot.py @@ -1,333 +1,596 @@ -import time, hashlib, hmac, base64, requests -import re, yaml, io - -PREFIX="switchbot_remote_" -DOMAIN="switch" -KEY_DEV_TYPE='remoteType' -KEY_DEV_NAME='deviceName' -KEY_DEV_ID='deviceId' - -# "input" from config -def auth(token=None, secret=None, nonce=None): - - token=str(token) - secret=str(secret) - nonce=str(nonce) - - t = int(round(time.time() * 1000)) - string_to_sign = '{}{}{}'.format(token, t, nonce) - - string_to_sign = bytes(string_to_sign, 'utf-8') - secret = bytes(secret, 'utf-8') - - sign = base64.b64encode(hmac.new(secret, msg=string_to_sign, digestmod=hashlib.sha256).digest()) - - h={"Authorization": (str(token)), "t": (str(t)), "sign": (str(sign, 'utf-8')), "nonce": (str(nonce)), "Content-Type": "application/json; charset=utf8"} - return h - -def gen_icon(dev): - '''Generate icon based on device type. Default to a remote icon.''' - ico = 'remote' - icons = {'Projector': 'projector', 'Light': 'lightbulb-on', 'TV':'television', 'Fan':'fan', 'Air Conditioner': 'air-conditioner'} - typ = dev.get(KEY_DEV_TYPE) - if typ in icons: - ico = icons[typ] - return 'mdi:'+ico - -def clear_existing(): - '''Clear switchbot devices which were saved to avoid zombies.''' - states = state.names(domain=DOMAIN) - prefix = f'{DOMAIN}.{PREFIX}' - for s in states: - if s[0:len(prefix)] == prefix: - log.warning(f"deleting sensor : {s}") - state.delete(s) - -def gen_dev_uid(dev:dict): - '''Generate a Unique ID for Switchbot devices. (devices must have unique names in switchbot app so it works)''' - name = dev.get(KEY_DEV_NAME) - if name is not None: - name = name.lower() - name = re.sub(r'[^0-9a-z]+', '_', name) - if name not in ['_', '']: - return PREFIX+name - return PREFIX + re.sub(r'[^0-9a-z]+', '_', str(dev.get(KEY_DEV_TYPE)).lower())+'_'+str(dev.get(KEY_DEV_ID)[-4:]) - - -def gen_dev_name(dev): - name = ['Switchbot'] - if (dev.get(KEY_DEV_NAME) is not None): - name.append(dev.get(KEY_DEV_NAME)) - #name.append(f"[IR {dev.get(KEY_DEV_TYPE)}]") - return ' '.join(name) - -def extract_device_id(device, _recursived=0): - ''' Retrieve the Switchbot DeviceId. force refresh the devices list if the device doesnt exists.''' - try: - uid = state.get(device) - return uid - except NameError: - if _recursived == 0: - switchbot_refresh_devices() - return extract_device_id(device, _recursived=_recursived+1) - else: - msg=f'Warning: impossible to find {device}. [pyscript SwitchBot]' - service.call('notify', 'persistent_notification', message=msg) - #service.call('notify', 'notify', message=msg) - return None - - - -@pyscript_executor -def requestHelper(_url,_json,_headers): - x=requests.post(_url,json = _json, headers=_headers) - -@pyscript_executor -def requestGetHelper(_url,_json,_headers): - return requests.get(_url,json = _json, headers=_headers) - -def command_execute(headers, device_id, command, parameter=None, custom=False): - url=f"https://api.switch-bot.com/v1.1/devices/{device_id}/commands" - data= {"command": command, "commandType":"command"} - if parameter is not None: - data["parameter"] = parameter - if custom: - data["commandType"] = 'customize' - requestHelper(url, data, headers) - -#services -@service -def switchbot_refresh_devices(): - """yaml -name: SwitchBot refresh devices -description: This service list registered (infrared) devices in the "Switchbot Hubs". The devices are saved as "switch.switchbot_remote_" in Home Assistant and can be used for other commands. -fields: - """ - headers_dict=auth(**pyscript.app_config) - url=f"https://api.switch-bot.com/v1.1/devices" - r = requestGetHelper(url, {}, headers_dict) - log.info(str(r.json())) - infrared = r.json()['body'].get("infraredRemoteList") - if infrared is None: - return None - clear_existing() - for dev in infrared: - log.warning(f"Adding Switchbot Device {dev.get(KEY_DEV_NAME)} [{dev.get(KEY_DEV_TYPE)}] -> {dev.get(KEY_DEV_ID)}") - dev['friendly_name'] = gen_dev_name(dev) - dev['icon'] = gen_icon(dev) - state.set(f'{DOMAIN}.{gen_dev_uid(dev)}', value=dev.get(KEY_DEV_ID), new_attributes=dev ) - -@service -def switchbot_hvac(device, temperature, mode, fan_speed, state): - """yaml -name: SwitchBot IR HVAC Control -description: Control IR HVAC "saved" in "Switchbot Hubs" -fields: - device: - name: Device - description: HVAC Target device - example: switch.switchbot_remote_hvac - default: - required: true - selector: - entity: - domain: switch - - temperature: - name: Temperature - description: HVAC Target Temperature in Celsius (min 16 - Max 30) - example: 26 - default: - required: true - selector: - number: - min: 16 - max: 30 - step: 1 - unit_of_measurement: "°C" - mode: box - - mode: - name: Mode - description: HVAC Mode Selector 1 (auto), 2 (cool), 3 (dry), 4 (fan), 5 (heat) - example: 1 - default: - required: true - selector: - number: - min: 1 - max: 5 - step: 1 - mode: box - - fan_speed: - name: Fan Speed - description: HVAC Fan Speed Selector 1 (auto), 2 (low), 3 (medium), 4 (high) - example: 1 - default: - required: true - selector: - number: - min: 1 - max: 4 - step: 1 - mode: box - - state: - name: Power State - description: HVAC Power State - example: off - default: - required: true - selector: - select: - options: - - on - - off - mode: list - """ - deviceId = extract_device_id(device) - headers_dict = auth(**pyscript.app_config) - command_execute(headers_dict, deviceId, 'setAll', parameter=f"{temperature},{mode},{fan_speed},{state}") - -@service -def switchbot_ir_light_control(device=None, command=None, steps=None): - """yaml -name: SwitchBot IR Light Control -description: Control IR Light "saved" in "Switchbot Hubs" -fields: - device: - name: Device - description: Target device - example: switch.switchbot_remote_light - default: - required: true - selector: - entity: - domain: switch - command: - name: Command - description: Select a Command - example: turnOff - default: - required: true - selector: - select: - options: - - turnOn - - turnOff - - brightnessUp - - brightnessDown - mode: list - steps: - name: Steps - description: How many times to run the command (default 1), only works with brightnessUp/Down - example: turnOff - default: 1 - required: false - selector: - number: - min: 1 - max: 10 - mode: box - """ - if steps == None or command == "turnOn" or command== "turnOff": - steps=1 - for i in range(steps): - device_id = extract_device_id(device) - headers = auth(**pyscript.app_config) - command_execute(headers, device_id, command) - -@service -def switchbot_turn_on(device=None): - - """yaml -name: SwitchBot Turn Device ON -description: Turn Switchbot controlled device ON -fields: - device: - name: Device - description: Target device - example: switch.switchbot_remote_light - default: - required: true - selector: - entity: - domain: switch - """ - deviceId = extract_device_id(device) - headers_dict = auth(**pyscript.app_config) - command_execute(headers_dict, deviceId, "turnOn") - -@service -def switchbot_turn_off(device=None): - """yaml -name: SwitchBot Turn Device OFF -description: Turn Switchbot controlled device OFF -fields: - device: - name: Device - description: Target device - example: switch.switchbot_remote_light - default: - required: true - selector: - entity: - domain: switch - """ - deviceId = extract_device_id(device) - headers_dict=auth(**pyscript.app_config) - command_execute(headers_dict, deviceId, "turnOff") - - -@service -def switchbot_generic_command(device=None, command=None, parameter=None, commandType=None): - """yaml -name: SwitchBot Generic Command -description: Control Switchbot Device through custom command(refer to https://github.com/OpenWonderLabs/SwitchBotAPI) -fields: - device: - name: Device - description: Target device (get req. to api) - example: switch.switchbot_remote_light - default: - required: true - selector: - entity: - domain: switch - - command: - name: Command - description: the name of the command - example: turnOff - default: - required: true - selector: - text: - - parameter: - name: Parameters - description: some commands require parameters, such as SetChannel - example: - default: - required: false - selector: - text: - - commandType: - name: Command Type - description: for customized buttons, this needs to be set to customzie - example: command - default: command - required: true - selector: - select: - options: - - command - - customize - - """ - deviceId = extract_device_id(device) - headers_dict = auth(**pyscript.app_config) - command_execute(headers_dict, deviceId, command, parameter=parameter, custom=(commandType=='customize')) - +from time import time +from hashlib import sha256 +from hmac import new +from base64 import b64encode +from requests import post, get +from re import sub +from uuid import uuid4 + +import yaml, io + +TTD = {'Curtain': 'cover', 'Contact Sensor': 'binary_sensor', 'Meter':'sensor', 'MeterPlus':'sensor', "Air Conditioner": "climate", 'Light': 'light', 'Bot': 'switch'} +ICONS = {'Projector': 'projector', 'Light': 'lightbulb-on', 'TV':'television', 'Fan':'fan', 'Air Conditioner': 'air-conditioner', 'Curtain': 'curtains', 'Contact Sensor': 'leak', 'Meter': 'thermometer', 'MeterPlus': 'thermometer'} +PREFIX="switchbot_remote_" +KEY_DEV_NAME='deviceName' +KEY_DEV_ID='deviceId' +KEY_DEV_IR_TYPE='remoteType' +KEY_DEV_TYPE='deviceType' +KEY_CLOUD='enableCloudService' + +# "input" from config +def auth(conf_dict=None): + + apiHeader={} + + token=str(conf_dict['token']) + secret=str(conf_dict['secret']) + + nonce=uuid4() + + t = int(round(time() * 1000)) + + string_to_sign = bytes(F"{token}{t}{nonce}", 'utf-8') + secret = bytes(secret, 'utf-8') + + sign = b64encode(new(secret, msg=string_to_sign, digestmod=sha256).digest()) + + apiHeader['Authorization']=token + apiHeader['Content-Type']='application/json' + apiHeader['charset']='utf8' + apiHeader['t']=str(t) + apiHeader['sign']=str(sign, 'utf-8') + apiHeader['nonce']=str(nonce) + + return apiHeader + +def gen_icon(dev): + '''Generate icon based on device type. Default to a remote icon.''' + ico = 'remote' + icons = ICONS + typ = dev.get(KEY_DEV_IR_TYPE, None) + if typ == None: + typ = dev.get(KEY_DEV_TYPE) + + if typ in icons: + ico = icons[typ] + return 'mdi:'+ico + +def clear_existing(): + '''Clear switchbot devices which were saved to avoid zombies.''' + states = state.names() + for s in states: + if PREFIX in s: + log.warning(f"deleting sensor : {s}") + state.delete(s) + +def gen_dev_uid(dev:dict): + '''Generate a Unique ID for Switchbot IR devices. (devices must have unique names in switchbot app so it works)''' + name = dev.get(KEY_DEV_NAME) + domain = type_to_domain(dev.get(KEY_DEV_IR_TYPE)) + if domain == None: + domain = type_to_domain(dev.get(KEY_DEV_TYPE)) + if name is not None: + name = name.lower() + name = sub(r'[^0-9a-z]+', '_', name) + if name not in ['_', '']: + return domain + '.' + PREFIX + name + return domain + '.' + PREFIX + sub(r'[^0-9a-z]+', '_', str(dev.get(KEY_DEV_IR_TYPE)).lower())+'_'+str(dev.get(KEY_DEV_ID)[-4:]) + +def type_to_domain(type): + if type in TTD: + return TTD[type] + elif type == None: + return None + else: + return 'switch' + +def gen_dev_name(dev): + name = ['Switchbot'] + if (dev.get(KEY_DEV_NAME) is not None): + name.append(dev.get(KEY_DEV_NAME)) + #name.append(f"[IR {dev.get(KEY_DEV_IR_TYPE)}]") + return ' '.join(name) + +def extract_device_id(device, _recursived=0): + ''' Retrieve the Switchbot DeviceId. force refresh the devices list if the device doesnt exists.''' + try: + uid = state.get(device) + return uid + except NameError: + if _recursived == 0: + switchbot_refresh_devices() + return extract_device_id(device, _recursived=_recursived+1) + else: + msg=f'Warning: impossible to find {device}. [pyscript SwitchBot]' + service.call('notify', 'persistent_notification', message=msg) + #service.call('notify', 'notify', message=msg) + return None + +def create_ir_entities(devices): + for dev in devices: + log.warning(f"Adding Switchbot Device {dev.get(KEY_DEV_NAME)} [{dev.get(KEY_DEV_IR_TYPE)}] -> {dev.get(KEY_DEV_ID)}") + dev['friendly_name'] = gen_dev_name(dev) + dev['icon'] = gen_icon(dev) + state.set(f'{gen_dev_uid(dev)}', value=dev.get(KEY_DEV_ID), new_attributes=dev) + +def create_non_ir_entities(devices): + for non_ir in devices: + if non_ir.get(KEY_CLOUD): # Only load devices that are cloud-connected. + log.warning(f"Adding Switchbot Device {non_ir.get(KEY_DEV_NAME)} [{non_ir.get(KEY_DEV_TYPE)}] -> {non_ir.get(KEY_DEV_ID)}") + non_ir['friendly_name'] = gen_dev_name(non_ir) + non_ir['icon'] = gen_icon(non_ir) + state.set(f'{gen_dev_uid(non_ir)}', value=non_ir.get(KEY_DEV_ID), new_attributes=non_ir) + + +@pyscript_executor +def requestHelper(_url,_json,_headers): + x=post(_url,json = _json, headers=_headers) + +@pyscript_executor +def requestGetHelper(_url,_json,_headers): + return get(_url,json = _json, headers=_headers) + + +def command_execute(headers, device_id, command, parameter=None, custom=False): + url=f"https://api.switch-bot.com/v1.1/devices/{device_id}/commands" + data= {"command": command, "commandType":"command"} + if parameter is not None: + data["parameter"] = parameter + if custom: + data["commandType"] = 'customize' + requestHelper(url, data, headers) + + +def get_status(headers, device_id): + url=f"https://api.switch-bot.com/v1.1/devices/{device_id}/status" + r = requestGetHelper(url, {}, headers) + data = r.json() + status = data['statusCode'] + if status == 100: + return data['body'] + elif status == "n/a": + log.warning(f"Status request for {device_id} unauthorized. Http 401 Error. User permission is denied due to invalid token.") + elif status == 190: + log.warning(f"Status request for {device_id}. System error. Device internal error due to device states not synchronized with server.") + return None + + + + + +# Status checking +# Status requests got every 5 minutes (288 API calls / device / day). +#@time_trigger("period(0:00, 300 sec)") +def h_switchbot_get_status(devices=None): + if devices == None: + states = state.names() + for s in states: + if (PREFIX in s): + if KEY_DEV_TYPE in state.getattr(s).keys(): + deviceId = extract_device_id(s) + headers_dict = auth(pyscript.app_config) + data = get_status(headers_dict, deviceId) + temp = state.getattr(s) + data['friendly_name'] = temp['friendly_name'] + data['icon'] = temp['icon'] + if data != None: + state.set(s, value=deviceId, new_attributes=data) + else: + for s in devices: + if (PREFIX in s): + if KEY_DEV_TYPE in state.getattr(s).keys(): + deviceId = extract_device_id(s) + headers_dict = auth(pyscript.app_config) + data = get_status(headers_dict, deviceId) + temp = state.getattr(s) + data['friendly_name'] = temp['friendly_name'] + data['icon'] = temp['icon'] + if data != None: + state.set(s, value=deviceId, new_attributes=data) + + + +#services +@service +@time_trigger("startup") +def switchbot_refresh_devices(): + """yaml +name: SwitchBot Refresh Devices +description: "Lists all the devices registered in your Switchbot Hubs™ connected to your account. (APIs call consumed: 1*execution)" +fields: + """ + headers_dict=auth(pyscript.app_config) + url=f"https://api.switch-bot.com/v1.1/devices" + r = requestGetHelper(url, {}, headers_dict) + log.info(str(r.json())) + infrared = r.json()['body'].get("infraredRemoteList") + non_infrared = r.json()['body'].get("deviceList") + if infrared and non_infrared is None: + return None + clear_existing() + create_ir_entities(infrared) + create_non_ir_entities(non_infrared) + h_switchbot_get_status() # Get an initial status for sensor-like devices. + + +@service +def switchbot_get_status(): + """yaml +name: SwitchBot Get Status +description: "This service updates the attributes of all devices. (API call consumed: 1*number_of_devices*execution)" +fields: + """ + h_switchbot_get_status() # Get an initial status for sensor-like devices. + +@service +def switchbot_get_single_status(devices=None): + """yaml +name: SwitchBot Get Specific Status +description: "This service updates the attributes of selected devices. It's advisable use this service instead of 'switchbot_get_status' if you need to update only a few devices. (API call consumed: 1*number_of_devices*execution)" +fields: + devices: + name: Devices + description: Target devices + example: switch.switchbot_remote_light + default: + required: true + selector: + entity: + multiple: true + """ + h_switchbot_get_status(devices) # Get an initial status for sensor-like devices. + +@service +def switchbot_ir_hvac(device=None, temperature=None, mode=None, fan_speed=None, state=None): + """yaml +name: SwitchBot IR HVAC Control +description: "Control IR HVAC connected to your SwitchBot account. (API call consumed: 1*execution)" +fields: + device: + name: Device + description: Target device + example: climate.switchbot_remote_hvac + default: + required: true + selector: + entity: + domain: climate + + state: + name: Power State + description: Select a State ("on" by Default) + example: off + default: on + required: true + selector: + select: + options: + - on + - off + mode: list + + temperature: + name: Temperature + description: Select a target temperature (required for "on" state) (min 16 - Max 30) ("26" by Default) + example: 26 + default: 26 + required: false + selector: + number: + min: 16 + max: 30 + step: 1 + unit_of_measurement: "°C" + mode: box + + mode: + name: Mode + description: Select a mode (required for "on" state) ("Fan" by Default) (Use Alt-Auto if Auto not working) + example: Fan + default: Fan + required: false + selector: + select: + options: + - Auto + - Alt-Auto + - Cool + - Heat + - Dry + - Fan + mode: list + + fan_speed: + name: Fan Speed + description: Select a Fan Speed (required for "on" state) ("Auto" by Default) + example: Auto + default: Auto + required: false + selector: + select: + options: + - Auto + - Low + - Medium + - High + mode: list + """ + deviceId = extract_device_id(device) + headers_dict = auth(pyscript.app_config) + if temperature == None or state == "off": + temperature = 26 + if mode == None or state == "off": + mode = "Cool" + if fan_speed == None or state == "off": + fan_speed = "Auto" + modes={"Alt-Auto":"0", "Auto": "1","Cool": "2","Dry": "3","Fan": "4","Heat": "5"} + speeds={"Auto": "1","Low": "2","Medium": "3","High": "4"} + command_execute(headers_dict, deviceId, 'setAll', parameter=f"{temperature},{modes[mode]},{speeds[fan_speed]},{state}") + +@service +def switchbot_ir_light(device=None, command=None, steps=None): + """yaml +name: SwitchBot IR Light Control +description: "Control IR Light connected to your SwitchBot account. (API call consumed: 1*steps*execution)" +fields: + device: + name: Device + description: Target device + example: switch.switchbot_remote_light + default: + required: true + selector: + entity: + domain: light + command: + name: Command + description: Select a Command + example: turnOff + default: + required: true + selector: + select: + options: + - turnOn + - turnOff + - brightnessUp + - brightnessDown + mode: list + steps: + name: Steps + description: Number of Steps ("brightnessUp"/"brightnessDown" command only) ("1" by Default) + example: 1 + default: 1 + required: false + selector: + number: + min: 1 + max: 10 + mode: box + """ + deviceId = extract_device_id(device) + headers = auth(pyscript.app_config) + if steps == None or command == "turnOn" or command== "turnOff": + steps=1 + for i in range(steps): + command_execute(headers, deviceId, command) + + +@service +def switchbot_curtain(device=None, command=None, index=None, mode=None, position=None): + """yaml +name: SwitchBot Curtain Control +description: "Control Switchbot Curtain™ connected to your SwitchBot account. (API call consumed: 1*execution)" +fields: + device: + name: Device + description: Target device + example: cover.switchbot_remote_bedroom_curtains + default: + required: true + selector: + entity: + domain: cover + + command: + name: Command + description: Select a Command + example: turnOff + default: + required: true + selector: + select: + options: + - turnOn + - turnOff + - setPosition + mode: list + + index: + name: Index + description: Index ("0" by Default) + example: 0 + default: 0 + required: false + selector: + number: + min: 0 + max: 1 + step: 1 + mode: box + + mode: + name: Mode + description: Select a Mode (required for "setPosition" command) ("Default" by Default) + example: Performance + default: Default + required: false + selector: + select: + options: + - Performance + - Silent + - Default + mode: list + + position: + name: Position + description: Select a Mode (0%-100%) (required for "setPosition" command) ("50" by Default) + example: 50 + default: 50 + required: false + selector: + number: + min: 0 + max: 100 + step: 1 + unit_of_measurement: "%" + mode: box + """ + + deviceId = extract_device_id(device) + headers_dict = auth(pyscript.app_config) + modes={"Performance": "0", "Silent": "1", "Default": "ff"} + if position == None: + position = "50" + if index == None: + index = "0" + if command == "turnOn" or command == "turnOff": + command_execute(headers_dict, deviceId, command, parameter=None) + else: + command_execute(headers_dict, deviceId, command, parameter=f"{index},{modes[mode]},{position}") + +@service +def switchbot_bot(device=None, command=None, repetition=None): + """yaml +name: SwitchBot Bot Control +description: "Control Switchbot Bot™ connected to your SwitchBot account. (API call consumed: 1*repetions*execution)" +fields: + device: + name: Device + description: Target device + example: switch.switchbot_remote_bot + default: + required: true + selector: + entity: + domain: switch + command: + name: Command + description: Select a Command + example: turnOff + default: + required: true + selector: + select: + options: + - turnOn + - turnOff + - press + mode: list + repetition: + name: Repetition + description: Number of repetitions ("press" command only) ("1" by Default) + example: 1 + default: 1 + required: false + selector: + number: + min: 1 + max: 10 + mode: box + """ + deviceId = extract_device_id(device) + headers_dict=auth(pyscript.app_config) + if repetition == None or not (command == "press"): + repetition = 1 + for i in range(repetition): + command_execute(headers_dict, deviceId, command) + +@service +def switchbot_turn_on(device=None): + """yaml +name: SwitchBot Turn Device ON +description: "Turn ON Switchbot a controlled device, behavior varies by device (API call consumed: 1*execution)" +fields: + device: + name: Device + description: Target device + example: switch.switchbot_remote_light + default: + required: true + selector: + entity: + """ + deviceId = extract_device_id(device) + headers_dict = auth(pyscript.app_config) + command_execute(headers_dict, deviceId, "turnOn") + +@service +def switchbot_turn_off(device=None): + """yaml +name: SwitchBot Turn Device OFF +description: "Turn ON Switchbot a controlled device, behavior varies by device (API call consumed: 1*execution)" +fields: + device: + name: Device + description: Target device + example: switch.switchbot_remote_light + default: + required: true + selector: + entity: + """ + deviceId = extract_device_id(device) + headers_dict=auth(pyscript.app_config) + command_execute(headers_dict, deviceId, "turnOff") + + +@service +def switchbot_generic_command(device=None, command=None, parameter=None, commandType=None): + """yaml +name: SwitchBot Generic Command +description: "Control Switchbot Device through custom command (refer to https://github.com/OpenWonderLabs/SwitchBotAPI) (API call consumed: 1*execution)" +fields: + device: + name: Device + description: Target device + example: switch.switchbot_remote_light + default: + required: true + selector: + entity: + + command: + name: Command + description: The name of the command + example: turnOff + default: + required: true + selector: + text: + + parameter: + name: Parameters + description: Some commands require parameters, such as "SetChannel" + example: + default: + required: false + selector: + text: + + commandType: + name: Command Type + description: For customized buttons, this needs to be set to customize + example: command + default: command + required: true + selector: + select: + options: + - command + - customize + """ + deviceId = extract_device_id(device) + headers_dict = auth(pyscript.app_config) + command_execute(headers_dict, deviceId, command, parameter=parameter, custom=(commandType=='customize')) \ No newline at end of file