Android and Linux

Sunday, February 20, 2011

Dawn/Dusk scheduler for Linux

I wanted to run some different commands in the morning and at night in order to set some variables to be used in home automation and switch my new camera from night mode to daytime mode, so I made a little scheduler to run things at dawn and dusk. There are probably other ways to do this, but this is the first time I've tried and I figured out this simple solution and think I'll stick with it.

First, create two files named "dawn" and "dusk" and put any commands you want to run in those scripts. They can be blank for now, but go ahead and make them because our scheduler will be looking for them.

Secondly, we need it to get the sunrise/sunset times. I'll have to leave this one to the reader. There are various services that will calculate the precise times for your latitude/longitude, but in my case I just grabbed it from my local TV news station's weather page. Lucky for me, dumping the page with a console browser gives me the sunrise/sunset times for the entire week and grabbing the top two with this command:
lynx -dump [site] | egrep -i -m 2 "sunset|sunrise" > suntimes
results in this output being put in the file named suntimes:

Sunrise: 07:18
Sunset: 18:22

So, again, this part will depend on your source, but what you want to get is two lines containing the sunrise and sunset time.

Once you figure out the command to get the sunrise/sunset times, put it on the first line of a new script and add these two lines below it:
at $(grep -i sunset suntimes | awk '{ print $2 }') < dawn
at $(grep -i sunrise suntimes | awk '{ print $2 }') < dusk
What that does is tell the at command to run the commands in the day or night file at the time in the second column of line containing "sunrise" or "sunset." The output from the first command is "at 07:18 < dawn" which tells the at scheduler to go run every command in the dawn file at 07:18. The second command is "at 18:22 run the dusk file"

So, running this daily with cron will automatically update the sunrise and sunset times and tell the system to run the dawn/dusk files according to the sunrise/sunset times. You can just add commands to the dawn/dusk files at any time.

That's the idea anyway. This is just an example, you'll probably want to use the full path for the suntimes, dawn and dusk files.

Saturday, February 19, 2011

Foscam shell script, etc

I've been having fun playing with the new camera and came up with a lot of changes to the script I posted a day or two ago. I'm going to post it here and edit it here as I make any changes or additions. I'll date the script and document any changes I make in italics between this text and the script.

I call the script "cam" and will use that name here.

Notes on this script: I worked out the brightness command (and renamed it "bright" to make it shorter). The SDK said brightness could be from 0 to 255, but nothing seems to work right when you set it to 125 or 200 or any other number that you'd naturally try. And when you are controlling the camera through the web interface, it only goes 0-16.

I figured if I took the number from the SDK and rounded it off to 256 and divided by 16, that would equal 16 and would correspond to the 0-16 in the web interface. Sure enough, setting brightness in increments of 16 would make the it change by 1 in the web interface and the changes actually looked right on the camera. So in the script I did away with 0 (who needs that?) and made 1=16, 2=32... until 16=255.

I set up my own day and night "profiles" and left them in the script in case anyone wants them. If not, they can be deleted by deleting everything from "day)" to the next ";;" and "night)" to the next ";;" and they can be changed as well.

For day, my settings are:
IR off
Outside mode
Contrast 4
Brightness 6

For night they are:
IR on
50hz mode
Contrast 6
Brightness 6

It waits two seconds between each command as this seems to be a little more reliable than pounding it with a flurry of settings changes.

I also added the ability to save a snapshot X seconds after performing a camera command. This is useful if you want to do something like pan the camera to a preset then take a snapshot.

"s" tells it to take the snapshot and the seconds argument will tell it how many seconds to wait. So cam s 5 go 3 will make the camera move the the number 3 preset position, wait 5 seconds, then take the snapshot.

This is a little backwards. Logically the "s 5" should be on the end of the command but I didn't want to get into parsing multiple arguments as it would require a more complicated rewrite of the script. Although it is long, it's very simple right now. So, to automatically take a snapshot when performing a command, the first two arguments have to be the "s" and the number of seconds to wait.

It's important to understand how the camera behaves when receiving commands in order to time the screenshot properly, and to do other things as well, but the screenshot is a good example.

When the camera receives a command, it replies with "ok" and carries it out. If it is panned all the way to the right and you tell it to pan all the way to the left, it says "ok" but then may take 10 seconds for it to pan after that ok is sent.

