I made this as a continuation of my current work with the NEO2 but there is no reason why this could not be adapted to other boards. There are also many ways to achieve the same thing i.e. colourful terminal login – this is merely a what I chose to do.
So I like colourful terminals when working with little boards like the Raspberry Pi , NEO and many others. I’ve long since gone off using the graphical interfaces (unless I’m making a media centre) – and play with the boards mainly from my Windows PC using WinSCP which gives me graphical access to the file structure and the ability to use Microsoft Studio Code (I used to use Notepad++ but that was, it seems, a lifetime ago).
So really the boring part of this is the terminal. In a previous article I showed you how I introduced a nice colourful prompt – and I also covered installing various libraries for Python – a language which as you will no doubt see when you read my code, I had studiously avoided until last week (and now I’m even pondering installing on an ESP8266)
So up to now, my little NEO2 board runs off a hard disk, using RSYNC I can back up to the remainder of the SD that I boot off (and it is as well that this works as I’ve messed up a few times and wiped the hard drive in the process of learning)… the only thing is… the signup for the terminal, so lovely on Armbian and even some of the FriendlyArm ROMs was missing from the setup. All I got was a reminder who I was logging in as (like I would not know – and anyway, it’s in the prompt) and a reminder of a standard password I no longer use.
The first thing to change my terminal login was to get rid of that nonsense. It seems there are many ways to put up login messages – from MOTD (message of the day) through a myriad of other options. FriendlyArm chose to to put identical messages in both /etc/issue and /etc/issue.net which, it turns out, are simple text files.
I wiped both of them (just leaving empty files) and lo and behold when I pulled up a terminal all I got was the message to say who I was – this apparently comes courtesy of WinSCP and may not appear depending what tool you use to access the boards.
For me the solution was to create something that would firstly clear the screen then put up a USEFUL welcome message on logging in. I thought it might also be nice if I could ALSO call that – by some new name like “cls” to clear the screen and put up that same information.
As I had already used Python to put up messages on the little LCD display, it occurred to me that I should re-used this new new knowledge! I made (cobbled) a simply Python program that calls mainly a very nice library called platform which can get all sorts of info from the computer to display. I wanted to be able to call that program when a user, any user, logs in – a good place to put the link to the program turns out to be /etc/profile– a simply line at the end that says:
python /root/info.py
I also wanted an alias – a command of my own that would call this PY file manually. It turns out that /etc/bash.bashrc is a good place to put this – a simple line at the end that says:
alias cls=’python /root/info.py’
So now this Python program would be called whenever someone logs into an SSH terminal program – and could also be called by issuing the command “cls”.
Of course once you see the terminal login program in action and look up the libraries it may be you chose to have a completely different set of information up there and the colours – well, that is up to you – I only defined the ones I wanted. Some of the routines were adapted from open source FriendlyArm examples – they are all pretty straightforward – just remember if you make changes – Python is utterly anal about SPACING.. it uses no braces or end statements for function – just positioning – one false move…
And the terminal login program (which bears some resemblance to the more complex I2c program to run a little OLED in a previous blog) called info.py – which I chose to put in the folder “/root” for no good reason…
import time import os import psutil import platform from datetime import datetime def get_ip_address(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, # SIOCGIFADDR struct.pack('256s', ifname[:15]) )[20:24]) byteunits = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB') def filesizeformat(value): exponent = int(log(value, 1024)) return "%.1f %s" % (float(value) / pow(1024, exponent), byteunits[exponent]) def bytes2human(n): """ >>> bytes2human(10000) '9K' >>> bytes2human(100001221) '95M' """ symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y') prefix = {} for i, s in enumerate(symbols): prefix[s] = 1 << (i + 1) * 10 for s in reversed(symbols): if n >= prefix[s]: value = int(float(n) / prefix[s]) return '%s%s' % (value, s) return "%sB" % n def cpu_usage(): # load average, uptime av1, av2, av3 = os.getloadavg() return "%.1f %.1f %.1f" \ % (av1, av2, av3) def cpu_temperature(): tempC = ((int(open('/sys/class/thermal/thermal_zone0/temp').read()) / 1000)) return "%sc" \ % (str(tempC)) def mem_usage(): usage = psutil.virtual_memory() return "%s/%s" \ % (bytes2human(usage.available), bytes2human(usage.total)) def disk_usage(dir): usage = psutil.disk_usage(dir) return " %s/%s" \ % (bytes2human(usage.total-usage.used), bytes2human(usage.total)) def network(iface): stat = psutil.net_io_counters(pernic=True)[iface] return "%s: Tx%s, Rx%s" % \ (iface, bytes2human(stat.bytes_sent), bytes2human(stat.bytes_recv)) def lan_ip(): f = os.popen('ifconfig eth0 | grep "inet\ addr" | cut -c 21-33') ip = str(f.read()) # strip out trailing chars for cleaner output return "%s" % ip.rstrip('\r\n').rstrip(' ') bold = '\033[1m' normal = '\033[0m' red='\033[91m' green='\033[92m' blue='\033[94m' default = '\033[39m' uptime = datetime.now() - datetime.fromtimestamp(psutil.boot_time()) os.system('cls' if os.name == 'nt' else 'clear') print blue + "____________________________________________________________________________\n" + normal print " Platform: " + red + "%s %s" % (platform.system(),platform.release()) + normal + "\t" + green + str(datetime.now().strftime('%a %b %d at %H:%M:%S')) + normal print " CPU Usage: " + red + cpu_usage() + normal + "\t\tCPU Temperature: " + red + cpu_temperature() + normal print " Memory Free: " + red + mem_usage() + normal + "\t\tDisk Free: " + red + disk_usage('/') + normal print " IP Address: " + red + lan_ip() + normal + "\tUptime: " + red + "%s" % str(uptime).split('.')[0] + normal bum=psutil.cpu_freq(0) print " Current CPU speed: " + red + "%d" % int(bum.current) + "Mhz" + normal + "\tmin: " + red + "%d" % int(bum.min) + "Mhz" + normal + " max: " + red + "%d" % int(bum.max) + "Mhz" + normal print blue + "____________________________________________________________________________\n" + normal
Pete – have you tried MobaXterm for Windows? I’ve been using the free Personal Edition when I need to ssh into a linux machine from Windows.
I have, Randy, then I forgot all about it. I find WinSCP does everything I need and is regularly updated – there is no free and commercial option – it is simply free. Thanks anyway.
Trying to adopt this to normal Debian computer and getting the following error.
File “info.py”, line 83, in
bum=psutil.cpu_freq(0)
AttributeError: ‘ModuleWrapper’ object has no attribute ‘cpu_freq’
In this instance I’m happy to let someone else step in with any solution – my knowledge of Python is on a par with my knowledge of Spanish.
Oh, hang on – I had a similar issue with another (what I probably incorrectly call a) method…. the version of psutils was too early… so – just check which version of the relevant library you have (don’t ask me how to do that).
And it gets worse as this evening I am playing with Python on an ESP8266 – and it uses Python 3 – which already is slightly different to Python 2.7 – we should all just go fishing until all these things stop mutating – which will probably be… never.
This has, for a long time, been a wonder of mine, but why does Python choose to run 2 separate version side by side?
it’s a backward compatibility thing. 3 is a ground up rewrite that breaks compatibility with 2 in many ways but is considered better for some things. However there’s so much stuff still based on 2 so 2 has to keep shipping. It’s the distro’s decision to ship both 2 and 3 because python is all user land stuff and any given distro could choose not to ship 2 or 3 but then a whole bunch of given stuff wouldn’t work at all. It’s a bit of a mess but probably no worse than other runtimes i.e. .net
Have same problem, psutil saying “…no attribute ‘cpu_freq'”.
So i checked:
Python 2.7.9 (default, Jun 29 2016, 13:08:31)
[GCC 4.9.2] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import psutil
psutil.__version__
‘5.2.2’
A look into documentation (https://pythonhosted.org/psutil/index.html#psutil.cpu_freq)
shows:
Availability: Linux, OSX, Windows
New in version 5.1.0.
But indeed:
>>> psutil.__all__
shows all implemented functions – and there is no “cpu_freq” !!
I had to update for the latest 5.1.0 to get all the facilities..
I’m just checking… I’m getting valid results on both boards… and it is definitely coming from here..
Here is the output right now.
Current CPU speed: 624Mhz min: 120Mhz max: 1008Mhz
____________________________________________________________________________
I ran the version number and get 2.1.1. Weird.
python
Python 2.7.9 (default, Jun 29 2016, 13:08:31)
[GCC 4.9.2] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import psutil
>>> psutil.__version__
‘2.1.1’
I tried to re-install using the pip install psutl command and received this output
Requirement already satisfied: psutil in /usr/lib/python3/dist-packages
I noted the python3 in the output which makes me wonder if there is some conflict between python 2 & 3.
I got that – I removed psutil – and installed – and then that worked…. yes, first time I tried it, it said it was already “satisfied” – I wasn’t….
Don’t expect the experienced voice of Python from me… someone else might have a better way.
Tried it on a different machine with python 2.7 AND 3.6 …
and both worked…
Then on my Windows PC… it worked…
No idea whats wrong on the other machine 🙂
“He who never makes mistakes may throw the first exception.” 🙂
Kernighan & Ritchie’s first law.
No worries. Have been there many, many times. Regardless how much I watch out when copy & pasting code snippets, something always falls through the cracks.
Nice script, thx Pete!
Agree with Python being a structure nightmare. Shame, such a nice and powerful language. Every time I quickly have to edit a python script in nano, just to set a variable to a different value, for example, I really have to be careful not to touch any of the spaces. Would it really have killed them to use brackets like everyone else?
There is one copy & paste error, I think, CPU load and Temp:
Remove line 40
Remove line 45, 46
Remove the / 1000 in line 47 on SBCs which show normal Celsius results in the temp file, or you will never get any temp higher than 0.
John John
You are of course correct about those lines and I have updated the blog – I’ve left the /1000 in as mine is showing the temperatures you see in the examples… with your comment, anyone having difficulty will know what to do.
Python has it’s moments – but for example I’ve just loaded up MicroPython for the ESP8266 – you know – just to give it a go.
Well, it loaded fine – the web interface did NOT work at all as you would expect on a phone web page.. but thankfully the serial did… but the very first official example I tried – turning the blue light on and off on the ESP8266….
Well, the example was:
>>> import machine
>>> pin = machine.Pin(2, machine.Pin.OUT)
>>> pin.high()
>>> pin.low()
So firstly – high and low didn’t work – thankfully on their forums someone had come across this – it is on and off on the ESP8266 (but the example was in the ESP8266 section) and secondly they were the wrong way around – on turned the light off. I left there thinking DARE I try something more complex like I2c after this?
And of course having used the Python here where:
print “hello”
works – I was a bit miffed to realise the microPython needs:
print(“hello”)
It turns out that the ESP Python implements Python 3 which needs the ()
Still – as I made mistakes in this very blog entry I suppose I should keep my mouth shut 🙂
I do want one more item out of there – the actual operating system and version as against Linux (ie Ununtu xx.x) – I’ll add that in when I figure it out.
don’t put script in /root folder, better in your own user one… so you can backup them more easily, and access them from your user, too… and for OS info, you should have all you need in lsb_release -a or other of its switches
You are of course assuming I’m using a “user” – right now I’m committing the horrible crime of using the units as root. I know, I will burn in hell…
I know 😛
There’s a Hell’s Circle for you, where no gui is allowed, nor root login, and user and passwords are 100 random chars long and no shell autocomplete is available, nor man pages are installed ?
And no Google!
“Would it really have killed them to use brackets like everyone else?”
This is the reason:
https://arstechnica.com/civis/viewtopic.php?f=15&t=1008590
Have you ever read compiled Javascript?