|
12 | 12 | from telegram.error import InvalidToken, TelegramError |
13 | 13 | import voluptuous as vol |
14 | 14 |
|
| 15 | +from homeassistant.components.script import DOMAIN as SCRIPT_DOMAIN |
15 | 16 | from homeassistant.config_entries import SOURCE_IMPORT |
16 | 17 | from homeassistant.const import ( |
| 18 | + ATTR_DOMAIN, |
| 19 | + ATTR_ENTITY_ID, |
17 | 20 | ATTR_LATITUDE, |
18 | 21 | ATTR_LONGITUDE, |
| 22 | + ATTR_SERVICE, |
19 | 23 | CONF_API_KEY, |
20 | 24 | CONF_PLATFORM, |
21 | 25 | CONF_SOURCE, |
|
34 | 38 | HomeAssistantError, |
35 | 39 | ServiceValidationError, |
36 | 40 | ) |
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 |
39 | 43 |
|
40 | 44 | from . import broadcast, polling, webhooks |
41 | 45 | from .bot import TelegramBotConfigEntry, TelegramNotificationService, initialize_bot |
|
165 | 169 | extra=vol.ALLOW_EXTRA, |
166 | 170 | ) |
167 | 171 |
|
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 | + ), |
170 | 177 | ) |
171 | 178 |
|
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 | + ), |
190 | 200 | ) |
191 | 201 |
|
192 | | -SERVICE_SCHEMA_SEND_FILE = BASE_SERVICE_SCHEMA.extend( |
| 202 | +SERVICE_SCHEMA_BASE_SEND_FILE = BASE_SERVICE_SCHEMA.extend( |
193 | 203 | { |
194 | 204 | vol.Optional(ATTR_URL): cv.string, |
195 | 205 | vol.Optional(ATTR_FILE): cv.string, |
|
201 | 211 | } |
202 | 212 | ) |
203 | 213 |
|
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 |
206 | 216 | ) |
207 | 217 |
|
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}), |
213 | 222 | ) |
214 | 223 |
|
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 | + ), |
228 | 232 | ) |
229 | 233 |
|
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 | + ), |
237 | 249 | ) |
238 | 250 |
|
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 | + ), |
266 | 291 | ) |
267 | 292 |
|
268 | 293 | SERVICE_SCHEMA_EDIT_CAPTION = vol.Schema( |
|
274 | 299 | vol.Required(ATTR_CHAT_ID): vol.Coerce(int), |
275 | 300 | vol.Required(ATTR_CAPTION): cv.string, |
276 | 301 | vol.Optional(ATTR_KEYBOARD_INLINE): cv.ensure_list, |
277 | | - }, |
278 | | - extra=vol.ALLOW_EXTRA, |
| 302 | + } |
279 | 303 | ) |
280 | 304 |
|
281 | 305 | SERVICE_SCHEMA_EDIT_REPLYMARKUP = vol.Schema( |
|
286 | 310 | ), |
287 | 311 | vol.Required(ATTR_CHAT_ID): vol.Coerce(int), |
288 | 312 | vol.Required(ATTR_KEYBOARD_INLINE): cv.ensure_list, |
289 | | - }, |
290 | | - extra=vol.ALLOW_EXTRA, |
| 313 | + } |
291 | 314 | ) |
292 | 315 |
|
293 | 316 | SERVICE_SCHEMA_ANSWER_CALLBACK_QUERY = vol.Schema( |
|
296 | 319 | vol.Required(ATTR_MESSAGE): cv.string, |
297 | 320 | vol.Required(ATTR_CALLBACK_QUERY_ID): vol.Coerce(int), |
298 | 321 | vol.Optional(ATTR_SHOW_ALERT): cv.boolean, |
299 | | - }, |
300 | | - extra=vol.ALLOW_EXTRA, |
| 322 | + } |
301 | 323 | ) |
302 | 324 |
|
303 | 325 | SERVICE_SCHEMA_DELETE_MESSAGE = vol.Schema( |
|
307 | 329 | vol.Required(ATTR_MESSAGEID): vol.Any( |
308 | 330 | cv.positive_int, vol.All(cv.string, "last") |
309 | 331 | ), |
310 | | - }, |
311 | | - extra=vol.ALLOW_EXTRA, |
| 332 | + } |
312 | 333 | ) |
313 | 334 |
|
314 | 335 | SERVICE_SCHEMA_LEAVE_CHAT = vol.Schema( |
|
327 | 348 | vol.Required(ATTR_CHAT_ID): vol.Coerce(int), |
328 | 349 | vol.Required(ATTR_REACTION): cv.string, |
329 | 350 | vol.Optional(ATTR_IS_BIG, default=False): cv.boolean, |
330 | | - }, |
331 | | - extra=vol.ALLOW_EXTRA, |
| 351 | + } |
332 | 352 | ) |
333 | 353 |
|
334 | | -SERVICE_MAP = { |
| 354 | +SERVICE_MAP: dict[str, VolSchemaType] = { |
335 | 355 | SERVICE_SEND_MESSAGE: SERVICE_SCHEMA_SEND_MESSAGE, |
336 | 356 | SERVICE_SEND_CHAT_ACTION: SERVICE_SCHEMA_SEND_CHAT_ACTION, |
337 | 357 | SERVICE_SEND_PHOTO: SERVICE_SCHEMA_SEND_FILE, |
@@ -400,6 +420,9 @@ async def async_send_telegram_message(service: ServiceCall) -> ServiceResponse: |
400 | 420 | kwargs = dict(service.data) |
401 | 421 | _LOGGER.debug("New telegram message %s: %s", msgtype, kwargs) |
402 | 422 |
|
| 423 | + if ATTR_TIMEOUT in service.data: |
| 424 | + _deprecate_timeout(hass, service) |
| 425 | + |
403 | 426 | config_entry_id: str | None = service.data.get(CONF_CONFIG_ENTRY_ID) |
404 | 427 | config_entry: TelegramBotConfigEntry | None = None |
405 | 428 | if config_entry_id: |
@@ -532,6 +555,36 @@ async def async_send_telegram_message(service: ServiceCall) -> ServiceResponse: |
532 | 555 | return True |
533 | 556 |
|
534 | 557 |
|
| 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 | + |
535 | 588 | async def async_setup_entry(hass: HomeAssistant, entry: TelegramBotConfigEntry) -> bool: |
536 | 589 | """Create the Telegram bot from config entry.""" |
537 | 590 | bot: Bot = await hass.async_add_executor_job(initialize_bot, hass, entry.data) |
|
0 commit comments