Adding custom commands to octoprint

To follow on from my last post about controlling a PSU with a transistor on a 3D printer running OctoPrint on a Sanguinololu board I have created a few custom buttons to increase the functionality of the software with these new features.

If not specified via the commandline, the configfile config.yaml for OctoPrint is expected in its settings folder, which is located at ~/.octoprint on Linux, at %APPDATA%/OctoPrint on Windows and at ~/Library/Application Support/OctoPrint on MacOS.

I added the following custom commands:
Turn PSU on
Turn PSU off
Get Position
Set Z10
Goto Z10

Shutdown octoprint, add this to the end of config.yaml and restart octoprint. note that the spacings are important.

controls:
  - name: Get Position
    type: feedback_command
    command: M114
    regex: "X:([0-9.-]+)Y:([0-9.-]+)Z:([0-9.-]+)E:([0-9.-]+)"
    template: "Position: X={0}, Y={1}, Z={2}, E={3}"
  - name: Power
    type: section
    children:
    - name: Turn on PSU
      type: command
      command: M42 S255 P30
    - name: Turn off PSU
      type: command
      command: M42 S0 P30
  - name: Z Commands
    type: section
    children:
    - name: Set Z10
      type: command
      command: G92 Z10
    - name: Goto Z10
      type: command
      command: G0 Z10

Controlling an ATX power supply (PSU) with a transistor

I have recently built a 3D printer. Yay me!

It is running OctoPrint which allows my 3D printer to be web accessible.

This is great except that as it stands I need to telephone my good lady Wife should I need to print anything while I am out – which surprisingly happens quite frequently – so she can turn on the PSU to allow me to print.

I use a standard ATX power supply to run my printer and wondered if I could use my printer’s control board (a sanguinololu) and a spare pin to turn on the PSU. It turns out that I can.
M42
Example: M42 P7 S255
M42 switches a general purpose I/O pin. Use M42 Px Sy to set pin x to value y, when omitting Px the LEDPIN will be used.

I have connected the control wire to pin A1 on the sanguinololu board, so to turn on and off the PSU I send:
To turn on:

M42 S255 P30

To turn off:

M42 S0 P30

The circuit I am using to turn the PSU on is as follows:
BC184L NPN Transistor

  []
 /|\
1 2 3
1 Emitter
2 Collector
3 Base

Connect Emitter (Pin 1) to Ground
Connect Collector (pin 2) to PS_ON (Green wire on ATX PSU)
Connect Base (Pin 3) to the pin you will be using on your control board via a 1KOhm resistor
[EMITTER>---GND
[COLLECTOR>---<PS_ON]
[DATA_PIN>---[1K]—[BASE>
I have colour coded the wires on my version to make identification easier:
Data pin: Blue wire
Emitter: Black wire
Collector: Green wire

Once you have soldered up your transistor and heatshrinked the legs for protection you can test the circuit just using the PSU by connecting the green and black wires as normal and using the 5VSB (purple) line to emulate the data line.
Connect the blue wire to the purple wire and the PSU should power up. Remove the blue wire and the PSU should power down.

Some PSUs require a load on the 5V line before they will power up, just connect a CD-ROM or (my preferred method) rewire a 12 volt fan so it is connected to the 5v line instead of the 12v line and plug that in.

212.3.208.65

I hope you are enjoying #algorithm :)

I guess you got here because you searched for the IP address 212.3.208.65 while watching algorithm.

What do you think so far?

Will they get together or has he spent too long in the Friend Zone?

Did you spot the camera crew in the black room reflected in the lightshade before it was turned on or in the aluminium foil in the same location?

Feel free to leave your comments about the movie :)

ArachnidLabs MiniShift arduino – the coding continues

So far I have modified my code to use control codes:
~b: display byte eg ~bf0 to show 11110000 on the display
~c: display character eg ~c41 to show ‘A’ (ASCII character 0×41) on the display
~i: invert data sent to the display eg ~i1
~m: display bytes in MSB or LSB order eg ~m0
~s: set speed between bytes sent eg ~s30 to leave a 30ms gap between bytes
~ : add trailing space after message eg ~ 1 to add trailing space
~~: display ~ character eg ~~

The serial port is set to run at 115200bps in this code to ensure data is transmitted in a timely manner.

As always, this is a work in progress and will grow as I think of more features.
file: minishift_text.ino

//Sample code to display text on the @ArachnidLabs minishift
// Written by Gregory Fenton, http://labby.co.uk

/*
Wiring:
 latchPin connected to CS   (pin 4) of minishift
 clockPin connected to SCK  (pin 3) of minishift
 dataPin  connected to MOSI (pin 5) of minishift
 */

#include "ascii8x8.c" // 8x8 font from PC

byte latchPin = 4;//53;
byte clockPin = 3;//52;
byte dataPin = 5;//51;

byte invert = 0;
byte interCharDelay = 50;
byte msb = 1;
byte showSpace = 0;

char s[257] =  { "~s32~b01~b02~b04~b08~b10~b20~b40~b80~b40~b20~b10~b08~b04~b02" }; //"ArachnidLabs minishift example by Gregory Fenton, labby.co.uk";

int hexToNybble(byte b)
{
        int p;
        if((b < '0' || b > '9') && (b < 'A' || b > 'F') && (b < 'a' || b > 'f'))
                return 0;
                
        p = b - 48;
        if(p > 9)
        {
                p -= 7;
                if(p > 15)
                        p -= 32;
        }
        return p;
}

void displayByte(byte b)
{
        digitalWrite(latchPin, LOW);
        shiftOut(dataPin, clockPin, msb == 0 ? LSBFIRST : MSBFIRST, b);
        digitalWrite(latchPin, HIGH);
}

void displayChar(byte c)
{
        byte i;
        for(i = 0 ; i < 8; i++)
        {
                displayByte(invert ? 255 - pgm_read_byte(font+(c * 8) + i) : pgm_read_byte(font+(c * 8) + i));
                delay(interCharDelay);
        }
}

void setup() {
        Serial.begin(115200);
        int i;
        //set pins to output because they are addressed in the main loop
        pinMode(latchPin, OUTPUT);
        pinMode(clockPin, OUTPUT);
        pinMode(dataPin, OUTPUT);

        //clear display by sending 256 blank bytes
        //256 is arbitrary and should be changed to the number of
        //columns in your display
        //sprintf(s, "Greg");
}

void loop() {
        int i = 0, l;
        byte m, n, o, p;
        char c;

        while(Serial.available())
        {
                c = Serial.read();
                s[i++] = c;
                if(!Serial.available() || i == 256)
                {

                        Serial.flush();
                        s[i++] = 0;
                        Serial.println(s);
                }
        }

        for(i = 0; s[i] != 0 && i < 256; i++);
        l = i - 1;

        for(i = 0; i <= l; i++)
        {
                o = 255;
                if(s[i] == '~')
                {       
                        if(i < l - 1)
                        {
                                m = s[i + 1];
                                n = s[i + 2];
                                switch(m)
                                {
                                case ' ': //Show trailing space
                                        showSpace = n & 1;
                                        o = 0;
                                        break;
                                case 'S': //set speed
                                case 's':
                                        o = s[i + 3];
                                        i++;
                                        interCharDelay = hexToNybble(n) * 16 + hexToNybble(o);
                                        o = 0;
                                        break;
                                case 'I': //invert
                                case 'i':
                                        invert = n & 1;
                                        o = 0;
                                        break;
                                case 'M': //MSB
                                case 'm':
                                        msb = n & 1;
                                        o = 0;
                                        break;
                                case '~': //Display ~ character
                                        displayChar(s[i--]);
                                        o = 0;
                                        break;
                                case 'C': // Display character
                                case 'c':
                                        o = s[i + 3];
                                        i++;
                                        if(((n >= '0' && n <= '9') || (n >= 'A' && n <= 'F') || (n >= 'a' && n <= 'f')) && ((o >= '0' && o <= '9') || (o >= 'A' && o <= 'F') || (o >= 'a' && o <= 'f')))
                                        {
                                                p = hexToNybble(n) * 16 + hexToNybble(o);
                                                displayChar(p);
                                        }
                                        o = 0;
                                        break;
                                case 'B': // Display byte
                                case 'b':
                                        o = s[i + 3];
                                        i++;
                                        if(((n >= '0' && n <= '9') || (n >= 'A' && n <= 'F') || (n >= 'a' && n <= 'f')) && ((o >= '0' && o <= '9') || (o >= 'A' && o <= 'F') || (o >= 'a' && o <= 'f')))
                                        {
                                                p = hexToNybble(n) * 16 + hexToNybble(o);
                                                displayByte(p);
                                                delay(interCharDelay);
                                        }
                                        o = 0;
                                        break;
                                }
                        }
                        if(i >= l)
                                i = 0;
                }
                if(o == 255)
                        displayChar(s[i]);
                else
                        i += 2;
                if(Serial.available())
                        break;
        }
        if(showSpace)
                displayChar(' ');
}

File: ascii8x8.c

#ifndef FONT8X8_H
#define FONT8X8_H

#ifdef __AVR__
 #include 
 #include 
#else
 #define PROGMEM
#endif

// Standard ASCII 8x8 font

static const unsigned char font[] PROGMEM = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0
	0x7E, 0x81, 0x95, 0xB1, 0xB1, 0x95, 0x81, 0x7E,
	0x7E, 0xFF, 0xEB, 0xCF, 0xCF, 0xEB, 0xFF, 0x7E,
	0x0E, 0x1F, 0x3F, 0x7E, 0x3F, 0x1F, 0x0E, 0x00,
	0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, 0x00,
	0x38, 0x3A, 0x9F, 0xFF, 0x9F, 0x3A, 0x38, 0x00,
	0x10, 0x38, 0xBC, 0xFF, 0xBC, 0x38, 0x10, 0x00,
	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
	0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
	0x70, 0xF8, 0x88, 0x88, 0xFD, 0x7F, 0x07, 0x0F,
	0x00, 0x4E, 0x5F, 0xF1, 0xF1, 0x5F, 0x4E, 0x00,
	0xC0, 0xE0, 0xFF, 0x7F, 0x05, 0x05, 0x07, 0x07,
	0xC0, 0xFF, 0x7F, 0x05, 0x05, 0x65, 0x7F, 0x3F,
	0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
	0x7F, 0x3E, 0x3E, 0x1C, 0x1C, 0x08, 0x08, 0x00,
	0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x3E, 0x7F, 0x00,
	0x00, 0x24, 0x66, 0xFF, 0xFF, 0x66, 0x24, 0x00,
	0x00, 0x5F, 0x5F, 0x00, 0x00, 0x5F, 0x5F, 0x00,
	0x06, 0x0F, 0x09, 0x7F, 0x7F, 0x01, 0x7F, 0x7F,
	0xDA, 0xBF, 0xA5, 0xA5, 0xFD, 0x59, 0x03, 0x02,
	0x00, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x00,
	0x80, 0x94, 0xB6, 0xFF, 0xFF, 0xB6, 0x94, 0x80,
	0x00, 0x04, 0x06, 0x7F, 0x7F, 0x06, 0x04, 0x00,
	0x00, 0x10, 0x30, 0x7F, 0x7F, 0x30, 0x10, 0x00,
	0x08, 0x08, 0x08, 0x2A, 0x3E, 0x1C, 0x08, 0x00,
	0x08, 0x1C, 0x3E, 0x2A, 0x08, 0x08, 0x08, 0x00,
	0x3C, 0x3C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00,
	0x08, 0x1C, 0x3E, 0x08, 0x08, 0x3E, 0x1C, 0x08,
	0x30, 0x38, 0x3C, 0x3E, 0x3E, 0x3C, 0x38, 0x30,
	0x06, 0x0E, 0x1E, 0x3E, 0x3E, 0x1E, 0x0E, 0x06,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32 ' '
	0x00, 0x06, 0x5F, 0x5F, 0x06, 0x00, 0x00, 0x00,
	0x00, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, 0x00,
	0x14, 0x7F, 0x7F, 0x14, 0x7F, 0x7F, 0x14, 0x00,
	0x24, 0x2E, 0x6B, 0x6B, 0x3A, 0x12, 0x00, 0x00,
	0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00,
	0x30, 0x7A, 0x4F, 0x5D, 0x37, 0x7A, 0x48, 0x00,
	0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x1C, 0x3E, 0x63, 0x41, 0x00, 0x00, 0x00,
	0x00, 0x41, 0x63, 0x3E, 0x1C, 0x00, 0x00, 0x00,
	0x08, 0x2A, 0x3E, 0x1C, 0x1C, 0x3E, 0x2A, 0x08,
	0x08, 0x08, 0x3E, 0x3E, 0x08, 0x08, 0x00, 0x00,
	0x00, 0xA0, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00,
	0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
	0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00,
	0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00,
	0x3E, 0x7F, 0x59, 0x4D, 0x7F, 0x3E, 0x00, 0x00,
	0x42, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, 0x00,
	0x62, 0x73, 0x59, 0x49, 0x6F, 0x66, 0x00, 0x00,
	0x22, 0x63, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00,
	0x18, 0x1C, 0x16, 0x13, 0x7F, 0x7F, 0x10, 0x00,
	0x27, 0x67, 0x45, 0x45, 0x7D, 0x39, 0x00, 0x00,
	0x3C, 0x7E, 0x4B, 0x49, 0x79, 0x30, 0x00, 0x00,
	0x03, 0x63, 0x71, 0x19, 0x0F, 0x07, 0x00, 0x00,
	0x36, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00,
	0x06, 0x4F, 0x49, 0x69, 0x3F, 0x1E, 0x00, 0x00,
	0x00, 0x00, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00,
	0x00, 0xA0, 0xEC, 0x6C, 0x00, 0x00, 0x00, 0x00,
	0x08, 0x1C, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00,
	0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00,
	0x00, 0x41, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00,
	0x02, 0x03, 0x51, 0x59, 0x0F, 0x06, 0x00, 0x00,
	0x3E, 0x7F, 0x41, 0x5D, 0x5D, 0x1F, 0x1E, 0x00, // 64
	0x7C, 0x7E, 0x13, 0x13, 0x7E, 0x7C, 0x00, 0x00, // 65 'A'
	0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00,
	0x1C, 0x3E, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00,
	0x41, 0x7F, 0x7F, 0x41, 0x63, 0x7F, 0x1C, 0x00,
	0x41, 0x7F, 0x7F, 0x49, 0x5D, 0x41, 0x63, 0x00,
	0x41, 0x7F, 0x7F, 0x49, 0x1D, 0x01, 0x03, 0x00,
	0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00,
	0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00,
	0x00, 0x41, 0x7F, 0x7F, 0x41, 0x00, 0x00, 0x00,
	0x30, 0x70, 0x40, 0x41, 0x7F, 0x3F, 0x01, 0x00,
	0x41, 0x7F, 0x7F, 0x08, 0x1C, 0x77, 0x63, 0x00,
	0x41, 0x7F, 0x7F, 0x41, 0x40, 0x60, 0x70, 0x00,
	0x7F, 0x7F, 0x06, 0x0C, 0x06, 0x7F, 0x7F, 0x00,
	0x7F, 0x7F, 0x06, 0x0C, 0x18, 0x7F, 0x7F, 0x00,
	0x1C, 0x3E, 0x63, 0x41, 0x63, 0x3E, 0x1C, 0x00,
	0x41, 0x7F, 0x7F, 0x49, 0x09, 0x0F, 0x06, 0x00,
	0x1E, 0x3F, 0x21, 0x71, 0x7F, 0x5E, 0x00, 0x00,
	0x41, 0x7F, 0x7F, 0x19, 0x39, 0x6F, 0x46, 0x00,
	0x26, 0x67, 0x4D, 0x59, 0x7B, 0x32, 0x00, 0x00,
	0x03, 0x41, 0x7F, 0x7F, 0x41, 0x03, 0x00, 0x00,
	0x7F, 0x7F, 0x40, 0x40, 0x7F, 0x7F, 0x00, 0x00,
	0x1F, 0x3F, 0x60, 0x60, 0x3F, 0x1F, 0x00, 0x00,
	0x7F, 0x7F, 0x30, 0x18, 0x30, 0x7F, 0x7F, 0x00,
	0x63, 0x77, 0x1C, 0x08, 0x1C, 0x77, 0x63, 0x00,
	0x07, 0x4F, 0x78, 0x78, 0x4F, 0x07, 0x00, 0x00,
	0x67, 0x73, 0x59, 0x4D, 0x47, 0x63, 0x71, 0x00,
	0x00, 0x7F, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00,
	0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00,
	0x00, 0x41, 0x41, 0x7F, 0x7F, 0x00, 0x00, 0x00,
	0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00,
	0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
	0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00,
	0x20, 0x74, 0x54, 0x54, 0x3C, 0x78, 0x40, 0x00,
	0x41, 0x3F, 0x7F, 0x44, 0x44, 0x7C, 0x38, 0x00,
	0x38, 0x7C, 0x44, 0x44, 0x6C, 0x28, 0x00, 0x00,
	0x30, 0x78, 0x48, 0x49, 0x3F, 0x7F, 0x40, 0x00,
	0x38, 0x7C, 0x54, 0x54, 0x5C, 0x18, 0x00, 0x00,
	0x48, 0x7E, 0x7F, 0x49, 0x03, 0x02, 0x00, 0x00,
	0x98, 0xBC, 0xA4, 0xA4, 0xF8, 0x7C, 0x04, 0x00,
	0x41, 0x7F, 0x7F, 0x08, 0x04, 0x7C, 0x78, 0x00,
	0x00, 0x44, 0x7D, 0x7D, 0x40, 0x00, 0x00, 0x00,
	0x40, 0xC4, 0x84, 0xFD, 0x7D, 0x00, 0x00, 0x00,
	0x41, 0x7F, 0x7F, 0x10, 0x38, 0x6C, 0x44, 0x00,
	0x00, 0x41, 0x7F, 0x7F, 0x40, 0x00, 0x00, 0x00,
	0x7C, 0x7C, 0x0C, 0x18, 0x0C, 0x7C, 0x78, 0x00,
	0x7C, 0x7C, 0x04, 0x04, 0x7C, 0x78, 0x00, 0x00,
	0x38, 0x7C, 0x44, 0x44, 0x7C, 0x38, 0x00, 0x00,
	0x84, 0xFC, 0xF8, 0xA4, 0x24, 0x3C, 0x18, 0x00,
	0x18, 0x3C, 0x24, 0xA4, 0xF8, 0xFC, 0x84, 0x00,
	0x44, 0x7C, 0x78, 0x44, 0x1C, 0x18, 0x00, 0x00,
	0x48, 0x5C, 0x54, 0x54, 0x74, 0x24, 0x00, 0x00,
	0x00, 0x04, 0x3E, 0x7F, 0x44, 0x24, 0x00, 0x00,
	0x3C, 0x7C, 0x40, 0x40, 0x3C, 0x7C, 0x40, 0x00,
	0x1C, 0x3C, 0x60, 0x60, 0x3C, 0x1C, 0x00, 0x00,
	0x3C, 0x7C, 0x60, 0x30, 0x60, 0x7C, 0x3C, 0x00,
	0x44, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0x44, 0x00,
	0x9C, 0xBC, 0xA0, 0xA0, 0xFC, 0x7C, 0x00, 0x00,
	0x4C, 0x64, 0x74, 0x5C, 0x4C, 0x64, 0x00, 0x00,
	0x08, 0x08, 0x3E, 0x77, 0x41, 0x41, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00,
	0x41, 0x41, 0x77, 0x3E, 0x08, 0x08, 0x00, 0x00,
	0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00,
	0x78, 0x7C, 0x46, 0x43, 0x46, 0x7C, 0x78, 0x00,
	0x0E, 0x9F, 0x91, 0xB1, 0xFB, 0x4A, 0x00, 0x00,
	0x3A, 0x7A, 0x40, 0x40, 0x7A, 0x7A, 0x40, 0x00,
	0x38, 0x7C, 0x54, 0x55, 0x5D, 0x19, 0x00, 0x00,
	0x02, 0x23, 0x75, 0x55, 0x55, 0x7D, 0x7B, 0x42,
	0x21, 0x75, 0x54, 0x54, 0x7D, 0x79, 0x40, 0x00,
	0x21, 0x75, 0x55, 0x54, 0x7C, 0x78, 0x40, 0x00,
	0x20, 0x74, 0x57, 0x57, 0x7C, 0x78, 0x40, 0x00,
	0x18, 0x3C, 0xA4, 0xA4, 0xA4, 0xE4, 0x40, 0x00,
	0x02, 0x3B, 0x7D, 0x55, 0x55, 0x5D, 0x1B, 0x02,
	0x39, 0x7D, 0x54, 0x54, 0x5D, 0x19, 0x00, 0x00,
	0x39, 0x7D, 0x55, 0x54, 0x5C, 0x18, 0x00, 0x00,
	0x01, 0x45, 0x7C, 0x7C, 0x41, 0x01, 0x00, 0x00,
	0x02, 0x03, 0x45, 0x7D, 0x7D, 0x43, 0x02, 0x00,
	0x01, 0x45, 0x7D, 0x7C, 0x40, 0x00, 0x00, 0x00,
	0x79, 0x7D, 0x26, 0x26, 0x7D, 0x79, 0x00, 0x00,
	0x70, 0x78, 0x2B, 0x2B, 0x78, 0x70, 0x00, 0x00,
	0x44, 0x7C, 0x7C, 0x55, 0x55, 0x45, 0x00, 0x00,
	0x20, 0x74, 0x54, 0x54, 0x7C, 0x7C, 0x54, 0x54,
	0x7C, 0x7E, 0x0B, 0x09, 0x7F, 0x7F, 0x49, 0x00,
	0x32, 0x7B, 0x49, 0x49, 0x7B, 0x32, 0x00, 0x00,
	0x32, 0x7A, 0x48, 0x48, 0x7A, 0x32, 0x00, 0x00,
	0x32, 0x7A, 0x4A, 0x48, 0x78, 0x30, 0x00, 0x00,
	0x3A, 0x7B, 0x41, 0x41, 0x7B, 0x7A, 0x40, 0x00,
	0x3A, 0x7A, 0x42, 0x40, 0x78, 0x78, 0x40, 0x00,
	0xBA, 0xBA, 0xA0, 0xA0, 0xFA, 0x7A, 0x00, 0x00,
	0x19, 0x3D, 0x66, 0x66, 0x66, 0x3D, 0x19, 0x00,
	0x3D, 0x7D, 0x40, 0x40, 0x7D, 0x3D, 0x00, 0x00,
	0x18, 0x3C, 0x24, 0xE7, 0xE7, 0x24, 0x24, 0x00,
	0x68, 0x7E, 0x7F, 0x49, 0x43, 0x66, 0x20, 0x00,
	0x2B, 0x2F, 0x7C, 0x7C, 0x2F, 0x2B, 0x00, 0x00,
	0x7F, 0x7F, 0x09, 0x2F, 0xF6, 0xF8, 0xA0, 0x00,
	0x40, 0xC8, 0x88, 0xFE, 0x7F, 0x09, 0x0B, 0x02,
	0x20, 0x74, 0x54, 0x55, 0x7D, 0x79, 0x40, 0x00,
	0x00, 0x44, 0x7D, 0x7D, 0x41, 0x00, 0x00, 0x00,
	0x30, 0x78, 0x48, 0x4A, 0x7A, 0x32, 0x00, 0x00,
	0x38, 0x78, 0x40, 0x42, 0x7A, 0x7A, 0x40, 0x00,
	0x7A, 0x7A, 0x0A, 0x0A, 0x7A, 0x70, 0x00, 0x00,
	0x7D, 0x7D, 0x19, 0x31, 0x7D, 0x7D, 0x00, 0x00,
	0x00, 0x26, 0x2F, 0x29, 0x2F, 0x2F, 0x28, 0x00,
	0x00, 0x26, 0x2F, 0x29, 0x29, 0x2F, 0x26, 0x00,
	0x30, 0x78, 0x4D, 0x45, 0x60, 0x20, 0x00, 0x00,
	0x38, 0x38, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
	0x08, 0x08, 0x08, 0x08, 0x38, 0x38, 0x00, 0x00,
	0x67, 0x37, 0x18, 0xCC, 0xEE, 0xAB, 0xB9, 0x90,
	0x6F, 0x3F, 0x18, 0x4C, 0x66, 0x73, 0xF9, 0xF8,
	0x00, 0x00, 0x60, 0xFA, 0xFA, 0x60, 0x00, 0x00,
	0x08, 0x1C, 0x36, 0x22, 0x08, 0x1C, 0x36, 0x22,
	0x22, 0x36, 0x1C, 0x08, 0x22, 0x36, 0x1C, 0x08,
	0xAA, 0x00, 0x55, 0x00, 0xAA, 0x00, 0x55, 0x00,
	0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
	0x55, 0xFF, 0xAA, 0xFF, 0x55, 0xFF, 0xAA, 0x00,
	0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
	0x10, 0x10, 0x10, 0xFF, 0xFF, 0x00, 0x00, 0x00,
	0x14, 0x14, 0x14, 0xFF, 0xFF, 0x00, 0x00, 0x00,
	0x10, 0x10, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
	0x10, 0x10, 0xF0, 0xF0, 0x10, 0xF0, 0xF0, 0x00,
	0x14, 0x14, 0x14, 0xFC, 0xFC, 0x00, 0x00, 0x00,
	0x14, 0x14, 0xF7, 0xF7, 0x00, 0xFF, 0xFF, 0x00,
	0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x00,
	0x14, 0x14, 0xF4, 0xF4, 0x04, 0xFC, 0xFC, 0x00,
	0x14, 0x14, 0x17, 0x17, 0x10, 0x1F, 0x1F, 0x00,
	0x10, 0x10, 0x1F, 0x1F, 0x10, 0x1F, 0x1F, 0x00,
	0x14, 0x14, 0x14, 0x1F, 0x1F, 0x00, 0x00, 0x00,
	0x10, 0x10, 0x10, 0xF0, 0xF0, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x1F, 0x1F, 0x10, 0x10, 0x10,
	0x10, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10,
	0x10, 0x10, 0x10, 0xF0, 0xF0, 0x10, 0x10, 0x10,
	0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x10,
	0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
	0x10, 0x10, 0x10, 0xFF, 0xFF, 0x10, 0x10, 0x10,
	0x00, 0x00, 0x00, 0xFF, 0xFF, 0x14, 0x14, 0x14,
	0x00, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x10,
	0x00, 0x00, 0x1F, 0x1F, 0x10, 0x17, 0x17, 0x14,
	0x00, 0x00, 0xFC, 0xFC, 0x04, 0xF4, 0xF4, 0x14,
	0x14, 0x14, 0x17, 0x17, 0x10, 0x17, 0x17, 0x14,
	0x14, 0x14, 0xF4, 0xF4, 0x04, 0xF4, 0xF4, 0x14,
	0x00, 0x00, 0xFF, 0xFF, 0x00, 0xF7, 0xF7, 0x14,
	0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
	0x14, 0x14, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0x14,
	0x14, 0x14, 0x14, 0x17, 0x17, 0x14, 0x14, 0x14,
	0x10, 0x10, 0x1F, 0x1F, 0x10, 0x1F, 0x1F, 0x10,
	0x14, 0x14, 0x14, 0xF4, 0xF4, 0x14, 0x14, 0x14,
	0x10, 0x10, 0xF0, 0xF0, 0x10, 0xF0, 0xF0, 0x10,
	0x00, 0x00, 0x1F, 0x1F, 0x10, 0x1F, 0x1F, 0x10,
	0x00, 0x00, 0x00, 0x1F, 0x1F, 0x14, 0x14, 0x14,
	0x00, 0x00, 0x00, 0xFC, 0xFC, 0x14, 0x14, 0x14,
	0x00, 0x00, 0xF0, 0xF0, 0x10, 0xF0, 0xF0, 0x10,
	0x10, 0x10, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0x10,
	0x14, 0x14, 0x14, 0xF7, 0xF7, 0x14, 0x14, 0x14,
	0x10, 0x10, 0x10, 0x1F, 0x1F, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0xF0, 0xF0, 0x10, 0x10, 0x10,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
	0x38, 0x7C, 0x44, 0x6C, 0x38, 0x6C, 0x44, 0x00,
	0xFC, 0xFE, 0x2A, 0x2A, 0x3E, 0x14, 0x00, 0x00,
	0x7E, 0x7E, 0x02, 0x02, 0x02, 0x06, 0x06, 0x00,
	0x02, 0x7E, 0x7E, 0x02, 0x7E, 0x7E, 0x02, 0x00,
	0x41, 0x63, 0x77, 0x5D, 0x49, 0x63, 0x63, 0x00,
	0x38, 0x7C, 0x44, 0x44, 0x7C, 0x3C, 0x04, 0x00,
	0x80, 0xFE, 0x7E, 0x20, 0x20, 0x3E, 0x1E, 0x00,
	0x04, 0x06, 0x02, 0x7E, 0x7C, 0x06, 0x02, 0x00,
	0x99, 0xBD, 0xE7, 0xE7, 0xBD, 0x99, 0x00, 0x00,
	0x1C, 0x3E, 0x6B, 0x49, 0x6B, 0x3E, 0x1C, 0x00,
	0x4C, 0x7E, 0x73, 0x01, 0x73, 0x7E, 0x4C, 0x00,
	0x30, 0x78, 0x4A, 0x4F, 0x7D, 0x39, 0x00, 0x00,
	0x18, 0x3C, 0x24, 0x3C, 0x3C, 0x24, 0x3C, 0x18,
	0x98, 0xFC, 0x64, 0x3C, 0x3E, 0x27, 0x3D, 0x18,
	0x1C, 0x3E, 0x6B, 0x49, 0x49, 0x49, 0x00, 0x00,
	0x7E, 0x7F, 0x01, 0x01, 0x7F, 0x7E, 0x00, 0x00,
	0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x00, 0x00,
	0x44, 0x44, 0x5F, 0x5F, 0x44, 0x44, 0x00, 0x00,
	0x40, 0x51, 0x5B, 0x4E, 0x44, 0x40, 0x00, 0x00,
	0x40, 0x44, 0x4E, 0x5B, 0x51, 0x40, 0x00, 0x00,
	0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x07, 0x06,
	0x60, 0xE0, 0x80, 0xFF, 0x7F, 0x00, 0x00, 0x00,
	0x08, 0x08, 0x6B, 0x6B, 0x08, 0x08, 0x00, 0x00,
	0x24, 0x12, 0x12, 0x36, 0x24, 0x24, 0x12, 0x00,
	0x00, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,
	0x10, 0x30, 0x70, 0xC0, 0xFF, 0xFF, 0x01, 0x01,
	0x00, 0x1F, 0x1F, 0x01, 0x1F, 0x1E, 0x00, 0x00,
	0x00, 0x19, 0x1D, 0x15, 0x17, 0x12, 0x00, 0x00,
	0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
#endif

ArachnidLabs minishift arduino example scrolling text

As an addon from my last post, I have made a scrolling text display system.

It is a work in process and I think I have the logic backwards. I definitely need more boards to stack so I can see it to full effect!
You need to grab Adafruit’s glcdfont.c from https://github.com/adafruit/Adafruit-GFX-Library/raw/master/glcdfont.c

See it running at http://youtu.be/baRenpdT_Ew

edit: Silly me, I had coded it with the board upside down! No wonder my scroll was going the wrong way :P
The code below has been corrected.

file: minishift_text.pde

//Sample code to display text on the @ArachnidLabs minishift
// Written by Gregory Fenton, http://labby.co.uk

/*
Wiring:
latchPin connected to CS   (pin 4) of minishift
clockPin connected to SCK  (pin 3) of minishift
dataPin  connected to MOSI (pin 5) of minishift
*/

#include "glcdfont.c" // Adafruit glcdfont

int latchPin = 2;
int clockPin = 3;
int dataPin = 4;

char s[256] = "ArachnidLabs minishift example by Gregory Fenton, labby.co.uk";

void displayByte(int b)
{
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, b);
    digitalWrite(latchPin, HIGH);
}

void displayChar(int c)
{
  int i;
  if(c > 31 && c < 127)
  {
    for(i = 0; i < 5; i++)
    {
      displayByte(pgm_read_byte(font+(c * 5) + i));
      delay(50);
    }
    displayByte(0);
  }
}

void setup() {
  Serial.begin(9600);
  int i;
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  
  //clear display by sending 256 blank bytes
  //256 is arbitrary and should be changed to the number of
  //columns in your display
  for(i = 0; i < 256; i++)
  {
    displayByte(0);
  }
}

void loop() {
  // Display the numbers 0 to 255 in binary
  int i = 0, l;
  char c;
  
  while(Serial.available())
  {
    c = Serial.read();
    s[i++] = c;
    if(!Serial.available())
    {
      
      Serial.flush();
      s[i++] = 0;
      Serial.println(s);
    }
  }
  
  for(i = 0; s[i] != 0; i++);
  l = i;
  
  for(i = 0; i < l; i++)
  {
    displayChar(s[i]);
    if(Serial.available())
      break;
  }
  displayChar(' ');
}

ArachnidLabs minishift arduino example

The ArachnidLabs minishift is a great little board that I purchased from the UK Maker Faire 2014 from their stand.

I could not find much online about the board, but here is a basic example to show the wiring and display some scrolling binary.

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

http://creativecommons.org/licenses/by-nc-sa/4.0/

Filename: minishift.pde

/*
Sample code to display binary 0..255 on the @ArachnidLabs minishift
Written by Gregory Fenton, http://labby.co.uk
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

http://creativecommons.org/licenses/by-nc-sa/4.0/

Wiring:
5v (or 3.3v) connected to 5v  (pin 1) of minishift
gnd connected to gnd  (pin 2) of minishift
clockPin connected to SCK  (pin 3) of minishift
latchPin connected to CS   (pin 4) of minishift
dataPin  connected to MOSI (pin 5) of minishift
*/

int latchPin = 4;
int clockPin = 3;
int dataPin = 2;

void displayByte(int b)
{
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, b);
    digitalWrite(latchPin, HIGH);
}