So let's imagine you run the script twice to tell it go to a preset position then tell it to take a snapshot:

cam go 3; cam snap

As soon as it gets the first command, it replies with "ok" and the command finishes and the second one is sent. You will most likely get a snapshot from the cam while it is in motion. The same applies for other commands, such as brightness and contrast. It takes a couple of seconds for the brightness to adjust and a brightness command followed by a snapshot command will probably give you a snapshot of the unchaged brightness level. So keep that in mind if you want to chain commands together or take a snapshot.

Another thing worth noting if using this script over the internet is the possible delay. This is especially true when sending commands over the mobile network, but applies to anything not sent over wifi. Let's walk through a command:

cam left; cam stop

This will start the camera moving left then tell it to stop. Over wifi, the camera only moves a hair before getting the stop command. But imagine sending this over a mobile network that takes two seconds for communications to reach the camera and phone. The camera doesn't get the command for two seconds, then it starts moving left and sends the reply. Two seconds later, the phone gets the "ok" and sends the stop command. The phone doesn't get that for another two seconds. The end result will be that the camera moves for 4 seconds then stops.

Again, this is something to keep in mind and if you find yourself performing intricate commands over slow connections frequently, it may be worth bouncing the commands off a computer on the home network instead of connecting to the camera directly. With ssh, you can send all the commands you want to your Linux box and have it send them to the camera locally (I should be an ssh spokesperson. The first part of this post shows an ssh example and links to some how-tos).

Take our previous example: cam left; cam stop

If you're on a slow connection, the camera could move a lot before getting the stop command. But if you send the entire command to the computer, it would wait until it got the entire command then send it to the camera and send you the output. The camera would barely move a hair. Using the computer could "standardize" your commands so that they would always take about the same amount of time to execute every time. Your connection wouldn't matter because the PC/cam connection over wifi is going to always be good.

Ok, enough random thoughts, here is the Foscam shell script. If using on Android, just replace "/bin/sh" with "/system/bin/sh".

Feb 22:
Added three new commands for controlling the LED, patrol speed and displaying all the camera settings that you can query on the camera.

The LED refers to the green light on the back of the camera which is for indicating the wifi state. My camera is mounted outside right now so I can't check what it does, but the options are 0, 1, or 2. 2 turns the led off. I believe 1 makes it flash when connected to wifi and 0 makes it stay on. I called the command "led".

The patrol speed must vary by models. It's not in the current SDK but it's in an older version and it says the values are 0-100. However, on my camera, 0 is super fast, normal seems to be 2 or 3, and anything over 5 or 6 is incredibly slow. I'm assuming the values for my camera are 0-6 or 0-10. I called this command "speed".

The "settings" command [nevermind, replaced Feb 23]

I plan to include a lot more commands into the script soon. There are some that I don't use and can't test right now (like ftp) but probably will soon, some I will never use and may not be able to test (like DDNS and scheduling), and there are many that I just don't think are useful. But I plan to put everything I can into the script sooner or later.

Feb 23: Some cool changes! The script can now chain together multiple actions in one command. For example:

cam go 3 bright 4 p 5 snap go 1 bright 7 ir on

That long sucker would tell the camera to go to preset 3, set brightness to 4, pause 5 seconds, take a snapshot, go to preset 1, turn brightness to 7 and turn infrared on.

Phwew, that's a doozy of an example, but it illustrates how it can perform a chain of commands. Any commands that are in the script can be used, but beware, there is no error checking yet so you better get the commands right. Commands that require and argument better have them or else this script might explode and burn down your house or something.

There are three other changes:

"setup" and "gsetup" commands. These replace the "settings" command I put in yesterday. It's actually the same line of code but a shorter name and two separate commands. setup will dump all the output from get_params.cgi, get_status.cgi, get_misc.cgi (over 200 lines on my camera) and gsetup can be used to filter it using grep. "cam gsetup ftp" will dump all the output then grep it for "ftp" so all you will see are the lines that contains "ftp".

pause, sleep, wait, p, s, w. Any of these six commands will pause the script for X seconds. "cam go 2 w 5 go 3" will go to preset 2, wait 5 seconds, then go to preset 3. Remember, the countdown starts as soon as the camera is contacted, so if it takes 10 seconds for the camera to pan from 2 to 3, set the wait accordingly. All of those 6 commands are the same. I figured not everyone mentally associates "sleep" for this and might be more comfortable using wait or pause, or just the letters.

