Wordle is a fun free word of the day game where you have six tries to find the five letter word.
It was tough today.
Wordle 204 6/6
Whew!
Wordle is a fun free word of the day game where you have six tries to find the five letter word.
It was tough today.
Wordle 204 6/6
Whew!
Caps-P
- publish
Caps-T
- select template
Make prod - publish to production server
start localhost:8000
dev server and reload on changes
pelican --autoreload --listen
First Robotics Rapid React
https://www.firstinspires.org/robotics/frc/kickoff
This plugin allows the use of Jinja2 directives inside your Pelican articles and pages.
In this approach, your content is first rendered by the Jinja template engine. The result is then passed to the normal Pelican reader as usual. There are two consequences for usage. First, this means the Pelican context and Jinja variables usually visible to your article or page template are not available at rendering time. Second, it means that if any of your input content could be parsed as Jinja directives, they will be rendered as such. This is unlikely to happen accidentally, but it’s good to be aware of.
All input that needs Pelican variables such as article, category, etc., should be put inside your theme’s templating. As such, the main use of this plugin is to automatically generate parts of your articles or pages.
Markdown, reStructured Text, and HTML input are all supported. Note that by enabling this plugin, all input files of these file types will be pre-processed with the Jinja renderer. It is not currently supported to selectively enable or disable jinja2content for only some of these input sources.
A short article on how to work with images so they display correctly in Obsidian and when published with Pelican.
This default Obsidian format, with drag and drop into the document, works in Obsidian, but not Pelican.
Obsidian Native: (doesn't work on this site)

Obsidian knows where to find the image, whereas Pelican needs a path added to find the image. In this case /images/
Added Path:

But the images are 2x based on the image format and the Retina display it was captured from. It needs to be resized to 50% to display properly. There is not a size option available in Obsidian markdown. You can revert to a standard img html tag to make this work. However, the image will not display in Obsidian.
Use <img>
tag:
<img src="/images/CleanShot%202022-01-05%20at%2019.30.59@2x.png" alt="alt text" title="image Title" width="50%"/>
The solution is to use images that are 1x sized. Or, set your screen capture tool to 1x, non Retina. This way the images will display correctly in Obsidian and when published with Pelican, with only the path being added manually to the file name.
1x with path added:

What automation tools are available in Pelican to automatically reformat and resize the images?
To be continued....
I created an Air Quality Index gadget made from a Raspberry Pi Zero W with a tiny OLED screen from Adafruit. It shows the AQI from my local PurpleAir sensor.
I created a Flask web server on the Pi so I could remotely see the AQI and change the PurpleAir sensor ID.
print("The triple-colon syntax will *not* show line numbers.")
from flask import Flask, render_template, request, jsonify, make_response
import os
import logging
import datastore
import aqistore
# DotMap is a dot-access dictionary subclass
# https://pypi.org/project/dotmap/
# https://github.com/drgrib/dotmap
from dotmap import DotMap
# logging configuration
# debug, info, warning, error, critical
logging.basicConfig(filename='./instance/aqi.log',
level=logging.DEBUG, format='%(asctime)s %(message)s')
logging.info('Started')
logging.info('running server.py')
# Example ajax code from
# https://github.com/caseydunham/ajax-flask-demo
app = Flask(__name__)
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'aqi.sqlite'),
LOGGER=os.path.join(app.instance_path, 'aqi.log'),
)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
logging.info('server - created instance folder.')
except OSError:
pass
# default sensor_id for PurpleAir sensor Forest Park
sensor_id = 104402
@app.route('/')
def index():
return render_template('index.html')
@app.route('/pi')
def pi():
return 'Raspberry Pie!'
@app.route('/sensor')
def sensor_index():
return render_template('sensor.html')
@app.route('/aqi')
def aqi_index():
resp = make_response(render_template('aqi.html'))
resp.set_cookie('aqi', 'aqi')
return resp
@app.route('/api/sensor', methods=['GET', 'POST'])
def get_sensor_post():
logging.info('**************** starting sensor ')
# logging.info('request user_agent: ', request.)
out = get_sensor_proc()
r = out.toDict()
return jsonify(result=r, status=200)
def get_sensor_proc():
error = None
out = DotMap()
sensor_id = 0
try:
sensor_id = datastore.get_sensor_id()
except Exception as e:
error = e
logging.warning(e)
out.sensor_id = sensor_id
out.error = error
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(message)s')
logging.info('get_sensor_proc - sensor_id from db.', out.toDict())
return out
@app.route('/api/aqi', methods=['GET', 'POST'])
def aqi_post():
logging.info('**************** starting aqi ')
# logging.info('request user_agent: ', request.)
out = aqi_proc()
r = out.toDict()
return jsonify(result=r, status=200)
def aqi_proc():
error = None
aqi = 0
aqiColor = 0
try:
out = aqistore.purpleAir()
except Exception as e:
error = e
logging.warning(e)
out.error = error
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(message)s')
logging.info('aqi_proc - data from purpleAir.', out.toDict())
return out
@app.route('/api/sensor_post', methods=['POST'])
def sensor_post():
json = request.get_json()
msg = DotMap(json)
out = sensor_proc(msg)
r = out.toDict()
return jsonify(result=r, status=200)
def sensor_proc(msg):
sensor_id = msg.sensor_id
logging.info('server - updating db sensor_id: ' + str(sensor_id))
error = None
if not sensor_id:
error = 'Sensor_id is required.'
logging.warning(error)
if error is None:
error = datastore.set_sensor_id(sensor_id)
out = DotMap()
out.sensor_id = sensor_id
out.error = error
return out
@app.route('/api/say_name', methods=['POST'])
def say_name_post():
json = request.get_json()
msg = DotMap(json)
out = say_name_proc(msg)
r = out.toDict()
return jsonify(result=r, status=200)
# process say_name message
def say_name_proc(msg):
datastore.get_db()
first_name = msg.first_name
last_name = msg.last_name
day_week = msg.day_week
out = DotMap()
out.first_name = first_name
out.last_name = last_name
out.day_week = day_week
datastore.close_db()
return out
@app.route('/init')
def init():
datastore.init_db()
return 'Database initialized'
# dynamic route
@app.route('/<name>')
def print_name(name):
return 'Hi, {}'.format(name)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)
It's been in the works for awhile, but today I updated my production server settings to show the new website based on the Pelican static site generator.
I tried to follow the same look and feel of the Ghost based server but with a fully customizable template. With Ghost I was limited to using their default template and never wanted to learn how to change it. With the new Pelican based site it is super easy to make all the modifications I want.
Why RealFaviconGenerator No hard decision With so many platforms and icons, it's hard to know exactly what you should do. What are the dimensions of favicon.ico? How many Touch icons do I need? RealFaviconGenerator did the reseach and testing for you.
Done in 5 minutes You spent hours on design, colors, graphics... How much time left for the favicon? Probably not much. But no worries, you only need a few minutes to tackle this task.
Compelling design, a platform at a time Each platform comes with its own design requirements. You can't just use the same picture everywhere. RealFaviconGenerator knows this and lets you craft your icons platform per platform.
Instant feedback How will Android display my icon? How will iOS round my Touch icon? No more guesswork. RealFaviconGenerator instantly shows you how your icons will look like.
This plugin generates an index for searching content on a Pelican-powered site.
Why would you want this?
Static sites are, well, static… and thus usually don’t have an application server component that could be used to power site search functionality. Rather than give up control (and privacy) to third-party search engine corporations, this plugin adds elegant and self-hosted site search capability to your site. Last but not least, searches are really fast. 🚀
Want to see just how fast? Try it out for yourself. Following are some sites that use this plugin:
When you install Pelican be sure to install the Makefile too. This allows you to use the make command to build your static website. It takes a bit of configuration for your specific server details, but it's easy to setup.
All the details are handled in these three files:
pelicanconf.py
publishconf.py
Makefile
The command I ended up using is: make ssh_upload
This creates a production build and uploads all the files to the server.
I actually renamed ssh_upload
in the Makefile to prod
, so now I use the command: make prod
It's not bad to open a shell command and execute the make prod
command, but it's even better to hit a hotkey within Obsidian to do the same thing.
Install the Obsidian ShellCommands Plugin
This plugin allows you to execute a shell command from within Obsidian.
It also allows you to execute that command from the Obsidian command pallet.
Which allows you to execute the command from a hotkey.
If you want to manually upload the files then here is a good use of the scp
command.
scp -r /Users/doug/OneDrive/www_root/pelican/projects/64zbit/output/* user@64zbit.com:/home/pi/dev_volumes/public_html/apache/new/
Thoughts
— 2021/12/04 We shall go into the land so our children can always hold us and will never be alone. — The wheel of time S1E4
It is like swimming. If you can’t swim, you won’t be having any fun at all. Swimming sucks if all you do is float (or even sink) and fight the water. But boy, if you figure out the technique and glide through the water, it is incredible. But you don’t learn swimming by aiming for ease and fun. You learn to swim by aiming to be fast and graceful.
School Success
I think kids’ school success comes down to this in this order:
What many seem to think:
European civilization is built on ham and cheese, which allowed protein to be stored throughout the icy winters.
Without this, urban societies in most of central Europe would simply not have been possible.
This is also why we have hardback books. Here's why. 1/
SQLite is a commonly misunderstood database. I myself first heard of the database when I was experimenting with android app development. My thoughts were that since the database was a single file and its name had lite in it, that it could not be taken seriously. But I could not have been more wrong. Now I love sqlite and use it for much of my scientific research. Sqlite is everywhere. It is on every android phone, airplanes, and the storage for many computer applications. The sqlite website details when using sqlite would be appropriate to use and can be summarized with these three questions.
And if you haven't seen this, well then. Let's fix that right now. Via @Oatmeal.
Raspberry Pi Zero W We've updated our popular PiOLED script for use with the Mini PiTFT, a 135x240 Color TFT add-on for your Raspberry Pi. This cute little display has two tactile buttons on GPIO pins that we'll use to make a simple user-interface display for your Pi-Hole.
The Expanse UI Design Here’s a look at the various FUI designs from the sci-fi series The Expanse.
Special thanks to Brian Benton who suggested this and provided some great links as well! A lot of the images have been collected from this massive image dump from drainsmith and further below we have some insights and images provided by Rhys Yorke who worked on The Expanse (Season 3 & 5) as a motion graphics designer.
The ping command is a built in linux and macOS command that shows the performance of the network connection to a remote server. It can be used to log network performance issues over time. The default ping command displays the results to standard output (the shell window). Used with the following options it routes the output to a file that you can look at later.
The ping command will ping the remote server every second until you manually kill the process. This will create 86,400 pings per day in the output file. It's not something you want to forget about and let it run forever. It could create a very large file that fills up your drive space and crashes your system. I run my ping network monitor on a Raspberry Pi 4 so that it will run 24 hours per day in low power and uninterupted environment.
You would normally just run the ping command interactivly and then stop it when you are done. But, that's not what we are doing today. We are looking for an intermident bug that may happen anytime in the future. For this we need to run the command for weeks at a time and be able to look at the results after a network error has been detected.
Here is the ping
command, running in the background, with the output directed to a file called "network.log".
Copy and paste this text to your command line.
ping google.com 2>&1 | while read pong; do date "+%c: $pong"; done >network.log &
Here are the details of what this command does
ping
// the ping command to rungoogle.com
// name of the remote server2>&1
// routes stderr to stdout| while read pong; do date "+%c: $pong"; done
// pipe the ping results and add the current date and time>network.log
// routes output to file network.log&
// at end means to run in backgroundThe pipe
command, represented by the vertical bar |
takes the output of the first command and routes it into the second command. In this case it takes the output of the ping
command and routes it into a command that prepends the current date and then uses the >
command to route everthing to a file instead of standard out (stdout).
The &
at the end of the line makes this command run in the background. This frees up your terminal so you can run other commands. It will continue running even when you exit your terminal and logout. The commands below show you how to find the background command later and control it.
The jobs command only works for jobs you have started in the current shell. If you exit the shell and open a new one then this command will not display your jobs. You will need to use the other commands listed below to work with system level processes.
Fun fact: jobs are started by a user, processes are started and managed by the system. A users job is also a system process.
Every command running on the computer is assigned a unique process id (PID). You can use this PID to interact with background processes.
The terms Command, Job, and Process are basically the same thing. They are programs running on your computer.
Type
top
into your shell to see a list of the top processes running on your current computer. Notice the PID column listed on the far left. Typeq
to exit this view. For a fun day of reading typeman top
to read all the details of thetop
command.
Use the jobs command to see running background jobs, -l
shows the process id (PID). (That’s a lowercase L)
jobs -l
Use the cat
command to view contents of the output file, use the | more
option to show a page at a time. This could take awhile, you are getting 86,400 lines per day and paging through them a few lines at a time will get tedious.
cat network.log
or
cat network.log | more
If all goes well you should see a time=
value at the end of each line. This tells you the ping completed successfully and you have a good connection to the server.
When the connection goes down you will receive error messages. These will be helpful in determining what went wrong.
Example showing a request timout error
The grep
command will help you find interesting data in your output file.
cat network.log | grep -v time
The -v
option tells grep to "invert match", so any line that does not contain the "time" string.
This command will search the network.log for any line that does not contain the string "time". So for any ping command that returns anything other than a normal ping time will be displayed. This includes any error messages that you should look at.
Example showing an unreachable server
Use the pgrep
command to find running ping jobs and return the process id (PID). Pgrep is included in many Linux distributions.
pgrep ping
pgrep
returns the process id (PID) where the string matches. In this case the PID = 24895. Warning: Don't use this PID, use the PID you find on your own system.
Use the kill
command to stop a running job. Be careful, you can kill the wrong job and crash your system. Make sure you enter the correct process id (PID) you found above.
kill PID
Here's nother command to find the running ping processes. Use ps
if your distribution doesn’t include the pgrep
command. The ps
command displays the current process status for all running processes. It's a long list and you can use grep
to show you just what you want.
ps -aux | grep ping
The process id on this distribution is in the second column from the left. In this case the PID = 24895.
When you are done with your analysis you can remove the network.log file with the rm
command. Becareful not to remove the wrong file, this can crash your system.
rm network.log
More info about the Jobs Command
https://www.computerhope.com/unix/ujobs.htm
Date logic from
https://stackoverflow.com/questions/10679807/how-do-i-timestamp-every-ping-result
Use the linux manual pages to learn more about each command.
man kill
man ps
man grep
man pgrep
man ping
man cat
man more
man jobs
man date
man top
man rm
You can search for the linux pipe command too.
For a long time I've wanted a quick way to save text snippets in a timestamped, quickly searchabe form. Today I created a Better Touch Tool keyboad shortcut to save text snippets to a specific DayOne journal.
Here are the details on github so that you too can enjoy this amazing automation feature.
Better Touch Tool create a DayOne journal entry. Contribute to dougpark/dayone development by creating an account on GitHub.
dougparkGitHub
The book that started it all for me. Sometime around 1979 #kim1 #6502 #robot #diy #developer
How to install Ubuntu Desktop on Raspberry Pi 4 | Ubuntu
Ubuntu is an open source software operating system that runs from the desktop, to the cloud, to all your internet connected things.
Install Ubuntu Desktop on Raspberry Pi 4
Covers the basics of updating your Pi 4 to USB boot.
Html5, Phaser 2, Action packed arcade game
Pluto Attacks was previously hosted at povingames.com
"The Plutonians are not happy with us calling their home a 'dwarf' planet. So when they discovered a trick in the space time continuum they sent an infinite number of drones to attack Earth. We created an energy weapon that can siphon off the energy from the drones weapons. This powers the Earths vessel and creates a powerful energy shield. Remember, don't let even one alien escape!"
Poving Games released this intense shooter based on the classic Phaser Invaders example and then taken it into complete overdrive! You don't have to shoot, that is done automatically. You just move left and right and blast away the plutonains. It all starts quite calmly and you'll no doubt do a perfect clearance of the first few levels.
Read More at phaser.io
Read More at html5games.net
You can start at Normal level 1 if you want to see how it all began. Typical space game with normal dodge and shoot action. You can even level up to the 20’s and still play a dodge and shoot game. However, it will drive you crazy and you will get bored.
The fun begins at about Fun level 20. Everything is faster and you quickly realize there is more to the game then just dodge and shoot. In fact dodging is no longer possible. There are explosions, lots and lots of explosions.
Plutonians are not happy with the reclassification of their home world to Dwarf Planet. So when they discovered a trick in the space time continuum they send an infinite number of drones to attack Earth. Earth learned just enough about their technology to use it to their own advantage. We created an energy weapon that can siphon off the energy from the drones weapons. This powers the Earth vessel and creates a powerful energy shield.
For desktop just press the space bar to start and then left and right arrows to move. That’s it.
For mobile just tap to start and then use your finger to move back and forth. It’s actually easier and more fun on mobile.
Levels go by pretty quickly. Hey, it’s a game with only two buttons and you can master it in 60 seconds. By level 20 it’s moving right along and by level 30 it’s actually pretty good. Have Fun!
Tip: Don’t let any aliens escape!
I've been doing this for decades and now I want to be an HTML5 game devloper. I'm starting with a server! Well, I have very little experience with game development, graphics, animation, sound, so it's going to be a fun journey.
Stories in the pipeline:
So, Jason Snell got me hooked on BitBar (BitBar (by Mat Ryer - @matryer) lets you put the output from any script/program in your Mac OS X Menu Bar.) and I've been working on a plugin ever since. Here's a quick way to get your current Wi-Fi SSID.
function display-ssid {
echo "---"
ssid=$(/System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport -I | awk -F' SSID: ' '/ SSID: / {print $2}')
echo "Wi-Fi: $ssid | terminal=false bash='$0' param1=copy param2=$ssid"
}
Get wireless SSID through shell script on Mac OS X
Is there any way to get the SSID of the current wireless network through a shell script on Mac OS X?
Mark SzymanskiStack Overflow