Internet of Things (IoT) Christmas Special: Santa Detector (Part 4)

So, let's take a closer look at the Java SE Embedded code snippet that will send out a tweet when the Santa Detector Raspberry Pi motion sensor is triggered, which will let the Oracle cloud and the Twitterverse know when Santa has arrived at your house. And, if you are doing this project with your child, it will prove once and for all that yes, there is a Santa Claus. Yay!

Here's the full compilable Java source code again for reference:
https://java.net/projects/orbit/downloads/download/SantaDetector.java

0. First, you need to have a Twitter 
account and you need to create your 
own Santa Detector Twitter app to 
make this work.  

Just follow the steps here:
Create Santa Detector Twitter App

And, make sure to do the following extra steps to make your Twitter app "Read and Write" enabled:

 1. Go to your Twitter app account by signing
  in with our Twitter login info:
    https://dev.twitter.com/
 2. Select your account icon -> My Applications
 3. Select the Santa Detector app (To create the
  app: see above)
 4. Click on the Settings tab
 5. In the section "Application Type Access:",
  select "Read and Write"
 6. Check the box for "Allow this application 
  to be used to Sign in with Twitter"
 7. Click "Update this Twitter's app settings"
 8. Click on the Details tab
 9. Refresh your Web browser
10. Make sure the Access level says: 
  "Read and write"
11. Copy the Twitter app information from the
  page into the SantaDetector.java code (Java
  variables near the top of the file):
   OAuth setting: Consumer Key
   OAuth setting: Consumer Secret
   Access token: Access token
   Access token: Access token secret

Next, take a look at the code snippet in the SantaDetector.java file that will send the tweet by calling the Java method tweetStatus():

 static void tweetStatus(String statusStr) {

        boolean verboseFlag = true;
        String requestURIEnc = null;

        try {
            requestURIEnc = URLEncoder.encode(requestURI, "UTF-8");
        } catch (UnsupportedEncodingException uee) {
            uee.printStackTrace();
        }

        try {

            if (statusStr == null) {
                statusStr = "Tweet, tweet.  Hello world!";
            }

            // Construct encoded string, parameter encoded string, & data
            String statusEncStr = URLEncoder.encode(statusStr, "UTF-8");

            // Param encode status string twice: once for unsafe characters 
            //  String, once for escaping % for Signature base string
            String statusUnsafeEncStr = unsafeEncode(unsafeEncode(statusStr));

            String postData = "status=" + statusEncStr;

            // First set the default cookie manager
            CookieHandler.setDefault(new CookieManager(null,
                    CookiePolicy.ACCEPT_ALL));

            // Send postData
            URL url = new URL(requestURI);

            HttpsURLConnection conn = (HttpsURLConnection) 
		url.openConnection();
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");

            // Get current date time with Calendar()
            Calendar cal = Calendar.getInstance();
            String timeStr = String.
                    valueOf(cal.getTimeInMillis()).substring(0, 10);

            String basestring = "POST&" + requestURIEnc
                    + "&oauth_consumer_key%3D" + consumerKey
                    + "%26oauth_nonce%3D5bffa3b2711bbcdaa4f301" + timeStr
                    + 
                   "%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D"
                    + timeStr + "%26oauth_token%3D" + accessToken
                    + "%26oauth_version%3D1.0" + "%26status%3D"
                    + statusUnsafeEncStr;

            String secretsStr = consumerSecret + "&" + accessTokenSecret;
            SecretKeySpec keySpec
                    = new SecretKeySpec(secretsStr.getBytes(),
                            "HmacSHA1");

            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(keySpec);
            byte[] result = mac.doFinal(basestring.getBytes());

            String signature = URLEncoder.encode(base64Encode(result), 
						 "UTF-8");

            String credentials
                    = "oauth_consumer_key=\"" + consumerKey + "\","
                    + "oauth_nonce=\"5bffa3b2711bbcdaa4f301" + timeStr
                    + "\","
                    + "oauth_signature=\"" + signature + "\","
                    + "oauth_signature_method=\"HMAC-SHA1\","
                    + "oauth_timestamp=\"" + timeStr + "\","
                    + "oauth_token=\""
                    + accessToken + "\","
                    + "oauth_version=\"1.0\"";

            conn.addRequestProperty("Authorization", "OAuth " + credentials);

            String lenStr = String.valueOf(postData.length());
            conn.setRequestProperty("Content-Length", lenStr);
            conn.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");

            // Do as if you're using Firefox 3.6.3
            conn.setRequestProperty("User-Agent",
                    "Mozilla/5.0 (Windows; U; Windows NT 5.1; "
                    + "en-US; rv:1.9.2.3) Gecko/20100401");

            if (tweetFlag) {
                conn.connect();
                OutputStream output = conn.getOutputStream();

                output.write(postData.getBytes("UTF-8"));

                // Get the response
                InputStream response = conn.getInputStream();
                BufferedReader rd
                        = new BufferedReader(new InputStreamReader(response));
                String line;
                while ((line = rd.readLine()) != null) {
                    if (verboseFlag) {
                        System.out.println(line);
                    }
                }
                rd.close();
            }
            
            System.out.println("Tweet status = " + statusStr +
                    "\n basestring = " + basestring);

        } catch (IOException | NoSuchAlgorithmException |
                InvalidKeyException | IllegalStateException e) {
            e.printStackTrace();
        }
    }

You see that you can take the above code snippet and just make a tweetStatus library out of it. It is self contained as long as you add the following utilities that need to go along with it.

    public static String unsafeEncode(String input) {
        StringBuilder resultStr = new StringBuilder();
        for (char ch : input.toCharArray()) {
            if (isUnsafe(ch)) {
                resultStr.append('%');
                resultStr.append(toHex(ch / 16));
                resultStr.append(toHex(ch % 16));
            } else {
                resultStr.append(ch);
            }
        }
        return resultStr.toString();
    }

    private static char toHex(int ch) {
        return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
    }

    private static boolean isUnsafe(char ch) {
        if (ch > 128 || ch < 0) {
            return true;
        }
        return "$&+,/:;=?@ \"<>#%{}|\\^~[]`'!_*".indexOf(ch) >= 0;
    }

    private final static char[] BASE64CHARS
           = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
           .toCharArray();

    private static final int[] intChars = new int[128];

    /**
     * Translates the specified byte array into Base64 string.
     *
     * @param inputBuffer byte array (not null)
     * @return the translated Base64 string (not null)
     */
    public static String base64Encode(byte[] inputBuffer) {

        // Check if intChars array needs to be init'd
        if (intChars.length == 0) {
            for (int index = 0; index < BASE64CHARS.length; index++) {
                intChars[BASE64CHARS[index]] = index;
            }
        }

        int bufferSize = inputBuffer.length;
        char[] charArray = new char[((bufferSize + 2) / 3) * 4];
        int charIndex = 0;
        int inputIndex = 0;
        while (inputIndex < bufferSize) {
            byte byte0 = inputBuffer[inputIndex++];
            byte byte1 = (inputIndex < bufferSize)
                    ? inputBuffer[inputIndex++] : 0;
            byte byte2 = (inputIndex < bufferSize)
                    ? inputBuffer[inputIndex++] : 0;

            int mask = 0x3F;
            charArray[charIndex++] = BASE64CHARS[(byte0 >> 2) & mask];
            charArray[charIndex++] = BASE64CHARS[((byte0 << 4)
                    | ((byte1 & 0xFF) >> 4)) & mask];
            charArray[charIndex++] = BASE64CHARS[((byte1 << 2)
                    | ((byte2 & 0xFF) >> 6)) & mask];
            charArray[charIndex++] = BASE64CHARS[byte2 & mask];
        }

        switch (bufferSize % 3) {
            case 1:
                charArray[--charIndex] = '=';
            case 2:
                charArray[--charIndex] = '=';
        }

        return new String(charArray);
    }


So, that's all there is to it to enable your Santa Detector to tweet when Santa has arrived. In the next blog post, we'll wrap it all up and figure out where to place the Raspberry Pi with the sensor for best coverage...

It's almost Christmas Eve, so get ready! ;-)

See the full series of steps:
Internet of Things (IoT) Christmas Special: Santa Detector (Part 1)
Internet of Things (IoT) Christmas Special: Santa Detector (Part 2)
Internet of Things (IoT) Christmas Special: Santa Detector (Part 3)
Internet of Things (IoT) Christmas Special: Santa Detector (Part 4)
Internet of Things (IoT) Christmas Special: Santa Detector (Part 5)
<<< Previous  | Next >>>

Comments:

Post a Comment:
Comments are closed for this entry.
About

Hinkmond Wong's blog on making Machine to Machine (M2M) and the Incredible Internet of Things (IoT) smarter with Java Embedded Technologies

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
2
3
4
5
6
7
8
9
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today