1 """Support for MQTT vacuums."""
3 from __future__
import annotations
6 from typing
import Any, cast
8 import voluptuous
as vol
22 ATTR_SUPPORTED_FEATURES,
34 from .
import subscription
35 from .config
import MQTT_BASE_SCHEMA
36 from .const
import CONF_COMMAND_TOPIC, CONF_RETAIN, CONF_STATE_TOPIC
37 from .entity
import MqttEntity, async_setup_entity_entry_helper
38 from .models
import ReceiveMessage
39 from .schemas
import MQTT_ENTITY_COMMON_SCHEMA
40 from .util
import valid_publish_topic
44 BATTERY =
"battery_level"
45 FAN_SPEED =
"fan_speed"
48 POSSIBLE_STATES: dict[str, str] = {
49 STATE_IDLE: STATE_IDLE,
50 STATE_DOCKED: STATE_DOCKED,
51 STATE_ERROR: STATE_ERROR,
52 STATE_PAUSED: STATE_PAUSED,
53 STATE_RETURNING: STATE_RETURNING,
54 STATE_CLEANING: STATE_CLEANING,
57 CONF_SUPPORTED_FEATURES = ATTR_SUPPORTED_FEATURES
58 CONF_PAYLOAD_TURN_ON =
"payload_turn_on"
59 CONF_PAYLOAD_TURN_OFF =
"payload_turn_off"
60 CONF_PAYLOAD_RETURN_TO_BASE =
"payload_return_to_base"
61 CONF_PAYLOAD_STOP =
"payload_stop"
62 CONF_PAYLOAD_CLEAN_SPOT =
"payload_clean_spot"
63 CONF_PAYLOAD_LOCATE =
"payload_locate"
64 CONF_PAYLOAD_START =
"payload_start"
65 CONF_PAYLOAD_PAUSE =
"payload_pause"
66 CONF_SET_FAN_SPEED_TOPIC =
"set_fan_speed_topic"
67 CONF_FAN_SPEED_LIST =
"fan_speed_list"
68 CONF_SEND_COMMAND_TOPIC =
"send_command_topic"
70 DEFAULT_NAME =
"MQTT State Vacuum"
71 DEFAULT_RETAIN =
False
73 DEFAULT_PAYLOAD_RETURN_TO_BASE =
"return_to_base"
74 DEFAULT_PAYLOAD_STOP =
"stop"
75 DEFAULT_PAYLOAD_CLEAN_SPOT =
"clean_spot"
76 DEFAULT_PAYLOAD_LOCATE =
"locate"
77 DEFAULT_PAYLOAD_START =
"start"
78 DEFAULT_PAYLOAD_PAUSE =
"pause"
80 _LOGGER = logging.getLogger(__name__)
82 SERVICE_TO_STRING: dict[VacuumEntityFeature, str] = {
83 VacuumEntityFeature.START:
"start",
84 VacuumEntityFeature.PAUSE:
"pause",
85 VacuumEntityFeature.STOP:
"stop",
86 VacuumEntityFeature.RETURN_HOME:
"return_home",
87 VacuumEntityFeature.FAN_SPEED:
"fan_speed",
88 VacuumEntityFeature.BATTERY:
"battery",
89 VacuumEntityFeature.STATUS:
"status",
90 VacuumEntityFeature.SEND_COMMAND:
"send_command",
91 VacuumEntityFeature.LOCATE:
"locate",
92 VacuumEntityFeature.CLEAN_SPOT:
"clean_spot",
95 STRING_TO_SERVICE = {v: k
for k, v
in SERVICE_TO_STRING.items()}
97 VacuumEntityFeature.START
98 | VacuumEntityFeature.STOP
99 | VacuumEntityFeature.RETURN_HOME
100 | VacuumEntityFeature.BATTERY
101 | VacuumEntityFeature.CLEAN_SPOT
105 | VacuumEntityFeature.PAUSE
106 | VacuumEntityFeature.LOCATE
107 | VacuumEntityFeature.FAN_SPEED
108 | VacuumEntityFeature.SEND_COMMAND
113 services: VacuumEntityFeature,
114 service_to_string: dict[VacuumEntityFeature, str],
116 """Convert SUPPORT_* service bitmask to list of service strings."""
118 service_to_string[service]
119 for service
in service_to_string
120 if service & services
126 _FEATURE_PAYLOADS = {
127 VacuumEntityFeature.START: CONF_PAYLOAD_START,
128 VacuumEntityFeature.STOP: CONF_PAYLOAD_STOP,
129 VacuumEntityFeature.PAUSE: CONF_PAYLOAD_PAUSE,
130 VacuumEntityFeature.CLEAN_SPOT: CONF_PAYLOAD_CLEAN_SPOT,
131 VacuumEntityFeature.LOCATE: CONF_PAYLOAD_LOCATE,
132 VacuumEntityFeature.RETURN_HOME: CONF_PAYLOAD_RETURN_TO_BASE,
135 MQTT_VACUUM_ATTRIBUTES_BLOCKED = frozenset(
137 vacuum.ATTR_BATTERY_ICON,
138 vacuum.ATTR_BATTERY_LEVEL,
139 vacuum.ATTR_FAN_SPEED,
143 MQTT_VACUUM_DOCS_URL =
"https://www.home-assistant.io/integrations/vacuum.mqtt/"
146 PLATFORM_SCHEMA_MODERN = MQTT_BASE_SCHEMA.extend(
148 vol.Optional(CONF_FAN_SPEED_LIST, default=[]): vol.All(
149 cv.ensure_list, [cv.string]
151 vol.Optional(CONF_NAME): vol.Any(cv.string,
None),
153 CONF_PAYLOAD_CLEAN_SPOT, default=DEFAULT_PAYLOAD_CLEAN_SPOT
155 vol.Optional(CONF_PAYLOAD_LOCATE, default=DEFAULT_PAYLOAD_LOCATE): cv.string,
157 CONF_PAYLOAD_RETURN_TO_BASE, default=DEFAULT_PAYLOAD_RETURN_TO_BASE
159 vol.Optional(CONF_PAYLOAD_START, default=DEFAULT_PAYLOAD_START): cv.string,
160 vol.Optional(CONF_PAYLOAD_PAUSE, default=DEFAULT_PAYLOAD_PAUSE): cv.string,
161 vol.Optional(CONF_PAYLOAD_STOP, default=DEFAULT_PAYLOAD_STOP): cv.string,
162 vol.Optional(CONF_SEND_COMMAND_TOPIC): valid_publish_topic,
163 vol.Optional(CONF_SET_FAN_SPEED_TOPIC): valid_publish_topic,
164 vol.Optional(CONF_STATE_TOPIC): valid_publish_topic,
165 vol.Optional(CONF_SUPPORTED_FEATURES, default=DEFAULT_SERVICE_STRINGS): vol.All(
166 cv.ensure_list, [vol.In(STRING_TO_SERVICE.keys())]
168 vol.Optional(CONF_COMMAND_TOPIC): valid_publish_topic,
169 vol.Optional(CONF_RETAIN, default=DEFAULT_RETAIN): cv.boolean,
171 ).extend(MQTT_ENTITY_COMMON_SCHEMA.schema)
173 DISCOVERY_SCHEMA = PLATFORM_SCHEMA_MODERN.extend({}, extra=vol.ALLOW_EXTRA)
178 config_entry: ConfigEntry,
179 async_add_entities: AddEntitiesCallback,
181 """Set up MQTT vacuum through YAML and through MQTT discovery."""
189 PLATFORM_SCHEMA_MODERN,
194 """Representation of a MQTT-controlled state vacuum."""
196 _default_name = DEFAULT_NAME
197 _entity_id_format = ENTITY_ID_FORMAT
198 _attributes_extra_blocked = MQTT_VACUUM_ATTRIBUTES_BLOCKED
200 _command_topic: str |
None
201 _set_fan_speed_topic: str |
None
202 _send_command_topic: str |
None
203 _payloads: dict[str, str |
None]
209 config_entry: ConfigEntry,
210 discovery_data: DiscoveryInfoType |
None,
212 """Initialize the vacuum."""
213 self._state_attrs: dict[str, Any] = {}
215 MqttEntity.__init__(self, hass, config, config_entry, discovery_data)
219 """Return the config schema."""
220 return DISCOVERY_SCHEMA
223 """(Re)Setup the entity."""
225 def _strings_to_services(
226 strings: list[str], string_to_service: dict[str, VacuumEntityFeature]
227 ) -> VacuumEntityFeature:
228 """Convert service strings to SUPPORT_* service bitmask."""
229 services = VacuumEntityFeature.STATE
230 for string
in strings:
231 services |= string_to_service[string]
234 supported_feature_strings: list[str] = config[CONF_SUPPORTED_FEATURES]
236 supported_feature_strings, STRING_TO_SERVICE
249 CONF_PAYLOAD_RETURN_TO_BASE,
250 CONF_PAYLOAD_CLEAN_SPOT,
256 """Update the entity state attributes."""
257 self._state_attrs.
update(payload)
263 """Handle state MQTT message."""
265 if STATE
in payload
and (
266 (state := payload[STATE])
in POSSIBLE_STATES
or state
is None
269 POSSIBLE_STATES[cast(str, state)]
if payload[STATE]
else None
276 """(Re)Subscribe to topics."""
280 {
"_attr_battery_level",
"_attr_fan_speed",
"_attr_state"},
284 """(Re)Subscribe to topics."""
285 subscription.async_subscribe_topics_internal(self.
hasshasshass, self.
_sub_state_sub_state)
288 """Publish a command."""
297 """Start the vacuum."""
301 """Pause the vacuum."""
305 """Stop the vacuum."""
309 """Tell the vacuum to return to its dock."""
313 """Perform a spot clean-up."""
317 """Locate the vacuum (usually by playing a song)."""
333 params: dict[str, Any] | list[Any] |
None =
None,
336 """Send a command to a vacuum cleaner."""
342 if isinstance(params, dict):
343 message: dict[str, Any] = {
"command": command}
344 message.update(params)
None async_publish_with_config(self, str topic, PublishPayloadType payload)
bool add_subscription(self, str state_topic_config_key, Callable[[ReceiveMessage], None] msg_callback, set[str]|None tracked_attributes, bool disable_encoding=False)
None async_clean_spot(self, **Any kwargs)
None async_locate(self, **Any kwargs)
None _update_state_attributes(self, dict[str, Any] payload)
VolSchemaType config_schema()
None _subscribe_topics(self)
None async_send_command(self, str command, dict[str, Any]|list[Any]|None params=None, **Any kwargs)
None _async_publish_command(self, VacuumEntityFeature feature)
None async_stop(self, **Any kwargs)
None async_set_fan_speed(self, str fan_speed, **Any kwargs)
None async_return_to_base(self, **Any kwargs)
None _state_message_received(self, ReceiveMessage msg)
None _setup_from_config(self, ConfigType config)
None _prepare_subscribe_topics(self)
None __init__(self, HomeAssistant hass, ConfigType config, ConfigEntry config_entry, DiscoveryInfoType|None discovery_data)
list[str] fan_speed_list(self)
VacuumEntityFeature supported_features(self)
None async_write_ha_state(self)
int|None supported_features(self)
web.Response get(self, web.Request request, str config_key)
IssData update(pyiss.ISS iss)
None async_setup_entity_entry_helper(HomeAssistant hass, ConfigEntry entry, type[MqttEntity]|None entity_class, str domain, AddEntitiesCallback async_add_entities, VolSchemaType discovery_schema, VolSchemaType platform_schema_modern, dict[str, type[MqttEntity]]|None schema_class_mapping=None)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
list[str] services_to_strings(VacuumEntityFeature services, dict[VacuumEntityFeature, str] service_to_string)
JsonObjectType json_loads_object(bytes|bytearray|memoryview|str obj)