Inventing with the IoT – Extension Task

If you have not read Inventing with the IoT – Workshop go do so first, otherwise this will make less sense than usual!

As I said in my previous post, I never actually worked with the IoT code before the workshop, so I downloaded it and combined it with my PiDuino code from earlier this week.  As a result I have an Internet of Things NeoPixel ring.

20140912-120350

IoT NeoPixel ring being modelled by Babbage

The modified Tell.py is straight forward enough.  Remove all the PiBrella code as we’re not using the buttons, then add some lines to get a pixel ID and red, green and blue colour values to define the pixel colour.  Bundle it together as a list object and send to the receiver.

The initial version of the Reveal.py read the incoming data, and uses the values to set the NeoPixel via the PiDuino (as described in my previous article).  That’s all well and good, but how will the remote end sending the command know it’s worked?  Good job I have a PiCamera to hand!  A little Heath Robinson later (note the camera mount), once the pixel is set, an image is captured, some text is overlayed and then uploaded to a gallery on my web hosting. I am using UberGallery, which is just the job as it just displays the images in a folder.

The finished article - stuffed toys optional

The finished article – stuffed toys optional

The following morning @SouthendRPiJams (aka Andy) and I had an IoT exchange, Andy was in the workshop on Saturday. I sent his Pi a message (i.e. “Hello”) which then appeared on his screen and made his PiGlow flash via modified versions of the Tell.py and Reveal.py code (the tell() command just sends the string). He then set up a Tell.py to send me the details my Reveal.py needed to light a pixel, and you can see the results in the gallery currently.

So what’s the practical application?  Currently none, this is just an experiment, but when you look at IoT lights like the Good Night Lamp this project could evolve into something similar; allowing you to be notified when family or friends are at home.  For the more technically minded it could represent the status of a set of services.

I will endeavour to keep my Pi up for a few days if you would like to try the Tell.py script yourself.  Check the gallery around 15-30 seconds after a command has been sent to see if it worked. Send me a tweet before you do, it’s always nice to see these things in action.  Let me know were you’re from and we can see who can get the award for the furthest connection.  Southend to Farnborough to beat.

Please do not make repeated, rapid calls else I’ll have to shut it down for fear of psychological damage to Babbage caused by all those lights!.

The code? Glad you asked…

Tell.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# Tell.py  12/09/2014  C.Monk
#
# Derived from
# Tell.py  12/09/2014  D.J.Whale
#
# Tells a revealed actuator to do something.
# Please exercise restraint and do not make frequent repetitive calls
 
import IoticLabs.JoinIOT as IOT
from config import *
import time
 
MY_NAME        = MY_COMPUTER + "_Tell"
THEIR_COMPUTER = "ForToffee_Pi_1"
THEIR_NAME     = THEIR_COMPUTER + "_Reveal"
THEIR_ACTUATOR = "PIXEL"
 
IOT.joinAs(MY_NAME)
pixel = IOT.attachTo(THEIR_NAME, THEIR_ACTUATOR)
 
def main():
 
  while True:
    p = int(raw_input("Pixel (0 - 15): "))
    if p < 0:
      break
    r = int(raw_input("Red (0-255): "))
    g = int(raw_input("Green (0-255): "))
    b = int(raw_input("Blue (0-255): "))
 
    print ("Sending pixel {} = r{}, g{}, b{}".format(p,r,g,b))
    pixel.tell([p,r,g,b]) 
 
try:
  main()
finally:
  IOT.leave()

Reveal.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# Reveal.py  12/09/2014  C.Monk
#
# Derived from
# Reveal.py  05/09/2014  D.J.Whale
#
# Reveals a set of neopixels so they can be remotely controlled.
#
# This script is designed only for the Raspberry Pi 
 
import IoticLabs.JoinIOT as IOT
from config import *
import time
from datetime import datetime
import picamera
import piduino
from Copro import *
import ftplib
from subprocess import call
 
piduino.firmware("firmware/copro/copro.hex")
piduino.connect(baud=9600)
 
MY_NAME        = MY_COMPUTER + "_Reveal"
MY_ACTUATOR    = "PIXEL"
 
