Sunday 31 January 2016

Bluetooth dartboard scoring device

So after doing a bit of "trading" on the darts markets over Xmas and the New Year, it looked like darts could be a fun game. After all, which other game actually requires you to leave the house and go down to the pub for a few hours? With the weather so rubbish in recent weeks, and with petanque (that's french boules to you) regularly being rained off, it seemed like a great idea!

A quick click around on Amazon and thirty quid later, and we've got a spanky new Winmau Blade4 dartboard and a set of Ted Hankey darts on next day delivery!


It didn't take long to get the board set up (in the hallway at Nerd Towers, so make sure you shout or give a whistle if you're coming out of the dining room!) and to get a couple of games played. There's nothing like hitting two fives and a nine to make you feel like you're actually there, at the Lakeside, competing in the WDO finals. Except...

...what would really make it complete would be a massive, comedy sized scoreboard.
We already had some 4" seven-segment LED displays knocking about. Surely it was just a case of hooking them up to a microcontroller and a MAX7219 driver chip and getting them to display 501?


Knowing nothing about the displayed, we did the usual - poke wires at the terminals until something happened! As it turned out, these displays have four LEDs per segment, not just one, so they actually require about 7.2V to get them to light up.

The process was simply a case of applying power to one of the pins, then grounding others, in turn, until a segment lit up. Because the LEDs are - by their very nature - diodes, it didn't matter if we accidentally put the power lead onto a ground pin; diodes don't let current flow the "wrong way" through them, so nothing happened. After a bit of poking about, we discovered that we had some common anode 7-segment displays.




Having checked the datasheet for the MAX7219 driver, we found it could indeed supply larger voltages than the 5v logic for the data. But these chips are designed to work with common cathode displays, not common anode.

We were going to have to come up with an alternative. Straight away, with anything to do with sinking lots of current, we were thinking about a transistor array. And, luckily, in our lucky bag of ICs, we've a load of ULN2803A chips. They're not just 8-way transistor arrays, but they're ideal for sinking up to 500mA of current - at higher voltages than the logic control signals. Perfect!




But each output requires its own input signal, to hold the output low (grounded).
That means with 3 lots of 8 segments, we'd need no less than 24 i/o pins. That's a lot of pins!

Of course, for a 18F4550 or other PIC with a 40-way package, it's not a problem. Those bad boys have pins to spare. But we've an abundance of 16F1829 chips here, which have a 20-pin count. So we thought that perhaps each ULN2803A current sink could have its own shift register, to allow us to activate as many segments as we liked 





So for each 7-segment display, we've now got a shift register, feeding it's outputs to the "input side" of a ULN2803A. The outputs of the transistor array are connected via 100ohm resistors to the cathodes of the segments.

(not shown in this photo are the resistors between the 7-segment cathods and the transistor array outputs - which is why the display is so bright, running at 9v!)


After a bit of quick etching, and drilling lots of holes with our little dremel...


.... we had a PCB ready for populating

(we may have an abudance of 595 shift registers and 2803A transistor arrays, but there's no point wasting them in case the circuit doesn't work - that's why we're still using through-hole components and sockets for fitting things to the PCB!)

The firmware was completed, allowing characters to be sent to each display, via ASCII. Since our bluetooth modules simply convert bluetooth to serial (at 57600bps) as long as we can correctly parse data over serial, there's no reason why they shouldn't work, parsing data sent from a smartphone app.

Here's an early video of displaying data over serial:



Now we're just waiting on a new bluetooth module (and a free afternoon) to finish the scoreboard and put it in pride of place, over the dartboard!

Friday 29 January 2016

Apple is shite too

With the recent postings about Windows 10 being so utterly useless, a few people have suggested alternative operating systems. The trouble is:


  • Linux is hard work

Just to get a printer working with it is difficult. It's not that I'm not particularly "tech-savvy". I know how computers work. I just think it's unnecessarily difficult to get a lot of hardware working with Linux. And anyone who says otherwise is usually a little bit sneery about not understanding which command to use at the terminal line, or which sudo apt get package to install.
And the truth is, they don't understand it either - they're just quicker at getting Google to reveal the answer! That's not knowledge, nor understanding. That's just knowing which key words to throw at a search engine to find how someone else did it. That's a useful skill too. But it's not understanding of the system.



  • Apple is evil

Mac computers - on the face of it - look nice. But the all-encompassing power-crazed embrace that Apple put around their technology makes it really difficult to do anything useful with.
Want to hand over some money to install the latest app from the app store? We'll make that easy for you.
Want to hand over some money to listen to music? That's a doddle.
Want to hand over some money to stand in a queue to have your phone looked at by one of our experts because we won't give you the tools to fix things yourself? We'll make that easy for you.
Want to hand over some money to upgrade part of your hardware or toolchain because we don't think hardware should be inter-operable and only Apple should dictate what talks with what? We'll make that easy.
Want to hand over some money to join our developer programme so you can deploy your own software onto Apple devices? We'll make that easy....

Apple makes giving them money easy.
Everything else on a Mac is really difficult.
Try getting some code running on a tablet or phone.
On Android it's easy: create an apk, install on the device. Done!

Don't even try to compile for iOS on a non-Mac device (I tried it. It's just about possible. But really, really difficult). So to target Apple's operating system, you need to use Apple's hardware. And Apple's XCode toolchain. And create certificates. And provisioning profiles. And ensure the provisioning profile matches exactly the one piece of hardware you've identified you want to put the code on. Then piss around some more with a mix of online (web-based) forms plus some local (application-based) settings, download some files (really, why mix online and offline building methods in the same process??!) and finally you might get your code to compile. To run on just one device.

On top of all this, I recently tried to compile a simple Unity app for an iOS device.
It took exactly four minutes on a Windows machine, from launching Unity, to creating an .apk that I could put onto my Android phone. Easy!

I booted up my Mac Mini that was last switched on over a year ago (which was then used to compile some Flash files into an application for iPhone).

  • I had to upgrade the device firmware.
  • Then I had to re-install Unity.
  • Then I had to download and install a massive 4.3Gb complier for iOS.
  • XCode wasn't up-to-date enough for the new compiler, so I had to upate that.
  • But XCode wouldn't update without upgrading the entire operating system.
  • It took nearly two hours to download and re-install Unity and the iOS compiler.
  • It took over two hours to download and install OS X El Capitan.
  • Then I had to re-install XCode. That took nearly three hours.


Having wasted a day, just to get my Mac up to a spec that Apple approved of, I then had to spend about seventy quid renewing my Apple developer licence. Just to make a bouncing ball go up and down on an iPhone screen.

Microsoft might be rubbish. But that's down to their incompetence.
Apple are evil. Because they actually planned this shit.


WTF is wrong with Windows 10?

At the risk of turning this blog into an anti-Microsoft rant, I'm trying to understand why Windows 10 has become so rubbish. Not just "it's a bit like Windows 8 but with naffer graphics". But it's completely, utterly shite.

(Given the experience I had recently with trying to compile a Unity app on a Mac recently, it's unlikely Microsoft will be the only company getting a roasting for producing crappy, needy, simply-fail-to-work-but-offer-no-way-of-going-back-to-a-working-version operating systems)

Both at home, at work and wherever I found a machine running Windows 10, I got rid of it. All except on one machine - a laptop used for testing development on the latest Microsoft operating system. And sometimes, it doesn't make sense to keep flipping between computers; it seems a bit churlish to say "I hate Windows 10 so much, I'm going to put this laptop down and boot up one of my other machines, just to browse the web or download some pdfs".

But it's got to the stage that that's what's happening!
I tried to download a pdf from a website on my laptop.
Some five minutes after it had downloaded, I went into my downloads folder and tried to move it onto the desktop (so it'd be easy to find when I came to read it later)



This was more than five minutes after the file had finished downloading.
A quick look at the task manager and this appeared


Now task manager used to flash a column red if it hit more than 90% or so. It seems like the latest version of Windows 10 now recognises that this is so common, it doesn't do it any more. The stupid Microsoft "anti-malware" is - to me at least - acting like malware.

It's chewing up almost all of the spare CPU and battering the hard disk.
Which in turn renders the rest of the computer useless, as it slows to a crawl. But more than that - it doesn't just make things "a bit slow" or make the computer a "bit cumbersome" but actively stops me from doing what I want with the bleeding thing - which, in this case, was to download a file and put it on the desktop.

If it wasn't for the fact I have to support legacy apps written on a variety of Windows platforms, I think I'd seriously be considering moving to Linux. All of the new development I do now is for mobile platforms (web, Android and - when I absolutely have to - iOS). I used to be a Windows-only developer but it really does look like Windows has had it's day.

I used to build applications with the view that if the mobile version wasn't available, you could always run it on your PC (after all, mobiles don't let you do cool stuff with hardware like plug into the serial port). But more and more it's obvious that it's the PC that's becoming a niche operating system.

I used to think that the proliferation of mobile devices was strangling the computer industry. After all, a mouse is far superior to a pudgy finger for fine resolution and moving things around a screen. And typing on a keyboard is a million times easier than poking a virtual keypad on a screen. Yet consumers (not necessarily computer users, but the majority of people using their tablets to "consume" data) demand less of their devices and simply point at an icon, saying "I want that one".

But it turns out that it's not the demands of the greater masses that's killed desktop computing. It's the developers of the operating systems that have made them so painful to work with. When every action is followed by a dialogue asking for "administrator permissions" or a boot up time of ten minutes while every background service starts and the proceeds to bring the computer to a crawl, it's no wonder people prefer to pick up a tablet and "just go".

But it doing so, OS developers have been going backwards too. In making their operating systems unusable, they're encouraging us to seek out alternative devices and platforms. Ten years ago, the idea of not using Microsoft Office in some shape or form seemed alien to anyone who had ever used a computer (many users confusing Office with Windows and wondering why their PC at home didn't come the full-blown Outlook by default). Now, Office is just another bit of software that you don't need to buy any more.

Windows is slowly becoming the same thing - it's still currently a popular OS. But it's utterly unusable for anything other than the most menial of tasks. It's slow. It doesn't let you do what you want. Half my (admittedly home-built) hardware doesn't work with it. A lot of old software doesn't run on it (unless you remember to right-click and run as administrator). Compilers and development tools don't work nicely together like they used to. In it's current form, Windows is worse than Linux and - dare I say it - probably Mac.

Microsoft used to make awesome software. Sure, it was expensive. And quite bloated. But it worked well. It let you get on with the job - make whatever you needed to make, using software that let you get on and make stuff. But now, Microsoft software is too slow, too bloated and too demanding. It actively gets in the way of trying to get stuff done. And Microsoft don't even make the best/easiest/most useful operating system either.

Interestingly, whenever "big business" appears in the news, it's always Google, Facebook, Amazon, eBay, Apple, even Starbucks that get the press. No-one even thinks to mention Microsoft.