void setup() {
  int i;
  //set pins to output because they are addressed in the main loop
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  
  //clear display by sending 256 blank bytes
  //256 is arbitrary and should be changed to the number of
  //columns in your display
  for(i = 0; i < 256; i++)
  {
    displayByte(0);
  }
}

void loop() {
  // Display the numbers 0 to 255 in binary
  int i;
  
  for (i = 0; i < 256; i++)
  {
    displayByte(i);
    delay(50);
  }
} 

PIC18F25K50 breadboard programming under linux

Hi all

This week I have been programming PICs (peripheral interface controller), a small microcontroller. You may have heard of the most popular at the moment, the Arduino.

The PIC I have been working with is the PIC18F25K50 and the low power version of that chip, the PIC18LF25K50.

These chips have onboard USB support, however the software to use the USB stack is currently not working. This will change over time I am sure.

Back to the point of the post.

I have successfully programmed one on a breadboard using the Pickit 3. No doubt I will retask the breadboard and completely forget the schematic which took me the best part of a day to work out.

Here’s the breadboard schematic, including 4 LEDs connected from pins A0-A3:
pic18f25k50 breadboard with 4 LEDs on A0-A3_bb

Be aware that you need to connect pin 1 of the Pickit 3 to the yellow side of the 6-pin header and that pin 6 is not connected.

I have a sketch that flashes the LEDs, if you want me to post the code then let me know.

Twitter API 1.1 update for the candy machine

**************************************
Author’s note:
PLEASE NOTE THAT I NOW USE AN L293 MOTOR DRIVER IC RATHER THAN JUST A TRANSISTOR
PLEASE DO NOT RUN THIS CODE WITHOUT MODIFYING YOUR CIRCUIT TO MATCH

I do this so that I can move the motor forwards for 2 seconds to dispense the candy and then reverse for 1 second which pulls any candy that has not yet fell back inside the machine so it can be moved safely without the candy falling out everywhere.
I will include an updated schematic, as well as the current version of my code in the next day or so. If I forget, feel free to remind me :)
The updated version is pretty cool – it telnets to a networked HP printer and updates the LCD display on the printer with the name of whoever tweeted me :D
A silly but fun hack that could easily be extended or retasked for other uses.
**************************************

I realised that I have not yet updated my blog to show how I have managed to get around the recent change to the way the Twitter API 1.1 works.

The 1.1 API strictly enforces authorization (I know, I spell it authorisation) before you can do a twitter search, previously you could do a basic authentication and it would work.

The way I got around it was to let the candy machine ask my server for the latest tweet and on my server use the ‘t’ package by Erik Michaels-Ober, a utility that allows you to do twitter 1.1 API calls from the command line.

To install t you must first install the prerequisites, which will only take a moment or two.
Once you have the prerequisites installed, you can simply type gem install t and begin the authorisation process.

When you have completed this stage you are almost done. Soon the sweet, sweet taste of Skittles (try the sour ones, the purple ones are out of this world!) will be but a tweet away :)

One thing I had to change is that the www-data user cannot run ‘t’ as $HOME is unset for security which means that there is nowhere for the config file to go. If you use the -P flag you can set the profile location which neatly sidesteps this issue t -P /var/www/.trc (mine isn’t there!)

So for clarity, the process is:
The Arduino asks my server for a web page containing the latest tweet
My server authenticates and queries twitter
If there has been a recent tweet it gets converted to a simple version the Arduino can understand and returned to the Arduino. If not, my server returns

The Arduino parses the returned string, first by size (the returned will be more than 3 characters long if there has been a tweet).
If the string is less than 12 characters long then the Arduino just goes back to the start after a delay.
If the string is 12 or more characters long then we have a tweet.
The first character is always < so we can safely skip that one.
The complete line is composed of the tweet ID, character 0x07 (bell in ASCII, Ctrl-G) the sender eg @gregoryfenton, character 0x07 and the contents of the tweet followed by character 0x7F to mark the end of the line.
I split the string and separate the parts into individual variables so I can do other stuff such as display the sender and message if required.

