Terminal Login

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.

promptSo 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.

Terminal Login

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 – once 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


Facebooktwittergoogle_pluspinterestlinkedin

18 thoughts on “Terminal Login

  1. 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.

    1. 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.

      1. 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

          1. 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!

  2. "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.

  3. 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'

    1. 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.

        1. 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

      1. 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" !!

        1. 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
          ____________________________________________________________________________

        2. 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.

          1. 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.

  4. 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.

    1. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *