guysie / ha-meural Goto Github PK
View Code? Open in Web Editor NEWIntegration for NETGEAR Meural Canvas digital art frame in Home Assistant
License: MIT License
Integration for NETGEAR Meural Canvas digital art frame in Home Assistant
License: MIT License
The Meural Canvas syncs to the cloud server irregularly. If network details like the local IP change, it can take hours or days for this information to be updated on the server.
When Home Assistant starts up, this integration gets the local IP from the cloud server. If this IP is incorrect, the integration will fail to set up a Canvas device. This can only be resolved by restarting Home Assistant after the correct local Canvas IP has been synced to the cloud server.
Currently the list of playlists (galleries) that can be selected as an input source are created by combining all available device galleries with all available user galleries. It is possible for a user gallery to exist, but not be synced to the device yet. select_source will attempt to switch to this unsynced gallery using a local call and fail. We should instead detect if a gallery has not been synced to the device yet, and then use a Meural API call to upload it to the device.
NETGEAR has recently added the option to enable 2 factor authentication to their account system. Current integration authentication only works with regular login and password. We should support users that have enabled 2FA on their accounts.
Sometime today the Meural stopped working, lots of these:
2022-02-05 19:48:18 ERROR (MainThread) [homeassistant.helpers.entity] Update for media_player.meural_eg fails
aiohttp.client_exceptions.ClientResponseError: 401, message='Unauthorized', url=URL('https://api.meural.com/v0/devices/***')
I thought OK - typical re-auth situation (as this usually is 401 error)...
When I deleted the integration and tried to run setup again, it fails with this error
[%key:common::config_flow::abort::cannot_connect%]
Login in Meural Web and App are working fine, Meural can be controlled this way.
Anything going on?
I just installed v1.0.2 into my hass virtualenv install and have this error accessing the API:
2020-08-08 11:54:16 ERROR (MainThread) [homeassistant.components.media_player] Error while setting up meural platform for media_player
Traceback (most recent call last):
File "/srv/homeassistant/lib/python3.8/site-packages/homeassistant/helpers/entity_platform.py", line 187, in _async_setup_platform
await asyncio.gather(*pending)
File "/srv/homeassistant/lib/python3.8/site-packages/homeassistant/helpers/entity_platform.py", line 293, in async_add_entities
await asyncio.gather(*tasks)
File "/srv/homeassistant/lib/python3.8/site-packages/homeassistant/helpers/entity_platform.py", line 450, in _async_add_entity
await entity.async_added_to_hass()
File "/home/homeassistant/.homeassistant/custom_components/meural/media_player.py", line 158, in async_added_to_hass
self._current_item = await self.meural.get_item(int(self._gallery_status["current_item"]))
File "/home/homeassistant/.homeassistant/custom_components/meural/pymeural.py", line 93, in get_item
return await self.request("get", f"items/{item_id}")
File "/home/homeassistant/.homeassistant/custom_components/meural/pymeural.py", line 46, in request
resp = await self.session.request(
File "/srv/homeassistant/lib/python3.8/site-packages/aiohttp/client.py", line 588, in _request
resp.raise_for_status()
File "/srv/homeassistant/lib/python3.8/site-packages/aiohttp/client_reqrep.py", line 941, in raise_for_status
raise ClientResponseError(
aiohttp.client_exceptions.ClientResponseError: 403, message='Forbidden', url='https://api.meural.com/v0/items/162212'
I know that the username and password I entered when setting up the integration are correct.
First of all, because of this integration I got interested in Meural and am a very happy user for a few years now :-) Thank you very much for creating this integration.
We have "many" playlists on our canvas. The downside of the playlists is that they can sometimes be beautiful and boring at the same time. For example, when going through 32 planets, after 6 we would like to see a different one. Ultimately, we would like the Meurals to shuffle between playlists and images (but I couldn't find settings that can do this, only shuffle images inside a playlist).
It would be great if we could select a random playlist, or even a random item. I checked the source, it is possible to browse galleries, but this is not exposed via a service? I think there could be a service call play_random_item
that picks a random gallery and random image to play. Not sure about the performance of switching playlists though.
We've already severely cut back on calls to the Meural API where possible, e.g. no calls are made when the device is sleeping, and all calls to change item or playlist are made locally if possible.
But there are options - like image duration and shuffle - that are only exposed via the device options in the Meural API, and not exposed in the local interface at all. The integration currently polls the Meural API every 10 seconds to update this information.
We should find a way to reduce these calls to the Meural API too.
Thumbnails for the mediabrowser are requested from the Meural server, based on the IDs of galleries on the local device. The gallery ID that represents albums in the local device does not match the album ID that is used on the Meural server side.
Furthermore, as of yet we do not know the API calls to retrieve lists of albums or their details from the Meural server. As a result we can't find the correct thumbnail for an album.
I have 12 Meurals. This integration works beautifully for the first 10. But the last two installed are not retrieved.
Item information is currently pulled from the Meural server. But the Meural server does not know anything about the images on the local SD card. If we want to be able to display item information, we need to be able to get this from the local device instead.
Home assistant gets its icons and logos from:
https://github.com/home-assistant/brands
This also works for custom components. Meural is not yet listed here, so there is no logo available in Home Assistant for this integration.
Hello, great work on this integration!
I have 2 Meurals, both seemed to be added without issue during the setup process. However, one of the Meurals seems to work perfectly in HA while the other was instantly "Unavailable" and HA does not appear to be getting any information from it. Both Meurals are "Online" in the Meural Netgear App and I have tried power cycling the "Unavailable" Meural to no avail.
Do you have any suggestions on what I can try to get the 2nd Meural working like the other one?
Hello Guy! Cool project. I am using some of your code as a reference while making my own project - something to display images from the MET on my Meural. I don't have the home assistant so I'm just robbing some of your python code to make it work.
Anyway I found an bug that I think I should tell you about, in case you hit it. I got AIOHTTP to choke on some image file and crash. This is from LocalMeural.sendPostcard
if you give it this url, aiohttp crashes
https://images.metmuseum.org/CRDImages/ep/original/DT1567.jpg
[22-03-19-0:03:51 ladyred] ~/Code/Meural > python3 main.py
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/aiohttp/client_reqrep.py", line 898, in start
message, payload = await protocol.read() # type: ignore[union-attr]
File "/usr/local/lib/python3.8/site-packages/aiohttp/streams.py", line 616, in read
await self._waiter
File "/usr/local/lib/python3.8/site-packages/aiohttp/client_proto.py", line 213, in data_received
messages, upgraded, tail = self._parser.feed_data(data)
File "aiohttp/_http_parser.pyx", line 551, in aiohttp._http_parser.HttpParser.feed_data
aiohttp.http_exceptions.BadHttpMessage: 400, message='Invalid header value char'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "main.py", line 21, in <module>
asyncio.run(main())
File "/usr/local/Cellar/[email protected]/3.8.8_1/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/local/Cellar/[email protected]/3.8.8_1/Frameworks/Python.framework/Versions/3.8/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
return future.result()
File "main.py", line 16, in main
gal_stat = await lm.send_postcard(URL, "image/jpeg")
File "/Users/ladyred/Code/Meural/meural/pymeural.py", line 190, in send_postcard
response = await self.session.get(url)
File "/usr/local/lib/python3.8/site-packages/aiohttp/client.py", line 559, in _request
await resp.start(conn)
File "/usr/local/lib/python3.8/site-packages/aiohttp/client_reqrep.py", line 900, in start
raise ClientResponseError(
aiohttp.client_exceptions.ClientResponseError: 400, message='Invalid header value char', url=URL('https://images.metmuseum.org/CRDImages/ep/original/LC-EP_1993_132_suppl_CH-001.jpg')
So I think it is some bug with aiohttp - that it can't handle the response of the server. Maybe it is based on aiohttp version? I have a pretty recent version.
[22-03-19-0:51:07 ladyred] ~/Code/Meural > pip3 list | grep aiohttp
aiohttp 3.8.1
Anyway, you may hit it if you try this data source (the met) or that aiohttp version.
PS I rewrote it with requests library and it works fine. So it is a library issue
response = requests.get(url)
image = response.content
files = {'photo': ("photo", image, content_type, "")}
PS my man, did you ever find a solution to the canvas showing the previous uploaded postcard when you hit the remote endpoint? I guess it is a meural bug but did you find any workaround?
Meural has introduced a new Photo Frame product:
https://meural.netgear.com/photo-frame/
It is currently unknown if HA-meural works with the Photo Frame, as we have no device to test with.
play_media will call the Meural API to load an item, if this item is not available in the currently displayed playlist. If the item is not available to the Canvas device in the Meural API (because it doesn't exist, or because we don't have subscription access to the item) we'll receive a bad request response. play_media currently does not handle this response.
Meural has added an additional type of collected images to their system, called Albums. These are linked to corresponding albums on your smartphone and synced by the Meural app. We currently only support displaying Playlists, but should add support for Albums.
I've installed HA-Meural and completed the setup. The media player never starts.
This error originated from a custom integration.
Logger: homeassistant.core
Source: custom_components/meural/pymeural.py:146
Integration: Meural (documentation, issues)
First occurred: 10:41:35 PM (5 occurrences)
Last logged: 10:54:06 PM
Error executing service: <ServiceCall media_player.turn_on (c:01GJ4GN7Z70WTPDW8CSCE7499N): entity_id=['media_player.meural']>
Error executing service: <ServiceCall media_player.turn_on (c:01GJ4GNXN65GR4PSB5R2BWFMNR): entity_id=['media_player.meural']>
Error executing service: <ServiceCall media_player.turn_on (c:01GJ4GVGVDT3G2TDXGTSNA24NB): entity_id=['media_player.meural']>
Error executing service: <ServiceCall media_player.turn_on (c:01GJ4GX9DS1MBB4E5EKGD38XAP): entity_id=['media_player.meural']>
Error executing service: <ServiceCall media_player.turn_on (c:01GJ4HC577X3HF6Q3FRA3SB49W): entity_id=['media_player.meural']>
Traceback (most recent call last):
File "/config/custom_components/meural/pymeural.py", line 147, in request
resp = await self.session.request(
File "/usr/local/lib/python3.10/site-packages/aiohttp/client.py", line 535, in _request
conn = await self._connector.connect(
File "/usr/local/lib/python3.10/site-packages/aiohttp/connector.py", line 542, in connect
proto = await self._create_connection(req, traces, timeout)
File "/usr/local/lib/python3.10/site-packages/aiohttp/connector.py", line 907, in _create_connection
_, proto = await self._create_direct_connection(req, traces, timeout)
File "/usr/local/lib/python3.10/site-packages/aiohttp/connector.py", line 1175, in _create_direct_connection
transp, proto = await self._wrap_create_connection(
File "/usr/local/lib/python3.10/site-packages/aiohttp/connector.py", line 986, in _wrap_create_connection
return await self._loop.create_connection(*args, **kwargs) # type: ignore[return-value] # noqa
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 1049, in create_connection
sock = await self._connect_sock(
File "/usr/local/lib/python3.10/asyncio/base_events.py", line 960, in _connect_sock
await self.sock_connect(sock, address)
File "/usr/local/lib/python3.10/asyncio/selector_events.py", line 500, in sock_connect
return await fut
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/core.py", line 1762, in catch_exceptions
await coro_or_task
File "/usr/src/homeassistant/homeassistant/core.py", line 1781, in _execute_service
await cast(Callable[[ServiceCall], Awaitable[None]], handler.job.target)(
File "/usr/src/homeassistant/homeassistant/helpers/entity_component.py", line 208, in handle_service
await service.entity_service_call(
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 678, in entity_service_call
future.result() # pop exception if have
File "/usr/src/homeassistant/homeassistant/helpers/entity.py", line 943, in async_request_call
await coro
File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 715, in _handle_entity_call
await result
File "/config/custom_components/meural/media_player.py", line 469, in async_turn_on
await self.local_meural.send_key_resume()
File "/config/custom_components/meural/pymeural.py", line 174, in send_key_resume
return await self.request("get", f"control_command/resume")
File "/config/custom_components/meural/pymeural.py", line 146, in request
with async_timeout.timeout(10):
File "/usr/local/lib/python3.10/site-packages/async_timeout/init.py", line 116, in exit
self._do_exit(exc_type)
File "/usr/local/lib/python3.10/site-packages/async_timeout/init.py", line 212, in _do_exit
raise asyncio.TimeoutError
asyncio.exceptions.TimeoutError
Because the meural integration supports service play_media, the TTS input is automatically added to the entity settings of the media control card. However, the meural has no speakers and is incapable of TTS.
When looking for Meural in the integrations list a placeholder icon is shown. Icon refers to:
https://brands.home-assistant.io/_/meural/icon.png
which does not exist yet, but:
https://brands.home-assistant.io/meural/icon.png
does.
Cache issue?
Home Assistant 115 added the new features Media Browser and Media Sources:
https://www.home-assistant.io/blog/2020/09/17/release-115/#media-browser
We should support Media Browser, allowing the user to visually browse through the galleries available on the Meural device.
We should support Media Sources, allowing the user to play compatible media made available by other HA integrations.
The full list of formats supported by the Meural according to the Netgear KB is:
.jpg, .jpeg, .png, .bmp, .svg, .gif, .mp4, .mov, and .heic (iOS Live Photos).
We currently only support previewing jpg/jpeg and png images. Should see if the preview functionality supports all other formats noted as well.
https://kb.netgear.com/000060767/Which-image-and-video-formats-does-the-Meural-Canvas-support
Entities that have a unique ID allow the user to change the name and entity ID without restarting Home Assistant. It also makes sure that your entity ID is reserved for this entity.
Unique ID should be a unique identifier like a serial number or mac address.
I just updated the firmware on my Canvas II and the Mini Media card for my Canvas II is now showing unavailable.
This was working for me when I first started using it, but is now out of sync - and reloading or skipping to the next image does not fix the issue. All the details about the image is an image in the current playlist but just not the right one. Even the image names do not match.
Make a service meural.preview_image that use the /remote/postcard
local call to preview the image available at a given URL.
API errors are now excepted with a simple logger message; for troubleshooting the logger should return the actual error response.
If orientationMatch is enabled on the Canvas device, the device will automatically switch to an item in the right orientation when the orientation of the device changes. However, the current_item in gallery_status - which we use to detect when we need to get new item details - does not update when this happens. We currently reload the gallery when we detect an orientation change to force an update of current_item, but this can cause flickering or a change in displayed item on the device. It would be preferable to find a way to update current_item that is not visible to the user.
Thanks for the integration! I’ve not purchased one of these devices but am interested. Got a couple questions if you can help:
I'd like to start by saying that this integration overall is awesome; the control of the Meural works really well, quickly and easily, Bravo!
However, one bug is that I have our canvas set to reverse the gesture direction (it feels more natural for swiping images back and forth) and the media 'forward' and 'back' controls are swapped within HA. Hopefully a simple fix of reading that setting from Netgear/Meural, or adding an toggle option in the add-on settings to reverse the control directions.
Obviously there's an easy workaround for now, so definitely not a high priority issue.
Thanks!
While using the postcard/preview function to temporarily play images on the Canvas, the currently played item information is not updated. This is by design in the Canvas, as the preview function is a temporary override that will automatically disappear - the currently played item is still playing, it's just showing something else right now.
However, this may be confusing for users for whom the HA interface offers no difference between playing or previewing images.
The local call /remote/postcard/ can be used to temporarily override the currently displayed item on the Canvas device. We should support this call so users can send any images (even non-artwork ones) to the Canvas device, especially for automation purposes (e.g. automatically displaying an image of who is ringing the doorbell).
The media type reported to HA by this integration is Music, because this allows us to use media_title for artwork name and media_artist for the artist name. Using media type image instead does not display media_artist in the media control card. But factually this is incorrect information, as we are NOT playing music.
Local galleries are retrieved using "get_galleries_json". Remote galleries on Meural server are retrieved by combining "user/galleries" and "devices/{device_id}/galleries". We expect the list of local and remote galleries to be the same, but often they are not. We currently resolve this by using the local gallery list as the 'truth', but that does not fix the problem.
We should figure out why there are discrepancies between lists of local galleries and remote galleries.
With the introduction of albums the Meural Canvas no longer correctly reports the currently played set of items using currentGallery. If an album is played, currentGallery will still report the ID of the last playlist played. All functionality that depends on currentGallery should be rewritten to rely on currentlyPlaying instead, which reports both ID and type (either gallery or album).
It seems the authorization token expires after a longer period of time - several months maybe? Requiring the user to reinstall the integration to get a new token. The device will be unavailable once the token expires.
We should, if we detect the token has expired and the integration is no longer authorised to access the API, request the user fill in their login and password again to get a new token.
Playlists for the device populate when Home Assistant starts. If user or device playlists change while Home Assistant is running they will not update. We should not have to restart Home Assistant to see new playlists.
Additionally, because the playlists are populated with both device and user playlists, some playlists can be in the list which are not synced to the device yet. This leads to the issues in #5.
If we only populate with device playlists, polled from the local device during the update loop, playlist management can be off-loaded to the Meural app and web interface.
Many Home Assistant users only install custom components via HACS. This integration is not yet available in HACS but we should make it available there.
For an integration to be added to HACS we'll need to follow their guidelines:
https://hacs.xyz/docs/publish/start
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.