homeassistant 2025.7.0b0__py3-none-any.whl → 2025.7.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (312) hide show
  1. homeassistant/components/aemet/sensor.py +1 -1
  2. homeassistant/components/airq/coordinator.py +2 -2
  3. homeassistant/components/alexa_devices/__init__.py +5 -2
  4. homeassistant/components/alexa_devices/notify.py +2 -0
  5. homeassistant/components/alexa_devices/quality_scale.yaml +1 -1
  6. homeassistant/components/alexa_devices/strings.json +11 -4
  7. homeassistant/components/alexa_devices/switch.py +2 -0
  8. homeassistant/components/alexa_devices/translations/bg.json +6 -4
  9. homeassistant/components/alexa_devices/translations/cs.json +12 -5
  10. homeassistant/components/alexa_devices/translations/de.json +14 -7
  11. homeassistant/components/alexa_devices/translations/el.json +12 -5
  12. homeassistant/components/alexa_devices/translations/en.json +12 -5
  13. homeassistant/components/alexa_devices/translations/es.json +12 -5
  14. homeassistant/components/alexa_devices/translations/et.json +12 -5
  15. homeassistant/components/alexa_devices/translations/ga.json +0 -6
  16. homeassistant/components/alexa_devices/translations/he.json +0 -4
  17. homeassistant/components/alexa_devices/translations/hu.json +0 -4
  18. homeassistant/components/alexa_devices/translations/id.json +1 -0
  19. homeassistant/components/alexa_devices/translations/lt.json +0 -4
  20. homeassistant/components/alexa_devices/translations/mk.json +12 -0
  21. homeassistant/components/alexa_devices/translations/nl.json +0 -4
  22. homeassistant/components/alexa_devices/translations/pl.json +0 -4
  23. homeassistant/components/alexa_devices/translations/pt.json +0 -4
  24. homeassistant/components/alexa_devices/translations/ru.json +4 -5
  25. homeassistant/components/alexa_devices/translations/sk.json +12 -5
  26. homeassistant/components/alexa_devices/translations/sv.json +17 -5
  27. homeassistant/components/alexa_devices/translations/tr.json +0 -4
  28. homeassistant/components/alexa_devices/translations/zh-Hans.json +27 -5
  29. homeassistant/components/alexa_devices/translations/zh-Hant.json +12 -5
  30. homeassistant/components/alexa_devices/utils.py +40 -0
  31. homeassistant/components/altruist/translations/id.json +11 -0
  32. homeassistant/components/anthropic/__init__.py +14 -1
  33. homeassistant/components/anthropic/translations/bg.json +21 -0
  34. homeassistant/components/anthropic/translations/ga.json +32 -1
  35. homeassistant/components/anthropic/translations/id.json +19 -0
  36. homeassistant/components/anthropic/translations/ru.json +30 -0
  37. homeassistant/components/backup/translations/de.json +1 -1
  38. homeassistant/components/buienradar/sensor.py +0 -1
  39. homeassistant/components/cambridge_audio/translations/sv.json +1 -1
  40. homeassistant/components/comelit/translations/de.json +1 -1
  41. homeassistant/components/counter/translations/sv.json +2 -2
  42. homeassistant/components/demo/translations/select.sv.json +2 -2
  43. homeassistant/components/derivative/translations/ga.json +20 -0
  44. homeassistant/components/derivative/translations/ru.json +3 -0
  45. homeassistant/components/devolo_home_control/translations/bg.json +6 -0
  46. homeassistant/components/devolo_home_control/translations/id.json +5 -0
  47. homeassistant/components/devolo_home_control/translations/sv.json +10 -0
  48. homeassistant/components/devolo_home_control/translations/zh-Hans.json +10 -0
  49. homeassistant/components/dlink/manifest.json +1 -1
  50. homeassistant/components/ecovacs/translations/sv.json +1 -1
  51. homeassistant/components/enphase_envoy/translations/sv.json +5 -2
  52. homeassistant/components/ezviz/translations/bg.json +6 -0
  53. homeassistant/components/ezviz/translations/mk.json +13 -0
  54. homeassistant/components/ezviz/translations/sv.json +10 -0
  55. homeassistant/components/ezviz/translations/zh-Hans.json +10 -0
  56. homeassistant/components/fronius/translations/sv.json +2 -2
  57. homeassistant/components/frontend/manifest.json +1 -1
  58. homeassistant/components/goodwe/translations/sv.json +5 -5
  59. homeassistant/components/google_generative_ai_conversation/__init__.py +21 -0
  60. homeassistant/components/google_generative_ai_conversation/config_flow.py +72 -36
  61. homeassistant/components/google_generative_ai_conversation/const.py +15 -2
  62. homeassistant/components/google_generative_ai_conversation/diagnostics.py +1 -0
  63. homeassistant/components/google_generative_ai_conversation/entity.py +7 -2
  64. homeassistant/components/google_generative_ai_conversation/helpers.py +73 -0
  65. homeassistant/components/google_generative_ai_conversation/strings.json +28 -1
  66. homeassistant/components/google_generative_ai_conversation/translations/bg.json +19 -0
  67. homeassistant/components/google_generative_ai_conversation/translations/cs.json +28 -0
  68. homeassistant/components/google_generative_ai_conversation/translations/de.json +28 -0
  69. homeassistant/components/google_generative_ai_conversation/translations/el.json +28 -0
  70. homeassistant/components/google_generative_ai_conversation/translations/en.json +28 -0
  71. homeassistant/components/google_generative_ai_conversation/translations/es.json +28 -0
  72. homeassistant/components/google_generative_ai_conversation/translations/et.json +28 -0
  73. homeassistant/components/google_generative_ai_conversation/translations/ga.json +9 -0
  74. homeassistant/components/google_generative_ai_conversation/translations/id.json +30 -0
  75. homeassistant/components/google_generative_ai_conversation/translations/mk.json +11 -0
  76. homeassistant/components/google_generative_ai_conversation/translations/ru.json +67 -0
  77. homeassistant/components/google_generative_ai_conversation/translations/sk.json +28 -0
  78. homeassistant/components/google_generative_ai_conversation/translations/sv.json +23 -0
  79. homeassistant/components/google_generative_ai_conversation/translations/zh-Hans.json +28 -0
  80. homeassistant/components/google_generative_ai_conversation/translations/zh-Hant.json +28 -0
  81. homeassistant/components/google_generative_ai_conversation/tts.py +48 -106
  82. homeassistant/components/group/translations/el.json +18 -18
  83. homeassistant/components/habitica/const.py +1 -1
  84. homeassistant/components/harmony/translations/select.sv.json +1 -1
  85. homeassistant/components/harmony/translations/sv.json +1 -1
  86. homeassistant/components/homeassistant_hardware/firmware_config_flow.py +89 -7
  87. homeassistant/components/homeassistant_hardware/strings.json +2 -1
  88. homeassistant/components/homeassistant_hardware/translations/de.json +1 -0
  89. homeassistant/components/homeassistant_hardware/translations/en-GB.json +1 -0
  90. homeassistant/components/homeassistant_hardware/translations/en.json +1 -0
  91. homeassistant/components/homeassistant_hardware/translations/ga.json +9 -0
  92. homeassistant/components/homeassistant_hardware/translations/mk.json +9 -0
  93. homeassistant/components/homeassistant_sky_connect/config_flow.py +1 -1
  94. homeassistant/components/homeassistant_sky_connect/strings.json +4 -2
  95. homeassistant/components/homeassistant_sky_connect/translations/de.json +2 -0
  96. homeassistant/components/homeassistant_sky_connect/translations/en-GB.json +2 -0
  97. homeassistant/components/homeassistant_sky_connect/translations/en.json +2 -0
  98. homeassistant/components/homeassistant_sky_connect/translations/ga.json +10 -0
  99. homeassistant/components/homeassistant_sky_connect/translations/mk.json +7 -0
  100. homeassistant/components/homeassistant_yellow/strings.json +2 -1
  101. homeassistant/components/homeassistant_yellow/translations/bg.json +0 -1
  102. homeassistant/components/homeassistant_yellow/translations/cs.json +0 -1
  103. homeassistant/components/homeassistant_yellow/translations/de.json +1 -0
  104. homeassistant/components/homeassistant_yellow/translations/el.json +0 -1
  105. homeassistant/components/homeassistant_yellow/translations/en-GB.json +2 -1
  106. homeassistant/components/homeassistant_yellow/translations/en.json +2 -1
  107. homeassistant/components/homeassistant_yellow/translations/es.json +0 -1
  108. homeassistant/components/homeassistant_yellow/translations/et.json +0 -1
  109. homeassistant/components/homeassistant_yellow/translations/fr.json +0 -1
  110. homeassistant/components/homeassistant_yellow/translations/ga.json +5 -0
  111. homeassistant/components/homeassistant_yellow/translations/he.json +0 -1
  112. homeassistant/components/homeassistant_yellow/translations/hu.json +0 -1
  113. homeassistant/components/homeassistant_yellow/translations/id.json +0 -1
  114. homeassistant/components/homeassistant_yellow/translations/it.json +0 -1
  115. homeassistant/components/homeassistant_yellow/translations/ja.json +0 -1
  116. homeassistant/components/homeassistant_yellow/translations/lt.json +0 -1
  117. homeassistant/components/homeassistant_yellow/translations/pt.json +0 -1
  118. homeassistant/components/homeassistant_yellow/translations/ru.json +0 -1
  119. homeassistant/components/homeassistant_yellow/translations/sk.json +0 -1
  120. homeassistant/components/homeassistant_yellow/translations/sv.json +0 -1
  121. homeassistant/components/homeassistant_yellow/translations/tr.json +0 -1
  122. homeassistant/components/homeassistant_yellow/translations/zh-Hans.json +0 -1
  123. homeassistant/components/homeassistant_yellow/translations/zh-Hant.json +0 -1
  124. homeassistant/components/homewizard/translations/sv.json +3 -1
  125. homeassistant/components/http/auth.py +1 -1
  126. homeassistant/components/image/__init__.py +34 -3
  127. homeassistant/components/input_number/translations/sv.json +2 -2
  128. homeassistant/components/input_select/translations/sv.json +6 -6
  129. homeassistant/components/input_text/translations/sv.json +1 -1
  130. homeassistant/components/iron_os/manifest.json +1 -1
  131. homeassistant/components/iron_os/translations/sv.json +1 -1
  132. homeassistant/components/keenetic_ndms2/translations/id.json +3 -0
  133. homeassistant/components/lamarzocco/entity.py +19 -1
  134. homeassistant/components/lamarzocco/number.py +0 -4
  135. homeassistant/components/lamarzocco/sensor.py +2 -4
  136. homeassistant/components/lamarzocco/translations/sv.json +3 -3
  137. homeassistant/components/lametric/translations/sv.json +2 -2
  138. homeassistant/components/lametric/update.py +1 -1
  139. homeassistant/components/lg_thinq/translations/sv.json +5 -5
  140. homeassistant/components/litterrobot/translations/bg.json +4 -0
  141. homeassistant/components/litterrobot/translations/ga.json +3 -0
  142. homeassistant/components/matter/translations/id.json +5 -0
  143. homeassistant/components/matter/vacuum.py +38 -26
  144. homeassistant/components/meater/__init__.py +5 -1
  145. homeassistant/components/meater/coordinator.py +4 -2
  146. homeassistant/components/media_source/local_source.py +21 -4
  147. homeassistant/components/minecraft_server/translations/sv.json +1 -1
  148. homeassistant/components/motioneye/translations/sv.json +1 -1
  149. homeassistant/components/mqtt/translations/bg.json +10 -0
  150. homeassistant/components/mqtt/translations/cs.json +19 -0
  151. homeassistant/components/mqtt/translations/el.json +21 -0
  152. homeassistant/components/mqtt/translations/fi.json +3 -0
  153. homeassistant/components/mqtt/translations/ga.json +25 -0
  154. homeassistant/components/mqtt/translations/mk.json +23 -0
  155. homeassistant/components/mqtt/translations/ru.json +1 -0
  156. homeassistant/components/mqtt/translations/sv.json +24 -0
  157. homeassistant/components/mqtt/translations/zh-Hans.json +26 -0
  158. homeassistant/components/mqtt/translations/zh-Hant.json +19 -0
  159. homeassistant/components/music_assistant/button.py +0 -6
  160. homeassistant/components/ntfy/translations/id.json +13 -0
  161. homeassistant/components/ntfy/translations/sv.json +1 -0
  162. homeassistant/components/number/translations/sv.json +2 -2
  163. homeassistant/components/nut/config_flow.py +4 -2
  164. homeassistant/components/ohme/translations/sv.json +1 -1
  165. homeassistant/components/ollama/__init__.py +8 -0
  166. homeassistant/components/ollama/const.py +2 -0
  167. homeassistant/components/ollama/translations/bg.json +19 -0
  168. homeassistant/components/ollama/translations/ga.json +31 -1
  169. homeassistant/components/ollama/translations/id.json +18 -0
  170. homeassistant/components/ollama/translations/mk.json +13 -1
  171. homeassistant/components/ollama/translations/sv.json +1 -0
  172. homeassistant/components/onewire/translations/sv.json +4 -4
  173. homeassistant/components/openai_conversation/__init__.py +8 -0
  174. homeassistant/components/openai_conversation/const.py +1 -1
  175. homeassistant/components/openai_conversation/conversation.py +1 -1
  176. homeassistant/components/openai_conversation/translations/bg.json +26 -0
  177. homeassistant/components/openai_conversation/translations/id.json +23 -0
  178. homeassistant/components/openai_conversation/translations/mk.json +44 -0
  179. homeassistant/components/openai_conversation/translations/sv.json +4 -0
  180. homeassistant/components/playstation_network/diagnostics.py +55 -0
  181. homeassistant/components/playstation_network/quality_scale.yaml +1 -1
  182. homeassistant/components/playstation_network/translations/bg.json +25 -1
  183. homeassistant/components/playstation_network/translations/es.json +1 -1
  184. homeassistant/components/playstation_network/translations/ga.json +31 -0
  185. homeassistant/components/playstation_network/translations/id.json +14 -0
  186. homeassistant/components/playstation_network/translations/mk.json +18 -0
  187. homeassistant/components/playstation_network/translations/pl.json +73 -0
  188. homeassistant/components/playstation_network/translations/sv.json +29 -0
  189. homeassistant/components/playstation_network/translations/zh-Hans.json +29 -0
  190. homeassistant/components/plugwise/translations/sv.json +2 -2
  191. homeassistant/components/qnap/translations/sv.json +1 -1
  192. homeassistant/components/random/translations/sv.json +4 -4
  193. homeassistant/components/remote_calendar/translations/fi.json +34 -0
  194. homeassistant/components/select/translations/sv.json +10 -10
  195. homeassistant/components/smarla/__init__.py +2 -2
  196. homeassistant/components/sonos/translations/bg.json +5 -0
  197. homeassistant/components/sonos/translations/cs.json +6 -0
  198. homeassistant/components/sonos/translations/el.json +6 -0
  199. homeassistant/components/sonos/translations/ga.json +8 -0
  200. homeassistant/components/sonos/translations/mk.json +10 -0
  201. homeassistant/components/sonos/translations/ru.json +6 -0
  202. homeassistant/components/sonos/translations/sv.json +6 -0
  203. homeassistant/components/sonos/translations/zh-Hans.json +9 -0
  204. homeassistant/components/sonos/translations/zh-Hant.json +6 -0
  205. homeassistant/components/subaru/strings.json +2 -2
  206. homeassistant/components/subaru/translations/ca.json +0 -1
  207. homeassistant/components/subaru/translations/cs.json +0 -2
  208. homeassistant/components/subaru/translations/de.json +2 -2
  209. homeassistant/components/subaru/translations/el.json +0 -2
  210. homeassistant/components/subaru/translations/en-GB.json +0 -2
  211. homeassistant/components/subaru/translations/en.json +2 -2
  212. homeassistant/components/subaru/translations/es.json +0 -2
  213. homeassistant/components/subaru/translations/et.json +0 -2
  214. homeassistant/components/subaru/translations/fi.json +0 -1
  215. homeassistant/components/subaru/translations/hu.json +0 -2
  216. homeassistant/components/subaru/translations/it.json +0 -1
  217. homeassistant/components/subaru/translations/ja.json +0 -1
  218. homeassistant/components/subaru/translations/ko.json +0 -1
  219. homeassistant/components/subaru/translations/lt.json +0 -2
  220. homeassistant/components/subaru/translations/pt-BR.json +0 -1
  221. homeassistant/components/subaru/translations/pt.json +0 -2
  222. homeassistant/components/subaru/translations/ru.json +0 -2
  223. homeassistant/components/subaru/translations/sk.json +0 -2
  224. homeassistant/components/subaru/translations/sv.json +0 -2
  225. homeassistant/components/subaru/translations/tr.json +0 -2
  226. homeassistant/components/subaru/translations/zh-Hans.json +0 -2
  227. homeassistant/components/subaru/translations/zh-Hant.json +0 -2
  228. homeassistant/components/switchbot/translations/bg.json +26 -0
  229. homeassistant/components/switchbot/translations/ga.json +33 -0
  230. homeassistant/components/switchbot/translations/id.json +19 -0
  231. homeassistant/components/switchbot/translations/mk.json +49 -0
  232. homeassistant/components/switchbot/translations/sv.json +54 -0
  233. homeassistant/components/switchbot/translations/zh-Hans.json +53 -0
  234. homeassistant/components/telegram_bot/__init__.py +20 -4
  235. homeassistant/components/telegram_bot/bot.py +33 -29
  236. homeassistant/components/telegram_bot/config_flow.py +66 -20
  237. homeassistant/components/telegram_bot/const.py +1 -1
  238. homeassistant/components/telegram_bot/strings.json +33 -10
  239. homeassistant/components/telegram_bot/translations/bg.json +0 -1
  240. homeassistant/components/telegram_bot/translations/cs.json +35 -12
  241. homeassistant/components/telegram_bot/translations/de.json +35 -12
  242. homeassistant/components/telegram_bot/translations/el.json +35 -12
  243. homeassistant/components/telegram_bot/translations/en-GB.json +6 -11
  244. homeassistant/components/telegram_bot/translations/en.json +35 -12
  245. homeassistant/components/telegram_bot/translations/es.json +35 -12
  246. homeassistant/components/telegram_bot/translations/et.json +34 -11
  247. homeassistant/components/telegram_bot/translations/fr.json +5 -12
  248. homeassistant/components/telegram_bot/translations/ga.json +5 -11
  249. homeassistant/components/telegram_bot/translations/he.json +3 -8
  250. homeassistant/components/telegram_bot/translations/hu.json +5 -12
  251. homeassistant/components/telegram_bot/translations/id.json +0 -5
  252. homeassistant/components/telegram_bot/translations/it.json +2 -5
  253. homeassistant/components/telegram_bot/translations/lt.json +5 -12
  254. homeassistant/components/telegram_bot/translations/mk.json +7 -5
  255. homeassistant/components/telegram_bot/translations/nl.json +5 -12
  256. homeassistant/components/telegram_bot/translations/pt.json +5 -12
  257. homeassistant/components/telegram_bot/translations/ru.json +12 -11
  258. homeassistant/components/telegram_bot/translations/sk.json +35 -12
  259. homeassistant/components/telegram_bot/translations/sv.json +28 -12
  260. homeassistant/components/telegram_bot/translations/tr.json +5 -12
  261. homeassistant/components/telegram_bot/translations/zh-Hans.json +35 -12
  262. homeassistant/components/telegram_bot/translations/zh-Hant.json +35 -12
  263. homeassistant/components/template/translations/sv.json +5 -5
  264. homeassistant/components/text/translations/sv.json +1 -1
  265. homeassistant/components/tilt_pi/translations/id.json +11 -0
  266. homeassistant/components/tts/__init__.py +15 -0
  267. homeassistant/components/unifiprotect/translations/zh-Hans.json +3 -3
  268. homeassistant/components/utility_meter/translations/sv.json +9 -9
  269. homeassistant/components/vegehub/translations/bg.json +2 -0
  270. homeassistant/components/vegehub/translations/id.json +11 -0
  271. homeassistant/components/vegehub/translations/sv.json +2 -1
  272. homeassistant/components/vicare/translations/sv.json +2 -2
  273. homeassistant/components/whirlpool/translations/sv.json +12 -12
  274. homeassistant/components/wyoming/translations/sv.json +2 -2
  275. homeassistant/components/zha/translations/bg.json +23 -0
  276. homeassistant/components/zha/translations/el.json +10 -0
  277. homeassistant/components/zha/translations/ga.json +20 -0
  278. homeassistant/components/zha/translations/id.json +6 -0
  279. homeassistant/components/zha/translations/sv.json +23 -0
  280. homeassistant/components/zha/translations/zh-Hans.json +50 -0
  281. homeassistant/components/zwave_js/api.py +1 -1
  282. homeassistant/components/zwave_js/config_flow.py +15 -68
  283. homeassistant/components/zwave_js/manifest.json +1 -1
  284. homeassistant/components/zwave_js/strings.json +1 -5
  285. homeassistant/components/zwave_js/translations/bg.json +0 -3
  286. homeassistant/components/zwave_js/translations/cs.json +0 -5
  287. homeassistant/components/zwave_js/translations/de.json +1 -5
  288. homeassistant/components/zwave_js/translations/el.json +0 -5
  289. homeassistant/components/zwave_js/translations/en-GB.json +1 -5
  290. homeassistant/components/zwave_js/translations/en.json +1 -5
  291. homeassistant/components/zwave_js/translations/es.json +1 -5
  292. homeassistant/components/zwave_js/translations/et.json +0 -5
  293. homeassistant/components/zwave_js/translations/ga.json +0 -5
  294. homeassistant/components/zwave_js/translations/hu.json +0 -5
  295. homeassistant/components/zwave_js/translations/lt.json +0 -5
  296. homeassistant/components/zwave_js/translations/mk.json +0 -5
  297. homeassistant/components/zwave_js/translations/pt.json +0 -5
  298. homeassistant/components/zwave_js/translations/ru.json +0 -5
  299. homeassistant/components/zwave_js/translations/sk.json +0 -5
  300. homeassistant/components/zwave_js/translations/sv.json +0 -5
  301. homeassistant/components/zwave_js/translations/zh-Hans.json +0 -5
  302. homeassistant/components/zwave_js/translations/zh-Hant.json +1 -5
  303. homeassistant/config_entries.py +6 -0
  304. homeassistant/const.py +1 -1
  305. homeassistant/package_constraints.txt +1 -1
  306. {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b2.dist-info}/METADATA +1 -1
  307. {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b2.dist-info}/RECORD +312 -294
  308. {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b2.dist-info}/WHEEL +0 -0
  309. {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b2.dist-info}/entry_points.txt +0 -0
  310. {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b2.dist-info}/licenses/LICENSE.md +0 -0
  311. {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b2.dist-info}/licenses/homeassistant/backports/LICENSE.Python +0 -0
  312. {homeassistant-2025.7.0b0.dist-info → homeassistant-2025.7.0b2.dist-info}/top_level.txt +0 -0