The server code is:
file: parsetwitter.php

<?php
$needle = "maker_space AND candy";
$tmpfile = "/var/www/lasttweet.php";

@include($tmpfile);

// lasttweet.php will set up the following variables:
// $tID  : ID of last tweet
// $tFrom: twitter ID of sender
// $tMsg : message
if(!isset($tID))
  $tID = "0";
if(!isset($tFrom))
  $tFrom = "";
if(!isset($tMsg))
  $tMsg = "";

$t = "`which t`";

exec("$t -P /var/www/.trc search all \"$needle\" -n 1 -l", $tweets);

$tweet = explode("  ", $tweets[0]);

if($tweet[0] != $tID)
{
    $r = str_replace("\\","\\\\",$tweet);
    $r = str_replace("\"","\\\"",$r);
    $r = str_replace("\$","\\\$",$r);
    $r = str_replace("\`","\\\`",$r);
    $data = "<?php
	      \$tID = \"$r[0]\";
	      \$tFrom = \"$r[2]\";
	      \$tMsg = \"$r[3]\";
	    ?>";
    printf ("<$r[0]%c$r[2]%c$r[3]%c%c", 7, 7, 7, 0x7f);
    file_put_contents($tmpfile, $data);
}
else
{
    printf ("<!%c", 0x7f);
}
?>