IOT.joinAs(MY_NAME)
 
def newData(actuator, value):
  #print("actuator: ", actuator.topic, actuator.originator, actuator.unique)
  #print("data:" + value)
  data = value.strip('[').strip(']').split(',')
  neopixel(int(data[0]), (int(data[1])/5, int(data[2])/5, int(data[3])/5)) #r,g,b / 5 to save retina!
 
  print 'Capturing image'
  i = datetime.now()  
  now = i.strftime('%Y%m%d-%H%M%S')  
  tweettime = i.strftime('%Y/%m/%d %H:%M:%S')
  photo_name = now + '.jpg'
  photo_full_path = '/home/pi/grabs/' + photo_name
 
#http://picamera.readthedocs.org/en/release-1.8/recipes1.html
  with picamera.PiCamera() as camera:
      camera.resolution = (1024, 768)
      #camera.start_preview()
      # Camera warm-up time
      time.sleep(2)
      camera.capture(photo_full_path)
 
#http://raspi.tv/2014/overlaying-text-and-graphics-on-a-photo-and-tweeting-it-pt-5-twitter-app-series
  overlay_text = "/usr/bin/convert "+ photo_full_path + "  -pointsize 24 -fill white -annotate +40+728 '" + actuator.topic + "' "  
  overlay_text += " -pointsize 36 -fill white -annotate +40+675 'Pixel " + data[0] + " = R:" + data[1] + " G:" + data[2] + " B:" + data[3] + "' " + photo_full_path  
 
  print "overlaying text"  
  call ([overlay_text], shell=True)  
 
#http://stackoverflow.com/questions/12613797/python-script-uploading-files-via-ftp
  print 'Uploading image'
  session = ftplib.FTP('','','')
  fup = open(photo_full_path, 'rb')
  session.storbinary('STOR ' + photo_name, fup)
  fup.close()
  session.quit()
  print 'Done'
 
try:
  IOT.reveal(MY_ACTUATOR, incoming=newData)
  IOT.loop(True)
finally:
  IOT.leave()
  neopixel(0xFF, (0, 0, 0))

What Next?

I need to look at the other functions currently implemented, the more curious amongst you will have noticed the library code is very much in its infancy.  There’s no direct feedback to a message being sent so the remote doesn’t know what happened.  One solution to that at the moment looks to be Feeds, so that may be my next step with this code.

Have fun, and let me know how you get on.

Posted in Add-On, Arduino, IoT, NeoPixel, Projects, Raspberry Jam, Raspberry Pi | Leave a comment

Inventing with the IoT – Workshop

CamJam has a lot to answer for; mainly the evaporation of my evenings this past week. During the jam I helped run the “Inventing with the Internet of Things” workshop, I had no idea what it was all about as it was a last minute thing but I know enough Python and the principles of networking to bumble along. The workshop was run by David Whale in conjunction with IoTic Labs

@whalegeek & @geeky_tim demonstrate the "Internet of Things"

@whalegeek & @geeky_tim demonstrate the “Internet of Things”

The general gist of the workshop is that each Raspberry Pi was a “Thing” on the Internet. Pairing off, one Pi acted as a “sensor” and sent a message when a button was pressed. The other reacted to that message by lighting an LED and playing a sound. Over the course of the workshop the idea was to demonstrate an event happening (a door opened) and a reaction to that event occurring (an alarm sounded). Thus demonstrating what the IoT can/will evolve into.

The source from the workshop is available from the IoTic Labs github . Tell.py is the sensor, Reveal.py is the recipient of that sensor information.

Download, tweak and have fun. You can run both parts on your Pi, if you don’t have a PiBrella tweak the code to do something else (wait for input via raw_input(), or print a message on screen). Once you strip out the Pi specific code it will run on Python on any platform! Modify config.py and set the MY_COMPUTER variable to something unique to you. In my case it now reads

MY_COMPUTER = “ForToffee_Pi_” + str(MY_NUMBER)

When you’re ready hit up the next article for the Extension Task!

Posted in IoT, Projects, Raspberry Jam, Raspberry Pi | Leave a comment

PiDuino Adventures

