Sticky floating div – AngularJS

On a design responsibility matrix web application at work, we want to show users how many decisions are left to be made where they had selected a more generic Uniclass2015 classification earlier in their project. A nice solution to this is to have a “sticky” floating div at the bottom of the screen. I started implementation this from flat designs I was given, but then noticed an issue when the user scrolled to the bottom of the screen. At the bottom of the page is quite a strong grey footer, and it doesn’t look terrible aesthetically pleasing when the floating div enters it.

floating-div-1

Floating div showing remaining decisions

floating-div-2

Floating div over the footer

I had a couple of options for a solution – 1. dock the floating div at the top of the footer when it hits it; or 2. hide the floating div when it hits the footer (the solution I went with). The application I was working on uses AngularJS 1, for the solution I’d need to manipulate the DOM so would need to create an Angular Directive.

First, the easy stuff. The CSS for the solution:

div.fixed-footer {
   position: fixed;
   bottom: 0px;
   height: 40px;
   width: 236px;
   background: #401145;
   z-index: 900;
   color: #FFF;
   opacity: 1;
   transition: opacity .25s ease-in-out;
   -moz-transition: opacity .25s ease-in-out;
   -webkit-transition: opacity .25s ease-in-out
}

Not too much going on here, one thing to note is the transition. I’ll use a transition on opacity to ease the floating div in and out as the user scrolls down to the footer.

And the HTML:

< div sticky-footer-dir class="fixed-footer" ng-hide="decisionsRemaining === 0">
 < div class="decisions">{{decisionsRemaining}}</div>
</div>

Again, not too much going on. The floating div uses the above CSS style, and is going to use the sticky-footer-dir (the directive coming up soon). The other stuff is just logic to show how many decisions remain.

The directive I had to create was based on a few answers on Stack Oveflow. But I couldn’t find an exact solution for AngularJS so had to implement my own.

(function () {
  'use strict';

  angular
    .module('powEditor')
    .directive('stickyFooterDir', StickyFooterDir);

  StickyFooterDir.$inject = ['$window'];

  function StickyFooterDir($window) {
    var directive = {
      link: link,
      restrict: 'A'
    };
    return directive;

    function link(scope, element, attrs) {
      var height = element[0].clientHeight;

      // Watch for document height changes
      scope.$watch(function () {
        return angular.element(document).height();
      }, function (newVal, oldVal) {
        toggleClass();
      });

      var toggleClass = function () {
        var elemRect = element[0].getBoundingClientRect();
        var elm = element[0];
        var footer = document.getElementsByClassName('footer')[0];
        var elmTop = elemRect.top + $window.pageYOffset;

        if (elmTop + elm.offsetHeight >= footer.offsetTop - 405) {
          element.css('opacity', '0');
        }

        if ($window.pageYOffset + $window.innerHeight < footer.offsetTop) {
          element.css('opacity', '1');
        }
      };

      // bind to 'onscroll' event
      $window.onscroll = function () {
        toggleClass();
      };

      // also bind to 'resize'
      angular.element($window).bind('resize', toggleClass);
    }
  }
})();

The directive isn’t too complicated, there are a couple of things to draw attention to. The main logic is in toggleClass, which gets the location of the floating div relative to the footer. If the floating div is within the footer, its opacity is set to 0 (hidden); otherwise it’s set to 1.

floating-div-3

The solution – no floating div when the user has scrolled to the footer of the page

We need to watch for a few changes to the window and the document. Most obvious is that we need to watch the scroll event of the document – as we’ll hide the floating div when the user scrolls to the footer of the page. Slightly less obvious, is that we need to watch for window resize and document height changes. If the user resizes the window (or rotates their tablet) we don’t want the solution to break. Similarly, if the user hides a dynamic element on the page (which could cause the document height to change) we also don’t want the solution to break.

Finally some improvements that could be made – most notably the hard coding of footer id and footer size. This directive doesn’t have to be too reusable, but it would have been better using scope parameters to pass these options to the directive.

BBC micro:bit first look

I was very excited to received my BBC micro:bit in the post this morning. This little microcomputer is tiny, about the same width as a bank card but half it’s length.

IMG_0219

Tiny computer

The computer came with a tiny getting started leaflet, which explained that the BBC micro:bit is a pocket sized computer with motion detection, a built-in compass and Bluetooth technology. Having a closer look at the board, I could see there is are also 2 push buttons, an array of 25 LED’s and a number of GPIO pins – 5 large and 20 small. I looked on the micro:bit website to find out more about these pins. I was amazed to see that the micro:bit supports SPI and I2C.

The little guide then mentioned that computer comes pre-loaded with a couple of programs. Turning on the micro:bit, I was told to press button A, then button B:

There is a nice “chase the dot” game, where you must tilt the micro:bit to catch the flashing dot with a steady one. Then, after being told to “get coding” there is a nice LED animation.

IMG_0232

 

I’ve not yet looked at coding the micro:bit, but know it’s all done via online editors – either using JavaScript, the Scratch like “Block editing”, touch develop or Python. Programs are then transferred to the micro:bit – what i didn’t know is that because the micro:bit has Bluetooth, it’s possible to transfer programs to it via Bluetooth as well as via the USB port.