I also semi-alphabetized the commands in the script and took out my example dawn and dusk commands as I doubt they were useful.
#! /bin/sh
# If using on Android, replace "/bin/sh" with "/system/bin/sh"
# Feb 23
[ -z "$1" ] && exec $0 h


######## set these options! ########
####################################
# cam username
user=""

# cam password
pass=""

# cam address or ip, with or without port.
# e.g., xxx.xx.xx.xxx:80
ip=""

# location to save snapshot
snapfile=""
####################################
####################################

addy="http://${user}:${pass}@${ip}"

arg=$#
while [ "$arg" -ne "0" ]; do

case "$1" in

50)
wget -q -O - "${addy}/camera_control.cgi?param=3&value=0"
shift; arg=$(($arg - 1));;

60)
wget -q -O - "${addy}/camera_control.cgi?param=3&value=1"
shift; arg=$(($arg - 1));;

alarm)
[ $2 = off ] && wget -q -O - "${addy}/set_alarm.cgi?motion_armed=0"
[ $2 = on ] && wget -q -O - "${addy}/set_alarm.cgi?motion_armed=1"
shift; shift; arg=$(($arg - 2));;

bright)
[ $2 = 1 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=16"
[ $2 = 2 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=32"
[ $2 = 3 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=48"
[ $2 = 4 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=64"
[ $2 = 5 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=80"
[ $2 = 6 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=96"
[ $2 = 7 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=112"
[ $2 = 8 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=128"
[ $2 = 9 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=144"
[ $2 = 10 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=160"
[ $2 = 11 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=176"
[ $2 = 12 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=192"
[ $2 = 13 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=208"
[ $2 = 14 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=224"
[ $2 = 15 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=240"
[ $2 = 16 ] && wget -q -O - "${addy}/camera_control.cgi?param=1&value=255"
shift; shift; arg=$(($arg - 2));;

center)
wget -q -O - "${addy}/decoder_control.cgi?command=25"
shift; arg=$(($arg - 1));;

contrast)
wget -q -O - "${addy}/camera_control.cgi?param=2&value=$2"
shift; shift; arg=$(($arg - 2));;

down)
wget -q -O - "${addy}/decoder_control.cgi?command=2"
shift; arg=$(($arg - 1));;

flip)
wget -q -O - "${addy}/camera_control.cgi?param=5&value=1"
shift; arg=$(($arg - 1));;

go)
[ $2 = 1 ] && wget -q -O - "${addy}/decoder_control.cgi?command=31"
[ $2 = 2 ] && wget -q -O - "${addy}/decoder_control.cgi?command=33"
[ $2 = 3 ] && wget -q -O - "${addy}/decoder_control.cgi?command=35"
[ $2 = 4 ] && wget -q -O - "${addy}/decoder_control.cgi?command=37"
[ $2 = 5 ] && wget -q -O - "${addy}/decoder_control.cgi?command=39"
[ $2 = 6 ] && wget -q -O - "${addy}/decoder_control.cgi?command=41"
[ $2 = 7 ] && wget -q -O - "${addy}/decoder_control.cgi?command=43"
[ $2 = 8 ] && wget -q -O - "${addy}/decoder_control.cgi?command=45"
[ $2 = 9 ] && wget -q -O - "${addy}/decoder_control.cgi?command=47"
[ $2 = 10 ] && wget -q -O - "${addy}/decoder_control.cgi?command=49"
[ $2 = 11 ] && wget -q -O - "${addy}/decoder_control.cgi?command=51"
[ $2 = 12 ] && wget -q -O - "${addy}/decoder_control.cgi?command=53"
[ $2 = 13 ] && wget -q -O - "${addy}/decoder_control.cgi?command=55"
[ $2 = 14 ] && wget -q -O - "${addy}/decoder_control.cgi?command=57"
[ $2 = 15 ] && wget -q -O - "${addy}/decoder_control.cgi?command=59"
[ $2 = 16 ] && wget -q -O - "${addy}/decoder_control.cgi?command=61"
shift; shift; arg=$(($arg - 2));;

horiz)
wget -q -O - "${addy}/decoder_control.cgi?command=28"
shift; arg=$(($arg - 1));;

interval)
wget -q -O - "${addy}/set_alarm.cgi?mail=${2}"
shift; shift; arg=$(($arg - 2));;

ir)
[ $2 = on ] && wget -q -O - "${addy}/decoder_control.cgi?command=95"
[ $2 = off ] && wget -q -O - "${addy}/decoder_control.cgi?command=94"
shift; shift; arg=$(($arg - 2));;

led)
wget -q -O - "${addy}/set_misc.cgi?led_mode=$2"
shift; shift; arg=$(($arg - 2));;

left)
wget -q -O - "${addy}/decoder_control.cgi?command=6"
shift; arg=$(($arg - 1));;

mail)
[ $2 = off ] && wget -q -O - "${addy}/set_alarm.cgi?mail=0"
[ $2 = on ] && wget -q -O - "${addy}/set_alarm.cgi?mail=1"
shift; shift; arg=$(($arg - 2));;

mirror)
wget -q -O - "${addy}/camera_control.cgi?param=5&value=2"
shift; arg=$(($arg - 1));;

out)
wget -q -O - "${addy}/camera_control.cgi?param=3&value=2"
shift; arg=$(($arg - 1));;

reboot)
wget -q -O - "${addy}/reboot.cgi"
shift; arg=$(($arg - 1));;

right)
wget -q -O - "${addy}/decoder_control.cgi?command=4"
shift; arg=$(($arg - 1));;

