{"id":25411340,"url":"https://github.com/karljorgensen/smart","last_synced_at":"2026-05-08T19:31:42.273Z","repository":{"id":277595088,"uuid":"932482601","full_name":"KarlJorgensen/Smart","owner":"KarlJorgensen","description":"Watch face for sqfmi Watchy Open Source smart watch","archived":false,"fork":false,"pushed_at":"2025-02-24T23:43:06.000Z","size":427,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-14T10:53:49.937Z","etag":null,"topics":["arduino","arduino-sketch","esp32","esp32-arduino","iot","smartwatch","watchy","watchy-faces"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KarlJorgensen.png","metadata":{"files":{"readme":"README-development.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-14T01:31:22.000Z","updated_at":"2025-02-24T23:43:10.000Z","dependencies_parsed_at":"2025-04-14T08:36:30.230Z","dependency_job_id":"eedb3f9c-fc5e-47d6-a8a2-8f9739b5428b","html_url":"https://github.com/KarlJorgensen/Smart","commit_stats":null,"previous_names":["karljorgensen/smart"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/KarlJorgensen/Smart","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarlJorgensen%2FSmart","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarlJorgensen%2FSmart/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarlJorgensen%2FSmart/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarlJorgensen%2FSmart/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KarlJorgensen","download_url":"https://codeload.github.com/KarlJorgensen/Smart/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KarlJorgensen%2FSmart/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279014104,"owners_count":26085459,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","arduino-sketch","esp32","esp32-arduino","iot","smartwatch","watchy","watchy-faces"],"created_at":"2025-02-16T10:17:12.073Z","updated_at":"2025-10-13T07:05:24.951Z","avatar_url":"https://github.com/KarlJorgensen.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Developing/Tweaking Stuff #\n\nYou probably want to customise your watch. Here are a few things to beware of.\n\nThe watch face consists a few parts:\n\n * The code - see `Smart.cpp` for details - should be pretty vanilla\n   for Arduino folks.\n\n * The Static Watch Face: This is responsible for most of the \"look\"\n   of the watch face. It is basically a background image.\n   \n * The hour \u0026 minute hands: Line drawings which are rotated, scaled\n   and placed at run-time. Lots of lovely trigonometry involved.\n\n * The day-of-week and date: Shown as text on the watch face.\n\n## The Static Watch Face ##\n\nThe source for this is `watchface-pixmap.svg` - a perfectly normal SVG\nfile which you can edit with your favourite editor (e.g. Inkscape).\n\nThis _must_ be a square SVG document, as it will result in a square\nimage.\n\nThis gets converted (through a couple of intermediate steps) to a\nraster image which gets embedded in the code.\n\nThe resulting image will be a very good likeness of the original SVG;\nyou can basically use all the facilities available in SVG with\nnear-utter abandon - as long as Inkscape supports it.\n\nExcept: The watch has an e-ink screen which _only_ supports black and\nwhite. It does _not_ support any shades of grey:\n\n * Any pixel which is at least 50% black will be completely black\n \n * Any pixel which is \u003c 50% black will be completely white.\n\n(in dark mode, black and white are obviously reversed)\n\nWhich means that nice stuff line antialised lines \u0026 gradients are a\nnon-starter.  But if you are careful of aligning things with the pixel\ngrid: you can use patterns for dithering.\n\nFor convenience, `watchface-pixmap.svg` defines the SVG document in\nunits of pixels (200 × 200), and has a grid to match.\n\nIf you want to get a preview of the watch face (static image only, no\nhands), running `make images` will generate `watchface-pixmap.xbm`\nwhich can be viewed with many image viewers. This is useful for\ngetting quick feedback on whether the result will look as intended.\n\nIf your image viewer does not support the XBM format you will be\nrelieved to know that `watchface-pixmap.png` is also generated and you\ncan use that instead.\n\nIf you want to use the Arduino IDE to upload the resulting binary to\nthe watch: Be sure to run `make headers` first: This will update the\n`*.h` file which contains the image.\n\n## The Hour/Minute Hands ##\n\nThese are line drawings consisting of a series of connected straight\nlines - in the code these are referred to as `MultiLine`.\n\nAlthough they are plain SVG files (named `hour_hand-lines.svg` and\n`minute_hand-lines.svg` respectively), they come with a number of\nlimitations in Smart:\n\n * The SVG document should be square. Defining it in units of pixels\n   is sensible, but not required.\n\n * The SVG document must contain a `path` element with an `id`\n   attribute of `minute_hand` (or `hour_hand` for the ... yes: you\n   guessed it: the hour hand). This is what matters.\n   \n * The path is translated into a sequence of straight lines. Straight\n   lines ONLY. Even if you use curves in the SVG, they will be\n   interpreted as straight lines.\n\n * Line (or rather: \"stroke\") attributes like paint and style are\n   ignored. The lines will *always* be drawn as solid 1px lines on the\n   watch. Unless `THICK_LINES` is true: Then the lines will be\n   thicker.\n\n * Gaps in the path are not supported. Yet.\n   \n * Colours, gradients \u0026 fills are ignored. The lines will be black (or\n   in dark mode: white) and that's it.\n\n * Each SVG file should contain _only one_ `\u003cpath\u003e` element:\n \n    * Paths will will result in C++ variables according to their `id`\n      attribute. As both the hour and minute hand are `#include`d into\n      the same `*.cpp` file, name collisions are possible. Or the\n      names may conflict with other (non-hand) variables/functions.\n\t  \n    * All paths will become part of the resulting binary. And space is\n      limited on the watch. You don't want to waste space in there.\n\n * Hands must be drawn in the 3 o'clock position\n \n * The center of the SVG document corresponds to the center of the\n   watch face.\n   \n * The edges of the document corresponds to the edges of the\n   screen. Design your hands with suitable lengths to fit the watch\n   face.\n   \nWhen the hand is drawn at run-time it will rotated to the correct\nposition.\n\nRemember that positions other than 3/6/9/12 o'clock will thus\nunavoidably introduce \"jagged\" lines. So the perceived thickness of\nlines may be different at different angles, which affects the\n\"look\". Be sure to test the layout.\n\n## Placing Text ##\n\nThe day-of-week and date will be displayed on the watch face.  The\npositions of this text is not fixed: we want to avoid the watch hands\ngetting in the way of the text.\n\nThe logic:\n\n * The _possible_ positions of text is defined by rectangles in\n   `watchface-pixmap.svg` - any rectangle with an `inkscape:label`\n   that starts with \"Box\" will be treated as a possible target to\n   position text.\n\n * `svg2boxes.py` will convert this into C++ code (`boxes.h`) which\n   describes each box and an \"exclusion zone\" (described in\n   angles). Unless the hands are quite \"thick\", this ensures that text\n   and watch hands do not overlap. (If your hands are \"thick\" then you\n   may want to make the boxes larger)\n\n * The order of the boxes matter: They are described in order of\n   decreasing preference. In Inkscape, the depth ordering is used to\n   describe the preferences: The box at the bottom is the most\n   preferred one, the top-most box is the least preferred one.\n\n * At run-time, the code will figure out which boxes are usable based\n   on the current angle of the watch hands and the exclusion zone for\n   the boxes.  The day-of-week goes into the first usable box, and the\n   date into the 2nd. (If only one box is usable, the date will not be\n   displayed.)\n\n * Boxes should not overlap; doing this could result in overlapping\n   text.\n\n * Text will be placed in the _center_ of the box. If the box is too\n   small, the text will overflow (and might look ugly).\n\n * Font selection is hard-coded and should somewhat \"fit\" the height\n   of the boxes.\n   \n * The length of each text label is pretty constant; this should \"fit\"\n   the width of the boxes.\n\nFor convenience, the boxes in `watchface-pixmap.svg` are defined with\nno fill and a very light grey stroke; this ensures that they will not\nbe visible in the resulting watch face - the watch face is strictly\nblack-and-white.\n\n# Getting Screenshots #\n\nGetting a screen shot of your screen face is far more cumbersome than\non a PC, and requires a separate build.\n\nIt takes a couple of steps:\n\n * Modify `settings.h` and\n\n   * set `SCREENSHOT_MODE` to a nonzero value\n   * set `SCREENSHOT_HOUR`, `SCREENSHOT_MINUTE` etc to the time you\n     want the face to show.\n   * set `SERIAL_SPEED` to your desired serial port baud rate\n\n * Patch `../libraries/GxEPD2/src/GxEPD2_BW.h` using\n   `GxEPD2_BW.h.patch`.\n\n   I know. This is ugly as it is _literally_ modifying a\n   3rd party library, but the [official\n   directions](https://github.com/sqfmi/Watchy/wiki/Screenshots-of-Watchfaces)\n   aren't any better. Perhaps that is the Arduino way?\n\n   My patch produces Plain PBM format output instead.\n\n   The patch can be applied with e.g. (adjust paths as necessary):\n\n        patch ../libraries/GxEPD2/src/GxEPD2_BW.h GxEPD2_BW.h.patch\n\n   NOTE: This patch was done against version 1.6.1 of GxEPD2. If your\n   version is different the patch may not apply.\n\n * Compile and upload to the watch\n\n * Once the upload is done connect a serial terminal to\n   `/dev/ttyACM0`.\n\n   This should not be done before the upload is complete as the upload\n   is also using the same serial port. Having both processes access\n   the serial port simultaneously is bound to break things.\n\n   In Emacs, you can use the `serial-term` command for\n   this. Alternatively, you can use e.g. `minicom`, and others are\n   available too.\n\n * The watch will now produce output to the serial terminal when it\n   redraws the screen - i.e. once per minute.\n\n * Capture the output and pipe it into `pnmtopng` and send the output\n   to a file of your choosing - e.g.:\n\n        pnmtopng \u003c serial-capture.txt \u003e screenshot.png\n\nAnd you (finally) have a screenshot. If you replace the original\n`screenshot.png` in this directory, it should show nicely in the\n`README.md`.\n\nOnce the code (and screenshot) is to your liking, you can revert\nthings again:\n\n * Modify `settings.h` and\n\n   * set `SCREENSHOT_MODE` to zero\n\n * If you used the patch above, it can be reverted with e.g. (adjust\n   paths as necessary):\n\n        patch --reverse ../libraries/GxEPD2/src/GxEPD2_BW.h GxEPD2_BW.h.patch\n\n * Compile and upload to the watch.\n\n * The watch should now show the correct time.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarljorgensen%2Fsmart","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkarljorgensen%2Fsmart","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarljorgensen%2Fsmart/lists"}