@@ -2,13 +2,12 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from contextlib import suppress
6
- import io
7
- import logging
5
+ from collections.abc import Mapping
8
6
  from typing import Any
9
- import wave
10
7
 
11
8
  from google.genai import types
9
+ from google.genai.errors import APIError, ClientError
10
+ from propcache.api import cached_property
12
11
 
13
12
  from homeassistant.components.tts import (
14
13
  ATTR_VOICE,
@@ -16,15 +15,14 @@ from homeassistant.components.tts import (
16
15
  TtsAudioType,
17
16
  Voice,
18
17
  )
19
- from homeassistant.config_entries import ConfigEntry
18
+ from homeassistant.config_entries import ConfigEntry, ConfigSubentry
20
19
  from homeassistant.core import HomeAssistant, callback
21
20
  from homeassistant.exceptions import HomeAssistantError
22
- from homeassistant.helpers import device_registry as dr
23
21
  from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
24
22
 
25
- from .const import ATTR_MODEL, DOMAIN, RECOMMENDED_TTS_MODEL
26
-
27
- _LOGGER = logging.getLogger(__name__)
23
+ from .const import CONF_CHAT_MODEL, LOGGER, RECOMMENDED_TTS_MODEL
24
+ from .entity import GoogleGenerativeAILLMBaseEntity
25
+ from .helpers import convert_to_wav
28
26
 
29
27
 
30
28
  async def async_setup_entry(
@@ -32,15 +30,23 @@ async def async_setup_entry(
32
30
  config_entry: ConfigEntry,
33
31
  async_add_entities: AddConfigEntryEntitiesCallback,
34
32
  ) -> None:
35
- """Set up TTS entity."""
36
- tts_entity = GoogleGenerativeAITextToSpeechEntity(config_entry)
37
- async_add_entities([tts_entity])
33
+ """Set up TTS entities."""
34
+ for subentry in config_entry.subentries.values():
35
+ if subentry.subentry_type != "tts":
36
+ continue
37
+
38
+ async_add_entities(
39
+ [GoogleGenerativeAITextToSpeechEntity(config_entry, subentry)],
40
+ config_subentry_id=subentry.subentry_id,
41
+ )
38
42
 
39
43
 
40
- class GoogleGenerativeAITextToSpeechEntity(TextToSpeechEntity):
44
+ class GoogleGenerativeAITextToSpeechEntity(
45
+ TextToSpeechEntity, GoogleGenerativeAILLMBaseEntity
46
+ ):
41
47
  """Google Generative AI text-to-speech entity."""
42
48
 
43
- _attr_supported_options = [ATTR_VOICE, ATTR_MODEL]
49
+ _attr_supported_options = [ATTR_VOICE]
44
50
  # See https://ai.google.dev/gemini-api/docs/speech-generation#languages
45
51
  _attr_supported_languages = [
46
52
  "ar-EG",
@@ -68,6 +74,8 @@ class GoogleGenerativeAITextToSpeechEntity(TextToSpeechEntity):
68
74
  "uk-UA",
69
75
  "vi-VN",
70
76
  ]
77
+ # Unused, but required by base class.
78
+ # The Gemini TTS models detect the input language automatically.
71
79
  _attr_default_language = "en-US"
72
80
  # See https://ai.google.dev/gemini-api/docs/speech-generation#voices
73
81
  _supported_voices = [
@@ -106,110 +114,44 @@ class GoogleGenerativeAITextToSpeechEntity(TextToSpeechEntity):
106
114
  )
107
115
  ]
108
116
 
109
- def __init__(self, entry: ConfigEntry) -> None:
110
- """Initialize Google Generative AI Conversation speech entity."""
111
- self.entry = entry
112
- self._attr_name = "Google Generative AI TTS"
113
- self._attr_unique_id = f"{entry.entry_id}_tts"
114
- self._attr_device_info = dr.DeviceInfo(
115
- identifiers={(DOMAIN, entry.entry_id)},
116
- manufacturer="Google",
117
- model="Generative AI",
118
- entry_type=dr.DeviceEntryType.SERVICE,
119
- )
120
- self._genai_client = entry.runtime_data
121
- self._default_voice_id = self._supported_voices[0].voice_id
117
+ def __init__(self, config_entry: ConfigEntry, subentry: ConfigSubentry) -> None:
118
+ """Initialize the TTS entity."""
119
+ super().__init__(config_entry, subentry, RECOMMENDED_TTS_MODEL)
122
120
 
123
121
  @callback
124
- def async_get_supported_voices(self, language: str) -> list[Voice] | None:
122
+ def async_get_supported_voices(self, language: str) -> list[Voice]:
125
123
  """Return a list of supported voices for a language."""
126
124
  return self._supported_voices
127
125
 
126
+ @cached_property
127
+ def default_options(self) -> Mapping[str, Any]:
128
+ """Return a mapping with the default options."""
129
+ return {
130
+ ATTR_VOICE: self._supported_voices[0].voice_id,
131
+ }
132
+
128
133
  async def async_get_tts_audio(
129
134
  self, message: str, language: str, options: dict[str, Any]
130
135
  ) -> TtsAudioType:
131
136
  """Load tts audio file from the engine."""
137
+ config = self.create_generate_content_config()
138
+ config.response_modalities = ["AUDIO"]
139
+ config.speech_config = types.SpeechConfig(
140
+ voice_config=types.VoiceConfig(
141
+ prebuilt_voice_config=types.PrebuiltVoiceConfig(
142
+ voice_name=options[ATTR_VOICE]
143
+ )
144
+ )
145
+ )
132
146
  try:
133
- response = self._genai_client.models.generate_content(
134
- model=options.get(ATTR_MODEL, RECOMMENDED_TTS_MODEL),
147
+ response = await self._genai_client.aio.models.generate_content(
148
+ model=self.subentry.data.get(CONF_CHAT_MODEL, RECOMMENDED_TTS_MODEL),
135
149
  contents=message,
136
- config=types.GenerateContentConfig(
137
- response_modalities=["AUDIO"],
138
- speech_config=types.SpeechConfig(
139
- voice_config=types.VoiceConfig(
140
- prebuilt_voice_config=types.PrebuiltVoiceConfig(
141
- voice_name=options.get(
142
- ATTR_VOICE, self._default_voice_id
143
- )
144
- )
145
- )
146
- ),
147
- ),
150
+ config=config,
148
151
  )
149
-
150
152
  data = response.candidates[0].content.parts[0].inline_data.data
151
153
  mime_type = response.candidates[0].content.parts[0].inline_data.mime_type
152
- except Exception as exc:
153
- _LOGGER.warning(
154
- "Error during processing of TTS request %s", exc, exc_info=True
155
- )
154
+ except (APIError, ClientError, ValueError) as exc:
155
+ LOGGER.error("Error during TTS: %s", exc, exc_info=True)
156
156
  raise HomeAssistantError(exc) from exc
157
- return "wav", self._convert_to_wav(data, mime_type)
158
-
159
- def _convert_to_wav(self, audio_data: bytes, mime_type: str) -> bytes:
160
- """Generate a WAV file header for the given audio data and parameters.
161
-
162
- Args:
163
- audio_data: The raw audio data as a bytes object.
164
- mime_type: Mime type of the audio data.
165
-
166
- Returns:
167
- A bytes object representing the WAV file header.
168
-
169
- """
170
- parameters = self._parse_audio_mime_type(mime_type)
171
-
172
- wav_buffer = io.BytesIO()
173
- with wave.open(wav_buffer, "wb") as wf:
174
- wf.setnchannels(1)
175
- wf.setsampwidth(parameters["bits_per_sample"] // 8)
176
- wf.setframerate(parameters["rate"])
177
- wf.writeframes(audio_data)
178
-
179
- return wav_buffer.getvalue()
180
-
181
- def _parse_audio_mime_type(self, mime_type: str) -> dict[str, int]:
182
- """Parse bits per sample and rate from an audio MIME type string.
183
-
184
- Assumes bits per sample is encoded like "L16" and rate as "rate=xxxxx".
185
-
186
- Args:
187
- mime_type: The audio MIME type string (e.g., "audio/L16;rate=24000").
188
-
189
- Returns:
190
- A dictionary with "bits_per_sample" and "rate" keys. Values will be
191
- integers if found, otherwise None.
192
-
193
- """
194
- if not mime_type.startswith("audio/L"):
195
- _LOGGER.warning("Received unexpected MIME type %s", mime_type)
196
- raise HomeAssistantError(f"Unsupported audio MIME type: {mime_type}")
197
-
198
- bits_per_sample = 16
199
- rate = 24000
200
-
201
- # Extract rate from parameters
202
- parts = mime_type.split(";")
203
- for param in parts: # Skip the main type part
204
- param = param.strip()
205
- if param.lower().startswith("rate="):
206
- # Handle cases like "rate=" with no value or non-integer value and keep rate as default
207
- with suppress(ValueError, IndexError):
208
- rate_str = param.split("=", 1)[1]
209
- rate = int(rate_str)
210
- elif param.startswith("audio/L"):
211
- # Keep bits_per_sample as default if conversion fails
212
- with suppress(ValueError, IndexError):
213
- bits_per_sample = int(param.split("L", 1)[1])
214
-
215
- return {"bits_per_sample": bits_per_sample, "rate": rate}
157
+ return "wav", convert_to_wav(data, mime_type)
@@ -3,12 +3,12 @@
3
3
  "step": {
4
4
  "binary_sensor": {
5
5
  "data": {
6
- "all": "\u038c\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",
6
+ "all": "\u039f\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",
7
7
  "entities": "\u039c\u03ad\u03bb\u03b7",
8
8
  "hide_members": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03bc\u03b5\u03bb\u03ce\u03bd",
9
9
  "name": "\u039f\u03bd\u03bf\u03bc\u03b1"
10
10
  },
11
- "description": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\", \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03bc\u03cc\u03bd\u03bf \u03b5\u03ac\u03bd \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03bc\u03ad\u03bb\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1. \u0395\u03ac\u03bd \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\" \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03ac\u03bd \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf.",
11
+ "description": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\", \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \"\u03b5\u03bd\u03b5\u03c1\u03b3\u03cc\" \u03bc\u03cc\u03bd\u03bf \u03b5\u03ac\u03bd \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03bc\u03ad\u03bb\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1. \u0395\u03ac\u03bd \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\" \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03ac\u03bd \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf.",
12
12
  "title": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03af\u03b1 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2"
13
13
  },
14
14
  "button": {
@@ -82,7 +82,7 @@
82
82
  "hide_members": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03bc\u03b5\u03bb\u03ce\u03bd",
83
83
  "ignore_non_numeric": "\u03a0\u03b1\u03c1\u03ac\u03b2\u03bb\u03b5\u03c8\u03b7 \u03bc\u03b7 \u03b1\u03c1\u03b9\u03b8\u03bc\u03b7\u03c4\u03b9\u03ba\u03ce\u03bd",
84
84
  "name": "\u039f\u03bd\u03bf\u03bc\u03b1",
85
- "round_digits": "\u03a3\u03c4\u03c1\u03bf\u03b3\u03b3\u03c5\u03bb\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c4\u03b9\u03bc\u03ae \u03c3\u03c4\u03bf\u03bd \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03c4\u03c9\u03bd \u03b4\u03b5\u03ba\u03b1\u03b4\u03b9\u03ba\u03ce\u03bd",
85
+ "round_digits": "\u03a3\u03c4\u03c1\u03bf\u03b3\u03b3\u03c5\u03bb\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03c4\u03b9\u03bc\u03ae\u03c2 \u03c3\u03b5 \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03b4\u03b5\u03ba\u03b1\u03b4\u03b9\u03ba\u03ce\u03bd \u03c8\u03b7\u03c6\u03af\u03c9\u03bd",
86
86
  "state_class": "\u039a\u03bb\u03ac\u03c3\u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7\u03c2",
87
87
  "type": "\u03a4\u03cd\u03c0\u03bf\u03c2",
88
88
  "unit_of_measurement": "\u039c\u03bf\u03bd\u03ac\u03b4\u03b1 \u03bc\u03ad\u03c4\u03c1\u03b7\u03c3\u03b7\u03c2"
@@ -106,9 +106,9 @@
106
106
  "event": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03c3\u03c5\u03bc\u03b2\u03ac\u03bd\u03c4\u03c9\u03bd",
107
107
  "fan": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03b1\u03bd\u03b5\u03bc\u03b9\u03c3\u03c4\u03ae\u03c1\u03c9\u03bd",
108
108
  "light": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03c6\u03ce\u03c4\u03c9\u03bd",
109
- "lock": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03ba\u03bb\u03b5\u03b9\u03b4\u03ce\u03bc\u03b1\u03c4\u03bf\u03c2",
110
- "media_player": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd",
111
- "notify": "\u0395\u03b9\u03b4\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2",
109
+ "lock": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03ba\u03bb\u03b5\u03b9\u03b4\u03b1\u03c1\u03b9\u03ce\u03bd",
110
+ "media_player": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03c3\u03c5\u03c3\u03ba\u03b5\u03c5\u03ce\u03bd \u03b1\u03bd\u03b1\u03c0\u03b1\u03c1\u03b1\u03b3\u03c9\u03b3\u03ae\u03c2 \u03c0\u03bf\u03bb\u03c5\u03bc\u03ad\u03c3\u03c9\u03bd",
111
+ "notify": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03b5\u03b9\u03b4\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c9\u03bd",
112
112
  "sensor": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03b1\u03b9\u03c3\u03b8\u03b7\u03c4\u03ae\u03c1\u03c9\u03bd",
113
113
  "switch": "\u039f\u03bc\u03ac\u03b4\u03b1 \u03b4\u03b9\u03b1\u03ba\u03bf\u03c0\u03c4\u03ce\u03bd"
114
114
  },
@@ -160,11 +160,11 @@
160
160
  "step": {
161
161
  "binary_sensor": {
162
162
  "data": {
163
- "all": "\u038c\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",
163
+ "all": "\u039f\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",
164
164
  "entities": "\u039c\u03ad\u03bb\u03b7",
165
165
  "hide_members": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03bc\u03b5\u03bb\u03ce\u03bd"
166
166
  },
167
- "description": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\", \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03bc\u03cc\u03bd\u03bf \u03b5\u03ac\u03bd \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03bc\u03ad\u03bb\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1. \u0395\u03ac\u03bd \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\" \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03ac\u03bd \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf."
167
+ "description": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\", \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \"\u03b5\u03bd\u03b5\u03c1\u03b3\u03cc\" \u03bc\u03cc\u03bd\u03bf \u03b5\u03ac\u03bd \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03bc\u03ad\u03bb\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1. \u0395\u03ac\u03bd \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\" \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03ac\u03bd \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf."
168
168
  },
169
169
  "button": {
170
170
  "data": {
@@ -186,11 +186,11 @@
186
186
  },
187
187
  "light": {
188
188
  "data": {
189
- "all": "\u038c\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",
189
+ "all": "\u039f\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",
190
190
  "entities": "\u039c\u03ad\u03bb\u03b7",
191
191
  "hide_members": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03bc\u03b5\u03bb\u03ce\u03bd"
192
192
  },
193
- "description": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\", \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03bc\u03cc\u03bd\u03bf \u03b5\u03ac\u03bd \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03bc\u03ad\u03bb\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1. \u0395\u03ac\u03bd \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\" \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03ac\u03bd \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf."
193
+ "description": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\", \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \"\u03b5\u03bd\u03b5\u03c1\u03b3\u03cc\" \u03bc\u03cc\u03bd\u03bf \u03b5\u03ac\u03bd \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03bc\u03ad\u03bb\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1. \u0395\u03ac\u03bd \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\" \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03ac\u03bd \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf."
194
194
  },
195
195
  "lock": {
196
196
  "data": {
@@ -216,7 +216,7 @@
216
216
  "entities": "\u039c\u03ad\u03bb\u03b7",
217
217
  "hide_members": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03bc\u03b5\u03bb\u03ce\u03bd",
218
218
  "ignore_non_numeric": "\u03a0\u03b1\u03c1\u03ac\u03b2\u03bb\u03b5\u03c8\u03b7 \u03bc\u03b7 \u03b1\u03c1\u03b9\u03b8\u03bc\u03b7\u03c4\u03b9\u03ba\u03ce\u03bd",
219
- "round_digits": "\u03a3\u03c4\u03c1\u03bf\u03b3\u03b3\u03c5\u03bb\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c4\u03b9\u03bc\u03ae \u03c3\u03c4\u03bf\u03bd \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03c4\u03c9\u03bd \u03b4\u03b5\u03ba\u03b1\u03b4\u03b9\u03ba\u03ce\u03bd",
219
+ "round_digits": "\u03a3\u03c4\u03c1\u03bf\u03b3\u03b3\u03c5\u03bb\u03bf\u03c0\u03bf\u03af\u03b7\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03c4\u03b9\u03bc\u03ae\u03c2 \u03c3\u03b5 \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03b4\u03b5\u03ba\u03b1\u03b4\u03b9\u03ba\u03ce\u03bd \u03c8\u03b7\u03c6\u03af\u03c9\u03bd",
220
220
  "state_class": "\u039a\u03bb\u03ac\u03c3\u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7\u03c2",
221
221
  "type": "\u03a4\u03cd\u03c0\u03bf\u03c2",
222
222
  "unit_of_measurement": "\u039c\u03bf\u03bd\u03ac\u03b4\u03b1 \u03bc\u03ad\u03c4\u03c1\u03b7\u03c3\u03b7\u03c2"
@@ -225,11 +225,11 @@
225
225
  },
226
226
  "switch": {
227
227
  "data": {
228
- "all": "\u038c\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",
228
+ "all": "\u039f\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2",
229
229
  "entities": "\u039c\u03ad\u03bb\u03b7",
230
230
  "hide_members": "\u0391\u03c0\u03cc\u03ba\u03c1\u03c5\u03c8\u03b7 \u03bc\u03b5\u03bb\u03ce\u03bd"
231
231
  },
232
- "description": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\", \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03bc\u03cc\u03bd\u03bf \u03b5\u03ac\u03bd \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03bc\u03ad\u03bb\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1. \u0395\u03ac\u03bd \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\" \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03ac\u03bd \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf."
232
+ "description": "\u0395\u03ac\u03bd \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\", \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \"\u03b5\u03bd\u03b5\u03c1\u03b3\u03cc\" \u03bc\u03cc\u03bd\u03bf \u03b5\u03ac\u03bd \u03cc\u03bb\u03b1 \u03c4\u03b1 \u03bc\u03ad\u03bb\u03b7 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b1. \u0395\u03ac\u03bd \u03b7 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ae \"\u03cc\u03bb\u03b5\u03c2 \u03bf\u03b9 \u03bf\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2\" \u03b5\u03af\u03bd\u03b1\u03b9 \u03b1\u03c0\u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7, \u03b7 \u03ba\u03b1\u03c4\u03ac\u03c3\u03c4\u03b1\u03c3\u03b7 \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03b7 \u03b5\u03ac\u03bd \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03bc\u03ad\u03bb\u03bf\u03c2 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03b7\u03bc\u03ad\u03bd\u03bf."
233
233
  }
234
234
  }
235
235
  },
@@ -242,9 +242,9 @@
242
242
  "median": "\u0394\u03b9\u03ac\u03bc\u03b5\u03c3\u03bf\u03c2",
243
243
  "min": "\u0395\u03bb\u03ac\u03c7\u03b9\u03c3\u03c4\u03bf",
244
244
  "product": "\u03a0\u03c1\u03bf\u03ca\u03cc\u03bd",
245
- "range": "\u03a3\u03c4\u03b1\u03c4\u03b9\u03c3\u03c4\u03b9\u03ba\u03cc \u03b5\u03cd\u03c1\u03bf\u03c2",
245
+ "range": "\u0395\u03cd\u03c1\u03bf\u03c2 \u03c3\u03c4\u03b1\u03c4\u03b9\u03c3\u03c4\u03b9\u03ba\u03ce\u03bd",
246
246
  "stdev": "\u03a4\u03c5\u03c0\u03b9\u03ba\u03ae \u03b1\u03c0\u03cc\u03ba\u03bb\u03b9\u03c3\u03b7",
247
- "sum": "\u0386\u03b8\u03c1\u03bf\u03b9\u03c3\u03bc\u03b1"
247
+ "sum": "\u0391\u03b8\u03c1\u03bf\u03b9\u03c3\u03bc\u03b1"
248
248
  }
249
249
  }
250
250
  },
@@ -267,7 +267,7 @@
267
267
  "description": "\u0394\u03b7\u03bc\u03b9\u03bf\u03c5\u03c1\u03b3\u03b5\u03af/\u0395\u03bd\u03b7\u03bc\u03b5\u03c1\u03ce\u03bd\u03b5\u03b9 \u03bc\u03b9\u03b1 \u03bf\u03bc\u03ac\u03b4\u03b1.",
268
268
  "fields": {
269
269
  "add_entities": {
270
- "description": "\u039b\u03af\u03c3\u03c4\u03b1 \u03c4\u03c9\u03bd \u03bc\u03b5\u03bb\u03ce\u03bd \u03c0\u03bf\u03c5 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03c0\u03c1\u03bf\u03c3\u03c4\u03b5\u03b8\u03bf\u03cd\u03bd \u03c3\u03c4\u03b7\u03bd \u03bf\u03bc\u03ac\u03b4\u03b1. \u0394\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03b5\u03af \u03c3\u03b5 \u03c3\u03c5\u03bd\u03b4\u03c5\u03b1\u03c3\u03bc\u03cc \u03bc\u03b5 \u03c4\u03b9\u03c2 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 `Entities` \u03ae `Remove entities`.",
270
+ "description": "\u039b\u03af\u03c3\u03c4\u03b1 \u03c4\u03c9\u03bd \u03bc\u03b5\u03bb\u03ce\u03bd \u03c0\u03bf\u03c5 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03c0\u03c1\u03bf\u03c3\u03c4\u03b5\u03b8\u03bf\u03cd\u03bd \u03c3\u03c4\u03b7\u03bd \u03bf\u03bc\u03ac\u03b4\u03b1. \u0394\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03b5\u03af \u03c3\u03b5 \u03c3\u03c5\u03bd\u03b4\u03c5\u03b1\u03c3\u03bc\u03cc \u03bc\u03b5 \u03c4\u03b9\u03c2 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 `\u039f\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2` \u03ae `\u0391\u03c6\u03b1\u03af\u03c1\u03b5\u03c3\u03b7 \u03bf\u03bd\u03c4\u03bf\u03c4\u03ae\u03c4\u03c9\u03bd`.",
271
271
  "name": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03bf\u03bd\u03c4\u03bf\u03c4\u03ae\u03c4\u03c9\u03bd"
272
272
  },
273
273
  "all": {
@@ -275,7 +275,7 @@
275
275
  "name": "\u039f\u03bb\u03b1"
276
276
  },
277
277
  "entities": {
278
- "description": "\u039b\u03af\u03c3\u03c4\u03b1 \u03cc\u03bb\u03c9\u03bd \u03c4\u03c9\u03bd \u03bc\u03b5\u03bb\u03ce\u03bd \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2. \u0394\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03b5\u03af \u03c3\u03b5 \u03c3\u03c5\u03bd\u03b4\u03c5\u03b1\u03c3\u03bc\u03cc \u03bc\u03b5 \u03c4\u03b9\u03c2 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 `Add entities` \u03ae `Remove entities`.",
278
+ "description": "\u039b\u03af\u03c3\u03c4\u03b1 \u03cc\u03bb\u03c9\u03bd \u03c4\u03c9\u03bd \u03bc\u03b5\u03bb\u03ce\u03bd \u03c4\u03b7\u03c2 \u03bf\u03bc\u03ac\u03b4\u03b1\u03c2. \u0394\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03b5\u03af \u03c3\u03b5 \u03c3\u03c5\u03bd\u03b4\u03c5\u03b1\u03c3\u03bc\u03cc \u03bc\u03b5 \u03c4\u03b9\u03c2 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 `\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03bf\u03bd\u03c4\u03bf\u03c4\u03ae\u03c4\u03c9\u03bd` \u03ae `\u0391\u03c6\u03b1\u03af\u03c1\u03b5\u03c3\u03b7 \u03bf\u03bd\u03c4\u03bf\u03c4\u03ae\u03c4\u03c9\u03bd`.",
279
279
  "name": "\u039f\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2"
280
280
  },
281
281
  "icon": {
@@ -291,7 +291,7 @@
291
291
  "name": "ID \u03b1\u03bd\u03c4\u03b9\u03ba\u03b5\u03b9\u03bc\u03ad\u03bd\u03bf\u03c5"
292
292
  },
293
293
  "remove_entities": {
294
- "description": "\u039b\u03af\u03c3\u03c4\u03b1 \u03c4\u03c9\u03bd \u03bc\u03b5\u03bb\u03ce\u03bd \u03c0\u03bf\u03c5 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b1\u03c6\u03b1\u03b9\u03c1\u03b5\u03b8\u03bf\u03cd\u03bd \u03b1\u03c0\u03cc \u03bc\u03b9\u03b1 \u03bf\u03bc\u03ac\u03b4\u03b1. \u0394\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03b5\u03af \u03c3\u03b5 \u03c3\u03c5\u03bd\u03b4\u03c5\u03b1\u03c3\u03bc\u03cc \u03bc\u03b5 \u03c4\u03b9\u03c2 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 `Entities` \u03ae `Add entities`.",
294
+ "description": "\u039b\u03af\u03c3\u03c4\u03b1 \u03c4\u03c9\u03bd \u03bc\u03b5\u03bb\u03ce\u03bd \u03c0\u03bf\u03c5 \u03c0\u03c1\u03ad\u03c0\u03b5\u03b9 \u03bd\u03b1 \u03b1\u03c6\u03b1\u03b9\u03c1\u03b5\u03b8\u03bf\u03cd\u03bd \u03b1\u03c0\u03cc \u03bc\u03b9\u03b1 \u03bf\u03bc\u03ac\u03b4\u03b1. \u0394\u03b5\u03bd \u03bc\u03c0\u03bf\u03c1\u03b5\u03af \u03bd\u03b1 \u03c7\u03c1\u03b7\u03c3\u03b9\u03bc\u03bf\u03c0\u03bf\u03b9\u03b7\u03b8\u03b5\u03af \u03c3\u03b5 \u03c3\u03c5\u03bd\u03b4\u03c5\u03b1\u03c3\u03bc\u03cc \u03bc\u03b5 \u03c4\u03b9\u03c2 \u03b5\u03c0\u03b9\u03bb\u03bf\u03b3\u03ad\u03c2 `\u039f\u03bd\u03c4\u03cc\u03c4\u03b7\u03c4\u03b5\u03c2` \u03ae `\u03a0\u03c1\u03bf\u03c3\u03b8\u03ae\u03ba\u03b7 \u03bf\u03bd\u03c4\u03bf\u03c4\u03ae\u03c4\u03c9\u03bd`.",
295
295
  "name": "\u0391\u03c6\u03b1\u03af\u03c1\u03b5\u03c3\u03b7 \u03bf\u03bd\u03c4\u03bf\u03c4\u03ae\u03c4\u03c9\u03bd"
296
296
  }
297
297
  },
@@ -9,7 +9,7 @@ ASSETS_URL = "https://habitica-assets.s3.amazonaws.com/mobileApp/images/"
9
9
  SITE_DATA_URL = "https://habitica.com/user/settings/siteData"
10
10
  FORGOT_PASSWORD_URL = "https://habitica.com/forgot-password"
11
11
  SIGN_UP_URL = "https://habitica.com/register"
12
- HABITICANS_URL = "https://habitica.com/static/img/home-main@3x.ffc32b12.png"
12
+ HABITICANS_URL = "https://cdn.habitica.com/assets/home-main@3x-Dwnue45Z.png"
13
13
 
14
14
  DOMAIN = "habitica"
15
15
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "state": {
3
3
  "harmony__activities": {
4
- "power_off": "Avst\u00e4ngd"
4
+ "power_off": "St\u00e4ng av"
5
5
  }
6
6
  }
7
7
  }
@@ -30,7 +30,7 @@
30
30
  "activities": {
31
31
  "name": "Aktiviteter",
32
32
  "state": {
33
- "power_off": "Avst\u00e4ngd"
33
+ "power_off": "St\u00e4ng av"
34
34
  }
35
35
  }
36
36
  }