sense)
wget -q -O - "${addy}/set_alarm.cgi?motion_sensitivity=${2}"
shift; shift; arg=$(($arg - 2));;

set)
# sets camera presets 1-16
[ $2 = 1 ] && wget -q -O - "${addy}/decoder_control.cgi?command=30"
[ $2 = 2 ] && wget -q -O - "${addy}/decoder_control.cgi?command=32"
[ $2 = 3 ] && wget -q -O - "${addy}/decoder_control.cgi?command=34"
[ $2 = 4 ] && wget -q -O - "${addy}/decoder_control.cgi?command=36"
[ $2 = 5 ] && wget -q -O - "${addy}/decoder_control.cgi?command=38"
[ $2 = 6 ] && wget -q -O - "${addy}/decoder_control.cgi?command=40"
[ $2 = 7 ] && wget -q -O - "${addy}/decoder_control.cgi?command=42"
[ $2 = 8 ] && wget -q -O - "${addy}/decoder_control.cgi?command=44"
[ $2 = 9 ] && wget -q -O - "${addy}/decoder_control.cgi?command=46"
[ $2 = 10 ] && wget -q -O - "${addy}/decoder_control.cgi?command=48"
[ $2 = 11 ] && wget -q -O - "${addy}/decoder_control.cgi?command=50"
[ $2 = 12 ] && wget -q -O - "${addy}/decoder_control.cgi?command=52"
[ $2 = 13 ] && wget -q -O - "${addy}/decoder_control.cgi?command=54"
[ $2 = 14 ] && wget -q -O - "${addy}/decoder_control.cgi?command=56"
[ $2 = 15 ] && wget -q -O - "${addy}/decoder_control.cgi?command=58"
[ $2 = 16 ] && wget -q -O - "${addy}/decoder_control.cgi?command=60"
shift; shift; arg=$(($arg - 2));;

setup)
wget -q -O - "${addy}/get_params.cgi"
wget -q -O - "${addy}/get_status.cgi"
wget -q -O - "${addy}/get_misc.cgi"
shift; arg=$(($arg - 1));;

gsetup)
wget -q -O - "${addy}/get_params.cgi" | grep -i "$2"
wget -q -O - "${addy}/get_status.cgi" | grep -i "$2"
wget -q -O - "${addy}/get_misc.cgi" | grep -i "$2"
shift; shift; arg=$(($arg - 2));;

sleep|wait|pause|p|s|w)
sleep $2
shift; shift; arg=$(($arg - 2));;

snap)
wget -q -O ${snapfile} "${addy}/snapshot.cgi?"
shift; arg=$(($arg - 1));;

speed)
wget -q -O - "${addy}/set_misc.cgi?ptz_patrol_rate=$2"
shift; shift; arg=$(($arg - 2));;

stop)
wget -q -O - "${addy}/decoder_control.cgi?command=3"
shift; arg=$(($arg - 1));;

up)
wget -q -O - "${addy}/decoder_control.cgi?command=0"
shift; arg=$(($arg - 1));;