Let's hope Windows 10 dies just as quickly as Microsoft's profile and we can get back to using our technology to do cool stuff, instead of fighting with it on a daily basis!


Wednesday 27 January 2016

Why is everything - not just iOS - so bloated these days?

Deploying stuff from Unity to Android is a doddle. It's almost drag-n-drop. Create an apk file and hit "build and load" and as if by magic your new app appears on the connected device (provided it's plugged into the USB port, and USB debugging is enabled).

But, in short, it's easy.

Deploying to iOS is a whole different story.
Not least of all because of all the messing about with certificates, provisioning, requests for certificates and all the other junk that goes on. A very good and comprehensive guide to deploying to iOS can be found here - http://gamasutra.com/blogs/ThaleiaDeniozou/20140826/224186/Export_from_Unity_to_an_iOS_Device.php

As we found a few years ago, deploying to an iOS device from anything other than a Mac is real pain. It can be done. We even managed to generate our own developer certificates using a Windows 7 machine, but it involved lots of manual processing and script-bashing to validate Md5-hashes and build files from the ethers.

This time, as we did then, it was just easier to boot up a Mac.
And download the iOS compiler.


As much as we've grown to hate Microsoft (seriously, first .NET, then Windows 10, then the unholy alliance of a .NET Visual Studio hacked onto a Java-based developer-  Unity - running on Windows 10) this just shows that there's no viable alternative.

280Mb vs 4.2Gb?!
I'm not sure that even Apple could justify that amount of bloat....

Monday 25 January 2016

Microsoft, you broke my laptop. Now you broke Unity!

We were just getting familiar with Unity 5 again recently. And even managed to work out how to use Monodevelop and the debugging and stack trace tools properly. Suddenly developing with C# in Unity wasn't the horrible nightmare it once was.

Then I made the mistake of allowing Unity to upgrade when it booted up this afternoon.
I went from v5.1 to v5.3 and in doing so, bloody Unity went and installed Visual Studio.

Now I'm not suggesting Visual Studio is shit. But it is. In fact, anything running on, developed using or in anyway associated with the (now defunct) .NET framework has always been a bit shit. It's like .NET wasn't actually integrated with Windows, and more sat alongside it.

Let's qualify that - it's probably upset a few people already.
But - anyone who knows me, knows I loved VB6 and Visual Studio (pre .NET). It was great. It created small, tight, easy-to-distribute executables. Applications written in VB6 and VC++6 run well and felt like they were "part of" Windows.

Appplications written with .NET invariably didn't like the particular library version you had on your PC and had to download and install a massive 1.2Gb pile of turgid cack which made half the other applications on the computer break. .NET applications are slow. You can visibly see the screen redrawing (with flexi-grids and data-grids particularly). It wasn't just the crappy mix of the Basic and C++ languages that morphed into C#, the poor use of namespaces or the horrid jumble of unnecessary class setters and getters that C# forced onto you, .NET applications just didn't feel "native" to Windows, even when compiled.

If you run software designed for Linux on a Windows machine, you know the experience. It's ok. But it's not native. The Java runtime (or the JVM virtual machine) it runs on makes it just that little bit glitchy. A bit like when Neo spots the flaws in the Matrix.

A bit like when you  drive a Citroen C2 and pretend it's a Mercedes or a BMW. It does the same thing - it goes, and stops, and burns fuel. But it's not the real thing. There's just something not quite the same about it. It doesn't have the same quality. It feels a bit cheap, when you know you've experienced something better (whereas drivers who've only ever had Citroens, or used Linux exlusively probably have no idea what luxurious means).

For me, .NET applications are like that too.
They do the job. But they're a bit crap, compared to what they should (or could) be.

We already know that Windows 10 is a pile of dog crap. So when Unity, running on my last machine to be running Windows 10, said it was installing Visual Studio, I knew trouble was ahead.

What I can't understand is how, as technology advances and computers supposedly get more powerful, instead of getting better, everything becomes just a little bit more.... well, shit.

When I try to open a file in Unity now, instead of Monodevelop popping up, I get this:


Then after waiting about 20 seconds (in computer terms, that's aaaages) this pops up:


By Microsoft's crappy timing standards, anything they say could take a few minutes is likely to take up to half an hour! As it turns out, I waited nine minutes (I know it took that long as I checked my phone before I left the room, made a brew, went for a sandwich, got back, then received a text - checking the time on the phone again). After nine minutes, nothing had changed.

Except in the taskbar, another application had tried to start and failed.


It wasn't even Visual Studio. It was Monodevelop. Except, somehow, Visual Studio had made it break. Unbelievable! After closing the dialog and making changes to my source code, I flicked back to Unity


The dialog box wouldn't go away.
I had to Task-Manager-End-Task to get it go.
It's broken my install of Unity on my laptop. I don't want Visual Studio on my machine. I'm not even sure I want Windows any more. I can't believe that Microsoft have managed to get things so spectacularly wrong. I even defended Windows 8. But this is a step too far.

It's also been the kick in the pants I needed, to wipe my laptop and go for a fresh factory reset. So I can re-install Windows 7 and Unity 5, and hunt down and uncheck any options to install Visual Studio when I install Unity next time!

Friday 22 January 2016

Talking to Bluetooth LE devices with Unity 5

In recent months, a few of us have been playing about with Unity. Steve is the master of playing about with stuff. He takes a prefab or shop-bought asset and kicks it about until it just does what he insists it should, through sheer dogged determined willpower. Scropp, like me, takes a slower, more in-depth view of how it works; maybe taking a bit longer to get there, but ultimately having a deeper understanding of how it all works.

That's not to say that either approach is correct, nor that any approach is wrong.
But after playing about with an existing BTLE plug-in from the Asset store(https://www.assetstore.unity3d.com/en/#!/content/26661) I was getting frustrated at being unable to "hack" the existing demo project to do what I wanted it to.


Firstly, it's written in about a million pieces, with classes referencing classes, and references to other Unity scripts (this is a bit of a weird idea for me - where a variable is declared globally, but not actually assigned in code, and simply drag-and-dropped into place using the Unity visual editor).

Secondly, the example script is difficult to follow easily. There are loads of panels and assets that are clearly of no use for most projects (they're included to demonstrate how flexible the plug-in can be with different types of hardware, but you'd never use all of them in the same project). But simply removing assets you don't want causes references to scripts that may or may not be needed to break, and the script stops compiling.

Trying to trace these back and find which reference to which no-longer-needed bit (especially when the reference is placed in the Unity editor and doesn't actually appear in the code anyway) burned a whole day. Sometimes hacking Unity example code can feel a little bit like using Arduino libraries.
With enough perseverance, you can get something to work. But that's about it - really getting it to do what you want instead of having to put up with how it works is about the best you can hope for. I didn't like that idea with my Unity project, so was determined to use the core library for the bluetooth communication, but build my own interface, from a blank Unity Project.

Here's how I did it.

Firstly, import the bluetooth LE library (for iOS and Android - let's build to multiple platforms from the same source code!) Then go into the assets folder and get rid of pretty much most of it!


I kept the plugins folder intact and got rid of everything else. In the screenshot above, the sprites folder remains, but it doesn't actually contain anything! The prefabs folder contains my own prefab (explained later) and the original prefab that came with the demo has been removed. Basically get rid of everything except the contents of the plugins folder.

I created two panels - one shall be the screen when the app first starts, listing all the available bluetooth devices in range, then when one is selected, the app will connect and display the "connected" panel (which is a simple interface for us to send and receive strings of text but you can make yours do pretty much anything you like!)

In the editor they are placed over the top of each other, but in the screenshot have been separated out so you can see the entire hierarchy. I tend to make my panels obviously different colours during development so that you can see which panel is supposed to be showing at any one time.


Unlike the original demo, we're going to shove everything into a single class. It's not exactly perfect programming practice, but this is a single-developer project, not something that's going to be shared as a library, or developed in tandem with fifteen other developers; my personal feeling is that a multi-classed development approach too early on just over-complicates things, when a few simple function calls and simple procedural processing can help make things much easier to understand (which is really useful when you come back to this in six months and don't have to re-learn how it works all over again!)

A controller script is created and attached to the canvas object. For new Unity users, it's as simple as right-clicking in the project and selecting "new script" and giving it a name, then dragging and dropping it onto the canvas object in the hierarchy view on the left. I called my script, rather cryptically, "controller.cs".

In the start function, simply create a couple of global references to the "scanning" and "connected" panels. Maybe it's a throwback to my embedded development time, but I just find global variables much easier to work with that the constant swapping of references and passing parameters that a fully object-oriented approach requires. Don't listen to what your university lecturer tells you - in the real world, we use global variables. A lot.

Then simply initialise the bluetooth plugin with a single line of code:

BluetoothLEHardwareInterface.Initialize (true, false, () => {}, (error) => {});

And then invoke our scanning routine after about one second (which gives the bluetooth plugin time to initialise properly) using

Invoke("scan",1000);

This simply tells Unity to "run the function called -scan- after one second".
The scan function monitors the bluetooth connection and when a device is within range, it calls the AddPeripheral function, to make the device appear in a list, as a clickable (button) object.

And this is where Unity mixes its programmatic and visual approaches. Personally, I don't like it. But some people love it, so this is how it goes:

The AddPeripheral function creates an instance of a button "prefab" and attaches to a (scrollable) panel. But we don't just say "use this panel" but create a global variable in which we store a reference to the scrollable panel object. Strangely, Unity likes this to be set using the visual editor, rather than entirely programmatically. So we create a global variable, so that the editor can access (and amend) the variable and when the script object is viewed in the editor, we can populate all the public variable values.

In fact we had to create a number of global variables to act as references to objects already in our Unity project

// --------------------------------------------------------
// these objects need to be set in the Unity visual editor
// so they are actually linked to something!
// --------------------------------------------------------
public Transform PanelScrollContents; // the panel on which you'll list the devices
public Text txtDebug; // this is just for testing, can be removed safely
public GameObject connectButton; // the button to click to connect to a device
public Text txtData; // the text box to type in your "send" data
public Text txtReceive; // the text box data is received into (for testing)

And then in the visual editor, linked them to the objects on screen



The last thing to do is create our "device connect" button as a prefab, so that it can be created at runtime in code. To create a prefab in Unity is pretty easy. Create your object on the screen in the main editor window and when you're happy with it, drag-n-drop it into the project space (the panel at the bottom in the middle of the screen) and Unity creates a "prefab" version of the object.

Our button has a very simple script attached to it.
It allows us to set the label of the button and also to retrieve the (mac) address of the device to connect to, when the button is pressed.

using UnityEngine;
using UnityEngine.UI;

public class connectButtonScript : MonoBehaviour {

     public controller controllerScript;
     public Text TextName;
     public Text TextAddress;

     public void onClick () {
          controllerScript.connectTo (TextName.text, TextAddress.text);
     }

     // Use this for initialization
     void Start () {
     
     }
     
     // Update is called once per frame
     void Update () {
     
     }
}

Although it's very simple we have to create three global references.
One is a variable onto which we drop the text label on the button. Another is a (transparent/hidden) text label which we use to store the address. And then we have to store a reference to the script/class that has created/called this one. For over twenty years, I've always hated this approach to programming. But here it is. In the AddPeripheral function, you'll see something like this:

GameObject buttonObject = (GameObject)Instantiate (connectButton);
connectButtonScript script = buttonObject.GetComponent ();
script.TextName.text = name;
script.TextAddress.text = address;
script.controllerScript = this;

That's creating an instance of our button prefab, and saying set the .text property of the global variable TextName to whatever the name of the object you've just clicked on is. The global variable TextName appears in the Unity visual editor and you have to drag and drop the "name" label from the button into the TextName global variable. A horrible way of completing references, but one that works, so let's stick with it for now!

Similarly the global variable TextAddress that was declared in the connectButtonScript.cs file is populated in the Unity visual editor by dragging and dropping the "address" label from the button onto the field.

The controllerScript global variable holds a reference to the script/class that created the button (so when the button is clicked, it can make a callback to the script that created it). In our case, a simple "this" will do - the controller.cs class is simply saying to the buttonScript "I am the controller script that created you".

And with all that in mind, here's the full controller.cs script

using UnityEngine;
using UnityEngine.UI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

public class controller : MonoBehaviour {

   // -------------------------------------------------------------------
   // this project doesn't offer a "scan" and "connect" buttons - it
   // just gets on and does it!
   // So when it runs, it immediately starts scanning and lists all
   // found devices in a list. Click the one you want and it immediately
   // connects without the need to click a "connect" button
   // -------------------------------------------------------------------

   // -----------------------------------------------------------------
   // change these to match the bluetooth device you're connecting to:
   // -----------------------------------------------------------------
   private string _FullUID = "713d****-503e-4c75-ba94-3148f18d941e";
   private string _serviceUUID = "0000";             
   private string _readCharacteristicUUID = "0002";    
   private string _writeCharacteristicUUID = "0003";

   // ---------------------------------------------------------------------
   // if you want to connect to different devices, you *could* take a look
   // at the function [void connectTo] and add in some if statements to
   // change the FullUID pattern to match the device
   // ---------------------------------------------------------------------



   // ----------------------------------------------------------------------
   // the following are public because they need to be set by dragging and
   // dropping the various objects in the Unity editor
   // ----------------------------------------------------------------------
   // --------------------------------------------------------
   // these objects need to be set in the Unity visual editor
   // so they are actually linked to something!
   // --------------------------------------------------------
   public Transform PanelScrollContents;            // the panel on which you'll list the devices
   public Text txtDebug;                        // this is just for testing, can be removed safely
   public GameObject connectButton;               // the button to click to connect to a device
   public Text txtData;                        // the text box to type in your "send" data
   public Text txtReceive;                        // the text box data is received into (for testing)


   // -------------------------------------------------------------
   // leave the rest of this junk alone but edit the couple
   // of functions that send and receive data if you like:
   //
   // sendDataBluetooth('string to send');
   //
   // and when data is received, it's passed into the function:
   //
   // receiveText('string received over bluetooth');
   //
   // so change these functions to do whatever you want them to do
   // and leave all the other stuff alone and it should just work!
   // -------------------------------------------------------------

   public bool isConnected=false;
   private bool _readFound=false;
   private bool _writeFound=false;
   private string _connectedID = null;

   private Dictionary<string, string> _peripheralList;
   private float _subscribingTimeout = 0f;
   private bool _scanning = false;
   private bool _connecting = false;

   private int devicesFound = 0;

   private GameObject panelScan;
   private GameObject panelConnected;
   private GameObject panelSettings;
   

   void connectBluetooth(string addr){
      BluetoothLEHardwareInterface.ConnectToPeripheral (addr, (address) => {
      },
      (address, serviceUUID) => {
      },
      (address, serviceUUID, characteristicUUID) => {
      
         // discovered characteristic
         if (IsEqual (serviceUUID, _serviceUUID)) {
            _connectedID = address;         
            isConnected = true;
         
            if (IsEqual (characteristicUUID, _readCharacteristicUUID)) {
               _readFound = true;
            } else if (IsEqual (characteristicUUID, _writeCharacteristicUUID)) {
               _writeFound = true;
            }

            showConnected();
         }
      }, (address) => {
      
         // this will get called when the device disconnects
         // be aware that this will also get called when the disconnect
         // is called above. both methods get call for the same action
         // this is for backwards compatibility
         isConnected = false;
      });

      _connecting = false;
   }
   
   string FullUUID (string uuid) {
      // this has changed for the BTLE Mini devices
      // return "713d" + uuid + "-503e-4c75-ba94-3148f18d941e";
      return _FullUID.Replace ("****", uuid);
   }
   
   bool IsEqual(string uuid1, string uuid2){
      if (uuid1.Length == 4) {
         uuid1 = FullUUID (uuid1);
      }
      if (uuid2.Length == 4) {
         uuid2 = FullUUID (uuid2);
      }
      return (uuid1.ToUpper().CompareTo(uuid2.ToUpper()) == 0);
   }

   public void connectTo(string sName, string sAddress){
      if (_connecting == false) {
         txtDebug.text += "Connect to " + sName + " " + sAddress + "\n";
         _connecting=true;

         // stop scanning
         BluetoothLEHardwareInterface.StopScan ();
         _scanning = false;

         // connect to selected device
         connectBluetooth (sAddress);
      }
   }

   public void scan(){
      if (_scanning==true) {
         txtDebug.text+="Stop scan\n";
         BluetoothLEHardwareInterface.StopScan ();
         _scanning = false;
      } else {

         txtDebug.text+="Start scan\n";
         RemovePeripherals ();
            
         devicesFound=0;

         // the first callback will only get called the first time this device is seen
         // this is because it gets added to a list in the BluetoothDeviceScript
         // after that only the second callback will get called and only if there is
         // advertising data available
         BluetoothLEHardwareInterface.ScanForPeripheralsWithServices (null, (address, name) => {               
            AddPeripheral (name, address);               
         }, (address, name, rssi, advertisingInfo) => {});
            
         _scanning = true;
      }         
   }


   void RemovePeripherals () {
      for (int i = 0; i < PanelScrollContents.childCount; ++i) {
         GameObject gameObject = PanelScrollContents.GetChild (i).gameObject;
         Destroy (gameObject);
      }
      
      if (_peripheralList != null) {
         _peripheralList.Clear ();
      }
   }
   
   void AddPeripheral (string name, string address){
      if (_peripheralList == null) {
         _peripheralList = new Dictionary<string, string> ();
      }
      if (!_peripheralList.ContainsKey (address)) {

         txtDebug.text+="Found "+name+"\n";
         devicesFound++;

         GameObject buttonObject = (GameObject)Instantiate (connectButton);
         connectButtonScript script = buttonObject.GetComponent<connectButtonScript> ();
         script.TextName.text = name;
         script.TextAddress.text = address;
         script.controllerScript = this;

         // each button is 50 pixels high
         // the container panel is 544 pixels high
         var h = (544 / 2) - (55*devicesFound);

         buttonObject.transform.SetParent (PanelScrollContents);
         buttonObject.transform.localScale = new Vector3 (1f, 1f, 1f);   
         buttonObject.transform.localPosition = new Vector3 (0, h, 0);

         _peripheralList[address] = name;

         txtDebug.text+="Button created\n";
      }
   }

   
   void sendByte (byte value) {
      byte[] data = new byte[] { value };
      BluetoothLEHardwareInterface.WriteCharacteristic (_connectedID, FullUUID (_serviceUUID), FullUUID (_writeCharacteristicUUID), data, data.Length, true, (characteristicUUID) => {         
         BluetoothLEHardwareInterface.Log ("Write Succeeded");
      });
   }
   
   void sendBytesBluetooth (byte[] data) {
      BluetoothLEHardwareInterface.Log (string.Format ("data length: {0} uuid: {1}", data.Length.ToString (), FullUUID (_writeCharacteristicUUID)));
      BluetoothLEHardwareInterface.WriteCharacteristic (_connectedID, FullUUID (_serviceUUID), FullUUID (_writeCharacteristicUUID), data, data.Length, true, (characteristicUUID) => {         
         BluetoothLEHardwareInterface.Log ("Write Succeeded");
      });
   }

   void sendDataBluetooth(string sData){
      if (sData.Length > 0) {
         byte[] bytes = ASCIIEncoding.UTF8.GetBytes (sData);
         if (bytes.Length > 0) {
            sendBytesBluetooth (bytes);
         }      
      }
   }

   void receiveText(string s){
      txtReceive.text += s;
   }

   public void clearReceived(){
      txtReceive.text = "";
   }

   public void sendBluetooth(){
      string sData = txtData.text;
      txtDebug.text+="Sending: "+sData+"\n";
      sendDataBluetooth (sData);
      txtDebug.text += "Sent";
   }

   void disconnect (Action<string> action){
      BluetoothLEHardwareInterface.DisconnectPeripheral (_connectedID, action);
   }

   void showScan(){
      panelSettings.SetActive (false);
      panelConnected.SetActive (false);
      panelScan.SetActive (true);
   }

   void showConnected(){
      panelSettings.SetActive (false);
      panelScan.SetActive (false);
      panelConnected.SetActive (true);
   }

   void showSettings(){
      panelScan.SetActive (false);
      panelConnected.SetActive (false);
      panelSettings.SetActive (true);
   }

   void Initialise(){
      BluetoothLEHardwareInterface.Initialize (true, false, () => {}, (error) => {});
   }
   
   // Use this for initialization
   void Start () {

      panelScan = GameObject.Find ("panelScan");
      panelSettings = GameObject.Find ("panelSettings");
      panelConnected = GameObject.Find ("panelConnected");

      // set up the panels
      showScan ();

      // initialise the bluetooth library
      Initialise ();

      // start scanning after 1 second
      Invoke("scan",1000);
   }



   // Update is called once per frame
   void Update () {
   
      if (_readFound && _writeFound){
         _readFound = false;
         _writeFound = false;         
         _subscribingTimeout = 1f;
      }
      
      if (_subscribingTimeout > 0f){
         _subscribingTimeout -= Time.deltaTime;
         if (_subscribingTimeout <= 0f){
            _subscribingTimeout = 0f;
            
            BluetoothLEHardwareInterface.SubscribeCharacteristicWithDeviceAddress (_connectedID, FullUUID (_serviceUUID), FullUUID (_readCharacteristicUUID), (deviceAddress, notification) => {               
            }, (deviceAddress2, characteristic, data) => {
               
               BluetoothLEHardwareInterface.Log ("id: " + _connectedID);
               if (deviceAddress2.CompareTo (_connectedID) == 0)
               {
                  BluetoothLEHardwareInterface.Log (string.Format ("data length: {0}", data.Length));
                  if (data.Length == 0){
                     // do nothing
                  } else {
                     string s = ASCIIEncoding.UTF8.GetString (data);
                     BluetoothLEHardwareInterface.Log ("data: " + s);
                     receiveText(s);
                  }
               }
               
            });

         }

      }

   }
}

Monday 11 January 2016

Tips for in-play Betfair sports trading

It's only been a few days, but when your own money is on the line, you tend to learn quickly! And after trying a few different markets for different sports, a few of us worked independently and each came to similar conclusions about sports trading.

Firstly, "scalping" is relatively low-risk, but don't expect to get rich quickly!
Scalping involves making lots of "micro-trades", backing and laying quickly.

Secondly, using the Betfair interface for scalping is too cumbersome. Trading software - and in particular using a "ladder view" with one-click order placing is a must for successful trading.


There are quite a few different trading platforms available online, with a baffling array of options, making each quite difficult to use for the novice trader. One piece of software that did simplify things quite nicely was "Traderline".

But with simplicity comes a cost - the software is not exactly stable! It has a tendency to freeze and become unresponsive, just as you're looking to cash in a profit (or, in a worst case scenario, get out of a losing bet!). So a big must for trading is robust, reliable software. (sadly, Traderline is not solid enough to use seriously - which is a shame as it was about the only one we  could understand well enough to actually try trading in the first place).

The screenshot above shows some scenarios we all discussed and formed theories about.
Firstly, its a football game and we're only trading the three possible outcomes - a home win, away win or the draw.

For scalping, you need a market with a lot of liquidity. i.e. one with a lot of money. To make lots of little, fast, trades, you also need there to be a lot of volitility. The prices need to be fluctuating (so you can get in at the top and out at the bottom if backing-then-laying, or in at the bottom and out at the top of the swing if you're laying-before-backing).

We all found that when this game entered half-time, the prices stabilised for about 15 minutes. Normally - for matched betting - that's great news; but for scalping, it's a right pain!

As the image above shows, we have one massive favourite to win the game, one massive underdog, and the chance of a draw relatively low (high odds).

When scalping the favourite, taking a single-tick profit means sneaking 0.01 (or 1%) each time. With a stake of £50, this means a 50p profit each time. If you look at the centre column, you can see when the market shifts, it jumps a massive 0.5 at a time. That means that a single tick swing can earn a lot more profit. But it also means that it takes longer for the market to move 0.5 points (instead of just 0.01). In this example, we've had our bet at 15.5 taken, and we're waiting for the market to move up to 16.0 (to earn us £3.13 profit, instead of the measly 36p-per-tick on the favourite).

However, we only need a single tick swing in the wrong direction, and we're a massive £3.33 down!

The yellow block in the centre column shows that we've got our "back" bet set to 16.0. If that bet gets taken, we'll be £3.13 in profit. The red block in the centre column shows that if the odds fall as low as 14.5, the trading software will automatically place a back bet at 14.5 and accept a loss of £6.90.

In trading, there will always be profitable bets and losing bets.
The trick is to trade sufficient volume that the number of profitable bets is more than the number of losing bets (or if not more in volume, the sum total of the profitable bets needs to be higher than the sum value of the losing bets!)

The problem with trading at such high odds is that each trade takes longer to complete.
And it only takes one or two "bad" trades in the centre column to wipe out twenty or more successful trades on the favourite.

So we all, independently, came to the conclusion that trading on a market that was "evenly balanced" gave more opportunities than one with a massive favourite.

In summary - trade only markets with:

  • Few/limited outcomes (head-to-head games or win/draw/lose only)
  • Lots of money in them
  • Movement in the odds over short periods of time (seconds not minutes)
  • Small difference (0.1 or 0.2) between back and lay odds.

Also, keep an eye on the clock:

  • As the event comes close to half time, activity slows down
  • Towards the end of a game, betting can get erratic, especially on the losing outcomes; avoid these!
  • In football, if the game is tied (or sometimes if the non-favourite has a single goal lead) the odds on a draw will shorten (get less) between half-time and full-time. This can be useful for backing at one set of odds, and laying off just a minute or so later at a tick or two lower. The general trend for the draw result, from half-time towards full-time (especially if the teams are already tied) heads downwards. If the favourite has the lead, this may not hold true.

There are also "trading patterns" to look out for.
The most common one is actually created by traders on the market, and not on the actual sport being played! It's better explained with an example, so here goes....

QPR are trading at around 2.10
In the middle of the game, when not much is actually happening, their price starts to move upwards to around 2.12. A few traders watching this price (note, watching the price, not the game) reckon it's it's likely to keep rising, and so start "laying" QPR (betting they won't win). Sure enough, this becomes a self-fulfilling prophecy - if enough people lay QPR (indicate that they don't think they can win) the back price goes up.

Now, at a price of around 2.16, the price levels off. Traders watching the "trend" have noticed that it's stopped rising and so don't want to risk "laying" QPR,, in case the price starts to come back down. Once again, it's a self-fulfilling prophecy. Once traders stop laying the team, the price stops rising. Once the price stops rising, traders look to cash in their profit and start backing the team to win (remember,lay at a low price, back at a higher price = profit).

As traders start to back the team, the price starts to drop (as the market suggests they're more likely to win, and so the odds on them winning shorten). Other traders watching this price drop now realise that their profits are at risk, and so they also back QPR(at higher odds than they laid the team off) and the price is driven lower.

All this happens without QPR actually doing anything on the football field!

Eventually the price returns to roughly where it started as the traders have either cashed in on their trades to take a bit of profit, or recognise that they've "missed the boat" and decide to leave the team alone. Either way, the end result is a price that yo-yos between two prices.

It's these trades that we're going to focus on in the future....



Sunday 10 January 2016

Betfair trading

After messing about with the Betfair API and getting comfortable with backing and laying sports events as part of  a matched betting strategy, it was only a matter of time before we starting playing about with "sports trading".

Simply put, this is the process of placing a back bet, followed by a lay bet (or vice versa) on a quickly-fluctuating market. It's often called "scalping" and is a technique often used by financial traders.

As we've had the Darts World Championships over Xmas, complete with an overlap (the PDC Darts was running up to New Year and ended on 3rd Jan, while at the same time, the WDO Darts tournament was just getting going). Darts fans are familiar with the players and their form, quality, likelihood of winning and so on. But the great thing about trading is that you don't need to!

Trading is a form of gambling.
Let's get that out there already. It's not risk free. But if you follow a few simple rules, it's also quite easy to make a few quid with a relatively low risk

The first thing to do - particularly while starting out - is stick to a "limited" market; that simply means one with very few outcomes. A tennis game, or - luckily for us at this time of year - a darts match - is a perfect example of  a limited market.

  • There can only be one winner
  • There are only two possible outcomes
  • As one player gains the upper hand, their odds shorten, while the odds on their opponent lengthen

This means that the odds on the players are like a see-saw. As one player's odds go down, the other's go up. They can't both go down - that means that both are more likely to win, which is impossible in a head-to-head challenge (whereas if trading on horses, for example, two or more horses can become the favourites or joint-favourites). Likewise, they can't both "drift" (see their odds go up) at the same time. Odds on the outcome tip from one side to the other.

The other thing to look for in a sports trading event is "liquidity". Simply put, that means money. Look for one with lots of it! It's not uncommon for a popular event - like a darts quarter-final - to have literally millions of pounds traded on it.

More money means faster action. This may be a good thing, or a bad one, depending on how you trade. Personally, I like to trade quickly. Here's an example of a trade:

Phil Taylor started his game at odds of 1.41.
The betting public thought he had a good chance of winning the game.
His opponent took an early lead - but even then, The Power's odds remained low, while his opponent's odds stayed resolutely high. But as the game wore on, Phil's odds sometimes drifted - as far as 1.8 when his opponent had a good set; when Phil got the darts, and looked more likely to win (like a tennis player with serve, a darts player with the darts has an advantage) his odds shortened.

Without putting a back bet, and just as a game started when The Power was throwing second, I placed a lay bet on Phil Taylor when his odds were around 1.5. My reasoning was that his opponent would throw first, score a decent score, and before he even threw his darts, the betting public would see this as a threat and bet in such a way that Phil's odds would grow a little bit.

In trading, the odds don't need to move much. I'm not backing Phil Taylor to lose. At this stage of the game, it still looked like he could win. But I'm not going to leave my lay bet running until the end of the game. I'm just going to put money on Phil to lose at the current odds of 1.50.

Sure enough, the first darts scored 140 and Phil was 501 to 361 down.
The odds on Phil Taylor winning the entire game went up a little bit to 1.55.
I stuck a bet on, backing Phil Taylor to win at 1.55

Now, whether he won or lost, I had locked in a bit of profit.
I'd secured a profit of 155-1.50 = 0.05 or five percent of my bet stake.

As it turned out, I'd only put a bet of a tenner on, so I was 50p up.
But if the stake had been £100, I would have been a fiver to the good.
And all for placing two bets within less than two minutes of each other!
Even though I'd bet a tenner, the full £10 was never at risk. Even if things hadn't gone the way I'd expected, I could always "cash out" the bet early, and take a much lower loss than the full ten pounds.

But that's basically how sports trading works.
Put a bet on, then place another bet on the opposite result when the odds have moved in your favour. The reason the term "scalping" is used, is that in a highly volatile market (such as a head-to-head game with evenly matched players) the odds tend to bounce around a set point.

The odds for one player may be around 1.80
They may drop to 1.78 or even 1.76, or go as high as 1.82 or 1.84, but they tend to gravitate around a fixed point. The trick to scalping is to get in and get out quickly. Place a bet, then place a reverse bet just one or two "ticks" above or below it (depending on which way the market is moving). Take a little profit on lots of bets, rather than a big profit on just a couple.

Why?
Well, I thought trading was easy.
I saw the odds on Phil Taylor bouncing around the 1.66 mark at one point in the match, and stuck a "back bet" when they reached what appeared to be a high point at 1.72. But - because I was trading "blind" (I didn't know what was actually going on in the game, I was just following the money) the odds went up to 1.74, then 1.76, before settling back at 1.72. It turns out that he'd just missed an important double to finish the game. His opponent came on, scored a fantastic "check out", and Phil Taylor's odds shot up to 1.9 (as his opponent's also fell to around 1.98 from the earlier 3.4).

So now I'd backed Phil Taylor at 1.72 but his odds had moved up to 1.9.
The best I could lay the bet at was 1.88 as this became the new "norm" for his odds. Which meant I had to swallow a loss of 1.88-1.72 = 0.16 (or 16% of my bet stake).
As I was betting £10 a time, this was £1.60

Compared to my 50p win earlier, I was now £1.10 down.
Within seconds, trading had gone from really easy money to really quite hard! I had to make three more successful trades like my first one to get back into profit!

I was going to need some help making these trades a little more quickly than through the clumsy betfair interface. What I need is some kind of trading software......