Android and Linux

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

Followers