vert)
wget -q -O - "${addy}/decoder_control.cgi?command=26"
shift; arg=$(($arg - 1));;

h|-h|help|--help|*)
echo "sleep|wait|pause|p|s|w- requires argument- will pause script for X seconds.
setup- dumps camera setup (as much as 200 lines)
gsetup- dumps setup but allows you to grep it for keyword. usage: cam gsetup (string)
led- requires argument 0-2. 2 is off, 0/1 on or flashing
snap- save snapshot to /sdcard/cam.jpg
speed- the speed the camera moves. 0-?, 0 is fastest, normal is 2-3
ir- turns IR on or off, must specify on or off
up/down/left/right/stop/center- starts movement, must use separate stop command to stop movement
contrast (0-6)- must specify number
bright (0-16)- must specify number 0-16
vert/horiz- start vert or horiz patrol
50/60/out- set 50hz, 60hz outdoor mode
flip/mirror- flip or mirror the image
alarm- specify on or off
mail- specify on or off to send email on motion detect
interval- image upload interval in seconds, 0 for off, 1 to 65535 for on
sense- motion sensitivity 0-4, 0 being most sensitive
reboot- reboots cam
set- set preset 1-16
go- go to preset 1-16"
shift; arg=$(($arg - 1));;

esac
done

Thursday, February 17, 2011

More Foscam

As I started looking into the commands to control the Foscam, I found that the SDK was released by the Foscam company. It was easy to go through it and whip up a quick script to control most of the camera functions, and I added some functions that weren't documented as well thanks to finding them in various forums. This particular one is for use on Android phones, just change "/system/bin/sh" to "/bin/sh" to run on Linux. It doesn't cover everything, just the functions I wanted to test, but it covers most of them.

#! /system/bin/sh

# Foscam control script
# fubaya @ a-more-common-hades.blogspot.com

## set these options##
user="yourname"
pass="yourpass"
ip="your cams ip or ip:port"
######################

addy="http://${user}:${pass}@${ip}"

case "$1" in

h|-h|help|--help)
echo "snap- save snapshot to /sdcard/cam.jpg
ir- turns IR on or off, must specify on or off
up/down/left/right/stop/center- starts movement, must use stop to stop movement
contrast (0-6)- must specify number
brightness (??)- must specify number, SDK says 0-255. untested
vert/horiz- start vert or horiz patrol
50/60/out- set 50hz, 60hz outdoor mode
flip/mirror- flip or mirror the image
alarm- specify on or off
mail- specify on or off to send email on motion detect
interval- image upload interval in seconds, 0 for off, 1 to 65535 for on
sense- motion sensitivity 0-4, 0 being most sensitive
reboot- reboots cam
set- set preset 1-16
go- go to preset 1-16

examples: ./ThisScript snap
./ThisScript ir off
./ThisScript alarm off
./ThisScript sense 3
./ThisScript go 12

current user/pass/ip setup for this script:
${addy}"
;;

snap)
wget -q -O /sdcard/cam.jpg "${addy}/snapshot.cgi?"
;;

ir)
[ $2 = on ] && wget -q -O - "${addy}/decoder_control.cgi?command=95"
[ $2 = off ] && wget -q -O - "${addy}/decoder_control.cgi?command=94"
;;

up)
wget -q -O - "${addy}/decoder_control.cgi?command=0"
;;

down)
wget -q -O - "${addy}/decoder_control.cgi?command=2"
;;

left)
wget -q -O - "${addy}/decoder_control.cgi?command=6"
;;

right)
wget -q -O - "${addy}/decoder_control.cgi?command=4"
;;

stop)
wget -q -O - "${addy}/decoder_control.cgi?command=3"
;;

center)
wget -q -O - "${addy}/decoder_control.cgi?command=25"
;;

contrast)
wget -q -O - "${addy}/camera_control.cgi?param=2&value=$2"
;;

brightness)
wget -q -O - "${addy}/camera_control.cgi?param=1&value=$2"
;;

vert)
wget -q -O - "${addy}/decoder_control.cgi?command=26"
;;

horiz)
wget -q -O - "${addy}/decoder_control.cgi?command=28"
;;

50)
wget -q -O - "${addy}/camera_control.cgi?param=3&value=0"
;;

60)
wget -q -O - "${addy}/camera_control.cgi?param=3&value=1"
;;

