Android and Linux

Wednesday, February 16, 2011

A new toy


I just got one of these Foscam FI8918W IP cameras and it's really cool. It can pan and tilt, has infrared lights to work at night, motion detection, jacks for audio in and out so you can stream audio and even talk to people through it.. Being an IP camera, it has it's own built-in server that connects to the internet through your home router, either wired or wireless.

The most common way to control it is by pointing your web browser to it's IP address, logging in and viewing the video or controlling the camera. There are also apps for mobile phones to view IP cameras, but the real power is performing commands on the camera using nothing more than specific URLs. For example, grabbing these URLs will give you a snapshot from the camera. They are the same command, just in a different order:

http://User:Pass@IP/snapshot.cgi?
http://IP/snapshot.cgi?user=user&pwd=pass


This one will turn on the camera's infrared lights:

http://User:Pass@IP/decoder_control.cgi?command=95

There are also URLs to pan, tilt and zoom, view the video stream, and adjust various other settings.

While these can be done by typing the URL into a browser, they can also be used in other ways. On the command line, this will tilt the camera down:

wget -q -O - http://User:Pass@IP/decoder_control.cgi?command=2

This two-step Tasker task will save a snapshot from the camera then pop it up on the screen:

1 HTTP get
Server/Port: (the camera's IP address)
Path: snapshot.cgi?user=user&pwd=password
Output File: cam.jpg

2 Popup
Background Image: cam.jpg

Unfortunately, although it runs embedded Linux, it's not open source. The commands seem to be found by people through trial and error, but people have found pretty much all of them. I haven't tested them all, but I look forward to it, and I look forward to integrating the camera with my computer, Tasker, and my home automation.

Sunday, February 13, 2011

Tasker/Zoom update task

I got tired of updating the beta versions of Tasker and Zoom so I made a little Task to automatically download them. In order to check if a newer version was available or if the installed version was current, I had to write a script which I've expanded to check for both versions of Tasker (market and non-market) and Zoom.
#! /system/bin/sh

case "$1" in

-z)
site=http://zoom.dinglisch.net/beta.html
file=/data/data/net.dinglisch.android.zoom/shared_prefs/state.xml

current=$(basename $(wget -q -O - $site | sed 's/\"/\n/g' | grep -m 1 '/releases/Zoom.'))
installed=Zoom.$(grep 'string name="lv"' $file | sed 's#<[^>]*>##g').apk

if echo $installed | grep -q $current
then echo "same" > /sdcard/Tasker/updater
else echo "$current" > /sdcard/Tasker/updater
fi
;;

-tm)
site=http://tasker.dinglisch.net/beta.html
file=/data/data/net.dinglisch.android.taskerm/shared_prefs/net.dinglisch.android.tasker.statey.xml

current=$(basename $(wget -q -O - $site | sed 's/\"/\n/g' | grep "http://tasker.dinglisch.net/releases" | grep m))

installed=Tasker.$(grep 'string name="lvn"' $file | sed 's#<[^>]*>##g').apk

if echo $installed | grep -q $current
then echo "same" > /sdcard/Tasker/updater
else echo "$current" > /sdcard/Tasker/updater
fi
;;

-t)
site=http://tasker.dinglisch.net/beta.html
file=/data/data/net.dinglisch.android.taskerm/shared_prefs/net.dinglisch.android.tasker.statey.xml

current=$(basename $(wget -q -O - $site | sed 's/\"/\n/g' | grep "http://tasker.dinglisch.net/releases" | grep -v m))
installed=Tasker.$(grep 'string name="lvn"' $file | sed 's#<[^>]*>##g').apk

if echo $installed | grep -q $current
then echo "same" > /sdcard/Tasker/updater
else echo "$current" > /sdcard/Tasker/updater
fi
;;

*)
echo "auto updater for Tasker/Zoom betas
-z check for Zoom update.
-t check for Tasker update, non Market version
-tm check for Tasker Market version update

This script checks the Tasker or Zoom beta website
for the newest version and writes it to a file if it's
newer than the installed version. See
http://a-more-common-hades.blogspot.com
for a Tasker task to utilize this script"
;;

esac
Then, the task to update them just needs to execute this script with one of three options.

-z check for Zoom update.
-t check for Tasker update, non Market version
-tm check for Tasker Market version update

I called the script "updateTZ" so the command I run is updateTZ -tm to check for the latest beta of the market version.

The Tasks are pretty simple but instead of pasting them here, I uploaded the two tasks to update Tasker and Zoom here at mediafire.com: http://www.mediafire.com/?fejn05a2uypvv. If you name the script anything else, or are using the non-market version of Tasker, you'll need to change the Locale Execute Plugin command accordingly.