At the weekend I took a 90 mile road trip north to Cambridge for the latest CamJam. As always lots to see and do, along with several purveyors of Pi related goodies, which may have been my wallets down fall.  Amongst my stash of swag is a PiDuino from the SKPang stall, at £10 down from £18 it was rude not to!

The PiDuino is an add-on board to connect an Atmega328 to a Raspberry Pi via SPI and serial.  The SPI is used to program the chip with your Arduino code and the serial (which can be disconnected) is there for communications between the devices.

PiDuino

A PiDuino

At the CamJam in July I had been shown an early version by David (whaleygeek) Whale who has provided not only software support for the Arduino code, but also a Python library to load the compiled firmware onto the chip at runtime (more on that later).

Soldering Iron at the Ready

The PiDuino comes in kit form so I had to get soldering first.  The instructions are nice and clear, however I have asked SKPang if they could adjust the sequence of events to start with the lower profile components first.  Starting with the jumper headers made the board unstable on the worktop.

After a couple of user errors (read twice, solder once!) the board powered up and away we went!

Getting Up and Running

The first thing I did was follow the instructions to install a modified version of avrdude from Gordon Henderson, and the Arduino IDE.  In reality you only need to do this if you plan on putting together and compiling your own firmware for the ATmega on the Pi.

Enter stage left WhaleyGeek and his Python loader.  Hats off to David on this one, I won’t go into details, just read his blog post about it.

It Lives!

Yup, it had to be done; Test_Blinky.py was run, the firmware loaded and the little red LED on the PiDuino winked at me.  It’s amazing how satisfying a flashing LED can be.

After this I downloaded Davids NeoPixel colour mixer code, wired up a 16 LED NeoPixel ring, tweaked the Python (24 NeoPixels down to 16) and ran the code.  It worked great!  The firmware that’s loaded is called CoPro and currently controls a set of NeoPixels, a servo and posts messages back when one of three analog inputs changes; all via serial comms.

Note: As I found out the PiDuino (understandably) draws current away from your Pi.  Make sure your power supply is up to the job, the USB hub on my Dell monitor wasn’t and every time I inserted/removed/touched a wire it caused a Pi resetting brown out.  A 2A power supply stabilised things nicely.

I also attached a 10k pot (variable resistor) I had kicking around in my kit.  This allowed me to simulate one of the resistive strips on the demo program.

Time to Tinker

Once I knew it was all working was time to tinker.  Using the demo program as a base I wrote a program to change the LED position on the Neopixel ring in step with the 10k pot; as it turns, the LED moves round the ring.  Oh, and it randomly picks a colour from a pre-set list, for added blinkyness.

When I was happy with that I added a servo I had to hand, to try out the servo support in the  CoPro firmware.  Again this worked very nicely as you can see in the video below (apologies for the poor lighting, hopefully the YouTube enhancements have improved things).

There were a couple of things that tripped me up

  1. The neopixel command required a short pause after each pixel is sent
  2. Global variables are a pain in the bum
  3. The CoPro firmware pushes the current analogue value to the serial buffer when it changes.  If nothing has changed since the last read you get back no values

The first I fixed in the copro.py class provided as the pause is already present if you provide multiple pixels.  I include the tweaked copro.py and my source in this zip.  I’ve not included all the rest of the PiDuino files as these are available from David’s blog post I mentioned earlier.

Here are some close ups of the wiring – A0 = 10k pot (3.3v), D9 = servo (5v), D10 = NeoPixel ring (5v)

PiDuino Wiring Breadboard Wiring

Posted in Add-On, Arduino, NeoPixel, Raspberry Pi | Leave a comment

Pi Controlled NeoPixel Ring

OK, so not 100% accurate; a Pi controlled Adafruit Trinket controlled NeoPixel ring :-D

I got the idea from seeing Dave Whale’s serial based Arduino interface with the Pi. The Trinket doesn’t have serial so I had to use something else to talk to it.

Enter I²C;  on the Trinket side I’m using the TinyWireS library, on the Pi side I’m calling smBus.writeList() with a list of the bytes I wish to send.  You’ll notice in the video there’s an extra breakout in the circuit, this is a bi-directional level converter to allow the 5v Trinket to talk to the 3.3v Pi without releasing any magic smoke.