out)
wget -q -O - "${addy}/camera_control.cgi?param=3&value=2"
;;

flip)
wget -q -O - "${addy}/camera_control.cgi?param=5&value=1"
;;

mirror)
wget -q -O - "${addy}/camera_control.cgi?param=5&value=2"
;;

reboot)
wget -q -O - "${addy}/reboot.cgi"
;;

alarm)
[ $2 = off ] && wget -q -O - "${addy}/set_alarm.cgi?motion_armed=0"
[ $2 = on ] && wget -q -O - "${addy}/set_alarm.cgi?motion_armed=1"
;;

sense)
wget -q -O - "${addy}/set_alarm.cgi?motion_sensitivity=${2}"
;;

mail)
[ $2 = off ] && wget -q -O - "${addy}/set_alarm.cgi?mail=0"
[ $2 = on ] && wget -q -O - "${addy}/set_alarm.cgi?mail=1"
;;

interval)
wget -q -O - "${addy}/set_alarm.cgi?mail=${2}"
;;

set)
[ $2 = 1 ] && wget -q -O - "${addy}/decoder_control.cgi?command=30"
[ $2 = 2 ] && wget -q -O - "${addy}/decoder_control.cgi?command=32"
[ $2 = 3 ] && wget -q -O - "${addy}/decoder_control.cgi?command=34"
[ $2 = 4 ] && wget -q -O - "${addy}/decoder_control.cgi?command=36"
[ $2 = 5 ] && wget -q -O - "${addy}/decoder_control.cgi?command=38"
[ $2 = 6 ] && wget -q -O - "${addy}/decoder_control.cgi?command=40"
[ $2 = 7 ] && wget -q -O - "${addy}/decoder_control.cgi?command=42"
[ $2 = 8 ] && wget -q -O - "${addy}/decoder_control.cgi?command=44"
[ $2 = 9 ] && wget -q -O - "${addy}/decoder_control.cgi?command=46"
[ $2 = 0 ] && wget -q -O - "${addy}/decoder_control.cgi?command=48"
[ $2 = 11 ] && wget -q -O - "${addy}/decoder_control.cgi?command=50"
[ $2 = 12 ] && wget -q -O - "${addy}/decoder_control.cgi?command=52"
[ $2 = 13 ] && wget -q -O - "${addy}/decoder_control.cgi?command=54"
[ $2 = 14 ] && wget -q -O - "${addy}/decoder_control.cgi?command=56"
[ $2 = 15 ] && wget -q -O - "${addy}/decoder_control.cgi?command=58"
[ $2 = 16 ] && wget -q -O - "${addy}/decoder_control.cgi?command=60"
;;

go)
[ $2 = 1 ] && wget -q -O - "${addy}/decoder_control.cgi?command=31"
[ $2 = 2 ] && wget -q -O - "${addy}/decoder_control.cgi?command=33"
[ $2 = 3 ] && wget -q -O - "${addy}/decoder_control.cgi?command=35"
[ $2 = 4 ] && wget -q -O - "${addy}/decoder_control.cgi?command=37"
[ $2 = 5 ] && wget -q -O - "${addy}/decoder_control.cgi?command=39"
[ $2 = 6 ] && wget -q -O - "${addy}/decoder_control.cgi?command=41"
[ $2 = 7 ] && wget -q -O - "${addy}/decoder_control.cgi?command=43"
[ $2 = 8 ] && wget -q -O - "${addy}/decoder_control.cgi?command=45"
[ $2 = 9 ] && wget -q -O - "${addy}/decoder_control.cgi?command=47"
[ $2 = 10 ] && wget -q -O - "${addy}/decoder_control.cgi?command=49"
[ $2 = 11 ] && wget -q -O - "${addy}/decoder_control.cgi?command=51"
[ $2 = 12 ] && wget -q -O - "${addy}/decoder_control.cgi?command=53"
[ $2 = 13 ] && wget -q -O - "${addy}/decoder_control.cgi?command=55"
[ $2 = 14 ] && wget -q -O - "${addy}/decoder_control.cgi?command=57"
[ $2 = 15 ] && wget -q -O - "${addy}/decoder_control.cgi?command=59"
[ $2 = 16 ] && wget -q -O - "${addy}/decoder_control.cgi?command=61"
;;

*)
echo "try h for help"
;;

esac

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.

Followers