If the currently installed version is up to date, the tasks flash "Tasker (or Zoom) is still up to date." If a new version is available, it downloads it then tries to open the downloaded file, which goes into the system install screen where you have to click "ok" to install.

Note: the current version of zoom, 1.0a8, has the wrong version information. It is still called 1.0a7 in the app so the zoom task won't currently work, it will keep seeing the app as an older version and update it.

Sunday, February 6, 2011

temp post

#! /system/bin/sh
label="'YOURLABEL'"
yourmail="YOUREMAIL@gmail.com"

dir="/data/data/com.google.android.gm/databases/"

case "$1" in

name)
sqlite3 ${dir}mailstore.${yourmail}.db "select fromAddress from messages ORDER BY _id DESC LIMIT 1" | grep -o '"[^"]*"' | tr -d \";;

email)
sqlite3 ${dir}mailstore.${yourmail}.db "select fromAddress from messages ORDER BY _id DESC LIMIT 1" | grep -o \<.*\> | tr -d '<>';;

subject)
sqlite3 ${dir}mailstore.${yourmail}.db "select subject from messages ORDER BY _id DESC LIMIT 1";;

lname)
sqlite3 ${dir}mailstore.${yourmail}.db "select subject from messages,message_labels,labels where labels.name = "$label" and message_labels.labels_id = labels._id and messages.messageId = message_labels.message_messageId order by messages._id desc limit 1" | grep -o '"[^"]*"' | tr -d \";;

lemail)
sqlite3 ${dir}mailstore.${yourmail}.db "select fromAddress,subject from messages,message_labels,labels where labels.name = "$label" and message_labels.labels_id = labels._id and messages.messageId = message_labels.message_messageId order by messages._id desc limit 1" | grep -o \<.*\> | tr -d '<>';;

lsubject)
sqlite3 ${dir}mailstore.${yourmail}.db "select subject from messages,message_labels,labels where labels.name = "$label" and message_labels.labels_id = labels._id and messages.messageId = message_labels.message_messageId order by messages._id desc limit 1";;

labelall)
sqlite3 ${dir}mailstore.${yourmail}.db "select fromAddress,subject from messages,message_labels,labels where labels.name = "$label" and message_labels.labels_id = labels._id and messages.messageId = message_labels.message_messageId order by messages._id desc limit 1";;

*)
sqlite3 ${dir}mailstore.${yourmail}.db "select fromAddress,subject from messages ORDER BY _id DESC LIMIT 1";;

esac

Thursday, February 3, 2011

Posting HTTP data with Curl/Linux and Tasker/Android

It can often be useful to submit information to a website automatically. This can be anything from a login to a search term and anything else that uses the HTTP post method to send data to a site. This is possible in Linux and Android alike. The first part of this post will be a walkthrough of the principal using Linux, but the final command will be nearly the same with Tasker on Android, so if you're only interested in using this with Tasker, don't skip ahead. You should read the Linux part to understand what's going on.

In the example I will use here, I wanted to get TAFs from NOAA's Aviation Weather Center. TAFs are Terminal Area Forecasts, short term weather forecasts prepared at the airport for the 5 mile radius surrounding it. They are released several times per day and are useful because they are more specific than a general area forecast. This can be useful for me because I live about four miles to the north of the airport and work about 2 miles south of it, so I spend most of my time being subjected to the weather forecasted under the TAF umbrella.

If you click that link, the text box on the right of the page is what I want. You have to put in your airport code, select raw or translated, and select TAF or both METAR and TAF (METARs tell you the current weather conditions).

On Linux:

Submitting this information in Linux can be done with the command line utility called cURL. But first you have to figure out what information to send to the site and how to send it. You can do this by looking through the raw HTML source code, but it's a lot easier to use a perl script from the cURL website named formfind.pl. Once you have that, it's time to get started.

The first thing you want to do is download the webpage. Let's use cURL to download it and save it as index.html:

curl -o index.html http://aviationweather.gov/adds/tafs/index.php

Now we use the formfind script to read the file:

formfind < index.html

From the output, we need to find the correct form by looking at the clues. The clues are the URL that the data is posted to and the descriptions of the information being posted.

This is obviously the text box on the upper left of the webpage:

--- FORM report. Uses POST to URL "/adds/phputils/airport_weather.php"
Input: NAME="inputstring" VALUE="City, St" (TEXT)
Input: NAME="Go2" VALUE="Go" (SUBMIT)
--- end of FORM

The next one posts to "/adds/tafs/displayMetarsTafs.php", maybe that's what we want? No, judging by the rest of the form, it is for the "Plotted TAFs" section.

Finally, this is the section we're interested in:

--- FORM report. Uses POST to URL "/adds/tafs/index.php"
Input: NAME="station_ids" (TEXT)
Input: NAME="std_trans" VALUE="standard" (RADIO)
Input: NAME="std_trans" VALUE="translated" (RADIO)
Input: NAME="submit_taf" VALUE="Get TAFs" (SUBMIT)
Input: NAME="submit_both" VALUE="Get TAFs and METARs" (SUBMIT)
--- end of FORM

station_ids: this is the four letter station identifier, let's use KDEN for Denver, since it's the example on the page.
std_trans: there are two of these because they represent the radio button where you select standard of translated (standard is a short code, translated is a readable forecast)
submit_taf and submit_both: these allow you to select TAF, or both METAR and TAF.

Now we just need to craft our cURL command to assign values for the input names that we want in the format name=value and submit it to the correct page. We want to use KDEN as the station ID, we want the report to be translated and we just want the TAFs.

curl -d station_ids=KDEN -d std_trans=translated -d submit_taf="Get TAFs" "http://aviationweather.gov/adds/tafs/index.php"

That command will give you the raw HTML output for the page we wanted. If you go to the site with a browser and select the same values, you'll see the same output, except the browser obviously doesn't show the raw HTML. But we were successful in submitting the data we wanted and visiting the page we wanted.

With Tasker on Android:

This turns out to be very similar. There isn't a way to find the correct information to post, so you will have to visually examine the source code for the clues I mentioned above or find another way to get it. But once you do, the HTTP Post action in Tasker is very obviously similar:

Server/Port: aviationweather.gov

Path: adds/tafs/index.php

Data:
station_ids=KDEN
std_trans=translated
submit_taf="Get TAFs"

Any website you get or post to with Tasker is saved in the %HTTPD variable, or you can specify a file to save it to. Looking at either the variable or file, you'll see the same output as we had above with cURL in Linux. We've successfully submitted the information into the forms and gotten back the page we wanted.

Another useful tip:

If you're using cURL to login to a website, cURL can save the login cookie to a text file with the -c option. I haven't used this on the xda forum, but this would probably work.

curl -c cookie.txt -d name=yourname pass= yourpass "http://forum.xda-developers.com"

Now that you have the cookie, you can then visit the page and login automatically by loading that cookie file. cURL isn't available on Android, but wget is and it can use that same file:

wget --load-cookies=cookie.txt "http://forum.xda-developers.com/private.php" -O pm.html

That would save your private message page to the file called pm.html. You could, for example, automatically check them every hour and alert yourself if you have a new message.

Monday, January 31, 2011

My screenshot

I was going to do a post about what Android apps I like, but it's to much work to just sit and describe the features of a bunch of apps. So, I'm going to go for a walk through my homescreen and describe how I use some of my favorite apps:


It looks pretty simple, but there's actually a lot going on thanks to the many cool Android apps available.

The top weather widget is Beautiful Widgets. The text on the right and left is displayed by Minimalistic Text. The actual text is updated every 30 minutes with a shell script controlled by Tasker which passes it to Minimalistic Text.

