Arduino meet Raspberry Pi

While at the electronics store the other day, I noticed they had motion detectors on sale for only $4. I decided with my latest obsession of electronic tinkering, picking up a OSEEP Passive Infrared Sensor (PIR) Module might be fun.

I guess I should have done a little more reading on the packaging; by the time I was home, I noticed this sensor reported in analog, not digital. This was an issue as the Raspberry Pi only reads digital input.

Lucky for me, I also picked up an Arduino UNO Starter Kit awhile back. I decided this would be a great time to learn more about converting analog signals to digital (one great thing about the UNO is that it has both digital and analog input/output pins).

As an extra, I learned the Nexcon Solar Charger 5000mAh I bough for hiking and camping works great as a Raspberry Pi power source, in theory I can have a portable motion detector 😀

motion_1

motion_2

The wiring is rather basic, there is no need for resistors or capacitors, just direct connections.

* Connect motion sensor to the Adruino’s 5v power and ground.
* Connect motion sensor’s signal pin to Analog A0 pin on Adruino
* Connect Adruino’s Digital 2 pin to Raspberry Pi’s GPIO 18
* Connect Andruino’s ground to Raspberry Pi’s Ground

screen-shot-2016-09-24-at-2-21-03-pm

Once we are wired up, we can compile and upload the Arduino UNO code using Arduino Studio.

Arduino

/*
OSEPP Motion detector analog to digital convertor
http://nessy.info
*/

int analog = A0;
int digital = 2

void setup(){

 // set our digital pin to OUTPUT
 pinMode(digital, OUTPUT);
}

void loop()
{

 // read value from analog pin
 int analog_value = analogRead(analog);

 // send digital signal when motion detected
 if (analog_value > 0) {
   digitalWrite(digital, HIGH);
 } else {
   digitalWrite(digital, LOW);
 }

 delay(100); // slow down the loop just a bit
}

This Arduino code will read analog input from our motion detector, and any time more than 0v is detected it sends a signal to digital pin 2.

Raspberry Pi (Python)

import time
from datetime import datetime

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN)

def detect():
  while True:
    if GPIO.input(18):
      print '[%s] Movement Detected!' % datetime.now().ctime()
    time.sleep(1)


detect()  # run movement detection

On the Raspberry Pi side we will listen for signal on GPIO pin 18, and print out a little message, and timestamp.

screen-shot-2016-09-24-at-1-42-55-pm

From here we can do all sort of things, Happy Hacking!

Raspberry Pi and Official NFL Score Board API

Now that I’ve got my hands on a Raspberry Pi 3 Model B Motherboard, I decided nows a good time to play around with the 16×2 LCD Module Controller HD44780 I had laying around (I’ve had this thing since December 2015).

A live NFL (National Football League) score board seemed fitting as the season just started.

I found a really good write up on raspberrypi-spy.co.uk about wiring up the controller and Pi, here is the diagram I used:

raspberry_pi_circuit

The code to power this controller is simple Python (pushed to Github):

#!/usr/bin/env python

import time

import Adafruit_CharLCD as LCD
import requests

# Raspberry Pi pin configuration:
lcd_rs = 7
lcd_en = 8
lcd_d4 = 25
lcd_d5 = 24
lcd_d6 = 23
lcd_d7 = 18

# Define LCD column and row size for 16x2 LCD.
lcd_columns = 16
lcd_rows = 2

# Initialize the LCD using the pins above.
lcd = LCD.Adafruit_CharLCD(
  lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7,
  lcd_columns, lcd_rows
)

# Start fetch / display loop
while True:

  # fetch current score from NFL api
  res = requests.get('http://www.nfl.com/liveupdate/scorestrip/ss.json')

  if res:

    for game in res.json().get('gms', []):

      # parse our teams and scores
      home_team = '%s %s' % (game['h'], game['hnn'])
      home_team = home_team[:13]
      home_team_score = game['hs']

      away_team = '%s %s' % (game['v'], game['vnn'])
      away_team = away_team[:13]
      away_team_score = game['vs']

      # clear lcd screen
      lcd.clear()

      # write results to lcd screen
      lcd.message('%s %s\n%s %s' % (
          home_team, home_team_score, away_team, away_team_score
        )
      )

      time.sleep(5)

 

SensorTag Temperature Readings in Python

