Wiki

Clone wiki

Pipsta / Naughty Nice Checker

Difficulty Level

pipsta_mono.pngpipsta_mono_empty.pngpipsta_mono_empty.pngpipsta_mono_empty.pngpipsta_mono_empty.png

• No Linux or Raspberry Pi knowledge is required

• A fully assembled and set-up Pipsta and an internet connection are all that is required

• Step-by-step instructions are provided

• There are optional advanced concepts at the end of the tutorial for those starting to learn Python

Time to Complete

pipsta_mono.pngpipsta_mono.pngpipsta_mono_empty.pngpipsta_mono_empty.pngpipsta_mono_empty.png

• The tutorial covers the operation of the script in overview

• The script itself has comments to describe operation in greater detail for those wishing to dig deeper

Overview

This project checks Santa's database for a specific name to see if that person has been naughty or nice this year. If they have been nice, a personalised certificate is printed. The certificate is time-stamped to defend against behaviour worsening once the certificate is in-hand.

Please note that this script doesn't really contact Santa's database for one --hopefully very obvious-- reason: his server is way too busy this time of year.

The real purpose of this script is to equip parents with a tool to allow kids a moment of reflection as the Santabase deliberates on their behaviour this last year. All delays have been tailored to allow thorough introspection by the child whilst stopping short of protracted periods that would cause duress.

These delays can, of course, be modified.

The principle is that, if the child has been nice enough all year long, a time-stamped confirmation certificate of niceness will be produced. In point of fact, the script will always produce a 'nice' result. We couldn't bring ourselves to arbitrarily pronounce children naughty. We would ask therefore that parents of unrelentingly naughty children refrain from the use of the script so we do not find ourselves inadvertently exonerating such behaviour.

Pre-requisites

This project assumes you have a fully working and configured Pipsta. There are wiki guides on how to assemble and set-up your Pipsta.

Step-by-Step Guide

1) If you haven't done so already, create a new directory under '/home/pi/pipsta/Examples' called 'christmas',

2) Download the file '2_NaughtyNice.zip' from here to the 'christmas' directory,

3) Right-click the file and select 'Extract Here'

4) You should now see: • File: naughty_nice.py - the script for this project

• File: NaughtyNice.png - the template image that will be modified with personal details and a timestamp

• File: GOODDP__.TTF - The font used for the name

• File: GOODDOGP.TXT - Information for the above font

• File: licence.txt - The licence for the above font

• File: whitrabt.ttf - The font used for the timestamp

• File: whitrabt.txt - The licence for the above font

5) Once you have navigated to '/home/pi/pipsta/Examples/christmas/2_NaughtyNice', press F4 to bring up the terminal

6) In the terminal, type:

#!python

python naughty_nice.py

7) This will run the script with both a default name (Tiny Tim) and a default deliberation period (0.25s).

8) The script will connect to Santa's database (the Santabase), and --if the named person has been 'Nice', a certificate will be printed.

9) To specify another person, put their name in quotes after the script name, e.g.

#!python

python naughty_nice.py "Someone Else"

NB: The script can handle names up to 20 characters. Longer names will be truncated!

10) Different deliberation periods can be produced by entering a value (in seconds), e.g.

#!python

python naughty_nice.py "Another Person" "0.001"

...for really fast deliberations!

How it Works

• The script iterates across lists of strings as shown here:

connection_strings.png

...feigning a connection attempt to the Santabase and a query upon it.

• The script then generates a random number (between 4 and 12 'considerations') of unique random numbers in the range 1-12.

• The unique numbers correspond to strings in a list of considerations:

consideration_strings.png

• Next, the text data is sent over USB to the printer in a way very similar to that found in the BasicPrint.py script. The notable enhancement to this is the use of the very easy to use python TextWrap module.

TextWrap can be told the desired 'width' for displaying characters in the terminal or, in Pipsta's case printing. This function intelligently breaks text up into whole words per line and as such dramatically improves the readability of text sent to the printer.

Dotted around the naughty_nice.py code, you will see references such as:

#!python

pipsta.write(textwrap.fill(text,32))

Breaking this down: - pipsta.write() sends data over USB to the printer - textwrap.fill() takes two parameters: the first being the raw text, the second being the number of characters at which the line wrap will occur. By default, the Pipsta prints 32 characters per line, so that's the point at which we will wrap.

Running the script, you will see that text sent to the printer is split into whole words on each line.

• Once the deliberations have been printed (along with timestamps from the system time), the paper is fed out a way to separate the text from what will be printed next.

• Next, a standard certificate template image (NaughtyNice.png) is loaded and resized to fit the paper width

• This image is then modified with (up to) 20 characters of the child's name in a nice font. As the fonts used are not monospaced (i.e. some characters are wider than others), the image size is not easy to determine in advance. To defend against the problems this causes, the image is produced and then trimmed in order to give better central alignment when pasted into the certificate template.

• The image is modified again with a 20-character long timestamp derived from the system time.

• This image is then printed and fed out to the tear bar

Quiet Time

In the event that the success of being pronounced "Nice" turns to raucousness, parents may benefit from their child spending some quiet-time investigating how many of the snowflakes around the certificate are exactly the same.

For Those Learning Python

Naughty or Nice Example?

There is a section of code that prints the certificate if is_nice is 'True':

#!python

if is_nice:
    certificate_image = prepare_certificate_image()
    certificate_image = add_childs_name(certificate_image, args.child[:20])
    certificate_image = add_childs_name(certificate_image, timestamp)
    print_data = convert_image(certificate_image)
else:
    try:
        again_next_year
    except:
        ional_behaviour_in_future

The code in the 'else' block is (quite literally) exceptionally naughty. Whether or not the script's author will be on Santa's "Nice List" after this remains to be seen…

Why is this code in there?

It was wordplay that proved irresistible to the author of the script.

How can the script run without this causing an error?

Owing to the fact that is_nice is always set to "True", this try, except block will not get executed.

To see what the try, except block does, uncomment the line (remove the # symbol and save):

#!python

#is_nice = False

...on the line above the 'if' clause.

This will now fail with an unhandled exception.

What does a Try, Except block do?

Any code that may be anticipated to cause an exception (i.e. an error that would cause your program to crash) can be 'wrapped' with a Try,Except block. In the event that an exception is thrown by code within a Try block, the Except block code will be run and the program will not crash.

As a very basic and clumsy example, trying to write to a file that does not exist would throw an exception. If this was within a Try block, the Except block could issue a message:

"Error writing to file!"

...and would continue to execute afterwards.

If this was within a Try, Except block, why does it fail with an exception?

There are several things to note here:

• again_next_year is a perfectly legitimate (if not very functional) line of Python code providing it is assigned a value before the line is reached.

• again_next_year is, however, not assigned a value, so this causes an exception to be thrown. As it is in a try block, the except block code is called...

• ...but unfortunately, ional_behaviour_in_future is also not assigned a value beforehand, so this then throws an unhandled exception.

With the:

#!python

is_nice = False

...line still uncommented, now try uncommenting the two lines at the top of the script to see what happens:

#!python

#again_next_year = 1
#ional_behaviour_in_future = 2

This forgiving functionality in terms of lines of Python code that do nothing is certainly worth keeping in mind when you're debugging. It may build, it may even pass all of your Try, Except block checks, but you're script might still not be doing what you really intended it to!

P.S. Remember to comment the lines (#) you uncommented after your investigation!

[END]

Updated