Merge pull request #7 from jdlcdl/kdmukai/initial_multilanguage
Kdmukai/initial multilanguage
@@ -0,0 +1,40 @@
|
||||
[run]
|
||||
branch = True
|
||||
|
||||
[report]
|
||||
skip_empty = True
|
||||
skip_covered = True
|
||||
|
||||
# Omit; need a different approach to test modules with hardware dependencies
|
||||
omit =
|
||||
*/__init__.py
|
||||
*/tests/*
|
||||
*/pyzbar/*
|
||||
*/gui/*
|
||||
|
||||
# Regexes for lines to exclude from consideration
|
||||
exclude_lines =
|
||||
# Have to re-enable the standard pragma
|
||||
pragma: no cover
|
||||
|
||||
# Don't complain about missing debug-only code:
|
||||
def __repr__
|
||||
def __str__
|
||||
if self\.debug
|
||||
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
raise AssertionError
|
||||
raise NotImplementedError
|
||||
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
if 0:
|
||||
if __name__ == .__main__.:
|
||||
|
||||
# Don't complain about abstract methods, they aren't run:
|
||||
@(abc\.)?abstractmethod
|
||||
|
||||
|
||||
[html]
|
||||
directory = coverage_html_report
|
||||
skip_empty = True
|
||||
skip_covered = False
|
||||
@@ -4,4 +4,7 @@ src/seedsigner.egg-info/
|
||||
.nova
|
||||
.vscode
|
||||
src/seedsigner/models/settings_definition.json
|
||||
*.mo
|
||||
.idea
|
||||
.coverage
|
||||
seedsigner-screenshots
|
||||
.mo
|
||||
@@ -1,3 +1,9 @@
|
||||
# jdlcdl branch: kdmukai/initial_multilanguage
|
||||
|
||||
My self-directed exploration, from mid November through mid December 2022, to carry-on where kdmukai left-off this past summer, in similar style, regarding internationalization/localization of seedsigner codebase (w/ exploration focus in locale 'fr'). Note: requirements.txt has new dependencies; also, follow instructions in babel/ to build binary message catalogs.
|
||||
|
||||
---------------
|
||||
|
||||
# Build an offline, airgapped Bitcoin signing device for less than $50!
|
||||
|
||||

|
||||
@@ -17,45 +23,47 @@
|
||||
|
||||
# Project Summary
|
||||
|
||||
The goal of SeedSigner is to lower the cost and complexity of Bitcoin multi-signature wallet use. To accomplish this goal, SeedSigner offers anyone the opportunity to build a verifiably air-gapped, stateless Bitcoin signing device using inexpensive, publicly available hardware components (usually < $50). SeedSigner helps users save with Bitcoin by assisting with trustless private key generation and multi-signature wallet setup, and helps users transact with Bitcoin via a secure, air-gapped QR-exchange signing model.
|
||||
The goal of SeedSigner is to lower the cost and complexity of Bitcoin multi-signature wallet use. To accomplish this goal, SeedSigner offers anyone the opportunity to build a verifiably air-gapped, stateless Bitcoin signing device using inexpensive, publicly available hardware components (usually < $50). SeedSigner helps users save with Bitcoin by assisting with trustless private key generation and multisignature (aka "multisig") wallet setup, and helps users transact with Bitcoin via a secure, air-gapped QR-exchange signing model.
|
||||
|
||||
Additional information about the project can be found at [seedsigner.com](https://seedsigner.com).
|
||||
Additional information about the project can be found at [SeedSigner.com](https://seedsigner.com).
|
||||
|
||||
You can follow [@SeedSigner](https://twitter.com/SeedSigner) on Twitter for the latest project news and developments.
|
||||
|
||||
If you have specific questions about the project, our [Telegram Group](https://t.me/joinchat/GHNuc_nhNQjLPWsS) is a great place to ask them.
|
||||
|
||||
### Feature Highlights:
|
||||
* Calculate word 12/24 of a BIP39 seed phrase
|
||||
* Create a 24-word BIP39 seed phrase with 99 dice rolls
|
||||
* Create a 24-word BIP39 seed phrase by taking a digital photo
|
||||
* Temporarily store up to 3 seed phrases while device is powered
|
||||
* Guided interface to manually create a SeedQR for instant input [(demo video here)](https://youtu.be/c1-PqTNx1vc)
|
||||
* BIP39 passphrase / word 25 support
|
||||
* Native Segwit Multisig XPUB generation w/ QR display
|
||||
* Scan and parse transaction data from animated QR codes
|
||||
* Calculate the final word (aka checksum) of a 12- or 24-word BIP39 seed phrase
|
||||
* Create a 24-word BIP39 seed phrase with 99 dice rolls or a 12-word with 50 rolls [(Verifying dice seed generation)](docs/dice_verification.md)
|
||||
* Create a 12- or 24-word BIP39 seed phrase via image entropy from the onboard camera
|
||||
* Temporarily stores seeds in memory while the device is powered; all memory is wiped when power is removed
|
||||
* SD card removable after boot to ensure no secret data can be written to it
|
||||
* Guided interface to manually transcribe a seed to the SeedQR format for instant seed loading [(demo video here)](https://youtu.be/c1-PqTNx1vc)
|
||||
* BIP39 passphrase (aka "word 25") support
|
||||
* Native Segwit Multisig XPUB generation
|
||||
* PSBT-compliant; scan and parse transaction data from animated QR codes
|
||||
* Sign transactions & transfer XPUB data using animated QR codes [(demo video here)](https://youtu.be/LPqvdQ2gSzs)
|
||||
* Live preview during photo-to-seed and QR scanning UX
|
||||
* Live preview during image entropy seed generation and QR scanning UX
|
||||
* Optimized seed word entry interface
|
||||
* Support for Bitcoin Mainnet & Testnet
|
||||
* Support for custom user-defined derivation paths
|
||||
* On-demand receive address verification
|
||||
* Address Explorer for single sig and multisig wallets
|
||||
* User-configurable QR code display density
|
||||
* Responsive, event-driven user interface
|
||||
|
||||
### Considerations:
|
||||
* Built for compatibility with Specter Desktop, Sparrow, and BlueWallet Vaults
|
||||
* Device takes up to 60 seconds to boot before menu appears (be patient!)
|
||||
* Always test your setup before transfering larger amounts of bitcoin (try testnet first!)
|
||||
* Always test your setup before transferring larger amounts of bitcoin (try Testnet first!)
|
||||
* Taproot not quite yet supported
|
||||
* Slightly rotating the screen clockwise or counter-clockwise should resolve lighting/glare issues
|
||||
* If you think SeedSigner adds value to the Bitcoin ecosystem, please help us spread the word! (tweets, pics, videos, etc.)
|
||||
|
||||
### Planned Upcoming Improvements / Functionality:
|
||||
* Single-sig and multi-sig change address verification
|
||||
* Re-imagined, graphically-focused user interface
|
||||
* Multi-language support
|
||||
* Customized Linux live-boot OS to allow MicroSD card removal
|
||||
* Significantly faster boot time
|
||||
* Reproducible builds
|
||||
* Port to MicroPython to broaden the range of compatible hardware to include low-cost microcontrollers
|
||||
* Other optimizations based on user feedback!
|
||||
|
||||
---------------
|
||||
@@ -64,7 +72,7 @@ If you have specific questions about the project, our [Telegram Group](https://t
|
||||
|
||||
To build a SeedSigner, you will need:
|
||||
|
||||
* Raspberry Pi Zero (preferably version 1.3 with no WiFi/Bluetooth capability, but any Raspberry Pi 2/3/4 or Zero model will work)
|
||||
* Raspberry Pi Zero (preferably version 1.3 with no WiFi/Bluetooth capability, but any Raspberry Pi 2/3/4 or Zero model will work, Raspberry Pi 1 devices will require a hardware modification to the Waveshare LCD Hat, as per the [instructions here](./docs/legacy_hardware.md))
|
||||
* Waveshare 1.3" 240x240 pxl LCD (correct pixel count is important, more info at https://www.waveshare.com/wiki/1.3inch_LCD_HAT)
|
||||
* Pi Zero-compatible camera (tested to work with the Aokin / AuviPal 5MP 1080p with OV5647 Sensor)
|
||||
|
||||
@@ -77,60 +85,180 @@ Notes:
|
||||
|
||||
# Software Installation
|
||||
|
||||
## Special Note on Minimizing Trust
|
||||
## A Special Note On Minimizing Trust
|
||||
As is the nature of pre-packaged software downloads, downloading and using the prepared SeedSigner release images means implicitly placing trust in the individual preparing those images; in our project the release images are prepared and signed by the eponymous creator of the project, SeedSigner "the person". That individual is additionally the only person in possession of the PGP keys that are used to sign the release images.
|
||||
|
||||
However, one of the many advantages of the open source software model is that the need for this kind of trust can be negated by our users' ability to (1) review the project's source code and (2) assemble the operating image necessary to use the software themselves. From our project's inception, instructions to build a SeedSigner operating image (using precisely the same process that is used to create the prepared release images) have been made availabile. We have put a lot of thought and work into making these instructions easy to understand and follow, even for less technical users. These instructions can be found [here](docs/manual_installation.md).
|
||||
|
||||
## Downloading the Software
|
||||
|
||||
The quickest and easiest way to install the software is to download the most recent "seedsigner_X_X_X.zip" file in the [software releases](https://github.com/SeedSigner/seedsigner/releases) section of this repository.
|
||||
|
||||
Download the current Version (0.6.0) software image that is compatible with your Raspberry Pi Hardware. The Pi Zero 1.3 is the most common and recommended board.
|
||||
| Board | Download Image Link/Name |
|
||||
| --------------------- | --------------------------------- |
|
||||
|**[Raspberry Pi Zero 1.3](https://www.raspberrypi.com/products/raspberry-pi-zero/)** |[`seedsigner_os.0.6.0.pi0.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner_os.0.6.0.pi0.img) |
|
||||
|[Raspberry Pi Zero W](https://www.raspberrypi.com/products/raspberry-pi-zero-w/) |[`seedsigner_os.0.6.0.pi0.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner_os.0.6.0.pi0.img) |
|
||||
|[Raspberry Pi Zero 2 W](https://www.raspberrypi.com/products/raspberry-pi-zero-2-w/) |[`seedsigner_os.0.6.0.pi02w.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner_os.0.6.0.pi02w.img) |
|
||||
|[Raspberry Pi 2 Model B](https://www.raspberrypi.com/products/raspberry-pi-2-model-b/) |[`seedsigner_os.0.6.0.pi2.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner_os.0.6.0.pi2.img) |
|
||||
|[Raspberry Pi 3 Model B](https://www.raspberrypi.com/products/raspberry-pi-3-model-b/) |[`seedsigner_os.0.6.0.pi02w.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner_os.0.6.0.pi02w.img) |
|
||||
|[Raspberry Pi 4 Model B](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) |[`seedsigner_os.0.6.0.pi4.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner_os.0.6.0.pi4.img) |
|
||||
|[Raspberry Pi 400](https://www.raspberrypi.com/products/raspberry-pi-400-unit/) |[`seedsigner_os.0.6.0.pi4.img`](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner_os.0.6.0.pi4.img) |
|
||||
|
||||
After downloading the .zip file, extract the seedsigner .img file, and write it to a MicroSD card (at least 4GB in size or larger). Then install the MicroSD in the assembled hardware and off you go.
|
||||
Note: If you have physically removed the WiFi component from your board, you will still use the image file of the original(un-modified) hardware. (Our files are compiled/based on the *processor* architecture). Although it is better to spend a few minutes upfront to determine which specific Pi hardware/model you have, if you are still unsure which hardware you have, you can try using the pi0.img file. Making an incorrect choice here will not ruin your board, because this is software, not firmware.
|
||||
|
||||
## Verifying the Software
|
||||
You can verify the data integrity and authenticity of the latest release with as little as three commands. This process assumes that you know [how to navigate on a terminal](https://terminalcheatsheet.com/guides/navigate-terminal) and have navigated to the folder where you have these four relevant files present: (This will most likely be your Downloads folder.)
|
||||
**also download** these 2 signature verification files to the same folder
|
||||
[The Plaintext manifest file](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner.0.6.0.sha256)
|
||||
[The Signature of the manifest file](https://github.com/SeedSigner/seedsigner/releases/download/0.6.0/seedsigner.0.6.0.sha256.sig)
|
||||
|
||||
* seedsigner_pubkey.gpg (from the main folder of this repo)
|
||||
* seedsigner_0_4_6.img.zip (from the software release)
|
||||
* seedsigner_0_4_6.img.zip.sha256 (from the software release)
|
||||
* seedsigner_0_4_6.img.zip.sha256.sig (from the software release)
|
||||
Users familiar with older versions of the SeedSigner software might be surprised with how fast their software downloads now are, because since version 0.6.0 the software image files are now 100x smaller! Each image file is now under 42 Megabytes so your downloads and verifications will be very quick now (and might even seem *too* quick)!
|
||||
|
||||
**Note:** The specific version number of the files in your folder might not match the above exactly, but their overall format and amount should be the same.
|
||||
Once the files have all finished downloading, follow the steps below to verify the download before continuing on to write the software onto a MicroSD card. Next, insert the MicroSD into your assembled hardware and connect the USB power. Allow about 45 seconds for our logo to appear, and then you can begin using your SeedSigner!
|
||||
|
||||
[Our previous software versions are available here](https://github.com/SeedSigner/seedsigner/releases). Choose a specific version and then expand the *Assets* sub-heading to display the .img file binary and also the 2 associated signature files. **Note:** The prior version files will have lower numbers than the scripts and examples provided in this document, but the naming format will be the same, so you can edit them as required for signature verification etc.
|
||||
|
||||
|
||||
## Verifying that the downloaded files are authentic (optional but highly recommended!)
|
||||
|
||||
You can quickly verify that the software you just downloaded is both authentic and unaltered, by following these instructions.
|
||||
We assume you are running the commands from a computer where both [GPG](https://gnupg.org/download/index.html) and [shasum](https://command-not-found.com/shasum) are already installed, and that you also know [how to navigate on a terminal](https://terminalcheatsheet.com/guides/navigate-terminal).
|
||||
|
||||
|
||||
### Step 1. Verify that the signature (.sig) file is genuine:
|
||||
|
||||
Run GPG's *fetch-keys* command to import the SeedSigner projects public key from the popular online keyserver called *Keybase.io*, into your computers *keychain*.
|
||||
|
||||
This process also assumes you are running the commands from a system where both [GPG](https://gnupg.org/download/index.html) and [shasum](https://command-not-found.com/shasum) are installed and working.
|
||||
|
||||
First make sure that the public key is present in your keychain:
|
||||
```
|
||||
gpg --import seedsigner_pubkey.gpg
|
||||
gpg --fetch-keys https://keybase.io/seedsigner/pgp_keys.asc
|
||||
```
|
||||
This command will import the public key, or return:
|
||||
The result should confirm that 1 key was *either* imported or updated. *Ignore* any key ID's or email addresses shown.
|
||||
|
||||

|
||||
|
||||
Next, you will run the *verify* command on the signature (.sig) file. (*Verify* must be run from inside the same folder that you downloaded the files into earlier. The `*`'s in this command will auto-fill the version from your current folder, so it should be copied and pasted as-is.)
|
||||
```
|
||||
key <...> not changed
|
||||
gpg --verify seedsigner.0.6.*.sha256.sig
|
||||
```
|
||||
|
||||
Now you can verify the authenticity of the small text file containing the release's SHA256 hash with the command:
|
||||
```
|
||||
gpg --verify seedsigner_0_*_*.img.zip.sha256.sig
|
||||
```
|
||||
**Note:** The `*`s in the command above allow the terminal to auto-populate the command with the version number you have in the folder you are in. It should be copied and pasted as is.
|
||||
When the verify command completes successfully, it should display output like this:
|
||||
<BR>
|
||||

|
||||
The result must display "**Good signature**". Ignore any email addresses - *only* matching Key fingerprints count here. Stop immediately if it displays "*Bad signature*"!
|
||||
<BR>
|
||||
|
||||
The reponse to this command should include the text:
|
||||
```
|
||||
Good signature from "seedsigner <btc.hardware.solutions@gmail.com>" [unknown]
|
||||
```
|
||||
The previous command validates that aforementioned small text file was signed using the private key that matches the published public key associated with the project (an early timestamped record of this public/private key's creation can be found in this [tweet](https://twitter.com/SeedSigner/status/1389617642286329856?s=20)).
|
||||
On the *last* output line, look at your *rightmost* 16 characters (the 4 blocks of 4).
|
||||
**Crucially, we must now check WHO that Primary key fingerprint /ID belongs to.** We will start by looking at Keybase.io to see if it is the *SeedSigner project* 's public key or not.
|
||||
|
||||
<details><summary> About the warning message:</summary>
|
||||
<p> Since you are about to match the outputted fingerprint/ID against the proofs at Keybase.io/SeedSigner, and thereby confirm who the pubkey really belongs to-, you can safely ignore this warning message:
|
||||
|
||||
The last step is to make sure the .zip file that you've downloaded, and that contains the released software, is a perfect match to the software that was published by the holder of the private key in the last step. The command for this step is:
|
||||
```
|
||||
shasum -a 256 -c seedsigner_0_*_*.img.zip.sha256
|
||||
> WARNING: This key is not certified with a trusted signature!
|
||||
> There is no indication that the signature belongs to the owner.
|
||||
```
|
||||
</p>
|
||||
</details>
|
||||
<br>
|
||||
|
||||
<details><summary> More about how the verify command works:</summary>
|
||||
<p>
|
||||
The verify command will attempt to decrypt the signature file (sha256.sig) by trying each public key already imported into your computer. If the public key we just imported (via fetch-keys), manages to: (a) successfully decrypt the .sig file , and (b), that result matches exactly to the clear-text equivalent (.sha256) of the .sig file, then its "a good signature"!
|
||||
|
||||
Crucially, we must still manually check who *exactly* owns the Key ID which gave us that "Good signature". Thats what the warning message means- Who does the matching key really belong to? We will start by looking at keybase.io to see if it is "The SeedSigner project"'s public Key or not.
|
||||
Note that it is the file hashes of .sig and .sha256 that *verify* compares, not their raw contents.
|
||||
|
||||
</p>
|
||||
</details>
|
||||
<br>
|
||||
|
||||
Now to determine ***who*** the Public key ID belongs to: Goto [Keybase.io/SeedSigner](https://keybase.io/seedsigner)
|
||||
<BR>
|
||||

|
||||
|
||||
|
||||
|
||||
**You must now *manually* compare: The 16 character fingerprint ID (as circled in red above) to, those *rightmost* 16 characters from your *verify* command.**
|
||||
|
||||
**If they match exactly, then you have successfully confirmed that your .sig file is authentically from the SeedSigner Project!**
|
||||
<BR>
|
||||
|
||||
<details><summary>Learn more about how keybase.io helps you check that someone (online) is who they say they are:</summary>
|
||||
<p>
|
||||
Keybase.io allows you to independently verify that the public key saved on Keybase.io, is both authentic and that it belongs to the organization it claims to represent.
|
||||
Keybase has already checked the three pubkey file locations cryptographically when they were saved there. You can further verify the key publications if you would like:
|
||||
|
||||
- *via Keybase*: By clicking on any of the three blue badges to see that the "proof" was published at that location. (The blue badge marked as tweet, is in the most human-readable form and it is also a bi-directional link on Twitter)
|
||||
or,
|
||||
- *without keybase (out-of-band)*: By using these 3 links directly: [Twitter](https://twitter.com/SeedSigner/status/1530555252373704707), [Github](https://gist.github.com/SeedSigner/5936fa1219b07e28a3672385b605b5d2) and [SeedSigner.com](https://seedsigner.com/keybase.txt). This method can be used if you would like to make an even deeper, independent inspection without relying on Keybase at all, or if the Keybase.io site is no longer valid or it is removed entirely.
|
||||
|
||||
Once you have used one of these methods, you will know if the Public Key stored on Keybase, is genuinely from the SeedSinger Project or not.
|
||||
</p>
|
||||
</details>
|
||||
<br>
|
||||
|
||||
If the two ID's do *not* match, then you must stop here immediately. Do not continue. Contact us for assistance in the Telegram group address above.
|
||||
|
||||
<br>
|
||||
|
||||
### Step 2. Verifying that the *software images/binaries* are genuine
|
||||
|
||||
Now that you have confirmed that you do have the real SeedSigner Project's Public Key (ie the 16 characters match) - you can return to your terminal window. Running the *shasum* command, is the final verification step and will confirm (via file hashing) that the software code/image files, were also not altered since publication, or even during your download process.
|
||||
(Prior to version 0.6.0 , your verify command will check the .zip file which contains the binary files.)
|
||||
|
||||
**On Linux or OSX:** Run this command
|
||||
```
|
||||
The reponse to this command should include the text:
|
||||
```
|
||||
seedsigner_0_4_6.img.zip: OK
|
||||
shasum -a 256 --ignore-missing --check seedsigner.0.6.*.sha256
|
||||
```
|
||||
|
||||
There are other steps you can take to verify the software, including examining the hash value in the .sha256 text file, but this one has been documented here because it seems the simplest for most people to follow. Please recognize that this process can only validate the software to the extent that the entity that first published the key is an honest actor, and assumes the private key has remained uncompromised and is not being used by a malicious actor.
|
||||
**On Windows (inside Powershell):** Run this command
|
||||
```
|
||||
CertUtil -hashfile seedsigner_os.0.6.0.Insert_Your_Pi_Models_binary_here_For_Example_pi02w.img SHA256
|
||||
```
|
||||
On Windows, you must then manually compare the resulting file hash value to the corresponding hash value shown inside the .SHA256 cleartext file.
|
||||
<BR>
|
||||
|
||||
Wait up to 30 seconds for the command to complete, and it should display:
|
||||
```
|
||||
seedsigner_os.0.6.x.[Your_Pi_Model_For_Example:pi02w].img: OK
|
||||
```
|
||||
**If you receive the "OK" message** for your **seedsigner_os.0.6.x.[Your_Pi_Model_For_Example:pi02w].img file**, as shown above, then your verification is fully complete!
|
||||
**All of your downloaded files have now been confirmed as both authentic and unaltered!** You can proceed to create/write your MicroSD card😄😄 !!
|
||||
|
||||
If your file result shows "FAILED", then you must stop here immediately. Do not continue. Contact us for assistance at the Telegram group address above.
|
||||
|
||||
<BR>
|
||||
|
||||
Please recognize that this process can only validate the software to the extent that the entity that first published the key is an honest actor, and their private key is not compromised or somehow being used by a malicious actor.
|
||||
<BR>
|
||||
<BR>
|
||||
|
||||
|
||||
## Writing the software onto your MicroSD card
|
||||
|
||||
To write the SeedSigner software onto your MicroSD card, there are a few options available:
|
||||
| Application | Description | Platform and official Source |
|
||||
|--------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
|
||||
| Balena Etcher | The application is called Etcher, and the company that wrote it is called Balena. Hence *Etcher by Balena* or *Balena Etcher* | [Available for Windows, Mac and Linux](https://www.balena.io/etcher#download-etcher) |
|
||||
| Raspberry Pi Imager | Produced by the Raspberry Pi organization. | [Available for Windows, Mac and Linux](https://www.raspberrypi.com/software/) |
|
||||
| DD Command Line Utility | Built-in to Linux and MacOS, the DD (Data Duplicator) is a tool for advanced users. If not used carefully it can accidentally format the incorrect disk! | Built-in to Linux and MacOS |
|
||||
|
||||
Be sure to download the software from the genuine publisher.
|
||||
Either of the Etcher or Pi Imager software is recommended. Some SeedSigner users have reported a better experience with one or the other. So, if the one application doesn’t work well for your particular machine, then please try the other one.
|
||||
<BR>
|
||||
### **General Considerations:**
|
||||
The writing and verify steps are very quick from version 0.6.0 upwards, so please pay close attention to your screen.
|
||||
Make sure to set any write-protection physical slider on the MicroSD Card Adapter to UN-locked.
|
||||
You also don’t need to pre-format the MicroSD beforehand. You *dont* need to unzip any .zip file beforehand.
|
||||
Current Etcher and Pi Imager software will perform a verify action (by default) to make sure the card was written successfully! Watching for that verify step to complete successfully, can save you a lot of headaches if you later need to troubleshoot issues where your SeedSigner device doesn’t boot up at power on.
|
||||
Writing the MicroSd card is also known as flashing.
|
||||
It will overwrite everything on the MicroSD card.
|
||||
If the one application fails for you, then please try again using our other recommended application.
|
||||
Advanced users may want to try the Linux/MacOS *DD* command instead of using Etcher or Pi Imager, however, a reminder is given that DD can overwrite the wrong disk if you are not careful !
|
||||
#### **Specific considerations for Windows users:**
|
||||
Use the Pi imager software as your first choice on Windows. Windows can sometimes flag the writing of a MicroSD as risky behaviour and hence it may prevent this activity. If this happens, your writing/flashing will fail, hang or wont even begin, in which case you should to try to run the Etcher/Pi-Imager app "As administrator", (right-click and choose that option). It can also be blocked by windows security in some cases, so If you have the (non-default) *Controlled Folder Access* option set to active, try turning that *off* temporarily.
|
||||
|
||||
|
||||
|
||||
|
||||
---------------
|
||||
|
||||
@@ -154,7 +282,7 @@ The upper and lower portions of the enclosure can be printed using a standard FD
|
||||
|
||||
* [Lil Pill](https://cults3d.com/en/3d-model/gadget/lil-pill-seedsigner-case) by @_CyberNomad
|
||||
* [OrangeSurf Case](https://github.com/orangesurf/orangesurf-seedsigner-case) by @OrangeSurfBTC
|
||||
* [PS4 Seedsigner](https://www.thingiverse.com/thing:5363525) by @Silexperience
|
||||
* [PS4 SeedSigner](https://www.thingiverse.com/thing:5363525) by @Silexperience
|
||||
* [OpenPill Faceplate](https://www.printables.com/en/model/179924-seedsigner-open-pill-cover-plates-digital-cross-jo) by @Revetuzo
|
||||
* [Waveshare CoverPlate](https://cults3d.com/en/3d-model/various/seedsigner-coverplate-for-waveshare-1-3-inch-lcd-hat-with-240x240-pixel-display) by @Adathome1
|
||||
|
||||
@@ -170,16 +298,35 @@ You can use SeedSigner to export your seed to a hand-transcribed SeedQR format t
|
||||
</table>
|
||||
|
||||
Standard SeedQR templates:
|
||||
* [12-word SeedQR template (25x25)](docs/seed_qr/printable_templates/12words_seedqr_template.pdf)
|
||||
* [24-word SeedQR template (29x29)](docs/seed_qr/printable_templates/24words_seedqr_template.pdf)
|
||||
* [Baseball card template: 24-word SeedQR (29x29)](docs/seed_qr/printable_templates/Seed_QR_Card.pdf)
|
||||
* [12-word SeedQR template dots (25x25)](docs/seed_qr/printable_templates/dots_25x25.pdf)
|
||||
* [24-word SeedQR template dots (29x29)](docs/seed_qr/printable_templates/dots_29x29.pdf)
|
||||
* [12-word SeedQR template grid (25x25)](docs/seed_qr/printable_templates/grid_25x25.pdf)
|
||||
* [24-word SeedQR template grid (29x29)](docs/seed_qr/printable_templates/grid_29x29.pdf)
|
||||
* [Baseball card template: 24-word SeedQR (29x29)](docs/seed_qr/printable_templates/trading_card_29x29_w24words.pdf)
|
||||
|
||||
CompactSeedQR templates:
|
||||
* [12-word CompactSeedQR template (21x21)](docs/seed_qr/printable_templates/compact_seedqr/12words_compactseedqr_template.pdf)
|
||||
* [24-word CompactSeedQR template (25x25)](docs/seed_qr/printable_templates/compact_seedqr/24words_compactseedqr_template.pdf)
|
||||
* [12-word CompactSeedQR template dots (21x21)](docs/seed_qr/printable_templates/dots_21x21.pdf)
|
||||
* [24-word CompactSeedQR template dots (25x25)](docs/seed_qr/printable_templates/dots_25x25.pdf)
|
||||
* [12-word CompactSeedQR template grid (21x21)](docs/seed_qr/printable_templates/grid_21x21.pdf)
|
||||
* [24-word CompactSeedQR template grid (25x25)](docs/seed_qr/printable_templates/grid_25x25.pdf)
|
||||
* [Baseball card template: 12-word Compact SeedQR (21x21)](docs/seed_qr/printable_templates/trading_card_21x21_w12words.pdf)
|
||||
* [Baseball card template: 24-word Compact SeedQR (25x25)](docs/seed_qr/printable_templates/trading_card_25x25_w24words.pdf)
|
||||
|
||||
_note: CompactSeedQR is an advanced feature that can be enabled in Settings_
|
||||
|
||||
|
||||
2-sided SeedQR templates - 8 per sheet
|
||||
Printing settings - (2-sided)("flip on long edge")("Actual Size")
|
||||
If printing on cardstock, adjust your printer settings via its control panel
|
||||
|
||||
A4 templates(210mm * 297mm):
|
||||
* [21x21 - stores 12-word seeds ONLY in CompactSeedQR format ONLY](docs/seed_qr/printable_templates/21x21_A4_trading_card_2sided.pdf)
|
||||
* [25x25 - stores 12-word or 24 word seeds depending on SeedQR format](docs/seed_qr/printable_templates/25x25_A4_trading_card_2sided.pdf)
|
||||
* [29x29 - stores 24-word seeds ONLY as plaintext SeedQR format ONLY](docs/seed_qr/printable_templates/29x29_A4_trading_card_2sided.pdf)
|
||||
|
||||
Letter templates(8.5in * 11in):
|
||||
* [21x21 - stores 12-word seeds ONLY in CompactSeedQR format ONLY](docs/seed_qr/printable_templates/21x21_letter_trading_card_2sided.pdf)
|
||||
* [25x25 - stores 12-word or 24 word seeds depending on format](docs/seed_qr/printable_templates/25x25_letter_trading_card_2sided.pdf)
|
||||
* [29x29 - stores 24-word seeds ONLY as plaintext SeedQR format ONLY](docs/seed_qr/printable_templates/29x29_letter_trading_card_2sided.pdf)
|
||||
---------------
|
||||
|
||||
# Manual Installation Instructions
|
||||
|
||||
@@ -21,8 +21,9 @@ Re-generate the `messages.pot` file:
|
||||
# -c TRANSLATOR_NOTE: will extract translator hints identified as comments starting with "# NOTE"
|
||||
# -s will strip the "NOTE:" part of the translator hint out
|
||||
# -F specifies the config file
|
||||
# --add-location=file will include filename but not line-number of msgid
|
||||
# -o is our target output file
|
||||
pybabel extract -c TRANSLATOR_NOTE: -s -F babel/babel.cfg -o babel/messages.pot .
|
||||
pybabel extract -c TRANSLATOR_NOTE: -s -F babel/babel.cfg --add-location=file -o babel/messages.pot .
|
||||
```
|
||||
This will rescan all wrapped text, picking up new strings as well as updating existings strings that have been edited.
|
||||
|
||||
@@ -77,4 +78,4 @@ In order to make that as transparent as possible, that procedure has been integr
|
||||
python3 setup.py install
|
||||
```
|
||||
|
||||
Unfortunately, it won't be executed by `pip3 install -e .` even though that has been propagated very long to be the developement-env installation procedure. -->
|
||||
Unfortunately, it won't be executed by `pip3 install -e .` even though that has been propagated very long to be the developement-env installation procedure. -->
|
||||
|
||||
@@ -1,40 +1,207 @@
|
||||
## Verifying dice seed generation
|
||||
# Verifying dice seed generation
|
||||
|
||||
It is possible to do a 'dry run' to verify that seed generation has not been tempered.
|
||||
This will ensure that the derivation algorithm has not been tempered and is still same as well known algorithm used bu coldcard and ian coleman bip39 webpage.
|
||||
For example an 'evil maid' attack would be someone accesing your sdcard and change the code to only take in account 5 or 6 dice, so the 24 words would still feel random but the attacker will need to brute force only 5 or 6 dice (very easy).
|
||||
This is part of the "do not trust, verify" crypto mottos.
|
||||
The intention of this documentation is to describe how to verify the seed generation code used in SeedSigner against other independent tools, to prove that they all generate the same results, despite them using different programming languages and code libraries.<br><br>
|
||||
As it is an important step to verify all software releases being used to ensure that the installation files downloaded have not been compromised, the same is true especially for the seed generation procedure which unknowingly might not work as expected due to bugs or even on purpose.<br><br>
|
||||
This guide describes how this can be achieved.<br><br>
|
||||
As usual: Don't Trust, Verify!<br>
|
||||
<br><br>
|
||||
**Note:**<br>
|
||||
**Do NOT use this with any seed you want to use later with real funds. This exercise is only for checking that the independent codebases get to the same end result!**<br>
|
||||
**However, if you do want to check your real seedphrases you should download the Iancoleman and/or Bitcoiner.Guide tools onto an airgapped, ephemeral computer (e.g. using tails-OS) and perform these tests on there. Destroy/abandon the TailsOS afterwards.**<br>
|
||||
**Never input seed phrases that you intend to use to store real funds onto an internet-connected computer!!!**
|
||||
<br><br><br>
|
||||
|
||||
### Verifying with Ian coleman webpage
|
||||
## 99 Dice Rolls / 24 Seed Words Example
|
||||
|
||||
Go to https://iancoleman.io/bip39 and check show entropy detail:
|
||||
<img src="img/dice_entr.png">
|
||||
The following 99 dice roll results are used in the verification steps as an example for a 24 words seed:<br>
|
||||
> 655152231316521321611331544441236164664431121534415633526456254462245546236542364246312613322234612
|
||||
|
||||
And then make sure to check 'Hex' or 'base 10' (1) and 24 words as mnemonic length (2).
|
||||
Do not use 'dice' format because dice 6 will be replaced by 0.
|
||||
And then enter the 99 dices numbers in (3) :
|
||||
<img src="img/dice_type.png">
|
||||
The corresponding 24 seed words are:<br>
|
||||
> eyebrow obvious such suggest poet seven breeze blame virtual frown dynamic donor harsh pigeon express broccoli easy apology scatter force recipe shadow claim radio
|
||||
|
||||
When the 99 dice number has been entered in the seedsigner and ian coleman page, you will be able to verify that the 24 words are the same.
|
||||
(Scroll down near the end to see result values for a 50 dice rolls / 12 seed words example)
|
||||
<br><br><br>
|
||||
|
||||
## Creating seed via Dice rolls in SeedSigner (here v0.6.0)
|
||||
|
||||
#### Here in real life:
|
||||
First we create a new seed based on dice rolls in SeedSigner:<br><br>
|
||||
Power on your SeedSigner, go to the 'Tools' menu and select 'New Seed' (with the dice symbols):<br>
|
||||
<img src="img/dicedoc/sesi_tools_dice_seed.png" width="600">
|
||||
|
||||
We start with first 3 roll, it is important to always read dice roll from left to right to avoid human bias:
|
||||
<img src="img/dice_pic1.png">
|
||||
Select '24 words (99 rolls)' and on the next screen enter the dice numbers one after another:<br>
|
||||
<img src="img/dicedoc/sesi_dice_1.png" width="600">
|
||||
|
||||
Then we arrive at the 99th dice:
|
||||
<img src="img/dice_pic2.png">
|
||||
Go on until the end (99 dice roll numbers):<br>
|
||||
<img src="img/dicedoc/sesi_dice_2.png" width="600">
|
||||
|
||||
Then same 24 words! :
|
||||
<img src="img/dice_pic3.png">
|
||||
After that the 24 seed words are shown (in 6 screens of 4 words each):<br>
|
||||
<img src="img/dicedoc/sesi_seed_1.png" width="600">
|
||||
<br>**.....**<br>
|
||||
<img src="img/dicedoc/sesi_seed_2.png" width="600">
|
||||
|
||||
Now we are sure that the dice derivation is correct and we can unplug everything and do a new dice roll only on the seedsigner.
|
||||
The fingerprint for this seed is:<br>
|
||||
<img src="img/dicedoc/sesi_finger_print.png" width="600">
|
||||
<br><br><br>
|
||||
Having now created a dice-based seed in the SeedSigner, we will go on to compare those details to what appears in the:
|
||||
* Sparrow desktop wallet software
|
||||
* Ian Coleman's Mnemonic Code Converter website
|
||||
* Seed Tool website
|
||||
|
||||
### Verifying with Coldcard
|
||||
We will create a wallet to have the complete zpub and receive/change addresses to check against the two web pages.<br>
|
||||
SeedSigner currently supports BlueWallet, Nunchuk, Sparrow and Specter Desktop. Here we will use Sparrow wallet as an example.<br>
|
||||
|
||||
There is nothing specific, the algorithm are completely the same. Coldcard has a verification script in python and all explanations here:
|
||||
https://coldcard.com/docs/verifying-dice-roll-math
|
||||
Keep the SeedSigner open and the newly created seed still loaded as we will need it in the next step.
|
||||
<br><br><br>
|
||||
|
||||
## Create new wallet from seed in Sparrow Wallet to see xpub/zpub and addresses
|
||||
|
||||
Go to https://www.sparrowwallet.com/download/ and download the release version supported by your operating system.<br><br>
|
||||
Open Sparrow Wallet, go to 'File' menu and select 'New Wallet'. Enter a name (e.g. test), and click 'Create Wallet'.<br><br>
|
||||
Click 'Airgapped Hardware Wallet' (1) and click on the 'Scan' button in the SeedSigner entry (2) which will open the camera scan screen:<br>
|
||||
<kbd><img src="img/dicedoc/sparrow_wallet_1.png"></kbd>
|
||||
|
||||
On SeedSigner go to the seed just created and click 'Export Xpub':<br>
|
||||
<img src="img/dicedoc/sesi_export_xpub_1.png" width="600">
|
||||
|
||||
Follow these menu entries in SeedSigner:<br>
|
||||
> Export Xpub --> Single Sig --> Native Segwit --> Sparrow<br>
|
||||
|
||||
<img src="img/dicedoc/sesi_export_xpub_2.png" width="600">
|
||||
|
||||
Click 'Export Xpub' and SeedSigner will show an animated QR code to be scanned in Sparrow Wallet (where we are still in the wallet creation).<br>
|
||||
Scan the QR code SeedSigner is showing in Sparrow Wallet.<br><br>
|
||||
The wallet has now been created in Sparrow. Click 'Apply' button to finalize. The wallet's settings screen now looks like this:<br>
|
||||
<kbd><img src="img/dicedoc/sparrow_wallet_2.png"></kbd>
|
||||
|
||||
We will later use this to verify: (1) fingerprint, (2) zpub (click this button to switch between xpub and zpub!) and (3) addresses on the 'Addresses' tab.
|
||||
<br><br><br>
|
||||
|
||||
## Verifying with Ian Coleman BIP39 website
|
||||
|
||||
Go to https://iancoleman.io/bip39 and check 'Show entropy details' (1):<br>
|
||||
<kbd><img src="img/dicedoc/coleman_entropy.png"></kbd>
|
||||
|
||||
<br>
|
||||
Make sure to check (1) 'Hex' and (2) '24 Words' as 'Mnemonic Length'.<br>
|
||||
(Do not use 'dice' format because dice 6 will be replaced by 0).<br>
|
||||
Then enter the 99 dices numbers in (3). The corresponding seed words are shown in (4):<br>
|
||||
<kbd><img src="img/dicedoc/coleman_verify.png"></kbd>
|
||||
<br><br>
|
||||
The 24 seed words are the same in SeedSigner and the Ian Coleman tool.
|
||||
<br><br>
|
||||
|
||||
### Verification of (1) fingerprint, (2) zpub and (3) generated addresses
|
||||
**Fingerprint:**<br>
|
||||
Fingerprint is not shown in the Ian Coleman tool (so cannot be verified here)
|
||||
<br><br>
|
||||
**Zpub:**<br>
|
||||
Scroll down to the 'Derivation Path' section, click on the 'BIP84' tab (1) and find the zpub in (2):
|
||||
<kbd><img src="img/dicedoc/coleman_zpub.png"></kbd><br><br>
|
||||
Compare to zpub in Sparrow:<br>
|
||||
<kbd><img src="img/dicedoc/sparrow_zpub.png"></kbd>
|
||||
<br>
|
||||
|
||||
Zpub is the same as shown in SeedSigner and Sparrow wallet.
|
||||
<br><br>
|
||||
**Addresses:**<br>
|
||||
Scroll down to the 'Derived Addresses' section and compare the receive addresses to the ones generated in Sparrow ('Addresses' tab of the wallet):
|
||||
<kbd><img src="img/dicedoc/coleman_addresses.png"></kbd>
|
||||
<br>
|
||||
|
||||
Check that the receive addresses all match.<br><br>
|
||||
To verify the change addresses, change 'External / Internal' to 1 (1):
|
||||
<kbd><img src="img/dicedoc/coleman_change_addresses_1.png"></kbd><br><br>
|
||||
Compare the change addresses to the ones generated in Sparrow ('Addresses' tab of the wallet):
|
||||
<kbd><img src="img/dicedoc/coleman_change_addresses_2.png"></kbd>
|
||||
<br>
|
||||
|
||||
Check that the change addresses all match.
|
||||
<br><br><br>
|
||||
|
||||
## Verifying with Seed Tool website
|
||||
|
||||
Go to https://bitcoiner.guide/seed/ and click on 'Seed Generation Input' (1):<br>
|
||||
<kbd><img src="img/dicedoc/seedtool_1.png"></kbd>
|
||||
|
||||
Then click on the 'Show the Entropy Section' tab (1):<br>
|
||||
<kbd><img src="img/dicedoc/seedtool_2.png"></kbd>
|
||||
|
||||
Enter the 99 dice numbers in (1), in (2) change back to 'Hex', check that (3) is still '24 Words' and the calculated seed words are shown in (4):<br>
|
||||
<kbd><img src="img/dicedoc/seedtool_3.png"></kbd>
|
||||
|
||||
Seed words shown are the same as in SeedSigner and the Ian Coleman web tool seen before.
|
||||
<br><br>
|
||||
|
||||
### Verification of (1) fingerprint, (2) zpub and (3) generated addresses
|
||||
|
||||
**Fingerprint:**<br>
|
||||
Fingerprint can be seen here (1): <br>
|
||||
<kbd><img src="img/dicedoc/seedtool_fingerprint.png"></kbd><br><br>
|
||||
**Zpub:**<br>
|
||||
Scroll down to the 'Derived Addresses' section (1), click on it, make sure that '84' is selected for 'Purpose' (2) and check the zpub at (3):<br>
|
||||
<kbd><img src="img/dicedoc/seedtool_zpub.png"></kbd><br><br>
|
||||
Compare to zpub in Sparrow:<br>
|
||||
<kbd><img src="img/dicedoc/sparrow_zpub.png"></kbd>
|
||||
<br>
|
||||
|
||||
Zpub is the same as shown in SeedSigner, Sparrow and Ian Colemand tool.
|
||||
<br><br>
|
||||
**Addresses:**<br>
|
||||
Scroll down a little bit where the receive addresses are shown and compare to the ones generated in Sparrow ('Addresses' tab of the wallet):<br>
|
||||
<kbd><img src="img/dicedoc/seedtool_addresses.png"></kbd>
|
||||
<br>
|
||||
|
||||
Check that the receive addresses all match.<br><br>
|
||||
To verify the change addresses, change the 'Receive/Change' dropdown box to '1 (Change)' (1):
|
||||
<kbd><img src="img/dicedoc/seedtool_change_addresses_1.png"></kbd><br><br>
|
||||
Compare the change addresses to the ones generated in Sparrow ('Addresses' tab of the wallet):
|
||||
<kbd><img src="img/dicedoc/seedtool_change_addresses_2.png"></kbd>
|
||||
<br>
|
||||
|
||||
Check that the change addresses all match.
|
||||
<br><br><br>
|
||||
|
||||
## 50 Dice Rolls / 12 Seed Words Example
|
||||
|
||||
SeedSigner supports the creation of mnenomic seeds both with 12 or 24 seed words corresponding to 50 or 99 dice rolls. Below are some example result values for using 50 dice rolls only.<br><br>
|
||||
All the steps shown can be executed the same way, just select the '12 words (50 rolls)' option in SeedSigner and change the 'Mnenomic Length' dropdown boxes in both web tools to '12 Words'.<br><br>
|
||||
|
||||
50 dice roll results as an example for a 12 words seed:<br>
|
||||
> 65515223131652132161133154444123616466443112153441
|
||||
|
||||
The corresponding 12 seed words are:<br>
|
||||
> hole luggage safe present express tragic orbit shed switch metal identify path
|
||||
|
||||
Fingerprint:<br>
|
||||
> 8d9cced8
|
||||
|
||||
Zpub:<br>
|
||||
> zpub6qf9ziL759pzyhKMWaPfNSiCETkoA6oq3fbCDvXqcURiMtPnkEg3nH93W5mrSkvGPoJC9xTYZheYDsYoiYc5AkSk9iY3DkCJHkFgHMdijW6
|
||||
|
||||
Addresses:<br>
|
||||
Receive:<br>
|
||||
> bc1q00lln3r4mt4uwvg7mxv96xgpewauwmggkex2ff<br>
|
||||
> bc1q0jj2cv965f3642mv4lgq5za80jtfpkd0jhjefr<br>
|
||||
> bc1qpecssejm2678v0rknk9tsxd5fsshezfr0vr5m5<br>
|
||||
> bc1qcsl37xn5rkfz8qhcfwq5u52acxecyyfz0kv4gh<br>
|
||||
> bc1q8ehx53re0wck4m9tzek8mlnctp2ztm7jq94zm4<br>
|
||||
> ...<br>
|
||||
|
||||
Change:<br>
|
||||
> bc1qz0ckhg3m349qpmweyn5v6r6tvx2wfw4nv8h75q<br>
|
||||
> bc1qme5tu2t424ws3z69u445q0yw88vpc7fwygra4r<br>
|
||||
> bc1qznuyuc087ky7fhv4nvlmll4p586ks4ggcyt36d<br>
|
||||
> bc1qjcqxv22j0g00pehruwwh34sw5znu6vp3myaspy<br>
|
||||
> bc1q6dpfl7czd22wt0max6p09vr6lvvpag7xw9u8lc<br>
|
||||
> ...
|
||||
|
||||
<br><br>
|
||||
## Conclusion
|
||||
|
||||
What did we achieve now?<br>
|
||||
|
||||
We created a dice-based seed in SeedSigner and set up a wallet using this seed in Sparrow wallet (as this is what a seed is used for).<br><br>
|
||||
We double-checked in two different web tools implementing different methods for seed creation that what SeedSigner generates perfectly matches up with what the other tools calculate based on the same dice entropy used.<br>
|
||||
|
||||
So congratulations if the fingerprints, zpubs and addresses all match up in your example so you can be much more confident that nothing is wrong with your generated seed.
|
||||
|
||||
### Epilogue
|
||||
You can use these methods to do dry run time to time to verify that no one has changed the micro sdcard. But do not use the generated 24 words as a valid wallet, they need to be generated alone, only on the seedsigner!
|
||||
|
||||
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 764 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 315 KiB |
|
After Width: | Height: | Size: 605 KiB |
|
After Width: | Height: | Size: 2.0 MiB |
|
After Width: | Height: | Size: 876 KiB |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 180 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 196 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 140 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 414 KiB |
|
After Width: | Height: | Size: 332 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 576 KiB |
|
After Width: | Height: | Size: 505 KiB |
|
After Width: | Height: | Size: 436 KiB |
|
After Width: | Height: | Size: 462 KiB |
|
After Width: | Height: | Size: 265 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 142 KiB |
|
After Width: | Height: | Size: 146 KiB |
@@ -0,0 +1,22 @@
|
||||
# Legacy Hardware Modifications
|
||||
|
||||
Older Raspberry Pi devices have a smaller GPIO header, 26 pin as opposed to the 40 pin header found on more recent models. The Waveshare LCD hat uses some of the pins between 26 and 40 for the buttons, meaning that these will need to be reassigned (and remapped in software) when used with an older device.
|
||||
|
||||
## Hardware Changes
|
||||
|
||||
A suggested remapping can be found here:
|
||||

|
||||
|
||||
This remapping can be done by soldering wires on to the Waveshare hat as below:
|
||||

|
||||
|
||||
Alternatively, you could do this by connecting the LCD hat on with individual breadboard jumper wires.
|
||||
|
||||
Once you have re-mapped the pins, it is advised to do an IO Test to ensure that everything works.
|
||||
|
||||
**Warning: Some of the GPIO pins on contain 5 volt output. Raspberry Pi GPIO pins are NOT 5V tolerant, meaning that if you accidentally connect a 5V supply pin to a GPIO input pin, you risk permanent damage.**
|
||||
|
||||
## Software Changes
|
||||
The Seedsigner software will automatically detect which hardware revision you are using and if the older hardware is detected, will remap the software to match the above modifications to the Waveshare hat.
|
||||
|
||||
If you are using a pre-built Seedsigner image that hasn't yet has this incorporated, you can simply take the file "buttons.py" (/src/seedsigner/hardware/ int his repository) and overwrite same file on your Seedsigner SD card. (The easiest way to do this is to copy it on to the /boot/ partitition of the SD card then copy it over via the command line while connected to your Pi via monitor+keyboard) O
|
||||
@@ -6,20 +6,25 @@ https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2
|
||||
|
||||
Best practice is to verify the downloaded .zip file containing the Raspberry Pi Lite OS matches the published SHA256 hash of the file; for additional reference that hash is: c5dad159a2775c687e9281b1a0e586f7471690ae28f2f2282c90e7d59f64273c. After verifying the file's data integrity, you can decompress the .zip file to obtain the operating system image that it contains. You can then use Balena's Etcher tool (https://www.balena.io/etcher/) to write the Raspberry Pi Lite software image to a memory card (4 GB or larger). It's important to note that an image authoring tool must be used (the operating system image cannot be simply copied into a file storage partition on the memory card).
|
||||
|
||||
The manual SeedSigner installation and configuration process requires an internet connection on the device to download the necessary libraries and code. But because the Pi Zero 1.3 does not have onboard wifi, you have two options:
|
||||
The manual SeedSigner installation and configuration process requires an internet connection on the Pi to download the necessary libraries and code.
|
||||
If your Pi does not have onboard wifi, you have two options:
|
||||
|
||||
1. Run these steps on a separate Raspberry Pi 2/3/4 or Zero W which can connect to the internet and then transfer the SD card to the Pi Zero 1.3 when complete.
|
||||
2. OR configure the Pi Zero 1.3 directly by relaying through your computer's internet connection over USB. See instructions [here](usb_relay.md).
|
||||
1. Run these steps on a separate Raspberry Pi 2/3/4 or Zero W which does have onboard Wi-Fi to connect to the internet, and then move the SD card over to the non Wi-Fi enabled Pi when complete.
|
||||
2. OR configure the non Wi-Fi enabled Pi directly by relaying through your computer's internet connection over USB. See instructions [here](usb_relay.md).
|
||||
|
||||
If your Pi does have onboard Wi-Fi, then using the Rasberry Pi Imager software will allow you to easily configure your Pi's Wi-Fi connection, as well as simultaneously write the image file. That will make your initial SSH into the Pi much easier.
|
||||
Use the Pi's onboard Wi-Fi only if you are setting up a local development environment, never for real funds or binary image creation.
|
||||
|
||||
For the following steps you'll need to either connect a keyboard & monitor to the network-connected Raspberry Pi you are working with, or SSH into the Pi if you're familiar with that process.
|
||||
|
||||
### Configure the Pi
|
||||
First things first, verify that you are using the correct version of the Raspberry Pi Lite operating system by typing the command:
|
||||
```
|
||||
```bash
|
||||
cat /etc/os-release
|
||||
```
|
||||
|
||||
The output of this command should match the following text:
|
||||
```
|
||||
```bash
|
||||
PRETTY_NAME="Raspbian GNU/Linux 10 (buster)"
|
||||
NAME="Raspbian GNU/Linux"
|
||||
VERSION_ID="10"
|
||||
@@ -33,7 +38,7 @@ BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
|
||||
```
|
||||
|
||||
Now launch the Raspberry Pi's System Configuration tool using the command:
|
||||
```
|
||||
```bash
|
||||
sudo raspi-config
|
||||
```
|
||||
|
||||
@@ -45,25 +50,65 @@ Set the following:
|
||||
* `Locale`: arrow up and down through the list and select or deselect languages with the spacebar.
|
||||
* Deselect the default language option that is selected
|
||||
* Select `en_US.UTF-8 UTF-8` for US English
|
||||
* Use the `TAB` button to select `Ok` and press `ENTER`
|
||||
* On the next screen select `en_US.UTF-8` for the default locale
|
||||
* You will also need to configure the WiFi settings if you are using the #1 option above to connect to the internet
|
||||
|
||||
When you exit the System Configuration tool, you will be prompted to reboot the system; allow the system to reboot and continue with these instructions.
|
||||
|
||||
|
||||
Each command should be run individually,unless its specified as a multi-line command.
|
||||
### Change the default password
|
||||
Change the system's default password from the default "raspberry". Run the command:
|
||||
```
|
||||
```bash
|
||||
passwd
|
||||
```
|
||||
You will be prompted to enter the current password ("raspberry") and then to enter a new password twice. In our prepared release image, the password used is `AirG@pped!`.
|
||||
|
||||
|
||||
### Install dependencies
|
||||
Copy this entire box and run it as one command (will take 15-20min to complete):
|
||||
### Install python3.10
|
||||
```bash
|
||||
# install compiler dependencies; takes ~1 minute on a Pi Zero 1.3
|
||||
# * openssl, libssl-dev: ssl support when pip fetches packages
|
||||
# * libsqlite3-dev: required by `coverage`
|
||||
sudo apt update && sudo apt install -y build-essential zlib1g-dev \
|
||||
libncurses5-dev libgdbm-dev libnss3-dev openssl libssl-dev \
|
||||
libreadline-dev libffi-dev wget libsqlite3-dev
|
||||
|
||||
# Grab the python3.10 source
|
||||
wget https://www.python.org/ftp/python/3.10.10/Python-3.10.10.tgz
|
||||
tar -xzvf Python-3.10.10.tgz
|
||||
cd Python-3.10.10
|
||||
|
||||
# Takes ~6 minutes on a Pi Zero 1.3 to check what is available
|
||||
./configure --enable-optimizations
|
||||
|
||||
# compiling takes ~80 minutes(!!) on a Pi Zero 1.3
|
||||
sudo make altinstall
|
||||
|
||||
# cleanup
|
||||
cd ..
|
||||
sudo rm -rf Python-3.10.10*
|
||||
|
||||
# Make python3.10 the default version
|
||||
sudo update-alternatives --install /usr/bin/python python /usr/local/bin/python3.10 1
|
||||
sudo update-alternatives --install /usr/bin/python3 python3 /usr/local/bin/python3.10 1
|
||||
```
|
||||
sudo apt-get update && sudo apt-get install -y wiringpi python3-pip \
|
||||
python3-numpy python-pil libopenjp2-7 git python3-opencv \
|
||||
python3-picamera libatlas-base-dev qrencode
|
||||
|
||||
Manually re-install `python3-apt` to avoid error messages in later steps (though, ironically, you will see the "ModuleNotFoundError: No module named 'apt_pkg'" error message during the `apt remove` step):
|
||||
```bash
|
||||
sudo apt remove --purge python3-apt -y
|
||||
sudo apt autoremove -y
|
||||
sudo apt install python3-apt -y
|
||||
```
|
||||
|
||||
|
||||
### Install dependencies
|
||||
Copy this entire box and run it as one command (will take a while to complete):
|
||||
```bash
|
||||
sudo apt update && sudo apt install -y wiringpi python3-pip \
|
||||
python3-numpy python-pil libjpeg-dev zlib1g-dev libopenjp2-7 \
|
||||
git python3-opencv python3-picamera libatlas-base-dev qrencode
|
||||
```
|
||||
|
||||
### Install `zbar`
|
||||
@@ -72,17 +117,17 @@ sudo apt-get update && sudo apt-get install -y wiringpi python3-pip \
|
||||
SeedSigner requires `zbar` at 0.23.x or higher.
|
||||
|
||||
Download the binary:
|
||||
```
|
||||
```bash
|
||||
curl -L http://raspbian.raspberrypi.org/raspbian/pool/main/z/zbar/libzbar0_0.23.90-1_armhf.deb --output libzbar0_0.23.90-1_armhf.deb
|
||||
```
|
||||
|
||||
And then install it:
|
||||
```
|
||||
```bash
|
||||
sudo apt install ./libzbar0_0.23.90-1_armhf.deb
|
||||
```
|
||||
|
||||
Cleanup:
|
||||
```
|
||||
```bash
|
||||
rm libzbar0_0.23.90-1_armhf.deb
|
||||
```
|
||||
|
||||
@@ -90,7 +135,7 @@ rm libzbar0_0.23.90-1_armhf.deb
|
||||
This library "provides functions for reading digital inputs and setting digital outputs, using SPI and I2C, and for accessing the system timers."
|
||||
|
||||
Run each of the following individual steps:
|
||||
```
|
||||
```bash
|
||||
wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.60.tar.gz
|
||||
tar zxvf bcm2835-1.60.tar.gz
|
||||
cd bcm2835-1.60/
|
||||
@@ -102,88 +147,91 @@ sudo rm -rf bcm2835-1.60
|
||||
```
|
||||
|
||||
### Set up `virtualenv`
|
||||
```
|
||||
pip3 install virtualenvwrapper
|
||||
```bash
|
||||
python -m pip install virtualenvwrapper
|
||||
```
|
||||
|
||||
Edit your bash profile with the command `nano ~/.profile` and add the following to the end:
|
||||
```
|
||||
```bash
|
||||
export WORKON_HOME=$HOME/.envs
|
||||
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
|
||||
source /home/pi/.local/bin/virtualenvwrapper.sh
|
||||
source $HOME/.local/bin/virtualenvwrapper.sh
|
||||
```
|
||||
Then `CTRL-X` and `y` to exit and save changes.
|
||||
|
||||
Now create the python virtualenv for SeedSigner with these two commands:
|
||||
```
|
||||
Now create the virtualenv for SeedSigner:
|
||||
```bash
|
||||
source ~/.profile
|
||||
mkvirtualenv --python=python3 seedsigner-env
|
||||
mkvirtualenv seedsigner-env
|
||||
```
|
||||
|
||||
For convenience you can configure your `.profile` to auto-activate the SeedSigner virtualenv when you ssh in. Once again `nano ~/.profile` and add at the end:
|
||||
```
|
||||
```bash
|
||||
workon seedsigner-env
|
||||
```
|
||||
|
||||
Optional: If you're going to be testing new code on the SeedSigner, you'll find yourself often needing to kill the SeedSigner code that automatically runs at startup (we'll be configuring this further down). As an extra convenience you can list the process id so that you can then kill it from the terminal:
|
||||
```
|
||||
ps aux | grep main.py
|
||||
```
|
||||
|
||||
Save your changes with `CTRL-X` and `y`.
|
||||
|
||||
Now when you `ssh` in you'll see something like:
|
||||
```
|
||||
pi 297 65.4 9.7 74096 36736 ? Rsl 09:26 10:29 /home/pi/.envs/seedsigner-env/bin/python main.py
|
||||
pi 857 0.0 0.4 7332 1876 pts/0 S+ 09:42 0:00 grep --color=auto main.py
|
||||
```
|
||||
|
||||
The top line is our SeedSigner code running. To stop it, run:
|
||||
```
|
||||
kill 297
|
||||
```
|
||||
Where `297` is the process id listed in the output above (it'll be different each time).
|
||||
|
||||
|
||||
### Download the SeedSigner code:
|
||||
```
|
||||
```bash
|
||||
git clone https://github.com/SeedSigner/seedsigner
|
||||
cd seedsigner
|
||||
```
|
||||
|
||||
If you want to run a specific branch within the main SeedSigner repo, switch to it with:
|
||||
```
|
||||
git checkout yourtargetbranch
|
||||
```
|
||||
|
||||
And if you want to test a pull request (PR), for example PR #123:
|
||||
```
|
||||
git fetch origin pull/123/head:pr_123
|
||||
git checkout pr_123
|
||||
```
|
||||
|
||||
where `pr_123` is any name you want to give to the new branch in your local repo that will hold the PR.
|
||||
|
||||
|
||||
### Install Python `pip` dependencies:
|
||||
```
|
||||
pip3 install -r requirements.txt
|
||||
```bash
|
||||
# Takes 1hr 45min on a Pi Zero 1.3
|
||||
pip install -r requirements.txt
|
||||
pip install -r requirements-raspi.txt
|
||||
```
|
||||
|
||||
#### `pyzbar`
|
||||
Note: The `requirements.txt` installs a fork of the python `pyzbar` repo (for now pointing to the fork in Keith's `kdmukai` github account [https://github.com/kdmukai/pyzbar](https://github.com/kdmukai/pyzbar)).
|
||||
Note: The `requirements.txt` installs a fork of the python `pyzbar` repo.
|
||||
|
||||
The fork is required because the main `pyzbar` repo has been abandoned. This [github issue](https://github.com/NaturalHistoryMuseum/pyzbar/issues/124#issuecomment-971967091) discusses the changes needed in order to support reading binary data from `zbar`, which is required for our `CompactSeedQR` format which writes byte data instead of strings. The changes specifically reference the following PRs which have already been merged into Keith's fork:
|
||||
* [PR 76](https://github.com/NaturalHistoryMuseum/pyzbar/pull/76/files): enables scanning to continue even when a null byte (`x\00`) is found.
|
||||
* [PR 82](https://github.com/NaturalHistoryMuseum/pyzbar/pull/82): enable `zbar`'s new binary mode. Note that this PR has a trivial bug that was fixed in Keith's fork.
|
||||
* [PR 82](https://github.com/NaturalHistoryMuseum/pyzbar/pull/82): enable `zbar`'s new binary mode. Note that this PR has a trivial bug that was fixed in our fork.
|
||||
|
||||
|
||||
### Finish configuring the virtualenv
|
||||
Set the SeedSigner `src/` directory as the project directory for the virtualenv (this is where the virtualenv will take you when you activate it):
|
||||
```bash
|
||||
cd src
|
||||
setvirtualenvproject
|
||||
```
|
||||
|
||||
Test it out:
|
||||
```bash
|
||||
# exit the virtualenv
|
||||
deactivate
|
||||
|
||||
# change dirs to somewhere else
|
||||
cd ~
|
||||
|
||||
# activate the virtualenv
|
||||
workon seedsigner-env
|
||||
|
||||
# you should now be back in the SeedSigner src/ directory
|
||||
pwd
|
||||
```
|
||||
|
||||
### Optional: increase spidev buffer size
|
||||
This allows `ST7789.py` to update the LCD without performing multiple write operations because the default buffer size is 4096 bytes. The default can be changed via the `/boot/cmdline.txt` file. You will need to add `spidev.bufsiz=131072` to the end of this single lined file command.
|
||||
|
||||
Example `cmdline.txt` contents:
|
||||
```
|
||||
console=serial0,115200 console=tty1 root=PARTUUID=2fa4ba7e-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait modules-load=dwc2,g_ether spidev.bufsiz=131072
|
||||
```
|
||||
|
||||
### Configure `systemd` to run SeedSigner at boot:
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo nano /etc/systemd/system/seedsigner.service
|
||||
```
|
||||
|
||||
Add the following contents to the text file that was created:
|
||||
```
|
||||
Add the following contents to the text file that was created:
|
||||
If you are not using the username pi, then replace `pi` in the service section below with your username. There are 3 lines to change.
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Seedsigner
|
||||
|
||||
@@ -199,46 +247,98 @@ WantedBy=multi-user.target
|
||||
|
||||
_Note: For local dev you'll want to edit the `Restart=always` line to `Restart=no`. This way when your dev code crashes it won't keep trying to restart itself. Note that the UI "Reset" will no longer work when auto-restarts are disabled._
|
||||
|
||||
_Note: Debugging output is completely wiped via routing the output to `/dev/null 2>&1`. When working in local dev, you're better off disabling the `systemd` SeedSigner service and just directly running the app so you can see all the debugging output live._
|
||||
_Note: Debugging output is completely wiped via routing the output to `/dev/null 2>&1`. When working in local dev, you'll `kill` the `systemd` SeedSigner service and just directly run the code on demand so you can see all the debugging output live._
|
||||
|
||||
Use `CTRL-X` and `y` to exit and save changes.
|
||||
|
||||
Configure the service to start running (this will restart the seedsigner code automatically at startup and if it crashes):
|
||||
```
|
||||
```bash
|
||||
sudo systemctl enable seedsigner.service
|
||||
```
|
||||
|
||||
Now reboot the Raspberry Pi:
|
||||
```
|
||||
```bash
|
||||
sudo reboot
|
||||
```
|
||||
|
||||
After the Raspberry Pi reboots, you should see the SeedSigner splash screen and the SeedSigner menu subsequently appear on the LCD screen (note that it can take up to 60 seconds for the menu to appear).
|
||||
|
||||
|
||||
#### Optional: kill `systemd` SeedSigner process on login
|
||||
If you're going to be testing new code on the device, you'll find yourself often needing to kill the SeedSigner instance that `systemd` automatically runs at startup.
|
||||
|
||||
You can configure your `~/.profile` to find and kill the SeedSigner process when you ssh in.
|
||||
|
||||
`nano ~/.profile` and add at the end:
|
||||
```bash
|
||||
# Find the SeedSigner process and kill it
|
||||
kill $(ps aux | grep '[m]ain.py' | awk '{print $2}')
|
||||
```
|
||||
|
||||
|
||||
### Further OS modifications
|
||||
Disable and remove the system's virtual memory / swap file with the commands:
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo apt remove dphys-swapfile -y
|
||||
sudo apt autoremove -y
|
||||
sudo rm /var/swap
|
||||
```
|
||||
|
||||
## Local testing and development
|
||||
For those who will use the SeedSigner installation for testing/development, it can be helpful to change the system's host name so it doesn't potentially conflict with other Raspberry Pis that may already be present on your network. (For those who don't plan to use the installation for testing or development, you can skip this portion of the process.) To change the host name first edit the "hostname" with the command:
|
||||
## Manually start the SeedSigner code
|
||||
```bash
|
||||
# activate the virtualenv if you haven't already
|
||||
workon seedsigner-env
|
||||
|
||||
# You should now be in the SeedSigner src/ directory. List its contents:
|
||||
ls
|
||||
|
||||
# You should see the main.py file. Run it:
|
||||
python main.py
|
||||
|
||||
# To kill the process, use CTRL-C
|
||||
```
|
||||
|
||||
|
||||
## Local testing and development
|
||||
|
||||
### Run specific branches or PRs
|
||||
The default branch is `dev`. If you want to run a specific release tag or a specific branch:
|
||||
```bash
|
||||
# release tag for v0.6.0:
|
||||
git checkout 0.6.0
|
||||
```
|
||||
|
||||
And if you want to test a pull request (PR), for example PR #123:
|
||||
```bash
|
||||
git fetch origin pull/123/head:pr_123
|
||||
git checkout pr_123
|
||||
```
|
||||
|
||||
where `pr_123` is any name you want to give to the new branch in your local repo that will hold the PR.
|
||||
|
||||
|
||||
### Change the host name
|
||||
For those who will use the SeedSigner installation for testing/development, it can be helpful to change the system's host name so it doesn't potentially conflict with other Raspberry Pis that may already be present on your network. (For those who don't plan to use the installation for testing or development, you can skip this portion of the process.) To change the host name first edit the "hostname" with the command:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/hostname
|
||||
```
|
||||
and change "raspberrypi" to "seedsigner" (or another name). Use `CTRL-X` and `y` to exit and save changes. You'll also need to edit the "hosts" file with the command:
|
||||
```
|
||||
|
||||
and change "raspberrypi" to "seedsigner" (or another name). Use `CTRL-X` and `y` to exit and save changes.
|
||||
|
||||
You'll also need to edit the "hosts" file with the command:
|
||||
```bash
|
||||
sudo nano /etc/hosts
|
||||
```
|
||||
|
||||
and change "raspberrypi" to "seedsigner" (or the other name you previously chose). Use `CTRL-X` and `y` to exit and save changes.
|
||||
|
||||
### Set a static IP
|
||||
Your local machine that `ssh`s into the SeedSigner can sometimes get confused if you're connecting to different SeedSigners that are all identified as `pi@seedsigner.local`. In this case it helps to set a static ip and just `ssh` directly to that instead.
|
||||
|
||||
First find your current `nameserver`:
|
||||
```
|
||||
```bash
|
||||
sudo cat /etc/resolv.conf
|
||||
```
|
||||
|
||||
@@ -260,21 +360,26 @@ static domain_name_servers=192.168.1.254
|
||||
`CTRL-X` and `y` to save changes.
|
||||
|
||||
After your next reboot, access this SeedSigner using its new static ip:
|
||||
```
|
||||
```bash
|
||||
# Use the static ip you set above:
|
||||
ssh pi@192.168.1.200
|
||||
|
||||
# But the hostname will still work, too:
|
||||
ssh pi@seedsigner.local
|
||||
```
|
||||
|
||||
### More convenient `ssh` access:
|
||||
Power SeedSigner devs will find themselves connecting to a lot of different SeedSigners. This can cause headaches with `ssh`'s built-in protections; a different device that uses the same `ssh` credentials is normally a potential spoofing attack. But we're doing this to ourselves on purpose and so we can carve out exceptions.
|
||||
|
||||
On your local machine, run `nano ~/.ssh/config` and add to the end:
|
||||
```
|
||||
```conf
|
||||
host seedsigner.local
|
||||
StrictHostKeyChecking no
|
||||
UserKnownHostsFile /dev/null
|
||||
User pi
|
||||
LogLevel QUIET
|
||||
|
||||
# Set this to the static ip you set above:
|
||||
host 192.168.1.200
|
||||
StrictHostKeyChecking no
|
||||
UserKnownHostsFile /dev/null
|
||||
@@ -293,7 +398,7 @@ The second entry does the same for a specific static ip; you'll want this if you
|
||||
You can also configure the SeedSigner so that you don't have to enter the `pi` password when you `ssh` in.
|
||||
|
||||
run `ssh-copy-id` with the same values that you connect via `ssh`:
|
||||
```
|
||||
```bash
|
||||
ssh-copy-id pi@seedsigner.local
|
||||
|
||||
# or if you're connecting over static ip, something like:
|
||||
@@ -307,7 +412,7 @@ _Note: If you don't have any ssh keys on your local machine, you'll need to crea
|
||||
|
||||
## Disable wifi/Bluetooth when using other Raspi boards
|
||||
If you plan to use your installation on a Raspberry Pi that is not a Zero version 1.3, but rather on a Raspberry Pi that has WiFi and Bluetooth capabilities, it is a good idea to disable the following WiFi & Bluetooth, as well as other relevant services (assuming you are not creating this installation for testing/development purposes). Enter the followiing commands to disable WiFi, Bluetooth, & other relevant services:
|
||||
```
|
||||
```bash
|
||||
sudo systemctl disable bluetooth.service
|
||||
sudo systemctl disable wpa_supplicant.service
|
||||
sudo systemctl disable dhcpcd.service
|
||||
@@ -316,12 +421,13 @@ sudo systemctl disable networking.service
|
||||
sudo systemctl disable dphys-swapfile.service
|
||||
sudo ifconfig wlan0 down
|
||||
```
|
||||
|
||||
Please note that if you are using WiFi to connect/interact with your Raspberry Pi, the last command will sever that connection.
|
||||
|
||||
You can now safely power the Raspberry Pi off from the SeedSigner main menu.
|
||||
|
||||
If you do not plan to use your installation for testing/development, it is also a good idea to disable WiFi and Bluetooth by editing the config.txt file found in the installation's "boot" partition. You can add the following text to the end of that file with any simple text editor (Windows: Notepad, Mac: TextEdit, Linux: nano):
|
||||
```
|
||||
```ini
|
||||
dtoverlay=disable-bt
|
||||
dtoverlay=pi3-disable-wifi
|
||||
```
|
||||
|
||||
@@ -23,7 +23,7 @@ Derivation paths for standard script types for mainnet:
|
||||
- Script Type: P2WSH in P2SH
|
||||
- Public Key Encoding: 0x0295b43f - Ypub
|
||||
|
||||
Custom derivation paths are also optional when generating an xpub from SeedSigner. The Public Key Encodings is detected based on the derivation path configured. Embit bitcoin library does the detection and is documented [here](https://github.com/diybitcoinhardware/embit/blob/master/docs/api/bip32.md#detect_version). For a video explination of these standards see a presentation by Stepan of Embit/Specter on this topic: https://youtube.com/watch?v=JCaC5DG2HTM
|
||||
Custom derivation paths are also optional when generating an xpub from SeedSigner. The Public Key Encodings are detected based on the derivation path configured. The `embit` bitcoin library does this detection and is documented [here](https://github.com/diybitcoinhardware/embit/blob/master/docs/api/bip32.md#detect_version). For a video explanation of these standards see a presentation by Stepan of `embit` on this topic: https://youtube.com/watch?v=JCaC5DG2HTM
|
||||
|
||||
Changing the network settings from main to test in SeedSigner will change the public key encoding and derivation path following [slip-0132](https://github.com/satoshilabs/slips/blob/master/slip-0132.md) standards.
|
||||
|
||||
@@ -32,4 +32,4 @@ Related Standards:
|
||||
- [bip-0044](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki)
|
||||
- [bip-0048](https://github.com/bitcoin/bips/blob/master/bip-0048.mediawiki)
|
||||
- [bip-0049](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki)
|
||||
- [bip-0084](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki)
|
||||
- [bip-0084](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki)
|
||||
|
||||
@@ -70,7 +70,7 @@ It's important to note here that QR codes can encode data in a number of differe
|
||||
|
||||
QR codes are typically used to encode a website url, in which case the "Alphanumeric" format has to be used (the encoded data can consist of upper- and lowercase letters, numbers, and certain allowed symbols).
|
||||
|
||||
If you have a long url like `https://ohnoihavealongurl.com` (29 characters), the chart shows that it would not fit in a 21x21 QR code; its max capacity is 25 alphanumeric chars. But it's within the 47-char capacity of the 29x29 size.
|
||||
If you have a long url like `https://ohnoihavealongurl.com` (29 characters), the chart shows that it would not fit in a 21x21 QR code; its max capacity is 25 alphanumeric chars. But it's within the 47-char capacity of the 25x25 size.
|
||||
|
||||
### Bit efficiency matters
|
||||
Notice that the "Numeric" column has greater capacity. This is because when you have fewer possible characters to encode, it takes less data to specify each one.
|
||||
@@ -298,16 +298,13 @@ It's just the above process in reverse:
|
||||
12. nuclear 1210
|
||||
```
|
||||
|
||||
It would be much more difficult to manually recreate your seed from a CompactSeedQR. Tools like [zxing.org](https://zxing.org/w/decode.jspx) can help you get the binary data out as a hexidecimal string:
|
||||
It would be much more difficult to manually recreate your seed from a CompactSeedQR. Tools like [zxing.org](https://zxing.org/w/decode.jspx) or [ZBar](https://zbar.sourceforge.net/) can help you get the binary data out as a hexidecimal string:
|
||||
|
||||
<img src="img/zxing_screenshot.png">
|
||||
|
||||
All 12-word CompactSeedQRs will start with `41 0` (that specifies the binary data format and says the length of the data is 16 bytes) and end with `0 ec` (unused byte and a half).
|
||||
|
||||
All 24-word CompactSeedQRs will start with `42 0` (binary, data length is 32 bytes) and end with `0` (unused half a byte).
|
||||
|
||||
The remaining hexidecimal data is just an alternate representation of the 128-bit entropy for your 12-word mnemonic (or 256 bits for a 24-word mnemonic). Various programming tools exist to convert from hex back into mnemonic form.
|
||||
Note that for some QR decoders, zxing in particular, may return more data than the compact seed itself: the data type, the data length, and padding. For example, the zxing result from 12-word CompactSeedQRs in low error correction mode will start with `41 0` (that specifies the binary data format and says the length of the data is 16 bytes) and end with `0 ec` (unused byte and a half). Similarly, 24-word CompactSeedQRs will start with `42 0` (binary, data length is 32 bytes) and end with `0` (unused half a byte).
|
||||
|
||||
The ZBar library just returns the encoded data, without metadata or padding.
|
||||
|
||||
## Obfuscation
|
||||
Conversely, having limited support for reading binary QR codes and the complications described above are seen by some as an added security feature. Should someone steal your CompactSeedQR or take a photo of it, they'll have to be fairly savvy to know how to decode it.
|
||||
|
||||
@@ -1,294 +0,0 @@
|
||||
import math
|
||||
|
||||
def generate_qr_template(qr_size, num_words=24, block_size=5, show_timing_marks=False):
|
||||
if num_words == 24:
|
||||
word_cols = 2
|
||||
else:
|
||||
word_cols = 1
|
||||
|
||||
html = """
|
||||
<html>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin-top: 5em;
|
||||
text-align: center;
|
||||
font-family: "Open Sans", sans-serif;
|
||||
-webkit-print-color-adjust: exact;
|
||||
}
|
||||
.title {
|
||||
margin-top: 0.5em;
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 1em
|
||||
}
|
||||
table {
|
||||
margin-top: 1em;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
td {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
.qrcell {
|
||||
text-align: center;
|
||||
font-size: 0.35em;
|
||||
color: black;
|
||||
width: 13px;
|
||||
height: 9px;
|
||||
}
|
||||
.qr_table {
|
||||
margin-left: 4em;
|
||||
display: inline-block;
|
||||
}
|
||||
.filled {
|
||||
background-color: black;
|
||||
border: none;
|
||||
color: white;
|
||||
}
|
||||
.col_name, .row_name {
|
||||
text-align: center;
|
||||
font-size: 0.7em;
|
||||
color: #aaa;
|
||||
}
|
||||
.col_name {
|
||||
border-top: 1px solid #bbb;
|
||||
border-bottom: 1px solid #bbb;
|
||||
height: 2em;
|
||||
}
|
||||
.row_name {
|
||||
border-right: 1px solid #bbb;
|
||||
border-left: 1px solid #bbb;
|
||||
width: 2em;
|
||||
}
|
||||
.first_td {
|
||||
border-top: 1px solid #bbb;
|
||||
border-left: 1px solid #bbb;
|
||||
}
|
||||
.col_block_divider {
|
||||
border-right: 1px solid #bbb;
|
||||
}
|
||||
.row_block_divider {
|
||||
border-bottom: 1px solid #bbb;
|
||||
}
|
||||
.no_border {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.word_list_table {
|
||||
border: 1px solid #aaa;
|
||||
"""
|
||||
|
||||
if num_words == 12:
|
||||
html += "margin-left: 10em;\n"
|
||||
else:
|
||||
html += "margin-left: 0;\n"
|
||||
|
||||
html += """
|
||||
float: left;
|
||||
}
|
||||
.word_list {
|
||||
font-size: 0.5em;
|
||||
text-align: right;
|
||||
padding-top: 2em;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
.word_row {
|
||||
height: 2.5em;
|
||||
}
|
||||
.word_num {
|
||||
width: 1em;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
}
|
||||
.word_blank {
|
||||
color: #ccc;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
"""
|
||||
|
||||
html += """
|
||||
<table align="center" class="word_list_table">
|
||||
<tr>
|
||||
<td class="word_list">
|
||||
"""
|
||||
for i in range(1, num_words + 1):
|
||||
if i == 13:
|
||||
html += """
|
||||
</td>
|
||||
<td class="word_list">
|
||||
"""
|
||||
html += f"""<div class="word_row">
|
||||
<span class="word_num">{i}: </span><span class="word_blank">____________________________</span>
|
||||
</div>
|
||||
"""
|
||||
html += "</td></tr></table>"
|
||||
|
||||
y_names = "A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,X,Y,Z"
|
||||
|
||||
html += """<table align="center" class="qr_table">"""
|
||||
html += f"""<tr rowspan="{block_size}"><td class="col_block_divider row_block_divider first_td"></td>"""
|
||||
for j in range(0, math.ceil(qr_size/block_size)):
|
||||
html += f"""<td colspan="{block_size}" class="col_name col_block_divider">{j + 1}</td>"""
|
||||
html += "</tr>"
|
||||
|
||||
for i in range(0, qr_size):
|
||||
html += """<tr>\n"""
|
||||
if i % block_size == 0:
|
||||
html += f"""<td rowspan="{block_size}" class="row_name row_block_divider qrcell">{y_names.split(",")[int(i / block_size)]}</td>"""
|
||||
for j in range(0, qr_size):
|
||||
html += f"""<td class="qrcell {"row_block_divider" if i == qr_size - 1 else ""} {"col_block_divider" if j == qr_size -1 else ""}" id="{i}_{j}">·</td>"""
|
||||
html += """</tr>\n"""
|
||||
html += "</table>"
|
||||
|
||||
html += "<script>"
|
||||
|
||||
def fill(i, j, clear_contents=True):
|
||||
js_result = f"""document.getElementById("{i}_{j}").classList.add("filled");\n"""
|
||||
if clear_contents:
|
||||
js_result += f"""document.getElementById("{i}_{j}").textContent = '';\n"""
|
||||
return js_result
|
||||
|
||||
def no_border(i, j):
|
||||
js_result = f"""document.getElementById("{i}_{j}").classList.remove("row_block_divider");\n"""
|
||||
js_result += f"""document.getElementById("{i}_{j}").classList.remove("col_block_divider");\n"""
|
||||
js_result += f"""document.getElementById("{i}_{j}").classList.add("no_border");\n"""
|
||||
return js_result
|
||||
|
||||
|
||||
# Generate the corner registration box
|
||||
def fill_registration_box(offset_i, offset_j):
|
||||
result = ""
|
||||
for i in range(0, 7):
|
||||
clear_middot = i != 0 and i != 6
|
||||
i += offset_i
|
||||
result += fill(i, offset_j + 0, clear_contents=clear_middot)
|
||||
result += fill(i, offset_j + 6, clear_contents=clear_middot)
|
||||
for j in range(1, 6):
|
||||
j += offset_j
|
||||
result += fill (offset_i + 0, j)
|
||||
result += fill (offset_i + 6, j)
|
||||
for i in range(2, 5):
|
||||
clear_middot = i != 2 and i != 4
|
||||
i += offset_i
|
||||
result += fill(i, offset_j + 2, clear_contents=clear_middot)
|
||||
result += fill(i, offset_j + 3)
|
||||
result += fill(i, offset_j + 4, clear_contents=clear_middot)
|
||||
|
||||
for i in range(offset_i, offset_i + 7):
|
||||
for j in range(offset_j, offset_j + 7):
|
||||
result += no_border(i, j)
|
||||
return result
|
||||
|
||||
html += fill_registration_box(0, 0)
|
||||
html += fill_registration_box(0, qr_size - 7)
|
||||
html += fill_registration_box(qr_size - 7, 0)
|
||||
|
||||
if show_timing_marks:
|
||||
# Fill the dotted timing marks
|
||||
html += fill(8, 6)
|
||||
html += fill(10, 6)
|
||||
html += fill(12, 6)
|
||||
if qr_size > 21:
|
||||
html += fill(14, 6)
|
||||
html += fill(16, 6)
|
||||
if qr_size > 25:
|
||||
html += fill(18, 6)
|
||||
html += fill(20, 6)
|
||||
|
||||
html += fill(6, 8)
|
||||
html += fill(6, 10)
|
||||
html += fill(6, 12)
|
||||
if qr_size > 21:
|
||||
html += fill(6, 14)
|
||||
html += fill(6, 16)
|
||||
if qr_size > 25:
|
||||
html += fill(6, 18)
|
||||
html += fill(6, 20)
|
||||
|
||||
if qr_size > 21:
|
||||
# Fill the smaller inset registration box
|
||||
html += fill(qr_size - 7, qr_size - 7, clear_contents=False)
|
||||
|
||||
# fill the sides
|
||||
for i in range(qr_size - 9, qr_size - 4):
|
||||
clear_middot = i != (qr_size - 9) and i != (qr_size - 5)
|
||||
html += fill(i, qr_size - 9, clear_contents=clear_middot)
|
||||
html += fill(i, qr_size - 5, clear_contents=clear_middot)
|
||||
for j in range(qr_size - 8, qr_size - 5):
|
||||
html += fill(qr_size - 9, j)
|
||||
html += fill(qr_size - 5, j)
|
||||
for i in range(qr_size - 9, qr_size - 4):
|
||||
for j in range(qr_size - 9, qr_size - 4):
|
||||
html += no_border(i, j)
|
||||
|
||||
|
||||
def add_block_dividers(i, j, class_name):
|
||||
return f"""document.getElementById("{i}_{j}").classList.add("{class_name}");\n"""
|
||||
|
||||
for i in range (0, qr_size):
|
||||
for j in range (block_size - 1, qr_size, block_size):
|
||||
html += add_block_dividers(i, j, "col_block_divider")
|
||||
|
||||
for i in range (block_size - 1, qr_size, block_size):
|
||||
for j in range (0, qr_size):
|
||||
html += add_block_dividers(i, j, "row_block_divider")
|
||||
|
||||
|
||||
html += """</script>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
return html
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="""
|
||||
Generates a blank QR code template at 21x21, 25x25, or 29x29.
|
||||
|
||||
ex: python3 qr_code_template.py 25 12
|
||||
ex: python3 qr_code_template.py 29 24
|
||||
|
||||
Optionally change the block size divider guides:
|
||||
|
||||
python3 qr_code_template.py 29 24 --block_size 6
|
||||
""",
|
||||
formatter_class=argparse.RawTextHelpFormatter
|
||||
)
|
||||
|
||||
# Required positional arguments
|
||||
parser.add_argument('qr_size',
|
||||
type=int,
|
||||
choices=[21, 25, 29],
|
||||
help="QR code size. 21 for 21x21, 25 for 25x25, 29 for 29x29")
|
||||
parser.add_argument('num_words',
|
||||
type=int,
|
||||
choices=[12, 24],
|
||||
help="Number of words in the mnemonic seed. 12 or 24")
|
||||
|
||||
# Add optional arguments
|
||||
parser.add_argument('-b', '--block_size',
|
||||
type=int,
|
||||
default=5,
|
||||
help="Size of the manual entry zoom blocks")
|
||||
parser.add_argument('-t', '--timing_marks',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Show timing marks (the dashed blocks linking the three large registration boxes")
|
||||
args = parser.parse_args()
|
||||
|
||||
html = generate_qr_template(qr_size=args.qr_size, num_words=args.num_words, block_size=args.block_size, show_timing_marks=args.timing_marks)
|
||||
file = open(f"{args.num_words}words_seedqr_template-{args.qr_size}x{args.qr_size}.html", "w")
|
||||
file.write(html)
|
||||
file.close()
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
## The Open Pill Enclosure
|
||||
|
||||
The "Open Pill" was the second officially released SeedSigner enclosure. Given some of the challenges associated with the "Orange Pill", the Open Pill was designed for quick, inexpensive, and simple deployment. No secondary hardware components are required for assembly and the design consists of a single printed part that can be produced with even basic 3D printers. This simpler design was intended to put the focus back on the project's software, which was improving by leaps and bounds when the enclosure was released.
|
||||
|
||||
<img src="/docs/img/Open_Pill_Models.JPG" width="400" height="400">
|
||||
|
||||
### Characterisics:
|
||||
- Supported Camera? Legacy RPi Camera (w/ gold Pi Zero Cable)
|
||||
- Supported HAT? Waveshare 240x240 pixel LCD display + controls
|
||||
- Recommended printing process? FDM
|
||||
- Recommended printing materials? PLA
|
||||
- Secondary Hardware Required? No
|
||||
- Data-enabled USB Port accessible? Yes
|
||||
- Mini-HDMI port accessible? Yes
|
||||
- Removeable Memory Card? Yes
|
||||
- Comfortable controls? No (see note below)
|
||||
|
||||
### Assembly Demonstration:
|
||||
https://www.youtube.com/watch?v=gXPFJygZobE
|
||||
|
||||
|
||||
### Comfortable Controls Optional Upgrade:
|
||||
The bare joystick on an open pill or open pill mini design can be uncomfortable for some thumbs. Twitter user @Vulcan21com developed a DIY solution to add comfort to the exposed joystick using a M2.5 knurled nut standardized under DIN 466, widely available at many hardware stores. The joystick itself has no threading, but it is possible to screw the M2.5 nut onto the joystick with a bit of precision and patience. While screwing it on for the first time it will cut a light thread into the plastic. Be gentle as to not transfer too much torque into the joystick. The result will look like this:
|
||||
|
||||
<img src="/docs/img/Open_Pill_w_Comfort_Joystick.png">
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
## The Open Pill Mini Enclosure
|
||||
|
||||
The "Open Pill Mini" is simply a smaller version of the original "Open Pill" that is designed to incorporate a more compact camera specifically designed for the Raspberry Pi Zero -- this enclosure is just about as small as a SeedSigner can conceivably get. It is pictured below, alongside the original Open Pill enclosure.
|
||||
|
||||
<img src="/docs/img/Open_Pill_Mini_Models.JPG" width="400" height="400">
|
||||
|
||||
### Characterisics:
|
||||
- Supported Camera? "ZeroCam" designed specifically for RPi Zero
|
||||
- Supported HAT? Waveshare 240x240 pixel LCD display + controls
|
||||
- Recommended printing process? FDM
|
||||
- Recommended printing materials? PLA
|
||||
- Secondary Hardware Required? No
|
||||
- Data-enabled USB Port accessible? Yes
|
||||
- Mini-HDMI port accessible? Yes
|
||||
- Removeable Memory Card? Yes
|
||||
- Comfortable controls? No (see note below)
|
||||
|
||||
### Assembly Demonstration:
|
||||
(assembly is very similar to the original Open Pill assembly, depicted below)
|
||||
https://www.youtube.com/watch?v=aIIc2DiZYcI
|
||||
|
||||
### Comfortable Controls Optional Upgrade:
|
||||
The bare joystick on an open pill or open pill mini design can be uncomfortable for some thumbs. Twitter user @Vulcan21com developed a DIY solution to add comfort to the exposed joystick using a M2.5 knurled nut standardized under DIN 466, widely available at many hardware stores. The joystick itself has no threading, but it is possible to screw the M2.5 nut onto the joystick with a bit of precision and patience. While screwing it on for the first time it will cut a light thread into the plastic. Be gentle as to not transfer too much torque into the joystick. The result will look like this:
|
||||
|
||||
<img src="/docs/img/Open_Pill_w_Comfort_Joystick.png">
|
||||
(image displayed is Open Pill, not Open Pill Mini)
|
||||
@@ -0,0 +1,19 @@
|
||||
## The Open Pill Mini w/ Coverplate Enclosure
|
||||
|
||||
The "Open Pill Mini w/ Coverplate" was designed as an attempt to incorporate the best of the "Orange Pill" and the "Open Pill" enclosures into a single design. It is fully enclosed for improved aesthetics and protection of electronic components, yet is compact and can be manufactured with a simple FDM printer, also not requiring any additional hardware components. A first for this enclosure was preventing access to the SeedSigner's data-enabled USB port as an additional security assurance for users.
|
||||
|
||||
<img src="/docs/img/Open_Pill_Mini_w_Faceplate.JPG" width="400" height="400">
|
||||
|
||||
### Characterisics:
|
||||
- Supported Camera? "ZeroCam" designed specifically for RPi Zero
|
||||
- Supported HAT? Waveshare 240x240 pixel LCD display + controls
|
||||
- Recommended printing process? FDM for enclosure & controls
|
||||
- Recommended printing materials? PLA for enclosure, TPU for controls
|
||||
- Secondary Hardware Required? No
|
||||
- Data-enabled USB Port accessible? No
|
||||
- Mini-HDMI port accessible? No
|
||||
- Removeable Memory Card? Yes
|
||||
- Comfortable controls? Yes
|
||||
|
||||
### Assembly Demonstration:
|
||||
https://www.youtube.com/watch?v=6-5cDneXoWs
|
||||
@@ -0,0 +1,24 @@
|
||||
## The Orange Pill Enclosure
|
||||
|
||||
The "Orange Pill" was the first SeedSigner enclosure. It's eye-catching design is the enclosure most commonly associated with the SeedSigner project for many. While aesthetically appealing and fun to showcase to others, the thumbstick topper's sub-optimal design, the need for secondary hardware components, and other drawbacks make this enclosure a less desirable choice for every day SeedSigner use.
|
||||
|
||||
<img src="/docs/img/Orange_Pill_Models.JPG" width="400" height="400">
|
||||
|
||||
### Characterisics:
|
||||
- Supported Camera? Legacy RPi Camera (w/ gold Pi Zero Cable)
|
||||
- Supported HAT? Waveshare 240x240 pixel LCD display + controls
|
||||
- Recommended printing process? FDM for enclosure, SLA for controls
|
||||
- Recommended printing materials? PLA for enclosure, resin for controls
|
||||
- Secondary Hardware Required? Yes
|
||||
- Data-enabled USB Port accessible? Yes
|
||||
- Mini-HDMI port accessible? Yes
|
||||
- Removeable Memory Card? Requires partial disassembly
|
||||
- Comfortable controls? Yes (but thumbstick can be clumsy)
|
||||
|
||||
### Secondary Hardware Required:
|
||||
- Four (4): 10mm M2.5 F-F spacers
|
||||
- Four (4): 6mm M2.5 screws
|
||||
- Four (4): 12mm M2.5 screws
|
||||
|
||||
### Assembly Demonstration:
|
||||
https://www.youtube.com/watch?v=aIIc2DiZYcI
|
||||
@@ -0,0 +1,34 @@
|
||||
## The Rugged Pill Enclosure
|
||||
|
||||
<img src="/docs/img/Rugged_Pill_Thumb.jpg" width="600" height="400">
|
||||
|
||||
- The Rugged Pill is an enclosure designed for building a SeedSigner without the need for screws or spacers.
|
||||
- This enclosure requires use of the so called "zerocam", which allows for a more compact form factor.
|
||||
- The enclosure offers a very comfortable handling experience.
|
||||
- The included controls can be printed from PLA, but TPU is recommended.
|
||||
- Recommended shore hardness is 95A, but any TPU will do.
|
||||
- Separate files are available for single and multicolor printing.
|
||||
- Top and bottom part snap fit together.
|
||||
- SD-card removable
|
||||
- Data port is closed. (Use the separate file labeled 4_SeedHammer)
|
||||
|
||||
|
||||
### File overwiev
|
||||
|
||||
#### Single color:
|
||||
- RuggedPill_Top.stl[^1]
|
||||
- RuggedPill_Bottom.stl[^1]
|
||||
- RuggedPillBottom_4SeedHammer.stl[^1]
|
||||
|
||||
- RuggedPill_Buttons.stl[^2]
|
||||
- RuggedPill_Thumbstick.stl[^2]
|
||||
- Rugged_Pill_Trackball.stl[^2]
|
||||
|
||||
#### Multimaterial:
|
||||
- RuggedPill_Top_MMU.3mf
|
||||
- RuggedPill_Bottom_MMU.3mf
|
||||
|
||||
You only need one set of buttons and a Thumbstick or Trackball, print both since they use minmal material. Test which one you like best and use that.
|
||||
|
||||
[^1]: (Recommended Materials: PLA, PETG)
|
||||
[^2]: (Recommended Materials: TPU)
|
||||
@@ -0,0 +1,25 @@
|
||||
## The Simple Pill Enclosure
|
||||
|
||||
The "Simple Pill" is a community-contributed design by @blackcoffeebtc. The most significant innovation of this design was the adaptation of a DPAD-stype thumbstick topper for a SeedSigner enclosure, offering a much more comfortable and responsive control experience. The Simple Pill was also the first enclosure to allow for easy access to the device's memory card.
|
||||
|
||||
<img src="/docs/img/Simple_Pill_Models.JPG" width="400" height="400">
|
||||
|
||||
### Characterisics:
|
||||
- Supported Camera? Legacy RPi Camera (w/ gold Pi Zero Cable)
|
||||
- Supported HAT? Waveshare 240x240 pixel LCD display + controls
|
||||
- Recommended printing process? FDM for enclosure, SLA for controls
|
||||
- Recommended printing materials? PLA for enclosure, resin for controls
|
||||
- Secondary Hardware Required? Yes
|
||||
- Data-enabled USB Port accessible? Yes
|
||||
- Mini-HDMI port accessible? Yes
|
||||
- Removeable Memory Card? Yes
|
||||
- Comfortable controls? Yes
|
||||
|
||||
### Secondary Hardware Required:
|
||||
- Four (4): 10mm M2.5 F-F spacers
|
||||
- Four (4): 6mm M2.5 screws
|
||||
- Four (4): 12mm M2.5 screws
|
||||
|
||||
### Assembly Demonstration:
|
||||
(assembly is similar to that of the original Orange Pill)
|
||||
https://www.youtube.com/watch?v=aIIc2DiZYcI
|
||||
@@ -0,0 +1,72 @@
|
||||
# i18n notes
|
||||
#
|
||||
# Format is "Pattern filename space-separated-list-of-line-numbers-with-pattern-prefixes" as of 20 November 2022
|
||||
#
|
||||
# kdmukai/intial_multilanguage branch already has plenty of work
|
||||
# * copied kdmukai's branch
|
||||
# * merged dev in into his branch.
|
||||
# * following his lead to change text literals and f-string substitutions.
|
||||
# * NOTE: TODO: add TranslatorNotes once I understand when they are needed!!!
|
||||
#
|
||||
# Common coding patterns noted: (source code lines below are prefixed w/[LFDECP) to identify pattern)
|
||||
#
|
||||
# * L) Literal text strings.
|
||||
#
|
||||
# * F) F-strings with placeholders.
|
||||
#
|
||||
# * V) variables with values set to a previously translated constant, ie _(display_name)
|
||||
#
|
||||
# * D) Default variables in baseclasses like "Button Label": is it necessary? user should never see these, else complain?
|
||||
#
|
||||
# * E) Exception messages: is it really necessary? only if frequent, else let user complain?
|
||||
#
|
||||
# * P) Proper names, partner logos, Coordinators... is it really of any concern at all?
|
||||
#
|
||||
# * print() debug messages to the C)onsole or /dev/null do not need translations? Not even included here.
|
||||
#
|
||||
#
|
||||
# While reading the notes below:
|
||||
# Each file and line-number are preceded by the type of i18n change needed, if truly 'needed'
|
||||
# A preceding # indicates there is nothing left to do, it's already i18n-ized.
|
||||
# A preceding ? indicates that I should give this another look, or a deeper look.
|
||||
# A preceding [DEP] might indicate nothing to do... if we really don't want to i18n these patterns.
|
||||
#
|
||||
|
||||
|
||||
E seedsigner/controller.py E117 E161 E168
|
||||
|
||||
ED seedsigner/gui/components.py E285 E324 E457 E498 E591 D1096 D1311
|
||||
E seedsigner/gui/keyboard.py E204 E207 E485 E587
|
||||
#L seedsigner/gui/renderer.py #L144
|
||||
|
||||
DE#LF seedsigner/gui/screens/screen.py D193 E524 #L756 #L771 #L885 #L888 #L900 #F1112
|
||||
#LF seedsigner/gui/screens/psbt_screens.py #L526 #L543? #L553 #L30 #L32 #L89 #L91 #L92 #L94 #F96 #F97 #F100 #L128 #L132 #L141 #L144 #L146 #F148 #L150 #L155 #L466 #L467 #L473 #L485 #L560 #F571 #FL667 #L677 #L689 #L703
|
||||
#L seedsigner/gui/screens/scan_screens.py #L22 #L138 #L139 #L140 #L156
|
||||
?#L seedsigner/gui/screens/settings_screens.py (_().replace() hmmm ?#L294) #L26 #L59 #L130 #L141 #L162 #L176 #L222 #L289
|
||||
#LF seedsigner/gui/screens/tools_screens.py #L41 #L72 #L99 #L119 #F150 #L161 #F167 #F177 #F189 #F193 #F200 #F241 #L274 #F311 #L352 #L354 #L369 #L385 #L393 #F402 #F410 #F418
|
||||
#L seedsigner/gui/screens/main_menu_screens.py #L12 #L24 #L29 #L39 #L44
|
||||
?#L seedsigner/gui/screens/seed_screens.py (why colon ?#L1033) #L411 #L424 #L555 #L561 #L571 #L587 #L593 #L597 #L606 #L616 #L625 #L638 #L1026 #L1121 #L1123 #L1131 #L1133 #L1147 #L1149 #L1226 #L1362 #L1419 #L1483 #L1500 #L1505 #L1518 #L1524 #L1532
|
||||
|
||||
E seedsigner/hardware/camera.py E36 E65
|
||||
E seedsigner/hardware/ST7789.py E154
|
||||
|
||||
E seedsigner/helpers/embit_utils.py E25 E35 E43 E45 E47 E91 E95
|
||||
E seedsigner/helpers/mnemonic_generation.py E22
|
||||
? seedsigner/helpers/ur2/DID-NOT-LOOK
|
||||
|
||||
E#LF seedsigner/views/psbt_views.py E30 #L36 #L37 #L38 #L55 #L94 #L166 #L167 #L168 #L185 #L186 #L187 #L253 #259 #L262 #L331 #L335 #L336 #L338 #L339 #L358 #L360 #L441 #F443 #L445 #FL447 #L451 #L453 #L478 #L530 #L532 #L533 #L534
|
||||
#L seedsigner/views/screensaver.py #L74
|
||||
E#LF seedsigner/views/seed_views.py (Why this one ?#E1464) #L1637 #L54 #L57 #L78 #L79 #L80 #L81 #L90 #F127 #L187 #L188 #L192 #L194 #L229 #L230 #L260 #L300 #L301 #L342 #L343 #L348 #F350 #L384 #L385 #L386 #L387 #L388 #L389 #L390 #L420 #L476 #L477 #L510 #L511 #L515 #L554 #L556 #L641 #L683 #L684 #L693 #L830 #L855 #L856 #F836 #L902 #L903 #F952 #L992 #L993 #L997 #L999 #F1000 #L1018 #L1020 #L1021 #L1022 #L1044 #L1045 #L1049 #L1050 #L1071 #L1120 #L1121 #L1213 #L1214 #L1218 #L1248 #L1257 #L1258 #L1259 #L1221 #L1268 #L1269 #L1270 #L1272 #L1280 #L1281 #L1282 #L1284 #L1353 #L1354 #L1391 #L1392 #L1393 #L1396 #L1406 #L1413 #L1510 #L1511 #F1639 #L1642 #L1652 #L1653 #L1682 #L1683 #L1684 #L1685
|
||||
#V seedsigner/views/settings_views.py #V26 #L20 #L21 #L36 #L39 #L46 #L54
|
||||
E#LF seedsigner/views/tools_views.py E605 E616 #L29 #L30 #L31 #L32 #L35 #L112 #L113 #L117 #L184 #L185 #L189 #L238 #L239 #L243 #L275 #L276 #L277 #L376 #L379 #L401 #L402 #L430 #L431 #L432 #L433 #L451 #L538 #L539 #L589 #F628 #FL631
|
||||
E#L seedsigner/views/view.py E66 #L124 #L125 #L126 #L127 #L142 #L145
|
||||
|
||||
E seedsigner/models/encode_qr.py E46 E104 E143 E146 E150 E153 E273 E356
|
||||
E seedsigner/models/psbt_parser.py E96 E226 E229 E232 E241 E245 E255 E269
|
||||
E seedsigner/models/seed.py E26 E42
|
||||
E seedsigner/models/seed_storage.py E68
|
||||
P#L seedsigner/models/settings_definition.py P37 P38 P39 P40 #V288 #L14 #L15 #L18 #L19 #L20 #L23 #L26 #L29 #L74 #L55 #L76 #L77 #L96 #L97 #L98 #L106 #L107 #L108 #L124 #L125 #L134 #L135 #L136 #L137 #L357 #L365 #L373 #L374 #L379 #L386 #L395 #L403 #L411 #L417 #L425 #L433 #L439 #L447 #L455 #L461 #L467 #L473
|
||||
E seedsigner/models/settings.py E112 E134 E150 E153 E162 E165
|
||||
E seedsigner/models/singleton.py E6 E24 E31
|
||||
E seedsigner/models/threads.py E23
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
picamera==1.13
|
||||
RPi.GPIO==0.7.0
|
||||
spidev==3.5
|
||||
@@ -1,12 +1,8 @@
|
||||
Babel==2.10.1
|
||||
embit==0.6.1
|
||||
numpy==1.21.1
|
||||
picamera==1.13
|
||||
Pillow==9.1.0
|
||||
pytz==2022.1
|
||||
-e git+https://github.com/seedsigner/pyzbar.git@c3c237821c6a20b17953efe59b90df0b514a1c03#egg=pyzbar
|
||||
embit==0.7.0
|
||||
numpy==1.25.2
|
||||
Pillow==9.4.0
|
||||
pyzbar @ git+https://github.com/seedsigner/pyzbar.git@c3c237821c6a20b17953efe59b90df0b514a1c03
|
||||
qrcode==7.3.1
|
||||
RPi.GPIO==0.7.0
|
||||
six==1.16.0
|
||||
spidev==3.5
|
||||
urtypes @ git+https://github.com/jreesun/urtypes.git@e0d0db277ec2339650343eaf7b220fffb9233241
|
||||
urtypes @ git+https://github.com/selfcustody/urtypes.git@7fb280eab3b3563dfc57d2733b0bf5cbc0a96a6a
|
||||
|
||||
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
||||
|
||||
setuptools.setup(
|
||||
name="seedsigner",
|
||||
version="0.5.0",
|
||||
version="0.7.0",
|
||||
author="SeedSigner",
|
||||
author_email="author@example.com",
|
||||
description="Build an offline, airgapped Bitcoin signing device for less than $50!",
|
||||
@@ -23,4 +23,4 @@ setuptools.setup(
|
||||
package_dir={"": "src"},
|
||||
packages=setuptools.find_packages(where="src"),
|
||||
python_requires=">=3.6",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
import time
|
||||
import logging
|
||||
|
||||
import traceback
|
||||
import gettext
|
||||
import os
|
||||
|
||||
from embit.descriptor import Descriptor
|
||||
from embit.psbt import PSBT
|
||||
from PIL.Image import Image
|
||||
from typing import List
|
||||
|
||||
from seedsigner.gui.renderer import Renderer
|
||||
from seedsigner.hardware.buttons import HardwareButtons
|
||||
from seedsigner.views.screensaver import ScreensaverScreen
|
||||
from seedsigner.views.view import Destination, NotYetImplementedView, UnhandledExceptionView
|
||||
|
||||
from .models import Seed, SeedStorage, Settings, Singleton, PSBTParser
|
||||
from seedsigner.models.settings import Settings
|
||||
from seedsigner.models.singleton import Singleton
|
||||
from seedsigner.models.threads import BaseThread
|
||||
from seedsigner.views.view import Destination
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
class BackStack(List[Destination]):
|
||||
class BackStack(list[Destination]):
|
||||
def __repr__(self):
|
||||
if len(self) == 0:
|
||||
return "[]"
|
||||
@@ -31,6 +29,54 @@ class BackStack(List[Destination]):
|
||||
|
||||
|
||||
|
||||
class StopFlowBasedTest(Exception):
|
||||
"""
|
||||
This is a special exception that is only raised by the test suite to stop the
|
||||
Controller's main loop. It should not be raised by any other code.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class FlowBasedTestException(Exception):
|
||||
"""
|
||||
This is a special exception that is only raised by the test suite.
|
||||
It should not be raised by any other code.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class BackgroundImportThread(BaseThread):
|
||||
def run(self):
|
||||
from importlib import import_module
|
||||
|
||||
# import seedsigner.hardware.buttons # slowly imports GPIO along the way
|
||||
|
||||
def time_import(module_name):
|
||||
last = time.time()
|
||||
import_module(module_name)
|
||||
# print(time.time() - last, module_name)
|
||||
|
||||
time_import('embit')
|
||||
time_import('seedsigner.helpers.embit_utils')
|
||||
|
||||
# Do costly initializations
|
||||
time_import('seedsigner.models.seed_storage')
|
||||
from seedsigner.models.seed_storage import SeedStorage
|
||||
Controller.get_instance()._storage = SeedStorage()
|
||||
|
||||
# Get MainMenuView ready to respond quickly
|
||||
time_import('seedsigner.views.scan_views')
|
||||
|
||||
time_import('seedsigner.views.seed_views')
|
||||
|
||||
time_import('seedsigner.views.tools_views')
|
||||
|
||||
time_import('seedsigner.views.settings_views')
|
||||
|
||||
|
||||
|
||||
class Controller(Singleton):
|
||||
"""
|
||||
The Controller is a globally available singleton that maintains SeedSigner state.
|
||||
@@ -49,29 +95,29 @@ class Controller(Singleton):
|
||||
rather than at the top in order avoid circular imports.
|
||||
"""
|
||||
|
||||
VERSION = "0.5.1"
|
||||
VERSION = "0.7.0"
|
||||
|
||||
# Declare class member vars with type hints to enable richer IDE support throughout
|
||||
# the code.
|
||||
buttons: HardwareButtons = None
|
||||
storage: SeedStorage = None
|
||||
_storage: 'SeedStorage' = None # TODO: Rename "storage" to something more indicative of its temp, in-memory state
|
||||
settings: Settings = None
|
||||
renderer: Renderer = None
|
||||
|
||||
# TODO: Refactor these flow-related attrs that survive across multiple Screens.
|
||||
# TODO: Should all in-memory flow-related attrs get wiped on MainMenuView?
|
||||
psbt: PSBT = None
|
||||
psbt_seed: Seed = None
|
||||
psbt_parser: PSBTParser = None
|
||||
psbt: 'embit.psbt.PSBT' = None
|
||||
psbt_seed: 'Seed' = None
|
||||
psbt_parser: 'PSBTParser' = None
|
||||
|
||||
unverified_address = None
|
||||
|
||||
multisig_wallet_descriptor: Descriptor = None
|
||||
multisig_wallet_descriptor: 'embit.descriptor.Descriptor' = None
|
||||
|
||||
image_entropy_preview_frames: List[Image] = None
|
||||
image_entropy_preview_frames: list[Image] = None
|
||||
image_entropy_final_image: Image = None
|
||||
|
||||
address_explorer_data: dict = None
|
||||
|
||||
sign_message_data: dict = None
|
||||
# TODO: end refactor section
|
||||
|
||||
# Destination placeholder for when we need to jump out to a side flow but intend to
|
||||
@@ -81,10 +127,12 @@ class Controller(Singleton):
|
||||
FLOW__VERIFY_MULTISIG_ADDR = "multisig_addr"
|
||||
FLOW__VERIFY_SINGLESIG_ADDR = "singlesig_addr"
|
||||
FLOW__ADDRESS_EXPLORER = "address_explorer"
|
||||
FLOW__SIGN_MESSAGE = "sign_message"
|
||||
resume_main_flow: str = None
|
||||
|
||||
back_stack: BackStack = None
|
||||
screensaver: ScreensaverScreen = None
|
||||
screensaver: 'ScreensaverScreen' = None
|
||||
toast_notification_thread: 'BaseToastOverlayManagerThread' = None
|
||||
|
||||
# Babel initialization
|
||||
gettext.install('messages', localedir='seedsigner/resources/babel')
|
||||
@@ -112,6 +160,9 @@ class Controller(Singleton):
|
||||
|
||||
each time you try to re-initialize a Controller.
|
||||
"""
|
||||
from seedsigner.gui.renderer import Renderer
|
||||
from seedsigner.hardware.microsd import MicroSD
|
||||
|
||||
# Must be called before the first get_instance() call
|
||||
if cls._instance:
|
||||
raise Exception("Instance already configured")
|
||||
@@ -120,16 +171,11 @@ class Controller(Singleton):
|
||||
controller = cls.__new__(cls)
|
||||
cls._instance = controller
|
||||
|
||||
# Input Buttons
|
||||
if disable_hardware:
|
||||
controller.buttons = None
|
||||
else:
|
||||
controller.buttons = HardwareButtons.get_instance()
|
||||
|
||||
# models
|
||||
# TODO: Rename "storage" to something more indicative of its temp, in-memory state
|
||||
controller.storage = SeedStorage()
|
||||
controller.settings = Settings.get_instance()
|
||||
|
||||
controller.microsd = MicroSD.get_instance()
|
||||
controller.microsd.start_detection()
|
||||
|
||||
# Store one working psbt in memory
|
||||
controller.psbt = None
|
||||
@@ -138,13 +184,14 @@ class Controller(Singleton):
|
||||
# Configure the Renderer
|
||||
Renderer.configure_instance()
|
||||
|
||||
controller.screensaver = ScreensaverScreen(controller.buttons)
|
||||
|
||||
controller.back_stack = BackStack()
|
||||
|
||||
# Other behavior constants
|
||||
controller.screensaver_activation_ms = 120 * 1000
|
||||
controller.screensaver_activation_ms = 2 * 60 * 1000 # two minutes
|
||||
|
||||
background_import_thread = BackgroundImportThread()
|
||||
background_import_thread.start()
|
||||
|
||||
return cls._instance
|
||||
|
||||
|
||||
@@ -152,9 +199,18 @@ class Controller(Singleton):
|
||||
def camera(self):
|
||||
from .hardware.camera import Camera
|
||||
return Camera.get_instance()
|
||||
|
||||
|
||||
@property
|
||||
def storage(self):
|
||||
while not self._storage:
|
||||
# Wait for the BackgroundImportThread to finish initializing the storage.
|
||||
# This is a rare timing issue that likely only occurs in the test suite.
|
||||
time.sleep(0.001)
|
||||
return self._storage
|
||||
|
||||
|
||||
def get_seed(self, seed_num: int) -> Seed:
|
||||
def get_seed(self, seed_num: int) -> 'Seed':
|
||||
if seed_num < len(self.storage.seeds):
|
||||
return self.storage.seeds[seed_num]
|
||||
else:
|
||||
@@ -169,7 +225,6 @@ class Controller(Singleton):
|
||||
|
||||
|
||||
def pop_prev_from_back_stack(self):
|
||||
from .views import Destination
|
||||
if len(self.back_stack) > 0:
|
||||
# Pop the top View (which is the current View_cls)
|
||||
self.back_stack.pop()
|
||||
@@ -184,13 +239,18 @@ class Controller(Singleton):
|
||||
self.back_stack = BackStack()
|
||||
|
||||
|
||||
def start(self) -> None:
|
||||
from .views import BackStackView
|
||||
from .views.main_menu_views import MainMenuView
|
||||
from .views.screensaver import OpeningSplashScreen
|
||||
def start(self, initial_destination: Destination = None) -> None:
|
||||
"""
|
||||
The main loop of the application.
|
||||
|
||||
opening_splash = OpeningSplashScreen()
|
||||
opening_splash.start()
|
||||
* initial_destination: The first View to run. If None, the MainMenuView is
|
||||
used. Only used by the test suite.
|
||||
"""
|
||||
from seedsigner.views import MainMenuView, BackStackView
|
||||
from seedsigner.views.screensaver import OpeningSplashScreen
|
||||
from seedsigner.gui.toast import RemoveSDCardToastManagerThread
|
||||
|
||||
OpeningSplashScreen().start()
|
||||
|
||||
""" Class references can be stored as variables in python!
|
||||
|
||||
@@ -218,7 +278,14 @@ class Controller(Singleton):
|
||||
View_cls(**init_args).run()
|
||||
"""
|
||||
try:
|
||||
next_destination = Destination(MainMenuView)
|
||||
if initial_destination:
|
||||
next_destination = initial_destination
|
||||
else:
|
||||
next_destination = Destination(MainMenuView)
|
||||
|
||||
# Set up our one-time toast notification tip to remove the SD card
|
||||
self.activate_toast(RemoveSDCardToastManagerThread())
|
||||
|
||||
while True:
|
||||
# Destination(None) is a special case; render the Home screen
|
||||
if next_destination.View_cls is None:
|
||||
@@ -228,23 +295,41 @@ class Controller(Singleton):
|
||||
# Home always wipes the back_stack
|
||||
self.clear_back_stack()
|
||||
|
||||
# Clear other temp vars
|
||||
# Home always wipes the back_stack/state of temp vars
|
||||
self.resume_main_flow = None
|
||||
self.multisig_wallet_descriptor = None
|
||||
self.unverified_address = None
|
||||
self.address_explorer_data = None
|
||||
|
||||
self.psbt = None
|
||||
self.psbt_parser = None
|
||||
self.psbt_seed = None
|
||||
|
||||
print(f"back_stack: {self.back_stack}")
|
||||
|
||||
try:
|
||||
# Instantiate the View class and run it
|
||||
print(f"Executing {next_destination}")
|
||||
next_destination = next_destination.run()
|
||||
|
||||
except StopFlowBasedTest:
|
||||
# This is a special exception that is only raised by the test suite
|
||||
# to stop the Controller loop and exit the test.
|
||||
return
|
||||
|
||||
except FlowBasedTestException as e:
|
||||
# This is a special exception that is only raised by the test suite.
|
||||
# Re-raise so the test suite can handle it.
|
||||
raise e
|
||||
|
||||
except Exception as e:
|
||||
# Display user-friendly error screen w/debugging info
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
next_destination = self.handle_exception(e)
|
||||
|
||||
if not next_destination:
|
||||
# Should only happen during dev when you hit an unimplemented option
|
||||
from seedsigner.views.view import NotYetImplementedView
|
||||
next_destination = Destination(NotYetImplementedView)
|
||||
|
||||
if next_destination.skip_current_view:
|
||||
@@ -277,16 +362,61 @@ class Controller(Singleton):
|
||||
print("-" * 30)
|
||||
|
||||
finally:
|
||||
if self.screensaver.is_running:
|
||||
from seedsigner.gui.renderer import Renderer
|
||||
if self.is_screensaver_running:
|
||||
self.screensaver.stop()
|
||||
|
||||
if self.toast_notification_thread and self.toast_notification_thread.is_alive():
|
||||
self.toast_notification_thread.stop()
|
||||
|
||||
# Clear the screen when exiting
|
||||
print("Clearing screen, exiting")
|
||||
Renderer.get_instance().display_blank_screen()
|
||||
|
||||
|
||||
@property
|
||||
def is_screensaver_running(self):
|
||||
return self.screensaver is not None and self.screensaver.is_running
|
||||
|
||||
|
||||
def start_screensaver(self):
|
||||
# If a toast is running, tell it to give up the Renderer.lock; it will then
|
||||
# block until the screensaver is done, at which point the toast can re-acquire
|
||||
# the Renderer.lock and resume where it left off.
|
||||
if self.toast_notification_thread and self.toast_notification_thread.is_alive():
|
||||
print(f"Controller: settings toggle_render_lock for {self.toast_notification_thread.__class__.__name__}")
|
||||
self.toast_notification_thread.toggle_renderer_lock()
|
||||
|
||||
print("Controller: Starting screensaver")
|
||||
if not self.screensaver:
|
||||
# Do a lazy/late import and instantiation to reduce Controller initial startup time
|
||||
from seedsigner.views.screensaver import ScreensaverScreen
|
||||
from seedsigner.hardware.buttons import HardwareButtons
|
||||
self.screensaver = ScreensaverScreen(HardwareButtons.get_instance())
|
||||
|
||||
# Start the screensaver, but it will block until it can acquire the Renderer.lock.
|
||||
self.screensaver.start()
|
||||
print("Controller: Screensaver started")
|
||||
|
||||
|
||||
def activate_toast(self, toast_manager_thread: 'BaseToastOverlayManagerThread'):
|
||||
"""
|
||||
Ensures that the Controller has explicit control over which processes get to
|
||||
claim the Renderer.lock and which need to (potentially) release it.
|
||||
"""
|
||||
if self.is_screensaver_running:
|
||||
# New toast notifications break out of the Screensaver
|
||||
print("Controller: stopping screensaver")
|
||||
self.screensaver.stop()
|
||||
|
||||
if self.toast_notification_thread and self.toast_notification_thread.is_alive():
|
||||
# Can only run one toast at a time
|
||||
print(f"Controller: stopping {self.toast_notification_thread.__class__.__name__}")
|
||||
self.toast_notification_thread.stop()
|
||||
|
||||
self.toast_notification_thread = toast_manager_thread
|
||||
print(f"Controller: starting {self.toast_notification_thread.__class__.__name__}")
|
||||
self.toast_notification_thread.start()
|
||||
|
||||
|
||||
def handle_exception(self, e) -> Destination:
|
||||
@@ -299,6 +429,7 @@ class Controller(Singleton):
|
||||
* python file, line num, method name
|
||||
* Exception message
|
||||
"""
|
||||
from seedsigner.views.view import UnhandledExceptionView
|
||||
logger.exception(e)
|
||||
|
||||
# The final exception output line is:
|
||||
@@ -306,7 +437,12 @@ class Controller(Singleton):
|
||||
# So we extract the Exception type and trim off any "foo.bar." namespacing:
|
||||
last_line = traceback.format_exc().splitlines()[-1]
|
||||
exception_type = last_line.split(":")[0].split(".")[-1]
|
||||
exception_msg = last_line.split(":")[1]
|
||||
|
||||
# Extract the error message, if there is one
|
||||
if ":" in last_line:
|
||||
exception_msg = last_line.split(":")[1]
|
||||
else:
|
||||
exception_msg = ""
|
||||
|
||||
# Scan for the last debugging line that includes a line number reference
|
||||
line_info = None
|
||||
|
||||