Skip to content

Commit 6803609

Browse files
Remove timeout parameter for Telegram bot actions (home-assistant#155198)
Co-authored-by: Martin Hjelmare <[email protected]>
1 parent 180053f commit 6803609

File tree

5 files changed

+262
-204
lines changed

5 files changed

+262
-204
lines changed

homeassistant/components/telegram_bot/__init__.py

Lines changed: 141 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@
1212
from telegram.error import InvalidToken, TelegramError
1313
import voluptuous as vol
1414

15+
from homeassistant.components.script import DOMAIN as SCRIPT_DOMAIN
1516
from homeassistant.config_entries import SOURCE_IMPORT
1617
from homeassistant.const import (
18+
ATTR_DOMAIN,
19+
ATTR_ENTITY_ID,
1720
ATTR_LATITUDE,
1821
ATTR_LONGITUDE,
22+
ATTR_SERVICE,
1923
CONF_API_KEY,
2024
CONF_PLATFORM,
2125
CONF_SOURCE,
@@ -34,8 +38,8 @@
3438
HomeAssistantError,
3539
ServiceValidationError,
3640
)
37-
from homeassistant.helpers import config_validation as cv
38-
from homeassistant.helpers.typing import ConfigType
41+
from homeassistant.helpers import config_validation as cv, issue_registry as ir
42+
from homeassistant.helpers.typing import ConfigType, VolSchemaType
3943

4044
from . import broadcast, polling, webhooks
4145
from .bot import TelegramBotConfigEntry, TelegramNotificationService, initialize_bot
@@ -165,31 +169,37 @@
165169
extra=vol.ALLOW_EXTRA,
166170
)
167171

