Closed n0bel closed 1 year ago
If I was gonna suggest a way to do it, I'd have all of the customization settings in one config files, including the WUAPI keys, the location cords, the radar settings, and other stuff like that. Try and separate operating code completely from configuration. That should make it easier for the user to setup the PiClock for their own use.
(Not sure if this is exactly what you were asking for, but I do think it's important!)
Someone asked for a rambling-Dan response?
That' probably the way to go @hsoj95 , config could be something like:
config:
keys:
- wu: <longstringhere>
- darksky: <somethingelse>
radar:
- radar1:
location:
lat:
lon:
clock:
type: digital
size:
Clock plugins could be just passed the config["clock"]
configuration, rather than passing around the whole config object. And it could carry over to other types of plugins. There's probably no need to worry about someone writing a malicious plugin that steals your API keys if that's passed in, but no reason to bounce around the whole thing.
For the questions:
Is there a global config that would need to be passed along?
I suppose the plugin interface can get as complicated as you'd want it to be. I've toyed with them a couple times, but everything I've come up with works but seems like it's oversimplified and there may be a better way. My most recent and what seemed to be simplest was just tossing a couple classes in a plugins directory with standard methods, parsing the files in that directory and importing them, then calling them. It works, not terribly elegant, but I did that just so I could more easily throw data around in different databases on my internal network so there really wasn't complexity there anyway. There's plenty of open source projects on Github that could be scoped out for ideas, which is on my ever growing list of things to check out.
Sounds like there's two plugin infrastructures to consider, data and display.
This may warrant a larger discussion on how much freedom the plugin is given. I like the idea of PiClock itself handling the layout, and plugins would then be written to operate within the given layout. Have the same frames that currently exist, and have the plugin use an existing frame. That would limit customization, but may make it easier for others to contribute and write plugins. If that was the way it went I'd like to see two more frames to account for alerts and RSS, but my want itself may indicate there could be later requests to allow more customization and would argue for allowing this more complicated customization from plugins from the start.
Having a specific frame layout the plugin is written to would let the plugin writer decide how the plugin will display within the section of the screen, and not have to worry about piecing all frames together. Also would make the config easier, it would get either the apikeys
module, the radar
module, etc. The plugin would be given two things when instantiated, the frame for it to occupy (or size and have it return the frame (or the plugin could just pull the size from the frame)), and the relevant config section. Plugins may also require some kind of registration on what data the plugin requires on tick and timer events (see below, I'm thinking raw API return vs an abstracted data backend return on timer events and time being sent on ticks).
Data backends would be different, and probably easier, and from what I remember may account for more of the opened issues. I'm thinking two things can be required from a data plugin:
Personally, I want to easily change these things and this is where my thinking is coming from:
Someone asked for a rambling-Dan response? Yup sure did.
How 'bout this for a config.
providers so the apis can be central (sources?) (apis?) (idk) pages (frames in old terminology) views which are things to put on a page somewhere views have common properties like name (plugin name), geometry (where on the page) as well as plugin specific properties.
(i don't think i have it formatted correctly tho, and maybe not even the syntax for yaml)
config:
providers:
- provider:
name: weather-wu
apiKey:
- provider:
name: map-google
apiKey:
- provider:
name: weather-darksky
apiKey:
- provider:
name: temperature-sensor
pages:
- page:
- view:
name: radar-wu
geometry:
x: 0
y: -80% # % or px negatives mean from bottom
w: 100px
h: 200px
location:
latitude: -93
longitude: 45
zoom: 7 # google maps units
markers:
latitude: -93
longitude: 45
color: red
- view:
name: radar-wu
geometry:
x: 0
...
...
...
- view:
name: clock-digital
geometry:
x: 30%
y: 20%
w: 100px
h: 200px
font: crazy
fontSize: 40
formatString: {0:%I:%M\n%S %p}
- view:
name: forecast-wu
geometry:
...
...
...
- view:
name: current-conditions-generic
provider: weather-darksky #optional provider spec if you have multiples of one type
geometry:
....
....
....
- page:
- view:
name: radar-wu
geometry:
x: 0
y: -80% # % or px negatives mean from bottom
w: 500px
h: 600px
location:
latitude: -93
longitude: 45
zoom: 7 # google maps units
markers:
latitude: -93
longitude: 45
color: red
- view:
name: boxed-string
geometry:
...
...
...
string: The indoor temperature is !temperature-sensor:sensor1
I like a providers
section, and the idea of specifying providers in views to specify where data is coming from per section.
I do get why it would be good to have pages, views, and the geometry laid out in the config file, but that seems like it would quickly become pretty unwieldy. Especially since much of the pages (all?) are based off the screen geometry that currently is hardcoded. Even updating that to be dynamic, I can't see how modifying the scale multipliers could easily done across multiple pages.
I may not have wrapped my head around how it would look yet, but I see this as changing the geometry of one frame/page resulting in requiring a lot of little tweaks throughout the config file to get everything to line up correctly. May be easier than it is currently with everything hardcoded, but still not for the faint of heart.
This feels like the advanced
config option, where nearly everything in the layout is in the config. I'd be interested in hearing from others where the value lies specifically in PiClock. Am I missing the value in being that customizable? Maybe it doesn't really matter how advanced and complex the config looks when you can just not change settings you're unsure of. Once stylesheets is included in the config, or at least some attributes within the stylesheets, I'd be concerned we'd getting into a ~1000 line configuration file for a ~2000 line program (numbers pulled from thin air) which doesn't make it any easier to change, just moves the complexity.
Maybe multiple configs to prevent the need to dig through more advanced settings (Providers, Layout, Radar)? Or config sections broken down with "Basic, Advanced, Caution".
This conversation has been on mothballs but I'd like to revive it.
I've read all the threads on PiClock2 and it seems the the general consensus of the power users is that this is a clock/radar project and shouldn't stray to far from that and I concur. That being said, I don't see where the complexity of a third party plug-in interface makes sense. I think it would be simpler to break the whole thing down onto modules. I was thinking a structure like this would allow us to break out the styles, frames, widgets and worker threads into separate files making it easier to customize the interface and design new widgets or threads without affecting the core code.
PiQt5PiClock
├── Config
│ └── Yaml
│
├── Styles
│ ├── Day
│ └── Night
│
├── Control
│ ├── MQTT
│ ├── KB/Mouse
│ └── Buttons
│
├── Data Provider
│ ├── Weather
│ │ ├── Current
│ │ ├── Forecast Hourly
│ │ └── Forecast Daily
│ ├── Time
│ │ └── Time/Date
│ └── Misc
│ ├── Temperature
│ └── Light Sensor
│
└── Frames
├── Frame 1 - Clock
│ ├── Widget Radar
│ ├── Widget Forecast
│ ├── Widget Current
│ └── Widget Clock Face
└── Frame 2 - Radar
├── Widget Radar
└── Widget Conditions
I already have a cursory shell of this structure up and running and it would only require a couple of line of code to add a thread or frame.
Config There's been a lot of discussion over the config format. I personally like the YAML idea as it's clean and easy to handle in code.
Styles After I did the slideshow, I played around with the styles and they can easily be removed from the code which creates the Qt elements and be applied in the same manner which CSS is on the web. The elements themselves can also be assigned class names and styles can be applied by class, id or object type. I removed every instance of setStyleSheet in the code, consolidated them into proper css, assigned classes to some of the elements and came out with this for the style:
# All QLabel elements
app_style = "QLabel { font-family:sans-serif; color: " + Config.textcolor + "; " + Config.fontattr + "}"
# All QFrame elements with the class frame
app_style += "QFrame.frame { background-color: black; border-image: url(" + Config.background + ") 0 0 0 0 stretch stretch;} "
# All elements with the class radar
app_style += ".radar { background-color: grey; } "
app_style += ".ss_bg { background-color: " + Config.slide_bg_color + "; } "
# The element with the id squares1
app_style += "#squares1 { border-image: url(" + Config.squares1 + ") 0 0 0 0 stretch stretch;} "
app_style += "#squares2 { border-image: url(" + Config.squares2 + ") 0 0 0 0 stretch stretch;} "
if not Config.digital:
app_style += "#clockface { border-image: url(" + Config.clockface + ") 0 0 0 0 stretch stretch;} "
else:
app_style += "#clockface { font-family:sans-serif;" + " font-weight: light; color: " + lcolor + "; font-size: " + str(int(Config.digitalsize * xscale)) + "px; } "
app_style += ".sz12 { font-size: " + str(int(12 * xscale)) + "px; } "
app_style += ".sz15 { font-size: " + str(int(15 * xscale)) + "px; } "
app_style += ".sz19 { font-size: " + str(int(19 * xscale)) + "px; } "
app_style += ".sz20 { font-size: " + str(int(20 * xscale)) + "px; } "
app_style += ".sz25 { font-size: " + str(int(25 * xscale)) + "px; } "
app_style += ".sz30 { font-size: " + str(int(30 * xscale)) + "px; } "
app_style += ".sz50 { font-size: " + str(int(50 * xscale)) + "px; } "
app_style += ".sz70 { font-size: " + str(int(70 * xscale)) + "px; } "
This makes the styles easier to modify and update and, in my opinion, will make it easier to create multiple styles which can be applied by a trigger. I personally have an ambient light sensor on one of my clocks and it applies a 'dark' theme when the lights are out.
Control Push buttons are limited, assigning kb keys is sort of arbitrary and not everyone has a kb hooked up, but...everyone has a smart phone (and if you don't you probably don't have a PiClock!). How can we leverage cell phone ownership and a control interface which is flexible and lightweight, MQTT. I have already written an MQTT module for PiClock which I can easily port to Python3 and PyQt5. It only requires the installation of mosquitto MQTT server (very lightweight) and it's good to go. This allows an unlimited amount of control of the PiClock which, coupled with a cell phone app is also highly convenient. I personally like Linear MQTT Dashboard and can expand on this if the discussion progresses.
Data Providers As Kevin has pointed out in another thread, there is some data which is universal and would be stored in the main thread, this could also be stored in YAML ?formatted? after retrieval. I was thinking we could use nodes in the config to store retrieved data since the display text would already be in that structure. We could use PyQt slot and signals to trigger the update of the views when new data is received.
Frames Simplify creation by separating each frame into its own file. Widgets like the radar, forecast, current conditions, slideshow and clock face would be included in these files and draw our views.
Features It would be cool, especially for those of us in weather disaster areas, to have an automated weather alert. Maybe customizable to either turn on the alert radio or go the the radar frame with a flashing ALERT on it. Seems pretty simple.
To Do My Stuff I need to update the slideshow to my newest version which allows slides to be changed while paused. I need to alter my MQTT routine to work if the MQTT server is unavailable.
Conclusion Let me know what you guys think, I'm willing to do the heavy lifting if we can decide on a direction to head in.
Hi
Thanks for this it is very interesting. I do like the idea of a smartphone app - as anyone tried to get an apple app validated? I also use the apple app for Home Assistant - in one place I can have several RPIs and do simple tasks with them. Could you add PiCLock to Home Assistant? To be able to pick different information screens - say graphs of pressure, rainfall...? And maybe store these as a record of local weather history? This could be added to national weather data platforms (the Met Office in the UK has local weather watchers - this adds extra data to weather models).
I would like to travel with my PiClock - so a way to pick up location via my smartphone?
Just some thoughts!
Hey,
Thanks for this it is very interesting. I do like the idea of a smartphone app - as anyone tried to get an apple app validated?
Not talking about creating an app, there are plenty of MQTT clients to choose from. I'm an android guy so I couldn't tell you what's available for Apple devices. The android app I use is Linear MQTT Dashboard.
I also use the apple app for Home Assistant - in one place I can have several RPIs and do simple tasks with them. Could you add PiCLock to Home Assistant? To be able to pick different information screens - say graphs of pressure, rainfall...?
I'm sure with some effort you could. The proposal would be to break up the code to make implementing changes like this easier. I proposed an MQTT control interface because I think it's simple to install, lightweight, and makes the control interface more robust.
And maybe store these as a record of local weather history? This could be added to national weather data platforms (the Met Office in the UK has local weather watchers - this adds extra data to weather models).
You would have to generating that data yourself to push to a service. Nobody would want the data you retrieved from an openly available API. That would mena you have a weather station and most of those have some means of directly pushing the data to service providers. Different animal.
I would like to travel with my PiClock - so a way to pick up location via my smartphone?
That's a pretty niche case, I doubt many people are doing this. You'd have to have an app on the phone which collect the coords and sends them to the MQTT server. Ip addressing would become and issue.....don't know about this one.....
Hi
Sorry I got rather carried away. I am fine with Android, I mentioned Apple because I had heard they where very difficult re validating apps and the Android Home Assistant is in beta and seems stuck there.
A MQTT interface is fine (Home Assistant uses a yaml file as its configurator) and the Apple app will work.
Yes - my data collection idea was not good - I would need a weather station, I was not thinking too clearly. I still like the idea of summing data for my own interest. Maybe I could get this from the API source too however I have not yet tried a RPI based weather station but may do in the future.
I do travel a lot and I take RPIs for safe wifi and music/videos so weather seemed a natural addition.
Good luck with the development.
First basic question:
Second basic question:
Thoughts? esp @dankolbrs