Is there always only 1 medias
?
Iâm guessing this is from the Automation? I believe itâs the âlatestâ post-card picture in that [0] media. Iâm just using it to download the latest postcard picture to HA, so I can use the picture from âanywhereâ (because I put it in the www folder). But @madcoder has since updated the BB-integration and you can now just use the âentityâ picture instead if you want.
medias[0]
is basically the first photo in the postcard. If you were opening the postcard in the app, it would be the first photo you see. There are often more images in the postcard, but thereâs no real criteria to go on, in order to determine the âbestâ image from the postcard, so we just use the first image to keep it simple. We could potentially be a little smarter about that, and maybe decode the report token in order to use the media id with the highest confidence of species recognition - on the assumption that the best/clearest photos will have the highest confidence scores. However, I believe when a photo is marked as a ârecognizedâ species, it assigns confidence=100%, so that might not help much.
With the new Recent Visitor entity, it pulls the same first image from new postcards. Before the first postcard (i.e., after restarting HA or reloading the integration), it scans the collections looking for the most recent visit for a species, and then uses the most recent image of that most recent species.
Would it be an option to include the complete array in the recent visitor entity? Then I can save them all
Not really â the Recent Visitor entity is just sensor. The value is the species name, and entity_picture
is the URL of an image. Home Assistant requires that be a single URL, so we canât really do that (one entity = one url). It would be possible to expose the rest of them as extra attributes, but HA warns against overusing (or misusing) attributes, because of how the state history works and how it writes data to the database.
If you want to use an automation like the examples earlier in this thread, you can use the downloader
service to download as many of the media URLs as youâd like. I donât know the easiest way to do that, so you would have to play around with the right kind of automation or script combination to download multiple URLs. Particularly, you need to be able to iterate the medias
array, because the number of elements in each postcard can be different. Some might only have one image, some might have any other number of images (the only guarantee is that it wonât be empty!)
But it might depend on the use case youâre looking for. Do you just want to be able to see all the various images of birds, grouped by species? Cause you can do that in the Media browser (in HA sidebar, click Media, then Bird Buddy). That shows all the collections just like the BB app does. You donât have to download and save all the media yourself, because once a postcard is collected those images are saved in your Bird Buddy collections. They donât yet offer a way to download your collection all at once, but I wouldnât be surprised if eventually they do.
Or do you want to see all of the individual sightings and images grouped together by postcard? Cause at that point thatâs pretty much what the Bird Buddy app does. Once a postcard is collected, the feed turns into a list of visits and images.
I guess I could add another section to the Bird Buddy media browser that groups them by visit (i.e., feed items in the BB app). But you would still need to find a way to get a media directory surfaced in lovelace, and I donât yet know of an easy way to do that. Even using a media-source://
URI I wasnât able to get it to load or proxy images from the media browser, other than using the actual Bird Buddy content or thumbnail URLs from the postcard media.
The use case would be: Iâm paranoid
Itâs more a case of âI donât trust cloud services in the long (multi-year) runâ and want to download them to storage I trust. Or: Iâm a hoarder
I was indeed thinking to just iterate over that array and download them all. I will play with that.
Do you have raw json examples perhaps to play with? (Iâm in the same boat where I donât have much bird visitors to test with)
Edit, solved my own question:
repeat:
count: "{{ trigger.event.data.sighting.medias | length }}"
sequence:
- service: downloader.download_file
data:
url: "{{ trigger.event.data.sighting.medias[repeat.index - 1].contentUrl }}"
subdir: birdy
filename: >-
{{ (as_timestamp(now())-(0)) | timestamp_custom('%Y-%m-%d_%H-%M-%S') }}-birdy-{{ repeat.index }}.jpg
overwrite: true
By the way, as an idea to display birds, this could help: GitHub - craibo/ha_strava: Strava Activities and Summary data integration for Home Assistant
The strava integration has a camera
entity which rotates an image every X seconds: ha_strava/camera.py at eedbe6983eb454c07fbb44791dee34f5687eb47a ¡ craibo/ha_strava ¡ GitHub
Maybe you can borrow the same functionality to display a camera with last entries?
Edit:
This could probably be a solution too: GitHub - jodur/imagesdirectory-camera: Camera entity for images, to create a slidehow or timelapse from images in a directory. The camra support browsing manually trough the slideshow also. The creation of anmiated Gif or mp4 is also supported by services
Since I have the snapshots in a directory, I can slideshow them
Awesome! Thank you for sharing the sample, thatâs exactly what I had in mind.
For what itâs worth, you can also use the medias[].createdAt
attribute, to get a timestamp from it. Itâll be in this format: createdAt: '2023-01-23T19:12:58.779Z'
. That will also be the actual timestamp of the BB media, whereas what you have now is using the timestamp of now
, which is whenever the automation runs. The default polling interval is 10 minutes, so your timestamp could be 10 minutes or more after the actual image was taken, while createdAt
will be when the image was uploaded to the cloud.
As for sample JSON that you can expect, youâll see that when you get your first triggered automation. When you go to Traces for the automation, you can click on âChanged variablesâ tab, and youâll see the full YAML. I also recently added a unit test to pybirdbuddy
with a fixture that mimics the payload. These top-level fixture attributes will be inside the trigger.event.data.*
model. You can also inspect the GraphQL schema if you really want to know all the possibilities.
However, if your goal is simply to create a backup of all your images, a much easier (or at least more resilient long-term) way to do that would be to write a separate python script utilizing the pybirdbuddy
library (underlying library behind the HA integration - I wrote both). That has functions for things like refreshing the list of collections, and inspecting all the media in each collection. You could use that to download each image individually. One thing youâll run into is how to avoid re-downloading images youâve already downloaded before. The createdAt
+repeat.index
can help with that. Or you can use the medias[].id
UUID as or in the filename, to determine if the file already exists, so you can skip it if you already have it.
I recommend the separate script instead, because with the postcard automation the automation will only trigger when a new previously unseen postcard arrives in the feed. If you open a postcard in the BB app yourself for example, then that postcard will never arrive in HA. But the library can iterate the entire collections.
Another idea that still runs as a separate script, but doesnât require iterating the entire list of all media in every collection, would be a script that works similar to how this integrationâs ânew postcardâ automation trigger works: Use pybirdbuddy to monitor the feed, using the refresh_feed( [, since=$lastTimestamp ] )
function. Youâll get the feed items that appear in the BB feed (each one with one of these types). If you filter those to FeedItemSpeciesSighting
or FeedItemSpeciesUnlocked
, each one will contain the media info for each individual sighting (i.e., same as the sightings that come into the automation trigger). Then once youâve processed a batch of feed items, you would save the feed.newest_edge.node.created_at
timestamp (to a file or whatever), and use that in the next call to refresh_feed(since=$lastTimestamp)
. One risk in doing this, would be if thereâs a non-sighting feed item that later becomes a sighting feed item (such as if it was a postcard feed item that later got collected, and now itâs a new sighting with an older timestamp).
I did have the idea to replicate the GenericCamera
entity (which is built in, and if you look up earlier in this thread, that was the simplest suggestion for getting the âRecent Visitorâ entity image to appear in the âPicture Entityâ card). Having it be part of the integration would remove the need to set it up manually, and would also remove the need for the Recent Visitor entity_picture. And once we have that, itâs not a stretch to expand on that functionality, supporting multiple URLs or media folders, and so on.
What I was trying to avoid is recreating something that already exists, if I can avoid it. Generic Camera already exists. The entities above that you link to, already exist. HA is designed to be intertwined, so if thereâs a Lovelace card or another integration that does what you want, then I think itâs reasonable and expected that you would just combine those together. This integration is not really geared towards presenting multiple forms of media in multiple ways - it has a specific focus, which is to surface the Bird Buddy metrics to HA, and pulling in the media is a bonus.
If you can find one that does the same thing by accessing a media-source://
URI to an image or directory of images, then thatâs perfect. Because then BB integration exposes the media in the media browser, and all you have to do is give that other entity the media-source URI, and itâs done.
Thanks for the suggestions, Iâve changed it now to:
alias: "[Birdy] Download new postcard sighting"
description: ""
trigger:
- platform: event
event_type: birdbuddy_new_postcard_sighting
condition: []
action:
- service: birdbuddy.collect_postcard
data:
strategy: best_guess
best_guess_confidence: 10
postcard: "{{ trigger.event.data.postcard }}"
sighting: "{{ trigger.event.data.sighting }}"
enabled: false
- service: downloader.download_file
data:
url: "{{ trigger.event.data.sighting.medias[0].contentUrl }}"
subdir: birdy
filename: last_postcard.jpg
overwrite: true
- repeat:
count: "{{ trigger.event.data.sighting.medias | length }}"
sequence:
- service: downloader.download_file
data:
url: >-
{{ trigger.event.data.sighting.medias[repeat.index - 1].contentUrl }}
subdir: birdy
filename: >-
{{ trigger.event.data.sighting.medias[repeat.index - 1].createdAt }}-birdy-{{ trigger.event.data.sighting.medias[repeat.index - 1].id }}.jpg
overwrite: true
- service: notify.david_devices
data:
title: Birdy Spotted!
message: A bird has been spotted, go check it out.
data:
group: ha-notification-group
tag: bird-buddy-sighting
push:
interruption-level: passive
mode: single
This results in:
Which is ok for my requirements just now, no need to make it âcomplexâ by writing a script. I realize the limitations Iâm exposing myself too with regards to opening in the BB app beforehand. I let HA be very much in control mostly though. It sends me a notification on a new sighting too, which pushes me to open the BB app (by then HA has already downloaded the sightings)
For now Iâm sticking to Picture entity to show the last one
If it inspires somebody, my view so far:
The yaml for this dashboard, also I agree it can be made simpler, but it does itâs job for now
- theme: Backend-selected
title: Bird Buddy
path: bird-buddy
icon: mdi:bird
type: custom:horizontal-layout
badges: []
cards:
- show_state: true
show_name: false
camera_view: auto
type: picture-entity
entity: sensor.birdy_recent_visitor
tap_action:
action: none
hold_action:
action: none
camera_image: camera.birdy
aspect_ratio: 3x4
- type: custom:apexcharts-card
graph_span: 5days
hours_12: false
header:
show: true
show_states: true
colorize_states: true
title: Batterij
series:
- entity: sensor.birdy_battery
type: area
stroke_width: 2
opacity: 0.3
fill_raw: last
name: Batterij
color: '#FFE15D'
show:
in_header: true
name_in_header: false
apex_config:
xaxis:
tooltip:
enabled: false
legend:
show: false
grid:
borderColor: '#7B7B7B'
chart:
foreColor: '#7B7B7B'
toolbar:
show: false
- type: vertical-stack
cards:
- type: custom:mushroom-update-card
entity: update.birdy_firmware_update
name: Firmware
hold_action:
action: none
double_tap_action:
action: none
show_buttons_control: false
collapsible_controls: false
icon: mdi:bird
- type: custom:mushroom-template-card
entity: sensor.birdy_feeder_state
tap_action:
action: more-info
icon: mdi:bird
icon_color: >-
{% if is_state(entity, 'DEEP_SLEEP') %}grey{% elif
is_state(entity, 'FIRMWARE_UPDATE') %}orange{% elif
is_state(entity, 'OFFLINE') %}red{% elif is_state(entity,
'OFF_GRID') %}red{% elif is_state(entity, 'ONLINE') %}green{% elif
is_state(entity, 'OUT_OF_FEEDER') %}red{% elif is_state(entity,
'READY_TO_STREAM') %}green{% elif is_state(entity, 'STREAMING')
%}green{% elif is_state(entity, 'TAKING_POSTCARDS') %}green{%
endif %}
primary: Status
secondary: >-
{% if is_state(entity, 'DEEP_SLEEP') %}Deep Sleep{% elif
is_state(entity, 'FIRMWARE_UPDATE') %}Firmware Update{% elif
is_state(entity, 'OFFLINE') %}Offline{% elif is_state(entity,
'OFF_GRID') %}Off Grid{% elif is_state(entity, 'ONLINE')
%}Online{% elif is_state(entity, 'OUT_OF_FEEDER') %}Out of
Feeder{% elif is_state(entity, 'READY_TO_STREAM') %}Ready for
Birds!{% elif is_state(entity, 'STREAMING') %}Streaming{% elif
is_state(entity, 'TAKING_POSTCARDS') %}Taking Postcards{% endif %}
- type: custom:mushroom-template-card
entity: sensor.birdy_battery
icon: >-
{% set s = states(entity) %} mdi:battery{{"-" + (((s|int/10)
|round(0)) * 10) | string if ((s|int) < 90) and ((s|int) > 5)}}
primary: Batterij
icon_color: |-
{% set battery_level = states(entity) | int %}
{% if battery_level >= 60 %}
green
{% elif battery_level >= 40 %}
orange
{% else %}
red
{% endif %}
secondary: '{{ (states(entity)) }}%'
tap_action:
action: more-info
- type: custom:mushroom-template-card
entity: binary_sensor.bird_buddy_charging
icon: mdi:power-plug{{'-off' if states(entity) == 'off'}}
icon_color: '{{''grey'' if states(entity) == ''off'' else ''green'' }}'
primary: |
{{ states(entity)
| replace('off','Not Charging')
| replace('on','Charging')
}}
tap_action:
action: more-info
secondary: ''
- type: custom:mushroom-template-card
entity: sensor.birdy_signal_strength
icon: |-
{% set rssi_level = states(entity) | int %}
{% if rssi_level >= -50 %}
mdi:wifi-strength-4
{% elif rssi_level >= -61 %}
mdi:wifi-strength-3
{% elif rssi_level >= -72 %}
mdi:wifi-strength-2
{% elif rssi_level >= -85 %}
mdi:wifi-strength-1
{% elif rssi_level >= -94 %}
mdi:wifi-strength-outline
{% else %}
mdi:wifi-strength-off-outline
{% endif %}
primary: Netwerk
icon_color: |-
{% set rssi_level = states(entity) | int %}
{% if rssi_level >= -70 %}
green
{% elif rssi_level >= -85 %}
orange
{% else %}
red
{% endif %}
secondary: '{{ states(entity) }} dBm'
tap_action:
action: more-info
The next thing I am doing is adding an event to my google calendar when it spots a bird with direct links to the images (Nothing new, I already have this for my doorbell)
Nice work!
One suggestion, which I realize has not been called out explicitly in this thread yet, but it is important for making sure you get all new postcards. The automation mode should be changed to queued
. I see your automation yaml is set to the default, single
, but that means if you get 2 new postcards within the 10 minute polling interval, it will only trigger for one of them, and the other will generate an error in your log (because the automation is âalready executingâ). Switching to queued
means it will run the automation back to back, for both postcards, and you wonât miss any.
Thanks for the tip!
My S3 upload and add to Google calendar is done too:
service: google.create_event
target:
entity_id: calendar.calls
data:
summary: Birdy!
start_date_time: "{{ (as_datetime(trigger.event.data.sighting.medias[0].createdAt) - timedelta( minutes = 1 )).strftime('%Y-%m-%d %H:%M:%S') }}"
end_date_time: "{{ as_datetime(trigger.event.data.sighting.medias[0].createdAt).strftime('%Y-%m-%d %H:%M:%S') }}"
description: >
{% for bird in trigger.event.data.sighting.medias -%}
{% set file = bird.createdAt ~ "-birdy-" ~ bird.id ~ ".jpg" %}
{% set name = bird.createdAt %}
<a href="https://my-fancy-birdy-bucket.s3.eu-west-1.amazonaws.com/{{ file }}">Vogel gespot op {{ name }}</a><br>
{% endfor %}
Do you know if we can also retrieve the videoâs BB makes? The sightings event now seems to only have jpg data for the images, but thereâs usually a video included in the app too.
The videos will appear in the media browser alongside the jpegs. Not every postcard has a video.
If you want to differentiate the medias array items for your downloads, youâll see medias[*].__typename=="MediaImage"
, or MediaVideo
. I believe the videos are .mp4 files, but Iâm not 100% sure of that. I do know that the videos in collections appear with the play icon in the media browser, and Iâve confirmed that they play.
Bingo:
" * Creates a camera entity in Home Assistant to feature recent Strava pictures as a photo-carousel"
Thatâs exactly what I was looking for to show me the last 10 or so pics
Hello,
Iâve given this some more thought and Iâd like to do this since I have a Synology NAS connected to HA. Can this script be converted to grab this:
and send them to my Synology?
The reason Iâm questioning is because Iâm not sure if your script is pulling all media that was accepted in BB or if its pulling all sightings. If new pics are saved in BB, I want HA to automatically detect them and send a copy to Synology.
Iâm not super familiar with the nuanced requirements of the media/URLs and how to pass them back and forth but I can follow directions
Thanks, Iâll have a look, I have some sightings with videos
they got my second BB online today. Is there still testing you need done? (I havenât connected it to HA yet)
Thanks for asking. @Snille was kind enough to invite me to his feeder, which helped uncover some issues with having multiple feeders on one account, as well as an edge case where youâve redeemed an invitation code, but still waiting for the owner to confirm the invitation. Those fixes went into v0.0.10 already; and thereâs another fix for the media browser (removing the per-Feeder directories in the browser), along with an unrelated improvement to the firmware updater, that merged last week but those have not been released yet.
Thereâs still an issue with the Recent Visitor entity when you have multiple feeders, where it might associate a visit from a bird species as the recent visitor on the wrong feeder, specifically when looking for visitors on startup (once the integration is running, itâll keep them associated with the correct feeder as new postcards arrive). I know why it happens, and the latest changes make a best effort attempt to keep it associated correctly, but it can still get confused if the same species visits both feeders (in my case it was actually an incorrect bird identification on his feeder, but that visit was attributed to my feeder because the cover photo of that species is a photo from my feeder). A future change will pull this info from the feed of sightings rather than from collections, so itâll be much more reliable. That of course wonât fix the problem of an incorrect bird identification, because I can only use what BB says.
I only saw that issue once, and it only happened as a result of a bad identification, because our feeders are in different countries and continents, so there really ought to be very little overlap. If your two feeders are in the same region, itâs a lot more likely to hit this bug.
Iâll try to get that resolved this week, but Iâve been on vacation for a week, so itâll have to wait until Iâve caught up at work.
Long story short: most of the functionality should work correctly with multiple feeders, whether the additional feeders are owner access or guest/member access.
This screenshot is from the media browser, which is effectively a clone of the BB appâs Collections tab (the middle tab in the app). It lists the bird species collections, and the individual images within each collection. Itâs not showing âsightingsâ per se, but individual images that have been collected from all sightings, grouped together by species.
In other words, if you donât collect the postcard sightings, either manually in the BB app or with the collect_postcard service, they wonât appear here (and they also wonât appear in the appâs collections). Itâs also possible for a single postcard to contain multiple âsightingsâ â of the same OR different birds/species. But the postcard itself is no longer relevant in the collections, because the image was already collected, or saved.
By the way, the HA integration does not âconnectâ individual feeders. It works by login account. So once itâs paired with your account it should be auto discovered. However, it might only create the new devices and entities on integration startup. So if you see the second feeder in the app, but not in HA, you should probably be able to just reload the integration to have it discover the new feeder automatically.
In the future Iâll make sure it can add the newly identified feeders automatically without having to reload (I havenât tested this). It also doesnât auto âun-discoverâ a removed feeder, which is something Iâll work on in the future.