Now all I need to do is think of a cool program to write…

RFID scanner

Anyone who is interested in Raspberry Pi computing and electronics will eventually stumble upon Radio Frequency Identification (RFID) readers. They are featured in a number of “build your own access control system” hobby projects and, cards, keyfobs and readers can be picked up cheaply on eBay.

RFID tags are becoming more commonly used for applications outside of security and access control, such as tracking products down a production line, embedding chips in pets and livestock for identification and wireless debit/credit card payments.

In construction, it’s clear that RFID tags could play an important part in identifying and tracking products from manufacture to installation. These tags, along with barcodes and QR codes could help contractors, service engineers and facilities managers install, service and replace products over the lifetime of a building.

This blog post will look at how to read the UID of a MIFARE RFID tag with an RFID-RC552 reader that’s connected up to a Raspberry Pi (Zero).

What you need

  • An RFID-RC552 reader – I used this one form eBay. Some soldering skills will be required to solder the pins to the reader
  • A Mifare S50, S70, UltraLight, Pro or Desfire RFID tag
  • Female-to-Female jumper wires
  • A Raspberry Pi (a Zero is used in this tutorial with a 40-pin GPIO header) with Raspian.

Important note: I found that the RC552 only worked with 2016-03-18-raspbian-jessie or lower. This uses the spi_bcm2708 module instead of the newer spi_bcm2835. The reader wouldn’t read with the later bcm module.

1. Enable Serial Peripheral Interface (SPI) interface (Device Tree Overlays)

The RC552 rader will use the SPI interface on the Pi – the Pi will be the master and the reader the slave. But before we connect any wires, we need to enable the SPI interface. This can be done using the raspi-config or by editing /boot/config.txt.

Add the following lines to /boot/config.txt.

device_tree_param=spi=on
dtoverlay=spi-bcm2708

Then edit /etc/modprobe.d/raspi-blacklist.conf. Add a # (comment) on line “blacklist spi-bcm2708”

#blacklist spi-bcm2708

Reboot the Pi.

sudo shutdown -r now

2. Check SPI Interface software

We need to check that the SPI module dtoverlay has been loaded. Running the following commands should give you the following output:

$ dmesg | grep spi
[    5.408904] bcm2708_spi 20204000.spi: master is unqueued, this is deprecated
[    5.659213] bcm2708_spi 20204000.spi: SPI Controller at 0x20204000 (irq 80)

$ lsmod
spi_bcm2708             6010  0

If this doesn’t work, it’s likely you’re using a newer version of Raspian, with a newer version of the SPI module (see important note above).

3. Install Software for use RFID-RC522

Install python-dev

sudo apt-get install python-dev

Install SPI-Py (Hardware SPI as a C Extension for Python)

git clone https://github.com/lthiery/SPI-Py.git
cd SPI-Py
sudo python setup.py install

Install MFRC522-python

This repository has some good RFID tag read and write examples, as well as doing the word to talk to the reader using SPI-Py.

git clone https://github.com/mxgxw/MFRC522-python.git 
cd MFRC522-python

4. Wire up the Pins

Please note that these are the instructions for the 40-pin GPIO header NOT the 26-pin (Raspberry Pi 1). If you wire up the reader using the wrong instructions you can waste hours of your life diagnosing why…trust me 🙂

Name Pin # Pin name
SDA 24 GPIO8
SCK 23 GPIO11
MOSI 19 GPIO10
MISO 21 GPIO9
IRQ Not connected Not connected
GND Any Ground Any Ground
RST 22 GPIO25
3.3V 1 3V3

You can use this image for reference.

Note also that the reader is rated only for 3.3v, if you connect it to the 5v rail you could damage the integrated chip on the reader.

IMG_0213

RFID reader all connected up to the Pi Zero

5. Testing

Try to read an RFID tag using code from the MFRC522-python repository

$ sudo python Read.py

All being well, if you hold a card over the reader you will see the following output:

Welcome to the MFRC522 data read example
Press Ctrl-C to stop.
Card detected
Card read UID: XX,XX,XX,XX
Size: 8
Sector 8 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Ctrl+C for Stop.

Try to write to a card.

$ sudo python Write.py

If you hold a card over the reader you will see the following output:

Card detected
Card read UID: XX,XX,XX,XX
Size: 8

Sector 8 looked like this:
Sector 8 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Sector 8 will now be filled with 0xFF:
4 backdata &0x0F == 0x0A 10
Data written

It now looks like this:
Sector 8 [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]

Now we fill it with 0x00:
4 backdata &0x0F == 0x0A 10
Data written

It is now empty:
Sector 8 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

6. Part 2 – PySide and Qt

So the next step is to create a nice Python project with a friendly UI to help users scan a UID of an RFID card and do something useful with it.

If you’re planning on presenting a UI using Python, PySide is a good choice as it wraps up the complexity of Qt in an easy to use library.

Our GUI will look something like this:

rfid-app-1

Basic UI using PySide

To setup and show this UI using PySide, we need the following code:

import sys
import RPi.GPIO as GPIO
import MFRC522
import time

