Skip to content

Latest commit

 

History

History
236 lines (161 loc) · 8.54 KB

File metadata and controls

236 lines (161 loc) · 8.54 KB

Developing/Tweaking Stuff

You probably want to customise your watch. Here are a few things to beware of.

The watch face consists a few parts:

  • The code - see Smart.cpp for details - should be pretty vanilla for Arduino folks.

  • The Static Watch Face: This is responsible for most of the "look" of the watch face. It is basically a background image.

  • The hour & minute hands: Line drawings which are rotated, scaled and placed at run-time. Lots of lovely trigonometry involved.

  • The day-of-week and date: Shown as text on the watch face.

The Static Watch Face

The source for this is watchface-pixmap.svg - a perfectly normal SVG file which you can edit with your favourite editor (e.g. Inkscape).

This must be a square SVG document, as it will result in a square image.

This gets converted (through a couple of intermediate steps) to a raster image which gets embedded in the code.

The resulting image will be a very good likeness of the original SVG; you can basically use all the facilities available in SVG with near-utter abandon - as long as Inkscape supports it.

Except: The watch has an e-ink screen which only supports black and white. It does not support any shades of grey:

  • Any pixel which is at least 50% black will be completely black

  • Any pixel which is < 50% black will be completely white.

(in dark mode, black and white are obviously reversed)

Which means that nice stuff line antialised lines & gradients are a non-starter. But if you are careful of aligning things with the pixel grid: you can use patterns for dithering.

For convenience, watchface-pixmap.svg defines the SVG document in units of pixels (200 × 200), and has a grid to match.

If you want to get a preview of the watch face (static image only, no hands), running make images will generate watchface-pixmap.xbm which can be viewed with many image viewers. This is useful for getting quick feedback on whether the result will look as intended.

If your image viewer does not support the XBM format you will be relieved to know that watchface-pixmap.png is also generated and you can use that instead.

If you want to use the Arduino IDE to upload the resulting binary to the watch: Be sure to run make headers first: This will update the *.h file which contains the image.

The Hour/Minute Hands

These are line drawings consisting of a series of connected straight lines - in the code these are referred to as MultiLine.

Although they are plain SVG files (named hour_hand-lines.svg and minute_hand-lines.svg respectively), they come with a number of limitations in Smart:

  • The SVG document should be square. Defining it in units of pixels is sensible, but not required.

  • The SVG document must contain a path element with an id attribute of minute_hand (or hour_hand for the ... yes: you guessed it: the hour hand). This is what matters.

  • The path is translated into a sequence of straight lines. Straight lines ONLY. Even if you use curves in the SVG, they will be interpreted as straight lines.

  • Line (or rather: "stroke") attributes like paint and style are ignored. The lines will always be drawn as solid 1px lines on the watch. Unless THICK_LINES is true: Then the lines will be thicker.

  • Gaps in the path are not supported. Yet.

  • Colours, gradients & fills are ignored. The lines will be black (or in dark mode: white) and that's it.

  • Each SVG file should contain only one <path> element:

    • Paths will will result in C++ variables according to their id attribute. As both the hour and minute hand are #included into the same *.cpp file, name collisions are possible. Or the names may conflict with other (non-hand) variables/functions.

    • All paths will become part of the resulting binary. And space is limited on the watch. You don't want to waste space in there.

  • Hands must be drawn in the 3 o'clock position

  • The center of the SVG document corresponds to the center of the watch face.

  • The edges of the document corresponds to the edges of the screen. Design your hands with suitable lengths to fit the watch face.

When the hand is drawn at run-time it will rotated to the correct position.

Remember that positions other than 3/6/9/12 o'clock will thus unavoidably introduce "jagged" lines. So the perceived thickness of lines may be different at different angles, which affects the "look". Be sure to test the layout.

Placing Text

The day-of-week and date will be displayed on the watch face. The positions of this text is not fixed: we want to avoid the watch hands getting in the way of the text.

The logic:

  • The possible positions of text is defined by rectangles in watchface-pixmap.svg - any rectangle with an inkscape:label that starts with "Box" will be treated as a possible target to position text.

  • svg2boxes.py will convert this into C++ code (boxes.h) which describes each box and an "exclusion zone" (described in angles). Unless the hands are quite "thick", this ensures that text and watch hands do not overlap. (If your hands are "thick" then you may want to make the boxes larger)

  • The order of the boxes matter: They are described in order of decreasing preference. In Inkscape, the depth ordering is used to describe the preferences: The box at the bottom is the most preferred one, the top-most box is the least preferred one.

  • At run-time, the code will figure out which boxes are usable based on the current angle of the watch hands and the exclusion zone for the boxes. The day-of-week goes into the first usable box, and the date into the 2nd. (If only one box is usable, the date will not be displayed.)

  • Boxes should not overlap; doing this could result in overlapping text.

  • Text will be placed in the center of the box. If the box is too small, the text will overflow (and might look ugly).

  • Font selection is hard-coded and should somewhat "fit" the height of the boxes.

  • The length of each text label is pretty constant; this should "fit" the width of the boxes.

For convenience, the boxes in watchface-pixmap.svg are defined with no fill and a very light grey stroke; this ensures that they will not be visible in the resulting watch face - the watch face is strictly black-and-white.

Getting Screenshots

Getting a screen shot of your screen face is far more cumbersome than on a PC, and requires a separate build.

It takes a couple of steps:

  • Modify settings.h and

    • set SCREENSHOT_MODE to a nonzero value
    • set SCREENSHOT_HOUR, SCREENSHOT_MINUTE etc to the time you want the face to show.
    • set SERIAL_SPEED to your desired serial port baud rate
  • Patch ../libraries/GxEPD2/src/GxEPD2_BW.h using GxEPD2_BW.h.patch.

    I know. This is ugly as it is literally modifying a 3rd party library, but the official directions aren't any better. Perhaps that is the Arduino way?

    My patch produces Plain PBM format output instead.

    The patch can be applied with e.g. (adjust paths as necessary):

     patch ../libraries/GxEPD2/src/GxEPD2_BW.h GxEPD2_BW.h.patch
    

    NOTE: This patch was done against version 1.6.1 of GxEPD2. If your version is different the patch may not apply.

  • Compile and upload to the watch

  • Once the upload is done connect a serial terminal to /dev/ttyACM0.

    This should not be done before the upload is complete as the upload is also using the same serial port. Having both processes access the serial port simultaneously is bound to break things.

    In Emacs, you can use the serial-term command for this. Alternatively, you can use e.g. minicom, and others are available too.

  • The watch will now produce output to the serial terminal when it redraws the screen - i.e. once per minute.

  • Capture the output and pipe it into pnmtopng and send the output to a file of your choosing - e.g.:

     pnmtopng < serial-capture.txt > screenshot.png
    

And you (finally) have a screenshot. If you replace the original screenshot.png in this directory, it should show nicely in the README.md.

Once the code (and screenshot) is to your liking, you can revert things again:

  • Modify settings.h and

    • set SCREENSHOT_MODE to zero
  • If you used the patch above, it can be reverted with e.g. (adjust paths as necessary):

     patch --reverse ../libraries/GxEPD2/src/GxEPD2_BW.h GxEPD2_BW.h.patch
    
  • Compile and upload to the watch.

  • The watch should now show the correct time.