I wanted to wrap up my previous post (TI SensorTag Temperature Readings) with a little python example, thus this write is going to be short and sweet.

Using the bluepy python library (written by Ian Harvey) I’ve been able to to capture temperature readings, then covert them to Fahrenheit.

To demonstrate I captured a couple temperature samples, a few while sitting on my desk, and a few held up to my air condition vent:

root@raspberrypi:~# python temp.py
79.31 degrees fahrenheit
79.31 degrees fahrenheit
79.31 degrees fahrenheit
78.46 degrees fahrenheit
78.01 degrees fahrenheit
76.1 degrees fahrenheit
76.49 degrees fahrenheit
76.27 degrees fahrenheit
75.99 degrees fahrenheit
76.16 degrees fahrenheit

The Python is pretty straight forward:

#!/usr/bin/env python

from bluepy import btle
from time import sleep

sensor = btle.Peripheral('A0:xx:xx:xx:xx:xx')

sensor.writeCharacteristic(0x24, '\x01', withResponse=True)

sleep(1) # warm up

for i in range(10):
    t_data = sensor.readCharacteristic(0x21)
    msb = ord(t_data[3])
    lsb = ord(t_data[2])
    c = ((msb * 256 + lsb) / 4) * 0.03125
    f = c * 9/5.0 + 32
    print '%s degrees fahrenheit' % round(f, 2)
    sleep(2)

sensor.writeCharacteristic(0x24, '\x00', withResponse=True)

Happy hacking!

Telegraf and missing CPU interrupts

As I’ve been playing around with Telegraf and Grafana, I’ve noticed CPU interrupts and context switches are not apart of the standard metric gathering.

We know vmstat shows this information, and can be shown it in a easy processable list form:

$ vmstat -s
 1016888 K total memory
 497920 K used memory
 184412 K active memory
 173296 K inactive memory
 518968 K free memory
 70276 K buffer memory
 86416 K swap cache
 522236 K total swap
 88460 K used swap
 433776 K free swap
 18175 non-nice user cpu ticks
 0 nice user cpu ticks
 17799 system cpu ticks
 172172 idle cpu ticks
 7214 IO-wait cpu ticks
 0 IRQ cpu ticks
 2412 softirq cpu ticks
 0 stolen cpu ticks
 227755 pages paged in
 986944 pages paged out
 2353 pages swapped in
 121572 pages swapped out
 458705 interrupts
 1467529 CPU context switches
 1461773910 boot time
 3456 forks

I decided to hack together a little exec plugin for Telegraf using a Python script,
running the script will get you standard out JSON:

$ /cpu.py
{
 "CPU context switches": 1487011,
 "IO-wait cpu ticks": 7375,
 "IRQ cpu ticks": 0,
 "K active memory": 190392,
 "K buffer memory": 70756,
 "K free memory": 512988,
 "K free swap": 433776,
 "K inactive memory": 173296,
 "K swap cache": 86560,
 "K total memory": 1016888,
 "K total swap": 522236,
 "K used memory": 503900,
 "K used swap": 88460,
 "boot time": 1461773910,
 "forks": 3607,
 "idle cpu ticks": 183663,
 "interrupts": 465536,
 "nice user cpu ticks": 0,
 "non-nice user cpu ticks": 18424,
 "pages paged in": 227767,
 "pages paged out": 990560,
 "pages swapped in": 2353,
 "pages swapped out": 121572,
 "softirq cpu ticks": 2418,
 "stolen cpu ticks": 0,
 "system cpu ticks": 17902
}

The script is a little hacky, but gets the job done for these test:

cpu.py

#!/usr/bin/env python
import commands
import json

output = {}
raw = commands.getstatusoutput('vmstat -s')
raw = raw[1].split('\n')

for row in raw:
    value = int(row.split()[0])
    key = ' '.join(row.split()[1:])
    output[key] = value

print json.dumps(output)

All that is left is to add this script to Telegraf as a plugin:

$ cat /etc/telegraf/telegraf.d/cpu.conf
[[inputs.exec]]
 command = "/cpu.py"
 data_format = "json"
 name_suffix = "_cpu"
 interval = "5s"

And now we have access to all the counters shown in vmstat:

Screen Shot 2016-04-27 at 9.59.11 AM

Python traceroute style tool