@@ -7,7 +7,10 @@ import asyncio
7
7
  import logging
8
8
  from typing import Any
9
9
 
10
- from ha_silabs_firmware_client import FirmwareUpdateClient
10
+ from aiohttp import ClientError
11
+ from ha_silabs_firmware_client import FirmwareUpdateClient, ManifestMissing
12
+ from universal_silabs_flasher.common import Version
13
+ from universal_silabs_flasher.firmware import NabuCasaMetadata
11
14
 
12
15
  from homeassistant.components.hassio import (
13
16
  AddonError,
@@ -149,15 +152,78 @@ class BaseFirmwareInstallFlow(ConfigEntryBaseFlow, ABC):
149
152
  assert self._device is not None
150
153
 
151
154
  if not self.firmware_install_task:
155
+ # We 100% need to install new firmware only if the wrong firmware is
156
+ # currently installed
157
+ firmware_install_required = self._probed_firmware_info is None or (
158
+ self._probed_firmware_info.firmware_type
159
+ != expected_installed_firmware_type
160
+ )
161
+
152
162
  session = async_get_clientsession(self.hass)
153
163
  client = FirmwareUpdateClient(fw_update_url, session)
154
- manifest = await client.async_update_data()
155
164
 
156
- fw_meta = next(
157
- fw for fw in manifest.firmwares if fw.filename.startswith(fw_type)
158
- )
165
+ try:
166
+ manifest = await client.async_update_data()
167
+ fw_manifest = next(
168
+ fw for fw in manifest.firmwares if fw.filename.startswith(fw_type)
169
+ )
170
+ except (StopIteration, TimeoutError, ClientError, ManifestMissing) as err:
171
+ _LOGGER.warning(
172
+ "Failed to fetch firmware update manifest", exc_info=True
173
+ )
174
+
175
+ # Not having internet access should not prevent setup
176
+ if not firmware_install_required:
177
+ _LOGGER.debug(
178
+ "Skipping firmware upgrade due to index download failure"
179
+ )
180
+ return self.async_show_progress_done(next_step_id=next_step_id)
181
+
182
+ raise AbortFlow(
183
+ "fw_download_failed",
184
+ description_placeholders={
185
+ **self._get_translation_placeholders(),
186
+ "firmware_name": firmware_name,
187
+ },
188
+ ) from err
189
+
190
+ if not firmware_install_required:
191
+ assert self._probed_firmware_info is not None
192
+
193
+ # Make sure we do not downgrade the firmware
194
+ fw_metadata = NabuCasaMetadata.from_json(fw_manifest.metadata)
195
+ fw_version = fw_metadata.get_public_version()
196
+ probed_fw_version = Version(self._probed_firmware_info.firmware_version)
197
+
198
+ if probed_fw_version >= fw_version:
199
+ _LOGGER.debug(
200
+ "Not downgrading firmware, installed %s is newer than available %s",
201
+ probed_fw_version,
202
+ fw_version,
203
+ )
204
+ return self.async_show_progress_done(next_step_id=next_step_id)
205
+
206
+ try:
207
+ fw_data = await client.async_fetch_firmware(fw_manifest)
208
+ except (TimeoutError, ClientError, ValueError) as err:
209
+ _LOGGER.warning("Failed to fetch firmware update", exc_info=True)
210
+
211
+ # If we cannot download new firmware, we shouldn't block setup
212
+ if not firmware_install_required:
213
+ _LOGGER.debug(
214
+ "Skipping firmware upgrade due to image download failure"
215
+ )
216
+ return self.async_show_progress_done(next_step_id=next_step_id)
217
+
218
+ # Otherwise, fail
219
+ raise AbortFlow(
220
+ "fw_download_failed",
221
+ description_placeholders={
222
+ **self._get_translation_placeholders(),
223
+ "firmware_name": firmware_name,
224
+ },
225
+ ) from err
159
226
 
160
- fw_data = await client.async_fetch_firmware(fw_meta)
161
227
  self.firmware_install_task = self.hass.async_create_task(
162
228
  async_flash_silabs_firmware(
163
229
  hass=self.hass,
@@ -215,6 +281,14 @@ class BaseFirmwareInstallFlow(ConfigEntryBaseFlow, ABC):
215
281
  },
216
282
  )
217
283
 
284
+ async def async_step_pre_confirm_zigbee(
285
+ self, user_input: dict[str, Any] | None = None
286
+ ) -> ConfigFlowResult:
287
+ """Pre-confirm Zigbee setup."""
288
+
289
+ # This step is necessary to prevent `user_input` from being passed through
290
+ return await self.async_step_confirm_zigbee()
291
+
218
292
  async def async_step_confirm_zigbee(
219
293
  self, user_input: dict[str, Any] | None = None
220
294
  ) -> ConfigFlowResult:
@@ -409,7 +483,15 @@ class BaseFirmwareInstallFlow(ConfigEntryBaseFlow, ABC):
409
483
  finally:
410
484
  self.addon_start_task = None
411
485
 
412
- return self.async_show_progress_done(next_step_id="confirm_otbr")
486
+ return self.async_show_progress_done(next_step_id="pre_confirm_otbr")
487
+
488
+ async def async_step_pre_confirm_otbr(
489
+ self, user_input: dict[str, Any] | None = None
490
+ ) -> ConfigFlowResult:
491
+ """Pre-confirm OTBR setup."""
492
+
493
+ # This step is necessary to prevent `user_input` from being passed through
494
+ return await self.async_step_confirm_otbr()
413
495
 
414
496
  async def async_step_confirm_otbr(
415
497
  self, user_input: dict[str, Any] | None = None
@@ -36,7 +36,8 @@
36
36
  "otbr_addon_already_running": "The OpenThread Border Router add-on is already running, it cannot be installed again.",
37
37
  "zha_still_using_stick": "This {model} is in use by the Zigbee Home Automation integration. Please migrate your Zigbee network to another adapter or delete the integration and try again.",
38
38
  "otbr_still_using_stick": "This {model} is in use by the OpenThread Border Router add-on. If you use the Thread network, make sure you have alternative border routers. Uninstall the add-on and try again.",
39
- "unsupported_firmware": "The radio firmware on your {model} could not be determined. Make sure that no other integration or add-on is currently trying to communicate with the device. If you are running Home Assistant OS in a virtual machine or in Docker, please make sure that permissions are set correctly for the device."
39
+ "unsupported_firmware": "The radio firmware on your {model} could not be determined. Make sure that no other integration or add-on is currently trying to communicate with the device. If you are running Home Assistant OS in a virtual machine or in Docker, please make sure that permissions are set correctly for the device.",
40
+ "fw_download_failed": "{firmware_name} firmware for your {model} failed to download. Make sure Home Assistant has internet access and try again."
40
41
  },
41
42
  "progress": {
42
43
  "install_firmware": "Please wait while {firmware_name} firmware is installed to your {model}, this will take a few minutes. Do not make any changes to your hardware or software until this finishes."
@@ -2,6 +2,7 @@
2
2
  "firmware_picker": {
3
3
  "options": {
4
4
  "abort": {
5
+ "fw_download_failed": "Download der {firmware_name}-Firmware f\u00fcr deinen {model} fehlgeschlagen. Stelle sicher, dass Home Assistant einen Internetzugang hat und versuche es erneut.",
5
6
  "not_hassio_thread": "Das OpenThread Border Router-Add-on kann nur mit Home Assistant OS installiert werden. Wenn du das {model} als Thread Border Router verwenden m\u00f6chtest, flashe die Firmware bitte manuell mit dem [Web Flasher]({docs_web_flasher_url}) und richte den OpenThread Border Router f\u00fcr die Kommunikation damit ein.",
6
7
  "otbr_addon_already_running": "Das OpenThread Border Router-Add-on wird bereits ausgef\u00fchrt und kann nicht erneut installiert werden.",
7
8
  "otbr_still_using_stick": "Dieses {model} wird vom OpenThread Border Router-Add-on verwendet. Wenn du das Thread-Netzwerk verwendest, stelle sicher, dass du alternative Border-Router hast. Deinstalliere das Add-on und versuche es erneut.",
@@ -2,6 +2,7 @@
2
2
  "firmware_picker": {
3
3
  "options": {
4
4
  "abort": {
5
+ "fw_download_failed": "{firmware_name} firmware for your {model} failed to download. Make sure Home Assistant has internet access and try again.",
5
6
  "not_hassio_thread": "The OpenThread Border Router add-on can only be installed with Home Assistant OS. If you would like to use the {model} as a Thread border router, please flash the firmware manually using the [web flasher]({docs_web_flasher_url}) and set up OpenThread Border Router to communicate with it.",
6
7
  "otbr_addon_already_running": "The OpenThread Border Router add-on is already running, it cannot be installed again.",
7
8
  "otbr_still_using_stick": "This {model} is in use by the OpenThread Border Router add-on. If you use the Thread network, make sure you have alternative border routers. Uninstall the add-on and try again.",
@@ -2,6 +2,7 @@
2
2
  "firmware_picker": {
3
3
  "options": {
4
4
  "abort": {
5
+ "fw_download_failed": "{firmware_name} firmware for your {model} failed to download. Make sure Home Assistant has internet access and try again.",
5
6
  "not_hassio_thread": "The OpenThread Border Router add-on can only be installed with Home Assistant OS. If you would like to use the {model} as a Thread border router, please flash the firmware manually using the [web flasher]({docs_web_flasher_url}) and set up OpenThread Border Router to communicate with it.",
6
7
  "otbr_addon_already_running": "The OpenThread Border Router add-on is already running, it cannot be installed again.",
7
8
  "otbr_still_using_stick": "This {model} is in use by the OpenThread Border Router add-on. If you use the Thread network, make sure you have alternative border routers. Uninstall the add-on and try again.",
@@ -0,0 +1,9 @@
1
+ {
2
+ "firmware_picker": {
3
+ "options": {
4
+ "progress": {
5
+ "install_firmware": "Fan go dt\u00ed go suite\u00e1lfar firmware {firmware_name} ar do {model}, t\u00f3gfaidh s\u00e9 seo c\u00fapla n\u00f3im\u00e9ad. N\u00e1 d\u00e9an aon athruithe ar do chrua-earra\u00ed n\u00e1 ar do bhogearra\u00ed go dt\u00ed go mbeidh s\u00e9 seo cr\u00edochnaithe."
6
+ }
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "firmware_picker": {
3
+ "options": {
4
+ "progress": {
5
+ "install_firmware": "\u041f\u043e\u0447\u0435\u043a\u0430\u0458\u0442\u0435 \u0434\u043e\u0434\u0435\u043a\u0430 \u0444\u0438\u0440\u043c\u0432\u0435\u0440\u043e\u0442 {firmware_name} \u0441\u0435 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430 \u043d\u0430 \u0432\u0430\u0448\u0438\u043e\u0442 {model}, \u043e\u0432\u0430 \u045c\u0435 \u043f\u043e\u0442\u0440\u0430\u0435 \u043d\u0435\u043a\u043e\u043b\u043a\u0443 \u043c\u0438\u043d\u0443\u0442\u0438. \u041d\u0435 \u043f\u0440\u0430\u0432\u0435\u0442\u0435 \u043d\u0438\u043a\u0430\u043a\u0432\u0438 \u043f\u0440\u043e\u043c\u0435\u043d\u0438 \u043d\u0430 \u0432\u0430\u0448\u0438\u043e\u0442 \u0445\u0430\u0440\u0434\u0432\u0435\u0440 \u0438\u043b\u0438 \u0441\u043e\u0444\u0442\u0432\u0435\u0440 \u0434\u043e\u0434\u0435\u043a\u0430 \u043e\u0432\u0430 \u043d\u0435 \u0437\u0430\u0432\u0440\u0448\u0438."
6
+ }
7
+ }
8
+ }
9
+ }
@@ -93,7 +93,7 @@ class SkyConnectFirmwareMixin(ConfigEntryBaseFlow, FirmwareInstallFlowProtocol):
93
93
  firmware_name="Zigbee",
94
94
  expected_installed_firmware_type=ApplicationType.EZSP,
95
95
  step_id="install_zigbee_firmware",
96
- next_step_id="confirm_zigbee",
96
+ next_step_id="pre_confirm_zigbee",
97
97
  )
98
98
 
99
99
  async def async_step_install_thread_firmware(
@@ -92,7 +92,8 @@
92
92
  "otbr_addon_already_running": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::otbr_addon_already_running%]",
93
93
  "zha_still_using_stick": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::zha_still_using_stick%]",
94
94
  "otbr_still_using_stick": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::otbr_still_using_stick%]",
95
- "unsupported_firmware": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::unsupported_firmware%]"
95
+ "unsupported_firmware": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::unsupported_firmware%]",
96
+ "fw_download_failed": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::fw_download_failed%]"
96
97
  },
97
98
  "progress": {
98
99
  "install_addon": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::progress::install_addon%]",
@@ -145,7 +146,8 @@
145
146
  "otbr_addon_already_running": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::otbr_addon_already_running%]",
146
147
  "zha_still_using_stick": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::zha_still_using_stick%]",
147
148
  "otbr_still_using_stick": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::otbr_still_using_stick%]",
148
- "unsupported_firmware": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::unsupported_firmware%]"
149
+ "unsupported_firmware": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::unsupported_firmware%]",
150
+ "fw_download_failed": "[%key:component::homeassistant_hardware::firmware_picker::options::abort::fw_download_failed%]"
149
151
  },
150
152
  "progress": {
151
153
  "install_addon": "[%key:component::homeassistant_hardware::silabs_multiprotocol_hardware::options::progress::install_addon%]",