Still with me? Here is the Arduino code:

#include <avr/wdt.h>
#include <Ethernet.h>
#include <SPI.h>

////////////////////////////////////////////////////////////////////////
//CONFIGURE
////////////////////////////////////////////////////////////////////////
char server[] = "example.com"; //domain name of the server you will connect to

//The location to go to on the server
//make sure to keep HTTP/1.0 at the end, this is telling it what type of file it is
String location = "/parsetwitter.php HTTP/1.0";


// if need to change the MAC address (Very Rare)
byte mac[] =
{
	0xDE, 0xAD, 0xFA, 0xCE, 0xFA, 0xDE
};
////////////////////////////////////////////////////////////////////////

EthernetClient client;

int tweetPinA = 8, tweetPinB = 9, LED = 13;

char inString[32]; // string for incoming serial data
int stringPos = 0; // string index counter
boolean startRead = false; // is reading?

void setup()
{
	wdt_disable();
	Ethernet.begin(mac);
	Serial.begin(9600);
	pinMode(tweetPinA, OUTPUT);
	digitalWrite(tweetPinA, LOW);
	pinMode(tweetPinB, OUTPUT);
	digitalWrite(tweetPinB, LOW);
	pinMode(LED, OUTPUT);
	digitalWrite(LED, LOW);
	wdt_enable(WDTO_8S);
}