The text on the left is the date, the time of the last update and the number of visitors to my two blogs (zeroed out so I don't embarrass myself :) ). I mostly keep track of that to watch for spikes if something of mine gets posted somewhere. Not that I mind, but when I had the iphone blog (which still gets a lot of hits) people would post a script of mine with entirely wrong information and I used to have to chase it down and provide the correct information before someone screwed up their phone, so I got into the habit of watching the hits for spikes as a safety measure.


To the right is weather information. Wind direction and speed, visibility and barometer, temp and conditions. This is all gathered and formatted by the same shell script.

The text in these two blocks is aligned to the top of the icon, which is why they appear higher than the button in the middle. I may not keep it that way, but I did that when perfecting the weather information. Some weather conditions are long, like "light precipitation" and screw up the left/right alignment so I started breaking the lines and extending the conditions downward, so this gives me more room when it's "show and ice mix." Once I have examples of more long weather conditions, I'll start shortening them to "snow/ice" and put them back on one line.

Clicking the text on either side opens apps. I currently have the one on the right opening Wordfeud, because I check it often throughout the day, and the one on the left opens the phone.


The middle button starts and stops BeyondPod, the podcast app. It's a Tasker widget that changes from the play symbol to a pause symbol. It's not perfect, if I push play in the app, there's no way for Tasker to detect it, so it still shows the play symbol. But tapping it once straightens it out. I listen to a lot of podcasts that are usually an hour or more long and I usually have to pause them often, so this makes it easy and kinda cool too.

I use Launcher Pro. If you notice, the Tasker/BeyondPod widget is in the center of the screen. This is done by making a regular 1x1 Tasker widget and resizing it to 2x2 with LauncherPro. The icon moves to the center of the 2x2 block when resized.

The empty space below is not empty at all.


It's a 4x2 Minimalistic Text widget that I use to display information from Tasker. I have a profile to detect when the variable %HOMETEXT is set, so I just set it in any tasks I want to flash text and it carries out another task to display whatever is in the variable with Minimalistic Text.


It displays for 10 seconds then changes to a period because you can't set it for blank text and that's the smallest thing available. It actually isn't showing in the pic because I haven't used it to flash anything since the last reboot, but you can hardly see the dot when it's there.

Tapping anywhere on that 4x2 widget locks the phone by executing the app "Screen Off and Lock." Screen Off and Lock is a nice little app that does only one thing. When opened, it turns off the screen. My power button has gone out and I don't want to send it in to be fixed yet, so this is how I lock the phone. There is another app called "Invisible Lock Widget" which gives you an invisible widget that also locks the phone. It's really useful too, but it's a widget and can't be executed by another app. Screen Off and Lock is a standalone app so it can be "opened" by other apps, in this case Minimalistic Text.

Finally, to the dock. I need to find a better looking dock and app drawer icon. I made the text icons myself to fit a thinner dock and I need to remake and recolor those too, so don't knock my dock, it's a work in progress.

You can make the dock twice as useful with LauncherPro. Not only can you tap an icon to open apps or folders, but you can also swipe them to carry out several different actions. In my case, I just use them to open more apps and folders. All folders are created with Folder Organizer. The top word is the name to describe what happens when you tap, the bottom word is for swiping, and here is what mine do:

cam: opens the camera.
comm: opens a "communications" folder which contains the Phone, SMS, gmail, GVoice etc.

all: opens a folder containing 8 more folders that contain all my apps in different categories.
web: opens a folder containing all my web tools; Browser, Market, Tapatalk, Ebay, Amazon, etc.

App Drawer: opens the app drawer like normal.
App Drawer (swipe): opens a folder with all my "hacking" tools. Better Terminal Emulator, Tasker, a folder full of GSCript scripts, etc.

rss: opens BeyondPod, which I use as an RSS reader as well as podcatcher.
recent: pops up a list of recent apps, much more friendlier than long pressing the home button.

opt: opens Quick Settings, the app to quickly toggle GPS, Wifi, Tethering, Volume etc.
tasks: opens a folder of shortcuts to all of my Tasker tasks which I may want to run by tapping.

I made the wallpaper with an app named "Simple Wallpaper." It only makes different gradients for use as wallpapers, but if you want a gradient, it is certainly a nice app to use.


That's it, everything is done from that one home screen. I do have LauncherPro set for three home screens. The one to the right is for controlling my X10 home automation modules and is still very much a work in progress. The screen to the left stays empty unless I am testing something.

I hope this has been helpful or given other people some ideas.

Tuesday, January 18, 2011

Zoom widget designer

Pent, the creator of Tasker, is coming out with a custom widget designer named Zoom. He just released the first beta earlier today. If I can figure it out, I'll try to post something cool later, but the Tasker integration isn't implemented yet, which is what I am most interested in.

Ok, it didn't take me long to find something cool. Although the Tasker integration won't be implemented until the next version of Tasker, you can create a widget with buttons. Name the buttons and for Click Actions, select Broadcast Intent.

Now, in Tasker, select a new event profile (the orange triangle), select UI, then Button Clicked and enter the name of the button and select a task for it to carry out. Using my earlier post about using Tasker with home automation, I made buttons for two X10 modules then linked them to the tasks for toggling those modules. Here is the result:



Sweet!

The buttons can be resized and moved around on the widget for better placement and appearance.

Sunday, January 16, 2011

61 minute cron

It seems like everyone who uses cron to schedule jobs in Linux eventually runs into a problem where they need to schedule a command at odd intervals, like 61 minutes. Cron can easily run every hour, but 61 minutes is harder to achieve.

The normal methods include using a sleep command or various rather elaborate methods in the script itself to fire off every 61 minutes.

A much simpler method is using cron's cousin, the at command. The at command will run through a file and run all the commands inside, so you just need to place the commands in a file, one per line, then add this line to the bottom of the file:
at now + 61 minutes < file
The commands can be any type of one-liner you want to use.

Here is an example. Call this file foo and to kick off the execution the first time, you can simply run: sh foo
date >> ~/foo_out
cd ~/tmp && rm *
at now + 61 minutes < ~/foo
That will output the date and time to ~/foo_out then move to a tmp directory and clean out files, then tell the at command to run itself again in 61 minutes which will again run the at command after executing the rest.

Followers