from PySide import QtGui
from PySide import QtCore
from threading import Thread
from Queue import Queue
from CpiLookup import LookupService
import ProductInfo

class MyWindow(QtGui.QWidget):
    lookup_service = LookupService()
    property_window = None

    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.setup_ui()
        self.resize(320, 240)
        self.setWindowTitle("CPI RFID Reader")
        self.setWindowFlags(QtCore.Qt.WindowTitleHint or QtCore.Qt.WindowSystemMenuHint or QtCore.Qt.WindowMinimizeButtonHint or QtCore.Qt.WindowCloseButtonHint)

    def setup_ui(self):
        self.layout = QtGui.QVBoxLayout()
        self.label = QtGui.QLabel("<font color='green' size='40'>Ready...</font>")
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.layout.addWidget(self.label)
        self.setLayout(self.layout)

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    win = MyWindow()
    win.show()
    sys.exit(app.exec_())

The above code will display the GUI on the main thread. We now need to think about how our RFID card will be read. The GUI is on the main thread, to make the application responsive, the RFID reading loop must be done on a background thread. Qt, like most UI frameworks, does NOT allow background threads to manipulate the UI thread directly (cross thread calls). Instead, Qt has a construct of Signals for passing messages from the background to the foreground. So in our example, we want the UI to be told when an RFID tag is read on the background thread. We achieve this by running the MFRC522 code on a background thread and emitting signals when a card us scanned.

We extend out MyWindow class by adding method called start_card_reader. This creates a background thread and connects up two messages that will be emitted – one when a RFID reader is ready to read, and another when an RFID tag is detected. In the window constructor, we then add a line to stat the thread.

class MyWindow(QtGui.QWidget):
    lookup_service = LookupService()
    property_window = None
 
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent) 

        self.setup_ui()
        self.resize(320, 240)
        self.setWindowTitle("CPI RFID Reader")
        self.setWindowFlags(QtCore.Qt.WindowTitleHint or QtCore.Qt.WindowSystemMenuHint or QtCore.Qt.WindowMinimizeButtonHint or QtCore.Qt.WindowCloseButtonHint)

        # Start the background thread
        self.start_card_reader()

    def setup_ui(self):
        self.layout = QtGui.QVBoxLayout()

        self.label = QtGui.QLabel("<font color='green' size='40'>Ready...</font>")
        self.label.setAlignment(QtCore.Qt.AlignCenter)
 
        self.layout.addWidget(self.label)
        self.setLayout(self.layout)


    def start_card_reader(self):
        self.reader_thread = RfidReader()
        self.reader_thread.reader_ready.connect(self.reader_ready)
        self.reader_thread.card_detected.connect(self.card_detected)
        self.reader_thread.start()


    def reader_ready(self):
        print('reader ready')
        self.label.setText("<font color='green' size='40'>Ready...</font>")


    def card_detected(self, data):
        print(data)
        self.label.setText("<font color='green' size='40'>Card detected!</font>")

         # Do more stuff!

We create another class for the background thread, which is inherited from QThread. QThread has a run method and this is where our background work will happen. We have a loop that runs until the application is closed.

The loop polls the RFID reader using the MFRC552 library and then emits the UID of the card to the UI thread.

class RfidReader(QtCore.QThread):
   reader_ready = QtCore.Signal()
   card_detected = QtCore.Signal(object)
   m_abort = False
 
   def __init__(self):
       QtCore.QThread.__init__(self)

   def run(self):
       print('Thread started')

       # Create an object of the class MFRC522
       MIFAREReader = MFRC522.MFRC522()

       # This loop keeps checking for chips. If one is near it will get the UID and authenticate
       while not self.m_abort:
           # Scan for cards 
           (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

           # If a card is found
           if status == MIFAREReader.MI_OK:
               print "Card detected"
 
           # Get the UID of the card
           (status,uid) = MIFAREReader.MFRC522_Anticoll()

           # If we have the UID, continue
           if status == MIFAREReader.MI_OK:
               # Print UID
               uid = str(uid[0]) + str(uid[1]) + str(uid[2]) + str(uid[3])
               print "Card read UID: " + uid

               # Signal the UI
               self.card_detected.emit(uid)

               # Put in a sleep so that we reduce reading the same card multiple times
               # Repeatedly
               time.sleep(5)
               self.reader_ready.emit()

Our application can then use the UID to do more stuff, like prompting the user for further action or, in the application I’m working on, properties about a construction product I’ve associated with the UID.

rfid-app-2

rfid-app-5

Use the RFID tag UID to get more information – note that some of this data could be stored in the RFID tag itself

7.Clean up

Just a final point, whenever you use the GPIO pins on the Pi, you should always clean up afterwards. We will do this when the user closes our main application window. Qt windows have a close event that you can override.

    def closeEvent(self, event):
        print('close')

        #Kill thread
        self.reader_thread.m_abort = True
        self.reader_thread.wait()

        GPIO.cleanup()

        #Accept the event to go on and close the window.
        #If we reject the event the window will not close
        event.accept()

So when the user closes the window, we stop and clean up our background thread, and then reset the GPIO pins on the Pi.

8. References