My aim is to implement the commands in the Neopixel library however at the moment it just calls setPixelColor with the 4 values (LED, Red, Green, Blue) provided by the Pi. I have a special case of LED==0xFF which lights all LEDs the specified colour (a concept I have pinched from David).  I have included the code below in it’s current (probably hacky) state.

One problem I did find is that the Pi randomly “loses” the I²C address of the Trinket and reports it as 0x03 for a second or two.  I’m not sure if the problem is the Pi or Trinket end but it seems to be an issue with Arduinos in general.  The basis of the work around I used in my Python code can be found here. If anyone knows the reason for this I would be most grateful; it’s a horrible hack

Arduino Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <TinyWireS.h>
#include <Adafruit_NeoPixel.h>
 
#define PIN 1
#define I2C_SLAVE_ADDRESS 0x04
 
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);
 
// The default buffer size, Can't recall the scope of defines right now
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif
 
int rxIndex = 0; 
 
volatile uint8_t i2c_regs[] =
{
    0x0, // RegisterID
    0x0, // Pin
    0x1, // R
    0x0, // G 
    0x0, // B
};
const byte reg_size = sizeof(i2c_regs);
 
//Handles receiving i2c data.
void receiveEvent(uint8_t howMany)
{
    if (TinyWireS.available()){  
      if (howMany < 1)
      {   // Sanity-check
          return;
      }
      if (howMany > TWI_RX_BUFFER_SIZE)
      {   // Also insane number
          return;
      }
 
      if (howMany == 1)
      {   // This write was only to set the buffer for next read
          return;
      }
      rxIndex = 0;
      while(howMany--)
      {   //Gets i2c data. 
          i2c_regs[rxIndex] = TinyWireS.receive();
          rxIndex++;
          if (rxIndex >= reg_size){
            if (i2c_regs[1] == 0xFF) {
              for (uint8_t p=0;p<strip.numPixels();p++){
                strip.setPixelColor(p,strip.Color(i2c_regs[2], i2c_regs[3], i2c_regs[4]));
              }
            }
            else {
              strip.setPixelColor(i2c_regs[1], strip.Color(i2c_regs[2], i2c_regs[3], i2c_regs[4]));    
            }
            strip.show();
            rxIndex = 0;
          } 
      }
 
    }
}
 
void setup() {
  TinyWireS.begin(I2C_SLAVE_ADDRESS);
  TinyWireS.onReceive(receiveEvent);
 
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}
 
void loop() {
  TinyWireS_stop_check();
}

Pi Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import time
import smbus
import os
import subprocess
 
i2cBus = 0
i2cAddr = 0x04
bus = smbus.SMBus(i2Bus)
debug = False
 
def writeList(reg, list):
    sent = False
    attempt = 0
    while sent==False:
        if debug:
            print "I2C: Writing list to register 0x%02X:" % reg
            print list
        try:
            bus.write_i2c_block_data(i2cAddr, reg, list)
            sent = True
        except IOError:
            #a 'hack' to catch the Arduino disappearing at random intervals
            #runs i2cdetect to refresh the i2c interface, output to /dev/null so we don't see the output
            FNULL = open(os.devnull, 'w')
            retcode = subprocess.call(['i2cdetect', '-y', str(i2cBus)], stdout=FNULL, stderr=subprocess.STDOUT)
            time.sleep(0.1)
            attempt += 1
            if attempt == 10:
                raise Exception('Unable to connect via I2C')
 
def setLED(led, red, green, blue):
    bytes= [led, red, green, blue]
    writeList(0x01, bytes)
 
setLED(0xFF, 0, 0, 0)
time.sleep(0.5)
setLED(0xFF, 32, 32, 32)
time.sleep(0.5)
setLED(0xFF, 0, 0, 0)
 
try:
    while True:
        for p in range(0, 16):
            setLED(p, 32, 0, 0)
            time.sleep(0.1)
        for p in range(0, 16):
            setLED(p, 0, 32, 0)
            time.sleep(0.1)
        for p in range(0, 16):
            setLED(p, 0, 0, 32)
            time.sleep(0.1)
        for p in range(0, 16):
            setLED(p, 0, 0, 0)
            time.sleep(0.1)
except KeyboardInterrupt:
        pass
 
setLED(0xFF, 0, 0, 0)
Posted in Arduino, NeoPixel, Projects, Raspberry Pi, Trinket | Leave a comment

Baby steps into Arduino

I have always programmed in VB (5, 6, .NET even VBA!), I’m also starting to look at C# again after a brief dalliance 5 years ago, and of course I have a passable knowledge of Python from working with the Raspberry Pi.

Ever since picking up and playing with the Pi I have become aware of these Arduino thingies. What really peaked my interest were the wearables like GEMMA and FLORA and the work of Charlotte Godley. They’re small, uncomplicated (in theory) devices to hack about on fairly easily.

Fast forward to the beginning of the month at the July CamJam and I was enticed by The PiHut and their wares, eventually crumbling and buying an Adafruit Trinket along with a NeoPixel ring (mmmm 16 LEDs!). After getting the IDE and drivers setup (more on that later) I loaded the obligatory blink sketch, which is the Arduino equivalent of ‘hello world’.

Flushed with success (or something like that) I moved on to the NeoPixel ring, wired it up and loaded the Larson Scanner sample. It needed a couple of tweaks; namely the data pin and the number of pixels, but it worked very well.

Ultimately it was time to write my first ever bit of Arduino (or C for that matter) code, cribbing from and building on the examples I had come across thus far.

The embedded video shows alternating green and purple filling up the ring, followed by yellow and red. I was working on this while helping run Pi sessions the tech zone at Gilwell 24 so the patterns arise from the Scout brand colours and the colours of my Scout scarf respectively. My code, for what it’s worth, is below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include &lt;Adafruit_NeoPixel.h&gt;
 
#define PIN 1
 
// Parameter 1 = number of pixels in strip
// Parameter 2 = pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);
 
void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}
 
void loop() {
  // Scout green and purple
  spin(strip.Color(132/4, 164/4, 11/4),strip.Color(77/4, 33/4, 119/4));
  // BWV Explorers red and yellow
  spin(strip.Color(255/4,0, 0), strip.Color(255/4,255/4, 0));
}
 
void spin(uint32_t c1, uint32_t c2){
  uint32_t c;
 
  // fill in reverse, so highest pixel number first
  for(int8_t p=strip.numPixels() - 1; p&gt;=0; p--){
    // set even pixels to colour 'c1', odd to 'c2'
    if (p%2==0){
      c = c1;  
    }
    else{
      c = c2;
    }
    cycle(0,p,c);
  }
  delay(100);
}
 
void cycle(int8_t f, int8_t l, uint32_t c){
 
  for(uint8_t i=f;i&lt;=l;i++)
  {
      // clear last pixel, set current pixel
      strip.setPixelColor(i-1, 0);
      strip.setPixelColor(i, c);
      strip.show();
      delay(100);
  }
}

Things I Learnt

The USB is temperamental – After much faffing and cursing I discovered in the Adafruit FAQ about reducing the chip_erase_delay. This made things much happier on my laptop!

Updating AVRDUDE helped too – After working well on another laptop my home one refused to work again. A few Google searches later and the AdaFruit forum came to the rescue with AVRDUDE v1.15.13

Commands in C must end with ‘;’ – Obvious I know but the number of times I forgot!

For loops work differently – I’m used to a For … Until construct (i.e. For n = 0 to 15 or for n in range(0 to 16)). It took me ages to work out why my for (n= 15; p=0; p--) didn’t work correctly!

Debugging is hard – The Trinket has no serial console so you can’t see what the code is doing. To resolve one issue I ended up downloading Tiny C Complier (TCC) and creating test code to see what I was doing wrong. For reference a uint_8 of 0 minus 1 is 255 not -1 because it’s unsigned – doh!

All in all it’s been a very fun learning curve and I’m looking forward to trying out a few more AdaFruit examples. Oh wait, what’s that in the next article?

Posted in Arduino, NeoPixel, Trinket | Leave a comment