Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
Core
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
mirrored_repos
HomeAssistant
Core
Commits
9c5a79c6
Unverified
Commit
9c5a79c6
authored
3 years ago
by
Allen Porter
Committed by
GitHub
3 years ago
Browse files
Options
Downloads
Patches
Plain Diff
Add an image placeholder for Nest WebRTC cameras (#58250)
parent
6d30105c
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
homeassistant/components/nest/camera_sdm.py
+43
-1
43 additions, 1 deletion
homeassistant/components/nest/camera_sdm.py
tests/components/nest/test_camera_sdm.py
+9
-5
9 additions, 5 deletions
tests/components/nest/test_camera_sdm.py
with
52 additions
and
6 deletions
homeassistant/components/nest/camera_sdm.py
+
43
−
1
View file @
9c5a79c6
...
...
@@ -3,9 +3,11 @@ from __future__ import annotations
from
collections.abc
import
Callable
import
datetime
import
io
import
logging
from
typing
import
Any
from
PIL
import
Image
,
ImageDraw
,
ImageFilter
from
google_nest_sdm.camera_traits
import
(
CameraEventImageTrait
,
CameraImageTrait
,
...
...
@@ -38,6 +40,15 @@ _LOGGER = logging.getLogger(__name__)
# Used to schedule an alarm to refresh the stream before expiration
STREAM_EXPIRATION_BUFFER
=
datetime
.
timedelta
(
seconds
=
30
)
# The Google Home app dispays a placeholder image that appears as a faint
# light source (dim, blurred sphere) giving the user an indication the camera
# is available, not just a blank screen. These constants define a blurred
# ellipse at the top left of the thumbnail.
PLACEHOLDER_ELLIPSE_BLUR
=
0.1
PLACEHOLDER_ELLIPSE_XY
=
[
-
0.4
,
0.3
,
0.3
,
0.4
]
PLACEHOLDER_OVERLAY_COLOR
=
"
#ffffff
"
PLACEHOLDER_ELLIPSE_OPACITY
=
255
async
def
async_setup_sdm_entry
(
hass
:
HomeAssistant
,
entry
:
ConfigEntry
,
async_add_entities
:
AddEntitiesCallback
...
...
@@ -62,6 +73,30 @@ async def async_setup_sdm_entry(
async_add_entities
(
entities
)
def
placeholder_image
(
width
:
int
|
None
=
None
,
height
:
int
|
None
=
None
)
->
Image
:
"""
Return a camera image preview for cameras without live thumbnails.
"""
if
not
width
or
not
height
:
return
Image
.
new
(
"
RGB
"
,
(
1
,
1
))
# Draw a dark scene with a fake light source
blank
=
Image
.
new
(
"
RGB
"
,
(
width
,
height
))
overlay
=
Image
.
new
(
"
RGB
"
,
blank
.
size
,
color
=
PLACEHOLDER_OVERLAY_COLOR
)
ellipse
=
Image
.
new
(
"
L
"
,
blank
.
size
,
color
=
0
)
draw
=
ImageDraw
.
Draw
(
ellipse
)
draw
.
ellipse
(
(
width
*
PLACEHOLDER_ELLIPSE_XY
[
0
],
height
*
PLACEHOLDER_ELLIPSE_XY
[
1
],
width
*
PLACEHOLDER_ELLIPSE_XY
[
2
],
height
*
PLACEHOLDER_ELLIPSE_XY
[
3
],
),
fill
=
PLACEHOLDER_ELLIPSE_OPACITY
,
)
mask
=
ellipse
.
filter
(
ImageFilter
.
GaussianBlur
(
radius
=
width
*
PLACEHOLDER_ELLIPSE_BLUR
)
)
return
Image
.
composite
(
overlay
,
blank
,
mask
)
class
NestCamera
(
Camera
):
"""
Devices that support cameras.
"""
...
...
@@ -212,7 +247,14 @@ class NestCamera(Camera):
# Fetch still image from the live stream
stream_url
=
await
self
.
stream_source
()
if
not
stream_url
:
return
None
if
self
.
frontend_stream_type
!=
STREAM_TYPE_WEB_RTC
:
return
None
# Nest Web RTC cams only have image previews for events, and not
# for "now" by design to save batter, and need a placeholder.
image
=
placeholder_image
(
width
=
width
,
height
=
height
)
with
io
.
BytesIO
()
as
content
:
image
.
save
(
content
,
format
=
"
JPEG
"
,
optimize
=
True
)
return
content
.
getvalue
()
return
await
async_get_image
(
self
.
hass
,
stream_url
,
output_format
=
IMAGE_JPEG
)
async
def
_async_active_event_image
(
self
)
->
bytes
|
None
:
...
...
This diff is collapsed.
Click to expand it.
tests/components/nest/test_camera_sdm.py
+
9
−
5
View file @
9c5a79c6
...
...
@@ -135,7 +135,7 @@ async def fire_alarm(hass, point_in_time):
await
hass
.
async_block_till_done
()
async
def
async_get_image
(
hass
):
async
def
async_get_image
(
hass
,
width
=
None
,
height
=
None
):
"""
Get image from the camera, a wrapper around camera.async_get_image.
"""
# Note: this patches ImageFrame to simulate decoding an image from a live
# stream, however the test may not use it. Tests assert on the image
...
...
@@ -145,7 +145,9 @@ async def async_get_image(hass):
autopatch
=
True
,
return_value
=
IMAGE_BYTES_FROM_STREAM
,
):
return
await
camera
.
async_get_image
(
hass
,
"
camera.my_camera
"
)
return
await
camera
.
async_get_image
(
hass
,
"
camera.my_camera
"
,
width
=
width
,
height
=
height
)
async
def
test_no_devices
(
hass
):
...
...
@@ -721,9 +723,11 @@ async def test_camera_web_rtc(hass, auth, hass_ws_client):
assert
msg
[
"
success
"
]
assert
msg
[
"
result
"
][
"
answer
"
]
==
"
v=0
\r\n
s=-
\r\n
"
# Nest WebRTC cameras do not support a still image
with
pytest
.
raises
(
HomeAssistantError
):
await
async_get_image
(
hass
)
# Nest WebRTC cameras return a placeholder
content
=
await
async_get_image
(
hass
)
assert
content
.
content_type
==
"
image/jpeg
"
content
=
await
async_get_image
(
hass
,
width
=
1024
,
height
=
768
)
assert
content
.
content_type
==
"
image/jpeg
"
async
def
test_camera_web_rtc_unsupported
(
hass
,
auth
,
hass_ws_client
):
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment