NFC MODULE V3 Raspberry pi


The below guide is to setup a pn532 nfc reader on a raspberry pi.

First up make surer the PN532 is setup in UART mode, and connect to the pi in the same manor as the diagram below.

PN532-PI.png

Figure 1: PN532 Rfid read connected to a Raspberry PI

Before getting started setup your pi with the latest debian image and complete your standard setup. Once the pi is setup run the commands below installing the necessary libraries.

Run the below commands to install the tools and libraries we will need for the rest of the setup.

sudo apt-get install git build-essential autoconf libtool libpcsclite-dev
sudo apt-get install libusb-dev libcurl4-openssl-dev libjson-c-dev python-pip

Download the nfc library from github.

git clone https://github.com/nfc-tools/libnfc.git
cd libnfc
sudo mkdir -p /etc/nfc/devices.d/

Copy the relevant config to the correct place on the pi.

sudo cp contrib/libnfc/pn532_uart_on_rpi_3.conf.sample /etc/nfc/devices.d/pn532_uart_on_rpi_3.conf

Compile the libnfc library.

autoreconf -vis
./configure --with-drivers=pn532_uart --sysconfdir=/etc --prefix=/usr
sudo make clean && sudo make install all

Install the python library

pip install -U nfcpy

To check everything is working try running the command below to make sure your reader is detected and listed.

nfc-scan-device

Now create your first python program to make sure everything is working.

import nfc
import ndef
from nfc.tag import tt1
from nfc.tag import tt2
from nfc.tag import tt3
from nfc.tag import tt4


tagtypes = (
    ('uid', nfc.tag.tt1.Type1Tag),
    ('uid', nfc.tag.tt2.Type2Tag),
    ('idm', nfc.tag.tt3.Type3Tag),
    ('uid', nfc.tag.tt4.Type4Tag)
)

def connected(tag):
    print tag.type
    for uid, type in tgtypes:
	if isinstance(tag, type):
	    print str(attr(tag, uid)).encode("hex")
	    return
    print "error: unknown tag type"

with nfc.ContactlessFrontend('tty:S0:pn532') as clf:
    print('waiting for connection')
    print(clf)
    tag = clf.connect(rdwr={'on-connect': lambda tag: False})
    print(str(tag.identifier).encode('hex'))
    print(tag.type)
    if not tag.ndef:
	print('no ndef data') 
    else:
	for record in tag.ndef.records:
	    print(record)

Restoring an old myford ml8 lathe


Recently i was given an old Myford ML8 lathe which was working but very rusty, i have never really tried dismantling and rebuild this type of machine before so this will be a learning experience.

lathe-01.jpg

Figure 1: lathe original state 01

lathe-02.jpg

Figure 2: lathe original state 02

lathe-03.jpg

Figure 3: lathe original state 03

Been cleaning the parts removing the rust and paint with a wire brush drill attachement, and smaller versions on a dremel for the awkward bit.

The smaller metal parts i have soaked in vinegar then rubed down with wire wool and sprayed with oil to top them re rusting.

lathe-04.jpg

Figure 4: lathe cleaning 01

lathe-05.jpg

Figure 5: lathe cleaning 02

lathe-06.jpg

Figure 6: lathe cleaning 03

After cleaning up the parts, i have primed them in some metal paint to help protect from rust, currently jut primed but i like the colour so will likely keep it bright red.

lathe-07.jpg

Figure 7: lathe cleaning 01

lathe-08.jpg

Figure 8: lathe cleaning 02

lathe-09.jpg

Figure 9: lathe cleaning 03

Sill lots of cleaning an painting todo, got a stuck pulley which will not come free from the shaft, and need to strip back the main housing and clean.

Building a sumo robot ring


We have decided to build some sumo robot at the hackspace, so i decided to take up this challenge here are some pictures from the build.

Problems

Attempting to cut out a large circle with the tools i had available proved to be tricky, tried using a router attached to some ply initally but this struggled to cut well.

In the end i used a jigsaw this worked quite well but the curve of the circle would move the blade away from its centre guild and caused me to take some chunks out that i had not in tended.

The build

IMG_20170624_160836.jpg

Figure 1: Joining two sheets of mdf together

IMG_20170625_105122.jpg

Figure 2: Cutting the circle with a jig bolted to a piece of wood

IMG_20170625_113520.jpg

Figure 3: The inaccuracy

IMG_20170729_113420.jpg

Figure 4: Fixing the inaccuracy

IMG_20170811_173114.jpg

Figure 5: Masking for the lines

The final ring

I am reasonably pleased with the outcome it certainly could have been better, if i had cut the initial circle out more accurately also the rim could have done with being thicker to support the weight, this would likely have been harder to bend with the tools I had available.

IMG_20170813_093622.jpg

Figure 6: The final ring

Lets build some robots

So now we have a ring lets build some robots, we can use them to test ideas for pi wars next year as well :)

I propose controlled for now, and small in size perhaps with these dimensions based on online dimensions.

500 millimetres high 200 millimetres width 200 millimetres depth 3000g weight limit

Auto generated update and rollback database scripts with magit and emacs


This code loops over all .sql .pks and .pkb files and merges them into the current buffer, it currently need to be run from the projects root.

Magit has some useful methods we can utilise to get a list of staged files, from there we can join the results into the current buffer. We can also use magit functions to get the same list before modification to generate a rollback.

Get previous version of staged files and generate a rollback script, we can use magit-find-file-noselect to get an older version.

(defun generate-oracle-rollback-script () 
  (interactive) 
  (insert "SET DEFINE OFF;\n\n")
  (loop for i in (cddr (magit-staged-files)) 
	if (string-match "\\(\.sql\\|\.pkb\\|\.pks\\)" i)
	collect (insert (concat "-- START AUTO GENERATED " i "\n" (with-current-buffer 
									    (magit-find-file-noselect "HEAD" 
									    (expand-file-name i)) (buffer-string))
									    )
				"\n-- END AUTO GENERATED " i "\n\n"))
	)

Get all staged files and generate an update script, we can get a list of staged files with magit-staged-files and insert into the current buffer with insert-file-contents.

(defun generate-oracle-update-script () 
  (interactive) 
  (insert "SET DEFINE OFF;\n\n")
  (loop for i in (cddr (magit-staged-files)) 
	if (string-match "\\(\.sql\\|\.pkb\\|\.pks\\)" i)
	collect (insert (concat "-- START AUTO GENERATED " i "\n" (with-temp-buffer
									    (insert-file-contents
									    (expand-file-name i))
									    (buffer-string))
				"\n-- END AUTO GENERATED " i "\n\n"))
	)
)

Future enhancement would be to detect the project root from any buffer with in the project you have open.

Blogging with org mode and nikola


Below are some tips and technologies used to write and deploy this blog.

Getting started

To get started creating your blog first install nikola with pip or use the docker container, then run nikola init to create your new blog.

Org header attributes

All org files should start with this header containing the blog entry meta data, the below example is from this post.

#+BEGIN_COMMENT
.. title: Blogging with org mode and nikola 
.. slug: blogging-with-org-mode-and-nikola
.. date: 2017-01-02 12:00:00 UTC
.. tags: emacs, python
.. category: emacs
.. description: How I use emacs and nikola to write my blog
.. type: text
#+END_COMMENT

Nikola lets you create your blog entries in various formats like org, markdown, rtf and ascii doc as a few examples, The main advantage is that you don't need a database and can redistribute your files as plain documents, if you use orgmode format in particular this works very well because you can export to various formats like pdf or word documents which works great for sending to people or for making offline or printable copies. Basically you get a lot of power with little effort.

Updating nikola configuration

To use org you will need to adjust conf.py the examples below are the relevant parts to find and update with the org extensions. ORG_REGEX_REPLACE is only needed if your using my modified plugin.

POSTS = (
    ("posts/*.rst", "posts", "post.tmpl"),
    ("posts/*.txt", "posts", "post.tmpl"),
    ("posts/*.org", "posts", "post.tmpl"),
    ("posts/*.md", "posts", "post.tmpl"),
)
PAGES = (
    ("stories/*.rst", "stories", "story.tmpl"),
    ("stories/*.txt", "stories", "story.tmpl"),
    ("stories/*.org", "stories", "story.tmpl"),
    ("stories/*.md", "stories", "story.tmpl"),
)
COMPILERS = {
    "rest": ('.rst', '.txt'),
    "markdown": ('.md', '.mdown', '.markdown'),
    "textile": ('.textile',),
    "txt2tags": ('.t2t',),
    "bbcode": ('.bb',),
    "wiki": ('.wiki',),
    "ipynb": ('.ipynb',),
    "html": ('.html', '.htm'),
    "orgmode": ('.org',),
    "php": ('.php',),
}
ORG_REGEX_REPLACE = [(r'src\=\"(../)*', 'src="/')]

ORG_PRETTY_URL_ADJUST = True

Hosting your blog

I hast my blog on my own server and domain which is an option but you can also deploy your blog to github pages if you don't want the cost and hassle of maintaining your own environment.

Containers

The setup I use below involves using containers to generate deploy an host the container, this means the setup is portable you just need docker available on your machine the rest of the technologies are installed inside the containers. If you want a similar setup you can copy the docker compose and drone files below.

To generate your blog you just need to run the following command.

docker-compose up

Nikola org file tips

Hiding posts

If you want to deploy but hide your posts from the index's you can tag them with draft.

.. tags: emacs, python, draft

You can also stop your posts from being deploy altogether by putting DEPLOY_DRAFT = False in your nikola config. see https://getnikola.com/handbook.html#drafts for more information.

Inline images

Emacs lets you render your images direct in your document which is great for verifying your image paths, however there is an issue with nikola currently which means it changes the depth of your post so the deployed images will not display:

You have a couple of options

  • Manually put in the correct path for nikola and loose the display and verification that the path is correct, you can still run the server locally to verify.
  • The other option is to use a patched version which I am doing, this means i never actually need to test my pages I can write the post commit and be confident its correct.

https://github.com/olymk2/plugins

  • Bug the dev's they are not planning on fixing this currently but if enough people want it fixed they might, so if you want to get this fixed i suggest you add to the issue below or raise a new issue.

https://github.com/getnikola/plugins/issues/188

Docker images for rendering your org files

You can use the container below to generate your blog, its a simple container with emacs added with org mode which is called to generate the html pages.

FROM olymk2/emacs

RUN apt-get update
RUN apt-get install -y locales locales-all python3 python3-pip python3-gdbm

RUN dpkg-reconfigure locales

ENV LC_ALL C.UTF-8

RUN locale-gen en_US.UTF-8  
ENV LANG en_US.UTF-8  
ENV LANG C.UTF-8  
ENV LANGUAGE en_US:en  

COPY ./build/requirements.txt /app/requirements.txt

RUN pip3 install -r /app/requirements.txt
RUN nikola plugin -i orgmode

WORKDIR /app
ENTRYPOINT nikola clean; nikola build

Auto deploy with drone

I use drone to deploy my blog you can use other CI services, but using drone keeps it simple as i can use the same containers I host my site with.

workspace:
  base: /drone
  path: src

pipeline:
  publish:
    pull: True
    image: appleboy/drone-ssh
    host: ${SSH_DOMAIN} 
    user: ${SSH_USER}
    key: ${SSH_KEY}
    port: 22
    command_timeout: 240
    script:
      - cd /var/www/your-site-location/
      - git pull
      - docker-compose build 
      - docker-compose up --remove-orphans 
      - echo 'Finished deploy'

Nikola Emacs plugin

I have been working on a simple plugin for emacs to give you a magit style menu to nikola from inside nikola if you would like to try this visit the link below. https://github.com/olymk2/emacs-nikola

Demonstration on how to switch windows with python


xcb-window-switcher.jpg

Figure 1: Window list output

I have been experimenting with writing my own launcher app similar to gnome do, one of the things i wanted was to switch windows by typing the name, so i wrote the below example to work out how to switch window.

It works with you xserver to request a list of windows and then send the event to change focus, i have only tested this in gnome how ever it will likely work with other desktops.

The main thing you need todo is to set input focus before raising the window, if you do not some window managers like gnome will just notify you instead of raising the window.

#!/usr/bin/env python
import time
import struct

import xcb
from xcb import xproto

# standard xcb to get an xserver connection and root window
xserver = xcb.connect()
xclient = xserver.core
setup = xserver.get_setup()

canvas = setup.roots[0]
root_window = canvas.root

unsigned_int_32_max_size = (1 << 32) - 1


def get_atom(name):
    return xclient.InternAtom(
	0,
	len(name),
	name
    ).reply()


# setup a load of atoms as constants for later use
_NET_WM_STATE = get_atom('_NET_WM_STATE')
_NET_WM_NAME = get_atom('_NET_WM_NAME')
_NET_WM_WINDOW_TYPE = get_atom('_NET_WM_WINDOW_TYPE')
_NET_WM_WINDOW_TYPE_APPLICATION = get_atom('_NET_WM_WINDOW_TYPE_NORMAL')
_NET_CLIENT_LIST = get_atom('_NET_CLIENT_LIST')

# query _NET_CLIENT_LIST which contains a list of windows
clientlist_reply = xclient.GetProperty(
    False, root_window, _NET_CLIENT_LIST.atom,
    xcb.xproto.GetPropertyType.Any,
    0, unsigned_int_32_max_size).reply()

# unpack the reply into a list, xcb returns a list of ints
# in this case
window_list = list(struct.unpack(
    'I' * clientlist_reply.value_len, clientlist_reply.value.buf()))


for window in window_list:
    if window is 0:
	continue

    # get some of the useful properties
    # you can use xprop in a terminal to see whats available
    window_name = xclient.GetProperty(
	delete=False,
	window=window,
	property=xproto.Atom.WM_NAME,
	type=xproto.GetPropertyType.Any,
	long_offset=0,
	long_length=unsigned_int_32_max_size).reply()

    window_class = xclient.GetProperty(
	delete=False,
	window=window,
	property=xproto.Atom.WM_CLASS,
	type=xproto.GetPropertyType.Any,
	long_offset=0,
	long_length=unsigned_int_32_max_size).reply()

    window_type = xclient.GetProperty(
	delete=False,
	window=window,
	property=_NET_WM_WINDOW_TYPE.atom,
	type=xproto.GetPropertyType.Any,
	long_offset=0,
	long_length=1).reply()

    window_net_name = xclient.GetProperty(
	delete=False,
	window=window,
	property=_NET_WM_NAME.atom,
	type=xproto.Atom.Any,
	long_offset=0,
	long_length=unsigned_int_32_max_size).reply()

    # This does the focus, set the window to have input focus
    # then raise the window with configure window
    xclient.SetInputFocus(
	xcb.xproto.InputFocus.Parent,
	window,
	xcb.xproto.Time.CurrentTime)

    xclient.ConfigureWindow(
	window,
	xproto.ConfigWindow.StackMode,
	[xproto.StackMode.Above])

    xserver.flush()
    time.sleep(0.25)

    window_class = ''.join([chr(c) for c in window_class.value])
    window_name = ''.join([chr(c) for c in window_name.value])
    window_net_name = ''.join([chr(c) for c in window_net_name.value])

    print('-------')
    print('window id = %s' % window)
    print('window name = %s' % window_name)
    print('window net name = %s' % window_net_name)
    print('window class = %s' % window_class)

GAUPS usage and setup


To quite screen hold down CTRL + d then press SHIFT + K and answer Y to exit the screen. Alternatively CTRL + a then type :quit.

screen /dev/ttyACM0 115200

Running $$ will list your current config, my current setup is in the example below.

$0=10 (step pulse, usec)
$1=25 (step idle delay, msec)
$2=0 (step port invert mask:00000000)
$3=0 (dir port invert mask:00000000)
$4=0 (step enable invert, bool)
$5=0 (limit pins invert, bool)
$6=0 (probe pin invert, bool)
$10=19 (status report mask:00010011)
$11=0.010 (junction deviation, mm)
$12=0.002 (arc tolerance, mm)
$13=0 (report inches, bool)
$20=0 (soft limits, bool)
$21=0 (hard limits, bool)
$22=1 (homing cycle, bool)
$23=0 (homing dir invert mask:00000000)
$24=25.000 (homing feed, mm/min)
$25=500.000 (homing seek, mm/min)
$26=250 (homing debounce, msec)
$27=1.000 (homing pull-off, mm)
$100=80.000 (x, step/mm)
$101=80.000 (y, step/mm)
$102=500.000 (z, step/mm)
$110=500.000 (x max rate, mm/min)
$111=500.000 (y max rate, mm/min)
$112=500.000 (z max rate, mm/min)
$120=10.000 (x accel, mm/sec^2)
$121=10.000 (y accel, mm/sec^2)
$122=10.000 (z accel, mm/sec^2)
$130=200.000 (x max travel, mm)
$131=200.000 (y max travel, mm)
$132=200.000 (z max travel, mm)

Run drone test suite from emacs


The first function drone-root simply searches for .drone.yml by searching up the file system tree from the current files path.

The second function drone-exec runs drone exec and output the results to a new buffer called *drone:.

(defun drone-root ()
  (or (locate-dominating-file default-directory ".drone.yml")
      (error "Missing .drone.yml not found in directory tree")))

;;;###autoload
(defun drone-exec ()
  "Run \"drone exec\" where .drone.yml is found."
  (interactive)
  (let ((default-directory (drone-root)))
    (with-current-buffer (get-buffer-create (concat "*drone: " default-directory "*"))
      (compilation-start (format "drone exec")
	nil
	(lambda (_) (buffer-name))))))

Fetch jira summary from JIRA-ID under cursor with emacs


The below snippet will grab the JIRA-ID under your cursor and use it to look up the summary and past it next to the JIRA-ID.

You need to have org-jira installed because this makes use of org-jira-get-issue-by-id to look up the ticket details.

(defun org-jira-get-summary ()
  "insert summary next to ticket id from jira"
  (interactive)
  (let ((jira_id (thing-at-point 'symbol)))
    (forward-symbol 1)
    (insert (format " - %s" 
      (cdr (assoc 'summary (car (org-jira-get-issue-by-id jira_id))))))))

This next snippet does the same as the first except it also replaces the ID with a link back to jira

(defun org-jira-get-summary-url ()
  "insert summary next to ticket id from jira with url link"
  (interactive)
  (let ((jira_id (thing-at-point 'symbol)))
    (sp-kill-symbol 1)
    (insert (format "[[%s][%s]] - %s" (concatenate 'string jiralib-url "browse/" jira_id) jira_id  
      (cdr (assoc 'summary (car (org-jira-get-issue-by-id jira_id))))))))

You will need to also place the code below some where to make the jira methods available, hopefully these will be merged directly into org jira soon.

(require 'org-jira)

Printing with Cairo GTK3 and python


gtk_print_example_01.png

Figure 1: You can download image used in the example below.

testing-256px.png

Figure 2: You can download image used in the example below.

This example uses the gtk3 toolkit the same toolkit used by popular software like gimp and inkscape, it should be quite easy to convert to gtk2 if required the advantage of using gtk is that the libraries are cross platform so you should be able to print on all platform however i have only tested this on ubuntu 15.04 so far.

#!/usr/bin/python
# -*- coding: utf8 -*-
from gi.repository import Gtk, Pango, PangoCairo#, cairo
import cairo

# a4 = 210 x 297
page_width = 210
page_height = 297
page_margin_top = 20
dpi = 600
_mm_dpi = 72 / 25.4

class PrintExample(Gtk.Window):

    def __init__(self):
	self.print_image()

    def print_image(self):
	"""setup the paper size, print settings and kick of the print operation"""

	ps = Gtk.PaperSize.new_custom("cc", "cc", page_width, page_height, Gtk.Unit.MM)
	print_settings = Gtk.PrintSettings()
	print_settings.set_resolution(dpi)

	page_setup = Gtk.PageSetup()
	page_setup.set_paper_size(ps)
	page_setup.set_bottom_margin(10.0, Gtk.Unit.MM)
	page_setup.set_left_margin(5.0, Gtk.Unit.MM)
	page_setup.set_right_margin(4.5, Gtk.Unit.MM)
	page_setup.set_top_margin(10.0, Gtk.Unit.MM)
	page_setup.set_orientation(Gtk.PageOrientation.PORTRAIT)


	print_operation = Gtk.PrintOperation()
	print_operation.set_n_pages(1)
	print_operation.set_default_page_setup(page_setup)
	print_operation.set_print_settings(print_settings)
	print_operation.connect("draw_page", self.draw_page)
	print_operation.set_export_filename("example.pdf")

	result = print_operation.run(Gtk.PrintOperationAction.PREVIEW, None)
	print(result)


    def draw_page (self, operation, print_context, page_number):
	"""draw with cairo to the print context layout for printing on sticky labels on an a4 sheet"""
	cr = print_context.get_cairo_context()
	cr.set_source_rgb(0, 0, 0)

	ims=cairo.ImageSurface.create_from_png("test.png")
	cr.set_line_width(1)

	desc = Pango.FontDescription("sans 5")

	layou_title_text = PangoCairo.create_layout(cr)
	layou_title_text.set_text("Title Text", -1)
	layou_title_text.set_font_description(desc)
	layou_title_text.set_width(100 * Pango.SCALE)
	layou_title_text.set_wrap(Pango.WrapMode.WORD)

	layou_desc_text = PangoCairo.create_layout(cr)
	layou_desc_text.set_text("Lorem ipsum .....", -1)
	layou_desc_text.set_font_description(desc)
	layou_desc_text.set_width(50 * Pango.SCALE)
	layou_desc_text.set_wrap(Pango.WrapMode.CHAR)

	#offset is the distance from the start of one box to the next including blank space
	rectangle_x_offset = 40.5 * _mm_dpi
	rectangle_y_offset = 21.5 * _mm_dpi

	#actual size of the box
	rectangle_width = 38 * _mm_dpi
	rectangle_height = 21.5 * _mm_dpi
	columns = int(page_width / 38)
	rows = int((page_height-page_margin_top) / 21)

	for column in range(0, columns):
	    for row in range(0, rows):
		#qr code
		cr.set_line_width(0.1)
		cr.save()
		cr.translate(column * rectangle_x_offset, row * rectangle_y_offset + 15)
		cr.scale(0.15, 0.15)
		cr.set_source_surface(ims, 0, 0)
		cr.paint()
		cr.restore()

		#rectangle
		cr.rectangle(column * rectangle_x_offset , row * rectangle_y_offset, rectangle_width , rectangle_height )
		cr.stroke()

		#title text
		cr.save()
		cr.move_to(column * rectangle_x_offset + 4, row * rectangle_y_offset + 4)
		PangoCairo.update_layout(cr, layou_title_text)
		PangoCairo.show_layout (cr, layou_title_text)
		cr.restore()

		#description text
		cr.save()
		cr.move_to(column * rectangle_x_offset + 50, row * rectangle_y_offset + 14)
		PangoCairo.update_layout(cr, layou_desc_text)
		PangoCairo.show_layout (cr, layou_desc_text)
		cr.restore()

win = PrintExample()
Gtk.main()