{"id":19893653,"url":"https://github.com/cameronsenese/codecard-avatar","last_synced_at":"2026-06-09T08:32:09.184Z","repository":{"id":170275764,"uuid":"606994978","full_name":"cameronsenese/codecard-avatar","owner":"cameronsenese","description":"Oracle serverless function that transforms your Code Card into an awesome, personalized id-badge! Note: This project is a mirror of the upstream project developed and maintained by Cameron Senese at GitLab.","archived":false,"fork":false,"pushed_at":"2023-02-27T04:54:00.000Z","size":3831,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-01T05:28:16.897Z","etag":null,"topics":["codecard","oci","python","serverless"],"latest_commit_sha":null,"homepage":"https://gitlab.com/byteQualia/codecard-avatar","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cameronsenese.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2023-02-27T04:49:17.000Z","updated_at":"2024-09-26T14:45:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"643ca3f2-8c1e-4757-bcc0-6360b25c183d","html_url":"https://github.com/cameronsenese/codecard-avatar","commit_stats":null,"previous_names":["cameronsenese/codecard-avatar"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cameronsenese/codecard-avatar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cameronsenese%2Fcodecard-avatar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cameronsenese%2Fcodecard-avatar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cameronsenese%2Fcodecard-avatar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cameronsenese%2Fcodecard-avatar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cameronsenese","download_url":"https://codeload.github.com/cameronsenese/codecard-avatar/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cameronsenese%2Fcodecard-avatar/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34098911,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"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":["codecard","oci","python","serverless"],"created_at":"2024-11-12T18:30:21.652Z","updated_at":"2026-06-09T08:32:09.167Z","avatar_url":"https://github.com/cameronsenese.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[oci]:https://cloud.oracle.com/en_US/cloud-infrastructure\n[oci-signup]:https://cloud.oracle.com/tryit\n\n# Code Card Avatar Function\n\n## Introduction\n\nThe Oracle Code Card is a Wi-Fi-enabled IoT device with an e-paper display that's able to interact with remote API endpoints, and retrieve and display content from cloud platforms such as Oracle Cloud Infrastructure. The Code Card runs on an [ESP8266](https://en.wikipedia.org/wiki/ESP8266) Wi-Fi microcontroller. \n\nThe Code Card avatar serverless function transforms your Code Card into an awesome, personalized id-badge!  \n\n![alt text](images/codecard-avatar-photo-v0.02.png \"Code Card Custom Avatar\")\n\nThe function is designed to assemble and display a bitmap image which includes a unique card-owner identicon that's generated on-the-fly via a 3rd party API. Generation of the identicon avatar is based on a hash of the card owner's name.\n\nApart from turning your Code Card into a personalized id-badge, the avatar function is a great reference for building an Oracle function which when invoked coordinates a number of interactions with a range of OCI services, external services, and the Code Card IoT device itself.\n\n## Overview\n\nThe avatar function is implemented as an Oracle Function (i.e. an OCI managed serverless function):\n\n - the function is invoked via an API published via the OCI API Gateway Service\n - the Oracle Function itself is written in Python: [codecard-avatar/func.py]( /codecard-avatar/func.py)\n - the function uses a custom container image based on oraclelinux:7-slim, and also includes rh-python36 and ImageMagick: [codecard-avatar/Dockerfile]( /codecard-avatar/Dockerfile)\n\n![alt text](images/codecard-avatar-workflow-v0.01.png \"Avatar Function: Workflow View\")\n\nIn reference to the workflow illustration, there are two main elements to the workflow:\n\n1. During the \"Configure\" phase, the Code Card is configured using the Code Card Configurator mobile application (here the Code Card unique ID and owner's name are registered in a database table hosted on Oracle APEX)\n2. During the \"Run\" phase, the avatar function is then invoked by the Code Card via API Gateway, which initiates a series of interactions with:\n\n   - the Code Card designer APEX backend\n   - the identicon generation web service (http://identicon-1132.appspot.com)\n   - OCI object storage\n\nNext, with the gathered artefacts the function proceeds to assemble the id-badge custom bitmap, and directs the Code Card to download and display the image via the object storage service.\n\n## Implementation\n\nThis implementation instruction describes the process for implementing each of the following solution components, including object storage, avatar generation serverless function, and API gateway.\n\n*This work instruction assumes that you will be utilising the shared [Code Card Designer](http://bit.ly/2PdOiU1) mobile application, and the associated back-end platform hosted at: `https://apex.oracle.com/pls/apex/appslab/functions/master`. If you would like to build and host your own Code Card back-end, check out the work instruction over [here](https://learncodeshare.net/2020/01/29/use-ords-to-run-the-codecard-backend-on-your-own-free-oracle-cloud-database/).*\n\nResources referenced in this tutorial will be named as follows:\n\n - Compartment containing the function: ***fn-compartment***\n - OCI IAM Function Dynamic Group Name: ***fnfunc-avatar***\n - Oracle Functions Application Name: ***codecard***\n - OCI IAM API GW Dynamic Group Name: ***gwfunc-avatar***\n - API Gateway name: ***gw-codecard***\n - API Gateway Deployment name: ***gw-avatar-deployment***\n - Object Storage Bucket Name: ***codecard-avatar***\n - Function Name: ***codecard-avatar***\n\n### Prerequisites\n\nThe following should be completed before going ahead and creating the autoscaler function:\n - **OCI Tenancy:** If you don't already have an OCI tenancy, you can sign-up right [here](https://www.oracle.com/cloud/free/) and experience the benefits of OCI with the included always free services\n - **Set up your tenancy for function development:** Follow the link to [this tutorial](https://docs.cloud.oracle.com/iaas/Content/Functions/Tasks/functionsconfiguringtenancies.htm) for guidance on the process\n - **Configure your client environment for function development:** Before you can start using Oracle Functions to create and deploy functions, you need to set up your client environment for function development: follow the link to [this tutorial](https://docs.cloud.oracle.com/iaas/Content/Functions/Tasks/functionsconfiguringclient.htm) for guidance on the process\n\n#### Additional IAM Policies\n\nWhen a function you've deployed to Oracle Functions is running, it can access other Oracle Cloud Infrastructure resources. To enable a function to access another Oracle Cloud Infrastructure resource, you need to include the function in a dynamic group, and then create a policy to grant the dynamic group access to that resource. Follow the link to [this tutorial](https://docs.cloud.oracle.com/iaas/Content/Functions/Tasks/functionsaccessingociresources.htm) for guidance on creating a dynamic group. \n\nFollow the process to create the dynamic groups required for both the Functions and API Gateway Services. \n\nFor our deployment scenario we'll require our dynamic groups to access a range of services, including the network and object storage. To enable this, create the following dynamic group and additional IAM policies:\n\n#### Dynamic Group\n\nFor the below dynamic group definition, the `resource.compartment.id` is that of the \"fn-compartment\" where the application and associated function will be deployed:\n\n```\nALL {resource.type = 'fnfunc', resource.compartment.id = 'ocid1.compartment.oc1..aaaaaaaafnaar7sww76or6eyb3j625uji3tp4cb4tosaxx4wbxvvagzzzzzz'}\n```\n\n#### IAM Policies\n\nCreate the additional IAM policies:\n\n```\nAllow dynamic-group fnfunc-avatar to use subnets in compartment fn-compartment\nAllow dynamic-group fnfunc-avatar to read virtual-network-family in compartment fn-compartment\nAllow dynamic-group fnfunc-avatar to use vnics in compartment fn-compartment\nAllow dynamic-group fnfunc-avatar to inspect compartments in compartment fn-compartment\nAllow dynamic-group fnfunc-avatar to manage objects in compartment fn-compartment\nAllow dynamic-group gwfunc-avatar to use functions-family in compartment fn-compartment\n```\n\n#### Clone the `codecard-avatar` Git Repository\n\nNow let's clone the `codecard-avatar` repository:\n\n```\n$ git clone https://nnn/codecard-avatar.git\n```\n\nCommands from this point forward will assume that you are in the `../codecard-avatar` directory, which is the directory containing the function code, and other dependencies such as the Dockerfile used to build the container image, the func.yaml (function configuration file), and a Python requirements definition file.\n\n### Object Storage Bucket\n\nThe avatar function requires an object storage bucket to both host the background template image, and to host the finalised custom image that's downloaded and diplayed by the Code Card.\n\nTo create and configure the object storage bucket using the OCI console, visit the product documentation [here](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/managingbuckets.htm), and then:\n\n1. Create the bucket named `codecard-avatar` by following the section \"To create a bucket\"\n2. Set the bucket as public, by following the section \"To change the visibility of a bucket\"\n\nCopy the background template bitmap `../codecard-avatar/images/background/identicon_bg.bmp` to the `codecard-avatar` bucket.\n\nFor guidance on the process using the OCI console, visit the product documentation [here](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/managingobjects.htm), and follow the section \"To upload objects to a bucket or folder\".\n\nFinally, make a record of the URI of the object storage bucket, using the format:\n`https://objectstorage.\u003cregion\u003e.oraclecloud.com/n/\u003cobject-storage-namespace\u003e/b/\u003cbucket-name\u003e`. \n\nThis value will be provided as the configuration parameter `oss_bucket` within the avatar function, as described in a later section of this work instruction.\n\n### Serverless Application and Function\n\nIn Oracle Functions, an application is a logical grouping of functions \u0026 a common context to store configuration variables that are available to all functions in the application. \n\n#### Create Oracle Functions Application: `codecard`\n\nNow create an application named `codecard` to host the `codecard-avatar` function. Follow the link to [this tutorial](https://docs.cloud.oracle.com/iaas/Content/Functions/Tasks/functionscreatingapps.htm) for guidance on the process.\n\n*When creating applications, Oracle recommends that you use the same region as the container registry that's specified in the Fn Project CLI context, and be sure to select the compartment specified in the Fn Project CLI context.*\n\n#### Create Function: `codecard-avatar`\n\nNext, to create the function.  \n\n#### Create the Function\n\n*Remember that all commands assume that you are in the `../codecard-avatar` directory of the `codecard-avatar` repository which is the directory containing the function code, and other dependencies such as the Dockerfile used to build the container image, the func.yaml (function configuration file), and a Python requirements definition file.*\n\nEnter the following single Fn Project command to build the function and its dependencies as a Docker image, push the image to the specified Docker registry, and deploy the function to Oracle Functions:\n\n```\n$ fn -v deploy --app codecard\n```\n\nThe Fn Project CLI will generate output similar to the following (abbreviated) detailing the steps taken to build and deploy the function.\n\n```\n$ Deploying codecard-avatar to app: codecard\n$ Bumped to version 0.0.1\n$ Building image...\n$ ...\n$ ...\n$ 0.0.1: digest: sha256:71c0f9fac6164b676b781970b5d79b86a28838081c6ea88e00cc1cf07630ccc6 size: 1363\n$ Updating function codecard-avatar using image iad.ocir.io/tenancy/codecard/codecard-avatar:0.0.1...\n```\n\n#### Implement Function Configuration Parameters\n\nNow that we have our function built and deployed - it requires the creation of a number of configuration parameters in order for it to operate successfully. User defined configuration parameters are made available to the function at runtime via key-value pairs known as custom configuration parameters.\n\nThe avatar function requires that each of the custom configuration parameters be set. Invoking the function without passing all custom configuration parameters will cause the function to fail.\n\nTo specify custom configuration parameters using the Fn Project CLI, the following command format is used:\n\n```\n$ fn config function \u003capp-name\u003e \u003cfunction-name\u003e \u003ckey\u003e \u003cvalue\u003e\n```\n\nCreate the following custom configuration parameters using the config function command:\n\n*-- APEX URL*\n```\n$ fn config function codecard codecard-avatar apex_url \u003cvalue\u003e\n```\n - Type: String\n - The `\u003cvalue\u003e` field should contain the URL of the Code Card back-end APEX application.\n - If you are using the publicly available shared instance, the value should be: `https://apex.oracle.com/pls/apex/appslab/functions/master`.\n\n*-- Identicon Service*\n```\n$ fn config function codecard codecard-avatar identicon_service \u003cvalue\u003e\n```\n - Type: String\n - The `\u003cvalue\u003e` field should contain the URL of an identicon generation web service.\n - The function is designed to use the sevice available at:  `http://identicon-1132.appspot.com`.\n\n*-- OSS Bucket*\n```\n$ fn config function codecard codecard-avatar oss_bucket \u003cvalue\u003e\n```\n - Type: String\n - The `\u003cvalue\u003e` configures the URL of the object storage bucket used to host background template and custom .bmp data. Insert value generated in the [Object Storage Bucket](#object-storage-bucket)  section of this work instruction.\n\n*-- Image BG Name*\n```\n$ fn config function codecard codecard-avatar image_bg_name \u003cvalue\u003e\n```\n - Type: String\n - The `\u003cvalue\u003e` field should contain the file name of the background template .bmp file.\n - The default value is: `identicon_bg` (per the name of the image template uploaded to object storage bucket earlier in the tutorial).\n\n### Configure Function Logging\n\nWhen a function you've deployed to Oracle Functions is invoked, you'll typically want to store the function's logs so that you can review them later. You specify where Oracle Functions stores a function's logs by setting a logging policy for the application containing the function. Follow the link to [this tutorial](https://docs.cloud.oracle.com/iaas/Content/Functions/Tasks/functionsexportingfunctionlogfiles.htm) for guidance on the process.\n\n### API Gateway\n\nThe solution utilizes an API gateway to front-end function invocation requests on the public internet.\n\n#### Create API Gateway\n\nFollow [this](https://docs.cloud.oracle.com/en-us/iaas/Content/APIGateway/Tasks/apigatewaycreatinggateway.htm) work instruction to create the API Gateway in your tenancy.\n\nInput values should be provided as follows:\n\n - API Gateway name: ***gw-codecard***\n - Type: ***Public***\n - Compartment:  ***fn-compartment***\n - VCN: ***Use the VCN deployed to host the function***\n - Subnet: ***Use the Subnet deployed to host the function***\n\n#### Create API Deployment Specification\n\nBefore you can deploy an API on an API gateway, you have to create an API deployment specification. Every API deployment has an API deployment specification.\n\nEach API deployment specification defines a set of resources, and the methods (for example, GET, PUT) that can be performed on each resource.\n\nFollow [this](https://docs.cloud.oracle.com/en-us/iaas/Content/APIGateway/Tasks/apigatewaycreatingdeployment.htm#consolescratch) work instruction to create the API Deployment specification using the OCI console.\n\n*Skip steps 6, 7, \u0026 8 if desired as they are optional.*\n\nInput values should be provided as follows:\n\n##### Basic Information\n - Deployment name: ***codecard***\n - Path Prefix: ***/codecard***\n - Compartment:  ***fn-compartment***\n\n##### Route1\n - Path: ***/avatar***\n - Method: ***POST***\n - Type: ***Oracle Functions***\n - Application: ***codecard***\n - Function Name: ***codecard-avatar***\n\nTo obtain the URL to invoke the `codecard-avatar` function:\n\n1. browse to: *Developer Services| API Gateway | Gateways | gw-codecard| Deployment Details* in the OCI console.\n2. In the \"Deployment Information\" section, record the \"Endpoint\" URL, and include  an appended \"/avatar\" at the end of the string.\n\nThis should look something like the following:\n\nhttps://db4zhpxkc3pctfju6ziv541234.apigateway.us-ashburn-1.oci.customer-oci.com/codecard/avatar\n\n### Test the Avatar Function\n\nAs a quick test, you can now manually invoke the function using curl before we go ahead and configure the Code Card for function invocation.\n\nBefore we send our test request to the API endpoint, we need to obtain the unique ID of your Code Card (when the Code Card communicates using HTTP methods, it always includes as a header it's unique ID (it's MAC address). \n\nTo do this, put your Code Card in to configuration mode by performing a simultaneous \"double short-press\" (press the A \u0026 B buttons simultaneously for a sub-second duration).\n\nOnce in configuration mode the Code Card will display it's unique ID as both a barcode and alphanumeric string on the e-paper display. Record the unique ID string for use with curl.\n\nTo invoke the function using a command shell, submit the following command:\n\n```\ncurl --header \"x-codecard-id: \u003ccodecard-id\u003e\" -X POST \u003cendpoint-url\u003e\n```\n\nSubstitute the values `\u003ccodecard-id\u003e` and `\u003cendpoint-url\u003e` with Code Card unique ID and API endpoint values as appropriate.\n\nWhen complete, the avatar function will return a JSON payload similar to the following, which includes the `backgroundImage` URL to the custom bitmap uploaded by the function to the object storage bucket:\n\n``` json\n{\n   \"template\":\"template8\",\n   \"title\":\"Joan Citizen\",\n   \"subtitle\":\"MVP: Oracle Dev Community\",\n   \"bodytext\":\"\",\n   \"backgroundColor\":\"white\",\n   \"backgroundImage\":\"https://objectstorage.\u003cregion\u003e.oraclecloud.com/n/\u003ctenancy\u003e/b/codecard/o/identicon_bg_JoCi.bmp\"\n}\n```\n\n## Invoke with Code Card\n\n### Preparation\nIn order to have your Code Card invoke the avatar function and your name and personalised identicon - the following preparatory steps need to be taken.\n\n#### Code Card Designer\nUsing the [Code Card designer mobile application](http://bit.ly/2PdOiU1), register the Code Card using the Code Card unique ID (MAC Address).\n\nNext save the \"Template 1\" layout to the \"A short press\" action, ensuring the \"title\" field contains your Firstname and Lastname as space separated, e.g. \"Joan Citizen\":\n\n![alt text](images/codecard-avatar-configurator-v0.01.png \"Code Card Configurator\")\n\n#### Code Card\n\nThe final step is to configure the Code Card to invoke the avatar function!\nIn this example, we will program the `shortpress` action for button `A` on the card.\n\n#### Establish serial connection with Code Card\nIn order to configure our Code Card, we need to establish a serial connection over USB to the CodeCard CLI. Follow [this guide](https://github.com/cameronsenese/codecard/blob/master/terminal/README.md#connect-via-terminal-emulator) to establish the serial over USB connection. Remember to ensure that the Code Card WiFi settings are configure correctly also! (Direction available from the referenced guide).\n\n#### Configure `buttona1` button action\n*In the Code Card CLI, `buttona1` correlates to button A shortpress action.*\n\nIn your terminal session you should now see the CodeCard CLI Menu, as follows.\n\n```\n***************************************************************************************\n  Code Card v1.0\n  Oracle Groundbreakers\n  developer.oracle.com/codecard\n***************************************************************************************\nCommands:\n  ls                Show all stored key/values\n  help              Show this help\n  shortpress[a|b]   Simulate the press of a button\n  longpress[a|b]    Simulate the long press of a button\n  connect           Connect to wifi\n  disconnect        Disconnect wifi\n  restart           Restart wifi\n  status            Show wifi status\n  home              Show home screen\n  reset             Reset to factory settings\n\nUsage:\n  Read saved key value:\n    key\n  Save new key value:\n    key=[value]\n\nAvailable keys:\n  ssid, password, buttona1, buttona2, buttonb1, buttonb2, fingerprinta1, fingerprinta2,\n  fingerprintb1, fingerprintb2, methoda1, methoda2, methodb1, methodb2,\n\u003e\u003e\u003e\n```\n\nFirst, we will set the HTTP method for the A shortpress by entering the following command.\n*Keep in mind that pausing for 2 seconds while typing will automatically enter the command. It may be easier to pre-type the commands elsewhere and copy-paste them into the window.*\n\n```\nmethoda1=POST\n```\n\nCode Card will confirm setting update as follows.\n\n```\n\u003e\u003e\u003e\nValue saved for methoda1: POST\n\u003e\u003e\u003e\n```\n\nNext configure the HTTP endpoint for the A shortpress by entering the following command. Be sure to substitute values in `\u003cbrackets\u003e` as appropriate.\n\n```\nbuttona1=\u003cendpoint-url\u003e\n```\n\nCode Card will confirm setting update as follows.\n\n```\n\u003e\u003e\u003e\nValue saved for buttona1: \u003cendpoint-url\u003e\n\u003e\u003e\u003e\n```\n\n### Invoke the function from the Code Card\nOk, so now our avatar function and Code Card are ready to Go! Powercycle your Code Card and perform a button A shortpress. If your card is still connected via the serial connection, you will see output similar to the following.\n\n```\n\u003e\u003e\u003e\nConnecting to 'accesspoint1' .................connected!\nIP address: 192.168.43.168\nMAC address: CC:50:E3:CC:BF:FF\n\u003e\u003e\u003e\nRequest:\n  host: db4zhpxkc3pctfju6ziv541234.apigateway.us-ashburn-1.oci.customer-oci.com\n  port: 443\n  url: https://db4zhpxkc3pctfju6ziv54323u.apigateway.us-ashburn-1.oci.customer-oci.com/codecard/avatar\n  fingerprint: 2E 66 84 9D A5 2F 1C FC 40 85 9E 73 9F B3 AD 4E 9C 1C F8 ED\n  method: POST\napplication/json\nResponse:\n  {\"template\":\"template8\",\"title\":\"Joan Citizen\",\"subtitle\":\"MVP: Oracle Dev Community\",\"bodytext\":\"\",\"backgroundColor\":\"white\",\"backgroundImage\":\"https://objectstorage.\u003cregion\u003e.oraclecloud.com/n/\u003ctenancy\u003e/b/codecard/o/identicon_bg_JoCi.bmp\"}\n\u003e\u003e\u003e\nRequest:\n  host: objectstorage.\u003cregion\u003e.oraclecloud.com\n  port: 443\n  url: https://objectstorage.\u003cregion\u003e.oraclecloud.com/n/\u003ctenancy\u003e/b/codecard/o/identicon_bg_JoCi.bmp\n  fingerprint:\n  method: GET\nResponse:\n  HTTP/1.1 200 OK\n  File size: 139530\n  Image Offset: 138\n  Header size: 124\n  Bit Depth: 24\n  Image size: 176x264\n  waited for available 1625 ms\n  waited for available 1115 ms\n  waited for available 1626 ms\n  waited for available 1114 ms\n  waited for available 1626 ms\n  waited for available 1626 ms\n  waited for available 1114 ms\n  waited for available 1626 ms\n  waited for available 1114 ms\n  waited for available 1626 ms\n  waited for available 1114 ms\n  waited for available 1626 ms\n  waited for available 2880 ms\n  waited for available 1627 ms\n  waited for available 7787 ms\n  waited for available 1626 ms\n  waited for available 4033 ms\n  waited for available 1626 ms\n  waited for available 3432 ms\n  waited for available 1625 ms\n  waited for available 2866 ms\n  waited for available 1626 ms\n  waited for available 2863 ms\n  downloaded in 50281 ms\n  bytes read 139530\nShuting down...\n```\n\nOnce completed, the custom bitmap will be output to the e-paper display:\n\n![alt text](images/identicon_bg_JoCi.png \"Custom bitmap file\")  \n\nThe bitmap file is also available for download from the object storage bucket.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcameronsenese%2Fcodecard-avatar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcameronsenese%2Fcodecard-avatar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcameronsenese%2Fcodecard-avatar/lists"}