168-
SERVICE_SCHEMA_SEND_MESSAGE = BASE_SERVICE_SCHEMA.extend(
169-
{vol.Required(ATTR_MESSAGE): cv.string, vol.Optional(ATTR_TITLE): cv.string}
172+
SERVICE_SCHEMA_SEND_MESSAGE = vol.All(
173+
cv.deprecated(ATTR_TIMEOUT),
174+
BASE_SERVICE_SCHEMA.extend(
175+
{vol.Required(ATTR_MESSAGE): cv.string, vol.Optional(ATTR_TITLE): cv.string}
176+
),
170177
)
171178

172-
SERVICE_SCHEMA_SEND_CHAT_ACTION = BASE_SERVICE_SCHEMA.extend(
173-
{
174-
vol.Required(ATTR_CHAT_ACTION): vol.In(
175-
(
176-
CHAT_ACTION_TYPING,
177-
CHAT_ACTION_UPLOAD_PHOTO,
178-
CHAT_ACTION_RECORD_VIDEO,
179-
CHAT_ACTION_UPLOAD_VIDEO,
180-
CHAT_ACTION_RECORD_VOICE,
181-
CHAT_ACTION_UPLOAD_VOICE,
182-
CHAT_ACTION_UPLOAD_DOCUMENT,
183-
CHAT_ACTION_CHOOSE_STICKER,
184-
CHAT_ACTION_FIND_LOCATION,
185-
CHAT_ACTION_RECORD_VIDEO_NOTE,
186-
CHAT_ACTION_UPLOAD_VIDEO_NOTE,
187-
)
188-
),
189-
}
179+
SERVICE_SCHEMA_SEND_CHAT_ACTION = vol.All(
180+
cv.deprecated(ATTR_TIMEOUT),
181+
BASE_SERVICE_SCHEMA.extend(
182+
{
183+
vol.Required(ATTR_CHAT_ACTION): vol.In(
184+
(
185+
CHAT_ACTION_TYPING,
186+
CHAT_ACTION_UPLOAD_PHOTO,
187+
CHAT_ACTION_RECORD_VIDEO,
188+
CHAT_ACTION_UPLOAD_VIDEO,
189+
CHAT_ACTION_RECORD_VOICE,
190+
CHAT_ACTION_UPLOAD_VOICE,
191+
CHAT_ACTION_UPLOAD_DOCUMENT,
192+
CHAT_ACTION_CHOOSE_STICKER,
193+
CHAT_ACTION_FIND_LOCATION,
194+
CHAT_ACTION_RECORD_VIDEO_NOTE,
195+
CHAT_ACTION_UPLOAD_VIDEO_NOTE,
196+
)
197+
),
198+
}
199+
),
190200
)
191201

192-
SERVICE_SCHEMA_SEND_FILE = BASE_SERVICE_SCHEMA.extend(
202+
SERVICE_SCHEMA_BASE_SEND_FILE = BASE_SERVICE_SCHEMA.extend(
193203
{
194204
vol.Optional(ATTR_URL): cv.string,
195205
vol.Optional(ATTR_FILE): cv.string,
@@ -201,68 +211,83 @@
201211
}
202212
)
203213

204-
SERVICE_SCHEMA_SEND_STICKER = SERVICE_SCHEMA_SEND_FILE.extend(
205-
{vol.Optional(ATTR_STICKER_ID): cv.string}
214+
SERVICE_SCHEMA_SEND_FILE = vol.All(
215+
cv.deprecated(ATTR_TIMEOUT), SERVICE_SCHEMA_BASE_SEND_FILE
206216
)
207217

208-
SERVICE_SCHEMA_SEND_LOCATION = BASE_SERVICE_SCHEMA.extend(
209-
{
210-
vol.Required(ATTR_LONGITUDE): cv.string,
211-
vol.Required(ATTR_LATITUDE): cv.string,
212-
}
218+
219+
SERVICE_SCHEMA_SEND_STICKER = vol.All(
220+
cv.deprecated(ATTR_TIMEOUT),
221+
SERVICE_SCHEMA_BASE_SEND_FILE.extend({vol.Optional(ATTR_STICKER_ID): cv.string}),
213222
)
214223

215-
SERVICE_SCHEMA_SEND_POLL = vol.Schema(
216-
{
217-
vol.Optional(CONF_CONFIG_ENTRY_ID): cv.string,
218-
vol.Optional(ATTR_TARGET): vol.All(cv.ensure_list, [vol.Coerce(int)]),
219-
vol.Required(ATTR_QUESTION): cv.string,
220-
vol.Required(ATTR_OPTIONS): vol.All(cv.ensure_list, [cv.string]),
221-
vol.Optional(ATTR_OPEN_PERIOD): cv.positive_int,
222-
vol.Optional(ATTR_IS_ANONYMOUS, default=True): cv.boolean,
223-
vol.Optional(ATTR_ALLOWS_MULTIPLE_ANSWERS, default=False): cv.boolean,
224-
vol.Optional(ATTR_DISABLE_NOTIF): cv.boolean,
225-
vol.Optional(ATTR_TIMEOUT): cv.positive_int,
226-
vol.Optional(ATTR_MESSAGE_THREAD_ID): vol.Coerce(int),
227-
}
224+
SERVICE_SCHEMA_SEND_LOCATION = vol.All(
225+
cv.deprecated(ATTR_TIMEOUT),
226+
BASE_SERVICE_SCHEMA.extend(
227+
{
228+
vol.Required(ATTR_LONGITUDE): cv.string,
229+
vol.Required(ATTR_LATITUDE): cv.string,
230+
}
231+
),
228232
)
229233

230-
SERVICE_SCHEMA_EDIT_MESSAGE = SERVICE_SCHEMA_SEND_MESSAGE.extend(
231-
{
232-
vol.Required(ATTR_MESSAGEID): vol.Any(
233-
cv.positive_int, vol.All(cv.string, "last")
234-
),
235-
vol.Required(ATTR_CHAT_ID): vol.Coerce(int),
236-
}
234+
SERVICE_SCHEMA_SEND_POLL = vol.All(
235+
cv.deprecated(ATTR_TIMEOUT),
236+
vol.Schema(
237+
{
238+
vol.Optional(CONF_CONFIG_ENTRY_ID): cv.string,
239+
vol.Optional(ATTR_TARGET): vol.All(cv.ensure_list, [vol.Coerce(int)]),
240+
vol.Required(ATTR_QUESTION): cv.string,
241+
vol.Required(ATTR_OPTIONS): vol.All(cv.ensure_list, [cv.string]),
242+
vol.Optional(ATTR_OPEN_PERIOD): cv.positive_int,
243+
vol.Optional(ATTR_IS_ANONYMOUS, default=True): cv.boolean,
244+
vol.Optional(ATTR_ALLOWS_MULTIPLE_ANSWERS, default=False): cv.boolean,
245+
vol.Optional(ATTR_DISABLE_NOTIF): cv.boolean,
246+
vol.Optional(ATTR_MESSAGE_THREAD_ID): vol.Coerce(int),
247+
}
248+
),
237249
)
238250

239-
SERVICE_SCHEMA_EDIT_MESSAGE_MEDIA = vol.Schema(
240-
{
241-
vol.Optional(CONF_CONFIG_ENTRY_ID): cv.string,
242-
vol.Required(ATTR_MESSAGEID): vol.Any(
243-
cv.positive_int, vol.All(cv.string, "last")
244-
),
245-
vol.Required(ATTR_CHAT_ID): vol.Coerce(int),
246-
vol.Optional(ATTR_TIMEOUT): cv.positive_int,
247-
vol.Optional(ATTR_CAPTION): cv.string,
248-
vol.Required(ATTR_MEDIA_TYPE): vol.In(
249-
(
250-
str(InputMediaType.ANIMATION),
251-
str(InputMediaType.AUDIO),
252-
str(InputMediaType.VIDEO),
253-
str(InputMediaType.DOCUMENT),
254-
str(InputMediaType.PHOTO),
255-
)
256-
),
257-
vol.Optional(ATTR_URL): cv.string,
258-
vol.Optional(ATTR_FILE): cv.string,
259-
vol.Optional(ATTR_USERNAME): cv.string,
260-
vol.Optional(ATTR_PASSWORD): cv.string,
261-
vol.Optional(ATTR_AUTHENTICATION): cv.string,
262-
vol.Optional(ATTR_VERIFY_SSL): cv.boolean,
263-
vol.Optional(ATTR_KEYBOARD_INLINE): cv.ensure_list,
264-
},
265-
extra=vol.ALLOW_EXTRA,
251+
SERVICE_SCHEMA_EDIT_MESSAGE = vol.All(
252+
cv.deprecated(ATTR_TIMEOUT),
253+
SERVICE_SCHEMA_BASE_SEND_FILE.extend(
254+
{
255+
vol.Required(ATTR_MESSAGEID): vol.Any(
256+
cv.positive_int, vol.All(cv.string, "last")
257+
),
258+
vol.Required(ATTR_CHAT_ID): vol.Coerce(int),
259+
}
260+
),
261+
)
262+
263+
SERVICE_SCHEMA_EDIT_MESSAGE_MEDIA = vol.All(
264+
cv.deprecated(ATTR_TIMEOUT),
265+
vol.Schema(
266+
{
267+
vol.Optional(CONF_CONFIG_ENTRY_ID): cv.string,
268+
vol.Required(ATTR_MESSAGEID): vol.Any(
269+
cv.positive_int, vol.All(cv.string, "last")
270+
),
271+
vol.Required(ATTR_CHAT_ID): vol.Coerce(int),
272+
vol.Optional(ATTR_CAPTION): cv.string,
273+
vol.Required(ATTR_MEDIA_TYPE): vol.In(
274+
(
275+
str(InputMediaType.ANIMATION),
276+
str(InputMediaType.AUDIO),
277+
str(InputMediaType.VIDEO),
278+
str(InputMediaType.DOCUMENT),
279+
str(InputMediaType.PHOTO),
280+
)
281+
),
282+
vol.Optional(ATTR_URL): cv.string,
283+
vol.Optional(ATTR_FILE): cv.string,
284+
vol.Optional(ATTR_USERNAME): cv.string,
285+
vol.Optional(ATTR_PASSWORD): cv.string,
286+
vol.Optional(ATTR_AUTHENTICATION): cv.string,
287+
vol.Optional(ATTR_VERIFY_SSL): cv.boolean,
288+
vol.Optional(ATTR_KEYBOARD_INLINE): cv.ensure_list,
289+
}
290+
),
266291
)
267292

268293
SERVICE_SCHEMA_EDIT_CAPTION = vol.Schema(
@@ -274,8 +299,7 @@
274299
vol.Required(ATTR_CHAT_ID): vol.Coerce(int),
275300
vol.Required(ATTR_CAPTION): cv.string,
276301
vol.Optional(ATTR_KEYBOARD_INLINE): cv.ensure_list,
277-
},
278-
extra=vol.ALLOW_EXTRA,
302+
}
279303
)
280304

281305
SERVICE_SCHEMA_EDIT_REPLYMARKUP = vol.Schema(
@@ -286,8 +310,7 @@
286310
),
287311
vol.Required(ATTR_CHAT_ID): vol.Coerce(int),
288312
vol.Required(ATTR_KEYBOARD_INLINE): cv.ensure_list,
289-
},
290-
extra=vol.ALLOW_EXTRA,
313+
}
291314
)
292315

293316
SERVICE_SCHEMA_ANSWER_CALLBACK_QUERY = vol.Schema(
@@ -296,8 +319,7 @@
296319
vol.Required(ATTR_MESSAGE): cv.string,
297320
vol.Required(ATTR_CALLBACK_QUERY_ID): vol.Coerce(int),
298321
vol.Optional(ATTR_SHOW_ALERT): cv.boolean,
299-
},
300-
extra=vol.ALLOW_EXTRA,
322+
}
301323
)
302324

303325
SERVICE_SCHEMA_DELETE_MESSAGE = vol.Schema(
@@ -307,8 +329,7 @@
307329
vol.Required(ATTR_MESSAGEID): vol.Any(
308330
cv.positive_int, vol.All(cv.string, "last")
309331
),
310-
},
311-
extra=vol.ALLOW_EXTRA,
332+
}
312333
)
313334

