From 60ceffb4301ceb998da6f71dfd0ac5f7274f5fca Mon Sep 17 00:00:00 2001 From: RogerSelwyn Date: Sun, 19 Jan 2025 18:35:08 +0000 Subject: [PATCH] feat: Add support for Vacuum entity --- README.md | 7 +- .../classes/base_input_entity.py | 12 +- .../classes/climate.py | 20 +-- .../mqtt_discoverystream_alt/classes/cover.py | 20 ++- .../mqtt_discoverystream_alt/classes/fan.py | 30 ++-- .../mqtt_discoverystream_alt/classes/light.py | 6 +- .../mqtt_discoverystream_alt/classes/scene.py | 4 +- .../classes/update.py | 6 +- .../classes/vacuum.py | 155 ++++++++++++++++++ .../mqtt_discoverystream_alt/const.py | 66 ++++---- 10 files changed, 243 insertions(+), 83 deletions(-) create mode 100644 custom_components/mqtt_discoverystream_alt/classes/vacuum.py diff --git a/README.md b/README.md index 3612978..28cdf03 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,11 @@ Provides discovery & command support for: |:----------------|:-------------------|:--------------------------|:----------| | Binary Sensor | binary_sensor | | | | Button | button | Press | | -| Climate | climate | Set HVAC Mode, Set Preset Mode, Set Temperature | | -| Cover | cover | Open, Close, Stop, Set Position, Set Tilt Position | | +| Climate | climate | Set HVAC Mode, Set Preset Mode, Set Temperature | | +| Cover | cover | Open, Close, Stop, Set Position, Set Tilt Position | | | Device Tracker | device_tracker | | | | Event | event | | | -| Fan | Fan | Turn On, Turn Off, Set Percentage, Set Preset Mode, Set Oscillating, Set Direction | | +| Fan | Fan | Turn On, Turn Off, Set Percentage, Set Preset Mode, Set Oscillating, Set Direction | | | Image | image | | References master HA image | | Input Boolean | switch | Turn On, Turn Off | | | Input Button | button | Press | | @@ -35,6 +35,7 @@ Provides discovery & command support for: | Switch | switch | Turn On, Turn Off | | | Text | text | Set Value | | | Update | update | Install | Not able to install specific version or trigger backup | +| Vacuum | vacuum | Start, Stop, Pause, Return To Base, Locate, Clean Spot, Set Fan Speed, Send Custom Command | | ## [Buy Me A Beer 🍻](https://buymeacoffee.com/rogtp) I work on this integration because I like things to work well for myself and others. Whilst I have now made significant changes to the integration, it would not be as it stands today without the initial creation by @koying. Please don't feel you are obligated to donate, but of course it is appreciated. diff --git a/custom_components/mqtt_discoverystream_alt/classes/base_input_entity.py b/custom_components/mqtt_discoverystream_alt/classes/base_input_entity.py index 0724bc2..c46a4c3 100644 --- a/custom_components/mqtt_discoverystream_alt/classes/base_input_entity.py +++ b/custom_components/mqtt_discoverystream_alt/classes/base_input_entity.py @@ -26,7 +26,7 @@ from ..const import ( ATTR_MODE, - ATTR_SET, + COMMAND_SET, CONF_CMD_T, CONF_MAX, CONF_MIN, @@ -52,7 +52,7 @@ class ButtonDiscoveryEntity(DiscoveryEntity): def build_config(self, config, entity_info: EntityInfo): """Build the config for a button.""" del config[CONF_STAT_T] - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) async def _async_handle_message(self, msg): """Handle a message for a button.""" @@ -73,7 +73,7 @@ class NumberDiscoveryEntity(DiscoveryEntity): def build_config(self, config, entity_info: EntityInfo): """Build the config for a number.""" - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) config[CONF_MAX] = entity_info.attributes[ATTR_MAX] config[CONF_MIN] = entity_info.attributes[ATTR_MIN] config[CONF_MODE] = entity_info.attributes[ATTR_MODE] @@ -101,7 +101,7 @@ def build_config(self, config, entity_info: EntityInfo): """Build the config for a select.""" if ATTR_OPTIONS in entity_info.attributes: config[CONF_OPS] = entity_info.attributes[ATTR_OPTIONS] - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) async def _async_handle_message(self, msg): """Handle a message for a select.""" @@ -127,7 +127,7 @@ def build_config(self, config, entity_info: EntityInfo): """Build the config for a switch.""" config[CONF_PL_OFF] = STATE_OFF config[CONF_PL_ON] = STATE_ON - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) async def _async_handle_message(self, msg): """Handle a message for a switch.""" @@ -156,7 +156,7 @@ class TextDiscoveryEntity(DiscoveryEntity): def build_config(self, config, entity_info: EntityInfo): """Build the config for a text.""" - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) config[CONF_MAX] = entity_info.attributes[ATTR_MAX] config[CONF_MIN] = entity_info.attributes[ATTR_MIN] config[CONF_MODE] = entity_info.attributes[ATTR_MODE] diff --git a/custom_components/mqtt_discoverystream_alt/classes/climate.py b/custom_components/mqtt_discoverystream_alt/classes/climate.py index b8446b5..2eace54 100644 --- a/custom_components/mqtt_discoverystream_alt/classes/climate.py +++ b/custom_components/mqtt_discoverystream_alt/classes/climate.py @@ -42,9 +42,9 @@ ) from ..const import ( - ATTR_MODE_COMMAND, - ATTR_PRESET_COMMAND, - ATTR_TEMP_COMMAND, + COMMAND_MODE, + COMMAND_PRESET, + COMMAND_TEMPERATURE, CONF_STAT_T, ) from ..utils import ( @@ -72,9 +72,7 @@ def build_config(self, config, entity_info: EntityInfo): config[CONF_CURRENT_TEMP_TOPIC] = build_topic(ATTR_CURRENT_TEMPERATURE) config[CONF_TEMP_MAX] = entity_info.attributes[ATTR_MAX_TEMP] config[CONF_TEMP_MIN] = entity_info.attributes[ATTR_MIN_TEMP] - add_config_command( - config, entity_info, CONF_MODE_COMMAND_TOPIC, ATTR_MODE_COMMAND - ) + add_config_command(config, entity_info, CONF_MODE_COMMAND_TOPIC, COMMAND_MODE) config[CONF_MODE_LIST] = entity_info.attributes[ATTR_HVAC_MODES] config[CONF_MODE_STATE_TOPIC] = build_topic(ATTR_HVAC_MODE) if ATTR_PRESET_MODES in entity_info.attributes: @@ -86,12 +84,12 @@ def build_config(self, config, entity_info: EntityInfo): config, entity_info, CONF_PRESET_MODE_COMMAND_TOPIC, - ATTR_PRESET_COMMAND, + COMMAND_PRESET, ) if ATTR_PRESET_MODE in entity_info.attributes: config[CONF_PRESET_MODE_STATE_TOPIC] = build_topic(ATTR_PRESET_MODE) add_config_command( - config, entity_info, CONF_TEMP_COMMAND_TOPIC, ATTR_TEMP_COMMAND + config, entity_info, CONF_TEMP_COMMAND_TOPIC, COMMAND_TEMPERATURE ) config[CONF_TEMP_STATE_TOPIC] = build_topic(ATTR_TEMPERATURE) config[CONF_TEMP_STEP] = ( @@ -140,13 +138,13 @@ async def _async_handle_message(self, msg): ATTR_ENTITY_ID: f"{domain}.{entity}", } service_name = None - if command == ATTR_MODE_COMMAND: + if command == COMMAND_MODE: service_payload[ATTR_HVAC_MODE] = msg.payload service_name = SERVICE_SET_HVAC_MODE - elif command == ATTR_PRESET_COMMAND: + elif command == COMMAND_PRESET: service_payload[ATTR_PRESET_MODE] = msg.payload service_name = SERVICE_SET_PRESET_MODE - elif command == ATTR_TEMP_COMMAND: + elif command == COMMAND_TEMPERATURE: service_payload[ATTR_TEMPERATURE] = msg.payload service_name = SERVICE_SET_TEMPERATURE diff --git a/custom_components/mqtt_discoverystream_alt/classes/cover.py b/custom_components/mqtt_discoverystream_alt/classes/cover.py index a8cc37f..9441dff 100644 --- a/custom_components/mqtt_discoverystream_alt/classes/cover.py +++ b/custom_components/mqtt_discoverystream_alt/classes/cover.py @@ -31,9 +31,9 @@ from ..const import ( ATTR_ATTRIBUTES, - ATTR_SET, - ATTR_SET_POSITION, - ATTR_SET_TILT, + COMMAND_SET, + COMMAND_SET_POSITION, + COMMAND_SET_TILT, CONF_CMD_T, CONF_SET_POS_T, CONF_TILT_CMD_T, @@ -57,7 +57,7 @@ class DiscoveryItem(DiscoveryEntity): def build_config(self, config, entity_info: EntityInfo): """Build the config for a cover.""" - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) if ATTR_CURRENT_POSITION in entity_info.attributes or ( entity_info.attributes[ATTR_SUPPORTED_FEATURES] @@ -72,13 +72,15 @@ def build_config(self, config, entity_info: EntityInfo): entity_info.attributes[ATTR_SUPPORTED_FEATURES] & CoverEntityFeature.SET_POSITION ): - add_config_command(config, entity_info, CONF_SET_POS_T, ATTR_SET_POSITION) + add_config_command( + config, entity_info, CONF_SET_POS_T, COMMAND_SET_POSITION + ) if ( entity_info.attributes[ATTR_SUPPORTED_FEATURES] & CoverEntityFeature.SET_TILT_POSITION ): - add_config_command(config, entity_info, CONF_TILT_CMD_T, ATTR_SET_TILT) + add_config_command(config, entity_info, CONF_TILT_CMD_T, COMMAND_SET_TILT) if ATTR_CURRENT_TILT_POSITION in entity_info.attributes: config[CONF_TILT_STATUS_TOPIC] = build_topic(ATTR_ATTRIBUTES) @@ -97,7 +99,7 @@ async def _async_handle_message(self, msg): service_payload = { ATTR_ENTITY_ID: f"{domain}.{entity}", } - if command == ATTR_SET: + if command == COMMAND_SET: if msg.payload == DEFAULT_PAYLOAD_OPEN: await self._hass.services.async_call( domain, SERVICE_OPEN_COVER, service_payload @@ -112,12 +114,12 @@ async def _async_handle_message(self, msg): ) else: command_error(command, msg.payload, entity) - elif command == ATTR_SET_POSITION: + elif command == COMMAND_SET_POSITION: service_payload[ATTR_POSITION] = msg.payload await self._hass.services.async_call( domain, SERVICE_SET_COVER_POSITION, service_payload ) - elif command == ATTR_SET_TILT: + elif command == COMMAND_SET_TILT: service_payload[ATTR_TILT_POSITION] = msg.payload await self._hass.services.async_call( domain, SERVICE_SET_COVER_TILT_POSITION, service_payload diff --git a/custom_components/mqtt_discoverystream_alt/classes/fan.py b/custom_components/mqtt_discoverystream_alt/classes/fan.py index 822ed1e..4df35e5 100644 --- a/custom_components/mqtt_discoverystream_alt/classes/fan.py +++ b/custom_components/mqtt_discoverystream_alt/classes/fan.py @@ -48,11 +48,11 @@ from ..const import ( ATTR_ATTRIBUTES, - ATTR_DIRECTION_COMMAND, - ATTR_OSCILLATION_COMMAND, - ATTR_PERCENTAGE_COMMAND, - ATTR_PRESET_COMMAND, - ATTR_SET, + COMMAND_DIRECTION, + COMMAND_OSCILLATION, + COMMAND_PERCENTAGE, + COMMAND_PRESET, + COMMAND_SET, CONF_CMD_T, ) from ..utils import ( @@ -74,7 +74,7 @@ class DiscoveryItem(DiscoveryEntity): def build_config(self, config, entity_info: EntityInfo): """Build the config for a fan.""" - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) config[CONF_PAYLOAD_OFF] = STATE_OFF config[CONF_PAYLOAD_ON] = STATE_ON @@ -89,7 +89,7 @@ def build_config(self, config, entity_info: EntityInfo): config, entity_info, CONF_DIRECTION_COMMAND_TOPIC, - ATTR_DIRECTION_COMMAND, + COMMAND_DIRECTION, ) if ATTR_OSCILLATING in entity_info.attributes or ( @@ -103,7 +103,7 @@ def build_config(self, config, entity_info: EntityInfo): config, entity_info, CONF_OSCILLATION_COMMAND_TOPIC, - ATTR_OSCILLATION_COMMAND, + COMMAND_OSCILLATION, ) config[CONF_PAYLOAD_OSCILLATION_ON] = True config[CONF_PAYLOAD_OSCILLATION_OFF] = False @@ -120,7 +120,7 @@ def build_config(self, config, entity_info: EntityInfo): config, entity_info, CONF_PRESET_MODE_COMMAND_TOPIC, - ATTR_PRESET_COMMAND, + COMMAND_PRESET, ) config[CONF_PRESET_MODE_STATE_TOPIC] = build_topic(ATTR_ATTRIBUTES) config[CONF_PRESET_MODE_VALUE_TEMPLATE] = ( @@ -136,7 +136,7 @@ def build_config(self, config, entity_info: EntityInfo): config, entity_info, CONF_PERCENTAGE_COMMAND_TOPIC, - ATTR_PERCENTAGE_COMMAND, + COMMAND_PERCENTAGE, ) if ATTR_PERCENTAGE_STEP in entity_info.attributes: @@ -179,7 +179,7 @@ async def _async_handle_message(self, msg): service_payload = { ATTR_ENTITY_ID: entity_id, } - if command == ATTR_SET: + if command == COMMAND_SET: if msg.payload == STATE_ON: await self._hass.services.async_call( domain, SERVICE_TURN_ON, service_payload @@ -191,17 +191,17 @@ async def _async_handle_message(self, msg): else: command_error(command, msg.payload, entity) - elif command == ATTR_DIRECTION_COMMAND: + elif command == COMMAND_DIRECTION: service_payload[ATTR_DIRECTION] = msg.payload await self._hass.services.async_call( domain, SERVICE_SET_DIRECTION, service_payload ) - elif command == ATTR_OSCILLATION_COMMAND: + elif command == COMMAND_OSCILLATION: service_payload[ATTR_OSCILLATING] = msg.payload await self._hass.services.async_call( domain, SERVICE_OSCILLATE, service_payload ) - elif command == ATTR_PERCENTAGE_COMMAND: + elif command == COMMAND_PERCENTAGE: state_obj = self._hass.states.get(entity_id) if pct_step := state_obj.attributes.get(ATTR_PERCENTAGE_STEP): service_payload[ATTR_PERCENTAGE] = int(msg.payload) * pct_step @@ -210,7 +210,7 @@ async def _async_handle_message(self, msg): await self._hass.services.async_call( domain, SERVICE_SET_PERCENTAGE, service_payload ) - elif command == ATTR_PRESET_COMMAND: + elif command == COMMAND_PRESET: service_payload[ATTR_PRESET_MODE] = msg.payload await self._hass.services.async_call( domain, SERVICE_SET_PRESET_MODE, service_payload diff --git a/custom_components/mqtt_discoverystream_alt/classes/light.py b/custom_components/mqtt_discoverystream_alt/classes/light.py index eaaf9f8..942c31a 100644 --- a/custom_components/mqtt_discoverystream_alt/classes/light.py +++ b/custom_components/mqtt_discoverystream_alt/classes/light.py @@ -42,9 +42,9 @@ ATTR_JSON, ATTR_R, ATTR_S, - ATTR_SET_LIGHT, ATTR_X, ATTR_Y, + COMMAND_SET_LIGHT, CONF_CMD_T, CONF_JSON_ATTR_T, STATE_CAPITAL_OFF, @@ -64,7 +64,7 @@ class DiscoveryItem(DiscoveryEntity): def build_config(self, config, entity_info: EntityInfo): # noqa: F821 """Build the config for a light.""" del config[CONF_JSON_ATTR_T] - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET_LIGHT) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET_LIGHT) config[CONF_SCHEMA] = ATTR_JSON supported_features = get_supported_features(self._hass, entity_info.entity_id) @@ -187,7 +187,7 @@ async def _async_handle_message(self, msg): else: _LOGGER.error( 'Invalid state for "%s" - payload: %s for %s', - ATTR_SET_LIGHT, + COMMAND_SET_LIGHT, {msg.payload}, {entity}, ) diff --git a/custom_components/mqtt_discoverystream_alt/classes/scene.py b/custom_components/mqtt_discoverystream_alt/classes/scene.py index 0049137..a43c7a9 100644 --- a/custom_components/mqtt_discoverystream_alt/classes/scene.py +++ b/custom_components/mqtt_discoverystream_alt/classes/scene.py @@ -4,7 +4,7 @@ from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_ON, STATE_ON, Platform -from ..const import ATTR_SET, CONF_CMD_T, CONF_PL_ON +from ..const import COMMAND_SET, CONF_CMD_T, CONF_PL_ON from ..utils import EntityInfo, add_config_command, validate_message from .base_entity import DiscoveryEntity @@ -20,7 +20,7 @@ class DiscoveryItem(DiscoveryEntity): def build_config(self, config, entity_info: EntityInfo): """Build the config for a scene.""" config[CONF_PL_ON] = STATE_ON - add_config_command(config, entity_info, CONF_CMD_T, ATTR_SET) + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) async def _async_handle_message(self, msg): """Handle a message for a scene.""" diff --git a/custom_components/mqtt_discoverystream_alt/classes/update.py b/custom_components/mqtt_discoverystream_alt/classes/update.py index 6409a2a..98f2b09 100644 --- a/custom_components/mqtt_discoverystream_alt/classes/update.py +++ b/custom_components/mqtt_discoverystream_alt/classes/update.py @@ -27,7 +27,7 @@ Platform, ) -from ..const import ATTR_ATTRIBUTES, ATTR_INSTALL, ATTR_INSTALL_COMMAND, CONF_CMD_T +from ..const import ATTR_ATTRIBUTES, ATTR_INSTALL, COMMAND_INSTALL, CONF_CMD_T from ..utils import ( EntityInfo, add_config_command, @@ -52,7 +52,7 @@ def build_config(self, config, entity_info: EntityInfo): & UpdateEntityFeature.INSTALL ): add_config_command(config, entity_info, CONF_CMD_T, ATTR_INSTALL) - config[CONF_PAYLOAD_INSTALL] = ATTR_INSTALL_COMMAND + config[CONF_PAYLOAD_INSTALL] = COMMAND_INSTALL config[CONF_LATEST_VERSION_TOPIC] = build_topic(ATTR_ATTRIBUTES) config[CONF_LATEST_VERSION_TEMPLATE] = ( "{{ value_json['" + ATTR_LATEST_VERSION + "'] }}" @@ -93,7 +93,7 @@ async def _async_handle_message(self, msg): service_payload = { ATTR_ENTITY_ID: entity_id, } - if command == ATTR_INSTALL_COMMAND: + if command == COMMAND_INSTALL: await self._hass.services.async_call( domain, SERVICE_INSTALL, service_payload ) diff --git a/custom_components/mqtt_discoverystream_alt/classes/vacuum.py b/custom_components/mqtt_discoverystream_alt/classes/vacuum.py new file mode 100644 index 0000000..b8df379 --- /dev/null +++ b/custom_components/mqtt_discoverystream_alt/classes/vacuum.py @@ -0,0 +1,155 @@ +"""Vacuum methods for MQTT Discovery Statestream.""" + +import json +import logging + +from homeassistant.components import mqtt +from homeassistant.components.mqtt.vacuum import ( + CONF_FAN_SPEED_LIST, + CONF_SEND_COMMAND_TOPIC, + CONF_SET_FAN_SPEED_TOPIC, + CONF_SUPPORTED_FEATURES, + DEFAULT_PAYLOAD_RETURN_TO_BASE, + STRING_TO_SERVICE, +) +from homeassistant.components.vacuum import ( + ATTR_FAN_SPEED, + ATTR_FAN_SPEED_LIST, + ATTR_PARAMS, + SERVICE_SEND_COMMAND, + SERVICE_SET_FAN_SPEED, + VacuumEntityFeature, +) +from homeassistant.const import ( + ATTR_BATTERY_LEVEL, + ATTR_COMMAND, + ATTR_ENTITY_ID, + ATTR_STATE, + ATTR_SUPPORTED_FEATURES, + Platform, +) +from homeassistant.helpers.json import JSONEncoder + +from ..const import ( + COMMAND_SEND, + COMMAND_SET, + COMMAND_SET_FAN_SPEED, + CONF_CMD_T, +) +from ..utils import ( + EntityInfo, + add_config_command, + command_error, + simple_attribute_add, + validate_message, +) +from .base_entity import DiscoveryEntity + +_LOGGER = logging.getLogger(__name__) + + +class DiscoveryItem(DiscoveryEntity): + """Vacuum class.""" + + PLATFORM = Platform.VACUUM + PUBLISH_STATE = False + + def build_config(self, config, entity_info: EntityInfo): + """Build the config for a vacuum.""" + + add_config_command(config, entity_info, CONF_CMD_T, COMMAND_SET) + config[CONF_SUPPORTED_FEATURES] = self._build_supported_features( + entity_info.attributes[ATTR_SUPPORTED_FEATURES] + ) + + if ATTR_FAN_SPEED_LIST in entity_info.attributes or ( + entity_info.attributes[ATTR_SUPPORTED_FEATURES] + & VacuumEntityFeature.FAN_SPEED + ): + config[CONF_FAN_SPEED_LIST] = entity_info.attributes[ATTR_FAN_SPEED_LIST] + + add_config_command( + config, + entity_info, + CONF_SET_FAN_SPEED_TOPIC, + COMMAND_SET_FAN_SPEED, + ) + if ( + entity_info.attributes[ATTR_SUPPORTED_FEATURES] + & VacuumEntityFeature.SEND_COMMAND + ): + add_config_command( + config, + entity_info, + CONF_SEND_COMMAND_TOPIC, + COMMAND_SEND, + ) + + async def async_publish_state(self, new_state, mybase): + """Build the state for a update.""" + await super().async_publish_state(new_state, mybase) + attributes = new_state.attributes + state = {ATTR_STATE: new_state.state} + simple_attribute_add(state, attributes, ATTR_BATTERY_LEVEL) + simple_attribute_add(state, attributes, ATTR_FAN_SPEED) + encoded = json.dumps(state, cls=JSONEncoder) + await mqtt.async_publish( + self._hass, + f"{mybase}{ATTR_STATE}", + encoded, + 1, + self._publish_retain, + ) + + def _build_supported_features(self, feat_list): + sup_feat = [] + for key, value in STRING_TO_SERVICE.items(): + self._check_feature( + sup_feat, + feat_list, + value, + key, + ) + return sup_feat + + def _check_feature(self, supported_features, feature_list, feature, feature_name): + if feature_list & feature: + supported_features.append(feature_name) + + async def _async_handle_message(self, msg): + """Handle a message for a vacuum.""" + valid, domain, entity, command = validate_message( + self._hass, msg, DiscoveryItem.PLATFORM + ) + if not valid: + return + + entity_id = f"{domain}.{entity}" + service_payload = { + ATTR_ENTITY_ID: entity_id, + } + + if command == COMMAND_SET: + if msg.payload in STRING_TO_SERVICE or msg.payload in [ + DEFAULT_PAYLOAD_RETURN_TO_BASE + ]: + await self._hass.services.async_call( + domain, msg.payload, service_payload + ) + else: + command_error(command, msg.payload, entity) + + elif command == COMMAND_SET_FAN_SPEED: + service_payload[ATTR_FAN_SPEED] = msg.payload + await self._hass.services.async_call( + domain, SERVICE_SET_FAN_SPEED, service_payload + ) + elif command == COMMAND_SEND: + payload_json = json.loads(msg.payload) + service_payload[ATTR_COMMAND] = payload_json[ATTR_COMMAND] + del payload_json[ATTR_COMMAND] + service_payload[ATTR_PARAMS] = payload_json + + await self._hass.services.async_call( + domain, SERVICE_SEND_COMMAND, service_payload + ) diff --git a/custom_components/mqtt_discoverystream_alt/const.py b/custom_components/mqtt_discoverystream_alt/const.py index e8e1e8a..26665e0 100644 --- a/custom_components/mqtt_discoverystream_alt/const.py +++ b/custom_components/mqtt_discoverystream_alt/const.py @@ -21,21 +21,24 @@ ATTR_ATTRIBUTES = "attributes" ATTR_COLOR = "color" ATTR_CONFIG = "config" -ATTR_DIRECTION_COMMAND = "command_direction" ATTR_INSTALL = "install" -ATTR_INSTALL_COMMAND = "install" ATTR_JSON = "JSON" ATTR_MODE = "mode" -ATTR_MODE_COMMAND = "command_mode" -ATTR_OSCILLATION_COMMAND = "command_oscillation" -ATTR_PERCENTAGE_COMMAND = "command_percentage" -ATTR_PRESET_COMMAND = "command_preset" -ATTR_SET = "set" -ATTR_SET_LIGHT = "set_light" -ATTR_SET_POSITION = "set_position" -ATTR_SET_TILT = "set_tilt" ATTR_SUGGESTED_DISPLAY_PRECISION = "suggested_display_precision" -ATTR_TEMP_COMMAND = "command_temperature" + +COMMAND_DIRECTION = "command_direction" +COMMAND_INSTALL = "install" +COMMAND_MODE = "command_mode" +COMMAND_OSCILLATION = "command_oscillation" +COMMAND_PERCENTAGE = "command_percentage" +COMMAND_PRESET = "command_preset" +COMMAND_SEND = "command_send" +COMMAND_SET = "set" +COMMAND_SET_FAN_SPEED = "set_fan_speed" +COMMAND_SET_LIGHT = "set_light" +COMMAND_SET_POSITION = "set_position" +COMMAND_SET_TILT = "set_tilt" +COMMAND_TEMPERATURE = "command_temperature" CONF_BASE_TOPIC = "base_topic" CONF_COMMAND_TOPIC = "command_topic" @@ -100,32 +103,33 @@ SUPPORTED_ENTITY_TYPE_COMMANDS = { Platform.BINARY_SENSOR: [], - Platform.BUTTON: [ATTR_SET], - Platform.CLIMATE: [ATTR_MODE_COMMAND, ATTR_PRESET_COMMAND, ATTR_TEMP_COMMAND], - Platform.COVER: [ATTR_SET, ATTR_SET_POSITION, ATTR_SET_TILT], + Platform.BUTTON: [COMMAND_SET], + Platform.CLIMATE: [COMMAND_MODE, COMMAND_PRESET, COMMAND_TEMPERATURE], + Platform.COVER: [COMMAND_SET, COMMAND_SET_POSITION, COMMAND_SET_TILT], Platform.DEVICE_TRACKER: [], Platform.EVENT: [], Platform.FAN: [ - ATTR_SET, - ATTR_DIRECTION_COMMAND, - ATTR_OSCILLATION_COMMAND, - ATTR_PERCENTAGE_COMMAND, - ATTR_PRESET_COMMAND, + COMMAND_SET, + COMMAND_DIRECTION, + COMMAND_OSCILLATION, + COMMAND_PERCENTAGE, + COMMAND_PRESET, ], Platform.IMAGE: [], - Platform.LIGHT: [ATTR_SET_LIGHT], - Platform.NUMBER: [ATTR_SET], - Platform.SCENE: [ATTR_SET], - Platform.SELECT: [ATTR_SET], + Platform.LIGHT: [COMMAND_SET_LIGHT], + Platform.NUMBER: [COMMAND_SET], + Platform.SCENE: [COMMAND_SET], + Platform.SELECT: [COMMAND_SET], Platform.SENSOR: [], - Platform.SWITCH: [ATTR_SET], - Platform.TEXT: [ATTR_SET], - Platform.UPDATE: [ATTR_INSTALL_COMMAND], - INPUT_BOOLEAN_DOMAIN: [ATTR_SET], - INPUT_BUTTON_DOMAIN: [ATTR_SET], - INPUT_NUMBER_DOMAIN: [ATTR_SET], - INPUT_SELECT_DOMAIN: [ATTR_SET], - INPUT_TEXT_DOMAIN: [ATTR_SET], + Platform.SWITCH: [COMMAND_SET], + Platform.TEXT: [COMMAND_SET], + Platform.UPDATE: [COMMAND_INSTALL], + Platform.VACUUM: [COMMAND_SEND, COMMAND_SET, COMMAND_SET_FAN_SPEED], + INPUT_BOOLEAN_DOMAIN: [COMMAND_SET], + INPUT_BUTTON_DOMAIN: [COMMAND_SET], + INPUT_NUMBER_DOMAIN: [COMMAND_SET], + INPUT_SELECT_DOMAIN: [COMMAND_SET], + INPUT_TEXT_DOMAIN: [COMMAND_SET], } OUTPUT_ENTITIES = {