void loop()
{
	int i = 0;
	String pageValue = connectAndRead(); //connect to the server and read the output

	Serial.println(pageValue); //print out the findings.
	
	for(i = 0; i < 3; i++)
	{
		wdt_reset();
		delay(5000); //wait (5x6) seconds before connecting again
	}
}

String connectAndRead()
{
	//connect to the server
	Serial.println("connecting...");

	//port 80 is typical of a www page
	if (client.connect(server, 80))
	{
		wdt_reset();

		Serial.println("connected");
		client.print("GET ");
		client.println(location);
		client.print("HOST: ");
		client.println(server);
		client.println("User-Agent: Candy Machine Tweet Scanner/1.0.1");
		client.println("Connection: close");
		client.println();

		//Connected - Read the page
		wdt_reset();
		return readPage(); //go and read the output
	}
	else
	{
		wdt_reset();
		return "connection failed";
	}

}

String readPage()
{
	//read the page, and capture & return everything between '<' and '>'

	stringPos = 0;
	memset( &inString, 0, 32 ); //clear inString memory

	while(true)
	{
		if (client.available())
		{
			wdt_reset();
			char c = client.read();

			if (c == '<' )
			{
				//'<' is our begining character
				startRead = true; //Ready to start reading the part
			}
			else if(startRead)
			{
				if(c != '>' && stringPos < 16)
				{
					//'>' is our ending character
					inString[stringPos] = c;
					stringPos ++;
				}
				else
				{
					//got what we need here! We can disconnect now
					wdt_reset();
					startRead = false;
					client.stop();
					client.flush();
					Serial.println("disconnecting.");
					if(stringPos > 12) // someone tweeted us!!!
					{
						wdt_reset();
						digitalWrite(LED, HIGH);
						Serial.println("We have received a tweet!");
						digitalWrite(tweetPinA, HIGH);
						digitalWrite(tweetPinB, LOW);
						delay(2000);
						wdt_reset();
						digitalWrite(tweetPinA, LOW);
						digitalWrite(tweetPinB, HIGH);
						delay(1000);
						wdt_reset();
						digitalWrite(tweetPinA, LOW);
						digitalWrite(tweetPinB, LOW);
						digitalWrite(LED, LOW);
					}
					return inString;
				}
			}
		}

	}
}

apache .htaccess ifModule not allowed here fix

I have just spent the best part of a day dealing with a stupid issue in apache.

My error log showed the following text and none of my sites worked, all giving error 500.

/var/www/.htaccess: <IfModule not allowed here

After much googling to no avail I tried something, and it worked.

In the apache2.conf file, add the lines
<Directory /var/www>
AllowOverride All
Options All
</Directory>

Save and restart apache.

I love it when such a big issue is fixed by such a little patch.

© 2009-2014 labby.co.uk All Rights Reserved -- Copyright notice by Blog Copyright