314335
SERVICE_SCHEMA_LEAVE_CHAT = vol.Schema(
@@ -327,11 +348,10 @@
327348
vol.Required(ATTR_CHAT_ID): vol.Coerce(int),
328349
vol.Required(ATTR_REACTION): cv.string,
329350
vol.Optional(ATTR_IS_BIG, default=False): cv.boolean,
330-
},
331-
extra=vol.ALLOW_EXTRA,
351+
}
332352
)
333353

334-
SERVICE_MAP = {
354+
SERVICE_MAP: dict[str, VolSchemaType] = {
335355
SERVICE_SEND_MESSAGE: SERVICE_SCHEMA_SEND_MESSAGE,
336356
SERVICE_SEND_CHAT_ACTION: SERVICE_SCHEMA_SEND_CHAT_ACTION,
337357
SERVICE_SEND_PHOTO: SERVICE_SCHEMA_SEND_FILE,
@@ -400,6 +420,9 @@ async def async_send_telegram_message(service: ServiceCall) -> ServiceResponse:
400420
kwargs = dict(service.data)
401421
_LOGGER.debug("New telegram message %s: %s", msgtype, kwargs)
402422

423+
if ATTR_TIMEOUT in service.data:
424+
_deprecate_timeout(hass, service)
425+
403426
config_entry_id: str | None = service.data.get(CONF_CONFIG_ENTRY_ID)
404427
config_entry: TelegramBotConfigEntry | None = None
405428
if config_entry_id:
@@ -532,6 +555,36 @@ async def async_send_telegram_message(service: ServiceCall) -> ServiceResponse:
532555
return True
533556

534557

558+
def _deprecate_timeout(hass: HomeAssistant, service: ServiceCall) -> None:
559+
# default: service was called using frontend such as developer tools or automation editor
560+
service_call_origin = "call_service"
561+
562+
origin = service.context.origin_event
563+
if origin and ATTR_ENTITY_ID in origin.data:
564+
# automation
565+
service_call_origin = origin.data[ATTR_ENTITY_ID]
566+
elif origin and origin.data.get(ATTR_DOMAIN) == SCRIPT_DOMAIN:
567+
# script
568+
service_call_origin = f"{origin.data[ATTR_DOMAIN]}.{origin.data[ATTR_SERVICE]}"
569+
570+
ir.async_create_issue(
571+
hass,
572+
DOMAIN,
573+
"deprecated_timeout_parameter",
574+
breaks_in_ha_version="2026.7.0",
575+
is_fixable=True,
576+
is_persistent=True,
577+
severity=ir.IssueSeverity.WARNING,
578+
translation_key="deprecated_timeout_parameter",
579+
translation_placeholders={
580+
"integration_title": "Telegram Bot",
581+
"action": f"{DOMAIN}.{service.service}",
582+
"action_origin": service_call_origin,
583+
},
584+
learn_more_url="https://github.com/home-assistant/core/pull/155198",
585+
)
586+
587+
535588
async def async_setup_entry(hass: HomeAssistant, entry: TelegramBotConfigEntry) -> bool:
536589
"""Create the Telegram bot from config entry."""
537590
bot: Bot = await hass.async_add_executor_job(initialize_bot, hass, entry.data)

homeassistant/components/telegram_bot/bot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ def _make_row_inline_keyboard(row_keyboard: Any) -> list[InlineKeyboardButton]:
448448
params[ATTR_MESSAGE_THREAD_ID] = data[ATTR_MESSAGE_THREAD_ID]
449449
# Keyboards:
450450
if ATTR_KEYBOARD in data:
451-
keys = data.get(ATTR_KEYBOARD)
451+
keys = data[ATTR_KEYBOARD]
452452
keys = keys if isinstance(keys, list) else [keys]
453453
if keys:
454454
params[ATTR_REPLYMARKUP] = ReplyKeyboardMarkup(

0 commit comments

Comments
 (0)