Recently, while talking with a some techies I was asked to explain how traceroute works. I was quick to answer what results I expect back from the command, and how to understand that data, but for the life of me I was having issues recalling how TTL works at the foundation.

Later that week I spent some time reading up on it, and click, it all came back.

To reinforce this I decided to write some code. I decided to use Scapy in order to make
crafting network packets a breeze (shown below). You should be able to get Scapy right from PyPi:

$ sudo pip install scapy

tracehop.py

#!/usr/bin/env python


# avoid printing some ipv6 debug stuff from scapy.
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

from scapy.all import IP, ICMP, sr1

from sys import argv


def tracehop(host_or_ip):
  """
  Return the network hops used to arrive at destination.
  """
  # craft our IP portion of the packet with destination address.
  ip = IP(dst=host_or_ip)

  # use a blank ICMP packet.
  icmp = ICMP()

  # set our time to live to 1, this will get our first hop.
  ip.ttl = 1

  # we will loop until getting a echo-response.
  while True:

    # send the ICMP packet and expect one response.
    res = sr1(ip/icmp, verbose=False)

    # print out the responding host source address.
    print res['IP'].src

    # if our ICMP type is 0 we've got
    # the echo response and can break while loop.
    # http://www.nthelp.com/icmp.html
    if res['ICMP'].type == 0:
      break

    # if we did not break above we increase the ttl by
    # one, and let the while loop run once again.
    ip.ttl += 1


if __name__ == '__main__':
  tracehop(argv[1])

The above code should be documented well enough to answer most questions.

Python is unable to create network sockets without root privileges. I do not advise running any script you find on the internet as root until reading over it, and fully understanding what may happen to your system and why root privileges are needed.

With that out of the way lets get right to the usage and output:

$ sudo python tracehop.py nessy.info
192.168.0.1
10.82.16.1
68.4.12.108
68.4.11.68
68.1.1.167
129.250.194.165
129.250.4.42
129.250.3.237
129.250.4.150
129.250.3.27
129.250.5.32
129.250.204.118
198.199.99.238
104.236.149.49

We can compare traceroute’s results to ours, and make sure the hops are relatively similar:

$ traceroute -n nessy.info
traceroute to nessy.info (104.236.149.49), 30 hops max, 60 byte packets
 1 192.168.0.1 19.107 ms 19.470 ms 19.315 ms
 2 10.82.16.1 19.208 ms 28.023 ms 28.233 ms
 3 68.4.12.108 28.142 ms 28.034 ms 27.901 ms
 4 68.4.11.68 27.799 ms 27.683 ms 27.557 ms
 5 68.1.1.167 27.426 ms 27.330 ms *
 6 129.250.194.165 27.095 ms 11.672 ms 18.996 ms
 7 129.250.4.42 27.821 ms 27.727 ms 32.801 ms
 8 129.250.3.237 15.742 ms 20.731 ms 17.218 ms
 9 129.250.4.150 28.956 ms 28.876 ms 28.787 ms
10 129.250.3.27 31.914 ms 32.112 ms 28.468 ms
11 129.250.4.118 28.356 ms 129.250.5.32 31.783 ms 25.326 ms
12 129.250.203.82 23.522 ms 30.280 ms 129.250.204.118 26.967 ms
13 198.199.99.238 26.921 ms 198.199.99.234 31.626 ms 198.199.99.254 27.053 ms
14 104.236.149.49 26.340 ms 26.614 ms 27.644 ms

Then again we could just proof this using traceroute, the -m flag sets our TTL:

$ traceroute -m 1 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 1 hops max, 60 byte packets
 1 192.168.0.1 (192.168.0.1) 3.398 ms 3.592 ms 3.482 ms

And then hack together quickly a bash script:

$ for i in $(seq 1 30) ; do
     traceroute -m $i -n nessy.info | tail -n 1 | egrep "$i " | awk '{print $2}'
  done

192.168.0.1
10.82.16.1
68.4.12.108
68.4.11.68
68.1.1.167
129.250.194.165
129.250.4.42
129.250.3.237
129.250.4.150
129.250.3.121
129.250.4.118
129.250.204.118
198.199.99.254
104.236.149.49

And now the inner-workings of traceroute should be stuck in my head,
never to be tripped up again, or at least that is the plan 😉