Display panels and scripts to get the most from your Bitcoin node
From the scripts folder, select the ipaddresses.py file to open in an editor.
Start running the script by the shortcut (F5) or choosing Start Debugging from the Run menu.
If there are no errors, you will see some startup text in the terminal pane, followed by sleeping for 120 seconds
.
You can stop debugging via the shortcut (SHIFT+F5) or from the Run menu.
Activate the python virtual environment if it isn’t already active. You can rely on the prompt prefixed with the environment name (nodeyez) to know its active or not.
source ~/.pyenv/nodeyez/bin/activate
From the terminal, you won’t having debugging support, and instead just run the script directly
cd ~/nodeyez/scripts
python ./ipaddresses.py
Press (CTRL+C) to stop the script execution.
Look for an image generated in the ../imageoutput folder.
In the footer of most images generated by Nodeyez is an “as of” datestamp. This can help you be certain whether you are reviewing the latest changes.
Nodeyez panels have been refactored to inherit from and extend an underlying class that provides helpful functions. The general organizational structure of the source files as read from top to bottom are desribed below
def __init__(self):
This function defines expected configuration parameter names, including any mappings of prior names for backwards compatibility. Defaults are then assigned before initialization is called from the inherited class. If there is any further logic that needs to occur once during setup, it follows the init.
The IP addresses doesnt define any new attributes, but does provide mappings from configuration field names previously used. For newly created panels, you won’t need to provide legacy mappings.
# Define which additional attributes we have
self.configAttributes = {
# legacy key name mappings
"colorBackground": "backgroundColor",
"colorTextFG": "textColor",
"sleepInterval": "interval",
}
You will however need to specify any custom field names that the panel expects. These should be included in the configAttributes dictionary, and both the key and value should be the new field name. For example, the arthash panel includes a field named shapeOutlineColor in addition to legacy key name mappings.
self.configAttributes = {
# legacy key name mappings
"colorBackground": "backgroundColor",
"colorShapeOutline": "shapeOutlineColor",
"colorTextFG": "textColor",
"sleepInterval": "interval",
# panel specific key names
"shapeOutlineColor": "shapeOutlineColor",
}
Defaults are specified after that. These are values that can override the base panel fields. For example, the IP Addresses panel sets the headerText
to IP Addresses
. If this isn’t done for a panel, the header text would be the same name as the panel, in this case ipaddresses
. The time between panel runs is overridden in the interval
configuration field, setting it to 120
(seconds, so 2 minutes). By default, panels have an interval of 10 minutes.
# Define our defaults (all panel specific key names should be listed)
self._defaultattr("headerText", "IP Addresses")
self._defaultattr("interval", 120)
Anything not overridden from the parent class keeps its default values.
field name | default value |
---|---|
backgroundColor | #000000 |
blockclockAddress | 21.21.21.21 |
blockclockEnabled | False |
blockclockPassword | emptystring/notset |
dataDirectory | ../data/ |
enabled | True |
footerEnabled | True |
headerColor | #ffffff |
headerEnabled | True |
headerText | the name it was initialized as |
height | 320 |
interval | 600 |
pagingEnabled | True |
pageNumber | None |
pageCount | None |
textColor | #ffffff |
watermarkEnabled | True |
watermarkAnchor | bottomleft |
width | 480 |
Next, the panel calls the parent class to initialize. An argument is provided to specify the name of the panel. If the headerText is not overridden, the name will be assigned as the headerText. The name is used for logging purposes, and for identifying the configuration file that can be read from to override the hard coded values in the panel code.
# Initialize
super().__init__(name="ipaddresses")
def fetchData(self):
If this function is overridden from the parent class, it represents logic that should occur each time the panel is generated, and should encapsulate that for retrieving any updated data and updating state.
For the IP Addresses panel, the logic makes this call. It’s calling a function of an imported package to retrieve all the ip addresses in use and assign to a property on the running instance for reference later in the run function.
self.netaddresses = psutil.net_if_addrs()
Panel specific helper functions can be added throughout the class. In many cases these are prepared before they are called by functions like fetchData
and run
In the case of the IP Addresses panel, its fairly simple and doesnt encapsulate data in additional class functions.
def run(self):
This function will be run each time the panel is generated, and after a call to fetchData. The bulk of logic for creating images occurs here.
Looking at the IP Addresses panel, it begins by setting up an image
super().startImage()
This call to the parent panel class does some common logic to prepare a canvas to draw on based on the configured height and width. This will typically be used in all panels. Once it is called however, the panel is also responsible for cleaning up and releasing resources. This can be done with finishImage() as noted below.
Next, a block of code examines all the network addresses attained during the fetch operation, and excludes those that are local loopbacks, not broadcast type, or not IPv4 address types to build up a variable of line delimited addresses.
ipaddresslist = ""
for netdevicekey in self.netaddresses.keys():
if netdevicekey == "lo": # loopback
continue
netdevice = self.netaddresses[netdevicekey]
for netaddress in netdevice:
family, ipaddress, _, broadcast, _ = netaddress
if broadcast == None:
continue
if int(family) != 2: # Restrict to AF_INET (IPv4) address types
continue
ipaddresslist = ipaddresslist + "\n" if len(ipaddresslist) > 0 else ipaddresslist
ipaddresslist = f"{ipaddresslist}{ipaddress}"
After this its time to take the prepared list of ip addresses and output it to the image canvas
maxFontSize = int(self.height * 32/320)
minFontSize = 12
fs, _, _ = vicarioustext.getmaxfontsize(self.draw, ipaddresslist, self.width, self.getInsetHeight(), True, maxFontSize, minFontSize)
if fs < minFontSize:
vicarioustext.drawtoplefttext(self.draw, ipaddresslist, minFontSize, 0, self.getInsetTop(), ImageColor.getrgb(self.textColor), True)
else:
vicarioustext.drawcenteredtext(self.draw, ipaddresslist, fs, self.width // 2, self.getInsetTop() + (self.getInsetHeight() // 2), ImageColor.getrgb(self.textColor), True)
The first three lines are setting up to try to find the largest size that the IP Address list can be written to the image, without running off the side of the image.
Helper functions from the vicarioustext package are used for writing out the text, either centered if it fits, or fully left aligned if for some reason it does not.
Finally, we finish the image using the helper function. This actually adds the header and footer to the image if enabled, along with a watermark and paging information. It also saves the canvas in memory to an image file so it can be viewed elsewhere. And then it closes the canvas object to free up memory.
super().finishImage()
Most panels will have a block of code at the bottom of the file to run the panel continuously. Here’s an example from the IP Addresses panel
if __name__ == '__main__':
p = IPAddressesPanel()
# If arguments were passed in, treat as a single run
if len(sys.argv) > 1:
if sys.argv[1] in ['-h','--help']:
print(f"Prepares an image with all the IP addresses used by this host")
print(f"Usage:")
print(f"1) Call without arguments to run continuously using the configuration or defaults")
print(f"2) Call with an argument other then -h or --help to run once and exit")
else:
p.fetchData()
p.run()
exit(0)
# Continuous run
p.runContinuous()
Create a temporary branch to test your changes.
Using the Terminal
git checkout -b test1
If this is your first time setting up git, you’ll also want to set your user email and name
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
Verify that the current branch name is depicted in the lower left corner of Visual Studio Code
Try making a change to the IP Addresses script. Within the run
function, change the maximum font size to 128.
maxFontSize = 128 # int(self.height * 32/320)
Save the file, and start running the script via the shortcut (F5) or from choosing Start Debugging from the Run menu.
Stop the script and review the output generated in the imageoutput folder as before. You should see the as of footer line changed to a more recent time, as well as visual changes to the font size based on your alterations.
Once you are satisfied with any changes you’ve made, you can publish them to a branch in your own repository, and then begin a pull request.
Before going much further, lets commit your changes to your local branch.
In Visual Studio Code, switch to the Source Control view (CTRL+SHIFT+G G). If the Source Control subpanel is not displayed, toggle it by clicking the three dots in the upper right corner of the Source Control pane and choosing that menu option. Expand the Source Control subpanel and you’ll see the list of files you’ve added, modified, or deleted.
At the top of the Source Control panel you can provide a comment for your changes, and click Commit.
View the status, reporting branch, working vs staged changes
cd ~/nodeyez
git status
Stage them for committing
git add .
The ‘.’ stages all files from your current working directory downward
Commit with a message
git commit -m "Brief description of your changes"
Sign in to Github, creating a new account if you do not already have one. If you are creating a new account, you should also setup an SSH key from the computer you are working on.
Navigate to the project at https://github.com/vicariousdrama/nodeyez.
Towards the upper right corner, you can click on the Fork button. This will start a fork of the project under your username. Review the settings making adjustments based on your preferences and proceed with Create Fork.
With your new fork created in Github, click the green Code dropdown button, and then select SSH. Copy the value. It should look something like git@github.com:Username/nodeyez.git
View your remotes
git remote -v
Add a new remote
git remote add myfork git@github.com:Username/nodeyez.git
You can use this command to push your branch to your desired forked repository, replacing myfork
with whatever you named your remote and test1
with your branch name.
git push --set-upstream myfork test1
From within the GitHub interface, you can view your branch, and create a pull request. By default, Github will open a pull request against the base repository from which yours is forked, but you can change that as desired.
Home | Back to Python and IDE Setup | Continue to Create New Panel |