1 """Provides functionality to interact with image processing services."""
3 from __future__
import annotations
6 from datetime
import timedelta
7 from enum
import StrEnum
9 from typing
import Any, Final, TypedDict, final
11 import voluptuous
as vol
29 _LOGGER = logging.getLogger(__name__)
31 DOMAIN =
"image_processing"
36 """Device class for image processing entities."""
50 EVENT_DETECT_FACE =
"image_processing.detect_face"
53 ATTR_CONFIDENCE: Final =
"confidence"
55 ATTR_GENDER =
"gender"
56 ATTR_GLASSES =
"glasses"
57 ATTR_MOTION: Final =
"motion"
58 ATTR_TOTAL_FACES =
"total_faces"
60 CONF_CONFIDENCE =
"confidence"
63 DEFAULT_CONFIDENCE = 80
65 SOURCE_SCHEMA = vol.Schema(
67 vol.Required(CONF_ENTITY_ID): cv.entity_domain(
"camera"),
68 vol.Optional(CONF_NAME): cv.string,
72 PLATFORM_SCHEMA = cv.PLATFORM_SCHEMA.extend(
74 vol.Optional(CONF_SOURCE): vol.All(cv.ensure_list, [SOURCE_SCHEMA]),
75 vol.Optional(CONF_CONFIDENCE, default=DEFAULT_CONFIDENCE): vol.All(
76 vol.Coerce(float), vol.Range(min=0, max=100)
80 PLATFORM_SCHEMA_BASE = cv.PLATFORM_SCHEMA_BASE.extend(PLATFORM_SCHEMA.schema)
84 """Face information."""
95 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
96 """Set up the image processing."""
97 component = EntityComponent[ImageProcessingEntity](
98 _LOGGER, DOMAIN, hass, SCAN_INTERVAL
101 await component.async_setup(config)
103 async
def async_scan_service(service: ServiceCall) ->
None:
104 """Service handler for scan."""
105 image_entities = await component.async_extract_from_service(service)
108 for entity
in image_entities:
109 entity.async_set_context(service.context)
110 update_tasks.append(asyncio.create_task(entity.async_update_ha_state(
True)))
113 await asyncio.wait(update_tasks)
115 hass.services.async_register(
123 """A class that describes sensor entities."""
125 device_class: ImageProcessingDeviceClass |
None =
None
126 camera_entity: str |
None =
None
127 confidence: float |
None =
None
131 """Base entity class for image processing."""
133 entity_description: ImageProcessingEntityDescription
134 _attr_device_class: ImageProcessingDeviceClass |
None
135 _attr_camera_entity: str |
None
136 _attr_confidence: float |
None
137 timeout = DEFAULT_TIMEOUT
141 """Return camera entity id from process pictures."""
142 if hasattr(self,
"_attr_camera_entity"):
143 return self._attr_camera_entity
144 if hasattr(self,
"entity_description"):
145 return self.entity_description.camera_entity
150 """Return minimum confidence to do some things."""
151 if hasattr(self,
"_attr_confidence"):
152 return self._attr_confidence
153 if hasattr(self,
"entity_description"):
154 return self.entity_description.confidence
159 """Return the class of this entity."""
160 if hasattr(self,
"_attr_device_class"):
161 return self._attr_device_class
162 if hasattr(self,
"entity_description"):
163 return self.entity_description.device_class
168 raise NotImplementedError
172 return await self.
hasshass.async_add_executor_job(self.
process_imageprocess_image, image)
175 """Update image and process it.
177 This method is a coroutine.
181 "No camera entity id was set by the image processing entity",
189 except HomeAssistantError
as err:
190 _LOGGER.error(
"Error on receive image from entity: %s", err)
198 """Base entity class for face image processing."""
200 _attr_device_class = ImageProcessingDeviceClass.FACE
203 """Initialize base face identify/verify entity."""
204 self.
facesfaces: list[FaceInformation] = []
208 def state(self) -> str | int | None:
209 """Return the state of the entity."""
210 confidence: float = 0
218 for face
in self.
facesfaces:
219 if ATTR_CONFIDENCE
not in face:
222 if (f_co := face[ATTR_CONFIDENCE]) > confidence:
224 for attr
in (ATTR_NAME, ATTR_MOTION):
234 """Return device specific state attributes."""
235 return {ATTR_FACES: self.
facesfaces, ATTR_TOTAL_FACES: self.
total_facestotal_faces}
238 """Send event with detected faces and store data."""
243 """Send event with detected faces and store data.
245 known are a dict in follow format:
252 ATTR_MOTION: 'smile',
253 ATTR_GLASSES: 'sunglasses'
257 This method must be run in the event loop.
262 ATTR_CONFIDENCE
in face
264 and face[ATTR_CONFIDENCE] < self.
confidenceconfidence
268 face.update({ATTR_ENTITY_ID: self.
entity_identity_id})
269 self.
hasshass.bus.async_fire(EVENT_DETECT_FACE, face)
ImageProcessingDeviceClass|None device_class(self)
float|None confidence(self)
str|None camera_entity(self)
None async_process_image(self, bytes image)
None process_image(self, bytes image)
dict[str, Any] state_attributes(self)
None process_faces(self, list[FaceInformation] faces, int total)
None async_process_faces(self, list[FaceInformation] faces, int total)
bytes|None async_get_image(HomeAssistant hass, str input_source, str output_format=IMAGE_JPEG, str|None extra_cmd=None, int|None width=None, int|None height=None)
bool async_setup(HomeAssistant hass, ConfigType config)
VolSchemaType make_entity_service_schema(dict|None schema, *int extra=vol.PREVENT_EXTRA)