Replies: 36 comments 91 replies
-
Hi @paddywwoof. Nice to hear from you. You are doing a great job with with viewer. Feel freee to adobt the code. Or if you like you could join this repo, if you like to drive this viewer further as a separate project. I could take over the homeassistant integration. This is the only real requirement I have. |
Beta Was this translation helpful? Give feedback.
-
I tried to run it in virtual box on ubuntu. But pi3d is crashing instantly in import sys worked for me, when I started to try things. The diagram is the general layout of the components. I will derive the class diagrams from it. |
Beta Was this translation helpful? Give feedback.
-
Would be nice to get it working on ubuntu with virtualbox. So I don't have to use my picture frame in the living room. |
Beta Was this translation helpful? Give feedback.
-
Helge, thanks for trying that. It's ages since I used a VM but I think I had to install some additional dependencies. See http://pi3d.github.io/html/ReadMe.html#setup-on-desktop-and-laptop-machines the mesa library and pos numpy and PIL. It ought to work on Windows but you need the angle drivers in addition. Which I haven't updated for ages but should still work. I will try and do some more work on this this week. Paddy |
Beta Was this translation helpful? Give feedback.
-
Mesa is installed: I tried to run the demos. Minimal.py is working. Minimal_2d.py is craching with segmentation fault within an opengl lib. I will install the sources of pi3d an try to debug. Hope I can tell you where excactly it crashes. |
Beta Was this translation helpful? Give feedback.
-
Hi Paddy, I could nail it down to Setting use_glx=True and everythings works fine. Except the window is partially transparent as you mentioned above. To turn the display on the raspi on/of I'm using def display_is_on(self):
return True
cmd = ["vcgencmd", "display_power"]
state = str(subprocess.check_output(cmd))
if (state.find("display_power=1") != -1):
return True
else:
return False If I always return true I can run and debug the picture_frame on ubuntu in the VM. |
Beta Was this translation helpful? Give feedback.
-
Helge, that's great that you got it working (annoying that doesn't just work with the mesa EGL - probably the config isn't right, or the display is a 64bit pointer and should be 32. I've spent hours and hours trying to debug why the DisplayOpenGL doesn't work on different platforms) My temporary fix for I will spend some time finding my way round your code then try to make a list of ideas and suggestions. You will see on the pi3d_demos develop branch https://github.com/pi3d/pi3d_demos/commits/develop that there are a few mods added relating to the background darkening for the text and the ability to have two portrait images side by side. That latter probably needs to be thought through a bit more. Paddy PS I use VS Code on ubuntu - it runs fine. You really don't need windows for anything... |
Beta Was this translation helpful? Give feedback.
-
Helge, I'm thinking maybe the best way to approach this is for me to go through your code and change the minimum in order to put in the features that have been added to PictureFrame2020 since you diverged. During that process I will get more of a feeling for how the code is structured and I can probably make better suggestions for the way of handling the file_list etc. One issue I have come across straight away is that rotated images don't get picked up and corrected. Do you find your images are fine? Looking at PIL.ExifInfo I can only see one tag including 'rientation' which is >>> with open('/home/patrick/Pictures/tester/IMG_20201130_194139.jpg', 'rb') as f:
... tags = exifread.process_file(f, details=False)
...
>>> print(tags['Image Orientation'])
Rotated 90 CW
>>> print(tags['Image Orientation'].values)
[6]
>>> print(tags['Image Orientation'].tag)
274 However I don't want to alter the existing code if it works OK for your images. PS also I'm not sure I understand why get_exif(key) returns {key: val} rather than just val - and why val is the printable form rather than the whole object (so the receiver can do the unscrambling) # in exif2dict ####
def get_orientation(self):
val = self.__get_if_exist('Image Orientation')
if val is not None:
return int(val.values[0])
else:
return 1
# then in model ##
try:
exifs = exif2dict.Exif2Dict(file_path_name)
orientation = exifs.get_orientation()
for exif in self.get_model_config()['image_attr']: which seems to rotate my images correctly |
Beta Was this translation helpful? Give feedback.
-
I've put my initial mods in a I will look at the OSM description lookup code next. As a first step I've made the image info into instances of class Pic so the properties can be accessed in a more friendly way (a dict could have been used), part of the reason for this (apart from readability) is to allow the info to be passed and altered by the PS at the moment |
Beta Was this translation helpful? Give feedback.
-
The problem might be that some functionality done in |
Beta Was this translation helpful? Give feedback.
-
some thoughts on db: While looking at the OSM location system in PictureFrame2020 I started thinking about the pros and cons of storage, at the moment the location is just stored in a CSV type file, so I looked at sqlite3 again. For the simple lookup it's fine but when I thought about the image list (__file_list) I could see some disadvantages to sqlite:
A solution would be if the db select creates a python list of ids that can be traversed (including backwards) and the info read for display (or written to the database as each image has the exif info extracted). For a CSV (or JSON) system then it would also make sense to hold the full list of image info as a dict and have the selection held as a list in a very similar way to the db mechanism. On startup all the image files would still need to be read from the SD dictionary structure (as well as checking from time to time for additional files) but in order to allow selection according to criteria the exif would be needed. The reason that the delayed exif reading was introduced was because for some users it was taking so long to read through all the files (>20minutes). So maybe a compromise would be for the exif reading to take place in a second thread which would add records to the db (or CSV and dict) in the background. The controller would need to keep informed and be able to handle additional records being added - maybe do a reselection when it detects a change. I suppose, to start with, the db functionality could be wrapped in its own class with 'select','update' and 'insert' methods and delay deciding how those are implemented? Paddy |
Beta Was this translation helpful? Give feedback.
-
I've made another upload to my fork paddywwoof@3c9c161 it has basic simple caching (not yet sqlite) I think the only functionality still to add is the paired portrait idea. Paddy |
Beta Was this translation helpful? Give feedback.
-
Another commit paddywwoof@4aab48e . "Portrait pairs" system now in. I'm not sure this is a nice way of doing it: The viewer gets passed a tuple of either (pic, None) or (pic1, pic2) if they are to be shown as pairs. As discussed above this functionality (and others) only works properly once images have been "processed", at the moment this happens as each picture is being got by Also this is just writing cache info to txt file, not yet looked at sqlite. And I haven't put in the small bit of code for heif decoding. PS patched a few errors thrown up running with random 'real' files on the 'real' picture frame in my kitchen. The whole exif extraction might be better inside a try block as there seem some odd formed results returned by exifread!! I also need to check out the MQTT which I haven't touched or checked in any way. |
Beta Was this translation helpful? Give feedback.
-
Sorry, I had a config file in the same directory I was running picture_frame.py from and didn't post that to github - though I see you patched it from the default in model.py. paddywwoof@073e538 How long does it take you to find an address? I'm assuming you mean geo_reverse.py. I did this >>> import time
>>> from picframe.geo_reverse import GeoReverse
>>> geo = GeoReverse('[email protected]', 'junk.txt')
>>> def timer():
... start = time.time()
... addr = geo.get_address(547123,-17987) #i.e. 54.7123, -1.7987
... print(time.time() - start)
...
>>> timer()
0.13068056106567383 and generally I've been finding the lookup to be measured in milliseconds rather than tens of seconds. Are you using your proper email address for the geo key? Does the text appear fine if you use PS you can see that I have used integer values for the lat and lon, that's because I envisage them being indexed fields in a database or being matched against and floats are always tricky to 'equal' to something. And slower as db fields. |
Beta Was this translation helpful? Give feedback.
-
Helge, that sounds good. I've just pushed a couple of changes to my repo. I made get_next_file bi directional. Going backwards it doesn't need to return the Pic object but that should be an inexpensive process as it should always be iterating over records that have already had their exif data extracted. It now correctly skips over images with dates outside the selection criteria going forwards and backwards. If the image is in a portrait pair then the right hand image isn't filtered, but otherwise seems good. I'm increasingly leaning towards a system: On a different topic, I've had a go with my RPi4 and I can't get it to run without blend_type: "blend" # default="blend", choices={"blend":0$
font_file: "./data/fonts/NotoSans-Regular.ttf"
shader: "./data/shaders/blend_new"
show_text_fm: "%b %d, %Y" # default "%b %d, %Y", format to show$ and in picture_frame.service [Service]
Type=idle
User=root
WorkingDirectory=/home/pi/.local/picture_frame
ExecStart=xinit /usr/bin/python3 /home/pi/.local/picture_frame/picture_frame.py configuration.yaml I haven't installed picture_frame properly just created ./local/picture_frame and copied picframe/ and data/ into it, as well as picture_frame.py and configuration.yaml but I think something like this will work for your proper setup. Paddy
|
Beta Was this translation helpful? Give feedback.
-
All elements were generated automatically in homeassistant. I haven't tested everything. But it seems to work in general. So mqtt is now optional and I put it in its own class In mqtt_config = m.get_mqtt_config()
mqtt = None
if mqtt_config['use_mqtt'] == True:
from picframe import interface_mqtt
mqtt = interface_mqtt.InterfaceMQTT(c, mqtt_config)
mqtt.start() Your MQTT is running in a separate thread. Is the pi3d.keyboard interface also running in a separate thread, or do I have to put it in its own thread? |
Beta Was this translation helpful? Give feedback.
-
Helge, I pushed the first draft of a version using sqlite3 on my repo. It's got 38 TODOs!
|
Beta Was this translation helpful? Give feedback.
-
Some more thoughts: controller holds a dict of where_clause which are changed or updated by the functions, something like {'date_to': 'exif_datetime < 1610789629', 'rating': 'rating > 4'} then ' AND '.join(where_clause.values()) and a similar sort_clause. For sorting, rather than have the list shuffling is a special function we could try to move it into the image_cache by having a The other thing might be to have a timer file that worked in a similar way to the mqtt in that it had a copy of the controller instance and turned the display on and off or the brightness up and down etc. This might or might not be nicer than having crontab and mqtt external systems. |
Beta Was this translation helpful? Give feedback.
-
Switched to more general system of filtering where the SQL is generated in the controller see paddywwoof@6285dfc |
Beta Was this translation helpful? Give feedback.
-
Added an MQTT picframe/stop and tidied up the kenburns system. Also reverted the ~pi/ back to ~/ as discussed above. We probably need some clear instruction on how to download for testing without installing to enable people to try it out. |
Beta Was this translation helpful? Give feedback.
-
I played with an keykoard interface """Keyboard interface of picture_frame."""
import logging
from pynput import keyboard
from picframe import __version__
class InterfaceKbd:
"""Keyboard interface of picture_frame.
This interface interacts via keyboard with the user to steer the image display.
Attributes
----------
controller : Controler
Controller for picture_frame
Methods
-------
"""
def __init__(self, controller):
self.__logger = logging.getLogger("interface_kbd.InterfaceKbd")
self.__logger.info('creating an instance of InterfaceKbd')
self.__controller = controller
listener = keyboard.Listener(
on_press=self.on_press,
on_release=self.on_release)
listener.start()
def on_press(self, key):
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
def on_release(self, key):
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
self.__controller.stop()
# Stop listener
return False This works fine. But requires X. Would you propose to use pi3d.Keyboard? This is non blocking, right? So I have to put it in a separate thread and polling for a key press (with sleep(1))? Or do you have a better idea? |
Beta Was this translation helpful? Give feedback.
-
Under Ubuntu with X it works like a charm. Cpu load is slightly higher, but this seems to be OK. I don't see any errors. I will test it tomorrow on raspberry without X. |
Beta Was this translation helpful? Give feedback.
-
Paddy, I'm still struggling with the setup. If you provide a binary package all is installed under the .local directory.
from the site-packacke. So no more ./local/picframe. What do you think? |
Beta Was this translation helpful? Give feedback.
-
On a different but related issue. I have just pushed up a revised version to paddywwoof/picture_frame develop branch. c.start()
server = interface_http.InterfaceHttp(c, "/home/pi/picture_frame/html")
... Fix for my muddle between using 'folder' and 'directory' paddywwoof@5588969 I still get seg faults running on this laptop. I've not tracked down exactly where but I'm pretty sure they're due to accessing after freeing, possibly due to the various thread looping. It might only happen when the processor is fast enough. I will carry on putting Going to try the new set up on as many RPis as I can now. Paddy |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
That' what I get in the output |
Beta Was this translation helpful? Give feedback.
-
OK, I have an idea. I'm running homeassistant ssl encrypted. I debuged server.py. The request was unreadable. If I turn off ssl. It works and the image is displayed. I assume, that homeassistant doesn't care about http or https. So I try to enable ssl with http.server. |
Beta Was this translation helpful? Give feedback.
-
One can use selfsigned certificates. But you have to import them to the browser as trustable. That's why I use letsencrypt. The root certificates are already known to the browser. But this ended for me in an other project. I had to write my own certbot plugin. I think normal user wouldn't use ssl. Only nerds like me. But its good to know its working. To use its externally one should use a vpn, or put everything behind a proxy. Never expose your hosts to the internet directly. |
Beta Was this translation helpful? Give feedback.
-
Perfect. But create feature branches, when working on issues that take more than 1 commit. So dev should always be working. |
Beta Was this translation helpful? Give feedback.
-
Moved from Issues. Original post from @paddywwoof
Hi @helgeerbe you've done some great stuff here. I've started to think about refactoring PictureFrame2020 (not just because of the bad 2020 karma) I had intended to break it into different functional classes very much along the lines you have but I'm not sure whether to just adopt your code as it is and add in the 'improvements' which have happened since you diverged. If I can keep it compatible with Home Assistant but still work without it - the main thing is that Wolfgang's setup will work (almost) unaltered; there's a lot of really good work in his picture frame blog and the less he has to re-write the better!
One thing has occurred to me (I've only just started to think about this so more will appear when I actually start to hack code):
make the file_list (and associated date, GPS, exif etc data) into an sqlite database see pi3d/pi3d_demos#41 (comment)
Beta Was this translation helpful? Give feedback.
All reactions