Adds facebox#14307
Adds facebox#14307robmarkcole wants to merge 37 commits intohome-assistant:devfrom robmarkcole:facebox-detect
Conversation
|
@pvizeli will keep this initial release a MVP. I don't understand why the test fails with the error, is that because I am not mocking the posted data?: |
| import base64 | ||
| import requests | ||
| import logging | ||
| import voluptuous as vol |
There was a problem hiding this comment.
Add a blank line between standard library and 3rd party imports.
|
|
||
| PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||
| vol.Required(CONF_IP_ADDRESS): cv.string, | ||
| vol.Required(CONF_PORT): cv.string, |
| https://home-assistant.io/components/image_processing.facebox_face_detect | ||
| """ | ||
| import base64 | ||
| import requests |
There was a problem hiding this comment.
This is a 3rd party library and should be grouped with those ie voluptuous.
| response = requests.post( | ||
| self._url, | ||
| json=self.encode_image(image), | ||
| timeout=30 |
There was a problem hiding this comment.
Do we need a 30 second timeout? I suggest 9 seconds, to avoid slow update warning.
| self.faces = response['faces'] | ||
|
|
||
| else: | ||
| self.total_faces = "Request_failed" |
There was a problem hiding this comment.
This would change the type of total faces from integer to string. That will make it hard to use templates for this attribute.
I suggest that we don't update the total faces if there's an error. Or set it to 0.
There was a problem hiding this comment.
Or None? I don’t want to have users think a classification has been successful and that the face count is zero, when in fact the classification was unsuccessful
| response['success'] = False | ||
|
|
||
| if response['success']: | ||
| self.total_faces = response['facesCount'] |
There was a problem hiding this comment.
We shouldn't update these instance attributes directly but pass the faces and faces count through the process_faces method. That will fire an event with the face data and update the instance attributes.
There was a problem hiding this comment.
Face detect and face identify components work differently (confusingly). Face detect (this Pr) have a state which is the number of faces, whilst face identify components have a state which is a recognised face. I prefer the former so have avoided using process_face. If we want this to be a face identify component I will use process_faces.
My plan was to release this PR as a face detect and recommend launching the Docker with recognition turned off, to enable fast processing. I would release a subsequent component for recognition (face identify component) - a slower classification process
There was a problem hiding this comment.
We can still use process_faces. It will not fire events if there's no confidence set and no confidence attribute in the face dict. Just make sure faces and total are of correct types.
| else: | ||
| self._name = "Facebox {0}".format( | ||
| split_entity_id(camera_entity)[1]) | ||
| self.total_faces = 0 |
There was a problem hiding this comment.
This is already set in the parent class.
| self._name = "Facebox {0}".format( | ||
| split_entity_id(camera_entity)[1]) | ||
| self.total_faces = 0 | ||
| self.faces = [] |
| } | ||
|
|
||
|
|
||
| class TestFaceboxSetup(object): |
There was a problem hiding this comment.
You don't need to use a class for the tests. Just define test functions that have names starting with test_ Pass in hass as parameter to the functions to get a hass instance to test with. Setup and teardown is handled by pytest.
|
|
||
| with requests_mock.Mocker() as mock_req: | ||
| url = "http://{}:{}/facebox/check".format(MOCK_IP, MOCK_PORT) | ||
| mock_req.get(url, text=MOCK_RESPONSE) |
There was a problem hiding this comment.
Use the post method on the mock object to mock a post request.
https://requests-mock.readthedocs.io/en/latest/mocker.html#methods
drop face_detect from filename and component contents as this component will handle both detection and identification
MartinHjelmare
left a comment
There was a problem hiding this comment.
I said something inaccurate in a previous comment about process_faces and when it will fire events. Actually it's like this: it will always fire a face detected event if self.confidence is not truthy.
I still think we should use process_faces. It should give us the proper behavior for this implementation.
| base64_img = base64.b64encode(image).decode('ascii') | ||
| return {"base64": base64_img} | ||
|
|
||
| def get_matched_faces(self, response): |
There was a problem hiding this comment.
Maybe pass in faces as that's what we're using in the method?
|
@MartinHjelmare I agree that |
|
@MartinHjelmare I've basically copied the tests from the microsoft component but am getting errors which appear to relate to asyncio - any ideas what's wrong here? I didn't get this error when using the Perhaps I should follow this example and use |
MartinHjelmare
left a comment
There was a problem hiding this comment.
Yeah I'm not sure exactly why it fails with sync tests, but coroutines should work.
We should probably look into this some time. It's useful to not have to use coroutines in the tests when setting up components too.
| } | ||
|
|
||
|
|
||
| def test_setup_platform(hass): |
There was a problem hiding this comment.
Make the tests coroutines with async def.
| from homeassistant.setup import async_setup_component | ||
| import homeassistant.components.image_processing as ip | ||
|
|
||
| from tests.common import assert_setup_component |
There was a problem hiding this comment.
'tests.common.assert_setup_component' imported but unused
was mock_req.get
| with requests_mock.Mocker() as mock_req: | ||
| url = "http://{}:{}/facebox/check".format(MOCK_IP, MOCK_PORT) | ||
| mock_req.post(url, text=MOCK_RESPONSE) | ||
| ip.scan(hass, entity_id=VALID_ENTITY_ID) |
There was a problem hiding this comment.
Call the service directly with await hass.services.async_call(...). Since we're in a coroutine here, we have to use the hass async api consistently.
| url = "http://{}:{}/facebox/check".format(MOCK_IP, MOCK_PORT) | ||
| mock_req.post(url, text=MOCK_RESPONSE) | ||
| ip.scan(hass, entity_id=VALID_ENTITY_ID) | ||
| hass.block_till_done() |
There was a problem hiding this comment.
await hass.async_block_till_done()
| mock_req.post(url, text=MOCK_RESPONSE) | ||
| await hass.services.async_call(ip.DOMAIN, | ||
| 'scan', | ||
| {'entity_id': VALID_ENTITY_ID}) |
There was a problem hiding this comment.
@MartinHjelmare this is giving confusing error:
simplejson.errors.JSONDecodeError: Expecting value: line 3 column 12 (char 30)
core.py 399 INFO Bus:Handling <Event service_executed[L]: service_call_id=4368981800-1>
|
@MartinHjelmare any ideas about the test service call which is giving the error: |
* Add sensors for electric cars * Updates based on review of @MartinHjelmare * Fix Travis error * Another fix for Travis
* Add support for shutter contact and motion detector device * Add support for power switch devices * Add support for light switch device * Cleanup binary_switch and light platform * Update comment
* add 2 devices io:RollerShutterUnoIOComponent io:ExteriorVenetianBlindIOComponent * add 2 devices * Update tahoma.py * Fix hounci-bot violation * Fixed Travis CI build failure ./homeassistant/components/cover/tahoma.py:83:13: E125 continuation line with same indent as next logical line * Fixed Travis CI build failure E125 continuation line with same indent as next logical line * Fixed Travis CI build failure E127 continuation line over-indented for visual indent * Fix indent * Change check
* Gogogate2 - bump version Uses latest version of library which ensures commands to device are idempotent * Update requirements_all * Expose sensor temperature * update version * import attribute * Set temperature * Remove temperature attribute Removed temperature attribute until it can be re-implemented as a separate sensor. * Update ordering * Fix copy-&-paste issue
* Added solt values for siteId and probability * Update snips.py * Update test_snips.py
* Add help for conversation/process service * Add logging to debug text received when service is called * Move conversation to specific folder
…14251) * When zwave node's info is parsed remove it and re-add back. * Delay value entity if not ready * If node is ready consider it parsed even if manufacturer/product are missing. * Add annotations
* Improving icloud device tracker * Adding config validations for new values * Adding config validations for new values * Moving icloud specific setup to platform schema. Setting default in platform schema.
* Starting to add attributes * All attributes added to programs * Basic zone attributes in place * Added advanced properties for zones * Working to move common logic into component + dispatcher * We shouldn't calculate the MAC with every entity * Small fixes * Small adjustments * Owner-requested changes * Restart * Restart part 2 * Added ID attribute to each switch * Collaborator-requested changes
* Waze Travel Time: optional inclusive/exclusive filters Added optional `inc_filter` and `excl_filter' params that allow to refine the reported routes: the first is not always the best/desired. A simple case-insensitive filtering (no regular expression) is used. * fix line lenght * fix spaces * Rename var * Fix typo * Fix missing var
* Ignore NaN values for influxdb * Catch TypeError
* Add zone 3 for Onkyo media player * CR Updates * Fix travis lint errors
|
@MartinHjelmare thanks for fixing the test, I wouldn't have guessed that solution. |
|
The branch is whack again. |
|
Oh bugger |
Replaces #14279
Description:
Adds component for face detection (number of faces) and identification (recognition of taught faces) using facebox. Run facebox with:
Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.github.io#<5300>
Example entry for
configuration.yaml(if applicable):Checklist:
tox. Your PR cannot be merged unless tests passIf user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
REQUIREMENTSvariable ([example][ex-requir]).requirements_all.txtby runningscript/gen_requirements_all.py..coveragerc.If the code does not interact with devices: