THE EASIEST

Pick-to-Light Integration

Pick-to-Light Code Samples

Because it uses the ultimate standard – a simple web URL

pick-to-light url causes device to light up with two lines of custom text

Pick-to-Light URL Sections

Our Pick-to-Light technology works with your existing ERP or WMS or even Google Docs.  A simple URL request, sent to our server on the Amazon Cloud, causes the associated Pick-to-Light device to light up with the operator’s name, SKU and quantity to pick!

  • Device ID

    Each Pick-to-Light Cloud Display Device has a unique Device ID.

  • Operation Type

    The type of API call. For example: Pick, Flash or Static.

  • Line 1

    Customize the first line to display. It can be anything. We recommend the pickers name, operation, and quantity.

  • Line 2

    Customize the second line to display. It can be anything. We recommend the SKU and perhaps, color.

  • Tempo & Tune

    Each picker can have a custom tune. First number is the tempo, followed by musical notes. ‘f5s,2’ is an F-sharp in the fifth octave held for two beats.

  • Time

    The number of seconds the device will light up.

Code Samples

These code samples will help you integrate the Pick-to-Light devices with your WMS or ERP.  Need a closed-loop system (to confirm picks)?

Very Simple Perl Example using LWP

#
use strict;
use warnings;
use LWP 5.64;

my $browser = LWP::UserAgent->new;
$browser->cookie_jar({});

my $host = 'https://www.sku-keeper.com/'; # the host
$browser->post( $host,
  [
    'name' => 'yourusername', # the log-in ID
    'pass' => 'yourpassword', # the password for the above ID
    'form_id' => 'user_login_block'
  ],
);

$browser->get($host."api/E8D787:72D9D7/pick/hello/there/15,c5,4/10");
$browser->get($host."api/FFFE81:A42B35/pick/hello/there/15,c5,4/10");
$browser->get($host."api/FAAD4B:8E336A/pick/hello/there/15,c5,4/10");
$browser->get($host."api/FF754A:E24C16/pick/hello/there/15,c5,4/10");
$browser->get($host."api/FB9915:C956FC/pick/hello/there/15,c5,4/10");

Java Example with exceptions

File Demo.java


public class Demo {

    public static void main(String[] args)
    {
        try {
            VoodooAPI v = new VoodooAPI();  //create a VoodooAPI object

            v.setUsernameAndPassword("yourusername","yourpassword");
            v.setDeviceID("FAAD4B:8E336A");
            v.setDisplay("hello","there");
            v.setTune("140,c5,1,c5,1,f5,3,p,2,c5,1,f5,1,a5,3");

            v.execute();  //first call will force a login

            v.setDeviceID("FF754A:E24C16");
            v.setDisplay("here's","another");

            v.execute();  //uses the same tune as above

            v.setDeviceID("FB9915:C956FC");
            v.setDisplay("and","another");

            v.execute();  //change only those parameters that you need to

        }
        catch (IllegalArgumentException e) {
            System.out.println ("Illegal Argument Exception, Result = " + e);
        }
        catch (RuntimeException e) {
            System.out.println ("Runtime Exception, Result = " + e);
        }
        catch (Exception e) {
            System.out.println ("Exception, Result = " + e);
        }

    }
}


File VoodooAPI.java


import java.util.*;
import java.net.*;
import java.io.*;

public class VoodooAPI {

    enum operationType {
        display, 
        flash,
        opStatic,
        opStatic2,
        location
    };

    private final String base = "https://www.sku-keeper.com/";
    private String username;
    private String password;
    private String deviceID;
    private String line1;
    private String line2;
    private operationType op = operationType.display;
    private String tune;
    private short time = 10;
    private String txnID;
    private boolean loggedIn = false;
    private List cookies;

    public void VoodooAPI()
    {
    }

    public void setUsernameAndPassword(final String u, final String p)
    {
        username = u;
        password = p;
    }

    public void login() throws Exception
    {
        //make sure there is a username and password set
        if (username=="") {
            throw(new IllegalArgumentException("Username not set"));
        }
        if (password=="") {
            throw(new IllegalArgumentException("Password not set"));
        }

        URLConnection connection = new URL(base).openConnection();
        HttpURLConnection httpConn = (HttpURLConnection)connection;
        httpConn.setInstanceFollowRedirects(false);
        connection.setDoOutput(true); // Triggers POST.
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

        String data="name="+username+"&pass="+password+"&form_id=user_login_block";
        try (OutputStream output = connection.getOutputStream()) {
            output.write(data.getBytes());
        }

        InputStream response = connection.getInputStream();
        cookies = connection.getHeaderFields().get("Set-Cookie");

        loggedIn = true;
    }

    public void execute() throws Exception
    {
        //make sure a deviceID has been set
        if (deviceID=="") {
            throw(new IllegalArgumentException("DeviceID not set"));
        }

        //set up the operation
        String opWord;
        switch (op) {
            case display: opWord = "display";
                break;
            case flash: opWord = "flash";
                break;
            case opStatic: opWord = "static";
                break;
            case opStatic2: opWord = "static2";
                break;
            case location: opWord = "location";
                break;
            default: throw(new IllegalArgumentException("Bad operation"));
        }

        //if there is no tune set, set it to none, which implies silence--not even a beep!
        if (tune=="") {
            tune = "none";
        }

        //are we already logged in?  No need to log in twice.
        if (!loggedIn) {
            login();
        }

        //if we get here and we're not logged in, there is some weird problem
        //I don't think this could really happen, because if there is an error, the login above will
        //throw an exception, and the code below will not execute.
        if (!loggedIn) {
            throw(new RuntimeException("Login failed!"));
        }

        //okay, set up the whole url for the get request
        //see:  https://voodoorobotics.com/constructing-a-url/
        String url = base+"api/"+deviceID+"/"+opWord+"/"+line1+"/"+line2;
        switch (op) {
            case display: 
            case flash: 
                url += "/"+tune+"/"+ Integer.toString(time);
                break;
            case opStatic:
            case opStatic2:
            case location:
        ; //do nothing!
        }

        //if there is a transaction ID for the closed loop, then add it here
        //see: https://voodoorobotics.com/closed-loop-system/
        if (txnID!="") {
            url += "/"+txnID;
        }

        try {
            URLConnection connection = new URL(url).openConnection();
            for (String cookie : cookies) {
                connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
            }
            InputStream response = connection.getInputStream();  //response discarded in this demo!
        }
        catch(Exception e) {
            loggedIn = false;  //if there was a problem, make sure that I'm logged out.
            throw e;
        }

    }

    public void setDeviceID(final String id)
    {
        deviceID = id;
    }

    public void setOperation(final operationType ot)
    {
        op = ot;
    }

    public void setDisplay(final String l1, final String l2)
    {
        line1 = l1;
        line2 = l2;
    }

    public void setTune(final String t)
    {
        tune = t;
    }

    public void setTime(final short t)
    {
        time = t;
    }

    public void setTransactionID(final String txn)
    {
        txnID = txn;
    }

}

C++ Example using libcurl and exceptions

File -- main.cpp:

#include "voodooapi.h"
#include "iostream"
#include "stdexcept"

using namespace std;

int main(int argc, char *argv[])
{
    (void)argc;     //suppress unused variable warning message!
    (void)argv;     //suppress unused variable warning message!

    try {
        VoodooAPI v;  //create a VoodooAPI object on the stack

        v.setUsernameAndPassword("yourname","yourpassword");
        v.setDeviceID("FAAD4B:8E336A");
        v.setDisplay("hello","there");
        v.setTune("140,c5,1,c5,1,f5,3,p,2,c5,1,f5,1,a5,3");

        v.execute();  //first call will force a login

        v.setDeviceID("FF754A:E24C16");
        v.setDisplay("here's","another");

        v.execute();  //uses the same tune as above

        v.setDeviceID("FB9915:C956FC");
        v.setDisplay("and","another");

        v.execute();  //change only those parameters that you need to

    }
    catch (invalid_argument e) {
        cout << e.what() << '\n';
    }
    catch (runtime_error e) {
        cout << e.what() << '\n';
    }

    return 0;
}
--------------------------------------------------------------------------------------------------------------------------------
File -- voodooapi.h:

#ifndef VOODOOAPI_H
#define VOODOOAPI_H

#include "string"
#include "stdexcept"
#include "curl/curl.h"
#include "iostream"


using namespace std;

class VoodooAPI
{
public:
    enum operationType
    {
        display,
        flash,
        opStatic,
        opStatic2,
        location
    };

    VoodooAPI();
    void setUsernameAndPassword(const string &u,const string &p);
    void login();  //login method could be made private--your choice!
    void execute();
    void setDeviceID(const string &id);
    void setOperation(const operationType ot);
    void setDisplay(const string &l1, const string &l2);
    void setTune(const string &t);
    void setTime(short t);
    void setTransactionID(const string &txn);

private:

    const string base = "https://www.sku-keeper.com/";
    string username;
    string password;
    string deviceID;
    string line1;
    string line2;
    operationType op = display;
    string tune;
    short time = 10;
    string txnID;
    CURL * curly = NULL;
};

#endif // VOODOOAPI_H
--------------------------------------------------------------------------------------------------------------------------------
File voodooapi.cpp:

#include "voodooapi.h"

VoodooAPI::VoodooAPI()
{
    //nothing needs to be done here in this example
}

void VoodooAPI::setUsernameAndPassword(const string &u, const string &p)
{
    username = u;
    password = p;
}

void VoodooAPI::login()
{
    //make sure there is a username and password set
    if (username=="") {
        throw(invalid_argument("Username not set"));
    }
    if (password=="") {
        throw(invalid_argument("Password not set"));
    }

    CURLcode res;

    res = curl_global_init(CURL_GLOBAL_ALL);
    if (res!=CURLE_OK) {
        throw(runtime_error(string("CURL curl_global_init failed: ")+curl_easy_strerror(res)));
    }

    curly = curl_easy_init();  //note that curl_global_init is called automatically in curl_easy_init if not called already
    if (!curly) {
        throw(runtime_error("CURL could not initialize"));
    }

    res = curl_easy_setopt(curly, CURLOPT_POST, 1);  //use a post call to login
    if (res!=CURLE_OK) {
        throw(runtime_error(string("CURL failed CURLOPT_POST: ")+curl_easy_strerror(res)));
    }

    string data="name="+username+"&pass="+password+"&form_id=user_login_block";
    //note: user_login_block is found in the HTML of the homepage--check it out!

    res = curl_easy_setopt(curly, CURLOPT_POSTFIELDS, data.c_str());  //make sure to pass the char *, not the string!
    if (res!=CURLE_OK) {
        throw(runtime_error(string("CURL failed CURLOPT_POSTFIELDS: ")+curl_easy_strerror(res)));
    }
    res = curl_easy_setopt(curly, CURLOPT_COOKIEFILE, ""); //enables the cookie engine without initial cookies
    if (res!=CURLE_OK) {
        throw(runtime_error(string("CURL failed CURLOPT_COOKIEFILE: ")+curl_easy_strerror(res)));
    }

    res = curl_easy_setopt(curly, CURLOPT_URL, base.c_str());  //goes to https://www.sku-keeper.com/
    if (res!=CURLE_OK) {
        throw(runtime_error(string("CURL failed CURLOPT_URL: ")+curl_easy_strerror(res)));
    }

    //now that all the parameters are set, let's go...
    res = curl_easy_perform(curly);
    if (res!=CURLE_OK) {
        throw(runtime_error(string("CURL post request failed: ")+curl_easy_strerror(res)));
    }
}

void VoodooAPI::execute()
{
    //make sure a deviceID has been set
    if (deviceID=="") {
        throw(invalid_argument("DeviceID not set"));
    }

    //set up the operation
    string opWord;
    switch (op) {
    case display: opWord = "display";
        break;
    case flash: opWord = "flash";
        break;
    case opStatic: opWord = "static";
        break;
    case opStatic2: opWord = "static2";
        break;
    case location: opWord = "location";
        break;
    default: throw(invalid_argument("Bad operation"));;
    }

    //if there is no tune set, set it to none, which implies silence--not even a beep!
    if (tune=="") {
        tune = "none";
    }

    //are we already logged in?  No need to log in twice.
    if (!curly) {
        login();
    }

    //if we get here and we're not logged in, there is some weird problem
    //I don't think this could really happen, because if there is an error, the login above will
    //throw an exception, and the code below will not execute.
    if (!curly) {
        throw(runtime_error("Login failed!"));
    }

    //okay, set up the whole url for the get request
    //see:  https://voodoorobotics.com/constructing-a-url/
    string url = base+"api/"+deviceID+"/"+opWord+"/"+line1+"/"+line2;
    switch (op) {
    case display: 
    case flash: 
        url += "/"+tune+"/"+to_string(time);
        break;
    case opStatic:
    case opStatic2:
    case location:
        ; //do nothing!
    }

    //if there is a transaction ID for the closed loop, then add it here
    //see: https://voodoorobotics.com/closed-loop-system/
    if (txnID!="") {
        url += "/"+txnID;
    }

    CURLcode res;

    res = curl_easy_setopt(curly, CURLOPT_HTTPGET, 1L);  //make sure we're doing a GET, not a POST
    if (res!=CURLE_OK) {
        curly = NULL;
        throw(runtime_error(string("CURL failed CURLOPT_HTTPGET: ")+curl_easy_strerror(res)));
    }

    res = curl_easy_setopt(curly, CURLOPT_URL, url.c_str());  //don't pass just url.  curl_easy_setopt expects a (char *)
    if (res!=CURLE_OK) {
        curly = NULL;
        throw(runtime_error(string("CURL failed CURLOPT_URL: ")+curl_easy_strerror(res)));
    }

    res = curl_easy_perform(curly);  //Finally, this is where the real action takes place.
    if (res!=CURLE_OK) {
        curly = NULL;
        throw(runtime_error(string("CURL failed get request: ")+curl_easy_strerror(res)));
    }
}

void VoodooAPI::setDeviceID(const string &id)
{
    deviceID = id;
}

void VoodooAPI::setOperation(const operationType ot)
{
    op = ot;
}

void VoodooAPI::setDisplay(const string &l1, const string &l2)
{
    line1 = l1;
    line2 = l2;
}

void VoodooAPI::setTune(const string &t)
{
    tune = t;
}

void VoodooAPI::setTime(short t)
{
    time = t;
}

void VoodooAPI::setTransactionID(const string &txn)
{
    txnID = txn;
}

PHP Example using libcurl

function init() 
{
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL,"https://www.sku-keeper.com/api");
	curl_setopt($ch, CURLOPT_HEADER, 1);
	curl_setopt($ch, CURLOPT_USERAGENT, 'PHP script');
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
	curl_setopt($ch, CURLOPT_COOKIEJAR, "cookie.txt");
	curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookie.txt');
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, "name=yourname&pass=yourpassword&form_id=user_login_block");

	ob_start();      // prevent any output
	curl_exec ($ch); // execute the curl command
	ob_end_clean();  // stop preventing output
	curl_close ($ch);
	unset($ch);

}

function lightDevice($devID,$line1,$line2,$time = 10,$flash = TRUE) {

	if ($flash) {
		$cmd = 'message';
	}
	else {
		$cmd = 'pick';
	}

	$ch = curl_init();
	curl_setopt($ch, CURLOPT_HEADER, 1);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
	curl_setopt($ch, CURLOPT_COOKIEFILE, "cookie.txt");
	curl_setopt($ch, CURLOPT_URL,"https://www.sku-keeper.com/api/$devID/$cmd/$line1/$line2/15,c5,4/$time");

	$buf3 = curl_exec ($ch);

	curl_close ($ch);
}

init();
lightDevice('E8D787:72D9D7','hell','yeah');
lightDevice('FFFE81:A42B35','hell','yeah');
lightDevice('FAAD4B:8E336A','hell','yeah');
lightDevice('FF754A:E24C16','hell','yeah');
lightDevice('FB9915:C956FC','hell','yeah');



Python Example using requests

import requests
session = requests.Session()

def init():

    postData = {
        'name': 'yourusername',
        'pass': 'yourpassword',
        'form_id': 'user_login_block',
        'op': 'Log in'
    }

    loginUrl = 'https://www.sku-keeper.com/api'
    response = session.post(loginUrl, data=postData)

def lightDevice(devID,line1,line2):
    newUrl = 'https://www.sku-keeper.com/api/'+devID+'/message/'+line1+'/'+line2+'/15,c5,4/10'
    response = session.get(newUrl)

init()
lightDevice('E8D787:72D9D7','hell','yeah')
lightDevice('FFFE81:A42B35','hell','yeah')
lightDevice('FAAD4B:8E336A','hell','yeah')
lightDevice('FF754A:E24C16','hell','yeah')
lightDevice('FB9915:C956FC','hell','yeah')

Javascript Example using XMLHttpRequest

var xhr = new XMLHttpRequest();

function init()
{
    xhr.open('POST', 'https://www.sku-keeper.com/api', false);
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.withCredentials = true;
    xhr.send('name=yourname&pass=yourpassword&form_id=user_login_block');
}

function lightDevice(devID,line1,line2,time = 10,flash = TRUE) 
{
    var cmd = '';
    if (flash) {
        cmd = 'message';
    }
    else {
        cmd = 'pick';
    }

    xhr.open('GET','https://www.sku-keeper.com/api/'+devID+'/'+cmd+'/'+line1+'/'+line2+'/15,c5,4/'+time);
    xhr.send();
}

init();
lightDevice('E8D787:72D9D7','hell','yeah');
lightDevice('FFFE81:A42B35','hell','yeah');
lightDevice('FAAD4B:8E336A','hell','yeah');
lightDevice('FF754A:E24C16','hell','yeah');
lightDevice('FB9915:C956FC','hell','yeah');

Google App Script Example using UrlFetchApp

function init()
{
 var formData = {
 'name': 'yourname',
 'pass': 'yourpassword',
 'form_id': 'user_login_block',
 };

 var options = {
 'method' : 'post',
 'payload' : formData,
 'contentType': 'application/x-www-form-urlencoded',
 'muteHttpExceptions': false,
 'followRedirects':false
 };
 var response = UrlFetchApp.fetch('https://www.sku-keeper.com/api', options);

 return response.getAllHeaders()['Set-Cookie'];
}



function lightDevice(devID,line1,line2,time,flash,cookie) 
{
 var cmd = '';
 if (flash) {
 cmd = 'message';
 }
 else {
 cmd = 'pick';
 }
 var options = {
 'muteHttpExceptions': false,
 'headers': {'Cookie':cookie},
 };
 UrlFetchApp.fetch('https://www.sku-keeper.com/api/'+devID+'/'+cmd+'/'+line1+'/'+line2+'/15,c5,4/'+time,options);
}

function go() 
{
 var cookie = init();
 lightDevice('D8927E:C752D3','hell','yeah',10,false,cookie);
 lightDevice('FFFE81:A42B35','hell','yeah',10,false,cookie);
 lightDevice('FAAD4B:8E336A','hell','yeah',10,false,cookie);
 lightDevice('FF754A:E24C16','hell','yeah',10,false,cookie);
 lightDevice('FB9915:C956FC','hell','yeah',10,false,cookie);
}

Visual Basic for Applications Example

Global oRequest As WinHttp.WinHttpRequest

Sub Mainsheet_UpdateURL()
    If ([typ] = "Plain") Then
        tp = "pick"
    Else
        If ([typ] = "Flash") Then
            tp = "message"
        Else
            tp = "static"
        End If
    End If
    

    Dim tid As String
    tid = Application.WorksheetFunction.VLookup([LocationName], Worksheets("TagIDs").Range("A2:B9999"), 2, False)
    
    Dim tun As String
    tun = Application.WorksheetFunction.VLookup([Tune], Worksheets("Tunes").Range("A2:B9999"), 2, False)
    [Constructed_URL] = "https://www.sku-keeper.com/api/" & tid & "/" & tp & "/" & [line1] & "/" & [line2]
    
    If Not ([typ] = "Static") Then
        [Constructed_URL] = [Constructed_URL] & "/" & tun & "/" & CStr([theSeconds])
    End If
        
End Sub
Sub Mainsheet_Change(ByVal Target As Range)
    Dim keycells As Range
    
    Set keycells = Range("c6:c16")
    If Not (Application.Intersect(keycells, Range(Target.Address)) Is Nothing) Then

        Call Mainsheet_UpdateURL
       
    End If
    
    'Changes in UserName or Password resets the connection
    Set keycells = Range("c2:c4")
    If Not Application.Intersect(keycells, Range(Target.Address)) Is Nothing Then

        Set oRequest = Nothing
               
    End If

End Sub
Sub Button2_Click()

    'Static oRequest As WinHttp.WinHttpRequest
      
    'On Error GoTo Err_DoSomeJob
    
    If ([theUser] = "") Then
        MsgBox "Username is required!"
        Exit Sub
    End If
    If ([thePassword] = "") Then
        MsgBox "Password is required!"
        Exit Sub
    End If
    If ([theSeconds] = "") Then
        MsgBox "Please set the number of seconds!"
        Exit Sub
    End If
        
    If (oRequest Is Nothing) Then
        
        loginURL = "https://www.sku-keeper.com/user/login"
        nm = [theUser]
        ps = [thePassword]
        loginBody = "name=" & nm & "&pass=" & ps & "&form_id=user_login&op=Log+in"
        sz = Len(loginBody)
    
        Set oRequest = New WinHttp.WinHttpRequest
        With oRequest
            .Open "POST", loginURL, False
            .SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
            .SetRequestHeader "Content-Length", CStr(sz)
            .Send loginBody
            .WaitForResponse
            sResult = .ResponseText
        End With
    End If
    
    
    sUrl = [Constructed_URL]
    With oRequest
        
        .Open "GET", sUrl, False
        .SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
        .Send "{range:9129370}"
        .WaitForResponse
        sResult = .ResponseText
    
    End With
     
End Sub

C# Example using HttpWebRequest with exceptions

using System;
using System.Collections.Generic;
using System.Net;
using System.Text;  // for class Encoding
using System.IO;    // for StreamReader

namespace CDDDemo
{
    public class IllegalArgumentException: Exception {
        public IllegalArgumentException(string message): base(message) {
        }
    }
    public class RuntimeException: Exception {
        public RuntimeException(string message): base(message) {
        }
    }
    class Program
    {
        static void Main(string[] args)
        {

            try {
                VoodooAPI v = new VoodooAPI();  //create a VoodooAPI object

                v.setUsernameAndPassword("yourusername","yourpassword");
                v.setDeviceID("FAAD4B:8E336A");
                v.setDisplay("hello","there");
                v.setTune("140,c5,1,c5,1,f5,3,p,2,c5,1,f5,1,a5,3");

                v.execute();  //first call will force a login

                v.setDeviceID("FF754A:E24C16");
                v.setDisplay("here's","another");

                v.execute();  //uses the same tune as above

                v.setDeviceID("FB9915:C956FC");
                v.setDisplay("and","another");

                v.execute();  //change only those parameters that you need to

            }
            catch (IllegalArgumentException e) {
                Console.WriteLine("Illegal Argument Exception, Result = " + e);
            }
            catch (RuntimeException e) {
                Console.WriteLine("Runtime Exception, Result = " + e);
            }
            catch (Exception e) {
                Console.WriteLine("Exception, Result = " + e);
            }

        }
        
    }

    public class VoodooAPI
    {

        public enum operationType {
            display, 
            flash,
            opStatic,
            opStatic2,
            location
        };

        private string baseurl = "https://www.sku-keeper.com/";
        private string username;
        private string password;
        private string deviceID;
        private string line1;
        private string line2;
        private operationType op = operationType.display;
        private string tune;
        private short time = 10;
        private string txnID;
        private bool loggedIn = false;
        CookieContainer cookieContainer;

        public VoodooAPI()
        {
            cookieContainer = new CookieContainer();
        }

        public void setUsernameAndPassword(string u, string p)
        {
            username = u;
            password = p;
        }

        public void login()
        {
            //make sure there is a username and password set
            if (username=="") {
                throw(new IllegalArgumentException("Username not set"));
            }
            if (password=="") {
                throw(new IllegalArgumentException("Password not set"));
            }

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(baseurl);
            request.CookieContainer = cookieContainer;
            
            string postData="name="+username+"&pass="+password+"&form_id=user_login_block";
            var data = Encoding.ASCII.GetBytes(postData);

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = data.Length;

            using (var stream = request.GetRequestStream())
            {
                stream.Write(data, 0, data.Length);
            }

            var response = (HttpWebResponse)request.GetResponse();

            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

            loggedIn = true;
        }

        public void execute()
        {
            //make sure a deviceID has been set
            if (deviceID=="") {
                throw(new IllegalArgumentException("DeviceID not set"));
            }

            //set up the operation
            string opWord;
            switch (op) {
                case operationType.display: opWord = "display";
                    break;
                case operationType.flash: opWord = "flash";
                    break;
                case operationType.opStatic: opWord = "static";
                    break;
                case operationType.opStatic2: opWord = "static2";
                    break;
                case operationType.location: opWord = "location";
                    break;
                default: throw(new IllegalArgumentException("Bad operation"));
            }

            //if there is no tune set, set it to none, which implies silence--not even a beep!
            if (tune=="") {
                tune = "none";
            }

            //are we already logged in?  No need to log in twice.
            if (!loggedIn) {
                login();
            }

            //if we get here and we're not logged in, there is some weird problem
            //I don't think this could really happen, because if there is an error, the login above will
            //throw an exception, and the code below will not execute.
            if (!loggedIn) {
                throw(new RuntimeException("Login failed!"));
            }

            //okay, set up the whole url for the get request
            //see:  https://voodoorobotics.com/constructing-a-url/
            string url = baseurl+"api/"+deviceID+"/"+opWord+"/"+line1+"/"+line2;
            switch (op) {
                case operationType.display: 
                    url += "/"+tune+"/"+ time.ToString();
                    break;
                case operationType.flash: 
                    url += "/"+tune+"/"+ time.ToString();
                    break;
                case operationType.opStatic:
                case operationType.opStatic2:
                case operationType.location:
                default:
                    break;
                     //do nothing!
            }

            //if there is a transaction ID for the closed loop, then add it here
            //see: https://voodoorobotics.com/closed-loop-system/
            if (txnID!="") {
                url += "/"+txnID;
            }

            try {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.CookieContainer = cookieContainer;

                var response = (HttpWebResponse)request.GetResponse();

                var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
                  //response discarded in this demo!
            }
            catch(Exception e) {
                loggedIn = false;  //if there was a problem, make sure that I'm logged out.
                throw e;  //rethrow the error
            }

        }

        public void setDeviceID(string id)
        {
            deviceID = id;
        }

        public void setOperation(operationType ot)
        {
            op = ot;
        }

        public void setDisplay(string l1, string l2)
        {
            line1 = l1;
            line2 = l2;
        }

        public void setTune(string t)
        {
            tune = t;
        }

        public void setTime(short t)
        {
            time = t;
        }

        public void setTransactionID(string txn)
        {
            txnID = txn;
        }

    }
}

Unboxing and & Setup

Unboxing Your Order

Voodoo Robotics CEO, Trevor Blumenau, goes through each item that may be included in your order.

Pick-to-Light Devices

Everything you ever wanted to know about batteries, (low) voltages, devices, mounting, device IDs, etc.

Check for the latest in AA battery prices at Slickdeals.

Double-sided tape can be purchased from Home Depot.

Turbos

Turbos connect the pick-to-light devices to the cloud.  They are very easy to set up: just set your connection information and add your username and password. Turbos have a very useful GUI that does a great job helping you debug your system, check radio ranges, test communications, and see device parameters.

Registering Devices

In order to use a pick-to-light device in your account, it has to be registered and paired with a location in your account. This video walks you through the process of getting your devices working in the system.

Using Pick-to-Light with Spreadsheets

Our Pick-to-light system is so flexible and easy to use that you don't have to integrate with a WMS/ERP - you can even use it with Google Sheets or Microsoft Excel.

Google Sheets

Pick-to-Light integration is so simple, you can even use Google Sheets for light-directed picking in any warehouse or distribution center!

Get your copy of the Free Pick-to-Light Spreadsheet and streamline your order fulfillment.

You May Also be Interested in:

Even Microsoft Office can be used to activate our Pick-to-Light devices.  A very simple Excel spreadsheet can be used to construct URLs for lighting up or storing data on the PTL devices.  Just think about it: you could have PTL devices that continuously mirror the content of cells in a spreadsheet. Whoa!  Suddenly, Pick-to-Light can be used in new ways throughout the supply chain.

The SKU-Station is a beautiful touch display kiosk for your warehouse. Your current ERP or WMS can be used to activate multiple devices at once, simulating a Pick-to-Light or Put-to-Light scenario.  Integrating with picklists is so simple:  It’s just URL calls.

© Copyright 2019 Voodoo Robotics. All Rights Reserved. Patents Pending. Voodoo Robotics, SKU-Keeper, SKU-Turbo, and SKU-Station logos are all trademarks of Voodoo Robotics.